@skitterbyte/skitterspec 18.0.0 → 20.0.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.
Files changed (38) hide show
  1. package/MIGRATION.md +296 -10
  2. package/README.md +53 -4
  3. package/assets/claude-md-section.md +38 -2
  4. package/assets/commands/spec-connect.md +2 -2
  5. package/assets/commands/spec-live.md +2 -2
  6. package/assets/core/env.config.json.example +7 -3
  7. package/assets/core/env.config.md +90 -30
  8. package/assets/hooks/review-gate.js +141 -0
  9. package/assets/review/page.html +1787 -0
  10. package/assets/rules/spec-planning.md +250 -10
  11. package/assets/rules/spec-reports.md +321 -0
  12. package/assets/skills/spec/SKILL.md +32 -4
  13. package/assets/skills/spec-bug/SKILL.md +113 -8
  14. package/assets/skills/spec-cancel/SKILL.md +84 -19
  15. package/assets/skills/spec-complete/SKILL.md +80 -23
  16. package/assets/skills/spec-diff/SKILL.md +678 -0
  17. package/assets/skills/spec-hotfix/SKILL.md +113 -10
  18. package/assets/skills/spec-init/SKILL.md +56 -7
  19. package/assets/skills/spec-next/SKILL.md +408 -7
  20. package/assets/skills/spec-review/SKILL.md +26 -3
  21. package/assets/skills/spec-reviewed/SKILL.md +258 -0
  22. package/assets/skills/spec-start/SKILL.md +283 -106
  23. package/assets/skills/spec-to-main/SKILL.md +28 -6
  24. package/package.json +11 -7
  25. package/src/cli.js +1808 -89
  26. package/src/env/building.js +143 -0
  27. package/src/env/commitcmd.js +108 -0
  28. package/src/env/config.js +58 -9
  29. package/src/env/hooks.js +117 -0
  30. package/src/env/provision.js +54 -15
  31. package/src/env/proxy.js +34 -1
  32. package/src/env/render.js +3 -12
  33. package/src/env/resolve.js +295 -9
  34. package/src/env/review.js +1536 -0
  35. package/src/env/serve.js +573 -0
  36. package/src/env/teardown.js +13 -6
  37. package/src/init.js +150 -1
  38. package/LICENSE +0 -21
@@ -5,6 +5,11 @@ description: Fix a production bug on the exact released version — fork a workt
5
5
 
6
6
  # /spec-hotfix — fix a released version, tag it, cherry-pick back to main
7
7
 
8
+ > Stay silent while this runs — speak only to ask something you cannot answer
9
+ > yourself, or to report a failure at the moment it happens. Read
10
+ > `.claude/rules/spec-reports.md` before reporting; it defines the block this
11
+ > skill ends with.
12
+
8
13
  This is the **hotfix** counterpart to `/spec-bug`. Same test-first discipline
9
14
  (reproduce as a **failing test (RED)**, then drive to **GREEN**), but the base is
10
15
  a **release tag**, not `main`: prod is running a tagged version, so the fix must
@@ -61,8 +66,7 @@ that header — must exist **before** `spec-env up`:
61
66
  `## Symptom` you established. It starts in `in-progress` — work begins now.
62
67
  - Run `skitterspec spec-env up hotfix-<name>`. It prints a `git worktree add …
63
68
  -b hotfix/<slug> <tag>` command (the branch forks from **the tag**, not
64
- `main`), the worktree path, the opener, and any `in the worktree, run:`
65
- bootstrap steps.
69
+ `main`), the worktree path, and any `in the worktree, run:` bootstrap steps.
66
70
  - Run the printed `git worktree add`, then **move the stub across yourself.**
67
71
  This is where a hotfix differs from `/spec-bug`, which no longer needs the move:
68
72
  that skill's worktree forks from `main`, so committing the stub puts it there,
@@ -193,6 +197,8 @@ narrative and decisions).
193
197
 
194
198
 
195
199
 
200
+
201
+
196
202
  ### Release gating (only when configured)
197
203
 
198
204
  **Only when `specs/.core/gating.config.json` exists.** A hotfix is the one spec
@@ -224,18 +230,115 @@ is a no-op.
224
230
 
225
231
 
226
232
 
233
+ ## 6b. Render the page — then offer the review, never write it
234
+
235
+ **Only when the project has per-spec isolation** (`specs/.core/env.config.json`
236
+ present). Without it there is no worktree to read and this step does not exist —
237
+ skip it in silence rather than explaining an absence.
238
+
239
+ The fix is green and nothing is committed yet. That is the moment the page is
240
+ about, so render it now — **after** the tests pass and **before** the commit:
241
+
242
+ ```
243
+ skitterspec spec-env review <spec>
244
+ ```
245
+
246
+ **This is free.** The engine reads git and splices the patches into a template;
247
+ the diff never passes through you, so a 266KB patch costs nothing.
248
+
249
+ **Then offer `/spec-diff`. Do not run it.** The written review is the part that
250
+ costs — roughly **700 output tokens**, because writing it means reading the diff
251
+ — and that spend is the operator's call, not a default.
252
+
253
+ **The offer is the `Review` row of step 6's block** — the counts, the page link
254
+ and a question, in one row:
255
+
256
+ | **Review** | <N> files, +<a> −<d> · [open the page](<the `open:` URL>) — want a written review before you commit? |
257
+
258
+ **It ends in a question, addressed to someone.** It was once a fenced block of
259
+ engine output, and it fired on every phase and was never once taken: two quoted
260
+ lines under the test counts, addressed to nobody, with the report then closing
261
+ on *"commit this first"* — the last instruction the reader got was to move on,
262
+ so they did. A row in a labelled table is findable; a question in it is
263
+ answerable. Both halves are load-bearing.
264
+
265
+ **Never bury it and never split it.** It sits above `Follow-ups` and `Next`, and
266
+ the page and the question stay in the same row: two adjacent rows about one page
267
+ make the reader resolve a distinction before acting on either. A later edit that
268
+ moves it out of the block, or separates the link from the question, undoes this
269
+ and should be read as a regression rather than tidying.
270
+
271
+
272
+ Relay the **`open:`** line rather than the bare path: a path is not clickable in
273
+ any terminal, and a page nobody can open is a page nobody reads.
274
+
275
+ - **Never write the review unasked**, and **never publish**. Publishing leaves
276
+ something behind that this tooling cannot remove, so it is always an ask. A
277
+ `file://` link is no use on a phone, and saying so **is** the ask —
278
+ `/spec-diff` §6 owns how.
279
+ **Follow the `reader:` line the engine printed — do not sniff for it.** It
280
+ answers where the person reading this is sitting, and the offer changes with it:
281
+
282
+ - **absent** (`unknown`) — the `file://` URL, exactly as always. **Do not warn:**
283
+ unknown is the ordinary state of a local machine, and a warning there is an
284
+ accusation against a healthy session.
285
+ - **`local`** — the `file://` URL.
286
+ - **`remote`** — the engine has already stood its local server up and put a URL
287
+ the reader can open on `open:`. So there is **nothing special to say**: relay
288
+ that line like any other. Any `also:` lines under it are the other addresses
289
+ this machine has, offered because the best-guess one can be wrong — pass them
290
+ on rather than editing them out.
291
+
292
+ **Never read an environment variable to decide this** — not `SSH_CONNECTION`,
293
+ not `CLAUDE_CODE_*`, not a tty check. The engine did it, reports it on that line
294
+ and in `--json`, and a second implementation here could not be tested and would
295
+ drift.
296
+
297
+ **Serving is the engine's to do; publishing is never.** A `remote` reader
298
+ authorises a local server — one process, ended by one flag, leaving nothing
299
+ behind — and authorises nothing else. Publishing leaves a page this tooling
300
+ cannot remove, so it stays an ask in every case, always. If the engine could not
301
+ serve (a busy port, a machine with no network address) it falls back to the
302
+ `file://` URL with its marker, and that is when publishing is worth naming.
303
+
304
+ - **Never fatal.** A failed render — no worktree, a git error — is one line, and
305
+ the fix is still done. The page is a convenience; the repo is the record.
306
+
307
+ **The range is measured from the base tag, not from `main`.** A hotfix forks its
308
+ worktree from its `> **Base version:**` tag, and the engine reads that header, so
309
+ the header line says `since <tag>` — do not relay it as `since main`, and do not
310
+ reach for a branch view expecting the base branch.
311
+
227
312
  ## 7. Report
228
313
 
229
- Summarise: the base tag, root cause, the failing→passing test, the fix, and the
230
- full test result. The spec stays in `in-progress`.
314
+ Do **not** `git push` or `git tag`-and-push unless the user asks deploying to
315
+ prod is theirs to trigger. The spec stays in `in-progress`.
231
316
 
232
317
  - **`/spec-live` is refused for a hotfix** — its branch is built on an old tag, so
233
318
  hot-reloading it onto the running dev server could break the shared instance.
234
319
  To test it, the user runs `/spec-connect` (its own isolated stack).
235
- - Suggest **`/spec-complete`** to land it: it patch-bumps the base tag, tags the
236
- hotfix branch **locally** (you push it to deploy), and cherry-picks the fix onto
237
- `main`. Add `--also <tag>` at completion to also patch other release lines
238
- (test/demo on their own versions).
320
+ - `Next` points at **`/spec-complete`** to land it: it patch-bumps the base tag,
321
+ tags the hotfix branch **locally** (you push it to deploy), and cherry-picks the
322
+ fix onto `main`. Add `--also <tag>` at completion to also patch other release
323
+ lines (test/demo on their own versions).
239
324
 
240
- Do **not** `git push` or `git tag`-and-push unless the user asks — deploying to
241
- prod is theirs to trigger.
325
+ End with the block defined in `.claude/rules/spec-reports.md`. That file carries
326
+ the shape; this section carries only what is specific here.
327
+
328
+ **Verdicts**
329
+
330
+ - `✅` — red→green on the base tag, fix in, suite passing.
331
+ - `⚠️` — green, with something worth knowing.
332
+ - `❌` — still red, or a later test broke. Quote the failure.
333
+ - `⏸` — no reproduction on that tag, or the tag could not be established.
334
+
335
+ **Fields:** `Tracker` · `Branch` · `Spec` · `Cause` · `Built` · `Tests` ·
336
+ `Review` · `Follow-ups` · `Next`
337
+
338
+ **The base tag goes in the verdict clause** — `✅ /spec-hotfix · hotfix-foo ·
339
+ green on v2.3.1`. Which released version this was fixed against is the first
340
+ thing anyone needs, and it is not a field: the clause is where the run says
341
+ where it got to.
342
+
343
+ Step 6b's offer is the `Review` row, not a paragraph after the block — the
344
+ counts, the link and the question in one row. Nothing follows the block.
@@ -5,6 +5,11 @@ description: Bootstrap the spec-driven-development workflow in the current proje
5
5
 
6
6
  # /spec-init — set up the spec-driven-development workflow
7
7
 
8
+ > Stay silent while this runs — speak only to ask something you cannot answer
9
+ > yourself, or to report a failure at the moment it happens. Read
10
+ > `.claude/rules/spec-reports.md` before reporting; it defines the block this
11
+ > skill ends with.
12
+
8
13
  Bootstrap (or repair) everything this project needs to run the spec lifecycle.
9
14
  **Idempotent:** detect what already exists, create only what's missing, and never
10
15
  clobber customised content. Finish with a summary of created vs already-present.
@@ -22,10 +27,11 @@ clobber customised content. Finish with a summary of created vs already-present.
22
27
  > **Leave alone**. Non-interactively it only adds what's missing; `--resync` /
23
28
  > `--reset` (reset needs `--yes`) drive the stronger actions.
24
29
 
25
- The system is **ten skills**: `spec` (feature), `spec-bug` (bug),
30
+ The system is **twelve skills**: `spec` (feature), `spec-bug` (bug),
26
31
  `spec-hotfix` (a bug fixed on a released tag), `spec-review`, `spec-start`,
27
- `spec-next`, `spec-to-main`, `spec-complete`, `spec-cancel`, and this
28
- `spec-init`. The lifecycle is `backlog in-progress complete / cancelled`,
32
+ `spec-next`, `spec-diff` (read a spec's diff as a page),
33
+ `spec-reviewed` (pick up a review you approved on that page), `spec-to-main`,
34
+ `spec-complete`, `spec-cancel`, and this `spec-init`. The lifecycle is `backlog → in-progress → complete / cancelled`,
29
35
  with `.core` holding always-apply project rules.
30
36
 
31
37
  ## 0. Workspace mode (only when adopting isolation)
@@ -99,6 +105,28 @@ Ensure it exists. If missing, create it documenting:
99
105
  Read a sibling spec skill (e.g. `spec`, `spec-next`) for the canonical shapes
100
106
  rather than inventing them. If the rule already exists, leave it unless stale.
101
107
 
108
+ ## 4a. The review-gate hook (`.claude/hooks/review-gate.js`)
109
+
110
+ `skitterspec init` installs the hook script and registers it in the project's
111
+ **committed** `.claude/settings.json` as a `PreToolUse` hook on `Bash`. It runs
112
+ one engine call per Bash tool call and refuses a `git commit` in a worktree
113
+ whose phase is still awaiting a verdict.
114
+
115
+ **Committed, not machine-local**, and the difference is the point: the trusted
116
+ worktree root is one machine's absolute path, while *a phase that ended owes an
117
+ answer* is the project's policy and should reach everyone who clones it. The
118
+ command is written with `${CLAUDE_PROJECT_DIR}`, so it holds in worktrees too.
119
+
120
+ **Say it is there, once.** A hook that blocks a commit with the operator not
121
+ knowing a hook exists reads as a broken git, so name it in the report when it is
122
+ newly registered — and say what turns it off (`review.required: false` in
123
+ `env.config.json`, which the hook defers to entirely).
124
+
125
+ **Never fatal, and never rewritten.** A settings file that is not parseable JSON
126
+ is reported and left exactly as it is — it is the operator's config, and
127
+ everything else in it would be lost. A settings file that already names this
128
+ script, however it was wrapped, is left alone rather than gaining a second copy.
129
+
102
130
  ## 5. CLAUDE.md
103
131
 
104
132
  Ensure a `## Spec workflow` section exists. If absent, add one with the
@@ -109,7 +137,28 @@ the section exists, refresh only stale folder/skill names — don't rewrite it.
109
137
 
110
138
  ## 6. Report
111
139
 
112
- Summarise per area folders, `.gitignore` lines, tooling-ignore negations,
113
- skills (present/missing), rule file, CLAUDE.md section — as created / updated /
114
- already-present, plus the `git check-ignore` result for `.core`. Do **not**
115
- `git commit` unless the user asks.
140
+ Do **not** `git commit` unless the user asks.
141
+
142
+ End with the block defined in `.claude/rules/spec-reports.md`. That file carries
143
+ the shape; this section carries only what is specific here.
144
+
145
+ **Verdicts**
146
+
147
+ - `✅` — every area is in place.
148
+ - `⚠️` — bootstrapped, with something worth knowing: a skill that could not be
149
+ installed, a CLAUDE.md that was left alone, a `.core` that is still ignored.
150
+ - `❌` — it wrote some areas and failed on another. Name which, so the re-run is
151
+ informed; this skill is idempotent and re-running it is the fix.
152
+ - `⏸` — not a git repo, or nothing it could safely write into.
153
+
154
+ **Fields:** `Built` · `Follow-ups` · `Next`
155
+
156
+ **`Built` is per area, one line each** — folders, `.gitignore` lines,
157
+ tooling-ignore negations, skills (present/missing), rule files, CLAUDE.md
158
+ section — as created / updated / already-present, plus the `git check-ignore`
159
+ result for `.core`. This is the one skill whose `Built` is a list rather than a
160
+ clause, because "what is now true of this project" is the entire answer it
161
+ exists to give.
162
+
163
+ **There is no spec to name**, so the verdict line drops that segment:
164
+ `✅ /spec-init · every area in place`.