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
|
@@ -10,9 +10,10 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const json_mutation_1 = require("./json-mutation");
|
|
12
12
|
/**
|
|
13
|
-
* Plugins contribute named sections to the project's
|
|
14
|
-
*
|
|
15
|
-
* the adapter-declared
|
|
13
|
+
* Plugins contribute named sections to the project's provider-native
|
|
14
|
+
* instructions path (`CLAUDE.md` for Claude, `AGENTS.md` for Codex,
|
|
15
|
+
* `.kimi-code/AGENTS.md` for Kimi, and the adapter-declared path for future
|
|
16
|
+
* providers) so the agent's global
|
|
16
17
|
* context includes per-plugin usage hints (e.g. "prefer Serena tools over
|
|
17
18
|
* raw Read/Grep when locating symbols"). Each plugin owns one named block
|
|
18
19
|
* delimited by HTML-comment markers; multiple plugins coexist without
|
|
@@ -88,7 +89,7 @@ function getBlockContent(projectPath, pluginName, filename = 'CLAUDE.md') {
|
|
|
88
89
|
* file does not exist, it is created with just the block. If it exists
|
|
89
90
|
* without our block, the block is appended at the end (separated by a blank
|
|
90
91
|
* line). The filename defaults to `CLAUDE.md` for backwards compatibility;
|
|
91
|
-
*
|
|
92
|
+
* other providers pass their adapter-declared relative path.
|
|
92
93
|
*/
|
|
93
94
|
async function upsertBlock(projectPath, pluginName, content, filename = 'CLAUDE.md') {
|
|
94
95
|
const file = instructionsMdPath(projectPath, filename);
|
|
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.detectMcpDrift = detectMcpDrift;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const paths_1 = require("./paths");
|
|
9
8
|
const claude_md_mutation_1 = require("./claude-md-mutation");
|
|
9
|
+
const providers_1 = require("../providers");
|
|
10
10
|
/**
|
|
11
11
|
* Returns true when the project's `.mcp.json` entry for any of the plugin's
|
|
12
12
|
* owned mcpServers no longer matches the bundled manifest. Used to surface
|
|
@@ -15,42 +15,45 @@ const claude_md_mutation_1 = require("./claude-md-mutation");
|
|
|
15
15
|
*
|
|
16
16
|
* Only inspects entries the plugin owns; user-authored entries are ignored.
|
|
17
17
|
*/
|
|
18
|
-
function detectMcpDrift(projectPath, plugin) {
|
|
18
|
+
function detectMcpDrift(projectPath, plugin, providerId = 'claude') {
|
|
19
19
|
const ownedKeys = plugin.manifest.owns.mcpServers ?? [];
|
|
20
|
-
|
|
21
|
-
return false;
|
|
20
|
+
const adapter = (0, providers_1.hasAdapter)(providerId) ? (0, providers_1.getAdapter)(providerId) : (0, providers_1.getAdapter)('claude');
|
|
22
21
|
// The plugin tells us what its current canonical entry should look like
|
|
23
22
|
// via `previewInstall` is too heavy; we instead introspect via a marker:
|
|
24
23
|
// plugins that ship their canonical entry expose it via `expectedMcpEntry`.
|
|
25
24
|
// We accept Plugins without it (drift detection silently disabled).
|
|
26
|
-
const expected = plugin
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
const expected = plugin.expectedMcpEntry?.();
|
|
26
|
+
// CLI-managed registries (Codex) have no project JSON to compare. Their
|
|
27
|
+
// registration is checked by the plugin's verify hook instead.
|
|
28
|
+
if (expected &&
|
|
29
|
+
ownedKeys.length > 0 &&
|
|
30
|
+
adapter.mcpRegistration === 'project-json' &&
|
|
31
|
+
adapter.projectMcpPath) {
|
|
32
|
+
const file = adapter.projectMcpPath(projectPath);
|
|
33
|
+
if (fs_1.default.existsSync(file)) {
|
|
34
|
+
let parsed;
|
|
35
|
+
try {
|
|
36
|
+
parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const servers = parsed.mcpServers ?? {};
|
|
42
|
+
for (const key of ownedKeys) {
|
|
43
|
+
const current = servers[key];
|
|
44
|
+
if (current === undefined)
|
|
45
|
+
continue;
|
|
46
|
+
if (JSON.stringify(current) !== JSON.stringify(expected))
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
36
50
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const servers = parsed.mcpServers ?? {};
|
|
41
|
-
for (const key of ownedKeys) {
|
|
42
|
-
const current = servers[key];
|
|
43
|
-
if (current === undefined)
|
|
44
|
-
continue;
|
|
45
|
-
if (JSON.stringify(current) !== JSON.stringify(expected))
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
// Shared-file contributor drift. Today only CLAUDE.md is contributed to;
|
|
49
|
-
// we hardcode the comparison here. If/when more shared-file contributors
|
|
50
|
-
// land we move this to a `compareDrift` hook on the contributor type.
|
|
51
|
+
// Provider-instructions contributor drift. The adapter path may be nested
|
|
52
|
+
// (for example Kimi's `.kimi-code/AGENTS.md`). If/when more shared-file
|
|
53
|
+
// contributors land we move this to a `compareDrift` hook.
|
|
51
54
|
if (plugin.manifest.claudeMdInstructions) {
|
|
52
55
|
const expectedMd = plugin.manifest.claudeMdInstructions.trim();
|
|
53
|
-
const actualMd = ((0, claude_md_mutation_1.getBlockContent)(projectPath, plugin.manifest.name) ?? '').trim();
|
|
56
|
+
const actualMd = ((0, claude_md_mutation_1.getBlockContent)(projectPath, plugin.manifest.name, adapter.instructionsFilename) ?? '').trim();
|
|
54
57
|
if (actualMd !== expectedMd)
|
|
55
58
|
return true;
|
|
56
59
|
}
|
|
@@ -20,7 +20,7 @@ const json_mutation_1 = require("./json-mutation");
|
|
|
20
20
|
* actually changed since the last check (no churn on the steady-state path).
|
|
21
21
|
* Otherwise this performs no project-file mutation.
|
|
22
22
|
*/
|
|
23
|
-
async function resolvePluginsForSpawn(projectPath, projectId, _jobId) {
|
|
23
|
+
async function resolvePluginsForSpawn(projectPath, projectId, _jobId, providerId = 'claude', legacyProviderId = providerId, slug) {
|
|
24
24
|
const mgr = (0, manager_1.getPluginManager)();
|
|
25
25
|
const state = mgr.getProjectState(projectPath);
|
|
26
26
|
const active = [];
|
|
@@ -28,13 +28,24 @@ async function resolvePluginsForSpawn(projectPath, projectId, _jobId) {
|
|
|
28
28
|
// Run verify in parallel for all installed plugins. Each verify is
|
|
29
29
|
// already timeout-wrapped inside PluginManager.
|
|
30
30
|
const checks = await Promise.all(Object.entries(state.plugins).map(async ([name, entry]) => {
|
|
31
|
+
const scopedProviderState = entry.providers?.[providerId];
|
|
32
|
+
const providerInstalled = entry.providers
|
|
33
|
+
? scopedProviderState !== undefined
|
|
34
|
+
: providerId === legacyProviderId;
|
|
35
|
+
// A plugin installed only for another provider must not appear in this
|
|
36
|
+
// rail's snapshot. Explicitly deactivated installs are intentionally
|
|
37
|
+
// absent rather than misreported as degraded.
|
|
38
|
+
if (!providerInstalled || scopedProviderState?.active === false)
|
|
39
|
+
return null;
|
|
31
40
|
// Skip orphans — they are not in the registry, so verify cannot run.
|
|
32
41
|
if (!mgr.registry.byName.has(name))
|
|
33
42
|
return { name, version: entry.version, result: { ok: false, reason: 'orphan', checkedAt: new Date().toISOString() } };
|
|
34
|
-
const result = await mgr.verify(projectPath, projectId, name);
|
|
43
|
+
const result = await mgr.verify(projectPath, projectId, name, undefined, providerId, legacyProviderId, slug);
|
|
35
44
|
return { name, version: entry.version, result };
|
|
36
45
|
}));
|
|
37
46
|
for (const c of checks) {
|
|
47
|
+
if (!c)
|
|
48
|
+
continue;
|
|
38
49
|
if (c.result.ok)
|
|
39
50
|
active.push({ name: c.name, version: c.version });
|
|
40
51
|
else
|
|
@@ -50,15 +50,20 @@ async function installSerena(ctx) {
|
|
|
50
50
|
}
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
ctx.log(
|
|
56
|
-
await plugin_manager_1.PluginManager.mergeMcpServers(ctx.projectPath, { serena: manifest_1.SERENA_MCP_ENTRY });
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
const adapter = (0, providers_1.getAdapter)(ctx.providerId ?? 'claude');
|
|
54
|
+
const mcpFile = adapter.projectMcpPath?.(ctx.projectPath);
|
|
55
|
+
ctx.log(`Adding mcpServers.serena to ${mcpFile ?? '.mcp.json'}`);
|
|
56
|
+
await plugin_manager_1.PluginManager.mergeMcpServers(ctx.projectPath, { serena: manifest_1.SERENA_MCP_ENTRY }, adapter.id);
|
|
57
|
+
// Claude additionally receives its historical custom-agent fragment. Kimi
|
|
58
|
+
// consumes the provider-aware AGENTS.md contributor and native MCP config;
|
|
59
|
+
// its built-in subagents are not modelled as SpecRails roles.
|
|
60
|
+
if (adapter.id === 'claude') {
|
|
61
|
+
ctx.log(`Writing ${CLAUDE_FRAGMENT_REL}`);
|
|
62
|
+
const fragmentDest = path_1.default.join(ctx.projectPath, CLAUDE_FRAGMENT_REL);
|
|
63
|
+
fs_1.default.mkdirSync(path_1.default.dirname(fragmentDest), { recursive: true });
|
|
64
|
+
fs_1.default.writeFileSync(fragmentDest, instructions_content_1.SERENA_INSTRUCTIONS_MD, 'utf8');
|
|
65
|
+
ctx.recordInstalledFile(CLAUDE_FRAGMENT_REL);
|
|
66
|
+
}
|
|
62
67
|
}
|
|
63
68
|
async function uninstallSerena(ctx) {
|
|
64
69
|
if (isCodex(ctx)) {
|
|
@@ -79,14 +84,17 @@ async function uninstallSerena(ctx) {
|
|
|
79
84
|
}
|
|
80
85
|
return;
|
|
81
86
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
ctx.
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
const adapter = (0, providers_1.getAdapter)(ctx.providerId ?? 'claude');
|
|
88
|
+
ctx.log(`Removing mcpServers.serena from ${adapter.projectMcpPath?.(ctx.projectPath) ?? '.mcp.json'}`);
|
|
89
|
+
await plugin_manager_1.PluginManager.removeMcpServers(ctx.projectPath, ['serena'], adapter.id);
|
|
90
|
+
if (adapter.id === 'claude') {
|
|
91
|
+
const fragmentDest = path_1.default.join(ctx.projectPath, CLAUDE_FRAGMENT_REL);
|
|
92
|
+
if (fs_1.default.existsSync(fragmentDest)) {
|
|
93
|
+
ctx.log(`Removing ${CLAUDE_FRAGMENT_REL}`);
|
|
94
|
+
try {
|
|
95
|
+
fs_1.default.unlinkSync(fragmentDest);
|
|
96
|
+
}
|
|
97
|
+
catch { /* best-effort */ }
|
|
89
98
|
}
|
|
90
|
-
catch { /* best-effort */ }
|
|
91
99
|
}
|
|
92
100
|
}
|
|
@@ -60,13 +60,30 @@ exports.serenaManifest = {
|
|
|
60
60
|
],
|
|
61
61
|
},
|
|
62
62
|
},
|
|
63
|
+
kimi: {
|
|
64
|
+
mcpEntry: {
|
|
65
|
+
command: 'uvx',
|
|
66
|
+
args: [
|
|
67
|
+
'--from',
|
|
68
|
+
'git+https://github.com/oraios/serena',
|
|
69
|
+
'serena',
|
|
70
|
+
'start-mcp-server',
|
|
71
|
+
'--context',
|
|
72
|
+
'ide-assistant',
|
|
73
|
+
'--project',
|
|
74
|
+
'.',
|
|
75
|
+
'--enable-web-dashboard',
|
|
76
|
+
'false',
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
63
80
|
},
|
|
64
81
|
// Format: structured "when / tools / why / fallback" block. Lets generic
|
|
65
82
|
// agent prompts (specrails-core sr-* "Tool Selection — Honor Project-
|
|
66
83
|
// Documented MCP Tools" section) match the right entry to the task.
|
|
67
84
|
//
|
|
68
|
-
// Tool names below are verified against Serena's actual exposed tools
|
|
69
|
-
//
|
|
85
|
+
// Tool names below are verified against Serena's actual exposed MCP tools.
|
|
86
|
+
// Keep this list aligned
|
|
70
87
|
// with upstream — wrong names cause agents to mistrust the whole block.
|
|
71
88
|
claudeMdInstructions: `## Plugin: serena (semantic code navigation)
|
|
72
89
|
|
|
@@ -85,11 +102,11 @@ exports.serenaManifest = {
|
|
|
85
102
|
- \`replace_content\` — surgical text replace inside a single file when symbol-aware tools don't fit.
|
|
86
103
|
- \`get_diagnostics_for_file\` — language-server diagnostics for a file.
|
|
87
104
|
|
|
88
|
-
**Why prefer over built-ins**: Serena returns only the relevant symbol body, not whole files. Empirically cuts input tokens 40–60% on real workloads compared
|
|
105
|
+
**Why prefer over built-ins**: Serena returns only the relevant symbol body, not whole files. Empirically cuts input tokens 40–60% on real workloads compared with whole-file reads or broad text search.
|
|
89
106
|
|
|
90
|
-
**Fallback to
|
|
107
|
+
**Fallback to the provider's built-in file/search tools for**: binary files, free-form prose, structured data without symbols (logs, JSON without schema, plain Markdown).
|
|
91
108
|
|
|
92
|
-
**
|
|
109
|
+
**Delegated agents**: when the active provider supports delegation, tell the delegated role to use these Serena tools. MCP inheritance is provider-owned, so verify availability in the delegated context and fall back to built-in file/search tools when needed.`,
|
|
93
110
|
};
|
|
94
111
|
exports.SERENA_MCP_ENTRY = {
|
|
95
112
|
command: 'uvx',
|
|
@@ -1,24 +1,51 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.verifySerena = verifySerena;
|
|
4
7
|
const child_process_1 = require("child_process");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
5
10
|
const win_spawn_1 = require("../../util/win-spawn");
|
|
11
|
+
const providers_1 = require("../../providers");
|
|
12
|
+
const codex_mcp_1 = require("../codex-mcp");
|
|
6
13
|
const TIMEOUT_MS = 1800;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
function registrationProblem(ctx) {
|
|
15
|
+
// Direct callers from the pre-provider API used verifySerena() as a cheap uv
|
|
16
|
+
// probe. Keep that contract; PluginManager always supplies provider context
|
|
17
|
+
// and therefore receives the stronger registration check below.
|
|
18
|
+
if (!ctx?.providerId)
|
|
19
|
+
return null;
|
|
20
|
+
if (!(0, providers_1.hasAdapter)(ctx.providerId))
|
|
21
|
+
return `unknown-provider:${ctx.providerId}`;
|
|
22
|
+
const adapter = (0, providers_1.getAdapter)(ctx.providerId);
|
|
23
|
+
if (adapter.mcpRegistration === 'cli-add') {
|
|
24
|
+
const slug = ctx.slug?.trim() || path_1.default.basename(ctx.projectPath);
|
|
25
|
+
const listing = (0, codex_mcp_1.codexMcpList)(slug);
|
|
26
|
+
if (!listing.ok)
|
|
27
|
+
return 'mcp-registry-unavailable';
|
|
28
|
+
return listing.servers.includes('serena') ? null : 'mcp-registration-missing';
|
|
29
|
+
}
|
|
30
|
+
const file = adapter.projectMcpPath?.(ctx.projectPath);
|
|
31
|
+
if (!file || !fs_1.default.existsSync(file))
|
|
32
|
+
return 'mcp-registration-missing';
|
|
33
|
+
try {
|
|
34
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
|
|
35
|
+
if (!parsed.mcpServers ||
|
|
36
|
+
typeof parsed.mcpServers !== 'object' ||
|
|
37
|
+
Array.isArray(parsed.mcpServers)) {
|
|
38
|
+
return 'mcp-registration-invalid';
|
|
39
|
+
}
|
|
40
|
+
return Object.prototype.hasOwnProperty.call(parsed.mcpServers, 'serena')
|
|
41
|
+
? null
|
|
42
|
+
: 'mcp-registration-missing';
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return 'mcp-registration-invalid';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function verifySerena(ctx) {
|
|
22
49
|
const checkedAt = new Date().toISOString();
|
|
23
50
|
const isWin = process.platform === 'win32';
|
|
24
51
|
return new Promise((resolve) => {
|
|
@@ -68,7 +95,10 @@ async function verifySerena() {
|
|
|
68
95
|
settled = true;
|
|
69
96
|
clearTimeout(timer);
|
|
70
97
|
if (code === 0) {
|
|
71
|
-
|
|
98
|
+
const reason = registrationProblem(ctx);
|
|
99
|
+
resolve(reason
|
|
100
|
+
? { ok: false, reason, checkedAt }
|
|
101
|
+
: { ok: true, reason: undefined, checkedAt });
|
|
72
102
|
}
|
|
73
103
|
else {
|
|
74
104
|
resolve({
|
|
@@ -8,6 +8,7 @@ const prereq_installer_1 = require("./plugins/prereq-installer");
|
|
|
8
8
|
const path_resolver_1 = require("./path-resolver");
|
|
9
9
|
const claude_approval_1 = require("./plugins/claude-approval");
|
|
10
10
|
const workspace_resolution_1 = require("./workspace-resolution");
|
|
11
|
+
const providers_1 = require("./providers");
|
|
11
12
|
/**
|
|
12
13
|
* Relocate-artifacts gate: the dir the PluginManager mutates (`.mcp.json` +
|
|
13
14
|
* `.specrails/plugins/` state + `.claude/agents/custom-*.md`). Relocated ⇒ the
|
|
@@ -41,6 +42,32 @@ function handleError(res, err) {
|
|
|
41
42
|
const message = err instanceof Error ? err.message : 'unknown error';
|
|
42
43
|
res.status(500).json({ error: message });
|
|
43
44
|
}
|
|
45
|
+
/** Resolve the explicit provider projection for one plugin operation. Legacy
|
|
46
|
+
* clients that omit it keep targeting the project's primary provider. */
|
|
47
|
+
function requestedProvider(req, res, project) {
|
|
48
|
+
const bodyProvider = req.body?.provider;
|
|
49
|
+
const queryProvider = req.query.provider;
|
|
50
|
+
const raw = bodyProvider ?? queryProvider;
|
|
51
|
+
if (raw !== undefined &&
|
|
52
|
+
(typeof raw !== 'string' || raw.trim().length === 0)) {
|
|
53
|
+
res.status(400).json({ error: 'provider must be a non-empty string' });
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const provider = typeof raw === 'string' ? raw.trim() : project.provider;
|
|
57
|
+
const configured = project.providers?.length > 0 ? project.providers : [project.provider];
|
|
58
|
+
if (!configured.includes(provider)) {
|
|
59
|
+
res.status(400).json({
|
|
60
|
+
error: `provider '${provider}' is not configured for this project`,
|
|
61
|
+
providers: configured,
|
|
62
|
+
});
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (!(0, providers_1.hasAdapter)(provider)) {
|
|
66
|
+
res.status(400).json({ error: `unknown provider '${provider}'` });
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return provider;
|
|
70
|
+
}
|
|
44
71
|
function createPluginsRouter() {
|
|
45
72
|
const router = (0, express_1.Router)({ mergeParams: true });
|
|
46
73
|
function ctx(req) {
|
|
@@ -57,7 +84,10 @@ function createPluginsRouter() {
|
|
|
57
84
|
router.get('/', async (req, res) => {
|
|
58
85
|
try {
|
|
59
86
|
const { project } = ctx(req);
|
|
60
|
-
const
|
|
87
|
+
const provider = requestedProvider(req, res, project);
|
|
88
|
+
if (!provider)
|
|
89
|
+
return;
|
|
90
|
+
const list = await (0, manager_1.getPluginManager)().listAvailable(pluginRoot(project), provider, project.provider);
|
|
61
91
|
res.json({ plugins: list });
|
|
62
92
|
}
|
|
63
93
|
catch (err) {
|
|
@@ -68,7 +98,10 @@ function createPluginsRouter() {
|
|
|
68
98
|
router.get('/:name/preview-install', async (req, res) => {
|
|
69
99
|
try {
|
|
70
100
|
const { project } = ctx(req);
|
|
71
|
-
const
|
|
101
|
+
const provider = requestedProvider(req, res, project);
|
|
102
|
+
if (!provider)
|
|
103
|
+
return;
|
|
104
|
+
const result = await (0, manager_1.getPluginManager)().previewInstall(pluginRoot(project), project.id, req.params.name, provider, project.slug);
|
|
72
105
|
res.json(result);
|
|
73
106
|
}
|
|
74
107
|
catch (err) {
|
|
@@ -79,7 +112,10 @@ function createPluginsRouter() {
|
|
|
79
112
|
router.post('/:name/install', async (req, res) => {
|
|
80
113
|
try {
|
|
81
114
|
const { project, broadcast } = ctx(req);
|
|
82
|
-
|
|
115
|
+
const provider = requestedProvider(req, res, project);
|
|
116
|
+
if (!provider)
|
|
117
|
+
return;
|
|
118
|
+
await (0, manager_1.getPluginManager)().install(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.slug, project.provider);
|
|
83
119
|
res.status(200).json({ ok: true });
|
|
84
120
|
}
|
|
85
121
|
catch (err) {
|
|
@@ -90,7 +126,10 @@ function createPluginsRouter() {
|
|
|
90
126
|
router.delete('/:name', async (req, res) => {
|
|
91
127
|
try {
|
|
92
128
|
const { project, broadcast } = ctx(req);
|
|
93
|
-
|
|
129
|
+
const provider = requestedProvider(req, res, project);
|
|
130
|
+
if (!provider)
|
|
131
|
+
return;
|
|
132
|
+
await (0, manager_1.getPluginManager)().uninstall(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.slug, project.provider);
|
|
94
133
|
res.status(200).json({ ok: true });
|
|
95
134
|
}
|
|
96
135
|
catch (err) {
|
|
@@ -182,7 +221,10 @@ function createPluginsRouter() {
|
|
|
182
221
|
router.post('/:name/activate', async (req, res) => {
|
|
183
222
|
try {
|
|
184
223
|
const { project, broadcast } = ctx(req);
|
|
185
|
-
|
|
224
|
+
const provider = requestedProvider(req, res, project);
|
|
225
|
+
if (!provider)
|
|
226
|
+
return;
|
|
227
|
+
await (0, manager_1.getPluginManager)().setActive(pluginRoot(project), project.id, req.params.name, true, broadcast, provider, project.slug, project.provider);
|
|
186
228
|
res.json({ ok: true });
|
|
187
229
|
}
|
|
188
230
|
catch (err) {
|
|
@@ -193,7 +235,10 @@ function createPluginsRouter() {
|
|
|
193
235
|
router.post('/:name/deactivate', async (req, res) => {
|
|
194
236
|
try {
|
|
195
237
|
const { project, broadcast } = ctx(req);
|
|
196
|
-
|
|
238
|
+
const provider = requestedProvider(req, res, project);
|
|
239
|
+
if (!provider)
|
|
240
|
+
return;
|
|
241
|
+
await (0, manager_1.getPluginManager)().setActive(pluginRoot(project), project.id, req.params.name, false, broadcast, provider, project.slug, project.provider);
|
|
197
242
|
res.json({ ok: true });
|
|
198
243
|
}
|
|
199
244
|
catch (err) {
|
|
@@ -204,7 +249,10 @@ function createPluginsRouter() {
|
|
|
204
249
|
router.post('/:name/update', async (req, res) => {
|
|
205
250
|
try {
|
|
206
251
|
const { project, broadcast } = ctx(req);
|
|
207
|
-
|
|
252
|
+
const provider = requestedProvider(req, res, project);
|
|
253
|
+
if (!provider)
|
|
254
|
+
return;
|
|
255
|
+
await (0, manager_1.getPluginManager)().updateMcpEntry(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.slug, project.provider);
|
|
208
256
|
res.json({ ok: true });
|
|
209
257
|
}
|
|
210
258
|
catch (err) {
|
|
@@ -215,7 +263,10 @@ function createPluginsRouter() {
|
|
|
215
263
|
router.get('/:name/health', async (req, res) => {
|
|
216
264
|
try {
|
|
217
265
|
const { project, broadcast } = ctx(req);
|
|
218
|
-
const
|
|
266
|
+
const provider = requestedProvider(req, res, project);
|
|
267
|
+
if (!provider)
|
|
268
|
+
return;
|
|
269
|
+
const result = await (0, manager_1.getPluginManager)().verify(pluginRoot(project), project.id, req.params.name, broadcast, provider, project.provider, project.slug);
|
|
219
270
|
res.json(result);
|
|
220
271
|
}
|
|
221
272
|
catch (err) {
|