heyspex 0.1.0 → 0.2.1

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 (352) hide show
  1. package/.claude-plugin/marketplace.json +14 -0
  2. package/README.md +21 -0
  3. package/bin/hs.mjs +1089 -104
  4. package/bin/spexcode.mjs +262 -0
  5. package/dev-factory/engine/worktree.mjs +740 -0
  6. package/dev-factory/lib/code-repo-root.mjs +67 -0
  7. package/dev-factory/lib/context-budget.mjs +84 -0
  8. package/dev-factory/lib/epic-detect.mjs +190 -0
  9. package/dev-factory/lib/fleet-queue-file.mjs +846 -0
  10. package/dev-factory/lib/fleet-queue.mjs +426 -0
  11. package/dev-factory/lib/fleet-state.mjs +14 -18
  12. package/dev-factory/lib/model-catalog.mjs +338 -0
  13. package/dev-factory/lib/seat-context.mjs +199 -0
  14. package/dev-factory/lib/spec-io.mjs +93 -0
  15. package/dev-factory/lib/sufficiency-score.mjs +8 -2
  16. package/dev-factory/lib/worktree-allocator.mjs +744 -0
  17. package/dev-factory/model-catalog.json +222 -0
  18. package/dist/cli/hs-check.mjs +1127 -103
  19. package/dist/cli/hs-claim.mjs +981 -63
  20. package/dist/cli/hs-connect.mjs +10059 -1729
  21. package/dist/cli/hs-defer.mjs +5507 -3072
  22. package/dist/cli/hs-dev.mjs +576 -0
  23. package/dist/cli/hs-env.mjs +416 -302
  24. package/dist/cli/hs-index-rebuild.mjs +7334 -0
  25. package/dist/cli/hs-index-reconcile.mjs +8138 -0
  26. package/dist/cli/hs-init.mjs +2840 -149
  27. package/dist/cli/hs-install.mjs +7214 -594
  28. package/dist/cli/hs-join.mjs +10640 -2421
  29. package/dist/cli/hs-vault-pull.mjs +8157 -6370
  30. package/dist/cli/hs-vault-push.mjs +6433 -0
  31. package/dist/cli/hs-vault.mjs +4029 -1555
  32. package/dist/cli/hs-workspace.mjs +2702 -538
  33. package/dist/cli-templates/customer-vault/specs/entity-model.md +594 -601
  34. package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +110 -177
  35. package/dist/cli-templates/customer-vault/specs/protocols/destructive-action-checklist.md +122 -0
  36. package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +13 -15
  37. package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +91 -0
  38. package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +150 -168
  39. package/dist/cli-templates/customer-vault/specs/protocols/spec-summary-authoring.md +83 -0
  40. package/dist/cli-templates/harness-commands/claude/hs-auto.md +36 -0
  41. package/dist/cli-templates/harness-commands/claude/hs-backfill.md +28 -0
  42. package/dist/cli-templates/harness-commands/claude/hs-capture.md +62 -0
  43. package/dist/cli-templates/harness-commands/claude/hs-defer.md +29 -0
  44. package/dist/cli-templates/harness-commands/claude/hs-dev.md +20 -0
  45. package/dist/cli-templates/harness-commands/claude/hs-doctor.md +32 -0
  46. package/dist/cli-templates/harness-commands/claude/hs-ground.md +30 -0
  47. package/dist/cli-templates/harness-commands/claude/hs-handoff.md +33 -0
  48. package/dist/cli-templates/harness-commands/claude/hs-log.md +27 -0
  49. package/dist/cli-templates/harness-commands/claude/hs-next.md +29 -0
  50. package/dist/cli-templates/harness-commands/claude/hs-promote.md +70 -0
  51. package/dist/cli-templates/harness-commands/claude/hs-push.md +35 -0
  52. package/dist/cli-templates/harness-commands/claude/hs-qc.md +27 -0
  53. package/dist/cli-templates/harness-commands/claude/hs-res.md +63 -0
  54. package/dist/cli-templates/harness-commands/claude/hs-resolve.md +23 -0
  55. package/dist/cli-templates/harness-commands/claude/hs-review.md +23 -0
  56. package/dist/cli-templates/harness-commands/claude/hs-view.md +28 -0
  57. package/dist/cli-templates/harness-commands/claude/kill-ports.md +32 -0
  58. package/dist/cli-templates/harness-commands/claude/prototype.md +91 -0
  59. package/dist/cli-templates/harness-commands/cursor/hs-auto.md +40 -0
  60. package/dist/cli-templates/harness-commands/cursor/hs-backfill.md +31 -0
  61. package/dist/cli-templates/harness-commands/cursor/hs-capture.md +65 -0
  62. package/dist/cli-templates/harness-commands/cursor/hs-defer.md +32 -0
  63. package/dist/cli-templates/harness-commands/cursor/hs-dev.md +24 -0
  64. package/dist/cli-templates/harness-commands/cursor/hs-doctor.md +36 -0
  65. package/dist/cli-templates/harness-commands/cursor/hs-ground.md +33 -0
  66. package/dist/cli-templates/harness-commands/cursor/hs-handoff.md +37 -0
  67. package/dist/cli-templates/harness-commands/cursor/hs-log.md +31 -0
  68. package/dist/cli-templates/harness-commands/cursor/hs-next.md +32 -0
  69. package/dist/cli-templates/harness-commands/cursor/hs-promote.md +73 -0
  70. package/dist/cli-templates/harness-commands/cursor/hs-push.md +38 -0
  71. package/dist/cli-templates/harness-commands/cursor/hs-qc.md +30 -0
  72. package/dist/cli-templates/harness-commands/cursor/hs-res.md +67 -0
  73. package/dist/cli-templates/harness-commands/cursor/hs-resolve.md +26 -0
  74. package/dist/cli-templates/harness-commands/cursor/hs-review.md +26 -0
  75. package/dist/cli-templates/harness-commands/cursor/hs-view.md +32 -0
  76. package/dist/cli-templates/harness-commands/cursor/kill-ports.md +35 -0
  77. package/dist/cli-templates/harness-commands/cursor/prototype.md +95 -0
  78. package/docs/copilot-plugin-install.md +162 -0
  79. package/docs/driving-heyspex-from-copilot.md +165 -0
  80. package/docs/mcp-client-config.md +259 -6
  81. package/package.json +249 -124
  82. package/plugins/heyspex/.claude-plugin/plugin.json +12 -0
  83. package/plugins/heyspex/.cursor-plugin/plugin.json +15 -0
  84. package/plugins/heyspex/.mcp.json +12 -0
  85. package/plugins/heyspex/README.md +309 -0
  86. package/plugins/heyspex/bin/launch-mcp.mjs +95 -0
  87. package/plugins/heyspex/bin/run-hook.mjs +80 -0
  88. package/plugins/heyspex/hooks/cursor-hooks.json +308 -0
  89. package/plugins/heyspex/hooks/hooks.json +418 -0
  90. package/plugins/heyspex/mcp.json +13 -0
  91. package/scripts/check-mcp-freshness.mjs +17 -9
  92. package/scripts/claude-hooks/_env-vault-events.mjs +68 -0
  93. package/scripts/claude-hooks/_guardrail-events.mjs +96 -0
  94. package/scripts/claude-hooks/_guardrail-loader.mjs +494 -0
  95. package/scripts/claude-hooks/_intent-classifier-router.mjs +456 -0
  96. package/scripts/claude-hooks/_intent-classifier-semantic.mjs +356 -0
  97. package/scripts/claude-hooks/_run.mjs +413 -0
  98. package/scripts/claude-hooks/_transcript-text.mjs +60 -0
  99. package/scripts/claude-hooks/_vault-retrieval.mjs +322 -0
  100. package/scripts/claude-hooks/agent-spawn-delegation-gate.mjs +133 -0
  101. package/scripts/claude-hooks/capture-execution-gate.mjs +51 -0
  102. package/scripts/claude-hooks/capture-workflow-gate.mjs +11 -0
  103. package/scripts/claude-hooks/check-auto-memory-budget.mjs +396 -0
  104. package/scripts/claude-hooks/check-claude-md-budget.mjs +327 -0
  105. package/scripts/claude-hooks/check-mcp-freshness-hook.mjs +14 -0
  106. package/scripts/claude-hooks/claim-before-code-gate.mjs +11 -0
  107. package/scripts/claude-hooks/claim-liveness-shared.mjs +577 -0
  108. package/scripts/claude-hooks/close-terminal-on-ship.mjs +64 -0
  109. package/scripts/claude-hooks/coo-denylist-gate.mjs +11 -0
  110. package/scripts/claude-hooks/coo-guard-check.mjs +11 -0
  111. package/scripts/claude-hooks/deep-research-cost-gate.mjs +11 -0
  112. package/scripts/claude-hooks/dev-server-task-reminder.mjs +15 -0
  113. package/scripts/claude-hooks/diagnose-capture-reminder.mjs +11 -0
  114. package/scripts/claude-hooks/directive-obligation-gate.mjs +11 -0
  115. package/scripts/claude-hooks/emit-claim-status.mjs +41 -0
  116. package/scripts/claude-hooks/enforce-session-sequence.mjs +11 -0
  117. package/scripts/claude-hooks/enforce-vault-naming.mjs +11 -0
  118. package/scripts/claude-hooks/env-vault-guard.mjs +11 -0
  119. package/scripts/claude-hooks/epic-milestone-phrasing-gate.mjs +11 -0
  120. package/scripts/claude-hooks/git-identity-guard.mjs +11 -0
  121. package/scripts/claude-hooks/git-reflog-audit.mjs +15 -0
  122. package/scripts/claude-hooks/git-stash-gate.mjs +11 -0
  123. package/scripts/claude-hooks/guard-auto-memory-writes.mjs +137 -0
  124. package/scripts/claude-hooks/id-display-format-gate.mjs +11 -0
  125. package/scripts/claude-hooks/inject-communication-style.mjs +86 -0
  126. package/scripts/claude-hooks/inject-coo-seat.mjs +78 -0
  127. package/scripts/claude-hooks/inject-dev-server-awareness.mjs +11 -0
  128. package/scripts/claude-hooks/inject-doctrine.mjs +13 -0
  129. package/scripts/claude-hooks/inject-vault-context.mjs +14 -0
  130. package/scripts/claude-hooks/intent-classifier-trigger.mjs +279 -0
  131. package/scripts/claude-hooks/log-session-activity.mjs +341 -0
  132. package/scripts/claude-hooks/naughty-list-gate.mjs +11 -0
  133. package/scripts/claude-hooks/notify-status-flip.mjs +72 -0
  134. package/scripts/claude-hooks/plan-exit-ingest-gate.mjs +170 -0
  135. package/scripts/claude-hooks/plan-ingest-close-reminder.mjs +66 -0
  136. package/scripts/claude-hooks/plan-review-gate.mjs +11 -0
  137. package/scripts/claude-hooks/preflight-reminder.mjs +262 -0
  138. package/scripts/claude-hooks/protected-action-intent.mjs +221 -0
  139. package/scripts/claude-hooks/research-method-guard.mjs +398 -0
  140. package/scripts/claude-hooks/research-protocol-gate.mjs +11 -0
  141. package/scripts/claude-hooks/session-end.mjs +451 -0
  142. package/scripts/claude-hooks/settings-write-gate.mjs +11 -0
  143. package/scripts/claude-hooks/settlement-check-gate.mjs +39 -0
  144. package/scripts/claude-hooks/status-flip-detect.mjs +17 -0
  145. package/scripts/claude-hooks/terminal-close-shared.mjs +426 -0
  146. package/scripts/claude-hooks/terminal-close-watcher.mjs +122 -0
  147. package/scripts/claude-hooks/vault-mirror-catchup.mjs +11 -0
  148. package/scripts/claude-hooks/vault-write-tier-guard.mjs +11 -0
  149. package/scripts/claude-hooks/wip-checkpoint.mjs +302 -0
  150. package/scripts/cursor-hooks/manifest.mjs +281 -0
  151. package/scripts/dev-server-status.mjs +34 -13
  152. package/scripts/dev-server-stop.mjs +313 -0
  153. package/scripts/heyspex-mode.mjs +288 -0
  154. package/scripts/hs-auto-resolve.mjs +240 -0
  155. package/scripts/hs-auto-source.mjs +398 -0
  156. package/scripts/hs-auto.mjs +134 -0
  157. package/scripts/hs-capture-cli.mjs +326 -0
  158. package/scripts/hs-classifier.mjs +136 -0
  159. package/scripts/hs-companion.mjs +88 -0
  160. package/scripts/hs-gateway.mjs +115 -0
  161. package/scripts/hs-mode.mjs +125 -0
  162. package/scripts/hs-next.mjs +441 -0
  163. package/scripts/hs-settings.mjs +338 -0
  164. package/scripts/hs-view.mjs +496 -0
  165. package/scripts/hs-worktree.mjs +201 -0
  166. package/scripts/install-claude-code-hooks.mjs +272 -0
  167. package/scripts/install-cursor-hooks.mjs +471 -0
  168. package/scripts/lib/agent-env-markers.mjs +38 -0
  169. package/scripts/lib/console-url-resolver.mjs +199 -61
  170. package/scripts/lib/customer-kit.mjs +1203 -0
  171. package/scripts/lib/dev-mode.mjs +249 -32
  172. package/scripts/lib/directive-obligations.mjs +349 -0
  173. package/scripts/lib/heyspex-home.mjs +72 -0
  174. package/scripts/lib/hook-dispositions.mjs +210 -0
  175. package/scripts/lib/hook-vault-header.mjs +30 -0
  176. package/scripts/lib/hs-command.mjs +277 -0
  177. package/scripts/lib/hs-companion-settings.mjs +472 -0
  178. package/scripts/lib/hs-source-branch.mjs +196 -0
  179. package/scripts/lib/hs-source-commit.mjs +59 -5
  180. package/scripts/lib/hs-source-identity.mjs +526 -0
  181. package/scripts/lib/hs-source-log.mjs +13 -22
  182. package/scripts/lib/hs-source-preflight.mjs +18 -4
  183. package/scripts/lib/hs-source-push.mjs +386 -307
  184. package/scripts/lib/hs-worktree-args.mjs +115 -0
  185. package/scripts/lib/shared-path-helpers.mjs +134 -0
  186. package/scripts/lib/standalone-doctor.mjs +540 -3
  187. package/scripts/lib/subagent-git-lock.mjs +109 -0
  188. package/scripts/lib/template-pin.mjs +34 -0
  189. package/scripts/lib/window-placement.mjs +109 -0
  190. package/scripts/provenance-lib.mjs +91 -0
  191. package/scripts/stamp-provenance-on-edit.mjs +222 -0
  192. package/scripts/wip-ledger-health.mjs +653 -0
  193. package/spexharness/doctrine/baseline/SPEXCODE-DOCTRINE.baseline.json +29 -0
  194. package/spexharness/src/adapters/audit.mjs +197 -0
  195. package/spexharness/src/adapters/claude-code.mjs +449 -0
  196. package/spexharness/src/adapters/copilot.mjs +236 -0
  197. package/spexharness/src/adapters/detect-harness.mjs +34 -0
  198. package/spexharness/src/chat/tui/ansi.mjs +448 -0
  199. package/spexharness/src/chat/tui/palette.mjs +22 -0
  200. package/spexharness/src/chat/tui/select.mjs +208 -0
  201. package/spexharness/src/config-root.mjs +54 -0
  202. package/spexharness/src/context-budget.mjs +141 -0
  203. package/spexharness/src/dev-server-control.mjs +389 -0
  204. package/spexharness/src/doctrine/behaviour.mjs +371 -0
  205. package/spexharness/src/doctrine/corpus.mjs +733 -0
  206. package/spexharness/src/doctrine/inject.mjs +338 -0
  207. package/spexharness/src/doctrine/merge.mjs +184 -0
  208. package/spexharness/src/doctrine/sources.mjs +252 -0
  209. package/spexharness/src/doctrine/synthesize.mjs +401 -0
  210. package/spexharness/src/doctrine/vault-source.mjs +574 -0
  211. package/spexharness/src/doctrine/writer.mjs +176 -0
  212. package/spexharness/src/events.mjs +84 -0
  213. package/spexharness/src/gates/_shell-write-targets.mjs +77 -0
  214. package/spexharness/src/gates/capture-workflow-gate.mjs +202 -0
  215. package/spexharness/src/gates/claim-before-code-gate.decide.mjs +33 -0
  216. package/spexharness/src/gates/claim-before-code-gate.mjs +129 -0
  217. package/spexharness/src/gates/deep-research-cost-gate.mjs +275 -0
  218. package/spexharness/src/gates/diagnose-capture-reminder.mjs +112 -0
  219. package/spexharness/src/gates/directive-obligation-gate.decide.mjs +132 -0
  220. package/spexharness/src/gates/directive-obligation-gate.mjs +183 -0
  221. package/spexharness/src/gates/enforce-session-sequence.mjs +895 -0
  222. package/spexharness/src/gates/enforce-vault-naming.mjs +215 -0
  223. package/spexharness/src/gates/epic-milestone-phrasing-gate.mjs +233 -0
  224. package/spexharness/src/gates/git-identity-guard.decide.mjs +436 -0
  225. package/spexharness/src/gates/git-identity-guard.mjs +61 -0
  226. package/spexharness/src/gates/git-reflog-audit.mjs +151 -0
  227. package/spexharness/src/gates/git-stash-gate.decide.mjs +361 -0
  228. package/spexharness/src/gates/git-stash-gate.mjs +159 -0
  229. package/spexharness/src/gates/id-display-format-gate.mjs +190 -0
  230. package/spexharness/src/gates/inject-doctrine-gate.mjs +89 -0
  231. package/spexharness/src/gates/inject-vault-context.mjs +239 -0
  232. package/spexharness/src/gates/naughty-list-gate.mjs +213 -0
  233. package/spexharness/src/gates/plan-review-gate.mjs +233 -0
  234. package/spexharness/src/gates/preflight-reminder-gate.mjs +265 -0
  235. package/spexharness/src/gates/research-protocol-gate.mjs +175 -0
  236. package/spexharness/src/gates/settings-write-gate.decide.mjs +96 -0
  237. package/spexharness/src/gates/settings-write-gate.mjs +104 -0
  238. package/spexharness/src/gates/vault-mirror-catchup.mjs +124 -0
  239. package/spexharness/src/gates/vault-write-tier-guard.decide.mjs +125 -0
  240. package/spexharness/src/gates/vault-write-tier-guard.mjs +42 -0
  241. package/spexharness/src/git-reflog-audit.mjs +294 -0
  242. package/spexharness/src/intent-classifier.mjs +196 -0
  243. package/spexharness/src/intent-directive.mjs +626 -0
  244. package/spexharness/src/profile/learn.mjs +551 -0
  245. package/spexharness/src/profile/proposals.mjs +357 -0
  246. package/spexharness/src/profile/vault-inclusion.mjs +386 -0
  247. package/spexharness/src/redact.mjs +151 -0
  248. package/spexharness/src/rule-table.mjs +849 -0
  249. package/spexharness/src/seat-context.mjs +122 -0
  250. package/spexharness/src/session-bootstrap.mjs +512 -0
  251. package/spexharness/src/session-record.mjs +815 -0
  252. package/spexharness/src/token-inventory.mjs +207 -0
  253. package/vendor/heyspex-mcp/account-switch.mjs +96 -0
  254. package/vendor/heyspex-mcp/alignment-gate.mjs +315 -1
  255. package/vendor/heyspex-mcp/blocker-resolver.mjs +37 -2
  256. package/vendor/heyspex-mcp/breakdown-ladder.mjs +119 -4
  257. package/vendor/heyspex-mcp/breakdown-source.mjs +271 -0
  258. package/vendor/heyspex-mcp/breakdown-writer.mjs +23 -3
  259. package/vendor/heyspex-mcp/capture-buffer-patches.mjs +77 -8
  260. package/vendor/heyspex-mcp/capture-channel.mjs +55 -5
  261. package/vendor/heyspex-mcp/capture-console-client.mjs +117 -3
  262. package/vendor/heyspex-mcp/capture-focus.mjs +1061 -31
  263. package/vendor/heyspex-mcp/capture-outbox.mjs +15 -5
  264. package/vendor/heyspex-mcp/capture-sources.mjs +195 -0
  265. package/vendor/heyspex-mcp/capture-tools.mjs +1264 -0
  266. package/vendor/heyspex-mcp/claim-tools.mjs +1147 -0
  267. package/vendor/heyspex-mcp/cli-verbs.mjs +2074 -0
  268. package/vendor/heyspex-mcp/cli.mjs +207 -15524
  269. package/vendor/heyspex-mcp/close-branch-report.mjs +102 -0
  270. package/vendor/heyspex-mcp/cloud-tool-surface.mjs +128 -0
  271. package/vendor/heyspex-mcp/cloud-vault-writes.mjs +602 -0
  272. package/vendor/heyspex-mcp/config-seed.yaml +15 -0
  273. package/vendor/heyspex-mcp/config-settings.mjs +290 -7
  274. package/vendor/heyspex-mcp/console-fetch.mjs +822 -17
  275. package/vendor/heyspex-mcp/console-transport.mjs +172 -0
  276. package/vendor/heyspex-mcp/credentials.mjs +585 -0
  277. package/vendor/heyspex-mcp/defer-spec.mjs +44 -4
  278. package/vendor/heyspex-mcp/deferred-reclaim.mjs +29 -3
  279. package/vendor/heyspex-mcp/design-handlers.mjs +31 -0
  280. package/vendor/heyspex-mcp/design-tools.mjs +4 -1
  281. package/vendor/heyspex-mcp/dev-factory-bridge.mjs +4 -4
  282. package/vendor/heyspex-mcp/dev-mode-core.mjs +45 -0
  283. package/vendor/heyspex-mcp/dev-tools.mjs +131 -0
  284. package/vendor/heyspex-mcp/diagnose-handlers.mjs +54 -0
  285. package/vendor/heyspex-mcp/events-tools.mjs +207 -0
  286. package/vendor/heyspex-mcp/filing-tools.mjs +723 -0
  287. package/vendor/heyspex-mcp/fleet-handlers.mjs +37 -0
  288. package/vendor/heyspex-mcp/fleet-queue-tools.mjs +71 -15
  289. package/vendor/heyspex-mcp/focus-tools.mjs +190 -0
  290. package/vendor/heyspex-mcp/folder-trust-store.mjs +60 -0
  291. package/vendor/heyspex-mcp/http-transport.mjs +302 -0
  292. package/vendor/heyspex-mcp/list-tools.mjs +257 -0
  293. package/vendor/heyspex-mcp/login-handoff.mjs +15 -1
  294. package/vendor/heyspex-mcp/mcp-config.mjs +107 -0
  295. package/vendor/heyspex-mcp/memory-tools.mjs +523 -0
  296. package/vendor/heyspex-mcp/mvp-mode.mjs +53 -6
  297. package/vendor/heyspex-mcp/obligation-backstop.mjs +103 -0
  298. package/vendor/heyspex-mcp/occupied-keys.mjs +142 -0
  299. package/vendor/heyspex-mcp/on-deck-brief.mjs +3377 -0
  300. package/vendor/heyspex-mcp/on-deck-scheduler.mjs +1708 -0
  301. package/vendor/heyspex-mcp/package-root.mjs +32 -0
  302. package/vendor/heyspex-mcp/peer-presence.mjs +8 -1
  303. package/vendor/heyspex-mcp/plan-ground.mjs +621 -652
  304. package/vendor/heyspex-mcp/plan-push.mjs +908 -22
  305. package/vendor/heyspex-mcp/plan-review.mjs +124 -30
  306. package/vendor/heyspex-mcp/preflight-gate.mjs +0 -0
  307. package/vendor/heyspex-mcp/procedure-handlers.mjs +327 -0
  308. package/vendor/heyspex-mcp/procedure-tools.mjs +1181 -970
  309. package/vendor/heyspex-mcp/promote-capture.mjs +388 -69
  310. package/vendor/heyspex-mcp/promote-diagnose.mjs +74 -0
  311. package/vendor/heyspex-mcp/promote-research-to-diagnose.mjs +9 -2
  312. package/vendor/heyspex-mcp/promote-research.mjs +666 -53
  313. package/vendor/heyspex-mcp/promotion-helpers.mjs +251 -0
  314. package/vendor/heyspex-mcp/prompts.mjs +1460 -0
  315. package/vendor/heyspex-mcp/read-path.mjs +191 -15
  316. package/vendor/heyspex-mcp/receipt-shape.mjs +146 -0
  317. package/vendor/heyspex-mcp/recipe-handlers.mjs +117 -0
  318. package/vendor/heyspex-mcp/regen-tasks.mjs +210 -3
  319. package/vendor/heyspex-mcp/register-spec.mjs +266 -54
  320. package/vendor/heyspex-mcp/request-context.mjs +83 -0
  321. package/vendor/heyspex-mcp/research-focus.mjs +207 -4
  322. package/vendor/heyspex-mcp/research-handlers.mjs +625 -0
  323. package/vendor/heyspex-mcp/research-tools.mjs +4 -4
  324. package/vendor/heyspex-mcp/response-budget.mjs +348 -0
  325. package/vendor/heyspex-mcp/review-focus.mjs +25 -1
  326. package/vendor/heyspex-mcp/roadmap-default.mjs +70 -0
  327. package/vendor/heyspex-mcp/search-specs.mjs +280 -0
  328. package/vendor/heyspex-mcp/seat-block-ledger.mjs +113 -0
  329. package/vendor/heyspex-mcp/seat-identity.mjs +2 -6
  330. package/vendor/heyspex-mcp/session-owner.mjs +109 -0
  331. package/vendor/heyspex-mcp/session-tools.mjs +162 -0
  332. package/vendor/heyspex-mcp/settings-registry.mjs +232 -0
  333. package/vendor/heyspex-mcp/settings-tools.mjs +85 -12
  334. package/vendor/heyspex-mcp/spec-edit-tools.mjs +453 -0
  335. package/vendor/heyspex-mcp/spec-id-lib.mjs +93 -17
  336. package/vendor/heyspex-mcp/split-research.mjs +304 -56
  337. package/vendor/heyspex-mcp/stdio-rpc.mjs +22 -0
  338. package/vendor/heyspex-mcp/submit-for-review.mjs +150 -7
  339. package/vendor/heyspex-mcp/summary-contract.mjs +105 -0
  340. package/vendor/heyspex-mcp/summary-write-tools.mjs +228 -0
  341. package/vendor/heyspex-mcp/symptom-query.mjs +146 -0
  342. package/vendor/heyspex-mcp/test-helpers.mjs +123 -1
  343. package/vendor/heyspex-mcp/tool-catalog.mjs +2819 -0
  344. package/vendor/heyspex-mcp/tool-dispatch.mjs +657 -0
  345. package/vendor/heyspex-mcp/tool-helpers.mjs +325 -0
  346. package/vendor/heyspex-mcp/validate-linkage.mjs +414 -27
  347. package/vendor/heyspex-mcp/vault-io.mjs +720 -0
  348. package/vendor/heyspex-mcp/vault-less-endpoints.mjs +52 -0
  349. package/vendor/heyspex-mcp/vault-resolve.mjs +554 -68
  350. package/vendor/heyspex-mcp/verify-reproduction.mjs +270 -30
  351. package/vendor/heyspex-mcp/whoami.mjs +92 -0
  352. package/vendor/heyspex-mcp/write-outbox.mjs +512 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * symptom-query.mjs — turn a SYMPTOM SENTENCE into the small set of bounded
3
+ * queries `GET /api/search` can actually answer. Pure: no imports, no I/O, no
4
+ * console, so both the MCP tool and the console's own route suite can drive it.
5
+ *
6
+ * WHY THIS IS NOT "just pass the sentence through"
7
+ * ------------------------------------------------
8
+ * The console's ranked path is `websearch_to_tsquery('english', $q)`, and
9
+ * unquoted words in a websearch query are AND-ed. A real bug report —
10
+ *
11
+ * "row-level security policies exist but are not enforced at runtime;
12
+ * the database connection bypasses tenant isolation"
13
+ *
14
+ * — is ~12 content words AND-ed together, which matches NOTHING in any vault,
15
+ * then falls through to the trigram near-miss on `name`, which also matches
16
+ * nothing. The endpoint answers honestly ("searched, zero hits") and the agent
17
+ * concludes the symptom was never filed, files a duplicate, and the two
18
+ * existing specs stay invisible. That is [[HS-YFLS]] AC2.
19
+ *
20
+ * So a symptom search is a handful of ANGLES, not one query:
21
+ *
22
+ * phrase — the sentence verbatim (AND). Rarely hits; when it does, it is
23
+ * the highest-precision answer there is, so it is asked first.
24
+ * bigrams — the adjacent salient pairs, quoted, OR-ed. "tenant isolation"
25
+ * and "row-level security" are CONCEPTS; a quoted phrase makes
26
+ * `ts_rank_cd` reward the document that contains the concept over
27
+ * one that merely mentions both words a page apart.
28
+ * terms — every salient term, OR-ed. The recall floor. A document that
29
+ * matches eight of the twelve terms outranks one that matches two
30
+ * without any extra scoring on our side, because `ts_rank_cd`
31
+ * already counts matched lexemes and their density.
32
+ *
33
+ * Nothing here is a reranker and nothing is semantic — the substrate is
34
+ * lexical by decision ([[retrieval-substrate-lexical-not-embeddings-gate-b-no]]).
35
+ */
36
+
37
+ /**
38
+ * Words that carry no retrieval signal in a bug report. Deliberately larger
39
+ * than a generic English stoplist: the vocabulary of a SYMPTOM ("happens",
40
+ * "should", "instead", "error", "issue") is noise when every spec in the vault
41
+ * is about something going wrong.
42
+ */
43
+ const STOPWORDS = new Set([
44
+ 'a', 'an', 'the', 'and', 'or', 'but', 'not', 'nor', 'for', 'to', 'in', 'on', 'at', 'of',
45
+ 'with', 'without', 'from', 'by', 'as', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
46
+ 'do', 'does', 'did', 'has', 'have', 'had', 'can', 'cannot', 'could', 'will', 'would',
47
+ 'should', 'shall', 'may', 'might', 'must', 'this', 'that', 'these', 'those', 'it', 'its',
48
+ 'we', 'our', 'you', 'your', 'they', 'them', 'their', 'there', 'here', 'when', 'where',
49
+ 'what', 'which', 'who', 'whom', 'how', 'why', 'all', 'any', 'some', 'only', 'also',
50
+ 'still', 'then', 'than', 'so', 'if', 'else', 'into', 'onto', 'out', 'up', 'down', 'over',
51
+ 'under', 'again', 'more', 'most', 'much', 'very', 'just', 'now', 'get', 'gets', 'got',
52
+ // symptom filler — true of every bug, so it discriminates between none of them
53
+ 'bug', 'issue', 'problem', 'error', 'fail', 'fails', 'failed', 'failing', 'broken',
54
+ 'wrong', 'happens', 'happening', 'instead', 'expected', 'actual', 'repro', 'steps',
55
+ 'seems', 'looks', 'like', 'never', 'always', 'sometimes', 'exist', 'exists',
56
+ ]);
57
+
58
+ /** Minimum length for a token to count as salient (drops `is`, `an`, `ok`, `x`). */
59
+ const MIN_TERM_LENGTH = 3;
60
+
61
+ /** Hard ceiling on salient terms — a 400-word paste must not become a 400-term OR. */
62
+ export const DEFAULT_MAX_TERMS = 12;
63
+
64
+ /** Hard ceiling on quoted bigram phrases. */
65
+ export const DEFAULT_MAX_BIGRAMS = 6;
66
+
67
+ /**
68
+ * Split a symptom sentence into ordered, de-duplicated content terms.
69
+ * Hyphens and underscores are KEPT inside a word (`row-level`, `vault_id`,
70
+ * `HS-WRUQ`) because those are the highest-signal tokens a spec vault has;
71
+ * everything else becomes a separator.
72
+ */
73
+ export function extractSymptomTerms(text, { maxTerms = DEFAULT_MAX_TERMS } = {}) {
74
+ if (typeof text !== 'string' || !text.trim()) return [];
75
+ const raw = text
76
+ .toLowerCase()
77
+ .replace(/[^a-z0-9_-]+/g, ' ')
78
+ .split(' ')
79
+ .map((t) => t.replace(/^[-_]+|[-_]+$/g, ''))
80
+ .filter(Boolean);
81
+
82
+ const ordered = [];
83
+ const seen = new Set();
84
+ for (const token of raw) {
85
+ if (token.length < MIN_TERM_LENGTH) continue;
86
+ if (STOPWORDS.has(token)) continue;
87
+ if (/^\d+$/.test(token)) continue;
88
+ if (seen.has(token)) continue;
89
+ seen.add(token);
90
+ ordered.push(token);
91
+ }
92
+ if (ordered.length <= maxTerms) return ordered;
93
+
94
+ // Over the cap: keep the most SALIENT terms, then restore reading order so
95
+ // the bigram angle below still pairs words that were adjacent in the report.
96
+ // Saliency is length plus a bonus for a compound (`row-level`, `vault_id`) —
97
+ // a crude rarity proxy, but one that needs no corpus statistics and cannot
98
+ // go stale.
99
+ const salience = (t) => t.length + (/[-_]/.test(t) ? 4 : 0);
100
+ const keep = new Set(
101
+ [...ordered]
102
+ .sort((a, b) => salience(b) - salience(a) || ordered.indexOf(a) - ordered.indexOf(b))
103
+ .slice(0, maxTerms),
104
+ );
105
+ return ordered.filter((t) => keep.has(t));
106
+ }
107
+
108
+ /** `["tenant","isolation","neon"]` → `['"tenant isolation"', '"isolation neon"']`. */
109
+ export function buildBigrams(terms, { maxBigrams = DEFAULT_MAX_BIGRAMS } = {}) {
110
+ const pairs = [];
111
+ for (let i = 0; i + 1 < terms.length && pairs.length < maxBigrams; i += 1) {
112
+ pairs.push(`${terms[i]} ${terms[i + 1]}`);
113
+ }
114
+ return pairs;
115
+ }
116
+
117
+ /**
118
+ * The angles to ask `GET /api/search`, most precise first.
119
+ *
120
+ * Returns `{ terms, queries: [{ label, q }] }`. Queries are de-duplicated by
121
+ * `q`, so a one-word symptom collapses to a single request rather than three
122
+ * identical ones. An input with no salient terms at all (punctuation, pure
123
+ * stopwords) yields `queries: []` — the caller must treat that as "nothing
124
+ * searchable was asked", never as "nothing is filed".
125
+ */
126
+ export function buildSymptomQueries(text, { maxTerms = DEFAULT_MAX_TERMS, maxBigrams = DEFAULT_MAX_BIGRAMS } = {}) {
127
+ const phrase = typeof text === 'string' ? text.trim().replace(/\s+/g, ' ') : '';
128
+ const terms = extractSymptomTerms(phrase, { maxTerms });
129
+ const queries = [];
130
+ const pushed = new Set();
131
+ const push = (label, q) => {
132
+ if (!q || pushed.has(q)) return;
133
+ pushed.add(q);
134
+ queries.push({ label, q });
135
+ };
136
+
137
+ if (terms.length > 0) {
138
+ // Precision first: the sentence as written, AND-ed by websearch_to_tsquery.
139
+ if (phrase) push('phrase', phrase);
140
+ const bigrams = buildBigrams(terms, { maxBigrams });
141
+ if (bigrams.length > 0) push('bigrams', bigrams.map((b) => `"${b}"`).join(' or '));
142
+ push('terms', terms.join(' or '));
143
+ }
144
+
145
+ return { phrase, terms, queries };
146
+ }
@@ -2,9 +2,120 @@
2
2
  * Shared test helpers for the vendor MCP round-trip suites.
3
3
  */
4
4
 
5
- import { cpSync, existsSync, mkdirSync } from 'node:fs';
5
+ import { randomUUID } from 'node:crypto';
6
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
7
+ import { tmpdir } from 'node:os';
6
8
  import { join } from 'node:path';
7
9
 
10
+ import { resetActiveConfigCache } from './vault-resolve.mjs';
11
+
12
+ /**
13
+ * A hermetic `{ account, vault }` scope for tests that drive the REAL console
14
+ * transport ([[HS-MVG4-WW9R-TASK-mcp-and-hs-name-account-vault-on-every]]).
15
+ *
16
+ * Since invariant 2 the transport refuses LOCALLY (no fetch) when the cwd
17
+ * resolves to an unregistered root or the machine has no configured account.
18
+ * A test that hits a stand-in console through `consoleFetch` with the default
19
+ * header resolvers therefore depends on the machine it runs on — registered
20
+ * here, unregistered on CI — unless it pins both facts. This helper pins them:
21
+ *
22
+ * - a temp HOME (`HOME` + `USERPROFILE`, what `os.homedir()` reads) holding
23
+ * `~/.heyspex/registry.json` with the roots the test names,
24
+ * - `HS_ACCOUNT_ID` (tier 1 of session-owner.mjs) as the configured account,
25
+ * - optionally `HEYSPEX_VAULT_ROOT` pointed at a registered root,
26
+ * - `CLAUDE_PROJECT_DIR` (the resolver's cwd base) pointed at that root —
27
+ * or at the temp home when none is given — so the resolver's walk starts
28
+ * inside the fixture and never climbs through the ambient checkout. The
29
+ * walk (tier 2) outranks `HEYSPEX_VAULT_ROOT` (tier 3, [[HS-VVNQ]]), so a
30
+ * satellite pin in the repo the suite is run FROM (heyspex-app's own
31
+ * `.mcp.json` since 2026-10-10) would otherwise silently replace the
32
+ * root a test pinned, and the machine's registry pointer (tier 4) would
33
+ * otherwise answer for a test that pinned nothing.
34
+ *
35
+ * `registerRoot(root)` adds a row for a root a test mints later (its own temp
36
+ * vault) and resets the memoized resolver so the next request sees it. Call
37
+ * `restore()` in `after`/`afterEach`. Nothing here touches the real profile.
38
+ *
39
+ * Row ids are UUIDs (what the console mints): the wire gate treats a non-UUID
40
+ * registry id as a legacy slug and looks for the repo's heyspex.yaml
41
+ * `vault_id` instead — a slug row with no marker is refused, by design.
42
+ *
43
+ * @param {{ accountId?: string, vaultId?: string, repoRootAbs?: string, activeVaultId?: string | null }} [opts]
44
+ * `repoRootAbs`: register this root as `vaultId` and set `HEYSPEX_VAULT_ROOT` to it.
45
+ * `activeVaultId`: the registry's active pointer (defaults to `vaultId` when a root is registered).
46
+ */
47
+ export function installScopedConsoleEnv({
48
+ accountId = 'acct_test',
49
+ vaultId = randomUUID(),
50
+ repoRootAbs,
51
+ activeVaultId,
52
+ } = {}) {
53
+ const ENV_KEYS = ['HOME', 'USERPROFILE', 'HS_ACCOUNT_ID', 'HEYSPEX_VAULT_ROOT', 'CLAUDE_PROJECT_DIR', 'HEYSPEX_MCP_TOKEN'];
54
+ const saved = Object.fromEntries(ENV_KEYS.map((k) => [k, process.env[k]]));
55
+ const home = mkdtempSync(join(tmpdir(), 'hs-scoped-home-'));
56
+ // The registry lives under the HeySpex home: HEYSPEX_HOME when a test set one, else the scoped HOME.
57
+ const registryHome = process.env.HEYSPEX_HOME?.trim() || home;
58
+ const registryDir = join(registryHome, '.heyspex');
59
+ mkdirSync(registryDir, { recursive: true });
60
+ const registryPath = join(registryDir, 'registry.json');
61
+ // Registry schema v2 (HS-RXLG): the pointer is the signed-in account's row.
62
+ const registry = {
63
+ schema_version: 2,
64
+ current_account_id: accountId,
65
+ accounts: {
66
+ [accountId]: {
67
+ active_vault_id: activeVaultId ?? (repoRootAbs ? vaultId : null),
68
+ active_workspace_id: null,
69
+ },
70
+ },
71
+ workspaces: [],
72
+ vaults: [],
73
+ };
74
+ const flush = () => {
75
+ writeFileSync(registryPath, JSON.stringify(registry, null, 2));
76
+ resetActiveConfigCache();
77
+ };
78
+
79
+ const registerRoot = (root, id) => {
80
+ const rowId = id ?? randomUUID();
81
+ registry.vaults = registry.vaults.filter((v) => v.id !== rowId && v.repo_root_abs !== root);
82
+ registry.vaults.push({ id: rowId, repo_root_abs: root, account_id: accountId });
83
+ flush();
84
+ return rowId;
85
+ };
86
+
87
+ process.env.HOME = home;
88
+ process.env.USERPROFILE = home;
89
+ process.env.HS_ACCOUNT_ID = accountId;
90
+ // The scoped registry row is bound to this account (machine-local binding), so the
91
+ // machine must hold a sign-in for it; an env bearer stands in for the credentials file.
92
+ process.env.HEYSPEX_MCP_TOKEN ||= 'hsmcp_scoped_test_token';
93
+ // Fence the resolver's walk inside the fixture (see the doc comment above).
94
+ process.env.CLAUDE_PROJECT_DIR = repoRootAbs ?? home;
95
+ if (repoRootAbs) {
96
+ registerRoot(repoRootAbs, vaultId);
97
+ process.env.HEYSPEX_VAULT_ROOT = repoRootAbs;
98
+ } else {
99
+ flush();
100
+ }
101
+
102
+ return {
103
+ home,
104
+ accountId,
105
+ vaultId,
106
+ registryPath,
107
+ registerRoot,
108
+ restore() {
109
+ for (const k of ENV_KEYS) {
110
+ if (saved[k] === undefined) delete process.env[k];
111
+ else process.env[k] = saved[k];
112
+ }
113
+ resetActiveConfigCache();
114
+ rmSync(home, { recursive: true, force: true });
115
+ },
116
+ };
117
+ }
118
+
8
119
  /**
9
120
  * Mirror into a temp vault every real-repo file that
10
121
  * `scripts/validate-vault-ids.mjs` needs to run in isolation.
@@ -19,6 +130,13 @@ import { join } from 'node:path';
19
130
  * id-suffix-shape rule, compiled from protocol frontmatter), so that file must be
20
131
  * mirrored too or the engine import dangles.
21
132
  *
133
+ * Post repo-split, `scripts/lib/resolve-validate-root.mjs` (copied wholesale as
134
+ * part of `scripts/`) also imports `vendor/heyspex-mcp/vault-resolve.mjs` by a
135
+ * relative path OUTSIDE `scripts/` — that file must be mirrored too, or the
136
+ * copied validator dangles with MODULE_NOT_FOUND the moment it computes its
137
+ * own default root. `vault-resolve.mjs` itself has no further local-file
138
+ * imports (node builtins only), so this is a single extra copy, not a chain.
139
+ *
22
140
  * Single source of truth: the next dependency the validator grows is a one-line
23
141
  * add here, not a silent breakage in every round-trip test.
24
142
  *
@@ -28,6 +146,10 @@ import { join } from 'node:path';
28
146
  export function mirrorValidatorDeps(repoRoot, root) {
29
147
  cpSync(join(repoRoot, 'scripts'), join(root, 'scripts'), { recursive: true });
30
148
 
149
+ const vaultResolveRel = join('vendor', 'heyspex-mcp', 'vault-resolve.mjs');
150
+ mkdirSync(join(root, 'vendor', 'heyspex-mcp'), { recursive: true });
151
+ cpSync(join(repoRoot, vaultResolveRel), join(root, vaultResolveRel));
152
+
31
153
  const indexerRel = join('spex-console', 'src', 'lib', 'indexer');
32
154
  mkdirSync(join(root, indexerRel), { recursive: true });
33
155
  for (const file of [