import * as fs from 'fs/promises'; import * as path from 'path'; import { simpleGit } from 'simple-git'; import { parseMarkdownChecklist, ChecklistItem } from './markdown-parser.js'; export interface RigstateState { hasPlan: boolean; planPath: string | null; activeTaskId: string | null; isDaemonRunning: boolean; gitStatus: { isClean: boolean; modifiedFiles: string[]; }; checklist: { total: number; completed: number; pending: string[]; }; } export class StateAnalyzer { private static PID_FILE = '.rigstate/daemon.pid'; static async analyze(cwd: string = process.cwd()): Promise { const git = simpleGit(cwd); const status = await git.status(); // 1. Find the plan and task ID let planPath: string | null = null; let activeTaskId: string | null = null; let checklist: ChecklistItem[] = []; const files = await fs.readdir(cwd); const planFile = files.find(f => f.startsWith('IMPLEMENTATION_PLAN') && f.endsWith('.md')); if (planFile) { planPath = path.join(cwd, planFile); const content = await fs.readFile(planPath, 'utf-8'); // Extract Task ID const idMatch = content.match(/\*\*(?:Task ID|ID):\*\*\s*(.+?)(?:\s|\n|$)/i); if (idMatch) { activeTaskId = idMatch[1].trim(); } // Parse Checklist checklist = parseMarkdownChecklist(content); } // 2. Check Daemon let isDaemonRunning = false; try { const pidPath = path.join(cwd, this.PID_FILE); const content = await fs.readFile(pidPath, 'utf-8'); const pid = parseInt(content.trim(), 10); process.kill(pid, 0); // Check if process exists isDaemonRunning = true; } catch { isDaemonRunning = false; } return { hasPlan: !!planPath, planPath, activeTaskId, isDaemonRunning, gitStatus: { isClean: status.isClean(), modifiedFiles: status.modified.concat(status.not_added) }, checklist: { total: checklist.length, completed: checklist.filter(c => c.checked).length, pending: checklist.filter(c => !c.checked).map(c => c.text) } }; } }