diff --git a/bin/goose-ultra-final/src/components/LayoutComponents.tsx b/bin/goose-ultra-final/src/components/LayoutComponents.tsx index 2f8e58c..ddfb2d1 100644 --- a/bin/goose-ultra-final/src/components/LayoutComponents.tsx +++ b/bin/goose-ultra-final/src/components/LayoutComponents.tsx @@ -2422,8 +2422,7 @@ Format: { "ideas": [{ "title": "Short Title", "subtitle": "One line", "tag": "To }, 45000); let systemPrompt = ''; - const isBackendRequest = userPrompt.includes('[BACKEND_REQUEST]'); - const isModificationMode = (state.state === OrchestratorState.PreviewReady || state.state === OrchestratorState.Editing) && !isBackendRequest; + const isModificationMode = (state.state === OrchestratorState.PreviewReady || state.state === OrchestratorState.Editing); let requestKind: 'chat' | 'plan' | 'code' = (isChatMode || isBrainstormMode) ? 'chat' : 'plan'; // SMART ROUTING: REMOVED CONCIERGE (F4: Plan First Enforcement) @@ -2431,9 +2430,7 @@ Format: { "ideas": [{ "title": "Short Title", "subtitle": "One line", "tag": "To if (isChatMode) { const sysP = personaSystem(state, state.chatPersona, state.customChatPersonaPrompt); systemPrompt = `[SYSTEM INSTRUCTION]: ${sysP}\n\n[CONTEXT]: This is CHAT mode (not building). Do not generate code unless explicitly asked. If user asks for a change to an existing project, propose a plan starting with '[PLAN]' and wait for approval. Use PLAIN PROSE for conversation, no markdown code blocks for speech.\n\n[IMAGE GENERATION]: You CAN generate images! If the user asks for an image, painting, illustration, or visual content, acknowledge that you're generating it. The system will handle the actual generation. Say something like "I'm creating that image for you now, please wait a moment...".`; - } else if (isBackendRequest) { - // Backend requests are effectively "new plans" but we handle the prompt generation specifically below - requestKind = 'plan'; + } else if (isBrainstormMode) { const lower = userPrompt.toLowerCase(); const wantsPlan = lower.includes('plan') || lower.includes('formalize') || lower.includes('blueprint'); @@ -2474,24 +2471,12 @@ Format: { "ideas": [{ "title": "Short Title", "subtitle": "One line", "tag": "To (window as any)._redesignApprovedSessions[state.activeProject.id] = true; } - const isBackendRequest = userPrompt.includes('[BACKEND_REQUEST]'); - if (isBackendRequest) { - // --- BACKEND GENERATION MODE --- - systemPrompt = `[SYSTEM INSTRUCTION]: BACKEND GENERATION REQUEST. - -The user wants to generate a server-side implementation for the existing frontend. -1. Analyze the provided frontend code in the user prompt. -2. Identify all API endpoints and data structures. -3. Propose a plan to create a 'server.js' (Node.js/Express) file. -4. The plan MUST start with '[PLAN]'. -5. Do NOT modify the frontend code. Only build the backend.`; - } else if (isQaFailureArtifact) { - // --- REPAIR MODE (F3: Retention & Match) --- - // "Broken frontend is treated as a REPAIR task" - const originalIntent = state.activeProject?.originalPrompt || "Unknown Intent"; + // --- 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. @@ -2504,32 +2489,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} @@ -2546,10 +2531,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} @@ -2564,644 +2549,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.`; + } + } 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; } - 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 + 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') { - dispatch({ type: 'TRANSITION', to: OrchestratorState.Planning }); + // 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: 'UPDATE_PLAN', plan: "# Analyzing Request...\n\n*Forging blueprint based on 2025 System Standards...*" }); + dispatch({ type: 'END_BUILD_SESSION', sessionId }); + dispatch({ type: 'UPDATE_STREAMING_CODE', code: null }); // Clear stream + finalizeRequest(); + return; } - 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.'); + 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; } } - 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.'); } - - - }; - - (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); + 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); +} }; - 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.
+Generate tailored build ideas or start fresh.
-