diff --git a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md index 284c8c20c3..ac4e42bbc2 100644 --- a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md @@ -14,7 +14,7 @@ Gestion des fournisseurs non interactive. Les entrées de registre sont classée | Sous-commande | Drapeaux pris en charge | Actions | | --- | --- | --- | -| `list` | `--json` | Répertoriez les fournisseurs configurés et les entrées de registre restantes. | +| `list` | `--json`, `--jsonl` | Répertoriez les fournisseurs configurés et les entrées de registre restantes. `--jsonl` émet un objet JSON par fournisseur configuré et par ligne. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Ajoutez un fournisseur registry/custom. `--force` écrase ; `--sync` actualise un proxy en cours d'exécution en mode sortie humaine. | | `edit ` | indicateurs de champ du fournisseur, `--headers `, `--json` | Modifiez les champs de fournisseur en direct validés sans remplacer les pools de clés. `--headers` fusionne les en-têtes de requête personnalisés ; passez `{}` ou `-` pour les effacer. | | `test ` | `--json` | Sondez le véritable point de terminaison du modèle en amont. | @@ -28,6 +28,7 @@ Gestion des fournisseurs non interactive. Les entrées de registre sont classée ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -36,6 +37,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` écrit uniquement les fournisseurs configurés, un objet JSON par ligne. Chaque objet contient les mêmes champs qu’un élément du tableau `configured` de `--json`, sans le résumé `registryCount`. Les scripts peuvent traiter les objets ligne par ligne. `--json` et `--jsonl` ne peuvent pas être combinés. + :::caution[Les en-têtes personnalisés ne sont pas un canal d'identification] `--headers` est destiné aux métadonnées de requête non secrètes : conseils de routage, locataire ou sélecteurs de projets, identifiants de traçage. Ce n'est **pas** un endroit pour mettre l'authentification diff --git a/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md index d20483a8a2..594d1fc30e 100644 --- a/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md @@ -13,7 +13,7 @@ description: プロバイダー構成、資格情報、クォータ、および |サブコマンド |サポートされているフラグ |アクション | | --- | --- | --- | -| `list` | `--json` |構成されたプロバイダーと残りのレジストリ エントリを一覧表示します。 | +| `list` | `--json`, `--jsonl` |構成されたプロバイダーと残りのレジストリ エントリを一覧表示します。 `--jsonl` は設定済みプロバイダーごとに1行の JSON オブジェクトを出力します。 | | `add ` | `--adapter `、`--base-url `、`--api-key `、`--default-model `、`--set-default`、`--force`、`--json`、`--sync` |レジストリ/カスタムプロバイダーを追加します。 `--force` は上書きします。 `--sync` は、実行中のプロキシを人間出力モードで更新します。 | | `edit ` |プロバイダーフィールドフラグ、`--headers `、`--json` |キー プールを置き換えずに、検証済みのライブ プロバイダー フィールドを編集します。`--headers` はカスタム要求ヘッダーをマージします。`{}` または `-` を渡すとクリアします。 | | `test ` | `--json` |実際の上流モデルのエンドポイントを調査します。 | @@ -27,6 +27,7 @@ description: プロバイダー構成、資格情報、クォータ、および ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -35,6 +36,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` は設定済みプロバイダーのみを、1行につき1つの JSON オブジェクトとして出力します。各オブジェクトのフィールドは `--json` の `configured` 配列の要素と同じで、`registryCount` の集計は含みません。スクリプトは各行のオブジェクトを順に処理できます。`--json` と `--jsonl` は同時に指定できません。 + :::caution[カスタムヘッダーは認証情報の経路ではありません] `--headers` は秘密ではないリクエストメタデータ用です — ルーティングヒント、テナントや プロジェクトのセレクター、トレース ID など。認証情報を入れる場所ではなく、バリデーターは diff --git a/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md index 250b3d7b1b..ed3c6a565d 100644 --- a/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md @@ -13,7 +13,7 @@ description: 제공자 설정, 자격 증명, 할당량, 모델 카탈로그 명 | 하위 명령 | 지원 플래그 | 동작 | | --- | --- | --- | -| `list` | `--json` | 설정된 제공자와 남아 있는 레지스트리 항목을 나열합니다. | +| `list` | `--json`, `--jsonl` | 설정된 제공자와 남아 있는 레지스트리 항목을 나열합니다. `--jsonl`은 설정된 제공자마다 JSON 객체를 한 줄씩 출력합니다. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | 레지스트리/사용자 지정 제공자를 추가합니다. `--force`는 덮어쓰고, `--sync`는 사람이 읽는 출력 모드에서 실행 중인 프록시를 새로 고칩니다. | | `edit ` | 제공자 필드 플래그, `--headers `, `--json` | 키 풀을 바꾸지 않고 검증된 실시간 제공자 필드를 수정합니다. `--headers`는 사용자 지정 요청 헤더를 병합하며, `{}` 또는 `-`로 지울 수 있습니다. | | `test ` | `--json` | 실제 상위 모델 엔드포인트를 확인합니다. | @@ -27,6 +27,7 @@ description: 제공자 설정, 자격 증명, 할당량, 모델 카탈로그 명 ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -35,6 +36,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl`은 설정된 제공자만 JSON 객체 하나당 한 줄로 출력합니다. 각 객체의 필드는 `--json`의 `configured` 배열 항목과 같으며, `registryCount` 요약은 포함하지 않습니다. 스크립트에서 각 줄의 객체를 순서대로 처리할 수 있습니다. `--json`과 `--jsonl`은 함께 사용할 수 없습니다. + :::caution[커스텀 헤더는 자격증명 통로가 아닙니다] `--headers`는 비밀이 아닌 요청 메타데이터용입니다 — 라우팅 힌트, 테넌트나 프로젝트 선택자, 추적 id 같은 것들이요. 인증 정보를 넣는 자리가 아니고, 검증기는 표준 자격증명 diff --git a/docs-site/src/content/docs/reference/cli/providers-accounts.md b/docs-site/src/content/docs/reference/cli/providers-accounts.md index b31c0f3159..3d602799bb 100644 --- a/docs-site/src/content/docs/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/reference/cli/providers-accounts.md @@ -14,7 +14,7 @@ both `--adapter` and `--base-url`. | Subcommand | Supported flags | Action | | --- | --- | --- | -| `list` | `--json` | List configured providers and the remaining registry entries. | +| `list` | `--json`, `--jsonl` | List configured providers and the remaining registry entries; `--jsonl` emits one configured provider object per line. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Add a registry/custom provider. `--force` overwrites; `--sync` refreshes a running proxy in human-output mode. | | `edit ` | provider field flags, `--headers `, `--json` | Edit validated live provider fields without replacing key pools. `--headers` merges custom request headers; pass `{}` or `-` to clear them. | | `test ` | `--json` | Probe the real upstream model endpoint. | @@ -29,6 +29,7 @@ both `--adapter` and `--base-url`. ```bash ocx provider list --json +ocx provider list --jsonl # one configured provider object per line ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -37,6 +38,11 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` writes only configured providers, one JSON object per line, and omits the +`registryCount` summary from `--json`. Each object has the same fields as an item in the `configured` array. +Use it for scripts that process one configured provider object per line. +`--json` and `--jsonl` cannot be combined. + :::caution[Custom headers are not a credential channel] `--headers` is for non-secret request metadata — routing hints, tenant or project selectors, tracing ids. It is **not** a place to put authentication diff --git a/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md index 56bde92668..4ae2bc7b5f 100644 --- a/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md @@ -15,7 +15,7 @@ pool'ами и контролируют каталог моделей, кото | Подкоманда | Поддерживаемые флаги | Действие | | --- | --- | --- | -| `list` | `--json` | Показать настроенных провайдеров и оставшиеся записи registry. | +| `list` | `--json`, `--jsonl` | Показать настроенных провайдеров и оставшиеся записи registry. `--jsonl` выводит по одному JSON-объекту настроенного провайдера на строку. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Добавить registry/custom-провайдера. `--force` перезаписывает; `--sync` обновляет живой прокси в human-output mode. | | `edit ` | provider field flags, `--headers `, `--json` | Изменить валидированные live-поля провайдера, не заменяя key-pool'ы. `--headers` объединяет пользовательские request-header'ы; передайте `{}` или `-`, чтобы очистить их. | | `test ` | `--json` | Пробный запрос к реальному upstream model-endpoint'у. | @@ -29,6 +29,7 @@ pool'ами и контролируют каталог моделей, кото ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -37,6 +38,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` выводит только настроенных провайдеров: один JSON-объект на строку. Поля каждого объекта совпадают с полями элемента массива `configured` в `--json`; сводка `registryCount` не включается. Скрипты могут обрабатывать объекты построчно. Флаги `--json` и `--jsonl` нельзя использовать вместе. + :::caution[Пользовательские заголовки — не канал для учётных данных] `--headers` предназначен для несекретных метаданных запроса — подсказок маршрутизации, селекторов тенанта или проекта, идентификаторов трассировки. Это не diff --git a/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md b/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md index f611d7be73..2d58adae3b 100644 --- a/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md @@ -16,7 +16,7 @@ bir ad hem `--adapter` hem de `--base-url` gerektirir. | Alt komut | Desteklenen bayraklar | Eylem | | --- | --- | --- | -| `list` | `--json` | Yapılandırılmış sağlayıcıları ve kalan kayıt defteri girdilerini listeleyin. | +| `list` | `--json`, `--jsonl` | Yapılandırılmış sağlayıcıları ve kalan kayıt defteri girdilerini listeleyin. `--jsonl`, yapılandırılmış her sağlayıcı için satır başına bir JSON nesnesi üretir. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Bir kayıt defteri/özel sağlayıcı ekleyin. `--force` üzerine yazar; `--sync`, insan çıktısı modunda çalışan bir proxy'yi yeniler. | | `edit ` | sağlayıcı alan bayrakları, `--headers `, `--json` | Anahtar havuzlarını değiştirmeden doğrulanmış canlı sağlayıcı alanlarını düzenleyin. `--headers` özel istek başlıklarını birleştirir; temizlemek için `{}` veya `-` iletin. | | `test ` | `--json` | Gerçek yukarı akış model uç noktasını araştırın. | @@ -30,6 +30,7 @@ bir ad hem `--adapter` hem de `--base-url` gerektirir. ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -38,6 +39,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` yalnızca yapılandırılmış sağlayıcıları, her satırda bir JSON nesnesi olacak şekilde yazar. Her nesne, `--json` çıktısındaki `configured` dizisinin bir öğesiyle aynı alanları içerir; `registryCount` özeti eklenmez. Betikler nesneleri satır satır işleyebilir. `--json` ve `--jsonl` birlikte kullanılamaz. + :::caution[Özel başlıklar bir kimlik bilgisi kanalı değildir] `--headers`, gizli olmayan istek meta verileri içindir — yönlendirme ipuçları, kiracı veya proje seçicileri, izleme kimlikleri. Kimlik doğrulama materyali diff --git a/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md b/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md index 85633f54f5..a6fe332390 100644 --- a/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md @@ -14,7 +14,7 @@ description: 提供方配置、凭据、配额,以及模型目录命令。 | 子命令 | 支持的标志 | 操作 | | --- | --- | --- | -| `list` | `--json` | 列出已配置的提供方以及剩余的注册表条目。 | +| `list` | `--json`, `--jsonl` | 列出已配置的提供方以及剩余的注册表条目。 `--jsonl` 为每个已配置的提供方输出一行 JSON 对象。 | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | 添加一个注册表/自定义提供方。`--force` 会覆盖;`--sync` 会在有人类输出模式运行的代理上刷新配置。 | | `edit ` | 提供方字段标志,`--headers `,`--json` | 在不替换密钥池的情况下,编辑经过校验的在线提供方字段。`--headers` 会合并自定义请求头;传入 `{}` 或 `-` 可清空。 | | `test ` | `--json` | 探测真实的上游模型端点。 | @@ -28,6 +28,7 @@ description: 提供方配置、凭据、配额,以及模型目录命令。 ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -36,6 +37,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` 仅输出已配置的提供方,每行一个 JSON 对象。每个对象的字段与 `--json` 输出中 `configured` 数组的元素相同,不包含 `registryCount` 汇总。脚本可以逐行处理这些对象。`--json` 与 `--jsonl` 不能同时使用。 + :::caution[自定义请求头不是凭据通道] `--headers` 用于非机密的请求元数据 —— 路由提示、租户或项目选择器、追踪 ID 等。它不是 存放认证信息的地方,校验器会拒绝标准凭据请求头名称(`Authorization`、`X-Api-Key`、 diff --git a/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md b/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md index c50a6d54ae..fbf1ff186c 100644 --- a/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md @@ -13,7 +13,7 @@ description: 供應商設定、憑證、配額與模型目錄指令。 | 子指令 | 支援的旗標 | 動作 | | --- | --- | --- | -| `list` | `--json` | 列出已設定的供應商與剩餘的 registry 項目。 | +| `list` | `--json`, `--jsonl` | 列出已設定的供應商與剩餘的 registry 項目。 `--jsonl` 為每個已設定的供應商輸出一行 JSON 物件。 | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | 新增 registry/自訂供應商。`--force` 覆寫;`--sync` 在人類輸出模式下重新整理執行中的代理。 | | `edit ` | 供應商欄位旗標, `--json` | 編輯已驗證的即時供應商欄位而不替換金鑰池。 | | `test ` | `--json` | 探測真實上游模型端點。 | @@ -27,6 +27,7 @@ description: 供應商設定、憑證、配額與模型目錄指令。 ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -35,6 +36,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` 僅輸出已設定的供應商,每行一個 JSON 物件。每個物件的欄位與 `--json` 輸出中 `configured` 陣列的元素相同,不包含 `registryCount` 摘要。指令碼可以逐行處理這些物件。`--json` 與 `--jsonl` 不能同時使用。 + ## 認證 ### `ocx login ` diff --git a/skills/ocx/references/01_management_surface.md b/skills/ocx/references/01_management_surface.md index d5711f3cac..10b0cd9e89 100644 --- a/skills/ocx/references/01_management_surface.md +++ b/skills/ocx/references/01_management_surface.md @@ -67,6 +67,7 @@ Drives no management route. | Flag | Value | Meaning | |---|---|---| | `--json` | boolean | Emit the provider list as JSON. | +| `--jsonl` | boolean | Emit one configured provider per JSON line. | JSON mode: `envelope`. diff --git a/skills/ocx/references/02_json_shapes.md b/skills/ocx/references/02_json_shapes.md index a91e35a2e1..261c8be5a2 100644 --- a/skills/ocx/references/02_json_shapes.md +++ b/skills/ocx/references/02_json_shapes.md @@ -52,6 +52,11 @@ to `requestedModel` is how you get a wrong answer about which provider served it `displayMetrics.cost.estimate.estimateReasons` lists why — for example `usage_estimated`, `cache_detail_missing`, `expected_price_overlay`. +## `ocx provider list --jsonl` + +One configured provider per line. Each object has the same fields as an item in the +`configured` array from `ocx provider list --json`; the `registryCount` summary is omitted. + ## `ocx logs explain ` ```json diff --git a/skills/ocx/references/03_recipes.md b/skills/ocx/references/03_recipes.md index 424ad34a53..9159751424 100644 --- a/skills/ocx/references/03_recipes.md +++ b/skills/ocx/references/03_recipes.md @@ -157,6 +157,7 @@ exist for them — do not attribute usage to either. ```bash ocx provider list --json +ocx provider list --jsonl # one configured provider per line ocx provider add --json # registry providers auto-configure by name ocx provider test --json ocx provider set-default --json diff --git a/src/cli/capabilities.ts b/src/cli/capabilities.ts index 1b5cfd6283..ff1f5fb9a2 100644 --- a/src/cli/capabilities.ts +++ b/src/cli/capabilities.ts @@ -148,7 +148,10 @@ export const CAPABILITIES: readonly Capability[] = [ summary: "Configured providers with connectivity and selected models.", // Local config + PROVIDER_REGISTRY. Does not call GET /api/providers. routes: [], - flags: [{ name: "--json", value: "boolean", summary: "Emit the provider list as JSON." }], + flags: [ + { name: "--json", value: "boolean", summary: "Emit the provider list as JSON." }, + { name: "--jsonl", value: "boolean", summary: "Emit one configured provider per JSON line." }, + ], mutates: false, json: "envelope", details: ["Reads local config; drives no management API route."], diff --git a/src/cli/provider.ts b/src/cli/provider.ts index 55c654d8d7..47f23fee62 100644 --- a/src/cli/provider.ts +++ b/src/cli/provider.ts @@ -79,26 +79,37 @@ function validateAndSave(config: ReturnType): void { function handleList(args: string[]): void { const wantsJson = consumeFlag(args, "--json"); - rejectUnknownArgs(args, "Usage: ocx provider list [--json]"); + const wantsJsonl = consumeFlag(args, "--jsonl"); + rejectUnknownArgs(args, "Usage: ocx provider list [--json|--jsonl]"); + + if (wantsJson && wantsJsonl) { + console.error("Use only one of --json or --jsonl."); + process.exit(1); + } const config = loadConfig(); const configured = Object.keys(config.providers); + const entries = configured.map(name => { + const prov = config.providers[name]; + const registryEntry = getProviderRegistryEntry(name); + return { + name, + adapter: prov.adapter, + baseUrl: prov.baseUrl, + authMode: prov.authMode ?? "key", + defaultModel: prov.defaultModel ?? null, + isDefault: name === config.defaultProvider, + source: registryEntry ? "registry" : "custom", + models: prov.models ?? [], + }; + }); + + if (wantsJsonl) { + for (const entry of entries) console.log(JSON.stringify(entry)); + return; + } if (wantsJson) { - const entries = configured.map(name => { - const prov = config.providers[name]; - const registryEntry = getProviderRegistryEntry(name); - return { - name, - adapter: prov.adapter, - baseUrl: prov.baseUrl, - authMode: prov.authMode ?? "key", - defaultModel: prov.defaultModel ?? null, - isDefault: name === config.defaultProvider, - source: registryEntry ? "registry" : "custom", - models: prov.models ?? [], - }; - }); console.log(JSON.stringify({ configured: entries, registryCount: PROVIDER_REGISTRY.length }, null, 2)); return; } @@ -444,6 +455,7 @@ Subcommands: Examples: ocx provider list + ocx provider list --jsonl ocx provider add anthropic --api-key sk-ant-... ocx provider add my-ollama --adapter openai-chat --base-url http://localhost:11434/v1 ocx provider show anthropic --json diff --git a/tests/cli/cli-provider.test.ts b/tests/cli/cli-provider.test.ts index b83bc8d514..ea29c5535f 100644 --- a/tests/cli/cli-provider.test.ts +++ b/tests/cli/cli-provider.test.ts @@ -109,6 +109,80 @@ describe("ocx provider", () => { } }); + test("provider list --jsonl matches JSON configured records with escaped model values", () => { + const escapedModel = 'model-"quoted"\\path\nnext\r\ttab-한글'; + const { dir } = freshConfig({ + providers: { + openai: { + adapter: "openai-responses", + baseUrl: "https://chatgpt.com/backend-api/codex", + authMode: "forward", + }, + "custom.models-1": { + adapter: "openai-chat", + baseUrl: "https://models.example.test/v1", + defaultModel: escapedModel, + models: ["plain-model", escapedModel], + }, + }, + defaultProvider: "custom.models-1", + }); + try { + const result = runCli(["provider", "list", "--jsonl"], { OPENCODEX_HOME: dir }); + const json = runCli(["provider", "list", "--json"], { OPENCODEX_HOME: dir }); + expect(result.status).toBe(0); + expect(json.status).toBe(0); + // Keep every physical line: embedded newlines must be escaped, and only + // the final record terminator may produce an empty split element. + const lines = result.stdout.split(/\r?\n/); + expect(lines.pop()).toBe(""); + expect(lines).toHaveLength(2); + const records = lines.map(line => JSON.parse(line)); + const envelope = JSON.parse(json.stdout); + expect(records).toEqual(envelope.configured); + expect(envelope.registryCount).toBeGreaterThan(0); + expect(records).toEqual([ + { + name: "openai", + adapter: "openai-responses", + baseUrl: "https://chatgpt.com/backend-api/codex", + authMode: "forward", + defaultModel: null, + isDefault: false, + source: "registry", + models: [], + }, + { + name: "custom.models-1", + adapter: "openai-chat", + baseUrl: "https://models.example.test/v1", + authMode: "key", + defaultModel: escapedModel, + isDefault: true, + source: "custom", + models: ["plain-model", escapedModel], + }, + ]); + } finally { + removeTreeWithRetry(dir); + } + }); + + test.each([ + ["--json", "--jsonl"], + ["--jsonl", "--json"], + ])("provider list rejects %s %s without stdout", (first, second) => { + const { dir } = freshConfig(); + try { + const result = runCli(["provider", "list", first, second], { OPENCODEX_HOME: dir }); + expect(result.status).toBe(1); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("Use only one of --json or --jsonl"); + } finally { + removeTreeWithRetry(dir); + } + }); + test("provider add registry provider seeds config", () => { const { dir } = freshConfig(); try {