@repo-os/repoos 0.5.45

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 (362) hide show
  1. package/LICENSE.md +110 -0
  2. package/README.md +272 -0
  3. package/dist/.build-info.json +4 -0
  4. package/dist/.build-stamp.json +3 -0
  5. package/dist/cli/colors.d.ts +13 -0
  6. package/dist/cli/colors.js +37 -0
  7. package/dist/cli/index.d.ts +2 -0
  8. package/dist/cli/index.js +221 -0
  9. package/dist/commands/check.d.ts +170 -0
  10. package/dist/commands/check.js +1227 -0
  11. package/dist/commands/docs.d.ts +2 -0
  12. package/dist/commands/docs.js +70 -0
  13. package/dist/commands/gc.d.ts +1 -0
  14. package/dist/commands/gc.js +57 -0
  15. package/dist/commands/init.d.ts +9 -0
  16. package/dist/commands/init.js +699 -0
  17. package/dist/commands/screenshots.d.ts +7 -0
  18. package/dist/commands/screenshots.js +77 -0
  19. package/dist/commands/serve.d.ts +55 -0
  20. package/dist/commands/serve.js +204 -0
  21. package/dist/commands/status.d.ts +140 -0
  22. package/dist/commands/status.js +569 -0
  23. package/dist/commands/stop.d.ts +1 -0
  24. package/dist/commands/stop.js +59 -0
  25. package/dist/commands/tasks.d.ts +47 -0
  26. package/dist/commands/tasks.js +334 -0
  27. package/dist/commands/tunnel.d.ts +1 -0
  28. package/dist/commands/tunnel.js +1271 -0
  29. package/dist/commands/ui-harness.d.ts +53 -0
  30. package/dist/commands/ui-harness.js +62 -0
  31. package/dist/commands/ui-smoke.d.ts +6 -0
  32. package/dist/commands/ui-smoke.js +220 -0
  33. package/dist/commands/upgrade.d.ts +15 -0
  34. package/dist/commands/upgrade.js +188 -0
  35. package/dist/core/auth-store.d.ts +81 -0
  36. package/dist/core/auth-store.js +530 -0
  37. package/dist/core/auth.d.ts +75 -0
  38. package/dist/core/auth.js +124 -0
  39. package/dist/core/bootstrap.d.ts +41 -0
  40. package/dist/core/bootstrap.js +236 -0
  41. package/dist/core/build.d.ts +92 -0
  42. package/dist/core/build.js +249 -0
  43. package/dist/core/canary.d.ts +10 -0
  44. package/dist/core/canary.js +14 -0
  45. package/dist/core/check-failure-summary.d.ts +10 -0
  46. package/dist/core/check-failure-summary.js +34 -0
  47. package/dist/core/config.d.ts +160 -0
  48. package/dist/core/config.js +1288 -0
  49. package/dist/core/context-pack.d.ts +74 -0
  50. package/dist/core/context-pack.js +778 -0
  51. package/dist/core/db.d.ts +236 -0
  52. package/dist/core/db.js +747 -0
  53. package/dist/core/detect.d.ts +69 -0
  54. package/dist/core/detect.js +251 -0
  55. package/dist/core/docs.d.ts +76 -0
  56. package/dist/core/docs.js +225 -0
  57. package/dist/core/frontmatter.d.ts +29 -0
  58. package/dist/core/frontmatter.js +215 -0
  59. package/dist/core/git.d.ts +505 -0
  60. package/dist/core/git.js +1453 -0
  61. package/dist/core/indexer.d.ts +33 -0
  62. package/dist/core/indexer.js +282 -0
  63. package/dist/core/input.d.ts +66 -0
  64. package/dist/core/input.js +222 -0
  65. package/dist/core/logger.d.ts +70 -0
  66. package/dist/core/logger.js +138 -0
  67. package/dist/core/models.d.ts +45 -0
  68. package/dist/core/models.js +291 -0
  69. package/dist/core/net-probe.d.ts +4 -0
  70. package/dist/core/net-probe.js +20 -0
  71. package/dist/core/providers/deepinfra.d.ts +23 -0
  72. package/dist/core/providers/deepinfra.js +44 -0
  73. package/dist/core/providers/index.d.ts +24 -0
  74. package/dist/core/providers/index.js +59 -0
  75. package/dist/core/providers/openrouter.d.ts +28 -0
  76. package/dist/core/providers/openrouter.js +82 -0
  77. package/dist/core/providers/spend.d.ts +86 -0
  78. package/dist/core/providers/spend.js +286 -0
  79. package/dist/core/providers/types.d.ts +56 -0
  80. package/dist/core/providers/types.js +39 -0
  81. package/dist/core/repoos.d.ts +59 -0
  82. package/dist/core/repoos.js +221 -0
  83. package/dist/core/runtime.d.ts +35 -0
  84. package/dist/core/runtime.js +167 -0
  85. package/dist/core/skills-registry.d.ts +39 -0
  86. package/dist/core/skills-registry.js +148 -0
  87. package/dist/core/skills-registry.test.d.ts +1 -0
  88. package/dist/core/skills-registry.test.js +52 -0
  89. package/dist/core/sysmem.d.ts +7 -0
  90. package/dist/core/sysmem.js +55 -0
  91. package/dist/core/tailscale.d.ts +2 -0
  92. package/dist/core/tailscale.js +19 -0
  93. package/dist/core/task.d.ts +53 -0
  94. package/dist/core/task.js +310 -0
  95. package/dist/core/toml-line.d.ts +20 -0
  96. package/dist/core/toml-line.js +52 -0
  97. package/dist/core/toml-validate.d.ts +44 -0
  98. package/dist/core/toml-validate.js +335 -0
  99. package/dist/core/tunnel-assistant.d.ts +30 -0
  100. package/dist/core/tunnel-assistant.js +65 -0
  101. package/dist/core/tunnel-registry.d.ts +96 -0
  102. package/dist/core/tunnel-registry.js +267 -0
  103. package/dist/core/tunnel-registry.test.d.ts +1 -0
  104. package/dist/core/tunnel-registry.test.js +309 -0
  105. package/dist/core/tunnel.d.ts +103 -0
  106. package/dist/core/tunnel.js +320 -0
  107. package/dist/core/types.d.ts +811 -0
  108. package/dist/core/types.js +27 -0
  109. package/dist/core/worktree-gc.d.ts +57 -0
  110. package/dist/core/worktree-gc.js +194 -0
  111. package/dist/server/__tests__/integration-job.test.d.ts +1 -0
  112. package/dist/server/__tests__/integration-job.test.js +129 -0
  113. package/dist/server/agents.d.ts +1020 -0
  114. package/dist/server/agents.js +4070 -0
  115. package/dist/server/attachments.d.ts +51 -0
  116. package/dist/server/attachments.js +130 -0
  117. package/dist/server/auto-engineering.d.ts +45 -0
  118. package/dist/server/auto-engineering.js +275 -0
  119. package/dist/server/branchless-release.d.ts +22 -0
  120. package/dist/server/branchless-release.js +67 -0
  121. package/dist/server/built-in-agents.d.ts +305 -0
  122. package/dist/server/built-in-agents.js +1838 -0
  123. package/dist/server/cto-monitor.d.ts +35 -0
  124. package/dist/server/cto-monitor.js +281 -0
  125. package/dist/server/cto.d.ts +125 -0
  126. package/dist/server/cto.js +590 -0
  127. package/dist/server/deployments.d.ts +119 -0
  128. package/dist/server/deployments.js +325 -0
  129. package/dist/server/diff-snapshot.d.ts +20 -0
  130. package/dist/server/diff-snapshot.js +73 -0
  131. package/dist/server/done.d.ts +160 -0
  132. package/dist/server/done.js +488 -0
  133. package/dist/server/freeform.d.ts +55 -0
  134. package/dist/server/freeform.js +179 -0
  135. package/dist/server/handoff.d.ts +99 -0
  136. package/dist/server/handoff.js +575 -0
  137. package/dist/server/hetzner.d.ts +45 -0
  138. package/dist/server/hetzner.js +117 -0
  139. package/dist/server/icons.d.ts +8 -0
  140. package/dist/server/icons.js +195 -0
  141. package/dist/server/integration-job.d.ts +75 -0
  142. package/dist/server/integration-job.js +144 -0
  143. package/dist/server/integration-orchestrator.d.ts +211 -0
  144. package/dist/server/integration-orchestrator.js +1299 -0
  145. package/dist/server/integration-status.d.ts +48 -0
  146. package/dist/server/integration-status.js +71 -0
  147. package/dist/server/live-index.d.ts +295 -0
  148. package/dist/server/live-index.js +452 -0
  149. package/dist/server/model-test.d.ts +20 -0
  150. package/dist/server/model-test.js +100 -0
  151. package/dist/server/ntfy.d.ts +57 -0
  152. package/dist/server/ntfy.js +112 -0
  153. package/dist/server/pm-attachments.d.ts +35 -0
  154. package/dist/server/pm-attachments.js +181 -0
  155. package/dist/server/pm-runs.d.ts +58 -0
  156. package/dist/server/pm-runs.js +80 -0
  157. package/dist/server/preview.d.ts +174 -0
  158. package/dist/server/preview.js +641 -0
  159. package/dist/server/release.d.ts +88 -0
  160. package/dist/server/release.js +449 -0
  161. package/dist/server/reload.d.ts +194 -0
  162. package/dist/server/reload.js +586 -0
  163. package/dist/server/remote-validation.d.ts +132 -0
  164. package/dist/server/remote-validation.js +478 -0
  165. package/dist/server/repo-lock.d.ts +36 -0
  166. package/dist/server/repo-lock.js +141 -0
  167. package/dist/server/review-guard.d.ts +14 -0
  168. package/dist/server/review-guard.js +159 -0
  169. package/dist/server/review.d.ts +243 -0
  170. package/dist/server/review.js +1211 -0
  171. package/dist/server/routes/agents.d.ts +6 -0
  172. package/dist/server/routes/agents.js +28 -0
  173. package/dist/server/routes/auth.d.ts +60 -0
  174. package/dist/server/routes/auth.js +755 -0
  175. package/dist/server/routes/config.d.ts +20 -0
  176. package/dist/server/routes/config.js +347 -0
  177. package/dist/server/routes/debugger.d.ts +33 -0
  178. package/dist/server/routes/debugger.js +360 -0
  179. package/dist/server/routes/deployments.d.ts +3 -0
  180. package/dist/server/routes/deployments.js +16 -0
  181. package/dist/server/routes/docs.d.ts +8 -0
  182. package/dist/server/routes/docs.js +135 -0
  183. package/dist/server/routes/helpers.d.ts +21 -0
  184. package/dist/server/routes/helpers.js +171 -0
  185. package/dist/server/routes/index.d.ts +19 -0
  186. package/dist/server/routes/index.js +18 -0
  187. package/dist/server/routes/info.d.ts +17 -0
  188. package/dist/server/routes/info.js +177 -0
  189. package/dist/server/routes/inputs.d.ts +7 -0
  190. package/dist/server/routes/inputs.js +125 -0
  191. package/dist/server/routes/model-providers.d.ts +27 -0
  192. package/dist/server/routes/model-providers.js +94 -0
  193. package/dist/server/routes/models.d.ts +3 -0
  194. package/dist/server/routes/models.js +36 -0
  195. package/dist/server/routes/notify.d.ts +2 -0
  196. package/dist/server/routes/notify.js +17 -0
  197. package/dist/server/routes/playground.d.ts +29 -0
  198. package/dist/server/routes/playground.js +81 -0
  199. package/dist/server/routes/release.d.ts +20 -0
  200. package/dist/server/routes/release.js +86 -0
  201. package/dist/server/routes/router.d.ts +12 -0
  202. package/dist/server/routes/router.js +32 -0
  203. package/dist/server/routes/skill-registry.d.ts +5 -0
  204. package/dist/server/routes/skill-registry.js +51 -0
  205. package/dist/server/routes/tasks.d.ts +58 -0
  206. package/dist/server/routes/tasks.js +1442 -0
  207. package/dist/server/routes/transcribe.d.ts +2 -0
  208. package/dist/server/routes/transcribe.js +124 -0
  209. package/dist/server/routes/types.d.ts +68 -0
  210. package/dist/server/routes/types.js +1 -0
  211. package/dist/server/routes/ui.d.ts +5 -0
  212. package/dist/server/routes/ui.js +81 -0
  213. package/dist/server/routes/utils.d.ts +3 -0
  214. package/dist/server/routes/utils.js +23 -0
  215. package/dist/server/serve-reaper.d.ts +135 -0
  216. package/dist/server/serve-reaper.js +491 -0
  217. package/dist/server/server.d.ts +49 -0
  218. package/dist/server/server.js +2171 -0
  219. package/dist/server/supervisor.d.ts +89 -0
  220. package/dist/server/supervisor.js +231 -0
  221. package/dist/server/system.d.ts +198 -0
  222. package/dist/server/system.js +480 -0
  223. package/dist/server/task-check.d.ts +45 -0
  224. package/dist/server/task-check.js +71 -0
  225. package/dist/server/task-transitions.d.ts +51 -0
  226. package/dist/server/task-transitions.js +78 -0
  227. package/dist/server/task-watchdog.d.ts +158 -0
  228. package/dist/server/task-watchdog.js +681 -0
  229. package/dist/server/test-run.d.ts +28 -0
  230. package/dist/server/test-run.js +81 -0
  231. package/dist/server/watcher.d.ts +21 -0
  232. package/dist/server/watcher.js +194 -0
  233. package/dist/server/write.d.ts +94 -0
  234. package/dist/server/write.js +345 -0
  235. package/dist/ui/assets/AgentsView-CF4wRvHh.css +1 -0
  236. package/dist/ui/assets/AgentsView-D-myL-kA.js +1 -0
  237. package/dist/ui/assets/ContextView-D3TC-RSp.css +1 -0
  238. package/dist/ui/assets/ContextView-DsOqAdyE.js +4 -0
  239. package/dist/ui/assets/DashboardView-BOhsIJqO.js +1 -0
  240. package/dist/ui/assets/DashboardView-Ck9o0RP2.css +1 -0
  241. package/dist/ui/assets/DeploymentsView--iIUVfEH.css +1 -0
  242. package/dist/ui/assets/DeploymentsView-DXu_FYR2.js +1 -0
  243. package/dist/ui/assets/InputsView-24HVbVPk.js +1 -0
  244. package/dist/ui/assets/InputsView-BLb7GHtx.css +1 -0
  245. package/dist/ui/assets/LoginView-6QlGg6cx.css +1 -0
  246. package/dist/ui/assets/LoginView-BqupI0Lt.js +1 -0
  247. package/dist/ui/assets/ReleasesView-BEG1A0YH.css +1 -0
  248. package/dist/ui/assets/ReleasesView-CAgMuxpe.js +3 -0
  249. package/dist/ui/assets/SettingsView-CA-NYSMK.css +1 -0
  250. package/dist/ui/assets/SettingsView-O3iZSnjg.js +3 -0
  251. package/dist/ui/assets/WorkView-D8Tl6qwy.js +1 -0
  252. package/dist/ui/assets/WorkView-DMYL2s3W.css +1 -0
  253. package/dist/ui/assets/abnfDiagram-VCTEODGH-J5lkSnEE.js +1 -0
  254. package/dist/ui/assets/arc-BHZnmhhM.js +1 -0
  255. package/dist/ui/assets/architecture-7GRP2DOG-pLdFt-xS.js +1 -0
  256. package/dist/ui/assets/architectureDiagram-5GKGNRK7-C3k89uKX.js +36 -0
  257. package/dist/ui/assets/array-BifhSqXX.js +1 -0
  258. package/dist/ui/assets/blockDiagram-I7D4REHJ-AWNoBzop.js +129 -0
  259. package/dist/ui/assets/button-lbikqSph.js +1 -0
  260. package/dist/ui/assets/c4Diagram-7LVT6UL2-DKG1D5gd.js +38 -0
  261. package/dist/ui/assets/channel-gA4qBv3A.js +1 -0
  262. package/dist/ui/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  263. package/dist/ui/assets/chunk-4HAMMTFA-D1YR8lF_.js +62 -0
  264. package/dist/ui/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  265. package/dist/ui/assets/chunk-75Z2AOVW-5GuBxfsL.js +2 -0
  266. package/dist/ui/assets/chunk-DU6HZSFF-DfdNNqwa.js +127 -0
  267. package/dist/ui/assets/chunk-F27PBJKO-BPZzinQ4.js +1 -0
  268. package/dist/ui/assets/chunk-FOHPRMQF-l2z4K2jD.js +161 -0
  269. package/dist/ui/assets/chunk-GMAD6QVW-DGWvSKj5.js +72 -0
  270. package/dist/ui/assets/chunk-GVQU2GXP-D6Aw75wJ.js +1 -0
  271. package/dist/ui/assets/chunk-IMKFNOWR-B8mMBKCW.js +231 -0
  272. package/dist/ui/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  273. package/dist/ui/assets/chunk-L3NEJ4N5-D5OJuXYE.js +1 -0
  274. package/dist/ui/assets/chunk-OSK3NFVY-B7r9w2UW.js +10 -0
  275. package/dist/ui/assets/chunk-P2QGCYS3-C74X4AQX.js +1 -0
  276. package/dist/ui/assets/chunk-POPQ4Y6H-C5_u1gUS.js +1 -0
  277. package/dist/ui/assets/chunk-PWAF6VOD-DfoTLtxn.js +1 -0
  278. package/dist/ui/assets/chunk-SHT3W25Y-D40m2eqz.js +168 -0
  279. package/dist/ui/assets/chunk-SVP7TREG-euxi0Kap.js +88 -0
  280. package/dist/ui/assets/chunk-TICWLB2K-fkdxngzN.js +206 -0
  281. package/dist/ui/assets/chunk-XXDRQBXY-DFBUG-OT.js +1 -0
  282. package/dist/ui/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  283. package/dist/ui/assets/classDiagram-ZZMXUADV-BzW8bq2P.js +1 -0
  284. package/dist/ui/assets/classDiagram-v2-VYDZK3BY-BzW8bq2P.js +1 -0
  285. package/dist/ui/assets/cose-bilkent-JH36ORCC-BTcgMon1.js +1 -0
  286. package/dist/ui/assets/cynefin-OW5HDTMX-B5m_COsS.js +1 -0
  287. package/dist/ui/assets/cynefinDiagram-5FMLGOSQ-C-AG6CGe.js +62 -0
  288. package/dist/ui/assets/cytoscape.esm-FBntH-9t.js +321 -0
  289. package/dist/ui/assets/dagre-GXQ25YYZ-DDfDnp8L.js +4 -0
  290. package/dist/ui/assets/dagre-PrKaheQc.js +1 -0
  291. package/dist/ui/assets/defaultLocale-BFoDCU3G.js +1 -0
  292. package/dist/ui/assets/diagram-S7CK7UJ4-DjQZAlEY.js +30 -0
  293. package/dist/ui/assets/diagram-UQ7AKVKN-DAZ9yp1B.js +41 -0
  294. package/dist/ui/assets/diagram-VSXAHHWV-BWepUKJD.js +3 -0
  295. package/dist/ui/assets/diagram-VX7I27RA-EcV1J81b.js +24 -0
  296. package/dist/ui/assets/diagram-Z3DM3KII-Dbz7XU_K.js +24 -0
  297. package/dist/ui/assets/dist-DTg6UBE_.js +1 -0
  298. package/dist/ui/assets/ebnfDiagram-PWID7BFC-BUyQw8Mm.js +1 -0
  299. package/dist/ui/assets/erDiagram-RLTQ6QDP-WVf8ukKt.js +99 -0
  300. package/dist/ui/assets/eventmodeling-NTZA5JFV-DHqyLOAn.js +1 -0
  301. package/dist/ui/assets/flowDiagram-HODETNUW-CYk_ze5K.js +1 -0
  302. package/dist/ui/assets/ganttDiagram-EL5Y4UJY-rB4MZuB-.js +292 -0
  303. package/dist/ui/assets/gitGraph-4MIJSDKK-BOTWM8dY.js +1 -0
  304. package/dist/ui/assets/gitGraphDiagram-WWUBYQGX-eYscuhtP.js +106 -0
  305. package/dist/ui/assets/graphlib-DS17s2tU.js +1 -0
  306. package/dist/ui/assets/index-BACBfnga.css +1 -0
  307. package/dist/ui/assets/index-BOQ-ust6.js +26 -0
  308. package/dist/ui/assets/info-A6RAGUB7-_67wOORe.js +1 -0
  309. package/dist/ui/assets/infoDiagram-27XIBGKW-XVXbddTA.js +2 -0
  310. package/dist/ui/assets/init-C-OQMol4.js +1 -0
  311. package/dist/ui/assets/ishikawaDiagram-5VMMS53U-ClLNiEru.js +70 -0
  312. package/dist/ui/assets/journeyDiagram-3NMN7TZE-NRawjR6i.js +139 -0
  313. package/dist/ui/assets/kanban-definition-UXKFOSKX-BgSzBfIx.js +89 -0
  314. package/dist/ui/assets/katex-DolUETbr.js +257 -0
  315. package/dist/ui/assets/line-KAyfuul4.js +1 -0
  316. package/dist/ui/assets/linear-cCCPOpu7.js +1 -0
  317. package/dist/ui/assets/mermaid-parser.core-CgXZk1iN.js +7 -0
  318. package/dist/ui/assets/mermaid.core-BUUkChHW.js +44 -0
  319. package/dist/ui/assets/mindmap-definition-YA3MSWOX-Cpn7vW4r.js +96 -0
  320. package/dist/ui/assets/ordinal-BDEzSJ7C.js +1 -0
  321. package/dist/ui/assets/packet-AYTQ26CC-0lZwM-d6.js +1 -0
  322. package/dist/ui/assets/path-COt_16Va.js +1 -0
  323. package/dist/ui/assets/pegDiagram-XKGWAZYB-impy0inn.js +1 -0
  324. package/dist/ui/assets/pie-WAS4IAKB-CqfdGHYg.js +1 -0
  325. package/dist/ui/assets/pieDiagram-E7YTZNPT-CxjL4I1h.js +39 -0
  326. package/dist/ui/assets/quadrantDiagram-AXDQQJYC-Cjd1QMIe.js +7 -0
  327. package/dist/ui/assets/radar-RG4KPBEZ-CRkQIwiv.js +1 -0
  328. package/dist/ui/assets/railroad-74A4TZTK-i67XSWTB.js +1 -0
  329. package/dist/ui/assets/railroad-abnf-HS5TGJTU-Cv9m5aS3.js +1 -0
  330. package/dist/ui/assets/railroad-ebnf-LZEXJU2U-C5ZIn-Jh.js +1 -0
  331. package/dist/ui/assets/railroad-peg-WCYAUIDC-CGra9Oq-.js +1 -0
  332. package/dist/ui/assets/railroadDiagram-O6MQD6OU-_pK0qyaY.js +1 -0
  333. package/dist/ui/assets/releases-B0WNV-SY.js +1 -0
  334. package/dist/ui/assets/repoos-cto-square.webp +0 -0
  335. package/dist/ui/assets/repoos-helpful-pm-square.webp +0 -0
  336. package/dist/ui/assets/repoos-orchestrator-square.webp +0 -0
  337. package/dist/ui/assets/repoos-performance-agent-square.webp +0 -0
  338. package/dist/ui/assets/repoos-ross-from-friends-square.webp +0 -0
  339. package/dist/ui/assets/repoos-tech-debt-agent-square.webp +0 -0
  340. package/dist/ui/assets/requirementDiagram-BXWQKSXE-CRrFX-yw.js +84 -0
  341. package/dist/ui/assets/rough.esm-By172zw-.js +1 -0
  342. package/dist/ui/assets/sankeyDiagram-P5KCCOFB-X_xFRj9E.js +40 -0
  343. package/dist/ui/assets/sequenceDiagram-WJ2MYXX4-Byb49lKf.js +162 -0
  344. package/dist/ui/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  345. package/dist/ui/assets/src-BH-TyZbA.js +1 -0
  346. package/dist/ui/assets/stateDiagram-D77RDMKH-CzaPrqYF.js +1 -0
  347. package/dist/ui/assets/stateDiagram-v2-MP3YSRHH-BCXckz7K.js +1 -0
  348. package/dist/ui/assets/swimlanes-42K2YHIH-Cx_1lnqr.js +1 -0
  349. package/dist/ui/assets/swimlanesDiagram-VR7AAH4N-54qsKi6A.js +8 -0
  350. package/dist/ui/assets/timeline-definition-24CTP7MA-B1IbZPQ-.js +120 -0
  351. package/dist/ui/assets/treeView-Q6P3EWNA-DFWhVE3d.js +1 -0
  352. package/dist/ui/assets/treemap-WGGIJYW6-BmbYPThn.js +1 -0
  353. package/dist/ui/assets/vendor-ui-DPm7zLxi.js +3 -0
  354. package/dist/ui/assets/vendor-vue-CobgyEJp.js +1 -0
  355. package/dist/ui/assets/vennDiagram-4TSXK5OY-Ae2AtRpt.js +34 -0
  356. package/dist/ui/assets/wardley-WFR3VGLG-BtD4X4tL.js +1 -0
  357. package/dist/ui/assets/wardleyDiagram-VM6X3IG4-B3YN2fTd.js +78 -0
  358. package/dist/ui/assets/xychartDiagram-S5SC5T6Z-CIzJfMKA.js +7 -0
  359. package/dist/ui/favicon.svg +11 -0
  360. package/dist/ui/index.html +49 -0
  361. package/dist/ui/sw.js +48 -0
  362. package/package.json +91 -0
@@ -0,0 +1,480 @@
1
+ /**
2
+ * System resource sampler. Uses `node:os` for machine-wide facts and `ps` for
3
+ * per-process CPU/memory stats. One `ps` invocation per interval covers all
4
+ * tracked PIDs — never one call per process. Zero runtime dependencies.
5
+ *
6
+ * Orphan detection: a live process not in the AgentRunner registry, or whose
7
+ * ppid is no longer the server's pid, is marked orphaned.
8
+ */
9
+ import { execFileSync } from "node:child_process";
10
+ import { existsSync, readFileSync, realpathSync, writeFileSync, mkdirSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { cpus, totalmem, freemem, loadavg, platform } from "node:os";
13
+ import { availableMemBytes } from "../core/sysmem.js";
14
+ const OWNERSHIP_FILE = "repoos-ownership.json";
15
+ const KB = 1024;
16
+ function safeExecFileSync(cmd, args) {
17
+ try {
18
+ return execFileSync(cmd, args, {
19
+ encoding: "utf8",
20
+ stdio: ["ignore", "pipe", "ignore"],
21
+ timeout: 5000,
22
+ });
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ function parsePsLine(line) {
29
+ const parts = line.trim().split(/\s+/);
30
+ if (parts.length < 6)
31
+ return null;
32
+ const pid = Number(parts[0]);
33
+ const ppid = Number(parts[1]);
34
+ const cpuPercent = Number(parts[2]);
35
+ const memPercent = Number(parts[3]);
36
+ const rssKB = Number(parts[4]);
37
+ const elapsed = parts.slice(5).join(" ");
38
+ if (isNaN(pid) || isNaN(ppid) || isNaN(cpuPercent) || isNaN(memPercent) || isNaN(rssKB)) {
39
+ return null;
40
+ }
41
+ return { pid, ppid, cpuPercent, memPercent, rssKB, elapsed };
42
+ }
43
+ /**
44
+ * Parse `ps -o pid=,ppid=,%cpu=,%mem=,rss=,etime=` output into records.
45
+ * One `ps` call covers all PIDs at once. Export for testing.
46
+ */
47
+ export function parsePsOutput(output) {
48
+ return output
49
+ .split("\n")
50
+ .map(parsePsLine)
51
+ .filter((r) => r !== null);
52
+ }
53
+ function machineInfo() {
54
+ return {
55
+ cpuCount: cpus().length,
56
+ totalMem: totalmem(),
57
+ freeMem: freemem(),
58
+ availableMem: availableMemBytes(),
59
+ loadavg: loadavg(),
60
+ platform: platform(),
61
+ };
62
+ }
63
+ let repoStatsCache = null;
64
+ const REPO_STATS_TTL_MS = 30_000;
65
+ /**
66
+ * git-derived codebase size: worktree count, tracked-file count, and total
67
+ * lines across tracked text files. Three `git` spawns, so memoised for 30s —
68
+ * the SSE loop calls this every 5s and these numbers change on the order of
69
+ * commits, not seconds. Returns the last good value (or null) on git failure.
70
+ */
71
+ export function sampleRepoStats(root, worktreeWarnThreshold = 20) {
72
+ const now = Date.now();
73
+ if (repoStatsCache &&
74
+ repoStatsCache.root === root &&
75
+ now - repoStatsCache.at < REPO_STATS_TTL_MS) {
76
+ return { ...repoStatsCache.stats, worktreeWarnThreshold };
77
+ }
78
+ const worktreeOut = safeExecFileSync("git", ["-C", root, "worktree", "list", "--porcelain"]);
79
+ const filesOut = safeExecFileSync("git", ["-C", root, "ls-files"]);
80
+ if (worktreeOut === null || filesOut === null) {
81
+ // Git unavailable or not a repo: keep serving a stale value for THIS root,
82
+ // never another root's.
83
+ return repoStatsCache?.root === root
84
+ ? { ...repoStatsCache.stats, worktreeWarnThreshold }
85
+ : null;
86
+ }
87
+ // Empty pattern matches every line; -I skips binary files. One spawn yields
88
+ // `path:<linecount>` per text file.
89
+ const locOut = safeExecFileSync("git", ["-C", root, "grep", "-I", "--count", "-e", ""]);
90
+ let linesOfCode = 0;
91
+ if (locOut !== null) {
92
+ for (const line of locOut.split("\n")) {
93
+ const m = line.match(/:(\d+)$/);
94
+ if (m)
95
+ linesOfCode += Number(m[1]);
96
+ }
97
+ }
98
+ const stats = {
99
+ worktrees: (worktreeOut.match(/^worktree /gm) ?? []).length,
100
+ trackedFiles: filesOut.split("\n").filter(Boolean).length,
101
+ linesOfCode,
102
+ worktreeWarnThreshold,
103
+ };
104
+ repoStatsCache = { at: now, root, stats };
105
+ return stats;
106
+ }
107
+ function sampleProcesses(pids) {
108
+ if (pids.length === 0)
109
+ return [];
110
+ const pidArgs = pids.map(String);
111
+ const output = safeExecFileSync("ps", [
112
+ "-o",
113
+ "pid=,ppid=,%cpu=,%mem=,rss=,etime=",
114
+ "-p",
115
+ ...pidArgs,
116
+ ]);
117
+ if (!output)
118
+ return [];
119
+ return parsePsOutput(output);
120
+ }
121
+ /**
122
+ * Persist RepoOS process ownership so orphan detection survives a server restart.
123
+ */
124
+ function readOwnership(cacheDir) {
125
+ const file = join(cacheDir, OWNERSHIP_FILE);
126
+ if (!existsSync(file))
127
+ return [];
128
+ try {
129
+ const raw = readFileSync(file, "utf8");
130
+ return JSON.parse(raw);
131
+ }
132
+ catch {
133
+ return [];
134
+ }
135
+ }
136
+ function writeOwnership(cacheDir, records) {
137
+ try {
138
+ mkdirSync(cacheDir, { recursive: true });
139
+ writeFileSync(join(cacheDir, OWNERSHIP_FILE), JSON.stringify(records, null, 2), "utf8");
140
+ }
141
+ catch {
142
+ /* best-effort: sampling should never fail on a writable-directory problem */
143
+ }
144
+ }
145
+ /**
146
+ * Update the persisted ownership records: add entries for newly-spawned agents
147
+ * (registry entries not yet persisted) and remove entries whose PIDs are dead.
148
+ */
149
+ function syncOwnership(cacheDir, running, livePids) {
150
+ const existing = readOwnership(cacheDir);
151
+ const byPid = new Map();
152
+ for (const r of existing)
153
+ byPid.set(r.pid, r);
154
+ for (const info of running) {
155
+ if (info.pid <= 0)
156
+ continue;
157
+ if (!byPid.has(info.pid)) {
158
+ byPid.set(info.pid, {
159
+ pid: info.pid,
160
+ taskId: info.id,
161
+ startedAt: info.startedAt,
162
+ executable: "",
163
+ workdir: info.workdir ?? "",
164
+ });
165
+ }
166
+ }
167
+ const out = [];
168
+ for (const [pid, rec] of byPid) {
169
+ if (livePids.has(pid) || running.some((r) => r.pid === pid)) {
170
+ out.push(rec);
171
+ }
172
+ }
173
+ writeOwnership(cacheDir, out);
174
+ return out;
175
+ }
176
+ /**
177
+ * A stray count at or above this is a real problem, not untidiness: it is the
178
+ * regime where #0211 failed its close-out gate twice on unrelated flaky tests.
179
+ */
180
+ const SERVE_WARN_THRESHOLD = 4;
181
+ /** Matches both a compiled (`dist/cli/index.js`) and a dev (`src/cli/index.ts`) serve. */
182
+ const SERVE_CMD_RE = /[/\\](?:dist[/\\]cli[/\\]index\.js|src[/\\]cli[/\\]index\.ts)\s+serve\b/;
183
+ /** Extract the repo root a serve process is running from, or null. */
184
+ export function parseServeRoot(command) {
185
+ const m = command.match(/(\S+?)[/\\](?:dist[/\\]cli[/\\]index\.js|src[/\\]cli[/\\]index\.ts)\s+serve\b/);
186
+ return m ? m[1] : null;
187
+ }
188
+ /** True when two repo-root paths point at the same directory (symlink-safe). */
189
+ function sameRoot(a, b) {
190
+ if (!a || !b)
191
+ return false;
192
+ if (a === b)
193
+ return true;
194
+ try {
195
+ return realpathSync(a) === realpathSync(b);
196
+ }
197
+ catch {
198
+ return false;
199
+ }
200
+ }
201
+ /** Extract `--port N` from a serve command line, or null. */
202
+ export function parseServePort(command) {
203
+ const m = command.match(/--port[= ](\d+)/);
204
+ return m ? Number(m[1]) : null;
205
+ }
206
+ /**
207
+ * Parse `ps ax -o pid=,ppid=,command=` output into serve-process records.
208
+ *
209
+ * Classification order matters. The control plane is checked first because the
210
+ * reload handoff deliberately detaches it, so it also runs with `ppid` 1 and
211
+ * would otherwise look abandoned. Everything else that RepoOS did not start is
212
+ * abandoned only if its parent is gone — a fixture server with a live vitest
213
+ * worker above it is the gate doing its job, not a leak.
214
+ *
215
+ * Exported for testing so classification can be exercised without spawning servers.
216
+ */
217
+ export function parseServeScan(output, serverPid, knownPids, rootExists, ownRoot) {
218
+ const rows = [];
219
+ const livePids = new Set();
220
+ for (const line of output.split("\n")) {
221
+ const m = line.trim().match(/^(\d+)\s+(\d+)\s+(.*)$/);
222
+ if (!m)
223
+ continue;
224
+ const pid = Number(m[1]);
225
+ livePids.add(pid);
226
+ rows.push({ pid, ppid: Number(m[2]), command: m[3] });
227
+ }
228
+ const processes = [];
229
+ for (const { pid, ppid, command } of rows) {
230
+ if (!SERVE_CMD_RE.test(command))
231
+ continue;
232
+ const root = parseServeRoot(command);
233
+ const rootIsLive = rootExists(root);
234
+ // A parent of 1 means the process was reparented after its spawner died.
235
+ const supervised = ppid !== 1 && livePids.has(ppid);
236
+ const kind = pid === serverPid
237
+ ? "control-plane"
238
+ : knownPids.has(pid)
239
+ ? "known-preview"
240
+ : supervised
241
+ ? "in-flight"
242
+ : // A detached serve for another repo whose root still exists is that
243
+ // repo's control plane (also ppid 1) — not ours to touch. Only an
244
+ // orphan of OUR root, or one whose root is gone, is a real stray.
245
+ ownRoot && root && rootIsLive && !sameRoot(root, ownRoot)
246
+ ? "foreign"
247
+ : "stray";
248
+ processes.push({
249
+ pid,
250
+ ppid,
251
+ port: parseServePort(command),
252
+ root,
253
+ rootExists: rootIsLive,
254
+ kind,
255
+ });
256
+ }
257
+ const strays = processes.filter((p) => p.kind === "stray");
258
+ const deadRoot = strays.filter((p) => !p.rootExists).length;
259
+ const level = strays.length === 0 ? "ok" : strays.length >= SERVE_WARN_THRESHOLD ? "warn" : "notice";
260
+ return {
261
+ total: processes.length,
262
+ strays: strays.length,
263
+ inFlight: processes.filter((p) => p.kind === "in-flight").length,
264
+ deadRoot,
265
+ level,
266
+ processes,
267
+ };
268
+ }
269
+ let serveScanCache = null;
270
+ /** The census walks every process on the machine, so it runs far less often than the 5s sample. */
271
+ const SERVE_SCAN_TTL_MS = 20_000;
272
+ /**
273
+ * Census live `repoos serve` processes. Cached — `ps ax` lists every process on
274
+ * the machine, which is much heavier than the targeted per-PID sample.
275
+ */
276
+ export function scanServeProcesses(serverPid, knownPids, ownRoot) {
277
+ const now = Date.now();
278
+ if (serveScanCache && now - serveScanCache.at < SERVE_SCAN_TTL_MS)
279
+ return serveScanCache.scan;
280
+ const output = safeExecFileSync("ps", ["ax", "-o", "pid=,ppid=,command="]);
281
+ if (output === null)
282
+ return serveScanCache?.scan ?? null;
283
+ const scan = parseServeScan(output, serverPid, knownPids, (root) => root !== null && existsSync(root), ownRoot);
284
+ serveScanCache = { at: now, scan };
285
+ return scan;
286
+ }
287
+ /** Drop the cached census. Exported for tests. */
288
+ export function resetServeScanCache() {
289
+ serveScanCache = null;
290
+ }
291
+ /**
292
+ * Reap every `stray` process the census finds — a process whose spawning
293
+ * parent is confirmed dead (reparented to PID 1). This is safe by
294
+ * construction: `in-flight` processes (a live parent still supervising them,
295
+ * e.g. the close-out gate's own test suite mid-run) are never included, and
296
+ * neither is the control plane or a known preview. Killing a stray destroys
297
+ * no live work — nothing will ever come back to claim it.
298
+ *
299
+ * Root cause this offsets (#0216): a failed reload-replacement handoff kills
300
+ * only the direct child process (`ReloadManager.killChild`, plain SIGTERM,
301
+ * not a process-group kill), so anything that child spawned before failing
302
+ * its readiness check survives as an orphan. Under repeated failed reload
303
+ * attempts this accumulates fast enough to strain the whole machine, not just
304
+ * starve the close-out gate. This periodic sweep is the general safety net;
305
+ * the process-group fix in reload.ts is the more targeted root-cause fix,
306
+ * tracked separately.
307
+ */
308
+ export function reapStrayServeProcesses(serverPid, knownPids, kill = process.kill.bind(process), scan, ownRoot) {
309
+ const doScan = scan ??
310
+ ((p, k) => {
311
+ resetServeScanCache();
312
+ return scanServeProcesses(p, k, ownRoot);
313
+ });
314
+ const result = doScan(serverPid, knownPids);
315
+ if (!result)
316
+ return 0;
317
+ let reaped = 0;
318
+ for (const p of result.processes) {
319
+ if (p.kind !== "stray")
320
+ continue;
321
+ try {
322
+ kill(p.pid, "SIGTERM");
323
+ reaped++;
324
+ }
325
+ catch {
326
+ /* already gone */
327
+ }
328
+ }
329
+ return reaped;
330
+ }
331
+ /**
332
+ * Kill a single process by PID: SIGTERM first, escalating to SIGKILL after a
333
+ * grace period if it hasn't exited. Same sequence AgentRunner.stop() and the
334
+ * stray-serve reaper already use elsewhere. Backs the manual "Kill" action in
335
+ * the System Resources panel — callers must verify the PID is one RepoOS
336
+ * itself is tracking (a fresh sampleSystem()/scanServeProcesses() result)
337
+ * before calling this; it does not re-check.
338
+ */
339
+ export function killTrackedProcess(pid, kill = process.kill.bind(process)) {
340
+ try {
341
+ kill(pid, "SIGTERM");
342
+ }
343
+ catch {
344
+ return false; // already gone, or no such process
345
+ }
346
+ const t = setTimeout(() => {
347
+ try {
348
+ kill(pid, "SIGKILL");
349
+ }
350
+ catch {
351
+ /* already gone */
352
+ }
353
+ }, 3000);
354
+ t.unref?.();
355
+ return true;
356
+ }
357
+ /**
358
+ * Sample the system: machine facts, RepoOS process totals, and a per-process
359
+ * breakdown with orphan detection. One `ps` call covers all tracked + agent PIDs.
360
+ */
361
+ export function sampleSystem(opts) {
362
+ const machine = machineInfo();
363
+ const serverPid = opts.serverPid;
364
+ const agentPids = new Set(opts.runningAgents.map((a) => a.pid).filter((p) => p > 0));
365
+ const idByPid = new Map();
366
+ for (const a of opts.runningAgents) {
367
+ if (a.pid > 0)
368
+ idByPid.set(a.pid, a.id);
369
+ }
370
+ const allPids = [serverPid, ...agentPids];
371
+ const ownership = syncOwnership(opts.cacheDir, opts.runningAgents, new Set(allPids));
372
+ const ownershipByPid = new Map();
373
+ for (const o of ownership)
374
+ ownershipByPid.set(o.pid, o);
375
+ const records = sampleProcesses(allPids);
376
+ const psByPid = new Map();
377
+ for (const r of records)
378
+ psByPid.set(r.pid, r);
379
+ let totalCpu = 0;
380
+ let totalMem = 0;
381
+ let totalMemPercent = 0;
382
+ const processes = [];
383
+ for (const pid of allPids) {
384
+ const ps = psByPid.get(pid);
385
+ if (!ps)
386
+ continue;
387
+ const memBytes = ps.rssKB * KB;
388
+ totalCpu += ps.cpuPercent;
389
+ totalMem += memBytes;
390
+ totalMemPercent += ps.memPercent;
391
+ const owned = ownershipByPid.get(pid);
392
+ const taskId = idByPid.get(pid) ?? owned?.taskId ?? null;
393
+ const orphaned = ps.ppid !== serverPid && pid !== serverPid;
394
+ processes.push({
395
+ pid,
396
+ taskId,
397
+ cpuPercent: ps.cpuPercent,
398
+ memBytes,
399
+ elapsed: ps.elapsed,
400
+ orphaned,
401
+ unverified: !idByPid.has(pid) && !owned,
402
+ });
403
+ }
404
+ // Discover orphaned RepoOS processes: PIDs that are NOT in the current
405
+ // running registry but WERE persisted as RepoOS-owned. Also include
406
+ // REGISTERED agents whose ppid is no longer the server.
407
+ const seenPids = new Set(allPids);
408
+ for (const [pid, owned] of ownershipByPid) {
409
+ if (seenPids.has(pid))
410
+ continue;
411
+ if (!isProcessAlive(pid))
412
+ continue;
413
+ const ps = sampleSingleProcess(pid);
414
+ if (!ps)
415
+ continue;
416
+ const memBytes = ps.rssKB * KB;
417
+ totalCpu += ps.cpuPercent;
418
+ totalMem += memBytes;
419
+ totalMemPercent += ps.memPercent;
420
+ processes.push({
421
+ pid,
422
+ taskId: owned.taskId,
423
+ cpuPercent: ps.cpuPercent,
424
+ memBytes,
425
+ elapsed: ps.elapsed,
426
+ orphaned: true,
427
+ unverified: false,
428
+ });
429
+ }
430
+ // Sort: orphans first, then by CPU descending
431
+ processes.sort((a, b) => {
432
+ if (a.orphaned !== b.orphaned)
433
+ return a.orphaned ? -1 : 1;
434
+ return b.cpuPercent - a.cpuPercent;
435
+ });
436
+ return {
437
+ machine,
438
+ totals: {
439
+ cpuPercent: Math.round(totalCpu * 10) / 10,
440
+ memBytes: totalMem,
441
+ memPercent: Math.round(totalMemPercent * 10) / 10,
442
+ },
443
+ processes,
444
+ serve: scanServeProcesses(serverPid, new Set(opts.knownServePids ?? []), opts.root),
445
+ repo: opts.root ? sampleRepoStats(opts.root, opts.worktreeWarnThreshold) : null,
446
+ serverPid,
447
+ at: new Date().toISOString(),
448
+ };
449
+ }
450
+ function isProcessAlive(pid) {
451
+ try {
452
+ process.kill(pid, 0);
453
+ return true;
454
+ }
455
+ catch {
456
+ return false;
457
+ }
458
+ }
459
+ function sampleSingleProcess(pid) {
460
+ const output = safeExecFileSync("ps", [
461
+ "-o",
462
+ "pid=,ppid=,%cpu=,%mem=,rss=,etime=",
463
+ "-p",
464
+ String(pid),
465
+ ]);
466
+ if (!output)
467
+ return null;
468
+ const records = parsePsOutput(output);
469
+ return records[0] ?? null;
470
+ }
471
+ /**
472
+ * True when the current platform can run the `ps` command with the expected
473
+ * flags (pid=,ppid=,%cpu=,%mem=,rss=,etime=). Windows `ps` (PowerShell alias)
474
+ * does not support these flags, so per-process stats are unavailable there.
475
+ */
476
+ export function psAvailable() {
477
+ if (platform() === "win32")
478
+ return false;
479
+ return safeExecFileSync("ps", ["-o", "pid=", "-p", String(process.pid)]) !== null;
480
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Tracks the `repoos check` invocations RepoOS's own server spawns directly
3
+ * for a task — the handoff-finalize check (handoff.ts's runCheck()) and the
4
+ * MTD merge-gate check (integration-orchestrator.ts's validateCandidate) —
5
+ * so the Debug tab (0310) can show when each ran, how long it took, whether
6
+ * it passed, and stream a currently-running one's output live.
7
+ *
8
+ * Deliberately in-memory only, same tradeoff as TestRunManager: this is
9
+ * observability for the current server session, not a durable audit log. A
10
+ * server restart mid-check simply loses the in-flight run; the check itself
11
+ * gets re-attempted by whatever triggered it.
12
+ */
13
+ export type TaskCheckKind = "handoff-finalize" | "merge-gate";
14
+ export interface TaskCheckRun {
15
+ id: string;
16
+ taskId: string;
17
+ kind: TaskCheckKind;
18
+ startedAt: string;
19
+ finishedAt: string | null;
20
+ durationMs: number | null;
21
+ running: boolean;
22
+ /** null while running; true/false once done() is called. */
23
+ passed: boolean | null;
24
+ code: number | null;
25
+ output: string;
26
+ }
27
+ export type TaskCheckEventKind = "started" | "output" | "done";
28
+ export type TaskCheckListener = (run: TaskCheckRun, event: TaskCheckEventKind, chunk?: string) => void;
29
+ export interface TaskCheckHandle {
30
+ readonly id: string;
31
+ chunk(text: string): void;
32
+ done(code: number | null): void;
33
+ }
34
+ export declare class TaskCheckManager {
35
+ private runsByTask;
36
+ private seq;
37
+ /**
38
+ * Begins tracking one check run for `taskId`. Returns a handle the caller
39
+ * feeds output chunks into as the underlying subprocess streams them, and
40
+ * calls `done()` on once the process exits.
41
+ */
42
+ start(taskId: string, kind: TaskCheckKind, onEvent: TaskCheckListener): TaskCheckHandle;
43
+ /** Past + in-progress runs for a task, oldest first. */
44
+ getRuns(taskId: string): TaskCheckRun[];
45
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Tracks the `repoos check` invocations RepoOS's own server spawns directly
3
+ * for a task — the handoff-finalize check (handoff.ts's runCheck()) and the
4
+ * MTD merge-gate check (integration-orchestrator.ts's validateCandidate) —
5
+ * so the Debug tab (0310) can show when each ran, how long it took, whether
6
+ * it passed, and stream a currently-running one's output live.
7
+ *
8
+ * Deliberately in-memory only, same tradeoff as TestRunManager: this is
9
+ * observability for the current server session, not a durable audit log. A
10
+ * server restart mid-check simply loses the in-flight run; the check itself
11
+ * gets re-attempted by whatever triggered it.
12
+ */
13
+ /** Cap on retained output per run so a very noisy check can't grow this
14
+ * without bound in memory — old text is dropped from the front. */
15
+ const MAX_BUFFERED_CHARS = 500_000;
16
+ /** How many past runs to retain per task — enough to inspect recent
17
+ * history without letting a task that gets checked repeatedly (retries)
18
+ * grow this without bound. */
19
+ const MAX_RUNS_PER_TASK = 10;
20
+ export class TaskCheckManager {
21
+ runsByTask = new Map();
22
+ seq = 0;
23
+ /**
24
+ * Begins tracking one check run for `taskId`. Returns a handle the caller
25
+ * feeds output chunks into as the underlying subprocess streams them, and
26
+ * calls `done()` on once the process exits.
27
+ */
28
+ start(taskId, kind, onEvent) {
29
+ const id = `${taskId}-${kind}-${++this.seq}`;
30
+ const run = {
31
+ id,
32
+ taskId,
33
+ kind,
34
+ startedAt: new Date().toISOString(),
35
+ finishedAt: null,
36
+ durationMs: null,
37
+ running: true,
38
+ passed: null,
39
+ code: null,
40
+ output: "",
41
+ };
42
+ const list = this.runsByTask.get(taskId) ?? [];
43
+ list.push(run);
44
+ while (list.length > MAX_RUNS_PER_TASK)
45
+ list.shift();
46
+ this.runsByTask.set(taskId, list);
47
+ onEvent(run, "started");
48
+ return {
49
+ id,
50
+ chunk: (text) => {
51
+ run.output += text;
52
+ if (run.output.length > MAX_BUFFERED_CHARS) {
53
+ run.output = run.output.slice(run.output.length - MAX_BUFFERED_CHARS);
54
+ }
55
+ onEvent(run, "output", text);
56
+ },
57
+ done: (code) => {
58
+ run.running = false;
59
+ run.finishedAt = new Date().toISOString();
60
+ run.durationMs = Math.max(0, Date.parse(run.finishedAt) - Date.parse(run.startedAt));
61
+ run.code = code;
62
+ run.passed = code === 0;
63
+ onEvent(run, "done");
64
+ },
65
+ };
66
+ }
67
+ /** Past + in-progress runs for a task, oldest first. */
68
+ getRuns(taskId) {
69
+ return this.runsByTask.get(taskId) ?? [];
70
+ }
71
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The canonical status-transition table (lifecycle audit, #0295-adjacent).
3
+ *
4
+ * Before this, `patchTaskFile` accepted any `(from, to)` status pair with no
5
+ * rule about which ones make sense — reachable from the task-panel dropdown,
6
+ * board drag-drop, and a direct PATCH, none of which know an agent might be
7
+ * running or a review mid-flight. This module is the single reference for
8
+ * which edges are legitimate and, of those, which are safe to perform as a
9
+ * bare metadata write versus which require a dedicated action endpoint
10
+ * (start/pause/done/abandon/reopen) because they carry real side effects
11
+ * (spawning or stopping an agent, running the close-out pipeline).
12
+ *
13
+ * Twelve edges total. Six are cheap enough (no side effect beyond the write
14
+ * itself, or a side effect — `guardReviewTransition` — that already runs
15
+ * safely inline within a PATCH request) to allow through the generic patch
16
+ * path; those are `GENERIC_PATCH_EDGES` below. The other six — spawning an
17
+ * agent, running the close-out pipeline, stopping a live agent/review, or
18
+ * re-provisioning a deleted worktree — each already have (or, for the two
19
+ * new ones, now have) their own `/api/tasks/:id/<action>` endpoint that
20
+ * performs the effect and writes the status as part of the same request.
21
+ * `GENERIC_PATCH_EDGES` is the enforcement point for the *other* six: they
22
+ * are rejected outright, from every generic-write caller (PATCH, the task
23
+ * drawer's dropdown, board drag-drop), no matter how the request arrives.
24
+ *
25
+ * `reopen` (done -> active in the original design sketch) lands on `ready`
26
+ * instead: the close-out pipeline deletes the task's branch and worktree, so
27
+ * re-provisioning them is exactly what `/start` (ready -> active) already
28
+ * does. Landing reopen on `ready` reuses that machinery instead of
29
+ * duplicating it.
30
+ */
31
+ import type { Status } from "../core/types.js";
32
+ export interface TransitionEdge {
33
+ /** Human-readable one-liner: what happens when this edge fires. */
34
+ effect: string;
35
+ /** Where this edge is actually performed. */
36
+ via: "generic-patch" | "action:start" | "action:done" | "action:pause" | "action:abandon" | "action:reopen" | "automated";
37
+ }
38
+ /** The full 12-edge allow-list. Absence of a `(from, to)` pair here means the
39
+ * transition is rejected, from every caller, with no exceptions. */
40
+ export declare const TRANSITIONS: Partial<Record<Status, Partial<Record<Status, TransitionEdge>>>>;
41
+ /**
42
+ * Whether a bare status write (no accompanying action) from `from` to `to`
43
+ * is allowed. `from === to` is always fine (no-op). Returns a reason and a
44
+ * pointer to the right endpoint when rejected.
45
+ */
46
+ export declare function checkGenericStatusPatch(from: Status, to: Status): {
47
+ ok: true;
48
+ } | {
49
+ ok: false;
50
+ reason: string;
51
+ };