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
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assessLoopMigration = assessLoopMigration;
4
+ const loop_compat_1 = require("./loop-compat");
5
+ const loop_graph_1 = require("./loop-graph");
6
+ function assessLoopMigration(loops, ports) {
7
+ const entries = loops.map((loop) => {
8
+ const engine = (0, loop_graph_1.isDefinitionGraph)(loop.graph) ? 'core' : 'legacy';
9
+ const base = { id: loop.id, name: loop.name, status: loop.status, engine, hasLegacyGraph: loop.hasLegacyGraph === true };
10
+ if (ports.isRunning(loop.id))
11
+ return { ...base, state: 'running', issues: [] };
12
+ let graph = loop.graph;
13
+ if (engine === 'legacy') {
14
+ // No repository binding is guessed: a multi-repository shell without an
15
+ // explicit scope stays an actionable issue, exactly as in conversion.
16
+ const converted = (0, loop_compat_1.convertLegacyLoop)(loop.graph);
17
+ if (!converted.ok)
18
+ return { ...base, state: 'needs_attention', issues: converted.issues };
19
+ graph = converted.graph;
20
+ }
21
+ let result;
22
+ try {
23
+ result = ports.validate(loop, graph);
24
+ }
25
+ catch (error) {
26
+ result = { ok: false, errors: [{ code: 'definition_invalid', message: error instanceof Error ? error.message : 'Invalid workflow' }] };
27
+ }
28
+ if (result.ok)
29
+ return { ...base, state: engine === 'core' ? 'current' : 'convertible', issues: [] };
30
+ return { ...base, state: engine === 'core' ? 'invalid' : 'needs_attention', issues: result.errors };
31
+ });
32
+ const summary = { current: 0, invalid: 0, convertible: 0, needs_attention: 0, running: 0 };
33
+ for (const entry of entries)
34
+ summary[entry.state] += 1;
35
+ return { loops: entries, summary };
36
+ }
@@ -13,6 +13,8 @@ exports.previewLoop = previewLoop;
13
13
  */
14
14
  const loop_command_catalog_1 = require("./loop-command-catalog");
15
15
  const loop_graph_1 = require("./loop-graph");
16
+ const loop_definition_1 = require("./loop-definition");
17
+ const loop_graph_2 = require("./loop-graph");
16
18
  const loop_constants_1 = require("./loop-constants");
17
19
  /** Stand-in ticket so `{{spec.*}}` resolves to something readable in the preview. */
18
20
  exports.SAMPLE_SPEC = {
@@ -50,6 +52,14 @@ function visitOrder(graph) {
50
52
  function previewLoop(graph, opts) {
51
53
  const spec = opts.spec ?? exports.SAMPLE_SPEC;
52
54
  const steps = [];
55
+ if ((0, loop_graph_2.isDefinitionGraph)(graph)) {
56
+ const definition = (0, loop_definition_1.compileLoopToDefinition)(graph, { ...opts, spec });
57
+ for (const [prefix, body] of [['', definition], ...Object.entries(definition.components ?? {})])
58
+ for (const [id, node] of Object.entries(body.nodes)) {
59
+ steps.push({ nodeId: prefix ? `${prefix}/${id}` : id, kind: node.kind, label: node.label, text: JSON.stringify(node.params, null, 2) });
60
+ }
61
+ return { steps };
62
+ }
53
63
  for (const node of visitOrder(graph)) {
54
64
  const label = typeof node.data?.label === 'string' && node.data.label.trim() ? node.data.label.trim() : undefined;
55
65
  let text = null;
@@ -11,6 +11,9 @@ exports.openspecChangeState = openspecChangeState;
11
11
  exports.extractChangeId = extractChangeId;
12
12
  exports.recoverOrphanLoopStepAccounting = recoverOrphanLoopStepAccounting;
13
13
  const crypto_1 = require("crypto");
14
+ const loop_definition_events_1 = require("./loop-definition-events");
15
+ const legacy_launch_telemetry_1 = require("./legacy-launch-telemetry");
16
+ const loop_definition_run_1 = require("./loop-definition-run");
14
17
  const spec_addenda_core_1 = require("../../specs/runtime/spec-addenda-core");
15
18
  const path_1 = __importDefault(require("path"));
16
19
  const fs_1 = __importDefault(require("fs"));
@@ -441,6 +444,7 @@ class LoopRunManager {
441
444
  now;
442
445
  options;
443
446
  _disposed = false;
447
+ _definitionTasks = new Map();
444
448
  _cancelled = new Set();
445
449
  /** The currently-spawned child per run, so cancel/stop can actually KILL a
446
450
  * blocked spawn (the cooperative `_cancelled` flag can't interrupt an await). */
@@ -478,6 +482,49 @@ class LoopRunManager {
478
482
  * awaited step resolves) — NOT dispose(), which never settles and would
479
483
  * leave the engine's `await` hanging forever. */
480
484
  cancel(runId) {
485
+ const frozen = (0, loop_runs_store_1.readDefinitionRun)(this.db, runId);
486
+ if (this.executors.cancelDefinition && frozen?.metadata.contextPath) {
487
+ void this.cancelDefinition(runId).catch(error => {
488
+ console.error(`[loop-run] durable cancellation failed for ${runId}: ${error instanceof Error ? error.message : String(error)}`);
489
+ });
490
+ return;
491
+ }
492
+ this.cancelResident(runId, false);
493
+ }
494
+ _definitionCancellations = new Map();
495
+ isDefinitionCancellationPending(runId) { return this._definitionCancellations.has(runId); }
496
+ /** Launch-time engine check, callable before a caller allocates worktrees. */
497
+ async assertEngineSupport(graph) {
498
+ if ((0, loop_graph_1.isDefinitionGraph)(graph)) {
499
+ if (!this.executors.runDefinition)
500
+ throw new Error('engine_unsupported: Core workflow execution is unavailable');
501
+ await this.executors.assertDefinitionSupport?.();
502
+ }
503
+ else
504
+ await this.executors.assertLegacyEngineSupport?.();
505
+ }
506
+ definitionForkOwnsRun(runId) {
507
+ return !!(0, loop_runs_store_1.readDefinitionForkTarget)(this.db, runId) || (0, loop_runs_store_1.readDefinitionExecutionClaim)(this.db, runId)?.owner.startsWith('fork:') === true;
508
+ }
509
+ /** Persist intent in the retained Core inbox before settling a resident pause.
510
+ * A rejected control leaves the execution available for an explicit retry. */
511
+ cancelDefinition(runId, requestId = `desktop-cancel:${runId}`) {
512
+ if (this.definitionForkOwnsRun(runId))
513
+ return Promise.reject(new Error('runtime_fork_owns_worktree: Continue the forked run'));
514
+ const pending = this._definitionCancellations.get(runId);
515
+ if (pending)
516
+ return pending;
517
+ const frozen = (0, loop_runs_store_1.readDefinitionRun)(this.db, runId);
518
+ const contextPath = frozen?.metadata.contextPath;
519
+ if (!contextPath || !this.executors.cancelDefinition)
520
+ return Promise.reject(new Error('runtime_control_unavailable: Frozen workflow cancellation is unavailable'));
521
+ const task = this.executors.cancelDefinition({ runId, contextPath, requestId }).then(() => {
522
+ this.cancelResident(runId, true);
523
+ }).finally(() => { this._definitionCancellations.delete(runId); });
524
+ this._definitionCancellations.set(runId, task);
525
+ return task;
526
+ }
527
+ cancelResident(runId, graceful) {
481
528
  this._cancelled.add(runId);
482
529
  const paused = this._pausedHumanDecisions.get(runId);
483
530
  if (paused) {
@@ -491,9 +538,21 @@ class LoopRunManager {
491
538
  const child = this._activeChild.get(runId);
492
539
  if (child?.pid) {
493
540
  try {
494
- (0, win_spawn_1.treeKillSafe)(child.pid, 'SIGKILL', () => { });
541
+ (0, win_spawn_1.treeKillSafe)(child.pid, graceful ? 'SIGTERM' : 'SIGKILL', () => { });
495
542
  }
496
543
  catch { /* already gone */ }
544
+ if (graceful) {
545
+ const timer = setTimeout(() => {
546
+ if (this._activeChild.get(runId) === child && child.pid) {
547
+ try {
548
+ (0, win_spawn_1.treeKillSafe)(child.pid, 'SIGKILL', () => { });
549
+ }
550
+ catch { /* already gone */ }
551
+ }
552
+ }, 1500);
553
+ timer.unref?.();
554
+ child.once('close', () => clearTimeout(timer));
555
+ }
497
556
  }
498
557
  }
499
558
  // ─── Interactive step routing (manager-agnostic /jobs/:id/messages) ─────────
@@ -511,11 +570,21 @@ class LoopRunManager {
511
570
  /** Feed one more user prompt to the ACTIVE step session owning this job row
512
571
  * (queued behind the active turn — steering; the loop tends to continue its
513
572
  * plan). Returns false when no interactive step is live for the id. */
514
- sendInteractiveTurn(jobId, text) {
573
+ pendingInterrupts(jobId) {
574
+ return structuredClone(this._pausedHumanDecisions.get(jobId)?.pending ?? []);
575
+ }
576
+ sendInteractiveTurn(jobId, text, control) {
577
+ if (this.definitionForkOwnsRun(jobId))
578
+ return false;
515
579
  const paused = this._pausedHumanDecisions.get(jobId);
516
580
  if (paused) {
581
+ if (paused.pending?.length) {
582
+ const selected = control?.interruptId ? paused.pending.find(item => item.id === control.interruptId) : paused.pending.length === 1 ? paused.pending[0] : undefined;
583
+ if (!selected || (selected.kind !== 'question' && control?.approve !== true))
584
+ return false;
585
+ }
517
586
  this._pausedHumanDecisions.delete(jobId);
518
- paused.resolve({ action: 'resume', text });
587
+ paused.resolve({ action: 'resume', text, ...control });
519
588
  return true;
520
589
  }
521
590
  const session = this._interactiveSteps.get(jobId);
@@ -614,7 +683,76 @@ class LoopRunManager {
614
683
  }
615
684
  this._pausedHumanDecisions.clear();
616
685
  }
617
- async run(req) {
686
+ isDisposed() { return this._disposed; }
687
+ isDefinitionRunActive(runId) { return this._definitionTasks.has(runId); }
688
+ _definitionClaims = new Map();
689
+ claimDefinition(req) {
690
+ if (this._definitionClaims.has(req.runId))
691
+ return;
692
+ const claim = (0, loop_runs_store_1.claimDefinitionExecution)(this.db, req.runId, { owner: (0, ids_1.newId)(), repositoryMounts: (0, loop_runs_store_1.definitionRepositoryMounts)(req) });
693
+ if (!claim.ok)
694
+ throw new Error(`runtime_run_active: ${claim.reason} (${claim.conflictingRunId})`);
695
+ this._definitionClaims.set(req.runId, claim.release);
696
+ }
697
+ releaseDefinition(runId) {
698
+ this._definitionClaims.get(runId)?.();
699
+ this._definitionClaims.delete(runId);
700
+ }
701
+ run(req) {
702
+ if (!(0, loop_graph_1.isDefinitionGraph)(req.graph))
703
+ return this._run(req);
704
+ const runId = req.runId ?? (0, ids_1.newId)();
705
+ if (this._definitionTasks.has(runId))
706
+ return Promise.reject(new Error('runtime_run_active: Workflow is already running'));
707
+ try {
708
+ this.claimDefinition({ ...req, runId });
709
+ }
710
+ catch (error) {
711
+ return Promise.reject(error);
712
+ }
713
+ const task = this._run({ ...req, runId }).finally(() => { this.releaseDefinition(runId); this._definitionTasks.delete(runId); });
714
+ this._definitionTasks.set(runId, task);
715
+ return task;
716
+ }
717
+ resumeDefinition(runId, input = {}) {
718
+ try {
719
+ return this.beginDefinitionResume(runId, input);
720
+ }
721
+ catch (error) {
722
+ return Promise.reject(error);
723
+ }
724
+ }
725
+ /** Synchronous admission lets HTTP reject competing writers before acknowledging a resume. */
726
+ beginDefinitionResume(runId, input = {}) {
727
+ if (this._disposed)
728
+ throw new Error('runtime_shutting_down: LoopRunManager is shut down');
729
+ const active = this._definitionTasks.get(runId);
730
+ if (active) {
731
+ const interruptId = input.interruptId ?? input.approve?.[0];
732
+ if (!this.isPaused(runId))
733
+ throw new Error('runtime_run_active: Select a pending question or approval');
734
+ const request = (0, loop_runs_store_1.readDefinitionRun)(this.db, runId)?.request;
735
+ if (!request)
736
+ throw new Error('runtime_run_not_found: Frozen workflow is unavailable');
737
+ this.claimDefinition({ ...request, runId });
738
+ if (!this.sendInteractiveTurn(runId, input.answer ?? '', { interruptId, approve: Boolean(input.approve?.length) })) {
739
+ this.releaseDefinition(runId);
740
+ throw new Error('runtime_run_active: Select a pending question or approval');
741
+ }
742
+ return active;
743
+ }
744
+ const frozen = (0, loop_runs_store_1.readDefinitionRun)(this.db, runId);
745
+ if (!frozen)
746
+ throw new Error('runtime_run_not_found: Frozen workflow is unavailable');
747
+ if (frozen.row.status === 'completed')
748
+ throw new Error('runtime_run_completed: Fork a completed workflow to continue');
749
+ this._cancelled.delete(runId);
750
+ this.claimDefinition({ ...frozen.request, runId });
751
+ const task = this._run(frozen.request, { resume: true, ...input }).finally(() => { this.releaseDefinition(runId); this._definitionTasks.delete(runId); });
752
+ this._definitionTasks.set(runId, task);
753
+ return task;
754
+ }
755
+ async _run(req, continuation) {
618
756
  // Later fresh steps must verify the admitted spec, even if its caller or
619
757
  // backlog changes while the implementation is running.
620
758
  req = { ...req, runtimeProviderOverride: (0, agent_runtime_settings_1.validateRuntimeProviderOverride)(req.runtimeProviderOverride), graph: structuredClone(req.graph) };
@@ -640,6 +778,12 @@ class LoopRunManager {
640
778
  }
641
779
  }
642
780
  }
781
+ const definitionEngine = (0, loop_graph_1.isDefinitionGraph)(req.graph);
782
+ if (definitionEngine && !this.executors.runDefinition)
783
+ throw new Error('engine_unsupported: Core workflow execution is unavailable');
784
+ // Saved runs resume with their retained package whatever the active Core lists.
785
+ if (!continuation)
786
+ await this.assertEngineSupport(req.graph);
643
787
  if (this._disposed)
644
788
  throw new Error('LoopRunManager is shut down');
645
789
  const adapter = (0, providers_1.getAdapter)(req.provider);
@@ -708,6 +852,8 @@ class LoopRunManager {
708
852
  iterationLimit: maxIterations,
709
853
  startedAt: launchStartedAt,
710
854
  });
855
+ if (definitionEngine)
856
+ (0, loop_runs_store_1.saveDefinitionRun)(this.db, runId, { request: req, source: 'definition' });
711
857
  if (req.executionManifest)
712
858
  this.db.prepare('UPDATE loop_runs SET execution_manifest = ? WHERE id = ?').run(JSON.stringify(req.executionManifest), runId);
713
859
  (0, db_1.createJob)(this.db, {
@@ -718,8 +864,15 @@ class LoopRunManager {
718
864
  owner: 'loop',
719
865
  causal_ownership: true,
720
866
  });
867
+ if (!definitionEngine)
868
+ (0, legacy_launch_telemetry_1.recordLegacyLaunch)(this.db, { kind: 'legacy_loop_traversal', projectId: req.projectId, runId, at: launchStartedAt });
721
869
  });
722
- persistLaunch();
870
+ if (continuation) {
871
+ (0, loop_runs_store_1.resumeLoopRun)(this.db, runId);
872
+ this.db.prepare("UPDATE jobs SET status='running',finished_at=NULL,exit_code=NULL WHERE id=? AND owner='loop'").run(runId);
873
+ }
874
+ else
875
+ persistLaunch();
723
876
  this._emit({
724
877
  type: 'loop.run_started',
725
878
  projectId: req.projectId,
@@ -729,7 +882,7 @@ class LoopRunManager {
729
882
  });
730
883
  // Surface the run as a JOB so the full session streams live in the Jobs list
731
884
  // + JobDetail. Both identities committed together above, before any spawn.
732
- let seq = 0;
885
+ let seq = continuation ? Number(this.db.prepare('SELECT COALESCE(MAX(seq),-1)+1 AS next FROM events WHERE job_id=?').get(runId).next) : 0;
733
886
  // Monotonic event-seq allocator for THIS run's job row. Shared with an
734
887
  // interactive step session (which persists its own provider events/logs on
735
888
  // the same job id) so replay ordering (getJobEvents ORDER BY seq) stays
@@ -840,7 +993,7 @@ class LoopRunManager {
840
993
  logLine(`▶ Loop "${req.loopName ?? req.loopId}" started${req.spec?.title ? ` — spec: ${req.spec.title}` : ''}`);
841
994
  if (req.isolation)
842
995
  logLine(`⎇ Isolated worktree: ${req.isolation.worktreePath} (branch ${req.isolation.branch})`);
843
- if (!usageTelemetryAvailable) {
996
+ if (!definitionEngine && !usageTelemetryAvailable) {
844
997
  logLine(`⚠️ ${adapter.displayName} does not report token/cost usage in headless mode; usage totals will remain unavailable.` +
845
998
  (configuredMaxCostUsd !== undefined
846
999
  ? ' The configured maxCostUsd guard is disabled because it cannot be verified.'
@@ -856,7 +1009,8 @@ class LoopRunManager {
856
1009
  model: req.model,
857
1010
  iterationLimit: maxIterations,
858
1011
  };
859
- emitRunEvent('loop_graph', graphPayload);
1012
+ if (!continuation)
1013
+ emitRunEvent('loop_graph', graphPayload);
860
1014
  console.log(`[loop] start run=${runId} loop=${req.loopId} provider=${req.provider} model=${req.model} nodes=${req.graph.nodes.length} cwd=${req.cwd}`);
861
1015
  const byId = (0, loop_graph_1.nodesById)(req.graph);
862
1016
  const start = (0, loop_graph_1.findStartNode)(req.graph);
@@ -1046,9 +1200,9 @@ class LoopRunManager {
1046
1200
  // that loop-back so each iteration starts FRESH (re-reading the current code),
1047
1201
  // keeping context bounded regardless of pass count. Within an iteration the
1048
1202
  // steps still resume, so RED→GREEN→REFACTOR share context.
1049
- const awaitHumanDecision = async (reason) => {
1203
+ const awaitHumanDecision = async (reason, pending) => {
1050
1204
  const decisionPromise = new Promise((resolve) => {
1051
- this._pausedHumanDecisions.set(runId, { reason, resolve });
1205
+ this._pausedHumanDecisions.set(runId, { reason, pending, resolve });
1052
1206
  });
1053
1207
  logLine(`\n■ Loop paused — needs a human decision: ${reason}`, 'stderr');
1054
1208
  try {
@@ -1075,6 +1229,7 @@ class LoopRunManager {
1075
1229
  projectId: req.projectId,
1076
1230
  jobId: runId,
1077
1231
  acceptingTurns: true,
1232
+ pendingInterrupts: pending,
1078
1233
  settleMode: 'auto',
1079
1234
  timestamp: pausedAt,
1080
1235
  });
@@ -1102,6 +1257,7 @@ class LoopRunManager {
1102
1257
  projectId: req.projectId,
1103
1258
  jobId: runId,
1104
1259
  acceptingTurns: false,
1260
+ pendingInterrupts: [],
1105
1261
  settleMode: 'auto',
1106
1262
  timestamp: resumedAt,
1107
1263
  });
@@ -1128,12 +1284,41 @@ class LoopRunManager {
1128
1284
  phaseRecovery = undefined;
1129
1285
  return failedId === nodeId ? successor : failedId;
1130
1286
  };
1287
+ let definitionCompletion;
1131
1288
  const firstStepId = start ? req.graph.edges.find((e) => e.source === start.id)?.target : undefined;
1132
1289
  try {
1133
1290
  let nodeId = start?.id;
1134
1291
  let settled = !start; // no start node → fall through to settle as failed
1135
1292
  if (!start)
1136
1293
  outcome = 'failed';
1294
+ if (definitionEngine) {
1295
+ settled = true;
1296
+ const projectEvent = (0, loop_definition_events_1.createDefinitionEventProjection)({ db: this.db, runId, projectId: req.projectId, ticketIds: exactTicketIds, nextSequence: takeSeq,
1297
+ broadcast: event => this._emit({ type: 'event', jobId: runId, event_type: event.eventType, source: 'stdout', payload: event.payload, seq: event.seq, timestamp: event.timestamp }),
1298
+ onProgress: (count, usage) => { stepNum = count; totalCost = usage.cost; totalTokens = usage.tokensIn + usage.tokensOut; totalDuration = usage.duration; costUncertain = usage.costUnknown; usageTelemetryAvailable = usage.present; },
1299
+ });
1300
+ let activeDurationMs = continuation ? (0, loop_runs_store_1.getLoopRun)(this.db, runId)?.total_duration_ms ?? 0 : 0;
1301
+ const result = await (0, loop_definition_run_1.runDefinitionLoop)(req, runId, { continuation, contextPath: () => (0, loop_runs_store_1.readDefinitionRun)(this.db, runId)?.metadata.contextPath,
1302
+ onPrepared: metadata => { (0, loop_runs_store_1.saveDefinitionRun)(this.db, runId, metadata); },
1303
+ invoke: input => { this.claimDefinition({ ...req, runId }); return this.executors.runDefinition(input); }, isCancelled: () => this._cancelled.has(runId),
1304
+ remainingMs: () => req.graph.config.timeoutMinutes > 0 ? Math.max(1, req.graph.config.timeoutMinutes * 60_000 - activeDurationMs) : undefined,
1305
+ onLine: logLine, onRuntimeEvent: projectEvent, onSpawn: child => {
1306
+ this._activeChild.set(runId, child);
1307
+ if (this._cancelled.has(runId))
1308
+ this.cancelResident(runId, false);
1309
+ },
1310
+ onInvocationEnd: result => { this._activeChild.delete(runId); if (result.runtimeStatus === 'paused')
1311
+ this.releaseDefinition(runId); if (result.durationMs !== undefined) {
1312
+ activeDurationMs = result.durationMs;
1313
+ totalDuration = result.durationMs;
1314
+ } }, awaitHumanDecision, });
1315
+ definitionCompletion = result.completion;
1316
+ if (result.durationMs !== undefined)
1317
+ totalDuration = result.durationMs;
1318
+ if (result.errorText)
1319
+ logLine(result.errorText, 'stderr');
1320
+ outcome = result.runtimeStatus === 'succeeded' ? 'success' : result.runtimeStatus === 'cancelled' ? 'stopped' : result.runtimeStatus === 'blocked' ? 'blocked' : 'failed';
1321
+ }
1137
1322
  while (nodeId && !settled) {
1138
1323
  if (this._cancelled.has(runId)) {
1139
1324
  outcome = 'stopped';
@@ -1771,7 +1956,7 @@ class LoopRunManager {
1771
1956
  try {
1772
1957
  const recoveredSteps = recoverOrphanLoopStepAccounting(this.db, new Date(this.now()).toISOString(), runId);
1773
1958
  this._activeStepRecovery.delete(runId);
1774
- runtimeUsage = programmaticUsageAvailability(this.db, runId);
1959
+ runtimeUsage = definitionEngine ? (0, loop_definition_events_1.readDefinitionUsage)(this.db, runId) : programmaticUsageAvailability(this.db, runId);
1775
1960
  usageTelemetryAvailable ||= runtimeUsage.present;
1776
1961
  const aggregate = this.db.prepare(`
1777
1962
  SELECT COALESCE(SUM(total_cost_usd), 0) AS cost,
@@ -1819,10 +2004,18 @@ class LoopRunManager {
1819
2004
  // terminal snapshot alongside counters so history does not depend on prose.
1820
2005
  let coreCompletion = null;
1821
2006
  try {
1822
- coreCompletion = await this.executors.readCoreCompletion?.(runId) ?? null;
2007
+ if (!definitionEngine)
2008
+ coreCompletion = await this.executors.readCoreCompletion?.(runId) ?? null;
1823
2009
  }
1824
2010
  catch { /* old/unavailable runtime */ }
2011
+ if (definitionEngine) {
2012
+ const usage = (0, loop_definition_events_1.readDefinitionUsage)(this.db, runId);
2013
+ usageTelemetryAvailable = usage.present;
2014
+ finalJobUsage = { tokensIn: usage.present && !usage.tokensInUnknown ? usage.tokensIn : null, tokensOut: usage.present && !usage.tokensOutUnknown ? usage.tokensOut : null, tokensCacheRead: usage.present && !usage.cacheReadUnknown ? usage.cacheRead : null, tokensCacheCreate: usage.present && !usage.cacheCreateUnknown ? usage.cacheCreate : null, numTurns: usage.present && !usage.turnsUnknown ? usage.turns : null };
2015
+ }
1825
2016
  const executionOutcome = outcome;
2017
+ if (definitionEngine && outcome === 'success' && !definitionCompletion?.ok)
2018
+ outcome = 'blocked';
1826
2019
  if (outcome === 'success' && coreCompletion && (coreCompletion.completion.implementation !== 'complete' || !['verified', 'with-exceptions'].includes(coreCompletion.completion.validation)))
1827
2020
  outcome = 'blocked';
1828
2021
  const costAvailable = usageTelemetryAvailable && !runtimeUsage.costUnknown;
@@ -1831,7 +2024,7 @@ class LoopRunManager {
1831
2024
  emitRunEvent('loop_completion', {
1832
2025
  version: 1, execution: executionOutcome, steps: stepNum, deciderEvaluations: iteration,
1833
2026
  turns: finalJobUsage.numTurns, costUsd: usageTelemetryAvailable ? totalCost : null,
1834
- costUncertain, core: coreCompletion,
2027
+ costUncertain, core: coreCompletion, ...(definitionEngine ? { engineVersion: 2, completion: definitionCompletion } : {}),
1835
2028
  });
1836
2029
  // Settle the backing job so the Jobs list + JobDetail reflect the final
1837
2030
  // status, and emit job.finalized so an open JobDetail re-fetches + stops the