spets 0.2.1 → 0.2.3

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 +161 -165
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -104,8 +104,7 @@ async function installPlugin(name) {
104
104
  installer();
105
105
  }
106
106
  function installClaudePlugin() {
107
- const claudeDir = join(homedir(), ".claude");
108
- const commandsDir = join(claudeDir, "commands");
107
+ const commandsDir = join(process.cwd(), ".claude", "commands");
109
108
  mkdirSync(commandsDir, { recursive: true });
110
109
  const skillPath = join(commandsDir, "spets.md");
111
110
  writeFileSync(skillPath, getClaudeSkillContent());
@@ -148,13 +147,18 @@ function installGeminiPlugin() {
148
147
  }
149
148
  async function uninstallPlugin(name) {
150
149
  if (name === "claude") {
151
- const skillPath = join(homedir(), ".claude", "commands", "spets.md");
150
+ const skillPath = join(process.cwd(), ".claude", "commands", "spets.md");
151
+ const globalSkillPath = join(homedir(), ".claude", "commands", "spets.md");
152
152
  const legacySkillPath = join(homedir(), ".claude", "commands", "sdd-do.md");
153
153
  let uninstalled = false;
154
154
  if (existsSync(skillPath)) {
155
155
  rmSync(skillPath);
156
156
  uninstalled = true;
157
157
  }
158
+ if (existsSync(globalSkillPath)) {
159
+ rmSync(globalSkillPath);
160
+ uninstalled = true;
161
+ }
158
162
  if (existsSync(legacySkillPath)) {
159
163
  rmSync(legacySkillPath);
160
164
  uninstalled = true;
@@ -241,13 +245,14 @@ async function uninstallPlugin(name) {
241
245
  async function listPlugins() {
242
246
  console.log("Available plugins:");
243
247
  console.log("");
244
- console.log(" claude - Claude Code /spets skill (global)");
248
+ console.log(" claude - Claude Code /spets skill (project-level)");
245
249
  console.log(" codex - Codex CLI $spets skill (project-level)");
246
250
  console.log(" gemini - Gemini CLI spets skill (project-level)");
247
251
  console.log("");
248
- const claudeSkillPath = join(homedir(), ".claude", "commands", "spets.md");
252
+ const claudeProjectPath = join(process.cwd(), ".claude", "commands", "spets.md");
253
+ const claudeGlobalPath = join(homedir(), ".claude", "commands", "spets.md");
249
254
  const claudeLegacySkillPath = join(homedir(), ".claude", "commands", "sdd-do.md");
250
- const claudeInstalled = existsSync(claudeSkillPath) || existsSync(claudeLegacySkillPath);
255
+ const claudeInstalled = existsSync(claudeProjectPath) || existsSync(claudeGlobalPath) || existsSync(claudeLegacySkillPath);
251
256
  const codexProjectPath = join(process.cwd(), ".codex", "skills", "spets", "SKILL.md");
252
257
  const codexGlobalPath = join(homedir(), ".codex", "skills", "spets", "SKILL.md");
253
258
  const codexInstalled = existsSync(codexProjectPath) || existsSync(codexGlobalPath);
@@ -259,7 +264,8 @@ async function listPlugins() {
259
264
  const geminiLocation = existsSync(geminiProjectPath) ? "project" : existsSync(geminiLegacyCommandPath) ? "project" : existsSync(geminiLegacyGlobalPath) ? "global" : null;
260
265
  console.log("Installed:");
261
266
  const installed = [];
262
- if (claudeInstalled) installed.push("claude (global)");
267
+ const claudeLocation = existsSync(claudeProjectPath) ? "project" : existsSync(claudeGlobalPath) ? "global" : "legacy";
268
+ if (claudeInstalled) installed.push(`claude (${claudeLocation})`);
263
269
  if (codexInstalled) installed.push(`codex (${codexLocation})`);
264
270
  if (geminiInstalled) installed.push(`gemini (${geminiLocation})`);
265
271
  if (installed.length > 0) {
@@ -273,62 +279,37 @@ async function listPlugins() {
273
279
  function getClaudeSkillContent() {
274
280
  return `# Spets Executor
275
281
 
276
- You execute spets orchestrator commands. Parse JSON, follow instructions, repeat.
282
+ You execute spets workflow commands. Follow orchestrator instructions exactly.
277
283
 
278
284
  ## Startup
279
285
 
280
286
  IF \`$ARGUMENTS\` starts with "resume":
281
- 1. RUN \`npx spets orchestrate resume\`
287
+ RUN \`npx spets orchestrate resume\`
288
+ ELSE IF \`$ARGUMENTS\` starts with "list":
289
+ RUN \`npx spets orchestrate list\`
282
290
  ELSE:
283
- 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
284
-
285
- Then GOTO **Loop**.
291
+ RUN \`npx spets orchestrate init "$ARGUMENTS"\`
286
292
 
287
293
  ## Loop
288
294
 
289
- 1. PARSE JSON response
290
- 2. SWITCH on \`type\`:
291
-
292
- ### type="phase"
293
- - EXECUTE what \`prompt\` says
294
- - RUN \`onComplete\` with your output as JSON argument
295
- - GOTO Loop
296
-
297
- ### type="checkpoint", checkpoint="clarify"
298
- - ASK user each decision in \`decisions[]\` using AskUserQuestion
299
- - Format each decision as a question with its options
300
- - RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
301
- - GOTO Loop
302
-
303
- ### type="checkpoint", checkpoint="approve"
304
- - READ \`specPath\`, summarize key points to user
305
- - ASK user using AskUserQuestion with options: Approve / Revise / Reject / Stop
306
- - RUN matching \`onComplete\` based on user's choice
307
- - GOTO Loop
295
+ 1. Parse the JSON response
296
+ 2. Read the \`instructions\` field
297
+ 3. Follow the instructions exactly
298
+ 4. Repeat until the response says to stop
308
299
 
309
- ### type="checkpoint", checkpoint="knowledge"
310
- - Show \`suggestedKnowledge[]\` to user
311
- - ASK user if they want to save, modify, or skip
312
- - If save: RUN \`onComplete\` with entries JSON
313
- - If skip: RUN \`onSkip\`
314
- - GOTO Loop
300
+ ## Rules
315
301
 
316
- ### type="list"
317
- - Show \`tasks[]\` to user with taskId, description, status, currentStep
318
- - ASK user which task to resume
319
- - RUN \`npx spets orchestrate resume <selectedTaskId>\`
320
- - GOTO Loop
321
-
322
- ### type="complete" or "error"
323
- - PRINT message
324
- - STOP
302
+ - NEVER skip or modify orchestrator commands
303
+ - NEVER improvise steps \u2014 only do what instructions say
304
+ - Always pass JSON output as a single-quoted string argument
305
+ - Minify JSON when passing as command arguments
325
306
 
326
307
  ## Forbidden
327
308
 
328
309
  EnterPlanMode, TaskCreate, TaskUpdate
329
310
 
330
311
  $ARGUMENTS
331
- description: Task description for the workflow (or "resume" to continue a previous workflow)
312
+ description: Task description for the workflow (or "resume" to list/continue previous workflows)
332
313
  `;
333
314
  }
334
315
  function getCodexSkillContent() {
@@ -339,65 +320,37 @@ description: SDD workflow executor - orchestrator-controlled spec-driven develop
339
320
 
340
321
  # Spets Executor
341
322
 
342
- You execute spets orchestrator commands. Parse JSON, follow instructions, repeat.
323
+ You execute spets workflow commands. Follow orchestrator instructions exactly.
343
324
 
344
325
  ## Startup
345
326
 
346
327
  IF \`$ARGUMENTS\` starts with "resume":
347
- 1. RUN \`npx spets orchestrate resume\`
328
+ RUN \`npx spets orchestrate resume\`
329
+ ELSE IF \`$ARGUMENTS\` starts with "list":
330
+ RUN \`npx spets orchestrate list\`
348
331
  ELSE:
349
- 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
350
-
351
- Then GOTO **Loop**.
332
+ RUN \`npx spets orchestrate init "$ARGUMENTS"\`
352
333
 
353
334
  ## Loop
354
335
 
355
- 1. PARSE JSON response
356
- 2. SWITCH on \`type\`:
357
-
358
- ### type="phase"
359
- - EXECUTE what \`prompt\` says
360
- - RUN \`onComplete\` with your output as minified JSON argument
361
- - GOTO Loop
362
-
363
- ### type="checkpoint", checkpoint="clarify"
364
- - FORMAT decisions as table for user:
365
- | # | Decision | Context | Options |
366
- |---|----------|---------|---------|
367
- | d1 | ... | ... | 1. ... 2. ... |
368
- - ASK user to pick an option for each decision
369
- - RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
370
- - GOTO Loop
371
-
372
- ### type="checkpoint", checkpoint="approve"
373
- - READ \`specPath\`, summarize key points to user
374
- - ASK user with options: Approve / Revise / Reject / Stop
375
- - RUN matching \`onComplete\` based on user's choice
376
- - GOTO Loop
377
-
378
- ### type="checkpoint", checkpoint="knowledge"
379
- - Show \`suggestedKnowledge[]\` to user
380
- - ASK user if they want to save, modify, or skip
381
- - If save: RUN \`onComplete\` with entries JSON
382
- - If skip: RUN \`onSkip\`
383
- - GOTO Loop
336
+ 1. Parse the JSON response
337
+ 2. Read the \`instructions\` field
338
+ 3. Follow the instructions exactly
339
+ 4. Repeat until the response says to stop
384
340
 
385
- ### type="list"
386
- - Show \`tasks[]\` to user with taskId, description, status, currentStep
387
- - ASK user which task to resume
388
- - RUN \`npx spets orchestrate resume <selectedTaskId>\`
389
- - GOTO Loop
341
+ ## Rules
390
342
 
391
- ### type="complete" or "error"
392
- - PRINT message
393
- - STOP
343
+ - NEVER skip or modify orchestrator commands
344
+ - NEVER improvise steps \u2014 only do what instructions say
345
+ - Always pass JSON output as a single-quoted string argument
346
+ - Minify JSON when passing as command arguments
394
347
 
395
348
  ## Forbidden
396
349
 
397
350
  Planning mode, task tracking tools
398
351
 
399
352
  $ARGUMENTS
400
- description: Task description for the workflow (or "resume" to continue a previous workflow)
353
+ description: Task description for the workflow (or "resume" to list/continue previous workflows)
401
354
  `;
402
355
  }
403
356
  function getGeminiSkillContent() {
@@ -408,61 +361,37 @@ description: SDD workflow executor - orchestrator-controlled spec-driven develop
408
361
 
409
362
  # Spets Executor
410
363
 
411
- You execute spets orchestrator commands. Parse JSON, follow instructions, repeat.
364
+ You execute spets workflow commands. Follow orchestrator instructions exactly.
412
365
 
413
366
  ## Startup
414
367
 
415
368
  IF \`$ARGUMENTS\` starts with "resume":
416
- 1. RUN \`npx spets orchestrate resume\`
369
+ RUN \`npx spets orchestrate resume\`
370
+ ELSE IF \`$ARGUMENTS\` starts with "list":
371
+ RUN \`npx spets orchestrate list\`
417
372
  ELSE:
418
- 1. RUN \`npx spets orchestrate init "$ARGUMENTS"\`
419
-
420
- Then GOTO **Loop**.
373
+ RUN \`npx spets orchestrate init "$ARGUMENTS"\`
421
374
 
422
375
  ## Loop
423
376
 
424
- 1. PARSE JSON response
425
- 2. SWITCH on \`type\`:
426
-
427
- ### type="phase"
428
- - EXECUTE what \`prompt\` says
429
- - RUN \`onComplete\` with your output as JSON argument
430
- - GOTO Loop
431
-
432
- ### type="checkpoint", checkpoint="clarify"
433
- - ASK user each decision in \`decisions[]\`
434
- - RUN \`onComplete\` with \`[{decisionId, selectedOptionId}, ...]\`
435
- - GOTO Loop
377
+ 1. Parse the JSON response
378
+ 2. Read the \`instructions\` field
379
+ 3. Follow the instructions exactly
380
+ 4. Repeat until the response says to stop
436
381
 
437
- ### type="checkpoint", checkpoint="approve"
438
- - READ \`specPath\`, summarize key points to user
439
- - ASK user with options: Approve / Revise / Reject / Stop
440
- - RUN matching \`onComplete\` based on user's choice
441
- - GOTO Loop
382
+ ## Rules
442
383
 
443
- ### type="checkpoint", checkpoint="knowledge"
444
- - Show \`suggestedKnowledge[]\` to user
445
- - ASK user if they want to save, modify, or skip
446
- - If save: RUN \`onComplete\` with entries JSON
447
- - If skip: RUN \`onSkip\`
448
- - GOTO Loop
449
-
450
- ### type="list"
451
- - Show \`tasks[]\` to user with taskId, description, status, currentStep
452
- - ASK user which task to resume
453
- - RUN \`npx spets orchestrate resume <selectedTaskId>\`
454
- - GOTO Loop
455
-
456
- ### type="complete" or "error"
457
- - PRINT message
458
- - STOP
384
+ - NEVER skip or modify orchestrator commands
385
+ - NEVER improvise steps \u2014 only do what instructions say
386
+ - Always pass JSON output as a single-quoted string argument
387
+ - Minify JSON when passing as command arguments
459
388
 
460
389
  ## Forbidden
461
390
 
462
391
  Planning mode, task tracking tools
463
392
 
464
393
  $ARGUMENTS
465
- description: Task description for the workflow (or "resume" to continue a previous workflow)
394
+ description: Task description for the workflow (or "resume" to list/continue previous workflows)
466
395
  `;
467
396
  }
468
397
 
@@ -504,19 +433,26 @@ async function initCommand(options) {
504
433
  const hookTemplate = join2(__dirname, "..", "templates", "hooks", "cleanup-branch.sh");
505
434
  if (existsSync2(hookTemplate)) {
506
435
  const hookDest = join2(spetsDir, "hooks", "cleanup-branch.sh");
507
- cpSync(hookTemplate, hookDest);
508
- try {
509
- execSync(`chmod +x "${hookDest}"`);
510
- } catch {
436
+ if (!existsSync2(hookDest)) {
437
+ cpSync(hookTemplate, hookDest);
438
+ try {
439
+ execSync(`chmod +x "${hookDest}"`);
440
+ } catch {
441
+ }
511
442
  }
512
443
  }
513
444
  const knowledgeGuideTemplate = join2(__dirname, "..", "templates", "knowledge", "guide.md");
514
445
  if (existsSync2(knowledgeGuideTemplate)) {
515
446
  const guideDest = join2(spetsDir, "knowledge", "guide.md");
516
- cpSync(knowledgeGuideTemplate, guideDest);
447
+ if (!existsSync2(guideDest)) {
448
+ cpSync(knowledgeGuideTemplate, guideDest);
449
+ }
517
450
  }
518
451
  const githubInfo = getGitHubInfoFromRemote();
519
- writeFileSync2(join2(spetsDir, "config.yml"), getDefaultConfig(githubInfo));
452
+ const configPath = join2(spetsDir, "config.yml");
453
+ if (!existsSync2(configPath)) {
454
+ writeFileSync2(configPath, getDefaultConfig(githubInfo));
455
+ }
520
456
  createDefaultSteps(spetsDir);
521
457
  createClaudeCommand(cwd);
522
458
  printEnhancedInitOutput(options);
@@ -740,20 +676,23 @@ async function runInteractiveSetup(cwd, spetsDir, options) {
740
676
  const hookTemplate = join2(__dirname, "..", "templates", "hooks", "cleanup-branch.sh");
741
677
  if (existsSync2(hookTemplate)) {
742
678
  const hookDest = join2(spetsDir, "hooks", "cleanup-branch.sh");
743
- cpSync(hookTemplate, hookDest);
744
- try {
745
- execSync(`chmod +x "${hookDest}"`);
746
- } catch {
679
+ if (!existsSync2(hookDest)) {
680
+ cpSync(hookTemplate, hookDest);
681
+ try {
682
+ execSync(`chmod +x "${hookDest}"`);
683
+ } catch {
684
+ }
747
685
  }
748
686
  }
749
687
  const knowledgeGuideTemplate = join2(__dirname, "..", "templates", "knowledge", "guide.md");
750
- if (existsSync2(knowledgeGuideTemplate)) {
751
- cpSync(knowledgeGuideTemplate, join2(spetsDir, "knowledge", "guide.md"));
688
+ const guideDest = join2(spetsDir, "knowledge", "guide.md");
689
+ if (existsSync2(knowledgeGuideTemplate) && !existsSync2(guideDest)) {
690
+ cpSync(knowledgeGuideTemplate, guideDest);
691
+ }
692
+ const configPath = join2(spetsDir, "config.yml");
693
+ if (!existsSync2(configPath)) {
694
+ writeFileSync2(configPath, getDefaultConfig(githubInfo, { agent, githubEnabled }));
752
695
  }
753
- writeFileSync2(
754
- join2(spetsDir, "config.yml"),
755
- getDefaultConfig(githubInfo, { agent, githubEnabled })
756
- );
757
696
  createDefaultSteps(spetsDir);
758
697
  createClaudeCommand(cwd);
759
698
  if (githubEnabled && githubInfo) {
@@ -765,10 +704,16 @@ async function runInteractiveSetup(cwd, spetsDir, options) {
765
704
  function createDefaultSteps(spetsDir) {
766
705
  const planDir = join2(spetsDir, "steps", "01-plan");
767
706
  mkdirSync2(planDir, { recursive: true });
768
- writeFileSync2(join2(planDir, "template.md"), getPlanTemplate());
707
+ const planTemplatePath = join2(planDir, "template.md");
708
+ if (!existsSync2(planTemplatePath)) {
709
+ writeFileSync2(planTemplatePath, getPlanTemplate());
710
+ }
769
711
  const implementDir = join2(spetsDir, "steps", "02-implement");
770
712
  mkdirSync2(implementDir, { recursive: true });
771
- writeFileSync2(join2(implementDir, "template.md"), getImplementTemplate());
713
+ const implementTemplatePath = join2(implementDir, "template.md");
714
+ if (!existsSync2(implementTemplatePath)) {
715
+ writeFileSync2(implementTemplatePath, getImplementTemplate());
716
+ }
772
717
  }
773
718
  function getPlanTemplate() {
774
719
  const fullTemplate = readFileSync(join2(__dirname, "..", "templates", "steps", "01-plan", "template.md"), "utf-8");
@@ -1753,6 +1698,36 @@ function buildKnowledgeExtractPrompt(params) {
1753
1698
  return parts.join("\n");
1754
1699
  }
1755
1700
 
1701
+ // src/orchestrator/instructions.ts
1702
+ function phaseWithJsonOutput(onComplete) {
1703
+ return `Execute the prompt. Then run:
1704
+ ${onComplete} '<your_json_output>'`;
1705
+ }
1706
+ function phaseExecute(outputFile, onComplete) {
1707
+ return `Execute the prompt \u2014 write the document to ${outputFile}. Then run:
1708
+ ${onComplete}`;
1709
+ }
1710
+ function checkpointClarify(onComplete) {
1711
+ return [
1712
+ `Present each decision to the user with its options. Collect their choices. Then run:`,
1713
+ ` ${onComplete} '<answers_json>'`,
1714
+ `Answer format: [{decisionId, selectedOptionId, customInput?}, ...]`
1715
+ ].join("\n");
1716
+ }
1717
+ function checkpointApprove(specPath, cmds) {
1718
+ return [
1719
+ `Read the document at ${specPath}. Summarize key points to the user. Ask: Approve / Revise / Reject / Stop. Then run the matching command:`,
1720
+ ` approve: ${cmds.approve}`,
1721
+ ` revise: ${cmds.revise}`,
1722
+ ` reject: ${cmds.reject}`,
1723
+ ` stop: ${cmds.stop}`
1724
+ ].join("\n");
1725
+ }
1726
+ var PRINT_MESSAGE_AND_STOP = "Print the message. Stop.";
1727
+ var PRINT_ERROR_AND_STOP = "Print the error. Stop.";
1728
+ var LIST_TASKS = "Show tasks to user. Ask which to resume. Run:\n npx spets orchestrate resume <selectedTaskId>";
1729
+ var LIST_EMPTY = "No resumable tasks found. Show this to the user. Stop.";
1730
+
1756
1731
  // src/orchestrator/responses.ts
1757
1732
  function buildPhaseExploreResponse(cwd, state) {
1758
1733
  const steps = getSteps(cwd);
@@ -1774,6 +1749,7 @@ function buildPhaseExploreResponse(cwd, state) {
1774
1749
  previousOutput,
1775
1750
  cwd
1776
1751
  });
1752
+ const onComplete = `npx spets orchestrate explore-done ${state.taskId}`;
1777
1753
  return {
1778
1754
  type: "phase",
1779
1755
  phase: "explore",
@@ -1786,7 +1762,8 @@ function buildPhaseExploreResponse(cwd, state) {
1786
1762
  context: {
1787
1763
  previousOutput
1788
1764
  },
1789
- onComplete: `npx spets orchestrate explore-done ${state.taskId}`
1765
+ onComplete,
1766
+ instructions: phaseWithJsonOutput(onComplete)
1790
1767
  };
1791
1768
  }
1792
1769
  function buildPhaseClarifyResponse(cwd, state) {
@@ -1801,6 +1778,7 @@ function buildPhaseClarifyResponse(cwd, state) {
1801
1778
  // Legacy support
1802
1779
  cwd
1803
1780
  });
1781
+ const onComplete = `npx spets orchestrate clarify-done ${state.taskId}`;
1804
1782
  return {
1805
1783
  type: "phase",
1806
1784
  phase: "clarify",
@@ -1812,7 +1790,8 @@ function buildPhaseClarifyResponse(cwd, state) {
1812
1790
  previousDecisions: state.decisionHistory,
1813
1791
  previousQA: state.qaHistory,
1814
1792
  // Legacy support
1815
- onComplete: `npx spets orchestrate clarify-done ${state.taskId}`
1793
+ onComplete,
1794
+ instructions: phaseWithJsonOutput(onComplete)
1816
1795
  };
1817
1796
  }
1818
1797
  function buildPhaseExecuteResponse(cwd, state) {
@@ -1855,6 +1834,8 @@ ${issues}`;
1855
1834
  verifyFeedback,
1856
1835
  cwd
1857
1836
  });
1837
+ const onComplete = `npx spets orchestrate execute-done ${state.taskId}`;
1838
+ const outputFile = join9(outputPath, state.taskId, `${state.currentStep}.md`);
1858
1839
  return {
1859
1840
  type: "phase",
1860
1841
  phase: "execute",
@@ -1869,11 +1850,12 @@ ${issues}`;
1869
1850
  context: {
1870
1851
  template: hasTemplate ? templatePath : void 0,
1871
1852
  previousOutput,
1872
- output: join9(outputPath, state.taskId, `${state.currentStep}.md`),
1853
+ output: outputFile,
1873
1854
  revisionFeedback: state.revisionFeedback,
1874
1855
  verifyFeedback
1875
1856
  },
1876
- onComplete: `npx spets orchestrate execute-done ${state.taskId}`
1857
+ onComplete,
1858
+ instructions: phaseExecute(outputFile, onComplete)
1877
1859
  };
1878
1860
  }
1879
1861
  function buildPhaseVerifyResponse(cwd, state) {
@@ -1892,6 +1874,7 @@ function buildPhaseVerifyResponse(cwd, state) {
1892
1874
  loadedKnowledge: state.loadedKnowledge?.map((k) => ({ filename: k.filename, content: k.content })),
1893
1875
  cwd
1894
1876
  });
1877
+ const onComplete = `npx spets orchestrate verify-done ${state.taskId}`;
1895
1878
  return {
1896
1879
  type: "phase",
1897
1880
  phase: "verify",
@@ -1907,7 +1890,8 @@ function buildPhaseVerifyResponse(cwd, state) {
1907
1890
  template: hasTemplate ? templatePath : void 0,
1908
1891
  document: documentPath
1909
1892
  },
1910
- onComplete: `npx spets orchestrate verify-done ${state.taskId}`
1893
+ onComplete,
1894
+ instructions: phaseWithJsonOutput(onComplete)
1911
1895
  };
1912
1896
  }
1913
1897
  function buildPhaseKnowledgeResponse(cwd, state) {
@@ -1920,6 +1904,7 @@ function buildPhaseKnowledgeResponse(cwd, state) {
1920
1904
  guide,
1921
1905
  cwd
1922
1906
  });
1907
+ const onComplete = `npx spets orchestrate knowledge-extract-done ${state.taskId}`;
1923
1908
  return {
1924
1909
  type: "phase",
1925
1910
  phase: "knowledge",
@@ -1932,21 +1917,31 @@ function buildPhaseKnowledgeResponse(cwd, state) {
1932
1917
  totalSteps: state.totalSteps
1933
1918
  },
1934
1919
  guide,
1935
- onComplete: `npx spets orchestrate knowledge-extract-done ${state.taskId}`
1920
+ onComplete,
1921
+ instructions: phaseWithJsonOutput(onComplete)
1936
1922
  };
1937
1923
  }
1938
1924
  function buildCheckpointClarifyResponse(state) {
1925
+ const onComplete = `npx spets orchestrate clarified ${state.taskId}`;
1939
1926
  return {
1940
1927
  type: "checkpoint",
1941
1928
  checkpoint: "clarify",
1942
1929
  taskId: state.taskId,
1943
1930
  step: state.currentStep,
1944
1931
  decisions: state.decisions || [],
1945
- onComplete: `npx spets orchestrate clarified ${state.taskId} '<answers_json>'`
1932
+ onComplete: `${onComplete} '<answers_json>'`,
1933
+ instructions: checkpointClarify(onComplete)
1946
1934
  };
1947
1935
  }
1948
1936
  function buildCheckpointApproveResponse(cwd, state) {
1949
1937
  const outputPath = getOutputPath(cwd);
1938
+ const specPath = join9(outputPath, state.taskId, `${state.currentStep}.md`);
1939
+ const cmds = {
1940
+ approve: `npx spets orchestrate approve ${state.taskId}`,
1941
+ revise: `npx spets orchestrate revise ${state.taskId} '<feedback>'`,
1942
+ reject: `npx spets orchestrate reject ${state.taskId}`,
1943
+ stop: `npx spets orchestrate stop ${state.taskId}`
1944
+ };
1950
1945
  return {
1951
1946
  type: "checkpoint",
1952
1947
  checkpoint: "approve",
@@ -1954,14 +1949,10 @@ function buildCheckpointApproveResponse(cwd, state) {
1954
1949
  step: state.currentStep,
1955
1950
  stepIndex: state.stepIndex,
1956
1951
  totalSteps: state.totalSteps,
1957
- specPath: join9(outputPath, state.taskId, `${state.currentStep}.md`),
1952
+ specPath,
1958
1953
  options: ["approve", "revise", "reject", "stop"],
1959
- onComplete: {
1960
- approve: `npx spets orchestrate approve ${state.taskId}`,
1961
- revise: `npx spets orchestrate revise ${state.taskId} '<feedback>'`,
1962
- reject: `npx spets orchestrate reject ${state.taskId}`,
1963
- stop: `npx spets orchestrate stop ${state.taskId}`
1964
- }
1954
+ onComplete: cmds,
1955
+ instructions: checkpointApprove(specPath, cmds)
1965
1956
  };
1966
1957
  }
1967
1958
  function buildCompleteResponse(cwd, state, status) {
@@ -1984,11 +1975,12 @@ function buildCompleteResponse(cwd, state, status) {
1984
1975
  status,
1985
1976
  taskId: state.taskId,
1986
1977
  outputs,
1987
- message: messages[status]
1978
+ message: messages[status],
1979
+ instructions: PRINT_MESSAGE_AND_STOP
1988
1980
  };
1989
1981
  }
1990
1982
  function buildErrorResponse(error, taskId, step) {
1991
- const response = { type: "error", error };
1983
+ const response = { type: "error", error, instructions: PRINT_ERROR_AND_STOP };
1992
1984
  if (taskId) response.taskId = taskId;
1993
1985
  if (step) response.step = step;
1994
1986
  return response;
@@ -2330,7 +2322,7 @@ var Orchestrator = class {
2330
2322
  const outputPath = getOutputPath(this.cwd);
2331
2323
  const tasks = [];
2332
2324
  if (!existsSync11(outputPath)) {
2333
- return { type: "list", tasks: [] };
2325
+ return { type: "list", tasks: [], instructions: LIST_EMPTY };
2334
2326
  }
2335
2327
  const dirs = readdirSync2(outputPath, { withFileTypes: true }).filter((d) => d.isDirectory());
2336
2328
  for (const dir of dirs) {
@@ -2352,7 +2344,11 @@ var Orchestrator = class {
2352
2344
  const bTime = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
2353
2345
  return bTime - aTime;
2354
2346
  });
2355
- return { type: "list", tasks };
2347
+ return {
2348
+ type: "list",
2349
+ tasks,
2350
+ instructions: tasks.length > 0 ? LIST_TASKS : LIST_EMPTY
2351
+ };
2356
2352
  }
2357
2353
  /**
2358
2354
  * Get current workflow status
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spets",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Spec Driven Development Execution Framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",