specrails-desktop 2.57.0 → 2.58.0

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 (336) hide show
  1. package/README.md +1 -1
  2. package/cli/dist/args.js +10 -4
  3. package/cli/dist/help.js +1 -1
  4. package/client/dist/assets/{ActivityFeedPage-DdMNmVBk.js → ActivityFeedPage-BQGppIR0.js} +1 -1
  5. package/client/dist/assets/{AgentBrowserCapture-CeerUf--.js → AgentBrowserCapture-PI-cxyxi.js} +1 -1
  6. package/client/dist/assets/{AgentModeAnalyticsPane-BjGb-8rh.js → AgentModeAnalyticsPane-mQsOqdXx.js} +2 -2
  7. package/client/dist/assets/{AgentModeCodePane-8XRkQEo_.js → AgentModeCodePane-BL-vpmlY.js} +2 -2
  8. package/client/dist/assets/{AgentModeJobsPane-BN3dgJOA.js → AgentModeJobsPane-DR_06oqH.js} +1 -1
  9. package/client/dist/assets/AgentsPage-BKIKjm_1.js +118 -0
  10. package/client/dist/assets/{AnalyticsPage-CyfhYiBn.js → AnalyticsPage-069npRVo.js} +1 -1
  11. package/client/dist/assets/{CodePage-C2Nf-Q5W.js → CodePage-Alitorrv.js} +2 -2
  12. package/client/dist/assets/DesktopAnalyticsPage-qtWAPM47.js +1 -0
  13. package/client/dist/assets/{DocsDialog-Br3bczCp.js → DocsDialog-DwL6rgcT.js} +1 -1
  14. package/client/dist/assets/{DocsPage-BcDr2cBm.js → DocsPage-BA1hiJZ-.js} +1 -1
  15. package/client/dist/assets/{ExportDropdown-BVGKEgkd.js → ExportDropdown-BcMpvV89.js} +1 -1
  16. package/client/dist/assets/InteractiveJobComposer-B3H1YHr6.js +19 -0
  17. package/client/dist/assets/JobDetailModal-XZQ9eAAy.js +1 -0
  18. package/client/dist/assets/{JobDetailPage-vBbNeRuz.js → JobDetailPage-B-SIaq_q.js} +1 -1
  19. package/client/dist/assets/{JobsPage-CJCtPhIz.js → JobsPage-iQXAv2mx.js} +1 -1
  20. package/client/dist/assets/LoopBuilderPage-B_gbFAHn.js +1 -0
  21. package/client/dist/assets/LoopPreviewModal-je5pSCf-.js +1 -0
  22. package/client/dist/assets/LoopsPage-BZwcY5cu.js +2 -0
  23. package/client/dist/assets/{MinimizedChatsContext-D3QzgV0B.js → MinimizedChatsContext-CNx_0bZu.js} +1 -1
  24. package/client/dist/assets/{PluginsPage-DOpTV75p.js → PluginsPage-DFocnoHX.js} +2 -2
  25. package/client/dist/assets/{ProjectSettingsDialog-Dkwrn0z1.js → ProjectSettingsDialog-Bh3S6EBB.js} +1 -1
  26. package/client/dist/assets/{RepositoryDeliveries-Du2UCf1a.js → RepositoryDeliveries-BiwJuS8r.js} +1 -1
  27. package/client/dist/assets/{RepositoryScopeSelector-hPGZNRBm.js → RepositoryScopeSelector-C2mvWBQ6.js} +1 -1
  28. package/client/dist/assets/{ReviewPacketPage-DcOq-UTA.js → ReviewPacketPage-CrAf-WDy.js} +2 -2
  29. package/client/dist/assets/TemplatePreviewModal-C7DordpN.js +1 -0
  30. package/client/dist/assets/{TicketDetailModalContext-DAK-NoK6.js → TicketDetailModalContext-B-DySpKL.js} +1 -1
  31. package/client/dist/assets/{Trans-DEbgkuAY.js → Trans-D3AfDylf.js} +1 -1
  32. package/client/dist/assets/agentRuntime-BeUb3g9g.js +1 -0
  33. package/client/dist/assets/agentRuntime-Bg9tbmqm.js +1 -0
  34. package/client/dist/assets/agentRuntime-D-GJVGkj.js +1 -0
  35. package/client/dist/assets/agentRuntime-D2__CVI_.js +1 -0
  36. package/client/dist/assets/agentRuntime-D35dGVOP.js +1 -0
  37. package/client/dist/assets/agentRuntime-DGz_IqKW.js +1 -0
  38. package/client/dist/assets/agentRuntime-O1liDt6G.js +1 -0
  39. package/client/dist/assets/agentRuntime-hInH9Fzj.js +1 -0
  40. package/client/dist/assets/agentstudio-B2CTtQgZ.js +1 -0
  41. package/client/dist/assets/agentstudio-BWAKeGgB.js +1 -0
  42. package/client/dist/assets/{agentstudio-DR7doNBV.js → agentstudio-Cja8Sjcp.js} +1 -1
  43. package/client/dist/assets/agentstudio-DtfPcr99.js +1 -0
  44. package/client/dist/assets/agentstudio-QdAJIDef.js +1 -0
  45. package/client/dist/assets/agentstudio-X70BKf6u.js +1 -0
  46. package/client/dist/assets/agentstudio-fLXpRGIi.js +1 -0
  47. package/client/dist/assets/agentstudio-qXKqVnWS.js +1 -0
  48. package/client/dist/assets/{analytics-jzCkOec3.js → analytics-B1DIQd4m.js} +1 -1
  49. package/client/dist/assets/{analytics-CoEzWPx4.js → analytics-BAIZ9vE_.js} +1 -1
  50. package/client/dist/assets/{analytics-DjLlE7jS.js → analytics-BTqgmgBd.js} +1 -1
  51. package/client/dist/assets/analytics-BWynXPEm.js +1 -0
  52. package/client/dist/assets/{analytics-nZIjjtCc.js → analytics-DGcUsQ44.js} +1 -1
  53. package/client/dist/assets/{analytics-BNgZ1Nj7.js → analytics-GnSnpJ4W.js} +1 -1
  54. package/client/dist/assets/{analytics-DFh5lSOl.js → analytics-TWgYaoO0.js} +1 -1
  55. package/client/dist/assets/{analytics-DZp-DS2U.js → analytics-kJy6Tuko.js} +1 -1
  56. package/client/dist/assets/builder-C0FyvM83.js +1 -0
  57. package/client/dist/assets/builder-C1neIYGR.js +1 -0
  58. package/client/dist/assets/builder-CvnFm0im.js +1 -0
  59. package/client/dist/assets/builder-CzW5ovyI.js +1 -0
  60. package/client/dist/assets/builder-D06L7iPy.js +1 -0
  61. package/client/dist/assets/builder-DGETbtZj.js +1 -0
  62. package/client/dist/assets/builder-DXEJUlC0.js +1 -0
  63. package/client/dist/assets/builder-DyQperXU.js +1 -0
  64. package/client/dist/assets/common-BCK7c9Pv.js +1 -0
  65. package/client/dist/assets/common-C0BOdeNi.js +1 -0
  66. package/client/dist/assets/common-C4Yvvhp6.js +1 -0
  67. package/client/dist/assets/{common-BrlwEnL7.js → common-DmsclwjP.js} +1 -1
  68. package/client/dist/assets/common-DpLWwgI1.js +1 -0
  69. package/client/dist/assets/common-OCvl3c8t.js +1 -0
  70. package/client/dist/assets/common-c0aujEZC.js +1 -0
  71. package/client/dist/assets/common-od8WThlf.js +1 -0
  72. package/client/dist/assets/dashboard-B1ndRHuC.js +1 -0
  73. package/client/dist/assets/dashboard-BX7KXiqA.js +1 -0
  74. package/client/dist/assets/dashboard-B_BSNxcN.js +1 -0
  75. package/client/dist/assets/dashboard-CCeFN7-V.js +1 -0
  76. package/client/dist/assets/dashboard-CRl0WtFJ.js +1 -0
  77. package/client/dist/assets/dashboard-XGdQ5mjw.js +1 -0
  78. package/client/dist/assets/dashboard-_oltA6Jd.js +1 -0
  79. package/client/dist/assets/dashboard-bAuf5KVk.js +1 -0
  80. package/client/dist/assets/{formatDistanceToNow-Cc2u5FwQ.js → formatDistanceToNow-aBss1Nai.js} +1 -1
  81. package/client/dist/assets/{getTimezoneOffsetInMilliseconds-BHm2U-w1.js → getTimezoneOffsetInMilliseconds-DOGj1Mfz.js} +1 -1
  82. package/client/dist/assets/index-BS7KCWkV.css +2 -0
  83. package/client/dist/assets/{index-Cxb288Rj.js → index-C4Mv6tV6.js} +32 -32
  84. package/client/dist/assets/{jira-api-DrGxiD9p.js → jira-api-BYbEPlkr.js} +1 -1
  85. package/client/dist/assets/{jobs-DSp9DoD_.js → jobs-6_-r75yC.js} +1 -1
  86. package/client/dist/assets/{jobs-C6qmvUAi.js → jobs-B1yqyId5.js} +1 -1
  87. package/client/dist/assets/{jobs-DoFaEl9g.js → jobs-BFuV7ttH.js} +1 -1
  88. package/client/dist/assets/{jobs-DTQO08nJ.js → jobs-BKa8LuwA.js} +1 -1
  89. package/client/dist/assets/{jobs-DrF8Do8s.js → jobs-BKiK-ZWh.js} +1 -1
  90. package/client/dist/assets/{jobs-DLHdDkHc.js → jobs-DmKV7b7d.js} +1 -1
  91. package/client/dist/assets/{jobs-C9j2PuwW.js → jobs-KG4Sn12X.js} +1 -1
  92. package/client/dist/assets/{jobs-Dpw6AEOP.js → jobs-pPv4KWjb.js} +1 -1
  93. package/client/dist/assets/loop-layout-BF8xMiNv.js +7 -0
  94. package/client/dist/assets/loops-B4_D-nbg.js +1 -0
  95. package/client/dist/assets/loops-BJDY9FTh.js +1 -0
  96. package/client/dist/assets/loops-BO3V8244.js +1 -0
  97. package/client/dist/assets/loops-C-hZK8pf.js +1 -0
  98. package/client/dist/assets/loops-CDOWZ0ci.js +1 -0
  99. package/client/dist/assets/loops-Dv849ckF.js +1 -0
  100. package/client/dist/assets/loops-Q9LIgGkq.js +1 -0
  101. package/client/dist/assets/loops-eUnCfLjC.js +1 -0
  102. package/client/dist/assets/{project-repositories-9Wzs0coQ.js → project-repositories-CSnfzUpg.js} +1 -1
  103. package/client/dist/assets/settings-3o4Ntzi5.js +1 -0
  104. package/client/dist/assets/settings-B97jlkwD.js +1 -0
  105. package/client/dist/assets/settings-BTaT_bsS.js +1 -0
  106. package/client/dist/assets/settings-CT8w7WiC.js +1 -0
  107. package/client/dist/assets/settings-Cvr8_tvh.js +1 -0
  108. package/client/dist/assets/settings-Dn1qgAC8.js +1 -0
  109. package/client/dist/assets/settings-EShDdg4J.js +1 -0
  110. package/client/dist/assets/settings-tfLhQZRN.js +1 -0
  111. package/client/dist/assets/{setup-Dwzt5nO1.js → setup-CBMu3tqH.js} +1 -1
  112. package/client/dist/assets/{setup-B5FHuxvB.js → setup-CPh-e6J2.js} +1 -1
  113. package/client/dist/assets/{setup-DpqzaEEA.js → setup-CRKLp_ke.js} +1 -1
  114. package/client/dist/assets/{setup-CROyqD5N.js → setup-Cy302v4J.js} +1 -1
  115. package/client/dist/assets/{setup-C9Fy9PKQ.js → setup-D681vTPf.js} +1 -1
  116. package/client/dist/assets/{setup-BihzXadx.js → setup-DYK0VBkE.js} +1 -1
  117. package/client/dist/assets/{setup-BtC6Hg4K.js → setup-KAuiIiVs.js} +1 -1
  118. package/client/dist/assets/{setup-zLEDnG7N.js → setup-OGX-oCfI.js} +1 -1
  119. package/client/dist/assets/{spending-T5GM7wpn.js → spending-HBSk-6jv.js} +1 -1
  120. package/client/dist/assets/{useDesktop-QogiN0zR.js → useDesktop-0unHDBJJ.js} +1 -1
  121. package/client/dist/assets/useRuntimeRuns-BN1rhyEm.js +1 -0
  122. package/client/dist/assets/{useSharedWebSocket-Dz-HI6De.js → useSharedWebSocket-BZMrX4jr.js} +2 -2
  123. package/client/dist/index.html +25 -25
  124. package/docs/agent-live-steering.md +16 -0
  125. package/docs/cli.md +7 -7
  126. package/docs/codex.md +2 -2
  127. package/docs/customizing.md +1 -1
  128. package/docs/gemini.md +1 -1
  129. package/docs/getting-started.md +1 -1
  130. package/docs/guide/de/integrations/7-local-engines.md +1 -1
  131. package/docs/guide/de/pipeline/1-rails-and-jobs.md +8 -6
  132. package/docs/guide/de/pipeline/2-the-job-detail-view.md +11 -2
  133. package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +2 -2
  134. package/docs/guide/de/pipeline/5-the-loop-builder.md +24 -5
  135. package/docs/guide/en/integrations/7-local-engines.md +1 -1
  136. package/docs/guide/en/pipeline/1-rails-and-jobs.md +8 -6
  137. package/docs/guide/en/pipeline/2-the-job-detail-view.md +11 -2
  138. package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +2 -2
  139. package/docs/guide/en/pipeline/5-the-loop-builder.md +34 -5
  140. package/docs/guide/en/settings/3-pipeline-telemetry-and-diagnostics.md +1 -1
  141. package/docs/guide/es/integrations/7-local-engines.md +1 -1
  142. package/docs/guide/es/pipeline/1-rails-and-jobs.md +8 -6
  143. package/docs/guide/es/pipeline/2-the-job-detail-view.md +11 -2
  144. package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +2 -2
  145. package/docs/guide/es/pipeline/5-the-loop-builder.md +30 -5
  146. package/docs/guide/es/settings/3-pipeline-telemetry-and-diagnostics.md +1 -2
  147. package/docs/guide/fr/integrations/7-local-engines.md +1 -1
  148. package/docs/guide/fr/pipeline/1-rails-and-jobs.md +8 -6
  149. package/docs/guide/fr/pipeline/2-the-job-detail-view.md +11 -2
  150. package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +2 -2
  151. package/docs/guide/fr/pipeline/5-the-loop-builder.md +24 -5
  152. package/docs/guide/it/integrations/7-local-engines.md +1 -1
  153. package/docs/guide/it/pipeline/1-rails-and-jobs.md +8 -6
  154. package/docs/guide/it/pipeline/2-the-job-detail-view.md +11 -2
  155. package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +2 -2
  156. package/docs/guide/it/pipeline/5-the-loop-builder.md +24 -5
  157. package/docs/guide/ja/integrations/7-local-engines.md +1 -1
  158. package/docs/guide/ja/pipeline/1-rails-and-jobs.md +8 -6
  159. package/docs/guide/ja/pipeline/2-the-job-detail-view.md +11 -2
  160. package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +2 -2
  161. package/docs/guide/ja/pipeline/5-the-loop-builder.md +24 -5
  162. package/docs/guide/pt/integrations/7-local-engines.md +1 -1
  163. package/docs/guide/pt/pipeline/1-rails-and-jobs.md +8 -6
  164. package/docs/guide/pt/pipeline/2-the-job-detail-view.md +11 -2
  165. package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +2 -2
  166. package/docs/guide/pt/pipeline/5-the-loop-builder.md +24 -5
  167. package/docs/guide/zh/integrations/7-local-engines.md +1 -1
  168. package/docs/guide/zh/pipeline/1-rails-and-jobs.md +8 -6
  169. package/docs/guide/zh/pipeline/2-the-job-detail-view.md +11 -2
  170. package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +2 -2
  171. package/docs/guide/zh/pipeline/5-the-loop-builder.md +24 -5
  172. package/docs/internals/api-reference.md +2 -2
  173. package/docs/internals/ci-performance.md +71 -0
  174. package/docs/internals/companion-rails-as-loops-contract.md +4 -3
  175. package/docs/internals/configuration.md +3 -3
  176. package/docs/internals/core-runtime-updates.md +3 -2
  177. package/docs/internals/interactive-jobs.md +2 -2
  178. package/docs/internals/loop-step-log-explorer.md +42 -0
  179. package/docs/internals/mission-rail-cards.md +1 -1
  180. package/docs/internals/operations-runbook.md +22 -0
  181. package/docs/internals/programmatic-agent-runtime.md +130 -7
  182. package/docs/internals/project-builder.md +35 -16
  183. package/docs/internals/source-map.md +48 -2
  184. package/docs/kimi.md +2 -2
  185. package/docs/local-providers.md +1 -1
  186. package/docs/running-pipelines.md +26 -18
  187. package/docs/tracking-cost.md +10 -1
  188. package/package.json +2 -1
  189. package/server/dist/core-compat.js +8 -3
  190. package/server/dist/core-execution.js +49 -3
  191. package/server/dist/db/migrations.js +101 -0
  192. package/server/dist/desktop-db.js +28 -0
  193. package/server/dist/desktop-router.js +2 -0
  194. package/server/dist/mcp/guide.js +6 -3
  195. package/server/dist/mcp/tools/jobs.js +14 -1
  196. package/server/dist/mcp/tools/loops.js +17 -8
  197. package/server/dist/mcp/tools/rails.js +3 -3
  198. package/server/dist/modules/agent-runtime/runtime/agent-runtime-bridge.js +313 -9
  199. package/server/dist/modules/agent-runtime/runtime/agent-runtime-controls-router.js +34 -1
  200. package/server/dist/modules/agent-runtime/runtime/agent-runtime-controls.js +203 -21
  201. package/server/dist/modules/agent-runtime/runtime/agent-runtime-effective-config.js +46 -1
  202. package/server/dist/modules/agent-runtime/runtime/agent-runtime-engines.js +10 -0
  203. package/server/dist/modules/agent-runtime/runtime/agent-runtime-loader.js +68 -3
  204. package/server/dist/modules/agent-runtime/runtime/agent-runtime-metrics.js +16 -8
  205. package/server/dist/modules/agent-runtime/runtime/agent-runtime-package-gc.js +81 -0
  206. package/server/dist/modules/agent-runtime/runtime/agent-runtime-package-lock.js +37 -0
  207. package/server/dist/modules/agent-runtime/runtime/agent-runtime-package.js +30 -24
  208. package/server/dist/modules/agent-runtime/runtime/agent-runtime-retention-host.js +87 -0
  209. package/server/dist/modules/agent-runtime/runtime/agent-runtime-retention-quarantine.js +231 -0
  210. package/server/dist/modules/agent-runtime/runtime/agent-runtime-retention-records.js +32 -0
  211. package/server/dist/modules/agent-runtime/runtime/agent-runtime-retention.js +102 -0
  212. package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings-router.js +12 -7
  213. package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings.js +57 -13
  214. package/server/dist/modules/agents/runtime/agent-catalog.js +32 -0
  215. package/server/dist/modules/agents/runtime/agent-refine-manager.js +12 -0
  216. package/server/dist/modules/agents/runtime/agent-role-descriptor.js +64 -0
  217. package/server/dist/modules/agents/runtime/profiles-router.js +26 -34
  218. package/server/dist/modules/builder/runtime/milestone-chain.js +121 -73
  219. package/server/dist/modules/delivery/runtime/definition-fork.js +158 -0
  220. package/server/dist/modules/delivery/runtime/delivery-evidence.js +56 -10
  221. package/server/dist/modules/delivery/runtime/isolated-settlement-reconstruction.js +99 -0
  222. package/server/dist/modules/delivery/runtime/isolated-settlement-store.js +53 -0
  223. package/server/dist/modules/delivery/runtime/multi-repo-execution-store.js +3 -1
  224. package/server/dist/modules/delivery/runtime/rail-isolated-launch.js +388 -203
  225. package/server/dist/modules/delivery/runtime/rail-launch-parser.js +3 -2
  226. package/server/dist/modules/delivery/runtime/rail-pr-store.js +6 -1
  227. package/server/dist/modules/delivery/runtime/rails-router.js +66 -10
  228. package/server/dist/modules/execution/runtime/queue-manager.js +11 -2
  229. package/server/dist/modules/loops/runtime/builtin-loops.js +70 -0
  230. package/server/dist/modules/loops/runtime/definition-cancellation.js +31 -0
  231. package/server/dist/modules/loops/runtime/legacy-launch-telemetry.js +78 -0
  232. package/server/dist/modules/loops/runtime/loop-command-catalog.js +13 -12
  233. package/server/dist/modules/loops/runtime/loop-compat.js +219 -0
  234. package/server/dist/modules/loops/runtime/loop-core-factory.js +42 -0
  235. package/server/dist/modules/loops/runtime/loop-definition-controls.js +48 -0
  236. package/server/dist/modules/loops/runtime/loop-definition-events.js +145 -0
  237. package/server/dist/modules/loops/runtime/loop-definition-recovery.js +106 -0
  238. package/server/dist/modules/loops/runtime/loop-definition-run.js +36 -0
  239. package/server/dist/modules/loops/runtime/loop-definition.js +246 -0
  240. package/server/dist/modules/loops/runtime/loop-effect.js +10 -1
  241. package/server/dist/modules/loops/runtime/loop-executors.js +63 -3
  242. package/server/dist/modules/loops/runtime/loop-factory.js +35 -15
  243. package/server/dist/modules/loops/runtime/loop-graph.js +84 -8
  244. package/server/dist/modules/loops/runtime/loop-migration.js +36 -0
  245. package/server/dist/modules/loops/runtime/loop-preview.js +10 -0
  246. package/server/dist/modules/loops/runtime/loop-run-manager.js +206 -13
  247. package/server/dist/modules/loops/runtime/loop-runs-store.js +271 -7
  248. package/server/dist/modules/loops/runtime/loop-templates.js +205 -45
  249. package/server/dist/modules/loops/runtime/loops-router.js +246 -29
  250. package/server/dist/modules/loops/runtime/loops-store.js +140 -20
  251. package/server/dist/modules/missions/runtime/agent-operator-prompt.js +14 -11
  252. package/server/dist/modules/specs/runtime/spec-addenda.js +28 -0
  253. package/server/dist/project-registry.js +87 -51
  254. package/server/dist/project-router-jobs.js +17 -6
  255. package/server/dist/project-router-loop-runs.js +200 -0
  256. package/server/dist/project-router-spending.js +17 -0
  257. package/server/dist/project-router.js +8 -6
  258. package/server/dist/schemas/agent-runtime.schema.json +93 -1
  259. package/server/dist/schemas/workflow-definition.schema.json +312 -0
  260. package/server/dist/vitest-setup.js +22 -0
  261. package/server/dist/worktree-overlay.js +1 -1
  262. package/client/dist/assets/AgentsPage-DfHWgP_x.js +0 -87
  263. package/client/dist/assets/DesktopAnalyticsPage-tc0p4jJW.js +0 -1
  264. package/client/dist/assets/InteractiveJobComposer-DFPpdg2D.js +0 -19
  265. package/client/dist/assets/JobDetailModal-BdOv-l-M.js +0 -1
  266. package/client/dist/assets/LoopBuilderPage-BemvUOxy.js +0 -7
  267. package/client/dist/assets/LoopPreviewModal-C6hNAeYN.js +0 -1
  268. package/client/dist/assets/LoopsPage-BZr0quvh.js +0 -1
  269. package/client/dist/assets/TemplatePreviewModal-Cejcquah.js +0 -1
  270. package/client/dist/assets/agentRuntime-BUimiX__.js +0 -1
  271. package/client/dist/assets/agentRuntime-BcN97sAB.js +0 -1
  272. package/client/dist/assets/agentRuntime-Ckyg-ahT.js +0 -1
  273. package/client/dist/assets/agentRuntime-DJCwyX4t.js +0 -1
  274. package/client/dist/assets/agentRuntime-DVzPJOl0.js +0 -1
  275. package/client/dist/assets/agentRuntime-V9AZTG3c.js +0 -1
  276. package/client/dist/assets/agentRuntime-bAAjw1vw.js +0 -1
  277. package/client/dist/assets/agentRuntime-v4qKAYH-.js +0 -1
  278. package/client/dist/assets/agentstudio-BNUth0uj.js +0 -1
  279. package/client/dist/assets/agentstudio-BNdB5hkr.js +0 -1
  280. package/client/dist/assets/agentstudio-C7-bt8FO.js +0 -1
  281. package/client/dist/assets/agentstudio-C8uNchpV.js +0 -1
  282. package/client/dist/assets/agentstudio-CKabyMlg.js +0 -1
  283. package/client/dist/assets/agentstudio-CN2pokQu.js +0 -1
  284. package/client/dist/assets/agentstudio-y2dVDXeM.js +0 -1
  285. package/client/dist/assets/analytics-BlypLLR6.js +0 -1
  286. package/client/dist/assets/builder-765NeYTp.js +0 -1
  287. package/client/dist/assets/builder-8MG3V6ea.js +0 -1
  288. package/client/dist/assets/builder-B-1UBs5K.js +0 -1
  289. package/client/dist/assets/builder-BTiGnPT0.js +0 -1
  290. package/client/dist/assets/builder-Cx9Rz-7u.js +0 -1
  291. package/client/dist/assets/builder-DKFMELBl.js +0 -1
  292. package/client/dist/assets/builder-OcmKrC0h.js +0 -1
  293. package/client/dist/assets/builder-P9qVBXFZ.js +0 -1
  294. package/client/dist/assets/common-B5AZNYMH.js +0 -1
  295. package/client/dist/assets/common-BFZ0c_vN.js +0 -1
  296. package/client/dist/assets/common-BttQx3z4.js +0 -1
  297. package/client/dist/assets/common-CM65k_-e.js +0 -1
  298. package/client/dist/assets/common-D4mvFFlu.js +0 -1
  299. package/client/dist/assets/common-TZ9Ny96S.js +0 -1
  300. package/client/dist/assets/common-nFpSF4GC.js +0 -1
  301. package/client/dist/assets/dashboard-B9uWNGO2.js +0 -1
  302. package/client/dist/assets/dashboard-BIwmO9wc.js +0 -1
  303. package/client/dist/assets/dashboard-BV4vOZkR.js +0 -1
  304. package/client/dist/assets/dashboard-Bf6MPVsM.js +0 -1
  305. package/client/dist/assets/dashboard-C8klWVvZ.js +0 -1
  306. package/client/dist/assets/dashboard-D1ORhPF0.js +0 -1
  307. package/client/dist/assets/dashboard-DSubvs9x.js +0 -1
  308. package/client/dist/assets/dashboard-px_vlRx_.js +0 -1
  309. package/client/dist/assets/index-C51x61Bz.css +0 -2
  310. package/client/dist/assets/loops-B7YpGizO.js +0 -1
  311. package/client/dist/assets/loops-BomD2J-h.js +0 -1
  312. package/client/dist/assets/loops-BrQHSQw3.js +0 -1
  313. package/client/dist/assets/loops-BvBwvTPA.js +0 -1
  314. package/client/dist/assets/loops-CODk6Slz.js +0 -1
  315. package/client/dist/assets/loops-DC6k-Ym-.js +0 -1
  316. package/client/dist/assets/loops-DSEg8-uY.js +0 -1
  317. package/client/dist/assets/loops-DhCoXD_v.js +0 -1
  318. package/client/dist/assets/settings-BsehKpty.js +0 -1
  319. package/client/dist/assets/settings-CQWob3SB.js +0 -1
  320. package/client/dist/assets/settings-CgCl0hzy.js +0 -1
  321. package/client/dist/assets/settings-DLRLd22L.js +0 -1
  322. package/client/dist/assets/settings-Dn5prAFl.js +0 -1
  323. package/client/dist/assets/settings-HZSu-K4l.js +0 -1
  324. package/client/dist/assets/settings-p4OVIyRh.js +0 -1
  325. package/client/dist/assets/settings-rddaldUp.js +0 -1
  326. package/client/dist/assets/useRuntimeRuns-Dqmz9fS9.js +0 -1
  327. package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +0 -84
  328. package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +0 -126
  329. package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +0 -114
  330. package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +0 -84
  331. package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +0 -84
  332. package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +0 -84
  333. package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +0 -84
  334. package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +0 -84
  335. package/server/dist/modules/loops/runtime/loop-templates-ported.js +0 -675
  336. /package/client/dist/assets/{LoopBuilderPage-DtxX27Jz.css → loop-layout-DtxX27Jz.css} +0 -0
@@ -1,5 +1,20 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.saveDefinitionRun = saveDefinitionRun;
7
+ exports.readDefinitionRun = readDefinitionRun;
8
+ exports.recordDefinitionCheckpoint = recordDefinitionCheckpoint;
9
+ exports.markDefinitionRestart = markDefinitionRestart;
10
+ exports.definitionRepositoryMounts = definitionRepositoryMounts;
11
+ exports.claimDefinitionExecution = claimDefinitionExecution;
12
+ exports.readDefinitionSuccessor = readDefinitionSuccessor;
13
+ exports.readDefinitionForkTarget = readDefinitionForkTarget;
14
+ exports.releaseDefinitionExecution = releaseDefinitionExecution;
15
+ exports.readDefinitionExecutionClaim = readDefinitionExecutionClaim;
16
+ exports.readDefinitionLineage = readDefinitionLineage;
17
+ exports.linkDefinitionFork = linkDefinitionFork;
3
18
  exports.createLoopRun = createLoopRun;
4
19
  exports.finishLoopRunAndJob = finishLoopRunAndJob;
5
20
  exports.listPendingLoopTerminalRecoveries = listPendingLoopTerminalRecoveries;
@@ -24,6 +39,218 @@ exports.listActiveLoopRuns = listActiveLoopRuns;
24
39
  exports.listLoopRuns = listLoopRuns;
25
40
  exports.countRunningForLoop = countRunningForLoop;
26
41
  exports.reconcileOrphanLoopRuns = reconcileOrphanLoopRuns;
42
+ const agent_runtime_retention_records_1 = require("../../agent-runtime/runtime/agent-runtime-retention-records");
43
+ /**
44
+ * Loop runs store — per-project record (jobs.sqlite `loop_runs`) of each
45
+ * executed loop. The manager creates a row at launch, updates counters as it
46
+ * iterates, and finalises it at the end. Powers loop analytics + the
47
+ * active derived state (a loop is active iff a row here has status='running'
48
+ * or status='paused').
49
+ */
50
+ const path_1 = __importDefault(require("path"));
51
+ const node_fs_1 = require("node:fs");
52
+ function frozenJson(value) {
53
+ const serialized = JSON.stringify(value, (_key, item) => {
54
+ if (typeof item === 'function' || typeof item === 'symbol' || typeof item === 'bigint' || typeof item === 'number' && !Number.isFinite(item))
55
+ throw new Error('Durable workflow inputs must contain only JSON data');
56
+ return item;
57
+ });
58
+ if (!serialized || Buffer.byteLength(serialized) > 4 * 1024 * 1024)
59
+ throw new Error('Durable workflow inputs exceed 4 MiB');
60
+ const sort = (input) => Array.isArray(input) ? input.map(sort) : input && typeof input === 'object'
61
+ ? Object.fromEntries(Object.entries(input).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, item]) => [key, sort(item)])) : input;
62
+ return JSON.stringify(sort(JSON.parse(serialized)));
63
+ }
64
+ /** Freeze launch data before spawn; preparation may add fields, never replace them. */
65
+ function saveDefinitionRun(db, runId, input) {
66
+ return db.transaction(() => {
67
+ const row = getLoopRun(db, runId);
68
+ if (!row || row.engine_version !== null && row.engine_version !== undefined && row.engine_version !== 2)
69
+ throw new Error('Definition run is missing or belongs to another engine');
70
+ const { request, ...fields } = input;
71
+ const requestJson = request ? frozenJson({ ...request, runId }) : row.run_request_json;
72
+ if (!requestJson || row.run_request_json && row.run_request_json !== requestJson)
73
+ throw new Error('Frozen loop request cannot change');
74
+ const normalized = JSON.parse(requestJson);
75
+ if (normalized.projectId !== row.project_id || normalized.loopId !== row.loop_id)
76
+ throw new Error('Frozen loop request belongs to another project or loop');
77
+ const prior = JSON.parse(row.runtime_metadata_json ?? '{"source":"definition"}');
78
+ for (const [key, value] of Object.entries(fields)) {
79
+ if (value !== undefined && key in prior && frozenJson(prior[key]) !== frozenJson(value))
80
+ throw new Error('Frozen Core metadata cannot change: ' + key);
81
+ }
82
+ const metadata = { ...prior, ...JSON.parse(frozenJson(fields)) };
83
+ if (metadata.source !== 'definition' || metadata.definitionHash !== undefined && !/^[a-f0-9]{64}$/.test(metadata.definitionHash))
84
+ throw new Error('Invalid Core definition identity');
85
+ db.prepare('UPDATE loop_runs SET engine_version=2,run_request_json=?,runtime_metadata_json=? WHERE id=?').run(requestJson, frozenJson(metadata), runId);
86
+ return { row: getLoopRun(db, runId), request: normalized, metadata };
87
+ })();
88
+ }
89
+ function readDefinitionRun(db, runId) {
90
+ const row = getLoopRun(db, runId);
91
+ if (!row || row.engine_version !== 2 || !row.run_request_json)
92
+ return undefined;
93
+ const request = JSON.parse(row.run_request_json), metadata = JSON.parse(row.runtime_metadata_json ?? '{"source":"definition"}');
94
+ if (request.runId !== runId || request.projectId !== row.project_id || request.loopId !== row.loop_id || metadata.source !== 'definition')
95
+ throw new Error('Frozen workflow ownership is inconsistent');
96
+ return { row, request, metadata };
97
+ }
98
+ /** The projection cursor is independent of the aggregate accounting totals. */
99
+ function recordDefinitionCheckpoint(db, runId, checkpoint) {
100
+ for (const value of [checkpoint.revision, checkpoint.eventCursor])
101
+ if (value !== undefined && (!Number.isSafeInteger(value) || value < 0))
102
+ throw new Error('Core checkpoint cursors must be nonnegative integers');
103
+ const serialized = frozenJson(checkpoint);
104
+ db.transaction(() => {
105
+ const row = readDefinitionRun(db, runId)?.row;
106
+ if (!row)
107
+ throw new Error('Frozen definition run is missing');
108
+ if (checkpoint.revision !== undefined && checkpoint.revision < (row.core_revision ?? 0) || checkpoint.eventCursor !== undefined && checkpoint.eventCursor < (row.core_event_cursor ?? 0))
109
+ return;
110
+ db.prepare('UPDATE loop_runs SET core_revision=?,core_event_cursor=?,runtime_status_json=? WHERE id=?')
111
+ .run(checkpoint.revision ?? row.core_revision ?? null, checkpoint.eventCursor ?? row.core_event_cursor ?? null, serialized, runId);
112
+ })();
113
+ }
114
+ /** Startup preserves the job and launch ownership; no terminal callback is queued. */
115
+ function markDefinitionRestart(db, runId, checkpoint = {}) {
116
+ db.transaction(() => {
117
+ if (!readDefinitionRun(db, runId))
118
+ throw new Error('Frozen definition run is missing');
119
+ recordDefinitionCheckpoint(db, runId, checkpoint);
120
+ db.prepare("UPDATE loop_runs SET status='paused',final_outcome=NULL,finished_at=NULL,restart_reason='restart' WHERE id=? AND status IN ('running','paused')").run(runId);
121
+ })();
122
+ }
123
+ function normalizeMount(mount) {
124
+ const absolute = path_1.default.resolve(mount);
125
+ const resolved = (0, node_fs_1.existsSync)(absolute) ? (0, node_fs_1.realpathSync)(absolute) : absolute;
126
+ const trimmed = resolved === path_1.default.parse(resolved).root ? resolved : resolved.replace(/[\\/]+$/, '');
127
+ return process.platform === 'win32' ? trimmed.toLowerCase() : trimmed;
128
+ }
129
+ function mountsOverlap(a, b) {
130
+ const contains = (parent, child) => {
131
+ const relative = path_1.default.relative(parent, child);
132
+ return relative === '' || !path_1.default.isAbsolute(relative) && relative !== '..' && !relative.startsWith('..' + path_1.default.sep);
133
+ };
134
+ return contains(a, b) || contains(b, a);
135
+ }
136
+ function parseMounts(raw) {
137
+ const parsed = JSON.parse(raw);
138
+ if (!Array.isArray(parsed) || parsed.some(item => typeof item !== 'string' || !path_1.default.isAbsolute(item)))
139
+ throw new Error('Invalid saved definition execution mounts');
140
+ return parsed;
141
+ }
142
+ /** Direct fork ancestry of a run: itself, its parents up the fork_of chain and every descendant. */
143
+ function definitionLineageIds(db, runId, parentRunId) {
144
+ const lineage = new Set();
145
+ const parents = db.prepare('SELECT fork_of FROM loop_runs WHERE id = ?');
146
+ const children = db.prepare('SELECT id FROM loop_runs WHERE fork_of = ?');
147
+ const queue = [runId, ...(parentRunId ? [parentRunId] : [])];
148
+ while (queue.length) {
149
+ const current = queue.shift();
150
+ if (lineage.has(current))
151
+ continue;
152
+ lineage.add(current);
153
+ const parent = parents.get(current)?.fork_of;
154
+ if (parent && !lineage.has(parent))
155
+ queue.push(parent);
156
+ for (const child of children.all(current))
157
+ if (!lineage.has(child.id))
158
+ queue.push(child.id);
159
+ }
160
+ return lineage;
161
+ }
162
+ /** The checkouts a frozen request may write to. Nested paths share a mount. */
163
+ function definitionRepositoryMounts(request) {
164
+ const mounts = [
165
+ ...(request.executionManifest?.repositories.map(repository => repository.worktreePath) ?? []),
166
+ ...(request.isolation ? [request.isolation.worktreePath] : []),
167
+ ...(request.executionManifest ? [] : [request.repoDir ?? request.cwd]),
168
+ ].filter((mount) => typeof mount === 'string' && mount.length > 0);
169
+ return [...new Set(mounts.map(normalizeMount))].sort();
170
+ }
171
+ /**
172
+ * Synchronous, atomic admission for one Core process over a worktree. A live
173
+ * claim of another run that overlaps any repository mount rejects: a parent
174
+ * and its fork share the checkout, and two owners of the same run are never
175
+ * allowed. Paused rows are not claims; only a resident process holds one, and
176
+ * settlement, cancellation and restart reconciliation release it.
177
+ */
178
+ function claimDefinitionExecution(db, runId, claim) {
179
+ if (!runId || !claim.owner)
180
+ throw new Error('Execution claims require a run and an owner');
181
+ const mounts = [...new Set(claim.repositoryMounts.map(normalizeMount))].sort();
182
+ return db.transaction(() => {
183
+ const collecting = claim.owner.startsWith('retention:') || claim.owner.startsWith('retention-recovery:');
184
+ if ((0, agent_runtime_retention_records_1.readRuntimeExpiration)(db, runId) && !claim.owner.startsWith('retention-recovery:'))
185
+ return { ok: false, reason: 'expired', conflictingRunId: runId };
186
+ const successor = readDefinitionSuccessor(db, runId);
187
+ if (successor && !(collecting && (0, agent_runtime_retention_records_1.readRuntimeExpiration)(db, successor)))
188
+ return { ok: false, reason: 'lineage_conflict', conflictingRunId: successor };
189
+ const pendingFork = readDefinitionForkTarget(db, runId);
190
+ if (pendingFork && !claim.owner.startsWith('fork:') && !(collecting && (0, agent_runtime_retention_records_1.readRuntimeExpiration)(db, pendingFork)))
191
+ return { ok: false, reason: 'lineage_conflict', conflictingRunId: pendingFork };
192
+ const existing = db.prepare('SELECT run_id, owner, repository_mounts_json FROM definition_execution_claims WHERE run_id = ?').get(runId);
193
+ if (existing)
194
+ return { ok: false, reason: 'active_owner', conflictingRunId: runId };
195
+ if (mounts.length) {
196
+ const lineage = definitionLineageIds(db, runId, claim.parentRunId);
197
+ const live = db.prepare('SELECT run_id, owner, repository_mounts_json FROM definition_execution_claims ORDER BY claimed_at, run_id').all();
198
+ for (const row of live) {
199
+ const overlap = parseMounts(row.repository_mounts_json).some(mount => mounts.some(candidate => mountsOverlap(candidate, mount)));
200
+ if (!overlap)
201
+ continue;
202
+ return { ok: false, reason: lineage.has(row.run_id) ? 'lineage_conflict' : 'active_owner', conflictingRunId: row.run_id };
203
+ }
204
+ }
205
+ const at = new Date().toISOString();
206
+ db.prepare('INSERT INTO definition_execution_claims (run_id, owner, repository_mounts_json, claimed_at, heartbeat_at) VALUES (?, ?, ?, ?, ?)')
207
+ .run(runId, claim.owner, JSON.stringify(mounts), at, at);
208
+ return { ok: true, release: () => releaseDefinitionExecution(db, runId, claim.owner) };
209
+ })();
210
+ }
211
+ /** The historical run remains intact; only its child owns shared checkout effects. */
212
+ function readDefinitionSuccessor(db, runId) {
213
+ const row = db.prepare('SELECT child_run_id FROM definition_fork_operations WHERE source_run_id=? AND adopted=1').get(runId);
214
+ return row?.child_run_id;
215
+ }
216
+ function readDefinitionForkTarget(db, runId) {
217
+ return db.prepare('SELECT child_run_id FROM definition_fork_operations WHERE source_run_id=? ORDER BY adopted DESC,created_at LIMIT 1').get(runId)?.child_run_id;
218
+ }
219
+ /** Idempotent: only the owner that holds the claim can release it. */
220
+ function releaseDefinitionExecution(db, runId, owner) {
221
+ db.prepare('DELETE FROM definition_execution_claims WHERE run_id = ? AND owner = ?').run(runId, owner);
222
+ }
223
+ function readDefinitionExecutionClaim(db, runId) {
224
+ const row = db.prepare('SELECT * FROM definition_execution_claims WHERE run_id = ?').get(runId);
225
+ return row ? { runId: row.run_id, owner: row.owner, repositoryMounts: parseMounts(row.repository_mounts_json), claimedAt: row.claimed_at, heartbeatAt: row.heartbeat_at } : undefined;
226
+ }
227
+ function readDefinitionLineage(db, runId) {
228
+ const row = getLoopRun(db, runId);
229
+ let forkCut = null;
230
+ if (row?.fork_cut_json) {
231
+ try {
232
+ forkCut = JSON.parse(row.fork_cut_json);
233
+ }
234
+ catch {
235
+ forkCut = null;
236
+ }
237
+ }
238
+ const children = db.prepare('SELECT id FROM loop_runs WHERE fork_of = ? ORDER BY started_at, id').all(runId).map(child => child.id);
239
+ return { runId, forkOf: row?.fork_of ?? null, children, forkCut };
240
+ }
241
+ /** Persist fork ancestry and Core cut provenance on a NEW child row. The source row is never touched. */
242
+ function linkDefinitionFork(db, childRunId, link) {
243
+ db.transaction(() => {
244
+ const child = readDefinitionRun(db, childRunId);
245
+ if (!child)
246
+ throw new Error('Forked definition run is missing');
247
+ if (childRunId === link.forkOf || !getLoopRun(db, link.forkOf))
248
+ throw new Error('Fork source is missing or identical to the child');
249
+ if (child.row.fork_of && child.row.fork_of !== link.forkOf)
250
+ throw new Error('Fork ancestry cannot change');
251
+ db.prepare('UPDATE loop_runs SET fork_of = ?, fork_cut_json = ? WHERE id = ?').run(link.forkOf, frozenJson(link.forkCut), childRunId);
252
+ })();
253
+ }
27
254
  function createLoopRun(db, input) {
28
255
  db.prepare(`
29
256
  INSERT INTO loop_runs (
@@ -116,6 +343,7 @@ function listPendingLoopTerminalRecoveries(db) {
116
343
  SELECT run_id, payload, callback_completed, created_at
117
344
  FROM loop_terminal_recovery
118
345
  WHERE callback_completed = 0
346
+ AND NOT EXISTS (SELECT 1 FROM definition_fork_operations f WHERE f.source_run_id=loop_terminal_recovery.run_id AND f.adopted=1)
119
347
  ORDER BY created_at, run_id
120
348
  `).all();
121
349
  }
@@ -253,7 +481,7 @@ function pauseLoopRun(db, id, counters) {
253
481
  return getLoopRun(db, id);
254
482
  }
255
483
  function resumeLoopRun(db, id) {
256
- db.prepare(`UPDATE loop_runs SET status = 'running' WHERE id = ? AND status = 'paused'`).run(id);
484
+ db.prepare(`UPDATE loop_runs SET status = 'running', restart_reason = NULL WHERE id = ? AND status = 'paused'`).run(id);
257
485
  return getLoopRun(db, id);
258
486
  }
259
487
  function getLoopRun(db, id) {
@@ -300,17 +528,19 @@ function getRunEventCounts(db, runId) {
300
528
  }
301
529
  return { steps, lines };
302
530
  }
531
+ // Adopted parents stay in history but their child owns execution and edit guards.
532
+ const ownsLoopExecution = 'NOT EXISTS (SELECT 1 FROM definition_fork_operations AS fork WHERE fork.source_run_id = loop_runs.id AND fork.adopted = 1)';
303
533
  /** All currently-running loop runs for a project, straight from the DB (NOT the
304
534
  * in-memory rail map, which is cleared on every server restart). Authoritative
305
535
  * source for seeding the dashboard's live rail metrics after a refresh. */
306
536
  function listRunningLoopRuns(db, projectId) {
307
537
  return db
308
- .prepare("SELECT * FROM loop_runs WHERE project_id = ? AND status = 'running' ORDER BY started_at ASC")
538
+ .prepare(`SELECT * FROM loop_runs WHERE project_id = ? AND status = 'running' AND ${ownsLoopExecution} ORDER BY started_at ASC`)
309
539
  .all(projectId);
310
540
  }
311
541
  function listActiveLoopRuns(db, projectId) {
312
542
  return db
313
- .prepare("SELECT * FROM loop_runs WHERE project_id = ? AND status IN ('running','paused') ORDER BY started_at ASC")
543
+ .prepare(`SELECT * FROM loop_runs WHERE project_id = ? AND status IN ('running','paused') AND ${ownsLoopExecution} ORDER BY started_at ASC`)
314
544
  .all(projectId);
315
545
  }
316
546
  function listLoopRuns(db, projectId, limit = 100) {
@@ -323,7 +553,7 @@ function listLoopRuns(db, projectId, limit = 100) {
323
553
  * Running?" guard that blocks edit/delete of a loop while it executes. */
324
554
  function countRunningForLoop(db, loopId) {
325
555
  const row = db
326
- .prepare(`SELECT COUNT(*) AS n FROM loop_runs WHERE loop_id = ? AND status IN ('running','paused')`)
556
+ .prepare(`SELECT COUNT(*) AS n FROM loop_runs WHERE loop_id = ? AND status IN ('running','paused') AND ${ownsLoopExecution}`)
327
557
  .get(loopId);
328
558
  return row.n;
329
559
  }
@@ -334,12 +564,16 @@ function countRunningForLoop(db, loopId) {
334
564
  * not sweep those rows: LoopRunManager is the sole invocation authority, so
335
565
  * treating the accumulated step total as a second surface='job' invocation
336
566
  * would double-count spend. A paused row is active too: its resumable context
337
- * lived in the old process. Returns the number of loop rows reconciled. */
567
+ * lived in the old process. Execution claims of every active row are released
568
+ * in the same transaction. Returns the number of loop rows reconciled. */
338
569
  function reconcileOrphanLoopRuns(db, finishedAt,
339
570
  /** Compatibility only for pre-migration rows whose exact launch ticket set
340
571
  * was never persisted. New rows always use ticket_ids_json. */
341
- legacyTicketIdsByRun) {
572
+ legacyTicketIdsByRun, definitionStates) {
342
573
  const reconcile = db.transaction(() => {
574
+ // Admission can crash before allocating a run row, or after its terminal
575
+ // commit but before releasing the reservation. Neither has a live executor.
576
+ db.prepare("DELETE FROM definition_execution_claims WHERE run_id NOT IN (SELECT id FROM loop_runs WHERE status IN ('running','paused'))").run();
343
577
  const active = db.prepare(`
344
578
  SELECT * FROM loop_runs WHERE status IN ('running', 'paused')
345
579
  `).all();
@@ -366,7 +600,37 @@ legacyTicketIdsByRun) {
366
600
  VALUES (?, ?, 0)
367
601
  ON CONFLICT(run_id) DO NOTHING
368
602
  `);
603
+ // No process survived the restart: every execution claim of an active row is
604
+ // stale, whether the row is retained as paused or settled as failed.
605
+ const releaseClaim = db.prepare('DELETE FROM definition_execution_claims WHERE run_id = ?');
606
+ let reconciled = 0;
369
607
  for (const run of active) {
608
+ // Adoption already transferred execution/delivery ownership to the child.
609
+ // The parent's paused row is immutable history, not another orphan launch.
610
+ if (readDefinitionSuccessor(db, run.id)) {
611
+ releaseClaim.run(run.id);
612
+ continue;
613
+ }
614
+ reconciled += 1;
615
+ const probe = definitionStates?.get(run.id);
616
+ const lease = probe?.lease;
617
+ if (!lease?.active && probe?.coreStatus !== 'unavailable')
618
+ releaseClaim.run(run.id);
619
+ else if (!readDefinitionExecutionClaim(db, run.id)) {
620
+ const request = readDefinitionRun(db, run.id)?.request;
621
+ if (request) {
622
+ const claim = claimDefinitionExecution(db, run.id, { owner: `retained:${run.id}`, repositoryMounts: definitionRepositoryMounts(request) });
623
+ if (!claim.ok)
624
+ throw new Error(`Cannot reserve retained Core worktree: ${claim.conflictingRunId}`);
625
+ }
626
+ }
627
+ if (run.engine_version === 2 && run.run_request_json) {
628
+ const state = definitionStates?.get(run.id);
629
+ if (state !== null && (!state?.status || ['running', 'paused', 'interrupted'].includes(state.status))) {
630
+ markDefinitionRestart(db, run.id, state ?? { status: 'unavailable', reason: 'Original Core status could not be read' });
631
+ continue;
632
+ }
633
+ }
370
634
  updateJob.run(finishedAt, run.id);
371
635
  updateRun.run(finishedAt, run.id);
372
636
  const persistedIds = parseTicketIdsJson(run.ticket_ids_json);
@@ -386,7 +650,7 @@ legacyTicketIdsByRun) {
386
650
  };
387
651
  insertIntent.run(run.id, JSON.stringify(payload));
388
652
  }
389
- return active.length;
653
+ return reconciled;
390
654
  });
391
655
  return reconcile();
392
656
  }