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,805 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createFlowService = createFlowService;
|
|
4
|
+
const domain_1 = require("./domain");
|
|
5
|
+
/**
|
|
6
|
+
* Flow use cases (imperative shell around the pure state machine). Start and
|
|
7
|
+
* hand-off are short sagas: every step is persisted in `flow_sessions.step`
|
|
8
|
+
* before the next external effect, and a failure compensates in reverse order.
|
|
9
|
+
* Operations on one Flow (and starts on one conversation) are serialized, and
|
|
10
|
+
* every use case is idempotent by `flowId`.
|
|
11
|
+
*/
|
|
12
|
+
const MAX_IDEA_LENGTH = 20_000;
|
|
13
|
+
const FLOW_ID_RE = /^[A-Za-z0-9-]{1,64}$/;
|
|
14
|
+
/** Effects whose failure must not mask the user's decision (logged, never thrown). */
|
|
15
|
+
const BEST_EFFORT = new Set(['stopProcesses', 'closeAgentSession', 'setTicketFlowState', 'deletePlaceholderTicket', 'restoreTicket', 'reopenTicket']);
|
|
16
|
+
function createFlowService(ports, log = console) {
|
|
17
|
+
const queues = new Map();
|
|
18
|
+
function serialized(key, work) {
|
|
19
|
+
const previous = queues.get(key) ?? Promise.resolve();
|
|
20
|
+
const run = previous.catch(() => undefined).then(work);
|
|
21
|
+
const tail = run.catch(() => undefined);
|
|
22
|
+
queues.set(key, tail);
|
|
23
|
+
void tail.then(() => { if (queues.get(key) === tail)
|
|
24
|
+
queues.delete(key); });
|
|
25
|
+
return run;
|
|
26
|
+
}
|
|
27
|
+
function commit(session) {
|
|
28
|
+
ports.repository.save(session);
|
|
29
|
+
ports.notifier.changed(session);
|
|
30
|
+
return session;
|
|
31
|
+
}
|
|
32
|
+
/** One history boundary of Flow mode (best effort: never fails the transition). */
|
|
33
|
+
function boundary(session, event, reason) {
|
|
34
|
+
try {
|
|
35
|
+
ports.conversation?.postBoundary?.({ conversationId: session.conversationId, flowId: session.id, event, reason, branch: session.branch });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
log.warn(`[flow] boundary row not posted for ${session.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function load(flowId) {
|
|
42
|
+
const session = ports.repository.get(flowId);
|
|
43
|
+
if (!session)
|
|
44
|
+
throw new domain_1.FlowNotFoundError(flowId);
|
|
45
|
+
return session;
|
|
46
|
+
}
|
|
47
|
+
function apply(session, command) {
|
|
48
|
+
return commit((0, domain_1.transition)(session, command).session);
|
|
49
|
+
}
|
|
50
|
+
/** Execute effects that only release or annotate (compensations, labels). */
|
|
51
|
+
async function settle(session, effects) {
|
|
52
|
+
for (const effect of effects) {
|
|
53
|
+
try {
|
|
54
|
+
await execute(session, effect);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (!BEST_EFFORT.has(effect.kind))
|
|
58
|
+
throw error;
|
|
59
|
+
log.warn(`[flow] ${effect.kind} failed for ${session.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function execute(session, effect) {
|
|
64
|
+
switch (effect.kind) {
|
|
65
|
+
case 'stopProcesses':
|
|
66
|
+
await ports.processes.stop({ flowId: session.id, conversationId: session.conversationId });
|
|
67
|
+
return;
|
|
68
|
+
case 'closeAgentSession':
|
|
69
|
+
await ports.agent.close({ flowId: session.id, conversationId: session.conversationId, coreSessionId: effect.coreSessionId });
|
|
70
|
+
return;
|
|
71
|
+
case 'releaseWorktree':
|
|
72
|
+
await ports.worktrees.release({ flowId: session.id, ticketId: effect.ticketId, worktreePath: effect.worktreePath, branch: effect.branch, ...repositoryOf(session) });
|
|
73
|
+
return;
|
|
74
|
+
case 'deletePlaceholderTicket':
|
|
75
|
+
ports.tickets.deletePlaceholder(effect.ticketId);
|
|
76
|
+
return;
|
|
77
|
+
case 'restoreTicket':
|
|
78
|
+
ports.tickets.restoreExisting(effect.ticketId, session.id);
|
|
79
|
+
return;
|
|
80
|
+
case 'setTicketFlowState':
|
|
81
|
+
ports.tickets.setFlowState(effect.ticketId, effect.state);
|
|
82
|
+
return;
|
|
83
|
+
case 'reopenTicket':
|
|
84
|
+
ports.tickets.reopen(effect.ticketId);
|
|
85
|
+
return;
|
|
86
|
+
default:
|
|
87
|
+
// Forward saga effects are driven explicitly by their use case.
|
|
88
|
+
throw new domain_1.FlowTransitionError('invalid_command', `Effect ${effect.kind} is not a settlement effect`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** The repository argument of a worktree/launch call (nothing for the primary). */
|
|
92
|
+
function repositoryOf(session) {
|
|
93
|
+
return session.repositoryId ? { repositoryId: session.repositoryId } : {};
|
|
94
|
+
}
|
|
95
|
+
async function assertAvailable() {
|
|
96
|
+
const availability = await ports.availability();
|
|
97
|
+
if (!availability.available)
|
|
98
|
+
throw new domain_1.FlowUnavailableError(availability.reason, availability.missing);
|
|
99
|
+
}
|
|
100
|
+
async function startFlow(input) {
|
|
101
|
+
const conversationId = typeof input.conversationId === 'string' ? input.conversationId.trim() : '';
|
|
102
|
+
if (!conversationId)
|
|
103
|
+
throw new domain_1.FlowValidationError('conversation_required', 'conversationId is required');
|
|
104
|
+
const idea = typeof input.idea === 'string' ? input.idea.trim() : '';
|
|
105
|
+
const fromSpec = input.ticketId !== undefined && input.ticketId !== null;
|
|
106
|
+
if (fromSpec && (typeof input.ticketId !== 'number' || !Number.isSafeInteger(input.ticketId) || input.ticketId <= 0)) {
|
|
107
|
+
throw new domain_1.FlowValidationError('invalid_ticket_id', 'ticketId must be a positive integer');
|
|
108
|
+
}
|
|
109
|
+
if (!idea && !fromSpec)
|
|
110
|
+
throw new domain_1.FlowValidationError('idea_required', 'Describe the idea to explore');
|
|
111
|
+
if (idea.length > MAX_IDEA_LENGTH)
|
|
112
|
+
throw new domain_1.FlowValidationError('idea_too_long', `The idea must be at most ${MAX_IDEA_LENGTH} characters`);
|
|
113
|
+
if (input.flowId !== undefined && !FLOW_ID_RE.test(input.flowId))
|
|
114
|
+
throw new domain_1.FlowValidationError('invalid_flow_id', 'flowId must be 1-64 characters of [A-Za-z0-9-]');
|
|
115
|
+
return serialized(`conversation:${conversationId}`, async () => {
|
|
116
|
+
// Idempotent retry of the same start: return the Flow it created.
|
|
117
|
+
if (input.flowId) {
|
|
118
|
+
const existing = ports.repository.get(input.flowId);
|
|
119
|
+
if (existing) {
|
|
120
|
+
if (existing.conversationId !== conversationId)
|
|
121
|
+
throw new domain_1.FlowConflictError('flow_id_conflict', 'This flowId belongs to another conversation', existing.id);
|
|
122
|
+
return existing;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const open = ports.repository.findOpenByConversation(conversationId);
|
|
126
|
+
if (open)
|
|
127
|
+
throw new domain_1.FlowConflictError('flow_already_open', 'This conversation already has a Flow; resume or discard it first', open.id);
|
|
128
|
+
// An existing spec must be free to work on (not done, not in another
|
|
129
|
+
// Flow, not on a rail) BEFORE anything is written.
|
|
130
|
+
const existingTicketId = fromSpec ? input.ticketId : null;
|
|
131
|
+
const inspected = existingTicketId !== null ? ports.tickets.inspectExisting(existingTicketId) : null;
|
|
132
|
+
if (inspected?.blocker) {
|
|
133
|
+
if (inspected.blocker.code === 'spec_not_found')
|
|
134
|
+
throw new domain_1.FlowValidationError(inspected.blocker.code, inspected.blocker.message);
|
|
135
|
+
throw new domain_1.FlowConflictError(inspected.blocker.code, inspected.blocker.message);
|
|
136
|
+
}
|
|
137
|
+
// Target triage before any effect: an unusable choice leaves nothing
|
|
138
|
+
// behind. A spec that targets exactly one repository runs there.
|
|
139
|
+
const specRepositories = inspected?.spec?.repositoryIds ?? [];
|
|
140
|
+
const requestedRepository = input.repositoryId ?? (specRepositories.length === 1 ? specRepositories[0] : null);
|
|
141
|
+
const repositoryId = (0, domain_1.resolveFlowRepository)(ports.repositories?.list() ?? [], requestedRepository);
|
|
142
|
+
await assertAvailable();
|
|
143
|
+
await ports.agent.assertReady({ conversationId });
|
|
144
|
+
const flowId = input.flowId ?? ports.ids();
|
|
145
|
+
let session = (0, domain_1.transition)(null, { type: 'start', flowId, conversationId, repositoryId, ticketId: existingTicketId, now: ports.clock.now() }).session;
|
|
146
|
+
ports.repository.insert(session);
|
|
147
|
+
ports.notifier.changed(session);
|
|
148
|
+
try {
|
|
149
|
+
if (existingTicketId !== null) {
|
|
150
|
+
// The existing spec is labelled "In Flow" and seeds the first turn.
|
|
151
|
+
const spec = ports.tickets.adoptExisting({ ticketId: existingTicketId, flowId, conversationId, startedAt: session.createdAt });
|
|
152
|
+
session = apply(session, { type: 'ticket-created', ticketId: existingTicketId, briefing: (0, domain_1.buildSpecSeedBriefing)(spec), now: ports.clock.now() });
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
const ticketId = ports.tickets.createPlaceholder({
|
|
156
|
+
flowId, conversationId, title: (0, domain_1.placeholderTitle)(idea, input.title), description: idea, startedAt: session.createdAt,
|
|
157
|
+
...(repositoryId ? { repositoryIds: [repositoryId] } : {}),
|
|
158
|
+
});
|
|
159
|
+
session = apply(session, { type: 'ticket-created', ticketId, now: ports.clock.now() });
|
|
160
|
+
}
|
|
161
|
+
const reserved = await ports.worktrees.reserve({ flowId, conversationId, ticketId: session.ticketId, ...repositoryOf(session) });
|
|
162
|
+
session = apply(session, { type: 'worktree-reserved', ...reserved, now: ports.clock.now() });
|
|
163
|
+
const opened = await ports.agent.open({ flowId, conversationId, worktreePath: reserved.worktreePath });
|
|
164
|
+
const started = apply(session, { type: 'session-opened', coreSessionId: opened.coreSessionId, now: ports.clock.now() });
|
|
165
|
+
boundary(started, 'entered', 'started');
|
|
166
|
+
return started;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
const latest = ports.repository.get(flowId) ?? session;
|
|
170
|
+
const failed = (0, domain_1.transition)(latest, { type: 'start-failed', now: ports.clock.now() });
|
|
171
|
+
try {
|
|
172
|
+
await settle(latest, failed.effects);
|
|
173
|
+
}
|
|
174
|
+
catch (compensationError) {
|
|
175
|
+
// The worktree could not be removed: keep the spec and the row for review.
|
|
176
|
+
log.warn(`[flow] start compensation incomplete for ${flowId}: ${compensationError instanceof Error ? compensationError.message : String(compensationError)}`);
|
|
177
|
+
commit({ ...failed.session, state: 'needs-review' });
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
commit(failed.session);
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function pauseFlow(flowId) {
|
|
186
|
+
return serialized(`flow:${flowId}`, async () => {
|
|
187
|
+
const session = load(flowId);
|
|
188
|
+
const result = (0, domain_1.transition)(session, { type: 'pause', now: ports.clock.now() });
|
|
189
|
+
if (result.session === session)
|
|
190
|
+
return session;
|
|
191
|
+
const paused = commit(result.session);
|
|
192
|
+
await settle(session, result.effects);
|
|
193
|
+
return paused;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/** Open the agent session of a paused Flow (caller holds the Flow's serialization). */
|
|
197
|
+
async function resumeSession(flowId) {
|
|
198
|
+
const session = load(flowId);
|
|
199
|
+
const result = (0, domain_1.transition)(session, { type: 'resume', now: ports.clock.now() });
|
|
200
|
+
if (result.effects.length === 0)
|
|
201
|
+
return session;
|
|
202
|
+
await assertAvailable();
|
|
203
|
+
await ports.agent.assertReady({ conversationId: session.conversationId });
|
|
204
|
+
if (!session.worktreePath || !ports.worktrees.exists(session.worktreePath)) {
|
|
205
|
+
throw new domain_1.FlowConflictError('flow_worktree_missing', 'The Flow worktree no longer exists; review it before continuing', flowId);
|
|
206
|
+
}
|
|
207
|
+
// Pause, hand-off and restart closed the previous Core session: resuming
|
|
208
|
+
// (also after Back to Flow) always opens a new one.
|
|
209
|
+
const opened = await ports.agent.open({ flowId, conversationId: session.conversationId, worktreePath: session.worktreePath, renew: true });
|
|
210
|
+
const resumed = apply(session, { type: 'session-opened', coreSessionId: opened.coreSessionId, now: ports.clock.now() });
|
|
211
|
+
await settle(resumed, result.effects.filter((effect) => effect.kind !== 'openAgentSession'));
|
|
212
|
+
return resumed;
|
|
213
|
+
}
|
|
214
|
+
function resumeFlow(flowId) {
|
|
215
|
+
return serialized(`flow:${flowId}`, () => resumeSession(flowId));
|
|
216
|
+
}
|
|
217
|
+
function discardFlow(flowId) {
|
|
218
|
+
return serialized(`flow:${flowId}`, async () => {
|
|
219
|
+
const session = load(flowId);
|
|
220
|
+
const result = (0, domain_1.transition)(session, { type: 'discard', now: ports.clock.now() });
|
|
221
|
+
if (result.session === session)
|
|
222
|
+
return session;
|
|
223
|
+
try {
|
|
224
|
+
await settle(session, result.effects);
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
// The worktree survived: the Flow stays open (without a session) so the user can retry.
|
|
228
|
+
if (session.state === 'active')
|
|
229
|
+
commit({ ...session, state: 'paused', coreSessionId: null, updatedAt: ports.clock.now() });
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
const discarded = commit(result.session);
|
|
233
|
+
if (((0, domain_1.isOpenFlow)(session) || session.state === 'needs-review') && discarded.state === 'discarded')
|
|
234
|
+
boundary(discarded, 'left', 'discarded');
|
|
235
|
+
return discarded;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/** Close a needs-review Flow, keeping its branch (and any worktree left
|
|
239
|
+
* behind): the conversation leaves Flow and the spec loses its label. */
|
|
240
|
+
function closeFlow(flowId) {
|
|
241
|
+
return serialized(`flow:${flowId}`, async () => {
|
|
242
|
+
const session = load(flowId);
|
|
243
|
+
const result = (0, domain_1.transition)(session, { type: 'close', now: ports.clock.now() });
|
|
244
|
+
if (result.session === session)
|
|
245
|
+
return session;
|
|
246
|
+
await settle(session, result.effects);
|
|
247
|
+
const closed = commit(result.session);
|
|
248
|
+
boundary(closed, 'left', 'closed');
|
|
249
|
+
return closed;
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Freeze HEAD, close the agent session and launch the rail with the Flow
|
|
254
|
+
* worktree. The rail launch adopts the worktree and marks this Flow
|
|
255
|
+
* `handed_off` in the same SQLite transaction; any failure before that
|
|
256
|
+
* commit reverts the Flow to `paused` with its worktree and spec intact.
|
|
257
|
+
*/
|
|
258
|
+
function handOffFlow(input) {
|
|
259
|
+
return serialized(`flow:${input.flowId}`, () => handOff(input));
|
|
260
|
+
}
|
|
261
|
+
/** The hand-off saga (caller holds the Flow's serialization). */
|
|
262
|
+
async function handOff(input) {
|
|
263
|
+
let session = load(input.flowId);
|
|
264
|
+
if (session.state === 'handed_off') {
|
|
265
|
+
if (session.railIndex === input.railIndex)
|
|
266
|
+
return { flow: session, loopRunIds: [], deliveryId: session.deliveryId };
|
|
267
|
+
throw new domain_1.FlowConflictError('flow_already_handed_off', `This Flow was handed off to rail ${session.railIndex}`, session.id);
|
|
268
|
+
}
|
|
269
|
+
if (!Number.isSafeInteger(input.railIndex) || input.railIndex < 0)
|
|
270
|
+
throw new domain_1.FlowValidationError('invalid_rail_index', 'railIndex must be a non-negative integer');
|
|
271
|
+
await assertAvailable();
|
|
272
|
+
const begun = (0, domain_1.transition)(session, { type: 'begin-hand-off', railIndex: input.railIndex, now: ports.clock.now() });
|
|
273
|
+
// The change this Flow's earlier Flow → Spec run derived (recorded at the
|
|
274
|
+
// return, or read from the returned delivery's evidence for Flows returned
|
|
275
|
+
// before it was recorded): the freeze allows it, the run re-derives it.
|
|
276
|
+
const derivedChanges = (0, domain_1.withDerivedChange)(begun.session, returnedDeliveryChange(begun.session));
|
|
277
|
+
session = commit(derivedChanges.length ? { ...begun.session, derivedChanges } : begun.session);
|
|
278
|
+
try {
|
|
279
|
+
await settle(session, begun.effects.filter((effect) => effect.kind === 'stopProcesses' || effect.kind === 'closeAgentSession'));
|
|
280
|
+
const frozen = await ports.worktrees.freeze({ flowId: session.id, conversationId: session.conversationId, ticketId: session.ticketId, worktreePath: session.worktreePath, baseSha: session.baseSha, allowedChanges: session.derivedChanges ?? [], ...repositoryOf(session) });
|
|
281
|
+
// A change the Flow's own earlier run left under another name is the
|
|
282
|
+
// Flow's: the next run re-derives it instead of being blocked by it.
|
|
283
|
+
if (frozen.adoptedChange)
|
|
284
|
+
session = commit({ ...session, derivedChanges: (0, domain_1.withDerivedChange)(session, frozen.adoptedChange) });
|
|
285
|
+
session = apply(session, { type: 'frozen', headSha: frozen.headSha, now: ports.clock.now() });
|
|
286
|
+
const launched = await ports.rails.launch({
|
|
287
|
+
flowId: session.id, conversationId: session.conversationId, ticketId: session.ticketId, railIndex: input.railIndex, options: input.options ?? {},
|
|
288
|
+
...repositoryOf(session),
|
|
289
|
+
});
|
|
290
|
+
const after = load(session.id);
|
|
291
|
+
if (after.state !== 'handed_off') {
|
|
292
|
+
throw new domain_1.FlowConflictError('flow_handoff_not_adopted', 'The rail launched without adopting the Flow worktree', session.id);
|
|
293
|
+
}
|
|
294
|
+
ports.notifier.changed(after);
|
|
295
|
+
boundary(after, 'left', 'handed_off');
|
|
296
|
+
return { flow: after, loopRunIds: launched.loopRunIds, deliveryId: launched.deliveryId ?? after.deliveryId };
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
const latest = ports.repository.get(session.id) ?? session;
|
|
300
|
+
// A launch that committed the ownership transfer is not rolled back.
|
|
301
|
+
if (latest.state !== 'handed_off')
|
|
302
|
+
commit((0, domain_1.transition)(latest, { type: 'hand-off-failed', now: ports.clock.now() }).session);
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* A relaunch runs on what the person uses in the Flow NOW (the conversation's
|
|
308
|
+
* provider/model/effort, as the hand-off card defaults to); the stopped run's
|
|
309
|
+
* engine only when that provider cannot run the loop. The loop is kept.
|
|
310
|
+
*/
|
|
311
|
+
function relaunchOptions(conversationId, previous) {
|
|
312
|
+
let engine = null;
|
|
313
|
+
try {
|
|
314
|
+
engine = ports.agent.launchEngine?.(conversationId) ?? null;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
engine = null;
|
|
318
|
+
}
|
|
319
|
+
if (!engine?.aiEngine)
|
|
320
|
+
return previous;
|
|
321
|
+
return { ...(previous.loopId ? { loopId: previous.loopId } : {}), ...engine };
|
|
322
|
+
}
|
|
323
|
+
/** The change the Flow's returned delivery derived (null when none, or unreadable). */
|
|
324
|
+
function returnedDeliveryChange(session) {
|
|
325
|
+
if (!session.deliveryId)
|
|
326
|
+
return null;
|
|
327
|
+
try {
|
|
328
|
+
return ports.rails.stoppedDelivery(session.deliveryId)?.derivation?.change ?? null;
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Why a stopped delivery failed when it has no review findings: the delivery
|
|
336
|
+
* codes plus the failing step and the runtime's own error. Null for a review
|
|
337
|
+
* outcome (requested changes). Never throws.
|
|
338
|
+
*/
|
|
339
|
+
async function failureOf(deliveryId, stopped) {
|
|
340
|
+
if (stopped?.findings)
|
|
341
|
+
return null;
|
|
342
|
+
let runtime = null;
|
|
343
|
+
try {
|
|
344
|
+
runtime = await ports.rails.runFailure?.(deliveryId) ?? null;
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
runtime = null;
|
|
348
|
+
}
|
|
349
|
+
const base = stopped?.failure ?? null;
|
|
350
|
+
if (!base && !runtime)
|
|
351
|
+
return stopped ? { stepId: null, cause: null, statusCode: null, failureCode: null, statusDetail: null } : null;
|
|
352
|
+
return {
|
|
353
|
+
stepId: runtime?.stepId ?? base?.stepId ?? null,
|
|
354
|
+
cause: runtime?.cause ?? base?.cause ?? null,
|
|
355
|
+
statusCode: base?.statusCode ?? null,
|
|
356
|
+
failureCode: base?.failureCode ?? null,
|
|
357
|
+
statusDetail: base?.statusDetail ?? null,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/** Give the stopped delivery's worktree back to its Flow (caller holds the Flow's serialization). */
|
|
361
|
+
async function returnWorktree(session, deliveryId) {
|
|
362
|
+
if ((0, domain_1.isOpenFlow)(session) && session.deliveryId === deliveryId && session.step === null)
|
|
363
|
+
return { session, railIndex: null, options: {} };
|
|
364
|
+
if (session.state !== 'handed_off' || session.deliveryId !== deliveryId) {
|
|
365
|
+
throw new domain_1.FlowConflictError('flow_not_handed_off', 'This Flow is not waiting on that delivery', session.id);
|
|
366
|
+
}
|
|
367
|
+
if (!session.worktreePath || !ports.worktrees.exists(session.worktreePath)) {
|
|
368
|
+
throw new domain_1.FlowConflictError('flow_worktree_missing', 'The Flow worktree no longer exists; it cannot go back to the Flow', session.id);
|
|
369
|
+
}
|
|
370
|
+
const stopped = ports.rails.stoppedDelivery(deliveryId);
|
|
371
|
+
// Read before the return closes the delivery (its codes are replaced by `returned_to_flow`).
|
|
372
|
+
const failure = await failureOf(deliveryId, stopped);
|
|
373
|
+
const result = (0, domain_1.transition)(session, { type: 'returned', deliveryId, briefing: (0, domain_1.buildReturnBriefing)(stopped?.findings ?? null, stopped?.derivation ?? null, failure), derivedChange: stopped?.derivation?.change ?? null, now: ports.clock.now() });
|
|
374
|
+
// Delivery owns the transaction: its ledger row disappears and this Flow
|
|
375
|
+
// becomes the owner again, or neither happens.
|
|
376
|
+
ports.rails.returnWorktree({
|
|
377
|
+
deliveryId,
|
|
378
|
+
worktreePath: session.worktreePath,
|
|
379
|
+
detail: failure
|
|
380
|
+
? 'Returned to Flow: the run failed; the worktree is back in its Flow with the error.'
|
|
381
|
+
: 'Returned to Flow: the worktree is back in its Flow for the requested changes.',
|
|
382
|
+
commit: () => ports.repository.save(result.session),
|
|
383
|
+
});
|
|
384
|
+
ports.notifier.changed(result.session);
|
|
385
|
+
boundary(result.session, 'entered', 'returned');
|
|
386
|
+
await settle(result.session, result.effects);
|
|
387
|
+
return { session: result.session, railIndex: stopped?.railIndex ?? null, options: stopped?.options ?? {}, failure };
|
|
388
|
+
}
|
|
389
|
+
function flowOfDelivery(deliveryId) {
|
|
390
|
+
const session = typeof deliveryId === 'string' && deliveryId ? ports.repository.findByDelivery(deliveryId) : null;
|
|
391
|
+
if (!session)
|
|
392
|
+
throw new domain_1.FlowNotFoundError(deliveryId);
|
|
393
|
+
return session;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Back to Flow: the Flow → Spec run stopped with requested changes. The
|
|
397
|
+
* worktree (intact, with the run's changes) returns from the rail ledger to
|
|
398
|
+
* the Flow, the spec is "In Flow" again and the agent session reopens; the
|
|
399
|
+
* agent receives the review on its next turn. Idempotent by delivery. A
|
|
400
|
+
* session that cannot open (provider, Core) leaves the Flow paused: the
|
|
401
|
+
* ownership already moved and the Flow bar resumes it.
|
|
402
|
+
*/
|
|
403
|
+
async function returnToFlow(input) {
|
|
404
|
+
const session = flowOfDelivery(input.deliveryId);
|
|
405
|
+
let failure;
|
|
406
|
+
const result = await serialized(`flow:${session.id}`, async () => {
|
|
407
|
+
const returned = await returnWorktree(load(session.id), input.deliveryId);
|
|
408
|
+
failure = returned.failure;
|
|
409
|
+
if (returned.session.state !== 'paused')
|
|
410
|
+
return returned.session;
|
|
411
|
+
try {
|
|
412
|
+
return await resumeSession(session.id);
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
log.warn(`[flow] ${session.id} returned paused; its session did not open: ${error instanceof Error ? error.message : String(error)}`);
|
|
416
|
+
return load(session.id);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
await announceReturn(result, input.deliveryId, failure);
|
|
420
|
+
return result;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Back to Flow, visibly: the card with what the reviewer asked for (or why
|
|
424
|
+
* the run failed), then ONE automatic Flow turn that starts on it (only
|
|
425
|
+
* while the Flow is active — a paused Flow keeps the briefing for the
|
|
426
|
+
* person's next turn). Both are idempotent by delivery; a failure never
|
|
427
|
+
* undoes the return. `failure` undefined ⇒ read again (a repeated return).
|
|
428
|
+
*/
|
|
429
|
+
async function announceReturn(session, deliveryId, failure) {
|
|
430
|
+
const conversation = ports.conversation;
|
|
431
|
+
if (!conversation || session.deliveryId !== deliveryId)
|
|
432
|
+
return;
|
|
433
|
+
try {
|
|
434
|
+
const stopped = ports.rails.stoppedDelivery(deliveryId);
|
|
435
|
+
const known = failure === undefined ? await failureOf(deliveryId, stopped) : failure;
|
|
436
|
+
conversation.postReturnCard({ conversationId: session.conversationId, flowId: session.id, deliveryId, findings: stopped?.findings ?? null, derivation: stopped?.derivation ?? null, ...(known ? { failure: known } : {}) });
|
|
437
|
+
if (session.state === 'active' && session.returnBriefing) {
|
|
438
|
+
await conversation.startReturnTurn({ conversationId: session.conversationId, flowId: session.id, deliveryId, ...(known ? { failure: known } : {}) });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
log.warn(`[flow] ${session.id} return briefing not announced: ${error instanceof Error ? error.message : String(error)}`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/** Deliveries whose automatic return is in flight (observer bursts, startup replay). */
|
|
446
|
+
const autoReturning = new Set();
|
|
447
|
+
/**
|
|
448
|
+
* A Flow → Spec run that failed outright (no review verdict) goes back to
|
|
449
|
+
* its Flow on its own — the same Back to Flow, idempotent by delivery — and
|
|
450
|
+
* the Flow agent receives the failure. A refusal (worktree gone, delivery
|
|
451
|
+
* busy) only logs: the card still offers Back to Flow by hand.
|
|
452
|
+
*/
|
|
453
|
+
async function autoReturn(deliveryId) {
|
|
454
|
+
if (autoReturning.has(deliveryId))
|
|
455
|
+
return null;
|
|
456
|
+
autoReturning.add(deliveryId);
|
|
457
|
+
try {
|
|
458
|
+
return await returnToFlow({ deliveryId });
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
log.warn(`[flow] automatic return of delivery ${deliveryId} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
finally {
|
|
465
|
+
autoReturning.delete(deliveryId);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Relaunch: run Flow → Spec again on the SAME worktree — the delivery gives
|
|
470
|
+
* it back, then the ordinary hand-off freezes it and launches the same rail
|
|
471
|
+
* with the same launch choices. The new run re-derives the existing change.
|
|
472
|
+
*/
|
|
473
|
+
async function relaunchFlow(input) {
|
|
474
|
+
const session = flowOfDelivery(input.deliveryId);
|
|
475
|
+
return serialized(`flow:${session.id}`, async () => {
|
|
476
|
+
const current = load(session.id);
|
|
477
|
+
if (current.state === 'handed_off' && current.deliveryId !== input.deliveryId) {
|
|
478
|
+
// Already relaunched: the Flow is on its new delivery.
|
|
479
|
+
return { flow: current, loopRunIds: [], deliveryId: current.deliveryId };
|
|
480
|
+
}
|
|
481
|
+
const stopped = ports.rails.stoppedDelivery(input.deliveryId);
|
|
482
|
+
const returned = await returnWorktree(current, input.deliveryId);
|
|
483
|
+
const railIndex = returned.railIndex ?? stopped?.railIndex ?? null;
|
|
484
|
+
if (railIndex === null)
|
|
485
|
+
throw new domain_1.FlowConflictError('flow_rail_unknown', 'The rail of the stopped run is unknown; hand off from the Flow bar', session.id);
|
|
486
|
+
return handOff({ flowId: session.id, railIndex, options: relaunchOptions(session.conversationId, { ...(stopped?.options ?? {}), ...returned.options }) });
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* The active Flow's Core session cannot serve the next turn (Core closed it,
|
|
491
|
+
* or the conversation switched provider): commit a new session id. The caller
|
|
492
|
+
* (the turn) closes the old session itself without aborting the turn and
|
|
493
|
+
* seeds the new one with the conversation. Null when the Flow is not active.
|
|
494
|
+
*/
|
|
495
|
+
function renewSession(flowId) {
|
|
496
|
+
return serialized(`flow:${flowId}`, async () => {
|
|
497
|
+
const session = ports.repository.get(flowId);
|
|
498
|
+
if (!session || session.state !== 'active' || session.step !== null)
|
|
499
|
+
return null;
|
|
500
|
+
const coreSessionId = (0, domain_1.nextFlowCoreSessionId)(session.id, Date.parse(ports.clock.now()) || Date.now(), session.coreSessionId);
|
|
501
|
+
return apply(session, { type: 'session-renewed', coreSessionId, now: ports.clock.now() });
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
/** A Flow turn carried the return briefing to the agent: clear it. Never throws for an unknown Flow. */
|
|
505
|
+
function briefingDelivered(flowId) {
|
|
506
|
+
return serialized(`flow:${flowId}`, async () => {
|
|
507
|
+
const session = ports.repository.get(flowId);
|
|
508
|
+
if (!session)
|
|
509
|
+
return null;
|
|
510
|
+
const result = (0, domain_1.transition)(session, { type: 'briefing-delivered', now: ports.clock.now() });
|
|
511
|
+
return result.session === session ? session : commit(result.session);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Delivery settled (reached review): record `delivered`, label the spec
|
|
516
|
+
* delivered and enqueue the durable settlement effects (arch 4.6). The
|
|
517
|
+
* effects then run in the background, in order; their failure never
|
|
518
|
+
* reverts the delivery. Idempotent by flowId.
|
|
519
|
+
*/
|
|
520
|
+
async function onFlowDelivered(input) {
|
|
521
|
+
const delivered = await serialized(`flow:${input.flowId}`, async () => {
|
|
522
|
+
const session = load(input.flowId);
|
|
523
|
+
const deliveryId = session.deliveryId ?? input.deliveryId ?? null;
|
|
524
|
+
if (!deliveryId)
|
|
525
|
+
throw new domain_1.FlowValidationError('delivery_required', 'A delivered Flow needs its delivery id');
|
|
526
|
+
const result = (0, domain_1.transition)(session, { type: 'delivered', deliveryId, now: ports.clock.now() });
|
|
527
|
+
let current = session;
|
|
528
|
+
if (result.session !== session) {
|
|
529
|
+
current = commit(result.session);
|
|
530
|
+
await settle(current, result.effects);
|
|
531
|
+
}
|
|
532
|
+
if (current.state === 'delivered')
|
|
533
|
+
ports.effects.enqueue((0, domain_1.plannedSettlementEffects)(current.id, ports.clock.now()));
|
|
534
|
+
return current;
|
|
535
|
+
});
|
|
536
|
+
void runSettlement(delivered.id).catch((error) => log.warn(`[flow] settlement of ${delivered.id} failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
537
|
+
return delivered;
|
|
538
|
+
}
|
|
539
|
+
/** A `rail.pr_state` change: settle the Flow whose delivery reached review,
|
|
540
|
+
* or take back the worktree of a run that failed outright. Only a Flow still
|
|
541
|
+
* handed off to THIS delivery reacts (a returned, relaunched, delivered or
|
|
542
|
+
* discarded Flow never does), so repeated broadcasts are no-ops. */
|
|
543
|
+
async function observeDelivery(deliveryId) {
|
|
544
|
+
const session = ports.repository.findByDelivery(deliveryId);
|
|
545
|
+
if (!session || session.state !== 'handed_off' || session.deliveryId !== deliveryId)
|
|
546
|
+
return null;
|
|
547
|
+
const state = ports.publication.deliveryState(deliveryId);
|
|
548
|
+
if (state?.delivered)
|
|
549
|
+
return onFlowDelivered({ flowId: session.id, deliveryId });
|
|
550
|
+
if (state?.crashed)
|
|
551
|
+
return autoReturn(deliveryId);
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
/** A Flow rail completed without a PR delivery row (PR delivery off): the
|
|
555
|
+
* run itself is the delivery reference. */
|
|
556
|
+
async function onRailRunCompleted(input) {
|
|
557
|
+
const session = ports.repository.get(input.flowId);
|
|
558
|
+
if (!session || session.state !== 'handed_off' || session.deliveryId)
|
|
559
|
+
return null;
|
|
560
|
+
return onFlowDelivered({ flowId: session.id, deliveryId: input.runId });
|
|
561
|
+
}
|
|
562
|
+
async function executeEffect(session, effect, all) {
|
|
563
|
+
const now = ports.clock.now();
|
|
564
|
+
const ticketId = session.ticketId;
|
|
565
|
+
if (ticketId === null)
|
|
566
|
+
return (0, domain_1.finishedEffect)(effect, 'skipped', now, 'ticket_missing');
|
|
567
|
+
switch (effect.kind) {
|
|
568
|
+
case 'rewrite-spec': {
|
|
569
|
+
let derived;
|
|
570
|
+
try {
|
|
571
|
+
derived = await ports.publication.derivedChange({ flowId: session.id, deliveryId: session.deliveryId, ticketId, branch: session.branch, baseSha: session.baseSha, ...repositoryOf(session) });
|
|
572
|
+
}
|
|
573
|
+
catch (error) {
|
|
574
|
+
// Label and change name never wait for Git: the delivery is real.
|
|
575
|
+
ports.tickets.markDelivered(ticketId, { openspecChangeName: null });
|
|
576
|
+
return (0, domain_1.failedAttempt)(effect, error instanceof Error ? error.message : String(error), now, 'derived_change_unreadable');
|
|
577
|
+
}
|
|
578
|
+
ports.tickets.markDelivered(ticketId, { openspecChangeName: derived.changeName });
|
|
579
|
+
if (!derived.proposal?.trim() && !derived.design?.trim())
|
|
580
|
+
return (0, domain_1.failedAttempt)(effect, 'The derived OpenSpec change was not found on the delivered branch', now, 'derived_change_missing');
|
|
581
|
+
const ticket = ports.tickets.read(ticketId);
|
|
582
|
+
if (!ticket)
|
|
583
|
+
return (0, domain_1.finishedEffect)(effect, 'skipped', now, 'ticket_missing');
|
|
584
|
+
// A Flow from an existing spec rewrites it ENTIRELY from what was built,
|
|
585
|
+
// but first keeps its current content as a comment: nothing is lost.
|
|
586
|
+
const existingSpec = (0, domain_1.isExistingSpecFlow)(session);
|
|
587
|
+
if (existingSpec)
|
|
588
|
+
ports.tickets.preserveOriginal(ticketId, session.id);
|
|
589
|
+
const summary = ports.publication.conversationSummary({ conversationId: session.conversationId, ticketId, from: session.createdAt, to: null });
|
|
590
|
+
const result = await ports.publication.rewriteSpec({
|
|
591
|
+
ticketId,
|
|
592
|
+
text: (0, domain_1.buildSpecRewriteText)({ title: ticket.title, derived, summary, ...(existingSpec ? { original: { title: ticket.title, description: ticket.description } } : {}) }),
|
|
593
|
+
});
|
|
594
|
+
if (!result.ok)
|
|
595
|
+
return (0, domain_1.failedAttempt)(effect, result.error, now, 'rewrite_failed');
|
|
596
|
+
// The rewritten spec now describes the work the Flow did for its addenda
|
|
597
|
+
// (shown to the Flow agent at start): they are applied, like a rail run's.
|
|
598
|
+
ports.tickets.applyAddenda(ticketId, session.id, session.deliveryId ?? session.id);
|
|
599
|
+
return (0, domain_1.finishedEffect)(effect, 'done', now);
|
|
600
|
+
}
|
|
601
|
+
case 'jira-create': {
|
|
602
|
+
if (!ports.publication.jira.connected())
|
|
603
|
+
return (0, domain_1.finishedEffect)(effect, 'skipped', now, 'jira_not_connected');
|
|
604
|
+
// A spec that already had its Jira issue before the Flow: update THAT
|
|
605
|
+
// issue (rewritten summary and description), never create a second one.
|
|
606
|
+
if ((0, domain_1.isExistingSpecFlow)(session) && ports.publication.jira.linked(ticketId)) {
|
|
607
|
+
const updated = ports.publication.jira.enqueueUpdate(ticketId, (0, domain_1.flowJiraUpdateKey)(session.id));
|
|
608
|
+
if (updated === 'enqueued')
|
|
609
|
+
return (0, domain_1.finishedEffect)(effect, 'done', now, 'updated');
|
|
610
|
+
if (updated === 'inactive')
|
|
611
|
+
return (0, domain_1.finishedEffect)(effect, 'skipped', now, 'jira_not_connected');
|
|
612
|
+
if (updated === 'failed')
|
|
613
|
+
return (0, domain_1.failedAttempt)(effect, 'The Jira update could not be enqueued', now, 'enqueue_failed');
|
|
614
|
+
// not_linked: the link went away meanwhile — create as for any unlinked spec.
|
|
615
|
+
}
|
|
616
|
+
const outcome = ports.publication.jira.enqueueCreate(ticketId, (0, domain_1.flowJiraCreateKey)(session.id));
|
|
617
|
+
if (outcome === 'enqueued' || outcome === 'already_linked')
|
|
618
|
+
return (0, domain_1.finishedEffect)(effect, 'done', now, outcome);
|
|
619
|
+
if (outcome === 'inactive')
|
|
620
|
+
return (0, domain_1.finishedEffect)(effect, 'skipped', now, 'jira_not_connected');
|
|
621
|
+
return (0, domain_1.failedAttempt)(effect, 'The Jira create could not be enqueued', now, 'enqueue_failed');
|
|
622
|
+
}
|
|
623
|
+
case 'jira-review': {
|
|
624
|
+
const create = all.find((candidate) => candidate.kind === 'jira-create');
|
|
625
|
+
if (create && create.status !== 'done')
|
|
626
|
+
return (0, domain_1.finishedEffect)(effect, 'skipped', now, 'no_jira_issue');
|
|
627
|
+
if (!ports.publication.jira.linked(ticketId))
|
|
628
|
+
return (0, domain_1.failedAttempt)(effect, 'Waiting for the Jira issue to be created', now, 'awaiting_issue');
|
|
629
|
+
ports.publication.jira.enqueueReview(ticketId, session.deliveryId ?? session.id);
|
|
630
|
+
return (0, domain_1.finishedEffect)(effect, 'done', now);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
/** Run the due settlement effects of one Flow, in order. Serialized per Flow;
|
|
635
|
+
* a pending effect that is not due yet stops the walk (order is kept). */
|
|
636
|
+
function runSettlement(flowId) {
|
|
637
|
+
return serialized(`settle:${flowId}`, async () => {
|
|
638
|
+
const session = load(flowId);
|
|
639
|
+
for (let guard = 0; guard < 16; guard++) {
|
|
640
|
+
const effects = ports.effects.list(flowId);
|
|
641
|
+
const effect = (0, domain_1.nextDueEffect)(effects, ports.clock.now());
|
|
642
|
+
if (!effect)
|
|
643
|
+
break;
|
|
644
|
+
let next;
|
|
645
|
+
try {
|
|
646
|
+
next = await executeEffect(session, effect, effects);
|
|
647
|
+
}
|
|
648
|
+
catch (error) {
|
|
649
|
+
next = (0, domain_1.failedAttempt)(effect, error instanceof Error ? error.message : String(error), ports.clock.now());
|
|
650
|
+
}
|
|
651
|
+
ports.effects.save(next);
|
|
652
|
+
if (next.status !== 'pending')
|
|
653
|
+
ports.notifier.changed(load(flowId));
|
|
654
|
+
}
|
|
655
|
+
const summary = (0, domain_1.summarizeSettlement)(ports.effects.list(flowId));
|
|
656
|
+
announceDelivered(session, summary);
|
|
657
|
+
return summary;
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* The Flow's closing summary in its conversation, once the spec rewrite and
|
|
662
|
+
* the Jira create settled (done, skipped or failed for good). The Jira
|
|
663
|
+
* review transition may still wait for the issue link: it never holds the
|
|
664
|
+
* summary back. Idempotent by Flow (the conversation dedupes); never throws.
|
|
665
|
+
*/
|
|
666
|
+
function announceDelivered(session, summary) {
|
|
667
|
+
const conversation = ports.conversation;
|
|
668
|
+
if (!conversation?.postDeliveredSummary || session.state !== 'delivered' || session.ticketId === null)
|
|
669
|
+
return;
|
|
670
|
+
const settled = (status) => status !== null && status !== 'pending';
|
|
671
|
+
if (!settled(summary.specRewrite) || !settled(summary.jiraCreate))
|
|
672
|
+
return;
|
|
673
|
+
try {
|
|
674
|
+
conversation.postDeliveredSummary({ conversationId: session.conversationId, flowId: session.id, deliveryId: session.deliveryId, ticketId: session.ticketId, settlement: summary });
|
|
675
|
+
}
|
|
676
|
+
catch (error) {
|
|
677
|
+
log.warn(`[flow] ${session.id} closing summary not posted: ${error instanceof Error ? error.message : String(error)}`);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
/** Startup replay: settle Flows whose delivery reached review while the app
|
|
681
|
+
* was down, return the ones whose run failed outright, then resume every
|
|
682
|
+
* pending effect. Never throws. */
|
|
683
|
+
async function replaySettlement() {
|
|
684
|
+
let resumed = 0;
|
|
685
|
+
for (const session of ports.repository.listHandedOff()) {
|
|
686
|
+
try {
|
|
687
|
+
const state = session.deliveryId ? ports.publication.deliveryState(session.deliveryId) : null;
|
|
688
|
+
if (session.deliveryId && state?.delivered) {
|
|
689
|
+
await onFlowDelivered({ flowId: session.id, deliveryId: session.deliveryId });
|
|
690
|
+
resumed++;
|
|
691
|
+
}
|
|
692
|
+
else if (session.deliveryId && state?.crashed) {
|
|
693
|
+
// A run that failed while the app was down (or before its automatic
|
|
694
|
+
// return completed) goes back to its Flow now.
|
|
695
|
+
if (await autoReturn(session.deliveryId))
|
|
696
|
+
resumed++;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
log.warn(`[flow] settlement replay failed for ${session.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return resumed + await runDueSettlements();
|
|
704
|
+
}
|
|
705
|
+
/** Retry tick: run every Flow with pending effects (due ones execute). */
|
|
706
|
+
async function runDueSettlements() {
|
|
707
|
+
let ran = 0;
|
|
708
|
+
for (const flowId of ports.effects.pendingFlowIds()) {
|
|
709
|
+
try {
|
|
710
|
+
await runSettlement(flowId);
|
|
711
|
+
ran++;
|
|
712
|
+
}
|
|
713
|
+
catch (error) {
|
|
714
|
+
log.warn(`[flow] settlement retry failed for ${flowId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return ran;
|
|
718
|
+
}
|
|
719
|
+
/** Packet view: settlement progress of the Flow a delivery belongs to. */
|
|
720
|
+
function settlementForDelivery(deliveryId) {
|
|
721
|
+
const session = ports.repository.findByDelivery(deliveryId);
|
|
722
|
+
if (!session)
|
|
723
|
+
return null;
|
|
724
|
+
const effects = ports.effects.list(session.id);
|
|
725
|
+
return effects.length ? (0, domain_1.summarizeSettlement)(effects) : { specRewrite: 'pending', jiraCreate: 'pending', jiraReview: 'pending' };
|
|
726
|
+
}
|
|
727
|
+
/** Startup reconciliation (arch 4.7): never leaves a Flow mid-saga or `active` without a session. */
|
|
728
|
+
async function reconcile() {
|
|
729
|
+
const changed = [];
|
|
730
|
+
for (const session of ports.repository.listUnsettled()) {
|
|
731
|
+
try {
|
|
732
|
+
const worktreePresent = session.worktreePath ? ports.worktrees.exists(session.worktreePath) : false;
|
|
733
|
+
const result = (0, domain_1.transition)(session, { type: 'restart', worktreePresent, now: ports.clock.now() });
|
|
734
|
+
if (result.session === session)
|
|
735
|
+
continue;
|
|
736
|
+
try {
|
|
737
|
+
await settle(session, result.effects);
|
|
738
|
+
}
|
|
739
|
+
catch (error) {
|
|
740
|
+
log.warn(`[flow] reconciliation could not compensate ${session.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
741
|
+
changed.push(commit({ ...result.session, state: 'needs-review' }));
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
changed.push(commit(result.session));
|
|
745
|
+
}
|
|
746
|
+
catch (error) {
|
|
747
|
+
log.warn(`[flow] reconciliation failed for ${session.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
return changed;
|
|
751
|
+
}
|
|
752
|
+
function getFlow(flowId) {
|
|
753
|
+
return load(flowId);
|
|
754
|
+
}
|
|
755
|
+
/** The conversation's open Flow, else its latest one (null when it never had a Flow). */
|
|
756
|
+
/** Conversations currently in Flow mode (open, paused or needing review) — the mission list's mark. */
|
|
757
|
+
function listOpen() {
|
|
758
|
+
return ports.repository.listUnsettled().filter((session) => session.state === 'active' || session.state === 'paused' || session.state === 'needs-review');
|
|
759
|
+
}
|
|
760
|
+
function getByConversation(conversationId) {
|
|
761
|
+
return ports.repository.findOpenByConversation(conversationId) ?? ports.repository.latestByConversation(conversationId);
|
|
762
|
+
}
|
|
763
|
+
async function diffSummary(flowId) {
|
|
764
|
+
const session = load(flowId);
|
|
765
|
+
// Measured against the Flow's base (the reservation SHA): committed (frozen
|
|
766
|
+
// at hand-off) and uncommitted work alike. A handed-off Flow still owns the
|
|
767
|
+
// same changes, so the bar never flashes "0 files" around Back to Flow.
|
|
768
|
+
// A needs-review Flow whose worktree survived still shows what it holds.
|
|
769
|
+
if (!session.worktreePath || !((0, domain_1.isOpenFlow)(session) || session.state === 'handed_off' || session.state === 'needs-review') || !ports.worktrees.exists(session.worktreePath)) {
|
|
770
|
+
return { branch: session.branch, baseSha: session.baseSha, headSha: session.headSha, files: [], totals: { files: 0, additions: 0, deletions: 0 } };
|
|
771
|
+
}
|
|
772
|
+
return ports.worktrees.diff({ worktreePath: session.worktreePath, baseSha: session.baseSha, branch: session.branch, ...repositoryOf(session) });
|
|
773
|
+
}
|
|
774
|
+
function costSoFar(flowId) {
|
|
775
|
+
const session = load(flowId);
|
|
776
|
+
const to = (0, domain_1.isOpenFlow)(session) ? null : session.updatedAt;
|
|
777
|
+
return { flowId, ...ports.usage.costSoFar({ conversationId: session.conversationId, from: session.createdAt, to }) };
|
|
778
|
+
}
|
|
779
|
+
return {
|
|
780
|
+
startFlow,
|
|
781
|
+
pauseFlow,
|
|
782
|
+
resumeFlow,
|
|
783
|
+
discardFlow,
|
|
784
|
+
closeFlow,
|
|
785
|
+
handOffFlow,
|
|
786
|
+
returnToFlow,
|
|
787
|
+
relaunchFlow,
|
|
788
|
+
briefingDelivered,
|
|
789
|
+
renewSession,
|
|
790
|
+
onFlowDelivered,
|
|
791
|
+
observeDelivery,
|
|
792
|
+
onRailRunCompleted,
|
|
793
|
+
runSettlement,
|
|
794
|
+
replaySettlement,
|
|
795
|
+
runDueSettlements,
|
|
796
|
+
settlementForDelivery,
|
|
797
|
+
reconcile,
|
|
798
|
+
getFlow,
|
|
799
|
+
getByConversation,
|
|
800
|
+
listOpen,
|
|
801
|
+
diffSummary,
|
|
802
|
+
costSoFar,
|
|
803
|
+
availability: () => ports.availability(),
|
|
804
|
+
};
|
|
805
|
+
}
|