@minniexcode/codex-switch 0.0.10 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.AI.md +68 -73
  2. package/README.CN.md +108 -111
  3. package/README.md +87 -80
  4. package/dist/app/add-provider.js +29 -15
  5. package/dist/app/bridge.js +15 -14
  6. package/dist/app/edit-provider.js +1 -1
  7. package/dist/app/get-status.js +21 -9
  8. package/dist/app/import-providers.js +1 -1
  9. package/dist/app/init-codex.js +13 -14
  10. package/dist/app/list-providers.js +48 -1
  11. package/dist/app/remove-provider.js +1 -1
  12. package/dist/app/run-doctor.js +12 -5
  13. package/dist/app/run-mutation.js +3 -2
  14. package/dist/app/setup-codex.js +3 -1
  15. package/dist/app/switch-provider.js +11 -13
  16. package/dist/cli/output.js +145 -18
  17. package/dist/cli.js +34 -2
  18. package/dist/commands/args.js +2 -2
  19. package/dist/commands/dispatch.js +40 -0
  20. package/dist/commands/handlers.js +130 -161
  21. package/dist/commands/help.js +11 -5
  22. package/dist/commands/registry.js +42 -20
  23. package/dist/domain/backups.js +4 -4
  24. package/dist/domain/config.js +110 -5
  25. package/dist/domain/providers.js +12 -0
  26. package/dist/domain/runtime-state.js +111 -13
  27. package/dist/infra/config-repo.js +16 -206
  28. package/dist/interaction/interactive.js +16 -6
  29. package/dist/runtime/copilot-adapter.js +12 -12
  30. package/dist/runtime/copilot-bridge.js +394 -45
  31. package/dist/runtime/copilot-cli.js +84 -12
  32. package/dist/runtime/copilot-installer.js +10 -9
  33. package/dist/runtime/copilot-sdk-loader.js +5 -5
  34. package/dist/storage/backup-repo.js +4 -4
  35. package/dist/storage/codex-paths.js +34 -8
  36. package/dist/storage/config-repo.js +0 -23
  37. package/dist/storage/lock-repo.js +2 -4
  38. package/dist/storage/runtime-state-repo.js +14 -13
  39. package/dist/storage/tool-config-repo.js +111 -0
  40. package/docs/Design/codex-switch-v0.0.11-design.md +824 -0
  41. package/docs/Design/codex-switch-v0.0.12-design.md +343 -0
  42. package/docs/PRD/codex-switch-prd-v0.0.11.md +577 -0
  43. package/docs/PRD/codex-switch-prd-v0.0.12.md +279 -0
  44. package/docs/PRD/codex-switch-prd-v0.1.0.md +125 -237
  45. package/docs/Tests/testing.md +39 -112
  46. package/docs/cli-usage.md +135 -565
  47. package/docs/codex-switch-command-design.md +3 -0
  48. package/docs/codex-switch-product-overview.md +52 -207
  49. package/docs/codex-switch-technical-architecture.md +3 -0
  50. package/package.json +1 -1
  51. package/dist/app/rollback-latest.js +0 -26
@@ -0,0 +1,824 @@
1
+ # codex-switch `0.0.11` 设计文档
2
+
3
+ ## 文档信息
4
+
5
+ - 文档类型:详细设计文档
6
+ - 适用版本:`0.0.11`
7
+ - 目标范围:`0.0.10 -> 0.0.11`
8
+ - 对应 PRD:[`../PRD/codex-switch-prd-v0.0.11.md`](../PRD/codex-switch-prd-v0.0.11.md)
9
+ - 关联上一版设计:[`./codex-switch-v0.0.10-design.md`](./codex-switch-v0.0.10-design.md)
10
+ - 关联专项设计:[`./codex-switch-copilot-integration-design.md`](./codex-switch-copilot-integration-design.md)
11
+
12
+ ## 1. 文档目标
13
+
14
+ 本设计文档用于把 `0.0.11` 的结构性变更收口到“实现者无需再补关键决策”的程度。文档必须直接回答以下问题:
15
+
16
+ - `codex-switch` 的 tool home 与目标 `codexDir` 如何彻底拆分,哪些文件归哪一层负责
17
+ - `codex-switch.json` 的最小稳定 contract 是什么,默认 `codexDir` 解析优先级如何固定
18
+ - `codexs login <upstream>` 的命令定位、主流程、失败边界和首版 `copilot` 语义是什么
19
+ - `add --copilot` 在 `0.0.11` 后到底还负责什么,不再负责什么
20
+ - 当前开发阶段不需要哪些兼容性/迁移逻辑,哪些历史状态允许手动处理
21
+ - `init`、direct provider、bridge、backup、rollback、`status`、`doctor` 在新路径模型下的最小可用实现边界是什么
22
+ - 哪些错误码、输出语义和测试场景必须被 `0.0.11` design 正式固定
23
+
24
+ 本设计只覆盖 `0.0.11` 的文档与实现契约,不顺手扩展成多 upstream 平台方案、GUI 模型、长期双写兼容层、自动迁移层或新的大 JSON 契约。
25
+
26
+ ## 2. 版本定位
27
+
28
+ `0.0.11` 是一次工具边界重构版本,不是单个命令补丁版本。
29
+
30
+ 它的目标不是“给现有 Copilot 路径补一个 `login` 命令”,也不是“把几个路径从 `~/.codex` 改到别处”。本版要解决的是:`codex-switch` 终于拥有独立且稳定的工具级 home 边界,并把上游登录从 provider mutation 命令里拆出来。
31
+
32
+ 同时,本版的实现策略明确偏向开发期最小落地,而不是 release 兼容性工程:
33
+
34
+ - 当前工具只有单用户自用场景
35
+ - `0.0.11` 到手动确认的 `0.1.0 release` 之前,都按开发版本处理
36
+ - 不为了历史状态、低价值升级路径或“也许以后会用到”的兼容故事引入污染性代码
37
+ - 旧状态允许手动清理、手动迁移或直接重新 `add provider`
38
+
39
+ 这意味着 `0.0.11` 要同时完成两类收口:
40
+
41
+ 1. 存储模型收口
42
+ - `providers.json`
43
+ - `backups/`
44
+ - lock 文件
45
+ - runtime state
46
+ - runtime install
47
+ 必须统一迁到 tool home
48
+ 2. 命令职责收口
49
+ - `login` 负责 upstream onboarding / auth readiness
50
+ - `add --copilot` 负责 provider precondition validation 与 registry mutation
51
+ - `switch` 继续负责最终 runtime gate 与 config/auth projection
52
+
53
+ 如果这两条线只完成其中一条,`0.0.11` 就不算完成。
54
+
55
+ ## 3. 设计原则
56
+
57
+ `0.0.11` 必须遵循以下原则:
58
+
59
+ 1. 工具管理态与目标 runtime 状态严格分层。
60
+ 2. `providers.json` 是 `codex-switch` tool home 内的管理态 SSOT。
61
+ 3. `config.toml` 与 `auth.json` 继续属于目标 `codexDir`,不承载 `codex-switch` registry、backup 或 runtime install。
62
+ 4. upstream login 是 onboarding / auth 能力,不是 provider mutation 能力。
63
+ 5. 开发阶段优先最小实现,不为一次性历史状态引入自动迁移或长期兼容层。
64
+ 6. 本版只真实落地 Copilot upstream,但目录模型和命令模型必须给未来 upstream 预留扩展位。
65
+ 7. design 文档以 `0.0.11` PRD 为事实源;若当前实现存在未完成或旧行为,设计稿应明确目标契约,而不是被旧实现反向锁死。
66
+ 8. `0.1.0` 只有在用户手动明确为 release 时才按 release 语义看待;否则仍按开发版本处理。
67
+
68
+ ## 4. 数据边界与路径模型
69
+
70
+ ### 4.1 双路径模型
71
+
72
+ `0.0.11` 起,CLI 的路径模型不再是“所有路径都从 `codexDir` 推导”。实现必须正式转为双路径模型:
73
+
74
+ - tool home 路径
75
+ - target Codex runtime 路径
76
+
77
+ 这两个路径只在命令执行时被同时解析,但职责独立。
78
+
79
+ ### 4.2 tool home 默认位置
80
+
81
+ 本版固定默认 tool home:
82
+
83
+ - Windows:`~/.config/codex-switch`
84
+
85
+ 旧的 `~/.codex-switch` 不再是默认主 home。本设计不要求自动读取、自动搬运或兼容保留旧 home 中的运行态数据。
86
+
87
+ ### 4.3 `CodexPaths` 稳定语义
88
+
89
+ `createCodexPaths` 需要产出以下稳定语义:
90
+
91
+ - `toolHomeDir`
92
+ - `toolConfigPath`
93
+ - `providersPath`
94
+ - `backupsDir`
95
+ - `latestBackupPath`
96
+ - `lockPath`
97
+ - `runtimeDir`
98
+ - `runtimesDir`
99
+ - `codexDir`
100
+ - `configPath`
101
+ - `authPath`
102
+
103
+ 其中:
104
+
105
+ - 由 tool home 派生:
106
+ - `toolConfigPath`
107
+ - `providersPath`
108
+ - `backupsDir`
109
+ - `latestBackupPath`
110
+ - `lockPath`
111
+ - `runtimeDir`
112
+ - `runtimesDir`
113
+ - 由 target `codexDir` 派生:
114
+ - `configPath`
115
+ - `authPath`
116
+
117
+ ### 4.4 tool home 文件职责
118
+
119
+ `0.0.11` 固定以下文件归属于 tool home:
120
+
121
+ - `codex-switch.json`
122
+ - 工具级配置文件
123
+ - `providers.json`
124
+ - provider registry SSOT
125
+ - `backups/`
126
+ - managed mutation backups
127
+ - `runtime/`
128
+ - runtime state,例如 `copilot-bridge-state.json`
129
+ - `runtimes/`
130
+ - optional runtime install,例如 Copilot SDK
131
+ - lock 文件
132
+ - `codex-switch` 写操作锁
133
+
134
+ ### 4.5 target `codexDir` 文件职责
135
+
136
+ 目标 `codexDir` 继续只承担目标 Codex runtime 文件:
137
+
138
+ - `config.toml`
139
+ - `auth.json`
140
+
141
+ 这些文件继续被 `switch`、`status`、`doctor`、`config show` 等命令使用,但它们不再承载 `codex-switch` 自己的 registry、backup 或 lock 语义。
142
+
143
+ ### 4.6 明确删除的旧语义
144
+
145
+ `0.0.11` design 必须明确删除以下旧叙述:
146
+
147
+ - `providers.json` 属于目标 `codexDir`
148
+ - `backups/` 属于目标 `codexDir`
149
+ - `codex-switch` lock 文件属于目标 `codexDir`
150
+ - runtime install 和 runtime state 可以散落在 tool home 之外
151
+ - `config.toml` / `auth.json` 承载 `codex-switch` registry 或 backup
152
+
153
+ ### 4.7 开发期历史状态处理原则
154
+
155
+ 对于旧版本遗留状态,本版采用手动处理原则,而不是自动兼容原则:
156
+
157
+ - 不自动迁移旧 `providers.json`
158
+ - 不自动迁移旧 `backups/`
159
+ - 不自动迁移旧 lock 文件
160
+ - 不自动迁移旧 `~/.codex-switch` runtime/state
161
+ - 若用户需要保留旧 provider,可手动重新 `add provider`
162
+ - 若用户需要保留旧备份,可手动拷贝或直接放弃
163
+
164
+ 设计目标是避免把一次性过渡需求固化为长期维护逻辑。
165
+
166
+ ## 5. Tool Config 设计
167
+
168
+ ### 5.1 配置文件
169
+
170
+ 新增工具级配置文件:
171
+
172
+ - `codex-switch.json`
173
+
174
+ 它位于 tool home 根目录,是 tool-level config 的唯一稳定入口。
175
+
176
+ ### 5.2 最小稳定字段
177
+
178
+ `0.0.11` 只固定最小稳定字段:
179
+
180
+ - `version`
181
+ - `defaultCodexDir`
182
+
183
+ 其中:
184
+
185
+ - `version`
186
+ - 记录 tool config 写入版本或格式版本元信息
187
+ - `defaultCodexDir`
188
+ - 用于在未显式指定 `--codex-dir` 时,解析默认目标 Codex 目录
189
+
190
+ ### 5.2.1 `defaultCodexDir` 写入策略
191
+
192
+ `0.0.11` 对 `defaultCodexDir` 的写入策略固定为:
193
+
194
+ - 只有当次命令显式传入 `--codex-dir` 时,`init` 才允许写入 `defaultCodexDir`
195
+ - 写入值仅限于用户显式传入的 `--codex-dir`
196
+ - 若 `codex-switch.json` 已存在,则 `init` 不覆盖已有 `defaultCodexDir`
197
+ - 若当次 `codexDir` 来自环境变量、已有 config、开发 sandbox 或 `~/.codex` fallback,则 `init` 不写入 `defaultCodexDir`
198
+ - 本版不引入单独的“set default codex dir”命令
199
+
200
+ 这意味着 `defaultCodexDir` 在 `0.0.11` 中只持久化显式用户选择,不持久化解析链中的 fallback 值。开发 sandbox、`~/.codex` 或临时环境变量可以参与当前命令解析,但不会因为执行一次 `init` 就被固化成长期默认值。
201
+
202
+ ### 5.3 明确不放进 `codex-switch.json` 的内容
203
+
204
+ 本版明确不把以下内容放入 `codex-switch.json`:
205
+
206
+ - provider registry
207
+ - backup manifest
208
+ - per-upstream runtime 策略
209
+ - per-workspace / per-provider 路由规则
210
+ - 多 profile 编辑器语义
211
+
212
+ ### 5.4 默认 `codexDir` 解析优先级
213
+
214
+ 本版固定默认目标 `codexDir` 的解析优先级为:
215
+
216
+ 1. `--codex-dir`
217
+ 2. 环境变量 `CODEXS_CODEX_DIR`
218
+ 3. `codex-switch.json.defaultCodexDir`
219
+ 4. 开发环境默认 sandbox
220
+ 5. `~/.codex`
221
+
222
+ 这个优先级属于公开 contract,相关帮助文案、错误消息、`init` 结果和测试都必须使用同一顺序。
223
+
224
+ ### 5.5 CLI 启动解析顺序
225
+
226
+ 除了优先级之外,本版还固定命令启动阶段的解析顺序。实现必须按以下顺序进入命令逻辑:
227
+
228
+ 1. 解析原始 CLI 参数与 flags
229
+ 2. 先 resolve tool home
230
+ 3. 读取 tool home 下的 `codex-switch.json`,若存在则校验其最小结构
231
+ 4. 再基于以下优先级 resolve `codexDir`
232
+ - `--codex-dir`
233
+ - `CODEXS_CODEX_DIR`
234
+ - `codex-switch.json.defaultCodexDir`
235
+ - 开发环境默认 sandbox
236
+ - `~/.codex`
237
+ 5. 用已解析出的 `toolHomeDir` 与 `codexDir` 构造 `CodexPaths`
238
+ 6. 命令 handler 只消费已经解析完成的 paths,不再各自重复推导默认 `codexDir`
239
+
240
+ 这条顺序属于实现前提,而不是建议。否则 `defaultCodexDir` 会停留在文档字段层,无法稳定接入命令流。
241
+
242
+ ## 6. `init` 详细设计
243
+
244
+ ### 6.1 新语义
245
+
246
+ `init` 不再以“初始化某个 `codexDir/providers.json`”为核心,而应转为纯 tool-home 初始化命令:
247
+
248
+ - 确保 tool home 已初始化
249
+ - 确保 `codex-switch.json` 存在
250
+ - 确保 `providers.json` 存在
251
+
252
+ ### 6.2 行为约束
253
+
254
+ `init`:
255
+
256
+ - 可以创建缺失的 tool home
257
+ - 可以创建缺失的 `providers.json`
258
+ - 可以创建缺失的 `codex-switch.json`
259
+ - 不解析 `config.toml` 或 `auth.json` 的存在性
260
+ - 不创建 target `codexDir`
261
+ - 不检查 target `codexDir` 是否存在
262
+ - 不写入任何 target runtime 文件
263
+
264
+ ### 6.3 结果语义
265
+
266
+ `init` 成功结果必须能表达:
267
+
268
+ - tool home 是否新建
269
+ - tool config 是否新建
270
+ - provider registry 是否新建
271
+
272
+ 当前旧结果中以 `createdCodexDir` / `configExists` / `authExists` 为中心的说法,需要在 `0.0.11` 中删除。`init` 的成功结果只描述 tool-home 初始化结果,不混入 target runtime 状态。
273
+
274
+ ## 7. `login` 命令设计
275
+
276
+ ### 7.1 命令面
277
+
278
+ 新增命令:
279
+
280
+ - `codexs login <upstream>`
281
+
282
+ 首版支持:
283
+
284
+ - `copilot`
285
+
286
+ 可接受别名:
287
+
288
+ - `github-copilot`
289
+
290
+ 内部二者归一为同一 upstream id。
291
+
292
+ ### 7.2 命令定位
293
+
294
+ `login` 是 upstream auth / onboarding 命令,不是 provider mutation 命令。
295
+
296
+ 因此它:
297
+
298
+ - 不写入 `providers.json`
299
+ - 不直接改写 `config.toml`
300
+ - 不直接改写 `auth.json`
301
+ - 不创建 provider
302
+ - 不删除 provider
303
+ - 不切换 active profile
304
+
305
+ ### 7.3 非支持输入
306
+
307
+ 首版 `login` 只接受已知 upstream 词汇。
308
+
309
+ 未知 upstream 必须失败为 `INVALID_ARGUMENT` 或等价明确错误,而不是静默接受字符串后进入空分支。
310
+
311
+ ### 7.4 TTY 边界
312
+
313
+ `login copilot` 只支持交互式 TTY。
314
+
315
+ 因此:
316
+
317
+ - 非 TTY 调用失败
318
+ - `--json` 调用失败
319
+ - 失败必须明确说明该命令需要交互式登录环境
320
+
321
+ 设计目标是避免“部分执行后才失败”的半吊子 contract。
322
+
323
+ ## 8. `login copilot` 详细设计
324
+
325
+ ### 8.1 成功定义
326
+
327
+ `login copilot` 成功的定义是:
328
+
329
+ - 本地 runtime 已可用
330
+ - Copilot auth readiness recheck 成功
331
+
332
+ 它不要求:
333
+
334
+ - 创建 provider
335
+ - 修改 active profile
336
+ - 修改 `config.toml`
337
+ - 修改 `auth.json`
338
+
339
+ ### 8.2 主流程
340
+
341
+ `login copilot` 的主流程固定为:
342
+
343
+ 1. 确认当前为 TTY
344
+ 2. 检查本地 Copilot SDK runtime 是否已安装
345
+ 3. 缺失时询问是否立即安装 SDK
346
+ 4. SDK 就绪后执行 auth readiness 检查
347
+ 5. 若 auth 已就绪,则直接成功返回
348
+ 6. 若 auth 未就绪,则检查系统级官方 `copilot` CLI 是否可用
349
+ 7. CLI 可用时启动官方 `copilot login`
350
+ 8. 登录返回后做一次显式 recheck
351
+ 9. recheck 成功则返回成功;失败则返回明确错误与下一步提示
352
+
353
+ ### 8.3 实现前提与职责拆分
354
+
355
+ `login copilot` 在 `0.0.11` 中依赖两个彼此独立的前提,它们不能混写为一个“本地 runtime”概念:
356
+
357
+ 1. tool home 本地安装的 `@github/copilot-sdk`
358
+ - 用于 auth readiness probe
359
+ - 用于后续 bridge/runtime-backed provider 能力
360
+ - 由 `codex-switch` 负责安装与探测
361
+ 2. 系统级官方 `copilot` CLI
362
+ - 用于执行真实的 `copilot login`
363
+ - 不由 `codex-switch` 安装
364
+ - 仍视为外部依赖
365
+
366
+ 因此,本版明确选择以下模型:
367
+
368
+ - `codex-switch` 只安装和管理本地 Copilot SDK
369
+ - `codex-switch` 不安装官方 `copilot` CLI
370
+ - `login copilot` 的登录动作只通过系统级 `copilot login` 完成
371
+ - 若系统中没有可用的 `copilot` CLI,则命令失败并提示用户先自行安装官方 CLI
372
+
373
+ 这也是 `0.0.11` 唯一可实现且与当前代码结构一致的模型。
374
+
375
+ ### 8.4 官方 CLI 启动语义
376
+
377
+ `login copilot` 不存在“优先使用 tool home 本地 launcher”的语义,因为当前 tool home 安装物是 SDK,不是官方 CLI。
378
+
379
+ 因此启动语义固定为:
380
+
381
+ 1. SDK 缺失时,先处理 SDK 安装
382
+ 2. SDK 存在但 auth 未就绪时,检查系统级 `copilot` CLI
383
+ 3. 系统级 CLI 缺失则失败
384
+ 4. 系统级 CLI 可用则执行 `copilot login`
385
+
386
+ 设计上不要求:
387
+
388
+ - 在 tool home 内安装官方 `copilot` CLI
389
+ - 同时维护“本地官方 CLI + 系统官方 CLI”双来源
390
+ - 为 `login copilot` 增加第二套官方 launcher 管理逻辑
391
+
392
+ ### 8.5 本地 runtime install 归属
393
+
394
+ Copilot SDK runtime install 必须归属于 tool home:
395
+
396
+ - 位于 `runtimes/` 下
397
+
398
+ Copilot runtime install 的公开叙述不能再使用 `~/.codex-switch` 作为当前主 home。这里的 runtime install 只指 SDK,不包含官方 `copilot` CLI。
399
+
400
+ ### 8.6 交互式安装语义
401
+
402
+ 当 SDK 缺失时:
403
+
404
+ - TTY 下可询问用户是否立即安装
405
+ - 用户确认后再安装
406
+ - 用户拒绝时命令终止,不继续进入 auth probe 或 launcher 流程
407
+
408
+ 安装成功后必须立即执行 auth readiness probe,而不是等下游 `add --copilot` 或 `switch` 再发现缺 auth。
409
+
410
+ ### 8.7 登录语义
411
+
412
+ 当 auth readiness probe 失败时:
413
+
414
+ - 若系统级 `copilot` CLI 可用,则直接启动官方登录流程
415
+ - `codex-switch` 不托管 GitHub/Copilot token
416
+ - browser / device-code / 官方提示体验完全委托给官方 tooling
417
+
418
+ 命令返回后必须做一次显式 recheck。`login copilot` 的成功不能只以“launcher 成功启动过”作为判据。
419
+
420
+ ### 8.8 失败边界
421
+
422
+ 至少要能清楚表达以下失败类型,并固定到明确的命令错误码:
423
+
424
+ - 当前非 TTY,无法完成交互式登录
425
+ - SDK 安装失败
426
+ - 系统级 `copilot` CLI 缺失
427
+ - `copilot login` 启动失败
428
+ - 登录返回后 recheck 仍未通过
429
+
430
+ 这些失败必须继续沿用 CLI `error.code` 层,而不是塞进 `doctor.data.issues[]` 或 warning-only 路径。
431
+
432
+ ### 8.9 `login copilot` 错误码 contract
433
+
434
+ 本版把 `login copilot` 的关键失败固定为以下命令错误码:
435
+
436
+ - `COPILOT_LOGIN_REQUIRES_TTY`
437
+ - 用于非 TTY 或 `--json` 调用 `login copilot`
438
+ - `COPILOT_SDK_INSTALL_FAILED`
439
+ - 用于 SDK 安装失败
440
+ - `COPILOT_CLI_MISSING`
441
+ - 用于系统级官方 `copilot` CLI 不可用
442
+ - `COPILOT_LOGIN_LAUNCH_FAILED`
443
+ - 用于 `copilot login` 无法启动或退出非零
444
+ - `COPILOT_LOGIN_RECHECK_FAILED`
445
+ - 用于 `copilot login` 返回后,auth readiness recheck 仍未通过
446
+
447
+ 同时保留以下既有错误码语义:
448
+
449
+ - `COPILOT_SDK_MISSING`
450
+ - 用于非 `login` 命令在前提检查阶段发现 SDK 缺失,例如 `add --copilot`、`switch`
451
+ - `COPILOT_AUTH_REQUIRED`
452
+ - 用于非 `login` 命令在前提检查阶段发现 auth 未就绪,例如 `add --copilot`、`switch`
453
+ - `INVALID_ARGUMENT`
454
+ - 用于未知 upstream、非法参数组合等普通参数错误,不再复用于 `login copilot` 的 TTY/launcher/recheck 失败
455
+
456
+ 设计意图是把“参数错误”“前提缺失”“登录流程失败”三类问题彻底分开,避免实现者把不同失败随手塞回旧错误码。
457
+
458
+ ## 9. `add --copilot` 语义调整
459
+
460
+ ### 9.1 新定位
461
+
462
+ `0.0.11` 后,`add --copilot` 只负责:
463
+
464
+ - 创建 Copilot provider
465
+ - 验证 runtime / auth 前提
466
+ - 在前提满足时写入 provider registry
467
+
468
+ 它不再负责:
469
+
470
+ - 安装 Copilot SDK
471
+ - 启动官方 Copilot login
472
+ - 编排完整安装 + 登录交互主流程
473
+
474
+ ### 9.2 失败语义
475
+
476
+ 当前提缺失时:
477
+
478
+ - 缺 runtime:
479
+ - 返回 `COPILOT_SDK_MISSING`
480
+ - 提示执行 `codexs login copilot`
481
+ - 缺 auth:
482
+ - 返回 `COPILOT_AUTH_REQUIRED`
483
+ - 提示执行 `codexs login copilot`
484
+
485
+ 本版要求是把推荐主路径切到 `login copilot`,而不是继续把用户引导回旧的 `add --install-copilot-sdk`。
486
+
487
+ ### 9.3 `--install-copilot-sdk`
488
+
489
+ `0.0.11` 的设计目标是让安装主流程退出 `add --copilot`,并把入口统一到 `login copilot`。因此本版对外语义固定为:
490
+
491
+ - `add --copilot --install-copilot-sdk` 不再执行 SDK 安装
492
+ - 该 flag 保留为兼容输入壳层,但命令必须直接失败
493
+ - 失败时使用明确错误,提示改用 `codexs login copilot`
494
+ - 帮助文案中不再把该 flag 描述为受支持主路径
495
+
496
+ 本版不允许把该 flag 解释为:
497
+
498
+ - “仅安装 SDK”
499
+ - “继续安装 SDK 但不 login”
500
+ - “实现者可自行决定是否还生效”
501
+
502
+ 设计选择已经固定:保留输入兼容壳层,但调用即报错并引导到 `login copilot`。
503
+
504
+ ## 10. 历史状态与开发期兼容策略
505
+
506
+ ### 10.1 不做自动迁移
507
+
508
+ `0.0.11` 不实现首次运行自动迁移,也不实现命令前自动迁移 preflight。
509
+
510
+ 当前设计中,历史状态处理由用户自行决定:
511
+
512
+ - 手动删除旧状态
513
+ - 手动复制需要保留的文件
514
+ - 直接重新 `add provider`
515
+
516
+ ### 10.2 不做兼容读写层
517
+
518
+ 本版不要求:
519
+
520
+ - 读取旧 `codexDir/providers.json` 作为 fallback
521
+ - 读取旧 `codexDir/backups/` 作为 fallback
522
+ - 读取旧 `~/.codex-switch` runtime/state 作为 fallback
523
+ - 新旧路径双读
524
+ - 新旧路径双写
525
+ - 启动时冲突检测与自动修复
526
+
527
+ 实现可以假定:一旦进入 `0.0.11` 开发模型,tool home 就是唯一有效管理态位置。
528
+
529
+ ### 10.3 手动处理优先于代码兼容
530
+
531
+ 如果旧状态与新布局不一致,本版推荐手动处理,而不是增加代码复杂度:
532
+
533
+ - provider 丢失可重新 `add provider`
534
+ - 旧 backup 可放弃,或由用户手动整理
535
+ - 旧 runtime/state 可直接清理
536
+
537
+ 这一选择是开发阶段决策,不视为缺陷。
538
+
539
+ ## 11. runtime state 与 runtime install 设计
540
+
541
+ ### 11.1 runtime state 归属
542
+
543
+ Copilot bridge runtime state 必须明确归属于 tool home:
544
+
545
+ - 位于 `runtime/` 下
546
+
547
+ 例如:
548
+
549
+ - `runtime/copilot-bridge-state.json`
550
+
551
+ ### 11.2 runtime install 归属
552
+
553
+ Copilot SDK runtime install 必须明确归属于 tool home:
554
+
555
+ - 位于 `runtimes/` 下
556
+
557
+ 例如:
558
+
559
+ - `runtimes/copilot/`
560
+
561
+ ### 11.3 与 backup 的关系
562
+
563
+ runtime state 继续保持在 managed backup 事务外:
564
+
565
+ - backup 不承诺捕获 runtime state
566
+ - rollback 不承诺恢复 bridge 进程
567
+ - `status` / `doctor` 负责解释 runtime state 是否 missing、stale 或 mismatch
568
+
569
+ 这条边界在 `0.0.11` 中继续保持,不因为路径迁移而重新引入 runtime-state 强事务承诺。
570
+
571
+ ## 12. 命令影响面与最小兼容边界
572
+
573
+ ### 12.1 必须保持可用的工作流
574
+
575
+ 在新路径模型下,以下工作流必须保持行为稳定:
576
+
577
+ - direct provider add / edit / remove / switch
578
+ - backup / rollback
579
+ - `status`
580
+ - `doctor`
581
+ - `bridge start`
582
+ - `bridge stop`
583
+ - `bridge status`
584
+ - 端口恢复后 provider/config 投影写回
585
+
586
+ 这里的“稳定”是指:在 `0.0.11` 新布局内可正常工作,而不是要求兼容旧布局数据。
587
+
588
+ ### 12.2 direct provider 最小边界
589
+
590
+ 本版虽然引入新的 tool home,但 direct provider 工作流不应回归。用户仍应能:
591
+
592
+ - 使用新 home 内的 provider registry
593
+ - 正常投影到目标 `config.toml`
594
+ - 正常写入或读取目标 `auth.json`
595
+
596
+ ### 12.3 Copilot provider 最小边界
597
+
598
+ Copilot provider 继续保留当前 bridge / runtime 路由的核心语义,但其 install 与 login 入口改由 `login copilot` 承担。
599
+
600
+ 这意味着:
601
+
602
+ - `switch` 仍是最终 runtime gate 权威入口
603
+ - `status` / `doctor` 仍可基于 active provider 输出 Copilot runtime 诊断
604
+ - `bridge` 命令族仍使用同一 runtime-state 与 provider binding 模型
605
+
606
+ ### 12.4 帮助与文案调整
607
+
608
+ 帮助文案、CLI usage、错误建议必须统一到以下主叙述:
609
+
610
+ - `login` 是 upstream onboarding 命令
611
+ - `add --copilot` 不再承担 install/login 主流程
612
+ - 当缺 runtime 或 auth 时,下一步推荐为 `codexs login copilot`
613
+
614
+ ### 12.5 开发版本语义
615
+
616
+ 从现在开始到用户手动确认 release 之前,所有版本都按开发版本处理,包括名义上的 `0.1.0`。
617
+
618
+ 因此本版不为了“未来可能发布”而提前加入:
619
+
620
+ - 自动迁移
621
+ - 发布期兼容垫层
622
+ - 面向外部用户的平滑升级逻辑
623
+ - 仅为历史版本数据保留的复杂兜底路径
624
+
625
+ ## 13. 错误语义与公开契约
626
+
627
+ ### 13.1 两层语义继续保留
628
+
629
+ 本版继续保持两层语义:
630
+
631
+ - CLI command failure `error.code`
632
+ - `doctor` / `status` 中的 `issues[]`
633
+
634
+ 二者不混为同一错误空间。
635
+
636
+ ### 13.2 本版重点命令错误
637
+
638
+ 本版重点涉及或需要继续保持清晰的错误语义包括:
639
+
640
+ - `COPILOT_LOGIN_REQUIRES_TTY`
641
+ - `COPILOT_SDK_MISSING`
642
+ - `COPILOT_AUTH_REQUIRED`
643
+ - `COPILOT_SDK_INSTALL_FAILED`
644
+ - `COPILOT_SDK_UNSUPPORTED`
645
+ - `COPILOT_CLI_MISSING`
646
+ - `COPILOT_LOGIN_LAUNCH_FAILED`
647
+ - `COPILOT_LOGIN_RECHECK_FAILED`
648
+ - `INVALID_ARGUMENT`
649
+
650
+ 这些命令面错误不要求并入 `src/domain/errors.ts` 的统一错误码集合。对于 `login copilot` 这类交互式集成流程,可以独立定义命令专用错误族;只要对外 `error.code` contract 清晰稳定即可。
651
+
652
+ ### 13.3 本版固定的公开契约
653
+
654
+ `0.0.11` design 需要显式固定以下对外契约:
655
+
656
+ - `providers.json`、`backups/`、runtime state、runtime install 均属于 tool home
657
+ - `config.toml` 与 `auth.json` 继续属于目标 Codex runtime
658
+ - `codex-switch.json` 是工具级配置文件,不承载 provider registry
659
+ - 默认目标 `codexDir` 解析优先级固定为:
660
+ - `--codex-dir`
661
+ - `CODEXS_CODEX_DIR`
662
+ - `codex-switch.json.defaultCodexDir`
663
+ - 开发环境默认 sandbox
664
+ - `~/.codex`
665
+ - `login` 是 upstream onboarding 命令,不是 provider mutation 命令
666
+ - `login copilot` 的登录动作只通过系统级 `copilot login` 完成
667
+ - `login copilot` 在已登录时不重复启动官方登录
668
+ - `add --copilot` 缺少 runtime/auth 前提时,应明确引导到 `codexs login copilot`
669
+ - 旧布局状态不属于 `0.0.11` 自动兼容范围
670
+
671
+ ## 14. 模块设计与代码落点
672
+
673
+ 本版按行为分组说明代码落点,而不是逐文件抄清单。
674
+
675
+ ### 14.1 路径与 tool config
676
+
677
+ 主要落点:
678
+
679
+ - `src/storage/codex-paths.ts`
680
+ - `src/storage/tool-config-repo.ts`
681
+
682
+ 职责:
683
+
684
+ - 固定双路径模型
685
+ - 解析默认 tool home
686
+ - 解析默认 `codexDir`
687
+ - 维护 `codex-switch.json` 的最小稳定 contract
688
+ - 清理不再需要的旧路径推导语义
689
+
690
+ ### 14.2 路径切换与命令前置假设
691
+
692
+ 主要落点:
693
+
694
+ - 命令入口统一路径解析
695
+ - 最小化 legacy helper 清理或删除
696
+
697
+ 职责:
698
+
699
+ - 让命令统一使用新 tool home 路径
700
+ - 删除或停用不再需要的旧路径推导语义
701
+ - 不引入自动迁移、冲突探测或 fallback 兼容层
702
+
703
+ ### 14.3 `init` 与 provider mutation
704
+
705
+ 主要落点:
706
+
707
+ - `src/app/init-codex.ts`
708
+ - `src/app/add-provider.ts`
709
+ - 相关 mutation helper
710
+
711
+ 职责:
712
+
713
+ - 把 `init` 从 `codexDir/providers.json` 初始化语义改为 tool-home 初始化语义
714
+ - 让 `add --copilot` 只负责前提校验与 provider 写入
715
+ - 让 direct provider 路径继续沿用既有 config/auth projection 模型
716
+
717
+ ### 14.4 Copilot onboarding 与 runtime
718
+
719
+ 主要落点:
720
+
721
+ - `src/commands/handlers.ts`
722
+ - `src/commands/registry.ts`
723
+ - `src/runtime/copilot-installer.ts`
724
+ - `src/runtime/copilot-cli.ts`
725
+ - `src/runtime/copilot-adapter.ts`
726
+ - runtime-state / bridge helper
727
+
728
+ 职责:
729
+
730
+ - 新增 `login copilot` 命令和帮助文案
731
+ - 执行 runtime install / auth probe / system `copilot login` / recheck 流程
732
+ - 统一 `login copilot` 相关错误语义
733
+ - 保持 bridge lifecycle 与 runtime-backed provider 运行态逻辑一致
734
+
735
+ ### 14.5 状态、诊断与恢复
736
+
737
+ 主要落点:
738
+
739
+ - `src/app/get-status.ts`
740
+ - `src/app/run-doctor.ts`
741
+ - `src/storage/backup-repo.ts`
742
+ - `src/app/rollback-backup.ts`
743
+
744
+ 职责:
745
+
746
+ - 更新 storage 路径叙述到新 tool home 模型
747
+ - 保持 runtime state 安全读取
748
+ - 保持 backup/rollback 在新 home 下的稳定语义
749
+
750
+ ## 15. 测试设计
751
+
752
+ ### 15.1 路径与初始化
753
+
754
+ 至少覆盖:
755
+
756
+ - `init` 首次运行创建 tool home
757
+ - `init` 创建 `codex-switch.json`
758
+ - `init` 创建 `providers.json`
759
+ - `defaultCodexDir` 生效
760
+ - `--codex-dir` 覆盖 `defaultCodexDir`
761
+ - `CODEXS_CODEX_DIR` 覆盖 `defaultCodexDir`
762
+
763
+ ### 15.2 历史状态非兼容策略
764
+
765
+ 至少覆盖:
766
+
767
+ - 新布局下不读取旧 `codexDir/providers.json`
768
+ - 新布局下不读取旧 `codexDir/backups/`
769
+ - 新布局下不读取旧 `~/.codex-switch` runtime/state
770
+ - 命令在新 tool home 缺少状态时按空状态或正常缺失路径处理,而不是尝试自动迁移
771
+
772
+ ### 15.3 `login copilot`
773
+
774
+ 至少覆盖:
775
+
776
+ - TTY 下缺 runtime 时的安装确认流
777
+ - runtime 已安装且 auth 已就绪时直接成功
778
+ - 系统级 `copilot` CLI 缺失时失败语义
779
+ - `copilot login` 启动失败时失败语义
780
+ - 登录返回后 recheck 失败
781
+ - 非 TTY 调用失败
782
+
783
+ ### 15.4 `add --copilot`
784
+
785
+ 至少覆盖:
786
+
787
+ - 缺 runtime 返回 `COPILOT_SDK_MISSING`
788
+ - 缺 auth 返回 `COPILOT_AUTH_REQUIRED`
789
+ - 错误建议指向 `codexs login copilot`
790
+ - 不再通过 `add --copilot` 自动完成安装与官方登录主流程
791
+
792
+ ### 15.5 兼容性回归
793
+
794
+ 至少覆盖:
795
+
796
+ - direct provider `add` / `edit` / `remove` / `switch` 不回归
797
+ - `backups list` / `rollback` 在新 home 下路径正确
798
+ - `status` / `doctor` 的 storage 边界更新到新模型
799
+ - `bridge start` / `bridge stop` / `bridge status` 使用新的 runtime state 路径
800
+
801
+ ## 16. 明确不做的事
802
+
803
+ `0.0.11` design 明确不引入以下能力:
804
+
805
+ - Gemini / DeepSeek / 其他 upstream 的真实 runtime 或登录流程
806
+ - `logout`
807
+ - 完整 `auth` 子命令族
808
+ - 将 `config.toml` / `auth.json` 迁出目标 `codexDir`
809
+ - package manager / plugin manager 产品化
810
+ - 多 workspace / 多 profile 的复杂工具级策略编辑器
811
+ - 长期双写、双读或自动回退到旧 layout 的兼容协议
812
+ - 首次运行自动迁移
813
+
814
+ ## 17. 完成标准
815
+
816
+ `0.0.11` 的完成标准不是“多了一个 `login copilot` 命令”,而是以下条件同时成立:
817
+
818
+ 1. `codex-switch` 拥有稳定独立的 tool home 边界。
819
+ 2. `providers.json`、backups、runtime state、runtime install 全部有清晰且一致的归属。
820
+ 3. `login` 与 provider mutation 的职责边界已经拆开。
821
+ 4. 旧状态不需要自动兼容,手动处理路径清晰且不会把一次性需求固化成长期逻辑。
822
+ 5. direct provider 与 Copilot provider 现有主工作流在新模型下不回归。
823
+
824
+ 只有在这个基础上,后续多 upstream、多 runtime、甚至多 CLI 生态扩展,才不会继续被旧路径和旧职责模型拖累。