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
@@ -0,0 +1,548 @@
1
+ import { readFileSync, existsSync, readdirSync } from 'node:fs';
2
+ import { join, dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { git, repoRoot, gitA, gitAbortError, currentGitBuildAbortSignal, gitInterpretationIdentity, headSha, worktreeSpecSig, worktreeSpecDelta, worktreeSpecDeltas, withGitAbortSignal } from './git.js';
5
+ import { guardWorktree } from './resilience.js';
6
+ import { HARNESS_IDENTITIES } from './harness-identity.js';
7
+ import { encodeProject, projectRuntimeRoot } from './project-store.js';
8
+ // Read an OPTIONAL JSON config file. An ABSENT file is the legitimate default (return {}); a
9
+ // PRESENT-but-malformed one is a user error we must NOT swallow — a typo would otherwise silently
10
+ // drop every tuned setting the file holds (lint budgets, launchers, layout) and revert to defaults
11
+ // with no diagnostic. Fail LOUD, naming the file and the parse error, so the author sees what broke.
12
+ export function readJsonConfig(p) {
13
+ if (!existsSync(p))
14
+ return {};
15
+ try {
16
+ return JSON.parse(readFileSync(p, 'utf8'));
17
+ }
18
+ catch (e) {
19
+ const err = new Error(`malformed ${p}: ${e.message}\n → its settings were NOT applied. Fix the JSON syntax (an absent file is a fine default; a broken one is not).`);
20
+ err.name = 'ConfigError'; // rendered message-only at the CLI boundary (like BackendError), not as a stack dump
21
+ throw err;
22
+ }
23
+ }
24
+ // committed `spexcode.json` with an OPTIONAL machine-local `spexcode.local.json` layered on top (gitignored).
25
+ // The local layer is the durable home for HOST-SPECIFIC values that must never be committed — e.g. an
26
+ // absolute worker-launcher path (the host-path leak the repo otherwise warns against). Precedence per field:
27
+ // local over committed; a targeted env override (e.g. SPEXCODE_CODEX_SERVER_CMD) still wins at its read site.
28
+ export function readConfig(root) {
29
+ const committed = readJsonConfig(join(root, 'spexcode.json'));
30
+ const local = readJsonConfig(join(root, 'spexcode.local.json'));
31
+ const out = { ...committed };
32
+ for (const k of Object.keys(local)) {
33
+ const b = committed[k], o = local[k];
34
+ out[k] = (b && o && typeof b === 'object' && typeof o === 'object' && !Array.isArray(o)) ? { ...b, ...o } : o;
35
+ }
36
+ return out;
37
+ }
38
+ export const templateConfigPath = fileURLToPath(new URL('../templates/spexcode.json', import.meta.url));
39
+ const MIN_POSITIVE_INTEGER = 1;
40
+ const MIN_NONNEGATIVE_INTEGER = 0;
41
+ function uploadConfigError(field, rule) {
42
+ const error = new Error(`uploads.${field} must be ${rule}`);
43
+ error.name = 'ConfigError';
44
+ throw error;
45
+ }
46
+ function configuredInteger(value, field, minimum) {
47
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum) {
48
+ uploadConfigError(field, minimum === MIN_POSITIVE_INTEGER ? 'a positive integer' : 'a non-negative integer');
49
+ }
50
+ return value;
51
+ }
52
+ function resolveUploadPolicy(values) {
53
+ const policy = {
54
+ maxBytes: configuredInteger(values.maxBytes, 'maxBytes', MIN_POSITIVE_INTEGER),
55
+ chunkBytes: configuredInteger(values.chunkBytes, 'chunkBytes', MIN_POSITIVE_INTEGER),
56
+ concurrency: configuredInteger(values.concurrency, 'concurrency', MIN_POSITIVE_INTEGER),
57
+ requestTimeoutMs: configuredInteger(values.requestTimeoutMs, 'requestTimeoutMs', MIN_POSITIVE_INTEGER),
58
+ retryLimit: configuredInteger(values.retryLimit, 'retryLimit', MIN_NONNEGATIVE_INTEGER),
59
+ retryDelayMs: configuredInteger(values.retryDelayMs, 'retryDelayMs', MIN_NONNEGATIVE_INTEGER),
60
+ incompleteTtlMs: configuredInteger(values.incompleteTtlMs, 'incompleteTtlMs', MIN_POSITIVE_INTEGER),
61
+ cleanupIntervalMs: configuredInteger(values.cleanupIntervalMs, 'cleanupIntervalMs', MIN_POSITIVE_INTEGER),
62
+ minFreeBytes: configuredInteger(values.minFreeBytes, 'minFreeBytes', MIN_NONNEGATIVE_INTEGER),
63
+ evidenceMaxBytes: configuredInteger(values.evidenceMaxBytes, 'evidenceMaxBytes', MIN_POSITIVE_INTEGER),
64
+ };
65
+ if (policy.chunkBytes > policy.maxBytes)
66
+ uploadConfigError('chunkBytes', 'no greater than uploads.maxBytes');
67
+ return policy;
68
+ }
69
+ export function uploadPolicyDefaults() {
70
+ return resolveUploadPolicy(readJsonConfig(templateConfigPath).uploads);
71
+ }
72
+ // The seed template is the sole default-value source. Existing projects may omit `uploads`; they receive this
73
+ // policy, while a committed/local value overrides it through readConfig's existing one-level merge.
74
+ export function readUploadPolicy(root) {
75
+ const configured = readConfig(root).uploads;
76
+ return resolveUploadPolicy({ ...uploadPolicyDefaults(), ...configured });
77
+ }
78
+ // The shared git common dir (env-stripped git() so a hook's exported GIT_DIR can't misdirect it).
79
+ // Cache by resolved checkout path: callers may deliberately chdir between isolated repositories in one process.
80
+ const commonDirsByPath = new Map();
81
+ const topsByPath = new Map();
82
+ export function gitCommonDir() {
83
+ return commonDirFor(process.cwd());
84
+ }
85
+ function commonDirFor(proj) {
86
+ const key = resolve(proj);
87
+ const known = commonDirsByPath.get(key);
88
+ if (known)
89
+ return known;
90
+ const common = git(['-C', proj, 'rev-parse', '--path-format=absolute', '--git-common-dir']).trim();
91
+ commonDirsByPath.set(key, common);
92
+ return common;
93
+ }
94
+ function topFor(proj) {
95
+ const key = resolve(proj);
96
+ const known = topsByPath.get(key);
97
+ if (known)
98
+ return known;
99
+ const top = git(['-C', proj, 'rev-parse', '--show-toplevel']).trim();
100
+ topsByPath.set(key, top);
101
+ return top;
102
+ }
103
+ export function mainBranch() {
104
+ let checkout;
105
+ try {
106
+ checkout = mainCheckout();
107
+ }
108
+ catch {
109
+ return 'main';
110
+ }
111
+ return readConfig(checkout).mainBranch?.trim() || 'main';
112
+ }
113
+ // the MAIN checkout (the root working tree) for a project — the SAME answer from main OR any linked worktree
114
+ // (dirname of the shared git common dir). Codex reads a LINKED worktree's PROJECT hooks from the root checkout's
115
+ // `.codex` (codex-rs hooks_config_folder override), NOT the worktree's, so the codex hooks shim + trust
116
+ // materialize here while AGENTS.md/skills stay per-worktree — see [[harness-adapter]] (harness.ts).
117
+ export function mainCheckout(proj) {
118
+ const gcd = proj ? commonDirFor(proj) : gitCommonDir();
119
+ return dirname(gcd);
120
+ }
121
+ // @@@ main root - identity checks need creation's configured-main answer without the record/overlay work in resolveLayout.
122
+ export function mainRoot(proj) {
123
+ if (proj) {
124
+ const checkout = mainCheckout(proj);
125
+ const configured = readConfig(checkout).main?.trim();
126
+ return configured ? resolve(checkout, configured) : checkout;
127
+ }
128
+ try {
129
+ const checkout = mainCheckout();
130
+ const configured = readConfig(checkout).main?.trim();
131
+ return configured ? resolve(checkout, configured) : checkout;
132
+ }
133
+ catch {
134
+ return repoRoot();
135
+ }
136
+ }
137
+ // @@@ global per-session store - Fork A: NO SpexCode files live in the worktree any more, so the worktree's
138
+ // spec/code tree is pristine (zero per-session pollution). Every per-session runtime artifact — the
139
+ // structured record (session.json) AND the launcher products (prompt, launch, launch.sh) AND the recorded comms AND
140
+ // the spec-discipline sentinels — lives in a per-USER GLOBAL store, keyed by the harness `session_id` so two
141
+ // agents in one folder never clobber, and grouped PER PROJECT (mirroring Claude's ~/.claude/projects/<enc>/)
142
+ // so the board enumerates ONE directory. This is the single seam that knows where the store sits; sessions.ts
143
+ // and the shell hooks resolve through the SAME scheme (the hooks reimplement it in bash, so any change here
144
+ // must be mirrored in .plugins/core/*/). SPEXCODE_HOME overrides the root for test isolation.
145
+ // encode a project-root path into ONE safe directory segment (Claude's scheme: path separators → '-'). The
146
+ // SAME transform runs in TS and in the shell hooks, so a board read and a hook write land on the SAME dir.
147
+ // this project's per-PROJECT runtime tier — the sessions/ records AND the per-TREE materialize slots (below) —
148
+ // living under the SAME global per-project dir, so NOTHING SpexCode materializes stays in the worktree (the
149
+ // worktree holds only the harness-discovered CLAUDE.md/AGENTS.md + shims, which must sit in-tree).
150
+ // proj-aware for `spex init <dir>` / materialize(proj); cwd-based default for the hooks/board. The shell
151
+ // hooks mirror this as hp_runtime_dir.
152
+ export function runtimeRoot(proj) {
153
+ const gcd = proj ? commonDirFor(proj) : gitCommonDir();
154
+ return projectRuntimeRoot(gcd);
155
+ }
156
+ // the per-WORKTREE materialize slot — <runtime>/trees/<enc(worktree-toplevel)> — holding the materialize
157
+ // products that are a pure function of ONE tree's .plugins (hooks-manifest, content-hash, plugin-folders).
158
+ // Slotted per tree exactly like sessions/<id> is slotted per session: the old single global file made the
159
+ // last-materialized tree win, so dispatch ran tree A's compiled hook set inside tree B's sessions
160
+ // ([[hook-dispatch]]). Key = the sessions encodeProject transform over `rev-parse --show-toplevel`, the
161
+ // SAME derivation dispatch.sh's shell mirror (hp_tree_dir) runs from its own cwd — so writer and reader
162
+ // land on the same slot from the same tree, and only from the same tree. Throws when `wt` is not a live
163
+ // git tree (fail loud); a best-effort caller (the close-time GC) wraps it.
164
+ export function treeSlotDir(wt) {
165
+ const top = topFor(wt);
166
+ return join(runtimeRoot(wt), 'trees', encodeProject(top || wt));
167
+ }
168
+ // this project's per-session records dir, one session's dir, its structured record, and a sibling artifact —
169
+ // all keyed by session_id under <home>/projects/<enc>/sessions/.
170
+ export function sessionsRoot() { return join(runtimeRoot(), 'sessions'); }
171
+ export function sessionStoreDir(id) { return join(sessionsRoot(), id); }
172
+ export function sessionRecordPath(id) { return join(sessionStoreDir(id), 'session.json'); }
173
+ export function sessionArtifactPath(id, name) { return join(sessionStoreDir(id), name); }
174
+ export const SESSION_LIFECYCLES = ['active', 'idle', 'awaiting', 'parked', 'error', 'asking', 'queued'];
175
+ export const SESSION_PROPOSALS = ['merge', 'nothing', 'close'];
176
+ const sessionLifecycles = new Set(SESSION_LIFECYCLES);
177
+ const sessionProposals = new Set(SESSION_PROPOSALS);
178
+ export const isSessionLifecycle = (value) => typeof value === 'string' && sessionLifecycles.has(value);
179
+ export const isSessionProposal = (value) => typeof value === 'string' && sessionProposals.has(value);
180
+ // A launch candidate is durable before it is public. Readers of the authored lifecycle use this one parser
181
+ // so the board and the independent timeline observer cannot disagree about an in-flight resume. Invalid
182
+ // pending bytes throw: a damaged publication fence is unknowable state, never permission to project online.
183
+ export function rawLaunchReadinessOriginal(raw) {
184
+ const pending = raw.launch_readiness_pending;
185
+ if (pending == null || pending === '')
186
+ return null;
187
+ const original = pending && typeof pending === 'object' ? pending.original : null;
188
+ if (pending.version !== 1 || !Number.isFinite(pending.startedAt) || !original || typeof original !== 'object'
189
+ || !isSessionLifecycle(original.status)
190
+ || !(original.proposal === null || original.proposal === '' || isSessionProposal(original.proposal))
191
+ || !(typeof original.note === 'string' || original.note === null)
192
+ || typeof original.stopped !== 'boolean' || typeof original.archived !== 'boolean'
193
+ || !(typeof original.cold_proof === 'string' || original.cold_proof === null)
194
+ || !(typeof original.adapter_recovery === 'string' || original.adapter_recovery === null)) {
195
+ throw new Error(`session '${raw.session_id}' has an invalid launch_readiness_pending fence`);
196
+ }
197
+ return original;
198
+ }
199
+ // the agent's OWN session id from the environment — the only locator now that the record left the worktree.
200
+ // Three tiers, in order:
201
+ // (1) a harness's per-thread env var (`sessionEnvVar`) RESOLVED VIA THE ALIAS — when it lands on a governed
202
+ // record (directly, or through that record's `harness_session_id`), that record's SpexCode id is the
203
+ // answer. This MUST win: codex's design-C runs ONE shared per-project app-server whose env carries the
204
+ // FIRST launched session's `SPEXCODE_SESSION_ID`, and the agent's shell tool (its `spex session
205
+ // done/park/ask`) runs INSIDE that app-server process, so `SPEXCODE_SESSION_ID` is contaminated with the
206
+ // wrong session. But codex injects the ACTING thread's id into every spawned command's env as
207
+ // CODEX_THREAD_ID (== codex's `sessionEnvVar`), so the per-thread var aliases to the RIGHT record while
208
+ // the shared `SPEXCODE_SESSION_ID` does not.
209
+ // (2) else `SPEXCODE_SESSION_ID` (the GOVERNED record id the launcher bakes in) — the claude path and the
210
+ // non-shared baseline.
211
+ // (3) else a harness's env var RAW — a self-launched, non-governed agent's own minted id, which has no
212
+ // governed record to alias to (codex CODEX_THREAD_ID / claude CLAUDE_CODE_SESSION_ID). The RAW form must
213
+ // stay BELOW (2): an un-aliased codex thread id is not a record key, so it must never beat a real
214
+ // `SPEXCODE_SESSION_ID`.
215
+ // Claude is UNCHANGED: its `sessionEnvVar` (CLAUDE_CODE_SESSION_ID) already EQUALS its record id, so tier (1)
216
+ // resolves to that very id — the same value `SPEXCODE_SESSION_ID` would have returned; there is no shared
217
+ // app-server to contaminate it. No worktree fallback. (sessions.ts's `ownSessionId` delegates here; spec-eval
218
+ // reads it to resolve the current node.)
219
+ export function envSessionId() {
220
+ for (const h of HARNESS_IDENTITIES) {
221
+ const v = process.env[h.sessionEnvVar];
222
+ if (v && v.trim()) {
223
+ const r = readAliasedRawRecord(v.trim());
224
+ if (r)
225
+ return r.session_id;
226
+ }
227
+ }
228
+ const o = process.env.SPEXCODE_SESSION_ID;
229
+ if (o && o.trim())
230
+ return o.trim();
231
+ for (const h of HARNESS_IDENTITIES) {
232
+ const v = process.env[h.sessionEnvVar];
233
+ if (v && v.trim())
234
+ return v.trim();
235
+ }
236
+ return null;
237
+ }
238
+ export function readRecordEntry(id) {
239
+ const path = sessionRecordPath(id);
240
+ let text;
241
+ try {
242
+ text = readFileSync(path, 'utf8');
243
+ }
244
+ catch (e) {
245
+ if (e.code === 'ENOENT')
246
+ return { kind: 'absent' };
247
+ throw e;
248
+ }
249
+ let raw;
250
+ try {
251
+ raw = JSON.parse(text);
252
+ }
253
+ catch (e) {
254
+ return { kind: 'corrupt', path, error: e instanceof Error ? e.message : String(e) };
255
+ }
256
+ if (!raw || typeof raw !== 'object' || !raw.session_id)
257
+ return { kind: 'corrupt', path, error: 'parsed, but carries no session_id — not a session record' };
258
+ return { kind: 'ok', raw: raw };
259
+ }
260
+ // The ONE public session-record parser. Internal mutation/readiness code uses readRecordEntry's exact raw
261
+ // candidate; every public projection passes through here. A valid pending fence replaces all lifecycle-facing
262
+ // fields with its frozen original and forces offline liveness. Malformed pending bytes remain a present,
263
+ // corrupt/unknown row instead of leaking candidate state or disappearing as absence.
264
+ export function projectPublicRecordEntry(id, entry) {
265
+ if (entry.kind === 'absent')
266
+ return entry;
267
+ if (entry.kind === 'corrupt')
268
+ return {
269
+ kind: 'corrupt', sessionId: id, governed: null, path: entry.path, error: entry.error, liveness: 'unknown',
270
+ };
271
+ try {
272
+ const original = rawLaunchReadinessOriginal(entry.raw);
273
+ if (!original)
274
+ return { kind: 'ok', raw: entry.raw, liveness: null };
275
+ return {
276
+ kind: 'ok',
277
+ raw: {
278
+ ...entry.raw,
279
+ status: original.status,
280
+ proposal: original.proposal || null,
281
+ note: original.note || null,
282
+ stopped: original.stopped,
283
+ archived: original.archived,
284
+ cold_proof: original.cold_proof ?? undefined,
285
+ adapter_recovery: original.adapter_recovery ?? undefined,
286
+ launch_readiness_pending: '',
287
+ },
288
+ liveness: 'offline',
289
+ };
290
+ }
291
+ catch (error) {
292
+ return {
293
+ kind: 'corrupt',
294
+ sessionId: id,
295
+ governed: typeof entry.raw.governed === 'boolean' ? entry.raw.governed : null,
296
+ path: sessionRecordPath(id),
297
+ error: error instanceof Error ? error.message : String(error),
298
+ liveness: 'unknown',
299
+ };
300
+ }
301
+ }
302
+ export function readPublicRecordEntry(id) {
303
+ return projectPublicRecordEntry(id, readRecordEntry(id));
304
+ }
305
+ export function readRawRecord(id) {
306
+ try {
307
+ const e = readRecordEntry(id);
308
+ return e.kind === 'ok' ? e.raw : null;
309
+ }
310
+ catch {
311
+ return null;
312
+ }
313
+ }
314
+ // resolve a possibly-ALIASED session id to its raw record. A codex hook or spawned command can carry the codex
315
+ // THREAD id — payload session_id / CODEX_THREAD_ID — not the SpexCode record id the store is keyed by. Direct id
316
+ // wins; else the one record that captured this id as `harness_session_id` (the backend stored it at thread/start,
317
+ // before any tool turn).
318
+ // Null when neither resolves. Mirrors the shell `hp_store_dir` alias grep — one resolution rule, both layers.
319
+ export function readAliasedRawRecord(id) {
320
+ const e = readAliasedRecordEntry(id);
321
+ return e.kind === 'ok' ? e.raw : null;
322
+ }
323
+ // the same alias resolution, keeping the three-way outcome. A CORRUPT record at the direct id settles the
324
+ // question — we found this session and cannot read it; walking on to the alias would report a corrupt record
325
+ // as absent, the exact collapse this type exists to prevent.
326
+ export function readAliasedRecordEntry(id) {
327
+ const direct = readRecordEntry(id);
328
+ if (direct.kind !== 'absent')
329
+ return direct;
330
+ // @@@ absence splits in two, and only one half is an alias question - an id owning a store dir is already
331
+ // one of ours (the sentinel-only agent above), so its emptiness is settled; searching would let an unrelated
332
+ // record answer under a live session's own name, and costs a whole-store re-parse per 1s supervisor tick.
333
+ if (existsSync(sessionStoreDir(id)))
334
+ return { kind: 'absent' };
335
+ for (const sid of listSessionIds()) {
336
+ const r = readRawRecord(sid);
337
+ if (r && r.harness_session_id && r.harness_session_id === id)
338
+ return { kind: 'ok', raw: r };
339
+ }
340
+ return { kind: 'absent' };
341
+ }
342
+ // every session_id this project has a record for (the board's enumeration source — replaces `git worktree
343
+ // list`). A MISSING store dir means no session ever launched → []. But any OTHER readdir failure THROWS
344
+ // (preserving the fail-loud-enumeration invariant `git worktree list` had): a transient FS error must never
345
+ // read as "every session vanished" — the watch poll skips the tick on a throw, never emitting a false mass-close.
346
+ export function listSessionIds() {
347
+ let ents;
348
+ try {
349
+ ents = readdirSync(sessionsRoot(), { withFileTypes: true });
350
+ }
351
+ catch (e) {
352
+ if (e.code === 'ENOENT')
353
+ return [];
354
+ throw e;
355
+ }
356
+ return ents.filter((d) => d.isDirectory()).map((d) => d.name);
357
+ }
358
+ // @@@ branch -> session, so a moved ref can DERIVE its invalidation scope - a session's evaluation depends
359
+ // on its own branch tip, the base branch tip and their merge-base; no other ref participates. Without this
360
+ // map a ref watcher knows only that "something under refs/ moved" and the honest fallback is to invalidate
361
+ // every session ([[taste]] 19). One record read per session, and only when the session store itself moved.
362
+ export function sessionBranchIndex() {
363
+ const index = new Map();
364
+ for (const id of listSessionIds()) {
365
+ let branch;
366
+ try {
367
+ branch = readRawRecord(id)?.branch;
368
+ }
369
+ catch {
370
+ continue;
371
+ } // a corrupt record narrows nothing
372
+ if (typeof branch === 'string' && branch)
373
+ index.set(branch, id);
374
+ }
375
+ return index;
376
+ }
377
+ // Retain only completed per-worktree overlays. Interpretation + main tip + HEAD + working signature completely
378
+ // determine the merge-base and projection; a landed main tip therefore dissolves now-moot ops on the next read.
379
+ const deltaCache = new Map();
380
+ const safeHead = (p) => { try {
381
+ return headSha(p);
382
+ }
383
+ catch {
384
+ return '';
385
+ } };
386
+ let layoutHeadWarned = false;
387
+ const layoutDeltaFlights = new Map();
388
+ // One exact public layout generation owns the cold overlay computation. The map is only an in-flight join:
389
+ // the entry is deleted at settlement and deltaCache remains the sole retained result state.
390
+ async function layoutDeltas(paths, main, mainRef, mainSha) {
391
+ const snapshots = paths.map((path) => ({ path, head: safeHead(path), sig: worktreeSpecSig(path) }));
392
+ const interpretation = gitInterpretationIdentity(main);
393
+ const flightKey = JSON.stringify([interpretation, mainRef, mainSha, snapshots.map(({ path, head, sig }) => [path, head, sig]).sort((a, b) => a[0].localeCompare(b[0]))]);
394
+ let flight = layoutDeltaFlights.get(flightKey);
395
+ if (flight?.controller.signal.aborted) {
396
+ layoutDeltaFlights.delete(flightKey);
397
+ flight = undefined;
398
+ }
399
+ if (!flight) {
400
+ const controller = new AbortController();
401
+ const entry = { promise: Promise.resolve(new Map()), controller, waiters: new Set(), settled: false };
402
+ entry.promise = withGitAbortSignal(controller.signal, async () => {
403
+ const outcomes = new Map();
404
+ const misses = [];
405
+ for (const snapshot of snapshots) {
406
+ const key = `${interpretation}\0${mainSha}\0${snapshot.head}\0${snapshot.sig}`;
407
+ const hit = snapshot.head && mainSha ? deltaCache.get(snapshot.path) : null;
408
+ if (hit?.key === key)
409
+ outcomes.set(snapshot.path, { ops: hit.ops });
410
+ else
411
+ misses.push(snapshot);
412
+ }
413
+ const valid = misses.filter(({ head }) => !!head && !!mainSha);
414
+ const batched = await worktreeSpecDeltas(main, mainSha, valid.map(({ path, head }) => ({ path, head })), interpretation);
415
+ for (const snapshot of valid) {
416
+ const outcome = batched.get(snapshot.path) ?? { error: new Error(`layout overlay batch omitted ${snapshot.path}`) };
417
+ if ('error' in outcome)
418
+ outcomes.set(snapshot.path, outcome);
419
+ else {
420
+ const key = `${interpretation}\0${mainSha}\0${snapshot.head}\0${snapshot.sig}`;
421
+ deltaCache.set(snapshot.path, { key, ops: outcome.ops });
422
+ outcomes.set(snapshot.path, { ops: outcome.ops });
423
+ }
424
+ }
425
+ await Promise.all(misses.filter(({ head }) => !head || !mainSha).map(async (snapshot) => {
426
+ if (!existsSync(snapshot.path)) {
427
+ outcomes.set(snapshot.path, { error: new Error(`worktree ${snapshot.path} is absent`) });
428
+ return;
429
+ }
430
+ if (!layoutHeadWarned) {
431
+ layoutHeadWarned = true;
432
+ console.warn('spec-cli: layout overlay cache bypassed (unreadable HEAD/main tip), recomputing every read');
433
+ }
434
+ try {
435
+ outcomes.set(snapshot.path, { ops: await worktreeSpecDelta(snapshot.path, mainRef) });
436
+ }
437
+ catch (error) {
438
+ outcomes.set(snapshot.path, { error });
439
+ }
440
+ }));
441
+ return outcomes;
442
+ }).finally(() => {
443
+ entry.settled = true;
444
+ if (layoutDeltaFlights.get(flightKey) === entry)
445
+ layoutDeltaFlights.delete(flightKey);
446
+ });
447
+ layoutDeltaFlights.set(flightKey, entry);
448
+ flight = entry;
449
+ }
450
+ const token = Symbol(flightKey);
451
+ const callerSignal = currentGitBuildAbortSignal();
452
+ flight.waiters.add(token);
453
+ let onAbort = null;
454
+ try {
455
+ if (!callerSignal)
456
+ return await flight.promise;
457
+ if (callerSignal.aborted)
458
+ throw gitAbortError();
459
+ return await Promise.race([
460
+ flight.promise,
461
+ new Promise((_, reject) => {
462
+ onAbort = () => reject(gitAbortError());
463
+ callerSignal.addEventListener('abort', onAbort, { once: true });
464
+ }),
465
+ ]);
466
+ }
467
+ finally {
468
+ if (onAbort)
469
+ callerSignal?.removeEventListener('abort', onAbort);
470
+ flight.waiters.delete(token);
471
+ if (!flight.settled && flight.waiters.size === 0)
472
+ flight.controller.abort();
473
+ }
474
+ }
475
+ export async function resolveLayout(options = {}) {
476
+ const root = repoRoot();
477
+ const main = dirname(gitCommonDir()); // the main checkout — same answer from main OR any linked worktree
478
+ const cfg = readConfig(main);
479
+ const base = mainBranch();
480
+ const convention = {
481
+ main: cfg.main || '',
482
+ mainBranch: base,
483
+ branchPrefix: cfg.branchPrefix ?? 'node/',
484
+ };
485
+ const mainRef = base;
486
+ // the board enumerates the GLOBAL per-session store (NOT `git worktree list`): every GOVERNED record this
487
+ // project owns, each carrying the worktree_path its spec-delta is computed from. Non-governed (user-self-
488
+ // launched) records are excluded — board state is a managed-session concern ([[state]]). Each delta is
489
+ // independent → compute (or cache-hit) in parallel, keyed by worktree path as before. guardWorktree wraps
490
+ // each: a worktree whose dir was genuinely removed mid-read (a worker self-merged + retired it) is OMITTED;
491
+ // one that still exists but hit a transient detail failure is kept as a DEGRADED row from the last cached delta.
492
+ const publicEntries = listSessionIds().map((id) => readPublicRecordEntry(id))
493
+ .filter((entry) => entry.kind === 'corrupt' ? entry.governed !== false : entry.kind === 'ok' && entry.raw.governed);
494
+ const records = publicEntries.flatMap((entry) => entry.kind === 'ok' ? [entry] : []);
495
+ const projectedActive = options.activeSessionIds ? new Set(options.activeSessionIds) : null;
496
+ const isActive = (record) => projectedActive
497
+ ? projectedActive.has(record.session_id)
498
+ : !record.archived;
499
+ // main's tip, resolved ONCE per board read — a component of every worktree's overlay cache key
500
+ // ([[worktree-linker]]: landed content must dissolve the ops it made moot).
501
+ const mainSha = await (async () => {
502
+ try {
503
+ return (await gitA(['-C', main, 'rev-parse', '--verify', `${mainRef}^{commit}`])).trim();
504
+ }
505
+ catch {
506
+ return '';
507
+ }
508
+ })();
509
+ const activePaths = records.filter(({ raw }) => isActive(raw)).map(({ raw }) => raw.worktree_path);
510
+ const deltas = await layoutDeltas(activePaths, main, mainRef, mainSha);
511
+ const rows = await Promise.all(records.map(({ raw: r, liveness }) => {
512
+ const node = r.node ?? (r.branch && r.branch.startsWith(convention.branchPrefix) ? r.branch.slice(convention.branchPrefix.length) : null);
513
+ const base = { path: r.worktree_path, branch: r.branch, node, session: r.session_id, status: r.status, isMain: false, ...(liveness ? { liveness } : {}), ops: [] };
514
+ // @@@ projected shelves cost nothing - a cold archived session ([[archive]]) keeps its record but leaves
515
+ // the working-set projection and skips the per-worktree spec delta. An archived runtime hazard is still
516
+ // projected active by listSessions, so it deliberately retains the same ops in both full and splice builds.
517
+ if (!isActive(r))
518
+ return Promise.resolve(base);
519
+ return guardWorktree(r.worktree_path, () => {
520
+ const outcome = deltas.get(r.worktree_path);
521
+ if (!outcome)
522
+ throw new Error(`layout overlay missing ${r.worktree_path}`);
523
+ if ('error' in outcome)
524
+ throw outcome.error;
525
+ return { ...base, ops: outcome.ops };
526
+ }, () => {
527
+ const cached = deltaCache.get(r.worktree_path);
528
+ if (!cached)
529
+ throw new Error(`layout overlay failed before ${r.worktree_path} had a last-known result`);
530
+ return { ...base, ops: cached.ops };
531
+ });
532
+ }));
533
+ const corruptRows = publicEntries.flatMap((entry) => entry.kind === 'corrupt'
534
+ ? [{ path: '', branch: null, node: null, session: entry.sessionId, status: 'corrupt', liveness: 'unknown', isMain: false, ops: [] }]
535
+ : []);
536
+ const sessionWorktrees = [...rows.filter((w) => w !== null), ...corruptRows];
537
+ // the main checkout row (isMain) — always present, carries no overlay; it anchors the merged tree the board draws.
538
+ const mainRow = { path: main, branch: base, node: null, session: null, status: null, isMain: true, ops: [] };
539
+ const worktrees = [mainRow, ...sessionWorktrees];
540
+ // drop cache entries for worktrees that may no longer hold one — closed sessions (gone from the store) AND
541
+ // newly-cold archived ones (which no longer compute a delta), so archiving SELF-EVICTS its cached ops instead of
542
+ // stranding them in a map nothing prunes.
543
+ const live = new Set(records.filter(({ raw }) => isActive(raw)).map(({ raw }) => raw.worktree_path));
544
+ for (const k of [...deltaCache.keys()])
545
+ if (!live.has(k))
546
+ deltaCache.delete(k);
547
+ return { main: convention.main || main || root, convention, worktrees };
548
+ }
@@ -0,0 +1,37 @@
1
+ export type ProcessIdentity = {
2
+ pid: number;
3
+ startToken: string;
4
+ };
5
+ export type ProcessAdapter = Readonly<{
6
+ platform: NodeJS.Platform;
7
+ startToken(pid: number): string | null;
8
+ processGroupId(pid: number): number | null;
9
+ linuxSessionId(pid: number): number | null;
10
+ }>;
11
+ export type VerifiedDetachedRuntime = Readonly<ProcessIdentity & {
12
+ receiptVersion: 4;
13
+ processGroupId: number;
14
+ linuxSessionId?: number;
15
+ }>;
16
+ export type DetachedRuntimeVerification = {
17
+ ok: true;
18
+ identity: VerifiedDetachedRuntime;
19
+ } | {
20
+ ok: false;
21
+ reason: string;
22
+ };
23
+ export declare function parseProcStat(text: string): {
24
+ ppid: number;
25
+ processGroupId: number;
26
+ sessionId: number;
27
+ ticks: number;
28
+ startToken: string;
29
+ rssPages: number;
30
+ };
31
+ export declare function processStartToken(pid: number, procRoot?: string): string | null;
32
+ export declare const hostProcessAdapter: ProcessAdapter;
33
+ export declare function verifyDetachedRuntime(pid: number, receiptFile: string, adapter?: ProcessAdapter): DetachedRuntimeVerification;
34
+ export declare function detachedRuntimeIsGone(pid: number, receiptFile: string, adapter?: ProcessAdapter): boolean;
35
+ export declare function migrateLegacyDetachedRuntimeReceipt(pid: number, legacyScopeFile: string, receiptFile: string, adapter?: ProcessAdapter): boolean;
36
+ export declare function writeDetachedRuntimeReceipt(pid: number, receiptFile: string, adapter?: ProcessAdapter): VerifiedDetachedRuntime;
37
+ export declare const detachedRuntimeGenerationToken: (identity: VerifiedDetachedRuntime) => string;