claude-all-hands 1.0.1 → 1.0.2

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 (160) hide show
  1. package/.claude/agents/code-simplifier.md +52 -0
  2. package/.claude/agents/curator.md +189 -245
  3. package/.claude/agents/documentor.md +147 -0
  4. package/.claude/agents/planner.md +123 -166
  5. package/.claude/agents/researcher.md +58 -41
  6. package/.claude/agents/surveyor.md +81 -0
  7. package/.claude/agents/worker.md +74 -0
  8. package/.claude/commands/audit-docs.md +94 -0
  9. package/.claude/commands/continue.md +120 -0
  10. package/.claude/commands/create-docs.md +100 -0
  11. package/.claude/commands/create-skill.md +107 -0
  12. package/.claude/commands/create-specialist.md +111 -0
  13. package/.claude/commands/curator-audit.md +4 -0
  14. package/.claude/commands/debug.md +183 -0
  15. package/.claude/commands/plan.md +199 -102
  16. package/.claude/commands/validate.md +11 -0
  17. package/.claude/commands/whats-next.md +106 -134
  18. package/.claude/envoy/envoy +11 -14
  19. package/.claude/envoy/package-lock.json +1388 -0
  20. package/.claude/envoy/package.json +29 -0
  21. package/.claude/envoy/src/cli.ts +126 -0
  22. package/.claude/envoy/src/commands/base.ts +216 -0
  23. package/.claude/envoy/src/commands/gemini.ts +999 -0
  24. package/.claude/envoy/src/commands/git.ts +639 -0
  25. package/.claude/envoy/src/commands/index.ts +73 -0
  26. package/.claude/envoy/src/commands/knowledge.ts +187 -0
  27. package/.claude/envoy/src/commands/perplexity.ts +129 -0
  28. package/.claude/envoy/src/commands/plan/core.ts +134 -0
  29. package/.claude/envoy/src/commands/plan/findings.ts +446 -0
  30. package/.claude/envoy/src/commands/plan/gates.ts +672 -0
  31. package/.claude/envoy/src/commands/plan/index.ts +135 -0
  32. package/.claude/envoy/src/commands/plan/lifecycle.ts +648 -0
  33. package/.claude/envoy/src/commands/plan/plan-file.ts +138 -0
  34. package/.claude/envoy/src/commands/plan/prompts.ts +285 -0
  35. package/.claude/envoy/src/commands/plan/protocols.ts +166 -0
  36. package/.claude/envoy/src/commands/repomix.ts +99 -0
  37. package/.claude/envoy/src/commands/tavily.ts +220 -0
  38. package/.claude/envoy/src/commands/xai.ts +168 -0
  39. package/.claude/envoy/src/lib/design.ts +41 -0
  40. package/.claude/envoy/src/lib/feedback-schemas.ts +154 -0
  41. package/.claude/envoy/src/lib/findings.ts +215 -0
  42. package/.claude/envoy/src/lib/gates.ts +572 -0
  43. package/.claude/envoy/src/lib/git.ts +132 -0
  44. package/.claude/envoy/src/lib/index.ts +188 -0
  45. package/.claude/envoy/src/lib/knowledge.ts +594 -0
  46. package/.claude/envoy/src/lib/markdown.ts +75 -0
  47. package/.claude/envoy/src/lib/observability.ts +262 -0
  48. package/.claude/envoy/src/lib/paths.ts +130 -0
  49. package/.claude/envoy/src/lib/plan-io.ts +117 -0
  50. package/.claude/envoy/src/lib/prompts.ts +231 -0
  51. package/.claude/envoy/src/lib/protocols.ts +314 -0
  52. package/.claude/envoy/src/lib/repomix.ts +133 -0
  53. package/.claude/envoy/src/lib/retry.ts +138 -0
  54. package/.claude/envoy/src/lib/watcher.ts +167 -0
  55. package/.claude/envoy/tsconfig.json +21 -0
  56. package/.claude/hooks/scripts/scan_agents.py +62 -0
  57. package/.claude/hooks/scripts/scan_commands.py +50 -0
  58. package/.claude/hooks/scripts/scan_skills.py +46 -70
  59. package/.claude/hooks/scripts/validate_artifacts.py +128 -0
  60. package/.claude/hooks/startup.sh +26 -24
  61. package/.claude/protocols/bug-discovery.yaml +55 -0
  62. package/.claude/protocols/debugging.yaml +51 -0
  63. package/.claude/protocols/discovery.yaml +53 -0
  64. package/.claude/protocols/implementation.yaml +84 -0
  65. package/.claude/settings.json +37 -97
  66. package/.claude/skills/brainstorming/SKILL.md +54 -0
  67. package/.claude/skills/commands-development/SKILL.md +630 -0
  68. package/.claude/skills/commands-development/references/arguments.md +252 -0
  69. package/.claude/skills/commands-development/references/patterns.md +796 -0
  70. package/.claude/skills/commands-development/references/tool-restrictions.md +376 -0
  71. package/.claude/skills/discovery-mode/SKILL.md +108 -0
  72. package/.claude/skills/hooks-development/SKILL.md +332 -0
  73. package/.claude/skills/hooks-development/references/command-vs-prompt.md +269 -0
  74. package/.claude/skills/hooks-development/references/examples.md +658 -0
  75. package/.claude/skills/hooks-development/references/hook-types.md +463 -0
  76. package/.claude/skills/hooks-development/references/input-output-schemas.md +469 -0
  77. package/.claude/skills/hooks-development/references/matchers.md +470 -0
  78. package/.claude/skills/hooks-development/references/troubleshooting.md +587 -0
  79. package/.claude/skills/implementation-mode/SKILL.md +171 -0
  80. package/.claude/skills/research-tools/SKILL.md +35 -33
  81. package/.claude/skills/skills-development/SKILL.md +192 -0
  82. package/.claude/skills/skills-development/references/api-security.md +226 -0
  83. package/.claude/skills/skills-development/references/be-clear-and-direct.md +531 -0
  84. package/.claude/skills/skills-development/references/common-patterns.md +595 -0
  85. package/.claude/skills/skills-development/references/core-principles.md +437 -0
  86. package/.claude/skills/skills-development/references/executable-code.md +175 -0
  87. package/.claude/skills/skills-development/references/iteration-and-testing.md +474 -0
  88. package/.claude/skills/skills-development/references/recommended-structure.md +168 -0
  89. package/.claude/skills/skills-development/references/skill-structure.md +372 -0
  90. package/.claude/skills/skills-development/references/use-xml-tags.md +466 -0
  91. package/.claude/skills/skills-development/references/using-scripts.md +113 -0
  92. package/.claude/skills/skills-development/references/using-templates.md +112 -0
  93. package/.claude/skills/skills-development/references/workflows-and-validation.md +510 -0
  94. package/.claude/skills/skills-development/templates/router-skill.md +73 -0
  95. package/.claude/skills/skills-development/templates/simple-skill.md +33 -0
  96. package/.claude/skills/skills-development/workflows/add-reference.md +96 -0
  97. package/.claude/skills/skills-development/workflows/add-script.md +93 -0
  98. package/.claude/skills/skills-development/workflows/add-template.md +74 -0
  99. package/.claude/skills/skills-development/workflows/add-workflow.md +120 -0
  100. package/.claude/skills/skills-development/workflows/audit-skill.md +138 -0
  101. package/.claude/skills/skills-development/workflows/create-domain-expertise-skill.md +605 -0
  102. package/.claude/skills/skills-development/workflows/create-new-skill.md +191 -0
  103. package/.claude/skills/skills-development/workflows/get-guidance.md +121 -0
  104. package/.claude/skills/skills-development/workflows/upgrade-to-router.md +161 -0
  105. package/.claude/skills/skills-development/workflows/verify-skill.md +204 -0
  106. package/.claude/skills/subagents-development/SKILL.md +325 -0
  107. package/.claude/skills/subagents-development/references/context-management.md +567 -0
  108. package/.claude/skills/subagents-development/references/debugging-agents.md +714 -0
  109. package/.claude/skills/subagents-development/references/error-handling-and-recovery.md +502 -0
  110. package/.claude/skills/subagents-development/references/evaluation-and-testing.md +374 -0
  111. package/.claude/skills/subagents-development/references/orchestration-patterns.md +591 -0
  112. package/.claude/skills/subagents-development/references/subagents.md +508 -0
  113. package/.claude/skills/subagents-development/references/writing-subagent-prompts.md +517 -0
  114. package/.claude/statusline.sh +24 -0
  115. package/bin/cli.js +110 -72
  116. package/package.json +1 -1
  117. package/.claude/agents/explorer.md +0 -62
  118. package/.claude/agents/parallel-worker.md +0 -121
  119. package/.claude/commands/curation-fix.md +0 -92
  120. package/.claude/commands/new-branch.md +0 -36
  121. package/.claude/commands/parallel-discovery.md +0 -69
  122. package/.claude/commands/parallel-orchestration.md +0 -99
  123. package/.claude/commands/plan-checkpoint.md +0 -37
  124. package/.claude/envoy/commands/__init__.py +0 -1
  125. package/.claude/envoy/commands/base.py +0 -95
  126. package/.claude/envoy/commands/parallel.py +0 -439
  127. package/.claude/envoy/commands/perplexity.py +0 -86
  128. package/.claude/envoy/commands/plans.py +0 -451
  129. package/.claude/envoy/commands/tavily.py +0 -156
  130. package/.claude/envoy/commands/vertex.py +0 -358
  131. package/.claude/envoy/commands/xai.py +0 -124
  132. package/.claude/envoy/envoy.py +0 -122
  133. package/.claude/envoy/pyrightconfig.json +0 -4
  134. package/.claude/envoy/requirements.txt +0 -2
  135. package/.claude/hooks/capture-queries.sh +0 -3
  136. package/.claude/hooks/scripts/enforce_planning.py +0 -118
  137. package/.claude/hooks/scripts/enforce_rg.py +0 -34
  138. package/.claude/hooks/scripts/validate_skill.py +0 -81
  139. package/.claude/skills/claude-envoy-curation/SKILL.md +0 -162
  140. package/.claude/skills/claude-envoy-usage/SKILL.md +0 -46
  141. package/.claude/skills/command-development/SKILL.md +0 -206
  142. package/.claude/skills/command-development/examples/simple-commands.md +0 -212
  143. package/.claude/skills/command-development/references/frontmatter-reference.md +0 -221
  144. package/.claude/skills/hook-development/SKILL.md +0 -127
  145. package/.claude/skills/hook-development/examples/command-hooks.md +0 -301
  146. package/.claude/skills/hook-development/examples/prompt-hooks.md +0 -114
  147. package/.claude/skills/hook-development/references/event-reference.md +0 -226
  148. package/.claude/skills/repomix-extraction/SKILL.md +0 -91
  149. package/.claude/skills/skill-development/SKILL.md +0 -168
  150. package/.claude/skills/skill-development/examples/complete-skill-examples.md +0 -281
  151. package/.claude/skills/skill-development/references/progressive-disclosure.md +0 -141
  152. package/.claude/skills/skill-development/references/writing-style.md +0 -180
  153. package/.claude/skills/skill-development/scripts/validate-skill.sh +0 -144
  154. package/.claude/skills/specialist-builder/SKILL.md +0 -327
  155. package/.claude/skills/specialist-builder/docs/agent-catalog.md +0 -28
  156. package/.claude/skills/specialist-builder/examples/complete-agent-examples.md +0 -206
  157. package/.claude/skills/specialist-builder/references/system-prompt-patterns.md +0 -281
  158. package/.claude/skills/specialist-builder/references/triggering-examples.md +0 -162
  159. package/.claude/skills/specialist-builder/scripts/validate-agent.sh +0 -137
  160. /package/.claude/{envoy/claude-envoy.py → skills/claude-envoy-patterns/SKILL.md} +0 -0
@@ -0,0 +1,648 @@
1
+ /**
2
+ * Prompt lifecycle commands: next, start-prompt, record-implementation, complete-prompt, etc.
3
+ */
4
+
5
+ import { execSync, spawnSync } from "child_process";
6
+ import { Command } from "commander";
7
+ import { GoogleGenAI } from "@google/genai";
8
+ import type { PromptFrontMatter } from "../../lib/index.js";
9
+ import {
10
+ getBaseBranch,
11
+ getBranch,
12
+ getDiff,
13
+ getPromptId,
14
+ planExists,
15
+ readAllPrompts,
16
+ readPlan,
17
+ readPrompt,
18
+ readUserInput,
19
+ updatePlanStage,
20
+ writePrompt,
21
+ writeSummary,
22
+ } from "../../lib/index.js";
23
+ import { BaseCommand, CommandResult } from "../base.js";
24
+
25
+ /**
26
+ * Get next available prompts respecting dependencies.
27
+ */
28
+ export class NextCommand extends BaseCommand {
29
+ readonly name = "next";
30
+ readonly description = "Get next available prompts respecting dependencies";
31
+
32
+ defineArguments(cmd: Command): void {
33
+ cmd.option("-n <count>", "Number of independent prompts to return");
34
+ }
35
+
36
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
37
+ const branch = getBranch();
38
+ if (!branch) {
39
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
40
+ }
41
+
42
+ if (!planExists()) {
43
+ return this.error("no_plan", "No plan directory exists for this branch");
44
+ }
45
+
46
+ // Get count from args, env var, or default to 1
47
+ const countArg = args.n as string | undefined;
48
+ const envCount = process.env.N_PARALLEL_WORKERS;
49
+ const count = countArg
50
+ ? parseInt(countArg, 10)
51
+ : envCount
52
+ ? parseInt(envCount, 10)
53
+ : 1;
54
+
55
+ if (isNaN(count) || count < 1) {
56
+ return this.error("invalid_count", "Count must be a positive integer");
57
+ }
58
+
59
+ const prompts = readAllPrompts();
60
+
61
+ // Build set of merged prompt numbers
62
+ const mergedNumbers = new Set<number>();
63
+ for (const p of prompts) {
64
+ if (p.frontMatter.status === "merged") {
65
+ mergedNumbers.add(p.number);
66
+ }
67
+ }
68
+
69
+ // Find prompts that can be worked on (not merged, not in_progress, deps satisfied)
70
+ const availablePrompts: Array<{
71
+ number: number;
72
+ variant: string | null;
73
+ frontMatter: PromptFrontMatter;
74
+ content: string;
75
+ }> = [];
76
+
77
+ for (const p of prompts) {
78
+ // Skip already merged or in_progress
79
+ if (p.frontMatter.status === "merged" || p.frontMatter.in_progress) {
80
+ continue;
81
+ }
82
+
83
+ // Check all dependencies are merged
84
+ const depsAreMerged = p.frontMatter.depends_on.every((dep) => mergedNumbers.has(dep));
85
+ if (!depsAreMerged) {
86
+ continue;
87
+ }
88
+
89
+ availablePrompts.push(p);
90
+ }
91
+
92
+ // Sort: debug prompts first, then by number, then by variant
93
+ availablePrompts.sort((a, b) => {
94
+ // Debug prompts first
95
+ const aDebug = a.frontMatter.kind === "debug" ? 0 : 1;
96
+ const bDebug = b.frontMatter.kind === "debug" ? 0 : 1;
97
+ if (aDebug !== bDebug) return aDebug - bDebug;
98
+
99
+ // Then by number
100
+ if (a.number !== b.number) return a.number - b.number;
101
+
102
+ // Then by variant (null first, then alphabetically)
103
+ if (!a.variant && b.variant) return -1;
104
+ if (a.variant && !b.variant) return 1;
105
+ return (a.variant || "").localeCompare(b.variant || "");
106
+ });
107
+
108
+ // Select up to count prompts, pulling all variants when one is selected
109
+ const selectedNumbers = new Set<number>();
110
+ const selected: typeof availablePrompts = [];
111
+
112
+ for (const p of availablePrompts) {
113
+ if (selectedNumbers.size >= count && !selectedNumbers.has(p.number)) {
114
+ break;
115
+ }
116
+ selectedNumbers.add(p.number);
117
+ selected.push(p);
118
+ }
119
+
120
+ // Format response
121
+ const result = selected.map((p) => ({
122
+ prompt_num: p.number,
123
+ variant: p.variant,
124
+ description: p.frontMatter.description,
125
+ relevant_files: p.frontMatter.relevant_files,
126
+ kind: p.frontMatter.kind,
127
+ }));
128
+
129
+ return this.success({
130
+ prompts: result,
131
+ count: result.length,
132
+ requested: count,
133
+ });
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Start working on a prompt - set in_progress and tracking info.
139
+ */
140
+ export class StartPromptCommand extends BaseCommand {
141
+ readonly name = "start-prompt";
142
+ readonly description = "Start working on a prompt";
143
+
144
+ defineArguments(cmd: Command): void {
145
+ cmd.argument("<number>", "Prompt number (integer)");
146
+ cmd.argument("[variant]", "Optional variant letter (A, B, etc.)");
147
+ cmd.option("--specialist <name>", "Name of the specialist/agent working on this prompt");
148
+ cmd.option("--worktree <branch>", "Worktree branch name for tracking");
149
+ }
150
+
151
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
152
+ const branch = getBranch();
153
+ if (!branch) {
154
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
155
+ }
156
+
157
+ const number = parseInt(args.number as string, 10);
158
+ if (isNaN(number) || number < 1) {
159
+ return this.error("invalid_number", "Prompt number must be a positive integer");
160
+ }
161
+
162
+ const variant = args.variant as string | undefined;
163
+ if (variant && !/^[A-Z]$/.test(variant)) {
164
+ return this.error("invalid_variant", "Variant must be a single uppercase letter (A-Z)");
165
+ }
166
+
167
+ const id = getPromptId(number, variant || null);
168
+ const prompt = readPrompt(number, variant || null);
169
+ if (!prompt) {
170
+ return this.error("not_found", `Prompt ${id} not found`);
171
+ }
172
+
173
+ const specialist = args.specialist as string | undefined;
174
+ const worktree = args.worktree as string | undefined;
175
+
176
+ // Update prompt front matter
177
+ const updatedFrontMatter: PromptFrontMatter = {
178
+ ...prompt.frontMatter,
179
+ in_progress: true,
180
+ current_iteration: 1,
181
+ delegated_to: (specialist as PromptFrontMatter["delegated_to"]) || null,
182
+ worktree_branch_name: worktree || null,
183
+ };
184
+
185
+ writePrompt(number, variant || null, updatedFrontMatter, prompt.content);
186
+
187
+ return this.success({
188
+ id,
189
+ in_progress: true,
190
+ specialist: specialist || null,
191
+ worktree: worktree || null,
192
+ current_iteration: 1,
193
+ });
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Record implementation walkthrough for a prompt.
199
+ */
200
+ export class RecordImplementationCommand extends BaseCommand {
201
+ readonly name = "record-implementation";
202
+ readonly description = "Record implementation walkthrough for a prompt";
203
+
204
+ defineArguments(cmd: Command): void {
205
+ cmd.argument("<number>", "Prompt number (integer)");
206
+ cmd.argument("[variant]", "Optional variant letter (A, B, etc.)");
207
+ cmd.option("--walkthrough <walkthrough>", "Structured walkthrough markdown");
208
+ cmd.option("--iteration <n>", "Iteration number (1 for initial, 2+ for refinements)");
209
+ cmd.option("--refinement-reason <reason>", "Context for why this iteration was needed");
210
+ }
211
+
212
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
213
+ const branch = getBranch();
214
+ if (!branch) {
215
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
216
+ }
217
+
218
+ const number = parseInt(args.number as string, 10);
219
+ if (isNaN(number) || number < 1) {
220
+ return this.error("invalid_number", "Prompt number must be a positive integer");
221
+ }
222
+
223
+ const variant = args.variant as string | undefined;
224
+ if (variant && !/^[A-Z]$/.test(variant)) {
225
+ return this.error("invalid_variant", "Variant must be a single uppercase letter (A-Z)");
226
+ }
227
+
228
+ const id = getPromptId(number, variant || null);
229
+ const prompt = readPrompt(number, variant || null);
230
+ if (!prompt) {
231
+ return this.error("not_found", `Prompt ${id} not found`);
232
+ }
233
+
234
+ const walkthrough = args.walkthrough as string | undefined;
235
+ if (!walkthrough) {
236
+ return this.error("missing_walkthrough", "Walkthrough is required");
237
+ }
238
+
239
+ const iterationStr = args.iteration as string | undefined;
240
+ const iteration = iterationStr ? parseInt(iterationStr, 10) : 1;
241
+ if (isNaN(iteration) || iteration < 1) {
242
+ return this.error("invalid_iteration", "Iteration must be a positive integer");
243
+ }
244
+
245
+ const refinementReason = args.refinementReason as string | undefined;
246
+ if (iteration > 1 && !refinementReason) {
247
+ return this.error("missing_refinement_reason", "Refinement reason is required for iteration > 1");
248
+ }
249
+
250
+ // Build walkthrough entry
251
+ const walkthroughEntry: PromptFrontMatter["walkthrough"][0] = {
252
+ iteration,
253
+ type: iteration === 1 ? "initial" : "review-refinement",
254
+ refinement_reason: refinementReason || null,
255
+ approach: walkthrough,
256
+ changes: [],
257
+ decisions: [],
258
+ };
259
+
260
+ // Append to existing walkthrough
261
+ const existingWalkthrough = prompt.frontMatter.walkthrough || [];
262
+ const updatedWalkthrough = [...existingWalkthrough, walkthroughEntry];
263
+
264
+ const updatedFrontMatter: PromptFrontMatter = {
265
+ ...prompt.frontMatter,
266
+ status: "implemented",
267
+ current_iteration: iteration,
268
+ walkthrough: updatedWalkthrough,
269
+ };
270
+
271
+ writePrompt(number, variant || null, updatedFrontMatter, prompt.content);
272
+
273
+ return this.success({
274
+ id,
275
+ status: "implemented",
276
+ iteration,
277
+ walkthrough_count: updatedWalkthrough.length,
278
+ });
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Complete a prompt - set status to merged.
284
+ */
285
+ export class CompletePromptCommand extends BaseCommand {
286
+ readonly name = "complete-prompt";
287
+ readonly description = "Complete a prompt (set status to merged)";
288
+
289
+ defineArguments(cmd: Command): void {
290
+ cmd.argument("<number>", "Prompt number (integer)");
291
+ cmd.argument("[variant]", "Optional variant letter (A, B, etc.)");
292
+ }
293
+
294
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
295
+ const branch = getBranch();
296
+ if (!branch) {
297
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
298
+ }
299
+
300
+ const number = parseInt(args.number as string, 10);
301
+ if (isNaN(number) || number < 1) {
302
+ return this.error("invalid_number", "Prompt number must be a positive integer");
303
+ }
304
+
305
+ const variant = args.variant as string | undefined;
306
+ if (variant && !/^[A-Z]$/.test(variant)) {
307
+ return this.error("invalid_variant", "Variant must be a single uppercase letter (A-Z)");
308
+ }
309
+
310
+ const id = getPromptId(number, variant || null);
311
+ const prompt = readPrompt(number, variant || null);
312
+ if (!prompt) {
313
+ return this.error("not_found", `Prompt ${id} not found`);
314
+ }
315
+
316
+ const updatedFrontMatter: PromptFrontMatter = {
317
+ ...prompt.frontMatter,
318
+ status: "merged",
319
+ in_progress: false,
320
+ };
321
+
322
+ writePrompt(number, variant || null, updatedFrontMatter, prompt.content);
323
+
324
+ return this.success({
325
+ id,
326
+ status: "merged",
327
+ });
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Get prompt walkthrough for documentation extraction.
333
+ */
334
+ export class GetPromptWalkthroughCommand extends BaseCommand {
335
+ readonly name = "get-prompt-walkthrough";
336
+ readonly description = "Get prompt walkthrough for documentation extraction";
337
+
338
+ defineArguments(cmd: Command): void {
339
+ cmd.argument("<number>", "Prompt number (integer)");
340
+ cmd.argument("[variant]", "Optional variant letter (A, B, etc.)");
341
+ }
342
+
343
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
344
+ const branch = getBranch();
345
+ if (!branch) {
346
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
347
+ }
348
+
349
+ const number = parseInt(args.number as string, 10);
350
+ if (isNaN(number) || number < 1) {
351
+ return this.error("invalid_number", "Prompt number must be a positive integer");
352
+ }
353
+
354
+ const variant = args.variant as string | undefined;
355
+ if (variant && !/^[A-Z]$/.test(variant)) {
356
+ return this.error("invalid_variant", "Variant must be a single uppercase letter (A-Z)");
357
+ }
358
+
359
+ const id = getPromptId(number, variant || null);
360
+ const prompt = readPrompt(number, variant || null);
361
+ if (!prompt) {
362
+ return this.error("not_found", `Prompt ${id} not found`);
363
+ }
364
+
365
+ // Get git diff summary for this prompt's changes
366
+ let gitDiffSummary = "";
367
+ const mergeCommit = prompt.frontMatter.merge_commit_hash;
368
+ const relevantFiles = prompt.frontMatter.relevant_files || [];
369
+
370
+ if (mergeCommit) {
371
+ try {
372
+ const result = spawnSync(
373
+ "git",
374
+ ["diff", "--stat", `${mergeCommit}^..${mergeCommit}`],
375
+ { encoding: "utf-8" }
376
+ );
377
+ gitDiffSummary = result.stdout || "(No changes in merge commit)";
378
+ } catch {
379
+ gitDiffSummary = "(Unable to get merge commit diff)";
380
+ }
381
+ } else if (relevantFiles.length > 0) {
382
+ try {
383
+ const baseBranch = getBaseBranch();
384
+ const result = spawnSync(
385
+ "git",
386
+ ["diff", "--stat", baseBranch, "--", ...relevantFiles],
387
+ { encoding: "utf-8" }
388
+ );
389
+ gitDiffSummary = result.stdout || "(No changes)";
390
+ } catch {
391
+ gitDiffSummary = "(Unable to get diff)";
392
+ }
393
+ }
394
+
395
+ return this.success({
396
+ prompt_num: number,
397
+ variant: variant || null,
398
+ description: prompt.frontMatter.description,
399
+ success_criteria: prompt.frontMatter.success_criteria,
400
+ walkthrough: prompt.frontMatter.walkthrough || [],
401
+ git_diff_summary: gitDiffSummary,
402
+ merge_commit_hash: mergeCommit || null,
403
+ });
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Mark a prompt as having its documentation extracted.
409
+ */
410
+ export class MarkPromptExtractedCommand extends BaseCommand {
411
+ readonly name = "mark-prompt-extracted";
412
+ readonly description = "Mark prompt documentation as extracted";
413
+
414
+ defineArguments(cmd: Command): void {
415
+ cmd.argument("<number>", "Prompt number (integer)");
416
+ cmd.argument("[variant]", "Optional variant letter (A, B, etc.)");
417
+ }
418
+
419
+ async execute(args: Record<string, unknown>): Promise<CommandResult> {
420
+ const branch = getBranch();
421
+ if (!branch) {
422
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
423
+ }
424
+
425
+ const number = parseInt(args.number as string, 10);
426
+ if (isNaN(number) || number < 1) {
427
+ return this.error("invalid_number", "Prompt number must be a positive integer");
428
+ }
429
+
430
+ const variant = args.variant as string | undefined;
431
+ if (variant && !/^[A-Z]$/.test(variant)) {
432
+ return this.error("invalid_variant", "Variant must be a single uppercase letter (A-Z)");
433
+ }
434
+
435
+ const id = getPromptId(number, variant || null);
436
+ const prompt = readPrompt(number, variant || null);
437
+ if (!prompt) {
438
+ return this.error("not_found", `Prompt ${id} not found`);
439
+ }
440
+
441
+ const updatedFrontMatter: PromptFrontMatter = {
442
+ ...prompt.frontMatter,
443
+ documentation_extracted: true,
444
+ };
445
+
446
+ writePrompt(number, variant || null, updatedFrontMatter, prompt.content);
447
+
448
+ return this.success({
449
+ id,
450
+ documentation_extracted: true,
451
+ });
452
+ }
453
+ }
454
+
455
+ /**
456
+ * Release all prompts from in_progress status.
457
+ */
458
+ export class ReleaseAllPromptsCommand extends BaseCommand {
459
+ readonly name = "release-all-prompts";
460
+ readonly description = "Release all prompts from in_progress status";
461
+
462
+ defineArguments(_cmd: Command): void {
463
+ // No arguments
464
+ }
465
+
466
+ async execute(_args: Record<string, unknown>): Promise<CommandResult> {
467
+ const branch = getBranch();
468
+ if (!branch) {
469
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
470
+ }
471
+
472
+ if (!planExists()) {
473
+ return this.error("no_plan", "No plan directory exists for this branch");
474
+ }
475
+
476
+ const prompts = readAllPrompts();
477
+ let releasedCount = 0;
478
+
479
+ for (const p of prompts) {
480
+ if (p.frontMatter.in_progress) {
481
+ const updatedFrontMatter: PromptFrontMatter = {
482
+ ...p.frontMatter,
483
+ in_progress: false,
484
+ };
485
+ writePrompt(p.number, p.variant, updatedFrontMatter, p.content);
486
+ releasedCount++;
487
+ }
488
+ }
489
+
490
+ return this.success({
491
+ released_count: releasedCount,
492
+ total_prompts: prompts.length,
493
+ });
494
+ }
495
+ }
496
+
497
+ /**
498
+ * Complete the plan - generate summary, create PR.
499
+ */
500
+ export class CompleteCommand extends BaseCommand {
501
+ readonly name = "complete";
502
+ readonly description = "Complete the plan - generate summary and create PR";
503
+
504
+ private readonly SUMMARY_PROMPT = `You are a technical writer creating a pull request summary.
505
+
506
+ Given a plan, implementation walkthroughs, user input, and git diff, generate a clear PR description.
507
+
508
+ Format:
509
+ ## Summary
510
+ [1-3 bullet points summarizing what was implemented]
511
+
512
+ ## Changes
513
+ [Grouped by area/feature, list major changes]
514
+
515
+ ## Testing
516
+ [How to test these changes]
517
+
518
+ ## Notes
519
+ [Any additional context, breaking changes, or follow-up items]`;
520
+
521
+ defineArguments(_cmd: Command): void {
522
+ // No arguments
523
+ }
524
+
525
+ async execute(_args: Record<string, unknown>): Promise<CommandResult> {
526
+ const branch = getBranch();
527
+ if (!branch) {
528
+ return this.error("no_branch", "Not in a git repository or no branch checked out");
529
+ }
530
+
531
+ if (!planExists()) {
532
+ return this.error("no_plan", "No plan directory exists for this branch");
533
+ }
534
+
535
+ const apiKey = process.env.VERTEX_API_KEY;
536
+ if (!apiKey) {
537
+ return this.error("auth_error", "VERTEX_API_KEY not set");
538
+ }
539
+
540
+ // Gather context
541
+ const plan = readPlan();
542
+ const userInput = readUserInput();
543
+ const prompts = readAllPrompts();
544
+ const baseBranch = getBaseBranch();
545
+ const diff = getDiff(baseBranch);
546
+
547
+ // Build context for summary generation
548
+ const promptSummaries = prompts.map((p) => {
549
+ const id = getPromptId(p.number, p.variant);
550
+ const walkthrough = p.frontMatter.walkthrough || [];
551
+ return `### Prompt ${id}: ${p.frontMatter.description}
552
+ Status: ${p.frontMatter.status}
553
+ Iterations: ${walkthrough.length}
554
+ ${walkthrough.map((w) => `- Iteration ${w.iteration} (${w.type}): ${w.approach.substring(0, 200)}...`).join("\n")}`;
555
+ }).join("\n\n");
556
+
557
+ const fullPrompt = `${this.SUMMARY_PROMPT}
558
+
559
+ ## Plan
560
+ ${plan?.content || "(No plan content)"}
561
+
562
+ ## User Input
563
+ ${userInput || "(No user input)"}
564
+
565
+ ## Prompts Implemented
566
+ ${promptSummaries}
567
+
568
+ ## Git Diff (against ${baseBranch})
569
+ \`\`\`diff
570
+ ${diff.substring(0, 50000)}
571
+ \`\`\`
572
+
573
+ Generate the PR summary now.`;
574
+
575
+ try {
576
+ // Generate summary with Gemini
577
+ const [summary, durationMs] = await this.timedExecute(async () => {
578
+ const client = new GoogleGenAI({ vertexai: true, apiKey });
579
+ const result = await client.models.generateContent({
580
+ model: "gemini-2.0-flash",
581
+ contents: fullPrompt,
582
+ });
583
+ return result.text ?? "";
584
+ });
585
+
586
+ // Write summary
587
+ writeSummary(summary);
588
+
589
+ // Update plan stage to completed
590
+ updatePlanStage("completed");
591
+
592
+ // Push to remote
593
+ try {
594
+ execSync(`git push -u origin ${branch}`, { encoding: "utf-8", stdio: "pipe" });
595
+ } catch {
596
+ // Push might fail if already up to date or no remote
597
+ }
598
+
599
+ // Create PR using gh CLI
600
+ let prUrl = "";
601
+ try {
602
+ const prResult = spawnSync(
603
+ "gh",
604
+ [
605
+ "pr",
606
+ "create",
607
+ "--title",
608
+ plan?.frontMatter?.branch_name || branch,
609
+ "--body",
610
+ summary,
611
+ "--base",
612
+ baseBranch,
613
+ ],
614
+ { encoding: "utf-8" }
615
+ );
616
+ if (prResult.status === 0) {
617
+ prUrl = prResult.stdout.trim();
618
+ } else {
619
+ // PR might already exist, try to get URL
620
+ const viewResult = spawnSync("gh", ["pr", "view", "--json", "url"], {
621
+ encoding: "utf-8",
622
+ });
623
+ if (viewResult.status === 0) {
624
+ const parsed = JSON.parse(viewResult.stdout);
625
+ prUrl = parsed.url || "";
626
+ }
627
+ }
628
+ } catch {
629
+ // gh CLI might not be available
630
+ }
631
+
632
+ return this.success(
633
+ {
634
+ success: true,
635
+ pr_url: prUrl,
636
+ summary_written: true,
637
+ stage: "completed",
638
+ },
639
+ {
640
+ command: "plan complete",
641
+ duration_ms: durationMs,
642
+ }
643
+ );
644
+ } catch (e) {
645
+ return this.error("api_error", e instanceof Error ? e.message : String(e));
646
+ }
647
+ }
648
+ }