diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 10effb86..ab1b5981 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -github: Gerome-Elaassaad +github: codinit-dev diff --git a/.github/workflows/electron.yml b/.github/workflows/electron.yml index 9d1c1261..b9a129f2 100644 --- a/.github/workflows/electron.yml +++ b/.github/workflows/electron.yml @@ -69,7 +69,6 @@ jobs: - name: Build Electron app env: - GH_TOKEN: ${{ secrets.TOKEN }} NODE_OPTIONS: "--max_old_space_size=4096" run: | if [ "$RUNNER_OS" == "Windows" ]; then @@ -116,6 +115,7 @@ jobs: tag_name: ${{ github.ref_name }} draft: false name: Release ${{ github.ref_name }} + fail_on_unmatched_files: false files: | artifacts/**/*.exe artifacts/**/*.dmg @@ -123,6 +123,7 @@ jobs: artifacts/**/*.AppImage artifacts/**/*.zip artifacts/**/*.blockmap - artifacts/**/*.yml + artifacts/**/latest.yml + artifacts/**/latest-*.yml env: GITHUB_TOKEN: ${{ secrets.TOKEN }} diff --git a/.gitignore b/.gitignore index b2b3a058..e2609f4e 100644 --- a/.gitignore +++ b/.gitignore @@ -51,4 +51,5 @@ CLAUDE.md AGENTS.md* .mcp.json -.claude \ No newline at end of file +.claude +backend \ No newline at end of file diff --git a/LICENSE b/LICENSE index 9a48e763..77703be1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 CodinIT.dev +Copyright (c) 2026 CodinIT.dev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 2da2d6fa..351e8e4a 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,127 @@
-
-
+
+
- ⚡ CodinIT.dev — Open‑Source AI App Builder ⚡
+
Build, manage, and deploy intelligent applications faster — directly from your browser or desktop.
---- -✨ What is CodinIT.dev? +--- -CodinIT.dev is an open‑source, AI‑powered full‑stack development platform designed to help you build modern Node.js applications with speed and precision. It combines code generation, project management, and deployment tools into a single workflow — powered by your choice of AI providers. +## Overview -Whether you’re prototyping, scaling a SaaS product, or experimenting with local LLMs, CodinIT.dev adapts to your stack and your workflow. +CodinIT.dev is an open‑source, AI full‑stack development platform designed to help developers build modern Node.js applications with speed and precision. It combines code generation, project management, and deployment tools into a single workflow, powered by your choice of AI providers. +Whether you are prototyping, scaling a SaaS product, or experimenting with local LLMs, CodinIT.dev adapts to your stack and workflow. --- -🚀 Quick Start +## Quick Start Get up and running in minutes. -1️⃣ Clone the Repository +### 1. Clone the Repository -``` -git clone https://github.com/codinit-dev/codinit-dev.git +```bash +git clone [https://github.com/codinit-dev/codinit-dev.git](https://github.com/codinit-dev/codinit-dev.git) cd codinit-dev + ``` -2️⃣ Install Dependencies +### 2. Install Dependencies -``` +```bash # npm npm install # or pnpm pnpm install -``` - -3️⃣ Configure Environment +``` -Create a .env file and add your preferred AI provider keys: +### 3. Configure Environment -(You can mix and match multiple providers.) +Create a `.env` file and add your preferred AI provider keys. You can mix and match multiple providers depending on your requirements. -4️⃣ Run the Dev Server +### 4. Run the Development Server -``` +```bash pnpm run dev -``` -The app will be available at: 👉 http://localhost:5173 +``` +The application will be available at: http://localhost:5173 --- -🧩 Key Features - -🧠 AI‑powered full‑stack development for Node.js apps - -🌐 19+ AI provider integrations (cloud & local) - -🖥️ Web + Desktop (Electron) support - -🐳 Docker‑ready — deploy to Vercel, Netlify, or GitHub Pages - -🔍 Built‑in search, diff viewer & file‑locking - -🧰 Supabase integration, data visualization & voice prompting - -🔐 Provider‑agnostic architecture — no vendor lock‑in - +## Core Capabilities +- **Automated Full-Stack Engineering:** Streamline the creation and management of complex Node.js architectures using intelligent generation. +- **Universal Model Integration:** Seamlessly connect with over 19 cloud and local AI providers. +- **Hybrid Environment Support:** native compatibility for both Web browsers and Desktop (Electron) environments. +- **Production-Ready Containerization:** Fully Dockerized workflow with preset configurations for Vercel, Netlify, and GitHub Pages. +- **Integrated Development Suite:** Includes robust utilities such as semantic search, diff visualization, and concurrency file-locking. +- **Expanded Ecosystem Connectivity:** Native integration with Supabase, real-time data visualization tools, and voice-command interfaces. +- **Vendor-Neutral Infrastructure:** A flexible architecture designed to prevent vendor lock-in, allowing dynamic switching between backend providers. --- -🔑 Supported AI Providers +## Supported AI Providers -☁️ Cloud Providers +CodinIT.dev allows you to use one provider or switch dynamically per task. -OpenAI · Anthropic · Google · Groq · xAI · DeepSeek · Cohere · Mistral · Together · Perplexity · HuggingFace · OpenRouter · and more +### Cloud Providers -🏠 Local Providers +OpenAI, Anthropic, Google, Groq, xAI, DeepSeek, Cohere, Mistral, Together, Perplexity, HuggingFace, OpenRouter, and more. -Ollama · LM Studio · OpenAI‑compatible local endpoints +### Local Providers -Use one provider or switch dynamically per task. +Ollama, LM Studio, and OpenAI‑compatible local endpoints. --- -🖥️ Desktop & Docker Usage +## Deployment & Desktop Usage -Run with Docker -``` +### Run with Docker + +```bash npm run dockerbuild docker compose --profile development up + ``` -Run as a Desktop App -Download the latest prebuilt release: 👉 https://github.com/codinit-dev/codinit-dev/releases/latest +### Run as a Desktop App + +Download the latest prebuilt release for macOS, Windows, and Linux. -Available for macOS, Windows, and Linux. +[Download Latest Release](https://github.com/codinit-dev/codinit-dev/releases/latest) diff --git a/__tests__/unit/providers/manager.test.ts b/__tests__/unit/providers/manager.test.ts index b54ca7ee..6aeb0f15 100644 --- a/__tests__/unit/providers/manager.test.ts +++ b/__tests__/unit/providers/manager.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { LLMManager } from '~/lib/modules/llm/manager'; import { mockOpenAIModels, mockApiKeys } from '../../fixtures/api-responses'; @@ -9,6 +9,15 @@ describe('LLMManager', () => { // Reset the singleton instance for each test (LLMManager as any)._instance = null; manager = LLMManager.getInstance(); + + // Silence console for cleaner test output + vi.spyOn(console, 'log').mockImplementation(() => { }); + vi.spyOn(console, 'error').mockImplementation(() => { }); + vi.spyOn(console, 'warn').mockImplementation(() => { }); + }); + + afterEach(() => { + vi.restoreAllMocks(); }); describe('getInstance', () => { diff --git a/__tests__/unit/runtime/code-validator.test.ts b/__tests__/unit/runtime/code-validator.test.ts index 243b4bf2..01749903 100644 --- a/__tests__/unit/runtime/code-validator.test.ts +++ b/__tests__/unit/runtime/code-validator.test.ts @@ -1,7 +1,17 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { validateCode } from '~/lib/runtime/code-validator'; describe('code-validator', () => { + beforeEach(() => { + vi.spyOn(console, 'log').mockImplementation(() => undefined); + vi.spyOn(console, 'warn').mockImplementation(() => undefined); + vi.spyOn(console, 'debug').mockImplementation(() => undefined); + vi.spyOn(console, 'error').mockImplementation(() => undefined); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); describe('validateCode - General', () => { it('should detect placeholder comments', () => { const code = ` diff --git a/__tests__/unit/runtime/message-parser.test.ts b/__tests__/unit/runtime/message-parser.test.ts index d6caa858..50aca263 100644 --- a/__tests__/unit/runtime/message-parser.test.ts +++ b/__tests__/unit/runtime/message-parser.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; function cleanoutMarkdownSyntax(content: string) { const codeBlockRegex = /^\s*```[\w-]*\s*\n?([\s\S]*?)\n?\s*```\s*$/; @@ -18,6 +18,15 @@ function cleanoutMarkdownSyntax(content: string) { } describe('message-parser - cleanoutMarkdownSyntax', () => { + beforeEach(() => { + vi.spyOn(console, 'log').mockImplementation(() => { }); + vi.spyOn(console, 'error').mockImplementation(() => { }); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + describe('Basic markdown removal', () => { it('should remove markdown code block with language', () => { const input = '```javascript\nconst x = 1;\n```'; diff --git a/__tests__/unit/server/llm-utils.test.ts b/__tests__/unit/server/llm-utils.test.ts index ab22de59..14f887d6 100644 --- a/__tests__/unit/server/llm-utils.test.ts +++ b/__tests__/unit/server/llm-utils.test.ts @@ -1,8 +1,26 @@ -import { describe, it, expect } from 'vitest'; -import { extractFileReferences, createReferencedFilesContext, processFileReferences } from '~/lib/.server/llm/utils'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { + extractFileReferences, + createReferencedFilesContext, + processFileReferences, + extractPropertiesFromMessage, + simplifyCodinitActions, + createFilesContext, + extractCurrentContext, +} from '~/lib/.server/llm/utils'; import type { FileMap } from '~/lib/.server/llm/constants'; +import type { Message } from 'ai'; describe('LLM Utils - File References', () => { + beforeEach(() => { + vi.spyOn(console, 'log').mockImplementation(() => { }); + vi.spyOn(console, 'error').mockImplementation(() => { }); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + describe('extractFileReferences', () => { it('should extract single file reference', () => { const text = 'Can you check @src/index.ts?'; @@ -268,3 +286,396 @@ Can you fix it to properly import from @app/utils.ts?`; }); }); }); + +describe('LLM Utils - Message Processing', () => { + describe('extractPropertiesFromMessage', () => { + it('should extract model and provider from message content', () => { + const message = { + role: 'user' as const, + content: '[Model: gpt-4]\n\n[Provider: OpenAI]\n\nHello world', + }; + const result = extractPropertiesFromMessage(message); + expect(result.model).toBe('gpt-4'); + expect(result.provider).toBe('OpenAI'); + expect(result.content).toBe('Hello world'); + }); + + it('should use default model when not specified', () => { + const message = { + role: 'user' as const, + content: '[Provider: Anthropic]\n\nHello world', + }; + const result = extractPropertiesFromMessage(message); + expect(result.model).toBe('claude-4-5-sonnet-latest'); + expect(result.provider).toBe('Anthropic'); + }); + + it('should use default provider when not specified', () => { + const message = { + role: 'user' as const, + content: '[Model: gpt-4]\n\nHello world', + }; + const result = extractPropertiesFromMessage(message); + expect(result.model).toBe('gpt-4'); + expect(result.provider).toBe('Anthropic'); + }); + + it('should handle plain text without model or provider', () => { + const message = { + role: 'user' as const, + content: 'Hello world', + }; + const result = extractPropertiesFromMessage(message); + expect(result.model).toBe('claude-4-5-sonnet-latest'); + expect(result.provider).toBe('Anthropic'); + expect(result.content).toBe('Hello world'); + }); + + it('should handle array content with text type', () => { + const message = { + role: 'user' as const, + content: [{ type: 'text' as const, text: '[Model: gpt-4]\n\n[Provider: OpenAI]\n\nHello' }], + } as any; + const result = extractPropertiesFromMessage(message); + expect(result.model).toBe('gpt-4'); + expect(result.provider).toBe('OpenAI'); + }); + + it('should handle array content with image and text', () => { + const message = { + role: 'user' as const, + content: [ + { type: 'text' as const, text: '[Model: gpt-4]\n\nDescribe this image' }, + { type: 'image_url' as const, image_url: { url: 'https://example.com/image.png' } }, + ], + } as any; + const result = extractPropertiesFromMessage(message); + expect(result.model).toBe('gpt-4'); + expect(Array.isArray(result.content)).toBe(true); + + if (Array.isArray(result.content)) { + expect(result.content[0].type).toBe('text'); + expect(result.content[1].type).toBe('image_url'); + } + }); + + it('should remove model and provider tags from cleaned content', () => { + const message = { + role: 'user' as const, + content: '[Model: gpt-4]\n\n[Provider: OpenAI]\n\nActual message', + }; + const result = extractPropertiesFromMessage(message); + expect(result.content).toBe('Actual message'); + expect(result.content).not.toContain('[Model:'); + expect(result.content).not.toContain('[Provider:'); + }); + + it('should handle empty text in array content', () => { + const message = { + role: 'user' as const, + content: [{ type: 'text' as const, text: '' }], + } as any; + const result = extractPropertiesFromMessage(message); + expect(result.model).toBe('claude-4-5-sonnet-latest'); + expect(result.provider).toBe('Anthropic'); + }); + }); + + describe('simplifyCodinitActions', () => { + it('should simplify codinitAction tags with type="file"', () => { + const input = + '