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
@@ -12,6 +12,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
12
12
  if (typeof require !== "undefined") return require.apply(this, arguments);
13
13
  throw Error('Dynamic require of "' + x + '" is not supported');
14
14
  });
15
+ var __esm = (fn, res) => function __init() {
16
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
17
+ };
15
18
  var __commonJS = (cb, mod2) => function __require2() {
16
19
  return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports;
17
20
  };
@@ -109,8 +112,8 @@ var require_main = __commonJS({
109
112
  "node_modules/dotenv/lib/main.js"(exports, module) {
110
113
  "use strict";
111
114
  var fs = __require("fs");
112
- var path6 = __require("path");
113
- var os = __require("os");
115
+ var path7 = __require("path");
116
+ var os2 = __require("os");
114
117
  var crypto3 = __require("crypto");
115
118
  var packageJson = require_package();
116
119
  var version = packageJson.version;
@@ -225,7 +228,7 @@ var require_main = __commonJS({
225
228
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
226
229
  }
227
230
  } else {
228
- possibleVaultPath = path6.resolve(process.cwd(), ".env.vault");
231
+ possibleVaultPath = path7.resolve(process.cwd(), ".env.vault");
229
232
  }
230
233
  if (fs.existsSync(possibleVaultPath)) {
231
234
  return possibleVaultPath;
@@ -233,7 +236,7 @@ var require_main = __commonJS({
233
236
  return null;
234
237
  }
235
238
  function _resolveHome(envPath) {
236
- return envPath[0] === "~" ? path6.join(os.homedir(), envPath.slice(1)) : envPath;
239
+ return envPath[0] === "~" ? path7.join(os2.homedir(), envPath.slice(1)) : envPath;
237
240
  }
238
241
  function _configVault(options) {
239
242
  const debug = Boolean(options && options.debug);
@@ -250,7 +253,7 @@ var require_main = __commonJS({
250
253
  return { parsed };
251
254
  }
252
255
  function configDotenv(options) {
253
- const dotenvPath2 = path6.resolve(process.cwd(), ".env");
256
+ const dotenvPath2 = path7.resolve(process.cwd(), ".env");
254
257
  let encoding = "utf8";
255
258
  const debug = Boolean(options && options.debug);
256
259
  const quiet = options && "quiet" in options ? options.quiet : true;
@@ -274,13 +277,13 @@ var require_main = __commonJS({
274
277
  }
275
278
  let lastError;
276
279
  const parsedAll = {};
277
- for (const path7 of optionPaths) {
280
+ for (const path8 of optionPaths) {
278
281
  try {
279
- const parsed = DotenvModule.parse(fs.readFileSync(path7, { encoding }));
282
+ const parsed = DotenvModule.parse(fs.readFileSync(path8, { encoding }));
280
283
  DotenvModule.populate(parsedAll, parsed, options);
281
284
  } catch (e) {
282
285
  if (debug) {
283
- _debug(`Failed to load ${path7} ${e.message}`);
286
+ _debug(`Failed to load ${path8} ${e.message}`);
284
287
  }
285
288
  lastError = e;
286
289
  }
@@ -295,7 +298,7 @@ var require_main = __commonJS({
295
298
  const shortPaths = [];
296
299
  for (const filePath of optionPaths) {
297
300
  try {
298
- const relative = path6.relative(process.cwd(), filePath);
301
+ const relative = path7.relative(process.cwd(), filePath);
299
302
  shortPaths.push(relative);
300
303
  } catch (e) {
301
304
  if (debug) {
@@ -472,17 +475,17 @@ var require_visit = __commonJS({
472
475
  visit.BREAK = BREAK;
473
476
  visit.SKIP = SKIP;
474
477
  visit.REMOVE = REMOVE;
475
- function visit_(key, node, visitor, path6) {
476
- const ctrl = callVisitor(key, node, visitor, path6);
478
+ function visit_(key, node, visitor, path7) {
479
+ const ctrl = callVisitor(key, node, visitor, path7);
477
480
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
478
- replaceNode(key, path6, ctrl);
479
- return visit_(key, ctrl, visitor, path6);
481
+ replaceNode(key, path7, ctrl);
482
+ return visit_(key, ctrl, visitor, path7);
480
483
  }
481
484
  if (typeof ctrl !== "symbol") {
482
485
  if (identity.isCollection(node)) {
483
- path6 = Object.freeze(path6.concat(node));
486
+ path7 = Object.freeze(path7.concat(node));
484
487
  for (let i = 0; i < node.items.length; ++i) {
485
- const ci = visit_(i, node.items[i], visitor, path6);
488
+ const ci = visit_(i, node.items[i], visitor, path7);
486
489
  if (typeof ci === "number")
487
490
  i = ci - 1;
488
491
  else if (ci === BREAK)
@@ -493,13 +496,13 @@ var require_visit = __commonJS({
493
496
  }
494
497
  }
495
498
  } else if (identity.isPair(node)) {
496
- path6 = Object.freeze(path6.concat(node));
497
- const ck = visit_("key", node.key, visitor, path6);
499
+ path7 = Object.freeze(path7.concat(node));
500
+ const ck = visit_("key", node.key, visitor, path7);
498
501
  if (ck === BREAK)
499
502
  return BREAK;
500
503
  else if (ck === REMOVE)
501
504
  node.key = null;
502
- const cv = visit_("value", node.value, visitor, path6);
505
+ const cv = visit_("value", node.value, visitor, path7);
503
506
  if (cv === BREAK)
504
507
  return BREAK;
505
508
  else if (cv === REMOVE)
@@ -520,17 +523,17 @@ var require_visit = __commonJS({
520
523
  visitAsync.BREAK = BREAK;
521
524
  visitAsync.SKIP = SKIP;
522
525
  visitAsync.REMOVE = REMOVE;
523
- async function visitAsync_(key, node, visitor, path6) {
524
- const ctrl = await callVisitor(key, node, visitor, path6);
526
+ async function visitAsync_(key, node, visitor, path7) {
527
+ const ctrl = await callVisitor(key, node, visitor, path7);
525
528
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
526
- replaceNode(key, path6, ctrl);
527
- return visitAsync_(key, ctrl, visitor, path6);
529
+ replaceNode(key, path7, ctrl);
530
+ return visitAsync_(key, ctrl, visitor, path7);
528
531
  }
529
532
  if (typeof ctrl !== "symbol") {
530
533
  if (identity.isCollection(node)) {
531
- path6 = Object.freeze(path6.concat(node));
534
+ path7 = Object.freeze(path7.concat(node));
532
535
  for (let i = 0; i < node.items.length; ++i) {
533
- const ci = await visitAsync_(i, node.items[i], visitor, path6);
536
+ const ci = await visitAsync_(i, node.items[i], visitor, path7);
534
537
  if (typeof ci === "number")
535
538
  i = ci - 1;
536
539
  else if (ci === BREAK)
@@ -541,13 +544,13 @@ var require_visit = __commonJS({
541
544
  }
542
545
  }
543
546
  } else if (identity.isPair(node)) {
544
- path6 = Object.freeze(path6.concat(node));
545
- const ck = await visitAsync_("key", node.key, visitor, path6);
547
+ path7 = Object.freeze(path7.concat(node));
548
+ const ck = await visitAsync_("key", node.key, visitor, path7);
546
549
  if (ck === BREAK)
547
550
  return BREAK;
548
551
  else if (ck === REMOVE)
549
552
  node.key = null;
550
- const cv = await visitAsync_("value", node.value, visitor, path6);
553
+ const cv = await visitAsync_("value", node.value, visitor, path7);
551
554
  if (cv === BREAK)
552
555
  return BREAK;
553
556
  else if (cv === REMOVE)
@@ -574,23 +577,23 @@ var require_visit = __commonJS({
574
577
  }
575
578
  return visitor;
576
579
  }
577
- function callVisitor(key, node, visitor, path6) {
580
+ function callVisitor(key, node, visitor, path7) {
578
581
  if (typeof visitor === "function")
579
- return visitor(key, node, path6);
582
+ return visitor(key, node, path7);
580
583
  if (identity.isMap(node))
581
- return visitor.Map?.(key, node, path6);
584
+ return visitor.Map?.(key, node, path7);
582
585
  if (identity.isSeq(node))
583
- return visitor.Seq?.(key, node, path6);
586
+ return visitor.Seq?.(key, node, path7);
584
587
  if (identity.isPair(node))
585
- return visitor.Pair?.(key, node, path6);
588
+ return visitor.Pair?.(key, node, path7);
586
589
  if (identity.isScalar(node))
587
- return visitor.Scalar?.(key, node, path6);
590
+ return visitor.Scalar?.(key, node, path7);
588
591
  if (identity.isAlias(node))
589
- return visitor.Alias?.(key, node, path6);
592
+ return visitor.Alias?.(key, node, path7);
590
593
  return void 0;
591
594
  }
592
- function replaceNode(key, path6, node) {
593
- const parent = path6[path6.length - 1];
595
+ function replaceNode(key, path7, node) {
596
+ const parent = path7[path7.length - 1];
594
597
  if (identity.isCollection(parent)) {
595
598
  parent.items[key] = node;
596
599
  } else if (identity.isPair(parent)) {
@@ -1200,10 +1203,10 @@ var require_Collection = __commonJS({
1200
1203
  var createNode = require_createNode();
1201
1204
  var identity = require_identity();
1202
1205
  var Node = require_Node();
1203
- function collectionFromPath(schema, path6, value) {
1206
+ function collectionFromPath(schema, path7, value) {
1204
1207
  let v = value;
1205
- for (let i = path6.length - 1; i >= 0; --i) {
1206
- const k = path6[i];
1208
+ for (let i = path7.length - 1; i >= 0; --i) {
1209
+ const k = path7[i];
1207
1210
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
1208
1211
  const a = [];
1209
1212
  a[k] = v;
@@ -1222,7 +1225,7 @@ var require_Collection = __commonJS({
1222
1225
  sourceObjects: /* @__PURE__ */ new Map()
1223
1226
  });
1224
1227
  }
1225
- var isEmptyPath = (path6) => path6 == null || typeof path6 === "object" && !!path6[Symbol.iterator]().next().done;
1228
+ var isEmptyPath = (path7) => path7 == null || typeof path7 === "object" && !!path7[Symbol.iterator]().next().done;
1226
1229
  var Collection = class extends Node.NodeBase {
1227
1230
  constructor(type, schema) {
1228
1231
  super(type);
@@ -1252,11 +1255,11 @@ var require_Collection = __commonJS({
1252
1255
  * be a Pair instance or a `{ key, value }` object, which may not have a key
1253
1256
  * that already exists in the map.
1254
1257
  */
1255
- addIn(path6, value) {
1256
- if (isEmptyPath(path6))
1258
+ addIn(path7, value) {
1259
+ if (isEmptyPath(path7))
1257
1260
  this.add(value);
1258
1261
  else {
1259
- const [key, ...rest] = path6;
1262
+ const [key, ...rest] = path7;
1260
1263
  const node = this.get(key, true);
1261
1264
  if (identity.isCollection(node))
1262
1265
  node.addIn(rest, value);
@@ -1270,8 +1273,8 @@ var require_Collection = __commonJS({
1270
1273
  * Removes a value from the collection.
1271
1274
  * @returns `true` if the item was found and removed.
1272
1275
  */
1273
- deleteIn(path6) {
1274
- const [key, ...rest] = path6;
1276
+ deleteIn(path7) {
1277
+ const [key, ...rest] = path7;
1275
1278
  if (rest.length === 0)
1276
1279
  return this.delete(key);
1277
1280
  const node = this.get(key, true);
@@ -1285,8 +1288,8 @@ var require_Collection = __commonJS({
1285
1288
  * scalar values from their surrounding node; to disable set `keepScalar` to
1286
1289
  * `true` (collections are always returned intact).
1287
1290
  */
1288
- getIn(path6, keepScalar) {
1289
- const [key, ...rest] = path6;
1291
+ getIn(path7, keepScalar) {
1292
+ const [key, ...rest] = path7;
1290
1293
  const node = this.get(key, true);
1291
1294
  if (rest.length === 0)
1292
1295
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -1304,8 +1307,8 @@ var require_Collection = __commonJS({
1304
1307
  /**
1305
1308
  * Checks if the collection includes a value with the key `key`.
1306
1309
  */
1307
- hasIn(path6) {
1308
- const [key, ...rest] = path6;
1310
+ hasIn(path7) {
1311
+ const [key, ...rest] = path7;
1309
1312
  if (rest.length === 0)
1310
1313
  return this.has(key);
1311
1314
  const node = this.get(key, true);
@@ -1315,8 +1318,8 @@ var require_Collection = __commonJS({
1315
1318
  * Sets a value in this collection. For `!!set`, `value` needs to be a
1316
1319
  * boolean to add/remove the item from the set.
1317
1320
  */
1318
- setIn(path6, value) {
1319
- const [key, ...rest] = path6;
1321
+ setIn(path7, value) {
1322
+ const [key, ...rest] = path7;
1320
1323
  if (rest.length === 0) {
1321
1324
  this.set(key, value);
1322
1325
  } else {
@@ -3831,9 +3834,9 @@ var require_Document = __commonJS({
3831
3834
  this.contents.add(value);
3832
3835
  }
3833
3836
  /** Adds a value to the document. */
3834
- addIn(path6, value) {
3837
+ addIn(path7, value) {
3835
3838
  if (assertCollection(this.contents))
3836
- this.contents.addIn(path6, value);
3839
+ this.contents.addIn(path7, value);
3837
3840
  }
3838
3841
  /**
3839
3842
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3908,14 +3911,14 @@ var require_Document = __commonJS({
3908
3911
  * Removes a value from the document.
3909
3912
  * @returns `true` if the item was found and removed.
3910
3913
  */
3911
- deleteIn(path6) {
3912
- if (Collection.isEmptyPath(path6)) {
3914
+ deleteIn(path7) {
3915
+ if (Collection.isEmptyPath(path7)) {
3913
3916
  if (this.contents == null)
3914
3917
  return false;
3915
3918
  this.contents = null;
3916
3919
  return true;
3917
3920
  }
3918
- return assertCollection(this.contents) ? this.contents.deleteIn(path6) : false;
3921
+ return assertCollection(this.contents) ? this.contents.deleteIn(path7) : false;
3919
3922
  }
3920
3923
  /**
3921
3924
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3930,10 +3933,10 @@ var require_Document = __commonJS({
3930
3933
  * scalar values from their surrounding node; to disable set `keepScalar` to
3931
3934
  * `true` (collections are always returned intact).
3932
3935
  */
3933
- getIn(path6, keepScalar) {
3934
- if (Collection.isEmptyPath(path6))
3936
+ getIn(path7, keepScalar) {
3937
+ if (Collection.isEmptyPath(path7))
3935
3938
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3936
- return identity.isCollection(this.contents) ? this.contents.getIn(path6, keepScalar) : void 0;
3939
+ return identity.isCollection(this.contents) ? this.contents.getIn(path7, keepScalar) : void 0;
3937
3940
  }
3938
3941
  /**
3939
3942
  * Checks if the document includes a value with the key `key`.
@@ -3944,10 +3947,10 @@ var require_Document = __commonJS({
3944
3947
  /**
3945
3948
  * Checks if the document includes a value at `path`.
3946
3949
  */
3947
- hasIn(path6) {
3948
- if (Collection.isEmptyPath(path6))
3950
+ hasIn(path7) {
3951
+ if (Collection.isEmptyPath(path7))
3949
3952
  return this.contents !== void 0;
3950
- return identity.isCollection(this.contents) ? this.contents.hasIn(path6) : false;
3953
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path7) : false;
3951
3954
  }
3952
3955
  /**
3953
3956
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3964,13 +3967,13 @@ var require_Document = __commonJS({
3964
3967
  * Sets a value in this document. For `!!set`, `value` needs to be a
3965
3968
  * boolean to add/remove the item from the set.
3966
3969
  */
3967
- setIn(path6, value) {
3968
- if (Collection.isEmptyPath(path6)) {
3970
+ setIn(path7, value) {
3971
+ if (Collection.isEmptyPath(path7)) {
3969
3972
  this.contents = value;
3970
3973
  } else if (this.contents == null) {
3971
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path6), value);
3974
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path7), value);
3972
3975
  } else if (assertCollection(this.contents)) {
3973
- this.contents.setIn(path6, value);
3976
+ this.contents.setIn(path7, value);
3974
3977
  }
3975
3978
  }
3976
3979
  /**
@@ -4356,10 +4359,10 @@ var require_resolve_block_map = __commonJS({
4356
4359
  let offset = bm.offset;
4357
4360
  let commentEnd = null;
4358
4361
  for (const collItem of bm.items) {
4359
- const { start, key, sep, value } = collItem;
4362
+ const { start, key, sep: sep2, value } = collItem;
4360
4363
  const keyProps = resolveProps.resolveProps(start, {
4361
4364
  indicator: "explicit-key-ind",
4362
- next: key ?? sep?.[0],
4365
+ next: key ?? sep2?.[0],
4363
4366
  offset,
4364
4367
  onError,
4365
4368
  parentIndent: bm.indent,
@@ -4373,7 +4376,7 @@ var require_resolve_block_map = __commonJS({
4373
4376
  else if ("indent" in key && key.indent !== bm.indent)
4374
4377
  onError(offset, "BAD_INDENT", startColMsg);
4375
4378
  }
4376
- if (!keyProps.anchor && !keyProps.tag && !sep) {
4379
+ if (!keyProps.anchor && !keyProps.tag && !sep2) {
4377
4380
  commentEnd = keyProps.end;
4378
4381
  if (keyProps.comment) {
4379
4382
  if (map.comment)
@@ -4397,7 +4400,7 @@ var require_resolve_block_map = __commonJS({
4397
4400
  ctx.atKey = false;
4398
4401
  if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
4399
4402
  onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
4400
- const valueProps = resolveProps.resolveProps(sep ?? [], {
4403
+ const valueProps = resolveProps.resolveProps(sep2 ?? [], {
4401
4404
  indicator: "map-value-ind",
4402
4405
  next: value,
4403
4406
  offset: keyNode.range[2],
@@ -4413,7 +4416,7 @@ var require_resolve_block_map = __commonJS({
4413
4416
  if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
4414
4417
  onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
4415
4418
  }
4416
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep, null, valueProps, onError);
4419
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep2, null, valueProps, onError);
4417
4420
  if (ctx.schema.compat)
4418
4421
  utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
4419
4422
  offset = valueNode.range[2];
@@ -4504,7 +4507,7 @@ var require_resolve_end = __commonJS({
4504
4507
  let comment = "";
4505
4508
  if (end) {
4506
4509
  let hasSpace = false;
4507
- let sep = "";
4510
+ let sep2 = "";
4508
4511
  for (const token of end) {
4509
4512
  const { source, type } = token;
4510
4513
  switch (type) {
@@ -4518,13 +4521,13 @@ var require_resolve_end = __commonJS({
4518
4521
  if (!comment)
4519
4522
  comment = cb;
4520
4523
  else
4521
- comment += sep + cb;
4522
- sep = "";
4524
+ comment += sep2 + cb;
4525
+ sep2 = "";
4523
4526
  break;
4524
4527
  }
4525
4528
  case "newline":
4526
4529
  if (comment)
4527
- sep += source;
4530
+ sep2 += source;
4528
4531
  hasSpace = true;
4529
4532
  break;
4530
4533
  default:
@@ -4567,18 +4570,18 @@ var require_resolve_flow_collection = __commonJS({
4567
4570
  let offset = fc.offset + fc.start.source.length;
4568
4571
  for (let i = 0; i < fc.items.length; ++i) {
4569
4572
  const collItem = fc.items[i];
4570
- const { start, key, sep, value } = collItem;
4573
+ const { start, key, sep: sep2, value } = collItem;
4571
4574
  const props = resolveProps.resolveProps(start, {
4572
4575
  flow: fcName,
4573
4576
  indicator: "explicit-key-ind",
4574
- next: key ?? sep?.[0],
4577
+ next: key ?? sep2?.[0],
4575
4578
  offset,
4576
4579
  onError,
4577
4580
  parentIndent: fc.indent,
4578
4581
  startOnNewline: false
4579
4582
  });
4580
4583
  if (!props.found) {
4581
- if (!props.anchor && !props.tag && !sep && !value) {
4584
+ if (!props.anchor && !props.tag && !sep2 && !value) {
4582
4585
  if (i === 0 && props.comma)
4583
4586
  onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
4584
4587
  else if (i < fc.items.length - 1)
@@ -4632,8 +4635,8 @@ var require_resolve_flow_collection = __commonJS({
4632
4635
  }
4633
4636
  }
4634
4637
  }
4635
- if (!isMap && !sep && !props.found) {
4636
- const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep, null, props, onError);
4638
+ if (!isMap && !sep2 && !props.found) {
4639
+ const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep2, null, props, onError);
4637
4640
  coll.items.push(valueNode);
4638
4641
  offset = valueNode.range[2];
4639
4642
  if (isBlock(value))
@@ -4645,7 +4648,7 @@ var require_resolve_flow_collection = __commonJS({
4645
4648
  if (isBlock(key))
4646
4649
  onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
4647
4650
  ctx.atKey = false;
4648
- const valueProps = resolveProps.resolveProps(sep ?? [], {
4651
+ const valueProps = resolveProps.resolveProps(sep2 ?? [], {
4649
4652
  flow: fcName,
4650
4653
  indicator: "map-value-ind",
4651
4654
  next: value,
@@ -4656,8 +4659,8 @@ var require_resolve_flow_collection = __commonJS({
4656
4659
  });
4657
4660
  if (valueProps.found) {
4658
4661
  if (!isMap && !props.found && ctx.options.strict) {
4659
- if (sep)
4660
- for (const st of sep) {
4662
+ if (sep2)
4663
+ for (const st of sep2) {
4661
4664
  if (st === valueProps.found)
4662
4665
  break;
4663
4666
  if (st.type === "newline") {
@@ -4674,7 +4677,7 @@ var require_resolve_flow_collection = __commonJS({
4674
4677
  else
4675
4678
  onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
4676
4679
  }
4677
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep, null, valueProps, onError) : null;
4680
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep2, null, valueProps, onError) : null;
4678
4681
  if (valueNode) {
4679
4682
  if (isBlock(value))
4680
4683
  onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
@@ -4854,7 +4857,7 @@ var require_resolve_block_scalar = __commonJS({
4854
4857
  chompStart = i + 1;
4855
4858
  }
4856
4859
  let value = "";
4857
- let sep = "";
4860
+ let sep2 = "";
4858
4861
  let prevMoreIndented = false;
4859
4862
  for (let i = 0; i < contentStart; ++i)
4860
4863
  value += lines[i][0].slice(trimIndent) + "\n";
@@ -4871,24 +4874,24 @@ var require_resolve_block_scalar = __commonJS({
4871
4874
  indent = "";
4872
4875
  }
4873
4876
  if (type === Scalar.Scalar.BLOCK_LITERAL) {
4874
- value += sep + indent.slice(trimIndent) + content;
4875
- sep = "\n";
4877
+ value += sep2 + indent.slice(trimIndent) + content;
4878
+ sep2 = "\n";
4876
4879
  } else if (indent.length > trimIndent || content[0] === " ") {
4877
- if (sep === " ")
4878
- sep = "\n";
4879
- else if (!prevMoreIndented && sep === "\n")
4880
- sep = "\n\n";
4881
- value += sep + indent.slice(trimIndent) + content;
4882
- sep = "\n";
4880
+ if (sep2 === " ")
4881
+ sep2 = "\n";
4882
+ else if (!prevMoreIndented && sep2 === "\n")
4883
+ sep2 = "\n\n";
4884
+ value += sep2 + indent.slice(trimIndent) + content;
4885
+ sep2 = "\n";
4883
4886
  prevMoreIndented = true;
4884
4887
  } else if (content === "") {
4885
- if (sep === "\n")
4888
+ if (sep2 === "\n")
4886
4889
  value += "\n";
4887
4890
  else
4888
- sep = "\n";
4891
+ sep2 = "\n";
4889
4892
  } else {
4890
- value += sep + content;
4891
- sep = " ";
4893
+ value += sep2 + content;
4894
+ sep2 = " ";
4892
4895
  prevMoreIndented = false;
4893
4896
  }
4894
4897
  }
@@ -5070,25 +5073,25 @@ var require_resolve_flow_scalar = __commonJS({
5070
5073
  if (!match)
5071
5074
  return source;
5072
5075
  let res = match[1];
5073
- let sep = " ";
5076
+ let sep2 = " ";
5074
5077
  let pos = first.lastIndex;
5075
5078
  line.lastIndex = pos;
5076
5079
  while (match = line.exec(source)) {
5077
5080
  if (match[1] === "") {
5078
- if (sep === "\n")
5079
- res += sep;
5081
+ if (sep2 === "\n")
5082
+ res += sep2;
5080
5083
  else
5081
- sep = "\n";
5084
+ sep2 = "\n";
5082
5085
  } else {
5083
- res += sep + match[1];
5084
- sep = " ";
5086
+ res += sep2 + match[1];
5087
+ sep2 = " ";
5085
5088
  }
5086
5089
  pos = line.lastIndex;
5087
5090
  }
5088
5091
  const last = /[ \t]*(.*)/sy;
5089
5092
  last.lastIndex = pos;
5090
5093
  match = last.exec(source);
5091
- return res + sep + (match?.[1] ?? "");
5094
+ return res + sep2 + (match?.[1] ?? "");
5092
5095
  }
5093
5096
  function doubleQuotedValue(source, onError) {
5094
5097
  let res = "";
@@ -5898,14 +5901,14 @@ var require_cst_stringify = __commonJS({
5898
5901
  }
5899
5902
  }
5900
5903
  }
5901
- function stringifyItem({ start, key, sep, value }) {
5904
+ function stringifyItem({ start, key, sep: sep2, value }) {
5902
5905
  let res = "";
5903
5906
  for (const st of start)
5904
5907
  res += st.source;
5905
5908
  if (key)
5906
5909
  res += stringifyToken(key);
5907
- if (sep)
5908
- for (const st of sep)
5910
+ if (sep2)
5911
+ for (const st of sep2)
5909
5912
  res += st.source;
5910
5913
  if (value)
5911
5914
  res += stringifyToken(value);
@@ -5930,9 +5933,9 @@ var require_cst_visit = __commonJS({
5930
5933
  visit.BREAK = BREAK;
5931
5934
  visit.SKIP = SKIP;
5932
5935
  visit.REMOVE = REMOVE;
5933
- visit.itemAtPath = (cst, path6) => {
5936
+ visit.itemAtPath = (cst, path7) => {
5934
5937
  let item = cst;
5935
- for (const [field, index] of path6) {
5938
+ for (const [field, index] of path7) {
5936
5939
  const tok = item?.[field];
5937
5940
  if (tok && "items" in tok) {
5938
5941
  item = tok.items[index];
@@ -5941,23 +5944,23 @@ var require_cst_visit = __commonJS({
5941
5944
  }
5942
5945
  return item;
5943
5946
  };
5944
- visit.parentCollection = (cst, path6) => {
5945
- const parent = visit.itemAtPath(cst, path6.slice(0, -1));
5946
- const field = path6[path6.length - 1][0];
5947
+ visit.parentCollection = (cst, path7) => {
5948
+ const parent = visit.itemAtPath(cst, path7.slice(0, -1));
5949
+ const field = path7[path7.length - 1][0];
5947
5950
  const coll = parent?.[field];
5948
5951
  if (coll && "items" in coll)
5949
5952
  return coll;
5950
5953
  throw new Error("Parent collection not found");
5951
5954
  };
5952
- function _visit(path6, item, visitor) {
5953
- let ctrl = visitor(item, path6);
5955
+ function _visit(path7, item, visitor) {
5956
+ let ctrl = visitor(item, path7);
5954
5957
  if (typeof ctrl === "symbol")
5955
5958
  return ctrl;
5956
5959
  for (const field of ["key", "value"]) {
5957
5960
  const token = item[field];
5958
5961
  if (token && "items" in token) {
5959
5962
  for (let i = 0; i < token.items.length; ++i) {
5960
- const ci = _visit(Object.freeze(path6.concat([[field, i]])), token.items[i], visitor);
5963
+ const ci = _visit(Object.freeze(path7.concat([[field, i]])), token.items[i], visitor);
5961
5964
  if (typeof ci === "number")
5962
5965
  i = ci - 1;
5963
5966
  else if (ci === BREAK)
@@ -5968,10 +5971,10 @@ var require_cst_visit = __commonJS({
5968
5971
  }
5969
5972
  }
5970
5973
  if (typeof ctrl === "function" && field === "key")
5971
- ctrl = ctrl(item, path6);
5974
+ ctrl = ctrl(item, path7);
5972
5975
  }
5973
5976
  }
5974
- return typeof ctrl === "function" ? ctrl(item, path6) : ctrl;
5977
+ return typeof ctrl === "function" ? ctrl(item, path7) : ctrl;
5975
5978
  }
5976
5979
  exports.visit = visit;
5977
5980
  }
@@ -7072,18 +7075,18 @@ var require_parser = __commonJS({
7072
7075
  if (this.type === "map-value-ind") {
7073
7076
  const prev = getPrevProps(this.peek(2));
7074
7077
  const start = getFirstKeyStartProps(prev);
7075
- let sep;
7078
+ let sep2;
7076
7079
  if (scalar.end) {
7077
- sep = scalar.end;
7078
- sep.push(this.sourceToken);
7080
+ sep2 = scalar.end;
7081
+ sep2.push(this.sourceToken);
7079
7082
  delete scalar.end;
7080
7083
  } else
7081
- sep = [this.sourceToken];
7084
+ sep2 = [this.sourceToken];
7082
7085
  const map = {
7083
7086
  type: "block-map",
7084
7087
  offset: scalar.offset,
7085
7088
  indent: scalar.indent,
7086
- items: [{ start, key: scalar, sep }]
7089
+ items: [{ start, key: scalar, sep: sep2 }]
7087
7090
  };
7088
7091
  this.onKeyLine = true;
7089
7092
  this.stack[this.stack.length - 1] = map;
@@ -7236,15 +7239,15 @@ var require_parser = __commonJS({
7236
7239
  } else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
7237
7240
  const start2 = getFirstKeyStartProps(it.start);
7238
7241
  const key = it.key;
7239
- const sep = it.sep;
7240
- sep.push(this.sourceToken);
7242
+ const sep2 = it.sep;
7243
+ sep2.push(this.sourceToken);
7241
7244
  delete it.key;
7242
7245
  delete it.sep;
7243
7246
  this.stack.push({
7244
7247
  type: "block-map",
7245
7248
  offset: this.offset,
7246
7249
  indent: this.indent,
7247
- items: [{ start: start2, key, sep }]
7250
+ items: [{ start: start2, key, sep: sep2 }]
7248
7251
  });
7249
7252
  } else if (start.length > 0) {
7250
7253
  it.sep = it.sep.concat(start, this.sourceToken);
@@ -7438,13 +7441,13 @@ var require_parser = __commonJS({
7438
7441
  const prev = getPrevProps(parent);
7439
7442
  const start = getFirstKeyStartProps(prev);
7440
7443
  fixFlowSeqItems(fc);
7441
- const sep = fc.end.splice(1, fc.end.length);
7442
- sep.push(this.sourceToken);
7444
+ const sep2 = fc.end.splice(1, fc.end.length);
7445
+ sep2.push(this.sourceToken);
7443
7446
  const map = {
7444
7447
  type: "block-map",
7445
7448
  offset: fc.offset,
7446
7449
  indent: fc.indent,
7447
- items: [{ start, key: fc, sep }]
7450
+ items: [{ start, key: fc, sep: sep2 }]
7448
7451
  };
7449
7452
  this.onKeyLine = true;
7450
7453
  this.stack[this.stack.length - 1] = map;
@@ -9826,11 +9829,11 @@ var require_baseGet = __commonJS({
9826
9829
  "use strict";
9827
9830
  var castPath = require_castPath();
9828
9831
  var toKey = require_toKey();
9829
- function baseGet(object, path6) {
9830
- path6 = castPath(path6, object);
9831
- var index = 0, length = path6.length;
9832
+ function baseGet(object, path7) {
9833
+ path7 = castPath(path7, object);
9834
+ var index = 0, length = path7.length;
9832
9835
  while (object != null && index < length) {
9833
- object = object[toKey(path6[index++])];
9836
+ object = object[toKey(path7[index++])];
9834
9837
  }
9835
9838
  return index && index == length ? object : void 0;
9836
9839
  }
@@ -9843,8 +9846,8 @@ var require_get = __commonJS({
9843
9846
  "node_modules/lodash/get.js"(exports, module) {
9844
9847
  "use strict";
9845
9848
  var baseGet = require_baseGet();
9846
- function get2(object, path6, defaultValue) {
9847
- var result = object == null ? void 0 : baseGet(object, path6);
9849
+ function get2(object, path7, defaultValue) {
9850
+ var result = object == null ? void 0 : baseGet(object, path7);
9848
9851
  return result === void 0 ? defaultValue : result;
9849
9852
  }
9850
9853
  module.exports = get2;
@@ -21774,13 +21777,62 @@ var require_lib2 = __commonJS({
21774
21777
  }
21775
21778
  });
21776
21779
 
21780
+ // scripts/lib/heyspex-home.mjs
21781
+ import { homedir as homedir3 } from "node:os";
21782
+ var init_heyspex_home = __esm({
21783
+ "scripts/lib/heyspex-home.mjs"() {
21784
+ "use strict";
21785
+ }
21786
+ });
21787
+
21788
+ // vendor/heyspex-mcp/credentials.mjs
21789
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync4, writeFileSync as writeFileSync4 } from "node:fs";
21790
+ import os, { homedir as homedir4 } from "node:os";
21791
+ import { dirname, join as join5, resolve as resolve2 } from "node:path";
21792
+ var init_credentials = __esm({
21793
+ "vendor/heyspex-mcp/credentials.mjs"() {
21794
+ "use strict";
21795
+ init_heyspex_home();
21796
+ }
21797
+ });
21798
+
21799
+ // scripts/lib/dev-mode.mjs
21800
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
21801
+ import { homedir as homedir5 } from "node:os";
21802
+ import { join as join6 } from "node:path";
21803
+ var init_dev_mode = __esm({
21804
+ "scripts/lib/dev-mode.mjs"() {
21805
+ "use strict";
21806
+ init_heyspex_home();
21807
+ init_credentials();
21808
+ }
21809
+ });
21810
+
21777
21811
  // spex-console/bin/hs-env.ts
21778
21812
  import { spawn } from "node:child_process";
21779
- import { existsSync as existsSync6 } from "node:fs";
21813
+ import { existsSync as existsSync10 } from "node:fs";
21780
21814
  import { networkInterfaces } from "node:os";
21781
- import path5 from "node:path";
21782
- import process2 from "node:process";
21783
- import { fileURLToPath } from "node:url";
21815
+ import path6 from "node:path";
21816
+ import process3 from "node:process";
21817
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
21818
+
21819
+ // scripts/lib/shared-path-helpers.mjs
21820
+ import { isAbsolute, resolve, sep } from "node:path";
21821
+ function resolveCodeRoot({
21822
+ explicit,
21823
+ packageRoot,
21824
+ vaultRoot,
21825
+ env = process.env
21826
+ } = {}) {
21827
+ const fromExplicit = typeof explicit === "string" ? explicit.trim() : "";
21828
+ if (fromExplicit) return fromExplicit;
21829
+ const fromEnv = typeof env?.HS_PKG_ROOT === "string" ? env.HS_PKG_ROOT.trim() : "";
21830
+ if (fromEnv) return fromEnv;
21831
+ const fromPackage = typeof packageRoot === "string" ? packageRoot.trim() : "";
21832
+ if (fromPackage) return fromPackage;
21833
+ const fromVault = typeof vaultRoot === "string" ? vaultRoot.trim() : "";
21834
+ return fromVault;
21835
+ }
21784
21836
 
21785
21837
  // spex-console/src/lib/env-vault/audit.ts
21786
21838
  import { appendFileSync } from "node:fs";
@@ -24685,20 +24737,20 @@ async function doRun(args, deps) {
24685
24737
  }
24686
24738
  const spawnCommand = useShell ? [quoteProgramForCmd(command), ...rest.map(quoteForCmd)].join(" ") : command;
24687
24739
  const spawnArgs = useShell ? [] : rest;
24688
- return await new Promise((resolve) => {
24740
+ return await new Promise((resolve5) => {
24689
24741
  const child = deps.spawn(spawnCommand, spawnArgs, {
24690
24742
  stdio: "inherit",
24691
24743
  env: { ...deps.env, ...decrypted },
24692
24744
  ...useShell ? { shell: true } : {}
24693
24745
  });
24694
24746
  child.on("error", (err) => {
24695
- resolve({
24747
+ resolve5({
24696
24748
  code: EXIT.RUNTIME,
24697
24749
  message: `hs env run: failed to spawn ${command}: ${err.message}`
24698
24750
  });
24699
24751
  });
24700
24752
  child.on("exit", (code, signal) => {
24701
- resolve({ code: signal ? EXIT.RUNTIME : code ?? EXIT.OK });
24753
+ resolve5({ code: signal ? EXIT.RUNTIME : code ?? EXIT.OK });
24702
24754
  });
24703
24755
  });
24704
24756
  }
@@ -25990,12 +26042,12 @@ async function runVerifyStep(command, deps) {
25990
26042
  });
25991
26043
  if (resolved.kind === "empty") return { code: EXIT.OK };
25992
26044
  if (resolved.kind === "unsafe") return { code: EXIT.RUNTIME, error: resolved.reason };
25993
- return await new Promise((resolve) => {
26045
+ return await new Promise((resolve5) => {
25994
26046
  let settled = false;
25995
26047
  const done = (r) => {
25996
26048
  if (!settled) {
25997
26049
  settled = true;
25998
- resolve(r);
26050
+ resolve5(r);
25999
26051
  }
26000
26052
  };
26001
26053
  const child = deps.spawn(resolved.command, resolved.args, {
@@ -26247,17 +26299,17 @@ import { spawnSync as spawnSync2 } from "node:child_process";
26247
26299
  import { randomBytes as randomBytes5 } from "node:crypto";
26248
26300
  import {
26249
26301
  chmodSync,
26250
- existsSync as existsSync5,
26251
- mkdirSync as mkdirSync4,
26252
- readdirSync,
26253
- readFileSync as readFileSync6,
26254
- renameSync as renameSync4,
26302
+ existsSync as existsSync9,
26303
+ mkdirSync as mkdirSync8,
26304
+ readdirSync as readdirSync2,
26305
+ readFileSync as readFileSync12,
26306
+ renameSync as renameSync7,
26255
26307
  statSync as statSync3,
26256
26308
  unlinkSync as unlinkSync3,
26257
- writeFileSync as writeFileSync4
26309
+ writeFileSync as writeFileSync8
26258
26310
  } from "node:fs";
26259
- import { homedir as homedir5 } from "node:os";
26260
- import path4 from "node:path";
26311
+ import { homedir as homedir11 } from "node:os";
26312
+ import path5 from "node:path";
26261
26313
 
26262
26314
  // node_modules/sops-age/dist/index.js
26263
26315
  var import_dotenv = __toESM(require_main(), 1);
@@ -26741,8 +26793,8 @@ function getErrorMap() {
26741
26793
 
26742
26794
  // node_modules/zod/v3/helpers/parseUtil.js
26743
26795
  var makeIssue = (params) => {
26744
- const { data, path: path6, errorMaps, issueData } = params;
26745
- const fullPath = [...path6, ...issueData.path || []];
26796
+ const { data, path: path7, errorMaps, issueData } = params;
26797
+ const fullPath = [...path7, ...issueData.path || []];
26746
26798
  const fullIssue = {
26747
26799
  ...issueData,
26748
26800
  path: fullPath
@@ -26858,11 +26910,11 @@ var errorUtil;
26858
26910
 
26859
26911
  // node_modules/zod/v3/types.js
26860
26912
  var ParseInputLazyPath = class {
26861
- constructor(parent, value, path6, key) {
26913
+ constructor(parent, value, path7, key) {
26862
26914
  this._cachedPath = [];
26863
26915
  this.parent = parent;
26864
26916
  this.data = value;
26865
- this._path = path6;
26917
+ this._path = path7;
26866
26918
  this._key = key;
26867
26919
  }
26868
26920
  get path() {
@@ -34931,18 +34983,18 @@ import { homedir as homedir2, platform } from "node:os";
34931
34983
  import { exec } from "node:child_process";
34932
34984
  import { promisify } from "node:util";
34933
34985
  var import_sshpk = __toESM(require_lib2(), 1);
34934
- async function loadFromFile(path6) {
34986
+ async function loadFromFile(path7) {
34935
34987
  if (globalThis.Deno) {
34936
- return Deno.readTextFile(path6);
34988
+ return Deno.readTextFile(path7);
34937
34989
  }
34938
34990
  if (globalThis.Bun) {
34939
- return Bun.file(path6).text();
34991
+ return Bun.file(path7).text();
34940
34992
  }
34941
34993
  if (typeof process !== "undefined" && process.versions?.node) {
34942
34994
  const fs = await import("fs/promises");
34943
- return fs.readFile(path6, "utf-8");
34995
+ return fs.readFile(path7, "utf-8");
34944
34996
  }
34945
- throw new Error(`Unable to determine method to load file "${path6}"`);
34997
+ throw new Error(`Unable to determine method to load file "${path7}"`);
34946
34998
  }
34947
34999
  function isSopsInput(value) {
34948
35000
  if (!value) {
@@ -35050,13 +35102,13 @@ async function parseSops(input, sopsFileType) {
35050
35102
  });
35051
35103
  }
35052
35104
  }
35053
- async function loadSopsFile(path6, sopsFileType) {
35105
+ async function loadSopsFile(path7, sopsFileType) {
35054
35106
  try {
35055
- const content = await loadFromFile(path6);
35107
+ const content = await loadFromFile(path7);
35056
35108
  return await parseSops(content, sopsFileType);
35057
35109
  } catch (err) {
35058
35110
  throw new Error(
35059
- `Failed to load SOPS file '${path6}': ${err.message}`,
35111
+ `Failed to load SOPS file '${path7}': ${err.message}`,
35060
35112
  {
35061
35113
  cause: err
35062
35114
  }
@@ -35473,15 +35525,15 @@ async function getSopsEncryptionKey(sops, secretKeys) {
35473
35525
  ${errors.join("\n")}`
35474
35526
  );
35475
35527
  }
35476
- function path2gopath(path6) {
35477
- return `${path6.filter((x) => !/^\d+$/.test(x)).join(":")}:`;
35528
+ function path2gopath(path7) {
35529
+ return `${path7.filter((x) => !/^\d+$/.test(x)).join(":")}:`;
35478
35530
  }
35479
- function decryptSOPSValue(ciphertext, decryptionKey, path6) {
35531
+ function decryptSOPSValue(ciphertext, decryptionKey, path7) {
35480
35532
  if (!ciphertext) {
35481
35533
  return "";
35482
35534
  }
35483
35535
  const encryptedValue = parse(ciphertext);
35484
- const aad = path2gopath(path6);
35536
+ const aad = path2gopath(path7);
35485
35537
  let decrypted;
35486
35538
  try {
35487
35539
  decrypted = decryptAesGcm(
@@ -35491,22 +35543,22 @@ function decryptSOPSValue(ciphertext, decryptionKey, path6) {
35491
35543
  );
35492
35544
  } catch (err) {
35493
35545
  throw new Error(
35494
- `AES-GCM decryption failed at path ${JSON.stringify(path6)} for value "${ciphertext}": ${err instanceof Error ? err.message : String(err)}`
35546
+ `AES-GCM decryption failed at path ${JSON.stringify(path7)} for value "${ciphertext}": ${err instanceof Error ? err.message : String(err)}`
35495
35547
  );
35496
35548
  }
35497
35549
  const decryptedValue = new TextDecoder().decode(decrypted);
35498
35550
  return convertDecryptedValue(decryptedValue, encryptedValue.datatype);
35499
35551
  }
35500
- function decryptObject(obj, decryptionKey, path6 = []) {
35552
+ function decryptObject(obj, decryptionKey, path7 = []) {
35501
35553
  if (typeof obj !== "object" || obj === null) {
35502
35554
  return obj;
35503
35555
  }
35504
35556
  for (const key of Object.keys(obj)) {
35505
35557
  const value = obj[key];
35506
35558
  if (typeof value === "string" && value.startsWith("ENC[AES256_GCM,data:")) {
35507
- obj[key] = decryptSOPSValue(value, decryptionKey, [...path6, key]);
35559
+ obj[key] = decryptSOPSValue(value, decryptionKey, [...path7, key]);
35508
35560
  } else if (typeof value === "object") {
35509
- obj[key] = decryptObject(value, decryptionKey, [...path6, key]);
35561
+ obj[key] = decryptObject(value, decryptionKey, [...path7, key]);
35510
35562
  }
35511
35563
  }
35512
35564
  return obj;
@@ -35578,69 +35630,90 @@ async function decryptSops(inputOrOptions, options) {
35578
35630
  import { randomUUID } from "node:crypto";
35579
35631
 
35580
35632
  // scripts/lib/console-url-resolver.mjs
35581
- import { readFileSync as readFileSync4 } from "node:fs";
35582
- import { homedir as homedir3 } from "node:os";
35583
- import { join as join5 } from "node:path";
35584
- var DEFAULT_CONSOLE_URL = "https://app.heyspex.com";
35585
- function trimTrailingSlash(url) {
35586
- return url.replace(/\/+$/, "");
35587
- }
35588
- function readCredentialsConsoleUrl({ homeDir = homedir3() } = {}) {
35633
+ init_heyspex_home();
35634
+ init_dev_mode();
35635
+ import { readFileSync as readFileSync6 } from "node:fs";
35636
+ import { homedir as homedir6 } from "node:os";
35637
+ import { join as join7 } from "node:path";
35638
+
35639
+ // spex-console/src/lib/cli/control-shared.ts
35640
+ import path4 from "node:path";
35641
+
35642
+ // scripts/lib/hs-command.mjs
35643
+ import { existsSync as existsSync5 } from "node:fs";
35644
+ import { delimiter, dirname as dirname2, join as join8 } from "node:path";
35645
+ import { fileURLToPath } from "node:url";
35646
+ var HS_BIN_NAME = "hs";
35647
+ var HS_DISPATCHER_PATH = (() => {
35589
35648
  try {
35590
- const raw = readFileSync4(join5(homeDir, ".heyspex", "credentials.yaml"), "utf8");
35591
- const match = raw.match(/^console_url:\s*["']?([^"'\r\n#]+)/m);
35592
- const value = match?.[1]?.trim();
35593
- return value && value.length > 0 ? trimTrailingSlash(value) : null;
35649
+ const here = dirname2(fileURLToPath(import.meta.url));
35650
+ return join8(dirname2(dirname2(here)), "bin", "hs.mjs");
35594
35651
  } catch {
35595
35652
  return null;
35596
35653
  }
35597
- }
35598
- function readDiscoveryFileConsoleUrl(repoRoot) {
35599
- if (!repoRoot) return null;
35600
- for (const name of [
35601
- "console-url",
35602
- "cockpit-url"
35603
- /* legacy-cockpit */
35604
- ]) {
35605
- try {
35606
- const discovery = readFileSync4(join5(repoRoot, ".heyspex", name), "utf8").trim();
35607
- if (discovery.length > 0) return trimTrailingSlash(discovery);
35608
- } catch {
35609
- }
35610
- }
35611
- return null;
35612
- }
35613
- var ConsoleUrlUnresolvedError = class extends Error {
35614
- constructor() {
35615
- super(
35616
- `resolveConsoleUrl: no HEYSPEX_CONSOLE_URL/HEYSPEX_COCKPIT_URL env, no console_url: in ~/.heyspex/credentials.yaml, and no .heyspex/console-url discovery file \u2014 refusing to silently fall back to the ${DEFAULT_CONSOLE_URL} default in strict mode.`
35617
- );
35618
- this.name = "ConsoleUrlUnresolvedError";
35619
- }
35620
- };
35621
- function resolveConsoleUrl({
35622
- repoRoot,
35623
- env = process.env,
35624
- homeDir = homedir3(),
35625
- strict = false
35626
- } = {}) {
35627
- const envUrl = (env.HEYSPEX_CONSOLE_URL ?? env.HEYSPEX_COCKPIT_URL)?.trim();
35628
- if (envUrl) return trimTrailingSlash(envUrl);
35629
- const credentialsUrl = readCredentialsConsoleUrl({ homeDir });
35630
- if (credentialsUrl) return credentialsUrl;
35631
- const discoveryUrl = readDiscoveryFileConsoleUrl(repoRoot);
35632
- if (discoveryUrl) return discoveryUrl;
35633
- if (strict) throw new ConsoleUrlUnresolvedError();
35634
- return DEFAULT_CONSOLE_URL;
35635
- }
35654
+ })();
35655
+ function shellQuote(p) {
35656
+ return /[\\\s]/.test(p) ? `"${p}"` : p;
35657
+ }
35658
+ var HS_DISPATCHER_PREFIX = HS_DISPATCHER_PATH ? `node ${shellQuote(HS_DISPATCHER_PATH)}` : HS_BIN_NAME;
35659
+
35660
+ // vendor/heyspex-mcp/console-fetch.mjs
35661
+ init_heyspex_home();
35662
+ init_credentials();
35663
+ import { readFileSync as readFileSync10 } from "node:fs";
35664
+ import { homedir as homedir9 } from "node:os";
35665
+ import { join as join12 } from "node:path";
35666
+
35667
+ // vendor/heyspex-mcp/session-owner.mjs
35668
+ init_heyspex_home();
35669
+ init_credentials();
35670
+ import { readFileSync as readFileSync7 } from "node:fs";
35671
+ import { homedir as homedir7 } from "node:os";
35672
+ import { join as join9 } from "node:path";
35673
+
35674
+ // vendor/heyspex-mcp/vault-less-endpoints.mjs
35675
+ var VAULT_LESS_ENDPOINTS = Object.freeze([
35676
+ "* /api/mcp/session",
35677
+ "* /api/mcp/pairing-codes",
35678
+ "POST /api/vaults",
35679
+ "GET /api/vaults",
35680
+ "POST /api/workspaces",
35681
+ "GET /api/workspaces",
35682
+ "* /api/admin/dev-mode"
35683
+ ]);
35684
+
35685
+ // vendor/heyspex-mcp/write-outbox.mjs
35686
+ import {
35687
+ readdirSync,
35688
+ readFileSync as readFileSync8,
35689
+ writeFileSync as writeFileSync6,
35690
+ mkdirSync as mkdirSync6,
35691
+ existsSync as existsSync6,
35692
+ renameSync as renameSync5,
35693
+ rmSync
35694
+ } from "node:fs";
35695
+ import { basename, join as join10, isAbsolute as isAbsolute2 } from "node:path";
35696
+
35697
+ // vendor/heyspex-mcp/vault-resolve.mjs
35698
+ init_heyspex_home();
35699
+ import { existsSync as existsSync7, readFileSync as readFileSync9 } from "node:fs";
35700
+ import { homedir as homedir8, tmpdir } from "node:os";
35701
+ import { dirname as dirname3, join as join11, resolve as resolve3 } from "node:path";
35702
+
35703
+ // vendor/heyspex-mcp/console-fetch.mjs
35704
+ var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMATCH", "VAULT_NOT_REGISTERED"]);
35636
35705
 
35637
35706
  // spex-console/src/lib/cli/control-shared.ts
35638
- import { readFileSync as readFileSync5 } from "node:fs";
35639
- import { homedir as homedir4 } from "node:os";
35640
- import { join as join6 } from "node:path";
35707
+ init_credentials();
35708
+
35709
+ // spex-console/src/lib/vault-registry/registry-file.ts
35710
+ import { existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync6, writeFileSync as writeFileSync7 } from "node:fs";
35711
+ import { dirname as dirname4, join as join13, resolve as resolve4 } from "node:path";
35712
+
35713
+ // spex-console/src/lib/heyspex-home.ts
35714
+ import { homedir as homedir10 } from "node:os";
35641
35715
 
35642
35716
  // spex-console/src/lib/cli/init.ts
35643
- var DEFAULT_CONSOLE_URL2 = resolveConsoleUrl();
35644
35717
  function parseVaultId(content) {
35645
35718
  const m = content.match(/^vault_id:\s*(.+?)\s*$/m);
35646
35719
  if (!m) return null;
@@ -35652,27 +35725,38 @@ var HELP2 = [
35652
35725
  "Usage:",
35653
35726
  " hs init [--console-url <url>] [--vault-root <path>] [--force] [--json]",
35654
35727
  " hs init --customer-vault <dir> [--console-url <url>] [--principles <all|none|a,b>]",
35655
- " [--vault-name <name>] [--no-git] [--json]",
35728
+ " [--vault-name <name>] [--git] [--json]",
35656
35729
  "",
35657
35730
  "Write the top-level heyspex.yaml vault marker (schema_version, console_url,",
35658
- "vault_root, vault_id) \u2014 the committed file the console / web companion read",
35731
+ "vault_root, vault_id; `hs connect` also records `account:`, the account id the",
35732
+ "repo was connected under) \u2014 the committed file the console / web companion read",
35659
35733
  "to bootstrap a vault. Idempotent: an existing marker is left untouched unless",
35660
35734
  "--force, EXCEPT a missing vault_id is backfilled in place either way (backward",
35661
35735
  "compatible \u2014 no schema_version bump). vault_id is reused exactly when already",
35662
35736
  "present; a fresh one is minted only when absent.",
35663
- "Does not modify .heyspex/config.yaml or its templates (ADR-0009).",
35737
+ "Also scaffolds the vault_root folder and seeds .heyspex/config.yaml (the",
35738
+ "HeySpex workflow settings, ADR-0009) from the shipped template",
35739
+ "(vendor/heyspex-mcp/config-seed.yaml) when that file is absent. An existing",
35740
+ ".heyspex/config.yaml is never rewritten \u2014 not even with --force; change its",
35741
+ "values with `hs settings set <key> <value>`.",
35664
35742
  "",
35665
35743
  "--customer-vault <dir> scaffolds a REAL customer vault at <dir> instead: the",
35666
- "specs/ folder tree, heyspex.yaml, and every row of the template shipping",
35667
- "manifest (spex-console/src/lib/cli/template-manifest.ts) \u2014 universal docs",
35744
+ "specs/ folder tree, heyspex.yaml, the seeded .heyspex/config.yaml, and every",
35745
+ "row of the template shipping manifest",
35746
+ "(spex-console/src/lib/cli/template-manifest.ts) \u2014 universal docs",
35668
35747
  "copied verbatim, template-shape docs written as author-prompt skeletons \u2014",
35669
- "plus a generated CLAUDE.md, the kept-principles index, and (unless --no-git)",
35670
- "one initial `git init` + commit pinning the template version. Refuses a",
35671
- "non-empty <dir> with a plain error. See init.customer-vault.ts.",
35748
+ "plus a generated CLAUDE.md, the kept-principles index, and the template_version",
35749
+ "pin; with --git, one initial `git init` + commit. Rerunnable: a <dir> that already",
35750
+ "holds heyspex.yaml and an empty/placeholder-only specs/ is accepted, existing",
35751
+ "files are never overwritten (an existing CLAUDE.md gets a CLAUDE.md.template",
35752
+ "beside it), and the result lists each manifest row as created or kept. Refuses a",
35753
+ "non-empty <dir> without heyspex.yaml, or a specs/ holding managed specs.",
35754
+ "See init.customer-vault.ts.",
35672
35755
  "",
35673
35756
  "Flags:",
35674
- " --console-url <url> console_url value (default: $HEYSPEX_CONSOLE_URL or",
35675
- " https://console.heyspex.local).",
35757
+ " --console-url <url> console_url value (default: the mode-aware console --",
35758
+ " $HEYSPEX_CONSOLE_URL, else the signed-in console, else",
35759
+ " https://app.heyspex.com in prod mode).",
35676
35760
  " --vault-root <path> vault_root value (default: specs/).",
35677
35761
  " --customer-vault <dir> Scaffold a new customer vault at <dir> (see above).",
35678
35762
  " --principles <all|none|a,b> Which universal principle docs to ship",
@@ -35680,8 +35764,9 @@ var HELP2 = [
35680
35764
  " keep/skip prompt per principle. Omitted + no TTY: all.",
35681
35765
  " --vault-name <name> Display name for the scaffolded vault (--customer-vault",
35682
35766
  " only; default: <dir>'s basename).",
35683
- " --no-git Skip git init + the initial commit (--customer-vault only).",
35684
- " --force Overwrite an existing heyspex.yaml.",
35767
+ " --git Also run git init + one initial commit (--customer-vault only;",
35768
+ " default: no git). --no-git is accepted as a no-op.",
35769
+ " --force Overwrite an existing heyspex.yaml (never .heyspex/config.yaml).",
35685
35770
  " --json Emit a machine-readable JSON result.",
35686
35771
  " --help, -h Show this help.",
35687
35772
  "",
@@ -35697,8 +35782,11 @@ function scopedProfileName(profileName, vaultId) {
35697
35782
  const short = vaultId.replace(/[^A-Za-z0-9]/g, "").slice(0, 8).toUpperCase();
35698
35783
  return short.length === 0 ? profileName : `${profileName}__V${short}`;
35699
35784
  }
35785
+ function sanitizedProfileToken(profileName) {
35786
+ return profileName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
35787
+ }
35700
35788
  function keysEnvVarName(profileName) {
35701
- return ENV_VAR_PREFIX + profileName.toUpperCase();
35789
+ return ENV_VAR_PREFIX + sanitizedProfileToken(profileName);
35702
35790
  }
35703
35791
  function looksLikePrivateKey(value) {
35704
35792
  if (typeof value !== "string") return false;
@@ -35736,7 +35824,7 @@ function upsertKeysLine(contentOrNull, profileName, privateKey, vaultId) {
35736
35824
  const matchesProfile = (raw) => {
35737
35825
  const bare = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
35738
35826
  const m = KEYS_LINE.exec(bare);
35739
- return m !== null && m[1].toUpperCase() === effective.toUpperCase();
35827
+ return m !== null && m[1].toUpperCase() === sanitizedProfileToken(effective);
35740
35828
  };
35741
35829
  const lines = [];
35742
35830
  let replaced = false;
@@ -35758,7 +35846,7 @@ function upsertKeysLine(contentOrNull, profileName, privateKey, vaultId) {
35758
35846
  }
35759
35847
  function existingKeyInSlot(contentOrNull, profileName, vaultId) {
35760
35848
  const effective = scopedProfileName(profileName, vaultId);
35761
- return parseKeysFile(contentOrNull ?? "")[effective.toLowerCase()] ?? null;
35849
+ return parseKeysFile(contentOrNull ?? "")[sanitizedProfileToken(effective).toLowerCase()] ?? null;
35762
35850
  }
35763
35851
  function dateStamp(when) {
35764
35852
  return when.toISOString().slice(0, 10).replace(/-/g, "");
@@ -35820,7 +35908,7 @@ function resolvePrivateKey(args) {
35820
35908
  if (!source.content) continue;
35821
35909
  const parsed = parseKeysFile(source.content);
35822
35910
  for (const candidate of candidateProfileNames(args)) {
35823
- const fromFile = parsed[candidate.toLowerCase()];
35911
+ const fromFile = parsed[sanitizedProfileToken(candidate).toLowerCase()];
35824
35912
  if (!fromFile) continue;
35825
35913
  if (!looksLikePrivateKey(fromFile)) {
35826
35914
  throw new EnvVaultConfigError(
@@ -35969,23 +36057,23 @@ function isExpiredDate(expires, today = todayIso()) {
35969
36057
  return expires !== null && today > expires;
35970
36058
  }
35971
36059
  function envDir(vaultRoot) {
35972
- return path4.join(vaultRoot, ".heyspex", "env");
36060
+ return path5.join(vaultRoot, ".heyspex", "env");
35973
36061
  }
35974
36062
  function profilePath(vaultRoot, name) {
35975
- return path4.join(envDir(vaultRoot), `${name}.env`);
36063
+ return path5.join(envDir(vaultRoot), `${name}.env`);
35976
36064
  }
35977
36065
  function keysPath(vaultRoot) {
35978
- return path4.join(vaultRoot, ".heyspex", "env.keys");
36066
+ return path5.join(vaultRoot, ".heyspex", "env.keys");
35979
36067
  }
35980
36068
  function homeKeysPath() {
35981
- return path4.join(process.env.HEYSPEX_ENV_KEYS_HOME || homedir5(), ".heyspex", "env.keys");
36069
+ return path5.join(process.env.HEYSPEX_ENV_KEYS_HOME || homedir11(), ".heyspex", "env.keys");
35982
36070
  }
35983
36071
  function dotenvPath(vaultRoot) {
35984
- return path4.join(vaultRoot, ".env");
36072
+ return path5.join(vaultRoot, ".env");
35985
36073
  }
35986
36074
  function readOrNull(file) {
35987
36075
  try {
35988
- return readFileSync6(file, "utf-8");
36076
+ return readFileSync12(file, "utf-8");
35989
36077
  } catch {
35990
36078
  return null;
35991
36079
  }
@@ -35999,7 +36087,7 @@ function renameWithRetry(tmp, file) {
35999
36087
  const retryable = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES"]);
36000
36088
  for (let attempt = 0; ; attempt++) {
36001
36089
  try {
36002
- renameSync4(tmp, file);
36090
+ renameSync7(tmp, file);
36003
36091
  return;
36004
36092
  } catch (err) {
36005
36093
  const code = err.code ?? "";
@@ -36016,15 +36104,15 @@ function unlinkQuiet(file) {
36016
36104
  }
36017
36105
  function atomicWrite(file, content, mode = 420) {
36018
36106
  const secret = mode === SECRET_MODE;
36019
- const dir = path4.dirname(file);
36020
- mkdirSync4(dir, { recursive: true, ...secret ? { mode: SECRET_DIR_MODE } : {} });
36021
- const tmp = path4.join(
36107
+ const dir = path5.dirname(file);
36108
+ mkdirSync8(dir, { recursive: true, ...secret ? { mode: SECRET_DIR_MODE } : {} });
36109
+ const tmp = path5.join(
36022
36110
  dir,
36023
- `.${path4.basename(file)}.${process.pid}.${randomBytes5(4).toString("hex")}.tmp`
36111
+ `.${path5.basename(file)}.${process.pid}.${randomBytes5(4).toString("hex")}.tmp`
36024
36112
  );
36025
36113
  let renamed = false;
36026
36114
  try {
36027
- writeFileSync4(tmp, content, { encoding: "utf-8", mode });
36115
+ writeFileSync8(tmp, content, { encoding: "utf-8", mode });
36028
36116
  if (secret) chmodOwnerOnly(tmp);
36029
36117
  renameWithRetry(tmp, file);
36030
36118
  renamed = true;
@@ -36038,11 +36126,11 @@ var LOCK_RETRY_MS3 = 50;
36038
36126
  var LOCK_STALE_MS3 = 5e3;
36039
36127
  function withFileLock(file, fn) {
36040
36128
  const lock = `${file}.lock`;
36041
- mkdirSync4(path4.dirname(file), { recursive: true, mode: SECRET_DIR_MODE });
36129
+ mkdirSync8(path5.dirname(file), { recursive: true, mode: SECRET_DIR_MODE });
36042
36130
  let held = false;
36043
36131
  for (let attempt = 0; attempt < LOCK_RETRIES && !held; attempt++) {
36044
36132
  try {
36045
- writeFileSync4(lock, `${process.pid}
36133
+ writeFileSync8(lock, `${process.pid}
36046
36134
  `, { flag: "wx" });
36047
36135
  held = true;
36048
36136
  } catch (err) {
@@ -36091,7 +36179,7 @@ function writeHomeKeyLine(profileName, privateKey, vaultId) {
36091
36179
  }
36092
36180
  function readVaultId(vaultRoot) {
36093
36181
  try {
36094
- const raw = readOrNull(path4.join(vaultRoot, "heyspex.yaml"));
36182
+ const raw = readOrNull(path5.join(vaultRoot, "heyspex.yaml"));
36095
36183
  return raw === null ? null : parseVaultId(raw);
36096
36184
  } catch {
36097
36185
  return null;
@@ -36234,7 +36322,7 @@ function legacyDecryptAllSync(vaultRoot, name) {
36234
36322
  }
36235
36323
  function initProfile(vaultRoot, name = DEFAULT_PROFILE2, opts = {}) {
36236
36324
  const pFile = profilePath(vaultRoot, name);
36237
- if (existsSync5(pFile) && !opts.force) {
36325
+ if (existsSync9(pFile) && !opts.force) {
36238
36326
  throw new EnvVaultConfigError(
36239
36327
  `Env profile "${name}" already exists at ${pFile}. Pass --force to re-key it (this discards existing values and mints a new keypair).`
36240
36328
  );
@@ -36280,7 +36368,7 @@ function listProfiles(vaultRoot) {
36280
36368
  } catch {
36281
36369
  return [];
36282
36370
  }
36283
- return readdirSync(dir).filter((f) => f.endsWith(".env")).map((f) => f.slice(0, -".env".length)).sort();
36371
+ return readdirSync2(dir).filter((f) => f.endsWith(".env")).map((f) => f.slice(0, -".env".length)).sort();
36284
36372
  }
36285
36373
  function listProfilesStatus(vaultRoot) {
36286
36374
  return listProfiles(vaultRoot).map((name) => {
@@ -36620,7 +36708,7 @@ function removeGrant(vaultRoot, profileName, name, opts = {}) {
36620
36708
  }
36621
36709
  async function exportProfile(vaultRoot, name = DEFAULT_PROFILE2, opts = {}) {
36622
36710
  const target = dotenvPath(vaultRoot);
36623
- if (existsSync5(target) && !opts.force) {
36711
+ if (existsSync9(target) && !opts.force) {
36624
36712
  throw new EnvVaultConfigError(
36625
36713
  `${target} already exists. Pass --force to overwrite it (it is disposable \u2014 the encrypted profile is the system of record).`
36626
36714
  );
@@ -36632,10 +36720,10 @@ async function exportProfile(vaultRoot, name = DEFAULT_PROFILE2, opts = {}) {
36632
36720
  return { path: target };
36633
36721
  }
36634
36722
  function resolveVaultPath(vaultRoot, filePath) {
36635
- const root = path4.resolve(vaultRoot);
36636
- const resolved = path4.resolve(root, filePath);
36637
- const rel = path4.relative(root, resolved);
36638
- if (path4.isAbsolute(filePath) || path4.isAbsolute(rel) || rel === ".." || rel.startsWith(`..${path4.sep}`)) {
36723
+ const root = path5.resolve(vaultRoot);
36724
+ const resolved = path5.resolve(root, filePath);
36725
+ const rel = path5.relative(root, resolved);
36726
+ if (path5.isAbsolute(filePath) || path5.isAbsolute(rel) || rel === ".." || rel.startsWith(`..${path5.sep}`)) {
36639
36727
  throw new EnvVaultConfigError(
36640
36728
  `Refusing to touch "${filePath}" \u2014 it resolves outside the vault root (${root}). Vault file paths must stay inside the repo (no "..", no absolute paths).`
36641
36729
  );
@@ -36649,7 +36737,7 @@ function writeTextFile(vaultRoot, filePath, content) {
36649
36737
  atomicWrite(resolveVaultPath(vaultRoot, filePath), content, SECRET_MODE);
36650
36738
  }
36651
36739
  function pathExists(vaultRoot, filePath) {
36652
- return existsSync5(resolveVaultPath(vaultRoot, filePath));
36740
+ return existsSync9(resolveVaultPath(vaultRoot, filePath));
36653
36741
  }
36654
36742
  function fileMtime(vaultRoot, filePath) {
36655
36743
  const resolved = resolveVaultPath(vaultRoot, filePath);
@@ -36676,14 +36764,14 @@ function listRepoSourceFiles(vaultRoot) {
36676
36764
  const walk = (dir, rel) => {
36677
36765
  let entries;
36678
36766
  try {
36679
- entries = readdirSync(dir, { withFileTypes: true });
36767
+ entries = readdirSync2(dir, { withFileTypes: true });
36680
36768
  } catch {
36681
36769
  return;
36682
36770
  }
36683
36771
  for (const entry of entries) {
36684
36772
  const childRel = rel === "" ? entry.name : `${rel}/${entry.name}`;
36685
36773
  if (entry.isDirectory()) {
36686
- if (!WALK_SKIP_DIRS.has(entry.name)) walk(path4.join(dir, entry.name), childRel);
36774
+ if (!WALK_SKIP_DIRS.has(entry.name)) walk(path5.join(dir, entry.name), childRel);
36687
36775
  } else if (entry.isFile()) {
36688
36776
  out.push(childRel);
36689
36777
  }
@@ -36709,7 +36797,7 @@ function isKeysFileGitignored(vaultRoot) {
36709
36797
  if (res.status === 1) return false;
36710
36798
  } catch {
36711
36799
  }
36712
- const gitignore = readOrNull(path4.join(vaultRoot, ".gitignore"));
36800
+ const gitignore = readOrNull(path5.join(vaultRoot, ".gitignore"));
36713
36801
  if (gitignore === null) return false;
36714
36802
  const ignorePatterns = /* @__PURE__ */ new Set([
36715
36803
  ".heyspex/env.keys",
@@ -36739,16 +36827,44 @@ async function httpPostJson(url, body) {
36739
36827
  return { status: res.status, body: parsed };
36740
36828
  }
36741
36829
 
36830
+ // spex-console/bin/run-entry.ts
36831
+ import process2 from "node:process";
36832
+ var BinExit = class extends Error {
36833
+ code;
36834
+ constructor(code) {
36835
+ super(`exit ${code}`);
36836
+ this.name = "BinExit";
36837
+ this.code = code;
36838
+ }
36839
+ };
36840
+ function runEntry(name, main2, options = {}) {
36841
+ const { fallbackCode = 1, unhandledLabel = "unhandled" } = options;
36842
+ void (async () => {
36843
+ try {
36844
+ await main2();
36845
+ } catch (err) {
36846
+ if (err instanceof BinExit) {
36847
+ process2.exitCode = err.code;
36848
+ return;
36849
+ }
36850
+ const message = err instanceof Error ? err.message : String(err);
36851
+ process2.stderr.write(`${name}: ${unhandledLabel}: ${message}
36852
+ `);
36853
+ process2.exitCode = fallbackCode;
36854
+ }
36855
+ })();
36856
+ }
36857
+
36742
36858
  // spex-console/bin/hs-env.ts
36743
36859
  function hsSelfCommand() {
36744
- const here = path5.dirname(fileURLToPath(import.meta.url));
36745
- const pkgRoot = process2.env.HS_PKG_ROOT?.trim();
36860
+ const here = path6.dirname(fileURLToPath2(import.meta.url));
36861
+ const pkgRoot = resolveCodeRoot({});
36746
36862
  const candidates = [
36747
- ...pkgRoot ? [path5.join(pkgRoot, "bin", "hs.mjs")] : [],
36748
- path5.resolve(here, "..", "..", "bin", "hs.mjs")
36863
+ ...pkgRoot ? [path6.join(pkgRoot, "bin", "hs.mjs")] : [],
36864
+ path6.resolve(here, "..", "..", "bin", "hs.mjs")
36749
36865
  ];
36750
- const launcher = candidates.find((c) => existsSync6(c));
36751
- return launcher ? [process2.execPath, launcher] : null;
36866
+ const launcher = candidates.find((c) => existsSync10(c));
36867
+ return launcher ? [process3.execPath, launcher] : null;
36752
36868
  }
36753
36869
  var VIRTUAL_ADAPTER = /nordlynx|tailscale|zerotier|hamachi|wireguard|openvpn|proton|tap-|tun\d|vethernet|\bwsl\b|hyper-v|docker|vmware|virtualbox|vbox|utun|bridge/i;
36754
36870
  function lanCandidates() {
@@ -36773,36 +36889,39 @@ function lanIp() {
36773
36889
  return lanCandidates()[0]?.address ?? null;
36774
36890
  }
36775
36891
  function readStdin() {
36776
- if (process2.stdin.isTTY) {
36777
- const eof = process2.platform === "win32" ? "Ctrl+Z then Enter" : "Ctrl+D";
36778
- process2.stderr.write(`Paste the value, press Enter, then ${eof} to finish (Ctrl+C cancels):
36892
+ if (process3.stdin.isTTY) {
36893
+ const eof = process3.platform === "win32" ? "Ctrl+Z then Enter" : "Ctrl+D";
36894
+ process3.stderr.write(`Paste the value, press Enter, then ${eof} to finish (Ctrl+C cancels):
36779
36895
  `);
36780
36896
  }
36781
- return new Promise((resolve, reject) => {
36897
+ return new Promise((resolve5, reject) => {
36782
36898
  const chunks = [];
36783
- process2.stdin.on("data", (c) => chunks.push(c));
36784
- process2.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
36785
- process2.stdin.on("error", reject);
36899
+ process3.stdin.on("data", (c) => chunks.push(c));
36900
+ process3.stdin.on("end", () => resolve5(Buffer.concat(chunks).toString("utf-8")));
36901
+ process3.stdin.on("error", reject);
36786
36902
  });
36787
36903
  }
36788
36904
  async function main() {
36789
- const vaultRoot = process2.env.HS_VAULT_ROOT;
36905
+ const vaultRoot = process3.env.HS_VAULT_ROOT;
36790
36906
  if (!vaultRoot) {
36791
- process2.stderr.write(
36907
+ process3.stderr.write(
36792
36908
  "hs env: HS_VAULT_ROOT is not set (the dispatcher must resolve and pass it).\n"
36793
36909
  );
36794
- process2.exit(EXIT.USAGE);
36910
+ process3.exitCode = EXIT.USAGE;
36911
+ return;
36795
36912
  }
36796
- const parsed = parseEnvArgs(process2.argv.slice(3));
36913
+ const parsed = parseEnvArgs(process3.argv.slice(3));
36797
36914
  if ("help" in parsed) {
36798
- process2.stdout.write(`${HELP}
36915
+ process3.stdout.write(`${HELP}
36799
36916
  `);
36800
- process2.exit(EXIT.OK);
36917
+ process3.exitCode = EXIT.OK;
36918
+ return;
36801
36919
  }
36802
36920
  if ("error" in parsed) {
36803
- process2.stderr.write(`hs env: ${parsed.error.message}
36921
+ process3.stderr.write(`hs env: ${parsed.error.message}
36804
36922
  `);
36805
- process2.exit(parsed.error.code);
36923
+ process3.exitCode = parsed.error.code;
36924
+ return;
36806
36925
  }
36807
36926
  const result = await runEnv(parsed.args, {
36808
36927
  vaultRoot,
@@ -36817,29 +36936,24 @@ async function main() {
36817
36936
  // `resolveVerifyCommand`) so no manifest text is shell-interpolated.
36818
36937
  ...options.shell === true ? { shell: true } : {}
36819
36938
  }),
36820
- stdout: (s) => process2.stdout.write(s),
36821
- stderr: (s) => process2.stderr.write(s),
36822
- env: process2.env,
36939
+ stdout: (s) => process3.stdout.write(s),
36940
+ stderr: (s) => process3.stderr.write(s),
36941
+ env: process3.env,
36823
36942
  audit: (event) => void appendEnvVaultAudit(vaultRoot, event),
36824
36943
  readStdin,
36825
- sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
36944
+ sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
36826
36945
  httpPostJson,
36827
36946
  pairingConsoleCandidates: defaultPairingConsoleCandidates,
36828
36947
  lanIp,
36829
36948
  lanCandidates,
36830
- platform: process2.platform,
36949
+ platform: process3.platform,
36831
36950
  hsSelfCommand: hsSelfCommand()
36832
36951
  });
36833
36952
  if (result.message) {
36834
- const sink = result.code === EXIT.OK ? process2.stdout : process2.stderr;
36953
+ const sink = result.code === EXIT.OK ? process3.stdout : process3.stderr;
36835
36954
  sink.write(`${result.message}
36836
36955
  `);
36837
36956
  }
36838
- process2.exit(result.code);
36957
+ process3.exitCode = result.code;
36839
36958
  }
36840
- main().catch((err) => {
36841
- const message = err instanceof Error ? err.message : String(err);
36842
- process2.stderr.write(`hs env: unhandled: ${message}
36843
- `);
36844
- process2.exit(EXIT.RUNTIME);
36845
- });
36959
+ runEntry("hs env", main, { fallbackCode: EXIT.RUNTIME });