specrails-desktop 2.64.2 → 2.65.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 +1 -1
- package/cli/dist/status.js +3 -0
- package/client/dist/assets/ActivityFeedPage-ByVKYII-.js +1 -0
- package/client/dist/assets/AgentBrowserCapture-BGUTjhUr.js +1 -0
- package/client/dist/assets/AgentModeAnalyticsPane-CtOLDDjB.js +2 -0
- package/client/dist/assets/AgentModeCodePane-CDhUKarT.js +2 -0
- package/client/dist/assets/AgentModeJobsPane-BAa_oEHJ.js +1 -0
- package/client/dist/assets/AgentsPage-D32hG4Ve.js +120 -0
- package/client/dist/assets/AnalyticsPage-BU50zeG6.js +5 -0
- package/client/dist/assets/BudgetCard-DP_jxwaD.js +55 -0
- package/client/dist/assets/CodePage-jiYnKGpp.js +3 -0
- package/client/dist/assets/CostValue-Bvn8674q.js +1 -0
- package/client/dist/assets/DesktopAnalyticsPage-CF__H4e3.js +1 -0
- package/client/dist/assets/DocView-RrAp70zp.js +11 -0
- package/client/dist/assets/DocsDialog-DkqHU-JF.js +1 -0
- package/client/dist/assets/DocsPage-C6X089zC.js +1 -0
- package/client/dist/assets/ExportDropdown-C5-o8y3K.js +1 -0
- package/client/dist/assets/HelpHint-Crf9_uoR.js +1 -0
- package/client/dist/assets/IntegrationsPage-aflU3KHK.js +1 -0
- package/client/dist/assets/InteractiveJobComposer-CEMMhyyJ.js +19 -0
- package/client/dist/assets/JobDetailModal-BVJ6hyRs.js +1 -0
- package/client/dist/assets/JobDetailPage-DHzBUmox.js +1 -0
- package/client/dist/assets/JobsPage-o-LAqkwC.js +1 -0
- package/client/dist/assets/LoopBuilderPage-DbSVmXBM.js +1 -0
- package/client/dist/assets/LoopPreviewModal-DbJcVyN1.js +1 -0
- package/client/dist/assets/{LoopWindowSurface-DE0v2K1p.js → LoopWindowSurface-Co1ZK26V.js} +1 -1
- package/client/dist/assets/LoopsPage-C4lgkPXB.js +2 -0
- package/client/dist/assets/MinimizedChatsContext-742ypO8n.js +1 -0
- package/client/dist/assets/PluginsPage-Acks9ges.js +2 -0
- package/client/dist/assets/RailTrack-BfLmBzBh.js +1 -0
- package/client/dist/assets/{RepositoryScopeSelector-2eSqR9WK.js → RepositoryScopeSelector-DcxbKI9w.js} +1 -1
- package/client/dist/assets/ReviewPacketPage-CAVSIOAJ.js +7 -0
- package/client/dist/assets/TemplatePreviewModal-C23SYCTm.js +1 -0
- package/client/dist/assets/TicketDetailModalContext-B-Gtm6Ob.js +23 -0
- package/client/dist/assets/Trans-C6J0cLyh.js +1 -0
- package/client/dist/assets/a11y-prefs-BqoP5goK.js +1 -0
- package/client/dist/assets/activity-BBWfoUOG.js +1 -0
- package/client/dist/assets/activity-BM_skann.js +1 -0
- package/client/dist/assets/activity-Cevl82ke.js +1 -0
- package/client/dist/assets/activity-CmACk5W5.js +1 -0
- package/client/dist/assets/activity-D9LBw3PQ.js +1 -0
- package/client/dist/assets/activity-Dspbb9lz.js +1 -0
- package/client/dist/assets/activity-FPjYIjv9.js +1 -0
- package/client/dist/assets/activity-nLCKMUKt.js +1 -0
- package/client/dist/assets/addspec-BI4jDMhA.js +1 -0
- package/client/dist/assets/addspec-BldTv7Tl.js +1 -0
- package/client/dist/assets/addspec-Cdq-2EcC.js +1 -0
- package/client/dist/assets/addspec-DH5M16BQ.js +1 -0
- package/client/dist/assets/addspec-DOFo9pD5.js +1 -0
- package/client/dist/assets/addspec-DPkwhdmL.js +1 -0
- package/client/dist/assets/addspec-Dzy12Pv3.js +1 -0
- package/client/dist/assets/addspec-skTs6EEW.js +1 -0
- package/client/dist/assets/agent-B_UEUy7Y.js +1 -0
- package/client/dist/assets/agent-BarjlhTA.js +1 -0
- package/client/dist/assets/agent-BfqIITo5.js +1 -0
- package/client/dist/assets/agent-Bt9a7Kyj.js +1 -0
- package/client/dist/assets/agent-C3689RwP.js +1 -0
- package/client/dist/assets/agent-CrmboTAi.js +1 -0
- package/client/dist/assets/agent-DcsoTnuE.js +1 -0
- package/client/dist/assets/agent-GDZoYwd4.js +1 -0
- package/client/dist/assets/{agentRuntime-es2ymSl-.js → agentRuntime-BYH70bKY.js} +1 -1
- package/client/dist/assets/agentRuntime-BijLh8I9.js +1 -0
- package/client/dist/assets/{agentRuntime-BzuwQQgn.js → agentRuntime-BvyuETPe.js} +1 -1
- package/client/dist/assets/{agentRuntime-BDvbJMmS.js → agentRuntime-C2WI6HQh.js} +1 -1
- package/client/dist/assets/{agentRuntime-BKJfv5YD.js → agentRuntime-CZPIlQsr.js} +1 -1
- package/client/dist/assets/{agentRuntime-DiCldqGG.js → agentRuntime-D2dDvCyJ.js} +1 -1
- package/client/dist/assets/agentRuntime-DWZedEbn.js +1 -0
- package/client/dist/assets/agentRuntime-DkIruUNw.js +1 -0
- package/client/dist/assets/agents-35_PDKx9.js +1 -0
- package/client/dist/assets/agents-8fZnHhEQ.js +1 -0
- package/client/dist/assets/agents-Bgimtw8z.js +1 -0
- package/client/dist/assets/agents-C4P160Us.js +1 -0
- package/client/dist/assets/agents-Clg67zbp.js +1 -0
- package/client/dist/assets/agents-DJfF4o6G.js +1 -0
- package/client/dist/assets/agents-Dc9-Y5cw.js +1 -0
- package/client/dist/assets/agents-EN1Zl4YZ.js +1 -0
- package/client/dist/assets/agentstudio-Bm4-NYaG.js +1 -0
- package/client/dist/assets/agentstudio-CD1fuj2o.js +1 -0
- package/client/dist/assets/agentstudio-CQGWFSst.js +1 -0
- package/client/dist/assets/agentstudio-CqVSb65S.js +1 -0
- package/client/dist/assets/agentstudio-DIE_HjsX.js +1 -0
- package/client/dist/assets/agentstudio-D_OmQK-k.js +1 -0
- package/client/dist/assets/agentstudio-Djz9aUfb.js +1 -0
- package/client/dist/assets/agentstudio-Qa3v9o5J.js +1 -0
- package/client/dist/assets/{aiedit-DNXxq_Dr.js → aiedit-1VzLs37W.js} +1 -1
- package/client/dist/assets/{aiedit-DCjA7jLJ.js → aiedit-BNp6GSik.js} +1 -1
- package/client/dist/assets/{aiedit-BoG24nlg.js → aiedit-BOY5xRPi.js} +1 -1
- package/client/dist/assets/{aiedit-iIjz2_Qk.js → aiedit-BrqMZvbc.js} +1 -1
- package/client/dist/assets/{aiedit-CjlSRQVP.js → aiedit-CVgtl7hm.js} +1 -1
- package/client/dist/assets/{aiedit-DQ-0_pvE.js → aiedit-CrFW9Jd2.js} +1 -1
- package/client/dist/assets/{aiedit-olnv3QSt.js → aiedit-YE2lILp7.js} +1 -1
- package/client/dist/assets/{aiedit-B0KUbpB6.js → aiedit-iA_R1AVQ.js} +1 -1
- package/client/dist/assets/analytics-3w0t-4ic.js +1 -0
- package/client/dist/assets/analytics-BRi4KQD6.js +1 -0
- package/client/dist/assets/analytics-BtjAqzke.js +1 -0
- package/client/dist/assets/analytics-COSQ1h47.js +1 -0
- package/client/dist/assets/analytics-CP2HjESk.js +1 -0
- package/client/dist/assets/analytics-DY65TC62.js +1 -0
- package/client/dist/assets/analytics-Den_vvxn.js +1 -0
- package/client/dist/assets/analytics-LmBS96O8.js +1 -0
- package/client/dist/assets/api-DOGbyfTO.js +2 -0
- package/client/dist/assets/builder-BMVvSr4v.js +1 -0
- package/client/dist/assets/builder-BN-MuLZt.js +1 -0
- package/client/dist/assets/builder-BQOZi4CF.js +1 -0
- package/client/dist/assets/builder-BjUPjsyu.js +1 -0
- package/client/dist/assets/builder-BoBtN18T.js +1 -0
- package/client/dist/assets/builder-C5g5NhxL.js +1 -0
- package/client/dist/assets/builder-RUHXw3yx.js +1 -0
- package/client/dist/assets/builder-fyS_AiyC.js +1 -0
- package/client/dist/assets/button-CHPkroew.js +1 -0
- package/client/dist/assets/chat-C9L5T7KI.js +1 -0
- package/client/dist/assets/chevron-right-CwMAj0w_.js +1 -0
- package/client/dist/assets/chevron-up-BAMuP0XD.js +1 -0
- package/client/dist/assets/chunk-OB3PAWPO-BBaq6pUk.js +3 -0
- package/client/dist/assets/code-4le5IIbf.js +1 -0
- package/client/dist/assets/code-B-jCVIbm.js +1 -0
- package/client/dist/assets/code-BRfrn5ix.js +1 -0
- package/client/dist/assets/code-CC9NCrDM.js +1 -0
- package/client/dist/assets/code-CK6pm8wY.js +1 -0
- package/client/dist/assets/code-DDiOzd6c.js +1 -0
- package/client/dist/assets/code-tGifiyf5.js +1 -0
- package/client/dist/assets/code-xkn8kQTg.js +1 -0
- package/client/dist/assets/commands-Bv1QshHR.js +1 -0
- package/client/dist/assets/commands-BvxTxboW.js +1 -0
- package/client/dist/assets/commands-C5ORR0fO.js +1 -0
- package/client/dist/assets/commands-CBKMFSTV.js +1 -0
- package/client/dist/assets/commands-CFJIRsJv.js +1 -0
- package/client/dist/assets/commands-D9o3ZcXl.js +1 -0
- package/client/dist/assets/commands-DNox0Edk.js +1 -0
- package/client/dist/assets/commands-DmIUMLdV.js +1 -0
- package/client/dist/assets/common-5H4TkaoI.js +1 -0
- package/client/dist/assets/common-9S3OdPjx.js +1 -0
- package/client/dist/assets/common-BqnwIcjs.js +1 -0
- package/client/dist/assets/common-CQP3VafS.js +1 -0
- package/client/dist/assets/common-CZnAfkB2.js +1 -0
- package/client/dist/assets/common-D5sNttV4.js +1 -0
- package/client/dist/assets/common-k_qX9nlv.js +1 -0
- package/client/dist/assets/common-s4HIi9XI.js +1 -0
- package/client/dist/assets/compass-B7guwBlY.js +1 -0
- package/client/dist/assets/confirm-dialog-ChZdHL3Q.js +1 -0
- package/client/dist/assets/copy-DOPlLymH.js +1 -0
- package/client/dist/assets/core-BozBzB6Y.js +1 -0
- package/client/dist/assets/dashboard-6zGLGcEz.js +1 -0
- package/client/dist/assets/dashboard-8Gi0FBDq.js +1 -0
- package/client/dist/assets/dashboard-B7E5YrSy.js +1 -0
- package/client/dist/assets/dashboard-BhdKV8xK.js +1 -0
- package/client/dist/assets/dashboard-Bu3zzH_s.js +1 -0
- package/client/dist/assets/dashboard-Ce_6rELA.js +1 -0
- package/client/dist/assets/dashboard-DWY-oz8P.js +1 -0
- package/client/dist/assets/dashboard-gUzlWk0o.js +1 -0
- package/client/dist/assets/date-input-Cdlr8kHz.js +1 -0
- package/client/dist/assets/dialog-C23lB2iP.js +5 -0
- package/client/dist/assets/dist-Di-oOFkX.js +1 -0
- package/client/dist/assets/dist-js-CBmS6MsJ.js +1 -0
- package/client/dist/assets/{dist-js-Rlh4FLH5.js → dist-js-DaJmKapi.js} +1 -1
- package/client/dist/assets/dropdown-menu-Bfp2CK6H.js +1 -0
- package/client/dist/assets/empty-state-D5w9OWj-.js +1 -0
- package/client/dist/assets/es2015-DfnECntk.js +41 -0
- package/client/dist/assets/esm-BKF6CE7v.js +1 -0
- package/client/dist/assets/event-BEnMLqAi.js +1 -0
- package/client/dist/assets/explore--NOz9LCN.js +1 -0
- package/client/dist/assets/explore-B2ulH6dO.js +1 -0
- package/client/dist/assets/explore-BD-QiLdg.js +1 -0
- package/client/dist/assets/explore-BOqd4_1j.js +1 -0
- package/client/dist/assets/explore-Be_Zh5zu.js +1 -0
- package/client/dist/assets/explore-CLjzPSKo.js +1 -0
- package/client/dist/assets/explore-D_-vHm29.js +1 -0
- package/client/dist/assets/explore-yEQTF6ro.js +1 -0
- package/client/dist/assets/file-text-CNXzL3wj.js +1 -0
- package/client/dist/assets/format-BODoFIw6.js +1 -0
- package/client/dist/assets/formatDistanceToNow-DLMIOS0N.js +1 -0
- package/client/dist/assets/getTimezoneOffsetInMilliseconds-O61feXch.js +1 -0
- package/client/dist/assets/git-compare-arrows-Cu6tICCq.js +1 -0
- package/client/dist/assets/humanise-command-CB4ybLwq.js +1 -0
- package/client/dist/assets/inbox-BLZ8cm6_.js +1 -0
- package/client/dist/assets/inbox-BQ3VmNYY.js +1 -0
- package/client/dist/assets/inbox-BdcXWCuT.js +1 -0
- package/client/dist/assets/inbox-CF1PHjns.js +1 -0
- package/client/dist/assets/inbox-CFNPDhso.js +1 -0
- package/client/dist/assets/inbox-DIttK_NW.js +1 -0
- package/client/dist/assets/inbox-Dfdv1Ykl.js +1 -0
- package/client/dist/assets/inbox-JS1inmeO.js +1 -0
- package/client/dist/assets/index-4UWY7Xyz.css +2 -0
- package/client/dist/assets/index-DHzB0T26.js +120 -0
- package/client/dist/assets/integrations-BcKgzgPD.js +1 -0
- package/client/dist/assets/integrations-BmX_XyJq.js +1 -0
- package/client/dist/assets/integrations-CHpwMjlY.js +1 -0
- package/client/dist/assets/integrations-CT3kr8e-.js +1 -0
- package/client/dist/assets/integrations-C_5XAkgz.js +1 -0
- package/client/dist/assets/integrations-Ct9zLX7N.js +1 -0
- package/client/dist/assets/integrations-DEYemxUv.js +1 -0
- package/client/dist/assets/integrations-DWvsB_WB.js +1 -0
- package/client/dist/assets/{jira-Cq6yvN4q.js → jira-B_ERkFRv.js} +1 -1
- package/client/dist/assets/jira-Bn-A5lwD.js +1 -0
- package/client/dist/assets/jira-C71Ybnhp.js +1 -0
- package/client/dist/assets/jira-CkwjeJz6.js +1 -0
- package/client/dist/assets/jira-D9pSLXjI.js +1 -0
- package/client/dist/assets/jira-DBRS_lcp.js +1 -0
- package/client/dist/assets/jira-DHS6CsKh.js +1 -0
- package/client/dist/assets/jira-MInHRUb1.js +1 -0
- package/client/dist/assets/jira-api-DHme7Upx.js +1 -0
- package/client/dist/assets/jobs-BMLTDo63.js +1 -0
- package/client/dist/assets/jobs-BO8q4Mi1.js +1 -0
- package/client/dist/assets/jobs-Ck8uOWMM.js +1 -0
- package/client/dist/assets/jobs-CyFfPCpg.js +1 -0
- package/client/dist/assets/jobs-DT5s4fZ6.js +1 -0
- package/client/dist/assets/jobs-DZAgVPcD.js +1 -0
- package/client/dist/assets/jobs-b5gPYaKr.js +1 -0
- package/client/dist/assets/jobs-xsZK1440.js +1 -0
- package/client/dist/assets/launch-forecast-BTa-p3RP.js +1 -0
- package/client/dist/assets/{loop-layout-DtxX27Jz.css → loop-layout-DLioOiRN.css} +1 -1
- package/client/dist/assets/loop-layout-Sl9cfTvs.js +7 -0
- package/client/dist/assets/loops-BEEOVJDR.js +1 -0
- package/client/dist/assets/loops-BcrQ2vk7.js +1 -0
- package/client/dist/assets/loops-BjWxzJIZ.js +1 -0
- package/client/dist/assets/loops-BogV595N.js +1 -0
- package/client/dist/assets/loops-CU0BLZiz.js +1 -0
- package/client/dist/assets/loops-CrNBgi1G.js +1 -0
- package/client/dist/assets/loops-CwalwS_i.js +1 -0
- package/client/dist/assets/loops-_TDVN-fX.js +1 -0
- package/client/dist/assets/mcp-BNs8gxoL.js +1 -0
- package/client/dist/assets/mcp-BvRh_xO5.js +1 -0
- package/client/dist/assets/mcp-C2F1pghi.js +1 -0
- package/client/dist/assets/mcp-D9RLKAs2.js +1 -0
- package/client/dist/assets/mcp-DAghcsR0.js +1 -0
- package/client/dist/assets/mcp-DWWAPi1G.js +1 -0
- package/client/dist/assets/mcp-DbGSFC3f.js +1 -0
- package/client/dist/assets/mcp-FelCicrv.js +1 -0
- package/client/dist/assets/narration-C3NBkAR4.js +1 -0
- package/client/dist/assets/narration-CkoJq-Lf.js +1 -0
- package/client/dist/assets/narration-Cr0NeW9K.js +1 -0
- package/client/dist/assets/narration-DJUXOs-W.js +1 -0
- package/client/dist/assets/narration-DgL8TMvN.js +1 -0
- package/client/dist/assets/narration-DjBafgv0.js +1 -0
- package/client/dist/assets/narration-Dle6Iv0c.js +1 -0
- package/client/dist/assets/narration-MYlfktga.js +1 -0
- package/client/dist/assets/nav-BSQ8KW1c.js +1 -0
- package/client/dist/assets/nav-BauVof8Z.js +1 -0
- package/client/dist/assets/nav-BfOAH1se.js +1 -0
- package/client/dist/assets/nav-D3bOsipX.js +1 -0
- package/client/dist/assets/nav-DOMMhlLx.js +1 -0
- package/client/dist/assets/nav-DPzVlgZU.js +1 -0
- package/client/dist/assets/nav-DZJbFbah.js +1 -0
- package/client/dist/assets/nav-D_5aojd2.js +1 -0
- package/client/dist/assets/notify-error-BsWANx1T.js +1 -0
- package/client/dist/assets/onboarding-BdZQnNm3.js +1 -0
- package/client/dist/assets/onboarding-CJQEv1vp.js +1 -0
- package/client/dist/assets/onboarding-CWJGYUW3.js +1 -0
- package/client/dist/assets/onboarding-ChfYN7dA.js +1 -0
- package/client/dist/assets/onboarding-CjvDUR3V.js +1 -0
- package/client/dist/assets/onboarding-I6vS-zTB.js +1 -0
- package/client/dist/assets/onboarding-dgC_9dTB.js +1 -0
- package/client/dist/assets/onboarding-mlXSyKzX.js +1 -0
- package/client/dist/assets/origin-03nTuaOb.js +1 -0
- package/client/dist/assets/packet-BjpyRnZr.js +1 -0
- package/client/dist/assets/packet-BwgG5mBt.js +1 -0
- package/client/dist/assets/packet-C3eAUFkV.js +1 -0
- package/client/dist/assets/packet-C8wZuSld.js +1 -0
- package/client/dist/assets/packet-CNXEy_85.js +1 -0
- package/client/dist/assets/packet-DsV5Aa_8.js +1 -0
- package/client/dist/assets/packet-aasskOE7.js +1 -0
- package/client/dist/assets/packet-phxCc2gJ.js +1 -0
- package/client/dist/assets/page-header-BStSHkP8.js +1 -0
- package/client/dist/assets/project-repositories-DJPeAVBK.js +1 -0
- package/client/dist/assets/{provider-capabilities-lePfeT_Y.js → provider-capabilities-DtwcTme4.js} +1 -1
- package/client/dist/assets/recovery-BPDOsC92.js +1 -0
- package/client/dist/assets/recovery-BluNHoXM.js +1 -0
- package/client/dist/assets/recovery-CRvEmB0C.js +1 -0
- package/client/dist/assets/recovery-CeIoRnkR.js +1 -0
- package/client/dist/assets/recovery-DHCo8KGi.js +1 -0
- package/client/dist/assets/recovery-OxAIpbBF.js +1 -0
- package/client/dist/assets/recovery-XXexYGOJ.js +1 -0
- package/client/dist/assets/recovery-pITlc--v.js +1 -0
- package/client/dist/assets/refresh-cw-DfyTkbsf.js +1 -0
- package/client/dist/assets/select-xA3pSmqE.js +1 -0
- package/client/dist/assets/settings--yzDbX9r.js +1 -0
- package/client/dist/assets/settings-5_heTv8s.js +1 -0
- package/client/dist/assets/settings-BSf27MDg.js +1 -0
- package/client/dist/assets/settings-BSj6FakR.js +1 -0
- package/client/dist/assets/settings-BZDo_8Nn.js +1 -0
- package/client/dist/assets/settings-BdWgmNc0.js +1 -0
- package/client/dist/assets/settings-DRouxKqb.js +1 -0
- package/client/dist/assets/settings-DnWFoY-F.js +1 -0
- package/client/dist/assets/setup-BJWy62ri.js +1 -0
- package/client/dist/assets/setup-BgKOIuzc.js +1 -0
- package/client/dist/assets/setup-BvVIyUlz.js +1 -0
- package/client/dist/assets/setup-BxCk2pe1.js +1 -0
- package/client/dist/assets/setup-C-xQTL7R.js +1 -0
- package/client/dist/assets/setup-CbaVoiwV.js +1 -0
- package/client/dist/assets/setup-DxTBkX3P.js +1 -0
- package/client/dist/assets/setup-oGoVAzOD.js +1 -0
- package/client/dist/assets/specs-7tAb4IKr.js +1 -0
- package/client/dist/assets/specs-BUcY4s5v.js +1 -0
- package/client/dist/assets/specs-Bk5LeBAA.js +1 -0
- package/client/dist/assets/specs-CAA4Lrlg.js +1 -0
- package/client/dist/assets/specs-CS091AnA.js +1 -0
- package/client/dist/assets/specs-DJ6gmFcK.js +1 -0
- package/client/dist/assets/specs-GfCcrBSC.js +1 -0
- package/client/dist/assets/specs-xQgyc7WL.js +1 -0
- package/client/dist/assets/spending-CVH8VREb.js +1 -0
- package/client/dist/assets/square-Co6h5vZg.js +1 -0
- package/client/dist/assets/tauri-shell-43ixPGfa.js +2 -0
- package/client/dist/assets/terminal-0v9sBylD.js +1 -0
- package/client/dist/assets/terminal-AbUAmCxE.js +1 -0
- package/client/dist/assets/terminal-BJayIbIP.js +1 -0
- package/client/dist/assets/terminal-C2RUlXyi.js +1 -0
- package/client/dist/assets/terminal-CMmSb_Nj.js +1 -0
- package/client/dist/assets/terminal-DKWjj7HJ.js +1 -0
- package/client/dist/assets/terminal-KlFu7_pV.js +1 -0
- package/client/dist/assets/terminal-i99yqFvm.js +1 -0
- package/client/dist/assets/tickets-846Oq3i3.js +1 -0
- package/client/dist/assets/tickets-B5LJTe_b.js +1 -0
- package/client/dist/assets/tickets-Bfo2GGmH.js +1 -0
- package/client/dist/assets/tickets-BhdZ1yY2.js +1 -0
- package/client/dist/assets/tickets-CgjWJHAW.js +1 -0
- package/client/dist/assets/tickets-Ct9DbDUR.js +1 -0
- package/client/dist/assets/tickets-rptLEJB1.js +1 -0
- package/client/dist/assets/tickets-xQ6DpYdu.js +1 -0
- package/client/dist/assets/trending-up-BGvb4zZt.js +1 -0
- package/client/dist/assets/undo-6zuS4-sL.js +1 -0
- package/client/dist/assets/undo-BeM4gDOP.js +1 -0
- package/client/dist/assets/undo-BeppX8xS.js +1 -0
- package/client/dist/assets/undo-BqvNZ5MG.js +1 -0
- package/client/dist/assets/undo-BzwEPf_k.js +1 -0
- package/client/dist/assets/undo-CJ9Cu1NN.js +1 -0
- package/client/dist/assets/undo-ds8nMFbX.js +1 -0
- package/client/dist/assets/undo-x_gA-knG.js +1 -0
- package/client/dist/assets/useDesktop-BuOp2-MR.js +1 -0
- package/client/dist/assets/useRuntimeRuns-BRS6ncnO.js +1 -0
- package/client/dist/assets/utils-ELimjS2Y.js +1 -0
- package/client/dist/assets/wrench-Br2n1Lxd.js +1 -0
- package/client/dist/index.html +75 -60
- package/docs/ci-cd.md +29 -1
- package/docs/cli.md +10 -31
- package/docs/codex.md +1 -1
- package/docs/creating-specs.md +15 -12
- package/docs/customizing.md +16 -13
- package/docs/getting-started.md +12 -11
- package/docs/guide/de/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/de/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/de/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/de/getting-started/{4-the-dashboard-tour.md → 5-the-dashboard-tour.md} +7 -3
- package/docs/guide/de/getting-started/6-universal-search.md +34 -0
- package/docs/guide/de/insights/1-analytics-and-cost-tracking.md +20 -6
- package/docs/guide/de/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/de/insights/3-code-explorer.md +1 -1
- package/docs/guide/de/integrations/1-ai-providers.md +1 -1
- package/docs/guide/de/integrations/2-plugins.md +1 -1
- package/docs/guide/de/integrations/3-jira-integration.md +3 -3
- package/docs/guide/de/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/de/integrations/5-mcp-server.md +1 -1
- package/docs/guide/de/integrations/6-agent-chat.md +12 -5
- package/docs/guide/de/integrations/8-flow-mode.md +69 -0
- package/docs/guide/de/pipeline/1-rails-and-jobs.md +21 -1
- package/docs/guide/de/pipeline/2-the-job-detail-view.md +12 -0
- package/docs/guide/de/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/de/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/de/settings/1-themes.md +1 -1
- package/docs/guide/de/settings/3-pipeline-telemetry-and-diagnostics.md +2 -2
- package/docs/guide/de/settings/5-project-environment.md +1 -1
- package/docs/guide/de/settings/6-updates.md +24 -0
- package/docs/guide/de/settings/7-existing-projects.md +33 -0
- package/docs/guide/de/settings/8-accessibility.md +23 -0
- package/docs/guide/de/specs/1-specs-and-the-backlog.md +41 -3
- package/docs/guide/de/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/de/specs/3-add-spec-explore-mode.md +1 -1
- package/docs/guide/en/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/en/getting-started/1-what-is-specrails.md +1 -1
- package/docs/guide/en/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/en/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/en/getting-started/5-the-dashboard-tour.md +52 -0
- package/docs/guide/en/getting-started/6-universal-search.md +34 -0
- package/docs/guide/en/insights/1-analytics-and-cost-tracking.md +24 -10
- package/docs/guide/en/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/en/insights/3-code-explorer.md +5 -5
- package/docs/guide/en/integrations/1-ai-providers.md +1 -1
- package/docs/guide/en/integrations/2-plugins.md +1 -1
- package/docs/guide/en/integrations/3-jira-integration.md +4 -4
- package/docs/guide/en/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/en/integrations/5-mcp-server.md +4 -4
- package/docs/guide/en/integrations/6-agent-chat.md +12 -5
- package/docs/guide/en/integrations/8-flow-mode.md +69 -0
- package/docs/guide/en/pipeline/1-rails-and-jobs.md +22 -3
- package/docs/guide/en/pipeline/2-the-job-detail-view.md +19 -7
- package/docs/guide/en/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/en/pipeline/5-the-loop-builder.md +2 -2
- package/docs/guide/en/settings/1-themes.md +1 -1
- package/docs/guide/en/settings/3-pipeline-telemetry-and-diagnostics.md +2 -2
- package/docs/guide/en/settings/5-project-environment.md +1 -1
- package/docs/guide/en/settings/6-updates.md +24 -0
- package/docs/guide/en/settings/7-existing-projects.md +33 -0
- package/docs/guide/en/settings/8-accessibility.md +23 -0
- package/docs/guide/en/specs/1-specs-and-the-backlog.md +42 -6
- package/docs/guide/en/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/en/specs/3-add-spec-explore-mode.md +2 -2
- package/docs/guide/es/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/es/agents/2-profiles-and-the-balanced-default.md +1 -1
- package/docs/guide/es/agents/3-customizing-models-per-agent.md +2 -2
- package/docs/guide/es/agents/4-custom-agents-catalog.md +1 -1
- package/docs/guide/es/getting-started/1-what-is-specrails.md +3 -3
- package/docs/guide/es/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/es/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/es/getting-started/5-the-dashboard-tour.md +52 -0
- package/docs/guide/es/getting-started/6-universal-search.md +34 -0
- package/docs/guide/es/insights/1-analytics-and-cost-tracking.md +26 -12
- package/docs/guide/es/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/es/insights/3-code-explorer.md +5 -5
- package/docs/guide/es/integrations/1-ai-providers.md +1 -1
- package/docs/guide/es/integrations/2-plugins.md +1 -1
- package/docs/guide/es/integrations/3-jira-integration.md +4 -4
- package/docs/guide/es/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/es/integrations/5-mcp-server.md +4 -4
- package/docs/guide/es/integrations/6-agent-chat.md +14 -7
- package/docs/guide/es/integrations/7-local-engines.md +1 -1
- package/docs/guide/es/integrations/8-flow-mode.md +69 -0
- package/docs/guide/es/pipeline/1-rails-and-jobs.md +33 -13
- package/docs/guide/es/pipeline/2-the-job-detail-view.md +38 -26
- package/docs/guide/es/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/es/pipeline/5-the-loop-builder.md +4 -4
- package/docs/guide/es/settings/1-themes.md +1 -1
- package/docs/guide/es/settings/3-pipeline-telemetry-and-diagnostics.md +10 -10
- package/docs/guide/es/settings/5-project-environment.md +1 -1
- package/docs/guide/es/settings/6-updates.md +24 -0
- package/docs/guide/es/settings/7-existing-projects.md +33 -0
- package/docs/guide/es/settings/8-accessibility.md +23 -0
- package/docs/guide/es/specs/1-specs-and-the-backlog.md +43 -7
- package/docs/guide/es/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/es/specs/3-add-spec-explore-mode.md +3 -3
- package/docs/guide/fr/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/fr/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/fr/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/fr/getting-started/{4-the-dashboard-tour.md → 5-the-dashboard-tour.md} +7 -3
- package/docs/guide/fr/getting-started/6-universal-search.md +34 -0
- package/docs/guide/fr/insights/1-analytics-and-cost-tracking.md +18 -4
- package/docs/guide/fr/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/fr/insights/3-code-explorer.md +1 -1
- package/docs/guide/fr/integrations/1-ai-providers.md +1 -1
- package/docs/guide/fr/integrations/2-plugins.md +1 -1
- package/docs/guide/fr/integrations/3-jira-integration.md +3 -3
- package/docs/guide/fr/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/fr/integrations/5-mcp-server.md +1 -1
- package/docs/guide/fr/integrations/6-agent-chat.md +11 -4
- package/docs/guide/fr/integrations/8-flow-mode.md +69 -0
- package/docs/guide/fr/pipeline/1-rails-and-jobs.md +21 -1
- package/docs/guide/fr/pipeline/2-the-job-detail-view.md +12 -0
- package/docs/guide/fr/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/fr/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/fr/settings/1-themes.md +1 -1
- package/docs/guide/fr/settings/3-pipeline-telemetry-and-diagnostics.md +2 -2
- package/docs/guide/fr/settings/5-project-environment.md +1 -1
- package/docs/guide/fr/settings/6-updates.md +24 -0
- package/docs/guide/fr/settings/7-existing-projects.md +33 -0
- package/docs/guide/fr/settings/8-accessibility.md +23 -0
- package/docs/guide/fr/specs/1-specs-and-the-backlog.md +41 -3
- package/docs/guide/fr/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/fr/specs/3-add-spec-explore-mode.md +1 -1
- package/docs/guide/it/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/it/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/it/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/it/getting-started/{4-the-dashboard-tour.md → 5-the-dashboard-tour.md} +7 -3
- package/docs/guide/it/getting-started/6-universal-search.md +34 -0
- package/docs/guide/it/insights/1-analytics-and-cost-tracking.md +18 -4
- package/docs/guide/it/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/it/insights/3-code-explorer.md +1 -1
- package/docs/guide/it/integrations/1-ai-providers.md +1 -1
- package/docs/guide/it/integrations/2-plugins.md +1 -1
- package/docs/guide/it/integrations/3-jira-integration.md +3 -3
- package/docs/guide/it/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/it/integrations/5-mcp-server.md +1 -1
- package/docs/guide/it/integrations/6-agent-chat.md +11 -4
- package/docs/guide/it/integrations/8-flow-mode.md +69 -0
- package/docs/guide/it/pipeline/1-rails-and-jobs.md +21 -1
- package/docs/guide/it/pipeline/2-the-job-detail-view.md +12 -0
- package/docs/guide/it/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/it/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/it/settings/1-themes.md +1 -1
- package/docs/guide/it/settings/3-pipeline-telemetry-and-diagnostics.md +2 -2
- package/docs/guide/it/settings/5-project-environment.md +1 -1
- package/docs/guide/it/settings/6-updates.md +24 -0
- package/docs/guide/it/settings/7-existing-projects.md +33 -0
- package/docs/guide/it/settings/8-accessibility.md +23 -0
- package/docs/guide/it/specs/1-specs-and-the-backlog.md +41 -3
- package/docs/guide/it/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/it/specs/3-add-spec-explore-mode.md +1 -1
- package/docs/guide/ja/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/ja/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/ja/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/ja/getting-started/{4-the-dashboard-tour.md → 5-the-dashboard-tour.md} +7 -3
- package/docs/guide/ja/getting-started/6-universal-search.md +34 -0
- package/docs/guide/ja/insights/1-analytics-and-cost-tracking.md +18 -4
- package/docs/guide/ja/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/ja/insights/3-code-explorer.md +1 -1
- package/docs/guide/ja/integrations/1-ai-providers.md +1 -1
- package/docs/guide/ja/integrations/2-plugins.md +1 -1
- package/docs/guide/ja/integrations/3-jira-integration.md +3 -3
- package/docs/guide/ja/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/ja/integrations/5-mcp-server.md +1 -1
- package/docs/guide/ja/integrations/6-agent-chat.md +11 -4
- package/docs/guide/ja/integrations/8-flow-mode.md +69 -0
- package/docs/guide/ja/pipeline/1-rails-and-jobs.md +21 -1
- package/docs/guide/ja/pipeline/2-the-job-detail-view.md +12 -0
- package/docs/guide/ja/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/ja/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/ja/settings/1-themes.md +1 -1
- package/docs/guide/ja/settings/3-pipeline-telemetry-and-diagnostics.md +2 -2
- package/docs/guide/ja/settings/5-project-environment.md +1 -1
- package/docs/guide/ja/settings/6-updates.md +24 -0
- package/docs/guide/ja/settings/7-existing-projects.md +33 -0
- package/docs/guide/ja/settings/8-accessibility.md +23 -0
- package/docs/guide/ja/specs/1-specs-and-the-backlog.md +41 -3
- package/docs/guide/ja/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/ja/specs/3-add-spec-explore-mode.md +1 -1
- package/docs/guide/pt/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/pt/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/pt/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/pt/getting-started/{4-the-dashboard-tour.md → 5-the-dashboard-tour.md} +7 -3
- package/docs/guide/pt/getting-started/6-universal-search.md +34 -0
- package/docs/guide/pt/insights/1-analytics-and-cost-tracking.md +18 -4
- package/docs/guide/pt/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/pt/insights/3-code-explorer.md +1 -1
- package/docs/guide/pt/integrations/1-ai-providers.md +1 -1
- package/docs/guide/pt/integrations/2-plugins.md +1 -1
- package/docs/guide/pt/integrations/3-jira-integration.md +3 -3
- package/docs/guide/pt/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/pt/integrations/5-mcp-server.md +1 -1
- package/docs/guide/pt/integrations/6-agent-chat.md +12 -5
- package/docs/guide/pt/integrations/8-flow-mode.md +69 -0
- package/docs/guide/pt/pipeline/1-rails-and-jobs.md +21 -1
- package/docs/guide/pt/pipeline/2-the-job-detail-view.md +12 -0
- package/docs/guide/pt/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/pt/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/pt/settings/1-themes.md +1 -1
- package/docs/guide/pt/settings/3-pipeline-telemetry-and-diagnostics.md +2 -2
- package/docs/guide/pt/settings/5-project-environment.md +1 -1
- package/docs/guide/pt/settings/6-updates.md +24 -0
- package/docs/guide/pt/settings/7-existing-projects.md +33 -0
- package/docs/guide/pt/settings/8-accessibility.md +23 -0
- package/docs/guide/pt/specs/1-specs-and-the-backlog.md +41 -3
- package/docs/guide/pt/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/pt/specs/3-add-spec-explore-mode.md +1 -1
- package/docs/guide/zh/agents/1-meet-the-agents.md +1 -1
- package/docs/guide/zh/getting-started/2-installing-and-first-run.md +2 -0
- package/docs/guide/zh/getting-started/3-try-the-sample-project.md +35 -0
- package/docs/guide/zh/getting-started/{4-the-dashboard-tour.md → 5-the-dashboard-tour.md} +7 -3
- package/docs/guide/zh/getting-started/6-universal-search.md +34 -0
- package/docs/guide/zh/insights/1-analytics-and-cost-tracking.md +18 -4
- package/docs/guide/zh/insights/2-the-integrated-terminal.md +1 -1
- package/docs/guide/zh/insights/3-code-explorer.md +1 -1
- package/docs/guide/zh/integrations/1-ai-providers.md +1 -1
- package/docs/guide/zh/integrations/2-plugins.md +1 -1
- package/docs/guide/zh/integrations/3-jira-integration.md +3 -3
- package/docs/guide/zh/integrations/4-mobile-companion.md +1 -1
- package/docs/guide/zh/integrations/5-mcp-server.md +1 -1
- package/docs/guide/zh/integrations/6-agent-chat.md +11 -4
- package/docs/guide/zh/integrations/8-flow-mode.md +69 -0
- package/docs/guide/zh/pipeline/1-rails-and-jobs.md +21 -1
- package/docs/guide/zh/pipeline/2-the-job-detail-view.md +12 -0
- package/docs/guide/zh/pipeline/3-reviewing-a-delivery.md +43 -0
- package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +2 -2
- package/docs/guide/zh/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/zh/settings/1-themes.md +1 -1
- package/docs/guide/zh/settings/3-pipeline-telemetry-and-diagnostics.md +2 -2
- package/docs/guide/zh/settings/5-project-environment.md +1 -1
- package/docs/guide/zh/settings/6-updates.md +24 -0
- package/docs/guide/zh/settings/7-existing-projects.md +33 -0
- package/docs/guide/zh/settings/8-accessibility.md +23 -0
- package/docs/guide/zh/specs/1-specs-and-the-backlog.md +41 -3
- package/docs/guide/zh/specs/2-add-spec-quick-mode.md +1 -1
- package/docs/guide/zh/specs/3-add-spec-explore-mode.md +1 -1
- package/docs/internals/README.md +8 -0
- package/docs/internals/adding-a-provider.md +19 -2
- package/docs/internals/agent-actions-audit.md +101 -0
- package/docs/internals/agent-sessions.md +36 -1
- package/docs/internals/api-reference.md +190 -45
- package/docs/internals/architecture.md +53 -47
- package/docs/internals/companion-inbox-decisions.md +42 -0
- package/docs/internals/companion-rails-as-loops-contract.md +17 -6
- package/docs/internals/configuration.md +140 -9
- package/docs/internals/core-runtime-updates.md +4 -4
- package/docs/internals/existing-project-anchoring.md +168 -0
- package/docs/internals/flow-mode.md +668 -0
- package/docs/internals/legacy-implementation-notes.md +13 -0
- package/docs/internals/local-testing-feedback-2026-10.md +210 -0
- package/docs/internals/mcp-mission-audit.md +4 -0
- package/docs/internals/mission-rail-cards.md +10 -5
- package/docs/internals/mission-read-only-policy.md +152 -0
- package/docs/internals/modal-standard.md +181 -0
- package/docs/internals/openspec-workflow.md +32 -0
- package/docs/internals/operations-runbook.md +30 -0
- package/docs/internals/profiles.md +6 -3
- package/docs/internals/programmatic-agent-runtime.md +8 -0
- package/docs/internals/project-builder.md +1 -1
- package/docs/internals/review-packet.md +161 -9
- package/docs/internals/safe-pr-review-flow.md +135 -6
- package/docs/internals/source-map.md +413 -18
- package/docs/internals/spec-addenda.md +10 -0
- package/docs/internals/spec-triage.md +140 -0
- package/docs/internals/visual-design-audit.md +15 -2
- package/docs/local-providers.md +3 -0
- package/docs/mcp.md +21 -3
- package/docs/platforms/macos.md +1 -1
- package/docs/platforms/windows.md +2 -2
- package/docs/running-pipelines.md +22 -6
- package/docs/tracking-cost.md +54 -10
- package/local-runner/dist/specrails-local-runner.js +3851 -1178
- package/mcp-bridge/dist/specrails-mcp.js +3864 -1143
- package/package.json +10 -9
- package/server/dist/agent-mcp-config.js +37 -1
- package/server/dist/api-version.js +19 -0
- package/server/dist/command-resolver.js +4 -2
- package/server/dist/core-compat.js +1 -1
- package/server/dist/core-execution.js +2 -1
- package/server/dist/core-update-manager.js +71 -13
- package/server/dist/db/job-search.js +248 -0
- package/server/dist/db/jobs.js +6 -0
- package/server/dist/db/migrations.js +239 -0
- package/server/dist/db.js +9 -2
- package/server/dist/desktop-db.js +99 -5
- package/server/dist/desktop-router.js +126 -13
- package/server/dist/docs-router.js +67 -1
- package/server/dist/feature-flags.js +22 -0
- package/server/dist/index.js +30 -15
- package/server/dist/jira/jira-adf.js +13 -1
- package/server/dist/jira/jira-clarifications.js +146 -0
- package/server/dist/jira/jira-client.js +8 -1
- package/server/dist/jira/jira-db.js +41 -0
- package/server/dist/jira/jira-sync-manager.js +328 -25
- package/server/dist/mcp/guide.js +17 -7
- package/server/dist/mcp/tools/agents.js +1 -1
- package/server/dist/mcp/tools/analytics.js +15 -3
- package/server/dist/mcp/tools/app-settings.js +14 -1
- package/server/dist/mcp/tools/chat.js +1 -1
- package/server/dist/mcp/tools/env.js +4 -2
- package/server/dist/mcp/tools/jobs.js +96 -7
- package/server/dist/mcp/tools/loops.js +1 -1
- package/server/dist/mcp/tools/meta.js +10 -13
- package/server/dist/mcp/tools/rails.js +15 -1
- package/server/dist/mcp/tools/setup.js +1 -1
- package/server/dist/mcp/tools/specs.js +8 -5
- package/server/dist/mcp/tools/support.js +6 -3
- package/server/dist/mcp/tools/types.js +38 -1
- package/server/dist/mobile/mobile-admin-router.js +0 -16
- package/server/dist/mobile/mobile-gateway.js +0 -18
- package/server/dist/mobile/mobile-inbox.js +240 -0
- package/server/dist/mobile/mobile-missions.js +6 -8
- package/server/dist/mobile/mobile-router.js +9 -9
- package/server/dist/mobile/mobile-webrtc-peer.js +4 -54
- package/server/dist/mobile/mobile-ws.js +27 -4
- package/server/dist/modules/accounting/runtime/ai-invocations.js +4 -0
- package/server/dist/modules/accounting/runtime/decision-times.js +102 -0
- package/server/dist/modules/accounting/runtime/loop-economics.js +284 -0
- package/server/dist/modules/accounting/runtime/spending.js +7 -2
- package/server/dist/modules/accounting/runtime/what-if.js +87 -0
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-bridge.js +86 -5
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-controls.js +28 -2
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-metrics.js +15 -2
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-settings-router.js +21 -2
- package/server/dist/modules/agent-runtime/runtime/core-capabilities.js +55 -0
- package/server/dist/modules/agent-sessions/adapters/host-process.js +1 -1
- package/server/dist/modules/agent-sessions/domain/availability.js +16 -0
- package/server/dist/modules/agent-sessions/domain/protocol.js +8 -1
- package/server/dist/modules/agent-sessions/index.js +3 -1
- package/server/dist/modules/agent-sessions/runtime/core-sessions-availability.js +16 -0
- package/server/dist/modules/agents/runtime/agent-refine-manager.js +3 -1
- package/server/dist/modules/agents/runtime/agent-store.js +60 -73
- package/server/dist/modules/audit/adapters/http.js +66 -0
- package/server/dist/modules/audit/adapters/runtime.js +60 -0
- package/server/dist/modules/audit/adapters/sqlite.js +73 -0
- package/server/dist/modules/audit/application.js +190 -0
- package/server/dist/modules/audit/domain.js +434 -0
- package/server/dist/modules/audit/index.js +27 -0
- package/server/dist/modules/audit/ports.js +2 -0
- package/server/dist/modules/browser/runtime/browser-capture-manager.js +18 -141
- package/server/dist/modules/browser/runtime/browser-capture-types.js +1 -10
- package/server/dist/modules/browser/runtime/browser-playwright.js +0 -19
- package/server/dist/modules/code/runtime/file-provenance.js +23 -0
- package/server/dist/modules/conversations/runtime/chat-manager.js +5 -2
- package/server/dist/modules/delivery/adapters/decisions/chains.js +1 -0
- package/server/dist/modules/delivery/adapters/decisions/create.js +19 -1
- package/server/dist/modules/delivery/adapters/decisions/discard.js +2 -0
- package/server/dist/modules/delivery/adapters/decisions/local-changes.js +427 -0
- package/server/dist/modules/delivery/adapters/decisions/merge-local.js +80 -6
- package/server/dist/modules/delivery/adapters/decisions/observations.js +5 -0
- package/server/dist/modules/delivery/adapters/decisions/ownership.js +2 -1
- package/server/dist/modules/delivery/adapters/decisions/transitions.js +9 -0
- package/server/dist/modules/delivery/adapters/review-wip-store.js +37 -0
- package/server/dist/modules/delivery/domain/review-wip.js +71 -0
- package/server/dist/modules/delivery/index.js +9 -1
- package/server/dist/modules/delivery/runtime/delivery-changes.js +355 -0
- package/server/dist/modules/delivery/runtime/delivery-evidence.js +249 -8
- package/server/dist/modules/delivery/runtime/flow-review-legacy.js +99 -0
- package/server/dist/modules/delivery/runtime/flow-review-outcome.js +107 -0
- package/server/dist/modules/delivery/runtime/flow-worktree-handoff.js +32 -0
- package/server/dist/modules/delivery/runtime/flow-worktree-return.js +87 -0
- package/server/dist/modules/delivery/runtime/isolated-worktree.js +380 -0
- package/server/dist/modules/delivery/runtime/local-restore-branch.js +325 -0
- package/server/dist/modules/delivery/runtime/local-restore-resolver.js +48 -0
- package/server/dist/modules/delivery/runtime/local-stash.js +423 -0
- package/server/dist/modules/delivery/runtime/multi-repo-execution.js +27 -1
- package/server/dist/modules/delivery/runtime/phase3-harvest.js +40 -0
- package/server/dist/modules/delivery/runtime/pr-body.js +50 -0
- package/server/dist/modules/delivery/runtime/rail-isolated-launch.js +169 -166
- package/server/dist/modules/delivery/runtime/rail-launch-parser.js +5 -2
- package/server/dist/modules/delivery/runtime/rail-pr-decision.js +7 -1
- package/server/dist/modules/delivery/runtime/rail-pr-store.js +193 -12
- package/server/dist/modules/delivery/runtime/rails-router.js +267 -5
- package/server/dist/modules/delivery/runtime/review-brief.js +208 -0
- package/server/dist/modules/delivery/runtime/review-packet.js +41 -2
- package/server/dist/modules/delivery/runtime/review-wip-gate.js +67 -0
- package/server/dist/modules/delivery/runtime/run-records.js +267 -0
- package/server/dist/modules/delivery/runtime/run-review-diagnosis.js +102 -0
- package/server/dist/modules/execution/adapters/budget-storage.js +76 -0
- package/server/dist/modules/execution/application/enforce-budget.js +17 -2
- package/server/dist/modules/execution/domain/agent-env.js +98 -0
- package/server/dist/modules/execution/domain/daily-budget.js +36 -0
- package/server/dist/modules/execution/domain/spend-caps.js +166 -0
- package/server/dist/modules/execution/index.js +34 -1
- package/server/dist/modules/execution/runtime/budget-overview.js +76 -0
- package/server/dist/modules/execution/runtime/daily-budget-gate.js +86 -0
- package/server/dist/modules/execution/runtime/interactive-job-session.js +8 -0
- package/server/dist/modules/execution/runtime/launch-forecast.js +33 -0
- package/server/dist/modules/execution/runtime/queue-manager.js +54 -15
- package/server/dist/modules/execution/runtime/run-duration-stats.js +31 -13
- package/server/dist/modules/flow/adapters/bindings.js +1089 -0
- package/server/dist/modules/flow/adapters/http.js +147 -0
- package/server/dist/modules/flow/adapters/sqlite.js +121 -0
- package/server/dist/modules/flow/application.js +805 -0
- package/server/dist/modules/flow/domain.js +790 -0
- package/server/dist/modules/flow/index.js +34 -0
- package/server/dist/modules/flow/ports.js +2 -0
- package/server/dist/modules/inbox/adapters/http.js +21 -0
- package/server/dist/modules/inbox/adapters/project-source.js +233 -0
- package/server/dist/modules/inbox/application.js +28 -0
- package/server/dist/modules/inbox/domain.js +43 -0
- package/server/dist/modules/inbox/index.js +10 -0
- package/server/dist/modules/inbox/ports.js +2 -0
- package/server/dist/modules/loops/runtime/loop-definition-run.js +9 -0
- package/server/dist/modules/loops/runtime/loop-definition.js +5 -2
- package/server/dist/modules/loops/runtime/loop-executors.js +90 -9
- package/server/dist/modules/loops/runtime/loop-factory.js +30 -2
- package/server/dist/modules/loops/runtime/loop-flow-spec-recipe.js +166 -0
- package/server/dist/modules/loops/runtime/loop-graph.js +1 -1
- package/server/dist/modules/loops/runtime/loop-role-engines.js +4 -1
- package/server/dist/modules/loops/runtime/loop-run-manager.js +267 -10
- package/server/dist/modules/loops/runtime/loop-runs-store.js +21 -5
- package/server/dist/modules/loops/runtime/loop-templates.js +55 -12
- package/server/dist/modules/missions/runtime/agent-chat-manager.js +283 -20
- package/server/dist/modules/missions/runtime/agent-chat-router.js +96 -21
- package/server/dist/modules/missions/runtime/agent-failure-briefing.js +11 -3
- package/server/dist/modules/missions/runtime/agent-fence-promotion.js +9 -1
- package/server/dist/modules/missions/runtime/agent-flow-prompt.js +64 -0
- package/server/dist/modules/missions/runtime/agent-input-store.js +9 -4
- package/server/dist/modules/missions/runtime/agent-operator-prompt.js +100 -14
- package/server/dist/modules/missions/runtime/agent-session-store.js +88 -27
- package/server/dist/modules/missions/runtime/core-session-runner.js +89 -9
- package/server/dist/modules/missions/runtime/flow-turn-context.js +17 -0
- package/server/dist/modules/missions/runtime/mission-core-sessions.js +295 -55
- package/server/dist/modules/missions/runtime/mission-run-notify.js +2 -0
- package/server/dist/modules/missions/runtime/mission-session-projector.js +56 -19
- package/server/dist/modules/missions/runtime/mission-tool-policy.js +47 -0
- package/server/dist/modules/onboarding/adapters/http.js +78 -0
- package/server/dist/modules/onboarding/adapters/providers.js +41 -0
- package/server/dist/modules/onboarding/adapters/runtime.js +130 -0
- package/server/dist/modules/onboarding/application.js +133 -0
- package/server/dist/modules/onboarding/catalog.js +217 -0
- package/server/dist/modules/onboarding/domain.js +102 -0
- package/server/dist/modules/onboarding/index.js +20 -0
- package/server/dist/modules/onboarding/ports.js +2 -0
- package/server/dist/modules/project-rules/adapters/http.js +91 -0
- package/server/dist/modules/project-rules/domain.js +122 -0
- package/server/dist/modules/project-rules/runtime/rules-inventory-runs.js +97 -0
- package/server/dist/modules/project-rules/runtime/rules-store.js +109 -0
- package/server/dist/modules/project-settings/adapters/http.js +13 -0
- package/server/dist/modules/project-settings/adapters/sqlite.js +78 -8
- package/server/dist/modules/project-settings/domain.js +47 -1
- package/server/dist/modules/project-settings/index.js +7 -1
- package/server/dist/modules/recovery/adapters/sqlite.js +28 -0
- package/server/dist/modules/recovery/domain.js +162 -0
- package/server/dist/modules/recovery/index.js +16 -0
- package/server/dist/modules/specs/adapters/timeline-http.js +101 -0
- package/server/dist/modules/specs/domain/handoff-labels.js +371 -0
- package/server/dist/modules/specs/domain/handoff.js +260 -0
- package/server/dist/modules/specs/domain/non-goals.js +101 -0
- package/server/dist/modules/specs/domain/timeline.js +164 -0
- package/server/dist/modules/specs/domain/triage.js +320 -0
- package/server/dist/modules/specs/runtime/contract-refine-runner.js +3 -2
- package/server/dist/modules/specs/runtime/generated-spec-parser.js +75 -0
- package/server/dist/modules/specs/runtime/proposal-manager.js +4 -3
- package/server/dist/modules/specs/runtime/smash-runner.js +2 -1
- package/server/dist/modules/specs/runtime/spec-addenda.js +31 -0
- package/server/dist/modules/specs/runtime/spec-draft-parser.js +6 -1
- package/server/dist/modules/specs/runtime/spec-generation.js +431 -0
- package/server/dist/modules/specs/runtime/spec-handoff.js +103 -0
- package/server/dist/modules/specs/runtime/spec-history.js +376 -0
- package/server/dist/modules/specs/runtime/spec-launcher-manager.js +4 -3
- package/server/dist/modules/specs/runtime/spec-search.js +117 -0
- package/server/dist/modules/specs/runtime/ticket-store.js +47 -2
- package/server/dist/modules/specs/runtime/ticket-trash-service.js +62 -0
- package/server/dist/modules/specs/runtime/ticket-trash.js +193 -0
- package/server/dist/modules/specs/runtime/triage-runner.js +171 -0
- package/server/dist/modules/specs/runtime/triage.js +365 -0
- package/server/dist/modules/terminals/domain/app-urls.js +96 -0
- package/server/dist/modules/terminals/runtime/app-urls.js +77 -0
- package/server/dist/modules/terminals/runtime/background-process-service.js +25 -28
- package/server/dist/project-env.js +60 -0
- package/server/dist/project-git.js +65 -0
- package/server/dist/project-registry.js +264 -27
- package/server/dist/project-router-background-processes.js +27 -3
- package/server/dist/project-router-git.js +30 -0
- package/server/dist/project-router-helpers.js +5 -30
- package/server/dist/project-router-jobs.js +49 -1
- package/server/dist/project-router-loop-runs.js +72 -2
- package/server/dist/project-router-rules.js +54 -0
- package/server/dist/project-router-search.js +52 -0
- package/server/dist/project-router-settings.js +6 -0
- package/server/dist/project-router-setup.js +1 -1
- package/server/dist/project-router-spending.js +138 -0
- package/server/dist/project-router-tickets.js +246 -427
- package/server/dist/project-router.js +7 -0
- package/server/dist/providers/claude-adapter.js +25 -3
- package/server/dist/providers/codex-adapter.js +9 -1
- package/server/dist/providers/gemini-adapter.js +6 -1
- package/server/dist/providers/kimi-adapter.js +2 -0
- package/server/dist/providers/local-adapter.js +2 -0
- package/server/dist/providers/runtime.js +8 -0
- package/server/dist/schemas/agent-runtime.schema.json +3 -1
- package/server/dist/schemas/workflow-definition.schema.json +1 -0
- package/server/dist/setup-manager.js +19 -1
- package/server/dist/transient-children.js +25 -8
- package/server/dist/update-channel.js +21 -0
- package/server/dist/util/search-snippet.js +74 -0
- package/server/dist/worktree-manager.js +19 -8
- package/client/dist/assets/ActivityFeedPage-Dtp7EyHc.js +0 -1
- package/client/dist/assets/AgentBrowserCapture-CLqlEFw8.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane-B8_hM3Tw.js +0 -2
- package/client/dist/assets/AgentModeCodePane-CNF8ZNjE.js +0 -2
- package/client/dist/assets/AgentModeJobsPane-CJpJbO9m.js +0 -1
- package/client/dist/assets/AgentsPage-BC8XSR79.js +0 -120
- package/client/dist/assets/AnalyticsPage-Cdv4jLtW.js +0 -1
- package/client/dist/assets/BarChart-BDMqVFJy.js +0 -55
- package/client/dist/assets/CodePage-DI1kegAr.js +0 -3
- package/client/dist/assets/DesktopAnalyticsPage-Bdp8E8U6.js +0 -1
- package/client/dist/assets/DocsDialog-Bm4RS7FX.js +0 -11
- package/client/dist/assets/DocsPage-DihYcU8r.js +0 -11
- package/client/dist/assets/ExportDropdown-Bb1lHx3r.js +0 -1
- package/client/dist/assets/IntegrationsPage-EAipiDWm.js +0 -1
- package/client/dist/assets/InteractiveJobComposer-BO6ASN-2.js +0 -19
- package/client/dist/assets/JobDetailModal-CuPYq7tP.js +0 -1
- package/client/dist/assets/JobDetailPage-BusMjJi9.js +0 -1
- package/client/dist/assets/JobsPage-C0QbsF2d.js +0 -1
- package/client/dist/assets/LoopBuilderPage-B7TlU4iS.js +0 -1
- package/client/dist/assets/LoopPreviewModal-BRWtXOD2.js +0 -1
- package/client/dist/assets/LoopsPage-C4q1DmCE.js +0 -2
- package/client/dist/assets/MinimizedChatsContext-DHfigjHS.js +0 -1
- package/client/dist/assets/PluginsPage-Z1JHSMdR.js +0 -2
- package/client/dist/assets/ProjectSettingsDialog-BUNj0tvN.js +0 -1
- package/client/dist/assets/RepositoryDeliveries-B4ybHOyB.js +0 -5
- package/client/dist/assets/ReviewPacketPage-hwfPNjyy.js +0 -4
- package/client/dist/assets/TemplatePreviewModal-V7FpMWuw.js +0 -1
- package/client/dist/assets/TicketDetailModalContext-Dkwo2cDs.js +0 -16
- package/client/dist/assets/Trans-BbFxRFtR.js +0 -1
- package/client/dist/assets/activity-B-rp4h_v.js +0 -1
- package/client/dist/assets/activity-C6kJpm9q.js +0 -1
- package/client/dist/assets/activity-CGx4kb_j.js +0 -1
- package/client/dist/assets/activity-CnoX2bH7.js +0 -1
- package/client/dist/assets/activity-DAyekdlt.js +0 -1
- package/client/dist/assets/activity-DCxtpT7j.js +0 -1
- package/client/dist/assets/activity-DiyjsgQV.js +0 -1
- package/client/dist/assets/activity-JzwRaWPD.js +0 -1
- package/client/dist/assets/addspec-BOvgmcgk.js +0 -1
- package/client/dist/assets/addspec-Clmyfn_R.js +0 -1
- package/client/dist/assets/addspec-CsNaBpHp.js +0 -1
- package/client/dist/assets/addspec-D2tvWmmV.js +0 -1
- package/client/dist/assets/addspec-D3nFwvD0.js +0 -1
- package/client/dist/assets/addspec-DVLEhK3w.js +0 -1
- package/client/dist/assets/addspec-DXbK-tb0.js +0 -1
- package/client/dist/assets/addspec-OHG8DFEn.js +0 -1
- package/client/dist/assets/agent-5bSixVzz.js +0 -1
- package/client/dist/assets/agent-BR4EHfhq.js +0 -1
- package/client/dist/assets/agent-C0IKkJP8.js +0 -1
- package/client/dist/assets/agent-C7li9ayC.js +0 -1
- package/client/dist/assets/agent-D0dRmEen.js +0 -1
- package/client/dist/assets/agent-DZVGHm7H.js +0 -1
- package/client/dist/assets/agent-Dip4h2YE.js +0 -1
- package/client/dist/assets/agent-Pp-P-n1p.js +0 -1
- package/client/dist/assets/agentRuntime-BxF81z52.js +0 -1
- package/client/dist/assets/agentRuntime-BxYS5V7u.js +0 -1
- package/client/dist/assets/agentRuntime-Dc9HG3BA.js +0 -1
- package/client/dist/assets/agents-B6ZsnARo.js +0 -1
- package/client/dist/assets/agents-BORdhe0K.js +0 -1
- package/client/dist/assets/agents-C6aq9Oqs.js +0 -1
- package/client/dist/assets/agents-Cbsc4bcX.js +0 -1
- package/client/dist/assets/agents-D0uYR6hq.js +0 -1
- package/client/dist/assets/agents-Doe1sHY5.js +0 -1
- package/client/dist/assets/agents-DyNi_I9m.js +0 -1
- package/client/dist/assets/agents-StKxiTg0.js +0 -1
- package/client/dist/assets/agentstudio-7cYCXn-L.js +0 -1
- package/client/dist/assets/agentstudio-BHWQh8G3.js +0 -1
- package/client/dist/assets/agentstudio-BjnWHyRs.js +0 -1
- package/client/dist/assets/agentstudio-BkV8vcK4.js +0 -1
- package/client/dist/assets/agentstudio-BzugqB_N.js +0 -1
- package/client/dist/assets/agentstudio-CWbp7KvH.js +0 -1
- package/client/dist/assets/agentstudio-DG6plf5o.js +0 -1
- package/client/dist/assets/agentstudio-DkZVF-Cc.js +0 -1
- package/client/dist/assets/analytics-B1DIQd4m.js +0 -1
- package/client/dist/assets/analytics-BAIZ9vE_.js +0 -1
- package/client/dist/assets/analytics-BTqgmgBd.js +0 -1
- package/client/dist/assets/analytics-BWynXPEm.js +0 -1
- package/client/dist/assets/analytics-DGcUsQ44.js +0 -1
- package/client/dist/assets/analytics-GnSnpJ4W.js +0 -1
- package/client/dist/assets/analytics-TWgYaoO0.js +0 -1
- package/client/dist/assets/analytics-kJy6Tuko.js +0 -1
- package/client/dist/assets/atom-one-dark-qiGhVQxg.js +0 -1
- package/client/dist/assets/builder-B9gorTnT.js +0 -1
- package/client/dist/assets/builder-Bvw5s3Mi.js +0 -1
- package/client/dist/assets/builder-CL5l4dU3.js +0 -1
- package/client/dist/assets/builder-CVDTVrQX.js +0 -1
- package/client/dist/assets/builder-CpS9liE9.js +0 -1
- package/client/dist/assets/builder-DNctIL9Q.js +0 -1
- package/client/dist/assets/builder-De2NxX6o.js +0 -1
- package/client/dist/assets/builder-DeYT7Y-m.js +0 -1
- package/client/dist/assets/button-4FS1ZDTp.js +0 -1
- package/client/dist/assets/chat-D_I7nU5K.js +0 -1
- package/client/dist/assets/chevron-up-6EFqEHBj.js +0 -1
- package/client/dist/assets/chunk-OB3PAWPO-B1EMk45A.js +0 -3
- package/client/dist/assets/clsx-CjueKrWZ.js +0 -1
- package/client/dist/assets/code-B37GRg9C.js +0 -1
- package/client/dist/assets/code-BBOEZbf9.js +0 -1
- package/client/dist/assets/code-BRm-jcyx.js +0 -1
- package/client/dist/assets/code-CF7w62CR.js +0 -1
- package/client/dist/assets/code-CLuvJt2r.js +0 -1
- package/client/dist/assets/code-D0RCm59f.js +0 -1
- package/client/dist/assets/code-DaZ-ZwCT.js +0 -1
- package/client/dist/assets/code-iIHkGaCL.js +0 -1
- package/client/dist/assets/commands-0XjAftla.js +0 -1
- package/client/dist/assets/commands-BAWSYHjQ.js +0 -1
- package/client/dist/assets/commands-BBwowgiE.js +0 -1
- package/client/dist/assets/commands-BacjIZLN.js +0 -1
- package/client/dist/assets/commands-Bs62IAZ3.js +0 -1
- package/client/dist/assets/commands-CLPdh-Hh.js +0 -1
- package/client/dist/assets/commands-DlbFzgrp.js +0 -1
- package/client/dist/assets/commands-LjPSsi5F.js +0 -1
- package/client/dist/assets/common-Bdi0qN4S.js +0 -1
- package/client/dist/assets/common-Bhb9zN1P.js +0 -1
- package/client/dist/assets/common-BykKlZg1.js +0 -1
- package/client/dist/assets/common-CvnNNSJA.js +0 -1
- package/client/dist/assets/common-D5zk_mqq.js +0 -1
- package/client/dist/assets/common-DQNO_al5.js +0 -1
- package/client/dist/assets/common-Dax30Vmp.js +0 -1
- package/client/dist/assets/common-DkllpVSb.js +0 -1
- package/client/dist/assets/core-B3mKBIh5.js +0 -1
- package/client/dist/assets/dashboard-B1ndRHuC.js +0 -1
- package/client/dist/assets/dashboard-BX7KXiqA.js +0 -1
- package/client/dist/assets/dashboard-B_BSNxcN.js +0 -1
- package/client/dist/assets/dashboard-CCeFN7-V.js +0 -1
- package/client/dist/assets/dashboard-CRl0WtFJ.js +0 -1
- package/client/dist/assets/dashboard-XGdQ5mjw.js +0 -1
- package/client/dist/assets/dashboard-_oltA6Jd.js +0 -1
- package/client/dist/assets/dashboard-bAuf5KVk.js +0 -1
- package/client/dist/assets/dialog-DtdR05v1.js +0 -45
- package/client/dist/assets/dist-js-CJ_2XX1Y.js +0 -1
- package/client/dist/assets/event-Bt7f3wXe.js +0 -1
- package/client/dist/assets/explore-BG99VGpL.js +0 -1
- package/client/dist/assets/explore-C0TjprJW.js +0 -1
- package/client/dist/assets/explore-C2dgEo7q.js +0 -1
- package/client/dist/assets/explore-C8NDHbob.js +0 -1
- package/client/dist/assets/explore-CWWgzQGR.js +0 -1
- package/client/dist/assets/explore-CcQXpdtS.js +0 -1
- package/client/dist/assets/explore-DgBACn39.js +0 -1
- package/client/dist/assets/explore-DsXAgnmJ.js +0 -1
- package/client/dist/assets/file-text-C0blZHLh.js +0 -1
- package/client/dist/assets/formatDistanceToNow-NjPHBLfB.js +0 -1
- package/client/dist/assets/getTimezoneOffsetInMilliseconds-vJ7qUoqN.js +0 -1
- package/client/dist/assets/git-branch-yf6LE1Bw.js +0 -1
- package/client/dist/assets/index-BgbCbIua.css +0 -2
- package/client/dist/assets/index-Ce4yZtKf.js +0 -83
- package/client/dist/assets/integrations-BkpRUbvp.js +0 -1
- package/client/dist/assets/integrations-Bo8qbJf4.js +0 -1
- package/client/dist/assets/integrations-CmSrKzZb.js +0 -1
- package/client/dist/assets/integrations-DGtq26Rr.js +0 -1
- package/client/dist/assets/integrations-De38GFnQ.js +0 -1
- package/client/dist/assets/integrations-Dw6zdtb-.js +0 -1
- package/client/dist/assets/integrations-Dwl9KQp0.js +0 -1
- package/client/dist/assets/integrations-Refg_d2I.js +0 -1
- package/client/dist/assets/jira-B6OYw4CJ.js +0 -1
- package/client/dist/assets/jira-BTF6RaOe.js +0 -1
- package/client/dist/assets/jira-CEetIB2q.js +0 -1
- package/client/dist/assets/jira-CIzsZLw5.js +0 -1
- package/client/dist/assets/jira-Daw9tmpI.js +0 -1
- package/client/dist/assets/jira-FXr7u2lh.js +0 -1
- package/client/dist/assets/jira-LaNQn7yl.js +0 -1
- package/client/dist/assets/jira-api-Cabj-H0J.js +0 -1
- package/client/dist/assets/job-time-BCL7wee9.js +0 -1
- package/client/dist/assets/jobs-ARwD85B9.js +0 -1
- package/client/dist/assets/jobs-BMF1w4WT.js +0 -1
- package/client/dist/assets/jobs-CBfzGLwm.js +0 -1
- package/client/dist/assets/jobs-CPjiluBY.js +0 -1
- package/client/dist/assets/jobs-CQQd58pY.js +0 -1
- package/client/dist/assets/jobs-De3EqaO0.js +0 -1
- package/client/dist/assets/jobs-Du9-Ei9a.js +0 -1
- package/client/dist/assets/jobs-qMHbnxwC.js +0 -1
- package/client/dist/assets/layers-BCLTgHXO.js +0 -1
- package/client/dist/assets/loader-circle-BqV9xYGf.js +0 -1
- package/client/dist/assets/loop-layout-CyXj9223.js +0 -7
- package/client/dist/assets/loops-B2PhQLKR.js +0 -1
- package/client/dist/assets/loops-BqbF46st.js +0 -1
- package/client/dist/assets/loops-CINnHbfI.js +0 -1
- package/client/dist/assets/loops-D-3XhH04.js +0 -1
- package/client/dist/assets/loops-DKkEEjZ_.js +0 -1
- package/client/dist/assets/loops-DzWR5-v6.js +0 -1
- package/client/dist/assets/loops-WyWDkhok.js +0 -1
- package/client/dist/assets/loops-scD5fIBf.js +0 -1
- package/client/dist/assets/mcp-6rMoZfEO.js +0 -1
- package/client/dist/assets/mcp-BD8sL5mP.js +0 -1
- package/client/dist/assets/mcp-BkcA3I5s.js +0 -1
- package/client/dist/assets/mcp-CCpSelOh.js +0 -1
- package/client/dist/assets/mcp-CUAN6ORK.js +0 -1
- package/client/dist/assets/mcp-CqbRxRTE.js +0 -1
- package/client/dist/assets/mcp-DP2YfVhO.js +0 -1
- package/client/dist/assets/mcp-DUVQamDz.js +0 -1
- package/client/dist/assets/narration-BEKMVxGm.js +0 -1
- package/client/dist/assets/narration-CjLwGKap.js +0 -1
- package/client/dist/assets/narration-DANWuGsW.js +0 -1
- package/client/dist/assets/narration-DGeEDWiT.js +0 -1
- package/client/dist/assets/narration-DJgpGwIP.js +0 -1
- package/client/dist/assets/narration-DbHnz0qV.js +0 -1
- package/client/dist/assets/narration-bZSsTZG8.js +0 -1
- package/client/dist/assets/narration-i6aKJKEc.js +0 -1
- package/client/dist/assets/nav--u7iPYlS.js +0 -1
- package/client/dist/assets/nav-C5Jgfaby.js +0 -1
- package/client/dist/assets/nav-CAna_Wpt.js +0 -1
- package/client/dist/assets/nav-CCLqeyHo.js +0 -1
- package/client/dist/assets/nav-Cf3c90Jk.js +0 -1
- package/client/dist/assets/nav-DMYQaQjR.js +0 -1
- package/client/dist/assets/nav-Df_PkZ9F.js +0 -1
- package/client/dist/assets/nav-VyNGBJwj.js +0 -1
- package/client/dist/assets/packet-8nn9RsU7.js +0 -1
- package/client/dist/assets/packet-B0H15elv.js +0 -1
- package/client/dist/assets/packet-BQvBgrwh.js +0 -1
- package/client/dist/assets/packet-BR7mO0-a.js +0 -1
- package/client/dist/assets/packet-BgcQ6q_K.js +0 -1
- package/client/dist/assets/packet-D2s92Jnn.js +0 -1
- package/client/dist/assets/packet-YbtcD1HS.js +0 -1
- package/client/dist/assets/packet-c0Qj_9eX.js +0 -1
- package/client/dist/assets/project-repositories-Cnnuj9Ia.js +0 -1
- package/client/dist/assets/rotate-ccw-DalJAQQX.js +0 -1
- package/client/dist/assets/settings-B1NV8Ow9.js +0 -1
- package/client/dist/assets/settings-BQ8XFZeE.js +0 -1
- package/client/dist/assets/settings-BRkxfBbO.js +0 -1
- package/client/dist/assets/settings-C_CcU1dP.js +0 -1
- package/client/dist/assets/settings-Cto9n0eL.js +0 -1
- package/client/dist/assets/settings-Pyw8uYtL.js +0 -1
- package/client/dist/assets/settings-b3HVCNNd.js +0 -1
- package/client/dist/assets/settings-hdive4u6.js +0 -1
- package/client/dist/assets/setup-Be485n2u.js +0 -1
- package/client/dist/assets/setup-CKGUxKr-.js +0 -1
- package/client/dist/assets/setup-Ck1Uwd7_.js +0 -1
- package/client/dist/assets/setup-Cm774a6v.js +0 -1
- package/client/dist/assets/setup-DIqMQpxt.js +0 -1
- package/client/dist/assets/setup-DfCsoNFL.js +0 -1
- package/client/dist/assets/setup-DkeE8mP0.js +0 -1
- package/client/dist/assets/setup-xVntVaz1.js +0 -1
- package/client/dist/assets/specs-Bqvtz2kz.js +0 -1
- package/client/dist/assets/specs-CKes-kz6.js +0 -1
- package/client/dist/assets/specs-CfXxPDNB.js +0 -1
- package/client/dist/assets/specs-CyF9HuTI.js +0 -1
- package/client/dist/assets/specs-DMj035Mt.js +0 -1
- package/client/dist/assets/specs-DfIdoU5L.js +0 -1
- package/client/dist/assets/specs-j5pGLQeU.js +0 -1
- package/client/dist/assets/specs-xW5pkkB7.js +0 -1
- package/client/dist/assets/spending-CQnrWiR3.js +0 -1
- package/client/dist/assets/square-D0JTbRSR.js +0 -1
- package/client/dist/assets/tauri-shell-DE6LfGPw.js +0 -2
- package/client/dist/assets/terminal-BAzpHtpY.js +0 -1
- package/client/dist/assets/terminal-C7dHeR3x.js +0 -1
- package/client/dist/assets/terminal-CMla5Qsz.js +0 -1
- package/client/dist/assets/terminal-CdNXH-n9.js +0 -1
- package/client/dist/assets/terminal-Cw5bZsmV.js +0 -1
- package/client/dist/assets/terminal-DFUP4eNv.js +0 -1
- package/client/dist/assets/terminal-DGqljeK_.js +0 -1
- package/client/dist/assets/terminal-cU70NodO.js +0 -1
- package/client/dist/assets/tickets--tiSOCcn.js +0 -1
- package/client/dist/assets/tickets-BUJ3DMWU.js +0 -1
- package/client/dist/assets/tickets-C1WNPODq.js +0 -1
- package/client/dist/assets/tickets-CDjhWmiE.js +0 -1
- package/client/dist/assets/tickets-CLgPC3uO.js +0 -1
- package/client/dist/assets/tickets-D41ZMQpf.js +0 -1
- package/client/dist/assets/tickets-DEaQC06P.js +0 -1
- package/client/dist/assets/tickets-kcMzbLCp.js +0 -1
- package/client/dist/assets/trash-D8zYUmTg.js +0 -1
- package/client/dist/assets/useDesktop-BjLT0_EE.js +0 -1
- package/client/dist/assets/useRuntimeRuns-C97qEqMg.js +0 -1
- package/client/dist/assets/useSharedWebSocket-Bj4LMp7b.js +0 -2
- package/client/dist/assets/utils-BC4DHlz2.js +0 -1
- package/docs/guide/en/getting-started/4-the-dashboard-tour.md +0 -48
- package/docs/guide/es/getting-started/4-the-dashboard-tour.md +0 -48
- package/server/dist/mobile/mobile-preview-channel.js +0 -179
- package/server/dist/mobile/mobile-preview.js +0 -366
- package/server/dist/modules/browser/domain/preview-origins.js +0 -117
- package/server/dist/modules/browser/runtime/preview-targets.js +0 -80
- /package/client/dist/assets/{atom-one-dark-B-oHczHB.css → DocView-B-oHczHB.css} +0 -0
- /package/docs/guide/de/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
- /package/docs/guide/en/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
- /package/docs/guide/es/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
- /package/docs/guide/fr/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
- /package/docs/guide/it/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
- /package/docs/guide/ja/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
- /package/docs/guide/pt/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
- /package/docs/guide/zh/getting-started/{3-adding-your-first-project.md → 4-adding-your-first-project.md} +0 -0
|
@@ -0,0 +1,1089 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.systemClock = exports.FLOW_FAILURE_RETURN_TURN_TEXT = exports.FLOW_RETURN_TURN_TEXT = void 0;
|
|
37
|
+
exports.deliveryFailureOf = deliveryFailureOf;
|
|
38
|
+
exports.isCrashedFlowDelivery = isCrashedFlowDelivery;
|
|
39
|
+
exports.railOfTicket = railOfTicket;
|
|
40
|
+
exports.createFlowTickets = createFlowTickets;
|
|
41
|
+
exports.launchOptionsOf = launchOptionsOf;
|
|
42
|
+
exports.createFlowWorktrees = createFlowWorktrees;
|
|
43
|
+
exports.createFlowPorts = createFlowPorts;
|
|
44
|
+
exports.createFlowHandOffAuthority = createFlowHandOffAuthority;
|
|
45
|
+
exports.createFlowTurnContext = createFlowTurnContext;
|
|
46
|
+
exports.flowConversationSummary = flowConversationSummary;
|
|
47
|
+
exports.changeNameFromArchive = changeNameFromArchive;
|
|
48
|
+
exports.readDerivedChange = readDerivedChange;
|
|
49
|
+
exports.createFlowPublication = createFlowPublication;
|
|
50
|
+
exports.startFlowSettlementScheduler = startFlowSettlementScheduler;
|
|
51
|
+
/**
|
|
52
|
+
* Production bindings of the Flow ports onto the other capabilities: delivery
|
|
53
|
+
* (worktree machinery, rail launch), specs (placeholder ticket), missions/Core
|
|
54
|
+
* agent sessions, accounting and the project's WebSocket. Bound to ONE project
|
|
55
|
+
* context at composition (project-registry); the application never sees them.
|
|
56
|
+
*/
|
|
57
|
+
const fs = __importStar(require("node:fs"));
|
|
58
|
+
const path = __importStar(require("node:path"));
|
|
59
|
+
const ids_1 = require("../../../ids");
|
|
60
|
+
const internal_api_1 = require("../../../internal-api");
|
|
61
|
+
const desktop_db_1 = require("../../../desktop-db");
|
|
62
|
+
const repo_lock_1 = require("../../../repo-lock");
|
|
63
|
+
const worktree_manager_1 = require("../../../worktree-manager");
|
|
64
|
+
const worktree_overlay_1 = require("../../../worktree-overlay");
|
|
65
|
+
const worktree_node_modules_1 = require("../../../worktree-node-modules");
|
|
66
|
+
const agent_store_1 = require("../../agents/runtime/agent-store");
|
|
67
|
+
const project_repositories_1 = require("../../../project-repositories");
|
|
68
|
+
const workspace_resolution_1 = require("../../../workspace-resolution");
|
|
69
|
+
const jira_db_1 = require("../../../jira/jira-db");
|
|
70
|
+
const providers_1 = require("../../../providers");
|
|
71
|
+
const provider_selection_1 = require("../../../provider-selection");
|
|
72
|
+
const runtime_1 = require("../../../providers/runtime");
|
|
73
|
+
const process_admission_1 = require("../../../process-admission");
|
|
74
|
+
const project_router_helpers_1 = require("../../../project-router-helpers");
|
|
75
|
+
const agent_runtime_controls_router_1 = require("../../agent-runtime/runtime/agent-runtime-controls-router");
|
|
76
|
+
const delivery_evidence_1 = require("../../delivery/runtime/delivery-evidence");
|
|
77
|
+
const flow_review_outcome_1 = require("../../delivery/runtime/flow-review-outcome");
|
|
78
|
+
const rail_pr_store_1 = require("../../delivery/runtime/rail-pr-store");
|
|
79
|
+
const flow_worktree_return_1 = require("../../delivery/runtime/flow-worktree-return");
|
|
80
|
+
const spec_generation_1 = require("../../specs/runtime/spec-generation");
|
|
81
|
+
const isolated_worktree_1 = require("../../delivery/runtime/isolated-worktree");
|
|
82
|
+
const flow_worktree_handoff_1 = require("../../delivery/runtime/flow-worktree-handoff");
|
|
83
|
+
const rails_store_1 = require("../../delivery/runtime/rails-store");
|
|
84
|
+
const agent_flow_prompt_1 = require("../../missions/runtime/agent-flow-prompt");
|
|
85
|
+
const agent_failure_briefing_1 = require("../../missions/runtime/agent-failure-briefing");
|
|
86
|
+
const flow_turn_context_1 = require("../../missions/runtime/flow-turn-context");
|
|
87
|
+
const ticket_store_1 = require("../../specs/runtime/ticket-store");
|
|
88
|
+
const spec_addenda_1 = require("../../specs/runtime/spec-addenda");
|
|
89
|
+
const spec_addenda_core_1 = require("../../specs/runtime/spec-addenda-core");
|
|
90
|
+
const rails_store_2 = require("../../delivery/runtime/rails-store");
|
|
91
|
+
const rail_pr_store_2 = require("../../delivery/runtime/rail-pr-store");
|
|
92
|
+
const domain_1 = require("../domain");
|
|
93
|
+
/** The automatic turn after Back to Flow (the briefing itself rides the Flow turn). */
|
|
94
|
+
exports.FLOW_RETURN_TURN_TEXT = 'Back to Flow: the Flow → Spec run came back with the findings above. In at most 2 short lines say what you will fix, then start fixing it in this worktree. If a finding leaves a genuine decision to me (for example removing behaviour nobody asked for versus recording it as a requirement), offer it as an `options` block before editing and wait for my answer.';
|
|
95
|
+
/** The automatic turn after a Flow → Spec run failed outright and came back on its own. */
|
|
96
|
+
exports.FLOW_FAILURE_RETURN_TURN_TEXT = 'Back to Flow: the Flow → Spec run failed with the error above and the worktree came back to this Flow intact. In at most 2 short lines tell me what failed in plain words and what you will do. If the cause is in this worktree, fix it here; if it is outside it (a tool version, the environment, credentials), tell me exactly what to change instead of working around it.';
|
|
97
|
+
/** Status codes of a Flow → Spec run that stopped for review reasons (never a crash). */
|
|
98
|
+
const FLOW_REVIEW_STATUS_CODES = new Set(['review_changes_requested', 'returned_to_flow']);
|
|
99
|
+
/** The delivery codes of a Flow → Spec run that failed outright (null for a review outcome). */
|
|
100
|
+
function deliveryFailureOf(snap) {
|
|
101
|
+
if (snap.flowReview)
|
|
102
|
+
return null;
|
|
103
|
+
// After the return, the delivery's own codes say `returned_to_flow`: the crash codes are gone.
|
|
104
|
+
const returned = snap.statusCode === 'returned_to_flow';
|
|
105
|
+
return {
|
|
106
|
+
stepId: null,
|
|
107
|
+
cause: null,
|
|
108
|
+
statusCode: returned ? null : snap.statusCode ?? null,
|
|
109
|
+
failureCode: snap.units.find((unit) => unit.failureCode)?.failureCode ?? null,
|
|
110
|
+
statusDetail: returned ? null : snap.statusDetail ?? null,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** Whether a Flow → Spec delivery failed outright and is idle (the automatic return may take its worktree). */
|
|
114
|
+
function isCrashedFlowDelivery(snap) {
|
|
115
|
+
return snap.loopId === flow_review_outcome_1.FLOW_SPEC_DELIVERY_LOOP_ID
|
|
116
|
+
&& snap.decision === 'implementation_failed'
|
|
117
|
+
&& !snap.flowReview
|
|
118
|
+
&& !FLOW_REVIEW_STATUS_CODES.has(snap.statusCode ?? '')
|
|
119
|
+
&& !snap.operation;
|
|
120
|
+
}
|
|
121
|
+
exports.systemClock = { now: () => new Date().toISOString() };
|
|
122
|
+
function canonical(value) {
|
|
123
|
+
try {
|
|
124
|
+
return fs.realpathSync.native(value);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return path.resolve(value);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function isInside(child, parent) {
|
|
131
|
+
const relative = path.relative(canonical(parent), canonical(child));
|
|
132
|
+
return relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
133
|
+
}
|
|
134
|
+
/** The rail of a spec from the project's rails and their live deliveries. */
|
|
135
|
+
function railOfTicket(db) {
|
|
136
|
+
return (ticketId) => {
|
|
137
|
+
const rail = (0, rails_store_2.getRails)(db).find((candidate) => candidate.ticketIds.includes(ticketId));
|
|
138
|
+
if (!rail)
|
|
139
|
+
return null;
|
|
140
|
+
return { railIndex: rail.railIndex, running: Boolean((0, rail_pr_store_2.getActivePrDeliveryByRail)(db, rail.railIndex)) };
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const CLOSED_SPEC_STATUSES = new Set(['done', 'cancelled']);
|
|
144
|
+
/** The open addenda of a spec, as the first Flow turn lists them. */
|
|
145
|
+
function renderOpenAddenda(ticket) {
|
|
146
|
+
const open = (0, spec_addenda_core_1.openAddenda)(ticket.addenda);
|
|
147
|
+
if (!open.length)
|
|
148
|
+
return '';
|
|
149
|
+
return ['## Open addenda (iterations requested on this spec)', '', ...open.slice(0, 20).map((addendum, index) => `${index + 1}. [${addendum.kind}] ${addendum.title}${addendum.body.trim() ? `\n ${addendum.body.trim().slice(0, 600).replace(/\n/g, '\n ')}` : ''}`)].join('\n');
|
|
150
|
+
}
|
|
151
|
+
function snapshotOf(ticket) {
|
|
152
|
+
return {
|
|
153
|
+
id: ticket.id,
|
|
154
|
+
title: ticket.title,
|
|
155
|
+
description: ticket.description ?? '',
|
|
156
|
+
status: ticket.status,
|
|
157
|
+
nonGoals: Array.isArray(ticket.nonGoals) ? ticket.nonGoals.filter((goal) => typeof goal === 'string') : [],
|
|
158
|
+
repositoryIds: Array.isArray(ticket.repositoryIds) ? ticket.repositoryIds.filter((id) => typeof id === 'string') : [],
|
|
159
|
+
addenda: renderOpenAddenda(ticket),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/** Why this spec cannot start a Flow now (null ⇒ it can). `flowId`: the Flow re-checking its own adoption. */
|
|
163
|
+
function existingSpecBlocker(ticket, railOf, flowId) {
|
|
164
|
+
if (!ticket)
|
|
165
|
+
return { code: 'spec_not_found', message: 'This spec no longer exists' };
|
|
166
|
+
if (CLOSED_SPEC_STATUSES.has(ticket.status))
|
|
167
|
+
return { code: 'spec_closed', message: `Spec #${ticket.id} is ${ticket.status === 'done' ? 'done' : 'cancelled'}; reopen it to work on it in Flow` };
|
|
168
|
+
if ((0, ticket_store_1.isFlowHeldTicket)(ticket) && ticket.metadata?.flow?.flowId !== flowId)
|
|
169
|
+
return { code: 'spec_in_flow', message: `Spec #${ticket.id} is already in Flow` };
|
|
170
|
+
const rail = railOf?.(ticket.id) ?? null;
|
|
171
|
+
if (rail?.running)
|
|
172
|
+
return { code: 'spec_running', message: `Spec #${ticket.id} is running on Rail ${rail.railIndex + 1}` };
|
|
173
|
+
if (rail)
|
|
174
|
+
return { code: 'spec_on_rail', message: `Spec #${ticket.id} is on Rail ${rail.railIndex + 1}; take it off the rail to start it in Flow` };
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
function createFlowTickets(ctx, clock = exports.systemClock, railOf) {
|
|
178
|
+
const file = () => (0, spec_addenda_1.ticketStorePathForProject)(ctx.project);
|
|
179
|
+
const announce = (revision, message) => {
|
|
180
|
+
try {
|
|
181
|
+
ctx.ticketWatcher.notifyDesktopWrite(revision);
|
|
182
|
+
}
|
|
183
|
+
catch { /* watcher is advisory */ }
|
|
184
|
+
try {
|
|
185
|
+
ctx.broadcast(message);
|
|
186
|
+
}
|
|
187
|
+
catch { /* clients rehydrate */ }
|
|
188
|
+
};
|
|
189
|
+
return {
|
|
190
|
+
createPlaceholder(input) {
|
|
191
|
+
let created;
|
|
192
|
+
// The non-promoting path: a plain local spec write. Jira sees nothing
|
|
193
|
+
// until the Flow -> Spec rail settles (isFlowHeldTicket guards promotion).
|
|
194
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
195
|
+
const id = s.next_id++;
|
|
196
|
+
created = {
|
|
197
|
+
id,
|
|
198
|
+
title: input.title,
|
|
199
|
+
description: input.description,
|
|
200
|
+
status: 'in_progress',
|
|
201
|
+
priority: 'medium',
|
|
202
|
+
labels: [],
|
|
203
|
+
assignee: null,
|
|
204
|
+
prerequisites: [],
|
|
205
|
+
metadata: {
|
|
206
|
+
flow: { conversationId: input.conversationId, flowId: input.flowId, worktreeId: input.flowId, startedAt: input.startedAt, state: 'active', chosenMode: 'flow' },
|
|
207
|
+
},
|
|
208
|
+
// A Flow in a non-primary repository: the spec targets exactly it, so
|
|
209
|
+
// the hand-off and every later launch run in that repository.
|
|
210
|
+
...(input.repositoryIds?.length ? { repositoryIds: [...input.repositoryIds] } : {}),
|
|
211
|
+
comments: [],
|
|
212
|
+
origin_conversation_id: null,
|
|
213
|
+
is_epic: false,
|
|
214
|
+
parent_epic_id: null,
|
|
215
|
+
execution_order: null,
|
|
216
|
+
short_summary: null,
|
|
217
|
+
created_at: input.startedAt,
|
|
218
|
+
updated_at: input.startedAt,
|
|
219
|
+
created_by: 'flow',
|
|
220
|
+
source: 'flow',
|
|
221
|
+
};
|
|
222
|
+
s.tickets[String(id)] = created;
|
|
223
|
+
});
|
|
224
|
+
announce(store.revision, { type: 'ticket_created', ticket: created, projectId: ctx.project.id, timestamp: clock.now() });
|
|
225
|
+
return created.id;
|
|
226
|
+
},
|
|
227
|
+
setFlowState(ticketId, state) {
|
|
228
|
+
let updated;
|
|
229
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
230
|
+
const ticket = s.tickets[String(ticketId)];
|
|
231
|
+
if (!ticket?.metadata?.flow || ticket.metadata.flow.state === state)
|
|
232
|
+
return;
|
|
233
|
+
ticket.metadata.flow = { ...ticket.metadata.flow, state };
|
|
234
|
+
ticket.updated_at = clock.now();
|
|
235
|
+
updated = ticket;
|
|
236
|
+
});
|
|
237
|
+
if (updated)
|
|
238
|
+
announce(store.revision, { type: 'ticket_updated', ticket: updated, projectId: ctx.project.id, timestamp: clock.now() });
|
|
239
|
+
},
|
|
240
|
+
deletePlaceholder(ticketId) {
|
|
241
|
+
let deleted = false;
|
|
242
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
243
|
+
const ticket = s.tickets[String(ticketId)];
|
|
244
|
+
// Only a Flow placeholder is ever deleted by Flow: never the person's own spec.
|
|
245
|
+
if (!ticket?.metadata?.flow || ticket.metadata.flow.origin === 'existing')
|
|
246
|
+
return;
|
|
247
|
+
delete s.tickets[String(ticketId)];
|
|
248
|
+
deleted = true;
|
|
249
|
+
});
|
|
250
|
+
if (deleted)
|
|
251
|
+
announce(store.revision, { type: 'ticket_deleted', ticketId, projectId: ctx.project.id, timestamp: clock.now() });
|
|
252
|
+
},
|
|
253
|
+
markDelivered(ticketId, input) {
|
|
254
|
+
let updated;
|
|
255
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
256
|
+
const ticket = s.tickets[String(ticketId)];
|
|
257
|
+
if (!ticket?.metadata?.flow)
|
|
258
|
+
return;
|
|
259
|
+
const changeName = input.openspecChangeName ?? (typeof ticket.metadata.openspecChangeName === 'string' ? ticket.metadata.openspecChangeName : null);
|
|
260
|
+
const unchanged = ticket.metadata.flow.state === 'delivered' && ticket.metadata.openspecChangeName === (changeName ?? undefined)
|
|
261
|
+
&& ticket.status !== 'in_progress' && ticket.status !== 'todo';
|
|
262
|
+
if (unchanged)
|
|
263
|
+
return;
|
|
264
|
+
ticket.metadata = { ...ticket.metadata, flow: { ...ticket.metadata.flow, state: 'delivered' }, ...(changeName ? { openspecChangeName: changeName } : {}) };
|
|
265
|
+
// The delivery is on review; never pull back a ticket that moved on (done, cancelled).
|
|
266
|
+
if (ticket.status === 'in_progress' || ticket.status === 'todo')
|
|
267
|
+
ticket.status = 'on_review';
|
|
268
|
+
ticket.updated_at = clock.now();
|
|
269
|
+
updated = ticket;
|
|
270
|
+
});
|
|
271
|
+
if (updated)
|
|
272
|
+
announce(store.revision, { type: 'ticket_updated', ticket: updated, projectId: ctx.project.id, timestamp: clock.now() });
|
|
273
|
+
},
|
|
274
|
+
read(ticketId) {
|
|
275
|
+
const ticket = (0, ticket_store_1.readStore)(file()).tickets[String(ticketId)];
|
|
276
|
+
if (!ticket)
|
|
277
|
+
return null;
|
|
278
|
+
const spec = snapshotOf(ticket);
|
|
279
|
+
return { title: spec.title, description: spec.description, status: spec.status, repositoryIds: [...spec.repositoryIds], nonGoals: [...spec.nonGoals] };
|
|
280
|
+
},
|
|
281
|
+
inspectExisting(ticketId) {
|
|
282
|
+
const ticket = (0, ticket_store_1.readStore)(file()).tickets[String(ticketId)];
|
|
283
|
+
return { spec: ticket ? snapshotOf(ticket) : null, blocker: existingSpecBlocker(ticket, railOf) };
|
|
284
|
+
},
|
|
285
|
+
adoptExisting(input) {
|
|
286
|
+
let adopted;
|
|
287
|
+
let blocker = null;
|
|
288
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
289
|
+
const ticket = s.tickets[String(input.ticketId)];
|
|
290
|
+
blocker = existingSpecBlocker(ticket, railOf, input.flowId);
|
|
291
|
+
if (blocker || !ticket)
|
|
292
|
+
return;
|
|
293
|
+
const current = ticket.metadata?.flow;
|
|
294
|
+
// Idempotent: this Flow already holds the spec.
|
|
295
|
+
if (current?.flowId === input.flowId && current.origin === 'existing') {
|
|
296
|
+
adopted = ticket;
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const previousStatus = ticket.status;
|
|
300
|
+
ticket.metadata = {
|
|
301
|
+
...ticket.metadata,
|
|
302
|
+
flow: {
|
|
303
|
+
conversationId: input.conversationId, flowId: input.flowId, worktreeId: input.flowId, startedAt: input.startedAt,
|
|
304
|
+
state: 'active', chosenMode: 'flow', origin: 'existing', previousStatus,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
// The same "in progress, In Flow" a placeholder spec shows.
|
|
308
|
+
ticket.status = 'in_progress';
|
|
309
|
+
ticket.updated_at = clock.now();
|
|
310
|
+
adopted = ticket;
|
|
311
|
+
});
|
|
312
|
+
if (blocker) {
|
|
313
|
+
const reason = blocker;
|
|
314
|
+
if (reason.code === 'spec_not_found')
|
|
315
|
+
throw new domain_1.FlowValidationError(reason.code, reason.message);
|
|
316
|
+
throw new domain_1.FlowConflictError(reason.code, reason.message);
|
|
317
|
+
}
|
|
318
|
+
announce(store.revision, { type: 'ticket_updated', ticket: adopted, projectId: ctx.project.id, timestamp: clock.now() });
|
|
319
|
+
return snapshotOf(adopted);
|
|
320
|
+
},
|
|
321
|
+
restoreExisting(ticketId, flowId) {
|
|
322
|
+
let updated;
|
|
323
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
324
|
+
const ticket = s.tickets[String(ticketId)];
|
|
325
|
+
const flow = ticket?.metadata?.flow;
|
|
326
|
+
// Only the spec THIS Flow holds; an existing spec is never deleted.
|
|
327
|
+
if (!ticket || !flow || flow.flowId !== flowId || flow.origin !== 'existing')
|
|
328
|
+
return;
|
|
329
|
+
const { flow: _held, ...metadata } = ticket.metadata ?? {};
|
|
330
|
+
ticket.metadata = metadata;
|
|
331
|
+
// Its own status comes back unless it moved on meanwhile (done, cancelled…).
|
|
332
|
+
if (ticket.status === 'in_progress' && flow.previousStatus)
|
|
333
|
+
ticket.status = flow.previousStatus;
|
|
334
|
+
ticket.updated_at = clock.now();
|
|
335
|
+
updated = ticket;
|
|
336
|
+
});
|
|
337
|
+
if (updated)
|
|
338
|
+
announce(store.revision, { type: 'ticket_updated', ticket: updated, projectId: ctx.project.id, timestamp: clock.now() });
|
|
339
|
+
},
|
|
340
|
+
preserveOriginal(ticketId, flowId) {
|
|
341
|
+
let updated;
|
|
342
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
343
|
+
const ticket = s.tickets[String(ticketId)];
|
|
344
|
+
const flow = ticket?.metadata?.flow;
|
|
345
|
+
if (!ticket || !flow || flow.flowId !== flowId)
|
|
346
|
+
return;
|
|
347
|
+
const comments = Array.isArray(ticket.comments) ? ticket.comments : [];
|
|
348
|
+
// Idempotent: the original was already kept for this Flow.
|
|
349
|
+
if (typeof flow.originalCommentId === 'number' && comments.some((comment) => comment.id === flow.originalCommentId))
|
|
350
|
+
return;
|
|
351
|
+
const id = comments.reduce((max, comment) => Math.max(max, typeof comment.id === 'number' ? comment.id : 0), 0) + 1;
|
|
352
|
+
const now = clock.now();
|
|
353
|
+
ticket.comments = [...comments, {
|
|
354
|
+
id,
|
|
355
|
+
body: (0, domain_1.buildOriginalSpecComment)({ title: ticket.title, description: ticket.description ?? '', nonGoals: Array.isArray(ticket.nonGoals) ? ticket.nonGoals : [], flowId }),
|
|
356
|
+
created_at: now,
|
|
357
|
+
created_by: 'flow',
|
|
358
|
+
}];
|
|
359
|
+
ticket.metadata = { ...ticket.metadata, flow: { ...flow, originalCommentId: id } };
|
|
360
|
+
ticket.updated_at = now;
|
|
361
|
+
updated = ticket;
|
|
362
|
+
});
|
|
363
|
+
if (updated)
|
|
364
|
+
announce(store.revision, { type: 'ticket_updated', ticket: updated, projectId: ctx.project.id, timestamp: clock.now() });
|
|
365
|
+
},
|
|
366
|
+
applyAddenda(ticketId, flowId, causalId) {
|
|
367
|
+
// Read-only probe first: a spec without live addenda (or a replay) never rewrites the store.
|
|
368
|
+
const probe = (0, ticket_store_1.readStore)(file()).tickets[String(ticketId)];
|
|
369
|
+
if (probe?.metadata?.flow?.flowId !== flowId || !(0, spec_addenda_core_1.readSpecAddenda)(probe.addenda).some((a) => a.status === 'open' || a.status === 'in_flight'))
|
|
370
|
+
return;
|
|
371
|
+
let updated;
|
|
372
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
373
|
+
const ticket = s.tickets[String(ticketId)];
|
|
374
|
+
// Only the spec this Flow holds (the label stays through settlement).
|
|
375
|
+
if (!ticket || ticket.metadata?.flow?.flowId !== flowId)
|
|
376
|
+
return;
|
|
377
|
+
if ((0, spec_addenda_1.applyFlowSpecAddenda)(s, ticketId, causalId, clock.now()))
|
|
378
|
+
updated = ticket;
|
|
379
|
+
});
|
|
380
|
+
if (updated)
|
|
381
|
+
announce(store.revision, { type: 'ticket_updated', ticket: updated, projectId: ctx.project.id, timestamp: clock.now() });
|
|
382
|
+
},
|
|
383
|
+
reopen(ticketId) {
|
|
384
|
+
let updated;
|
|
385
|
+
const store = (0, ticket_store_1.mutateStore)(file(), (s) => {
|
|
386
|
+
const ticket = s.tickets[String(ticketId)];
|
|
387
|
+
if (!ticket?.metadata?.flow)
|
|
388
|
+
return;
|
|
389
|
+
// A failed run moved the spec back to todo; Back to Flow works on it again.
|
|
390
|
+
// Never pull back a ticket that moved on (done, cancelled).
|
|
391
|
+
const status = ticket.status === 'todo' || ticket.status === 'on_review' ? 'in_progress' : ticket.status;
|
|
392
|
+
if (status === ticket.status && ticket.metadata.flow.state === 'paused')
|
|
393
|
+
return;
|
|
394
|
+
ticket.status = status;
|
|
395
|
+
ticket.metadata = { ...ticket.metadata, flow: { ...ticket.metadata.flow, state: 'paused' } };
|
|
396
|
+
ticket.updated_at = clock.now();
|
|
397
|
+
updated = ticket;
|
|
398
|
+
});
|
|
399
|
+
if (updated)
|
|
400
|
+
announce(store.revision, { type: 'ticket_updated', ticket: updated, projectId: ctx.project.id, timestamp: clock.now() });
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
/** The engine choices a stopped Flow → Spec launch used (Relaunch repeats them). */
|
|
405
|
+
function launchOptionsOf(raw) {
|
|
406
|
+
let config = {};
|
|
407
|
+
try {
|
|
408
|
+
const parsed = raw ? JSON.parse(raw) : null;
|
|
409
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
410
|
+
config = parsed;
|
|
411
|
+
}
|
|
412
|
+
catch { /* defaults */ }
|
|
413
|
+
const text = (value) => typeof value === 'string' && value.trim() && value.length <= 200 ? value.trim() : undefined;
|
|
414
|
+
const loopId = text(config.loopId), aiEngine = text(config.aiEngine), model = text(config.model), reasoningEffort = text(config.reasoning_effort ?? config.reasoningEffort);
|
|
415
|
+
return { ...(loopId ? { loopId } : {}), ...(aiEngine ? { aiEngine } : {}), ...(model ? { model } : {}), ...(reasoningEffort ? { reasoningEffort } : {}) };
|
|
416
|
+
}
|
|
417
|
+
// ─── Worktree reservation (delivery's single machinery) ───────────────────────
|
|
418
|
+
function readOverlayManifest(worktreePath) {
|
|
419
|
+
try {
|
|
420
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(worktreePath, worktree_overlay_1.OVERLAY_MANIFEST), 'utf8'));
|
|
421
|
+
return Array.isArray(parsed.paths) ? parsed.paths.filter((entry) => typeof entry === 'string') : [];
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
return [];
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async function forkPoint(git, worktreePath, repo) {
|
|
428
|
+
const branch = await git.run(['symbolic-ref', '--quiet', '--short', 'HEAD'], repo);
|
|
429
|
+
if (branch.code !== 0 || !branch.stdout.trim())
|
|
430
|
+
return null;
|
|
431
|
+
const base = await git.run(['merge-base', 'HEAD', branch.stdout.trim()], worktreePath);
|
|
432
|
+
const sha = base.code === 0 ? base.stdout.trim() : '';
|
|
433
|
+
return /^[0-9a-f]{40,64}$/i.test(sha) ? sha : null;
|
|
434
|
+
}
|
|
435
|
+
function excludedFromDiff(file, overlay) {
|
|
436
|
+
if (file === worktree_overlay_1.OVERLAY_MANIFEST)
|
|
437
|
+
return true;
|
|
438
|
+
if (file === 'node_modules' || file.startsWith('node_modules/') || file.includes('/node_modules/'))
|
|
439
|
+
return true;
|
|
440
|
+
const roots = [...worktree_manager_1.PR_NEVER_STAGE_PATHSPEC_ROOTS, ...overlay];
|
|
441
|
+
return roots.some((root) => file === root || file.startsWith(`${root.replace(/\/$/, '')}/`));
|
|
442
|
+
}
|
|
443
|
+
const STATUS = { A: 'added', M: 'modified', D: 'deleted', R: 'renamed', T: 'modified', C: 'added' };
|
|
444
|
+
function createFlowWorktrees(ctx, deps = { providerFor: () => 'claude' }) {
|
|
445
|
+
const git = deps.git ?? worktree_manager_1.defaultGitRunner;
|
|
446
|
+
// The Flow's repository: the project root for the primary (unchanged), or a
|
|
447
|
+
// non-primary Git member's own checkout and per-repository mount root.
|
|
448
|
+
const repositoryTarget = (repositoryId) => {
|
|
449
|
+
try {
|
|
450
|
+
return (0, isolated_worktree_1.isolatedRepositoryTarget)(ctx.project, repositoryId);
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
throw new domain_1.FlowConflictError('flow_repository_missing', `The Flow's repository is no longer usable: ${error instanceof Error ? error.message : String(error)}`);
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
const flowRoot = (flowId, repositoryId) => path.join(repositoryTarget(repositoryId).worktreesRoot, flowId);
|
|
457
|
+
return {
|
|
458
|
+
async reserve(input) {
|
|
459
|
+
let prepared;
|
|
460
|
+
repositoryTarget(input.repositoryId);
|
|
461
|
+
try {
|
|
462
|
+
prepared = await (deps.prepare ?? isolated_worktree_1.prepareIsolatedWorktree)({
|
|
463
|
+
ctx: ctx,
|
|
464
|
+
ticketId: input.ticketId,
|
|
465
|
+
provider: deps.providerFor(input.conversationId),
|
|
466
|
+
// The Flow id is the mount id: the worktree path is provably Flow-owned.
|
|
467
|
+
runId: input.flowId,
|
|
468
|
+
...(input.repositoryId ? { repositoryId: input.repositoryId } : {}),
|
|
469
|
+
}, { git });
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
if (error instanceof isolated_worktree_1.RepositoryHasNoCommitsError)
|
|
473
|
+
throw new domain_1.FlowConflictError(error.code, error.message);
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
// The Flow's base is the reservation SHA; never leave it unknown (a null
|
|
477
|
+
// base would measure the diff against HEAD and lose committed work).
|
|
478
|
+
return { branch: prepared.branch, worktreePath: prepared.worktreePath, baseSha: prepared.baseSha ?? prepared.initialSha, headSha: prepared.initialSha };
|
|
479
|
+
},
|
|
480
|
+
async release(input) {
|
|
481
|
+
const repo = repositoryTarget(input.repositoryId).path;
|
|
482
|
+
const root = flowRoot(input.flowId, input.repositoryId);
|
|
483
|
+
const target = input.worktreePath ?? (0, worktree_manager_1.worktreePath)(root, input.ticketId);
|
|
484
|
+
// Never remove anything outside the Flow's own mount root.
|
|
485
|
+
if (!isInside(target, root))
|
|
486
|
+
throw new Error(`Refusing to remove ${target}: it is not a Flow-owned worktree`);
|
|
487
|
+
await (0, repo_lock_1.withRepoLock)(repo, async () => {
|
|
488
|
+
const mounted = (await (0, worktree_manager_1.listWorktrees)(git, repo)).some((entry) => canonical(entry) === canonical(target));
|
|
489
|
+
let branch = input.branch;
|
|
490
|
+
if (mounted && !branch) {
|
|
491
|
+
const head = await git.run(['rev-parse', '--abbrev-ref', 'HEAD'], target);
|
|
492
|
+
branch = head.code === 0 && head.stdout.trim() !== 'HEAD' ? head.stdout.trim() : null;
|
|
493
|
+
}
|
|
494
|
+
if (mounted) {
|
|
495
|
+
await (0, worktree_manager_1.removeWorktree)(git, { repoDir: repo, worktreePath: target, branch: branch ?? '', deleteBranch: Boolean(branch), force: true });
|
|
496
|
+
}
|
|
497
|
+
else if (branch) {
|
|
498
|
+
// The mount is gone but the Flow-created branch may remain.
|
|
499
|
+
await git.run(['branch', '-D', branch], repo).catch(() => undefined);
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
503
|
+
}
|
|
504
|
+
catch { /* best effort: empty mount root */ }
|
|
505
|
+
});
|
|
506
|
+
},
|
|
507
|
+
async freeze(input) {
|
|
508
|
+
const { path: repo, primary } = repositoryTarget(input.repositoryId);
|
|
509
|
+
return (0, repo_lock_1.withRepoLock)(repo, async () => {
|
|
510
|
+
// Same never-commit set the rail uses: overlay links and warm node_modules.
|
|
511
|
+
const sources = (0, isolated_worktree_1.resolveOverlaySources)({ slug: ctx.project.slug, baseRepo: repo, provider: deps.providerFor(input.conversationId) }, primary ? undefined : () => (0, workspace_resolution_1.resolveProjectExecution)(ctx.project));
|
|
512
|
+
const overlay = (0, worktree_overlay_1.applyWorktreeOverlay)({ worktreePath: input.worktreePath, ...sources });
|
|
513
|
+
const warm = (0, worktree_node_modules_1.linkNodeModulesIntoWorktree)(repo, input.worktreePath);
|
|
514
|
+
const excludes = [...new Set([...overlay.createdPaths, ...(warm.authenticated ?? warm.linked ?? [])])];
|
|
515
|
+
const title = ctx.getTicketSpec(input.ticketId)?.title ?? `Flow ${input.flowId}`;
|
|
516
|
+
// The Flow's own derived change (a returned Flow → Spec run left it
|
|
517
|
+
// active) is intended; any other new active change still blocks.
|
|
518
|
+
// Everything in a Flow worktree is the Flow's own work. A single active
|
|
519
|
+
// change the Flow does not know yet (an earlier Flow -> Spec run named
|
|
520
|
+
// it differently) is adopted as its derived change; several are
|
|
521
|
+
// ambiguous and still block, with a message the agent can act on.
|
|
522
|
+
const unknown = await unknownActiveChanges(git, input.worktreePath, input.baseSha, input.allowedChanges);
|
|
523
|
+
if (unknown.length > 1) {
|
|
524
|
+
throw new domain_1.FlowConflictError('flow_freeze_failed', `This Flow has ${unknown.length} open spec changes (${unknown.join(', ')}); keep one and archive or remove the others, then hand off again`, input.flowId);
|
|
525
|
+
}
|
|
526
|
+
const adoptedChange = unknown.length === 1 && !input.allowedChanges.some((name) => fs.existsSync(path.join(input.worktreePath, 'openspec', 'changes', name))) ? unknown[0] : undefined;
|
|
527
|
+
if (unknown.length === 1 && !adoptedChange) {
|
|
528
|
+
throw new domain_1.FlowConflictError('flow_freeze_failed', `This Flow has two open spec changes (${[...input.allowedChanges.filter((name) => fs.existsSync(path.join(input.worktreePath, 'openspec', 'changes', name))), unknown[0]].join(', ')}); keep one and archive or remove the other, then hand off again`, input.flowId);
|
|
529
|
+
}
|
|
530
|
+
const allowed = adoptedChange ? [...input.allowedChanges, adoptedChange] : input.allowedChanges;
|
|
531
|
+
const commit = await (0, worktree_manager_1.commitWorktreeAndVerify)(git, input.worktreePath, `Flow #${input.ticketId}: ${title}`, excludes, input.baseSha ?? undefined, { allowedActiveChanges: allowed });
|
|
532
|
+
if (!commit.clean) {
|
|
533
|
+
throw new domain_1.FlowConflictError('flow_freeze_failed', `The Flow worktree could not be committed: ${commit.error ?? commit.dirty.slice(0, 5).join(', ')}`, input.flowId);
|
|
534
|
+
}
|
|
535
|
+
const headSha = await (0, isolated_worktree_1.readHeadSha)(git, input.worktreePath);
|
|
536
|
+
if (!headSha)
|
|
537
|
+
throw new domain_1.FlowConflictError('flow_freeze_failed', 'The Flow worktree HEAD could not be verified', input.flowId);
|
|
538
|
+
return adoptedChange ? { headSha, adoptedChange } : { headSha };
|
|
539
|
+
});
|
|
540
|
+
},
|
|
541
|
+
exists(worktreePath) {
|
|
542
|
+
return fs.existsSync(path.join(worktreePath, '.git'));
|
|
543
|
+
},
|
|
544
|
+
async diff(input) {
|
|
545
|
+
const overlay = readOverlayManifest(input.worktreePath);
|
|
546
|
+
// Legacy sessions without a recorded base: the fork point from the
|
|
547
|
+
// project's checked-out branch, never HEAD (frozen commits would vanish).
|
|
548
|
+
const base = input.baseSha ?? await forkPoint(git, input.worktreePath, repositoryTarget(input.repositoryId).path) ?? 'HEAD';
|
|
549
|
+
const files = new Map();
|
|
550
|
+
const nameStatus = await git.run(['-c', 'core.quotepath=false', 'diff', '--no-renames', '--name-status', base, '--'], input.worktreePath);
|
|
551
|
+
if (nameStatus.code === 0) {
|
|
552
|
+
for (const line of nameStatus.stdout.split('\n')) {
|
|
553
|
+
const [code, file] = line.split('\t');
|
|
554
|
+
if (!file || excludedFromDiff(file, overlay))
|
|
555
|
+
continue;
|
|
556
|
+
files.set(file, { path: file, status: STATUS[code?.[0] ?? 'M'] ?? 'modified', additions: null, deletions: null });
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
const numstat = await git.run(['-c', 'core.quotepath=false', 'diff', '--no-renames', '--numstat', base, '--'], input.worktreePath);
|
|
560
|
+
if (numstat.code === 0) {
|
|
561
|
+
for (const line of numstat.stdout.split('\n')) {
|
|
562
|
+
const [added, removed, file] = line.split('\t');
|
|
563
|
+
const entry = file ? files.get(file) : undefined;
|
|
564
|
+
if (!entry)
|
|
565
|
+
continue;
|
|
566
|
+
entry.additions = added === '-' ? null : Number(added);
|
|
567
|
+
entry.deletions = removed === '-' ? null : Number(removed);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const untracked = await git.run(['-c', 'core.quotepath=false', 'ls-files', '--others', '--exclude-standard'], input.worktreePath);
|
|
571
|
+
if (untracked.code === 0) {
|
|
572
|
+
for (const file of untracked.stdout.split('\n').map((line) => line.trim()).filter(Boolean)) {
|
|
573
|
+
if (excludedFromDiff(file, overlay) || files.has(file))
|
|
574
|
+
continue;
|
|
575
|
+
files.set(file, { path: file, status: 'untracked', additions: null, deletions: null });
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const list = [...files.values()].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
579
|
+
return {
|
|
580
|
+
branch: input.branch,
|
|
581
|
+
baseSha: input.baseSha,
|
|
582
|
+
headSha: await (0, isolated_worktree_1.readHeadSha)(git, input.worktreePath),
|
|
583
|
+
files: list,
|
|
584
|
+
totals: {
|
|
585
|
+
files: list.length,
|
|
586
|
+
additions: list.reduce((sum, file) => sum + (file.additions ?? 0), 0),
|
|
587
|
+
deletions: list.reduce((sum, file) => sum + (file.deletions ?? 0), 0),
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
},
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
function createFlowPorts(deps) {
|
|
594
|
+
const { ctx, repository } = deps;
|
|
595
|
+
const clock = deps.clock ?? exports.systemClock;
|
|
596
|
+
const providerFor = (conversationId) => (0, agent_store_1.getAgentConversation)(ctx.desktopDb, conversationId)?.provider ?? ctx.project.provider ?? 'claude';
|
|
597
|
+
const host = () => {
|
|
598
|
+
const agentHost = deps.agentHost();
|
|
599
|
+
if (!agentHost)
|
|
600
|
+
throw new domain_1.FlowUnavailableError('Flow needs the mission agent chat, which is disabled');
|
|
601
|
+
return agentHost;
|
|
602
|
+
};
|
|
603
|
+
return {
|
|
604
|
+
repository,
|
|
605
|
+
// Target triage: a workspace or multi-repository project names the Git
|
|
606
|
+
// member a Flow runs in; a single repository is never triaged.
|
|
607
|
+
repositories: {
|
|
608
|
+
list: () => (0, project_repositories_1.getProjectRepositories)(ctx.project).map((member) => ({
|
|
609
|
+
id: member.id, name: member.name, isPrimary: member.isPrimary, kind: member.kind, ...(member.available === false ? { available: false } : {}),
|
|
610
|
+
})),
|
|
611
|
+
},
|
|
612
|
+
tickets: createFlowTickets(ctx, clock, railOfTicket(ctx.db)),
|
|
613
|
+
worktrees: createFlowWorktrees(ctx, { git: deps.git, providerFor }),
|
|
614
|
+
agent: {
|
|
615
|
+
async assertReady({ conversationId }) {
|
|
616
|
+
const conversation = (0, agent_store_1.getAgentConversation)(ctx.desktopDb, conversationId);
|
|
617
|
+
if (!conversation)
|
|
618
|
+
throw new domain_1.FlowValidationError('conversation_not_found', 'The mission conversation does not exist');
|
|
619
|
+
if (conversation.pinned_project_id !== ctx.project.id) {
|
|
620
|
+
throw new domain_1.FlowValidationError('conversation_not_pinned', 'Pin the mission to this project before starting a Flow');
|
|
621
|
+
}
|
|
622
|
+
try {
|
|
623
|
+
await host().assertFlowSupport(conversationId);
|
|
624
|
+
}
|
|
625
|
+
catch (error) {
|
|
626
|
+
if (error instanceof domain_1.FlowUnavailableError)
|
|
627
|
+
throw error;
|
|
628
|
+
throw new domain_1.FlowUnavailableError(error instanceof Error ? error.message : String(error));
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
async open({ flowId, renew }) {
|
|
632
|
+
// The Core session itself opens lazily on the first Flow turn (cwd = worktree).
|
|
633
|
+
// A resume never reuses a closed session: it gets a new generation.
|
|
634
|
+
return { coreSessionId: renew ? (0, domain_1.nextFlowCoreSessionId)(flowId, Date.now()) : (0, domain_1.flowCoreSessionId)(flowId) };
|
|
635
|
+
},
|
|
636
|
+
async close({ conversationId, coreSessionId }) {
|
|
637
|
+
const agentHost = deps.agentHost();
|
|
638
|
+
if (agentHost)
|
|
639
|
+
await agentHost.closeFlowSession(conversationId, coreSessionId, 'flow_closed');
|
|
640
|
+
},
|
|
641
|
+
launchEngine(conversationId) {
|
|
642
|
+
const conversation = (0, agent_store_1.getAgentConversation)(ctx.desktopDb, conversationId);
|
|
643
|
+
if (!conversation?.provider || !(0, provider_selection_1.isProviderEnabled)(ctx.project, conversation.provider))
|
|
644
|
+
return null;
|
|
645
|
+
return {
|
|
646
|
+
aiEngine: conversation.provider,
|
|
647
|
+
...(conversation.model ? { model: conversation.model } : {}),
|
|
648
|
+
...(conversation.reasoning_effort ? { reasoningEffort: conversation.reasoning_effort } : {}),
|
|
649
|
+
};
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
rails: {
|
|
653
|
+
async launch({ flowId, conversationId, ticketId, railIndex, options, repositoryId }) {
|
|
654
|
+
const rail = (0, rails_store_1.getRail)(ctx.db, railIndex);
|
|
655
|
+
if (rail.ticketIds.length > 0 && !(rail.ticketIds.length === 1 && rail.ticketIds[0] === ticketId)) {
|
|
656
|
+
throw new domain_1.FlowConflictError('rail_not_empty', `Rail ${railIndex} already carries other specs; pick a free rail`, flowId);
|
|
657
|
+
}
|
|
658
|
+
const base = `/projects/${encodeURIComponent(ctx.project.id)}/rails/${railIndex}`;
|
|
659
|
+
if (rail.ticketIds.length === 0) {
|
|
660
|
+
const assigned = await deps.internalApi.call('PUT', `${base}/tickets`, { ticketIds: [ticketId] });
|
|
661
|
+
if (!assigned.ok) {
|
|
662
|
+
const reason = (0, internal_api_1.internalApiError)(assigned);
|
|
663
|
+
throw new domain_1.FlowLaunchRejectedError(assigned.status, reason.error, reason.detail ?? reason.error);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
const launched = await deps.internalApi.call('POST', `${base}/launch`, {
|
|
667
|
+
flowId,
|
|
668
|
+
originSurface: 'agent-chat',
|
|
669
|
+
originConversationId: conversationId,
|
|
670
|
+
// Never fall back to the rail's default loop: Flow hands off to Flow -> Spec unless told otherwise.
|
|
671
|
+
loopId: options.loopId ?? domain_1.FLOW_SPEC_LOOP_ID,
|
|
672
|
+
// A Flow in a non-primary repository launches exactly that repository.
|
|
673
|
+
...(repositoryId ? { repositoryIds: [repositoryId] } : {}),
|
|
674
|
+
...(options.aiEngine ? { aiEngine: options.aiEngine } : {}),
|
|
675
|
+
...(options.model ? { model: options.model } : {}),
|
|
676
|
+
...(options.reasoningEffort ? { reasoning_effort: options.reasoningEffort } : {}),
|
|
677
|
+
});
|
|
678
|
+
if (!launched.ok) {
|
|
679
|
+
const reason = (0, internal_api_1.internalApiError)(launched);
|
|
680
|
+
throw new domain_1.FlowLaunchRejectedError(launched.status, reason.error, reason.detail ?? reason.error);
|
|
681
|
+
}
|
|
682
|
+
const body = (launched.body ?? {});
|
|
683
|
+
return {
|
|
684
|
+
loopRunIds: Array.isArray(body.loopRunIds) ? body.loopRunIds.filter((id) => typeof id === 'string') : [],
|
|
685
|
+
deliveryId: typeof body.prDeliveryId === 'string' ? body.prDeliveryId : null,
|
|
686
|
+
};
|
|
687
|
+
},
|
|
688
|
+
stoppedDelivery(deliveryId) {
|
|
689
|
+
const row = (0, rail_pr_store_1.getPrDelivery)(ctx.db, deliveryId);
|
|
690
|
+
if (!row)
|
|
691
|
+
return null;
|
|
692
|
+
const derivation = (0, delivery_evidence_1.readSettleEvidence)(row.settle_evidence)?.units[0]?.runtime?.derivation ?? null;
|
|
693
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
|
|
694
|
+
return {
|
|
695
|
+
railIndex: row.rail_index, options: launchOptionsOf(row.launch_config_json), findings: snap.flowReview ?? null,
|
|
696
|
+
derivation: derivation ? { change: derivation.change, files: derivation.files, explained: derivation.explained, unexplainedFiles: derivation.unexplainedFiles.slice(0, domain_1.FLOW_UNEXPLAINED_FILES_CAP), unexplainedOmitted: derivation.unexplainedOmitted + Math.max(0, derivation.unexplainedFiles.length - domain_1.FLOW_UNEXPLAINED_FILES_CAP) } : null,
|
|
697
|
+
failure: deliveryFailureOf(snap),
|
|
698
|
+
};
|
|
699
|
+
},
|
|
700
|
+
async runFailure(deliveryId) {
|
|
701
|
+
try {
|
|
702
|
+
const row = (0, rail_pr_store_1.getPrDelivery)(ctx.db, deliveryId);
|
|
703
|
+
const runId = row ? (0, rail_pr_store_1.toPrDeliverySnapshot)(row).runIds[0] : undefined;
|
|
704
|
+
if (!runId)
|
|
705
|
+
return null;
|
|
706
|
+
// The runtime's own record: the step it stopped at and its error
|
|
707
|
+
// (the same source the mission run card shows).
|
|
708
|
+
const summary = await (0, agent_runtime_controls_router_1.runtimeRunSummary)(ctx, runId);
|
|
709
|
+
if (!summary)
|
|
710
|
+
return null;
|
|
711
|
+
return {
|
|
712
|
+
stepId: summary.pendingApproval?.stepId ?? summary.nextStep ?? null,
|
|
713
|
+
cause: summary.status === 'failed' ? (0, domain_1.firstErrorLine)(summary.error) : null,
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
catch {
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
returnWorktree({ deliveryId, worktreePath, detail, commit }) {
|
|
721
|
+
try {
|
|
722
|
+
const closed = (0, flow_worktree_return_1.returnFlowWorktree)(ctx.db, { deliveryId, worktreePath, detail }, commit);
|
|
723
|
+
(0, flow_worktree_return_1.announceReturnedDelivery)(ctx.project.id, closed, (message) => ctx.broadcast(message));
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
if (error instanceof flow_worktree_return_1.FlowReturnRejectedError)
|
|
727
|
+
throw new domain_1.FlowConflictError(error.code, error.message);
|
|
728
|
+
throw error;
|
|
729
|
+
}
|
|
730
|
+
},
|
|
731
|
+
},
|
|
732
|
+
conversation: {
|
|
733
|
+
postReturnCard({ conversationId, flowId, deliveryId, findings, derivation, failure }) {
|
|
734
|
+
deps.agentHost()?.postSystemRow?.(conversationId, {
|
|
735
|
+
kind: 'flow-return-briefing', flowId, deliveryId,
|
|
736
|
+
reason: findings?.reason ?? null, score: findings?.score ?? null, summary: findings?.summary ?? null,
|
|
737
|
+
issues: findings?.issues ?? [], issuesOmitted: findings?.issuesOmitted ?? 0, failingChecks: findings?.failingChecks ?? [],
|
|
738
|
+
derivation,
|
|
739
|
+
// A run that failed outright: the client localizes the step and keeps the codes as technical details.
|
|
740
|
+
...(!findings && failure ? { failure } : {}),
|
|
741
|
+
at: clock.now(),
|
|
742
|
+
}, `flow-return-briefing:${deliveryId}`);
|
|
743
|
+
},
|
|
744
|
+
async startReturnTurn({ conversationId, deliveryId, failure }) {
|
|
745
|
+
await deps.agentHost()?.startAutomaticTurn?.(conversationId, failure ? exports.FLOW_FAILURE_RETURN_TURN_TEXT : exports.FLOW_RETURN_TURN_TEXT, { turnKey: `flow-return:${deliveryId}`, label: 'Back to Flow' });
|
|
746
|
+
},
|
|
747
|
+
postDeliveredSummary({ conversationId, flowId, deliveryId, ticketId, settlement }) {
|
|
748
|
+
const row = deliveryId ? (0, rail_pr_store_1.getPrDelivery)(ctx.db, deliveryId) : undefined;
|
|
749
|
+
const ticket = (0, ticket_store_1.readStore)((0, spec_addenda_1.ticketStorePathForProject)(ctx.project)).tickets[String(ticketId)];
|
|
750
|
+
const changeName = typeof ticket?.metadata?.openspecChangeName === 'string' ? ticket.metadata.openspecChangeName : null;
|
|
751
|
+
let jiraKey = null;
|
|
752
|
+
try {
|
|
753
|
+
const link = (0, jira_db_1.getLinkByLocalId)(ctx.db, ticketId);
|
|
754
|
+
jiraKey = link && !link.tombstoned ? link.jiraKey : null;
|
|
755
|
+
}
|
|
756
|
+
catch {
|
|
757
|
+
jiraKey = null;
|
|
758
|
+
}
|
|
759
|
+
deps.agentHost()?.postSystemRow?.(conversationId, {
|
|
760
|
+
kind: 'flow-delivered', flowId, deliveryId, ticketId,
|
|
761
|
+
prUrl: row?.pr_url ?? null, prNumber: row?.pr_number ?? null,
|
|
762
|
+
// Flow → Spec archives the change before it delivers (its `archive` step).
|
|
763
|
+
changeName, changeArchived: Boolean(changeName),
|
|
764
|
+
specRewrite: settlement.specRewrite, jiraCreate: settlement.jiraCreate, jiraKey,
|
|
765
|
+
at: clock.now(),
|
|
766
|
+
}, `flow-delivered:${flowId}`);
|
|
767
|
+
},
|
|
768
|
+
postBoundary({ conversationId, flowId, event, reason, branch }) {
|
|
769
|
+
const at = clock.now();
|
|
770
|
+
deps.agentHost()?.postSystemRow?.(conversationId, {
|
|
771
|
+
kind: 'flow-boundary', flowId, event, reason, branch, at,
|
|
772
|
+
}, `flow-boundary:${flowId}:${event}:${reason}:${at}`);
|
|
773
|
+
},
|
|
774
|
+
},
|
|
775
|
+
processes: deps.processes ?? { stop: async () => { } },
|
|
776
|
+
effects: deps.effects,
|
|
777
|
+
publication: createFlowPublication(ctx, { git: deps.git }),
|
|
778
|
+
usage: { costSoFar: (input) => (0, desktop_db_1.sumFlowInvocations)(ctx.desktopDb, input) },
|
|
779
|
+
notifier: {
|
|
780
|
+
changed(session) {
|
|
781
|
+
try {
|
|
782
|
+
ctx.broadcast({ type: 'flow.state', projectId: ctx.project.id, conversationId: session.conversationId, flowId: session.id, flow: session, timestamp: clock.now() });
|
|
783
|
+
}
|
|
784
|
+
catch { /* clients rehydrate through GET */ }
|
|
785
|
+
},
|
|
786
|
+
},
|
|
787
|
+
clock,
|
|
788
|
+
ids: ids_1.newId,
|
|
789
|
+
availability: deps.availability,
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* The rails launch route's view of Flow (delivery never imports this module).
|
|
794
|
+
* `adopt` and `release` run inside delivery's SQLite transaction on the same
|
|
795
|
+
* project connection, so the ownership transfer is atomic.
|
|
796
|
+
*/
|
|
797
|
+
function createFlowHandOffAuthority(repository, clock = exports.systemClock, onChanged, summarize) {
|
|
798
|
+
return {
|
|
799
|
+
resolve(flowId) {
|
|
800
|
+
const session = repository.get(flowId);
|
|
801
|
+
if (!session || session.step !== 'handoff:launch' || !session.worktreePath || !session.branch || !session.headSha || session.ticketId === null) {
|
|
802
|
+
throw new flow_worktree_handoff_1.FlowHandOffNotReadyError('This Flow is not waiting for a rail launch; end it from the Flow bar');
|
|
803
|
+
}
|
|
804
|
+
return {
|
|
805
|
+
flowId,
|
|
806
|
+
ticketId: session.ticketId,
|
|
807
|
+
conversationId: session.conversationId,
|
|
808
|
+
...(session.repositoryId ? { repositoryId: session.repositoryId } : {}),
|
|
809
|
+
branch: session.branch,
|
|
810
|
+
worktreePath: session.worktreePath,
|
|
811
|
+
headSha: session.headSha,
|
|
812
|
+
baseSha: session.baseSha,
|
|
813
|
+
// A re-derivation updates the Flow's own change in place (null ⇒ named after the spec).
|
|
814
|
+
changeId: (0, domain_1.currentDerivedChange)(session),
|
|
815
|
+
// A summary failure never blocks the hand-off: Core derives from the diff alone.
|
|
816
|
+
summary: (() => { try {
|
|
817
|
+
return summarize?.(session) ?? '';
|
|
818
|
+
}
|
|
819
|
+
catch {
|
|
820
|
+
return '';
|
|
821
|
+
} })(),
|
|
822
|
+
adopt(adoption) {
|
|
823
|
+
const current = repository.get(flowId);
|
|
824
|
+
if (!current)
|
|
825
|
+
throw new flow_worktree_handoff_1.FlowHandOffNotReadyError('The Flow disappeared during the hand-off');
|
|
826
|
+
repository.save((0, domain_1.transition)(current, { type: 'handed-off', railIndex: adoption.railIndex, deliveryId: adoption.deliveryId, headSha: adoption.headSha, now: clock.now() }).session);
|
|
827
|
+
// Announce the hand-off as soon as the delivery's transaction commits,
|
|
828
|
+
// so the hand-off card gives way to the run card that appears with it
|
|
829
|
+
// instead of waiting for the rest of the launch.
|
|
830
|
+
setImmediate(() => {
|
|
831
|
+
// Best effort: the connection may be gone (project closed) by then.
|
|
832
|
+
try {
|
|
833
|
+
const adopted = repository.get(flowId);
|
|
834
|
+
if (adopted?.state === 'handed_off' && adopted.deliveryId === adoption.deliveryId)
|
|
835
|
+
onChanged?.(adopted);
|
|
836
|
+
}
|
|
837
|
+
catch { /* clients rehydrate through GET */ }
|
|
838
|
+
});
|
|
839
|
+
},
|
|
840
|
+
release() {
|
|
841
|
+
const current = repository.get(flowId);
|
|
842
|
+
if (!current)
|
|
843
|
+
return;
|
|
844
|
+
const reverted = (0, domain_1.transition)(current, { type: 'adoption-reverted', now: clock.now() }).session;
|
|
845
|
+
repository.save(reverted);
|
|
846
|
+
onChanged?.(reverted);
|
|
847
|
+
},
|
|
848
|
+
};
|
|
849
|
+
},
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
/** The turn of an active Flow with a session (null otherwise). */
|
|
853
|
+
function toFlowTurn(session) {
|
|
854
|
+
if (!session || session.state !== 'active' || session.step !== null || !session.worktreePath || !session.coreSessionId)
|
|
855
|
+
return null;
|
|
856
|
+
return {
|
|
857
|
+
flowId: session.id,
|
|
858
|
+
cwd: session.worktreePath,
|
|
859
|
+
branch: session.branch,
|
|
860
|
+
coreSessionId: session.coreSessionId,
|
|
861
|
+
systemPrompt: (0, agent_flow_prompt_1.buildFlowSystemPrompt)(),
|
|
862
|
+
policy: flow_turn_context_1.FLOW_SESSION_BOUNDARY,
|
|
863
|
+
...(session.returnBriefing ? { briefing: session.returnBriefing } : {}),
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Missions' FlowTurnContext, bound app-wide: a conversation is in Flow while
|
|
868
|
+
* the Flow of its pinned project is `active` with an open session.
|
|
869
|
+
*/
|
|
870
|
+
function createFlowTurnContext(deps) {
|
|
871
|
+
return {
|
|
872
|
+
async offerable(conversationId) {
|
|
873
|
+
const projectId = deps.conversationProject(conversationId);
|
|
874
|
+
if (!projectId || !deps.availability)
|
|
875
|
+
return false;
|
|
876
|
+
const service = deps.flowServiceFor(projectId);
|
|
877
|
+
if (!service)
|
|
878
|
+
return false;
|
|
879
|
+
const open = service.getByConversation(conversationId);
|
|
880
|
+
if (open && (open.state === 'active' || open.state === 'paused'))
|
|
881
|
+
return false;
|
|
882
|
+
return (await deps.availability()).available;
|
|
883
|
+
},
|
|
884
|
+
forConversation(conversationId) {
|
|
885
|
+
const projectId = deps.conversationProject(conversationId);
|
|
886
|
+
if (!projectId)
|
|
887
|
+
return null;
|
|
888
|
+
return toFlowTurn(deps.flowServiceFor(projectId)?.getByConversation(conversationId) ?? null);
|
|
889
|
+
},
|
|
890
|
+
async renewSession(conversationId, flowId) {
|
|
891
|
+
const projectId = deps.conversationProject(conversationId);
|
|
892
|
+
const service = projectId ? deps.flowServiceFor(projectId) : null;
|
|
893
|
+
if (!service?.renewSession)
|
|
894
|
+
return null;
|
|
895
|
+
return toFlowTurn(await service.renewSession(flowId));
|
|
896
|
+
},
|
|
897
|
+
async briefingDelivered(conversationId, flowId) {
|
|
898
|
+
const projectId = deps.conversationProject(conversationId);
|
|
899
|
+
if (!projectId)
|
|
900
|
+
return;
|
|
901
|
+
await deps.flowServiceFor(projectId)?.briefingDelivered?.(flowId);
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
// ─── Settlement publication (arch section 4.6) ───────────────────────────────
|
|
906
|
+
/** Decisions that mean the delivery reached review (or went beyond it). */
|
|
907
|
+
const DELIVERED_DECISIONS = new Set(['on_review', 'pr_draft', 'pr_ready', 'completed', 'merged']);
|
|
908
|
+
const ARCHIVED_CHANGE = /^openspec\/changes\/archive\/([^/]+)\/(proposal|design)\.md$/;
|
|
909
|
+
const ACTIVE_CHANGE = /^openspec\/changes\/(?!archive\/)([^/]+)\/(proposal|design)\.md$/;
|
|
910
|
+
const TEXT_CAP = 64 * 1024;
|
|
911
|
+
/**
|
|
912
|
+
* The bounded summary of a Flow conversation: the person's messages since the
|
|
913
|
+
* Flow started (automatic briefings excluded), the first line of each final
|
|
914
|
+
* agent reply and the recorded decisions. Message times (SQLite) and Flow times
|
|
915
|
+
* (ISO) are compared as instants, never as strings.
|
|
916
|
+
*/
|
|
917
|
+
function flowConversationSummary(desktopDb, input) {
|
|
918
|
+
const messages = (0, agent_store_1.listAgentMessages)(desktopDb, input.conversationId)
|
|
919
|
+
.filter((message) => (0, domain_1.inFlowWindow)(message.created_at, input.from, input.to))
|
|
920
|
+
.map((message) => ({
|
|
921
|
+
role: message.role,
|
|
922
|
+
content: message.content,
|
|
923
|
+
...(message.context_refs.some((ref) => ref.kind === agent_failure_briefing_1.FAILURE_BRIEFING_REF_KIND) ? { automated: true } : {}),
|
|
924
|
+
}));
|
|
925
|
+
return (0, domain_1.buildFlowSummary)({ idea: input.idea, messages });
|
|
926
|
+
}
|
|
927
|
+
/** Strip OpenSpec's `YYYY-MM-DD-` archive prefix. */
|
|
928
|
+
function changeNameFromArchive(directory) {
|
|
929
|
+
return directory.replace(/^\d{4}-\d{2}-\d{2}-/, '');
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Read the derived OpenSpec change from the delivered commit: the archived
|
|
933
|
+
* (or still active) change directory the run added since the Flow base, its
|
|
934
|
+
* proposal and design, and a bounded diffstat. Pure Git reads; never mutates.
|
|
935
|
+
*/
|
|
936
|
+
async function readDerivedChange(git, repo, input) {
|
|
937
|
+
const base = input.baseSha ?? `${input.ref}~1`;
|
|
938
|
+
const added = await git.run(['-c', 'core.quotepath=false', 'diff', '--name-only', '--diff-filter=A', base, input.ref, '--', 'openspec/changes'], repo);
|
|
939
|
+
if (added.code !== 0)
|
|
940
|
+
throw new Error(`git diff failed: ${added.stderr.trim() || added.code}`);
|
|
941
|
+
const candidates = added.stdout.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
942
|
+
const directories = new Map();
|
|
943
|
+
for (const file of candidates) {
|
|
944
|
+
const archived = ARCHIVED_CHANGE.exec(file);
|
|
945
|
+
const active = archived ? null : ACTIVE_CHANGE.exec(file);
|
|
946
|
+
const match = archived ?? active;
|
|
947
|
+
if (!match)
|
|
948
|
+
continue;
|
|
949
|
+
const dir = file.slice(0, file.lastIndexOf('/'));
|
|
950
|
+
const entry = directories.get(dir) ?? { name: archived ? changeNameFromArchive(match[1]) : match[1], files: new Map() };
|
|
951
|
+
entry.files.set(match[2], file);
|
|
952
|
+
directories.set(dir, entry);
|
|
953
|
+
}
|
|
954
|
+
const ranked = [...directories.entries()].sort(([a], [b]) => Number(b.includes('/archive/')) - Number(a.includes('/archive/')));
|
|
955
|
+
const chosen = ranked.find(([, entry]) => input.changeName && entry.name === input.changeName) ?? ranked[0];
|
|
956
|
+
const show = async (file) => {
|
|
957
|
+
if (!file)
|
|
958
|
+
return null;
|
|
959
|
+
const result = await git.run(['show', `${input.ref}:${file}`], repo);
|
|
960
|
+
return result.code === 0 ? result.stdout.slice(0, TEXT_CAP) : null;
|
|
961
|
+
};
|
|
962
|
+
const stat = await git.run(['diff', '--stat=120', base, input.ref, '--'], repo);
|
|
963
|
+
return {
|
|
964
|
+
changeName: chosen?.[1].name ?? input.changeName,
|
|
965
|
+
proposal: await show(chosen?.[1].files.get('proposal')),
|
|
966
|
+
design: await show(chosen?.[1].files.get('design')),
|
|
967
|
+
diffstat: stat.code === 0 ? stat.stdout.slice(0, 8000) : null,
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
function createFlowPublication(ctx, deps = {}) {
|
|
971
|
+
const git = deps.git ?? worktree_manager_1.defaultGitRunner;
|
|
972
|
+
const ticketFile = () => (0, spec_addenda_1.ticketStorePathForProject)(ctx.project);
|
|
973
|
+
const readTicket = (ticketId) => (0, ticket_store_1.readStore)(ticketFile()).tickets[String(ticketId)];
|
|
974
|
+
return {
|
|
975
|
+
deliveryState(deliveryId) {
|
|
976
|
+
const row = (0, rail_pr_store_1.getPrDelivery)(ctx.db, deliveryId);
|
|
977
|
+
if (!row)
|
|
978
|
+
return null;
|
|
979
|
+
const delivered = DELIVERED_DECISIONS.has(row.decision) && row.implementation_outcome === 'succeeded';
|
|
980
|
+
return { delivered, crashed: !delivered && isCrashedFlowDelivery((0, rail_pr_store_1.toPrDeliverySnapshot)(row)) };
|
|
981
|
+
},
|
|
982
|
+
async derivedChange(input) {
|
|
983
|
+
const row = input.deliveryId ? (0, rail_pr_store_1.getPrDelivery)(ctx.db, input.deliveryId) : undefined;
|
|
984
|
+
let units = [];
|
|
985
|
+
try {
|
|
986
|
+
units = row ? JSON.parse(row.branches) : [];
|
|
987
|
+
}
|
|
988
|
+
catch {
|
|
989
|
+
units = [];
|
|
990
|
+
}
|
|
991
|
+
const unit = units.find((entry) => entry.ticketId === input.ticketId) ?? units[0];
|
|
992
|
+
const ref = unit?.finalSha ?? unit?.branch ?? row?.branch ?? input.branch;
|
|
993
|
+
if (!ref)
|
|
994
|
+
throw new Error('The delivered branch of this Flow is unknown');
|
|
995
|
+
const metadata = readTicket(input.ticketId)?.metadata;
|
|
996
|
+
const changeName = typeof metadata?.openspecChangeName === 'string' ? metadata.openspecChangeName : null;
|
|
997
|
+
// The delivered branch lives in the Flow's repository (the project root for the primary).
|
|
998
|
+
const repo = input.repositoryId ? (0, project_repositories_1.getProjectRepositories)(ctx.project).find((member) => member.id === input.repositoryId)?.path : ctx.project.path;
|
|
999
|
+
if (!repo)
|
|
1000
|
+
throw new Error(`The Flow's repository ${input.repositoryId} is no longer registered`);
|
|
1001
|
+
return readDerivedChange(git, repo, { ref, baseSha: input.baseSha, changeName });
|
|
1002
|
+
},
|
|
1003
|
+
conversationSummary(input) {
|
|
1004
|
+
return flowConversationSummary(ctx.desktopDb, { conversationId: input.conversationId, idea: readTicket(input.ticketId)?.description ?? null, from: input.from, to: input.to });
|
|
1005
|
+
},
|
|
1006
|
+
async rewriteSpec({ ticketId, text }) {
|
|
1007
|
+
const provider = (ctx.project.provider ?? 'claude');
|
|
1008
|
+
const scope = { specrails: false, openspec: false, full: false, mcp: false, contractRefine: true, userMcp: false };
|
|
1009
|
+
if (!(0, spec_generation_1.resolveSpecGenerationToolPolicy)(provider, scope))
|
|
1010
|
+
return { ok: false, error: `Provider ${provider} cannot run spec generation` };
|
|
1011
|
+
const model = (0, project_router_helpers_1.resolveDefaultSpecModel)({ projectPath: ctx.project.path, slug: ctx.project.slug, provider });
|
|
1012
|
+
const outcome = await (deps.generate ?? spec_generation_1.generateSpecFromText)({
|
|
1013
|
+
db: ctx.db,
|
|
1014
|
+
project: ctx.project,
|
|
1015
|
+
ticketStorePath: ticketFile(),
|
|
1016
|
+
ticketWatcher: ctx.ticketWatcher,
|
|
1017
|
+
broadcast: ctx.broadcast,
|
|
1018
|
+
admission: (0, process_admission_1.captureProcessAdmission)(ctx.project.id),
|
|
1019
|
+
}, {
|
|
1020
|
+
text, provider, model, scope, ticketId, surface: 'flow',
|
|
1021
|
+
// Contract Layer always (feedback-2026-10 decision 6.2), awaited so the
|
|
1022
|
+
// Jira issue that follows is born with the complete spec.
|
|
1023
|
+
contractRefine: (0, runtime_1.supportsContractRefine)((0, providers_1.getAdapter)(provider)) ? { model: null, await: true } : null,
|
|
1024
|
+
hooks: {
|
|
1025
|
+
onPersisted: (ticket) => {
|
|
1026
|
+
try {
|
|
1027
|
+
ctx.broadcast({ type: 'ticket_updated', ticket: ticket, projectId: ctx.project.id, timestamp: new Date().toISOString() });
|
|
1028
|
+
}
|
|
1029
|
+
catch { /* clients rehydrate */ }
|
|
1030
|
+
},
|
|
1031
|
+
},
|
|
1032
|
+
});
|
|
1033
|
+
return outcome.ok ? { ok: true } : { ok: false, error: outcome.error };
|
|
1034
|
+
},
|
|
1035
|
+
jira: {
|
|
1036
|
+
connected: () => { try {
|
|
1037
|
+
return ctx.jiraSyncManager.isActive();
|
|
1038
|
+
}
|
|
1039
|
+
catch {
|
|
1040
|
+
return false;
|
|
1041
|
+
} },
|
|
1042
|
+
enqueueCreate: (ticketId, key) => ctx.jiraSyncManager.enqueuePromote(ticketId, key),
|
|
1043
|
+
enqueueUpdate: (ticketId, key) => ctx.jiraSyncManager.enqueueSpecUpdate(ticketId, key),
|
|
1044
|
+
linked: (ticketId) => { try {
|
|
1045
|
+
const link = (0, jira_db_1.getLinkByLocalId)(ctx.db, ticketId);
|
|
1046
|
+
return Boolean(link && !link.tombstoned);
|
|
1047
|
+
}
|
|
1048
|
+
catch {
|
|
1049
|
+
return false;
|
|
1050
|
+
} },
|
|
1051
|
+
enqueueReview: (ticketId, refId) => ctx.jiraSyncManager.onRailReview([ticketId], refId),
|
|
1052
|
+
},
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
/** Periodic retry of due settlement effects (backoff lives in the rows). */
|
|
1056
|
+
function startFlowSettlementScheduler(service, intervalMs = 30_000) {
|
|
1057
|
+
let running = false;
|
|
1058
|
+
const timer = setInterval(() => {
|
|
1059
|
+
if (running)
|
|
1060
|
+
return;
|
|
1061
|
+
running = true;
|
|
1062
|
+
void service.runDueSettlements().catch(() => undefined).finally(() => { running = false; });
|
|
1063
|
+
}, intervalMs);
|
|
1064
|
+
timer.unref?.();
|
|
1065
|
+
return { stop: () => clearInterval(timer) };
|
|
1066
|
+
}
|
|
1067
|
+
/** Active OpenSpec changes in the worktree that are neither in the base commit nor already the Flow's. */
|
|
1068
|
+
async function unknownActiveChanges(git, worktreePath, baseSha, known) {
|
|
1069
|
+
let names;
|
|
1070
|
+
try {
|
|
1071
|
+
names = fs.readdirSync(path.join(worktreePath, 'openspec', 'changes'), { withFileTypes: true })
|
|
1072
|
+
.filter((entry) => entry.isDirectory() && entry.name !== 'archive' && (0, domain_1.isOpenSpecChangeId)(entry.name))
|
|
1073
|
+
.map((entry) => entry.name);
|
|
1074
|
+
}
|
|
1075
|
+
catch {
|
|
1076
|
+
return [];
|
|
1077
|
+
}
|
|
1078
|
+
if (!names.length)
|
|
1079
|
+
return [];
|
|
1080
|
+
const baseline = new Set();
|
|
1081
|
+
if (baseSha) {
|
|
1082
|
+
const listed = await git.run(['ls-tree', '-d', '--name-only', `${baseSha}:openspec/changes`], worktreePath).catch(() => null);
|
|
1083
|
+
if (listed?.code === 0)
|
|
1084
|
+
for (const name of listed.stdout.split('\n'))
|
|
1085
|
+
if (name.trim())
|
|
1086
|
+
baseline.add(name.trim());
|
|
1087
|
+
}
|
|
1088
|
+
return names.filter((name) => !baseline.has(name) && !known.includes(name));
|
|
1089
|
+
}
|