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
|
@@ -25,7 +25,8 @@ const node_readline_1 = require("node:readline");
|
|
|
25
25
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
26
26
|
const cli_prompt_1 = require("./util/cli-prompt");
|
|
27
27
|
const spawn_lifecycle_1 = require("./spawn-lifecycle");
|
|
28
|
-
const
|
|
28
|
+
const providers_1 = require("./providers");
|
|
29
|
+
const runtime_1 = require("./providers/runtime");
|
|
29
30
|
const explore_contract_refine_1 = require("./explore-contract-refine");
|
|
30
31
|
const db_1 = require("./db");
|
|
31
32
|
const explore_cwd_manager_1 = require("./explore-cwd-manager");
|
|
@@ -65,29 +66,30 @@ function isResultErrorEvent(resultEvent) {
|
|
|
65
66
|
// `error_*` subtype as a model-side error rather than malformed output.
|
|
66
67
|
return subtype === 'error_max_turns' || subtype.startsWith('error_');
|
|
67
68
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
69
|
+
function buildRefineArgs(adapter, model, systemPrompt, sessionId) {
|
|
70
|
+
const action = sessionId && adapter.capabilities.nativeResume ? 'chat-resume' : 'spec-gen';
|
|
71
|
+
// Chat adapters intentionally keep resumed Explore prompts short because the
|
|
72
|
+
// app-managed cwd already carries the normal Explore stance. Contract Refine
|
|
73
|
+
// is different: its schema is invocation-specific and must be present on the
|
|
74
|
+
// resumed turn. Providers without a native system-prompt flag therefore need
|
|
75
|
+
// the schema folded here, exactly once, before their chat-resume builder
|
|
76
|
+
// deliberately ignores `systemPrompt`.
|
|
77
|
+
const foldForResume = action === 'chat-resume' && !adapter.capabilities.systemPromptArg;
|
|
78
|
+
const options = {
|
|
79
|
+
prompt: foldForResume
|
|
80
|
+
? `${systemPrompt}\n\n---\n\n${explore_contract_refine_1.CONTRACT_MARKER_USER_MESSAGE}`
|
|
81
|
+
: explore_contract_refine_1.CONTRACT_MARKER_USER_MESSAGE,
|
|
82
|
+
model,
|
|
83
|
+
systemPrompt: foldForResume ? undefined : systemPrompt,
|
|
84
|
+
sessionId,
|
|
85
|
+
toolPolicy: 'none',
|
|
86
|
+
maxTurns: 1,
|
|
87
|
+
};
|
|
88
|
+
return { args: adapter.buildArgs(action, options), options };
|
|
87
89
|
}
|
|
88
90
|
/** Build the pure-output, no-resume invocation used by Quick Refine and by the
|
|
89
91
|
* one-time compatibility recovery for cwd-scoped Explore sessions. */
|
|
90
|
-
function buildFreshRefineArgs(model, title, description) {
|
|
92
|
+
function buildFreshRefineArgs(adapter, model, title, description) {
|
|
91
93
|
const systemPrompt = [
|
|
92
94
|
(0, explore_contract_refine_1.buildContractRefineSystemPrompt)(),
|
|
93
95
|
'',
|
|
@@ -99,15 +101,14 @@ function buildFreshRefineArgs(model, title, description) {
|
|
|
99
101
|
'### Description',
|
|
100
102
|
description,
|
|
101
103
|
].join('\n');
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
'
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
];
|
|
104
|
+
const options = {
|
|
105
|
+
prompt: explore_contract_refine_1.CONTRACT_MARKER_USER_MESSAGE,
|
|
106
|
+
model,
|
|
107
|
+
systemPrompt,
|
|
108
|
+
toolPolicy: 'none',
|
|
109
|
+
maxTurns: 1,
|
|
110
|
+
};
|
|
111
|
+
return { args: adapter.buildArgs('spec-gen', options), options };
|
|
111
112
|
}
|
|
112
113
|
/** Match only Claude's missing cwd-scoped session diagnostic. The CLI has
|
|
113
114
|
* emitted it both as stderr and inside structured result payloads, so inspect
|
|
@@ -180,8 +181,10 @@ function prepareContractRefineSpawn(deps, conversation) {
|
|
|
180
181
|
cwd = deps.projectPath;
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
|
-
const
|
|
184
|
-
|
|
184
|
+
const adapter = (0, providers_1.getAdapter)(conversation.provider ?? deps.providerId ?? 'claude');
|
|
185
|
+
const model = conversation.model ?? adapter.defaultModel();
|
|
186
|
+
const built = buildRefineArgs(adapter, model, systemPrompt, conversation.session_id ?? '');
|
|
187
|
+
return { args: built.args, cwd, systemPrompt, env, options: built.options, adapter };
|
|
185
188
|
}
|
|
186
189
|
/** Grace before SIGKILL-escalating a child that swallowed SIGTERM. */
|
|
187
190
|
const REFINE_SIGKILL_GRACE_MS = 2_000;
|
|
@@ -358,13 +361,9 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
358
361
|
console.log(`[contract-refine-runner] skip: conversation missing or not explore (kind=${conversation?.kind})`);
|
|
359
362
|
return { ok: false, reason: 'not-explore', ticketId, conversationId };
|
|
360
363
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
// ran on a non-claude engine; the Add Spec UI already hides the toggle for
|
|
365
|
-
// those, but a manually-crafted scope must never spawn the wrong CLI.
|
|
366
|
-
if (conversation.provider && conversation.provider !== 'claude') {
|
|
367
|
-
console.log(`[contract-refine-runner] skip: provider '${conversation.provider}' does not support contract refine`);
|
|
364
|
+
const adapter = (0, providers_1.getAdapter)(conversation.provider ?? deps.providerId ?? 'claude');
|
|
365
|
+
if (adapter.capabilities.structuredActions !== true) {
|
|
366
|
+
console.log(`[contract-refine-runner] skip: provider '${adapter.id}' does not support structured actions`);
|
|
368
367
|
return { ok: false, reason: 'provider-unsupported', ticketId, conversationId };
|
|
369
368
|
}
|
|
370
369
|
// Per-conversation gating: contractRefine on the conversation's stored
|
|
@@ -394,13 +393,15 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
394
393
|
deps.broadcast({
|
|
395
394
|
type: 'explore.contract_refine_started',
|
|
396
395
|
projectId: deps.projectId,
|
|
396
|
+
provider: adapter.id,
|
|
397
397
|
ticketId,
|
|
398
398
|
timestamp: now().toISOString(),
|
|
399
399
|
});
|
|
400
|
-
const { args, cwd, env: refineEnv } = prepareContractRefineSpawn({
|
|
400
|
+
const { args, cwd, env: refineEnv, options: refineOptions } = prepareContractRefineSpawn({
|
|
401
401
|
projectSlug: deps.projectSlug,
|
|
402
402
|
projectPath: deps.projectPath,
|
|
403
403
|
projectName: deps.projectName,
|
|
404
|
+
providerId: adapter.id,
|
|
404
405
|
}, conversation);
|
|
405
406
|
const startedAt = now().toISOString();
|
|
406
407
|
// Spawn/stream/timeout/settlement is owned by the shared spawn-lifecycle; the
|
|
@@ -408,38 +409,24 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
408
409
|
// the raw result event) and all finalize/record/broadcast logic stay here.
|
|
409
410
|
// Keeping the invocation result in one shape also lets the narrowly-gated
|
|
410
411
|
// missing-session recovery re-enter the exact same finalization path.
|
|
411
|
-
const invoke = async (invocationArgs) => {
|
|
412
|
+
const invoke = async (invocationArgs, invocationOptions) => {
|
|
412
413
|
let fullText = '';
|
|
413
414
|
let resultEvent = null;
|
|
414
415
|
const run = await (0, spawn_lifecycle_1.runAiCliInvocation)({
|
|
415
|
-
adapter
|
|
416
|
-
binary:
|
|
416
|
+
adapter,
|
|
417
|
+
binary: adapter.binary,
|
|
417
418
|
argv: invocationArgs,
|
|
418
419
|
cwd,
|
|
419
|
-
env: refineEnv ?? process.env,
|
|
420
|
+
env: (0, runtime_1.buildProviderEnv)(adapter, invocationOptions, refineEnv ?? process.env),
|
|
420
421
|
spawn,
|
|
421
422
|
timeoutMs,
|
|
422
423
|
onSpawn: (child) => (0, transient_children_1.trackTransientChild)(deps.projectId, child),
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
parsed = JSON.parse(line);
|
|
424
|
+
onEvent: (event) => {
|
|
425
|
+
if (event.kind === 'text-delta') {
|
|
426
|
+
fullText += event.text;
|
|
427
427
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
if (!parsed)
|
|
432
|
-
return;
|
|
433
|
-
const type = parsed.type;
|
|
434
|
-
if (type === 'result') {
|
|
435
|
-
resultEvent = parsed;
|
|
436
|
-
}
|
|
437
|
-
else if (type === 'assistant') {
|
|
438
|
-
const message = parsed.message;
|
|
439
|
-
for (const b of (message?.content ?? [])) {
|
|
440
|
-
if (b.type === 'text' && typeof b.text === 'string')
|
|
441
|
-
fullText += b.text;
|
|
442
|
-
}
|
|
428
|
+
else if (event.kind === 'result') {
|
|
429
|
+
resultEvent = event.payload;
|
|
443
430
|
}
|
|
444
431
|
},
|
|
445
432
|
});
|
|
@@ -450,9 +437,10 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
450
437
|
timedOut: run.timedOut,
|
|
451
438
|
spawnFailed: run.spawnFailed,
|
|
452
439
|
stderrTail: run.stderrTail,
|
|
440
|
+
events: run.events,
|
|
453
441
|
};
|
|
454
442
|
};
|
|
455
|
-
let result = await invoke(args);
|
|
443
|
+
let result = await invoke(args, refineOptions);
|
|
456
444
|
if (!admission.isCurrent()) {
|
|
457
445
|
return { ok: false, reason: 'aborted', ticketId, conversationId };
|
|
458
446
|
}
|
|
@@ -468,7 +456,7 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
468
456
|
const missingSessionDiagnostic = containsMissingClaudeSessionDiagnostic(result.fullText) ||
|
|
469
457
|
containsMissingClaudeSessionDiagnostic(result.resultEvent) ||
|
|
470
458
|
containsMissingClaudeSessionDiagnostic(result.stderrTail);
|
|
471
|
-
if (resumedFromRelocatedWorkspace && resumeFailed && missingSessionDiagnostic) {
|
|
459
|
+
if (adapter.id === 'claude' && resumedFromRelocatedWorkspace && resumeFailed && missingSessionDiagnostic) {
|
|
472
460
|
let ticket = null;
|
|
473
461
|
try {
|
|
474
462
|
ticket = (0, ticket_store_1.readStore)(resolveContractTicketsPath(deps.projectPath)).tickets[String(ticketId)] ?? null;
|
|
@@ -478,7 +466,8 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
478
466
|
}
|
|
479
467
|
if (ticket) {
|
|
480
468
|
console.warn(`[contract-refine-runner] resume session unavailable; retrying once fresh from workspace ticket=${ticketId}`);
|
|
481
|
-
|
|
469
|
+
const fresh = buildFreshRefineArgs(adapter, conversation.model ?? adapter.defaultModel(), ticket.title, ticket.description);
|
|
470
|
+
result = await invoke(fresh.args, fresh.options);
|
|
482
471
|
if (!admission.isCurrent()) {
|
|
483
472
|
return { ok: false, reason: 'aborted', ticketId, conversationId };
|
|
484
473
|
}
|
|
@@ -486,10 +475,11 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
486
475
|
}
|
|
487
476
|
const finishedAt = now().toISOString();
|
|
488
477
|
if (result.spawnFailed) {
|
|
489
|
-
recordSafely(deps, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed',
|
|
478
|
+
recordSafely(deps, adapter, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.events);
|
|
490
479
|
deps.broadcast({
|
|
491
480
|
type: 'explore.contract_refine_failed',
|
|
492
481
|
projectId: deps.projectId,
|
|
482
|
+
provider: adapter.id,
|
|
493
483
|
ticketId,
|
|
494
484
|
reason: 'crashed',
|
|
495
485
|
timestamp: finishedAt,
|
|
@@ -498,17 +488,19 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
498
488
|
}
|
|
499
489
|
console.log(`[contract-refine-runner] spawn done code=${result.code} timedOut=${result.timedOut} hasResult=${!!result.resultEvent} textBytes=${result.fullText.length}`);
|
|
500
490
|
if (result.timedOut) {
|
|
501
|
-
recordSafely(deps, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'aborted', result.
|
|
491
|
+
recordSafely(deps, adapter, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'aborted', result.events);
|
|
502
492
|
deps.broadcast({
|
|
503
493
|
type: 'explore.contract_refine_failed',
|
|
504
494
|
projectId: deps.projectId,
|
|
495
|
+
provider: adapter.id,
|
|
505
496
|
ticketId,
|
|
506
497
|
reason: 'timeout',
|
|
507
498
|
timestamp: finishedAt,
|
|
508
499
|
});
|
|
509
500
|
return { ok: false, reason: 'timeout', ticketId, conversationId };
|
|
510
501
|
}
|
|
511
|
-
|
|
502
|
+
const providerError = result.events.some((event) => event.kind === 'error');
|
|
503
|
+
if (result.code !== 0 || providerError || !result.fullText.trim()) {
|
|
512
504
|
const r = result.resultEvent;
|
|
513
505
|
console.log(`[contract-refine-runner] non-zero exit code=${result.code} ` +
|
|
514
506
|
`subtype=${r?.subtype ?? '-'} is_error=${r?.is_error ?? '-'} ` +
|
|
@@ -516,25 +508,27 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
516
508
|
`textTail=${JSON.stringify(result.fullText.slice(-400))}`);
|
|
517
509
|
if (r)
|
|
518
510
|
console.log(`[contract-refine-runner] result event: ${JSON.stringify(r).slice(0, 2000)}`);
|
|
519
|
-
recordSafely(deps, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.
|
|
511
|
+
recordSafely(deps, adapter, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.events);
|
|
520
512
|
deps.broadcast({
|
|
521
513
|
type: 'explore.contract_refine_failed',
|
|
522
514
|
projectId: deps.projectId,
|
|
515
|
+
provider: adapter.id,
|
|
523
516
|
ticketId,
|
|
524
|
-
reason: result.resultEvent ? 'model_error' : 'crashed',
|
|
517
|
+
reason: providerError || result.resultEvent ? 'model_error' : 'crashed',
|
|
525
518
|
timestamp: finishedAt,
|
|
526
519
|
});
|
|
527
|
-
return { ok: false, reason: result.resultEvent ? 'model_error' : 'crashed', ticketId, conversationId };
|
|
520
|
+
return { ok: false, reason: providerError || result.resultEvent ? 'model_error' : 'crashed', ticketId, conversationId };
|
|
528
521
|
}
|
|
529
522
|
// BUG-PARSER-04: exit-0 but the result event flags an error / max-turns
|
|
530
523
|
// truncation — classify as model_error, not malformed.
|
|
531
|
-
if (isResultErrorEvent(result.resultEvent)) {
|
|
524
|
+
if (result.resultEvent && isResultErrorEvent(result.resultEvent)) {
|
|
532
525
|
const r = result.resultEvent;
|
|
533
526
|
console.log(`[contract-refine-runner] result error event subtype=${r.subtype ?? '-'} is_error=${r.is_error ?? '-'}`);
|
|
534
|
-
recordSafely(deps, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.
|
|
527
|
+
recordSafely(deps, adapter, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.events);
|
|
535
528
|
deps.broadcast({
|
|
536
529
|
type: 'explore.contract_refine_failed',
|
|
537
530
|
projectId: deps.projectId,
|
|
531
|
+
provider: adapter.id,
|
|
538
532
|
ticketId,
|
|
539
533
|
reason: 'model_error',
|
|
540
534
|
timestamp: finishedAt,
|
|
@@ -547,10 +541,11 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
547
541
|
const reason = parse.reason === 'parser-error'
|
|
548
542
|
? 'parser_error'
|
|
549
543
|
: 'malformed';
|
|
550
|
-
recordSafely(deps, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.
|
|
544
|
+
recordSafely(deps, adapter, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.events);
|
|
551
545
|
deps.broadcast({
|
|
552
546
|
type: 'explore.contract_refine_failed',
|
|
553
547
|
projectId: deps.projectId,
|
|
548
|
+
provider: adapter.id,
|
|
554
549
|
ticketId,
|
|
555
550
|
reason,
|
|
556
551
|
timestamp: finishedAt,
|
|
@@ -565,17 +560,18 @@ async function runContractRefine(deps, conversationId, ticketId) {
|
|
|
565
560
|
}
|
|
566
561
|
catch (err) {
|
|
567
562
|
console.error('[contract-refine-runner] PATCH failed:', err);
|
|
568
|
-
recordSafely(deps, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.
|
|
563
|
+
recordSafely(deps, adapter, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'failed', result.events);
|
|
569
564
|
deps.broadcast({
|
|
570
565
|
type: 'explore.contract_refine_failed',
|
|
571
566
|
projectId: deps.projectId,
|
|
567
|
+
provider: adapter.id,
|
|
572
568
|
ticketId,
|
|
573
569
|
reason: 'parser_error',
|
|
574
570
|
timestamp: finishedAt,
|
|
575
571
|
});
|
|
576
572
|
return { ok: false, reason: 'parser_error', ticketId, conversationId };
|
|
577
573
|
}
|
|
578
|
-
recordSafely(deps, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'success', result.
|
|
574
|
+
recordSafely(deps, adapter, conversationId, ticketId, conversation.model, startedAt, finishedAt, 'success', result.events);
|
|
579
575
|
if (updated) {
|
|
580
576
|
deps.broadcast({
|
|
581
577
|
type: 'ticket_updated',
|
|
@@ -605,79 +601,106 @@ async function runContractRefineForQuick(deps, ticketId, generatedTitle, generat
|
|
|
605
601
|
return { ok: false, reason: 'disabled', ticketId, conversationId: '' };
|
|
606
602
|
}
|
|
607
603
|
const admission = (0, process_admission_1.captureProcessAdmission)(deps.projectId);
|
|
608
|
-
const
|
|
604
|
+
const adapter = (0, providers_1.getAdapter)(deps.providerId ?? 'claude');
|
|
605
|
+
if (adapter.capabilities.structuredActions !== true) {
|
|
606
|
+
return { ok: false, reason: 'provider-unsupported', ticketId, conversationId: '' };
|
|
607
|
+
}
|
|
608
|
+
const resolvedModel = model ?? adapter.defaultModel();
|
|
609
|
+
const built = buildFreshRefineArgs(adapter, resolvedModel, generatedTitle, generatedDescription);
|
|
609
610
|
const startedAt = now().toISOString();
|
|
610
611
|
deps.broadcast({
|
|
611
612
|
type: 'explore.contract_refine_started',
|
|
612
613
|
projectId: deps.projectId,
|
|
614
|
+
provider: adapter.id,
|
|
613
615
|
ticketId,
|
|
614
616
|
timestamp: startedAt,
|
|
615
617
|
});
|
|
616
618
|
// Relocate-artifacts gate: spawn from the workspace + SPECRAILS_REPO_DIR when
|
|
617
619
|
// relocated, else cwd = project.path + process.env (byte-identical legacy).
|
|
618
620
|
const quickExec = (0, workspace_resolution_1.resolveProjectExecution)({ slug: deps.projectSlug, path: deps.projectPath });
|
|
619
|
-
let
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
(0,
|
|
621
|
+
let fullText = '';
|
|
622
|
+
let resultEvent = null;
|
|
623
|
+
const run = await (0, spawn_lifecycle_1.runAiCliInvocation)({
|
|
624
|
+
adapter,
|
|
625
|
+
binary: adapter.binary,
|
|
626
|
+
argv: built.args,
|
|
627
|
+
cwd: quickExec.cwd,
|
|
628
|
+
env: (0, runtime_1.buildProviderEnv)(adapter, built.options, quickExec.relocated ? { ...process.env, ...quickExec.env } : process.env),
|
|
629
|
+
spawn,
|
|
630
|
+
timeoutMs,
|
|
631
|
+
onSpawn: (child) => (0, transient_children_1.trackTransientChild)(deps.projectId, child),
|
|
632
|
+
onEvent: (event) => {
|
|
633
|
+
if (event.kind === 'text-delta')
|
|
634
|
+
fullText += event.text;
|
|
635
|
+
else if (event.kind === 'result')
|
|
636
|
+
resultEvent = event.payload;
|
|
637
|
+
},
|
|
638
|
+
});
|
|
639
|
+
const result = {
|
|
640
|
+
fullText,
|
|
641
|
+
resultEvent,
|
|
642
|
+
code: run.code,
|
|
643
|
+
timedOut: run.timedOut,
|
|
644
|
+
spawnFailed: run.spawnFailed,
|
|
645
|
+
events: run.events,
|
|
646
|
+
};
|
|
647
|
+
if (!admission.isCurrent()) {
|
|
648
|
+
return { ok: false, reason: 'aborted', ticketId, conversationId: '' };
|
|
627
649
|
}
|
|
628
|
-
|
|
629
|
-
|
|
650
|
+
const finishedAt = now().toISOString();
|
|
651
|
+
console.log(`[contract-refine-runner] quick spawn done code=${result.code} timedOut=${result.timedOut} textBytes=${result.fullText.length}`);
|
|
652
|
+
if (result.spawnFailed) {
|
|
653
|
+
recordSafelyQuick(deps, adapter, ticketId, resolvedModel, startedAt, finishedAt, 'failed', result.events);
|
|
630
654
|
deps.broadcast({
|
|
631
655
|
type: 'explore.contract_refine_failed',
|
|
632
656
|
projectId: deps.projectId,
|
|
657
|
+
provider: adapter.id,
|
|
633
658
|
ticketId,
|
|
634
659
|
reason: 'crashed',
|
|
635
|
-
timestamp:
|
|
660
|
+
timestamp: finishedAt,
|
|
636
661
|
});
|
|
637
662
|
return { ok: false, reason: 'crashed', ticketId, conversationId: '' };
|
|
638
663
|
}
|
|
639
|
-
const result = await readRefineChildOutput(child, timeoutMs);
|
|
640
|
-
if (!admission.isCurrent()) {
|
|
641
|
-
return { ok: false, reason: 'aborted', ticketId, conversationId: '' };
|
|
642
|
-
}
|
|
643
|
-
const finishedAt = now().toISOString();
|
|
644
|
-
console.log(`[contract-refine-runner] quick spawn done code=${result.code} timedOut=${result.timedOut} textBytes=${result.fullText.length}`);
|
|
645
664
|
if (result.timedOut) {
|
|
646
|
-
recordSafelyQuick(deps, ticketId,
|
|
665
|
+
recordSafelyQuick(deps, adapter, ticketId, resolvedModel, startedAt, finishedAt, 'aborted', result.events);
|
|
647
666
|
deps.broadcast({
|
|
648
667
|
type: 'explore.contract_refine_failed',
|
|
649
668
|
projectId: deps.projectId,
|
|
669
|
+
provider: adapter.id,
|
|
650
670
|
ticketId,
|
|
651
671
|
reason: 'timeout',
|
|
652
672
|
timestamp: finishedAt,
|
|
653
673
|
});
|
|
654
674
|
return { ok: false, reason: 'timeout', ticketId, conversationId: '' };
|
|
655
675
|
}
|
|
656
|
-
|
|
676
|
+
const providerError = result.events.some((event) => event.kind === 'error');
|
|
677
|
+
if (result.code !== 0 || providerError || !result.fullText.trim()) {
|
|
657
678
|
const r = result.resultEvent;
|
|
658
679
|
console.log(`[contract-refine-runner] quick non-zero exit code=${result.code} ` +
|
|
659
680
|
`subtype=${r?.subtype ?? '-'} is_error=${r?.is_error ?? '-'} ` +
|
|
660
681
|
`num_turns=${r?.num_turns ?? '-'} ` +
|
|
661
682
|
`textTail=${JSON.stringify(result.fullText.slice(-400))}`);
|
|
662
|
-
recordSafelyQuick(deps, ticketId,
|
|
683
|
+
recordSafelyQuick(deps, adapter, ticketId, resolvedModel, startedAt, finishedAt, 'failed', result.events);
|
|
663
684
|
deps.broadcast({
|
|
664
685
|
type: 'explore.contract_refine_failed',
|
|
665
686
|
projectId: deps.projectId,
|
|
687
|
+
provider: adapter.id,
|
|
666
688
|
ticketId,
|
|
667
|
-
reason: result.resultEvent ? 'model_error' : 'crashed',
|
|
689
|
+
reason: providerError || result.resultEvent ? 'model_error' : 'crashed',
|
|
668
690
|
timestamp: finishedAt,
|
|
669
691
|
});
|
|
670
|
-
return { ok: false, reason: result.resultEvent ? 'model_error' : 'crashed', ticketId, conversationId: '' };
|
|
692
|
+
return { ok: false, reason: providerError || result.resultEvent ? 'model_error' : 'crashed', ticketId, conversationId: '' };
|
|
671
693
|
}
|
|
672
694
|
// BUG-PARSER-04: exit-0 but the result event flags an error / max-turns
|
|
673
695
|
// truncation — classify as model_error, not malformed.
|
|
674
|
-
if (isResultErrorEvent(result.resultEvent)) {
|
|
696
|
+
if (result.resultEvent && isResultErrorEvent(result.resultEvent)) {
|
|
675
697
|
const r = result.resultEvent;
|
|
676
698
|
console.log(`[contract-refine-runner] quick result error event subtype=${r.subtype ?? '-'} is_error=${r.is_error ?? '-'}`);
|
|
677
|
-
recordSafelyQuick(deps, ticketId,
|
|
699
|
+
recordSafelyQuick(deps, adapter, ticketId, resolvedModel, startedAt, finishedAt, 'failed', result.events);
|
|
678
700
|
deps.broadcast({
|
|
679
701
|
type: 'explore.contract_refine_failed',
|
|
680
702
|
projectId: deps.projectId,
|
|
703
|
+
provider: adapter.id,
|
|
681
704
|
ticketId,
|
|
682
705
|
reason: 'model_error',
|
|
683
706
|
timestamp: finishedAt,
|
|
@@ -687,10 +710,11 @@ async function runContractRefineForQuick(deps, ticketId, generatedTitle, generat
|
|
|
687
710
|
const parse = (0, explore_contract_refine_1.parseContractLayerBlock)(result.fullText);
|
|
688
711
|
if (!parse.ok) {
|
|
689
712
|
const reason = parse.reason === 'parser-error' ? 'parser_error' : 'malformed';
|
|
690
|
-
recordSafelyQuick(deps, ticketId,
|
|
713
|
+
recordSafelyQuick(deps, adapter, ticketId, resolvedModel, startedAt, finishedAt, 'failed', result.events);
|
|
691
714
|
deps.broadcast({
|
|
692
715
|
type: 'explore.contract_refine_failed',
|
|
693
716
|
projectId: deps.projectId,
|
|
717
|
+
provider: adapter.id,
|
|
694
718
|
ticketId,
|
|
695
719
|
reason,
|
|
696
720
|
timestamp: finishedAt,
|
|
@@ -704,17 +728,18 @@ async function runContractRefineForQuick(deps, ticketId, generatedTitle, generat
|
|
|
704
728
|
}
|
|
705
729
|
catch (err) {
|
|
706
730
|
console.error('[contract-refine-runner] quick PATCH failed:', err);
|
|
707
|
-
recordSafelyQuick(deps, ticketId,
|
|
731
|
+
recordSafelyQuick(deps, adapter, ticketId, resolvedModel, startedAt, finishedAt, 'failed', result.events);
|
|
708
732
|
deps.broadcast({
|
|
709
733
|
type: 'explore.contract_refine_failed',
|
|
710
734
|
projectId: deps.projectId,
|
|
735
|
+
provider: adapter.id,
|
|
711
736
|
ticketId,
|
|
712
737
|
reason: 'parser_error',
|
|
713
738
|
timestamp: finishedAt,
|
|
714
739
|
});
|
|
715
740
|
return { ok: false, reason: 'parser_error', ticketId, conversationId: '' };
|
|
716
741
|
}
|
|
717
|
-
recordSafelyQuick(deps, ticketId,
|
|
742
|
+
recordSafelyQuick(deps, adapter, ticketId, resolvedModel, startedAt, finishedAt, 'success', result.events);
|
|
718
743
|
if (updated) {
|
|
719
744
|
deps.broadcast({
|
|
720
745
|
type: 'ticket_updated',
|
|
@@ -726,13 +751,16 @@ async function runContractRefineForQuick(deps, ticketId, generatedTitle, generat
|
|
|
726
751
|
deps.broadcast({ type: 'spending.invalidated', projectId: deps.projectId });
|
|
727
752
|
return { ok: true, ticketId, conversationId: '' };
|
|
728
753
|
}
|
|
729
|
-
function recordSafelyQuick(deps, ticketId, model, startedAt, finishedAt, status,
|
|
754
|
+
function recordSafelyQuick(deps, adapter, ticketId, model, startedAt, finishedAt, status, events) {
|
|
730
755
|
try {
|
|
731
|
-
const normalised
|
|
756
|
+
const { result: normalised, estimated } = (0, result_event_1.finaliseInvocationResult)(adapter, events, {
|
|
757
|
+
fallbackModel: model ?? adapter.defaultModel(),
|
|
758
|
+
durationMs: Math.max(0, Date.parse(finishedAt) - Date.parse(startedAt)),
|
|
759
|
+
});
|
|
732
760
|
(0, ai_invocations_1.recordInvocation)(deps.db, {
|
|
733
761
|
id: (0, node_crypto_1.randomUUID)(),
|
|
734
762
|
project_id: deps.projectId,
|
|
735
|
-
provider:
|
|
763
|
+
provider: adapter.id,
|
|
736
764
|
surface: 'quick-spec',
|
|
737
765
|
surface_ref_id: `contract-refine:${ticketId}`,
|
|
738
766
|
conversation_id: null,
|
|
@@ -740,21 +768,25 @@ function recordSafelyQuick(deps, ticketId, model, startedAt, finishedAt, status,
|
|
|
740
768
|
status,
|
|
741
769
|
started_at: startedAt,
|
|
742
770
|
finished_at: finishedAt,
|
|
771
|
+
total_cost_usd_estimated: estimated,
|
|
743
772
|
...normalised,
|
|
744
|
-
model:
|
|
773
|
+
model: normalised.model ?? model ?? undefined,
|
|
745
774
|
});
|
|
746
775
|
}
|
|
747
776
|
catch (err) {
|
|
748
777
|
console.error('[contract-refine-runner] quick recordInvocation failed:', err);
|
|
749
778
|
}
|
|
750
779
|
}
|
|
751
|
-
function recordSafely(deps, conversationId, ticketId, model, startedAt, finishedAt, status,
|
|
780
|
+
function recordSafely(deps, adapter, conversationId, ticketId, model, startedAt, finishedAt, status, events) {
|
|
752
781
|
try {
|
|
753
|
-
const normalised
|
|
782
|
+
const { result: normalised, estimated } = (0, result_event_1.finaliseInvocationResult)(adapter, events, {
|
|
783
|
+
fallbackModel: model ?? adapter.defaultModel(),
|
|
784
|
+
durationMs: Math.max(0, Date.parse(finishedAt) - Date.parse(startedAt)),
|
|
785
|
+
});
|
|
754
786
|
(0, ai_invocations_1.recordInvocation)(deps.db, {
|
|
755
787
|
id: (0, node_crypto_1.randomUUID)(),
|
|
756
788
|
project_id: deps.projectId,
|
|
757
|
-
provider:
|
|
789
|
+
provider: adapter.id,
|
|
758
790
|
surface: 'explore-spec',
|
|
759
791
|
surface_ref_id: `contract-refine:${conversationId}`,
|
|
760
792
|
conversation_id: conversationId,
|
|
@@ -762,8 +794,9 @@ function recordSafely(deps, conversationId, ticketId, model, startedAt, finished
|
|
|
762
794
|
status,
|
|
763
795
|
started_at: startedAt,
|
|
764
796
|
finished_at: finishedAt,
|
|
797
|
+
total_cost_usd_estimated: estimated,
|
|
765
798
|
...normalised,
|
|
766
|
-
model:
|
|
799
|
+
model: normalised.model ?? model ?? undefined,
|
|
767
800
|
});
|
|
768
801
|
}
|
|
769
802
|
catch (err) {
|
|
@@ -9,10 +9,12 @@ exports.detectAvailableCLIs = detectAvailableCLIs;
|
|
|
9
9
|
exports.detectCLI = detectCLI;
|
|
10
10
|
exports.getCLIStatus = getCLIStatus;
|
|
11
11
|
exports.checkCoreCompat = checkCoreCompat;
|
|
12
|
+
exports.coreCompatSupportsProvider = coreCompatSupportsProvider;
|
|
12
13
|
const child_process_1 = require("child_process");
|
|
13
14
|
const fs_1 = __importDefault(require("fs"));
|
|
14
15
|
const path_1 = __importDefault(require("path"));
|
|
15
16
|
const setup_manager_1 = require("./setup-manager");
|
|
17
|
+
const bundled_core_1 = require("./bundled-core");
|
|
16
18
|
// Windows has no `which`; probe PATH via `where` instead.
|
|
17
19
|
const WHICH_CMD = process.platform === 'win32' ? 'where' : 'which';
|
|
18
20
|
// These must mirror KNOWN_VERBS in cli/specrails-desktop.ts
|
|
@@ -27,15 +29,55 @@ const DESKTOP_KNOWN_COMMANDS = new Set([
|
|
|
27
29
|
'compat-check',
|
|
28
30
|
'enrich',
|
|
29
31
|
]);
|
|
32
|
+
function isRecord(value) {
|
|
33
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
function isStringArray(value) {
|
|
36
|
+
return Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A provider key alone is not proof that Core can render or launch it. Require
|
|
40
|
+
* the common workflow surface and, for Kimi, the managed materialization runner
|
|
41
|
+
* that Desktop depends on for every headless Core command.
|
|
42
|
+
*/
|
|
43
|
+
function isRenderedProviderContract(provider, value) {
|
|
44
|
+
if (!isRecord(value))
|
|
45
|
+
return false;
|
|
46
|
+
if (typeof value.enrichCommand !== 'string' ||
|
|
47
|
+
value.enrichCommand.length === 0 ||
|
|
48
|
+
!isStringArray(value.enrichArgs) ||
|
|
49
|
+
typeof value.updateCommand !== 'string' ||
|
|
50
|
+
value.updateCommand.length === 0 ||
|
|
51
|
+
!isStringArray(value.updateArgs) ||
|
|
52
|
+
!isRecord(value.cli)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (provider !== 'kimi')
|
|
56
|
+
return true;
|
|
57
|
+
const cli = value.cli;
|
|
58
|
+
const skillRunner = cli.skillRunner;
|
|
59
|
+
return cli.providerBinary === 'kimi' &&
|
|
60
|
+
typeof skillRunner === 'string' &&
|
|
61
|
+
skillRunner === '.kimi-code/specrails/run-skill.mjs' &&
|
|
62
|
+
isStringArray(cli.enrichArgs) &&
|
|
63
|
+
cli.enrichArgs.includes(skillRunner);
|
|
64
|
+
}
|
|
30
65
|
async function findCoreContract() {
|
|
31
|
-
// Strategy 1:
|
|
66
|
+
// Strategy 1: the packaged Desktop's bundled Core is authoritative.
|
|
67
|
+
const bundledRoot = (0, bundled_core_1.getBundledCoreRoot)();
|
|
68
|
+
if (bundledRoot) {
|
|
69
|
+
const contractPath = path_1.default.join(bundledRoot, 'integration-contract.json');
|
|
70
|
+
if (fs_1.default.existsSync(contractPath))
|
|
71
|
+
return contractPath;
|
|
72
|
+
}
|
|
73
|
+
// Strategy 2: Try require.resolve (works for local installs)
|
|
32
74
|
try {
|
|
33
75
|
const contractPath = require.resolve('specrails-core/integration-contract.json');
|
|
34
76
|
if (fs_1.default.existsSync(contractPath))
|
|
35
77
|
return contractPath;
|
|
36
78
|
}
|
|
37
79
|
catch { /* not locally installed */ }
|
|
38
|
-
// Strategy
|
|
80
|
+
// Strategy 3: npm root -g
|
|
39
81
|
try {
|
|
40
82
|
const globalRoot = (0, child_process_1.execSync)('npm root -g', {
|
|
41
83
|
encoding: 'utf-8',
|
|
@@ -149,9 +191,15 @@ async function checkCoreCompat() {
|
|
|
149
191
|
missingCommands: [],
|
|
150
192
|
extraCommands: [],
|
|
151
193
|
contractFound: false,
|
|
194
|
+
supportedProviders: [],
|
|
152
195
|
};
|
|
153
196
|
}
|
|
154
197
|
const contract = JSON.parse(fs_1.default.readFileSync(contractPath, 'utf-8'));
|
|
198
|
+
const supportedProviders = contract.providers && typeof contract.providers === 'object'
|
|
199
|
+
? Object.entries(contract.providers)
|
|
200
|
+
.filter(([provider, providerContract]) => isRenderedProviderContract(provider, providerContract))
|
|
201
|
+
.map(([provider]) => provider)
|
|
202
|
+
: [];
|
|
155
203
|
const desktopCheckpointKeys = setup_manager_1.CHECKPOINTS.map((cp) => cp.key);
|
|
156
204
|
// v1/v2 store checkpoints as a string[]; v3+ stores them as a description map.
|
|
157
205
|
const contractCheckpoints = Array.isArray(contract.checkpoints)
|
|
@@ -182,8 +230,15 @@ async function checkCoreCompat() {
|
|
|
182
230
|
extraCommands,
|
|
183
231
|
contractFound: true,
|
|
184
232
|
contractSchemaVersion: contract.schemaVersion,
|
|
233
|
+
supportedProviders,
|
|
185
234
|
};
|
|
186
235
|
}
|
|
236
|
+
/** True only when the located Core contract explicitly renders this provider. */
|
|
237
|
+
function coreCompatSupportsProvider(result, provider) {
|
|
238
|
+
return result.contractFound &&
|
|
239
|
+
Array.isArray(result.supportedProviders) &&
|
|
240
|
+
result.supportedProviders.includes(provider);
|
|
241
|
+
}
|
|
187
242
|
// v3 contracts no longer include `coreVersion` at the top level â fall back
|
|
188
243
|
// to reading it from the package.json next to the contract file.
|
|
189
244
|
function readCoreVersionNear(contractPath) {
|