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
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createUsageService = createUsageService;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const domain_1 = require("../domain");
|
|
6
|
+
const application_1 = require("../application");
|
|
7
|
+
const errors_1 = require("../adapters/errors");
|
|
8
|
+
function createUsageService(deps) {
|
|
9
|
+
const now = deps.now ?? Date.now;
|
|
10
|
+
const instanceId = (0, node_crypto_1.randomUUID)();
|
|
11
|
+
const rows = new Map(domain_1.USAGE_PROVIDERS.map(id => [id, (0, domain_1.initialUsage)(id, (0, node_crypto_1.randomUUID)())]));
|
|
12
|
+
const contexts = new Map(), identities = new Map();
|
|
13
|
+
const failures = new Map(), running = new Map();
|
|
14
|
+
const controllers = new Map();
|
|
15
|
+
let revision = 0, disposed = false;
|
|
16
|
+
function snapshot() { return { scope: 'machine', instanceId, revision, providers: domain_1.USAGE_PROVIDERS.map(id => (0, application_1.withFreshness)(rows.get(id), now())) }; }
|
|
17
|
+
function clear(id) {
|
|
18
|
+
const previous = rows.get(id);
|
|
19
|
+
rows.set(id, { ...(0, domain_1.initialUsage)(id, (0, node_crypto_1.randomUUID)()), installed: previous.installed, attemptedAt: previous.attemptedAt, refreshState: previous.refreshState });
|
|
20
|
+
identities.delete(id);
|
|
21
|
+
revision++;
|
|
22
|
+
}
|
|
23
|
+
async function collect(id, signal) {
|
|
24
|
+
const reader = deps.readers[id];
|
|
25
|
+
try {
|
|
26
|
+
const installed = await deps.installed(id);
|
|
27
|
+
if (signal.aborted)
|
|
28
|
+
return;
|
|
29
|
+
rows.set(id, { ...rows.get(id), installed });
|
|
30
|
+
if (!installed) {
|
|
31
|
+
clear(id);
|
|
32
|
+
rows.set(id, { ...rows.get(id), refreshState: 'idle', retryAt: new Date(now() + 30_000).toISOString(), issue: { code: 'cli-missing', retryable: false } });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (deps.eligible && !await deps.eligible(id))
|
|
36
|
+
throw new errors_1.UsageError('unsupported-cli');
|
|
37
|
+
if (signal.aborted)
|
|
38
|
+
return;
|
|
39
|
+
const before = await reader.context(signal);
|
|
40
|
+
if (signal.aborted)
|
|
41
|
+
return;
|
|
42
|
+
if (contexts.get(id) !== before) {
|
|
43
|
+
clear(id);
|
|
44
|
+
contexts.set(id, before);
|
|
45
|
+
}
|
|
46
|
+
const result = await reader.read(signal);
|
|
47
|
+
const after = await reader.context(signal);
|
|
48
|
+
if (signal.aborted)
|
|
49
|
+
return;
|
|
50
|
+
if (before !== after) {
|
|
51
|
+
clear(id);
|
|
52
|
+
contexts.set(id, after);
|
|
53
|
+
throw new errors_1.UsageError('account-changed', true);
|
|
54
|
+
}
|
|
55
|
+
if (result.identity && identities.get(id) && identities.get(id) !== result.identity)
|
|
56
|
+
clear(id);
|
|
57
|
+
if (result.identity)
|
|
58
|
+
identities.set(id, result.identity);
|
|
59
|
+
const available = result.availability === 'available';
|
|
60
|
+
if (!available)
|
|
61
|
+
clear(id);
|
|
62
|
+
rows.set(id, { ...rows.get(id), availability: result.availability, plan: result.plan, source: result.source, windows: available ? result.windows : [], spend: available ? result.spend ?? null : null,
|
|
63
|
+
// Identity is internal: explicitly select fields instead of returning adapter metadata.
|
|
64
|
+
providerId: id, installed: true, refreshState: 'idle', freshness: available ? 'fresh' : 'unknown',
|
|
65
|
+
observedAt: available ? new Date(now()).toISOString() : null, retryAt: new Date(now() + 30_000).toISOString(),
|
|
66
|
+
issue: available ? null : { code: result.availability, retryable: false } });
|
|
67
|
+
failures.delete(id);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (signal.aborted)
|
|
71
|
+
return;
|
|
72
|
+
const issue = error instanceof errors_1.UsageError ? error : new errors_1.UsageError('collection-failed', true);
|
|
73
|
+
const count = (failures.get(id) ?? 0) + 1;
|
|
74
|
+
failures.set(id, count);
|
|
75
|
+
if (!issue.retryable)
|
|
76
|
+
clear(id);
|
|
77
|
+
const row = rows.get(id);
|
|
78
|
+
rows.set(id, { ...row, refreshState: 'error', availability: row.observedAt ? 'available' : (['signed-out', 'unsupported-cli', 'unsupported-platform', 'unsupported-auth'].includes(issue.code) ? issue.code : 'unavailable'),
|
|
79
|
+
issue: { code: issue.code, retryable: issue.retryable }, retryAt: new Date(now() + (issue.retryMs ?? (0, application_1.backoff)(count))).toISOString() });
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
revision++;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function refresh(providerId, automatic = false) {
|
|
86
|
+
let scheduled = false;
|
|
87
|
+
if (!disposed)
|
|
88
|
+
for (const id of providerId ? [providerId] : domain_1.USAGE_PROVIDERS) {
|
|
89
|
+
const row = rows.get(id);
|
|
90
|
+
if (running.has(id)) {
|
|
91
|
+
scheduled = true;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (row.retryAt && Date.parse(row.retryAt) > now())
|
|
95
|
+
continue;
|
|
96
|
+
if (automatic && row.issue && !row.issue.retryable)
|
|
97
|
+
continue;
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
controllers.set(id, controller);
|
|
100
|
+
rows.set(id, { ...row, attemptedAt: new Date(now()).toISOString(), refreshState: 'refreshing' });
|
|
101
|
+
revision++;
|
|
102
|
+
scheduled = true;
|
|
103
|
+
const task = collect(id, controller.signal).finally(() => { running.delete(id); controllers.delete(id); });
|
|
104
|
+
running.set(id, task);
|
|
105
|
+
}
|
|
106
|
+
const view = snapshot();
|
|
107
|
+
return { snapshot: view, scheduled, retryAt: view.providers.filter(p => !providerId || p.providerId === providerId).map(p => p.retryAt).filter((s) => !!s).sort()[0] ?? null };
|
|
108
|
+
}
|
|
109
|
+
async function dispose() { disposed = true; controllers.forEach(c => c.abort()); await Promise.allSettled(running.values()); }
|
|
110
|
+
return { snapshot, refresh, dispose, settled: () => Promise.allSettled(running.values()) };
|
|
111
|
+
}
|
|
@@ -494,6 +494,15 @@ class ProjectRegistry {
|
|
|
494
494
|
delete input.path;
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
|
+
if (input.workspacePath !== undefined || input.workspacePaths !== undefined) {
|
|
498
|
+
const context = this._contexts.get(projectId);
|
|
499
|
+
if (!context)
|
|
500
|
+
throw new project_repositories_1.RepositoryValidationError('Load this project before changing its workspace', 'project_unavailable', 503);
|
|
501
|
+
const references = (0, multi_repo_execution_store_1.getRepositoryExecutionReferences)(context.db, repositoryId);
|
|
502
|
+
const unfinished = context.db.prepare("SELECT id FROM loop_runs WHERE status <> 'completed' LIMIT 1").get();
|
|
503
|
+
if (unfinished || references.runIds.length || references.deliveryIds.length)
|
|
504
|
+
throw new project_repositories_1.RepositoryValidationError('Workspace is referenced by runs or pending deliveries', 'repository_in_use', 409, references);
|
|
505
|
+
}
|
|
497
506
|
if (input.path !== undefined)
|
|
498
507
|
this._assertRepositoryUnreferenced(projectId, repositoryId);
|
|
499
508
|
const repository = (0, desktop_db_1.updateProjectRepository)(this._desktopDb, projectId, repositoryId, input);
|
|
@@ -1108,7 +1117,8 @@ class ProjectRegistry {
|
|
|
1108
1117
|
const loopRunManager = new loop_run_manager_1.LoopRunManager(db, boundBroadcast, (0, loop_executors_1.createLoopExecutors)({
|
|
1109
1118
|
pluginScope: () => ({ stateRoot: (0, workspace_resolution_1.resolveProjectExecution)(project).cwd, legacyProviderId: project.provider }),
|
|
1110
1119
|
// A project registered as a package of a larger checkout scopes Core to that package in isolated worktrees.
|
|
1111
|
-
sourcePath: () => project.path,
|
|
1120
|
+
sourcePath: () => (0, project_repositories_1.resolveProjectRepository)(project).path,
|
|
1121
|
+
workspacePaths: () => { const primary = (0, project_repositories_1.resolveProjectRepository)(project); return primary.workspacePaths ?? (primary.workspacePath ? [primary.workspacePath] : undefined); },
|
|
1112
1122
|
env: () => (0, workspace_resolution_1.resolveLoopBaseEnv)({ slug: project.slug, path: project.path }, undefined, (0, project_env_1.applyWorktreeEnvPassthrough)(db, process.env)),
|
|
1113
1123
|
// Named rail profiles and global per-agent defaults ride the same
|
|
1114
1124
|
// SPECRAILS_PROFILE_PATH snapshot in both AI transports. An explicit null
|
|
@@ -1363,6 +1373,11 @@ class ProjectRegistry {
|
|
|
1363
1373
|
: typeof data.jobId === 'string' ? [data.jobId] : [];
|
|
1364
1374
|
return { ok: true, loopRunIds: ids.filter((v) => typeof v === 'string') };
|
|
1365
1375
|
},
|
|
1376
|
+
integrateDelivery: async (delivery) => {
|
|
1377
|
+
const action = delivery.decision === 'no_changes' ? 'acknowledge-no-changes' : 'merge-local';
|
|
1378
|
+
const r = await internalApi.call('POST', `${railsBase}/pr-decision`, { prDeliveryId: delivery.id, expectedDecision: delivery.decision, action });
|
|
1379
|
+
return r.ok ? { ok: true } : { ok: false, status: r.status, ...(0, internal_api_1.internalApiError)(r) };
|
|
1380
|
+
},
|
|
1366
1381
|
activeDeliveryForRail: (railIndex) => {
|
|
1367
1382
|
const row = (0, rail_pr_store_1.getActivePrDeliveryByRail)(db, railIndex);
|
|
1368
1383
|
return row ? (0, rail_pr_store_1.toPrDeliverySnapshot)(row) : null;
|
|
@@ -15,6 +15,7 @@ exports.inspectRepositoryPath = inspectRepositoryPath;
|
|
|
15
15
|
exports.assertDistinctRepositories = assertDistinctRepositories;
|
|
16
16
|
exports.isRepositoryPathWithin = isRepositoryPathWithin;
|
|
17
17
|
exports.resolveRepositoryProject = resolveRepositoryProject;
|
|
18
|
+
exports.validateWorkspaceSelection = validateWorkspaceSelection;
|
|
18
19
|
const fs_1 = __importDefault(require("fs"));
|
|
19
20
|
const path_1 = __importDefault(require("path"));
|
|
20
21
|
const child_process_1 = require("child_process");
|
|
@@ -117,6 +118,33 @@ function inspectRepositoryPath(input, requireAvailable = true) {
|
|
|
117
118
|
const canonical = canonicalRepositoryPath(input.path);
|
|
118
119
|
if (requireAvailable && !repositoryAvailable(canonical))
|
|
119
120
|
throw new RepositoryValidationError(`Repository directory is unavailable: ${canonical}`, 'repository_unavailable');
|
|
121
|
+
if (input.workspacePath != null && input.workspacePaths != null)
|
|
122
|
+
throw new RepositoryValidationError('Use workspacePaths or workspacePath, not both', 'invalid_workspace_path');
|
|
123
|
+
let workspacePaths;
|
|
124
|
+
if (input.workspacePaths !== undefined && input.workspacePaths !== null) {
|
|
125
|
+
if (!Array.isArray(input.workspacePaths) || !input.workspacePaths.length || input.workspacePaths.some(item => typeof item !== 'string' || !item.trim()))
|
|
126
|
+
throw new RepositoryValidationError('workspacePaths must be a nonempty array of workspace directories');
|
|
127
|
+
workspacePaths = input.workspacePaths.map(item => inspectRepositoryPath({ path: canonical, workspacePath: item }, requireAvailable).workspacePath);
|
|
128
|
+
if (new Set(workspacePaths.map(repositoryPathKey)).size !== workspacePaths.length || workspacePaths.some((root, index) => workspacePaths.some((other, otherIndex) => index !== otherIndex && isRepositoryPathWithin(root, other))))
|
|
129
|
+
throw new RepositoryValidationError('Code workspaces must have distinct non-overlapping directories', 'invalid_workspace_path');
|
|
130
|
+
}
|
|
131
|
+
let workspacePath;
|
|
132
|
+
if (input.workspacePath !== undefined && input.workspacePath !== null) {
|
|
133
|
+
if (typeof input.workspacePath !== 'string' || !input.workspacePath.trim())
|
|
134
|
+
throw new RepositoryValidationError('Workspace path must not be empty');
|
|
135
|
+
workspacePath = canonicalRepositoryPath(path_1.default.resolve(canonical, input.workspacePath));
|
|
136
|
+
if (!isRepositoryPathWithin(canonical, workspacePath))
|
|
137
|
+
throw new RepositoryValidationError('Workspace must be inside its registered repository', 'invalid_workspace_path');
|
|
138
|
+
if (requireAvailable && !repositoryAvailable(workspacePath))
|
|
139
|
+
throw new RepositoryValidationError(`Workspace directory is unavailable: ${workspacePath}`, 'workspace_unavailable');
|
|
140
|
+
// A nested independent Git checkout needs its own membership and delivery.
|
|
141
|
+
if (workspacePath !== canonical) {
|
|
142
|
+
for (let current = workspacePath; current !== canonical; current = path_1.default.dirname(current)) {
|
|
143
|
+
if (fs_1.default.existsSync(path_1.default.join(current, '.git')))
|
|
144
|
+
throw new RepositoryValidationError('A nested Git repository must be registered as a separate workspace', 'invalid_workspace_path');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
120
148
|
let gitIdentity = null;
|
|
121
149
|
if (repositoryAvailable(canonical)) {
|
|
122
150
|
try {
|
|
@@ -125,14 +153,15 @@ function inspectRepositoryPath(input, requireAvailable = true) {
|
|
|
125
153
|
}
|
|
126
154
|
catch { /* Non-Git context folders are supported. */ }
|
|
127
155
|
}
|
|
128
|
-
return { ...input, path: canonical, name: input.name?.trim(), integrationBranch: input.integrationBranch?.trim() || null, canonicalKey: repositoryPathKey(canonical), gitIdentity, kind: gitIdentity ? 'git' : 'folder' };
|
|
156
|
+
return { ...input, workspacePath, workspacePaths, path: canonical, name: input.name?.trim(), integrationBranch: input.integrationBranch?.trim() || null, canonicalKey: repositoryPathKey(canonical), gitIdentity, kind: gitIdentity ? 'git' : 'folder' };
|
|
129
157
|
}
|
|
130
158
|
function assertDistinctRepositories(repositories) {
|
|
131
159
|
for (let i = 0; i < repositories.length; i++) {
|
|
132
160
|
for (let j = 0; j < i; j++) {
|
|
133
161
|
const a = repositories[i], b = repositories[j];
|
|
134
162
|
const overlapping = isRepositoryPathWithin(a.canonicalKey, b.canonicalKey) || isRepositoryPathWithin(b.canonicalKey, a.canonicalKey);
|
|
135
|
-
|
|
163
|
+
const container = (a.kind === 'folder' && b.kind === 'git' && isRepositoryPathWithin(a.canonicalKey, b.canonicalKey)) || (b.kind === 'folder' && a.kind === 'git' && isRepositoryPathWithin(b.canonicalKey, a.canonicalKey));
|
|
164
|
+
if ((overlapping && !container) || (a.gitIdentity !== null && a.gitIdentity === b.gitIdentity)) {
|
|
136
165
|
throw new RepositoryValidationError('Repositories in one project must have distinct, non-overlapping roots and Git identities', 'duplicate_repository', 409);
|
|
137
166
|
}
|
|
138
167
|
}
|
|
@@ -155,3 +184,23 @@ function resolveRepositoryProject(projects, inputPath, projectId) {
|
|
|
155
184
|
}
|
|
156
185
|
return selected.sort((a, b) => b.path.length - a.path.length)[0];
|
|
157
186
|
}
|
|
187
|
+
/** A launch may narrow registered code workspaces, never invent new targets. */
|
|
188
|
+
function validateWorkspaceSelection(project, value, repositoryIds) {
|
|
189
|
+
if (value === undefined)
|
|
190
|
+
return undefined;
|
|
191
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) || !Object.keys(value).length)
|
|
192
|
+
throw new RepositoryValidationError('workspaceSelection must map repository IDs to nonempty workspace path arrays', 'invalid_workspace_selection');
|
|
193
|
+
const entries = Object.entries(value).map(([id, paths]) => {
|
|
194
|
+
if (!repositoryIds.includes(id))
|
|
195
|
+
throw new RepositoryValidationError('Workspace selection refers to an unselected repository', 'invalid_workspace_selection');
|
|
196
|
+
const repository = resolveProjectRepository(project, id);
|
|
197
|
+
if (!Array.isArray(paths) || !paths.length || paths.some(item => typeof item !== 'string' || !item.trim()))
|
|
198
|
+
throw new RepositoryValidationError('Select at least one code workspace per repository', 'invalid_workspace_selection');
|
|
199
|
+
const allowed = repository.workspacePaths ?? (repository.workspacePath ? [repository.workspacePath] : [repository.path]);
|
|
200
|
+
const selected = paths.map(item => canonicalRepositoryPath(path_1.default.resolve(repository.path, item)));
|
|
201
|
+
if (new Set(selected.map(repositoryPathKey)).size !== selected.length || selected.some(item => !allowed.some(root => repositoryPathKey(root) === repositoryPathKey(item))))
|
|
202
|
+
throw new RepositoryValidationError('Select only registered code workspace paths', 'invalid_workspace_selection');
|
|
203
|
+
return [id, selected];
|
|
204
|
+
});
|
|
205
|
+
return Object.fromEntries(entries);
|
|
206
|
+
}
|
|
@@ -347,7 +347,7 @@ function formatDescriptionWithCriteria(body, criteria) {
|
|
|
347
347
|
* Order:
|
|
348
348
|
* 1. `models.defaults.model` from the install-config.yaml (per-project HOME
|
|
349
349
|
* dir), if it parses AND is in the provider allow-list.
|
|
350
|
-
* 2. Provider default from `PROVIDER_DEFAULT_MODEL` (`sonnet` / `gpt-
|
|
350
|
+
* 2. Provider default from `PROVIDER_DEFAULT_MODEL` (`sonnet` / `gpt-6.1-sol`).
|
|
351
351
|
*
|
|
352
352
|
* Logs a warning when the configured value exists but is not valid for the
|
|
353
353
|
* project's provider.
|
|
@@ -352,9 +352,11 @@ function registerLoopRunRoutes(deps) {
|
|
|
352
352
|
effort = globalAgentDefaults.pipelineEffort;
|
|
353
353
|
}
|
|
354
354
|
let repositoryIds;
|
|
355
|
+
let workspaceSelection;
|
|
355
356
|
const primary = (0, project_repositories_1.getProjectRepositories)(c.project).find((repository) => repository.isPrimary);
|
|
356
357
|
try {
|
|
357
358
|
repositoryIds = (0, project_repositories_1.validateTicketRepositoryIds)(c.project, body.repositoryIds) ?? [primary.id];
|
|
359
|
+
workspaceSelection = (0, project_repositories_1.validateWorkspaceSelection)(c.project, body.workspaceSelection, repositoryIds);
|
|
358
360
|
(0, loop_graph_1.assertLoopShellRepositoryScope)(loop.graph, repositoryIds);
|
|
359
361
|
(0, process_admission_1.assertProcessAdmission)(c.project.id);
|
|
360
362
|
}
|
|
@@ -386,7 +388,7 @@ function registerLoopRunRoutes(deps) {
|
|
|
386
388
|
try {
|
|
387
389
|
let prDeliveryId;
|
|
388
390
|
const ids = await (0, multi_repo_execution_1.launchMultiRepositoryRail)({
|
|
389
|
-
ctx: c, railIndex: rail.railIndex, ticketIds: [], repositoryIds, scope: 'all',
|
|
391
|
+
ctx: c, railIndex: rail.railIndex, ticketIds: [], repositoryIds, workspaceSelection, scope: 'all',
|
|
390
392
|
loopId, loopName: loop.name, loopGraph: loop.graph, provider, model, effort,
|
|
391
393
|
onPrDeliveryCreated: (id) => { prDeliveryId = id; },
|
|
392
394
|
});
|
|
@@ -418,6 +420,7 @@ function registerLoopRunRoutes(deps) {
|
|
|
418
420
|
graph: loop.graph,
|
|
419
421
|
projectId: c.project.id,
|
|
420
422
|
repositoryId: primary.id,
|
|
423
|
+
workspacePaths: workspaceSelection?.[primary.id],
|
|
421
424
|
cwd: exec.cwd,
|
|
422
425
|
repoDir: exec.relocated ? exec.repoDir : undefined,
|
|
423
426
|
railIndex: null,
|
|
@@ -19,8 +19,8 @@ const path_1 = __importDefault(require("path"));
|
|
|
19
19
|
const openspec_runtime_plugin_1 = require("../openspec-runtime-plugin");
|
|
20
20
|
const WHICH_CMD = process.platform === 'win32' ? 'where' : 'which';
|
|
21
21
|
const CLAUDE_MODELS = [
|
|
22
|
-
{ value: 'sonnet', label: '
|
|
23
|
-
{ value: 'fable', label: '
|
|
22
|
+
{ value: 'sonnet', label: 'Sonnet 5.5', default: true },
|
|
23
|
+
{ value: 'fable', label: 'Fable 5.1' },
|
|
24
24
|
{ value: 'opus', label: 'Claude Opus 5.5' },
|
|
25
25
|
{ value: 'haiku', label: 'Claude Haiku' },
|
|
26
26
|
];
|
|
@@ -28,6 +28,7 @@ const CLAUDE_MODELS = [
|
|
|
28
28
|
* CLI accepts collapse to the short alias. */
|
|
29
29
|
function normaliseModel(model) {
|
|
30
30
|
switch (model) {
|
|
31
|
+
case 'claude-sonnet-5-5':
|
|
31
32
|
case 'claude-sonnet-5':
|
|
32
33
|
case 'claude-sonnet-4-6':
|
|
33
34
|
case 'claude-sonnet-4-5':
|
|
@@ -54,14 +55,15 @@ function normaliseModel(model) {
|
|
|
54
55
|
/**
|
|
55
56
|
* Catalog aliases whose GENERATION Specrails pins explicitly.
|
|
56
57
|
*
|
|
57
|
-
* The catalog
|
|
58
|
+
* The catalog aliases (`sonnet`, `opus`) stay the stored and validated identities
|
|
58
59
|
* — profiles, project settings, conversation rows and analytics all keep using
|
|
59
60
|
* it, and `normaliseModel` collapses the pinned id back to it. Only the spawn
|
|
60
61
|
* argument is expanded, so picking "Claude Opus" is a product decision about
|
|
61
62
|
* WHICH Opus runs instead of delegating that to whatever generation the CLI's
|
|
62
|
-
* bare
|
|
63
|
+
* bare model alias currently points at.
|
|
63
64
|
*/
|
|
64
65
|
const PINNED_ALIAS_MODEL_IDS = {
|
|
66
|
+
sonnet: 'claude-sonnet-5-5',
|
|
65
67
|
opus: 'claude-opus-5-5',
|
|
66
68
|
};
|
|
67
69
|
/** Catalog value (or concrete id) in, spawn model id out. */
|
|
@@ -39,19 +39,18 @@ exports._CODEX_MIN_VERSION = CODEX_MIN_VERSION;
|
|
|
39
39
|
const CODEX_MODELS = [
|
|
40
40
|
// Newest first. gpt-6-astra has no rate card in `server/modules/accounting/runtime/pricing.ts` yet, so
|
|
41
41
|
// its turns show cost as unavailable (honest-metrics: never fabricated).
|
|
42
|
+
{ value: 'gpt-6.1-sol', label: 'GPT-6.1 Sol', default: true },
|
|
42
43
|
{ value: 'gpt-6-astra', label: 'GPT-6 Astra' },
|
|
43
44
|
{ value: 'gpt-5.6-sol', label: 'GPT-5.6 Sol' },
|
|
44
45
|
{ value: 'gpt-5.6-terra', label: 'GPT-5.6 Terra' },
|
|
45
46
|
{ value: 'gpt-5.6-luna', label: 'GPT-5.6 Luna' },
|
|
46
|
-
{ value: 'gpt-5.5', label: 'GPT-5.5', default: true },
|
|
47
|
-
{ value: 'gpt-5.4', label: 'GPT-5.4' },
|
|
48
|
-
{ value: 'gpt-5.4-mini', label: 'GPT-5.4 Mini' },
|
|
49
|
-
{ value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex' },
|
|
50
47
|
];
|
|
51
48
|
// Model-specific CLI capabilities (models/list, reviewed 2026-09-05).
|
|
52
49
|
// Keep the provider-wide union for legacy models without current metadata.
|
|
53
50
|
const BASE_EFFORTS = ['low', 'medium', 'high', 'xhigh'];
|
|
54
51
|
const CODEX_MODEL_EFFORTS = {
|
|
52
|
+
// Codex models/list advertises these six efforts for Sol 6.1 (2026-09-30).
|
|
53
|
+
'gpt-6.1-sol': [...BASE_EFFORTS, 'max', 'ultra'],
|
|
55
54
|
'gpt-6-astra': [...BASE_EFFORTS, 'max', 'ultra'],
|
|
56
55
|
'gpt-5.6-sol': [...BASE_EFFORTS, 'max', 'ultra'],
|
|
57
56
|
'gpt-5.6-terra': [...BASE_EFFORTS, 'max', 'ultra'],
|
|
@@ -381,7 +380,7 @@ exports.codexAdapter = {
|
|
|
381
380
|
modelCatalog: () => CODEX_MODELS,
|
|
382
381
|
reasoningEffortsForModel: (model) => CODEX_MODEL_EFFORTS[model]
|
|
383
382
|
?? ['minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'],
|
|
384
|
-
defaultModel: () => 'gpt-
|
|
383
|
+
defaultModel: () => 'gpt-6.1-sol',
|
|
385
384
|
buildArgs: buildCodexArgs,
|
|
386
385
|
parseStreamLine: parseCodexStreamLine,
|
|
387
386
|
extractResult: extractCodexResult,
|
|
@@ -210,7 +210,22 @@ async function createWorktree(git, input) {
|
|
|
210
210
|
// it out into a worktree (resume from the committed partial work).
|
|
211
211
|
// 3. neither → create a fresh branch off base.
|
|
212
212
|
const existing = await listWorktrees(git, input.repoDir);
|
|
213
|
-
|
|
213
|
+
let mounted = existing.find((p) => canonicalWorktreePath(p) === canonicalWorktreePath(wt));
|
|
214
|
+
if (input.reuseBranchWorktree) {
|
|
215
|
+
// New allocations have run-specific paths. A continuation must find the
|
|
216
|
+
// exact recorded branch, never borrow a ticket-keyed mount on another ref.
|
|
217
|
+
mounted = undefined;
|
|
218
|
+
for (const candidate of existing) {
|
|
219
|
+
const head = await git.run(['rev-parse', '--abbrev-ref', 'HEAD'], candidate);
|
|
220
|
+
if (head.code === 0 && head.stdout.trim() === branch) {
|
|
221
|
+
mounted = candidate;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (mounted) {
|
|
227
|
+
if (input.fresh)
|
|
228
|
+
throw new Error(`Fresh launch cannot reuse existing worktree ${mounted}`);
|
|
214
229
|
// The still-mounted worktree may be checked out on a DIFFERENT branch than
|
|
215
230
|
// the caller's preferred name (the path is keyed by ticketId only, so a
|
|
216
231
|
// stale mount from a prior run of the same ticket collides here). The
|
|
@@ -218,16 +233,18 @@ async function createWorktree(git, input) {
|
|
|
218
233
|
// — reporting the caller's preferred name recorded a branch that never
|
|
219
234
|
// existed, so the later `git push` had no ref and the PR delivery wedged
|
|
220
235
|
// at local-only. Detached HEAD / a git failure falls back to the input.
|
|
221
|
-
const head = await git.run(['rev-parse', '--abbrev-ref', 'HEAD'],
|
|
236
|
+
const head = await git.run(['rev-parse', '--abbrev-ref', 'HEAD'], mounted);
|
|
222
237
|
const actual = head.code === 0 ? head.stdout.trim() : '';
|
|
223
238
|
const actualBranch = actual && actual !== 'HEAD' ? actual : branch;
|
|
224
239
|
if (input.refreshFromBaseRef && actualBranch === branch) {
|
|
225
|
-
await fastForwardExistingBranch(git, input.repoDir, branch, input.baseRef,
|
|
240
|
+
await fastForwardExistingBranch(git, input.repoDir, branch, input.baseRef, mounted);
|
|
226
241
|
}
|
|
227
|
-
await ensurePrNeverStageExcludes(git,
|
|
228
|
-
return { branch: actualBranch, worktreePath:
|
|
242
|
+
await ensurePrNeverStageExcludes(git, mounted);
|
|
243
|
+
return { branch: actualBranch, worktreePath: mounted, worktreeCreated: false, branchCreated: false };
|
|
229
244
|
}
|
|
230
245
|
const hasBranch = (await git.run(['rev-parse', '--verify', '--quiet', `refs/heads/${branch}`], input.repoDir)).code === 0;
|
|
246
|
+
if (hasBranch && input.fresh)
|
|
247
|
+
throw new Error(`Fresh launch cannot reuse existing branch ${branch}`);
|
|
231
248
|
if (hasBranch && input.refreshFromBaseRef) {
|
|
232
249
|
await fastForwardExistingBranch(git, input.repoDir, branch, input.baseRef);
|
|
233
250
|
}
|
|
@@ -322,8 +339,94 @@ async function auditStagedPaths(git, worktreePath, excludePaths, phase) {
|
|
|
322
339
|
const parsed = parseNulTerminatedPaths(result, phase);
|
|
323
340
|
if (parsed.error)
|
|
324
341
|
return { forbidden: [], error: parsed.error };
|
|
342
|
+
try {
|
|
343
|
+
const deliverable = parsed.paths.filter(candidate => !forbiddenStagedPaths([candidate], excludePaths).length);
|
|
344
|
+
const external = deliverable.filter(candidate => {
|
|
345
|
+
const target = path.join(worktreePath, candidate);
|
|
346
|
+
let stat;
|
|
347
|
+
try {
|
|
348
|
+
stat = fs.lstatSync(target);
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
if (err.code === 'ENOENT')
|
|
352
|
+
return false; // staged deletion
|
|
353
|
+
throw err;
|
|
354
|
+
}
|
|
355
|
+
if (!stat.isSymbolicLink())
|
|
356
|
+
return false;
|
|
357
|
+
const link = fs.readlinkSync(target);
|
|
358
|
+
const relative = path.relative(worktreePath, link);
|
|
359
|
+
return path.isAbsolute(link) && (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative));
|
|
360
|
+
});
|
|
361
|
+
if (external.length)
|
|
362
|
+
return { forbidden: [], error: `External absolute symlinks cannot be delivered: ${describeForbiddenPaths(external)}. Working files were preserved.` };
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
return { forbidden: [], error: `Could not inspect staged symlinks: ${err instanceof Error ? err.message : String(err)}` };
|
|
366
|
+
}
|
|
325
367
|
return { forbidden: forbiddenStagedPaths(parsed.paths, excludePaths) };
|
|
326
368
|
}
|
|
369
|
+
/** Automated delivery must not publish an unfinished change introduced by this
|
|
370
|
+
* checkout. Baseline active changes and archived changes remain legitimate. */
|
|
371
|
+
async function deliveryHygieneError(git, worktreePath, baseRef) {
|
|
372
|
+
// Agents may create their own commits before settlement. Index-only checks
|
|
373
|
+
// cannot catch an overlay link already in HEAD, even when it is now excluded.
|
|
374
|
+
const changed = parseNulTerminatedPaths(await gitRun(git, ['diff', '--name-only', '--no-renames', '-z', baseRef, 'HEAD', '--'], worktreePath), 'Committed delivery audit');
|
|
375
|
+
if (changed.error)
|
|
376
|
+
return changed.error;
|
|
377
|
+
if (changed.paths.length) {
|
|
378
|
+
const tree = parseNulTerminatedPaths(await gitRun(git, ['ls-tree', '-r', '-z', 'HEAD'], worktreePath), 'Committed symlink audit');
|
|
379
|
+
if (tree.error)
|
|
380
|
+
return tree.error;
|
|
381
|
+
const paths = new Set(changed.paths);
|
|
382
|
+
for (const entry of tree.paths) {
|
|
383
|
+
const tab = entry.indexOf('\t'), metadata = entry.slice(0, tab).split(' '), rel = entry.slice(tab + 1);
|
|
384
|
+
if (metadata[0] !== '120000' || !paths.has(rel))
|
|
385
|
+
continue;
|
|
386
|
+
if (tab < 0 || metadata[1] !== 'blob' || !/^[a-f0-9]{40,64}$/i.test(metadata[2]))
|
|
387
|
+
return 'Committed symlink audit returned malformed tree evidence';
|
|
388
|
+
const blob = await gitRun(git, ['cat-file', 'blob', metadata[2]], worktreePath);
|
|
389
|
+
if (blob.code !== 0)
|
|
390
|
+
return `Could not inspect committed symlink ${JSON.stringify(rel)}`;
|
|
391
|
+
const relative = path.relative(worktreePath, blob.stdout);
|
|
392
|
+
if (path.isAbsolute(blob.stdout) && (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) {
|
|
393
|
+
return `External absolute symlink already committed on the delivery branch: ${JSON.stringify(rel)}. Review and remove it before delivery; working files were preserved.`;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
const baseline = await gitRun(git, ['ls-tree', '-d', '--name-only', '-z', `${baseRef}:openspec/changes`], worktreePath);
|
|
398
|
+
// A missing subtree is normal, but an invalid baseline is never a pass.
|
|
399
|
+
if (baseline.code !== 0) {
|
|
400
|
+
const exists = await gitRun(git, ['rev-parse', '--verify', `${baseRef}^{commit}`], worktreePath);
|
|
401
|
+
if (exists.code !== 0)
|
|
402
|
+
return `Could not inspect OpenSpec delivery baseline: ${gitFailure(exists, baseRef)}`;
|
|
403
|
+
const root = await gitRun(git, ['ls-tree', '-r', '--name-only', '-z', baseRef, '--', 'openspec/changes'], worktreePath);
|
|
404
|
+
if (root.code !== 0 || root.stdout)
|
|
405
|
+
return `Could not inspect OpenSpec delivery baseline: ${gitFailure(baseline, baseRef)}`;
|
|
406
|
+
}
|
|
407
|
+
const parsed = baseline.code === 0 ? parseNulTerminatedPaths(baseline, 'OpenSpec baseline audit') : { paths: [] };
|
|
408
|
+
if (parsed.error)
|
|
409
|
+
return parsed.error;
|
|
410
|
+
const known = new Set(parsed.paths);
|
|
411
|
+
try {
|
|
412
|
+
const directory = path.join(worktreePath, 'openspec', 'changes');
|
|
413
|
+
let entries;
|
|
414
|
+
try {
|
|
415
|
+
entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
416
|
+
}
|
|
417
|
+
catch (err) {
|
|
418
|
+
if (err.code === 'ENOENT')
|
|
419
|
+
return undefined;
|
|
420
|
+
throw err;
|
|
421
|
+
}
|
|
422
|
+
const active = entries.filter(entry => entry.name !== 'archive' && (entry.isDirectory() || entry.isSymbolicLink()) && !known.has(entry.name)).map(entry => `openspec/changes/${entry.name}`);
|
|
423
|
+
if (active.length)
|
|
424
|
+
return `OpenSpec delivery blocked by new active changes: ${describeForbiddenPaths(active)}. Archive the intended change and review unrelated work before delivery; files were preserved.`;
|
|
425
|
+
}
|
|
426
|
+
catch (err) {
|
|
427
|
+
return `Could not inspect active OpenSpec changes: ${err instanceof Error ? err.message : String(err)}`;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
327
430
|
function forbiddenResetPathspecs(excludePaths) {
|
|
328
431
|
return [
|
|
329
432
|
'--',
|
|
@@ -341,7 +444,12 @@ function describeForbiddenPaths(paths) {
|
|
|
341
444
|
* agent paths may stay untracked in the worktree because they must never land on
|
|
342
445
|
* the ticket branch or PR.
|
|
343
446
|
*/
|
|
344
|
-
async function commitWorktreeAndVerify(git, worktreePath, message, excludePaths = []) {
|
|
447
|
+
async function commitWorktreeAndVerify(git, worktreePath, message, excludePaths = [], baseRef) {
|
|
448
|
+
if (baseRef) {
|
|
449
|
+
const error = await deliveryHygieneError(git, worktreePath, baseRef);
|
|
450
|
+
if (error)
|
|
451
|
+
return { staged: false, committed: false, clean: false, dirty: [], error };
|
|
452
|
+
}
|
|
345
453
|
const pathspecs = commitPathspecs(excludePaths);
|
|
346
454
|
// The add is deliberately PLAIN — no exclude pathspecs. `git add` exits 1
|
|
347
455
|
// with "The following paths are ignored by one of your .gitignore files"
|
|
@@ -137,11 +137,11 @@ function overlayRootsOf(input) {
|
|
|
137
137
|
* manifest entry may authenticate against. Empty for unauthorised rels. */
|
|
138
138
|
function sourceCandidatesForOverlayEntry(input, rel) {
|
|
139
139
|
const roots = overlayRootsOf(input);
|
|
140
|
-
if (rel === '.mcp.json' ||
|
|
140
|
+
if (rel === '.mcp.json' || [input.instructionsFilename, 'CLAUDE.md', 'AGENTS.md', 'GEMINI.md'].includes(rel)) {
|
|
141
141
|
return roots.map((root) => path_1.default.join(root, rel));
|
|
142
142
|
}
|
|
143
|
-
const providerPrefix =
|
|
144
|
-
if (!
|
|
143
|
+
const providerPrefix = [input.providerDir, '.claude', '.codex', '.gemini', '.kimi-code'].map(dir => `${dir}/`).find(prefix => rel.startsWith(prefix));
|
|
144
|
+
if (!providerPrefix)
|
|
145
145
|
return [];
|
|
146
146
|
const providerRel = rel.slice(providerPrefix.length);
|
|
147
147
|
if (!providerRel || providerRel === 'worktrees' || providerRel.startsWith('worktrees/'))
|
|
@@ -247,7 +247,7 @@ function captureOverlayCleanupEvidence(input, candidates, includeManifest = fals
|
|
|
247
247
|
if (dereferencedDigest(source) === destinationDigest)
|
|
248
248
|
return true;
|
|
249
249
|
// A bootstrap refresh is still an exact, reproducible source copy.
|
|
250
|
-
if (
|
|
250
|
+
if (![input.instructionsFilename, 'CLAUDE.md', 'AGENTS.md', 'GEMINI.md', '.kimi-code/AGENTS.md'].includes(rel) || !destinationStat.isFile())
|
|
251
251
|
return false;
|
|
252
252
|
try {
|
|
253
253
|
return fs_1.default.readFileSync(destination, 'utf8') === refreshLegacyInstructions(fs_1.default.readFileSync(source, 'utf8'));
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{d as r,f as i,m as a,u as o}from"./TicketDetailModalContext-B-DySpKL.js";import{n as s}from"./createLucideIcon-Bjbbp_KS.js";import{s as c}from"./useDesktop-0unHDBJJ.js";import{F as l,G as u,Yt as d,at as f,nt as p,qt as m,x as h}from"./index-C4Mv6tV6.js";var g=e(t(),1),_=n();function v({projectId:e,conversationId:t}){let{t:n}=s(`agent`),{error:v}=d(),y=f(t??`__new-mission__`),{closeBrowser:b,queueCapture:x,browserOwnerId:S,browserUrl:C,setBrowserUrl:w}=u(),{materializeDraftConversation:T}=l(),[E,D]=(0,g.useState)(!1),[O,k]=(0,g.useState)(!1),[A,j]=(0,g.useState)(`probing`);(0,g.useEffect)(()=>{if(t&&(E||O||A===`screencast`))return p(t)},[t,E,O,A]);let M=(0,g.useMemo)(()=>{if(C)return C;try{return i(localStorage.getItem(`specrails-desktop:agent-browser-url:${e}`)??``)??`about:blank`}catch{return`about:blank`}},[e]);(0,g.useEffect)(()=>{let e=!0;return r().then(t=>{e&&j(t?`native`:`screencast`)}),()=>{e=!1}},[]);let N=(0,g.useMemo)(()=>`agent-${t??`home`}-${Math.round(performance.now())}`,[t]),P=async e=>{k(!0);try{let r=await m(t??(await T()).id,a(e.screenshotDataUrl,`capture-${Date.now()}.png`));x(r),c.success(n(`workspace.browserCaptured`)),b()}catch(e){throw c.error(n(`workspace.uploadFailed`),{description:e instanceof Error?e.message:void 0}),e}finally{k(!1)}};return A===`probing`?null:A===`native`?(0,_.jsx)(o,{ownerId:S??void 0,leaseRevision:y,onBusyChange:D,transferError:v,url:M,onClose:b,onFallback:()=>j(`screencast`),onUrlChange:t=>{if(w(t),i(t)&&t!==`about:blank`)try{localStorage.setItem(`specrails-desktop:agent-browser-url:${e}`,t)}catch{}},confirmLabel:n(`workspace.browserConfirm`),selectLabel:n(`workspace.browserSelectStart`),onCaptured:P}):(0,_.jsx)(h,{open:!0,onClose:b,projectId:e,pendingSpecId:N,confirmLabel:n(`workspace.browserConfirm`),selectLabel:n(`workspace.browserSelectStart`),onCaptured:P})}export{v as AgentBrowserCapture};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AnalyticsPage-069npRVo.js","assets/rolldown-runtime-CNC7AqOf.js","assets/jsx-runtime-zu2_FqZY.js","assets/chunk-KS7C4IRE-DEKu087k.js","assets/preload-helper-Czpn1I53.js","assets/useSharedWebSocket-BZMrX4jr.js","assets/activity-DiyjsgQV.js","assets/addspec-BOvgmcgk.js","assets/agent-aiVhqFW1.js","assets/agentRuntime-BeUb3g9g.js","assets/agents-CTwbx-fb.js","assets/agentstudio-BWAKeGgB.js","assets/aiedit-iIjz2_Qk.js","assets/analytics-BWynXPEm.js","assets/attachments-B53PG733.js","assets/browser-CG0PE1j_.js","assets/builder-CzW5ovyI.js","assets/chat-BGD7MXAy.js","assets/code-DaZ-ZwCT.js","assets/commands-BAWSYHjQ.js","assets/common-DmsclwjP.js","assets/dashboard-XGdQ5mjw.js","assets/explore-DgBACn39.js","assets/integrations-mB-7zoyT.js","assets/jira-CKJg3HZd.js","assets/jobs-KG4Sn12X.js","assets/loops-B4_D-nbg.js","assets/mcp-CUAN6ORK.js","assets/narration-n3hOA7LY.js","assets/nav-DhPb-Isc.js","assets/packet-B0H15elv.js","assets/settings-tfLhQZRN.js","assets/setup-CRKLp_ke.js","assets/specs-DfIdoU5L.js","assets/terminal-BAzpHtpY.js","assets/tickets-D41ZMQpf.js","assets/createLucideIcon-Bjbbp_KS.js","assets/Trans-D3AfDylf.js","assets/useDesktop-0unHDBJJ.js","assets/react-dom-DiWzBDP9.js","assets/provider-capabilities-Vi1ZGvAK.js","assets/spending-HBSk-6jv.js","assets/clsx-CjueKrWZ.js","assets/formatDistanceToNow-aBss1Nai.js","assets/getTimezoneOffsetInMilliseconds-DOGj1Mfz.js","assets/index-C4Mv6tV6.js","assets/TicketDetailModalContext-B-DySpKL.js","assets/save-B6wGWwBR.js","assets/MinimizedChatsContext-CNx_0bZu.js","assets/sparkles-DrY8hb0X.js","assets/x-CBMI9ejn.js","assets/zap-CUOlvtT1.js","assets/circle-x-CMYsN4ZH.js","assets/download-CFHyyHcw.js","assets/file-text-CFT-xXKN.js","assets/git-branch-BRM0F5GN.js","assets/layers-eDMjG41I.js","assets/loader-circle-DcygOQpC.js","assets/pencil-C9RkrIPZ.js","assets/square-Ci-PFcFe.js","assets/plus-CsnjfkmX.js","assets/rotate-ccw-Wh4id13q.js","assets/search-Cq_gE3Ik.js","assets/trash-2-BOU3WdZZ.js","assets/triangle-alert-H9T4jAmh.js","assets/wrench-BfmNO9Vw.js","assets/dialog-xXB2q5HJ.js","assets/utils-BC4DHlz2.js","assets/lib-CGdyxIWg.js","assets/button-Ccc9Dc-D.js","assets/jira-api-BYbEPlkr.js","assets/RepositoryScopeSelector-C2mvWBQ6.js","assets/project-repositories-CSnfzUpg.js","assets/core-B3mKBIh5.js","assets/RepositoryDeliveries-BiwJuS8r.js","assets/useRuntimeRuns-BN1rhyEm.js","assets/event-Bt7f3wXe.js","assets/index-BS7KCWkV.css","assets/ExportDropdown-BcMpvV89.js","assets/BarChart-nBOMNfiy.js","assets/value-s-gzBeyF.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{t as r}from"./preload-helper-Czpn1I53.js";import{n as i}from"./createLucideIcon-Bjbbp_KS.js";import{t as a}from"./loader-circle-DcygOQpC.js";import{t as o}from"./x-CBMI9ejn.js";import{t as s}from"./utils-BC4DHlz2.js";import{Ct as c,G as l,St as u}from"./index-C4Mv6tV6.js";var d=e(t(),1),f=n(),p=(0,d.lazy)(()=>r(()=>import(`./AnalyticsPage-069npRVo.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80]))),m=420,h=560;function g(){let{t:e}=i(`agent`),{closeAnalyticsPane:t}=l(),[n,r]=(0,d.useState)(h),[g,_]=(0,d.useState)(!1),v=(0,d.useCallback)(e=>{let t=e.clientX,i=n,a=window.innerWidth-m;try{e.currentTarget.setPointerCapture(e.pointerId)}catch{}let o=e=>{let n=Math.min(Math.max(i+(t-e.clientX),m),a);r(n)},s=()=>{window.removeEventListener(`pointermove`,o),window.removeEventListener(`pointerup`,s),window.removeEventListener(`pointercancel`,s)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s),window.addEventListener(`pointercancel`,s)},[n]);return(0,f.jsxs)(`div`,{className:s(`flex h-full flex-col overflow-hidden border-l border-border bg-background`,g&&`absolute inset-0 z-30 border-l-0`),style:g?void 0:{width:n,flexShrink:0},"data-testid":`agent-analytics-pane`,children:[(0,f.jsx)(`div`,{className:`relative flex items-center`,children:!g&&(0,f.jsx)(`div`,{role:`separator`,"aria-orientation":`vertical`,onPointerDown:v,className:`absolute left-0 top-0 h-full w-1.5 -translate-x-full cursor-col-resize select-none touch-none hover:bg-accent-primary/20`,title:e(`workspace.resizeAnalytics`)})}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border/60 bg-surface/40 px-3 py-1.5`,children:[(0,f.jsx)(`span`,{className:`text-xs font-medium text-foreground/70`,children:e(`workspace.analytics`)}),(0,f.jsxs)(`div`,{className:`ml-auto flex items-center gap-1`,children:[(0,f.jsx)(`button`,{type:`button`,onClick:()=>_(e=>!e),"aria-label":e(g?`restore`:`maximize`),title:e(g?`restore`:`maximize`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:g?(0,f.jsx)(u,{className:`h-4 w-4`}):(0,f.jsx)(c,{className:`h-4 w-4`})}),(0,f.jsx)(`button`,{type:`button`,onClick:t,"aria-label":e(`workspace.closeAnalytics`),title:e(`workspace.closeAnalytics`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:(0,f.jsx)(o,{className:`h-4 w-4`})})]})]}),(0,f.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:(0,f.jsx)(d.Suspense,{fallback:(0,f.jsx)(`div`,{className:`flex h-24 items-center justify-center text-muted-foreground`,children:(0,f.jsx)(a,{className:`h-4 w-4 animate-spin`})}),children:(0,f.jsx)(p,{})})})]})}export{g as AgentModeAnalyticsPane};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CodePage-Alitorrv.js","assets/rolldown-runtime-CNC7AqOf.js","assets/jsx-runtime-zu2_FqZY.js","assets/react-dom-DiWzBDP9.js","assets/preload-helper-Czpn1I53.js","assets/chunk-KS7C4IRE-DEKu087k.js","assets/TicketDetailModalContext-B-DySpKL.js","assets/useSharedWebSocket-BZMrX4jr.js","assets/activity-DiyjsgQV.js","assets/addspec-BOvgmcgk.js","assets/agent-aiVhqFW1.js","assets/agentRuntime-BeUb3g9g.js","assets/agents-CTwbx-fb.js","assets/agentstudio-BWAKeGgB.js","assets/aiedit-iIjz2_Qk.js","assets/analytics-BWynXPEm.js","assets/attachments-B53PG733.js","assets/browser-CG0PE1j_.js","assets/builder-CzW5ovyI.js","assets/chat-BGD7MXAy.js","assets/code-DaZ-ZwCT.js","assets/commands-BAWSYHjQ.js","assets/common-DmsclwjP.js","assets/dashboard-XGdQ5mjw.js","assets/explore-DgBACn39.js","assets/integrations-mB-7zoyT.js","assets/jira-CKJg3HZd.js","assets/jobs-KG4Sn12X.js","assets/loops-B4_D-nbg.js","assets/mcp-CUAN6ORK.js","assets/narration-n3hOA7LY.js","assets/nav-DhPb-Isc.js","assets/packet-B0H15elv.js","assets/settings-tfLhQZRN.js","assets/setup-CRKLp_ke.js","assets/specs-DfIdoU5L.js","assets/terminal-BAzpHtpY.js","assets/tickets-D41ZMQpf.js","assets/createLucideIcon-Bjbbp_KS.js","assets/Trans-D3AfDylf.js","assets/useDesktop-0unHDBJJ.js","assets/provider-capabilities-Vi1ZGvAK.js","assets/save-B6wGWwBR.js","assets/spending-HBSk-6jv.js","assets/MinimizedChatsContext-CNx_0bZu.js","assets/sparkles-DrY8hb0X.js","assets/x-CBMI9ejn.js","assets/zap-CUOlvtT1.js","assets/circle-x-CMYsN4ZH.js","assets/download-CFHyyHcw.js","assets/file-text-CFT-xXKN.js","assets/git-branch-BRM0F5GN.js","assets/layers-eDMjG41I.js","assets/loader-circle-DcygOQpC.js","assets/pencil-C9RkrIPZ.js","assets/square-Ci-PFcFe.js","assets/plus-CsnjfkmX.js","assets/rotate-ccw-Wh4id13q.js","assets/search-Cq_gE3Ik.js","assets/trash-2-BOU3WdZZ.js","assets/triangle-alert-H9T4jAmh.js","assets/wrench-BfmNO9Vw.js","assets/dialog-xXB2q5HJ.js","assets/utils-BC4DHlz2.js","assets/clsx-CjueKrWZ.js","assets/lib-CGdyxIWg.js","assets/formatDistanceToNow-aBss1Nai.js","assets/getTimezoneOffsetInMilliseconds-DOGj1Mfz.js","assets/button-Ccc9Dc-D.js","assets/jira-api-BYbEPlkr.js","assets/RepositoryScopeSelector-C2mvWBQ6.js","assets/project-repositories-CSnfzUpg.js","assets/index-C4Mv6tV6.js","assets/core-B3mKBIh5.js","assets/RepositoryDeliveries-BiwJuS8r.js","assets/useRuntimeRuns-BN1rhyEm.js","assets/event-Bt7f3wXe.js","assets/index-BS7KCWkV.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{t as r}from"./preload-helper-Czpn1I53.js";import{n as i}from"./createLucideIcon-Bjbbp_KS.js";import{t as a}from"./x-CBMI9ejn.js";import{Ct as o,G as s,St as c,it as l,rt as u}from"./index-C4Mv6tV6.js";var d=e(t(),1),f=n(),p=(0,d.lazy)(()=>r(()=>import(`./CodePage-Alitorrv.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]))),m=420,h=560;function g({projectId:e,conversationId:t}){let{t:n}=i(`agent`),{closeCodePane:r}=s(),[g,_]=(0,d.useState)(h),[v,y]=(0,d.useState)(()=>window.innerWidth),[b,x]=(0,d.useState)(!1),S=(0,d.useRef)(null),C=(0,d.useRef)(null),w=Math.max(0,v-Math.min(m,v/2)),T=Math.min(m,w),E=Math.min(w,Math.max(T,g)),D=(0,d.useCallback)(e=>Math.min(w,Math.max(T,e)),[w,T]),O=`${e}:${t}`,k=(0,d.useCallback)(n=>{l(e,t,{path:n})},[e,t]);(0,d.useLayoutEffect)(()=>{let e=S.current,t=e?.parentElement;if(!e||!t)return;let n=()=>{let n=t.getBoundingClientRect().width||t.clientWidth||window.innerWidth,r=0;for(let n of t.children){if(n===e||!(n instanceof HTMLElement))continue;let t=getComputedStyle(n);t.display===`none`||t.position===`absolute`||t.position===`fixed`||Number(t.flexGrow)>0||(r+=n.getBoundingClientRect().width)}y(Math.max(0,n-r))},r=new ResizeObserver(n),i=()=>{r.disconnect(),r.observe(t);for(let n of t.children)n!==e&&r.observe(n);n()},a=new MutationObserver(i);return a.observe(t,{childList:!0}),i(),window.addEventListener(`resize`,n),()=>{r.disconnect(),a.disconnect(),window.removeEventListener(`resize`,n)}},[O]),(0,d.useEffect)(()=>()=>{C.current?.()},[O,b,w]);let A=(0,d.useCallback)(e=>{if(e.button!==0)return;e.preventDefault(),C.current?.();let t=e.clientX,n=E,r=e.pointerId,i=e.currentTarget;try{i.setPointerCapture(r)}catch{}let a=e=>{e.pointerId===r&&_(D(n+t-e.clientX))},o=()=>{window.removeEventListener(`pointermove`,a),window.removeEventListener(`pointerup`,s),window.removeEventListener(`pointercancel`,s),window.removeEventListener(`blur`,o),i.removeEventListener(`lostpointercapture`,o);try{i.hasPointerCapture(r)&&i.releasePointerCapture(r)}catch{}C.current=null},s=e=>{e.pointerId===r&&o()};C.current=o,window.addEventListener(`pointermove`,a),window.addEventListener(`pointerup`,s),window.addEventListener(`pointercancel`,s),window.addEventListener(`blur`,o),i.addEventListener(`lostpointercapture`,o)},[E,D]);return(0,f.jsxs)(`div`,{ref:S,className:`flex h-full min-w-0 flex-col overflow-hidden border-l border-border bg-background${b?` absolute inset-0 z-30 border-l-0`:` relative`}`,style:b?void 0:{width:E,maxWidth:`100%`,flexShrink:0},"data-testid":`agent-code-pane`,children:[!b&&(0,f.jsx)(`div`,{role:`separator`,"aria-orientation":`vertical`,onPointerDown:A,tabIndex:0,"aria-label":n(`workspace.resizeCode`),"aria-valuemin":Math.round(T),"aria-valuemax":Math.round(w),"aria-valuenow":Math.round(E),onKeyDown:e=>{let t=e.key===`ArrowLeft`?E+32:e.key===`ArrowRight`?E-32:e.key===`Home`?T:e.key===`End`?w:null;t!==null&&(e.preventDefault(),_(D(t)))},className:`absolute inset-y-0 left-0 z-20 w-1.5 cursor-col-resize select-none touch-none hover:bg-accent-primary/20 focus-visible:bg-accent-primary/30 focus-visible:outline-none`,title:n(`workspace.resizeCode`)}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border/60 bg-surface/40 px-3 py-1.5`,children:[(0,f.jsx)(`span`,{className:`text-xs font-medium text-foreground/70`,children:n(`workspace.files`)}),(0,f.jsxs)(`div`,{className:`ml-auto flex items-center gap-1`,children:[(0,f.jsx)(`button`,{type:`button`,onClick:()=>{C.current?.(),x(e=>!e)},"aria-label":n(b?`restore`:`maximize`),title:n(b?`restore`:`maximize`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:b?(0,f.jsx)(c,{className:`h-4 w-4`}):(0,f.jsx)(o,{className:`h-4 w-4`})}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>{C.current?.(),r()},"aria-label":n(`workspace.closeFiles`),title:n(`workspace.closeFiles`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:(0,f.jsx)(a,{className:`h-4 w-4`})})]})]}),(0,f.jsx)(`div`,{className:`min-h-0 flex-1 overflow-hidden`,children:(0,f.jsx)(d.Suspense,{fallback:(0,f.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`…`}),children:(0,f.jsx)(p,{embedded:!0,initialRepositoryId:u(e,t).repositoryId,onRepositoryChange:n=>l(e,t,{repositoryId:n}),initialPath:u(e,t).path,onSelectedPathChange:k},O)})})]},O)}export{g as AgentModeCodePane};
|