@seanmars/tospec 0.26.0 → 0.27.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/CHANGELOG.md +46 -0
- package/README.md +3 -1
- package/assets/how/page.mjs +235 -0
- package/assets/how/skeleton.html +790 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +8 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/core/shared/skill-generation.d.ts +7 -1
- package/dist/core/shared/skill-generation.d.ts.map +1 -1
- package/dist/core/shared/skill-generation.js +3 -1
- package/dist/core/shared/skill-generation.js.map +1 -1
- package/dist/core/templates/fragments/debugging.d.ts +32 -0
- package/dist/core/templates/fragments/debugging.d.ts.map +1 -0
- package/dist/core/templates/fragments/debugging.js +32 -0
- package/dist/core/templates/fragments/debugging.js.map +1 -0
- package/dist/core/templates/fragments/verify.d.ts +2 -2
- package/dist/core/templates/fragments/verify.d.ts.map +1 -1
- package/dist/core/templates/fragments/verify.js +5 -3
- package/dist/core/templates/fragments/verify.js.map +1 -1
- package/dist/core/templates/skill-templates.d.ts +2 -0
- package/dist/core/templates/skill-templates.d.ts.map +1 -1
- package/dist/core/templates/skill-templates.js +2 -0
- package/dist/core/templates/skill-templates.js.map +1 -1
- package/dist/core/templates/workflows/apply.d.ts.map +1 -1
- package/dist/core/templates/workflows/apply.js +16 -2
- package/dist/core/templates/workflows/apply.js.map +1 -1
- package/dist/core/templates/workflows/explore.js +3 -3
- package/dist/core/templates/workflows/grill.d.ts.map +1 -1
- package/dist/core/templates/workflows/grill.js +3 -1
- package/dist/core/templates/workflows/grill.js.map +1 -1
- package/dist/core/templates/workflows/how.d.ts +3 -0
- package/dist/core/templates/workflows/how.d.ts.map +1 -0
- package/dist/core/templates/workflows/how.js +283 -0
- package/dist/core/templates/workflows/how.js.map +1 -0
- package/dist/core/templates/workflows/issue.d.ts.map +1 -1
- package/dist/core/templates/workflows/issue.js +13 -0
- package/dist/core/templates/workflows/issue.js.map +1 -1
- package/dist/core/templates/workflows/restate-your-goal.d.ts +17 -0
- package/dist/core/templates/workflows/restate-your-goal.d.ts.map +1 -0
- package/dist/core/templates/workflows/restate-your-goal.js +45 -0
- package/dist/core/templates/workflows/restate-your-goal.js.map +1 -0
- package/dist/core/templates/workflows/update.d.ts.map +1 -1
- package/dist/core/templates/workflows/update.js +1 -0
- package/dist/core/templates/workflows/update.js.map +1 -1
- package/package.json +2 -2
- package/schemas/issue/schema.yaml +7 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VERIFY_DOC, VERIFY_POINTER } from '../fragments/verify.js';
|
|
2
2
|
import { VALIDATE_VERDICT_RULE } from '../fragments/validate.js';
|
|
3
|
+
import { PERF_CONFIRMATION, PREMISE_CHECK } from '../fragments/debugging.js';
|
|
3
4
|
/** One parameterized template literal, not a template engine. */
|
|
4
5
|
function buildApplyBody(v) {
|
|
5
6
|
return `**Task tracking is file-based only.** The tracks file's checkboxes (\`- [ ]\` / \`- [x]\`) are the single source of truth for progress. Never use a built-in todo or task-tracking tool — editing the checkbox in the file is the only way progress gets recorded.
|
|
@@ -48,10 +49,14 @@ function buildApplyBody(v) {
|
|
|
48
49
|
|
|
49
50
|
Before checking an item off, re-read its description and confirm every part of it is covered by your changes and the behavior it describes actually works. An item checked off half-finished is the most expensive mistake in this loop.
|
|
50
51
|
|
|
52
|
+
"Actually works" means you ran it: a test, the feedback loop, or a command that drives the real code and would fail if you were wrong. Pointing at the line or walking through the code is not that check. When nothing you can run reaches the behavior (it needs the user's environment or credentials), name the item in your report as not verified by a run rather than present it as proven.
|
|
53
|
+
|
|
51
54
|
**Pause if** the item is unclear, implementation reveals a design issue (suggest \`tospec-update\`), or you hit an error or blocker — report it and wait for guidance. Don't guess.
|
|
52
55
|
|
|
53
56
|
**Pause too if** the item turns out to need work beyond what the specs and the tracks file describe, or you catch yourself wanting to drop, narrow, defer, or make an exception to specified behavior so the item fits — say what the extra scope is and ask. Absorbing it silently is worse than the delay: it turns "done" into a claim the user has no way to check.
|
|
54
57
|
|
|
58
|
+
**Stopping mid-item.** Whenever you stop with an item started but not finished (a pause above, the user stopping you, the session running out), leave its box unchecked and put one line directly under it as a nested bullet: \` - Resume: <done so far>; <what is left>; <next action>\`. Never open the line with \`[\`, which validate reads as a mistyped checkbox. Nothing else records a half-done item: the box says only "not done", so the next pass would redo the finished part or skip the unfinished one. When the item you take has a \`Resume:\` line, start from it: check what it claims is done against the code, then continue rather than redo. Delete the line when you check the item off.
|
|
59
|
+
|
|
55
60
|
${v.sddBranch}
|
|
56
61
|
|
|
57
62
|
${v.issueBranch}
|
|
@@ -74,6 +79,7 @@ ${v.guardrailsHead}
|
|
|
74
79
|
- Keep code changes minimal and scoped to the item at hand
|
|
75
80
|
- Any test you do write goes at the pre-agreed seam (design.md for sdd; the existing/new seam identified for issue) — never against internals
|
|
76
81
|
- Fix root cause: check every caller of a shared function before declaring a fix complete
|
|
82
|
+
- Callers are not a change's whole reach: when the code you change reads or writes data that leaves the function (a persisted file or database column, a serialized or wire format, a config key, a feature flag), find the other readers and writers of that data too — a symbol search does not find them
|
|
77
83
|
- Don't hand off to archive until the full test suite is green`;
|
|
78
84
|
}
|
|
79
85
|
// An assertion that recomputes the expected value the way the code does can
|
|
@@ -84,6 +90,12 @@ const TAUTOLOGICAL_ASSERTIONS = "tautological ones (the expected value computed
|
|
|
84
90
|
// can be found again; nothing else removed it, so it rode into the fix's diff.
|
|
85
91
|
// Only the issue branches carry it: no other workflow adds the tag.
|
|
86
92
|
const DEBUG_LOG_CLEANUP = 'Before checking a task off, grep the project for `[DEBUG-` and delete every tagged log line diagnosis added.';
|
|
93
|
+
// Fixes that keep failing the feedback loop are evidence the diagnosis is
|
|
94
|
+
// wrong, and a fix cannot be right on a wrong Root Cause. Apply never edits
|
|
95
|
+
// task.md's diagnosis on its own, so the way out is a report, not a third fix.
|
|
96
|
+
// The guard sentence points back at Fix Plan, where issue settled whether the
|
|
97
|
+
// triggering state is legitimate, instead of restating that test here.
|
|
98
|
+
const ISSUE_FIX_DISCIPLINE = `A guard, a retry, or a swallowed error at the line that broke is a fix only when \`task.md\`'s Fix Plan found the triggering state legitimate. ${PREMISE_CHECK} Here the assumption is usually \`task.md\`'s Root Cause: if the test shows it is wrong, stop and report it, because no fix is right on a wrong diagnosis, and revising \`task.md\` is \`tospec-update\`'s work.`;
|
|
87
99
|
// Default apply — implement per slice; tests beyond the listed steps are optional, not mandated.
|
|
88
100
|
const APPLY_VARIANT = {
|
|
89
101
|
checkOffRule: 'Take the next unchecked item, implement it, confirm it works against its specs, check it off (\`- [ ]\` → \`- [x]\`), then move to the next.',
|
|
@@ -97,7 +109,7 @@ For each tracer-bullet slice in \`tasks.md\`:
|
|
|
97
109
|
Test steps that \`tasks.md\` lists for a slice are part of that slice. Beyond those, writing a new test is **not required** in this loop — add one when it earns its keep. If you do, put it at the seam \`design.md\` named and don't test internals or add implementation-coupled assertions (mocking internal collaborators, reaching into private state, checking the database instead of the interface) or ${TAUTOLOGICAL_ASSERTIONS}.`,
|
|
98
110
|
issueBranch: `### issue branch — fix root cause
|
|
99
111
|
|
|
100
|
-
Read \`task.md\`'s feedback loop, then fix the root cause, not the symptom — if the same defect is reachable through multiple callers of a shared function, the fix belongs in the shared function, not patched into just the caller the ticket named (grep every caller of the function you're touching). Confirm the fix with \`task.md\`'s feedback loop and keep the existing suite green. ${DEBUG_LOG_CLEANUP}
|
|
112
|
+
Read \`task.md\`'s feedback loop, then fix the root cause, not the symptom — if the same defect is reachable through multiple callers of a shared function, the fix belongs in the shared function, not patched into just the caller the ticket named (grep every caller of the function you're touching). Confirm the fix with \`task.md\`'s feedback loop and keep the existing suite green. ${PERF_CONFIRMATION} ${ISSUE_FIX_DISCIPLINE} ${DEBUG_LOG_CLEANUP}
|
|
101
113
|
|
|
102
114
|
Test steps that \`task.md\` lists are part of the fix. Beyond those, writing a new regression test is **not required** here — add one when the bug is likely to recur, extending the existing test if there's one at the right seam.`,
|
|
103
115
|
// Scoped to tests beyond the listed steps: both branches make those part of
|
|
@@ -140,7 +152,9 @@ Read \`task.md\`'s feedback loop. Then:
|
|
|
140
152
|
- **Existing test, passing** → the bug is an edge case the existing test doesn't cover. Add a new failing test for that edge case first, run it and confirm it fails on the asserted behavior (a compile, import or setup error is not red), then fix.
|
|
141
153
|
- **No existing test** → write the red regression test from \`task.md\`'s feedback loop first, run it and confirm it fails on the asserted behavior (a compile, import or setup error is not red), then fix.
|
|
142
154
|
|
|
143
|
-
Fix root cause, not symptom — if the same defect is reachable through multiple callers of a shared function, the fix belongs in the shared function, not patched into just the caller the ticket named.
|
|
155
|
+
Fix root cause, not symptom — if the same defect is reachable through multiple callers of a shared function, the fix belongs in the shared function, not patched into just the caller the ticket named. ${ISSUE_FIX_DISCIPLINE}
|
|
156
|
+
|
|
157
|
+
${PERF_CONFIRMATION}
|
|
144
158
|
|
|
145
159
|
${DEBUG_LOG_CLEANUP}`,
|
|
146
160
|
guardrailsHead: `- Red before green, always — never write the implementation before its failing test
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/apply.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/apply.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAc7E,iEAAiE;AACjE,SAAS,cAAc,CAAC,CAAe;IACrC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAwC0D,CAAC,CAAC,YAAY;;;;;;;;;;;;;;EAc/E,CAAC,CAAC,SAAS;;EAEX,CAAC,CAAC,WAAW;;;;;;wMAMyL,qBAAqB;;EAE3N,cAAc;;;;;;;EAOd,CAAC,CAAC,cAAc;;;;;;+DAM6C,CAAC;AAChE,CAAC;AAED,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,MAAM,uBAAuB,GAC3B,yOAAyO,CAAC;AAE5O,6EAA6E;AAC7E,+EAA+E;AAC/E,oEAAoE;AACpE,MAAM,iBAAiB,GACrB,8GAA8G,CAAC;AAEjH,0EAA0E;AAC1E,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,uEAAuE;AACvE,MAAM,oBAAoB,GAAG,kJAAkJ,aAAa,kNAAkN,CAAC;AAE/Y,iGAAiG;AAEjG,MAAM,aAAa,GAAiB;IAClC,YAAY,EACV,8IAA8I;IAChJ,SAAS,EAAE;;;;;;;kZAOqY,uBAAuB,GAAG;IAC1a,WAAW,EAAE;;iYAEkX,iBAAiB,IAAI,oBAAoB,IAAI,iBAAiB;;qOAE1N;IACnO,4EAA4E;IAC5E,iFAAiF;IACjF,cAAc,EAAE;;wFAEsE;CACvF,CAAC;AAEF,MAAM,UAAU,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;AAEjD,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,wIAAwI;QACrJ,YAAY,EAAE;;;;EAIhB,UAAU,EAAE;QACV,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,CAAC;QAC3F,UAAU,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE;KACxC,CAAC;AACJ,CAAC;AAED,6CAA6C;AAE7C,MAAM,iBAAiB,GAAiB;IACtC,YAAY,EACV,sIAAsI;IACxI,SAAS,EAAE;;;obAGua,uBAAuB;;;4JAG/S;IAC1J,WAAW,EAAE;;;;;;;0MAO2L,oBAAoB;;EAE5N,iBAAiB;;EAEjB,iBAAiB,EAAE;IACnB,cAAc,EAAE;yCACuB;CACxC,CAAC;AAEF,MAAM,cAAc,GAAG,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAEzD,MAAM,UAAU,kCAAkC;IAChD,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,oJAAoJ;QACjK,YAAY,EAAE;;;;EAIhB,cAAc,EAAE;QACd,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,CAAC;QAC3F,UAAU,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE;KACxC,CAAC;AACJ,CAAC"}
|
|
@@ -28,11 +28,11 @@ ${INTERVIEW_MECHANICS}
|
|
|
28
28
|
|
|
29
29
|
3. **Converge**
|
|
30
30
|
|
|
31
|
-
You're done when you can fully restate the requirement back to the user in your own words and they confirm it's correct — not when you run out of questions.
|
|
31
|
+
You're done when you can fully restate the requirement back to the user in your own words and they confirm it's correct — not when you run out of questions. Step 4 is where that confirmation happens.
|
|
32
32
|
|
|
33
|
-
4. **Restate**
|
|
33
|
+
4. **Restate the whole explore and get it confirmed**
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Run the \`tospec-restate-your-goal\` workflow as a sub-step over the whole explore, not just the last answer: the goal, the problem, the decisions made (with reasoning), and anything explicitly ruled out. It ends by asking the user to confirm or correct. A correction means there's still a hidden branch: go back to step 2 with it, then restate again. Only a confirmed restatement moves on to step 5; it stays in the conversation, so \`tospec-propose\`/\`tospec-issue\` can synthesize it straight from context (that's exactly the input they expect).
|
|
36
36
|
|
|
37
37
|
5. **Record any settled decision — don't ask first**
|
|
38
38
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grill.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"grill.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmDjD,wBAAgB,qBAAqB,IAAI,aAAa,CAerD"}
|
|
@@ -30,7 +30,9 @@ ${INTERVIEW_MECHANICS}
|
|
|
30
30
|
|
|
31
31
|
**Converge**
|
|
32
32
|
|
|
33
|
-
You're done only when you can fully restate the shared understanding
|
|
33
|
+
You're done only when you can fully restate the shared understanding and the user confirms it's right. Running out of questions is not convergence.
|
|
34
|
+
|
|
35
|
+
Run the \`tospec-restate-your-goal\` workflow as a sub-step over the whole grill, with the grill's findings as the extra items: the claims that held up (and any that fell), the assumptions now made explicit, the questions answered, and anything left deliberately open. It ends by asking the user to confirm or correct. If the user corrects the restatement, there's still a hidden branch; keep grilling, then restate again. Only a confirmed restatement moves on to the handoff.
|
|
34
36
|
|
|
35
37
|
**Hand off once the understanding is confirmed**
|
|
36
38
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grill.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BjB,mBAAmB
|
|
1
|
+
{"version":3,"file":"grill.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/grill.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BjB,mBAAmB;;;;;;;;;;;;;0DAaqC,iBAAiB,CAAC,mCAAmC,EAAE,sDAAsD,CAAC;;;;;;oHAMpD,CAAC;AAErH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,mVAAmV;QAChW,YAAY,EAAE;;;;EAIhB,UAAU,EAAE;QACV,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,iEAAiE;QACjE,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KACzG,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"how.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/how.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmPjD,wBAAgB,yBAAyB,IAAI,aAAa,CA0BzD"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How Workflow Template
|
|
3
|
+
*
|
|
4
|
+
* Adapted from pstack's `how`: explain how part of the codebase works at the
|
|
5
|
+
* level a senior engineer needs before changing it. pstack answers in chat with
|
|
6
|
+
* mermaid; this one writes an offline HTML page with interactive diagrams to the
|
|
7
|
+
* system temp directory, so the explanation is easier to follow and the working
|
|
8
|
+
* tree stays untouched.
|
|
9
|
+
*
|
|
10
|
+
* Diagrams are JSON specs the page lays out on a grid in the browser, not
|
|
11
|
+
* mermaid: a mermaid bundle would add ~3 MB to every page, and asking the agent
|
|
12
|
+
* for raw SVG coordinates produces overlaps. The skeleton and `page.mjs` ship
|
|
13
|
+
* as files under `assets/how/` because they are HTML and JS, not prompt prose.
|
|
14
|
+
*
|
|
15
|
+
* The agent writes only the sections, and `page.mjs build` wraps them in the
|
|
16
|
+
* skeleton: retyping the skeleton's ~38 KB per page cost ~10k output tokens
|
|
17
|
+
* and could break the diagrams with one wrong character.
|
|
18
|
+
*/
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
// dist/core/templates/workflows → package root, as for the other shipped assets.
|
|
21
|
+
const ASSET_DIR = new URL('../../../../assets/how/', import.meta.url);
|
|
22
|
+
const EXPLORER_DOC = `# Explorer brief
|
|
23
|
+
|
|
24
|
+
You are one of several explorers tracing different slices of the same subsystem in parallel. The prompt that sent you here gives the question and your angle. Do not try to cover everything: go deep on your angle. You are read-only: read and search, change nothing.
|
|
25
|
+
|
|
26
|
+
## Report
|
|
27
|
+
|
|
28
|
+
### Components
|
|
29
|
+
The key types, functions, modules and services. For each: name, \`path:line\`, and one sentence on what it does.
|
|
30
|
+
|
|
31
|
+
### Flow
|
|
32
|
+
Step by step: what runs, in which file, what it does, what it calls next, and the data passed between steps. Name each decision point and what it branches on.
|
|
33
|
+
|
|
34
|
+
### State
|
|
35
|
+
What persists, what is held only in memory, and what changes it. List any status values and the events that move between them.
|
|
36
|
+
|
|
37
|
+
### Boundaries
|
|
38
|
+
Where this slice meets the rest of the codebase: its inputs, its outputs, and who calls in.
|
|
39
|
+
|
|
40
|
+
### Non-obvious things
|
|
41
|
+
Behavior that is surprising, historically motivated, or easy to get wrong: things that look like they work one way and work another.
|
|
42
|
+
|
|
43
|
+
### Files read
|
|
44
|
+
Every file you read, so the synthesis can cite them.
|
|
45
|
+
|
|
46
|
+
### Open questions
|
|
47
|
+
What you could not trace. Say so plainly: a guess reported as a finding is worse than a gap.
|
|
48
|
+
`;
|
|
49
|
+
const WRITING_DOC = `# Writing the page
|
|
50
|
+
|
|
51
|
+
## The content file
|
|
52
|
+
|
|
53
|
+
You write only the content; \`page.mjs build\` wraps it in \`skeleton.html\`, whose stylesheet, script and Content-Security-Policy reach the page unchanged. Never read, copy or edit the skeleton or the built page. The file starts with four header lines, then a line that is exactly \`---\`, then the sections:
|
|
54
|
+
|
|
55
|
+
\`\`\`html
|
|
56
|
+
lang: zh-Hant-TW
|
|
57
|
+
title: How the CLI derives artifact status
|
|
58
|
+
question: How does the status command know each artifact's state?
|
|
59
|
+
meta: my-project · 2026-10-23
|
|
60
|
+
---
|
|
61
|
+
<section id="overview">
|
|
62
|
+
<h2>Overview</h2>
|
|
63
|
+
<p class="lede">...</p>
|
|
64
|
+
</section>
|
|
65
|
+
\`\`\`
|
|
66
|
+
|
|
67
|
+
- \`lang\` is the language you answer in (\`zh-Hant-TW\`, \`en\`, ...); it also picks the language of the page's buttons.
|
|
68
|
+
- \`title\`, \`question\` (the user's question) and \`meta\` (project name and date) are plain text: the build escapes them, so write \`<\` and \`&\` as they are. \`meta\` may be empty.
|
|
69
|
+
- Everything after \`---\` is HTML and goes into the page as written, so escape \`<\`, \`>\` and \`&\` in the text there yourself. No \`<html>\`, \`<head>\`, \`<body>\` or \`<style>\`: the skeleton has them.
|
|
70
|
+
|
|
71
|
+
## Sections
|
|
72
|
+
|
|
73
|
+
Each section is a \`<section>\` with an \`<h2>\`; the page builds its table of contents from them. Use the ones that apply, in this order:
|
|
74
|
+
|
|
75
|
+
- **Overview** — one or two paragraphs: what this is, what it does, why it exists. Open with \`<p class="lede">\`. A reader who stops here can still decide whether to read on.
|
|
76
|
+
- **Key Concepts** — the types, services and abstractions the rest depends on, as a concept grid. Short definitions, not an inventory.
|
|
77
|
+
- **How It Works** — the core, and the longest section. What triggers it, what happens step by step, where data goes, where it branches. Lead with the diagram, then walk it in prose or a numbered step list.
|
|
78
|
+
- **Where Things Live** — a short file map: only what someone needs to start working here.
|
|
79
|
+
- **Gotchas** — non-obvious behavior, historical context, pitfalls, and every place the code disagrees with a spec or an ADR. Skip it when there is nothing.
|
|
80
|
+
- **Open Questions** — what could not be traced. Skip it when there is nothing.
|
|
81
|
+
|
|
82
|
+
## Style
|
|
83
|
+
|
|
84
|
+
- Concrete over abstract: "\`archive\` calls \`applySpecs()\`", not "the command delegates to a helper".
|
|
85
|
+
- When something is complex, say why it is complex, not only what it does. When it is simple, do not pad it.
|
|
86
|
+
- Prose, not pseudocode. Cite \`path:line\` so the reader knows where to look; quote code only when a snippet is essential to the point.
|
|
87
|
+
- Use an analogy when one helps; never force one.
|
|
88
|
+
- Write in the language of the conversation. Identifiers, paths and established technical terms stay as they are.
|
|
89
|
+
|
|
90
|
+
## Choosing diagrams
|
|
91
|
+
|
|
92
|
+
| The reader needs to see | Diagram |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| Which parts exist and what depends on what | architecture: \`flow\` with \`groups\` for layers or processes |
|
|
95
|
+
| Who calls whom, in what order, for one request or command | \`sequence\` |
|
|
96
|
+
| The lifecycle of one thing: its statuses and what moves it | state: \`flow\` with \`state\` nodes, \`start\` / \`end\`, and events on the edges |
|
|
97
|
+
| Branching logic | flowchart: \`flow\` with \`decision\` nodes |
|
|
98
|
+
|
|
99
|
+
A diagram has to explain something the prose would explain worse; skip it when prose covers the point. Keep each one to 12 nodes or fewer (a sequence: 6 participants, 14 messages). Split a bigger picture into an overview and a zoom-in. Add \`steps\` when order matters: the reader walks them with Previous / Next (or the arrow keys), and each step lights up its part of the diagram.
|
|
100
|
+
|
|
101
|
+
## Diagram specs
|
|
102
|
+
|
|
103
|
+
Put a spec in a figure and the page draws it:
|
|
104
|
+
|
|
105
|
+
\`\`\`html
|
|
106
|
+
<figure class="diagram">
|
|
107
|
+
<script type="application/json">{ "type": "flow", ... }</script>
|
|
108
|
+
<figcaption>What this diagram shows</figcaption>
|
|
109
|
+
</figure>
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
The JSON must be valid (double quotes, no trailing commas, no comments) and must not contain \`</script\`.
|
|
113
|
+
|
|
114
|
+
### flow
|
|
115
|
+
|
|
116
|
+
\`\`\`json
|
|
117
|
+
{
|
|
118
|
+
"type": "flow",
|
|
119
|
+
"groups": [{ "label": "CLI process", "cols": [0, 1], "rows": [0, 0] }],
|
|
120
|
+
"nodes": [
|
|
121
|
+
{ "id": "cli", "label": "commander program", "col": 0, "row": 0, "note": "Parses argv and dispatches to a command.", "ref": "src/cli/index.ts:422" },
|
|
122
|
+
{ "id": "cmd", "label": "statusCommand", "col": 1, "row": 0 },
|
|
123
|
+
{ "id": "fs", "label": "change directory", "kind": "store", "col": 1, "row": 1 }
|
|
124
|
+
],
|
|
125
|
+
"edges": [
|
|
126
|
+
{ "from": "cli", "to": "cmd", "label": "status --json" },
|
|
127
|
+
{ "from": "cmd", "to": "fs", "label": "reads files", "dashed": true }
|
|
128
|
+
],
|
|
129
|
+
"steps": [
|
|
130
|
+
{ "title": "Dispatch", "text": "commander matches the subcommand.", "show": ["cli", "cli->cmd"] },
|
|
131
|
+
{ "title": "Derive status", "text": "Status comes from which files exist.", "show": ["cmd->fs"] }
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
\`\`\`
|
|
135
|
+
|
|
136
|
+
- **Grid**: \`col\` and \`row\` count from 0. Each cell is 220 × 116 px and holds one node; two nodes in one cell is an error. A fractional value (\`0.5\`) centres a node between two cells.
|
|
137
|
+
- **Layout**: run the main path left to right (or top to bottom) in reading order. Put a store below or beside what writes it, and external systems at the edges. An edge that would cross another node bends around it by itself; set \`"bend": 60\` (px, the sign picks the side) to override.
|
|
138
|
+
- **Groups**: \`cols\` and \`rows\` are inclusive \`[first, last]\` ranges. Use them for a layer, a process or a package boundary.
|
|
139
|
+
- **Node kinds**: \`box\` (the default: module, function, service), \`store\` (database, file, cache), \`external\` (outside the codebase), \`actor\` (a person or a calling tool), \`decision\` (a branch; label it as a question), \`state\`, \`start\`, \`end\`.
|
|
140
|
+
- **Labels**: a name, not a sentence. About 20 Latin or 10 CJK characters a line, three lines at most; \`\\n\` forces a break. The explanation goes in \`note\`, shown when the reader clicks the node or edge; \`ref\` adds a copyable \`path:line\`.
|
|
141
|
+
- **Edges**: \`label\` names what moves (a call, an event, data). \`"dashed": true\` marks an async, optional or read-only link. In a state diagram the label is the event or condition.
|
|
142
|
+
- **Steps**: \`show\` lists node ids and \`"from->to"\` edges; an edge lights its two ends with it.
|
|
143
|
+
|
|
144
|
+
### sequence
|
|
145
|
+
|
|
146
|
+
\`\`\`json
|
|
147
|
+
{
|
|
148
|
+
"type": "sequence",
|
|
149
|
+
"participants": [
|
|
150
|
+
{ "id": "user", "label": "User", "kind": "actor" },
|
|
151
|
+
{ "id": "cmd", "label": "archive command", "ref": "src/commands/archive.ts" },
|
|
152
|
+
{ "id": "merge", "label": "specs-apply" },
|
|
153
|
+
{ "id": "fs", "label": "file system", "kind": "store" }
|
|
154
|
+
],
|
|
155
|
+
"messages": [
|
|
156
|
+
{ "from": "user", "to": "cmd", "label": "archive <name>" },
|
|
157
|
+
{ "divider": "Validate" },
|
|
158
|
+
{ "from": "cmd", "to": "cmd", "label": "re-validate deltas", "note": "Any ERROR stops the archive here." },
|
|
159
|
+
{ "divider": "Merge" },
|
|
160
|
+
{ "from": "cmd", "to": "merge", "label": "applySpecs()" },
|
|
161
|
+
{ "from": "merge", "to": "fs", "label": "write specs/" },
|
|
162
|
+
{ "from": "merge", "to": "cmd", "label": "merged", "reply": true }
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
\`\`\`
|
|
166
|
+
|
|
167
|
+
- Participants are columns, left to right in the order a request first reaches them.
|
|
168
|
+
- Each message is a row. \`"reply": true\` draws a dashed return; \`from\` equal to \`to\` is a self-call; \`{ "divider": "..." }\` labels a phase.
|
|
169
|
+
- Every message is a step on its own, with its \`note\` as the step text. Set \`"steps": false\` to turn that off.
|
|
170
|
+
|
|
171
|
+
### Hand-drawn SVG
|
|
172
|
+
|
|
173
|
+
When neither type fits, put an \`<svg viewBox="...">\` straight into the figure, with no \`<script>\`. Use the page's classes so it matches: \`<g class="node k-store">\` around a shape and its \`<text>\`, \`<g class="edge">\` around a \`<path class="line">\`. Add \`data-key\`, \`data-title\` and \`data-note\` to a group to make it clickable. Nothing lays this out for you, so check every coordinate.
|
|
174
|
+
|
|
175
|
+
## Components
|
|
176
|
+
|
|
177
|
+
\`\`\`html
|
|
178
|
+
<section id="overview">
|
|
179
|
+
<h2>Overview</h2>
|
|
180
|
+
<p class="lede">The answer in one paragraph.</p>
|
|
181
|
+
</section>
|
|
182
|
+
|
|
183
|
+
<dl class="concepts">
|
|
184
|
+
<div><dt>Artifact graph <code class="ref">src/core/artifact-graph/</code></dt><dd>What it is, in one or two sentences.</dd></div>
|
|
185
|
+
</dl>
|
|
186
|
+
|
|
187
|
+
<ol class="steps">
|
|
188
|
+
<li><strong>Resolve the root.</strong> Walk up to the nearest directory holding the project folder. <code class="ref">src/core/root-selection.ts:12</code></li>
|
|
189
|
+
</ol>
|
|
190
|
+
|
|
191
|
+
<table>
|
|
192
|
+
<tr><th>Path</th><th>What lives there</th></tr>
|
|
193
|
+
<tr><td><code class="ref">src/commands/</code></td><td>One file per command body.</td></tr>
|
|
194
|
+
</table>
|
|
195
|
+
|
|
196
|
+
<aside class="callout warn"><strong>Title</strong><p>A gotcha.</p></aside>
|
|
197
|
+
<aside class="callout open"><strong>Title</strong><p>An open question.</p></aside>
|
|
198
|
+
<aside class="callout note"><strong>Title</strong><p>A side note.</p></aside>
|
|
199
|
+
|
|
200
|
+
<details><summary>Deep dive: ...</summary><p>Detail most readers can skip.</p></details>
|
|
201
|
+
\`\`\`
|
|
202
|
+
|
|
203
|
+
A \`<code class="ref">\` copies its text when clicked: use it for every path and \`path:line\`, and plain \`<code>\` for identifiers.
|
|
204
|
+
|
|
205
|
+
## Before reporting
|
|
206
|
+
|
|
207
|
+
\`page.mjs build\` checks the page it writes. It fails on a missing header value, a whole page pasted in as content, an unknown node id, two nodes in one cell, a label too long for three lines, invalid JSON, anything loaded from outside the file, and a file outside the temp directory. Fix every FAIL line in the content file and build again. It cannot judge the writing, so also confirm that every claim about the code carries a \`path\` or \`path:line\`.
|
|
208
|
+
`;
|
|
209
|
+
const HOW_BODY = `**This is read-only on the project.** Read files, search code, and run read-only \`tospec\` commands; write no code, source edits, or artifact files. The one write is the HTML page, and it goes to the system temp directory, never inside the project, so explaining leaves the working tree as it was.
|
|
210
|
+
|
|
211
|
+
**Steps**
|
|
212
|
+
|
|
213
|
+
1. **Start from what the project already says**
|
|
214
|
+
|
|
215
|
+
If \`tospec/specs/\` has a capability this question touches, read its spec first: it says what the code is meant to do, which tells you what to look for. Do the same with the \`accepted\` ADRs in \`tospec/decisions/\` (\`index.md\` lists them) for why it is shaped this way. The code is what runs: where it disagrees with a spec or an ADR, explain the code and report the gap under Gotchas.
|
|
216
|
+
|
|
217
|
+
2. **Size the question**
|
|
218
|
+
|
|
219
|
+
- **Simple** — one module, one utility, one function: explore it yourself, then go to step 4.
|
|
220
|
+
- **Complex** — a subsystem across several files or services, a cross-cutting feature, an architectural overview: go to step 3.
|
|
221
|
+
|
|
222
|
+
When in doubt, take the simple path.
|
|
223
|
+
|
|
224
|
+
3. **Explore in parallel (complex only)**
|
|
225
|
+
|
|
226
|
+
Split the question into 2–4 angles, each a distinct slice (for example: entry points and wiring, the core data flow, persistence and state, error paths). If your tool can spawn subagents, spawn one read-only explorer per angle in a single message. Each prompt holds only the question, that explorer's angle, and the instruction to read \`EXPLORER.md\` at its path in this skill's directory and report in its shape; never paste the file into the prompt, which retypes it once per explorer. Otherwise work the angles yourself, one at a time, keeping notes in the shape \`EXPLORER.md\` gives. Then reconcile: merge overlaps, and settle any contradiction by reading the code yourself rather than picking one account.
|
|
227
|
+
|
|
228
|
+
4. **Plan the page**
|
|
229
|
+
|
|
230
|
+
Follow \`WRITING.md\`: which sections apply, and which diagram answers which part of the question. Decide the diagrams before writing prose: the prose then walks the reader through them.
|
|
231
|
+
|
|
232
|
+
5. **Write the page**
|
|
233
|
+
|
|
234
|
+
1. Get the output folder from \`page.mjs\` beside this file (it creates the folder if needed):
|
|
235
|
+
\`\`\`bash
|
|
236
|
+
node <this skill's directory>/page.mjs dir
|
|
237
|
+
\`\`\`
|
|
238
|
+
2. Write the content file \`<output folder>/<topic-slug>-<yyyyMMdd-HHmmss>.content.html\` in the format \`WRITING.md\` gives: the header lines, \`---\`, then the sections built from its components and diagram specs. Write only that: the build wraps it in \`skeleton.html\` beside this file, so never read or copy the skeleton.
|
|
239
|
+
3. Build the page; it is written beside the content file as \`<same name>.html\` and checked:
|
|
240
|
+
\`\`\`bash
|
|
241
|
+
node <this skill's directory>/page.mjs build <content file>
|
|
242
|
+
\`\`\`
|
|
243
|
+
Fix every FAIL line in the content file and build again. Never edit the built page: the next build overwrites it.
|
|
244
|
+
|
|
245
|
+
6. **Report**
|
|
246
|
+
|
|
247
|
+
In the conversation, answer the question in 2–4 sentences (the gist of the Overview) and give the page's absolute path. Do not paste the whole explanation into the chat: the page is the explanation. Offer to open it in the default browser, and open it only when the user says so.
|
|
248
|
+
|
|
249
|
+
**Guardrails**
|
|
250
|
+
- **Never write inside the project** — the page lives only in the temp directory
|
|
251
|
+
- **Explain the code that runs** — not the code a spec or ADR describes; report the difference instead
|
|
252
|
+
- **Name the gaps** — whatever you could not trace goes under Open Questions; never paper over it`;
|
|
253
|
+
function readAsset(name) {
|
|
254
|
+
return readFileSync(new URL(name, ASSET_DIR), 'utf-8');
|
|
255
|
+
}
|
|
256
|
+
export function getTospecHowSkillTemplate() {
|
|
257
|
+
return {
|
|
258
|
+
name: 'tospec-how',
|
|
259
|
+
description: 'Explain how part of the codebase works as an offline HTML page with architecture, sequence, state and flow diagrams, written to the system temp directory. Covers "how does X work", walkthroughs before changing something, and placement or layering questions ("where should this live", "which layer owns this"). Use for /tospec-how.',
|
|
260
|
+
instructions: `Explain how part of this codebase works — a subsystem, a flow, a module — at the level a senior engineer needs to build a working mental model before changing it, as an offline HTML page with diagrams.
|
|
261
|
+
|
|
262
|
+
**Input**: The question: "how does X work", a code path to walk through before a change, or a placement question ("where should this live", "which layer owns this"). When the scope is ambiguous, state your interpretation and go; the user can redirect.
|
|
263
|
+
|
|
264
|
+
${HOW_BODY}`,
|
|
265
|
+
license: 'MIT',
|
|
266
|
+
compatibility: 'Requires tospec CLI and Node.js.',
|
|
267
|
+
metadata: { author: 'tospec' },
|
|
268
|
+
// Explicit invocation only, as pstack's original is. "How does X work" is
|
|
269
|
+
// an everyday question, and auto-triggering on it turns a two-sentence
|
|
270
|
+
// answer into subagents, an HTML page and three permission prompts. No
|
|
271
|
+
// workflow runs this as a sub-step, so nothing depends on the model
|
|
272
|
+
// reaching it on its own.
|
|
273
|
+
disableModelInvocation: true,
|
|
274
|
+
allowedTools: ['Bash(tospec:*)', 'Read', 'Grep', 'Glob'],
|
|
275
|
+
extraFiles: {
|
|
276
|
+
'EXPLORER.md': EXPLORER_DOC,
|
|
277
|
+
'WRITING.md': WRITING_DOC,
|
|
278
|
+
'skeleton.html': readAsset('skeleton.html'),
|
|
279
|
+
'page.mjs': readAsset('page.mjs'),
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=how.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"how.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/how.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,iFAAiF;AACjF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,yBAAyB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAEtE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BpB,CAAC;AAEF,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+JnB,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kGA2CiF,CAAC;AAEnG,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,YAAY,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,4UAA4U;QACzV,YAAY,EAAE;;;;EAIhB,QAAQ,EAAE;QACR,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,kCAAkC;QACjD,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,0EAA0E;QAC1E,uEAAuE;QACvE,uEAAuE;QACvE,oEAAoE;QACpE,0BAA0B;QAC1B,sBAAsB,EAAE,IAAI;QAC5B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QACxD,UAAU,EAAE;YACV,aAAa,EAAE,YAAY;YAC3B,YAAY,EAAE,WAAW;YACzB,eAAe,EAAE,SAAS,CAAC,eAAe,CAAC;YAC3C,UAAU,EAAE,SAAS,CAAC,UAAU,CAAC;SAClC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAsFjD,wBAAgB,2BAA2B,IAAI,aAAa,CAc3D"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { VALIDATE_VERDICT_RULE } from '../fragments/validate.js';
|
|
2
|
+
import { GIT_COMMAND_RULE } from '../fragments/change-diff.js';
|
|
3
|
+
import { LEGITIMATE_STATE_RULE, PERF_MEASUREMENT, PREMISE_CHECK } from '../fragments/debugging.js';
|
|
2
4
|
const ISSUE_BODY = `Diagnose before you propose a fix. Jumping to a hypothesis before you can reproduce the bug on command is the exact failure this workflow prevents.
|
|
3
5
|
|
|
4
6
|
**Planning boundary**: The request that triggered this workflow authorizes diagnosis only, even if it asks to fix something. Diagnosis includes the feedback loop's failing test (step 3) and temporary \`[DEBUG-xxxx]\` logging (step 5). Do not edit project code beyond those, and do not start implementation in the same response: present the ticket and \`task.md\`, then wait for a new user request before starting \`tospec-apply\`.
|
|
@@ -29,20 +31,28 @@ const ISSUE_BODY = `Diagnose before you propose a fix. Jumping to a hypothesis b
|
|
|
29
31
|
|
|
30
32
|
Do not skip this to go read code and form a theory. No red-capable command, no hypotheses.
|
|
31
33
|
|
|
34
|
+
${PERF_MEASUREMENT}
|
|
35
|
+
|
|
32
36
|
4. **Rank falsifiable hypotheses**
|
|
33
37
|
|
|
38
|
+
Two sources are worth a look before you rank. **A regression** (it used to work): the commit that broke it is a candidate. \`git log -S '<symbol>'\` or \`git log -L <start>,<end>:<file>\` on the code the loop drives lists the commits that changed it. \`git bisect run\` with the loop's command finds the commit directly, but it moves the checkout, so ask the user before starting it. A commit is not a cause: read its diff and rank the mechanism it changed. **A symptom that appears only after a restart**: suspect persisted state first (config files, caches, lock files, serialized data). ${GIT_COMMAND_RULE}
|
|
39
|
+
|
|
34
40
|
List as many as the evidence genuinely supports — when the feedback loop already points at one cause, one or two is fine. Each hypothesis must predict something checkable: "if X is the cause, changing Y makes the bug disappear." A hypothesis you can't falsify is a vibe — sharpen it or drop it. Show the ranked list to the user before testing; they often have context that instantly re-ranks it ("we just touched that module"). Then continue verifying without waiting for a reply: if the user later supplies information that changes the order, re-rank and continue from the new top.
|
|
35
41
|
|
|
36
42
|
5. **Verify hypotheses one at a time**
|
|
37
43
|
|
|
38
44
|
Change one variable per probe. Tag any temporary debug logging with a unique prefix (\`[DEBUG-xxxx]\`) so cleanup is one grep. Stop at the first hypothesis the loop from step 3 confirms.
|
|
39
45
|
|
|
46
|
+
${PREMISE_CHECK} If the assumption is false, re-rank from what the failed probes share that it did not predict. If every hypothesis is refuted, go back to step 4 with the new evidence: task.md is written on a confirmed cause only.
|
|
47
|
+
|
|
40
48
|
6. **Write the diagnosis into task.md**
|
|
41
49
|
\`\`\`bash
|
|
42
50
|
tospec instructions task --change "<name>" --json
|
|
43
51
|
\`\`\`
|
|
44
52
|
Include: the symptom and how to reproduce it, the verified root cause (not a guess — how you verified it), why existing tests didn't already catch this, the fix plan, the test plan, and a checkbox task list for \`tospec-apply\`. This is where the issue's detail lives (the ticket only summarizes).
|
|
45
53
|
|
|
54
|
+
**Place the fix before you plan it.** ${LEGITIMATE_STATE_RULE} Then name the one fact the fix is safe because of (e.g. "no other caller passes null"), and how you established it: by running code that would fail if the fact were false, or, when nothing can run it, by the \`file:line\` that shows it, marked unproven. Fix Plan carries both.
|
|
55
|
+
|
|
46
56
|
**Before moving on, reconcile Test Plan against Tasks.** Walk the Test Plan's "tests to add" items one by one and name the task that covers each. Every item must either map to a numbered task or say in the Test Plan why it needs none. Nothing checks this later: \`tospec validate\` sees two prose sections, and apply reports done when the Tasks boxes are ticked — so an item that never became a task is silently lost, and the change still looks complete.
|
|
47
57
|
|
|
48
58
|
7. **Delta specs — only if behavior changes**
|
|
@@ -63,8 +73,11 @@ Summarize the confirmed root cause, the fix plan, and prompt: "Run \`tospec-appl
|
|
|
63
73
|
- The request that invoked this workflow authorizes diagnosis only. Any fix instruction in it does not carry forward: don't edit project code beyond the feedback loop's failing test and temporary \`[DEBUG-xxxx]\` logging, and don't start \`tospec-apply\` in the same response — stop after presenting the ticket and \`task.md\` and wait for a new request
|
|
64
74
|
- The ticket file and its timestamp are CLI-generated — never create, rename, or move ticket files; only edit the Summary in the existing stub
|
|
65
75
|
- No hypotheses before a red-capable feedback loop exists
|
|
76
|
+
- A performance loop's number carries its run count, range, and limiter before any hypothesis rests on it
|
|
66
77
|
- Ranked, falsifiable hypotheses — as many as the evidence supports, never an unverified guess
|
|
67
78
|
- Root cause must be verified, not assumed — state how you confirmed it
|
|
79
|
+
- Two failed probes on one assumption: test the assumption before a third probe
|
|
80
|
+
- Fix Plan says why the fix is not a guard over an illegitimate state, and names the one fact it is safe because of, proven or marked unproven
|
|
68
81
|
- Every secret in pasted commands and output becomes \`<REDACTED>\`; steps that need the user's login are theirs to run, uncaptured
|
|
69
82
|
- Every Test Plan item maps to a task, or the Test Plan says why it needs none
|
|
70
83
|
- Don't write \`specs\` unless the fix actually changes external behavior`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/issue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEnG,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8Bd,gBAAgB;;;;mlBAI8jB,gBAAgB;;;;;;;;KAQ9lB,aAAa;;;;;;;;2CAQyB,qBAAqB;;;;;;;;;;;;KAY3D,qBAAqB;;;;;;;;;;;;;;;;;0EAiBgD,CAAC;AAE3E,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,6NAA6N;QAC1O,YAAY,EAAE;;;;EAIhB,UAAU,EAAE;QACV,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KACnF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Restate-Your-Goal Workflow Template
|
|
3
|
+
*
|
|
4
|
+
* Adapted from pstack's `in-your-own-words`: the agent says back, in its own
|
|
5
|
+
* words, what it thinks the user wants and why, so a misunderstanding surfaces
|
|
6
|
+
* before work builds on it. Read-only; unlike grill it interrogates nothing and
|
|
7
|
+
* hands off nothing — the user's reply decides what happens next.
|
|
8
|
+
*
|
|
9
|
+
* pstack's original is explicit-invocation only. This one stays model-invocable
|
|
10
|
+
* because `tospec-explore` and `tospec-grill` run it as the sub-step that
|
|
11
|
+
* confirms their conclusion, so it also has to say how to hand control back
|
|
12
|
+
* to a host workflow. Its prose names no host: a `tospec-<id>` mention reads
|
|
13
|
+
* as a dependency to findWorkflowReferenceGaps, and restate needs neither host.
|
|
14
|
+
*/
|
|
15
|
+
import type { SkillTemplate } from '../types.js';
|
|
16
|
+
export declare function getTospecRestateYourGoalSkillTemplate(): SkillTemplate;
|
|
17
|
+
//# sourceMappingURL=restate-your-goal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restate-your-goal.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/restate-your-goal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgCjD,wBAAgB,qCAAqC,IAAI,aAAa,CAcrE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const RESTATE_BODY = `**This is a check on your understanding, not a step forward.** Read files and run read-only \`tospec\` commands if they help; write no code, source edits, or artifact files.
|
|
2
|
+
|
|
3
|
+
**Ground it in what is already here**
|
|
4
|
+
|
|
5
|
+
1. **The conversation** is the primary source: what the user asked for, what they corrected, what they rejected.
|
|
6
|
+
2. **The change under discussion**, if the conversation is about exactly one: read its planning artifacts (\`tospec status --change "<name>" --json\` lists them) so the restatement agrees with what is written, or says where it does not.
|
|
7
|
+
3. **Nothing to restate** — no request in context and no change under discussion: say so and stop. Do not invent a goal.
|
|
8
|
+
|
|
9
|
+
**Write the restatement**
|
|
10
|
+
|
|
11
|
+
Use your own words. Echoing the user's phrasing hides a misunderstanding; a paraphrase exposes it. Keep it short:
|
|
12
|
+
|
|
13
|
+
- **Goal** — what the user wants to be true when this is done.
|
|
14
|
+
- **Problem** — what is wrong or missing now, and who it affects.
|
|
15
|
+
- **Decided** — choices the conversation settled, each with the reason it won. Omit when nothing was settled.
|
|
16
|
+
- **Out of scope** — what was explicitly ruled out. Omit when nothing was.
|
|
17
|
+
- **Assumptions** — what you inferred but the user never said. Mark each one as your guess.
|
|
18
|
+
|
|
19
|
+
A host workflow that runs this as a sub-step may name extra items to cover (e.g. a grill's claims that held up and questions left open); add them after these.
|
|
20
|
+
|
|
21
|
+
Restate the goal, not the solution. When the user asked for a specific implementation, name the problem it is meant to solve; when you cannot tell what that problem is, say so instead of filling the gap.
|
|
22
|
+
|
|
23
|
+
**Stop and let the user answer**
|
|
24
|
+
|
|
25
|
+
End by asking the user to confirm or correct the restatement, then stop. If they correct it, restate again with the correction folded in. Running out of things to say is not confirmation; only the user's "yes" is.
|
|
26
|
+
|
|
27
|
+
After the user confirms:
|
|
28
|
+
- **Run as a sub-step of another workflow**: return to that workflow's next step. The confirmed restatement stays in the conversation as its input.
|
|
29
|
+
- **Run on its own**: stop there. Do not resume earlier work in the same turn; the user's next message decides what happens.`;
|
|
30
|
+
export function getTospecRestateYourGoalSkillTemplate() {
|
|
31
|
+
return {
|
|
32
|
+
name: 'tospec-restate-your-goal',
|
|
33
|
+
description: "Restate in your own words what you think the user's goal is and what problem they are trying to solve, then wait for them to confirm or correct it. Use when the user asks you to restate, summarize what they want, or check you are on the same page, and when a discussion has converged and its conclusion needs the user's confirmation before anything is written.",
|
|
34
|
+
instructions: `Restate in your own words what you think the user's goal is and what problem they are trying to solve.
|
|
35
|
+
|
|
36
|
+
**Input**: Optional. A focus for the restatement (a change name, or one part of the request). When empty, restate the goal behind the whole conversation so far.
|
|
37
|
+
|
|
38
|
+
${RESTATE_BODY}`,
|
|
39
|
+
license: 'MIT',
|
|
40
|
+
compatibility: 'Requires tospec CLI.',
|
|
41
|
+
metadata: { author: 'tospec' },
|
|
42
|
+
allowedTools: ['Bash(tospec:*)', 'Read', 'Grep', 'Glob'],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=restate-your-goal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restate-your-goal.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/restate-your-goal.ts"],"names":[],"mappings":"AAgBA,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;6HA4BwG,CAAC;AAE9H,MAAM,UAAU,qCAAqC;IACnD,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,0WAA0W;QACvX,YAAY,EAAE;;;;EAIhB,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../src/core/templates/workflows/update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA+EjD,wBAAgB,4BAA4B,IAAI,aAAa,CAc5D"}
|
|
@@ -39,6 +39,7 @@ const UPDATE_BODY = `**Steps**
|
|
|
39
39
|
|
|
40
40
|
This is the only step that writes files.
|
|
41
41
|
- Show each drafted revision and why. Write it only after the user confirms.
|
|
42
|
+
- Apply a confirmed revision as edits to the passages it changes, and leave the rest of the file as it is. Rewrite a whole file only when the revision replaces most of it: retyping an artifact to change one paragraph costs its full length, and any slip on the way alters text the user never saw in the revision.
|
|
42
43
|
- If the user rejects a revision, leave that artifact unchanged.
|
|
43
44
|
- When a substantial rewrite is needed, get that artifact's rules and template first:
|
|
44
45
|
\`\`\`bash
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/update.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,WAAW,GAAG
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../../src/core/templates/workflows/update.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8CAoD0B,qBAAqB;;;KAG9D,iBAAiB,CAAC,mCAAmC,EAAE,uDAAuD,CAAC;;;;;;;;;;;;;;;;;;oLAkBgE,CAAC;AAErL,MAAM,UAAU,4BAA4B;IAC1C,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,oPAAoP;QACjQ,YAAY,EAAE;;;;EAIhB,WAAW,EAAE;QACX,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,sBAAsB;QACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9B,YAAY,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;KAC7F,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seanmars/tospec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Spec-driven development CLI for structured requirements and issue workflows",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://www.npmjs.com/package/@seanmars/tospec",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@types/cross-spawn": "^6.0.6",
|
|
38
38
|
"@types/node": "^24.13.4",
|
|
39
39
|
"typescript": "^7.0.2",
|
|
40
|
-
"vitest": "^5.0.
|
|
40
|
+
"vitest": "^5.0.5"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@inquirer/core": "^12.0.3",
|