specrails-desktop 2.30.2 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -24
- package/client/dist/assets/{ActivityFeedPage-9DZOvIcY.js → ActivityFeedPage-CAhFRUO4.js} +1 -1
- package/client/dist/assets/{AgentBrowserCapture-DqyHbzk7.js → AgentBrowserCapture-Ct4G5lsE.js} +1 -1
- package/client/dist/assets/AgentModeCodePane-DQt9WIvu.js +2 -0
- package/client/dist/assets/{AgentModeJobsPane-CTIHMUKN.js → AgentModeJobsPane-podaJVl9.js} +1 -1
- package/client/dist/assets/AgentsPage-DTZdbW80.js +87 -0
- package/client/dist/assets/AnalyticsPage-BskgGPm0.js +1 -0
- package/client/dist/assets/CodePage-CvtYo1DU.js +2 -0
- package/client/dist/assets/{DesktopAnalyticsPage-CkXUFj3F.js → DesktopAnalyticsPage-Dnf99E8e.js} +1 -1
- package/client/dist/assets/{DocsDialog-PhdCJNVj.js → DocsDialog-DHi36rZ4.js} +1 -1
- package/client/dist/assets/{DocsPage-BY-wDthx.js → DocsPage-DIdVrQz1.js} +1 -1
- package/client/dist/assets/{InteractiveJobComposer-C9I0A4KR.js → InteractiveJobComposer-BHeB2inv.js} +1 -1
- package/client/dist/assets/{JobDetailModal-I_RoQJV4.js → JobDetailModal-CF1SKUHH.js} +1 -1
- package/client/dist/assets/JobDetailPage-De3rY18h.js +1 -0
- package/client/dist/assets/{JobsPage-DcllM4Ip.js → JobsPage-CfAqqJTx.js} +1 -1
- package/client/dist/assets/{LoopBuilderPage-DGm_iuff.js → LoopBuilderPage-DSBMuTb3.js} +2 -2
- package/client/dist/assets/{LoopPreviewModal-BC-TeFdD.js → LoopPreviewModal-B-c37kA0.js} +1 -1
- package/client/dist/assets/LoopsPage-DjnNXdmm.js +1 -0
- package/client/dist/assets/{MinimizedChatsContext-Cs34FPTz.js → MinimizedChatsContext-DIsnQMVz.js} +1 -1
- package/client/dist/assets/PluginsPage-DA5pQ_6u.js +2 -0
- package/client/dist/assets/{ProjectSettingsDialog-nEs-ENrE.js → ProjectSettingsDialog-DA23PSi6.js} +1 -1
- package/client/dist/assets/{TemplatePreviewModal-D4qW-J9B.js → TemplatePreviewModal-Cp7IQ-g2.js} +1 -1
- package/client/dist/assets/TicketDetailModal-BPD2i_0R.js +14 -0
- package/client/dist/assets/{Trans-CPISVji8.js → Trans-cWtExGkC.js} +1 -1
- package/client/dist/assets/addspec-4WmLJmBG.js +1 -0
- package/client/dist/assets/addspec-BRlk8jON.js +1 -0
- package/client/dist/assets/addspec-C7XRejU4.js +1 -0
- package/client/dist/assets/addspec-CHW9xf_X.js +1 -0
- package/client/dist/assets/addspec-DTmRrWrF.js +1 -0
- package/client/dist/assets/addspec-DhmnXER8.js +1 -0
- package/client/dist/assets/addspec-Di41DpYV.js +1 -0
- package/client/dist/assets/addspec-x3mizDxc.js +1 -0
- package/client/dist/assets/agent-BKsuIgIT.js +1 -0
- package/client/dist/assets/agent-Bs9NilfI.js +1 -0
- package/client/dist/assets/agent-C23h684q.js +1 -0
- package/client/dist/assets/agent-CqEjy3Z2.js +1 -0
- package/client/dist/assets/agent-D5DZTks1.js +1 -0
- package/client/dist/assets/agent-DE8hUYPl.js +1 -0
- package/client/dist/assets/agent-DsTuJGSc.js +1 -0
- package/client/dist/assets/agent-DwZM05-x.js +1 -0
- package/client/dist/assets/agents-45GbINfh.js +1 -0
- package/client/dist/assets/agents-BHp0_FQt.js +1 -0
- package/client/dist/assets/agents-Bvyi3y6R.js +1 -0
- package/client/dist/assets/agents-DMKFStHL.js +1 -0
- package/client/dist/assets/agents-DaYcxAr1.js +1 -0
- package/client/dist/assets/agents-IUOgqT5t.js +1 -0
- package/client/dist/assets/agents-ms7TwG16.js +1 -0
- package/client/dist/assets/agents-rzPnqoBR.js +1 -0
- package/client/dist/assets/agentstudio-8TQqBenW.js +1 -0
- package/client/dist/assets/agentstudio-B8Z_mmEX.js +1 -0
- package/client/dist/assets/agentstudio-BZR9YmLs.js +1 -0
- package/client/dist/assets/agentstudio-Bge9pAWb.js +1 -0
- package/client/dist/assets/agentstudio-Bz169Vzt.js +1 -0
- package/client/dist/assets/agentstudio-D6L2jpNi.js +1 -0
- package/client/dist/assets/agentstudio-K2-Z7CL0.js +1 -0
- package/client/dist/assets/agentstudio-Zmgzthv8.js +1 -0
- package/client/dist/assets/analytics-B8Qtptbl.js +1 -0
- package/client/dist/assets/analytics-BHqUazhP.js +1 -0
- package/client/dist/assets/analytics-BPptRY4f.js +1 -0
- package/client/dist/assets/analytics-BxDGOIwf.js +1 -0
- package/client/dist/assets/analytics-C9RaQcE3.js +1 -0
- package/client/dist/assets/analytics-CJIwqrEl.js +1 -0
- package/client/dist/assets/analytics-D_OZdQ9O.js +1 -0
- package/client/dist/assets/analytics-We6lUMI8.js +1 -0
- package/client/dist/assets/builder-3bygQtZi.js +1 -0
- package/client/dist/assets/builder-BiUG9Z5K.js +1 -0
- package/client/dist/assets/builder-CGRz_-zP.js +1 -0
- package/client/dist/assets/builder-CWYPw7Cw.js +1 -0
- package/client/dist/assets/builder-CX1437hF.js +1 -0
- package/client/dist/assets/{builder-CwA4T7gP.js → builder-Cowk9jtL.js} +1 -1
- package/client/dist/assets/builder-DwDexYRE.js +1 -0
- package/client/dist/assets/builder-skfnZ1uC.js +1 -0
- package/client/dist/assets/code-B0O8-p8k.js +1 -0
- package/client/dist/assets/code-B1VLZDhS.js +1 -0
- package/client/dist/assets/code-B86IMAfz.js +1 -0
- package/client/dist/assets/code-Bpj4Ddml.js +1 -0
- package/client/dist/assets/code-BykBZ5-e.js +1 -0
- package/client/dist/assets/code-CHPkOkDS.js +1 -0
- package/client/dist/assets/code-CkUuW4m9.js +1 -0
- package/client/dist/assets/code-cAqaqMTx.js +1 -0
- package/client/dist/assets/{dashboard-Dy2Um-US.js → dashboard-BVq6kRJe.js} +1 -1
- package/client/dist/assets/{dashboard-CHCEkds4.js → dashboard-BaKPPmLH.js} +1 -1
- package/client/dist/assets/{dashboard-CrlTV1ms.js → dashboard-Bm8e4zYG.js} +1 -1
- package/client/dist/assets/{dashboard-WhzOQw1S.js → dashboard-Bt6IesnM.js} +1 -1
- package/client/dist/assets/{dashboard-Cslu_GCH.js → dashboard-C_NQZle_.js} +1 -1
- package/client/dist/assets/{dashboard-DweT3Y4R.js → dashboard-CyZKoGoI.js} +1 -1
- package/client/dist/assets/{dashboard-DUU8-_Rg.js → dashboard-HIUdUBQ0.js} +1 -1
- package/client/dist/assets/{dashboard-Cqmmbh3l.js → dashboard-pm4Mr229.js} +1 -1
- package/client/dist/assets/{dist-js-jwoXo0YD.js → dist-js-BaP-xLOy.js} +1 -1
- package/client/dist/assets/{dist-js-Dj72W6qo.js → dist-js-CLlgOa5a.js} +1 -1
- package/client/dist/assets/format-command-C0D9IPmV.js +1 -0
- package/client/dist/assets/{formatDistanceToNow-ByKli7Q_.js → formatDistanceToNow-DUyzS4rr.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-qrcBaLW1.js → getTimezoneOffsetInMilliseconds-BCIwmmTj.js} +1 -1
- package/client/dist/assets/{i18n-Bf9Ckd10.js → i18n-D21Pr8Sj.js} +2 -2
- package/client/dist/assets/index-BdSDUFnA.css +2 -0
- package/client/dist/assets/index-Ci4-JKDr.js +77 -0
- package/client/dist/assets/{jobs-CVFD8rar.js → jobs-BAls3bWq.js} +1 -1
- package/client/dist/assets/{jobs-DoSaFzAa.js → jobs-B_TeSQxb.js} +1 -1
- package/client/dist/assets/jobs-Bgq-PZkC.js +1 -0
- package/client/dist/assets/jobs-Bpks6doU.js +1 -0
- package/client/dist/assets/jobs-CN_zv4Gr.js +1 -0
- package/client/dist/assets/jobs-DUlWSYq2.js +1 -0
- package/client/dist/assets/{jobs-B-sDHEay.js → jobs-DhxKgWFq.js} +1 -1
- package/client/dist/assets/{jobs-lk1_Dq1U.js → jobs-SwYS2M-B.js} +1 -1
- package/client/dist/assets/nav-BHDiSIVu.js +1 -0
- package/client/dist/assets/nav-CMiYAq4i.js +1 -0
- package/client/dist/assets/nav-CqS7NrDW.js +1 -0
- package/client/dist/assets/nav-D-0M7xfv.js +1 -0
- package/client/dist/assets/nav-D65O6u9I.js +1 -0
- package/client/dist/assets/nav-D_LKYvBr.js +1 -0
- package/client/dist/assets/nav-FDTJmU79.js +1 -0
- package/client/dist/assets/nav-VaB-C4k5.js +1 -0
- package/client/dist/assets/provider-capabilities-BvoExILy.js +1 -0
- package/client/dist/assets/settings-BveOJoaI.js +1 -0
- package/client/dist/assets/settings-Cj1C6F5k.js +1 -0
- package/client/dist/assets/settings-CuVwOpe0.js +1 -0
- package/client/dist/assets/settings-D5X4DfRc.js +1 -0
- package/client/dist/assets/settings-DXwxe-BW.js +1 -0
- package/client/dist/assets/settings-Di81Ba_V.js +1 -0
- package/client/dist/assets/settings-jbLjCYC_.js +1 -0
- package/client/dist/assets/settings-wIZNPFnn.js +1 -0
- package/client/dist/assets/setup-BBiHEO7h.js +1 -0
- package/client/dist/assets/setup-BlTWhNIQ.js +1 -0
- package/client/dist/assets/setup-Bp2L_oiP.js +1 -0
- package/client/dist/assets/setup-CInYXp1-.js +1 -0
- package/client/dist/assets/{setup-CITtPjed.js → setup-CYH3bP6K.js} +1 -1
- package/client/dist/assets/setup-DwcQ921P.js +1 -0
- package/client/dist/assets/setup-PBLjuDSs.js +1 -0
- package/client/dist/assets/setup-bx6FtoBp.js +1 -0
- package/client/dist/assets/{spending-DMnCXy84.js → spending-BCyUxoOI.js} +1 -1
- package/client/dist/assets/{tickets-B8BuAaj5.js → tickets-BL9r1G0e.js} +1 -1
- package/client/dist/assets/{tickets-DpmdE8tv.js → tickets-B_NyHJ8f.js} +1 -1
- package/client/dist/assets/{tickets-B_yh4qQk.js → tickets-BarF1wuG.js} +1 -1
- package/client/dist/assets/{tickets-pAUJkDTu.js → tickets-CclVhpQA.js} +1 -1
- package/client/dist/assets/{tickets-D_yDquEw.js → tickets-CqqOHbli.js} +1 -1
- package/client/dist/assets/{tickets-CFk2n2Or.js → tickets-DCkFSiqt.js} +1 -1
- package/client/dist/assets/{tickets-DQp7JS2R.js → tickets-Djn3ccfT.js} +1 -1
- package/client/dist/assets/{tickets-Bs37scwY.js → tickets-MiHBPsy_.js} +1 -1
- package/client/dist/assets/{useBrowserCaptureSession-CkBJShUw.js → useBrowserCaptureSession-CkVCDzer.js} +1 -1
- package/client/dist/assets/{useDesktop-B4pSBIDd.js → useDesktop-DCP_MHp9.js} +1 -1
- package/client/dist/index.html +25 -24
- package/docs/README.md +7 -3
- package/docs/cli.md +3 -3
- package/docs/codex.md +51 -64
- package/docs/creating-specs.md +36 -4
- package/docs/customizing.md +5 -5
- package/docs/gemini.md +35 -47
- package/docs/getting-started.md +15 -9
- package/docs/guide/de/agents/2-profiles-and-the-balanced-default.md +5 -1
- package/docs/guide/de/agents/4-custom-agents-catalog.md +7 -4
- package/docs/guide/de/getting-started/1-what-is-specrails.md +1 -0
- package/docs/guide/de/getting-started/2-installing-and-first-run.md +1 -0
- package/docs/guide/de/getting-started/4-the-dashboard-tour.md +4 -4
- package/docs/guide/de/integrations/1-ai-providers.md +29 -18
- package/docs/guide/de/integrations/2-plugins.md +3 -3
- package/docs/guide/de/integrations/6-agent-chat.md +8 -1
- package/docs/guide/de/pipeline/1-rails-and-jobs.md +9 -6
- package/docs/guide/de/pipeline/2-the-job-detail-view.md +3 -1
- package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +13 -13
- package/docs/guide/de/pipeline/5-the-loop-builder.md +6 -2
- package/docs/guide/de/specs/2-add-spec-quick-mode.md +6 -1
- package/docs/guide/en/agents/2-profiles-and-the-balanced-default.md +7 -1
- package/docs/guide/en/agents/4-custom-agents-catalog.md +17 -4
- package/docs/guide/en/getting-started/1-what-is-specrails.md +2 -1
- package/docs/guide/en/getting-started/2-installing-and-first-run.md +2 -1
- package/docs/guide/en/getting-started/4-the-dashboard-tour.md +5 -5
- package/docs/guide/en/insights/3-code-explorer.md +5 -0
- package/docs/guide/en/integrations/1-ai-providers.md +63 -22
- package/docs/guide/en/integrations/2-plugins.md +3 -3
- package/docs/guide/en/integrations/6-agent-chat.md +14 -2
- package/docs/guide/en/pipeline/1-rails-and-jobs.md +19 -7
- package/docs/guide/en/pipeline/2-the-job-detail-view.md +3 -1
- package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +25 -11
- package/docs/guide/en/pipeline/5-the-loop-builder.md +7 -2
- package/docs/guide/en/specs/2-add-spec-quick-mode.md +10 -1
- package/docs/guide/es/agents/2-profiles-and-the-balanced-default.md +5 -1
- package/docs/guide/es/agents/4-custom-agents-catalog.md +7 -4
- package/docs/guide/es/getting-started/1-what-is-specrails.md +1 -0
- package/docs/guide/es/getting-started/2-installing-and-first-run.md +1 -0
- package/docs/guide/es/getting-started/4-the-dashboard-tour.md +4 -4
- package/docs/guide/es/integrations/1-ai-providers.md +30 -18
- package/docs/guide/es/integrations/2-plugins.md +3 -3
- package/docs/guide/es/integrations/6-agent-chat.md +8 -1
- package/docs/guide/es/pipeline/1-rails-and-jobs.md +9 -6
- package/docs/guide/es/pipeline/2-the-job-detail-view.md +3 -1
- package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +15 -13
- package/docs/guide/es/pipeline/5-the-loop-builder.md +6 -2
- package/docs/guide/es/specs/2-add-spec-quick-mode.md +6 -1
- package/docs/guide/fr/agents/2-profiles-and-the-balanced-default.md +5 -1
- package/docs/guide/fr/agents/4-custom-agents-catalog.md +7 -4
- package/docs/guide/fr/getting-started/1-what-is-specrails.md +1 -0
- package/docs/guide/fr/getting-started/2-installing-and-first-run.md +1 -0
- package/docs/guide/fr/getting-started/4-the-dashboard-tour.md +4 -4
- package/docs/guide/fr/integrations/1-ai-providers.md +29 -18
- package/docs/guide/fr/integrations/2-plugins.md +3 -3
- package/docs/guide/fr/integrations/6-agent-chat.md +8 -1
- package/docs/guide/fr/pipeline/1-rails-and-jobs.md +9 -6
- package/docs/guide/fr/pipeline/2-the-job-detail-view.md +3 -1
- package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +15 -13
- package/docs/guide/fr/pipeline/5-the-loop-builder.md +6 -2
- package/docs/guide/fr/specs/2-add-spec-quick-mode.md +6 -1
- package/docs/guide/it/agents/2-profiles-and-the-balanced-default.md +5 -1
- package/docs/guide/it/agents/4-custom-agents-catalog.md +7 -4
- package/docs/guide/it/getting-started/1-what-is-specrails.md +1 -0
- package/docs/guide/it/getting-started/2-installing-and-first-run.md +1 -0
- package/docs/guide/it/getting-started/4-the-dashboard-tour.md +4 -4
- package/docs/guide/it/integrations/1-ai-providers.md +28 -18
- package/docs/guide/it/integrations/2-plugins.md +3 -3
- package/docs/guide/it/integrations/6-agent-chat.md +8 -1
- package/docs/guide/it/pipeline/1-rails-and-jobs.md +9 -6
- package/docs/guide/it/pipeline/2-the-job-detail-view.md +3 -1
- package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +13 -13
- package/docs/guide/it/pipeline/5-the-loop-builder.md +6 -2
- package/docs/guide/it/specs/2-add-spec-quick-mode.md +6 -1
- package/docs/guide/ja/agents/2-profiles-and-the-balanced-default.md +6 -1
- package/docs/guide/ja/agents/4-custom-agents-catalog.md +7 -4
- package/docs/guide/ja/getting-started/1-what-is-specrails.md +1 -0
- package/docs/guide/ja/getting-started/2-installing-and-first-run.md +1 -0
- package/docs/guide/ja/getting-started/4-the-dashboard-tour.md +4 -4
- package/docs/guide/ja/integrations/1-ai-providers.md +28 -18
- package/docs/guide/ja/integrations/2-plugins.md +3 -3
- package/docs/guide/ja/integrations/6-agent-chat.md +7 -1
- package/docs/guide/ja/pipeline/1-rails-and-jobs.md +9 -6
- package/docs/guide/ja/pipeline/2-the-job-detail-view.md +3 -1
- package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +14 -13
- package/docs/guide/ja/pipeline/5-the-loop-builder.md +6 -2
- package/docs/guide/ja/specs/2-add-spec-quick-mode.md +6 -1
- package/docs/guide/pt/agents/2-profiles-and-the-balanced-default.md +5 -1
- package/docs/guide/pt/agents/4-custom-agents-catalog.md +7 -4
- package/docs/guide/pt/getting-started/1-what-is-specrails.md +1 -0
- package/docs/guide/pt/getting-started/2-installing-and-first-run.md +1 -0
- package/docs/guide/pt/getting-started/4-the-dashboard-tour.md +4 -4
- package/docs/guide/pt/integrations/1-ai-providers.md +28 -18
- package/docs/guide/pt/integrations/2-plugins.md +3 -3
- package/docs/guide/pt/integrations/6-agent-chat.md +7 -1
- package/docs/guide/pt/pipeline/1-rails-and-jobs.md +9 -6
- package/docs/guide/pt/pipeline/2-the-job-detail-view.md +2 -1
- package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +14 -13
- package/docs/guide/pt/pipeline/5-the-loop-builder.md +6 -2
- package/docs/guide/pt/specs/2-add-spec-quick-mode.md +6 -1
- package/docs/guide/zh/agents/2-profiles-and-the-balanced-default.md +4 -1
- package/docs/guide/zh/agents/4-custom-agents-catalog.md +7 -4
- package/docs/guide/zh/getting-started/1-what-is-specrails.md +1 -0
- package/docs/guide/zh/getting-started/2-installing-and-first-run.md +1 -0
- package/docs/guide/zh/getting-started/4-the-dashboard-tour.md +4 -4
- package/docs/guide/zh/integrations/1-ai-providers.md +26 -18
- package/docs/guide/zh/integrations/2-plugins.md +3 -3
- package/docs/guide/zh/integrations/6-agent-chat.md +6 -1
- package/docs/guide/zh/pipeline/1-rails-and-jobs.md +9 -6
- package/docs/guide/zh/pipeline/2-the-job-detail-view.md +2 -1
- package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +1 -1
- package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +12 -12
- package/docs/guide/zh/pipeline/5-the-loop-builder.md +6 -2
- package/docs/guide/zh/specs/2-add-spec-quick-mode.md +6 -1
- package/docs/internals/README.md +4 -1
- package/docs/internals/adding-a-provider.md +32 -28
- package/docs/internals/api-reference.md +37 -13
- package/docs/internals/architecture.md +5 -5
- package/docs/internals/bundled-framework-build-plan.md +3 -3
- package/docs/internals/code-explorer-story.md +4 -0
- package/docs/internals/configuration.md +17 -5
- package/docs/internals/global-artifacts-alignment-contract.md +1 -1
- package/docs/internals/operations-runbook.md +1 -1
- package/docs/internals/profiles.md +37 -45
- package/docs/internals/project-builder.md +16 -0
- package/docs/kimi.md +291 -0
- package/docs/mcp.md +9 -2
- package/docs/platforms/macos.md +17 -7
- package/docs/platforms/windows.md +9 -4
- package/docs/running-pipelines.md +46 -12
- package/docs/terminal.md +1 -1
- package/docs/tracking-cost.md +25 -6
- package/package.json +4 -2
- package/server/dist/agent-chat-manager.js +74 -32
- package/server/dist/agent-chat-router.js +40 -17
- package/server/dist/agent-cwd-manager.js +14 -7
- package/server/dist/agent-generator.js +69 -85
- package/server/dist/agent-mcp-config.js +17 -11
- package/server/dist/agent-operator-prompt.js +29 -20
- package/server/dist/agent-refine-manager.js +58 -38
- package/server/dist/ai-invocations.js +65 -20
- package/server/dist/attachment-manager.js +49 -15
- package/server/dist/blueprint-chat-manager.js +41 -16
- package/server/dist/blueprint-router.js +40 -6
- package/server/dist/chat-manager.js +165 -89
- package/server/dist/code-explorer-router.js +26 -7
- package/server/dist/contract-refine-runner.js +146 -113
- package/server/dist/core-compat.js +57 -2
- package/server/dist/core-package.js +3 -3
- package/server/dist/core-update-manager.js +17 -1
- package/server/dist/db.js +60 -5
- package/server/dist/desktop-analytics.js +44 -6
- package/server/dist/desktop-router.js +127 -11
- package/server/dist/explore-cwd-manager.js +19 -3
- package/server/dist/feature-flags.js +1 -1
- package/server/dist/file-story-manager.js +3 -3
- package/server/dist/file-summary-generator.js +21 -15
- package/server/dist/file-summary-manager.js +6 -6
- package/server/dist/framework-manager.js +19 -2
- package/server/dist/framework-migration.js +27 -12
- package/server/dist/install-config-path.js +1 -1
- package/server/dist/interactive-job-session.js +8 -6
- package/server/dist/loop-command-catalog.js +27 -10
- package/server/dist/loop-executors.js +59 -27
- package/server/dist/loop-factory.js +2 -2
- package/server/dist/loop-run-manager.js +100 -39
- package/server/dist/loops-router.js +1 -1
- package/server/dist/mcp/guide.js +23 -16
- package/server/dist/mcp/tools/agents.js +47 -41
- package/server/dist/mcp/tools/analytics.js +2 -2
- package/server/dist/mcp/tools/loops.js +2 -2
- package/server/dist/mcp/tools/plugins.js +14 -9
- package/server/dist/mcp/tools/rails.js +12 -13
- package/server/dist/mcp/tools/support.js +1 -1
- package/server/dist/mobile/mobile-router.js +5 -1
- package/server/dist/offline-assemble.js +13 -1
- package/server/dist/path-resolver.js +2 -2
- package/server/dist/plugin-manager.js +391 -106
- package/server/dist/plugins/claude-md-mutation.js +5 -4
- package/server/dist/plugins/drift.js +32 -29
- package/server/dist/plugins/rail-integration.js +13 -2
- package/server/dist/plugins/serena/install.js +25 -17
- package/server/dist/plugins/serena/manifest.js +22 -5
- package/server/dist/plugins/serena/verify.js +46 -16
- package/server/dist/plugins-router.js +59 -8
- package/server/dist/profile-manager.js +148 -36
- package/server/dist/profiles-router.js +311 -82
- package/server/dist/project-registry.js +2 -2
- package/server/dist/project-router-chat.js +17 -8
- package/server/dist/project-router-helpers.js +93 -5
- package/server/dist/project-router-jobs.js +76 -12
- package/server/dist/project-router-loop-runs.js +42 -14
- package/server/dist/project-router-settings.js +31 -10
- package/server/dist/project-router-setup.js +4 -5
- package/server/dist/project-router-spending.js +15 -3
- package/server/dist/project-router-tickets.js +187 -181
- package/server/dist/project-router.js +1 -0
- package/server/dist/proposal-manager.js +125 -85
- package/server/dist/providers/claude-adapter.js +14 -0
- package/server/dist/providers/codex-adapter.js +20 -0
- package/server/dist/providers/gemini-adapter.js +14 -0
- package/server/dist/providers/index.js +18 -1
- package/server/dist/providers/kimi-adapter.js +361 -0
- package/server/dist/providers/kimi-skill-prompt.js +332 -0
- package/server/dist/providers/runtime.js +137 -0
- package/server/dist/queue-manager.js +103 -78
- package/server/dist/rail-isolated-launch.js +1 -1
- package/server/dist/rails-router.js +51 -38
- package/server/dist/result-event.js +5 -0
- package/server/dist/schemas/profile.v1.json +3 -4
- package/server/dist/setup-manager.js +222 -101
- package/server/dist/setup-prerequisites.js +7 -1
- package/server/dist/smash-runner.js +104 -57
- package/server/dist/spawn-lifecycle.js +18 -14
- package/server/dist/spec-launcher-manager.js +66 -54
- package/server/dist/spec-models.js +15 -6
- package/server/dist/spending.js +110 -17
- package/server/dist/util/cli-prompt.js +142 -5
- package/server/dist/util/stream-display.js +46 -0
- package/server/dist/workspace-manager.js +100 -37
- package/server/dist/worktree-manager.js +4 -0
- package/server/dist/worktree-overlay.js +12 -3
- package/client/dist/assets/AgentModeCodePane-BAYyFRmY.js +0 -2
- package/client/dist/assets/AgentsPage-DuyJuaFs.js +0 -86
- package/client/dist/assets/AnalyticsPage-BY7gtCx6.js +0 -1
- package/client/dist/assets/CodePage-vyQr40Vl.js +0 -2
- package/client/dist/assets/JobDetailPage-CU4FEnUC.js +0 -1
- package/client/dist/assets/LoopsPage-SqglnXlp.js +0 -1
- package/client/dist/assets/PluginsPage-B89S8o1a.js +0 -2
- package/client/dist/assets/TicketDetailModal-CI47Dq9E.js +0 -14
- package/client/dist/assets/addspec-BXjvkh5q.js +0 -1
- package/client/dist/assets/addspec-C4bwrmpi.js +0 -1
- package/client/dist/assets/addspec-CArHXUDM.js +0 -1
- package/client/dist/assets/addspec-DTKJcXiR.js +0 -1
- package/client/dist/assets/addspec-DbNBbrha.js +0 -1
- package/client/dist/assets/addspec-Rw8uVBC1.js +0 -1
- package/client/dist/assets/addspec-htHGZHOe.js +0 -1
- package/client/dist/assets/addspec-lr_LP6jk.js +0 -1
- package/client/dist/assets/agent-BABjRt0P.js +0 -1
- package/client/dist/assets/agent-BuUpgqVx.js +0 -1
- package/client/dist/assets/agent-CCDZesgU.js +0 -1
- package/client/dist/assets/agent-CVn64zWH.js +0 -1
- package/client/dist/assets/agent-CWeOny0E.js +0 -1
- package/client/dist/assets/agent-DOysmad_.js +0 -1
- package/client/dist/assets/agent-DSsjTBhn.js +0 -1
- package/client/dist/assets/agent-DlZMxfM9.js +0 -1
- package/client/dist/assets/agents-6ZOJXWVk.js +0 -1
- package/client/dist/assets/agents-BZ0XQKjg.js +0 -1
- package/client/dist/assets/agents-BqWklnHR.js +0 -1
- package/client/dist/assets/agents-Bz-thHkB.js +0 -1
- package/client/dist/assets/agents-CJclElx6.js +0 -1
- package/client/dist/assets/agents-D_l9L0VA.js +0 -1
- package/client/dist/assets/agents-DhG7mg6-.js +0 -1
- package/client/dist/assets/agents-u_C0jPB5.js +0 -1
- package/client/dist/assets/agentstudio-BF19hbXj.js +0 -1
- package/client/dist/assets/agentstudio-BIUe1Im2.js +0 -1
- package/client/dist/assets/agentstudio-BLGvxWBx.js +0 -1
- package/client/dist/assets/agentstudio-D9UKiWTj.js +0 -1
- package/client/dist/assets/agentstudio-Drs37nIM.js +0 -1
- package/client/dist/assets/agentstudio-nEnKkcXM.js +0 -1
- package/client/dist/assets/agentstudio-pyFcSBKy.js +0 -1
- package/client/dist/assets/agentstudio-zfTzQh3U.js +0 -1
- package/client/dist/assets/analytics-BC7mwR4s.js +0 -1
- package/client/dist/assets/analytics-BiNg8edP.js +0 -1
- package/client/dist/assets/analytics-C0s_T2GN.js +0 -1
- package/client/dist/assets/analytics-CdsAPAwZ.js +0 -1
- package/client/dist/assets/analytics-Cr1_q-lC.js +0 -1
- package/client/dist/assets/analytics-DZ8Aoq3I.js +0 -1
- package/client/dist/assets/analytics-IEsKZvpW.js +0 -1
- package/client/dist/assets/analytics-SRPf84OT.js +0 -1
- package/client/dist/assets/builder-BH8Fua-g.js +0 -1
- package/client/dist/assets/builder-BoV7DgKd.js +0 -1
- package/client/dist/assets/builder-Cc_Lf79C.js +0 -1
- package/client/dist/assets/builder-CwZ7Bme2.js +0 -1
- package/client/dist/assets/builder-CxW-JFsR.js +0 -1
- package/client/dist/assets/builder-D94lrV7x.js +0 -1
- package/client/dist/assets/builder-cqHpCyGa.js +0 -1
- package/client/dist/assets/code-76gS0IdL.js +0 -1
- package/client/dist/assets/code-BDXEM4ml.js +0 -1
- package/client/dist/assets/code-C1VwxlML.js +0 -1
- package/client/dist/assets/code-CnMZyJpr.js +0 -1
- package/client/dist/assets/code-D20ef9Cf.js +0 -1
- package/client/dist/assets/code-DdOXaWRY.js +0 -1
- package/client/dist/assets/code-Duohuf9l.js +0 -1
- package/client/dist/assets/code-geHmknB9.js +0 -1
- package/client/dist/assets/format-command-Dfa1o2d-.js +0 -1
- package/client/dist/assets/index-Dh9i4CnN.css +0 -2
- package/client/dist/assets/index-F9r8mWP_.js +0 -76
- package/client/dist/assets/jobs-BCtGfgUA.js +0 -1
- package/client/dist/assets/jobs-BHR_EnDI.js +0 -1
- package/client/dist/assets/jobs-BMbZJjJJ.js +0 -1
- package/client/dist/assets/jobs-DzSIR8V6.js +0 -1
- package/client/dist/assets/nav-BRJBxaGt.js +0 -1
- package/client/dist/assets/nav-CAGKv3_F.js +0 -1
- package/client/dist/assets/nav-CNskRJKQ.js +0 -1
- package/client/dist/assets/nav-DY93irBL.js +0 -1
- package/client/dist/assets/nav-DhjvYgqt.js +0 -1
- package/client/dist/assets/nav-Gb-r4wop.js +0 -1
- package/client/dist/assets/nav-TvumAFD2.js +0 -1
- package/client/dist/assets/nav-myFaXRHD.js +0 -1
- package/client/dist/assets/settings-B0ypw9uw.js +0 -1
- package/client/dist/assets/settings-B9ilOSYO.js +0 -1
- package/client/dist/assets/settings-BqlWHRHA.js +0 -1
- package/client/dist/assets/settings-D8dlqt4d.js +0 -1
- package/client/dist/assets/settings-DAZqjX2a.js +0 -1
- package/client/dist/assets/settings-DRh39v1S.js +0 -1
- package/client/dist/assets/settings-Mj1OJbfd.js +0 -1
- package/client/dist/assets/settings-lRReaSYm.js +0 -1
- package/client/dist/assets/setup-3832BJCo.js +0 -1
- package/client/dist/assets/setup-B8J-gECe.js +0 -1
- package/client/dist/assets/setup-BCIOxVsc.js +0 -1
- package/client/dist/assets/setup-BciLj_tU.js +0 -1
- package/client/dist/assets/setup-CTkE3cfh.js +0 -1
- package/client/dist/assets/setup-ajB4rYm-.js +0 -1
- package/client/dist/assets/setup-xFO1wNl0.js +0 -1
|
@@ -4,6 +4,7 @@ exports.isProjectBuilderEnabled = isProjectBuilderEnabled;
|
|
|
4
4
|
exports.createBlueprintRouter = createBlueprintRouter;
|
|
5
5
|
const express_1 = require("express");
|
|
6
6
|
const providers_1 = require("./providers");
|
|
7
|
+
const runtime_1 = require("./providers/runtime");
|
|
7
8
|
const blueprint_store_1 = require("./blueprint-store");
|
|
8
9
|
function isProjectBuilderEnabled() {
|
|
9
10
|
return process.env.SPECRAILS_PROJECT_BUILDER !== 'false';
|
|
@@ -32,11 +33,19 @@ function createBlueprintRouter(deps) {
|
|
|
32
33
|
router.get('/models', (req, res) => {
|
|
33
34
|
const provider = validProvider(req.query.provider) ?? 'claude';
|
|
34
35
|
const adapter = (0, providers_1.getAdapter)(provider);
|
|
36
|
+
const toolPolicy = (0, runtime_1.pureOutputToolPolicy)(adapter);
|
|
37
|
+
const requestedModel = typeof req.query.model === 'string' && req.query.model
|
|
38
|
+
? req.query.model
|
|
39
|
+
: null;
|
|
40
|
+
const model = requestedModel ?? adapter.defaultModel();
|
|
35
41
|
res.json({
|
|
36
42
|
provider,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
available: toolPolicy !== null,
|
|
44
|
+
toolPolicy,
|
|
45
|
+
models: toolPolicy ? adapter.modelCatalog() : [],
|
|
46
|
+
defaultModel: toolPolicy ? adapter.defaultModel() : null,
|
|
47
|
+
model,
|
|
48
|
+
efforts: toolPolicy ? (0, providers_1.reasoningEffortsForModel)(adapter, model) : [],
|
|
40
49
|
});
|
|
41
50
|
});
|
|
42
51
|
router.get('/conversations', (_req, res) => {
|
|
@@ -45,6 +54,10 @@ function createBlueprintRouter(deps) {
|
|
|
45
54
|
router.post('/conversations', (req, res) => {
|
|
46
55
|
const body = (req.body ?? {});
|
|
47
56
|
const provider = validProvider(body.provider) ?? 'claude';
|
|
57
|
+
if (!(0, runtime_1.pureOutputToolPolicy)((0, providers_1.getAdapter)(provider))) {
|
|
58
|
+
res.status(409).json({ error: 'provider_tool_policy_unsupported', provider });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
48
61
|
const model = typeof body.model === 'string' && body.model ? body.model : null;
|
|
49
62
|
const conversation = (0, blueprint_store_1.createBlueprintConversation)(desktopDb, { provider, model });
|
|
50
63
|
res.status(201).json({ conversation });
|
|
@@ -71,6 +84,10 @@ function createBlueprintRouter(deps) {
|
|
|
71
84
|
res.status(400).json({ error: 'invalid provider' });
|
|
72
85
|
return;
|
|
73
86
|
}
|
|
87
|
+
if (!(0, runtime_1.pureOutputToolPolicy)((0, providers_1.getAdapter)(provider))) {
|
|
88
|
+
res.status(409).json({ error: 'provider_tool_policy_unsupported', provider });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
74
91
|
patch.provider = provider;
|
|
75
92
|
if (provider !== conversation.provider) {
|
|
76
93
|
// A session id is provider-local; a switch must reset it and the model.
|
|
@@ -85,8 +102,7 @@ function createBlueprintRouter(deps) {
|
|
|
85
102
|
}
|
|
86
103
|
const effectiveProvider = patch.provider ?? conversation.provider;
|
|
87
104
|
if (typeof body.model === 'string' && body.model) {
|
|
88
|
-
|
|
89
|
-
if (!valid.has(body.model)) {
|
|
105
|
+
if (!(0, providers_1.isModelAvailableForAdapter)((0, providers_1.getAdapter)(effectiveProvider), body.model)) {
|
|
90
106
|
res.status(400).json({ error: 'model not in provider catalog' });
|
|
91
107
|
return;
|
|
92
108
|
}
|
|
@@ -132,10 +148,28 @@ function createBlueprintRouter(deps) {
|
|
|
132
148
|
res.status(409).json({ error: 'a turn is already streaming' });
|
|
133
149
|
return;
|
|
134
150
|
}
|
|
151
|
+
const adapter = (0, providers_1.getAdapter)(conversation.provider);
|
|
152
|
+
if (!(0, runtime_1.pureOutputToolPolicy)(adapter)) {
|
|
153
|
+
res.status(409).json({
|
|
154
|
+
error: 'provider_tool_policy_unsupported',
|
|
155
|
+
provider: conversation.provider,
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (body.model !== undefined
|
|
160
|
+
&& body.model !== null
|
|
161
|
+
&& !(0, providers_1.isModelAvailableForAdapter)(adapter, body.model)) {
|
|
162
|
+
res.status(400).json({ error: 'model not in provider catalog' });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
135
165
|
const model = typeof body.model === 'string' && body.model ? body.model : undefined;
|
|
166
|
+
const effectiveModel = model
|
|
167
|
+
?? (conversation.model && (0, providers_1.isModelAvailableForAdapter)(adapter, conversation.model)
|
|
168
|
+
? conversation.model
|
|
169
|
+
: adapter.defaultModel());
|
|
136
170
|
let reasoningEffort;
|
|
137
171
|
if (body.reasoning_effort !== undefined) {
|
|
138
|
-
const allowedEfforts = (0, providers_1.
|
|
172
|
+
const allowedEfforts = (0, providers_1.reasoningEffortsForModel)(adapter, effectiveModel);
|
|
139
173
|
if (typeof body.reasoning_effort !== 'string'
|
|
140
174
|
|| !allowedEfforts.includes(body.reasoning_effort)) {
|
|
141
175
|
res.status(400).json({ error: 'reasoning effort not in provider catalog' });
|
|
@@ -17,6 +17,7 @@ const crypto_1 = require("crypto");
|
|
|
17
17
|
const spec_draft_parser_1 = require("./spec-draft-parser");
|
|
18
18
|
const attachment_manager_1 = require("./attachment-manager");
|
|
19
19
|
const providers_1 = require("./providers");
|
|
20
|
+
const runtime_1 = require("./providers/runtime");
|
|
20
21
|
const context_scope_1 = require("./context-scope");
|
|
21
22
|
const user_mcp_config_1 = require("./user-mcp-config");
|
|
22
23
|
const binary_probe_1 = require("./binary-probe");
|
|
@@ -24,6 +25,7 @@ const explore_stdin_session_1 = require("./explore-stdin-session");
|
|
|
24
25
|
const workspace_resolution_1 = require("./workspace-resolution");
|
|
25
26
|
const workspace_manager_1 = require("./workspace-manager");
|
|
26
27
|
const blueprint_render_1 = require("./blueprint-render");
|
|
28
|
+
const explore_draft_title_1 = require("./explore-draft-title");
|
|
27
29
|
const COMMAND_INSTRUCTION = 'When you want to suggest a SpecRails command for the user to execute, wrap it in a command block like this: ' +
|
|
28
30
|
':::command\n/specrails:implement #42\n::: ' +
|
|
29
31
|
'The user will be prompted to confirm before the command runs.';
|
|
@@ -607,6 +609,12 @@ class ChatManager {
|
|
|
607
609
|
const successRate = stats.totalJobs > 0
|
|
608
610
|
? Math.round(((stats.totalJobs - stats.failedJobs) / stats.totalJobs) * 100)
|
|
609
611
|
: null;
|
|
612
|
+
const totalCost = stats.unpricedRuns > 0 && stats.pricedRuns === 0
|
|
613
|
+
? 'unavailable'
|
|
614
|
+
: `${stats.unpricedRuns > 0 ? 'at least ' : ''}$${stats.totalCostUsd.toFixed(3)}`;
|
|
615
|
+
const todayCost = stats.unpricedTodayRuns > 0 && stats.pricedTodayRuns === 0
|
|
616
|
+
? 'unavailable'
|
|
617
|
+
: `${stats.unpricedTodayRuns > 0 ? 'at least ' : ''}$${stats.costToday.toFixed(3)}`;
|
|
610
618
|
return (`## Current Dashboard Context\n\n` +
|
|
611
619
|
`### Active Job\n${activeLine}\n\n` +
|
|
612
620
|
(jobLines.length > 0 ? `### Recent Jobs\n${jobLines.join('\n')}\n\n` : '') +
|
|
@@ -614,8 +622,8 @@ class ChatManager {
|
|
|
614
622
|
`- Total jobs: ${stats.totalJobs}\n` +
|
|
615
623
|
`- Jobs today: ${stats.jobsToday}\n` +
|
|
616
624
|
(successRate != null ? `- Overall success rate: ${successRate}%\n` : '') +
|
|
617
|
-
`- Total cost:
|
|
618
|
-
`- Cost today:
|
|
625
|
+
`- Total cost: ${totalCost}\n` +
|
|
626
|
+
`- Cost today: ${todayCost}`);
|
|
619
627
|
}
|
|
620
628
|
catch {
|
|
621
629
|
// Context is best-effort; fall back gracefully
|
|
@@ -781,6 +789,15 @@ class ChatManager {
|
|
|
781
789
|
// provider wins; null/legacy conversations fall back to the project
|
|
782
790
|
// primary (this._adapter). Resolved once and used for the whole turn.
|
|
783
791
|
const adapter = this._adapterForConversation(conversation);
|
|
792
|
+
if (conversation.kind === 'milestone' && !(0, runtime_1.supportsToolPolicy)(adapter, 'read-only')) {
|
|
793
|
+
this._broadcast({
|
|
794
|
+
type: 'chat_error',
|
|
795
|
+
conversationId,
|
|
796
|
+
error: 'provider_tool_policy_unsupported',
|
|
797
|
+
timestamp: new Date().toISOString(),
|
|
798
|
+
});
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
784
801
|
if (!(0, binary_probe_1.binaryOnPath)(adapter.binary)) {
|
|
785
802
|
this._broadcast({
|
|
786
803
|
type: 'chat_error',
|
|
@@ -824,19 +841,57 @@ class ChatManager {
|
|
|
824
841
|
role: 'user',
|
|
825
842
|
content: userText,
|
|
826
843
|
});
|
|
827
|
-
|
|
828
|
-
|
|
844
|
+
const lightweight = options?.lightweight ?? false;
|
|
845
|
+
const conversationScope = this._resolveConversationScope(conversation);
|
|
846
|
+
const spawnCwd = this._resolveSpawnCwd(conversation.kind, conversationScope, adapter.id);
|
|
847
|
+
// Kimi print mode does not run the TUI slash-command interceptor. Resolve
|
|
848
|
+
// its project skill before the generic `.claude/commands` fallback can fold
|
|
849
|
+
// provider-incompatible content. Other adapters retain the legacy resolver.
|
|
850
|
+
const isDesktopExploreDraftCommand = /^\/specrails:explore-spec(?:\s|$)/.test(userText);
|
|
851
|
+
let resolvedText;
|
|
852
|
+
try {
|
|
853
|
+
resolvedText = adapter.capabilities.materializeHeadlessSkills
|
|
854
|
+
&& !isDesktopExploreDraftCommand
|
|
855
|
+
? (0, runtime_1.formatProviderCommand)(adapter, userText, spawnCwd, conversation.session_id ?? undefined)
|
|
856
|
+
: (0, command_resolver_1.resolveCommand)(userText, this._cwd ?? process.cwd());
|
|
857
|
+
}
|
|
858
|
+
catch (err) {
|
|
859
|
+
// Headless skill resolution is deliberately fail-closed (sending the
|
|
860
|
+
// unresolved slash text to Kimi print mode would silently do the wrong
|
|
861
|
+
// thing), but this happens after an Explore slot is claimed. Surface an
|
|
862
|
+
// actionable chat error and release the slot just like a terminal child
|
|
863
|
+
// instead of leaving the conversation permanently marked as streaming.
|
|
864
|
+
if (conversation.kind === 'explore') {
|
|
865
|
+
const life = this._exploreLifecycle.get(conversationId);
|
|
866
|
+
if (life) {
|
|
867
|
+
life.isStreaming = false;
|
|
868
|
+
life.lastActivityAt = Date.now();
|
|
869
|
+
if (life.isMinimized)
|
|
870
|
+
this._startIdleTimer(conversationId);
|
|
871
|
+
}
|
|
872
|
+
this._drainExploreQueue();
|
|
873
|
+
}
|
|
874
|
+
this._broadcast({
|
|
875
|
+
type: 'chat_error',
|
|
876
|
+
conversationId,
|
|
877
|
+
error: err instanceof Error ? err.message : String(err),
|
|
878
|
+
timestamp: new Date().toISOString(),
|
|
879
|
+
});
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
829
882
|
// Fold attachments into the prompt as <user-attachment> text blocks under
|
|
830
883
|
// an "## Attached Resources" section, mirroring how /generate-spec wires
|
|
831
884
|
// them. Errors during extraction are logged and skipped — the chat turn
|
|
832
885
|
// proceeds without that attachment rather than failing.
|
|
833
886
|
let hasAttachments = false;
|
|
887
|
+
let attachmentImagePaths = [];
|
|
834
888
|
if (options?.attachments && options.attachments.ids.length > 0) {
|
|
835
889
|
try {
|
|
836
890
|
const attachmentResult = await this._awaitWhileLive(attachment_manager_1.attachmentManager.getClaudeArgs(options.attachments.slug, options.attachments.ticketKey, options.attachments.ids));
|
|
837
891
|
if (attachmentResult.disposed)
|
|
838
892
|
return;
|
|
839
|
-
const { textBlocks } = attachmentResult.value;
|
|
893
|
+
const { textBlocks, imagePaths } = attachmentResult.value;
|
|
894
|
+
attachmentImagePaths = imagePaths;
|
|
840
895
|
if (textBlocks.length > 0) {
|
|
841
896
|
resolvedText = `${resolvedText}\n\n## Attached Resources\n\n${textBlocks.join('\n\n')}`;
|
|
842
897
|
hasAttachments = true;
|
|
@@ -853,8 +908,6 @@ class ChatManager {
|
|
|
853
908
|
// Build spawn args via the resolved adapter. System prompt placement
|
|
854
909
|
// (--system-prompt flag vs prompt-fold) and resume vs fresh-turn are both
|
|
855
910
|
// adapter-driven via capability flags.
|
|
856
|
-
const lightweight = options?.lightweight ?? false;
|
|
857
|
-
const conversationScope = this._resolveConversationScope(conversation);
|
|
858
911
|
let systemPrompt = conversation.kind === 'milestone'
|
|
859
912
|
? this._buildMilestoneSystemPrompt(conversation)
|
|
860
913
|
: lightweight
|
|
@@ -863,7 +916,10 @@ class ChatManager {
|
|
|
863
916
|
if (hasAttachments)
|
|
864
917
|
systemPrompt = `${systemPrompt}\n\n${attachment_manager_1.USER_ATTACHMENT_SYSTEM_NOTE}`;
|
|
865
918
|
const binary = adapter.binary;
|
|
866
|
-
const
|
|
919
|
+
const requestedModel = conversation.model;
|
|
920
|
+
const model = requestedModel && (0, providers_1.isModelAvailableForAdapter)(adapter, requestedModel)
|
|
921
|
+
? requestedModel
|
|
922
|
+
: adapter.defaultModel();
|
|
867
923
|
const action = conversation.session_id && adapter.capabilities.nativeResume
|
|
868
924
|
? 'chat-resume'
|
|
869
925
|
: 'chat-turn';
|
|
@@ -921,23 +977,34 @@ class ChatManager {
|
|
|
921
977
|
`## User turn\n\n${resolvedText}`;
|
|
922
978
|
}
|
|
923
979
|
}
|
|
980
|
+
const foldProjectChatSystemPrompt = !adapter.capabilities.systemPromptArg &&
|
|
981
|
+
adapter.capabilities.foldProjectChatSystemPrompt === true;
|
|
924
982
|
// Sidebar turns: the volatile dashboard snapshot lives in the user turn
|
|
925
983
|
// (not --system-prompt) so the cacheable system-prompt prefix stays
|
|
926
984
|
// byte-stable across turns — same pattern as the codex scoped-context
|
|
927
|
-
// prepend above.
|
|
928
|
-
//
|
|
929
|
-
|
|
930
|
-
// must not start receiving it here.
|
|
931
|
-
if (!lightweight && adapter.capabilities.systemPromptArg) {
|
|
985
|
+
// prepend above. Kimi explicitly requests the same dynamic context through
|
|
986
|
+
// a folded prompt; Codex/Gemini keep their cwd-instruction-file contract.
|
|
987
|
+
if (!lightweight && (adapter.capabilities.systemPromptArg || foldProjectChatSystemPrompt)) {
|
|
932
988
|
const dashboardContext = this._buildDashboardContextBlock();
|
|
933
989
|
if (dashboardContext) {
|
|
934
990
|
promptForAdapter = `${dashboardContext}\n\n## User turn\n\n${promptForAdapter}`;
|
|
935
991
|
}
|
|
936
992
|
}
|
|
993
|
+
// Kimi prompt mode has no native system-prompt argument. Fold the stable
|
|
994
|
+
// sidebar contract exactly once here, after adding volatile dashboard
|
|
995
|
+
// context. Explore is intentionally excluded: its isolated cwd already
|
|
996
|
+
// contains provider-native AGENTS.md framing, while the scoped project
|
|
997
|
+
// context above remains per-turn. Milestone already folded its complete
|
|
998
|
+
// contract earlier in this function.
|
|
999
|
+
if (foldProjectChatSystemPrompt &&
|
|
1000
|
+
conversation.kind !== 'explore' &&
|
|
1001
|
+
conversation.kind !== 'milestone') {
|
|
1002
|
+
promptForAdapter = `${systemPrompt}\n\n---\n\n${promptForAdapter}`;
|
|
1003
|
+
}
|
|
937
1004
|
const buildRecoveryPrompt = () => buildResumeRecoveryPrompt((0, db_1.getMessages)(this._db, conversationId)
|
|
938
1005
|
.filter((message) => message.id !== persistedUserMessage.id)
|
|
939
1006
|
.map((message) => ({ role: message.role, content: message.content })), promptForAdapter);
|
|
940
|
-
|
|
1007
|
+
const turnOptions = {
|
|
941
1008
|
prompt: promptForAdapter,
|
|
942
1009
|
systemPrompt,
|
|
943
1010
|
model,
|
|
@@ -952,14 +1019,15 @@ class ChatManager {
|
|
|
952
1019
|
// plugin, and connector MCP servers — which require the `user` setting
|
|
953
1020
|
// source. Claude-only (codex reads ~/.codex natively, ignores this).
|
|
954
1021
|
loadUserEnv: adapter.id === 'claude' && !!conversationScope?.userMcp,
|
|
955
|
-
|
|
1022
|
+
imagePaths: adapter.capabilities.supportsImageInput ? attachmentImagePaths : undefined,
|
|
1023
|
+
};
|
|
1024
|
+
let args = adapter.buildArgs(action, turnOptions);
|
|
956
1025
|
if (conversationScope) {
|
|
957
1026
|
console.log(`[chat-manager] scope=${JSON.stringify(conversationScope)} flags=${scopeFlags.join(' ')} promptBytes=${Buffer.byteLength(systemPrompt)}`);
|
|
958
1027
|
}
|
|
959
1028
|
// No OTEL env injection here — ChatManager spawns are interactive user sessions,
|
|
960
1029
|
// not pipeline jobs. Telemetry is scoped to QueueManager pipeline runs only.
|
|
961
1030
|
// spawnAiCli reroutes multi-line argv values through stdin on Windows.
|
|
962
|
-
const spawnCwd = this._resolveSpawnCwd(conversation.kind, conversationScope, adapter.id);
|
|
963
1031
|
// Relocate-artifacts env for gated spawns: NON-explore (sidebar) turns, and
|
|
964
1032
|
// Explore turns with `contextScope.mcp` (they spawn from the workspace when
|
|
965
1033
|
// relocated — see `_resolveSpawnCwd`; the env makes the workspace's
|
|
@@ -979,6 +1047,7 @@ class ChatManager {
|
|
|
979
1047
|
spawnEnv = { ...spawnEnv, GEMINI_CLI_TRUST_WORKSPACE: 'true' };
|
|
980
1048
|
}
|
|
981
1049
|
}
|
|
1050
|
+
spawnEnv = (0, runtime_1.buildProviderEnv)(adapter, turnOptions, spawnEnv);
|
|
982
1051
|
const allowMissingSessionRecovery = adapter.id === 'claude' &&
|
|
983
1052
|
conversation.kind === 'explore' &&
|
|
984
1053
|
exploreMcp &&
|
|
@@ -1085,42 +1154,30 @@ class ChatManager {
|
|
|
1085
1154
|
const readerHandler = (line) => {
|
|
1086
1155
|
if (this._disposed)
|
|
1087
1156
|
return;
|
|
1088
|
-
const ev
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
if (ev.sessionId)
|
|
1101
|
-
capturedSessionId = ev.sessionId;
|
|
1102
|
-
break;
|
|
1103
|
-
case 'result':
|
|
1104
|
-
sawResult = true;
|
|
1105
|
-
// Claude's result event carries the canonical (post-rotation)
|
|
1106
|
-
// session_id; codex captures from thread.started but mirroring here
|
|
1107
|
-
// is harmless.
|
|
1108
|
-
{
|
|
1157
|
+
for (const ev of (0, runtime_1.parseStreamEvents)(adapter, line)) {
|
|
1158
|
+
adapterEvents.push(ev);
|
|
1159
|
+
switch (ev.kind) {
|
|
1160
|
+
case 'text-delta':
|
|
1161
|
+
emitDelta(ev.text);
|
|
1162
|
+
break;
|
|
1163
|
+
case 'session-started':
|
|
1164
|
+
if (ev.sessionId)
|
|
1165
|
+
capturedSessionId = ev.sessionId;
|
|
1166
|
+
break;
|
|
1167
|
+
case 'result': {
|
|
1168
|
+
sawResult = true;
|
|
1109
1169
|
const sid = ev.payload.session_id;
|
|
1110
1170
|
if (sid)
|
|
1111
1171
|
capturedSessionId = sid;
|
|
1172
|
+
break;
|
|
1112
1173
|
}
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
case 'other':
|
|
1121
|
-
// No-op for ChatManager — adapter parses tool_use into the unified
|
|
1122
|
-
// event shape but the chat UI does not currently surface them.
|
|
1123
|
-
break;
|
|
1174
|
+
case 'error':
|
|
1175
|
+
capturedErrorMessage = ev.message;
|
|
1176
|
+
break;
|
|
1177
|
+
case 'tool-use':
|
|
1178
|
+
case 'other':
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1124
1181
|
}
|
|
1125
1182
|
};
|
|
1126
1183
|
stdoutReader.on('line', readerHandler);
|
|
@@ -1440,7 +1497,7 @@ class ChatManager {
|
|
|
1440
1497
|
// AND sidebar (surface='chat-sidebar') turns — see _recordChatInvocation.
|
|
1441
1498
|
const invStatus = wasAborting
|
|
1442
1499
|
? 'aborted'
|
|
1443
|
-
: code === 0
|
|
1500
|
+
: code === 0 && !capturedErrorMessage
|
|
1444
1501
|
? 'success'
|
|
1445
1502
|
: 'failed';
|
|
1446
1503
|
this._recordChatInvocation({
|
|
@@ -1457,7 +1514,7 @@ class ChatManager {
|
|
|
1457
1514
|
complete();
|
|
1458
1515
|
return;
|
|
1459
1516
|
}
|
|
1460
|
-
if (code === 0) {
|
|
1517
|
+
if (code === 0 && !capturedErrorMessage) {
|
|
1461
1518
|
// Parse out any spec-draft fenced blocks (Explore Spec protocol).
|
|
1462
1519
|
// No-op for non-Explore conversations (parser pre-checks for the fence
|
|
1463
1520
|
// marker and returns the original text unchanged).
|
|
@@ -1603,8 +1660,10 @@ class ChatManager {
|
|
|
1603
1660
|
if (!this._projectId)
|
|
1604
1661
|
return;
|
|
1605
1662
|
try {
|
|
1663
|
+
const finishedAt = new Date().toISOString();
|
|
1606
1664
|
const { result, estimated } = (0, result_event_1.finaliseInvocationResult)(adapter, adapterEvents, {
|
|
1607
1665
|
fallbackModel: model,
|
|
1666
|
+
durationMs: Math.max(0, Date.parse(finishedAt) - Date.parse(turnStartedAt)),
|
|
1608
1667
|
});
|
|
1609
1668
|
// MED-1: the persistent-stdin transport reuses ONE long-lived child for
|
|
1610
1669
|
// the whole session, so claude's `result` event reports
|
|
@@ -1646,7 +1705,7 @@ class ChatManager {
|
|
|
1646
1705
|
conversation_id: conversationId,
|
|
1647
1706
|
status,
|
|
1648
1707
|
started_at: turnStartedAt,
|
|
1649
|
-
finished_at:
|
|
1708
|
+
finished_at: finishedAt,
|
|
1650
1709
|
total_cost_usd_estimated: estimated,
|
|
1651
1710
|
// Non-cumulative fields (model, durations, session_id) pass through.
|
|
1652
1711
|
...result,
|
|
@@ -1843,33 +1902,31 @@ class ChatManager {
|
|
|
1843
1902
|
const onLine = (line) => {
|
|
1844
1903
|
if (this._disposed || settled)
|
|
1845
1904
|
return;
|
|
1846
|
-
const ev
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1905
|
+
for (const ev of (0, runtime_1.parseStreamEvents)(adapter, line)) {
|
|
1906
|
+
adapterEvents.push(ev);
|
|
1907
|
+
switch (ev.kind) {
|
|
1908
|
+
case 'text-delta':
|
|
1909
|
+
emitDelta(ev.text);
|
|
1910
|
+
break;
|
|
1911
|
+
case 'session-started':
|
|
1912
|
+
if (ev.sessionId)
|
|
1913
|
+
capturedSessionId = ev.sessionId;
|
|
1914
|
+
break;
|
|
1915
|
+
case 'result': {
|
|
1916
|
+
const payload = ev.payload;
|
|
1917
|
+
if (recoverMissingSession(isMissingClaudeSessionErrorResult(payload) ? payload : null))
|
|
1918
|
+
break;
|
|
1919
|
+
if (payload.session_id)
|
|
1920
|
+
capturedSessionId = payload.session_id;
|
|
1921
|
+
resultIsError =
|
|
1922
|
+
payload.is_error === true ||
|
|
1923
|
+
(typeof payload.subtype === 'string' && payload.subtype.startsWith('error'));
|
|
1924
|
+
finishTurn();
|
|
1925
|
+
break;
|
|
1926
|
+
}
|
|
1927
|
+
default:
|
|
1861
1928
|
break;
|
|
1862
|
-
if (payload.session_id)
|
|
1863
|
-
capturedSessionId = payload.session_id;
|
|
1864
|
-
// LOW-7: detect a failed turn reported through the result frame.
|
|
1865
|
-
resultIsError =
|
|
1866
|
-
payload.is_error === true ||
|
|
1867
|
-
(typeof payload.subtype === 'string' && payload.subtype.startsWith('error'));
|
|
1868
|
-
finishTurn();
|
|
1869
|
-
break;
|
|
1870
1929
|
}
|
|
1871
|
-
default:
|
|
1872
|
-
break;
|
|
1873
1930
|
}
|
|
1874
1931
|
};
|
|
1875
1932
|
this._stdinSessions.setHandlers(conversationId, {
|
|
@@ -2022,8 +2079,10 @@ class ChatManager {
|
|
|
2022
2079
|
// 'explore-spec' — no new surface value (analytics guardrail).
|
|
2023
2080
|
const surface = opts.kind === 'explore' || opts.kind === 'milestone' ? 'explore-spec' : 'chat-sidebar';
|
|
2024
2081
|
try {
|
|
2082
|
+
const finishedAt = new Date().toISOString();
|
|
2025
2083
|
const { result, estimated } = (0, result_event_1.finaliseInvocationResult)(opts.adapter, opts.events, {
|
|
2026
2084
|
fallbackModel: opts.model,
|
|
2085
|
+
durationMs: Math.max(0, Date.parse(finishedAt) - Date.parse(opts.startedAt)),
|
|
2027
2086
|
});
|
|
2028
2087
|
(0, ai_invocations_1.recordInvocation)(this._db, {
|
|
2029
2088
|
id: (0, crypto_1.randomUUID)(),
|
|
@@ -2034,7 +2093,7 @@ class ChatManager {
|
|
|
2034
2093
|
conversation_id: opts.conversationId,
|
|
2035
2094
|
status: opts.status,
|
|
2036
2095
|
started_at: opts.startedAt,
|
|
2037
|
-
finished_at:
|
|
2096
|
+
finished_at: finishedAt,
|
|
2038
2097
|
total_cost_usd_estimated: estimated,
|
|
2039
2098
|
...result,
|
|
2040
2099
|
});
|
|
@@ -2051,14 +2110,33 @@ class ChatManager {
|
|
|
2051
2110
|
// Title generation runs on the conversation's own provider.
|
|
2052
2111
|
const conv = (0, db_1.getConversation)(this._db, conversationId);
|
|
2053
2112
|
const adapter = this._adapterForConversation(conv ?? {});
|
|
2113
|
+
const toolPolicy = (0, runtime_1.pureOutputToolPolicy)(adapter);
|
|
2114
|
+
if (!toolPolicy) {
|
|
2115
|
+
// Kimi `-p` forces automatic tool approval, so it cannot safely run a
|
|
2116
|
+
// pure-output title turn. Preserve the user-facing feature with the
|
|
2117
|
+
// same deterministic, local fallback used by Agent Chat.
|
|
2118
|
+
const title = (0, explore_draft_title_1.generateAutoTitle)([{ role: 'user', content: firstUserMsg }]);
|
|
2119
|
+
if (title) {
|
|
2120
|
+
(0, db_1.updateConversation)(this._db, conversationId, { title });
|
|
2121
|
+
this._broadcast({
|
|
2122
|
+
type: 'chat_title_update',
|
|
2123
|
+
conversationId,
|
|
2124
|
+
title,
|
|
2125
|
+
timestamp: new Date().toISOString(),
|
|
2126
|
+
});
|
|
2127
|
+
}
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2054
2130
|
const titlePrompt = `Generate a 4-6 word title for this conversation. Output ONLY the title text, no quotes or punctuation.\n\n` +
|
|
2055
2131
|
`User: ${firstUserMsg.slice(0, 200)}\nAssistant: ${firstResponse.slice(0, 300)}`;
|
|
2056
|
-
const
|
|
2132
|
+
const titleOptions = {
|
|
2057
2133
|
prompt: titlePrompt,
|
|
2058
2134
|
model: adapter.defaultModel(),
|
|
2059
|
-
|
|
2135
|
+
toolPolicy,
|
|
2136
|
+
};
|
|
2137
|
+
const args = adapter.buildArgs('auto-title', titleOptions);
|
|
2060
2138
|
const child = this._spawnOwned(adapter.binary, args, {
|
|
2061
|
-
env:
|
|
2139
|
+
env: (0, runtime_1.buildProviderEnv)(adapter, titleOptions),
|
|
2062
2140
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
2063
2141
|
cwd: this._cwd,
|
|
2064
2142
|
});
|
|
@@ -2078,15 +2156,13 @@ class ChatManager {
|
|
|
2078
2156
|
reader.on('line', (line) => {
|
|
2079
2157
|
if (this._disposed)
|
|
2080
2158
|
return;
|
|
2081
|
-
const ev
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
if (trimmed)
|
|
2089
|
-
titleText = trimmed;
|
|
2159
|
+
for (const ev of (0, runtime_1.parseStreamEvents)(adapter, line)) {
|
|
2160
|
+
titleEvents.push(ev);
|
|
2161
|
+
if (!titleText && ev.kind === 'text-delta') {
|
|
2162
|
+
const trimmed = ev.text.trim();
|
|
2163
|
+
if (trimmed)
|
|
2164
|
+
titleText = trimmed;
|
|
2165
|
+
}
|
|
2090
2166
|
}
|
|
2091
2167
|
});
|
|
2092
2168
|
child.on('error', () => {
|
|
@@ -13,6 +13,7 @@ const build_dirs_1 = require("./build-dirs");
|
|
|
13
13
|
const file_provenance_1 = require("./file-provenance");
|
|
14
14
|
const file_summary_manager_1 = require("./file-summary-manager");
|
|
15
15
|
const file_story_1 = require("./file-story");
|
|
16
|
+
const providers_1 = require("./providers");
|
|
16
17
|
const MAX_TREE_PAGE = 2000;
|
|
17
18
|
const MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
18
19
|
const BINARY_PROBE_BYTES = 8 * 1024;
|
|
@@ -346,6 +347,18 @@ function createCodeExplorerRouter(deps) {
|
|
|
346
347
|
const listByTicket = deps.listProvenanceByTicket ?? file_provenance_1.listProvenanceByTicket;
|
|
347
348
|
// Summary OUTPUT root (workspace when relocated). Source reads use projectPath.
|
|
348
349
|
const summaryRoot = () => deps.resolveSummaryRoot?.() ?? deps.projectPath;
|
|
350
|
+
const aiTransformProvider = deps.aiTransformProvider;
|
|
351
|
+
const aiTransformsAvailable = (0, providers_1.pureOutputToolPolicy)((0, providers_1.getAdapter)(aiTransformProvider)) !== null;
|
|
352
|
+
function requireAiTransforms(res) {
|
|
353
|
+
if (aiTransformsAvailable)
|
|
354
|
+
return true;
|
|
355
|
+
res.status(409).json({
|
|
356
|
+
error: 'provider_tool_policy_unsupported',
|
|
357
|
+
provider: aiTransformProvider,
|
|
358
|
+
requiredPolicy: 'pure-output',
|
|
359
|
+
});
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
349
362
|
// Short-TTL per-project cache so paginating a large `all` tree reuses ONE
|
|
350
363
|
// synchronous filesystem walk instead of re-walking (and re-statting) on every
|
|
351
364
|
// page — the cursor only slices an already-materialized array. Also caches the
|
|
@@ -375,14 +388,16 @@ function createCodeExplorerRouter(deps) {
|
|
|
375
388
|
res.status(404).end();
|
|
376
389
|
return;
|
|
377
390
|
}
|
|
378
|
-
// Lazily attach the file-summary watcher on first Code-Explorer use.
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
//
|
|
382
|
-
|
|
383
|
-
|
|
391
|
+
// Lazily attach the file-summary watcher on first Code-Explorer use. A
|
|
392
|
+
// provider without a native pure-output boundary must not attach it:
|
|
393
|
+
// implicit file-change work and explicit POSTs both fail closed before a
|
|
394
|
+
// manager or provider process can run.
|
|
395
|
+
if (aiTransformsAvailable) {
|
|
396
|
+
try {
|
|
397
|
+
deps.fileSummaryManager.attachWatcher(deps.projectId, deps.projectPath, summaryRoot());
|
|
398
|
+
}
|
|
399
|
+
catch { /* non-fatal */ }
|
|
384
400
|
}
|
|
385
|
-
catch { /* non-fatal */ }
|
|
386
401
|
next();
|
|
387
402
|
});
|
|
388
403
|
router.get('/tree', (req, res) => {
|
|
@@ -694,6 +709,8 @@ function createCodeExplorerRouter(deps) {
|
|
|
694
709
|
// turn; the file.story_updated WS event fires too so other open viewers of
|
|
695
710
|
// the same file refresh.
|
|
696
711
|
router.post('/file/story/explain', async (req, res) => {
|
|
712
|
+
if (!requireAiTransforms(res))
|
|
713
|
+
return;
|
|
697
714
|
const relRaw = req.query.path;
|
|
698
715
|
if (!relRaw || typeof relRaw !== 'string') {
|
|
699
716
|
res.status(400).json({ error: 'path query parameter is required' });
|
|
@@ -754,6 +771,8 @@ function createCodeExplorerRouter(deps) {
|
|
|
754
771
|
}
|
|
755
772
|
});
|
|
756
773
|
router.post('/file/regenerate-summary', async (req, res) => {
|
|
774
|
+
if (!requireAiTransforms(res))
|
|
775
|
+
return;
|
|
757
776
|
const relRaw = req.query.path;
|
|
758
777
|
if (!relRaw || typeof relRaw !== 'string') {
|
|
759
778
|
res.status(400).json({ error: 'path query parameter is required' });
|