claude360 0.2.8 → 0.3.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.
- package/README.md +107 -126
- package/bin/claude360.js +7 -3
- package/package.json +1 -1
- package/src/account-status.js +8 -5
- package/src/auth.js +9 -2
- package/src/banner.js +47 -6
- package/src/cc-switch.js +34 -6
- package/src/colors.js +31 -0
- package/src/diagnostics.js +68 -25
- package/src/glyphs.js +33 -0
- package/src/index.js +248 -105
- package/src/init-config.js +61 -27
- package/src/init-flow.js +25 -6
- package/src/mcp-skill.js +48 -21
- package/src/menu.js +20 -13
- package/src/messages.js +78 -0
- package/src/notices.js +33 -0
- package/src/onboarding.js +12 -5
- package/src/prompts.js +7 -6
- package/src/token-manager.js +90 -20
- package/src/tool-installer.js +25 -9
- package/src/tool-launcher.js +150 -46
- package/src/topup.js +55 -5
- package/src/ui.js +264 -8
- package/src/workflows.js +10 -7
- package/src/zcf-notice.js +15 -1
package/README.md
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
# Claude360 CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://nodejs.org/)
|
|
4
|
+
[]()
|
|
5
|
+
[]()
|
|
6
|
+
|
|
7
|
+
面向 [Claude360](https://claude360.xyz) 已注册用户的跨平台命令行工具,让不熟悉终端配置的用户也能一行命令完成 **Claude Code / Codex** 的安装、授权、Key 选择、余额查询、微信扫码充值与日常启动。
|
|
4
8
|
|
|
5
9
|
- 不要求用户在终端输入站点账号密码,授权全程在浏览器完成。
|
|
6
10
|
- 不修改 shell profile / PowerShell profile / 全局环境变量。
|
|
7
|
-
- 分组倍率、充值金额、API
|
|
11
|
+
- 分组倍率、充值金额、API 凭证生命周期均以后端为唯一来源,CLI 不内置任何业务口径。
|
|
12
|
+
- 全部交互文字采用**分层语义配色**,自动适配 truecolor / 256 色 / 无色终端。
|
|
13
|
+
|
|
14
|
+
> 本仓库仅包含 **CLI 客户端**(Node.js)。其依赖的 `/api/cli/*` 后端接口由 Claude360 服务端提供,**不在本仓库内**。
|
|
8
15
|
|
|
9
16
|
## 目录
|
|
10
17
|
|
|
@@ -13,14 +20,14 @@
|
|
|
13
20
|
- [快速开始](#快速开始)
|
|
14
21
|
- [首次配置流程](#首次配置流程)
|
|
15
22
|
- [日常使用](#日常使用)
|
|
23
|
+
- [终端配色体系](#终端配色体系)
|
|
16
24
|
- [本地配置](#本地配置)
|
|
17
|
-
- [
|
|
25
|
+
- [后端接口契约](#后端接口契约)
|
|
18
26
|
- [Claude Code 与 Codex 集成](#claude-code-与-codex-集成)
|
|
19
27
|
- [诊断与故障排查](#诊断与故障排查)
|
|
20
28
|
- [开发与测试](#开发与测试)
|
|
21
29
|
- [项目结构](#项目结构)
|
|
22
30
|
- [安全模型](#安全模型)
|
|
23
|
-
- [已知风险与路线图](#已知风险与路线图)
|
|
24
31
|
- [致谢](#致谢)
|
|
25
32
|
- [许可证](#许可证)
|
|
26
33
|
|
|
@@ -30,20 +37,22 @@
|
|
|
30
37
|
| --- | --- |
|
|
31
38
|
| 一行命令安装 | Windows PowerShell / macOS / Linux bash 一行命令拉起 bootstrap,自动检测 Node/npm 与全局 npm 权限 |
|
|
32
39
|
| 方向键交互 | 全部菜单 / 选择 / 确认使用方向键导航(↑↓ 移动、Enter 确认、Esc 返回、空格多选、←→ 切换 YES/NO),非 TTY / CI 环境自动降级为编号输入 |
|
|
40
|
+
| 分层语义配色 | 成功 / 失败 / 警告 / 信息 / 步骤 / 键值回显 / 路径 / 标题等按角色着色,层次分明;自动适配 truecolor / 256 色 / `NO_COLOR` |
|
|
33
41
|
| 真实模型选择 | 模型列表来自 `GET /api/cli/models`(用户可用分组 × 模型元数据),展示模型 ID / 名称 / 标签 / 说明,保存真实 model id |
|
|
34
42
|
| 浏览器设备授权 | 通过 `/api/cli/auth/*` 设备码流程换取受限 CLI 凭证,不接触账号密码 |
|
|
35
43
|
| API Key 选择/创建 | 已有 Key 列表展示并选择;无 Key 时按后端分组倍率向导创建 |
|
|
36
44
|
| 余额与分组展示 | 日常主菜单展示账户余额、当前 Key、当前分组与倍率(来自后端) |
|
|
37
45
|
| 微信 Native 扫码充值 | 终端内渲染二维码;金额选项与最低充值额由后端返回,CLI 不内置 |
|
|
38
46
|
| 启动 Claude Code | 自动注入 `ANTHROPIC_BASE_URL` 和 `ANTHROPIC_AUTH_TOKEN`,以子进程启动 |
|
|
39
|
-
| 启动 Codex | 写入隔离的
|
|
47
|
+
| 启动 Codex | 写入隔离的 Claude360 provider / profile 覆盖层配置,并以 `codex --profile claude360` 启动 |
|
|
40
48
|
| 工具更新 | 菜单内更新 `claude360` 自身、Claude Code、Codex,全部需要二次确认 |
|
|
41
|
-
| 一键完整初始化 |
|
|
49
|
+
| 一键完整初始化 | 登录、Key、安装/更新、API 注入、输出语言、提示词风格、工作流、MCP、模型、权限配置、连接测试、启动一站式向导 |
|
|
42
50
|
| 推荐工作流 / Skill | 六步工作流、Git 指令、功能规划 UX、BMad 安装器等,写入 `~/.claude/commands/claude360/` 与 `~/.codex/prompts/`,写前备份、冲突二次确认 |
|
|
43
51
|
| 推荐 MCP | Context7 / Open Web Search / Spec 工作流 / DeepWiki / Playwright / Exa / Serena,多选安装、重依赖单独确认、同名去重 |
|
|
44
52
|
| AI 输出语言 / 提示词风格 | 写入 `~/.claude/CLAUDE.md` 或 `~/.codex/AGENTS.md` 的 Claude360 标记区块,不覆盖用户内容 |
|
|
45
53
|
| 配置备份 | 所有写入用户工具配置的操作先备份到 `~/.claude/backup/` 或 `~/.codex/backup/` 时间戳目录 |
|
|
46
|
-
| 诊断报告 | OS/Node/npm/全局 npm 权限/工具版本/连通性/授权状态/余额/Key
|
|
54
|
+
| 诊断报告 | OS/Node/npm/全局 npm 权限/工具版本/连通性/授权状态/余额/Key/支付端点一站式检查,按模块分组着色表格展示 |
|
|
55
|
+
| cc-switch 配置生成 | 生成可导入 [cc-switch](https://github.com/farion1231/cc-switch) 的供应商配置,支持完整 / 脱敏预览与本地保存(0600) |
|
|
47
56
|
|
|
48
57
|
## 系统要求
|
|
49
58
|
|
|
@@ -55,33 +64,40 @@
|
|
|
55
64
|
|
|
56
65
|
## 快速开始
|
|
57
66
|
|
|
58
|
-
###
|
|
67
|
+
### 一行命令安装(推荐)
|
|
68
|
+
|
|
69
|
+
macOS / Linux:
|
|
59
70
|
|
|
60
71
|
```bash
|
|
61
72
|
curl -fsSL https://claude360.xyz/install.sh | bash
|
|
62
73
|
```
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
Windows PowerShell:
|
|
65
76
|
|
|
66
77
|
```powershell
|
|
67
78
|
irm https://claude360.xyz/install.ps1 | iex
|
|
68
79
|
```
|
|
69
80
|
|
|
70
|
-
Bootstrap
|
|
81
|
+
Bootstrap 脚本职责:识别 OS / 架构 → 检查 Node.js 与 npm(缺失或 < 18 直接退出并给出修复建议)→ 展示影响范围并要求确认 → `npm install -g claude360@latest` → `claude360 setup` 进入首次配置向导。
|
|
71
82
|
|
|
72
|
-
|
|
73
|
-
2. 检查 Node.js 与 npm(缺失或 < 18 直接退出并给出修复建议)。
|
|
74
|
-
3. 展示影响范围并要求确认。
|
|
75
|
-
4. 执行 `npm install -g claude360@latest`。
|
|
76
|
-
5. 执行 `claude360 setup` 进入首次配置向导。
|
|
77
|
-
|
|
78
|
-
### 手动安装
|
|
83
|
+
### 通过 npm 全局安装
|
|
79
84
|
|
|
80
85
|
```bash
|
|
81
86
|
npm install -g claude360@latest
|
|
82
87
|
claude360
|
|
83
88
|
```
|
|
84
89
|
|
|
90
|
+
### 从源码运行(开发者)
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
git clone https://github.com/Johnhpure/claude360cli.git
|
|
94
|
+
cd claude360cli
|
|
95
|
+
npm install
|
|
96
|
+
node ./bin/claude360.js # 直接以源码模式运行
|
|
97
|
+
# 或链接到全局命令:
|
|
98
|
+
npm link && claude360
|
|
99
|
+
```
|
|
100
|
+
|
|
85
101
|
## 首次配置流程
|
|
86
102
|
|
|
87
103
|
```
|
|
@@ -115,7 +131,7 @@ claude360
|
|
|
115
131
|
|
|
116
132
|
## 日常使用
|
|
117
133
|
|
|
118
|
-
主菜单按分组展示,TTY 环境下用 **方向键 + Enter** 选择(Esc 返回);非 TTY / CI
|
|
134
|
+
主菜单按分组展示,TTY 环境下用 **方向键 + Enter** 选择(Esc 返回);非 TTY / CI 环境自动降级为编号输入:
|
|
119
135
|
|
|
120
136
|
```
|
|
121
137
|
请选择功能:
|
|
@@ -140,18 +156,34 @@ claude360
|
|
|
140
156
|
退出 退出 claude360 CLI
|
|
141
157
|
```
|
|
142
158
|
|
|
143
|
-
- **余额与充值**:调用 `GET /api/cli/me
|
|
144
|
-
- **启动 Claude Code
|
|
145
|
-
- **启动 Codex**:写入 `~/.codex/config.toml`
|
|
159
|
+
- **余额与充值**:调用 `GET /api/cli/me` 展示账号、余额、已用、当前 Key 名称与分组;充值先取 `/api/cli/topup/options`,按后端校验通过的金额或最低额提交,再用 `qrcode-terminal` 在终端渲染 `code_url`,渲染失败时降级为纯文本 URL。轮询订单状态,支付完成自动刷新余额。
|
|
160
|
+
- **启动 Claude Code**:以 `claude` 子进程启动,并通过 `ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` 注入。
|
|
161
|
+
- **启动 Codex**:写入 `~/.codex/config.toml` 的 `[model_providers.claude360]` 与 profile 覆盖层 `~/.codex/claude360.config.toml`,发现冲突字段会先要求用户确认再覆盖,然后 `codex --profile claude360`,并通过 `CLAUDE360_API_KEY` 注入。
|
|
146
162
|
- **安装或更新工具**:三选一菜单(仅 Claude Code / 仅 Codex / 两者),每步都需要确认。
|
|
147
163
|
- **切换 Key / 模型**:重新进入 Token 向导,或从 `/api/cli/models` 拉取真实模型列表选择默认模型。
|
|
148
|
-
|
|
164
|
+
|
|
165
|
+
## 终端配色体系
|
|
166
|
+
|
|
167
|
+
CLI 的全部行内交互文字通过统一的语义消息层(`src/messages.js`)输出,每种角色有专属颜色与符号前缀,形成清晰层级;色值集中在 `src/colors.js` 的单一主题中:
|
|
168
|
+
|
|
169
|
+
| 角色 | 符号 | 颜色 | 用途 |
|
|
170
|
+
| --- | --- | --- | --- |
|
|
171
|
+
| success | `✓` | 绿 | 操作成功 |
|
|
172
|
+
| error | `×` | 红 | 失败 / 异常 |
|
|
173
|
+
| warn | `!` | 黄 | 警告 / 降级 |
|
|
174
|
+
| step | `→` | 紫 | 进行中 / 步骤 |
|
|
175
|
+
| info | — | 天蓝 | 中性信息 |
|
|
176
|
+
| result | — | 灰蓝标签 + 亮白值 | 键值回显 |
|
|
177
|
+
| path / hint | — | 灰阶 | 路径 / 次要说明 |
|
|
178
|
+
| title / heading | — | 白 / 亮青(加粗) | 标题 |
|
|
179
|
+
|
|
180
|
+
着色能力自动探测:truecolor(24-bit)→ 256 色(量化)→ 无色。设置环境变量 `NO_COLOR=1` 可强制关闭颜色,`FORCE_COLOR=2` 可强制真彩色;非 TTY / 管道 / CI 输出默认为纯文本(不含 ANSI 序列),保证可被脚本解析。
|
|
149
181
|
|
|
150
182
|
## 本地配置
|
|
151
183
|
|
|
152
184
|
| 平台 | 路径 |
|
|
153
185
|
| --- | --- |
|
|
154
|
-
| macOS / Linux | `~/.claude360/config.json
|
|
186
|
+
| macOS / Linux | `~/.claude360/config.json`(权限 `0600`) |
|
|
155
187
|
| Windows | `%USERPROFILE%\.claude360\config.json` |
|
|
156
188
|
|
|
157
189
|
示例:
|
|
@@ -169,36 +201,35 @@ claude360
|
|
|
169
201
|
|
|
170
202
|
注意事项:
|
|
171
203
|
|
|
172
|
-
-
|
|
204
|
+
- 当前版本接受**本地明文**保存 `cliToken` 与 `apiKey`,CLI 仅收紧文件权限,不接入系统密钥链。
|
|
173
205
|
- CLI 日志与诊断输出会脱敏 API Key。
|
|
174
206
|
- 若需要重置,删除 `~/.claude360/config.json` 即可触发完整重新授权。
|
|
175
207
|
|
|
176
|
-
##
|
|
208
|
+
## 后端接口契约
|
|
177
209
|
|
|
178
|
-
CLI 仅依赖一组隔离的 `/api/cli`
|
|
210
|
+
CLI 仅依赖一组隔离的 `/api/cli` 接口(由 Claude360 服务端提供,**后端代码不在本仓库**):
|
|
179
211
|
|
|
180
212
|
| 方法 | 路径 | 说明 |
|
|
181
213
|
| --- | --- | --- |
|
|
182
214
|
| POST | `/api/cli/auth/start` | 创建设备码授权会话 |
|
|
183
215
|
| POST | `/api/cli/auth/confirm` | 浏览器端登录用户确认授权(站点 Web Session) |
|
|
184
|
-
| POST | `/api/cli/auth/poll` | CLI
|
|
216
|
+
| POST | `/api/cli/auth/poll` | CLI 轮询授权结果:`pending` / `approved` / `denied` / `expired` / `consumed` |
|
|
185
217
|
| GET | `/api/cli/me` | 返回当前用户、分组、余额、已用额度、展示单位 |
|
|
186
218
|
| GET | `/api/cli/tokens` | 当前用户 Key 列表(脱敏) |
|
|
187
219
|
| POST | `/api/cli/tokens/:id/reveal` | 校验归属并返回明文 Key,被限频且禁用缓存 |
|
|
188
|
-
| POST | `/api/cli/tokens` | 按分组创建新 Key
|
|
220
|
+
| POST | `/api/cli/tokens` | 按分组创建新 Key |
|
|
189
221
|
| GET | `/api/cli/groups` | 用户可用分组(含 `display_name`、`ratio`、`description`) |
|
|
190
|
-
| GET | `/api/cli/models` | 当前用户可用模型列表(含 `display_name`、`tags`、`description`、`recommended
|
|
222
|
+
| GET | `/api/cli/models` | 当前用户可用模型列表(含 `display_name`、`tags`、`description`、`recommended`) |
|
|
191
223
|
| GET | `/api/cli/topup/options` | 后端配置的充值金额选项与最低额,包含 WeChat 启用状态 |
|
|
192
224
|
| POST | `/api/cli/topup/wechat` | 创建微信 Native 订单,返回 `code_url`、`order_id`、`pay_money` |
|
|
193
|
-
| GET | `/api/cli/topup
|
|
225
|
+
| GET | `/api/cli/topup/order?order_id=` | 查询订单状态(仅订单所属用户) |
|
|
194
226
|
|
|
195
|
-
|
|
227
|
+
契约要点:
|
|
196
228
|
|
|
197
229
|
- 设备码、user_code、CLI 凭证均有过期机制;CLI 凭证可后台吊销。
|
|
198
|
-
- 已批准会话被消费后保持 `consumed
|
|
230
|
+
- 已批准会话被消费后保持 `consumed`,CLI 凭证有独立有效期,设备码窗口过期不影响已发出的凭证。
|
|
199
231
|
- Key reveal 强制鉴权 + 限频;后端日志不记录明文 Key。
|
|
200
232
|
- 充值订单仅订单所属用户可查询。
|
|
201
|
-
- 详细字段格式见 `prd/claude360-cli-prd.md` 第 7 章。
|
|
202
233
|
|
|
203
234
|
## Claude Code 与 Codex 集成
|
|
204
235
|
|
|
@@ -215,17 +246,15 @@ ANTHROPIC_AUTH_TOKEN=<selected_api_key>
|
|
|
215
246
|
|
|
216
247
|
### Codex
|
|
217
248
|
|
|
218
|
-
写入 `~/.codex/config.toml`(仅修改 `model_providers.claude360
|
|
249
|
+
写入 `~/.codex/config.toml`(仅修改 `model_providers.claude360`,不动其他 provider),模型等覆盖项写入隔离的 profile 覆盖层 `~/.codex/claude360.config.toml`:
|
|
219
250
|
|
|
220
251
|
```toml
|
|
252
|
+
# ~/.codex/config.toml
|
|
221
253
|
[model_providers.claude360]
|
|
222
254
|
name = "Claude360"
|
|
223
255
|
base_url = "https://claude360.xyz/v1"
|
|
224
256
|
env_key = "CLAUDE360_API_KEY"
|
|
225
257
|
wire_api = "responses"
|
|
226
|
-
|
|
227
|
-
[profiles.claude360]
|
|
228
|
-
model_provider = "claude360"
|
|
229
258
|
```
|
|
230
259
|
|
|
231
260
|
启动命令:
|
|
@@ -236,22 +265,11 @@ codex --profile claude360
|
|
|
236
265
|
|
|
237
266
|
并通过子进程环境变量 `CLAUDE360_API_KEY=<selected_api_key>` 注入凭证。
|
|
238
267
|
|
|
239
|
-
>
|
|
268
|
+
> **风险说明**:Codex 自定义 provider 使用 Responses 协议(`wire_api = "responses"`)。后端网关必须支持 `/v1/responses` 或在网关层将 Responses 请求适配到现有模型能力,否则 Codex 调用会失败。
|
|
240
269
|
|
|
241
270
|
## 诊断与故障排查
|
|
242
271
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
- 操作系统与架构。
|
|
246
|
-
- 终端二维码渲染能力。
|
|
247
|
-
- Node.js / npm 版本。
|
|
248
|
-
- 全局 npm 安装权限。
|
|
249
|
-
- Claude Code / Codex 是否安装及版本。
|
|
250
|
-
- `https://claude360.xyz` API 连通性。
|
|
251
|
-
- CLI 授权状态、账户余额、Key 列表拉取状态。
|
|
252
|
-
- 微信支付端点可用性。
|
|
253
|
-
|
|
254
|
-
常见异常及处理建议:
|
|
272
|
+
主菜单“诊断与修复”会汇报:操作系统与架构、终端二维码渲染能力、Node.js / npm 版本、全局 npm 安装权限、Claude Code / Codex 安装与版本、API 连通性、CLI 授权状态、账户余额、Key 列表拉取状态、微信支付端点可用性。报告以分组着色表格展示,状态用绿 ✓ / 黄 ! / 红 × 区分,失败项附修复建议。
|
|
255
273
|
|
|
256
274
|
| 现象 | 处理 |
|
|
257
275
|
| --- | --- |
|
|
@@ -266,123 +284,86 @@ codex --profile claude360
|
|
|
266
284
|
|
|
267
285
|
## 开发与测试
|
|
268
286
|
|
|
269
|
-
项目使用 Node 内置 test runner
|
|
270
|
-
|
|
271
|
-
```bash
|
|
272
|
-
# 进入 CLI 包
|
|
273
|
-
cd claude360-cli
|
|
274
|
-
|
|
275
|
-
# 安装依赖(qrcode-terminal、smol-toml)
|
|
276
|
-
npm install
|
|
277
|
-
|
|
278
|
-
# 跑全部测试
|
|
279
|
-
npm test
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
期望结果:全部测试通过。
|
|
283
|
-
|
|
284
|
-
后端 Go 测试(在仓库根目录执行):
|
|
287
|
+
项目使用 Node 内置 test runner,不引入额外测试框架。
|
|
285
288
|
|
|
286
289
|
```bash
|
|
287
|
-
|
|
290
|
+
npm install # 安装依赖(@inquirer/core、qrcode-terminal、smol-toml)
|
|
291
|
+
npm test # 跑全部测试(26 个测试文件 / 232 个用例)
|
|
292
|
+
npm test messages # 只跑某个测试文件(test/messages.test.js)
|
|
288
293
|
```
|
|
289
294
|
|
|
290
|
-
|
|
295
|
+
调试入口:
|
|
291
296
|
|
|
292
297
|
```bash
|
|
293
|
-
#
|
|
294
|
-
|
|
298
|
+
node ./bin/claude360.js # 源码模式运行
|
|
299
|
+
npm link && claude360 # 链接到全局命令
|
|
295
300
|
```
|
|
296
301
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
cd claude360-cli && npm link
|
|
301
|
-
claude360
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
调试时可注入自定义提示器、API client、浏览器打开函数等:`src/index.js` 中 `runCli({...})` 全部依赖均可注入,便于自动化测试和插桩。
|
|
302
|
+
`src/index.js` 的 `runCli({...})` 全部依赖(提示器、API client、浏览器打开函数、`writeLine`、`execCommand` 等)均可注入,便于自动化测试与插桩。
|
|
305
303
|
|
|
306
304
|
## 项目结构
|
|
307
305
|
|
|
308
306
|
```
|
|
309
|
-
|
|
307
|
+
claude360cli/
|
|
310
308
|
├── bin/
|
|
311
309
|
│ └── claude360.js # CLI 入口
|
|
312
310
|
├── install/
|
|
313
311
|
│ ├── install.sh # macOS / Linux bootstrap
|
|
314
312
|
│ ├── install.ps1 # Windows PowerShell bootstrap
|
|
315
313
|
│ └── verification-matrix.md
|
|
316
|
-
├── scripts/
|
|
314
|
+
├── scripts/
|
|
315
|
+
│ └── test.js # 测试运行器(node --test 包装)
|
|
317
316
|
├── src/
|
|
318
|
-
│ ├── api-client.js # HTTP + NewAPI 信封解析
|
|
319
|
-
│ ├── auth.js # 设备码授权流程
|
|
320
|
-
│ ├── config-store.js # 本地配置读写(0600)
|
|
321
|
-
│ ├── diagnostics.js # 诊断报告
|
|
322
|
-
│ ├── group-manager.js # 分组与倍率展示(无本地映射)
|
|
323
317
|
│ ├── index.js # 顶层编排:环境检查 → 工具引导 → 授权 → Key → 主菜单
|
|
324
|
-
│ ├──
|
|
325
|
-
│ ├──
|
|
318
|
+
│ ├── colors.js # 色彩能力探测 + 单一语义主题(PALETTE / theme)
|
|
319
|
+
│ ├── messages.js # 语义消息层(formatMessage / createMessenger)
|
|
320
|
+
│ ├── banner.js # 品牌横幅与流光动效、环境检查行
|
|
321
|
+
│ ├── menu.js # 首次 / 日常菜单渲染与选择
|
|
322
|
+
│ ├── prompts.js # 方向键单选 / 多选 / 确认(@inquirer/core)+ 降级输入
|
|
323
|
+
│ ├── ui.js # 表格 / 标题 / 信息盒子等结构化渲染
|
|
324
|
+
│ ├── api-client.js # HTTP + 后端信封解析
|
|
325
|
+
│ ├── auth.js # 设备码授权流程
|
|
326
326
|
│ ├── token-manager.js # Key 选择 / 创建 / reveal
|
|
327
|
+
│ ├── account-status.js # 主菜单账户状态面板
|
|
328
|
+
│ ├── topup.js # 微信 Native 充值流程
|
|
329
|
+
│ ├── diagnostics.js # 诊断报告
|
|
330
|
+
│ ├── init-config.js # 输出语言 / 提示词风格 / 默认模型 / 权限写入
|
|
331
|
+
│ ├── init-flow.js # 一键完整初始化编排
|
|
332
|
+
│ ├── mcp-skill.js # 推荐 MCP / Skill / AGENTS 安装
|
|
333
|
+
│ ├── workflows.js # 推荐工作流安装
|
|
327
334
|
│ ├── tool-installer.js # 全局 npm 安装 / 更新(需确认)
|
|
328
335
|
│ ├── tool-launcher.js # Claude Code / Codex 子进程启动与配置写入
|
|
329
|
-
│
|
|
330
|
-
├──
|
|
336
|
+
│ ├── cc-switch.js # cc-switch 供应商配置生成
|
|
337
|
+
│ ├── config-store.js # 本地配置读写(0600)
|
|
338
|
+
│ ├── group-manager.js # 分组与倍率展示(无本地映射)
|
|
339
|
+
│ ├── backup.js # 写入前时间戳备份
|
|
340
|
+
│ ├── sanitize.js # 输出脱敏(Key / 错误信息)
|
|
341
|
+
│ ├── onboarding.js # 环境检查与工具安装引导
|
|
342
|
+
│ ├── platform.js # 平台路径与能力探测
|
|
343
|
+
│ └── zcf-notice.js # 开源参考声明
|
|
344
|
+
├── test/ # 26 个测试文件(与 src 一一对应)
|
|
331
345
|
├── package.json
|
|
332
346
|
└── README.md
|
|
333
347
|
```
|
|
334
348
|
|
|
335
|
-
后端配套文件(位于仓库根目录):
|
|
336
|
-
|
|
337
|
-
```
|
|
338
|
-
controller/cli.go # /api/cli/* handler
|
|
339
|
-
controller/cli_test.go
|
|
340
|
-
middleware/cli_auth.go # CLI bearer 中间件
|
|
341
|
-
middleware/cli_auth_test.go
|
|
342
|
-
model/cli_auth.go # CliAuthSession 模型
|
|
343
|
-
model/cli_auth_test.go
|
|
344
|
-
model/topup.go # 新增 GetUserTopUpByTradeNo
|
|
345
|
-
model/main.go # 增加 CliAuthSession AutoMigrate
|
|
346
|
-
router/api-router.go # 注册 /api/cli/* 路由
|
|
347
|
-
web/src/pages/CliAuthorize/ # 浏览器授权页
|
|
348
|
-
```
|
|
349
|
-
|
|
350
349
|
## 安全模型
|
|
351
350
|
|
|
352
351
|
- CLI 不接收、不保存站点账号密码。
|
|
353
352
|
- 设备码、user_code、CLI 凭证均短期有效;CLI 凭证可后台吊销。
|
|
354
|
-
-
|
|
355
|
-
-
|
|
356
|
-
- 后端日志不记录明文 Key;CLI 日志不打印完整 Key。
|
|
353
|
+
- 授权轮询限频;`POST /api/cli/tokens/:id/reveal` 强制鉴权 + 限频 + 禁用缓存。
|
|
354
|
+
- 后端日志不记录明文 Key;CLI 日志不打印完整 Key(统一经 `sanitize.js` 脱敏)。
|
|
357
355
|
- 充值订单只能被订单所属用户查询。
|
|
358
356
|
- 本地配置文件 macOS/Linux 写入 mode `0600`;Windows 写入当前用户目录。
|
|
359
357
|
- 任何全局 npm、系统运行时安装都需用户在终端显式确认。
|
|
360
358
|
- CLI 不修改 shell profile / PowerShell profile / 全局环境变量。
|
|
361
359
|
|
|
362
|
-
## 已知风险与路线图
|
|
363
|
-
|
|
364
|
-
| 项 | 状态 |
|
|
365
|
-
| --- | --- |
|
|
366
|
-
| 自动化测试(Backend Go + CLI Node) | ✅ 全部通过(CLI Node + Go 后端 PASS) |
|
|
367
|
-
| 真实站点手动端到端验证 | ⚠️ 待执行(见 `prd/claude360-cli-verification.md` Task 13 Step 3) |
|
|
368
|
-
| Codex `wire_api = "responses"` 端到端兼容 | ⚠️ 需 NewAPI/Claude360 网关确认 `/v1/responses` 兼容性 |
|
|
369
|
-
| 微信 Native 真实商户回调 | ⚠️ 需对接生产商户配置后验证 |
|
|
370
|
-
| 系统密钥链保存 | ❌ 第一版不做 |
|
|
371
|
-
| 新用户注册闭环 | ❌ 第一版不做 |
|
|
372
|
-
| 多支付方式聚合 | ❌ 第一版不做 |
|
|
373
|
-
| 多域名 / 私有部署切换 | ❌ 第一版不做 |
|
|
374
|
-
|
|
375
|
-
完整需求边界见 `prd/claude360-cli-prd.md`。
|
|
376
|
-
|
|
377
360
|
## 致谢
|
|
378
361
|
|
|
379
|
-
本 CLI 的交互式初始化流程、工作流导入、MCP 推荐配置等设计,借鉴并参考了开源项目
|
|
380
|
-
[NPX ZCF](https://github.com/UfoMiao/zcf) 的部分功能体验,感谢作者 UfoMiao 的开源贡献。
|
|
362
|
+
本 CLI 的交互式初始化流程、工作流导入、MCP 推荐配置等设计,借鉴并参考了开源项目 [NPX ZCF](https://github.com/UfoMiao/zcf) 的部分功能体验,感谢作者 UfoMiao 的开源贡献。
|
|
381
363
|
|
|
382
364
|
- 相关功能入口(完整初始化、推荐工作流 / MCP / Skill / AGENTS)会在终端展示开源参考声明。
|
|
383
365
|
- 随 CLI 安装的推荐工作流文件均为 Claude360 自研改编内容,文件头保留对 NPX ZCF 的 attribution 注释。
|
|
384
|
-
- 如后续直接引入 ZCF 的源码、配置文件或文档片段,需先核查其开源许可证并在此处补充对应声明。
|
|
385
366
|
|
|
386
367
|
## 许可证
|
|
387
368
|
|
|
388
|
-
|
|
369
|
+
本仓库尚未声明开源许可证。在对外公开分发前,建议补充一个 `LICENSE` 文件(如 MIT)。在添加许可证之前,默认保留所有权利(All Rights Reserved)。
|
package/bin/claude360.js
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
import { runCli } from "../src/index.js";
|
|
4
4
|
import { safeErrorMessage } from "../src/sanitize.js";
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const rawArgs = process.argv.slice(2);
|
|
7
|
+
const verbose = rawArgs.includes("--verbose") || rawArgs.includes("-v");
|
|
8
|
+
// 仅取位置参数作为命令;--verbose/-v 等 flag 单独解析,避免 "doctor --verbose"
|
|
9
|
+
// 被当成未知命令(现有命令均不以 - 开头,按 - 前缀剥离 flag 安全)。
|
|
10
|
+
const command = rawArgs.filter((arg) => !arg.startsWith("-")).join(" ");
|
|
7
11
|
|
|
8
12
|
try {
|
|
9
|
-
await runCli({ command, forceSetup: command === "setup" });
|
|
13
|
+
await runCli({ command, verbose, forceSetup: command === "setup" });
|
|
10
14
|
} catch (error) {
|
|
11
|
-
console.error(safeErrorMessage(error));
|
|
15
|
+
console.error(verbose && error?.stack ? error.stack : safeErrorMessage(error));
|
|
12
16
|
process.exitCode = 1;
|
|
13
17
|
}
|
package/package.json
CHANGED
package/src/account-status.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { loadGroups } from "./group-manager.js";
|
|
8
8
|
import { sanitizeError } from "./sanitize.js";
|
|
9
|
+
import { formatMessage, formatResult } from "./messages.js";
|
|
9
10
|
import { renderStatusTable } from "./ui.js";
|
|
10
11
|
|
|
11
12
|
export async function loadAccountStatus({ api, config = {} } = {}) {
|
|
@@ -75,7 +76,7 @@ export function formatGroupRatio(groups, groupName) {
|
|
|
75
76
|
|
|
76
77
|
const STATUS_HEAD = ["账号", "余额", "已用额度", "当前 Key", "分组", "倍率", "状态"];
|
|
77
78
|
|
|
78
|
-
export function formatAccountStatus({ me, error, config = {}, groups = [], width = 0 } = {}) {
|
|
79
|
+
export function formatAccountStatus({ me, error, config = {}, groups = [], width = 0, color = false } = {}) {
|
|
79
80
|
const configured = config.configuredTools || {};
|
|
80
81
|
const toolLine = `Claude Code:${configured.claudeCode ? "已配置" : "未配置"} Codex:${configured.codex ? "已配置" : "未配置"}`;
|
|
81
82
|
const tokenName = config.tokenName || "-";
|
|
@@ -89,7 +90,7 @@ export function formatAccountStatus({ me, error, config = {}, groups = [], width
|
|
|
89
90
|
} else if (!me) {
|
|
90
91
|
const reason = sanitizeError(error);
|
|
91
92
|
row = [maskAccount(config.account), "-", "-", tokenName, group, formatGroupRatio(groups, group), "获取失败"];
|
|
92
|
-
extraLines = [
|
|
93
|
+
extraLines = [formatMessage("warn", `状态获取失败${reason ? `:${reason}` : ""}`, { color }), toolLine];
|
|
93
94
|
} else {
|
|
94
95
|
const account = me.email || me.display_name || me.username;
|
|
95
96
|
const balance = me.balance_display ?? String(me.quota ?? "-");
|
|
@@ -103,12 +104,14 @@ export function formatAccountStatus({ me, error, config = {}, groups = [], width
|
|
|
103
104
|
formatGroupRatio(groups, group),
|
|
104
105
|
me.low_balance ? "余额较低" : "正常",
|
|
105
106
|
];
|
|
106
|
-
extraLines =
|
|
107
|
+
extraLines = me.low_balance
|
|
108
|
+
? [formatResult("今日用量", usage, { color }), formatMessage("warn", "余额较低,建议充值", { color }), toolLine]
|
|
109
|
+
: [formatResult("今日用量", usage, { color }), toolLine];
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
return [
|
|
110
|
-
"Claude360 账户状态",
|
|
111
|
-
renderStatusTable({ head: STATUS_HEAD, row }, { width }),
|
|
113
|
+
formatMessage("heading", "Claude360 账户状态", { color }),
|
|
114
|
+
renderStatusTable({ head: STATUS_HEAD, row }, { width, color }),
|
|
112
115
|
...extraLines,
|
|
113
116
|
].join("\n");
|
|
114
117
|
}
|
package/src/auth.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { colorLevel } from "./colors.js";
|
|
2
|
+
import { createMessenger } from "./messages.js";
|
|
3
|
+
|
|
4
|
+
// 语义消息器工厂:真实终端着色,测试/管道(writeLine 被替换)下无色。
|
|
5
|
+
const mk = (writeLine) => createMessenger({ writeLine, color: writeLine === console.log ? colorLevel() : 0 });
|
|
6
|
+
|
|
1
7
|
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2
8
|
|
|
3
9
|
export async function startAuth({
|
|
@@ -14,6 +20,7 @@ export async function startAuth({
|
|
|
14
20
|
throw new Error("缺少浏览器打开函数");
|
|
15
21
|
}
|
|
16
22
|
|
|
23
|
+
const msg = mk(writeLine);
|
|
17
24
|
const start = await api.post("/api/cli/auth/start");
|
|
18
25
|
if (!start?.device_code || !start?.verification_url || !start?.user_code) {
|
|
19
26
|
throw new Error("授权服务返回数据不完整");
|
|
@@ -22,8 +29,8 @@ export async function startAuth({
|
|
|
22
29
|
const verificationUrl = withAuthCodes(start.verification_url, {
|
|
23
30
|
userCode: start.user_code,
|
|
24
31
|
});
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
msg.result("授权地址", verificationUrl);
|
|
33
|
+
msg.result("用户码", start.user_code);
|
|
27
34
|
await openBrowser(verificationUrl);
|
|
28
35
|
|
|
29
36
|
const intervalMs = secondsToMs(start.interval, 5);
|
package/src/banner.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// 渲染函数默认无色(color: false),保证测试与管道输出稳定;
|
|
4
4
|
// 运行时由 index.js 通过 playBanner / 显式 color 参数开启彩色。
|
|
5
5
|
|
|
6
|
-
import { BOLD, DIM, ESC, RESET, colorEnabled, colorLevel, fg, toLevel } from "./colors.js";
|
|
6
|
+
import { BOLD, DIM, ESC, PALETTE, RESET, colorEnabled, colorLevel, fg, toLevel } from "./colors.js";
|
|
7
7
|
|
|
8
8
|
export const BRAND_BASE_URL = "https://claude360.xyz";
|
|
9
9
|
|
|
@@ -46,7 +46,48 @@ function gradientAt(t) {
|
|
|
46
46
|
];
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// 默认按 emoji 呈现(2 列宽)的 BMP 杂项符号(Unicode Emoji_Presentation=Yes 的 BMP 部分)。
|
|
50
|
+
// 这些符号即便不带变体选择符,主流终端也按 2 列渲染:✅ U+2705、❌ U+274C、⏳ U+23F3 等。
|
|
51
|
+
// 关键:同区间内的窄符号 —— ✓ U+2713、✔ U+2714、▶ U+25B6、○ U+25CB、→ U+2192、× U+00D7
|
|
52
|
+
// —— 不在此集合,仍按 1 列处理,保证步骤标记与 messages 行内符号的既有对齐不变。
|
|
53
|
+
const BMP_EMOJI_WIDE = new Set();
|
|
54
|
+
for (const [start, end] of [
|
|
55
|
+
[0x231a, 0x231b], [0x23e9, 0x23ec], [0x23f0, 0x23f0], [0x23f3, 0x23f3],
|
|
56
|
+
[0x25fd, 0x25fe], [0x2614, 0x2615], [0x2648, 0x2653], [0x267f, 0x267f],
|
|
57
|
+
[0x2693, 0x2693], [0x26a1, 0x26a1], [0x26aa, 0x26ab], [0x26bd, 0x26be],
|
|
58
|
+
[0x26c4, 0x26c5], [0x26ce, 0x26ce], [0x26d4, 0x26d4], [0x26ea, 0x26ea],
|
|
59
|
+
[0x26f2, 0x26f3], [0x26f5, 0x26f5], [0x26fa, 0x26fa], [0x26fd, 0x26fd],
|
|
60
|
+
[0x2705, 0x2705], [0x270a, 0x270b], [0x2728, 0x2728], [0x274c, 0x274c],
|
|
61
|
+
[0x274e, 0x274e], [0x2753, 0x2755], [0x2757, 0x2757], [0x2795, 0x2797],
|
|
62
|
+
[0x27b0, 0x27b0], [0x27bf, 0x27bf], [0x2b1b, 0x2b1c], [0x2b50, 0x2b50],
|
|
63
|
+
[0x2b55, 0x2b55],
|
|
64
|
+
]) {
|
|
65
|
+
for (let cp = start; cp <= end; cp += 1) {
|
|
66
|
+
BMP_EMOJI_WIDE.add(cp);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
49
70
|
function charDisplayWidth(codePoint) {
|
|
71
|
+
// 变体选择符 VS16(U+FE0F)把前一个 BMP 符号强制为 emoji 呈现(2 列)。逐字符累加无法
|
|
72
|
+
// 回溯前字符,故给 VS16 计 1 列,补足基础符 1→2 的差值(⚙️ U+2699+FE0F、⚠️ ℹ️ 同理)。
|
|
73
|
+
if (codePoint === 0xfe0f) {
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
// 零宽连接符(U+200D,emoji 序列拼接)不占列宽。
|
|
77
|
+
if (codePoint === 0x200d) {
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
// SMP emoji 平面(🚀 🎉 📦 🔐 等 U+1Fxxx)与 CJK 扩展区按 2 列宽渲染。
|
|
81
|
+
if (
|
|
82
|
+
(codePoint >= 0x1f000 && codePoint <= 0x1faff) ||
|
|
83
|
+
(codePoint >= 0x20000 && codePoint <= 0x3fffd)
|
|
84
|
+
) {
|
|
85
|
+
return 2;
|
|
86
|
+
}
|
|
87
|
+
// BMP 默认 emoji 呈现的宽符号(✅ ❌ ⏳ 等)。
|
|
88
|
+
if (BMP_EMOJI_WIDE.has(codePoint)) {
|
|
89
|
+
return 2;
|
|
90
|
+
}
|
|
50
91
|
return (
|
|
51
92
|
(codePoint >= 0x1100 && codePoint <= 0x115f) ||
|
|
52
93
|
(codePoint >= 0x2e80 && codePoint <= 0x303e) ||
|
|
@@ -186,8 +227,8 @@ export function renderBanner({
|
|
|
186
227
|
return rows.map((row) => row.text).join("\n");
|
|
187
228
|
}
|
|
188
229
|
const styles = {
|
|
189
|
-
title: `${BOLD}${fg(
|
|
190
|
-
sub: `${fg(
|
|
230
|
+
title: `${BOLD}${fg(...PALETTE.title, level)}`,
|
|
231
|
+
sub: `${fg(...PALETTE.path, level)}`,
|
|
191
232
|
};
|
|
192
233
|
return rows.map((row) => {
|
|
193
234
|
if (row.style === "footer") {
|
|
@@ -243,9 +284,9 @@ export const CHECK_WARN = "!";
|
|
|
243
284
|
export const CHECK_FAIL = "×";
|
|
244
285
|
|
|
245
286
|
const CHECK_COLORS = {
|
|
246
|
-
ok:
|
|
247
|
-
warn:
|
|
248
|
-
fail:
|
|
287
|
+
ok: PALETTE.success,
|
|
288
|
+
warn: PALETTE.warn,
|
|
289
|
+
fail: PALETTE.error,
|
|
249
290
|
};
|
|
250
291
|
|
|
251
292
|
export function formatCheckLine(status, text, { color = false } = {}) {
|