"use client"; import { useEffect, useState, useCallback } from "react"; import { useAppStore } from "@/store/app-store"; import { getElectronAPI } from "@/lib/electron"; import { Button } from "@/components/ui/button"; import { HotkeyButton } from "@/components/ui/hotkey-button"; import { Card } from "@/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Save, RefreshCw, FileText, Sparkles, Loader2, FilePlus2 } from "lucide-react"; import { Checkbox } from "@/components/ui/checkbox"; import { XmlSyntaxEditor } from "@/components/ui/xml-syntax-editor"; import type { SpecRegenerationEvent } from "@/types/electron"; export function SpecView() { const { currentProject, appSpec, setAppSpec } = useAppStore(); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [hasChanges, setHasChanges] = useState(false); const [specExists, setSpecExists] = useState(true); // Regeneration state const [showRegenerateDialog, setShowRegenerateDialog] = useState(false); const [projectDefinition, setProjectDefinition] = useState(""); const [isRegenerating, setIsRegenerating] = useState(false); // Create spec state const [showCreateDialog, setShowCreateDialog] = useState(false); const [projectOverview, setProjectOverview] = useState(""); const [isCreating, setIsCreating] = useState(false); const [generateFeatures, setGenerateFeatures] = useState(true); // Load spec from file const loadSpec = useCallback(async () => { if (!currentProject) return; setIsLoading(true); try { const api = getElectronAPI(); const result = await api.readFile( `${currentProject.path}/.automaker/app_spec.txt` ); if (result.success && result.content) { setAppSpec(result.content); setSpecExists(true); setHasChanges(false); } else { // File doesn't exist setAppSpec(""); setSpecExists(false); } } catch (error) { console.error("Failed to load spec:", error); setSpecExists(false); } finally { setIsLoading(false); } }, [currentProject, setAppSpec]); useEffect(() => { loadSpec(); }, [loadSpec]); // Subscribe to spec regeneration events useEffect(() => { const api = getElectronAPI(); if (!api.specRegeneration) return; const unsubscribe = api.specRegeneration.onEvent((event: SpecRegenerationEvent) => { console.log("[SpecView] Regeneration event:", event.type); if (event.type === "spec_regeneration_complete") { setIsRegenerating(false); setIsCreating(false); setShowRegenerateDialog(false); setShowCreateDialog(false); setProjectDefinition(""); setProjectOverview(""); // Reload the spec to show the new content loadSpec(); } else if (event.type === "spec_regeneration_error") { setIsRegenerating(false); setIsCreating(false); console.error("[SpecView] Regeneration error:", event.error); } }); return () => { unsubscribe(); }; }, [loadSpec]); // Save spec to file const saveSpec = async () => { if (!currentProject) return; setIsSaving(true); try { const api = getElectronAPI(); await api.writeFile( `${currentProject.path}/.automaker/app_spec.txt`, appSpec ); setHasChanges(false); } catch (error) { console.error("Failed to save spec:", error); } finally { setIsSaving(false); } }; const handleChange = (value: string) => { setAppSpec(value); setHasChanges(true); }; const handleRegenerate = async () => { if (!currentProject || !projectDefinition.trim()) return; setIsRegenerating(true); try { const api = getElectronAPI(); if (!api.specRegeneration) { console.error("[SpecView] Spec regeneration not available"); setIsRegenerating(false); return; } const result = await api.specRegeneration.generate( currentProject.path, projectDefinition.trim() ); if (!result.success) { console.error("[SpecView] Failed to start regeneration:", result.error); setIsRegenerating(false); } // If successful, we'll wait for the events to update the state } catch (error) { console.error("[SpecView] Failed to regenerate spec:", error); setIsRegenerating(false); } }; const handleCreateSpec = async () => { if (!currentProject || !projectOverview.trim()) return; setIsCreating(true); setShowCreateDialog(false); try { const api = getElectronAPI(); if (!api.specRegeneration) { console.error("[SpecView] Spec regeneration not available"); setIsCreating(false); return; } const result = await api.specRegeneration.create( currentProject.path, projectOverview.trim(), generateFeatures ); if (!result.success) { console.error("[SpecView] Failed to start spec creation:", result.error); setIsCreating(false); } // If successful, we'll wait for the events to update the state } catch (error) { console.error("[SpecView] Failed to create spec:", error); setIsCreating(false); } }; if (!currentProject) { return (

No project selected

); } if (isLoading) { return (
); } // Show empty state when no spec exists (isCreating is handled by bottom-right indicator in sidebar) if (!specExists) { return (
{/* Header */}

App Specification

{currentProject.path}/.automaker/app_spec.txt

{/* Empty State */}

No App Specification Found

Create an app specification to help our system understand your project. We'll analyze your codebase and generate a comprehensive spec based on your description.

{/* Create Dialog */} Create App Specification We didn't find an app_spec.txt file. Let us help you generate your app_spec.txt to help describe your project for our system. We'll analyze your project's tech stack and create a comprehensive specification.

Describe what your project does and what features you want to build. Be as detailed as you want - this will help us create a better specification.