spexcode 0.6.2 → 0.6.6

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 (495) hide show
  1. package/README.md +3 -1
  2. package/bin/spex.mjs +4 -0
  3. package/node_modules/@spexcode/session-core/dist/delivery-queue.d.ts +23 -0
  4. package/node_modules/@spexcode/session-core/dist/delivery-queue.js +195 -0
  5. package/node_modules/@spexcode/session-core/dist/index.d.ts +5 -0
  6. package/node_modules/@spexcode/session-core/dist/index.js +5 -0
  7. package/node_modules/@spexcode/session-core/dist/internal.d.ts +3 -0
  8. package/node_modules/@spexcode/session-core/dist/internal.js +3 -0
  9. package/node_modules/@spexcode/session-core/dist/message.d.ts +22 -0
  10. package/node_modules/@spexcode/session-core/dist/message.js +52 -0
  11. package/node_modules/@spexcode/session-core/dist/record-lock.d.ts +7 -0
  12. package/node_modules/@spexcode/session-core/dist/record-lock.js +152 -0
  13. package/node_modules/@spexcode/session-core/dist/runtime-session.d.ts +50 -0
  14. package/node_modules/@spexcode/session-core/dist/runtime-session.js +286 -0
  15. package/node_modules/@spexcode/session-core/dist/session-cursors.d.ts +14 -0
  16. package/node_modules/@spexcode/session-core/dist/session-cursors.js +82 -0
  17. package/node_modules/@spexcode/session-core/dist/session-timeline.d.ts +46 -0
  18. package/node_modules/@spexcode/session-core/dist/session-timeline.js +216 -0
  19. package/node_modules/@spexcode/session-core/package.json +33 -0
  20. package/node_modules/@spexcode/spec-cli/bin/spex.mjs +77 -0
  21. package/node_modules/@spexcode/spec-cli/dist/attach.d.ts +2 -0
  22. package/node_modules/@spexcode/spec-cli/dist/attach.js +48 -0
  23. package/node_modules/@spexcode/spec-cli/dist/claude-headless.d.ts +36 -0
  24. package/node_modules/@spexcode/spec-cli/dist/claude-headless.js +316 -0
  25. package/node_modules/@spexcode/spec-cli/dist/cli.d.ts +1 -0
  26. package/node_modules/@spexcode/spec-cli/dist/cli.js +1908 -0
  27. package/node_modules/@spexcode/spec-cli/dist/client.d.ts +112 -0
  28. package/node_modules/@spexcode/spec-cli/dist/client.js +481 -0
  29. package/node_modules/@spexcode/spec-cli/dist/cockpit.d.ts +7 -0
  30. package/node_modules/@spexcode/spec-cli/dist/cockpit.js +26 -0
  31. package/node_modules/@spexcode/spec-cli/dist/codex-headless.d.ts +1 -0
  32. package/{spec-cli/src/codex-headless.ts → node_modules/@spexcode/spec-cli/dist/codex-headless.js} +3 -9
  33. package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.d.ts +58 -0
  34. package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.js +798 -0
  35. package/node_modules/@spexcode/spec-cli/dist/commit-surgery.d.ts +1 -0
  36. package/node_modules/@spexcode/spec-cli/dist/commit-surgery.js +90 -0
  37. package/node_modules/@spexcode/spec-cli/dist/contract-filter.d.ts +14 -0
  38. package/node_modules/@spexcode/spec-cli/dist/contract-filter.js +219 -0
  39. package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.d.ts +6 -0
  40. package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.js +50 -0
  41. package/node_modules/@spexcode/spec-cli/dist/doctor.d.ts +9 -0
  42. package/node_modules/@spexcode/spec-cli/dist/doctor.js +553 -0
  43. package/node_modules/@spexcode/spec-cli/dist/eval-host.d.ts +1 -0
  44. package/node_modules/@spexcode/spec-cli/dist/eval-host.js +19 -0
  45. package/node_modules/@spexcode/spec-cli/dist/execution-trace.d.ts +26 -0
  46. package/node_modules/@spexcode/spec-cli/dist/execution-trace.js +475 -0
  47. package/node_modules/@spexcode/spec-cli/dist/file-write.d.ts +2 -0
  48. package/node_modules/@spexcode/spec-cli/dist/file-write.js +26 -0
  49. package/node_modules/@spexcode/spec-cli/dist/flat.d.ts +89 -0
  50. package/node_modules/@spexcode/spec-cli/dist/flat.js +1076 -0
  51. package/node_modules/@spexcode/spec-cli/dist/gateway-auth.d.ts +56 -0
  52. package/node_modules/@spexcode/spec-cli/dist/gateway-auth.js +168 -0
  53. package/node_modules/@spexcode/spec-cli/dist/gateway-hub.d.ts +28 -0
  54. package/node_modules/@spexcode/spec-cli/dist/gateway-hub.js +363 -0
  55. package/node_modules/@spexcode/spec-cli/dist/gateway.d.ts +38 -0
  56. package/node_modules/@spexcode/spec-cli/dist/gateway.js +527 -0
  57. package/node_modules/@spexcode/spec-cli/dist/graphCache.d.ts +27 -0
  58. package/node_modules/@spexcode/spec-cli/dist/graphCache.js +717 -0
  59. package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.d.ts +14 -0
  60. package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.js +36 -0
  61. package/node_modules/@spexcode/spec-cli/dist/graphStream.d.ts +85 -0
  62. package/node_modules/@spexcode/spec-cli/dist/graphStream.js +1195 -0
  63. package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.d.ts +64 -0
  64. package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.js +166 -0
  65. package/node_modules/@spexcode/spec-cli/dist/guide.d.ts +8 -0
  66. package/{spec-cli/src/guide.ts → node_modules/@spexcode/spec-cli/dist/guide.js} +36 -32
  67. package/node_modules/@spexcode/spec-cli/dist/harness-select.d.ts +18 -0
  68. package/node_modules/@spexcode/spec-cli/dist/harness-select.js +62 -0
  69. package/node_modules/@spexcode/spec-cli/dist/harness.d.ts +338 -0
  70. package/node_modules/@spexcode/spec-cli/dist/harness.js +3146 -0
  71. package/node_modules/@spexcode/spec-cli/dist/headless-controller.d.ts +9 -0
  72. package/node_modules/@spexcode/spec-cli/dist/headless-controller.js +47 -0
  73. package/node_modules/@spexcode/spec-cli/dist/help.d.ts +15 -0
  74. package/node_modules/@spexcode/spec-cli/dist/help.js +594 -0
  75. package/node_modules/@spexcode/spec-cli/dist/hook-prompts.d.ts +18 -0
  76. package/node_modules/@spexcode/spec-cli/dist/hook-prompts.js +122 -0
  77. package/node_modules/@spexcode/spec-cli/dist/hooks.d.ts +1 -0
  78. package/{spec-cli/src/hooks.ts → node_modules/@spexcode/spec-cli/dist/hooks.js} +15 -15
  79. package/node_modules/@spexcode/spec-cli/dist/host-resources.d.ts +97 -0
  80. package/node_modules/@spexcode/spec-cli/dist/host-resources.js +795 -0
  81. package/node_modules/@spexcode/spec-cli/dist/host.d.ts +88 -0
  82. package/node_modules/@spexcode/spec-cli/dist/host.js +663 -0
  83. package/node_modules/@spexcode/spec-cli/dist/index.d.ts +1 -0
  84. package/node_modules/@spexcode/spec-cli/dist/index.js +899 -0
  85. package/node_modules/@spexcode/spec-cli/dist/init.d.ts +1 -0
  86. package/node_modules/@spexcode/spec-cli/dist/init.js +284 -0
  87. package/node_modules/@spexcode/spec-cli/dist/issues-cli.d.ts +6 -0
  88. package/node_modules/@spexcode/spec-cli/dist/issues-cli.js +334 -0
  89. package/node_modules/@spexcode/spec-cli/dist/issues.d.ts +69 -0
  90. package/node_modules/@spexcode/spec-cli/dist/issues.js +189 -0
  91. package/node_modules/@spexcode/spec-cli/dist/lint.d.ts +34 -0
  92. package/node_modules/@spexcode/spec-cli/dist/lint.js +476 -0
  93. package/node_modules/@spexcode/spec-cli/dist/listen.d.ts +8 -0
  94. package/node_modules/@spexcode/spec-cli/dist/listen.js +24 -0
  95. package/node_modules/@spexcode/spec-cli/dist/localIssues.d.ts +65 -0
  96. package/node_modules/@spexcode/spec-cli/dist/localIssues.js +582 -0
  97. package/node_modules/@spexcode/spec-cli/dist/login-page.d.ts +5 -0
  98. package/{spec-cli/src/login-page.ts → node_modules/@spexcode/spec-cli/dist/login-page.js} +7 -7
  99. package/node_modules/@spexcode/spec-cli/dist/loop-in.d.ts +23 -0
  100. package/{spec-cli/src/loop-in.ts → node_modules/@spexcode/spec-cli/dist/loop-in.js} +35 -45
  101. package/node_modules/@spexcode/spec-cli/dist/machine-peer.d.ts +69 -0
  102. package/node_modules/@spexcode/spec-cli/dist/machine-peer.js +603 -0
  103. package/node_modules/@spexcode/spec-cli/dist/materialize.d.ts +18 -0
  104. package/node_modules/@spexcode/spec-cli/dist/materialize.js +468 -0
  105. package/node_modules/@spexcode/spec-cli/dist/mentions.d.ts +50 -0
  106. package/node_modules/@spexcode/spec-cli/dist/mentions.js +117 -0
  107. package/node_modules/@spexcode/spec-cli/dist/opencode-headless.d.ts +5 -0
  108. package/node_modules/@spexcode/spec-cli/dist/opencode-headless.js +215 -0
  109. package/node_modules/@spexcode/spec-cli/dist/opencode.d.ts +3 -0
  110. package/{spec-cli/src/opencode.ts → node_modules/@spexcode/spec-cli/dist/opencode.js} +9 -13
  111. package/node_modules/@spexcode/spec-cli/dist/pi-harness.d.ts +3 -0
  112. package/{spec-cli/src/pi-harness.ts → node_modules/@spexcode/spec-cli/dist/pi-harness.js} +45 -40
  113. package/node_modules/@spexcode/spec-cli/dist/pi-headless.d.ts +25 -0
  114. package/node_modules/@spexcode/spec-cli/dist/pi-headless.js +196 -0
  115. package/node_modules/@spexcode/spec-cli/dist/plugin-harness.d.ts +21 -0
  116. package/node_modules/@spexcode/spec-cli/dist/plugin-harness.js +146 -0
  117. package/node_modules/@spexcode/spec-cli/dist/pty-bridge.d.ts +10 -0
  118. package/node_modules/@spexcode/spec-cli/dist/pty-bridge.js +404 -0
  119. package/node_modules/@spexcode/spec-cli/dist/pty-helper.d.mts +1 -0
  120. package/node_modules/@spexcode/spec-cli/dist/pty-helper.mjs +101 -0
  121. package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.d.mts +2 -0
  122. package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.mjs +23 -0
  123. package/node_modules/@spexcode/spec-cli/dist/public-graph.d.ts +46 -0
  124. package/node_modules/@spexcode/spec-cli/dist/public-graph.js +56 -0
  125. package/node_modules/@spexcode/spec-cli/dist/ranker.d.ts +15 -0
  126. package/node_modules/@spexcode/spec-cli/dist/ranker.js +188 -0
  127. package/node_modules/@spexcode/spec-cli/dist/reaper.d.ts +6 -0
  128. package/node_modules/@spexcode/spec-cli/dist/reaper.js +81 -0
  129. package/node_modules/@spexcode/spec-cli/dist/reviews.d.ts +189 -0
  130. package/node_modules/@spexcode/spec-cli/dist/reviews.js +350 -0
  131. package/node_modules/@spexcode/spec-cli/dist/runtime-guard.d.ts +6 -0
  132. package/node_modules/@spexcode/spec-cli/dist/runtime-guard.js +37 -0
  133. package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.d.ts +21 -0
  134. package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.js +84 -0
  135. package/node_modules/@spexcode/spec-cli/dist/runtime-rotate.d.ts +1 -0
  136. package/node_modules/@spexcode/spec-cli/dist/runtime-rotate.js +58 -0
  137. package/node_modules/@spexcode/spec-cli/dist/search.bench.d.mts +1 -0
  138. package/node_modules/@spexcode/spec-cli/dist/search.bench.mjs +75 -0
  139. package/node_modules/@spexcode/spec-cli/dist/search.d.ts +20 -0
  140. package/node_modules/@spexcode/spec-cli/dist/search.js +61 -0
  141. package/node_modules/@spexcode/spec-cli/dist/session-declarations.d.ts +13 -0
  142. package/node_modules/@spexcode/spec-cli/dist/session-declarations.js +126 -0
  143. package/node_modules/@spexcode/spec-cli/dist/session-execution.d.ts +10 -0
  144. package/node_modules/@spexcode/spec-cli/dist/session-execution.js +70 -0
  145. package/node_modules/@spexcode/spec-cli/dist/session-files.d.ts +28 -0
  146. package/node_modules/@spexcode/spec-cli/dist/session-files.js +130 -0
  147. package/node_modules/@spexcode/spec-cli/dist/session-follow.d.ts +31 -0
  148. package/node_modules/@spexcode/spec-cli/dist/session-follow.js +179 -0
  149. package/node_modules/@spexcode/spec-cli/dist/session-reparent.d.ts +10 -0
  150. package/node_modules/@spexcode/spec-cli/dist/session-reparent.js +33 -0
  151. package/node_modules/@spexcode/spec-cli/dist/session-timeline.d.ts +11 -0
  152. package/node_modules/@spexcode/spec-cli/dist/session-timeline.js +20 -0
  153. package/node_modules/@spexcode/spec-cli/dist/session-web.d.ts +24 -0
  154. package/node_modules/@spexcode/spec-cli/dist/session-web.js +141 -0
  155. package/node_modules/@spexcode/spec-cli/dist/sessions.d.ts +433 -0
  156. package/node_modules/@spexcode/spec-cli/dist/sessions.js +4667 -0
  157. package/node_modules/@spexcode/spec-cli/dist/sh.d.ts +1 -0
  158. package/node_modules/@spexcode/spec-cli/dist/sh.js +3 -0
  159. package/node_modules/@spexcode/spec-cli/dist/shim-runtime.d.ts +1 -0
  160. package/{spec-cli/src/shim-runtime.ts → node_modules/@spexcode/spec-cli/dist/shim-runtime.js} +3 -4
  161. package/node_modules/@spexcode/spec-cli/dist/slash-commands.d.ts +9 -0
  162. package/node_modules/@spexcode/spec-cli/dist/slash-commands.js +307 -0
  163. package/node_modules/@spexcode/spec-cli/dist/source-files.d.ts +9 -0
  164. package/node_modules/@spexcode/spec-cli/dist/source-files.js +113 -0
  165. package/node_modules/@spexcode/spec-cli/dist/supervise.d.ts +1 -0
  166. package/node_modules/@spexcode/spec-cli/dist/supervise.js +308 -0
  167. package/node_modules/@spexcode/spec-cli/dist/tree.d.ts +25 -0
  168. package/node_modules/@spexcode/spec-cli/dist/tree.js +98 -0
  169. package/node_modules/@spexcode/spec-cli/dist/tsx-bin.d.ts +3 -0
  170. package/node_modules/@spexcode/spec-cli/dist/tsx-bin.js +41 -0
  171. package/node_modules/@spexcode/spec-cli/dist/uninstall.d.ts +3 -0
  172. package/node_modules/@spexcode/spec-cli/dist/uninstall.js +177 -0
  173. package/node_modules/@spexcode/spec-cli/dist/uploads.d.ts +36 -0
  174. package/node_modules/@spexcode/spec-cli/dist/uploads.js +243 -0
  175. package/node_modules/@spexcode/spec-cli/dist/worktree-sources.d.ts +1 -0
  176. package/node_modules/@spexcode/spec-cli/dist/worktree-sources.js +47 -0
  177. package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/dispatch.sh +5 -5
  178. package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/harness.sh +1 -1
  179. package/node_modules/@spexcode/spec-cli/package.json +49 -0
  180. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +8 -0
  181. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec-first.sh +1 -1
  182. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec-of-file.sh +1 -0
  183. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/spec.md +2 -2
  184. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/stop-gate.sh +31 -29
  185. package/node_modules/@spexcode/spec-core/dist/anchors.d.ts +94 -0
  186. package/node_modules/@spexcode/spec-core/dist/anchors.js +730 -0
  187. package/node_modules/@spexcode/spec-core/dist/git.d.ts +170 -0
  188. package/node_modules/@spexcode/spec-core/dist/git.js +2768 -0
  189. package/node_modules/@spexcode/spec-core/dist/graph-delta.d.ts +44 -0
  190. package/node_modules/@spexcode/spec-core/dist/graph-delta.js +72 -0
  191. package/node_modules/@spexcode/spec-core/dist/graph.d.ts +34 -0
  192. package/node_modules/@spexcode/spec-core/dist/graph.js +237 -0
  193. package/node_modules/@spexcode/spec-core/dist/graphDelta.d.ts +3 -0
  194. package/node_modules/@spexcode/spec-core/dist/graphDelta.js +13 -0
  195. package/node_modules/@spexcode/spec-core/dist/harness-identity.d.ts +31 -0
  196. package/node_modules/@spexcode/spec-core/dist/harness-identity.js +20 -0
  197. package/node_modules/@spexcode/spec-core/dist/identity-presets.d.ts +152 -0
  198. package/node_modules/@spexcode/spec-core/dist/identity-presets.js +132 -0
  199. package/node_modules/@spexcode/spec-core/dist/index.d.ts +45 -0
  200. package/node_modules/@spexcode/spec-core/dist/index.js +19 -0
  201. package/node_modules/@spexcode/spec-core/dist/layout.d.ts +187 -0
  202. package/node_modules/@spexcode/spec-core/dist/layout.js +548 -0
  203. package/node_modules/@spexcode/spec-core/dist/process-identity.d.ts +37 -0
  204. package/node_modules/@spexcode/spec-core/dist/process-identity.js +214 -0
  205. package/node_modules/@spexcode/spec-core/dist/project-identity.d.ts +12 -0
  206. package/node_modules/@spexcode/spec-core/dist/project-identity.js +71 -0
  207. package/node_modules/@spexcode/spec-core/dist/project-store.d.ts +3 -0
  208. package/node_modules/@spexcode/spec-core/dist/project-store.js +14 -0
  209. package/node_modules/@spexcode/spec-core/dist/resilience.d.ts +2 -0
  210. package/node_modules/@spexcode/spec-core/dist/resilience.js +40 -0
  211. package/node_modules/@spexcode/spec-core/dist/review/index.d.ts +3 -0
  212. package/node_modules/@spexcode/spec-core/dist/review/index.js +5 -0
  213. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.d.ts +77 -0
  214. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.js +308 -0
  215. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.d.ts +66 -0
  216. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.js +180 -0
  217. package/node_modules/@spexcode/spec-core/dist/review/session.d.ts +4 -0
  218. package/node_modules/@spexcode/spec-core/dist/review/session.js +8 -0
  219. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.d.ts +15 -0
  220. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.js +12 -0
  221. package/node_modules/@spexcode/spec-core/dist/root-lru.d.ts +4 -0
  222. package/{spec-cli/src/root-lru.ts → node_modules/@spexcode/spec-core/dist/root-lru.js} +26 -30
  223. package/node_modules/@spexcode/spec-core/dist/specs.d.ts +117 -0
  224. package/node_modules/@spexcode/spec-core/dist/specs.js +489 -0
  225. package/node_modules/@spexcode/spec-core/package.json +28 -0
  226. package/node_modules/@spexcode/spec-eval/dist/cache.d.ts +10 -0
  227. package/node_modules/@spexcode/spec-eval/dist/cache.js +50 -0
  228. package/node_modules/@spexcode/spec-eval/dist/cli.d.ts +22 -0
  229. package/node_modules/@spexcode/spec-eval/dist/cli.js +981 -0
  230. package/node_modules/@spexcode/spec-eval/dist/evaltab.d.ts +98 -0
  231. package/node_modules/@spexcode/spec-eval/dist/evaltab.js +176 -0
  232. package/node_modules/@spexcode/spec-eval/dist/filing.d.ts +16 -0
  233. package/node_modules/@spexcode/spec-eval/dist/filing.js +36 -0
  234. package/node_modules/@spexcode/spec-eval/dist/freshness.d.ts +48 -0
  235. package/node_modules/@spexcode/spec-eval/dist/freshness.js +799 -0
  236. package/node_modules/@spexcode/spec-eval/dist/host.d.ts +46 -0
  237. package/node_modules/@spexcode/spec-eval/dist/host.js +53 -0
  238. package/node_modules/@spexcode/spec-eval/dist/humanok.d.ts +11 -0
  239. package/node_modules/@spexcode/spec-eval/dist/humanok.js +27 -0
  240. package/node_modules/@spexcode/spec-eval/dist/index.d.ts +4 -0
  241. package/node_modules/@spexcode/spec-eval/dist/index.js +4 -0
  242. package/node_modules/@spexcode/spec-eval/dist/remarks.d.ts +31 -0
  243. package/node_modules/@spexcode/spec-eval/dist/remarks.js +1 -0
  244. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.d.ts +13 -0
  245. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.js +303 -0
  246. package/node_modules/@spexcode/spec-eval/dist/scenarios.d.ts +99 -0
  247. package/node_modules/@spexcode/spec-eval/dist/scenarios.js +650 -0
  248. package/node_modules/@spexcode/spec-eval/dist/sessioneval.d.ts +307 -0
  249. package/node_modules/@spexcode/spec-eval/dist/sessioneval.js +1883 -0
  250. package/node_modules/@spexcode/spec-eval/dist/sidecar.d.ts +55 -0
  251. package/node_modules/@spexcode/spec-eval/dist/sidecar.js +82 -0
  252. package/node_modules/@spexcode/spec-eval/dist/timeline.d.ts +25 -0
  253. package/node_modules/@spexcode/spec-eval/dist/timeline.js +65 -0
  254. package/node_modules/@spexcode/spec-eval/dist/ui-path.d.ts +1 -0
  255. package/node_modules/@spexcode/spec-eval/dist/ui-path.js +2 -0
  256. package/node_modules/@spexcode/spec-eval/package.json +36 -0
  257. package/node_modules/@spexcode/spec-forge/dist/cache.d.ts +29 -0
  258. package/node_modules/@spexcode/spec-forge/dist/cache.js +59 -0
  259. package/node_modules/@spexcode/spec-forge/dist/cli.d.ts +1 -0
  260. package/node_modules/@spexcode/spec-forge/dist/cli.js +100 -0
  261. package/node_modules/@spexcode/spec-forge/dist/drivers/github.d.ts +2 -0
  262. package/node_modules/@spexcode/spec-forge/dist/drivers/github.js +116 -0
  263. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.d.ts +7 -0
  264. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.js +144 -0
  265. package/node_modules/@spexcode/spec-forge/dist/drivers.d.ts +10 -0
  266. package/node_modules/@spexcode/spec-forge/dist/drivers.js +83 -0
  267. package/node_modules/@spexcode/spec-forge/dist/index.d.ts +4 -0
  268. package/node_modules/@spexcode/spec-forge/dist/index.js +4 -0
  269. package/node_modules/@spexcode/spec-forge/dist/links.d.ts +15 -0
  270. package/node_modules/@spexcode/spec-forge/dist/links.js +65 -0
  271. package/node_modules/@spexcode/spec-forge/dist/needs-eval.d.ts +10 -0
  272. package/node_modules/@spexcode/spec-forge/dist/needs-eval.js +20 -0
  273. package/node_modules/@spexcode/spec-forge/dist/port.d.ts +53 -0
  274. package/node_modules/@spexcode/spec-forge/dist/port.js +1 -0
  275. package/node_modules/@spexcode/spec-forge/dist/resident.d.ts +7 -0
  276. package/node_modules/@spexcode/spec-forge/dist/resident.js +43 -0
  277. package/node_modules/@spexcode/spec-forge/package.json +32 -0
  278. package/package.json +33 -19
  279. package/spec-cli/bin/spex.mjs +0 -69
  280. package/spec-cli/src/anchors.ts +0 -728
  281. package/spec-cli/src/attach.ts +0 -43
  282. package/spec-cli/src/claude-headless.ts +0 -321
  283. package/spec-cli/src/cli.ts +0 -1258
  284. package/spec-cli/src/client.ts +0 -414
  285. package/spec-cli/src/cockpit.ts +0 -43
  286. package/spec-cli/src/codex-runtime-generations.ts +0 -646
  287. package/spec-cli/src/commit-surgery.ts +0 -68
  288. package/spec-cli/src/contract-filter.ts +0 -202
  289. package/spec-cli/src/delivery-queue.ts +0 -165
  290. package/spec-cli/src/doctor.ts +0 -516
  291. package/spec-cli/src/execution-trace.ts +0 -444
  292. package/spec-cli/src/file-write.ts +0 -22
  293. package/spec-cli/src/gateway-auth.ts +0 -181
  294. package/spec-cli/src/gateway-hub.ts +0 -358
  295. package/spec-cli/src/gateway.ts +0 -461
  296. package/spec-cli/src/git.ts +0 -2556
  297. package/spec-cli/src/graph.ts +0 -271
  298. package/spec-cli/src/graphCache.ts +0 -710
  299. package/spec-cli/src/graphDelta.ts +0 -77
  300. package/spec-cli/src/graphStream.ts +0 -1019
  301. package/spec-cli/src/harness-select.ts +0 -77
  302. package/spec-cli/src/harness.ts +0 -3025
  303. package/spec-cli/src/headless-controller.ts +0 -63
  304. package/spec-cli/src/help.ts +0 -492
  305. package/spec-cli/src/host-resources.ts +0 -762
  306. package/spec-cli/src/host.ts +0 -611
  307. package/spec-cli/src/identity-presets.d.ts +0 -13
  308. package/spec-cli/src/identity-presets.js +0 -138
  309. package/spec-cli/src/index.ts +0 -818
  310. package/spec-cli/src/init.ts +0 -258
  311. package/spec-cli/src/issues-cli.ts +0 -276
  312. package/spec-cli/src/issues.ts +0 -237
  313. package/spec-cli/src/layout.ts +0 -640
  314. package/spec-cli/src/lint.ts +0 -488
  315. package/spec-cli/src/listen.ts +0 -28
  316. package/spec-cli/src/localIssues.ts +0 -538
  317. package/spec-cli/src/materialize.ts +0 -417
  318. package/spec-cli/src/mentions.ts +0 -81
  319. package/spec-cli/src/opencode-headless.ts +0 -205
  320. package/spec-cli/src/pi-headless.ts +0 -153
  321. package/spec-cli/src/plugin-harness.ts +0 -157
  322. package/spec-cli/src/process-identity.ts +0 -207
  323. package/spec-cli/src/project-identity.ts +0 -73
  324. package/spec-cli/src/project-store.ts +0 -17
  325. package/spec-cli/src/pty-bridge.ts +0 -396
  326. package/spec-cli/src/pty-helper.mjs +0 -96
  327. package/spec-cli/src/pty-native-helper.mjs +0 -22
  328. package/spec-cli/src/ranker.ts +0 -191
  329. package/spec-cli/src/reaper.ts +0 -125
  330. package/spec-cli/src/resilience.ts +0 -41
  331. package/spec-cli/src/reviewSnapshot.ts +0 -28
  332. package/spec-cli/src/reviews.ts +0 -434
  333. package/spec-cli/src/runtime-guard.ts +0 -35
  334. package/spec-cli/src/runtime-ownership.ts +0 -88
  335. package/spec-cli/src/search.bench.mjs +0 -80
  336. package/spec-cli/src/search.ts +0 -63
  337. package/spec-cli/src/session-cursors.ts +0 -91
  338. package/spec-cli/src/session-execution.ts +0 -68
  339. package/spec-cli/src/session-files.ts +0 -121
  340. package/spec-cli/src/session-follow.ts +0 -182
  341. package/spec-cli/src/session-reparent.ts +0 -33
  342. package/spec-cli/src/session-timeline.ts +0 -247
  343. package/spec-cli/src/session-web.ts +0 -135
  344. package/spec-cli/src/sessions.ts +0 -3883
  345. package/spec-cli/src/sh.ts +0 -3
  346. package/spec-cli/src/slash-commands.ts +0 -318
  347. package/spec-cli/src/source-files.ts +0 -104
  348. package/spec-cli/src/specs.ts +0 -498
  349. package/spec-cli/src/supervise.ts +0 -245
  350. package/spec-cli/src/tree.ts +0 -118
  351. package/spec-cli/src/tsx-bin.ts +0 -18
  352. package/spec-cli/src/uninstall.ts +0 -171
  353. package/spec-cli/src/uploads.ts +0 -253
  354. package/spec-cli/src/worktree-sources.ts +0 -42
  355. package/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +0 -8
  356. package/spec-dashboard/dist/assets/App-B6IbFbGu.js +0 -2
  357. package/spec-dashboard/dist/assets/Dashboard-C5ap-Sga.css +0 -1
  358. package/spec-dashboard/dist/assets/Dashboard-_sDk7Rcg.js +0 -27
  359. package/spec-dashboard/dist/assets/EvalsPage-BT357Lyt.js +0 -2
  360. package/spec-dashboard/dist/assets/IssuesPage-BG9rNOgV.js +0 -1
  361. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  362. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  363. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  364. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  365. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  366. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  367. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  368. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  369. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  370. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  371. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  372. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  373. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  374. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  375. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  376. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  377. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  378. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  379. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  380. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  381. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  382. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  383. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  384. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  385. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  386. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  387. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  388. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  389. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  390. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  391. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  392. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  393. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  394. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  395. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  396. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  397. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  398. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  399. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  400. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  401. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  402. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  403. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  404. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  405. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  406. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  407. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  408. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  409. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  410. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  411. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  412. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  413. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  414. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  415. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  416. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  417. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  418. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  419. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  420. package/spec-dashboard/dist/assets/MobileApp-D9yPMR3A.js +0 -2
  421. package/spec-dashboard/dist/assets/Modal-B3EcgeA3.js +0 -1
  422. package/spec-dashboard/dist/assets/PageScroll-CNZOugWV.js +0 -1
  423. package/spec-dashboard/dist/assets/ProjectsPage-C2CRHmvs.js +0 -1
  424. package/spec-dashboard/dist/assets/SessionInterface-6GBZ9nXN.css +0 -32
  425. package/spec-dashboard/dist/assets/SessionInterface-DOEjuT3l.js +0 -40
  426. package/spec-dashboard/dist/assets/SessionWindow-1nYgZ4CL.js +0 -1
  427. package/spec-dashboard/dist/assets/Settings-7WeTJn0V.js +0 -1
  428. package/spec-dashboard/dist/assets/Thread-CEbzAFQn.js +0 -13
  429. package/spec-dashboard/dist/assets/bindings-BC9vqpYU.js +0 -1
  430. package/spec-dashboard/dist/assets/data-SlvxNA2r.js +0 -1
  431. package/spec-dashboard/dist/assets/index-DLVeOHL-.js +0 -41
  432. package/spec-dashboard/dist/assets/index-DYLGfPjx.css +0 -1
  433. package/spec-dashboard/dist/assets/launch-Cp579UoJ.css +0 -1
  434. package/spec-dashboard/dist/assets/launch-yxCYr64x.js +0 -276
  435. package/spec-dashboard/dist/assets/sessionSurface--7l69h4F.js +0 -1
  436. package/spec-dashboard/dist/index.html +0 -29
  437. package/spec-dashboard/src/reviewFilters.js +0 -322
  438. package/spec-dashboard/src/reviewQuery.js +0 -174
  439. package/spec-dashboard/src/session.js +0 -199
  440. package/spec-eval/src/cache.ts +0 -57
  441. package/spec-eval/src/cli.ts +0 -894
  442. package/spec-eval/src/evaltab.ts +0 -264
  443. package/spec-eval/src/filing.ts +0 -39
  444. package/spec-eval/src/freshness.ts +0 -836
  445. package/spec-eval/src/humanok.ts +0 -28
  446. package/spec-eval/src/scenariofresh.ts +0 -244
  447. package/spec-eval/src/scenarios.ts +0 -672
  448. package/spec-eval/src/sessioneval.ts +0 -2220
  449. package/spec-eval/src/sidecar.ts +0 -93
  450. package/spec-eval/src/timeline.ts +0 -54
  451. package/spec-forge/src/__fixtures__/github-forge.json +0 -63
  452. package/spec-forge/src/cache.ts +0 -66
  453. package/spec-forge/src/cli.ts +0 -99
  454. package/spec-forge/src/drivers/github.ts +0 -132
  455. package/spec-forge/src/drivers/gitlab.ts +0 -153
  456. package/spec-forge/src/drivers.ts +0 -73
  457. package/spec-forge/src/links.ts +0 -72
  458. package/spec-forge/src/needs-eval.ts +0 -29
  459. package/spec-forge/src/port.ts +0 -36
  460. package/spec-forge/src/resident.ts +0 -46
  461. /package/{spec-cli → node_modules/@spexcode/spec-cli}/README.md +0 -0
  462. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-0.5.2-eef1.fixture +0 -0
  463. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-sed-v0.fixture +0 -0
  464. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/commit-msg +0 -0
  465. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-checkout +0 -0
  466. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-merge +0 -0
  467. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/pre-commit +0 -0
  468. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/prepare-commit-msg +0 -0
  469. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/reference-transaction +0 -0
  470. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/extract/spec.md +0 -0
  471. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/regroup/spec.md +0 -0
  472. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/rename/spec.md +0 -0
  473. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/spec.md +0 -0
  474. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/tidy/spec.md +0 -0
  475. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/comment-altitude/spec.md +0 -0
  476. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/idle.sh +0 -0
  477. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/spec.md +0 -0
  478. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/mark-active.sh +0 -0
  479. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/spec.md +0 -0
  480. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/fail.sh +0 -0
  481. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/spec.md +0 -0
  482. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec.md +0 -0
  483. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec.md +0 -0
  484. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec.md +0 -0
  485. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +0 -0
  486. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/forge-link/spec.md +0 -0
  487. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +0 -0
  488. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +0 -0
  489. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/spec.md +0 -0
  490. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/digest.mjs +0 -0
  491. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/spec.md +0 -0
  492. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/spec.md +0 -0
  493. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/spec.md +0 -0
  494. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/spec.md +0 -0
  495. /package/{spec-cli → node_modules/@spexcode/spec-core}/templates/spexcode.json +0 -0
@@ -0,0 +1,603 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { execFile, spawn } from 'node:child_process';
3
+ import { createServer as createHttpServer } from 'node:http';
4
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { createConnection, createServer as createNetServer } from 'node:net';
6
+ import { dirname, join, resolve } from 'node:path';
7
+ import { promisify } from 'node:util';
8
+ import { runtimeRoot, spexcodeHome } from '@spexcode/spec-core';
9
+ import { readEndpointRecord } from './host.js';
10
+ const execFileAsync = promisify(execFile);
11
+ const PEER_VERSION = 1;
12
+ const PEER_RETRY_MS = 2_000;
13
+ const PEER_BODY_LIMIT = 1_048_576;
14
+ export const peerStorePath = () => join(spexcodeHome(), 'gateway', 'peers.json');
15
+ export const peerSocketPath = () => join(spexcodeHome(), 'gateway', 'peer.sock');
16
+ function validPort(value) {
17
+ return typeof value === 'number' && Number.isInteger(value) && value > 0 && value < 65536;
18
+ }
19
+ function validMachineId(value) {
20
+ return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
21
+ }
22
+ function validPeer(value) {
23
+ if (!value || typeof value !== 'object' || Array.isArray(value))
24
+ return false;
25
+ const peer = value;
26
+ return validMachineId(peer.machineId) && typeof peer.sshAddress === 'string' && peer.sshAddress.length > 0 &&
27
+ validPort(peer.inboundPort) && validPort(peer.outboundPort) && validPort(peer.remoteInboundPort) && validPort(peer.remoteOutboundPort) &&
28
+ typeof peer.owner === 'boolean' && (peer.state === 'connecting' || peer.state === 'connected') &&
29
+ typeof peer.createdAt === 'string' && (typeof peer.lastOkAt === 'string' || peer.lastOkAt === null) &&
30
+ (typeof peer.lastError === 'string' || peer.lastError === null);
31
+ }
32
+ function readStore() {
33
+ const file = peerStorePath();
34
+ if (!existsSync(file))
35
+ return { version: PEER_VERSION, machineId: '', peers: [] };
36
+ let parsed;
37
+ try {
38
+ parsed = JSON.parse(readFileSync(file, 'utf8'));
39
+ }
40
+ catch (error) {
41
+ throw new Error(`malformed ${file}: ${error.message}`);
42
+ }
43
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed) || parsed.version !== PEER_VERSION ||
44
+ (typeof parsed.machineId !== 'string' && parsed.machineId !== undefined) || !Array.isArray(parsed.peers) || !parsed.peers.every(validPeer)) {
45
+ throw new Error(`malformed ${file}: expected {version:${PEER_VERSION},peers:[...]}`);
46
+ }
47
+ return { ...parsed, machineId: typeof parsed.machineId === 'string' ? parsed.machineId : '' };
48
+ }
49
+ function writeStore(store) {
50
+ const file = peerStorePath();
51
+ mkdirSync(dirname(file), { recursive: true, mode: 0o700 });
52
+ const tmp = `${file}.${process.pid}.${randomUUID()}.tmp`;
53
+ try {
54
+ writeFileSync(tmp, `${JSON.stringify(store, null, 2)}\n`, { mode: 0o600 });
55
+ renameSync(tmp, file);
56
+ }
57
+ finally {
58
+ try {
59
+ rmSync(tmp);
60
+ }
61
+ catch { /* rename consumed it */ }
62
+ }
63
+ }
64
+ export function listMachinePeers() {
65
+ return readStore().peers;
66
+ }
67
+ export function readPeerMachineId() {
68
+ const store = readStore();
69
+ if (validMachineId(store.machineId))
70
+ return store.machineId;
71
+ const machineId = randomUUID();
72
+ writeStore({ ...store, machineId });
73
+ return machineId;
74
+ }
75
+ export function peerSenderRef(machineId, sessionId) {
76
+ return sessionId && validMachineId(sessionId) ? `peer:${machineId}:${sessionId}` : `peer:${machineId}`;
77
+ }
78
+ function validPeerSender(value, machineId) {
79
+ if (typeof value !== 'string')
80
+ return false;
81
+ const match = value.match(/^peer:([0-9a-f-]{36})(?::([0-9a-f-]{36}))?$/i);
82
+ return !!match && match[1] === machineId && (match[2] === undefined || validMachineId(match[2]));
83
+ }
84
+ export function findMachinePeer(sshAddress) {
85
+ return listMachinePeers().find((peer) => peer.sshAddress === sshAddress) ?? null;
86
+ }
87
+ export function resolveMachinePeer(sshAddress) {
88
+ const peer = findMachinePeer(sshAddress);
89
+ if (!peer || peer.state !== 'connected') {
90
+ const error = new Error(`no communication tunnel for SSH address ${JSON.stringify(sshAddress)} — run \`spex peer connect ${sshAddress}\`, then retry the unchanged command`);
91
+ error.name = 'BackendError';
92
+ throw error;
93
+ }
94
+ return peer;
95
+ }
96
+ function replacePeer(next) {
97
+ const store = readStore();
98
+ const at = store.peers.findIndex((peer) => peer.machineId === next.machineId || peer.sshAddress === next.sshAddress);
99
+ if (at >= 0)
100
+ store.peers[at] = next;
101
+ else
102
+ store.peers.push(next);
103
+ writeStore(store);
104
+ }
105
+ function removePeer(match) {
106
+ const store = readStore();
107
+ const peer = store.peers.find(match) ?? null;
108
+ if (!peer)
109
+ return null;
110
+ writeStore({ ...store, peers: store.peers.filter((item) => item !== peer) });
111
+ return peer;
112
+ }
113
+ async function freePort() {
114
+ const server = createNetServer();
115
+ await new Promise((resolve, reject) => {
116
+ server.once('error', reject);
117
+ server.listen(0, '127.0.0.1', () => resolve());
118
+ });
119
+ const address = server.address();
120
+ await new Promise((resolve) => server.close(() => resolve()));
121
+ if (!address || typeof address === 'string' || !validPort(address.port))
122
+ throw new Error('could not allocate loopback peer port');
123
+ return address.port;
124
+ }
125
+ function readRequest(req) {
126
+ return new Promise((resolve, reject) => {
127
+ let body = '';
128
+ req.setEncoding('utf8');
129
+ req.on('data', (chunk) => {
130
+ body += chunk;
131
+ if (Buffer.byteLength(body, 'utf8') > PEER_BODY_LIMIT) {
132
+ req.destroy();
133
+ reject(new Error('peer envelope exceeds 1 MiB'));
134
+ }
135
+ });
136
+ req.once('end', () => resolve(body));
137
+ req.once('error', reject);
138
+ });
139
+ }
140
+ function json(res, status, body) {
141
+ res.writeHead(status, { 'content-type': 'application/json' });
142
+ res.end(JSON.stringify(body));
143
+ }
144
+ // Session records live under the shared Git common-dir store, whereas a running backend publishes under
145
+ // the worktree root it serves. A direct endpoint beside the session remains the simple case; linked
146
+ // worktrees use the record's worktree_path to find their own published endpoint.
147
+ function peerProjectsForSession(sessionId) {
148
+ const projects = join(spexcodeHome(), 'projects');
149
+ let ids = [];
150
+ try {
151
+ ids = readdirSync(projects);
152
+ }
153
+ catch {
154
+ return [];
155
+ }
156
+ const endpointRecords = ids.flatMap((id) => {
157
+ const endpoint = readEndpointRecord(join(projects, id, 'backend.json'));
158
+ return endpoint ? [{ id, endpoint }] : [];
159
+ });
160
+ const hits = [];
161
+ for (const id of ids) {
162
+ const root = join(projects, id);
163
+ const record = join(root, 'sessions', sessionId, 'session.json');
164
+ if (!existsSync(record))
165
+ continue;
166
+ const direct = readEndpointRecord(join(root, 'backend.json'));
167
+ if (direct) {
168
+ hits.push({ id, url: direct.url });
169
+ continue;
170
+ }
171
+ let worktree = '';
172
+ try {
173
+ const parsed = JSON.parse(readFileSync(record, 'utf8'));
174
+ if (typeof parsed?.worktree_path === 'string' && parsed.worktree_path)
175
+ worktree = resolve(parsed.worktree_path);
176
+ }
177
+ catch { /* the backend gives the record's named error after routing reaches it */ }
178
+ const exact = worktree ? endpointRecords.filter(({ endpoint }) => resolve(endpoint.root) === worktree) : [];
179
+ if (exact.length === 1) {
180
+ hits.push({ id, url: exact[0].endpoint.url });
181
+ continue;
182
+ }
183
+ if (exact.length > 1) {
184
+ hits.push({ id, url: null, endpointConflict: `session ${sessionId} has ${exact.length} live backends for worktree ${worktree}` });
185
+ continue;
186
+ }
187
+ const common = endpointRecords.filter(({ endpoint }) => {
188
+ try {
189
+ return runtimeRoot(endpoint.root) === root;
190
+ }
191
+ catch {
192
+ return false;
193
+ }
194
+ });
195
+ if (common.length === 1)
196
+ hits.push({ id, url: common[0].endpoint.url });
197
+ else if (common.length > 1)
198
+ hits.push({ id, url: null, endpointConflict: `session ${sessionId} has ${common.length} live backends in its Git project` });
199
+ else
200
+ hits.push({ id, url: null });
201
+ }
202
+ return hits;
203
+ }
204
+ function peerSessionRequest(req) {
205
+ const url = new URL(req.url ?? '/', 'http://127.0.0.1');
206
+ if (url.search)
207
+ return null;
208
+ const base = url.pathname.match(/^\/api\/sessions\/([0-9a-f-]{36})$/i);
209
+ if (req.method === 'GET' && base)
210
+ return { kind: 'show', sessionId: base[1] };
211
+ const input = url.pathname.match(/^\/api\/sessions\/([0-9a-f-]{36})\/input$/i);
212
+ if (req.method === 'POST' && input)
213
+ return { kind: 'input', sessionId: input[1] };
214
+ const close = url.pathname.match(/^\/api\/sessions\/([0-9a-f-]{36})\/close$/i);
215
+ if (req.method === 'POST' && close)
216
+ return { kind: 'close', sessionId: close[1] };
217
+ const projectSessions = url.pathname.match(/^\/api\/sessions\/([0-9a-f-]{36})\/project\/sessions$/i);
218
+ if (req.method === 'GET' && projectSessions)
219
+ return { kind: 'list', sessionId: projectSessions[1] };
220
+ if (req.method === 'POST' && projectSessions)
221
+ return { kind: 'create', sessionId: projectSessions[1] };
222
+ return null;
223
+ }
224
+ async function peerCreateRequest(req) {
225
+ const raw = await readRequest(req);
226
+ let parsed;
227
+ try {
228
+ parsed = JSON.parse(raw);
229
+ }
230
+ catch {
231
+ throw new Error('session create body must be JSON');
232
+ }
233
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
234
+ throw new Error('session create body must be a JSON object');
235
+ const input = parsed;
236
+ const unknown = Object.keys(input).filter((key) => !['prompt', 'launcher', 'name', 'base', 'requestKey'].includes(key)).sort();
237
+ if (unknown.length)
238
+ throw new Error(`unknown peer session-create field${unknown.length === 1 ? '' : 's'}: ${unknown.join(', ')}`);
239
+ if (typeof input.prompt !== 'string')
240
+ throw new Error('session-create prompt must be a string');
241
+ if (input.launcher !== undefined && typeof input.launcher !== 'string')
242
+ throw new Error('session-create launcher must be a string');
243
+ if (input.name !== undefined && typeof input.name !== 'string')
244
+ throw new Error('session-create name must be a string');
245
+ if (input.base !== undefined && typeof input.base !== 'string')
246
+ throw new Error('session-create base must be a string');
247
+ if (typeof input.requestKey !== 'string' || !/^[\x21-\x7e]{1,128}$/.test(input.requestKey)) {
248
+ throw new Error('session-create requestKey must be 1-128 visible ASCII characters');
249
+ }
250
+ return {
251
+ requestKey: input.requestKey,
252
+ body: {
253
+ prompt: input.prompt,
254
+ ...(input.launcher !== undefined ? { launcher: input.launcher } : {}),
255
+ ...(input.name !== undefined ? { name: input.name } : {}),
256
+ ...(input.base !== undefined ? { base: input.base } : {}),
257
+ },
258
+ };
259
+ }
260
+ async function forwardToProject(peer, req, res) {
261
+ const request = peerSessionRequest(req);
262
+ if (!request) {
263
+ json(res, 404, { error: 'peer accepts GET /api/sessions/<full-id>, POST /api/sessions/<full-id>/input, POST /api/sessions/<full-id>/close, GET /api/sessions/<full-id>/project/sessions, or POST /api/sessions/<full-id>/project/sessions only' });
264
+ return;
265
+ }
266
+ const { sessionId } = request;
267
+ const projects = peerProjectsForSession(sessionId);
268
+ if (!projects.length) {
269
+ json(res, 404, { error: `no local project owns session ${sessionId}` });
270
+ return;
271
+ }
272
+ if (projects.length > 1) {
273
+ json(res, 409, { error: `session ${sessionId} is ambiguous across ${projects.length} local projects` });
274
+ return;
275
+ }
276
+ if (projects[0].endpointConflict) {
277
+ json(res, 409, { error: projects[0].endpointConflict });
278
+ return;
279
+ }
280
+ if (!projects[0].url) {
281
+ json(res, 502, { error: `target backend for session ${sessionId} is offline` });
282
+ return;
283
+ }
284
+ let path = request.kind === 'list' || request.kind === 'create'
285
+ ? '/api/sessions'
286
+ : `/api/sessions/${encodeURIComponent(sessionId)}`;
287
+ let init = { method: 'GET' };
288
+ if (request.kind === 'input') {
289
+ let body;
290
+ try {
291
+ const parsed = JSON.parse(await readRequest(req));
292
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed) || parsed.kind !== 'text' || typeof parsed.text !== 'string')
293
+ throw new Error('input must be {kind:"text",text:"..."}');
294
+ body = {
295
+ kind: 'text', text: parsed.text,
296
+ from: validPeerSender(parsed.from, peer.machineId) ? parsed.from : peerSenderRef(peer.machineId),
297
+ };
298
+ }
299
+ catch (error) {
300
+ json(res, 400, { error: error.message });
301
+ return;
302
+ }
303
+ path += '/input';
304
+ init = { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) };
305
+ }
306
+ else if (request.kind === 'close') {
307
+ try {
308
+ await readRequest(req);
309
+ }
310
+ catch (error) {
311
+ json(res, 400, { error: error.message });
312
+ return;
313
+ }
314
+ // A peer cannot claim to be a local session on the receiving machine. Close is the backend's ordinary
315
+ // external-user operation, authorized here solely by the SSH-created loopback listener.
316
+ path += '/close';
317
+ init = { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ source: { kind: 'user' } }) };
318
+ }
319
+ else if (request.kind === 'create') {
320
+ let create;
321
+ try {
322
+ create = await peerCreateRequest(req);
323
+ }
324
+ catch (error) {
325
+ json(res, 400, { error: error.message });
326
+ return;
327
+ }
328
+ init = {
329
+ method: 'POST',
330
+ headers: { 'content-type': 'application/json', 'Idempotency-Key': create.requestKey },
331
+ body: JSON.stringify(create.body),
332
+ };
333
+ }
334
+ let upstream;
335
+ try {
336
+ upstream = await fetch(`${projects[0].url}${path}`, init);
337
+ }
338
+ catch (error) {
339
+ json(res, 502, { error: `target backend is unreachable: ${error.message}` });
340
+ return;
341
+ }
342
+ const text = await upstream.text();
343
+ res.writeHead(upstream.status, { 'content-type': upstream.headers.get('content-type') ?? 'application/json' });
344
+ res.end(text);
345
+ }
346
+ function validRpc(value) {
347
+ if (!value || typeof value !== 'object' || Array.isArray(value))
348
+ return false;
349
+ const request = value;
350
+ if (request.op === 'list')
351
+ return true;
352
+ if (request.op === 'connect' || request.op === 'disconnect')
353
+ return typeof request.sshAddress === 'string' && request.sshAddress.length > 0;
354
+ if (request.op === 'drop')
355
+ return validMachineId(request.machineId);
356
+ return request.op === 'accept' && validMachineId(request.sourceMachineId) && typeof request.sshAddress === 'string' && request.sshAddress.length > 0 &&
357
+ validPort(request.remoteInboundPort) && validPort(request.remoteOutboundPort);
358
+ }
359
+ function remoteCommand(op, body) {
360
+ return `spex internal ${op} ${Buffer.from(JSON.stringify(body)).toString('base64url')}`;
361
+ }
362
+ function sshArgs(peer) {
363
+ return [
364
+ '-N', '-o', 'ExitOnForwardFailure=yes',
365
+ '-L', `127.0.0.1:${peer.outboundPort}:127.0.0.1:${peer.remoteInboundPort}`,
366
+ '-R', `127.0.0.1:${peer.remoteOutboundPort}:127.0.0.1:${peer.inboundPort}`,
367
+ '--', peer.sshAddress,
368
+ ];
369
+ }
370
+ export class MachinePeerGateway {
371
+ inbound = new Map();
372
+ children = new Map();
373
+ control = null;
374
+ retry = null;
375
+ closing = false;
376
+ start() {
377
+ for (const peer of listMachinePeers())
378
+ this.startInbound(peer);
379
+ this.startControl();
380
+ for (const peer of listMachinePeers())
381
+ if (peer.owner)
382
+ this.ensureTunnel(peer);
383
+ this.retry = setInterval(() => {
384
+ for (const peer of listMachinePeers())
385
+ if (peer.owner && peer.state === 'connecting')
386
+ this.ensureTunnel(peer);
387
+ }, PEER_RETRY_MS);
388
+ this.retry.unref();
389
+ }
390
+ startControl() {
391
+ const path = peerSocketPath();
392
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
393
+ if (existsSync(path)) {
394
+ const error = new Error(`machine peer service already owns ${path} — another \`spex dashboard\` may be running`);
395
+ error.name = 'BackendError';
396
+ throw error;
397
+ }
398
+ this.control = createNetServer({ allowHalfOpen: true }, (socket) => {
399
+ let input = '';
400
+ socket.setEncoding('utf8');
401
+ socket.on('data', (chunk) => { input += chunk; });
402
+ socket.on('end', () => void this.handleRpc(input)
403
+ .then((reply) => socket.end(`${JSON.stringify(reply)}\n`))
404
+ .catch((error) => socket.end(`${JSON.stringify({ ok: false, error: error.message })}\n`)));
405
+ socket.on('error', () => socket.destroy());
406
+ });
407
+ this.control.listen(path);
408
+ try {
409
+ chmodSync(path, 0o600);
410
+ }
411
+ catch { /* platform lacks unix modes */ }
412
+ }
413
+ async handleRpc(raw) {
414
+ let request;
415
+ try {
416
+ request = JSON.parse(raw);
417
+ }
418
+ catch {
419
+ return { ok: false, error: 'peer control request is not JSON' };
420
+ }
421
+ if (!validRpc(request))
422
+ return { ok: false, error: 'invalid peer control request' };
423
+ try {
424
+ if (request.op === 'list')
425
+ return { ok: true, peers: listMachinePeers() };
426
+ if (request.op === 'connect')
427
+ return { ok: true, peer: await this.connect(request.sshAddress) };
428
+ if (request.op === 'accept')
429
+ return { ok: true, peer: await this.accept(request), machineId: readPeerMachineId() };
430
+ if (request.op === 'disconnect') {
431
+ const peer = await this.disconnect(request.sshAddress);
432
+ if (!peer)
433
+ throw new Error(`no communication tunnel for SSH address ${JSON.stringify(request.sshAddress)}`);
434
+ return { ok: true, peer };
435
+ }
436
+ return { ok: true, peer: await this.drop(request.machineId) ?? undefined };
437
+ }
438
+ catch (error) {
439
+ return { ok: false, error: error.message };
440
+ }
441
+ }
442
+ startInbound(peer) {
443
+ if (this.inbound.has(peer.machineId))
444
+ return;
445
+ const server = createHttpServer((req, res) => void forwardToProject(peer, req, res));
446
+ server.on('error', (error) => console.error(`[peer] ${peer.machineId} inbound port ${peer.inboundPort}: ${error.message}`));
447
+ server.listen(peer.inboundPort, '127.0.0.1');
448
+ this.inbound.set(peer.machineId, server);
449
+ }
450
+ stopInbound(machineId) {
451
+ const server = this.inbound.get(machineId);
452
+ if (!server)
453
+ return;
454
+ this.inbound.delete(machineId);
455
+ server.close();
456
+ }
457
+ ensureTunnel(peer) {
458
+ if (this.closing || this.children.has(peer.machineId))
459
+ return;
460
+ this.startInbound(peer);
461
+ const child = spawn('ssh', sshArgs(peer), { stdio: 'ignore' });
462
+ this.children.set(peer.machineId, child);
463
+ child.once('error', (error) => this.tunnelEnded(peer.machineId, error.message));
464
+ child.once('exit', (code, signal) => this.tunnelEnded(peer.machineId, `ssh exited (${code ?? signal ?? 'unknown'})`));
465
+ const next = { ...peer, state: 'connected', lastOkAt: new Date().toISOString(), lastError: null };
466
+ replacePeer(next);
467
+ }
468
+ tunnelEnded(machineId, error) {
469
+ this.children.delete(machineId);
470
+ if (this.closing)
471
+ return;
472
+ const peer = listMachinePeers().find((item) => item.machineId === machineId);
473
+ if (!peer || !peer.owner)
474
+ return;
475
+ replacePeer({ ...peer, state: 'connecting', lastError: error });
476
+ }
477
+ async connect(sshAddress) {
478
+ const existing = findMachinePeer(sshAddress);
479
+ if (existing) {
480
+ if (existing.owner)
481
+ this.ensureTunnel(existing);
482
+ return existing;
483
+ }
484
+ if (sshAddress.startsWith('-'))
485
+ throw new Error('SSH address must not begin with -');
486
+ const inboundPort = await freePort();
487
+ const outboundPort = await freePort();
488
+ const sourceMachineId = readPeerMachineId();
489
+ const remote = await execFileAsync('ssh', ['--', sshAddress, remoteCommand('peer-accept', {
490
+ sourceMachineId, sshAddress, remoteInboundPort: inboundPort, remoteOutboundPort: outboundPort,
491
+ })], { maxBuffer: 64 * 1024 });
492
+ let reply;
493
+ try {
494
+ reply = JSON.parse(remote.stdout.trim());
495
+ }
496
+ catch {
497
+ throw new Error(`remote peer accept returned invalid JSON: ${remote.stdout.trim() || remote.stderr.trim()}`);
498
+ }
499
+ if (!reply.ok || !reply.peer || !validMachineId(reply.machineId))
500
+ throw new Error(reply.ok ? 'remote peer accept returned no machine identity' : reply.error);
501
+ const peer = {
502
+ machineId: reply.machineId, sshAddress, inboundPort, outboundPort,
503
+ remoteInboundPort: reply.peer.inboundPort, remoteOutboundPort: reply.peer.outboundPort,
504
+ owner: true, state: 'connecting', createdAt: new Date().toISOString(), lastOkAt: null, lastError: null,
505
+ };
506
+ replacePeer(peer);
507
+ this.startInbound(peer);
508
+ this.ensureTunnel(peer);
509
+ return findMachinePeer(sshAddress) ?? peer;
510
+ }
511
+ async accept(request) {
512
+ const existing = listMachinePeers().find((peer) => peer.machineId === request.sourceMachineId);
513
+ if (existing)
514
+ return existing;
515
+ const peer = {
516
+ machineId: request.sourceMachineId, sshAddress: request.sshAddress,
517
+ inboundPort: await freePort(), outboundPort: await freePort(),
518
+ remoteInboundPort: request.remoteInboundPort, remoteOutboundPort: request.remoteOutboundPort,
519
+ owner: false, state: 'connected', createdAt: new Date().toISOString(), lastOkAt: new Date().toISOString(), lastError: null,
520
+ };
521
+ replacePeer(peer);
522
+ this.startInbound(peer);
523
+ return peer;
524
+ }
525
+ async drop(machineId) {
526
+ const child = this.children.get(machineId);
527
+ if (child) {
528
+ this.children.delete(machineId);
529
+ try {
530
+ child.kill('SIGTERM');
531
+ }
532
+ catch { /* already gone */ }
533
+ }
534
+ this.stopInbound(machineId);
535
+ return removePeer((peer) => peer.machineId === machineId);
536
+ }
537
+ async disconnect(sshAddress) {
538
+ const peer = findMachinePeer(sshAddress);
539
+ if (!peer)
540
+ return null;
541
+ const removed = await this.drop(peer.machineId);
542
+ if (peer.owner) {
543
+ try {
544
+ await execFileAsync('ssh', ['--', peer.sshAddress, remoteCommand('peer-drop', { machineId: readPeerMachineId() })], { maxBuffer: 64 * 1024 });
545
+ }
546
+ catch (error) {
547
+ console.error(`[peer] remote peer cleanup failed for ${peer.sshAddress}: ${error.message}`);
548
+ }
549
+ }
550
+ return removed;
551
+ }
552
+ async close() {
553
+ this.closing = true;
554
+ if (this.retry)
555
+ clearInterval(this.retry);
556
+ for (const child of this.children.values())
557
+ try {
558
+ child.kill('SIGTERM');
559
+ }
560
+ catch { /* already gone */ }
561
+ this.children.clear();
562
+ for (const server of this.inbound.values())
563
+ server.close();
564
+ this.inbound.clear();
565
+ const control = this.control;
566
+ this.control = null;
567
+ if (control)
568
+ await new Promise((resolve) => control.close(() => resolve()));
569
+ try {
570
+ rmSync(peerSocketPath());
571
+ }
572
+ catch { /* already removed */ }
573
+ }
574
+ }
575
+ export async function peerRpc(request) {
576
+ const path = peerSocketPath();
577
+ return await new Promise((resolve, reject) => {
578
+ const socket = createConnection(path);
579
+ let output = '';
580
+ socket.setEncoding('utf8');
581
+ socket.once('connect', () => socket.end(JSON.stringify(request)));
582
+ socket.on('data', (chunk) => { output += chunk; });
583
+ socket.once('error', (error) => reject(new Error(`no host gateway peer service at ${path} — run \`spex dashboard\` (${error.message})`)));
584
+ socket.once('end', () => {
585
+ try {
586
+ resolve(JSON.parse(output));
587
+ }
588
+ catch {
589
+ reject(new Error('host gateway peer service returned invalid JSON'));
590
+ }
591
+ });
592
+ });
593
+ }
594
+ export async function peerControlOrThrow(request) {
595
+ const reply = await peerRpc(request);
596
+ if (!reply.ok)
597
+ throw new Error(reply.error);
598
+ if (reply.peers)
599
+ return reply.peers;
600
+ if (reply.peer)
601
+ return reply.peer;
602
+ return [];
603
+ }
@@ -0,0 +1,18 @@
1
+ import { type HarnessArtifacts } from './harness.js';
2
+ export type MaterializedArtifact = {
3
+ kind: 'hook manifest' | 'contract' | 'shim' | 'skill' | 'agent' | 'plugin bundle' | 'trust';
4
+ path: string;
5
+ };
6
+ export type MaterializeResult = {
7
+ contentHash: string;
8
+ planted: MaterializedArtifact[];
9
+ };
10
+ export declare function contentHash(proj: string): string;
11
+ export declare function retiredAxisNotice(cfg: {
12
+ render?: string;
13
+ private?: boolean;
14
+ }): void;
15
+ export declare function stripSpexcodeBlock(text: string, comment?: readonly [string, string]): string;
16
+ export declare const GENERATED_MARK = "<!-- spexcode:generated -->";
17
+ export declare function dematerialize(proj?: string, arts?: HarnessArtifacts): void;
18
+ export declare function materialize(proj?: string): MaterializeResult;