specrails-desktop 2.58.1 → 2.59.1
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.
- package/README.md +2 -5
- package/client/dist/assets/{ActivityFeedPage-BQGppIR0.js → ActivityFeedPage-vAY9C71W.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-CpwjGXQm.js +1 -0
- package/client/dist/assets/AgentModeAnalyticsPane-BHeoJVxQ.js +2 -0
- package/client/dist/assets/AgentModeCodePane-B0Nf3YkN.js +2 -0
- package/client/dist/assets/{AgentModeJobsPane-DR_06oqH.js → AgentModeJobsPane-CpbIItY_.js} +1 -1
- package/client/dist/assets/{AgentsPage-BKIKjm_1.js → AgentsPage-BVJAFXn3.js} +3 -3
- package/client/dist/assets/{AnalyticsPage-069npRVo.js → AnalyticsPage-DDWees-K.js} +1 -1
- package/client/dist/assets/CodePage-CzV5tkvS.js +3 -0
- package/client/dist/assets/{DesktopAnalyticsPage-qtWAPM47.js → DesktopAnalyticsPage-DfRHNK7i.js} +1 -1
- package/client/dist/assets/DocsDialog-BxduBYbh.js +11 -0
- package/client/dist/assets/DocsPage-DOVeRJn_.js +11 -0
- package/client/dist/assets/{ExportDropdown-BcMpvV89.js → ExportDropdown-BnKVV8UK.js} +1 -1
- package/client/dist/assets/InteractiveJobComposer-Da9dvM-0.js +19 -0
- package/client/dist/assets/JobDetailModal-DhwKbZGe.js +1 -0
- package/client/dist/assets/JobDetailPage-MtPE-E_1.js +1 -0
- package/client/dist/assets/JobsPage-0vdlbNik.js +1 -0
- package/client/dist/assets/LoopBuilderPage-DCUHozXh.js +1 -0
- package/client/dist/assets/{LoopPreviewModal-je5pSCf-.js → LoopPreviewModal-Df-S8NGf.js} +1 -1
- package/client/dist/assets/LoopWindowSurface-sdb7QbSo.js +1 -0
- package/client/dist/assets/LoopsPage-CDfCC9Px.js +2 -0
- package/client/dist/assets/MinimizedChatsContext-DKlPf54Y.js +1 -0
- package/client/dist/assets/PluginsPage-iL0G3rQQ.js +2 -0
- package/client/dist/assets/ProjectSettingsDialog-DOkjT7xv.js +1 -0
- package/client/dist/assets/{RepositoryDeliveries-BiwJuS8r.js → RepositoryDeliveries-CJVpOUpZ.js} +1 -1
- package/client/dist/assets/RepositoryScopeSelector-BeM-2gIZ.js +2 -0
- package/client/dist/assets/ReviewPacketPage-EBCim2w_.js +4 -0
- package/client/dist/assets/TemplatePreviewModal-1-92UGwN.js +1 -0
- package/client/dist/assets/TicketDetailModalContext-CkVXuHxU.js +16 -0
- package/client/dist/assets/{Trans-D3AfDylf.js → Trans-CzhPjnjB.js} +1 -1
- package/client/dist/assets/agent--8QAfoXL.js +1 -0
- package/client/dist/assets/agent-3HxXkIWX.js +1 -0
- package/client/dist/assets/agent-BjttZLIl.js +1 -0
- package/client/dist/assets/agent-CpFCz32T.js +1 -0
- package/client/dist/assets/agent-DVnw6ybO.js +1 -0
- package/client/dist/assets/agent-Z5s_GTP0.js +1 -0
- package/client/dist/assets/agent-hv57-zyG.js +1 -0
- package/client/dist/assets/agent-xGrZ_aN1.js +1 -0
- package/client/dist/assets/{agentRuntime-DGz_IqKW.js → agentRuntime-15Pkk6we.js} +1 -1
- package/client/dist/assets/agentRuntime-Bpx3yWHK.js +1 -0
- package/client/dist/assets/{agentRuntime-Bg9tbmqm.js → agentRuntime-C78n13To.js} +1 -1
- package/client/dist/assets/{agentRuntime-D-GJVGkj.js → agentRuntime-CCI7XF4c.js} +1 -1
- package/client/dist/assets/{agentRuntime-D2__CVI_.js → agentRuntime-CKDHe2-a.js} +1 -1
- package/client/dist/assets/{agentRuntime-D35dGVOP.js → agentRuntime-Ddqvp2bP.js} +1 -1
- package/client/dist/assets/{agentRuntime-hInH9Fzj.js → agentRuntime-TXPQowKJ.js} +1 -1
- package/client/dist/assets/{agentRuntime-O1liDt6G.js → agentRuntime-hqZRy08E.js} +1 -1
- package/client/dist/assets/{builder-DGETbtZj.js → builder-B9gorTnT.js} +1 -1
- package/client/dist/assets/{builder-DyQperXU.js → builder-Bvw5s3Mi.js} +1 -1
- package/client/dist/assets/{builder-C1neIYGR.js → builder-CL5l4dU3.js} +1 -1
- package/client/dist/assets/{builder-DXEJUlC0.js → builder-CVDTVrQX.js} +1 -1
- package/client/dist/assets/{builder-CzW5ovyI.js → builder-CpS9liE9.js} +1 -1
- package/client/dist/assets/{builder-CvnFm0im.js → builder-DNctIL9Q.js} +1 -1
- package/client/dist/assets/{builder-D06L7iPy.js → builder-De2NxX6o.js} +1 -1
- package/client/dist/assets/{builder-C0FyvM83.js → builder-DeYT7Y-m.js} +1 -1
- package/client/dist/assets/{button-Ccc9Dc-D.js → button-D1xExSTF.js} +1 -1
- package/client/dist/assets/{common-DmsclwjP.js → common-Bdi0qN4S.js} +1 -1
- package/client/dist/assets/{common-C4Yvvhp6.js → common-Bhb9zN1P.js} +1 -1
- package/client/dist/assets/{common-od8WThlf.js → common-BykKlZg1.js} +1 -1
- package/client/dist/assets/{common-C0BOdeNi.js → common-CvnNNSJA.js} +1 -1
- package/client/dist/assets/{common-BCK7c9Pv.js → common-D5zk_mqq.js} +1 -1
- package/client/dist/assets/{common-DpLWwgI1.js → common-DQNO_al5.js} +1 -1
- package/client/dist/assets/{common-OCvl3c8t.js → common-Dax30Vmp.js} +1 -1
- package/client/dist/assets/{common-c0aujEZC.js → common-DkllpVSb.js} +1 -1
- package/client/dist/assets/{dialog-xXB2q5HJ.js → dialog-CMgps2MY.js} +1 -1
- package/client/dist/assets/external-link-D6XxC_Cu.js +1 -0
- package/client/dist/assets/file-text-BcLCfcWZ.js +1 -0
- package/client/dist/assets/{formatDistanceToNow-aBss1Nai.js → formatDistanceToNow-DlQaXc7c.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-DOGj1Mfz.js → getTimezoneOffsetInMilliseconds-DxUFGcVq.js} +1 -1
- package/client/dist/assets/index-Bfunvi6w.css +2 -0
- package/client/dist/assets/index-Czov72g7.js +83 -0
- package/client/dist/assets/integrations-BkpRUbvp.js +1 -0
- package/client/dist/assets/integrations-Bo8qbJf4.js +1 -0
- package/client/dist/assets/integrations-CmSrKzZb.js +1 -0
- package/client/dist/assets/integrations-DGtq26Rr.js +1 -0
- package/client/dist/assets/integrations-De38GFnQ.js +1 -0
- package/client/dist/assets/integrations-Dw6zdtb-.js +1 -0
- package/client/dist/assets/integrations-Dwl9KQp0.js +1 -0
- package/client/dist/assets/integrations-Refg_d2I.js +1 -0
- package/client/dist/assets/jira-api-CbJvbRYx.js +1 -0
- package/client/dist/assets/{jobs-KG4Sn12X.js → jobs-1G3wodhl.js} +1 -1
- package/client/dist/assets/{jobs-6_-r75yC.js → jobs-B4pu8TdF.js} +1 -1
- package/client/dist/assets/{jobs-pPv4KWjb.js → jobs-BD47Ov11.js} +1 -1
- package/client/dist/assets/{jobs-B1yqyId5.js → jobs-BLOoVRRl.js} +1 -1
- package/client/dist/assets/{jobs-BKiK-ZWh.js → jobs-CSrRx5lD.js} +1 -1
- package/client/dist/assets/{jobs-BFuV7ttH.js → jobs-DZAbh1m2.js} +1 -1
- package/client/dist/assets/{jobs-DmKV7b7d.js → jobs-epP7gt8W.js} +1 -1
- package/client/dist/assets/{jobs-BKa8LuwA.js → jobs-tWjcDF_6.js} +1 -1
- package/client/dist/assets/loops--KWr0X-w.js +1 -0
- package/client/dist/assets/{loops-BO3V8244.js → loops-3IutojWt.js} +1 -1
- package/client/dist/assets/{loops-C-hZK8pf.js → loops-BAosWtXE.js} +1 -1
- package/client/dist/assets/{loops-eUnCfLjC.js → loops-BISDssL5.js} +1 -1
- package/client/dist/assets/{loops-Dv849ckF.js → loops-Cm55CXJ4.js} +1 -1
- package/client/dist/assets/{loops-CDOWZ0ci.js → loops-D7tL_Saw.js} +1 -1
- package/client/dist/assets/{loops-BJDY9FTh.js → loops-DHQtnfze.js} +1 -1
- package/client/dist/assets/{loops-Q9LIgGkq.js → loops-kIJJkaxf.js} +1 -1
- package/client/dist/assets/nav--u7iPYlS.js +1 -0
- package/client/dist/assets/nav-C5Jgfaby.js +1 -0
- package/client/dist/assets/nav-CAna_Wpt.js +1 -0
- package/client/dist/assets/nav-CCLqeyHo.js +1 -0
- package/client/dist/assets/nav-Cf3c90Jk.js +1 -0
- package/client/dist/assets/nav-DMYQaQjR.js +1 -0
- package/client/dist/assets/nav-Df_PkZ9F.js +1 -0
- package/client/dist/assets/nav-VyNGBJwj.js +1 -0
- package/client/dist/assets/{project-repositories-CSnfzUpg.js → project-repositories-BkBD3rxx.js} +1 -1
- package/client/dist/assets/provider-capabilities-lePfeT_Y.js +1 -0
- package/client/dist/assets/save-OsUqVn99.js +1 -0
- package/client/dist/assets/settings-B5Hy_Kol.js +1 -0
- package/client/dist/assets/settings-BBj_kZaD.js +1 -0
- package/client/dist/assets/settings-ByVE7jdZ.js +1 -0
- package/client/dist/assets/settings-COlH_P33.js +1 -0
- package/client/dist/assets/settings-D77mC_Lb.js +1 -0
- package/client/dist/assets/settings-DZKy7MqN.js +1 -0
- package/client/dist/assets/settings-Dbyd6gmj.js +1 -0
- package/client/dist/assets/settings-Dn-pXukr.js +1 -0
- package/client/dist/assets/setup-Be485n2u.js +1 -0
- package/client/dist/assets/setup-CKGUxKr-.js +1 -0
- package/client/dist/assets/setup-Ck1Uwd7_.js +1 -0
- package/client/dist/assets/setup-Cm774a6v.js +1 -0
- package/client/dist/assets/setup-DIqMQpxt.js +1 -0
- package/client/dist/assets/setup-DfCsoNFL.js +1 -0
- package/client/dist/assets/setup-DkeE8mP0.js +1 -0
- package/client/dist/assets/setup-xVntVaz1.js +1 -0
- package/client/dist/assets/{spending-HBSk-6jv.js → spending-CYotH-9N.js} +1 -1
- package/client/dist/assets/subscriptionUsage-BH73RO86.js +1 -0
- package/client/dist/assets/subscriptionUsage-BWTeWlHx.js +1 -0
- package/client/dist/assets/subscriptionUsage-CBh82zVa.js +1 -0
- package/client/dist/assets/subscriptionUsage-CHcQ7lLe.js +1 -0
- package/client/dist/assets/subscriptionUsage-CdlE5Mg1.js +1 -0
- package/client/dist/assets/subscriptionUsage-DUPBmSQi.js +1 -0
- package/client/dist/assets/subscriptionUsage-DrlwrJ17.js +1 -0
- package/client/dist/assets/subscriptionUsage-EFu0mIK3.js +1 -0
- package/client/dist/assets/tauri-shell-DE6LfGPw.js +2 -0
- package/client/dist/assets/{useDesktop-0unHDBJJ.js → useDesktop-DpxVGfUC.js} +1 -1
- package/client/dist/assets/{useRuntimeRuns-BN1rhyEm.js → useRuntimeRuns-CfGRbhr9.js} +1 -1
- package/client/dist/assets/useSharedWebSocket-C17TGqT8.js +2 -0
- package/client/dist/index.html +33 -32
- package/docs/README.md +1 -9
- package/docs/agent-live-steering.md +0 -6
- package/docs/agents/README.md +0 -2
- package/docs/agents/mcp.md +1 -14
- package/docs/cli.md +0 -13
- package/docs/codex.md +2 -75
- package/docs/creating-specs.md +0 -39
- package/docs/customizing.md +1 -15
- package/docs/getting-started.md +0 -23
- package/docs/guide/de/agents/2-profiles-and-the-balanced-default.md +0 -8
- package/docs/guide/de/agents/4-custom-agents-catalog.md +0 -15
- package/docs/guide/de/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/de/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/de/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/de/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/de/integrations/1-ai-providers.md +2 -50
- package/docs/guide/de/integrations/2-plugins.md +0 -8
- package/docs/guide/de/integrations/5-mcp-server.md +1 -14
- package/docs/guide/de/integrations/6-agent-chat.md +0 -11
- package/docs/guide/de/integrations/7-local-engines.md +0 -4
- package/docs/guide/de/pipeline/1-rails-and-jobs.md +0 -13
- package/docs/guide/de/pipeline/2-the-job-detail-view.md +0 -3
- package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +0 -20
- package/docs/guide/de/pipeline/5-the-loop-builder.md +0 -6
- package/docs/guide/de/specs/2-add-spec-quick-mode.md +0 -7
- package/docs/guide/en/agents/2-profiles-and-the-balanced-default.md +0 -10
- package/docs/guide/en/agents/4-custom-agents-catalog.md +0 -25
- package/docs/guide/en/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/en/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/en/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/en/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/en/insights/3-code-explorer.md +0 -5
- package/docs/guide/en/integrations/1-ai-providers.md +10 -99
- package/docs/guide/en/integrations/2-plugins.md +0 -8
- package/docs/guide/en/integrations/5-mcp-server.md +1 -1
- package/docs/guide/en/integrations/6-agent-chat.md +0 -17
- package/docs/guide/en/integrations/7-local-engines.md +0 -4
- package/docs/guide/en/pipeline/1-rails-and-jobs.md +2 -24
- package/docs/guide/en/pipeline/2-the-job-detail-view.md +0 -3
- package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +10 -65
- package/docs/guide/en/pipeline/5-the-loop-builder.md +0 -7
- package/docs/guide/en/specs/2-add-spec-quick-mode.md +0 -11
- package/docs/guide/es/agents/2-profiles-and-the-balanced-default.md +0 -8
- package/docs/guide/es/agents/4-custom-agents-catalog.md +0 -15
- package/docs/guide/es/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/es/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/es/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/es/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/es/integrations/1-ai-providers.md +10 -75
- package/docs/guide/es/integrations/2-plugins.md +0 -8
- package/docs/guide/es/integrations/5-mcp-server.md +1 -1
- package/docs/guide/es/integrations/6-agent-chat.md +0 -11
- package/docs/guide/es/integrations/7-local-engines.md +0 -4
- package/docs/guide/es/pipeline/1-rails-and-jobs.md +3 -13
- package/docs/guide/es/pipeline/2-the-job-detail-view.md +0 -3
- package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +10 -53
- package/docs/guide/es/pipeline/5-the-loop-builder.md +1 -6
- package/docs/guide/es/specs/2-add-spec-quick-mode.md +0 -7
- package/docs/guide/fr/agents/2-profiles-and-the-balanced-default.md +0 -8
- package/docs/guide/fr/agents/4-custom-agents-catalog.md +0 -15
- package/docs/guide/fr/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/fr/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/fr/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/fr/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/fr/integrations/1-ai-providers.md +2 -50
- package/docs/guide/fr/integrations/2-plugins.md +0 -8
- package/docs/guide/fr/integrations/5-mcp-server.md +1 -14
- package/docs/guide/fr/integrations/6-agent-chat.md +0 -11
- package/docs/guide/fr/integrations/7-local-engines.md +0 -4
- package/docs/guide/fr/pipeline/1-rails-and-jobs.md +0 -13
- package/docs/guide/fr/pipeline/2-the-job-detail-view.md +0 -3
- package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +0 -22
- package/docs/guide/fr/pipeline/5-the-loop-builder.md +0 -6
- package/docs/guide/fr/specs/2-add-spec-quick-mode.md +0 -7
- package/docs/guide/it/agents/2-profiles-and-the-balanced-default.md +0 -8
- package/docs/guide/it/agents/4-custom-agents-catalog.md +0 -15
- package/docs/guide/it/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/it/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/it/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/it/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/it/integrations/1-ai-providers.md +2 -48
- package/docs/guide/it/integrations/2-plugins.md +0 -8
- package/docs/guide/it/integrations/5-mcp-server.md +1 -14
- package/docs/guide/it/integrations/6-agent-chat.md +0 -11
- package/docs/guide/it/integrations/7-local-engines.md +0 -4
- package/docs/guide/it/pipeline/1-rails-and-jobs.md +2 -13
- package/docs/guide/it/pipeline/2-the-job-detail-view.md +0 -3
- package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +0 -20
- package/docs/guide/it/pipeline/5-the-loop-builder.md +1 -6
- package/docs/guide/it/specs/2-add-spec-quick-mode.md +0 -7
- package/docs/guide/ja/agents/2-profiles-and-the-balanced-default.md +0 -9
- package/docs/guide/ja/agents/4-custom-agents-catalog.md +0 -15
- package/docs/guide/ja/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/ja/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/ja/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/ja/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/ja/integrations/1-ai-providers.md +1 -69
- package/docs/guide/ja/integrations/2-plugins.md +0 -8
- package/docs/guide/ja/integrations/5-mcp-server.md +1 -14
- package/docs/guide/ja/integrations/6-agent-chat.md +0 -10
- package/docs/guide/ja/integrations/7-local-engines.md +0 -4
- package/docs/guide/ja/pipeline/1-rails-and-jobs.md +0 -13
- package/docs/guide/ja/pipeline/2-the-job-detail-view.md +0 -3
- package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +0 -21
- package/docs/guide/ja/pipeline/5-the-loop-builder.md +0 -6
- package/docs/guide/ja/specs/2-add-spec-quick-mode.md +0 -7
- package/docs/guide/pt/agents/2-profiles-and-the-balanced-default.md +0 -8
- package/docs/guide/pt/agents/4-custom-agents-catalog.md +0 -15
- package/docs/guide/pt/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/pt/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/pt/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/pt/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/pt/integrations/1-ai-providers.md +2 -48
- package/docs/guide/pt/integrations/2-plugins.md +0 -8
- package/docs/guide/pt/integrations/5-mcp-server.md +1 -14
- package/docs/guide/pt/integrations/6-agent-chat.md +0 -10
- package/docs/guide/pt/integrations/7-local-engines.md +0 -4
- package/docs/guide/pt/pipeline/1-rails-and-jobs.md +0 -13
- package/docs/guide/pt/pipeline/2-the-job-detail-view.md +0 -2
- package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +0 -21
- package/docs/guide/pt/pipeline/5-the-loop-builder.md +0 -6
- package/docs/guide/pt/specs/2-add-spec-quick-mode.md +0 -7
- package/docs/guide/zh/agents/2-profiles-and-the-balanced-default.md +0 -7
- package/docs/guide/zh/agents/4-custom-agents-catalog.md +0 -15
- package/docs/guide/zh/getting-started/1-what-is-specrails.md +0 -2
- package/docs/guide/zh/getting-started/2-installing-and-first-run.md +0 -2
- package/docs/guide/zh/getting-started/3-adding-your-first-project.md +0 -4
- package/docs/guide/zh/getting-started/4-the-dashboard-tour.md +0 -5
- package/docs/guide/zh/integrations/1-ai-providers.md +1 -67
- package/docs/guide/zh/integrations/2-plugins.md +0 -8
- package/docs/guide/zh/integrations/5-mcp-server.md +1 -14
- package/docs/guide/zh/integrations/6-agent-chat.md +0 -9
- package/docs/guide/zh/integrations/7-local-engines.md +0 -4
- package/docs/guide/zh/pipeline/1-rails-and-jobs.md +0 -13
- package/docs/guide/zh/pipeline/2-the-job-detail-view.md +0 -2
- package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +0 -20
- package/docs/guide/zh/pipeline/5-the-loop-builder.md +0 -6
- package/docs/guide/zh/specs/2-add-spec-quick-mode.md +0 -7
- package/docs/internals/adding-a-provider.md +7 -0
- package/docs/internals/api-reference.md +1 -0
- package/docs/internals/core-runtime-updates.md +9 -2
- package/docs/internals/desktop-owned-workflows.md +144 -0
- package/docs/internals/mission-rail-cards.md +15 -0
- package/docs/internals/operations-runbook.md +26 -0
- package/docs/internals/programmatic-agent-runtime.md +34 -28
- package/docs/internals/project-builder.md +34 -11
- package/docs/internals/safe-pr-review-flow.md +25 -7
- package/docs/internals/source-map.md +53 -3
- package/docs/internals/spec-addenda.md +11 -5
- package/docs/internals/visual-design-audit.md +5 -0
- package/docs/local-providers.md +8 -13
- package/docs/mcp.md +1 -17
- package/docs/platforms/macos.md +0 -40
- package/docs/platforms/windows-parity.md +1 -1
- package/docs/platforms/windows.md +0 -8
- package/docs/running-pipelines.md +1 -46
- package/docs/subscription-usage.md +19 -0
- package/docs/terminal.md +0 -2
- package/docs/tracking-cost.md +2 -33
- package/package.json +1 -1
- package/server/dist/core-execution.js +24 -15
- package/server/dist/core-update-manager.js +1 -1
- package/server/dist/db/migrations.js +9 -0
- package/server/dist/desktop-db.js +23 -10
- package/server/dist/desktop-router.js +8 -4
- package/server/dist/index.js +10 -5
- package/server/dist/mcp/guide.js +1 -0
- package/server/dist/mcp/tools/jobs.js +1 -1
- package/server/dist/mcp/tools/loops.js +2 -0
- package/server/dist/mcp/tools/meta.js +6 -7
- package/server/dist/mcp/tools/projects.js +31 -6
- package/server/dist/mcp/tools/rails.js +6 -3
- package/server/dist/mcp/tools/setup.js +10 -0
- package/server/dist/mcp/tools/specs.js +1 -1
- package/server/dist/modules/accounting/runtime/pricing.js +6 -1
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-bridge.js +169 -17
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-metrics.js +1 -1
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings-router.js +1 -1
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings.js +42 -0
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-verification-suggestions.js +10 -4
- package/server/dist/modules/builder/runtime/milestone-chain.js +76 -10
- package/server/dist/modules/delivery/runtime/delivery-evidence.js +3 -2
- package/server/dist/modules/delivery/runtime/multi-repo-execution.js +10 -5
- package/server/dist/modules/delivery/runtime/rail-isolated-launch.js +66 -30
- package/server/dist/modules/delivery/runtime/rail-launch-parser.js +8 -0
- package/server/dist/modules/delivery/runtime/rail-pr-store.js +3 -3
- package/server/dist/modules/delivery/runtime/rail-relaunch.js +154 -0
- package/server/dist/modules/delivery/runtime/rails-router.js +157 -36
- package/server/dist/modules/delivery/runtime/review-packet.js +1 -1
- package/server/dist/modules/execution/runtime/revision-seed.js +6 -2
- package/server/dist/modules/loops/runtime/loop-agent-defaults.json +6 -0
- package/server/dist/modules/loops/runtime/loop-agents.js +21 -0
- package/server/dist/modules/loops/runtime/loop-command-catalog.js +1 -1
- package/server/dist/modules/loops/runtime/loop-core-factory.js +19 -3
- package/server/dist/modules/loops/runtime/loop-definition-events.js +1 -1
- package/server/dist/modules/loops/runtime/loop-definition.js +79 -12
- package/server/dist/modules/loops/runtime/loop-effect.js +1 -1
- package/server/dist/modules/loops/runtime/loop-executors.js +24 -9
- package/server/dist/modules/loops/runtime/loop-factory.js +1 -1
- package/server/dist/modules/loops/runtime/loop-graph.js +5 -14
- package/server/dist/modules/loops/runtime/loop-implement-recipe.js +53 -0
- package/server/dist/modules/loops/runtime/loop-run-manager.js +30 -20
- package/server/dist/modules/loops/runtime/loop-templates.js +29 -5
- package/server/dist/modules/loops/runtime/loops-router.js +17 -0
- package/server/dist/modules/missions/runtime/agent-context-resolver.js +1 -1
- package/server/dist/modules/missions/runtime/agent-operator-prompt.js +17 -8
- package/server/dist/modules/specs/runtime/spec-models.js +4 -7
- package/server/dist/modules/subscription-usage/adapters/claude.js +123 -0
- package/server/dist/modules/subscription-usage/adapters/codex.js +164 -0
- package/server/dist/modules/subscription-usage/adapters/errors.js +15 -0
- package/server/dist/modules/subscription-usage/adapters/http.js +20 -0
- package/server/dist/modules/subscription-usage/adapters/local-auth.js +61 -0
- package/server/dist/modules/subscription-usage/application.js +12 -0
- package/server/dist/modules/subscription-usage/domain.js +104 -0
- package/server/dist/modules/subscription-usage/index.js +2 -0
- package/server/dist/modules/subscription-usage/ports.js +2 -0
- package/server/dist/modules/subscription-usage/runtime/composition.js +20 -0
- package/server/dist/modules/subscription-usage/runtime/usage-service.js +111 -0
- package/server/dist/project-registry.js +16 -1
- package/server/dist/project-repositories.js +51 -2
- package/server/dist/project-router-helpers.js +1 -1
- package/server/dist/project-router-loop-runs.js +4 -1
- package/server/dist/providers/claude-adapter.js +6 -4
- package/server/dist/providers/codex-adapter.js +4 -5
- package/server/dist/schemas/workflow-definition.schema.json +2 -0
- package/server/dist/worktree-manager.js +114 -6
- package/server/dist/worktree-overlay.js +4 -4
- package/client/dist/assets/AgentBrowserCapture-PI-cxyxi.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane-mQsOqdXx.js +0 -2
- package/client/dist/assets/AgentModeCodePane-BL-vpmlY.js +0 -2
- package/client/dist/assets/CodePage-Alitorrv.js +0 -3
- package/client/dist/assets/DocsDialog-DwL6rgcT.js +0 -11
- package/client/dist/assets/DocsPage-BA1hiJZ-.js +0 -11
- package/client/dist/assets/InteractiveJobComposer-B3H1YHr6.js +0 -19
- package/client/dist/assets/JobDetailModal-XZQ9eAAy.js +0 -1
- package/client/dist/assets/JobDetailPage-B-SIaq_q.js +0 -1
- package/client/dist/assets/JobsPage-iQXAv2mx.js +0 -1
- package/client/dist/assets/LoopBuilderPage-B_gbFAHn.js +0 -1
- package/client/dist/assets/LoopsPage-BZwcY5cu.js +0 -2
- package/client/dist/assets/MinimizedChatsContext-CNx_0bZu.js +0 -1
- package/client/dist/assets/PluginsPage-DFocnoHX.js +0 -2
- package/client/dist/assets/ProjectSettingsDialog-Bh3S6EBB.js +0 -1
- package/client/dist/assets/RepositoryScopeSelector-C2mvWBQ6.js +0 -1
- package/client/dist/assets/ReviewPacketPage-CrAf-WDy.js +0 -4
- package/client/dist/assets/TemplatePreviewModal-C7DordpN.js +0 -1
- package/client/dist/assets/TicketDetailModalContext-B-DySpKL.js +0 -16
- package/client/dist/assets/agent-BaG10AN6.js +0 -1
- package/client/dist/assets/agent-CH4aJ884.js +0 -1
- package/client/dist/assets/agent-CLc9fA7v.js +0 -1
- package/client/dist/assets/agent-DHh9-AdL.js +0 -1
- package/client/dist/assets/agent-DkKnd6Wv.js +0 -1
- package/client/dist/assets/agent-aiVhqFW1.js +0 -1
- package/client/dist/assets/agent-dbznD3eO.js +0 -1
- package/client/dist/assets/agent-sMVFcPwL.js +0 -1
- package/client/dist/assets/agentRuntime-BeUb3g9g.js +0 -1
- package/client/dist/assets/file-text-CFT-xXKN.js +0 -1
- package/client/dist/assets/index-BS7KCWkV.css +0 -2
- package/client/dist/assets/index-C4Mv6tV6.js +0 -80
- package/client/dist/assets/integrations-CH0zy1Mw.js +0 -1
- package/client/dist/assets/integrations-CIAjhd7L.js +0 -1
- package/client/dist/assets/integrations-CZdwOe8A.js +0 -1
- package/client/dist/assets/integrations-Ct7omMld.js +0 -1
- package/client/dist/assets/integrations-D6MSxy3-.js +0 -1
- package/client/dist/assets/integrations-DbZa-Zyc.js +0 -1
- package/client/dist/assets/integrations-b8pH-vfl.js +0 -1
- package/client/dist/assets/integrations-mB-7zoyT.js +0 -1
- package/client/dist/assets/jira-api-BYbEPlkr.js +0 -1
- package/client/dist/assets/layers-eDMjG41I.js +0 -1
- package/client/dist/assets/loops-B4_D-nbg.js +0 -1
- package/client/dist/assets/nav-B-tpjyc2.js +0 -1
- package/client/dist/assets/nav-BJNXGg29.js +0 -1
- package/client/dist/assets/nav-BdhtRLP7.js +0 -1
- package/client/dist/assets/nav-ByYgyN5T.js +0 -1
- package/client/dist/assets/nav-DA0Mva2c.js +0 -1
- package/client/dist/assets/nav-DcJm_Jg_.js +0 -1
- package/client/dist/assets/nav-DhMPtAXc.js +0 -1
- package/client/dist/assets/nav-DhPb-Isc.js +0 -1
- package/client/dist/assets/provider-capabilities-Vi1ZGvAK.js +0 -1
- package/client/dist/assets/save-B6wGWwBR.js +0 -1
- package/client/dist/assets/settings-3o4Ntzi5.js +0 -1
- package/client/dist/assets/settings-B97jlkwD.js +0 -1
- package/client/dist/assets/settings-BTaT_bsS.js +0 -1
- package/client/dist/assets/settings-CT8w7WiC.js +0 -1
- package/client/dist/assets/settings-Cvr8_tvh.js +0 -1
- package/client/dist/assets/settings-Dn1qgAC8.js +0 -1
- package/client/dist/assets/settings-EShDdg4J.js +0 -1
- package/client/dist/assets/settings-tfLhQZRN.js +0 -1
- package/client/dist/assets/setup-CBMu3tqH.js +0 -1
- package/client/dist/assets/setup-CPh-e6J2.js +0 -1
- package/client/dist/assets/setup-CRKLp_ke.js +0 -1
- package/client/dist/assets/setup-Cy302v4J.js +0 -1
- package/client/dist/assets/setup-D681vTPf.js +0 -1
- package/client/dist/assets/setup-DYK0VBkE.js +0 -1
- package/client/dist/assets/setup-KAuiIiVs.js +0 -1
- package/client/dist/assets/setup-OGX-oCfI.js +0 -1
- package/client/dist/assets/useSharedWebSocket-BZMrX4jr.js +0 -2
- package/client/dist/assets/wrench-BfmNO9Vw.js +0 -1
- package/docs/agy-cli-provider-study.md +0 -257
- package/docs/gemini-cli-provider-study.md +0 -301
- package/docs/gemini-core-support-evaluation.md +0 -160
- package/docs/gemini.md +0 -257
- package/docs/kimi.md +0 -291
|
@@ -7,6 +7,7 @@ exports.readFrozenRuntimeHost = readFrozenRuntimeHost;
|
|
|
7
7
|
exports.runAgentRuntimeInvocation = runAgentRuntimeInvocation;
|
|
8
8
|
exports.assertRetainedForkSupport = assertRetainedForkSupport;
|
|
9
9
|
exports.runAgentRuntimeControl = runAgentRuntimeControl;
|
|
10
|
+
const agent_runtime_verification_suggestions_1 = require("./agent-runtime-verification-suggestions");
|
|
10
11
|
const agent_runtime_history_1 = require("./agent-runtime-history");
|
|
11
12
|
const agent_runtime_repositories_1 = require("./agent-runtime-repositories");
|
|
12
13
|
const node_util_1 = require("node:util");
|
|
@@ -32,15 +33,126 @@ function runtimeChangeName(runId) {
|
|
|
32
33
|
* cwd is relative to the registered directory; one already inside the scope is kept.
|
|
33
34
|
*/
|
|
34
35
|
function scopedHostChecks(checks, repositories = []) {
|
|
35
|
-
return checks.
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
return checks.flatMap(check => {
|
|
37
|
+
const repository = repositories.find(repository => repository.id === check.repositoryId);
|
|
38
|
+
const scopes = repository?.scope;
|
|
39
|
+
if (!repository || !scopes?.length)
|
|
40
|
+
return [check];
|
|
41
|
+
if (check.cwd === undefined)
|
|
42
|
+
return scopes.map((scope, index) => ({ ...check, cwd: scope,
|
|
43
|
+
...(check.key && scopes.length > 1 ? { key: check.key.slice(0, 90) + '-workspace-' + index } : {}),
|
|
44
|
+
}));
|
|
45
|
+
const declared = repository.registeredScope;
|
|
46
|
+
const inputCwd = check.cwd.replace(/\\/g, '/');
|
|
47
|
+
const rawCwd = (0, node_path_1.isAbsolute)(inputCwd) && repository.path ? (0, node_path_1.relative)(repository.path, inputCwd).split(node_path_1.sep).join('/') : inputCwd;
|
|
48
|
+
if (!(0, node_path_1.isAbsolute)(rawCwd) && declared?.some(root => rawCwd === root || rawCwd.startsWith(root + '/')) && !scopes.some(root => rawCwd === root || rawCwd.startsWith(root + '/')))
|
|
49
|
+
return [];
|
|
50
|
+
let cwd = check.cwd.replace(/\\/g, '/');
|
|
51
|
+
if ((0, node_path_1.isAbsolute)(cwd)) {
|
|
52
|
+
if (!repository.path)
|
|
53
|
+
throw new Error('Verification workspace root is unavailable');
|
|
54
|
+
cwd = (0, node_path_1.relative)(repository.path, cwd).split(node_path_1.sep).join('/');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const normalized = node_path_1.posix.normalize(cwd);
|
|
58
|
+
if (scopes.some(scope => cwd === scope || cwd.startsWith(scope + '/')))
|
|
59
|
+
cwd = normalized;
|
|
60
|
+
else if (scopes.length === 1)
|
|
61
|
+
cwd = node_path_1.posix.join(scopes[0], normalized);
|
|
62
|
+
else
|
|
63
|
+
throw new Error('Verification must select an explicit workspace cwd when several scopes are configured');
|
|
64
|
+
}
|
|
65
|
+
cwd = node_path_1.posix.normalize(cwd);
|
|
66
|
+
if (!scopes.some(root => cwd === root || cwd.startsWith(root + '/')))
|
|
67
|
+
throw new Error(`Verification cwd ${JSON.stringify(check.cwd)} escapes the selected code workspace ${scopes.join(', ')}`);
|
|
68
|
+
return [{ ...check, cwd }];
|
|
42
69
|
});
|
|
43
70
|
}
|
|
71
|
+
/** Discover only checks belonging to the admitted worktrees. Explicit host
|
|
72
|
+
* checks win; inferred commands are frozen per run, never saved to project settings. */
|
|
73
|
+
function completeHostChecks(config, repositories) {
|
|
74
|
+
for (const repository of repositories) {
|
|
75
|
+
if (config.verification.some(check => check.repositoryId === repository.id) || !repository.path)
|
|
76
|
+
continue;
|
|
77
|
+
const workspacePaths = (repository.scope?.length ? repository.scope.map(scope => (0, node_path_1.resolve)(repository.path, scope)) : [repository.path]).filter(workspace => (0, node_fs_1.existsSync)(workspace));
|
|
78
|
+
const root = (0, node_fs_1.realpathSync)(repository.path);
|
|
79
|
+
for (const workspace of workspacePaths) {
|
|
80
|
+
const inside = (0, node_path_1.relative)(root, (0, node_fs_1.realpathSync)(workspace));
|
|
81
|
+
if ((0, node_path_1.isAbsolute)(inside) || inside === '..' || inside.startsWith('..' + node_path_1.sep))
|
|
82
|
+
throw new Error('Verification workspace escapes its admitted repository');
|
|
83
|
+
}
|
|
84
|
+
const suggestions = (0, agent_runtime_verification_suggestions_1.suggestVerificationCommands)([{ id: repository.id, path: repository.path, workspacePaths }]);
|
|
85
|
+
config.verification.push(...suggestions.map(({ reason: _reason, ...check }) => check));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Configured-only gates cannot obtain missing checks from an agent later. */
|
|
89
|
+
function requiresConfiguredChecks(value) {
|
|
90
|
+
if (!value || typeof value !== 'object')
|
|
91
|
+
return false;
|
|
92
|
+
const body = value;
|
|
93
|
+
return Object.values(body.nodes ?? {}).some(node => node.kind === 'verify' && node.params?.commands === 'configured' && !node.params.additionalCommandsFrom && node.params.unverified !== true)
|
|
94
|
+
|| Object.values(body.components ?? {}).some(requiresConfiguredChecks);
|
|
95
|
+
}
|
|
96
|
+
/** Keep TAP failure diagnostics and totals in the readable log. The unfiltered
|
|
97
|
+
* event stream remains available as runtime evidence. State is invocation-local. */
|
|
98
|
+
function verificationLogFilter() {
|
|
99
|
+
const streams = new Map();
|
|
100
|
+
return text => (0, node_util_1.stripVTControlCharacters)(text).split(/(?<=\n)/).flatMap(line => {
|
|
101
|
+
const match = line.match(/^(\[verification [^\]]+\] )?(.*?)(?:\n)?$/);
|
|
102
|
+
if (!match)
|
|
103
|
+
return [line];
|
|
104
|
+
const key = match[1] ?? '', body = match[2].trim();
|
|
105
|
+
const state = streams.get(key) ?? { tap: false, failed: false, yaml: false, inputLines: null };
|
|
106
|
+
streams.set(key, state);
|
|
107
|
+
if (/AssertionError\b.*\bInput:\s*$/.test(body))
|
|
108
|
+
state.inputLines = 0;
|
|
109
|
+
else if (state.inputLines !== null) {
|
|
110
|
+
// Node prints assert.match's entire source input as quoted concatenation
|
|
111
|
+
// lines. Bound only that block; stacks, expected values and other streams
|
|
112
|
+
// remain visible and original events remain intact.
|
|
113
|
+
if (/^["'`]/.test(body)) {
|
|
114
|
+
state.inputLines++;
|
|
115
|
+
if (state.inputLines > 2)
|
|
116
|
+
return state.inputLines === 3 ? [key + '[Assertion input shortened; inspect raw evidence]\n'] : [];
|
|
117
|
+
}
|
|
118
|
+
else if (!body)
|
|
119
|
+
return [];
|
|
120
|
+
else
|
|
121
|
+
state.inputLines = null;
|
|
122
|
+
}
|
|
123
|
+
if (/^[✔✓]\s/.test(body))
|
|
124
|
+
return [];
|
|
125
|
+
if (/^[✖✗]\s/.test(body)) {
|
|
126
|
+
state.failed = true;
|
|
127
|
+
return [line];
|
|
128
|
+
}
|
|
129
|
+
if (/^TAP version |^# Subtest:/.test(body)) {
|
|
130
|
+
state.tap = true;
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
if (/^(?:not )?ok \d+\b/.test(body)) {
|
|
134
|
+
state.tap = true;
|
|
135
|
+
state.failed = body.startsWith('not ok');
|
|
136
|
+
state.yaml = false;
|
|
137
|
+
return state.failed ? [line] : [];
|
|
138
|
+
}
|
|
139
|
+
if (!state.tap)
|
|
140
|
+
return [line];
|
|
141
|
+
if (body === '---') {
|
|
142
|
+
state.yaml = true;
|
|
143
|
+
return state.failed ? [line] : [];
|
|
144
|
+
}
|
|
145
|
+
if (body === '...') {
|
|
146
|
+
state.yaml = false;
|
|
147
|
+
return state.failed ? [line] : [];
|
|
148
|
+
}
|
|
149
|
+
if (state.yaml)
|
|
150
|
+
return state.failed ? [line] : [];
|
|
151
|
+
if (/^1\.\.\d+$/.test(body) || !body)
|
|
152
|
+
return [];
|
|
153
|
+
return [line];
|
|
154
|
+
}).map(line => line.length > 2_000 ? line.slice(0, 1_900) + '\n[Long diagnostic line shortened; inspect raw evidence]\n' : line).join('');
|
|
155
|
+
}
|
|
44
156
|
exports.RUNTIME_HOST_ENV_KEYS = [
|
|
45
157
|
'SPECRAILS_REPO_DIR', 'SPECRAILS_GIT_AUTO', 'SPECRAILS_REPO_MAP_PATH',
|
|
46
158
|
'SPECRAILS_EXECUTION_CONTEXT', 'SPECRAILS_EXECUTION_MANIFEST', 'SPECRAILS_REPOSITORIES',
|
|
@@ -80,7 +192,7 @@ function readFrozenRuntimeHost(contextPath, baseEnv, runId) {
|
|
|
80
192
|
* rail's cancellation and worktree ownership remain in Desktop. */
|
|
81
193
|
async function runAgentRuntimeInvocation(options) {
|
|
82
194
|
const definitionEngine = options.engineVersion === 2 || options.definitionPath !== undefined || options.prepareDefinition !== undefined;
|
|
83
|
-
if (options.resume && (options.definitionPath || options.prepareDefinition || options.workflowRoleBindings))
|
|
195
|
+
if (options.resume && (options.definitionPath || options.prepareDefinition || options.workflowRoleBindings || options.loopConfig))
|
|
84
196
|
throw new Error('Resume must use the frozen workflow definition and role bindings');
|
|
85
197
|
const selectedCli = options.resume ? (0, agent_runtime_package_1.resolveRetainedAgentRuntime)(options.contextPath) : (0, agent_runtime_loader_1.findCoreAgentRuntimeCli)();
|
|
86
198
|
let cli = selectedCli;
|
|
@@ -96,11 +208,14 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
96
208
|
if (!Array.isArray(admittedContext.repositories) || !admittedContext.repositories.length || admittedContext.repositories.some(repo => !repo || typeof repo.id !== 'string' || !repo.id))
|
|
97
209
|
throw new Error('Core context is missing its repository scope');
|
|
98
210
|
const source = (0, node_fs_1.existsSync)(options.configPath) ? 'project-role' : 'default';
|
|
99
|
-
const { config, origins } = (0, agent_runtime_effective_config_1.resolveEffectiveRuntimeConfig)((0, agent_runtime_settings_1.loadRuntimeConfigFile)(options.configPath, options.defaultProvider), {
|
|
100
|
-
repositoryIds: admittedContext.repositories.map(repo => repo.id), source, providerOverride: options.providerOverride,
|
|
211
|
+
const { config, origins } = (0, agent_runtime_effective_config_1.resolveEffectiveRuntimeConfig)(options.loopConfig ? (0, agent_runtime_settings_1.loadLoopRuntimeConfig)(options.configPath, options.loopConfig, options.providerOverride ?? { provider: options.defaultProvider ?? 'claude' }) : (0, agent_runtime_settings_1.loadRuntimeConfigFile)(options.configPath, options.defaultProvider), {
|
|
212
|
+
repositoryIds: admittedContext.repositories.map(repo => repo.id), source: options.loopConfig ? 'loop-role' : source, providerOverride: options.loopConfig ? undefined : options.providerOverride,
|
|
101
213
|
});
|
|
102
214
|
config.verification = scopedHostChecks(config.verification, admittedContext.repositories);
|
|
103
|
-
|
|
215
|
+
if (definitionEngine)
|
|
216
|
+
completeHostChecks(config, admittedContext.repositories);
|
|
217
|
+
if (!options.loopConfig)
|
|
218
|
+
config.rolePrompts = { ...(await (0, agent_runtime_loader_1.loadCoreAgentRuntime)()).rolePromptDefaults(), ...(0, agent_runtime_settings_1.loadRuntimeRolePrompts)(), ...config.rolePrompts };
|
|
104
219
|
// Core rejects unknown connection keys: drop the desktop-only local-engine
|
|
105
220
|
// fields (label/defaultModel/rates/supportsReasoningEffort) before Core sees it.
|
|
106
221
|
const runtime = await (0, agent_runtime_loader_1.loadCoreAgentRuntime)();
|
|
@@ -119,9 +234,21 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
119
234
|
: options.definitionPath ? JSON.parse((0, node_fs_1.readFileSync)(options.definitionPath, 'utf8')) : undefined : undefined;
|
|
120
235
|
if (definitionEngine && !draft)
|
|
121
236
|
throw new Error('A new Core workflow requires a definition');
|
|
237
|
+
if (requiresConfiguredChecks(draft)) {
|
|
238
|
+
const missing = admittedContext.repositories.filter(repository => !config.verification.some(check => check.repositoryId === repository.id));
|
|
239
|
+
if (missing.length)
|
|
240
|
+
throw new Error(`verification_checks_missing: No configured or detected verification commands for ${missing.map(repository => repository.name ?? repository.id).join(', ')}. Configure checks in project agent-runtime settings before starting this workflow.`);
|
|
241
|
+
if (config.verification.length > 100)
|
|
242
|
+
throw new Error('verification_checks_limit: This workflow supports at most 100 verification commands. Reduce the configured checks before starting it.');
|
|
243
|
+
}
|
|
122
244
|
const selectedOrigins = (0, agent_runtime_effective_config_1.bindWorkflowRoleSelections)(config, draft, options.workflowRoleBindings);
|
|
245
|
+
if (options.loopConfig && draft?.roles?.includes('loop-decider') && !config.roles?.['loop-decider'])
|
|
246
|
+
throw new Error('The loop must define its loop-decider agent');
|
|
123
247
|
const workflowOrigins = { ...(0, agent_runtime_effective_config_1.bindWorkflowRoleDefaults)(config, draft), ...selectedOrigins };
|
|
124
|
-
|
|
248
|
+
if (options.loopConfig)
|
|
249
|
+
for (const role of Object.keys(config.roles ?? {}))
|
|
250
|
+
workflowOrigins[role] = 'loop-role';
|
|
251
|
+
const override = options.loopConfig ? undefined : options.providerOverride;
|
|
125
252
|
runtime.validateRuntimeConfig(JSON.parse(JSON.stringify(config)));
|
|
126
253
|
(0, agent_runtime_loader_1.validateRequestedRoleEfforts)(runtime, config);
|
|
127
254
|
cli = (0, agent_runtime_package_1.retainAgentRuntime)(cli, options.contextPath);
|
|
@@ -169,6 +296,17 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
169
296
|
const definitionFile = (0, node_path_1.join)((0, node_path_1.dirname)(options.contextPath), 'desktop-workflow-definition.json');
|
|
170
297
|
const requiresVerified = definitionEngine && JSON.parse((0, node_fs_1.readFileSync)(definitionFile, 'utf8')).delivery?.requiresVerified === true;
|
|
171
298
|
const frozenPath = (0, node_path_1.join)((0, node_path_1.dirname)(options.contextPath), 'desktop-runtime-config.json');
|
|
299
|
+
if ((0, node_fs_1.existsSync)(frozenPath)) {
|
|
300
|
+
const checks = JSON.parse((0, node_fs_1.readFileSync)(frozenPath, 'utf8')).verification;
|
|
301
|
+
for (const check of checks) {
|
|
302
|
+
const repository = admittedContext.repositories?.find(repo => repo.id === check.repositoryId);
|
|
303
|
+
const cwd = repository?.path ? (0, node_path_1.resolve)(repository.path, check.cwd ?? repository.scope?.[0] ?? '.') : check.cwd;
|
|
304
|
+
try {
|
|
305
|
+
options.onLine?.(`[verification scope] ${JSON.stringify({ repositoryId: check.repositoryId, workspace: repository?.name, cwd, command: check.command, args: check.args })}\n`);
|
|
306
|
+
}
|
|
307
|
+
catch { /* Advisory log observer. */ }
|
|
308
|
+
}
|
|
309
|
+
}
|
|
172
310
|
if ((0, node_fs_1.existsSync)(frozenPath)) {
|
|
173
311
|
const frozen = JSON.parse((0, node_fs_1.readFileSync)(frozenPath, 'utf8'));
|
|
174
312
|
for (const [role, assignment] of [...Object.entries(frozen.agents), ...(frozen.fixer ? [['fixer', frozen.fixer]] : [])]) {
|
|
@@ -198,6 +336,7 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
198
336
|
let result;
|
|
199
337
|
let graph;
|
|
200
338
|
let stderr = '', summary = '', invalidProtocol = false, timedOut = false;
|
|
339
|
+
const stepFailures = new Map();
|
|
201
340
|
let timer;
|
|
202
341
|
const child = (0, node_child_process_1.spawn)((0, core_node_runtime_1.resolveCoreNodeRuntime)(), args, {
|
|
203
342
|
cwd: options.cwd, env: (0, win_spawn_1.windowsSpawnEnv)(options.env), shell: false, windowsHide: true,
|
|
@@ -217,6 +356,7 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
217
356
|
callback?.();
|
|
218
357
|
}
|
|
219
358
|
catch { /* Logging cannot replay a workflow. */ } };
|
|
359
|
+
const readableVerification = verificationLogFilter();
|
|
220
360
|
const lines = (0, node_readline_1.createInterface)({ input: child.stdout });
|
|
221
361
|
lines.on('line', line => {
|
|
222
362
|
if (line.length > 2_000_000) {
|
|
@@ -267,8 +407,17 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
267
407
|
}
|
|
268
408
|
else if (event.type === 'workflow-event') {
|
|
269
409
|
const payload = event.event;
|
|
270
|
-
|
|
271
|
-
|
|
410
|
+
const kind = payload?.type === 'step_succeeded' && payload.outcome === 'fail' ? 'verification_failed' : payload?.type;
|
|
411
|
+
const detail = payload?.error?.message ?? payload?.message;
|
|
412
|
+
const stepKey = JSON.stringify([payload?.scopeId ?? null, payload?.nodePath ?? payload?.stepId ?? null]);
|
|
413
|
+
if (payload?.type === 'step_failed' && typeof detail === 'string' && detail.trim()) {
|
|
414
|
+
stepFailures.delete(stepKey);
|
|
415
|
+
stepFailures.set(stepKey, detail.trim().slice(0, 4_000));
|
|
416
|
+
}
|
|
417
|
+
else if (payload?.type === 'step_succeeded')
|
|
418
|
+
stepFailures.delete(stepKey);
|
|
419
|
+
if (kind)
|
|
420
|
+
observe(() => options.onLine?.(`[runtime] ${kind}${payload.stepId ? ': ' + payload.stepId : ''}${detail ? ' — ' + detail : ''}\n`));
|
|
272
421
|
}
|
|
273
422
|
else if (event.type === 'agent-event') {
|
|
274
423
|
const payload = event.event;
|
|
@@ -285,7 +434,9 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
285
434
|
}
|
|
286
435
|
}
|
|
287
436
|
else if (event.type === 'verification-output' && typeof event.text === 'string') {
|
|
288
|
-
|
|
437
|
+
const readable = readableVerification(String(event.text));
|
|
438
|
+
if (readable)
|
|
439
|
+
observe(() => options.onLine?.(readable));
|
|
289
440
|
}
|
|
290
441
|
else if (event.type === 'span') {
|
|
291
442
|
// Trace spans are telemetry; the raw line is already recorded for diagnostics.
|
|
@@ -321,6 +472,7 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
321
472
|
const validPause = definitionEngine && code === 2 && result?.status === 'paused';
|
|
322
473
|
const failed = (!validPause && (code !== 0 || result?.status !== 'succeeded')) || invalidProtocol || timedOut || Boolean(observerError) || Boolean(acceptanceBlocked);
|
|
323
474
|
const runtimeError = typeof result?.error === 'string' ? result.error : result?.error?.message;
|
|
475
|
+
const completionError = Array.isArray(result?.completion?.reasons) ? result.completion.reasons.filter(reason => typeof reason === 'string' && reason.trim()).join('; ').slice(0, 4_000) : '';
|
|
324
476
|
const runtimeStatus = invalidProtocol || timedOut || observerError || (result?.status === 'paused' && !validPause) || (result?.status === 'succeeded' && code !== 0) ? 'failed' : acceptanceBlocked ? 'blocked' : ['succeeded', 'paused', 'failed', 'blocked', 'cancelled'].includes(result?.status ?? '') ? result.status : 'failed';
|
|
325
477
|
const errorText = observerError ?? (timedOut ? 'Programmatic workflow timed out; inspect its checkpoint before recovery'
|
|
326
478
|
: invalidProtocol ? 'Core returned an invalid runtime event stream'
|
|
@@ -328,9 +480,9 @@ async function runAgentRuntimeInvocation(options) {
|
|
|
328
480
|
: runtimeError ?? (result?.status === 'paused' ? (typeof result.pendingQuestion?.question === 'string' && result.pendingQuestion.question.trim()
|
|
329
481
|
? `Workflow awaits an answer in Agent Runtime settings: ${result.pendingQuestion.question.trim().slice(0, 500)}`
|
|
330
482
|
: 'Workflow awaits approval in Agent Runtime settings')
|
|
331
|
-
: failed ? stderr || 'Core exited without a successful programmatic workflow result' : undefined));
|
|
483
|
+
: failed ? completionError || [...stepFailures.values()].at(-1) || stderr || 'Core exited without a successful programmatic workflow result' : undefined));
|
|
332
484
|
try {
|
|
333
|
-
(0, agent_runtime_history_1.writeRuntimeHistory)(options.contextPath, invalidProtocol || timedOut || observerError || !result ? { status: 'failed', error: errorText } : { ...result });
|
|
485
|
+
(0, agent_runtime_history_1.writeRuntimeHistory)(options.contextPath, invalidProtocol || timedOut || observerError || !result ? { status: 'failed', error: errorText } : { ...result, ...(failed && errorText ? { error: errorText } : {}) });
|
|
334
486
|
}
|
|
335
487
|
catch { /* Projection failure cannot replay a completed execution. */ }
|
|
336
488
|
resolve({
|
|
@@ -121,7 +121,7 @@ function applyRuntimeSelectionOrigins(summary, selection, runId) {
|
|
|
121
121
|
const record = object(selection), origins = object(record?.origins);
|
|
122
122
|
if (!summary || record?.schemaVersion !== 1 || record.runId !== runId || !origins)
|
|
123
123
|
return summary;
|
|
124
|
-
if (!['architect', 'developer', 'reviewer'].every(role => ['project-role', 'default', ...(role === 'developer' ? ['explicit-launch-override'] : [])].includes(String(origins[role]))))
|
|
124
|
+
if (!['architect', 'developer', 'reviewer'].every(role => ['loop-role', 'project-role', 'default', ...(role === 'developer' ? ['explicit-launch-override'] : [])].includes(String(origins[role]))))
|
|
125
125
|
return summary;
|
|
126
126
|
return { ...summary, roles: summary.roles.map(role => {
|
|
127
127
|
const origin = origins[role.role];
|
|
@@ -84,7 +84,7 @@ function registerAgentRuntimeSettingsRoutes({ router, ctx }) {
|
|
|
84
84
|
router.get('/:projectId/agent-runtime/verification-suggestions', (req, res) => {
|
|
85
85
|
try {
|
|
86
86
|
const project = ctx(req).project;
|
|
87
|
-
const repositories = (0, project_repositories_1.getProjectRepositories)(project).map((repository) => ({ id: repository.id, name: repository.name, path: repository.path }));
|
|
87
|
+
const repositories = (0, project_repositories_1.getProjectRepositories)(project).map((repository) => ({ id: repository.id, name: repository.name, path: repository.path, workspacePath: repository.workspacePath, workspacePaths: repository.workspacePaths }));
|
|
88
88
|
res.json({ repositories: repositories.map(({ id, name }) => ({ id, name })), suggestions: (0, agent_runtime_verification_suggestions_1.suggestVerificationCommands)(repositories) });
|
|
89
89
|
}
|
|
90
90
|
catch {
|
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.AgentRuntimeConfigError = exports.REVIEW_THRESHOLD_FLOORS = exports.MAX_OUTPUT_TOKENS_MAX = exports.MAX_OUTPUT_TOKENS_MIN = exports.CONTEXT_WINDOW_TOKENS_MAX = exports.CONTEXT_WINDOW_TOKENS_MIN = exports.RUNTIME_ROLE_ID = void 0;
|
|
7
7
|
exports.stripDesktopConnectionFields = stripDesktopConnectionFields;
|
|
8
8
|
exports.coreConnectionFieldGates = coreConnectionFieldGates;
|
|
9
|
+
exports.validateLoopRuntimeSettings = validateLoopRuntimeSettings;
|
|
10
|
+
exports.loadLoopRuntimeConfig = loadLoopRuntimeConfig;
|
|
9
11
|
exports.validateAgentRuntimeConfig = validateAgentRuntimeConfig;
|
|
10
12
|
exports.defaultAgentRuntimeConfig = defaultAgentRuntimeConfig;
|
|
11
13
|
exports.agentRuntimeConfigPath = agentRuntimeConfigPath;
|
|
@@ -121,6 +123,46 @@ exports.REVIEW_THRESHOLD_FLOORS = {
|
|
|
121
123
|
minScore: 70,
|
|
122
124
|
aspects: { type_correctness: 60, pattern_adherence: 60, test_coverage: 60, security: 75, architectural_alignment: 60 },
|
|
123
125
|
};
|
|
126
|
+
/** Validate a portable recipe without accepting host-owned fields or project fallbacks. */
|
|
127
|
+
function validateLoopRuntimeSettings(input, providers = loadRuntimeProviders()) {
|
|
128
|
+
if (!input || typeof input !== 'object' || Array.isArray(input) || Object.keys(input).some(key => ![
|
|
129
|
+
'schemaVersion', 'agents', 'fixer', 'roles', 'rolePrompts', 'limits', 'review', 'architect', 'approvalBeforeArchive', 'efficiency', 'guardrails',
|
|
130
|
+
].includes(key)))
|
|
131
|
+
throw new AgentRuntimeConfigError('Invalid loop agent configuration');
|
|
132
|
+
// "inherit" is a recipe-only assignment, resolved before Core sees it.
|
|
133
|
+
const portableProviders = [...providers, { id: 'inherit', kind: 'cli', cli: 'claude' }];
|
|
134
|
+
const config = validateAgentRuntimeConfig({ ...input, enabled: true, providers: portableProviders, verification: [] });
|
|
135
|
+
if (['architect', 'developer', 'reviewer', 'fixer'].some(role => !config.rolePrompts?.[role]?.trim()))
|
|
136
|
+
throw new AgentRuntimeConfigError('Loop agents require an explicit definition for architect, developer, reviewer and fixer');
|
|
137
|
+
const { enabled: _enabled, providers: _providers, verification: _checks, ...settings } = config;
|
|
138
|
+
return settings;
|
|
139
|
+
}
|
|
140
|
+
/** Read only repository checks from the old project file. Role migration is explicit. */
|
|
141
|
+
function loadLoopRuntimeConfig(file, input, selection = { provider: 'claude' }) {
|
|
142
|
+
let verification = [];
|
|
143
|
+
try {
|
|
144
|
+
const saved = JSON.parse(node_fs_1.default.readFileSync(file, 'utf8'));
|
|
145
|
+
if (!saved || typeof saved !== 'object' || Array.isArray(saved))
|
|
146
|
+
throw new AgentRuntimeConfigError('Saved runtime configuration must be an object');
|
|
147
|
+
verification = saved.verification ?? [];
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error.code !== 'ENOENT')
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
const providers = loadRuntimeProviders();
|
|
154
|
+
const settings = validateLoopRuntimeSettings(input, providers);
|
|
155
|
+
const inherit = (agent) => agent.provider !== 'inherit' ? agent : {
|
|
156
|
+
...agent, provider: selection.provider, model: agent.model ?? selection.model, effort: agent.effort ?? selection.effort,
|
|
157
|
+
};
|
|
158
|
+
for (const role of ROLES)
|
|
159
|
+
settings.agents[role] = inherit(settings.agents[role]);
|
|
160
|
+
if (settings.fixer)
|
|
161
|
+
settings.fixer = inherit(settings.fixer);
|
|
162
|
+
for (const [role, agent] of Object.entries(settings.roles ?? {}))
|
|
163
|
+
settings.roles[role] = inherit(agent);
|
|
164
|
+
return validateAgentRuntimeConfig({ ...settings, providers, enabled: true, verification });
|
|
165
|
+
}
|
|
124
166
|
const CLI_PROVIDERS = ['claude', 'codex', 'gemini', 'kimi'];
|
|
125
167
|
const ROLES = ['architect', 'developer', 'reviewer'];
|
|
126
168
|
const schemaValidator = new ajv_1.default({ allErrors: true }).compile(agent_runtime_schema_json_1.default);
|
|
@@ -110,10 +110,16 @@ function otherSuggestions(repository) {
|
|
|
110
110
|
function suggestVerificationCommands(repositories) {
|
|
111
111
|
const out = [];
|
|
112
112
|
for (const repository of repositories) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
const workspaces = repository.workspacePaths ?? (repository.workspacePath ? [repository.workspacePath] : [repository.path]);
|
|
114
|
+
for (const workspace of workspaces) {
|
|
115
|
+
if (!workspace || !node_fs_1.default.existsSync(workspace))
|
|
116
|
+
continue;
|
|
117
|
+
const member = { ...repository, path: workspace };
|
|
118
|
+
const node = nodeSuggestions(member);
|
|
119
|
+
const checks = node.length ? node : otherSuggestions(member);
|
|
120
|
+
const cwd = node_path_1.default.relative(repository.path, workspace).split(node_path_1.default.sep).join('/');
|
|
121
|
+
out.push(...checks.map(check => cwd ? { ...check, cwd, reason: `${cwd}: ${check.reason}` } : check));
|
|
122
|
+
}
|
|
117
123
|
}
|
|
118
124
|
return out;
|
|
119
125
|
}
|
|
@@ -4,14 +4,11 @@
|
|
|
4
4
|
// "Launch Milestone N": order the milestone's todo specs by their declared
|
|
5
5
|
// dependencies (prerequisites, then execution_order), put ONE spec on each
|
|
6
6
|
// rail (mode `implement`), launch the first through the ORDINARY rails launch
|
|
7
|
-
// route, and
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// `rail.pr_state` broadcast tapped in the project's bound broadcast — the
|
|
13
|
-
// engine's `onLoopRunFinished` fires BEFORE the delivery row leaves
|
|
14
|
-
// `building`, so it is only a fallback for delivery-less shared-cwd runs),
|
|
7
|
+
// route, and integrate each completed delivery through the guarded local decision
|
|
8
|
+
// path BEFORE allocating the next worktree from the integration branch. Older
|
|
9
|
+
// adapters without integration retain their historical stacking behavior.
|
|
10
|
+
// Launches are sequential; auto-continue is on by default. The plan lives in
|
|
11
|
+
// SQLite and retains the current delivery through integration and recovery.
|
|
15
12
|
// pauses with a typed reason on any failure (never skips ahead), and is
|
|
16
13
|
// visible/controllable (resume / cancel) from every surface.
|
|
17
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -77,6 +74,7 @@ class MilestoneChainManager {
|
|
|
77
74
|
db;
|
|
78
75
|
projectId;
|
|
79
76
|
io;
|
|
77
|
+
integrating = new Set();
|
|
80
78
|
constructor(db, projectId, io) {
|
|
81
79
|
this.db = db;
|
|
82
80
|
this.projectId = projectId;
|
|
@@ -218,7 +216,7 @@ class MilestoneChainManager {
|
|
|
218
216
|
}
|
|
219
217
|
/**
|
|
220
218
|
* Launch a milestone. Always sequential: one spec per rail, each stacked on
|
|
221
|
-
* the
|
|
219
|
+
* the accumulated integration branch when integration is bound. `autoAdvance` defaults to ON; turning it off
|
|
222
220
|
* parks the chain at a checkpoint after every delivered rail.
|
|
223
221
|
*/
|
|
224
222
|
async start(n, opts = {}) {
|
|
@@ -308,7 +306,7 @@ class MilestoneChainManager {
|
|
|
308
306
|
return;
|
|
309
307
|
}
|
|
310
308
|
const earlierDeliveries = (0, milestone_chain_store_1.parseLaunched)(row).filter((entry) => entry.chunk <= chunkIndex && entry.deliveryId).map((entry) => entry.deliveryId);
|
|
311
|
-
const multiRepositoryHistory = earlierDeliveries.some((id) => this.io.getDelivery(id)?.executionManifest);
|
|
309
|
+
const multiRepositoryHistory = !this.io.integrateDelivery && earlierDeliveries.some((id) => this.io.getDelivery(id)?.executionManifest);
|
|
312
310
|
if (!multiRepositoryHistory && head && !(await this.branchExistsSafe(head))) {
|
|
313
311
|
this.pause(row, 'head_missing', { headBranch: head });
|
|
314
312
|
return;
|
|
@@ -371,6 +369,56 @@ class MilestoneChainManager {
|
|
|
371
369
|
return 'chunk_stopped';
|
|
372
370
|
return 'chunk_failed';
|
|
373
371
|
}
|
|
372
|
+
completeIntegrated(row) {
|
|
373
|
+
if (!row.current_delivery_id || !(0, milestone_chain_store_1.isActiveChainStatus)(row.status))
|
|
374
|
+
return;
|
|
375
|
+
(0, milestone_chain_store_1.updateChain)(this.db, row.id, row.status, { status: 'waiting', currentDeliveryId: null, currentRunIds: [], headBranch: row.integration_branch, pauseReason: 'integration_complete' }, this.now());
|
|
376
|
+
this.afterChunkSuccess(row.id, row.integration_branch);
|
|
377
|
+
}
|
|
378
|
+
/** Keep the delivery attached until its guarded integration is durably confirmed. */
|
|
379
|
+
async integrateChunk(chainId) {
|
|
380
|
+
if (!this.io.integrateDelivery || this.integrating.has(chainId))
|
|
381
|
+
return;
|
|
382
|
+
const row = (0, milestone_chain_store_1.getChain)(this.db, chainId);
|
|
383
|
+
if (!row?.current_delivery_id || !(0, milestone_chain_store_1.isActiveChainStatus)(row.status))
|
|
384
|
+
return;
|
|
385
|
+
const snap = this.io.getDelivery(row.current_delivery_id);
|
|
386
|
+
if (!snap) {
|
|
387
|
+
this.pause(row, 'integration_failed:delivery_missing');
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (snap.implementationOutcome === 'partially_succeeded' || snap.implementationOutcome === 'failed') {
|
|
391
|
+
this.pauseFailedChunk(row, 'chunk_failed');
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (snap.decision === 'merged' || snap.decision === 'completed') {
|
|
395
|
+
this.completeIntegrated(row);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
this.integrating.add(chainId);
|
|
399
|
+
(0, milestone_chain_store_1.updateChain)(this.db, row.id, row.status, { status: 'waiting', pauseReason: 'integration_pending' }, this.now());
|
|
400
|
+
const pending = (0, milestone_chain_store_1.getChain)(this.db, chainId);
|
|
401
|
+
this.emit(pending);
|
|
402
|
+
try {
|
|
403
|
+
const result = await this.io.integrateDelivery(snap);
|
|
404
|
+
const current = (0, milestone_chain_store_1.getChain)(this.db, chainId);
|
|
405
|
+
if (!current || !(0, milestone_chain_store_1.isActiveChainStatus)(current.status) || current.current_delivery_id !== snap.id)
|
|
406
|
+
return;
|
|
407
|
+
const settled = this.io.getDelivery(snap.id);
|
|
408
|
+
if (settled?.decision === 'merged' || settled?.decision === 'completed')
|
|
409
|
+
this.completeIntegrated(current);
|
|
410
|
+
else
|
|
411
|
+
this.pause(current, 'integration_failed:' + (result.ok ? 'not_confirmed' : result.error));
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
const current = (0, milestone_chain_store_1.getChain)(this.db, chainId);
|
|
415
|
+
if (current && (0, milestone_chain_store_1.isActiveChainStatus)(current.status) && current.current_delivery_id === snap.id)
|
|
416
|
+
this.pause(current, 'integration_failed:unavailable');
|
|
417
|
+
}
|
|
418
|
+
finally {
|
|
419
|
+
this.integrating.delete(chainId);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
374
422
|
/** The delivery-settle chokepoint: a `rail.pr_state` for the in-flight chunk. */
|
|
375
423
|
handleDeliveryState(snap) {
|
|
376
424
|
for (const row of (0, milestone_chain_store_1.listActiveChains)(this.db)) {
|
|
@@ -378,6 +426,13 @@ class MilestoneChainManager {
|
|
|
378
426
|
continue;
|
|
379
427
|
if (snap.decision === 'building')
|
|
380
428
|
continue;
|
|
429
|
+
if (this.io.integrateDelivery && SUCCESS_DECISIONS.has(snap.decision)) {
|
|
430
|
+
if (row.status === 'running' || row.status === 'waiting' && row.pause_reason === 'integration_pending')
|
|
431
|
+
void this.integrateChunk(row.id);
|
|
432
|
+
else if (row.pause_reason?.startsWith('integration_') && ['merged', 'completed'].includes(snap.decision))
|
|
433
|
+
this.completeIntegrated(row);
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
381
436
|
if (SUCCESS_DECISIONS.has(snap.decision)) {
|
|
382
437
|
const delivered = snap.executionManifest ? null : snap.decision === 'no_changes'
|
|
383
438
|
? row.head_branch
|
|
@@ -457,6 +512,10 @@ class MilestoneChainManager {
|
|
|
457
512
|
return { ok: false, status: 404, error: 'chain_not_found' };
|
|
458
513
|
if (row.status !== 'paused' && row.status !== 'awaiting_approval')
|
|
459
514
|
return { ok: false, status: 409, error: 'chain_not_paused', detail: `chain is ${row.status}` };
|
|
515
|
+
if (this.io.integrateDelivery && row.current_delivery_id && row.pause_reason?.startsWith('integration_')) {
|
|
516
|
+
await this.integrateChunk(id);
|
|
517
|
+
return { ok: true, status: 202, chain: (0, milestone_chain_store_1.toChainSnapshot)((0, milestone_chain_store_1.getChain)(this.db, id)) };
|
|
518
|
+
}
|
|
460
519
|
if (row.head_branch && !(await this.branchExistsSafe(row.head_branch))) {
|
|
461
520
|
(0, milestone_chain_store_1.updateChain)(this.db, row.id, row.status, { status: 'paused', pauseReason: 'head_missing' }, this.now());
|
|
462
521
|
const fresh = (0, milestone_chain_store_1.getChain)(this.db, row.id);
|
|
@@ -503,6 +562,13 @@ class MilestoneChainManager {
|
|
|
503
562
|
*/
|
|
504
563
|
async recoverOnStartup() {
|
|
505
564
|
for (const row of (0, milestone_chain_store_1.listActiveChains)(this.db)) {
|
|
565
|
+
if (this.io.integrateDelivery && row.status === 'waiting' && row.pause_reason?.startsWith('integration_')) {
|
|
566
|
+
if (row.current_delivery_id)
|
|
567
|
+
await this.integrateChunk(row.id);
|
|
568
|
+
else if (row.pause_reason === 'integration_complete')
|
|
569
|
+
this.afterChunkSuccess(row.id, row.integration_branch);
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
506
572
|
if (row.status !== 'running')
|
|
507
573
|
continue;
|
|
508
574
|
if (row.current_delivery_id) {
|
|
@@ -475,7 +475,7 @@ function projectDefinitionRuntimeEvidence(status, reviewerStepId) {
|
|
|
475
475
|
if (!['succeeded', 'failed'].includes(scope.status) || !scope.attemptId || !isRecord(scope.output))
|
|
476
476
|
continue;
|
|
477
477
|
const output = scope.output;
|
|
478
|
-
if (scope.kind === 'verify' && typeof output.receiptId === 'string' && Array.isArray(output.commands)) {
|
|
478
|
+
if ((scope.kind === 'verify' || scope.kind === 'implementation-step' && output.phase === 'verify') && typeof output.receiptId === 'string' && Array.isArray(output.commands)) {
|
|
479
479
|
for (const raw of output.commands) {
|
|
480
480
|
if (commands.length >= RUNTIME_LIST_CAP)
|
|
481
481
|
break;
|
|
@@ -487,7 +487,8 @@ function projectDefinitionRuntimeEvidence(status, reviewerStepId) {
|
|
|
487
487
|
}
|
|
488
488
|
}
|
|
489
489
|
const review = scope.status !== 'succeeded' ? null : scope.kind === 'implementation' ? parseRuntimeReview(output.review)
|
|
490
|
-
:
|
|
490
|
+
: scope.kind === 'implementation-step' && output.phase === 'reviewer' ? parseRuntimeReview(output)
|
|
491
|
+
: reviewerStepId === scope.nodePath && scope.kind === 'role-turn' ? parseRuntimeReview(output.structured ?? output) : null;
|
|
491
492
|
if (review)
|
|
492
493
|
scopedReviews.push({ nodePath: scope.nodePath, scopeId: scope.scopeId, attemptId: scope.attemptId, review });
|
|
493
494
|
}
|
|
@@ -231,7 +231,7 @@ async function launchMultiRepositoryRail(input, io = {}) {
|
|
|
231
231
|
integrationBranches.set(repo.id, target.branch);
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
|
-
const previousParentId = input.revision?.ofDeliveryId ?? input.repositoryContinuation?.deliveryId;
|
|
234
|
+
const previousParentId = input.revision?.ofDeliveryId ?? input.repositoryContinuation?.deliveryId ?? input.retryOfDelivery?.deliveryId;
|
|
235
235
|
const previousParent = previousParentId ? (0, rail_pr_store_1.getPrDelivery)(ctx.db, previousParentId) : undefined;
|
|
236
236
|
const previousManifest = (0, multi_repo_execution_store_1.readExecutionManifest)(previousParent?.execution_manifest);
|
|
237
237
|
const previousChildren = previousParentId ? listRepositoryDeliveries(ctx.db, previousParentId) : [];
|
|
@@ -268,12 +268,13 @@ async function launchMultiRepositoryRail(input, io = {}) {
|
|
|
268
268
|
artifactRepositoryId, selectedRepositoryIds: selected.map((repo) => repo.id), repositories: [],
|
|
269
269
|
};
|
|
270
270
|
const generation = (0, rail_pr_store_1.createPrDeliveryGeneration)(ctx.db, {
|
|
271
|
+
launchConfig: input.launchConfig,
|
|
271
272
|
id: parentId, railIndex: input.railIndex, loopId: input.loopId, railKey: `${input.railIndex}-${input.loopId}`,
|
|
272
273
|
ticketIds: input.ticketIds, baseBranch: input.baseBranch ?? '', loopName: input.loopName,
|
|
273
274
|
originSurface: input.originSurface ?? 'dashboard', originConversationId: input.originConversationId,
|
|
274
275
|
specSnapshot: (0, rail_isolated_launch_1.buildSpecSnapshot)(ctx, input.ticketIds),
|
|
275
276
|
...(input.revision ? { revisionNote: input.revision.note, revisionOf: input.revision.ofDeliveryId } : {}),
|
|
276
|
-
}, input.revision ? { id: input.revision.ofDeliveryId, decision: input.revision.decision } : input.repositoryContinuation ? { id: input.repositoryContinuation.deliveryId, decision: input.repositoryContinuation.decision } : null);
|
|
277
|
+
}, input.revision ? { id: input.revision.ofDeliveryId, decision: input.revision.decision } : input.repositoryContinuation ? { id: input.repositoryContinuation.deliveryId, decision: input.repositoryContinuation.decision } : input.retryOfDelivery ? { id: input.retryOfDelivery.deliveryId, decision: input.retryOfDelivery.decision } : null);
|
|
277
278
|
for (const child of previousChildren) {
|
|
278
279
|
if (!['merged', 'completed', 'discarded', 'superseded'].includes(child.decision))
|
|
279
280
|
(0, rail_pr_store_1.transitionDecision)(ctx.db, child.id, child.decision, 'superseded');
|
|
@@ -315,14 +316,14 @@ async function launchMultiRepositoryRail(input, io = {}) {
|
|
|
315
316
|
const childSettlement = deferred();
|
|
316
317
|
const previous = previousChildren.find((row) => row.repository_id === repository.id);
|
|
317
318
|
const previousRepository = previousManifest?.repositories.find((row) => row.repositoryId === repository.id);
|
|
318
|
-
const previousBaseBranch = previous && ['merged', 'completed'].includes(previous.decision)
|
|
319
|
+
const previousBaseBranch = input.retryOfDelivery ? undefined : previous && ['merged', 'completed'].includes(previous.decision)
|
|
319
320
|
? previousRepository?.integrationBranch ?? previous.base_branch
|
|
320
321
|
: previous?.base_branch;
|
|
321
322
|
const oldSnapshot = previous ? (0, rail_pr_store_1.toPrDeliverySnapshot)(previous) : null;
|
|
322
323
|
const revisionBranches = new Map();
|
|
323
|
-
if (oldSnapshot && !['merged', 'completed', 'discarded'].includes(oldSnapshot.decision) && !previous?.pr_url) {
|
|
324
|
+
if (!input.retryOfDelivery && oldSnapshot && !['merged', 'completed', 'discarded'].includes(oldSnapshot.decision) && !previous?.pr_url) {
|
|
324
325
|
for (const unit of oldSnapshot.branches) {
|
|
325
|
-
if (unit.finalSha)
|
|
326
|
+
if (unit.succeeded && unit.finalSha && unit.implementationOutcome !== 'failed' && unit.deliveryOutcome !== 'blocked')
|
|
326
327
|
revisionBranches.set(unit.ticketId, { branch: unit.branch, sha: unit.finalSha });
|
|
327
328
|
}
|
|
328
329
|
}
|
|
@@ -355,6 +356,7 @@ async function launchMultiRepositoryRail(input, io = {}) {
|
|
|
355
356
|
...input, ctx: childCtx, scope: effectiveScope, loopGraph: graph,
|
|
356
357
|
runtimeStateProject: ctx.project,
|
|
357
358
|
revision: input.revision && previous ? { ...input.revision, ofDeliveryId: previous.id, decision: previous.decision } : undefined,
|
|
359
|
+
retryOfDelivery: input.retryOfDelivery && previous ? { deliveryId: previous.id, decision: previous.decision } : undefined,
|
|
358
360
|
requiredPrContinuation: continuation,
|
|
359
361
|
explicitPrTarget: continuation?.prNumber ? { prNumber: continuation.prNumber } : input.explicitPrTarget,
|
|
360
362
|
originConversationId: undefined,
|
|
@@ -389,6 +391,9 @@ async function launchMultiRepositoryRail(input, io = {}) {
|
|
|
389
391
|
if (head.code !== 0 || !/^[a-f0-9]{40,64}$/i.test(head.stdout.trim()))
|
|
390
392
|
throw new Error(`Cannot freeze HEAD for ${repository.name}`);
|
|
391
393
|
manifest.repositories.push({ repositoryId: repository.id, name: repository.name, sourcePath: repository.path,
|
|
394
|
+
...(repository.workspacePath ? { workspacePath: repository.workspacePath } : {}),
|
|
395
|
+
...(repository.workspacePaths ? { workspacePaths: [...repository.workspacePaths] } : {}),
|
|
396
|
+
...((input.workspaceSelection?.[repository.id] ?? previousRepository?.selectedWorkspacePaths) ? { selectedWorkspacePaths: [...(input.workspaceSelection?.[repository.id] ?? previousRepository.selectedWorkspacePaths)] } : {}),
|
|
392
397
|
gitCommonDir: (0, repo_lock_1.repositoryLockKey)(repository.path), baseBranch: child.base_branch, integrationBranch: integrationBranches.get(repository.id) ?? previousRepository?.integrationBranch ?? child.base_branch, baseSha: head.stdout.trim(),
|
|
393
398
|
worktreePath: worktree.worktree_path, branch: worktree.branch, worktreeId: worktree.id });
|
|
394
399
|
}
|