@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,160 @@
1
+ import type { RepoOSConfig, Task } from "../core/types.js";
2
+ export interface CheckSummary {
3
+ ok: boolean;
4
+ /** Failing close-out stage — "build" | "check". */
5
+ stage?: string;
6
+ /** The exact command that failed (argv joined with spaces). */
7
+ command?: string;
8
+ /** Exit status of the failing command (null = killed / never exited). */
9
+ exitCode?: number | null;
10
+ /** Spawn failure code when the command could not start (ENOENT/EACCES). */
11
+ errorCode?: string;
12
+ /** Redacted tail of stdout+stderr (bounded). */
13
+ output?: string;
14
+ /** Human-readable failure detail (redacted, includes command + status). */
15
+ detail?: string;
16
+ /** True when a timeout suggests machine contention, not a test assertion. */
17
+ transient?: boolean;
18
+ }
19
+ export interface CompleteResult {
20
+ ok: boolean;
21
+ /** Whether the branch was merged into main (even when later steps failed). */
22
+ merged: boolean;
23
+ /** True when the branch was already integrated into main before this run. */
24
+ alreadyMerged?: boolean;
25
+ /** Files that conflicted (merge aborted, task still in review). */
26
+ conflicts: string[];
27
+ /** Whether the merge was a fast-forward. */
28
+ ff: boolean;
29
+ /** True when a non-fast-forward/conflicting merge was detected in pre-flight. */
30
+ drifted: boolean;
31
+ /** Post-merge build/check gate (undefined when the merge itself failed). */
32
+ check?: CheckSummary;
33
+ /** The updated task, present when the task reached `done`. */
34
+ task?: Task;
35
+ /** True when the failure is a dirty main that must be committed/stashed first. */
36
+ needsCommit?: boolean;
37
+ /** The uncommitted files on main that blocked the merge, when known. */
38
+ dirtyFiles?: string[];
39
+ /** Human-readable reason (not ok). */
40
+ reason?: string;
41
+ }
42
+ /** The progress steps reported to the UI while the flow runs. */
43
+ export type DoneStep = "sync" | "merge" | "build" | "check" | "done";
44
+ export interface MergeAttempt {
45
+ /** Whether the branch was merged into the main checkout. */
46
+ merged: boolean;
47
+ /** Whether the merge was a fast-forward. */
48
+ ff: boolean;
49
+ /** True when main was not an ancestor of the branch at merge time. */
50
+ drifted: boolean;
51
+ /** Files that conflicted (merge aborted, task still in review). */
52
+ conflicts: string[];
53
+ /** Human-readable failure reason (not merged and not a conflict). */
54
+ reason?: string;
55
+ /** True when an automatic sync-with-main ran before the successful merge. */
56
+ autoSynced?: boolean;
57
+ /**
58
+ * True when the branch was already integrated into main before this run (a
59
+ * retry after an earlier close-out merged it), so the merge step is a no-op.
60
+ */
61
+ alreadyMerged?: boolean;
62
+ }
63
+ /**
64
+ * Merge `branch` into the main checkout, auto-syncing with main on a snag.
65
+ *
66
+ * Runs the existing pre-flight + merge once. If the merge cannot proceed
67
+ * because the branch needs to be synchronized with main (drift or a conflict),
68
+ * it runs the repository's existing sync-with-main operation (`main` merged
69
+ * into the branch's worktree) and retries the merge. A successful sync makes
70
+ * the retry a clean fast-forward, so the close-out completes without a manual
71
+ * "Sync with main" step. Real source conflicts fail the sync too, and the
72
+ * original failure is returned so the user sees exactly which files conflicted.
73
+ * Never merges before the first attempt — automatic sync is the fallback, not
74
+ * the default.
75
+ */
76
+ export declare function mergeTaskBranchWithAutoSync(root: string, branch: string, opts?: {
77
+ autoResolve?: string[];
78
+ }): Promise<MergeAttempt>;
79
+ /** Replace anything that looks like a credential with `***`. */
80
+ export declare function redactSecrets(text: string): string;
81
+ /** Strip ANSI SGR escape sequences so diagnostics stay readable in JSON. */
82
+ export declare function stripAnsi(text: string): string;
83
+ /**
84
+ * The useful part of a failed command's combined output: the LAST meaningful
85
+ * lines (errors print at the tail, so the old first-6-lines slice kept noise
86
+ * and dropped the reason), redacted, ANSI-free, and bounded.
87
+ */
88
+ export declare function captureOutput(stdout: string, stderr: string): string;
89
+ export type CheckStage = "build" | "check";
90
+ export interface RunStepOptions {
91
+ cwd: string;
92
+ candidates: string[][];
93
+ /** Human-readable label used in failure text. */
94
+ label: string;
95
+ /** Stage the failing command belongs to (for diagnostics). */
96
+ stage: CheckStage;
97
+ /** Per-command wall-clock budget before SIGKILL, in ms. */
98
+ timeout?: number;
99
+ /** Child-process environment (defaults to the parent's). */
100
+ env?: NodeJS.ProcessEnv;
101
+ }
102
+ /**
103
+ * Try each candidate command in order until one exits 0. A command that runs
104
+ * and fails (non-zero exit, spawn error other than ENOENT/EACCES) is the
105
+ * authoritative failure: it is reported with the exact command, exit status,
106
+ * and a redacted output tail so the failing stage is diagnosable. Commands
107
+ * that cannot be launched (missing tool) are skipped in favor of the next
108
+ * candidate. Returns `{ ok: true }` on success.
109
+ */
110
+ export declare function runDoneStep(opts: RunStepOptions): Promise<CheckSummary>;
111
+ /**
112
+ * Report the outcome of a close-out check retry honestly (#0216). A retry is
113
+ * only reached when the first run failed with a timeout-shaped signature, but
114
+ * that heuristic is message-based and a genuine assertion failure could match
115
+ * it too — so the retry is never assumed to be contention. The task's own
116
+ * guidance for telling the two apart: a failure that reproduces IDENTICALLY is
117
+ * a real defect, because contention lands on a different test each run. When
118
+ * the retry produces the same output as the first run, say so instead of
119
+ * blaming the machine; only a retry that fails differently supports the
120
+ * contention reading.
121
+ */
122
+ export declare function describeRetryFailure(first: CheckSummary, retry: CheckSummary): CheckSummary;
123
+ /**
124
+ * A timeout means the gate could not obtain enough machine time; it says
125
+ * nothing about the merged branch. Retry that infrastructure failure once,
126
+ * while preserving ordinary non-zero test failures as immediately actionable.
127
+ * Exported for the retry-wiring regression tests.
128
+ */
129
+ export declare function runCloseOutCheck(root: string, env?: NodeJS.ProcessEnv): Promise<CheckSummary>;
130
+ /** Post-merge gate runners, overridable in tests to avoid real builds. */
131
+ export interface CompleteTaskSteps {
132
+ build?: (cwd: string) => Promise<CheckSummary>;
133
+ check?: (cwd: string) => Promise<CheckSummary>;
134
+ }
135
+ /**
136
+ * A server-owned close-out lock (0143). The serve process's ReloadManager
137
+ * reads `closingOut()` and defers every auto-reload while the pipeline runs —
138
+ * a close-out builds/checks dist itself, so an auto-reload mid-flight would
139
+ * kill the very server orchestrating the close-out. `completeTask` acquires
140
+ * the lock for its whole run and always releases it.
141
+ */
142
+ export interface CloseOutLock {
143
+ closingOut: () => boolean;
144
+ acquire: () => void;
145
+ release: () => void;
146
+ }
147
+ /**
148
+ * Not the live close-out path (0187 review — flagged as unlogged; noting why
149
+ * it stays that way rather than adding logging nothing will ever read).
150
+ * `server.ts` imports this but never calls it — since #0118 the merge-queue
151
+ * (`JobCoordinator` + `CloseOutOrchestrator` in integration-orchestrator.ts,
152
+ * which now carries the phase/failure logging) is what actually runs a
153
+ * review->done close-out. This single-shot, run-against-main-directly version
154
+ * predates that and is exercised only by `src/ui-app/tests/done-*.test.ts`.
155
+ * Kept for its helpers (`mergeTaskBranchWithAutoSync`, `runDoneStep`,
156
+ * `redactSecrets`, `stripAnsi` — the last used live by `agents.ts`); consider
157
+ * deleting `completeTask`/`completeTaskLocked` themselves in a follow-up if
158
+ * nothing comes to depend on them.
159
+ */
160
+ export declare function completeTask(config: RepoOSConfig, task: Task, onProgress?: (step: DoneStep) => void, steps?: CompleteTaskSteps, closeOut?: CloseOutLock): Promise<CompleteResult>;
@@ -0,0 +1,488 @@
1
+ /**
2
+ * `POST /api/tasks/:id/done` orchestration — the review -> done close-out.
3
+ *
4
+ * Runs against the MAIN checkout (`config.root`), never the task's worktree:
5
+ * 1. merge the task's branch into main (FF when possible, merge commit
6
+ * otherwise); if the merge hits a synchronization snag (drift/conflict),
7
+ * the branch is automatically synced with main and the merge retried;
8
+ * an unrecoverable conflict is aborted and the task stays review.
9
+ * A retry after the branch was already integrated is detected up front
10
+ * (`alreadyMerged`) so it resumes the remaining steps instead of being
11
+ * mislabelled as a failed merge.
12
+ * 2. rebuild + `repoos check` so the merged main
13
+ * stays green. The check runs the merged checkout's OWN freshly-built
14
+ * CLI (`dist/cli/index.js`) first — a globally linked `repoos` resolves
15
+ * build freshness and gate code against its own install snapshot, which
16
+ * can disagree with the checkout being closed out (#0130). Failure output
17
+ * is preserved with the exact command, exit status, and a redacted tail
18
+ * of stdout/stderr so the failing stage is diagnosable.
19
+ * 3. set status `done`, delete the branch, remove the task's worktree.
20
+ * A failure at any step leaves the task in `review`; if the merge already
21
+ * happened, we report that state honestly and a retry resumes from the failed
22
+ * step rather than treating the branch as a new conflicting merge.
23
+ */
24
+ import { spawn } from "node:child_process";
25
+ import { existsSync } from "node:fs";
26
+ import { join, relative } from "node:path";
27
+ import { mergeBranch, preflightMerge, syncBranchWithMain, deleteBranch, removeWorktree, commitTaskFile, currentBranch, isAncestor, localBranches, runGit, dirtyFiles, GitDirtyCheckError, worktreePathForBranch, } from "../core/git.js";
28
+ import { markTaskReleased } from "./write.js";
29
+ /**
30
+ * Merge `branch` into the main checkout, auto-syncing with main on a snag.
31
+ *
32
+ * Runs the existing pre-flight + merge once. If the merge cannot proceed
33
+ * because the branch needs to be synchronized with main (drift or a conflict),
34
+ * it runs the repository's existing sync-with-main operation (`main` merged
35
+ * into the branch's worktree) and retries the merge. A successful sync makes
36
+ * the retry a clean fast-forward, so the close-out completes without a manual
37
+ * "Sync with main" step. Real source conflicts fail the sync too, and the
38
+ * original failure is returned so the user sees exactly which files conflicted.
39
+ * Never merges before the first attempt — automatic sync is the fallback, not
40
+ * the default.
41
+ */
42
+ export async function mergeTaskBranchWithAutoSync(root, branch, opts = {}) {
43
+ // Already integrated — the idempotent-retry case (#0130). The branch tip is
44
+ // an ancestor of main (an earlier close-out merged it but stranded the task
45
+ // in review on a later gate), so the merge step is a no-op and a retry must
46
+ // resume the remaining steps rather than report a failed merge. When the
47
+ // branch ref is also gone the close-out cleanup already ran (`deleteBranch`
48
+ // refuses unmerged branches, so a missing branch was integrated) and there
49
+ // is nothing left to merge.
50
+ const head = currentBranch(root);
51
+ if (head !== null && head !== branch && isAncestor(root, branch, head) === true) {
52
+ return {
53
+ merged: true,
54
+ ff: true,
55
+ drifted: false,
56
+ conflicts: [],
57
+ alreadyMerged: true,
58
+ };
59
+ }
60
+ if (!localBranches(root).has(branch) && worktreePathForBranch(root, branch) === null) {
61
+ return {
62
+ merged: true,
63
+ ff: true,
64
+ drifted: false,
65
+ conflicts: [],
66
+ alreadyMerged: true,
67
+ };
68
+ }
69
+ const attempt = async () => {
70
+ const preflight = await preflightMerge(root, branch, opts);
71
+ if (!preflight.ok) {
72
+ return {
73
+ merged: false,
74
+ ff: false,
75
+ drifted: preflight.drifted,
76
+ conflicts: preflight.conflicts,
77
+ reason: preflight.reason ?? "merge conflict",
78
+ };
79
+ }
80
+ const merge = await mergeBranch(root, branch, opts);
81
+ return {
82
+ merged: merge.merged,
83
+ ff: merge.ff,
84
+ drifted: preflight.drifted,
85
+ conflicts: merge.conflicts,
86
+ reason: merge.conflicts.length
87
+ ? `merge conflict: ${merge.conflicts.join(", ")}`
88
+ : merge.reason,
89
+ };
90
+ };
91
+ const first = await attempt();
92
+ if (first.merged)
93
+ return first;
94
+ // The merge hit a synchronization-related snag: automatically sync the branch
95
+ // with main, then retry. If the sync itself cannot complete cleanly (real
96
+ // source conflicts), surface the first failure rather than inventing a new
97
+ // error — the user resolves those files in the worktree and retries.
98
+ const sync = await syncBranchWithMain(root, branch, opts);
99
+ if (!sync.ok)
100
+ return first;
101
+ const retry = await attempt();
102
+ if (retry.merged)
103
+ return { ...retry, autoSynced: true };
104
+ return retry;
105
+ }
106
+ /** Non-blocking `spawn`, resolving with exit status + captured output. */
107
+ function runProcess(cmd, args, opts) {
108
+ return new Promise((resolve) => {
109
+ const child = spawn(cmd, args, { cwd: opts.cwd, env: opts.env });
110
+ let stdout = "";
111
+ let stderr = "";
112
+ let timer;
113
+ let settled = false;
114
+ let timedOut = false;
115
+ const finish = (status, error) => {
116
+ if (settled)
117
+ return;
118
+ settled = true;
119
+ if (timer)
120
+ clearTimeout(timer);
121
+ resolve({ status, stdout, stderr, error, timedOut });
122
+ };
123
+ child.stdout.on("data", (d) => (stdout += d.toString("utf8")));
124
+ child.stderr.on("data", (d) => (stderr += d.toString("utf8")));
125
+ child.on("error", (err) => finish(null, err));
126
+ child.on("close", (code) => finish(code));
127
+ timer = setTimeout(() => {
128
+ timedOut = true;
129
+ child.kill("SIGKILL");
130
+ }, opts.timeout);
131
+ });
132
+ }
133
+ /** Token shapes that must never surface in close-out diagnostics. */
134
+ const SECRET_PATTERNS = [
135
+ /github_pat_[A-Za-z0-9_]+/g,
136
+ /gh[pousr]_[A-Za-z0-9]+/g,
137
+ /\bsk-[A-Za-z0-9_-]+/g,
138
+ /xox[baprs]-[A-Za-z0-9-]+/g,
139
+ /\bAKIA[0-9A-Z]{16}\b/g,
140
+ /\bBearer\s+[A-Za-z0-9._~+/=-]+/gi,
141
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----/g,
142
+ ];
143
+ /** Replace anything that looks like a credential with `***`. */
144
+ export function redactSecrets(text) {
145
+ let out = text;
146
+ for (const re of SECRET_PATTERNS)
147
+ out = out.replace(re, "***");
148
+ return out;
149
+ }
150
+ /** Strip ANSI SGR escape sequences so diagnostics stay readable in JSON. */
151
+ export function stripAnsi(text) {
152
+ // eslint-disable-next-line no-control-regex
153
+ return text.replace(/\u001b\[[0-9;]*m/g, "");
154
+ }
155
+ const MAX_OUTPUT_CHARS = 4000;
156
+ const MAX_OUTPUT_LINES = 40;
157
+ /**
158
+ * The useful part of a failed command's combined output: the LAST meaningful
159
+ * lines (errors print at the tail, so the old first-6-lines slice kept noise
160
+ * and dropped the reason), redacted, ANSI-free, and bounded.
161
+ */
162
+ export function captureOutput(stdout, stderr) {
163
+ const combined = redactSecrets(stripAnsi([stdout, stderr].join("\n")));
164
+ const lines = combined
165
+ .split("\n")
166
+ .map((l) => l.trim())
167
+ .filter(Boolean);
168
+ const tail = lines.slice(-MAX_OUTPUT_LINES).join("\n");
169
+ return tail.length > MAX_OUTPUT_CHARS ? tail.slice(-MAX_OUTPUT_CHARS) : tail;
170
+ }
171
+ /** Quote argv so a path with spaces stays a single command token. */
172
+ function fmtCommand(argv) {
173
+ return argv.map((a) => (/\s/.test(a) ? JSON.stringify(a) : a)).join(" ");
174
+ }
175
+ /**
176
+ * Try each candidate command in order until one exits 0. A command that runs
177
+ * and fails (non-zero exit, spawn error other than ENOENT/EACCES) is the
178
+ * authoritative failure: it is reported with the exact command, exit status,
179
+ * and a redacted output tail so the failing stage is diagnosable. Commands
180
+ * that cannot be launched (missing tool) are skipped in favor of the next
181
+ * candidate. Returns `{ ok: true }` on success.
182
+ */
183
+ export async function runDoneStep(opts) {
184
+ const timeout = opts.timeout ?? 240_000;
185
+ let missing = "";
186
+ for (const cmd of opts.candidates) {
187
+ const run = await runProcess(cmd[0], cmd.slice(1), {
188
+ cwd: opts.cwd,
189
+ timeout,
190
+ env: opts.env,
191
+ });
192
+ if (run.status === 0)
193
+ return { ok: true, stage: opts.stage };
194
+ if (run.error && (run.error.code === "ENOENT" || run.error.code === "EACCES")) {
195
+ missing = `${cmd[0]} is not available`;
196
+ continue;
197
+ }
198
+ const command = fmtCommand(cmd);
199
+ const statusText = run.timedOut
200
+ ? `timed out after ${Math.round(timeout / 1000)}s (killed)`
201
+ : run.error
202
+ ? `could not start (${run.error.code ?? run.error.message})`
203
+ : `exit ${run.status}`;
204
+ const output = captureOutput(run.stdout, run.stderr);
205
+ const short = output.slice(0, 500).replace(/\s+/g, " ").trim();
206
+ // Vitest reports a contention-induced polling deadline as a normal
207
+ // non-zero test result, not as a timeout of this outer subprocess. Treat
208
+ // that narrow shape like a process deadline: retry once, but do not hide
209
+ // assertion failures or other real regressions behind a retry.
210
+ const transient = run.timedOut ||
211
+ (opts.stage === "check" &&
212
+ /(?:timed out waiting for|test timed out|worker .*?(?:timeout|exited))/i.test(output));
213
+ return {
214
+ ok: false,
215
+ stage: opts.stage,
216
+ command,
217
+ exitCode: run.status,
218
+ errorCode: run.error?.code,
219
+ output,
220
+ detail: `${opts.label} failed (${statusText}) — ${command}${short ? ` — ${short}` : ""}`,
221
+ transient,
222
+ };
223
+ }
224
+ return { ok: false, stage: opts.stage, detail: missing || `\`${opts.label}\` could not be run` };
225
+ }
226
+ const BUILD_STEPS = [
227
+ ["bun", "run", "build"],
228
+ ["npm", "run", "build"],
229
+ ];
230
+ /**
231
+ * Commit regenerated `dist/` — the post-merge build just rewrote it — so main
232
+ * stays clean and mergeable. Nothing else generated is tracked: screenshots
233
+ * are regenerated on demand via `repoos screenshots`, never by the close-out.
234
+ */
235
+ async function commitGenerated(root) {
236
+ await runProcess("git", ["add", "-A", "--", "dist"], { cwd: root, timeout: 4000 });
237
+ // `--only` scopes the commit to dist: a plain commit would take the whole
238
+ // index and sweep in any unrelated work staged in main (#0353). When dist is
239
+ // gitignored (as here) nothing is staged and git fails the commit harmlessly.
240
+ await runProcess("git", ["commit", "-o", "-m", "chore: regenerate dist", "--", "dist"], {
241
+ cwd: root,
242
+ timeout: 4000,
243
+ });
244
+ }
245
+ /**
246
+ * The commands that run the post-merge gate, in preference order. The merged
247
+ * checkout's OWN freshly-built CLI comes first: a globally linked `repoos`
248
+ * resolves build freshness and runs gate code against its own install snapshot
249
+ * (in this self-hosted repo the global install is the main checkout's dist),
250
+ * which can disagree with the checkout being closed out — running `check` from
251
+ * the merged `dist/cli/index.js` guarantees the gate evaluates the merged code
252
+ * with the merged gate logic (#0130).
253
+ */
254
+ function checkCandidates(root) {
255
+ const localCli = join(root, "dist", "cli", "index.js");
256
+ const list = [];
257
+ if (existsSync(localCli)) {
258
+ list.push([process.execPath, localCli, "check"]);
259
+ }
260
+ list.push(["repoos", "check"], ["bun", "run", "repoos", "check"]);
261
+ return list;
262
+ }
263
+ /**
264
+ * Report the outcome of a close-out check retry honestly (#0216). A retry is
265
+ * only reached when the first run failed with a timeout-shaped signature, but
266
+ * that heuristic is message-based and a genuine assertion failure could match
267
+ * it too — so the retry is never assumed to be contention. The task's own
268
+ * guidance for telling the two apart: a failure that reproduces IDENTICALLY is
269
+ * a real defect, because contention lands on a different test each run. When
270
+ * the retry produces the same output as the first run, say so instead of
271
+ * blaming the machine; only a retry that fails differently supports the
272
+ * contention reading.
273
+ */
274
+ export function describeRetryFailure(first, retry) {
275
+ if (retry.ok || !retry.transient)
276
+ return retry;
277
+ const reproduced = first.output !== undefined && first.output === retry.output;
278
+ retry.detail = `${retry.detail ?? "repoos check failed"} — ${reproduced
279
+ ? "the same failure appeared on the retry with identical output. Identical reproduction points at a genuine defect, not machine contention"
280
+ : first.output === undefined || retry.output === undefined
281
+ ? "the failure reappeared on the retry, but it could not be compared against the first run"
282
+ : "the retry failed on different output than the first run; the machine may be too loaded to run the gate reliably"}`;
283
+ return retry;
284
+ }
285
+ /**
286
+ * A timeout means the gate could not obtain enough machine time; it says
287
+ * nothing about the merged branch. Retry that infrastructure failure once,
288
+ * while preserving ordinary non-zero test failures as immediately actionable.
289
+ * Exported for the retry-wiring regression tests.
290
+ */
291
+ export async function runCloseOutCheck(root, env) {
292
+ const first = await runDoneStep({
293
+ cwd: root,
294
+ candidates: checkCandidates(root),
295
+ label: "repoos check",
296
+ stage: "check",
297
+ timeout: 600_000,
298
+ env,
299
+ });
300
+ if (!first.transient)
301
+ return first;
302
+ const retry = await runDoneStep({
303
+ cwd: root,
304
+ candidates: checkCandidates(root),
305
+ label: "repoos check (retry after timeout)",
306
+ stage: "check",
307
+ timeout: 600_000,
308
+ env,
309
+ });
310
+ return describeRetryFailure(first, retry);
311
+ }
312
+ /**
313
+ * Not the live close-out path (0187 review — flagged as unlogged; noting why
314
+ * it stays that way rather than adding logging nothing will ever read).
315
+ * `server.ts` imports this but never calls it — since #0118 the merge-queue
316
+ * (`JobCoordinator` + `CloseOutOrchestrator` in integration-orchestrator.ts,
317
+ * which now carries the phase/failure logging) is what actually runs a
318
+ * review->done close-out. This single-shot, run-against-main-directly version
319
+ * predates that and is exercised only by `src/ui-app/tests/done-*.test.ts`.
320
+ * Kept for its helpers (`mergeTaskBranchWithAutoSync`, `runDoneStep`,
321
+ * `redactSecrets`, `stripAnsi` — the last used live by `agents.ts`); consider
322
+ * deleting `completeTask`/`completeTaskLocked` themselves in a follow-up if
323
+ * nothing comes to depend on them.
324
+ */
325
+ export async function completeTask(config, task, onProgress, steps = {}, closeOut) {
326
+ closeOut?.acquire();
327
+ try {
328
+ return await completeTaskLocked(config, task, onProgress, steps);
329
+ }
330
+ finally {
331
+ closeOut?.release();
332
+ }
333
+ }
334
+ async function completeTaskLocked(config, task, onProgress, steps = {}) {
335
+ const root = config.root;
336
+ onProgress?.("merge");
337
+ // Ensure the task file is committed in main before merging: API-created tasks
338
+ // are untracked in main, and the agent's main-copy sync leaves uncommitted
339
+ // edits — either would abort `git merge`. The branch's version of the task
340
+ // file is authoritative for the final state, so if it is the only conflicted
341
+ // path the merge resolves it automatically.
342
+ commitTaskFile(root, task.absPath, `docs(${task.id}): update task`);
343
+ const rel = relative(root, task.absPath);
344
+ // Drop `dist/` and `screenshots/` from the branch before merging so hashed
345
+ // Vite asset filenames and binary PNGs don't cause artificial conflicts.
346
+ // Both are regenerated from source on main right after the merge anyway.
347
+ const wt = worktreePathForBranch(root, task.branch);
348
+ if (wt !== null && !task.hotfix) {
349
+ const r1 = await runGit(wt, ["ls-files", "dist/", "screenshots/"], 5000);
350
+ if (r1.status === 0 && r1.stdout.trim().length > 0) {
351
+ await runGit(wt, ["rm", "-r", "--cached", "--", "dist/", "screenshots/"], 15_000);
352
+ await runGit(wt, ["commit", "-m", "chore: drop dist and screenshots before merge"], 15_000);
353
+ }
354
+ }
355
+ const autoResolve = [rel, "dist/", "screenshots/"];
356
+ // Direct-to-main hotfix: the work was done on main itself; skip the merge.
357
+ const isMainHotfix = task.hotfix && task.hotfixTarget === "main";
358
+ // Publish-time dirty-main guard (#0211): the main tree can be dirtied
359
+ // between the enqueue-time check and this publish step (validation takes
360
+ // minutes and `repoos check`/builds regenerate `dist/`). Re-check right
361
+ // before the merge so a dirty main is surfaced as an actionable error
362
+ // instead of git's raw "your local changes would be overwritten" message at
363
+ // the tail of a long job. Fails closed: an error/timeout in the check is
364
+ // "unknown", not "clean", and aborts the close-out rather than risking a
365
+ // merge git will refuse.
366
+ let publishDirty;
367
+ try {
368
+ publishDirty = await dirtyFiles(root);
369
+ }
370
+ catch (err) {
371
+ if (err instanceof GitDirtyCheckError) {
372
+ return {
373
+ ok: false,
374
+ merged: false,
375
+ conflicts: [],
376
+ ff: false,
377
+ drifted: false,
378
+ needsCommit: true,
379
+ reason: `could not verify main is clean at publish time (${err.message}). The close-out was NOT merged; retry, or commit/stash main's working tree first.`,
380
+ };
381
+ }
382
+ throw err;
383
+ }
384
+ if (publishDirty.length > 0) {
385
+ return {
386
+ ok: false,
387
+ merged: false,
388
+ conflicts: [],
389
+ ff: false,
390
+ drifted: false,
391
+ needsCommit: true,
392
+ dirtyFiles: publishDirty,
393
+ reason: `main has ${publishDirty.length} uncommitted file${publishDirty.length === 1 ? "" : "s"} at publish time, so the merge would abort: ${publishDirty.slice(0, 8).join(", ")}${publishDirty.length > 8 ? ", …" : ""}. The close-out was NOT merged; commit or stash those on main (or use "Commit & continue") and retry.`,
394
+ };
395
+ }
396
+ let merge;
397
+ if (isMainHotfix) {
398
+ merge = { merged: true, ff: true, drifted: false, conflicts: [] };
399
+ }
400
+ else {
401
+ // Cheap pre-flight: detect source-file conflicts before the expensive
402
+ // build/check steps run. Never leaves a half-applied merge.
403
+ // When the merge cannot proceed because the branch needs to be synchronized
404
+ // with main, `mergeTaskBranchWithAutoSync` runs the existing sync-with-main
405
+ // operation and retries, so the close-out completes without a manual step.
406
+ // A retry where the branch was already integrated is detected up front and
407
+ // reported as `alreadyMerged`, resuming from the remaining steps.
408
+ merge = await mergeTaskBranchWithAutoSync(root, task.branch, { autoResolve });
409
+ }
410
+ if (!merge.merged) {
411
+ return {
412
+ ok: false,
413
+ merged: false,
414
+ alreadyMerged: merge.alreadyMerged,
415
+ conflicts: merge.conflicts,
416
+ ff: false,
417
+ drifted: merge.drifted,
418
+ reason: merge.reason ?? "merge failed",
419
+ };
420
+ }
421
+ onProgress?.("build");
422
+ const build = steps.build
423
+ ? await steps.build(root)
424
+ : await runDoneStep({
425
+ cwd: root,
426
+ candidates: BUILD_STEPS,
427
+ label: "bun run build",
428
+ stage: "build",
429
+ timeout: 300_000,
430
+ });
431
+ if (!build.ok) {
432
+ return {
433
+ ok: false,
434
+ merged: true,
435
+ alreadyMerged: merge.alreadyMerged,
436
+ conflicts: [],
437
+ ff: merge.ff,
438
+ drifted: merge.drifted,
439
+ check: build,
440
+ reason: `build failed after merge (${build.exitCode ?? build.errorCode ?? "killed"}) — the branch IS merged into main; retrying resumes from the build step. Task kept in review.`,
441
+ };
442
+ }
443
+ await commitGenerated(root);
444
+ onProgress?.("check");
445
+ // The close-out already ran a full build above (`BUILD_STEPS`), and
446
+ // `bun run build` is staleness-aware now (#0377), so `repoos check`'s own
447
+ // "Full build" step detects the fresh marker and skips itself — no private
448
+ // skip env flag needed (that plumbing was removed with #0377).
449
+ const check = steps.check ? await steps.check(root) : await runCloseOutCheck(root);
450
+ if (!check.ok) {
451
+ return {
452
+ ok: false,
453
+ merged: true,
454
+ alreadyMerged: merge.alreadyMerged,
455
+ conflicts: [],
456
+ ff: merge.ff,
457
+ drifted: merge.drifted,
458
+ check,
459
+ reason: `repoos check failed after merge (${check.exitCode ?? check.errorCode ?? "killed"}) — the branch IS merged into main; retrying resumes from the check step. Task kept in review.`,
460
+ };
461
+ }
462
+ onProgress?.("done");
463
+ const updated = markTaskReleased(config, task.absPath);
464
+ // Best-effort cleanup; content is preserved in the merged main. The worktree
465
+ // must go first — git refuses to delete a branch checked out in a worktree.
466
+ // Both are fail-soft, so an already-cleaned retry is a no-op here.
467
+ // Hotfix tasks: never delete a worktree that doesn't exist, and never delete
468
+ // main. For branch-mode hotfixes, switch back to main after closing.
469
+ if (!task.hotfix) {
470
+ removeWorktree(root, task.branch);
471
+ deleteBranch(root, task.branch);
472
+ }
473
+ else {
474
+ if (task.hotfixTarget !== "main" && task.branch) {
475
+ deleteBranch(root, task.branch);
476
+ }
477
+ }
478
+ return {
479
+ ok: true,
480
+ merged: true,
481
+ alreadyMerged: merge.alreadyMerged,
482
+ conflicts: [],
483
+ ff: merge.ff,
484
+ drifted: merge.drifted,
485
+ check: { ok: true },
486
+ task: updated,
487
+ };
488
+ }