spexcode 0.6.1 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/README.md +99 -149
  2. package/bin/spex.mjs +4 -0
  3. package/node_modules/@spexcode/spec-cli/bin/spex.mjs +76 -0
  4. package/node_modules/@spexcode/spec-cli/dist/attach.d.ts +2 -0
  5. package/node_modules/@spexcode/spec-cli/dist/attach.js +48 -0
  6. package/node_modules/@spexcode/spec-cli/dist/claude-headless.d.ts +33 -0
  7. package/node_modules/@spexcode/spec-cli/dist/claude-headless.js +307 -0
  8. package/node_modules/@spexcode/spec-cli/dist/cli.d.ts +1 -0
  9. package/node_modules/@spexcode/spec-cli/dist/cli.js +1859 -0
  10. package/node_modules/@spexcode/spec-cli/dist/client.d.ts +111 -0
  11. package/node_modules/@spexcode/spec-cli/dist/client.js +476 -0
  12. package/node_modules/@spexcode/spec-cli/dist/cockpit.d.ts +7 -0
  13. package/node_modules/@spexcode/spec-cli/dist/cockpit.js +26 -0
  14. package/node_modules/@spexcode/spec-cli/dist/codex-headless.d.ts +1 -0
  15. package/{spec-cli/src/codex-headless.ts → node_modules/@spexcode/spec-cli/dist/codex-headless.js} +3 -9
  16. package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.d.ts +53 -0
  17. package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.js +686 -0
  18. package/node_modules/@spexcode/spec-cli/dist/commit-surgery.d.ts +1 -0
  19. package/node_modules/@spexcode/spec-cli/dist/commit-surgery.js +90 -0
  20. package/node_modules/@spexcode/spec-cli/dist/contract-filter.d.ts +14 -0
  21. package/node_modules/@spexcode/spec-cli/dist/contract-filter.js +219 -0
  22. package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.d.ts +6 -0
  23. package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.js +50 -0
  24. package/node_modules/@spexcode/spec-cli/dist/delivery-queue.d.ts +23 -0
  25. package/node_modules/@spexcode/spec-cli/dist/delivery-queue.js +179 -0
  26. package/node_modules/@spexcode/spec-cli/dist/doctor.d.ts +9 -0
  27. package/node_modules/@spexcode/spec-cli/dist/doctor.js +547 -0
  28. package/node_modules/@spexcode/spec-cli/dist/eval-host.d.ts +1 -0
  29. package/node_modules/@spexcode/spec-cli/dist/eval-host.js +19 -0
  30. package/node_modules/@spexcode/spec-cli/dist/execution-trace.d.ts +26 -0
  31. package/node_modules/@spexcode/spec-cli/dist/execution-trace.js +475 -0
  32. package/node_modules/@spexcode/spec-cli/dist/file-write.d.ts +2 -0
  33. package/node_modules/@spexcode/spec-cli/dist/file-write.js +26 -0
  34. package/node_modules/@spexcode/spec-cli/dist/flat.d.ts +89 -0
  35. package/node_modules/@spexcode/spec-cli/dist/flat.js +1076 -0
  36. package/node_modules/@spexcode/spec-cli/dist/gateway-auth.d.ts +56 -0
  37. package/node_modules/@spexcode/spec-cli/dist/gateway-auth.js +168 -0
  38. package/node_modules/@spexcode/spec-cli/dist/gateway-hub.d.ts +28 -0
  39. package/node_modules/@spexcode/spec-cli/dist/gateway-hub.js +361 -0
  40. package/node_modules/@spexcode/spec-cli/dist/gateway.d.ts +37 -0
  41. package/node_modules/@spexcode/spec-cli/dist/gateway.js +503 -0
  42. package/node_modules/@spexcode/spec-cli/dist/graphCache.d.ts +27 -0
  43. package/node_modules/@spexcode/spec-cli/dist/graphCache.js +716 -0
  44. package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.d.ts +14 -0
  45. package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.js +35 -0
  46. package/node_modules/@spexcode/spec-cli/dist/graphStream.d.ts +85 -0
  47. package/node_modules/@spexcode/spec-cli/dist/graphStream.js +1195 -0
  48. package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.d.ts +64 -0
  49. package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.js +166 -0
  50. package/node_modules/@spexcode/spec-cli/dist/guide.d.ts +8 -0
  51. package/{spec-cli/src/guide.ts → node_modules/@spexcode/spec-cli/dist/guide.js} +115 -22
  52. package/node_modules/@spexcode/spec-cli/dist/harness-select.d.ts +18 -0
  53. package/node_modules/@spexcode/spec-cli/dist/harness-select.js +62 -0
  54. package/node_modules/@spexcode/spec-cli/dist/harness.d.ts +325 -0
  55. package/node_modules/@spexcode/spec-cli/dist/harness.js +3026 -0
  56. package/node_modules/@spexcode/spec-cli/dist/headless-controller.d.ts +9 -0
  57. package/node_modules/@spexcode/spec-cli/dist/headless-controller.js +47 -0
  58. package/node_modules/@spexcode/spec-cli/dist/help.d.ts +10 -0
  59. package/node_modules/@spexcode/spec-cli/dist/help.js +574 -0
  60. package/node_modules/@spexcode/spec-cli/dist/hook-prompts.d.ts +18 -0
  61. package/node_modules/@spexcode/spec-cli/dist/hook-prompts.js +122 -0
  62. package/node_modules/@spexcode/spec-cli/dist/hooks.d.ts +1 -0
  63. package/{spec-cli/src/hooks.ts → node_modules/@spexcode/spec-cli/dist/hooks.js} +15 -15
  64. package/node_modules/@spexcode/spec-cli/dist/host-resources.d.ts +97 -0
  65. package/node_modules/@spexcode/spec-cli/dist/host-resources.js +795 -0
  66. package/node_modules/@spexcode/spec-cli/dist/host.d.ts +88 -0
  67. package/node_modules/@spexcode/spec-cli/dist/host.js +663 -0
  68. package/node_modules/@spexcode/spec-cli/dist/index.d.ts +1 -0
  69. package/node_modules/@spexcode/spec-cli/dist/index.js +899 -0
  70. package/node_modules/@spexcode/spec-cli/dist/init.d.ts +1 -0
  71. package/node_modules/@spexcode/spec-cli/dist/init.js +284 -0
  72. package/node_modules/@spexcode/spec-cli/dist/issues-cli.d.ts +6 -0
  73. package/node_modules/@spexcode/spec-cli/dist/issues-cli.js +334 -0
  74. package/node_modules/@spexcode/spec-cli/dist/issues.d.ts +69 -0
  75. package/node_modules/@spexcode/spec-cli/dist/issues.js +189 -0
  76. package/node_modules/@spexcode/spec-cli/dist/lint.d.ts +34 -0
  77. package/node_modules/@spexcode/spec-cli/dist/lint.js +476 -0
  78. package/node_modules/@spexcode/spec-cli/dist/listen.d.ts +7 -0
  79. package/{spec-cli/src/listen.ts → node_modules/@spexcode/spec-cli/dist/listen.js} +13 -17
  80. package/node_modules/@spexcode/spec-cli/dist/localIssues.d.ts +65 -0
  81. package/node_modules/@spexcode/spec-cli/dist/localIssues.js +582 -0
  82. package/node_modules/@spexcode/spec-cli/dist/login-page.d.ts +5 -0
  83. package/{spec-cli/src/login-page.ts → node_modules/@spexcode/spec-cli/dist/login-page.js} +7 -7
  84. package/node_modules/@spexcode/spec-cli/dist/loop-in.d.ts +23 -0
  85. package/{spec-cli/src/loop-in.ts → node_modules/@spexcode/spec-cli/dist/loop-in.js} +35 -45
  86. package/node_modules/@spexcode/spec-cli/dist/machine-peer.d.ts +69 -0
  87. package/node_modules/@spexcode/spec-cli/dist/machine-peer.js +603 -0
  88. package/node_modules/@spexcode/spec-cli/dist/materialize.d.ts +18 -0
  89. package/node_modules/@spexcode/spec-cli/dist/materialize.js +468 -0
  90. package/node_modules/@spexcode/spec-cli/dist/mentions.d.ts +50 -0
  91. package/node_modules/@spexcode/spec-cli/dist/mentions.js +117 -0
  92. package/node_modules/@spexcode/spec-cli/dist/opencode-headless.d.ts +4 -0
  93. package/node_modules/@spexcode/spec-cli/dist/opencode-headless.js +208 -0
  94. package/node_modules/@spexcode/spec-cli/dist/opencode.d.ts +3 -0
  95. package/{spec-cli/src/opencode.ts → node_modules/@spexcode/spec-cli/dist/opencode.js} +9 -13
  96. package/node_modules/@spexcode/spec-cli/dist/pi-harness.d.ts +3 -0
  97. package/{spec-cli/src/pi-harness.ts → node_modules/@spexcode/spec-cli/dist/pi-harness.js} +45 -40
  98. package/node_modules/@spexcode/spec-cli/dist/pi-headless.d.ts +25 -0
  99. package/node_modules/@spexcode/spec-cli/dist/pi-headless.js +196 -0
  100. package/node_modules/@spexcode/spec-cli/dist/plugin-harness.d.ts +21 -0
  101. package/node_modules/@spexcode/spec-cli/dist/plugin-harness.js +146 -0
  102. package/node_modules/@spexcode/spec-cli/dist/pty-bridge.d.ts +10 -0
  103. package/node_modules/@spexcode/spec-cli/dist/pty-bridge.js +404 -0
  104. package/node_modules/@spexcode/spec-cli/dist/pty-helper.d.mts +1 -0
  105. package/node_modules/@spexcode/spec-cli/dist/pty-helper.mjs +101 -0
  106. package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.d.mts +2 -0
  107. package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.mjs +23 -0
  108. package/node_modules/@spexcode/spec-cli/dist/public-graph.d.ts +46 -0
  109. package/node_modules/@spexcode/spec-cli/dist/public-graph.js +56 -0
  110. package/node_modules/@spexcode/spec-cli/dist/ranker.d.ts +15 -0
  111. package/node_modules/@spexcode/spec-cli/dist/ranker.js +188 -0
  112. package/node_modules/@spexcode/spec-cli/dist/reaper.d.ts +6 -0
  113. package/node_modules/@spexcode/spec-cli/dist/reaper.js +81 -0
  114. package/node_modules/@spexcode/spec-cli/dist/reviews.d.ts +189 -0
  115. package/node_modules/@spexcode/spec-cli/dist/reviews.js +350 -0
  116. package/node_modules/@spexcode/spec-cli/dist/runtime-guard.d.ts +6 -0
  117. package/node_modules/@spexcode/spec-cli/dist/runtime-guard.js +37 -0
  118. package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.d.ts +21 -0
  119. package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.js +84 -0
  120. package/node_modules/@spexcode/spec-cli/dist/search.bench.d.mts +1 -0
  121. package/node_modules/@spexcode/spec-cli/dist/search.bench.mjs +75 -0
  122. package/node_modules/@spexcode/spec-cli/dist/search.d.ts +20 -0
  123. package/node_modules/@spexcode/spec-cli/dist/search.js +61 -0
  124. package/node_modules/@spexcode/spec-cli/dist/session-cursors.d.ts +14 -0
  125. package/node_modules/@spexcode/spec-cli/dist/session-cursors.js +82 -0
  126. package/node_modules/@spexcode/spec-cli/dist/session-declarations.d.ts +13 -0
  127. package/node_modules/@spexcode/spec-cli/dist/session-declarations.js +126 -0
  128. package/node_modules/@spexcode/spec-cli/dist/session-execution.d.ts +10 -0
  129. package/node_modules/@spexcode/spec-cli/dist/session-execution.js +70 -0
  130. package/node_modules/@spexcode/spec-cli/dist/session-files.d.ts +28 -0
  131. package/node_modules/@spexcode/spec-cli/dist/session-files.js +130 -0
  132. package/node_modules/@spexcode/spec-cli/dist/session-follow.d.ts +31 -0
  133. package/node_modules/@spexcode/spec-cli/dist/session-follow.js +179 -0
  134. package/node_modules/@spexcode/spec-cli/dist/session-reparent.d.ts +10 -0
  135. package/node_modules/@spexcode/spec-cli/dist/session-reparent.js +33 -0
  136. package/node_modules/@spexcode/spec-cli/dist/session-timeline.d.ts +51 -0
  137. package/node_modules/@spexcode/spec-cli/dist/session-timeline.js +233 -0
  138. package/node_modules/@spexcode/spec-cli/dist/session-web.d.ts +24 -0
  139. package/node_modules/@spexcode/spec-cli/dist/session-web.js +141 -0
  140. package/node_modules/@spexcode/spec-cli/dist/sessions.d.ts +412 -0
  141. package/node_modules/@spexcode/spec-cli/dist/sessions.js +4239 -0
  142. package/node_modules/@spexcode/spec-cli/dist/sh.d.ts +1 -0
  143. package/node_modules/@spexcode/spec-cli/dist/sh.js +3 -0
  144. package/node_modules/@spexcode/spec-cli/dist/shim-runtime.d.ts +1 -0
  145. package/{spec-cli/src/shim-runtime.ts → node_modules/@spexcode/spec-cli/dist/shim-runtime.js} +3 -4
  146. package/node_modules/@spexcode/spec-cli/dist/slash-commands.d.ts +9 -0
  147. package/node_modules/@spexcode/spec-cli/dist/slash-commands.js +307 -0
  148. package/node_modules/@spexcode/spec-cli/dist/source-files.d.ts +9 -0
  149. package/node_modules/@spexcode/spec-cli/dist/source-files.js +113 -0
  150. package/node_modules/@spexcode/spec-cli/dist/supervise.d.ts +1 -0
  151. package/node_modules/@spexcode/spec-cli/dist/supervise.js +308 -0
  152. package/node_modules/@spexcode/spec-cli/dist/tree.d.ts +25 -0
  153. package/node_modules/@spexcode/spec-cli/dist/tree.js +98 -0
  154. package/node_modules/@spexcode/spec-cli/dist/tsx-bin.d.ts +3 -0
  155. package/node_modules/@spexcode/spec-cli/dist/tsx-bin.js +41 -0
  156. package/node_modules/@spexcode/spec-cli/dist/uninstall.d.ts +3 -0
  157. package/node_modules/@spexcode/spec-cli/dist/uninstall.js +177 -0
  158. package/node_modules/@spexcode/spec-cli/dist/uploads.d.ts +36 -0
  159. package/node_modules/@spexcode/spec-cli/dist/uploads.js +243 -0
  160. package/node_modules/@spexcode/spec-cli/dist/worktree-sources.d.ts +1 -0
  161. package/node_modules/@spexcode/spec-cli/dist/worktree-sources.js +47 -0
  162. package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/dispatch.sh +5 -5
  163. package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/harness.sh +27 -7
  164. package/node_modules/@spexcode/spec-cli/package.json +47 -0
  165. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +8 -0
  166. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/core/comment-altitude/spec.md +9 -0
  167. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec-first.sh +1 -1
  168. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec-of-file.sh +1 -0
  169. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/core/spec.md +22 -0
  170. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/spec.md +2 -2
  171. package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/stop-gate.sh +31 -29
  172. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +15 -0
  173. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/forge-link/spec.md +10 -0
  174. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +13 -0
  175. package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +12 -0
  176. package/node_modules/@spexcode/spec-core/dist/anchors.d.ts +94 -0
  177. package/node_modules/@spexcode/spec-core/dist/anchors.js +730 -0
  178. package/node_modules/@spexcode/spec-core/dist/git.d.ts +166 -0
  179. package/node_modules/@spexcode/spec-core/dist/git.js +2736 -0
  180. package/node_modules/@spexcode/spec-core/dist/graph-delta.d.ts +44 -0
  181. package/node_modules/@spexcode/spec-core/dist/graph-delta.js +72 -0
  182. package/node_modules/@spexcode/spec-core/dist/graph.d.ts +34 -0
  183. package/node_modules/@spexcode/spec-core/dist/graph.js +237 -0
  184. package/node_modules/@spexcode/spec-core/dist/graphDelta.d.ts +3 -0
  185. package/node_modules/@spexcode/spec-core/dist/graphDelta.js +13 -0
  186. package/node_modules/@spexcode/spec-core/dist/harness-identity.d.ts +31 -0
  187. package/node_modules/@spexcode/spec-core/dist/harness-identity.js +20 -0
  188. package/node_modules/@spexcode/spec-core/dist/identity-presets.d.ts +152 -0
  189. package/node_modules/@spexcode/spec-core/dist/identity-presets.js +132 -0
  190. package/node_modules/@spexcode/spec-core/dist/index.d.ts +45 -0
  191. package/node_modules/@spexcode/spec-core/dist/index.js +19 -0
  192. package/node_modules/@spexcode/spec-core/dist/layout.d.ts +183 -0
  193. package/node_modules/@spexcode/spec-core/dist/layout.js +548 -0
  194. package/node_modules/@spexcode/spec-core/dist/process-identity.d.ts +37 -0
  195. package/node_modules/@spexcode/spec-core/dist/process-identity.js +214 -0
  196. package/node_modules/@spexcode/spec-core/dist/project-identity.d.ts +12 -0
  197. package/node_modules/@spexcode/spec-core/dist/project-identity.js +71 -0
  198. package/node_modules/@spexcode/spec-core/dist/project-store.d.ts +3 -0
  199. package/node_modules/@spexcode/spec-core/dist/project-store.js +14 -0
  200. package/node_modules/@spexcode/spec-core/dist/resilience.d.ts +2 -0
  201. package/node_modules/@spexcode/spec-core/dist/resilience.js +40 -0
  202. package/node_modules/@spexcode/spec-core/dist/review/index.d.ts +3 -0
  203. package/node_modules/@spexcode/spec-core/dist/review/index.js +5 -0
  204. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.d.ts +77 -0
  205. package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.js +308 -0
  206. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.d.ts +66 -0
  207. package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.js +180 -0
  208. package/node_modules/@spexcode/spec-core/dist/review/session.d.ts +4 -0
  209. package/node_modules/@spexcode/spec-core/dist/review/session.js +8 -0
  210. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.d.ts +15 -0
  211. package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.js +12 -0
  212. package/node_modules/@spexcode/spec-core/dist/root-lru.d.ts +4 -0
  213. package/{spec-cli/src/root-lru.ts → node_modules/@spexcode/spec-core/dist/root-lru.js} +26 -30
  214. package/node_modules/@spexcode/spec-core/dist/specs.d.ts +117 -0
  215. package/node_modules/@spexcode/spec-core/dist/specs.js +489 -0
  216. package/node_modules/@spexcode/spec-core/package.json +28 -0
  217. package/node_modules/@spexcode/spec-eval/dist/cache.d.ts +10 -0
  218. package/node_modules/@spexcode/spec-eval/dist/cache.js +50 -0
  219. package/node_modules/@spexcode/spec-eval/dist/cli.d.ts +22 -0
  220. package/node_modules/@spexcode/spec-eval/dist/cli.js +981 -0
  221. package/node_modules/@spexcode/spec-eval/dist/evaltab.d.ts +98 -0
  222. package/node_modules/@spexcode/spec-eval/dist/evaltab.js +176 -0
  223. package/node_modules/@spexcode/spec-eval/dist/filing.d.ts +16 -0
  224. package/node_modules/@spexcode/spec-eval/dist/filing.js +36 -0
  225. package/node_modules/@spexcode/spec-eval/dist/freshness.d.ts +48 -0
  226. package/node_modules/@spexcode/spec-eval/dist/freshness.js +799 -0
  227. package/node_modules/@spexcode/spec-eval/dist/host.d.ts +46 -0
  228. package/node_modules/@spexcode/spec-eval/dist/host.js +53 -0
  229. package/node_modules/@spexcode/spec-eval/dist/humanok.d.ts +11 -0
  230. package/node_modules/@spexcode/spec-eval/dist/humanok.js +27 -0
  231. package/node_modules/@spexcode/spec-eval/dist/index.d.ts +4 -0
  232. package/node_modules/@spexcode/spec-eval/dist/index.js +4 -0
  233. package/node_modules/@spexcode/spec-eval/dist/remarks.d.ts +31 -0
  234. package/node_modules/@spexcode/spec-eval/dist/remarks.js +1 -0
  235. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.d.ts +13 -0
  236. package/node_modules/@spexcode/spec-eval/dist/scenariofresh.js +303 -0
  237. package/node_modules/@spexcode/spec-eval/dist/scenarios.d.ts +99 -0
  238. package/node_modules/@spexcode/spec-eval/dist/scenarios.js +650 -0
  239. package/node_modules/@spexcode/spec-eval/dist/sessioneval.d.ts +307 -0
  240. package/node_modules/@spexcode/spec-eval/dist/sessioneval.js +1883 -0
  241. package/node_modules/@spexcode/spec-eval/dist/sidecar.d.ts +55 -0
  242. package/node_modules/@spexcode/spec-eval/dist/sidecar.js +82 -0
  243. package/node_modules/@spexcode/spec-eval/dist/timeline.d.ts +25 -0
  244. package/node_modules/@spexcode/spec-eval/dist/timeline.js +65 -0
  245. package/node_modules/@spexcode/spec-eval/dist/ui-path.d.ts +1 -0
  246. package/node_modules/@spexcode/spec-eval/dist/ui-path.js +2 -0
  247. package/node_modules/@spexcode/spec-eval/package.json +36 -0
  248. package/node_modules/@spexcode/spec-forge/dist/cache.d.ts +29 -0
  249. package/node_modules/@spexcode/spec-forge/dist/cache.js +59 -0
  250. package/node_modules/@spexcode/spec-forge/dist/cli.d.ts +1 -0
  251. package/node_modules/@spexcode/spec-forge/dist/cli.js +100 -0
  252. package/node_modules/@spexcode/spec-forge/dist/drivers/github.d.ts +2 -0
  253. package/node_modules/@spexcode/spec-forge/dist/drivers/github.js +116 -0
  254. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.d.ts +7 -0
  255. package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.js +144 -0
  256. package/node_modules/@spexcode/spec-forge/dist/drivers.d.ts +10 -0
  257. package/node_modules/@spexcode/spec-forge/dist/drivers.js +83 -0
  258. package/node_modules/@spexcode/spec-forge/dist/index.d.ts +4 -0
  259. package/node_modules/@spexcode/spec-forge/dist/index.js +4 -0
  260. package/node_modules/@spexcode/spec-forge/dist/links.d.ts +15 -0
  261. package/node_modules/@spexcode/spec-forge/dist/links.js +65 -0
  262. package/node_modules/@spexcode/spec-forge/dist/needs-eval.d.ts +10 -0
  263. package/node_modules/@spexcode/spec-forge/dist/needs-eval.js +20 -0
  264. package/node_modules/@spexcode/spec-forge/dist/port.d.ts +53 -0
  265. package/node_modules/@spexcode/spec-forge/dist/port.js +1 -0
  266. package/node_modules/@spexcode/spec-forge/dist/resident.d.ts +7 -0
  267. package/node_modules/@spexcode/spec-forge/dist/resident.js +43 -0
  268. package/node_modules/@spexcode/spec-forge/package.json +32 -0
  269. package/package.json +33 -19
  270. package/spec-cli/bin/spex.mjs +0 -69
  271. package/spec-cli/src/anchors.ts +0 -706
  272. package/spec-cli/src/attach.ts +0 -43
  273. package/spec-cli/src/claude-headless.ts +0 -321
  274. package/spec-cli/src/cli.ts +0 -1115
  275. package/spec-cli/src/client.ts +0 -315
  276. package/spec-cli/src/cockpit.ts +0 -43
  277. package/spec-cli/src/codex-runtime-generations.ts +0 -646
  278. package/spec-cli/src/commit-surgery.ts +0 -68
  279. package/spec-cli/src/contract-filter.ts +0 -202
  280. package/spec-cli/src/delivery-queue.ts +0 -107
  281. package/spec-cli/src/doctor.ts +0 -516
  282. package/spec-cli/src/file-write.ts +0 -22
  283. package/spec-cli/src/gateway-auth.ts +0 -181
  284. package/spec-cli/src/gateway-hub.ts +0 -356
  285. package/spec-cli/src/gateway.ts +0 -368
  286. package/spec-cli/src/git.ts +0 -2180
  287. package/spec-cli/src/graph.ts +0 -221
  288. package/spec-cli/src/graphCache.ts +0 -641
  289. package/spec-cli/src/graphDelta.ts +0 -77
  290. package/spec-cli/src/graphStream.ts +0 -1019
  291. package/spec-cli/src/harness-select.ts +0 -77
  292. package/spec-cli/src/harness.ts +0 -2747
  293. package/spec-cli/src/headless-controller.ts +0 -63
  294. package/spec-cli/src/help.ts +0 -480
  295. package/spec-cli/src/host-resources.ts +0 -707
  296. package/spec-cli/src/host.ts +0 -611
  297. package/spec-cli/src/identity-presets.d.ts +0 -13
  298. package/spec-cli/src/identity-presets.js +0 -128
  299. package/spec-cli/src/index.ts +0 -730
  300. package/spec-cli/src/init.ts +0 -258
  301. package/spec-cli/src/issues-cli.ts +0 -276
  302. package/spec-cli/src/issues.ts +0 -237
  303. package/spec-cli/src/layout.ts +0 -557
  304. package/spec-cli/src/lint.ts +0 -458
  305. package/spec-cli/src/localIssues.ts +0 -538
  306. package/spec-cli/src/materialize.ts +0 -412
  307. package/spec-cli/src/mentions.ts +0 -81
  308. package/spec-cli/src/opencode-headless.ts +0 -205
  309. package/spec-cli/src/pi-headless.ts +0 -153
  310. package/spec-cli/src/plugin-harness.ts +0 -157
  311. package/spec-cli/src/process-identity.ts +0 -207
  312. package/spec-cli/src/project-identity.ts +0 -73
  313. package/spec-cli/src/project-store.ts +0 -17
  314. package/spec-cli/src/pty-bridge.ts +0 -396
  315. package/spec-cli/src/pty-helper.mjs +0 -96
  316. package/spec-cli/src/pty-native-helper.mjs +0 -22
  317. package/spec-cli/src/ranker.ts +0 -191
  318. package/spec-cli/src/reaper.ts +0 -125
  319. package/spec-cli/src/resilience.ts +0 -41
  320. package/spec-cli/src/reviewSnapshot.ts +0 -28
  321. package/spec-cli/src/reviews.ts +0 -405
  322. package/spec-cli/src/runtime-guard.ts +0 -35
  323. package/spec-cli/src/runtime-ownership.ts +0 -88
  324. package/spec-cli/src/search.bench.mjs +0 -80
  325. package/spec-cli/src/search.ts +0 -63
  326. package/spec-cli/src/session-cursors.ts +0 -91
  327. package/spec-cli/src/session-follow.ts +0 -182
  328. package/spec-cli/src/session-timeline.ts +0 -98
  329. package/spec-cli/src/sessions.ts +0 -3403
  330. package/spec-cli/src/sh.ts +0 -3
  331. package/spec-cli/src/slash-commands.ts +0 -318
  332. package/spec-cli/src/source-files.ts +0 -104
  333. package/spec-cli/src/specs.ts +0 -498
  334. package/spec-cli/src/supervise.ts +0 -245
  335. package/spec-cli/src/tree.ts +0 -118
  336. package/spec-cli/src/tsx-bin.ts +0 -18
  337. package/spec-cli/src/uninstall.ts +0 -171
  338. package/spec-cli/src/uploads.ts +0 -253
  339. package/spec-cli/src/worktree-sources.ts +0 -42
  340. package/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +0 -8
  341. package/spec-cli/templates/spec/project/.plugins/core/comment-altitude/spec.md +0 -28
  342. package/spec-cli/templates/spec/project/.plugins/core/spec.md +0 -23
  343. package/spec-cli/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +0 -32
  344. package/spec-cli/templates/spec/project/.plugins/prompts/forge-link/spec.md +0 -9
  345. package/spec-cli/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +0 -15
  346. package/spec-cli/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +0 -18
  347. package/spec-dashboard/dist/assets/App-F9uaAVcH.js +0 -2
  348. package/spec-dashboard/dist/assets/Dashboard-Ba_jhxp1.js +0 -27
  349. package/spec-dashboard/dist/assets/Dashboard-C5ap-Sga.css +0 -1
  350. package/spec-dashboard/dist/assets/EvalsPage-FixoOg_n.js +0 -2
  351. package/spec-dashboard/dist/assets/IssuesPage-CuKLFhH3.js +0 -1
  352. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  353. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  354. package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  355. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  356. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  357. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  358. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  359. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  360. package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  361. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  362. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  363. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  364. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  365. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  366. package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  367. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  368. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  369. package/spec-dashboard/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  370. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  371. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  372. package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  373. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  374. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  375. package/spec-dashboard/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  376. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  377. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  378. package/spec-dashboard/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  379. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  380. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  381. package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  382. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  383. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  384. package/spec-dashboard/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  385. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  386. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  387. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  388. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  389. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  390. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  391. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  392. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  393. package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  394. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  395. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  396. package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  397. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  398. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  399. package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  400. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  401. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  402. package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  403. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  404. package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  405. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  406. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  407. package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  408. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  409. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  410. package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  411. package/spec-dashboard/dist/assets/MobileApp-CHgEHORJ.js +0 -2
  412. package/spec-dashboard/dist/assets/Modal-CQgYymmr.js +0 -1
  413. package/spec-dashboard/dist/assets/PageScroll-hT7UTLvD.js +0 -1
  414. package/spec-dashboard/dist/assets/ProjectsPage-CtXxakF9.js +0 -1
  415. package/spec-dashboard/dist/assets/SessionInterface-6GBZ9nXN.css +0 -32
  416. package/spec-dashboard/dist/assets/SessionInterface-Bpie-9fs.js +0 -39
  417. package/spec-dashboard/dist/assets/SessionWindow-CixDi4PI.js +0 -1
  418. package/spec-dashboard/dist/assets/Settings-C2MsucfE.js +0 -1
  419. package/spec-dashboard/dist/assets/Thread-C6Go8HRh.js +0 -13
  420. package/spec-dashboard/dist/assets/bindings-BC9vqpYU.js +0 -1
  421. package/spec-dashboard/dist/assets/data-B-RQmit6.js +0 -1
  422. package/spec-dashboard/dist/assets/index-CsI8DElI.css +0 -1
  423. package/spec-dashboard/dist/assets/index-DrVao0Ep.js +0 -41
  424. package/spec-dashboard/dist/assets/launch-BBH02b1v.js +0 -276
  425. package/spec-dashboard/dist/assets/launch-Cp579UoJ.css +0 -1
  426. package/spec-dashboard/dist/assets/terminalFont-C6oGNKrf.js +0 -1
  427. package/spec-dashboard/dist/index.html +0 -29
  428. package/spec-dashboard/src/reviewFilters.js +0 -322
  429. package/spec-dashboard/src/reviewQuery.js +0 -174
  430. package/spec-dashboard/src/session.js +0 -199
  431. package/spec-eval/src/cache.ts +0 -57
  432. package/spec-eval/src/cli.ts +0 -889
  433. package/spec-eval/src/evaltab.ts +0 -262
  434. package/spec-eval/src/filing.ts +0 -39
  435. package/spec-eval/src/freshness.ts +0 -557
  436. package/spec-eval/src/humanok.ts +0 -28
  437. package/spec-eval/src/scenariofresh.ts +0 -244
  438. package/spec-eval/src/scenarios.ts +0 -672
  439. package/spec-eval/src/sessioneval.ts +0 -2226
  440. package/spec-eval/src/sidecar.ts +0 -93
  441. package/spec-eval/src/timeline.ts +0 -54
  442. package/spec-forge/src/__fixtures__/github-forge.json +0 -63
  443. package/spec-forge/src/cache.ts +0 -66
  444. package/spec-forge/src/cli.ts +0 -99
  445. package/spec-forge/src/drivers/github.ts +0 -132
  446. package/spec-forge/src/drivers/gitlab.ts +0 -153
  447. package/spec-forge/src/drivers.ts +0 -73
  448. package/spec-forge/src/links.ts +0 -72
  449. package/spec-forge/src/needs-eval.ts +0 -29
  450. package/spec-forge/src/port.ts +0 -36
  451. package/spec-forge/src/resident.ts +0 -46
  452. /package/{spec-cli → node_modules/@spexcode/spec-cli}/README.md +0 -0
  453. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-0.5.2-eef1.fixture +0 -0
  454. /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-sed-v0.fixture +0 -0
  455. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/commit-msg +0 -0
  456. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-checkout +0 -0
  457. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-merge +0 -0
  458. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/pre-commit +0 -0
  459. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/prepare-commit-msg +0 -0
  460. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/reference-transaction +0 -0
  461. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/extract/spec.md +0 -0
  462. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/regroup/spec.md +0 -0
  463. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/rename/spec.md +0 -0
  464. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/spec.md +0 -0
  465. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/tidy/spec.md +0 -0
  466. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/idle.sh +0 -0
  467. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/spec.md +0 -0
  468. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/mark-active.sh +0 -0
  469. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/spec.md +0 -0
  470. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/fail.sh +0 -0
  471. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/spec.md +0 -0
  472. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec.md +0 -0
  473. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec.md +0 -0
  474. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/spec.md +0 -0
  475. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/digest.mjs +0 -0
  476. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/spec.md +0 -0
  477. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/spec.md +0 -0
  478. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/spec.md +0 -0
  479. /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/spec.md +0 -0
  480. /package/{spec-cli → node_modules/@spexcode/spec-core}/templates/spexcode.json +0 -0
@@ -1,91 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
2
- import { join } from 'node:path'
3
- import { sessionArtifactPath, sessionStoreDir } from './layout.js'
4
- import type { TimelineEvent } from './session-timeline.js'
5
-
6
- // @@@ session-cursors - a reader's durable place in a log. One `cursors.json` per session in its global store
7
- // dir: `follows` holds one entry per followed session, including the reader's own id when it watches its own
8
- // log. A position is an event INDEX into timeline.ndjson (lines already consumed), so it is also the index of
9
- // the next unread event. A position is NOT a work list: what a session still owes its agent is a debt, and it
10
- // lives in its own queue ([[delivery-queue]]). Binding both to one counter is what made a session's own status
11
- // lines get consumed as though they were mail, and made "anything outstanding?" a scan of all history.
12
-
13
- export type Cursors = { version: 1; follows: Record<string, number> }
14
-
15
- const cursorsPath = (id: string): string => sessionArtifactPath(id, 'cursors.json')
16
- const at = (v: unknown): number => (typeof v === 'number' && Number.isFinite(v) && v > 0 ? Math.floor(v) : 0)
17
-
18
- // Never throws: a missing, empty, or unparseable file reads as "nothing consumed", because re-showing a
19
- // message is the honest recovery for a lost position and skipping one is not. Followed entries whose target
20
- // store dir is gone are dropped here — expiry is this read, and the next write persists it.
21
- export function readCursors(id: string): Cursors {
22
- let raw: { follows?: unknown } | null = null
23
- try { raw = JSON.parse(readFileSync(cursorsPath(id), 'utf8')) } catch { /* no cursors yet */ }
24
- const follows: Record<string, number> = {}
25
- const stored = raw?.follows
26
- if (stored && typeof stored === 'object') {
27
- for (const [target, pos] of Object.entries(stored as Record<string, unknown>)) {
28
- if (!target || !existsSync(sessionStoreDir(target))) continue
29
- follows[target] = at(pos)
30
- }
31
- }
32
- return { version: 1, follows }
33
- }
34
-
35
- // Written whole and atomically, one field per line — the same shape as the session record, so a position stays
36
- // readable by an exact whole-line match where a value regex would not be.
37
- function writeCursors(id: string, cursors: Cursors): void {
38
- const dir = sessionStoreDir(id)
39
- mkdirSync(dir, { recursive: true })
40
- const tmp = join(dir, `.cursors.json.${process.pid}.tmp`)
41
- writeFileSync(tmp, JSON.stringify(cursors, null, 2) + '\n')
42
- renameSync(tmp, cursorsPath(id))
43
- }
44
-
45
- export const followCursor = (id: string, target: string): number | null => {
46
- const stored = readCursors(id).follows[target]
47
- return stored === undefined ? null : stored
48
- }
49
-
50
- // Start or advance a follow. Following IS this entry existing, so the first call registers the relationship.
51
- // Monotonic: a stale read can leave a position too low (an event read twice), never too high (one lost).
52
- export function advanceFollow(id: string, target: string, to: number): void {
53
- const cursors = readCursors(id)
54
- const stored = cursors.follows[target]
55
- if (stored !== undefined && to <= stored) return
56
- writeCursors(id, { ...cursors, follows: { ...cursors.follows, [target]: Math.max(0, Math.floor(to)) } })
57
- }
58
-
59
- export const followedSessions = (id: string): string[] => Object.keys(readCursors(id).follows)
60
-
61
- const sameStatus = (a: TimelineEvent, b: TimelineEvent): boolean =>
62
- a.kind === 'status' && b.kind === 'status' && a.status === b.status
63
- && (a.proposal ?? null) === (b.proposal ?? null) && (a.note ?? null) === (b.note ?? null)
64
-
65
- // @@@ edges, not lines - what a reader has not yet seen, with repeated status lines dropped. X→X IS NOT A
66
- // TRANSITION: the log is append-only and already holds runs of identical status lines from before the
67
- // timeline observer was deleted (every stray `spex serve` process ran an fs.watch over the same store and
68
- // re-recorded each real move, so ONE transition landed as up to 6 lines within ~200ms). Those bytes are
69
- // history and stay. Any consumer that decides "did it move?" must therefore compare VALUES, never adjacency,
70
- // and must compare against the last status the reader ALREADY saw — otherwise a duplicate straddling the
71
- // cursor boundary reads as a fresh move on the very next tick. `next` is where the cursor goes after consuming
72
- // the WHOLE slice: the full length, because a dropped duplicate is still consumed. `at[i]` is the absolute
73
- // index of `events[i]`, which is what lets a reader that STOPS on one event ([[session-follow]]'s take-one
74
- // wait) advance to exactly `at[i] + 1` and leave the lines behind it unread for the next reader.
75
- export function unreadSince(events: TimelineEvent[], from: number): { events: TimelineEvent[]; at: number[]; next: number } {
76
- const start = Math.min(Math.max(0, Math.floor(from)), events.length)
77
- let prev: TimelineEvent | null = null
78
- for (let i = start - 1; i >= 0; i--) if (events[i].kind === 'status') { prev = events[i]; break }
79
- const out: TimelineEvent[] = []
80
- const at: number[] = []
81
- for (let i = start; i < events.length; i++) {
82
- const e = events[i]
83
- if (e.kind === 'status') {
84
- if (prev && sameStatus(prev, e)) continue
85
- prev = e
86
- }
87
- out.push(e)
88
- at.push(i)
89
- }
90
- return { events: out, at, next: events.length }
91
- }
@@ -1,182 +0,0 @@
1
- import { existsSync } from 'node:fs'
2
- import { sessionStoreDir } from './layout.js'
3
- import { advanceFollow, followCursor, unreadSince } from './session-cursors.js'
4
- import { timelineDisplay, timelineEvents, timelineStamp } from './session-timeline.js'
5
- import { sessionLabel, type DisplayStatus, type Session } from './sessions.js'
6
-
7
- // @@@ session-follow - supervision is FOLLOWING a log past a cursor, never polling a derived board. One tick
8
- // costs ONE stat per target: if timeline.ndjson has not grown, nothing is opened and nothing is parsed. No
9
- // call here reaches the backend, a rendezvous socket, or tmux, which is the whole point — M followers over N
10
- // sessions cost the control plane zero, where the old poll cost one board build (a connect + a tmux spawn per
11
- // live session) per follower per interval.
12
-
13
- // Actionable = a state whose arrival means "a human/supervisor must now act". `offline` is deliberately ABSENT
14
- // where the old poll had it: liveness is a present-tense probe derivation, never authored, so it can never
15
- // appear on a log ([[state]]). A follower learns what a session DECLARED and never that it died.
16
- const ACTIONABLE = new Set<DisplayStatus>(['review', 'done', 'close-pending', 'error', 'asking'])
17
- const NEXT: Record<string, string> = {
18
- review: 'merge | close',
19
- done: 'merge | close',
20
- 'close-pending': 'close',
21
- error: 'resume (relaunch & retry) | show --capture | close',
22
- asking: 'send "<msg>" | show --capture',
23
- idle: 'send "<msg>" | show --capture',
24
- queued: 'waiting for a free slot — starts automatically | close',
25
- }
26
- const trunc = (s: string, n: number): string => (s.length <= n ? s : `${s.slice(0, n - 1)}…`)
27
-
28
- export function sessionEvent(s: Session): string {
29
- const note = s.note ? ` — note: ${s.note}` : ''
30
- const asked = s.promptPreview ? ` · asked: ${s.promptPreview}` : ''
31
- return `[spex] ${s.status} · ${sessionLabel(s)} — act: ${NEXT[s.status] || '—'}${note}${asked} [id ${s.id}]`
32
- }
33
- // @@@ launchEvent - a session's FIRST sighting, emitted once per id whatever its status, so the stream is a
34
- // complete lifecycle feed: launched → [transitions] → closed. A launch's own first line is `active` (not
35
- // actionable), so without this the feed would be blind to new sessions starting.
36
- export function launchEvent(s: Session): string {
37
- const note = s.note ? ` — note: ${s.note}` : ''
38
- const asked = s.promptPreview ? ` · asked: ${s.promptPreview}` : ''
39
- return `[spex] launched · ${sessionLabel(s)} — act: capture | send "<msg>"${note}${asked} [id ${s.id}]`
40
- }
41
-
42
- // `targets` is re-read every tick so a BROAD follow picks up sessions that launch while it runs; an explicit
43
- // selector resolves once and hands back a fixed list. `self` is the follower's own session: its inbox rides the
44
- // same follow, and it is where the durable cursors live — a follower with no session record (a human shell)
45
- // keeps them in memory for the life of the process.
46
- export type FollowOpts = {
47
- targets: () => string[]
48
- self?: string | null
49
- statuses?: string[]
50
- includeIdle?: boolean
51
- intervalMs?: number
52
- as?: string
53
- take?: boolean
54
- timeoutMs?: number
55
- onObserved?: (id: string, status: DisplayStatus, previous: DisplayStatus | null) => void
56
- row?: (id: string, status: DisplayStatus, note: string | null) => Session | null
57
- }
58
- // Only `take` mode (what `spex session wait` runs) resolves; a stream follow never returns. There is no
59
- // transport outcome, because there is no transport: following is reading a file, so the failure that once
60
- // needed its own vocabulary — a backend that could not be reached, misread as a session verdict — cannot occur.
61
- export type FollowOutcome =
62
- | { reached: DisplayStatus; id: string; path: DisplayStatus[] }
63
- | { mail: { from: string | null; text: string } }
64
- | { timedOut: true; path: DisplayStatus[] }
65
- | { gone: string }
66
-
67
- type FollowState = { pos: number; prev: DisplayStatus | null; path: DisplayStatus[]; stamp: string | null }
68
-
69
- export async function followSessions(emit: (line: string) => void, opts: FollowOpts): Promise<FollowOutcome> {
70
- const { targets, self = null, statuses, includeIdle = false, intervalMs = 1000, as, take = false, timeoutMs = 1_200_000, onObserved, row } = opts
71
- const tag = as ? `[${as}] ` : ''
72
- const state = new Map<string, FollowState>()
73
- const memo = new Map<string, number>() // cursors for a follower that has no record of its own to store them in
74
- const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
75
- // the no-hang wall: a fixed deadline computed ONCE, checked before EVERY sleep below.
76
- const deadline = take ? Date.now() + Math.max(1000, timeoutMs) : 0
77
- const isActionable = (st: DisplayStatus) => ACTIONABLE.has(st) || (includeIdle && st === 'idle')
78
- const passes = (st: DisplayStatus) => !statuses?.length || statuses.includes(st)
79
- const anyPath = (): DisplayStatus[] => {
80
- for (const f of state.values()) if (f.path.length) return f.path
81
- return []
82
- }
83
- const readCursor = (id: string): number | null => (self ? followCursor(self, id) : memo.get(id) ?? null)
84
- const writeCursor = (id: string, to: number): void => { if (self) advanceFollow(self, id, to); else memo.set(id, to) }
85
- const line = (id: string, st: DisplayStatus, note: string | null, first: boolean): void => {
86
- const s = row?.(id, st, note)
87
- if (!s) return
88
- if (first) emit(tag + launchEvent(s))
89
- else if (passes(st) && isActionable(st)) emit(tag + sessionEvent(s))
90
- }
91
- let first = true
92
- let shown = -1 // stream mode: the last inbox line this process printed (see the INBOX read below)
93
-
94
- for (;;) {
95
- const ids = targets()
96
- const seen = new Set<string>()
97
- for (const id of ids) {
98
- if (id === self) continue // the follower's own log is its INBOX, followed below on its own cursor rule
99
- seen.add(id)
100
- if (!existsSync(sessionStoreDir(id))) {
101
- if (state.delete(id)) emit(`${tag}[spex] closed · removed [id ${id}]`)
102
- if (take) return { gone: id }
103
- continue
104
- }
105
- let f = state.get(id)
106
- if (!f) {
107
- const evs = timelineEvents(id)
108
- // A stored cursor always wins — that IS the resume, losing nothing across a follower's death. With
109
- // none: a target already present when the follow started predates it, so we begin at the log's END
110
- // (its history is not news); a target that appears on a LATER tick genuinely just launched, so its
111
- // whole log is read from 0 and its `launched` line reaches the feed.
112
- const pos = readCursor(id) ?? (first ? evs.length : 0)
113
- // The ARRIVAL state is the last status line BEFORE the cursor — a fact on the log, not whatever a poll
114
- // happened to catch. With no such line the first status we read is the arrival instead.
115
- let prev: DisplayStatus | null = null
116
- for (let i = Math.min(pos, evs.length) - 1; i >= 0; i--) {
117
- const e = evs[i]
118
- if (e.kind === 'status') { prev = timelineDisplay(e); break }
119
- }
120
- f = { pos, prev, path: prev ? [prev] : [], stamp: null }
121
- state.set(id, f)
122
- if (prev) { onObserved?.(id, prev, null); line(id, prev, null, true) }
123
- }
124
- const stamp = timelineStamp(id)
125
- if (stamp !== null && stamp === f.stamp) continue // THE cheap tick: nothing appended, nothing parsed
126
- f.stamp = stamp
127
- const evs = timelineEvents(id)
128
- const slice = unreadSince(evs, f.pos)
129
- let hit: FollowOutcome | null = null
130
- for (let k = 0; k < slice.events.length && !hit; k++) {
131
- const e = slice.events[k]
132
- if (e.kind === 'sent') {
133
- const s = row?.(id, f.prev ?? 'unknown', null)
134
- if (s) emit(`${tag}[spex] message · ${sessionLabel(s)} — from ${e.from ?? 'human'}: ${trunc(e.text, 120)} [id ${id}]`)
135
- continue
136
- }
137
- const st = timelineDisplay(e)
138
- const was = f.prev
139
- f.prev = st
140
- f.path.push(st)
141
- onObserved?.(id, st, was)
142
- line(id, st, e.note, was === null)
143
- // THE edge: a previously-observed NON-actionable status moving INTO an actionable one. An actionable
144
- // ARRIVAL (was === null) is not an edge — that standing level is what a level-triggered wait falsely
145
- // returned on; nor is an actionable→actionable hop (review→done). The rise OUT of non-actionable is the
146
- // one signal that means "the target needs you AGAIN". The previous state is the previous LINE, so two
147
- // moves inside one tick are two edges rather than one collapsed sample.
148
- if (take && was !== null && !isActionable(was) && isActionable(st)) hit = { reached: st, id, path: f.path }
149
- // Consume exactly up to the event we stopped on, so the lines behind it stay unread for the next wait.
150
- if (hit) { f.pos = slice.at[k] + 1; writeCursor(id, f.pos) }
151
- }
152
- if (hit) return hit
153
- f.pos = slice.next
154
- writeCursor(id, f.pos)
155
- }
156
- for (const id of [...state.keys()]) {
157
- if (seen.has(id)) continue
158
- state.delete(id)
159
- emit(`${tag}[spex] closed · removed [id ${id}]`)
160
- }
161
- // THE FOLLOWER'S OWN LOG — watched exactly like any other target, on its own entry in `cursors.json`. It is
162
- // a WATCH, not a delivery: a message reaches the agent as a prompt through the adapter ([[delivery-queue]]),
163
- // so this position only decides what THIS process has already reported and can never make an agent miss
164
- // mail. Never advanced here in take mode — the waiter stops on the event and the next wait resumes on it.
165
- if (self && existsSync(sessionStoreDir(self))) {
166
- const mine = unreadSince(timelineEvents(self), followCursor(self, self) ?? 0)
167
- for (let k = 0; k < mine.events.length; k++) {
168
- const e = mine.events[k]
169
- if (e.kind !== 'sent') continue
170
- if (take) return { mail: { from: e.from, text: e.text } }
171
- // a stream has no turn boundary to advance that cursor, so its own high-water mark — process-local,
172
- // never written — is what keeps an unread line from being re-printed on every tick.
173
- if (mine.at[k] <= shown) continue
174
- shown = mine.at[k]
175
- emit(`${tag}[spex] message · you — from ${e.from ?? 'human'}: ${trunc(e.text, 120)} [id ${self}]`)
176
- }
177
- }
178
- first = false
179
- if (take && Date.now() >= deadline) return { timedOut: true, path: anyPath() }
180
- await sleep(intervalMs)
181
- }
182
- }
@@ -1,98 +0,0 @@
1
- import { randomUUID } from 'node:crypto'
2
- import { existsSync, readFileSync, appendFileSync, mkdirSync, statSync } from 'node:fs'
3
- import { sessionStoreDir, sessionArtifactPath, readAliasedRawRecord } from './layout.js'
4
- import type { Lifecycle, Proposal } from './sessions.js'
5
-
6
- // @@@ session-timeline - the session's append-only log in its global store dir: every authored-lifecycle
7
- // transition (status + proposal + the FULL note text) and every message addressed to it. It is what a
8
- // terminal-free surface renders as the conversation, and it is the DELIVERY itself — a message is delivered
9
- // when its bytes are in this file.
10
- //
11
- // There is exactly ONE writer path for the authored axis: every lifecycle hook shells to `spex internal
12
- // session-*`, the same TypeScript writer the CLI declarations use, so no move reaches session.json without
13
- // reaching this log. That is why there is no observer process, no repair tick, and no read-time folding of a
14
- // move recorded twice — nothing writes state behind this module's back.
15
-
16
- export type TimelineEvent =
17
- | { ts: string; kind: 'status'; status: Lifecycle; proposal: Proposal | null; note: string | null; display?: string }
18
- | { ts: string; kind: 'sent'; mid: string; text: string; from: string | null; replyVia?: 'note' }
19
-
20
- const timelinePath = (id: string): string => sessionArtifactPath(id, 'timeline.ndjson')
21
-
22
- function append(id: string, ev: TimelineEvent): void {
23
- mkdirSync(sessionStoreDir(id), { recursive: true })
24
- appendFileSync(timelinePath(id), JSON.stringify(ev) + '\n')
25
- }
26
-
27
- // Record a lifecycle value that has already landed in session.json. TypeScript state writers call this
28
- // synchronously before returning, so a later write cannot erase an intermediate declaration note from the
29
- // conversation. Best-effort: history is an accessory to the state machine, and failing to write it must never
30
- // break the transition that already happened.
31
- export function recordStatus(id: string, status: Lifecycle, proposal: Proposal | null, note: string | null): void {
32
- try { append(id, { ts: new Date().toISOString(), kind: 'status', status, proposal, note }) }
33
- catch { /* the record already moved; the history line is the only loss */ }
34
- }
35
-
36
- // The DELIVERY ([[dispatch]]): appending this line IS the send, so unlike a status line it must fail LOUD —
37
- // the caller reports the throw rather than a false success. `text` is the message BEFORE any mechanism insert
38
- // (hints are transport, not conversation); `replyVia` is the effective channel the prompt seam chose. Returns
39
- // the new line's `mid`, which a best-effort poke carries.
40
- export function appendSent(id: string, text: string, from: string | null, replyVia?: 'note'): { mid: string } {
41
- const mid = randomUUID()
42
- append(id, { ts: new Date().toISOString(), kind: 'sent', mid, text, from, ...(replyVia ? { replyVia } : {}) })
43
- return { mid }
44
- }
45
-
46
- // The unowned read: any process may take it with nothing but filesystem access, and taking it perturbs
47
- // nothing. Index = event position, which is what a cursor names ([[session-cursors]]).
48
- export function timelineEvents(id: string): TimelineEvent[] {
49
- try {
50
- const p = timelinePath(id)
51
- if (!existsSync(p)) return []
52
- return readFileSync(p, 'utf8').split('\n').filter(Boolean).map((l) => {
53
- try { return JSON.parse(l) as TimelineEvent } catch { return null }
54
- }).filter((e): e is TimelineEvent => e != null && (e.kind === 'status' || e.kind === 'sent'))
55
- } catch { return [] }
56
- }
57
-
58
- // the same L0 read taken as CHEAPLY as it can be: a follower ([[session-follow]]) ticks over many logs, so it
59
- // stats first and parses only what grew. null = no log yet (a session that has authored nothing).
60
- export function timelineStamp(id: string): string | null {
61
- try { const s = statSync(timelinePath(id)); return `${s.size}:${s.mtimeMs}` }
62
- catch { return null }
63
- }
64
-
65
- // the display word for an authored state — the SAME vocabulary every other surface speaks (awaiting → its
66
- // proposal's label, active → working), duplicated here as a tiny read-time map rather than importing the state
67
- // machine (sessions.ts imports THIS module for appendSent; a value import back would be a cycle — the
68
- // Lifecycle/Proposal imports above are type-only, erased at runtime).
69
- const PROPOSAL_DISPLAY: Record<string, DisplayWord> = { merge: 'review', nothing: 'done', close: 'close-pending' }
70
- type DisplayWord = 'working' | 'idle' | 'review' | 'done' | 'close-pending' | 'parked' | 'error' | 'asking' | 'queued'
71
- export const timelineDisplay = (e: { status: Lifecycle; proposal: Proposal | null }): DisplayWord =>
72
- e.status === 'awaiting' ? (PROPOSAL_DISPLAY[e.proposal ?? 'nothing'] ?? 'done')
73
- : e.status === 'active' ? 'working' : e.status
74
-
75
- // the channel of the LAST HUMAN send (from == null): 'note' when the note-reply hint rode along, else null.
76
- // This is what makes the reply-channel hints SYMMETRIC ([[session-timeline]]): a human send with no note flag
77
- // arriving after a note-send is the "back at a terminal" transition, and the delivery gets the counter-insert.
78
- // Derived from the durable log — no new state, and it survives a server restart. Agent senders (`from` set)
79
- // say nothing about where the HUMAN is reading, so they neither set nor clear it.
80
- export function lastHumanSendVia(id: string): 'note' | null {
81
- const evs = timelineEvents(id)
82
- for (let i = evs.length - 1; i >= 0; i--) {
83
- const e = evs[i]
84
- if (e.kind === 'sent' && e.from == null) return e.replyVia === 'note' ? 'note' : null
85
- }
86
- return null
87
- }
88
-
89
- // the read surface behind GET /api/sessions/:id/timeline: the last `limit` events, oldest first, each status
90
- // event carrying its composed display word. null = no such session (the route 404s).
91
- export function readTimeline(id: string, limit = 500): { events: TimelineEvent[] } | null {
92
- let raw: ReturnType<typeof readAliasedRawRecord>
93
- try { raw = readAliasedRawRecord(id) } catch { return null }
94
- if (!raw || !raw.governed) return null
95
- const evs = timelineEvents(id)
96
- const tail = evs.slice(Math.max(0, evs.length - Math.max(1, limit)))
97
- return { events: tail.map((e) => (e.kind === 'status' ? { ...e, display: timelineDisplay(e) } : e)) }
98
- }