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
package/docs/tracking-cost.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Tracking cost
|
|
2
2
|
|
|
3
|
-
specrails-desktop records
|
|
3
|
+
specrails-desktop records AI CLI invocations across Claude, Codex, Gemini, and Kimi and surfaces the available metrics on one Analytics page per project. This guide walks through what's tracked, what's unavailable, and how to read the dashboard.
|
|
4
4
|
|
|
5
5
|
## What gets tracked
|
|
6
6
|
|
|
@@ -15,7 +15,17 @@ Six surfaces, all per-project:
|
|
|
15
15
|
| **`smash`** | SMASH runs that break an epic spec into sub-specs |
|
|
16
16
|
| **`file-summary`** | Code-explorer AI summaries of individual files |
|
|
17
17
|
|
|
18
|
-
Each invocation row carries
|
|
18
|
+
Each invocation row carries the provider, model, status, timestamps, duration,
|
|
19
|
+
and relevant ticket/conversation IDs. Token, USD-cost, and turn fields are
|
|
20
|
+
nullable because not every CLI reports them; Kimi leaves those values
|
|
21
|
+
unavailable rather than writing zero.
|
|
22
|
+
|
|
23
|
+
The surface list is app-wide, not a promise that every provider can spawn
|
|
24
|
+
every row type. Kimi records its agentic chats/Explore/rails/loops, but Quick
|
|
25
|
+
Spec, AI Edit, Contract Refine, SMASH/Re-SMASH, file summaries, construction
|
|
26
|
+
story, AI auto-title, Project Builder blueprint/milestone generation, Loop
|
|
27
|
+
Decider, and Agent Studio automation fail before spawn. Those rejected
|
|
28
|
+
requests create no invocation row; AI auto-title uses a deterministic fallback.
|
|
19
29
|
|
|
20
30
|
> Cost averages exclude `failed`/`aborted` rows, but those rows still count toward the total run count and the failure rate.
|
|
21
31
|
|
|
@@ -25,6 +35,9 @@ Whether a cost figure is exact depends on the provider's CLI, not on which provi
|
|
|
25
35
|
|
|
26
36
|
- **Claude cost is provider-billed and authoritative** — the figure comes straight from the CLI's own usage report.
|
|
27
37
|
- **Codex and Gemini do not report cost natively**, so the app **estimates** their cost from a local rate-card (`server/pricing.ts`) using the captured token counts. Estimated rows are flagged: they render with a `~` tilde in the raw table (hover for the tooltip — *"Estimated from local pricing table — this provider does not report cost natively"*) and feed an "includes ~$X estimated" footnote in the Hero.
|
|
38
|
+
- **Kimi reports neither token counts nor a native USD-cost envelope** in its
|
|
39
|
+
stream. Specrails does not invent an estimate: cost and token cells stay
|
|
40
|
+
unavailable.
|
|
28
41
|
|
|
29
42
|
On multi-provider projects, a **Provider breakdown** card splits spend across the project's installed engines so you can see authoritative vs estimated at a glance.
|
|
30
43
|
|
|
@@ -32,10 +45,12 @@ On multi-provider projects, a **Provider breakdown** card splits spend across th
|
|
|
32
45
|
|
|
33
46
|
## What's NOT tracked (intentionally)
|
|
34
47
|
|
|
35
|
-
- **Sidebar chat** — the general-purpose chat panel in the right sidebar. It spawns an AI process but isn't pipeline work, so the app excludes it from analytics by design.
|
|
48
|
+
- **Sidebar chat** — the general-purpose chat panel in the right sidebar. It spawns an AI process, including `kimi -p` when Kimi is selected, but isn't pipeline work, so the app excludes it from analytics by design.
|
|
36
49
|
- **Setup wizard** — the install/enrich flow when you add a project. It *does* spawn an AI CLI (a genuine model invocation), but it's an interactive one-time wizard rather than a repeatable pipeline job, so it's deliberately left uninstrumented.
|
|
37
50
|
|
|
38
|
-
If you want the absolute total of what an engine has cost you, your provider's
|
|
51
|
+
If you want the absolute total of what an engine has cost you, your provider's
|
|
52
|
+
own console is the source of truth. This is especially important for Kimi,
|
|
53
|
+
whose CLI stream provides no billable usage envelope to Desktop.
|
|
39
54
|
|
|
40
55
|
## The Analytics page
|
|
41
56
|
|
|
@@ -45,7 +60,7 @@ Open **Analytics** from the project right sidebar.
|
|
|
45
60
|
|
|
46
61
|
- **Period** — `7d`, `30d`, `90d`, or `All`. (There's no 24-hour or custom-range option here — the custom calendar range lives on Desktop Analytics, below.)
|
|
47
62
|
- **Surface** — chips for `All` plus each of the six surfaces (Jobs, Explore, Quick, Refine, SMASH, File summaries). All are included by default; toggle chips to narrow the view.
|
|
48
|
-
- **Engine** — one chip per installed provider
|
|
63
|
+
- **Engine** — one chip per installed provider plus `All`. These appear **only on multi-provider projects** and let you filter activity by engine.
|
|
49
64
|
|
|
50
65
|
The period and surface filters are URL-synced, so you can share or bookmark a view.
|
|
51
66
|
|
|
@@ -62,7 +77,10 @@ When the project has zero invocations in the period (e.g. you just started), the
|
|
|
62
77
|
|
|
63
78
|
### Provider breakdown
|
|
64
79
|
|
|
65
|
-
On multi-provider projects, a dedicated card splits
|
|
80
|
+
On multi-provider projects, a dedicated card splits available spend across the
|
|
81
|
+
project's installed engines. It is data-driven, so Kimi appears even though its
|
|
82
|
+
cost is unavailable. Estimated Codex/Gemini totals carry a `~` tilde. The card
|
|
83
|
+
is hidden on single-provider projects.
|
|
66
84
|
|
|
67
85
|
### Daily stacked timeline
|
|
68
86
|
|
|
@@ -159,3 +177,4 @@ For the cross-project view, open **Analytics** from the Arc sidebar on the left.
|
|
|
159
177
|
- [Creating specs](creating-specs.md) — every spec you create adds rows to your analytics.
|
|
160
178
|
- [Using Codex](codex.md) — how cost works when you run a project on Codex (estimated, ~ tilde).
|
|
161
179
|
- [Using Gemini](gemini.md) — how cost works when you run a project on Gemini (also estimated, ~ tilde).
|
|
180
|
+
- [Using Kimi](kimi.md) — why Kimi duration/outcome are recorded while tokens and cost remain unavailable.
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specrails-desktop",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.31.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/fjpulidop/specrails-desktop.git"
|
|
8
8
|
},
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=20.
|
|
10
|
+
"node": ">=20.19.0"
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
13
13
|
"specrails-desktop": "cli/dist/specrails-desktop.js"
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"cross-spawn": "^7.0.6",
|
|
52
52
|
"diff": "^9.0.0",
|
|
53
53
|
"express": "^5.2.1",
|
|
54
|
+
"js-yaml": "4.1.1",
|
|
54
55
|
"multer": "^2.2.0",
|
|
55
56
|
"node-pty": "^1.0.0",
|
|
56
57
|
"pdf-parse": "^2.4.5",
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
"@types/cross-spawn": "^6.0.6",
|
|
70
71
|
"@types/diff": "^7.0.2",
|
|
71
72
|
"@types/express": "^5.0.6",
|
|
73
|
+
"@types/js-yaml": "^4.0.9",
|
|
72
74
|
"@types/multer": "^2.1.0",
|
|
73
75
|
"@types/node": "^25.5.0",
|
|
74
76
|
"@types/pdf-parse": "^1.1.5",
|
|
@@ -8,8 +8,10 @@ exports.sanitizeAgentTitle = sanitizeAgentTitle;
|
|
|
8
8
|
const crypto_1 = require("crypto");
|
|
9
9
|
const readline_1 = require("readline");
|
|
10
10
|
const os_1 = require("os");
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
12
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
12
13
|
const providers_1 = require("./providers");
|
|
14
|
+
const runtime_1 = require("./providers/runtime");
|
|
13
15
|
const spawn_lifecycle_1 = require("./spawn-lifecycle");
|
|
14
16
|
const cli_prompt_1 = require("./util/cli-prompt");
|
|
15
17
|
const result_event_1 = require("./result-event");
|
|
@@ -23,6 +25,18 @@ const attachment_manager_1 = require("./attachment-manager");
|
|
|
23
25
|
const agent_context_resolver_1 = require("./agent-context-resolver");
|
|
24
26
|
const agent_store_1 = require("./agent-store");
|
|
25
27
|
const explore_draft_title_1 = require("./explore-draft-title");
|
|
28
|
+
/**
|
|
29
|
+
* Providers report an expired or foreign resume token as a normalized error.
|
|
30
|
+
* Those errors are safe to recover from by clearing the token and retrying the
|
|
31
|
+
* same turn once; every other provider error remains terminal.
|
|
32
|
+
*/
|
|
33
|
+
function isStaleResumeError(message) {
|
|
34
|
+
if (!message)
|
|
35
|
+
return false;
|
|
36
|
+
return (/no rollout found for thread id/i.test(message) ||
|
|
37
|
+
/unknown (?:session|thread)(?: id)?\b/i.test(message) ||
|
|
38
|
+
/(?:session|thread)(?: id)?\b[^\n]{0,160}\b(?:not found|does not exist)\b/i.test(message));
|
|
39
|
+
}
|
|
26
40
|
class AgentChatManager {
|
|
27
41
|
_broadcast;
|
|
28
42
|
_db;
|
|
@@ -218,17 +232,20 @@ class AgentChatManager {
|
|
|
218
232
|
// Resolve a model that is VALID for this provider. A stale model from another
|
|
219
233
|
// provider (e.g. claude's "sonnet" after switching to codex) is rejected by
|
|
220
234
|
// the provider — fall back to the provider's default instead of failing.
|
|
221
|
-
const catalog = new Set(adapter.modelCatalog().map((m) => m.value));
|
|
222
235
|
const requested = options.model || conversation.model;
|
|
223
|
-
const model = requested &&
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
|
|
236
|
+
const model = requested && (0, providers_1.isModelAvailableForAdapter)(adapter, requested)
|
|
237
|
+
? requested
|
|
238
|
+
: adapter.defaultModel();
|
|
239
|
+
// Reasoning effort is model-scoped. A stale value from a previous model is
|
|
240
|
+
// discarded and the default is selected from the effective model's exact
|
|
241
|
+
// catalog (K3 follows its native high default; other Kimi models expose no
|
|
242
|
+
// per-invocation knob).
|
|
243
|
+
const efforts = (0, providers_1.reasoningEffortsForModel)(adapter, model);
|
|
229
244
|
const storedEffort = conversation.reasoning_effort;
|
|
230
245
|
const reasoningEffort = efforts.length
|
|
231
|
-
? (storedEffort && efforts.includes(storedEffort)
|
|
246
|
+
? (storedEffort && efforts.includes(storedEffort)
|
|
247
|
+
? storedEffort
|
|
248
|
+
: (0, providers_1.defaultReasoningEffortForModel)(adapter, model))
|
|
232
249
|
: undefined;
|
|
233
250
|
// Resolve attachments (conversation-keyed) into extracted text blocks +
|
|
234
251
|
// absolute image paths. Extraction failure degrades to a text-only turn.
|
|
@@ -286,6 +303,9 @@ class AgentChatManager {
|
|
|
286
303
|
const systemPrompt = hasAttachments
|
|
287
304
|
? `${agent_operator_prompt_1.OPERATOR_SYSTEM_PROMPT}\n\n${attachment_manager_1.USER_ATTACHMENT_SYSTEM_NOTE}`
|
|
288
305
|
: agent_operator_prompt_1.OPERATOR_SYSTEM_PROMPT;
|
|
306
|
+
const effectivePrompt = adapter.capabilities.systemPromptArg
|
|
307
|
+
? prompt
|
|
308
|
+
: `${systemPrompt}\n\n---\n\n${prompt}`;
|
|
289
309
|
// Only pass native image paths to providers that can vision-load them (codex
|
|
290
310
|
// `--image`); claude/gemini already have the `@path` ref folded into prompt.
|
|
291
311
|
const spawnImagePaths = adapter.capabilities.supportsImageInput ? imagePaths : undefined;
|
|
@@ -300,7 +320,10 @@ class AgentChatManager {
|
|
|
300
320
|
// / `.gemini/settings.json` and launch with the other's capability.
|
|
301
321
|
// Claude and Codex keep their historical global cwd and explicit MCP
|
|
302
322
|
// registration mechanisms unchanged.
|
|
303
|
-
const
|
|
323
|
+
const projectMcpPath = adapter.projectMcpPath?.('.');
|
|
324
|
+
const needsConversationMcpCwd = !!projectMcpPath &&
|
|
325
|
+
node_path_1.default.dirname(projectMcpPath) !== '.';
|
|
326
|
+
const cwd = needsConversationMcpCwd
|
|
304
327
|
? (0, agent_cwd_manager_1.ensureAgentConversationCwd)(conversationId)
|
|
305
328
|
: (0, agent_cwd_manager_1.ensureAgentCwd)();
|
|
306
329
|
let mcpArgs = [];
|
|
@@ -329,21 +352,22 @@ class AgentChatManager {
|
|
|
329
352
|
let capturedError = null;
|
|
330
353
|
console.log(`[agent-chat] turn start conv=${conversationId} provider=${adapter.id} binary=${adapter.binary} ` +
|
|
331
354
|
`action=${action} model=${model} cwd=${cwd} mcp=${mcpArgs.length ? 'mcp-config' : Object.keys(mcpEnv).join(',') || 'none'}`);
|
|
355
|
+
const buildOpts = {
|
|
356
|
+
prompt: effectivePrompt,
|
|
357
|
+
systemPrompt: adapter.capabilities.systemPromptArg ? systemPrompt : undefined,
|
|
358
|
+
model,
|
|
359
|
+
sessionId: useResume ? conversation.session_id ?? undefined : undefined,
|
|
360
|
+
extraArgs: mcpArgs,
|
|
361
|
+
imagePaths: spawnImagePaths,
|
|
362
|
+
reasoning_effort: reasoningEffort,
|
|
363
|
+
};
|
|
332
364
|
const invocation = this._awaitWhileLive((0, spawn_lifecycle_1.runAiCliInvocation)({
|
|
333
365
|
adapter,
|
|
334
366
|
action,
|
|
335
367
|
cwd,
|
|
336
|
-
env: { ...process.env, ...mcpEnv },
|
|
368
|
+
env: (0, runtime_1.buildProviderEnv)(adapter, buildOpts, { ...process.env, ...mcpEnv }),
|
|
337
369
|
spawn: this._spawnOwned.bind(this),
|
|
338
|
-
buildOpts
|
|
339
|
-
prompt,
|
|
340
|
-
systemPrompt: adapter.capabilities.systemPromptArg ? systemPrompt : undefined,
|
|
341
|
-
model,
|
|
342
|
-
sessionId: useResume ? conversation.session_id ?? undefined : undefined,
|
|
343
|
-
extraArgs: mcpArgs,
|
|
344
|
-
imagePaths: spawnImagePaths,
|
|
345
|
-
reasoning_effort: reasoningEffort,
|
|
346
|
-
},
|
|
370
|
+
buildOpts,
|
|
347
371
|
onSpawn: (child) => {
|
|
348
372
|
if (this._disposed) {
|
|
349
373
|
this._terminate(child);
|
|
@@ -464,7 +488,10 @@ class AgentChatManager {
|
|
|
464
488
|
// Auto-heal a stale/foreign session: a resume that produced no text (e.g. a
|
|
465
489
|
// provider switch leaving another provider's session id, or codex
|
|
466
490
|
// "no rollout found for thread id") retries once as a fresh turn.
|
|
467
|
-
if (canResume &&
|
|
491
|
+
if (canResume &&
|
|
492
|
+
!r.spawnFailed &&
|
|
493
|
+
!r.text &&
|
|
494
|
+
(!r.error || isStaleResumeError(r.error))) {
|
|
468
495
|
console.log(`[agent-chat] resume produced no text — retrying fresh conv=${conversationId}`);
|
|
469
496
|
(0, agent_store_1.updateAgentConversation)(this._db, conversationId, { session_id: null });
|
|
470
497
|
r = await invoke(false);
|
|
@@ -485,6 +512,17 @@ class AgentChatManager {
|
|
|
485
512
|
record(r, 'failed');
|
|
486
513
|
return;
|
|
487
514
|
}
|
|
515
|
+
// A normalized provider error is authoritative even when the CLI exits
|
|
516
|
+
// zero or streamed partial text before failing.
|
|
517
|
+
if (r.error || r.code !== 0) {
|
|
518
|
+
persistSession(null);
|
|
519
|
+
const reason = r.error ||
|
|
520
|
+
(r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
|
|
521
|
+
`${adapter.binary} exited with code ${r.code ?? 'unknown'}`;
|
|
522
|
+
this._emitError(conversationId, reason);
|
|
523
|
+
record(r, 'failed');
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
488
526
|
if (r.text) {
|
|
489
527
|
(0, agent_store_1.addAgentMessage)(this._db, { conversationId, role: 'assistant', content: r.text });
|
|
490
528
|
persistSession(r.sessionId);
|
|
@@ -499,9 +537,8 @@ class AgentChatManager {
|
|
|
499
537
|
// Failure: reset the session so the NEXT turn starts fresh, and surface the
|
|
500
538
|
// real reason instead of silently doing nothing.
|
|
501
539
|
persistSession(null);
|
|
502
|
-
const reason = r.
|
|
503
|
-
|
|
504
|
-
(r.code !== 0 ? `${adapter.binary} exited with code ${r.code}` : 'The agent returned no output.');
|
|
540
|
+
const reason = (r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
|
|
541
|
+
'The agent returned no output.';
|
|
505
542
|
this._emitError(conversationId, reason);
|
|
506
543
|
record(r, 'failed');
|
|
507
544
|
}
|
|
@@ -523,8 +560,10 @@ class AgentChatManager {
|
|
|
523
560
|
if (this._disposed)
|
|
524
561
|
return;
|
|
525
562
|
try {
|
|
563
|
+
const finishedAt = new Date().toISOString();
|
|
526
564
|
const { result, estimated } = (0, result_event_1.finaliseInvocationResult)(adapter, outcome.events, {
|
|
527
565
|
fallbackModel: model,
|
|
566
|
+
durationMs: Math.max(0, Date.parse(finishedAt) - Date.parse(outcome.startedAt)),
|
|
528
567
|
});
|
|
529
568
|
(0, desktop_db_1.recordAgentInvocation)(this._db, {
|
|
530
569
|
id: (0, crypto_1.randomUUID)(),
|
|
@@ -533,7 +572,7 @@ class AgentChatManager {
|
|
|
533
572
|
provider: adapter.id,
|
|
534
573
|
status,
|
|
535
574
|
started_at: outcome.startedAt,
|
|
536
|
-
finished_at:
|
|
575
|
+
finished_at: finishedAt,
|
|
537
576
|
total_cost_usd_estimated: estimated,
|
|
538
577
|
...result,
|
|
539
578
|
});
|
|
@@ -614,13 +653,17 @@ class AgentChatManager {
|
|
|
614
653
|
try {
|
|
615
654
|
const conversationId = conversation.id;
|
|
616
655
|
const adapter = (0, providers_1.getAdapter)(conversation.provider);
|
|
656
|
+
const toolPolicy = (0, runtime_1.pureOutputToolPolicy)(adapter);
|
|
657
|
+
if (!toolPolicy)
|
|
658
|
+
return;
|
|
617
659
|
const model = adapter.defaultModel();
|
|
618
660
|
const prompt = 'Generate a concise 3-6 word title for this conversation. ' +
|
|
619
661
|
'Output ONLY the title text — no quotes, no punctuation, no markdown, no preamble.\n\n' +
|
|
620
662
|
`User: ${firstUserMsg.slice(0, 240)}\nAssistant: ${firstResponse.slice(0, 320)}`;
|
|
621
|
-
const
|
|
663
|
+
const titleOptions = { prompt, model, toolPolicy };
|
|
664
|
+
const args = adapter.buildArgs('auto-title', titleOptions);
|
|
622
665
|
const child = this._spawnOwned(adapter.binary, args, {
|
|
623
|
-
env:
|
|
666
|
+
env: (0, runtime_1.buildProviderEnv)(adapter, titleOptions),
|
|
624
667
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
625
668
|
cwd: (0, os_1.tmpdir)(),
|
|
626
669
|
});
|
|
@@ -633,12 +676,11 @@ class AgentChatManager {
|
|
|
633
676
|
reader.on('line', (line) => {
|
|
634
677
|
if (this._disposed)
|
|
635
678
|
return;
|
|
636
|
-
const ev
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
raw += ev.text;
|
|
679
|
+
for (const ev of (0, runtime_1.parseStreamEvents)(adapter, line)) {
|
|
680
|
+
events.push(ev);
|
|
681
|
+
if (ev.kind === 'text-delta')
|
|
682
|
+
raw += ev.text;
|
|
683
|
+
}
|
|
642
684
|
});
|
|
643
685
|
child.on('error', () => {
|
|
644
686
|
this._auxProcesses.delete(child);
|
|
@@ -120,24 +120,30 @@ function createAgentChatRouter(deps) {
|
|
|
120
120
|
router.get('/models', (req, res) => {
|
|
121
121
|
const provider = validProvider(req.query.provider) ?? 'claude';
|
|
122
122
|
const adapter = (0, providers_1.getAdapter)(provider);
|
|
123
|
+
const requestedModel = (0, providers_1.isModelAvailableForAdapter)(adapter, req.query.model)
|
|
124
|
+
? req.query.model
|
|
125
|
+
: null;
|
|
126
|
+
const model = requestedModel ?? adapter.defaultModel();
|
|
123
127
|
res.json({
|
|
124
128
|
provider,
|
|
129
|
+
model,
|
|
125
130
|
models: adapter.modelCatalog(),
|
|
131
|
+
customModelAliases: adapter.capabilities.customModelAliases === true,
|
|
126
132
|
// The composer gates the image affordance on this (design D22: capability,
|
|
127
133
|
// never provider id — gemini stays false until live-verified).
|
|
128
134
|
supportsImageInput: adapter.capabilities.supportsImageInput === true,
|
|
129
135
|
// Per-provider reasoning-effort tiers (ascending). Empty ⇒ no selector
|
|
130
136
|
// (gemini has no per-spawn knob).
|
|
131
|
-
efforts: adapter
|
|
137
|
+
efforts: (0, providers_1.reasoningEffortsForModel)(adapter, model),
|
|
132
138
|
});
|
|
133
139
|
});
|
|
134
|
-
/** Validate a requested
|
|
135
|
-
const validEffort = (provider, value) => {
|
|
140
|
+
/** Validate a requested effort against the effective model's exact catalog. */
|
|
141
|
+
const validEffort = (provider, model, value) => {
|
|
136
142
|
if (value === null)
|
|
137
143
|
return null;
|
|
138
144
|
if (typeof value !== 'string')
|
|
139
145
|
return undefined;
|
|
140
|
-
const efforts = (0, providers_1.getAdapter)(provider)
|
|
146
|
+
const efforts = (0, providers_1.reasoningEffortsForModel)((0, providers_1.getAdapter)(provider), model);
|
|
141
147
|
return efforts.includes(value) ? value : undefined;
|
|
142
148
|
};
|
|
143
149
|
router.get('/conversations', (_req, res) => {
|
|
@@ -154,13 +160,20 @@ function createAgentChatRouter(deps) {
|
|
|
154
160
|
}
|
|
155
161
|
provider = v;
|
|
156
162
|
}
|
|
163
|
+
const adapter = (0, providers_1.getAdapter)(provider);
|
|
164
|
+
const requestedModel = body.model == null ? null : body.model;
|
|
165
|
+
if (requestedModel !== null && !(0, providers_1.isModelAvailableForAdapter)(adapter, requestedModel)) {
|
|
166
|
+
res.status(400).json({ error: 'Model not available for this provider' });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const effectiveModel = requestedModel ?? adapter.defaultModel();
|
|
157
170
|
const conversation = (0, agent_store_1.createAgentConversation)(desktopDb, {
|
|
158
171
|
provider,
|
|
159
|
-
model:
|
|
172
|
+
model: requestedModel,
|
|
160
173
|
pinnedProjectId: typeof body.pinnedProjectId === 'string' ? body.pinnedProjectId : null,
|
|
161
174
|
tierLevel: body.tierLevel !== undefined ? (0, agent_tier_1.normalizeLevel)(body.tierLevel) : 0,
|
|
162
|
-
// Off-catalog values fall back to null (=
|
|
163
|
-
reasoningEffort: validEffort(provider, body.reasoningEffort) ?? null,
|
|
175
|
+
// Off-catalog values fall back to null (= no provider-specific override).
|
|
176
|
+
reasoningEffort: validEffort(provider, effectiveModel, body.reasoningEffort) ?? null,
|
|
164
177
|
});
|
|
165
178
|
res.status(201).json({ conversation });
|
|
166
179
|
});
|
|
@@ -206,31 +219,41 @@ function createAgentChatRouter(deps) {
|
|
|
206
219
|
}
|
|
207
220
|
}
|
|
208
221
|
// Explicit model pick — validated against the (new or current) provider's catalog.
|
|
209
|
-
if (body.model !== undefined
|
|
222
|
+
if (body.model !== undefined) {
|
|
223
|
+
const effectiveProvider = patch.provider ?? conversation.provider;
|
|
210
224
|
if (body.model === null) {
|
|
211
225
|
patch.model = null;
|
|
212
226
|
}
|
|
213
227
|
else if (typeof body.model === 'string') {
|
|
214
|
-
|
|
215
|
-
const valid = new Set((0, providers_1.getAdapter)(effectiveProvider).modelCatalog().map((m) => m.value));
|
|
216
|
-
if (!valid.has(body.model)) {
|
|
228
|
+
if (!(0, providers_1.isModelAvailableForAdapter)((0, providers_1.getAdapter)(effectiveProvider), body.model)) {
|
|
217
229
|
res.status(400).json({ error: 'Model not available for this provider' });
|
|
218
230
|
return;
|
|
219
231
|
}
|
|
220
232
|
patch.model = body.model;
|
|
221
233
|
}
|
|
222
234
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
235
|
+
const effectiveProvider = patch.provider ?? conversation.provider;
|
|
236
|
+
const adapter = (0, providers_1.getAdapter)(effectiveProvider);
|
|
237
|
+
const effectiveModel = typeof patch.model === 'string'
|
|
238
|
+
? patch.model
|
|
239
|
+
: patch.model === null
|
|
240
|
+
? adapter.defaultModel()
|
|
241
|
+
: conversation.model ?? adapter.defaultModel();
|
|
242
|
+
// Explicit effort pick — validated against the effective model. A model
|
|
243
|
+
// change without an effort pick clears a now-incompatible persisted value.
|
|
244
|
+
if (body.reasoningEffort !== undefined) {
|
|
245
|
+
const v = validEffort(effectiveProvider, effectiveModel, body.reasoningEffort);
|
|
228
246
|
if (v === undefined) {
|
|
229
|
-
res.status(400).json({ error: 'Effort not available for this provider' });
|
|
247
|
+
res.status(400).json({ error: 'Effort not available for this provider and model' });
|
|
230
248
|
return;
|
|
231
249
|
}
|
|
232
250
|
patch.reasoning_effort = v;
|
|
233
251
|
}
|
|
252
|
+
else if (body.model !== undefined
|
|
253
|
+
&& conversation.reasoning_effort
|
|
254
|
+
&& validEffort(effectiveProvider, effectiveModel, conversation.reasoning_effort) === undefined) {
|
|
255
|
+
patch.reasoning_effort = null;
|
|
256
|
+
}
|
|
234
257
|
res.json({ conversation: (0, agent_store_1.updateAgentConversation)(desktopDb, conversation.id, patch) });
|
|
235
258
|
});
|
|
236
259
|
router.delete('/conversations/:id', (req, res) => {
|
|
@@ -16,10 +16,10 @@ const agent_operator_prompt_1 = require("./agent-operator-prompt");
|
|
|
16
16
|
//
|
|
17
17
|
// The agent chat spawns the AI CLI from an app-owned cwd (NOT a project path), so
|
|
18
18
|
// no project's CLAUDE.md is auto-loaded and the agent starts with a focused
|
|
19
|
-
// "operator" stance. Claude/Codex retain the original app-global cwd.
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
19
|
+
// "operator" stance. Claude/Codex retain the original app-global cwd. Providers
|
|
20
|
+
// whose MCP config is cwd-discovered under a nested project path (Gemini/Kimi)
|
|
21
|
+
// get a per-conversation child cwd so concurrent turns cannot overwrite each
|
|
22
|
+
// other's capability-file reference.
|
|
23
23
|
function homeDir() {
|
|
24
24
|
return process.env.SPECRAILS_REGISTRY_HOME || os_1.default.homedir();
|
|
25
25
|
}
|
|
@@ -65,6 +65,14 @@ function ensureAgentCwd() {
|
|
|
65
65
|
fs_1.default.rmdirSync(path_1.default.join(dir, '.gemini'));
|
|
66
66
|
}
|
|
67
67
|
catch { /* non-empty / absent */ }
|
|
68
|
+
try {
|
|
69
|
+
fs_1.default.unlinkSync(path_1.default.join(dir, '.kimi-code', 'mcp.json'));
|
|
70
|
+
}
|
|
71
|
+
catch { /* absent */ }
|
|
72
|
+
try {
|
|
73
|
+
fs_1.default.rmdirSync(path_1.default.join(dir, '.kimi-code'));
|
|
74
|
+
}
|
|
75
|
+
catch { /* non-empty / absent */ }
|
|
68
76
|
return dir;
|
|
69
77
|
}
|
|
70
78
|
/** Path for provider state that must not be shared across agent conversations. */
|
|
@@ -75,9 +83,8 @@ function agentConversationCwdPath(conversationId) {
|
|
|
75
83
|
return path_1.default.join(agentCwdPath(), 'conversations', conversationId);
|
|
76
84
|
}
|
|
77
85
|
/**
|
|
78
|
-
* Materialise an isolated agent cwd for one conversation.
|
|
79
|
-
*
|
|
80
|
-
* overwritten by a concurrent turn belonging to another conversation.
|
|
86
|
+
* Materialise an isolated agent cwd for one conversation. Cwd-discovered
|
|
87
|
+
* provider MCP files can never be overwritten by another conversation.
|
|
81
88
|
*/
|
|
82
89
|
function ensureAgentConversationCwd(conversationId) {
|
|
83
90
|
return ensureCwd(agentConversationCwdPath(conversationId));
|