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
@@ -11,10 +11,27 @@ import {
11
11
  rmSync,
12
12
  readdirSync,
13
13
  } from 'node:fs';
14
- import { join } from 'node:path';
14
+ import { join, isAbsolute, resolve, sep } from 'node:path';
15
15
  import { parseSimpleFocusYaml } from './capture-focus.mjs';
16
16
  import { yamlScalar } from './yaml-scalar.mjs';
17
- import { familyOf, mintFamilyKey, mintFileKey, parseSpecId } from './spec-id-lib.mjs';
17
+ import { ownerFrontmatterEntry, resolveSessionOwner } from './session-owner.mjs';
18
+ import { collectOccupiedKeysEitherKind, familyOf, mintFamilyKey, mintFileKey, parseSpecId } from './spec-id-lib.mjs';
19
+ import { assertPathUnderRoot } from '../../scripts/lib/shared-path-helpers.mjs';
20
+ // Cloud-mode vault WRITES ([[HS-BYU4-CWPX-TASK-promotion-writes-go-through-the-console]]).
21
+ // `heyspex_complete_research` is a promotion in the same shape as the others:
22
+ // it CREATES a research doc and then LINKS the source idea/capture to it via
23
+ // `promoted_to:` — a basename the console only mints when the POST answers.
24
+ import {
25
+ createSpecViaConsole,
26
+ updateSpecViaConsole,
27
+ } from './cloud-vault-writes.mjs';
28
+ import {
29
+ fetchSpecRecordViaConsole,
30
+ resolveWriteModeFromDeps,
31
+ splitRawSpecForConsole,
32
+ cloudWriteFailureResult,
33
+ } from './promotion-helpers.mjs';
34
+
18
35
 
19
36
  export function researchFocusPath(vaultRoot) {
20
37
  return join(vaultRoot, '.heyspex', 'research-focus.yaml');
@@ -42,6 +59,11 @@ export function writeResearchFocus(vaultRoot, { specPath, sourceIdeaId, scope, r
42
59
  return { error: 'INVALID_SCOPE', message: `scope must be one of ${[...VALID_SCOPES].join('|')}` };
43
60
  }
44
61
  const dir = join(vaultRoot, '.heyspex');
62
+ try {
63
+ assertPathUnderRoot(vaultRoot, dir, 'research-focus write');
64
+ } catch (err) {
65
+ return { error: 'BAD_VAULT_ROOT', message: err.message };
66
+ }
45
67
  mkdirSync(dir, { recursive: true });
46
68
  const lines = [
47
69
  '# HeySpex research-on-deck — MCP /hs-res ([[idea-capture-guardrails]])',
@@ -189,6 +211,161 @@ function collectOccupiedResearchIds(vaultRoot) {
189
211
  return occupied;
190
212
  }
191
213
 
214
+ /**
215
+ * Cloud write mode ([[HS-BYU4-CWPX-TASK-promotion-writes-go-through-the-console]]):
216
+ * the same two-step promotion the disk path performs, reordered CREATE FIRST /
217
+ * LINK SECOND because the console mints the research doc's id, family and
218
+ * filename — so the `promoted_to:` wikilink the source idea gets can only be
219
+ * built after `POST /api/specs` returns.
220
+ *
221
+ * Nothing is minted locally: `mintFileKey` / `mintFamilyKey` /
222
+ * `allocateRandomVaultId` all draw against a vault scan, which in a file-less
223
+ * vault is empty and can therefore collide with a key the cloud vault already
224
+ * holds. An INHERITED family (read off the source idea, never minted) is still
225
+ * passed through, matching the disk path's precedence.
226
+ *
227
+ * The research-focus PIN stays on local disk: it is per-workstation machine
228
+ * state under the local dot-directory, not vault content, and nothing indexes
229
+ * it (same call HS-KR16 made for the promote-research review-gate markers).
230
+ */
231
+ async function completeResearchViaConsole(vaultRoot, args, deps, { sourceIdeaId, scope }) {
232
+ const cloudDeps = { consoleFetch: deps?.consoleFetch, consoleUrl: deps?.consoleUrl };
233
+ const completed = [];
234
+
235
+ // 1. The source idea/capture, through the console — there is no local file.
236
+ let ideaRecord;
237
+ try {
238
+ ideaRecord = await fetchSpecRecordViaConsole(deps?.consoleFetch, sourceIdeaId);
239
+ } catch (err) {
240
+ return cloudWriteFailureResult(err, {
241
+ step: { kind: 'read', type: 'source_idea', spec_id: sourceIdeaId },
242
+ completed,
243
+ });
244
+ }
245
+ if (!ideaRecord) {
246
+ return {
247
+ error: 'IDEA_NOT_FOUND',
248
+ message: `Source idea ${sourceIdeaId} was not found through the console (cloud write mode — no local vault is consulted).`,
249
+ };
250
+ }
251
+
252
+ const ideaFmId =
253
+ ideaRecord.raw.match(/^id:\s*(\S+)/m)?.[1]?.replace(/^['"]|['"]$/g, '') ?? null;
254
+ const ideaFamilyValue =
255
+ ideaRecord.raw.match(/^family:\s*(\S+)/m)?.[1]?.replace(/^['"]|['"]$/g, '') ?? null;
256
+ const familyKey = familyOf({
257
+ id: ideaFmId ?? sourceIdeaId,
258
+ basename: ideaRecord.basename,
259
+ frontmatter: { family: ideaFamilyValue },
260
+ });
261
+
262
+ const today = new Date().toISOString().slice(0, 10);
263
+ const tags = Array.isArray(args.tags) ? args.tags : ['research'];
264
+ const related = Array.isArray(args.related) ? [...args.related] : [];
265
+ const sourceLink = `[[${ideaRecord.basename}]]`;
266
+ if (!related.some((r) => String(r).includes(sourceIdeaId))) {
267
+ related.unshift(sourceLink);
268
+ }
269
+
270
+ // 2. CREATE FIRST. `id`/`file_id`/`created`/`updated` are all server-minted
271
+ // and therefore absent from the request by construction — and so is
272
+ // `status` ([[HS-ISZP]]): the console seeds `open` and refuses an
273
+ // out-of-band status on create.
274
+ const frontmatter = {
275
+ ...(familyKey ? { family: familyKey } : {}),
276
+ // An explicit `args.owner` wins; else the paired session account; else the
277
+ // key is OMITTED ([[HS-WE87-WW9R-TASK-thread-the-gated-caller-through-every]]).
278
+ ...ownerFrontmatterEntry({
279
+ explicit: args.owner,
280
+ resolve: deps?.resolveSessionOwner ?? resolveSessionOwner,
281
+ }),
282
+ tags,
283
+ related,
284
+ source_idea: sourceLink,
285
+ scope,
286
+ };
287
+ let created;
288
+ try {
289
+ created = await createSpecViaConsole({
290
+ ...cloudDeps,
291
+ type: 'research',
292
+ name: args.title,
293
+ summary: args.executive_summary?.trim() || args.summary?.trim() || null,
294
+ frontmatter,
295
+ body: buildResearchBody(args, { sourceIdeaId, scope }),
296
+ actingAgent: deps?.actingAgent ?? null,
297
+ });
298
+ } catch (err) {
299
+ return cloudWriteFailureResult(err, {
300
+ step: { kind: 'create', type: 'research', name: args.title },
301
+ completed,
302
+ });
303
+ }
304
+ completed.push({
305
+ kind: 'create',
306
+ type: 'research',
307
+ spec_id: created.specId,
308
+ basename: created.basename,
309
+ rel_path: created.relPath,
310
+ });
311
+
312
+ // 3. …LINK SECOND: the idea's `promoted_to:` names the basename the POST
313
+ // returned, so this could not have been built any earlier.
314
+ const ideaSplit = splitRawSpecForConsole(ideaRecord.raw);
315
+ const ideaFrontmatter = {
316
+ ...ideaSplit.frontmatter,
317
+ promoted_to: `[[${created.basename}]]`,
318
+ updated: today,
319
+ };
320
+ try {
321
+ const res = await updateSpecViaConsole({
322
+ ...cloudDeps,
323
+ specId: ideaFmId ?? sourceIdeaId,
324
+ frontmatter: ideaFrontmatter,
325
+ body: ideaSplit.body,
326
+ });
327
+ completed.push({
328
+ kind: 'update',
329
+ type: 'source_idea',
330
+ spec_id: res.specId,
331
+ basename: res.basename ?? ideaRecord.basename,
332
+ rel_path: res.relPath,
333
+ });
334
+ } catch (err) {
335
+ return {
336
+ error: 'IDEA_UPDATE_FAILED',
337
+ message:
338
+ `Research ${created.specId} was created through the console at ${created.relPath}, but linking ` +
339
+ `${sourceIdeaId} back to it failed: ${String(err?.message ?? err)}`,
340
+ research_id: created.specId,
341
+ research_path: created.relPath,
342
+ write_mode: 'cloud',
343
+ completed_steps: completed,
344
+ partial: true,
345
+ };
346
+ }
347
+
348
+ const pinResult = clearResearchFocus(vaultRoot);
349
+
350
+ return {
351
+ success: true,
352
+ write_mode: 'cloud',
353
+ research_id: created.specId,
354
+ research_path: created.relPath,
355
+ research_basename: created.basename,
356
+ source_idea_id: sourceIdeaId,
357
+ source_idea_path: ideaRecord.relPath,
358
+ scope,
359
+ pin_cleared: pinResult.existed,
360
+ writes: completed.map((w) => ({ kind: w.kind, path: w.rel_path ?? null, spec_id: w.spec_id })),
361
+ next_steps: [
362
+ `Open ${created.specId} in console to review the draft research`,
363
+ 'Add wikilinks back to related specs',
364
+ 'Add `enhances:` to bind this research to a milestone, or `bound_epic:` when an epic is filed from it',
365
+ ],
366
+ };
367
+ }
368
+
192
369
  /**
193
370
  * Atomically write the research file, update the source idea's `promoted_to`,
194
371
  * and clear the research-focus pin. Returns the new research id + path.
@@ -237,6 +414,20 @@ export function executeCompleteResearch(vaultRoot, args = {}, deps = {}) {
237
414
  };
238
415
  }
239
416
  }
417
+ // ── Vault WRITE mode ([[HS-BYU4-CWPX-TASK-promotion-writes-go-through-the-console]]) ──
418
+ //
419
+ // Resolved ONCE here from `deps.writeMode` (the caller's single
420
+ // `resolveVaultWriteMode()` call) and defaulting to `local`, so every
421
+ // pre-existing caller keeps the SYNCHRONOUS disk path below — this function
422
+ // is deliberately NOT declared `async`: `handleCompleteResearch` consumes
423
+ // its return value synchronously, and making it async would turn that into
424
+ // an unawaited Promise. The cloud branch returns a Promise instead, which a
425
+ // cloud-aware caller awaits (and `await` on the plain object the disk branch
426
+ // returns is a no-op, so one call site can serve both).
427
+ if (resolveWriteModeFromDeps(deps) === 'cloud') {
428
+ return completeResearchViaConsole(vaultRoot, args, deps, { sourceIdeaId, scope });
429
+ }
430
+
240
431
  if (!deps.allocateRandomVaultId) {
241
432
  return { error: 'MISSING_DEPS', message: 'allocateRandomVaultId is required' };
242
433
  }
@@ -284,11 +475,19 @@ export function executeCompleteResearch(vaultRoot, args = {}, deps = {}) {
284
475
  mintFamilyKey(vaultRoot);
285
476
  // Per-file FILE KEY (owner ruling 2026-07-10) — filename + `file_id:` SSOT,
286
477
  // and (V3) the anchor for `id:` itself.
287
- const fileKey = mintFileKey(vaultRoot);
478
+ // Disk occupancy ([[HS-FJWL]]): this writer commits through the disk-only
479
+ // `commitWrites`, and the caller resolves `deps.writeMode` before reaching
480
+ // it, so the vault walk is complete on every path that gets here.
481
+ const fileKey = mintFileKey(collectOccupiedKeysEitherKind(vaultRoot));
288
482
  const newId = `HS-${fileKey}`;
289
483
  const slug = slugify(args.title);
290
484
  const filename = `${newId}-${familyKey}-RES-${slug}.md`;
291
485
  const researchDir = join(vaultRoot, 'specs', 'research');
486
+ try {
487
+ assertPathUnderRoot(vaultRoot, researchDir, 'research-focus write');
488
+ } catch (err) {
489
+ return { error: 'BAD_VAULT_ROOT', message: err.message };
490
+ }
292
491
  mkdirSync(researchDir, { recursive: true });
293
492
  const absResearchPath = join(researchDir, filename);
294
493
 
@@ -307,7 +506,11 @@ export function executeCompleteResearch(vaultRoot, args = {}, deps = {}) {
307
506
  name: args.title,
308
507
  type: 'research',
309
508
  status: 'open',
310
- owner: args.owner || 'pwher',
509
+ // Same owner rule as the cloud twin above.
510
+ ...ownerFrontmatterEntry({
511
+ explicit: args.owner,
512
+ resolve: deps?.resolveSessionOwner ?? resolveSessionOwner,
513
+ }),
311
514
  created: today,
312
515
  updated: today,
313
516
  tags,