@jeffreycao/copilot-api 2.6.11 → 2.6.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/README.zh-CN.md +13 -7
- package/dist/auth-B0w9MzMB.js +2 -0
- package/dist/{auth-aGQ_vPFn.js → auth-B1iccyyN.js} +47 -9
- package/dist/auth-B1iccyyN.js.map +1 -0
- package/dist/{config-g8kEbc0j.js → config-B_pC8QXv.js} +421 -10
- package/dist/config-B_pC8QXv.js.map +1 -0
- package/dist/{debug-DXGZGaoU.js → debug-C4rsL806.js} +2 -2
- package/dist/{debug-DXGZGaoU.js.map → debug-C4rsL806.js.map} +1 -1
- package/dist/main.js +3 -3
- package/dist/{models-C1H-ahM4.js → models-NNzBeGzA.js} +2 -2
- package/dist/{models-C1H-ahM4.js.map → models-NNzBeGzA.js.map} +1 -1
- package/dist/{server-Biyjjk2W.js → server-w3-DhBM0.js} +119 -297
- package/dist/server-w3-DhBM0.js.map +1 -0
- package/dist/{start-CYq2v7cu.js → start-B2vhz_qK.js} +7 -6
- package/dist/{start-CYq2v7cu.js.map → start-B2vhz_qK.js.map} +1 -1
- package/dist/{token-SzcMtW4G.js → token-3SWNt25T.js} +2 -2
- package/dist/{token-SzcMtW4G.js.map → token-3SWNt25T.js.map} +1 -1
- package/package.json +2 -1
- package/dist/auth-BTdaexGw.js +0 -2
- package/dist/auth-aGQ_vPFn.js.map +0 -1
- package/dist/config-g8kEbc0j.js.map +0 -1
- package/dist/server-Biyjjk2W.js.map +0 -1
package/README.md
CHANGED
|
@@ -680,9 +680,11 @@ Use `copilot-api auth login --provider copilot` only when you want to enable the
|
|
|
680
680
|
|
|
681
681
|
The Codex provider stores up to 3 accounts. Add or update an account with `copilot-api auth login --provider codex --alias work`; the newly signed-in account becomes active. List accounts with `copilot-api auth codex --list`, switch with `copilot-api auth codex --use <alias-or-accountId>`, and remove an account that is not in use with `copilot-api auth codex --remove <alias-or-accountId>`. Aliases are case-insensitive and cannot duplicate another account's alias or ID; the account currently in use cannot be removed. Restart a running server after switching or removing an account so it stops using the previous account; a credential refresh never writes a removed account back. Legacy single-account `codex_credentials.json` files remain compatible and upgrade to the multi-account shape on the next credential write.
|
|
682
682
|
|
|
683
|
-
Use `copilot-api auth login --provider deepseek`, `--provider dashscope`, `--provider openrouter`, `--provider opencode-go`, or `--provider kimi` to add or update those common third-party providers from the CLI. DeepSeek prompts for masked `apiKey`, provider `type` (default `anthropic`), and `baseUrl` defaulting to `https://api.deepseek.com/anthropic`. DashScope prompts for masked `apiKey`, provider `type` (default `openai-compatible`), and prefilled `baseUrl`. OpenRouter prompts for masked `apiKey` and prefilled `baseUrl` only, and writes `type: "anthropic"`. OpenCode Go prompts for masked `apiKey` and prefilled `baseUrl` only, and writes `type: "openai-compatible"` (baseUrl `https://opencode.ai/zen/go`). Kimi prompts for masked `apiKey`, provider `type` (default `openai-compatible`), and `baseUrl` defaulting to `https://api.kimi.com/coding` (the same base URL serves both the Anthropic and OpenAI-compatible endpoints). OpenCode Go
|
|
683
|
+
Use `copilot-api auth login --provider deepseek`, `--provider dashscope`, `--provider openrouter`, `--provider opencode-go`, or `--provider kimi` to add or update those common third-party providers from the CLI. DeepSeek prompts for masked `apiKey`, provider `type` (default `anthropic`), and `baseUrl` defaulting to `https://api.deepseek.com/anthropic`. DashScope prompts for masked `apiKey`, provider `type` (default `openai-compatible`), and prefilled `baseUrl`. OpenRouter prompts for masked `apiKey` and prefilled `baseUrl` only, and writes `type: "anthropic"`. OpenCode Go prompts for masked `apiKey` and prefilled `baseUrl` only, and writes `type: "openai-compatible"` (baseUrl `https://opencode.ai/zen/go`). Kimi prompts for masked `apiKey`, provider `type` (default `openai-compatible`), and `baseUrl` defaulting to `https://api.kimi.com/coding` (the same base URL serves both the Anthropic and OpenAI-compatible endpoints). OpenCode Go selects the protocol from the model-level models.dev `provider.npm`, then the provider-level `npm`: `@ai-sdk/anthropic` uses Anthropic Messages, `@ai-sdk/openai` uses OpenAI Responses (unless the model has `shape: completions`), and unrecognized or missing packages use OpenAI-compatible. After a provider is configured and enabled, `copilot-api start` can run without any GitHub token.
|
|
684
684
|
|
|
685
|
-
|
|
685
|
+
OpenCode Go model listings (`/opencode-go/v1/models` and its entries in `/v1/models`) use the `opencode-go.models` section of [models.dev/api.json](https://models.dev/api.json). At startup the server loads `models-dev-api.json` from `COPILOT_API_HOME` (or the default app data directory). If a valid cache exists, the server starts listening and refreshes the catalog in the background every five minutes. Without a valid cache, startup waits for the first download and fails if it cannot obtain a catalog. Refreshes use `ETag` or `Last-Modified` when available; both validators are saved in `models-dev-api.meta.json` with a checksum of the JSON. A `304` keeps the existing cache, and a failed background refresh keeps the last valid disk or memory catalog. Models marked `status: deprecated` are excluded.
|
|
686
|
+
|
|
687
|
+
Use `copilot-api auth login --provider custom` to add or update another third-party provider from the CLI. Choose manual entry or search the existing models.dev catalog. The catalog selection includes providers with an HTTP API URL using Anthropic Messages, OpenAI-compatible Chat Completions, or OpenAI Responses; `openrouter`, `github-copilot`, and `opencode-go` are excluded. The selected provider ID, protocol, and API URL prefill editable fields, and models.dev model prices are used for token cost estimates in USD unless a model has explicit pricing in `config.json`. The command then prompts for masked `apiKey` and `authType`; `authType` may be left as the type default or set to `x-api-key` / `authorization`. The desktop custom-provider form offers the same catalog selection and manual entry.
|
|
686
688
|
|
|
687
689
|
Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `copilot-api auth keys` (one operation per invocation): add a key with `--add <key>`, remove one with `--remove <key>`, list all with `--list`, or clear them all with `--clear`. Clients authenticate with any configured key via `x-api-key` or `Authorization: Bearer`. Without keys, loopback listeners start with authentication bypassed and print an info message; non-loopback listeners refuse to start.
|
|
688
690
|
|
|
@@ -704,7 +706,10 @@ Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `c
|
|
|
704
706
|
},
|
|
705
707
|
"providers": {},
|
|
706
708
|
"modelMappings": {},
|
|
707
|
-
"
|
|
709
|
+
"smallModels": {
|
|
710
|
+
"codex": "gpt-6-luna",
|
|
711
|
+
"copilot": "gpt-6-luna"
|
|
712
|
+
},
|
|
708
713
|
"contextManagement": {
|
|
709
714
|
"messages": true,
|
|
710
715
|
"responses": false
|
|
@@ -736,6 +741,7 @@ Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `c
|
|
|
736
741
|
- **providers:** Global upstream provider map. Each provider key (for example `dashscope`) becomes a route prefix (`/dashscope/v1/messages`). Supports `type: "anthropic"`, `type: "openai-compatible"`, and `type: "openai-responses"`. Top-level clients can also use `model: "dashscope/model-id"` with `/v1/messages`, `/v1/messages/count_tokens`, `/v1/responses`, and `/v1/chat/completions`; the gateway strips the `dashscope/` prefix before forwarding upstream. The `/v1/responses` route for `anthropic` and `openai-compatible` providers uses the Responses Lite → Messages adapter; `openai-compatible` providers then reuse the Messages → Chat translation. Codex clients (`User-Agent` starting with `codex`) also use the adapter for non-`gpt-*` models on `openai-responses` providers. `GET /v1/models` aggregates enabled provider models with `provider/model-id` IDs, while the top-level Codex-UA catalog also merges these adaptable models as `use_responses_lite` entries (except DeepSeek models, which use `use_responses_lite: false` and `tool_mode: null`). Use `GET /dashscope/v1/models` for a single provider's raw model list.
|
|
737
742
|
- `enabled` defaults to `true` if omitted.
|
|
738
743
|
- `baseUrl` should be provider API base URL without the final endpoint. For Anthropic providers, omit `/v1/messages`; for OpenAI-compatible providers, omit `/v1/chat/completions`; for OpenAI Responses providers, omit `/v1/responses`.
|
|
744
|
+
- `modelsDevProviderId` (optional): Written when custom authorization selects a models.dev provider. In that case, `baseUrl` is the API URL supplied by models.dev (or your edited value), and the gateway appends `/messages`, `/chat/completions`, or `/responses` directly. Model-level protocol and USD pricing metadata from the cached catalog are applied when available; model-level API URL overrides apply while `baseUrl` matches the catalog's provider URL. Explicit `models.<id>.pricing` takes precedence. Manually entered providers continue to use `baseUrl` plus `/v1/<endpoint>`.
|
|
739
745
|
- `apiKey` is used as the upstream credential value and is required unless `authType` is `azure-entra`.
|
|
740
746
|
- `authType` (optional): Controls upstream authentication. Supports `x-api-key`, `authorization`, and `azure-entra` for regular providers. Anthropic providers default to `x-api-key`; OpenAI-compatible and OpenAI Responses providers default to `authorization`. `authorization` sends `Authorization: Bearer <apiKey>`. `azure-entra` uses Azure Identity's `DefaultAzureCredential` with the `https://cognitiveservices.azure.com/.default` scope, sends the resulting bearer token, and does not require `apiKey`. For an Azure OpenAI v1 endpoint, use a provider such as `{ "type": "openai-compatible", "baseUrl": "https://<resource-name>.openai.azure.com/openai", "authType": "azure-entra" }`. Authenticate locally with `az login`, use a managed identity in Azure, or set the standard `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` environment variables. `oauth2` is reserved for the built-in `codex` provider and is written automatically by `auth login --provider codex`.
|
|
741
747
|
- `accountId` is used only by the built-in `codex` provider and identifies its active Codex account. CLI and desktop account switching update it automatically.
|
|
@@ -745,7 +751,7 @@ Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `c
|
|
|
745
751
|
- `topP` (optional): Default top_p value used when the request does not specify one.
|
|
746
752
|
- `topK` (optional): Default top_k value used when the request does not specify one.
|
|
747
753
|
- `extraBody` (optional): Dynamic fields merged into the upstream request body for that model. Request body fields with the same name take precedence. OpenAI-compatible providers can use this for fields such as `enable_thinking`, `preserve_thinking`, `reasoning_effort`. `thinking_budget` is a special OpenAI-compatible provider override: when configured in `extraBody`, it is forced after Anthropic `thinking.budget_tokens` translation and overrides the request-derived budget. For providers whose name is `dashscope` or whose `baseUrl` contains `aliyuncs.com`, the request-derived `thinking_budget` (from Anthropic `thinking.budget_tokens`) is forwarded upstream; for other OpenAI-compatible providers the request-derived `thinking_budget` is stripped, while an `extraBody` `thinking_budget` is still honored. For DashScope providers, `preserve_thinking` defaults to `true` when not explicitly set in `extraBody` or the request body.
|
|
748
|
-
- `pricing` (optional): Per-model token prices, in the provider `pricingCurrency`, per 1M tokens. Supported fields are `input`, `output`, `cachedInput` (implicit cache read), `explicitCachedInput` (explicit cache read), and `cacheCreationInput`. Use `tiers` with `maxInputTokens` for input-size tiered pricing. For providers that bill separate peak and off-peak rates, add `offPeak` with the same fields as the top level and declare peak hours with `peakWindows`: each entry takes `startMinuteUtc` (inclusive) and `endMinuteUtc` (exclusive) as minutes from 00:00 UTC, plus optional `weekdays` ISO day numbers (1 = Monday, 7 = Sunday, omitted means every day). Without `peakWindows` the `offPeak` prices never apply and every request bills at the peak price. The built-in catalog uses this for DeepSeek (peak on weekdays UTC 01:00-04:00 and 06:00-10:00, off-peak otherwise including weekends) and for DashScope DeepSeek (off-peak on UTC 14:00-24:00)
|
|
754
|
+
- `pricing` (optional): Per-model token prices, in the provider `pricingCurrency`, per 1M tokens. Supported fields are `input`, `output`, `cachedInput` (implicit cache read), `explicitCachedInput` (explicit cache read), and `cacheCreationInput`. Use `tiers` with `maxInputTokens` for input-size tiered pricing. For providers that bill separate peak and off-peak rates, add `offPeak` with the same fields as the top level and declare peak hours with `peakWindows`: each entry takes `startMinuteUtc` (inclusive) and `endMinuteUtc` (exclusive) as minutes from 00:00 UTC, plus optional `weekdays` ISO day numbers (1 = Monday, 7 = Sunday, omitted means every day). Without `peakWindows` the `offPeak` prices never apply and every request bills at the peak price. The built-in catalog uses this for DeepSeek (peak on weekdays UTC 01:00-04:00 and 06:00-10:00, off-peak otherwise including weekends) and for DashScope DeepSeek (off-peak on UTC 14:00-24:00). OpenCode Go prices use the current models.dev values.
|
|
749
755
|
- `contextCache` (optional): Defaults to `true` for providers whose name is `dashscope` or whose `baseUrl` contains `aliyuncs.com`; defaults to `false` for other OpenAI-compatible providers. This enables Alibaba Cloud Model Studio/DashScope explicit context cache by injecting `cache_control: { "type": "ephemeral" }` on up to 4 content blocks using the Context Cache format. The cache breakpoint strategy matches opencode's main provider flow: the first 2 system messages plus the last 2 non-system messages. Marked string content is converted to text content part arrays for `system` / `user` / `assistant` / `tool` messages; existing array content is marked on the last part. Set this to `false` when the model already supports implicit caching, or when the upstream does not accept this explicit-cache extension field. Set this to `true` for non-DashScope providers that support the same explicit-cache extension. Applied on both `/v1/messages` and `/v1/chat/completions` routes.
|
|
750
756
|
- `supportPdf` (optional): Controls whether the model supports PDF/document content. Defaults to `false`; unsupported PDFs are converted to a text notice. Set it to `true` to send PDF/document blocks as OpenAI Chat Completions file parts.
|
|
751
757
|
- `toolContentSupportType` (optional): Tool result content capabilities for that model, as an array of `array`, `image`, and `pdf`. Provider routes default to string-only tool content when omitted. If `supportPdf` is `true` but this list does not include `pdf`, file parts in tool results are moved to user role messages. The Copilot main flow uses the same string-only default, because some Copilot models do not support array or image tool content either.
|
|
@@ -755,8 +761,8 @@ Gateway API keys live under `auth.apiKeys` in `config.json`. Manage them with `c
|
|
|
755
761
|
- `inputModalities` (optional): Supported Codex input types. Use `["text", "image"]` for a model that accepts both text and images. Missing configured values use upstream metadata before the built-in non-GPT model catalog. GPT models do not receive these built-in capability defaults and continue to use the native Codex catalog or upstream metadata.
|
|
756
762
|
- `reasoningEfforts` (optional): Reasoning levels advertised for Codex. Missing configured and upstream values use the built-in non-GPT model catalog before falling back to `["high", "xhigh", "max", "ultra"]`. Provider Responses requests with an unsupported effort are normalized to a supported level when these capabilities are known.
|
|
757
763
|
- `defaultReasoningEffort` (optional): Default Codex reasoning level. Built-in model metadata may provide a known default; otherwise it defaults to `max` when available, then the first configured level. Synthetic Codex models always enable parallel tool calls.
|
|
758
|
-
- `reasoningField` (optional): Assistant thinking field sent upstream on OpenAI-compatible `/v1/messages` requests. Supports `reasoning` and `reasoning_content`; defaults to `reasoning_content`. Use `reasoning` for OpenRouter-style models;
|
|
759
|
-
- **
|
|
764
|
+
- `reasoningField` (optional): Assistant thinking field sent upstream on OpenAI-compatible `/v1/messages` requests. Supports `reasoning` and `reasoning_content`; defaults to `reasoning_content`. Use `reasoning` for OpenRouter-style models; OpenCode Go Hy-family models use this field based on the models.dev family metadata.
|
|
765
|
+
- **smallModels:** Per-provider model IDs for Codex task-title `/v1/responses` requests. `codex` and `copilot` default to `gpt-6-luna`; other providers switch only when named explicitly (e.g. `smallModels.dashscope`). Use a model supported by that provider; an empty string disables switching. The request must have matching user `input_text` in one of its last two input items. `copilot` also controls tool-less Claude Code warmups for non-token-based-billing accounts. The old `smallModel` key is ignored.
|
|
760
766
|
- **contextManagement:** Controls whether the proxy adds Responses API `context_management` compaction instructions. `messages` applies when Anthropic-style `/v1/messages` requests are translated to Responses API, including `openai-responses` provider message routes, and defaults to `true`. `responses` applies to native `/v1/responses` traffic, including `provider/model` aliases and the built-in `codex` provider, and defaults to `false`. Enable `responses` only after checking that your client supports context management compaction. When enabled, the request includes `context_management` in the body and keeps only the latest compaction carrier on follow-up turns. The proxy only adds context management and compacts history for `gpt-*` models; both configuration switches have no effect on non-GPT models such as Grok. **Note:** Context management is also forcibly disabled for GPT-5.6 and above models (e.g. `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`) because enabling it breaks prompt cache hits on those models. These overrides take precedence over the `contextManagement` and `modelResponsesApiCompactThresholds` settings.
|
|
761
767
|
- **modelResponsesApiCompactThresholds:** Per-model Responses API `compact_threshold` overrides used when the proxy adds `context_management`. These values take precedence over the fallback threshold from `resolveResponsesCompactThreshold` (`max_prompt_tokens * ratio`, or the default fallback). Defaults set `gpt-5.4` and `gpt-5.5` to `217600` (`272000 * 0.8`). Models not listed continue to use the normal fallback logic.
|
|
762
768
|
- **modelReasoningEfforts:** Per-model fallback reasoning effort for `/v1/messages` requests. It is used only when the request does not provide `output_config.effort`.
|
package/README.zh-CN.md
CHANGED
|
@@ -722,9 +722,11 @@ Copilot API 现在使用子命令结构,主要命令包括:
|
|
|
722
722
|
|
|
723
723
|
Codex provider 最多保存 3 个账号。使用 `copilot-api auth login --provider codex --alias work` 新增或更新账号,新登录账号会成为当前账号;使用 `copilot-api auth codex --list` 查看账号,使用 `copilot-api auth codex --use <alias-or-accountId>` 手动切换,使用 `copilot-api auth codex --remove <alias-or-accountId>` 移除未在使用的账号。别名不区分大小写,且不能与其他账号的别名或账号 ID 重复;正在使用的账号无法移除。切换或移除账号后需要重启正在运行的服务,使其停止使用旧账号;凭据刷新不会把已移除的账号写回。旧版单账号 `codex_credentials.json` 会自动兼容,并在下一次写入凭据时升级为多账号格式。
|
|
724
724
|
|
|
725
|
-
使用 `copilot-api auth login --provider deepseek`、`--provider dashscope`、`--provider openrouter`、`--provider opencode-go` 或 `--provider kimi` 可以通过 CLI 快速新增或更新这些常用第三方 provider。DeepSeek 会提示输入掩码显示的 `apiKey`、provider `type`(默认 `anthropic`),以及默认 `https://api.deepseek.com/anthropic` 的 `baseUrl`。DashScope 会提示输入掩码显示的 `apiKey`、provider `type`(默认 `openai-compatible`)和预填默认值的 `baseUrl`。OpenRouter 只提示输入掩码显示的 `apiKey` 和预填默认值的 `baseUrl`,并固定写入 `type: "anthropic"`。OpenCode Go 只提示输入掩码显示的 `apiKey` 和预填默认值的 `baseUrl`,并固定写入 `type: "openai-compatible"`(baseUrl `https://opencode.ai/zen/go`)。Kimi 会提示输入掩码显示的 `apiKey`、provider `type`(默认 `openai-compatible`)和默认值为 `https://api.kimi.com/coding` 的 `baseUrl`(同一个 base URL 同时支持 Anthropic 和 OpenAI-compatible 两种端点)。此外,OpenCode Go
|
|
725
|
+
使用 `copilot-api auth login --provider deepseek`、`--provider dashscope`、`--provider openrouter`、`--provider opencode-go` 或 `--provider kimi` 可以通过 CLI 快速新增或更新这些常用第三方 provider。DeepSeek 会提示输入掩码显示的 `apiKey`、provider `type`(默认 `anthropic`),以及默认 `https://api.deepseek.com/anthropic` 的 `baseUrl`。DashScope 会提示输入掩码显示的 `apiKey`、provider `type`(默认 `openai-compatible`)和预填默认值的 `baseUrl`。OpenRouter 只提示输入掩码显示的 `apiKey` 和预填默认值的 `baseUrl`,并固定写入 `type: "anthropic"`。OpenCode Go 只提示输入掩码显示的 `apiKey` 和预填默认值的 `baseUrl`,并固定写入 `type: "openai-compatible"`(baseUrl `https://opencode.ai/zen/go`)。Kimi 会提示输入掩码显示的 `apiKey`、provider `type`(默认 `openai-compatible`)和默认值为 `https://api.kimi.com/coding` 的 `baseUrl`(同一个 base URL 同时支持 Anthropic 和 OpenAI-compatible 两种端点)。此外,OpenCode Go 先读取 models.dev 中模型级 `provider.npm`,缺失时再使用 provider 级 `npm`:`@ai-sdk/anthropic` 走 Anthropic Messages,`@ai-sdk/openai` 走 OpenAI Responses(模型设置 `shape: completions` 时走 OpenAI 兼容协议);无法识别或缺失 `npm` 时默认走 OpenAI 兼容协议。配置并启用 provider 后,`copilot-api start` 可在没有 GitHub token 的情况下启动。
|
|
726
726
|
|
|
727
|
-
|
|
727
|
+
OpenCode Go 的模型列表(`/opencode-go/v1/models` 及 `/v1/models` 中的对应条目)来自 [models.dev/api.json](https://models.dev/api.json) 的 `opencode-go.models`。服务启动时先读取 `COPILOT_API_HOME`(或默认应用数据目录)下的 `models-dev-api.json`。有有效缓存时,服务立即开始监听并在后台刷新目录,此后每五分钟刷新一次;没有有效缓存时,启动会等待首次下载,获取目录失败则启动失败。刷新时有 `ETag` 或 `Last-Modified` 就使用条件请求,并将两个校验值连同 JSON 校验和保存到 `models-dev-api.meta.json`。收到 `304` 则保留现有缓存;后台刷新失败时继续使用上一份有效的磁盘或内存目录。`status: deprecated` 的模型不会出现在列表中。
|
|
728
|
+
|
|
729
|
+
使用 `copilot-api auth login --provider custom` 可以通过 CLI 新增或更新其他第三方 provider。先选择手动填写,或搜索现有的 models.dev 目录。目录仅列出具有 HTTP API URL、使用 Anthropic Messages、OpenAI 兼容 Chat Completions 或 OpenAI Responses 协议的 provider;不包含 `openrouter`、`github-copilot` 和 `opencode-go`。选中后会将 provider ID、协议和 API URL 预填到可编辑字段中。若 `config.json` 没有为模型显式配置价格,则使用 models.dev 的模型价格以 USD 估算 token 费用。随后输入掩码显示的 `apiKey` 和 `authType`;`authType` 可保持 type 默认值,也可选择 `x-api-key` / `authorization`。桌面端的自定义 provider 表单同样支持目录选择和手动填写。
|
|
728
730
|
|
|
729
731
|
网关 API Key 存放在 `config.json` 的 `auth.apiKeys` 中,可通过 `copilot-api auth keys` 管理(每次只执行一种操作):`--add <key>` 添加、`--remove <key>` 删除、`--list` 列出全部、`--clear` 清空。客户端通过 `x-api-key` 或 `Authorization: Bearer` 使用任意已配置的 Key 认证。未配置任何 Key 时,回环监听会以“不校验认证”的方式启动并输出一条 info 级别提示;非回环监听则拒绝启动。
|
|
730
732
|
|
|
@@ -748,7 +750,10 @@ Codex provider 最多保存 3 个账号。使用 `copilot-api auth login --provi
|
|
|
748
750
|
},
|
|
749
751
|
"providers": {},
|
|
750
752
|
"modelMappings": {},
|
|
751
|
-
"
|
|
753
|
+
"smallModels": {
|
|
754
|
+
"codex": "gpt-6-luna",
|
|
755
|
+
"copilot": "gpt-6-luna"
|
|
756
|
+
},
|
|
752
757
|
"contextManagement": {
|
|
753
758
|
"messages": true,
|
|
754
759
|
"responses": false
|
|
@@ -779,7 +784,8 @@ Codex provider 最多保存 3 个账号。使用 `copilot-api auth login --provi
|
|
|
779
784
|
- **extraPrompts:** `model -> prompt` 的映射。把 Anthropic 风格请求翻译为 Responses API 时,会将其附加到第一条 system prompt 后面。你可以借此为不同模型注入护栏或指引。对于 GPT-5.3+ 模型(如 `gpt-5.3-codex`、`gpt-5.4`、`gpt-5.5`),未显式配置时会自动使用内置的 commentary prompt。内置 prompt 会启用带阶段感知的 commentary,让模型在工具调用或更深层推理前先发出简短的用户可见进度说明。
|
|
780
785
|
- **providers:** 全局上游 provider 映射。每个 provider key(例如 `dashscope`)都会变成一个路由前缀(`/dashscope/v1/messages`)。支持 `type: "anthropic"`、`type: "openai-compatible"` 和 `type: "openai-responses"`。顶层客户端也可以在 `/v1/messages`、`/v1/messages/count_tokens`、`/v1/responses` 和 `/v1/chat/completions` 中使用 `model: "dashscope/model-id"`;AI gateway 会在转发上游前移除 `dashscope/` 前缀。`anthropic` 和 `openai-compatible` provider 的 `/v1/responses` 会通过 Responses Lite → Messages 适配;其中 `openai-compatible` provider 再复用 Messages → Chat 翻译。Codex 客户端(`User-Agent` 以 `codex` 开头)在 `openai-responses` provider 上请求非 `gpt-*` 模型时同样走该适配路径。`GET /v1/models` 会聚合已启用 provider 的模型,并以 `provider/model-id` 形式返回;Codex UA 的顶层模型列表还会把这些可适配模型合并为 `use_responses_lite` 模型(DeepSeek 模型除外,它们使用 `use_responses_lite: false` 和 `tool_mode: null`)。单个 provider 的原始模型列表仍可使用 `GET /dashscope/v1/models`。
|
|
781
786
|
- `enabled`:可选,若省略则默认为 `true`。
|
|
782
|
-
- `baseUrl
|
|
787
|
+
- `baseUrl`:手动填写 provider 时使用其 API 基础 URL,不要带结尾的 endpoint。Anthropic provider 不要带 `/v1/messages`;OpenAI 兼容 provider 不要带 `/v1/chat/completions`;OpenAI Responses provider 不要带 `/v1/responses`。
|
|
788
|
+
- `modelsDevProviderId`:可选,通过自定义授权选择 models.dev provider 时写入。此时 `baseUrl` 为 models.dev 提供的 API URL(也可编辑),网关直接追加 `/messages`、`/chat/completions` 或 `/responses`。缓存目录中的模型级协议和 USD 价格元数据在可用时生效;仅当 `baseUrl` 与目录中的 provider API URL 一致时,才应用模型级 API URL 覆盖。显式配置的 `models.<id>.pricing` 优先。手动填写的 provider 仍使用 `baseUrl` 加 `/v1/<endpoint>`。
|
|
783
789
|
- `apiKey`:作为上游凭据值使用;除 `authType` 为 `azure-entra` 外,普通 provider 必须配置。
|
|
784
790
|
- `authType`:可选,控制上游认证方式。普通 provider 支持 `x-api-key`、`authorization` 和 `azure-entra`。Anthropic provider 默认 `x-api-key`;OpenAI 兼容和 OpenAI Responses provider 默认 `authorization`。`authorization` 会发送 `Authorization: Bearer <apiKey>`。`azure-entra` 使用 Azure Identity 的 `DefaultAzureCredential` 和 `https://cognitiveservices.azure.com/.default` scope 获取并发送 Bearer token,不需要配置 `apiKey`。Azure OpenAI v1 endpoint 可配置为 `{ "type": "openai-compatible", "baseUrl": "https://<resource-name>.openai.azure.com/openai", "authType": "azure-entra" }`。本地可先执行 `az login`,在 Azure 中可使用托管身份,也可设置标准的 `AZURE_TENANT_ID`、`AZURE_CLIENT_ID` 和 `AZURE_CLIENT_SECRET` 环境变量。`oauth2` 仅保留给内置 `codex` provider,并由 `auth login --provider codex` 自动写入。
|
|
785
791
|
- `accountId`:仅用于内置 `codex` provider,记录当前选中的 Codex 账号。CLI 或桌面端切换账号时自动更新。
|
|
@@ -789,7 +795,7 @@ Codex provider 最多保存 3 个账号。使用 `copilot-api auth login --provi
|
|
|
789
795
|
- `topP`:可选,当请求未指定时使用的默认 `top_p`。
|
|
790
796
|
- `topK`:可选,当请求未指定时使用的默认 `top_k`。
|
|
791
797
|
- `extraBody`:可选,按模型合入上游请求体的动态字段;请求体显式同名字段优先。OpenAI 兼容 provider 可用它配置 `enable_thinking`、`preserve_thinking`、`reasoning_effort` 等字段。`thinking_budget` 是 OpenAI 兼容 provider 的特殊覆盖项:配置在 `extraBody` 后,会在 Anthropic `thinking.budget_tokens` 翻译之后强制写入,并覆盖请求派生出的预算值。对于 provider name 为 `dashscope` 或 `baseUrl` 包含 `aliyuncs.com` 的 provider,请求派生的 `thinking_budget`(来自 Anthropic `thinking.budget_tokens`)会转发给上游;其他 OpenAI 兼容 provider 会移除请求派生的 `thinking_budget`,但 `extraBody` 中的 `thinking_budget` 仍然生效。对于 DashScope provider,当 `preserve_thinking` 未在 `extraBody` 或请求体中显式设置时,默认为 `true`。
|
|
792
|
-
- `pricing`:可选,按模型配置 token 单价,币种使用 provider 的 `pricingCurrency`,单位为每 100 万 tokens。支持 `input`、`output`、`cachedInput`(隐式缓存读)、`explicitCachedInput`(显式缓存读)和 `cacheCreationInput`。如需按输入 token 总量分档,可用带 `maxInputTokens` 的 `tiers`。分时计费的 provider 可再配置 `offPeak`(字段与顶层相同)声明闲时单价,并用 `peakWindows` 声明忙时时段:每项包含 `startMinuteUtc`(含)和 `endMinuteUtc`(不含),取值为 UTC 当日分钟数,可选用 `weekdays` 以 ISO 星期号(1 表示周一,7 表示周日)限定生效日,省略表示每天生效。未配置 `peakWindows` 时 `offPeak` 不生效,始终按忙时价计费。内置目录已按此方式为 DeepSeek(周一至周五 UTC 01:00-04:00、06:00-10:00 为忙时,其余含周末为闲时)和 DashScope DeepSeek(UTC 14:00-24:00 为闲时)配置峰谷价,OpenCode Go
|
|
798
|
+
- `pricing`:可选,按模型配置 token 单价,币种使用 provider 的 `pricingCurrency`,单位为每 100 万 tokens。支持 `input`、`output`、`cachedInput`(隐式缓存读)、`explicitCachedInput`(显式缓存读)和 `cacheCreationInput`。如需按输入 token 总量分档,可用带 `maxInputTokens` 的 `tiers`。分时计费的 provider 可再配置 `offPeak`(字段与顶层相同)声明闲时单价,并用 `peakWindows` 声明忙时时段:每项包含 `startMinuteUtc`(含)和 `endMinuteUtc`(不含),取值为 UTC 当日分钟数,可选用 `weekdays` 以 ISO 星期号(1 表示周一,7 表示周日)限定生效日,省略表示每天生效。未配置 `peakWindows` 时 `offPeak` 不生效,始终按忙时价计费。内置目录已按此方式为 DeepSeek(周一至周五 UTC 01:00-04:00、06:00-10:00 为忙时,其余含周末为闲时)和 DashScope DeepSeek(UTC 14:00-24:00 为闲时)配置峰谷价,OpenCode Go 的价格采用 models.dev 当前公布的数值。
|
|
793
799
|
- `contextCache`:可选,provider name 为 `dashscope` 或 `baseUrl` 包含 `aliyuncs.com` 时默认 `true`,其他 OpenAI 兼容 provider 默认 `false`。用于启用阿里云百炼/DashScope 的显式缓存(explicit context cache),会按其 Context Cache 格式在最多 4 个 content block 上注入 `cache_control: { "type": "ephemeral" }`。缓存断点策略与 opencode 主链路保持一致:前 2 条 system 消息 + 最后 2 条非 system 消息。标记字符串 content 时会把 `system` / `user` / `assistant` / `tool` 消息转换为 text content part 数组;已有数组 content 则标记最后一个 part。如果模型本身已经支持隐式缓存,或上游不支持该显式缓存扩展字段,可在模型配置中设为 `false`。支持相同显式缓存扩展的非 DashScope provider 可设为 `true`。同时适用于 `/v1/messages` 和 `/v1/chat/completions` 路由。
|
|
794
800
|
- `supportPdf`:可选,控制该模型是否支持 PDF/document content。默认 `false`,不支持时会把 PDF 转成提示文本;设为 `true` 时会把 PDF/document 转成 OpenAI Chat Completions 的 file part。
|
|
795
801
|
- `toolContentSupportType`:可选,配置该模型的 tool result content 支持能力,值为 `array`、`image`、`pdf` 的数组。provider 侧未配置时默认只发送 string tool content。若 `supportPdf` 为 `true` 但这里不包含 `pdf`,tool result 里的 file part 会被转成 user role 消息。Copilot 主链路同样默认只发送 string tool content,因为部分 Copilot 模型也不支持数组或图片形式的 tool content。
|
|
@@ -799,8 +805,8 @@ Codex provider 最多保存 3 个账号。使用 `copilot-api auth login --provi
|
|
|
799
805
|
- `inputModalities`:可选,Codex 支持的输入类型;模型同时支持文本和图片时配置为 `["text", "image"]`。用户未配置时优先使用上游元数据,再使用非 GPT 模型的内置目录。GPT 模型不注入这些内置能力默认值,继续使用原生 Codex catalog 或上游元数据。
|
|
800
806
|
- `reasoningEfforts`:可选,Codex 支持的推理档位。配置和上游元数据均未提供时,会先使用非 GPT 模型的内置目录,再回退到 `["high", "xhigh", "max", "ultra"]`。已知模型能力时,Provider Responses 请求中的不支持档位会被归一化为支持的档位。
|
|
801
807
|
- `defaultReasoningEffort`:可选,Codex 默认推理档位;内置模型元数据可以提供已知默认值,否则可用档位包含 `max` 时默认取 `max`,再回退到配置的第一个档位。合成 Codex 模型始终启用并行工具调用。
|
|
802
|
-
- `reasoningField`:可选,OpenAI-compatible `/v1/messages` 转发 assistant 思考文本时使用的字段,支持 `reasoning` 与 `reasoning_content`,默认 `reasoning_content`;OpenRouter 风格模型设为 `reasoning
|
|
803
|
-
- **
|
|
808
|
+
- `reasoningField`:可选,OpenAI-compatible `/v1/messages` 转发 assistant 思考文本时使用的字段,支持 `reasoning` 与 `reasoning_content`,默认 `reasoning_content`;OpenRouter 风格模型设为 `reasoning`,OpenCode Go 的 Hy 系列模型会根据 models.dev 的 family 元数据使用 `reasoning` 字段。
|
|
809
|
+
- **smallModels:** 按 provider 指定 Codex 客户端 `/v1/responses` 标题请求的模型。`codex`、`copilot` 默认使用 `gpt-6-luna`;其他 provider 仅在配置同名键时切换(如 `smallModels.dashscope`)。模型须受对应 provider 支持;设为空字符串可禁用切换。标题提示词须出现在最后两个 input 项之一的 user `input_text` 中。`copilot` 也用于非 token-based 计费账户的 Claude Code 无工具预热;旧 `smallModel` 不再生效。
|
|
804
810
|
- **contextManagement:** 控制代理是否为 Responses API 附加 `context_management` 压缩指令。`messages` 作用于被翻译成 Responses API 的 Anthropic 风格 `/v1/messages` 请求,包括 `openai-responses` provider 的 Messages 路由,默认值为 `true`。`responses` 作用于 native `/v1/responses` 流量,包括 `provider/model` 别名和内置 `codex` provider,默认值为 `false`。只有在确认客户端支持 context management compaction 后,才建议在 Responses API 下启用 `responses`。启用后,请求体会带上 `context_management`,并在后续轮次中仅保留最新的压缩承载内容。代理仅为 `gpt-*` 模型添加 context management 并压缩历史;这两个配置开关对 Grok 等非 GPT 模型不生效。**注意:** 对于 GPT-5.6 及以上模型(如 `gpt-5.6-sol`、`gpt-5.6-terra`、`gpt-5.6-luna`),context management 功能同样会被强制禁用,因为开启后会破坏这些模型的 prompt 缓存命中。这些强制覆盖优先于 `contextManagement` 和 `modelResponsesApiCompactThresholds` 配置。
|
|
805
811
|
- **modelResponsesApiCompactThresholds:** 按模型覆盖 Responses API 的 `compact_threshold`,仅在代理自动附加 `context_management` 时使用。它的优先级高于 `resolveResponsesCompactThreshold` 基于 `max_prompt_tokens * ratio` 的兜底阈值。默认将 `gpt-5.4` 和 `gpt-5.5` 设为 `217600`(`272000 * 0.8`)。未列出的模型继续使用原有兜底逻辑。
|
|
806
812
|
- **modelReasoningEfforts:** `/v1/messages` 请求的模型级默认推理强度。仅当请求没有传入 `output_config.effort` 时,该配置才会生效。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { F as getConfiguredApiKeys, L as loginCodex, Z as state, a as selectCodexAccount, c as setupGitHubToken, i as removeCodexAccount, r as persistCodexCredentials, t as getCodexAccounts } from "./token-
|
|
1
|
+
import { B as PATHS, T as SUPPORTED_PROVIDER_TYPES, V as ensurePaths, a as normalizeProviderBaseUrl, c as setProviderConfig, f as loadModelsDevProviderOptions, n as getRawProviderConfig, r as isSupportedProviderType, z as setConfiguredApiKeys } from "./config-B_pC8QXv.js";
|
|
2
|
+
import { F as getConfiguredApiKeys, L as loginCodex, Z as state, a as selectCodexAccount, c as setupGitHubToken, i as removeCodexAccount, r as persistCodexCredentials, t as getCodexAccounts } from "./token-3SWNt25T.js";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
//#region src/lib/quick-providers.ts
|
|
@@ -224,14 +224,21 @@ async function promptRequiredSecret(message, fieldName) {
|
|
|
224
224
|
if (!normalizedValue) throw new Error(`${fieldName} must be a non-empty string`);
|
|
225
225
|
return normalizedValue;
|
|
226
226
|
}
|
|
227
|
-
async function promptCustomProviderName() {
|
|
228
|
-
const providerName = await
|
|
227
|
+
async function promptCustomProviderName(defaultName) {
|
|
228
|
+
const providerName = (await prompt("Enter provider name", {
|
|
229
|
+
type: "text",
|
|
230
|
+
...defaultName ? {
|
|
231
|
+
default: defaultName,
|
|
232
|
+
initial: defaultName
|
|
233
|
+
} : {}
|
|
234
|
+
}) || defaultName || "").trim();
|
|
229
235
|
assertCustomProviderName(providerName);
|
|
230
236
|
return providerName;
|
|
231
237
|
}
|
|
232
|
-
async function promptCustomProviderType() {
|
|
238
|
+
async function promptCustomProviderType(defaultType) {
|
|
233
239
|
const providerType = await prompt("Select provider type", {
|
|
234
240
|
type: "select",
|
|
241
|
+
initial: defaultType,
|
|
235
242
|
options: SUPPORTED_PROVIDER_TYPES.map((type) => ({
|
|
236
243
|
label: type,
|
|
237
244
|
value: type
|
|
@@ -240,6 +247,34 @@ async function promptCustomProviderType() {
|
|
|
240
247
|
if (typeof providerType !== "string" || !isSupportedProviderType(providerType)) throw new Error("No provider type selected");
|
|
241
248
|
return providerType;
|
|
242
249
|
}
|
|
250
|
+
async function promptModelsDevProvider() {
|
|
251
|
+
const source = await prompt("Choose custom provider source", {
|
|
252
|
+
type: "select",
|
|
253
|
+
options: [{
|
|
254
|
+
label: "Enter manually",
|
|
255
|
+
value: "manual"
|
|
256
|
+
}, {
|
|
257
|
+
label: "Choose from models.dev",
|
|
258
|
+
value: "models-dev"
|
|
259
|
+
}]
|
|
260
|
+
});
|
|
261
|
+
if (source === "manual") return void 0;
|
|
262
|
+
if (source !== "models-dev") throw new Error("No provider source selected");
|
|
263
|
+
const providers = await loadModelsDevProviderOptions();
|
|
264
|
+
const query = (await prompt("Search models.dev providers (blank to list all)", { type: "text" }) ?? "").trim().toLowerCase();
|
|
265
|
+
const matches = providers.filter((provider) => provider.id.toLowerCase().includes(query) || provider.name.toLowerCase().includes(query));
|
|
266
|
+
if (matches.length === 0) throw new Error("No matching models.dev providers with a supported API URL");
|
|
267
|
+
const selectedId = await prompt("Select a models.dev provider", {
|
|
268
|
+
type: "select",
|
|
269
|
+
options: matches.map((provider) => ({
|
|
270
|
+
label: `${provider.name} (${provider.id}) — ${provider.type}`,
|
|
271
|
+
value: provider.id
|
|
272
|
+
}))
|
|
273
|
+
});
|
|
274
|
+
const selectedProvider = matches.find((provider) => provider.id === selectedId);
|
|
275
|
+
if (!selectedProvider) throw new Error("No models.dev provider selected");
|
|
276
|
+
return selectedProvider;
|
|
277
|
+
}
|
|
243
278
|
async function promptQuickProviderType(defaultType) {
|
|
244
279
|
const providerType = await prompt(`Select provider type (default: ${defaultType})`, {
|
|
245
280
|
type: "select",
|
|
@@ -288,6 +323,7 @@ function buildCustomProviderConfig(existingProviderConfig, options) {
|
|
|
288
323
|
type: options.type,
|
|
289
324
|
enabled: true,
|
|
290
325
|
baseUrl: options.baseUrl,
|
|
326
|
+
...options.modelsDevProviderId && { modelsDevProviderId: options.modelsDevProviderId },
|
|
291
327
|
apiKey: options.apiKey,
|
|
292
328
|
...options.authType ? { authType: options.authType } : {},
|
|
293
329
|
pricingCurrency: options.pricingCurrency ?? existingProviderConfig.pricingCurrency,
|
|
@@ -295,9 +331,10 @@ function buildCustomProviderConfig(existingProviderConfig, options) {
|
|
|
295
331
|
};
|
|
296
332
|
}
|
|
297
333
|
async function configureCustomProvider() {
|
|
298
|
-
const
|
|
299
|
-
const
|
|
300
|
-
const
|
|
334
|
+
const catalogProvider = await promptModelsDevProvider();
|
|
335
|
+
const providerName = await promptCustomProviderName(catalogProvider?.id);
|
|
336
|
+
const type = await promptCustomProviderType(catalogProvider?.type);
|
|
337
|
+
const baseUrl = catalogProvider ? await promptQuickProviderBaseUrl(catalogProvider.api) : normalizeProviderBaseUrl(await promptRequiredText("Enter provider baseUrl", "baseUrl"));
|
|
301
338
|
if (!baseUrl) throw new Error("baseUrl must be a non-empty string");
|
|
302
339
|
const apiKey = await promptRequiredSecret("Enter provider apiKey", "apiKey");
|
|
303
340
|
const authType = await promptCustomProviderAuthType(type);
|
|
@@ -306,6 +343,7 @@ async function configureCustomProvider() {
|
|
|
306
343
|
apiKey,
|
|
307
344
|
authType,
|
|
308
345
|
baseUrl,
|
|
346
|
+
modelsDevProviderId: catalogProvider?.id,
|
|
309
347
|
type
|
|
310
348
|
}));
|
|
311
349
|
consola.success(`Custom provider '${providerName}' written to ${PATHS.CONFIG_PATH}`);
|
|
@@ -571,4 +609,4 @@ const auth = defineCommand({
|
|
|
571
609
|
//#endregion
|
|
572
610
|
export { runProviderSetup as a, runAuthLogin as i, runAuthCodex as n, runAuthKeys as r, auth as t };
|
|
573
611
|
|
|
574
|
-
//# sourceMappingURL=auth-
|
|
612
|
+
//# sourceMappingURL=auth-B1iccyyN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-B1iccyyN.js","names":[],"sources":["../src/lib/quick-providers.ts","../src/lib/interactive-prompt.ts","../src/auth.ts"],"sourcesContent":["import type { ProviderType } from \"./config\"\n\ninterface QuickProviderConfig {\n type: ProviderType\n baseUrl: string\n pricingCurrency: string\n editableType: boolean\n}\n\nexport const QUICK_PROVIDER_CONFIGS = {\n \"opencode-go\": {\n type: \"openai-compatible\",\n baseUrl: \"https://opencode.ai/zen/go\",\n pricingCurrency: \"USD\",\n editableType: false,\n },\n kimi: {\n type: \"openai-compatible\",\n baseUrl: \"https://api.kimi.com/coding\",\n pricingCurrency: \"USD\",\n editableType: true,\n },\n deepseek: {\n type: \"anthropic\",\n baseUrl: \"https://api.deepseek.com/anthropic\",\n pricingCurrency: \"CNY\",\n editableType: true,\n },\n dashscope: {\n type: \"openai-compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode\",\n pricingCurrency: \"CNY\",\n editableType: true,\n },\n openrouter: {\n type: \"anthropic\",\n baseUrl: \"https://openrouter.ai/api\",\n pricingCurrency: \"USD\",\n editableType: false,\n },\n} satisfies Record<string, QuickProviderConfig>\n\nexport type QuickProviderName = keyof typeof QUICK_PROVIDER_CONFIGS\n","import consola from \"consola\"\n\ninterface PromptSelectOption {\n label: string\n value: string\n hint?: string\n}\n\ninterface TextPromptOptions {\n type?: \"text\"\n default?: string\n initial?: string\n placeholder?: string\n}\n\ninterface SelectPromptOptions {\n type: \"select\"\n initial?: string\n options: Array<string | PromptSelectOption>\n}\n\nexport type InteractivePromptOptions = SelectPromptOptions | TextPromptOptions\n\ninterface ClackSelectOptions {\n message: string\n initialValue?: string\n options: Array<PromptSelectOption>\n}\n\ninterface ClackTextOptions {\n message: string\n defaultValue?: string\n initialValue?: string\n placeholder?: string\n}\n\nexport interface ClackPromptBackend {\n isCancel(value: unknown): boolean\n select(options: ClackSelectOptions): Promise<string | symbol>\n text(options: ClackTextOptions): Promise<string | symbol>\n}\n\ninterface PromptRuntime {\n bunVersion?: string\n platform: NodeJS.Platform\n stdinIsTTY?: boolean\n stdoutIsTTY?: boolean\n stdoutIsTTYStream?: boolean\n}\n\n// Consola 3.4.2 bundles a prompt implementation that writes keyboard input to\n// tty fd 0. Bun treats that as a real stdin write on Windows and throws EPIPE.\nexport function shouldUseClackPrompt(\n runtime: PromptRuntime = {\n bunVersion: process.versions.bun,\n platform: process.platform,\n stdinIsTTY: process.stdin.isTTY,\n stdoutIsTTY: process.stdout.isTTY,\n stdoutIsTTYStream: typeof process.stdout.getColorDepth === \"function\",\n },\n): boolean {\n return Boolean(\n runtime.platform === \"win32\"\n && runtime.bunVersion\n && runtime.stdinIsTTY\n && runtime.stdoutIsTTY\n && runtime.stdoutIsTTYStream,\n )\n}\n\nfunction getCancelValue(options: InteractivePromptOptions): string | undefined {\n return options.type === \"select\" ?\n options.initial\n : (options.default ?? options.initial)\n}\n\nexport async function promptWithClack(\n message: string,\n options: InteractivePromptOptions,\n backend: ClackPromptBackend,\n): Promise<string | undefined> {\n if (options.type === \"select\") {\n const value = await backend.select({\n message,\n options: options.options.map((option) =>\n typeof option === \"string\" ? { label: option, value: option } : option,\n ),\n initialValue: options.initial,\n })\n if (backend.isCancel(value)) {\n return getCancelValue(options)\n }\n return typeof value === \"string\" ? value : undefined\n }\n\n const value = await backend.text({\n message,\n defaultValue: options.default,\n initialValue: options.initial,\n placeholder: options.placeholder,\n })\n if (backend.isCancel(value)) {\n return getCancelValue(options)\n }\n return typeof value === \"string\" ? value : undefined\n}\n\nexport async function prompt(\n message: string,\n options: InteractivePromptOptions,\n): Promise<string | undefined> {\n if (!shouldUseClackPrompt()) {\n if (options.type === \"select\") {\n const value = await consola.prompt(message, options)\n return typeof value === \"string\" ? value : undefined\n }\n return await consola.prompt(message, options)\n }\n\n const clack = await import(\"@clack/prompts\")\n return await promptWithClack(message, options, clack)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport {\n getRawProviderConfig,\n isSupportedProviderType,\n normalizeProviderBaseUrl,\n setProviderConfig,\n setConfiguredApiKeys,\n SUPPORTED_PROVIDER_TYPES,\n type ProviderAuthType,\n type ProviderConfig,\n type ProviderType,\n} from \"./lib/config\"\nimport { loginCodex } from \"./lib/oauth/codex\"\nimport {\n loadModelsDevProviderOptions,\n type ModelsDevProviderOption,\n} from \"./lib/models-dev-cache\"\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { getConfiguredApiKeys } from \"./lib/request-auth\"\nimport {\n QUICK_PROVIDER_CONFIGS,\n type QuickProviderName,\n} from \"./lib/quick-providers\"\nimport { prompt } from \"./lib/interactive-prompt\"\nimport { state } from \"./lib/state\"\nimport {\n getCodexAccounts,\n persistCodexCredentials,\n removeCodexAccount,\n selectCodexAccount,\n setupGitHubToken,\n type CodexAccountSummary,\n} from \"./lib/token\"\n\ninterface RunAuthOptions {\n alias?: string\n provider?: string\n verbose: boolean\n showToken: boolean\n}\n\nconst authArgs = {\n provider: {\n type: \"string\",\n description:\n \"Provider to log in with or configure (copilot, codex, opencode-go, kimi, deepseek, dashscope, openrouter, custom)\",\n },\n alias: {\n type: \"string\",\n description: \"Optional alias for a Codex account\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show provider access token on auth\",\n },\n} as const\n\nconst BUILTIN_PROVIDER_NAMES = [\"copilot\", \"codex\"] as const\nconst QUICK_PROVIDER_NAMES = Object.keys(\n QUICK_PROVIDER_CONFIGS,\n) as Array<QuickProviderName>\nconst AUTH_PROVIDER_NAMES = [\n ...BUILTIN_PROVIDER_NAMES,\n ...QUICK_PROVIDER_NAMES,\n \"custom\",\n] as const\nconst CUSTOM_PROVIDER_AUTH_TYPE_OPTION = \"__default__\"\nconst QUICK_PROVIDER_DEFAULT_TYPE_OPTION = \"__default__\"\nconst CUSTOM_PROVIDER_AUTH_TYPES = [\"x-api-key\", \"authorization\"] as const\n\ntype BuiltinProviderName = (typeof BUILTIN_PROVIDER_NAMES)[number]\ntype AuthProviderName = (typeof AUTH_PROVIDER_NAMES)[number]\ntype CustomProviderAuthType = (typeof CUSTOM_PROVIDER_AUTH_TYPES)[number]\n\nconst BUILTIN_PROVIDER_LABELS: Record<BuiltinProviderName, string> = {\n copilot: \"GitHub Copilot\",\n codex: \"OpenAI Codex\",\n}\nconst AUTH_PROVIDER_LABELS: Record<AuthProviderName, string> = {\n ...BUILTIN_PROVIDER_LABELS,\n \"opencode-go\": \"OpenCode Go\",\n kimi: \"Kimi\",\n deepseek: \"DeepSeek\",\n dashscope: \"DashScope\",\n openrouter: \"OpenRouter\",\n custom: \"Custom provider\",\n}\n\nfunction isAuthProviderName(\n providerName: string,\n): providerName is AuthProviderName {\n return AUTH_PROVIDER_NAMES.includes(providerName as AuthProviderName)\n}\n\nfunction isCustomProviderAuthType(\n value: string,\n): value is CustomProviderAuthType {\n return CUSTOM_PROVIDER_AUTH_TYPES.includes(value as CustomProviderAuthType)\n}\n\nfunction isQuickProviderName(\n providerName: AuthProviderName,\n): providerName is QuickProviderName {\n return QUICK_PROVIDER_NAMES.includes(providerName as QuickProviderName)\n}\n\nasync function resolveProviderSelection(\n providerArg: string | undefined,\n): Promise<AuthProviderName> {\n const availableProviders = [...AUTH_PROVIDER_NAMES]\n\n if (providerArg !== undefined) {\n const providerName = providerArg.trim()\n if (!isAuthProviderName(providerName)) {\n throw new Error(\n `Unknown provider '${providerArg}'. Expected one of: ${availableProviders.join(\", \")}`,\n )\n }\n return providerName\n }\n\n if (availableProviders.length === 1) {\n return availableProviders[0]\n }\n\n const provider = await prompt(\"Select a provider to log in with\", {\n type: \"select\",\n options: availableProviders.map((providerName) => ({\n label: `${AUTH_PROVIDER_LABELS[providerName]} (${providerName})`,\n value: providerName,\n })),\n })\n\n if (!provider || !isAuthProviderName(provider)) {\n throw new Error(\"No provider selected\")\n }\n\n return provider\n}\n\nfunction assertCustomProviderName(providerName: string): void {\n if (!providerName) {\n throw new Error(\"Provider name must be a non-empty string\")\n }\n\n if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(providerName)) {\n throw new Error(\n \"Provider name must start with a letter or number and contain only letters, numbers, underscores, or hyphens\",\n )\n }\n\n if (providerName === \"copilot\" || providerName === \"codex\") {\n throw new Error(\n `Provider name '${providerName}' is reserved for a builtin provider`,\n )\n }\n}\n\nasync function promptRequiredText(\n message: string,\n fieldName: string,\n): Promise<string> {\n const value = await prompt(message, { type: \"text\" })\n const normalizedValue = typeof value === \"string\" ? value.trim() : \"\"\n if (!normalizedValue) {\n throw new Error(`${fieldName} must be a non-empty string`)\n }\n return normalizedValue\n}\n\nfunction canUseMaskedPrompt(): boolean {\n return Boolean(\n process.stdin.isTTY\n && process.stdout.isTTY\n && typeof process.stdin.setRawMode === \"function\",\n )\n}\n\nasync function promptMaskedText(message: string): Promise<string> {\n if (!canUseMaskedPrompt()) {\n const value = await prompt(message, { type: \"text\" })\n return typeof value === \"string\" ? value : \"\"\n }\n\n return await new Promise<string>((resolve, reject) => {\n let value = \"\"\n const rawModeWasEnabled = process.stdin.isRaw === true\n\n function cleanup(): void {\n process.stdin.off(\"data\", onData)\n process.stdin.setRawMode(rawModeWasEnabled)\n process.stdin.pause()\n }\n\n function finish(): void {\n cleanup()\n process.stdout.write(\"\\n\")\n resolve(value)\n }\n\n function cancel(): void {\n cleanup()\n process.stdout.write(\"\\n\")\n reject(new Error(\"Prompt cancelled\"))\n }\n\n function onData(chunk: Buffer): void {\n const input = chunk.toString(\"utf8\")\n\n if (input.startsWith(\"\\u001B\")) {\n return\n }\n\n for (const char of input) {\n if (char === \"\\u0003\") {\n cancel()\n return\n }\n\n if (char === \"\\r\" || char === \"\\n\") {\n finish()\n return\n }\n\n if (char === \"\\b\" || char === \"\\u007F\") {\n if (value.length > 0) {\n value = value.slice(0, -1)\n process.stdout.write(\"\\b \\b\")\n }\n continue\n }\n\n if (char >= \" \") {\n value += char\n process.stdout.write(\"*\")\n }\n }\n }\n\n process.stdout.write(`${message}: `)\n process.stdin.setRawMode(true)\n process.stdin.resume()\n process.stdin.on(\"data\", onData)\n })\n}\n\nasync function promptRequiredSecret(\n message: string,\n fieldName: string,\n): Promise<string> {\n const value = await promptMaskedText(message)\n const normalizedValue = value.trim()\n if (!normalizedValue) {\n throw new Error(`${fieldName} must be a non-empty string`)\n }\n return normalizedValue\n}\n\nasync function promptCustomProviderName(defaultName?: string): Promise<string> {\n const value = await prompt(\"Enter provider name\", {\n type: \"text\",\n ...(defaultName ? { default: defaultName, initial: defaultName } : {}),\n })\n const providerName = (value || defaultName || \"\").trim()\n assertCustomProviderName(providerName)\n return providerName\n}\n\nasync function promptCustomProviderType(\n defaultType?: ProviderType,\n): Promise<ProviderType> {\n const providerType = await prompt(\"Select provider type\", {\n type: \"select\",\n initial: defaultType,\n options: SUPPORTED_PROVIDER_TYPES.map((type) => ({\n label: type,\n value: type,\n })),\n })\n\n if (\n typeof providerType !== \"string\"\n || !isSupportedProviderType(providerType)\n ) {\n throw new Error(\"No provider type selected\")\n }\n\n return providerType\n}\n\nasync function promptModelsDevProvider(): Promise<\n ModelsDevProviderOption | undefined\n> {\n const source = await prompt(\"Choose custom provider source\", {\n type: \"select\",\n options: [\n { label: \"Enter manually\", value: \"manual\" },\n { label: \"Choose from models.dev\", value: \"models-dev\" },\n ],\n })\n if (source === \"manual\") return undefined\n if (source !== \"models-dev\") throw new Error(\"No provider source selected\")\n\n const providers = await loadModelsDevProviderOptions()\n const query = (\n (await prompt(\"Search models.dev providers (blank to list all)\", {\n type: \"text\",\n })) ?? \"\"\n )\n .trim()\n .toLowerCase()\n const matches = providers.filter(\n (provider) =>\n provider.id.toLowerCase().includes(query)\n || provider.name.toLowerCase().includes(query),\n )\n if (matches.length === 0) {\n throw new Error(\"No matching models.dev providers with a supported API URL\")\n }\n const selectedId = await prompt(\"Select a models.dev provider\", {\n type: \"select\",\n options: matches.map((provider) => ({\n label: `${provider.name} (${provider.id}) — ${provider.type}`,\n value: provider.id,\n })),\n })\n const selectedProvider = matches.find(\n (provider) => provider.id === selectedId,\n )\n if (!selectedProvider) throw new Error(\"No models.dev provider selected\")\n return selectedProvider\n}\n\nasync function promptQuickProviderType(\n defaultType: ProviderType,\n): Promise<ProviderType> {\n const providerType = await prompt(\n `Select provider type (default: ${defaultType})`,\n {\n type: \"select\",\n options: [\n {\n label: `Default (${defaultType})`,\n value: QUICK_PROVIDER_DEFAULT_TYPE_OPTION,\n },\n ...SUPPORTED_PROVIDER_TYPES.map((type) => ({\n label: type,\n value: type,\n })),\n ],\n },\n )\n\n if (providerType === QUICK_PROVIDER_DEFAULT_TYPE_OPTION) {\n return defaultType\n }\n\n if (\n typeof providerType === \"string\"\n && isSupportedProviderType(providerType)\n ) {\n return providerType\n }\n\n throw new Error(\"No provider type selected\")\n}\n\nfunction getDefaultProviderAuthType(\n providerType: ProviderType,\n): ProviderAuthType {\n return providerType === \"anthropic\" ? \"x-api-key\" : \"authorization\"\n}\n\nasync function promptCustomProviderAuthType(\n providerType: ProviderType,\n): Promise<ProviderAuthType | undefined> {\n const defaultAuthType = getDefaultProviderAuthType(providerType)\n const authType = await prompt(\"Select provider auth type\", {\n type: \"select\",\n options: [\n {\n label: `Default (${defaultAuthType})`,\n value: CUSTOM_PROVIDER_AUTH_TYPE_OPTION,\n },\n ...CUSTOM_PROVIDER_AUTH_TYPES.map((value) => ({\n label: value,\n value,\n })),\n ],\n })\n\n if (authType === CUSTOM_PROVIDER_AUTH_TYPE_OPTION) {\n return undefined\n }\n\n if (typeof authType === \"string\" && isCustomProviderAuthType(authType)) {\n return authType\n }\n\n throw new Error(\"No provider auth type selected\")\n}\n\nasync function promptQuickProviderBaseUrl(\n defaultBaseUrl: string,\n): Promise<string> {\n const value = await prompt(\n `Enter provider baseUrl (default: ${defaultBaseUrl})`,\n {\n type: \"text\",\n default: defaultBaseUrl,\n initial: defaultBaseUrl,\n },\n )\n const baseUrl = normalizeProviderBaseUrl(\n typeof value === \"string\" && value.trim() ? value : defaultBaseUrl,\n )\n if (!baseUrl) {\n throw new Error(\"baseUrl must be a non-empty string\")\n }\n\n return baseUrl\n}\n\nfunction buildCustomProviderConfig(\n existingProviderConfig: ProviderConfig,\n options: {\n apiKey: string\n authType?: ProviderAuthType\n baseUrl: string\n pricingCurrency?: string\n type: ProviderType\n modelsDevProviderId?: string\n },\n): ProviderConfig {\n return {\n type: options.type,\n enabled: true,\n baseUrl: options.baseUrl,\n ...(options.modelsDevProviderId && {\n modelsDevProviderId: options.modelsDevProviderId,\n }),\n apiKey: options.apiKey,\n ...(options.authType ? { authType: options.authType } : {}),\n pricingCurrency:\n options.pricingCurrency ?? existingProviderConfig.pricingCurrency,\n ...(existingProviderConfig.models ?\n { models: existingProviderConfig.models }\n : {}),\n }\n}\n\nasync function configureCustomProvider(): Promise<void> {\n const catalogProvider = await promptModelsDevProvider()\n const providerName = await promptCustomProviderName(catalogProvider?.id)\n const type = await promptCustomProviderType(catalogProvider?.type)\n const baseUrl =\n catalogProvider ?\n await promptQuickProviderBaseUrl(catalogProvider.api)\n : normalizeProviderBaseUrl(\n await promptRequiredText(\"Enter provider baseUrl\", \"baseUrl\"),\n )\n if (!baseUrl) {\n throw new Error(\"baseUrl must be a non-empty string\")\n }\n\n const apiKey = await promptRequiredSecret(\"Enter provider apiKey\", \"apiKey\")\n const authType = await promptCustomProviderAuthType(type)\n const existingProviderConfig = getRawProviderConfig(providerName) ?? {}\n\n setProviderConfig(\n providerName,\n buildCustomProviderConfig(existingProviderConfig, {\n apiKey,\n authType,\n baseUrl,\n modelsDevProviderId: catalogProvider?.id,\n type,\n }),\n )\n\n consola.success(\n `Custom provider '${providerName}' written to ${PATHS.CONFIG_PATH}`,\n )\n}\n\nasync function configureQuickProvider(\n providerName: QuickProviderName,\n): Promise<void> {\n const defaultProviderConfig = QUICK_PROVIDER_CONFIGS[providerName]\n const apiKey = await promptRequiredSecret(\n `Enter ${providerName} apiKey`,\n \"apiKey\",\n )\n const type =\n defaultProviderConfig.editableType ?\n await promptQuickProviderType(defaultProviderConfig.type)\n : defaultProviderConfig.type\n const baseUrl = await promptQuickProviderBaseUrl(\n defaultProviderConfig.baseUrl,\n )\n const existingProviderConfig = getRawProviderConfig(providerName) ?? {}\n\n setProviderConfig(\n providerName,\n buildCustomProviderConfig(existingProviderConfig, {\n apiKey,\n baseUrl,\n pricingCurrency: defaultProviderConfig.pricingCurrency,\n type,\n }),\n )\n\n consola.success(\n `${AUTH_PROVIDER_LABELS[providerName]} provider '${providerName}' written to ${PATHS.CONFIG_PATH}`,\n )\n}\n\nasync function loginWithCodex(alias?: string): Promise<void> {\n const credentials = await loginCodex({\n onAuth(info) {\n consola.info(\"Open the following URL to authenticate with Codex:\")\n consola.log(info.url)\n if (info.instructions) {\n consola.info(info.instructions)\n }\n },\n onPrompt(message) {\n return prompt(message, { type: \"text\" }).then((value) => value ?? \"\")\n },\n onProgress(message) {\n consola.debug(message)\n },\n })\n\n await persistCodexCredentials(credentials, {\n activateAccount: true,\n alias,\n enableProvider: true,\n })\n consola.success(\n `Codex provider config written to ${PATHS.CONFIG_PATH} and credentials written to ${PATHS.CODEX_CREDENTIAL_PATH}`,\n )\n}\n\nasync function loginWithProvider(\n provider: AuthProviderName,\n alias?: string,\n): Promise<void> {\n if (alias !== undefined && provider !== \"codex\") {\n throw new Error(\"--alias is only supported with the codex provider\")\n }\n\n if (provider === \"copilot\") {\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n return\n }\n\n if (provider === \"codex\") {\n await loginWithCodex(alias)\n return\n }\n\n if (isQuickProviderName(provider)) {\n await configureQuickProvider(provider)\n return\n }\n\n await configureCustomProvider()\n}\n\nexport async function runProviderSetup(): Promise<void> {\n const provider = await resolveProviderSelection(undefined)\n consola.info(`Logging in with ${AUTH_PROVIDER_LABELS[provider]}`)\n await loginWithProvider(provider)\n}\n\nexport async function runAuthLogin(options: RunAuthOptions): Promise<void> {\n const tlsModule = await import(\"./lib/tls\")\n tlsModule.enableSystemCACompat()\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n const provider = await resolveProviderSelection(options.provider)\n\n consola.info(`Logging in with ${AUTH_PROVIDER_LABELS[provider]}`)\n await loginWithProvider(provider, options.alias)\n}\n\nconst authCodexArgs = {\n list: {\n alias: \"l\",\n type: \"boolean\",\n default: false,\n description: \"List stored Codex accounts\",\n },\n remove: {\n alias: \"r\",\n type: \"string\",\n description:\n \"Remove a Codex account by alias or account id; the account in use cannot be removed\",\n },\n use: {\n alias: \"u\",\n type: \"string\",\n description: \"Select a Codex account by alias or account id\",\n },\n} as const\n\ninterface RunAuthCodexOptions {\n list?: boolean\n remove?: string\n use?: string\n}\n\nfunction formatCodexAccountName(\n account: Pick<CodexAccountSummary, \"accountId\" | \"alias\">,\n): string {\n return account.alias ?\n `${account.alias} (${account.accountId})`\n : account.accountId\n}\n\nfunction formatCodexAccount(account: CodexAccountSummary): string {\n return `${account.active ? \"*\" : \"-\"} ${formatCodexAccountName(account)}`\n}\n\nexport async function runAuthCodex(\n options: RunAuthCodexOptions,\n): Promise<void> {\n await ensurePaths()\n\n const operationCount = [\n options.list === true,\n options.use !== undefined,\n options.remove !== undefined,\n ].filter(Boolean).length\n if (operationCount > 1) {\n throw new Error(\"Use only one of --list, --use, or --remove per invocation\")\n }\n\n if (options.use !== undefined) {\n const account = await selectCodexAccount(options.use)\n consola.success(`Selected Codex account ${formatCodexAccountName(account)}`)\n consola.info(\"Restart the server to use the selected Codex account.\")\n return\n }\n\n if (options.remove !== undefined) {\n const account = await removeCodexAccount(options.remove)\n consola.success(`Removed Codex account ${formatCodexAccountName(account)}`)\n return\n }\n\n const accounts = await getCodexAccounts()\n if (accounts.length === 0) {\n consola.info(\n \"No Codex accounts configured. Run `copilot-api auth login --provider codex` to add one.\",\n )\n return\n }\n\n consola.info(\"Configured Codex accounts:\")\n for (const account of accounts) {\n consola.info(formatCodexAccount(account))\n }\n}\n\nconst authKeysArgs = {\n add: {\n alias: \"a\",\n type: \"string\",\n description: \"Add an API key for gateway authentication\",\n },\n remove: {\n alias: \"r\",\n type: \"string\",\n description: \"Remove an API key\",\n },\n list: {\n alias: \"l\",\n type: \"boolean\",\n default: false,\n description: \"List configured API keys\",\n },\n clear: {\n type: \"boolean\",\n default: false,\n description: \"Remove all configured API keys\",\n },\n} as const\n\ninterface RunAuthKeysOptions {\n add?: string\n remove?: string\n list?: boolean\n clear?: boolean\n}\n\nfunction normalizeAuthKeyValue(value: string): string {\n const normalizedKey = value.trim()\n if (!normalizedKey) {\n throw new Error(\"API key must be a non-empty string\")\n }\n return normalizedKey\n}\n\nexport async function runAuthKeys(options: RunAuthKeysOptions): Promise<void> {\n const tlsModule = await import(\"./lib/tls\")\n tlsModule.enableSystemCACompat()\n\n await ensurePaths()\n\n const operations = [\n ...(options.add !== undefined ? [\"add\"] : []),\n ...(options.remove !== undefined ? [\"remove\"] : []),\n ...(options.list ? [\"list\"] : []),\n ...(options.clear ? [\"clear\"] : []),\n ]\n if (operations.length > 1) {\n throw new Error(\n \"Use only one of --add, --remove, --list, or --clear per invocation\",\n )\n }\n\n const operation = operations[0] ?? \"list\"\n\n if (operation === \"add\") {\n const apiKey = normalizeAuthKeyValue(options.add ?? \"\")\n const currentKeys = getConfiguredApiKeys()\n if (currentKeys.includes(apiKey)) {\n consola.info(\n `API key already configured. ${currentKeys.length} API key(s) configured.`,\n )\n return\n }\n const storedKeys = setConfiguredApiKeys([...currentKeys, apiKey])\n consola.success(\n `API key added to ${PATHS.CONFIG_PATH}. ${storedKeys.length} API key(s) configured.`,\n )\n return\n }\n\n if (operation === \"remove\") {\n const apiKey = normalizeAuthKeyValue(options.remove ?? \"\")\n const currentKeys = getConfiguredApiKeys()\n if (!currentKeys.includes(apiKey)) {\n consola.info(\n `API key not found. ${currentKeys.length} API key(s) configured.`,\n )\n return\n }\n const storedKeys = setConfiguredApiKeys(\n currentKeys.filter((key) => key !== apiKey),\n )\n consola.success(\n `API key removed from ${PATHS.CONFIG_PATH}. ${storedKeys.length} API key(s) configured.`,\n )\n return\n }\n\n if (operation === \"clear\") {\n setConfiguredApiKeys([])\n consola.success(`Removed all API keys from ${PATHS.CONFIG_PATH}.`)\n return\n }\n\n const currentKeys = getConfiguredApiKeys()\n if (currentKeys.length === 0) {\n consola.info(\n \"No API keys configured. Run `npx @jeffreycao/copilot-api@latest auth keys --add <key>` to add one.\",\n )\n return\n }\n consola.info(\"Configured API keys:\")\n for (const key of currentKeys) {\n consola.info(`- ${key}`)\n }\n}\n\nconst authLogin = defineCommand({\n meta: {\n name: \"login\",\n description:\n \"Authenticate or configure a provider without running the server\",\n },\n args: authArgs,\n run({ args }) {\n return runAuthLogin({\n alias: args.alias,\n provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n\nconst authKeys = defineCommand({\n meta: {\n name: \"keys\",\n description: \"Manage gateway API keys (auth.apiKeys) in the config\",\n },\n args: authKeysArgs,\n run({ args }) {\n return runAuthKeys({\n add: args.add,\n remove: args.remove,\n list: args.list,\n clear: args.clear,\n })\n },\n})\n\nconst authCodex = defineCommand({\n meta: {\n name: \"codex\",\n description: \"List, select, or remove stored Codex accounts\",\n },\n args: authCodexArgs,\n run({ args }) {\n return runAuthCodex({\n list: args.list,\n remove: args.remove,\n use: args.use,\n })\n },\n})\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run authentication flows without running the server\",\n },\n args: authArgs,\n subCommands: {\n codex: authCodex,\n login: authLogin,\n keys: authKeys,\n },\n run({ args }) {\n if ((args._[0] ?? \"\").trim()) {\n return\n }\n\n return runAuthLogin({\n alias: args.alias,\n provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n"],"mappings":";;;;;AASA,MAAa,yBAAyB;CACpC,eAAe;EACb,MAAM;EACN,SAAS;EACT,iBAAiB;EACjB,cAAc;CAChB;CACA,MAAM;EACJ,MAAM;EACN,SAAS;EACT,iBAAiB;EACjB,cAAc;CAChB;CACA,UAAU;EACR,MAAM;EACN,SAAS;EACT,iBAAiB;EACjB,cAAc;CAChB;CACA,WAAW;EACT,MAAM;EACN,SAAS;EACT,iBAAiB;EACjB,cAAc;CAChB;CACA,YAAY;EACV,MAAM;EACN,SAAS;EACT,iBAAiB;EACjB,cAAc;CAChB;AACF;;;ACYA,SAAgB,qBACd,UAAyB;CACvB,YAAY,QAAQ,SAAS;CAC7B,UAAU,QAAQ;CAClB,YAAY,QAAQ,MAAM;CAC1B,aAAa,QAAQ,OAAO;CAC5B,mBAAmB,OAAO,QAAQ,OAAO,kBAAkB;AAC7D,GACS;CACT,OAAO,QACL,QAAQ,aAAa,WAChB,QAAQ,cACR,QAAQ,cACR,QAAQ,eACR,QAAQ,iBACf;AACF;AAEA,SAAS,eAAe,SAAuD;CAC7E,OAAO,QAAQ,SAAS,WACpB,QAAQ,UACP,QAAQ,WAAW,QAAQ;AAClC;AAEA,eAAsB,gBACpB,SACA,SACA,SAC6B;CAC7B,IAAI,QAAQ,SAAS,UAAU;EAC7B,MAAM,QAAQ,MAAM,QAAQ,OAAO;GACjC;GACA,SAAS,QAAQ,QAAQ,KAAK,WAC5B,OAAO,WAAW,WAAW;IAAE,OAAO;IAAQ,OAAO;GAAO,IAAI,MAClE;GACA,cAAc,QAAQ;EACxB,CAAC;EACD,IAAI,QAAQ,SAAS,KAAK,GACxB,OAAO,eAAe,OAAO;EAE/B,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;CAC7C;CAEA,MAAM,QAAQ,MAAM,QAAQ,KAAK;EAC/B;EACA,cAAc,QAAQ;EACtB,cAAc,QAAQ;EACtB,aAAa,QAAQ;CACvB,CAAC;CACD,IAAI,QAAQ,SAAS,KAAK,GACxB,OAAO,eAAe,OAAO;CAE/B,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;AAEA,eAAsB,OACpB,SACA,SAC6B;CAC7B,IAAI,CAAC,qBAAqB,GAAG;EAC3B,IAAI,QAAQ,SAAS,UAAU;GAC7B,MAAM,QAAQ,MAAM,QAAQ,OAAO,SAAS,OAAO;GACnD,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;EAC7C;EACA,OAAO,MAAM,QAAQ,OAAO,SAAS,OAAO;CAC9C;CAGA,OAAO,MAAM,gBAAgB,SAAS,SAAS,MAD3B,OAAO,iBACyB;AACtD;;;AC5EA,MAAM,WAAW;CACf,UAAU;EACR,MAAM;EACN,aACE;CACJ;CACA,OAAO;EACL,MAAM;EACN,aAAa;CACf;CACA,SAAS;EACP,OAAO;EACP,MAAM;EACN,SAAS;EACT,aAAa;CACf;CACA,cAAc;EACZ,MAAM;EACN,SAAS;EACT,aAAa;CACf;AACF;AAEA,MAAM,yBAAyB,CAAC,WAAW,OAAO;AAClD,MAAM,uBAAuB,OAAO,KAClC,sBACF;AACA,MAAM,sBAAsB;CAC1B,GAAG;CACH,GAAG;CACH;AACF;AACA,MAAM,mCAAmC;AACzC,MAAM,qCAAqC;AAC3C,MAAM,6BAA6B,CAAC,aAAa,eAAe;AAUhE,MAAM,uBAAyD;CAH7D,SAAS;CACT,OAAO;CAIP,eAAe;CACf,MAAM;CACN,UAAU;CACV,WAAW;CACX,YAAY;CACZ,QAAQ;AACV;AAEA,SAAS,mBACP,cACkC;CAClC,OAAO,oBAAoB,SAAS,YAAgC;AACtE;AAEA,SAAS,yBACP,OACiC;CACjC,OAAO,2BAA2B,SAAS,KAA+B;AAC5E;AAEA,SAAS,oBACP,cACmC;CACnC,OAAO,qBAAqB,SAAS,YAAiC;AACxE;AAEA,eAAe,yBACb,aAC2B;CAC3B,MAAM,qBAAqB,CAAC,GAAG,mBAAmB;CAElD,IAAI,gBAAgB,KAAA,GAAW;EAC7B,MAAM,eAAe,YAAY,KAAK;EACtC,IAAI,CAAC,mBAAmB,YAAY,GAClC,MAAM,IAAI,MACR,qBAAqB,YAAY,sBAAsB,mBAAmB,KAAK,IAAI,GACrF;EAEF,OAAO;CACT;CAEA,IAAI,mBAAmB,WAAW,GAChC,OAAO,mBAAmB;CAG5B,MAAM,WAAW,MAAM,OAAO,oCAAoC;EAChE,MAAM;EACN,SAAS,mBAAmB,KAAK,kBAAkB;GACjD,OAAO,GAAG,qBAAqB,cAAc,IAAI,aAAa;GAC9D,OAAO;EACT,EAAE;CACJ,CAAC;CAED,IAAI,CAAC,YAAY,CAAC,mBAAmB,QAAQ,GAC3C,MAAM,IAAI,MAAM,sBAAsB;CAGxC,OAAO;AACT;AAEA,SAAS,yBAAyB,cAA4B;CAC5D,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,0CAA0C;CAG5D,IAAI,CAAC,+BAA+B,KAAK,YAAY,GACnD,MAAM,IAAI,MACR,6GACF;CAGF,IAAI,iBAAiB,aAAa,iBAAiB,SACjD,MAAM,IAAI,MACR,kBAAkB,aAAa,qCACjC;AAEJ;AAEA,eAAe,mBACb,SACA,WACiB;CACjB,MAAM,QAAQ,MAAM,OAAO,SAAS,EAAE,MAAM,OAAO,CAAC;CACpD,MAAM,kBAAkB,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;CACnE,IAAI,CAAC,iBACH,MAAM,IAAI,MAAM,GAAG,UAAU,4BAA4B;CAE3D,OAAO;AACT;AAEA,SAAS,qBAA8B;CACrC,OAAO,QACL,QAAQ,MAAM,SACT,QAAQ,OAAO,SACf,OAAO,QAAQ,MAAM,eAAe,UAC3C;AACF;AAEA,eAAe,iBAAiB,SAAkC;CAChE,IAAI,CAAC,mBAAmB,GAAG;EACzB,MAAM,QAAQ,MAAM,OAAO,SAAS,EAAE,MAAM,OAAO,CAAC;EACpD,OAAO,OAAO,UAAU,WAAW,QAAQ;CAC7C;CAEA,OAAO,MAAM,IAAI,SAAiB,SAAS,WAAW;EACpD,IAAI,QAAQ;EACZ,MAAM,oBAAoB,QAAQ,MAAM,UAAU;EAElD,SAAS,UAAgB;GACvB,QAAQ,MAAM,IAAI,QAAQ,MAAM;GAChC,QAAQ,MAAM,WAAW,iBAAiB;GAC1C,QAAQ,MAAM,MAAM;EACtB;EAEA,SAAS,SAAe;GACtB,QAAQ;GACR,QAAQ,OAAO,MAAM,IAAI;GACzB,QAAQ,KAAK;EACf;EAEA,SAAS,SAAe;GACtB,QAAQ;GACR,QAAQ,OAAO,MAAM,IAAI;GACzB,uBAAO,IAAI,MAAM,kBAAkB,CAAC;EACtC;EAEA,SAAS,OAAO,OAAqB;GACnC,MAAM,QAAQ,MAAM,SAAS,MAAM;GAEnC,IAAI,MAAM,WAAW,MAAQ,GAC3B;GAGF,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,SAAS,KAAU;KACrB,OAAO;KACP;IACF;IAEA,IAAI,SAAS,QAAQ,SAAS,MAAM;KAClC,OAAO;KACP;IACF;IAEA,IAAI,SAAS,QAAQ,SAAS,KAAU;KACtC,IAAI,MAAM,SAAS,GAAG;MACpB,QAAQ,MAAM,MAAM,GAAG,EAAE;MACzB,QAAQ,OAAO,MAAM,OAAO;KAC9B;KACA;IACF;IAEA,IAAI,QAAQ,KAAK;KACf,SAAS;KACT,QAAQ,OAAO,MAAM,GAAG;IAC1B;GACF;EACF;EAEA,QAAQ,OAAO,MAAM,GAAG,QAAQ,GAAG;EACnC,QAAQ,MAAM,WAAW,IAAI;EAC7B,QAAQ,MAAM,OAAO;EACrB,QAAQ,MAAM,GAAG,QAAQ,MAAM;CACjC,CAAC;AACH;AAEA,eAAe,qBACb,SACA,WACiB;CAEjB,MAAM,mBAAkB,MADJ,iBAAiB,OAAO,EAAA,CACd,KAAK;CACnC,IAAI,CAAC,iBACH,MAAM,IAAI,MAAM,GAAG,UAAU,4BAA4B;CAE3D,OAAO;AACT;AAEA,eAAe,yBAAyB,aAAuC;CAK7E,MAAM,gBAAgB,MAJF,OAAO,uBAAuB;EAChD,MAAM;EACN,GAAI,cAAc;GAAE,SAAS;GAAa,SAAS;EAAY,IAAI,CAAC;CACtE,CAAC,KAC8B,eAAe,GAAA,CAAI,KAAK;CACvD,yBAAyB,YAAY;CACrC,OAAO;AACT;AAEA,eAAe,yBACb,aACuB;CACvB,MAAM,eAAe,MAAM,OAAO,wBAAwB;EACxD,MAAM;EACN,SAAS;EACT,SAAS,yBAAyB,KAAK,UAAU;GAC/C,OAAO;GACP,OAAO;EACT,EAAE;CACJ,CAAC;CAED,IACE,OAAO,iBAAiB,YACrB,CAAC,wBAAwB,YAAY,GAExC,MAAM,IAAI,MAAM,2BAA2B;CAG7C,OAAO;AACT;AAEA,eAAe,0BAEb;CACA,MAAM,SAAS,MAAM,OAAO,iCAAiC;EAC3D,MAAM;EACN,SAAS,CACP;GAAE,OAAO;GAAkB,OAAO;EAAS,GAC3C;GAAE,OAAO;GAA0B,OAAO;EAAa,CACzD;CACF,CAAC;CACD,IAAI,WAAW,UAAU,OAAO,KAAA;CAChC,IAAI,WAAW,cAAc,MAAM,IAAI,MAAM,6BAA6B;CAE1E,MAAM,YAAY,MAAM,6BAA6B;CACrD,MAAM,SACH,MAAM,OAAO,mDAAmD,EAC/D,MAAM,OACR,CAAC,KAAM,GAAA,CAEN,KAAK,CAAC,CACN,YAAY;CACf,MAAM,UAAU,UAAU,QACvB,aACC,SAAS,GAAG,YAAY,CAAC,CAAC,SAAS,KAAK,KACrC,SAAS,KAAK,YAAY,CAAC,CAAC,SAAS,KAAK,CACjD;CACA,IAAI,QAAQ,WAAW,GACrB,MAAM,IAAI,MAAM,2DAA2D;CAE7E,MAAM,aAAa,MAAM,OAAO,gCAAgC;EAC9D,MAAM;EACN,SAAS,QAAQ,KAAK,cAAc;GAClC,OAAO,GAAG,SAAS,KAAK,IAAI,SAAS,GAAG,MAAM,SAAS;GACvD,OAAO,SAAS;EAClB,EAAE;CACJ,CAAC;CACD,MAAM,mBAAmB,QAAQ,MAC9B,aAAa,SAAS,OAAO,UAChC;CACA,IAAI,CAAC,kBAAkB,MAAM,IAAI,MAAM,iCAAiC;CACxE,OAAO;AACT;AAEA,eAAe,wBACb,aACuB;CACvB,MAAM,eAAe,MAAM,OACzB,kCAAkC,YAAY,IAC9C;EACE,MAAM;EACN,SAAS,CACP;GACE,OAAO,YAAY,YAAY;GAC/B,OAAO;EACT,GACA,GAAG,yBAAyB,KAAK,UAAU;GACzC,OAAO;GACP,OAAO;EACT,EAAE,CACJ;CACF,CACF;CAEA,IAAI,iBAAiB,oCACnB,OAAO;CAGT,IACE,OAAO,iBAAiB,YACrB,wBAAwB,YAAY,GAEvC,OAAO;CAGT,MAAM,IAAI,MAAM,2BAA2B;AAC7C;AAEA,SAAS,2BACP,cACkB;CAClB,OAAO,iBAAiB,cAAc,cAAc;AACtD;AAEA,eAAe,6BACb,cACuC;CAEvC,MAAM,WAAW,MAAM,OAAO,6BAA6B;EACzD,MAAM;EACN,SAAS,CACP;GACE,OAAO,YALW,2BAA2B,YAK1B,EAAgB;GACnC,OAAO;EACT,GACA,GAAG,2BAA2B,KAAK,WAAW;GAC5C,OAAO;GACP;EACF,EAAE,CACJ;CACF,CAAC;CAED,IAAI,aAAa,kCACf;CAGF,IAAI,OAAO,aAAa,YAAY,yBAAyB,QAAQ,GACnE,OAAO;CAGT,MAAM,IAAI,MAAM,gCAAgC;AAClD;AAEA,eAAe,2BACb,gBACiB;CACjB,MAAM,QAAQ,MAAM,OAClB,oCAAoC,eAAe,IACnD;EACE,MAAM;EACN,SAAS;EACT,SAAS;CACX,CACF;CACA,MAAM,UAAU,yBACd,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,QAAQ,cACtD;CACA,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,oCAAoC;CAGtD,OAAO;AACT;AAEA,SAAS,0BACP,wBACA,SAQgB;CAChB,OAAO;EACL,MAAM,QAAQ;EACd,SAAS;EACT,SAAS,QAAQ;EACjB,GAAI,QAAQ,uBAAuB,EACjC,qBAAqB,QAAQ,oBAC/B;EACA,QAAQ,QAAQ;EAChB,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;EACzD,iBACE,QAAQ,mBAAmB,uBAAuB;EACpD,GAAI,uBAAuB,SACzB,EAAE,QAAQ,uBAAuB,OAAO,IACxC,CAAC;CACL;AACF;AAEA,eAAe,0BAAyC;CACtD,MAAM,kBAAkB,MAAM,wBAAwB;CACtD,MAAM,eAAe,MAAM,yBAAyB,iBAAiB,EAAE;CACvE,MAAM,OAAO,MAAM,yBAAyB,iBAAiB,IAAI;CACjE,MAAM,UACJ,kBACE,MAAM,2BAA2B,gBAAgB,GAAG,IACpD,yBACE,MAAM,mBAAmB,0BAA0B,SAAS,CAC9D;CACJ,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,oCAAoC;CAGtD,MAAM,SAAS,MAAM,qBAAqB,yBAAyB,QAAQ;CAC3E,MAAM,WAAW,MAAM,6BAA6B,IAAI;CACxD,MAAM,yBAAyB,qBAAqB,YAAY,KAAK,CAAC;CAEtE,kBACE,cACA,0BAA0B,wBAAwB;EAChD;EACA;EACA;EACA,qBAAqB,iBAAiB;EACtC;CACF,CAAC,CACH;CAEA,QAAQ,QACN,oBAAoB,aAAa,eAAe,MAAM,aACxD;AACF;AAEA,eAAe,uBACb,cACe;CACf,MAAM,wBAAwB,uBAAuB;CACrD,MAAM,SAAS,MAAM,qBACnB,SAAS,aAAa,UACtB,QACF;CACA,MAAM,OACJ,sBAAsB,eACpB,MAAM,wBAAwB,sBAAsB,IAAI,IACxD,sBAAsB;CAC1B,MAAM,UAAU,MAAM,2BACpB,sBAAsB,OACxB;CACA,MAAM,yBAAyB,qBAAqB,YAAY,KAAK,CAAC;CAEtE,kBACE,cACA,0BAA0B,wBAAwB;EAChD;EACA;EACA,iBAAiB,sBAAsB;EACvC;CACF,CAAC,CACH;CAEA,QAAQ,QACN,GAAG,qBAAqB,cAAc,aAAa,aAAa,eAAe,MAAM,aACvF;AACF;AAEA,eAAe,eAAe,OAA+B;CAC3D,MAAM,cAAc,MAAM,WAAW;EACnC,OAAO,MAAM;GACX,QAAQ,KAAK,oDAAoD;GACjE,QAAQ,IAAI,KAAK,GAAG;GACpB,IAAI,KAAK,cACP,QAAQ,KAAK,KAAK,YAAY;EAElC;EACA,SAAS,SAAS;GAChB,OAAO,OAAO,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,MAAM,UAAU,SAAS,EAAE;EACtE;EACA,WAAW,SAAS;GAClB,QAAQ,MAAM,OAAO;EACvB;CACF,CAAC;CAED,MAAM,wBAAwB,aAAa;EACzC,iBAAiB;EACjB;EACA,gBAAgB;CAClB,CAAC;CACD,QAAQ,QACN,oCAAoC,MAAM,YAAY,8BAA8B,MAAM,uBAC5F;AACF;AAEA,eAAe,kBACb,UACA,OACe;CACf,IAAI,UAAU,KAAA,KAAa,aAAa,SACtC,MAAM,IAAI,MAAM,mDAAmD;CAGrE,IAAI,aAAa,WAAW;EAC1B,MAAM,iBAAiB,EAAE,OAAO,KAAK,CAAC;EACtC,QAAQ,QAAQ,2BAA2B,MAAM,iBAAiB;EAClE;CACF;CAEA,IAAI,aAAa,SAAS;EACxB,MAAM,eAAe,KAAK;EAC1B;CACF;CAEA,IAAI,oBAAoB,QAAQ,GAAG;EACjC,MAAM,uBAAuB,QAAQ;EACrC;CACF;CAEA,MAAM,wBAAwB;AAChC;AAEA,eAAsB,mBAAkC;CACtD,MAAM,WAAW,MAAM,yBAAyB,KAAA,CAAS;CACzD,QAAQ,KAAK,mBAAmB,qBAAqB,WAAW;CAChE,MAAM,kBAAkB,QAAQ;AAClC;AAEA,eAAsB,aAAa,SAAwC;CAEzE,CAAA,MADwB,OAAO,qBAAA,CACrB,qBAAqB;CAE/B,IAAI,QAAQ,SAAS;EACnB,QAAQ,QAAQ;EAChB,QAAQ,KAAK,yBAAyB;CACxC;CAEA,MAAM,YAAY,QAAQ;CAE1B,MAAM,YAAY;CAClB,MAAM,WAAW,MAAM,yBAAyB,QAAQ,QAAQ;CAEhE,QAAQ,KAAK,mBAAmB,qBAAqB,WAAW;CAChE,MAAM,kBAAkB,UAAU,QAAQ,KAAK;AACjD;AAEA,MAAM,gBAAgB;CACpB,MAAM;EACJ,OAAO;EACP,MAAM;EACN,SAAS;EACT,aAAa;CACf;CACA,QAAQ;EACN,OAAO;EACP,MAAM;EACN,aACE;CACJ;CACA,KAAK;EACH,OAAO;EACP,MAAM;EACN,aAAa;CACf;AACF;AAQA,SAAS,uBACP,SACQ;CACR,OAAO,QAAQ,QACX,GAAG,QAAQ,MAAM,IAAI,QAAQ,UAAU,KACvC,QAAQ;AACd;AAEA,SAAS,mBAAmB,SAAsC;CAChE,OAAO,GAAG,QAAQ,SAAS,MAAM,IAAI,GAAG,uBAAuB,OAAO;AACxE;AAEA,eAAsB,aACpB,SACe;CACf,MAAM,YAAY;CAOlB,IALuB;EACrB,QAAQ,SAAS;EACjB,QAAQ,QAAQ,KAAA;EAChB,QAAQ,WAAW,KAAA;CACrB,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,SACG,GACnB,MAAM,IAAI,MAAM,2DAA2D;CAG7E,IAAI,QAAQ,QAAQ,KAAA,GAAW;EAC7B,MAAM,UAAU,MAAM,mBAAmB,QAAQ,GAAG;EACpD,QAAQ,QAAQ,0BAA0B,uBAAuB,OAAO,GAAG;EAC3E,QAAQ,KAAK,uDAAuD;EACpE;CACF;CAEA,IAAI,QAAQ,WAAW,KAAA,GAAW;EAChC,MAAM,UAAU,MAAM,mBAAmB,QAAQ,MAAM;EACvD,QAAQ,QAAQ,yBAAyB,uBAAuB,OAAO,GAAG;EAC1E;CACF;CAEA,MAAM,WAAW,MAAM,iBAAiB;CACxC,IAAI,SAAS,WAAW,GAAG;EACzB,QAAQ,KACN,yFACF;EACA;CACF;CAEA,QAAQ,KAAK,4BAA4B;CACzC,KAAK,MAAM,WAAW,UACpB,QAAQ,KAAK,mBAAmB,OAAO,CAAC;AAE5C;AAEA,MAAM,eAAe;CACnB,KAAK;EACH,OAAO;EACP,MAAM;EACN,aAAa;CACf;CACA,QAAQ;EACN,OAAO;EACP,MAAM;EACN,aAAa;CACf;CACA,MAAM;EACJ,OAAO;EACP,MAAM;EACN,SAAS;EACT,aAAa;CACf;CACA,OAAO;EACL,MAAM;EACN,SAAS;EACT,aAAa;CACf;AACF;AASA,SAAS,sBAAsB,OAAuB;CACpD,MAAM,gBAAgB,MAAM,KAAK;CACjC,IAAI,CAAC,eACH,MAAM,IAAI,MAAM,oCAAoC;CAEtD,OAAO;AACT;AAEA,eAAsB,YAAY,SAA4C;CAE5E,CAAA,MADwB,OAAO,qBAAA,CACrB,qBAAqB;CAE/B,MAAM,YAAY;CAElB,MAAM,aAAa;EACjB,GAAI,QAAQ,QAAQ,KAAA,IAAY,CAAC,KAAK,IAAI,CAAC;EAC3C,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,QAAQ,IAAI,CAAC;EACjD,GAAI,QAAQ,OAAO,CAAC,MAAM,IAAI,CAAC;EAC/B,GAAI,QAAQ,QAAQ,CAAC,OAAO,IAAI,CAAC;CACnC;CACA,IAAI,WAAW,SAAS,GACtB,MAAM,IAAI,MACR,oEACF;CAGF,MAAM,YAAY,WAAW,MAAM;CAEnC,IAAI,cAAc,OAAO;EACvB,MAAM,SAAS,sBAAsB,QAAQ,OAAO,EAAE;EACtD,MAAM,cAAc,qBAAqB;EACzC,IAAI,YAAY,SAAS,MAAM,GAAG;GAChC,QAAQ,KACN,+BAA+B,YAAY,OAAO,wBACpD;GACA;EACF;EACA,MAAM,aAAa,qBAAqB,CAAC,GAAG,aAAa,MAAM,CAAC;EAChE,QAAQ,QACN,oBAAoB,MAAM,YAAY,IAAI,WAAW,OAAO,wBAC9D;EACA;CACF;CAEA,IAAI,cAAc,UAAU;EAC1B,MAAM,SAAS,sBAAsB,QAAQ,UAAU,EAAE;EACzD,MAAM,cAAc,qBAAqB;EACzC,IAAI,CAAC,YAAY,SAAS,MAAM,GAAG;GACjC,QAAQ,KACN,sBAAsB,YAAY,OAAO,wBAC3C;GACA;EACF;EACA,MAAM,aAAa,qBACjB,YAAY,QAAQ,QAAQ,QAAQ,MAAM,CAC5C;EACA,QAAQ,QACN,wBAAwB,MAAM,YAAY,IAAI,WAAW,OAAO,wBAClE;EACA;CACF;CAEA,IAAI,cAAc,SAAS;EACzB,qBAAqB,CAAC,CAAC;EACvB,QAAQ,QAAQ,6BAA6B,MAAM,YAAY,EAAE;EACjE;CACF;CAEA,MAAM,cAAc,qBAAqB;CACzC,IAAI,YAAY,WAAW,GAAG;EAC5B,QAAQ,KACN,oGACF;EACA;CACF;CACA,QAAQ,KAAK,sBAAsB;CACnC,KAAK,MAAM,OAAO,aAChB,QAAQ,KAAK,KAAK,KAAK;AAE3B;AAEA,MAAM,YAAY,cAAc;CAC9B,MAAM;EACJ,MAAM;EACN,aACE;CACJ;CACA,MAAM;CACN,IAAI,EAAE,QAAQ;EACZ,OAAO,aAAa;GAClB,OAAO,KAAK;GACZ,UAAU,KAAK;GACf,SAAS,KAAK;GACd,WAAW,KAAK;EAClB,CAAC;CACH;AACF,CAAC;AAED,MAAM,WAAW,cAAc;CAC7B,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;CACN,IAAI,EAAE,QAAQ;EACZ,OAAO,YAAY;GACjB,KAAK,KAAK;GACV,QAAQ,KAAK;GACb,MAAM,KAAK;GACX,OAAO,KAAK;EACd,CAAC;CACH;AACF,CAAC;AAED,MAAM,YAAY,cAAc;CAC9B,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;CACN,IAAI,EAAE,QAAQ;EACZ,OAAO,aAAa;GAClB,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,KAAK,KAAK;EACZ,CAAC;CACH;AACF,CAAC;AAED,MAAa,OAAO,cAAc;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;CACN,aAAa;EACX,OAAO;EACP,OAAO;EACP,MAAM;CACR;CACA,IAAI,EAAE,QAAQ;EACZ,KAAK,KAAK,EAAE,MAAM,GAAA,CAAI,KAAK,GACzB;EAGF,OAAO,aAAa;GAClB,OAAO,KAAK;GACZ,UAAU,KAAK;GACf,SAAS,KAAK;GACd,WAAW,KAAK;EAClB,CAAC;CACH;AACF,CAAC"}
|