@minniexcode/codex-switch 0.0.9 → 0.0.11
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 +52 -13
- package/README.CN.md +94 -39
- package/README.md +75 -33
- package/dist/app/add-provider.js +29 -26
- package/dist/app/bridge.js +15 -15
- package/dist/app/edit-provider.js +2 -18
- package/dist/app/get-status.js +35 -13
- package/dist/app/import-providers.js +1 -1
- package/dist/app/init-codex.js +13 -14
- package/dist/app/list-providers.js +0 -1
- package/dist/app/remove-provider.js +1 -1
- package/dist/app/run-doctor.js +21 -39
- package/dist/app/run-mutation.js +3 -2
- package/dist/app/setup-codex.js +30 -18
- package/dist/app/show-config.js +1 -5
- package/dist/app/switch-provider.js +16 -33
- package/dist/cli/output.js +4 -6
- package/dist/cli.js +35 -3
- package/dist/commands/args.js +2 -2
- package/dist/commands/dispatch.js +40 -0
- package/dist/commands/handlers.js +202 -84
- package/dist/commands/help.js +2 -0
- package/dist/commands/registry.js +33 -12
- package/dist/domain/backups.js +4 -4
- package/dist/domain/config.js +102 -61
- package/dist/domain/providers.js +12 -5
- package/dist/domain/runtime-state.js +81 -4
- package/dist/domain/setup.js +58 -3
- package/dist/interaction/add-interactive.js +55 -1
- package/dist/interaction/interactive.js +1 -5
- package/dist/runtime/copilot-adapter.js +56 -13
- package/dist/runtime/copilot-bridge.js +392 -44
- package/dist/runtime/copilot-cli.js +142 -0
- package/dist/runtime/copilot-installer.js +59 -11
- package/dist/runtime/copilot-sdk-loader.js +5 -5
- package/dist/storage/auth-repo.js +28 -77
- package/dist/storage/backup-repo.js +4 -4
- package/dist/storage/codex-paths.js +34 -8
- package/dist/storage/config-repo.js +1 -36
- package/dist/storage/lock-repo.js +2 -4
- package/dist/storage/runtime-state-repo.js +43 -10
- package/dist/storage/tool-config-repo.js +111 -0
- package/docs/Design/codex-switch-copilot-integration-design.md +517 -0
- package/docs/Design/codex-switch-v0.0.10-design.md +669 -0
- package/docs/Design/codex-switch-v0.0.11-design.md +824 -0
- package/docs/PRD/codex-switch-prd-v0.0.10.md +406 -0
- package/docs/PRD/codex-switch-prd-v0.0.11.md +577 -0
- package/docs/cli-usage.md +166 -271
- package/docs/codex-switch-product-overview.md +2 -2
- package/docs/codex-switch-technical-architecture.md +6 -5
- package/package.json +1 -1
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
# codex-switch `0.0.10` 设计文档
|
|
2
|
+
|
|
3
|
+
## 文档信息
|
|
4
|
+
|
|
5
|
+
- 文档类型:详细设计文档
|
|
6
|
+
- 适用版本:`0.0.10`
|
|
7
|
+
- 目标范围:`0.0.9 -> 0.0.10`
|
|
8
|
+
- 对应 PRD:[`../PRD/codex-switch-prd-v0.0.10.md`](../PRD/codex-switch-prd-v0.0.10.md)
|
|
9
|
+
- 关联上一版设计:[`./codex-switch-v0.0.9-design.md`](./codex-switch-v0.0.9-design.md)
|
|
10
|
+
|
|
11
|
+
## 1. 文档目标
|
|
12
|
+
|
|
13
|
+
本设计文档用于把 `0.0.10` 的 hardening 范围收口到“实现者无需再补关键决策”的程度。文档必须直接回答以下问题:
|
|
14
|
+
|
|
15
|
+
- `migrate` 在进入交互前,如何先判断哪些 profile 可 adopt、哪些不可 adopt、失败时如何对外表达
|
|
16
|
+
- `doctor` 与 `status` 的当前公开结构到底是什么,哪些字段稳定,哪些旧说法需要删除
|
|
17
|
+
- `backups list` 与 `rollback` 的稳定 JSON 载荷和失败语义是什么
|
|
18
|
+
- runtime state 应如何安全读取,哪些路径该宽容,哪些路径该严格
|
|
19
|
+
- 发布前需要检查哪些版本与产物一致性问题
|
|
20
|
+
|
|
21
|
+
本设计只覆盖 `0.0.10` design 文件本身,不顺手扩写 README、roadmap、PRD 或代码实现细节之外的未来方案。
|
|
22
|
+
|
|
23
|
+
## 2. 版本定位
|
|
24
|
+
|
|
25
|
+
`0.0.10` 是边界收口版本,不是命令面扩展版本。
|
|
26
|
+
|
|
27
|
+
它的定位不是继续发明新的状态层、聚合 schema 或自动化迁移协议,而是围绕当前已经存在的实现模型,消除文档承诺和代码事实之间的偏差,让以下几条线稳定下来:
|
|
28
|
+
|
|
29
|
+
- `migrate` 的 adoptability 前置检查与交互边界
|
|
30
|
+
- `doctor` / `status` 的公开契约和诊断边界
|
|
31
|
+
- backup / rollback 的恢复契约
|
|
32
|
+
- Copilot runtime state 的安全读路径
|
|
33
|
+
- release correctness 的最低发布门槛
|
|
34
|
+
|
|
35
|
+
## 3. 设计原则
|
|
36
|
+
|
|
37
|
+
`0.0.10` 必须遵循以下原则:
|
|
38
|
+
|
|
39
|
+
1. 以当前实现契约为事实源,不回引已经与代码脱节的旧概念。
|
|
40
|
+
2. 不把 `auth.json` 重新定义为 provider secret mirror。
|
|
41
|
+
3. 不引入 `status.health.*`、并行诊断结构或新的大 JSON 输出族。
|
|
42
|
+
4. 命令错误码与 `doctor` issue code 是两层契约,命名应尽量对齐,但不能混为一体。
|
|
43
|
+
5. 文档中的“稳定字段”要少而明确;面向人类阅读的 reason/message 文本允许演进,但结构边界必须固定。
|
|
44
|
+
|
|
45
|
+
## 4. 数据边界与公开契约
|
|
46
|
+
|
|
47
|
+
### 4.1 文件角色
|
|
48
|
+
|
|
49
|
+
- `providers.json`
|
|
50
|
+
- 管理态 registry
|
|
51
|
+
- 是 managed state 的 SSOT
|
|
52
|
+
- 记录 provider 名称、profile 绑定以及 runtime-backed provider 的持久化配置
|
|
53
|
+
- `config.toml`
|
|
54
|
+
- 运行态路由投影
|
|
55
|
+
- 表达当前 active profile 与 `model_providers.<name>` runtime 路由
|
|
56
|
+
- 允许出现尚未被 `providers.json` 接管的 live state
|
|
57
|
+
- `auth.json`
|
|
58
|
+
- 独立 auth state 文件
|
|
59
|
+
- 只在 `status` / `doctor` 中做存在性、可解析性与基础元数据读取
|
|
60
|
+
- 不是 provider secret mirror,也不是 managed provider ownership 的证明
|
|
61
|
+
- runtime state
|
|
62
|
+
- 指 Copilot bridge 的本地运行态文件,当前落在 `copilot-bridge-state.json`
|
|
63
|
+
- 用于 bridge 运行状况探测、stale state 判断和 direct provider 场景的安全读取
|
|
64
|
+
- 不纳入 managed backup 的强事务边界
|
|
65
|
+
- backups
|
|
66
|
+
- 用于恢复 managed files
|
|
67
|
+
- 不承诺恢复运行中 bridge 进程,也不承诺恢复外部 Copilot 登录态
|
|
68
|
+
|
|
69
|
+
### 4.2 契约分层
|
|
70
|
+
|
|
71
|
+
- 命令返回中的 `error.code`
|
|
72
|
+
- 面向 CLI 调用方
|
|
73
|
+
- 用于表达命令失败原因,例如 `INVALID_ARGUMENT`、`BACKUP_NOT_FOUND`
|
|
74
|
+
- `doctor.data.issues[].code`
|
|
75
|
+
- 面向诊断域
|
|
76
|
+
- 用于表达系统状态问题,例如 `AUTH_JSON_INVALID`、`BRIDGE_STATE_STALE`
|
|
77
|
+
|
|
78
|
+
二者可能名称相近,但并不等价。例如:
|
|
79
|
+
|
|
80
|
+
- `MIGRATE_NO_ADOPTABLE_PROFILES` 是命令错误码,不是 `doctor` issue code
|
|
81
|
+
- `AUTH_JSON_INVALID` 当前既可能出现在内部错误归一化路径中,也可能作为 `doctor` issue code 出现,但语义仍以“诊断问题”优先,不应被重新包装成 auth mirror 协议
|
|
82
|
+
|
|
83
|
+
## 5. `migrate` 详细设计
|
|
84
|
+
|
|
85
|
+
### 5.1 设计目标
|
|
86
|
+
|
|
87
|
+
`migrate` 在 `0.0.10` 的重点不是新增自动化导入能力,而是把交互式 adopt 路径做扎实。命令需要先判断“能不能迁”,再决定“如何迁”。
|
|
88
|
+
|
|
89
|
+
### 5.2 adoptability 前置检查
|
|
90
|
+
|
|
91
|
+
交互流程前必须先完成 adoptability 预检查。该检查以当前 config consistency 模型为边界,围绕 unmanaged profile 是否已经具备成为 managed provider 的最小条件展开。
|
|
92
|
+
|
|
93
|
+
稳定输出字段:
|
|
94
|
+
|
|
95
|
+
- `availableProfiles`
|
|
96
|
+
- `adoptableProfiles`
|
|
97
|
+
- `blockingReasonsByProfile`
|
|
98
|
+
|
|
99
|
+
其中:
|
|
100
|
+
|
|
101
|
+
- `availableProfiles` 表示当前 `config.toml` 中可见 profile 集合
|
|
102
|
+
- `adoptableProfiles` 表示通过最小 adopt 条件检查的 profile 集合
|
|
103
|
+
- `blockingReasonsByProfile` 是面向人类可读的诊断映射;字段存在本身是稳定契约,但 reason 文本不承诺固定枚举
|
|
104
|
+
|
|
105
|
+
阻塞原因必须逐项对齐现有 config consistency 模型,至少覆盖:
|
|
106
|
+
|
|
107
|
+
- 缺 `model`
|
|
108
|
+
- 缺 `model_provider`
|
|
109
|
+
- `model_provider` 名称与 profile 不匹配
|
|
110
|
+
- 缺 `model_providers.<name>` section
|
|
111
|
+
- 缺 `base_url`
|
|
112
|
+
- 缺 `env_key`
|
|
113
|
+
|
|
114
|
+
### 5.3 无可 adopt profile 的失败语义
|
|
115
|
+
|
|
116
|
+
`0.0.10` 正式引入并固定以下命令错误码:
|
|
117
|
+
|
|
118
|
+
- `MIGRATE_NO_ADOPTABLE_PROFILES`
|
|
119
|
+
|
|
120
|
+
它用于表达:命令在进入 strategy prompt、profile 选择和 provider 详情收集之前,就已经判断出没有任何 profile 满足 adopt 前提。
|
|
121
|
+
|
|
122
|
+
示例:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"error": {
|
|
127
|
+
"code": "MIGRATE_NO_ADOPTABLE_PROFILES",
|
|
128
|
+
"message": "No adoptable profiles were found for migrate.",
|
|
129
|
+
"details": {
|
|
130
|
+
"availableProfiles": ["copilot", "openai"],
|
|
131
|
+
"adoptableProfiles": [],
|
|
132
|
+
"blockingReasonsByProfile": {
|
|
133
|
+
"copilot": ["model_provider is missing."],
|
|
134
|
+
"openai": ["model_providers.openai.base_url is missing."]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 5.4 非交互式 `migrate` 的边界
|
|
142
|
+
|
|
143
|
+
`0.0.10` 不引入完整的非交互式 `migrate` profile 选择和 secret 注入参数。
|
|
144
|
+
|
|
145
|
+
因此需要保留两条失败路径的分工:
|
|
146
|
+
|
|
147
|
+
- `MIGRATE_NO_ADOPTABLE_PROFILES`
|
|
148
|
+
- 表示输入状态本身不满足 adopt 前提
|
|
149
|
+
- 失败发生在交互需求之前
|
|
150
|
+
- `INVALID_ARGUMENT`
|
|
151
|
+
- 表示当前 release 仍要求 interactive TTY 才能完成 profile 选择和 provider details 收集
|
|
152
|
+
- 即使存在 adoptable profiles,也不能把非交互调用伪装成受支持 contract
|
|
153
|
+
|
|
154
|
+
非交互错误仍可继续暴露:
|
|
155
|
+
|
|
156
|
+
- `availableProfiles`
|
|
157
|
+
- `adoptableProfiles`
|
|
158
|
+
- 面向用户的 suggestion 文案
|
|
159
|
+
|
|
160
|
+
但文档不应把这些细节提升成“已支持自动化 migrate”的承诺。
|
|
161
|
+
|
|
162
|
+
### 5.5 空 registry 场景
|
|
163
|
+
|
|
164
|
+
当 `providers.json` 已存在但 registry 为空时:
|
|
165
|
+
|
|
166
|
+
- 跳过 `merge` / `overwrite` prompt
|
|
167
|
+
- 对外不新增额外 schema
|
|
168
|
+
- 内部按 `overwrite` 语义继续即可
|
|
169
|
+
|
|
170
|
+
该决策的目的不是改变最终结果,而是去掉没有决策价值的交互。
|
|
171
|
+
|
|
172
|
+
### 5.6 与当前实现的衔接
|
|
173
|
+
|
|
174
|
+
当前 `migrate` 主要落在:
|
|
175
|
+
|
|
176
|
+
- `src/commands/handlers.ts`
|
|
177
|
+
- `src/app/setup-codex.ts`
|
|
178
|
+
- `src/domain/setup.ts`
|
|
179
|
+
|
|
180
|
+
`0.0.10` 的实现约束是:
|
|
181
|
+
|
|
182
|
+
- adoptability 预检查前置到交互入口之前
|
|
183
|
+
- 交互层只负责选择 adoptable profiles 和收集缺失 provider details
|
|
184
|
+
- app 层继续负责最终 mutation、backup、post-doctor 复检
|
|
185
|
+
|
|
186
|
+
## 6. `doctor` 与 `status` 详细设计
|
|
187
|
+
|
|
188
|
+
### 6.1 `doctor` 的主诊断结构
|
|
189
|
+
|
|
190
|
+
`doctor` 继续以 `doctor.data.issues[]` 作为主诊断面,不新增并行结构。
|
|
191
|
+
|
|
192
|
+
单项 issue 的目标结构保持:
|
|
193
|
+
|
|
194
|
+
- `code`
|
|
195
|
+
- `message`
|
|
196
|
+
- 与该问题直接相关的附加字段
|
|
197
|
+
|
|
198
|
+
示例:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"code": "AUTH_JSON_INVALID",
|
|
203
|
+
"message": "Failed to parse auth.json.",
|
|
204
|
+
"file": "C:\\Users\\name\\.codex\\auth.json"
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 6.2 `doctor` 诊断域边界
|
|
209
|
+
|
|
210
|
+
`0.0.10` 中允许且应清晰表达的诊断域包括:
|
|
211
|
+
|
|
212
|
+
- config / providers consistency
|
|
213
|
+
- active profile 未受管
|
|
214
|
+
- shared profile reference
|
|
215
|
+
- `model_provider` / `base_url` / `env_key` 缺失或不一致
|
|
216
|
+
- `AUTH_JSON_INVALID`
|
|
217
|
+
- 仅在 auth 文件存在但不可解析时出现
|
|
218
|
+
- Codex runtime probe
|
|
219
|
+
- `CODEX_NOT_INSTALLED`
|
|
220
|
+
- `CODEX_VERSION_UNSUPPORTED`
|
|
221
|
+
- `CODEX_LOGIN_FAILED`
|
|
222
|
+
- Copilot / bridge 诊断
|
|
223
|
+
- `COPILOT_SDK_MISSING`
|
|
224
|
+
- `COPILOT_AUTH_REQUIRED`
|
|
225
|
+
- `BRIDGE_STATE_MISSING`
|
|
226
|
+
- `BRIDGE_STATE_STALE`
|
|
227
|
+
- `PROVIDER_BASE_URL_MISMATCH`
|
|
228
|
+
- `BRIDGE_HEALTHCHECK_FAILED`
|
|
229
|
+
|
|
230
|
+
### 6.3 `doctor` 明确不做的事
|
|
231
|
+
|
|
232
|
+
- 不检查 `auth.json` 与 active provider 的 key/value mirror 一致性
|
|
233
|
+
- 不报告 `auth mirror mismatch` 一类问题码
|
|
234
|
+
- 不发明新的 `doctor.health.*` 或第二套自动化诊断 schema
|
|
235
|
+
|
|
236
|
+
### 6.4 `status` 的当前事实边界
|
|
237
|
+
|
|
238
|
+
`status` 保持当前 JSON shape,不新增 `health.overall`、`health.summary` 等字段。
|
|
239
|
+
|
|
240
|
+
`status.data` 继续围绕以下字段表达:
|
|
241
|
+
|
|
242
|
+
- `currentProfile`
|
|
243
|
+
- `currentProfileMapped`
|
|
244
|
+
- `provider`
|
|
245
|
+
- `activeProviderResolvable`
|
|
246
|
+
- `activeProviderCandidates`
|
|
247
|
+
- `runtimeProvider`
|
|
248
|
+
- `copilotSdk`
|
|
249
|
+
- `copilotAuth`
|
|
250
|
+
- `copilotBridge`
|
|
251
|
+
- `copilotRuntimeState`
|
|
252
|
+
- `liveState`
|
|
253
|
+
- `auth`
|
|
254
|
+
- `configProfiles`
|
|
255
|
+
- `issues`
|
|
256
|
+
- `storage`
|
|
257
|
+
|
|
258
|
+
### 6.5 `status.data.auth` 的稳定 shape
|
|
259
|
+
|
|
260
|
+
`status.data.auth` 在 `0.0.10` 中固定为中性文件状态摘要:
|
|
261
|
+
|
|
262
|
+
- `exists`
|
|
263
|
+
- `valid`
|
|
264
|
+
- `parseError`
|
|
265
|
+
- `authMode`
|
|
266
|
+
|
|
267
|
+
示例:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"exists": true,
|
|
272
|
+
"valid": true,
|
|
273
|
+
"parseError": null,
|
|
274
|
+
"authMode": "session"
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
该结构不包含:
|
|
279
|
+
|
|
280
|
+
- provider ownership
|
|
281
|
+
- managed key 列表
|
|
282
|
+
- auth mirror 是否与当前 provider 一致的结论
|
|
283
|
+
|
|
284
|
+
### 6.6 `status.data.storage` 的稳定 shape
|
|
285
|
+
|
|
286
|
+
`status.data.storage` 在 `0.0.10` 中固定为:
|
|
287
|
+
|
|
288
|
+
- `managementSSOT`
|
|
289
|
+
- `runtimeMirrors`
|
|
290
|
+
- `authStateFile`
|
|
291
|
+
- `rollbackState`
|
|
292
|
+
|
|
293
|
+
示例:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"managementSSOT": "providers.json",
|
|
298
|
+
"runtimeMirrors": ["config.toml"],
|
|
299
|
+
"authStateFile": "auth.json",
|
|
300
|
+
"rollbackState": "backups/latest.json"
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 6.7 direct provider 与脏 runtime state
|
|
305
|
+
|
|
306
|
+
`status` / `doctor` 需要能在 direct provider 场景下稳定输出,即使本地存在 stale 或损坏的 Copilot runtime state,也不应因为“读到不可信运行态文件”而导致整个读路径崩溃。
|
|
307
|
+
|
|
308
|
+
设计目标不是新增公共输出 schema,而是把问题包装回现有:
|
|
309
|
+
|
|
310
|
+
- `copilotRuntimeState`
|
|
311
|
+
- `copilotBridge`
|
|
312
|
+
- `doctor.data.issues[]`
|
|
313
|
+
- `warnings`
|
|
314
|
+
|
|
315
|
+
## 7. backup / rollback 详细设计
|
|
316
|
+
|
|
317
|
+
### 7.1 `backups list` 稳定载荷
|
|
318
|
+
|
|
319
|
+
`backups list` 的稳定列表项写死为:
|
|
320
|
+
|
|
321
|
+
- `backupId`
|
|
322
|
+
- `createdAt`
|
|
323
|
+
- `reason`
|
|
324
|
+
- `files`
|
|
325
|
+
- `backupPath`
|
|
326
|
+
|
|
327
|
+
单项示例:
|
|
328
|
+
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"backupId": "20260511-221457-switch",
|
|
332
|
+
"createdAt": "2026-05-11T22:14:57.000Z",
|
|
333
|
+
"reason": "switch",
|
|
334
|
+
"files": ["config.toml", "providers.json"],
|
|
335
|
+
"backupPath": "C:\\Users\\name\\.codex\\backups\\20260511-221457-switch"
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
当前实现额外返回的 `count` 应在设计中明确标为命令层派生便利字段,而不是 PRD 级主契约。它可以保留,但不应成为外部集成的唯一依赖项。
|
|
340
|
+
|
|
341
|
+
### 7.2 manifest 异常的列表行为
|
|
342
|
+
|
|
343
|
+
当 `backups/` 下存在损坏或不完整的历史项时:
|
|
344
|
+
|
|
345
|
+
- 命令应继续返回其余有效备份
|
|
346
|
+
- `warnings` 用于提示 `manifest.json` 缺失或非法
|
|
347
|
+
- 只有在没有任何有效备份可列出时,才失败为 `BACKUP_NOT_FOUND`
|
|
348
|
+
|
|
349
|
+
### 7.3 `rollback` 成功载荷
|
|
350
|
+
|
|
351
|
+
`rollback` 的稳定成功载荷为:
|
|
352
|
+
|
|
353
|
+
- `restoredFiles`
|
|
354
|
+
- `backupId`
|
|
355
|
+
- `backupPath`
|
|
356
|
+
|
|
357
|
+
示例:
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"data": {
|
|
362
|
+
"restoredFiles": ["config.toml", "providers.json"],
|
|
363
|
+
"backupId": "20260511-221457-switch",
|
|
364
|
+
"backupPath": "C:\\Users\\name\\.codex\\backups\\20260511-221457-switch"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
对 `rollback latest` 路径,`backupId` 可以为 `null`,但仍需返回 `backupPath` 与 `restoredFiles`。
|
|
370
|
+
|
|
371
|
+
### 7.4 `rollback` 路径区分
|
|
372
|
+
|
|
373
|
+
必须在设计稿中明确两条路径:
|
|
374
|
+
|
|
375
|
+
1. `rollback`
|
|
376
|
+
- 读取 `backups/latest.json`
|
|
377
|
+
- 适合“恢复最近一次受管变更”
|
|
378
|
+
2. `rollback <backupId>`
|
|
379
|
+
- 按显式历史目录加载对应 manifest
|
|
380
|
+
- 适合恢复指定时间点
|
|
381
|
+
|
|
382
|
+
### 7.5 `rollback` 失败语义
|
|
383
|
+
|
|
384
|
+
`0.0.10` 先收口到两类失败:
|
|
385
|
+
|
|
386
|
+
- `BACKUP_NOT_FOUND`
|
|
387
|
+
- `ROLLBACK_FAILED`
|
|
388
|
+
|
|
389
|
+
其中:
|
|
390
|
+
|
|
391
|
+
- `BACKUP_NOT_FOUND`
|
|
392
|
+
- latest manifest 不存在
|
|
393
|
+
- 指定 `backupId` 不存在
|
|
394
|
+
- backups 目录不存在或没有有效备份
|
|
395
|
+
- `ROLLBACK_FAILED`
|
|
396
|
+
- latest manifest 读取失败
|
|
397
|
+
- 指定 manifest 读取失败
|
|
398
|
+
- manifest 指向的备份文件缺失
|
|
399
|
+
- restore 过程中 copy/delete 失败
|
|
400
|
+
|
|
401
|
+
如果后续版本要继续细分,只能选择以下一种路径:
|
|
402
|
+
|
|
403
|
+
- 新增更具体的 `error.code`
|
|
404
|
+
- 维持主错误码不变,但在 `details.reason` 或 `details.cause` 中细分
|
|
405
|
+
|
|
406
|
+
不能同时模糊地引入一组既不像命令错误码、又不像诊断 issue code 的中间状态。
|
|
407
|
+
|
|
408
|
+
## 8. runtime state 与恢复边界
|
|
409
|
+
|
|
410
|
+
### 8.1 设计选择
|
|
411
|
+
|
|
412
|
+
runtime state 的设计选择是:
|
|
413
|
+
|
|
414
|
+
- 新增安全检查与诊断包装
|
|
415
|
+
- 不直接发明新的公共输出 schema
|
|
416
|
+
|
|
417
|
+
### 8.2 读取策略分层
|
|
418
|
+
|
|
419
|
+
建议把运行态读取分成两类路径:
|
|
420
|
+
|
|
421
|
+
- safe inspection helper
|
|
422
|
+
- 供 `status`、`doctor`、direct provider 相关只读路径使用
|
|
423
|
+
- 遇到脏 runtime state 时,返回可解释的空值、warning 或 issue,而不是直接崩溃
|
|
424
|
+
- stricter loader
|
|
425
|
+
- 供 bridge lifecycle 路径使用
|
|
426
|
+
- 在 `bridge start/stop/status` 等需要高置信度状态的场景中维持严格校验
|
|
427
|
+
|
|
428
|
+
这样可以保证:
|
|
429
|
+
|
|
430
|
+
- 诊断类命令足够稳健
|
|
431
|
+
- bridge 生命周期命令仍保留必要的严格性
|
|
432
|
+
- direct provider 读路径不会被无关的 stale runtime state 连带打崩
|
|
433
|
+
|
|
434
|
+
### 8.3 与 backup / rollback 的关系
|
|
435
|
+
|
|
436
|
+
runtime state 继续保持在 managed backup 事务外:
|
|
437
|
+
|
|
438
|
+
- backup 不承诺捕获 `copilot-bridge-state.json`
|
|
439
|
+
- rollback 不承诺恢复 bridge 进程
|
|
440
|
+
- `doctor` / `status` 负责解释运行态是否 stale、missing 或 mismatch
|
|
441
|
+
|
|
442
|
+
## 9. release correctness
|
|
443
|
+
|
|
444
|
+
`0.0.10` 需要把以下内容纳入发布正确性检查:
|
|
445
|
+
|
|
446
|
+
- CLI `--version` 必须与 `package.json` 一致
|
|
447
|
+
- README 与公开文档中的版本字样应与本次发布版本一致
|
|
448
|
+
- `npm pack` 作为发布前 sanity check 执行
|
|
449
|
+
|
|
450
|
+
这里的设计选择是:
|
|
451
|
+
|
|
452
|
+
- `npm pack` 是 preflight,不是默认测试流的一部分
|
|
453
|
+
- 版本一致性检查属于 release correctness,不等同于功能测试
|
|
454
|
+
|
|
455
|
+
## 10. 公开接口 / 契约变化
|
|
456
|
+
|
|
457
|
+
`0.0.10` 需要在设计稿中单独固定以下公开变化:
|
|
458
|
+
|
|
459
|
+
- `status.data.auth` 是中性文件状态,不含 provider ownership 或 managed key 列表
|
|
460
|
+
- `doctor` 不再承诺任何 `auth mirror mismatch` 类问题码
|
|
461
|
+
- `backups list` 的稳定 JSON 载荷固定为 `backupId`、`createdAt`、`reason`、`files`、`backupPath`
|
|
462
|
+
- `rollback` 的稳定成功载荷固定为 `restoredFiles`、`backupId`、`backupPath`
|
|
463
|
+
- `MIGRATE_NO_ADOPTABLE_PROFILES` 是命令错误码,不是 `doctor` / `status` issue code
|
|
464
|
+
- 本版明确不引入 `status.health.*` 契约
|
|
465
|
+
|
|
466
|
+
## 11. 模块设计与代码落点
|
|
467
|
+
|
|
468
|
+
本版按行为分组说明代码落点,而不是逐文件抄清单。
|
|
469
|
+
|
|
470
|
+
### 11.1 命令流与交互前置检查
|
|
471
|
+
|
|
472
|
+
主要落点:
|
|
473
|
+
|
|
474
|
+
- `src/commands/handlers.ts`
|
|
475
|
+
- `src/interaction/interactive.ts`
|
|
476
|
+
|
|
477
|
+
职责:
|
|
478
|
+
|
|
479
|
+
- 解析 `migrate`、`rollback` 等命令的交互边界
|
|
480
|
+
- 在进入 prompt 前完成 adoptability 预检查
|
|
481
|
+
- 空 registry 时跳过无意义策略 prompt
|
|
482
|
+
- 在 help / human output 中同步更准确的失败说明
|
|
483
|
+
|
|
484
|
+
### 11.2 诊断与状态聚合
|
|
485
|
+
|
|
486
|
+
主要落点:
|
|
487
|
+
|
|
488
|
+
- `src/app/get-status.ts`
|
|
489
|
+
- `src/app/run-doctor.ts`
|
|
490
|
+
- `src/storage/auth-repo.ts`
|
|
491
|
+
- runtime state 读取辅助
|
|
492
|
+
|
|
493
|
+
职责:
|
|
494
|
+
|
|
495
|
+
- 聚合 config/providers consistency、auth state、runtime probe、bridge probe
|
|
496
|
+
- 固定 `status.data.auth` 与 `status.data.storage` shape
|
|
497
|
+
- 继续沿用 `doctor.data.issues[]` 作为主诊断面
|
|
498
|
+
|
|
499
|
+
### 11.3 恢复与运行态边界
|
|
500
|
+
|
|
501
|
+
主要落点:
|
|
502
|
+
|
|
503
|
+
- `src/storage/backup-repo.ts`
|
|
504
|
+
- `src/app/rollback-backup.ts`
|
|
505
|
+
- `src/storage/runtime-state-repo.ts`
|
|
506
|
+
- bridge runtime helper
|
|
507
|
+
|
|
508
|
+
职责:
|
|
509
|
+
|
|
510
|
+
- 保持 backup manifest 校验、list、restore 语义一致
|
|
511
|
+
- 明确 latest 与显式 `backupId` 的 rollback 路径
|
|
512
|
+
- 在读路径上对 runtime state 做安全包装,在生命周期路径上保留严格加载
|
|
513
|
+
|
|
514
|
+
### 11.4 人类可读输出与帮助文本
|
|
515
|
+
|
|
516
|
+
主要落点:
|
|
517
|
+
|
|
518
|
+
- `src/commands/registry.ts`
|
|
519
|
+
- `src/cli/output.ts`
|
|
520
|
+
- 相关 help 文案与错误消息
|
|
521
|
+
|
|
522
|
+
职责:
|
|
523
|
+
|
|
524
|
+
- 让 `migrate` 非交互失败信息更直接
|
|
525
|
+
- 让 `doctor` / `status` 的字段说明不再暗示 auth mirror 模型
|
|
526
|
+
- 让 `backups list` / `rollback` 的对外说明与真实载荷对齐
|
|
527
|
+
|
|
528
|
+
## 12. 示例片段
|
|
529
|
+
|
|
530
|
+
### 12.1 `status.data.auth`
|
|
531
|
+
|
|
532
|
+
```json
|
|
533
|
+
{
|
|
534
|
+
"exists": true,
|
|
535
|
+
"valid": false,
|
|
536
|
+
"parseError": "Failed to parse auth.json.",
|
|
537
|
+
"authMode": null
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### 12.2 `status.data.storage`
|
|
542
|
+
|
|
543
|
+
```json
|
|
544
|
+
{
|
|
545
|
+
"managementSSOT": "providers.json",
|
|
546
|
+
"runtimeMirrors": ["config.toml"],
|
|
547
|
+
"authStateFile": "auth.json",
|
|
548
|
+
"rollbackState": "backups/latest.json"
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### 12.3 `backups list` 单项
|
|
553
|
+
|
|
554
|
+
```json
|
|
555
|
+
{
|
|
556
|
+
"backupId": "20260511-221457-migrate",
|
|
557
|
+
"createdAt": "2026-05-11T22:14:57.000Z",
|
|
558
|
+
"reason": "migrate",
|
|
559
|
+
"files": ["providers.json", "config.toml"],
|
|
560
|
+
"backupPath": "C:\\Users\\name\\.codex\\backups\\20260511-221457-migrate"
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### 12.4 `rollback` success
|
|
565
|
+
|
|
566
|
+
```json
|
|
567
|
+
{
|
|
568
|
+
"data": {
|
|
569
|
+
"restoredFiles": ["providers.json", "config.toml"],
|
|
570
|
+
"backupId": null,
|
|
571
|
+
"backupPath": "C:\\Users\\name\\.codex\\backups\\20260511-221457-migrate"
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### 12.5 `MIGRATE_NO_ADOPTABLE_PROFILES`
|
|
577
|
+
|
|
578
|
+
```json
|
|
579
|
+
{
|
|
580
|
+
"error": {
|
|
581
|
+
"code": "MIGRATE_NO_ADOPTABLE_PROFILES",
|
|
582
|
+
"message": "No adoptable profiles were found for migrate.",
|
|
583
|
+
"details": {
|
|
584
|
+
"availableProfiles": ["work-openai"],
|
|
585
|
+
"adoptableProfiles": [],
|
|
586
|
+
"blockingReasonsByProfile": {
|
|
587
|
+
"work-openai": [
|
|
588
|
+
"model_provider must match the profile name.",
|
|
589
|
+
"model_providers.work-openai.env_key is missing."
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### 12.6 `doctor.data.issues[]` 单项
|
|
598
|
+
|
|
599
|
+
```json
|
|
600
|
+
{
|
|
601
|
+
"code": "BRIDGE_STATE_STALE",
|
|
602
|
+
"message": "Copilot bridge runtime state exists for a provider that is not the current active profile.",
|
|
603
|
+
"activeProfile": "openai",
|
|
604
|
+
"runtimeProvider": "copilot",
|
|
605
|
+
"runtimeProfile": "copilot"
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
## 13. 测试设计
|
|
610
|
+
|
|
611
|
+
测试设计按当前测试组织展开,重点覆盖以下内容。
|
|
612
|
+
|
|
613
|
+
### 13.1 `migrate`
|
|
614
|
+
|
|
615
|
+
- 0 adoptable profiles 时直接失败为 `MIGRATE_NO_ADOPTABLE_PROFILES`
|
|
616
|
+
- `providers.json` 已存在但 registry 为空时跳过策略 prompt
|
|
617
|
+
- 非交互失败继续走 `INVALID_ARGUMENT`,并带清晰 suggestion
|
|
618
|
+
- `blockingReasonsByProfile` 覆盖以下阻塞类型:
|
|
619
|
+
- 缺 `model`
|
|
620
|
+
- 缺 `model_provider`
|
|
621
|
+
- `model_provider` 名称不匹配
|
|
622
|
+
- 缺 `model_providers.<name>`
|
|
623
|
+
- 缺 `base_url`
|
|
624
|
+
- 缺 `env_key`
|
|
625
|
+
|
|
626
|
+
### 13.2 `doctor` / `status`
|
|
627
|
+
|
|
628
|
+
- `AUTH_JSON_INVALID`
|
|
629
|
+
- config/profile/provider consistency
|
|
630
|
+
- `COPILOT_SDK_MISSING`
|
|
631
|
+
- `COPILOT_AUTH_REQUIRED`
|
|
632
|
+
- `BRIDGE_STATE_MISSING`
|
|
633
|
+
- `BRIDGE_STATE_STALE`
|
|
634
|
+
- `PROVIDER_BASE_URL_MISMATCH`
|
|
635
|
+
- `BRIDGE_HEALTHCHECK_FAILED`
|
|
636
|
+
- direct provider 下脏 runtime state 仍能稳定输出
|
|
637
|
+
|
|
638
|
+
### 13.3 backup / rollback
|
|
639
|
+
|
|
640
|
+
- invalid or missing manifest warnings
|
|
641
|
+
- `BACKUP_NOT_FOUND`
|
|
642
|
+
- `ROLLBACK_FAILED`
|
|
643
|
+
- restore missing backup file
|
|
644
|
+
- `rollback latest`
|
|
645
|
+
- 显式 `rollback <backupId>`
|
|
646
|
+
|
|
647
|
+
### 13.4 release correctness
|
|
648
|
+
|
|
649
|
+
- built CLI `--version`
|
|
650
|
+
- `package.json` version
|
|
651
|
+
- README 版本标注一致性
|
|
652
|
+
- `npm pack` preflight
|
|
653
|
+
|
|
654
|
+
## 14. 完成标准
|
|
655
|
+
|
|
656
|
+
`0.0.10` 设计工作完成时,必须满足:
|
|
657
|
+
|
|
658
|
+
1. 文档中不再出现 `auth mirror`、`auth mirror mismatch`、`status.health.*` 等与当前实现冲突的硬承诺。
|
|
659
|
+
2. `migrate`、`doctor`、`status`、`backups list`、`rollback` 的公共契约可以直接从设计稿读出,而不需要回查旧 PRD 或猜测代码行为。
|
|
660
|
+
3. runtime state 被明确定位为“安全检查与诊断包装对象”,而不是新的强事务 managed state。
|
|
661
|
+
4. 发布前检查明确包含 CLI 版本、打包产物与公开文档版本标注三类一致性校验。
|
|
662
|
+
|
|
663
|
+
## 15. 发布前检查
|
|
664
|
+
|
|
665
|
+
发布 `0.0.10` 前至少执行:
|
|
666
|
+
|
|
667
|
+
1. 验证 `node dist/cli.js --version` 与 `package.json` 一致。
|
|
668
|
+
2. 验证公开文档中的版本字样没有停留在旧版本或提前承诺未来 schema。
|
|
669
|
+
3. 执行 `npm pack`,确认发布包可生成,且文档、构建产物和 CLI 入口完整。
|