specrails-desktop 2.36.0 → 2.42.2

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 (510) hide show
  1. package/README.md +94 -247
  2. package/client/dist/assets/ActivityFeedPage-DoEMumQS.js +1 -0
  3. package/client/dist/assets/AgentBrowserCapture-DIh4K0gh.js +1 -0
  4. package/client/dist/assets/AgentModeAnalyticsPane-mbq4WEoO.js +2 -0
  5. package/client/dist/assets/AgentModeCodePane-CKh7zuA4.js +2 -0
  6. package/client/dist/assets/AgentModeJobsPane-BDokPiLJ.js +1 -0
  7. package/client/dist/assets/AgentsPage-BFVAZbBj.js +87 -0
  8. package/client/dist/assets/AnalyticsPage-3Y9LuWwz.js +1 -0
  9. package/client/dist/assets/CodePage-C9KyuV_C.js +3 -0
  10. package/client/dist/assets/DesktopAnalyticsPage-Bhi54bXQ.js +1 -0
  11. package/client/dist/assets/{DocsDialog-C76VdBJC.js → DocsDialog-Dj6mt4ga.js} +2 -2
  12. package/client/dist/assets/{DocsPage-ziMlj6B6.js → DocsPage-24yWglNI.js} +1 -1
  13. package/client/dist/assets/ExportDropdown-ophapHrT.js +1 -0
  14. package/client/dist/assets/InteractiveJobComposer-C1ucmxQh.js +19 -0
  15. package/client/dist/assets/JobDetailModal-DNWmgVHD.js +1 -0
  16. package/client/dist/assets/JobDetailPage-BcajZyuu.js +1 -0
  17. package/client/dist/assets/JobsPage-B9nTZw6e.js +1 -0
  18. package/client/dist/assets/LoopBuilderPage-Oc48iOFW.js +7 -0
  19. package/client/dist/assets/LoopPreviewModal-ae0Fr6SU.js +1 -0
  20. package/client/dist/assets/LoopsPage-CUEqzUBI.js +1 -0
  21. package/client/dist/assets/MinimizedChatsContext-Deg39peL.js +1 -0
  22. package/client/dist/assets/PluginsPage-C1xtARIx.js +2 -0
  23. package/client/dist/assets/ProjectSettingsDialog-JZzrXFBN.js +1 -0
  24. package/client/dist/assets/RepositoryDeliveries-CSDsiVUz.js +5 -0
  25. package/client/dist/assets/RepositoryScopeSelector-D-RCaknl.js +1 -0
  26. package/client/dist/assets/ReviewPacketPage-x5EfGTiL.js +1 -0
  27. package/client/dist/assets/TemplatePreviewModal-BSyuZxGq.js +1 -0
  28. package/client/dist/assets/TicketDetailModalContext-DqyF0so-.js +14 -0
  29. package/client/dist/assets/Trans-SnMX4MhW.js +1 -0
  30. package/client/dist/assets/agent-BdT0SB1D.js +1 -0
  31. package/client/dist/assets/agent-Bh9K7iEt.js +1 -0
  32. package/client/dist/assets/agent-C4ibdFk9.js +1 -0
  33. package/client/dist/assets/agent-CSFY22Zo.js +1 -0
  34. package/client/dist/assets/agent-DAnqxUn8.js +1 -0
  35. package/client/dist/assets/agent-DTQiu0Mi.js +1 -0
  36. package/client/dist/assets/agent-T54WuR_Y.js +1 -0
  37. package/client/dist/assets/agent-i75WDZOA.js +1 -0
  38. package/client/dist/assets/browser-05vRDg_y.js +1 -0
  39. package/client/dist/assets/browser-Bulb-cB1.js +1 -0
  40. package/client/dist/assets/browser-C7f-Jsg1.js +1 -0
  41. package/client/dist/assets/browser-CG0PE1j_.js +1 -0
  42. package/client/dist/assets/browser-CMzaqAjo.js +1 -0
  43. package/client/dist/assets/browser-DMajYdNX.js +1 -0
  44. package/client/dist/assets/browser-DxcOHrdP.js +1 -0
  45. package/client/dist/assets/browser-ObE7xVo3.js +1 -0
  46. package/client/dist/assets/builder-765NeYTp.js +1 -0
  47. package/client/dist/assets/builder-8MG3V6ea.js +1 -0
  48. package/client/dist/assets/builder-B-1UBs5K.js +1 -0
  49. package/client/dist/assets/builder-BTiGnPT0.js +1 -0
  50. package/client/dist/assets/builder-Cx9Rz-7u.js +1 -0
  51. package/client/dist/assets/builder-DKFMELBl.js +1 -0
  52. package/client/dist/assets/builder-OcmKrC0h.js +1 -0
  53. package/client/dist/assets/builder-P9qVBXFZ.js +1 -0
  54. package/client/dist/assets/{button-CJqFnUOL.js → button-DCBqEaZl.js} +1 -1
  55. package/client/dist/assets/{code-CkUuW4m9.js → code-B37GRg9C.js} +1 -1
  56. package/client/dist/assets/{code-B0O8-p8k.js → code-BBOEZbf9.js} +1 -1
  57. package/client/dist/assets/{code-B1VLZDhS.js → code-BRm-jcyx.js} +1 -1
  58. package/client/dist/assets/{code-Bpj4Ddml.js → code-CF7w62CR.js} +1 -1
  59. package/client/dist/assets/{code-BykBZ5-e.js → code-CLuvJt2r.js} +1 -1
  60. package/client/dist/assets/{code-B86IMAfz.js → code-D0RCm59f.js} +1 -1
  61. package/client/dist/assets/code-DaZ-ZwCT.js +1 -0
  62. package/client/dist/assets/{code-cAqaqMTx.js → code-iIHkGaCL.js} +1 -1
  63. package/client/dist/assets/commands-0XjAftla.js +1 -0
  64. package/client/dist/assets/commands-BAWSYHjQ.js +1 -0
  65. package/client/dist/assets/commands-BBwowgiE.js +1 -0
  66. package/client/dist/assets/commands-BacjIZLN.js +1 -0
  67. package/client/dist/assets/commands-Bs62IAZ3.js +1 -0
  68. package/client/dist/assets/commands-CLPdh-Hh.js +1 -0
  69. package/client/dist/assets/commands-DlbFzgrp.js +1 -0
  70. package/client/dist/assets/commands-LjPSsi5F.js +1 -0
  71. package/client/dist/assets/common-B5AZNYMH.js +1 -0
  72. package/client/dist/assets/common-BFZ0c_vN.js +1 -0
  73. package/client/dist/assets/common-BrlwEnL7.js +1 -0
  74. package/client/dist/assets/common-BttQx3z4.js +1 -0
  75. package/client/dist/assets/common-CM65k_-e.js +1 -0
  76. package/client/dist/assets/common-D4mvFFlu.js +1 -0
  77. package/client/dist/assets/common-TZ9Ny96S.js +1 -0
  78. package/client/dist/assets/common-nFpSF4GC.js +1 -0
  79. package/client/dist/assets/dashboard-B14uYXkG.js +1 -0
  80. package/client/dist/assets/dashboard-BK_mez-z.js +1 -0
  81. package/client/dist/assets/dashboard-BfBir_6o.js +1 -0
  82. package/client/dist/assets/dashboard-Bt0cCzeG.js +1 -0
  83. package/client/dist/assets/dashboard-BwkjxI6H.js +1 -0
  84. package/client/dist/assets/{dashboard-C8WOEiPu.js → dashboard-C3bDKf7s.js} +1 -1
  85. package/client/dist/assets/dashboard-CdvjGfog.js +1 -0
  86. package/client/dist/assets/dashboard-fRrP0Kv0.js +1 -0
  87. package/client/dist/assets/dialog-SRw01_QU.js +45 -0
  88. package/client/dist/assets/dist-js-CJ_2XX1Y.js +1 -0
  89. package/client/dist/assets/formatDistanceToNow-DSj5DprF.js +1 -0
  90. package/client/dist/assets/getTimezoneOffsetInMilliseconds-YhD8rIEs.js +1 -0
  91. package/client/dist/assets/index-DwAmL7m5.css +2 -0
  92. package/client/dist/assets/index-EzrkUb8B.js +76 -0
  93. package/client/dist/assets/{jira-api-B1-MUehg.js → jira-api-CSCqGr-Q.js} +1 -1
  94. package/client/dist/assets/{jobs-CN_zv4Gr.js → jobs-B8rrzfyZ.js} +1 -1
  95. package/client/dist/assets/{jobs-DUlWSYq2.js → jobs-BS6RTurf.js} +1 -1
  96. package/client/dist/assets/{jobs-Bpks6doU.js → jobs-BTT0Bsks.js} +1 -1
  97. package/client/dist/assets/{jobs-Bgq-PZkC.js → jobs-CezU69AE.js} +1 -1
  98. package/client/dist/assets/{jobs-SwYS2M-B.js → jobs-ClFJae0s.js} +1 -1
  99. package/client/dist/assets/{jobs-BAls3bWq.js → jobs-DJSFIFVy.js} +1 -1
  100. package/client/dist/assets/{jobs-DhxKgWFq.js → jobs-DhgGr8vm.js} +1 -1
  101. package/client/dist/assets/{jobs-B_TeSQxb.js → jobs-DzMjUcaN.js} +1 -1
  102. package/client/dist/assets/mcp-6rMoZfEO.js +1 -0
  103. package/client/dist/assets/mcp-BD8sL5mP.js +1 -0
  104. package/client/dist/assets/mcp-BkcA3I5s.js +1 -0
  105. package/client/dist/assets/mcp-CCpSelOh.js +1 -0
  106. package/client/dist/assets/mcp-CUAN6ORK.js +1 -0
  107. package/client/dist/assets/mcp-CqbRxRTE.js +1 -0
  108. package/client/dist/assets/mcp-DP2YfVhO.js +1 -0
  109. package/client/dist/assets/mcp-DUVQamDz.js +1 -0
  110. package/client/dist/assets/narration-B-ynWTpn.js +1 -0
  111. package/client/dist/assets/narration-Bj_laZwg.js +1 -0
  112. package/client/dist/assets/narration-BxHpmMv_.js +1 -0
  113. package/client/dist/assets/narration-C1Px0-0j.js +1 -0
  114. package/client/dist/assets/narration-CAXhGbzM.js +1 -0
  115. package/client/dist/assets/narration-DQ1l_Kq6.js +1 -0
  116. package/client/dist/assets/narration-XISXwqZd.js +1 -0
  117. package/client/dist/assets/narration-kwzfglQo.js +1 -0
  118. package/client/dist/assets/nav-1-Hh2kOz.js +1 -0
  119. package/client/dist/assets/nav-B34QkESm.js +1 -0
  120. package/client/dist/assets/nav-Bap_UXAq.js +1 -0
  121. package/client/dist/assets/{nav-pYuXq7sf.js → nav-BwxXIB24.js} +1 -1
  122. package/client/dist/assets/nav-Ch-zHBG5.js +1 -0
  123. package/client/dist/assets/nav-CygC_WN-.js +1 -0
  124. package/client/dist/assets/{nav-iwjCg5FR.js → nav-KnnLQtOQ.js} +1 -1
  125. package/client/dist/assets/nav-m00uxYUG.js +1 -0
  126. package/client/dist/assets/packet-BQ2tXfJI.js +1 -0
  127. package/client/dist/assets/packet-BdpOJ1Cy.js +1 -0
  128. package/client/dist/assets/packet-C3Ievb9R.js +1 -0
  129. package/client/dist/assets/packet-C4zJIG0Y.js +1 -0
  130. package/client/dist/assets/packet-Cx-zRuWn.js +1 -0
  131. package/client/dist/assets/packet-DUTGX52M.js +1 -0
  132. package/client/dist/assets/packet-DhsKtUPB.js +1 -0
  133. package/client/dist/assets/packet-z3LJ8Zyy.js +1 -0
  134. package/client/dist/assets/project-repositories-DYhTvwQ1.js +1 -0
  135. package/client/dist/assets/provider-capabilities-B-wOHfLP.js +1 -0
  136. package/client/dist/assets/settings-BBt2xtDQ.js +1 -0
  137. package/client/dist/assets/settings-BJB9RKJj.js +1 -0
  138. package/client/dist/assets/settings-CHwQR2rB.js +1 -0
  139. package/client/dist/assets/settings-CrMi3kSi.js +1 -0
  140. package/client/dist/assets/settings-DKyhDGD1.js +1 -0
  141. package/client/dist/assets/settings-Deupji9c.js +1 -0
  142. package/client/dist/assets/settings-DqRMmwAM.js +1 -0
  143. package/client/dist/assets/settings-J4rj6vo-.js +1 -0
  144. package/client/dist/assets/setup-2xGgu4Sk.js +1 -0
  145. package/client/dist/assets/setup-Ba11l2JA.js +1 -0
  146. package/client/dist/assets/setup-BzW4kMok.js +1 -0
  147. package/client/dist/assets/setup-COzwYhkJ.js +1 -0
  148. package/client/dist/assets/setup-CRVULhtF.js +1 -0
  149. package/client/dist/assets/setup-DgvlxwpE.js +1 -0
  150. package/client/dist/assets/setup-Dw_wYeEY.js +1 -0
  151. package/client/dist/assets/setup-ZPtEeJPW.js +1 -0
  152. package/client/dist/assets/spending-BqbdPm_4.js +1 -0
  153. package/client/dist/assets/square-Ci-PFcFe.js +1 -0
  154. package/client/dist/assets/{terminal-BFRZnMPP.js → terminal-BAzpHtpY.js} +1 -1
  155. package/client/dist/assets/{terminal-IahE4LW9.js → terminal-C7dHeR3x.js} +1 -1
  156. package/client/dist/assets/{terminal-tITa81iz.js → terminal-CMla5Qsz.js} +1 -1
  157. package/client/dist/assets/{terminal-BZiIu3rf.js → terminal-CdNXH-n9.js} +1 -1
  158. package/client/dist/assets/{terminal-ScjyXNxQ.js → terminal-Cw5bZsmV.js} +1 -1
  159. package/client/dist/assets/{terminal-C2NAd7BW.js → terminal-DFUP4eNv.js} +1 -1
  160. package/client/dist/assets/{terminal-d7GadXbN.js → terminal-DGqljeK_.js} +1 -1
  161. package/client/dist/assets/{terminal-QpXZU2Bn.js → terminal-cU70NodO.js} +1 -1
  162. package/client/dist/assets/useDesktop-RSMTyy7V.js +1 -0
  163. package/client/dist/assets/useSharedWebSocket-BOdS5_Iz.js +2 -0
  164. package/client/dist/index.html +34 -35
  165. package/docs/README.md +3 -0
  166. package/docs/agent-live-steering.md +57 -0
  167. package/docs/ci-cd.md +57 -0
  168. package/docs/code-explorer.md +48 -0
  169. package/docs/codex.md +12 -1
  170. package/docs/features/detachable-mission-windows.md +59 -0
  171. package/docs/guide/de/integrations/5-mcp-server.md +13 -9
  172. package/docs/guide/de/integrations/6-agent-chat.md +1 -0
  173. package/docs/guide/en/integrations/5-mcp-server.md +13 -9
  174. package/docs/guide/en/integrations/6-agent-chat.md +1 -0
  175. package/docs/guide/es/integrations/5-mcp-server.md +13 -9
  176. package/docs/guide/es/integrations/6-agent-chat.md +1 -0
  177. package/docs/guide/fr/integrations/5-mcp-server.md +13 -9
  178. package/docs/guide/fr/integrations/6-agent-chat.md +1 -0
  179. package/docs/guide/it/integrations/5-mcp-server.md +13 -9
  180. package/docs/guide/it/integrations/6-agent-chat.md +1 -0
  181. package/docs/guide/ja/integrations/5-mcp-server.md +13 -9
  182. package/docs/guide/ja/integrations/6-agent-chat.md +1 -0
  183. package/docs/guide/pt/integrations/5-mcp-server.md +13 -9
  184. package/docs/guide/pt/integrations/6-agent-chat.md +1 -0
  185. package/docs/guide/zh/integrations/5-mcp-server.md +13 -9
  186. package/docs/guide/zh/integrations/6-agent-chat.md +1 -0
  187. package/docs/internals/README.md +1 -0
  188. package/docs/internals/browser-capture-performance.md +55 -3
  189. package/docs/internals/browser-login-popups.md +45 -0
  190. package/docs/internals/browser-native-retina-audit.md +39 -0
  191. package/docs/internals/ci-cd-audit.md +39 -0
  192. package/docs/internals/core-runtime-updates.md +68 -0
  193. package/docs/internals/embedded-browser-native-webview-evaluation.md +2 -0
  194. package/docs/internals/implementation-reliability-audit.md +93 -0
  195. package/docs/internals/interactive-jobs.md +110 -6
  196. package/docs/internals/mcp-mission-audit.md +76 -0
  197. package/docs/internals/project-builder.md +404 -42
  198. package/docs/internals/safe-pr-review-flow.md +52 -10
  199. package/docs/internals/startup-recovery-audit.md +58 -0
  200. package/docs/mcp.md +74 -41
  201. package/docs/mission-processes.md +59 -0
  202. package/docs/multi-repo-projects.md +51 -0
  203. package/docs/platforms/windows-parity.md +70 -0
  204. package/docs/platforms/windows.md +13 -11
  205. package/docs/running-pipelines.md +14 -0
  206. package/mcp-bridge/dist/specrails-mcp.js +7186 -0
  207. package/package.json +9 -4
  208. package/server/dist/agent-chat-manager.js +537 -68
  209. package/server/dist/agent-chat-router.js +87 -6
  210. package/server/dist/agent-context-resolver.js +129 -25
  211. package/server/dist/agent-defaults.js +19 -11
  212. package/server/dist/agent-input-store.js +206 -0
  213. package/server/dist/agent-mcp-config.js +54 -15
  214. package/server/dist/agent-operator-prompt.js +255 -65
  215. package/server/dist/agent-spec-framing.js +202 -0
  216. package/server/dist/agent-steering.js +218 -0
  217. package/server/dist/agent-store.js +153 -0
  218. package/server/dist/api-not-found.js +8 -0
  219. package/server/dist/background-process-control.js +164 -0
  220. package/server/dist/background-process-service.js +61 -0
  221. package/server/dist/background-process-store.js +242 -0
  222. package/server/dist/background-windows-bootstrap.js +238 -0
  223. package/server/dist/blueprint-chat-manager.js +476 -62
  224. package/server/dist/blueprint-commit.js +21 -1
  225. package/server/dist/blueprint-draft-parser.js +122 -17
  226. package/server/dist/blueprint-generation.js +238 -0
  227. package/server/dist/blueprint-operator-prompt.js +91 -63
  228. package/server/dist/blueprint-router.js +55 -3
  229. package/server/dist/blueprint-spec-fixtures.js +85 -0
  230. package/server/dist/blueprint-spec-quality.js +57 -16
  231. package/server/dist/blueprint-store.js +92 -1
  232. package/server/dist/browser-capture-manager.js +86 -30
  233. package/server/dist/browser-playwright.js +168 -45
  234. package/server/dist/browser-viewport.js +26 -0
  235. package/server/dist/chat-manager.js +23 -15
  236. package/server/dist/chromium-archive.cjs +83 -0
  237. package/server/dist/chromium-resolver.js +72 -64
  238. package/server/dist/code-activity.js +145 -0
  239. package/server/dist/code-explorer-router.js +714 -114
  240. package/server/dist/core-compat.js +28 -1
  241. package/server/dist/core-execution.js +111 -0
  242. package/server/dist/core-package.js +4 -16
  243. package/server/dist/core-runtime.js +202 -0
  244. package/server/dist/core-update-manager.js +161 -60
  245. package/server/dist/core-update-state.js +29 -0
  246. package/server/dist/db.js +66 -35
  247. package/server/dist/delivery-evidence.js +142 -39
  248. package/server/dist/desktop-db.js +239 -43
  249. package/server/dist/desktop-router.js +109 -9
  250. package/server/dist/dev-ports.js +8 -3
  251. package/server/dist/file-provenance.js +34 -22
  252. package/server/dist/file-story-manager.js +62 -64
  253. package/server/dist/file-story.js +118 -35
  254. package/server/dist/file-summary-generator.js +46 -5
  255. package/server/dist/file-summary-manager.js +355 -106
  256. package/server/dist/framework-manager.js +98 -110
  257. package/server/dist/framework-reseed.js +76 -10
  258. package/server/dist/git-diagnostics.js +2 -2
  259. package/server/dist/headroom-manager.js +38 -3
  260. package/server/dist/host-control.js +52 -0
  261. package/server/dist/index.js +43 -2
  262. package/server/dist/interactive-job-session.js +149 -16
  263. package/server/dist/internal-api.js +48 -0
  264. package/server/dist/jira/jira-materializer.js +1 -0
  265. package/server/dist/json-tolerant.js +174 -0
  266. package/server/dist/legacy-migration.js +4 -2
  267. package/server/dist/loop-command-catalog.js +83 -21
  268. package/server/dist/loop-constants.js +6 -1
  269. package/server/dist/loop-decider.js +11 -1
  270. package/server/dist/loop-executors.js +194 -45
  271. package/server/dist/loop-factory.js +11 -4
  272. package/server/dist/loop-graph.js +90 -4
  273. package/server/dist/loop-run-manager.js +301 -69
  274. package/server/dist/loop-shell-invocation.js +21 -0
  275. package/server/dist/loop-step-idle.js +55 -0
  276. package/server/dist/loop-templates.js +31 -7
  277. package/server/dist/mcp/agent-capability.js +37 -4
  278. package/server/dist/mcp/guide.js +149 -36
  279. package/server/dist/mcp/mcp-admin-router.js +20 -4
  280. package/server/dist/mcp/mcp-server.js +89 -43
  281. package/server/dist/mcp/mcp-tiers.js +6 -5
  282. package/server/dist/mcp/mcp-token.js +3 -1
  283. package/server/dist/mcp/resources.js +5 -4
  284. package/server/dist/mcp/tools/catalog.js +4 -0
  285. package/server/dist/mcp/tools/code.js +125 -14
  286. package/server/dist/mcp/tools/context.js +153 -0
  287. package/server/dist/mcp/tools/git.js +15 -5
  288. package/server/dist/mcp/tools/jobs.js +84 -71
  289. package/server/dist/mcp/tools/loops.js +17 -6
  290. package/server/dist/mcp/tools/meta.js +74 -27
  291. package/server/dist/mcp/tools/mission.js +29 -0
  292. package/server/dist/mcp/tools/projects.js +22 -6
  293. package/server/dist/mcp/tools/rails.js +48 -11
  294. package/server/dist/mcp/tools/specs.js +86 -14
  295. package/server/dist/mcp/tools/support.js +1 -1
  296. package/server/dist/mcp/tools/types.js +117 -43
  297. package/server/dist/mcp/tools/watch.js +144 -51
  298. package/server/dist/milestone-chain-store.js +164 -0
  299. package/server/dist/milestone-chain.js +487 -0
  300. package/server/dist/milestone-progress.js +348 -0
  301. package/server/dist/mobile/mobile-devices.js +10 -7
  302. package/server/dist/mobile/mobile-gateway.js +2 -0
  303. package/server/dist/mobile/mobile-missions.js +214 -0
  304. package/server/dist/mobile/mobile-redact.js +17 -3
  305. package/server/dist/mobile/mobile-router.js +46 -4
  306. package/server/dist/mobile/mobile-ws.js +49 -4
  307. package/server/dist/multi-repo-bases.js +56 -0
  308. package/server/dist/multi-repo-checkout.js +101 -0
  309. package/server/dist/multi-repo-delivery.js +100 -0
  310. package/server/dist/multi-repo-execution-store.js +65 -0
  311. package/server/dist/multi-repo-execution.js +453 -0
  312. package/server/dist/offline-assemble.js +10 -8
  313. package/server/dist/openspec-runtime-plugin-commands.json +18 -0
  314. package/server/dist/openspec-runtime-plugin.js +120 -0
  315. package/server/dist/plugins/codex-spawn.js +49 -0
  316. package/server/dist/plugins/serena/manifest.js +2 -2
  317. package/server/dist/plugins/serena/templates/instructions.md +16 -0
  318. package/server/dist/pr-publisher.js +1 -1
  319. package/server/dist/profiles-router.js +3 -18
  320. package/server/dist/project-code-discovery.js +142 -0
  321. package/server/dist/project-git.js +19 -21
  322. package/server/dist/project-registry.js +272 -20
  323. package/server/dist/project-repositories.js +157 -0
  324. package/server/dist/project-repository-provenance.js +31 -0
  325. package/server/dist/project-router-background-processes.js +105 -0
  326. package/server/dist/project-router-git.js +75 -16
  327. package/server/dist/project-router-jobs.js +2 -126
  328. package/server/dist/project-router-loop-runs.js +72 -2
  329. package/server/dist/project-router-tickets.js +53 -8
  330. package/server/dist/project-router.js +239 -38
  331. package/server/dist/provider-detection.js +18 -6
  332. package/server/dist/provider-limit.js +64 -0
  333. package/server/dist/providers/claude-adapter.js +26 -1
  334. package/server/dist/providers/claude-background-tasks.js +18 -0
  335. package/server/dist/providers/claude-live-session.js +383 -0
  336. package/server/dist/providers/codex-adapter.js +19 -0
  337. package/server/dist/providers/codex-live-session.js +545 -0
  338. package/server/dist/providers/gemini-adapter.js +1 -0
  339. package/server/dist/providers/live-session-types.js +12 -0
  340. package/server/dist/providers/live-session.js +13 -0
  341. package/server/dist/providers/terminal-result.js +24 -0
  342. package/server/dist/queue-manager.js +2 -0
  343. package/server/dist/rail-isolated-launch.js +141 -16
  344. package/server/dist/rail-pr-decision.js +364 -99
  345. package/server/dist/rail-pr-store.js +24 -10
  346. package/server/dist/rail-worktree-release.js +34 -2
  347. package/server/dist/rail-worktrees-store.js +4 -4
  348. package/server/dist/rails-router.js +249 -55
  349. package/server/dist/repo-lock.js +92 -17
  350. package/server/dist/review-packet.js +23 -13
  351. package/server/dist/schemas/file-summary.v1.json +59 -59
  352. package/server/dist/schemas/profile.v1.json +137 -137
  353. package/server/dist/setup-manager.js +52 -8
  354. package/server/dist/shell-integration/bash-shim.bash +45 -0
  355. package/server/dist/shell-integration/fish-shim.fish +36 -0
  356. package/server/dist/shell-integration/powershell-shim.ps1 +48 -0
  357. package/server/dist/shell-integration/zsh-shim.zsh +47 -0
  358. package/server/dist/smash-runner.js +1 -0
  359. package/server/dist/spawn-lifecycle.js +44 -27
  360. package/server/dist/spec-contract-prompt.js +143 -0
  361. package/server/dist/spec-draft-parser.js +6 -1
  362. package/server/dist/spec-models.js +1 -0
  363. package/server/dist/stuck-run-detector.js +1 -0
  364. package/server/dist/terminal-manager.js +21 -1
  365. package/server/dist/terminal-shell-integration.js +4 -1
  366. package/server/dist/transient-children.js +619 -230
  367. package/server/dist/util/cli-prompt.js +78 -5
  368. package/server/dist/util/sqlite-migrations.js +20 -0
  369. package/server/dist/util/win-spawn.js +18 -3
  370. package/server/dist/util/windows-provider-shell.js +29 -0
  371. package/server/dist/verification-sentinel.js +14 -0
  372. package/server/dist/vitest-setup.js +2 -0
  373. package/server/dist/windows-job-supervisor.js +133 -0
  374. package/server/dist/workspace-manager.js +9 -30
  375. package/server/dist/worktree-manager.js +17 -2
  376. package/server/dist/worktree-overlay.js +3 -1
  377. package/client/dist/assets/ActivityFeedPage-tAQcWs1R.js +0 -1
  378. package/client/dist/assets/AgentBrowserCapture-BX8BNae5.js +0 -1
  379. package/client/dist/assets/AgentModeAnalyticsPane-BVAqCL0K.js +0 -2
  380. package/client/dist/assets/AgentModeCodePane-9XfqQc9c.js +0 -2
  381. package/client/dist/assets/AgentModeJobsPane-BCjLsPhc.js +0 -1
  382. package/client/dist/assets/AgentsPage-C8J_42sm.js +0 -87
  383. package/client/dist/assets/AnalyticsPage-BtQuyfJm.js +0 -1
  384. package/client/dist/assets/CodePage-BZ2MwdCu.js +0 -2
  385. package/client/dist/assets/DesktopAnalyticsPage-Bh_29V4g.js +0 -1
  386. package/client/dist/assets/ExportDropdown-BrtfWzEG.js +0 -1
  387. package/client/dist/assets/InteractiveJobComposer-BCZiSfzc.js +0 -19
  388. package/client/dist/assets/JobDetailModal-NAJmuYIT.js +0 -1
  389. package/client/dist/assets/JobDetailPage-fE0ZycUX.js +0 -1
  390. package/client/dist/assets/JobsPage-z5M_HVJG.js +0 -1
  391. package/client/dist/assets/LoopBuilderPage-j1FQS47c.js +0 -7
  392. package/client/dist/assets/LoopPreviewModal-DhDJjdCe.js +0 -1
  393. package/client/dist/assets/LoopsPage-Ll7zORZb.js +0 -1
  394. package/client/dist/assets/MinimizedChatsContext-Bd3OqR_S.js +0 -1
  395. package/client/dist/assets/PluginsPage-DN4kGvJt.js +0 -2
  396. package/client/dist/assets/ProjectSettingsDialog-OgsgxjzF.js +0 -1
  397. package/client/dist/assets/ReviewPacketPage-DFog4sXn.js +0 -1
  398. package/client/dist/assets/TemplatePreviewModal-L2XxqiOD.js +0 -1
  399. package/client/dist/assets/TicketDetailModal-CsF-AWZX.js +0 -14
  400. package/client/dist/assets/Trans-Bsz9_gyq.js +0 -1
  401. package/client/dist/assets/agent-BQgKv_2F.js +0 -1
  402. package/client/dist/assets/agent-C1NRDJqL.js +0 -1
  403. package/client/dist/assets/agent-CLNleiy6.js +0 -1
  404. package/client/dist/assets/agent-CmceArkQ.js +0 -1
  405. package/client/dist/assets/agent-D3UxQ3SR.js +0 -1
  406. package/client/dist/assets/agent-DB1JeE64.js +0 -1
  407. package/client/dist/assets/agent-DXkHcQ-D.js +0 -1
  408. package/client/dist/assets/agent-DjJJJ2M8.js +0 -1
  409. package/client/dist/assets/auth-D_5bQv5W.js +0 -1
  410. package/client/dist/assets/ban-E4EaZe3a.js +0 -1
  411. package/client/dist/assets/bot-DzuuuC5R.js +0 -1
  412. package/client/dist/assets/browser-BgqHDMXP.js +0 -1
  413. package/client/dist/assets/browser-CsKJtrpv.js +0 -1
  414. package/client/dist/assets/browser-Cu58EpZU.js +0 -1
  415. package/client/dist/assets/browser-CvXOJm-j.js +0 -1
  416. package/client/dist/assets/browser-DOrFh1c7.js +0 -1
  417. package/client/dist/assets/browser-DQv_Jo7x.js +0 -1
  418. package/client/dist/assets/browser-LPgxvJu2.js +0 -1
  419. package/client/dist/assets/browser-eL-3MIEI.js +0 -1
  420. package/client/dist/assets/builder-0IWtosUm.js +0 -1
  421. package/client/dist/assets/builder-Bf2N6XWn.js +0 -1
  422. package/client/dist/assets/builder-BnqaaBkT.js +0 -1
  423. package/client/dist/assets/builder-BxxfGgAO.js +0 -1
  424. package/client/dist/assets/builder-C5IIgWsq.js +0 -1
  425. package/client/dist/assets/builder-CHuahItu.js +0 -1
  426. package/client/dist/assets/builder-CjWosXL_.js +0 -1
  427. package/client/dist/assets/builder-CpCIOoKj.js +0 -1
  428. package/client/dist/assets/code-CHPkOkDS.js +0 -1
  429. package/client/dist/assets/commands-6tYQih5m.js +0 -1
  430. package/client/dist/assets/commands-BK2QinXN.js +0 -1
  431. package/client/dist/assets/commands-C2Nca76h.js +0 -1
  432. package/client/dist/assets/commands-CKdLihNX.js +0 -1
  433. package/client/dist/assets/commands-CYIBTAlc.js +0 -1
  434. package/client/dist/assets/commands-CjUtYJIM.js +0 -1
  435. package/client/dist/assets/commands-Cq_u_8y9.js +0 -1
  436. package/client/dist/assets/commands-D_ZHYQug.js +0 -1
  437. package/client/dist/assets/common-6MLbD-jM.js +0 -1
  438. package/client/dist/assets/common-BKGEu4rm.js +0 -1
  439. package/client/dist/assets/common-BNbnv8cE.js +0 -1
  440. package/client/dist/assets/common-BqGWtDbt.js +0 -1
  441. package/client/dist/assets/common-DBtTzeYm.js +0 -1
  442. package/client/dist/assets/common-DEW3Nr8n.js +0 -1
  443. package/client/dist/assets/common-DHsv9N5d.js +0 -1
  444. package/client/dist/assets/common-mkrEcW-Y.js +0 -1
  445. package/client/dist/assets/dashboard-B9GhC5ku.js +0 -1
  446. package/client/dist/assets/dashboard-CBnv6zOI.js +0 -1
  447. package/client/dist/assets/dashboard-CaP0fU87.js +0 -1
  448. package/client/dist/assets/dashboard-D4ZZ4x84.js +0 -1
  449. package/client/dist/assets/dashboard-DmuTQBX8.js +0 -1
  450. package/client/dist/assets/dashboard-DynLYj3d.js +0 -1
  451. package/client/dist/assets/dashboard-zj4gGFJ1.js +0 -1
  452. package/client/dist/assets/dialog-CdWCb02j.js +0 -45
  453. package/client/dist/assets/dist-bVqfYmby.js +0 -1
  454. package/client/dist/assets/dist-js-CWeUdf5Z.js +0 -1
  455. package/client/dist/assets/formatDistanceToNow-DQCvMgUc.js +0 -1
  456. package/client/dist/assets/getTimezoneOffsetInMilliseconds-C16cxSe1.js +0 -1
  457. package/client/dist/assets/git-refresh-wTW0rO0Z.js +0 -1
  458. package/client/dist/assets/i18n-hnX2DPmo.js +0 -2
  459. package/client/dist/assets/index-DIhMEAVw.js +0 -66
  460. package/client/dist/assets/index-DwygcU7s.css +0 -2
  461. package/client/dist/assets/mcp-B8X8wBLu.js +0 -1
  462. package/client/dist/assets/mcp-C2AojZZN.js +0 -1
  463. package/client/dist/assets/mcp-D8BT78_L.js +0 -1
  464. package/client/dist/assets/mcp-Df5RWBNk.js +0 -1
  465. package/client/dist/assets/mcp-Dj7BgMQW.js +0 -1
  466. package/client/dist/assets/mcp-Q7iT7rcz.js +0 -1
  467. package/client/dist/assets/mcp-YlvNvJbW.js +0 -1
  468. package/client/dist/assets/mcp-mKFpTSRb.js +0 -1
  469. package/client/dist/assets/narration-4Z2VUhZw.js +0 -1
  470. package/client/dist/assets/narration-BGuiEDj3.js +0 -1
  471. package/client/dist/assets/narration-BuSoqRmv.js +0 -1
  472. package/client/dist/assets/narration-CB9t29fy.js +0 -1
  473. package/client/dist/assets/narration-CU3x8FHD.js +0 -1
  474. package/client/dist/assets/narration-CWeXhfP5.js +0 -1
  475. package/client/dist/assets/narration-DRaDnhT5.js +0 -1
  476. package/client/dist/assets/narration-DtEbQgCw.js +0 -1
  477. package/client/dist/assets/nav-ApJVg3xu.js +0 -1
  478. package/client/dist/assets/nav-BKNky1Bg.js +0 -1
  479. package/client/dist/assets/nav-C6vWWKYx.js +0 -1
  480. package/client/dist/assets/nav-CXJ6Aw89.js +0 -1
  481. package/client/dist/assets/nav-CsmFBIDf.js +0 -1
  482. package/client/dist/assets/nav-DjkmQJjd.js +0 -1
  483. package/client/dist/assets/packet-B1IxaL5f.js +0 -1
  484. package/client/dist/assets/packet-Bh5kkbiB.js +0 -1
  485. package/client/dist/assets/packet-By8fqYxW.js +0 -1
  486. package/client/dist/assets/packet-CZdvA44E.js +0 -1
  487. package/client/dist/assets/packet-CrjHRQCP.js +0 -1
  488. package/client/dist/assets/packet-Dwi2pTtx.js +0 -1
  489. package/client/dist/assets/packet-_-ZIa0IR.js +0 -1
  490. package/client/dist/assets/packet-n0W6E1Hn.js +0 -1
  491. package/client/dist/assets/play-DNlrawbS.js +0 -1
  492. package/client/dist/assets/provider-capabilities-Doej9lfa.js +0 -1
  493. package/client/dist/assets/settings-Bd0x4TBa.js +0 -1
  494. package/client/dist/assets/settings-C1-7cXzC.js +0 -1
  495. package/client/dist/assets/settings-CAFaT38b.js +0 -1
  496. package/client/dist/assets/settings-Ct3v1nW2.js +0 -1
  497. package/client/dist/assets/settings-DHh7_IF5.js +0 -1
  498. package/client/dist/assets/settings-DQXAmdcv.js +0 -1
  499. package/client/dist/assets/settings-guzlhpup.js +0 -1
  500. package/client/dist/assets/settings-sZfTPMEH.js +0 -1
  501. package/client/dist/assets/setup-3jWaoVUO.js +0 -1
  502. package/client/dist/assets/setup-BjgRneb2.js +0 -1
  503. package/client/dist/assets/setup-BzFIjv-f.js +0 -1
  504. package/client/dist/assets/setup-C4VfQsxE.js +0 -1
  505. package/client/dist/assets/setup-DfUkpDbN.js +0 -1
  506. package/client/dist/assets/setup-ECe90Pmu.js +0 -1
  507. package/client/dist/assets/setup-dlqC4Jmm.js +0 -1
  508. package/client/dist/assets/setup-jwfLMiM2.js +0 -1
  509. package/client/dist/assets/spending-EC9xqio-.js +0 -1
  510. package/client/dist/assets/useDesktop-BQVt8lFd.js +0 -1
@@ -74,6 +74,8 @@ const db_1 = require("./db");
74
74
  const delivery_evidence_1 = require("./delivery-evidence");
75
75
  const integration_branch_1 = require("./integration-branch");
76
76
  const repo_lock_1 = require("./repo-lock");
77
+ const project_repositories_1 = require("./project-repositories");
78
+ const multi_repo_execution_store_1 = require("./multi-repo-execution-store");
77
79
  const rail_isolation_1 = require("./rail-isolation");
78
80
  const rail_pr_store_1 = require("./rail-pr-store");
79
81
  const agent_chat_registry_1 = require("./agent-chat-registry");
@@ -92,6 +94,7 @@ const active_pr_continuation_1 = require("./active-pr-continuation");
92
94
  const pr_lifecycle_1 = require("./pr-lifecycle");
93
95
  const rail_worktree_release_1 = require("./rail-worktree-release");
94
96
  const rail_pr_recovery_git_1 = require("./rail-pr-recovery-git");
97
+ const loop_graph_1 = require("./loop-graph");
95
98
  /** A PR follow-up may only run on the verified PR branch in a dedicated
96
99
  * worktree. Routers must surface this error instead of degrading to shared cwd. */
97
100
  class PrContinuationIsolationError extends Error {
@@ -371,12 +374,31 @@ function branchRecords(results) {
371
374
  /**
372
375
  * Launch the rail's tickets in isolated worktrees + schedule the merge-back.
373
376
  * Returns the loop run ids. Throws if worktree allocation fails, but only after
374
- * tearing down owned partial allocation. A fresh launch may degrade to shared
375
- * cwd in the router; a PR continuation raises PrContinuationIsolationError and
376
- * must fail closed because shared cwd cannot prove which branch receives work.
377
+ * tearing down owned partial allocation. The router refuses shared-cwd
378
+ * fallback for these errors; execution stays bound to a verified worktree.
377
379
  */
378
380
  async function launchIsolatedRail(input, io = {}) {
379
381
  const { ctx, railIndex, ticketIds, loopId, loopName, loopGraph, provider, model, effort } = input;
382
+ let expectedRepositoryBaseSha = input.repositoryExecution?.expectedBaseSha;
383
+ let singleRepositoryId = input.repositoryExecution?.repositoryId;
384
+ if (!input.repositoryExecution) {
385
+ const members = (0, project_repositories_1.getProjectRepositories)(ctx.project);
386
+ const primary = members.find((repo) => repo.isPrimary) ?? members[0];
387
+ const selected = input.repositoryIds ?? (ticketIds.length === 0 && primary ? [primary.id] : [...new Set(ticketIds.flatMap((id) => {
388
+ const ids = ctx.getTicketSpec(id)?.repositoryIds;
389
+ return ids?.length ? ids : primary ? [primary.id] : [];
390
+ }))]);
391
+ (0, loop_graph_1.assertLoopShellRepositoryScope)(loopGraph, selected);
392
+ if (primary && selected.length === 1 && selected[0] === primary.id) {
393
+ input = { ...input, baseBranch: input.repositoryBaseBranches?.[primary.id] ?? input.baseBranch };
394
+ singleRepositoryId = primary.id;
395
+ expectedRepositoryBaseSha = input.repositoryBaseShas?.[primary.id];
396
+ }
397
+ if (selected.length !== 1 || selected[0] !== primary?.id) {
398
+ const { launchMultiRepositoryRail } = await Promise.resolve().then(() => __importStar(require('./multi-repo-execution')));
399
+ return launchMultiRepositoryRail({ ...input, repositoryIds: selected }, io);
400
+ }
401
+ }
380
402
  const git = io.git ?? worktree_manager_1.defaultGitRunner;
381
403
  const exec = io.exec ?? pr_publisher_1.defaultExec;
382
404
  const create = io.create ?? worktree_manager_1.createWorktree;
@@ -385,7 +407,7 @@ async function launchIsolatedRail(input, io = {}) {
385
407
  const resolveExecution = io.resolveExecution ?? workspace_resolution_1.resolveProjectExecution;
386
408
  const baseRepo = ctx.project.path;
387
409
  const slug = ctx.project.slug;
388
- const worktreesRoot = path.join((0, artifact_registry_1.resolveHome)(), '.specrails', 'projects', slug, 'worktrees');
410
+ const worktreesRoot = path.join((0, artifact_registry_1.resolveHome)(), '.specrails', 'projects', slug, 'worktrees', ...(input.repositoryExecution ? [input.repositoryExecution.repositoryId] : []));
389
411
  // A revision run is seeded with a full briefing (the instruction PLUS the
390
412
  // frozen spec, the branch that carries the work and what the previous run
391
413
  // actually reported) rather than the bare sentence — the run starts a FRESH
@@ -400,7 +422,7 @@ async function launchIsolatedRail(input, io = {}) {
400
422
  : (0, loop_constants_1.loadConstantMap)(ctx.desktopDb);
401
423
  // Capture the PR-delivery mode ONCE at launch entry so a mid-flight env flip
402
424
  // can never split one launch across the two delivery paths.
403
- const prMode = (0, rail_isolation_1.isRailPrDeliveryEnabled)();
425
+ const prMode = Boolean(input.repositoryExecution) || (0, rail_isolation_1.isRailPrDeliveryEnabled)();
404
426
  // Ask-first PR delivery (safe-pr-review-flow): persist the authoritative
405
427
  // decision row UP FRONT (decision='building') — so the origin link survives
406
428
  // every await and late-joining clients hydrate mid-build via GET /rails —
@@ -472,7 +494,7 @@ async function launchIsolatedRail(input, io = {}) {
472
494
  // run — the batch pipeline handles the tickets internally); `per-ticket` → one
473
495
  // unit per ticket. The branch/ledger key is the unit's primary (first) ticket.
474
496
  const scope = input.scope ?? 'per-ticket';
475
- let units = scope === 'all'
497
+ let units = input.repositoryExecution && ticketIds.length === 0 ? [{ ticketId: 0, ticketIds: [] }] : scope === 'all'
476
498
  ? [{ ticketId: ticketIds[0], ticketIds: [...ticketIds] }]
477
499
  : ticketIds.map((id) => ({ ticketId: id, ticketIds: [id] }));
478
500
  // Effective artifact root for the per-worktree overlay: a RELOCATED project's
@@ -544,9 +566,12 @@ async function launchIsolatedRail(input, io = {}) {
544
566
  // Resolve the project's designated integration branch ONCE, and branch every
545
567
  // ticket's worktree off it (not the ambient HEAD). Empty setting → auto-resolve
546
568
  // (repo default → HEAD fallback). See server/integration-branch.ts.
569
+ const executionRepository = (0, project_repositories_1.getProjectRepositories)(ctx.project).find((repo) => input.repositoryExecution
570
+ ? repo.id === input.repositoryExecution.repositoryId : repo.isPrimary);
547
571
  integration = await (0, integration_branch_1.resolveIntegrationBranch)(git, {
548
572
  repoDir: baseRepo,
549
- projectSetting: (0, db_1.getProjectSettings)(ctx.db).integrationBranch,
573
+ explicit: input.baseBranch ?? undefined,
574
+ projectSetting: executionRepository?.integrationBranch ?? (input.repositoryExecution && !input.repositoryExecution.primary ? undefined : (0, db_1.getProjectSettings)(ctx.db).integrationBranch),
550
575
  });
551
576
  // Prefer the freshly-fetched remote-tracking ref (origin/<branch>) over the
552
577
  // bare local name for repo-default/project-setting sources — see
@@ -644,6 +669,9 @@ async function launchIsolatedRail(input, io = {}) {
644
669
  }
645
670
  if (prMode) {
646
671
  const generation = (0, rail_pr_store_1.createPrDeliveryGeneration)(ctx.db, {
672
+ parentDeliveryId: input.repositoryExecution?.parentDeliveryId,
673
+ repositoryId: input.repositoryExecution?.repositoryId,
674
+ repositoryPath: input.repositoryExecution ? baseRepo : undefined,
647
675
  railIndex,
648
676
  loopId,
649
677
  railKey: `${railIndex}-${loopId}`,
@@ -709,6 +737,9 @@ async function launchIsolatedRail(input, io = {}) {
709
737
  const takenBranches = await (0, worktree_manager_1.listLocalBranches)(git, baseRepo);
710
738
  const preexistingBranches = new Set(takenBranches);
711
739
  const unitBranchName = (ticketId) => {
740
+ const revisionBranch = input.repositoryExecution?.revisionBranches?.get(ticketId);
741
+ if (revisionBranch)
742
+ return { branch: revisionBranch.branch, ownership: 'preexisting' };
712
743
  const continuation = launchContinuation && continuationTargets.get(ticketId);
713
744
  if (continuation) {
714
745
  takenBranches.add(continuation.branch);
@@ -716,7 +747,10 @@ async function launchIsolatedRail(input, io = {}) {
716
747
  }
717
748
  const preferred = (0, pr_naming_1.ticketBranchName)(unitNamingInput(ctx, ticketId));
718
749
  const branch = (0, pr_naming_1.resolveCollisionFreeName)(preferred, {
719
- taken: (name) => takenBranches.has(name) && !(0, rail_worktrees_store_1.railWorktreeBranchExistsForTicket)(ctx.db, ticketId, name),
750
+ // A grouped run can reuse a branch only through the exact revision/PR
751
+ // evidence above. An accepted predecessor may now lag the integration
752
+ // branch, so ordinary grouped allocations must start a fresh branch.
753
+ taken: (name) => takenBranches.has(name) && (Boolean(input.repositoryExecution) || !(0, rail_worktrees_store_1.railWorktreeBranchExistsForTicket)(ctx.db, ticketId, name)),
720
754
  reserved: [integration.branch],
721
755
  }) ?? (0, worktree_manager_1.worktreeBranch)(slug, ticketId);
722
756
  takenBranches.add(branch);
@@ -731,12 +765,19 @@ async function launchIsolatedRail(input, io = {}) {
731
765
  let worktreeOwnership = 'created';
732
766
  let initialSha = null;
733
767
  try {
768
+ const revisionBranch = input.repositoryExecution?.revisionBranches?.get(unit.ticketId);
769
+ if (revisionBranch) {
770
+ const observed = await git.run(['rev-parse', '--verify', `refs/heads/${revisionBranch.branch}`], baseRepo);
771
+ if (observed.code !== 0 || observed.stdout.trim() !== revisionBranch.sha) {
772
+ throw new Error(`Revision branch ${revisionBranch.branch} no longer matches its recorded delivery commit`);
773
+ }
774
+ }
734
775
  handle = await create(git, {
735
776
  repoDir: baseRepo,
736
777
  worktreesRoot,
737
778
  slug,
738
779
  ticketId: unit.ticketId,
739
- baseRef: continuationTarget?.baseRef ?? worktreeBaseRef.baseRef,
780
+ baseRef: revisionBranch?.sha ?? continuationTarget?.baseRef ?? worktreeBaseRef.baseRef,
740
781
  branch: branchPlan.branch,
741
782
  refreshFromBaseRef: Boolean(continuationTarget?.baseRef),
742
783
  });
@@ -749,6 +790,11 @@ async function launchIsolatedRail(input, io = {}) {
749
790
  }
750
791
  else {
751
792
  initialSha = await readHeadSha(git, handle.worktreePath);
793
+ if (expectedRepositoryBaseSha && initialSha !== expectedRepositoryBaseSha)
794
+ throw new Error('The repository base changed before its worktree could be frozen');
795
+ if (revisionBranch && (handle.branch !== revisionBranch.branch || initialSha !== revisionBranch.sha)) {
796
+ throw new Error(`Revision checkout does not expose the exact recorded branch ${revisionBranch.branch}`);
797
+ }
752
798
  }
753
799
  // Per-run overlay: merge-link the framework surface the checkout didn't
754
800
  // bring into the worktree (idempotent; resume-safe via its manifest).
@@ -806,10 +852,12 @@ async function launchIsolatedRail(input, io = {}) {
806
852
  console.warn(`[rail-isolated] provenance snapshot failed: ${err.message}`);
807
853
  }
808
854
  }
809
- const runId = (0, ids_1.newId)();
855
+ const runId = input.repositoryExecution?.runIds.get(unit.ticketId) ?? (0, ids_1.newId)();
810
856
  const ledgerId = (0, ids_1.newId)();
811
857
  (0, rail_worktrees_store_1.createRailWorktree)(ctx.db, {
812
858
  id: ledgerId, railIndex, ticketId: unit.ticketId, runId,
859
+ repositoryId: input.repositoryExecution?.repositoryId,
860
+ repositoryPath: input.repositoryExecution ? baseRepo : undefined,
813
861
  branch: handle.branch, worktreePath: handle.worktreePath,
814
862
  });
815
863
  allocated.push({
@@ -910,6 +958,7 @@ async function launchIsolatedRail(input, io = {}) {
910
958
  runId: a.runId,
911
959
  ticketId: a.ticketId,
912
960
  repoDir: a.handle.worktreePath,
961
+ repositoryId: input.repositoryExecution?.repositoryId,
913
962
  snapshot: a.provenanceSnapshot,
914
963
  broadcast: (msg) => ctx.broadcast(msg),
915
964
  });
@@ -934,19 +983,33 @@ async function launchIsolatedRail(input, io = {}) {
934
983
  const settleAllocatedRun = async (a, enginePromise) => {
935
984
  let actualOutcome = 'failed';
936
985
  let engineFailure;
986
+ let stallReason;
937
987
  try {
938
988
  const result = await enginePromise;
939
989
  actualOutcome = result.outcome;
990
+ stallReason = result.stallReason;
940
991
  }
941
992
  catch (err) {
942
993
  engineFailure = errorDetail(err);
943
994
  console.error(`[rail-isolated] loop run ${a.runId} rejected: ${engineFailure}`);
944
995
  }
996
+ if (input.repositoryExecution?.isAborted?.()) {
997
+ // The coordinator never started. Do not commit incidental edits or
998
+ // release a mount borrowed from a previous delivery while rolling back.
999
+ const finalSha = await readHeadSha(git, a.handle.worktreePath);
1000
+ if (a.worktreeOwnership !== 'created')
1001
+ markWorktree(a, 'needs-review');
1002
+ return {
1003
+ run: a, implementationOutcome: 'failed', deliveryOutcome: 'not_started',
1004
+ initialSha: a.initialSha, finalSha, changed: Boolean(finalSha && a.initialSha !== finalSha),
1005
+ safeToRelease: a.worktreeOwnership === 'created' && finalSha !== null && finalSha === a.initialSha,
1006
+ };
1007
+ }
945
1008
  const implementationOutcome = actualOutcome === 'success' ? 'succeeded' : 'failed';
946
1009
  recordRunProvenance(a);
947
1010
  let callbackFailure;
948
1011
  try {
949
- ctx.onLoopRunFinished(a.runId, actualOutcome, runFinishedOpts);
1012
+ ctx.onLoopRunFinished(a.runId, actualOutcome, { ...runFinishedOpts, ...(stallReason ? { stallReason } : {}) });
950
1013
  }
951
1014
  catch (err) {
952
1015
  callbackFailure = errorDetail(err);
@@ -1112,12 +1175,23 @@ async function launchIsolatedRail(input, io = {}) {
1112
1175
  const enginePromise = ctx.loopRunManager.run({
1113
1176
  runId: a.runId, loopId, loopName, graph: loopGraph, projectId: ctx.project.id,
1114
1177
  cwd: a.handle.worktreePath, repoDir: a.handle.worktreePath,
1178
+ repositoryId: singleRepositoryId,
1115
1179
  isolation: { branch: a.handle.branch, worktreePath: a.handle.worktreePath },
1116
- railIndex, ticketId: a.ticketId,
1117
- spec: spec ? { ...spec, ticketIds: a.ticketIds } : { ticketIds: a.ticketIds },
1180
+ railIndex, ticketId: a.ticketIds.length ? a.ticketId : null,
1181
+ spec: {
1182
+ ...spec,
1183
+ ticketIds: a.ticketIds,
1184
+ ...(a.ticketIds.length > 1 ? {
1185
+ tickets: a.ticketIds.map((id) => {
1186
+ const ticket = ctx.getTicketSpec(id);
1187
+ return { id, title: ticket?.title, description: ticket?.description, repositoryIds: ticket?.repositoryIds };
1188
+ }),
1189
+ } : {}),
1190
+ },
1118
1191
  ticketCompletionStatus: runFinishedOpts.ticketCompletionStatus,
1119
1192
  deferTerminalOutcome: true,
1120
1193
  constants, provider, model, effort,
1194
+ profileName: input.profileName,
1121
1195
  });
1122
1196
  runPromises.push(settleAllocatedRun(a, enginePromise));
1123
1197
  try {
@@ -1454,6 +1528,7 @@ async function launchIsolatedRail(input, io = {}) {
1454
1528
  ticketId: result.run.ticketId,
1455
1529
  runId: result.run.runId,
1456
1530
  worktreePath: result.run.handle.worktreePath,
1531
+ loopId,
1457
1532
  })));
1458
1533
  }
1459
1534
  catch (e) {
@@ -1592,7 +1667,7 @@ async function launchIsolatedRail(input, io = {}) {
1592
1667
  broadcastPrState();
1593
1668
  syncOriginCard('update');
1594
1669
  }
1595
- });
1670
+ }).finally(() => { input.repositoryExecution?.onSettled(prDeliveryId); });
1596
1671
  return allocated.map((a) => a.runId);
1597
1672
  }
1598
1673
  function recoveryOverlayExcludes(repoDir, worktreePath) {
@@ -1712,8 +1787,25 @@ async function reconcileRailWorktrees(db, repoDir, io = {}) {
1712
1787
  const git = io.git ?? worktree_manager_1.defaultGitRunner;
1713
1788
  const exec = io.exec ?? pr_publisher_1.defaultExec;
1714
1789
  const remove = io.remove ?? worktree_manager_1.removeWorktree;
1790
+ if (!io.repositoryOnly) {
1791
+ const paths = db.prepare('SELECT DISTINCT repository_path FROM rail_worktrees WHERE repository_path IS NOT NULL UNION SELECT DISTINCT repository_path FROM rail_pr_deliveries WHERE repository_path IS NOT NULL').all();
1792
+ if (paths.length) {
1793
+ let count = 0;
1794
+ for (const target of [...new Set([repoDir, ...paths.map((row) => row.repository_path)])]) {
1795
+ count += await reconcileRailWorktrees(db, target, { ...io, repositoryOnly: true, primaryRepoDir: repoDir });
1796
+ }
1797
+ const { refreshRepositoryDeliveryGroup } = await Promise.resolve().then(() => __importStar(require('./multi-repo-execution')));
1798
+ const groups = db.prepare('SELECT id FROM rail_pr_deliveries WHERE parent_delivery_id IS NULL AND execution_manifest IS NOT NULL').all();
1799
+ for (const group of groups) {
1800
+ refreshRepositoryDeliveryGroup(db, group.id, { startup: true });
1801
+ io.onDeliveryRecovered?.(group.id);
1802
+ }
1803
+ return count;
1804
+ }
1805
+ }
1806
+ const belongsHere = (row) => (row.repository_path ?? io.primaryRepoDir ?? repoDir) === repoDir;
1715
1807
  return (0, repo_lock_1.withRepoLock)(repoDir, async () => {
1716
- const stuck = (0, rail_worktrees_store_1.listNonTerminalRailWorktrees)(db);
1808
+ const stuck = (0, rail_worktrees_store_1.listNonTerminalRailWorktrees)(db).filter(belongsHere);
1717
1809
  const autoReleaseWorktreeIds = new Set();
1718
1810
  const settledDeliveries = db.prepare(`
1719
1811
  SELECT decision, delivery_outcome, worktree_ids FROM rail_pr_deliveries
@@ -1787,7 +1879,38 @@ async function reconcileRailWorktrees(db, repoDir, io = {}) {
1787
1879
  // mismatch are all recoverable uncertainty. Never force-remove them.
1788
1880
  (0, rail_worktrees_store_1.updateRailWorktreeState)(db, row.id, 'needs-review');
1789
1881
  }
1790
- const recovered = (0, rail_pr_store_1.reconcileFailedBuildingPrDeliveries)(db, { startup: true });
1882
+ const recovered = (0, rail_pr_store_1.reconcileFailedBuildingPrDeliveries)(db, { startup: true, repositoryPath: repoDir, legacyRepositoryPath: io.primaryRepoDir ?? repoDir });
1883
+ // Multi-repository recovery must not conflate the same run/branch names
1884
+ // across object stores. Promote only a clean unchanged base or an exact
1885
+ // app-marked settlement commit; retain uncertain work for explicit revision.
1886
+ for (const delivery of recovered) {
1887
+ const manifest = (0, multi_repo_execution_store_1.readExecutionManifest)(delivery.execution_manifest);
1888
+ if (!delivery.parent_delivery_id || !manifest || delivery.pr_url || delivery.implementation_outcome !== 'succeeded')
1889
+ continue;
1890
+ const units = (0, rail_pr_store_1.toPrDeliverySnapshot)(delivery).branches;
1891
+ const recoveredUnits = await Promise.all(units.map(async (unit) => {
1892
+ const ledger = stuck.find((row) => row.run_id === unit.runId && row.branch === unit.branch);
1893
+ const snapshot = manifest.repositories.find((repo) => repo.worktreeId === ledger?.id);
1894
+ const sha = unit.runId ? verifiedShaByRun.get(unit.runId) : undefined;
1895
+ const proven = Boolean(snapshot && sha && (sha === snapshot.baseSha || await (0, rail_pr_recovery_git_1.commitCarriesRunMarker)(git, repoDir, sha, unit.runId)));
1896
+ const noChanges = proven && sha === snapshot.baseSha;
1897
+ return {
1898
+ ...unit, repositoryId: delivery.repository_id ?? undefined,
1899
+ succeeded: proven && !noChanges, initialSha: snapshot?.baseSha ?? null, finalSha: proven ? sha : null,
1900
+ changed: proven ? !noChanges : undefined, worktreePath: ledger?.worktree_path,
1901
+ branchOwnership: 'preexisting', deliveryOutcome: proven ? noChanges ? 'no_changes' : 'ready' : 'blocked',
1902
+ failureCode: proven ? null : 'settlement_interrupted',
1903
+ };
1904
+ }));
1905
+ const ready = recoveredUnits.filter((unit) => unit.deliveryOutcome === 'ready').length;
1906
+ const unchanged = recoveredUnits.length > 0 && recoveredUnits.every((unit) => unit.deliveryOutcome === 'no_changes');
1907
+ const blocked = recoveredUnits.some((unit) => unit.deliveryOutcome === 'blocked');
1908
+ const next = blocked ? 'pr_failed' : unchanged ? 'no_changes' : ready ? 'on_review' : 'pr_failed';
1909
+ (0, rail_pr_store_1.transitionDecision)(db, delivery.id, delivery.decision, next, {
1910
+ branches: recoveredUnits, deliveryOutcome: blocked ? 'blocked' : unchanged ? 'no_changes' : 'ready',
1911
+ statusCode: blocked ? 'settlement_interrupted' : unchanged ? 'no_changes' : 'ready_for_review',
1912
+ });
1913
+ }
1791
1914
  // Migration 49 repairs legacy false implementation failures before Git is
1792
1915
  // available. Revisit those already-pr_failed rows here: if their own
1793
1916
  // durable run/worktree ledger proves one exact clean object, the card can
@@ -1848,6 +1971,8 @@ async function reconcileRailWorktrees(db, repoDir, io = {}) {
1848
1971
  return recoveryProtectionScan;
1849
1972
  };
1850
1973
  for (const delivery of recoveryCandidates) {
1974
+ if (!belongsHere(delivery))
1975
+ continue;
1851
1976
  if (!['succeeded', 'partially_succeeded'].includes(delivery.implementation_outcome))
1852
1977
  continue;
1853
1978
  // Exact-SHA promotion here is specifically an existing-PR retry. A fresh