@sabaiway/agent-workflow-kit 1.15.1 → 1.16.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 (55) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +2 -1
  3. package/SKILL.md +91 -15
  4. package/capability.json +1 -1
  5. package/package.json +5 -2
  6. package/tools/commands.mjs +206 -0
  7. package/tools/delegation.mjs +8 -0
  8. package/tools/family-registry.mjs +263 -13
  9. package/tools/procedures.mjs +3 -1
  10. package/bin/install.test.mjs +0 -347
  11. package/tools/delegation.test.mjs +0 -116
  12. package/tools/detect-backends.test.mjs +0 -444
  13. package/tools/engine-source.test.mjs +0 -280
  14. package/tools/family-registry.test.mjs +0 -279
  15. package/tools/fs-safe.test.mjs +0 -346
  16. package/tools/hide-footprint.integration.test.mjs +0 -168
  17. package/tools/hide-footprint.test.mjs +0 -463
  18. package/tools/inject-methodology.test.mjs +0 -689
  19. package/tools/known-footprint.test.mjs +0 -271
  20. package/tools/manifest/fixtures/bad-available/SKILL.md +0 -7
  21. package/tools/manifest/fixtures/bad-available/capability.json +0 -10
  22. package/tools/manifest/fixtures/detect-array/SKILL.md +0 -7
  23. package/tools/manifest/fixtures/detect-array/capability.json +0 -10
  24. package/tools/manifest/fixtures/malformed-json/capability.json +0 -1
  25. package/tools/manifest/fixtures/metadata-version/SKILL.md +0 -10
  26. package/tools/manifest/fixtures/metadata-version/capability.json +0 -9
  27. package/tools/manifest/fixtures/missing-key/SKILL.md +0 -7
  28. package/tools/manifest/fixtures/missing-key/capability.json +0 -8
  29. package/tools/manifest/fixtures/missing-source/SKILL.md +0 -7
  30. package/tools/manifest/fixtures/missing-source/capability.json +0 -11
  31. package/tools/manifest/fixtures/nested-version-decoy/SKILL.md +0 -10
  32. package/tools/manifest/fixtures/nested-version-decoy/capability.json +0 -9
  33. package/tools/manifest/fixtures/null-root/capability.json +0 -1
  34. package/tools/manifest/fixtures/provides-roles-mismatch/SKILL.md +0 -7
  35. package/tools/manifest/fixtures/provides-roles-mismatch/bin/run.sh +0 -2
  36. package/tools/manifest/fixtures/provides-roles-mismatch/capability.json +0 -11
  37. package/tools/manifest/fixtures/stub/capability.json +0 -10
  38. package/tools/manifest/fixtures/traversal-source/SKILL.md +0 -7
  39. package/tools/manifest/fixtures/traversal-source/capability.json +0 -11
  40. package/tools/manifest/fixtures/unknown-schema/capability.json +0 -9
  41. package/tools/manifest/fixtures/valid/SKILL.md +0 -10
  42. package/tools/manifest/fixtures/valid/bin/run.sh +0 -3
  43. package/tools/manifest/fixtures/valid/capability.json +0 -18
  44. package/tools/manifest/fixtures/version-mismatch/SKILL.md +0 -7
  45. package/tools/manifest/fixtures/version-mismatch/capability.json +0 -9
  46. package/tools/manifest/fixtures/win-absolute-source/SKILL.md +0 -7
  47. package/tools/manifest/fixtures/win-absolute-source/capability.json +0 -11
  48. package/tools/manifest/validate.test.mjs +0 -73
  49. package/tools/procedures.test.mjs +0 -303
  50. package/tools/recipes.test.mjs +0 -538
  51. package/tools/release-scan.test.mjs +0 -41
  52. package/tools/setup-backends.test.mjs +0 -500
  53. package/tools/uninstall.integration.test.mjs +0 -144
  54. package/tools/uninstall.test.mjs +0 -401
  55. package/tools/velocity-profile.test.mjs +0 -496
package/CHANGELOG.md CHANGED
@@ -4,6 +4,63 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
4
4
  is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
5
5
  every `migrations/<version>-<slug>.md` newer than it, in semver order.
6
6
 
7
+ ## 1.16.0 — Onboarding & discoverability: `help`, honest versioning, an enriched `status` (kit)
8
+
9
+ A **feature** release (additive, backward-compatible). Makes the kit self-explanatory: a discoverable
10
+ command surface, honest installed-on-this-machine version legibility, and one `status` that answers
11
+ "versions + deployment + settings + bridges". The deployment-lineage head stays **`1.3.0`** — nothing
12
+ in the deployed `docs/ai` *structure* changed, so there is **no migration**. The kit **package**
13
+ version is a separate axis from that head.
14
+
15
+ - **`/agent-workflow-kit help` + safe unknown-invocation routing.** New `tools/commands.mjs`: a frozen
16
+ command catalog (grouped Inspect / Configure / Orchestrate / Lifecycle, each tagged read-only /
17
+ writer / guarded) + a pure `routeInvocation` router. A discoverable index, and the read-only landing
18
+ spot for any unrecognized invocation — **no unrecognized/garbage token ever reaches a writer/guarded
19
+ mode** (only an explicit known token, or the acknowledged bare-bootstrap exception). Drift-guarded
20
+ against the `### Mode:` headers.
21
+ - **Honest version legibility.** `tools/family-registry.mjs` gains a no-leak `--json` envelope (user-safe
22
+ field names only — never the internal manifest/stamp terms) feeding a shared **version block**:
23
+ deployment-structure head · installed package versions per member · the two-axes disambiguation when
24
+ the numbers coincide. An **offline caveat** flags a memory install too old to ship the current
25
+ orchestration template ("installed on this machine", no network). Bootstrap/upgrade now print a
26
+ **welcome mat** (success → version block → backend line → one caveat-aware next step) and bootstrap
27
+ opens with a one-line first-contact orientation.
28
+ - **Settings & bridges in `status`.** `status` is now the single answer to "versions + deployment +
29
+ settings + bridges": orchestration recipes (effective per slot), attribution
30
+ (`includeCoAuthoredBy`), velocity (`defaultMode`), the bridges (readiness + wrapper PATH presence,
31
+ no model claim), and **visibility** (visible / hidden / unclear, via `inferVisibility`) — each in
32
+ plain language, **localized-on-error** (a malformed file surfaces its own error, the rest still
33
+ renders). `loadConfig` is shared with the procedures advisor (one strict-JSON reader).
34
+ - **Surgical delegation gate.** `references/templates/orchestration.json` joins the memory
35
+ required-asset set: a memory too old to seed `docs/ai/orchestration.json` now **falls back** to the
36
+ kit's bundled substrate (which seeds it) instead of being delegate-classified — closing the
37
+ stale-memory trap the read-only note only informs about.
38
+ - **Tarball guard `69 → 70`** (the new shipped `tools/commands.mjs`); `npm pack --dry-run --json`
39
+ re-verified. No `docs/ai` structural change → lineage head unchanged.
40
+
41
+ ## 1.15.2 — Strip the package's own tests + fixtures from the npm tarball (kit)
42
+
43
+ Packaging only — no API/behaviour change; removed the package's own colocated tests + fixtures from
44
+ the published tarball, deploy/mirror payload tests retained. The deployment-lineage head stays
45
+ **`1.3.0`** (no `docs/ai` structural change, no migration file). The kit **package** version is a
46
+ separate axis.
47
+
48
+ - **`files[]` scoped negation.** Appended `!bin/*.test.mjs`, `!tools/**/*.test.mjs`, and
49
+ `!tools/manifest/fixtures/**` to the package allowlist (npm ignores a root `.npmignore` when
50
+ `files[]` is present, so negation entries in `files[]` are the mechanism). Tarball **115 → 69
51
+ files**: 18 of the package's own colocated tests + 28 manifest fixtures no longer ship.
52
+ - **Deploy/mirror payload tests retained.** `references/scripts/*.test.mjs` (deployed into a
53
+ consumer repo's `scripts/` with the docs-rotation scripts) and
54
+ `bridges/antigravity-cli-bridge/bin/agy.test.mjs` (part of the byte-identical bridge mirror the
55
+ installed kit links from) still ship — a blanket `!**/*.test.mjs` would have silently broken
56
+ installs, so the negation is deliberately scoped. **Never broaden it to `!references/**` or
57
+ `!bridges/**`.**
58
+ - **New tarball guard.** `test/package-content.test.mjs` (dev-only; outside `files[]`, never ships)
59
+ pins the exact shape via `npm pack --dry-run --json`: no own-test/fixture leak, payload tests +
60
+ runtime files present, exact file count `=== 69`.
61
+ - Test files stay on disk; the gate + publish CI run them from the checkout, unchanged. This is a
62
+ tarball-only exclusion.
63
+
7
64
  ## 1.15.1 — Version-axis clarity, hidden-mode invariant, lineage-head drift guard (kit)
8
65
 
9
66
  Patch: documentation + a regression guard; no behaviour change to shipped tooling, and the
package/README.md CHANGED
@@ -218,9 +218,10 @@ command is printed).
218
218
  |---------|------|--------------|
219
219
  | `/agent-workflow-kit` | new / empty project | recon → **asks visible-or-hidden** + **conversational language** + **agent attribution** (default off) → deploys `AGENTS.md` + `docs/ai/` filled with real recon data → installs enforcement → **asks before committing** |
220
220
  | `/agent-workflow-kit upgrade` | existing deployment | reads `docs/ai/.workflow-version`, shows the changelog diff, preserves your authored memory, applies migrations, re-stamps — then prints a **read-only** one-line backend-status line (what's set up vs missing); never installs a bridge — set one up with `/agent-workflow-kit setup` |
221
+ | `/agent-workflow-kit help` | any time | **read-only command index** — every command, grouped (Inspect / Configure / Orchestrate / Lifecycle) and tagged read-only / writer / guarded. The discoverable entry point, and where any unrecognized invocation lands (always read-only — a garbage invocation never writes). Never writes, never commits, never runs a subscription CLI. |
221
222
  | `/agent-workflow-kit backends` | any time | **read-only** check of the optional execution-backends (the `codex` / `agy` bridges): what's set up vs missing and the next step. Never writes, never commits, never runs a subscription CLI (credentials = marker-file presence, not a live login). |
222
223
  | `/agent-workflow-kit setup [backend]` | opt-in, any time | **link-only** auto-setup of a bridge: places the bundled bridge skill (only into an absent / empty / managed dir — never overwrites an unmanaged one) + links its wrappers onto `PATH` via managed symlinks (idempotent; refuses to clobber a non-symlink; try `--dry-run` to preview). The binary install + the one-time subscription login stay **manual**: it prints the exact **login** command and points the binary install at each bridge's `setup/README.md`. POSIX wrappers — on Windows use WSL. Never commits, never runs a subscription CLI. |
223
- | `/agent-workflow-kit status` | any time | **read-only** view of the whole family: which members (kit / memory / engine / the two bridges) are installed and at what version, and — with a project — what's deployed (`docs/ai`, the version stamps, and whether the AI files are git-ignored for hidden mode). Never writes, never commits, never runs a subscription CLI. |
224
+ | `/agent-workflow-kit status` | any time | **read-only** single view of **versions + deployment + settings + bridges**: which members (kit / memory / engine / the two bridges) are installed and at what version (with an honest "installed on this machine" note when one is behind) and — in a project — what's deployed (`docs/ai`, the version stamps, and the **visibility**: visible / hidden / unclear), plus your settings (orchestration recipes, attribution, velocity) and the bridges' readiness. The two version axes (package number vs deployment-structure head) stay decoupled. Never writes, never commits, never runs a subscription CLI. |
224
225
  | `/agent-workflow-kit recipes` | any time | **read-only** orchestration advisor: presents four named recipes for composing the bridges into plan → execute → review — **Solo / Reviewed / Council / Delegated** — plans + recommends one for your environment (degrading with a stated reason when a backend isn't ready), and offers the choice. The orchestrator runs it via the bridge skills and **always commits**; the kit never executes a recipe, never runs a subscription CLI, never commits. |
225
226
  | `/agent-workflow-kit procedures <activity>` | any time | **read-only** activity-procedures advisor: prints a named activity's ordered steps (`plan-authoring` / `plan-execution`) read **live** from the engine, plus the **resolved recipe per slot** from your hand-edited `docs/ai/orchestration.json` + backend readiness (default Reviewed when a backend is ready, Council on request, slot-aware incl. Delegated). `--override <slot>=<recipe>` adjusts one slot per run. Composes with `recipes`; never writes, never commits, never runs a subscription CLI. |
226
227
  | `/agent-workflow-kit uninstall` | opt-in, any time | **guarded teardown** — the inverse of `init` / `setup`. Removes only what's **provably ours** (managed skill dirs + bridge wrappers; in a project, the hidden-mode git-ignore block it added + the pre-commit hook it installed); **never deletes** your `docs/ai` / `AGENTS.md` (prints the exact `rm` to run by hand) or your `.claude/settings.json` (prints an **edit** — remove the attribution key, review any velocity `permissions.*` — never an `rm`). Always `--dry-run` first; preflight-then-mutate; never commits. |
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: agent-workflow-kit
3
3
  description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
4
4
  disable-model-invocation: true
5
5
  metadata:
6
- version: '1.15.1'
6
+ version: '1.16.0'
7
7
  ---
8
8
 
9
9
  # agent-workflow-kit
@@ -35,9 +35,11 @@ validator shipped by the candidate (which could itself be broken). Delegate only
35
35
  hold:
36
36
  - result is **valid** and `kind` is `memory-substrate`;
37
37
  - **every required asset is present** in the candidate, at its real path:
38
- `references/templates/`, `references/contracts.md`, `references/scripts/`,
39
- `scripts/stamp-takeover.mjs`, `migrations/`, `capability.json`. A partial install (manifest +
40
- `SKILL.md` only) is treated as **invalid**.
38
+ `references/templates/`, **`references/templates/orchestration.json`** (the orchestration-config
39
+ template — a memory too old to ship it, pre-`1.2.0`, can't seed `docs/ai/orchestration.json`, so it
40
+ falls back to the kit's own bundled substrate, which does), `references/contracts.md`,
41
+ `references/scripts/`, `scripts/stamp-takeover.mjs`, `migrations/`, `capability.json`. A partial
42
+ install (manifest + `SKILL.md` only) is treated as **invalid**.
41
43
 
42
44
  On **unsupported** (unknown schema), **invalid**, **unavailable**, **wrong-family**, or
43
45
  **wrong-name**, **use the bundled copy** — never block. The fallback decision is final once
@@ -96,10 +98,11 @@ ever deleted.
96
98
 
97
99
  ## Modes
98
100
 
99
- Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to guard against bootstrapping over a live system, but the user makes the final call.
101
+ Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to guard against bootstrapping over a live system, but the user makes the final call. The invocation→mode mapping is pinned by `tools/commands.mjs` `routeInvocation` (unit-tested): a **known** subcommand routes to its mode; the **bare/empty** invocation routes to `bootstrap`; **any unrecognized/ambiguous** token routes to `help`, which is **read-only** — so a garbage invocation never triggers a write (see the safe-routing rule under *Version status & the two axes*).
100
102
 
101
103
  - **`/agent-workflow-kit`** (default) — bootstrap a new or empty project. If `docs/ai/` already exists, stop and ask whether they meant `upgrade`.
102
104
  - **`/agent-workflow-kit upgrade`** — upgrade an existing deployment to the skill's current `version`.
105
+ - **`/agent-workflow-kit help`** — read-only **command index**: enumerate every command, grouped (Inspect / Configure / Orchestrate / Lifecycle) and tagged read-only / writer / guarded. The single discoverable entry point, and the landing spot for any unrecognized invocation. Never writes, never commits, never runs a subscription CLI.
103
106
  - **`/agent-workflow-kit backends`** — read-only environment check: which optional **execution-backends** (the `codex` / `agy` bridges) are set up vs missing. Never writes, never commits, never runs a subscription CLI.
104
107
  - **`/agent-workflow-kit setup [backend]`** — the **link-only**, opt-in companion to `backends`: place the bundled bridge skill + link its wrappers onto `PATH`. **In-agent only** — `init` (npx) never places bridges. The binary install + the interactive subscription login stay **manual** (it prints the exact commands); idempotent; refuses to clobber a non-symlink; never commits, never runs a subscription CLI.
105
108
  - **`/agent-workflow-kit status`** — read-only view of the **whole family**: which members (kit / memory / engine / the two bridges) are installed, at what version, and — in a project — what is deployed (`docs/ai`, the version stamps, the hidden-mode fence). Never writes, never commits, never runs a subscription CLI.
@@ -110,6 +113,8 @@ Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to
110
113
 
111
114
  ### Version status & the two axes — surface this on every invocation
112
115
 
116
+ **Safe-routing rule (which mode did the user invoke?).** Map the invocation token with `tools/commands.mjs` `routeInvocation`: a **known** subcommand → its mode; the **bare/empty** invocation → `bootstrap` — the one writer reachable without a token, and only on an undeployed project (if `docs/ai/` already exists, **ask upgrade-vs-bootstrap**, never overwrite); **any unrecognized/ambiguous** token → `help`, which is **read-only**. The invariant: **no unrecognized/garbage invocation ever triggers a write** (only an explicit known token or the acknowledged bare-bootstrap exception can). The mapping is unit-tested, so it is not left to interpretation.
117
+
113
118
  Before acting, read `docs/ai/.workflow-version` (the project's stamp), state a one-line status, then route:
114
119
 
115
120
  - **absent** → bootstrap (a fresh deployment).
@@ -151,6 +156,67 @@ readiness, then **append an actionable recipe recommendation** from the recipe p
151
156
  I'm skipping the backend-status line."* — never a silent skip (Hard Constraint — no silent
152
157
  failures).
153
158
 
159
+ ### The version block + welcome mat (shared by bootstrap + upgrade)
160
+
161
+ Bootstrap (step 11) and **every** successful `upgrade` exit (steps 4 + 8) close with the same
162
+ **report footer**, in this **canonical order**: success state → **version block** → the **one-line
163
+ backend-status line** → **welcome mat**. Only the version block comes from
164
+ `node ${CLAUDE_SKILL_DIR}/tools/family-registry.mjs --json` (add `--dir <project>` for the deploy
165
+ axis) — **never hardcoded semver**; the backend-status line is its own shared contract (above), and
166
+ the welcome mat **composes signals already gathered** (the version block's notes + the backend-status
167
+ line), not a fresh helper call. Present everything in the user's conversational language; never paste
168
+ the JSON or any internal field name.
169
+
170
+ **Version block — three plain lines, fed from `--json`:**
171
+ - **`Deployment structure: <deploymentHead> (current)`** — the deployed `docs/ai` structure version
172
+ (the envelope's `deploymentHead`); **the only axis `upgrade` compares**.
173
+ - **`Installed on this machine — package versions:`** `kit <v> · memory <v> · engine <v> ·
174
+ codex-bridge <v> · antigravity-bridge <v>` — one per `installed[]` entry, labelled by its `display`
175
+ and showing its `version`, or, when there is no version, the plain phrase for its `state` (map
176
+ below). Append any `installed[].notes` **in plain words** (e.g. the memory-behind refresh+restart
177
+ line).
178
+ - **The two axes are different — say so even when the numbers coincide:** an installed *package*
179
+ version (e.g. engine `1.3.0`) is a package number, **not** the deployment-structure version on line
180
+ one (which is also `1.3.0` today). The head advances only when the deployed `docs/ai` structure
181
+ changes, so a higher package number on npm/GitHub is **not** a newer deployment.
182
+
183
+ **`state` → plain language** (map the envelope's `installed[].state` token; never show the raw token):
184
+ `installed` → its version · `absent` → "not installed" · `other-tool` → "a different tool occupies
185
+ that skill slot" · `placeholder` → "a placeholder, not a working install" · `invalid` → "installed
186
+ but its manifest didn't validate" · `unsupported` → "installed but its manifest schema is too new for
187
+ this kit" · `uncheckable` → "couldn't be checked (a permission error)".
188
+
189
+ **Helper-failure contract (mirror the backend-status line).** The version block needs the
190
+ family-registry helper, which the **agent host** runs. If the host can't run it (`node` not on the
191
+ agent's PATH, or the helper errors), **skip the version block and say so with the concrete reason** —
192
+ e.g. *"Couldn't run the family-registry helper here (node is not on the agent host PATH), so I'm
193
+ skipping the installed-versions block."* — never a silent skip (Hard Constraint). It is non-essential:
194
+ the rest of the report — and the commit gate — proceeds.
195
+
196
+ **Welcome mat — the last line(s) of the footer.** After the version block and the backend-status
197
+ line, print *"Run `/agent-workflow-kit help` to see every command."* then **one** recommended next
198
+ step, chosen **caveat-aware** from signals already in hand (the version block's notes + the
199
+ backend-status line — no new helper call) in this priority order:
200
+ 1. a member is **behind** (an `installed[].notes` caveat fired — memory/engine) → *refresh the behind
201
+ member first* (its `npx …@latest init` + restart the session);
202
+ 2. else **no backend is ready** (the backend-status line shows none ready) → *set one up with
203
+ `/agent-workflow-kit setup`*;
204
+ 3. else **a backend is ready but the orchestration config is still all-Solo** (no `reviewed` /
205
+ `council` / `delegated` slot anywhere — inspect `docs/ai/orchestration.json`, or read the
206
+ procedures advisor's resolved recipes) → *put it to work with `/agent-workflow-kit recipes`*;
207
+ 4. else (a backend is ready **and** a backend-backed recipe is already selected) → the optional
208
+ *`/agent-workflow-kit velocity`* opt-in (never run it without a yes).
209
+
210
+ Keep it compact — a few short lines, plain language, no kit-internal terms.
211
+
212
+ ### Mode: help
213
+
214
+ Read-only. The single discoverable **command index** — it answers *"what can `/agent-workflow-kit` do, and which commands change things?"* It **never writes, never commits, and never runs a subscription CLI**.
215
+
216
+ Run `node ${CLAUDE_SKILL_DIR}/tools/commands.mjs` (add `--json` for the machine-readable catalog) and present its grouped index — **Inspect / Configure / Orchestrate / Lifecycle**, each command tagged **read-only / writer / guarded** — in the user's conversational language. That catalog is the **single source of truth** for the command surface (the same one the bootstrap / upgrade report footers point at); `routeInvocation(token)` in the same file is the executable contract for which invocation maps to which mode.
217
+
218
+ `help` is also the landing spot for any **unrecognized or ambiguous** invocation — and that path is **always read-only** (the safe-routing rule under *Version status & the two axes*). When you arrive here that way, render the index and, in plain language, note that the invocation wasn't recognized so nothing was changed.
219
+
154
220
  ### Mode: bootstrap
155
221
 
156
222
  > Bundled sources below (templates, scripts) live in **this skill's own directory** — `${CLAUDE_SKILL_DIR}/` in Claude Code, or the folder containing this `SKILL.md` in Codex / other agents. Use that as the copy/read source; the working directory is the **target project**, not the skill.
@@ -164,6 +230,7 @@ readiness, then **append an actionable recipe recommendation** from the recipe p
164
230
  - `src/` (or equivalent) 2–3 levels deep → modules, routes/pages, components, services, types.
165
231
  - Tests (framework, location, E2E?) and linter rules.
166
232
  - Record: stack, package manager, daily commands (`dev`/`test`/`lint`/`type-check`), routes/pages, architecture layers.
233
+ - **First-contact orientation — say this before the first question (read-only).** In 1–2 plain lines, tell the user what this is — a portable memory & workflow system for this repo, so future sessions boot from a small structured memory instead of re-reading everything — and that they can run **`/agent-workflow-kit help`** any time to see every command. This is the "start here"; keep it to a sentence or two, then ask the visibility question.
167
234
  2. **Choose visibility — ASK the user explicitly and wait for the answer, before writing anything.** This decides what gets tracked and is hard to reverse after a commit, so never assume the default silently: `visible` (committed — canonical, recommended) or `hidden` (in-tree, git-ignored via the **project-local** `.git/info/exclude` — one managed block covering the full AI/agent footprint, never the machine-global excludes). See [Visibility contract](references/contracts.md#visibility-contract).
168
235
  3. **Choose conversational language — ASK the user explicitly and wait for the answer.** Which language should the agent *talk to them* in — questions, explanations, summaries, status updates? Offer the language they're already writing in as the default. Carry the answer into the `{{COMM_LANGUAGE}}` slot of the *Communication language* block when `AGENTS.md` is created (step 5). See [Communication contract](references/contracts.md#communication-contract). This sets the **dialogue** language only — never the files.
169
236
  4. **Choose agent attribution — ASK the user explicitly and wait for the answer.** May the agent attribute work to itself / to AI — `Co-Authored-By` trailers, "Generated with …" footers, "AI"/agent/model mentions in code, comments, commit messages, PR titles/bodies, or docs? **Default to `off`** (no agent/AI mention anywhere) unless they opt in — people are routinely surprised to find an AI listed as a repo contributor. Carry the answer into the `{{AGENT_ATTRIBUTION}}` slot of the *Attribution* block when `AGENTS.md` is created (step 5). **If `off` and the project uses Claude Code**, also set `"includeCoAuthoredBy": false` in the project's `.claude/settings.json` (create it if absent) — the trailer is added by the harness, so a doc directive alone won't stop it. See [Attribution contract](references/contracts.md#attribution-contract).
@@ -186,7 +253,7 @@ readiness, then **append an actionable recipe recommendation** from the recipe p
186
253
  independent axes: a packaging-only release bumps the package but leaves the lineage head until a
187
254
  migration actually changes the deployed `docs/ai` structure. A stamp greater than the head →
188
255
  STOP (never downgrade).
189
- 11. **Report & ask.** Show `tree docs/ai/`, 2–3 lines on what was filled with real data vs left as TODO, then print the **one-line backend-status line** (the shared contract above same detector, format, invariants, and detector-unavailable skip-with-reason). Then **ask before committing** never auto-commit. Finally, offer the optional, opt-in **velocity profile** in one line — `/agent-workflow-kit velocity` seeds a read-only allowlist so routine read-only commands stop prompting (*Mode: velocity*); never run it without a yes.
256
+ 11. **Report & ask.** Show `tree docs/ai/`, 2–3 lines on what was filled with real data vs left as TODO, then print the **report footer** in the canonical order (version block → one-line backend-status line → welcome mat — the shared contracts above, rendered from the helpers, same host-can't-run skip-with-reason). The welcome mat ends on **one** recommended next step including the optional, opt-in `/agent-workflow-kit velocity` (a read-only allowlist so routine read-only commands stop prompting; *Mode: velocity*) when nothing more pressing applies, never run without a yes. Then **ask before committing** — never auto-commit.
190
257
 
191
258
  Fill strategy:
192
259
 
@@ -220,12 +287,12 @@ Fill strategy:
220
287
  4. **Equal-head exit — a real successful-exit report, not a bare stop.** If the stamp **equals** the head, the lineage is up to date — but step 3 (the methodology-slot **and** hidden-mode footprint reconciles) ran first and may have changed things, so this is a proper exit report, not a no-op:
221
288
  - **Report step 3's outcome in plain language** — for **each** pointer (workflow-methodology and orchestration-recipes) whether it was *added*, was *already present* (nothing changed), or was *skipped because the entry point is over its line limit* (the cap-refusal soft-skip from step 3, with its reason); whether the `docs/ai/orchestration.json` config was *seeded* or was *already present* (a user edit is preserved); and, for a hidden deployment, whether the hidden-mode footprint was *moved to project-local*, was *already project-local* (nothing changed), or needed a question (ambiguous visibility / a leftover machine-wide block). Plain wording only — never the reconcile/slot/anchor/marker terms (Gotcha: never leak kit internals).
222
289
  - **Name the version axis so the package number isn't mistaken for a newer release.** When you state the deployment is up to date, say it is current at the **deployment-lineage head** (`1.3.0`) and add one plain line: this head versions the deployed `docs/ai` structure and is a **separate axis** from the kit **package** version published on npm/GitHub (the larger number users see on the repo/npm page). A packaging-only release can bump that package version **without** moving the head — the head advances only when the deployed `docs/ai` structure changes — so an equal-head report is **not** a stale deployment even though GitHub shows a higher package number. (This is the only place the two axes meet the user in `upgrade`; surfacing it here prevents the recurring "but GitHub shows a higher version" confusion.)
223
- - **Print the one-line backend-status line** — the shared contract above (run `node ${CLAUDE_SKILL_DIR}/tools/detect-backends.mjs`; same format, invariants, and detector-unavailable skip-with-reason).
224
- - **Then ask before committing — never auto-commit.** If step 3 added the slot (or anything else changed), report it and ask. If step 3 was a pure zero-diff no-op and nothing else changed, say **"already up to date"** and still print the read-only backend line.
290
+ - **Print the report footer** in the canonical order (version block → one-line backend-status line → welcome mat — the shared contracts above; rendered from the helpers, same host-can't-run skip-with-reason). The welcome mat closes on **one** caveat-aware next step (a behind member first, else `setup` / `recipes` / `velocity`).
291
+ - **Then ask before committing — never auto-commit.** If step 3 added the slot (or anything else changed), report it and ask. If step 3 was a pure zero-diff no-op and nothing else changed, say **"already up to date"** and still print the read-only version block + backend line.
225
292
  5. Show the relevant `${CLAUDE_SKILL_DIR}/CHANGELOG.md` diff (entries newer than the project's stamp).
226
293
  6. Apply `${CLAUDE_SKILL_DIR}/migrations/<version>-<slug>.md` in **semver order**, only those newer than the project's stamp. Migrations are **idempotent** — safe to re-run.
227
294
  7. Reconcile drift: add any kernel files/scripts the project is missing; never clobber project-authored content (their `decisions.md`, `known_issues.md`, page specs stay). Any user question a migration raises follows the same rule as bootstrap — **structured multiple-choice where supported** (`AskUserQuestion` in Claude Code), otherwise prose. If `AGENTS.md` has no *Communication language* block (pre-1.1.0 deployment), **ask the user their conversational language** and insert the block — see `migrations/1.1.0-communication-language.md`. If it has no *Attribution* block (pre-1.2.0 deployment), **ask whether the agent may attribute work to itself / AI** and insert the block (defaulting to `off`) — see `migrations/1.2.0-agent-attribution.md`.
228
- 8. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0`, not the package version). Report changes — and when you report the stamp, **name the axis**: the head versions the deployed `docs/ai` structure and is a separate axis from the kit **package** version on npm/GitHub (the larger number users see there), so the user doesn't read the bigger package number as a newer deployment (same framing as the step 4 equal-head exit). Then **print the one-line backend-status line** (the shared contract above same detector, format, invariants, and detector-unavailable skip-with-reason). Then **ask before committing**.
295
+ 8. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0`, not the package version). Report changes — and when you report the stamp, **name the axis**: the head versions the deployed `docs/ai` structure and is a separate axis from the kit **package** version on npm/GitHub (the larger number users see there), so the user doesn't read the bigger package number as a newer deployment (same framing as the step 4 equal-head exit). Then **print the report footer** in the canonical order (version block → one-line backend-status line → welcome mat — the shared contracts above; rendered from the helpers, same host-can't-run skip-with-reason; the welcome mat closes on one caveat-aware next step). Then **ask before committing**.
229
296
 
230
297
  ### Mode: backends
231
298
 
@@ -259,14 +326,22 @@ For each backend it:
259
326
 
260
327
  ### Mode: status
261
328
 
262
- Read-only. Answers *"which family members are installed (and at what version), and what is deployed in this project?"* across the **whole family**the unified registry behind it (`tools/family-registry.mjs`) aggregates every member's `capability.json`. It **never writes, never commits, and never runs a subscription CLI**.
329
+ Read-only. The **single answer to "versions + deployment + settings + bridges"** across the whole family — `tools/family-registry.mjs` aggregates every member's `capability.json` and surveys the project. It **never writes, never commits, and never runs a subscription CLI**.
330
+
331
+ Run `node ${CLAUDE_SKILL_DIR}/tools/family-registry.mjs --json [--dir <project>]` and render it **compact**, in the user's conversational language — **never paste the JSON or any internal field name** (no-leak rule). Map the **`installed[].state`** token via the value→plain-language map under *The version block + welcome mat* (the `visibility` and wrapper states have their own phrasings, below). Present, each area on its own line(s), routing detail to its domain mode:
263
332
 
264
- Run `node ${CLAUDE_SKILL_DIR}/tools/family-registry.mjs [--dir <project>]` and present its two-axis table:
333
+ 1. **Versions the version block** (from `installed[]` + `deploymentHead`): the deployment-structure head, the installed package versions by `display`, the two-axes disambiguation, plus any member `notes` (e.g. a behind member's refresh+restart line). This is the shared version block above.
334
+ 2. **Deployment (`--dir`)** (from `project`): whether `docs/ai/` is deployed + the deploy stamps by `display`; and **visibility** — render `project.visibility.state` in **user-safe words only**: *visible (tracked)* / *hidden (git-ignored, local-only)* / *unclear (uncommitted or partially set up)* — **never** the words "hidden fence" or any marker term. A `visibility.error` → surface it plainly.
335
+ 3. **Settings (`--dir`, one line each)** (from `project.settings`):
336
+ - **recipes** — the effective recipe per slot (detail → `/agent-workflow-kit procedures` / `recipes`); a `recipes.detectError` → say the backends couldn't be checked, so recipes floored at solo.
337
+ - **attribution** — `includeCoAuthoredBy` effective; call out a **local override** only when `local` is non-null **and** differs from `project` (a `null` `local` means the key is absent there, so the project value stands — that is not an override).
338
+ - **velocity** — the effective `permissions.defaultMode` + whether an allowlist is seeded (detail → `/agent-workflow-kit velocity`).
339
+ - Any area's **`error`** field → surface it **loudly** in plain language; the rest of `status` still renders (never a crash).
340
+ 4. **Bridges (host, one line)** (from `bridges[]`): per bridge — readiness + wrapper PATH-presence; render each wrapper's `state` as *on PATH* (`present`) / *not on PATH* (`missing`) / *couldn't check* (`unknown`) (detail → `/agent-workflow-kit backends` / `setup`). **No default-model claim.** "credentials present" means a marker file exists, not a live login.
265
341
 
266
- 1. **Skill axis (always):** per member `installed` + the manifest health (`ok` / `not-installed` / `foreign` / `stub` / `invalid-manifest` / `unsupported-schema`, the same precedence the backend detector uses) + the installed version (read from the member's own `SKILL.md`, the authoritative source).
267
- 2. **Deploy axis (`--dir <project>`):** the deployment stamps (`docs/ai/.workflow-version`, `.memory-version`), whether `docs/ai/` exists, and whether the hidden-mode managed fence is present.
342
+ Restate the **two-axes honesty** an installed *package* version is not a project's deployment-lineage stamp (see *Version status & the two axes*); the installed version is whatever is on disk under `~/.claude/skills/…`, so a stale install shows its real (older) version, honestly. A host that can't run the helper **skip with the concrete reason** (the helper-failure contract), never silently.
268
343
 
269
- State plainly that the two version axes stay decoupled (an installed *skill* version is not a project's deployment-lineage stamp see *Version status & the two axes*). The installed version reflects whatever is on disk under `~/.claude/skills/…`; a stale install shows its real (older) version, honestly.
344
+ **Invariants:** read-only · never writes · never commits · never runs a subscription CLI · plain language only, no leaked internal terms.
270
345
 
271
346
  ### Mode: recipes
272
347
 
@@ -354,6 +429,7 @@ The non-obvious traps — scan these before bootstrapping or upgrading. Each is
354
429
  - **Hidden mode is project-local, and the hide tool owns the known footprint.** `tools/hide-footprint.mjs` writes **one managed block** in the **project-local `.git/info/exclude`** — never the machine-global `core.excludesFile` (which would silently affect every repo on the host; **AD-014** amends **AD-006**). It hides the kit's own artifacts **and** the known external AI/agent footprint (the `KNOWN_FOOTPRINT` table in [contracts](references/contracts.md#visibility-contract)). A **tracked** file is **never silently un-tracked** — the tool prints the `git rm --cached` it will not run. Never leak its internal marker / asks terms to the user; translate every outcome to plain language.
355
430
  - **`CLAUDE.md` is a symlink, not a copy.** `ln -s AGENTS.md CLAUDE.md` — single source, no duplication. A copy drifts; a symlink can't.
356
431
  - **Never overwrite an existing entry point or hook.** If `AGENTS.md` / `CLAUDE.md` already exist, or the installer reports a pre-existing non-marker git hook, **stop and ask** the user to merge vs replace — don't clobber.
432
+ - **Unrecognized invocations are read-only.** Only a **known** subcommand reaches its mode; the **bare** invocation bootstraps (and an existing `docs/ai/` makes it ask upgrade-vs-bootstrap first, never overwrite); **any other / ambiguous** token routes to `help` (read-only). A garbage invocation never writes. The mapping is pinned by `tools/commands.mjs` `routeInvocation` (unit-tested) — don't hand-route around it.
357
433
  - **No Node runtime → skip enforcement.** If the project has no Node (recon step 1), skip bootstrap steps 8–9 (scripts + hook) and follow the cap/archive/index policy manually, or port the scripts to the project's language.
358
434
  - **Conversational language never translates artifacts.** It governs *dialogue only*. Code, identifiers, paths, commands, log output, abbreviations, and every deployed `docs/ai/` / `AGENTS.md` file stay in their source language. See [Communication contract](references/contracts.md#communication-contract).
359
435
  - **Never auto-commit.** Report quality-gate results and wait for explicit approval — in both modes.
@@ -415,6 +491,6 @@ Deploy these into `AGENTS.md`; remove rows that don't apply to the stack.
415
491
  - [`references/scripts/`](references/scripts/) — the Node enforcement scripts (caps + staleness + index-freshness gate, 3-tier archive, hook installer) and their unit tests.
416
492
  - [`migrations/`](migrations/) — per-version upgrade steps; see `migrations/README.md`.
417
493
  - [`launchers/`](launchers/) — run the bootstrapper from non-Claude agents (`SKILL.md` is a native Codex skill; a Devin Desktop workflow launcher + install script). See `launchers/README.md`.
418
- - [`tools/`](tools/) — the family-wide tooling the kit **owns and ships**: `manifest/{schema.md,validate.mjs}` (the `capability.json` schema + the validator the kit runs as the memory detector, and root CI invokes), `delegation.mjs` (the executable delegate/fallback decision + hand-off plan), `inject-methodology.mjs` + `engine-source.mjs` (the bounded **two-slot** reconciliation — ensure-slot / inject-if-empty / cap for the `workflow:methodology` **and** `workflow:orchestration` pointers; both fragments read **live** from the installed `agent-workflow-engine` via `engine-source.mjs` (`deps.rel` selects which) — the family's one source of truth, no bundled mirror; fail-loud when the engine is needed but absent, orchestration soft-skipped when it would bust the cap), `detect-backends.mjs` (the read-only **backend detector** behind `/agent-workflow-kit backends`, plus the axis-aware `guideFor`; exports the readiness consts the planner reuses), `recipes.mjs` (the read-only **recipe planner** behind `/agent-workflow-kit recipes` — `RECIPES` / `planRecipe` / `recommendRecipe` over the bridges' role vocabulary, drift-guarded against `provides`/`cost`/`quota` + an engine↔kit recipe-name parity guard; pure, never runs a subscription CLI; also exports the pure `ACTIVITIES` / `resolveActivityRecipe` activity-procedures resolver), `procedures.mjs` (the read-only **activity-procedures advisor** behind `/agent-workflow-kit procedures` — reads `references/procedures.md` live from the engine via `engine-source.mjs`, reads + validates the hand-edited `docs/ai/orchestration.json`, and prints the steps + the resolved effective recipe per slot; drift-guarded activity/slot table vs the canon; read-only, never runs a subscription CLI), `setup-backends.mjs` (the **link-only** backend setup behind `/agent-workflow-kit setup` — place the bundled bridge + link wrappers), `fs-safe.mjs` (the shared symlink-traversal-safe copy/link/**remove/unlink** primitives that `setup-backends`, the npx installer, and the uninstaller use), `known-footprint.mjs` + `hide-footprint.mjs` (the **hidden-mode** registry + the single hide-writer behind step 9 / the upgrade reconcile — one managed block in the **project-local** `.git/info/exclude` covering the full AI/agent footprint; pinned by `known-footprint.test.mjs` drift-guard + `hide-footprint.test.mjs` / `.integration.test.mjs`), `family-registry.mjs` (the **unified family registry** behind `/agent-workflow-kit status` — aggregates every member's `capability.json`; pinned by a `family-registry.test.mjs` drift-guard), `uninstall.mjs` (the **guarded teardown** behind `/agent-workflow-kit uninstall` — classify each surface, preflight-then-mutate, never delete user-authored content), and `release-scan.mjs` (the attribution-off release gate). The bundled bridge skill mirrors live under [`bridges/`](bridges/) (byte-identical to the repo-root bridges, pinned by `test/bridges-mirror.test.mjs`). See [`tools/manifest/schema.md`](tools/manifest/schema.md).
494
+ - [`tools/`](tools/) — the family-wide tooling the kit **owns and ships**: `manifest/{schema.md,validate.mjs}` (the `capability.json` schema + the validator the kit runs as the memory detector, and root CI invokes), `commands.mjs` (the canonical **command catalog** + the pure `routeInvocation` router behind `/agent-workflow-kit help` and the safe unknown-invocation routing rule — one source of truth for the command surface, drift-guarded against the `### Mode:` headers), `delegation.mjs` (the executable delegate/fallback decision + hand-off plan), `inject-methodology.mjs` + `engine-source.mjs` (the bounded **two-slot** reconciliation — ensure-slot / inject-if-empty / cap for the `workflow:methodology` **and** `workflow:orchestration` pointers; both fragments read **live** from the installed `agent-workflow-engine` via `engine-source.mjs` (`deps.rel` selects which) — the family's one source of truth, no bundled mirror; fail-loud when the engine is needed but absent, orchestration soft-skipped when it would bust the cap), `detect-backends.mjs` (the read-only **backend detector** behind `/agent-workflow-kit backends`, plus the axis-aware `guideFor`; exports the readiness consts the planner reuses), `recipes.mjs` (the read-only **recipe planner** behind `/agent-workflow-kit recipes` — `RECIPES` / `planRecipe` / `recommendRecipe` over the bridges' role vocabulary, drift-guarded against `provides`/`cost`/`quota` + an engine↔kit recipe-name parity guard; pure, never runs a subscription CLI; also exports the pure `ACTIVITIES` / `resolveActivityRecipe` activity-procedures resolver), `procedures.mjs` (the read-only **activity-procedures advisor** behind `/agent-workflow-kit procedures` — reads `references/procedures.md` live from the engine via `engine-source.mjs`, reads + validates the hand-edited `docs/ai/orchestration.json`, and prints the steps + the resolved effective recipe per slot; drift-guarded activity/slot table vs the canon; read-only, never runs a subscription CLI), `setup-backends.mjs` (the **link-only** backend setup behind `/agent-workflow-kit setup` — place the bundled bridge + link wrappers), `fs-safe.mjs` (the shared symlink-traversal-safe copy/link/**remove/unlink** primitives that `setup-backends`, the npx installer, and the uninstaller use), `known-footprint.mjs` + `hide-footprint.mjs` (the **hidden-mode** registry + the single hide-writer behind step 9 / the upgrade reconcile — one managed block in the **project-local** `.git/info/exclude` covering the full AI/agent footprint; pinned by `known-footprint.test.mjs` drift-guard + `hide-footprint.test.mjs` / `.integration.test.mjs`), `family-registry.mjs` (the **unified family registry** behind `/agent-workflow-kit status` — aggregates every member's `capability.json`; pinned by a `family-registry.test.mjs` drift-guard), `uninstall.mjs` (the **guarded teardown** behind `/agent-workflow-kit uninstall` — classify each surface, preflight-then-mutate, never delete user-authored content), and `release-scan.mjs` (the attribution-off release gate). The bundled bridge skill mirrors live under [`bridges/`](bridges/) (byte-identical to the repo-root bridges, pinned by `test/bridges-mirror.test.mjs`). See [`tools/manifest/schema.md`](tools/manifest/schema.md).
419
495
  - [`capability.json`](capability.json) — the kit's own `agent-workflow` family manifest (`kind: composition-root`).
420
496
  - [`CHANGELOG.md`](CHANGELOG.md) — version history of this kernel.
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "1.15.1",
6
+ "version": "1.16.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "1.15.1",
3
+ "version": "1.16.0",
4
4
  "description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -50,7 +50,10 @@
50
50
  "launchers/",
51
51
  "migrations/",
52
52
  "tools/",
53
- "bridges/"
53
+ "bridges/",
54
+ "!bin/*.test.mjs",
55
+ "!tools/**/*.test.mjs",
56
+ "!tools/manifest/fixtures/**"
54
57
  ],
55
58
  "engines": {
56
59
  "node": ">=18"
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env node
2
+ // commands.mjs — the kit's canonical command catalog + the pure invocation router behind the
3
+ // `/agent-workflow-kit help` index and the safe unknown-invocation routing rule.
4
+ //
5
+ // Until now the modes existed only as `### Mode:` headers in SKILL.md, never enumerated for the user:
6
+ // there was no discoverable command surface and no executable answer to "what did the user actually
7
+ // invoke?". This module is the SINGLE source of truth for both — one frozen catalog (one entry per
8
+ // mode, grouped + tagged read-only/writer/guarded with a plain-language one-liner) that the `help`
9
+ // mode renders and the report footers point at, plus `routeInvocation(token)` that maps a raw
10
+ // subcommand token to its mode.
11
+ //
12
+ // Safety invariant (pinned by the tests): `bootstrap` is a writer and the BARE/EMPTY invocation maps
13
+ // to it — that is the ONE acknowledged exception, itself guarded downstream by the existing
14
+ // "docs/ai/ exists → ask upgrade-vs-bootstrap" check (SKILL.md Mode: bootstrap). The invariant is
15
+ // therefore: NO unrecognized/garbage token ever maps to a writer/guarded mode — every such token
16
+ // routes to `help`, which is read-only.
17
+ //
18
+ // Source of truth = the COMMANDS table below; a drift-guard test (commands.test.mjs) pins its keys to
19
+ // the `### Mode:` headers in SKILL.md, so the catalog cannot silently drift from the documented modes.
20
+ // Pure, dependency-free, Node >= 18. No side effects on import (the isDirectRun idiom).
21
+
22
+ import { pathToFileURL } from 'node:url';
23
+
24
+ const SKILL_NAME = 'agent-workflow-kit';
25
+ const BARE_INVOCATION = `/${SKILL_NAME}`;
26
+ const invocationOf = (token) => `${BARE_INVOCATION}${token ? ` ${token}` : ''}`;
27
+
28
+ // ── kinds ────────────────────────────────────────────────────────────────────────
29
+ // read-only — never writes, never commits, never runs a subscription CLI.
30
+ // writer — writes files (a project deployment or a settings/skill placement).
31
+ // guarded — a destructive teardown gated behind a mandatory dry-run-first + explicit consent.
32
+ // `writer` and `guarded` are the "acts on the system" kinds; only an explicit known token may reach
33
+ // one (plus the bare bootstrap exception). Garbage routes to `help` (read-only) — see routeInvocation.
34
+ export const READ_ONLY = 'read-only';
35
+ export const WRITER = 'writer';
36
+ export const GUARDED = 'guarded';
37
+ const KINDS = new Set([READ_ONLY, WRITER, GUARDED]);
38
+
39
+ // ── groups (fixed render order) ────────────────────────────────────────────────────
40
+ export const GROUP_ORDER = Object.freeze(['Inspect', 'Configure', 'Orchestrate', 'Lifecycle']);
41
+
42
+ // ── the canonical catalog ──────────────────────────────────────────────────────────
43
+ // One entry per `### Mode:` in SKILL.md. `key` is the mode (and, for every non-bootstrap mode, the
44
+ // routable subcommand token — bootstrap is the bare invocation, so it has no token). `oneLine` is
45
+ // plain-language: NO internal terms (no reconcile/fence/stamp/manifest/anchor) a third-party user
46
+ // hasn't read SKILL.md for. The drift-guard test pins these keys to the SKILL.md headers.
47
+ const CATALOG = [
48
+ {
49
+ key: 'bootstrap',
50
+ invocation: BARE_INVOCATION,
51
+ group: 'Lifecycle',
52
+ kind: WRITER,
53
+ oneLine: 'Deploy the memory & workflow system into a new or empty project (asks visibility, language, and attribution first).',
54
+ },
55
+ {
56
+ key: 'upgrade',
57
+ invocation: invocationOf('upgrade'),
58
+ group: 'Lifecycle',
59
+ kind: WRITER,
60
+ oneLine: 'Bring an existing deployment up to the current version — your authored notes are preserved.',
61
+ },
62
+ {
63
+ key: 'uninstall',
64
+ invocation: invocationOf('uninstall'),
65
+ group: 'Lifecycle',
66
+ kind: GUARDED,
67
+ oneLine: 'Remove only what setup placed; it never deletes your notes and always previews before changing anything.',
68
+ },
69
+ {
70
+ key: 'status',
71
+ invocation: invocationOf('status'),
72
+ group: 'Inspect',
73
+ kind: READ_ONLY,
74
+ oneLine: 'Show what is installed and at what version, your settings and backends, and what is deployed in this project.',
75
+ },
76
+ {
77
+ key: 'backends',
78
+ invocation: invocationOf('backends'),
79
+ group: 'Inspect',
80
+ kind: READ_ONLY,
81
+ oneLine: 'Check which optional review/execute backends (codex, agy) are set up versus missing, and the next step.',
82
+ },
83
+ {
84
+ key: 'help',
85
+ invocation: invocationOf('help'),
86
+ group: 'Inspect',
87
+ kind: READ_ONLY,
88
+ oneLine: 'List every command, grouped, marking each as read-only or as one that makes changes.',
89
+ },
90
+ {
91
+ key: 'setup',
92
+ invocation: invocationOf('setup'),
93
+ group: 'Configure',
94
+ kind: WRITER,
95
+ oneLine: 'Set up an optional backend — place its helper and link its commands onto your PATH (opt-in; preview first).',
96
+ },
97
+ {
98
+ key: 'velocity',
99
+ invocation: invocationOf('velocity'),
100
+ group: 'Configure',
101
+ kind: WRITER,
102
+ oneLine: 'Seed a read-only command allowlist so routine read-only commands stop prompting (Claude Code; opt-in; preview first).',
103
+ },
104
+ {
105
+ key: 'recipes',
106
+ invocation: invocationOf('recipes'),
107
+ group: 'Orchestrate',
108
+ kind: READ_ONLY,
109
+ oneLine: 'See the orchestration recipes (Solo / Reviewed / Council / Delegated) and which one fits this environment.',
110
+ },
111
+ {
112
+ key: 'procedures',
113
+ invocation: invocationOf('procedures'),
114
+ group: 'Orchestrate',
115
+ kind: READ_ONLY,
116
+ oneLine: 'Show a named activity’s steps and which recipe applies at each stage here.',
117
+ },
118
+ ];
119
+
120
+ // Deep-freeze: freeze the array AND every entry, so the catalog is genuinely immutable at runtime
121
+ // (Object.freeze on the array alone leaves the entry objects writable).
122
+ export const COMMANDS = Object.freeze(CATALOG.map((c) => Object.freeze(c)));
123
+
124
+ // The mode every garbage/unrecognized token routes to. Read-only by contract (see routeInvocation).
125
+ export const UNKNOWN_INVOCATION_MODE = 'help';
126
+ // The mode the bare/empty invocation maps to — the one writer reachable without an explicit token,
127
+ // guarded downstream by the docs/ai upgrade-vs-bootstrap check.
128
+ export const BARE_INVOCATION_MODE = 'bootstrap';
129
+
130
+ const byKey = new Map(COMMANDS.map((c) => [c.key, c]));
131
+ // Routable subcommand tokens = every mode except bootstrap (whose invocation is the bare default).
132
+ const ROUTABLE_TOKENS = new Set(COMMANDS.filter((c) => c.key !== BARE_INVOCATION_MODE).map((c) => c.key));
133
+
134
+ export const commandFor = (key) => byKey.get(key) ?? null;
135
+ export const kindOf = (key) => byKey.get(key)?.kind ?? null;
136
+
137
+ // ── the pure router ────────────────────────────────────────────────────────────────
138
+ // routeInvocation(token) → a mode key. `token` is the subcommand the user typed — either the raw word
139
+ // (`upgrade`) OR the full slash form (`/agent-workflow-kit upgrade`); the first word is significant
140
+ // and trailing args are ignored. Precise semantics:
141
+ // undefined / null / '' / whitespace-only / the exact bare invocation → 'bootstrap'
142
+ // a known first token (upgrade/status/setup/backends/recipes/procedures/velocity/uninstall/help)
143
+ // → that mode
144
+ // anything else (unrecognized / ambiguous) → 'help' (read-only — NEVER a writer/guarded mode)
145
+ export const routeInvocation = (token) => {
146
+ if (token == null) return BARE_INVOCATION_MODE;
147
+ const trimmed = String(token).trim();
148
+ if (trimmed === '' || trimmed === BARE_INVOCATION) return BARE_INVOCATION_MODE;
149
+ // Accept either the raw subcommand token OR the full slash invocation the user types — strip a
150
+ // leading `/agent-workflow-kit ` prefix so `/agent-workflow-kit upgrade` routes like `upgrade`.
151
+ const rest = trimmed.startsWith(`${BARE_INVOCATION} `)
152
+ ? trimmed.slice(BARE_INVOCATION.length).trim()
153
+ : trimmed;
154
+ if (rest === '') return BARE_INVOCATION_MODE;
155
+ const first = rest.split(/\s+/)[0];
156
+ return ROUTABLE_TOKENS.has(first) ? first : UNKNOWN_INVOCATION_MODE;
157
+ };
158
+
159
+ // ── render ──────────────────────────────────────────────────────────────────────────
160
+
161
+ const KIND_TAG = { [READ_ONLY]: '[read-only]', [WRITER]: '[writer] ', [GUARDED]: '[guarded] ' };
162
+ const pad = (s, n) => (s.length >= n ? s : s + ' '.repeat(n - s.length));
163
+
164
+ // formatHelp() → the grouped, kind-tagged human index. Deterministic; groups in GROUP_ORDER, modes in
165
+ // catalog order within each group. The header states the index itself is read-only.
166
+ export const formatHelp = () => {
167
+ const invocWidth = Math.max(...COMMANDS.map((c) => c.invocation.length));
168
+ const lines = [
169
+ `${SKILL_NAME} — command index (this list is read-only)`,
170
+ '',
171
+ 'Each command is tagged read-only · writer (makes changes) · guarded (destructive, previews first).',
172
+ ];
173
+ for (const group of GROUP_ORDER) {
174
+ const inGroup = COMMANDS.filter((c) => c.group === group);
175
+ if (!inGroup.length) continue;
176
+ lines.push('', group);
177
+ for (const c of inGroup) {
178
+ lines.push(` ${pad(c.invocation, invocWidth)} ${KIND_TAG[c.kind] ?? c.kind} ${c.oneLine}`);
179
+ }
180
+ }
181
+ return lines.join('\n');
182
+ };
183
+
184
+ // The machine form behind `--json`: the flat catalog (machines group by `group` themselves) plus the
185
+ // two routing anchors, so a consumer can reproduce routeInvocation without re-deriving the rules.
186
+ export const buildJson = () => ({
187
+ skill: SKILL_NAME,
188
+ groupOrder: [...GROUP_ORDER],
189
+ unknownInvocationMode: UNKNOWN_INVOCATION_MODE,
190
+ bareInvocationMode: BARE_INVOCATION_MODE,
191
+ commands: COMMANDS.map(({ key, invocation, group, kind, oneLine }) => ({ key, invocation, group, kind, oneLine })),
192
+ });
193
+
194
+ // ── CLI ──────────────────────────────────────────────────────────────────────────────
195
+ const main = (argv) => {
196
+ if (argv.includes('--json')) {
197
+ console.log(JSON.stringify(buildJson(), null, 2));
198
+ return;
199
+ }
200
+ console.log(formatHelp());
201
+ };
202
+
203
+ const isDirectRun = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
204
+ if (isDirectRun) main(process.argv.slice(2));
205
+
206
+ export { KINDS, SKILL_NAME, BARE_INVOCATION };
@@ -20,8 +20,16 @@ export const EXPECTED_MEMORY_NAME = 'agent-workflow-memory';
20
20
  // The assets a memory candidate must carry, AND their required type. A partial install (manifest +
21
21
  // SKILL.md only) is missing these → invalid → fallback. Checking the type (not just existence)
22
22
  // rejects a wrong-shaped install (e.g. a file where a dir is expected) BEFORE any project write.
23
+ //
24
+ // `references/templates/orchestration.json` (Step 2.4) is a SURGICAL gate: a memory too old to ship
25
+ // the orchestration-config template (pre-1.2.0, e.g. v1.0.0) can't seed `docs/ai/orchestration.json`,
26
+ // so it must NOT be delegate-classified — the kit then falls back to its OWN bundled substrate, which
27
+ // DOES seed orchestration.json (Mode: upgrade step 3). This closes the stale-memory trap that the
28
+ // read-only family-registry note (MEMORY_ORCH_TEMPLATE_REL) only INFORMS about — the gate ACTS. The
29
+ // two key on the same asset; a cross-tool parity test pins them in lockstep.
23
30
  export const REQUIRED_MEMORY_ASSETS = [
24
31
  { path: 'references/templates', type: 'dir' },
32
+ { path: 'references/templates/orchestration.json', type: 'file' },
25
33
  { path: 'references/contracts.md', type: 'file' },
26
34
  { path: 'references/scripts', type: 'dir' },
27
35
  { path: 'scripts/stamp-takeover.mjs', type: 'file' },