spets 0.1.38 → 0.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1624 -638
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -725,8 +725,8 @@ function formatDocStatus(status) {
725
725
  import { execSync as execSync2 } from "child_process";
726
726
 
727
727
  // src/orchestrator/index.ts
728
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
729
- import { join as join4, dirname as dirname2 } from "path";
728
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
729
+ import { join as join5, dirname as dirname2 } from "path";
730
730
  import matter2 from "gray-matter";
731
731
 
732
732
  // src/core/section-tree.ts
@@ -934,66 +934,732 @@ Save to: ${section.outputPath}
934
934
  `;
935
935
  }
936
936
 
937
- // src/orchestrator/index.ts
938
- var Orchestrator = class {
939
- cwd;
940
- constructor(cwd = process.cwd()) {
941
- this.cwd = cwd;
937
+ // src/core/prompt-builder.ts
938
+ import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
939
+ import { join as join4 } from "path";
940
+ function buildContextPrompt(params) {
941
+ const cwd = params.cwd || process.cwd();
942
+ const stepsDir = getStepsDir(cwd);
943
+ const isFirstStep = params.stepIndex === 1;
944
+ const instructionPath = join4(stepsDir, params.step, "instruction.md");
945
+ const instruction = existsSync4(instructionPath) ? readFileSync4(instructionPath, "utf-8") : "";
946
+ const parts = [];
947
+ parts.push("# Context Gathering Phase");
948
+ parts.push("");
949
+ parts.push("Your task is to gather context before generating a document.");
950
+ parts.push("Do NOT generate the document yet - only gather information.");
951
+ parts.push("");
952
+ parts.push("## Task Information");
953
+ parts.push("");
954
+ parts.push(`- **Task ID**: ${params.taskId}`);
955
+ parts.push(`- **Current Step**: ${params.step} (${params.stepIndex}/${params.totalSteps})`);
956
+ parts.push("");
957
+ if (isFirstStep) {
958
+ parts.push("## User Request");
959
+ parts.push("");
960
+ parts.push(`> ${params.description}`);
961
+ parts.push("");
962
+ } else if (params.previousOutput) {
963
+ parts.push("## Previous Step Output");
964
+ parts.push("");
965
+ if (existsSync4(params.previousOutput)) {
966
+ parts.push(readFileSync4(params.previousOutput, "utf-8"));
967
+ }
968
+ parts.push("");
942
969
  }
943
- // ===========================================================================
944
- // Config & Path Helpers
945
- // ===========================================================================
946
- getSteps() {
947
- const config = loadConfig(this.cwd);
948
- return config.steps;
970
+ if (instruction) {
971
+ parts.push("## Step Instruction (Preview)");
972
+ parts.push("");
973
+ parts.push("The next phase will use this instruction to generate a document:");
974
+ parts.push("");
975
+ parts.push("```");
976
+ parts.push(instruction.slice(0, 500) + (instruction.length > 500 ? "..." : ""));
977
+ parts.push("```");
978
+ parts.push("");
949
979
  }
950
- getOutputPath() {
951
- return getOutputsDir(this.cwd);
980
+ parts.push("## Your Task");
981
+ parts.push("");
982
+ parts.push("1. **Analyze** the request/input to understand what is being asked");
983
+ parts.push("2. **Search** the codebase for relevant files, patterns, conventions");
984
+ parts.push("3. **Identify** key constraints, dependencies, and considerations");
985
+ parts.push("");
986
+ parts.push("## Output Format");
987
+ parts.push("");
988
+ parts.push("Output a JSON object with this structure:");
989
+ parts.push("");
990
+ parts.push("```json");
991
+ parts.push("{");
992
+ parts.push(' "summary": "Brief summary of what you understood and found",');
993
+ parts.push(' "relevantFiles": ["path/to/file1.ts", "path/to/file2.ts"],');
994
+ parts.push(' "keyFindings": [');
995
+ parts.push(' "Finding 1: description",');
996
+ parts.push(' "Finding 2: description"');
997
+ parts.push(" ]");
998
+ parts.push("}");
999
+ parts.push("```");
1000
+ parts.push("");
1001
+ parts.push("**Important:** Output ONLY the JSON, no other text.");
1002
+ parts.push("");
1003
+ return parts.join("\n");
1004
+ }
1005
+ function buildExplorePrompt(params) {
1006
+ const cwd = params.cwd || process.cwd();
1007
+ const stepsDir = getStepsDir(cwd);
1008
+ const isFirstStep = params.stepIndex === 1;
1009
+ const instructionPath = join4(stepsDir, params.step, "instruction.md");
1010
+ const instruction = existsSync4(instructionPath) ? readFileSync4(instructionPath, "utf-8") : "";
1011
+ const parts = [];
1012
+ parts.push("# Explore Phase - Deep Codebase Analysis");
1013
+ parts.push("");
1014
+ parts.push("Your task is to deeply explore the codebase to understand context for document generation.");
1015
+ parts.push("**IMPORTANT:** Do NOT just list files. You MUST read file contents and analyze them.");
1016
+ parts.push("");
1017
+ parts.push("## Task Information");
1018
+ parts.push("");
1019
+ parts.push(`- **Task ID**: ${params.taskId}`);
1020
+ parts.push(`- **Current Step**: ${params.step} (${params.stepIndex}/${params.totalSteps})`);
1021
+ parts.push("");
1022
+ if (isFirstStep) {
1023
+ parts.push("## User Request");
1024
+ parts.push("");
1025
+ parts.push(`> ${params.description}`);
1026
+ parts.push("");
1027
+ } else if (params.previousOutput) {
1028
+ parts.push("## Previous Step Output");
1029
+ parts.push("");
1030
+ if (existsSync4(params.previousOutput)) {
1031
+ parts.push(readFileSync4(params.previousOutput, "utf-8"));
1032
+ }
1033
+ parts.push("");
952
1034
  }
953
- getStatePath(taskId) {
954
- return join4(this.getOutputPath(), taskId, ".state.json");
1035
+ if (instruction) {
1036
+ parts.push("## Step Instruction (Preview)");
1037
+ parts.push("");
1038
+ parts.push("The document to be generated must follow this instruction:");
1039
+ parts.push("");
1040
+ parts.push("```");
1041
+ parts.push(instruction.slice(0, 1e3) + (instruction.length > 1e3 ? "\n...(truncated)" : ""));
1042
+ parts.push("```");
1043
+ parts.push("");
955
1044
  }
956
- getSpecPath(taskId, step) {
957
- return join4(this.getOutputPath(), taskId, `${step}.md`);
1045
+ parts.push("## Your Task");
1046
+ parts.push("");
1047
+ parts.push("1. **Search** for relevant files using patterns (Glob, Grep)");
1048
+ parts.push("2. **Read** the content of important files (not just paths)");
1049
+ parts.push("3. **Analyze** code patterns, naming conventions, architecture");
1050
+ parts.push('4. **Identify** constraints (e.g., "uses TypeScript strict mode")');
1051
+ parts.push("5. **Find** dependencies (internal and external)");
1052
+ parts.push("");
1053
+ parts.push("**Key difference from context phase:** You must READ file contents, not just list them.");
1054
+ parts.push("");
1055
+ parts.push("## Output Format");
1056
+ parts.push("");
1057
+ parts.push("Output a JSON object with this structure:");
1058
+ parts.push("");
1059
+ parts.push("```json");
1060
+ parts.push("{");
1061
+ parts.push(' "summary": "Comprehensive summary of what you found and understood",');
1062
+ parts.push(' "relevantFiles": [');
1063
+ parts.push(" {");
1064
+ parts.push(' "path": "src/core/example.ts",');
1065
+ parts.push(' "purpose": "Why this file is relevant",');
1066
+ parts.push(' "keySnippets": ["function doSomething() {...}", "export interface Config {...}"]');
1067
+ parts.push(" }");
1068
+ parts.push(" ],");
1069
+ parts.push(' "patterns": [');
1070
+ parts.push(' "Uses dependency injection pattern",');
1071
+ parts.push(' "All exports are named (no default exports)"');
1072
+ parts.push(" ],");
1073
+ parts.push(' "constraints": [');
1074
+ parts.push(' "TypeScript strict mode enabled",');
1075
+ parts.push(' "Must maintain backward compatibility"');
1076
+ parts.push(" ],");
1077
+ parts.push(' "dependencies": [');
1078
+ parts.push(' "gray-matter for frontmatter parsing",');
1079
+ parts.push(' "Internal: uses ../core/config.js"');
1080
+ parts.push(" ]");
1081
+ parts.push("}");
1082
+ parts.push("```");
1083
+ parts.push("");
1084
+ parts.push("**Important:** Output ONLY the JSON, no other text.");
1085
+ parts.push("");
1086
+ return parts.join("\n");
1087
+ }
1088
+ function buildClarifyPrompt(params) {
1089
+ const cwd = params.cwd || process.cwd();
1090
+ const stepsDir = getStepsDir(cwd);
1091
+ const instructionPath = join4(stepsDir, params.step, "instruction.md");
1092
+ const instruction = existsSync4(instructionPath) ? readFileSync4(instructionPath, "utf-8") : "";
1093
+ const parts = [];
1094
+ parts.push("# Clarify Phase");
1095
+ parts.push("");
1096
+ parts.push("Your task is to identify any questions that need user input before generating the document.");
1097
+ parts.push("Do NOT generate the document yet - only generate questions if needed.");
1098
+ parts.push("");
1099
+ parts.push("## Task Information");
1100
+ parts.push("");
1101
+ parts.push(`- **Task ID**: ${params.taskId}`);
1102
+ parts.push(`- **Current Step**: ${params.step}`);
1103
+ parts.push(`- **Description**: ${params.description}`);
1104
+ parts.push("");
1105
+ parts.push("## Gathered Context");
1106
+ parts.push("");
1107
+ parts.push(params.gatheredContext);
1108
+ parts.push("");
1109
+ if (instruction) {
1110
+ parts.push("## Step Instruction");
1111
+ parts.push("");
1112
+ parts.push(instruction);
1113
+ parts.push("");
958
1114
  }
959
- getStepInstructionPath(step) {
960
- return join4(getStepsDir(this.cwd), step, "instruction.md");
1115
+ if (params.previousQA && params.previousQA.length > 0) {
1116
+ parts.push("## Previous Questions & Answers");
1117
+ parts.push("");
1118
+ parts.push("The following questions have already been asked and answered:");
1119
+ parts.push("");
1120
+ for (const entry of params.previousQA) {
1121
+ parts.push(`**Q: ${entry.question.question}**`);
1122
+ if (entry.question.context) {
1123
+ parts.push(`Context: ${entry.question.context}`);
1124
+ }
1125
+ parts.push(`A: ${entry.answer.answer}`);
1126
+ parts.push("");
1127
+ }
1128
+ parts.push("Based on these answers, determine if there are still ambiguities that need clarification.");
1129
+ parts.push("Do NOT repeat questions that have already been answered.");
1130
+ parts.push("");
961
1131
  }
962
- getStepTemplatePath(step) {
963
- return join4(getStepsDir(this.cwd), step, "template.md");
1132
+ parts.push("## Consider These Questions");
1133
+ parts.push("");
1134
+ parts.push("1. Is the task description clear enough to proceed?");
1135
+ parts.push("2. Are there multiple valid approaches that need user decision?");
1136
+ parts.push("3. Are there ambiguities that could lead to wrong implementation?");
1137
+ parts.push("4. Are there missing requirements or constraints?");
1138
+ parts.push("");
1139
+ parts.push("## Output Format");
1140
+ parts.push("");
1141
+ parts.push("Output a JSON object with questions array:");
1142
+ parts.push("");
1143
+ parts.push("```json");
1144
+ parts.push("{");
1145
+ parts.push(' "questions": [');
1146
+ parts.push(" {");
1147
+ parts.push(' "id": "q1",');
1148
+ parts.push(' "question": "Your specific question?",');
1149
+ parts.push(' "context": "Why this matters for the document",');
1150
+ parts.push(' "options": ["Option A", "Option B"] // optional');
1151
+ parts.push(" }");
1152
+ parts.push(" ]");
1153
+ parts.push("}");
1154
+ parts.push("```");
1155
+ parts.push("");
1156
+ parts.push('If no questions are needed, return: `{"questions": []}`');
1157
+ parts.push("");
1158
+ parts.push("**Important:** Output ONLY the JSON, no other text.");
1159
+ parts.push("");
1160
+ return parts.join("\n");
1161
+ }
1162
+ function buildGeneratePrompt(params) {
1163
+ const cwd = params.cwd || process.cwd();
1164
+ const config = loadConfig(cwd);
1165
+ const stepsDir = getStepsDir(cwd);
1166
+ const outputsDir = getOutputsDir(cwd);
1167
+ const isFirstStep = params.stepIndex === 1;
1168
+ const prevStep = params.stepIndex > 1 ? config.steps[params.stepIndex - 2] : null;
1169
+ const instructionPath = join4(stepsDir, params.step, "instruction.md");
1170
+ const templatePath = join4(stepsDir, params.step, "template.md");
1171
+ const outputPath = join4(outputsDir, params.taskId, `${params.step}.md`);
1172
+ if (!existsSync4(instructionPath)) {
1173
+ throw new Error(`Instruction not found: ${instructionPath}`);
964
1174
  }
965
- // ===========================================================================
966
- // State Management
967
- // ===========================================================================
968
- loadState(taskId) {
969
- const statePath = this.getStatePath(taskId);
970
- if (!existsSync4(statePath)) {
971
- return null;
1175
+ const instruction = readFileSync4(instructionPath, "utf-8");
1176
+ const template = existsSync4(templatePath) ? readFileSync4(templatePath, "utf-8") : null;
1177
+ let previousSpec = null;
1178
+ if (prevStep) {
1179
+ const prevPath = join4(outputsDir, params.taskId, `${prevStep}.md`);
1180
+ if (existsSync4(prevPath)) {
1181
+ previousSpec = {
1182
+ step: prevStep,
1183
+ content: readFileSync4(prevPath, "utf-8")
1184
+ };
972
1185
  }
973
- const data = JSON.parse(readFileSync4(statePath, "utf-8"));
974
- return data;
975
1186
  }
976
- saveState(state) {
977
- state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
978
- const statePath = this.getStatePath(state.taskId);
979
- const dir = dirname2(statePath);
980
- if (!existsSync4(dir)) {
981
- mkdirSync3(dir, { recursive: true });
982
- }
983
- writeFileSync3(statePath, JSON.stringify(state, null, 2));
1187
+ const parts = [];
1188
+ parts.push("# Document Generation Phase");
1189
+ parts.push("");
1190
+ parts.push("Generate the document based on the gathered context and user answers.");
1191
+ parts.push("");
1192
+ parts.push("## Step Instruction");
1193
+ parts.push("");
1194
+ parts.push(instruction);
1195
+ parts.push("");
1196
+ if (template) {
1197
+ parts.push("## Document Template");
1198
+ parts.push("");
1199
+ parts.push("**CRITICAL: You MUST follow this template structure completely.**");
1200
+ parts.push("");
1201
+ parts.push(template);
1202
+ parts.push("");
984
1203
  }
985
- // ===========================================================================
986
- // Spec Helpers
987
- // ===========================================================================
988
- checkUnresolvedQuestions(specPath) {
989
- if (!existsSync4(specPath)) {
990
- return [];
1204
+ parts.push("## Gathered Context");
1205
+ parts.push("");
1206
+ parts.push(params.gatheredContext);
1207
+ parts.push("");
1208
+ if (params.answers && params.answers.length > 0) {
1209
+ parts.push("## User Answers");
1210
+ parts.push("");
1211
+ for (const answer of params.answers) {
1212
+ parts.push(`- **${answer.questionId}**: ${answer.answer}`);
991
1213
  }
992
- const content = readFileSync4(specPath, "utf-8");
993
- const { data } = matter2(content);
994
- const questions = [];
995
- if (data.open_questions && Array.isArray(data.open_questions)) {
996
- for (let i = 0; i < data.open_questions.length; i++) {
1214
+ parts.push("");
1215
+ }
1216
+ if (isFirstStep) {
1217
+ parts.push("## User Request");
1218
+ parts.push("");
1219
+ parts.push(`> ${params.description}`);
1220
+ parts.push("");
1221
+ } else if (previousSpec) {
1222
+ parts.push(`## Input: ${previousSpec.step}.md`);
1223
+ parts.push("");
1224
+ parts.push(previousSpec.content);
1225
+ parts.push("");
1226
+ }
1227
+ parts.push("## Task Context");
1228
+ parts.push("");
1229
+ parts.push(`- **Task ID**: ${params.taskId}`);
1230
+ parts.push(`- **Current Step**: ${params.step} (${params.stepIndex}/${params.totalSteps})`);
1231
+ parts.push("");
1232
+ if (params.revisionFeedback) {
1233
+ parts.push("## Revision Feedback");
1234
+ parts.push("");
1235
+ parts.push("Previous version was not approved. Please revise based on this feedback:");
1236
+ parts.push("");
1237
+ parts.push(`> ${params.revisionFeedback}`);
1238
+ parts.push("");
1239
+ }
1240
+ parts.push("## Output Instructions");
1241
+ parts.push("");
1242
+ parts.push(`Generate the document and save to: \`${outputPath}\``);
1243
+ parts.push("");
1244
+ parts.push("**Required frontmatter:**");
1245
+ parts.push("```yaml");
1246
+ parts.push("---");
1247
+ parts.push(`id: ${params.taskId}`);
1248
+ parts.push(`step: ${params.step}`);
1249
+ parts.push("status: pending_approval");
1250
+ parts.push("---");
1251
+ parts.push("```");
1252
+ parts.push("");
1253
+ return {
1254
+ prompt: parts.join("\n"),
1255
+ outputPath
1256
+ };
1257
+ }
1258
+ function buildSectionPrompt(params) {
1259
+ const { section, sharedContext, gatheredContext, answers } = params;
1260
+ const parts = [];
1261
+ parts.push(`# Section: ${section.title}`);
1262
+ parts.push("");
1263
+ parts.push("## Document Context");
1264
+ parts.push("");
1265
+ parts.push(`**Goal:** ${sharedContext.documentGoal}`);
1266
+ parts.push(`**Step:** ${sharedContext.stepName}`);
1267
+ parts.push(`**Total Sections:** ${sharedContext.totalSections}`);
1268
+ parts.push("");
1269
+ parts.push("## Document Structure");
1270
+ parts.push("");
1271
+ parts.push("```");
1272
+ parts.push(sharedContext.treeOverview);
1273
+ parts.push("```");
1274
+ parts.push("");
1275
+ parts.push("## Your Position");
1276
+ parts.push("");
1277
+ parts.push(`- **Path:** ${section.position.path.join(" > ")}`);
1278
+ parts.push(`- **Siblings:** ${section.position.siblings.join(", ") || "None"}`);
1279
+ parts.push(`- **Parent:** ${section.position.parent || "Root"}`);
1280
+ parts.push("");
1281
+ if (gatheredContext) {
1282
+ parts.push("## Gathered Context");
1283
+ parts.push("");
1284
+ parts.push(gatheredContext);
1285
+ parts.push("");
1286
+ }
1287
+ if (answers && answers.length > 0) {
1288
+ parts.push("## User Answers");
1289
+ parts.push("");
1290
+ for (const answer of answers) {
1291
+ parts.push(`- **${answer.questionId}**: ${answer.answer}`);
1292
+ }
1293
+ parts.push("");
1294
+ }
1295
+ if (section.templateContent) {
1296
+ parts.push("## Template Guide");
1297
+ parts.push("");
1298
+ parts.push(section.templateContent);
1299
+ parts.push("");
1300
+ }
1301
+ parts.push("## Your Task");
1302
+ parts.push("");
1303
+ parts.push(`Write the "${section.title.replace(/^#+\\s*/, "")}" section.`);
1304
+ parts.push("Consider how it relates to sibling sections and contributes to the parent section.");
1305
+ parts.push("");
1306
+ parts.push("## Output");
1307
+ parts.push("");
1308
+ parts.push(`Save to: \`${section.outputPath}\``);
1309
+ parts.push("");
1310
+ parts.push("Write ONLY the content for this section (including its header).");
1311
+ parts.push("Do NOT include content from other sections.");
1312
+ parts.push("");
1313
+ return {
1314
+ prompt: parts.join("\n"),
1315
+ outputPath: section.outputPath
1316
+ };
1317
+ }
1318
+ function buildConsolidatePrompt(params) {
1319
+ const { group, childContents, sharedContext, parentTitle } = params;
1320
+ const parts = [];
1321
+ parts.push("# Consolidate Sections");
1322
+ parts.push("");
1323
+ parts.push("## Document Context");
1324
+ parts.push("");
1325
+ parts.push(`**Goal:** ${sharedContext.documentGoal}`);
1326
+ parts.push(`**Step:** ${sharedContext.stepName}`);
1327
+ parts.push("");
1328
+ parts.push("## Document Structure");
1329
+ parts.push("");
1330
+ parts.push("```");
1331
+ parts.push(sharedContext.treeOverview);
1332
+ parts.push("```");
1333
+ parts.push("");
1334
+ parts.push("## Your Task");
1335
+ parts.push("");
1336
+ parts.push(`Consolidate the following child sections into the parent section "${parentTitle || group.parentId}".`);
1337
+ parts.push("");
1338
+ parts.push("## Child Sections to Consolidate");
1339
+ parts.push("");
1340
+ for (const child of childContents) {
1341
+ parts.push(`### Child: ${child.id}`);
1342
+ parts.push("");
1343
+ parts.push(child.content);
1344
+ parts.push("");
1345
+ parts.push("---");
1346
+ parts.push("");
1347
+ }
1348
+ parts.push("## Output Instructions");
1349
+ parts.push("");
1350
+ parts.push(`Save consolidated content to: \`${group.outputPath}\``);
1351
+ parts.push("");
1352
+ parts.push("**Guidelines:**");
1353
+ parts.push("- Combine child sections into a coherent parent section");
1354
+ parts.push("- Maintain the hierarchy (parent header, then children)");
1355
+ parts.push("- Ensure smooth transitions between sections");
1356
+ parts.push("- Preserve all content from child sections");
1357
+ parts.push("");
1358
+ return {
1359
+ prompt: parts.join("\n"),
1360
+ outputPath: group.outputPath
1361
+ };
1362
+ }
1363
+ function buildExecutePrompt(params) {
1364
+ const cwd = params.cwd || process.cwd();
1365
+ const config = loadConfig(cwd);
1366
+ const stepsDir = getStepsDir(cwd);
1367
+ const outputsDir = getOutputsDir(cwd);
1368
+ const isFirstStep = params.stepIndex === 1;
1369
+ const prevStep = params.stepIndex > 1 ? config.steps[params.stepIndex - 2] : null;
1370
+ const instructionPath = join4(stepsDir, params.step, "instruction.md");
1371
+ const templatePath = join4(stepsDir, params.step, "template.md");
1372
+ const outputPath = join4(outputsDir, params.taskId, `${params.step}.md`);
1373
+ if (!existsSync4(instructionPath)) {
1374
+ throw new Error(`Instruction not found: ${instructionPath}`);
1375
+ }
1376
+ const instruction = readFileSync4(instructionPath, "utf-8");
1377
+ const template = existsSync4(templatePath) ? readFileSync4(templatePath, "utf-8") : null;
1378
+ let previousSpec = null;
1379
+ if (prevStep) {
1380
+ const prevPath = join4(outputsDir, params.taskId, `${prevStep}.md`);
1381
+ if (existsSync4(prevPath)) {
1382
+ previousSpec = {
1383
+ step: prevStep,
1384
+ content: readFileSync4(prevPath, "utf-8")
1385
+ };
1386
+ }
1387
+ }
1388
+ const parts = [];
1389
+ parts.push("# Execute Phase - Document/Code Generation");
1390
+ parts.push("");
1391
+ parts.push("Generate the document/code based on the explored context and user answers.");
1392
+ parts.push("");
1393
+ parts.push("## Step Instruction");
1394
+ parts.push("");
1395
+ parts.push(instruction);
1396
+ parts.push("");
1397
+ if (template) {
1398
+ parts.push("## Document Template");
1399
+ parts.push("");
1400
+ parts.push("**CRITICAL: You MUST follow this template structure completely.**");
1401
+ parts.push("");
1402
+ parts.push(template);
1403
+ parts.push("");
1404
+ }
1405
+ parts.push("## Explored Context");
1406
+ parts.push("");
1407
+ parts.push(`### Summary`);
1408
+ parts.push(params.exploreOutput.summary);
1409
+ parts.push("");
1410
+ if (params.exploreOutput.relevantFiles.length > 0) {
1411
+ parts.push("### Relevant Files");
1412
+ for (const file of params.exploreOutput.relevantFiles) {
1413
+ parts.push(`- **${file.path}**: ${file.purpose}`);
1414
+ if (file.keySnippets && file.keySnippets.length > 0) {
1415
+ parts.push(" ```");
1416
+ parts.push(" " + file.keySnippets.slice(0, 2).join("\n "));
1417
+ parts.push(" ```");
1418
+ }
1419
+ }
1420
+ parts.push("");
1421
+ }
1422
+ if (params.exploreOutput.patterns.length > 0) {
1423
+ parts.push("### Patterns");
1424
+ for (const pattern of params.exploreOutput.patterns) {
1425
+ parts.push(`- ${pattern}`);
1426
+ }
1427
+ parts.push("");
1428
+ }
1429
+ if (params.exploreOutput.constraints.length > 0) {
1430
+ parts.push("### Constraints");
1431
+ for (const constraint of params.exploreOutput.constraints) {
1432
+ parts.push(`- ${constraint}`);
1433
+ }
1434
+ parts.push("");
1435
+ }
1436
+ if (params.exploreOutput.dependencies.length > 0) {
1437
+ parts.push("### Dependencies");
1438
+ for (const dep of params.exploreOutput.dependencies) {
1439
+ parts.push(`- ${dep}`);
1440
+ }
1441
+ parts.push("");
1442
+ }
1443
+ if (params.answers && params.answers.length > 0) {
1444
+ parts.push("## User Answers");
1445
+ parts.push("");
1446
+ for (const answer of params.answers) {
1447
+ parts.push(`- **${answer.questionId}**: ${answer.answer}`);
1448
+ }
1449
+ parts.push("");
1450
+ }
1451
+ if (isFirstStep) {
1452
+ parts.push("## User Request");
1453
+ parts.push("");
1454
+ parts.push(`> ${params.description}`);
1455
+ parts.push("");
1456
+ } else if (previousSpec) {
1457
+ parts.push(`## Input: ${previousSpec.step}.md`);
1458
+ parts.push("");
1459
+ parts.push(previousSpec.content);
1460
+ parts.push("");
1461
+ }
1462
+ parts.push("## Task Context");
1463
+ parts.push("");
1464
+ parts.push(`- **Task ID**: ${params.taskId}`);
1465
+ parts.push(`- **Current Step**: ${params.step} (${params.stepIndex}/${params.totalSteps})`);
1466
+ parts.push("");
1467
+ if (params.verifyFeedback) {
1468
+ parts.push("## Auto-Fix Required");
1469
+ parts.push("");
1470
+ parts.push("**Previous draft failed verification. Fix these issues:**");
1471
+ parts.push("");
1472
+ parts.push(params.verifyFeedback);
1473
+ parts.push("");
1474
+ }
1475
+ if (params.revisionFeedback) {
1476
+ parts.push("## Revision Feedback");
1477
+ parts.push("");
1478
+ parts.push("Previous version was not approved. Please revise based on this feedback:");
1479
+ parts.push("");
1480
+ parts.push(`> ${params.revisionFeedback}`);
1481
+ parts.push("");
1482
+ }
1483
+ parts.push("## Output Instructions");
1484
+ parts.push("");
1485
+ parts.push(`Generate the document and save to: \`${outputPath}\``);
1486
+ parts.push("");
1487
+ parts.push("**Required frontmatter:**");
1488
+ parts.push("```yaml");
1489
+ parts.push("---");
1490
+ parts.push(`id: ${params.taskId}`);
1491
+ parts.push(`step: ${params.step}`);
1492
+ parts.push("status: pending_approval");
1493
+ parts.push("---");
1494
+ parts.push("```");
1495
+ parts.push("");
1496
+ return {
1497
+ prompt: parts.join("\n"),
1498
+ outputPath
1499
+ };
1500
+ }
1501
+ function buildVerifyPrompt(params) {
1502
+ const cwd = params.cwd || process.cwd();
1503
+ const stepsDir = getStepsDir(cwd);
1504
+ const instructionPath = join4(stepsDir, params.step, "instruction.md");
1505
+ const templatePath = join4(stepsDir, params.step, "template.md");
1506
+ const instruction = existsSync4(instructionPath) ? readFileSync4(instructionPath, "utf-8") : "";
1507
+ const template = existsSync4(templatePath) ? readFileSync4(templatePath, "utf-8") : "";
1508
+ const document = existsSync4(params.documentPath) ? readFileSync4(params.documentPath, "utf-8") : "";
1509
+ const parts = [];
1510
+ parts.push("# Verify Phase - Self-Validation");
1511
+ parts.push("");
1512
+ parts.push("Your task is to validate the generated document against the requirements.");
1513
+ parts.push("This is an automated quality check before human review.");
1514
+ parts.push("");
1515
+ parts.push(`**Attempt ${params.verifyAttempts} of 3**`);
1516
+ parts.push("");
1517
+ parts.push("## Task Information");
1518
+ parts.push("");
1519
+ parts.push(`- **Task ID**: ${params.taskId}`);
1520
+ parts.push(`- **Current Step**: ${params.step} (${params.stepIndex}/${params.totalSteps})`);
1521
+ parts.push("");
1522
+ parts.push("## Document to Verify");
1523
+ parts.push("");
1524
+ parts.push("```markdown");
1525
+ parts.push(document);
1526
+ parts.push("```");
1527
+ parts.push("");
1528
+ parts.push("## Requirements (Instruction)");
1529
+ parts.push("");
1530
+ if (instruction) {
1531
+ parts.push(instruction);
1532
+ } else {
1533
+ parts.push("(No instruction found)");
1534
+ }
1535
+ parts.push("");
1536
+ if (template) {
1537
+ parts.push("## Expected Structure (Template)");
1538
+ parts.push("");
1539
+ parts.push(template);
1540
+ parts.push("");
1541
+ }
1542
+ parts.push("## Verification Checklist");
1543
+ parts.push("");
1544
+ parts.push("Evaluate the document against these criteria:");
1545
+ parts.push("");
1546
+ parts.push("1. **Requirements Coverage** (0-100)");
1547
+ parts.push(" - Does the document address all requirements from the instruction?");
1548
+ parts.push(" - Are there missing pieces?");
1549
+ parts.push("");
1550
+ parts.push("2. **Template Compliance** (0-100)");
1551
+ parts.push(" - Does it follow the template structure?");
1552
+ parts.push(" - Are all required sections present?");
1553
+ parts.push(" - Is frontmatter correct?");
1554
+ parts.push("");
1555
+ parts.push("3. **Consistency** (0-100)");
1556
+ parts.push(" - Is terminology consistent throughout?");
1557
+ parts.push(" - Are there contradictions?");
1558
+ parts.push(" - Does it align with explored codebase patterns?");
1559
+ parts.push("");
1560
+ parts.push("4. **Completeness** (0-100)");
1561
+ parts.push(" - Are all sections fully filled in?");
1562
+ parts.push(" - Are there placeholder texts or TODOs?");
1563
+ parts.push(" - Is there enough detail?");
1564
+ parts.push("");
1565
+ parts.push("## Pass Criteria");
1566
+ parts.push("");
1567
+ parts.push("The document passes if:");
1568
+ parts.push("- ALL scores >= 70");
1569
+ parts.push('- NO issues with severity "error"');
1570
+ parts.push("");
1571
+ parts.push("If it fails, the document will be automatically revised (up to 3 attempts).");
1572
+ parts.push("");
1573
+ parts.push("## Output Format");
1574
+ parts.push("");
1575
+ parts.push("Output a JSON object with this structure:");
1576
+ parts.push("");
1577
+ parts.push("```json");
1578
+ parts.push("{");
1579
+ parts.push(' "passed": true,');
1580
+ parts.push(' "score": {');
1581
+ parts.push(' "requirementsCoverage": 85,');
1582
+ parts.push(' "templateCompliance": 90,');
1583
+ parts.push(' "consistency": 80,');
1584
+ parts.push(' "completeness": 75');
1585
+ parts.push(" },");
1586
+ parts.push(' "issues": [');
1587
+ parts.push(" {");
1588
+ parts.push(' "severity": "warning",');
1589
+ parts.push(' "category": "completeness",');
1590
+ parts.push(' "description": "Section X could use more detail",');
1591
+ parts.push(' "suggestion": "Add examples for the edge cases"');
1592
+ parts.push(" }");
1593
+ parts.push(" ],");
1594
+ parts.push(' "summary": "Document meets requirements with minor suggestions for improvement."');
1595
+ parts.push("}");
1596
+ parts.push("```");
1597
+ parts.push("");
1598
+ parts.push("**Important:** Output ONLY the JSON, no other text.");
1599
+ parts.push("");
1600
+ return parts.join("\n");
1601
+ }
1602
+
1603
+ // src/orchestrator/index.ts
1604
+ var Orchestrator = class {
1605
+ cwd;
1606
+ constructor(cwd = process.cwd()) {
1607
+ this.cwd = cwd;
1608
+ }
1609
+ // ===========================================================================
1610
+ // Config & Path Helpers
1611
+ // ===========================================================================
1612
+ getSteps() {
1613
+ const config = loadConfig(this.cwd);
1614
+ return config.steps;
1615
+ }
1616
+ getOutputPath() {
1617
+ return getOutputsDir(this.cwd);
1618
+ }
1619
+ getStatePath(taskId) {
1620
+ return join5(this.getOutputPath(), taskId, ".state.json");
1621
+ }
1622
+ getSpecPath(taskId, step) {
1623
+ return join5(this.getOutputPath(), taskId, `${step}.md`);
1624
+ }
1625
+ getStepInstructionPath(step) {
1626
+ return join5(getStepsDir(this.cwd), step, "instruction.md");
1627
+ }
1628
+ getStepTemplatePath(step) {
1629
+ return join5(getStepsDir(this.cwd), step, "template.md");
1630
+ }
1631
+ // ===========================================================================
1632
+ // State Management
1633
+ // ===========================================================================
1634
+ loadState(taskId) {
1635
+ const statePath = this.getStatePath(taskId);
1636
+ if (!existsSync5(statePath)) {
1637
+ return null;
1638
+ }
1639
+ const data = JSON.parse(readFileSync5(statePath, "utf-8"));
1640
+ return data;
1641
+ }
1642
+ saveState(state) {
1643
+ state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1644
+ const statePath = this.getStatePath(state.taskId);
1645
+ const dir = dirname2(statePath);
1646
+ if (!existsSync5(dir)) {
1647
+ mkdirSync3(dir, { recursive: true });
1648
+ }
1649
+ writeFileSync3(statePath, JSON.stringify(state, null, 2));
1650
+ }
1651
+ // ===========================================================================
1652
+ // Spec Helpers
1653
+ // ===========================================================================
1654
+ checkUnresolvedQuestions(specPath) {
1655
+ if (!existsSync5(specPath)) {
1656
+ return [];
1657
+ }
1658
+ const content = readFileSync5(specPath, "utf-8");
1659
+ const { data } = matter2(content);
1660
+ const questions = [];
1661
+ if (data.open_questions && Array.isArray(data.open_questions)) {
1662
+ for (let i = 0; i < data.open_questions.length; i++) {
997
1663
  const q = data.open_questions[i];
998
1664
  if (!q.resolved) {
999
1665
  questions.push({
@@ -1013,6 +1679,7 @@ var Orchestrator = class {
1013
1679
  // ===========================================================================
1014
1680
  /**
1015
1681
  * Phase 1: Context gathering
1682
+ * @deprecated Use responsePhaseExplore instead
1016
1683
  */
1017
1684
  responsePhaseContext(state) {
1018
1685
  const steps = this.getSteps();
@@ -1020,8 +1687,8 @@ var Orchestrator = class {
1020
1687
  let previousOutput;
1021
1688
  if (state.stepIndex > 1) {
1022
1689
  const prevStep = steps[state.stepIndex - 2];
1023
- const prevPath = join4(outputPath, state.taskId, `${prevStep}.md`);
1024
- if (existsSync4(prevPath)) {
1690
+ const prevPath = join5(outputPath, state.taskId, `${prevStep}.md`);
1691
+ if (existsSync5(prevPath)) {
1025
1692
  previousOutput = prevPath;
1026
1693
  }
1027
1694
  }
@@ -1040,16 +1707,64 @@ var Orchestrator = class {
1040
1707
  onComplete: `context-done ${state.taskId}`
1041
1708
  };
1042
1709
  }
1710
+ /**
1711
+ * Phase 1 (New): Deep codebase exploration
1712
+ */
1713
+ responsePhaseExplore(state) {
1714
+ const steps = this.getSteps();
1715
+ const outputPath = this.getOutputPath();
1716
+ let previousOutput;
1717
+ if (state.stepIndex > 1) {
1718
+ const prevStep = steps[state.stepIndex - 2];
1719
+ const prevPath = join5(outputPath, state.taskId, `${prevStep}.md`);
1720
+ if (existsSync5(prevPath)) {
1721
+ previousOutput = prevPath;
1722
+ }
1723
+ }
1724
+ const prompt = buildExplorePrompt({
1725
+ taskId: state.taskId,
1726
+ step: state.currentStep,
1727
+ description: state.description,
1728
+ stepIndex: state.stepIndex,
1729
+ totalSteps: state.totalSteps,
1730
+ previousOutput,
1731
+ cwd: this.cwd
1732
+ });
1733
+ return {
1734
+ type: "phase",
1735
+ phase: "explore",
1736
+ step: state.currentStep,
1737
+ stepIndex: state.stepIndex,
1738
+ totalSteps: state.totalSteps,
1739
+ taskId: state.taskId,
1740
+ description: state.description,
1741
+ prompt,
1742
+ context: {
1743
+ instruction: this.getStepInstructionPath(state.currentStep),
1744
+ previousOutput
1745
+ },
1746
+ onComplete: `explore-done ${state.taskId}`
1747
+ };
1748
+ }
1043
1749
  /**
1044
1750
  * Phase 2: Question generation
1045
1751
  */
1046
1752
  responsePhaseClarify(state) {
1753
+ const prompt = buildClarifyPrompt({
1754
+ taskId: state.taskId,
1755
+ step: state.currentStep,
1756
+ description: state.description,
1757
+ gatheredContext: state.context || "",
1758
+ previousQA: state.qaHistory,
1759
+ cwd: this.cwd
1760
+ });
1047
1761
  return {
1048
1762
  type: "phase",
1049
1763
  phase: "clarify",
1050
1764
  step: state.currentStep,
1051
1765
  taskId: state.taskId,
1052
1766
  description: state.description,
1767
+ prompt,
1053
1768
  gatheredContext: state.context || "",
1054
1769
  previousQA: state.qaHistory,
1055
1770
  context: {
@@ -1060,6 +1775,7 @@ var Orchestrator = class {
1060
1775
  }
1061
1776
  /**
1062
1777
  * Phase 3: Document generation
1778
+ * @deprecated Use responsePhaseExecute instead
1063
1779
  */
1064
1780
  responsePhaseGenerate(state) {
1065
1781
  const steps = this.getSteps();
@@ -1067,13 +1783,13 @@ var Orchestrator = class {
1067
1783
  let previousOutput;
1068
1784
  if (state.stepIndex > 1) {
1069
1785
  const prevStep = steps[state.stepIndex - 2];
1070
- const prevPath = join4(outputPath, state.taskId, `${prevStep}.md`);
1071
- if (existsSync4(prevPath)) {
1786
+ const prevPath = join5(outputPath, state.taskId, `${prevStep}.md`);
1787
+ if (existsSync5(prevPath)) {
1072
1788
  previousOutput = prevPath;
1073
1789
  }
1074
1790
  }
1075
1791
  const templatePath = this.getStepTemplatePath(state.currentStep);
1076
- const hasTemplate = existsSync4(templatePath);
1792
+ const hasTemplate = existsSync5(templatePath);
1077
1793
  return {
1078
1794
  type: "phase",
1079
1795
  phase: "generate",
@@ -1088,12 +1804,112 @@ var Orchestrator = class {
1088
1804
  instruction: this.getStepInstructionPath(state.currentStep),
1089
1805
  template: hasTemplate ? templatePath : void 0,
1090
1806
  previousOutput,
1091
- output: join4(outputPath, state.taskId, `${state.currentStep}.md`),
1807
+ output: join5(outputPath, state.taskId, `${state.currentStep}.md`),
1092
1808
  revisionFeedback: state.revisionFeedback
1093
1809
  },
1094
1810
  onComplete: `generate-done ${state.taskId}`
1095
1811
  };
1096
1812
  }
1813
+ /**
1814
+ * Phase 3 (New): Document/code generation with explore output
1815
+ */
1816
+ responsePhaseExecute(state) {
1817
+ const steps = this.getSteps();
1818
+ const outputPath = this.getOutputPath();
1819
+ let previousOutput;
1820
+ if (state.stepIndex > 1) {
1821
+ const prevStep = steps[state.stepIndex - 2];
1822
+ const prevPath = join5(outputPath, state.taskId, `${prevStep}.md`);
1823
+ if (existsSync5(prevPath)) {
1824
+ previousOutput = prevPath;
1825
+ }
1826
+ }
1827
+ const templatePath = this.getStepTemplatePath(state.currentStep);
1828
+ const hasTemplate = existsSync5(templatePath);
1829
+ let verifyFeedback;
1830
+ if (state.verifyOutput && !state.verifyOutput.passed && state.verifyAttempts && state.verifyAttempts > 1) {
1831
+ const issues = state.verifyOutput.issues.filter((i) => i.severity === "error").map((i) => `- [${i.category}] ${i.description}${i.suggestion ? ` \u2192 ${i.suggestion}` : ""}`).join("\n");
1832
+ verifyFeedback = `Auto-fix attempt ${state.verifyAttempts}/3. Fix these issues:
1833
+ ${issues}`;
1834
+ }
1835
+ const exploreOutput = state.exploreOutput || {
1836
+ summary: state.context || "",
1837
+ relevantFiles: [],
1838
+ patterns: [],
1839
+ constraints: [],
1840
+ dependencies: []
1841
+ };
1842
+ const { prompt } = buildExecutePrompt({
1843
+ taskId: state.taskId,
1844
+ step: state.currentStep,
1845
+ description: state.description,
1846
+ stepIndex: state.stepIndex,
1847
+ totalSteps: state.totalSteps,
1848
+ exploreOutput,
1849
+ answers: state.answers,
1850
+ revisionFeedback: state.revisionFeedback,
1851
+ verifyFeedback,
1852
+ cwd: this.cwd
1853
+ });
1854
+ return {
1855
+ type: "phase",
1856
+ phase: "execute",
1857
+ step: state.currentStep,
1858
+ stepIndex: state.stepIndex,
1859
+ totalSteps: state.totalSteps,
1860
+ taskId: state.taskId,
1861
+ description: state.description,
1862
+ prompt,
1863
+ exploreOutput,
1864
+ answers: state.answers,
1865
+ context: {
1866
+ instruction: this.getStepInstructionPath(state.currentStep),
1867
+ template: hasTemplate ? templatePath : void 0,
1868
+ previousOutput,
1869
+ output: join5(outputPath, state.taskId, `${state.currentStep}.md`),
1870
+ revisionFeedback: state.revisionFeedback,
1871
+ verifyFeedback
1872
+ },
1873
+ onComplete: `execute-done ${state.taskId}`
1874
+ };
1875
+ }
1876
+ /**
1877
+ * Phase 4 (New): Self-validation
1878
+ */
1879
+ responsePhaseVerify(state) {
1880
+ const outputPath = this.getOutputPath();
1881
+ const templatePath = this.getStepTemplatePath(state.currentStep);
1882
+ const hasTemplate = existsSync5(templatePath);
1883
+ const documentPath = join5(outputPath, state.taskId, `${state.currentStep}.md`);
1884
+ const prompt = buildVerifyPrompt({
1885
+ taskId: state.taskId,
1886
+ step: state.currentStep,
1887
+ description: state.description,
1888
+ stepIndex: state.stepIndex,
1889
+ totalSteps: state.totalSteps,
1890
+ documentPath,
1891
+ verifyAttempts: state.verifyAttempts || 1,
1892
+ cwd: this.cwd
1893
+ });
1894
+ return {
1895
+ type: "phase",
1896
+ phase: "verify",
1897
+ step: state.currentStep,
1898
+ stepIndex: state.stepIndex,
1899
+ totalSteps: state.totalSteps,
1900
+ taskId: state.taskId,
1901
+ description: state.description,
1902
+ prompt,
1903
+ verifyAttempts: state.verifyAttempts || 1,
1904
+ maxAttempts: 3,
1905
+ context: {
1906
+ instruction: this.getStepInstructionPath(state.currentStep),
1907
+ template: hasTemplate ? templatePath : void 0,
1908
+ document: documentPath
1909
+ },
1910
+ onComplete: `verify-done ${state.taskId}`
1911
+ };
1912
+ }
1097
1913
  /**
1098
1914
  * Phase 3 (section mode): Parallel section generation
1099
1915
  */
@@ -1106,15 +1922,15 @@ var Orchestrator = class {
1106
1922
  let previousOutput;
1107
1923
  if (state.stepIndex > 1) {
1108
1924
  const prevStep = steps[state.stepIndex - 2];
1109
- const prevPath = join4(outputPath, state.taskId, `${prevStep}.md`);
1110
- if (existsSync4(prevPath)) {
1925
+ const prevPath = join5(outputPath, state.taskId, `${prevStep}.md`);
1926
+ if (existsSync5(prevPath)) {
1111
1927
  previousOutput = prevPath;
1112
1928
  }
1113
1929
  }
1114
1930
  const parallelSections = state.sectionPlan.leaves.map((leaf) => ({
1115
1931
  id: leaf.id,
1116
1932
  title: leaf.title,
1117
- outputPath: join4(outputPath, state.taskId, leaf.outputPath),
1933
+ outputPath: join5(outputPath, state.taskId, leaf.outputPath),
1118
1934
  instruction: buildSectionInstruction(leaf, state.sectionPlan.sharedContext),
1119
1935
  position: {
1120
1936
  path: leaf.position.path,
@@ -1138,7 +1954,7 @@ var Orchestrator = class {
1138
1954
  instruction: this.getStepInstructionPath(state.currentStep),
1139
1955
  template: this.getStepTemplatePath(state.currentStep),
1140
1956
  previousOutput,
1141
- outputDir: join4(outputPath, state.taskId, "sections", state.currentStep)
1957
+ outputDir: join5(outputPath, state.taskId, "sections", state.currentStep)
1142
1958
  },
1143
1959
  onComplete: `sections-done ${state.taskId}`
1144
1960
  };
@@ -1153,7 +1969,7 @@ var Orchestrator = class {
1153
1969
  const outputPath = this.getOutputPath();
1154
1970
  const parallelGroups = level.groups.map((group) => ({
1155
1971
  ...group,
1156
- outputPath: join4(outputPath, state.taskId, group.outputPath)
1972
+ outputPath: join5(outputPath, state.taskId, group.outputPath)
1157
1973
  }));
1158
1974
  return {
1159
1975
  type: "phase",
@@ -1195,11 +2011,11 @@ var Orchestrator = class {
1195
2011
  missing.push(childId);
1196
2012
  continue;
1197
2013
  }
1198
- const fullPath = join4(outputPath, state.taskId, childPath);
1199
- if (!existsSync4(fullPath)) {
2014
+ const fullPath = join5(outputPath, state.taskId, childPath);
2015
+ if (!existsSync5(fullPath)) {
1200
2016
  missing.push(childId);
1201
2017
  } else {
1202
- const content = readFileSync4(fullPath, "utf-8");
2018
+ const content = readFileSync5(fullPath, "utf-8");
1203
2019
  if (!content.trim()) {
1204
2020
  warnings.push(`Empty section file: ${childId}`);
1205
2021
  }
@@ -1244,7 +2060,7 @@ var Orchestrator = class {
1244
2060
  step: state.currentStep,
1245
2061
  stepIndex: state.stepIndex,
1246
2062
  totalSteps: state.totalSteps,
1247
- specPath: join4(outputPath, state.taskId, `${state.currentStep}.md`),
2063
+ specPath: join5(outputPath, state.taskId, `${state.currentStep}.md`),
1248
2064
  options: ["approve", "revise", "reject", "stop"],
1249
2065
  onComplete: {
1250
2066
  approve: `approve ${state.taskId}`,
@@ -1259,8 +2075,8 @@ var Orchestrator = class {
1259
2075
  const outputPath = this.getOutputPath();
1260
2076
  const outputs = [];
1261
2077
  for (let i = 0; i < state.stepIndex; i++) {
1262
- const specPath = join4(outputPath, state.taskId, `${steps[i]}.md`);
1263
- if (existsSync4(specPath)) {
2078
+ const specPath = join5(outputPath, state.taskId, `${steps[i]}.md`);
2079
+ if (existsSync5(specPath)) {
1264
2080
  outputs.push(specPath);
1265
2081
  }
1266
2082
  }
@@ -1287,7 +2103,7 @@ var Orchestrator = class {
1287
2103
  // Command Handlers
1288
2104
  // ===========================================================================
1289
2105
  /**
1290
- * Initialize a new workflow - starts at phase_context
2106
+ * Initialize a new workflow - starts at phase_explore
1291
2107
  */
1292
2108
  cmdInit(description) {
1293
2109
  try {
@@ -1299,18 +2115,19 @@ var Orchestrator = class {
1299
2115
  currentStep: steps[0],
1300
2116
  stepIndex: 1,
1301
2117
  totalSteps: steps.length,
1302
- status: "phase_context",
1303
- phase: "context",
2118
+ status: "phase_explore",
2119
+ phase: "explore",
1304
2120
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
1305
2121
  };
1306
2122
  this.saveState(state);
1307
- return this.responsePhaseContext(state);
2123
+ return this.responsePhaseExplore(state);
1308
2124
  } catch (e) {
1309
2125
  return this.responseError(e.message);
1310
2126
  }
1311
2127
  }
1312
2128
  /**
1313
2129
  * Phase 1 complete: Context gathered, move to clarify phase
2130
+ * @deprecated Use cmdExploreDone instead
1314
2131
  */
1315
2132
  cmdContextDone(taskId, context) {
1316
2133
  const state = this.loadState(taskId);
@@ -1323,10 +2140,25 @@ var Orchestrator = class {
1323
2140
  this.saveState(state);
1324
2141
  return this.responsePhaseClarify(state);
1325
2142
  }
2143
+ /**
2144
+ * Phase 1 complete (New): Exploration complete, move to clarify phase
2145
+ */
2146
+ cmdExploreDone(taskId, exploreOutput) {
2147
+ const state = this.loadState(taskId);
2148
+ if (!state) {
2149
+ return this.responseError(`No workflow found: ${taskId}`, taskId);
2150
+ }
2151
+ state.exploreOutput = exploreOutput;
2152
+ state.context = JSON.stringify(exploreOutput);
2153
+ state.status = "phase_clarify";
2154
+ state.phase = "clarify";
2155
+ this.saveState(state);
2156
+ return this.responsePhaseClarify(state);
2157
+ }
1326
2158
  /**
1327
2159
  * Phase 2 complete: Questions generated (or none)
1328
2160
  * If questions exist → checkpoint
1329
- * If no questions → move to generate phase with accumulated answers
2161
+ * If no questions → move to draft phase with accumulated answers
1330
2162
  */
1331
2163
  cmdClarifyDone(taskId, questions) {
1332
2164
  const state = this.loadState(taskId);
@@ -1344,14 +2176,15 @@ var Orchestrator = class {
1344
2176
  this.initSectionPlan(state);
1345
2177
  if (state.sectionPlan) {
1346
2178
  state.status = "phase_sections";
1347
- state.phase = "generate";
2179
+ state.phase = "draft";
1348
2180
  this.saveState(state);
1349
2181
  return this.responsePhaseGenerateSections(state);
1350
2182
  }
1351
- state.status = "phase_generate";
1352
- state.phase = "generate";
2183
+ state.status = "phase_execute";
2184
+ state.phase = "draft";
2185
+ state.verifyAttempts = 0;
1353
2186
  this.saveState(state);
1354
- return this.responsePhaseGenerate(state);
2187
+ return this.responsePhaseExecute(state);
1355
2188
  }
1356
2189
  /**
1357
2190
  * Human answered questions, loop back to clarify phase
@@ -1376,6 +2209,7 @@ var Orchestrator = class {
1376
2209
  }
1377
2210
  /**
1378
2211
  * Phase 3 complete: Document generated, move to approve checkpoint
2212
+ * @deprecated Use cmdExecuteDone instead for new workflow
1379
2213
  */
1380
2214
  cmdGenerateDone(taskId) {
1381
2215
  const state = this.loadState(taskId);
@@ -1383,7 +2217,7 @@ var Orchestrator = class {
1383
2217
  return this.responseError(`No workflow found: ${taskId}`, taskId);
1384
2218
  }
1385
2219
  const specPath = this.getSpecPath(taskId, state.currentStep);
1386
- if (!existsSync4(specPath)) {
2220
+ if (!existsSync5(specPath)) {
1387
2221
  return this.responseError(`Document not found: ${specPath}`, taskId, state.currentStep);
1388
2222
  }
1389
2223
  state.status = "approve_pending";
@@ -1392,209 +2226,79 @@ var Orchestrator = class {
1392
2226
  return this.responseCheckpointApprove(state);
1393
2227
  }
1394
2228
  /**
1395
- * @deprecated Use cmdContextDone, cmdClarifyDone, cmdGenerateDone instead
1396
- */
1397
- cmdDone(taskId) {
1398
- const state = this.loadState(taskId);
1399
- if (!state) {
1400
- return this.responseError(`No workflow found: ${taskId}`, taskId);
1401
- }
1402
- const specPath = this.getSpecPath(taskId, state.currentStep);
1403
- if (!existsSync4(specPath)) {
1404
- return this.responseError(`Spec not found: ${specPath}`, taskId, state.currentStep);
1405
- }
1406
- const questions = this.checkUnresolvedQuestions(specPath);
1407
- if (questions.length > 0) {
1408
- state.questions = questions;
1409
- state.status = "clarify_pending";
1410
- state.phase = "clarify";
1411
- this.saveState(state);
1412
- return this.responseCheckpointClarify(state);
1413
- }
1414
- state.status = "approve_pending";
1415
- state.phase = "review";
1416
- this.saveState(state);
1417
- return this.responseCheckpointApprove(state);
1418
- }
1419
- /**
1420
- * Approve current step and move to next
1421
- */
1422
- cmdApprove(taskId) {
1423
- const state = this.loadState(taskId);
1424
- if (!state) {
1425
- return this.responseError(`No workflow found: ${taskId}`, taskId);
1426
- }
1427
- const steps = this.getSteps();
1428
- const specPath = this.getSpecPath(taskId, state.currentStep);
1429
- if (existsSync4(specPath)) {
1430
- const content = readFileSync4(specPath, "utf-8");
1431
- const { content: body, data } = matter2(content);
1432
- data.status = "approved";
1433
- data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1434
- writeFileSync3(specPath, matter2.stringify(body, data));
1435
- }
1436
- if (state.stepIndex < state.totalSteps) {
1437
- state.currentStep = steps[state.stepIndex];
1438
- state.stepIndex += 1;
1439
- state.status = "phase_context";
1440
- state.phase = "context";
1441
- state.context = void 0;
1442
- state.questions = void 0;
1443
- state.answers = void 0;
1444
- state.qaHistory = void 0;
1445
- state.revisionFeedback = void 0;
1446
- this.saveState(state);
1447
- return this.responsePhaseContext(state);
1448
- } else {
1449
- state.status = "completed";
1450
- this.saveState(state);
1451
- return this.responseComplete(state, "completed");
1452
- }
1453
- }
1454
- /**
1455
- * Request revision with feedback - goes back to generate phase
1456
- */
1457
- cmdRevise(taskId, feedback) {
1458
- const state = this.loadState(taskId);
1459
- if (!state) {
1460
- return this.responseError(`No workflow found: ${taskId}`, taskId);
1461
- }
1462
- state.status = "phase_generate";
1463
- state.phase = "generate";
1464
- state.revisionFeedback = feedback;
1465
- this.saveState(state);
1466
- return this.responsePhaseGenerate(state);
1467
- }
1468
- /**
1469
- * Reject and stop workflow
2229
+ * Phase 3 complete (New): Execution complete, move to verify phase
1470
2230
  */
1471
- cmdReject(taskId) {
2231
+ cmdExecuteDone(taskId) {
1472
2232
  const state = this.loadState(taskId);
1473
2233
  if (!state) {
1474
2234
  return this.responseError(`No workflow found: ${taskId}`, taskId);
1475
2235
  }
1476
2236
  const specPath = this.getSpecPath(taskId, state.currentStep);
1477
- if (existsSync4(specPath)) {
1478
- const content = readFileSync4(specPath, "utf-8");
1479
- const { content: body, data } = matter2(content);
1480
- data.status = "rejected";
1481
- data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1482
- writeFileSync3(specPath, matter2.stringify(body, data));
1483
- }
1484
- state.status = "rejected";
1485
- this.saveState(state);
1486
- return this.responseComplete(state, "rejected");
1487
- }
1488
- /**
1489
- * Stop workflow (can resume later)
1490
- */
1491
- cmdStop(taskId) {
1492
- const state = this.loadState(taskId);
1493
- if (!state) {
1494
- return this.responseError(`No workflow found: ${taskId}`, taskId);
2237
+ if (!existsSync5(specPath)) {
2238
+ return this.responseError(`Document not found: ${specPath}`, taskId, state.currentStep);
1495
2239
  }
1496
- state.status = "stopped";
2240
+ state.status = "phase_verify";
2241
+ state.phase = "verify";
2242
+ state.verifyAttempts = (state.verifyAttempts || 0) + 1;
1497
2243
  this.saveState(state);
1498
- return this.responseComplete(state, "stopped");
2244
+ return this.responsePhaseVerify(state);
1499
2245
  }
1500
- // ===========================================================================
1501
- // Section-based Workflow Commands
1502
- // ===========================================================================
1503
2246
  /**
1504
- * Initialize section-based generation for current step
1505
- * Called internally when template has sections
2247
+ * @deprecated Use cmdExecuteDone instead
1506
2248
  */
1507
- initSectionPlan(state) {
1508
- const templatePath = this.getStepTemplatePath(state.currentStep);
1509
- if (!existsSync4(templatePath)) {
1510
- return;
1511
- }
1512
- const template = readFileSync4(templatePath, "utf-8");
1513
- const instructionPath = this.getStepInstructionPath(state.currentStep);
1514
- const instructionSummary = existsSync4(instructionPath) ? readFileSync4(instructionPath, "utf-8").slice(0, 500) : "";
1515
- const plan = parseTemplateToTree(
1516
- template,
1517
- state.currentStep,
1518
- state.description,
1519
- `sections/${state.currentStep}`,
1520
- instructionSummary
1521
- );
1522
- if (plan.leaves.length > 1) {
1523
- state.sectionPlan = plan;
1524
- state.sectionStatuses = plan.leaves.map((leaf) => ({
1525
- id: leaf.id,
1526
- status: "pending",
1527
- outputPath: leaf.outputPath
1528
- }));
1529
- state.consolidateProgress = {
1530
- currentLevel: 0,
1531
- completedLevels: [],
1532
- totalLevels: plan.consolidateLevels.length
1533
- };
1534
- }
2249
+ cmdDraftDone(taskId) {
2250
+ return this.cmdExecuteDone(taskId);
1535
2251
  }
1536
2252
  /**
1537
- * All sections completed, move to consolidation
2253
+ * Phase 4 complete (New): Verification done
2254
+ * If passed → approve_pending
2255
+ * If failed → phase_execute (auto-fix, max 3 attempts)
2256
+ * If max attempts reached → approve_pending with warning
1538
2257
  */
1539
- cmdSectionsDone(taskId) {
2258
+ cmdVerifyDone(taskId, verifyOutput) {
1540
2259
  const state = this.loadState(taskId);
1541
2260
  if (!state) {
1542
2261
  return this.responseError(`No workflow found: ${taskId}`, taskId);
1543
2262
  }
1544
- if (!state.sectionPlan || !state.consolidateProgress) {
1545
- return this.responseError("No section plan found", taskId, state.currentStep);
1546
- }
1547
- if (state.sectionStatuses) {
1548
- state.sectionStatuses = state.sectionStatuses.map((s) => ({
1549
- ...s,
1550
- status: "completed"
1551
- }));
2263
+ state.verifyOutput = verifyOutput;
2264
+ if (verifyOutput.passed) {
2265
+ state.status = "approve_pending";
2266
+ state.phase = "review";
2267
+ this.saveState(state);
2268
+ return this.responseCheckpointApprove(state);
1552
2269
  }
1553
- if (state.consolidateProgress.totalLevels > 0) {
1554
- state.status = "phase_consolidate";
1555
- state.consolidateProgress.currentLevel = 0;
2270
+ const attempts = state.verifyAttempts || 1;
2271
+ if (attempts >= 3) {
2272
+ state.status = "approve_pending";
2273
+ state.phase = "review";
1556
2274
  this.saveState(state);
1557
- const firstLevel = state.sectionPlan.consolidateLevels[0];
1558
- const validation = this.validateConsolidateReady(state, firstLevel);
1559
- if (!validation.valid) {
1560
- return this.responseError(
1561
- validation.error || "Validation failed",
1562
- taskId,
1563
- state.currentStep
1564
- );
1565
- }
1566
- return this.responsePhaseConsolidate(state, firstLevel);
2275
+ const response = this.responseCheckpointApprove(state);
2276
+ return response;
1567
2277
  }
1568
- state.status = "approve_pending";
1569
- state.phase = "review";
2278
+ state.status = "phase_execute";
2279
+ state.phase = "draft";
1570
2280
  this.saveState(state);
1571
- return this.responseCheckpointApprove(state);
2281
+ return this.responsePhaseExecute(state);
1572
2282
  }
1573
2283
  /**
1574
- * Consolidation level completed, move to next level or approve
2284
+ * @deprecated Use cmdExploreDone, cmdClarifyDone, cmdExecuteDone, cmdVerifyDone instead
1575
2285
  */
1576
- cmdConsolidateLevelDone(taskId, level) {
2286
+ cmdDone(taskId) {
1577
2287
  const state = this.loadState(taskId);
1578
2288
  if (!state) {
1579
2289
  return this.responseError(`No workflow found: ${taskId}`, taskId);
1580
2290
  }
1581
- if (!state.sectionPlan || !state.consolidateProgress) {
1582
- return this.responseError("No section plan found", taskId, state.currentStep);
2291
+ const specPath = this.getSpecPath(taskId, state.currentStep);
2292
+ if (!existsSync5(specPath)) {
2293
+ return this.responseError(`Spec not found: ${specPath}`, taskId, state.currentStep);
1583
2294
  }
1584
- state.consolidateProgress.completedLevels.push(level);
1585
- state.consolidateProgress.currentLevel++;
1586
- if (state.consolidateProgress.currentLevel < state.consolidateProgress.totalLevels) {
2295
+ const questions = this.checkUnresolvedQuestions(specPath);
2296
+ if (questions.length > 0) {
2297
+ state.questions = questions;
2298
+ state.status = "clarify_pending";
2299
+ state.phase = "clarify";
1587
2300
  this.saveState(state);
1588
- const nextLevel = state.sectionPlan.consolidateLevels[state.consolidateProgress.currentLevel];
1589
- const validation = this.validateConsolidateReady(state, nextLevel);
1590
- if (!validation.valid) {
1591
- return this.responseError(
1592
- validation.error || "Validation failed",
1593
- taskId,
1594
- state.currentStep
1595
- );
1596
- }
1597
- return this.responsePhaseConsolidate(state, nextLevel);
2301
+ return this.responseCheckpointClarify(state);
1598
2302
  }
1599
2303
  state.status = "approve_pending";
1600
2304
  state.phase = "review";
@@ -1602,394 +2306,261 @@ var Orchestrator = class {
1602
2306
  return this.responseCheckpointApprove(state);
1603
2307
  }
1604
2308
  /**
1605
- * Get current workflow status
2309
+ * Approve current step and move to next
1606
2310
  */
1607
- cmdStatus(taskId) {
2311
+ cmdApprove(taskId) {
1608
2312
  const state = this.loadState(taskId);
1609
2313
  if (!state) {
1610
2314
  return this.responseError(`No workflow found: ${taskId}`, taskId);
1611
2315
  }
1612
- switch (state.status) {
1613
- case "phase_context":
1614
- return this.responsePhaseContext(state);
1615
- case "phase_clarify":
1616
- return this.responsePhaseClarify(state);
1617
- case "clarify_pending":
1618
- return this.responseCheckpointClarify(state);
1619
- case "phase_generate":
1620
- return this.responsePhaseGenerate(state);
1621
- case "phase_sections":
1622
- return this.responsePhaseGenerateSections(state);
1623
- case "phase_consolidate":
1624
- if (state.sectionPlan && state.consolidateProgress) {
1625
- const level = state.sectionPlan.consolidateLevels[state.consolidateProgress.currentLevel];
1626
- return this.responsePhaseConsolidate(state, level);
1627
- }
1628
- return this.responseError("Invalid consolidate state", taskId);
1629
- case "approve_pending":
1630
- return this.responseCheckpointApprove(state);
1631
- case "completed":
1632
- case "stopped":
1633
- case "rejected":
1634
- return this.responseComplete(state, state.status);
1635
- default:
1636
- return this.responseError(`Unknown status: ${state.status}`, taskId);
1637
- }
1638
- }
1639
- };
1640
-
1641
- // src/core/step-executor.ts
1642
- import { existsSync as existsSync6, writeFileSync as writeFileSync4 } from "fs";
1643
- import matter3 from "gray-matter";
1644
-
1645
- // src/core/prompt-builder.ts
1646
- import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
1647
- import { join as join5 } from "path";
1648
- function buildContextPrompt(params) {
1649
- const cwd = params.cwd || process.cwd();
1650
- const stepsDir = getStepsDir(cwd);
1651
- const isFirstStep = params.stepIndex === 1;
1652
- const instructionPath = join5(stepsDir, params.step, "instruction.md");
1653
- const instruction = existsSync5(instructionPath) ? readFileSync5(instructionPath, "utf-8") : "";
1654
- const parts = [];
1655
- parts.push("# Context Gathering Phase");
1656
- parts.push("");
1657
- parts.push("Your task is to gather context before generating a document.");
1658
- parts.push("Do NOT generate the document yet - only gather information.");
1659
- parts.push("");
1660
- parts.push("## Task Information");
1661
- parts.push("");
1662
- parts.push(`- **Task ID**: ${params.taskId}`);
1663
- parts.push(`- **Current Step**: ${params.step} (${params.stepIndex}/${params.totalSteps})`);
1664
- parts.push("");
1665
- if (isFirstStep) {
1666
- parts.push("## User Request");
1667
- parts.push("");
1668
- parts.push(`> ${params.description}`);
1669
- parts.push("");
1670
- } else if (params.previousOutput) {
1671
- parts.push("## Previous Step Output");
1672
- parts.push("");
1673
- if (existsSync5(params.previousOutput)) {
1674
- parts.push(readFileSync5(params.previousOutput, "utf-8"));
1675
- }
1676
- parts.push("");
1677
- }
1678
- if (instruction) {
1679
- parts.push("## Step Instruction (Preview)");
1680
- parts.push("");
1681
- parts.push("The next phase will use this instruction to generate a document:");
1682
- parts.push("");
1683
- parts.push("```");
1684
- parts.push(instruction.slice(0, 500) + (instruction.length > 500 ? "..." : ""));
1685
- parts.push("```");
1686
- parts.push("");
1687
- }
1688
- parts.push("## Your Task");
1689
- parts.push("");
1690
- parts.push("1. **Analyze** the request/input to understand what is being asked");
1691
- parts.push("2. **Search** the codebase for relevant files, patterns, conventions");
1692
- parts.push("3. **Identify** key constraints, dependencies, and considerations");
1693
- parts.push("");
1694
- parts.push("## Output Format");
1695
- parts.push("");
1696
- parts.push("Output a JSON object with this structure:");
1697
- parts.push("");
1698
- parts.push("```json");
1699
- parts.push("{");
1700
- parts.push(' "summary": "Brief summary of what you understood and found",');
1701
- parts.push(' "relevantFiles": ["path/to/file1.ts", "path/to/file2.ts"],');
1702
- parts.push(' "keyFindings": [');
1703
- parts.push(' "Finding 1: description",');
1704
- parts.push(' "Finding 2: description"');
1705
- parts.push(" ]");
1706
- parts.push("}");
1707
- parts.push("```");
1708
- parts.push("");
1709
- parts.push("**Important:** Output ONLY the JSON, no other text.");
1710
- parts.push("");
1711
- return parts.join("\n");
1712
- }
1713
- function buildClarifyPrompt(params) {
1714
- const cwd = params.cwd || process.cwd();
1715
- const stepsDir = getStepsDir(cwd);
1716
- const instructionPath = join5(stepsDir, params.step, "instruction.md");
1717
- const instruction = existsSync5(instructionPath) ? readFileSync5(instructionPath, "utf-8") : "";
1718
- const parts = [];
1719
- parts.push("# Clarify Phase");
1720
- parts.push("");
1721
- parts.push("Your task is to identify any questions that need user input before generating the document.");
1722
- parts.push("Do NOT generate the document yet - only generate questions if needed.");
1723
- parts.push("");
1724
- parts.push("## Task Information");
1725
- parts.push("");
1726
- parts.push(`- **Task ID**: ${params.taskId}`);
1727
- parts.push(`- **Current Step**: ${params.step}`);
1728
- parts.push(`- **Description**: ${params.description}`);
1729
- parts.push("");
1730
- parts.push("## Gathered Context");
1731
- parts.push("");
1732
- parts.push(params.gatheredContext);
1733
- parts.push("");
1734
- if (instruction) {
1735
- parts.push("## Step Instruction");
1736
- parts.push("");
1737
- parts.push(instruction);
1738
- parts.push("");
1739
- }
1740
- if (params.previousQA && params.previousQA.length > 0) {
1741
- parts.push("## Previous Questions & Answers");
1742
- parts.push("");
1743
- parts.push("The following questions have already been asked and answered:");
1744
- parts.push("");
1745
- for (const entry of params.previousQA) {
1746
- parts.push(`**Q: ${entry.question.question}**`);
1747
- if (entry.question.context) {
1748
- parts.push(`Context: ${entry.question.context}`);
1749
- }
1750
- parts.push(`A: ${entry.answer.answer}`);
1751
- parts.push("");
2316
+ const steps = this.getSteps();
2317
+ const specPath = this.getSpecPath(taskId, state.currentStep);
2318
+ if (existsSync5(specPath)) {
2319
+ const content = readFileSync5(specPath, "utf-8");
2320
+ const { content: body, data } = matter2(content);
2321
+ data.status = "approved";
2322
+ data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
2323
+ writeFileSync3(specPath, matter2.stringify(body, data));
1752
2324
  }
1753
- parts.push("Based on these answers, determine if there are still ambiguities that need clarification.");
1754
- parts.push("Do NOT repeat questions that have already been answered.");
1755
- parts.push("");
1756
- }
1757
- parts.push("## Consider These Questions");
1758
- parts.push("");
1759
- parts.push("1. Is the task description clear enough to proceed?");
1760
- parts.push("2. Are there multiple valid approaches that need user decision?");
1761
- parts.push("3. Are there ambiguities that could lead to wrong implementation?");
1762
- parts.push("4. Are there missing requirements or constraints?");
1763
- parts.push("");
1764
- parts.push("## Output Format");
1765
- parts.push("");
1766
- parts.push("Output a JSON object with questions array:");
1767
- parts.push("");
1768
- parts.push("```json");
1769
- parts.push("{");
1770
- parts.push(' "questions": [');
1771
- parts.push(" {");
1772
- parts.push(' "id": "q1",');
1773
- parts.push(' "question": "Your specific question?",');
1774
- parts.push(' "context": "Why this matters for the document",');
1775
- parts.push(' "options": ["Option A", "Option B"] // optional');
1776
- parts.push(" }");
1777
- parts.push(" ]");
1778
- parts.push("}");
1779
- parts.push("```");
1780
- parts.push("");
1781
- parts.push('If no questions are needed, return: `{"questions": []}`');
1782
- parts.push("");
1783
- parts.push("**Important:** Output ONLY the JSON, no other text.");
1784
- parts.push("");
1785
- return parts.join("\n");
1786
- }
1787
- function buildGeneratePrompt(params) {
1788
- const cwd = params.cwd || process.cwd();
1789
- const config = loadConfig(cwd);
1790
- const stepsDir = getStepsDir(cwd);
1791
- const outputsDir = getOutputsDir(cwd);
1792
- const isFirstStep = params.stepIndex === 1;
1793
- const prevStep = params.stepIndex > 1 ? config.steps[params.stepIndex - 2] : null;
1794
- const instructionPath = join5(stepsDir, params.step, "instruction.md");
1795
- const templatePath = join5(stepsDir, params.step, "template.md");
1796
- const outputPath = join5(outputsDir, params.taskId, `${params.step}.md`);
1797
- if (!existsSync5(instructionPath)) {
1798
- throw new Error(`Instruction not found: ${instructionPath}`);
1799
- }
1800
- const instruction = readFileSync5(instructionPath, "utf-8");
1801
- const template = existsSync5(templatePath) ? readFileSync5(templatePath, "utf-8") : null;
1802
- let previousSpec = null;
1803
- if (prevStep) {
1804
- const prevPath = join5(outputsDir, params.taskId, `${prevStep}.md`);
1805
- if (existsSync5(prevPath)) {
1806
- previousSpec = {
1807
- step: prevStep,
1808
- content: readFileSync5(prevPath, "utf-8")
1809
- };
2325
+ if (state.stepIndex < state.totalSteps) {
2326
+ state.currentStep = steps[state.stepIndex];
2327
+ state.stepIndex += 1;
2328
+ state.status = "phase_explore";
2329
+ state.phase = "explore";
2330
+ state.context = void 0;
2331
+ state.exploreOutput = void 0;
2332
+ state.questions = void 0;
2333
+ state.answers = void 0;
2334
+ state.qaHistory = void 0;
2335
+ state.verifyOutput = void 0;
2336
+ state.verifyAttempts = void 0;
2337
+ state.revisionFeedback = void 0;
2338
+ this.saveState(state);
2339
+ return this.responsePhaseExplore(state);
2340
+ } else {
2341
+ state.status = "completed";
2342
+ this.saveState(state);
2343
+ return this.responseComplete(state, "completed");
1810
2344
  }
1811
2345
  }
1812
- const parts = [];
1813
- parts.push("# Document Generation Phase");
1814
- parts.push("");
1815
- parts.push("Generate the document based on the gathered context and user answers.");
1816
- parts.push("");
1817
- parts.push("## Step Instruction");
1818
- parts.push("");
1819
- parts.push(instruction);
1820
- parts.push("");
1821
- if (template) {
1822
- parts.push("## Document Template");
1823
- parts.push("");
1824
- parts.push("**CRITICAL: You MUST follow this template structure completely.**");
1825
- parts.push("");
1826
- parts.push(template);
1827
- parts.push("");
1828
- }
1829
- parts.push("## Gathered Context");
1830
- parts.push("");
1831
- parts.push(params.gatheredContext);
1832
- parts.push("");
1833
- if (params.answers && params.answers.length > 0) {
1834
- parts.push("## User Answers");
1835
- parts.push("");
1836
- for (const answer of params.answers) {
1837
- parts.push(`- **${answer.questionId}**: ${answer.answer}`);
2346
+ /**
2347
+ * Request revision with feedback - goes back to draft phase
2348
+ */
2349
+ cmdRevise(taskId, feedback) {
2350
+ const state = this.loadState(taskId);
2351
+ if (!state) {
2352
+ return this.responseError(`No workflow found: ${taskId}`, taskId);
1838
2353
  }
1839
- parts.push("");
2354
+ state.status = "phase_execute";
2355
+ state.phase = "draft";
2356
+ state.revisionFeedback = feedback;
2357
+ state.verifyOutput = void 0;
2358
+ state.verifyAttempts = 0;
2359
+ this.saveState(state);
2360
+ return this.responsePhaseExecute(state);
1840
2361
  }
1841
- if (isFirstStep) {
1842
- parts.push("## User Request");
1843
- parts.push("");
1844
- parts.push(`> ${params.description}`);
1845
- parts.push("");
1846
- } else if (previousSpec) {
1847
- parts.push(`## Input: ${previousSpec.step}.md`);
1848
- parts.push("");
1849
- parts.push(previousSpec.content);
1850
- parts.push("");
2362
+ /**
2363
+ * Reject and stop workflow
2364
+ */
2365
+ cmdReject(taskId) {
2366
+ const state = this.loadState(taskId);
2367
+ if (!state) {
2368
+ return this.responseError(`No workflow found: ${taskId}`, taskId);
2369
+ }
2370
+ const specPath = this.getSpecPath(taskId, state.currentStep);
2371
+ if (existsSync5(specPath)) {
2372
+ const content = readFileSync5(specPath, "utf-8");
2373
+ const { content: body, data } = matter2(content);
2374
+ data.status = "rejected";
2375
+ data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
2376
+ writeFileSync3(specPath, matter2.stringify(body, data));
2377
+ }
2378
+ state.status = "rejected";
2379
+ this.saveState(state);
2380
+ return this.responseComplete(state, "rejected");
1851
2381
  }
1852
- parts.push("## Task Context");
1853
- parts.push("");
1854
- parts.push(`- **Task ID**: ${params.taskId}`);
1855
- parts.push(`- **Current Step**: ${params.step} (${params.stepIndex}/${params.totalSteps})`);
1856
- parts.push("");
1857
- if (params.revisionFeedback) {
1858
- parts.push("## Revision Feedback");
1859
- parts.push("");
1860
- parts.push("Previous version was not approved. Please revise based on this feedback:");
1861
- parts.push("");
1862
- parts.push(`> ${params.revisionFeedback}`);
1863
- parts.push("");
2382
+ /**
2383
+ * Stop workflow (can resume later)
2384
+ */
2385
+ cmdStop(taskId) {
2386
+ const state = this.loadState(taskId);
2387
+ if (!state) {
2388
+ return this.responseError(`No workflow found: ${taskId}`, taskId);
2389
+ }
2390
+ state.status = "stopped";
2391
+ this.saveState(state);
2392
+ return this.responseComplete(state, "stopped");
1864
2393
  }
1865
- parts.push("## Output Instructions");
1866
- parts.push("");
1867
- parts.push(`Generate the document and save to: \`${outputPath}\``);
1868
- parts.push("");
1869
- parts.push("**Required frontmatter:**");
1870
- parts.push("```yaml");
1871
- parts.push("---");
1872
- parts.push(`id: ${params.taskId}`);
1873
- parts.push(`step: ${params.step}`);
1874
- parts.push("status: pending_approval");
1875
- parts.push("---");
1876
- parts.push("```");
1877
- parts.push("");
1878
- return {
1879
- prompt: parts.join("\n"),
1880
- outputPath
1881
- };
1882
- }
1883
- function buildSectionPrompt(params) {
1884
- const { section, sharedContext, gatheredContext, answers } = params;
1885
- const parts = [];
1886
- parts.push(`# Section: ${section.title}`);
1887
- parts.push("");
1888
- parts.push("## Document Context");
1889
- parts.push("");
1890
- parts.push(`**Goal:** ${sharedContext.documentGoal}`);
1891
- parts.push(`**Step:** ${sharedContext.stepName}`);
1892
- parts.push(`**Total Sections:** ${sharedContext.totalSections}`);
1893
- parts.push("");
1894
- parts.push("## Document Structure");
1895
- parts.push("");
1896
- parts.push("```");
1897
- parts.push(sharedContext.treeOverview);
1898
- parts.push("```");
1899
- parts.push("");
1900
- parts.push("## Your Position");
1901
- parts.push("");
1902
- parts.push(`- **Path:** ${section.position.path.join(" > ")}`);
1903
- parts.push(`- **Siblings:** ${section.position.siblings.join(", ") || "None"}`);
1904
- parts.push(`- **Parent:** ${section.position.parent || "Root"}`);
1905
- parts.push("");
1906
- if (gatheredContext) {
1907
- parts.push("## Gathered Context");
1908
- parts.push("");
1909
- parts.push(gatheredContext);
1910
- parts.push("");
2394
+ // ===========================================================================
2395
+ // Section-based Workflow Commands
2396
+ // ===========================================================================
2397
+ /**
2398
+ * Initialize section-based generation for current step
2399
+ * Called internally when template has sections
2400
+ */
2401
+ initSectionPlan(state) {
2402
+ const templatePath = this.getStepTemplatePath(state.currentStep);
2403
+ if (!existsSync5(templatePath)) {
2404
+ return;
2405
+ }
2406
+ const template = readFileSync5(templatePath, "utf-8");
2407
+ const instructionPath = this.getStepInstructionPath(state.currentStep);
2408
+ const instructionSummary = existsSync5(instructionPath) ? readFileSync5(instructionPath, "utf-8").slice(0, 500) : "";
2409
+ const plan = parseTemplateToTree(
2410
+ template,
2411
+ state.currentStep,
2412
+ state.description,
2413
+ `sections/${state.currentStep}`,
2414
+ instructionSummary
2415
+ );
2416
+ if (plan.leaves.length > 1) {
2417
+ state.sectionPlan = plan;
2418
+ state.sectionStatuses = plan.leaves.map((leaf) => ({
2419
+ id: leaf.id,
2420
+ status: "pending",
2421
+ outputPath: leaf.outputPath
2422
+ }));
2423
+ state.consolidateProgress = {
2424
+ currentLevel: 0,
2425
+ completedLevels: [],
2426
+ totalLevels: plan.consolidateLevels.length
2427
+ };
2428
+ }
1911
2429
  }
1912
- if (answers && answers.length > 0) {
1913
- parts.push("## User Answers");
1914
- parts.push("");
1915
- for (const answer of answers) {
1916
- parts.push(`- **${answer.questionId}**: ${answer.answer}`);
2430
+ /**
2431
+ * All sections completed, move to consolidation
2432
+ */
2433
+ cmdSectionsDone(taskId) {
2434
+ const state = this.loadState(taskId);
2435
+ if (!state) {
2436
+ return this.responseError(`No workflow found: ${taskId}`, taskId);
1917
2437
  }
1918
- parts.push("");
2438
+ if (!state.sectionPlan || !state.consolidateProgress) {
2439
+ return this.responseError("No section plan found", taskId, state.currentStep);
2440
+ }
2441
+ if (state.sectionStatuses) {
2442
+ state.sectionStatuses = state.sectionStatuses.map((s) => ({
2443
+ ...s,
2444
+ status: "completed"
2445
+ }));
2446
+ }
2447
+ if (state.consolidateProgress.totalLevels > 0) {
2448
+ state.status = "phase_consolidate";
2449
+ state.consolidateProgress.currentLevel = 0;
2450
+ this.saveState(state);
2451
+ const firstLevel = state.sectionPlan.consolidateLevels[0];
2452
+ const validation = this.validateConsolidateReady(state, firstLevel);
2453
+ if (!validation.valid) {
2454
+ return this.responseError(
2455
+ validation.error || "Validation failed",
2456
+ taskId,
2457
+ state.currentStep
2458
+ );
2459
+ }
2460
+ return this.responsePhaseConsolidate(state, firstLevel);
2461
+ }
2462
+ state.status = "approve_pending";
2463
+ state.phase = "review";
2464
+ this.saveState(state);
2465
+ return this.responseCheckpointApprove(state);
1919
2466
  }
1920
- if (section.templateContent) {
1921
- parts.push("## Template Guide");
1922
- parts.push("");
1923
- parts.push(section.templateContent);
1924
- parts.push("");
2467
+ /**
2468
+ * Consolidation level completed, move to next level or approve
2469
+ */
2470
+ cmdConsolidateLevelDone(taskId, level) {
2471
+ const state = this.loadState(taskId);
2472
+ if (!state) {
2473
+ return this.responseError(`No workflow found: ${taskId}`, taskId);
2474
+ }
2475
+ if (!state.sectionPlan || !state.consolidateProgress) {
2476
+ return this.responseError("No section plan found", taskId, state.currentStep);
2477
+ }
2478
+ state.consolidateProgress.completedLevels.push(level);
2479
+ state.consolidateProgress.currentLevel++;
2480
+ if (state.consolidateProgress.currentLevel < state.consolidateProgress.totalLevels) {
2481
+ this.saveState(state);
2482
+ const nextLevel = state.sectionPlan.consolidateLevels[state.consolidateProgress.currentLevel];
2483
+ const validation = this.validateConsolidateReady(state, nextLevel);
2484
+ if (!validation.valid) {
2485
+ return this.responseError(
2486
+ validation.error || "Validation failed",
2487
+ taskId,
2488
+ state.currentStep
2489
+ );
2490
+ }
2491
+ return this.responsePhaseConsolidate(state, nextLevel);
2492
+ }
2493
+ state.status = "approve_pending";
2494
+ state.phase = "review";
2495
+ this.saveState(state);
2496
+ return this.responseCheckpointApprove(state);
1925
2497
  }
1926
- parts.push("## Your Task");
1927
- parts.push("");
1928
- parts.push(`Write the "${section.title.replace(/^#+\\s*/, "")}" section.`);
1929
- parts.push("Consider how it relates to sibling sections and contributes to the parent section.");
1930
- parts.push("");
1931
- parts.push("## Output");
1932
- parts.push("");
1933
- parts.push(`Save to: \`${section.outputPath}\``);
1934
- parts.push("");
1935
- parts.push("Write ONLY the content for this section (including its header).");
1936
- parts.push("Do NOT include content from other sections.");
1937
- parts.push("");
1938
- return {
1939
- prompt: parts.join("\n"),
1940
- outputPath: section.outputPath
1941
- };
1942
- }
1943
- function buildConsolidatePrompt(params) {
1944
- const { group, childContents, sharedContext, parentTitle } = params;
1945
- const parts = [];
1946
- parts.push("# Consolidate Sections");
1947
- parts.push("");
1948
- parts.push("## Document Context");
1949
- parts.push("");
1950
- parts.push(`**Goal:** ${sharedContext.documentGoal}`);
1951
- parts.push(`**Step:** ${sharedContext.stepName}`);
1952
- parts.push("");
1953
- parts.push("## Document Structure");
1954
- parts.push("");
1955
- parts.push("```");
1956
- parts.push(sharedContext.treeOverview);
1957
- parts.push("```");
1958
- parts.push("");
1959
- parts.push("## Your Task");
1960
- parts.push("");
1961
- parts.push(`Consolidate the following child sections into the parent section "${parentTitle || group.parentId}".`);
1962
- parts.push("");
1963
- parts.push("## Child Sections to Consolidate");
1964
- parts.push("");
1965
- for (const child of childContents) {
1966
- parts.push(`### Child: ${child.id}`);
1967
- parts.push("");
1968
- parts.push(child.content);
1969
- parts.push("");
1970
- parts.push("---");
1971
- parts.push("");
2498
+ /**
2499
+ * Get current workflow status
2500
+ */
2501
+ cmdStatus(taskId) {
2502
+ const state = this.loadState(taskId);
2503
+ if (!state) {
2504
+ return this.responseError(`No workflow found: ${taskId}`, taskId);
2505
+ }
2506
+ const migratedStatus = this.migrateStatus(state.status);
2507
+ if (migratedStatus !== state.status) {
2508
+ state.status = migratedStatus;
2509
+ this.saveState(state);
2510
+ }
2511
+ switch (state.status) {
2512
+ // Legacy (backward compatibility)
2513
+ case "phase_context":
2514
+ return this.responsePhaseContext(state);
2515
+ case "phase_generate":
2516
+ return this.responsePhaseGenerate(state);
2517
+ case "phase_draft":
2518
+ return this.responsePhaseExecute(state);
2519
+ // New 5-phase workflow
2520
+ case "phase_explore":
2521
+ return this.responsePhaseExplore(state);
2522
+ case "phase_clarify":
2523
+ return this.responsePhaseClarify(state);
2524
+ case "clarify_pending":
2525
+ return this.responseCheckpointClarify(state);
2526
+ case "phase_execute":
2527
+ return this.responsePhaseExecute(state);
2528
+ case "phase_verify":
2529
+ return this.responsePhaseVerify(state);
2530
+ // Section-based workflow
2531
+ case "phase_sections":
2532
+ return this.responsePhaseGenerateSections(state);
2533
+ case "phase_consolidate":
2534
+ if (state.sectionPlan && state.consolidateProgress) {
2535
+ const level = state.sectionPlan.consolidateLevels[state.consolidateProgress.currentLevel];
2536
+ return this.responsePhaseConsolidate(state, level);
2537
+ }
2538
+ return this.responseError("Invalid consolidate state", taskId);
2539
+ // Checkpoints and completion
2540
+ case "approve_pending":
2541
+ return this.responseCheckpointApprove(state);
2542
+ case "completed":
2543
+ case "stopped":
2544
+ case "rejected":
2545
+ return this.responseComplete(state, state.status);
2546
+ default:
2547
+ return this.responseError(`Unknown status: ${state.status}`, taskId);
2548
+ }
1972
2549
  }
1973
- parts.push("## Output Instructions");
1974
- parts.push("");
1975
- parts.push(`Save consolidated content to: \`${group.outputPath}\``);
1976
- parts.push("");
1977
- parts.push("**Guidelines:**");
1978
- parts.push("- Combine child sections into a coherent parent section");
1979
- parts.push("- Maintain the hierarchy (parent header, then children)");
1980
- parts.push("- Ensure smooth transitions between sections");
1981
- parts.push("- Preserve all content from child sections");
1982
- parts.push("");
1983
- return {
1984
- prompt: parts.join("\n"),
1985
- outputPath: group.outputPath
1986
- };
1987
- }
2550
+ /**
2551
+ * Migrate legacy workflow status to new status
2552
+ * This allows existing workflows to continue working
2553
+ */
2554
+ migrateStatus(status) {
2555
+ return status;
2556
+ }
2557
+ };
1988
2558
 
1989
2559
  // src/core/step-executor.ts
1990
- import { readFileSync as readFileSync6, existsSync as fsExistsSync, mkdirSync as mkdirSync4 } from "fs";
1991
- import { dirname as dirname3 } from "path";
1992
- import { join as join6 } from "path";
2560
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
2561
+ import { dirname as dirname3, join as join6 } from "path";
2562
+ import matter3 from "gray-matter";
2563
+ var fsExistsSync = existsSync6;
1993
2564
  var StepExecutor = class {
1994
2565
  adapter;
1995
2566
  config;
@@ -2005,6 +2576,7 @@ var StepExecutor = class {
2005
2576
  /**
2006
2577
  * Execute context phase - AI gathers context
2007
2578
  * Returns gathered context as string
2579
+ * @deprecated Use executeExplorePhase instead
2008
2580
  */
2009
2581
  async executeContextPhase(step, context) {
2010
2582
  this.adapter.io.notify(`Phase 1/4: Gathering context for ${step}`, "info");
@@ -2030,6 +2602,39 @@ var StepExecutor = class {
2030
2602
  };
2031
2603
  }
2032
2604
  // ==========================================================================
2605
+ // Phase 1 (New): Explore - Deep Codebase Analysis
2606
+ // ==========================================================================
2607
+ /**
2608
+ * Execute explore phase - AI deeply analyzes codebase
2609
+ * Returns detailed exploration output with patterns, constraints, etc.
2610
+ */
2611
+ async executeExplorePhase(step, context) {
2612
+ this.adapter.io.notify(`Phase 1/5: Exploring codebase for ${step}`, "info");
2613
+ const params = {
2614
+ taskId: context.taskId,
2615
+ step,
2616
+ description: context.description,
2617
+ stepIndex: context.stepIndex,
2618
+ totalSteps: context.totalSteps,
2619
+ previousOutput: context.previousOutput,
2620
+ cwd: this.cwd
2621
+ };
2622
+ const prompt = buildExplorePrompt(params);
2623
+ const response = await this.adapter.ai.execute({
2624
+ prompt,
2625
+ outputPath: ""
2626
+ // No file output needed
2627
+ });
2628
+ const exploreOutput = this.parseExploreOutput(response || "");
2629
+ this.adapter.io.notify(`Found ${exploreOutput.relevantFiles.length} relevant files, ${exploreOutput.patterns.length} patterns`, "info");
2630
+ return {
2631
+ phase: "explore",
2632
+ exploreOutput,
2633
+ context: JSON.stringify(exploreOutput)
2634
+ // Also set legacy context
2635
+ };
2636
+ }
2637
+ // ==========================================================================
2033
2638
  // Phase 2: Clarify (Question Generation)
2034
2639
  // ==========================================================================
2035
2640
  /**
@@ -2082,6 +2687,7 @@ var StepExecutor = class {
2082
2687
  // ==========================================================================
2083
2688
  /**
2084
2689
  * Execute generate phase - AI creates document
2690
+ * @deprecated Use executeDraftPhase instead
2085
2691
  */
2086
2692
  async executeGeneratePhase(step, context) {
2087
2693
  this.adapter.io.notify(`Phase 3/4: Generating document for ${step}`, "info");
@@ -2108,6 +2714,94 @@ var StepExecutor = class {
2108
2714
  return { phase: "generate" };
2109
2715
  }
2110
2716
  // ==========================================================================
2717
+ // Phase 3 (New): Execute - Document/Code Generation with Explore Output
2718
+ // ==========================================================================
2719
+ /**
2720
+ * Execute the execute phase - AI creates document/code using explore output
2721
+ */
2722
+ async executeExecutePhase(step, context) {
2723
+ const attemptInfo = context.verifyAttempts && context.verifyAttempts > 1 ? ` (attempt ${context.verifyAttempts}/3)` : "";
2724
+ this.adapter.io.notify(`Phase 3/5: Executing for ${step}${attemptInfo}`, "info");
2725
+ if (!context.exploreOutput && !context.gatheredContext) {
2726
+ throw new Error("Explore phase must be completed before draft phase");
2727
+ }
2728
+ const exploreOutput = context.exploreOutput || {
2729
+ summary: context.gatheredContext || "",
2730
+ relevantFiles: [],
2731
+ patterns: [],
2732
+ constraints: [],
2733
+ dependencies: []
2734
+ };
2735
+ const params = {
2736
+ taskId: context.taskId,
2737
+ step,
2738
+ description: context.description,
2739
+ stepIndex: context.stepIndex,
2740
+ totalSteps: context.totalSteps,
2741
+ exploreOutput,
2742
+ answers: context.answers,
2743
+ revisionFeedback: context.revisionFeedback,
2744
+ verifyFeedback: context.verifyFeedback,
2745
+ cwd: this.cwd
2746
+ };
2747
+ const { prompt, outputPath } = buildExecutePrompt(params);
2748
+ await this.adapter.ai.execute({ prompt, outputPath });
2749
+ if (!existsSync6(outputPath)) {
2750
+ throw new Error(`AI did not create document at ${outputPath}`);
2751
+ }
2752
+ this.adapter.io.notify(`Document created: ${outputPath}`, "success");
2753
+ return { phase: "execute" };
2754
+ }
2755
+ /**
2756
+ * @deprecated Use executeExecutePhase instead
2757
+ */
2758
+ async executeDraftPhase(step, context) {
2759
+ return this.executeExecutePhase(step, context);
2760
+ }
2761
+ // ==========================================================================
2762
+ // Phase 4 (New): Verify - Self-Validation
2763
+ // ==========================================================================
2764
+ /**
2765
+ * Execute verify phase - AI validates the generated document
2766
+ */
2767
+ async executeVerifyPhase(step, context) {
2768
+ const attempts = context.verifyAttempts || 1;
2769
+ this.adapter.io.notify(`Phase 4/5: Verifying document for ${step} (attempt ${attempts}/3)`, "info");
2770
+ const outputsDir = getOutputsDir(this.cwd);
2771
+ const documentPath = join6(outputsDir, context.taskId, `${step}.md`);
2772
+ if (!existsSync6(documentPath)) {
2773
+ throw new Error(`Document not found: ${documentPath}`);
2774
+ }
2775
+ const params = {
2776
+ taskId: context.taskId,
2777
+ step,
2778
+ description: context.description,
2779
+ stepIndex: context.stepIndex,
2780
+ totalSteps: context.totalSteps,
2781
+ documentPath,
2782
+ verifyAttempts: attempts,
2783
+ cwd: this.cwd
2784
+ };
2785
+ const prompt = buildVerifyPrompt(params);
2786
+ const response = await this.adapter.ai.execute({
2787
+ prompt,
2788
+ outputPath: ""
2789
+ // No file output needed
2790
+ });
2791
+ const verifyOutput = this.parseVerifyOutput(response || "");
2792
+ if (verifyOutput.passed) {
2793
+ this.adapter.io.notify(`Verification passed! Scores: ${JSON.stringify(verifyOutput.score)}`, "success");
2794
+ } else {
2795
+ const errorCount = verifyOutput.issues.filter((i) => i.severity === "error").length;
2796
+ const warningCount = verifyOutput.issues.filter((i) => i.severity === "warning").length;
2797
+ this.adapter.io.notify(`Verification failed: ${errorCount} errors, ${warningCount} warnings`, "warning");
2798
+ }
2799
+ return {
2800
+ phase: "verify",
2801
+ verifyOutput
2802
+ };
2803
+ }
2804
+ // ==========================================================================
2111
2805
  // Phase 3 (Section Mode): Parallel Section Generation
2112
2806
  // ==========================================================================
2113
2807
  /**
@@ -2379,6 +3073,75 @@ var StepExecutor = class {
2379
3073
  }
2380
3074
  return { questions: [] };
2381
3075
  }
3076
+ /**
3077
+ * Parse explore phase output (JSON)
3078
+ */
3079
+ parseExploreOutput(response) {
3080
+ try {
3081
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
3082
+ if (jsonMatch) {
3083
+ const parsed = JSON.parse(jsonMatch[0]);
3084
+ if (typeof parsed.summary === "string") {
3085
+ return {
3086
+ summary: parsed.summary || "",
3087
+ relevantFiles: Array.isArray(parsed.relevantFiles) ? parsed.relevantFiles : [],
3088
+ patterns: Array.isArray(parsed.patterns) ? parsed.patterns : [],
3089
+ constraints: Array.isArray(parsed.constraints) ? parsed.constraints : [],
3090
+ dependencies: Array.isArray(parsed.dependencies) ? parsed.dependencies : []
3091
+ };
3092
+ }
3093
+ }
3094
+ } catch {
3095
+ }
3096
+ return {
3097
+ summary: response,
3098
+ relevantFiles: [],
3099
+ patterns: [],
3100
+ constraints: [],
3101
+ dependencies: []
3102
+ };
3103
+ }
3104
+ /**
3105
+ * Parse verify phase output (JSON)
3106
+ */
3107
+ parseVerifyOutput(response) {
3108
+ try {
3109
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
3110
+ if (jsonMatch) {
3111
+ const parsed = JSON.parse(jsonMatch[0]);
3112
+ if (typeof parsed.passed === "boolean" && parsed.score) {
3113
+ return {
3114
+ passed: parsed.passed,
3115
+ score: {
3116
+ requirementsCoverage: parsed.score.requirementsCoverage ?? 0,
3117
+ templateCompliance: parsed.score.templateCompliance ?? 0,
3118
+ consistency: parsed.score.consistency ?? 0,
3119
+ completeness: parsed.score.completeness ?? 0
3120
+ },
3121
+ issues: Array.isArray(parsed.issues) ? parsed.issues : [],
3122
+ summary: parsed.summary || ""
3123
+ };
3124
+ }
3125
+ }
3126
+ } catch {
3127
+ }
3128
+ return {
3129
+ passed: false,
3130
+ score: {
3131
+ requirementsCoverage: 0,
3132
+ templateCompliance: 0,
3133
+ consistency: 0,
3134
+ completeness: 0
3135
+ },
3136
+ issues: [{
3137
+ severity: "error",
3138
+ category: "parsing",
3139
+ description: "Failed to parse verification output",
3140
+ suggestion: "Ensure AI returns valid JSON"
3141
+ }],
3142
+ summary: "Verification parsing failed"
3143
+ };
3144
+ }
2382
3145
  /**
2383
3146
  * Update document status in frontmatter
2384
3147
  */
@@ -2990,7 +3753,7 @@ async function startCommand(query, options) {
2990
3753
  console.log(`
2991
3754
  \u{1F680} Starting workflow: ${query}
2992
3755
  `);
2993
- if (response.type === "phase" && response.phase === "context") {
3756
+ if (response.type === "phase" && (response.phase === "explore" || response.phase === "context")) {
2994
3757
  taskId = response.taskId;
2995
3758
  if (isGitHubMode && "io" in adapter && "setTaskId" in adapter.io) {
2996
3759
  adapter.io.setTaskId(taskId);
@@ -3001,7 +3764,21 @@ async function startCommand(query, options) {
3001
3764
  if (response.type === "phase") {
3002
3765
  const phaseResponse = response;
3003
3766
  taskId = phaseResponse.taskId;
3004
- if (phaseResponse.phase === "context") {
3767
+ if (phaseResponse.phase === "explore") {
3768
+ const exploreResp = phaseResponse;
3769
+ console.log(`
3770
+ --- Step ${exploreResp.stepIndex}/${exploreResp.totalSteps}: ${exploreResp.step} ---`);
3771
+ console.log("Phase 1/5: Exploring codebase...\n");
3772
+ const stepContext = {
3773
+ taskId: exploreResp.taskId,
3774
+ description: exploreResp.description,
3775
+ stepIndex: exploreResp.stepIndex,
3776
+ totalSteps: exploreResp.totalSteps,
3777
+ previousOutput: exploreResp.context.previousOutput
3778
+ };
3779
+ const result = await stepExecutor.executeExplorePhase(exploreResp.step, stepContext);
3780
+ response = orchestrator.cmdExploreDone(taskId, result.exploreOutput);
3781
+ } else if (phaseResponse.phase === "context") {
3005
3782
  const contextResp = phaseResponse;
3006
3783
  console.log(`
3007
3784
  --- Step ${contextResp.stepIndex}/${contextResp.totalSteps}: ${contextResp.step} ---`);
@@ -3028,6 +3805,36 @@ async function startCommand(query, options) {
3028
3805
  };
3029
3806
  const result = await stepExecutor.executeClarifyPhase(clarifyResp.step, stepContext);
3030
3807
  response = orchestrator.cmdClarifyDone(taskId, result.questions || []);
3808
+ } else if (phaseResponse.phase === "execute" || phaseResponse.phase === "draft") {
3809
+ const executeResp = phaseResponse;
3810
+ const attemptInfo = executeResp.context.verifyFeedback ? " (auto-fix)" : "";
3811
+ console.log(`Phase 3/5: Executing${attemptInfo}...
3812
+ `);
3813
+ const stepContext = {
3814
+ taskId: executeResp.taskId,
3815
+ description: executeResp.description,
3816
+ stepIndex: executeResp.stepIndex,
3817
+ totalSteps: executeResp.totalSteps,
3818
+ exploreOutput: executeResp.exploreOutput,
3819
+ answers: executeResp.answers,
3820
+ revisionFeedback: executeResp.context.revisionFeedback,
3821
+ verifyFeedback: executeResp.context.verifyFeedback
3822
+ };
3823
+ await stepExecutor.executeExecutePhase(executeResp.step, stepContext);
3824
+ response = orchestrator.cmdExecuteDone(taskId);
3825
+ } else if (phaseResponse.phase === "verify") {
3826
+ const verifyResp = phaseResponse;
3827
+ console.log(`Phase 4/5: Verifying document (attempt ${verifyResp.verifyAttempts}/${verifyResp.maxAttempts})...
3828
+ `);
3829
+ const stepContext = {
3830
+ taskId: verifyResp.taskId,
3831
+ description: verifyResp.description,
3832
+ stepIndex: verifyResp.stepIndex,
3833
+ totalSteps: verifyResp.totalSteps,
3834
+ verifyAttempts: verifyResp.verifyAttempts
3835
+ };
3836
+ const result = await stepExecutor.executeVerifyPhase(verifyResp.step, stepContext);
3837
+ response = orchestrator.cmdVerifyDone(taskId, result.verifyOutput);
3031
3838
  } else if (phaseResponse.phase === "generate") {
3032
3839
  const generateResp = phaseResponse;
3033
3840
  console.log("Phase 3/4: Generating document...\n");
@@ -3280,7 +4087,21 @@ async function resumeCommand(options) {
3280
4087
  if (response.type === "phase") {
3281
4088
  const phaseResponse = response;
3282
4089
  taskId = phaseResponse.taskId;
3283
- if (phaseResponse.phase === "context") {
4090
+ if (phaseResponse.phase === "explore") {
4091
+ const exploreResp = phaseResponse;
4092
+ console.log(`
4093
+ --- Step ${exploreResp.stepIndex}/${exploreResp.totalSteps}: ${exploreResp.step} ---`);
4094
+ console.log("Phase 1/5: Exploring codebase...\n");
4095
+ const stepContext = {
4096
+ taskId: exploreResp.taskId,
4097
+ description: exploreResp.description,
4098
+ stepIndex: exploreResp.stepIndex,
4099
+ totalSteps: exploreResp.totalSteps,
4100
+ previousOutput: exploreResp.context.previousOutput
4101
+ };
4102
+ const result = await stepExecutor.executeExplorePhase(exploreResp.step, stepContext);
4103
+ response = orchestrator.cmdExploreDone(taskId, result.exploreOutput);
4104
+ } else if (phaseResponse.phase === "context") {
3284
4105
  const contextResp = phaseResponse;
3285
4106
  console.log(`
3286
4107
  --- Step ${contextResp.stepIndex}/${contextResp.totalSteps}: ${contextResp.step} ---`);
@@ -3306,6 +4127,36 @@ async function resumeCommand(options) {
3306
4127
  };
3307
4128
  const result = await stepExecutor.executeClarifyPhase(clarifyResp.step, stepContext);
3308
4129
  response = orchestrator.cmdClarifyDone(taskId, result.questions || []);
4130
+ } else if (phaseResponse.phase === "execute" || phaseResponse.phase === "draft") {
4131
+ const executeResp = phaseResponse;
4132
+ const attemptInfo = executeResp.context.verifyFeedback ? " (auto-fix)" : "";
4133
+ console.log(`Phase 3/5: Executing${attemptInfo}...
4134
+ `);
4135
+ const stepContext = {
4136
+ taskId: executeResp.taskId,
4137
+ description: executeResp.description,
4138
+ stepIndex: executeResp.stepIndex,
4139
+ totalSteps: executeResp.totalSteps,
4140
+ exploreOutput: executeResp.exploreOutput,
4141
+ answers: executeResp.answers,
4142
+ revisionFeedback: executeResp.context.revisionFeedback,
4143
+ verifyFeedback: executeResp.context.verifyFeedback
4144
+ };
4145
+ await stepExecutor.executeExecutePhase(executeResp.step, stepContext);
4146
+ response = orchestrator.cmdExecuteDone(taskId);
4147
+ } else if (phaseResponse.phase === "verify") {
4148
+ const verifyResp = phaseResponse;
4149
+ console.log(`Phase 4/5: Verifying document (attempt ${verifyResp.verifyAttempts}/${verifyResp.maxAttempts})...
4150
+ `);
4151
+ const stepContext = {
4152
+ taskId: verifyResp.taskId,
4153
+ description: verifyResp.description,
4154
+ stepIndex: verifyResp.stepIndex,
4155
+ totalSteps: verifyResp.totalSteps,
4156
+ verifyAttempts: verifyResp.verifyAttempts
4157
+ };
4158
+ const result = await stepExecutor.executeVerifyPhase(verifyResp.step, stepContext);
4159
+ response = orchestrator.cmdVerifyDone(taskId, result.verifyOutput);
3309
4160
  } else if (phaseResponse.phase === "generate") {
3310
4161
  const generateResp = phaseResponse;
3311
4162
  console.log("Phase 3/4: Generating document...\n");
@@ -3551,11 +4402,14 @@ Parse JSON response \u2192 execute action from table below \u2192 loop until \`t
3551
4402
 
3552
4403
  | \`phase\` | Action |
3553
4404
  |---------|--------|
3554
- | \`context\` | [ACTION_CONTEXT](#action_context) |
4405
+ | \`explore\` | [ACTION_EXPLORE](#action_explore) |
3555
4406
  | \`clarify\` | [ACTION_CLARIFY](#action_clarify) |
3556
- | \`generate\` | [ACTION_GENERATE](#action_generate) |
4407
+ | \`execute\` | [ACTION_EXECUTE](#action_execute) |
4408
+ | \`verify\` | [ACTION_VERIFY](#action_verify) |
3557
4409
  | \`generate-sections\` | [ACTION_PARALLEL_SECTIONS](#action_parallel_sections) |
3558
4410
  | \`consolidate\` | [ACTION_PARALLEL_CONSOLIDATE](#action_parallel_consolidate) |
4411
+ | \`context\` | [ACTION_CONTEXT](#action_context) (legacy) |
4412
+ | \`generate\` | [ACTION_GENERATE](#action_generate) (legacy) |
3559
4413
 
3560
4414
  ### \`type: "checkpoint"\`
3561
4415
 
@@ -3580,28 +4434,66 @@ Print: "Error: {error}" \u2192 STOP
3580
4434
 
3581
4435
  ## Action Definitions
3582
4436
 
3583
- ### ACTION_CONTEXT
4437
+ **IMPORTANT:** Each phase response includes a \`prompt\` field containing the exact instructions to follow.
4438
+ This ensures identical behavior across CLI, Claude Code, and GitHub modes.
4439
+
4440
+ ### ACTION_EXPLORE
3584
4441
 
3585
4442
  \`\`\`
3586
- 1. Read(context.instruction)
3587
- 2. IF context.previousOutput EXISTS: Read(context.previousOutput)
3588
- 3. Explore codebase for: {description}
3589
- 4. Bash: npx spets orchestrate context-done {taskId}
3590
- 5. Parse response \u2192 next action
4443
+ 1. Follow the instructions in response.prompt EXACTLY
4444
+ 2. The prompt tells you:
4445
+ - What to search for
4446
+ - How to analyze the codebase
4447
+ - The exact JSON output format required
4448
+ 3. Bash: npx spets orchestrate explore-done {taskId} '{exploreJson}'
4449
+ 4. Parse response \u2192 next action
3591
4450
  \`\`\`
3592
4451
 
3593
4452
  ### ACTION_CLARIFY
3594
4453
 
3595
4454
  \`\`\`
3596
- 1. Analyze: gatheredContext, previousQA (if exists)
3597
- 2. Generate questions array (0-4 questions)
4455
+ 1. Follow the instructions in response.prompt EXACTLY
4456
+ 2. The prompt tells you:
4457
+ - What context to analyze
4458
+ - How to generate questions
4459
+ - The exact JSON output format required
3598
4460
  3. Bash: npx spets orchestrate clarify-done {taskId} '{questionsJson}'
3599
4461
  - Format: [{"id":"q1","question":"..."},...]
3600
4462
  - Empty if no questions: []
3601
4463
  4. Parse response \u2192 next action
3602
4464
  \`\`\`
3603
4465
 
3604
- ### ACTION_GENERATE
4466
+ ### ACTION_EXECUTE
4467
+
4468
+ \`\`\`
4469
+ 1. Follow the instructions in response.prompt EXACTLY
4470
+ 2. The prompt tells you:
4471
+ - The instruction and template to follow
4472
+ - The explore output and answers to use
4473
+ - Where to save the document/code (context.output)
4474
+ - Any revision/verify feedback to address
4475
+ 3. Write the document/code to context.output
4476
+ 4. Bash: npx spets orchestrate execute-done {taskId}
4477
+ 5. Parse response \u2192 next action
4478
+ \`\`\`
4479
+
4480
+ ### ACTION_VERIFY
4481
+
4482
+ \`\`\`
4483
+ 1. Follow the instructions in response.prompt EXACTLY
4484
+ 2. The prompt tells you:
4485
+ - The document to verify (already included in prompt)
4486
+ - The requirements and template to check against
4487
+ - The scoring criteria and pass conditions
4488
+ - The exact JSON output format required
4489
+ 3. Bash: npx spets orchestrate verify-done {taskId} '{verifyJson}'
4490
+ 4. Parse response \u2192 next action
4491
+ - If passed: goes to human review
4492
+ - If failed (attempts < 3): goes back to draft phase (auto-fix)
4493
+ - If failed (attempts >= 3): goes to human review with warning
4494
+ \`\`\`
4495
+
4496
+ ### ACTION_GENERATE (legacy)
3605
4497
 
3606
4498
  \`\`\`
3607
4499
  1. Read(context.instruction)
@@ -3613,6 +4505,16 @@ Print: "Error: {error}" \u2192 STOP
3613
4505
  7. Parse response \u2192 next action
3614
4506
  \`\`\`
3615
4507
 
4508
+ ### ACTION_CONTEXT (legacy)
4509
+
4510
+ \`\`\`
4511
+ 1. Read(context.instruction)
4512
+ 2. IF context.previousOutput EXISTS: Read(context.previousOutput)
4513
+ 3. Explore codebase for: {description}
4514
+ 4. Bash: npx spets orchestrate context-done {taskId}
4515
+ 5. Parse response \u2192 next action
4516
+ \`\`\`
4517
+
3616
4518
  ### ACTION_PARALLEL_SECTIONS
3617
4519
 
3618
4520
  **PARALLEL EXECUTION (FOREGROUND)**
@@ -3731,17 +4633,25 @@ Print: "Error: {error}" \u2192 STOP
3731
4633
  ## Orchestrator Commands Reference
3732
4634
 
3733
4635
  \`\`\`bash
4636
+ # New 5-phase workflow
3734
4637
  npx spets orchestrate init "<description>"
3735
- npx spets orchestrate context-done <taskId>
4638
+ npx spets orchestrate explore-done <taskId> '<json>'
3736
4639
  npx spets orchestrate clarify-done <taskId> '<json>'
3737
4640
  npx spets orchestrate clarified <taskId> '<json>'
3738
- npx spets orchestrate generate-done <taskId>
3739
- npx spets orchestrate sections-done <taskId>
3740
- npx spets orchestrate consolidate-level-done <taskId> <level>
4641
+ npx spets orchestrate execute-done <taskId>
4642
+ npx spets orchestrate verify-done <taskId> '<json>'
3741
4643
  npx spets orchestrate approve <taskId>
3742
4644
  npx spets orchestrate revise <taskId> "<feedback>"
3743
4645
  npx spets orchestrate reject <taskId>
3744
4646
  npx spets orchestrate stop <taskId>
4647
+
4648
+ # Section-based workflow
4649
+ npx spets orchestrate sections-done <taskId>
4650
+ npx spets orchestrate consolidate-level-done <taskId> <level>
4651
+
4652
+ # Legacy (backward compatible)
4653
+ npx spets orchestrate context-done <taskId>
4654
+ npx spets orchestrate generate-done <taskId>
3745
4655
  \`\`\`
3746
4656
 
3747
4657
  ---
@@ -4293,6 +5203,31 @@ async function orchestrateCommand(action, args) {
4293
5203
  outputJSON(result);
4294
5204
  break;
4295
5205
  }
5206
+ case "explore-done": {
5207
+ const taskId = args[0];
5208
+ const exploreJson = args[1];
5209
+ if (!taskId) {
5210
+ outputError("Task ID is required for explore-done");
5211
+ return;
5212
+ }
5213
+ let exploreOutput = {
5214
+ summary: "",
5215
+ relevantFiles: [],
5216
+ patterns: [],
5217
+ constraints: [],
5218
+ dependencies: []
5219
+ };
5220
+ if (exploreJson) {
5221
+ try {
5222
+ exploreOutput = JSON.parse(exploreJson);
5223
+ } catch {
5224
+ exploreOutput.summary = exploreJson;
5225
+ }
5226
+ }
5227
+ const result = orchestrator.cmdExploreDone(taskId, exploreOutput);
5228
+ outputJSON(result);
5229
+ break;
5230
+ }
4296
5231
  case "clarify-done": {
4297
5232
  const taskId = args[0];
4298
5233
  const questionsJson = args[1];
@@ -4323,6 +5258,57 @@ async function orchestrateCommand(action, args) {
4323
5258
  outputJSON(result);
4324
5259
  break;
4325
5260
  }
5261
+ case "execute-done": {
5262
+ const taskId = args[0];
5263
+ if (!taskId) {
5264
+ outputError("Task ID is required for execute-done");
5265
+ return;
5266
+ }
5267
+ const result = orchestrator.cmdExecuteDone(taskId);
5268
+ outputJSON(result);
5269
+ break;
5270
+ }
5271
+ // Legacy alias for execute-done
5272
+ case "draft-done": {
5273
+ const taskId = args[0];
5274
+ if (!taskId) {
5275
+ outputError("Task ID is required for draft-done");
5276
+ return;
5277
+ }
5278
+ const result = orchestrator.cmdExecuteDone(taskId);
5279
+ outputJSON(result);
5280
+ break;
5281
+ }
5282
+ case "verify-done": {
5283
+ const taskId = args[0];
5284
+ const verifyJson = args[1];
5285
+ if (!taskId) {
5286
+ outputError("Task ID is required for verify-done");
5287
+ return;
5288
+ }
5289
+ let verifyOutput = {
5290
+ passed: false,
5291
+ score: {
5292
+ requirementsCoverage: 0,
5293
+ templateCompliance: 0,
5294
+ consistency: 0,
5295
+ completeness: 0
5296
+ },
5297
+ issues: [],
5298
+ summary: ""
5299
+ };
5300
+ if (verifyJson) {
5301
+ try {
5302
+ verifyOutput = JSON.parse(verifyJson);
5303
+ } catch {
5304
+ outputError("Invalid JSON for verify output");
5305
+ return;
5306
+ }
5307
+ }
5308
+ const result = orchestrator.cmdVerifyDone(taskId, verifyOutput);
5309
+ outputJSON(result);
5310
+ break;
5311
+ }
4326
5312
  case "done": {
4327
5313
  const taskId = args[0];
4328
5314
  if (!taskId) {
@@ -4430,7 +5416,7 @@ async function orchestrateCommand(action, args) {
4430
5416
  break;
4431
5417
  }
4432
5418
  default:
4433
- outputError(`Unknown action: ${action}. Valid actions: init, context-done, clarify-done, generate-done, done, clarified, approve, revise, reject, stop, status, sections-done, consolidate-level-done`);
5419
+ outputError(`Unknown action: ${action}. Valid actions: init, explore-done, clarify-done, execute-done, verify-done, clarified, approve, revise, reject, stop, status, sections-done, consolidate-level-done (legacy: context-done, generate-done, draft-done, done)`);
4434
5420
  }
4435
5421
  } catch (e) {
4436
5422
  outputError(e.message);