diff --git a/.github/workflows/claude-issue-triage.yml b/.github/workflows/claude-issue-triage.yml index a2683c99..bf30dc25 100644 --- a/.github/workflows/claude-issue-triage.yml +++ b/.github/workflows/claude-issue-triage.yml @@ -165,7 +165,7 @@ jobs: ### STAGE 3: Solution Proposal (CONDITIONAL)${{ steps.analyze.outputs.severity == 'high' && '\n\n**⚠️ REQUIRED** - Critical issue, must propose fix' || '\n\n**OPTIONAL** - Propose fix if solution is clear and straightforward' }} - ${{ steps.analyze.outputs.severity == 'high' && '**You MUST propose a fix for this critical issue:**' || '**Propose a fix only if:**\n- Root cause is clear\n- Fix is straightforward (< 50 lines changed)\n- You\'re confident it won\'t introduce regressions' }} + ${{ steps.analyze.outputs.severity == 'high' && '**You MUST propose a fix for this critical issue:**' || '**Propose a fix only if:**\n- Root cause is clear\n- Fix is straightforward (< 50 lines changed)\n- You''re confident it won''t introduce regressions' }} #### 3.1 Design the Fix @@ -249,7 +249,7 @@ jobs: **Comment Structure** (adapt based on investigation depth): - ${{ steps.analyze.outputs.should_investigate == 'true' && '**For investigated issues:**\n\n```markdown\n## Investigation Results\n\nThanks for reporting this, @${{ github.event.issue.user.login }}! I\'ve performed a thorough analysis.\n\n### Classification\n- **Type:** [bug/feature/etc]\n- **Severity:** [P0-critical/P1-high/etc]\n- **Component:** [worker/ui/etc]\n\n### Root Cause Analysis\n[Detailed explanation of what\'s causing the issue]\n\n**Location:** `path/to/file.ts:123`\n\n**Introduced in:** PR #XXX (if found) or Commit ABC123\n\n### Proposed Solution\n[Explain the fix approach]\n\n### Status\n- ✅ PR #XXX created with proposed fix (if applicable)\n- ⏳ Requires manual review and testing\n- 📋 Added to backlog for team review (if no PR)\n\n### Next Steps\n[What happens next - PR review, team discussion, etc.]\n```' || '**For standard triage:**\n\n```markdown\nThanks for reporting this, @${{ github.event.issue.user.login }}!\n\n### Classification\n- **Labels:** [list applied labels]\n- **Priority:** [explanation of priority]\n\n[Context-specific response based on issue type]\n\n### Next Steps\nThe team will review this and provide updates.\n```' }} + ${{ steps.analyze.outputs.should_investigate == 'true' && '**For investigated issues:**\n\n```markdown\n## Investigation Results\n\nThanks for reporting this, @${{ github.event.issue.user.login }}! I''ve performed a thorough analysis.\n\n### Classification\n- **Type:** [bug/feature/etc]\n- **Severity:** [P0-critical/P1-high/etc]\n- **Component:** [worker/ui/etc]\n\n### Root Cause Analysis\n[Detailed explanation of what''s causing the issue]\n\n**Location:** `path/to/file.ts:123`\n\n**Introduced in:** PR #XXX (if found) or Commit ABC123\n\n### Proposed Solution\n[Explain the fix approach]\n\n### Status\n- ✅ PR #XXX created with proposed fix (if applicable)\n- ⏳ Requires manual review and testing\n- 📋 Added to backlog for team review (if no PR)\n\n### Next Steps\n[What happens next - PR review, team discussion, etc.]\n```' || '**For standard triage:**\n\n```markdown\nThanks for reporting this, @${{ github.event.issue.user.login }}!\n\n### Classification\n- **Labels:** [list applied labels]\n- **Priority:** [explanation of priority]\n\n[Context-specific response based on issue type]\n\n### Next Steps\nThe team will review this and provide updates.\n```' }} --- diff --git a/.github/workflows/claude-reviews.yml b/.github/workflows/claude-reviews.yml index 0117ff8f..f85694c1 100644 --- a/.github/workflows/claude-reviews.yml +++ b/.github/workflows/claude-reviews.yml @@ -45,32 +45,6 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Minimize Old Review Comments - run: | - echo "Collapsing previous review comments from github-actions[bot]..." - - # Get all comments from github-actions[bot] on this PR - OLD_REVIEWS=$(gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \ - --jq '[.[] | select(.user.login == "github-actions[bot]") | select(.body | contains("## Code Review") or contains("🔒 **CRITICAL PATH SECURITY REVIEW**") or contains("## 🔍 Code Quality & Security Review")) | .id]') - - if [ -n "$OLD_REVIEWS" ] && [ "$OLD_REVIEWS" != "[]" ]; then - echo "Found old review comments to collapse" - echo "$OLD_REVIEWS" | jq -r '.[]' | while read comment_id; do - echo "Collapsing comment $comment_id" - gh api repos/${{ github.repository }}/issues/comments/$comment_id -X PATCH \ - -f body="
🔒 Previous review (outdated) - - This review has been superseded by a newer review. -
" || echo "Failed to collapse comment $comment_id" - done - echo "✓ Old comments collapsed" - else - echo "No old review comments found" - fi - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - continue-on-error: true - - name: Run Comprehensive Review uses: anthropics/claude-code-action@v1 with: @@ -137,16 +111,8 @@ jobs: [Overall assessment with approval/disapproval reasoning] ``` - 5. Post review (MANDATORY FINAL STEP - use single efficient command) + 5. Post review (MANDATORY FINAL STEP) ```bash - # Post new review (collapse old ones first if any exist) - OLD_IDS=$(gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '[.[] | select(.user.login == "github-actions[bot]") | select(.body | startswith("## Code & Security Review")) | .id] | @csv' | tr -d '"') - if [ -n "$OLD_IDS" ]; then - for id in ${OLD_IDS//,/ }; do - gh api -X PATCH repos/${{ github.repository }}/issues/comments/$id -f body="
Outdated
" & - done - wait - fi gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "YOUR_REVIEW_HERE" ``` @@ -180,3 +146,42 @@ jobs: --allowed-tools "mcp__github_inline_comment__create_inline_comment,Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh search:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr edit:*),Bash(gh api:*)" --max-turns ${{ steps.critical_paths.outputs.is_critical == 'true' && '90' || '65' }} --model claude-sonnet-4-5-20250929 + + - name: Intelligent Comment Cleanup + uses: anthropics/claude-code-action@v1 + if: always() + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + prompt: | + Clean up stale bot comments on PR #${{ github.event.pull_request.number }}. + + **Task:** + 1. Fetch all comments on this PR + 2. Identify bot comments (users ending in [bot]) that are stale/outdated: + - Old reviews superseded by newer ones + - Old PR description suggestions + - Previously collapsed/outdated markers + - Progress/status comments from previous workflow runs + 3. Keep only the most recent comment per category per bot + 4. DELETE all stale comments (do not collapse) + + **Get all comments:** + ```bash + gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '.[] | {id, user: .user.login, body, created_at}' + ``` + + **Delete a comment:** + ```bash + gh api repos/${{ github.repository }}/issues/comments/COMMENT_ID -X DELETE + ``` + + Be intelligent: + - Preserve the newest useful comment in each category + - Delete everything else that's redundant or stale + - If unsure, keep the comment (conservative approach) + + claude_args: | + --allowed-tools "Bash(gh api repos/*/issues/*/comments:*),Bash(gh api repos/*/issues/comments/*:*)" + --max-turns 8 + --model claude-haiku-4-5-20251001 diff --git a/.husky/commit-msg b/.husky/commit-msg index 3b9e0aa4..2e99098d 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1 +1,10 @@ -bunx commitlint --edit $1 +# Add common bun installation paths to PATH +export PATH="/opt/homebrew/bin:$HOME/.bun/bin:$PATH" + +# Run commitlint if bunx is available +if command -v bunx >/dev/null 2>&1; then + bunx commitlint --edit $1 +else + echo "⚠️ bunx not found in PATH, skipping commitlint" + exit 0 +fi diff --git a/.husky/pre-commit b/.husky/pre-commit index 4dfead07..eac0326d 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,10 @@ -bun test +# Add common bun installation paths to PATH +export PATH="/opt/homebrew/bin:$HOME/.bun/bin:$PATH" + +# Run tests with bun +if command -v bun >/dev/null 2>&1; then + bun test +else + echo "⚠️ bun not found in PATH, skipping tests" + exit 0 +fi diff --git a/SandboxDockerfile b/SandboxDockerfile index 9bd45e9d..10daa45e 100644 --- a/SandboxDockerfile +++ b/SandboxDockerfile @@ -52,7 +52,6 @@ RUN chmod 755 /workspace/data # Set environment variable to indicate Docker container environment ENV CONTAINER_ENV=docker ENV VITE_LOGGER_TYPE=json - # # Set environment variable to indicate Docker container environment # ENV CONTAINER_ENV=docker diff --git a/src/components/config-modal.tsx b/src/components/config-modal.tsx index d7c7d980..e4092f96 100644 --- a/src/components/config-modal.tsx +++ b/src/components/config-modal.tsx @@ -68,18 +68,18 @@ const getModelDisplayName = (model: AIModels | string): string => { // Model recommendations by agent const getModelRecommendation = (agentAction: string) => { const recommendations: Record = { - templateSelection: '💡 Recommended: Fast models for quick template selection', - blueprint: '🏗️ Recommended: Creative models for architecture design', - projectSetup: '⚙️ Recommended: Reliable models for precise setup', - phaseGeneration: '📋 Recommended: Large context models for comprehensive planning', - firstPhaseImplementation: '🏁 Recommended: High-capability models for foundation development', - phaseImplementation: '⚡ Recommended: Strong coding models for implementation', - realtimeCodeFixer: '🚀 Recommended: Fast debugging models', - fastCodeFixer: '⚡ Recommended: Ultra-fast models for quick fixes', - conversationalResponse: '💬 Recommended: Balanced models for natural conversation', - codeReview: '🔍 Recommended: Analytical models with large context', - fileRegeneration: '📝 Recommended: Pure coding models', - screenshotAnalysis: '👁️ Recommended: Vision-capable models for image analysis' + templateSelection: 'Recommended: Fast models for quick template selection', + blueprint: 'Recommended: Creative models for architecture design', + projectSetup: 'Recommended: Reliable models for precise setup', + phaseGeneration: 'Recommended: Large context models for comprehensive planning', + firstPhaseImplementation: 'Recommended: High-capability models for foundation development', + phaseImplementation: 'Recommended: Strong coding models for implementation', + realtimeCodeFixer: 'Recommended: Fast debugging models', + fastCodeFixer: 'Recommended: Ultra-fast models for quick fixes', + conversationalResponse: 'Recommended: Balanced models for natural conversation', + codeReview: 'Recommended: Analytical models with large context', + fileRegeneration: 'Recommended: Pure coding models', + screenshotAnalysis: 'Recommended: Vision-capable models for image analysis' }; return recommendations[agentAction] || ''; }; @@ -98,7 +98,6 @@ export function ConfigModal({ // Form state const [formData, setFormData] = useState({ modelName: userConfig?.name || 'default', - maxTokens: userConfig?.max_tokens?.toString() || '', temperature: userConfig?.temperature?.toString() || '', reasoningEffort: userConfig?.reasoning_effort || 'default', fallbackModel: userConfig?.fallbackModel || 'default' @@ -115,11 +114,12 @@ export function ConfigModal({ const [byokData, setByokData] = useState(null); const [loadingByok, setLoadingByok] = useState(false); - // Load BYOK data + // Load BYOK data (filtered by agent constraints) const loadByokData = async () => { try { setLoadingByok(true); - const response = await apiClient.getByokProviders(); + // Pass agent key to get constraint-filtered models + const response = await apiClient.getByokProviders(agentConfig.key); if (response.success && response.data) { setByokData(response.data); } @@ -136,7 +136,6 @@ export function ConfigModal({ // First time opening - reset everything and load data setFormData({ modelName: userConfig?.name || 'default', - maxTokens: userConfig?.max_tokens?.toString() || '', temperature: userConfig?.temperature?.toString() || '', reasoningEffort: userConfig?.reasoning_effort || 'default', fallbackModel: userConfig?.fallbackModel || 'default' @@ -162,7 +161,6 @@ export function ConfigModal({ useEffect(() => { const originalFormData = { modelName: userConfig?.name || 'default', - maxTokens: userConfig?.max_tokens?.toString() || '', temperature: userConfig?.temperature?.toString() || '', reasoningEffort: userConfig?.reasoning_effort || 'default', fallbackModel: userConfig?.fallbackModel || 'default' @@ -246,7 +244,6 @@ export function ConfigModal({ const buildCurrentConfig = (): ModelConfigUpdate => { return { ...(formData.modelName !== 'default' && { modelName: formData.modelName }), - ...(formData.maxTokens && { maxTokens: parseInt(formData.maxTokens) }), ...(formData.temperature && { temperature: parseFloat(formData.temperature) }), ...(formData.reasoningEffort !== 'default' && { reasoningEffort: formData.reasoningEffort }), ...(formData.fallbackModel !== 'default' && { fallbackModel: formData.fallbackModel }), @@ -289,19 +286,31 @@ export function ConfigModal({ Configure {agentConfig.name} - -

{agentConfig.description}

- {getModelRecommendation(agentConfig.key) && ( - - - - {getModelRecommendation(agentConfig.key)} - - - )} + + {agentConfig.description} + {/* Alerts outside DialogDescription to avoid nested p/div issues */} +
+ {agentConfig.constraint?.enabled && ( + + + + Model selection limited to {agentConfig.constraint.allowedModels.length} allowed model{agentConfig.constraint.allowedModels.length !== 1 ? 's' : ''} for this operation. + + + )} + {getModelRecommendation(agentConfig.key) && ( + + + + {getModelRecommendation(agentConfig.key)} + + + )} +
+
{/* Current Status */}
@@ -428,7 +437,7 @@ export function ConfigModal({

Parameters

-
+
{/* Temperature */}
@@ -449,25 +458,6 @@ export function ConfigModal({ )}
- {/* Max Tokens */} -
- - setFormData({...formData, maxTokens: e.target.value})} - className="h-10" - /> - {defaultConfig?.max_tokens && ( -

- 🔧 Default: {defaultConfig.max_tokens?.toLocaleString()} -

- )} -
- {/* Reasoning Effort */}
diff --git a/src/components/model-config-tabs.tsx b/src/components/model-config-tabs.tsx index 1b957a7d..5e2b7b38 100644 --- a/src/components/model-config-tabs.tsx +++ b/src/components/model-config-tabs.tsx @@ -117,11 +117,15 @@ const categorizeAgent = (agentKey: string): string => { return 'advanced'; }; -// Frontend-specific agent display interface +// Frontend-specific agent display interface export interface AgentDisplayConfig { key: string; name: string; description: string; + constraint?: { + enabled: boolean; + allowedModels: string[]; + }; } interface ModelConfigTabsProps { diff --git a/src/components/monaco-editor/monaco-editor.tsx b/src/components/monaco-editor/monaco-editor.tsx index 5777877e..b4900047 100644 --- a/src/components/monaco-editor/monaco-editor.tsx +++ b/src/components/monaco-editor/monaco-editor.tsx @@ -36,7 +36,7 @@ self.MonacoEnvironment = { }; // From GitHub Dark theme -monaco.editor.defineTheme('v1-dev-dark', { +monaco.editor.defineTheme('vibesdk-dark', { base: 'vs-dark', inherit: true, rules: [ @@ -77,7 +77,7 @@ monaco.editor.defineTheme('v1-dev-dark', { }, }); -monaco.editor.defineTheme('v1-dev', { +monaco.editor.defineTheme('vibesdk', { base: 'vs', inherit: true, rules: [ @@ -116,43 +116,13 @@ monaco.editor.defineTheme('v1-dev', { }, }); -monaco.editor.setTheme('v1-dev'); - -monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ - noSemanticValidation: true, - noSyntaxValidation: true, -}); - -// Configure TypeScript defaults for JSX support -monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ - jsx: monaco.languages.typescript.JsxEmit.React, - allowJs: true, - allowSyntheticDefaultImports: true, - esModuleInterop: true, - moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, - module: monaco.languages.typescript.ModuleKind.ESNext, - target: monaco.languages.typescript.ScriptTarget.ESNext, - jsxFactory: 'React.createElement', - jsxFragmentFactory: 'React.Fragment', -}); - -// Configure JavaScript defaults for JSX support -monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ - allowJs: true, - allowSyntheticDefaultImports: true, - esModuleInterop: true, - jsx: monaco.languages.typescript.JsxEmit.React, - moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, - module: monaco.languages.typescript.ModuleKind.ESNext, - target: monaco.languages.typescript.ScriptTarget.ESNext, - jsxFactory: 'React.createElement', - jsxFragmentFactory: 'React.Fragment', -}); +monaco.editor.setTheme('vibesdk'); export type MonacoEditorProps = React.ComponentProps<'div'> & { createOptions?: monaco.editor.IStandaloneEditorConstructionOptions; find?: string; replace?: string; + enableTypeScriptFeatures?: 'auto' | boolean; }; /** @@ -163,6 +133,7 @@ export const MonacoEditor = memo(function MonacoEditor({ createOptions = {}, find, replace, + enableTypeScriptFeatures = 'auto', ...props }) { const containerRef = useRef(null); @@ -171,6 +142,63 @@ export const MonacoEditor = memo(function MonacoEditor({ const stickyScroll = useRef(true); const { theme } = useTheme(); + const shouldEnableTypeScript = React.useMemo(() => { + if (enableTypeScriptFeatures === 'auto') { + return !createOptions.readOnly; + } + return enableTypeScriptFeatures; + }, [enableTypeScriptFeatures, createOptions.readOnly]); + + // Configure TypeScript diagnostics based on mode + useEffect(() => { + const tsDefaults = monaco.languages.typescript.typescriptDefaults; + const jsDefaults = monaco.languages.typescript.javascriptDefaults; + + if (shouldEnableTypeScript) { + // Enable full IntelliSense for editing + tsDefaults.setDiagnosticsOptions({ + noSemanticValidation: false, + noSyntaxValidation: false, + }); + tsDefaults.setCompilerOptions({ + jsx: monaco.languages.typescript.JsxEmit.React, + allowJs: true, + allowSyntheticDefaultImports: true, + esModuleInterop: true, + moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, + module: monaco.languages.typescript.ModuleKind.ESNext, + target: monaco.languages.typescript.ScriptTarget.ESNext, + jsxFactory: 'React.createElement', + jsxFragmentFactory: 'React.Fragment', + }); + jsDefaults.setCompilerOptions({ + allowJs: true, + allowSyntheticDefaultImports: true, + esModuleInterop: true, + jsx: monaco.languages.typescript.JsxEmit.React, + moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, + module: monaco.languages.typescript.ModuleKind.ESNext, + target: monaco.languages.typescript.ScriptTarget.ESNext, + jsxFactory: 'React.createElement', + jsxFragmentFactory: 'React.Fragment', + }); + } else { + // Disable expensive features for viewing + tsDefaults.setDiagnosticsOptions({ + noSemanticValidation: true, + noSyntaxValidation: true, + }); + tsDefaults.setCompilerOptions({ + jsx: monaco.languages.typescript.JsxEmit.React, + target: monaco.languages.typescript.ScriptTarget.ESNext, + }); + jsDefaults.setCompilerOptions({ + jsx: monaco.languages.typescript.JsxEmit.React, + target: monaco.languages.typescript.ScriptTarget.ESNext, + }); + } + }, [shouldEnableTypeScript]); + useEffect(() => { let configuredTheme = theme; @@ -180,7 +208,7 @@ export const MonacoEditor = memo(function MonacoEditor({ editor.current = monaco.editor.create(containerRef.current!, { language: createOptions.language || 'typescript', minimap: { enabled: false }, - theme: configuredTheme === 'dark' ? 'v1-dev-dark' : 'v1-dev', + theme: configuredTheme === 'dark' ? 'vibesdk-dark' : 'vibesdk', automaticLayout: true, value: defaultCode, fontSize: 13, @@ -207,6 +235,10 @@ export const MonacoEditor = memo(function MonacoEditor({ } return () => { + const model = editor.current?.getModel(); + if (model) { + model.dispose(); + } editor.current?.dispose(); }; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -217,10 +249,16 @@ export const MonacoEditor = memo(function MonacoEditor({ const model = editor.current.getModel(); if (!model) return; - editor.current.setValue(createOptions.value || ''); + model.pushEditOperations( + [], + [{ + range: model.getFullModelRange(), + text: createOptions.value || '' + }], + () => null + ); if (stickyScroll.current) { - // Scroll to bottom const lineCount = model.getLineCount(); editor.current.revealLine(lineCount); } @@ -293,7 +331,7 @@ export const MonacoEditor = memo(function MonacoEditor({ // Update theme when app theme changes useEffect(() => { if (editor.current) { - monaco.editor.setTheme(theme === 'dark' ? 'v1-dev-dark' : 'v1-dev'); + monaco.editor.setTheme(theme === 'dark' ? 'vibesdk-dark' : 'vibesdk'); } }, [theme]); diff --git a/src/components/ui/model-selector.tsx b/src/components/ui/model-selector.tsx index 0677d92d..7fbc6155 100644 --- a/src/components/ui/model-selector.tsx +++ b/src/components/ui/model-selector.tsx @@ -111,7 +111,7 @@ export function ModelSelector({ className="w-full justify-between" disabled={disabled} > - {getSelectedDisplay() || placeholder} + {getSelectedDisplay() || placeholder} @@ -203,7 +203,7 @@ export function ModelSelector({ {/* System default display */} {systemDefault && ( -

+

🔧 System default: {getModelDisplayName(systemDefault)}

)} diff --git a/src/lib/api-client.ts b/src/lib/api-client.ts index a6ea0952..ae87ebe9 100644 --- a/src/lib/api-client.ts +++ b/src/lib/api-client.ts @@ -684,11 +684,14 @@ class ApiClient { /** * Get BYOK providers and available models + * @param agentAction - Optional agent action to filter models by constraints */ - async getByokProviders(): Promise> { - return this.request( - '/api/model-configs/byok-providers', - ); + async getByokProviders(agentAction?: string): Promise> { + const endpoint = agentAction + ? `/api/model-configs/byok-providers?agentAction=${encodeURIComponent(agentAction)}` + : '/api/model-configs/byok-providers'; + + return this.request(endpoint); } /** diff --git a/src/routes/app/index.tsx b/src/routes/app/index.tsx index b576d1f9..03a9cdc1 100644 --- a/src/routes/app/index.tsx +++ b/src/routes/app/index.tsx @@ -1000,7 +1000,7 @@ export default function AppView() { 'on', scrollBeyondLastLine: false, fontSize: 13, - theme: 'v1-dev', + theme: 'vibesdk', automaticLayout: true, }} /> diff --git a/src/routes/chat/chat.tsx b/src/routes/chat/chat.tsx index 71803cea..df1a3c47 100644 --- a/src/routes/chat/chat.tsx +++ b/src/routes/chat/chat.tsx @@ -36,7 +36,6 @@ import { useAutoScroll } from '@/hooks/use-auto-scroll'; import { useImageUpload } from '@/hooks/use-image-upload'; import { useDragDrop } from '@/hooks/use-drag-drop'; import { ImageAttachmentPreview } from '@/components/image-attachment-preview'; -import { createAIMessage } from './utils/message-helpers'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'; @@ -113,14 +112,12 @@ export default function Chat() { totalFiles, websocket, sendUserMessage, - sendAiMessage, blueprint, previewUrl, clearEdit, projectStages, phaseTimeline, isThinking, - onCompleteBootstrap, // Deployment and generation control isDeploying, cloudflareDeploymentUrl, @@ -235,7 +232,7 @@ export default function Chat() { const imageInputRef = useRef(null); // Fake stream bootstrap files - const { streamedFiles: streamedBootstrapFiles, doneStreaming } = + const { streamedFiles: streamedBootstrapFiles } = useFileContentStream(bootstrapFiles, { tps: 600, enabled: isBootstrapping, @@ -413,28 +410,7 @@ export default function Chat() { setView('editor'); } }, [isGeneratingBlueprint, view]); - - useEffect(() => { - // Only show bootstrap completion message for NEW chats, not when reloading existing ones - if (doneStreaming && !isGeneratingBlueprint && !blueprint && urlChatId === 'new') { - onCompleteBootstrap(); - sendAiMessage( - createAIMessage( - 'creating-blueprint', - 'Bootstrapping complete, now creating a blueprint for you...', - true, - ), - ); - } - }, [ - doneStreaming, - isGeneratingBlueprint, - sendAiMessage, - blueprint, - onCompleteBootstrap, - urlChatId, - ]); - + const isRunning = useMemo(() => { return ( isBootstrapping || isGeneratingBlueprint // || codeGenState === 'active' @@ -1183,7 +1159,7 @@ export default function Chat() { lineNumbers: 'on', scrollBeyondLastLine: false, fontSize: 13, - theme: 'v1-dev', + theme: 'vibesdk', automaticLayout: true, }} find={ diff --git a/src/routes/chat/components/preview-iframe.tsx b/src/routes/chat/components/preview-iframe.tsx index eae8d601..1b1986af 100644 --- a/src/routes/chat/components/preview-iframe.tsx +++ b/src/routes/chat/components/preview-iframe.tsx @@ -336,6 +336,7 @@ export const PreviewIframe = forwardRef( if (loadState.status === 'loaded' && loadState.loadedSrc) { return (