@jeffreycao/copilot-api 1.12.8 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +107 -62
  2. package/README.zh-CN.md +107 -62
  3. package/dist/auth-BwQ7Vhzt.js +2 -0
  4. package/dist/{auth-BMROoous.js → auth-DcYySZhC.js} +151 -8
  5. package/dist/auth-DcYySZhC.js.map +1 -0
  6. package/dist/{config-B71_S_hQ.js → config-CQxppJtD.js} +5 -1
  7. package/dist/config-CQxppJtD.js.map +1 -0
  8. package/dist/{debug-TyT2u9dt.js → debug-IUKehQot.js} +2 -2
  9. package/dist/{debug-TyT2u9dt.js.map → debug-IUKehQot.js.map} +1 -1
  10. package/dist/electron-fetch-DPhDE6JE.js +22 -0
  11. package/dist/electron-fetch-DPhDE6JE.js.map +1 -0
  12. package/dist/main.js +6 -25
  13. package/dist/main.js.map +1 -1
  14. package/dist/{mcp-CTb-DbQH.js → mcp-BseuqgHR.js} +2 -2
  15. package/dist/{mcp-CTb-DbQH.js.map → mcp-BseuqgHR.js.map} +1 -1
  16. package/dist/{server-DQXpAOIW.js → server-7U9OZLf0.js} +451 -93
  17. package/dist/server-7U9OZLf0.js.map +1 -0
  18. package/dist/{start-BW-kr6B8.js → start-Dq2b9vPm.js} +69 -58
  19. package/dist/start-Dq2b9vPm.js.map +1 -0
  20. package/dist/{tls-CaLAeSaF.js → tls-BniQ6Rel.js} +1 -1
  21. package/dist/{tls-CaLAeSaF.js.map → tls-BniQ6Rel.js.map} +1 -1
  22. package/dist/{token-fpw8tAQS.js → token-CFArcYwb.js} +8 -6
  23. package/dist/token-CFArcYwb.js.map +1 -0
  24. package/dist/{tool-search-D3SN0jX-.js → tool-search-OX6iPJ9D.js} +1 -1
  25. package/dist/{tool-search-D3SN0jX-.js.map → tool-search-OX6iPJ9D.js.map} +1 -1
  26. package/package.json +1 -1
  27. package/pages/index.html +68 -14
  28. package/dist/auth-BMROoous.js.map +0 -1
  29. package/dist/check-usage-7Dxi5XkE.js +0 -43
  30. package/dist/check-usage-7Dxi5XkE.js.map +0 -1
  31. package/dist/config-B71_S_hQ.js.map +0 -1
  32. package/dist/server-DQXpAOIW.js.map +0 -1
  33. package/dist/start-BW-kr6B8.js.map +0 -1
  34. package/dist/token-fpw8tAQS.js.map +0 -1
package/README.zh-CN.md CHANGED
@@ -9,27 +9,27 @@
9
9
  >
10
10
  > 1. **Claude Code 配置:** 与 Claude Code 搭配使用时,请将模型 ID 配置为 `claude-opus-4-6` 或 `claude-opus-4.6`。示例 claude `settings.json` 见 [通过 `settings.json` 手动配置](#manual-configuration-with-settingsjson)。
11
11
  >
12
- > 2. **推荐给 opencode 用户:** opencode 而言,优先使用 opencode OAuth app。它与 opencode 内置的 GitHub Copilot provider 行为一致,且没有 Terms of Service 风险:
13
- > ```sh
14
- > npx @jeffreycao/copilot-api@latest --oauth-app=opencode start
15
- > ```
12
+ > 2. **内置 `copilot`、`codex` 与第三方 provider:** 执行 `npx @jeffreycao/copilot-api@latest auth`,可选择 `copilot`、`codex`、`deepseek`、`custom` provider
16
13
  >
17
- > 3. **内置 `codex` provider:** 执行一次 `npx @jeffreycao/copilot-api@latest auth login --provider codex` 后,AI gateway 会自动持久化并刷新 Codex OAuth 凭据。
18
- >
19
- > 4. **注意事项:** README 顶部移除的 GitHub Copilot warning 见 [GitHub Copilot 安全提示](./NOTICE.md#github-copilot-security-notice)。
14
+ > 3. **注意事项:** README 顶部移除的 GitHub Copilot warning [GitHub Copilot 安全提示](./NOTICE.md#github-copilot-security-notice)。
20
15
 
21
16
  ---
22
17
 
23
18
  ## 项目概览
24
19
 
25
- 这个项目最初是一个通过逆向工程实现的 GitHub Copilot API 代理,但现在也可以看作一个小型 AI gateway。除了 Copilot,它还可以在同一个 OpenAI / Anthropic 兼容入口后面路由内置的 `codex` provider 和第三方 provider,例如 DashScope,让 [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) 这类工具复用同一个本地端点。
20
+ 这是一个小型 AI gateway,可以使用 GitHub Copilot、内置 `codex` provider,也可以使用 DashScope 等已配置的第三方 provider。GitHub Copilot 现在是可选能力:如果本地没有 GitHub token,只要至少配置了一个启用中的 provider,服务仍可按 provider-only 模式启动。
21
+
22
+ AI gateway 会从同一个本地端点暴露 OpenAI / Anthropic 兼容 API,让 [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview)、OpenCode、Codex 和 OpenAI 兼容客户端可以共用同一个本地服务。
26
23
 
27
24
  在 GitHub Copilot 路径上,AI gateway 会在可用时优先使用 Copilot 原生的 Anthropic 风格 Messages API,在重工具调用场景下保留更原生的 Claude 行为。
28
25
 
29
26
  ## 功能特性
30
27
 
31
28
  - **OpenAI 与 Anthropic 双兼容**:通过 `/v1/responses`、`/v1/chat/completions`、`/v1/models`、`/v1/embeddings` 和 `/v1/messages` 对外暴露同一个本地 AI gateway。
29
+ - **Copilot 可选**:有 GitHub 凭据时可以使用 GitHub Copilot,没有 GitHub 凭据时也可以只依赖已配置的 provider 运行。
32
30
  - **同一网关接入 Copilot、`codex` 与第三方 provider**:可统一路由 GitHub Copilot、内置 `codex` provider 和配置好的外部 provider。
31
+ - **第三方 provider 可独立启动**:配置 DashScope、DeepSeek、OpenRouter 或自定义 provider 后,不需要 GitHub Copilot 登录即可启动 AI gateway。
32
+ - **OpenAI 兼容 provider 同时支持 chat 和 Messages API**:`openai-compatible` provider 可通过顶层 `/v1/chat/completions` 搭配 `model: "provider/model"` 提供 Chat Completions,也可通过 `/v1/messages` 完成 Anthropic Messages 的请求/响应翻译。
33
33
  - **面向 Claude 的更原生 Copilot 路由**:优先使用原生 `/v1/messages`,保留 Claude 风格工具流,支持 Anthropic beta 能力、通过 Responses-capable 模型支持 Claude WebSearch,并保留 subagent / session 标记。
34
34
  - **Claude Code 与 OpenCode 集成**:兼容 Claude Code 与 OpenCode,也支持通过 `@ai-sdk/anthropic` 直接作为 Anthropic provider 使用。
35
35
  - **灵活的认证与部署选项**:支持交互式登录、直接 token、个人 / Business / Enterprise、GitHub Enterprise、opencode OAuth 和自定义数据目录。
@@ -41,7 +41,8 @@
41
41
 
42
42
  - Bun(>= 1.2.x)
43
43
  - 如果要通过 `npx` 运行已发布 CLI,需要 Node.js
44
- - 已订阅 Copilot 的 GitHub 账号(个人版、Business 或 Enterprise)
44
+ - 只有在使用 GitHub Copilot provider 时,才需要已订阅 Copilot 的 GitHub 账号
45
+ - 如果不使用 GitHub Copilot,需要至少一个已配置 provider 的 API key 或 OAuth 登录
45
46
 
46
47
  ## 安装
47
48
 
@@ -76,21 +77,28 @@ npx @jeffreycao/copilot-api@latest start
76
77
  npx @jeffreycao/copilot-api@latest start --port 8080
77
78
  ```
78
79
 
79
- 如果只想做认证:
80
+ 如果只想做认证或 provider 配置:
80
81
 
81
82
  ```sh
82
83
  npx @jeffreycao/copilot-api@latest auth
83
84
  ```
84
85
 
86
+ 如果要不依赖 GitHub Copilot 运行,先配置至少一个 provider,然后正常启动服务:
87
+
88
+ ```sh
89
+ npx @jeffreycao/copilot-api@latest auth login --provider dashscope
90
+ npx @jeffreycao/copilot-api@latest start
91
+ ```
92
+
85
93
  ## Electron 桌面应用
86
94
 
87
- 如果你更喜欢图形界面,仓库里还提供了位于 `desktop/` 的 Electron 桌面应用。它支持 GitHub Copilot 登录或手动填入 token,可以一键启动或停止本地代理,并在界面里直接查看本地端点、鉴权 Header、可用模型、额度和日志。
95
+ 如果你更喜欢图形界面,仓库里还提供了位于 `desktop/` 的 Electron 桌面应用。它支持 GitHub Copilot 登录、OpenAI Codex OAuth,以及 DeepSeek、DashScope、OpenRouter 或自定义 provider 的 API Key 配置。授权或配置 provider 后,可以一键启动或停止本地代理,并在界面里直接查看本地端点、鉴权 Header、可用模型、额度和日志。
88
96
 
89
97
  设置页还可以配置 `OAuth App`、`API Home`、`Enterprise URL`、详细日志以及最小化到托盘。桌面安装包发布在 GitHub Releases:
90
98
 
91
99
  https://github.com/caozhiyuan/copilot-api/releases
92
100
 
93
- 下载对应平台的安装包后,在应用内登录、选择端口并启动服务,再把你的客户端指向应用里显示的本地端点即可。发布版桌面应用使用随包内置的 Electron 运行时,正常使用不需要额外安装 Node.js;token usage 历史记录会在该内置运行时支持 SQLite 时启用。
101
+ 下载对应平台的安装包后,在应用内授权或配置 provider,选择端口并启动服务,再把你的客户端指向应用里显示的本地端点即可。发布版桌面应用使用随包内置的 Electron 运行时,正常使用不需要额外安装 Node.js;token usage 历史记录会在该内置运行时支持 SQLite 时启用。
94
102
 
95
103
  桌面应用里的高级配置页会通过 `GET/POST /admin/config/model-mappings` 读写这份共享的模型映射。同一份映射会统一作用于 `POST /v1/messages`、`POST /v1/messages/count_tokens`、`POST /v1/responses` 和 `POST /v1/chat/completions`,不再按接口区分。它使用的是 `auth.adminApiKey`,不是普通的 `auth.apiKeys`;应用会在服务启动并自动生成该 key 后,直接从 `config.json` 读取它来发起请求。
96
104
 
@@ -118,7 +126,7 @@ mkdir -p ./copilot-data
118
126
  docker run -p 4141:4141 -v $(pwd)/copilot-data:/root/.local/share/copilot-api copilot-api
119
127
  ```
120
128
 
121
- 这会把宿主机上的 `./copilot-data` 映射到容器内的 `/root/.local/share/copilot-api`,用于持久化 GitHub 认证数据。
129
+ 这会把宿主机上的 `./copilot-data` 映射到容器内的 `/root/.local/share/copilot-api`,用于持久化 GitHub 认证数据、provider 配置和其他 gateway 状态。
122
130
 
123
131
  也可以直接通过环境变量传入 GitHub token:
124
132
 
@@ -130,9 +138,8 @@ docker run -p 4141:4141 -e GH_TOKEN=your_github_token_here copilot-api
130
138
 
131
139
  Copilot API 现在使用子命令结构,主要命令包括:
132
140
 
133
- - `start`:启动 Copilot API 服务。如有需要,也会自动处理认证。
134
- - `auth`:仅执行 GitHub 认证流程,不启动服务。通常用于生成可与 `--github-token` 一起使用的 token,尤其适合非交互环境。
135
- - `check-usage`:直接在终端中显示当前 GitHub Copilot 用量与额度信息(无需启动服务)。
141
+ - `start`:启动 AI gateway 服务。如果已有 GitHub token,则启用 Copilot 路径;如果没有 GitHub token,但存在至少一个启用中的 provider,则按 provider-only 模式启动;如果两者都没有,会引导你配置 provider。
142
+ - `auth`:仅执行 provider 登录或配置流程,不启动服务。可用于 GitHub Copilot 登录、Codex OAuth,或第三方 provider API key 配置。
136
143
  - `debug`:显示诊断信息,包括版本、运行时详情、文件路径以及认证状态,便于排障与支持。
137
144
 
138
145
  ## 命令行选项
@@ -155,7 +162,6 @@ Copilot API 现在使用子命令结构,主要命令包括:
155
162
  | --- | --- | --- | --- |
156
163
  | --port | 监听端口 | 4141 | -p |
157
164
  | --verbose | 启用详细日志 | false | -v |
158
- | --account-type | 使用的账号类型(individual、business、enterprise) | individual | -a |
159
165
  | --manual | 启用手动请求审批 | false | 无 |
160
166
  | --rate-limit | 请求之间的速率限制秒数 | 无 | -r |
161
167
  | --wait | 达到速率限制时等待,而不是直接报错 | false | -w |
@@ -168,11 +174,15 @@ Copilot API 现在使用子命令结构,主要命令包括:
168
174
 
169
175
  | 选项 | 说明 | 默认值 | 别名 |
170
176
  | --- | --- | --- | --- |
171
- | --provider | 要登录或配置的 provider(`copilot`、`codex` 或 `custom`) | 交互选择 | 无 |
177
+ | --provider | 要登录或配置的 provider(`copilot`、`codex`、`deepseek`、`dashscope`、`openrouter` 或 `custom`) | 交互选择 | 无 |
172
178
  | --verbose | 启用详细日志 | false | -v |
173
179
  | --show-token | 认证时显示 GitHub token | false | 无 |
174
180
 
175
- 使用 `copilot-api auth login --provider custom` 可以通过 CLI 新增或更新第三方 provider。命令会依次提示输入 provider name、项目支持的 type(`anthropic`、`openai-compatible``openai-responses`)、`baseUrl`、`apiKey` `authType`;`authType` 可保持 type 默认值,也可选择 `x-api-key` / `authorization`。
181
+ 只有在需要启用 GitHub Copilot provider 时,才需要执行 `copilot-api auth login --provider copilot`。使用 `codex` 或第三方 provider-only 模式不要求配置 Copilot。
182
+
183
+ 使用 `copilot-api auth login --provider deepseek`、`--provider dashscope` 或 `--provider openrouter` 可以通过 CLI 快速新增或更新这些常用第三方 provider。DeepSeek 和 DashScope 会提示输入掩码显示的 `apiKey`、provider `type`(默认 `openai-compatible`)和预填默认值的 `baseUrl`。OpenRouter 只提示输入掩码显示的 `apiKey` 和预填默认值的 `baseUrl`,并固定写入 `type: "anthropic"`。配置并启用 provider 后,`copilot-api start` 可在没有 GitHub token 的情况下启动。
184
+
185
+ 使用 `copilot-api auth login --provider custom` 可以通过 CLI 新增或更新其他第三方 provider。命令会依次提示输入 provider name、项目支持的 type(`anthropic`、`openai-compatible` 或 `openai-responses`)、`baseUrl`、掩码显示的 `apiKey` 和 `authType`;`authType` 可保持 type 默认值,也可选择 `x-api-key` / `authorization`。
176
186
 
177
187
  ### Debug 命令选项
178
188
 
@@ -192,39 +202,7 @@ Copilot API 现在使用子命令结构,主要命令包括:
192
202
  "apiKeys": [],
193
203
  "adminApiKey": "<startup 自动生成>"
194
204
  },
195
- "providers": {
196
- "custom": {
197
- "type": "anthropic",
198
- "enabled": true,
199
- "baseUrl": "your-base-url",
200
- "apiKey": "sk-your-provider-key",
201
- "authType": "x-api-key"
202
- },
203
- "dashscope": {
204
- "type": "openai-compatible",
205
- "enabled": true,
206
- "baseUrl": "https://dashscope.aliyuncs.com/compatible-mode",
207
- "apiKey": "sk-your-dashscope-key",
208
- "models": {
209
- "qwen3.6-plus": {
210
- "temperature": 1,
211
- "topP": 0.95,
212
- "topK": 20,
213
- "extraBody": {
214
- "preserve_thinking": true
215
- }
216
- },
217
- "glm-5.1": {
218
- "temperature": 0.7,
219
- "topP": 0.95,
220
- "contextCache": true,
221
- "extraBody": {
222
- "preserve_thinking": true
223
- }
224
- }
225
- }
226
- }
227
- },
205
+ "providers": {},
228
206
  "modelMappings": {},
229
207
  "extraPrompts": {
230
208
  "gpt-5-mini": "<built-in exploration prompt>",
@@ -256,19 +234,75 @@ Copilot API 现在使用子命令结构,主要命令包括:
256
234
  - **auth.adminApiKey:** 仅用于 `/admin/*` 路由的单个 admin key。若未配置,服务会在启动时自动生成一个随机 key,并回写到 `config.json`。它同样使用 `x-api-key` 或 `Authorization: Bearer` 这两种头,但普通 `auth.apiKeys` 不能访问 `/admin/*`。
257
235
  - **modelMappings:** 用于顶层 `POST /v1/messages`、`POST /v1/messages/count_tokens`、`POST /v1/responses` 和 `POST /v1/chat/completions` 请求的精确 `sourceModel -> targetModel` 重写映射,这几类接口共用同一份规则。省略该字段或保留为 `{}` 时,不会做模型重写。`source` 和 `target` 都必须是非空字符串。`target` 可以是普通模型 ID,也可以是 `provider/model` 形式的别名,例如 `dashscope/qwen3.6-plus`;重写发生在 provider alias 解析之前。这些映射不再按接口区分。`GET/POST /admin/config/model-mappings` 管理接口读写的也只有这个字段。
258
236
  - **extraPrompts:** `model -> prompt` 的映射。把 Anthropic 风格请求翻译给 Copilot 时,会将其附加到第一条 system prompt 后面。你可以借此为不同模型注入护栏或指引。缺失的默认项会自动补齐,但不会覆盖你自定义的 prompt。内置的 `gpt-5.3-codex` 和 `gpt-5.4` prompt 会启用带阶段感知的 commentary,让模型在工具调用或更深层推理前先发出简短的用户可见进度说明。
259
- - **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/` 前缀。`GET /v1/models` 不聚合 provider 模型;provider 模型列表请使用 `GET /dashscope/v1/models`。
237
+ - **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/` 前缀。`openai-compatible` provider 同时支持 chat 和 Messages 流程:`/v1/chat/completions` 会直连上游 `/v1/chat/completions`,而 `/v1/messages` 和 `/:provider/v1/messages` 会先翻译为上游 Chat Completions,再把响应翻译回 Anthropic Messages。`GET /v1/models` 不聚合 provider 模型;provider 模型列表请使用 `GET /dashscope/v1/models`。
260
238
  - `enabled`:可选,若省略则默认为 `true`。
261
239
  - `baseUrl`:provider API 的基础 URL,不要带结尾的 endpoint。Anthropic provider 不要带 `/v1/messages`;OpenAI 兼容 provider 不要带 `/v1/chat/completions`;OpenAI Responses provider 不要带 `/v1/responses`。
262
240
  - `apiKey`:作为上游凭据值使用;普通 provider 必须配置。
263
241
  - `authType`:可选,控制 `apiKey` 如何发送到上游。普通 provider 支持 `x-api-key` 和 `authorization`。Anthropic provider 默认 `x-api-key`;OpenAI 兼容和 OpenAI Responses provider 默认 `authorization`。当设置为 `authorization` 时,代理会发送 `Authorization: Bearer <apiKey>`。`oauth2` 仅保留给内置 `codex` provider,并由 `auth login --provider codex` 自动写入。
242
+ - `pricingCurrency`:可选,provider 维度的 token 费用币种,例如 `USD` 或 `CNY`。快捷 provider 默认 DashScope、DeepSeek 为 `CNY`,Codex/OpenRouter 为 `USD`。费用按币种分别汇总,不做汇率换算。
264
243
  - `models`:可选,按模型 ID 配置的映射。每个键为请求中的模型名,值支持:
265
244
  - `temperature`:可选,当请求未指定时使用的默认温度。
266
245
  - `topP`:可选,当请求未指定时使用的默认 `top_p`。
267
246
  - `topK`:可选,当请求未指定时使用的默认 `top_k`。
268
247
  - `extraBody`:可选,按模型合入上游请求体的动态字段;请求体显式同名字段优先。OpenAI 兼容 provider 可用它配置 `enable_thinking`、`preserve_thinking`、`reasoning_effort` 等字段。`thinking_budget` 是 OpenAI 兼容 provider 的特殊覆盖项:配置在 `extraBody` 后,会在 Anthropic `thinking.budget_tokens` 翻译之后强制写入,并覆盖请求派生出的预算值。
248
+ - `pricing`:可选,按模型配置 token 单价,币种使用 provider 的 `pricingCurrency`,单位为每 100 万 tokens。支持 `input`、`output`、`cachedInput`(隐式缓存读)、`explicitCachedInput`(显式缓存读)和 `cacheCreationInput`。如需按输入 token 总量分档,可用带 `maxInputTokens` 的 `tiers`。
269
249
  - `contextCache`:可选,OpenAI 兼容 provider 默认 `true`,用于启用阿里云百炼/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`。
270
250
  - `supportPdf`:可选,控制该模型是否支持 PDF/document content。默认 `false`,不支持时会把 PDF 转成提示文本;设为 `true` 时会把 PDF/document 转成 OpenAI Chat Completions 的 file part。
271
251
  - `toolContentSupportType`:可选,配置该模型的 tool result content 支持能力,值为 `array`、`image`、`pdf` 的数组。provider 侧未配置时默认只发送 string tool content。若 `supportPdf` 为 `true` 但这里不包含 `pdf`,tool result 里的 file part 会被转成 user role 消息。Copilot 主链路不使用这个 provider 默认,仍按 array + image 且不支持 PDF 的能力处理。
252
+
253
+ DashScope 模型配置示例:
254
+ ```json
255
+ {
256
+ "providers": {
257
+ "dashscope": {
258
+ "type": "openai-compatible",
259
+ "enabled": true,
260
+ "baseUrl": "https://dashscope.aliyuncs.com/compatible-mode",
261
+ "apiKey": "sk-your-dashscope-key",
262
+ "pricingCurrency": "CNY",
263
+ "models": {
264
+ "qwen3.6-plus": {
265
+ "temperature": 1,
266
+ "topP": 0.95,
267
+ "topK": 20,
268
+ "extraBody": {
269
+ "preserve_thinking": true
270
+ }
271
+ },
272
+ "glm-5.1": {
273
+ "temperature": 0.7,
274
+ "topP": 0.95,
275
+ "contextCache": true,
276
+ "pricing": {
277
+ "tiers": [
278
+ {
279
+ "maxInputTokens": 32000,
280
+ "input": 6,
281
+ "cachedInput": 1.2,
282
+ "explicitCachedInput": 0.6,
283
+ "cacheCreationInput": 7.5,
284
+ "output": 24
285
+ },
286
+ {
287
+ "maxInputTokens": 200000,
288
+ "input": 8,
289
+ "cachedInput": 1.6,
290
+ "explicitCachedInput": 0.8,
291
+ "cacheCreationInput": 10,
292
+ "output": 28
293
+ }
294
+ ]
295
+ },
296
+ "extraBody": {
297
+ "preserve_thinking": true
298
+ }
299
+ }
300
+ }
301
+ }
302
+ }
303
+ }
304
+ ```
305
+ 内置 token 价格覆盖 Codex GPT 模型(USD)、DashScope `qwen3.7-max`、`qwen3.7-plus`、`glm-5.1`、`glm-5.2`(CNY),以及 DeepSeek `deepseek-v4-flash`、`deepseek-v4-pro`、`deepseek-chat`、`deepseek-reasoner`(CNY)。用户配置的 `pricing` 优先于内置价格。DashScope 若上游 usage 中出现 `cache_creation_input_tokens` 字段,cached tokens 按显式缓存读价计费;否则 `cachedInput` 作为隐式缓存读价。DeepSeek 的 `prompt_cache_hit_tokens` 会归入 cached input,`prompt_cache_miss_tokens` 会归入普通 input。
272
306
  - **smallModel:** 无工具预热消息的回退模型(例如 Claude Code 的探测请求);默认是 `gpt-5-mini`。
273
307
  - **useResponsesApiContextManagement:** 当为 `true` 时,代理会为 Responses API 附加 `context_management` 压缩指令。默认值为 `true`。如需全局关闭,可设为 `false`。启用后,请求体会带上 `context_management`,并在后续轮次中仅保留最新的压缩承载内容,因此特别适合长任务场景。
274
308
  - **modelResponsesApiCompactThresholds:** 按模型覆盖 Responses API 的 `compact_threshold`,仅在代理自动附加 `context_management` 时使用。它的优先级高于 `resolveResponsesCompactThreshold` 基于 `max_prompt_tokens * ratio` 的兜底阈值。默认将 `gpt-5.4` 和 `gpt-5.5` 设为 `217600`(`272000 * 0.8`)。未列出的模型继续使用原有兜底逻辑。
@@ -308,7 +342,7 @@ curl http://localhost:4141/admin/config/model-mappings \
308
342
 
309
343
  ## API 端点
310
344
 
311
- 服务端提供多个端点来与 Copilot API 交互。它支持 OpenAI 兼容端点,也支持 Anthropic 兼容端点,因此可以更灵活地接入不同工具与服务。
345
+ 服务端提供多个 OpenAI / Anthropic 兼容端点。请求会根据所选模型和 `provider/model` 别名路由到 GitHub Copilot、内置 `codex` provider 或已配置的 provider。
312
346
 
313
347
  ### OpenAI 兼容端点
314
348
 
@@ -317,7 +351,7 @@ curl http://localhost:4141/admin/config/model-mappings \
317
351
  | 端点 | 方法 | 说明 |
318
352
  | --- | --- | --- |
319
353
  | `POST /v1/responses` | `POST` | OpenAI 中用于生成模型响应的高级接口。支持 `openai-responses` provider 的 `provider/model` 别名。 |
320
- | `POST /v1/chat/completions` | `POST` | 为给定聊天对话创建模型响应。支持 `openai-compatible` provider 的 `provider/model` 别名。 |
354
+ | `POST /v1/chat/completions` | `POST` | 为给定聊天对话创建模型响应。支持 `openai-compatible` provider 的 `provider/model` 别名;目标 provider 已配置时可在没有 Copilot 的情况下使用。 |
321
355
  | `GET /v1/models` | `GET` | 列出当前可用模型。 |
322
356
  | `POST /v1/embeddings` | `POST` | 创建表示输入文本的向量嵌入。 |
323
357
 
@@ -327,9 +361,9 @@ curl http://localhost:4141/admin/config/model-mappings \
327
361
 
328
362
  | 端点 | 方法 | 说明 |
329
363
  | --- | --- | --- |
330
- | `POST /v1/messages` | `POST` | 为给定对话创建模型响应。支持已配置 provider 的 `provider/model` 别名。 |
364
+ | `POST /v1/messages` | `POST` | 为给定对话创建模型响应。支持已配置 provider 的 `provider/model` 别名,包括通过 `openai-compatible` provider 做翻译。 |
331
365
  | `POST /v1/messages/count_tokens` | `POST` | 计算一组消息的 token 数。支持已配置 provider 的 `provider/model` 别名。 |
332
- | `POST /:provider/v1/messages` | `POST` | 将 Anthropic Messages 请求代理到已配置的 AnthropicOpenAI 兼容或 OpenAI Responses provider。 |
366
+ | `POST /:provider/v1/messages` | `POST` | 将 Anthropic Messages 请求代理到已配置的 Anthropic provider,或翻译到 OpenAI 兼容 / OpenAI Responses provider。 |
333
367
  | `GET /:provider/v1/models` | `GET` | 将模型列表请求代理到已配置的 provider。 |
334
368
  | `POST /:provider/v1/messages/count_tokens` | `POST` | 为 provider 路由请求在本地计算 token 数。 |
335
369
 
@@ -365,8 +399,9 @@ npx @jeffreycao/copilot-api@latest start --port 8080 --verbose
365
399
  # 执行认证流程
366
400
  npx @jeffreycao/copilot-api@latest auth login
367
401
 
368
- # 在终端中查看 Copilot 用量与额度(无需启动服务)
369
- npx @jeffreycao/copilot-api@latest check-usage
402
+ # 配置第三方 provider,然后不依赖 GitHub Copilot 启动
403
+ npx @jeffreycao/copilot-api@latest auth login --provider dashscope
404
+ npx @jeffreycao/copilot-api@latest start
370
405
 
371
406
  # 以 JSON 格式输出调试信息
372
407
  npx @jeffreycao/copilot-api@latest debug --json
@@ -375,6 +410,18 @@ npx @jeffreycao/copilot-api@latest debug --json
375
410
  bunx --bun @jeffreycao/copilot-api@latest start
376
411
  ```
377
412
 
413
+ 配置 `dashscope` 后的 OpenAI 兼容 provider 调用示例:
414
+
415
+ ```sh
416
+ curl http://localhost:4141/v1/chat/completions \
417
+ -H "content-type: application/json" \
418
+ -d '{"model":"dashscope/qwen3.6-plus","messages":[{"role":"user","content":"hello"}]}'
419
+
420
+ curl http://localhost:4141/dashscope/v1/messages \
421
+ -H "content-type: application/json" \
422
+ -d '{"model":"qwen3.6-plus","max_tokens":1024,"messages":[{"role":"user","content":"hello"}]}'
423
+ ```
424
+
378
425
  ## 与 Claude Code 一起使用
379
426
 
380
427
  这个 AI gateway 可以为 [Claude Code](https://docs.anthropic.com/en/claude-code) 提供后端能力。Claude Code 是 Anthropic 提供的实验性面向开发者的对话式 AI 助手。
@@ -414,8 +461,7 @@ npx @jeffreycao/copilot-api@latest start --claude-code
414
461
  "CLAUDE_CODE_ATTRIBUTION_HEADER": "0",
415
462
  "CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION": "false",
416
463
  "CLAUDE_CODE_DISABLE_TERMINAL_TITLE": "true",
417
- "CLAUDE_CODE_ENABLE_AWAY_SUMMARY": "0",
418
- "CLAUDE_PLUGIN_ENABLE_QUESTION_RULES": "true"
464
+ "CLAUDE_CODE_ENABLE_AWAY_SUMMARY": "0"
419
465
  },
420
466
  "permissions": {
421
467
  "deny": [
@@ -716,7 +762,6 @@ bun run start start
716
762
  - `--manual`:为每个请求启用手动审批,让你完全控制何时发送请求。
717
763
  - `--rate-limit <seconds>`:强制请求之间至少保持一定秒数的间隔。例如 `copilot-api start --rate-limit 30` 会确保两次请求之间至少间隔 30 秒。
718
764
  - `--wait`:与 `--rate-limit` 配合使用。在命中速率限制时,服务会等待冷却结束,而不是直接返回错误。对于不会自动重试的客户端,这会很有帮助。
719
- - 如果你使用的是 GitHub Business 或 Enterprise 版 Copilot 账号,请使用 `--account-type` 参数(例如 `--account-type business`)。详见 [官方文档](https://docs.github.com/en/enterprise-cloud@latest/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/managing-github-copilot-access-to-your-organizations-network#configuring-copilot-subscription-based-network-routing-for-your-enterprise-or-organization)。
720
765
 
721
766
  <a id="claudemd-or-agentsmd-recommended-content"></a>
722
767
 
@@ -0,0 +1,2 @@
1
+ import { t as auth } from "./auth-DcYySZhC.js";
2
+ export { auth };
@@ -1,12 +1,12 @@
1
- import { E as ensurePaths, T as PATHS, t as SUPPORTED_PROVIDER_TYPES, u as getRawProviderConfig, v as isSupportedProviderType, w as setProviderConfig, x as normalizeProviderBaseUrl } from "./config-B71_S_hQ.js";
2
- import { A as loginCodex, L as state, a as setupGitHubToken, n as persistCodexCredentials } from "./token-fpw8tAQS.js";
1
+ import { E as ensurePaths, T as PATHS, t as SUPPORTED_PROVIDER_TYPES, u as getRawProviderConfig, v as isSupportedProviderType, w as setProviderConfig, x as normalizeProviderBaseUrl } from "./config-CQxppJtD.js";
2
+ import { R as state, a as setupGitHubToken, j as loginCodex, n as persistCodexCredentials } from "./token-CFArcYwb.js";
3
3
  import { defineCommand } from "citty";
4
4
  import consola from "consola";
5
5
  //#region src/auth.ts
6
6
  const authArgs = {
7
7
  provider: {
8
8
  type: "string",
9
- description: "Provider to log in with or configure (copilot, codex, custom)"
9
+ description: "Provider to log in with or configure (copilot, codex, deepseek, dashscope, openrouter, custom)"
10
10
  },
11
11
  verbose: {
12
12
  alias: "v",
@@ -20,12 +20,42 @@ const authArgs = {
20
20
  description: "Show provider access token on auth"
21
21
  }
22
22
  };
23
- const AUTH_PROVIDER_NAMES = [...["copilot", "codex"], "custom"];
23
+ const BUILTIN_PROVIDER_NAMES = ["copilot", "codex"];
24
+ const QUICK_PROVIDER_CONFIGS = {
25
+ deepseek: {
26
+ type: "openai-compatible",
27
+ baseUrl: "https://api.deepseek.com",
28
+ pricingCurrency: "CNY",
29
+ editableType: true
30
+ },
31
+ dashscope: {
32
+ type: "openai-compatible",
33
+ baseUrl: "https://dashscope.aliyuncs.com/compatible-mode",
34
+ pricingCurrency: "CNY",
35
+ editableType: true
36
+ },
37
+ openrouter: {
38
+ type: "anthropic",
39
+ baseUrl: "https://openrouter.ai/api",
40
+ pricingCurrency: "USD",
41
+ editableType: false
42
+ }
43
+ };
44
+ const QUICK_PROVIDER_NAMES = Object.keys(QUICK_PROVIDER_CONFIGS);
45
+ const AUTH_PROVIDER_NAMES = [
46
+ ...BUILTIN_PROVIDER_NAMES,
47
+ ...QUICK_PROVIDER_NAMES,
48
+ "custom"
49
+ ];
24
50
  const CUSTOM_PROVIDER_AUTH_TYPE_OPTION = "__default__";
51
+ const QUICK_PROVIDER_DEFAULT_TYPE_OPTION = "__default__";
25
52
  const CUSTOM_PROVIDER_AUTH_TYPES = ["x-api-key", "authorization"];
26
53
  const AUTH_PROVIDER_LABELS = {
27
54
  copilot: "GitHub Copilot",
28
55
  codex: "OpenAI Codex",
56
+ deepseek: "DeepSeek",
57
+ dashscope: "DashScope",
58
+ openrouter: "OpenRouter",
29
59
  custom: "Custom provider"
30
60
  };
31
61
  function isAuthProviderName(providerName) {
@@ -34,6 +64,9 @@ function isAuthProviderName(providerName) {
34
64
  function isCustomProviderAuthType(value) {
35
65
  return CUSTOM_PROVIDER_AUTH_TYPES.includes(value);
36
66
  }
67
+ function isQuickProviderName(providerName) {
68
+ return QUICK_PROVIDER_NAMES.includes(providerName);
69
+ }
37
70
  async function resolveProviderSelection(providerArg) {
38
71
  const availableProviders = [...AUTH_PROVIDER_NAMES];
39
72
  if (providerArg !== void 0) {
@@ -63,6 +96,68 @@ async function promptRequiredText(message, fieldName) {
63
96
  if (!normalizedValue) throw new Error(`${fieldName} must be a non-empty string`);
64
97
  return normalizedValue;
65
98
  }
99
+ function canUseMaskedPrompt() {
100
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY && typeof process.stdin.setRawMode === "function");
101
+ }
102
+ async function promptMaskedText(message) {
103
+ if (!canUseMaskedPrompt()) {
104
+ const value = await consola.prompt(message, { type: "text" });
105
+ return typeof value === "string" ? value : "";
106
+ }
107
+ return await new Promise((resolve, reject) => {
108
+ let value = "";
109
+ const rawModeWasEnabled = process.stdin.isRaw === true;
110
+ function cleanup() {
111
+ process.stdin.off("data", onData);
112
+ process.stdin.setRawMode(rawModeWasEnabled);
113
+ process.stdin.pause();
114
+ }
115
+ function finish() {
116
+ cleanup();
117
+ process.stdout.write("\n");
118
+ resolve(value);
119
+ }
120
+ function cancel() {
121
+ cleanup();
122
+ process.stdout.write("\n");
123
+ reject(/* @__PURE__ */ new Error("Prompt cancelled"));
124
+ }
125
+ function onData(chunk) {
126
+ const input = chunk.toString("utf8");
127
+ if (input.startsWith("\x1B")) return;
128
+ for (const char of input) {
129
+ if (char === "") {
130
+ cancel();
131
+ return;
132
+ }
133
+ if (char === "\r" || char === "\n") {
134
+ finish();
135
+ return;
136
+ }
137
+ if (char === "\b" || char === "") {
138
+ if (value.length > 0) {
139
+ value = value.slice(0, -1);
140
+ process.stdout.write("\b \b");
141
+ }
142
+ continue;
143
+ }
144
+ if (char >= " ") {
145
+ value += char;
146
+ process.stdout.write("*");
147
+ }
148
+ }
149
+ }
150
+ process.stdout.write(`${message}: `);
151
+ process.stdin.setRawMode(true);
152
+ process.stdin.resume();
153
+ process.stdin.on("data", onData);
154
+ });
155
+ }
156
+ async function promptRequiredSecret(message, fieldName) {
157
+ const normalizedValue = (await promptMaskedText(message)).trim();
158
+ if (!normalizedValue) throw new Error(`${fieldName} must be a non-empty string`);
159
+ return normalizedValue;
160
+ }
66
161
  async function promptCustomProviderName() {
67
162
  const providerName = await promptRequiredText("Enter provider name", "Provider name");
68
163
  assertCustomProviderName(providerName);
@@ -79,6 +174,21 @@ async function promptCustomProviderType() {
79
174
  if (typeof providerType !== "string" || !isSupportedProviderType(providerType)) throw new Error("No provider type selected");
80
175
  return providerType;
81
176
  }
177
+ async function promptQuickProviderType(defaultType) {
178
+ const providerType = await consola.prompt(`Select provider type (default: ${defaultType})`, {
179
+ type: "select",
180
+ options: [{
181
+ label: `Default (${defaultType})`,
182
+ value: QUICK_PROVIDER_DEFAULT_TYPE_OPTION
183
+ }, ...SUPPORTED_PROVIDER_TYPES.map((type) => ({
184
+ label: type,
185
+ value: type
186
+ }))]
187
+ });
188
+ if (providerType === QUICK_PROVIDER_DEFAULT_TYPE_OPTION) return defaultType;
189
+ if (typeof providerType === "string" && isSupportedProviderType(providerType)) return providerType;
190
+ throw new Error("No provider type selected");
191
+ }
82
192
  function getDefaultProviderAuthType(providerType) {
83
193
  return providerType === "anthropic" ? "x-api-key" : "authorization";
84
194
  }
@@ -98,6 +208,16 @@ async function promptCustomProviderAuthType(providerType) {
98
208
  if (typeof authType === "string" && isCustomProviderAuthType(authType)) return authType;
99
209
  throw new Error("No provider auth type selected");
100
210
  }
211
+ async function promptQuickProviderBaseUrl(defaultBaseUrl) {
212
+ const value = await consola.prompt(`Enter provider baseUrl (default: ${defaultBaseUrl})`, {
213
+ type: "text",
214
+ default: defaultBaseUrl,
215
+ initial: defaultBaseUrl
216
+ });
217
+ const baseUrl = normalizeProviderBaseUrl(typeof value === "string" && value.trim() ? value : defaultBaseUrl);
218
+ if (!baseUrl) throw new Error("baseUrl must be a non-empty string");
219
+ return baseUrl;
220
+ }
101
221
  function buildCustomProviderConfig(existingProviderConfig, options) {
102
222
  return {
103
223
  type: options.type,
@@ -105,6 +225,7 @@ function buildCustomProviderConfig(existingProviderConfig, options) {
105
225
  baseUrl: options.baseUrl,
106
226
  apiKey: options.apiKey,
107
227
  ...options.authType ? { authType: options.authType } : {},
228
+ pricingCurrency: options.pricingCurrency ?? existingProviderConfig.pricingCurrency,
108
229
  ...existingProviderConfig.models ? { models: existingProviderConfig.models } : {}
109
230
  };
110
231
  }
@@ -113,7 +234,7 @@ async function configureCustomProvider() {
113
234
  const type = await promptCustomProviderType();
114
235
  const baseUrl = normalizeProviderBaseUrl(await promptRequiredText("Enter provider baseUrl", "baseUrl"));
115
236
  if (!baseUrl) throw new Error("baseUrl must be a non-empty string");
116
- const apiKey = await promptRequiredText("Enter provider apiKey", "apiKey");
237
+ const apiKey = await promptRequiredSecret("Enter provider apiKey", "apiKey");
117
238
  const authType = await promptCustomProviderAuthType(type);
118
239
  setProviderConfig(providerName, buildCustomProviderConfig(getRawProviderConfig(providerName) ?? {}, {
119
240
  apiKey,
@@ -123,6 +244,19 @@ async function configureCustomProvider() {
123
244
  }));
124
245
  consola.success(`Custom provider '${providerName}' written to ${PATHS.CONFIG_PATH}`);
125
246
  }
247
+ async function configureQuickProvider(providerName) {
248
+ const defaultProviderConfig = QUICK_PROVIDER_CONFIGS[providerName];
249
+ const apiKey = await promptRequiredSecret(`Enter ${providerName} apiKey`, "apiKey");
250
+ const type = defaultProviderConfig.editableType ? await promptQuickProviderType(defaultProviderConfig.type) : defaultProviderConfig.type;
251
+ const baseUrl = await promptQuickProviderBaseUrl(defaultProviderConfig.baseUrl);
252
+ setProviderConfig(providerName, buildCustomProviderConfig(getRawProviderConfig(providerName) ?? {}, {
253
+ apiKey,
254
+ baseUrl,
255
+ pricingCurrency: defaultProviderConfig.pricingCurrency,
256
+ type
257
+ }));
258
+ consola.success(`${AUTH_PROVIDER_LABELS[providerName]} provider '${providerName}' written to ${PATHS.CONFIG_PATH}`);
259
+ }
126
260
  async function loginWithCodex() {
127
261
  await persistCodexCredentials(await loginCodex({
128
262
  onAuth(info) {
@@ -149,10 +283,19 @@ async function loginWithProvider(provider) {
149
283
  await loginWithCodex();
150
284
  return;
151
285
  }
286
+ if (isQuickProviderName(provider)) {
287
+ await configureQuickProvider(provider);
288
+ return;
289
+ }
152
290
  await configureCustomProvider();
153
291
  }
292
+ async function runProviderSetup() {
293
+ const provider = await resolveProviderSelection(void 0);
294
+ consola.info(`Logging in with ${AUTH_PROVIDER_LABELS[provider]}`);
295
+ await loginWithProvider(provider);
296
+ }
154
297
  async function runAuthLogin(options) {
155
- (await import("./tls-CaLAeSaF.js")).enableSystemCACompat();
298
+ (await import("./tls-BniQ6Rel.js")).enableSystemCACompat();
156
299
  if (options.verbose) {
157
300
  consola.level = 5;
158
301
  consola.info("Verbose logging enabled");
@@ -193,6 +336,6 @@ const auth = defineCommand({
193
336
  }
194
337
  });
195
338
  //#endregion
196
- export { auth };
339
+ export { runAuthLogin as n, runProviderSetup as r, auth as t };
197
340
 
198
- //# sourceMappingURL=auth-BMROoous.js.map
341
+ //# sourceMappingURL=auth-DcYySZhC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-DcYySZhC.js","names":[],"sources":["../src/auth.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport {\n getRawProviderConfig,\n isSupportedProviderType,\n normalizeProviderBaseUrl,\n setProviderConfig,\n SUPPORTED_PROVIDER_TYPES,\n type ProviderAuthType,\n type ProviderConfig,\n type ProviderType,\n} from \"./lib/config\"\nimport { loginCodex } from \"./lib/oauth/codex\"\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { persistCodexCredentials, setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\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, deepseek, dashscope, openrouter, custom)\",\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_CONFIGS = {\n deepseek: {\n type: \"openai-compatible\",\n baseUrl: \"https://api.deepseek.com\",\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<\n string,\n {\n type: ProviderType\n baseUrl: string\n pricingCurrency: string\n editableType: boolean\n }\n>\nconst QUICK_PROVIDER_NAMES = Object.keys(QUICK_PROVIDER_CONFIGS) as Array<\n keyof typeof QUICK_PROVIDER_CONFIGS\n>\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 QuickProviderName = (typeof QUICK_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 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 consola.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 consola.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 consola.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(): Promise<string> {\n const providerName = await promptRequiredText(\n \"Enter provider name\",\n \"Provider name\",\n )\n assertCustomProviderName(providerName)\n return providerName\n}\n\nasync function promptCustomProviderType(): Promise<ProviderType> {\n const providerType = await consola.prompt(\"Select provider type\", {\n type: \"select\",\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 promptQuickProviderType(\n defaultType: ProviderType,\n): Promise<ProviderType> {\n const providerType = await consola.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 consola.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 consola.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 },\n): ProviderConfig {\n return {\n type: options.type,\n enabled: true,\n baseUrl: options.baseUrl,\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 providerName = await promptCustomProviderName()\n const type = await promptCustomProviderType()\n const baseUrl = 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 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(): 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 consola.prompt(message, {\n type: \"text\",\n })\n },\n onProgress(message) {\n consola.debug(message)\n },\n })\n\n await persistCodexCredentials(credentials, { enableProvider: true })\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(provider: AuthProviderName): Promise<void> {\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()\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)\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 provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\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 login: authLogin,\n },\n run({ args }) {\n if ((args._[0] ?? \"\").trim()) {\n return\n }\n\n return runAuthLogin({\n provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n"],"mappings":"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"}