import { writable, get } from "svelte/store"; import { invoke } from "@tauri-apps/api/core"; export type WorkflowPhase = 1 | 2 | 3 | 4; export type CriterionStatus = "pending" | "pass" | "fail" | "partial"; export interface VerifyCriterion { id: string; text: string; status: CriterionStatus; } export interface WorkflowState { version: 1; currentPhase: WorkflowPhase; quickMode: boolean; discuss: { description: string; contextCaptured: boolean; }; plan: { tasksApproved: boolean; }; execute: { completed: boolean; }; verify: { criteria: VerifyCriterion[]; verificationComplete: boolean; report: string; }; } export const WORKFLOW_STATE_FILENAME = "workflow-state.json"; const DEFAULT_STATE: WorkflowState = { version: 1, currentPhase: 1, quickMode: false, discuss: { description: "", contextCaptured: false }, plan: { tasksApproved: false }, execute: { completed: false }, verify: { criteria: [], verificationComplete: false, report: "" }, }; // ─── Pure functions (exported for testing) ─────────────────────────────────── export function buildDiscussPrompt(description: string): string { return `Please help me clarify and document the following project goal, then write a \`CONTEXT.md\` file in the working directory. Project description: ${description} The \`CONTEXT.md\` file should include: ## Goal A clear, one-paragraph statement of what we are building and why. ## Scope What is in scope and what is explicitly out of scope. ## Acceptance Criteria A numbered list of concrete, verifiable criteria that must be met for this project to be considered complete. Each criterion should be specific and testable. ## Key Assumptions Any assumptions being made about the implementation, environment, or user needs. ## Open Questions Any questions that need to be resolved before or during development. Write the file concisely but thoroughly. Focus on information that guides implementation and defines success.`; } export function buildVerifyPrompt(criteria: VerifyCriterion[]): string { if (criteria.length === 0) { return `Please review the project implementation and write a \`VERIFY.md\` file in the working directory with your overall assessment. Include: ## Summary Overall pass/fail assessment. ## Findings What you found when reviewing the implementation. ## Recommendation Whether the project is ready to ship or what remains to be done.`; } const criteriaList = criteria.map((c, i) => `${i + 1}. ${c.text}`).join("\n"); return `Please verify the project implementation against the following acceptance criteria and write a \`VERIFY.md\` file in the working directory. Acceptance criteria: ${criteriaList} For each criterion, check whether it is met by examining the codebase and any relevant files. Then write \`VERIFY.md\` with: ## Summary Overall PASSED / FAILED / PARTIAL status. ## Criterion Results For each criterion: state whether it PASSES, FAILS, or is PARTIAL, with a brief explanation. ## Findings Any notable issues, edge cases, or improvements spotted during review. ## Recommendation Whether the project is ready to ship or what remains to be done.`; } export function canAdvancePhase(state: WorkflowState): boolean { switch (state.currentPhase) { case 1: return state.quickMode || state.discuss.contextCaptured; case 2: return state.plan.tasksApproved; case 3: return state.execute.completed; case 4: return state.verify.verificationComplete; } } export function canGoBack(phase: WorkflowPhase): boolean { return phase > 1; } export function getPhaseLabel(phase: WorkflowPhase): string { switch (phase) { case 1: return "Discuss"; case 2: return "Plan"; case 3: return "Execute"; case 4: return "Verify"; } } export function generateCriterionId(): string { return `criterion-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`; } // ─── Store ──────────────────────────────────────────────────────────────────── function createWorkflowStore() { const state = writable({ ...DEFAULT_STATE }); async function loadState(workingDirectory: string): Promise { try { const path = `${workingDirectory}/${WORKFLOW_STATE_FILENAME}`; const content = await invoke("read_file_content", { path }); const parsed = JSON.parse(content) as WorkflowState; state.set(parsed); } catch { state.set({ ...DEFAULT_STATE }); } } async function saveState(workingDirectory: string): Promise { try { const path = `${workingDirectory}/${WORKFLOW_STATE_FILENAME}`; const current = get(state); await invoke("write_file_content", { path, content: JSON.stringify(current, null, 2) }); } catch (error) { console.error("Failed to save workflow state:", error); } } function setPhase(phase: WorkflowPhase): void { state.update((s) => ({ ...s, currentPhase: phase })); } function setQuickMode(value: boolean): void { state.update((s) => ({ ...s, quickMode: value })); } function reset(): void { state.set({ ...DEFAULT_STATE }); } function setDiscussDescription(text: string): void { state.update((s) => ({ ...s, discuss: { ...s.discuss, description: text } })); } function markContextCaptured(): void { state.update((s) => ({ ...s, discuss: { ...s.discuss, contextCaptured: true } })); } function approvePlan(): void { state.update((s) => ({ ...s, plan: { tasksApproved: true } })); } function completeExecution(): void { state.update((s) => ({ ...s, execute: { completed: true } })); } function addCriterion(text: string): void { const criterion: VerifyCriterion = { id: generateCriterionId(), text, status: "pending", }; state.update((s) => ({ ...s, verify: { ...s.verify, criteria: [...s.verify.criteria, criterion] }, })); } function removeCriterion(id: string): void { state.update((s) => ({ ...s, verify: { ...s.verify, criteria: s.verify.criteria.filter((c) => c.id !== id) }, })); } function updateCriterionStatus(id: string, status: CriterionStatus): void { state.update((s) => ({ ...s, verify: { ...s.verify, criteria: s.verify.criteria.map((c) => (c.id === id ? { ...c, status } : c)), }, })); } function completeVerification(report: string): void { state.update((s) => ({ ...s, verify: { ...s.verify, verificationComplete: true, report }, })); } return { state: { subscribe: state.subscribe }, loadState, saveState, setPhase, setQuickMode, reset, setDiscussDescription, markContextCaptured, approvePlan, completeExecution, addCriterion, removeCriterion, updateCriterionStatus, completeVerification, }; } export const workflowStore = createWorkflowStore();