heyspex 0.2.4 → 0.2.6

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 (48) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/bin/hs.mjs +281 -30
  3. package/dev-factory/lib/dispatch-guard.mjs +75 -0
  4. package/dev-factory/lib/runner-path.mjs +51 -0
  5. package/dev-factory/spexcrawl/spexcrawl-cli.mjs +734 -0
  6. package/dist/cli/hs-connect.mjs +20 -1
  7. package/dist/cli/hs-defer.mjs +3802 -3744
  8. package/dist/cli/hs-events.mjs +1296 -0
  9. package/dist/cli/hs-export-events.mjs +1252 -0
  10. package/dist/cli/hs-handoff.mjs +2576 -0
  11. package/dist/cli/hs-index-rebuild.mjs +209 -36
  12. package/dist/cli/hs-index-reconcile.mjs +212 -39
  13. package/dist/cli/hs-init.mjs +20 -1
  14. package/dist/cli/hs-install.mjs +20 -1
  15. package/dist/cli/hs-join.mjs +20 -1
  16. package/dist/cli/hs-next-launch.mjs +2698 -0
  17. package/dist/cli/hs-pin.mjs +1336 -0
  18. package/dist/cli/hs-prereq.mjs +1380 -0
  19. package/dist/cli/hs-revalidate.mjs +3257 -0
  20. package/dist/cli/hs-spawn.mjs +12377 -0
  21. package/dist/cli/hs-test.mjs +1046 -0
  22. package/dist/cli/hs-trash.mjs +362 -0
  23. package/dist/cli/hs-trust.mjs +197 -0
  24. package/dist/cli/hs-vault-pull.mjs +214 -41
  25. package/dist/cli/hs-vault-push.mjs +212 -39
  26. package/dist/cli-templates/harness-commands/claude/hs-log.md +1 -1
  27. package/dist/cli-templates/harness-commands/claude/hs-res.md +71 -63
  28. package/dist/cli-templates/harness-commands/claude/hs-review.md +23 -23
  29. package/dist/cli-templates/harness-commands/cursor/hs-log.md +1 -1
  30. package/dist/cli-templates/harness-commands/cursor/hs-res.md +66 -58
  31. package/dist/cli-templates/harness-commands/cursor/hs-review.md +18 -18
  32. package/docs/copilot-plugin-install.md +2 -2
  33. package/package.json +9 -5
  34. package/plugins/heyspex/.claude-plugin/plugin.json +1 -1
  35. package/plugins/heyspex/.cursor-plugin/plugin.json +1 -1
  36. package/scripts/claude-hooks/wip-checkpoint.mjs +17 -2
  37. package/scripts/claude-statusline/statusline-command.mjs +287 -27
  38. package/scripts/hs-companion.mjs +8 -0
  39. package/scripts/install-claude-code-hooks.mjs +104 -3
  40. package/scripts/install-copilot-hooks.mjs +21 -1
  41. package/scripts/install-cursor-hooks.mjs +4 -3
  42. package/scripts/lib/capture-execution-guard.mjs +221 -0
  43. package/scripts/lib/customer-kit.mjs +48 -0
  44. package/scripts/lib/hs-companion-settings.mjs +25 -0
  45. package/scripts/record-grounding.mjs +38 -0
  46. package/vendor/heyspex-mcp/http-transport.mjs +1 -1
  47. package/vendor/heyspex-mcp/test-helpers.mjs +37 -23
  48. package/bin/postinstall.mjs +0 -88
@@ -7,61 +7,69 @@ description: Confidence-ladder research method's entrypoint — SpexCrawl via th
7
7
 
8
8
  **Usage:** `/hs-res [research question/topic]`
9
9
 
10
- # Research (`/hs-res`)
11
-
12
- > Parity: `.commandcode/skills/hs-res/SKILL.md` · `.cursor/skills/hs-res/SKILL.md` · `.agents/skills/hs-res/SKILL.md`
13
-
14
- ## What to do
15
-
16
- 1. **Take the question.** `$ARGUMENTS` is the research question/topic. If empty, load the
17
- console doc-toolbar Promote pin via `heyspex_active_research`
18
- (`.heyspex/research-focus.yaml` → `source_idea_id`, `scope`, `spec_path`) and read the source
19
- capture body as the question. Either way, restate the scope and confirm with the user.
20
-
21
- 2. **Gather via SpexCrawl (the Companion) — the PRIMARY method** (owner ruling 2026-08-14,
22
- [[spexcrawl-through-the-companion-is-the]]: "Companion > SpexCrawl is now default method
23
- for research"). Decompose into a few independent search angles, then per angle:
24
- `node dev-factory/spexcrawl/spexcrawl-cli.mjs search "<query>" --json` — one call
25
- searches AND returns the cleaned pages of the top results. Specific extra URLs:
26
- `node dev-factory/spexcrawl/spexcrawl-cli.mjs scrape "<url>" --json`.
27
- Prerequisites: the Companion running and paired to the console. LAN mode
28
- (`npm run console:log:lan`) is needed ONLY when the Companion runs on a DIFFERENT
29
- machine than the console — since HS-V9WH the Companion polls loopback consoles too
30
- ([[a-queue-is-dead-if-its-only-consumer]]: the LAN line was a bug workaround
31
- misdocumented as a requirement). When missing, the CLI exits 3 with
32
- `SPEXCRAWL_UNAVAILABLE` naming the fix; a silent hang means the Companion is not
33
- running or not polling this console.
34
-
35
- **Fallback — self-hosted Firecrawl, AUTOMATIC, no permission needed (owner ruling
36
- 2026-08-22).** When the SpexCrawl path malfunctions, times out, hits a gate, or is otherwise
37
- unavailable, fall back immediately: `node dev-factory/spexcrawl/firecrawl-cli.mjs
38
- search "<query>" --json` and `node dev-factory/spexcrawl/firecrawl-cli.mjs scrape
39
- "<url>" --json`. May run on any fleet machine (coffee-geek, basement-geek, spec-ops) —
40
- prefer other reachable machines over the one the orchestrating session runs on; check
41
- `docker info`, start Docker/the stack if needed, poll the real endpoint for readiness before
42
- use. If this task's changed/claimed files are SpexCrawl-related, skip SpexCrawl entirely and
43
- go straight to Firecrawl. Hosted `api.firecrawl.dev` credits are unchanged — still
44
- ask-before-spend every time. Full contract: `.commandcode/skills/hs-res/SKILL.md`.
45
-
46
- 3. **Assemble a numbered sources block** (`[S1]`, `[S2]`, …) from the gathered
47
- `{title, url, snippet, markdown}` results, write it plus the question and cite-only
48
- instructions to a temp prompt file.
49
-
50
- 4. **Synthesize via DeepSeek** —
51
- `node dev-factory/spexcrawl/synthesize-cli.mjs --prompt-file <path> --json`
52
- (defaults `--max-tokens` to 32000 and auto-escalates ×3 up to a 96000 ceiling if DeepSeek's
53
- default-on "thinking" mode burns the whole budget on reasoning — never pass a lower
54
- `--max-tokens` yourself; the CLI self-heals this failure mode. Exhausted escalation exits 3
55
- with `SYNTHESIZE_UNAVAILABLE`).
56
-
57
- 5. **Save** via `heyspex_save_research` (or `heyspex_complete_research` under the console pin
58
- pipeline), with `sources` populated from the gathered URLs.
59
-
60
- **Never fall back** to `deep-research`/`deep-research-quick|medium|thorough`, the
61
- `Workflow({ scriptPath: '.claude/workflows/deep-research-*.js' })` launch, or native
62
- `WebSearch`/`WebFetch` for this method. Self-hosted Firecrawl fallback is automatic (no
63
- permission needed, 2026-08-22 ruling); hosted `api.firecrawl.dev` credits still need the
64
- user's explicit per-run permission, every time. If a CLI reports unavailable
65
- (`SPEXCRAWL_UNAVAILABLE` / `FIRECRAWL_UNAVAILABLE` / `SYNTHESIZE_UNAVAILABLE`, exit 3),
66
- **stop** and tell the user — never silently substitute another backend. Full method,
67
- escalation rule, and hard prohibitions: `.commandcode/skills/hs-res/SKILL.md`.
10
+ # Research (`/hs-res`)
11
+
12
+ > Parity: `.commandcode/skills/hs-res/SKILL.md` · `.cursor/skills/hs-res/SKILL.md` · `.agents/skills/hs-res/SKILL.md`
13
+
14
+ ## What to do
15
+
16
+ 1. **Take the question.** `$ARGUMENTS` is the research question/topic. If empty, load the
17
+ console doc-toolbar Promote pin via `heyspex_active_research`
18
+ (`.heyspex/research-focus.yaml` → `source_idea_id`, `scope`, `spec_path`) and read the source
19
+ capture body as the question. Either way, restate the scope and confirm with the user.
20
+
21
+ 2. **Gather via SpexCrawl (the Companion) — the PRIMARY method** (owner ruling 2026-08-14,
22
+ [[spexcrawl-through-the-companion-is-the]]: "Companion > SpexCrawl is now default method
23
+ for research"). Decompose into a few independent search angles, then per angle:
24
+ `node dev-factory/spexcrawl/spexcrawl-cli.mjs search "<query>" --json` — one call
25
+ searches AND returns the cleaned pages of the top results. Specific extra URLs:
26
+ `node dev-factory/spexcrawl/spexcrawl-cli.mjs scrape "<url>" --json`.
27
+ Prerequisites: the Companion running and paired to the console. LAN mode
28
+ (`npm run console:log:lan`) is needed ONLY when the Companion runs on a DIFFERENT
29
+ machine than the console — since HS-V9WH the Companion polls loopback consoles too
30
+ ([[a-queue-is-dead-if-its-only-consumer]]: the LAN line was a bug workaround
31
+ misdocumented as a requirement). When missing, the CLI exits 3 with
32
+ `SPEXCRAWL_UNAVAILABLE` naming the fix; a silent hang means the Companion is not
33
+ running or not polling this console.
34
+
35
+ **Fallback — self-hosted Firecrawl, AUTOMATIC, no permission needed (owner ruling
36
+ 2026-08-22).** When the SpexCrawl path malfunctions, times out, hits a gate, or is otherwise
37
+ unavailable, fall back immediately: `node dev-factory/spexcrawl/firecrawl-cli.mjs
38
+ search "<query>" --json` and `node dev-factory/spexcrawl/firecrawl-cli.mjs scrape
39
+ "<url>" --json`. May run on any fleet machine (coffee-geek, basement-geek, spec-ops) —
40
+ prefer other reachable machines over the one the orchestrating session runs on; check
41
+ `docker info`, start Docker/the stack if needed, poll the real endpoint for readiness before
42
+ use. If this task's changed/claimed files are SpexCrawl-related, skip SpexCrawl entirely and
43
+ go straight to Firecrawl. Hosted `api.firecrawl.dev` credits are unchanged — still
44
+ ask-before-spend every time. Full contract: `.commandcode/skills/hs-res/SKILL.md`.
45
+
46
+ **In a repo that uses the `heyspex` npm package** (not a HeySpex platform checkout): the
47
+ package ships only the SpexCrawl client (`dev-factory/spexcrawl/spexcrawl-cli.mjs` under
48
+ `node_modules/heyspex/`). It needs the HeySpex Companion, which the npm package does not
49
+ distribute yet, so it usually exits 3 `SPEXCRAWL_UNAVAILABLE`. The Firecrawl fallback and
50
+ the DeepSeek synthesis CLI (`firecrawl-cli.mjs`, `synthesize-cli.mjs`) are HeySpex-platform
51
+ only and are not in the package. When a CLI named in steps 2 or 4 is missing or reports
52
+ unavailable, stop and tell the user this research method is not available in their install.
53
+
54
+ 3. **Assemble a numbered sources block** (`[S1]`, `[S2]`, …) from the gathered
55
+ `{title, url, snippet, markdown}` results, write it plus the question and cite-only
56
+ instructions to a temp prompt file.
57
+
58
+ 4. **Synthesize via DeepSeek** —
59
+ `node dev-factory/spexcrawl/synthesize-cli.mjs --prompt-file <path> --json`
60
+ (defaults `--max-tokens` to 32000 and auto-escalates ×3 up to a 96000 ceiling if DeepSeek's
61
+ default-on "thinking" mode burns the whole budget on reasoning — never pass a lower
62
+ `--max-tokens` yourself; the CLI self-heals this failure mode. Exhausted escalation exits 3
63
+ with `SYNTHESIZE_UNAVAILABLE`).
64
+
65
+ 5. **Save** via `heyspex_save_research` (or `heyspex_complete_research` under the console pin
66
+ pipeline), with `sources` populated from the gathered URLs.
67
+
68
+ **Never fall back** to `deep-research`/`deep-research-quick|medium|thorough`, the
69
+ `Workflow({ scriptPath: '.claude/workflows/deep-research-*.js' })` launch, or native
70
+ `WebSearch`/`WebFetch` for this method. Self-hosted Firecrawl fallback is automatic (no
71
+ permission needed, 2026-08-22 ruling); hosted `api.firecrawl.dev` credits still need the
72
+ user's explicit per-run permission, every time. If a CLI reports unavailable
73
+ (`SPEXCRAWL_UNAVAILABLE` / `FIRECRAWL_UNAVAILABLE` / `SYNTHESIZE_UNAVAILABLE`, exit 3),
74
+ **stop** and tell the user — never silently substitute another backend. Full method,
75
+ escalation rule, and hard prohibitions: `.commandcode/skills/hs-res/SKILL.md`.
@@ -1,26 +1,26 @@
1
1
  ---
2
2
  name: hs-review
3
- description: Pull the next review-ready spec from the HeySpex review queue (review-focus.yaml → manifest traversal of `status: in_review` with HS-REV companion → folder scan).
3
+ description: 'Pull the next review-ready spec from the HeySpex review queue (review-focus.yaml → manifest traversal of `status: in_review` with HS-REV companion → folder scan).'
4
4
  ---
5
5
 
6
6
  <!-- Generated by scripts/sync-skills.mjs from .claude/commands/hs-review.md — do not edit by hand. Run `npm run skills:sync`. -->
7
7
 
8
8
  **Usage:** `/hs-review [HS-XXXX-TASK | HS-XXXX-EPIC] [--ignore-focus]`
9
9
 
10
- Invoke the `heyspex_next_review` MCP tool to fetch the next review-ready spec from the HeySpex vault, then paste the returned `prompt_markdown` verbatim so the user (reviewer) can walk acceptance against the parent spec + HS-REV companion.
11
-
12
- Argument parsing for `$ARGUMENTS` (all optional; if `$ARGUMENTS` is empty, call the tool with no parameters):
13
-
14
- - A bare token matching `HS-TASK-*` / `HS-EPIC-*` / `HS-*-*` → pass as `spec_id`.
15
- - A bare token matching `HS-ROADMAP-*` → pass as `roadmap_id`.
16
- - `--ignore-focus` → set `ignore_focus: true`.
17
-
18
- Resolution precedence (built into the tool, do not re-implement here): `args.spec_id` → `.heyspex/review-focus.yaml` pin → manifest traversal for `status: in_review` specs with an `HS-REV-<suffix>-*.md` companion → folder scan as fallback. Sorted by `updated:` ascending (oldest first).
19
-
20
- After the tool returns, output the `prompt_markdown` field as-is, then on a final line state the source: `_Source: {source_kind} · {spec_id} · phase {phase_id} · age {age_in_review_days}d_`. Do not summarize, paraphrase, or start executing the returned prompt.
21
-
22
- This skill does NOT claim the spec. Reviewing is a human-in-loop activity by design (CLAUDE.md §Session Completion); the reviewer walks the four sections of the HS-REV companion (`## Acceptance verification`, `## Reviewer notes`, `## Memory candidates`, `## Decision: close or reopen`) and decides pass/reopen. Memory candidates are scored against the four-axis rubric (non-derivability / reusability / surprise-cost / concreteness, 0–3 each, threshold ≥ 7/12) — the prompt body includes the rubric and the conflict-check instruction.
23
-
24
- If the tool errors with `NO_REVIEW_READY`, tell the user the review queue is empty (no specs at `status: in_review` with an HS-REV companion) and suggest checking `specs/reviews/` for stale companions or filing the missing review doc. If `SPEC_NOT_IN_REVIEW`, surface the spec's actual status so the user can pick the right `/hs-review HS-XXXX` target. If `NO_REVIEW_DOC`, the parent spec is `in_review` but has no `HS-REV-<suffix>-*.md` companion — point the user at CLAUDE.md §Session Completion §3 for the four-section template.
25
-
26
- Cross-reference: [[HS-XRO1-RVDC-TASK-heyspex-review-on-deck-mcp-and-hs-review]] (spec), [[HS-UKD6-CLR4-RES-close-out-review-screen-jtbd-architecture]] §J17 (downstream Review surface that will call this tool from the "Copy `/hs-review`" affordance).
10
+ Invoke the `heyspex_next_review` MCP tool to fetch the next review-ready spec from the HeySpex vault, then paste the returned `prompt_markdown` verbatim so the user (reviewer) can walk acceptance against the parent spec + HS-REV companion.
11
+
12
+ Argument parsing for `$ARGUMENTS` (all optional; if `$ARGUMENTS` is empty, call the tool with no parameters):
13
+
14
+ - A bare token matching `HS-TASK-*` / `HS-EPIC-*` / `HS-*-*` → pass as `spec_id`.
15
+ - A bare token matching `HS-ROADMAP-*` → pass as `roadmap_id`.
16
+ - `--ignore-focus` → set `ignore_focus: true`.
17
+
18
+ Resolution precedence (built into the tool, do not re-implement here): `args.spec_id` → `.heyspex/review-focus.yaml` pin → manifest traversal for `status: in_review` specs with an `HS-REV-<suffix>-*.md` companion → folder scan as fallback. Sorted by `updated:` ascending (oldest first).
19
+
20
+ After the tool returns, output the `prompt_markdown` field as-is, then on a final line state the source: `_Source: {source_kind} · {spec_id} · phase {phase_id} · age {age_in_review_days}d_`. Do not summarize, paraphrase, or start executing the returned prompt.
21
+
22
+ This skill does NOT claim the spec. Reviewing is a human-in-loop activity by design (CLAUDE.md §Session Completion); the reviewer walks the four sections of the HS-REV companion (`## Acceptance verification`, `## Reviewer notes`, `## Memory candidates`, `## Decision: close or reopen`) and decides pass/reopen. Memory candidates are scored against the four-axis rubric (non-derivability / reusability / surprise-cost / concreteness, 0–3 each, threshold ≥ 7/12) — the prompt body includes the rubric and the conflict-check instruction.
23
+
24
+ If the tool errors with `NO_REVIEW_READY`, tell the user the review queue is empty (no specs at `status: in_review` with an HS-REV companion) and suggest checking `specs/reviews/` for stale companions or filing the missing review doc. If `SPEC_NOT_IN_REVIEW`, surface the spec's actual status so the user can pick the right `/hs-review HS-XXXX` target. If `NO_REVIEW_DOC`, the parent spec is `in_review` but has no `HS-REV-<suffix>-*.md` companion — point the user at CLAUDE.md §Session Completion §3 for the four-section template.
25
+
26
+ Cross-reference: [[HS-XRO1-RVDC-TASK-heyspex-review-on-deck-mcp-and-hs-review]] (spec), [[HS-UKD6-CLR4-RES-close-out-review-screen-jtbd-architecture]] §J17 (downstream Review surface that will call this tool from the "Copy `/hs-review`" affordance).
@@ -32,7 +32,7 @@ The heyspex-app repository is not required and is not available to customers. Ev
32
32
  works from the published npm package `heyspex` (or a tarball your HeySpex contact hands you), which
33
33
  carries the plugin, the marketplace manifest, the hooks and the MCP server.
34
34
 
35
- - Node.js 20 or newer on PATH (`node --version`).
35
+ - Node.js 20–24 on PATH (`node --version`; the package requires `>=20 <25`).
36
36
  - GitHub Copilot CLI installed and signed in. Any one of: the GitHub Copilot app (its bundled
37
37
  `%LOCALAPPDATA%\github-copilot-sdk\cli\<version>\copilot.exe` is auto-detected, newest version
38
38
  wins, no PATH entry needed), `npm install -g @github/copilot`, or `winget install GitHub.Copilot`.
@@ -43,7 +43,7 @@ carries the plugin, the marketplace manifest, the hooks and the MCP server.
43
43
  ```bash
44
44
  npm install heyspex
45
45
  # or, from a tarball you were given:
46
- npm install ./heyspex-0.2.0.tgz
46
+ npm install ./heyspex-<version>.tgz
47
47
  ```
48
48
 
49
49
  - Sign the machine in to the HeySpex console so hooks and MCP tools can reach the vault:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heyspex",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "HeySpex CLI + MCP server — connect Claude Code, Cursor, and any MCP client to your HeySpex spec vault",
5
5
  "keywords": [
6
6
  "heyspex",
@@ -37,7 +37,6 @@
37
37
  },
38
38
  "files": [
39
39
  "bin/hs.mjs",
40
- "bin/postinstall.mjs",
41
40
  "bin/hs-vault-binding.mjs",
42
41
  "vendor/heyspex-mcp/**/*.mjs",
43
42
  "!vendor/heyspex-mcp/**/*.test.mjs",
@@ -66,6 +65,7 @@
66
65
  "dev-factory/lib/sufficiency-score.mjs",
67
66
  "dev-factory/lib/model-catalog.mjs",
68
67
  "dev-factory/model-catalog.json",
68
+ "dev-factory/spexcrawl/spexcrawl-cli.mjs",
69
69
  "docs/mcp-client-config.md",
70
70
  "docs/copilot-plugin-install.md",
71
71
  "docs/driving-heyspex-from-copilot.md",
@@ -88,8 +88,12 @@
88
88
  "scripts/lib/hs-worktree-args.mjs",
89
89
  "dev-factory/lib/worktree-allocator.mjs",
90
90
  "dev-factory/engine/worktree.mjs",
91
+ "dev-factory/lib/runner-path.mjs",
92
+ "dev-factory/lib/dispatch-guard.mjs",
91
93
  "scripts/hs-view.mjs",
92
94
  "scripts/hs-capture-cli.mjs",
95
+ "scripts/record-grounding.mjs",
96
+ "scripts/lib/capture-execution-guard.mjs",
93
97
  "scripts/lib/heyspex-home.mjs",
94
98
  "scripts/hs-companion.mjs",
95
99
  "scripts/lib/hs-companion-settings.mjs",
@@ -183,9 +187,9 @@
183
187
  "esbuild": "^0.24.2"
184
188
  },
185
189
  "scripts": {
186
- "prepack": "node scripts/build-cli-bundle.mjs && node scripts/prepack-closure-gate.mjs",
190
+ "prepack": "node scripts/sync-skills.mjs && node scripts/build-cli-bundle.mjs && node scripts/prepack-closure-gate.mjs && node scripts/pack-manifest.mjs strip",
191
+ "postpack": "node scripts/pack-manifest.mjs restore",
187
192
  "build:cli": "node scripts/build-cli-bundle.mjs",
188
- "postinstall": "node bin/postinstall.mjs",
189
193
  "setup": "node scripts/heyspex-doctor.mjs --fix",
190
194
  "doctor": "node scripts/heyspex-doctor.mjs",
191
195
  "heyspex:on": "node scripts/hs-mode.mjs on",
@@ -253,5 +257,5 @@
253
257
  "verify:onboarding": "node scripts/verify-onboarding-scenario.mjs --fake",
254
258
  "sweep": "node scripts/sweep.mjs"
255
259
  },
256
- "//files": "PUBLISHED SURFACE - every entry is verified by `node scripts/verify-mcp-package.mjs`. It must cover the STATIC import closure of vendor/heyspex-mcp/cli.mjs, plus (since [[HS-LGG2-WW9R-TASK-ship-the-hook-runtime-in-the-npm]]) the customer hook kit: scripts/claude-hooks/_run.mjs, every HOOK_SCOPES customer hook (scripts/lib/customer-kit.mjs) and their static closure under spexharness/src, dev-factory/lib and scripts/ - the hookTargets check names any file that falls out - plus the run-time data files in customer-kit.mjs CUSTOMER_HOOK_DATA (only the baseline edition of SpexCode Doctrine, never the learned spexharness/doctrine/SPEXCODE-DOCTRINE.json; [[HS-A2PO-WW9R-TASK-owner-ruling-does-inject-doctrine-ship]]) - and nothing else. SpexFleet internals (dev-factory/router.mjs, cloud-clients.mjs, cost-tracker.mjs, spexcrawl/) are deliberately absent - research-tools.mjs reaches them through the lazy dev-factory-bridge.mjs. Do not add a path here without re-running the verifier; npm publish is a one-way door ([[HS-ZJSP-0JNK-TASK-ship-the-heyspex-mcp-server-as-an]] / [[HS-8DET-0JNK-TASK-confirm-the-open-core-boundary-and]]). `dist/cli/*.mjs` + `dist/cli-templates/**` are a SEPARATE published surface (`hs-init`, `hs-install`, `hs-claim`, `hs-check`, `hs-env`, `hs-connect`, `hs-join`, `hs-vault`, `hs-workspace`, `hs-defer`, `hs-vault-pull`, `hs-vault-push`, `hs-dev`, `hs-index-rebuild`, `hs-index-reconcile` bundled by `scripts/build-cli-bundle.mjs`'s `ENTRIES` array, regenerated fresh every `prepack` - `dist/` itself stays git-ignored) - see that script's doc comment for the entry scope decision and [[HS-JOQX-0JNK-TASK-published-package-runs-hs-init-and-hs]]."
260
+ "//files": "PUBLISHED SURFACE - every entry is verified by `node scripts/verify-mcp-package.mjs`. It must cover the STATIC import closure of vendor/heyspex-mcp/cli.mjs, plus (since [[HS-LGG2-WW9R-TASK-ship-the-hook-runtime-in-the-npm]]) the customer hook kit: scripts/claude-hooks/_run.mjs, every HOOK_SCOPES customer hook (scripts/lib/customer-kit.mjs) and their static closure under spexharness/src, dev-factory/lib and scripts/ - the hookTargets check names any file that falls out - plus the run-time data files in customer-kit.mjs CUSTOMER_HOOK_DATA (only the baseline edition of SpexCode Doctrine, never the learned spexharness/doctrine/SPEXCODE-DOCTRINE.json; [[HS-A2PO-WW9R-TASK-owner-ruling-does-inject-doctrine-ship]]) - and nothing else. SpexFleet internals (dev-factory/router.mjs, cloud-clients.mjs, cost-tracker.mjs, spexcrawl/) are deliberately absent - research-tools.mjs reaches them through the lazy dev-factory-bridge.mjs. Do not add a path here without re-running the verifier; npm publish is a one-way door ([[HS-ZJSP-0JNK-TASK-ship-the-heyspex-mcp-server-as-an]] / [[HS-8DET-0JNK-TASK-confirm-the-open-core-boundary-and]]). `dist/cli/*.mjs` + `dist/cli-templates/**` are a SEPARATE published surface (`hs-init`, `hs-install`, `hs-claim`, `hs-check`, `hs-env`, `hs-connect`, `hs-join`, `hs-vault`, `hs-workspace`, `hs-defer`, `hs-vault-pull`, `hs-vault-push`, `hs-dev`, `hs-index-rebuild`, `hs-index-reconcile`, `hs-handoff`, `hs-pin`, `hs-events`, `hs-export-events`, `hs-prereq`, `hs-trash`, `hs-trust`, `hs-next-launch`, `hs-revalidate`, `hs-test`, `hs-spawn` bundled by `scripts/build-cli-bundle.mjs`'s `ENTRIES` array, regenerated fresh every `prepack` - `dist/` itself stays git-ignored) - see that script's doc comment for the entry scope decision and [[HS-JOQX-0JNK-TASK-published-package-runs-hs-init-and-hs]]."
257
261
  }
@@ -2,7 +2,7 @@
2
2
  "name": "heyspex",
3
3
  "displayName": "HeySpex",
4
4
  "icon": "./assets/heyspex-glyph-256.png",
5
- "description": "HeySpex vault integration for Claude Code and GitHub Copilot CLI (Claude-format plugin, installed from the same marketplace): MCP server (spec vault tools + hs-* prompts) and lifecycle hooks. Prototype packaging per HS-QTBK — additive; the project-level .mcp.json/settings.json wiring remains the live source of truth until cutover.",
5
+ "description": "SpexCode plugin (for Claude Code), also loaded by GitHub Copilot CLI (Claude-format plugin, installed from the same marketplace): HeySpex vault integration — MCP server (spec vault tools + hs-* prompts) and lifecycle hooks. Prototype packaging per HS-QTBK — additive; the project-level .mcp.json/settings.json wiring remains the live source of truth until cutover.",
6
6
  "author": {
7
7
  "name": "pwher",
8
8
  "email": "paul@monstergrowth.com"
@@ -3,7 +3,7 @@
3
3
  "displayName": "HeySpex",
4
4
  "version": "0.1.0",
5
5
  "logo": "assets/heyspex-glyph.svg",
6
- "description": "HeySpex vault integration for Cursor: MCP server (spec vault tools + hs-* workflows) and the full lifecycle hook set. Prototype packaging — additive; the project-level .cursor/mcp.json and .cursor/hooks.json wiring remains the live source of truth until cutover.",
6
+ "description": "Cursor build of the SpexCode plugin (for Claude Code): HeySpex vault integration for Cursor — MCP server (spec vault tools + hs-* workflows) and the full lifecycle hook set. Prototype packaging — additive; the project-level .cursor/mcp.json and .cursor/hooks.json wiring remains the live source of truth until cutover.",
7
7
  "author": {
8
8
  "name": "pwher",
9
9
  "email": "paul@monstergrowth.com"
@@ -49,6 +49,7 @@ import fs from 'node:fs';
49
49
  import path from 'node:path';
50
50
  import { fileURLToPath } from 'node:url';
51
51
  import { getActiveConfig, isResolvedVault } from '../../vendor/heyspex-mcp/vault-resolve.mjs';
52
+ import { parseSpecId } from '../../vendor/heyspex-mcp/spec-id-lib.mjs';
52
53
  import { hookVaultHeaders } from '../lib/hook-vault-header.mjs';
53
54
  import { resolveConsoleUrl as resolveConsoleUrlShared } from '../lib/console-url-resolver.mjs';
54
55
  import { readCredentialsMcpToken, resolveDevMode } from '../lib/dev-mode.mjs';
@@ -105,9 +106,23 @@ function ledgerRoots() {
105
106
  // HS-EPIC-BUD-PROTECT under vault id `vault-test`). Real ids are server-minted
106
107
  // file keys; a SessionStart preview must never present one of these as the
107
108
  // prior session's hand-off.
108
- const FIXTURE_ID_RE = /^HS-EPIC-(?:FILLER-\d+|OLD\d+|BUD-[A-Z0-9-]+|CLAIMED-BUD|TRIGGER(?:-[A-Z0-9-]+)?)$/;
109
+ // Parsed through the sanctioned id parser (spec-id-lib parseSpecId), never a
110
+ // hand-rolled type-first regex ([[HS-MIL-KY1F]]): only legacy type-first EPIC
111
+ // ids whose family token is one of the known fixture families qualify.
112
+ const FIXTURE_EPIC_FAMILIES = {
113
+ FILLER: (slug) => /^\d+$/.test(slug), // HS-EPIC-FILLER-07
114
+ BUD: (slug) => slug !== '', // HS-EPIC-BUD-PROTECT
115
+ CLAIMED: (slug) => slug === 'BUD', // HS-EPIC-CLAIMED-BUD
116
+ TRIGGER: () => true, // HS-EPIC-TRIGGER, HS-EPIC-TRIGGER-X
117
+ };
109
118
  function isFixtureLedgerEntry(epicId) {
110
- return typeof epicId === 'string' && FIXTURE_ID_RE.test(epicId);
119
+ if (typeof epicId !== 'string') return false;
120
+ const parsed = parseSpecId(epicId);
121
+ if (!parsed || parsed.ordering !== 'type-first' || parsed.typeLabel !== 'EPIC') return false;
122
+ const { familyKey, titleSlug } = parsed;
123
+ if (/^OLD\d+$/.test(familyKey)) return titleSlug === ''; // HS-EPIC-OLD34
124
+ const rule = FIXTURE_EPIC_FAMILIES[familyKey];
125
+ return rule ? rule(titleSlug) : false;
111
126
  }
112
127
 
113
128
  async function readStdinJson() {