@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.
- package/MIGRATION.md +296 -10
- package/README.md +53 -4
- package/assets/claude-md-section.md +38 -2
- package/assets/commands/spec-connect.md +2 -2
- package/assets/commands/spec-live.md +2 -2
- package/assets/core/env.config.json.example +7 -3
- package/assets/core/env.config.md +90 -30
- package/assets/hooks/review-gate.js +141 -0
- package/assets/review/page.html +1787 -0
- package/assets/rules/spec-planning.md +250 -10
- package/assets/rules/spec-reports.md +321 -0
- package/assets/skills/spec/SKILL.md +32 -4
- package/assets/skills/spec-bug/SKILL.md +113 -8
- package/assets/skills/spec-cancel/SKILL.md +84 -19
- package/assets/skills/spec-complete/SKILL.md +80 -23
- package/assets/skills/spec-diff/SKILL.md +678 -0
- package/assets/skills/spec-hotfix/SKILL.md +113 -10
- package/assets/skills/spec-init/SKILL.md +56 -7
- package/assets/skills/spec-next/SKILL.md +408 -7
- package/assets/skills/spec-review/SKILL.md +26 -3
- package/assets/skills/spec-reviewed/SKILL.md +258 -0
- package/assets/skills/spec-start/SKILL.md +283 -106
- package/assets/skills/spec-to-main/SKILL.md +28 -6
- package/package.json +11 -7
- package/src/cli.js +1808 -89
- package/src/env/building.js +143 -0
- package/src/env/commitcmd.js +108 -0
- package/src/env/config.js +58 -9
- package/src/env/hooks.js +117 -0
- package/src/env/provision.js +54 -15
- package/src/env/proxy.js +34 -1
- package/src/env/render.js +3 -12
- package/src/env/resolve.js +295 -9
- package/src/env/review.js +1536 -0
- package/src/env/serve.js +573 -0
- package/src/env/teardown.js +13 -6
- package/src/init.js +150 -1
- 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,
|
|
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
|
-
|
|
230
|
-
|
|
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
|
-
-
|
|
236
|
-
hotfix branch **locally** (you push it to deploy), and cherry-picks the
|
|
237
|
-
`main`. Add `--also <tag>` at completion to also patch other release
|
|
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
|
-
|
|
241
|
-
|
|
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 **
|
|
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-
|
|
28
|
-
`spec-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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`.
|