From b83ab0f821fdc6aceb6c8c055959ce9518d6cfee Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 20 Sep 2026 13:49:20 +0800 Subject: [PATCH 1/9] feat(clients): add the Kilo global-config client integration Kilo becomes the sixteenth file-toggle client, in the OpenCode family: the managed writer owns only provider.opencodex in the first existing global file among kilo.jsonc, kilo.json, opencode.jsonc, opencode.json and config.json under XDG ~/.config/kilo, and never a project config. - V1-only contribution: Kilo's published schema has no OpenCode V2 providers key, so no V2 block or variants are emitted. - Admission follows OpenCode's rule: loopback uses {env:OPENCODEX_KILO_API_KEY} as options.apiKey, a non-loopback bind moves to the x-opencodex-api-key header, and a real key is never serialized. - JSONC parse: comments and trailing commas are canonicalized before the rewrite-safety scan (parseJsonc extracted to src/lib/jsonc.ts and shared with the OpenCode launcher); serialization stays pretty JSON. - No ocx kilo launcher, and no implicit owned-catalog fan-out membership, matching OpenCode. --- .github/pr-assets/kilo-client-integration.png | Bin 0 -> 138660 bytes .../content/docs/fr/guides/integrations.md | 13 +- .../content/docs/fr/reference/cli/agents.md | 5 +- .../src/content/docs/guides/integrations.md | 29 ++- .../content/docs/ja/reference/cli/agents.md | 5 +- .../content/docs/ko/reference/cli/agents.md | 5 +- .../src/content/docs/reference/cli/agents.md | 5 +- .../content/docs/reference/configuration.md | 2 +- .../content/docs/ru/reference/cli/agents.md | 5 +- .../content/docs/tr/guides/integrations.md | 13 +- .../content/docs/tr/reference/cli/agents.md | 5 +- .../docs/zh-cn/reference/cli/agents.md | 5 +- .../content/docs/zh-tw/guides/integrations.md | 13 +- .../docs/zh-tw/reference/cli/agents.md | 5 +- gui/src/app-routing.ts | 1 + .../client-config-clients.ts | 4 +- gui/src/components/integration-marks.ts | 1 + gui/src/i18n/de.ts | 3 + gui/src/i18n/en.ts | 3 + gui/src/i18n/fr.ts | 3 + gui/src/i18n/ja.ts | 3 + gui/src/i18n/ko.ts | 3 + gui/src/i18n/ru.ts | 3 + gui/src/i18n/tr.ts | 3 + gui/src/i18n/vi.ts | 3 + gui/src/i18n/zh-TW.ts | 3 + gui/src/i18n/zh.ts | 3 + .../integrations/FileIntegrationPage.tsx | 2 + gui/src/pages/integrations/integration-api.ts | 1 + .../pages/integrations/integration-tabs.ts | 2 + .../pages/integrations/overview-clients.ts | 1 + gui/tests/client-config-panel.test.tsx | 2 +- gui/tests/fr-localization.test.ts | 2 + gui/tests/integrations-api.test.ts | 2 +- gui/tests/integrations-overview-rows.test.ts | 3 +- gui/tests/locale-parity.test.ts | 2 + scripts/test-layout/layout.json | 1 + src/cli/export-command.ts | 4 +- src/cli/help.ts | 2 +- src/cli/opencode.ts | 85 +------- src/cli/registry.ts | 4 +- src/clients/config-export.ts | 19 +- src/clients/config-export/constants.ts | 8 + src/clients/config-export/contracts.ts | 3 +- src/clients/config-export/kilo.ts | 106 +++++++++ src/integrations/config-io.ts | 15 +- src/integrations/mutation-plan.ts | 7 +- src/integrations/registry.ts | 7 + src/integrations/state.ts | 2 +- src/lib/jsonc.ts | 97 +++++++++ structure/clients/integrations.md | 11 +- tests/clients/kilo-client.test.ts | 202 ++++++++++++++++++ tests/config/client-config-export.test.ts | 14 +- tests/fixtures/test-layout-expected.json | 1 + tests/gui/integrations-invariants.test.ts | 3 +- 55 files changed, 622 insertions(+), 132 deletions(-) create mode 100644 .github/pr-assets/kilo-client-integration.png create mode 100644 src/clients/config-export/kilo.ts create mode 100644 src/lib/jsonc.ts create mode 100644 tests/clients/kilo-client.test.ts diff --git a/.github/pr-assets/kilo-client-integration.png b/.github/pr-assets/kilo-client-integration.png new file mode 100644 index 0000000000000000000000000000000000000000..0fcb0ff479910277f679d28e4bd562e6b27ab482 GIT binary patch literal 138660 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

UF62+7ETleEQA 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 literal 0 HcmV?d00001 diff --git a/docs-site/src/content/docs/fr/guides/integrations.md b/docs-site/src/content/docs/fr/guides/integrations.md index d4438e568fb..1d0b7872a5f 100644 --- a/docs-site/src/content/docs/fr/guides/integrations.md +++ b/docs-site/src/content/docs/fr/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Intégrations -description: Connectez opencodex à OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast et omo depuis le tableau de bord — un commutateur par client, avec une sauvegarde avant chaque écriture. +description: Connectez opencodex à OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast, omo, Cline CLI et Kilo depuis le tableau de bord — un commutateur par client, avec une sauvegarde avant chaque écriture. --- L'onglet **Intégrations** écrit le bloc fournisseur d'opencodex dans le fichier de configuration du client, -puis peut le retirer. Quinze clients fonctionnent ainsi, chacun avec son propre commutateur : +puis peut le retirer. Seize clients fonctionnent ainsi, chacun avec son propre commutateur : | Client | Fichier de configuration | Format | Prise d'effet de la modification | Identifiant | |---|---|---|---|---| @@ -23,6 +23,7 @@ puis peut le retirer. Quinze clients fonctionnent ainsi, chacun avec son propre | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | immédiatement à l'enregistrement — Raycast surveille le fichier | aucun — bouclage uniquement | | omo | `~/.omo/agent/models.json` | JSON | nouvelles sessions | espace réservé de bouclage | | Cline CLI | `~/.cline/data/settings/providers.json` + `models.json` | JSON | après arrêt et redémarrage | bouclage uniquement | +| Kilo | premier fichier existant parmi `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` ou `config.json` sous `~/.config/kilo` | JSONC | nouvelles sessions | `OPENCODEX_KILO_API_KEY` | Les modèles GJC dotés d'une échelle d'effort de raisonnement prise en charge exportent `reasoning: true`, `thinking.levels` et `compat.supportsReasoningEffort`, afin que GJC propose le choix de l'effort. Les modèles Codex natifs reçoivent leur échelle standard même si le catalogue l'omet. Ces champs sont absents sans échelle connue ; `none` n'envoie pas d'effort et `ultra` devient `max` sur le réseau. Actualisez l'intégration pour mettre à jour ces options. @@ -299,3 +300,11 @@ ocx integration client restore --op ``` [CLI / rollback / CLINE_PROVIDER_SETTINGS_PATH](/guides/integrations/#cline-cli). + +## Kilo + +Kilo n’écrit que `provider.opencodex` dans le premier fichier global existant sous `~/.config/kilo`. Les autres clés restent inchangées. Appliquer réécrit tout le fichier ; commentaires et virgules finales ne sont pas conservés. Sélectionnez `opencodex/` dans Kilo. + +```bash +ocx integration client enable --client kilo +``` diff --git a/docs-site/src/content/docs/fr/reference/cli/agents.md b/docs-site/src/content/docs/fr/reference/cli/agents.md index b63eb62f9c3..01edd410cb4 100644 --- a/docs-site/src/content/docs/fr/reference/cli/agents.md +++ b/docs-site/src/content/docs/fr/reference/cli/agents.md @@ -176,7 +176,7 @@ Gérez et appliquez la clôture du modèle Grok Build. ## Exportation de la configuration client -### `ocx export --client ` +### `ocx export --client ` Imprimez une configuration client connectée au proxy en cours d'exécution. La commande sérialise le bloc fournisseur `opencodex` — URL de base, liste de modèles et référence d’identifiant du client @@ -187,7 +187,7 @@ les modèles Codex peuvent actuellement voir. | Option | Actions | | --- | --- | -| `--client ` | Requis. Sélectionne le dialecte de configuration client. | +| `--client ` | Requis. Sélectionne le dialecte de configuration client. | | `--json` | Imprimez le document généré en tant que JSON sur la sortie standard pour les scripts. Il s'agit de JSON même lorsque le format natif du client sélectionné est YAML, TOML ou JSON5. | | `--out ` | Écrivez le format de configuration natif du client dans ``. Refuse de remplacer un fichier existant. | | `--force` | Autoriser `--out` à remplacer un fichier existant. | @@ -220,6 +220,7 @@ propres valeurs par défaut à ces lignes. | `aside` | `~/.aside/u//models.json` pour le compte que le fichier `accounts.json` d'Aside désigne comme courant ; un manifeste illisible est refusé plutôt que de retomber sur un compte | `aside-models.json` | aucun — espace réservé de bouclage | | `raycast` | `~/.config/raycast/ai/providers.yaml`, sur macOS comme sur Windows (Raycast n'honore pas `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | aucun — bouclage uniquement, aucune entrée `api_keys` n'est écrite | | `omo` | `~/.omo/agent/models.json` (`OMO_CODING_AGENT_DIR`, puis `SENPI_CODING_AGENT_DIR`, puis `PI_CODING_AGENT_DIR` l'emportent dans cet ordre une fois définis ; une valeur relative est refusée) | `omo-models.json` | aucun — espace réservé de bouclage | +| `kilo` | premier fichier existant parmi `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` ou `config.json` sous `~/.config/kilo` | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | L'exportation Raycast est un document `providers.yaml` autonome contenant un seul élément `id: opencodex` dans la séquence `providers` : `name: OpenCodex`, l'URL de base `/v1` du proxy et chaque modèle routé avec diff --git a/docs-site/src/content/docs/guides/integrations.md b/docs-site/src/content/docs/guides/integrations.md index 9d7d4509abc..0b7b530adad 100644 --- a/docs-site/src/content/docs/guides/integrations.md +++ b/docs-site/src/content/docs/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Integrations -description: Connect opencodex to OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast, omo and Cline CLI from the dashboard — one switch per client, with a backup taken before every write. +description: Connect opencodex to OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast, omo, Cline CLI and Kilo from the dashboard — one switch per client, with a backup taken before every write. --- The **Integrations** tab writes opencodex's provider block into a client's own config -file, and removes it again. Fifteen clients work this way, each with a switch: +file, and removes it again. Sixteen clients work this way, each with a switch: | Client | Config file | Format | When the change takes effect | Credential | |---|---|---|---|---| @@ -23,6 +23,7 @@ file, and removes it again. Fifteen clients work this way, each with a switch: | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | immediately on save — Raycast watches the file | none — loopback only | | omo | `~/.omo/agent/models.json` | JSON | new sessions | loopback placeholder | | Cline CLI | `~/.cline/data/settings/providers.json` and sibling `models.json` | JSON pair | after stopping and restarting Cline | loopback placeholder | +| Kilo | first existing `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json`, or `config.json` under `~/.config/kilo` | JSONC | new sessions | `OPENCODEX_KILO_API_KEY` | Generated catalogs include only enabled models from each provider selection. This applies to both downloads and managed integrations, including Pi and Aside. The management model list still shows @@ -518,3 +519,27 @@ listens on a non-loopback address, put a data-admission key (the token described key) in the app's API key field. The app sends it as `Authorization: Bearer`, which `/v1/chat/completions` accepts as proxy admission and never forwards upstream; see the [authentication matrix](/reference/proxy-formats/#authentication-matrix). + +## Kilo + +Kilo CLI, VS Code, and JetBrains share one global config. This integration writes +`provider.opencodex` into the first existing file among `kilo.jsonc`, `kilo.json`, +`opencode.jsonc`, `opencode.json`, and `config.json` under `~/.config/kilo` +(`XDG_CONFIG_HOME` relocates that directory). If none exist, the destination is +`kilo.jsonc`. Project configs are never written. + +The owned fragment is only `provider.opencodex` (OpenCode V1 shape: `npm`, `options`, +`models`). Kilo's published schema has no OpenCode V2 `providers` key, so that block is +not emitted. `$schema`, `model`, `enabled_providers`, MCP, and other keys stay +user-owned. Select `opencodex/` in Kilo after applying. + +Loopback uses `{env:OPENCODEX_KILO_API_KEY}` as `options.apiKey`. A non-loopback bind +moves admission to `options.headers["x-opencodex-api-key"]` and never serializes a real +key. Apply rewrites the whole global file as pretty JSON, so comments and trailing +commas in other keys are not preserved. Kilo is not on the implicit catalog fan-out; +refresh it explicitly after changing the routed model selection. + +```bash +ocx integration client enable --client kilo +ocx export --client kilo --out ./kilo.jsonc +``` diff --git a/docs-site/src/content/docs/ja/reference/cli/agents.md b/docs-site/src/content/docs/ja/reference/cli/agents.md index 20d62ca3eca..fd83c91851a 100644 --- a/docs-site/src/content/docs/ja/reference/cli/agents.md +++ b/docs-site/src/content/docs/ja/reference/cli/agents.md @@ -136,7 +136,7 @@ Grok Build モデル フェンスを管理および適用します。 ## クライアント設定のエクスポート -### `ocx export --client ` +### `ocx export --client ` 実行中のプロキシに接続するクライアント設定を出力します。このコマンドは、ベース URL、モデル一覧、およびクライアントに応じた認証情報参照または `opencodex-loopback` プレースホルダーを含む `opencodex` プロバイダーブロックを、選択したクライアントのネイティブ形式でシリアル化します。 @@ -144,7 +144,7 @@ Grok Build モデル フェンスを管理および適用します。 |旗 |アクション | | --- | --- | -| `--client ` |必須。クライアントの設定形式を選択します。 | +| `--client ` |必須。クライアントの設定形式を選択します。 | | `--json` |構成 JSON のみを標準出力に出力するため、リダイレクトはバイト正確な出力をキャプチャします。 `--out` 書き込みメモを含むすべての診断は stderr に送られます。 | | `--out ` |設定を `` に書き込みます。既存のファイルの置き換えを拒否します。 | | `--force` | `--out` が既存のファイルを置き換えることを許可します。 | @@ -174,6 +174,7 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `aside` | `~/.aside/u//models.json`。Aside 自身の `accounts.json` が現在のアカウントとして指す account を使います。マニフェストが読めない場合は、既定のアカウントに落とさず拒否します | `aside-models.json` | なし — loopback placeholder | | `raycast` | `~/.config/raycast/ai/providers.yaml` (macOS と Windows で同じ。Raycast は `XDG_CONFIG_HOME` を尊重しません) | `raycast-providers.yaml` | なし — loopback のみ。`api_keys` エントリは書き込まれません | | `omo` | `~/.omo/agent/models.json` (`OMO_CODING_AGENT_DIR`、次に `SENPI_CODING_AGENT_DIR`、次に `PI_CODING_AGENT_DIR` の順で設定時に優先。相対値は拒否されます) | `omo-models.json` | なし — loopback placeholder | +| `kilo` | `~/.config/kilo` 配下で最初に存在する `kilo.jsonc`、`kilo.json`、`opencode.jsonc`、`opencode.json`、`config.json` | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | Raycast のエクスポートは、`providers` シーケンスに `id: opencodex` 要素を 1 つだけ持つ独立した `providers.yaml` 文書です。内容は `name: OpenCodex`、プロキシの `/v1` ベース URL、および `abilities` 付きのルーティング済み全モデルです (`tools` と `system_message` は常にサポート、`vision` はカタログの入力モダリティから、`reasoning_effort` はモデルに effort ラダーがある場合、`temperature` は推論モデルではオフ)。Custom Providers は Raycast Pro の機能で、Raycast はこのファイルを監視しているため、保存した変更は再起動なしで反映されます。形式は [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers) に記載されています。`api_keys` エントリは書き込まれないため、このエクスポートは loopback 専用で、loopback 以外のバインドは拒否されます。 diff --git a/docs-site/src/content/docs/ko/reference/cli/agents.md b/docs-site/src/content/docs/ko/reference/cli/agents.md index 8dec1675fc8..be03f868d19 100644 --- a/docs-site/src/content/docs/ko/reference/cli/agents.md +++ b/docs-site/src/content/docs/ko/reference/cli/agents.md @@ -163,7 +163,7 @@ Grok Build model fence를 관리하고 적용합니다. ## 클라이언트 설정 내보내기 -### `ocx export --client ` +### `ocx export --client ` 실행 중인 프록시에 연결할 client config를 출력합니다. 이 명령은 base URL, model list, 그리고 client에 따라 credential reference 또는 `opencodex-loopback` placeholder를 포함한 `opencodex` provider block을 선택한 client의 네이티브 형식으로 직렬화합니다. @@ -171,7 +171,7 @@ Grok Build model fence를 관리하고 적용합니다. | 플래그 | 동작 | | --- | --- | -| `--client ` | 필수입니다. 클라이언트 설정 형식을 선택합니다. | +| `--client ` | 필수입니다. 클라이언트 설정 형식을 선택합니다. | | `--json` | config JSON만 stdout에 출력하므로, redirect가 byte-exact 출력을 캡처합니다. `--out` write note를 포함한 모든 진단 메시지는 stderr로 갑니다. | | `--out ` | config를 ``에 씁니다. 기존 파일이 있으면 덮어쓰지 않습니다. | | `--force` | `--out`이 기존 파일을 덮어쓰도록 허용합니다. | @@ -201,6 +201,7 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `aside` | `~/.aside/u//models.json`. Aside의 `accounts.json`이 현재 계정으로 지정한 account를 사용합니다. 매니페스트를 읽을 수 없으면 임의의 계정으로 넘어가지 않고 거부합니다 | `aside-models.json` | 없음 — loopback placeholder | | `raycast` | `~/.config/raycast/ai/providers.yaml` (macOS와 Windows 모두 동일. Raycast는 `XDG_CONFIG_HOME`을 따르지 않습니다) | `raycast-providers.yaml` | 없음 — loopback 전용. `api_keys` 항목은 쓰지 않습니다 | | `omo` | `~/.omo/agent/models.json` (`OMO_CODING_AGENT_DIR`, `SENPI_CODING_AGENT_DIR`, `PI_CODING_AGENT_DIR` 순서로 설정된 값이 우선. 상대 경로는 거부됩니다) | `omo-models.json` | 없음 — loopback placeholder | +| `kilo` | `~/.config/kilo`에서 먼저 존재하는 `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` 또는 `config.json` | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | Raycast 내보내기는 `providers` 시퀀스에 `id: opencodex` 요소 하나만 담은 독립 `providers.yaml` 문서입니다. 내용은 `name: OpenCodex`, proxy의 `/v1` base URL, 그리고 `abilities`가 붙은 라우팅된 모든 모델입니다(`tools`와 `system_message`는 항상 지원, `vision`은 카탈로그의 입력 모달리티를 따름, `reasoning_effort`는 모델에 effort 사다리가 있을 때, `temperature`는 추론 모델에서 꺼짐). Custom Providers는 Raycast Pro 기능이며, Raycast가 이 파일을 감시하므로 저장한 변경은 재시작 없이 적용됩니다. 형식은 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)에 문서화되어 있습니다. `api_keys` 항목은 쓰지 않으므로 이 내보내기는 loopback 전용이며, loopback이 아닌 bind는 거부됩니다. diff --git a/docs-site/src/content/docs/reference/cli/agents.md b/docs-site/src/content/docs/reference/cli/agents.md index 3d2e1a57aa1..5b46f5f81d5 100644 --- a/docs-site/src/content/docs/reference/cli/agents.md +++ b/docs-site/src/content/docs/reference/cli/agents.md @@ -283,7 +283,7 @@ Manage and apply the Grok Build model fence. ## Client config export -### `ocx export --client ` +### `ocx export --client ` Print a client config wired to the running proxy. The command serializes the `opencodex` provider block — base URL, model list, and the client's credential @@ -294,7 +294,7 @@ models Codex can currently see. | Flag | Action | | --- | --- | -| `--client ` | Required. Selects the client config dialect. | +| `--client ` | Required. Selects the client config dialect. | | `--json` | Print the generated document as JSON on stdout for scripts. This is JSON even when the selected client's native format is YAML, TOML, or JSON5. | | `--out ` | Write the client's native config format to ``. Refuses to replace an existing file. | | `--force` | Allow `--out` to replace an existing file. | @@ -326,6 +326,7 @@ client applies its own defaults for those). | `aside` | `~/.aside/u//models.json` for the account Aside's own `accounts.json` names as current; an unreadable manifest is refused rather than defaulting to an account | `aside-models.json` | none — loopback placeholder | | `raycast` | `~/.config/raycast/ai/providers.yaml` on macOS and Windows alike (Raycast does not honor `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | none — loopback only, no `api_keys` entry is written | | `omo` | `~/.omo/agent/models.json` (`OMO_CODING_AGENT_DIR`, then `SENPI_CODING_AGENT_DIR`, then `PI_CODING_AGENT_DIR` win in that order when set; a relative value is refused) | `omo-models.json` | none — loopback placeholder | +| `kilo` | first existing `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json`, or `config.json` under `~/.config/kilo` (`XDG_CONFIG_HOME` relocates that directory) | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | The managed DSH export requires DSH 0.1.0-rc.6 or newer and owns only `llm-pi-ai.providers.opencodex`. DSH hot reloads that provider; the user's default model and diff --git a/docs-site/src/content/docs/reference/configuration.md b/docs-site/src/content/docs/reference/configuration.md index 3a299fa7f98..909edc30e26 100644 --- a/docs-site/src/content/docs/reference/configuration.md +++ b/docs-site/src/content/docs/reference/configuration.md @@ -61,7 +61,7 @@ a known configured model id. Cursor may require a model-list refresh or restart `fastRows` is an optional boolean and defaults to `true`. The raw OpenAI-style `/v1/models` list, Claude Code discovery, and client config exports (including pi, OpenCode, -OMP, Hermes, OpenClaw, Kimi, gjc, DSH, MCode, ZCode, Prime, Aside, Raycast, and omo) add a `--fast` selector for every model whose +OMP, Hermes, OpenClaw, Kimi, gjc, DSH, MCode, ZCode, Prime, Aside, Raycast, omo, Cline, and Kilo) add a `--fast` selector for every model whose resolved Fast policy is eligible. Selecting one routes the base model and requests the `priority` service tier — the same Fast the Codex app exposes through its picker toggle. The base row stays listed, so the row is an addition rather than a replacement. diff --git a/docs-site/src/content/docs/ru/reference/cli/agents.md b/docs-site/src/content/docs/ru/reference/cli/agents.md index e2ad3a31e22..a42fe96010d 100644 --- a/docs-site/src/content/docs/ru/reference/cli/agents.md +++ b/docs-site/src/content/docs/ru/reference/cli/agents.md @@ -163,7 +163,7 @@ override, но файлы на диске никогда не меняются. ## Экспорт client config -### `ocx export --client ` +### `ocx export --client ` Печатает client config, направленный на работающий прокси. Команда сериализует блок провайдера `opencodex` в нативном формате выбранного клиента: base URL, список моделей и, @@ -174,7 +174,7 @@ override, но файлы на диске никогда не меняются. | Флаг | Действие | | --- | --- | -| `--client ` | Обязателен. Выбирает формат конфигурации клиента. | +| `--client ` | Обязателен. Выбирает формат конфигурации клиента. | | `--json` | Печатать только JSON-конфиг в stdout, чтобы redirect сохранял побайтно точный вывод. Вся диагностика, включая заметку о записи через `--out`, идёт в stderr. | | `--out ` | Записать конфиг в ``. Перезаписывать существующий файл не позволит. | | `--force` | Разрешить `--out` заменить существующий файл. | @@ -207,6 +207,7 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `aside` | `~/.aside/u//models.json` для аккаунта, который `accounts.json` самого Aside называет текущим; нечитаемый манифест отклоняется, а не подменяется произвольным аккаунтом | `aside-models.json` | нет — loopback placeholder | | `raycast` | `~/.config/raycast/ai/providers.yaml` одинаково на macOS и Windows (Raycast не учитывает `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | нет — только loopback, запись `api_keys` не создаётся | | `omo` | `~/.omo/agent/models.json` (`OMO_CODING_AGENT_DIR`, затем `SENPI_CODING_AGENT_DIR`, затем `PI_CODING_AGENT_DIR` имеют приоритет в этом порядке, если заданы; относительное значение отклоняется) | `omo-models.json` | нет — loopback placeholder | +| `kilo` | первый существующий файл среди `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` или `config.json` в `~/.config/kilo` | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | Экспорт для Raycast — это отдельный документ `providers.yaml` с одним элементом `id: opencodex` в последовательности `providers`: `name: OpenCodex`, базовый URL прокси с `/v1` и каждая маршрутизируемая diff --git a/docs-site/src/content/docs/tr/guides/integrations.md b/docs-site/src/content/docs/tr/guides/integrations.md index 71d77a09e5b..1646c75a99e 100644 --- a/docs-site/src/content/docs/tr/guides/integrations.md +++ b/docs-site/src/content/docs/tr/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Entegrasyonlar -description: Kontrol panelinden OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast ve omo'yu opencodex'e bağlayın — istemci başına tek bir anahtar ve her yazmadan önce alınan bir yedek. +description: Kontrol panelinden OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast, omo, Cline CLI ve Kilo'yu opencodex'e bağlayın — istemci başına tek bir anahtar ve her yazmadan önce alınan bir yedek. --- **Entegrasyonlar** sekmesi, opencodex'in sağlayıcı bloğunu istemcinin kendi -yapılandırma dosyasına yazar ve tekrar kaldırır. On beş istemci bu şekilde +yapılandırma dosyasına yazar ve tekrar kaldırır. On altı istemci bu şekilde çalışır, her biri bir anahtarla: | İstemci | Yapılandırma dosyası | Format | Değişiklik ne zaman geçerli olur? | Kimlik bilgisi | @@ -24,6 +24,7 @@ yapılandırma dosyasına yazar ve tekrar kaldırır. On beş istemci bu şekild | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | kaydedildiği anda — Raycast dosyayı izler | yok — yalnızca geri döngü | | omo | `~/.omo/agent/models.json` | JSON | yeni oturumlarda | geri döngü yer tutucusu | | Cline CLI | `~/.cline/data/settings/providers.json` + `models.json` | JSON | kapatıp yeniden başlattıktan sonra | yalnızca loopback | +| Kilo | `~/.config/kilo` altında ilk bulunan `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` veya `config.json` | JSONC | yeni oturumlarda | `OPENCODEX_KILO_API_KEY` | Desteklenen akıl yürütme düzeylerine sahip GJC modelleri, GJC'nin düzey seçimi sunabilmesi için `reasoning: true`, `thinking.levels` ve `compat.supportsReasoningEffort` alanlarını dışa aktarır. Yerel Codex modelleri, katalogda belirtilmese bile standart düzeylerini alır. Bilinen düzeyi olmayan modellerde bu alanlar bulunmaz. `none` düzey göndermez ve `ultra` gönderimde `max` düzeyine dönüşür; bu yüzden seçeneklerde yer almazlar. Model seçeneklerini güncellemek için entegrasyonu yenileyin. @@ -324,3 +325,11 @@ ocx integration client restore --op ``` [CLI / rollback / CLINE_PROVIDER_SETTINGS_PATH](/guides/integrations/#cline-cli). + +## Kilo + +Kilo yalnızca `~/.config/kilo` altındaki ilk mevcut genel dosyada `provider.opencodex` yazar. Diğer anahtarlar değişmez. Uygula dosyanın tamamını yeniden yazar; yorumlar ve sondaki virgüller korunmaz. Kilo’da `opencodex/` seçin. + +```bash +ocx integration client enable --client kilo +``` diff --git a/docs-site/src/content/docs/tr/reference/cli/agents.md b/docs-site/src/content/docs/tr/reference/cli/agents.md index c1fb9849612..5269764e8f9 100644 --- a/docs-site/src/content/docs/tr/reference/cli/agents.md +++ b/docs-site/src/content/docs/tr/reference/cli/agents.md @@ -202,7 +202,7 @@ Grok Build model çitini yönetin ve uygulayın. ## İstemci yapılandırma dışa aktarma -### `ocx export --client ` +### `ocx export --client ` Çalışan proxy'ye bağlı bir istemci yapılandırmasını yazdırın. Komut, `opencodex` sağlayıcı bloğunu — temel URL, model listesi ve istemcinin kimlik bilgisi @@ -214,7 +214,7 @@ yalnızca Codex'in şu anda görebildiği modelleri yayınlar. | Bayrak | Eylem | | --- | --- | -| `--client ` | Gerekli. İstemci yapılandırma lehçesini seçer. | +| `--client ` | Gerekli. İstemci yapılandırma lehçesini seçer. | | `--json` | Betikler için stdout üzerinde oluşturulan belgeyi JSON olarak yazdırın. Bu, seçilen istemcinin yerel formatı YAML, TOML veya JSON5 olsa bile JSON'dur. | | `--out ` | İstemcinin yerel yapılandırma formatını `` konumuna yazın. Mevcut bir dosyanın üzerine yazmayı reddeder. | | `--force` | `--out`'un mevcut bir dosyanın üzerine yazmasına izin verin. | @@ -247,6 +247,7 @@ için kendi varsayılanlarını uygular) gelir. | `aside` | Aside'ın kendi `accounts.json` dosyasının güncel olarak gösterdiği hesap için `~/.aside/u//models.json`; okunamayan bir manifest, gelişigüzel bir hesaba düşmek yerine reddedilir | `aside-models.json` | yok — geri döngü yer tutucusu | | `raycast` | `~/.config/raycast/ai/providers.yaml`, macOS ve Windows'ta aynı (Raycast `XDG_CONFIG_HOME` değerini dikkate almaz) | `raycast-providers.yaml` | yok — yalnızca geri döngü, `api_keys` girdisi yazılmaz | | `omo` | `~/.omo/agent/models.json` (ayarlandığında sırasıyla `OMO_CODING_AGENT_DIR`, `SENPI_CODING_AGENT_DIR`, `PI_CODING_AGENT_DIR` öncelikli; göreli değer reddedilir) | `omo-models.json` | yok — geri döngü yer tutucusu | +| `kilo` | `~/.config/kilo` altında ilk bulunan `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` veya `config.json` | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | Raycast dışa aktarımı, `providers` dizisinde tek bir `id: opencodex` öğesi içeren bağımsız bir `providers.yaml` belgesidir: `name: OpenCodex`, proxy'nin `/v1` temel URL'si ve diff --git a/docs-site/src/content/docs/zh-cn/reference/cli/agents.md b/docs-site/src/content/docs/zh-cn/reference/cli/agents.md index b1a0d4306ce..9aef791ac0b 100644 --- a/docs-site/src/content/docs/zh-cn/reference/cli/agents.md +++ b/docs-site/src/content/docs/zh-cn/reference/cli/agents.md @@ -141,7 +141,7 @@ ocx claude desktop import [--apply] Validate and import JSON ## Client config export -### `ocx export --client ` +### `ocx export --client ` 输出连接到正在运行代理的客户端配置。此命令会以所选客户端的原生格式序列化 `opencodex` provider 块,其中包含基础 URL、模型列表,以及该客户端适用的凭据引用或 `opencodex-loopback` 占位值。 @@ -149,7 +149,7 @@ ocx claude desktop import [--apply] Validate and import JSON | 标志 | 动作 | | --- | --- | -| `--client ` | 必需。选择客户端配置格式。 | +| `--client ` | 必需。选择客户端配置格式。 | | `--json` | 仅在 stdout 打印配置 JSON,这样重定向即可捕获字节级精确输出。包括 `--out` 写入提示在内的所有诊断信息都会输出到 stderr。 | | `--out ` | 将配置写入 ``。拒绝替换已存在的文件。 | | `--force` | 允许 `--out` 替换已存在的文件。 | @@ -179,6 +179,7 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `aside` | `~/.aside/u//models.json`,对应 Aside 自己的 `accounts.json` 指明的当前账户;清单不可读时会被拒绝,而不是退回到某个账户 | `aside-models.json` | 无 — loopback placeholder | | `raycast` | `~/.config/raycast/ai/providers.yaml`(macOS 与 Windows 相同;Raycast 不遵循 `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | 无 — 仅限回环,不会写入 `api_keys` 条目 | | `omo` | `~/.omo/agent/models.json`(设置后依次由 `OMO_CODING_AGENT_DIR`、`SENPI_CODING_AGENT_DIR`、`PI_CODING_AGENT_DIR` 优先;相对路径会被拒绝) | `omo-models.json` | 无 — loopback placeholder | +| `kilo` | `~/.config/kilo` 下最先存在的 `kilo.jsonc`、`kilo.json`、`opencode.jsonc`、`opencode.json` 或 `config.json` | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | Raycast 导出是一份独立的 `providers.yaml` 文档,在 `providers` 序列中只有一个 `id: opencodex` 元素:`name: OpenCodex`、代理的 `/v1` 基础 URL,以及每个已路由模型及其 `abilities`(`tools` 与 `system_message` 始终支持,`vision` 取自目录的输入模态,`reasoning_effort` 在模型有 effort 阶梯时设置,`temperature` 对推理模型关闭)。Custom Providers 是 Raycast Pro 功能,且 Raycast 会监视该文件,因此保存后的更改无需重启即可生效。格式见 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)。不会写入任何 `api_keys` 条目,所以该导出仅限回环,非回环绑定会被拒绝。 diff --git a/docs-site/src/content/docs/zh-tw/guides/integrations.md b/docs-site/src/content/docs/zh-tw/guides/integrations.md index 9aa5f572483..388144edec0 100644 --- a/docs-site/src/content/docs/zh-tw/guides/integrations.md +++ b/docs-site/src/content/docs/zh-tw/guides/integrations.md @@ -1,9 +1,9 @@ --- title: 整合 -description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、OpenClaw、Kimi Code、gjc、DeepSeek Harness、MiniMax Code、ZCode、Prime Agent、Aside、Raycast 與 omo——每個客戶端一個開關,每次寫入前都會先備份。 +description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、OpenClaw、Kimi Code、gjc、DeepSeek Harness、MiniMax Code、ZCode、Prime Agent、Aside、Raycast、omo、Cline CLI 與 Kilo——每個客戶端一個開關,每次寫入前都會先備份。 --- -**整合(Integrations)** 分頁會把 opencodex 的 provider 區塊寫入客戶端自己的設定檔,也會把它移除。共有十五個客戶端以這種方式運作,每個都有一個開關: +**整合(Integrations)** 分頁會把 opencodex 的 provider 區塊寫入客戶端自己的設定檔,也會把它移除。共有十六個客戶端以這種方式運作,每個都有一個開關: | 客戶端 | 設定檔 | 格式 | 變更生效時機 | 憑證 | |---|---|---|---|---| @@ -22,6 +22,7 @@ description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、 | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | 儲存後立即生效——Raycast 會監看該檔案 | 無——僅限 loopback | | omo | `~/.omo/agent/models.json` | JSON | 新工作階段 | loopback 佔位符 | | Cline CLI | `~/.cline/data/settings/providers.json` + `models.json` | JSON | 結束並重新啟動後 | 僅限 loopback | +| Kilo | `~/.config/kilo` 下最先存在的 `kilo.jsonc`、`kilo.json`、`opencode.jsonc`、`opencode.json` 或 `config.json` | JSONC | 新工作階段 | `OPENCODEX_KILO_API_KEY` | 具有受支援推理強度階梯的 GJC 模型會匯出 `reasoning: true`、`thinking.levels` 與 `compat.supportsReasoningEffort`,讓 GJC 提供強度選擇。原生 Codex 模型即使未在目錄中列出階梯,也會取得標準階梯。沒有已知階梯的模型會省略這些欄位;`none` 不傳送強度,`ultra` 在傳輸時會折疊成 `max`,因此不會列為選項。重新整理整合即可更新模型選項。 @@ -201,3 +202,11 @@ ocx integration client restore --op ``` [CLI / rollback / CLINE_PROVIDER_SETTINGS_PATH](/guides/integrations/#cline-cli). + +## Kilo + +Kilo 只會把 `provider.opencodex` 寫入 `~/.config/kilo` 下最先存在的全域檔。其他鍵保持不變。套用會重寫整個檔案,因此不會保留註解與尾隨逗號。請在 Kilo 中選擇 `opencodex/<模型>`。 + +```bash +ocx integration client enable --client kilo +``` diff --git a/docs-site/src/content/docs/zh-tw/reference/cli/agents.md b/docs-site/src/content/docs/zh-tw/reference/cli/agents.md index 9b06950e1a3..813232c3f4e 100644 --- a/docs-site/src/content/docs/zh-tw/reference/cli/agents.md +++ b/docs-site/src/content/docs/zh-tw/reference/cli/agents.md @@ -139,7 +139,7 @@ ocx claude desktop import [--apply] 驗證並匯入 JSON ## 客戶端設定匯出 -### `ocx export --client ` +### `ocx export --client ` 印出連接到執行中代理的客戶端設定。此指令會用所選客戶端的原生格式,序列化含有 base URL、模型清單,以及適用的環境變數參考或 loopback 佔位符的 `opencodex` provider 區塊。 @@ -147,7 +147,7 @@ ocx claude desktop import [--apply] 驗證並匯入 JSON | 旗標 | 動作 | | --- | --- | -| `--client ` | 必填。選擇客戶端設定格式。 | +| `--client ` | 必填。選擇客戶端設定格式。 | | `--json` | 僅在 stdout 印出設定 JSON,使重導向能擷取逐位元組輸出。所有診斷訊息(含 `--out` 寫入提示)皆送至 stderr。 | | `--out ` | 將設定寫入 ``。拒絕覆寫既有檔案。 | | `--force` | 允許 `--out` 覆寫既有檔案。 | @@ -177,6 +177,7 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `aside` | `~/.aside/u//models.json`,對應 Aside 自己的 `accounts.json` 指定的目前帳戶;資訊清單無法讀取時會被拒絕,而不是退回任一帳戶 | `aside-models.json` | 無——loopback 佔位符 | | `raycast` | `~/.config/raycast/ai/providers.yaml`(macOS 與 Windows 相同;Raycast 不遵循 `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | 無——僅限 loopback,不會寫入 `api_keys` 項目 | | `omo` | `~/.omo/agent/models.json`(設定後依序由 `OMO_CODING_AGENT_DIR`、`SENPI_CODING_AGENT_DIR`、`PI_CODING_AGENT_DIR` 優先;相對路徑會被拒絕) | `omo-models.json` | 無——loopback 佔位符 | +| `kilo` | `~/.config/kilo` 下最先存在的 `kilo.jsonc`、`kilo.json`、`opencode.jsonc`、`opencode.json` 或 `config.json` | `kilo.jsonc` | `OPENCODEX_KILO_API_KEY` | Raycast 匯出是一份獨立的 `providers.yaml` 文件,在 `providers` 序列中只有一個 `id: opencodex` 元素:`name: OpenCodex`、proxy 的 `/v1` base URL,以及每個路由模型及其 `abilities`(`tools` 與 `system_message` 一律支援,`vision` 依目錄的輸入模態而定,`reasoning_effort` 在模型有 effort 階梯時設定,`temperature` 對推理模型關閉)。Custom Providers 是 Raycast Pro 功能,且 Raycast 會監看該檔案,因此儲存後的變更不需重新啟動即可生效。格式說明見 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)。不會寫入任何 `api_keys` 項目,所以此匯出僅限 loopback,非 loopback 的 bind 會被拒絕。 diff --git a/gui/src/app-routing.ts b/gui/src/app-routing.ts index 3f7f107b8c1..86bd81aafc7 100644 --- a/gui/src/app-routing.ts +++ b/gui/src/app-routing.ts @@ -109,6 +109,7 @@ export const INTEGRATION_TAB_HASHES = [ "integrations/raycast", "integrations/omo", "integrations/cline", + "integrations/kilo", ] as const; /** diff --git a/gui/src/components/apikeys-workspace/client-config-clients.ts b/gui/src/components/apikeys-workspace/client-config-clients.ts index e164810fbb7..049d0d7cc39 100644 --- a/gui/src/components/apikeys-workspace/client-config-clients.ts +++ b/gui/src/components/apikeys-workspace/client-config-clients.ts @@ -8,7 +8,7 @@ * with EXPORT_CLIENT_IDS by hand; adding a client server-side renders no row * until this tuple changes. */ -export const CLIENTS = ["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline"] as const; +export const CLIENTS = ["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline", "kilo"] as const; export type ExportClientId = (typeof CLIENTS)[number]; export const CLIENT_LABEL_KEYS = { @@ -27,6 +27,7 @@ export const CLIENT_LABEL_KEYS = { raycast: "api.clientConfig.clientRaycast", omo: "api.clientConfig.clientOmo", cline: "api.clientConfig.clientCline", + kilo: "api.clientConfig.clientKilo", } as const; /** @@ -79,6 +80,7 @@ export const CLIENT_MARKS: Partial> = { // so it would paint the plate and throw the face away — see the README. omo: "/provider-icons/omo.svg", cline: "/provider-icons/cline-color.svg", + kilo: "/provider-icons/kilo.svg", }; /** diff --git a/gui/src/components/integration-marks.ts b/gui/src/components/integration-marks.ts index 58873cb1cb0..526c1b7041a 100644 --- a/gui/src/components/integration-marks.ts +++ b/gui/src/components/integration-marks.ts @@ -60,6 +60,7 @@ export const INTEGRATION_MARKS: Record = { raycast: CLIENT_MARKS.raycast ?? null, omo: CLIENT_MARKS.omo ?? null, cline: CLIENT_MARKS.cline ?? null, + kilo: CLIENT_MARKS.kilo ?? null, }; /** diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 65c50730417..0e8a00498a5 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -1412,6 +1412,7 @@ export const de: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Aside-Profile", "integrations.aside.profilesHint": "Wähle, welche Profile die ausgewählten Modelle erhalten. Das aktive Aside-Profil bleibt unverändert.", "integrations.aside.all": "Alle Profile synchronisieren", @@ -1620,6 +1621,7 @@ export const de: Record = { "integrations.semantics.raycast": "Fügt einen OpenCodex-Provider-Eintrag in die providers.yaml von Raycast ein, damit jedes geroutete Modell in der Modellauswahl von Raycast AI erscheint. Raycast Pro erforderlich.", "integrations.semantics.omo": "Verwaltet ausschließlich providers.opencodex in der models.json von omo — ~/.omo/agent, sofern nicht OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR oder PI_CODING_AGENT_DIR sie umleitet. Ihre übrigen Provider bleiben unverändert. Gilt ab neuen Sitzungen.", "integrations.semantics.cline": "Verwaltet OpenCodex in providers.json und models.json der Cline CLI. Beenden Sie Cline vor Änderungen oder Synchronisierung und starten Sie es danach neu. Rückgängig stellt beide Originaldateien wieder her. Ihr Standardanbieter bleibt unverändert; wählen Sie OpenCodex in Cline.", + "integrations.semantics.kilo": "Verwaltet nur provider.opencodex in Kilos globaler Konfiguration (erste vorhandene Datei unter kilo.jsonc, kilo.json, opencode.jsonc, opencode.json oder config.json in ~/.config/kilo). Andere Schlüssel bleiben unverändert. Anwenden schreibt die ganze Datei neu, daher bleiben Kommentare und nachgestellte Kommas nicht erhalten. Wählen Sie opencodex/ in Kilo.", "integrations.raycast.proRequired": "Custom Providers ist eine Funktion von Raycast Pro. Die Datei wird geschrieben, aber Raycast ignoriert sie, bis ein Pro-Abonnement aktiv ist.", "integrations.raycast.planUnknown": "Es konnte nicht festgestellt werden, ob Raycast Pro aktiv ist; Custom Providers erfordert Raycast Pro.", "integrations.raycast.revealConfig": "Öffnen Sie Raycast → Einstellungen → AI und klicken Sie einmal auf „Reveal Providers Config“, damit der Providers-Ordner existiert.", @@ -2114,6 +2116,7 @@ export const de: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "Dies ist ein Paket für zwei Dateien, keine Cline-Einstellungsdatei. Fügen Sie settings in providers.json und catalog in die benachbarte models.json ein. Der Integrationsschalter erstellt vor dem Schreiben ein Backup.", "api.clientConfig.clineDownloaded": "{filename} heruntergeladen. Noch nichts geändert; settings und catalog gehören in zwei separate Cline-Dateien.", "api.clientConfig.copy": "Konfiguration kopieren", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index ce4b09b4370..d68f613c0d7 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -1960,6 +1960,7 @@ export const en = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Aside profiles", "integrations.aside.profilesHint": "Choose which profiles receive the selected models. Aside’s active profile stays unchanged.", "integrations.aside.all": "Sync all profiles", @@ -2208,6 +2209,7 @@ export const en = { "integrations.semantics.raycast": "Adds an OpenCodex provider entry to Raycast's providers.yaml so every routed model appears in the Raycast AI model picker. Raycast Pro required.", "integrations.semantics.omo": "Manages only providers.opencodex in omo's models.json — ~/.omo/agent unless OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR or PI_CODING_AGENT_DIR redirects it. Your other providers stay unchanged. Applies to new sessions.", "integrations.semantics.cline": "Manages OpenCodex in Cline CLI providers.json and models.json. Stop Cline before changing or syncing these files, then restart. Undo restores both originals. Your default provider stays unchanged; select OpenCodex in Cline.", + "integrations.semantics.kilo": "Manages only provider.opencodex in Kilo's global config (first existing kilo.jsonc, kilo.json, opencode.jsonc, opencode.json, or config.json under ~/.config/kilo). Other keys stay unchanged. Apply rewrites the whole file, so comments and trailing commas are not preserved. Select opencodex/ in Kilo.", "integrations.raycast.proRequired": "Custom Providers is a Raycast Pro feature. The file will be written, but Raycast ignores it until a Pro subscription is active.", "integrations.raycast.planUnknown": "Could not determine whether Raycast Pro is active; Custom Providers requires Raycast Pro.", "integrations.raycast.revealConfig": "Open Raycast → Settings → AI and click Reveal Providers Config once so the providers folder exists.", @@ -2713,6 +2715,7 @@ export const en = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "This is a two-file bundle, not a Cline settings file. Merge settings into providers.json and catalog into sibling models.json. Use the integration switch for a backed-up write.", "api.clientConfig.clineDownloaded": "Downloaded {filename}. Nothing changed yet; settings and catalog belong in two separate Cline files.", "api.clientConfig.copy": "Copy config", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index f600d6ef38a..1cc84f4965f 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -1932,6 +1932,7 @@ export const fr: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Profils Aside", "integrations.aside.profilesHint": "Choisissez les profils qui recevront les modèles sélectionnés. Le profil actif dans Aside reste inchangé.", "integrations.aside.all": "Synchroniser tous les profils", @@ -2140,6 +2141,7 @@ export const fr: Record = { "integrations.semantics.raycast": "Ajoute une entrée de fournisseur OpenCodex dans le providers.yaml de Raycast afin que chaque modèle routé apparaisse dans le sélecteur de modèles de Raycast AI. Raycast Pro requis.", "integrations.semantics.omo": "Gère uniquement providers.opencodex dans le models.json d'omo — ~/.omo/agent, sauf redirection par OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR ou PI_CODING_AGENT_DIR. Vos autres fournisseurs restent inchangés. S'applique aux nouvelles sessions.", "integrations.semantics.cline": "Gère OpenCodex dans providers.json et models.json de Cline CLI. Quittez Cline avant toute modification ou synchronisation, puis redémarrez-le. Annuler restaure les deux fichiers originaux. Votre fournisseur par défaut reste inchangé ; sélectionnez OpenCodex dans Cline.", + "integrations.semantics.kilo": "Gère uniquement provider.opencodex dans la configuration globale de Kilo (premier fichier existant parmi kilo.jsonc, kilo.json, opencode.jsonc, opencode.json ou config.json sous ~/.config/kilo). Les autres clés restent inchangées. Appliquer réécrit tout le fichier : commentaires et virgules finales ne sont pas conservés. Sélectionnez opencodex/ dans Kilo.", "integrations.raycast.proRequired": "Custom Providers est une fonctionnalité Raycast Pro. Le fichier sera écrit, mais Raycast l'ignore tant qu'un abonnement Pro n'est pas actif.", "integrations.raycast.planUnknown": "Impossible de déterminer si Raycast Pro est actif ; Custom Providers nécessite Raycast Pro.", "integrations.raycast.revealConfig": "Ouvrez Raycast → Réglages → AI et cliquez une fois sur « Reveal Providers Config » pour que le dossier des fournisseurs existe.", @@ -2634,6 +2636,7 @@ export const fr: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "Ce paquet contient deux fichiers, pas un fichier de paramètres Cline. Fusionnez settings dans providers.json et catalog dans models.json du même dossier. Utilisez le commutateur d’intégration pour sauvegarder avant l’écriture.", "api.clientConfig.clineDownloaded": "{filename} téléchargé. Rien n’a changé ; settings et catalog vont dans deux fichiers Cline distincts.", "api.clientConfig.copy": "Copier la configuration", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 6a979cd7836..4381c6f0434 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -1855,6 +1855,7 @@ export const ja: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Asideのプロファイル", "integrations.aside.profilesHint": "選択したモデルを同期するプロファイルを選んでください。Asideで使用中のプロファイルは変わりません。", "integrations.aside.all": "すべてのプロファイルを同期", @@ -2063,6 +2064,7 @@ export const ja: Record = { "integrations.semantics.raycast": "Raycast の providers.yaml に OpenCodex のプロバイダーエントリを追加し、ルーティングされたすべてのモデルを Raycast AI のモデル選択に表示します。Raycast Pro が必要です。", "integrations.semantics.omo": "omo の models.json にある providers.opencodex のみを管理します。場所は ~/.omo/agent で、OMO_CODING_AGENT_DIR・SENPI_CODING_AGENT_DIR・PI_CODING_AGENT_DIR のいずれかが設定されている場合はそちらが優先されます。他のプロバイダーは変更しません。新しいセッションから適用されます。", "integrations.semantics.cline": "Cline CLI の providers.json と models.json の OpenCodex 項目を管理します。変更・同期前に Cline を終了し、完了後に再起動してください。元に戻すと両方の元ファイルが復元されます。既定のプロバイダーは変わりません。Cline で OpenCodex を選択してください。", + "integrations.semantics.kilo": "Kilo のグローバル設定(~/.config/kilo 配下で最初に存在する kilo.jsonc、kilo.json、opencode.jsonc、opencode.json、config.json)の provider.opencodex のみを管理します。他のキーは変更しません。適用時にファイル全体を書き直すため、コメントと末尾カンマは保持されません。Kilo で opencodex/<モデル> を選択してください。", "integrations.raycast.proRequired": "Custom Providers は Raycast Pro の機能です。ファイルは書き込まれますが、Pro サブスクリプションが有効になるまで Raycast はこれを無視します。", "integrations.raycast.planUnknown": "Raycast Pro が有効かどうか確認できませんでした。Custom Providers には Raycast Pro が必要です。", "integrations.raycast.revealConfig": "Raycast → 設定 → AI を開き、「Reveal Providers Config」を一度クリックして providers フォルダを作成してください。", @@ -2563,6 +2565,7 @@ export const ja: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "これは Cline 設定ファイルではなく、2 ファイル分のデータです。settings を providers.json に、catalog を隣の models.json にマージしてください。バックアップ付きの書き込みには統合スイッチを使ってください。", "api.clientConfig.clineDownloaded": "{filename} をダウンロードしました。設定はまだ変わっていません。settings と catalog は別々の Cline ファイルに保存します。", "api.clientConfig.copy": "設定をコピー", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index e99ab00cade..1ec06eef3db 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -1448,6 +1448,7 @@ export const ko: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Aside 프로필", "integrations.aside.profilesHint": "선택한 모델을 동기화할 프로필을 고르세요. Aside에서 사용 중인 프로필은 바뀌지 않습니다.", "integrations.aside.all": "모든 프로필 동기화", @@ -1656,6 +1657,7 @@ export const ko: Record = { "integrations.semantics.raycast": "Raycast의 providers.yaml에 OpenCodex 프로바이더 항목을 추가해 라우팅된 모든 모델이 Raycast AI 모델 선택기에 표시되도록 합니다. Raycast Pro가 필요합니다.", "integrations.semantics.omo": "omo의 models.json에서 providers.opencodex만 관리합니다. 위치는 ~/.omo/agent이며 OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR, PI_CODING_AGENT_DIR 중 설정된 값이 있으면 그쪽이 우선합니다. 다른 프로바이더는 그대로 유지됩니다. 새 세션부터 적용됩니다.", "integrations.semantics.cline": "Cline CLI의 providers.json과 models.json에서 OpenCodex 항목을 관리합니다. 변경·동기화 전에 Cline을 종료하고 완료 후 다시 실행하세요. 되돌리기는 두 파일의 원본을 복원합니다. 기본 프로바이더는 유지되므로 Cline에서 OpenCodex를 선택하세요.", + "integrations.semantics.kilo": "Kilo 전역 설정(~/.config/kilo에서 먼저 존재하는 kilo.jsonc, kilo.json, opencode.jsonc, opencode.json, config.json)의 provider.opencodex만 관리합니다. 다른 키는 그대로 둡니다. 적용 시 파일 전체를 다시 쓰므로 주석과 후행 쉼표는 보존되지 않습니다. Kilo에서 opencodex/<모델>을 선택하세요.", "integrations.raycast.proRequired": "Custom Providers는 Raycast Pro 기능입니다. 파일은 기록되지만 Pro 구독이 활성화될 때까지 Raycast는 이를 무시합니다.", "integrations.raycast.planUnknown": "Raycast Pro 활성 여부를 확인할 수 없습니다. Custom Providers에는 Raycast Pro가 필요합니다.", "integrations.raycast.revealConfig": "Raycast → 설정 → AI를 열고 「Reveal Providers Config」를 한 번 클릭해 providers 폴더를 만드세요.", @@ -2153,6 +2155,7 @@ export const ko: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "이 묶음은 Cline 설정 파일 자체가 아닙니다. settings는 providers.json에, catalog는 옆의 models.json에 병합하세요. 백업을 남기려면 통합 스위치를 사용하세요.", "api.clientConfig.clineDownloaded": "{filename}을 다운로드했습니다. 아직 설정은 바뀌지 않았습니다. settings와 catalog는 서로 다른 Cline 파일에 넣어야 합니다.", "api.clientConfig.copy": "설정 복사", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index f6f24178696..2368a18005f 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -1927,6 +1927,7 @@ export const ru: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Профили Aside", "integrations.aside.profilesHint": "Выберите профили, в которые будут добавлены выбранные модели. Активный профиль Aside не изменится.", "integrations.aside.all": "Синхронизировать все профили", @@ -2135,6 +2136,7 @@ export const ru: Record = { "integrations.semantics.raycast": "Добавляет запись провайдера OpenCodex в providers.yaml Raycast, чтобы каждая маршрутизируемая модель появилась в выборе моделей Raycast AI. Требуется Raycast Pro.", "integrations.semantics.omo": "Управляет только providers.opencodex в models.json omo — ~/.omo/agent, если только OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR или PI_CODING_AGENT_DIR не перенаправляет путь. Остальные провайдеры остаются без изменений. Применяется к новым сессиям.", "integrations.semantics.cline": "Управляет OpenCodex в файлах providers.json и models.json Cline CLI. Закройте Cline перед изменением или синхронизацией и запустите снова после завершения. Отмена восстанавливает оба исходных файла. Провайдер по умолчанию не меняется; выберите OpenCodex в Cline.", + "integrations.semantics.kilo": "Управляет только provider.opencodex в глобальной конфигурации Kilo (первый существующий файл среди kilo.jsonc, kilo.json, opencode.jsonc, opencode.json или config.json в ~/.config/kilo). Остальные ключи не меняются. Применение перезаписывает весь файл, поэтому комментарии и завершающие запятые не сохраняются. Выберите opencodex/<модель> в Kilo.", "integrations.raycast.proRequired": "Custom Providers — функция Raycast Pro. Файл будет записан, но Raycast игнорирует его, пока не активна подписка Pro.", "integrations.raycast.planUnknown": "Не удалось определить, активен ли Raycast Pro; для Custom Providers требуется Raycast Pro.", "integrations.raycast.revealConfig": "Откройте Raycast → Настройки → AI и один раз нажмите «Reveal Providers Config», чтобы папка провайдеров появилась.", @@ -2634,6 +2636,7 @@ export const ru: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "Это пакет для двух файлов, а не файл настроек Cline. Объедините settings с providers.json, а catalog — с models.json в той же папке. Переключатель интеграции создаёт резервную копию перед записью.", "api.clientConfig.clineDownloaded": "Файл {filename} загружен. Настройки ещё не изменены; settings и catalog предназначены для двух отдельных файлов Cline.", "api.clientConfig.copy": "Копировать конфигурацию", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 71e82d9b404..1927eb25148 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -1946,6 +1946,7 @@ export const tr: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Aside profilleri", "integrations.aside.profilesHint": "Seçili modellerin hangi profillere aktarılacağını seçin. Aside’ın etkin profili değişmez.", "integrations.aside.all": "Tüm profilleri eşitle", @@ -2153,6 +2154,7 @@ export const tr: Record = { "integrations.semantics.raycast": "Raycast'in providers.yaml dosyasına bir OpenCodex sağlayıcı girdisi ekler; böylece yönlendirilen her model Raycast AI model seçicisinde görünür. Raycast Pro gerekir.", "integrations.semantics.omo": "Yalnızca omo'nun models.json dosyasındaki providers.opencodex girdisini yönetir — OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR veya PI_CODING_AGENT_DIR yönlendirmediği sürece ~/.omo/agent. Diğer sağlayıcılarınız değişmeden kalır. Yeni oturumlardan itibaren geçerlidir.", "integrations.semantics.cline": "Cline CLI providers.json ve models.json dosyalarındaki OpenCodex girdilerini yönetir. Değişiklik veya eşitleme öncesinde Cline’ı kapatın, ardından yeniden başlatın. Geri al iki özgün dosyayı da geri yükler. Varsayılan sağlayıcınız değişmez; Cline içinde OpenCodex’i seçin.", + "integrations.semantics.kilo": "Yalnızca Kilo’nun genel yapılandırmasındaki ( ~/.config/kilo altında ilk bulunan kilo.jsonc, kilo.json, opencode.jsonc, opencode.json veya config.json) provider.opencodex öğesini yönetir. Diğer anahtarlar değişmez. Uygula dosyanın tamamını yeniden yazar; yorumlar ve sondaki virgüller korunmaz. Kilo’da opencodex/ seçin.", "integrations.raycast.proRequired": "Custom Providers bir Raycast Pro özelliğidir. Dosya yazılır, ancak bir Pro aboneliği etkin olana kadar Raycast bunu yok sayar.", "integrations.raycast.planUnknown": "Raycast Pro’nun etkin olup olmadığı belirlenemedi; Custom Providers için Raycast Pro gerekir.", "integrations.raycast.revealConfig": "Raycast → Ayarlar → AI bölümünü açıp sağlayıcı klasörünün oluşması için „Reveal Providers Config“ seçeneğine bir kez tıklayın.", @@ -2653,6 +2655,7 @@ export const tr: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "Bu, bir Cline ayar dosyası değil, iki dosyalık bir pakettir. settings içeriğini providers.json, catalog içeriğini aynı klasördeki models.json ile birleştirin. Yazmadan önce yedek almak için entegrasyon anahtarını kullanın.", "api.clientConfig.clineDownloaded": "{filename} indirildi. Henüz değişiklik yapılmadı; settings ve catalog ayrı Cline dosyalarına aittir.", "api.clientConfig.copy": "JSON Kopyala", diff --git a/gui/src/i18n/vi.ts b/gui/src/i18n/vi.ts index 151c3da8578..a18adfab605 100644 --- a/gui/src/i18n/vi.ts +++ b/gui/src/i18n/vi.ts @@ -1915,6 +1915,7 @@ export const vi: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Cấu hình Aside", "integrations.aside.profilesHint": "Chọn profile nào sẽ nhận các model được chọn. Profile đang hoạt động của Aside sẽ được giữ nguyên.", "integrations.aside.all": "Đồng bộ tất cả profile", @@ -2163,6 +2164,7 @@ export const vi: Record = { "integrations.semantics.raycast": "Thêm một provider OpenCodex vào providers.yaml của Raycast để mọi model được định tuyến xuất hiện trong bộ chọn model AI của Raycast. Yêu cầu Raycast Pro.", "integrations.semantics.omo": "Chỉ quản lý providers.opencodex trong models.json của omo — ~/.omo/agent, trừ khi OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR hoặc PI_CODING_AGENT_DIR chuyển hướng. Các nhà cung cấp khác của bạn không thay đổi. Áp dụng cho phiên mới.", "integrations.semantics.cline": "Quản lý OpenCodex trong providers.json và models.json của Cline CLI. Hãy dừng Cline trước khi thay đổi hoặc đồng bộ các tệp này, rồi khởi động lại. Hoàn tác sẽ khôi phục cả hai bản gốc. Nhà cung cấp mặc định của bạn không thay đổi; hãy chọn OpenCodex trong Cline.", + "integrations.semantics.kilo": "Chỉ quản lý provider.opencodex trong cấu hình toàn cục của Kilo (tệp tồn tại đầu tiên trong kilo.jsonc, kilo.json, opencode.jsonc, opencode.json hoặc config.json dưới ~/.config/kilo). Các khóa khác giữ nguyên. Áp dụng ghi lại toàn bộ tệp nên chú thích và dấu phẩy cuối không được giữ. Chọn opencodex/ trong Kilo.", "integrations.raycast.proRequired": "Custom Providers là một tính năng của Raycast Pro. File sẽ được ghi, nhưng Raycast sẽ bỏ qua nó cho đến khi đăng ký Pro được kích hoạt.", "integrations.raycast.planUnknown": "Không thể xác định xem Raycast Pro có đang hoạt động hay không; Custom Providers yêu cầu Raycast Pro.", "integrations.raycast.revealConfig": "Mở Raycast → Settings → AI và nhấp vào Reveal Providers Config một lần để thư mục providers được tạo.", @@ -2647,6 +2649,7 @@ export const vi: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "Đây là gói gồm hai tệp, không phải tệp cài đặt Cline. Hãy hợp nhất cài đặt vào providers.json và catalog vào models.json cùng cấp. Dùng công tắc tích hợp để ghi kèm bản sao lưu.", "api.clientConfig.clineDownloaded": "Đã tải xuống {filename}. Chưa có gì thay đổi; cài đặt và catalog thuộc hai tệp Cline riêng biệt.", "api.clientConfig.copy": "Sao chép cấu hình", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index f1ac8003519..9016b3d0945 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2734,6 +2734,7 @@ export const zhTW: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Aside 設定檔", "integrations.aside.profilesHint": "選擇要接收所選模型的設定檔。Aside 目前使用的設定檔不會改變。", "integrations.aside.all": "同步所有設定檔", @@ -2942,6 +2943,7 @@ export const zhTW: Record = { "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中新增一個 OpenCodex 供應商項目,讓所有已路由的模型出現在 Raycast AI 模型選擇器中。需要 Raycast Pro。", "integrations.semantics.omo": "僅管理 omo 的 models.json 中的 providers.opencodex,路徑為 ~/.omo/agent,若設定了 OMO_CODING_AGENT_DIR、SENPI_CODING_AGENT_DIR 或 PI_CODING_AGENT_DIR 則以其為準。你的其他供應商維持不變。對新工作階段生效。", "integrations.semantics.cline": "管理 Cline CLI 的 providers.json 和 models.json 中的 OpenCodex 項目。修改或同步前請結束 Cline,完成後重新啟動。復原會還原兩個檔案的原始內容。預設供應商保持不變,請在 Cline 中選擇 OpenCodex。", + "integrations.semantics.kilo": "僅管理 Kilo 全域設定(~/.config/kilo 下最先存在的 kilo.jsonc、kilo.json、opencode.jsonc、opencode.json 或 config.json)中的 provider.opencodex。其他鍵保持不變。套用會重寫整個檔案,因此不會保留註解與尾隨逗號。請在 Kilo 中選擇 opencodex/<模型>。", "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。檔案會被寫入,但在 Pro 訂閱生效之前 Raycast 會忽略它。", "integrations.raycast.planUnknown": "無法確認 Raycast Pro 是否已啟用;Custom Providers 需要 Raycast Pro。", "integrations.raycast.revealConfig": "開啟 Raycast → 設定 → AI,點一次「Reveal Providers Config」,以便建立 providers 資料夾。", @@ -2995,6 +2997,7 @@ export const zhTW: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "這是兩個檔案的資料包,不是 Cline 設定檔。將 settings 合併至 providers.json,將 catalog 合併至同目錄的 models.json。使用整合開關可在寫入前備份。", "api.clientConfig.clineDownloaded": "已下載 {filename},設定尚未變更。settings 與 catalog 應分別儲存至兩個 Cline 檔案。", "cws.tabsLabel": "Combo 詳細區段", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 33b48c1a11d..afd7a514886 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -1429,6 +1429,7 @@ export const zh: Record = { "integrations.tab.raycast": "Raycast", "integrations.tab.omo": "omo", "integrations.tab.cline": "Cline CLI", + "integrations.tab.kilo": "Kilo", "integrations.aside.profilesTitle": "Aside 配置文件", "integrations.aside.profilesHint": "选择要接收所选模型的配置文件。Aside 当前使用的配置文件不会改变。", "integrations.aside.all": "同步所有配置文件", @@ -1637,6 +1638,7 @@ export const zh: Record = { "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中添加一个 OpenCodex 提供商条目,让所有已路由的模型出现在 Raycast AI 模型选择器中。需要 Raycast Pro。", "integrations.semantics.omo": "仅管理 omo 的 models.json 中的 providers.opencodex,路径为 ~/.omo/agent,若设置了 OMO_CODING_AGENT_DIR、SENPI_CODING_AGENT_DIR 或 PI_CODING_AGENT_DIR 则以其为准。你的其他提供商保持不变。对新会话生效。", "integrations.semantics.cline": "管理 Cline CLI 的 providers.json 和 models.json 中的 OpenCodex 项目。修改或同步前请退出 Cline,完成后重新启动。撤销会恢复两个文件的原始内容。默认提供商保持不变,请在 Cline 中选择 OpenCodex。", + "integrations.semantics.kilo": "仅管理 Kilo 全局配置(~/.config/kilo 下最先存在的 kilo.jsonc、kilo.json、opencode.jsonc、opencode.json 或 config.json)中的 provider.opencodex。其他键保持不变。应用会重写整个文件,因此不会保留注释和尾随逗号。请在 Kilo 中选择 opencodex/<模型>。", "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。文件会被写入,但在 Pro 订阅生效之前 Raycast 会忽略它。", "integrations.raycast.planUnknown": "无法确定 Raycast Pro 是否已激活;Custom Providers 需要 Raycast Pro。", "integrations.raycast.revealConfig": "打开 Raycast → 设置 → AI,点击一次“Reveal Providers Config”,以便创建 providers 文件夹。", @@ -2134,6 +2136,7 @@ export const zh: Record = { "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.clientOmo": "omo", "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clientKilo": "Kilo", "api.clientConfig.clineBundle": "这是两个文件的数据包,不是 Cline 设置文件。将 settings 合并到 providers.json,将 catalog 合并到同目录的 models.json。使用集成开关可在写入前备份。", "api.clientConfig.clineDownloaded": "已下载 {filename},设置尚未更改。settings 和 catalog 应分别保存到两个 Cline 文件。", "api.clientConfig.copy": "复制配置", diff --git a/gui/src/pages/integrations/FileIntegrationPage.tsx b/gui/src/pages/integrations/FileIntegrationPage.tsx index b8806d563df..a24e1e978cb 100644 --- a/gui/src/pages/integrations/FileIntegrationPage.tsx +++ b/gui/src/pages/integrations/FileIntegrationPage.tsx @@ -83,6 +83,7 @@ const SEMANTICS_KEY: Record = { raycast: "integrations.semantics.raycast", omo: "integrations.semantics.omo", cline: "integrations.semantics.cline", + kilo: "integrations.semantics.kilo", }; const TAB_LABEL_KEY: Record = { @@ -101,6 +102,7 @@ const TAB_LABEL_KEY: Record = { raycast: "integrations.tab.raycast", omo: "integrations.tab.omo", cline: "integrations.tab.cline", + kilo: "integrations.tab.kilo", }; export default function FileIntegrationPage({ diff --git a/gui/src/pages/integrations/integration-api.ts b/gui/src/pages/integrations/integration-api.ts index 02733e095ce..dda62381bba 100644 --- a/gui/src/pages/integrations/integration-api.ts +++ b/gui/src/pages/integrations/integration-api.ts @@ -17,6 +17,7 @@ export const FILE_INTEGRATION_CLIENTS = [ "raycast", "omo", "cline", + "kilo", ] as const; export type FileIntegrationClientId = (typeof FILE_INTEGRATION_CLIENTS)[number]; diff --git a/gui/src/pages/integrations/integration-tabs.ts b/gui/src/pages/integrations/integration-tabs.ts index a1810763ddb..d9e9aa71dd1 100644 --- a/gui/src/pages/integrations/integration-tabs.ts +++ b/gui/src/pages/integrations/integration-tabs.ts @@ -49,6 +49,7 @@ export const TABS: readonly TabDefinition[] = [ { id: "raycast", hash: "integrations/raycast", labelKey: "integrations.tab.raycast" }, { id: "omo", hash: "integrations/omo", labelKey: "integrations.tab.omo" }, { id: "cline", hash: "integrations/cline", labelKey: "integrations.tab.cline" }, + { id: "kilo", hash: "integrations/kilo", labelKey: "integrations.tab.kilo" }, ] as const; export const FILE_CLIENTS = new Set([ @@ -67,4 +68,5 @@ export const FILE_CLIENTS = new Set([ "raycast", "omo", "cline", + "kilo", ]); diff --git a/gui/src/pages/integrations/overview-clients.ts b/gui/src/pages/integrations/overview-clients.ts index d54d99d0057..e11cc9c4637 100644 --- a/gui/src/pages/integrations/overview-clients.ts +++ b/gui/src/pages/integrations/overview-clients.ts @@ -155,6 +155,7 @@ const FILE_LABEL_KEY: Record = { raycast: "integrations.tab.raycast", omo: "integrations.tab.omo", cline: "integrations.tab.cline", + kilo: "integrations.tab.kilo", }; /** A file client's block is in the file for both `current` and `stale`. */ diff --git a/gui/tests/client-config-panel.test.tsx b/gui/tests/client-config-panel.test.tsx index dffaf4d0994..a1d9b2276a0 100644 --- a/gui/tests/client-config-panel.test.tsx +++ b/gui/tests/client-config-panel.test.tsx @@ -171,7 +171,7 @@ function rowButton(container: HTMLElement, name: string, label: string): HTMLBut } test("the API download surface includes DSH, MiniMax Code, Aside, Raycast and omo as clients", () => { - expect(CLIENTS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline"]); + expect(CLIENTS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline", "kilo"]); expect(CLIENT_LABEL_KEYS.dsh).toBe("api.clientConfig.clientDsh"); expect(CLIENT_LABEL_KEYS.mcode).toBe("api.clientConfig.clientMcode"); expect(CLIENT_LABEL_KEYS.zcode).toBe("api.clientConfig.clientZcode"); diff --git a/gui/tests/fr-localization.test.ts b/gui/tests/fr-localization.test.ts index 9baa172e2ec..502e5303808 100644 --- a/gui/tests/fr-localization.test.ts +++ b/gui/tests/fr-localization.test.ts @@ -146,6 +146,8 @@ const INTENTIONAL_ENGLISH = new Set([ // Cline product name and CLI acronym are intentionally preserved. "integrations.tab.cline", "api.clientConfig.clientCline", + "integrations.tab.kilo", + "api.clientConfig.clientKilo", "models.reasoningEffort.minimal", "models.reasoningEffort.max", "models.reasoningEffort.ultra", diff --git a/gui/tests/integrations-api.test.ts b/gui/tests/integrations-api.test.ts index 17599aa4998..0e9c598e55c 100644 --- a/gui/tests/integrations-api.test.ts +++ b/gui/tests/integrations-api.test.ts @@ -21,7 +21,7 @@ const originalFetch = globalThis.fetch; test("all registered export clients include Cline in file integrations", () => { expect(FILE_INTEGRATION_CLIENTS).toEqual([ - "opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline", + "opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline", "kilo", ]); }); diff --git a/gui/tests/integrations-overview-rows.test.ts b/gui/tests/integrations-overview-rows.test.ts index 4e44e8d674b..07abdab1220 100644 --- a/gui/tests/integrations-overview-rows.test.ts +++ b/gui/tests/integrations-overview-rows.test.ts @@ -290,8 +290,9 @@ test("every client counts toward the summary, not just the file clients", () => test("an unsettled file list renders unknown rows instead of dropping them", () => { const built = buildOverviewRows(sources({ clients: [], clientsSettled: false })); - expect(built.rows).toHaveLength(20); + expect(built.rows).toHaveLength(21); expect(rowById(built, "cline")).toMatchObject({ hash: "integrations/cline", labelKey: "integrations.tab.cline", state: "unknown" }); + expect(rowById(built, "kilo")).toMatchObject({ hash: "integrations/kilo", labelKey: "integrations.tab.kilo", state: "unknown" }); expect(rowById(built, "omp").state).toBe("unknown"); expect(rowById(built, "mcode").state).toBe("unknown"); expect(rowById(built, "zcode").state).toBe("unknown"); diff --git a/gui/tests/locale-parity.test.ts b/gui/tests/locale-parity.test.ts index 44508dd9dd0..60f45e7dcfd 100644 --- a/gui/tests/locale-parity.test.ts +++ b/gui/tests/locale-parity.test.ts @@ -161,6 +161,8 @@ const ZH_TW_KEEP_ENGLISH: ReadonlySet = new Set([ // Cline product name and CLI acronym are intentionally preserved. "integrations.tab.cline", "api.clientConfig.clientCline", + "integrations.tab.kilo", + "api.clientConfig.clientKilo", "integrations.codex.title", // Provider proper nouns kept in English "provider.name.commandCodeAuth", diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index 404f6269668..7cdf7d061d5 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -1069,6 +1069,7 @@ "jev-decision.test.ts": "routing", "jev-provider.test.ts": "providers", "keyring-smoke.test.ts": "ci-workflows", + "kilo-client.test.ts": "clients", "kimi-oauth-identity.test.ts": "providers", "kimi-responses-adjacency.test.ts": "providers", "kiro-account-load.test.ts": "providers/kiro", diff --git a/src/cli/export-command.ts b/src/cli/export-command.ts index 21d62f59c77..3831e6b8c53 100644 --- a/src/cli/export-command.ts +++ b/src/cli/export-command.ts @@ -1,8 +1,8 @@ /** * `ocx export --client ` — print a client config for the live proxy. * - * Fourteen clients, five formats. The accepted list is `EXPORT_CLIENT_IDS`, not - * this comment: OpenCode, Pi, Prime, Aside, ZCode and omo are JSON; OMP, + * Sixteen clients, five formats. The accepted list is `EXPORT_CLIENT_IDS`, not + * this comment: OpenCode, Pi, Prime, Aside, ZCode, omo and Kilo are JSON; OMP, * Hermes, gjc, DSH, MiniMax Code and Raycast are YAML; OpenClaw is JSON5; Kimi * is TOML. * diff --git a/src/cli/help.ts b/src/cli/help.ts index 967e431add0..86bf33a681f 100644 --- a/src/cli/help.ts +++ b/src/cli/help.ts @@ -83,7 +83,7 @@ Usage: ocx api-key Alias of ocx access key ocx access External API keys and endpoint information ocx api Protocol paths: vocabulary, request-path preview, and policy - ocx export --client Print a client config wired to the running proxy (15 clients) + ocx export --client Print a client config wired to the running proxy (16 clients) ocx integration client Enable, disable, inspect or roll back a client integration ocx grok Grok Build model selection and apply ocx system Runtime settings, startup, sync, OpenCodex updates, and Codex CLI inspection diff --git a/src/cli/opencode.ts b/src/cli/opencode.ts index d70bf56302c..7b6fe1d14b5 100644 --- a/src/cli/opencode.ts +++ b/src/cli/opencode.ts @@ -51,6 +51,8 @@ import type { OcxConfig } from "../types"; import { withProcessRuntimeProvenance } from "../lib/bun-runtime"; import { selfLaunchArgv } from "../lib/self-launch-argv"; import { withoutSiblingMarker } from "../codex/sibling-start"; +import { parseJsonc } from "../lib/jsonc"; +export { parseJsonc }; /** * The provider-block serializer, its constants, and the config-path helpers now live in @@ -124,89 +126,6 @@ function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } -/** - * Strip `//` and block comments outside string literals. Escape-aware so a quote inside - * an escaped sequence cannot flip string state and expose config text to the stripper. - */ -function stripJsonComments(text: string): string { - let out = ""; - let inString = false; - let inLine = false; - let inBlock = false; - for (let i = 0; i < text.length; i++) { - const ch = text[i]!; - const next = text[i + 1]; - if (inLine) { - if (ch === "\n") { - inLine = false; - out += ch; - } - continue; - } - if (inBlock) { - // Newlines are preserved so JSON.parse error positions stay meaningful. - if (ch === "\n") out += ch; - else if (ch === "*" && next === "/") { inBlock = false; i++; } - continue; - } - if (inString) { - out += ch; - if (ch === "\\") { - const escaped = text[i + 1]; - if (escaped !== undefined) { out += escaped; i++; } - continue; - } - if (ch === "\"") inString = false; - continue; - } - if (ch === "\"") { inString = true; out += ch; continue; } - if (ch === "/" && next === "/") { inLine = true; i++; continue; } - if (ch === "/" && next === "*") { inBlock = true; i++; continue; } - out += ch; - } - return out; -} - -/** Drop commas that sit directly before `}` or `]`, ignoring string contents. */ -function stripTrailingCommas(text: string): string { - let out = ""; - let inString = false; - for (let i = 0; i < text.length; i++) { - const ch = text[i]!; - if (inString) { - out += ch; - if (ch === "\\") { - const escaped = text[i + 1]; - if (escaped !== undefined) { out += escaped; i++; } - continue; - } - if (ch === "\"") inString = false; - continue; - } - if (ch === "\"") { inString = true; out += ch; continue; } - if (ch === ",") { - let j = i + 1; - while (j < text.length && /\s/.test(text[j]!)) j++; - if (text[j] === "}" || text[j] === "]") continue; - } - out += ch; - } - return out; -} - -/** - * opencode documents opencode.json as JSONC, so a valid user config may carry comments - * or trailing commas. Strict JSON.parse runs first and untouched — the tolerant path is - * only attempted when that throws, keeping well-formed configs away from the stripper. - */ -export function parseJsonc(text: string): unknown { - try { - return JSON.parse(text); - } catch { - return JSON.parse(stripTrailingCommas(stripJsonComments(text))); - } -} - /** Model key as the proxy routes it: `provider/id` for routed models, bare slug for native OpenAI entries. */ export function opencodeModelKey(provider: string, id: string): string { return provider === "native" ? id : `${provider}/${id}`; diff --git a/src/cli/registry.ts b/src/cli/registry.ts index 214baa31a25..ace37100128 100644 --- a/src/cli/registry.ts +++ b/src/cli/registry.ts @@ -416,8 +416,8 @@ export const CLI_COMMANDS: CliCommandEntry[] = [ }, { name: "export", - usage: "ocx export --client [--json] [--out ] [--force]", - summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast, omo, Cline) wired to the running proxy.", + usage: "ocx export --client [--json] [--out ] [--force]", + summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast, omo, Cline, Kilo) wired to the running proxy.", details: [ "--json prints the generated document as JSON on stdout; use --out for the client's native format.", "--out writes the native config there and refuses to replace an existing file without --force.", diff --git a/src/clients/config-export.ts b/src/clients/config-export.ts index 36de2d58225..bcc3e3893ae 100644 --- a/src/clients/config-export.ts +++ b/src/clients/config-export.ts @@ -31,7 +31,7 @@ import type { OcxConfig } from "../types"; export type { ConfigFormat } from "../integrations/serialize"; export type { ManagedFragment, ManagedContribution, BuildContribution, OpencodeLaunchEnv, OpencodeCatalogModel, ExportModel, ExportContext, ExportClientId, ExportClientSpec, PiModelEntry } from "./config-export/contracts"; -export { OPENCODE_PROVIDER_ID, OPENCODE_CONFIG_SCHEMA, OPENCODE_API_KEY_ENV, OPENCODE_API_KEY_ENV_REF, HERMES_API_KEY_ENV, HERMES_API_KEY_ENV_REF, OPENCLAW_API_KEY_ENV, OPENCLAW_API_KEY_ENV_REF, LOOPBACK_API_KEY_PLACEHOLDER, GAJAE_API_KEY_ENV, SCHEMA_REQUIRED_OUTPUT_BUDGET, OPENCODE_PROVIDER_BLOCK_DEFAULT_CONFIG } from "./config-export/constants"; +export { OPENCODE_PROVIDER_ID, OPENCODE_CONFIG_SCHEMA, OPENCODE_API_KEY_ENV, OPENCODE_API_KEY_ENV_REF, KILO_API_KEY_ENV, KILO_API_KEY_ENV_REF, KILO_CONFIG_SCHEMA, HERMES_API_KEY_ENV, HERMES_API_KEY_ENV_REF, OPENCLAW_API_KEY_ENV, OPENCLAW_API_KEY_ENV_REF, LOOPBACK_API_KEY_PLACEHOLDER, GAJAE_API_KEY_ENV, SCHEMA_REQUIRED_OUTPUT_BUDGET, OPENCODE_PROVIDER_BLOCK_DEFAULT_CONFIG } from "./config-export/constants"; export { normalizeExportModels } from "./config-export/model-metadata"; export type { OmpModelEntry, OmpProviderBlock, OmpGeneratedConfig } from "./config-export/omp"; export type { ZcodeModelEntry, ZcodeProviderBlock, ZcodeGeneratedConfig } from "./config-export/zcode"; @@ -53,7 +53,7 @@ export type { RaycastAbility, RaycastAbilityName, RaycastModelEntry, RaycastProv export { buildRaycastClientConfig, summarizeRaycast, buildRaycastContribution } from "./config-export/raycast"; import type { OpencodeLaunchEnv, OpencodeCatalogModel, ExportContext, PiModelEntry, ManagedContribution, ManagedFragment, ExportClientId, ExportClientSpec } from "./config-export/contracts"; -import { OPENCODE_API_KEY_ENV_REF, OPENCODE_PROVIDER_BLOCK_DEFAULT_CONFIG, OPENCODE_CONFIG_SCHEMA, OPENCODE_PROVIDER_ID, PI_API_DIALECT, LOOPBACK_API_KEY_PLACEHOLDER, HERMES_API_KEY_ENV_REF, OPENCLAW_API_KEY_ENV_REF, OPENCODE_API_KEY_ENV, HERMES_API_KEY_ENV, OPENCLAW_API_KEY_ENV } from "./config-export/constants"; +import { OPENCODE_API_KEY_ENV_REF, OPENCODE_PROVIDER_BLOCK_DEFAULT_CONFIG, OPENCODE_CONFIG_SCHEMA, OPENCODE_PROVIDER_ID, PI_API_DIALECT, LOOPBACK_API_KEY_PLACEHOLDER, HERMES_API_KEY_ENV_REF, OPENCLAW_API_KEY_ENV_REF, OPENCODE_API_KEY_ENV, HERMES_API_KEY_ENV, OPENCLAW_API_KEY_ENV, KILO_API_KEY_ENV } from "./config-export/constants"; import { exportModelLabel, authoritativeContextWindow, outputBudgetFor, normalizeExportModels, inputModalitiesForClient, opencodeModelCapabilities, proxyAdmissionHeaders, singleFragment } from "./config-export/model-metadata"; import { buildOmpClientConfig, summarizeOmp, buildOmpContribution } from "./config-export/omp"; import { buildDshClientConfig, summarizeDsh, buildDshContribution } from "./config-export/dsh"; @@ -61,6 +61,9 @@ import { buildMcodeClientConfig, summarizeMcode, buildMcodeContribution } from " import { buildZcodeClientConfig, summarizeZcode, buildZcodeContribution } from "./config-export/zcode"; import { buildClineClientConfig, summarizeCline, buildClineContribution } from "./config-export/cline"; import { buildRaycastClientConfig, summarizeRaycast, buildRaycastContribution } from "./config-export/raycast"; +import { buildKiloClientConfig, summarizeKilo, buildKiloContribution, kiloConfigPath } from "./config-export/kilo"; +export { kiloConfigPath, kiloHomeDir, KILO_CONFIG_CANDIDATES } from "./config-export/kilo"; +export type { KiloGeneratedConfig, KiloProviderBlock, KiloModelEntry } from "./config-export/kilo"; @@ -1588,6 +1591,18 @@ export const EXPORT_CLIENTS: Record = { buildContribution: buildClineContribution, loopbackOnly: true, }, + kilo: { + id: "kilo", + filename: "kilo.jsonc", + destination: env => kiloConfigPath(env), + apiKeyEnv: KILO_API_KEY_ENV, + exportHint: `export ${KILO_API_KEY_ENV}=`, + build: buildKiloClientConfig, + format: "json", + summarize: summarizeKilo, + buildContribution: buildKiloContribution, + loopbackOnly: false, + }, }; export const EXPORT_CLIENT_IDS: readonly ExportClientId[] = Object.keys(EXPORT_CLIENTS) as ExportClientId[]; diff --git a/src/clients/config-export/constants.ts b/src/clients/config-export/constants.ts index 5e272cec4e3..a80cbbf4c5e 100644 --- a/src/clients/config-export/constants.ts +++ b/src/clients/config-export/constants.ts @@ -14,6 +14,14 @@ export const OPENCODE_CONFIG_SCHEMA = "https://opencode.ai/config.json"; */ export const OPENCODE_API_KEY_ENV = "OPENCODEX_OPENCODE_API_KEY"; +/** + * Env var carrying the proxy admission key to Kilo. Independent of OpenCode's + * so the two clients can keep distinct credentials. + */ +export const KILO_API_KEY_ENV = "OPENCODEX_KILO_API_KEY"; +export const KILO_API_KEY_ENV_REF = `{env:${KILO_API_KEY_ENV}}`; +export const KILO_CONFIG_SCHEMA = "https://app.kilo.ai/config.json"; + /** Env reference shared by apiKey and the dedicated proxy admission header. */ export const OPENCODE_API_KEY_ENV_REF = `{env:${OPENCODE_API_KEY_ENV}}`; diff --git a/src/clients/config-export/contracts.ts b/src/clients/config-export/contracts.ts index 6744150d7a7..dbffbc5b292 100644 --- a/src/clients/config-export/contracts.ts +++ b/src/clients/config-export/contracts.ts @@ -105,7 +105,8 @@ export type ExportClientId = | "aside" | "raycast" | "omo" - | "cline"; + | "cline" + | "kilo"; export interface ExportClientSpec { id: ExportClientId; diff --git a/src/clients/config-export/kilo.ts b/src/clients/config-export/kilo.ts new file mode 100644 index 00000000000..7f084a1a0e5 --- /dev/null +++ b/src/clients/config-export/kilo.ts @@ -0,0 +1,106 @@ +import { existsSync } from "node:fs"; +import { homedir } from "node:os"; +import { join } from "node:path"; +import type { ExportContext, ManagedContribution, OpencodeLaunchEnv } from "./contracts"; +import { + KILO_API_KEY_ENV_REF, + KILO_CONFIG_SCHEMA, + OPENCODE_PROVIDER_BLOCK_DEFAULT_CONFIG, + OPENCODE_PROVIDER_ID, +} from "./constants"; +import { + authoritativeContextWindow, + exportModelLabel, + normalizeExportModels, + opencodeModelCapabilities, + outputBudgetFor, + proxyAdmissionHeaders, + singleFragment, +} from "./model-metadata"; + +export const KILO_CONFIG_CANDIDATES = [ + "kilo.jsonc", + "kilo.json", + "opencode.jsonc", + "opencode.json", + "config.json", +] as const; + +export interface KiloModelEntry { + name: string; + limit?: { context: number; output: number }; + attachment?: boolean; + modalities?: { input: string[]; output: string[] }; +} + +export interface KiloProviderBlock { + npm: string; + name: string; + options: { + baseURL: string; + apiKey?: string; + headers?: Record; + }; + models: Record; +} + +export interface KiloGeneratedConfig { + $schema: string; + provider: Record; +} + +export function kiloHomeDir(env: OpencodeLaunchEnv = process.env, home: string = homedir()): string { + const xdg = env.XDG_CONFIG_HOME && env.XDG_CONFIG_HOME.length > 0 ? env.XDG_CONFIG_HOME : join(home, ".config"); + return join(xdg, "kilo"); +} + +export function kiloConfigPath(env: OpencodeLaunchEnv = process.env, home: string = homedir()): string { + const dir = kiloHomeDir(env, home); + for (const name of KILO_CONFIG_CANDIDATES) { + const path = join(dir, name); + if (existsSync(path)) return path; + } + return join(dir, "kilo.jsonc"); +} + +function kiloProviderBlock(ctx: ExportContext): KiloProviderBlock { + const config = ctx.config ?? OPENCODE_PROVIDER_BLOCK_DEFAULT_CONFIG; + const models: Record = {}; + for (const model of normalizeExportModels(ctx.models)) { + const entry: KiloModelEntry = { name: exportModelLabel(model) }; + const context = authoritativeContextWindow(model.contextWindow); + if (context !== undefined) { + entry.limit = { context, output: outputBudgetFor(context) }; + } + const capabilities = opencodeModelCapabilities(model.inputModalities); + if (capabilities) { + entry.attachment = capabilities.attachment; + entry.modalities = capabilities.modalities; + } + models[model.namespaced] = entry; + } + const headers = proxyAdmissionHeaders(config, KILO_API_KEY_ENV_REF); + return { + npm: "@ai-sdk/openai-compatible", + name: "OpenCodex", + options: headers ? { baseURL: ctx.baseUrl, headers } : { baseURL: ctx.baseUrl, apiKey: KILO_API_KEY_ENV_REF }, + models, + }; +} + +export function buildKiloClientConfig(ctx: ExportContext): KiloGeneratedConfig { + return { + $schema: KILO_CONFIG_SCHEMA, + provider: { [OPENCODE_PROVIDER_ID]: kiloProviderBlock(ctx) }, + }; +} + +export function summarizeKilo(document: unknown): { modelCount: number; modelsWithoutLimits: number } { + const models = Object.values((document as KiloGeneratedConfig | undefined)?.provider?.[OPENCODE_PROVIDER_ID]?.models ?? {}); + return { modelCount: models.length, modelsWithoutLimits: models.filter(model => !model.limit).length }; +} + +export function buildKiloContribution(ctx: ExportContext): ManagedContribution { + const doc = buildKiloClientConfig(ctx); + return singleFragment("kilo", ["provider", OPENCODE_PROVIDER_ID], doc.provider[OPENCODE_PROVIDER_ID]); +} diff --git a/src/integrations/config-io.ts b/src/integrations/config-io.ts index df5337a121e..45f5458cf25 100644 --- a/src/integrations/config-io.ts +++ b/src/integrations/config-io.ts @@ -9,6 +9,7 @@ */ import { lstatSync, mkdirSync, readFileSync, rmSync, statSync } from "node:fs"; import type { ConfigFormat } from "../clients/config-export"; +import { canonicalizeJsonc } from "../lib/jsonc"; import { MAX_JSON_NESTING } from "./serialize"; import { atomicWriteFileNoFollow, isMissingPathError } from "../config/atomic-write"; import type { JournalEntry } from "./journal"; @@ -132,7 +133,11 @@ function jsonTextSafeToRewrite(text: string): boolean { } /** Parse a client config, tolerating absence. PARSE_FAILED on garbage. */ -export function parseConfig(text: string | null, format: ConfigFormat): unknown | typeof PARSE_FAILED { +export function parseConfig( + text: string | null, + format: ConfigFormat, + options?: { jsonc?: boolean }, +): unknown | typeof PARSE_FAILED { if (text === null || text.trim().length === 0) return {}; try { switch (format) { @@ -143,9 +148,13 @@ export function parseConfig(text: string | null, format: ConfigFormat): unknown * would otherwise cap the rewrite only after JSON.parse had already * built the 50k-deep object graph. The outcome is unchanged: invalid * JSON still returns PARSE_FAILED, from the catch below. + * + * Kilo's global file is JSONC. Comments and trailing commas are + * stripped first so the rewrite-safety scan sees JSON, not comment text. */ - if (!jsonTextSafeToRewrite(text)) return PARSE_FAILED; - return JSON.parse(text); + const source = options?.jsonc ? canonicalizeJsonc(text) : text; + if (!jsonTextSafeToRewrite(source)) return PARSE_FAILED; + return JSON.parse(source); } case "json5": return Bun.JSON5.parse(text); case "yaml": return Bun.YAML.parse(text); diff --git a/src/integrations/mutation-plan.ts b/src/integrations/mutation-plan.ts index 9ab2fac0d82..b1157c97df1 100644 --- a/src/integrations/mutation-plan.ts +++ b/src/integrations/mutation-plan.ts @@ -144,6 +144,7 @@ const CLIENT_MANAGED_PATHS = { ["settings", "providers", OPENCODE_PROVIDER_ID], ["catalog", "providers", OPENCODE_PROVIDER_ID], ], + kilo: [["provider", OPENCODE_PROVIDER_ID]], } satisfies Record; /** Not a configuration surface. Exported so a parity case can compare it against the shipped clients. */ @@ -743,7 +744,7 @@ function previewRestore(input: IntegrationWriteInput, request: PreviewRequest): ? {} : observed.clientId === "cline" ? parseClineDocument(observed.before) - : parseConfig(observed.before, observed.format), + : parseConfig(observed.before, observed.format, observed.clientId === "kilo" ? { jsonc: true } : undefined), restore: { opId: observed.entry.opId, entry: observed.entry, @@ -880,7 +881,9 @@ export function observeIntegration(input: IntegrationWriteInput, effects: Observ } as const; } const before = loaded.before; - const parsed = clientId === "cline" ? parseClineDocument(before) : parseConfig(before, effective.format); + const parsed = clientId === "cline" + ? parseClineDocument(before) + : parseConfig(before, effective.format, clientId === "kilo" ? { jsonc: true } : undefined); if (parsed === PARSE_FAILED) { return { failed: observationFailure("unsafe", "unsafe", `${configPath} could not be parsed, or holds something opencodex cannot rewrite without changing it (a non-finite number, a large integer or a tiny one a rewrite would round, -0, a duplicate member, or nesting deeper than 1000 levels)`) } as const; diff --git a/src/integrations/registry.ts b/src/integrations/registry.ts index 55d87a60ac4..7230ef126aa 100644 --- a/src/integrations/registry.ts +++ b/src/integrations/registry.ts @@ -48,6 +48,8 @@ import { zcodeStoreSchemaEstablished, type BuildContribution, type ConfigFormat, + kiloConfigPath, + kiloHomeDir, type ExportClientId, } from "../clients/config-export"; @@ -345,6 +347,11 @@ export const INTEGRATION_CLIENTS: Record clineSettingsDir(env, home), writerLock: { suffix: ".lock" }, }, + kilo: { + id: "kilo", + configPath: (env = process.env, home = homedir()) => kiloConfigPath(env, home), + detectDir: (env = process.env, home = homedir()) => kiloHomeDir(env, home), + }, }; export const INTEGRATION_CLIENT_IDS: readonly IntegrationClientId[] = diff --git a/src/integrations/state.ts b/src/integrations/state.ts index d41444615bd..42546347699 100644 --- a/src/integrations/state.ts +++ b/src/integrations/state.ts @@ -572,7 +572,7 @@ export function readIntegrationState(input: IntegrationStateInput): IntegrationS const parsed = input.clientId === "cline" ? parseClineDocument(loaded.before) - : parseConfig(loaded.before, effective.format); + : parseConfig(loaded.before, effective.format, input.clientId === "kilo" ? { jsonc: true } : undefined); const contribution = effective.buildContribution(exportContextOf(input)); const { state, reason } = classifyIntegration({ fileText: loaded.before, diff --git a/src/lib/jsonc.ts b/src/lib/jsonc.ts new file mode 100644 index 00000000000..8f714e7df4e --- /dev/null +++ b/src/lib/jsonc.ts @@ -0,0 +1,97 @@ +/** + * JSONC parse used by OpenCode's launcher and Kilo's managed writer. + * + * Strict JSON.parse runs first and untouched — the tolerant path is only + * attempted when that throws, keeping well-formed configs away from the stripper. + */ + +/** + * Strip `//` and block comments outside string literals. Escape-aware so a quote inside + * an escaped sequence cannot flip string state and expose config text to the stripper. + */ +function stripJsonComments(text: string): string { + let out = ""; + let inString = false; + let inLine = false; + let inBlock = false; + for (let i = 0; i < text.length; i++) { + const ch = text[i]!; + const next = text[i + 1]; + if (inLine) { + if (ch === "\n") { + inLine = false; + out += ch; + } + continue; + } + if (inBlock) { + // Newlines are preserved so JSON.parse error positions stay meaningful. + if (ch === "\n") out += ch; + else if (ch === "*" && next === "/") { inBlock = false; i++; } + continue; + } + if (inString) { + out += ch; + if (ch === "\\") { + const escaped = text[i + 1]; + if (escaped !== undefined) { out += escaped; i++; } + continue; + } + if (ch === "\"") inString = false; + continue; + } + if (ch === "\"") { inString = true; out += ch; continue; } + if (ch === "/" && next === "/") { inLine = true; i++; continue; } + if (ch === "/" && next === "*") { inBlock = true; i++; continue; } + out += ch; + } + return out; +} + +/** Drop commas that sit directly before `}` or `]`, ignoring string contents. */ +function stripTrailingCommas(text: string): string { + let out = ""; + let inString = false; + for (let i = 0; i < text.length; i++) { + const ch = text[i]!; + if (inString) { + out += ch; + if (ch === "\\") { + const escaped = text[i + 1]; + if (escaped !== undefined) { out += escaped; i++; } + continue; + } + if (ch === "\"") inString = false; + continue; + } + if (ch === "\"") { inString = true; out += ch; continue; } + if (ch === ",") { + let j = i + 1; + while (j < text.length && /\s/.test(text[j]!)) j++; + if (text[j] === "}" || text[j] === "]") continue; + } + out += ch; + } + return out; +} + +/** + * Return JSON that `JSON.parse` will accept. Strict text is returned untouched; + * comments and trailing commas are stripped only when the strict parse throws. + */ +export function canonicalizeJsonc(text: string): string { + try { + JSON.parse(text); + return text; + } catch { + return stripTrailingCommas(stripJsonComments(text)); + } +} + +/** + * JSON with optional comments and trailing commas. Strict JSON.parse runs first + * and untouched — the tolerant path is only attempted when that throws. + */ +export function parseJsonc(text: string): unknown { + return JSON.parse(canonicalizeJsonc(text)); +} diff --git a/structure/clients/integrations.md b/structure/clients/integrations.md index 9a07703610f..6b081a81521 100644 --- a/structure/clients/integrations.md +++ b/structure/clients/integrations.md @@ -173,7 +173,7 @@ All registered integrations consume the shared catalog, including [Anthropic see | Client | Per-model output | | --- | --- | -| OpenCode | `attachment`, `modalities.input` | +| OpenCode, Kilo | `attachment`, `modalities.input` | | Pi, OMP, Prime, Aside, omo, Gajae, DSH | `input` (text/image only) | | ZCode | `modalities.input` (text/image only) | | Cline | `modalities.input`, `supportsVision` | @@ -375,6 +375,15 @@ sibling policy. Profile journal views retain source-store provenance for older l The shared atomic replacement publisher also identifies explicit Remote Workspace file writes as `remote-workspace`; its isolated owner and support limits are documented in [Remote Workspace](../remote-workspace.md). +## Kilo global JSONC + +Kilo owns only `provider.opencodex` in the first existing global file among `kilo.jsonc`, +`kilo.json`, `opencode.jsonc`, `opencode.json`, and `config.json` under `~/.config/kilo` +(`XDG_CONFIG_HOME` relocates that directory). Parse accepts JSONC comments and trailing +commas; serialize rewrites the whole file as pretty JSON, so comments in other keys are +not preserved. Kilo is not on the implicit owned-catalog fan-out. Remote admission uses +the same `{env:OPENCODEX_KILO_API_KEY}` / `x-opencodex-api-key` rule as OpenCode. + ## Cline paired files Cline CLI uses `providers.json` for connection settings and sibling `models.json` for its diff --git a/tests/clients/kilo-client.test.ts b/tests/clients/kilo-client.test.ts new file mode 100644 index 00000000000..3fc97f8f2ce --- /dev/null +++ b/tests/clients/kilo-client.test.ts @@ -0,0 +1,202 @@ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join } from "node:path"; +import { + EXPORT_CLIENTS, + KILO_API_KEY_ENV_REF, + KILO_CONFIG_SCHEMA, + OPENCODE_PROVIDER_ID, + buildClientConfig, + buildClientConfigText, + buildClientContribution, + kiloConfigPath, + kiloHomeDir, + type ExportContext, +} from "../../src/clients/config-export"; +import type { KiloGeneratedConfig } from "../../src/clients/config-export/kilo"; +import { PARSE_FAILED, parseConfig } from "../../src/integrations/config-io"; +import { INTEGRATION_CLIENTS } from "../../src/integrations/registry"; +import { createIntegrationStateStore, type IntegrationStateStore } from "../../src/integrations/store"; +import { applyIntegration, disableIntegration, restoreIntegration } from "../../src/integrations/writer"; +import type { OcxConfig } from "../../src/types"; +import { removeTreeWithRetry } from "../helpers/remove-tree"; + +const LOOPBACK: OcxConfig = { + port: 10100, + hostname: "127.0.0.1", + defaultProvider: "mock", + providers: { mock: { adapter: "openai-chat", baseUrl: "http://127.0.0.1/v1" } }, +} as OcxConfig; + +const REMOTE: OcxConfig = { ...LOOPBACK, hostname: "0.0.0.0" } as OcxConfig; + +function context(config: OcxConfig = LOOPBACK): ExportContext { + return { + baseUrl: "http://127.0.0.1:10100/v1", + config, + models: [ + { namespaced: "anthropic/claude-opus-5", provider: "anthropic", id: "claude-opus-5", contextWindow: 200_000, inputModalities: ["text", "image"] }, + { namespaced: "mystery/model", provider: "mystery", id: "model" }, + { namespaced: "audio/only", provider: "audio", id: "only", inputModalities: ["audio"] }, + { namespaced: "unknown/mod", provider: "unknown", id: "mod", inputModalities: ["smell"] }, + ], + }; +} + +describe("kilo client config", () => { + test("emits a V1-only document with Kilo's schema and npm package", () => { + const document = buildClientConfig("kilo", context()) as KiloGeneratedConfig; + expect(document.$schema).toBe(KILO_CONFIG_SCHEMA); + expect(document).not.toHaveProperty("providers"); + expect(Object.keys(document.provider)).toEqual([OPENCODE_PROVIDER_ID]); + const provider = document.provider[OPENCODE_PROVIDER_ID]!; + expect(provider.npm).toBe("@ai-sdk/openai-compatible"); + expect(provider.name).toBe("OpenCodex"); + expect(JSON.stringify(document)).not.toContain('"package"'); + expect(JSON.stringify(provider.models)).not.toContain("variants"); + }); + + test("the contribution owns only provider.opencodex", () => { + const contribution = buildClientContribution("kilo", context()); + expect(contribution.clientId).toBe("kilo"); + expect(contribution.fragments.map(fragment => fragment.path)).toEqual([["provider", OPENCODE_PROVIDER_ID]]); + }); + + test("loopback uses the Kilo env ref; remote uses the admission header; never a real key", () => { + const sentinel = ["sk", "live", "kilo", "sentinel"].join("-"); + const withKey = { ...LOOPBACK, apiKeys: [{ key: sentinel }] } as OcxConfig; + const loopback = buildClientConfig("kilo", context(withKey)) as KiloGeneratedConfig; + expect(loopback.provider[OPENCODE_PROVIDER_ID]!.options.apiKey).toBe(KILO_API_KEY_ENV_REF); + expect(loopback.provider[OPENCODE_PROVIDER_ID]!.options.headers).toBeUndefined(); + + const remote = buildClientConfig("kilo", context({ ...REMOTE, apiKeys: [{ key: sentinel }] } as OcxConfig)) as KiloGeneratedConfig; + expect(remote.provider[OPENCODE_PROVIDER_ID]!.options.apiKey).toBeUndefined(); + expect(remote.provider[OPENCODE_PROVIDER_ID]!.options.headers).toEqual({ "x-opencodex-api-key": KILO_API_KEY_ENV_REF }); + + const bytes = buildClientConfigText("kilo", context(withKey)).text; + expect(bytes).not.toContain(sentinel); + expect(bytes).not.toContain("OPENCODEX_OPENCODE_API_KEY"); + expect(EXPORT_CLIENTS.kilo.loopbackOnly).toBe(false); + expect(EXPORT_CLIENTS.kilo.filename).toBe("kilo.jsonc"); + expect(EXPORT_CLIENTS.kilo.format).toBe("json"); + }); + + test("audio-only and unknown modalities follow OpenCode's capability helper", () => { + const document = buildClientConfig("kilo", context()) as KiloGeneratedConfig; + const models = document.provider[OPENCODE_PROVIDER_ID]!.models; + expect(models["audio/only"]).toEqual({ + name: "only (audio)", + attachment: true, + modalities: { input: ["audio"], output: ["text"] }, + }); + expect(models["unknown/mod"]).toEqual({ name: "mod (unknown)" }); + expect(models["mystery/model"]!.limit).toBeUndefined(); + expect(EXPORT_CLIENTS.kilo.summarize(document)).toEqual({ modelCount: 4, modelsWithoutLimits: 3 }); + }); + + test("path order: first existing candidate wins; empty dir is kilo.jsonc; XDG relocates", () => { + const root = mkdtempSync(join(tmpdir(), "ocx-kilo-path-")); + try { + const home = join(root, "home"); + const dir = kiloHomeDir({}, home); + expect(dir).toBe(join(home, ".config", "kilo")); + mkdirSync(dir, { recursive: true }); + expect(kiloConfigPath({}, home)).toBe(join(dir, "kilo.jsonc")); + writeFileSync(join(dir, "config.json"), "{}\n"); + expect(kiloConfigPath({}, home)).toBe(join(dir, "config.json")); + writeFileSync(join(dir, "kilo.json"), "{}\n"); + expect(kiloConfigPath({}, home)).toBe(join(dir, "kilo.json")); + writeFileSync(join(dir, "kilo.jsonc"), "{}\n"); + expect(kiloConfigPath({}, home)).toBe(join(dir, "kilo.jsonc")); + + const xdg = join(root, "xdg"); + mkdirSync(join(xdg, "kilo"), { recursive: true }); + expect(kiloHomeDir({ XDG_CONFIG_HOME: xdg }, home)).toBe(join(xdg, "kilo")); + expect(kiloConfigPath({ XDG_CONFIG_HOME: xdg }, home)).toBe(join(xdg, "kilo", "kilo.jsonc")); + expect(INTEGRATION_CLIENTS.kilo.detectDir({ XDG_CONFIG_HOME: xdg }, home)).toBe(join(xdg, "kilo")); + } finally { + removeTreeWithRetry(root); + } + }); +}); + +describe("kilo JSONC apply/disable/restore", () => { + let home: string; + let store: IntegrationStateStore; + + beforeEach(() => { + const base = mkdtempSync(join(tmpdir(), "ocx-kilo-writer-")); + home = join(base, "home"); + mkdirSync(home, { recursive: true }); + store = createIntegrationStateStore(join(base, "store", "integrations")); + }); + + afterEach(() => { + removeTreeWithRetry(dirname(home)); + }); + + const kitchenSink = `{ + // user comment + "$schema": "https://app.kilo.ai/config.json", + "model": "anthropic/claude-opus-4", + "enabled_providers": ["anthropic"], + "mcp": { "keep": true }, + "provider": { + "anthropic": { "npm": "@ai-sdk/anthropic" }, + }, +} +`; + + test("JSONC comments and trailing commas parse; apply/disable leave non-owned keys", () => { + const spec = INTEGRATION_CLIENTS.kilo; + mkdirSync(spec.detectDir({}, home), { recursive: true }); + const configPath = spec.configPath({}, home); + writeFileSync(configPath, kitchenSink); + + const parsed = parseConfig(kitchenSink, "json", { jsonc: true }); + expect(parsed).not.toBe(PARSE_FAILED); + expect(parsed).toMatchObject({ + model: "anthropic/claude-opus-4", + enabled_providers: ["anthropic"], + mcp: { keep: true }, + provider: { anthropic: { npm: "@ai-sdk/anthropic" } }, + }); + expect(parseConfig(kitchenSink, "json")).toBe(PARSE_FAILED); + + const write = { + clientId: "kilo" as const, + models: context().models, + config: LOOPBACK, + port: 10100, + env: {} as NodeJS.ProcessEnv, + home, + store, + }; + const applied = applyIntegration(write); + expect(applied.ok).toBe(true); + const afterApply = JSON.parse(readFileSync(configPath, "utf8")) as KiloGeneratedConfig & { + model: string; + enabled_providers: string[]; + mcp: { keep: boolean }; + provider: Record; + }; + expect(afterApply.model).toBe("anthropic/claude-opus-4"); + expect(afterApply.enabled_providers).toEqual(["anthropic"]); + expect(afterApply.mcp).toEqual({ keep: true }); + expect(afterApply.provider.anthropic).toEqual({ npm: "@ai-sdk/anthropic" }); + expect(afterApply.provider[OPENCODE_PROVIDER_ID]).toBeDefined(); + expect(afterApply).not.toHaveProperty("providers"); + + const disabled = disableIntegration(write); + expect(disabled.ok).toBe(true); + const afterDisable = JSON.parse(readFileSync(configPath, "utf8")) as typeof afterApply; + expect(afterDisable.provider[OPENCODE_PROVIDER_ID]).toBeUndefined(); + expect(afterDisable.provider.anthropic).toEqual({ npm: "@ai-sdk/anthropic" }); + expect(afterDisable.model).toBe("anthropic/claude-opus-4"); + expect(afterDisable.mcp).toEqual({ keep: true }); + + const restored = restoreIntegration({ ...write, opId: store.listOperations("kilo")[0]!.opId }); + expect(restored.ok).toBe(true); + }); +}); diff --git a/tests/config/client-config-export.test.ts b/tests/config/client-config-export.test.ts index d1dd5ebca47..7aa1be9eb53 100644 --- a/tests/config/client-config-export.test.ts +++ b/tests/config/client-config-export.test.ts @@ -847,8 +847,8 @@ describe("hub-resolved Fast exports", () => { }); describe("EXPORT_CLIENTS registry", () => { - test("covers exactly the fourteen file-toggle clients", () => { - expect(EXPORT_CLIENT_IDS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline"]); + test("covers exactly the sixteen file-toggle clients", () => { + expect(EXPORT_CLIENT_IDS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline", "kilo"]); for (const id of EXPORT_CLIENT_IDS) expect(isExportClientId(id)).toBe(true); // The exception clients keep their own surfaces and are not export clients. expect(isExportClientId("claude-desktop")).toBe(false); @@ -1003,9 +1003,10 @@ describe("EXPORT_CLIENTS registry", () => { expect(typeof spec.summarize).toBe("function"); expect(typeof spec.buildContribution).toBe("function"); // The filename's extension must match the declared format, so a reader - // never has to guess which one is authoritative. + // never has to guess which one is authoritative. Kilo's destination is + // `.jsonc` while serialize stays pretty JSON (`format: "json"`). const extension = spec.filename.slice(spec.filename.lastIndexOf(".") + 1); - expect(extension).toBe(spec.format); + expect(extension).toBe(id === "kilo" ? "jsonc" : spec.format); } }); @@ -1019,6 +1020,11 @@ describe("EXPORT_CLIENTS registry", () => { const extensionFor = { json: "json", yaml: "yaml", toml: "toml", json5: "json5" } as const; for (const id of EXPORT_CLIENT_IDS) { const spec = EXPORT_CLIENTS[id]; + if (id === "kilo") { + expect(spec.filename.endsWith(".jsonc")).toBe(true); + expect(spec.format).toBe("json"); + continue; + } expect(spec.filename.endsWith(`.${extensionFor[spec.format]}`)).toBe(true); } }); diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index e8de7d32f2e..deb368ebc7d 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -897,6 +897,7 @@ "jev-decision.test.ts": "routing", "jev-provider.test.ts": "providers", "keyring-smoke.test.ts": "ci-workflows", + "kilo-client.test.ts": "clients", "kimi-oauth-identity.test.ts": "providers", "kimi-responses-adjacency.test.ts": "providers", "kiro-account-load.test.ts": "providers/kiro", diff --git a/tests/gui/integrations-invariants.test.ts b/tests/gui/integrations-invariants.test.ts index 0378ac8e1b6..6511c4b9c04 100644 --- a/tests/gui/integrations-invariants.test.ts +++ b/tests/gui/integrations-invariants.test.ts @@ -99,7 +99,7 @@ describe("the client registries cannot drift apart", () => { const guiRouting = await import("../../gui/src/app-routing"); const expected = [...EXPORT_CLIENT_IDS].sort(); - expect(expected).toHaveLength(15); + expect(expected).toHaveLength(16); expect([...INTEGRATION_CLIENT_IDS].sort()).toEqual(expected); expect([...gui.CLIENTS].sort()).toEqual(expected); @@ -273,6 +273,7 @@ describe("every client survives a full lifecycle", () => { // contract -- verified against senpi's own compiled validator, not assumed // from the family resemblance (260912 plan unit, 001). omo: '{\n "providers": {\n "mine": { "api": "http://keep-me" }\n }\n}\n', + kilo: '{\n "model": "keep-me",\n "provider": {\n "mine": { "npm": "keep-me" }\n }\n}\n', }; /** Where the seed's user-owned entry lives when the seed is a sequence. */ const USER_ELEMENT: Partial> = { From 28b4fae3942035e07fa0b23194ae89d4000de31c Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 20 Sep 2026 15:36:44 +0800 Subject: [PATCH 2/9] fix(clients): address Kilo review findings CodeRabbit findings on #5272: - Bind Kilo lifecycle ops to the owned file. Resolution picks the first EXISTING candidate, so a candidate created after apply moved discovery while the owned file still held our block: status answered absent and disable no-oped, stranding the block. New opt-in registry seam bindsDriftedRecord: while the recorded path is still one of Kilo's own candidates under the current env and home, reads and mutations stay on the recorded file. A record from another home never binds, keeping the one-home-cannot-authorize-another refusal contract. - Reject unterminated block comments in the JSONC stripper instead of dropping the malformed tail through the parse gate. - Strip comments/trailing commas unconditionally in canonicalizeJsonc: the strict-parse probe materialized a deeply nested document before the rewrite guard's depth ceiling could refuse it. - Name XDG_CONFIG_HOME relocation and the kilo.jsonc creation fallback in every locale's Kilo semantics string and the translated guides. --- .../content/docs/fr/guides/integrations.md | 4 +- .../content/docs/tr/guides/integrations.md | 4 +- .../content/docs/zh-tw/guides/integrations.md | 4 +- gui/src/i18n/de.ts | 2 +- gui/src/i18n/en.ts | 2 +- gui/src/i18n/fr.ts | 2 +- gui/src/i18n/ja.ts | 2 +- gui/src/i18n/ko.ts | 2 +- gui/src/i18n/ru.ts | 2 +- gui/src/i18n/tr.ts | 2 +- gui/src/i18n/vi.ts | 2 +- gui/src/i18n/zh-TW.ts | 2 +- gui/src/i18n/zh.ts | 2 +- src/integrations/mutation-plan.ts | 8 ++- src/integrations/registry.ts | 16 +++++ src/integrations/state.ts | 8 ++- src/lib/jsonc.ts | 29 ++++---- structure/clients/integrations.md | 9 +++ tests/clients/kilo-client.test.ts | 68 +++++++++++++++++++ 19 files changed, 140 insertions(+), 30 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/integrations.md b/docs-site/src/content/docs/fr/guides/integrations.md index 1d0b7872a5f..e09c72dd003 100644 --- a/docs-site/src/content/docs/fr/guides/integrations.md +++ b/docs-site/src/content/docs/fr/guides/integrations.md @@ -23,7 +23,7 @@ puis peut le retirer. Seize clients fonctionnent ainsi, chacun avec son propre c | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | immédiatement à l'enregistrement — Raycast surveille le fichier | aucun — bouclage uniquement | | omo | `~/.omo/agent/models.json` | JSON | nouvelles sessions | espace réservé de bouclage | | Cline CLI | `~/.cline/data/settings/providers.json` + `models.json` | JSON | après arrêt et redémarrage | bouclage uniquement | -| Kilo | premier fichier existant parmi `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` ou `config.json` sous `~/.config/kilo` | JSONC | nouvelles sessions | `OPENCODEX_KILO_API_KEY` | +| Kilo | premier fichier existant parmi `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` ou `config.json` sous `~/.config/kilo` (`XDG_CONFIG_HOME` déplace ce répertoire ; `kilo.jsonc` est créé si aucun n'existe) | JSONC | nouvelles sessions | `OPENCODEX_KILO_API_KEY` | Les modèles GJC dotés d'une échelle d'effort de raisonnement prise en charge exportent `reasoning: true`, `thinking.levels` et `compat.supportsReasoningEffort`, afin que GJC propose le choix de l'effort. Les modèles Codex natifs reçoivent leur échelle standard même si le catalogue l'omet. Ces champs sont absents sans échelle connue ; `none` n'envoie pas d'effort et `ultra` devient `max` sur le réseau. Actualisez l'intégration pour mettre à jour ces options. @@ -303,7 +303,7 @@ ocx integration client restore --op ## Kilo -Kilo n’écrit que `provider.opencodex` dans le premier fichier global existant sous `~/.config/kilo`. Les autres clés restent inchangées. Appliquer réécrit tout le fichier ; commentaires et virgules finales ne sont pas conservés. Sélectionnez `opencodex/` dans Kilo. +Kilo n’écrit que `provider.opencodex` dans le premier fichier global existant sous `~/.config/kilo` (`XDG_CONFIG_HOME` déplace ce répertoire ; `kilo.jsonc` est créé si aucun candidat n’existe). Les autres clés restent inchangées. Appliquer réécrit tout le fichier ; commentaires et virgules finales ne sont pas conservés. Sélectionnez `opencodex/` dans Kilo. ```bash ocx integration client enable --client kilo diff --git a/docs-site/src/content/docs/tr/guides/integrations.md b/docs-site/src/content/docs/tr/guides/integrations.md index 1646c75a99e..4767d62e173 100644 --- a/docs-site/src/content/docs/tr/guides/integrations.md +++ b/docs-site/src/content/docs/tr/guides/integrations.md @@ -24,7 +24,7 @@ yapılandırma dosyasına yazar ve tekrar kaldırır. On altı istemci bu şekil | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | kaydedildiği anda — Raycast dosyayı izler | yok — yalnızca geri döngü | | omo | `~/.omo/agent/models.json` | JSON | yeni oturumlarda | geri döngü yer tutucusu | | Cline CLI | `~/.cline/data/settings/providers.json` + `models.json` | JSON | kapatıp yeniden başlattıktan sonra | yalnızca loopback | -| Kilo | `~/.config/kilo` altında ilk bulunan `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` veya `config.json` | JSONC | yeni oturumlarda | `OPENCODEX_KILO_API_KEY` | +| Kilo | `~/.config/kilo` altında ilk bulunan `kilo.jsonc`, `kilo.json`, `opencode.jsonc`, `opencode.json` veya `config.json` (`XDG_CONFIG_HOME` bu dizini taşır; hiçbiri yoksa `kilo.jsonc` oluşturulur) | JSONC | yeni oturumlarda | `OPENCODEX_KILO_API_KEY` | Desteklenen akıl yürütme düzeylerine sahip GJC modelleri, GJC'nin düzey seçimi sunabilmesi için `reasoning: true`, `thinking.levels` ve `compat.supportsReasoningEffort` alanlarını dışa aktarır. Yerel Codex modelleri, katalogda belirtilmese bile standart düzeylerini alır. Bilinen düzeyi olmayan modellerde bu alanlar bulunmaz. `none` düzey göndermez ve `ultra` gönderimde `max` düzeyine dönüşür; bu yüzden seçeneklerde yer almazlar. Model seçeneklerini güncellemek için entegrasyonu yenileyin. @@ -328,7 +328,7 @@ ocx integration client restore --op ## Kilo -Kilo yalnızca `~/.config/kilo` altındaki ilk mevcut genel dosyada `provider.opencodex` yazar. Diğer anahtarlar değişmez. Uygula dosyanın tamamını yeniden yazar; yorumlar ve sondaki virgüller korunmaz. Kilo’da `opencodex/` seçin. +Kilo yalnızca `~/.config/kilo` altındaki ilk mevcut genel dosyada `provider.opencodex` yazar (`XDG_CONFIG_HOME` bu dizini taşır; hiçbir aday yoksa `kilo.jsonc` oluşturulur). Diğer anahtarlar değişmez. Uygula dosyanın tamamını yeniden yazar; yorumlar ve sondaki virgüller korunmaz. Kilo’da `opencodex/` seçin. ```bash ocx integration client enable --client kilo diff --git a/docs-site/src/content/docs/zh-tw/guides/integrations.md b/docs-site/src/content/docs/zh-tw/guides/integrations.md index 388144edec0..c445d204b14 100644 --- a/docs-site/src/content/docs/zh-tw/guides/integrations.md +++ b/docs-site/src/content/docs/zh-tw/guides/integrations.md @@ -22,7 +22,7 @@ description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、 | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | 儲存後立即生效——Raycast 會監看該檔案 | 無——僅限 loopback | | omo | `~/.omo/agent/models.json` | JSON | 新工作階段 | loopback 佔位符 | | Cline CLI | `~/.cline/data/settings/providers.json` + `models.json` | JSON | 結束並重新啟動後 | 僅限 loopback | -| Kilo | `~/.config/kilo` 下最先存在的 `kilo.jsonc`、`kilo.json`、`opencode.jsonc`、`opencode.json` 或 `config.json` | JSONC | 新工作階段 | `OPENCODEX_KILO_API_KEY` | +| Kilo | `~/.config/kilo` 下最先存在的 `kilo.jsonc`、`kilo.json`、`opencode.jsonc`、`opencode.json` 或 `config.json`(`XDG_CONFIG_HOME` 會移動該目錄;若都不存在則建立 `kilo.jsonc`) | JSONC | 新工作階段 | `OPENCODEX_KILO_API_KEY` | 具有受支援推理強度階梯的 GJC 模型會匯出 `reasoning: true`、`thinking.levels` 與 `compat.supportsReasoningEffort`,讓 GJC 提供強度選擇。原生 Codex 模型即使未在目錄中列出階梯,也會取得標準階梯。沒有已知階梯的模型會省略這些欄位;`none` 不傳送強度,`ultra` 在傳輸時會折疊成 `max`,因此不會列為選項。重新整理整合即可更新模型選項。 @@ -205,7 +205,7 @@ ocx integration client restore --op ## Kilo -Kilo 只會把 `provider.opencodex` 寫入 `~/.config/kilo` 下最先存在的全域檔。其他鍵保持不變。套用會重寫整個檔案,因此不會保留註解與尾隨逗號。請在 Kilo 中選擇 `opencodex/<模型>`。 +Kilo 只會把 `provider.opencodex` 寫入 `~/.config/kilo` 下最先存在的全域檔(`XDG_CONFIG_HOME` 會移動該目錄;若沒有任何候選檔則建立 `kilo.jsonc`)。其他鍵保持不變。套用會重寫整個檔案,因此不會保留註解與尾隨逗號。請在 Kilo 中選擇 `opencodex/<模型>`。 ```bash ocx integration client enable --client kilo diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 0e8a00498a5..b8790b07f2a 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -1621,7 +1621,7 @@ export const de: Record = { "integrations.semantics.raycast": "Fügt einen OpenCodex-Provider-Eintrag in die providers.yaml von Raycast ein, damit jedes geroutete Modell in der Modellauswahl von Raycast AI erscheint. Raycast Pro erforderlich.", "integrations.semantics.omo": "Verwaltet ausschließlich providers.opencodex in der models.json von omo — ~/.omo/agent, sofern nicht OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR oder PI_CODING_AGENT_DIR sie umleitet. Ihre übrigen Provider bleiben unverändert. Gilt ab neuen Sitzungen.", "integrations.semantics.cline": "Verwaltet OpenCodex in providers.json und models.json der Cline CLI. Beenden Sie Cline vor Änderungen oder Synchronisierung und starten Sie es danach neu. Rückgängig stellt beide Originaldateien wieder her. Ihr Standardanbieter bleibt unverändert; wählen Sie OpenCodex in Cline.", - "integrations.semantics.kilo": "Verwaltet nur provider.opencodex in Kilos globaler Konfiguration (erste vorhandene Datei unter kilo.jsonc, kilo.json, opencode.jsonc, opencode.json oder config.json in ~/.config/kilo). Andere Schlüssel bleiben unverändert. Anwenden schreibt die ganze Datei neu, daher bleiben Kommentare und nachgestellte Kommas nicht erhalten. Wählen Sie opencodex/ in Kilo.", + "integrations.semantics.kilo": "Verwaltet nur provider.opencodex in Kilos globaler Konfiguration — die erste vorhandene Datei unter kilo.jsonc, kilo.json, opencode.jsonc, opencode.json oder config.json in ~/.config/kilo (XDG_CONFIG_HOME verschiebt dieses Verzeichnis; ist keine vorhanden, wird kilo.jsonc erstellt). Andere Schlüssel bleiben unverändert. Anwenden schreibt die ganze Datei neu, daher bleiben Kommentare und nachgestellte Kommas nicht erhalten. Wählen Sie opencodex/ in Kilo.", "integrations.raycast.proRequired": "Custom Providers ist eine Funktion von Raycast Pro. Die Datei wird geschrieben, aber Raycast ignoriert sie, bis ein Pro-Abonnement aktiv ist.", "integrations.raycast.planUnknown": "Es konnte nicht festgestellt werden, ob Raycast Pro aktiv ist; Custom Providers erfordert Raycast Pro.", "integrations.raycast.revealConfig": "Öffnen Sie Raycast → Einstellungen → AI und klicken Sie einmal auf „Reveal Providers Config“, damit der Providers-Ordner existiert.", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index d68f613c0d7..3a518a84ed2 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -2209,7 +2209,7 @@ export const en = { "integrations.semantics.raycast": "Adds an OpenCodex provider entry to Raycast's providers.yaml so every routed model appears in the Raycast AI model picker. Raycast Pro required.", "integrations.semantics.omo": "Manages only providers.opencodex in omo's models.json — ~/.omo/agent unless OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR or PI_CODING_AGENT_DIR redirects it. Your other providers stay unchanged. Applies to new sessions.", "integrations.semantics.cline": "Manages OpenCodex in Cline CLI providers.json and models.json. Stop Cline before changing or syncing these files, then restart. Undo restores both originals. Your default provider stays unchanged; select OpenCodex in Cline.", - "integrations.semantics.kilo": "Manages only provider.opencodex in Kilo's global config (first existing kilo.jsonc, kilo.json, opencode.jsonc, opencode.json, or config.json under ~/.config/kilo). Other keys stay unchanged. Apply rewrites the whole file, so comments and trailing commas are not preserved. Select opencodex/ in Kilo.", + "integrations.semantics.kilo": "Manages only provider.opencodex in Kilo's global config — the first existing file among kilo.jsonc, kilo.json, opencode.jsonc, opencode.json, or config.json under ~/.config/kilo (XDG_CONFIG_HOME relocates that directory; kilo.jsonc is created when none exist). Other keys stay unchanged. Apply rewrites the whole file, so comments and trailing commas are not preserved. Select opencodex/ in Kilo.", "integrations.raycast.proRequired": "Custom Providers is a Raycast Pro feature. The file will be written, but Raycast ignores it until a Pro subscription is active.", "integrations.raycast.planUnknown": "Could not determine whether Raycast Pro is active; Custom Providers requires Raycast Pro.", "integrations.raycast.revealConfig": "Open Raycast → Settings → AI and click Reveal Providers Config once so the providers folder exists.", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index 1cc84f4965f..327cb089347 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -2141,7 +2141,7 @@ export const fr: Record = { "integrations.semantics.raycast": "Ajoute une entrée de fournisseur OpenCodex dans le providers.yaml de Raycast afin que chaque modèle routé apparaisse dans le sélecteur de modèles de Raycast AI. Raycast Pro requis.", "integrations.semantics.omo": "Gère uniquement providers.opencodex dans le models.json d'omo — ~/.omo/agent, sauf redirection par OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR ou PI_CODING_AGENT_DIR. Vos autres fournisseurs restent inchangés. S'applique aux nouvelles sessions.", "integrations.semantics.cline": "Gère OpenCodex dans providers.json et models.json de Cline CLI. Quittez Cline avant toute modification ou synchronisation, puis redémarrez-le. Annuler restaure les deux fichiers originaux. Votre fournisseur par défaut reste inchangé ; sélectionnez OpenCodex dans Cline.", - "integrations.semantics.kilo": "Gère uniquement provider.opencodex dans la configuration globale de Kilo (premier fichier existant parmi kilo.jsonc, kilo.json, opencode.jsonc, opencode.json ou config.json sous ~/.config/kilo). Les autres clés restent inchangées. Appliquer réécrit tout le fichier : commentaires et virgules finales ne sont pas conservés. Sélectionnez opencodex/ dans Kilo.", + "integrations.semantics.kilo": "Gère uniquement provider.opencodex dans la configuration globale de Kilo — le premier fichier existant parmi kilo.jsonc, kilo.json, opencode.jsonc, opencode.json ou config.json sous ~/.config/kilo (XDG_CONFIG_HOME déplace ce répertoire ; kilo.jsonc est créé si aucun n'existe). Les autres clés restent inchangées. Appliquer réécrit tout le fichier : commentaires et virgules finales ne sont pas conservés. Sélectionnez opencodex/ dans Kilo.", "integrations.raycast.proRequired": "Custom Providers est une fonctionnalité Raycast Pro. Le fichier sera écrit, mais Raycast l'ignore tant qu'un abonnement Pro n'est pas actif.", "integrations.raycast.planUnknown": "Impossible de déterminer si Raycast Pro est actif ; Custom Providers nécessite Raycast Pro.", "integrations.raycast.revealConfig": "Ouvrez Raycast → Réglages → AI et cliquez une fois sur « Reveal Providers Config » pour que le dossier des fournisseurs existe.", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 4381c6f0434..d29ae906ec1 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -2064,7 +2064,7 @@ export const ja: Record = { "integrations.semantics.raycast": "Raycast の providers.yaml に OpenCodex のプロバイダーエントリを追加し、ルーティングされたすべてのモデルを Raycast AI のモデル選択に表示します。Raycast Pro が必要です。", "integrations.semantics.omo": "omo の models.json にある providers.opencodex のみを管理します。場所は ~/.omo/agent で、OMO_CODING_AGENT_DIR・SENPI_CODING_AGENT_DIR・PI_CODING_AGENT_DIR のいずれかが設定されている場合はそちらが優先されます。他のプロバイダーは変更しません。新しいセッションから適用されます。", "integrations.semantics.cline": "Cline CLI の providers.json と models.json の OpenCodex 項目を管理します。変更・同期前に Cline を終了し、完了後に再起動してください。元に戻すと両方の元ファイルが復元されます。既定のプロバイダーは変わりません。Cline で OpenCodex を選択してください。", - "integrations.semantics.kilo": "Kilo のグローバル設定(~/.config/kilo 配下で最初に存在する kilo.jsonc、kilo.json、opencode.jsonc、opencode.json、config.json)の provider.opencodex のみを管理します。他のキーは変更しません。適用時にファイル全体を書き直すため、コメントと末尾カンマは保持されません。Kilo で opencodex/<モデル> を選択してください。", + "integrations.semantics.kilo": "Kilo のグローバル設定(~/.config/kilo 配下で最初に存在する kilo.jsonc、kilo.json、opencode.jsonc、opencode.json、config.json。XDG_CONFIG_HOME はこのディレクトリを移動し、いずれも存在しなければ kilo.jsonc が作成されます)の provider.opencodex のみを管理します。他のキーは変更しません。適用時にファイル全体を書き直すため、コメントと末尾カンマは保持されません。Kilo で opencodex/<モデル> を選択してください。", "integrations.raycast.proRequired": "Custom Providers は Raycast Pro の機能です。ファイルは書き込まれますが、Pro サブスクリプションが有効になるまで Raycast はこれを無視します。", "integrations.raycast.planUnknown": "Raycast Pro が有効かどうか確認できませんでした。Custom Providers には Raycast Pro が必要です。", "integrations.raycast.revealConfig": "Raycast → 設定 → AI を開き、「Reveal Providers Config」を一度クリックして providers フォルダを作成してください。", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 1ec06eef3db..324bc053d66 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -1657,7 +1657,7 @@ export const ko: Record = { "integrations.semantics.raycast": "Raycast의 providers.yaml에 OpenCodex 프로바이더 항목을 추가해 라우팅된 모든 모델이 Raycast AI 모델 선택기에 표시되도록 합니다. Raycast Pro가 필요합니다.", "integrations.semantics.omo": "omo의 models.json에서 providers.opencodex만 관리합니다. 위치는 ~/.omo/agent이며 OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR, PI_CODING_AGENT_DIR 중 설정된 값이 있으면 그쪽이 우선합니다. 다른 프로바이더는 그대로 유지됩니다. 새 세션부터 적용됩니다.", "integrations.semantics.cline": "Cline CLI의 providers.json과 models.json에서 OpenCodex 항목을 관리합니다. 변경·동기화 전에 Cline을 종료하고 완료 후 다시 실행하세요. 되돌리기는 두 파일의 원본을 복원합니다. 기본 프로바이더는 유지되므로 Cline에서 OpenCodex를 선택하세요.", - "integrations.semantics.kilo": "Kilo 전역 설정(~/.config/kilo에서 먼저 존재하는 kilo.jsonc, kilo.json, opencode.jsonc, opencode.json, config.json)의 provider.opencodex만 관리합니다. 다른 키는 그대로 둡니다. 적용 시 파일 전체를 다시 쓰므로 주석과 후행 쉼표는 보존되지 않습니다. Kilo에서 opencodex/<모델>을 선택하세요.", + "integrations.semantics.kilo": "Kilo 전역 설정(~/.config/kilo에서 먼저 존재하는 kilo.jsonc, kilo.json, opencode.jsonc, opencode.json, config.json. XDG_CONFIG_HOME는 이 디렉터리를 이동하며, 아무것도 없으면 kilo.jsonc가 생성됨)의 provider.opencodex만 관리합니다. 다른 키는 그대로 둡니다. 적용 시 파일 전체를 다시 쓰므로 주석과 후행 쉼표는 보존되지 않습니다. Kilo에서 opencodex/<모델>을 선택하세요.", "integrations.raycast.proRequired": "Custom Providers는 Raycast Pro 기능입니다. 파일은 기록되지만 Pro 구독이 활성화될 때까지 Raycast는 이를 무시합니다.", "integrations.raycast.planUnknown": "Raycast Pro 활성 여부를 확인할 수 없습니다. Custom Providers에는 Raycast Pro가 필요합니다.", "integrations.raycast.revealConfig": "Raycast → 설정 → AI를 열고 「Reveal Providers Config」를 한 번 클릭해 providers 폴더를 만드세요.", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 2368a18005f..e8d92ca5746 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -2136,7 +2136,7 @@ export const ru: Record = { "integrations.semantics.raycast": "Добавляет запись провайдера OpenCodex в providers.yaml Raycast, чтобы каждая маршрутизируемая модель появилась в выборе моделей Raycast AI. Требуется Raycast Pro.", "integrations.semantics.omo": "Управляет только providers.opencodex в models.json omo — ~/.omo/agent, если только OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR или PI_CODING_AGENT_DIR не перенаправляет путь. Остальные провайдеры остаются без изменений. Применяется к новым сессиям.", "integrations.semantics.cline": "Управляет OpenCodex в файлах providers.json и models.json Cline CLI. Закройте Cline перед изменением или синхронизацией и запустите снова после завершения. Отмена восстанавливает оба исходных файла. Провайдер по умолчанию не меняется; выберите OpenCodex в Cline.", - "integrations.semantics.kilo": "Управляет только provider.opencodex в глобальной конфигурации Kilo (первый существующий файл среди kilo.jsonc, kilo.json, opencode.jsonc, opencode.json или config.json в ~/.config/kilo). Остальные ключи не меняются. Применение перезаписывает весь файл, поэтому комментарии и завершающие запятые не сохраняются. Выберите opencodex/<модель> в Kilo.", + "integrations.semantics.kilo": "Управляет только provider.opencodex в глобальной конфигурации Kilo — первый существующий файл среди kilo.jsonc, kilo.json, opencode.jsonc, opencode.json или config.json в ~/.config/kilo (XDG_CONFIG_HOME переносит этот каталог; если файла нет, создаётся kilo.jsonc). Остальные ключи не меняются. Применение перезаписывает весь файл, поэтому комментарии и завершающие запятые не сохраняются. Выберите opencodex/<модель> в Kilo.", "integrations.raycast.proRequired": "Custom Providers — функция Raycast Pro. Файл будет записан, но Raycast игнорирует его, пока не активна подписка Pro.", "integrations.raycast.planUnknown": "Не удалось определить, активен ли Raycast Pro; для Custom Providers требуется Raycast Pro.", "integrations.raycast.revealConfig": "Откройте Raycast → Настройки → AI и один раз нажмите «Reveal Providers Config», чтобы папка провайдеров появилась.", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 1927eb25148..6c97d861b4e 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -2154,7 +2154,7 @@ export const tr: Record = { "integrations.semantics.raycast": "Raycast'in providers.yaml dosyasına bir OpenCodex sağlayıcı girdisi ekler; böylece yönlendirilen her model Raycast AI model seçicisinde görünür. Raycast Pro gerekir.", "integrations.semantics.omo": "Yalnızca omo'nun models.json dosyasındaki providers.opencodex girdisini yönetir — OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR veya PI_CODING_AGENT_DIR yönlendirmediği sürece ~/.omo/agent. Diğer sağlayıcılarınız değişmeden kalır. Yeni oturumlardan itibaren geçerlidir.", "integrations.semantics.cline": "Cline CLI providers.json ve models.json dosyalarındaki OpenCodex girdilerini yönetir. Değişiklik veya eşitleme öncesinde Cline’ı kapatın, ardından yeniden başlatın. Geri al iki özgün dosyayı da geri yükler. Varsayılan sağlayıcınız değişmez; Cline içinde OpenCodex’i seçin.", - "integrations.semantics.kilo": "Yalnızca Kilo’nun genel yapılandırmasındaki ( ~/.config/kilo altında ilk bulunan kilo.jsonc, kilo.json, opencode.jsonc, opencode.json veya config.json) provider.opencodex öğesini yönetir. Diğer anahtarlar değişmez. Uygula dosyanın tamamını yeniden yazar; yorumlar ve sondaki virgüller korunmaz. Kilo’da opencodex/ seçin.", + "integrations.semantics.kilo": "Yalnızca Kilo’nun genel yapılandırmasındaki provider.opencodex öğesini yönetir — ~/.config/kilo altındaki ilk bulunan kilo.jsonc, kilo.json, opencode.jsonc, opencode.json veya config.json (XDG_CONFIG_HOME bu dizini taşır; hiçbiri yoksa kilo.jsonc oluşturulur). Diğer anahtarlar değişmez. Uygula dosyanın tamamını yeniden yazar; yorumlar ve sondaki virgüller korunmaz. Kilo’da opencodex/ seçin.", "integrations.raycast.proRequired": "Custom Providers bir Raycast Pro özelliğidir. Dosya yazılır, ancak bir Pro aboneliği etkin olana kadar Raycast bunu yok sayar.", "integrations.raycast.planUnknown": "Raycast Pro’nun etkin olup olmadığı belirlenemedi; Custom Providers için Raycast Pro gerekir.", "integrations.raycast.revealConfig": "Raycast → Ayarlar → AI bölümünü açıp sağlayıcı klasörünün oluşması için „Reveal Providers Config“ seçeneğine bir kez tıklayın.", diff --git a/gui/src/i18n/vi.ts b/gui/src/i18n/vi.ts index a18adfab605..61c3408eb2e 100644 --- a/gui/src/i18n/vi.ts +++ b/gui/src/i18n/vi.ts @@ -2164,7 +2164,7 @@ export const vi: Record = { "integrations.semantics.raycast": "Thêm một provider OpenCodex vào providers.yaml của Raycast để mọi model được định tuyến xuất hiện trong bộ chọn model AI của Raycast. Yêu cầu Raycast Pro.", "integrations.semantics.omo": "Chỉ quản lý providers.opencodex trong models.json của omo — ~/.omo/agent, trừ khi OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR hoặc PI_CODING_AGENT_DIR chuyển hướng. Các nhà cung cấp khác của bạn không thay đổi. Áp dụng cho phiên mới.", "integrations.semantics.cline": "Quản lý OpenCodex trong providers.json và models.json của Cline CLI. Hãy dừng Cline trước khi thay đổi hoặc đồng bộ các tệp này, rồi khởi động lại. Hoàn tác sẽ khôi phục cả hai bản gốc. Nhà cung cấp mặc định của bạn không thay đổi; hãy chọn OpenCodex trong Cline.", - "integrations.semantics.kilo": "Chỉ quản lý provider.opencodex trong cấu hình toàn cục của Kilo (tệp tồn tại đầu tiên trong kilo.jsonc, kilo.json, opencode.jsonc, opencode.json hoặc config.json dưới ~/.config/kilo). Các khóa khác giữ nguyên. Áp dụng ghi lại toàn bộ tệp nên chú thích và dấu phẩy cuối không được giữ. Chọn opencodex/ trong Kilo.", + "integrations.semantics.kilo": "Chỉ quản lý provider.opencodex trong cấu hình toàn cục của Kilo — tệp tồn tại đầu tiên trong kilo.jsonc, kilo.json, opencode.jsonc, opencode.json hoặc config.json dưới ~/.config/kilo (XDG_CONFIG_HOME chuyển thư mục này; nếu không tệp nào tồn tại, kilo.jsonc sẽ được tạo). Các khóa khác giữ nguyên. Áp dụng ghi lại toàn bộ tệp nên chú thích và dấu phẩy cuối không được giữ. Chọn opencodex/ trong Kilo.", "integrations.raycast.proRequired": "Custom Providers là một tính năng của Raycast Pro. File sẽ được ghi, nhưng Raycast sẽ bỏ qua nó cho đến khi đăng ký Pro được kích hoạt.", "integrations.raycast.planUnknown": "Không thể xác định xem Raycast Pro có đang hoạt động hay không; Custom Providers yêu cầu Raycast Pro.", "integrations.raycast.revealConfig": "Mở Raycast → Settings → AI và nhấp vào Reveal Providers Config một lần để thư mục providers được tạo.", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 9016b3d0945..82eea9be002 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2943,7 +2943,7 @@ export const zhTW: Record = { "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中新增一個 OpenCodex 供應商項目,讓所有已路由的模型出現在 Raycast AI 模型選擇器中。需要 Raycast Pro。", "integrations.semantics.omo": "僅管理 omo 的 models.json 中的 providers.opencodex,路徑為 ~/.omo/agent,若設定了 OMO_CODING_AGENT_DIR、SENPI_CODING_AGENT_DIR 或 PI_CODING_AGENT_DIR 則以其為準。你的其他供應商維持不變。對新工作階段生效。", "integrations.semantics.cline": "管理 Cline CLI 的 providers.json 和 models.json 中的 OpenCodex 項目。修改或同步前請結束 Cline,完成後重新啟動。復原會還原兩個檔案的原始內容。預設供應商保持不變,請在 Cline 中選擇 OpenCodex。", - "integrations.semantics.kilo": "僅管理 Kilo 全域設定(~/.config/kilo 下最先存在的 kilo.jsonc、kilo.json、opencode.jsonc、opencode.json 或 config.json)中的 provider.opencodex。其他鍵保持不變。套用會重寫整個檔案,因此不會保留註解與尾隨逗號。請在 Kilo 中選擇 opencodex/<模型>。", + "integrations.semantics.kilo": "僅管理 Kilo 全域設定——~/.config/kilo 下最先存在的 kilo.jsonc、kilo.json、opencode.jsonc、opencode.json 或 config.json(XDG_CONFIG_HOME 會移動該目錄;若都不存在則建立 kilo.jsonc)——中的 provider.opencodex。其他鍵保持不變。套用會重寫整個檔案,因此不會保留註解與尾隨逗號。請在 Kilo 中選擇 opencodex/<模型>。", "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。檔案會被寫入,但在 Pro 訂閱生效之前 Raycast 會忽略它。", "integrations.raycast.planUnknown": "無法確認 Raycast Pro 是否已啟用;Custom Providers 需要 Raycast Pro。", "integrations.raycast.revealConfig": "開啟 Raycast → 設定 → AI,點一次「Reveal Providers Config」,以便建立 providers 資料夾。", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index afd7a514886..b495a32eb83 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -1638,7 +1638,7 @@ export const zh: Record = { "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中添加一个 OpenCodex 提供商条目,让所有已路由的模型出现在 Raycast AI 模型选择器中。需要 Raycast Pro。", "integrations.semantics.omo": "仅管理 omo 的 models.json 中的 providers.opencodex,路径为 ~/.omo/agent,若设置了 OMO_CODING_AGENT_DIR、SENPI_CODING_AGENT_DIR 或 PI_CODING_AGENT_DIR 则以其为准。你的其他提供商保持不变。对新会话生效。", "integrations.semantics.cline": "管理 Cline CLI 的 providers.json 和 models.json 中的 OpenCodex 项目。修改或同步前请退出 Cline,完成后重新启动。撤销会恢复两个文件的原始内容。默认提供商保持不变,请在 Cline 中选择 OpenCodex。", - "integrations.semantics.kilo": "仅管理 Kilo 全局配置(~/.config/kilo 下最先存在的 kilo.jsonc、kilo.json、opencode.jsonc、opencode.json 或 config.json)中的 provider.opencodex。其他键保持不变。应用会重写整个文件,因此不会保留注释和尾随逗号。请在 Kilo 中选择 opencodex/<模型>。", + "integrations.semantics.kilo": "仅管理 Kilo 全局配置——~/.config/kilo 下最先存在的 kilo.jsonc、kilo.json、opencode.jsonc、opencode.json 或 config.json(XDG_CONFIG_HOME 会移动该目录;若都不存在则创建 kilo.jsonc)——中的 provider.opencodex。其他键保持不变。应用会重写整个文件,因此不会保留注释和尾随逗号。请在 Kilo 中选择 opencodex/<模型>。", "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。文件会被写入,但在 Pro 订阅生效之前 Raycast 会忽略它。", "integrations.raycast.planUnknown": "无法确定 Raycast Pro 是否已激活;Custom Providers 需要 Raycast Pro。", "integrations.raycast.revealConfig": "打开 Raycast → 设置 → AI,点击一次“Reveal Providers Config”,以便创建 providers 文件夹。", diff --git a/src/integrations/mutation-plan.ts b/src/integrations/mutation-plan.ts index b1157c97df1..a49cd8c2189 100644 --- a/src/integrations/mutation-plan.ts +++ b/src/integrations/mutation-plan.ts @@ -851,6 +851,12 @@ export function observeIntegration(input: IntegrationWriteInput, effects: Observ * target is known, because that is the path it has to match. */ stored = store.readRecords()[clientId] ?? null; + const recordedPath = stored?.clientId === clientId + && stored.configPath !== resolved.configPath + && io.statKind(stored.configPath) === "file" + && spec.bindsDriftedRecord?.(stored.configPath, input.env, input.home) === true + ? stored.configPath + : resolved.configPath; /* * Inside the same guard as resolution, because this resolver can refuse the * same way: the store is named by a client env var, and a relative one is a @@ -858,7 +864,7 @@ export function observeIntegration(input: IntegrationWriteInput, effects: Observ * collection route. */ effective = resolveIntegrationTarget({ - clientId, configPath: resolved.configPath, io, record: stored, env: input.env, home: input.home, + clientId, configPath: recordedPath, io, record: stored, env: input.env, home: input.home, }); configPath = effective.configPath; } catch (error) { diff --git a/src/integrations/registry.ts b/src/integrations/registry.ts index 7230ef126aa..569323eecff 100644 --- a/src/integrations/registry.ts +++ b/src/integrations/registry.ts @@ -50,6 +50,7 @@ import { type ConfigFormat, kiloConfigPath, kiloHomeDir, + KILO_CONFIG_CANDIDATES, type ExportClientId, } from "../clients/config-export"; @@ -117,6 +118,19 @@ export interface IntegrationClientSpec { * catalog. `resolveIntegrationPaths` still throws for callers that mutate. */ unresolvedPathHint?: (env?: NodeJS.ProcessEnv, home?: string) => string; + /** + * Recognize a resolution drift that is still THIS client's own file, for a + * client whose config path depends on mutable world state rather than only + * env and home. + * + * Kilo resolves to the first EXISTING candidate, so a candidate created + * after apply moves resolution while the owned file still holds our block. + * While this predicate accepts the recorded path, reads and mutations stay + * bound to it instead of silently re-homing onto the newcomer. A client + * without this hook never binds: a record from another home stays a refusal + * ("a record for one home cannot authorize a write to another"). + */ + bindsDriftedRecord?: (recordPath: string, env?: NodeJS.ProcessEnv, home?: string) => boolean; } /** @@ -351,6 +365,8 @@ export const INTEGRATION_CLIENTS: Record kiloConfigPath(env, home), detectDir: (env = process.env, home = homedir()) => kiloHomeDir(env, home), + bindsDriftedRecord: (recordPath, env = process.env, home = homedir()) => + KILO_CONFIG_CANDIDATES.some(name => recordPath === join(kiloHomeDir(env, home), name)), }, }; diff --git a/src/integrations/state.ts b/src/integrations/state.ts index 42546347699..cd0549a3900 100644 --- a/src/integrations/state.ts +++ b/src/integrations/state.ts @@ -530,8 +530,14 @@ export function readIntegrationState(input: IntegrationStateInput): IntegrationS * would let the badge and the switch disagree. */ record = store.readRecords()[input.clientId] ?? null; + const recordedPath = record?.clientId === input.clientId + && record.configPath !== paths.configPath + && io.statKind(record.configPath) === "file" + && spec.bindsDriftedRecord?.(record.configPath, input.env, input.home) === true + ? record.configPath + : paths.configPath; effective = resolveIntegrationTarget({ - clientId: input.clientId, configPath: paths.configPath, io, record, env: input.env, home: input.home, + clientId: input.clientId, configPath: recordedPath, io, record, env: input.env, home: input.home, }); } catch (error) { if (!(error instanceof ClientPathError)) throw error; diff --git a/src/lib/jsonc.ts b/src/lib/jsonc.ts index 8f714e7df4e..34f63158ec5 100644 --- a/src/lib/jsonc.ts +++ b/src/lib/jsonc.ts @@ -1,8 +1,8 @@ /** * JSONC parse used by OpenCode's launcher and Kilo's managed writer. * - * Strict JSON.parse runs first and untouched — the tolerant path is only - * attempted when that throws, keeping well-formed configs away from the stripper. + * Comments and trailing commas are stripped by escape-aware passes that are + * identity on valid strict JSON, so no strict-parse probe is ever needed. */ /** @@ -45,6 +45,12 @@ function stripJsonComments(text: string): string { if (ch === "/" && next === "*") { inBlock = true; i++; continue; } out += ch; } + /* + * An unterminated block comment means the remainder of the document was + * comment text. Returning it stripped would let a trailing `/*` delete an + * arbitrary malformed tail, so the caller sees a parse failure instead. + */ + if (inBlock) throw new SyntaxError("Unterminated block comment"); return out; } @@ -76,21 +82,20 @@ function stripTrailingCommas(text: string): string { } /** - * Return JSON that `JSON.parse` will accept. Strict text is returned untouched; - * comments and trailing commas are stripped only when the strict parse throws. + * Return JSON that `JSON.parse` will accept. Comments and trailing commas are + * stripped unconditionally: never probed with a strict `JSON.parse` first, + * because materializing a deeply nested document before the rewrite guard's + * depth ceiling would bypass that guard's resource contract. The passes are + * identity on valid strict JSON — `//`, `/*`, and a comma before `}` or `]` + * can only appear inside strings there, which the strippers never touch. */ export function canonicalizeJsonc(text: string): string { - try { - JSON.parse(text); - return text; - } catch { - return stripTrailingCommas(stripJsonComments(text)); - } + return stripTrailingCommas(stripJsonComments(text)); } /** - * JSON with optional comments and trailing commas. Strict JSON.parse runs first - * and untouched — the tolerant path is only attempted when that throws. + * JSON with optional comments and trailing commas. Same stripping rules as + * `canonicalizeJsonc`; throws on text that is still not JSON afterwards. */ export function parseJsonc(text: string): unknown { return JSON.parse(canonicalizeJsonc(text)); diff --git a/structure/clients/integrations.md b/structure/clients/integrations.md index 6b081a81521..1e6621b2f47 100644 --- a/structure/clients/integrations.md +++ b/structure/clients/integrations.md @@ -384,6 +384,15 @@ commas; serialize rewrites the whole file as pretty JSON, so comments in other k not preserved. Kilo is not on the implicit owned-catalog fan-out. Remote admission uses the same `{env:OPENCODEX_KILO_API_KEY}` / `x-opencodex-api-key` rule as OpenCode. +Because that resolution depends on which candidates EXIST, a candidate created after +apply can win discovery while the owned file still holds the block. The registry's +opt-in `bindsDriftedRecord` seam covers exactly that case: while the recorded path is +still one of Kilo's own candidates under the current env and home, reads and mutations +stay bound to the recorded file (status reports it, disable removes the block from it) +and priority discovery resumes only once the record is dropped. A record from a +different home never binds, preserving the audit contract that a record for one home +cannot authorize a write to another. + ## Cline paired files Cline CLI uses `providers.json` for connection settings and sibling `models.json` for its diff --git a/tests/clients/kilo-client.test.ts b/tests/clients/kilo-client.test.ts index 3fc97f8f2ce..f14608fa1b0 100644 --- a/tests/clients/kilo-client.test.ts +++ b/tests/clients/kilo-client.test.ts @@ -18,6 +18,7 @@ import type { KiloGeneratedConfig } from "../../src/clients/config-export/kilo"; import { PARSE_FAILED, parseConfig } from "../../src/integrations/config-io"; import { INTEGRATION_CLIENTS } from "../../src/integrations/registry"; import { createIntegrationStateStore, type IntegrationStateStore } from "../../src/integrations/store"; +import { readIntegrationState } from "../../src/integrations/state"; import { applyIntegration, disableIntegration, restoreIntegration } from "../../src/integrations/writer"; import type { OcxConfig } from "../../src/types"; import { removeTreeWithRetry } from "../helpers/remove-tree"; @@ -199,4 +200,71 @@ describe("kilo JSONC apply/disable/restore", () => { const restored = restoreIntegration({ ...write, opId: store.listOperations("kilo")[0]!.opId }); expect(restored.ok).toBe(true); }); + + test("an unterminated block comment is PARSE_FAILED, and apply refuses without touching the file", () => { + const spec = INTEGRATION_CLIENTS.kilo; + mkdirSync(spec.detectDir({}, home), { recursive: true }); + const configPath = spec.configPath({}, home); + const poisoned = '{\n "model": "keep",\n /* never closed\n'; + writeFileSync(configPath, poisoned); + + // Stripping an unterminated block comment would delete the malformed tail; + // the stripper throws instead so the rewrite gate sees a parse failure. + expect(parseConfig(poisoned, "json", { jsonc: true })).toBe(PARSE_FAILED); + + const applied = applyIntegration({ + clientId: "kilo", models: context().models, config: LOOPBACK, + port: 10100, env: {} as NodeJS.ProcessEnv, home, store, + }); + expect(applied.ok).toBe(false); + expect(readFileSync(configPath, "utf8")).toBe(poisoned); + }); + + test("lifecycle stays bound to the owned file when a higher-priority candidate appears", () => { + /* + * Resolution picks the first EXISTING candidate, so apply can own + * config.json while a later-created kilo.jsonc wins discovery. The + * ownership record then binds reads and mutations to config.json while + * it still exists: status reports it, disable removes OUR block from it, + * and the newcomer is never touched. Only after the record is dropped + * does priority discovery pick kilo.jsonc up again. + */ + const spec = INTEGRATION_CLIENTS.kilo; + const dir = spec.detectDir({}, home); + mkdirSync(dir, { recursive: true }); + const ownedPath = join(dir, "config.json"); + writeFileSync(ownedPath, "{}\n"); + + const write = { + clientId: "kilo" as const, + models: context().models, + config: LOOPBACK, + port: 10100, + env: {} as NodeJS.ProcessEnv, + home, + store, + }; + expect(applyIntegration(write).ok).toBe(true); + const owned = readFileSync(ownedPath, "utf8"); + expect(owned).toContain(OPENCODE_PROVIDER_ID); + + const newcomer = join(dir, "kilo.jsonc"); + const newcomerText = '{ "model": "keep" }\n'; + writeFileSync(newcomer, newcomerText); + + const bound = readIntegrationState(write); + expect(bound.state).toBe("current"); + expect(bound.configPath).toBe(ownedPath); + + const disabled = disableIntegration(write); + expect(disabled.ok).toBe(true); + const afterDisable = JSON.parse(readFileSync(ownedPath, "utf8")) as { provider?: Record }; + expect(afterDisable.provider?.[OPENCODE_PROVIDER_ID]).toBeUndefined(); + expect(readFileSync(newcomer, "utf8")).toBe(newcomerText); + + // Record dropped: discovery is priority again, pointing at the newcomer. + const released = readIntegrationState(write); + expect(released.state).toBe("absent"); + expect(released.configPath).toBe(newcomer); + }); }); From 01844ae38a3a57c8ec5a91c6517531c2dbacca4c Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 20 Sep 2026 15:57:09 +0800 Subject: [PATCH 3/9] fix(clients): keep block comments as token separators in JSONC A block comment between two digits collapsed into nothing, turning 1 slash-star x star-slash 2 into 12: a malformed Kilo value would pass the rewrite gate as a different valid one. Emit a space where the comment was, which is identity for every valid JSONC document, and cover both sides with regression tests. --- src/lib/jsonc.ts | 10 +++++++++- tests/clients/kilo-client.test.ts | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/lib/jsonc.ts b/src/lib/jsonc.ts index 34f63158ec5..dda3c392eb7 100644 --- a/src/lib/jsonc.ts +++ b/src/lib/jsonc.ts @@ -27,7 +27,15 @@ function stripJsonComments(text: string): string { if (inBlock) { // Newlines are preserved so JSON.parse error positions stay meaningful. if (ch === "\n") out += ch; - else if (ch === "*" && next === "/") { inBlock = false; i++; } + else if (ch === "*" && next === "/") { + // Emit a separator, not nothing: a block comment between two digits is + // two tokens and must not collapse into one, which would silently + // change a malformed value into a different valid one. Whitespace is + // legal wherever a comment was, so this is identity for valid JSONC. + out += " "; + inBlock = false; + i++; + } continue; } if (inString) { diff --git a/tests/clients/kilo-client.test.ts b/tests/clients/kilo-client.test.ts index f14608fa1b0..5882ee908f6 100644 --- a/tests/clients/kilo-client.test.ts +++ b/tests/clients/kilo-client.test.ts @@ -201,6 +201,15 @@ describe("kilo JSONC apply/disable/restore", () => { expect(restored.ok).toBe(true); }); + test("a block comment is a token separator, not deletion: malformed values refuse", () => { + // `1/*x*/2` is two tokens; stripping the comment to nothing would yield + // `12` — a different valid value. The stripper keeps a separator, so the + // rewrite gate sees a parse failure instead of a changed user value. + expect(parseConfig('{"value":1/*c*/2}', "json", { jsonc: true })).toBe(PARSE_FAILED); + // Where a comment was, whitespace is legal: valid JSONC is unaffected. + expect(parseConfig('{"value": 1 /* keep */ , "b": [1,/*c*/2]}', "json", { jsonc: true })).toEqual({ value: 1, b: [1, 2] }); + }); + test("an unterminated block comment is PARSE_FAILED, and apply refuses without touching the file", () => { const spec = INTEGRATION_CLIENTS.kilo; mkdirSync(spec.detectDir({}, home), { recursive: true }); From 4bdf04535daf4056e0587cf70e232fb3b51c1af7 Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 20 Sep 2026 16:20:08 +0800 Subject: [PATCH 4/9] fix(clients): bind Kilo restore paths to the journaled candidate Restore and its preview refused when fresh first-existing discovery had moved on from the journaled file, even though the disable/apply side had just been bound. The same opt-in bindsDriftedRecord exception now lets a journaled Kilo candidate restore against the journaled file; a path outside the current Kilo home still refuses, keeping the one-home contract. Covers direct restore and restore preview with regression tests. --- src/integrations/target.ts | 3 +++ structure/clients/integrations.md | 5 ++-- tests/clients/kilo-client.test.ts | 39 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/integrations/target.ts b/src/integrations/target.ts index 3a62d9feee5..40840dafbae 100644 --- a/src/integrations/target.ts +++ b/src/integrations/target.ts @@ -194,6 +194,9 @@ export function declaredIntegrationTarget(args: { }): IntegrationTarget | null { const { clientId, configPath, resolvedConfigPath } = args; if (configPath === resolvedConfigPath) return configFileTarget(clientId, configPath, null); + if (INTEGRATION_CLIENTS[clientId].bindsDriftedRecord?.(configPath, args.env, args.home) === true) { + return configFileTarget(clientId, configPath, null); + } const declared = INTEGRATION_CLIENTS[clientId].currentStore; if (!declared) return null; try { diff --git a/structure/clients/integrations.md b/structure/clients/integrations.md index 1e6621b2f47..aea8b6614b2 100644 --- a/structure/clients/integrations.md +++ b/structure/clients/integrations.md @@ -388,8 +388,9 @@ Because that resolution depends on which candidates EXIST, a candidate created a apply can win discovery while the owned file still holds the block. The registry's opt-in `bindsDriftedRecord` seam covers exactly that case: while the recorded path is still one of Kilo's own candidates under the current env and home, reads and mutations -stay bound to the recorded file (status reports it, disable removes the block from it) -and priority discovery resumes only once the record is dropped. A record from a +stay bound to the recorded file (status reports it, disable removes the block from it, +and both restore paths act on the journaled file instead of refusing) and priority +discovery resumes only once the record is dropped. A record from a different home never binds, preserving the audit contract that a record for one home cannot authorize a write to another. diff --git a/tests/clients/kilo-client.test.ts b/tests/clients/kilo-client.test.ts index 5882ee908f6..99a65210e1f 100644 --- a/tests/clients/kilo-client.test.ts +++ b/tests/clients/kilo-client.test.ts @@ -19,6 +19,7 @@ import { PARSE_FAILED, parseConfig } from "../../src/integrations/config-io"; import { INTEGRATION_CLIENTS } from "../../src/integrations/registry"; import { createIntegrationStateStore, type IntegrationStateStore } from "../../src/integrations/store"; import { readIntegrationState } from "../../src/integrations/state"; +import { previewIntegration } from "../../src/integrations/mutation-plan"; import { applyIntegration, disableIntegration, restoreIntegration } from "../../src/integrations/writer"; import type { OcxConfig } from "../../src/types"; import { removeTreeWithRetry } from "../helpers/remove-tree"; @@ -276,4 +277,42 @@ describe("kilo JSONC apply/disable/restore", () => { expect(released.state).toBe("absent"); expect(released.configPath).toBe(newcomer); }); + + test("restore and its preview stay bound to the journaled file when a higher-priority candidate appears", () => { + const spec = INTEGRATION_CLIENTS.kilo; + const dir = spec.detectDir({}, home); + mkdirSync(dir, { recursive: true }); + const ownedPath = join(dir, "config.json"); + writeFileSync(ownedPath, "{}\n"); + + const write = { + clientId: "kilo" as const, + models: context().models, + config: LOOPBACK, + port: 10100, + env: {} as NodeJS.ProcessEnv, + home, + store, + }; + expect(applyIntegration(write).ok).toBe(true); + + const newcomer = join(dir, "kilo.jsonc"); + const newcomerText = '{ "model": "keep" }\n'; + writeFileSync(newcomer, newcomerText); + + expect(disableIntegration(write).ok).toBe(true); + const disableOp = store.listOperations("kilo")[0]!; + + // Fresh priority discovery now picks the newcomer; the journaled disable + // op names config.json, still one of Kilo's own candidates here, so both + // restore paths act on the journaled file instead of refusing. + const preview = previewIntegration(write, { operation: "restore", opId: disableOp.opId }); + expect(preview.refusalReason).toBeUndefined(); + expect(preview.canApply).toBe(true); + + const restored = restoreIntegration({ ...write, opId: disableOp.opId }); + expect(restored.ok).toBe(true); + expect(readFileSync(ownedPath, "utf8")).toContain(OPENCODE_PROVIDER_ID); + expect(readFileSync(newcomer, "utf8")).toBe(newcomerText); + }); }); From 5d4246739112452cd8be1e0eba6516f25f0e361e Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 20 Sep 2026 18:39:34 +0800 Subject: [PATCH 5/9] refactor(clients): promote JSONC tolerance to an ExportClientSpec flag Review feedback on #5272: the clientId === "kilo" branches at every parse site grow another equality for each new OpenCode-family client, and forgetting one blocks commented files as PARSE_FAILED. The spec now carries jsonc: true, and state plus both planner parse sites read it. Also collapses the record-path binding duplicated between readIntegrationState and observeIntegration into one boundIntegrationConfigPath helper, so status and the writer cannot drift apart on that rule again. --- src/clients/config-export.ts | 1 + src/clients/config-export/contracts.ts | 10 +++++++++ src/integrations/mutation-plan.ts | 15 ++++++------- src/integrations/registry.ts | 30 ++++++++++++++++++++++++++ src/integrations/state.ts | 14 ++++++------ 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/clients/config-export.ts b/src/clients/config-export.ts index bcc3e3893ae..ca014e47ecf 100644 --- a/src/clients/config-export.ts +++ b/src/clients/config-export.ts @@ -1602,6 +1602,7 @@ export const EXPORT_CLIENTS: Record = { summarize: summarizeKilo, buildContribution: buildKiloContribution, loopbackOnly: false, + jsonc: true, }, }; diff --git a/src/clients/config-export/contracts.ts b/src/clients/config-export/contracts.ts index dbffbc5b292..94d1e46e9bb 100644 --- a/src/clients/config-export/contracts.ts +++ b/src/clients/config-export/contracts.ts @@ -147,6 +147,16 @@ export interface ExportClientSpec { * reasoning as the Grok managed block's non-loopback refusal. */ loopbackOnly: boolean; + /** + * True when the destination file may carry comments and trailing commas + * even though `format` is "json" and serialization stays pretty JSON. + * + * Parse tolerates them by canonicalizing the text before the rewrite-safety + * scan (Kilo's kilo.jsonc). A spec flag rather than a client-name branch: + * the next OpenCode-family client opts in here instead of growing another + * `clientId ===` check at every parse site. + */ + jsonc?: boolean; } export interface PiModelEntry { diff --git a/src/integrations/mutation-plan.ts b/src/integrations/mutation-plan.ts index a49cd8c2189..7a4db1de338 100644 --- a/src/integrations/mutation-plan.ts +++ b/src/integrations/mutation-plan.ts @@ -26,6 +26,7 @@ import { parseClineDocument } from "./cline-document"; import { PARSE_FAILED, defaultIntegrationIO, loadTarget, parseConfig, type IntegrationIO } from "./config-io"; import { INTEGRATION_CLIENTS, + boundIntegrationConfigPath, isLoopbackOnly, resolveIntegrationPaths, type IntegrationClientId, @@ -744,7 +745,7 @@ function previewRestore(input: IntegrationWriteInput, request: PreviewRequest): ? {} : observed.clientId === "cline" ? parseClineDocument(observed.before) - : parseConfig(observed.before, observed.format, observed.clientId === "kilo" ? { jsonc: true } : undefined), + : parseConfig(observed.before, observed.format, EXPORT_CLIENTS[observed.clientId].jsonc ? { jsonc: true } : undefined), restore: { opId: observed.entry.opId, entry: observed.entry, @@ -851,12 +852,10 @@ export function observeIntegration(input: IntegrationWriteInput, effects: Observ * target is known, because that is the path it has to match. */ stored = store.readRecords()[clientId] ?? null; - const recordedPath = stored?.clientId === clientId - && stored.configPath !== resolved.configPath - && io.statKind(stored.configPath) === "file" - && spec.bindsDriftedRecord?.(stored.configPath, input.env, input.home) === true - ? stored.configPath - : resolved.configPath; + const recordedPath = boundIntegrationConfigPath({ + clientId, record: stored, resolvedPath: resolved.configPath, + statKind: io.statKind, env: input.env, home: input.home, + }); /* * Inside the same guard as resolution, because this resolver can refuse the * same way: the store is named by a client env var, and a relative one is a @@ -889,7 +888,7 @@ export function observeIntegration(input: IntegrationWriteInput, effects: Observ const before = loaded.before; const parsed = clientId === "cline" ? parseClineDocument(before) - : parseConfig(before, effective.format, clientId === "kilo" ? { jsonc: true } : undefined); + : parseConfig(before, effective.format, exportSpec.jsonc ? { jsonc: true } : undefined); if (parsed === PARSE_FAILED) { return { failed: observationFailure("unsafe", "unsafe", `${configPath} could not be parsed, or holds something opencodex cannot rewrite without changing it (a non-finite number, a large integer or a tiny one a rewrite would round, -0, a duplicate member, or nesting deeper than 1000 levels)`) } as const; diff --git a/src/integrations/registry.ts b/src/integrations/registry.ts index 569323eecff..36f0e25d0f3 100644 --- a/src/integrations/registry.ts +++ b/src/integrations/registry.ts @@ -373,6 +373,36 @@ export const INTEGRATION_CLIENTS: Record string; + env?: NodeJS.ProcessEnv; + home?: string; +}): string { + const record = input.record; + if ( + record && record.clientId === input.clientId && + record.configPath !== input.resolvedPath && + input.statKind(record.configPath) === "file" && + INTEGRATION_CLIENTS[input.clientId].bindsDriftedRecord?.(record.configPath, input.env, input.home) === true + ) { + return record.configPath; + } + return input.resolvedPath; +} + export function isIntegrationClientId(value: string): value is IntegrationClientId { return Object.prototype.hasOwnProperty.call(INTEGRATION_CLIENTS, value); } diff --git a/src/integrations/state.ts b/src/integrations/state.ts index cd0549a3900..f6643527ab3 100644 --- a/src/integrations/state.ts +++ b/src/integrations/state.ts @@ -33,6 +33,8 @@ import { } from "./ownership-policy"; import { INTEGRATION_CLIENTS, + boundIntegrationConfigPath, + boundIntegrationConfigPath, resolveIntegrationPaths, unresolvedPathHintFor, type IntegrationClientId, @@ -530,12 +532,10 @@ export function readIntegrationState(input: IntegrationStateInput): IntegrationS * would let the badge and the switch disagree. */ record = store.readRecords()[input.clientId] ?? null; - const recordedPath = record?.clientId === input.clientId - && record.configPath !== paths.configPath - && io.statKind(record.configPath) === "file" - && spec.bindsDriftedRecord?.(record.configPath, input.env, input.home) === true - ? record.configPath - : paths.configPath; + const recordedPath = boundIntegrationConfigPath({ + clientId: input.clientId, record, resolvedPath: paths.configPath, + statKind: io.statKind, env: input.env, home: input.home, + }); effective = resolveIntegrationTarget({ clientId: input.clientId, configPath: recordedPath, io, record, env: input.env, home: input.home, }); @@ -578,7 +578,7 @@ export function readIntegrationState(input: IntegrationStateInput): IntegrationS const parsed = input.clientId === "cline" ? parseClineDocument(loaded.before) - : parseConfig(loaded.before, effective.format, input.clientId === "kilo" ? { jsonc: true } : undefined); + : parseConfig(loaded.before, effective.format, EXPORT_CLIENTS[input.clientId].jsonc ? { jsonc: true } : undefined); const contribution = effective.buildContribution(exportContextOf(input)); const { state, reason } = classifyIntegration({ fileText: loaded.before, From 7365449360cd8c6354655ad84e1693a53f2000f7 Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 27 Sep 2026 09:06:00 +0800 Subject: [PATCH 6/9] fix(clients): update Kilo export for current model metadata --- src/clients/config-export/kilo.ts | 2 +- src/integrations/state.ts | 1 - tests/clients/kilo-client.test.ts | 9 +++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/clients/config-export/kilo.ts b/src/clients/config-export/kilo.ts index 7f084a1a0e5..cb31dc8cfe0 100644 --- a/src/clients/config-export/kilo.ts +++ b/src/clients/config-export/kilo.ts @@ -70,7 +70,7 @@ function kiloProviderBlock(ctx: ExportContext): KiloProviderBlock { const entry: KiloModelEntry = { name: exportModelLabel(model) }; const context = authoritativeContextWindow(model.contextWindow); if (context !== undefined) { - entry.limit = { context, output: outputBudgetFor(context) }; + entry.limit = { context, output: outputBudgetFor(context, model) }; } const capabilities = opencodeModelCapabilities(model.inputModalities); if (capabilities) { diff --git a/src/integrations/state.ts b/src/integrations/state.ts index f6643527ab3..4ba2ee75e7c 100644 --- a/src/integrations/state.ts +++ b/src/integrations/state.ts @@ -34,7 +34,6 @@ import { import { INTEGRATION_CLIENTS, boundIntegrationConfigPath, - boundIntegrationConfigPath, resolveIntegrationPaths, unresolvedPathHintFor, type IntegrationClientId, diff --git a/tests/clients/kilo-client.test.ts b/tests/clients/kilo-client.test.ts index 99a65210e1f..0b5ec4a6c04 100644 --- a/tests/clients/kilo-client.test.ts +++ b/tests/clients/kilo-client.test.ts @@ -47,6 +47,15 @@ function context(config: OcxConfig = LOOPBACK): ExportContext { } describe("kilo client config", () => { + test("uses the model output limit in Kilo's context metadata", () => { + const document = buildClientConfig("kilo", { + ...context(), + models: [{ namespaced: "custom/limited", provider: "custom", id: "limited", contextWindow: 100_000, maxTokens: 8_192 }], + }) as KiloGeneratedConfig; + expect(document.provider[OPENCODE_PROVIDER_ID]?.models["custom/limited"]?.limit) + .toEqual({ context: 100_000, output: 8_192 }); + }); + test("emits a V1-only document with Kilo's schema and npm package", () => { const document = buildClientConfig("kilo", context()) as KiloGeneratedConfig; expect(document.$schema).toBe(KILO_CONFIG_SCHEMA); From 4d39d1e22fe7b7421d71cc3ec49732db7d91fd36 Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 27 Sep 2026 09:10:19 +0800 Subject: [PATCH 7/9] test(gui): recognize Kilo's built-in plate color --- gui/tests/integration-marks.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/tests/integration-marks.test.ts b/gui/tests/integration-marks.test.ts index b13387d1b68..8b60b94de7d 100644 --- a/gui/tests/integration-marks.test.ts +++ b/gui/tests/integration-marks.test.ts @@ -12,8 +12,8 @@ function bodyOf(src: string): string { } function inksOf(body: string): Set { - const matches = body.match(/(?:fill|stop-color)\s*[:=]\s*"?#[0-9a-fA-F]{3,8}/g) ?? []; - return new Set(matches.map(raw => raw.split(/[:=]/).pop()!.replace(/"/g, "").trim().toLowerCase())); + const matches = body.matchAll(/(?:fill|stop-color)\s*[:=]\s*"?(#[0-9a-fA-F]{3,8}|oklch\([^)]+\))/g); + return new Set([...matches].map(match => match[1]!.toLowerCase())); } /* From 16c931a29016278947f023373b0abb477b48f6dc Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 27 Sep 2026 09:21:37 +0800 Subject: [PATCH 8/9] chore(pr): move Kilo screenshot to PR assets branch --- .github/pr-assets/kilo-client-integration.png | Bin 138660 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .github/pr-assets/kilo-client-integration.png diff --git a/.github/pr-assets/kilo-client-integration.png b/.github/pr-assets/kilo-client-integration.png deleted file mode 100644 index 0fcb0ff479910277f679d28e4bd562e6b27ab482..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138660 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

UF62+7ETleEQA zEI9q@#6M!7ee~V`y7FHw0Cht+v#~SK?*WUy96~TbOsYq-h>(yFu+}m&huwGH0hhJA zovyBKIihc$Q0ITw=pGACAKQ!!HI}(8D6IQ-ChU4!wMKMnUY@&^6De)ktZB|_m^$<1 z!b#Opb3JEe;J@@SluSYCaa^j>$(=bDfk^NBcVyw%5l`%1AZ7bXH?3j-;eelW7ztL( z6~py^stEg-awFG@l^#)pXB^*HFFTPoGCn(Y#vTO)GroNnhJn?0LSXCUl8IaPw-cB< zY0j!6;3h6Jv+-t^E8bqNk7HYqSWVPbwwR4hg)tiIS-5z&tj_+#&Mk)arBDKC%P)KlSUg66Fwt}G*3S-AZ@{iC`;%eUHDE8U!* z52pYCSbi{MSGqr!^!!H!Fvf_ANyu;bp{Qz85AMFgC2Hkh-)7g@b1rd)aPeylf7ALT z^m;e(n@jP{8@-KwD1jPd zS_1ZoF$hj_0F&*O`cwfIv2CYIv+BKVtQ!&@@@TLE_Q1^_3?lBbm@EbASEm0F=UXKe zUnAp5^*F1QA@@MY{Q?35pT+@Tor6t&2MR)jj47aGTUg}vzHLJ#BMDJ0)&LkB=@6sW z!2n(G&eKzH43J@PVVFN*a9xrFX@wKYGpW~QG2h#vu?P>J9(VxJx!CzpZDhDXiy^%q z_AcN|o_&`?ZSa^bGme>jL2)RiBzeNA;wUR4BO@zI>-|kjS62Z5tU@vZCfMQ2MjeEm z-;9Tuq`<{ZaAE@xK_Aq;T}ceQt2#Ygt@hXAxsQmB4las+r@4(qDMZ3pQ(ZliX8CAk z4!0dxFs&^u>j37D_Mhp1Ml%sRH=v~iaM{ba)PVZ!Q~zU%9*u}?YX{?4WvbHo+|nKRV5em-zrA#Fa&mXS0HNdn zL*@en7(kJkgl7O>)v%X&RvBp?$*%c6z$WdGdfE@1+J$P&QjUNSF9Q@%7WwyF@H;x) zxh|w>x4KCUli;%~7v;X+HbYEFOIw_tb_e_`(9;`C;_5!ar5gdaW54Mbe0c`xHG9P2 zK~Vo-r=Rx8C0=Z?sU~FA53Z1*Muxov5;q(5sy77zu5q0EQ|JJ@AM&lBpx2ZT4B{0h zfK&%JF2IRk-^wUK((hJ?HJ<<8fT$HPC1c)z$;8COG-AmO^gaGizq`=z@bR5fKwQHG z_{WF?)Vg*yi{^%F4cf<f;y>bpMyQgyg3h*TL9iL3zC?j^OO*=He2UkO2Qvm5!~V zBKH42>X#~Ydk-{vBq8B5xEg3(K21WXB#ZisPisp`N1T*f)efxR{W(Jx5iMHQ&G{rl#MBQK6wpoMwICytvHN3i_xZC=tl`BY;$iD;h)) z!-*B|0kR74Daw3(^WjK5xGD^uP>kj)=5pCJP*-o^_*tgzRNzC~9xonj&%5IVn3_sYfP)V6k^iw>8H>WAZcAE3YdB~t`#1!{SLe#j+d z$LG(Vk0*8QdAPa71_22J$++cmgUp+I8l(yBHu$s?EYRXNu4OgS(guwFC?6GeN;6*T z{wzqQ+deCxWg5O}lA2Z2xa5htjVW#WRGIpteuGbre?CC8!^5D_Bq&>dskpcEf-m7q z76hmZHv`$gDHb&901<}TqSEw{F(d{~UxCXexd;|VTfO}^VPBCFacCl=qG~7WE zYYGZN>ycJndq2^`$#3T;5?G=)2kk(lg|5!CgIFe`JLi9u>h`s~s8NvRRpR!miMlqb zoGj0jhlAn^`uYnmD$dEwPJen|J?@GC54v?C^_6bm848$iz=vG9Sb_+DHeGZPR#a3N>4cDM4kh!v1EL&v zwy3stmO~VfVuDOy7kc5W*WfItQ9SiVY#owr$(;!#xS8VER7^!lm}oR4|K(8dhWT0> zZFIMcfDvVB`cc6FgvJ8Bo-lE{#_|XN6Y|+F?h2(147?I526`3&bO=v)7fC*`?ql^dZraJuu+S51=u{D%i{Zhz)vByX4 zM1O<$I5+sEE6M{si06mL-=amXwm?nD|62g6h|e7qsNmTk=U!mhb7*Fur}qNIN#LVq zTYFA|HUGHZqB$%oD(E#82uN-*v)p(fJ>aP)V)L!SX;Y~s68j=PRKvs&_vMwGWVc=^^%kMprXEu5YCMG7zQ%WIZj7zDtyFjPNV{}(Z7s7XH8`NfFQhsdIXsY!Lm^Inz30Wx!nEyD63reA-U+dAC>Y~FMBKO(0l=3U4sy^+fZTjg`c)<3m@r|}T5syI9OgG?k|qj=CZ3aZdtTxl?}XR$26m7anN`kIiCkeuvsuq@t_2hM>} ze7vnV5eeJ<>_5Kbdjstx7dVfFewJ>;G^r6J!#BYErQL_D&k4KCID?f-+;8r)t(@ZB zxuBPhE|Uba(+X8-(1sb)y+Os&`{AwM*J>pNl2Q7AMFZJ#Kq6b6iExu#53eK~r{hV; zvfuYHM2t5-q!6gvPe>oVn#n1+wi9M7{qQli6UNP2L4)o-*6Bt%u0mp083~9JcyG4(MJ3>0%R=b_4J>@!8G>>`~or$@aM7D*B-y z?&j;$Nr0#&YN6O%-cCM?z{?UlGK;Xtx1-iXCA<6FGot-{v!m|DeBM=Ik&n5$Vv}9C zQAo40*Z|ucSB;tQJG)w=(Q*S=FTcp=1fLQXTH*U5*t5V_b!=v~=4d`WSjzzz)mR+d z2LLVrNR0tGpF3mpkW{X2&zB@2U%O8L7)TOJSIHG6778?73P~s)Alw(M8lX8se5eB? zlW_ky^aso+Bs3J}ZIcejB+piiU_xv4tjzS|Q%{xDpA8#eterM;5w~|mZY6URKGW+I z*lRwk!Aur6IyP?AxPD($309QK$~}h2njnx8T$Bn$DBDZ<89=O}^W;_mHdVpZ9-@rQ z+G4q2nu$ru7K}r+-^;nyqWR-(Vt_sf74Bsge%orUpaCRxVG8NXY7hmyo|chTj1ct= zh&QO#f`Q_5wVijfIa~d133$URDmZ1_ahk9XtZ?+S0E4Za&ZhBk20a$*LkJZIE(HYu zukCdrLA*Ccbn!@QXV)k%EXO1T13#F#ZVSsCU>tUiCrvAfuT@FnXgw#b^vkyow^&vP z`ID$i)jmBv9Zsz8BO?<<*G|`jrJX}-6jz;Ky-QV@e`_5a`J{-h>EYvCfR9YDW~=ZW z--E@9G!^+a?;`RZgU*l+M&A8p`aQt#V9+*Uh|FIA8;lf|l}s#YGW+0MW#0Sgno%+3h3otaasgeH z_p85pLG`z~ilptE7rSx{ZDCK(%PKeJOiI$$)c(p@qm;p4f90BPvu$A=S*b2lct9L)lnzD^( z5OW&g^;KVwjYS zEXhZ^;jZ=fp@l(mwIkOt)xPV_kv_2{=c_h!-wOGI-T3T!79X8OrvXEENz~SO1O&`M zIVo{9_(OcBhkBfW2?(bvDIXu3Kj~Az!8(2u>7DUeTYGHp5Jrhw;tT2oXzqfxQ%5dH z=Y#Sr61ZH8__gMaL58G z450dYtz6T;Xi^1s(}<|ao9kqYlm{~J`26I2h?8B}vYLD=>3P3pcj5rO+Cv#`aA_H`HwOlTz%T)5{+54!4H@hc zb%Bf`>I-vWJ09P`Eordx$*9G%{es4OfG>Ed^5#cN(D3BP?!z-EtO@4Zw4`FEW-dl23*1*%K!632@`tj74i}oX(YL~ zM`M$0ISC14dyZo3>#bPhMJ1+zJ8L42>Yqo0o{ZEwv`g$uU>Op_P`yp^G_UArDg9ya zoCeE_?5 zt1Tj@*aqiY{m{`VS`Ti-ijmVpJdfm6>H}7tK$y6OO7pd?}q_u-;shqut zd+t+}TD7X<(M_B)jUMAI;SIDy+o4W*z6Y!xHgOn#)S-aP_!I;sf!G(H84&x@k4T*0 z{j+t*-~IbLkgO+lV9a~*UqX!3-I^p?g1ZJ6K50>)%z7h>{OR}mnt>*9*QC{iq`&r<7iI*i=$E0 zkVD3Va1Pw9=ls|mJ3bmC3)=o8Llszi+Y0ROG#AU^iP;e)`7fUR%^Q+Xr1!A=NF!dX z(dg1wsmo$rw}vlm@n^%|BJst6=G*Nn)}040ey%%p4@VE}DQ?cNHY@%DflT3v=W(vV zAb#ZIYr)|n<$p))vm)I>1%msz;i#*xC5$JP$2mLcTV#-?7Iu?z)m&!~jAsM`(MEr> zfgY$C^uajxmX}&a{$AD=UTehO%@%D!zcw`j2tv|g3^w;PSq^#TBL%L^=|eZ;S3&!Q z&P{V7o!S+r-`mKy$a9l|^1f2+su}4ig`Cgpo(@l=L(eKgDMg{pRb0}aj9>El6T%Fz;znNo21bzG{ zSnO7X+4)K*&Y}2@*BeMNXdtDJ#a&r%mK~(RU!(?qMkKw?}>(i4^c7*%gWX^&RZTpxH`j2L}~w4ISo+Rd*hyIzAZ`apw~8_ z>T!55{QanJoiqU!^pH$kL(V7iiT>>TPMh1IDEn-X#=n{Y*c?;i_0F!0Js|To)Ko0r8i6De-t~} zv3vS|m8)O1fxj@LTlI`^G+QU6k!`FS;FLwSU?t)wVh`W|e<+&BON6hmS}fKPu=vAc zRlYm-G;~a|8+YMM7QZ>_Wv3_Hl+Ssjf_@4i9U{;4H zV~rn`)Zu*}^M{qU;I~GAZyW@|1lMwc)&U*YD;v&YL`$QmK|(PuG3b719F}=f3Y7Az zYM^l$2ubd;=$8j&zOBdC?>E8GyMiQ@)Sbq8Fic~LQ2ZT#l@jtfY!ePj+^(A zVB-O-vKaGfP?7K|i8rLKlCTne9d5wlMe`VWSPaYqg0G}jLpMA=s#reCi{FhwL7|-W zG81hMp3A7FoI*)>_?aF)H+z^Npd__I&iN{o=~uC@z69X8N+5nlqeXj=F|F|G)%T(z z%%pSV&JTd&{{Ox2LK33T?wxS$70Q$t9l2mJ`WYZyKp_?pdk)wyRaD@XR&jw3R$x?s921aJP!jliMhZ;~ z(3m;FC#B&$gy@>JuXFsHGKy{(dF<>ff{KfgMdJTegK|S{(tWw#Z6ui znP~k)Sfl$-U~Wew3TfpiWrT)tu}1hFFz|xuML-DEQDY#xNGZA?17V=%?qA-5dT~Xn zUhost|B7{1A>pByL-@N8?0@1&WjdJrDySupvAduj#6VQ)$2Kx;&QguG9dghKAqAx5 z80xo)Z*aRI{rlm|FCl;XGLQ`83g<`~&EV*g%5Wtv}2#PV5Z+#t( zEI90|e&ou-@o%r82IRKD3($PZCpU+#h`*JfHO993t8i4w6SOvPT>e}A=EW$wN9Dxv z(z1fz8fwf}4EV*A0L+b8!(b-z8U>Ej#U#p51{Ths?K5XXkS7D)0j;d}9wm2Px# From 7dd796d724fadec5536f87ec21f9368467fc4455 Mon Sep 17 00:00:00 2001 From: imranshaiedi-byte Date: Sun, 27 Sep 2026 11:16:27 +0800 Subject: [PATCH 9/9] fix(clients): refuse a Kilo restore that would orphan the live file A historical undo of an older candidate committed that file's prior record over the candidate that currently owns Kilo, leaving the live block with nothing to disable it. Direct restore and preview now refuse that collision. --- src/integrations/mutation-plan.ts | 17 +++++++++ src/integrations/registry.ts | 32 ++++++++++++++++ src/integrations/writer.ts | 23 +++++++++++- structure/clients/integrations.md | 7 ++++ tests/clients/kilo-client.test.ts | 61 +++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 1 deletion(-) diff --git a/src/integrations/mutation-plan.ts b/src/integrations/mutation-plan.ts index 7a4db1de338..a0bebde582c 100644 --- a/src/integrations/mutation-plan.ts +++ b/src/integrations/mutation-plan.ts @@ -29,6 +29,7 @@ import { boundIntegrationConfigPath, isLoopbackOnly, resolveIntegrationPaths, + restoreOwnershipCollision, type IntegrationClientId, } from "./registry"; import { declaredIntegrationTarget, resolveIntegrationTarget, type IntegrationTarget } from "./target"; @@ -584,6 +585,22 @@ export function observeRestore( failed: observationFailure("conflict", "conflict", "that operation was recorded for a different location"), } as const; } + /* + * A legal historical path is not enough. Another candidate can already own + * the single record, and committing this row's prior record would orphan the + * block that candidate still holds. Direct restore asks the same question. + */ + const currentOwner = store.readRecords()[clientId] ?? null; + const collision = restoreOwnershipCollision({ + clientId, + journaledPath: configPath, + currentPath: currentOwner && currentOwner.clientId === clientId ? currentOwner.configPath : null, + env: input.env, + home: input.home, + }); + if (collision !== null) { + return { failed: observationFailure("conflict", "conflict", collision) } as const; + } if (clientId === "cline") { try { io = createClineIO(io, configPath, store, effects.recover); } catch (error) { diff --git a/src/integrations/registry.ts b/src/integrations/registry.ts index 36f0e25d0f3..c6228fcda78 100644 --- a/src/integrations/registry.ts +++ b/src/integrations/registry.ts @@ -403,6 +403,38 @@ export function boundIntegrationConfigPath(input: { return input.resolvedPath; } +/** + * Why a historical restore must not run, or null when it may. + * + * Kilo keeps one ownership record and may legally have written more than one + * candidate. Treating every same-home journaled path as a restore target lets + * an undo of an older file commit that file's prior record over the candidate + * that owns the integration now. The managed block in the current file stays + * on disk, the record points at the old file, and a later disable drops the + * record and orphans the newcomer. + * + * A missing current record is not a collision: undoing the disable that + * dropped it still restores the journaled file. A client without + * bindsDriftedRecord is unchanged, because that seam is what made the second + * candidate a legal target. Direct restore and its preview both ask here, so + * they cannot admit different answers. + */ +export function restoreOwnershipCollision(input: { + clientId: IntegrationClientId; + journaledPath: string; + currentPath: string | null; + env?: NodeJS.ProcessEnv; + home?: string; +}): string | null { + const currentPath = input.currentPath; + if (currentPath === null || currentPath === input.journaledPath) return null; + const binds = INTEGRATION_CLIENTS[input.clientId].bindsDriftedRecord; + if (!binds) return null; + if (binds(input.journaledPath, input.env, input.home) !== true) return null; + if (binds(currentPath, input.env, input.home) !== true) return null; + return `that operation was recorded for ${input.journaledPath}, but ${currentPath} currently owns this integration`; +} + export function isIntegrationClientId(value: string): value is IntegrationClientId { return Object.prototype.hasOwnProperty.call(INTEGRATION_CLIENTS, value); } diff --git a/src/integrations/writer.ts b/src/integrations/writer.ts index 10419149cc0..395dc44ed42 100644 --- a/src/integrations/writer.ts +++ b/src/integrations/writer.ts @@ -33,7 +33,13 @@ import { semanticProtectedContributionFingerprint, } from "./ownership-policy"; import { AmbiguousSelectorError, createdContainerPaths, mergeContribution, removeFragments } from "./merge"; -import { INTEGRATION_CLIENTS, isLoopbackOnly, resolveIntegrationPaths, type IntegrationClientId } from "./registry"; +import { + INTEGRATION_CLIENTS, + isLoopbackOnly, + resolveIntegrationPaths, + restoreOwnershipCollision, + type IntegrationClientId, +} from "./registry"; import { declaredIntegrationTarget } from "./target"; import { exportContextOf } from "./state"; import type { IntegrationState } from "./state"; @@ -625,6 +631,21 @@ export function restoreIntegration(input: IntegrationRestoreInput): WriteOutcome return refuse(clientId, "conflict", "conflict", `that operation was recorded for ${configPath}, which this client no longer writes; it now resolves to ${resolvedPath}`); } + /* + * Preview refuses this in observeRestore. Refusing here too is what keeps an + * undo of an older candidate from replacing the record a newer candidate owns. + */ + const currentOwner = store.readRecords()[clientId] ?? null; + const collision = restoreOwnershipCollision({ + clientId, + journaledPath: configPath, + currentPath: currentOwner && currentOwner.clientId === clientId ? currentOwner.configPath : null, + env: input.env, + home: input.home, + }); + if (collision !== null) { + return refuse(clientId, "conflict", "conflict", collision); + } if (clientId === "cline") { try { io = createClineIO(io, configPath, store, true); } catch (error) { diff --git a/structure/clients/integrations.md b/structure/clients/integrations.md index aea8b6614b2..50293f79593 100644 --- a/structure/clients/integrations.md +++ b/structure/clients/integrations.md @@ -394,6 +394,13 @@ discovery resumes only once the record is dropped. A record from a different home never binds, preserving the audit contract that a record for one home cannot authorize a write to another. +Restore of a journaled candidate stays legal while that file is the current owner, and +while no record owns the client (undoing the disable that dropped the record). It is +refused, by both direct restore and preview, when a different Kilo candidate currently +holds the single ownership record. Committing the older row's prior record would point +ownership back at the old file and leave the active block on disk with nothing to +disable it. + ## Cline paired files Cline CLI uses `providers.json` for connection settings and sibling `models.json` for its diff --git a/tests/clients/kilo-client.test.ts b/tests/clients/kilo-client.test.ts index 0b5ec4a6c04..887bdb75d25 100644 --- a/tests/clients/kilo-client.test.ts +++ b/tests/clients/kilo-client.test.ts @@ -324,4 +324,65 @@ describe("kilo JSONC apply/disable/restore", () => { expect(readFileSync(ownedPath, "utf8")).toContain(OPENCODE_PROVIDER_ID); expect(readFileSync(newcomer, "utf8")).toBe(newcomerText); }); + + test("refuses a historical restore once another candidate owns the integration", () => { + /* + * apply config.json, then a higher-priority kilo.jsonc appears, disable + * drops the old record, and a fresh apply owns kilo.jsonc. Restoring the + * historical disable would put config.json's prior record back into the + * single slot while kilo.jsonc still holds the live block. Later disable + * would then drop that record and orphan the newcomer. Both restore paths + * refuse, and the live file stays the one disable removes. + */ + const spec = INTEGRATION_CLIENTS.kilo; + const dir = spec.detectDir({}, home); + mkdirSync(dir, { recursive: true }); + const ownedPath = join(dir, "config.json"); + writeFileSync(ownedPath, "{}\n"); + + const write = { + clientId: "kilo" as const, + models: context().models, + config: LOOPBACK, + port: 10100, + env: {} as NodeJS.ProcessEnv, + home, + store, + }; + expect(applyIntegration(write).ok).toBe(true); + + const newcomer = join(dir, "kilo.jsonc"); + const newcomerText = '{ "model": "keep" }\n'; + writeFileSync(newcomer, newcomerText); + expect(disableIntegration(write).ok).toBe(true); + const disableOp = store.listOperations("kilo").find(op => op.kind === "disable" && op.configPath === ownedPath); + expect(disableOp).toBeDefined(); + + expect(applyIntegration(write).ok).toBe(true); + expect(store.readRecords().kilo?.configPath).toBe(newcomer); + const live = readFileSync(newcomer, "utf8"); + expect(live).toContain(OPENCODE_PROVIDER_ID); + const retired = readFileSync(ownedPath, "utf8"); + expect(retired).not.toContain(OPENCODE_PROVIDER_ID); + + const preview = previewIntegration(write, { operation: "restore", opId: disableOp!.opId }); + expect(preview.canApply).toBe(false); + expect(preview.refusalReason).toBe("conflict"); + + const restored = restoreIntegration({ ...write, opId: disableOp!.opId }); + expect(restored.ok).toBe(false); + if (restored.ok) return; + expect(restored.reason).toBe("conflict"); + expect(restored.message).toContain(newcomer); + expect(readFileSync(newcomer, "utf8")).toBe(live); + expect(readFileSync(ownedPath, "utf8")).toBe(retired); + expect(store.readRecords().kilo?.configPath).toBe(newcomer); + + const disabled = disableIntegration(write); + expect(disabled.ok).toBe(true); + const after = JSON.parse(readFileSync(newcomer, "utf8")) as { provider?: Record }; + expect(after.provider?.[OPENCODE_PROVIDER_ID]).toBeUndefined(); + expect(readFileSync(ownedPath, "utf8")).toBe(retired); + expect(store.readRecords().kilo).toBeUndefined(); + }); });