@gitwhy-cli/whyspec 0.1.0
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/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/adapters/agents-md.d.ts +13 -0
- package/dist/adapters/agents-md.d.ts.map +1 -0
- package/dist/adapters/agents-md.js +165 -0
- package/dist/adapters/agents-md.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +13 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +206 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/cursor.d.ts +12 -0
- package/dist/adapters/cursor.d.ts.map +1 -0
- package/dist/adapters/cursor.js +220 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/types.d.ts +16 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +19 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +109 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/capture.d.ts +18 -0
- package/dist/commands/capture.d.ts.map +1 -0
- package/dist/commands/capture.js +85 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/debug.d.ts +16 -0
- package/dist/commands/debug.d.ts.map +1 -0
- package/dist/commands/debug.js +74 -0
- package/dist/commands/debug.js.map +1 -0
- package/dist/commands/execute.d.ts +36 -0
- package/dist/commands/execute.d.ts.map +1 -0
- package/dist/commands/execute.js +110 -0
- package/dist/commands/execute.js.map +1 -0
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +166 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +23 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +95 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/plan.d.ts +20 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +48 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/search.d.ts +12 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +36 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/show.d.ts +25 -0
- package/dist/commands/show.d.ts.map +1 -0
- package/dist/commands/show.js +145 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/status.d.ts +29 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +125 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/template.d.ts +14 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +25 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/core/categorize.d.ts +30 -0
- package/dist/core/categorize.d.ts.map +1 -0
- package/dist/core/categorize.js +72 -0
- package/dist/core/categorize.js.map +1 -0
- package/dist/core/config.d.ts +26 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +52 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context.d.ts +27 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +75 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/search.d.ts +51 -0
- package/dist/core/search.d.ts.map +1 -0
- package/dist/core/search.js +235 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/storage.d.ts +36 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +80 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/templates.d.ts +28 -0
- package/dist/core/templates.d.ts.map +1 -0
- package/dist/core/templates.js +176 -0
- package/dist/core/templates.js.map +1 -0
- package/dist/ui/ascii-logo.d.ts +7 -0
- package/dist/ui/ascii-logo.d.ts.map +1 -0
- package/dist/ui/ascii-logo.js +15 -0
- package/dist/ui/ascii-logo.js.map +1 -0
- package/dist/ui/tool-picker.d.ts +13 -0
- package/dist/ui/tool-picker.d.ts.map +1 -0
- package/dist/ui/tool-picker.js +76 -0
- package/dist/ui/tool-picker.js.map +1 -0
- package/dist/ui/welcome.d.ts +4 -0
- package/dist/ui/welcome.d.ts.map +1 -0
- package/dist/ui/welcome.js +43 -0
- package/dist/ui/welcome.js.map +1 -0
- package/dist/utils/changes.d.ts +19 -0
- package/dist/utils/changes.d.ts.map +1 -0
- package/dist/utils/changes.js +63 -0
- package/dist/utils/changes.js.map +1 -0
- package/dist/utils/git.d.ts +28 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +104 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/slugify.d.ts +12 -0
- package/dist/utils/slugify.d.ts.map +1 -0
- package/dist/utils/slugify.js +21 -0
- package/dist/utils/slugify.js.map +1 -0
- package/dist/utils/telemetry.d.ts +21 -0
- package/dist/utils/telemetry.d.ts.map +1 -0
- package/dist/utils/telemetry.js +32 -0
- package/dist/utils/telemetry.js.map +1 -0
- package/package.json +81 -0
- package/skills/whyspec-capture/SKILL.md +154 -0
- package/skills/whyspec-debug/SKILL.md +404 -0
- package/skills/whyspec-execute/SKILL.md +118 -0
- package/skills/whyspec-plan/SKILL.md +170 -0
- package/skills/whyspec-search/SKILL.md +69 -0
- package/skills/whyspec-show/SKILL.md +90 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { WHYSPEC_COMMANDS, COMMAND_DESCRIPTIONS, } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate the Cursor command instructions for each WhySpec command.
|
|
4
|
+
* Cursor commands are plain markdown — no YAML frontmatter.
|
|
5
|
+
*/
|
|
6
|
+
function getCursorCommandContent(command) {
|
|
7
|
+
switch (command) {
|
|
8
|
+
case "plan":
|
|
9
|
+
return `# WhySpec Plan
|
|
10
|
+
|
|
11
|
+
${COMMAND_DESCRIPTIONS.plan}
|
|
12
|
+
|
|
13
|
+
## Objective
|
|
14
|
+
|
|
15
|
+
Create a structured plan before coding — capturing intent, design decisions to make, and implementation tasks. This is the BEFORE side of the Decision Bridge.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. Ask the developer 2-3 forcing questions:
|
|
20
|
+
- "What problem does this solve?"
|
|
21
|
+
- "What constraints exist?"
|
|
22
|
+
- "How will you know it works?"
|
|
23
|
+
|
|
24
|
+
2. Call the WhySpec CLI to create the change folder:
|
|
25
|
+
\`\`\`bash
|
|
26
|
+
whyspec plan --json "<change-name>"
|
|
27
|
+
\`\`\`
|
|
28
|
+
|
|
29
|
+
3. Parse the JSON response to get the folder path and templates.
|
|
30
|
+
|
|
31
|
+
4. Create three files in the change folder:
|
|
32
|
+
- **intent.md** — Why this change exists, decisions to make, constraints, success criteria
|
|
33
|
+
- **design.md** — Technical approach, trade-off matrix, architecture, questions to resolve
|
|
34
|
+
- **tasks.md** — Verification criteria (defined FIRST), then implementation checklist
|
|
35
|
+
|
|
36
|
+
5. Each decision-to-make should be a checkbox: \`- [ ] Token storage: cookie vs localStorage?\`
|
|
37
|
+
|
|
38
|
+
## Important
|
|
39
|
+
|
|
40
|
+
- Always call the CLI first — it handles path creation and validation.
|
|
41
|
+
- Capture COMPLETE reasoning, not abbreviated summaries.
|
|
42
|
+
- The "Decisions to Make" section in design.md is the BEFORE side of the Decision Bridge.`;
|
|
43
|
+
case "execute":
|
|
44
|
+
return `# WhySpec Execute
|
|
45
|
+
|
|
46
|
+
${COMMAND_DESCRIPTIONS.execute}
|
|
47
|
+
|
|
48
|
+
## Objective
|
|
49
|
+
|
|
50
|
+
Implement a planned change using the plan files as context. Track progress through the task list and commit atomically.
|
|
51
|
+
|
|
52
|
+
## Workflow
|
|
53
|
+
|
|
54
|
+
1. Call the WhySpec CLI to get execution context:
|
|
55
|
+
\`\`\`bash
|
|
56
|
+
whyspec execute --json "<change-name>"
|
|
57
|
+
\`\`\`
|
|
58
|
+
|
|
59
|
+
2. Parse the JSON response to get intent, design, tasks, and progress.
|
|
60
|
+
|
|
61
|
+
3. Read intent.md and design.md for WHY context — understand the goal before coding.
|
|
62
|
+
|
|
63
|
+
4. Work through tasks.md sequentially:
|
|
64
|
+
- Show progress: "Working on task 3/7: <description>"
|
|
65
|
+
- Implement the code changes
|
|
66
|
+
- Mark each task complete: \`- [ ]\` → \`- [x]\` in tasks.md
|
|
67
|
+
- Commit atomically (one commit per task or logical unit)
|
|
68
|
+
|
|
69
|
+
5. On completion, prompt: "Ready to capture reasoning? Run /whyspec-capture"
|
|
70
|
+
|
|
71
|
+
## Important
|
|
72
|
+
|
|
73
|
+
- Use intent.md as context while implementing — it contains the WHY.
|
|
74
|
+
- Track deviations from the plan — surprises are valuable for capture.
|
|
75
|
+
- Do not skip tasks or mark them done without implementing.`;
|
|
76
|
+
case "capture":
|
|
77
|
+
return `# WhySpec Capture
|
|
78
|
+
|
|
79
|
+
${COMMAND_DESCRIPTIONS.capture}
|
|
80
|
+
|
|
81
|
+
## Objective
|
|
82
|
+
|
|
83
|
+
After coding, capture the reasoning behind what was built — completing the Decision Bridge by recording which decisions were made and why.
|
|
84
|
+
|
|
85
|
+
## Workflow
|
|
86
|
+
|
|
87
|
+
1. Call the WhySpec CLI to get the capture template:
|
|
88
|
+
\`\`\`bash
|
|
89
|
+
whyspec capture --json "<change-name>"
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
2. Parse the JSON response to get the template, linked commits, and files changed.
|
|
93
|
+
|
|
94
|
+
3. Read intent.md and design.md from the change folder.
|
|
95
|
+
|
|
96
|
+
4. Create a context file with:
|
|
97
|
+
- Map each "Decision to Make" from design.md → "Decisions Made" with rationale
|
|
98
|
+
- Map each "Question to Resolve" → resolved answer
|
|
99
|
+
- Capture "Surprises" — decisions NOT in the plan
|
|
100
|
+
- Include story, rejected alternatives, trade-offs, verification, risks
|
|
101
|
+
|
|
102
|
+
## Important
|
|
103
|
+
|
|
104
|
+
- Include ALL decisions, not just the ones from the plan.
|
|
105
|
+
- Surprises (unplanned decisions) are the most valuable part of the capture.
|
|
106
|
+
- This completes the Decision Bridge: plan PREDICTED decisions, capture RECORDS them.`;
|
|
107
|
+
case "show":
|
|
108
|
+
return `# WhySpec Show
|
|
109
|
+
|
|
110
|
+
${COMMAND_DESCRIPTIONS.show}
|
|
111
|
+
|
|
112
|
+
## Objective
|
|
113
|
+
|
|
114
|
+
Display the full story of a change — from intent through design, tasks, and captured reasoning — with the Decision Bridge delta highlighted.
|
|
115
|
+
|
|
116
|
+
## Workflow
|
|
117
|
+
|
|
118
|
+
1. Call the WhySpec CLI to get the full change data:
|
|
119
|
+
\`\`\`bash
|
|
120
|
+
whyspec show --json "<change-name>"
|
|
121
|
+
\`\`\`
|
|
122
|
+
|
|
123
|
+
2. Parse the JSON response containing intent, design, tasks, context, and Decision Bridge delta.
|
|
124
|
+
|
|
125
|
+
3. Display the change story in sections:
|
|
126
|
+
- **Intent** — WHY (from intent.md)
|
|
127
|
+
- **Design** — HOW (from design.md)
|
|
128
|
+
- **Tasks** — WHAT (from tasks.md with completion status)
|
|
129
|
+
- **Context** — REASONING (from captured context)
|
|
130
|
+
- **Decision Bridge Delta** — Decisions to Make vs Decisions Made
|
|
131
|
+
|
|
132
|
+
## Important
|
|
133
|
+
|
|
134
|
+
- The Decision Bridge delta is the unique value — always show it.
|
|
135
|
+
- If context hasn't been captured yet, show intent + design + tasks and suggest running /whyspec-capture.`;
|
|
136
|
+
case "search":
|
|
137
|
+
return `# WhySpec Search
|
|
138
|
+
|
|
139
|
+
${COMMAND_DESCRIPTIONS.search}
|
|
140
|
+
|
|
141
|
+
## Objective
|
|
142
|
+
|
|
143
|
+
Find past decisions and reasoning across all changes — building institutional knowledge that improves future work.
|
|
144
|
+
|
|
145
|
+
## Workflow
|
|
146
|
+
|
|
147
|
+
1. Call the WhySpec CLI to search:
|
|
148
|
+
\`\`\`bash
|
|
149
|
+
whyspec search --json "<query>"
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
2. Parse the JSON response containing scored results with snippets.
|
|
153
|
+
|
|
154
|
+
3. Display results ranked by relevance:
|
|
155
|
+
- Title matches score highest (100 points)
|
|
156
|
+
- Reasoning/decision matches score next (30 points)
|
|
157
|
+
- File path matches score lower (20 points)
|
|
158
|
+
|
|
159
|
+
4. For each result, show: title, change name, score, and a relevant snippet.
|
|
160
|
+
|
|
161
|
+
## Important
|
|
162
|
+
|
|
163
|
+
- Search covers both active changes and archived ones.
|
|
164
|
+
- Search also finds intent.md and design.md — not just captured contexts.
|
|
165
|
+
- Use this before starting new work: "Has anyone reasoned about this area before?"`;
|
|
166
|
+
case "debug":
|
|
167
|
+
return `# WhySpec Debug
|
|
168
|
+
|
|
169
|
+
${COMMAND_DESCRIPTIONS.debug}
|
|
170
|
+
|
|
171
|
+
## Objective
|
|
172
|
+
|
|
173
|
+
Investigate a bug using the scientific method — capturing symptoms, hypotheses, evidence, root cause, fix, and prevention. Searches past decisions for related context.
|
|
174
|
+
|
|
175
|
+
## Workflow
|
|
176
|
+
|
|
177
|
+
1. Call the WhySpec CLI to create a debug session:
|
|
178
|
+
\`\`\`bash
|
|
179
|
+
whyspec debug --json "<bug-description>"
|
|
180
|
+
\`\`\`
|
|
181
|
+
|
|
182
|
+
2. Parse the JSON response to get the debug folder path and related past contexts.
|
|
183
|
+
|
|
184
|
+
3. Follow the scientific method:
|
|
185
|
+
- **Symptoms** — Expected vs actual behavior, error messages, reproduction steps
|
|
186
|
+
- **Related contexts** — Check past decisions in this area (from CLI response)
|
|
187
|
+
- **Hypotheses** — Form 3+ falsifiable hypotheses with "what would prove this wrong?"
|
|
188
|
+
- **Investigation** — Test each hypothesis with evidence gathering
|
|
189
|
+
- **Root cause** — Prove the diagnosis BEFORE proposing a fix (Iron Law)
|
|
190
|
+
- **Fix** — Apply the fix and verify
|
|
191
|
+
- **Prevention** — How to prevent this class of bug in the future
|
|
192
|
+
|
|
193
|
+
4. Create debug.md with the full investigation trail.
|
|
194
|
+
|
|
195
|
+
5. On completion, prompt: "Ready to capture debug reasoning? Run /whyspec-capture"
|
|
196
|
+
|
|
197
|
+
## Important
|
|
198
|
+
|
|
199
|
+
- No fix without root cause — this is the Iron Law.
|
|
200
|
+
- Check related past contexts BEFORE forming hypotheses.
|
|
201
|
+
- The debug.md persists across sessions so investigation survives context resets.`;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Generate Cursor custom slash command files for all 6 WhySpec commands.
|
|
206
|
+
*
|
|
207
|
+
* Creates .cursor/commands/whyspec-<command>.md files — plain markdown
|
|
208
|
+
* that Cursor discovers automatically as slash commands.
|
|
209
|
+
*
|
|
210
|
+
* @param projectRoot - Optional project root prefix for paths (default: "")
|
|
211
|
+
* @returns Array of GeneratedFile objects
|
|
212
|
+
*/
|
|
213
|
+
export function generateCursorCommands(projectRoot = "") {
|
|
214
|
+
const prefix = projectRoot ? `${projectRoot}/` : "";
|
|
215
|
+
return WHYSPEC_COMMANDS.map((command) => ({
|
|
216
|
+
path: `${prefix}.cursor/commands/whyspec-${command}.md`,
|
|
217
|
+
content: getCursorCommandContent(command) + "\n",
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/adapters/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,gBAAgB,EAChB,oBAAoB,GAErB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,SAAS,uBAAuB,CAAC,OAAuB;IACtD,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,OAAO;;EAEX,oBAAoB,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0FA+B+D,CAAC;QAEvF,KAAK,SAAS;YACZ,OAAO;;EAEX,oBAAoB,CAAC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4DA6B8B,CAAC;QAEzD,KAAK,SAAS;YACZ,OAAO;;EAEX,oBAAoB,CAAC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;sFA2BwD,CAAC;QAEnF,KAAK,MAAM;YACT,OAAO;;EAEX,oBAAoB,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;0GAyB+E,CAAC;QAEvG,KAAK,QAAQ;YACX,OAAO;;EAEX,oBAAoB,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;mFA0BsD,CAAC;QAEhF,KAAK,OAAO;YACV,OAAO;;EAEX,oBAAoB,CAAC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAgCsD,CAAC;IACjF,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,cAAsB,EAAE;IAExB,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpD,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACxC,IAAI,EAAE,GAAG,MAAM,4BAA4B,OAAO,KAAK;QACvD,OAAO,EAAE,uBAAuB,CAAC,OAAO,CAAC,GAAG,IAAI;KACjD,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A file to be generated by an adapter.
|
|
3
|
+
* Adapters return these; the caller handles writing to disk.
|
|
4
|
+
*/
|
|
5
|
+
export interface GeneratedFile {
|
|
6
|
+
/** Relative path from project root (e.g., ".claude/skills/whyspec-plan/SKILL.md") */
|
|
7
|
+
path: string;
|
|
8
|
+
/** File content */
|
|
9
|
+
content: string;
|
|
10
|
+
}
|
|
11
|
+
/** The 6 WhySpec commands that adapters generate config for. */
|
|
12
|
+
export declare const WHYSPEC_COMMANDS: readonly ["plan", "execute", "capture", "show", "search", "debug"];
|
|
13
|
+
export type WhySpecCommand = (typeof WHYSPEC_COMMANDS)[number];
|
|
14
|
+
/** One-line descriptions for each command, used across all adapters. */
|
|
15
|
+
export declare const COMMAND_DESCRIPTIONS: Record<WhySpecCommand, string>;
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gEAAgE;AAChE,eAAO,MAAM,gBAAgB,oEAOnB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAO/D,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** The 6 WhySpec commands that adapters generate config for. */
|
|
2
|
+
export const WHYSPEC_COMMANDS = [
|
|
3
|
+
"plan",
|
|
4
|
+
"execute",
|
|
5
|
+
"capture",
|
|
6
|
+
"show",
|
|
7
|
+
"search",
|
|
8
|
+
"debug",
|
|
9
|
+
];
|
|
10
|
+
/** One-line descriptions for each command, used across all adapters. */
|
|
11
|
+
export const COMMAND_DESCRIPTIONS = {
|
|
12
|
+
plan: "Declare intent and plan decisions before coding",
|
|
13
|
+
execute: "Implement from plan with full reasoning context",
|
|
14
|
+
capture: "Save the reasoning behind what was built",
|
|
15
|
+
show: "View the full story of a change with Decision Bridge delta",
|
|
16
|
+
search: "Search past decisions and reasoning across all changes",
|
|
17
|
+
debug: "Debug with the scientific method and capture root cause",
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAWA,gEAAgE;AAChE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM;IACN,SAAS;IACT,SAAS;IACT,MAAM;IACN,QAAQ;IACR,OAAO;CACC,CAAC;AAIX,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAmC;IAClE,IAAI,EAAE,iDAAiD;IACvD,OAAO,EAAE,iDAAiD;IAC1D,OAAO,EAAE,0CAA0C;IACnD,IAAI,EAAE,4DAA4D;IAClE,MAAM,EAAE,wDAAwD;IAChE,KAAK,EAAE,yDAAyD;CACjE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { runInit } from "../commands/init.js";
|
|
4
|
+
import { planCommand } from "../commands/plan.js";
|
|
5
|
+
import { executeCommand } from "../commands/execute.js";
|
|
6
|
+
import { captureCommand } from "../commands/capture.js";
|
|
7
|
+
import { showCommand } from "../commands/show.js";
|
|
8
|
+
import { searchCommand } from "../commands/search.js";
|
|
9
|
+
import { debugCommand } from "../commands/debug.js";
|
|
10
|
+
import { listCommand } from "../commands/list.js";
|
|
11
|
+
import { statusCommand } from "../commands/status.js";
|
|
12
|
+
import { templateCommand } from "../commands/template.js";
|
|
13
|
+
const program = new Command();
|
|
14
|
+
program
|
|
15
|
+
.name("whyspec")
|
|
16
|
+
.description("The reasoning layer for AI-assisted development — capture WHY code was built the way it was")
|
|
17
|
+
.version("0.1.0")
|
|
18
|
+
.option("--json", "Output structured JSON for agent consumption");
|
|
19
|
+
// ── init ────────────────────────────────────────────────────────────────────
|
|
20
|
+
program
|
|
21
|
+
.command("init")
|
|
22
|
+
.description("Initialize WhySpec in the current project")
|
|
23
|
+
.action(async () => {
|
|
24
|
+
await runInit();
|
|
25
|
+
});
|
|
26
|
+
// ── plan ────────────────────────────────────────────────────────────────────
|
|
27
|
+
program
|
|
28
|
+
.command("plan")
|
|
29
|
+
.description("Create a change folder with intent, design, and task templates")
|
|
30
|
+
.argument("[name]", "Name of the change (e.g., add-jwt-auth)")
|
|
31
|
+
.action(async (name, _opts, cmd) => {
|
|
32
|
+
const json = cmd.optsWithGlobals().json;
|
|
33
|
+
await planCommand(name, { json });
|
|
34
|
+
});
|
|
35
|
+
// ── execute ─────────────────────────────────────────────────────────────────
|
|
36
|
+
program
|
|
37
|
+
.command("execute")
|
|
38
|
+
.description("Get execution context from a plan (intent + design + tasks)")
|
|
39
|
+
.argument("[name]", "Name of the change to execute")
|
|
40
|
+
.action(async (name, _opts, cmd) => {
|
|
41
|
+
const json = cmd.optsWithGlobals().json;
|
|
42
|
+
await executeCommand(name, { json });
|
|
43
|
+
});
|
|
44
|
+
// ── capture ─────────────────────────────────────────────────────────────────
|
|
45
|
+
program
|
|
46
|
+
.command("capture")
|
|
47
|
+
.description("Capture reasoning after implementation (creates ctx_<id>.md)")
|
|
48
|
+
.argument("[name]", "Name of the change to capture")
|
|
49
|
+
.action(async (name, _opts, cmd) => {
|
|
50
|
+
const json = cmd.optsWithGlobals().json;
|
|
51
|
+
await captureCommand(name, { json });
|
|
52
|
+
});
|
|
53
|
+
// ── show ────────────────────────────────────────────────────────────────────
|
|
54
|
+
program
|
|
55
|
+
.command("show")
|
|
56
|
+
.description("Display the full story of a change with Decision Bridge delta")
|
|
57
|
+
.argument("<name>", "Name of the change to show")
|
|
58
|
+
.action(async (name, _opts, cmd) => {
|
|
59
|
+
const json = cmd.optsWithGlobals().json;
|
|
60
|
+
await showCommand(name, { json });
|
|
61
|
+
});
|
|
62
|
+
// ── search ──────────────────────────────────────────────────────────────────
|
|
63
|
+
program
|
|
64
|
+
.command("search")
|
|
65
|
+
.description("Search past decisions and reasoning across all changes")
|
|
66
|
+
.argument("<query>", "Search query")
|
|
67
|
+
.option("--domain <domain>", "Filter by domain")
|
|
68
|
+
.option("--limit <n>", "Maximum results", "10")
|
|
69
|
+
.action(async (query, opts, cmd) => {
|
|
70
|
+
const json = cmd.optsWithGlobals().json;
|
|
71
|
+
await searchCommand(query, { json, domain: opts.domain, limit: opts.limit });
|
|
72
|
+
});
|
|
73
|
+
// ── debug ───────────────────────────────────────────────────────────────────
|
|
74
|
+
program
|
|
75
|
+
.command("debug")
|
|
76
|
+
.description("Create a structured debug session (scientific method)")
|
|
77
|
+
.argument("[name]", "Name or description of the bug")
|
|
78
|
+
.action(async (name, _opts, cmd) => {
|
|
79
|
+
const json = cmd.optsWithGlobals().json;
|
|
80
|
+
await debugCommand(name, { json });
|
|
81
|
+
});
|
|
82
|
+
// ── list ────────────────────────────────────────────────────────────────────
|
|
83
|
+
program
|
|
84
|
+
.command("list")
|
|
85
|
+
.description("List all active changes with status")
|
|
86
|
+
.action(async (_opts, cmd) => {
|
|
87
|
+
const json = cmd.optsWithGlobals().json;
|
|
88
|
+
await listCommand({ json });
|
|
89
|
+
});
|
|
90
|
+
// ── status ──────────────────────────────────────────────────────────────────
|
|
91
|
+
program
|
|
92
|
+
.command("status")
|
|
93
|
+
.description("Get detailed status for a change")
|
|
94
|
+
.argument("<name>", "Name of the change")
|
|
95
|
+
.action(async (name, _opts, cmd) => {
|
|
96
|
+
const json = cmd.optsWithGlobals().json;
|
|
97
|
+
await statusCommand(name, { json });
|
|
98
|
+
});
|
|
99
|
+
// ── template ────────────────────────────────────────────────────────────────
|
|
100
|
+
program
|
|
101
|
+
.command("template")
|
|
102
|
+
.description("Get a raw file template (intent, design, tasks, context, debug)")
|
|
103
|
+
.argument("<type>", "Template type: intent | design | tasks | context | debug")
|
|
104
|
+
.action(async (type, _opts, cmd) => {
|
|
105
|
+
const json = cmd.optsWithGlobals().json;
|
|
106
|
+
await templateCommand(type, { json });
|
|
107
|
+
});
|
|
108
|
+
program.parse();
|
|
109
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* whyspec capture — Capture reasoning context for a change.
|
|
3
|
+
*
|
|
4
|
+
* --json mode: returns XML template + commits + files + Decision Bridge data.
|
|
5
|
+
* Non-JSON mode: writes ctx_<id>.md with metadata header + XML template.
|
|
6
|
+
*/
|
|
7
|
+
export interface CaptureJsonOutput {
|
|
8
|
+
template: string;
|
|
9
|
+
commits: string[];
|
|
10
|
+
files_changed: string[];
|
|
11
|
+
decisions_to_make: string[];
|
|
12
|
+
change_name: string;
|
|
13
|
+
change_path: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function captureCommand(name: string | undefined, options: {
|
|
16
|
+
json?: boolean;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CA0Ef"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* whyspec capture — Capture reasoning context for a change.
|
|
3
|
+
*
|
|
4
|
+
* --json mode: returns XML template + commits + files + Decision Bridge data.
|
|
5
|
+
* Non-JSON mode: writes ctx_<id>.md with metadata header + XML template.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { resolveChange } from "../utils/changes.js";
|
|
11
|
+
import { getCurrentBranch, getCommitsSince, getFilesChanged, getRemoteUrl } from "../utils/git.js";
|
|
12
|
+
import { generateContextId, renderContextXml, extractDecisions, getChangeFolderCreatedAt, } from "../core/context.js";
|
|
13
|
+
function readFileOrEmpty(filePath) {
|
|
14
|
+
if (!existsSync(filePath))
|
|
15
|
+
return "";
|
|
16
|
+
return readFileSync(filePath, "utf-8");
|
|
17
|
+
}
|
|
18
|
+
export async function captureCommand(name, options) {
|
|
19
|
+
const gitwhyDir = join(process.cwd(), ".gitwhy");
|
|
20
|
+
const change = resolveChange(gitwhyDir, name);
|
|
21
|
+
// Read planning artifacts
|
|
22
|
+
const intentContent = readFileOrEmpty(join(change.path, "intent.md"));
|
|
23
|
+
const designContent = readFileOrEmpty(join(change.path, "design.md"));
|
|
24
|
+
// Extract Decision Bridge data from design.md
|
|
25
|
+
const decisions = extractDecisions(designContent);
|
|
26
|
+
// Also extract decisions from intent.md if it has a Decisions to Make section
|
|
27
|
+
const intentDecisions = extractDecisions(intentContent);
|
|
28
|
+
const allDecisions = [...new Set([...decisions, ...intentDecisions])];
|
|
29
|
+
// Auto-detect commits and files changed since the change folder was created
|
|
30
|
+
let commits = [];
|
|
31
|
+
let filesChanged = [];
|
|
32
|
+
try {
|
|
33
|
+
const createdAt = getChangeFolderCreatedAt(change.path);
|
|
34
|
+
commits = getCommitsSince(createdAt);
|
|
35
|
+
filesChanged = getFilesChanged(createdAt);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Gracefully handle if git operations fail
|
|
39
|
+
}
|
|
40
|
+
if (options.json) {
|
|
41
|
+
const output = {
|
|
42
|
+
template: renderContextXml(),
|
|
43
|
+
commits,
|
|
44
|
+
files_changed: filesChanged,
|
|
45
|
+
decisions_to_make: allDecisions,
|
|
46
|
+
change_name: change.name,
|
|
47
|
+
change_path: `.gitwhy/changes/${change.name}`,
|
|
48
|
+
};
|
|
49
|
+
console.log(JSON.stringify(output, null, 2));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Non-JSON mode: write ctx_<id>.md with GitWhy-compatible metadata header
|
|
53
|
+
const contextId = generateContextId();
|
|
54
|
+
const branch = getCurrentBranch();
|
|
55
|
+
const repository = getRemoteUrl();
|
|
56
|
+
const commitList = commits.length > 0 ? commits.map((c) => c.slice(0, 7)).join(", ") : "none";
|
|
57
|
+
const metadataHeader = [
|
|
58
|
+
`# ${change.name}`,
|
|
59
|
+
"",
|
|
60
|
+
`**Context ID:** ${contextId}`,
|
|
61
|
+
`**Agent:** whyspec`,
|
|
62
|
+
...(repository ? [`**Repository:** ${repository}`] : []),
|
|
63
|
+
`**Branch:** ${branch}`,
|
|
64
|
+
`**Date:** ${new Date().toISOString()}`,
|
|
65
|
+
`**Change:** ${change.name}`,
|
|
66
|
+
`**Intent:** .gitwhy/changes/${change.name}/intent.md`,
|
|
67
|
+
`**Commits:** ${commitList}`,
|
|
68
|
+
"",
|
|
69
|
+
"---",
|
|
70
|
+
"",
|
|
71
|
+
].join("\n");
|
|
72
|
+
const content = metadataHeader + renderContextXml() + "\n";
|
|
73
|
+
const fileName = `${contextId}.md`;
|
|
74
|
+
const filePath = join(change.path, fileName);
|
|
75
|
+
writeFileSync(filePath, content);
|
|
76
|
+
console.log(chalk.green("Captured context:") + ` ${fileName}`);
|
|
77
|
+
console.log(` ${chalk.dim("change:")} ${change.name}`);
|
|
78
|
+
console.log(` ${chalk.dim("branch:")} ${branch}`);
|
|
79
|
+
console.log(` ${chalk.dim("commits:")} ${commitList}`);
|
|
80
|
+
if (allDecisions.length > 0) {
|
|
81
|
+
console.log(` ${chalk.dim("decisions to map:")} ${allDecisions.length}`);
|
|
82
|
+
allDecisions.forEach((d) => console.log(` - ${d}`));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* whyspec debug — Create a structured debug session (scientific method).
|
|
3
|
+
*
|
|
4
|
+
* --json mode: returns path, template, and related past contexts.
|
|
5
|
+
* Non-JSON mode: creates debug.md, prints related contexts and next steps.
|
|
6
|
+
*/
|
|
7
|
+
import { type SearchResult } from "../core/search.js";
|
|
8
|
+
export interface DebugJsonOutput {
|
|
9
|
+
path: string;
|
|
10
|
+
template: string;
|
|
11
|
+
related_contexts: SearchResult[];
|
|
12
|
+
}
|
|
13
|
+
export declare function debugCommand(name: string | undefined, options: {
|
|
14
|
+
json?: boolean;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=debug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/commands/debug.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,YAAY,EAAE,CAAC;CAClC;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoEf"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* whyspec debug — Create a structured debug session (scientific method).
|
|
3
|
+
*
|
|
4
|
+
* --json mode: returns path, template, and related past contexts.
|
|
5
|
+
* Non-JSON mode: creates debug.md, prints related contexts and next steps.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { slugify } from "../utils/slugify.js";
|
|
11
|
+
import { debugTemplate } from "../core/templates.js";
|
|
12
|
+
import { searchChanges } from "../core/search.js";
|
|
13
|
+
export async function debugCommand(name, options) {
|
|
14
|
+
if (!name) {
|
|
15
|
+
throw new Error("Bug description is required. Usage: whyspec debug \"description of the bug\"");
|
|
16
|
+
}
|
|
17
|
+
const repoRoot = process.cwd();
|
|
18
|
+
const slug = slugify(name);
|
|
19
|
+
const gitwhyDir = join(repoRoot, ".gitwhy");
|
|
20
|
+
const changePath = join(gitwhyDir, "changes", slug);
|
|
21
|
+
// Quick search for related contexts using first few words of the bug name.
|
|
22
|
+
const searchQuery = name.split(/\s+/).slice(0, 3).join(" ");
|
|
23
|
+
let relatedContexts = [];
|
|
24
|
+
try {
|
|
25
|
+
relatedContexts = searchChanges(repoRoot, searchQuery, { limit: 5 });
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Gracefully continue if search fails (e.g., no .gitwhy/ dir yet).
|
|
29
|
+
}
|
|
30
|
+
// Generate debug template.
|
|
31
|
+
const template = debugTemplate(name);
|
|
32
|
+
// Append related contexts section if any were found.
|
|
33
|
+
let fullTemplate = template;
|
|
34
|
+
if (relatedContexts.length > 0) {
|
|
35
|
+
fullTemplate += "\n## Related Contexts\n";
|
|
36
|
+
fullTemplate += "<!-- Past decisions and reasoning in this area -->\n";
|
|
37
|
+
for (const ctx of relatedContexts) {
|
|
38
|
+
fullTemplate += `- **${ctx.change_name}/${ctx.id}** (score: ${ctx.score}) — ${ctx.title}\n`;
|
|
39
|
+
fullTemplate += ` ${ctx.snippet}\n`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (options.json) {
|
|
43
|
+
const output = {
|
|
44
|
+
path: `.gitwhy/changes/${slug}`,
|
|
45
|
+
template: fullTemplate,
|
|
46
|
+
related_contexts: relatedContexts,
|
|
47
|
+
};
|
|
48
|
+
console.log(JSON.stringify(output, null, 2));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Non-JSON mode: create directory and file.
|
|
52
|
+
mkdirSync(changePath, { recursive: true });
|
|
53
|
+
writeFileSync(join(changePath, ".started"), new Date().toISOString());
|
|
54
|
+
writeFileSync(join(changePath, "debug.md"), fullTemplate);
|
|
55
|
+
console.log(chalk.green("Created debug session:") + ` ${slug}`);
|
|
56
|
+
console.log(` ${chalk.dim("path:")} .gitwhy/changes/${slug}/`);
|
|
57
|
+
console.log(` ${chalk.dim("file:")} debug.md`);
|
|
58
|
+
if (relatedContexts.length > 0) {
|
|
59
|
+
console.log();
|
|
60
|
+
console.log(chalk.bold("Related past contexts:"));
|
|
61
|
+
for (const ctx of relatedContexts) {
|
|
62
|
+
const scoreColor = ctx.score >= 100 ? chalk.green : ctx.score >= 30 ? chalk.yellow : chalk.dim;
|
|
63
|
+
console.log(` ${scoreColor(`[${ctx.score}]`)} ${ctx.change_name}/${ctx.id} — ${ctx.title}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(chalk.bold("Next steps:"));
|
|
68
|
+
console.log(` 1. Fill in ${chalk.cyan("Symptoms")} (expected vs actual)`);
|
|
69
|
+
console.log(` 2. Form 3+ ${chalk.cyan("Hypotheses")} with disproof criteria`);
|
|
70
|
+
console.log(` 3. ${chalk.cyan("Investigate")} each hypothesis with evidence`);
|
|
71
|
+
console.log(` 4. Verify ${chalk.cyan("Root Cause")} before fixing`);
|
|
72
|
+
console.log(` 5. Run ${chalk.cyan("whyspec capture")} to save debug reasoning`);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=debug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/commands/debug.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* whyspec execute — Get execution context and track progress for a change.
|
|
3
|
+
*
|
|
4
|
+
* --json mode: returns plan file contents + task progress for agent consumption.
|
|
5
|
+
* Non-JSON mode: displays progress summary with task list.
|
|
6
|
+
*/
|
|
7
|
+
export interface PendingTask {
|
|
8
|
+
line: number;
|
|
9
|
+
description: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TaskProgress {
|
|
12
|
+
total: number;
|
|
13
|
+
completed: number;
|
|
14
|
+
remaining: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ExecuteJsonOutput {
|
|
17
|
+
change_name: string;
|
|
18
|
+
intent_content: string;
|
|
19
|
+
design_content: string;
|
|
20
|
+
tasks_content: string;
|
|
21
|
+
progress: TaskProgress;
|
|
22
|
+
pending_tasks: PendingTask[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse tasks.md for checkbox items, scoped to the ## Tasks section only.
|
|
26
|
+
* Ignores checkboxes in ## Verification and other sections.
|
|
27
|
+
* Recognizes: - [x], - [X] (completed) and - [ ] (pending).
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseTasks(content: string): {
|
|
30
|
+
progress: TaskProgress;
|
|
31
|
+
pending: PendingTask[];
|
|
32
|
+
};
|
|
33
|
+
export declare function executeCommand(name: string | undefined, options: {
|
|
34
|
+
json?: boolean;
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
//# sourceMappingURL=execute.d.ts.map
|