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,236 @@
1
+ // spexharness/src/adapters/copilot.mjs
2
+ //
3
+ // GitHub Copilot CLI front for the shared hook gates ([[HS-20SW-DRSM-DIAG-heyspex-capture-on-idea-and-workflow]];
4
+ // contract: GitHub Docs "Hooks configuration" + "CLI plugin reference", fetched 2026-10-16;
5
+ // [[HS-0GBS-CTF8-RES-copilot-plugin-parity-with-the-spexcode]]). Pure functions, no I/O.
6
+ //
7
+ // What Copilot does that Claude Code does not:
8
+ // INPUT two shapes. camelCase config events `{ sessionId, timestamp, cwd, toolName, toolArgs }` and the
9
+ // PascalCase shape `.claude/settings.json` rows receive `{ hook_event_name, session_id, timestamp,
10
+ // cwd, tool_name, tool_input }` (tool names already mapped to Claude's: bash/powershell -> Bash,
11
+ // create -> Write, edit/apply_patch -> Edit, view -> Read, task -> Agent). No `transcript_path`.
12
+ // OUTPUT ONE top-level JSON object on stdout: `{ permissionDecision: allow|deny|ask, permissionDecisionReason }`.
13
+ // It does NOT read `hookSpecificOutput`. Unparseable stdout is ignored.
14
+ // EXIT 0 -> stdout parsed. 2 -> always deny (stderr reason lost). ANY other non-zero -> deny ("hook
15
+ // errored"). Timeout -> fail open. So a Copilot hook prints its deny as JSON and exits 0, never 2.
16
+ //
17
+ // This module maps both directions; ./detect-harness.mjs decides WHEN it applies.
18
+
19
+ // HeySpex MCP tool names arrive in several spellings depending on the Copilot host (the payload spelling is not
20
+ // documented; [[HS-0GBS-CTF8-RES-copilot-plugin-parity-with-the-spexcode]] residual gap). Every spelling below maps
21
+ // to the Claude-side `mcp__heyspex__<tool>` the gates and `.claude/settings.json` matchers already use:
22
+ // mcp__heyspex__heyspex_x mcp__plugin_heyspex_heyspex__heyspex_x heyspex/heyspex_x heyspex.heyspex_x heyspex_x
23
+ const HEYSPEX_MCP_NAME = /^(?:mcp__plugin_heyspex_heyspex__|mcp__heyspex__|heyspex[/.:])?(heyspex_[A-Za-z0-9_]+)$/;
24
+
25
+ /**
26
+ * @param {unknown} name
27
+ * @returns {{ name: string, suffix: string } | null} null when `name` is not a HeySpex MCP tool in a known spelling
28
+ */
29
+ export function normalizeMcpToolName(name) {
30
+ if (typeof name !== 'string') return null;
31
+ const m = HEYSPEX_MCP_NAME.exec(name.trim());
32
+ return m ? { name: `mcp__heyspex__${m[1]}`, suffix: m[1] } : null;
33
+ }
34
+
35
+ const COPILOT_TOOL_TO_CLAUDE = {
36
+ bash: 'Bash',
37
+ powershell: 'PowerShell',
38
+ create: 'Write',
39
+ edit: 'Edit',
40
+ apply_patch: 'Edit',
41
+ view: 'Read',
42
+ task: 'Agent',
43
+ };
44
+
45
+ function parseArgs(value) {
46
+ if (value && typeof value === 'object') return value;
47
+ if (typeof value !== 'string' || !value.trim()) return {};
48
+ try {
49
+ const parsed = JSON.parse(value);
50
+ return parsed && typeof parsed === 'object' ? parsed : {};
51
+ } catch {
52
+ return {};
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Either Copilot payload shape -> the Claude-shaped payload every hook already reads. Never throws; a payload
58
+ * that is already Claude-shaped passes through with its `hook_event_name`, and unknown fields stay untouched.
59
+ * @param {unknown} payload
60
+ * @returns {Record<string, unknown>}
61
+ */
62
+ export function normalizeCopilotPayload(payload) {
63
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return {};
64
+ const p = /** @type {Record<string, any>} */ (payload);
65
+ const out = { ...p };
66
+ if (out.session_id === undefined && typeof p.sessionId === 'string') out.session_id = p.sessionId;
67
+ if (out.tool_name === undefined && typeof p.toolName === 'string') {
68
+ out.tool_name = COPILOT_TOOL_TO_CLAUDE[p.toolName] ?? p.toolName;
69
+ }
70
+ if (out.tool_input === undefined && p.toolArgs !== undefined) {
71
+ const args = { ...parseArgs(p.toolArgs) };
72
+ if (args.file_path === undefined && typeof args.path === 'string') args.file_path = args.path;
73
+ out.tool_input = args;
74
+ }
75
+ if (typeof out.tool_name === 'string') {
76
+ const mcp = normalizeMcpToolName(out.tool_name);
77
+ if (mcp) {
78
+ if (mcp.name !== out.tool_name && out.tool_name_original === undefined) out.tool_name_original = out.tool_name;
79
+ out.tool_name = mcp.name;
80
+ out.tool_name_suffix = mcp.suffix;
81
+ }
82
+ }
83
+ if (out.tool_response === undefined && p.toolResult !== undefined) out.tool_response = p.toolResult;
84
+ if (typeof out.hook_event_name !== 'string') {
85
+ if (out.tool_response !== undefined) out.hook_event_name = 'PostToolUse';
86
+ else if (out.tool_name !== undefined) out.hook_event_name = 'PreToolUse';
87
+ else if (typeof p.prompt === 'string') out.hook_event_name = 'UserPromptSubmit';
88
+ }
89
+ return out;
90
+ }
91
+
92
+ const body = (decision, reason) => JSON.stringify({ permissionDecision: decision, permissionDecisionReason: reason });
93
+
94
+ /**
95
+ * A gate decision (decide.mjs shape) -> what a Copilot hook process emits. A deny is ALWAYS exit 0 with the
96
+ * JSON on stdout (exit 2 would lose the reason). `allow`, `inject` and warn-only rewrites print nothing on
97
+ * stdout (Copilot has no additionalContext channel for tool hooks).
98
+ * @param {{ id?: string, event?: unknown }} _gate
99
+ * @param {{ point?: string }} engineEvent
100
+ * @param {{ decision?: string, reason?: string, rewrite?: { ask?: boolean, warn?: boolean } }} decision
101
+ * @returns {{ exitCode: 0, stdout: string, stderr: string }}
102
+ */
103
+ export function toCopilotResponse(_gate, engineEvent, decision) {
104
+ const kind = decision?.decision ?? 'allow';
105
+ const reason = String(decision?.reason ?? 'Denied by a HeySpex hook.');
106
+ if (kind === 'deny') {
107
+ const o = { permissionDecision: 'deny', permissionDecisionReason: reason };
108
+ // a Stop-time deny is a re-drive: carry the Claude stop shape too so either reader acts on it
109
+ if (engineEvent?.point === 'stop') Object.assign(o, { decision: 'block', reason });
110
+ return { exitCode: 0, stdout: JSON.stringify(o), stderr: '' };
111
+ }
112
+ if (kind === 'rewrite' && decision.rewrite?.ask) return { exitCode: 0, stdout: body('ask', reason), stderr: '' };
113
+ if (kind === 'rewrite' && decision.rewrite?.warn) {
114
+ return { exitCode: 0, stdout: '', stderr: reason.endsWith('\n') ? reason : `${reason}\n` };
115
+ }
116
+ return { exitCode: 0, stdout: '', stderr: '' };
117
+ }
118
+
119
+ /**
120
+ * Rewrite a Claude-dialect stdout blob (`{"hookSpecificOutput":{"permissionDecision":...}}`) into Copilot's
121
+ * top-level object. Anything else (already top-level, Stop `{decision:"block"}`, additionalContext, plain
122
+ * text) is returned unchanged. Used by the shared runner for hand-written hooks that print Claude JSON.
123
+ * @param {string} text
124
+ * @returns {string}
125
+ */
126
+ export function rewriteStdoutForCopilot(text) {
127
+ try {
128
+ const o = JSON.parse(text);
129
+ const h = o?.hookSpecificOutput;
130
+ if (h && typeof h.permissionDecision === 'string') {
131
+ return body(h.permissionDecision, h.permissionDecisionReason ?? 'Denied by a HeySpex hook.');
132
+ }
133
+ } catch {
134
+ /* not JSON: pass through */
135
+ }
136
+ return text;
137
+ }
138
+
139
+ /**
140
+ * A hand-written hook that decided "deny" the legacy way (exit 2, reason on stderr) -> the Copilot JSON deny.
141
+ * @param {string} stderrText
142
+ * @returns {string}
143
+ */
144
+ export function denyFromLegacyExit(stderrText) {
145
+ const reason = String(stderrText ?? '').replace(/\r/g, '').trim() || 'Denied by a HeySpex hook.';
146
+ return body('deny', reason);
147
+ }
148
+
149
+ /**
150
+ * VS Code's Local harness ignores hook matchers, so the runner re-applies them. True when ANY matcher admits the
151
+ * tool (an empty / `*` / `.*` matcher admits everything; an invalid regex fails open to "admit"). Matchers are
152
+ * Claude Code's: a regex that must match the WHOLE tool name.
153
+ * @param {string[]} matchers
154
+ * @param {string[]} toolNames every spelling of the tool (normalized first, original after)
155
+ * @returns {boolean}
156
+ */
157
+ export function toolMatchesAnyMatcher(matchers, toolNames) {
158
+ if (!Array.isArray(matchers) || matchers.length === 0) return true;
159
+ const names = toolNames.filter((n) => typeof n === 'string' && n);
160
+ for (const m of matchers) {
161
+ if (typeof m !== 'string' || m === '' || m === '*' || m === '**') return true;
162
+ try {
163
+ const re = new RegExp(`^(?:${m})$`);
164
+ if (names.some((n) => re.test(n))) return true;
165
+ } catch {
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+
172
+ /** All spellings a gate matcher might name for this (normalized) payload's tool. */
173
+ export function toolNameCandidates(payload) {
174
+ const names = [];
175
+ const add = (n) => { if (typeof n === 'string' && n && !names.includes(n)) names.push(n); };
176
+ add(payload?.tool_name);
177
+ add(payload?.tool_name_original);
178
+ if (typeof payload?.tool_name_suffix === 'string') add(`mcp__plugin_heyspex_heyspex__${payload.tool_name_suffix}`);
179
+ return names;
180
+ }
181
+
182
+ const CONTEXT_EVENTS = new Set(['SessionStart', 'PostToolUse', 'SubagentStart']);
183
+
184
+ /**
185
+ * The ONE place the runner decides what a Copilot hook process may print. Guarantees: the result is '' or a
186
+ * single valid JSON object. Non-JSON output is dropped (Copilot ignores unparseable stdout anyway). Claude's
187
+ * `hookSpecificOutput` permission form becomes the top-level form. Copilot drops command-hook output on
188
+ * `UserPromptSubmit`, so a context-only result there prints nothing (a permission / block result still prints).
189
+ * For events that DO accept context (sessionStart, postToolUse, subagentStart) the Claude
190
+ * `hookSpecificOutput.additionalContext` is mirrored to the top-level `additionalContext` Copilot documents.
191
+ * @param {string} text raw buffered stdout
192
+ * @param {string} [eventName] normalized hook_event_name
193
+ * @returns {string}
194
+ */
195
+ export function finalizeCopilotStdout(text, eventName) {
196
+ let o;
197
+ try {
198
+ o = JSON.parse(rewriteStdoutForCopilot(String(text ?? '')));
199
+ } catch {
200
+ return '';
201
+ }
202
+ if (!o || typeof o !== 'object' || Array.isArray(o)) return '';
203
+ const decided = typeof o.permissionDecision === 'string' || o.decision === 'block';
204
+ if (eventName === 'UserPromptSubmit' && !decided) return '';
205
+ const ctx = o.hookSpecificOutput?.additionalContext;
206
+ if (typeof ctx === 'string' && o.additionalContext === undefined && CONTEXT_EVENTS.has(String(eventName))) {
207
+ o = { ...o, additionalContext: ctx };
208
+ }
209
+ return JSON.stringify(o);
210
+ }
211
+
212
+ /**
213
+ * Append `extra` to a finished Copilot stdout blob's additionalContext (creating the object when stdout is
214
+ * empty). A permission decision is never touched. Returns the new stdout.
215
+ * @param {string} finalText '' or one JSON object
216
+ * @param {string} extra
217
+ * @returns {string}
218
+ */
219
+ export function mergeAdditionalContext(finalText, extra) {
220
+ if (!extra) return finalText;
221
+ let o = {};
222
+ if (finalText) {
223
+ try { o = JSON.parse(finalText); } catch { return finalText; }
224
+ if (!o || typeof o !== 'object' || Array.isArray(o)) return finalText;
225
+ }
226
+ if (typeof o.permissionDecision === 'string') return finalText;
227
+ const prev = typeof o.additionalContext === 'string' ? o.additionalContext : o.hookSpecificOutput?.additionalContext;
228
+ const merged = typeof prev === 'string' && prev ? `${prev}
229
+
230
+ ${extra}` : extra;
231
+ o.additionalContext = merged;
232
+ if (o.hookSpecificOutput && typeof o.hookSpecificOutput === 'object') {
233
+ o.hookSpecificOutput = { ...o.hookSpecificOutput, additionalContext: merged };
234
+ }
235
+ return JSON.stringify(o);
236
+ }
@@ -0,0 +1,34 @@
1
+ // spexharness/src/adapters/detect-harness.mjs
2
+ //
3
+ // Which agent harness is invoking this hook? ([[HS-20SW-DRSM-DIAG-heyspex-capture-on-idea-and-workflow]] Copilot
4
+ // compatibility; contract: GitHub Docs "Hooks configuration", fetched 2026-10-16.) GitHub Copilot CLI runs the
5
+ // hooks registered in `.claude/settings.json` too, but it speaks a different output dialect (ONE top-level
6
+ // `{permissionDecision, permissionDecisionReason}` object, not `hookSpecificOutput`) and treats every
7
+ // non-zero exit as a deny, so the shared runner must know when it is talking to Copilot.
8
+ //
9
+ // DETECTION IS POSITIVE-SIGNATURE ONLY - never "session_id missing". Pure: payload + env in, a string out.
10
+ // - explicit override HEYSPEX_HARNESS = copilot | claude-code | cursor (wins)
11
+ // - 'copilot' the payload carries `timestamp` (absent from Claude Code payloads) AND no Cursor marker; or it
12
+ // is the camelCase config shape ({ sessionId, toolName, toolArgs } with no snake_case twins).
13
+ // - 'cursor' `conversation_id` / `workspace_roots` / `cursor_version` present.
14
+ // - 'claude-code' a `hook_event_name` + `session_id` payload with none of the above.
15
+ // - 'unknown' anything else (including a non-object payload). Callers treat unknown like claude-code.
16
+
17
+ const OVERRIDES = new Set(['copilot', 'claude-code', 'cursor']);
18
+
19
+ /**
20
+ * @param {unknown} payload parsed hook stdin (or null)
21
+ * @param {Record<string, string | undefined>} [env]
22
+ * @returns {'claude-code' | 'copilot' | 'cursor' | 'unknown'}
23
+ */
24
+ export function detectHarness(payload, env = process.env) {
25
+ const forced = String(env?.HEYSPEX_HARNESS ?? '').trim().toLowerCase();
26
+ if (OVERRIDES.has(forced)) return forced;
27
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return 'unknown';
28
+ const p = /** @type {Record<string, unknown>} */ (payload);
29
+ if ('conversation_id' in p || 'workspace_roots' in p || 'cursor_version' in p) return 'cursor';
30
+ const camel = ('toolName' in p || 'toolArgs' in p) && !('tool_name' in p);
31
+ if ('timestamp' in p || camel) return 'copilot';
32
+ if (typeof p.hook_event_name === 'string' && typeof p.session_id === 'string') return 'claude-code';
33
+ return 'unknown';
34
+ }