spexcode 0.6.1 → 0.6.5

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 (480) hide show
  1. package/README.md +99 -149
  2. package/bin/spex.mjs +4 -0
  3. package/node_modules/@spexcode/spec-cli/bin/spex.mjs +76 -0
  4. package/node_modules/@spexcode/spec-cli/dist/attach.d.ts +2 -0
  5. package/node_modules/@spexcode/spec-cli/dist/attach.js +48 -0
  6. package/node_modules/@spexcode/spec-cli/dist/claude-headless.d.ts +33 -0
  7. package/node_modules/@spexcode/spec-cli/dist/claude-headless.js +307 -0
  8. package/node_modules/@spexcode/spec-cli/dist/cli.d.ts +1 -0
  9. package/node_modules/@spexcode/spec-cli/dist/cli.js +1859 -0
  10. package/node_modules/@spexcode/spec-cli/dist/client.d.ts +111 -0
  11. package/node_modules/@spexcode/spec-cli/dist/client.js +476 -0
  12. package/node_modules/@spexcode/spec-cli/dist/cockpit.d.ts +7 -0
  13. package/node_modules/@spexcode/spec-cli/dist/cockpit.js +26 -0
  14. package/node_modules/@spexcode/spec-cli/dist/codex-headless.d.ts +1 -0
  15. package/{spec-cli/src/codex-headless.ts → node_modules/@spexcode/spec-cli/dist/codex-headless.js} +3 -9
  16. package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.d.ts +53 -0
  17. package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.js +686 -0
  18. package/node_modules/@spexcode/spec-cli/dist/commit-surgery.d.ts +1 -0
  19. package/node_modules/@spexcode/spec-cli/dist/commit-surgery.js +90 -0
  20. package/node_modules/@spexcode/spec-cli/dist/contract-filter.d.ts +14 -0
  21. package/node_modules/@spexcode/spec-cli/dist/contract-filter.js +219 -0
  22. package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.d.ts +6 -0
  23. package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.js +50 -0
  24. package/node_modules/@spexcode/spec-cli/dist/delivery-queue.d.ts +23 -0
  25. package/node_modules/@spexcode/spec-cli/dist/delivery-queue.js +179 -0
  26. package/node_modules/@spexcode/spec-cli/dist/doctor.d.ts +9 -0
  27. package/node_modules/@spexcode/spec-cli/dist/doctor.js +547 -0
  28. package/node_modules/@spexcode/spec-cli/dist/eval-host.d.ts +1 -0
  29. package/node_modules/@spexcode/spec-cli/dist/eval-host.js +19 -0
  30. package/node_modules/@spexcode/spec-cli/dist/execution-trace.d.ts +26 -0
  31. package/node_modules/@spexcode/spec-cli/dist/execution-trace.js +475 -0
  32. package/node_modules/@spexcode/spec-cli/dist/file-write.d.ts +2 -0
  33. package/node_modules/@spexcode/spec-cli/dist/file-write.js +26 -0
  34. package/node_modules/@spexcode/spec-cli/dist/flat.d.ts +89 -0
  35. package/node_modules/@spexcode/spec-cli/dist/flat.js +1076 -0
  36. package/node_modules/@spexcode/spec-cli/dist/gateway-auth.d.ts +56 -0
  37. package/node_modules/@spexcode/spec-cli/dist/gateway-auth.js +168 -0
  38. package/node_modules/@spexcode/spec-cli/dist/gateway-hub.d.ts +28 -0
  39. package/node_modules/@spexcode/spec-cli/dist/gateway-hub.js +361 -0
  40. package/node_modules/@spexcode/spec-cli/dist/gateway.d.ts +37 -0
  41. package/node_modules/@spexcode/spec-cli/dist/gateway.js +503 -0
  42. package/node_modules/@spexcode/spec-cli/dist/graphCache.d.ts +27 -0
  43. package/node_modules/@spexcode/spec-cli/dist/graphCache.js +716 -0
  44. package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.d.ts +14 -0
  45. package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.js +35 -0
  46. package/node_modules/@spexcode/spec-cli/dist/graphStream.d.ts +85 -0
  47. package/node_modules/@spexcode/spec-cli/dist/graphStream.js +1195 -0
  48. package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.d.ts +64 -0
  49. package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.js +166 -0
  50. package/node_modules/@spexcode/spec-cli/dist/guide.d.ts +8 -0
  51. package/{spec-cli/src/guide.ts → node_modules/@spexcode/spec-cli/dist/guide.js} +115 -22
  52. package/node_modules/@spexcode/spec-cli/dist/harness-select.d.ts +18 -0
  53. package/node_modules/@spexcode/spec-cli/dist/harness-select.js +62 -0
  54. package/node_modules/@spexcode/spec-cli/dist/harness.d.ts +325 -0
  55. package/node_modules/@spexcode/spec-cli/dist/harness.js +3026 -0
  56. package/node_modules/@spexcode/spec-cli/dist/headless-controller.d.ts +9 -0
  57. package/node_modules/@spexcode/spec-cli/dist/headless-controller.js +47 -0
  58. package/node_modules/@spexcode/spec-cli/dist/help.d.ts +10 -0
  59. package/node_modules/@spexcode/spec-cli/dist/help.js +574 -0
  60. package/node_modules/@spexcode/spec-cli/dist/hook-prompts.d.ts +18 -0
  61. package/node_modules/@spexcode/spec-cli/dist/hook-prompts.js +122 -0
  62. package/node_modules/@spexcode/spec-cli/dist/hooks.d.ts +1 -0
  63. package/{spec-cli/src/hooks.ts → node_modules/@spexcode/spec-cli/dist/hooks.js} +15 -15
  64. package/node_modules/@spexcode/spec-cli/dist/host-resources.d.ts +97 -0
  65. package/node_modules/@spexcode/spec-cli/dist/host-resources.js +795 -0
  66. package/node_modules/@spexcode/spec-cli/dist/host.d.ts +88 -0
  67. package/node_modules/@spexcode/spec-cli/dist/host.js +663 -0
  68. package/node_modules/@spexcode/spec-cli/dist/index.d.ts +1 -0
  69. package/node_modules/@spexcode/spec-cli/dist/index.js +899 -0
  70. package/node_modules/@spexcode/spec-cli/dist/init.d.ts +1 -0
  71. package/node_modules/@spexcode/spec-cli/dist/init.js +284 -0
  72. package/node_modules/@spexcode/spec-cli/dist/issues-cli.d.ts +6 -0
  73. package/node_modules/@spexcode/spec-cli/dist/issues-cli.js +334 -0
  74. package/node_modules/@spexcode/spec-cli/dist/issues.d.ts +69 -0
  75. package/node_modules/@spexcode/spec-cli/dist/issues.js +189 -0
  76. package/node_modules/@spexcode/spec-cli/dist/lint.d.ts +34 -0
  77. package/node_modules/@spexcode/spec-cli/dist/lint.js +476 -0
  78. package/node_modules/@spexcode/spec-cli/dist/listen.d.ts +7 -0
  79. package/{spec-cli/src/listen.ts → node_modules/@spexcode/spec-cli/dist/listen.js} +13 -17
  80. package/node_modules/@spexcode/spec-cli/dist/localIssues.d.ts +65 -0
  81. package/node_modules/@spexcode/spec-cli/dist/localIssues.js +582 -0
  82. package/node_modules/@spexcode/spec-cli/dist/login-page.d.ts +5 -0
  83. package/{spec-cli/src/login-page.ts → node_modules/@spexcode/spec-cli/dist/login-page.js} +7 -7
  84. package/node_modules/@spexcode/spec-cli/dist/loop-in.d.ts +23 -0
  85. package/{spec-cli/src/loop-in.ts → node_modules/@spexcode/spec-cli/dist/loop-in.js} +35 -45
  86. package/node_modules/@spexcode/spec-cli/dist/machine-peer.d.ts +69 -0
  87. package/node_modules/@spexcode/spec-cli/dist/machine-peer.js +603 -0
  88. package/node_modules/@spexcode/spec-cli/dist/materialize.d.ts +18 -0
  89. package/node_modules/@spexcode/spec-cli/dist/materialize.js +468 -0
  90. package/node_modules/@spexcode/spec-cli/dist/mentions.d.ts +50 -0
  91. package/node_modules/@spexcode/spec-cli/dist/mentions.js +117 -0
  92. package/node_modules/@spexcode/spec-cli/dist/opencode-headless.d.ts +4 -0
  93. package/node_modules/@spexcode/spec-cli/dist/opencode-headless.js +208 -0
  94. package/node_modules/@spexcode/spec-cli/dist/opencode.d.ts +3 -0
  95. package/{spec-cli/src/opencode.ts → node_modules/@spexcode/spec-cli/dist/opencode.js} +9 -13
  96. package/node_modules/@spexcode/spec-cli/dist/pi-harness.d.ts +3 -0
  97. package/{spec-cli/src/pi-harness.ts → node_modules/@spexcode/spec-cli/dist/pi-harness.js} +45 -40
  98. package/node_modules/@spexcode/spec-cli/dist/pi-headless.d.ts +25 -0
  99. package/node_modules/@spexcode/spec-cli/dist/pi-headless.js +196 -0
  100. package/node_modules/@spexcode/spec-cli/dist/plugin-harness.d.ts +21 -0
  101. package/node_modules/@spexcode/spec-cli/dist/plugin-harness.js +146 -0
  102. package/node_modules/@spexcode/spec-cli/dist/pty-bridge.d.ts +10 -0
  103. package/node_modules/@spexcode/spec-cli/dist/pty-bridge.js +404 -0
  104. package/node_modules/@spexcode/spec-cli/dist/pty-helper.d.mts +1 -0
  105. package/node_modules/@spexcode/spec-cli/dist/pty-helper.mjs +101 -0
  106. package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.d.mts +2 -0
  107. package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.mjs +23 -0
  108. package/node_modules/@spexcode/spec-cli/dist/public-graph.d.ts +46 -0
  109. package/node_modules/@spexcode/spec-cli/dist/public-graph.js +56 -0
  110. package/node_modules/@spexcode/spec-cli/dist/ranker.d.ts +15 -0
  111. package/node_modules/@spexcode/spec-cli/dist/ranker.js +188 -0
  112. package/node_modules/@spexcode/spec-cli/dist/reaper.d.ts +6 -0
  113. package/node_modules/@spexcode/spec-cli/dist/reaper.js +81 -0
  114. package/node_modules/@spexcode/spec-cli/dist/reviews.d.ts +189 -0
  115. package/node_modules/@spexcode/spec-cli/dist/reviews.js +350 -0
  116. package/node_modules/@spexcode/spec-cli/dist/runtime-guard.d.ts +6 -0
  117. package/node_modules/@spexcode/spec-cli/dist/runtime-guard.js +37 -0
  118. package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.d.ts +21 -0
  119. package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.js +84 -0
  120. package/node_modules/@spexcode/spec-cli/dist/search.bench.d.mts +1 -0
  121. package/node_modules/@spexcode/spec-cli/dist/search.bench.mjs +75 -0
  122. package/node_modules/@spexcode/spec-cli/dist/search.d.ts +20 -0
  123. package/node_modules/@spexcode/spec-cli/dist/search.js +61 -0
  124. package/node_modules/@spexcode/spec-cli/dist/session-cursors.d.ts +14 -0
  125. package/node_modules/@spexcode/spec-cli/dist/session-cursors.js +82 -0
  126. package/node_modules/@spexcode/spec-cli/dist/session-declarations.d.ts +13 -0
  127. package/node_modules/@spexcode/spec-cli/dist/session-declarations.js +126 -0
  128. package/node_modules/@spexcode/spec-cli/dist/session-execution.d.ts +10 -0
  129. package/node_modules/@spexcode/spec-cli/dist/session-execution.js +70 -0
  130. package/node_modules/@spexcode/spec-cli/dist/session-files.d.ts +28 -0
  131. package/node_modules/@spexcode/spec-cli/dist/session-files.js +130 -0
  132. package/node_modules/@spexcode/spec-cli/dist/session-follow.d.ts +31 -0
  133. package/node_modules/@spexcode/spec-cli/dist/session-follow.js +179 -0
  134. package/node_modules/@spexcode/spec-cli/dist/session-reparent.d.ts +10 -0
  135. package/node_modules/@spexcode/spec-cli/dist/session-reparent.js +33 -0
  136. package/node_modules/@spexcode/spec-cli/dist/session-timeline.d.ts +51 -0
  137. package/node_modules/@spexcode/spec-cli/dist/session-timeline.js +233 -0
  138. package/node_modules/@spexcode/spec-cli/dist/session-web.d.ts +24 -0
  139. package/node_modules/@spexcode/spec-cli/dist/session-web.js +141 -0
  140. package/node_modules/@spexcode/spec-cli/dist/sessions.d.ts +412 -0
  141. package/node_modules/@spexcode/spec-cli/dist/sessions.js +4239 -0
  142. package/node_modules/@spexcode/spec-cli/dist/sh.d.ts +1 -0
  143. package/node_modules/@spexcode/spec-cli/dist/sh.js +3 -0
  144. package/node_modules/@spexcode/spec-cli/dist/shim-runtime.d.ts +1 -0
  145. package/{spec-cli/src/shim-runtime.ts → node_modules/@spexcode/spec-cli/dist/shim-runtime.js} +3 -4
  146. package/node_modules/@spexcode/spec-cli/dist/slash-commands.d.ts +9 -0
  147. package/node_modules/@spexcode/spec-cli/dist/slash-commands.js +307 -0
  148. package/node_modules/@spexcode/spec-cli/dist/source-files.d.ts +9 -0
  149. package/node_modules/@spexcode/spec-cli/dist/source-files.js +113 -0
  150. package/node_modules/@spexcode/spec-cli/dist/supervise.d.ts +1 -0
  151. package/node_modules/@spexcode/spec-cli/dist/supervise.js +308 -0
  152. package/node_modules/@spexcode/spec-cli/dist/tree.d.ts +25 -0
  153. package/node_modules/@spexcode/spec-cli/dist/tree.js +98 -0
  154. package/node_modules/@spexcode/spec-cli/dist/tsx-bin.d.ts +3 -0
  155. package/node_modules/@spexcode/spec-cli/dist/tsx-bin.js +41 -0
  156. package/node_modules/@spexcode/spec-cli/dist/uninstall.d.ts +3 -0
  157. package/node_modules/@spexcode/spec-cli/dist/uninstall.js +177 -0
  158. package/node_modules/@spexcode/spec-cli/dist/uploads.d.ts +36 -0
  159. package/node_modules/@spexcode/spec-cli/dist/uploads.js +243 -0
  160. package/node_modules/@spexcode/spec-cli/dist/worktree-sources.d.ts +1 -0
  161. package/node_modules/@spexcode/spec-cli/dist/worktree-sources.js +47 -0
  162. package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/dispatch.sh +5 -5
  163. package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/harness.sh +27 -7
  164. package/node_modules/@spexcode/spec-cli/package.json +47 -0
  165. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +8 -0
  166. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/core/comment-altitude/spec.md +9 -0
  167. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec-first.sh +1 -1
  168. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec-of-file.sh +1 -0
  169. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/core/spec.md +22 -0
  170. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/spec.md +2 -2
  171. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/stop-gate.sh +31 -29
  172. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +15 -0
  173. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/forge-link/spec.md +10 -0
  174. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +13 -0
  175. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +12 -0
  176. package/node_modules/@spexcode/spec-core/dist/anchors.d.ts +94 -0
  177. package/node_modules/@spexcode/spec-core/dist/anchors.js +730 -0
  178. package/node_modules/@spexcode/spec-core/dist/git.d.ts +166 -0
  179. package/node_modules/@spexcode/spec-core/dist/git.js +2736 -0
  180. package/node_modules/@spexcode/spec-core/dist/graph-delta.d.ts +44 -0
  181. package/node_modules/@spexcode/spec-core/dist/graph-delta.js +72 -0
  182. package/node_modules/@spexcode/spec-core/dist/graph.d.ts +34 -0
  183. package/node_modules/@spexcode/spec-core/dist/graph.js +237 -0
  184. package/node_modules/@spexcode/spec-core/dist/graphDelta.d.ts +3 -0
  185. package/node_modules/@spexcode/spec-core/dist/graphDelta.js +13 -0
  186. package/node_modules/@spexcode/spec-core/dist/harness-identity.d.ts +31 -0
  187. package/node_modules/@spexcode/spec-core/dist/harness-identity.js +20 -0
  188. package/node_modules/@spexcode/spec-core/dist/identity-presets.d.ts +152 -0
  189. package/node_modules/@spexcode/spec-core/dist/identity-presets.js +132 -0
  190. package/node_modules/@spexcode/spec-core/dist/index.d.ts +45 -0
  191. package/node_modules/@spexcode/spec-core/dist/index.js +19 -0
  192. package/node_modules/@spexcode/spec-core/dist/layout.d.ts +183 -0
  193. package/node_modules/@spexcode/spec-core/dist/layout.js +548 -0
  194. package/node_modules/@spexcode/spec-core/dist/process-identity.d.ts +37 -0
  195. package/node_modules/@spexcode/spec-core/dist/process-identity.js +214 -0
  196. package/node_modules/@spexcode/spec-core/dist/project-identity.d.ts +12 -0
  197. package/node_modules/@spexcode/spec-core/dist/project-identity.js +71 -0
  198. package/node_modules/@spexcode/spec-core/dist/project-store.d.ts +3 -0
  199. package/node_modules/@spexcode/spec-core/dist/project-store.js +14 -0
  200. package/node_modules/@spexcode/spec-core/dist/resilience.d.ts +2 -0
  201. package/node_modules/@spexcode/spec-core/dist/resilience.js +40 -0
  202. package/node_modules/@spexcode/spec-core/dist/review/index.d.ts +3 -0
  203. package/node_modules/@spexcode/spec-core/dist/review/index.js +5 -0
  204. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.d.ts +77 -0
  205. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.js +308 -0
  206. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.d.ts +66 -0
  207. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.js +180 -0
  208. package/node_modules/@spexcode/spec-core/dist/review/session.d.ts +4 -0
  209. package/node_modules/@spexcode/spec-core/dist/review/session.js +8 -0
  210. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.d.ts +15 -0
  211. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.js +12 -0
  212. package/node_modules/@spexcode/spec-core/dist/root-lru.d.ts +4 -0
  213. package/{spec-cli/src/root-lru.ts → node_modules/@spexcode/spec-core/dist/root-lru.js} +26 -30
  214. package/node_modules/@spexcode/spec-core/dist/specs.d.ts +117 -0
  215. package/node_modules/@spexcode/spec-core/dist/specs.js +489 -0
  216. package/node_modules/@spexcode/spec-core/package.json +28 -0
  217. package/node_modules/@spexcode/spec-eval/dist/cache.d.ts +10 -0
  218. package/node_modules/@spexcode/spec-eval/dist/cache.js +50 -0
  219. package/node_modules/@spexcode/spec-eval/dist/cli.d.ts +22 -0
  220. package/node_modules/@spexcode/spec-eval/dist/cli.js +981 -0
  221. package/node_modules/@spexcode/spec-eval/dist/evaltab.d.ts +98 -0
  222. package/node_modules/@spexcode/spec-eval/dist/evaltab.js +176 -0
  223. package/node_modules/@spexcode/spec-eval/dist/filing.d.ts +16 -0
  224. package/node_modules/@spexcode/spec-eval/dist/filing.js +36 -0
  225. package/node_modules/@spexcode/spec-eval/dist/freshness.d.ts +48 -0
  226. package/node_modules/@spexcode/spec-eval/dist/freshness.js +799 -0
  227. package/node_modules/@spexcode/spec-eval/dist/host.d.ts +46 -0
  228. package/node_modules/@spexcode/spec-eval/dist/host.js +53 -0
  229. package/node_modules/@spexcode/spec-eval/dist/humanok.d.ts +11 -0
  230. package/node_modules/@spexcode/spec-eval/dist/humanok.js +27 -0
  231. package/node_modules/@spexcode/spec-eval/dist/index.d.ts +4 -0
  232. package/node_modules/@spexcode/spec-eval/dist/index.js +4 -0
  233. package/node_modules/@spexcode/spec-eval/dist/remarks.d.ts +31 -0
  234. package/node_modules/@spexcode/spec-eval/dist/remarks.js +1 -0
  235. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.d.ts +13 -0
  236. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.js +303 -0
  237. package/node_modules/@spexcode/spec-eval/dist/scenarios.d.ts +99 -0
  238. package/node_modules/@spexcode/spec-eval/dist/scenarios.js +650 -0
  239. package/node_modules/@spexcode/spec-eval/dist/sessioneval.d.ts +307 -0
  240. package/node_modules/@spexcode/spec-eval/dist/sessioneval.js +1883 -0
  241. package/node_modules/@spexcode/spec-eval/dist/sidecar.d.ts +55 -0
  242. package/node_modules/@spexcode/spec-eval/dist/sidecar.js +82 -0
  243. package/node_modules/@spexcode/spec-eval/dist/timeline.d.ts +25 -0
  244. package/node_modules/@spexcode/spec-eval/dist/timeline.js +65 -0
  245. package/node_modules/@spexcode/spec-eval/dist/ui-path.d.ts +1 -0
  246. package/node_modules/@spexcode/spec-eval/dist/ui-path.js +2 -0
  247. package/node_modules/@spexcode/spec-eval/package.json +36 -0
  248. package/node_modules/@spexcode/spec-forge/dist/cache.d.ts +29 -0
  249. package/node_modules/@spexcode/spec-forge/dist/cache.js +59 -0
  250. package/node_modules/@spexcode/spec-forge/dist/cli.d.ts +1 -0
  251. package/node_modules/@spexcode/spec-forge/dist/cli.js +100 -0
  252. package/node_modules/@spexcode/spec-forge/dist/drivers/github.d.ts +2 -0
  253. package/node_modules/@spexcode/spec-forge/dist/drivers/github.js +116 -0
  254. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.d.ts +7 -0
  255. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.js +144 -0
  256. package/node_modules/@spexcode/spec-forge/dist/drivers.d.ts +10 -0
  257. package/node_modules/@spexcode/spec-forge/dist/drivers.js +83 -0
  258. package/node_modules/@spexcode/spec-forge/dist/index.d.ts +4 -0
  259. package/node_modules/@spexcode/spec-forge/dist/index.js +4 -0
  260. package/node_modules/@spexcode/spec-forge/dist/links.d.ts +15 -0
  261. package/node_modules/@spexcode/spec-forge/dist/links.js +65 -0
  262. package/node_modules/@spexcode/spec-forge/dist/needs-eval.d.ts +10 -0
  263. package/node_modules/@spexcode/spec-forge/dist/needs-eval.js +20 -0
  264. package/node_modules/@spexcode/spec-forge/dist/port.d.ts +53 -0
  265. package/node_modules/@spexcode/spec-forge/dist/port.js +1 -0
  266. package/node_modules/@spexcode/spec-forge/dist/resident.d.ts +7 -0
  267. package/node_modules/@spexcode/spec-forge/dist/resident.js +43 -0
  268. package/node_modules/@spexcode/spec-forge/package.json +32 -0
  269. package/package.json +33 -19
  270. package/spec-cli/bin/spex.mjs +0 -69
  271. package/spec-cli/src/anchors.ts +0 -706
  272. package/spec-cli/src/attach.ts +0 -43
  273. package/spec-cli/src/claude-headless.ts +0 -321
  274. package/spec-cli/src/cli.ts +0 -1115
  275. package/spec-cli/src/client.ts +0 -315
  276. package/spec-cli/src/cockpit.ts +0 -43
  277. package/spec-cli/src/codex-runtime-generations.ts +0 -646
  278. package/spec-cli/src/commit-surgery.ts +0 -68
  279. package/spec-cli/src/contract-filter.ts +0 -202
  280. package/spec-cli/src/delivery-queue.ts +0 -107
  281. package/spec-cli/src/doctor.ts +0 -516
  282. package/spec-cli/src/file-write.ts +0 -22
  283. package/spec-cli/src/gateway-auth.ts +0 -181
  284. package/spec-cli/src/gateway-hub.ts +0 -356
  285. package/spec-cli/src/gateway.ts +0 -368
  286. package/spec-cli/src/git.ts +0 -2180
  287. package/spec-cli/src/graph.ts +0 -221
  288. package/spec-cli/src/graphCache.ts +0 -641
  289. package/spec-cli/src/graphDelta.ts +0 -77
  290. package/spec-cli/src/graphStream.ts +0 -1019
  291. package/spec-cli/src/harness-select.ts +0 -77
  292. package/spec-cli/src/harness.ts +0 -2747
  293. package/spec-cli/src/headless-controller.ts +0 -63
  294. package/spec-cli/src/help.ts +0 -480
  295. package/spec-cli/src/host-resources.ts +0 -707
  296. package/spec-cli/src/host.ts +0 -611
  297. package/spec-cli/src/identity-presets.d.ts +0 -13
  298. package/spec-cli/src/identity-presets.js +0 -128
  299. package/spec-cli/src/index.ts +0 -730
  300. package/spec-cli/src/init.ts +0 -258
  301. package/spec-cli/src/issues-cli.ts +0 -276
  302. package/spec-cli/src/issues.ts +0 -237
  303. package/spec-cli/src/layout.ts +0 -557
  304. package/spec-cli/src/lint.ts +0 -458
  305. package/spec-cli/src/localIssues.ts +0 -538
  306. package/spec-cli/src/materialize.ts +0 -412
  307. package/spec-cli/src/mentions.ts +0 -81
  308. package/spec-cli/src/opencode-headless.ts +0 -205
  309. package/spec-cli/src/pi-headless.ts +0 -153
  310. package/spec-cli/src/plugin-harness.ts +0 -157
  311. package/spec-cli/src/process-identity.ts +0 -207
  312. package/spec-cli/src/project-identity.ts +0 -73
  313. package/spec-cli/src/project-store.ts +0 -17
  314. package/spec-cli/src/pty-bridge.ts +0 -396
  315. package/spec-cli/src/pty-helper.mjs +0 -96
  316. package/spec-cli/src/pty-native-helper.mjs +0 -22
  317. package/spec-cli/src/ranker.ts +0 -191
  318. package/spec-cli/src/reaper.ts +0 -125
  319. package/spec-cli/src/resilience.ts +0 -41
  320. package/spec-cli/src/reviewSnapshot.ts +0 -28
  321. package/spec-cli/src/reviews.ts +0 -405
  322. package/spec-cli/src/runtime-guard.ts +0 -35
  323. package/spec-cli/src/runtime-ownership.ts +0 -88
  324. package/spec-cli/src/search.bench.mjs +0 -80
  325. package/spec-cli/src/search.ts +0 -63
  326. package/spec-cli/src/session-cursors.ts +0 -91
  327. package/spec-cli/src/session-follow.ts +0 -182
  328. package/spec-cli/src/session-timeline.ts +0 -98
  329. package/spec-cli/src/sessions.ts +0 -3403
  330. package/spec-cli/src/sh.ts +0 -3
  331. package/spec-cli/src/slash-commands.ts +0 -318
  332. package/spec-cli/src/source-files.ts +0 -104
  333. package/spec-cli/src/specs.ts +0 -498
  334. package/spec-cli/src/supervise.ts +0 -245
  335. package/spec-cli/src/tree.ts +0 -118
  336. package/spec-cli/src/tsx-bin.ts +0 -18
  337. package/spec-cli/src/uninstall.ts +0 -171
  338. package/spec-cli/src/uploads.ts +0 -253
  339. package/spec-cli/src/worktree-sources.ts +0 -42
  340. package/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +0 -8
  341. package/spec-cli/templates/spec/project/.plugins/core/comment-altitude/spec.md +0 -28
  342. package/spec-cli/templates/spec/project/.plugins/core/spec.md +0 -23
  343. package/spec-cli/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +0 -32
  344. package/spec-cli/templates/spec/project/.plugins/prompts/forge-link/spec.md +0 -9
  345. package/spec-cli/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +0 -15
  346. package/spec-cli/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +0 -18
  347. package/spec-dashboard/dist/assets/App-F9uaAVcH.js +0 -2
  348. package/spec-dashboard/dist/assets/Dashboard-Ba_jhxp1.js +0 -27
  349. package/spec-dashboard/dist/assets/Dashboard-C5ap-Sga.css +0 -1
  350. package/spec-dashboard/dist/assets/EvalsPage-FixoOg_n.js +0 -2
  351. package/spec-dashboard/dist/assets/IssuesPage-CuKLFhH3.js +0 -1
  352. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  353. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  354. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  355. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  356. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  357. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  358. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  359. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  360. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  361. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  362. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  363. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  364. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  365. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  366. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  367. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  368. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  369. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  370. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  371. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  372. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  373. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  374. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  375. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  376. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  377. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  378. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  379. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  380. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  381. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  382. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  383. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  384. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  385. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  386. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  387. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  388. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  389. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  390. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  391. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  392. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  393. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  394. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  395. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  396. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  397. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  398. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  399. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  400. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  401. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  402. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  403. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  404. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  405. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  406. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  407. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  408. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  409. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  410. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  411. package/spec-dashboard/dist/assets/MobileApp-CHgEHORJ.js +0 -2
  412. package/spec-dashboard/dist/assets/Modal-CQgYymmr.js +0 -1
  413. package/spec-dashboard/dist/assets/PageScroll-hT7UTLvD.js +0 -1
  414. package/spec-dashboard/dist/assets/ProjectsPage-CtXxakF9.js +0 -1
  415. package/spec-dashboard/dist/assets/SessionInterface-6GBZ9nXN.css +0 -32
  416. package/spec-dashboard/dist/assets/SessionInterface-Bpie-9fs.js +0 -39
  417. package/spec-dashboard/dist/assets/SessionWindow-CixDi4PI.js +0 -1
  418. package/spec-dashboard/dist/assets/Settings-C2MsucfE.js +0 -1
  419. package/spec-dashboard/dist/assets/Thread-C6Go8HRh.js +0 -13
  420. package/spec-dashboard/dist/assets/bindings-BC9vqpYU.js +0 -1
  421. package/spec-dashboard/dist/assets/data-B-RQmit6.js +0 -1
  422. package/spec-dashboard/dist/assets/index-CsI8DElI.css +0 -1
  423. package/spec-dashboard/dist/assets/index-DrVao0Ep.js +0 -41
  424. package/spec-dashboard/dist/assets/launch-BBH02b1v.js +0 -276
  425. package/spec-dashboard/dist/assets/launch-Cp579UoJ.css +0 -1
  426. package/spec-dashboard/dist/assets/terminalFont-C6oGNKrf.js +0 -1
  427. package/spec-dashboard/dist/index.html +0 -29
  428. package/spec-dashboard/src/reviewFilters.js +0 -322
  429. package/spec-dashboard/src/reviewQuery.js +0 -174
  430. package/spec-dashboard/src/session.js +0 -199
  431. package/spec-eval/src/cache.ts +0 -57
  432. package/spec-eval/src/cli.ts +0 -889
  433. package/spec-eval/src/evaltab.ts +0 -262
  434. package/spec-eval/src/filing.ts +0 -39
  435. package/spec-eval/src/freshness.ts +0 -557
  436. package/spec-eval/src/humanok.ts +0 -28
  437. package/spec-eval/src/scenariofresh.ts +0 -244
  438. package/spec-eval/src/scenarios.ts +0 -672
  439. package/spec-eval/src/sessioneval.ts +0 -2226
  440. package/spec-eval/src/sidecar.ts +0 -93
  441. package/spec-eval/src/timeline.ts +0 -54
  442. package/spec-forge/src/__fixtures__/github-forge.json +0 -63
  443. package/spec-forge/src/cache.ts +0 -66
  444. package/spec-forge/src/cli.ts +0 -99
  445. package/spec-forge/src/drivers/github.ts +0 -132
  446. package/spec-forge/src/drivers/gitlab.ts +0 -153
  447. package/spec-forge/src/drivers.ts +0 -73
  448. package/spec-forge/src/links.ts +0 -72
  449. package/spec-forge/src/needs-eval.ts +0 -29
  450. package/spec-forge/src/port.ts +0 -36
  451. package/spec-forge/src/resident.ts +0 -46
  452. /package/{spec-cli → node_modules/@spexcode/spec-cli}/README.md +0 -0
  453. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-0.5.2-eef1.fixture +0 -0
  454. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-sed-v0.fixture +0 -0
  455. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/commit-msg +0 -0
  456. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-checkout +0 -0
  457. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-merge +0 -0
  458. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/pre-commit +0 -0
  459. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/prepare-commit-msg +0 -0
  460. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/reference-transaction +0 -0
  461. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/extract/spec.md +0 -0
  462. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/regroup/spec.md +0 -0
  463. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/rename/spec.md +0 -0
  464. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/spec.md +0 -0
  465. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/tidy/spec.md +0 -0
  466. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/idle.sh +0 -0
  467. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/spec.md +0 -0
  468. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/mark-active.sh +0 -0
  469. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/spec.md +0 -0
  470. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/fail.sh +0 -0
  471. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/spec.md +0 -0
  472. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec.md +0 -0
  473. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec.md +0 -0
  474. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/spec.md +0 -0
  475. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/digest.mjs +0 -0
  476. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/spec.md +0 -0
  477. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/spec.md +0 -0
  478. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/spec.md +0 -0
  479. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/spec.md +0 -0
  480. /package/{spec-cli → node_modules/@spexcode/spec-core}/templates/spexcode.json +0 -0
@@ -0,0 +1,144 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ let ctx = null;
3
+ function gitlabCtx() {
4
+ if (ctx)
5
+ return ctx;
6
+ const remote = execFileSync('git', ['remote', 'get-url', 'origin'], { encoding: 'utf8' }).trim();
7
+ const parsed = parseRemote(remote);
8
+ if (!parsed)
9
+ throw new Error(`gitlab: cannot parse origin remote '${remote}' as a GitLab URL`);
10
+ const token = process.env.GITLAB_TOKEN || credentialToken(parsed.host);
11
+ if (!token) {
12
+ throw new Error(`gitlab: no token for ${parsed.host} — set GITLAB_TOKEN, or store a PAT in git's credential store:\n` +
13
+ ` printf "protocol=https\\nhost=${parsed.host}\\nusername=<user>\\npassword=<token>\\n\\n" | git credential approve`);
14
+ }
15
+ ctx = { ...parsed, token };
16
+ return ctx;
17
+ }
18
+ export function parseRemote(remote) {
19
+ let m = remote.match(/^(https?:\/\/[^/]+)\/(.+?)(?:\.git)?\/?$/);
20
+ if (m)
21
+ return { base: m[1], host: m[1].replace(/^https?:\/\//, ''), project: m[2] };
22
+ m = remote.match(/^(?:ssh:\/\/)?[\w.-]+@([\w.-]+)(?::\d+)?[:/](.+?)(?:\.git)?\/?$/);
23
+ if (m)
24
+ return { base: `https://${m[1]}`, host: m[1], project: m[2] };
25
+ return null;
26
+ }
27
+ function credentialToken(host) {
28
+ try {
29
+ const out = execFileSync('git', ['credential', 'fill'], {
30
+ input: `protocol=https\nhost=${host}\n\n`,
31
+ encoding: 'utf8',
32
+ env: { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_ASKPASS: 'true' },
33
+ stdio: ['pipe', 'pipe', 'ignore'],
34
+ });
35
+ return out.match(/^password=(.+)$/m)?.[1] ?? '';
36
+ }
37
+ catch {
38
+ return '';
39
+ }
40
+ }
41
+ async function api(path, init) {
42
+ const { base, project, token } = gitlabCtx();
43
+ const sep = path.includes('?') ? '&' : '?';
44
+ const url = `${base}/api/v4/projects/${encodeURIComponent(project)}/${path}${init?.method ? '' : `${sep}per_page=100`}`;
45
+ const res = await fetch(url, {
46
+ ...init,
47
+ headers: { 'PRIVATE-TOKEN': token, 'content-type': 'application/json', ...init?.headers },
48
+ });
49
+ if (!res.ok)
50
+ throw new Error(`gitlab: ${init?.method ?? 'GET'} ${path} → ${res.status} ${(await res.text()).slice(0, 300)}`);
51
+ return (await res.json());
52
+ }
53
+ // GitLab's API has no bounded list query; stop at a short page and cap the walk.
54
+ async function paged(path) {
55
+ const sep = path.includes('?') ? '&' : '?';
56
+ const out = [];
57
+ for (let page = 1; page <= 20; page++) {
58
+ const rows = await api(`${path}${sep}page=${page}`);
59
+ out.push(...rows);
60
+ if (rows.length < 100)
61
+ break;
62
+ }
63
+ return out;
64
+ }
65
+ async function toIssue(r) {
66
+ return {
67
+ number: r.iid,
68
+ title: r.title,
69
+ body: r.description ?? '',
70
+ url: r.web_url,
71
+ state: normalizeState(r.state),
72
+ labels: forgeLabels(r.labels),
73
+ author: r.author?.username ?? '',
74
+ createdAt: r.created_at ?? '',
75
+ comments: r.user_notes_count > 0 ? await listNotes(r.iid) : [],
76
+ };
77
+ }
78
+ function forgeLabels(labels) {
79
+ return (labels ?? []).flatMap((label) => {
80
+ const name = typeof label === 'string' ? label : label.name ?? '';
81
+ if (!name)
82
+ return [];
83
+ if (typeof label === 'string')
84
+ return [{ name }];
85
+ return [{ name, ...(label.color ? { color: label.color } : {}), ...(label.text_color ? { textColor: label.text_color } : {}) }];
86
+ });
87
+ }
88
+ function normalizeState(state) {
89
+ const s = (state || '').toLowerCase();
90
+ return s === 'opened' ? 'open' : s;
91
+ }
92
+ async function listNotes(iid) {
93
+ const rows = await paged(`issues/${iid}/notes`);
94
+ return rows
95
+ .filter((n) => !n.system)
96
+ .map((n) => ({ author: n.author?.username ?? '', createdAt: n.created_at ?? '', body: n.body ?? '' }));
97
+ }
98
+ export const gitlabDriver = {
99
+ host: 'gitlab',
100
+ async listIssues() {
101
+ const rows = await paged('issues?state=all&with_labels_details=true');
102
+ return Promise.all(rows.map(toIssue));
103
+ },
104
+ async listIssuesSince(sinceISO) {
105
+ const rows = await paged(`issues?state=all&with_labels_details=true&updated_after=${encodeURIComponent(sinceISO)}`);
106
+ return Promise.all(rows.map(toIssue));
107
+ },
108
+ async listPRs() {
109
+ const rows = await paged('merge_requests?state=opened');
110
+ return Promise.all(rows.map(async (r) => ({
111
+ number: r.iid,
112
+ title: r.title,
113
+ url: r.web_url,
114
+ state: normalizeState(r.state),
115
+ headRefName: r.source_branch,
116
+ closesIssues: (await paged(`merge_requests/${r.iid}/closes_issues`)).map((i) => i.iid),
117
+ })));
118
+ },
119
+ async createIssue({ title, body }) {
120
+ const r = await api('issues', {
121
+ method: 'POST',
122
+ body: JSON.stringify({ title, description: body }),
123
+ });
124
+ if (!r.web_url?.startsWith('http') || !Number.isFinite(r.iid))
125
+ throw new Error(`gitlab: issue create returned an unexpected result: ${JSON.stringify(r)}`);
126
+ return { number: r.iid, url: r.web_url };
127
+ },
128
+ async createComment({ number, body }) {
129
+ const { base, project } = gitlabCtx();
130
+ const r = await api(`issues/${number}/notes`, { method: 'POST', body: JSON.stringify({ body }) });
131
+ if (!Number.isFinite(r.id))
132
+ throw new Error(`gitlab: note create returned an unexpected result: ${JSON.stringify(r)}`);
133
+ return { url: `${base}/${project}/-/issues/${number}#note_${r.id}` };
134
+ },
135
+ async closeIssue({ number }) {
136
+ const r = await api(`issues/${number}`, {
137
+ method: 'PUT',
138
+ body: JSON.stringify({ state_event: 'close' }),
139
+ });
140
+ if (!r.web_url?.startsWith('http'))
141
+ throw new Error(`gitlab: issue close returned an unexpected result: ${JSON.stringify(r)}`);
142
+ return { url: r.web_url };
143
+ },
144
+ };
@@ -0,0 +1,10 @@
1
+ import type { ForgeDriver } from './port.js';
2
+ export declare const FORGE_DRIVERS: ForgeDriver[];
3
+ export declare const DEFAULT_FORGE_HOST = "github";
4
+ export declare function forgeDriverFor(host: string): ForgeDriver | undefined;
5
+ export declare function forgeIssueStores(): {
6
+ id: string;
7
+ label: string;
8
+ kind: 'forge';
9
+ }[];
10
+ export declare function resolveForgeHost(): string;
@@ -0,0 +1,83 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { githubDriver } from './drivers/github.js';
5
+ import { gitlabDriver } from './drivers/gitlab.js';
6
+ export const FORGE_DRIVERS = [githubDriver, gitlabDriver];
7
+ export const DEFAULT_FORGE_HOST = 'github';
8
+ export function forgeDriverFor(host) {
9
+ return FORGE_DRIVERS.find((d) => d.host === host);
10
+ }
11
+ export function forgeIssueStores() {
12
+ const driver = forgeDriverFor(resolveForgeHost());
13
+ return driver ? [{ id: driver.host, label: driver.host, kind: 'forge' }] : [];
14
+ }
15
+ function gitEnv() {
16
+ const env = { ...process.env };
17
+ delete env.GIT_DIR;
18
+ delete env.GIT_WORK_TREE;
19
+ delete env.GIT_INDEX_FILE;
20
+ delete env.GIT_OBJECT_DIRECTORY;
21
+ return env;
22
+ }
23
+ function gitOut(args) {
24
+ try {
25
+ return execFileSync('git', args, { env: gitEnv(), encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || null;
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function configuredHost() {
32
+ const root = gitOut(['rev-parse', '--show-toplevel']);
33
+ if (!root)
34
+ return null;
35
+ for (const name of ['spexcode.local.json', 'spexcode.json']) {
36
+ const p = join(root, name);
37
+ if (!existsSync(p))
38
+ continue;
39
+ let parsed;
40
+ try {
41
+ parsed = JSON.parse(readFileSync(p, 'utf8'));
42
+ }
43
+ catch (e) {
44
+ throw new Error(`${p} is not valid JSON: ${e.message}`);
45
+ }
46
+ const host = parsed?.forge?.host;
47
+ if (typeof host === 'string' && host.trim())
48
+ return host.trim();
49
+ }
50
+ return null;
51
+ }
52
+ function remoteHostname(url) {
53
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(url)) {
54
+ try {
55
+ return new URL(url).hostname || null;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ const scp = /^(?:[^@\s/]+@)?([^:/\s]+):./.exec(url);
62
+ return scp ? scp[1] : null;
63
+ }
64
+ function hostFor(hostname) {
65
+ const h = hostname.toLowerCase();
66
+ if (h.includes('github'))
67
+ return 'github';
68
+ if (h.includes('bitbucket'))
69
+ return 'bitbucket';
70
+ return 'gitlab';
71
+ }
72
+ let cached = null;
73
+ const RESOLVE_TTL_MS = 30_000;
74
+ export function resolveForgeHost() {
75
+ const now = Date.now();
76
+ if (cached && now - cached.at < RESOLVE_TTL_MS)
77
+ return cached.host;
78
+ const url = gitOut(['remote', 'get-url', 'origin']);
79
+ const hostname = url ? remoteHostname(url) : null;
80
+ const host = configuredHost() ?? (hostname ? hostFor(hostname) : DEFAULT_FORGE_HOST);
81
+ cached = { host, at: now };
82
+ return host;
83
+ }
@@ -0,0 +1,4 @@
1
+ export * from './port.js';
2
+ export * from './links.js';
3
+ export * from './drivers.js';
4
+ export * from './resident.js';
@@ -0,0 +1,4 @@
1
+ export * from './port.js';
2
+ export * from './links.js';
3
+ export * from './drivers.js';
4
+ export * from './resident.js';
@@ -0,0 +1,15 @@
1
+ import type { ForgeIssue, ForgePR } from './port.js';
2
+ export type LinkedIssue = ForgeIssue & {
3
+ via: 'marker' | 'pr';
4
+ };
5
+ export type LinkedPR = ForgePR & {
6
+ via: 'branch';
7
+ };
8
+ export type NodeLinks = {
9
+ node: string;
10
+ issues: LinkedIssue[];
11
+ prs: LinkedPR[];
12
+ };
13
+ export declare function parseSpecMarkers(body: string): string[];
14
+ export declare function branchToNode(branch: string, nodeIds: string[]): string | null;
15
+ export declare function resolveLinks(issues: ForgeIssue[], prs: ForgePR[], nodeIds: string[]): NodeLinks[];
@@ -0,0 +1,65 @@
1
+ export function parseSpecMarkers(body) {
2
+ const ids = [];
3
+ for (const m of (body || '').matchAll(/^\s*spec:\s*(.+)$/gim)) {
4
+ for (const part of m[1].split(',')) {
5
+ const id = part.trim();
6
+ if (id)
7
+ ids.push(id);
8
+ }
9
+ }
10
+ return ids;
11
+ }
12
+ export function branchToNode(branch, nodeIds) {
13
+ if (!branch?.startsWith('node/'))
14
+ return null;
15
+ const rest = branch.slice('node/'.length);
16
+ let best = null;
17
+ for (const id of nodeIds) {
18
+ if (rest === id || rest.startsWith(id + '-')) {
19
+ if (!best || id.length > best.length)
20
+ best = id;
21
+ }
22
+ }
23
+ return best;
24
+ }
25
+ export function resolveLinks(issues, prs, nodeIds) {
26
+ const known = new Set(nodeIds);
27
+ const byNode = new Map();
28
+ const slot = (node) => {
29
+ let s = byNode.get(node);
30
+ if (!s) {
31
+ s = { issues: new Map(), prs: new Map() };
32
+ byNode.set(node, s);
33
+ }
34
+ return s;
35
+ };
36
+ const prNode = new Map();
37
+ for (const pr of prs) {
38
+ const node = branchToNode(pr.headRefName, nodeIds);
39
+ if (!node)
40
+ continue;
41
+ prNode.set(pr.number, node);
42
+ slot(node).prs.set(pr.number, { ...pr, via: 'branch' });
43
+ }
44
+ const issueByNumber = new Map(issues.map((i) => [i.number, i]));
45
+ for (const issue of issues) {
46
+ for (const id of parseSpecMarkers(issue.body)) {
47
+ if (known.has(id))
48
+ slot(id).issues.set(issue.number, { ...issue, via: 'marker' });
49
+ }
50
+ }
51
+ for (const pr of prs) {
52
+ const node = prNode.get(pr.number);
53
+ if (!node)
54
+ continue;
55
+ for (const num of pr.closesIssues) {
56
+ const issue = issueByNumber.get(num);
57
+ if (issue && !slot(node).issues.has(num)) {
58
+ slot(node).issues.set(num, { ...issue, via: 'pr' });
59
+ }
60
+ }
61
+ }
62
+ return [...byNode.entries()]
63
+ .map(([node, s]) => ({ node, issues: [...s.issues.values()], prs: [...s.prs.values()] }))
64
+ .sort((a, b) => a.node.localeCompare(b.node));
65
+ }
@@ -0,0 +1,10 @@
1
+ import type { ForgeIssue, ForgePR } from './port.js';
2
+ import { type LinkedIssue } from './links.js';
3
+ export declare const NEEDS_EVAL = "needs-eval";
4
+ export declare function isNeedsEval(issue: ForgeIssue): boolean;
5
+ export type EvalPending = LinkedIssue;
6
+ export type NodeEvalPending = {
7
+ node: string;
8
+ pending: EvalPending[];
9
+ };
10
+ export declare function resolveEvalPending(issues: ForgeIssue[], prs: ForgePR[], nodeIds: string[]): NodeEvalPending[];
@@ -0,0 +1,20 @@
1
+ import { resolveLinks } from './links.js';
2
+ export const NEEDS_EVAL = 'needs-eval';
3
+ const BODY_MARKER = new RegExp(`^\\s*${NEEDS_EVAL}\\s*:?\\s*$`, 'im');
4
+ export function isNeedsEval(issue) {
5
+ if (issue.labels.some((l) => l.name.trim().toLowerCase() === NEEDS_EVAL))
6
+ return true;
7
+ return BODY_MARKER.test(issue.body || '');
8
+ }
9
+ export function resolveEvalPending(issues, prs, nodeIds) {
10
+ const flagged = new Set(issues.filter(isNeedsEval).map((i) => i.number));
11
+ if (!flagged.size)
12
+ return [];
13
+ const out = [];
14
+ for (const { node, issues: linked } of resolveLinks(issues, prs, nodeIds)) {
15
+ const pending = linked.filter((i) => i.state === 'open' && flagged.has(i.number));
16
+ if (pending.length)
17
+ out.push({ node, pending });
18
+ }
19
+ return out;
20
+ }
@@ -0,0 +1,53 @@
1
+ export type ForgeComment = {
2
+ author: string;
3
+ createdAt: string;
4
+ body: string;
5
+ };
6
+ export type ForgeLabel = {
7
+ name: string;
8
+ color?: string;
9
+ textColor?: string;
10
+ };
11
+ export type ForgeIssue = {
12
+ number: number;
13
+ title: string;
14
+ body: string;
15
+ url: string;
16
+ state: string;
17
+ labels: ForgeLabel[];
18
+ author: string;
19
+ createdAt: string;
20
+ comments: ForgeComment[];
21
+ };
22
+ export type ForgePR = {
23
+ number: number;
24
+ title: string;
25
+ url: string;
26
+ state: string;
27
+ headRefName: string;
28
+ closesIssues: number[];
29
+ };
30
+ export interface ForgeDriver {
31
+ readonly host: string;
32
+ listIssues(): Promise<ForgeIssue[]>;
33
+ listPRs(): Promise<ForgePR[]>;
34
+ createIssue(input: {
35
+ title: string;
36
+ body: string;
37
+ }): Promise<{
38
+ number: number;
39
+ url: string;
40
+ }>;
41
+ createComment(input: {
42
+ number: number;
43
+ body: string;
44
+ }): Promise<{
45
+ url: string;
46
+ }>;
47
+ closeIssue(input: {
48
+ number: number;
49
+ }): Promise<{
50
+ url: string;
51
+ }>;
52
+ listIssuesSince?(sinceISO: string): Promise<ForgeIssue[]>;
53
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { ForgeIssue, ForgePR } from './port.js';
2
+ export declare function residentForgeState(): {
3
+ issues: ForgeIssue[];
4
+ prs: ForgePR[];
5
+ };
6
+ export declare function residentForgeRevision(): number;
7
+ export declare function refreshForgeNow(): Promise<void>;
@@ -0,0 +1,43 @@
1
+ import { ForgeCache } from './cache.js';
2
+ import { forgeDriverFor, resolveForgeHost } from './drivers.js';
3
+ const cache = new ForgeCache();
4
+ let inFlight = null;
5
+ let lastAttempt = 0;
6
+ const TTL_MS = 20_000;
7
+ let lastIssueSync = null;
8
+ let lastFull = 0;
9
+ const FULL_MS = 30 * 60_000;
10
+ function refreshIfStale(now) {
11
+ if (inFlight || (lastAttempt && now - lastAttempt < TTL_MS))
12
+ return;
13
+ const driver = forgeDriverFor(resolveForgeHost());
14
+ if (!driver)
15
+ return;
16
+ lastAttempt = now;
17
+ const startISO = new Date(now).toISOString(); // stamped at fetch START so an update during the fetch lands in the next window
18
+ const incremental = lastIssueSync && driver.listIssuesSince && now - lastFull < FULL_MS;
19
+ inFlight = (incremental
20
+ ? Promise.all([
21
+ driver.listIssuesSince(lastIssueSync).then((delta) => cache.applyIssues(delta)),
22
+ driver.listPRs().then((prs) => cache.setPRs(prs)),
23
+ ]).then(() => { lastIssueSync = startISO; })
24
+ : cache.reconcile(driver).then(() => { lastFull = now; lastIssueSync = startISO; }))
25
+ .catch(() => { })
26
+ .finally(() => { inFlight = null; });
27
+ }
28
+ export function residentForgeState() {
29
+ refreshIfStale(Date.now());
30
+ return cache.state();
31
+ }
32
+ export function residentForgeRevision() {
33
+ return cache.stateRevision();
34
+ }
35
+ export async function refreshForgeNow() {
36
+ if (inFlight)
37
+ await inFlight;
38
+ lastAttempt = 0;
39
+ lastFull = 0;
40
+ refreshIfStale(Date.now());
41
+ if (inFlight)
42
+ await inFlight;
43
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@spexcode/spec-forge",
3
+ "version": "0.6.5",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": "./dist/index.js",
7
+ "./port": "./dist/port.js",
8
+ "./links": "./dist/links.js",
9
+ "./drivers": "./dist/drivers.js",
10
+ "./resident": "./dist/resident.js",
11
+ "./cli": "./dist/cli.js",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "files": ["dist"],
15
+ "description": "Host-agnostic forge link tracer — reads a forge's open issues/PRs and resolves each to the spec node it serves (issue-body `Spec: <id>` marker + `node/<id>` PR branch). Read-only; a node's status stays git-derived.",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "build": "node ../scripts/build-dist.mjs",
21
+ "prepublishOnly": "node ../scripts/release-publish.mjs --from-package-publish",
22
+ "test": "tsx --test src/*.test.ts"
23
+ },
24
+ "dependencies": {
25
+ "@spexcode/spec-core": "0.6.5"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.16.0",
29
+ "tsx": "^4.19.2",
30
+ "typescript": "^5.6.3"
31
+ }
32
+ }
package/package.json CHANGED
@@ -1,42 +1,47 @@
1
1
  {
2
2
  "name": "spexcode",
3
- "version": "0.6.1",
3
+ "version": "0.6.5",
4
4
  "type": "module",
5
5
  "description": "SpexCode — a spec-driven, self-developing dev tool. The `spex` CLI + spec server reads the .spec tree and its git history, and serves the dashboard.",
6
6
  "license": "MIT",
7
7
  "bin": {
8
- "spex": "spec-cli/bin/spex.mjs"
8
+ "spex": "bin/spex.mjs"
9
9
  },
10
+ "workspaces": [
11
+ "packages/*",
12
+ "spec-cli",
13
+ "spec-eval",
14
+ "spec-forge",
15
+ "spec-dashboard"
16
+ ],
10
17
  "files": [
11
- "spec-cli/src",
12
- "!spec-cli/src/**/*.test.ts",
13
- "spec-cli/bin",
14
- "spec-cli/templates",
15
- "spec-cli/hooks",
16
- "spec-eval/src",
17
- "!spec-eval/src/**/*.test.ts",
18
- "spec-forge/src",
19
- "!spec-forge/src/**/*.test.ts",
20
- "spec-dashboard/dist",
21
- "spec-dashboard/src/reviewFilters.js",
22
- "spec-dashboard/src/reviewQuery.js",
23
- "spec-dashboard/src/session.js",
24
- "README.md"
18
+ "bin"
25
19
  ],
26
20
  "engines": {
27
21
  "node": ">=22"
28
22
  },
29
23
  "scripts": {
30
- "api": "cd spec-cli && npm run serve",
24
+ "build": "npm run build --workspace=@spexcode/spec-core && npm run build --workspace=@spexcode/spec-eval && npm run build --workspace=@spexcode/spec-forge && npm run build --workspace=@spexcode/spec-cli",
25
+ "api": "npm run build && node bin/spex.mjs serve",
31
26
  "web": "cd spec-dashboard && npm run dev",
27
+ "build:public": "node scripts/public-graph-build.mjs",
28
+ "test:public-graph": "npm run build:public && node spec-dashboard/test/public-graph-static.e2e.mjs",
32
29
  "lint": "node scripts/sync-init-plugins.mjs --check && cd spec-cli && npm run -s lint",
33
30
  "sync:init-plugins": "node scripts/sync-init-plugins.mjs --write",
34
31
  "test:init-plugins": "node --test scripts/sync-init-plugins.test.mjs",
32
+ "test:release-publish": "node --test scripts/release-publish.test.mjs",
33
+ "release:check": "node scripts/release-publish.mjs",
34
+ "release:publish": "node scripts/release-publish.mjs --publish",
35
+ "prepublishOnly": "node scripts/release-publish.mjs --from-package-publish",
36
+ "test:docs-release": "node --test scripts/docs-release.test.mjs scripts/reference-snapshot.test.mjs",
35
37
  "hooks": "bash scripts/install-hooks.sh",
36
38
  "prepack": "node scripts/sync-init-plugins.mjs --check && node scripts/prepack.mjs"
37
39
  },
38
40
  "dependencies": {
39
- "tsx": "^4.19.2"
41
+ "@spexcode/spec-cli": "0.6.5"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
40
45
  },
41
46
  "optionalDependencies": {
42
47
  "@hono/node-server": "^1.13.7",
@@ -47,5 +52,14 @@
47
52
  "devDependencies": {
48
53
  "@types/node": "^20.16.0",
49
54
  "typescript": "^5.6.3"
50
- }
55
+ },
56
+ "bundleDependencies": [
57
+ "@spexcode/spec-cli"
58
+ ],
59
+ "main": "index.js",
60
+ "directories": {
61
+ "doc": "docs"
62
+ },
63
+ "keywords": [],
64
+ "author": ""
51
65
  }
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env node
2
- // @@@ spex launcher - this repo has no build step, so the installed `spex` bin shells to tsx to
3
- // run the TypeScript CLI directly. After `npm link` (or a global install) `spex lint` works anywhere.
4
- import { spawn } from 'node:child_process'
5
- import { existsSync, readdirSync, readFileSync } from 'node:fs'
6
- import { createRequire } from 'node:module'
7
- import { fileURLToPath } from 'node:url'
8
- import { dirname, join } from 'node:path'
9
-
10
- // @@@ self-contained - resolve tsx + cli from THIS package, not the cwd. A fresh worktree off main has
11
- // no node_modules, so `npx tsx` there would try to install; using the package's own tsx makes a global
12
- // `spex` work from any cwd (agents, git hooks) against this package's code, operating on the cwd.
13
- const pkg = join(dirname(fileURLToPath(import.meta.url)), '..') // spec-cli/
14
- const cli = join(pkg, 'src', 'cli.ts')
15
-
16
- // @@@ mid-merge guard - no build step means every spex call parses this package's live TypeScript, so
17
- // while a merge conflict is being resolved in the checkout that hosts it, the source holds conflict
18
- // markers and tsx dies with a raw esbuild stacktrace — on EVERY call, including the Stop hook and an
19
- // agent's `spex session done`. Catch that one transient state up front: scan the source trees the CLI
20
- // imports (spec-cli ←→ spec-eval ←→ spec-forge), and if any file carries a marker, print one actionable
21
- // line and exit 75 (EX_TEMPFAIL: transient, retry) instead of spawning tsx into the stacktrace.
22
- const srcRoots = [join(pkg, 'src'), join(pkg, '..', 'spec-eval', 'src'), join(pkg, '..', 'spec-forge', 'src')]
23
- const conflicted = srcRoots.flatMap((root) => {
24
- if (!existsSync(root)) return []
25
- return readdirSync(root, { recursive: true })
26
- .filter((f) => /\.(ts|tsx|js|mjs)$/.test(String(f)))
27
- .map((f) => join(root, String(f)))
28
- .filter((path) => {
29
- try { return /^<{7} /m.test(readFileSync(path, 'utf8')) } catch { return false }
30
- })
31
- })
32
- if (conflicted.length) {
33
- console.error('spex: paused mid-merge — unresolved conflict markers in the source spex runs:')
34
- for (const f of conflicted) console.error(` ${f}`)
35
- console.error('spex executes this TypeScript directly (no build step); resolve the merge, then retry. (exit 75)')
36
- process.exit(75)
37
- }
38
- // @@@ cross-platform tsx resolution ([[platform-support]]) - resolve tsx's JS ENTRY (dist/cli.mjs) with
39
- // Node's own resolver from spec-cli, then run it through THIS node binary (process.execPath). tsx may live
40
- // in spec-cli/node_modules (dev) or be hoisted above the installed `spexcode` package (a real consumer
41
- // project) — one resolver covers both without hardcoded consumer paths. We deliberately never spawn the
42
- // `.bin/tsx` shim, nor a `.mjs` directly: on Windows the shim is an extensionless sh script and the `.mjs`
43
- // leans on a shebang, neither of which `child_process.spawn` can execute — that is the #37 crash
44
- // (`spawn …\node_modules\.bin\tsx ENOENT`) of `spex init`. `node dist/cli.mjs …` is shell-free and identical
45
- // on every OS.
46
- function resolveTsxCli() {
47
- try {
48
- const req = createRequire(join(pkg, 'package.json'))
49
- return join(dirname(req.resolve('tsx/package.json')), 'dist', 'cli.mjs')
50
- } catch {
51
- console.error('spex: cannot find the `tsx` runtime this package needs — run `npm install` in the SpexCode package, then retry.')
52
- process.exit(69)
53
- }
54
- }
55
- const tsxCli = resolveTsxCli()
56
- const args = process.argv.slice(2)
57
- const env = { ...process.env }
58
- // A backend/dashboard is a project or host control plane, never the managed session that happened to start
59
- // it. Scrub before tsx starts: doing this inside cli.ts is too late because tsx's resident esbuild helper has
60
- // already inherited the caller. New session launches provide the adapter-registry-derived key manifest; the
61
- // fallback covers sessions created before that manifest existed.
62
- if (args[0] === 'serve' || args[0] === 'dashboard') {
63
- const identityKeys = (env.SPEXCODE_SESSION_IDENTITY_VARS
64
- || 'SPEXCODE_SESSION_ID,CLAUDE_CODE_SESSION_ID,CODEX_THREAD_ID,OPENCODE_SESSION_ID,PI_SESSION_ID')
65
- .split(',').map((key) => key.trim()).filter(Boolean)
66
- for (const key of identityKeys) delete env[key]
67
- }
68
- spawn(process.execPath, [tsxCli, cli, ...args], { stdio: 'inherit', env })
69
- .on('exit', (code) => process.exit(code ?? 0))