From afcd51e95d24de85c932c6f8c06c423f15c3ce6a Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Sat, 20 Dec 2025 20:27:49 +1100 Subject: [PATCH 001/200] fix: prevent duplicate release creation and type conflicts - remove GH_TOKEN from build step (electron-builder generates files only) - add releaseType: release to prevent draft/release conflicts - GitHub Actions release job handles uploading all artifacts --- .github/workflows/electron.yml | 1 - electron-builder.yml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/electron.yml b/.github/workflows/electron.yml index 9d1c1261..21396585 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 diff --git a/electron-builder.yml b/electron-builder.yml index 13603b1f..bd094705 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -84,6 +84,7 @@ publish: provider: github owner: codinit-dev repo: codinit-dev + releaseType: release electronDownload: mirror: https://npmmirror.com/mirrors/electron/ From 7b918bbd6199ccb27a6da4ef68bb116d9b04e68e Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Sat, 20 Dec 2025 21:35:36 +1100 Subject: [PATCH 002/200] fix: prevent duplicate yml file uploads in release workflow --- .github/workflows/electron.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/electron.yml b/.github/workflows/electron.yml index 21396585..b9a129f2 100644 --- a/.github/workflows/electron.yml +++ b/.github/workflows/electron.yml @@ -115,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 @@ -122,6 +123,7 @@ jobs: artifacts/**/*.AppImage artifacts/**/*.zip artifacts/**/*.blockmap - artifacts/**/*.yml + artifacts/**/latest.yml + artifacts/**/latest-*.yml env: GITHUB_TOKEN: ${{ secrets.TOKEN }} From ca1193eaf05441f672bdd55044e42892ef556f82 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Sat, 20 Dec 2025 21:42:31 +1100 Subject: [PATCH 003/200] refactor: remove redundant GitHub API call from update checker --- app/lib/api/updates.ts | 113 +++++++++++++---------------------------- 1 file changed, 35 insertions(+), 78 deletions(-) diff --git a/app/lib/api/updates.ts b/app/lib/api/updates.ts index 84b9fc5a..c7f1c201 100644 --- a/app/lib/api/updates.ts +++ b/app/lib/api/updates.ts @@ -11,13 +11,6 @@ export interface UpdateCheckResult { }; } -interface GitHubRelease { - tag_name: string; - html_url: string; - body: string; - published_at: string; -} - interface ApiUpdateResponse { updateAvailable: boolean; currentVersion: string; @@ -29,33 +22,8 @@ interface ApiUpdateResponse { message?: string; } -function compareVersions(v1: string, v2: string): number { - // Remove 'v' prefix if present - const version1 = v1.replace(/^v/, ''); - const version2 = v2.replace(/^v/, ''); - - const parts1 = version1.split('.').map(Number); - const parts2 = version2.split('.').map(Number); - - for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { - const part1 = parts1[i] || 0; - const part2 = parts2[i] || 0; - - if (part1 > part2) { - return 1; - } - - if (part1 < part2) { - return -1; - } - } - - return 0; -} - export const checkForUpdates = async (): Promise => { try { - // Get update info from the API route const apiResponse = await fetch('/api/update', { method: 'POST', headers: { @@ -64,70 +32,59 @@ export const checkForUpdates = async (): Promise => { }); if (!apiResponse.ok) { - throw new Error(`API request failed: ${apiResponse.status}`); - } + if (apiResponse.status === 403) { + const resetTime = apiResponse.headers.get('X-RateLimit-Reset'); - const apiData = (await apiResponse.json()) as ApiUpdateResponse; - - if (apiData.error) { - throw new Error(apiData.message || 'API returned an error'); - } - - const currentVersion = apiData.currentVersion; - - // Fetch the latest release from GitHub - const response = await fetch(`https://api.github.com/repos/codinit-dev/codinit-dev/releases/latest`, { - headers: { - Accept: 'application/vnd.github.v3+json', - 'User-Agent': 'codinit-dev', - }, - }); - - if (!response.ok) { - // If no releases found or repo doesn't exist - if (response.status === 404) { return { available: false, - version: currentVersion, - currentVersion, - }; - } - - // Check for rate limiting - if (response.status === 403) { - const resetTime = response.headers.get('X-RateLimit-Reset'); - return { - available: false, - version: currentVersion, - currentVersion, + version: 'unknown', + currentVersion: 'unknown', error: { type: 'rate_limit', - message: `GitHub API rate limit exceeded. ${resetTime ? `Resets at ${new Date(parseInt(resetTime) * 1000).toLocaleTimeString()}` : ''}`, + message: `GitHub API rate limit exceeded. ${resetTime ? `Resets at ${new Date(parseInt(resetTime) * 1000).toLocaleTimeString()}` : 'Try again later.'}`, }, }; } - throw new Error(`GitHub API returned ${response.status}`); + throw new Error(`API request failed: ${apiResponse.status}`); } - const release = (await response.json()) as GitHubRelease; - const latestVersion = release.tag_name.replace(/^v/, ''); // Remove 'v' prefix if present + const apiData = (await apiResponse.json()) as ApiUpdateResponse; + + if (apiData.error) { + const errorMessage = apiData.message || 'API returned an error'; + let errorType: 'rate_limit' | 'network' | 'auth' | 'unknown' = 'unknown'; + + if (errorMessage.toLowerCase().includes('rate limit')) { + errorType = 'rate_limit'; + } else if (errorMessage.toLowerCase().includes('network') || errorMessage.toLowerCase().includes('fetch')) { + errorType = 'network'; + } else if (errorMessage.toLowerCase().includes('auth') || errorMessage.toLowerCase().includes('403')) { + errorType = 'auth'; + } - // Compare versions - const updateAvailable = compareVersions(latestVersion, currentVersion) > 0; + return { + available: false, + version: apiData.currentVersion, + currentVersion: apiData.currentVersion, + error: { + type: errorType, + message: errorMessage, + }, + }; + } return { - available: updateAvailable, - version: latestVersion, - currentVersion, - releaseNotes: release.body, - releaseUrl: release.html_url, - publishedAt: release.published_at, + available: apiData.updateAvailable, + version: apiData.latestVersion || apiData.currentVersion, + currentVersion: apiData.currentVersion, + releaseNotes: apiData.releaseNotes, + releaseUrl: apiData.releaseUrl, + publishedAt: apiData.publishedAt, }; } catch (error) { console.error('Error checking for updates:', error); - // Determine error type const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; const isNetworkError = errorMessage.toLowerCase().includes('network') || From c31eba4bd86a86aba0af800e2413a1e9bb34cf2b Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Sat, 20 Dec 2025 21:48:08 +1100 Subject: [PATCH 004/200] refactor: centralize version and repository configuration --- app/lib/version.ts | 2 ++ app/routes/api.update.ts | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 app/lib/version.ts diff --git a/app/lib/version.ts b/app/lib/version.ts new file mode 100644 index 00000000..9b208db1 --- /dev/null +++ b/app/lib/version.ts @@ -0,0 +1,2 @@ +export const APP_VERSION = '1.1.26'; +export const GITHUB_REPOSITORY = 'codinit-dev/codinit-dev'; diff --git a/app/routes/api.update.ts b/app/routes/api.update.ts index e0c1640d..b16c9b1a 100644 --- a/app/routes/api.update.ts +++ b/app/routes/api.update.ts @@ -1,7 +1,8 @@ import { json, type ActionFunction } from '@remix-run/cloudflare'; +import { APP_VERSION, GITHUB_REPOSITORY } from '~/lib/version'; -const CURRENT_VERSION = '1.1.26'; -const GITHUB_REPO = 'codinit-dev/codinit-dev'; +const GITHUB_REPO = GITHUB_REPOSITORY; +const CURRENT_VERSION = APP_VERSION; interface GitHubRelease { tag_name: string; From df0d4b930a372122781f11104c33c1b2bbebf473 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Sat, 20 Dec 2025 21:54:02 +1100 Subject: [PATCH 005/200] refactor: use centralized repository config in UpdateTab --- app/components/@settings/tabs/update/UpdateTab.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/components/@settings/tabs/update/UpdateTab.tsx b/app/components/@settings/tabs/update/UpdateTab.tsx index 98767666..3175941d 100644 --- a/app/components/@settings/tabs/update/UpdateTab.tsx +++ b/app/components/@settings/tabs/update/UpdateTab.tsx @@ -5,6 +5,7 @@ import { toast } from 'react-toastify'; import { Dialog, DialogRoot, DialogTitle, DialogDescription, DialogButton } from '~/components/ui/Dialog'; import { classNames } from '~/utils/classNames'; import { Markdown } from '~/components/chat/Markdown'; +import { GITHUB_REPOSITORY } from '~/lib/version'; interface UpdateSettings { autoUpdate: boolean; @@ -232,7 +233,7 @@ const UpdateTab = () => {

)}

- Updates are checked from: codinit-dev/codinit-dev (GitHub releases) + Updates are checked from: {GITHUB_REPOSITORY} (GitHub releases)

{hasUpdate && releaseUrl && ( @@ -295,8 +296,8 @@ const UpdateTab = () => {

- A new version ({latestVersion}) is available from{' '} - codinit-dev/codinit-dev on GitHub. + A new version ({latestVersion}) is available from {GITHUB_REPOSITORY}{' '} + on GitHub.

{releaseUrl && ( From 488ad0569490c4fbcd22fb59415f884c34b8da5b Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Sat, 20 Dec 2025 22:01:05 +1100 Subject: [PATCH 006/200] fix: remove unnecessary z-index and transparent background from ChatHeader --- app/components/header/ChatHeader.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/header/ChatHeader.tsx b/app/components/header/ChatHeader.tsx index 5b9c968a..61851e46 100644 --- a/app/components/header/ChatHeader.tsx +++ b/app/components/header/ChatHeader.tsx @@ -11,7 +11,7 @@ export function ChatHeader() { } return ( -
+
+ )} +
+ +
+ +
+ setApiKey(e.target.value)} + placeholder="Enter your Pro API key..." + className={classNames( + 'flex-1 px-4 py-2 rounded-lg text-sm', + 'bg-white dark:bg-[#0F0F0F]', + 'border border-gray-200 dark:border-[#2A2A2A]', + 'text-codinit-elements-textPrimary', + 'focus:outline-none focus:ring-2 focus:ring-blue-500/30', + )} + /> + +
+
+ + + + ); +} From 2cfd57a15a0bee1d70a91a91e86aa43e1034c866 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Thu, 25 Dec 2025 20:58:24 +1100 Subject: [PATCH 019/200] feat: integrate Pro features in chat UI with Web Search and Lazy Edits toggles Migrate hardcoded colors to CSS custom properties throughout chat components. Add Web Search and Lazy Edits feature toggles with provider validation. Improve chat header styling and visual hierarchy with border separator. --- app/components/chat/BaseChat.module.scss | 30 +++++++------- app/components/chat/BaseChat.tsx | 8 +++- app/components/chat/Chatbox.tsx | 50 +++++++++++++++++++++++- app/components/header/ChatHeader.tsx | 12 +++--- 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/app/components/chat/BaseChat.module.scss b/app/components/chat/BaseChat.module.scss index 2d6dd4db..694afef9 100644 --- a/app/components/chat/BaseChat.module.scss +++ b/app/components/chat/BaseChat.module.scss @@ -125,11 +125,11 @@ } ._PromptContainer_1k1wl_1 { - background: radial-gradient(circle at 4% -40%, #cccccc 0%, transparent 30%); + background: radial-gradient(circle at 4% -40%, var(--codinit-elements-icon-tertiary) 0%, transparent 30%); } ._GradientBorder_1k1wl_5 { - border: 1px solid rgba(204, 204, 204, 0.2); + border: 1px solid var(--codinit-elements-borderColor); } @supports (-webkit-mask-composite: xor) { @@ -142,7 +142,7 @@ ._GradientBorder_1k1wl_5:before { position: absolute; padding: 1px; - background: linear-gradient(180deg, #cccccc, #fff3); + background: linear-gradient(180deg, var(--codinit-elements-borderColor), #fff3); border-radius: inherit; content: ''; inset: 0; @@ -157,21 +157,21 @@ } [data-theme='light'] ._GradientBorder_1k1wl_5:before { - background: linear-gradient(180deg, #cccccc, #0003); + background: linear-gradient(180deg, var(--codinit-elements-borderColor), #0003); } } ._LiquidGlassButton_16cym_1 { min-height: 40px; overflow: visible; - background: linear-gradient(135deg, rgba(204, 204, 204, 0.1), rgba(204, 204, 204, 0.05)); + background: linear-gradient(135deg, var(--codinit-elements-item-backgroundAccent), rgba(204, 204, 204, 0.05)); backdrop-filter: blur(20px) saturate(140%); -webkit-backdrop-filter: blur(20px) saturate(180%); box-shadow: inset 0 1px rgba(255, 255, 255, 0.1), inset 0 -1px rgba(0, 0, 0, 0.1), 0 8px 32px -8px rgba(0, 0, 0, 0.1), - 0 0 0 1px rgba(204, 204, 204, 0.1); + 0 0 0 1px var(--codinit-elements-borderColor); transition: all 0.4s cubic-bezier(0.32, 0.72, 0, 1); will-change: transform, box-shadow; backface-visibility: hidden; @@ -209,12 +209,12 @@ } ._LiquidGlassButton_16cym_1:hover { - background: linear-gradient(135deg, rgba(204, 204, 204, 0.15), rgba(204, 204, 204, 0.08)); + background: linear-gradient(135deg, var(--codinit-elements-item-backgroundAccent), rgba(204, 204, 204, 0.08)); box-shadow: inset 0 1px rgba(255, 255, 255, 0.1), inset 0 -1px rgba(0, 0, 0, 0.15), 0 12px 40px -8px rgba(0, 0, 0, 0.15), - 0 0 0 1px rgba(204, 204, 204, 0.15); + 0 0 0 1px var(--codinit-elements-borderColor); } ._LiquidGlassButton_16cym_1:hover:before { @@ -227,11 +227,11 @@ inset 0 1px rgba(255, 255, 255, 0.2), inset 0 -1px rgba(0, 0, 0, 0.1), 0 4px 20px -8px rgba(0, 0, 0, 0.1), - 0 0 0 1px rgba(204, 204, 204, 0.05); + 0 0 0 1px var(--codinit-elements-borderColor); } [data-theme='light'] ._LiquidGlassButton_16cym_1 { - background: linear-gradient(135deg, rgba(204, 204, 204, 0.7), rgba(204, 204, 204, 0.5)); + background: linear-gradient(135deg, var(--codinit-elements-bg-depth-3), var(--codinit-elements-bg-depth-2)); box-shadow: inset 0 1px rgba(255, 255, 255, 0.9), inset 0 -1px rgba(0, 0, 0, 0.05), @@ -249,7 +249,7 @@ } [data-theme='light'] ._LiquidGlassButton_16cym_1:hover { - background: linear-gradient(135deg, rgba(204, 204, 204, 0.95), rgba(204, 204, 204, 0.85)); + background: linear-gradient(135deg, var(--codinit-elements-bg-depth-4), var(--codinit-elements-bg-depth-3)); box-shadow: inset 0 1px rgba(255, 255, 255, 1), inset 0 -1px rgba(0, 0, 0, 0.08), @@ -271,9 +271,9 @@ background: linear-gradient( 90deg, transparent 0%, - rgba(204, 204, 204, 0.8) 20%, - rgba(255, 255, 255, 0.8) 50%, - rgba(204, 204, 204, 0.8) 80%, + var(--codinit-elements-borderColor) 20%, + var(--codinit-elements-textPrimary) 50%, + var(--codinit-elements-borderColor) 80%, transparent 100% ); opacity: 0.6; @@ -287,7 +287,7 @@ content: ''; position: absolute; inset: 0; - background: linear-gradient(90deg, transparent 0%, rgba(204, 204, 204, 0.8) 50%, transparent 100%); + background: linear-gradient(90deg, transparent 0%, var(--codinit-elements-borderColor) 50%, transparent 100%); animation: _shimmer_16cym_1 3s ease-in-out infinite; } diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 07c5bdaa..5273377c 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -39,6 +39,7 @@ import type { ProgressAnnotation } from '~/types/context'; import { SupabaseChatAlert } from '~/components/chat/SupabaseAlert'; import { expoUrlAtom } from '~/lib/stores/qrCodeStore'; import { useStore } from '@nanostores/react'; +import { proStore } from '~/lib/stores/pro'; import { StickToBottom, useStickToBottomContext } from '~/lib/hooks'; import { ChatBox } from './Chatbox'; import type { DesignScheme } from '~/types/design-scheme'; @@ -448,7 +449,7 @@ export const BaseChat = React.forwardRef( {/* Unified Header Container - spans full width */} {chatStarted && ( -
+
{/* Chat Header Section - constrained to chat width */}
@@ -775,6 +776,11 @@ export const BaseChat = React.forwardRef( setDesignScheme={setDesignScheme} selectedElement={selectedElement} setSelectedElement={setSelectedElement} + codinit_options={{ + enable_web_search: proStore.get().features.webSearch, + enable_lazy_edits: proStore.get().features.lazyEdits, + files: uploadedFiles.length > 0, + }} />
diff --git a/app/components/chat/Chatbox.tsx b/app/components/chat/Chatbox.tsx index 77bbb718..e84ff87f 100644 --- a/app/components/chat/Chatbox.tsx +++ b/app/components/chat/Chatbox.tsx @@ -27,6 +27,7 @@ import { ToolMentionAutocomplete } from './ToolMentionAutocomplete'; import { insertToolMention, insertFileReference } from '~/utils/toolMentionParser'; import { useStore } from '@nanostores/react'; import { workbenchStore } from '~/lib/stores/workbench'; +import { proStore, toggleFeature } from '~/lib/stores/pro'; interface ChatBoxProps { isModelSettingsCollapsed: boolean; @@ -69,6 +70,11 @@ interface ChatBoxProps { setDesignScheme?: (scheme: DesignScheme) => void; selectedElement?: ElementInfo | null; setSelectedElement?: ((element: ElementInfo | null) => void) | undefined; + codinit_options?: { + enable_web_search?: boolean; + enable_lazy_edits?: boolean; + files?: boolean; + }; } export const ChatBox: React.FC = (props) => { @@ -285,11 +291,11 @@ export const ChatBox: React.FC = (props) => { )} onDragEnter={(e) => { e.preventDefault(); - e.currentTarget.style.border = '2px solid #1488fc'; + e.currentTarget.style.border = '2px solid var(--codinit-elements-borderColorActive)'; }} onDragOver={(e) => { e.preventDefault(); - e.currentTarget.style.border = '2px solid #1488fc'; + e.currentTarget.style.border = '2px solid var(--codinit-elements-borderColorActive)'; }} onDragLeave={(e) => { e.preventDefault(); @@ -413,6 +419,46 @@ export const ChatBox: React.FC = (props) => {
{props.chatMode === 'discuss' ? Discuss : } + { + if (props.provider?.name !== 'CodinIT') { + toast.info('Web Search is a Pro feature available with CodinIT Pro provider.'); + return; + } + + toggleFeature('webSearch'); + }} + > +
+ + { + if (props.provider?.name !== 'CodinIT') { + toast.info('Lazy Edits is a Pro feature available with CodinIT Pro provider.'); + return; + } + + toggleFeature('lazyEdits'); + }} + > +
+ {() => props.isModelSettingsCollapsed ? ( diff --git a/app/components/header/ChatHeader.tsx b/app/components/header/ChatHeader.tsx index 61851e46..c3e5116d 100644 --- a/app/components/header/ChatHeader.tsx +++ b/app/components/header/ChatHeader.tsx @@ -11,23 +11,23 @@ export function ChatHeader() { } return ( -
+
/ -
+
{() => }
+ ); }, ), diff --git a/app/components/workbench/CodeModeHeader.tsx b/app/components/workbench/CodeModeHeader.tsx index f538efe5..8d00cf6d 100644 --- a/app/components/workbench/CodeModeHeader.tsx +++ b/app/components/workbench/CodeModeHeader.tsx @@ -18,34 +18,31 @@ export const CodeModeHeader = memo( }; return ( -
+
{/* Toggle Buttons Section */} -
-
- setSelectedView('preview')} - /> - setSelectedView('code')} /> - setSelectedView('diff')} - /> -
+
+ setSelectedView('preview')} + /> + setSelectedView('code')} + /> + setSelectedView('diff')} + />
- +
- +
+ Publish +
diff --git a/app/components/workbench/DiffViewHeader.tsx b/app/components/workbench/DiffViewHeader.tsx index c156fbe3..39d1a36b 100644 --- a/app/components/workbench/DiffViewHeader.tsx +++ b/app/components/workbench/DiffViewHeader.tsx @@ -49,24 +49,22 @@ export const DiffViewHeader = memo( const showStats = additions > 0 || deletions > 0; return ( -
+
{/* Toggle Buttons Section */} -
-
- setSelectedView('preview')} - /> - setSelectedView('code')} /> - setSelectedView('diff')} - /> -
+
+ setSelectedView('preview')} + /> + setSelectedView('code')} /> + setSelectedView('diff')} + />
diff --git a/app/components/workbench/Preview.tsx b/app/components/workbench/Preview.tsx index cbdfad21..a9626485 100644 --- a/app/components/workbench/Preview.tsx +++ b/app/components/workbench/Preview.tsx @@ -493,11 +493,12 @@ export const Preview = memo(() => {
) : (
-
+
-
No Preview Available
-
- Start a development server to see your app +
+
Ready to Build?
+
+ Start a development server or prompt the AI to see your app in action.
diff --git a/app/components/workbench/PreviewHeader.tsx b/app/components/workbench/PreviewHeader.tsx index ad7960b9..b7f1e02d 100644 --- a/app/components/workbench/PreviewHeader.tsx +++ b/app/components/workbench/PreviewHeader.tsx @@ -112,12 +112,12 @@ export const PreviewHeader = memo( }; return ( -
+
{/* Toggle Buttons Section */} -
+
setSelectedView('preview')} /> @@ -130,13 +130,7 @@ export const PreviewHeader = memo( /> - + {/* Address Bar */} -
+
- - + className="text-codinit-elements-textSecondary" + />
{/* Right Action Buttons */} @@ -338,25 +329,19 @@ export const PreviewHeader = memo(
- {/* Deploy Dialog Button */} - + className="w-8 h-8 rounded-md bg-codinit-elements-item-backgroundActive text-codinit-elements-textPrimary border border-codinit-elements-borderColor" + /> - + className="w-8 h-8 rounded-md bg-codinit-elements-textPrimary text-codinit-elements-background-depth-1" + />
From c0f9c6f5f87997527226e38b05c574d723da1f68 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Thu, 25 Dec 2025 20:59:09 +1100 Subject: [PATCH 021/200] feat: add CodinIT provider integration with Pro feature options support Extend chat validation schema to accept codinit_options for Web Search, Lazy Edits, and file handling. Register CodinIT provider in LLM registry and pass Pro options through the chat API pipeline. --- app/lib/api/chat-validation.ts | 12 ++++++++++++ app/lib/modules/llm/base-provider.ts | 1 + app/lib/modules/llm/registry.ts | 2 ++ app/routes/api.chat.ts | 2 ++ 4 files changed, 17 insertions(+) diff --git a/app/lib/api/chat-validation.ts b/app/lib/api/chat-validation.ts index 836bb8b3..fbe31028 100644 --- a/app/lib/api/chat-validation.ts +++ b/app/lib/api/chat-validation.ts @@ -31,6 +31,13 @@ const chatRequestSchema = z.object({ designScheme: z.any().optional(), supabase: supabaseConfigSchema.optional(), enableMCPTools: z.boolean().default(false), + codinit_options: z + .object({ + enable_web_search: z.boolean().optional(), + enable_lazy_edits: z.boolean().optional(), + files: z.boolean().optional(), + }) + .optional(), }); export interface ValidatedChatRequest { @@ -48,6 +55,11 @@ export interface ValidatedChatRequest { }; }; enableMCPTools: boolean; + codinit_options?: { + enable_web_search?: boolean; + enable_lazy_edits?: boolean; + files?: boolean; + }; } export function validateChatRequest(data: unknown): ValidatedChatRequest { diff --git a/app/lib/modules/llm/base-provider.ts b/app/lib/modules/llm/base-provider.ts index 981c3682..80f838c0 100644 --- a/app/lib/modules/llm/base-provider.ts +++ b/app/lib/modules/llm/base-provider.ts @@ -154,6 +154,7 @@ export abstract class BaseProvider implements ProviderInfo { serverEnv?: Env; apiKeys?: Record; providerSettings?: Record; + codinit_options?: any; }): LanguageModelV1; } diff --git a/app/lib/modules/llm/registry.ts b/app/lib/modules/llm/registry.ts index df31b1cf..07710b2e 100644 --- a/app/lib/modules/llm/registry.ts +++ b/app/lib/modules/llm/registry.ts @@ -1,4 +1,5 @@ import AnthropicProvider from './providers/anthropic'; +import CodinITProvider from './providers/codinit'; import DeepseekProvider from './providers/deepseek'; import GoogleProvider from './providers/google'; import GroqProvider from './providers/groq'; @@ -19,6 +20,7 @@ import GithubProvider from './providers/github'; export { AnthropicProvider, + CodinITProvider, DeepseekProvider, GoogleProvider, GroqProvider, diff --git a/app/routes/api.chat.ts b/app/routes/api.chat.ts index 0c9e8e0d..06f08cc4 100644 --- a/app/routes/api.chat.ts +++ b/app/routes/api.chat.ts @@ -276,6 +276,7 @@ async function chatAction({ context, request }: ActionFunctionArgs) { summary, messageSliceId, designScheme, + codinit_options: validatedRequest.codinit_options, }); stream.switchSource(result.toDataStream()); @@ -361,6 +362,7 @@ async function chatAction({ context, request }: ActionFunctionArgs) { summary, messageSliceId, designScheme, + codinit_options: validatedRequest.codinit_options, }); (async () => { From e96b8b5e87d51eda0c053bd94719e429425072a6 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Thu, 25 Dec 2025 20:59:39 +1100 Subject: [PATCH 022/200] refactor: migrate hardcoded colors to CSS variables and optimize diff view styling Replace rgba borders with CSS custom properties in code.scss. Remove Tailwind utilities from diff-view.css in favor of vanilla CSS for better performance. Revert icon color overrides and reduce header height to 48px in variables.scss. --- app/styles/components/code.scss | 4 +- app/styles/diff-view.css | 44 ++++-- app/styles/variables.scss | 236 ++++++++++++++++++++------------ 3 files changed, 187 insertions(+), 97 deletions(-) diff --git a/app/styles/components/code.scss b/app/styles/components/code.scss index a1a16e39..536596b0 100644 --- a/app/styles/components/code.scss +++ b/app/styles/components/code.scss @@ -1,11 +1,11 @@ .actions .shiki { background-color: var(--codinit-elements-actions-code-background) !important; - border: 1px solid rgba(153, 153, 153, 0.1) !important; /* Neutral border */ + border: 1px solid var(--codinit-elements-borderColor) !important; } .shiki { &:not(:has(.actions), .actions *, .mcp-tool-invocation-code *) { background-color: var(--codinit-elements-messages-code-background) !important; - border: 1px solid rgba(153, 153, 153, 0.08) !important; /* Neutral border */ + border: 1px solid var(--codinit-elements-borderColor) !important; } } diff --git a/app/styles/diff-view.css b/app/styles/diff-view.css index accc9129..a135a2af 100644 --- a/app/styles/diff-view.css +++ b/app/styles/diff-view.css @@ -33,40 +33,62 @@ /* Estilos para as linhas de diff */ .diff-block-added { - @apply bg-green-500/20 border-l-4 border-green-500; + background-color: rgba(34, 197, 94, 0.2); + border-left: 4px solid rgb(34, 197, 94); } .diff-block-removed { - @apply bg-red-500/20 border-l-4 border-red-500; + background-color: rgba(239, 68, 68, 0.2); + border-left: 4px solid rgb(239, 68, 68); } /* Melhorar contraste para mudanças */ -.diff-panel-content .group:hover .diff-block-added { - @apply bg-green-500/30; +.diff-panel-content .diff-line:hover .diff-block-added { + background-color: rgba(34, 197, 94, 0.3); } -.diff-panel-content .group:hover .diff-block-removed { - @apply bg-red-500/30; +.diff-panel-content .diff-line:hover .diff-block-removed { + background-color: rgba(239, 68, 68, 0.3); } /* Estilos unificados para ambas as visualizações */ .diff-line { - @apply flex group min-w-fit transition-colors duration-150; + display: flex; + min-width: fit-content; + transition: background-color 150ms ease; } .diff-line-number { - @apply w-12 shrink-0 pl-2 py-0.5 text-left font-mono text-codinit-elements-textTertiary border-r border-codinit-elements-borderColor bg-codinit-elements-background-depth-1; + width: 3rem; + flex-shrink: 0; + padding: 0.125rem 0 0.125rem 0.5rem; + text-align: left; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + color: var(--codinit-elements-textTertiary); + border-right: 1px solid var(--codinit-elements-borderColor); + background-color: var(--codinit-elements-background-depth-1); } .diff-line-content { - @apply px-4 py-0.5 font-mono whitespace-pre flex-1 group-hover:bg-codinit-elements-background-depth-2 text-codinit-elements-textPrimary; + padding: 0.125rem 1rem; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + white-space: pre; + flex: 1; + color: var(--codinit-elements-textPrimary); + transition: background-color 150ms ease; +} + +.diff-line:hover .diff-line-content { + background-color: var(--codinit-elements-background-depth-2); } /* Cores específicas para adições/remoções */ .diff-added { - @apply bg-green-500/20 border-l-4 border-green-500; + background-color: rgba(34, 197, 94, 0.2); + border-left: 4px solid rgb(34, 197, 94); } .diff-removed { - @apply bg-red-500/20 border-l-4 border-red-500; + background-color: rgba(239, 68, 68, 0.2); + border-left: 4px solid rgb(239, 68, 68); } diff --git a/app/styles/variables.scss b/app/styles/variables.scss index 2969df1f..eaa5c0e4 100644 --- a/app/styles/variables.scss +++ b/app/styles/variables.scss @@ -62,9 +62,9 @@ --codinit-elements-icon-success: theme('colors.green.500'); --codinit-elements-icon-error: theme('colors.red.500'); - --codinit-elements-icon-primary: #cccccc; /* Changed from theme('colors.gray.950') to low-contrast gray */ - --codinit-elements-icon-secondary: #a0a0a0; /* Changed from theme('colors.gray.600') to dimmer gray */ - --codinit-elements-icon-tertiary: #888888; /* Changed from theme('colors.gray.500') to softer gray */ + --codinit-elements-icon-primary: theme('colors.gray.950'); + --codinit-elements-icon-secondary: theme('colors.gray.600'); + --codinit-elements-icon-tertiary: theme('colors.gray.500'); --codinit-elements-dividerColor: theme('colors.gray.100'); @@ -136,13 +136,19 @@ :root, :root[data-theme='dark'] { /* Pure neutral gray with blue accents - improved contrast */ - --codinit-elements-borderColor: #3a3a3a; /* Neutral gray border - slightly lighter for visibility */ - --codinit-elements-borderColorActive: #3b82f6; /* Blue active border */ - - --codinit-elements-bg-depth-1: #121212; /* Main background - darker base */ - --codinit-elements-bg-depth-2: #1a1a1a; /* Content surfaces */ - --codinit-elements-bg-depth-3: #242424; /* Distinction elements */ - --codinit-elements-bg-depth-4: #2e2e2e; /* Buttons/inputs - more contrast */ + --codinit-elements-borderColor: #3a3a3a; + /* Neutral gray border - slightly lighter for visibility */ + --codinit-elements-borderColorActive: #3b82f6; + /* Blue active border */ + + --codinit-elements-bg-depth-1: #121212; + /* Main background - darker base */ + --codinit-elements-bg-depth-2: #1a1a1a; + /* Content surfaces */ + --codinit-elements-bg-depth-3: #242424; + /* Distinction elements */ + --codinit-elements-bg-depth-4: #2e2e2e; + /* Buttons/inputs - more contrast */ /* Aliases for background-depth variables */ --codinit-elements-background-depth-1: var(--codinit-elements-bg-depth-1); @@ -151,21 +157,31 @@ --codinit-elements-background-depth-4: var(--codinit-elements-bg-depth-4); /* Optimized contrast for text */ - --codinit-elements-textPrimary: #ffffff; /* Pure white for better readability */ - --codinit-elements-textSecondary: #cccccc; /* Neutral gray */ - --codinit-elements-textTertiary: #999999; /* Muted neutral */ - - --codinit-elements-code-background: #0a0a0a; /* Dark code background */ - --codinit-elements-code-text: #f0f6fc; /* Bright code text */ + --codinit-elements-textPrimary: #ffffff; + /* Pure white for better readability */ + --codinit-elements-textSecondary: #cccccc; + /* Neutral gray */ + --codinit-elements-textTertiary: #999999; + /* Muted neutral */ + + --codinit-elements-code-background: #0a0a0a; + /* Dark code background */ + --codinit-elements-code-text: #f0f6fc; + /* Bright code text */ /* Primary Button - Blue accent */ - --codinit-elements-button-primary-background: #3b82f6; /* Blue background */ - --codinit-elements-button-primary-backgroundHover: #2563eb; /* Darker blue on hover */ - --codinit-elements-button-primary-text: #ffffff; /* White text for max contrast */ + --codinit-elements-button-primary-background: #3b82f6; + /* Blue background */ + --codinit-elements-button-primary-backgroundHover: #2563eb; + /* Darker blue on hover */ + --codinit-elements-button-primary-text: #ffffff; + /* White text for max contrast */ /* Secondary Button - Neutral gray with better contrast */ - --codinit-elements-button-secondary-background: #2e2e2e; /* Matches depth-4 for visibility on containers */ - --codinit-elements-button-secondary-backgroundHover: #3a3a3a; /* Lighter hover for clear feedback */ + --codinit-elements-button-secondary-background: #2e2e2e; + /* Matches depth-4 for visibility on containers */ + --codinit-elements-button-secondary-backgroundHover: #3a3a3a; + /* Lighter hover for clear feedback */ --codinit-elements-button-secondary-text: #e0e0e0; /* Danger Button - Remains prominent */ @@ -175,21 +191,30 @@ /* Item backgrounds and content - neutral gray with improved contrast */ --codinit-elements-item-contentDefault: #a0a0a0; - --codinit-elements-item-contentActive: #ffffff; /* White for active */ - --codinit-elements-item-contentAccent: #d0d0d0; /* Neutral gray accent */ - --codinit-elements-item-contentDanger: #f85149; /* Remains prominent */ - --codinit-elements-item-backgroundDefault: transparent; /* Transparent for layering */ - --codinit-elements-item-backgroundActive: #2e2e2e; /* Matches depth-4 for clear hover/active */ - --codinit-elements-item-backgroundAccent: rgba(204, 204, 204, 0.08); /* Subtle neutral accent background */ + --codinit-elements-item-contentActive: #ffffff; + /* White for active */ + --codinit-elements-item-contentAccent: #d0d0d0; + /* Neutral gray accent */ + --codinit-elements-item-contentDanger: #f85149; + /* Remains prominent */ + --codinit-elements-item-backgroundDefault: transparent; + /* Transparent for layering */ + --codinit-elements-item-backgroundActive: #2e2e2e; + /* Matches depth-4 for clear hover/active */ + --codinit-elements-item-backgroundAccent: rgba(204, 204, 204, 0.08); + /* Subtle neutral accent background */ --codinit-elements-item-backgroundDanger: rgba(248, 81, 73, 0.1); /* Loader - Higher contrast */ - --codinit-elements-loader-background: rgba(255, 255, 255, 0.1); /* Slightly more opaque */ - --codinit-elements-loader-progress: #79c0ff; /* Brighter progress color */ + --codinit-elements-loader-background: rgba(255, 255, 255, 0.1); + /* Slightly more opaque */ + --codinit-elements-loader-progress: #79c0ff; + /* Brighter progress color */ /* Artifacts - Neutral gray aligned with new depth system */ --codinit-elements-artifacts-background: var(--codinit-elements-bg-depth-1); - --codinit-elements-artifacts-backgroundHover: rgba(255, 255, 255, 0.06); /* Subtle hover */ + --codinit-elements-artifacts-backgroundHover: rgba(255, 255, 255, 0.06); + /* Subtle hover */ --codinit-elements-artifacts-borderColor: var(--codinit-elements-borderColor); --codinit-elements-artifacts-inlineCode-background: var(--codinit-elements-bg-depth-3); --codinit-elements-artifacts-inlineCode-text: #ffffff; @@ -200,87 +225,130 @@ /* Messages - Neutral gray aligned with new depth system */ --codinit-elements-messages-background: var(--codinit-elements-bg-depth-2); - --codinit-elements-messages-linkColor: #d0d0d0; /* Slightly brighter link */ - --codinit-elements-messages-code-background: #0a0a0a; /* Darker code background */ + --codinit-elements-messages-linkColor: #d0d0d0; + /* Slightly brighter link */ + --codinit-elements-messages-code-background: #0a0a0a; + /* Darker code background */ --codinit-elements-messages-inlineCode-background: var(--codinit-elements-bg-depth-3); --codinit-elements-messages-inlineCode-text: var(--codinit-elements-textPrimary); /* Icons - Adjusted for dark theme contrast */ - --codinit-elements-icon-success: #56d364; /* Remains green */ - --codinit-elements-icon-error: #f85149; /* Remains red */ - --codinit-elements-icon-primary: #f0f6fc; /* Bright white */ - --codinit-elements-icon-secondary: #c9d1d9; /* Bright */ - --codinit-elements-icon-tertiary: #8b949e; /* Subtle */ - - --codinit-elements-dividerColor: #333333; /* Aligned with border color */ - - --codinit-elements-prompt-background: rgba(18, 18, 18, 0.85); /* Aligned with depth-1 */ + --codinit-elements-icon-success: #56d364; + /* Remains green */ + --codinit-elements-icon-error: #f85149; + /* Remains red */ + --codinit-elements-icon-primary: #f0f6fc; + /* Bright white */ + --codinit-elements-icon-secondary: #c9d1d9; + /* Bright */ + --codinit-elements-icon-tertiary: #8b949e; + /* Subtle */ + + --codinit-elements-dividerColor: #333333; + /* Aligned with border color */ + + --codinit-elements-prompt-background: rgba(18, 18, 18, 0.85); + /* Aligned with depth-1 */ /* Sidebar - Blue accent */ - --codinit-elements-sidebar-buttonBackgroundDefault: rgba(59, 130, 246, 0.1); /* Blue accent background */ - --codinit-elements-sidebar-buttonBackgroundHover: rgba(59, 130, 246, 0.15); /* Blue hover */ - --codinit-elements-sidebar-buttonText: #3b82f6; /* Blue accent */ + --codinit-elements-sidebar-buttonBackgroundDefault: rgba(59, 130, 246, 0.1); + /* Blue accent background */ + --codinit-elements-sidebar-buttonBackgroundHover: rgba(59, 130, 246, 0.15); + /* Blue hover */ + --codinit-elements-sidebar-buttonText: #3b82f6; + /* Blue accent */ /* Preview Address Bar - Compatible with undertone */ - --codinit-elements-preview-addressBar-background: var( - --codinit-elements-bg-depth-2 - ); /* Use depth-2 for consistency */ - --codinit-elements-preview-addressBar-backgroundHover: rgba(255, 255, 255, 0.05); /* Subtle hover */ - --codinit-elements-preview-addressBar-backgroundActive: var( - --codinit-elements-bg-depth-1 - ); /* Use depth-1 for active */ + --codinit-elements-preview-addressBar-background: var(--codinit-elements-bg-depth-2); + /* Use depth-2 for consistency */ + --codinit-elements-preview-addressBar-backgroundHover: rgba(255, 255, 255, 0.05); + /* Subtle hover */ + --codinit-elements-preview-addressBar-backgroundActive: var(--codinit-elements-bg-depth-1); + /* Use depth-1 for active */ --codinit-elements-preview-addressBar-text: var(--codinit-elements-textSecondary); --codinit-elements-preview-addressBar-textActive: var(--codinit-elements-textPrimary); /* Terminals - Neutral gray */ - --codinit-elements-terminals-background: var(--codinit-elements-bg-depth-1); /* Use depth-1 for terminal background */ - --codinit-elements-terminals-buttonBackground: var(--codinit-elements-bg-depth-3); /* Use depth-3 for buttons */ + --codinit-elements-terminals-background: var(--codinit-elements-bg-depth-1); + /* Use depth-1 for terminal background */ + --codinit-elements-terminals-buttonBackground: var(--codinit-elements-bg-depth-3); + /* Use depth-3 for buttons */ - --codinit-elements-cta-background: var(--codinit-elements-bg-depth-3); /* Use depth-3 for CTA */ + --codinit-elements-cta-background: var(--codinit-elements-bg-depth-3); + /* Use depth-3 for CTA */ --codinit-elements-cta-text: #ffffff; /* Terminal Colors - Pure neutral gray */ - --codinit-terminal-background: var(--codinit-elements-terminals-background); /* Inherit from terminal background */ - --codinit-terminal-foreground: #ffffff; /* Pure white foreground */ - --codinit-terminal-selection-background: rgba(204, 204, 204, 0.2); /* Neutral gray selection */ - --codinit-terminal-black: #000000; /* Pure black */ - --codinit-terminal-red: #ff7b72; /* Brighter red */ - --codinit-terminal-green: #76d974; /* Brighter green */ - --codinit-terminal-yellow: #e2e27a; /* Brighter yellow */ - --codinit-terminal-blue: #63a3ff; /* Brighter blue */ - --codinit-terminal-magenta: #ff79c6; /* Brighter magenta */ - --codinit-terminal-cyan: #98d4ca; /* Brighter cyan */ - --codinit-terminal-white: #ffffff; /* Pure white */ - --codinit-terminal-brightBlack: #555555; /* Neutral gray */ - --codinit-terminal-brightRed: #ff7b72; /* Brighter red */ - --codinit-terminal-brightGreen: #76d974; /* Brighter green */ - --codinit-terminal-brightYellow: #e2e27a; /* Brighter yellow */ - --codinit-terminal-brightBlue: #63a3ff; /* Brighter blue */ - --codinit-terminal-brightMagenta: #ff79c6; /* Brighter magenta */ - --codinit-terminal-brightCyan: #98d4ca; /* Brighter cyan */ - --codinit-terminal-brightWhite: #ffffff; /* Pure white */ - --modern-scrollbar-thumb-background: rgba(153, 153, 153, 0.3); /* Neutral gray thumb */ - --modern-scrollbar-thumb-backgroundHover: rgba(153, 153, 153, 0.5); /* More opaque on hover */ + --codinit-terminal-background: var(--codinit-elements-terminals-background); + /* Inherit from terminal background */ + --codinit-terminal-foreground: #ffffff; + /* Pure white foreground */ + --codinit-terminal-selection-background: rgba(204, 204, 204, 0.2); + /* Neutral gray selection */ + --codinit-terminal-black: #000000; + /* Pure black */ + --codinit-terminal-red: #ff7b72; + /* Brighter red */ + --codinit-terminal-green: #76d974; + /* Brighter green */ + --codinit-terminal-yellow: #e2e27a; + /* Brighter yellow */ + --codinit-terminal-blue: #63a3ff; + /* Brighter blue */ + --codinit-terminal-magenta: #ff79c6; + /* Brighter magenta */ + --codinit-terminal-cyan: #98d4ca; + /* Brighter cyan */ + --codinit-terminal-white: #ffffff; + /* Pure white */ + --codinit-terminal-brightBlack: #555555; + /* Neutral gray */ + --codinit-terminal-brightRed: #ff7b72; + /* Brighter red */ + --codinit-terminal-brightGreen: #76d974; + /* Brighter green */ + --codinit-terminal-brightYellow: #e2e27a; + /* Brighter yellow */ + --codinit-terminal-brightBlue: #63a3ff; + /* Brighter blue */ + --codinit-terminal-brightMagenta: #ff79c6; + /* Brighter magenta */ + --codinit-terminal-brightCyan: #98d4ca; + /* Brighter cyan */ + --codinit-terminal-brightWhite: #ffffff; + /* Pure white */ + --modern-scrollbar-thumb-background: rgba(153, 153, 153, 0.3); + /* Neutral gray thumb */ + --modern-scrollbar-thumb-backgroundHover: rgba(153, 153, 153, 0.5); + /* More opaque on hover */ /* Command/Dialog popover variables - Dark Theme - neutral gray aligned */ - --background: 0 0% 7%; /* #121212 */ + --background: 0 0% 7%; + /* #121212 */ --foreground: 0 0% 98%; - --card: 0 0% 10%; /* #1a1a1a */ + --card: 0 0% 10%; + /* #1a1a1a */ --card-foreground: 0 0% 98%; - --popover: 0 0% 10%; /* #1a1a1a */ + --popover: 0 0% 10%; + /* #1a1a1a */ --popover-foreground: 0 0% 98%; --primary: 217.2 91.2% 59.8%; --primary-foreground: 0 0% 98%; - --secondary: 0 0% 14%; /* #242424 */ + --secondary: 0 0% 14%; + /* #242424 */ --secondary-foreground: 0 0% 98%; - --muted: 0 0% 14%; /* #242424 */ + --muted: 0 0% 14%; + /* #242424 */ --muted-foreground: 0 0% 64%; - --accent: 0 0% 18%; /* #2e2e2e */ + --accent: 0 0% 18%; + /* #2e2e2e */ --accent-foreground: 0 0% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; - --border: 0 0% 23%; /* #3a3a3a */ - --input: 0 0% 18%; /* #2e2e2e */ + --border: 0 0% 23%; + /* #3a3a3a */ + --input: 0 0% 18%; + /* #2e2e2e */ --ring: 217.2 91.2% 59.8%; } @@ -290,7 +358,7 @@ * Hierarchy: Element Token -> (Element Token | Color Tokens) -> Primitives */ :root { - --header-height: 54px; + --header-height: 48px; --chat-max-width: 36rem; --chat-min-width: 533px; --workbench-width: min(calc(100% - var(--chat-min-width)), 3000px); From 5676013767f1292bf5a185957ef858373c7a40c2 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Thu, 25 Dec 2025 20:59:54 +1100 Subject: [PATCH 023/200] feat: implement Pro subscription state management with API verification Create Nanostores-based pro.ts store for managing Pro tier status, credits, and feature flags. Include API key verification function that communicates with CodinIT backend for user info retrieval. --- app/lib/stores/pro.ts | 77 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 app/lib/stores/pro.ts diff --git a/app/lib/stores/pro.ts b/app/lib/stores/pro.ts new file mode 100644 index 00000000..c145c5d2 --- /dev/null +++ b/app/lib/stores/pro.ts @@ -0,0 +1,77 @@ +import { map } from 'nanostores'; + +export interface ProState { + isPro: boolean; + tier: 'free' | 'pro'; + credits: { + total: number; + used: number; + }; + features: { + webSearch: boolean; + lazyEdits: boolean; + }; +} + +export const proStore = map({ + isPro: false, + tier: 'free', + credits: { + total: 0, + used: 0, + }, + features: { + webSearch: false, + lazyEdits: false, + }, +}); + +export const setProState = (state: Partial) => { + proStore.set({ + ...proStore.get(), + ...state, + }); +}; + +export const toggleFeature = (feature: keyof ProState['features']) => { + const currentState = proStore.get(); + proStore.setKey('features', { + ...currentState.features, + [feature]: !currentState.features[feature], + }); +}; + +export const verifyProKey = async (apiKey: string, baseUrl: string = 'https://api.codinit.dev/v1') => { + try { + const response = await fetch(`${baseUrl}/user/info`, { + headers: { + Authorization: `Bearer ${apiKey}`, + }, + }); + + if (!response.ok) { + throw new Error('Invalid API Key or backend unreachable'); + } + + const data = (await response.json()) as { + tier: 'free' | 'pro'; + totalCredits: number; + usedCredits: number; + }; + + setProState({ + isPro: data.tier === 'pro', + tier: data.tier, + credits: { + total: data.totalCredits, + used: data.usedCredits, + }, + }); + + return data; + } catch (error) { + console.error('Pro verification failed:', error); + setProState({ isPro: false, tier: 'free' }); + throw error; + } +}; From 473800eacf1edde9b46648338eff4d231849ee22 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Thu, 25 Dec 2025 21:00:21 +1100 Subject: [PATCH 024/200] refactor: adjust workbench positioning and remove padding for edge-to-edge layout Align workbench top position with updated header height variable. Remove horizontal padding and add left border for cleaner edge-to-edge design that matches the new header styling. --- app/components/workbench/Workbench.client.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/workbench/Workbench.client.tsx b/app/components/workbench/Workbench.client.tsx index 22dc2a47..5d413522 100644 --- a/app/components/workbench/Workbench.client.tsx +++ b/app/components/workbench/Workbench.client.tsx @@ -134,7 +134,7 @@ export const Workbench = memo( >
-
-
+
+
Date: Thu, 25 Dec 2025 21:39:49 +1100 Subject: [PATCH 025/200] added browser mapping --- app/components/chat/Chatbox.tsx | 2 +- package.json | 1 + pnpm-lock.yaml | 11 +++++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/components/chat/Chatbox.tsx b/app/components/chat/Chatbox.tsx index e84ff87f..f9d16b4e 100644 --- a/app/components/chat/Chatbox.tsx +++ b/app/components/chat/Chatbox.tsx @@ -430,7 +430,7 @@ export const ChatBox: React.FC = (props) => { )} onClick={() => { if (props.provider?.name !== 'CodinIT') { - toast.info('Web Search is a Pro feature available with CodinIT Pro provider.'); + toast.info('Web Search is a Pro feature coming soon...'); return; } diff --git a/package.json b/package.json index 30a59ef9..9200edd9 100644 --- a/package.json +++ b/package.json @@ -191,6 +191,7 @@ "@types/react-window": "^1.8.8", "@vitejs/plugin-react": "^4.7.0", "@vitest/browser": "^3.1.0", + "baseline-browser-mapping": "^2.9.11", "concurrently": "^8.2.2", "cross-env": "^7.0.3", "electron": "^35.7.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01badcd3..5a3f685e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -437,6 +437,9 @@ importers: '@vitest/browser': specifier: ^3.1.0 version: 3.2.4(playwright@1.56.1)(vite@5.4.21(@types/node@22.18.12)(sass-embedded@1.93.2)(sass@1.93.2))(vitest@3.2.4) + baseline-browser-mapping: + specifier: ^2.9.11 + version: 2.9.11 concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -4134,8 +4137,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.20: - resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==} + baseline-browser-mapping@2.9.11: + resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} hasBin: true basic-auth@2.0.1: @@ -12963,7 +12966,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.8.20: {} + baseline-browser-mapping@2.9.11: {} basic-auth@2.0.1: dependencies: @@ -13094,7 +13097,7 @@ snapshots: browserslist@4.27.0: dependencies: - baseline-browser-mapping: 2.8.20 + baseline-browser-mapping: 2.9.11 caniuse-lite: 1.0.30001751 electron-to-chromium: 1.5.240 node-releases: 2.0.26 From 1fccf5a813a40240302163cd1bdb0d9baf6145a1 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Fri, 26 Dec 2025 19:05:09 +1100 Subject: [PATCH 026/200] redesign artifact component with modernized card layout and improved animations --- app/components/chat/Artifact.tsx | 129 +++++++++++++++---------------- 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/app/components/chat/Artifact.tsx b/app/components/chat/Artifact.tsx index b30a7318..a099b222 100644 --- a/app/components/chat/Artifact.tsx +++ b/app/components/chat/Artifact.tsx @@ -78,82 +78,77 @@ export const Artifact = memo(({ messageId }: ArtifactProps) => { : artifact?.title; return ( - <> -
-
- - {artifact.type !== 'bundled' &&
} - - {actions.length && artifact.type !== 'bundled' && ( +
+ Click to open Webview +
+
+ + + {actions.length > 0 && artifact.type !== 'bundled' && ( + <> +
+
-
-
-
+
+
+ + )} +
+ + {artifact.type === 'bundled' && ( +
+
+ {allActionFinished ? ( +
+ ) : ( +
)} - +
+
+ {allActionFinished + ? artifact.id === 'restored-project-setup' + ? 'Restore files from snapshot' + : 'Initial files created' + : 'Creating initial files'} +
- {artifact.type === 'bundled' && ( -
-
- {allActionFinished ? ( -
- ) : ( -
- )} -
-
- {/* This status text remains the same */} - {allActionFinished - ? artifact.id === 'restored-project-setup' - ? 'Restore files from snapshot' - : 'Initial files created' - : 'Creating initial files'} + )} + + + {artifact.type !== 'bundled' && showActions && actions.length > 0 && ( + +
+
-
+ )} - - {artifact.type !== 'bundled' && showActions && actions.length > 0 && ( - -
- -
- -
- - )} - -
- +
+
); }); From 90f6f5ec5f9871963a59aa4dd9c77f6f92cc5c25 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Fri, 26 Dec 2025 19:05:11 +1100 Subject: [PATCH 027/200] simplify shadow gradient and clean up spacing in base chat styles --- app/components/chat/BaseChat.module.scss | 43 +++++++----------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/app/components/chat/BaseChat.module.scss b/app/components/chat/BaseChat.module.scss index 694afef9..72dd0736 100644 --- a/app/components/chat/BaseChat.module.scss +++ b/app/components/chat/BaseChat.module.scss @@ -47,25 +47,10 @@ } ._Shadow_8mvus_1 { - background: linear-gradient( - to top, - var(--codinit-elements-bg-depth-1) 0%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 98.7%, transparent) 8.1%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 95.1%, transparent) 15.5%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 89.6%, transparent) 22.5%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 82.5%, transparent) 29%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 74.1%, transparent) 35.3%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 64.8%, transparent) 41.2%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 55%, transparent) 47.1%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 45%, transparent) 52.9%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 35.2%, transparent) 58.8%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 25.9%, transparent) 64.7%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 17.5%, transparent) 71%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 10.4%, transparent) 77.5%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 4.9%, transparent) 84.5%, - color-mix(in srgb, var(--codinit-elements-bg-depth-1) 1.3%, transparent) 91.9%, - transparent 100% - ); + background: linear-gradient(to bottom, + var(--codinit-elements-bg-depth-1) 0%, + transparent 100%); + height: 24px; } *:has(+ ._StickyPinnedMessage_rq7xp_1) { @@ -104,7 +89,7 @@ margin-block-end: 16px; } -._MigrationSummary_1ebkv_1 ul li > ul { +._MigrationSummary_1ebkv_1 ul li>ul { margin-block-start: 4px; padding-left: 0.75rem; } @@ -116,7 +101,7 @@ margin-block-end: 6px; } -._MigrationSummary_1ebkv_1 ol + ul { +._MigrationSummary_1ebkv_1 ol+ul { padding-left: 2rem; } @@ -268,14 +253,12 @@ transform: translate(-50%); height: 2px; width: 100px; - background: linear-gradient( - 90deg, - transparent 0%, - var(--codinit-elements-borderColor) 20%, - var(--codinit-elements-textPrimary) 50%, - var(--codinit-elements-borderColor) 80%, - transparent 100% - ); + background: linear-gradient(90deg, + transparent 0%, + var(--codinit-elements-borderColor) 20%, + var(--codinit-elements-textPrimary) 50%, + var(--codinit-elements-borderColor) 80%, + transparent 100%); opacity: 0.6; transition: opacity 0.6s cubic-bezier(0.32, 0.72, 0, 1), @@ -376,4 +359,4 @@ opacity: 1; transform: translateY(0); } -} +} \ No newline at end of file From 405548c7860476655d44b9819dba3f6c06aef4a7 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Fri, 26 Dec 2025 19:05:17 +1100 Subject: [PATCH 028/200] implement animated workbench header with synchronized width transitions --- app/components/chat/BaseChat.tsx | 133 ++++++++++++++++++------------- 1 file changed, 77 insertions(+), 56 deletions(-) diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 5273377c..363a4401 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -6,6 +6,8 @@ import type { JSONValue, Message } from 'ai'; import React, { lazy, Suspense, type RefCallback, useEffect, useState } from 'react'; import { ClientOnly } from 'remix-utils/client-only'; import { Menu } from '~/components/sidebar/Menu.client'; +import { motion } from 'framer-motion'; +import { cubicEasingFn } from '~/utils/easings'; const Workbench = lazy(() => import('~/components/workbench/Workbench.client').then((module) => ({ @@ -447,69 +449,88 @@ export const BaseChat = React.forwardRef( > {() => } - {/* Unified Header Container - spans full width */} {chatStarted && (
- {/* Chat Header Section - constrained to chat width */} -
+ {/* Chat Header Section - Syncs with Chat Panel */} +
- {/* Workbench Header Section - fills remaining space */} -
- {selectedView === 'code' && ( - { - workbenchStore.downloadZip(); + {/* Workbench Header Section - Syncs with Workbench Panel */} + + {() => ( + setIsSyncing(true)} - onPushToGitHub={() => setIsPushDialogOpen(true)} - isSyncing={isSyncing} - setIsPushDialogOpen={setIsPushDialogOpen} - /> - )} - - {selectedView === 'preview' && ( - - )} - - {selectedView === 'diff' && selectedFile && currentDocument && ( - setIsDiffFullscreen(!isDiffFullscreen)} - /> + className="overflow-hidden" + > +
+ {selectedView === 'code' && ( + { + workbenchStore.downloadZip(); + }} + onSyncFiles={() => setIsSyncing(true)} + onPushToGitHub={() => setIsPushDialogOpen(true)} + isSyncing={isSyncing} + setIsPushDialogOpen={setIsPushDialogOpen} + /> + )} + + {selectedView === 'preview' && ( + + )} + + {selectedView === 'diff' && selectedFile && currentDocument && ( + setIsDiffFullscreen(!isDiffFullscreen)} + /> + )} +
+
)} -
+
)} From 197b2701c8eb450c3f040c12c72495212757702d Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Fri, 26 Dec 2025 19:05:20 +1100 Subject: [PATCH 029/200] integrate Pro subscription state in chat API requests --- app/components/chat/Chat.client.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/components/chat/Chat.client.tsx b/app/components/chat/Chat.client.tsx index 18addabb..6f40a10c 100644 --- a/app/components/chat/Chat.client.tsx +++ b/app/components/chat/Chat.client.tsx @@ -28,6 +28,7 @@ import type { DesignScheme } from '~/types/design-scheme'; import type { ElementInfo } from '~/components/workbench/Inspector'; import type { TextUIPart, FileUIPart, Attachment } from '@ai-sdk/ui-utils'; import { useMCPStore } from '~/lib/stores/mcp'; +import { proStore } from '~/lib/stores/pro'; import type { LlmErrorAlertType } from '~/types/actions'; const logger = createScopedLogger('Chat'); @@ -140,6 +141,7 @@ export const ChatImpl = memo( } = useChat({ api: '/api/chat', body: { + isPro: proStore.get().isPro, apiKeys, files, promptId, From 6c44ad4ba9c9ce6097cedacf593b3d772b06d2e2 Mon Sep 17 00:00:00 2001 From: Gerome-Elassaad Date: Fri, 26 Dec 2025 19:05:23 +1100 Subject: [PATCH 030/200] reorganize chatbox layout with send button positioned in bottom toolbar --- app/components/chat/Chatbox.tsx | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/components/chat/Chatbox.tsx b/app/components/chat/Chatbox.tsx index f9d16b4e..1d85aa58 100644 --- a/app/components/chat/Chatbox.tsx +++ b/app/components/chat/Chatbox.tsx @@ -179,7 +179,7 @@ export const ChatBox: React.FC = (props) => { <>
= (props) => {