@minniexcode/codex-switch 0.0.3 → 0.0.4
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.AI.md +8 -3
- package/README.md +160 -91
- package/dist/app/edit-provider.js +64 -0
- package/dist/app/import-providers.js +10 -1
- package/dist/app/list-backups.js +17 -0
- package/dist/app/rollback-backup.js +30 -0
- package/dist/app/setup-codex.js +138 -0
- package/dist/app/show-provider.js +22 -0
- package/dist/cli/add-interactive.js +25 -31
- package/dist/cli/args.js +8 -5
- package/dist/cli/help.js +70 -12
- package/dist/cli/interactive.js +67 -8
- package/dist/cli/output.js +34 -1
- package/dist/cli/prompt.js +19 -2
- package/dist/cli.js +160 -12
- package/dist/domain/backups.js +103 -0
- package/dist/domain/errors.js +3 -3
- package/dist/domain/providers.js +10 -0
- package/dist/domain/setup.js +30 -0
- package/dist/infra/backup-repo.js +65 -6
- package/dist/infra/codex-cli.js +62 -0
- package/dist/infra/codex-discovery.js +48 -0
- package/dist/infra/codex-paths.js +14 -1
- package/dist/infra/providers-repo.js +29 -0
- package/docs/PRD/codex-switch-prd-v0.1.0.md +393 -0
- package/docs/{codex-switch-prd.md → PRD/codex-switch-prd.md} +9 -5
- package/docs/cli-usage.md +580 -0
- package/docs/codex-switch-command-design.md +1 -1
- package/docs/codex-switch-product-overview.md +1 -1
- package/docs/codex-switch-product-research.md +2 -2
- package/docs/codex-switch-technical-architecture.md +1 -1
- package/docs/codex-switch-v0.0.4-design.md +874 -0
- package/package.json +1 -1
|
@@ -0,0 +1,874 @@
|
|
|
1
|
+
# codex-switch `0.0.4` 设计文档
|
|
2
|
+
|
|
3
|
+
## 文档信息
|
|
4
|
+
|
|
5
|
+
- 文档类型:详细设计文档
|
|
6
|
+
- 适用版本:`0.0.4` 功能里程碑
|
|
7
|
+
- 对应目标 PRD:[`PRD/codex-switch-prd-v0.1.0.md`](./PRD/codex-switch-prd-v0.1.0.md)
|
|
8
|
+
- 历史基线 PRD:[`PRD/codex-switch-prd.md`](./PRD/codex-switch-prd.md)
|
|
9
|
+
- 当前架构基线:[`codex-switch-technical-architecture.md`](./codex-switch-technical-architecture.md)
|
|
10
|
+
- 当前命令基线:[`codex-switch-command-design.md`](./codex-switch-command-design.md)
|
|
11
|
+
|
|
12
|
+
## 1. 文档目标
|
|
13
|
+
|
|
14
|
+
这份文档回答的不是“未来想做什么”,而是 `0.0.4` 这批功能应该如何落地:
|
|
15
|
+
|
|
16
|
+
- 功能为什么进入 `0.0.4`
|
|
17
|
+
- 每个功能的职责边界是什么
|
|
18
|
+
- 命令行为、交互方式、失败语义如何定义
|
|
19
|
+
- 现有架构上应该怎样扩展
|
|
20
|
+
- 代码层面需要新增哪些模块
|
|
21
|
+
- 哪些内容明确不在 `0.0.4` 范围内
|
|
22
|
+
|
|
23
|
+
目标是让后续实现阶段不需要再补关键设计决策。
|
|
24
|
+
|
|
25
|
+
## 2. 背景与设计原则
|
|
26
|
+
|
|
27
|
+
### 2.1 当前基线
|
|
28
|
+
|
|
29
|
+
当前 `0.0.3` 已经具备:
|
|
30
|
+
|
|
31
|
+
- provider 基础管理:`list`、`add`、`remove`
|
|
32
|
+
- provider 切换:`switch`
|
|
33
|
+
- 文件导入导出:`import`、`export`
|
|
34
|
+
- 状态与诊断:`status`、`doctor`
|
|
35
|
+
- 安全恢复:`rollback`
|
|
36
|
+
- TTY 渐进式交互
|
|
37
|
+
- 统一 JSON envelope
|
|
38
|
+
- 写操作锁、备份、回滚模型
|
|
39
|
+
|
|
40
|
+
### 2.2 `0.0.4` 进入的原因
|
|
41
|
+
|
|
42
|
+
当前主要短板不是“能不能切换”,而是下面几类使用门槛:
|
|
43
|
+
|
|
44
|
+
- 首次使用需要人工准备 `providers.json`
|
|
45
|
+
- 缺少查看单个 provider 的命令
|
|
46
|
+
- 缺少修改单个 provider 的命令
|
|
47
|
+
- 只支持 latest rollback,不支持历史备份选择
|
|
48
|
+
- `import` 只有整体替换,没有 merge 模式
|
|
49
|
+
- 一部分错误码仍沿用 MVP 时代的宽泛复用
|
|
50
|
+
|
|
51
|
+
### 2.3 设计原则
|
|
52
|
+
|
|
53
|
+
`0.0.4` 必须继续沿用现有设计原则:
|
|
54
|
+
|
|
55
|
+
- `CLI First`
|
|
56
|
+
- `Local First`
|
|
57
|
+
- `Safe by Default`
|
|
58
|
+
- `AI Friendly`
|
|
59
|
+
- `Split State Model`
|
|
60
|
+
- `Lightweight Transactions`
|
|
61
|
+
|
|
62
|
+
在此基础上增加三条演进原则:
|
|
63
|
+
|
|
64
|
+
- 不破坏现有 JSON envelope
|
|
65
|
+
- 不复用语义不匹配的错误码
|
|
66
|
+
- 所有写命令默认纳入备份与回滚模型
|
|
67
|
+
|
|
68
|
+
## 3. 范围与边界
|
|
69
|
+
|
|
70
|
+
### 3.1 `0.0.4` 范围内
|
|
71
|
+
|
|
72
|
+
本版本详细设计覆盖以下功能:
|
|
73
|
+
|
|
74
|
+
- `codexs setup`
|
|
75
|
+
- `codexs show <provider>`
|
|
76
|
+
- `codexs edit <provider>`
|
|
77
|
+
- `codexs backups list`
|
|
78
|
+
- `codexs rollback <backup-id>`
|
|
79
|
+
- `codexs import --merge`
|
|
80
|
+
- CLI 错误码与参数错误语义收紧
|
|
81
|
+
|
|
82
|
+
### 3.2 明确不在 `0.0.4` 范围内
|
|
83
|
+
|
|
84
|
+
下面这些内容不进入本设计:
|
|
85
|
+
|
|
86
|
+
- Copilot auth 接入
|
|
87
|
+
- 本地代理服务
|
|
88
|
+
- 第三方依赖动态安装
|
|
89
|
+
- GUI / MCP / daemon
|
|
90
|
+
- 远程同步或云端控制面
|
|
91
|
+
- 放宽 `providers.json` 为半初始化 provider 模型
|
|
92
|
+
|
|
93
|
+
### 3.3 数据边界
|
|
94
|
+
|
|
95
|
+
`0.0.4` 仍然坚持当前状态模型:
|
|
96
|
+
|
|
97
|
+
- `providers.json`:管理态单一事实源
|
|
98
|
+
- `config.toml`:运行态配置
|
|
99
|
+
- `auth.json`:运行态认证文件
|
|
100
|
+
- `backups/` + `latest.json`:回滚态
|
|
101
|
+
|
|
102
|
+
不引入数据库,不引入新的长期状态仓库。
|
|
103
|
+
|
|
104
|
+
## 4. 功能总览
|
|
105
|
+
|
|
106
|
+
### 4.1 `setup`
|
|
107
|
+
|
|
108
|
+
目标:
|
|
109
|
+
|
|
110
|
+
- 完成首次初始化
|
|
111
|
+
- 从已有 Codex 目录引导生成或更新 `providers.json`
|
|
112
|
+
- 初始化结束后立刻用 `doctor` 验证状态
|
|
113
|
+
|
|
114
|
+
### 4.2 `show`
|
|
115
|
+
|
|
116
|
+
目标:
|
|
117
|
+
|
|
118
|
+
- 查看单个 provider 的完整详情
|
|
119
|
+
- 为人类和 AI 提供单条记录读取能力
|
|
120
|
+
|
|
121
|
+
### 4.3 `edit`
|
|
122
|
+
|
|
123
|
+
目标:
|
|
124
|
+
|
|
125
|
+
- 原位修改单个 provider
|
|
126
|
+
- 保留当前文件模型和备份模型
|
|
127
|
+
|
|
128
|
+
### 4.4 `backups list`
|
|
129
|
+
|
|
130
|
+
目标:
|
|
131
|
+
|
|
132
|
+
- 把历史备份从“仅 latest 隐式存在”提升为“可枚举资源”
|
|
133
|
+
|
|
134
|
+
### 4.5 `rollback <backup-id>`
|
|
135
|
+
|
|
136
|
+
目标:
|
|
137
|
+
|
|
138
|
+
- 从 latest rollback 扩展为显式历史恢复
|
|
139
|
+
|
|
140
|
+
### 4.6 `import --merge`
|
|
141
|
+
|
|
142
|
+
目标:
|
|
143
|
+
|
|
144
|
+
- 在不完全替换 registry 的情况下导入 provider 清单
|
|
145
|
+
|
|
146
|
+
## 5. 用户与调用模型
|
|
147
|
+
|
|
148
|
+
### 5.1 人类用户
|
|
149
|
+
|
|
150
|
+
人类模式优先使用:
|
|
151
|
+
|
|
152
|
+
- 清晰帮助信息
|
|
153
|
+
- 渐进式 TTY 交互
|
|
154
|
+
- 危险写入确认
|
|
155
|
+
- 明确的恢复路径
|
|
156
|
+
|
|
157
|
+
### 5.2 AI / 自动化调用
|
|
158
|
+
|
|
159
|
+
AI 模式优先使用:
|
|
160
|
+
|
|
161
|
+
- `--json`
|
|
162
|
+
- 显式参数
|
|
163
|
+
- 稳定 envelope
|
|
164
|
+
- 稳定错误码
|
|
165
|
+
|
|
166
|
+
约束:
|
|
167
|
+
|
|
168
|
+
- `--json` 下不允许进入交互
|
|
169
|
+
- 非 TTY 环境不依赖 prompt 完成核心流程
|
|
170
|
+
|
|
171
|
+
## 6. 公共接口与契约
|
|
172
|
+
|
|
173
|
+
### 6.1 JSON Envelope 保持不变
|
|
174
|
+
|
|
175
|
+
继续使用:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"ok": true,
|
|
180
|
+
"command": "command-name",
|
|
181
|
+
"data": {},
|
|
182
|
+
"warnings": [],
|
|
183
|
+
"error": null
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
规则:
|
|
188
|
+
|
|
189
|
+
- 顶层字段不改名
|
|
190
|
+
- 顶层字段不增删重排为语义信号
|
|
191
|
+
- 扩展字段统一进入 `data`
|
|
192
|
+
- 软提示进入 `warnings`
|
|
193
|
+
- 错误细节进入 `error.details`
|
|
194
|
+
|
|
195
|
+
### 6.2 `providers.json` 保持完整 provider 模型
|
|
196
|
+
|
|
197
|
+
当前 `0.0.4` 仍要求 managed provider 至少具备:
|
|
198
|
+
|
|
199
|
+
- `profile`
|
|
200
|
+
- `apiKey`
|
|
201
|
+
|
|
202
|
+
允许补充:
|
|
203
|
+
|
|
204
|
+
- `baseUrl`
|
|
205
|
+
- `note`
|
|
206
|
+
- `tags`
|
|
207
|
+
|
|
208
|
+
不允许:
|
|
209
|
+
|
|
210
|
+
- 写入缺少 `apiKey` 的正式 provider
|
|
211
|
+
- 在 `setup` 中默认创建半成品记录
|
|
212
|
+
|
|
213
|
+
### 6.3 备份 ID 契约
|
|
214
|
+
|
|
215
|
+
`0.0.4` 引入显式 `backupId` 概念。
|
|
216
|
+
|
|
217
|
+
规则:
|
|
218
|
+
|
|
219
|
+
- `backupId` 等于备份目录 basename
|
|
220
|
+
- 示例:`20260511-221457-switch`
|
|
221
|
+
- `backups list` 返回该 ID
|
|
222
|
+
- `rollback <backup-id>` 使用该 ID 定位 manifest
|
|
223
|
+
|
|
224
|
+
## 7. 命令详细设计
|
|
225
|
+
|
|
226
|
+
### 7.1 `codexs setup`
|
|
227
|
+
|
|
228
|
+
#### 用途
|
|
229
|
+
|
|
230
|
+
初始化 codex-switch 的受管状态。
|
|
231
|
+
|
|
232
|
+
#### 命令形态
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
codexs setup [--json] [--codex-dir <path>] [--merge|--overwrite]
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
说明:
|
|
239
|
+
|
|
240
|
+
- `--codex-dir` 显式指定目标目录
|
|
241
|
+
- `--merge` 和 `--overwrite` 只用于非交互模式显式决定已有 `providers.json` 的处理策略
|
|
242
|
+
- 默认不增加更多参数,避免首次引入就过重
|
|
243
|
+
|
|
244
|
+
#### 主流程
|
|
245
|
+
|
|
246
|
+
1. 确认 `codex` CLI 是否可执行
|
|
247
|
+
2. 确认 `codex` 版本是否满足最低门槛
|
|
248
|
+
3. 确定目标 Codex 目录
|
|
249
|
+
4. 读取目标 `config.toml`
|
|
250
|
+
5. 解析 profile 列表和当前 active profile
|
|
251
|
+
6. 基于 profile 列表构造初始化候选
|
|
252
|
+
7. 为缺失 `apiKey` 的候选项补问必填字段
|
|
253
|
+
8. 检测 `providers.json` 是否已存在
|
|
254
|
+
9. 执行 `overwrite`、`merge` 或 `cancel`
|
|
255
|
+
10. 通过统一 mutation 流程写入 `providers.json`
|
|
256
|
+
11. 自动执行 `doctor`
|
|
257
|
+
12. 输出 setup 结果和 doctor 结果摘要
|
|
258
|
+
|
|
259
|
+
#### 目录发现策略
|
|
260
|
+
|
|
261
|
+
优先级:
|
|
262
|
+
|
|
263
|
+
1. `--codex-dir` 显式指定
|
|
264
|
+
2. 默认目录 `~/.codex`
|
|
265
|
+
3. 未来可扩展的候选目录发现器返回的其他目录
|
|
266
|
+
|
|
267
|
+
交互行为:
|
|
268
|
+
|
|
269
|
+
- 单候选目录:直接继续
|
|
270
|
+
- 多候选目录:TTY 下选择或手动输入
|
|
271
|
+
- 非交互且多候选目录:失败并返回 `CODEX_DIR_AMBIGUOUS`
|
|
272
|
+
|
|
273
|
+
#### 输入补问策略
|
|
274
|
+
|
|
275
|
+
`setup` 不从运行态猜测 API key。
|
|
276
|
+
|
|
277
|
+
TTY 下:
|
|
278
|
+
|
|
279
|
+
- 可为每个要纳入管理的 profile 补问 `providerName`
|
|
280
|
+
- 可补问 `apiKey`
|
|
281
|
+
- 可选补问 `baseUrl`、`note`、`tags`
|
|
282
|
+
|
|
283
|
+
非交互下:
|
|
284
|
+
|
|
285
|
+
- 若无法构造完整 provider,直接失败
|
|
286
|
+
- 不写入部分完成的 registry
|
|
287
|
+
|
|
288
|
+
#### 已存在 `providers.json` 时的策略
|
|
289
|
+
|
|
290
|
+
TTY 下:
|
|
291
|
+
|
|
292
|
+
- 显示检测结果
|
|
293
|
+
- 提供 `overwrite`、`merge`、`cancel`
|
|
294
|
+
|
|
295
|
+
非交互下:
|
|
296
|
+
|
|
297
|
+
- 只有显式 `--merge` 或 `--overwrite` 才继续
|
|
298
|
+
- 否则返回 `PROVIDERS_ALREADY_EXISTS`
|
|
299
|
+
|
|
300
|
+
#### 成功输出
|
|
301
|
+
|
|
302
|
+
人类模式:
|
|
303
|
+
|
|
304
|
+
- 目标目录
|
|
305
|
+
- 初始化了多少 providers
|
|
306
|
+
- 采用了哪种写入策略
|
|
307
|
+
- 是否执行了 doctor
|
|
308
|
+
- doctor 是否发现问题
|
|
309
|
+
|
|
310
|
+
JSON 模式建议字段:
|
|
311
|
+
|
|
312
|
+
- `codexDir`
|
|
313
|
+
- `strategy`
|
|
314
|
+
- `providersInitialized`
|
|
315
|
+
- `providerNames`
|
|
316
|
+
- `doctor`
|
|
317
|
+
|
|
318
|
+
#### 失败错误码
|
|
319
|
+
|
|
320
|
+
- `CODEX_NOT_INSTALLED`
|
|
321
|
+
- `CODEX_VERSION_UNSUPPORTED`
|
|
322
|
+
- `CODEX_DIR_NOT_FOUND`
|
|
323
|
+
- `CODEX_DIR_AMBIGUOUS`
|
|
324
|
+
- `CONFIG_NOT_FOUND`
|
|
325
|
+
- `PROFILE_NOT_FOUND`
|
|
326
|
+
- `PROVIDERS_ALREADY_EXISTS`
|
|
327
|
+
- `PROMPT_CANCELLED`
|
|
328
|
+
- `BACKUP_FAILED`
|
|
329
|
+
- `ROLLBACK_FAILED`
|
|
330
|
+
|
|
331
|
+
#### 边界
|
|
332
|
+
|
|
333
|
+
- 不负责自动登录 provider
|
|
334
|
+
- 不负责从远程拉取任何配置
|
|
335
|
+
- 不负责创建复杂 profile 结构
|
|
336
|
+
- 不负责引入第三方 auth
|
|
337
|
+
|
|
338
|
+
### 7.2 `codexs show <provider>`
|
|
339
|
+
|
|
340
|
+
#### 用途
|
|
341
|
+
|
|
342
|
+
展示单个 provider 的完整记录。
|
|
343
|
+
|
|
344
|
+
#### 命令形态
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
codexs show <provider> [--json] [--codex-dir <path>]
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
#### 行为
|
|
351
|
+
|
|
352
|
+
- 读取 `providers.json`
|
|
353
|
+
- 查找目标 provider
|
|
354
|
+
- 返回完整字段
|
|
355
|
+
- 默认对敏感值做安全展示
|
|
356
|
+
|
|
357
|
+
#### 输出策略
|
|
358
|
+
|
|
359
|
+
人类模式:
|
|
360
|
+
|
|
361
|
+
- 展示 `profile`、`baseUrl`、`note`、`tags`
|
|
362
|
+
- `apiKey` 默认只显示掩码摘要
|
|
363
|
+
|
|
364
|
+
JSON 模式:
|
|
365
|
+
|
|
366
|
+
- `data.provider` 返回完整结构
|
|
367
|
+
- `apiKey` 是否完整返回由当前安全策略决定;`0.0.4` 建议默认返回完整值给显式本地自动化调用,不在普通文本模式泄露
|
|
368
|
+
|
|
369
|
+
#### 失败错误码
|
|
370
|
+
|
|
371
|
+
- `PROVIDERS_NOT_FOUND`
|
|
372
|
+
- `PROVIDERS_PARSE_ERROR`
|
|
373
|
+
- `PROVIDER_NOT_FOUND`
|
|
374
|
+
|
|
375
|
+
#### 边界
|
|
376
|
+
|
|
377
|
+
- 不做模糊搜索
|
|
378
|
+
- 不支持按 tag 查询
|
|
379
|
+
|
|
380
|
+
### 7.3 `codexs edit <provider>`
|
|
381
|
+
|
|
382
|
+
#### 用途
|
|
383
|
+
|
|
384
|
+
修改单个 provider 记录。
|
|
385
|
+
|
|
386
|
+
#### 命令形态
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
codexs edit <provider> [--profile <name>] [--api-key <key>] [--base-url <url>] [--note <text>] [--tag <tag> ...] [--json] [--codex-dir <path>]
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### 设计取舍
|
|
393
|
+
|
|
394
|
+
默认采用“显式参数优先 + TTY 补齐”的方式,而不是外部编辑器。
|
|
395
|
+
|
|
396
|
+
原因:
|
|
397
|
+
|
|
398
|
+
- 参数契约更适合自动化
|
|
399
|
+
- 行为更容易测试
|
|
400
|
+
- 不引入平台级编辑器差异
|
|
401
|
+
- 保持和 `add` 的交互模型一致
|
|
402
|
+
|
|
403
|
+
#### 行为
|
|
404
|
+
|
|
405
|
+
- 读取现有 provider
|
|
406
|
+
- 将传入字段覆盖到原记录
|
|
407
|
+
- 未传入的字段保持原值
|
|
408
|
+
- TTY 下如果没有传任何可编辑字段,可进入字段选择式补问
|
|
409
|
+
- 最终写回 `providers.json`
|
|
410
|
+
|
|
411
|
+
#### tag 语义
|
|
412
|
+
|
|
413
|
+
`0.0.4` 建议先采用简单规则:
|
|
414
|
+
|
|
415
|
+
- 传入 `--tag` 时,用提供的 tag 列表整体替换原 tags
|
|
416
|
+
- 未传 `--tag` 时保留原 tags
|
|
417
|
+
|
|
418
|
+
不在 `0.0.4` 引入复杂的 `--add-tag` / `--remove-tag`
|
|
419
|
+
|
|
420
|
+
#### 成功输出
|
|
421
|
+
|
|
422
|
+
- `provider`
|
|
423
|
+
- `backupPath`
|
|
424
|
+
- `updatedFields`
|
|
425
|
+
|
|
426
|
+
#### 失败错误码
|
|
427
|
+
|
|
428
|
+
- `PROVIDERS_NOT_FOUND`
|
|
429
|
+
- `PROVIDERS_PARSE_ERROR`
|
|
430
|
+
- `PROVIDER_NOT_FOUND`
|
|
431
|
+
- `INVALID_ARGUMENT`
|
|
432
|
+
- `BACKUP_FAILED`
|
|
433
|
+
- `ROLLBACK_FAILED`
|
|
434
|
+
|
|
435
|
+
#### 边界
|
|
436
|
+
|
|
437
|
+
- 不支持重命名 provider key
|
|
438
|
+
- 不支持编辑多个 provider
|
|
439
|
+
- 不引入字段级 patch 语法
|
|
440
|
+
|
|
441
|
+
### 7.4 `codexs backups list`
|
|
442
|
+
|
|
443
|
+
#### 用途
|
|
444
|
+
|
|
445
|
+
列出历史备份条目。
|
|
446
|
+
|
|
447
|
+
#### 命令形态
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
codexs backups list [--json] [--codex-dir <path>]
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### 行为
|
|
454
|
+
|
|
455
|
+
- 扫描 `backups/` 目录
|
|
456
|
+
- 忽略 `latest.json`
|
|
457
|
+
- 读取每个备份目录下的 `manifest.json`
|
|
458
|
+
- 按 `createdAt` 倒序输出
|
|
459
|
+
|
|
460
|
+
#### JSON 字段
|
|
461
|
+
|
|
462
|
+
- `backups`
|
|
463
|
+
- `backupId`
|
|
464
|
+
- `createdAt`
|
|
465
|
+
- `reason`
|
|
466
|
+
- `files`
|
|
467
|
+
- `backupPath`
|
|
468
|
+
- `count`
|
|
469
|
+
|
|
470
|
+
#### 失败错误码
|
|
471
|
+
|
|
472
|
+
- `BACKUP_NOT_FOUND`
|
|
473
|
+
- `PROVIDERS_PARSE_ERROR`
|
|
474
|
+
|
|
475
|
+
说明:
|
|
476
|
+
|
|
477
|
+
- `BACKUP_NOT_FOUND` 在这里表示备份目录不存在或为空
|
|
478
|
+
- 若 manifest 结构损坏,可新增专门解析错误,`0.0.4` 先允许复用更具体的新错误码实现
|
|
479
|
+
|
|
480
|
+
#### 边界
|
|
481
|
+
|
|
482
|
+
- 不做分页
|
|
483
|
+
- 不做模糊过滤
|
|
484
|
+
- 不展示文件 diff
|
|
485
|
+
|
|
486
|
+
### 7.5 `codexs rollback <backup-id>`
|
|
487
|
+
|
|
488
|
+
#### 用途
|
|
489
|
+
|
|
490
|
+
恢复指定历史备份。
|
|
491
|
+
|
|
492
|
+
#### 命令形态
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
codexs rollback [<backup-id>] [--json] [--codex-dir <path>]
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
说明:
|
|
499
|
+
|
|
500
|
+
- 不带参数时保持 current latest rollback 语义
|
|
501
|
+
- 带 `backup-id` 时按显式条目恢复
|
|
502
|
+
|
|
503
|
+
#### 行为
|
|
504
|
+
|
|
505
|
+
- 当未传 `backup-id`:沿用 `latest.json`
|
|
506
|
+
- 当传 `backup-id`:加载 `backups/<backup-id>/manifest.json`
|
|
507
|
+
- 恢复 manifest 中列出的所有文件
|
|
508
|
+
- 成功后返回 restored 文件清单
|
|
509
|
+
|
|
510
|
+
#### 交互
|
|
511
|
+
|
|
512
|
+
TTY 下:
|
|
513
|
+
|
|
514
|
+
- latest rollback 保持当前确认方式
|
|
515
|
+
- 指定 `backup-id` 时,也先展示目标备份摘要并确认
|
|
516
|
+
|
|
517
|
+
非交互下:
|
|
518
|
+
|
|
519
|
+
- 不做确认
|
|
520
|
+
|
|
521
|
+
#### 失败错误码
|
|
522
|
+
|
|
523
|
+
- `BACKUP_NOT_FOUND`
|
|
524
|
+
- `ROLLBACK_FAILED`
|
|
525
|
+
|
|
526
|
+
#### 边界
|
|
527
|
+
|
|
528
|
+
- 不支持部分文件回滚
|
|
529
|
+
- 不在 `0.0.4` 做“预览 diff 后再恢复”
|
|
530
|
+
|
|
531
|
+
### 7.6 `codexs import --merge`
|
|
532
|
+
|
|
533
|
+
#### 用途
|
|
534
|
+
|
|
535
|
+
将外部 provider 文件并入当前 registry。
|
|
536
|
+
|
|
537
|
+
#### 命令形态
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
codexs import <file> [--merge] [--json] [--codex-dir <path>]
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
#### 行为
|
|
544
|
+
|
|
545
|
+
- 未带 `--merge`:保持现有整体替换语义
|
|
546
|
+
- 带 `--merge`:
|
|
547
|
+
- 读取外部文件
|
|
548
|
+
- 读取当前 `providers.json`
|
|
549
|
+
- 合并两边 providers
|
|
550
|
+
- 同名冲突时以导入文件为准
|
|
551
|
+
- 写回最终 registry
|
|
552
|
+
|
|
553
|
+
#### 成功输出
|
|
554
|
+
|
|
555
|
+
- `mode`
|
|
556
|
+
- `backupPath`
|
|
557
|
+
- `importedCount`
|
|
558
|
+
- `mergedCount`
|
|
559
|
+
- `replacedProviders`
|
|
560
|
+
|
|
561
|
+
#### 失败错误码
|
|
562
|
+
|
|
563
|
+
- `INVALID_IMPORT_FILE`
|
|
564
|
+
- `PROVIDERS_NOT_FOUND`
|
|
565
|
+
- `PROVIDERS_PARSE_ERROR`
|
|
566
|
+
- `BACKUP_FAILED`
|
|
567
|
+
- `ROLLBACK_FAILED`
|
|
568
|
+
|
|
569
|
+
#### 边界
|
|
570
|
+
|
|
571
|
+
- 不做交互式冲突逐条选择
|
|
572
|
+
- 不支持三方 merge
|
|
573
|
+
|
|
574
|
+
## 8. 错误码设计
|
|
575
|
+
|
|
576
|
+
### 8.1 问题背景
|
|
577
|
+
|
|
578
|
+
当前实现里,`INVALID_IMPORT_FILE` 被复用到了多个不相干场景,例如:
|
|
579
|
+
|
|
580
|
+
- 参数缺失
|
|
581
|
+
- 未知命令
|
|
582
|
+
- 用户取消某些流程
|
|
583
|
+
|
|
584
|
+
这会降低 AI 和脚本的判断质量。
|
|
585
|
+
|
|
586
|
+
### 8.2 `0.0.4` 新错误码
|
|
587
|
+
|
|
588
|
+
建议新增:
|
|
589
|
+
|
|
590
|
+
- `INVALID_ARGUMENT`
|
|
591
|
+
- `UNKNOWN_COMMAND`
|
|
592
|
+
- `PROMPT_CANCELLED`
|
|
593
|
+
- `CODEX_NOT_INSTALLED`
|
|
594
|
+
- `CODEX_VERSION_UNSUPPORTED`
|
|
595
|
+
- `CODEX_DIR_NOT_FOUND`
|
|
596
|
+
- `CODEX_DIR_AMBIGUOUS`
|
|
597
|
+
- `PROVIDERS_ALREADY_EXISTS`
|
|
598
|
+
- `BACKUP_NOT_FOUND`
|
|
599
|
+
|
|
600
|
+
### 8.3 归类原则
|
|
601
|
+
|
|
602
|
+
- 参数问题:`INVALID_ARGUMENT`
|
|
603
|
+
- 命令分发问题:`UNKNOWN_COMMAND`
|
|
604
|
+
- 用户主动取消:`PROMPT_CANCELLED`
|
|
605
|
+
- 环境缺失 / 版本问题:`CODEX_*`
|
|
606
|
+
- 备份定位失败:`BACKUP_NOT_FOUND`
|
|
607
|
+
- 登录失败:`CODEX_LOGIN_FAILED`
|
|
608
|
+
|
|
609
|
+
## 9. 架构与模块设计
|
|
610
|
+
|
|
611
|
+
### 9.1 保持现有四层结构
|
|
612
|
+
|
|
613
|
+
继续沿用:
|
|
614
|
+
|
|
615
|
+
- CLI 层
|
|
616
|
+
- Application 层
|
|
617
|
+
- Domain 层
|
|
618
|
+
- Infrastructure 层
|
|
619
|
+
|
|
620
|
+
不在 `0.0.4` 引入新层次。
|
|
621
|
+
|
|
622
|
+
### 9.2 建议新增模块
|
|
623
|
+
|
|
624
|
+
#### CLI 层
|
|
625
|
+
|
|
626
|
+
建议新增:
|
|
627
|
+
|
|
628
|
+
- `src/cli/setup-interactive.ts`
|
|
629
|
+
- 负责 setup 的交互收集和已有 registry 处理策略选择
|
|
630
|
+
- `src/cli/backups-interactive.ts`
|
|
631
|
+
- 负责 rollback 目标摘要确认
|
|
632
|
+
|
|
633
|
+
建议扩展:
|
|
634
|
+
|
|
635
|
+
- `src/cli/help.ts`
|
|
636
|
+
- `src/cli/output.ts`
|
|
637
|
+
- `src/cli/args.ts`
|
|
638
|
+
|
|
639
|
+
#### Application 层
|
|
640
|
+
|
|
641
|
+
建议新增:
|
|
642
|
+
|
|
643
|
+
- `src/app/setup-codex.ts`
|
|
644
|
+
- `src/app/show-provider.ts`
|
|
645
|
+
- `src/app/edit-provider.ts`
|
|
646
|
+
- `src/app/list-backups.ts`
|
|
647
|
+
- `src/app/rollback-backup.ts`
|
|
648
|
+
|
|
649
|
+
建议扩展:
|
|
650
|
+
|
|
651
|
+
- `src/app/import-providers.ts`
|
|
652
|
+
- `src/app/run-doctor.ts`
|
|
653
|
+
- `src/app/types.ts`
|
|
654
|
+
|
|
655
|
+
#### Domain 层
|
|
656
|
+
|
|
657
|
+
建议新增:
|
|
658
|
+
|
|
659
|
+
- `src/domain/setup.ts`
|
|
660
|
+
- setup 过程中的数据模型和校验
|
|
661
|
+
- `src/domain/backups.ts`
|
|
662
|
+
- backup list / backup id 相关纯逻辑
|
|
663
|
+
|
|
664
|
+
建议扩展:
|
|
665
|
+
|
|
666
|
+
- `src/domain/errors.ts`
|
|
667
|
+
- `src/domain/providers.ts`
|
|
668
|
+
- `src/domain/backup.ts`
|
|
669
|
+
|
|
670
|
+
#### Infrastructure 层
|
|
671
|
+
|
|
672
|
+
建议新增:
|
|
673
|
+
|
|
674
|
+
- `src/infra/codex-discovery.ts`
|
|
675
|
+
- 负责候选 Codex 目录发现
|
|
676
|
+
|
|
677
|
+
建议扩展:
|
|
678
|
+
|
|
679
|
+
- `src/infra/codex-cli.ts`
|
|
680
|
+
- 增加版本读取与版本门槛比较
|
|
681
|
+
- `src/infra/backup-repo.ts`
|
|
682
|
+
- 增加列举指定备份、读取指定 manifest
|
|
683
|
+
- `src/infra/providers-repo.ts`
|
|
684
|
+
- 增加单 provider 读取与 merge 写入辅助
|
|
685
|
+
|
|
686
|
+
### 9.3 依赖方向
|
|
687
|
+
|
|
688
|
+
保持当前依赖方向不变:
|
|
689
|
+
|
|
690
|
+
- `cli -> app`
|
|
691
|
+
- `app -> domain + infra`
|
|
692
|
+
- `infra -> domain`
|
|
693
|
+
- `domain -> none`
|
|
694
|
+
|
|
695
|
+
### 9.4 setup 时序
|
|
696
|
+
|
|
697
|
+
```text
|
|
698
|
+
argv
|
|
699
|
+
-> parseArgs
|
|
700
|
+
-> executeCommand("setup")
|
|
701
|
+
-> app/setup-codex
|
|
702
|
+
-> infra/codex-cli.checkAvailable + readVersion
|
|
703
|
+
-> infra/codex-discovery.findCandidates
|
|
704
|
+
-> cli/setup-interactive (TTY only)
|
|
705
|
+
-> infra/config-repo read config.toml
|
|
706
|
+
-> domain/setup build provider drafts
|
|
707
|
+
-> app/run-mutation
|
|
708
|
+
-> infra/providers-repo write providers.json
|
|
709
|
+
-> app/run-doctor
|
|
710
|
+
-> output
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
### 9.5 rollback with backup-id 时序
|
|
714
|
+
|
|
715
|
+
```text
|
|
716
|
+
argv
|
|
717
|
+
-> parseArgs
|
|
718
|
+
-> executeCommand("rollback")
|
|
719
|
+
-> app/rollback-backup
|
|
720
|
+
-> infra/backup-repo.loadManifestById or loadLatestManifest
|
|
721
|
+
-> cli confirmation (TTY only)
|
|
722
|
+
-> infra/backup-repo.restoreManifest
|
|
723
|
+
-> output
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
## 10. 技术实现细节
|
|
727
|
+
|
|
728
|
+
### 10.1 参数解析
|
|
729
|
+
|
|
730
|
+
`args.ts` 需要支持:
|
|
731
|
+
|
|
732
|
+
- 子命令 `backups list`
|
|
733
|
+
- `rollback` 的可选位置参数 `<backup-id>`
|
|
734
|
+
- `import --merge`
|
|
735
|
+
- `setup --merge`
|
|
736
|
+
- `setup --overwrite`
|
|
737
|
+
|
|
738
|
+
建议:
|
|
739
|
+
|
|
740
|
+
- 保持当前轻量 parser,不引入 commander 等外部解析库
|
|
741
|
+
- 在 parser 结果里把 `backups list` 归一为单一 command key,例如 `backups-list`
|
|
742
|
+
|
|
743
|
+
### 10.2 Codex 版本检查
|
|
744
|
+
|
|
745
|
+
`infra/codex-cli.ts` 需要新增:
|
|
746
|
+
|
|
747
|
+
- `readCodexVersion(): { ok: true; version: string } | { ok: false; cause: string }`
|
|
748
|
+
- `checkCodexVersion(minVersion: string): { ok: boolean; currentVersion?: string; cause?: string }`
|
|
749
|
+
|
|
750
|
+
建议:
|
|
751
|
+
|
|
752
|
+
- 通过 `codex --version` 获取原始文本
|
|
753
|
+
- 在 domain 层做轻量版本字符串解析
|
|
754
|
+
- 最低版本门槛作为常量维护
|
|
755
|
+
|
|
756
|
+
### 10.3 目录发现
|
|
757
|
+
|
|
758
|
+
`codex-discovery.ts` 的职责:
|
|
759
|
+
|
|
760
|
+
- 接收显式 `--codex-dir`
|
|
761
|
+
- 发现默认目录
|
|
762
|
+
- 未来可扩展更多候选目录策略
|
|
763
|
+
|
|
764
|
+
`0.0.4` 建议最小实现:
|
|
765
|
+
|
|
766
|
+
- 当前先支持默认目录 + 显式目录
|
|
767
|
+
- 保留接口为返回候选列表,避免以后重写调用链
|
|
768
|
+
|
|
769
|
+
### 10.4 provider merge
|
|
770
|
+
|
|
771
|
+
`import --merge` 合并算法:
|
|
772
|
+
|
|
773
|
+
- 读取当前 registry
|
|
774
|
+
- 读取导入 registry
|
|
775
|
+
- 浅层按 provider name 合并
|
|
776
|
+
- 冲突时导入侧覆盖本地
|
|
777
|
+
- 使用 deterministic key ordering 写回
|
|
778
|
+
|
|
779
|
+
### 10.5 show 的敏感字段输出
|
|
780
|
+
|
|
781
|
+
文本模式:
|
|
782
|
+
|
|
783
|
+
- `apiKey` 只显示掩码,例如前 3 后 2
|
|
784
|
+
|
|
785
|
+
JSON 模式:
|
|
786
|
+
|
|
787
|
+
- 明确标注这是本地机器可读输出
|
|
788
|
+
- 默认允许返回完整 `apiKey`
|
|
789
|
+
|
|
790
|
+
### 10.6 edit 的字段更新
|
|
791
|
+
|
|
792
|
+
建议先使用“完整对象重写”而不是字段级 patch 存储。
|
|
793
|
+
|
|
794
|
+
原因:
|
|
795
|
+
|
|
796
|
+
- 当前 `providers.json` 结构小
|
|
797
|
+
- 现有 repo 已有整体读写能力
|
|
798
|
+
- 更容易复用现有 backup/mutation 模型
|
|
799
|
+
|
|
800
|
+
### 10.7 backup 枚举
|
|
801
|
+
|
|
802
|
+
`backup-repo.ts` 需要:
|
|
803
|
+
|
|
804
|
+
- 枚举 `backups/` 下所有目录
|
|
805
|
+
- 过滤非目录项和 `latest.json`
|
|
806
|
+
- 尝试读取每个 `manifest.json`
|
|
807
|
+
- 若某一条 manifest 损坏,建议该条以 warning 形式跳过,而不是让整个 `backups list` 失败
|
|
808
|
+
|
|
809
|
+
## 11. 测试设计
|
|
810
|
+
|
|
811
|
+
### 11.1 CLI 测试
|
|
812
|
+
|
|
813
|
+
需要覆盖:
|
|
814
|
+
|
|
815
|
+
- `setup` 在非交互缺参数或多目录冲突时的失败 envelope
|
|
816
|
+
- `show` 成功和 provider 不存在
|
|
817
|
+
- `edit` 显式字段更新
|
|
818
|
+
- `backups list` 返回排序结果
|
|
819
|
+
- `rollback <backup-id>` 成功与目标不存在
|
|
820
|
+
- `import --merge` 冲突覆盖语义
|
|
821
|
+
|
|
822
|
+
### 11.2 Application 测试
|
|
823
|
+
|
|
824
|
+
需要覆盖:
|
|
825
|
+
|
|
826
|
+
- setup draft 生成与已有 registry 策略
|
|
827
|
+
- edit 更新字段集合计算
|
|
828
|
+
- merge 导入结果
|
|
829
|
+
- 指定 manifest 回滚
|
|
830
|
+
|
|
831
|
+
### 11.3 Domain 测试
|
|
832
|
+
|
|
833
|
+
需要覆盖:
|
|
834
|
+
|
|
835
|
+
- 版本比较
|
|
836
|
+
- backupId 解析
|
|
837
|
+
- provider merge 纯逻辑
|
|
838
|
+
- `apiKey` 掩码逻辑
|
|
839
|
+
|
|
840
|
+
### 11.4 Fixture 设计
|
|
841
|
+
|
|
842
|
+
建议新增 fixture:
|
|
843
|
+
|
|
844
|
+
- 多 profile config
|
|
845
|
+
- 已存在 providers 的 setup 场景
|
|
846
|
+
- 多个历史备份目录
|
|
847
|
+
- 损坏 manifest 场景
|
|
848
|
+
|
|
849
|
+
## 12. 验收标准
|
|
850
|
+
|
|
851
|
+
`0.0.4` 设计落地后,至少应满足:
|
|
852
|
+
|
|
853
|
+
- 用户可以通过 `setup` 完成首次初始化
|
|
854
|
+
- `show` 能查看单个 provider
|
|
855
|
+
- `edit` 能稳定更新单个 provider
|
|
856
|
+
- `backups list` 能列出历史备份
|
|
857
|
+
- `rollback <backup-id>` 能恢复指定备份
|
|
858
|
+
- `import --merge` 能按导入侧覆盖策略写回
|
|
859
|
+
- 新增错误码足以覆盖参数、环境、取消、备份定位等核心场景
|
|
860
|
+
- 所有新增写命令继续沿用锁、备份、回滚模型
|
|
861
|
+
|
|
862
|
+
## 13. 后续演进接口
|
|
863
|
+
|
|
864
|
+
这份设计刻意为后续能力留了接口,但不在 `0.0.4` 落地:
|
|
865
|
+
|
|
866
|
+
- 更复杂的目录发现策略
|
|
867
|
+
- 更复杂的 tag patch 语法
|
|
868
|
+
- 交互式 import 冲突逐条选择
|
|
869
|
+
- 第三方 auth provider 接入
|
|
870
|
+
- 本地代理和依赖安装
|
|
871
|
+
|
|
872
|
+
## 14. 结论
|
|
873
|
+
|
|
874
|
+
`0.0.4` 的本质不是再堆几个命令,而是把 codex-switch 从“已经能用的切换工具”推进到“具备初始化、精细查看编辑、历史恢复、结构化错误语义”的下一阶段。技术上不需要推翻当前四层结构,只需要围绕现有 parser、mutation orchestration、backup repo 和 provider repo 做有边界的增量扩展。
|