@vibeapi/api-helper 0.0.131 → 0.0.133

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 CHANGED
@@ -1,137 +1,198 @@
1
1
  # VibeCLI(@vibeapi/api-helper)
2
2
 
3
- > 一条命令,在 Claude Code / Claude Desktop / Codex / Grok Build / Antigravity CLI 之间统一配置 API Key 与模型。
3
+ > 一条命令,为 Claude Code、Claude Desktop、Codex、Grok Build、Antigravity CLI 配置 VibeAPI 的令牌和模型。
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@vibeapi/api-helper.svg)](https://www.npmjs.com/package/@vibeapi/api-helper)
6
6
  [![Node](https://img.shields.io/node/v/@vibeapi/api-helper.svg)](https://nodejs.org)
7
7
 
8
- 命令名:`vibecli`(也可用 `api-helper`)。需要 **Node.js >= 20**。每个命令的用法、示例和适用场景:`vibecli <命令> --help`,或在线文档 https://docs.vibeapi.cn/zh/docs/coding-tools/commands 。
8
+ 命令名是 `vibecli`,也可以用 `api-helper`。需要 **Node.js 20 及以上**。令牌在 VibeAPI 控制台的「令牌」页新建。每个命令的用法、示例和适用场景见 `vibecli <命令> --help`,或在线文档 https://docs.vibeapi.cn/zh/docs/coding-tools/commands 。
9
9
 
10
- ## 安装 / 运行
10
+ ## 安装与运行
11
+
12
+ 不安装、直接运行最新版:
13
+
14
+ ```bash
15
+ npx @vibeapi/cli@latest
16
+ ```
17
+
18
+ 或者全局安装,之后用 `vibecli` 运行:
11
19
 
12
20
  ```bash
13
- npx @vibeapi/cli@latest # 免安装直接跑(@latest 确保拿到最新版)
14
- npm install -g @vibeapi/cli # 或全局安装后用 vibecli
21
+ npm install -g @vibeapi/cli
15
22
  ```
16
23
 
17
- > `@vibeapi/cli` 与 `@vibeapi/api-helper` 是同一产物的双包名(同版本等价),装哪个都一样。
24
+ `@vibeapi/cli` 与 `@vibeapi/api-helper` 是同一个程序的两个包名,同版本内容相同,安装哪个都可以。
18
25
 
19
- npmjs.com 不可用时,可直接从 CNB 备用制品库启动:
26
+ npmjs.com 无法访问时,从 CNB 备用制品库启动:
20
27
 
21
28
  ```bash
22
29
  npx --yes --registry https://npm.cnb.cool/vibeapi/npm/-/packages/ @vibeapi/cli@latest
23
30
  ```
24
31
 
25
- 全局安装的 `vibecli` 每次启动都会进入自动更新预检(6 小时内复用缓存),固定按 **CNB → npmjs → npmmirror → Yarn registry** 查询和安装;检测到新版会自动升级并重新执行当前命令。网络或权限错误不会阻断原命令,每个安装源最长等待 45 秒,安装失败后 1 小时内不重复打扰。设置 `VIBECLI_DISABLE_AUTO_UPDATE=1` 可关闭启动更新。`npx @latest` 在 CLI 启动前由 npm 解析,因此首次下载失败时请使用上面的 CNB 命令。
32
+ 全局安装的 `vibecli` 每次启动先检查更新(结果缓存 6 小时),按 **CNB → npmjs → npmmirror → Yarn registry** 的顺序查询和安装;有新版时自动升级,再重新执行当前命令。网络或权限出错时照常执行原命令:每个安装源最多等 45 秒,安装失败后 1 小时内不再重试。设置 `VIBECLI_DISABLE_AUTO_UPDATE=1` 可关闭启动时的更新。`npx @vibeapi/cli@latest` 由 npm 在 VibeCLI 启动前下载,所以第一次就下载失败时,请改用上面的 CNB 命令。
26
33
 
27
- 还没装编码工具?国内一条命令装好(与官方安装器相同的安装方式,程序从国内镜像下载;再跑一次就是升级)。Node.js(VibeCLI 需要 20 及以上)和 Git 的脚本先找机器上已有的,有就不装:
34
+ ### 还没有安装编码工具
35
+
36
+ 每个工具一条命令,安装方式与官方安装器相同,程序从国内镜像下载;再运行一次即升级。Node.js(VibeCLI 需要 20 及以上)和 Git 的脚本会先查找机器上已有的版本,已有就不安装。
28
37
 
29
38
  | 工具 | macOS / Linux | Windows PowerShell |
30
39
  | --------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
31
40
  | Claude Code | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/claude-code.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/claude-code.ps1 \| iex` |
32
41
  | Codex | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/codex.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/codex.ps1 \| iex` |
42
+ | Grok Build | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/grok.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/grok.ps1 \| iex` |
33
43
  | Antigravity CLI | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/agy.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/agy.ps1 \| iex` |
34
44
  | Node.js | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/node.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/node.ps1 \| iex` |
35
45
  | Git | `curl -fsSL https://cnb.cool/vibeapi/install/-/git/raw/main/git.sh \| sh` | `irm https://cnb.cool/vibeapi/install/-/git/raw/main/git.ps1 \| iex` |
36
46
 
37
47
  ## 快速开始
38
48
 
39
- 下面三种方式**三选一即可**,任选一种就已经配置完成 —— 不要按顺序依次执行。
49
+ 下面三种方式**任选一种**,完成任意一种就已经配置好了,不要依次全部执行。
40
50
 
41
- ### 方式 A:一条命令直配(推荐)
51
+ ### 方式 A:一条命令配置(推荐)
42
52
 
43
- 无需任何交互,粘贴即用;重复执行即换令牌。
53
+ 不需要任何交互;换令牌时重新执行一次即可。
44
54
 
45
55
  ```bash
46
56
  vibecli setup --key sk-xxx
47
57
  ```
48
58
 
49
- `--key` 会按令牌能访问的模型分组自动配置:有 Claude 模型配 Claude Code 和 Claude Desktop(macOS / Windows 上桌面端没装也先写好,装好打开就能用;Linux 官方版装了才配)、有 GPT 模型配 Codex、有 Grok 模型配 Grok Build、有 Gemini 模型配 Antigravity CLI(`agy`)。没装的命令行工具先问要不要从国内镜像装上(`--install` 直接装),装好才写它的配置;不装就不动它的配置目录,装好后运行 `vibecli config <工具> --yes` 补上。拿到的是多个分组的令牌(如 Claude 分组 + GPT 分组 + Grok 分组),就各配各的:
59
+ `--key` 按令牌能用的模型自动选择工具:
60
+
61
+ | 令牌能用的模型 | 配置的工具 |
62
+ | -------------- | --------------------------- |
63
+ | Claude | Claude Code、Claude Desktop |
64
+ | GPT | Codex |
65
+ | Grok | Grok Build |
66
+ | Gemini | Antigravity CLI(`agy`) |
67
+
68
+ Claude Desktop 在 macOS 和 Windows 上即使还没有安装也会先写好配置,安装后打开即可使用;Linux 上只配置已安装的官方版。
69
+
70
+ 还没有安装的命令行工具,VibeCLI 会先问是否从国内镜像安装(加 `--install` 直接安装、不再询问),安装完成后才写它的配置。选择不安装时不改动它的配置目录,以后安装好再运行 `vibecli config <工具> --yes` 补上配置。
71
+
72
+ 不同分组各有一个令牌时(例如 Claude 分组、GPT 分组、Grok 分组各一个),分别指定:
50
73
 
51
74
  ```bash
52
75
  vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d
53
76
  ```
54
77
 
55
- 每个工具都能单独给 Key:`--claudekey`、`--codexkey`、`--grokkey`、`--desktopkey`、`--agykey`。
78
+ 每个工具都可以单独指定令牌:`--claudekey`、`--codexkey`、`--grokkey`、`--desktopkey`、`--agykey`。
56
79
 
57
- Codex 同时开启 1M 上下文时,末尾加最短参数 `--1m`;已经配置过的用户无需再次输入 Key。单独执行 `--1m` 只重新生成模型目录里的上下文设置,不改写 Codex 凭据:
80
+ Codex 默认开启 1M 上下文。配置 Codex 时显式开启,在末尾加 `--1m`:
58
81
 
59
82
  ```bash
60
83
  vibecli setup --codexkey sk-xxx --1m
84
+ ```
85
+
86
+ 已经配置过 Codex、只想开启 1M 上下文时,不需要再输入令牌。这条命令只重新生成模型目录里的上下文设置,不改写 Codex 的凭据:
87
+
88
+ ```bash
61
89
  vibecli setup --1m
90
+ ```
91
+
92
+ 关闭 1M 上下文,同样不改写凭据:
93
+
94
+ ```bash
62
95
  vibecli setup --no-1m
63
96
  ```
64
97
 
65
- 配完直接运行 `claude` / `codex` / `grok` 即可(agy 要新开一个终端)。Claude Desktop 默认隐藏官方(Claude.ai 账号)登录入口、只走网关,想保留就加 `--claude-official on`。
98
+ 配置完成后直接运行 `claude`、`codex` 或 `grok` 即可;`agy` 要在新开的终端里运行。Claude Desktop 默认隐藏官方(Claude.ai 账号)登录入口、只用 VibeAPI,要保留官方登录入口时加 `--claude-official on`。
66
99
 
67
100
  ### 方式 B:交互式向导
68
101
 
69
- 想在菜单里挑工具和模型时用(中文系统自动中文界面,非中文系统先选语言):
102
+ 想在菜单里选择工具和模型时使用。中文系统自动显示中文界面,其他系统先选择语言:
70
103
 
71
104
  ```bash
72
105
  vibecli init
73
106
  ```
74
107
 
75
- ### 方式 C:CI / 脚本
108
+ ### 方式 C:CI 与脚本
109
+
110
+ 先保存令牌:
76
111
 
77
112
  ```bash
78
113
  vibecli auth sk-xxx --non-interactive
114
+ ```
115
+
116
+ 再把配置写入某个工具,例如 Claude Code:
117
+
118
+ ```bash
79
119
  vibecli config claude-code --non-interactive
80
120
  ```
81
121
 
82
- ### 配完之后
122
+ ### 配置完成后
123
+
124
+ 查看当前配置:
125
+
126
+ ```bash
127
+ vibecli status
128
+ ```
129
+
130
+ 模型设置被固定、想恢复成工具自带的默认模型时(保留令牌):
83
131
 
84
132
  ```bash
85
- vibecli status # 查看当前配置
86
- vibecli config claude-code clear-model # 模型选择被钉住时,交还给工具自带默认(保留 API Key)
133
+ vibecli config claude-code clear-model
87
134
  ```
88
135
 
89
- ## 能做什么
136
+ ## 功能
90
137
 
91
- - **多工具一键配置**:把当前 API Key / 模型注入 Claude Code、Claude Desktop(桌面端第三方推理模式,写应用本地配置库,无需管理员 / 描述文件)、Codex、Grok Build、Antigravity CLI(OpenCode 暂时下架,`vibecli config opencode` 仍可用)。
92
- - **按工具选模型**:使用默认 / 实时从 API 拉取 / 内置预设 / 手动输入;每个工具可用不同模型。
93
- - Claude Code 用默认模型时不写 `ANTHROPIC_*_MODEL` 环境变量,顶层 `model` 由 `settings-template.json` 提供(当前为 `opus[1m]`);显式选择其它模型时会覆盖该模板值。Codex 默认 `gpt-6-astra`,Grok Build 默认 `grok-4.6`,其余工具默认 `gpt-5.5`。
94
- - Codex(CLI 与桌面版)的模型菜单除自带的 GPT 模型外,还列出网关的 Claude、Gemini 与国产模型(只列 Key 能用的);Claude Code 的 `/model` 菜单也会在内置档位后列出 Key 能用的国产模型;每个模型按自己的上下文窗口设置,窗口用到 80% 时自动压缩。默认启用 1M 上下文,交互配置 Codex 时可取消(取消后窗口不超过 272K)。需要 Codex 0.122 及以上;Codex、Claude Code 版本过旧时,配置完成会提示升级命令。
95
- - **不动你的其它配置**:只改本工具的 provider 字段,你的 hooks、MCP、插件、权限设置原样保留。
96
- - **配置改坏了一键重置**:`vibecli config <tool> --force`(或 `setup … --force`)先快照再整份重写为推荐配置,坏掉的 JSON/TOML 也能救回;不加 `--force` 时只幂等合并、不碰坏文件。
97
- - **改前自动备份 + 一键还原**:覆盖配置前先快照(每文件留 10 份),`vibecli config <tool> restore` 随时回退;还原本身也可再撤销。
98
- - **多 Profile + 可迁移凭据**:work/personal 各自独立;API Key 存在权限为 `0600` 的 `~/.vibecli/config.yaml`,与 Claude/Codex 本身的明文凭据方式一致,换机不会被主机绑定加密阻断。
99
- - **CI 友好**:所有命令支持 `--json` / `--non-interactive` / `--yes` / `--dry-run` / `--no-color`。
138
+ - **一次配置多个工具**:把当前的令牌和模型写入 Claude Code、Claude Desktop(第三方推理模式,写入应用的本地配置库,不需要管理员权限或描述文件)、Codex、Grok Build、Antigravity CLI。OpenCode 暂时下架,`vibecli config opencode` 仍可使用。
139
+ - **每个工具单独选模型**:可以用默认模型、从 API 实时获取、选内置预设或手动输入,每个工具可以用不同的模型。
140
+ - Claude Code 使用默认模型时不写 `ANTHROPIC_*_MODEL` 环境变量,顶层 `model` 取 `settings-template.json` 的值(当前为 `opus[1m]`);显式选择其他模型时覆盖这个值。Codex 默认 `gpt-6-astra`,Grok Build 默认 `grok-4.6`,其余工具默认 `gpt-5.5`。
141
+ - Codex(命令行版与桌面版)的模型菜单除了自带的 GPT 模型,还列出网关的 Claude、Gemini、Grok 和国产模型;Claude Code 的 `/model` 菜单在内置档位之后列出 GPT、Gemini、Grok 和国产模型。两边都只列令牌能用的模型。每个模型按自己的上下文窗口设置,用到窗口的 80% 时自动压缩。Codex 默认开启 1M 上下文,交互配置时可以关闭(关闭后窗口不超过 272K)。需要 Codex 0.122 及以上;Codex 或 Claude Code 版本过旧时,配置完成后会给出升级命令。
142
+ - **保留你的其他配置**:只改本工具的服务商(provider)字段,你的 hooks、MCP、插件和权限设置原样保留。
143
+ - **配置损坏时重置**:`vibecli config <tool> --force`(或 `vibecli setup … --force`)先备份,再用推荐配置整份重写,已经不是合法 JSON / TOML 的文件也能恢复。不加 `--force` 时只做合并,遇到损坏的文件不改动。
144
+ - **写入前自动备份,可以还原**:覆盖配置文件前先备份(每个文件保留 10 份),`vibecli config <tool> restore` 随时还原,还原之后还可以再撤销。
145
+ - **多个 Profile,凭据可随机器迁移**:work、personal 等 Profile 互相独立。令牌保存在权限为 `0600` 的 `~/.vibecli/config.yaml`,与 Claude Code、Codex 自己保存凭据的方式一样是明文,换机器后不会因为加密绑定原机器而无法读取。
146
+ - **适合 CI**:全局选项 `--json`、`--non-interactive`、`--yes`、`--no-color` 适用于各个命令;`setup`、`config` 和只读命令支持 `--dry-run` 预演,其他会写入的命令遇到 `--dry-run` 直接拒绝执行。
100
147
 
101
148
  ## 常用命令
102
149
 
150
+ | 命令 | 用途 |
151
+ | ------------------------------------------------- | ---------------------------------------------------------------------------------- |
152
+ | `vibecli config <tool>` | 打开某个工具的菜单:选择模型后应用、移除或还原 |
153
+ | `vibecli config <tool> restore` | 把该工具的配置还原到上次修改前 |
154
+ | `vibecli config <tool> clear-model` | 去掉固定的模型设置,恢复工具自带的默认模型(保留令牌) |
155
+ | `vibecli config <tool> remove` | 移除 VibeAPI 写入的配置(Codex 会退出令牌登录,可以改用 ChatGPT 订阅登录) |
156
+ | `vibecli config tool-model set codex gpt-6-astra` | 单独给某个工具指定模型 |
157
+ | `vibecli config profile use work` | 切换 Profile |
158
+ | `vibecli doctor` | 检查配置、网络和工具版本;加 `--deep` 时实际发一条请求 |
159
+ | `vibecli doctor --report` | 检查后上传诊断信息,得到一个诊断码,发给客服 |
160
+ | `vibecli upgrade` | 升级 Claude Code、Codex、Grok Build、agy;官方下载地址无法访问时改用国内镜像 |
161
+ | `vibecli codex sessions` | 换过登录方式后 Codex 的旧会话不显示时,让它们重新出现(先退出 Codex) |
162
+ | `vibecli setup --desktop-registry on` | Windows 上 Claude Desktop 不读取本地配置时,改为写入注册表(会请求一次管理员确认) |
163
+ | `vibecli base` | 列出并测试全部接入地址 |
164
+ | `vibecli base auto` | 换到第一个能用的接入地址,已配置的工具一起换 |
165
+
166
+ ### 主域名无法访问或证书报错
167
+
168
+ 校园网、酒店网络有时会把 `www.vibeapi.cn` 解析到别的服务器,表现为浏览器提示「连接不是私密连接」、报 `Self-signed certificate`,或者一直超时。这时换一个接入地址即可,令牌不用改。
169
+
170
+ 自动测试并换到第一个能用的地址:
171
+
103
172
  ```bash
104
- vibecli config <tool> # 配置某工具(选模型 → 应用 / 移除 / 还原)
105
- vibecli config <tool> restore # 还原该工具到上次更改前
106
- vibecli config <tool> clear-model # 清掉钉死的模型设置,回到工具自带默认(保留 API Key)
107
- vibecli config <tool> remove # 移除 VibeAPI 写入的配置(Codex 会退出 API Key 登录,可改用 ChatGPT 订阅)
108
- vibecli config tool-model set codex gpt-6-astra # 单独给某工具指定模型
109
- vibecli config profile use work # 切换 profile
110
- vibecli doctor # 健康巡检(--deep 实发一条请求)
111
- vibecli doctor --report # 巡检后上传诊断信息,得到诊断码发给客服
112
- vibecli upgrade # 升级 Claude Code / Codex / agy,官方渠道连不上自动改走国内镜像
113
- vibecli codex sessions # 换过登录方式后 Codex 旧会话不显示时,让它们重新出现(先退出 Codex)
114
- vibecli setup --desktop-registry on # Windows:桌面端不认本地配置时,强制写注册表(会请求一次管理员确认)
115
- vibecli base # 查看并测试所有接入地址
116
- vibecli base auto # 换到第一个能用的接入地址,已配置的工具一起换
173
+ vibecli base auto
117
174
  ```
118
175
 
119
- ### 主域名连不上或证书报错
176
+ 指定一个地址:
120
177
 
121
- 校园网、酒店网络有时会把 `www.vibeapi.cn` 解析到别的服务器,表现为「连接不是私密连接」「Self-signed certificate」或一直超时。这时换一个接入地址即可,API Key 不用改:
178
+ ```bash
179
+ vibecli base https://www.vibeapi.si
180
+ ```
181
+
182
+ 网络恢复后回到主站:
122
183
 
123
184
  ```bash
124
- vibecli base auto # 自动测试并换到第一个能用的地址
125
- vibecli base https://www.vibeapi.si # 或指定一个地址
126
- vibecli base default # 网络恢复后回到主站
185
+ vibecli base default
127
186
  ```
128
187
 
129
- `auto` 按这个优先级尝试,取第一个能用的:`www.vibeapi.cn` → `www.vibeapi.si` → `hk.vibeapi.cn` → `us13-www.vibeapi.cn` → `cf.vibeapi.cn` → `token.nfeyre.top`。网关控制台以后新增的地址会排在这些后面。保存了令牌时,每个地址都用它实际拉一次模型列表,拉得到才算能用;`vibecli base` 每个地址测 3 次取中位数,并标出最快的一个。第一次 `vibecli setup` / `vibecli init` 时主站连不上,也会按同样的顺序自动换到能用的地址。切换后地址保存在当前 profile 里,Claude Code、Codex、Claude 桌面端等已用 VibeCLI 配置过的工具会一起改过去,以后再运行 `vibecli setup` 也不会改回主站。首次配置时就可以指定:`vibecli setup --base https://www.vibeapi.si --key sk-xxx`。向导主菜单里也有「切换接入地址」。
188
+ `vibecli base auto` 按下面的顺序尝试,取第一个能用的:`www.vibeapi.cn` → `www.vibeapi.si` → `hk.vibeapi.cn` → `us13-www.vibeapi.cn` → `cf.vibeapi.cn` → `token.nfeyre.top`。网关控制台以后新增的地址排在这些之后。保存了令牌时,VibeCLI 用它在每个地址获取一次模型列表,获取到才算能用;`vibecli base` 对每个地址测 3 次取中位数,并标出最快的一个。
189
+
190
+ 第一次运行 `vibecli setup` 或 `vibecli init` 时如果主站无法访问,也会按同样的顺序自动换到能用的地址。切换后的地址保存在当前 Profile 里,已经用 VibeCLI 配置过的工具(Claude Code、Codex、Claude Desktop 等)会一起改用新地址,以后再运行 `vibecli setup` 也不会改回主站。首次配置时也可以直接指定地址:`vibecli setup --base https://www.vibeapi.si --key sk-xxx`。向导主菜单里也有「切换接入地址」。
130
191
 
131
192
  ## 支持
132
193
 
133
194
  主页 <https://www.vibeapi.cn/> · 反馈 <https://www.vibeapi.cn/support> · [CNB 备用制品库](https://cnb.cool/vibeapi/npm/-/registries/@vibeapi/cli)
134
195
 
135
- ## License
196
+ ## 许可证
136
197
 
137
- UNLICENSED — 仅供 VibeAPI 用户使用,详见随包附带的 LICENSE。
198
+ UNLICENSED:仅供 VibeAPI 用户使用,详见随包附带的 LICENSE。
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": 1,
3
- "revision": "2026-10-21T07:44:19Z-7",
3
+ "revision": "2026-10-25T16:32:50Z-9",
4
4
  "min_client_version": "",
5
5
  "upgrade_message": "",
6
6
  "defaults": {
@@ -214,6 +214,16 @@
214
214
  "hidden": true,
215
215
  "context_window": 1000000
216
216
  },
217
+ {
218
+ "id": "kimi-k3.1-pro",
219
+ "name": "Kimi K3.1 Pro",
220
+ "description": "105 万上下文 | Agent 编程",
221
+ "group": "",
222
+ "group_name": "",
223
+ "recommended": false,
224
+ "hidden": false,
225
+ "context_window": 1048576
226
+ },
217
227
  {
218
228
  "id": "kimi-k3",
219
229
  "name": "Kimi K3",
@@ -433,6 +443,16 @@
433
443
  "hidden": true,
434
444
  "context_window": 1000000
435
445
  },
446
+ {
447
+ "id": "kimi-k3.1-pro",
448
+ "name": "Kimi K3.1 Pro",
449
+ "description": "105 万上下文 | Agent 编程",
450
+ "group": "",
451
+ "group_name": "",
452
+ "recommended": false,
453
+ "hidden": false,
454
+ "context_window": 1048576
455
+ },
436
456
  {
437
457
  "id": "kimi-k3",
438
458
  "name": "Kimi K3",
@@ -689,7 +709,8 @@
689
709
  "hint": "可以使用高级模型 Fable,并且畅享满血提示词缓存",
690
710
  "groups": [
691
711
  "Claude 官方满血版"
692
- ]
712
+ ],
713
+ "default": true
693
714
  }
694
715
  ]
695
716
  }
package/dist/brand.json CHANGED
@@ -16,23 +16,23 @@
16
16
  },
17
17
  {
18
18
  "url": "https://www.vibeapi.si",
19
- "label": "主站备用域名(证书报错时用)"
19
+ "label": "主站备用域名"
20
20
  },
21
21
  {
22
22
  "url": "https://hk.vibeapi.cn",
23
- "label": "香港线路"
23
+ "label": "香港"
24
24
  },
25
25
  {
26
26
  "url": "https://us13-www.vibeapi.cn",
27
- "label": "US13 线路"
27
+ "label": "美国"
28
28
  },
29
29
  {
30
30
  "url": "https://cf.vibeapi.cn",
31
- "label": "Cloudflare 线路"
31
+ "label": "Cloudflare 加速"
32
32
  },
33
33
  {
34
34
  "url": "https://token.nfeyre.top",
35
- "label": "全球加速(兜底)"
35
+ "label": "全球加速"
36
36
  }
37
37
  ],
38
38
  "links": {
package/dist/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- if(Number(process.versions.node.split(".")[0])<20){const{brand:e}=await import("./lib/brand.js"),r=e().productName;console.error(`${r} 需要 Node.js 20 或更高版本,当前是 v${process.versions.node}。\n请安装 Node.js LTS(国内镜像:https://registry.npmmirror.com/binary.html?path=node/ ,或用 nvm install --lts),装好后重开终端再运行。\n${r} needs Node.js 20 or later (found v${process.versions.node}); install the LTS release and open a new terminal.`),process.exit(1)}const{Command:e}=await import("./lib/command.js"),{logger:r}=await import("./utils/logger.js"),{reportCliError:o}=await import("./lib/errors.js"),{telemetryPending:s}=await import("./lib/telemetry.js");try{await(new e).execute(process.argv.slice(2))}catch(e){r.logError("CLI",e),o(e)}s()&&process.exit();export{};
2
+ if(Number(process.versions.node.split(".")[0])<20){const{brand:e}=await import("./lib/brand.js"),r=e().productName;console.error(`无法启动 ${r}:需要 Node.js 20 或更高版本,当前是 v${process.versions.node}。\n请安装 Node.js LTS 版(国内镜像:https://registry.npmmirror.com/binary.html?path=node/ ,也可以运行 nvm install --lts),安装后重新打开终端再运行。\n${r} needs Node.js 20 or later (found v${process.versions.node}); install the LTS release and open a new terminal.`),process.exit(1)}const{Command:e}=await import("./lib/command.js"),{logger:r}=await import("./utils/logger.js"),{reportCliError:o}=await import("./lib/errors.js"),{telemetryPending:s}=await import("./lib/telemetry.js");try{await(new e).execute(process.argv.slice(2))}catch(e){r.logError("CLI",e),o(e)}s()&&process.exit();export{};
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": 1,
3
- "revision": "2026-10-21T07:44:19Z-7",
3
+ "revision": "2026-10-25T16:32:50Z-9",
4
4
  "min_client_version": "",
5
5
  "upgrade_message": "",
6
6
  "defaults": {
@@ -214,6 +214,16 @@
214
214
  "hidden": true,
215
215
  "context_window": 1000000
216
216
  },
217
+ {
218
+ "id": "kimi-k3.1-pro",
219
+ "name": "Kimi K3.1 Pro",
220
+ "description": "105 万上下文 | Agent 编程",
221
+ "group": "",
222
+ "group_name": "",
223
+ "recommended": false,
224
+ "hidden": false,
225
+ "context_window": 1048576
226
+ },
217
227
  {
218
228
  "id": "kimi-k3",
219
229
  "name": "Kimi K3",
@@ -433,6 +443,16 @@
433
443
  "hidden": true,
434
444
  "context_window": 1000000
435
445
  },
446
+ {
447
+ "id": "kimi-k3.1-pro",
448
+ "name": "Kimi K3.1 Pro",
449
+ "description": "105 万上下文 | Agent 编程",
450
+ "group": "",
451
+ "group_name": "",
452
+ "recommended": false,
453
+ "hidden": false,
454
+ "context_window": 1048576
455
+ },
436
456
  {
437
457
  "id": "kimi-k3",
438
458
  "name": "Kimi K3",
@@ -689,7 +709,8 @@
689
709
  "hint": "可以使用高级模型 Fable,并且畅享满血提示词缓存",
690
710
  "groups": [
691
711
  "Claude 官方满血版"
692
- ]
712
+ ],
713
+ "default": true
693
714
  }
694
715
  ]
695
716
  }
@@ -1 +1 @@
1
- import{refreshClientConfig as o}from"../lib/client-config-sync.js";import e from"chalk";import t from"ora";import{spawnSync as s}from"child_process";import{existsSync as r,readdirSync as n,readFileSync as a}from"fs";import{connect as i}from"net";import{join as c}from"path";import{configManager as l}from"../lib/config.js";import{savedApiKey as d}from"./base.js";import{toolManager as p}from"../lib/tool-manager.js";import{i18n as u}from"../lib/i18n.js";import{validateApiKey as m}from"../lib/api-validator.js";import{getAdapter as f}from"../lib/tools/registry.js";import{findInstalls as g,installLabel as _}from"../lib/tools/tool-installs.js";import{detectManagedOverrides as h}from"../lib/tools/claude-managed.js";import{codexAuthProblem as y,codexCatalogRejection as k,codexConfigPath as w,codexWorkModeOn as b}from"../lib/tools/codex.js";import{claudeAccountLoginPresent as v}from"../lib/tools/claude-code.js";import{toolHome as j}from"../lib/tools/types.js";import{gatewayAddresses as x,probeGatewayAddress as $}from"../lib/gateway-addresses.js";import{listAdapters as T}from"../lib/tools/registry.js";import{logger as A}from"../utils/logger.js";import{maskHome as P,maskSecrets as R,uploadReport as N}from"../lib/telemetry.js";import{CLI_NAME as O}from"../lib/brand.js";import{balanceLookupEnabled as C,balanceNeedsAttention as I,balanceText as H,fetchKeyBalances as L}from"../lib/key-balance.js";const S=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy","ALL_PROXY","all_proxy"];function U(o,e,t=3e3){return new Promise(s=>{const r=i({host:o,port:e}),n=o=>{r.destroy(),s(o)};r.setTimeout(t,()=>n(!1)),r.once("connect",()=>n(!0)),r.once("error",()=>n(!1))})}function E(){const o=A.getLogDir();if(!r(o))return"";const e=n(o).filter(o=>/^\d{4}-\d{2}-\d{2}\.log$/.test(o)).sort().slice(-2).map(e=>`== ${e}\n`+a(c(o,e),"utf-8")).join("\n");return R(e.slice(-15e4))}function K(){const o={};for(const e of S){const t=process.env[e]?.trim();if(t)try{const s=new URL(t.includes("://")?t:`http://${t}`);o[e]=`${s.protocol}//${s.host}`}catch{o[e]="(unparsable)"}}return o}export async function doctorCommand(r={}){const n=t(u.t("doctor.checking")).start(),i=[],A=Number(process.versions.node.split(".")[0]);i.push({name:"Node.js",status:A>=20?"pass":"fail",message:`v${process.versions.node}`}),n.text=u.t("doctor.check_proxy"),i.push(await async function(){const o=u.t("doctor.proxy"),e=new Map;for(const o of S){const t=process.env[o]?.trim();t&&!e.has(t)&&e.set(t,o)}if(0===e.size)return{name:o,status:"pass",message:u.t("doctor.proxy_none")};const t=[];for(const[o,s]of e){let e;try{e=new URL(o.includes("://")?o:`http://${o}`)}catch{t.push(`${s}=${o}`);continue}const r=Number(e.port)||("https:"===e.protocol?443:e.protocol.startsWith("socks")?1080:80);await U(e.hostname,r)||t.push(`${s}=${o}`)}return 0===t.length?{name:o,status:"pass",message:[...e.keys()].join(", ")}:{name:o,status:"fail",message:u.t("doctor.proxy_dead",{proxies:t.join(", ")})}}()),n.text=u.t("doctor.check_api_key_network");const R=d(),B=u.t("doctor.api_key_network");if(R){const o=await m(R);o.valid?(i.push({name:B,status:"pass"}),n.text=u.t("doctor.check_balance"),i.push(...await async function(o){if(!C())return[];const e=l.listToolApiKeys().map(o=>({tool:o,key:l.getApiKeyForTool(o)})).filter(e=>Boolean(e.key)&&e.key!==o),t=await L([o,...e.map(o=>o.key)]),s=[{name:u.t("doctor.balance"),key:o},...e.map(o=>({name:u.t("doctor.balance_tool",{tool:f(o.tool)?.displayName??o.tool}),key:o.key}))],r=[];for(const o of s){const e=t.get(o.key);e&&r.push({name:o.name,status:I(e)?"warn":"pass",message:H(e)})}return r}(R))):"invalid_api_key"===o.error?i.push({name:B,status:"fail",message:u.t("doctor.api_key_invalid")}):(i.push({name:B,status:"fail",message:`${u.t("doctor.network_error")}: ${o.message??o.error}`}),n.text=u.t("doctor.check_other_addresses"),i.push(await async function(){const o=u.t("doctor.other_addresses"),e=l.getBaseUrl(),t=x().filter(o=>o.url!==e),s=d(),r=await Promise.all(t.map(o=>$(o.url,{apiKey:s}))),n=t.filter((o,e)=>r[e].ok).map(o=>o.url);return 0===n.length?{name:o,status:"fail",message:u.t("doctor.other_addresses_none")}:{name:o,status:"warn",message:u.t("doctor.other_addresses_found",{urls:n.join(", ")})}}()))}else i.push({name:B,status:"fail",message:u.t("doctor.api_key_missing")});n.text=u.t("doctor.check_client_config");const G=await o();i.push({name:u.t("doctor.client_config"),status:"cloud"===G.source||"cache"===G.source&&!G.problem?"pass":"warn",message:[G.source?u.t(`refresh.source.${G.source}`):u.t("refresh.source.none"),G.revision?u.t("doctor.client_config_revision",{revision:G.revision}):"",G.problem??""].filter(Boolean).join(" · ")}),n.text=u.t("doctor.check_tools");const D=p.getInstalledTools();i.push({name:u.t("doctor.installed_tools"),status:D.length>0?"pass":"warn",message:D.length>0?D.map(o=>f(o)?.displayName??o).join(", "):u.t("doctor.no_tools_installed")}),i.push(...function(){const o=[];for(const e of p.getInstalledTools()){const t=f(e);if(!t?.installSpec)continue;const s=g(t.installSpec);if(0===s.length)continue;const r=[],n=p.outdatedVersion(e);n&&r.push(u.t("doctor.tool_outdated",{min:n.min})),s.length>1&&r.push(u.t("doctor.tool_duplicates",{others:s.slice(1).map(_).join("、")})),o.push({name:t.displayName,status:r.length>0?"warn":"pass",message:[_(s[0]),...r,...r.length>0?[u.t("doctor.run_upgrade",{tool:e})]:[]].join("\n ")})}return o}());const q=function(){if(!p.isToolInstalled("claude-code"))return null;const o=u.t("doctor.claude_config"),e=h();if(e.length>0){const t=e.map(o=>`${o.source}: ${o.keys.join(", ")}`).join("; ");return{name:o,status:"fail",message:u.t("doctor.claude_managed",{detail:t})}}let t={};try{t=JSON.parse(a(c(process.env.CLAUDE_CONFIG_DIR?.trim()||c(j(),".claude"),"settings.json"),"utf-8")).env??{}}catch{}const s=l.getApiKeyForTool("claude-code");return t.ANTHROPIC_AUTH_TOKEN&&t.ANTHROPIC_BASE_URL?t.ANTHROPIC_BASE_URL!==l.getBaseUrl()||s&&t.ANTHROPIC_AUTH_TOKEN!==s?{name:o,status:"warn",message:u.t("doctor.claude_config_changed")}:{name:o,status:"pass"}:{name:o,status:"warn",message:u.t("doctor.claude_not_configured")}}();q&&i.push(q),D.includes("claude-code")&&v()&&i.push({name:u.t("doctor.claude_login"),status:"pass",message:u.t("tools.claude_code.account_login_overridden")});const F=D.includes("codex")?y():null;if(D.includes("codex")&&i.push({name:u.t("doctor.codex_auth"),status:F?"fail":"pass",message:F?u.t(`doctor.codex_${F}`,{path:P(w())}):void 0}),D.includes("codex")){const o=k();i.push({name:u.t("doctor.codex_catalog"),status:o?"fail":"pass",message:o?u.t("doctor.codex_catalog_rejected",{path:o.bin,version:o.version??"?",error:o.error}):void 0})}D.includes("codex")&&b()&&i.push({name:u.t("doctor.codex_work_mode"),status:"warn",message:u.t("tools.codex.work_mode_on")}),"win32"===process.platform&&D.includes("claude-code")&&!process.env.CLAUDE_CODE_GIT_BASH_PATH&&i.push({name:"Git for Windows",status:p.isGitInstalled()?"pass":"warn",message:p.isGitInstalled()?void 0:u.t("tools.claude_code.no_git_bash")}),r.deep&&D.includes("claude-code")&&(n.text=u.t("doctor.check_claude_request"),i.push(function(){const o=u.t("doctor.claude_request"),e=g(f("claude-code").installSpec)[0];if(!e)return{name:o,status:"warn",message:u.t("doctor.claude_request_skipped")};const t={encoding:"utf-8",timeout:12e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},r=["-p","Reply with the single word OK."],n=/\.cmd$/i.test(e.path)?s(`"${e.path}" ${r.map(o=>`"${o}"`).join(" ")}`,{...t,shell:!0}):s(e.path,r,t),a=`${n.stdout??""}`.trim();if(0===n.status&&a)return{name:o,status:"pass",message:a.slice(0,80)};const i=(`${n.stderr??""}`.trim()||a||n.error?.message||`exit ${n.status}`).slice(0,300);return{name:o,status:"fail",message:u.t("doctor.claude_request_failed",{reason:i})}}())),n.stop(),console.log("\n"+e.bold(u.t("doctor.results_title"))+"\n");const M={pass:e.green("√"),warn:e.yellow("!"),fail:e.red("×")};for(const o of i)console.log(`${M[o.status]} ${o.name}`),o.message&&console.log(e.gray(` ${o.message}`));if(i.every(o=>"pass"===o.status)&&console.log("\n"+e.green.bold(u.t("doctor.all_good"))),!r.deep&&D.includes("claude-code")&&console.log(e.gray("\n"+u.t("doctor.deep_hint"))),r.report){const o=t(u.t("doctor.report_uploading")).start(),e=await N(function(o,e){const t={};for(const o of T()){if(o.hidden)continue;let e=null;try{e=p.detectCurrentConfig(o.name).apiKey?"has_key":"no_key"}catch{e="unreadable"}t[o.name]={installed:p.isToolInstalled(o.name),version:p.installedVersion(o.name),copies:o.installSpec?g(o.installSpec).map(o=>({kind:o.kind,version:o.version,path:o.path})):void 0,config:e}}const s=l.getProfile();return{checks:o,tools:t,settings:{base_url:l.getBaseUrl(),profile:l.getActiveProfileName(),profiles:l.listProfiles().length,key_fingerprint:l.getApiKeyFingerprint()||null,tool_keys:Object.keys(s.tool_api_keys??{}),models:s.models,tool_models:s.tool_models??{},tool_settings:s.tool_settings??{},lang:l.getLang()},client_config:e,env:{shell:process.env.SHELL??process.env.ComSpec??null,term:process.env.TERM_PROGRAM??null,proxies:K()},log:E()}}(i,{source:G.source??void 0,revision:G.revision,problem:G.problem}));e?o.succeed(u.t("doctor.report_done",{code:e})):o.fail(u.t("doctor.report_failed",{cli:O}))}else i.some(o=>"fail"===o.status)&&console.log(e.gray("\n"+u.t("doctor.report_hint",{cli:O})));i.some(o=>"fail"===o.status)&&(process.exitCode=1)}
1
+ import{refreshClientConfig as o}from"../lib/client-config-sync.js";import t from"chalk";import e from"ora";import{spawnSync as s}from"child_process";import{existsSync as r,readdirSync as n,readFileSync as a}from"fs";import{connect as i}from"net";import{join as c}from"path";import{configManager as l}from"../lib/config.js";import{savedApiKey as d}from"./base.js";import{toolManager as p}from"../lib/tool-manager.js";import{i18n as u}from"../lib/i18n.js";import{validateApiKey as m}from"../lib/api-validator.js";import{getAdapter as f}from"../lib/tools/registry.js";import{findInstalls as _,installLabel as g}from"../lib/tools/tool-installs.js";import{detectManagedOverrides as h}from"../lib/tools/claude-managed.js";import{codexAuthProblem as y,codexCatalogRejection as k,codexConfigPath as w,codexWorkModeOn as b}from"../lib/tools/codex.js";import{claudeAccountLoginPresent as v}from"../lib/tools/claude-code.js";import{toolHome as j}from"../lib/tools/types.js";import{gatewayAddresses as x,probeGatewayAddress as $}from"../lib/gateway-addresses.js";import{listAdapters as T}from"../lib/tools/registry.js";import{logger as A}from"../utils/logger.js";import{maskHome as P,maskSecrets as R,uploadReport as N}from"../lib/telemetry.js";import{CLI_NAME as O}from"../lib/brand.js";import{balanceLookupEnabled as C,balanceNeedsAttention as I,balanceText as H,fetchKeyBalances as L}from"../lib/key-balance.js";const S=["HTTPS_PROXY","https_proxy","HTTP_PROXY","http_proxy","ALL_PROXY","all_proxy"];function U(o,t,e=3e3){return new Promise(s=>{const r=i({host:o,port:t}),n=o=>{r.destroy(),s(o)};r.setTimeout(e,()=>n(!1)),r.once("connect",()=>n(!0)),r.once("error",()=>n(!1))})}function E(){const o=A.getLogDir();if(!r(o))return"";const t=n(o).filter(o=>/^\d{4}-\d{2}-\d{2}\.log$/.test(o)).sort().slice(-2).map(t=>`== ${t}\n`+a(c(o,t),"utf-8")).join("\n");return R(t.slice(-15e4))}function K(){const o={};for(const t of S){const e=process.env[t]?.trim();if(e)try{const s=new URL(e.includes("://")?e:`http://${e}`);o[t]=`${s.protocol}//${s.host}`}catch{o[t]="(unparsable)"}}return o}export async function doctorCommand(r={}){const n=e(u.t("doctor.checking")).start(),i=[],A=Number(process.versions.node.split(".")[0]);i.push({name:"Node.js",status:A>=20?"pass":"fail",message:`v${process.versions.node}`}),n.text=u.t("doctor.check_proxy"),i.push(await async function(){const o=u.t("doctor.proxy"),t=new Map;for(const o of S){const e=process.env[o]?.trim();e&&!t.has(e)&&t.set(e,o)}if(0===t.size)return{name:o,status:"pass",message:u.t("doctor.proxy_none")};const e=[];for(const[o,s]of t){let t;try{t=new URL(o.includes("://")?o:`http://${o}`)}catch{e.push(`${s}=${o}`);continue}const r=Number(t.port)||("https:"===t.protocol?443:t.protocol.startsWith("socks")?1080:80);await U(t.hostname,r)||e.push(`${s}=${o}`)}return 0===e.length?{name:o,status:"pass",message:[...t.keys()].join(", ")}:{name:o,status:"fail",message:u.t("doctor.proxy_dead",{proxies:e.join(", ")})}}()),n.text=u.t("doctor.check_api_key_network");const R=d(),B=u.t("doctor.api_key_network");if(R){const o=await m(R);o.valid?(i.push({name:B,status:"pass"}),n.text=u.t("doctor.check_balance"),i.push(...await async function(o){if(!C())return[];const t=l.listToolApiKeys().map(o=>({tool:o,key:l.getApiKeyForTool(o)})).filter(t=>Boolean(t.key)&&t.key!==o),e=await L([o,...t.map(o=>o.key)]),s=[{name:u.t("doctor.balance"),key:o},...t.map(o=>({name:u.t("doctor.balance_tool",{tool:f(o.tool)?.displayName??o.tool}),key:o.key}))],r=[];for(const o of s){const t=e.get(o.key);t&&r.push({name:o.name,status:I(t)?"warn":"pass",message:H(t)})}return r}(R))):"invalid_api_key"===o.error?i.push({name:B,status:"fail",message:u.t("doctor.api_key_invalid")}):(i.push({name:B,status:"fail",message:`${u.t("doctor.network_error")}: ${o.message??o.error}`}),n.text=u.t("doctor.check_other_addresses"),i.push(await async function(){const o=u.t("doctor.other_addresses"),t=l.getBaseUrl(),e=x().filter(o=>o.url!==t),s=d(),r=await Promise.all(e.map(o=>$(o.url,{apiKey:s}))),n=e.filter((o,t)=>r[t].ok).map(o=>o.url);return 0===n.length?{name:o,status:"fail",message:u.t("doctor.other_addresses_none")}:{name:o,status:"warn",message:u.t("doctor.other_addresses_found",{urls:n.join(", ")})}}()))}else i.push({name:B,status:"fail",message:u.t("doctor.api_key_missing")});n.text=u.t("doctor.check_client_config");const G=await o();i.push({name:u.t("doctor.client_config"),status:"cloud"===G.source||"cache"===G.source&&!G.problem?"pass":"warn",message:[G.source?u.t(`refresh.source.${G.source}`):u.t("refresh.source.none"),G.revision?u.t("doctor.client_config_revision",{revision:G.revision}):"",G.problem??""].filter(Boolean).join(" · ")}),n.text=u.t("doctor.check_tools");const D=p.getInstalledTools();i.push({name:u.t("doctor.installed_tools"),status:D.length>0?"pass":"warn",message:D.length>0?D.map(o=>f(o)?.displayName??o).join(u.t("setup.list_separator")):u.t("doctor.no_tools_installed")}),i.push(...function(){const o=[];for(const t of p.getInstalledTools()){const e=f(t);if(!e?.installSpec)continue;const s=_(e.installSpec);if(0===s.length)continue;const r=[],n=p.outdatedVersion(t);n&&r.push(u.t("doctor.tool_outdated",{min:n.min})),s.length>1&&r.push(u.t("doctor.tool_duplicates",{others:s.slice(1).map(g).join("、")})),o.push({name:e.displayName,status:r.length>0?"warn":"pass",message:[g(s[0]),...r,...r.length>0?[u.t("doctor.run_upgrade",{tool:t})]:[]].join("\n ")})}return o}());const q=function(){if(!p.isToolInstalled("claude-code"))return null;const o=u.t("doctor.claude_config"),t=h();if(t.length>0){const e=t.map(o=>`${o.source}: ${o.keys.join(", ")}`).join("; ");return{name:o,status:"fail",message:u.t("doctor.claude_managed",{detail:e})}}let e={};try{e=JSON.parse(a(c(process.env.CLAUDE_CONFIG_DIR?.trim()||c(j(),".claude"),"settings.json"),"utf-8")).env??{}}catch{}const s=l.getApiKeyForTool("claude-code");return e.ANTHROPIC_AUTH_TOKEN&&e.ANTHROPIC_BASE_URL?e.ANTHROPIC_BASE_URL!==l.getBaseUrl()||s&&e.ANTHROPIC_AUTH_TOKEN!==s?{name:o,status:"warn",message:u.t("doctor.claude_config_changed")}:{name:o,status:"pass"}:{name:o,status:"warn",message:u.t("doctor.claude_not_configured")}}();q&&i.push(q),D.includes("claude-code")&&v()&&i.push({name:u.t("doctor.claude_login"),status:"pass",message:u.t("tools.claude_code.account_login_overridden")});const F=D.includes("codex")?y():null;if(D.includes("codex")&&i.push({name:u.t("doctor.codex_auth"),status:F?"fail":"pass",message:F?u.t(`doctor.codex_${F}`,{path:P(w())}):void 0}),D.includes("codex")){const o=k();i.push({name:u.t("doctor.codex_catalog"),status:o?"fail":"pass",message:o?u.t("doctor.codex_catalog_rejected",{path:o.bin,version:o.version??"?",error:o.error}):void 0})}D.includes("codex")&&b()&&i.push({name:u.t("doctor.codex_work_mode"),status:"warn",message:u.t("tools.codex.work_mode_on")}),"win32"===process.platform&&D.includes("claude-code")&&!process.env.CLAUDE_CODE_GIT_BASH_PATH&&i.push({name:"Git for Windows",status:p.isGitInstalled()?"pass":"warn",message:p.isGitInstalled()?void 0:u.t("tools.claude_code.no_git_bash")}),r.deep&&D.includes("claude-code")&&(n.text=u.t("doctor.check_claude_request"),i.push(function(){const o=u.t("doctor.claude_request"),t=_(f("claude-code").installSpec)[0];if(!t)return{name:o,status:"warn",message:u.t("doctor.claude_request_skipped")};const e={encoding:"utf-8",timeout:12e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},r=["-p","Reply with the single word OK."],n=/\.cmd$/i.test(t.path)?s(`"${t.path}" ${r.map(o=>`"${o}"`).join(" ")}`,{...e,shell:!0}):s(t.path,r,e),a=`${n.stdout??""}`.trim();if(0===n.status&&a)return{name:o,status:"pass",message:a.slice(0,80)};const i=(`${n.stderr??""}`.trim()||a||n.error?.message||`exit ${n.status}`).slice(0,300);return{name:o,status:"fail",message:u.t("doctor.claude_request_failed",{reason:i})}}())),n.stop(),console.log("\n"+t.bold(u.t("doctor.results_title"))+"\n");const M={pass:t.green("√"),warn:t.yellow("!"),fail:t.red("×")};for(const o of i)console.log(`${M[o.status]} ${o.name}`),o.message&&console.log(t.gray(` ${o.message}`));if(i.every(o=>"pass"===o.status)&&console.log("\n"+t.green.bold(u.t("doctor.all_good"))),!r.deep&&D.includes("claude-code")&&console.log(t.gray("\n"+u.t("doctor.deep_hint"))),r.report){const o=e(u.t("doctor.report_uploading")).start(),t=await N(function(o,t){const e={};for(const o of T()){if(o.hidden)continue;let t=null;try{t=p.detectCurrentConfig(o.name).apiKey?"has_key":"no_key"}catch{t="unreadable"}e[o.name]={installed:p.isToolInstalled(o.name),version:p.installedVersion(o.name),copies:o.installSpec?_(o.installSpec).map(o=>({kind:o.kind,version:o.version,path:o.path})):void 0,config:t}}const s=l.getProfile();return{checks:o,tools:e,settings:{base_url:l.getBaseUrl(),profile:l.getActiveProfileName(),profiles:l.listProfiles().length,key_fingerprint:l.getApiKeyFingerprint()||null,tool_keys:Object.keys(s.tool_api_keys??{}),models:s.models,tool_models:s.tool_models??{},tool_settings:s.tool_settings??{},lang:l.getLang()},client_config:t,env:{shell:process.env.SHELL??process.env.ComSpec??null,term:process.env.TERM_PROGRAM??null,proxies:K()},log:E()}}(i,{source:G.source??void 0,revision:G.revision,problem:G.problem}));t?o.succeed(u.t("doctor.report_done",{code:t})):o.fail(u.t("doctor.report_failed",{cli:O}))}else i.some(o=>"fail"===o.status)&&console.log(t.gray("\n"+u.t("doctor.report_hint",{cli:O})));i.some(o=>"fail"===o.status)&&(process.exitCode=1)}
@@ -1 +1 @@
1
- import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as l}from"../lib/i18n.js";import{configManager as s}from"../lib/config.js";import{toolManager as a,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as d}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as p,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as _,EXIT_CODES as k}from"../lib/errors.js";import{emitJson as h,isColorEnabled as b,isDryRun as w,isJsonMode as v,isNonInteractive as x,shouldAutoConfirm as C}from"../lib/runtime-options.js";import{join as K}from"path";import{confirmWritePlan as j,printWritePlan as $,toolWritePlan as T}from"../lib/write-plan.js";import G from"inquirer";import{logger as N}from"../utils/logger.js";import{forgetInstalls as S}from"../lib/tools/tool-installs.js";import{CLI_NAME as M,brandEnv as E}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function I(o){const e=await d(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function O(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function A(e){console.log(o.green(e))}function L(e){console.log(o.yellow(e))}function D(e){console.error(o.red(e))}let F=null;function B(o){const e={operation:1,authentication:2,network:3};(!F||e[o]>e[F])&&(F=o)}async function R(e,t){v()||console.log(o.gray(l.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const a="zh_CN"===l.getLocale()?"<你的 Key>":"<your key>",n="--key"===e?`${M} setup --key ${a}`:`${M} setup ${e} ${a}`;let d;if("network_error"===i.error?(B("network"),d=_(l.t("setup.unreachable",{url:s.getBaseUrl(),reason:i.message||"network error"}),`${M} base auto`,"network_error")):"invalid_api_key"===i.error?(B("authentication"),d=y(l.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(B("operation"),d=g(l.t("setup.validate_failed",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),v())throw d;return D(d.message),console.log(o.gray(l.t("errors.next_step",{command:d.hint}))),!1}async function P(t,i,r={}){const{oneMillion:d,officialLogin:c,desktopRegistry:u,force:y}=r,_=n[t];try{"claude-desktop"===t&&void 0!==u&&s.setToolSetting("claude-desktop",f,u),"codex"===t&&void 0!==d&&s.setToolSetting("codex",p,d),"claude-desktop"===t&&void 0!==c&&s.setToolSetting("claude-desktop",m,!c),await a.applyPrivateConfig(t,i,s.getModelsForTool(t),{force:y})}catch(o){if(v())throw g(o instanceof Error?o.message:String(o),`${M} setup --key ${"zh_CN"===l.getLocale()?"<你的 Key>":"<your key>"}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return D("× "+l.t("setup.apply_failed",{tool:_.displayName,reason:e})),!1}return a.printApplied(t),y&&console.log(o.gray(" "+l.t("config.force_done",{tool:_.displayName,name:t}))),"codex"===t&&void 0!==d&&console.log(o.gray(" "+l.t(d?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!a.isToolInstalled(t)&&console.log(o.yellow(" ! "+l.t("setup.gui_preconfigured",{tool:_.displayName,install:_.installCommand}))),!0}function Y(o){return!e(o)?.isInstalled&&!a.isToolInstalled(o)}function q(o){L(l.t("setup.still_missing",{tools:o.map(o=>n[o].displayName).join(l.t("setup.list_separator")),commands:o.map(o=>`${M} config ${o} --yes`).join(l.t("setup.list_separator"))}))}function z(e,t,i=[]){const a=T(e),n=K(s.getConfigDir(),"config.yaml");if(v())h({dry_run:!0,tools:a,install_first:i,key_file:t?n:null});else{if(0===a.length&&0===i.length){const e=(b()?o.cyan:o=>o)(l.t("runtime.dry_run_label"));return void console.log(`${e} ${l.t("setup.dry_run_none")}`)}$(a,{label:l.t("runtime.dry_run_label"),keyFile:t?n:void 0,installFirst:i})}}function H(){return"darwin"===process.platform||"win32"===process.platform||a.isToolInstalled("claude-desktop")}export async function setupCommand(r){F=null;const d=r.key?.trim(),f=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),m=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return D(l.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const _=void 0!==r.desktopRegistry;let h;if(_&&(h=parseOnOff(r.desktopRegistry),void 0===h))return D(l.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||_,$=Boolean(d||f.length>0),T={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!$&&(m||b)&&w())return void z([...m?["codex"]:[],...b?["claude-desktop"]:[]],!1);if(!$&&(m||b)){if(m){const o=s.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;s.setToolSetting("codex",p,e);const t=await u(o);c(e,t??void 0),A(l.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){D(l.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else D(l.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=s.getApiKeyForTool("claude-desktop");o?await P("claude-desktop",o,{...T,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(D(l.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!$)return D(l.t("setup.usage")),void(process.exitCode=1);const B=w();B||await i(d||f[0].apiKey);const W=[],U=[];let J,Q=0,V=0;const X=new Set,Z=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of Z){if(!await R(o.label,o.apiKey)){V+=1;continue}const e=await I(o.apiKey);!e.probed||O(e,o.need)?(e.probed||L(l.t("setup.probe_failed",{label:o.label})),W.push({tool:o.tool,apiKey:o.apiKey,dedicated:!0}),X.add(o.tool)):(D(l.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),V+=1)}const oo=!!d&&await R("--key",d);d&&!oo&&(J=k[F??"operation"]);const eo=d&&oo?await I(d):void 0;if(d&&eo&&!eo.probed&&L(l.t("setup.probe_failed",{label:"--key"})),!(d&&eo&&eo.probed)||eo.hasClaude||eo.hasGpt||eo.hasGrok||eo.hasGemini||(D(l.t("setup.key_no_family")),J=1),d&&eo&&void 0===J){const o=[{tool:"claude-code",capable:eo.hasClaude,skipMsg:l.t(H()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:eo.hasGpt,skipMsg:l.t("setup.skip_no_gpt")},{tool:"grok",capable:eo.hasGrok,skipMsg:l.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:eo.hasClaude&&H(),skipMsg:"",quiet:!0},{tool:"agy",capable:eo.hasGemini,skipMsg:l.t("setup.skip_no_gemini")}];for(const e of o)X.has(e.tool)||(e.capable?(W.push({tool:e.tool,apiKey:d,dedicated:!1}),X.add(e.tool)):e.quiet||L(e.skipMsg))}const to=Boolean(d&&oo&&void 0===J);if(B)return z(W.filter(o=>!Y(o.tool)).map(o=>o.tool),W.length>0,W.filter(o=>Y(o.tool)).map(o=>o.tool)),void((V>0||void 0!==J)&&(process.exitCode=J??k[F??"operation"]));const io=W.filter(o=>!Y(o.tool)),lo=to||W.some(o=>o.dedicated);if((W.length>0||lo)&&!r.fromInstaller&&!await j(io.map(o=>o.tool),{keyFile:lo?K(s.getConfigDir(),"config.yaml"):void 0,installFirst:W.filter(o=>Y(o.tool)).map(o=>o.tool)}))return void(process.exitCode=k.cancelled);to&&d&&s.setApiKey(d);for(const o of W)o.dedicated&&s.setToolApiKey(o.tool,o.apiKey),Y(o.tool)?U.push({tool:o.tool,apiKey:o.apiKey}):await P(o.tool,o.apiKey,T)?Q+=1:(V+=1,X.delete(o.tool));if(void 0!==J)return U.length>0&&q(U.map(o=>o.tool)),void(process.exitCode=J);let so=[];if(U.length>0){const e=await async function(e,t,i){const s=e.map(o=>o.tool);if(0===s.length)return{still:[],applied:[],failed:[]};const r=s.map(o=>n[o].displayName).join(l.t("setup.list_separator"));let d=t;if(void 0!==d||v()||(C()?d=!x():process.stdin.isTTY&&(console.log(""),d=(await G.prompt([{type:"confirm",name:"go",message:l.t("setup.install_confirm",{tools:r}),default:!0}])).go)),!d){console.log("");for(const e of s)console.log(o.yellow("! "+l.t("setup.install_hint",{tool:n[e].displayName,install:n[e].installCommand})));return v()||console.log(o.gray(l.t("setup.install_all_hint",{cli:M}))),{still:s,applied:[],failed:[]}}const p=[];for(const e of s){console.log(o.bold(`\n${n[e].displayName}`));try{await a.installTool(e)}catch(o){N.logError(`setup: install ${e}`,o)}S(),a.isToolInstalled(e)||p.push(e)}const c=s.filter(o=>!p.includes(o));c.length>0&&console.log("");const u=[],f=[];for(const{tool:o,apiKey:t}of e.filter(o=>c.includes(o.tool)))await P(o,t,i)?u.push(o):f.push(o);return{still:p,applied:u,failed:f}}(U,r.install,T);so=e.still,Q+=e.applied.length,V+=e.failed.length;for(const o of[...so,...e.failed])X.delete(o)}if(Q>0){const t=[...X].filter(o=>!e(o)?.isInstalled&&!so.includes(o)),i=t.map(o=>n[o]?.command).filter(Boolean).join(" / "),s=l.t("setup.done",{count:String(Q)});A("\n"+(i?`${s}${l.t("setup.done_commands",{commands:i})}`:s)),so.length>0&&q(so);for(const o of t){const e=a.ensureNativeOnPath(o);e&&A(l.t("setup.path_added",{tool:n[o].displayName,dir:e}))}const r=t.filter(o=>!a.isOnPath(o));if(r.length>0&&!v()&&"1"!==E("PATH_HINT_BY_CALLER")){const e=r.map(o=>n[o].command).join(" / ");console.log(o.yellow(" ! "+l.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}0===Q&&so.length>0&&q(so),V>0&&(D(l.t("setup.failed_summary",{count:String(V)})),v()||console.error(`${M} setup --key ${"zh_CN"===l.getLocale()?"<你的 Key>":"<your key>"}`)),await t([...X]),(V>0||0===Q&&0===so.length)&&(process.exitCode=k[F??"operation"])}
1
+ import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as l}from"../lib/i18n.js";import{configManager as s}from"../lib/config.js";import{toolManager as a,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as d}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as p,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as _,EXIT_CODES as k}from"../lib/errors.js";import{emitJson as h,isColorEnabled as b,isDryRun as w,isJsonMode as v,isNonInteractive as x,shouldAutoConfirm as C}from"../lib/runtime-options.js";import{join as j}from"path";import{confirmWritePlan as K,printWritePlan as $,toolWritePlan as T}from"../lib/write-plan.js";import G from"inquirer";import{logger as S}from"../utils/logger.js";import{forgetInstalls as M}from"../lib/tools/tool-installs.js";import{CLI_NAME as N,brandEnv as E}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function I(o){const e=await d(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function O(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function A(e){console.log(o.green(e))}function D(e){console.log(o.yellow(e))}function F(e){console.error(o.red(e))}let B=null;function L(o){const e={operation:1,authentication:2,network:3};(!B||e[o]>e[B])&&(B=o)}async function R(e,t){v()||console.log(o.gray(l.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const a=l.t("errors.key_placeholder"),n="--key"===e?`${N} setup --key ${a}`:`${N} setup ${e} ${a}`;let d;if("network_error"===i.error?(L("network"),d=_(l.t("setup.unreachable",{url:s.getBaseUrl(),reason:i.message||"network error"}),`${N} base auto`,"network_error")):"invalid_api_key"===i.error?(L("authentication"),d=y(l.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(L("operation"),d=g(l.t("setup.validate_failed",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),v())throw d;return F(d.message),console.log(o.gray(l.t("errors.next_step",{command:d.hint}))),!1}async function P(t,i,r={}){const{oneMillion:d,officialLogin:c,desktopRegistry:u,force:y}=r,_=n[t];try{"claude-desktop"===t&&void 0!==u&&s.setToolSetting("claude-desktop",f,u),"codex"===t&&void 0!==d&&s.setToolSetting("codex",p,d),"claude-desktop"===t&&void 0!==c&&s.setToolSetting("claude-desktop",m,!c),await a.applyPrivateConfig(t,i,s.getModelsForTool(t),{force:y})}catch(o){if(v())throw g(o instanceof Error?o.message:String(o),`${N} setup --key ${l.t("errors.key_placeholder")}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return F("× "+l.t("setup.apply_failed",{tool:_.displayName,reason:e})),!1}return a.printApplied(t),y&&console.log(o.gray(" "+l.t("config.force_done",{tool:_.displayName,name:t}))),"codex"===t&&void 0!==d&&console.log(o.gray(" "+l.t(d?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!a.isToolInstalled(t)&&console.log(o.yellow(" ! "+l.t("setup.gui_preconfigured",{tool:_.displayName,install:_.installCommand}))),!0}function Y(o){return!e(o)?.isInstalled&&!a.isToolInstalled(o)}function q(o){D(l.t("setup.still_missing",{tools:o.map(o=>n[o].displayName).join(l.t("setup.list_separator")),commands:o.map(o=>`${N} config ${o} --yes`).join(l.t("setup.list_separator"))}))}function H(e,t,i=[]){const a=T(e),n=j(s.getConfigDir(),"config.yaml");if(v())h({dry_run:!0,tools:a,install_first:i,key_file:t?n:null});else{if(0===a.length&&0===i.length){const e=(b()?o.cyan:o=>o)(l.t("runtime.dry_run_label"));return void console.log(`${e} ${l.t("setup.dry_run_none")}`)}$(a,{label:l.t("runtime.dry_run_label"),keyFile:t?n:void 0,installFirst:i})}}function W(){return"darwin"===process.platform||"win32"===process.platform||a.isToolInstalled("claude-desktop")}export async function setupCommand(r){B=null;const d=r.key?.trim(),f=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),m=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return F(l.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const _=void 0!==r.desktopRegistry;let h;if(_&&(h=parseOnOff(r.desktopRegistry),void 0===h))return F(l.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||_,$=Boolean(d||f.length>0),T={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!$&&(m||b)&&w())return void H([...m?["codex"]:[],...b?["claude-desktop"]:[]],!1);if(!$&&(m||b)){if(m){const o=s.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;s.setToolSetting("codex",p,e);const t=await u(o);c(e,t??void 0),A(l.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){F(l.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else F(l.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=s.getApiKeyForTool("claude-desktop");o?await P("claude-desktop",o,{...T,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(F(l.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!$)return F(l.t("setup.usage")),void(process.exitCode=1);const L=w();L||await i(d||f[0].apiKey);const U=[],z=[];let J,Q=0,V=0;const X=new Set,Z=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of Z){if(!await R(o.label,o.apiKey)){V+=1;continue}const e=await I(o.apiKey);!e.probed||O(e,o.need)?(e.probed||D(l.t("setup.probe_failed",{label:o.label})),U.push({tool:o.tool,apiKey:o.apiKey,dedicated:!0}),X.add(o.tool)):(F(l.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),V+=1)}const oo=!!d&&await R("--key",d);d&&!oo&&(J=k[B??"operation"]);const eo=d&&oo?await I(d):void 0;if(d&&eo&&!eo.probed&&D(l.t("setup.probe_failed",{label:"--key"})),!(d&&eo&&eo.probed)||eo.hasClaude||eo.hasGpt||eo.hasGrok||eo.hasGemini||(F(l.t("setup.key_no_family")),J=1),d&&eo&&void 0===J){const o=[{tool:"claude-code",capable:eo.hasClaude,skipMsg:l.t(W()?"setup.skip_no_claude_desktop":"setup.skip_no_claude")},{tool:"codex",capable:eo.hasGpt,skipMsg:l.t("setup.skip_no_gpt")},{tool:"grok",capable:eo.hasGrok,skipMsg:l.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:eo.hasClaude&&W(),skipMsg:"",quiet:!0},{tool:"agy",capable:eo.hasGemini,skipMsg:l.t("setup.skip_no_gemini")}];for(const e of o)X.has(e.tool)||(e.capable?(U.push({tool:e.tool,apiKey:d,dedicated:!1}),X.add(e.tool)):e.quiet||D(e.skipMsg))}const to=Boolean(d&&oo&&void 0===J);if(L)return H(U.filter(o=>!Y(o.tool)).map(o=>o.tool),U.length>0,U.filter(o=>Y(o.tool)).map(o=>o.tool)),void((V>0||void 0!==J)&&(process.exitCode=J??k[B??"operation"]));const io=U.filter(o=>!Y(o.tool)),lo=to||U.some(o=>o.dedicated);if((U.length>0||lo)&&!r.fromInstaller&&!await K(io.map(o=>o.tool),{keyFile:lo?j(s.getConfigDir(),"config.yaml"):void 0,installFirst:U.filter(o=>Y(o.tool)).map(o=>o.tool)}))return void(process.exitCode=k.cancelled);to&&d&&s.setApiKey(d);for(const o of U)o.dedicated&&s.setToolApiKey(o.tool,o.apiKey),Y(o.tool)?z.push({tool:o.tool,apiKey:o.apiKey}):await P(o.tool,o.apiKey,T)?Q+=1:(V+=1,X.delete(o.tool));if(void 0!==J)return z.length>0&&q(z.map(o=>o.tool)),void(process.exitCode=J);let so=[];if(z.length>0){const e=await async function(e,t,i){const s=e.map(o=>o.tool);if(0===s.length)return{still:[],applied:[],failed:[]};const r=s.map(o=>n[o].displayName).join(l.t("setup.list_separator"));let d=t;if(void 0!==d||v()||(C()?d=!x():process.stdin.isTTY&&(console.log(""),d=(await G.prompt([{type:"confirm",name:"go",message:l.t("setup.install_confirm",{tools:r}),default:!0}])).go)),!d){console.log("");for(const e of s)console.log(o.yellow("! "+l.t("setup.install_hint",{tool:n[e].displayName,install:n[e].installCommand})));return v()||console.log(o.gray(l.t("setup.install_all_hint",{cli:N}))),{still:s,applied:[],failed:[]}}const p=[];for(const e of s){console.log(o.bold(`\n${n[e].displayName}`));try{await a.installTool(e)}catch(o){S.logError(`setup: install ${e}`,o)}M(),a.isToolInstalled(e)||p.push(e)}const c=s.filter(o=>!p.includes(o));c.length>0&&console.log("");const u=[],f=[];for(const{tool:o,apiKey:t}of e.filter(o=>c.includes(o.tool)))await P(o,t,i)?u.push(o):f.push(o);return{still:p,applied:u,failed:f}}(z,r.install,T);so=e.still,Q+=e.applied.length,V+=e.failed.length;for(const o of[...so,...e.failed])X.delete(o)}if(Q>0){const t=[...X].filter(o=>!e(o)?.isInstalled&&!so.includes(o)),i=t.map(o=>n[o]?.command).filter(Boolean).join(" / "),s=l.t("setup.done",{count:String(Q)});A("\n"+(i?`${s}${l.t("setup.done_commands",{commands:i})}`:s)),so.length>0&&q(so);for(const o of t){const e=a.ensureNativeOnPath(o);e&&A(l.t("setup.path_added",{tool:n[o].displayName,dir:e}))}const r=t.filter(o=>!a.isOnPath(o));if(r.length>0&&!v()&&"1"!==E("PATH_HINT_BY_CALLER")){const e=r.map(o=>n[o].command).join(" / ");console.log(o.yellow(" ! "+l.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}0===Q&&so.length>0&&q(so),V>0&&(F(l.t("setup.failed_summary",{count:String(V)})),v()||console.error(`${N} setup --key ${l.t("errors.key_placeholder")}`)),await t([...X]),(V>0||0===Q&&0===so.length)&&(process.exitCode=k[B??"operation"])}
@@ -1 +1 @@
1
- import{KEY_INFO_PATH as e}from"./gateway-protocol.js";import{logger as r}from"../utils/logger.js";import{configManager as t}from"./config.js";import{i18n as o}from"./i18n.js";import{rememberPublishedAddresses as a}from"./gateway-addresses.js";import{eligibleLists as n}from"./client-config.js";import{track as s}from"./telemetry.js";import{refreshClientConfig as i}from"./client-config-sync.js";const l=e=>new Promise(r=>setTimeout(r,e));async function c(e,r,a){const n=`${t.getBaseUrl()}/v1/models`,s=new AbortController,i=setTimeout(()=>s.abort(),r);try{const r=await a(n,{method:"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},signal:s.signal});if(401===r.status)return{valid:!1,error:"invalid_api_key",message:"API Key is invalid or expired"};if(r.ok){try{const e=await r.json();if(e&&"list"===e.object)return{valid:!0}}catch{return{valid:!0}}return{valid:!0}}return{valid:!1,error:"unknown_error",message:`HTTP ${r.status}: ${r.statusText}`}}catch(e){return e instanceof Error&&"AbortError"===e.name?{valid:!1,error:"network_error",message:"Request timeout"}:function(e){const r=e?.cause?.code;return"string"==typeof r&&u.has(r)}(e)?{valid:!1,error:"network_error",message:o.t("messages.certificate_intercepted",{url:n})}:{valid:!1,error:"network_error",message:e instanceof Error?e.message:"Network connection failed"}}finally{clearTimeout(i)}}const u=new Set(["DEPTH_ZERO_SELF_SIGNED_CERT","SELF_SIGNED_CERT_IN_CHAIN","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_UNTRUSTED","ERR_TLS_CERT_ALTNAME_INVALID"]);export async function fetchModels(e,o={}){const{timeoutMs:a=3e4,fetchFn:n=fetch}=o,s=`${t.getBaseUrl()}/v1/models`,i=new AbortController,l=setTimeout(()=>i.abort(),a);try{const r=await n(s,{method:"GET",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},signal:i.signal});if(!r.ok)return{ok:!1,models:[],error:`HTTP ${r.status}`};const t=await r.json();return{ok:!0,models:(Array.isArray(t?.data)?t.data:[]).map(e=>"string"==typeof e?e:e?.id).filter(e=>"string"==typeof e&&e.trim().length>0).map(e=>e.trim())}}catch(e){return r.logError("fetchModels",e),{ok:!1,models:[],error:e instanceof Error?e.message:"network error"}}finally{clearTimeout(l)}}function f(e){return e.filter(e=>!!e&&"object"==typeof e&&"string"==typeof e.name).map(e=>({name:e.name.trim(),..."string"==typeof e.labelOverride?{labelOverride:e.labelOverride}:{},..."boolean"==typeof e.supports1m?{supports1m:e.supports1m}:{}})).filter(e=>e.name.length>0)}export async function fetchGatewayStatus(e={}){const{timeoutMs:o=15e3,fetchFn:n=fetch}=e,s=`${t.getBaseUrl()}/api/status`,i=new AbortController,l=setTimeout(()=>i.abort(),o);try{const e=await n(s,{method:"GET",signal:i.signal});if(!e.ok)return{ok:!1,claudeDesktopGroupModels:{},error:`HTTP ${e.status}`};const r=await e.json();a(r?.data,t.getBaseUrl());let o=r?.data?.claude_desktop_group_models;if("string"==typeof o)try{o=JSON.parse(o)}catch{o=void 0}const l={};if(o&&"object"==typeof o&&!Array.isArray(o))for(const[e,r]of Object.entries(o))Array.isArray(r)&&(l[e]=f(r));return{ok:!0,claudeDesktopGroupModels:l}}catch(e){return r.logError("fetchGatewayStatus",e),{ok:!1,claudeDesktopGroupModels:{},error:e instanceof Error?e.message:"network error"}}finally{clearTimeout(l)}}export async function fetchKeyGroupInfo(o,a={}){const{timeoutMs:n=1e4,fetchFn:s=fetch}=a,i=`${t.getBaseUrl()}${e}`,l=new AbortController,c=setTimeout(()=>l.abort(),n);try{const e=await s(i,{method:"GET",headers:{Authorization:`Bearer ${o}`},signal:l.signal});if(!e.ok)return null;const r=await e.json(),t=r?.data;if(!t||"string"!=typeof t.group||!Array.isArray(t.claude_desktop_models))return null;const a=Array.isArray(t.groups)?t.groups.filter(e=>"string"==typeof e&&!!e):[];return{group:t.group,groups:a.length>0?a:[t.group],claudeDesktopModels:f(t.claude_desktop_models)}}catch(e){return r.logError("fetchKeyGroupInfo",e),null}finally{clearTimeout(c)}}export async function fetchClientModelConfig(e={}){const r=await i(e);return r.config?n(r.config.models):null}export async function validateApiKey(e,t={}){const o=Date.now(),a=await async function(e,t){const{timeoutMs:o=3e4,retries:a=2,backoffMs:n=500,fetchFn:s=fetch,sleepFn:i=l}=t;let u={valid:!1,error:"network_error",message:"Network connection failed"};for(let t=0;t<=a;t++){const l=await c(e,o,s);if(l.valid||"invalid_api_key"===l.error)return l.valid||r.logError("validateApiKey",new Error(l.message||"invalid_api_key")),l;u=l,t<a&&await i(n*Math.pow(2,t))}return r.logError("validateApiKey",new Error(u.message||"network_error")),u}(e,t);return s("validate-key",a.valid?"ok":"fail",{duration_ms:Date.now()-o,...a.valid?{}:{error:a.message??a.error,detail:{reason:a.error}}}),a}
1
+ import{KEY_INFO_PATH as r}from"./gateway-protocol.js";import{logger as e}from"../utils/logger.js";import{configManager as t}from"./config.js";import{i18n as o}from"./i18n.js";import{rememberPublishedAddresses as a}from"./gateway-addresses.js";import{eligibleLists as n}from"./client-config.js";import{track as s}from"./telemetry.js";import{refreshClientConfig as i}from"./client-config-sync.js";const l=r=>new Promise(e=>setTimeout(e,r));async function c(r,e,a){const n=`${t.getBaseUrl()}/v1/models`,s=new AbortController,i=setTimeout(()=>s.abort(),e);try{const e=await a(n,{method:"GET",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"},signal:s.signal});if(401===e.status)return{valid:!1,error:"invalid_api_key",message:o.t("validator.rejected")};if(e.ok){try{const r=await e.json();if(r&&"list"===r.object)return{valid:!0}}catch{return{valid:!0}}return{valid:!0}}return{valid:!1,error:"unknown_error",message:`HTTP ${e.status}: ${e.statusText}`}}catch(r){return r instanceof Error&&"AbortError"===r.name?{valid:!1,error:"network_error",message:o.t("validator.timeout")}:function(r){const e=r?.cause?.code;return"string"==typeof e&&u.has(e)}(r)?{valid:!1,error:"network_error",message:o.t("messages.certificate_intercepted",{url:n})}:{valid:!1,error:"network_error",message:r instanceof Error?r.message:o.t("validator.network")}}finally{clearTimeout(i)}}const u=new Set(["DEPTH_ZERO_SELF_SIGNED_CERT","SELF_SIGNED_CERT_IN_CHAIN","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_UNTRUSTED","ERR_TLS_CERT_ALTNAME_INVALID"]);export async function fetchModels(r,o={}){const{timeoutMs:a=3e4,fetchFn:n=fetch}=o,s=`${t.getBaseUrl()}/v1/models`,i=new AbortController,l=setTimeout(()=>i.abort(),a);try{const e=await n(s,{method:"GET",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"},signal:i.signal});if(!e.ok)return{ok:!1,models:[],error:`HTTP ${e.status}`};const t=await e.json();return{ok:!0,models:(Array.isArray(t?.data)?t.data:[]).map(r=>"string"==typeof r?r:r?.id).filter(r=>"string"==typeof r&&r.trim().length>0).map(r=>r.trim())}}catch(r){return e.logError("fetchModels",r),{ok:!1,models:[],error:r instanceof Error?r.message:"network error"}}finally{clearTimeout(l)}}function f(r){return r.filter(r=>!!r&&"object"==typeof r&&"string"==typeof r.name).map(r=>({name:r.name.trim(),..."string"==typeof r.labelOverride?{labelOverride:r.labelOverride}:{},..."boolean"==typeof r.supports1m?{supports1m:r.supports1m}:{}})).filter(r=>r.name.length>0)}export async function fetchGatewayStatus(r={}){const{timeoutMs:o=15e3,fetchFn:n=fetch}=r,s=`${t.getBaseUrl()}/api/status`,i=new AbortController,l=setTimeout(()=>i.abort(),o);try{const r=await n(s,{method:"GET",signal:i.signal});if(!r.ok)return{ok:!1,claudeDesktopGroupModels:{},error:`HTTP ${r.status}`};const e=await r.json();a(e?.data,t.getBaseUrl());let o=e?.data?.claude_desktop_group_models;if("string"==typeof o)try{o=JSON.parse(o)}catch{o=void 0}const l={};if(o&&"object"==typeof o&&!Array.isArray(o))for(const[r,e]of Object.entries(o))Array.isArray(e)&&(l[r]=f(e));return{ok:!0,claudeDesktopGroupModels:l}}catch(r){return e.logError("fetchGatewayStatus",r),{ok:!1,claudeDesktopGroupModels:{},error:r instanceof Error?r.message:"network error"}}finally{clearTimeout(l)}}export async function fetchKeyGroupInfo(o,a={}){const{timeoutMs:n=1e4,fetchFn:s=fetch}=a,i=`${t.getBaseUrl()}${r}`,l=new AbortController,c=setTimeout(()=>l.abort(),n);try{const r=await s(i,{method:"GET",headers:{Authorization:`Bearer ${o}`},signal:l.signal});if(!r.ok)return null;const e=await r.json(),t=e?.data;if(!t||"string"!=typeof t.group||!Array.isArray(t.claude_desktop_models))return null;const a=Array.isArray(t.groups)?t.groups.filter(r=>"string"==typeof r&&!!r):[];return{group:t.group,groups:a.length>0?a:[t.group],claudeDesktopModels:f(t.claude_desktop_models)}}catch(r){return e.logError("fetchKeyGroupInfo",r),null}finally{clearTimeout(c)}}export async function fetchClientModelConfig(r={}){const e=await i(r);return e.config?n(e.config.models):null}export async function validateApiKey(r,t={}){const a=Date.now(),n=await async function(r,t){const{timeoutMs:a=3e4,retries:n=2,backoffMs:s=500,fetchFn:i=fetch,sleepFn:u=l}=t;let f={valid:!1,error:"network_error",message:o.t("validator.network")};for(let t=0;t<=n;t++){const o=await c(r,a,i);if(o.valid||"invalid_api_key"===o.error)return o.valid||e.logError("validateApiKey",new Error(o.message||"invalid_api_key")),o;f=o,t<n&&await u(s*Math.pow(2,t))}return e.logError("validateApiKey",new Error(f.message||"network_error")),f}(r,t);return s("validate-key",n.valid?"ok":"fail",{duration_ms:Date.now()-a,...n.valid?{}:{error:n.message??n.error,detail:{reason:n.error}}}),n}