@minniexcode/codex-switch 0.0.8 → 0.0.10

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 (44) hide show
  1. package/README.AI.md +5 -3
  2. package/README.CN.md +25 -3
  3. package/README.md +3 -2
  4. package/dist/app/add-provider.js +1 -12
  5. package/dist/app/bridge.js +295 -0
  6. package/dist/app/edit-provider.js +1 -17
  7. package/dist/app/get-status.js +32 -2
  8. package/dist/app/list-providers.js +0 -1
  9. package/dist/app/run-doctor.js +45 -38
  10. package/dist/app/setup-codex.js +27 -17
  11. package/dist/app/show-config.js +1 -5
  12. package/dist/app/switch-provider.js +33 -20
  13. package/dist/cli/output.js +4 -6
  14. package/dist/cli.js +1 -1
  15. package/dist/commands/handlers.js +223 -39
  16. package/dist/commands/help.js +1 -0
  17. package/dist/commands/registry.js +48 -4
  18. package/dist/domain/config.js +4 -68
  19. package/dist/domain/providers.js +0 -5
  20. package/dist/domain/runtime-state.js +2 -1
  21. package/dist/domain/setup.js +58 -3
  22. package/dist/interaction/add-interactive.js +55 -1
  23. package/dist/interaction/interactive.js +1 -5
  24. package/dist/runtime/copilot-adapter.js +44 -1
  25. package/dist/runtime/copilot-bridge-worker.js +1 -1
  26. package/dist/runtime/copilot-bridge.js +60 -19
  27. package/dist/runtime/copilot-cli.js +70 -0
  28. package/dist/runtime/copilot-installer.js +49 -2
  29. package/dist/storage/auth-repo.js +28 -77
  30. package/dist/storage/config-repo.js +1 -36
  31. package/dist/storage/runtime-state-repo.js +32 -0
  32. package/docs/Design/codex-switch-copilot-integration-design.md +517 -0
  33. package/docs/Design/codex-switch-v0.0.10-design.md +669 -0
  34. package/docs/Design/codex-switch-v0.0.9-design.md +182 -0
  35. package/docs/PRD/codex-switch-prd-v0.0.10.md +406 -0
  36. package/docs/PRD/codex-switch-prd-v0.0.9.md +166 -0
  37. package/docs/Tests/testing-bridge-v0.0.9.md +367 -0
  38. package/docs/cli-usage.md +38 -14
  39. package/docs/codex-switch-product-overview.md +2 -2
  40. package/docs/codex-switch-technical-architecture.md +6 -5
  41. package/package.json +1 -1
  42. /package/docs/{test-report-0.0.5.md → Tests/test-report-0.0.5.md} +0 -0
  43. /package/docs/{test-report-0.0.7.md → Tests/test-report-0.0.7.md} +0 -0
  44. /package/docs/{testing.md → Tests/testing.md} +0 -0
@@ -0,0 +1,166 @@
1
+ # codex-switch `0.0.9` PRD
2
+
3
+ ## 文档信息
4
+
5
+ - 状态:Active PRD
6
+ - 产品名:`codex-switch`
7
+ - CLI 命令名:`codexs`
8
+ - 当前基线版本:`0.0.8`
9
+ - 目标版本:`0.0.9`
10
+ - 文档定位:定义 `0.0.8 -> 0.0.9` 的直接需求范围
11
+ - 关联设计文档:`../Design/codex-switch-v0.0.9-design.md`(待产出)
12
+ - 关联上一版设计:[`../Design/codex-switch-v0.0.8-design.md`](../Design/codex-switch-v0.0.8-design.md)
13
+
14
+ ## 一句话定义
15
+
16
+ `0.0.9` 的目标,是把 GitHub Copilot 的本地 bridge 从“切换时临时可用”收敛成“可按需自动拉起、可手动管理、可诊断恢复”的稳定运行态能力。
17
+
18
+ ## In Scope
19
+
20
+ - 官方 `@github/copilot-sdk`
21
+ - 本地 Node/TypeScript bridge
22
+ - detached 用户态 bridge 守护进程
23
+ - `switch` 的 bridge 自动启动 / 复用
24
+ - `bridge start`
25
+ - `bridge stop`
26
+ - `bridge status`
27
+ - 单实例 bridge 生命周期管理
28
+ - 5 位数 bridge 端口默认策略
29
+ - 端口冲突自动探测与自动换端口
30
+ - runtime state manifest 的持久化与诊断
31
+ - `status` / `doctor` 的 bridge 生命周期诊断
32
+ - direct provider 回归稳定性
33
+
34
+ ## Out of Scope
35
+
36
+ - 开机自启动
37
+ - 登录自启动
38
+ - Windows Service / 系统服务注册
39
+ - 多实例 bridge 编排
40
+ - 非官方 SDK
41
+ - 独立 GUI / TUI
42
+ - Responses API、Embeddings、图像/音频接口
43
+ - 持久化 GitHub token 到 `providers.json` / `auth.json`
44
+
45
+ ## 运行形态
46
+
47
+ - bridge 是由 `codex-switch` 启动和管理的本地后台进程
48
+ - bridge 不是系统服务,也不注册开机或登录自动启动项
49
+ - `switch` 到 Copilot provider 时,bridge 应自动启动或复用
50
+ - 用户也可以通过 `bridge` 命令族手动启动、停止和查看状态
51
+ - `0.0.9` 的“守护进程”语义仅指 detached 用户态后台进程,不等同于 OS service
52
+
53
+ ## 命令面
54
+
55
+ 新增命令:
56
+
57
+ - `codexs bridge start [provider]`
58
+ - `codexs bridge stop [provider]`
59
+ - `codexs bridge status [provider]`
60
+
61
+ 命令规则:
62
+
63
+ - `bridge` 命令族只服务于 Copilot runtime-backed provider
64
+ - `provider` 可显式传入;未传入时优先使用当前 active provider
65
+ - 如果未传入且当前 active provider 不是 Copilot provider:
66
+ - TTY 下允许交互选择目标 Copilot provider
67
+ - 非交互或 `--json` 下必须明确失败
68
+ - `bridge start` 必须先完成:
69
+ - provider 解析
70
+ - runtime 配置校验
71
+ - SDK probe
72
+ - Copilot auth state 校验
73
+ - bridge 启动或复用
74
+ - healthcheck
75
+ - `bridge stop` 只停止当前受管 bridge 进程并清理 runtime state manifest,不修改 provider registry
76
+ - `bridge status` 返回 runtime state、provider 绑定关系、healthcheck 结果与异常原因
77
+
78
+ ## 生命周期规则
79
+
80
+ - `add --copilot` 只负责创建 provider 和可选安装 SDK,不负责启动 bridge
81
+ - `switch <copilot-provider>` 仍然是最常见的自动启动入口
82
+ - `bridge start` 与 `switch` 共享同一套 bridge 启动与复用逻辑
83
+ - 同一时刻只允许一个 bridge 实例处于受管运行状态
84
+ - 如果 bridge 已为同一 provider 运行且健康,则 `bridge start` 和 `switch` 都直接复用
85
+ - 如果已有 bridge 为另一 Copilot provider 运行:
86
+ - `bridge start <new-provider>` 先停止旧实例,再启动新实例
87
+ - `switch <new-provider>` 也遵守同样的单实例替换规则
88
+ - `bridge stop` 应该是幂等的:bridge 已停止时不报致命错误
89
+
90
+ ## 端口策略
91
+
92
+ - `--bridge-host` 默认 `127.0.0.1`
93
+ - `--bridge-port` 默认值必须是 5 位数端口
94
+ - Copilot provider 的默认端口不再使用 `4141`
95
+ - 如果 provider 指定端口已被占用:
96
+ - bridge 启动阶段必须自动检测冲突
97
+ - 自动选择新的可用 5 位数端口
98
+ - 自动更新 provider 的 runtime 配置和对应 `baseUrl`
99
+ - 自动保持 `config.toml` runtime projection 与 provider 配置一致
100
+ - 自动换端口后的新端口必须持久化,避免下一次启动再次撞到旧端口
101
+ - 端口自动切换只允许在 Copilot bridge provider 路径发生,不能影响 direct provider
102
+
103
+ ## 依赖策略
104
+
105
+ - `@github/copilot-sdk` 继续不进入 core CLI 默认依赖
106
+ - 命中 Copilot 路径时才 probe SDK
107
+ - SDK 自动安装仍然只允许发生在 `add --copilot`
108
+ - `bridge start`、`switch`、`status`、`doctor` 都不能隐式安装 SDK
109
+ - `bridge start` 在 SDK 缺失时必须明确失败,并提示回到 `add --copilot --install-copilot-sdk`
110
+ - SDK 运行前提仍然是用户本机已具备可用的 GitHub Copilot CLI / login 状态,`codex-switch` 不托管这部分登录数据
111
+
112
+ ## 数据边界
113
+
114
+ - `providers.json` 保存 Copilot provider、bridge host/port、`baseUrl` 与 shared secret
115
+ - `config.toml` 保存 Copilot provider 对应的 runtime `base_url` 与 `env_key`
116
+ - `auth.json` 只保存 Codex 到本地 bridge 的 shared secret
117
+ - runtime state manifest 保存当前 bridge 进程状态、provider 绑定、最后健康检查时间
118
+ - runtime state manifest 不进入 managed backup 事务
119
+ - GitHub/Copilot 上游认证状态仍然只由官方 SDK 管理,不进入受管 registry
120
+
121
+ ## 错误语义
122
+
123
+ `0.0.9` 继续稳定并收敛以下错误码:
124
+
125
+ - `COPILOT_SDK_MISSING`
126
+ - `COPILOT_SDK_INSTALL_FAILED`
127
+ - `COPILOT_SDK_INSTALL_REQUIRES_TTY`
128
+ - `COPILOT_SDK_UNSUPPORTED`
129
+ - `COPILOT_AUTH_REQUIRED`
130
+ - `COPILOT_PREMIUM_UNAVAILABLE`
131
+ - `BRIDGE_PORT_CONFLICT`
132
+ - `BRIDGE_START_FAILED`
133
+ - `BRIDGE_HEALTHCHECK_FAILED`
134
+ - `RUNTIME_PROVIDER_INVALID`
135
+ - `PROVIDER_BASE_URL_MISMATCH`
136
+
137
+ 新增要求:
138
+
139
+ - `bridge start`、`switch`、`bridge status` 对同一类 bridge 失败应尽量映射到同一类错误码
140
+ - 端口冲突在自动恢复成功时不应向上冒泡为致命失败
141
+ - 只有在无法找到可用端口或无法持久化新端口时,才允许保留 `BRIDGE_PORT_CONFLICT` 失败
142
+
143
+ ## 验收标准
144
+
145
+ - `add --copilot` 可以创建 Copilot provider,并写入 5 位数默认端口
146
+ - `switch` 到 Copilot provider 时完成 `probe -> auth check -> start or reuse bridge -> healthcheck -> config/auth write`
147
+ - `codexs bridge start [provider]` 可以手动启动或复用 bridge
148
+ - `codexs bridge stop [provider]` 可以手动停止当前 bridge,并清理 runtime state
149
+ - `codexs bridge status [provider]` 可以给出 bridge 是否运行、绑定哪个 provider、端口是多少、是否健康
150
+ - 当 bridge 目标端口被占用时,系统会自动切换到新的可用 5 位数端口,并持久化该变更
151
+ - direct provider 不经过 Copilot 特有的 runtime gate
152
+ - `status` / `doctor` 能诊断 SDK 缺失、认证缺失、bridge 不健康、stale runtime state、runtime base_url 漂移
153
+
154
+ ## 测试重点
155
+
156
+ - `bridge start/stop/status` 参数解析与帮助文案
157
+ - 省略 provider 时的 active provider 解析路径
158
+ - TTY 下的 Copilot provider 交互选择路径
159
+ - 非交互下目标 provider 不明确时的失败路径
160
+ - 单实例 bridge 的复用路径
161
+ - 单实例 bridge 的替换路径
162
+ - `switch` 与 `bridge start` 共享生命周期逻辑的回归
163
+ - 端口占用时的自动换端口与持久化
164
+ - stale runtime state 的诊断与清理
165
+ - `bridge stop` 幂等性
166
+ - direct provider 回归
@@ -0,0 +1,367 @@
1
+ # `0.0.9` Bridge Automated Testing Guide
2
+
3
+ This document defines the automated test strategy for the `0.0.9` Copilot bridge release.
4
+
5
+ ## Goal
6
+
7
+ The release must prove that the managed Copilot bridge can:
8
+
9
+ - resolve the correct provider target
10
+ - start, stop, and report status through the public CLI surface
11
+ - reuse one healthy instance for the same provider
12
+ - replace an existing managed instance for a different provider
13
+ - recover from preferred-port conflicts using another 5-digit port
14
+ - persist recovered ports into `providers.json` and `config.toml`
15
+ - clean up newly started workers when persistence fails
16
+ - surface stale runtime-state diagnostics through `status` and `doctor`
17
+
18
+ ## Test Layers
19
+
20
+ Bridge coverage is intentionally split across four layers.
21
+
22
+ ### 1. Runtime Layer
23
+
24
+ File: `tests/runtime.spec.js`
25
+
26
+ Use this layer for low-level worker/runtime behaviors:
27
+
28
+ - bridge HTTP health endpoint behavior
29
+ - worker fallback defaults
30
+ - port conflict recovery
31
+ - single-instance replacement at the runtime-state layer
32
+ - direct `probeCopilotBridgeRuntime()` status behavior
33
+
34
+ ### 2. Workflow Layer
35
+
36
+ File: `tests/workflows.spec.js`
37
+
38
+ Use this layer for app use cases and filesystem side effects:
39
+
40
+ - `startBridge`
41
+ - `stopBridge`
42
+ - `statusBridge`
43
+ - `switchProvider`
44
+ - `runDoctor`
45
+ - persistence and rollback behavior
46
+
47
+ ### 3. Command Layer
48
+
49
+ File: `tests/commands.spec.js`
50
+
51
+ Use this layer for registry, argument parsing, and dispatch wiring:
52
+
53
+ - nested command parsing
54
+ - help text
55
+ - `executeCommand()` dispatch for `bridge start|stop|status`
56
+ - mismatch-guard and unresolved-target error contracts
57
+
58
+ ### 4. Built CLI Layer
59
+
60
+ File: `tests/cli-e2e.spec.js`
61
+
62
+ Use this layer only for a small number of user-visible end-to-end checks:
63
+
64
+ - `bridge start --json`
65
+ - `bridge status --json`
66
+ - `bridge stop --json`
67
+ - stable JSON error envelopes for bridge failures
68
+
69
+ ## Shared Fixtures And Helpers
70
+
71
+ ### Existing helpers
72
+
73
+ - `tests/helpers.js`
74
+ - `makeSandboxCopy()`
75
+ - `makeEmptyCodexDir()`
76
+ - `runBuiltCli()`
77
+ - `runJsonCli()`
78
+ - `tests/workflows.spec.js`
79
+ - `makeFixture()`
80
+ - `withCodexAvailable()`
81
+ - `withFakeCopilotSdk()`
82
+ - `getFreePort()`
83
+ - `requestJson()`
84
+ - `tests/commands.spec.js`
85
+ - `makeTempCodexDir()`
86
+ - `writeBridgeFixture()`
87
+ - `withFakeCopilotSdk()`
88
+
89
+ ### Environment hooks
90
+
91
+ Mock bridge-oriented tests should continue to use:
92
+
93
+ - `CODEX_SWITCH_COPILOT_RUNTIME_DIR`
94
+ - `CODEX_SWITCH_RUNTIME_STATE_DIR`
95
+
96
+ These keep SDK loading and runtime-state persistence isolated inside temporary directories.
97
+
98
+ ## Required Automated Coverage
99
+
100
+ ### Runtime tests
101
+
102
+ Required scenarios:
103
+
104
+ - healthy in-process bridge serves `/healthz`
105
+ - worker fallback port remains `41415`
106
+ - `ensureCopilotBridge()` reuses a healthy worker for the same provider
107
+ - `ensureCopilotBridge()` replaces a different managed provider instance
108
+ - `ensureCopilotBridge()` recovers from preferred-port conflicts
109
+ - `ensureCopilotBridge()` reports startup failures with `BRIDGE_START_FAILED`
110
+
111
+ Recommended additions when extending runtime coverage:
112
+
113
+ - `probeCopilotBridgeRuntime()` with missing state
114
+ - `probeCopilotBridgeRuntime()` with stale state and no active Copilot provider
115
+ - `probeCopilotBridgeRuntime()` with base URL mismatch
116
+ - `probeCopilotBridgeRuntime()` with failed healthcheck
117
+
118
+ ### Workflow tests
119
+
120
+ Required scenarios:
121
+
122
+ - explicit `bridge start|status|stop`
123
+ - `bridge stop` idempotency without runtime state
124
+ - recovered-port persistence into `providers.json` and `config.toml`
125
+ - cleanup when recovered-port persistence fails for a newly started worker
126
+ - cleanup when recovered-port persistence fails after replacing a previous worker
127
+ - providers rollback when config projection update fails
128
+ - stale runtime-state surfaced by `status` and `doctor` while a direct provider is active
129
+ - `switchProvider()` keeps bridge cleanup semantics on failure
130
+
131
+ Recommended additions when extending workflow coverage:
132
+
133
+ - active-provider bridge target resolution without explicit provider argument
134
+ - sole Copilot provider resolution without explicit provider argument
135
+ - explicit mismatch guard for `bridge stop`
136
+ - explicit mismatch guard for `bridge status`
137
+ - `BRIDGE_TARGET_UNRESOLVED` for non-interactive multi-provider ambiguity
138
+
139
+ ### Command tests
140
+
141
+ Required scenarios:
142
+
143
+ - nested `bridge` command parsing
144
+ - bridge help text rendering
145
+ - `executeCommand()` dispatches `bridge start|status|stop`
146
+
147
+ Recommended additions when extending command coverage:
148
+
149
+ - `executeCommand()` mismatch guard for `bridge stop`
150
+ - `executeCommand()` mismatch guard for `bridge status`
151
+ - `executeCommand()` unresolved target failures
152
+
153
+ ### Built CLI tests
154
+
155
+ Required scenarios:
156
+
157
+ - `bridge start|status|stop` through the built CLI entrypoint
158
+ - read-command JSON envelope remains stable while `doctor` now may report multiple issue codes
159
+
160
+ Recommended additions when extending CLI coverage:
161
+
162
+ - `bridge status` stale runtime-state envelope
163
+ - `bridge start` unresolved-target envelope
164
+
165
+ ## Fast Execution Order
166
+
167
+ When time is limited, implement and verify tests in this order:
168
+
169
+ 1. `tests/commands.spec.js`
170
+ 2. `tests/workflows.spec.js`
171
+ 3. `tests/cli-e2e.spec.js`
172
+ 4. `tests/runtime.spec.js`
173
+
174
+ This order catches the highest-value regressions first:
175
+
176
+ - wiring regressions
177
+ - persistence/cleanup regressions
178
+ - user-visible CLI regressions
179
+ - low-level runtime regressions
180
+
181
+ ## Running The Suite
182
+
183
+ Build and run all tests:
184
+
185
+ ```bash
186
+ npm test
187
+ ```
188
+
189
+ This runs:
190
+
191
+ ```bash
192
+ npm run build
193
+ node tests/run-tests.js
194
+ ```
195
+
196
+ ## Release Gate For `0.0.9`
197
+
198
+ Treat bridge automation as release-ready only when all of the following are true:
199
+
200
+ - `commands`, `runtime`, `workflows`, and `cli-e2e` all pass
201
+ - `bridge start|stop|status` are covered at both app and CLI layers
202
+ - single-instance reuse and replacement are covered
203
+ - recovered-port persistence and cleanup failure paths are covered
204
+ - stale runtime-state diagnostics are covered in both `status` and `doctor`
205
+
206
+ ## Remaining Manual Smoke Checks
207
+
208
+ Automated coverage does not replace a final real-environment smoke pass.
209
+
210
+ Before shipping, still run a logged-in Copilot smoke check for:
211
+
212
+ - real `bridge start`
213
+ - real `bridge status`
214
+ - one real request through `/v1/chat/completions`
215
+ - real `bridge stop`
216
+ - real `switch <copilot-provider>` reuse/replacement behavior
217
+
218
+ ## Minimal Manual Smoke Checklist
219
+
220
+ Use this short checklist after the automated suite passes and after you have logged into Copilot in the real target environment.
221
+
222
+ ### Preconditions
223
+
224
+ - run from the repository root
225
+ - use the real Codex directory you intend to validate
226
+ - ensure the target Copilot provider already exists in `providers.json`
227
+ - ensure the optional Copilot SDK is installed
228
+ - ensure you are logged into Copilot before starting the live smoke pass
229
+
230
+ Suggested placeholder values:
231
+
232
+ - `<CODEX_DIR>`: your real Codex directory
233
+ - `<COPILOT_PROVIDER>`: the Copilot-backed provider name you want to validate
234
+
235
+ ### 1. Confirm the automated gate is still green
236
+
237
+ ```bash
238
+ npm test
239
+ ```
240
+
241
+ Expected result:
242
+
243
+ - build succeeds
244
+ - all automated suites pass
245
+
246
+ ### 2. Start the real managed bridge
247
+
248
+ ```bash
249
+ node dist/cli.js bridge start <COPILOT_PROVIDER> --json --codex-dir <CODEX_DIR>
250
+ ```
251
+
252
+ Expected result:
253
+
254
+ - command exits successfully
255
+ - JSON payload reports the requested provider
256
+ - payload includes `host`, `port`, and `baseUrl`
257
+ - `reused` is `false` on the first successful start unless a healthy matching bridge is already running
258
+
259
+ ### 3. Confirm bridge status
260
+
261
+ ```bash
262
+ node dist/cli.js bridge status <COPILOT_PROVIDER> --json --codex-dir <CODEX_DIR>
263
+ ```
264
+
265
+ Expected result:
266
+
267
+ - command exits successfully
268
+ - `health.ok` is `true`
269
+ - `active` is `true`
270
+ - `matches` is `true`
271
+
272
+ ### 4. Send one real request through the bridge
273
+
274
+ Use the `baseUrl` and API key from the selected provider record. Replace `<BRIDGE_BASE_URL>` and `<BRIDGE_API_KEY>` with real values from your environment.
275
+
276
+ ```bash
277
+ curl -sS <BRIDGE_BASE_URL>/chat/completions \
278
+ -H "Content-Type: application/json" \
279
+ -H "Authorization: Bearer <BRIDGE_API_KEY>" \
280
+ -d "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"user\",\"content\":\"Reply with the single word OK.\"}]}"
281
+ ```
282
+
283
+ Expected result:
284
+
285
+ - HTTP request succeeds
286
+ - response contains a completion payload
287
+ - model output proves the request reached the live bridge successfully
288
+
289
+ If your shell or environment prefers the OpenAI-style path, validate the same request against:
290
+
291
+ ```text
292
+ <BRIDGE_BASE_URL>/chat/completions
293
+ ```
294
+
295
+ ### 5. Verify same-provider reuse
296
+
297
+ Run the start command again:
298
+
299
+ ```bash
300
+ node dist/cli.js bridge start <COPILOT_PROVIDER> --json --codex-dir <CODEX_DIR>
301
+ ```
302
+
303
+ Expected result:
304
+
305
+ - command exits successfully
306
+ - `reused` is `true`
307
+ - reported `port` remains stable
308
+
309
+ ### 6. Verify switch reuse or replacement behavior
310
+
311
+ Run a real switch into the Copilot provider:
312
+
313
+ ```bash
314
+ node dist/cli.js switch <COPILOT_PROVIDER> --json --codex-dir <CODEX_DIR>
315
+ ```
316
+
317
+ Expected result:
318
+
319
+ - command exits successfully
320
+ - provider/profile switch succeeds
321
+ - if the same healthy bridge is already running, it is reused
322
+ - if another managed bridge instance was active, it is replaced cleanly
323
+
324
+ If you have a second Copilot provider available, also validate explicit replacement:
325
+
326
+ ```bash
327
+ node dist/cli.js bridge start <SECOND_COPILOT_PROVIDER> --json --codex-dir <CODEX_DIR>
328
+ ```
329
+
330
+ Expected result:
331
+
332
+ - previous managed instance is replaced
333
+ - status for the new provider is healthy
334
+ - no stale runtime-state mismatch is left behind
335
+
336
+ ### 7. Stop the managed bridge
337
+
338
+ ```bash
339
+ node dist/cli.js bridge stop <COPILOT_PROVIDER> --json --codex-dir <CODEX_DIR>
340
+ ```
341
+
342
+ Expected result:
343
+
344
+ - command exits successfully
345
+ - payload reports `stopped: true`
346
+
347
+ ### 8. Confirm shutdown state
348
+
349
+ ```bash
350
+ node dist/cli.js bridge status <COPILOT_PROVIDER> --json --codex-dir <CODEX_DIR>
351
+ ```
352
+
353
+ Expected result:
354
+
355
+ - command may either report inactive bridge health or a missing runtime state, depending on the exact environment state
356
+ - it must not falsely report a healthy active managed bridge after stop
357
+
358
+ ### Manual Pass Criteria
359
+
360
+ Treat the live smoke pass as complete only when all of the following are true:
361
+
362
+ - `bridge start` succeeds in a logged-in real environment
363
+ - `bridge status` reports a healthy active bridge
364
+ - one real request succeeds through the bridge
365
+ - repeated `bridge start` reuses the same healthy instance
366
+ - `switch <copilot-provider>` preserves expected reuse/replacement behavior
367
+ - `bridge stop` shuts the managed instance down cleanly
package/docs/cli-usage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # codex-switch CLI Usage
2
2
 
3
- 本文档详细介绍 `codex-switch` 在 `0.0.4` 版本中的命令、参数、交互规则和典型使用方式。
3
+ 本文档详细介绍 `codex-switch` 在 `0.0.10` 版本中的命令、参数、交互规则和典型使用方式。
4
4
 
5
5
  可执行命令名:
6
6
 
@@ -260,9 +260,9 @@ codexs migrate --merge --codex-dir ./.tmp-codex
260
260
  行为说明:
261
261
 
262
262
  - 读取 `config.toml` 中已有 profile
263
- - 仅 adopt 已具备 `model`、`model_provider` 且能解析到匹配 `model_providers.*.base_url` 和 `env_key` 的 unmanaged profile
263
+ - 仅 adopt 已具备 `model`、`model_provider` 且能解析到匹配 `model_providers.*.base_url` 的 unmanaged profile
264
264
  - 收集每个 profile 对应的 provider 记录
265
- - 保持现有受管备份、锁、`auth.json` mirror 和 post-run `doctor` 流程
265
+ - 保持现有受管备份、锁和 post-run `doctor` 流程,不重写 `auth.json`
266
266
 
267
267
  交互模式:
268
268
 
@@ -291,14 +291,15 @@ codexs setup
291
291
 
292
292
  ### 5.4 `add`
293
293
 
294
- 新增一个 provider
294
+ 新增一个 provider。`add` 当前同时支持 direct provider 和 Copilot bridge provider 两条路径。
295
295
 
296
296
  ```bash
297
297
  codexs add <provider> --profile <name> --api-key <key> [--base-url <url>] [--note <text>] [--tag <tag> ...]
298
- codexs add [--profile <name>] [--api-key <key>] [--base-url <url>] [--note <text>] [--tag <tag> ...]
298
+ codexs add <provider> --copilot --profile <name> [--bridge-host <host>] [--bridge-port <port>] [--bridge-api-key <secret>] [--install-copilot-sdk]
299
+ codexs add
299
300
  ```
300
301
 
301
- 示例:
302
+ direct provider 示例:
302
303
 
303
304
  ```bash
304
305
  codexs add packycode --profile packycode --api-key sk-xxx
@@ -306,7 +307,14 @@ codexs add packycode --profile packycode --api-key sk-xxx --tag paid --tag daily
306
307
  codexs add
307
308
  ```
308
309
 
309
- 字段说明:
310
+ Copilot provider 示例:
311
+
312
+ ```bash
313
+ codexs add copilot-main --copilot --profile copilot-main --install-copilot-sdk
314
+ codexs add copilot-main --copilot --profile copilot-main --bridge-port 41415 --bridge-api-key local-secret
315
+ ```
316
+
317
+ direct provider 字段说明:
310
318
 
311
319
  - `provider`:provider 名称,也是后续 `switch/show/edit/remove` 的标识
312
320
  - `--profile`:写入到 `config.toml` 的 profile 名称
@@ -315,16 +323,31 @@ codexs add
315
323
  - `--note`:备注
316
324
  - `--tag`:标签,可重复传多次
317
325
 
326
+ Copilot provider 字段说明:
327
+
328
+ - `--copilot`:切换到 Copilot provider 模式
329
+ - `--profile`:必填
330
+ - `--api-key`:在 `--copilot` 下禁止使用;Copilot 不接收 direct provider API key
331
+ - `--bridge-host`:本地 bridge host,默认 `127.0.0.1`
332
+ - `--bridge-port`:本地 bridge port,默认 `41415`
333
+ - `--bridge-api-key`:本地 bridge shared secret;留空时自动生成
334
+ - `--install-copilot-sdk`:允许在首次接入时安装可选 Copilot SDK runtime
335
+
318
336
  交互模式:
319
337
 
320
- - 如果缺少 `provider`、`profile`、`apiKey`,会在 TTY 中补问
321
- - profile 选择会优先复用现有 `config.toml` profile
322
- - API key 的隐藏输入会做二次确认
323
- - tag 仅支持预设选项多选
338
+ - direct provider 缺少 `provider`、`profile`、`apiKey` 时,会在 TTY 中补问
339
+ - direct provider API key 隐藏输入会做二次确认
340
+ - Copilot provider 会先做固定 preflight:检查 SDK、必要时立即安装、检查 GitHub Copilot 登录态、必要时执行官方 `copilot login`,全部通过后才进入专用输入流
341
+ - Copilot provider 的专用输入流只采集 provider/profile/model、note/tags 和 bridge 参数
342
+ - Copilot provider 不会提示 `API key`、`Confirm API key` 或输出 `API key is required.`
343
+ - 若官方 `copilot login` 无法启动,会回退为人工提示:运行 `copilot login`,完成 GitHub 官方 device/browser 流程后执行一次明确 recheck
344
+ - `add --copilot --json` 永远不会启动登录流程;若 auth 未就绪,直接返回 `COPILOT_AUTH_REQUIRED`,并提示手动运行 `copilot login`
324
345
 
325
346
  非交互模式:
326
347
 
327
- - 必须显式传入所有必填字段
348
+ - direct provider 必须显式传入所有必填字段
349
+ - `add --copilot` 必须显式传入 `<provider>` 和 `--profile`
350
+ - `add --copilot --json` 不会进入任何 prompt;若 SDK 缺失且未传 `--install-copilot-sdk`,直接失败;若 auth 未就绪,也直接返回 `COPILOT_AUTH_REQUIRED`
328
351
 
329
352
  ### 5.5 `edit`
330
353
 
@@ -377,8 +400,9 @@ codexs switch
377
400
 
378
401
  - 根据 `providers.json` 找到目标 provider
379
402
  - 更新相关运行态配置
380
- - 重写当前 active provider 对应的 `auth.json` mirror
381
- - 会先备份 `config.toml` `auth.json`
403
+ - direct provider 会切换当前 active profile,并将 `auth.json` 重写为 `auth_mode = "apikey"` 和 `OPENAI_API_KEY = <provider.apiKey>`
404
+ - Copilot bridge provider 不写 `OPENAI_API_KEY`,而是维护本地 bridge 路由
405
+ - 备份 `config.toml`,并在 direct provider 切换时一并备份 `auth.json`
382
406
 
383
407
  交互模式:
384
408
 
@@ -150,7 +150,7 @@ MVP 的能力范围主要包括:
150
150
 
151
151
  - `config.toml` 是主配置文件
152
152
  - `providers.json` 是 `codex-switch` 自身维护的 provider 清单
153
- - `auth.json` 在存在时会被纳入备份与回滚考虑
153
+ - `auth.json` 是当前 active direct provider 的认证投影文件;切换 direct provider 时会刷新 `OPENAI_API_KEY`
154
154
  - `backups/` 用于保存历史备份
155
155
 
156
156
  产品不会要求用户先理解全部内部实现,只暴露统一的命令接口。
@@ -167,7 +167,7 @@ MVP 的能力范围主要包括:
167
167
 
168
168
  ### 场景 3:切换到目标 provider
169
169
 
170
- 用户执行切换命令后,工具会完成校验、备份、修改和必要的登录动作。
170
+ 用户执行切换命令后,工具会完成校验、备份、修改运行态配置,并在 direct provider 场景下同步 `auth.json`。
171
171
 
172
172
  ### 场景 4:出现异常时恢复
173
173
 
@@ -98,7 +98,7 @@
98
98
  - `Low Coupling`
99
99
  - 参数解析、业务编排、文件访问、错误模型彼此解耦
100
100
  - `Split State Model`
101
- - `providers.json` 是管理态事实源,`config.toml` / `auth.json` 是运行态镜像
101
+ - `providers.json` 是管理态事实源,`config.toml` 是运行态路由文件,`auth.json` 是 direct provider 的认证投影
102
102
  - `Lightweight Transactions`
103
103
  - 单次写操作要有锁、备份、回滚边界
104
104
 
@@ -125,7 +125,8 @@ Infrastructure 层
125
125
  当前实现还明确区分三类状态对象:
126
126
 
127
127
  - 管理态单一事实源:`providers.json`
128
- - 运行态镜像:`config.toml`、`auth.json`
128
+ - 运行态路由:`config.toml`
129
+ - 当前 active direct provider 的认证投影:`auth.json`
129
130
  - 回滚态:`backups/latest.json` 和对应 manifest
130
131
 
131
132
  这意味着未来即使引入 GUI / MCP / HTTP 适配层,核心同步目标仍然是 runtime files,而不是把 runtime files 本身当成长期管理数据库。
@@ -555,13 +556,13 @@ scripts/
555
556
  - 深度解析 profile 内部更多字段
556
557
  - 管理 base URL 或模型等 profile 内容
557
558
 
558
- 它在当前架构里属于运行态镜像,只承担“当前活跃 profile 落地”的职责。
559
+ 它在当前架构里是 direct provider 的认证投影文件,不承担 provider 选择职责,也不作为 provider registry 的事实源。
559
560
 
560
561
  ### 5.3 `auth.json`
561
562
 
562
563
  当前实现不直接建模其内部字段,但它有明确架构角色:
563
564
 
564
- - 属于运行态镜像
565
+ - 属于 direct provider 的认证投影
565
566
  - 在存在时纳入备份与回滚
566
567
  - 不是 provider registry 的事实源
567
568
 
@@ -622,7 +623,7 @@ scripts/
622
623
  6. 校验 provider 对应的 `profile` 在配置中存在
623
624
  7. 创建备份:
624
625
  - `config.toml`
625
- - `auth.json`(如果存在)
626
+ - `auth.json` 仅在历史备份清单已包含时由 rollback 兼容恢复
626
627
  8. 更新顶层 `profile`
627
628
  9. 如果未传 `--no-login`,执行 `codex login --with-api-key`
628
629
  10. 成功后把这次备份记录为 `latest.json`