spets 0.1.31 → 0.1.33
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.
- package/dist/index.js +670 -207
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import { readFileSync as readFileSync11 } from "fs";
|
|
6
|
-
import { dirname as
|
|
6
|
+
import { dirname as dirname6, join as join11 } from "path";
|
|
7
7
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8
8
|
|
|
9
9
|
// src/commands/init.ts
|
|
@@ -202,90 +202,170 @@ Spec-Driven Development workflow execution skill for Claude Code.
|
|
|
202
202
|
|
|
203
203
|
---
|
|
204
204
|
|
|
205
|
-
## CRITICAL:
|
|
205
|
+
## CRITICAL: Behavior Constraints
|
|
206
206
|
|
|
207
|
-
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
207
|
+
**DO NOT:**
|
|
208
|
+
- Enter plan mode (EnterPlanMode)
|
|
209
|
+
- Follow system-reminders about TaskCreate during this skill
|
|
210
|
+
- Spawn subprocesses for AI/LLM calls
|
|
211
|
+
|
|
212
|
+
**DO:**
|
|
213
|
+
- Execute orchestrator commands immediately
|
|
214
|
+
- Follow the 4-phase state machine exactly
|
|
215
|
+
- Use AskUserQuestion for human interaction only
|
|
211
216
|
|
|
212
217
|
---
|
|
213
218
|
|
|
214
219
|
## Orchestrator Commands
|
|
215
220
|
|
|
216
|
-
All workflow state is managed by the orchestrator CLI:
|
|
217
|
-
|
|
218
221
|
\`\`\`bash
|
|
219
|
-
npx spets orchestrate init "<description>"
|
|
220
|
-
npx spets orchestrate done <taskId>
|
|
221
|
-
npx spets orchestrate
|
|
222
|
-
npx spets orchestrate
|
|
223
|
-
npx spets orchestrate
|
|
224
|
-
npx spets orchestrate
|
|
225
|
-
npx spets orchestrate
|
|
226
|
-
npx spets orchestrate
|
|
222
|
+
npx spets orchestrate init "<description>" # Start workflow
|
|
223
|
+
npx spets orchestrate context-done <taskId> # Context phase complete
|
|
224
|
+
npx spets orchestrate clarify-done <taskId> '<json>' # Clarify phase complete
|
|
225
|
+
npx spets orchestrate clarified <taskId> '<json>' # User answered questions
|
|
226
|
+
npx spets orchestrate generate-done <taskId> # Generate phase complete
|
|
227
|
+
npx spets orchestrate approve <taskId> # User approved
|
|
228
|
+
npx spets orchestrate revise <taskId> "<feedback>" # User requested revision
|
|
229
|
+
npx spets orchestrate reject <taskId> # User rejected
|
|
230
|
+
npx spets orchestrate stop <taskId> # Pause workflow
|
|
231
|
+
npx spets orchestrate status <taskId> # Get current state
|
|
227
232
|
\`\`\`
|
|
228
233
|
|
|
229
234
|
---
|
|
230
235
|
|
|
231
|
-
##
|
|
236
|
+
## Workflow: 4-Phase Model
|
|
232
237
|
|
|
233
|
-
|
|
238
|
+
Each step goes through 4 phases:
|
|
239
|
+
1. **context** - Gather codebase context
|
|
240
|
+
2. **clarify** - Generate questions (checkpoint if questions exist)
|
|
241
|
+
3. **generate** - Create document
|
|
242
|
+
4. **review** - Human approval (checkpoint always)
|
|
234
243
|
|
|
235
|
-
|
|
244
|
+
---
|
|
236
245
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
246
|
+
## Response Types & Actions
|
|
247
|
+
|
|
248
|
+
### 1. Phase: context (\`type: "phase", phase: "context"\`)
|
|
249
|
+
|
|
250
|
+
AI gathers context about the codebase.
|
|
251
|
+
|
|
252
|
+
**Action:**
|
|
253
|
+
1. Read \`context.instruction\` file
|
|
254
|
+
2. Read \`context.previousOutput\` file (if exists)
|
|
255
|
+
3. Explore codebase relevant to the task description
|
|
256
|
+
4. Call: \`npx spets orchestrate context-done {taskId}\`
|
|
257
|
+
|
|
258
|
+
**Note:** Do NOT include context as argument - just signal completion.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### 2. Phase: clarify (\`type: "phase", phase: "clarify"\`)
|
|
263
|
+
|
|
264
|
+
AI generates questions based on gathered context.
|
|
265
|
+
|
|
266
|
+
**Action:**
|
|
267
|
+
1. Review \`gatheredContext\` and \`previousQA\` (if exists)
|
|
268
|
+
2. Generate clarifying questions if needed (max 3-4)
|
|
269
|
+
3. If questions exist:
|
|
270
|
+
\`\`\`bash
|
|
271
|
+
npx spets orchestrate clarify-done {taskId} '[{"id":"q1","question":"..."},...]'
|
|
272
|
+
\`\`\`
|
|
273
|
+
4. If no questions needed:
|
|
274
|
+
\`\`\`bash
|
|
275
|
+
npx spets orchestrate clarify-done {taskId} '[]'
|
|
276
|
+
\`\`\`
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### 3. Checkpoint: clarify (\`type: "checkpoint", checkpoint: "clarify"\`)
|
|
281
|
+
|
|
282
|
+
Human needs to answer questions.
|
|
283
|
+
|
|
284
|
+
**Action:**
|
|
285
|
+
1. Use **AskUserQuestion** tool to ask the questions
|
|
286
|
+
2. Collect answers into JSON array
|
|
287
|
+
3. Call:
|
|
288
|
+
\`\`\`bash
|
|
289
|
+
npx spets orchestrate clarified {taskId} '[{"questionId":"q1","answer":"..."},...]'
|
|
290
|
+
\`\`\`
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
### 4. Phase: generate (\`type: "phase", phase: "generate"\`)
|
|
295
|
+
|
|
296
|
+
AI creates the document.
|
|
297
|
+
|
|
298
|
+
**Action:**
|
|
299
|
+
1. Read \`context.instruction\` file
|
|
300
|
+
2. Read \`context.template\` file (if exists)
|
|
301
|
+
3. Read \`context.previousOutput\` file (if exists)
|
|
302
|
+
4. Use \`gatheredContext\` and \`answers\` (if provided)
|
|
303
|
+
5. Consider \`context.revisionFeedback\` (if revision)
|
|
304
|
+
6. Write document to \`context.output\`
|
|
305
|
+
7. Call: \`npx spets orchestrate generate-done {taskId}\`
|
|
306
|
+
|
|
307
|
+
---
|
|
240
308
|
|
|
241
|
-
###
|
|
309
|
+
### 5. Checkpoint: approve (\`type: "checkpoint", checkpoint: "approve"\`)
|
|
242
310
|
|
|
243
|
-
|
|
311
|
+
Human reviews and approves document.
|
|
244
312
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
313
|
+
**Action:**
|
|
314
|
+
1. Read and summarize document from \`specPath\`
|
|
315
|
+
2. Use **AskUserQuestion** with options:
|
|
316
|
+
- **Approve** - Proceed to next step
|
|
317
|
+
- **Revise** - Request changes (collect feedback)
|
|
318
|
+
- **Reject** - Stop workflow
|
|
319
|
+
- **Stop** - Pause for later
|
|
251
320
|
|
|
252
|
-
|
|
321
|
+
3. Execute based on selection:
|
|
322
|
+
- Approve: \`npx spets orchestrate approve {taskId}\`
|
|
323
|
+
- Revise: \`npx spets orchestrate revise {taskId} "{feedback}"\`
|
|
324
|
+
- Reject: \`npx spets orchestrate reject {taskId}\`
|
|
325
|
+
- Stop: \`npx spets orchestrate stop {taskId}\`
|
|
253
326
|
|
|
254
|
-
|
|
255
|
-
2. **Collect answers** into JSON format
|
|
256
|
-
3. **Submit answers**: \`npx spets orchestrate clarified {taskId} '<answers_json>'\`
|
|
327
|
+
---
|
|
257
328
|
|
|
258
|
-
###
|
|
329
|
+
### 6. Complete (\`type: "complete"\`)
|
|
259
330
|
|
|
260
|
-
|
|
261
|
-
2. **Use AskUserQuestion** with options: Approve, Revise, Reject, Stop
|
|
262
|
-
3. **Execute the selected action**
|
|
331
|
+
Workflow finished.
|
|
263
332
|
|
|
264
|
-
|
|
333
|
+
**Action:**
|
|
334
|
+
- \`completed\`: Show success, list outputs
|
|
335
|
+
- \`stopped\`: Show resume instructions
|
|
336
|
+
- \`rejected\`: Show rejection message
|
|
265
337
|
|
|
266
|
-
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
### 7. Error (\`type: "error"\`)
|
|
341
|
+
|
|
342
|
+
**Action:** Display error message and stop.
|
|
267
343
|
|
|
268
344
|
---
|
|
269
345
|
|
|
270
|
-
## Response Type
|
|
346
|
+
## Response Type Summary
|
|
271
347
|
|
|
272
|
-
|
|
|
273
|
-
|
|
274
|
-
|
|
|
275
|
-
|
|
|
276
|
-
| checkpoint |
|
|
277
|
-
|
|
|
278
|
-
|
|
|
348
|
+
| type | phase/checkpoint | Action |
|
|
349
|
+
|------|------------------|--------|
|
|
350
|
+
| phase | context | Explore codebase \u2192 \`context-done\` |
|
|
351
|
+
| phase | clarify | Generate questions \u2192 \`clarify-done\` |
|
|
352
|
+
| checkpoint | clarify | AskUserQuestion \u2192 \`clarified\` |
|
|
353
|
+
| phase | generate | Write document \u2192 \`generate-done\` |
|
|
354
|
+
| checkpoint | approve | AskUserQuestion \u2192 \`approve/revise/reject/stop\` |
|
|
355
|
+
| complete | - | Display final message |
|
|
356
|
+
| error | - | Display error, stop |
|
|
279
357
|
|
|
280
358
|
---
|
|
281
359
|
|
|
282
|
-
##
|
|
360
|
+
## Execution Flow (FIRST ACTION)
|
|
283
361
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
362
|
+
When skill is loaded, **immediately** run:
|
|
363
|
+
|
|
364
|
+
\`\`\`bash
|
|
365
|
+
npx spets orchestrate init "{user_request}"
|
|
366
|
+
\`\`\`
|
|
367
|
+
|
|
368
|
+
Then follow the response type actions above in a loop until \`type: "complete"\` or \`type: "error"\`.
|
|
289
369
|
|
|
290
370
|
---
|
|
291
371
|
|
|
@@ -294,24 +374,36 @@ Display completion message based on status (completed, stopped, rejected)
|
|
|
294
374
|
\`\`\`
|
|
295
375
|
User: /spets Add user authentication
|
|
296
376
|
|
|
297
|
-
[
|
|
298
|
-
[
|
|
377
|
+
[Run: npx spets orchestrate init "Add user authentication"]
|
|
378
|
+
[Response: type=phase, phase=context, step=01-plan]
|
|
299
379
|
|
|
300
|
-
[
|
|
301
|
-
[
|
|
302
|
-
[
|
|
303
|
-
[Skill calls: npx spets orchestrate done mku3abc-xyz]
|
|
380
|
+
[Read instruction, explore codebase]
|
|
381
|
+
[Run: npx spets orchestrate context-done {taskId}]
|
|
382
|
+
[Response: type=phase, phase=clarify]
|
|
304
383
|
|
|
305
|
-
[
|
|
306
|
-
[
|
|
307
|
-
[
|
|
384
|
+
[Generate 2 questions about auth approach]
|
|
385
|
+
[Run: npx spets orchestrate clarify-done {taskId} '[{"id":"q1",...},{"id":"q2",...}]']
|
|
386
|
+
[Response: type=checkpoint, checkpoint=clarify]
|
|
308
387
|
|
|
309
|
-
|
|
388
|
+
[AskUserQuestion with the questions]
|
|
389
|
+
[User answers]
|
|
390
|
+
[Run: npx spets orchestrate clarified {taskId} '[{"questionId":"q1","answer":"OAuth"},...]']
|
|
391
|
+
[Response: type=phase, phase=clarify]
|
|
310
392
|
|
|
311
|
-
[
|
|
312
|
-
[
|
|
393
|
+
[No more questions needed]
|
|
394
|
+
[Run: npx spets orchestrate clarify-done {taskId} '[]']
|
|
395
|
+
[Response: type=phase, phase=generate]
|
|
313
396
|
|
|
314
|
-
[
|
|
397
|
+
[Read instruction, template, write document]
|
|
398
|
+
[Run: npx spets orchestrate generate-done {taskId}]
|
|
399
|
+
[Response: type=checkpoint, checkpoint=approve]
|
|
400
|
+
|
|
401
|
+
[Show document summary, AskUserQuestion: Approve/Revise/Reject/Stop]
|
|
402
|
+
[User: Approve]
|
|
403
|
+
[Run: npx spets orchestrate approve {taskId}]
|
|
404
|
+
[Response: type=phase, phase=context, step=02-implement]
|
|
405
|
+
|
|
406
|
+
[... continues with next step ...]
|
|
315
407
|
\`\`\`
|
|
316
408
|
|
|
317
409
|
$ARGUMENTS
|
|
@@ -1531,7 +1623,7 @@ var Orchestrator = class {
|
|
|
1531
1623
|
};
|
|
1532
1624
|
|
|
1533
1625
|
// src/core/step-executor.ts
|
|
1534
|
-
import { existsSync as existsSync6,
|
|
1626
|
+
import { existsSync as existsSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
1535
1627
|
import matter3 from "gray-matter";
|
|
1536
1628
|
|
|
1537
1629
|
// src/core/prompt-builder.ts
|
|
@@ -1772,8 +1864,115 @@ function buildGeneratePrompt(params) {
|
|
|
1772
1864
|
outputPath
|
|
1773
1865
|
};
|
|
1774
1866
|
}
|
|
1867
|
+
function buildSectionPrompt(params) {
|
|
1868
|
+
const { section, sharedContext, gatheredContext, answers } = params;
|
|
1869
|
+
const parts = [];
|
|
1870
|
+
parts.push(`# Section: ${section.title}`);
|
|
1871
|
+
parts.push("");
|
|
1872
|
+
parts.push("## Document Context");
|
|
1873
|
+
parts.push("");
|
|
1874
|
+
parts.push(`**Goal:** ${sharedContext.documentGoal}`);
|
|
1875
|
+
parts.push(`**Step:** ${sharedContext.stepName}`);
|
|
1876
|
+
parts.push(`**Total Sections:** ${sharedContext.totalSections}`);
|
|
1877
|
+
parts.push("");
|
|
1878
|
+
parts.push("## Document Structure");
|
|
1879
|
+
parts.push("");
|
|
1880
|
+
parts.push("```");
|
|
1881
|
+
parts.push(sharedContext.treeOverview);
|
|
1882
|
+
parts.push("```");
|
|
1883
|
+
parts.push("");
|
|
1884
|
+
parts.push("## Your Position");
|
|
1885
|
+
parts.push("");
|
|
1886
|
+
parts.push(`- **Path:** ${section.position.path.join(" > ")}`);
|
|
1887
|
+
parts.push(`- **Siblings:** ${section.position.siblings.join(", ") || "None"}`);
|
|
1888
|
+
parts.push(`- **Parent:** ${section.position.parent || "Root"}`);
|
|
1889
|
+
parts.push("");
|
|
1890
|
+
if (gatheredContext) {
|
|
1891
|
+
parts.push("## Gathered Context");
|
|
1892
|
+
parts.push("");
|
|
1893
|
+
parts.push(gatheredContext);
|
|
1894
|
+
parts.push("");
|
|
1895
|
+
}
|
|
1896
|
+
if (answers && answers.length > 0) {
|
|
1897
|
+
parts.push("## User Answers");
|
|
1898
|
+
parts.push("");
|
|
1899
|
+
for (const answer of answers) {
|
|
1900
|
+
parts.push(`- **${answer.questionId}**: ${answer.answer}`);
|
|
1901
|
+
}
|
|
1902
|
+
parts.push("");
|
|
1903
|
+
}
|
|
1904
|
+
if (section.templateContent) {
|
|
1905
|
+
parts.push("## Template Guide");
|
|
1906
|
+
parts.push("");
|
|
1907
|
+
parts.push(section.templateContent);
|
|
1908
|
+
parts.push("");
|
|
1909
|
+
}
|
|
1910
|
+
parts.push("## Your Task");
|
|
1911
|
+
parts.push("");
|
|
1912
|
+
parts.push(`Write the "${section.title.replace(/^#+\\s*/, "")}" section.`);
|
|
1913
|
+
parts.push("Consider how it relates to sibling sections and contributes to the parent section.");
|
|
1914
|
+
parts.push("");
|
|
1915
|
+
parts.push("## Output");
|
|
1916
|
+
parts.push("");
|
|
1917
|
+
parts.push(`Save to: \`${section.outputPath}\``);
|
|
1918
|
+
parts.push("");
|
|
1919
|
+
parts.push("Write ONLY the content for this section (including its header).");
|
|
1920
|
+
parts.push("Do NOT include content from other sections.");
|
|
1921
|
+
parts.push("");
|
|
1922
|
+
return {
|
|
1923
|
+
prompt: parts.join("\n"),
|
|
1924
|
+
outputPath: section.outputPath
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
function buildConsolidatePrompt(params) {
|
|
1928
|
+
const { group, childContents, sharedContext, parentTitle } = params;
|
|
1929
|
+
const parts = [];
|
|
1930
|
+
parts.push("# Consolidate Sections");
|
|
1931
|
+
parts.push("");
|
|
1932
|
+
parts.push("## Document Context");
|
|
1933
|
+
parts.push("");
|
|
1934
|
+
parts.push(`**Goal:** ${sharedContext.documentGoal}`);
|
|
1935
|
+
parts.push(`**Step:** ${sharedContext.stepName}`);
|
|
1936
|
+
parts.push("");
|
|
1937
|
+
parts.push("## Document Structure");
|
|
1938
|
+
parts.push("");
|
|
1939
|
+
parts.push("```");
|
|
1940
|
+
parts.push(sharedContext.treeOverview);
|
|
1941
|
+
parts.push("```");
|
|
1942
|
+
parts.push("");
|
|
1943
|
+
parts.push("## Your Task");
|
|
1944
|
+
parts.push("");
|
|
1945
|
+
parts.push(`Consolidate the following child sections into the parent section "${parentTitle || group.parentId}".`);
|
|
1946
|
+
parts.push("");
|
|
1947
|
+
parts.push("## Child Sections to Consolidate");
|
|
1948
|
+
parts.push("");
|
|
1949
|
+
for (const child of childContents) {
|
|
1950
|
+
parts.push(`### Child: ${child.id}`);
|
|
1951
|
+
parts.push("");
|
|
1952
|
+
parts.push(child.content);
|
|
1953
|
+
parts.push("");
|
|
1954
|
+
parts.push("---");
|
|
1955
|
+
parts.push("");
|
|
1956
|
+
}
|
|
1957
|
+
parts.push("## Output Instructions");
|
|
1958
|
+
parts.push("");
|
|
1959
|
+
parts.push(`Save consolidated content to: \`${group.outputPath}\``);
|
|
1960
|
+
parts.push("");
|
|
1961
|
+
parts.push("**Guidelines:**");
|
|
1962
|
+
parts.push("- Combine child sections into a coherent parent section");
|
|
1963
|
+
parts.push("- Maintain the hierarchy (parent header, then children)");
|
|
1964
|
+
parts.push("- Ensure smooth transitions between sections");
|
|
1965
|
+
parts.push("- Preserve all content from child sections");
|
|
1966
|
+
parts.push("");
|
|
1967
|
+
return {
|
|
1968
|
+
prompt: parts.join("\n"),
|
|
1969
|
+
outputPath: group.outputPath
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1775
1972
|
|
|
1776
1973
|
// src/core/step-executor.ts
|
|
1974
|
+
import { readFileSync as readFileSync6, existsSync as fsExistsSync, mkdirSync as mkdirSync4 } from "fs";
|
|
1975
|
+
import { dirname as dirname3 } from "path";
|
|
1777
1976
|
import { join as join6 } from "path";
|
|
1778
1977
|
var StepExecutor = class {
|
|
1779
1978
|
adapter;
|
|
@@ -1893,6 +2092,122 @@ var StepExecutor = class {
|
|
|
1893
2092
|
return { phase: "generate" };
|
|
1894
2093
|
}
|
|
1895
2094
|
// ==========================================================================
|
|
2095
|
+
// Phase 3 (Section Mode): Parallel Section Generation
|
|
2096
|
+
// ==========================================================================
|
|
2097
|
+
/**
|
|
2098
|
+
* Execute section generation phase - AI creates individual sections in parallel
|
|
2099
|
+
*/
|
|
2100
|
+
async executeSectionsPhase(sections, sharedContext, gatheredContext, answers) {
|
|
2101
|
+
this.adapter.io.notify(
|
|
2102
|
+
`Phase 3/4: Generating ${sections.length} sections in parallel`,
|
|
2103
|
+
"info"
|
|
2104
|
+
);
|
|
2105
|
+
const results = await Promise.all(
|
|
2106
|
+
sections.map(async (section) => {
|
|
2107
|
+
try {
|
|
2108
|
+
const params = {
|
|
2109
|
+
section: {
|
|
2110
|
+
id: section.id,
|
|
2111
|
+
title: section.title,
|
|
2112
|
+
outputPath: section.outputPath,
|
|
2113
|
+
instruction: section.instruction,
|
|
2114
|
+
position: section.position,
|
|
2115
|
+
templateContent: section.templateContent
|
|
2116
|
+
},
|
|
2117
|
+
sharedContext,
|
|
2118
|
+
gatheredContext,
|
|
2119
|
+
answers
|
|
2120
|
+
};
|
|
2121
|
+
const { prompt, outputPath } = buildSectionPrompt(params);
|
|
2122
|
+
const dir = dirname3(outputPath);
|
|
2123
|
+
if (!fsExistsSync(dir)) {
|
|
2124
|
+
mkdirSync4(dir, { recursive: true });
|
|
2125
|
+
}
|
|
2126
|
+
await this.adapter.ai.execute({ prompt, outputPath });
|
|
2127
|
+
if (!fsExistsSync(outputPath)) {
|
|
2128
|
+
return { id: section.id, success: false, error: `File not created: ${outputPath}` };
|
|
2129
|
+
}
|
|
2130
|
+
this.adapter.io.notify(`Section created: ${section.id}`, "success");
|
|
2131
|
+
return { id: section.id, success: true };
|
|
2132
|
+
} catch (error) {
|
|
2133
|
+
return {
|
|
2134
|
+
id: section.id,
|
|
2135
|
+
success: false,
|
|
2136
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
})
|
|
2140
|
+
);
|
|
2141
|
+
const failures = results.filter((r) => !r.success);
|
|
2142
|
+
if (failures.length > 0) {
|
|
2143
|
+
const errorMsg = failures.map((f) => `${f.id}: ${f.error}`).join(", ");
|
|
2144
|
+
throw new Error(`Section generation failed: ${errorMsg}`);
|
|
2145
|
+
}
|
|
2146
|
+
return { phase: "generate" };
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Execute consolidation phase - AI merges child sections into parent
|
|
2150
|
+
*/
|
|
2151
|
+
async executeConsolidatePhase(groups, sharedContext, getSectionPath) {
|
|
2152
|
+
this.adapter.io.notify(
|
|
2153
|
+
`Consolidating ${groups.length} section groups`,
|
|
2154
|
+
"info"
|
|
2155
|
+
);
|
|
2156
|
+
const results = await Promise.all(
|
|
2157
|
+
groups.map(async (group) => {
|
|
2158
|
+
try {
|
|
2159
|
+
const childContents = [];
|
|
2160
|
+
for (const childId of group.childIds) {
|
|
2161
|
+
const childPath = getSectionPath(childId);
|
|
2162
|
+
if (!childPath || !fsExistsSync(childPath)) {
|
|
2163
|
+
return {
|
|
2164
|
+
parentId: group.parentId,
|
|
2165
|
+
success: false,
|
|
2166
|
+
error: `Child section not found: ${childId}`
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
childContents.push({
|
|
2170
|
+
id: childId,
|
|
2171
|
+
content: readFileSync6(childPath, "utf-8")
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
2174
|
+
const params = {
|
|
2175
|
+
group: {
|
|
2176
|
+
parentId: group.parentId,
|
|
2177
|
+
childIds: group.childIds,
|
|
2178
|
+
outputPath: group.outputPath
|
|
2179
|
+
},
|
|
2180
|
+
childContents,
|
|
2181
|
+
sharedContext
|
|
2182
|
+
};
|
|
2183
|
+
const { prompt, outputPath } = buildConsolidatePrompt(params);
|
|
2184
|
+
const dir = dirname3(outputPath);
|
|
2185
|
+
if (!fsExistsSync(dir)) {
|
|
2186
|
+
mkdirSync4(dir, { recursive: true });
|
|
2187
|
+
}
|
|
2188
|
+
await this.adapter.ai.execute({ prompt, outputPath });
|
|
2189
|
+
if (!fsExistsSync(outputPath)) {
|
|
2190
|
+
return { parentId: group.parentId, success: false, error: `File not created: ${outputPath}` };
|
|
2191
|
+
}
|
|
2192
|
+
this.adapter.io.notify(`Consolidated: ${group.parentId}`, "success");
|
|
2193
|
+
return { parentId: group.parentId, success: true };
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
return {
|
|
2196
|
+
parentId: group.parentId,
|
|
2197
|
+
success: false,
|
|
2198
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
})
|
|
2202
|
+
);
|
|
2203
|
+
const failures = results.filter((r) => !r.success);
|
|
2204
|
+
if (failures.length > 0) {
|
|
2205
|
+
const errorMsg = failures.map((f) => `${f.parentId}: ${f.error}`).join(", ");
|
|
2206
|
+
throw new Error(`Consolidation failed: ${errorMsg}`);
|
|
2207
|
+
}
|
|
2208
|
+
return { phase: "generate" };
|
|
2209
|
+
}
|
|
2210
|
+
// ==========================================================================
|
|
1896
2211
|
// Phase 4: Review (Approval)
|
|
1897
2212
|
// ==========================================================================
|
|
1898
2213
|
/**
|
|
@@ -2025,8 +2340,8 @@ var StepExecutor = class {
|
|
|
2025
2340
|
|
|
2026
2341
|
// src/adapters/cli.ts
|
|
2027
2342
|
import { spawn, spawnSync } from "child_process";
|
|
2028
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as
|
|
2029
|
-
import { dirname as
|
|
2343
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
2344
|
+
import { dirname as dirname4 } from "path";
|
|
2030
2345
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
2031
2346
|
var CLIAIAdapter = class {
|
|
2032
2347
|
claudeCommand;
|
|
@@ -2037,9 +2352,9 @@ var CLIAIAdapter = class {
|
|
|
2037
2352
|
console.log(`
|
|
2038
2353
|
\u{1F4DD} Generating...`);
|
|
2039
2354
|
if (params.outputPath) {
|
|
2040
|
-
const outputDir =
|
|
2355
|
+
const outputDir = dirname4(params.outputPath);
|
|
2041
2356
|
if (!existsSync7(outputDir)) {
|
|
2042
|
-
|
|
2357
|
+
mkdirSync5(outputDir, { recursive: true });
|
|
2043
2358
|
}
|
|
2044
2359
|
}
|
|
2045
2360
|
const stdout = await this.callClaude(params.prompt);
|
|
@@ -2172,9 +2487,9 @@ var CLISystemAdapter = class {
|
|
|
2172
2487
|
return readFileSync7(path, "utf-8");
|
|
2173
2488
|
}
|
|
2174
2489
|
writeFile(path, content) {
|
|
2175
|
-
const dir =
|
|
2490
|
+
const dir = dirname4(path);
|
|
2176
2491
|
if (!existsSync7(dir)) {
|
|
2177
|
-
|
|
2492
|
+
mkdirSync5(dir, { recursive: true });
|
|
2178
2493
|
}
|
|
2179
2494
|
writeFileSync5(path, content);
|
|
2180
2495
|
}
|
|
@@ -2210,8 +2525,8 @@ function createCLIAdapter(claudeCommand = "claude") {
|
|
|
2210
2525
|
|
|
2211
2526
|
// src/adapters/github.ts
|
|
2212
2527
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
2213
|
-
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync8, mkdirSync as
|
|
2214
|
-
import { dirname as
|
|
2528
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync8, mkdirSync as mkdirSync6 } from "fs";
|
|
2529
|
+
import { dirname as dirname5 } from "path";
|
|
2215
2530
|
var GitHubAIAdapter = class {
|
|
2216
2531
|
claudeCommand;
|
|
2217
2532
|
constructor(claudeCommand = "claude") {
|
|
@@ -2221,9 +2536,9 @@ var GitHubAIAdapter = class {
|
|
|
2221
2536
|
console.log(`
|
|
2222
2537
|
\u{1F4DD} Generating...`);
|
|
2223
2538
|
if (params.outputPath) {
|
|
2224
|
-
const outputDir =
|
|
2539
|
+
const outputDir = dirname5(params.outputPath);
|
|
2225
2540
|
if (!existsSync8(outputDir)) {
|
|
2226
|
-
|
|
2541
|
+
mkdirSync6(outputDir, { recursive: true });
|
|
2227
2542
|
}
|
|
2228
2543
|
}
|
|
2229
2544
|
const stdout = await this.callClaude(params.prompt);
|
|
@@ -2409,9 +2724,9 @@ var GitHubSystemAdapter = class {
|
|
|
2409
2724
|
return readFileSync8(path, "utf-8");
|
|
2410
2725
|
}
|
|
2411
2726
|
writeFile(path, content) {
|
|
2412
|
-
const dir =
|
|
2727
|
+
const dir = dirname5(path);
|
|
2413
2728
|
if (!existsSync8(dir)) {
|
|
2414
|
-
|
|
2729
|
+
mkdirSync6(dir, { recursive: true });
|
|
2415
2730
|
}
|
|
2416
2731
|
writeFileSync6(path, content);
|
|
2417
2732
|
}
|
|
@@ -2574,6 +2889,41 @@ async function startCommand(query, options) {
|
|
|
2574
2889
|
};
|
|
2575
2890
|
await stepExecutor.executeGeneratePhase(generateResp.step, stepContext);
|
|
2576
2891
|
response = orchestrator.cmdGenerateDone(taskId);
|
|
2892
|
+
} else if (phaseResponse.phase === "generate-sections") {
|
|
2893
|
+
const sectionsResp = phaseResponse;
|
|
2894
|
+
console.log(`Phase 3/4: Generating ${sectionsResp.parallelSections.length} sections in parallel...
|
|
2895
|
+
`);
|
|
2896
|
+
await stepExecutor.executeSectionsPhase(
|
|
2897
|
+
sectionsResp.parallelSections,
|
|
2898
|
+
sectionsResp.sharedContext,
|
|
2899
|
+
sectionsResp.sharedContext.stepInstruction,
|
|
2900
|
+
void 0
|
|
2901
|
+
// answers not passed here, already incorporated in instruction
|
|
2902
|
+
);
|
|
2903
|
+
response = orchestrator.cmdSectionsDone(taskId);
|
|
2904
|
+
} else if (phaseResponse.phase === "consolidate") {
|
|
2905
|
+
const consolidateResp = phaseResponse;
|
|
2906
|
+
console.log(`Phase 3/4: Consolidating level ${consolidateResp.level} (${consolidateResp.parallelGroups.length} groups)...
|
|
2907
|
+
`);
|
|
2908
|
+
const getSectionPath = (id) => {
|
|
2909
|
+
for (const group of consolidateResp.parallelGroups) {
|
|
2910
|
+
if (group.parentId === id) {
|
|
2911
|
+
return group.outputPath;
|
|
2912
|
+
}
|
|
2913
|
+
for (const childId of group.childIds) {
|
|
2914
|
+
if (childId === id) {
|
|
2915
|
+
return void 0;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
return void 0;
|
|
2920
|
+
};
|
|
2921
|
+
await stepExecutor.executeConsolidatePhase(
|
|
2922
|
+
consolidateResp.parallelGroups,
|
|
2923
|
+
consolidateResp.sharedContext,
|
|
2924
|
+
getSectionPath
|
|
2925
|
+
);
|
|
2926
|
+
response = orchestrator.cmdConsolidateLevelDone(taskId, consolidateResp.level);
|
|
2577
2927
|
}
|
|
2578
2928
|
} else if (response.type === "checkpoint") {
|
|
2579
2929
|
taskId = response.taskId;
|
|
@@ -2691,8 +3041,8 @@ function listResumableTasks(cwd) {
|
|
|
2691
3041
|
try {
|
|
2692
3042
|
const response = orchestrator.cmdStatus(taskId);
|
|
2693
3043
|
if (response.type === "error") continue;
|
|
2694
|
-
if (response.type === "
|
|
2695
|
-
const
|
|
3044
|
+
if (response.type === "phase" || response.type === "checkpoint") {
|
|
3045
|
+
const phaseResponse = response;
|
|
2696
3046
|
tasks.push({
|
|
2697
3047
|
taskId,
|
|
2698
3048
|
status: response.type === "checkpoint" ? "awaiting_input" : "in_progress",
|
|
@@ -2774,41 +3124,99 @@ async function resumeCommand(options) {
|
|
|
2774
3124
|
}
|
|
2775
3125
|
try {
|
|
2776
3126
|
while (response.type !== "complete" && response.type !== "error") {
|
|
2777
|
-
if (response.type === "
|
|
2778
|
-
const
|
|
2779
|
-
taskId =
|
|
2780
|
-
|
|
2781
|
-
|
|
3127
|
+
if (response.type === "phase") {
|
|
3128
|
+
const phaseResponse = response;
|
|
3129
|
+
taskId = phaseResponse.taskId;
|
|
3130
|
+
if (phaseResponse.phase === "context") {
|
|
3131
|
+
const contextResp = phaseResponse;
|
|
3132
|
+
console.log(`
|
|
3133
|
+
--- Step ${contextResp.stepIndex}/${contextResp.totalSteps}: ${contextResp.step} ---`);
|
|
3134
|
+
console.log("Phase 1/4: Gathering context...\n");
|
|
3135
|
+
const stepContext = {
|
|
3136
|
+
taskId: contextResp.taskId,
|
|
3137
|
+
description: contextResp.description,
|
|
3138
|
+
stepIndex: contextResp.stepIndex,
|
|
3139
|
+
totalSteps: contextResp.totalSteps,
|
|
3140
|
+
previousOutput: contextResp.context.previousOutput
|
|
3141
|
+
};
|
|
3142
|
+
const result = await stepExecutor.executeContextPhase(contextResp.step, stepContext);
|
|
3143
|
+
response = orchestrator.cmdContextDone(taskId, result.context || "");
|
|
3144
|
+
} else if (phaseResponse.phase === "clarify") {
|
|
3145
|
+
const clarifyResp = phaseResponse;
|
|
3146
|
+
console.log("Phase 2/4: Generating questions...\n");
|
|
3147
|
+
const stepContext = {
|
|
3148
|
+
taskId: clarifyResp.taskId,
|
|
3149
|
+
description: clarifyResp.description,
|
|
3150
|
+
stepIndex: 0,
|
|
3151
|
+
totalSteps: 0,
|
|
3152
|
+
gatheredContext: clarifyResp.gatheredContext
|
|
3153
|
+
};
|
|
3154
|
+
const result = await stepExecutor.executeClarifyPhase(clarifyResp.step, stepContext);
|
|
3155
|
+
response = orchestrator.cmdClarifyDone(taskId, result.questions || []);
|
|
3156
|
+
} else if (phaseResponse.phase === "generate") {
|
|
3157
|
+
const generateResp = phaseResponse;
|
|
3158
|
+
console.log("Phase 3/4: Generating document...\n");
|
|
3159
|
+
const stepContext = {
|
|
3160
|
+
taskId: generateResp.taskId,
|
|
3161
|
+
description: generateResp.description,
|
|
3162
|
+
stepIndex: generateResp.stepIndex,
|
|
3163
|
+
totalSteps: generateResp.totalSteps,
|
|
3164
|
+
gatheredContext: generateResp.gatheredContext,
|
|
3165
|
+
answers: generateResp.answers,
|
|
3166
|
+
revisionFeedback: generateResp.context.revisionFeedback
|
|
3167
|
+
};
|
|
3168
|
+
await stepExecutor.executeGeneratePhase(generateResp.step, stepContext);
|
|
3169
|
+
response = orchestrator.cmdGenerateDone(taskId);
|
|
3170
|
+
} else if (phaseResponse.phase === "generate-sections") {
|
|
3171
|
+
const sectionsResp = phaseResponse;
|
|
3172
|
+
console.log(`Phase 3/4: Generating ${sectionsResp.parallelSections.length} sections in parallel...
|
|
2782
3173
|
`);
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
3174
|
+
await stepExecutor.executeSectionsPhase(
|
|
3175
|
+
sectionsResp.parallelSections,
|
|
3176
|
+
sectionsResp.sharedContext,
|
|
3177
|
+
sectionsResp.sharedContext.stepInstruction,
|
|
3178
|
+
void 0
|
|
3179
|
+
);
|
|
3180
|
+
response = orchestrator.cmdSectionsDone(taskId);
|
|
3181
|
+
} else if (phaseResponse.phase === "consolidate") {
|
|
3182
|
+
const consolidateResp = phaseResponse;
|
|
3183
|
+
console.log(`Phase 3/4: Consolidating level ${consolidateResp.level} (${consolidateResp.parallelGroups.length} groups)...
|
|
3184
|
+
`);
|
|
3185
|
+
const getSectionPath = (id) => {
|
|
3186
|
+
for (const group of consolidateResp.parallelGroups) {
|
|
3187
|
+
if (group.parentId === id) {
|
|
3188
|
+
return group.outputPath;
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
return void 0;
|
|
3192
|
+
};
|
|
3193
|
+
await stepExecutor.executeConsolidatePhase(
|
|
3194
|
+
consolidateResp.parallelGroups,
|
|
3195
|
+
consolidateResp.sharedContext,
|
|
3196
|
+
getSectionPath
|
|
3197
|
+
);
|
|
3198
|
+
response = orchestrator.cmdConsolidateLevelDone(taskId, consolidateResp.level);
|
|
2799
3199
|
}
|
|
2800
3200
|
} else if (response.type === "checkpoint") {
|
|
2801
3201
|
taskId = response.taskId;
|
|
2802
3202
|
if (response.checkpoint === "clarify") {
|
|
2803
|
-
|
|
2804
|
-
|
|
3203
|
+
const clarifyCheckpoint = response;
|
|
3204
|
+
console.log("Phase 2/4: Questions need answers\n");
|
|
3205
|
+
const answers = await adapter.io.askMultiple(clarifyCheckpoint.questions);
|
|
3206
|
+
if (answers.length === 0) {
|
|
3207
|
+
adapter.io.notify("No answers provided", "warning");
|
|
3208
|
+
response = orchestrator.cmdStatus(taskId);
|
|
3209
|
+
} else {
|
|
3210
|
+
response = orchestrator.cmdClarified(taskId, answers);
|
|
3211
|
+
}
|
|
2805
3212
|
} else if (response.checkpoint === "approve") {
|
|
2806
|
-
const
|
|
3213
|
+
const approveCheckpoint = response;
|
|
3214
|
+
console.log("Phase 4/4: Review document\n");
|
|
2807
3215
|
const approval = await adapter.io.approve(
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
3216
|
+
approveCheckpoint.specPath,
|
|
3217
|
+
approveCheckpoint.step,
|
|
3218
|
+
approveCheckpoint.stepIndex,
|
|
3219
|
+
approveCheckpoint.totalSteps
|
|
2812
3220
|
);
|
|
2813
3221
|
if (approval.action === "approve") {
|
|
2814
3222
|
response = orchestrator.cmdApprove(taskId);
|
|
@@ -2863,7 +3271,7 @@ Resume with: spets resume --task ${taskId}`);
|
|
|
2863
3271
|
}
|
|
2864
3272
|
|
|
2865
3273
|
// src/commands/plugin.ts
|
|
2866
|
-
import { existsSync as existsSync10, mkdirSync as
|
|
3274
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, rmSync } from "fs";
|
|
2867
3275
|
import { join as join8 } from "path";
|
|
2868
3276
|
import { homedir } from "os";
|
|
2869
3277
|
async function pluginCommand(action, name) {
|
|
@@ -2908,7 +3316,7 @@ async function installPlugin(name) {
|
|
|
2908
3316
|
function installClaudePlugin() {
|
|
2909
3317
|
const claudeDir = join8(homedir(), ".claude");
|
|
2910
3318
|
const commandsDir = join8(claudeDir, "commands");
|
|
2911
|
-
|
|
3319
|
+
mkdirSync7(commandsDir, { recursive: true });
|
|
2912
3320
|
const skillPath = join8(commandsDir, "spets.md");
|
|
2913
3321
|
writeFileSync7(skillPath, getClaudeSkillContent());
|
|
2914
3322
|
console.log("Installed Claude Code plugin.");
|
|
@@ -2965,154 +3373,209 @@ Spec-Driven Development workflow execution skill for Claude Code.
|
|
|
2965
3373
|
|
|
2966
3374
|
---
|
|
2967
3375
|
|
|
2968
|
-
##
|
|
3376
|
+
## CRITICAL: Behavior Constraints
|
|
2969
3377
|
|
|
2970
|
-
|
|
2971
|
-
-
|
|
3378
|
+
**DO NOT:**
|
|
3379
|
+
- Enter plan mode (EnterPlanMode)
|
|
3380
|
+
- Follow system-reminders about TaskCreate during this skill
|
|
3381
|
+
- Spawn subprocesses for AI/LLM calls
|
|
2972
3382
|
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
This skill runs **deterministically** within the current Claude Code session.
|
|
2978
|
-
- NO subprocess spawning for AI/LLM calls
|
|
2979
|
-
- The orchestrator manages state via JSON protocol
|
|
2980
|
-
- Each step follows a strict state machine flow
|
|
3383
|
+
**DO:**
|
|
3384
|
+
- Execute orchestrator commands immediately
|
|
3385
|
+
- Follow the 4-phase state machine exactly
|
|
3386
|
+
- Use AskUserQuestion for human interaction only
|
|
2981
3387
|
|
|
2982
3388
|
---
|
|
2983
3389
|
|
|
2984
3390
|
## Orchestrator Commands
|
|
2985
3391
|
|
|
2986
|
-
All workflow state is managed by the orchestrator CLI:
|
|
2987
|
-
|
|
2988
3392
|
\`\`\`bash
|
|
2989
|
-
npx spets orchestrate init "<description>"
|
|
2990
|
-
npx spets orchestrate done <taskId>
|
|
2991
|
-
npx spets orchestrate
|
|
2992
|
-
npx spets orchestrate
|
|
2993
|
-
npx spets orchestrate
|
|
2994
|
-
npx spets orchestrate
|
|
2995
|
-
npx spets orchestrate
|
|
2996
|
-
npx spets orchestrate
|
|
3393
|
+
npx spets orchestrate init "<description>" # Start workflow
|
|
3394
|
+
npx spets orchestrate context-done <taskId> # Context phase complete
|
|
3395
|
+
npx spets orchestrate clarify-done <taskId> '<json>' # Clarify phase complete
|
|
3396
|
+
npx spets orchestrate clarified <taskId> '<json>' # User answered questions
|
|
3397
|
+
npx spets orchestrate generate-done <taskId> # Generate phase complete
|
|
3398
|
+
npx spets orchestrate approve <taskId> # User approved
|
|
3399
|
+
npx spets orchestrate revise <taskId> "<feedback>" # User requested revision
|
|
3400
|
+
npx spets orchestrate reject <taskId> # User rejected
|
|
3401
|
+
npx spets orchestrate stop <taskId> # Pause workflow
|
|
3402
|
+
npx spets orchestrate status <taskId> # Get current state
|
|
2997
3403
|
\`\`\`
|
|
2998
3404
|
|
|
2999
3405
|
---
|
|
3000
3406
|
|
|
3001
|
-
##
|
|
3407
|
+
## Workflow: 4-Phase Model
|
|
3002
3408
|
|
|
3003
|
-
|
|
3409
|
+
Each step goes through 4 phases:
|
|
3410
|
+
1. **context** - Gather codebase context
|
|
3411
|
+
2. **clarify** - Generate questions (checkpoint if questions exist)
|
|
3412
|
+
3. **generate** - Create document
|
|
3413
|
+
4. **review** - Human approval (checkpoint always)
|
|
3004
3414
|
|
|
3005
|
-
|
|
3415
|
+
---
|
|
3006
3416
|
|
|
3007
|
-
|
|
3008
|
-
npx spets orchestrate init "{user_request}"
|
|
3009
|
-
\`\`\`
|
|
3417
|
+
## Response Types & Actions
|
|
3010
3418
|
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
"template": ".spets/steps/01-plan/template.md",
|
|
3023
|
-
"output": ".spets/outputs/mku3abc-xyz/01-plan.md",
|
|
3024
|
-
"revisionFeedback": null
|
|
3025
|
-
},
|
|
3026
|
-
"onComplete": "done mku3abc-xyz"
|
|
3027
|
-
}
|
|
3028
|
-
\`\`\`
|
|
3419
|
+
### 1. Phase: context (\`type: "phase", phase: "context"\`)
|
|
3420
|
+
|
|
3421
|
+
AI gathers context about the codebase.
|
|
3422
|
+
|
|
3423
|
+
**Action:**
|
|
3424
|
+
1. Read \`context.instruction\` file
|
|
3425
|
+
2. Read \`context.previousOutput\` file (if exists)
|
|
3426
|
+
3. Explore codebase relevant to the task description
|
|
3427
|
+
4. Call: \`npx spets orchestrate context-done {taskId}\`
|
|
3428
|
+
|
|
3429
|
+
**Note:** Do NOT include context as argument - just signal completion.
|
|
3029
3430
|
|
|
3030
3431
|
---
|
|
3031
3432
|
|
|
3032
|
-
### 2.
|
|
3433
|
+
### 2. Phase: clarify (\`type: "phase", phase: "clarify"\`)
|
|
3033
3434
|
|
|
3034
|
-
|
|
3435
|
+
AI generates questions based on gathered context.
|
|
3035
3436
|
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3437
|
+
**Action:**
|
|
3438
|
+
1. Review \`gatheredContext\` and \`previousQA\` (if exists)
|
|
3439
|
+
2. Generate clarifying questions if needed (max 3-4)
|
|
3440
|
+
3. If questions exist:
|
|
3441
|
+
\`\`\`bash
|
|
3442
|
+
npx spets orchestrate clarify-done {taskId} '[{"id":"q1","question":"..."},...]'
|
|
3443
|
+
\`\`\`
|
|
3444
|
+
4. If no questions needed:
|
|
3042
3445
|
\`\`\`bash
|
|
3043
|
-
npx spets orchestrate done {taskId}
|
|
3446
|
+
npx spets orchestrate clarify-done {taskId} '[]'
|
|
3044
3447
|
\`\`\`
|
|
3045
3448
|
|
|
3046
3449
|
---
|
|
3047
3450
|
|
|
3048
|
-
### 3.
|
|
3451
|
+
### 3. Checkpoint: clarify (\`type: "checkpoint", checkpoint: "clarify"\`)
|
|
3049
3452
|
|
|
3050
|
-
|
|
3453
|
+
Human needs to answer questions.
|
|
3051
3454
|
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3455
|
+
**Action:**
|
|
3456
|
+
1. Use **AskUserQuestion** tool to ask the questions
|
|
3457
|
+
2. Collect answers into JSON array
|
|
3458
|
+
3. Call:
|
|
3055
3459
|
\`\`\`bash
|
|
3056
|
-
npx spets orchestrate clarified {taskId} '[{"questionId":"q1","answer":"..."}]'
|
|
3460
|
+
npx spets orchestrate clarified {taskId} '[{"questionId":"q1","answer":"..."},...]'
|
|
3057
3461
|
\`\`\`
|
|
3058
3462
|
|
|
3059
3463
|
---
|
|
3060
3464
|
|
|
3061
|
-
### 4.
|
|
3465
|
+
### 4. Phase: generate (\`type: "phase", phase: "generate"\`)
|
|
3466
|
+
|
|
3467
|
+
AI creates the document.
|
|
3468
|
+
|
|
3469
|
+
**Action:**
|
|
3470
|
+
1. Read \`context.instruction\` file
|
|
3471
|
+
2. Read \`context.template\` file (if exists)
|
|
3472
|
+
3. Read \`context.previousOutput\` file (if exists)
|
|
3473
|
+
4. Use \`gatheredContext\` and \`answers\` (if provided)
|
|
3474
|
+
5. Consider \`context.revisionFeedback\` (if revision)
|
|
3475
|
+
6. Write document to \`context.output\`
|
|
3476
|
+
7. Call: \`npx spets orchestrate generate-done {taskId}\`
|
|
3477
|
+
|
|
3478
|
+
---
|
|
3479
|
+
|
|
3480
|
+
### 5. Checkpoint: approve (\`type: "checkpoint", checkpoint: "approve"\`)
|
|
3062
3481
|
|
|
3063
|
-
|
|
3482
|
+
Human reviews and approves document.
|
|
3064
3483
|
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
-
|
|
3069
|
-
-
|
|
3070
|
-
-
|
|
3484
|
+
**Action:**
|
|
3485
|
+
1. Read and summarize document from \`specPath\`
|
|
3486
|
+
2. Use **AskUserQuestion** with options:
|
|
3487
|
+
- **Approve** - Proceed to next step
|
|
3488
|
+
- **Revise** - Request changes (collect feedback)
|
|
3489
|
+
- **Reject** - Stop workflow
|
|
3490
|
+
- **Stop** - Pause for later
|
|
3071
3491
|
|
|
3072
|
-
3.
|
|
3073
|
-
-
|
|
3074
|
-
-
|
|
3075
|
-
-
|
|
3076
|
-
-
|
|
3492
|
+
3. Execute based on selection:
|
|
3493
|
+
- Approve: \`npx spets orchestrate approve {taskId}\`
|
|
3494
|
+
- Revise: \`npx spets orchestrate revise {taskId} "{feedback}"\`
|
|
3495
|
+
- Reject: \`npx spets orchestrate reject {taskId}\`
|
|
3496
|
+
- Stop: \`npx spets orchestrate stop {taskId}\`
|
|
3077
3497
|
|
|
3078
3498
|
---
|
|
3079
3499
|
|
|
3080
|
-
###
|
|
3500
|
+
### 6. Complete (\`type: "complete"\`)
|
|
3501
|
+
|
|
3502
|
+
Workflow finished.
|
|
3081
3503
|
|
|
3082
|
-
|
|
3083
|
-
- \`completed\`: Show success
|
|
3504
|
+
**Action:**
|
|
3505
|
+
- \`completed\`: Show success, list outputs
|
|
3084
3506
|
- \`stopped\`: Show resume instructions
|
|
3085
3507
|
- \`rejected\`: Show rejection message
|
|
3086
3508
|
|
|
3087
3509
|
---
|
|
3088
3510
|
|
|
3089
|
-
|
|
3511
|
+
### 7. Error (\`type: "error"\`)
|
|
3512
|
+
|
|
3513
|
+
**Action:** Display error message and stop.
|
|
3514
|
+
|
|
3515
|
+
---
|
|
3516
|
+
|
|
3517
|
+
## Response Type Summary
|
|
3090
3518
|
|
|
3091
|
-
|
|
|
3092
|
-
|
|
3093
|
-
|
|
|
3094
|
-
|
|
|
3095
|
-
| checkpoint |
|
|
3096
|
-
|
|
|
3097
|
-
|
|
|
3519
|
+
| type | phase/checkpoint | Action |
|
|
3520
|
+
|------|------------------|--------|
|
|
3521
|
+
| phase | context | Explore codebase \u2192 \`context-done\` |
|
|
3522
|
+
| phase | clarify | Generate questions \u2192 \`clarify-done\` |
|
|
3523
|
+
| checkpoint | clarify | AskUserQuestion \u2192 \`clarified\` |
|
|
3524
|
+
| phase | generate | Write document \u2192 \`generate-done\` |
|
|
3525
|
+
| checkpoint | approve | AskUserQuestion \u2192 \`approve/revise/reject/stop\` |
|
|
3526
|
+
| complete | - | Display final message |
|
|
3527
|
+
| error | - | Display error, stop |
|
|
3098
3528
|
|
|
3099
3529
|
---
|
|
3100
3530
|
|
|
3101
|
-
##
|
|
3531
|
+
## Execution Flow (FIRST ACTION)
|
|
3532
|
+
|
|
3533
|
+
When skill is loaded, **immediately** run:
|
|
3534
|
+
|
|
3535
|
+
\`\`\`bash
|
|
3536
|
+
npx spets orchestrate init "{user_request}"
|
|
3537
|
+
\`\`\`
|
|
3102
3538
|
|
|
3103
|
-
|
|
3104
|
-
2. **ONE STEP AT A TIME** - Complete one step, get approval, then next
|
|
3105
|
-
3. **DETERMINISTIC FLOW** - Follow the exact state machine transitions
|
|
3106
|
-
4. **NO PROCESS SPAWN FOR AI** - Generate documents in current session
|
|
3107
|
-
5. **WAIT FOR APPROVAL** - Never proceed without user approval
|
|
3539
|
+
Then follow the response type actions above in a loop until \`type: "complete"\` or \`type: "error"\`.
|
|
3108
3540
|
|
|
3109
3541
|
---
|
|
3110
3542
|
|
|
3111
|
-
##
|
|
3543
|
+
## Example Session
|
|
3544
|
+
|
|
3545
|
+
\`\`\`
|
|
3546
|
+
User: /spets Add user authentication
|
|
3547
|
+
|
|
3548
|
+
[Run: npx spets orchestrate init "Add user authentication"]
|
|
3549
|
+
[Response: type=phase, phase=context, step=01-plan]
|
|
3550
|
+
|
|
3551
|
+
[Read instruction, explore codebase]
|
|
3552
|
+
[Run: npx spets orchestrate context-done {taskId}]
|
|
3553
|
+
[Response: type=phase, phase=clarify]
|
|
3554
|
+
|
|
3555
|
+
[Generate 2 questions about auth approach]
|
|
3556
|
+
[Run: npx spets orchestrate clarify-done {taskId} '[{"id":"q1",...},{"id":"q2",...}]']
|
|
3557
|
+
[Response: type=checkpoint, checkpoint=clarify]
|
|
3558
|
+
|
|
3559
|
+
[AskUserQuestion with the questions]
|
|
3560
|
+
[User answers]
|
|
3561
|
+
[Run: npx spets orchestrate clarified {taskId} '[{"questionId":"q1","answer":"OAuth"},...]']
|
|
3562
|
+
[Response: type=phase, phase=clarify]
|
|
3112
3563
|
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3564
|
+
[No more questions needed]
|
|
3565
|
+
[Run: npx spets orchestrate clarify-done {taskId} '[]']
|
|
3566
|
+
[Response: type=phase, phase=generate]
|
|
3567
|
+
|
|
3568
|
+
[Read instruction, template, write document]
|
|
3569
|
+
[Run: npx spets orchestrate generate-done {taskId}]
|
|
3570
|
+
[Response: type=checkpoint, checkpoint=approve]
|
|
3571
|
+
|
|
3572
|
+
[Show document summary, AskUserQuestion: Approve/Revise/Reject/Stop]
|
|
3573
|
+
[User: Approve]
|
|
3574
|
+
[Run: npx spets orchestrate approve {taskId}]
|
|
3575
|
+
[Response: type=phase, phase=context, step=02-implement]
|
|
3576
|
+
|
|
3577
|
+
[... continues with next step ...]
|
|
3578
|
+
\`\`\`
|
|
3116
3579
|
|
|
3117
3580
|
$ARGUMENTS
|
|
3118
3581
|
request: The user's task description for the workflow
|
|
@@ -3806,7 +4269,7 @@ async function orchestrateCommand(action, args) {
|
|
|
3806
4269
|
}
|
|
3807
4270
|
|
|
3808
4271
|
// src/index.ts
|
|
3809
|
-
var __dirname2 =
|
|
4272
|
+
var __dirname2 = dirname6(fileURLToPath2(import.meta.url));
|
|
3810
4273
|
var pkg = JSON.parse(readFileSync11(join11(__dirname2, "..", "package.json"), "utf-8"));
|
|
3811
4274
|
var program = new Command();
|
|
3812
4275
|
program.name("spets").description("Spec Driven Development Execution Framework").version(pkg.version);
|