claude360 0.2.7 → 0.2.9

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,10 +1,17 @@
1
1
  # Claude360 CLI
2
2
 
3
- 面向 [Claude360](https://claude360.xyz) 已注册用户的跨平台命令行工具,让不熟悉终端配置的用户也能一行命令完成 Claude Code / Codex 的安装、授权、Key 选择、余额查询、微信扫码充值与日常启动。
3
+ [![Node.js](https://img.shields.io/badge/Node.js-%E2%89%A518-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
4
+ [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue)]()
5
+ [![Tests](https://img.shields.io/badge/tests-232%20passing-success)]()
6
+
7
+ 面向 [Claude360](https://claude360.xyz) 已注册用户的跨平台命令行工具,让不熟悉终端配置的用户也能一行命令完成 **Claude Code / Codex** 的安装、授权、Key 选择、余额查询、微信扫码充值与日常启动。
4
8
 
5
9
  - 不要求用户在终端输入站点账号密码,授权全程在浏览器完成。
6
10
  - 不修改 shell profile / PowerShell profile / 全局环境变量。
7
- - 分组倍率、充值金额、API 凭证生命周期均以 NewAPI 后端为唯一来源,CLI 不内置任何业务口径。
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 | 写入隔离的 `[model_providers.claude360]` / `[profiles.claude360]` 配置,并以 `codex --profile claude360` 启动 |
47
+ | 启动 Codex | 写入隔离的 Claude360 provider / profile 覆盖层配置,并以 `codex --profile claude360` 启动 |
40
48
  | 工具更新 | 菜单内更新 `claude360` 自身、Claude Code、Codex,全部需要二次确认 |
41
- | 一键完整初始化 | Claude Code / Codex 完整初始化向导:登录、Key、安装/更新、API 注入、输出语言、提示词风格、工作流、MCP、模型、权限配置、连接测试、启动 |
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
- ### macOS / Linux
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
- ### Windows PowerShell
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
- 1. 识别 OS / 架构。
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`,展示账号、余额、已用、当前 Key 名称与分组;充值先取 `/api/cli/topup/options`,按后端校验通过的金额或最低额提交,再用 `qrcode-terminal` 在终端渲染 `code_url`,渲染失败时降级为纯文本 URL。轮询 `/api/cli/topup/order?order_id=`,支付完成自动刷新余额。
144
- - **启动 Claude Code**:调用 `claude` 子进程,并通过 `ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` 注入。
145
- - **启动 Codex**:写入 `~/.codex/config.toml` `[model_providers.claude360]` 与 `[profiles.claude360]`,发现既有冲突字段会先要求用户确认再覆盖,然后 `codex --profile claude360`,并通过 `CLAUDE360_API_KEY` 注入。
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` (权限 `0600`) |
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
- - 第一版接受**本地明文**保存 `cliToken` 与 `apiKey`,CLI 仅收紧文件权限,不接入系统密钥链。
204
+ - 当前版本接受**本地明文**保存 `cliToken` 与 `apiKey`,CLI 仅收紧文件权限,不接入系统密钥链。
173
205
  - CLI 日志与诊断输出会脱敏 API Key。
174
206
  - 若需要重置,删除 `~/.claude360/config.json` 即可触发完整重新授权。
175
207
 
176
- ## 后端接口
208
+ ## 后端接口契约
177
209
 
178
- CLI 仅依赖一组隔离的 `/api/cli` 接口,由 `newapi/controller/cli.go` 提供:
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 轮询授权结果,状态:`pending` / `approved` / `denied` / `expired` / `consumed` |
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(受 `operation_setting.GetMaxUserTokens()` 约束) |
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`;`tool` 参数预留) |
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/:order_id` | 查询订单状态(仅订单所属用户) |
225
+ | GET | `/api/cli/topup/order?order_id=` | 查询订单状态(仅订单所属用户) |
194
226
 
195
- 实现要点:
227
+ 契约要点:
196
228
 
197
229
  - 设备码、user_code、CLI 凭证均有过期机制;CLI 凭证可后台吊销。
198
- - 已批准会话被消费后保持 `consumed` 状态,CLI 凭证有独立有效期,设备码窗口过期不影响已发出的凭证。
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` `profiles.claude360` 两个表,不动其他 provider):
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
- > **风险说明**:当前 Codex 自定义 provider 使用 Responses 协议(`wire_api = "responses"`)。Claude360 / NewAPI 必须支持 `/v1/responses` 或在网关层把 Responses 请求适配到现有模型能力,否则 Codex 调用会失败。详见 `prd/claude360-cli-verification.md` 中“Release Risks”。
268
+ > **风险说明**:Codex 自定义 provider 使用 Responses 协议(`wire_api = "responses"`)。后端网关必须支持 `/v1/responses` 或在网关层将 Responses 请求适配到现有模型能力,否则 Codex 调用会失败。
240
269
 
241
270
  ## 诊断与故障排查
242
271
 
243
- 执行主菜单中“诊断”项,CLI 会汇报以下检查项:
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
- go test ./model ./middleware ./controller -run 'TestCli|TestGetUserTopUpByTradeNo' -count=1
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
- node ./bin/claude360.js
298
+ node ./bin/claude360.js # 源码模式运行
299
+ npm link && claude360 # 链接到全局命令
295
300
  ```
296
301
 
297
- 修改源码后无需重启全局安装,可通过 `npm link` 把当前 CLI 包链到全局:
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
- claude360-cli/
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
- │ ├── menu.js # 主菜单
325
- │ ├── platform.js # 平台路径与能力探测
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
- └── topup.js # 微信 Native 充值流程
330
- ├── test/ # 11 个测试文件
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
- - 授权轮询限频(`middleware.CriticalRateLimit()`)。
355
- - `POST /api/cli/tokens/:id/reveal` 强制鉴权 + 限频 + 禁用缓存。
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
- 随仓库根目录 `LICENSE` 发布,未单独声明。
369
+ 本仓库尚未声明开源许可证。在对外公开分发前,建议补充一个 `LICENSE` 文件(如 MIT)。在添加许可证之前,默认保留所有权利(All Rights Reserved)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude360",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Interactive Claude360 CLI for browser auth, API key setup, balance checks, top-up, Claude Code and Codex launch.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 = [`! 状态获取失败${reason ? `:${reason}` : ""}`, toolLine];
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 = [`今日用量:${usage}${me.low_balance ? " ! 余额较低,建议充值" : ""}`, toolLine];
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
- writeLine(`授权地址:${verificationUrl}`);
26
- writeLine(`用户码:${start.user_code}`);
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
 
@@ -186,8 +186,8 @@ export function renderBanner({
186
186
  return rows.map((row) => row.text).join("\n");
187
187
  }
188
188
  const styles = {
189
- title: `${BOLD}${fg(240, 246, 255, level)}`,
190
- sub: `${fg(148, 163, 184, level)}`,
189
+ title: `${BOLD}${fg(...PALETTE.title, level)}`,
190
+ sub: `${fg(...PALETTE.path, level)}`,
191
191
  };
192
192
  return rows.map((row) => {
193
193
  if (row.style === "footer") {
@@ -243,9 +243,9 @@ export const CHECK_WARN = "!";
243
243
  export const CHECK_FAIL = "×";
244
244
 
245
245
  const CHECK_COLORS = {
246
- ok: [74, 222, 128],
247
- warn: [250, 204, 21],
248
- fail: [248, 113, 113],
246
+ ok: PALETTE.success,
247
+ warn: PALETTE.warn,
248
+ fail: PALETTE.error,
249
249
  };
250
250
 
251
251
  export function formatCheckLine(status, text, { color = false } = {}) {
package/src/cc-switch.js CHANGED
@@ -4,6 +4,11 @@
4
4
  import { chmod, mkdir, writeFile } from "node:fs/promises";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
+ import { colorLevel } from "./colors.js";
8
+ import { createMessenger } from "./messages.js";
9
+
10
+ // 语义消息器工厂:真实终端着色,测试/管道(writeLine 被替换)下无色。
11
+ const mk = (writeLine) => createMessenger({ writeLine, color: writeLine === console.log ? colorLevel() : 0 });
7
12
 
8
13
  function normalizeBaseUrl(baseUrl = "https://claude360.xyz") {
9
14
  return String(baseUrl).replace(/\/+$/, "");
@@ -134,9 +139,10 @@ export async function runCcSwitchGenerator({
134
139
  throw new Error("缺少菜单选择输入");
135
140
  }
136
141
 
142
+ const msg = mk(writeLine);
137
143
  let apiKey = config.apiKey;
138
144
  if (!apiKey) {
139
- writeLine("当前没有可用 API Key,需要先创建 Claude360 API Key。");
145
+ msg.warn("当前没有可用 API Key,需要先创建 Claude360 API Key。");
140
146
  if (typeof ensureApiKey !== "function") {
141
147
  return { done: false, reason: "no_key" };
142
148
  }
@@ -150,7 +156,7 @@ export async function runCcSwitchGenerator({
150
156
  const token = await ensureApiKey();
151
157
  apiKey = token?.apiKey;
152
158
  if (!apiKey) {
153
- writeLine("未获取到可用 API Key,已取消生成。");
159
+ msg.info("未获取到可用 API Key,已取消生成。");
154
160
  return { done: false, reason: "no_key" };
155
161
  }
156
162
  }
@@ -185,12 +191,12 @@ export async function runCcSwitchGenerator({
185
191
  if (reveal === "masked") {
186
192
  const maskedConfig = maskCcSwitchConfig(fullConfig, apiKey);
187
193
  writeLine(JSON.stringify(maskedConfig, null, 2));
188
- writeLine("提示:脱敏配置仅用于预览,无法直接使用,也不会保存到文件。");
194
+ msg.hint("提示:脱敏配置仅用于预览,无法直接使用,也不会保存到文件。");
189
195
  return { done: true, target, masked: true, saved: false };
190
196
  }
191
197
 
192
198
  writeLine(JSON.stringify(fullConfig, null, 2));
193
- writeLine("请将以上配置复制到 cc-switch 中使用。");
199
+ msg.info("请将以上配置复制到 cc-switch 中使用。");
194
200
 
195
201
  const saveChoice = await promptSelect("是否保存到本地文件?", [
196
202
  { label: "保存到 ~/.claude360/cc-switch-claude360.json", value: "save" },
@@ -201,6 +207,6 @@ export async function runCcSwitchGenerator({
201
207
  }
202
208
 
203
209
  const savedPath = await save(fullConfig);
204
- writeLine(`已保存到:${savedPath}(文件权限 0600)`);
210
+ msg.success(`已保存到:${savedPath}(文件权限 0600)`);
205
211
  return { done: true, target, masked: false, saved: true, savedPath };
206
212
  }
package/src/colors.js CHANGED
@@ -91,3 +91,34 @@ export function fg(r, g, b, level = 2) {
91
91
  }
92
92
  return "";
93
93
  }
94
+
95
+ // ──────────────────────────────────────────────
96
+ // 语义调色板(单一事实源)
97
+ // ──────────────────────────────────────────────
98
+ // 全 CLI 的角色配色统一在此定义,banner / menu / prompts / ui / messages
99
+ // 都从这里取色,杜绝各文件重复硬编码同一组 RGB(色值沿用 Tailwind 体系)。
100
+ // 设计目标:状态色(绿/红/黄)醒目、信息色(天蓝)中性、进行色(紫)区别于
101
+ // 信息、标题白做强调、两级灰(path/hint)用于回显与次要说明 —— 形成层级。
102
+ export const PALETTE = {
103
+ title: [240, 246, 255], // 强调白:页面/品牌标题、回显值
104
+ heading: [34, 211, 238], // 亮青:章节标题、品牌高亮
105
+ info: [125, 211, 252], // 天蓝:中性信息、表头、选择键
106
+ success: [74, 222, 128], // 绿:操作成功
107
+ warn: [250, 204, 21], // 黄:警告 / 降级
108
+ error: [248, 113, 113], // 红:失败 / 危险操作
109
+ step: [167, 139, 250], // 紫:进行中 / 步骤(与 info 拉开区分)
110
+ path: [148, 163, 184], // 灰蓝:路径 / 命令 / URL 回显
111
+ hint: [100, 116, 139], // 暗灰:次要说明 / 帮助 / 未选中项
112
+ border: [71, 85, 105], // 青灰:边框 / 分隔线
113
+ };
114
+
115
+ // 按色彩深度 level 现算各语义角色的前景 SGR(真彩色保留 RGB,256 色量化)。
116
+ // level=0 时全部为空串,调用方据此走无色路径。
117
+ export function theme(level) {
118
+ const t = {};
119
+ for (const name of Object.keys(PALETTE)) {
120
+ const [r, g, b] = PALETTE[name];
121
+ t[name] = fg(r, g, b, level);
122
+ }
123
+ return t;
124
+ }