{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/utils/plan/parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,KAAK,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3E,UAAU,aAAa;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,KAAK;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,IAAI,EAAE,CAAC;CACd;AAED,UAAU,KAAK;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAyBD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAiGrD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAwBjE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAWzE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB,CAoCA","sourcesContent":["/**\n * Plan parser module for hierarchical phase/stage/step structure.\n * Parses .hoocode/plan.md files with completion tracking.\n */\n\ntype Status = \"pending\" | \"in-progress\" | \"success\" | \"failed\" | \"skipped\";\n\ninterface ChecklistItem {\n\ttext: string;\n\tcompleted: boolean;\n}\n\nexport interface Step {\n\tid: string;\n\ttitle: string;\n\tstatus: Status;\n\tchecklist: ChecklistItem[];\n\tevidence?: string;\n\tcompletedAt?: string;\n}\n\ninterface Stage {\n\tid: string;\n\ttitle: string;\n\tsteps: Step[];\n}\n\ninterface Phase {\n\tid: string;\n\ttitle: string;\n\tstages: Stage[];\n}\n\nexport interface ParsedPlan {\n\tphases: Phase[];\n}\n\nconst PHASE_REGEX = /^##\\s+Phase\\s+(\\d+):\\s+(.+)$/i;\nconst STAGE_REGEX = /^###\\s+Stage\\s+(\\d+\\.\\d+):\\s+(.+)$/i;\nconst STEP_REGEX = /^-\\s+\\[([ xX])\\]\\s+Step\\s+(\\d+\\.\\d+\\.\\d+):\\s+(.+)$/i;\nconst STATUS_REGEX = /^\\s+-\\s+Status:\\s*(\\S+)/i;\nconst CHECKLIST_REGEX = /^\\s+-\\s+\\[([ xX])\\]\\s+(.+)$/i;\nconst EVIDENCE_REGEX = /^\\s+-\\s+Evidence:\\s*(.+)$/i;\nconst COMPLETED_REGEX = /^\\s+-\\s+Completed:\\s*(.+)$/i;\n\nfunction parseStatus(status: string): Status {\n\tswitch (status.toLowerCase()) {\n\t\tcase \"in-progress\":\n\t\t\treturn \"in-progress\";\n\t\tcase \"success\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"failed\";\n\t\tcase \"skipped\":\n\t\t\treturn \"skipped\";\n\t\tdefault:\n\t\t\treturn \"pending\";\n\t}\n}\n\nexport function parsePlan(content: string): ParsedPlan {\n\tconst lines = content.split(\"\\n\");\n\tconst plan: ParsedPlan = { phases: [] };\n\n\tlet currentPhase: Phase | null = null;\n\tlet currentStage: Stage | null = null;\n\tlet currentStep: Step | null = null;\n\tlet inChecklist = false;\n\n\tfor (const line of lines) {\n\t\t// Check for phase header\n\t\tconst phaseMatch = line.match(PHASE_REGEX);\n\t\tif (phaseMatch) {\n\t\t\tcurrentPhase = {\n\t\t\t\tid: phaseMatch[1],\n\t\t\t\ttitle: phaseMatch[2].trim(),\n\t\t\t\tstages: [],\n\t\t\t};\n\t\t\tplan.phases.push(currentPhase);\n\t\t\tcurrentStage = null;\n\t\t\tcurrentStep = null;\n\t\t\tinChecklist = false;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check for stage header\n\t\tconst stageMatch = line.match(STAGE_REGEX);\n\t\tif (stageMatch && currentPhase) {\n\t\t\tcurrentStage = {\n\t\t\t\tid: stageMatch[1],\n\t\t\t\ttitle: stageMatch[2].trim(),\n\t\t\t\tsteps: [],\n\t\t\t};\n\t\t\tcurrentPhase.stages.push(currentStage);\n\t\t\tcurrentStep = null;\n\t\t\tinChecklist = false;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check for step header\n\t\tconst stepMatch = line.match(STEP_REGEX);\n\t\tif (stepMatch && currentStage) {\n\t\t\tcurrentStep = {\n\t\t\t\tid: stepMatch[2],\n\t\t\t\ttitle: stepMatch[3].trim(),\n\t\t\t\tstatus: stepMatch[1].trim() !== \"\" ? \"success\" : \"pending\",\n\t\t\t\tchecklist: [],\n\t\t\t};\n\t\t\tcurrentStage.steps.push(currentStep);\n\t\t\tinChecklist = false;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// If no current step, skip further processing\n\t\tif (!currentStep) continue;\n\n\t\t// Check for status\n\t\tconst statusMatch = line.match(STATUS_REGEX);\n\t\tif (statusMatch) {\n\t\t\tcurrentStep.status = parseStatus(statusMatch[1]);\n\t\t\tinChecklist = false;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check for completed timestamp\n\t\tconst completedMatch = line.match(COMPLETED_REGEX);\n\t\tif (completedMatch) {\n\t\t\tcurrentStep.completedAt = completedMatch[1].trim();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check for evidence\n\t\tconst evidenceMatch = line.match(EVIDENCE_REGEX);\n\t\tif (evidenceMatch) {\n\t\t\tcurrentStep.evidence = evidenceMatch[1].trim();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check for checklist start\n\t\tif (line.match(/^\\s+-\\s+Checklist:\\s*$/i)) {\n\t\t\tinChecklist = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check for checklist items\n\t\tif (inChecklist) {\n\t\t\tconst checklistMatch = line.match(CHECKLIST_REGEX);\n\t\t\tif (checklistMatch) {\n\t\t\t\tcurrentStep.checklist.push({\n\t\t\t\t\ttext: checklistMatch[2].trim(),\n\t\t\t\t\tcompleted: checklistMatch[1].trim() !== \"\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn plan;\n}\n\nexport function findNextPendingStep(plan: ParsedPlan): Step | null {\n\t// First, look for any in-progress steps (to resume after crash)\n\tfor (const phase of plan.phases) {\n\t\tfor (const stage of phase.stages) {\n\t\t\tfor (const step of stage.steps) {\n\t\t\t\tif (step.status === \"in-progress\") {\n\t\t\t\t\treturn step;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Then, look for pending steps\n\tfor (const phase of plan.phases) {\n\t\tfor (const stage of phase.stages) {\n\t\t\tfor (const step of stage.steps) {\n\t\t\t\tif (step.status === \"pending\") {\n\t\t\t\t\treturn step;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nexport function getStepById(plan: ParsedPlan, stepId: string): Step | null {\n\tfor (const phase of plan.phases) {\n\t\tfor (const stage of phase.stages) {\n\t\t\tfor (const step of stage.steps) {\n\t\t\t\tif (step.id === stepId) {\n\t\t\t\t\treturn step;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function getCompletionStats(plan: ParsedPlan): {\n\ttotal: number;\n\tcompleted: number;\n\tpending: number;\n\tinProgress: number;\n\tfailed: number;\n\tskipped: number;\n} {\n\tconst stats = {\n\t\ttotal: 0,\n\t\tcompleted: 0,\n\t\tpending: 0,\n\t\tinProgress: 0,\n\t\tfailed: 0,\n\t\tskipped: 0,\n\t};\n\n\tfor (const phase of plan.phases) {\n\t\tfor (const stage of phase.stages) {\n\t\t\tfor (const step of stage.steps) {\n\t\t\t\tstats.total++;\n\t\t\t\tswitch (step.status) {\n\t\t\t\t\tcase \"success\":\n\t\t\t\t\t\tstats.completed++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"pending\":\n\t\t\t\t\t\tstats.pending++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"in-progress\":\n\t\t\t\t\t\tstats.inProgress++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"failed\":\n\t\t\t\t\t\tstats.failed++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"skipped\":\n\t\t\t\t\t\tstats.skipped++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn stats;\n}\n"]}