spexcode 0.6.2 → 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 (479) hide show
  1. package/README.md +3 -1
  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} +36 -32
  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 +1 -1
  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/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec-first.sh +1 -1
  167. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec-of-file.sh +1 -0
  168. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/spec.md +2 -2
  169. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/stop-gate.sh +31 -29
  170. package/node_modules/@spexcode/spec-core/dist/anchors.d.ts +94 -0
  171. package/node_modules/@spexcode/spec-core/dist/anchors.js +730 -0
  172. package/node_modules/@spexcode/spec-core/dist/git.d.ts +166 -0
  173. package/node_modules/@spexcode/spec-core/dist/git.js +2736 -0
  174. package/node_modules/@spexcode/spec-core/dist/graph-delta.d.ts +44 -0
  175. package/node_modules/@spexcode/spec-core/dist/graph-delta.js +72 -0
  176. package/node_modules/@spexcode/spec-core/dist/graph.d.ts +34 -0
  177. package/node_modules/@spexcode/spec-core/dist/graph.js +237 -0
  178. package/node_modules/@spexcode/spec-core/dist/graphDelta.d.ts +3 -0
  179. package/node_modules/@spexcode/spec-core/dist/graphDelta.js +13 -0
  180. package/node_modules/@spexcode/spec-core/dist/harness-identity.d.ts +31 -0
  181. package/node_modules/@spexcode/spec-core/dist/harness-identity.js +20 -0
  182. package/node_modules/@spexcode/spec-core/dist/identity-presets.d.ts +152 -0
  183. package/node_modules/@spexcode/spec-core/dist/identity-presets.js +132 -0
  184. package/node_modules/@spexcode/spec-core/dist/index.d.ts +45 -0
  185. package/node_modules/@spexcode/spec-core/dist/index.js +19 -0
  186. package/node_modules/@spexcode/spec-core/dist/layout.d.ts +183 -0
  187. package/node_modules/@spexcode/spec-core/dist/layout.js +548 -0
  188. package/node_modules/@spexcode/spec-core/dist/process-identity.d.ts +37 -0
  189. package/node_modules/@spexcode/spec-core/dist/process-identity.js +214 -0
  190. package/node_modules/@spexcode/spec-core/dist/project-identity.d.ts +12 -0
  191. package/node_modules/@spexcode/spec-core/dist/project-identity.js +71 -0
  192. package/node_modules/@spexcode/spec-core/dist/project-store.d.ts +3 -0
  193. package/node_modules/@spexcode/spec-core/dist/project-store.js +14 -0
  194. package/node_modules/@spexcode/spec-core/dist/resilience.d.ts +2 -0
  195. package/node_modules/@spexcode/spec-core/dist/resilience.js +40 -0
  196. package/node_modules/@spexcode/spec-core/dist/review/index.d.ts +3 -0
  197. package/node_modules/@spexcode/spec-core/dist/review/index.js +5 -0
  198. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.d.ts +77 -0
  199. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.js +308 -0
  200. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.d.ts +66 -0
  201. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.js +180 -0
  202. package/node_modules/@spexcode/spec-core/dist/review/session.d.ts +4 -0
  203. package/node_modules/@spexcode/spec-core/dist/review/session.js +8 -0
  204. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.d.ts +15 -0
  205. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.js +12 -0
  206. package/node_modules/@spexcode/spec-core/dist/root-lru.d.ts +4 -0
  207. package/{spec-cli/src/root-lru.ts → node_modules/@spexcode/spec-core/dist/root-lru.js} +26 -30
  208. package/node_modules/@spexcode/spec-core/dist/specs.d.ts +117 -0
  209. package/node_modules/@spexcode/spec-core/dist/specs.js +489 -0
  210. package/node_modules/@spexcode/spec-core/package.json +28 -0
  211. package/node_modules/@spexcode/spec-eval/dist/cache.d.ts +10 -0
  212. package/node_modules/@spexcode/spec-eval/dist/cache.js +50 -0
  213. package/node_modules/@spexcode/spec-eval/dist/cli.d.ts +22 -0
  214. package/node_modules/@spexcode/spec-eval/dist/cli.js +981 -0
  215. package/node_modules/@spexcode/spec-eval/dist/evaltab.d.ts +98 -0
  216. package/node_modules/@spexcode/spec-eval/dist/evaltab.js +176 -0
  217. package/node_modules/@spexcode/spec-eval/dist/filing.d.ts +16 -0
  218. package/node_modules/@spexcode/spec-eval/dist/filing.js +36 -0
  219. package/node_modules/@spexcode/spec-eval/dist/freshness.d.ts +48 -0
  220. package/node_modules/@spexcode/spec-eval/dist/freshness.js +799 -0
  221. package/node_modules/@spexcode/spec-eval/dist/host.d.ts +46 -0
  222. package/node_modules/@spexcode/spec-eval/dist/host.js +53 -0
  223. package/node_modules/@spexcode/spec-eval/dist/humanok.d.ts +11 -0
  224. package/node_modules/@spexcode/spec-eval/dist/humanok.js +27 -0
  225. package/node_modules/@spexcode/spec-eval/dist/index.d.ts +4 -0
  226. package/node_modules/@spexcode/spec-eval/dist/index.js +4 -0
  227. package/node_modules/@spexcode/spec-eval/dist/remarks.d.ts +31 -0
  228. package/node_modules/@spexcode/spec-eval/dist/remarks.js +1 -0
  229. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.d.ts +13 -0
  230. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.js +303 -0
  231. package/node_modules/@spexcode/spec-eval/dist/scenarios.d.ts +99 -0
  232. package/node_modules/@spexcode/spec-eval/dist/scenarios.js +650 -0
  233. package/node_modules/@spexcode/spec-eval/dist/sessioneval.d.ts +307 -0
  234. package/node_modules/@spexcode/spec-eval/dist/sessioneval.js +1883 -0
  235. package/node_modules/@spexcode/spec-eval/dist/sidecar.d.ts +55 -0
  236. package/node_modules/@spexcode/spec-eval/dist/sidecar.js +82 -0
  237. package/node_modules/@spexcode/spec-eval/dist/timeline.d.ts +25 -0
  238. package/node_modules/@spexcode/spec-eval/dist/timeline.js +65 -0
  239. package/node_modules/@spexcode/spec-eval/dist/ui-path.d.ts +1 -0
  240. package/node_modules/@spexcode/spec-eval/dist/ui-path.js +2 -0
  241. package/node_modules/@spexcode/spec-eval/package.json +36 -0
  242. package/node_modules/@spexcode/spec-forge/dist/cache.d.ts +29 -0
  243. package/node_modules/@spexcode/spec-forge/dist/cache.js +59 -0
  244. package/node_modules/@spexcode/spec-forge/dist/cli.d.ts +1 -0
  245. package/node_modules/@spexcode/spec-forge/dist/cli.js +100 -0
  246. package/node_modules/@spexcode/spec-forge/dist/drivers/github.d.ts +2 -0
  247. package/node_modules/@spexcode/spec-forge/dist/drivers/github.js +116 -0
  248. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.d.ts +7 -0
  249. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.js +144 -0
  250. package/node_modules/@spexcode/spec-forge/dist/drivers.d.ts +10 -0
  251. package/node_modules/@spexcode/spec-forge/dist/drivers.js +83 -0
  252. package/node_modules/@spexcode/spec-forge/dist/index.d.ts +4 -0
  253. package/node_modules/@spexcode/spec-forge/dist/index.js +4 -0
  254. package/node_modules/@spexcode/spec-forge/dist/links.d.ts +15 -0
  255. package/node_modules/@spexcode/spec-forge/dist/links.js +65 -0
  256. package/node_modules/@spexcode/spec-forge/dist/needs-eval.d.ts +10 -0
  257. package/node_modules/@spexcode/spec-forge/dist/needs-eval.js +20 -0
  258. package/node_modules/@spexcode/spec-forge/dist/port.d.ts +53 -0
  259. package/node_modules/@spexcode/spec-forge/dist/port.js +1 -0
  260. package/node_modules/@spexcode/spec-forge/dist/resident.d.ts +7 -0
  261. package/node_modules/@spexcode/spec-forge/dist/resident.js +43 -0
  262. package/node_modules/@spexcode/spec-forge/package.json +32 -0
  263. package/package.json +33 -19
  264. package/spec-cli/bin/spex.mjs +0 -69
  265. package/spec-cli/src/anchors.ts +0 -728
  266. package/spec-cli/src/attach.ts +0 -43
  267. package/spec-cli/src/claude-headless.ts +0 -321
  268. package/spec-cli/src/cli.ts +0 -1258
  269. package/spec-cli/src/client.ts +0 -414
  270. package/spec-cli/src/cockpit.ts +0 -43
  271. package/spec-cli/src/codex-runtime-generations.ts +0 -646
  272. package/spec-cli/src/commit-surgery.ts +0 -68
  273. package/spec-cli/src/contract-filter.ts +0 -202
  274. package/spec-cli/src/delivery-queue.ts +0 -165
  275. package/spec-cli/src/doctor.ts +0 -516
  276. package/spec-cli/src/execution-trace.ts +0 -444
  277. package/spec-cli/src/file-write.ts +0 -22
  278. package/spec-cli/src/gateway-auth.ts +0 -181
  279. package/spec-cli/src/gateway-hub.ts +0 -358
  280. package/spec-cli/src/gateway.ts +0 -461
  281. package/spec-cli/src/git.ts +0 -2556
  282. package/spec-cli/src/graph.ts +0 -271
  283. package/spec-cli/src/graphCache.ts +0 -710
  284. package/spec-cli/src/graphDelta.ts +0 -77
  285. package/spec-cli/src/graphStream.ts +0 -1019
  286. package/spec-cli/src/harness-select.ts +0 -77
  287. package/spec-cli/src/harness.ts +0 -3025
  288. package/spec-cli/src/headless-controller.ts +0 -63
  289. package/spec-cli/src/help.ts +0 -492
  290. package/spec-cli/src/host-resources.ts +0 -762
  291. package/spec-cli/src/host.ts +0 -611
  292. package/spec-cli/src/identity-presets.d.ts +0 -13
  293. package/spec-cli/src/identity-presets.js +0 -138
  294. package/spec-cli/src/index.ts +0 -818
  295. package/spec-cli/src/init.ts +0 -258
  296. package/spec-cli/src/issues-cli.ts +0 -276
  297. package/spec-cli/src/issues.ts +0 -237
  298. package/spec-cli/src/layout.ts +0 -640
  299. package/spec-cli/src/lint.ts +0 -488
  300. package/spec-cli/src/localIssues.ts +0 -538
  301. package/spec-cli/src/materialize.ts +0 -417
  302. package/spec-cli/src/mentions.ts +0 -81
  303. package/spec-cli/src/opencode-headless.ts +0 -205
  304. package/spec-cli/src/pi-headless.ts +0 -153
  305. package/spec-cli/src/plugin-harness.ts +0 -157
  306. package/spec-cli/src/process-identity.ts +0 -207
  307. package/spec-cli/src/project-identity.ts +0 -73
  308. package/spec-cli/src/project-store.ts +0 -17
  309. package/spec-cli/src/pty-bridge.ts +0 -396
  310. package/spec-cli/src/pty-helper.mjs +0 -96
  311. package/spec-cli/src/pty-native-helper.mjs +0 -22
  312. package/spec-cli/src/ranker.ts +0 -191
  313. package/spec-cli/src/reaper.ts +0 -125
  314. package/spec-cli/src/resilience.ts +0 -41
  315. package/spec-cli/src/reviewSnapshot.ts +0 -28
  316. package/spec-cli/src/reviews.ts +0 -434
  317. package/spec-cli/src/runtime-guard.ts +0 -35
  318. package/spec-cli/src/runtime-ownership.ts +0 -88
  319. package/spec-cli/src/search.bench.mjs +0 -80
  320. package/spec-cli/src/search.ts +0 -63
  321. package/spec-cli/src/session-cursors.ts +0 -91
  322. package/spec-cli/src/session-execution.ts +0 -68
  323. package/spec-cli/src/session-files.ts +0 -121
  324. package/spec-cli/src/session-follow.ts +0 -182
  325. package/spec-cli/src/session-reparent.ts +0 -33
  326. package/spec-cli/src/session-timeline.ts +0 -247
  327. package/spec-cli/src/session-web.ts +0 -135
  328. package/spec-cli/src/sessions.ts +0 -3883
  329. package/spec-cli/src/sh.ts +0 -3
  330. package/spec-cli/src/slash-commands.ts +0 -318
  331. package/spec-cli/src/source-files.ts +0 -104
  332. package/spec-cli/src/specs.ts +0 -498
  333. package/spec-cli/src/supervise.ts +0 -245
  334. package/spec-cli/src/tree.ts +0 -118
  335. package/spec-cli/src/tsx-bin.ts +0 -18
  336. package/spec-cli/src/uninstall.ts +0 -171
  337. package/spec-cli/src/uploads.ts +0 -253
  338. package/spec-cli/src/worktree-sources.ts +0 -42
  339. package/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +0 -8
  340. package/spec-dashboard/dist/assets/App-B6IbFbGu.js +0 -2
  341. package/spec-dashboard/dist/assets/Dashboard-C5ap-Sga.css +0 -1
  342. package/spec-dashboard/dist/assets/Dashboard-_sDk7Rcg.js +0 -27
  343. package/spec-dashboard/dist/assets/EvalsPage-BT357Lyt.js +0 -2
  344. package/spec-dashboard/dist/assets/IssuesPage-BG9rNOgV.js +0 -1
  345. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  346. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  347. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  348. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  349. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  350. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  351. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  352. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  353. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  354. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  355. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  356. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  357. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  358. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  359. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  360. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  361. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  362. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  363. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  364. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  365. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  366. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  367. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  368. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  369. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  370. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  371. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  372. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  373. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  374. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  375. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  376. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  377. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  378. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  379. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  380. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  381. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  382. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  383. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  384. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  385. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  386. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  387. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  388. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  389. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  390. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  391. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  392. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  393. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  394. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  395. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  396. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  397. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  398. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  399. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  400. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  401. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  402. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  403. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  404. package/spec-dashboard/dist/assets/MobileApp-D9yPMR3A.js +0 -2
  405. package/spec-dashboard/dist/assets/Modal-B3EcgeA3.js +0 -1
  406. package/spec-dashboard/dist/assets/PageScroll-CNZOugWV.js +0 -1
  407. package/spec-dashboard/dist/assets/ProjectsPage-C2CRHmvs.js +0 -1
  408. package/spec-dashboard/dist/assets/SessionInterface-6GBZ9nXN.css +0 -32
  409. package/spec-dashboard/dist/assets/SessionInterface-DOEjuT3l.js +0 -40
  410. package/spec-dashboard/dist/assets/SessionWindow-1nYgZ4CL.js +0 -1
  411. package/spec-dashboard/dist/assets/Settings-7WeTJn0V.js +0 -1
  412. package/spec-dashboard/dist/assets/Thread-CEbzAFQn.js +0 -13
  413. package/spec-dashboard/dist/assets/bindings-BC9vqpYU.js +0 -1
  414. package/spec-dashboard/dist/assets/data-SlvxNA2r.js +0 -1
  415. package/spec-dashboard/dist/assets/index-DLVeOHL-.js +0 -41
  416. package/spec-dashboard/dist/assets/index-DYLGfPjx.css +0 -1
  417. package/spec-dashboard/dist/assets/launch-Cp579UoJ.css +0 -1
  418. package/spec-dashboard/dist/assets/launch-yxCYr64x.js +0 -276
  419. package/spec-dashboard/dist/assets/sessionSurface--7l69h4F.js +0 -1
  420. package/spec-dashboard/dist/index.html +0 -29
  421. package/spec-dashboard/src/reviewFilters.js +0 -322
  422. package/spec-dashboard/src/reviewQuery.js +0 -174
  423. package/spec-dashboard/src/session.js +0 -199
  424. package/spec-eval/src/cache.ts +0 -57
  425. package/spec-eval/src/cli.ts +0 -894
  426. package/spec-eval/src/evaltab.ts +0 -264
  427. package/spec-eval/src/filing.ts +0 -39
  428. package/spec-eval/src/freshness.ts +0 -836
  429. package/spec-eval/src/humanok.ts +0 -28
  430. package/spec-eval/src/scenariofresh.ts +0 -244
  431. package/spec-eval/src/scenarios.ts +0 -672
  432. package/spec-eval/src/sessioneval.ts +0 -2220
  433. package/spec-eval/src/sidecar.ts +0 -93
  434. package/spec-eval/src/timeline.ts +0 -54
  435. package/spec-forge/src/__fixtures__/github-forge.json +0 -63
  436. package/spec-forge/src/cache.ts +0 -66
  437. package/spec-forge/src/cli.ts +0 -99
  438. package/spec-forge/src/drivers/github.ts +0 -132
  439. package/spec-forge/src/drivers/gitlab.ts +0 -153
  440. package/spec-forge/src/drivers.ts +0 -73
  441. package/spec-forge/src/links.ts +0 -72
  442. package/spec-forge/src/needs-eval.ts +0 -29
  443. package/spec-forge/src/port.ts +0 -36
  444. package/spec-forge/src/resident.ts +0 -46
  445. /package/{spec-cli → node_modules/@spexcode/spec-cli}/README.md +0 -0
  446. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-0.5.2-eef1.fixture +0 -0
  447. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-sed-v0.fixture +0 -0
  448. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/commit-msg +0 -0
  449. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-checkout +0 -0
  450. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-merge +0 -0
  451. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/pre-commit +0 -0
  452. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/prepare-commit-msg +0 -0
  453. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/reference-transaction +0 -0
  454. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/extract/spec.md +0 -0
  455. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/regroup/spec.md +0 -0
  456. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/rename/spec.md +0 -0
  457. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/spec.md +0 -0
  458. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/tidy/spec.md +0 -0
  459. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/comment-altitude/spec.md +0 -0
  460. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/idle.sh +0 -0
  461. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/spec.md +0 -0
  462. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/mark-active.sh +0 -0
  463. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/spec.md +0 -0
  464. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/fail.sh +0 -0
  465. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/spec.md +0 -0
  466. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec.md +0 -0
  467. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec.md +0 -0
  468. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec.md +0 -0
  469. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +0 -0
  470. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/forge-link/spec.md +0 -0
  471. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +0 -0
  472. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +0 -0
  473. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/spec.md +0 -0
  474. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/digest.mjs +0 -0
  475. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/spec.md +0 -0
  476. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/spec.md +0 -0
  477. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/spec.md +0 -0
  478. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/spec.md +0 -0
  479. /package/{spec-cli → node_modules/@spexcode/spec-core}/templates/spexcode.json +0 -0
@@ -1,258 +0,0 @@
1
- import { existsSync, mkdirSync, copyFileSync, readFileSync, readdirSync, renameSync, rmSync, statSync, chmodSync, writeFileSync } from 'node:fs'
2
- import { join, resolve, relative, dirname } from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
- import { execFileSync } from 'node:child_process'
5
- import { readConfig, readJsonConfig } from './layout.js'
6
- import { resolveHarnessTargets, parseHarnessFlag, NATIVE_HARNESS_IDS } from './harness-select.js'
7
- import { gitBinary } from './git.js'
8
-
9
- // this file lives at <pkgRoot>/src/init.ts, so `..` is the package root — the same derivation the
10
- // launch paths use, never a hardcoded repo path (so a relocated/installed package still finds its data).
11
- const pkgRoot = fileURLToPath(new URL('..', import.meta.url))
12
- const TEMPLATES = join(pkgRoot, 'templates')
13
- const MANAGED_HOOK_HEADER = '# spexcode-managed-hook-v1'
14
-
15
- function isManagedHook(path: string): boolean {
16
- const source = readFileSync(path, 'utf8')
17
- return source.split('\n').slice(0, 4).includes(MANAGED_HOOK_HEADER)
18
- }
19
-
20
- function replaceHook(source: string, dest: string): void {
21
- const temp = `${dest}.spexcode-${process.pid}`
22
- try {
23
- copyFileSync(source, temp)
24
- chmodSync(temp, 0o755)
25
- renameSync(temp, dest)
26
- } finally {
27
- rmSync(temp, { force: true })
28
- }
29
- }
30
-
31
- // the cumulative preset chain, lean → cautious (see [[init-preset]]). `default` is the live `.plugins`
32
- // instance set (planted from templates/spec); a higher tier would be a SEPARATE package under
33
- // templates/presets/<tier>/ that seeding stacks ON TOP — a superset. No non-default tier ships today
34
- // (the `careful` package was retired); the chain mechanism stays for when one earns its keep.
35
- // Selection matters ONLY here at seed time; the running repo just
36
- // walks whatever `.plugins` ended up planted, so there is no launcher-side preset gate.
37
- const PRESET_TIERS = ['default'] as const
38
- const presetRank = (name: string): number => (PRESET_TIERS as readonly string[]).indexOf(name)
39
-
40
- // recursively copy srcDir -> destDir, NEVER overwriting an existing file. Returns the repo-relative
41
- // paths of files actually written (so the caller can report exactly what was planted vs already there).
42
- function copyTreeNoClobber(srcDir: string, destDir: string, base: string): string[] {
43
- const written: string[] = []
44
- mkdirSync(destDir, { recursive: true })
45
- for (const e of readdirSync(srcDir, { withFileTypes: true })) {
46
- const src = join(srcDir, e.name)
47
- const dest = join(destDir, e.name)
48
- if (e.isDirectory()) {
49
- written.push(...copyTreeNoClobber(src, dest, base))
50
- } else if (existsSync(dest)) {
51
- // additive only — a pre-existing file is the user's, leave it untouched.
52
- continue
53
- } else {
54
- copyFileSync(src, dest)
55
- written.push(relative(base, dest))
56
- }
57
- }
58
- return written
59
- }
60
-
61
- // resolve the target repo's git hooks dir the same way scripts/install-hooks.sh does — the COMMON dir's
62
- // hooks/ (shared across all worktrees). Returns null (with a loud reason) when <dir> isn't a git repo.
63
- function resolveHooksDir(dir: string): string | null {
64
- try {
65
- const common = execFileSync(gitBinary(process.env), ['-C', dir, 'rev-parse', '--path-format=absolute', '--git-common-dir'], {
66
- encoding: 'utf8',
67
- stdio: ['ignore', 'pipe', 'ignore'], // swallow git's own "fatal: not a git repository" — our warning is the signal
68
- }).trim()
69
- return join(common, 'hooks')
70
- } catch {
71
- return null
72
- }
73
- }
74
-
75
- // Detect once, at adoption, while the root checkout still names the branch being adopted. Steady-state
76
- // layout never re-derives trunk identity from a mutable checkout (an ordinary `git switch node/x` must not
77
- // turn that feature branch into trunk).
78
- function adoptionMainBranch(dir: string): string {
79
- try {
80
- const common = execFileSync(gitBinary(process.env), ['-C', dir, 'rev-parse', '--path-format=absolute', '--git-common-dir'], { encoding: 'utf8' }).trim()
81
- const branch = execFileSync(gitBinary(process.env), ['-C', dirname(common), 'symbolic-ref', '--short', 'HEAD'], { encoding: 'utf8' }).trim()
82
- if (branch) return branch
83
- } catch { /* render the one product-level repair below */ }
84
- const error = new Error('cannot determine the source-of-truth branch at adoption — check out the trunk in the root checkout, or set "mainBranch" in spexcode.json before re-running `spex init`')
85
- error.name = 'ConfigError'
86
- throw error
87
- }
88
-
89
- export async function specInit(targetArg: string | undefined, presetArg?: string, harnessArg?: string): Promise<void> {
90
- const targetDir = resolve(targetArg ?? process.cwd())
91
-
92
- // the preset the NEW adopter gets — `--preset <name>` wins, else an existing target spexcode.json's
93
- // `preset` field, else the lean `default`. Validated loudly against the chain (an unknown name would
94
- // otherwise seed silently). A non-default tier stacks its template package on top of the default set below.
95
- const selected = (presetArg ?? '').trim() || (readConfig(targetDir).preset ?? '').trim() || 'default'
96
- if (!(PRESET_TIERS as readonly string[]).includes(selected)) {
97
- console.error(`spex init: unknown preset '${selected}'. Valid presets (cumulative, lean→cautious): ${PRESET_TIERS.join(', ')}.`)
98
- process.exit(1)
99
- }
100
-
101
- // SpexCode is git-backed: git IS the version database and the hooks live in `.git`. A non-git target
102
- // would leave a HALF-STATE — specs on disk but no version history, no hooks, no harness shims, no
103
- // sessions. So fail LOUD before writing anything, rather than seeding debris and warning past it. We do
104
- // NOT `git init` for them: creating a repo is a side effect beyond init's remit (a subdir, a dir not
105
- // meant as a repo root), and `git init` is one deliberate command.
106
- try {
107
- execFileSync(gitBinary(process.env), ['-C', targetDir, 'rev-parse', '--is-inside-work-tree'], { stdio: ['ignore', 'ignore', 'ignore'] })
108
- } catch {
109
- console.error(`spex init: ${targetDir} is not a git repository. SpexCode is git-backed (git is the version database; the hooks live in .git). Run \`git init\` there first, then \`spex init\`.`)
110
- process.exit(1)
111
- }
112
-
113
- // the harness DELIVERY TARGET set ([[harness-select]]) is a REQUIRED, explicit choice — `--harness <ids>`
114
- // stamps it into spexcode.json; absent the flag, a pre-existing explicit `harnesses` field IS the choice.
115
- // Neither → abort BEFORE writing anything: with many harnesses, a silent "deliver to all" would litter the
116
- // adopter's tree (and global tool configs) with artifacts for harnesses they never installed. Legality
117
- // (unknown ids, plugin exclusivity, empty set) fails loud here too, not as a soft materialize warning.
118
- const flagRaw = (harnessArg ?? '').trim() ? parseHarnessFlag(harnessArg!.trim()) : null
119
- const chosenHarnesses = flagRaw ?? readConfig(targetDir).harnesses ?? null
120
- if (chosenHarnesses === null) {
121
- console.error(`spex init: --harness is required — name the harness(es) this repo delivers into, e.g. \`spex init --harness claude\`. Known native ids: ${NATIVE_HARNESS_IDS.join(', ')} (comma-separate several; a plugin bundle: --harness plugin:<folder>). A pre-existing spexcode.json "harnesses" field also satisfies this.`)
122
- process.exit(1)
123
- }
124
- try {
125
- resolveHarnessTargets(chosenHarnesses)
126
- } catch (e) {
127
- console.error(`spex init: ${(e as Error).message}`)
128
- process.exit(1)
129
- }
130
-
131
- if (!existsSync(targetDir)) mkdirSync(targetDir, { recursive: true })
132
- console.log(`spex init → ${targetDir}`)
133
-
134
- // 1. seed the spec tree: templates/spec/* -> <dir>/.spec/* (an existing .spec aborts this phase loudly).
135
- const specDest = join(targetDir, '.spec')
136
- if (existsSync(specDest)) {
137
- console.warn(`• .spec already exists at ${specDest} — skipping spec scaffold (won't overwrite an existing tree).`)
138
- } else {
139
- const planted = copyTreeNoClobber(join(TEMPLATES, 'spec'), specDest, targetDir)
140
- console.log(`✓ seeded ${planted.length} spec file(s) under .spec/ (root 'project' node + default .plugins)`)
141
- // 1a. stack the selected preset's package(s) ON TOP of the default set — cumulative, so every tier from
142
- // just above `default` up to the selection is planted. Each lives under templates/presets/<tier>/ mirroring
143
- // the default layout (its `.plugins/<plugin>` lands in the seeded project node's `.plugins`). See [[init-preset]].
144
- for (let r = 1; r <= presetRank(selected); r++) {
145
- const tier = PRESET_TIERS[r]
146
- const pkg = join(TEMPLATES, 'presets', tier)
147
- if (!existsSync(pkg)) { console.warn(`• preset '${tier}' has no package at ${pkg} — skipped.`); continue }
148
- const added = copyTreeNoClobber(pkg, join(specDest, 'project'), targetDir)
149
- console.log(`✓ seeded preset '${tier}' (${added.length} file(s)) into .plugins`)
150
- }
151
- }
152
-
153
- // 1b. plant a starter spexcode.json (the lint/layout knob) carrying the CHOSEN `harnesses` set. The
154
- // template ships launchers for every native harness; seeding keeps only the SELECTED ones (a launcher for
155
- // a tool the adopter didn't pick is exactly the litter --harness exists to prevent) — a plugin-only
156
- // selection keeps them all, since the bundle serves the HOST agent while dispatched sessions still need a
157
- // launcher. The success message reports values read back from the planted file, never restated literals.
158
- const cfgDest = join(targetDir, 'spexcode.json')
159
- const nativeChosen = (chosenHarnesses as unknown[]).filter((m): m is string => typeof m === 'string')
160
- if (existsSync(cfgDest)) {
161
- const cfg = (readJsonConfig(cfgDest) ?? {}) as Record<string, unknown>
162
- const stampedBranch = typeof cfg.mainBranch !== 'string' || !cfg.mainBranch.trim()
163
- if (stampedBranch) cfg.mainBranch = adoptionMainBranch(targetDir)
164
- if (flagRaw) cfg.harnesses = flagRaw
165
- if (flagRaw || stampedBranch) {
166
- writeFileSync(cfgDest, JSON.stringify(cfg, null, 2) + '\n')
167
- console.log(`✓ stamped ${[
168
- flagRaw ? `"harnesses": ${JSON.stringify(flagRaw)}` : '',
169
- stampedBranch ? `"mainBranch": ${JSON.stringify(cfg.mainBranch)}` : '',
170
- ].filter(Boolean).join(' and ')} into the existing spexcode.json (other fields untouched)`)
171
- } else {
172
- console.warn(`• spexcode.json already exists at ${cfgDest} — left untouched (harnesses: ${JSON.stringify(chosenHarnesses)}).`)
173
- }
174
- } else {
175
- const cfg = (readJsonConfig(join(TEMPLATES, 'spexcode.json')) ?? {}) as Record<string, any>
176
- cfg.harnesses = chosenHarnesses
177
- cfg.mainBranch = adoptionMainBranch(targetDir)
178
- if (nativeChosen.length && cfg.sessions?.launchers) {
179
- cfg.sessions.launchers = Object.fromEntries(
180
- Object.entries(cfg.sessions.launchers as Record<string, { harness?: string }>).filter(([, l]) => nativeChosen.includes(l.harness ?? 'claude')))
181
- const names = Object.keys(cfg.sessions.launchers)
182
- if (names.length) cfg.sessions.defaultLauncher = names[0]
183
- }
184
- writeFileSync(cfgDest, JSON.stringify(cfg, null, 2) + '\n')
185
- const roots = JSON.stringify(readJsonConfig(cfgDest)?.lint?.governedRoots ?? null)
186
- console.log(`✓ planted spexcode.json — mainBranch ${JSON.stringify(cfg.mainBranch)}, harnesses ${JSON.stringify(chosenHarnesses)}, launchers ${JSON.stringify(Object.keys(cfg.sessions?.launchers ?? {}))}; lint.governedRoots starts as ${roots} (the whole git-tracked tree, tests excluded)`)
187
- }
188
-
189
- // 2. install the git hooks. Unknown existing hooks are user-owned and stay byte-identical. An exact
190
- // SpexCode snapshot is refreshed because a multi-hook protocol cannot mix old and new generations.
191
- const hooksDir = resolveHooksDir(targetDir)
192
- if (!hooksDir) {
193
- console.warn(`• ${targetDir} is not a git repository — skipped hook install. Run \`git init\` there, then \`spex init\` again (or \`npm run hooks\`).`)
194
- } else {
195
- mkdirSync(hooksDir, { recursive: true })
196
- const hooksSrc = join(TEMPLATES, 'hooks')
197
- const installed: string[] = []
198
- const refreshed: string[] = []
199
- for (const e of readdirSync(hooksSrc, { withFileTypes: true })) {
200
- if (!e.isFile()) continue
201
- const source = join(hooksSrc, e.name)
202
- const dest = join(hooksDir, e.name)
203
- if (existsSync(dest)) {
204
- if (readFileSync(dest).equals(readFileSync(source))) continue
205
- if (isManagedHook(dest)) {
206
- replaceHook(source, dest)
207
- refreshed.push(e.name)
208
- } else {
209
- console.warn(`• user hook ${e.name} already exists in ${hooksDir} — left untouched.`)
210
- }
211
- continue
212
- }
213
- copyFileSync(source, dest)
214
- chmodSync(dest, 0o755)
215
- installed.push(e.name)
216
- }
217
- if (installed.length) console.log(`✓ installed git hooks (${installed.join(', ')}) → ${hooksDir}`)
218
- if (refreshed.length) console.log(`✓ refreshed SpexCode hook snapshots (${refreshed.join(', ')}) → ${hooksDir}`)
219
- }
220
-
221
- // 2c. MATERIALIZE the harness-discovered artifacts so a USER-self-launched harness works with zero further
222
- // steps. Runs with cwd = the target so the loaders read the just-seeded
223
- // .plugins. Idempotent — the planted git hooks (pre-commit/post-checkout/post-merge) keep it fresh
224
- // thereafter on the git-native anchors ([[commit-surgery]]); no harness event ever triggers a materialize.
225
- const prevCwd = process.cwd()
226
- try {
227
- process.chdir(targetDir)
228
- const { materialize } = await import('./materialize.js')
229
- const result = materialize(targetDir)
230
- const display = (path: string) => {
231
- const local = relative(targetDir, path)
232
- return local && local !== '..' && !local.startsWith('../') && !local.startsWith('..\\') ? local : path
233
- }
234
- console.log(`✓ materialized harness artifacts (${result.planted.map((a) => `${a.kind}: ${display(a.path)}`).join(', ')})`)
235
- } catch (e) {
236
- console.warn(`• materialize skipped (${(e as Error).message}) — run \`spex materialize\` once the packages are installed.`)
237
- } finally {
238
- process.chdir(prevCwd)
239
- }
240
-
241
- // 3. next steps — what the human must do to bring the instance to life. The governedRoots line reads the
242
- // LIVE value (the planted starter's, or a pre-existing config's) so it can never drift from what's on disk.
243
- const rootsNow = JSON.stringify(readJsonConfig(cfgDest)?.lint?.governedRoots ?? null)
244
- console.log(`
245
- Next steps:
246
- 1. The seeded .spec/ tree and spexcode.json are project source of truth: add and commit them. Generated
247
- harness artifacts are machine-local and can stay untracked.
248
- 2. Edit .spec/project/spec.md to describe YOUR project, then grow child nodes beneath it.
249
- 3. lint.governedRoots in spexcode.json (currently ${rootsNow}) names what \`spex spec lint\` governs —
250
- ["."] governs the whole git-tracked tree (tests excluded); narrow it to explicit source roots
251
- when you want a curated graph.
252
- 4. Start the backend and open the dashboard:
253
- spex serve # http://localhost:8787
254
- 5. \`spex spec lint\` should report 0 errors. Coverage warnings are your adoption TODO (source files no
255
- spec node claims yet). You're adopting SpexCode — the spec tree is now ground truth.
256
- (On a fresh CLONE, re-run \`spex init\` — git never clones .git/hooks/, and the harness shims are
257
- gitignored machine-local files that regenerate per-machine.)`)
258
- }
@@ -1,276 +0,0 @@
1
- import { readFileSync } from 'node:fs'
2
- import { closeIssue, createIssue, findIssue, isRemark, mergedIssues, promote, type ForgeSlice, type Issue } from './issues.js'
3
- import { FORGE_DRIVERS, forgeDriverFor, resolveForgeHost } from '../../spec-forge/src/drivers.js'
4
- import { currentSession, issuesEnabled, reply, resolveRemark, retractRemark } from './localIssues.js'
5
- import { summarizeLoopIn } from './mentions.js'
6
- import { loadSpecsLite } from './specs.js'
7
-
8
- // @@@ issues-cli - the `spex issue` / `spex remark` CLI surface: argv parsing, console output, exit codes.
9
- // It lives ABOVE the eval layer, which is the whole point. These handlers used to sit in `issues.ts` and
10
- // `localIssues.ts` — modules the eval package imports — and a CLI surface is by definition the topmost layer,
11
- // so hosting one down there gave those files two altitudes at once. That is what held the spec/eval package
12
- // cycle: the loop-in's candidate resolution needs eval knowledge, its only callers were these handlers, and
13
- // they could not reach eval from below it. Nothing here is new logic; it is the same surface at its own height.
14
- //
15
- // It is NOT merged into `cli.ts`: that file is the thin dispatch hub ([[cli-surface]]) whose eighty lazy
16
- // `await import(...)` sites keep one invocation from loading every verb's module. Moving 265 lines of verb
17
- // implementation there would have traded one two-altitude module for another. The hub gains one lazy line
18
- // pointing here instead.
19
-
20
- const fl = (args: string[], name: string): string | undefined => {
21
- const i = args.indexOf(`--${name}`)
22
- return i >= 0 ? args[i + 1] : undefined
23
- }
24
- const hasFlag = (args: string[], name: string) => args.includes(`--${name}`)
25
-
26
- // the CLI's live forge pull — `ls` and `show` own their freshness (a live driver read), degrading LOUDLY
27
- // to local-only (one stderr note) when the forge is unreachable: local reading never hostages on a network.
28
- async function liveForgeSlice(verb: string): Promise<ForgeSlice | null> {
29
- try {
30
- const host = resolveForgeHost()
31
- const driver = forgeDriverFor(host)
32
- if (!driver) throw new Error(`no driver for this repo's forge host '${host}' (known: ${FORGE_DRIVERS.map((d) => d.host).join(', ')})`)
33
- const [issues, prs] = await Promise.all([driver.listIssues(), driver.listPRs()])
34
- return { host: driver.host, state: { issues, prs } }
35
- } catch (e) {
36
- console.error(`spex issue ${verb}: forge unreachable — local only (${e instanceof Error ? e.message.split('\n')[0] : e})`)
37
- return null
38
- }
39
- }
40
-
41
- // the single-issue read behind `spex issue show` AND `GET /api/issues/:id` — find the thread in the SAME
42
- // merged, eval-remark-free read every issue surface consumes (never a second lookup path: an eval-remark
43
- // thread is not an issue, so `show` can't see one either). A local id needs no forge slice; a forge id
44
- // (`<host>#<n>`) reads from the caller-supplied slice (live pull on the CLI, resident cache on the server).
45
-
46
- function renderIssue(t: Issue): string {
47
- const L: string[] = []
48
- L.push(`${t.concern} [${t.id}]`)
49
- L.push(` ${[t.store, t.status, t.nodes.length ? `re: ${t.nodes.join(', ')}` : '', t.by ? `by ${t.by}` : '', t.created].filter(Boolean).join(' · ')}`)
50
- if (t.url) L.push(` ${t.url}`)
51
- if (t.evidence.length) L.push(` evidence: ${t.evidence.join(', ')}`)
52
- L.push('', t.body)
53
- for (const r of t.replies) {
54
- L.push('', `── ${isRemark(r) ? `remark ${t.id}#${r.rid}${r.resolved ? ` (resolved by ${r.resolvedBy})` : ' (unresolved)'}` : 'reply'}: ${r.by} @ ${r.at} ──`)
55
- L.push(r.body)
56
- }
57
- return L.join('\n')
58
- }
59
-
60
- // `spex issue <verb>` — the ONE issue surface, a noun drawer ([[cli-surface]]). `ls` is THE read over
61
- // every store: the drain view a supervisor/human works from, `[--node id] [--store local|<host>] [--all]
62
- // [--json]`; `show <id>` is the single-thread detail (the same read GET /api/issues/:id serves). The
63
- // write verbs (open|reply — localIssues.ts) are store-routed (`open --store <host>` / a `<host>#<n>` id
64
- // go through the driver); `close` is the store-routed lifecycle verb (the SAME closeIssue the dashboard's
65
- // Close button calls); `promote` is the one cross-store verb; `links` is the read-only forge→spec trace
66
- // (spec-forge). The list imposes NO salience ranking — replies are a signal the drain WEIGHS by judgment,
67
- // never an automatic priority order. The forge slice is a LIVE pull that degrades loudly to local-only.
68
- // (`nudge` left this drawer for `spex internal nudge` — only the post-merge hook calls it; the old
69
- // on|off|status toggle verbs are gone — the switch is the `issues.enabled` settings key.)
70
- export async function runIssues(args: string[]): Promise<number> {
71
- // the drawer's READ verbs (ls/show) surface a store failure exactly as the writes do
72
- // ([[issues-store-rename]]'s both-exist teeth): one clean `spex issue: <message>` line + exit 1, never a
73
- // raw stack — the message carries the repair, the stack is internals. The verbs that already catch with
74
- // a more specific prefix (open/reply/close/promote) return before this guard ever sees their errors.
75
- try { return await issueVerbs(args) }
76
- catch (e) { console.error(`spex issue: ${e instanceof Error ? e.message : e}`); return 1 }
77
- }
78
- async function issueVerbs(args: string[]): Promise<number> {
79
- if (ISSUE_WRITE_SUBS.has(args[0])) return runIssueWrite(args)
80
- if (args[0] === 'on' || args[0] === 'off' || args[0] === 'status') {
81
- // v0.3.0 signpost — report the new home, never run ([[cli-surface]]: a removed spelling only points).
82
- console.error(`spex: \`spex issue ${args[0]}\` was removed in v0.3.0 — the switch is the \`issues.enabled\` key in spexcode.json (edit the JSON; \`spex guide settings\` documents it, \`spex doctor\` reports its state)`)
83
- return 2
84
- }
85
- if (args[0] === 'show') {
86
- const id = args[1]
87
- if (!id || id.startsWith('--')) { console.error('usage: spex issue show <issue-id> [--json] (a local id, or a forge id like github#12)'); return 2 }
88
- const nodeIds = loadSpecsLite().map((s) => s.id)
89
- const t = findIssue(id, id.includes('#') ? await liveForgeSlice('show') : null, nodeIds)
90
- if (!t) { console.error(`spex issue show: no issue '${id}' (see \`spex issue ls --all\`)`); return 1 }
91
- console.log(hasFlag(args, 'json') ? JSON.stringify(t, null, 2) : renderIssue(t))
92
- return 0
93
- }
94
- if (args[0] === 'links') {
95
- const { runIssueLinks } = await import('../../spec-forge/src/cli.js')
96
- return runIssueLinks(args.slice(1))
97
- }
98
- if (args[0] === 'close') {
99
- // the CLI leg of the ONE close verb ([[issues]] closeIssue — the same routing POST /api/issues/:id/close
100
- // runs): a local id resolves the thread `landed`, a forge id (`<host>#<n>`) closes the remote issue
101
- // through the driver. Lifecycle on the issue object, never node state.
102
- const id = args[1]
103
- if (!id || id.startsWith('--')) { console.error('usage: spex issue close <issue-id> (a local id, or a forge id like github#12)'); return 2 }
104
- try {
105
- const r = await closeIssue(id)
106
- console.log(r.store === 'local'
107
- ? `closed '${id}' — local thread landed`
108
- : `closed '${id}' on ${r.store}${r.url ? ` ${r.url}` : ''}`)
109
- return 0
110
- } catch (e) {
111
- console.error(`spex issue close: ${e instanceof Error ? e.message : e}`)
112
- return 1
113
- }
114
- }
115
- if (args[0] === 'promote') {
116
- const id = args[1]
117
- if (!id || id.startsWith('--')) { console.error('usage: spex issue promote <local-issue-id>'); return 2 }
118
- try {
119
- const r = await promote(id)
120
- console.log(`promoted '${id}' → ${r.host}#${r.number} ${r.url}\n local thread closed landed (permalink recorded in its reply trail)`)
121
- return 0
122
- } catch (e) {
123
- console.error(`spex issue promote: ${e instanceof Error ? e.message : e}`)
124
- return 1
125
- }
126
- }
127
- if (args[0] !== 'ls') {
128
- console.error(`spex issue: unknown verb '${args[0]}' — ls | show | open | reply | close | promote | links (spex help issue)`)
129
- return 2
130
- }
131
- args = args.slice(1)
132
- const nodeIds = loadSpecsLite().map((s) => s.id)
133
- const forge = await liveForgeSlice('ls')
134
- let issues = mergedIssues(forge, nodeIds)
135
- const node = fl(args, 'node')
136
- const store = fl(args, 'store')
137
- if (node) issues = issues.filter((p) => p.nodes.includes(node))
138
- if (store) issues = issues.filter((p) => p.store === store)
139
- if (!hasFlag(args, 'all')) issues = issues.filter((p) => p.status === 'open')
140
- if (hasFlag(args, 'json')) { console.log(JSON.stringify(issues, null, 2)); return 0 }
141
- if (!issues.length) { console.log(node ? `no issues for node '${node}'` : 'no open issues'); return 0 }
142
- console.log(`issues — ${issues.length} ${hasFlag(args, 'all') ? 'total' : 'open'}${store ? ` in '${store}'` : ''}${node ? ` for '${node}'` : ''}\n`)
143
- for (const p of issues) {
144
- const tags = [p.store, p.status !== 'open' ? `[${p.status}]` : '', p.nodes.length ? `re: ${p.nodes.join(', ')}` : '', p.by ? `by ${p.by}` : ''].filter(Boolean).join(' · ')
145
- console.log(`• ${p.concern} [${p.id}]`)
146
- console.log(` ${tags}`)
147
- if (p.replies.length) console.log(` ${p.replies.length} reply(ies) in thread`)
148
- if (p.url) console.log(` ${p.url}`)
149
- }
150
- if (!issuesEnabled()) console.log('\n(the issues workflow is OFF — set `"issues": { "enabled": true }` in spexcode.json to re-enable writes/nudges)')
151
- return 0
152
- }
153
-
154
- const VALUE_FLAGS = new Set(['--node', '--body', '--evidence', '--scenario', '--code-sha', '--store'])
155
- // bare positionals, skipping flags + their values.
156
- function bare(args: string[]): string[] {
157
- const out: string[] = []
158
- for (let i = 0; i < args.length; i++) {
159
- const t = args[i]
160
- if (t.startsWith('--')) { if (VALUE_FLAGS.has(t)) i++; continue }
161
- out.push(t)
162
- }
163
- return out
164
- }
165
- // `--body -` reads stdin; `--body "text"` is literal; absent → undefined.
166
- function readBody(args: string[]): string | undefined {
167
- const v = fl(args, 'body')
168
- if (v === undefined) return undefined
169
- return v === '-' ? readFileSync(0, 'utf8') : v
170
- }
171
- // a repeatable value flag: every `--<name> <value>` pair, in order.
172
- const repeated = (args: string[], name: string): string[] =>
173
- args.flatMap((a, i) => (a === `--${name}` ? [args[i + 1]] : [])).filter(Boolean) as string[]
174
-
175
- // the local-issue WRITE verbs of the issue drawer (`spex issue <verb>`): open "<concern>" [--store local|<host>] [--node id…]
176
- // [--evidence hash…] [--body -|text], and the id-based reply. Store is a property of the issue,
177
- // never a second command — open and reply route by it (issues.ts createIssue/replyIssue).
178
- export async function runIssueWrite(args: string[]): Promise<number> {
179
- const sub = args[0]
180
- try {
181
- if (sub === 'reply') {
182
- const id = bare(args.slice(1))[0]
183
- const body = readBody(args)
184
- if (!id || !body) { console.error('usage: spex issue reply <issue-id> --body -|<text> [--evidence <hash>…]'); return 2 }
185
- // the ONE store-routed reply verb ([[issues]]): a forge id posts a real comment through the driver,
186
- // a local id commits to the store — the same command either way (dynamic import: no static cycle).
187
- const r = await (await import('./loop-in.js')).replyIssueWithLoopIn(id, body, { evidence: repeated(args, 'evidence') })
188
- console.log(r.store === 'local'
189
- ? `replied to '${id}' — ${r.replies?.length} post(s) in thread`
190
- : `commented on '${id}' — ${r.url}`)
191
- const s = summarizeLoopIn(r.loopIn)
192
- if (s) console.log(` ${s}`)
193
- return 0
194
- }
195
- // `open`: start a new issue — STORE-ROUTED through the one creation port ([[issues]] createIssue, the
196
- // same routine POST /api/issues runs): default local commits to the trunk store; `--store <host>`
197
- // creates the real forge issue through that store's driver (no promote round-trip when the concern is
198
- // born forge-visible). The concern is the bare positional(s) after the sub.
199
- const concern = sub === 'open' ? bare(args.slice(1)).join(' ').trim() : ''
200
- if (!concern) {
201
- console.error('usage: spex issue open "<concern>" [--store local|<host>] [--node <id>…] [--evidence <hash>…] [--body -|<text>]\n spex issue reply|close|promote <issue-id> …')
202
- return 2
203
- }
204
- const r = await (await import('./issues.js')).createIssue(concern, {
205
- store: fl(args, 'store'),
206
- nodes: repeated(args, 'node'),
207
- body: readBody(args),
208
- evidence: repeated(args, 'evidence'),
209
- })
210
- const re = r.nodes.length ? ` (re: ${r.nodes.join(', ')})` : ''
211
- console.log(r.store === 'local'
212
- ? `opened '${r.id}'${re} — committed to the local issue store; read it with \`spex issue ls\``
213
- : `opened '${r.id}' on ${r.store}${re} — ${r.url}`)
214
- return 0
215
- } catch (e) {
216
- console.error(`spex issue: ${e instanceof Error ? e.message : e}`)
217
- return 1
218
- }
219
- }
220
-
221
- // the first positionals runIssueWrite handles — the issue drawer routes these to it. Exported so the
222
- // router and the runner can never drift. (`nudge` is not here: it is machine plumbing, called only by the
223
- // post-merge hook as `spex internal nudge`; the on|off|status toggle verbs died in v0.3.0 — the switch is
224
- // the `issues.enabled` settings key.)
225
- export const ISSUE_WRITE_SUBS = new Set(['open', 'reply'])
226
-
227
- // ── remark CLI ([[remark-substrate]]) — CLI-first: the whole author→resolve→retract loop, no server needed ──
228
- // `spex remark add <issue-id | <node> --scenario <name>> --body -|<text> [--code-sha <sha>] [--evidence <hash>…]`
229
- // host = a local issue id, OR a <node> with --scenario <name>. Records targetCodeSha (default: worktree HEAD).
230
- export async function runRemark(args: string[]): Promise<number> {
231
- try {
232
- const scenario = fl(args, 'scenario')
233
- const positional = bare(args)[0]
234
- const body = readBody(args)
235
- if (!positional || !body) {
236
- console.error('usage: spex remark add <issue-id | node --scenario name> --body -|<text> [--code-sha <sha>] [--evidence <hash>…]')
237
- return 2
238
- }
239
- // THE FLAG DECIDES THE PARSE ([[cli-surface]] §1): `--scenario` present ⇒ the positional is a NODE id
240
- // (the remark pins to that node's scenario track); absent ⇒ it is an ISSUE id. Never type-sniffed —
241
- // a node id and an issue id are both bare slugs, so any "looks like" guess would misroute; the flag
242
- // is the one unambiguous discriminator, and a wrong host fails loud downstream (unknown issue/node).
243
- const host = scenario ? { node: positional, scenario } : { issue: positional }
244
- const r = await (await import('./loop-in.js')).remarkWithLoopIn(host, body, { codeSha: fl(args, 'code-sha'), evidence: repeated(args, 'evidence') })
245
- console.log(`remark ${r.ref} (against ${r.codeSha.slice(0, 7) || 'HEAD'}) — read it with \`spex issue ls --all\``)
246
- const s = summarizeLoopIn(r.loopIn)
247
- if (s) console.log(` ${s}`)
248
- return 0
249
- } catch (e) {
250
- console.error(`spex remark add: ${e instanceof Error ? e.message : e}`)
251
- return 1
252
- }
253
- }
254
-
255
- // `spex remark resolve <remark-ref>` — flip resolved=true (agent-only, never the author, monotonic — see resolveRemark).
256
- export async function runResolve(args: string[]): Promise<number> {
257
- const ref = bare(args)[0]
258
- if (!ref) { console.error('usage: spex remark resolve <remark-ref> (the <thread-id>#<rid> `spex remark add` printed)'); return 2 }
259
- try {
260
- const by = currentSession()
261
- resolveRemark(ref, by)
262
- console.log(`resolved remark ${ref} — by ${by}`)
263
- return 0
264
- } catch (e) { console.error(`spex remark resolve: ${e instanceof Error ? e.message : e}`); return 1 }
265
- }
266
-
267
- // `spex remark retract <remark-ref>` — the author withdraws their OWN remark, removing it (author-only — see retractRemark).
268
- export async function runRetract(args: string[]): Promise<number> {
269
- const ref = bare(args)[0]
270
- if (!ref) { console.error('usage: spex remark retract <remark-ref>'); return 2 }
271
- try {
272
- retractRemark(ref, currentSession())
273
- console.log(`retracted remark ${ref}`)
274
- return 0
275
- } catch (e) { console.error(`spex remark retract: ${e instanceof Error ? e.message : e}`); return 1 }
276
- }