heyspex 0.1.0 → 0.2.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 (322) hide show
  1. package/README.md +21 -0
  2. package/bin/hs.mjs +931 -98
  3. package/bin/spexcode.mjs +262 -0
  4. package/dev-factory/engine/worktree.mjs +740 -0
  5. package/dev-factory/lib/code-repo-root.mjs +67 -0
  6. package/dev-factory/lib/context-budget.mjs +84 -0
  7. package/dev-factory/lib/epic-detect.mjs +190 -0
  8. package/dev-factory/lib/fleet-queue-file.mjs +846 -0
  9. package/dev-factory/lib/fleet-queue.mjs +426 -0
  10. package/dev-factory/lib/fleet-state.mjs +14 -18
  11. package/dev-factory/lib/model-catalog.mjs +338 -0
  12. package/dev-factory/lib/seat-context.mjs +199 -0
  13. package/dev-factory/lib/spec-io.mjs +93 -0
  14. package/dev-factory/lib/sufficiency-score.mjs +8 -2
  15. package/dev-factory/lib/worktree-allocator.mjs +744 -0
  16. package/dev-factory/model-catalog.json +222 -0
  17. package/dist/cli/hs-check.mjs +1085 -103
  18. package/dist/cli/hs-claim.mjs +936 -63
  19. package/dist/cli/hs-connect.mjs +9786 -1910
  20. package/dist/cli/hs-defer.mjs +5267 -3053
  21. package/dist/cli/hs-dev.mjs +564 -0
  22. package/dist/cli/hs-env.mjs +385 -299
  23. package/dist/cli/hs-index-rebuild.mjs +7129 -0
  24. package/dist/cli/hs-index-reconcile.mjs +7852 -0
  25. package/dist/cli/hs-init.mjs +777 -138
  26. package/dist/cli/hs-install.mjs +6583 -485
  27. package/dist/cli/hs-join.mjs +10137 -2368
  28. package/dist/cli/hs-vault-pull.mjs +4659 -5882
  29. package/dist/cli/hs-vault.mjs +3793 -1537
  30. package/dist/cli/hs-workspace.mjs +2550 -524
  31. package/dist/cli-templates/customer-vault/specs/entity-model.md +594 -601
  32. package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +110 -177
  33. package/dist/cli-templates/customer-vault/specs/protocols/destructive-action-checklist.md +122 -0
  34. package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +13 -15
  35. package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +91 -0
  36. package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +150 -168
  37. package/dist/cli-templates/customer-vault/specs/protocols/spec-summary-authoring.md +83 -0
  38. package/dist/cli-templates/harness-commands/claude/hs-auto.md +36 -0
  39. package/dist/cli-templates/harness-commands/claude/hs-backfill.md +28 -0
  40. package/dist/cli-templates/harness-commands/claude/hs-capture.md +62 -0
  41. package/dist/cli-templates/harness-commands/claude/hs-defer.md +29 -0
  42. package/dist/cli-templates/harness-commands/claude/hs-dev.md +20 -0
  43. package/dist/cli-templates/harness-commands/claude/hs-doctor.md +32 -0
  44. package/dist/cli-templates/harness-commands/claude/hs-ground.md +28 -0
  45. package/dist/cli-templates/harness-commands/claude/hs-handoff.md +33 -0
  46. package/dist/cli-templates/harness-commands/claude/hs-log.md +27 -0
  47. package/dist/cli-templates/harness-commands/claude/hs-next.md +29 -0
  48. package/dist/cli-templates/harness-commands/claude/hs-promote.md +70 -0
  49. package/dist/cli-templates/harness-commands/claude/hs-push.md +35 -0
  50. package/dist/cli-templates/harness-commands/claude/hs-qc.md +27 -0
  51. package/dist/cli-templates/harness-commands/claude/hs-res.md +63 -0
  52. package/dist/cli-templates/harness-commands/claude/hs-resolve.md +23 -0
  53. package/dist/cli-templates/harness-commands/claude/hs-review.md +23 -0
  54. package/dist/cli-templates/harness-commands/claude/hs-view.md +26 -0
  55. package/dist/cli-templates/harness-commands/claude/kill-ports.md +32 -0
  56. package/dist/cli-templates/harness-commands/claude/prototype.md +91 -0
  57. package/dist/cli-templates/harness-commands/cursor/hs-auto.md +40 -0
  58. package/dist/cli-templates/harness-commands/cursor/hs-backfill.md +31 -0
  59. package/dist/cli-templates/harness-commands/cursor/hs-capture.md +65 -0
  60. package/dist/cli-templates/harness-commands/cursor/hs-defer.md +32 -0
  61. package/dist/cli-templates/harness-commands/cursor/hs-dev.md +24 -0
  62. package/dist/cli-templates/harness-commands/cursor/hs-doctor.md +36 -0
  63. package/dist/cli-templates/harness-commands/cursor/hs-ground.md +31 -0
  64. package/dist/cli-templates/harness-commands/cursor/hs-handoff.md +37 -0
  65. package/dist/cli-templates/harness-commands/cursor/hs-log.md +31 -0
  66. package/dist/cli-templates/harness-commands/cursor/hs-next.md +32 -0
  67. package/dist/cli-templates/harness-commands/cursor/hs-promote.md +73 -0
  68. package/dist/cli-templates/harness-commands/cursor/hs-push.md +38 -0
  69. package/dist/cli-templates/harness-commands/cursor/hs-qc.md +30 -0
  70. package/dist/cli-templates/harness-commands/cursor/hs-res.md +67 -0
  71. package/dist/cli-templates/harness-commands/cursor/hs-resolve.md +26 -0
  72. package/dist/cli-templates/harness-commands/cursor/hs-review.md +26 -0
  73. package/dist/cli-templates/harness-commands/cursor/hs-view.md +30 -0
  74. package/dist/cli-templates/harness-commands/cursor/kill-ports.md +35 -0
  75. package/dist/cli-templates/harness-commands/cursor/prototype.md +95 -0
  76. package/docs/mcp-client-config.md +259 -6
  77. package/package.json +231 -124
  78. package/plugins/heyspex/.claude-plugin/plugin.json +12 -0
  79. package/plugins/heyspex/.cursor-plugin/plugin.json +15 -0
  80. package/plugins/heyspex/.mcp.json +12 -0
  81. package/plugins/heyspex/bin/launch-mcp.mjs +95 -0
  82. package/plugins/heyspex/bin/run-hook.mjs +62 -0
  83. package/plugins/heyspex/hooks/cursor-hooks.json +227 -0
  84. package/plugins/heyspex/hooks/hooks.json +361 -0
  85. package/plugins/heyspex/mcp.json +13 -0
  86. package/scripts/check-mcp-freshness.mjs +17 -9
  87. package/scripts/claude-hooks/_env-vault-events.mjs +68 -0
  88. package/scripts/claude-hooks/_guardrail-events.mjs +96 -0
  89. package/scripts/claude-hooks/_guardrail-loader.mjs +494 -0
  90. package/scripts/claude-hooks/_intent-classifier-router.mjs +410 -0
  91. package/scripts/claude-hooks/_intent-classifier-semantic.mjs +351 -0
  92. package/scripts/claude-hooks/_run.mjs +120 -0
  93. package/scripts/claude-hooks/_transcript-text.mjs +60 -0
  94. package/scripts/claude-hooks/_vault-retrieval.mjs +322 -0
  95. package/scripts/claude-hooks/agent-spawn-delegation-gate.mjs +133 -0
  96. package/scripts/claude-hooks/capture-workflow-gate.mjs +11 -0
  97. package/scripts/claude-hooks/check-auto-memory-budget.mjs +396 -0
  98. package/scripts/claude-hooks/check-claude-md-budget.mjs +327 -0
  99. package/scripts/claude-hooks/check-mcp-freshness-hook.mjs +14 -0
  100. package/scripts/claude-hooks/claim-before-code-gate.mjs +11 -0
  101. package/scripts/claude-hooks/claim-liveness-shared.mjs +575 -0
  102. package/scripts/claude-hooks/close-terminal-on-ship.mjs +64 -0
  103. package/scripts/claude-hooks/coo-denylist-gate.mjs +11 -0
  104. package/scripts/claude-hooks/coo-guard-check.mjs +11 -0
  105. package/scripts/claude-hooks/deep-research-cost-gate.mjs +11 -0
  106. package/scripts/claude-hooks/dev-server-task-reminder.mjs +15 -0
  107. package/scripts/claude-hooks/emit-claim-status.mjs +41 -0
  108. package/scripts/claude-hooks/enforce-session-sequence.mjs +11 -0
  109. package/scripts/claude-hooks/enforce-vault-naming.mjs +11 -0
  110. package/scripts/claude-hooks/env-vault-guard.mjs +11 -0
  111. package/scripts/claude-hooks/epic-milestone-phrasing-gate.mjs +11 -0
  112. package/scripts/claude-hooks/git-identity-guard.mjs +11 -0
  113. package/scripts/claude-hooks/git-reflog-audit.mjs +15 -0
  114. package/scripts/claude-hooks/git-stash-gate.mjs +11 -0
  115. package/scripts/claude-hooks/guard-auto-memory-writes.mjs +137 -0
  116. package/scripts/claude-hooks/id-display-format-gate.mjs +11 -0
  117. package/scripts/claude-hooks/inject-communication-style.mjs +66 -0
  118. package/scripts/claude-hooks/inject-coo-seat.mjs +78 -0
  119. package/scripts/claude-hooks/inject-dev-server-awareness.mjs +11 -0
  120. package/scripts/claude-hooks/inject-doctrine.mjs +13 -0
  121. package/scripts/claude-hooks/inject-vault-context.mjs +14 -0
  122. package/scripts/claude-hooks/intent-classifier-trigger.mjs +247 -0
  123. package/scripts/claude-hooks/log-session-activity.mjs +341 -0
  124. package/scripts/claude-hooks/naughty-list-gate.mjs +11 -0
  125. package/scripts/claude-hooks/notify-status-flip.mjs +72 -0
  126. package/scripts/claude-hooks/plan-exit-ingest-gate.mjs +170 -0
  127. package/scripts/claude-hooks/plan-ingest-close-reminder.mjs +66 -0
  128. package/scripts/claude-hooks/plan-review-gate.mjs +11 -0
  129. package/scripts/claude-hooks/preflight-reminder.mjs +262 -0
  130. package/scripts/claude-hooks/protected-action-intent.mjs +221 -0
  131. package/scripts/claude-hooks/research-method-guard.mjs +398 -0
  132. package/scripts/claude-hooks/research-protocol-gate.mjs +11 -0
  133. package/scripts/claude-hooks/session-end.mjs +449 -0
  134. package/scripts/claude-hooks/settings-write-gate.mjs +11 -0
  135. package/scripts/claude-hooks/settlement-check-gate.mjs +39 -0
  136. package/scripts/claude-hooks/status-flip-detect.mjs +17 -0
  137. package/scripts/claude-hooks/terminal-close-shared.mjs +426 -0
  138. package/scripts/claude-hooks/terminal-close-watcher.mjs +122 -0
  139. package/scripts/claude-hooks/wip-checkpoint.mjs +298 -0
  140. package/scripts/cursor-hooks/manifest.mjs +235 -0
  141. package/scripts/dev-server-status.mjs +34 -13
  142. package/scripts/dev-server-stop.mjs +313 -0
  143. package/scripts/heyspex-mode.mjs +268 -0
  144. package/scripts/hs-auto-resolve.mjs +240 -0
  145. package/scripts/hs-auto-source.mjs +398 -0
  146. package/scripts/hs-auto.mjs +134 -0
  147. package/scripts/hs-capture-cli.mjs +326 -0
  148. package/scripts/hs-classifier.mjs +136 -0
  149. package/scripts/hs-companion.mjs +88 -0
  150. package/scripts/hs-gateway.mjs +115 -0
  151. package/scripts/hs-mode.mjs +125 -0
  152. package/scripts/hs-next.mjs +441 -0
  153. package/scripts/hs-settings.mjs +338 -0
  154. package/scripts/hs-view.mjs +333 -0
  155. package/scripts/hs-worktree.mjs +201 -0
  156. package/scripts/install-claude-code-hooks.mjs +270 -0
  157. package/scripts/install-cursor-hooks.mjs +471 -0
  158. package/scripts/lib/agent-env-markers.mjs +38 -0
  159. package/scripts/lib/console-url-resolver.mjs +197 -60
  160. package/scripts/lib/customer-kit.mjs +886 -0
  161. package/scripts/lib/dev-mode.mjs +244 -28
  162. package/scripts/lib/heyspex-home.mjs +72 -0
  163. package/scripts/lib/hs-command.mjs +277 -0
  164. package/scripts/lib/hs-companion-settings.mjs +472 -0
  165. package/scripts/lib/hs-source-commit.mjs +59 -5
  166. package/scripts/lib/hs-source-identity.mjs +526 -0
  167. package/scripts/lib/hs-source-log.mjs +11 -21
  168. package/scripts/lib/hs-source-push.mjs +107 -58
  169. package/scripts/lib/hs-worktree-args.mjs +115 -0
  170. package/scripts/lib/shared-path-helpers.mjs +134 -0
  171. package/scripts/lib/standalone-doctor.mjs +540 -3
  172. package/scripts/lib/subagent-git-lock.mjs +109 -0
  173. package/scripts/lib/template-pin.mjs +34 -0
  174. package/scripts/provenance-lib.mjs +91 -0
  175. package/scripts/stamp-provenance-on-edit.mjs +222 -0
  176. package/scripts/wip-ledger-health.mjs +653 -0
  177. package/spexharness/doctrine/baseline/SPEXCODE-DOCTRINE.baseline.json +29 -0
  178. package/spexharness/src/adapters/audit.mjs +197 -0
  179. package/spexharness/src/adapters/claude-code.mjs +441 -0
  180. package/spexharness/src/chat/tui/ansi.mjs +448 -0
  181. package/spexharness/src/chat/tui/palette.mjs +22 -0
  182. package/spexharness/src/chat/tui/select.mjs +208 -0
  183. package/spexharness/src/config-root.mjs +54 -0
  184. package/spexharness/src/context-budget.mjs +141 -0
  185. package/spexharness/src/dev-server-control.mjs +389 -0
  186. package/spexharness/src/doctrine/behaviour.mjs +371 -0
  187. package/spexharness/src/doctrine/corpus.mjs +733 -0
  188. package/spexharness/src/doctrine/inject.mjs +338 -0
  189. package/spexharness/src/doctrine/merge.mjs +184 -0
  190. package/spexharness/src/doctrine/sources.mjs +252 -0
  191. package/spexharness/src/doctrine/synthesize.mjs +401 -0
  192. package/spexharness/src/doctrine/vault-source.mjs +574 -0
  193. package/spexharness/src/doctrine/writer.mjs +176 -0
  194. package/spexharness/src/events.mjs +84 -0
  195. package/spexharness/src/gates/capture-workflow-gate.mjs +202 -0
  196. package/spexharness/src/gates/claim-before-code-gate.decide.mjs +33 -0
  197. package/spexharness/src/gates/claim-before-code-gate.mjs +129 -0
  198. package/spexharness/src/gates/deep-research-cost-gate.mjs +274 -0
  199. package/spexharness/src/gates/enforce-session-sequence.mjs +895 -0
  200. package/spexharness/src/gates/enforce-vault-naming.mjs +215 -0
  201. package/spexharness/src/gates/epic-milestone-phrasing-gate.mjs +233 -0
  202. package/spexharness/src/gates/git-identity-guard.decide.mjs +436 -0
  203. package/spexharness/src/gates/git-identity-guard.mjs +61 -0
  204. package/spexharness/src/gates/git-reflog-audit.mjs +151 -0
  205. package/spexharness/src/gates/git-stash-gate.decide.mjs +361 -0
  206. package/spexharness/src/gates/git-stash-gate.mjs +159 -0
  207. package/spexharness/src/gates/id-display-format-gate.mjs +190 -0
  208. package/spexharness/src/gates/inject-doctrine-gate.mjs +89 -0
  209. package/spexharness/src/gates/inject-vault-context.mjs +239 -0
  210. package/spexharness/src/gates/naughty-list-gate.mjs +213 -0
  211. package/spexharness/src/gates/plan-review-gate.mjs +233 -0
  212. package/spexharness/src/gates/preflight-reminder-gate.mjs +265 -0
  213. package/spexharness/src/gates/research-protocol-gate.mjs +175 -0
  214. package/spexharness/src/gates/settings-write-gate.decide.mjs +96 -0
  215. package/spexharness/src/gates/settings-write-gate.mjs +104 -0
  216. package/spexharness/src/git-reflog-audit.mjs +294 -0
  217. package/spexharness/src/intent-classifier.mjs +194 -0
  218. package/spexharness/src/intent-directive.mjs +541 -0
  219. package/spexharness/src/profile/learn.mjs +551 -0
  220. package/spexharness/src/profile/proposals.mjs +357 -0
  221. package/spexharness/src/profile/vault-inclusion.mjs +386 -0
  222. package/spexharness/src/redact.mjs +151 -0
  223. package/spexharness/src/rule-table.mjs +819 -0
  224. package/spexharness/src/seat-context.mjs +122 -0
  225. package/spexharness/src/session-bootstrap.mjs +512 -0
  226. package/spexharness/src/session-record.mjs +815 -0
  227. package/spexharness/src/token-inventory.mjs +207 -0
  228. package/vendor/heyspex-mcp/account-switch.mjs +95 -0
  229. package/vendor/heyspex-mcp/alignment-gate.mjs +315 -1
  230. package/vendor/heyspex-mcp/blocker-resolver.mjs +37 -2
  231. package/vendor/heyspex-mcp/breakdown-ladder.mjs +119 -4
  232. package/vendor/heyspex-mcp/breakdown-source.mjs +271 -0
  233. package/vendor/heyspex-mcp/breakdown-writer.mjs +23 -3
  234. package/vendor/heyspex-mcp/capture-buffer-patches.mjs +46 -5
  235. package/vendor/heyspex-mcp/capture-channel.mjs +55 -5
  236. package/vendor/heyspex-mcp/capture-console-client.mjs +80 -1
  237. package/vendor/heyspex-mcp/capture-focus.mjs +1035 -29
  238. package/vendor/heyspex-mcp/capture-outbox.mjs +5 -1
  239. package/vendor/heyspex-mcp/capture-tools.mjs +1219 -0
  240. package/vendor/heyspex-mcp/claim-tools.mjs +1124 -0
  241. package/vendor/heyspex-mcp/cli-verbs.mjs +2076 -0
  242. package/vendor/heyspex-mcp/cli.mjs +201 -15524
  243. package/vendor/heyspex-mcp/cloud-tool-surface.mjs +128 -0
  244. package/vendor/heyspex-mcp/cloud-vault-writes.mjs +412 -0
  245. package/vendor/heyspex-mcp/config-seed.yaml +15 -0
  246. package/vendor/heyspex-mcp/config-settings.mjs +290 -7
  247. package/vendor/heyspex-mcp/console-fetch.mjs +657 -16
  248. package/vendor/heyspex-mcp/console-transport.mjs +166 -0
  249. package/vendor/heyspex-mcp/credentials.mjs +584 -0
  250. package/vendor/heyspex-mcp/defer-spec.mjs +44 -4
  251. package/vendor/heyspex-mcp/deferred-reclaim.mjs +29 -3
  252. package/vendor/heyspex-mcp/design-handlers.mjs +31 -0
  253. package/vendor/heyspex-mcp/design-tools.mjs +4 -1
  254. package/vendor/heyspex-mcp/dev-factory-bridge.mjs +4 -4
  255. package/vendor/heyspex-mcp/dev-mode-core.mjs +45 -0
  256. package/vendor/heyspex-mcp/dev-tools.mjs +124 -0
  257. package/vendor/heyspex-mcp/diagnose-handlers.mjs +54 -0
  258. package/vendor/heyspex-mcp/events-tools.mjs +207 -0
  259. package/vendor/heyspex-mcp/filing-tools.mjs +688 -0
  260. package/vendor/heyspex-mcp/fleet-handlers.mjs +37 -0
  261. package/vendor/heyspex-mcp/fleet-queue-tools.mjs +69 -14
  262. package/vendor/heyspex-mcp/focus-tools.mjs +190 -0
  263. package/vendor/heyspex-mcp/folder-trust-store.mjs +59 -0
  264. package/vendor/heyspex-mcp/http-transport.mjs +300 -0
  265. package/vendor/heyspex-mcp/list-tools.mjs +257 -0
  266. package/vendor/heyspex-mcp/login-handoff.mjs +15 -1
  267. package/vendor/heyspex-mcp/mcp-config.mjs +94 -0
  268. package/vendor/heyspex-mcp/memory-tools.mjs +523 -0
  269. package/vendor/heyspex-mcp/mvp-mode.mjs +53 -6
  270. package/vendor/heyspex-mcp/occupied-keys.mjs +141 -0
  271. package/vendor/heyspex-mcp/on-deck-brief.mjs +3360 -0
  272. package/vendor/heyspex-mcp/on-deck-scheduler.mjs +1708 -0
  273. package/vendor/heyspex-mcp/package-root.mjs +32 -0
  274. package/vendor/heyspex-mcp/peer-presence.mjs +8 -1
  275. package/vendor/heyspex-mcp/plan-ground.mjs +621 -652
  276. package/vendor/heyspex-mcp/plan-push.mjs +906 -21
  277. package/vendor/heyspex-mcp/plan-review.mjs +124 -30
  278. package/vendor/heyspex-mcp/preflight-gate.mjs +0 -0
  279. package/vendor/heyspex-mcp/procedure-handlers.mjs +325 -0
  280. package/vendor/heyspex-mcp/procedure-tools.mjs +540 -351
  281. package/vendor/heyspex-mcp/promote-capture.mjs +386 -69
  282. package/vendor/heyspex-mcp/promote-diagnose.mjs +74 -0
  283. package/vendor/heyspex-mcp/promote-research-to-diagnose.mjs +9 -2
  284. package/vendor/heyspex-mcp/promote-research.mjs +660 -53
  285. package/vendor/heyspex-mcp/promotion-helpers.mjs +251 -0
  286. package/vendor/heyspex-mcp/prompts.mjs +1460 -0
  287. package/vendor/heyspex-mcp/read-path.mjs +29 -9
  288. package/vendor/heyspex-mcp/receipt-shape.mjs +146 -0
  289. package/vendor/heyspex-mcp/recipe-handlers.mjs +117 -0
  290. package/vendor/heyspex-mcp/regen-tasks.mjs +210 -3
  291. package/vendor/heyspex-mcp/register-spec.mjs +266 -54
  292. package/vendor/heyspex-mcp/request-context.mjs +59 -0
  293. package/vendor/heyspex-mcp/research-focus.mjs +207 -4
  294. package/vendor/heyspex-mcp/research-handlers.mjs +623 -0
  295. package/vendor/heyspex-mcp/research-tools.mjs +4 -4
  296. package/vendor/heyspex-mcp/response-budget.mjs +348 -0
  297. package/vendor/heyspex-mcp/review-focus.mjs +25 -1
  298. package/vendor/heyspex-mcp/search-specs.mjs +280 -0
  299. package/vendor/heyspex-mcp/seat-block-ledger.mjs +113 -0
  300. package/vendor/heyspex-mcp/seat-identity.mjs +2 -6
  301. package/vendor/heyspex-mcp/session-owner.mjs +108 -0
  302. package/vendor/heyspex-mcp/session-tools.mjs +152 -0
  303. package/vendor/heyspex-mcp/settings-registry.mjs +232 -0
  304. package/vendor/heyspex-mcp/settings-tools.mjs +85 -12
  305. package/vendor/heyspex-mcp/spec-edit-tools.mjs +446 -0
  306. package/vendor/heyspex-mcp/spec-id-lib.mjs +93 -17
  307. package/vendor/heyspex-mcp/split-research.mjs +301 -56
  308. package/vendor/heyspex-mcp/stdio-rpc.mjs +22 -0
  309. package/vendor/heyspex-mcp/submit-for-review.mjs +132 -6
  310. package/vendor/heyspex-mcp/summary-contract.mjs +105 -0
  311. package/vendor/heyspex-mcp/summary-write-tools.mjs +224 -0
  312. package/vendor/heyspex-mcp/symptom-query.mjs +146 -0
  313. package/vendor/heyspex-mcp/test-helpers.mjs +108 -1
  314. package/vendor/heyspex-mcp/tool-catalog.mjs +2813 -0
  315. package/vendor/heyspex-mcp/tool-dispatch.mjs +639 -0
  316. package/vendor/heyspex-mcp/tool-helpers.mjs +325 -0
  317. package/vendor/heyspex-mcp/validate-linkage.mjs +414 -27
  318. package/vendor/heyspex-mcp/vault-io.mjs +724 -0
  319. package/vendor/heyspex-mcp/vault-less-endpoints.mjs +52 -0
  320. package/vendor/heyspex-mcp/vault-resolve.mjs +366 -68
  321. package/vendor/heyspex-mcp/verify-reproduction.mjs +270 -30
  322. package/vendor/heyspex-mcp/whoami.mjs +91 -0
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * hs-command.mjs — the ONE resolver for "how do you actually run a HeySpex
4
+ * command on THIS machine"
5
+ * ([[HS-I6HT-EKYU-DIAG-every-message-tells-the-user-to-run-hs]]).
6
+ *
7
+ * THE DEFECT THIS EXISTS TO KILL. Every place that told a human what to run
8
+ * hard-coded `hs login`. On the owner's own machine that command does not
9
+ * exist — `which hs` finds nothing in Git Bash and `Get-Command hs` returns
10
+ * nothing in PowerShell, because the package declares the `hs` bin but
11
+ * nothing has ever linked it globally. The product printed advice that could
12
+ * not be carried out, which is the same shape as the console-unreachable
13
+ * message that sent agents off to start a local dev server.
14
+ *
15
+ * THE FIX IS THE MESSAGE, NOT THE PATH (decided 2026-08-23, see the diagnose).
16
+ * Linking `hs` globally would point one command name at whatever branch
17
+ * happens to be checked out, and would do nothing at all for a customer who
18
+ * never links it — so it fixes one machine and leaves the product defect
19
+ * standing. Instead: every message asks THIS module for the runnable form and
20
+ * prints that.
21
+ *
22
+ * `hs` resolves on PATH → `hs login`
23
+ * it does not → `node "C:\path\to\checkout\bin\hs.mjs" login`
24
+ *
25
+ * NEVER PRINT AN `npx` FORM. THIS IS MEASURED, NOT ASSUMED — do not
26
+ * re-derive it. The tempting fallback is `npx hs login`, and inside a
27
+ * checkout it even works, which is exactly what makes it a trap. It fails
28
+ * for the reader because **`npx` resolves from the reader's CURRENT WORKING
29
+ * DIRECTORY, not from wherever the message was printed.** A human reads an
30
+ * error in one window and pastes the command into whatever terminal is open,
31
+ * which is usually not the checkout — the owner did precisely that today,
32
+ * typing `hs login` at a shell sitting in his home folder. Measured
33
+ * 2026-08-23 from a directory outside the repo:
34
+ *
35
+ * npx --no -- hs --version
36
+ * → npm error npx canceled due to missing packages: ["hs@2.0.1"]
37
+ * npx --no -- heyspex --version
38
+ * → npm error 404 Not Found - GET https://registry.npmjs.org/heyspex
39
+ *
40
+ * So `npx hs` offers to install an unrelated public package (and WITHOUT
41
+ * `--no` it simply installs it), and `npx heyspex` cannot work either because
42
+ * this package is not published publicly. That is the same trap
43
+ * [[never-print-npx-hs-it-installs-a]] recorded on 2026-08-12 — note that
44
+ * lesson predates a rename and still calls the package `workflow-pm`; the
45
+ * name is now `heyspex`, and neither name is a safe npx target.
46
+ *
47
+ * THE ABSOLUTE-PATH RULE. When `hs` is not on PATH we print an absolute-path
48
+ * invocation of THIS install's dispatcher: `node <abs>/bin/hs.mjs <args>`.
49
+ * The path is resolved from THIS MODULE'S OWN LOCATION (`import.meta.url`),
50
+ * never from `process.cwd()`, so the printed command runs from any folder,
51
+ * touches no registry, and cannot resolve to somebody else's package. The
52
+ * reader provably has this install, because this install is what printed the
53
+ * message. It is also the form the lesson itself blesses: a repo-local
54
+ * dispatcher is valid precisely when the checkout exists — which is the case
55
+ * here and was NOT the case in the fresh-machine join scenario that lesson
56
+ * was written about. Do NOT reuse this helper to build text handed to a
57
+ * machine that has no HeySpex yet; that path is a public join URL, not a
58
+ * command line.
59
+ *
60
+ * SYNCHRONOUS, CACHED, NEVER THROWS. The lookup is a plain scan of `PATH`
61
+ * with `fs.existsSync` — no `child_process`, so it costs microseconds and is
62
+ * safe to call while building an error string. The answer is cached after
63
+ * the first call (PATH does not change inside a process). Every failure mode
64
+ * degrades to the absolute-path dispatcher form rather than throwing,
65
+ * because the caller is usually already in the middle of reporting a
66
+ * different failure.
67
+ *
68
+ * SHELL-INDEPENDENT. Node sees the Windows-form `PATH` (`C:\…;C:\…`) whether
69
+ * it was launched from Git Bash, PowerShell, or cmd — the MSYS layer
70
+ * converts it back on the way into a native binary — so one `path.delimiter`
71
+ * split gives the same answer in all three. On Windows the scan accepts the
72
+ * extensionless shim (what Git Bash runs), every `PATHEXT` variant (what cmd
73
+ * runs), and `.ps1` (what PowerShell runs); `npm link` writes all of them
74
+ * together, so any one of them proves the command is live. The dispatcher
75
+ * path is always double-quoted on Windows — see `shellQuote` for the
76
+ * measurement, and note that a BARE backslash path is broken in Git Bash
77
+ * specifically, which is the shell coding agents use.
78
+ *
79
+ * Plain Node ESM, zero deps beyond `node:fs`/`node:path`/`node:url`, and —
80
+ * deliberately — ZERO imports of other repo files. `console-url-resolver.mjs`
81
+ * grew a static import of `dev-mode.mjs` on 2026-08-23 and broke a clean
82
+ * install of the published package (module-not-found on load) until the file
83
+ * was added to the package list. If this module ever gains a repo import,
84
+ * run `node scripts/verify-mcp-package.mjs` before calling the work done.
85
+ */
86
+ import { existsSync } from 'node:fs';
87
+ import { delimiter, dirname, join } from 'node:path';
88
+ import { fileURLToPath } from 'node:url';
89
+
90
+ /** The command name the package declares (`bin.hs` in package.json). */
91
+ export const HS_BIN_NAME = 'hs';
92
+
93
+ /**
94
+ * Absolute path to THIS install's CLI dispatcher, resolved from this
95
+ * module's own location — `<root>/scripts/lib/hs-command.mjs` → up three →
96
+ * `<root>`, then `bin/hs.mjs`. That layout holds in a checkout AND in the
97
+ * published package (both `bin/hs.mjs` and `scripts/lib/hs-command.mjs` are
98
+ * in the package's `files` list). Never derived from `process.cwd()`.
99
+ */
100
+ export const HS_DISPATCHER_PATH = (() => {
101
+ try {
102
+ const here = dirname(fileURLToPath(import.meta.url)); // <root>/scripts/lib
103
+ return join(dirname(dirname(here)), 'bin', 'hs.mjs');
104
+ } catch {
105
+ return null;
106
+ }
107
+ })();
108
+
109
+ /**
110
+ * Quote the dispatcher path for pasting into a shell.
111
+ *
112
+ * MEASURED 2026-08-23 from the home folder, running the printed string
113
+ * verbatim in each shell:
114
+ *
115
+ * node C:\…\bin\hs.mjs Git Bash ✗ PowerShell ✓ cmd ✓
116
+ * node "C:\…\bin\hs.mjs" Git Bash ✓ PowerShell ✓ cmd ✓
117
+ *
118
+ * Git Bash eats the backslashes as escapes when the path is bare, and Git
119
+ * Bash is the shell coding agents run commands in — so an unquoted Windows
120
+ * path would re-create the exact defect this module exists to kill, for the
121
+ * agent audience. Any path carrying a backslash or whitespace is therefore
122
+ * always double-quoted; a clean POSIX path is left bare.
123
+ */
124
+ function shellQuote(p) {
125
+ return /[\\\s]/.test(p) ? `"${p}"` : p;
126
+ }
127
+
128
+ /**
129
+ * What a message prints in front of a subcommand when `hs` is NOT on PATH:
130
+ * `node <abs>/bin/hs.mjs`. Falls back to the bare name only if this module
131
+ * cannot locate itself at all (should be impossible; never throw).
132
+ */
133
+ export const HS_DISPATCHER_PREFIX = HS_DISPATCHER_PATH
134
+ ? `node ${shellQuote(HS_DISPATCHER_PATH)}`
135
+ : HS_BIN_NAME;
136
+
137
+ /**
138
+ * Windows-only extensions to try on top of the bare name. `PATHEXT` covers
139
+ * cmd/PowerShell's own list; we add the extensionless shim (Git Bash runs
140
+ * it) and `.ps1` (PowerShell runs it, and it is absent from the default
141
+ * `PATHEXT`).
142
+ */
143
+ function candidateNames(name, env) {
144
+ if (process.platform !== 'win32') return [name];
145
+ // Lower-cased on purpose: npm writes `hs.cmd` / `hs.ps1` in lower case, and
146
+ // the Windows filesystem is case-insensitive, so one spelling is enough.
147
+ const pathext = (env.PATHEXT || '.COM;.EXE;.BAT;.CMD')
148
+ .split(';')
149
+ .map((e) => e.trim().toLowerCase())
150
+ .filter(Boolean);
151
+ const extensions = [...new Set([...pathext, '.ps1'])];
152
+ return [name, ...extensions.map((ext) => name + ext)];
153
+ }
154
+
155
+ /**
156
+ * Is `name` an executable somewhere on `PATH`? Pure `fs.existsSync` — no
157
+ * subprocess. Returns the absolute path of the first hit, or `null`.
158
+ *
159
+ * Injectable `env` and `exists` so tests can describe a machine instead of
160
+ * depending on the one they run on.
161
+ */
162
+ export function findOnPath(name, { env = process.env, exists = existsSync } = {}) {
163
+ try {
164
+ const raw = env.PATH ?? env.Path ?? env.path ?? '';
165
+ for (const dir of String(raw).split(delimiter)) {
166
+ const trimmed = dir.trim().replace(/^"(.*)"$/, '$1');
167
+ if (!trimmed) continue;
168
+ for (const candidate of candidateNames(name, env)) {
169
+ const full = join(trimmed, candidate);
170
+ try {
171
+ if (exists(full)) return full;
172
+ } catch {
173
+ // An unreadable or denied PATH entry is not a match — keep scanning.
174
+ }
175
+ }
176
+ }
177
+ } catch {
178
+ // A malformed PATH is treated as "not found", never as a crash.
179
+ }
180
+ return null;
181
+ }
182
+
183
+ let cached = null;
184
+
185
+ /**
186
+ * Test/CI escape hatch: force the "is `hs` on PATH" answer WITHOUT touching
187
+ * PATH itself, so a fixture recorded on one machine's PATH state stays
188
+ * reproducible on another's. THE DEFECT THIS EXISTS TO KILL: a golden
189
+ * recorded when `hs` was not linked started failing the moment `npm link`
190
+ * put it on this developer's PATH — the resolver was correct, the fixture
191
+ * was silently machine-dependent. Recognized values (read via
192
+ * `describeHsCommand`'s `env`, or `process.env` when none is injected):
193
+ *
194
+ * "1" → force on-PATH (prefix = `hs`, as a linked install would show)
195
+ * "0" → force NOT on PATH (prefix = the absolute dispatcher form)
196
+ * anything else (including unset) → the real PATH scan decides, unchanged
197
+ *
198
+ * Never set by product code — only test/CI fixtures reach for this, and
199
+ * only to PIN a canonical form, never to fake a real machine's state for a
200
+ * human-facing message.
201
+ */
202
+ export const HS_ON_PATH_OVERRIDE_ENV = 'HEYSPEX_HS_ON_PATH';
203
+
204
+ function onPathOverride(env) {
205
+ const raw = String(env?.[HS_ON_PATH_OVERRIDE_ENV] ?? '');
206
+ if (raw === '1') return true;
207
+ if (raw === '0') return false;
208
+ return undefined;
209
+ }
210
+
211
+ /**
212
+ * Describe how HeySpex commands run on this machine.
213
+ *
214
+ * @returns {{ onPath: boolean, prefix: string, resolvedPath: string|null,
215
+ * dispatcherPath: string|null }}
216
+ * `prefix` is what a message should put in front of a subcommand — `"hs"`
217
+ * when the bin is on PATH, else `node <abs>/bin/hs.mjs`.
218
+ */
219
+ export function describeHsCommand({ env, exists, useCache = true } = {}) {
220
+ const injected = env !== undefined || exists !== undefined;
221
+ const effectiveEnv = env ?? process.env;
222
+
223
+ const override = onPathOverride(effectiveEnv);
224
+ if (override !== undefined) {
225
+ // The override wins outright — it is never merged with a real PATH scan,
226
+ // and it is never cached (it's a cheap string compare, and caching it
227
+ // would let one test's override leak into the next call).
228
+ return {
229
+ onPath: override,
230
+ prefix: override ? HS_BIN_NAME : HS_DISPATCHER_PREFIX,
231
+ resolvedPath: null,
232
+ dispatcherPath: HS_DISPATCHER_PATH,
233
+ };
234
+ }
235
+
236
+ if (useCache && !injected && cached) return cached;
237
+
238
+ const resolvedPath = findOnPath(HS_BIN_NAME, {
239
+ env: env ?? process.env,
240
+ exists: exists ?? existsSync,
241
+ });
242
+ const answer = {
243
+ onPath: resolvedPath !== null,
244
+ prefix: resolvedPath !== null ? HS_BIN_NAME : HS_DISPATCHER_PREFIX,
245
+ resolvedPath,
246
+ dispatcherPath: HS_DISPATCHER_PATH,
247
+ };
248
+ if (useCache && !injected) cached = answer;
249
+ return answer;
250
+ }
251
+
252
+ /**
253
+ * The runnable form of a HeySpex command, ready to paste into a message.
254
+ *
255
+ * hsCommand('login') → 'hs login'
256
+ * or 'node "C:\dev-projects\workflow-protocol\bin\hs.mjs" login'
257
+ * hsCommand() → 'hs' or 'node "…\bin\hs.mjs"'
258
+ *
259
+ * Never throws: an unexpected failure yields the absolute-path dispatcher
260
+ * form, which runs from any working directory on a machine that has this
261
+ * install.
262
+ */
263
+ export function hsCommand(args = '', options = {}) {
264
+ let prefix = HS_DISPATCHER_PREFIX;
265
+ try {
266
+ prefix = describeHsCommand(options).prefix;
267
+ } catch {
268
+ // Fall through to the dispatcher form — a message must never fail to render.
269
+ }
270
+ const tail = String(args ?? '').trim();
271
+ return tail ? `${prefix} ${tail}` : prefix;
272
+ }
273
+
274
+ /** Test seam: forget the cached PATH lookup. */
275
+ export function resetHsCommandCache() {
276
+ cached = null;
277
+ }