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
@@ -21,7 +21,24 @@
21
21
 
22
22
  import { execFileSync } from 'node:child_process';
23
23
  import { readFileSync, writeFileSync, mkdirSync, existsSync, renameSync } from 'node:fs';
24
- import { dirname, join } from 'node:path';
24
+ import { dirname, join, isAbsolute, resolve, sep } from 'node:path';
25
+ import { assertPathUnderRoot } from '../../scripts/lib/shared-path-helpers.mjs';
26
+ // Cloud-mode vault WRITES ([[HS-BYU4-CWPX-TASK-promotion-writes-go-through-the-console]]).
27
+ // Regen has no create-first/link-second reorder — nothing it writes links to a
28
+ // basename another write in the same batch mints — but the same rule applies:
29
+ // a `writeFileSync` under `specs/` in cloud mode is a split brain.
30
+ import {
31
+ createSpecViaConsole,
32
+ updateSpecViaConsole,
33
+ stripServerMintedFields,
34
+ } from './cloud-vault-writes.mjs';
35
+ import {
36
+ resolveWriteModeFromDeps,
37
+ splitRawSpecForConsole,
38
+ cloudWriteFailureResult,
39
+ cloudModeUnsupportedWrite,
40
+ } from './promotion-helpers.mjs';
41
+
25
42
 
26
43
  const TERMINAL_STATUSES = new Set([
27
44
  'closed',
@@ -49,6 +66,11 @@ export function softDeleteToTrash(vaultRoot, relPath, bucket = 'misc') {
49
66
  if (!existsSync(abs)) return { ok: false, error: 'not_found', source: relPath };
50
67
  const basename = relPath.split(/[\\/]/).pop() || `${timestamp()}-spec.md`;
51
68
  const trashDir = join(vaultRoot, 'specs', '.trash', bucket);
69
+ try {
70
+ assertPathUnderRoot(vaultRoot, trashDir, 'regen-tasks write');
71
+ } catch (err) {
72
+ return { ok: false, error: 'BAD_VAULT_ROOT', source: relPath, message: err.message };
73
+ }
52
74
  mkdirSync(trashDir, { recursive: true });
53
75
  const dest = join(trashDir, `${timestamp()}-${basename}`);
54
76
  renameSync(abs, dest);
@@ -136,7 +158,77 @@ function epicSlugFromRel(relPath) {
136
158
  *
137
159
  * Both modes return `{ ok, mode, task, epic, brief?, commit_result? }`.
138
160
  */
139
- export function executeRegenTask(vaultRoot, { task_id, commit = false, new_body, retire_reason, loadTask }) {
161
+ /**
162
+ * The cloud twin of the `.trash/` soft-delete — EXPLICIT DEGRADE.
163
+ *
164
+ * `softDeleteToTrash` renames a file into `specs/.trash/<bucket>/`, which is
165
+ * not a spec of any type the console models (no TYPE_TO_FOLDER entry, no id,
166
+ * no frontmatter contract), so there is no POST/PUT route that could carry it.
167
+ * In cloud mode the replacement still happens — `PUT /api/specs/:id` overwrites
168
+ * the body and the console keeps its own version history — but the local
169
+ * `.trash/` copy the [[destructive-action-checklist]] recovery procedure names
170
+ * does not exist. That is REPORTED on every affected entry rather than
171
+ * silently skipped, so the caller knows which recovery path applies.
172
+ */
173
+ function cloudTrashDegrade(relPath) {
174
+ return cloudModeUnsupportedWrite(
175
+ `specs/.trash/… (soft-delete of ${relPath})`,
176
+ 'a trash copy is not a spec of any type the console models, so there is no route to write it; the replacement itself still landed through PUT /api/specs/:id and the console keeps its own version history',
177
+ { recovery: 'Restore the previous body from the console\'s spec history rather than from a local .trash/ file.' },
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Replace one existing spec's body through the console.
183
+ * `new_body` is the agent-authored full markdown (frontmatter + body), the
184
+ * same string the disk path writes verbatim.
185
+ */
186
+ async function putBodyViaConsole(specId, newBody, cloudDeps) {
187
+ const { frontmatter, body } = splitRawSpecForConsole(newBody);
188
+ return updateSpecViaConsole({ ...cloudDeps, specId, frontmatter, body });
189
+ }
190
+
191
+ /**
192
+ * Cloud-mode `executeRegenTask` commit. Same result shape as the disk path
193
+ * plus `write_mode: 'cloud'` and the `.trash/` degrade note.
194
+ */
195
+ async function regenTaskCommitViaConsole({ taskSummary, epicSummary, new_body, retire_reason, cloudDeps }) {
196
+ let res;
197
+ try {
198
+ res = await putBodyViaConsole(taskSummary.id, new_body, cloudDeps);
199
+ } catch (err) {
200
+ return {
201
+ ok: false,
202
+ ...cloudWriteFailureResult(err, {
203
+ step: { kind: 'update', type: 'task', spec_id: taskSummary.id },
204
+ completed: [],
205
+ }),
206
+ };
207
+ }
208
+ return {
209
+ ok: true,
210
+ mode: 'commit',
211
+ write_mode: 'cloud',
212
+ task: { id: res.specId ?? taskSummary.id, rel_path: res.relPath ?? taskSummary.rel_path },
213
+ retired_to: null,
214
+ retire_reason: retire_reason || null,
215
+ epic: epicSummary ? { id: epicSummary.id } : null,
216
+ cloud_mode_unsupported_writes: [cloudTrashDegrade(taskSummary.rel_path ?? taskSummary.id)],
217
+ message:
218
+ `Replaced the body of ${taskSummary.id} through the console (cloud write mode — nothing was written to local disk). ` +
219
+ 'No local .trash/ copy was made; recover the previous body from the console\'s spec history.',
220
+ };
221
+ }
222
+
223
+ export function executeRegenTask(vaultRoot, { task_id, commit = false, new_body, retire_reason, loadTask, writeMode, consoleFetch, consoleUrl }) {
224
+ // Vault WRITE mode ([[HS-BYU4-CWPX-TASK-promotion-writes-go-through-the-console]]),
225
+ // resolved ONCE by the caller and defaulting to `local`. This function stays
226
+ // SYNCHRONOUS on the local path on purpose — `spec-edit-tools.mjs` consumes
227
+ // its return value synchronously — and returns a Promise only in cloud mode,
228
+ // which a cloud-aware caller awaits (awaiting the plain object the local
229
+ // path returns is a no-op, so one call site serves both).
230
+ const cloudWriteMode = resolveWriteModeFromDeps({ writeMode });
231
+ const cloudDeps = { consoleFetch, consoleUrl };
140
232
  if (!task_id) {
141
233
  return { ok: false, error: 'MISSING_TASK_ID', message: 'task_id is required' };
142
234
  }
@@ -159,6 +251,15 @@ export function executeRegenTask(vaultRoot, { task_id, commit = false, new_body,
159
251
  message: 'commit: true requires non-empty new_body',
160
252
  };
161
253
  }
254
+ if (cloudWriteMode === 'cloud') {
255
+ return regenTaskCommitViaConsole({
256
+ taskSummary,
257
+ epicSummary,
258
+ new_body,
259
+ retire_reason,
260
+ cloudDeps,
261
+ });
262
+ }
162
263
  if (!taskSummary.rel_path) {
163
264
  return { ok: false, error: 'NO_REL_PATH', task_id };
164
265
  }
@@ -172,6 +273,11 @@ export function executeRegenTask(vaultRoot, { task_id, commit = false, new_body,
172
273
  // it — that's an agent error and surfaces as a malformed spec at the
173
274
  // next /hs-next.
174
275
  const destAbs = join(vaultRoot, taskSummary.rel_path);
276
+ try {
277
+ assertPathUnderRoot(vaultRoot, dirname(destAbs), 'regen-tasks write');
278
+ } catch (err) {
279
+ return { ok: false, error: 'BAD_VAULT_ROOT', task_id, message: err.message };
280
+ }
175
281
  mkdirSync(dirname(destAbs), { recursive: true });
176
282
  writeFileSync(destAbs, new_body, 'utf8');
177
283
  return {
@@ -222,7 +328,93 @@ export function executeRegenTask(vaultRoot, { task_id, commit = false, new_body,
222
328
  * The tool is deliberately deterministic — the LLM thinking happens between
223
329
  * brief mode and commit mode in the calling agent.
224
330
  */
225
- export function executeRegenTasksForEpic(vaultRoot, { epic_id, commit = false, task_specs, loadTask }) {
331
+ /**
332
+ * Cloud-mode `executeRegenTasksForEpic` commit — the same two entry shapes the
333
+ * disk path takes, routed through the console:
334
+ *
335
+ * `{ id, new_body, retire_reason }` → `PUT /api/specs/:id` (replace in place;
336
+ * no local `.trash/` copy — reported, see {@link cloudTrashDegrade}).
337
+ * `{ new_id, body, rel_path }` → `POST /api/specs` (the caller-supplied
338
+ * `new_id`/`rel_path` are IGNORED: the console mints the id, the family
339
+ * and the filename, so nothing is hand-picked — HS-BYU4 AC3. The minted
340
+ * id is reported back in `wrote[]`.)
341
+ */
342
+ async function regenTasksForEpicCommitViaConsole({ epicSummary, task_specs, loadTask, cloudDeps }) {
343
+ const retired = [];
344
+ const wrote = [];
345
+ const errors = [];
346
+ const unsupported = [];
347
+ for (const entry of task_specs) {
348
+ if (entry && typeof entry === 'object' && entry.id && typeof entry.new_body === 'string') {
349
+ const target = loadSpecRecord(loadTask, entry.id);
350
+ const specId = target?.id || target?.frontmatter?.id || entry.id;
351
+ try {
352
+ const res = await putBodyViaConsole(specId, entry.new_body, cloudDeps);
353
+ retired.push({ id: entry.id, trash_path: null, retire_reason: entry.retire_reason || null });
354
+ unsupported.push(cloudTrashDegrade(target?.relPath || target?.rel_path || entry.id));
355
+ wrote.push({ id: res.specId ?? specId, rel_path: res.relPath ?? null });
356
+ } catch (err) {
357
+ errors.push({
358
+ id: entry.id,
359
+ ...cloudWriteFailureResult(err, {
360
+ step: { kind: 'update', type: 'task', spec_id: specId },
361
+ completed: wrote,
362
+ }),
363
+ });
364
+ }
365
+ } else if (entry && typeof entry === 'object' && entry.new_id && typeof entry.body === 'string') {
366
+ const { frontmatter, body } = splitRawSpecForConsole(entry.body);
367
+ const cleaned = stripServerMintedFields(frontmatter);
368
+ try {
369
+ const created = await createSpecViaConsole({
370
+ ...cloudDeps,
371
+ type: cleaned.type ?? frontmatter.type ?? 'task',
372
+ name: cleaned.name ?? frontmatter.name ?? String(entry.new_id),
373
+ summary: cleaned.summary ?? null,
374
+ frontmatter: cleaned,
375
+ body,
376
+ });
377
+ wrote.push({
378
+ id: created.specId,
379
+ rel_path: created.relPath,
380
+ requested_id: entry.new_id,
381
+ note:
382
+ 'The console minted this id/filename server-side; the caller-supplied `new_id`/`rel_path` were not used (file keys are never hand-picked).',
383
+ });
384
+ } catch (err) {
385
+ errors.push({
386
+ new_id: entry.new_id,
387
+ ...cloudWriteFailureResult(err, {
388
+ step: { kind: 'create', type: 'task', name: entry.new_id },
389
+ completed: wrote,
390
+ }),
391
+ });
392
+ }
393
+ } else {
394
+ errors.push({ entry, error: 'INVALID_SHAPE' });
395
+ }
396
+ }
397
+ return {
398
+ ok: errors.length === 0,
399
+ mode: 'commit',
400
+ write_mode: 'cloud',
401
+ epic: { id: epicSummary.id },
402
+ retired,
403
+ wrote,
404
+ errors,
405
+ bucket: null,
406
+ ...(unsupported.length > 0 ? { cloud_mode_unsupported_writes: unsupported } : {}),
407
+ message:
408
+ `Stage-1-2-3 commit for ${epicSummary.id} through the console: replaced ${retired.length}, wrote ${wrote.length}, errors ${errors.length}. ` +
409
+ 'Cloud write mode — nothing was written to local disk and no .trash/ copies were made; recover previous bodies from the console\'s spec history.',
410
+ };
411
+ }
412
+
413
+ export function executeRegenTasksForEpic(vaultRoot, { epic_id, commit = false, task_specs, loadTask, writeMode, consoleFetch, consoleUrl }) {
414
+ // Same once-per-call resolution + sync-unless-cloud contract as
415
+ // {@link executeRegenTask} above.
416
+ const cloudWriteMode = resolveWriteModeFromDeps({ writeMode });
417
+ const cloudDeps = { consoleFetch, consoleUrl };
226
418
  if (!epic_id) {
227
419
  return { ok: false, error: 'MISSING_EPIC_ID', message: 'epic_id is required' };
228
420
  }
@@ -255,6 +447,9 @@ export function executeRegenTasksForEpic(vaultRoot, { epic_id, commit = false, t
255
447
  message: 'commit: true requires task_specs: [{ id, new_body, retire_reason } | { new_id, body, rel_path }]',
256
448
  };
257
449
  }
450
+ if (cloudWriteMode === 'cloud') {
451
+ return regenTasksForEpicCommitViaConsole({ epicSummary, task_specs, loadTask, cloudDeps });
452
+ }
258
453
  const bucket = epicSlugFromRel(epicSummary.rel_path);
259
454
  const retired = [];
260
455
  const wrote = [];
@@ -273,6 +468,12 @@ export function executeRegenTasksForEpic(vaultRoot, { epic_id, commit = false, t
273
468
  continue;
274
469
  }
275
470
  const abs = join(vaultRoot, rel);
471
+ try {
472
+ assertPathUnderRoot(vaultRoot, dirname(abs), 'regen-tasks write');
473
+ } catch (err) {
474
+ errors.push({ id: entry.id, error: 'BAD_VAULT_ROOT', message: err.message });
475
+ continue;
476
+ }
276
477
  mkdirSync(dirname(abs), { recursive: true });
277
478
  writeFileSync(abs, entry.new_body, 'utf8');
278
479
  retired.push({ id: entry.id, trash_path: del.trash_path, retire_reason: entry.retire_reason || null });
@@ -283,6 +484,12 @@ export function executeRegenTasksForEpic(vaultRoot, { epic_id, commit = false, t
283
484
  errors.push({ new_id: entry.new_id, error: 'CONFLICT', rel_path: entry.rel_path });
284
485
  continue;
285
486
  }
487
+ try {
488
+ assertPathUnderRoot(vaultRoot, dirname(abs), 'regen-tasks write');
489
+ } catch (err) {
490
+ errors.push({ new_id: entry.new_id, error: 'BAD_VAULT_ROOT', message: err.message });
491
+ continue;
492
+ }
286
493
  mkdirSync(dirname(abs), { recursive: true });
287
494
  writeFileSync(abs, entry.body, 'utf8');
288
495
  wrote.push({ id: entry.new_id, rel_path: entry.rel_path });