diff --git a/bin/goose-ultra-final/src/components/LayoutComponents.tsx b/bin/goose-ultra-final/src/components/LayoutComponents.tsx index ddfb2d1..56b22df 100644 --- a/bin/goose-ultra-final/src/components/LayoutComponents.tsx +++ b/bin/goose-ultra-final/src/components/LayoutComponents.tsx @@ -2472,11 +2472,12 @@ Format: { "ideas": [{ "title": "Short Title", "subtitle": "One line", "tag": "To } - // --- REPAIR MODE (F3: Retention & Match) --- - // "Broken frontend is treated as a REPAIR task" - const originalIntent = state.activeProject?.originalPrompt || "Unknown Intent"; + if (isQaFailureArtifact) { + // --- REPAIR MODE (F3: Retention & Match) --- + // "Broken frontend is treated as a REPAIR task" + const originalIntent = state.activeProject?.originalPrompt || "Unknown Intent"; - systemPrompt = `[SYSTEM INSTRUCTION]: REPAIR MODE ACTIVE. + systemPrompt = `[SYSTEM INSTRUCTION]: REPAIR MODE ACTIVE. The previous build FAILED Quality Assurance (Unstyled/Broken) or was completely lost. The user wants to FIX/REDO it. @@ -2489,32 +2490,32 @@ YOUR GOAL: Propose a repair plan to fix the broken output while STAYING TRUE to 2. YOU MUST PROPOSE A VALID, STYLED IMPLEMENTATION. 3. Start plan with '[PLAN]'. 4. Do NOT ask for clarification. JUST FIX IT.`; - } else if (isRedesignConfirmed) { - // --- REDESIGN APPROVED MODE --- - systemPrompt = `[SYSTEM INSTRUCTION]: REDESIGN APPROVED. + } else if (isRedesignConfirmed) { + // --- REDESIGN APPROVED MODE --- + systemPrompt = `[SYSTEM INSTRUCTION]: REDESIGN APPROVED. The user has explicitely authorized a redesign. 1. You may change layout, colors, and structure. 2. Ignore previous Design Lock constraints. 3. Propose a comprehensive plan starting with '[PLAN]'.`; - } else { - // --- CLIE: CONTEXT-LOCKED EXECUTION --- - try { - // 1. Analyze Intent - const intent = classifyIntent(userPrompt); + } else { + // --- CLIE: CONTEXT-LOCKED EXECUTION --- + try { + // 1. Analyze Intent + const intent = classifyIntent(userPrompt); - // 2. Load Manifest (Context Soul) - let manifest = await loadProjectManifest(state.activeProject.id); - if (!manifest && state.activeProject.originalPrompt) { - // Lazy init if missing - await initializeProjectContext(state.activeProject, state.activeProject.originalPrompt); - manifest = await loadProjectManifest(state.activeProject.id); - } + // 2. Load Manifest (Context Soul) + let manifest = await loadProjectManifest(state.activeProject.id); + if (!manifest && state.activeProject.originalPrompt) { + // Lazy init if missing + await initializeProjectContext(state.activeProject, state.activeProject.originalPrompt); + manifest = await loadProjectManifest(state.activeProject.id); + } - // 3. Enhance Prompt - const enhancedContext = enhancePromptWithContext(userPrompt, manifest, intent); + // 3. Enhance Prompt + const enhancedContext = enhancePromptWithContext(userPrompt, manifest, intent); - systemPrompt = `[CLIE v${CLIE_VERSION}] [SYSTEM INSTRUCTION]: EXECUTION MODE LOCKED. + systemPrompt = `[CLIE v${CLIE_VERSION}] [SYSTEM INSTRUCTION]: EXECUTION MODE LOCKED. ${enhancedContext} @@ -2531,10 +2532,10 @@ BEFORE proposing changes, state: - MUST_NOT_TOUCH: [layout, colors, typography, existing components, structure] Then provide a BRIEF plan starting with '[PLAN]' describing ONLY the changes needed.`; - } catch (e) { - console.error('[CLIE] Failed to enhance prompt:', e); - // Fallback to standard - systemPrompt = `[SYSTEM INSTRUCTION]: MODIFICATION MODE with DESIGN LOCK ENABLED. + } catch (e) { + console.error('[CLIE] Failed to enhance prompt:', e); + // Fallback to standard + systemPrompt = `[SYSTEM INSTRUCTION]: MODIFICATION MODE with DESIGN LOCK ENABLED. ${memoryBlock} @@ -2549,644 +2550,644 @@ DESIGN LOCK RULES: 3. ONLY implement the request. Brief plan starting with '[PLAN]'.`; - } - } - } else { - // P0-WF1: FORCE PLAN-FIRST - // "Every idea must produce a plan first" - // We ignore overrideInput / one-shot triggers for the initial build request. - requestKind = 'plan'; - systemPrompt = `[SYSTEM INSTRUCTION]: Propose an implementation plan starting with '[PLAN]'. DO NOT output code yet.`; -} - -if (state.preferredFramework) { - systemPrompt += `\n\n[USER PREFERENCE]: The user has explicitly requested to use the "${state.preferredFramework}" framework. You MUST prioritize this framework, along with its standard ecosystem (e.g. if React, use typical React libs; if Tailwind, use utility classes).`; -} - -// IMMEDIATE FEEDBACK: If we are planning, switch to Plan tab immediately so user sees the stream -if (requestKind === 'plan') { - dispatch({ type: 'TRANSITION', to: OrchestratorState.Planning }); - dispatch({ type: 'SET_TAB', tab: TabId.Plan }); - dispatch({ type: 'UPDATE_PLAN', plan: "# Analyzing Request...\n\n*Forging blueprint based on 2025 System Standards...*" }); -} - -setThinkingLabel('Thinking...'); - -if ((window as any).electron) { - const sessionId = Date.now().toString(); - let currentProjectId = state.activeProject?.id || null; - - if (!currentProjectId) { - const id = (globalThis.crypto && 'randomUUID' in globalThis.crypto) ? (globalThis.crypto as any).randomUUID() : Date.now().toString(); - const name = userPrompt.substring(0, 20) || "New Project"; - dispatch({ type: 'CREATE_PROJECT', id, createdAt: Date.now(), name }); - void ensureProjectOnDisk({ id, name, slug: name.toLowerCase().replace(/\s+/g, '-'), createdAt: Date.now(), description: 'New Vibe Project' }); - void writeLastActiveProjectId(id); - currentProjectId = id; - } - - const targetProjectId = currentProjectId; - - - - (window as any).electron.removeChatListeners(); - - - - const handleResponse = (response: string) => { - clearTimeout(timeoutId); - // Session gating: ignore if session was cancelled - if (state.activeRequestStatus === 'cancelled') { - console.log('[ChatPanel] Ignoring response from cancelled session'); - return; - } - - - dispatch({ type: 'ADD_LOG', log: { id: Date.now().toString(), timestamp: Date.now(), type: 'system', message: response } }); - const hasDoctype = response.includes(''); - const isPlan = isPlanMessage(response); - - if (requestKind === 'plan') { - // F5: Plan Streaming handled via onChatChunk below (lines 1550+) - // Here we just finalize the plan. - - // FORCE transition to PlanReady regardless of tag presence - // We demanded a plan, so we treat the output as a plan. - dispatch({ type: 'UPDATE_PLAN', plan: response }); - // LAYER 1 FIX: Transition to PlanReady - user MUST approve before building - dispatch({ type: 'TRANSITION', to: OrchestratorState.PlanReady }); - dispatch({ type: 'SET_TAB', tab: TabId.Plan }); - dispatch({ type: 'END_BUILD_SESSION', sessionId }); - dispatch({ type: 'UPDATE_STREAMING_CODE', code: null }); // Clear stream - finalizeRequest(); - return; - } - - if (isChatMode) { - // IT Expert: Check for JSON ActionProposal - if (state.chatPersona === 'it') { - try { - // Try to extract JSON from response - let jsonStr = response.trim(); - // Strip markdown fences if present - jsonStr = jsonStr.replace(/```json/gi, '').replace(/```/g, '').trim(); - // Find first { and last } - const first = jsonStr.indexOf('{'); - const last = jsonStr.lastIndexOf('}'); - if (first !== -1 && last > first) { - jsonStr = jsonStr.substring(first, last + 1); - const parsed = JSON.parse(jsonStr); - if (parsed.runner && parsed.script && parsed.proposalId) { - // Valid ActionProposal - const proposal: import('../types').ActionProposal = { - ...parsed, - status: 'pending' - }; - dispatch({ type: 'SET_PENDING_PROPOSAL', proposal }); - finalizeRequest(); - return; - } - } - } catch (e) { - // Not valid JSON, treat as normal chat response - console.log('[IT Expert] Response is not a valid proposal, rendering as chat.'); } } - finalizeRequest(); - return; + } else { + // P0-WF1: FORCE PLAN-FIRST + // "Every idea must produce a plan first" + // We ignore overrideInput / one-shot triggers for the initial build request. + requestKind = 'plan'; + systemPrompt = `[SYSTEM INSTRUCTION]: Propose an implementation plan starting with '[PLAN]'. DO NOT output code yet.`; } + if (state.preferredFramework) { + systemPrompt += `\n\n[USER PREFERENCE]: The user has explicitly requested to use the "${state.preferredFramework}" framework. You MUST prioritize this framework, along with its standard ecosystem (e.g. if React, use typical React libs; if Tailwind, use utility classes).`; + } - }; - - (window as any).electron.onChatComplete(handleResponse); - (window as any).electron.onChatError((error: string) => { - clearTimeout(timeoutId); - // Session gating - if (state.activeRequestStatus === 'cancelled') return; - + // IMMEDIATE FEEDBACK: If we are planning, switch to Plan tab immediately so user sees the stream if (requestKind === 'plan') { - dispatch({ type: 'UPDATE_PLAN', plan: "# Planning Failed\n\nThe orchestrator encountered an error while analyzing your request:\n\n> " + error + "\n\nPlease try again." }); + dispatch({ type: 'TRANSITION', to: OrchestratorState.Planning }); + dispatch({ type: 'SET_TAB', tab: TabId.Plan }); + dispatch({ type: 'UPDATE_PLAN', plan: "# Analyzing Request...\n\n*Forging blueprint based on 2025 System Standards...*" }); } - dispatch({ type: 'ADD_LOG', log: { id: Date.now().toString(), timestamp: Date.now(), type: 'error', message: "Error: " + error } }); - dispatch({ type: 'REQUEST_ERROR' }); - if (!isChatMode && requestKind !== 'plan') { - dispatch({ type: 'END_BUILD_SESSION', sessionId }); - dispatch({ type: 'UPDATE_STREAMING_CODE', code: null }); - } - setIsThinking(false); + setThinkingLabel('Thinking...'); + if ((window as any).electron) { + const sessionId = Date.now().toString(); + let currentProjectId = state.activeProject?.id || null; + + if (!currentProjectId) { + const id = (globalThis.crypto && 'randomUUID' in globalThis.crypto) ? (globalThis.crypto as any).randomUUID() : Date.now().toString(); + const name = userPrompt.substring(0, 20) || "New Project"; + dispatch({ type: 'CREATE_PROJECT', id, createdAt: Date.now(), name }); + void ensureProjectOnDisk({ id, name, slug: name.toLowerCase().replace(/\s+/g, '-'), createdAt: Date.now(), description: 'New Vibe Project' }); + void writeLastActiveProjectId(id); + currentProjectId = id; + } + + const targetProjectId = currentProjectId; + + + (window as any).electron.removeChatListeners(); + + + + const handleResponse = (response: string) => { + clearTimeout(timeoutId); + // Session gating: ignore if session was cancelled + if (state.activeRequestStatus === 'cancelled') { + console.log('[ChatPanel] Ignoring response from cancelled session'); + return; + } + + + dispatch({ type: 'ADD_LOG', log: { id: Date.now().toString(), timestamp: Date.now(), type: 'system', message: response } }); + const hasDoctype = response.includes(''); + const isPlan = isPlanMessage(response); + + if (requestKind === 'plan') { + // F5: Plan Streaming handled via onChatChunk below (lines 1550+) + // Here we just finalize the plan. + + // FORCE transition to PlanReady regardless of tag presence + // We demanded a plan, so we treat the output as a plan. + dispatch({ type: 'UPDATE_PLAN', plan: response }); + // LAYER 1 FIX: Transition to PlanReady - user MUST approve before building + dispatch({ type: 'TRANSITION', to: OrchestratorState.PlanReady }); + dispatch({ type: 'SET_TAB', tab: TabId.Plan }); + dispatch({ type: 'END_BUILD_SESSION', sessionId }); + dispatch({ type: 'UPDATE_STREAMING_CODE', code: null }); // Clear stream + finalizeRequest(); + return; + } + + if (isChatMode) { + // IT Expert: Check for JSON ActionProposal + if (state.chatPersona === 'it') { + try { + // Try to extract JSON from response + let jsonStr = response.trim(); + // Strip markdown fences if present + jsonStr = jsonStr.replace(/```json/gi, '').replace(/```/g, '').trim(); + // Find first { and last } + const first = jsonStr.indexOf('{'); + const last = jsonStr.lastIndexOf('}'); + if (first !== -1 && last > first) { + jsonStr = jsonStr.substring(first, last + 1); + const parsed = JSON.parse(jsonStr); + if (parsed.runner && parsed.script && parsed.proposalId) { + // Valid ActionProposal + const proposal: import('../types').ActionProposal = { + ...parsed, + status: 'pending' + }; + dispatch({ type: 'SET_PENDING_PROPOSAL', proposal }); + finalizeRequest(); + return; + } + } + } catch (e) { + // Not valid JSON, treat as normal chat response + console.log('[IT Expert] Response is not a valid proposal, rendering as chat.'); + } + } + finalizeRequest(); + return; + } + + + }; + + (window as any).electron.onChatComplete(handleResponse); + (window as any).electron.onChatError((error: string) => { + clearTimeout(timeoutId); + // Session gating + if (state.activeRequestStatus === 'cancelled') return; + + if (requestKind === 'plan') { + dispatch({ type: 'UPDATE_PLAN', plan: "# Planning Failed\n\nThe orchestrator encountered an error while analyzing your request:\n\n> " + error + "\n\nPlease try again." }); + } + dispatch({ type: 'ADD_LOG', log: { id: Date.now().toString(), timestamp: Date.now(), type: 'error', message: "Error: " + error } }); + dispatch({ type: 'REQUEST_ERROR' }); + if (!isChatMode && requestKind !== 'plan') { + dispatch({ type: 'END_BUILD_SESSION', sessionId }); + dispatch({ type: 'UPDATE_STREAMING_CODE', code: null }); + } + setIsThinking(false); + setThinkingLabel('Thinking...'); + if ((window as any).electron) { + (window as any).electron.removeChatListeners(); + } + }); + + // F5: PLAN STREAMING - Attach listener BEFORE startChat + if (requestKind === 'plan') { + let planStreamBuffer = ''; + (window as any).electron.onChatChunk((chunk: string) => { + planStreamBuffer += chunk; + // We use UPDATE_STREAMING_CODE so the Plan Tab (or overlay if visible) can see it. + // Note: PlanView must be capable of rendering streaming code if it's the active tab. + dispatch({ type: 'UPDATE_STREAMING_CODE', code: planStreamBuffer }); + }); + } + + (window as any).electron.startChat([ + { role: 'system', content: systemPrompt }, + { role: 'user', content: userPrompt } + ], state.chatSettings.activeModel); + + } else { + clearTimeout(timeoutId); + setTimeout(() => { + dispatch({ type: 'ADD_LOG', log: { id: Date.now().toString(), timestamp: Date.now(), type: 'system', message: "[OFFLINE] Simulated response." } }); + finalizeRequest(); + }, 1000); } - }); - - // F5: PLAN STREAMING - Attach listener BEFORE startChat - if (requestKind === 'plan') { - let planStreamBuffer = ''; - (window as any).electron.onChatChunk((chunk: string) => { - planStreamBuffer += chunk; - // We use UPDATE_STREAMING_CODE so the Plan Tab (or overlay if visible) can see it. - // Note: PlanView must be capable of rendering streaming code if it's the active tab. - dispatch({ type: 'UPDATE_STREAMING_CODE', code: planStreamBuffer }); - }); - } - - (window as any).electron.startChat([ - { role: 'system', content: systemPrompt }, - { role: 'user', content: userPrompt } - ], state.chatSettings.activeModel); - -} else { - clearTimeout(timeoutId); - setTimeout(() => { - dispatch({ type: 'ADD_LOG', log: { id: Date.now().toString(), timestamp: Date.now(), type: 'system', message: "[OFFLINE] Simulated response." } }); - finalizeRequest(); - }, 1000); -} }; -const showStreaming = (state.state === OrchestratorState.Building) && state.activeBuildSessionId != null && state.streamingCode != null; + const showStreaming = (state.state === OrchestratorState.Building) && state.activeBuildSessionId != null && state.streamingCode != null; -useEffect(() => { - if (!showStreaming) return; - const id = setInterval(() => { - setActiveTechIndex((i) => (techTags.length ? (i + 1) % techTags.length : 0)); - }, 900); - return () => clearInterval(id); -}, [showStreaming, techTags.length]); + useEffect(() => { + if (!showStreaming) return; + const id = setInterval(() => { + setActiveTechIndex((i) => (techTags.length ? (i + 1) % techTags.length : 0)); + }, 900); + return () => clearInterval(id); + }, [showStreaming, techTags.length]); -return ( -
Generate tailored build ideas or start fresh.
-