cartethyia 2.7.5 → 2.7.7
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/.env.example +8 -3
- package/README.md +26 -2
- package/dist/dashboard/assets/BannedPage-B05aF8Dg.js +1 -0
- package/dist/dashboard/assets/BannedPage-B05aF8Dg.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-CLUhmjUy.js +3 -0
- package/dist/dashboard/assets/CliToolDetailPage-CLUhmjUy.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-CQmrqqrk.js +1 -0
- package/dist/dashboard/assets/CliToolsPage-CQmrqqrk.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-CHG_1Wr3.js +1 -0
- package/dist/dashboard/assets/CombosPage-CHG_1Wr3.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-D5rol2j2.js → ConsoleLogPage-DPgbklad.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-DPgbklad.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-BKj_r0rp.js → CustomizationPage-pnfAqr_-.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-pnfAqr_-.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DGJuU2A6.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-DGJuU2A6.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-B5nZvmf0.js → InjectSystemPromptPanel-C-e2AMz6.js} +245 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-C-e2AMz6.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-J8wPbmfT.js +1 -0
- package/dist/dashboard/assets/LoginPage-J8wPbmfT.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-DnQPSIA8.js → ModelPicker-C6WlpU5E.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BSQnF2Lp.js +1 -0
- package/dist/dashboard/assets/OverviewPage-BSQnF2Lp.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-DK_e0FJz.js +7 -0
- package/dist/dashboard/assets/ProviderDetailPage-DK_e0FJz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-D_a3r6Gc.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-D_a3r6Gc.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-5SnUSy3j.js → ProxyPage-BBTRBAQ3.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BBTRBAQ3.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-B2WqMSG1.js +1 -0
- package/dist/dashboard/assets/QuotaPage-B2WqMSG1.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-BJtRZ4qD.js → SettingsPage-D7xp5Ij_.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-D7xp5Ij_.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-LND6_Ss7.js +1 -0
- package/dist/dashboard/assets/SetupPage-LND6_Ss7.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-BfAb5-o_.js → StudioPage-BzNnm6Bi.js} +4 -4
- package/dist/dashboard/assets/StudioPage-BzNnm6Bi.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js +1 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-BNzeZ2Vk.js → UsagePage-C1TbL24N.js} +13 -13
- package/dist/dashboard/assets/UsagePage-C1TbL24N.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +1 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js +9 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js.gz +0 -0
- package/dist/dashboard/assets/app-mweRcsKp.css +2 -0
- package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
- package/dist/dashboard/assets/{assert-C0K-c4eo.js → assert-CidQVoNo.js} +1 -1
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DfbhQU4k.js → badge-BaX2GTrn.js} +1 -1
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/{banner-BllT4LcF.js → banner-DFH4Bkte.js} +1 -1
- package/dist/dashboard/assets/banner-DFH4Bkte.js.gz +0 -0
- package/dist/dashboard/assets/{card-CtkX66Wd.js → card-CxDw0lK6.js} +1 -1
- package/dist/dashboard/assets/card-CxDw0lK6.js.gz +0 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js +1 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-CQXVMn4P.js → cli-tools-Bwv5-zGZ.js} +1 -1
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-BQqBQd2n.js → clipboard-button-DfS1ntiq.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js +1 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BrTEZ8zu.js → drawer-QqPul6sC.js} +1 -1
- package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js +1 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js +1 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
- package/dist/dashboard/assets/entry-vqGb8yVz.js +4 -0
- package/dist/dashboard/assets/entry-vqGb8yVz.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DP-5E01-.js +1 -0
- package/dist/dashboard/assets/formatters-DP-5E01-.js.gz +0 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js +1 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js.gz +0 -0
- package/dist/dashboard/assets/{index-FQlj0HUT.js → index-D36vCZht.js} +2 -2
- package/dist/dashboard/assets/index-D36vCZht.js.gz +0 -0
- package/dist/dashboard/assets/{inline-C4gU5iOL.js → inline-CHJQwxLa.js} +1 -1
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/{input-BHHX_Tmm.js → input-BlmlizVV.js} +1 -1
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/{layout-CajrYUnD.js → layout-Bz93I-yE.js} +1 -1
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Bx2I7XUe.js → list-row-Ml16KCfu.js} +1 -1
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/{live-DNNqRbj2.js → live-7_QpnYGu.js} +1 -1
- package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-Rr0TIvcj.js → mutation-GU7XdEjz.js} +1 -1
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/{network-C5UBACrJ.js → network-CuMDaTzT.js} +1 -1
- package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js +2 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-Xsi9Qx04.js → pagination-B5aOoweZ.js} +1 -1
- package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai.webp +0 -0
- package/dist/dashboard/assets/providers/zcode.webp +0 -0
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js → query-keys-YSoQOUh6.js} +1 -1
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js.gz → query-keys-YSoQOUh6.js.gz} +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +1 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/{routing-in0f_IfK.js → routing-fnCsxgNO.js} +1 -1
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/{select-BLULNqTp.js → select-C9Ssle9b.js} +2 -2
- package/dist/dashboard/assets/select-C9Ssle9b.js.gz +0 -0
- package/dist/dashboard/assets/{settings-CcGczj6I.js → settings-BxslsErn.js} +1 -1
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/{stack-D2lIR0tg.js → stack-j7cXjgYX.js} +1 -1
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/{state-DTARjfiW.js → state-DHmEnLa2.js} +1 -1
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/{switch-c0oPSnqW.js → switch-DmZcyTIC.js} +1 -1
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-m8WGNPrz.js → useMutation-CbCP4w1o.js} +1 -1
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +57 -57
- package/migrations/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -0
- package/migrations/full-postgres/0043_add_provider_custom_user_agent.sql +14 -0
- package/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -0
- package/migrations/lite-sqlite3/0043_add_provider_custom_user_agent.sql +10 -0
- package/package.json +3 -1
- package/src/boot/dependencies.ts +10 -2
- package/src/config/providers.ts +13 -7
- package/src/config/security.ts +1 -1
- package/src/config/spec.ts +31 -17
- package/src/config/usage.ts +27 -0
- package/src/console/api-keys/routes.ts +19 -23
- package/src/console/cli-tools/cartethyia-websearch-plugin.ts +186 -0
- package/src/console/cli-tools/contracts.ts +39 -295
- package/src/console/cli-tools/fs-ops.ts +29 -0
- package/src/console/cli-tools/injectors/claude.ts +3 -3
- package/src/console/cli-tools/injectors/codex.ts +6 -6
- package/src/console/cli-tools/injectors/driver.ts +8 -105
- package/src/console/cli-tools/injectors/kilo.ts +146 -21
- package/src/console/cli-tools/injectors/opencode.ts +68 -17
- package/src/console/cli-tools/routes.ts +6 -0
- package/src/console/cli-tools/service.ts +7 -6
- package/src/console/observability/contracts.ts +6 -0
- package/src/console/observability/store.ts +3 -0
- package/src/console/providers/catalog/contracts.ts +4 -0
- package/src/console/providers/catalog/routes.ts +1 -0
- package/src/console/providers/detail/routes.ts +8 -0
- package/src/console/providers/detail/store.ts +4 -0
- package/src/console/quota/account-quota-tenant.ts +74 -0
- package/src/console/share/share-stats.ts +7 -9
- package/src/observability/event-log.ts +7 -0
- package/src/observability/event-query.ts +2 -0
- package/src/observability/telemetry-buffer.ts +9 -1
- package/src/persistence/boot.ts +13 -4
- package/src/persistence/schema.ts +15 -1
- package/src/persistence/stores/api-key-store.ts +19 -1
- package/src/protocol/canonical-model.ts +7 -0
- package/src/protocol/dsml.ts +5 -76
- package/src/protocol/request/gemini.ts +20 -1
- package/src/protocol/tool-identity.ts +15 -1
- package/src/providers/adapters/compatible-adapter.ts +29 -1
- package/src/providers/default-registry.ts +20 -4
- package/src/providers/discovery/discovery-types.ts +18 -0
- package/src/providers/discovery/probe-phases.ts +45 -0
- package/src/providers/discovery/probing-service.ts +41 -6
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +108 -16
- package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
- package/src/providers/integrations/antigravity/antigravity.ts +44 -11
- package/src/providers/integrations/codex/codex.ts +28 -1
- package/src/providers/integrations/cursor/cursor.ts +2 -3
- package/src/providers/integrations/github/github-discovery.ts +15 -2
- package/src/providers/integrations/github/github-oauth.ts +178 -9
- package/src/providers/integrations/github/github.ts +95 -14
- package/src/providers/integrations/kiro/kiro.ts +1 -2
- package/src/providers/integrations/qoder/chat-proto.ts +328 -0
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +258 -0
- package/src/providers/integrations/qoder/qoder-adapter.ts +275 -0
- package/src/providers/integrations/qoder/qoder-auth.ts +201 -0
- package/src/providers/integrations/qoder/qoder-body.ts +78 -0
- package/src/providers/integrations/qoder/qoder-catalog.ts +14 -4
- package/src/providers/integrations/qoder/qoder-chat.ts +514 -0
- package/src/providers/integrations/qoder/qoder-cosy.ts +162 -0
- package/src/providers/integrations/qoder/qoder-grpc.ts +667 -0
- package/src/providers/integrations/qoder/qoder-ide.ts +584 -0
- package/src/providers/integrations/qoder/qoder-oauth.ts +4 -4
- package/src/providers/integrations/qoder/qoder-quota.ts +1 -1
- package/src/providers/integrations/qoder/qoder-realm.ts +40 -4
- package/src/providers/integrations/qoder/qoder-types.ts +51 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +123 -8
- package/src/providers/integrations/qoder/qoder.ts +147 -1830
- package/src/providers/integrations/trae/trae.ts +2 -2
- package/src/providers/operations/account-error-classification.ts +67 -17
- package/src/providers/operations/byok-wire-profile.ts +19 -15
- package/src/providers/provider-contracts.ts +7 -0
- package/src/providers/provider-usage.ts +24 -55
- package/src/security/abuse.ts +5 -5
- package/src/security/admission/service.ts +11 -4
- package/src/security/api-key-auth.ts +5 -3
- package/src/transport/dispatch/attempt-finalize.ts +69 -21
- package/src/transport/dispatch/attempt-loop.ts +22 -0
- package/src/transport/dispatch/upstream.ts +4 -2
- package/src/transport/failure-policy.ts +15 -1
- package/src/transport/guards/error-lifecycle.ts +4 -0
- package/src/transport/request/state.ts +6 -0
- package/src/transport/routing/route-catalog.ts +8 -0
- package/src/transport/routing/route-model.ts +4 -0
- package/src/transport/routing/router.ts +8 -110
- package/src/transport/surface/reasoning-summary.ts +9 -14
- package/src/transport/vision-handoff.ts +83 -28
- package/dist/dashboard/assets/BannedPage-Cj15GsMp.js +0 -1
- package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +0 -1
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js +0 -1
- package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +0 -1
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js +0 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +0 -5
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +0 -1
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js +0 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js +0 -1
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js +0 -1
- package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
- package/dist/dashboard/assets/app--PJWq8_C.css +0 -2
- package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
- package/dist/dashboard/assets/app-Bgd3zANQ.js +0 -9
- package/dist/dashboard/assets/app-Bgd3zANQ.js.gz +0 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
- package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BEK7KP0H.js +0 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js +0 -1
- package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
- package/dist/dashboard/assets/entry-EBHJ3DrE.js +0 -1
- package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js +0 -4
- package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
- package/dist/dashboard/assets/formatters-BAACA727.js +0 -1
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js +0 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
- package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js +0 -2
- package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai-coding-plan.svg +0 -6
- package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
- package/dist/dashboard/assets/quota-DvQbD_sr.js +0 -1
- package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
- package/src/console/cli-tools/injectors/cline.ts +0 -110
- package/src/console/cli-tools/injectors/copilot.ts +0 -108
- package/src/console/cli-tools/injectors/cowork.ts +0 -64
- package/src/console/cli-tools/injectors/deepseek-tui.ts +0 -85
- package/src/console/cli-tools/injectors/droid.ts +0 -96
- package/src/console/cli-tools/injectors/grok-build.ts +0 -70
- package/src/console/cli-tools/injectors/hermes.ts +0 -101
- package/src/console/cli-tools/injectors/jcode.ts +0 -115
- package/src/console/cli-tools/injectors/openclaw.ts +0 -161
- package/src/providers/integrations/qoder/qoder-text-tools.ts +0 -277
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {} from "../contracts";
|
|
2
|
-
import { ensureV1Suffix, homeDir, readJsonFile, readTextFile, removeFile, textGet, textHas, textRemove, textUpsert,
|
|
2
|
+
import { ensureV1Suffix, homeDir, readJsonFile, readTextFile, removeFile, textGet, textHas, textRemove, textUpsert, writeJsonFileWithBackup, writeTextFileWithBackup } from "../fs-ops";
|
|
3
3
|
import type { InjectorSpec } from "../contracts";
|
|
4
4
|
|
|
5
5
|
|
|
@@ -93,12 +93,12 @@ export const codexSpec: InjectorSpec = {
|
|
|
93
93
|
` refresh_interval_ms = 0`,
|
|
94
94
|
].join("\n"),
|
|
95
95
|
);
|
|
96
|
-
await
|
|
96
|
+
await writeTextFileWithBackup(path, text);
|
|
97
97
|
|
|
98
98
|
const auth = ((await readJsonFile(codexAuthPath())) as Record<string, string> | null) ?? {};
|
|
99
99
|
auth[CODEX_PROVIDER] = input.apiKey;
|
|
100
|
-
await
|
|
101
|
-
await
|
|
100
|
+
await writeJsonFileWithBackup(codexAuthPath(), auth);
|
|
101
|
+
await writeTextFileWithBackup(codexAuthHelperPath(), CODEX_AUTH_HELPER_SOURCE);
|
|
102
102
|
},
|
|
103
103
|
|
|
104
104
|
async reset(path) {
|
|
@@ -118,12 +118,12 @@ export const codexSpec: InjectorSpec = {
|
|
|
118
118
|
if (textGet(text, { kind: "flat", key: "model_provider" }) === CODEX_PROVIDER) {
|
|
119
119
|
text = textUpsert(text, { kind: "flat", key: "model_provider", insertAtTop: true }, "openai");
|
|
120
120
|
}
|
|
121
|
-
await
|
|
121
|
+
await writeTextFileWithBackup(path, text);
|
|
122
122
|
|
|
123
123
|
const auth = (await readJsonFile(codexAuthPath())) as Record<string, string> | null;
|
|
124
124
|
if (auth?.[CODEX_PROVIDER]) {
|
|
125
125
|
delete auth[CODEX_PROVIDER];
|
|
126
|
-
await
|
|
126
|
+
await writeJsonFileWithBackup(codexAuthPath(), auth);
|
|
127
127
|
}
|
|
128
128
|
await removeFile(codexAuthHelperPath());
|
|
129
129
|
},
|
|
@@ -6,25 +6,15 @@ import type {
|
|
|
6
6
|
ApplyResult,
|
|
7
7
|
DownloadResult,
|
|
8
8
|
InjectorSpec,
|
|
9
|
-
ToolDef,
|
|
10
9
|
ToolId,
|
|
11
10
|
ToolInjector,
|
|
12
11
|
ToolStatus,
|
|
13
12
|
} from "../contracts";
|
|
14
|
-
import { TOOL_IDS
|
|
15
|
-
import { checkBinaryInstalled, ensureDir,
|
|
13
|
+
import { TOOL_IDS } from "../contracts";
|
|
14
|
+
import { checkBinaryInstalled, ensureDir, fileExists, keyPrefix } from "../fs-ops";
|
|
16
15
|
import { claudeSpec } from './claude';
|
|
17
|
-
import { clineSpec } from './cline';
|
|
18
16
|
import { codexSpec } from './codex';
|
|
19
|
-
import { copilotSpec } from './copilot';
|
|
20
|
-
import { coworkSpec } from './cowork';
|
|
21
|
-
import { deepseekTuiSpec } from './deepseek-tui';
|
|
22
|
-
import { droidSpec } from './droid';
|
|
23
|
-
import { grokBuildSpec } from './grok-build';
|
|
24
|
-
import { hermesSpec } from './hermes';
|
|
25
|
-
import { jcodeSpec } from './jcode';
|
|
26
17
|
import { kiloSpec } from './kilo';
|
|
27
|
-
import { openclawSpec } from './openclaw';
|
|
28
18
|
import { opencodeSpec } from './opencode';
|
|
29
19
|
|
|
30
20
|
// ── injectors/driver.ts ──
|
|
@@ -92,11 +82,12 @@ export function createFileInjector(spec: InjectorSpec): ToolInjector {
|
|
|
92
82
|
const path = spec.resolvePath();
|
|
93
83
|
const dir = spec.resolveDir ? spec.resolveDir() : dirname(path);
|
|
94
84
|
await ensureDir(dir);
|
|
95
|
-
await spec.apply(input, path);
|
|
85
|
+
const warnings = await spec.apply(input, path);
|
|
96
86
|
return {
|
|
97
87
|
success: true,
|
|
98
88
|
settingsPath: path,
|
|
99
89
|
message: spec.messages?.applied ?? `${spec.displayName ?? spec.toolId} settings applied`,
|
|
90
|
+
...(Array.isArray(warnings) && warnings.length > 0 ? { warnings } : {}),
|
|
100
91
|
};
|
|
101
92
|
},
|
|
102
93
|
|
|
@@ -131,114 +122,26 @@ export function createFileInjector(spec: InjectorSpec): ToolInjector {
|
|
|
131
122
|
};
|
|
132
123
|
}
|
|
133
124
|
|
|
134
|
-
/** Create a guide injector for a specific tool definition (any `configType: "guide"` entry). */
|
|
135
|
-
function guideInjectorFor(def: ToolDef): ToolInjector {
|
|
136
|
-
return {
|
|
137
|
-
toolId: def.id,
|
|
138
|
-
|
|
139
|
-
async getStatus(): Promise<ToolStatus> {
|
|
140
|
-
// Guide tools are always "not installed" from an injection standpoint —
|
|
141
|
-
// we can't detect the binary reliably, and config is manual.
|
|
142
|
-
return {
|
|
143
|
-
toolId: def.id,
|
|
144
|
-
installed: false,
|
|
145
|
-
configured: false,
|
|
146
|
-
settingsPath: null,
|
|
147
|
-
currentEndpoint: null,
|
|
148
|
-
currentApiKeyPrefix: null,
|
|
149
|
-
currentModels: null,
|
|
150
|
-
message: "Guide-only tool — use Download Config to get setup instructions",
|
|
151
|
-
};
|
|
152
|
-
},
|
|
153
|
-
|
|
154
|
-
async apply(): Promise<ApplyResult> {
|
|
155
|
-
return { success: false, message: `${def.name} is a guide-only tool — use Download Config` };
|
|
156
|
-
},
|
|
157
|
-
|
|
158
|
-
async reset(): Promise<ApplyResult> {
|
|
159
|
-
return { success: true, message: `${def.name} has no injected config to reset` };
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
async download(input: ApplyInput): Promise<DownloadResult> {
|
|
163
|
-
const baseUrl = ensureV1Suffix(input.endpoint);
|
|
164
|
-
const model = input.activeModel ?? input.modelIds[0] ?? "";
|
|
165
|
-
const apiKey = input.apiKey;
|
|
166
|
-
const codeBlock = def.codeBlock;
|
|
167
|
-
|
|
168
|
-
if (codeBlock) {
|
|
169
|
-
const content = codeBlock.code
|
|
170
|
-
.replace(/\{\{baseUrl\}\}/g, baseUrl)
|
|
171
|
-
.replace(/\{\{apiKey\}\}/g, apiKey)
|
|
172
|
-
.replace(/\{\{model\}\}/g, model);
|
|
173
|
-
const ext =
|
|
174
|
-
codeBlock.language === "json" ? "json" : codeBlock.language === "bash" ? "sh" : "txt";
|
|
175
|
-
return {
|
|
176
|
-
content,
|
|
177
|
-
filename: `${def.id}-config.${ext}`,
|
|
178
|
-
mimeType: codeBlock.language === "json" ? "application/json" : "text/plain",
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// No code block — generate a simple guide summary.
|
|
183
|
-
const steps = def.guideSteps ?? [];
|
|
184
|
-
const lines = [`# ${def.name} — Setup Guide`, ""];
|
|
185
|
-
for (const step of steps) {
|
|
186
|
-
lines.push(`## Step ${step.step}: ${step.title}`);
|
|
187
|
-
if (step.desc) lines.push(step.desc);
|
|
188
|
-
if (step.value) {
|
|
189
|
-
lines.push("```");
|
|
190
|
-
lines.push(
|
|
191
|
-
step.value
|
|
192
|
-
.replace(/\{\{baseUrl\}\}/g, baseUrl)
|
|
193
|
-
.replace(/\{\{apiKey\}\}/g, apiKey)
|
|
194
|
-
.replace(/\{\{model\}\}/g, model),
|
|
195
|
-
);
|
|
196
|
-
lines.push("```");
|
|
197
|
-
}
|
|
198
|
-
lines.push("");
|
|
199
|
-
}
|
|
200
|
-
lines.push(`Endpoint: ${baseUrl}`);
|
|
201
|
-
lines.push(`API Key: ${apiKey}`);
|
|
202
|
-
lines.push(`Model: ${model}`);
|
|
203
|
-
return { content: lines.join("\n"), filename: `${def.id}-guide.txt`, mimeType: "text/plain" };
|
|
204
|
-
},
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
125
|
// ── injectors/index.ts ──
|
|
209
126
|
/**
|
|
210
127
|
* Single dispatch point for CliToolService: given a toolId, look up the
|
|
211
128
|
* injector and call getStatus/apply/reset/download.
|
|
212
129
|
*
|
|
213
130
|
* File-based injectors are driven by a generic driver (createFileInjector)
|
|
214
|
-
* configured via declarative specs.
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
* built exhaustively from that registry so a non-guide tool without an
|
|
218
|
-
* injector fails loudly at import, never silently at lookup time.
|
|
131
|
+
* configured via declarative specs. The map is built exhaustively from that
|
|
132
|
+
* registry so a tool without an injector fails loudly at import, never
|
|
133
|
+
* silently at lookup time.
|
|
219
134
|
*/
|
|
220
135
|
const FILE_INJECTORS: Partial<Record<ToolId, ToolInjector>> = {
|
|
221
136
|
claude: createFileInjector(claudeSpec),
|
|
222
137
|
codex: createFileInjector(codexSpec),
|
|
223
|
-
cline: createFileInjector(clineSpec),
|
|
224
138
|
opencode: createFileInjector(opencodeSpec),
|
|
225
|
-
droid: createFileInjector(droidSpec),
|
|
226
|
-
hermes: createFileInjector(hermesSpec),
|
|
227
|
-
"grok-build": createFileInjector(grokBuildSpec),
|
|
228
|
-
copilot: createFileInjector(copilotSpec),
|
|
229
|
-
"deepseek-tui": createFileInjector(deepseekTuiSpec),
|
|
230
|
-
jcode: createFileInjector(jcodeSpec),
|
|
231
139
|
kilo: createFileInjector(kiloSpec),
|
|
232
|
-
openclaw: createFileInjector(openclawSpec),
|
|
233
|
-
cowork: createFileInjector(coworkSpec),
|
|
234
140
|
};
|
|
235
141
|
|
|
236
142
|
export const INJECTORS: Record<ToolId, ToolInjector> = Object.fromEntries(
|
|
237
143
|
TOOL_IDS.map((id) => {
|
|
238
|
-
const injector =
|
|
239
|
-
TOOL_REGISTRY[id].configType === "guide"
|
|
240
|
-
? guideInjectorFor(TOOL_REGISTRY[id])
|
|
241
|
-
: FILE_INJECTORS[id];
|
|
144
|
+
const injector = FILE_INJECTORS[id];
|
|
242
145
|
if (injector === undefined) {
|
|
243
146
|
throw new Error(`No injector registered for tool: ${id}`);
|
|
244
147
|
}
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
import { platform } from "node:os";
|
|
2
2
|
import type {} from "../contracts";
|
|
3
|
-
import {
|
|
4
|
-
import { homeDir, isLocalEndpoint, join, readJsonFile,
|
|
3
|
+
import { jsonDownload } from "../contracts";
|
|
4
|
+
import { homeDir, isLocalEndpoint, join, readJsonFile, writeJsonFileWithBackup } from "../fs-ops";
|
|
5
5
|
import type { InjectorSpec } from "../contracts";
|
|
6
6
|
|
|
7
7
|
const IS_WIN = platform() === "win32";
|
|
8
8
|
const IS_MAC = platform() === "darwin";
|
|
9
9
|
|
|
10
10
|
// Kilo Code injector spec.
|
|
11
|
+
//
|
|
12
|
+
// Kilo Code is a fork of OpenCode, but it now reads its own config file —
|
|
13
|
+
// `~/.config/kilo/kilo.jsonc` (Windows: `%USERPROFILE%\.config\kilo\kilo.jsonc`)
|
|
14
|
+
// — with the same provider shape as OpenCode: `provider.<id>.npm/options/models`
|
|
15
|
+
// plus a top-level `model`. Unlike OpenCode, Kilo runs on the AI SDK, so the
|
|
16
|
+
// `npm` value must be an `@ai-sdk/*` package (default `@ai-sdk/openai-compatible`).
|
|
17
|
+
//
|
|
18
|
+
// The older VS Code extension also keeps a credential store at
|
|
19
|
+
// `~/.local/share/kilo/auth.json`; we still write the endpoint there for
|
|
20
|
+
// backward compatibility, but the canonical config is now `kilo.jsonc`.
|
|
21
|
+
|
|
22
|
+
const KILO_PROVIDER_ID = "cartethyia";
|
|
23
|
+
|
|
24
|
+
function resolveKiloConfigDirectory(): string {
|
|
25
|
+
if (IS_WIN) return join(process.env.USERPROFILE ?? homeDir(), ".config", "kilo");
|
|
26
|
+
if (IS_MAC) return join(homeDir(), ".config", "kilo");
|
|
27
|
+
return join(homeDir(), ".config", "kilo");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function kiloConfigPath(): string {
|
|
31
|
+
return join(resolveKiloConfigDirectory(), "kilo.jsonc");
|
|
32
|
+
}
|
|
33
|
+
|
|
11
34
|
function resolveKiloDataDirectory(): string {
|
|
12
35
|
if (IS_WIN) return join(process.env.LOCALAPPDATA ?? homeDir(), "kilo");
|
|
13
36
|
if (IS_MAC) return join(homeDir(), "Library", "Application Support", "kilo");
|
|
@@ -21,15 +44,52 @@ function kiloVscodeSettingsPath(): string {
|
|
|
21
44
|
return join(homeDir(), ".config", "Code", "User", "settings.json");
|
|
22
45
|
}
|
|
23
46
|
|
|
47
|
+
function kiloModelDef(model: string): unknown {
|
|
48
|
+
return {
|
|
49
|
+
name: model,
|
|
50
|
+
limit: { context: 128000, output: 64000 },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function buildKiloModels(models: readonly string[]): Record<string, unknown> {
|
|
55
|
+
const map: Record<string, unknown> = {};
|
|
56
|
+
for (const m of models) {
|
|
57
|
+
if (!m) continue;
|
|
58
|
+
map[m] = kiloModelDef(m);
|
|
59
|
+
}
|
|
60
|
+
return map;
|
|
61
|
+
}
|
|
62
|
+
|
|
24
63
|
export const kiloSpec: InjectorSpec = {
|
|
25
64
|
toolId: "kilo",
|
|
26
65
|
displayName: "Kilo Code",
|
|
27
66
|
binary: "kilo",
|
|
28
|
-
resolveDir:
|
|
29
|
-
resolvePath:
|
|
67
|
+
resolveDir: resolveKiloConfigDirectory,
|
|
68
|
+
resolvePath: kiloConfigPath,
|
|
30
69
|
|
|
31
70
|
async readStatus(path) {
|
|
32
|
-
const
|
|
71
|
+
const config = (await readJsonFile(path)) as {
|
|
72
|
+
provider?: Record<string, { npm?: string; options?: { baseURL?: string; apiKey?: string }; models?: Record<string, unknown> }>;
|
|
73
|
+
model?: string;
|
|
74
|
+
} | null;
|
|
75
|
+
const provider = config?.provider?.[KILO_PROVIDER_ID];
|
|
76
|
+
const endpoint = provider?.options?.baseURL ?? null;
|
|
77
|
+
const models = provider?.models ? Object.keys(provider.models) : null;
|
|
78
|
+
const active =
|
|
79
|
+
typeof config?.model === "string" && config.model.startsWith(`${KILO_PROVIDER_ID}/`)
|
|
80
|
+
? config.model.split("/").slice(1).join("/")
|
|
81
|
+
: null;
|
|
82
|
+
if (endpoint) {
|
|
83
|
+
return {
|
|
84
|
+
configured: isLocalEndpoint(endpoint),
|
|
85
|
+
currentEndpoint: endpoint,
|
|
86
|
+
rawApiKey: provider?.options?.apiKey ?? null,
|
|
87
|
+
currentModels: active && models ? [active, ...models.filter((m) => m !== active)] : models,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Fallback to the legacy auth.json store (older VS Code extension).
|
|
92
|
+
const auth = (await readJsonFile(join(resolveKiloDataDirectory(), "auth.json"))) as Record<
|
|
33
93
|
string,
|
|
34
94
|
{ baseUrl?: string; baseURL?: string; apiKey?: string; model?: string }
|
|
35
95
|
> | null;
|
|
@@ -47,22 +107,77 @@ export const kiloSpec: InjectorSpec = {
|
|
|
47
107
|
},
|
|
48
108
|
|
|
49
109
|
async apply(input, path) {
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
110
|
+
// Canonical config: ~/.config/kilo/kilo.jsonc
|
|
111
|
+
const existing = (await readJsonFile(path)) as Record<string, unknown> | null;
|
|
112
|
+
const config: Record<string, unknown> = (existing ?? {}) as Record<string, unknown>;
|
|
113
|
+
if (!config.provider || typeof config.provider !== "object") config.provider = {};
|
|
114
|
+
const providers = config.provider as Record<string, unknown>;
|
|
115
|
+
const prior = (providers[KILO_PROVIDER_ID] as Record<string, unknown> | undefined) ?? {};
|
|
116
|
+
const priorModels = (prior.models as Record<string, unknown> | undefined) ?? {};
|
|
117
|
+
const otherProviders = Object.keys(providers).filter((id) => id !== KILO_PROVIDER_ID);
|
|
118
|
+
providers[KILO_PROVIDER_ID] = {
|
|
119
|
+
npm: input.sdk ?? (prior as { npm?: string }).npm ?? "@ai-sdk/openai-compatible",
|
|
120
|
+
options: {
|
|
121
|
+
...((prior.options as Record<string, unknown> | undefined) ?? {}),
|
|
122
|
+
baseURL: input.endpoint,
|
|
123
|
+
apiKey: input.apiKey,
|
|
124
|
+
},
|
|
125
|
+
models: { ...priorModels, ...buildKiloModels(input.modelIds) },
|
|
126
|
+
};
|
|
127
|
+
const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
|
|
128
|
+
config.model = activeModel === "" ? "" : `${KILO_PROVIDER_ID}/${activeModel}`;
|
|
129
|
+
|
|
130
|
+
// YOLO mode: auto-approve shell/read/write.
|
|
131
|
+
if (input.bypassPermissions === true) {
|
|
132
|
+
config.permissions = [
|
|
133
|
+
{ action: "shell", resource: "*", effect: "allow" },
|
|
134
|
+
{ action: "external_directory", resource: "*", effect: "allow" },
|
|
135
|
+
{ action: "question", resource: "*", effect: "deny" },
|
|
136
|
+
];
|
|
137
|
+
} else if (input.bypassPermissions === false) {
|
|
138
|
+
delete config.permissions;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await writeJsonFileWithBackup(path, config);
|
|
142
|
+
|
|
143
|
+
// Legacy credential store for the older VS Code extension.
|
|
144
|
+
const authPath = join(resolveKiloDataDirectory(), "auth.json");
|
|
145
|
+
const auth = ((await readJsonFile(authPath)) as Record<string, unknown> | null) ?? {};
|
|
146
|
+
auth["openai-compatible"] = { baseUrl: input.endpoint, apiKey: input.apiKey, model: activeModel };
|
|
147
|
+
await writeJsonFileWithBackup(authPath, auth);
|
|
54
148
|
|
|
55
149
|
const settings =
|
|
56
150
|
((await readJsonFile(kiloVscodeSettingsPath())) as Record<string, unknown> | null) ?? {};
|
|
57
151
|
settings["kilo.code.authProviderOverride"] = "openai-compatible";
|
|
58
|
-
await
|
|
152
|
+
await writeJsonFileWithBackup(kiloVscodeSettingsPath(), settings);
|
|
153
|
+
|
|
154
|
+
return otherProviders.length > 0
|
|
155
|
+
? [
|
|
156
|
+
`Config already has other provider(s): ${otherProviders.join(", ")}. They were kept as-is — only ${KILO_PROVIDER_ID} was written/updated.`,
|
|
157
|
+
]
|
|
158
|
+
: undefined;
|
|
59
159
|
},
|
|
60
160
|
|
|
61
161
|
async reset(path) {
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
162
|
+
const config = (await readJsonFile(path)) as Record<string, unknown> | null;
|
|
163
|
+
if (config && config.provider && typeof config.provider === "object") {
|
|
164
|
+
const providers = config.provider as Record<string, unknown>;
|
|
165
|
+
delete providers[KILO_PROVIDER_ID];
|
|
166
|
+
if (Object.keys(providers).length === 0) delete config.provider;
|
|
167
|
+
}
|
|
168
|
+
if (typeof config?.model === "string" && config.model.startsWith(`${KILO_PROVIDER_ID}/`)) {
|
|
169
|
+
delete config.model;
|
|
170
|
+
}
|
|
171
|
+
if (config) await writeJsonFileWithBackup(path, config);
|
|
172
|
+
|
|
173
|
+
const auth = (await readJsonFile(join(resolveKiloDataDirectory(), "auth.json"))) as Record<
|
|
174
|
+
string,
|
|
175
|
+
unknown
|
|
176
|
+
> | null;
|
|
177
|
+
if (auth) {
|
|
178
|
+
delete auth["openai-compatible"];
|
|
179
|
+
await writeJsonFileWithBackup(join(resolveKiloDataDirectory(), "auth.json"), auth);
|
|
180
|
+
}
|
|
66
181
|
|
|
67
182
|
const settings = (await readJsonFile(kiloVscodeSettingsPath())) as Record<
|
|
68
183
|
string,
|
|
@@ -70,21 +185,31 @@ export const kiloSpec: InjectorSpec = {
|
|
|
70
185
|
> | null;
|
|
71
186
|
if (settings && "kilo.code.authProviderOverride" in settings) {
|
|
72
187
|
delete settings["kilo.code.authProviderOverride"];
|
|
73
|
-
await
|
|
188
|
+
await writeJsonFileWithBackup(kiloVscodeSettingsPath(), settings);
|
|
74
189
|
}
|
|
75
190
|
},
|
|
76
191
|
|
|
77
192
|
download(input) {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
193
|
+
const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
|
|
194
|
+
const config: Record<string, unknown> = {
|
|
195
|
+
provider: {
|
|
196
|
+
[KILO_PROVIDER_ID]: {
|
|
197
|
+
npm: input.sdk ?? "@ai-sdk/openai-compatible",
|
|
198
|
+
options: {
|
|
199
|
+
baseURL: input.endpoint,
|
|
200
|
+
apiKey: input.apiKey,
|
|
201
|
+
},
|
|
202
|
+
models: buildKiloModels(input.modelIds),
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
model: activeModel === "" ? "" : `${KILO_PROVIDER_ID}/${activeModel}`,
|
|
206
|
+
};
|
|
207
|
+
return jsonDownload(config, { filename: "kilo.jsonc" });
|
|
82
208
|
},
|
|
83
209
|
|
|
84
210
|
messages: {
|
|
85
211
|
applied: "Kilo Code settings applied",
|
|
86
212
|
reset: "Cartethyia settings removed from Kilo Code",
|
|
87
|
-
resetMissing: "No
|
|
213
|
+
resetMissing: "No config file to reset",
|
|
88
214
|
},
|
|
89
215
|
};
|
|
90
|
-
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {} from "../contracts";
|
|
2
|
-
import { ensureV1Suffix, homeDir, join, readJsonFile,
|
|
2
|
+
import { ensureV1Suffix, homeDir, join, readJsonFile, writeJsonFileWithBackup } from "../fs-ops";
|
|
3
3
|
import type { InjectorSpec } from "../contracts";
|
|
4
|
+
import { DEFAULT_SDK } from "../contracts";
|
|
5
|
+
import { writeWebsearchPlugin, removeWebsearchPlugin } from "../cartethyia-websearch-plugin";
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
// OpenCode injector spec.
|
|
@@ -18,6 +20,7 @@ interface OpencodeProvider {
|
|
|
18
20
|
interface OpencodeConfig {
|
|
19
21
|
provider?: Record<string, OpencodeProvider>;
|
|
20
22
|
model?: string;
|
|
23
|
+
websearch?: { provider?: string };
|
|
21
24
|
agent?: {
|
|
22
25
|
explorer?: {
|
|
23
26
|
description?: string;
|
|
@@ -50,11 +53,14 @@ export const opencodeSpec: InjectorSpec = {
|
|
|
50
53
|
if (!config) {
|
|
51
54
|
return { configured: false, currentEndpoint: null, rawApiKey: null, currentModels: null };
|
|
52
55
|
}
|
|
53
|
-
|
|
56
|
+
// The provider key written by this injector is the websearch provider name
|
|
57
|
+
// when one is configured, otherwise the default `cartethyia`.
|
|
58
|
+
const providerId = config.websearch?.provider ?? "cartethyia";
|
|
59
|
+
const provider = config.provider?.[providerId];
|
|
54
60
|
const endpoint = provider?.options?.baseURL ?? null;
|
|
55
61
|
const models = provider?.models ? Object.keys(provider.models) : null;
|
|
56
62
|
const active =
|
|
57
|
-
typeof config.model === "string" && config.model.startsWith(
|
|
63
|
+
typeof config.model === "string" && config.model.startsWith(`${providerId}/`)
|
|
58
64
|
? config.model.split("/").slice(1).join("/")
|
|
59
65
|
: null;
|
|
60
66
|
return {
|
|
@@ -69,10 +75,16 @@ export const opencodeSpec: InjectorSpec = {
|
|
|
69
75
|
const existing = (await readJsonFile(path)) as OpencodeConfig | null;
|
|
70
76
|
const config: OpencodeConfig = (existing ?? {}) as OpencodeConfig;
|
|
71
77
|
|
|
78
|
+
// The provider key written into opencode.jsonc follows the websearch
|
|
79
|
+
// provider name when one is chosen, which keeps the websearch plugin and
|
|
80
|
+
// the provider block pointing at the same entry.
|
|
81
|
+
const providerId = input.websearch ?? "cartethyia";
|
|
82
|
+
|
|
72
83
|
if (!config.provider) config.provider = {};
|
|
73
|
-
const prior = config.provider
|
|
74
|
-
config.provider.
|
|
75
|
-
|
|
84
|
+
const prior = config.provider[providerId];
|
|
85
|
+
const otherProviders = Object.keys(config.provider).filter((id) => id !== providerId);
|
|
86
|
+
config.provider[providerId] = {
|
|
87
|
+
npm: input.sdk ?? prior?.npm ?? DEFAULT_SDK,
|
|
76
88
|
options: {
|
|
77
89
|
...(prior?.options ?? {}),
|
|
78
90
|
baseURL: ensureV1Suffix(input.endpoint),
|
|
@@ -82,47 +94,85 @@ export const opencodeSpec: InjectorSpec = {
|
|
|
82
94
|
};
|
|
83
95
|
|
|
84
96
|
const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
|
|
85
|
-
config.model = activeModel === "" ? "" :
|
|
97
|
+
config.model = activeModel === "" ? "" : `${providerId}/${activeModel}`;
|
|
98
|
+
|
|
99
|
+
if (input.websearch !== undefined) {
|
|
100
|
+
config.websearch = { provider: input.websearch };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// YOLO mode: auto-approve shell/read/write. When on, write OpenCode's
|
|
104
|
+
// permission rules; when off, leave whatever the user had (or nothing).
|
|
105
|
+
if (input.bypassPermissions === true) {
|
|
106
|
+
config.permissions = [
|
|
107
|
+
{ action: "shell", resource: "*", effect: "allow" },
|
|
108
|
+
{ action: "external_directory", resource: "*", effect: "allow" },
|
|
109
|
+
{ action: "question", resource: "*", effect: "deny" },
|
|
110
|
+
];
|
|
111
|
+
} else if (input.bypassPermissions === false) {
|
|
112
|
+
delete config.permissions;
|
|
113
|
+
}
|
|
86
114
|
|
|
87
115
|
if (!config.agent) config.agent = {};
|
|
88
116
|
const subagentModel = input.subagentModel ?? input.modelIds[0] ?? activeModel;
|
|
89
117
|
config.agent.explorer = {
|
|
90
118
|
description: "Fast explorer subagent",
|
|
91
119
|
mode: "subagent",
|
|
92
|
-
model:
|
|
120
|
+
model: `${providerId}/${subagentModel}`,
|
|
93
121
|
};
|
|
94
122
|
|
|
95
|
-
await
|
|
123
|
+
await writeJsonFileWithBackup(path, config);
|
|
124
|
+
|
|
125
|
+
// Write (or refresh) the websearch provider plugin when web search is
|
|
126
|
+
// routed through the gateway. The plugin id follows the provider name.
|
|
127
|
+
if (input.websearch !== undefined) {
|
|
128
|
+
await writeWebsearchPlugin(opencodeSpec.resolveDir?.() ?? join(homeDir(), ".config", "opencode"), providerId);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return otherProviders.length > 0
|
|
132
|
+
? [
|
|
133
|
+
`Config already has other provider(s): ${otherProviders.join(", ")}. They were kept as-is — only ${providerId} was written/updated.`,
|
|
134
|
+
]
|
|
135
|
+
: undefined;
|
|
96
136
|
},
|
|
97
137
|
|
|
98
138
|
async reset(path) {
|
|
99
139
|
const config = (await readJsonFile(path)) as OpencodeConfig | null;
|
|
100
140
|
if (!config) return false;
|
|
101
141
|
|
|
142
|
+
const providerId = config.websearch?.provider ?? "cartethyia";
|
|
143
|
+
|
|
102
144
|
if (config.provider) {
|
|
103
|
-
delete config.provider
|
|
145
|
+
delete config.provider[providerId];
|
|
104
146
|
if (Object.keys(config.provider).length === 0) delete config.provider;
|
|
105
147
|
}
|
|
106
148
|
|
|
107
|
-
if (typeof config.model === "string" && config.model.startsWith(
|
|
149
|
+
if (typeof config.model === "string" && config.model.startsWith(`${providerId}/`)) {
|
|
108
150
|
delete config.model;
|
|
109
151
|
}
|
|
110
152
|
|
|
111
|
-
if (config.agent?.explorer?.model?.startsWith(
|
|
153
|
+
if (config.agent?.explorer?.model?.startsWith(`${providerId}/`)) {
|
|
112
154
|
delete config.agent.explorer;
|
|
113
155
|
if (Object.keys(config.agent).length === 0) delete config.agent;
|
|
114
156
|
}
|
|
115
157
|
|
|
116
|
-
|
|
158
|
+
if (config.websearch) {
|
|
159
|
+
delete config.websearch;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
await writeJsonFileWithBackup(path, config);
|
|
163
|
+
|
|
164
|
+
// Remove the generated websearch plugin when present.
|
|
165
|
+
await removeWebsearchPlugin(opencodeSpec.resolveDir?.() ?? join(homeDir(), ".config", "opencode"), providerId);
|
|
117
166
|
},
|
|
118
167
|
|
|
119
168
|
download(input) {
|
|
120
169
|
const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
|
|
121
170
|
const subagentModel = input.subagentModel ?? input.modelIds[0] ?? activeModel;
|
|
171
|
+
const providerId = input.websearch ?? "cartethyia";
|
|
122
172
|
const config: OpencodeConfig = {
|
|
123
173
|
provider: {
|
|
124
|
-
|
|
125
|
-
npm:
|
|
174
|
+
[providerId]: {
|
|
175
|
+
npm: input.sdk ?? DEFAULT_SDK,
|
|
126
176
|
options: {
|
|
127
177
|
baseURL: ensureV1Suffix(input.endpoint),
|
|
128
178
|
apiKey: input.apiKey,
|
|
@@ -130,12 +180,13 @@ export const opencodeSpec: InjectorSpec = {
|
|
|
130
180
|
models: buildOpencodeModels(input.modelIds),
|
|
131
181
|
},
|
|
132
182
|
},
|
|
133
|
-
model: activeModel === "" ? "" :
|
|
183
|
+
model: activeModel === "" ? "" : `${providerId}/${activeModel}`,
|
|
184
|
+
...(input.websearch !== undefined ? { websearch: { provider: input.websearch } } : {}),
|
|
134
185
|
agent: {
|
|
135
186
|
explorer: {
|
|
136
187
|
description: "Fast explorer subagent",
|
|
137
188
|
mode: "subagent",
|
|
138
|
-
model:
|
|
189
|
+
model: `${providerId}/${subagentModel}`,
|
|
139
190
|
},
|
|
140
191
|
},
|
|
141
192
|
};
|
|
@@ -102,6 +102,10 @@ function parseApplyInput(
|
|
|
102
102
|
...(value.mode === "file" || value.mode === "remote" || value.mode === "both"
|
|
103
103
|
? { mode: value.mode }
|
|
104
104
|
: {}),
|
|
105
|
+
...(typeof value.sdk === "string" && value.sdk.length > 0 ? { sdk: value.sdk } : {}),
|
|
106
|
+
...(typeof value.websearch === "string" && value.websearch.length > 0
|
|
107
|
+
? { websearch: value.websearch }
|
|
108
|
+
: {}),
|
|
105
109
|
};
|
|
106
110
|
}
|
|
107
111
|
|
|
@@ -128,6 +132,8 @@ const applyBody = t.Object({
|
|
|
128
132
|
}),
|
|
129
133
|
),
|
|
130
134
|
bypassPermissions: t.Optional(t.Boolean()),
|
|
135
|
+
sdk: t.Optional(t.String()),
|
|
136
|
+
websearch: t.Optional(t.String()),
|
|
131
137
|
});
|
|
132
138
|
|
|
133
139
|
const mappingBody = t.Object({
|
|
@@ -44,8 +44,6 @@ function toToolRegistryEntry(def: ToolDef): ToolRegistryEntry {
|
|
|
44
44
|
...(def.settingsFile === undefined ? {} : { settingsFile: def.settingsFile }),
|
|
45
45
|
...(def.docsUrl === undefined ? {} : { docsUrl: def.docsUrl }),
|
|
46
46
|
...(def.notes === undefined ? {} : { notes: def.notes }),
|
|
47
|
-
...(def.guideSteps === undefined ? {} : { guideSteps: def.guideSteps }),
|
|
48
|
-
...(def.codeBlock === undefined ? {} : { codeBlock: def.codeBlock }),
|
|
49
47
|
};
|
|
50
48
|
}
|
|
51
49
|
|
|
@@ -64,8 +62,8 @@ function applyMessage(outcome: ApplyOutcome, toolId: string, fileMessage: string
|
|
|
64
62
|
case "remote":
|
|
65
63
|
return `Saved the remote route for ${toolId}. No config file was written.`;
|
|
66
64
|
case "none":
|
|
67
|
-
//
|
|
68
|
-
//
|
|
65
|
+
// Nothing was written and no remote route was saved; surface the
|
|
66
|
+
// injector's own message verbatim.
|
|
69
67
|
return fileMessage.length > 0 ? fileMessage : `Nothing to apply for ${toolId}.`;
|
|
70
68
|
}
|
|
71
69
|
}
|
|
@@ -274,8 +272,8 @@ export class CliToolService {
|
|
|
274
272
|
*
|
|
275
273
|
* `mode` defaults to `both` so the common single-machine case does the
|
|
276
274
|
* obviously-right thing without the operator choosing. A tool that has no
|
|
277
|
-
* injectable config
|
|
278
|
-
*
|
|
275
|
+
* injectable config reports `remote` honestly instead of claiming a file
|
|
276
|
+
* write it never performed.
|
|
279
277
|
*/
|
|
280
278
|
async applyConfig(
|
|
281
279
|
tenantId: string,
|
|
@@ -292,12 +290,14 @@ export class CliToolService {
|
|
|
292
290
|
let wroteFile = false;
|
|
293
291
|
let settingsPath: string | undefined;
|
|
294
292
|
let fileMessage = "";
|
|
293
|
+
let fileWarnings: readonly string[] | undefined;
|
|
295
294
|
|
|
296
295
|
if (wantsFile) {
|
|
297
296
|
const result: ApplyResult = await injector.apply(input);
|
|
298
297
|
wroteFile = result.success;
|
|
299
298
|
if (result.settingsPath !== undefined) settingsPath = result.settingsPath;
|
|
300
299
|
fileMessage = result.message;
|
|
300
|
+
fileWarnings = result.warnings;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
let savedRemoteRoute = false;
|
|
@@ -321,6 +321,7 @@ export class CliToolService {
|
|
|
321
321
|
savedRemoteRoute,
|
|
322
322
|
...(settingsPath === undefined ? {} : { settingsPath }),
|
|
323
323
|
message: applyMessage(outcome, toolId, fileMessage),
|
|
324
|
+
...(fileWarnings && fileWarnings.length > 0 ? { warnings: fileWarnings } : {}),
|
|
324
325
|
};
|
|
325
326
|
}
|
|
326
327
|
|
|
@@ -232,6 +232,12 @@ export interface UsageRequestItem {
|
|
|
232
232
|
* written before the column existed.
|
|
233
233
|
*/
|
|
234
234
|
payloadCaptureState?: string;
|
|
235
|
+
/**
|
|
236
|
+
* True for a completed request whose output was far smaller than the model's
|
|
237
|
+
* ceiling and which ended with an ordinary `stop` (a "degenerate stop").
|
|
238
|
+
* Absent for everything else — including rows written before the column.
|
|
239
|
+
*/
|
|
240
|
+
degenerateStop?: boolean;
|
|
235
241
|
/**
|
|
236
242
|
* Bitmask of the payload stages captured for this request: 1 request,
|
|
237
243
|
* 2 provider request, 4 provider response, 8 client response. Read from the
|