@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.
- package/README.AI.md +68 -73
- package/README.CN.md +108 -111
- package/README.md +87 -80
- package/dist/app/add-provider.js +29 -15
- package/dist/app/bridge.js +15 -14
- package/dist/app/edit-provider.js +1 -1
- package/dist/app/get-status.js +21 -9
- package/dist/app/import-providers.js +1 -1
- package/dist/app/init-codex.js +13 -14
- package/dist/app/list-providers.js +48 -1
- package/dist/app/remove-provider.js +1 -1
- package/dist/app/run-doctor.js +12 -5
- package/dist/app/run-mutation.js +3 -2
- package/dist/app/setup-codex.js +3 -1
- package/dist/app/switch-provider.js +11 -13
- package/dist/cli/output.js +145 -18
- package/dist/cli.js +34 -2
- package/dist/commands/args.js +2 -2
- package/dist/commands/dispatch.js +40 -0
- package/dist/commands/handlers.js +130 -161
- package/dist/commands/help.js +11 -5
- package/dist/commands/registry.js +42 -20
- package/dist/domain/backups.js +4 -4
- package/dist/domain/config.js +110 -5
- package/dist/domain/providers.js +12 -0
- package/dist/domain/runtime-state.js +111 -13
- package/dist/infra/config-repo.js +16 -206
- package/dist/interaction/interactive.js +16 -6
- package/dist/runtime/copilot-adapter.js +12 -12
- package/dist/runtime/copilot-bridge.js +394 -45
- package/dist/runtime/copilot-cli.js +84 -12
- package/dist/runtime/copilot-installer.js +10 -9
- package/dist/runtime/copilot-sdk-loader.js +5 -5
- package/dist/storage/backup-repo.js +4 -4
- package/dist/storage/codex-paths.js +34 -8
- package/dist/storage/config-repo.js +0 -23
- package/dist/storage/lock-repo.js +2 -4
- package/dist/storage/runtime-state-repo.js +14 -13
- package/dist/storage/tool-config-repo.js +111 -0
- package/docs/Design/codex-switch-v0.0.11-design.md +824 -0
- package/docs/Design/codex-switch-v0.0.12-design.md +343 -0
- package/docs/PRD/codex-switch-prd-v0.0.11.md +577 -0
- package/docs/PRD/codex-switch-prd-v0.0.12.md +279 -0
- package/docs/PRD/codex-switch-prd-v0.1.0.md +125 -237
- package/docs/Tests/testing.md +39 -112
- package/docs/cli-usage.md +135 -565
- package/docs/codex-switch-command-design.md +3 -0
- package/docs/codex-switch-product-overview.md +52 -207
- package/docs/codex-switch-technical-architecture.md +3 -0
- package/package.json +1 -1
- package/dist/app/rollback-latest.js +0 -26
package/README.md
CHANGED
|
@@ -1,136 +1,149 @@
|
|
|
1
|
-
|
|
1
|
+
# @minniexcode/codex-switch
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@minniexcode/codex-switch` is a local-first CLI for managing and switching Codex provider and profile configuration safely.
|
|
4
4
|
|
|
5
|
-
It
|
|
5
|
+
It keeps `codex-switch` tool state separate from the target Codex runtime, so provider management, backup flow, and runtime projection stay explicit instead of relying on manual file edits.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Chinese version: [README.CN.md](./README.CN.md)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Version
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Current package version: `0.0.12`
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
- Migrate unmanaged runtime profiles from an existing Codex directory
|
|
15
|
-
- List, show, add, edit, and remove provider records
|
|
16
|
-
- Switch the active provider/profile safely
|
|
17
|
-
- Import and export provider definitions
|
|
18
|
-
- Run diagnostics and detect local drift
|
|
19
|
-
- List backups and roll back to a previous managed state
|
|
20
|
-
|
|
21
|
-
Current version: `0.0.10`
|
|
13
|
+
This repository is still on a development-version line. The current release focuses on making the primary workflows, help text, and operational boundaries consistent with the implementation.
|
|
22
14
|
|
|
23
15
|
## Install
|
|
24
16
|
|
|
25
|
-
Install globally:
|
|
26
|
-
|
|
27
17
|
```bash
|
|
28
18
|
npm install -g @minniexcode/codex-switch
|
|
29
19
|
```
|
|
30
20
|
|
|
31
|
-
|
|
21
|
+
Run without a global install:
|
|
32
22
|
|
|
33
23
|
```bash
|
|
34
24
|
npx @minniexcode/codex-switch --help
|
|
35
25
|
```
|
|
36
26
|
|
|
37
|
-
CLI
|
|
27
|
+
Built CLI entrypoint:
|
|
38
28
|
|
|
39
29
|
```bash
|
|
40
30
|
codexs --help
|
|
41
31
|
```
|
|
42
32
|
|
|
43
|
-
##
|
|
33
|
+
## Primary Workflows
|
|
44
34
|
|
|
45
|
-
|
|
35
|
+
Direct provider workflow:
|
|
46
36
|
|
|
47
37
|
```bash
|
|
48
38
|
codexs init
|
|
49
|
-
codexs
|
|
39
|
+
codexs add my-provider --profile my-provider --api-key sk-xxx
|
|
40
|
+
codexs switch my-provider
|
|
41
|
+
codexs status
|
|
42
|
+
codexs doctor
|
|
50
43
|
```
|
|
51
44
|
|
|
52
|
-
|
|
45
|
+
GitHub Copilot workflow:
|
|
53
46
|
|
|
54
47
|
```bash
|
|
55
|
-
codexs
|
|
56
|
-
codexs
|
|
48
|
+
codexs init
|
|
49
|
+
codexs login copilot
|
|
50
|
+
codexs add copilot-main --copilot --profile copilot-main
|
|
51
|
+
codexs switch copilot-main
|
|
52
|
+
codexs status
|
|
53
|
+
codexs doctor
|
|
57
54
|
```
|
|
58
55
|
|
|
59
|
-
|
|
56
|
+
Notes:
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
- `init` prepares the `codex-switch` tool home and managed state.
|
|
59
|
+
- `login copilot` handles upstream Copilot onboarding and auth readiness.
|
|
60
|
+
- `add --copilot` does not perform login for you; it assumes Copilot login is already ready.
|
|
61
|
+
- `status` is the main read command after switching.
|
|
62
|
+
- `doctor` is the main repair-oriented diagnostic command.
|
|
63
|
+
|
|
64
|
+
## Advanced Adopt Workflow
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Use `migrate` only when you already have Codex runtime state that should be adopted into managed `providers.json` state:
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
codexs
|
|
70
|
-
codexs
|
|
71
|
-
codexs doctor
|
|
69
|
+
codexs init
|
|
70
|
+
codexs migrate
|
|
72
71
|
```
|
|
73
72
|
|
|
74
|
-
|
|
73
|
+
`migrate` is an advanced adopt helper. It is not the default first step for a fresh install.
|
|
74
|
+
|
|
75
|
+
## Command Surface
|
|
75
76
|
|
|
76
77
|
```bash
|
|
77
78
|
codexs init
|
|
79
|
+
codexs login copilot
|
|
78
80
|
codexs migrate
|
|
79
81
|
codexs list
|
|
80
82
|
codexs show <provider>
|
|
81
83
|
codexs current
|
|
82
84
|
codexs status
|
|
85
|
+
codexs config show [profile]
|
|
86
|
+
codexs config list-profiles
|
|
83
87
|
codexs add <provider> --profile <name> --api-key <key>
|
|
84
|
-
codexs
|
|
88
|
+
codexs add <provider> --copilot --profile <name>
|
|
89
|
+
codexs edit <provider>
|
|
85
90
|
codexs switch <provider>
|
|
86
|
-
codexs remove <provider>
|
|
87
|
-
codexs import <file>
|
|
88
|
-
codexs export <file>
|
|
91
|
+
codexs remove <provider> [--force] [--switch-to <profile>]
|
|
92
|
+
codexs import <file>
|
|
93
|
+
codexs export <file> [--force]
|
|
94
|
+
codexs bridge start [provider]
|
|
95
|
+
codexs bridge status [provider]
|
|
96
|
+
codexs bridge stop [provider]
|
|
89
97
|
codexs backups list
|
|
90
98
|
codexs rollback [backup-id]
|
|
91
99
|
codexs doctor
|
|
92
100
|
```
|
|
93
101
|
|
|
94
|
-
|
|
102
|
+
`setup` still exists only as a deprecated compatibility entry that points callers to `init` or `migrate`.
|
|
95
103
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
codexs help migrate
|
|
100
|
-
codexs help setup
|
|
101
|
-
```
|
|
104
|
+
## Runtime Model
|
|
105
|
+
|
|
106
|
+
`codex-switch` uses a dual-path model.
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
Tool home:
|
|
104
109
|
|
|
105
|
-
|
|
110
|
+
```text
|
|
111
|
+
~/.config/codex-switch/
|
|
112
|
+
codex-switch.json
|
|
113
|
+
providers.json
|
|
114
|
+
backups/
|
|
115
|
+
runtime/
|
|
116
|
+
runtimes/
|
|
117
|
+
```
|
|
106
118
|
|
|
107
|
-
|
|
119
|
+
Target Codex runtime:
|
|
108
120
|
|
|
109
121
|
```text
|
|
110
122
|
~/.codex/
|
|
111
123
|
config.toml
|
|
112
124
|
auth.json
|
|
113
|
-
providers.json
|
|
114
|
-
backups/
|
|
115
125
|
```
|
|
116
126
|
|
|
117
|
-
|
|
127
|
+
Key points:
|
|
118
128
|
|
|
119
|
-
- `providers.json` is the managed provider registry
|
|
120
|
-
- `
|
|
121
|
-
- `
|
|
122
|
-
-
|
|
123
|
-
-
|
|
129
|
+
- `providers.json` is the managed provider registry and lives under the tool home.
|
|
130
|
+
- `codex-switch.json` stores tool-level metadata such as `defaultCodexDir`.
|
|
131
|
+
- `config.toml` remains the active runtime routing file in the target Codex directory.
|
|
132
|
+
- `auth.json` remains the active auth projection file in the target Codex directory.
|
|
133
|
+
- Direct providers rewrite `OPENAI_API_KEY` into the active runtime projection.
|
|
134
|
+
- Copilot providers keep upstream GitHub authentication in the official Copilot runtime while `codex-switch` manages local bridge state and routing.
|
|
124
135
|
|
|
125
|
-
|
|
136
|
+
Path controls:
|
|
126
137
|
|
|
127
|
-
|
|
138
|
+
- `--codex-dir <path>` targets a specific Codex runtime directory.
|
|
139
|
+
- `CODEXS_CODEX_DIR` provides the default target runtime when `--codex-dir` is not passed.
|
|
140
|
+
- `CODEXS_HOME` overrides the tool home location.
|
|
128
141
|
|
|
129
|
-
|
|
130
|
-
- `init` is automation-friendly and idempotent, but still returns a structured error in non-interactive or `--json` mode when the resolved target directory does not exist.
|
|
131
|
-
- `migrate` remains intentionally TTY-only for adopt initialization. It requires interactive profile selection and provider detail collection, and non-interactive/`--json` runs fail fast with a structured error.
|
|
142
|
+
## Automation Notes
|
|
132
143
|
|
|
133
|
-
|
|
144
|
+
This CLI supports both human TTY usage and non-interactive automation.
|
|
145
|
+
|
|
146
|
+
Global flags:
|
|
134
147
|
|
|
135
148
|
```bash
|
|
136
149
|
--json
|
|
@@ -139,37 +152,31 @@ Recommended global flags:
|
|
|
139
152
|
--version
|
|
140
153
|
```
|
|
141
154
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- use `--json` for stable machine-readable output
|
|
145
|
-
- pass all required arguments explicitly in scripts or CI
|
|
146
|
-
- use `--codex-dir <path>` for sandbox or test environments
|
|
155
|
+
Operational limits:
|
|
147
156
|
|
|
148
|
-
|
|
157
|
+
- `login copilot` requires a real TTY and does not support `--json`.
|
|
158
|
+
- `migrate` still depends on interactive profile selection and provider-detail collection in this release.
|
|
159
|
+
- Automation should pass explicit arguments and prefer `--json` for stable parsing.
|
|
149
160
|
|
|
150
|
-
|
|
161
|
+
## Local Development
|
|
151
162
|
|
|
152
163
|
```bash
|
|
153
164
|
npm run build
|
|
154
165
|
npm test
|
|
166
|
+
npx tsc --noEmit
|
|
167
|
+
node dist/cli.js --help
|
|
168
|
+
npm pack --dry-run
|
|
155
169
|
```
|
|
156
170
|
|
|
157
|
-
The repository includes a development fixture under `dev-codex/local-sandbox` plus dedicated test docs:
|
|
158
|
-
|
|
159
|
-
- [Testing Guide](./docs/testing.md)
|
|
160
|
-
- [Test Report for 0.0.5](./docs/test-report-0.0.5.md)
|
|
161
|
-
|
|
162
171
|
## Documentation
|
|
163
172
|
|
|
164
173
|
- [Chinese README](./README.CN.md)
|
|
165
174
|
- [AI README](./README.AI.md)
|
|
166
175
|
- [Detailed CLI Usage](./docs/cli-usage.md)
|
|
167
|
-
- [Testing Guide](./docs/testing.md)
|
|
168
|
-
- [Test Report for 0.0.5](./docs/test-report-0.0.5.md)
|
|
176
|
+
- [Testing Guide](./docs/Tests/testing.md)
|
|
169
177
|
- [Product Overview](./docs/codex-switch-product-overview.md)
|
|
170
|
-
- [
|
|
171
|
-
- [
|
|
172
|
-
- [Design Doc 0.0.4](./docs/Design/codex-switch-v0.0.4-design.md)
|
|
178
|
+
- [PRD 0.0.12](./docs/PRD/codex-switch-prd-v0.0.12.md)
|
|
179
|
+
- [Release Gate PRD 0.1.0](./docs/PRD/codex-switch-prd-v0.1.0.md)
|
|
173
180
|
|
|
174
181
|
## License
|
|
175
182
|
|
package/dist/app/add-provider.js
CHANGED
|
@@ -41,12 +41,13 @@ const errors_1 = require("../domain/errors");
|
|
|
41
41
|
const config_repo_1 = require("../storage/config-repo");
|
|
42
42
|
const fs_utils_1 = require("../storage/fs-utils");
|
|
43
43
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
44
|
+
const copilot_adapter_1 = require("../runtime/copilot-adapter");
|
|
44
45
|
const copilot_installer_1 = require("../runtime/copilot-installer");
|
|
45
46
|
const run_mutation_1 = require("./run-mutation");
|
|
46
47
|
/**
|
|
47
48
|
* Adds a new provider record to the managed providers registry.
|
|
48
49
|
*/
|
|
49
|
-
function addProvider(args) {
|
|
50
|
+
async function addProvider(args) {
|
|
50
51
|
(0, fs_utils_1.ensureDir)(args.codexDir);
|
|
51
52
|
const providers = (0, providers_repo_1.readProvidersFileIfExists)(args.providersPath);
|
|
52
53
|
if (providers.providers[args.providerName]) {
|
|
@@ -67,17 +68,26 @@ function addProvider(args) {
|
|
|
67
68
|
}
|
|
68
69
|
: undefined;
|
|
69
70
|
if (args.copilot) {
|
|
70
|
-
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)();
|
|
71
|
+
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)(args.runtimesDir);
|
|
71
72
|
if (!installStatus.installed) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
throw (0, errors_1.cliError)("COPILOT_SDK_MISSING", "The optional Copilot SDK runtime is not installed. Run `codexs login copilot` first.", {
|
|
74
|
+
installDir: installStatus.installDir,
|
|
75
|
+
packageName: installStatus.packageName,
|
|
76
|
+
suggestion: "Run `codexs login copilot` to install the Copilot SDK and complete login.",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
await (0, copilot_adapter_1.readCopilotAuthState)(args.runtimesDir);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
const normalized = (0, errors_1.normalizeError)(error);
|
|
84
|
+
if (normalized.code === "COPILOT_AUTH_REQUIRED") {
|
|
85
|
+
throw (0, errors_1.cliError)("COPILOT_AUTH_REQUIRED", "Copilot authentication is required before a Copilot provider can be added.", {
|
|
86
|
+
...(normalized.details ?? {}),
|
|
87
|
+
suggestion: "Run `codexs login copilot` to complete GitHub Copilot login.",
|
|
78
88
|
});
|
|
79
89
|
}
|
|
80
|
-
|
|
90
|
+
throw error;
|
|
81
91
|
}
|
|
82
92
|
}
|
|
83
93
|
const document = (0, config_repo_1.readStructuredConfig)(args.configPath);
|
|
@@ -97,13 +107,17 @@ function addProvider(args) {
|
|
|
97
107
|
}),
|
|
98
108
|
}
|
|
99
109
|
: undefined;
|
|
100
|
-
const upsertModelProviders =
|
|
110
|
+
const upsertModelProviders = args.copilot
|
|
101
111
|
? {
|
|
102
|
-
[args.profile]:
|
|
103
|
-
baseUrl: args.copilot ? (0, providers_1.buildCopilotBridgeBaseUrl)(runtime) : args.baseUrl ?? undefined,
|
|
104
|
-
},
|
|
112
|
+
[args.profile]: (0, providers_1.buildCopilotModelProviderProjection)(runtime),
|
|
105
113
|
}
|
|
106
|
-
:
|
|
114
|
+
: !existingModelProvider && args.createProfile
|
|
115
|
+
? {
|
|
116
|
+
[args.profile]: {
|
|
117
|
+
baseUrl: args.baseUrl ?? undefined,
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
: undefined;
|
|
107
121
|
if (existingProfile) {
|
|
108
122
|
(0, config_repo_1.requireManagedProfileRuntime)(document, providers, args.profile);
|
|
109
123
|
}
|
|
@@ -123,7 +137,7 @@ function addProvider(args) {
|
|
|
123
137
|
},
|
|
124
138
|
};
|
|
125
139
|
return (0, run_mutation_1.runMutation)({
|
|
126
|
-
|
|
140
|
+
lockPath: args.lockPath,
|
|
127
141
|
backupsDir: args.backupsDir,
|
|
128
142
|
latestBackupPath: args.latestBackupPath,
|
|
129
143
|
operation: "add",
|
package/dist/app/bridge.js
CHANGED
|
@@ -22,13 +22,14 @@ async function startBridge(args) {
|
|
|
22
22
|
requestedProviderName: args.providerName ?? null,
|
|
23
23
|
providers,
|
|
24
24
|
configPath: args.configPath,
|
|
25
|
+
runtimeDir: args.runtimeDir,
|
|
25
26
|
runtime: args.runtime,
|
|
26
27
|
json: args.json,
|
|
27
28
|
commandName: "start",
|
|
28
29
|
preferRuntimeState: false,
|
|
29
30
|
});
|
|
30
|
-
await requireBridgeRuntimeReadiness();
|
|
31
|
-
const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(target.providerName, target.provider);
|
|
31
|
+
await requireBridgeRuntimeReadiness(args.runtimesDir);
|
|
32
|
+
const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(target.providerName, target.provider, args.runtimeDir);
|
|
32
33
|
const nextProvider = bridge.portChanged ? rewriteBridgeProviderPort(target.provider, bridge.port) : target.provider;
|
|
33
34
|
if (bridge.portChanged) {
|
|
34
35
|
try {
|
|
@@ -43,7 +44,7 @@ async function startBridge(args) {
|
|
|
43
44
|
}
|
|
44
45
|
catch (error) {
|
|
45
46
|
if (!bridge.reused) {
|
|
46
|
-
(0, copilot_bridge_1.stopCopilotBridge)();
|
|
47
|
+
(0, copilot_bridge_1.stopCopilotBridge)(args.runtimeDir);
|
|
47
48
|
}
|
|
48
49
|
throw error;
|
|
49
50
|
}
|
|
@@ -66,7 +67,7 @@ async function startBridge(args) {
|
|
|
66
67
|
*/
|
|
67
68
|
async function stopBridge(args) {
|
|
68
69
|
const providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
|
|
69
|
-
const state = (0, runtime_state_repo_1.readCopilotBridgeState)();
|
|
70
|
+
const state = (0, runtime_state_repo_1.readCopilotBridgeState)(args.runtimeDir);
|
|
70
71
|
if (!state && !args.providerName) {
|
|
71
72
|
return {
|
|
72
73
|
data: {
|
|
@@ -90,6 +91,7 @@ async function stopBridge(args) {
|
|
|
90
91
|
requestedProviderName: args.providerName ?? null,
|
|
91
92
|
providers,
|
|
92
93
|
configPath: args.configPath,
|
|
94
|
+
runtimeDir: args.runtimeDir,
|
|
93
95
|
runtime: args.runtime,
|
|
94
96
|
json: args.json,
|
|
95
97
|
commandName: "stop",
|
|
@@ -101,7 +103,7 @@ async function stopBridge(args) {
|
|
|
101
103
|
requestedProvider: args.providerName,
|
|
102
104
|
});
|
|
103
105
|
}
|
|
104
|
-
(0, copilot_bridge_1.stopCopilotBridge)();
|
|
106
|
+
(0, copilot_bridge_1.stopCopilotBridge)(args.runtimeDir);
|
|
105
107
|
return {
|
|
106
108
|
data: {
|
|
107
109
|
provider: target.providerName,
|
|
@@ -115,18 +117,19 @@ async function stopBridge(args) {
|
|
|
115
117
|
*/
|
|
116
118
|
async function statusBridge(args) {
|
|
117
119
|
const providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
|
|
118
|
-
const state = (0, runtime_state_repo_1.readCopilotBridgeState)();
|
|
120
|
+
const state = (0, runtime_state_repo_1.readCopilotBridgeState)(args.runtimeDir);
|
|
119
121
|
const target = await resolveBridgeTarget({
|
|
120
122
|
requestedProviderName: args.providerName ?? null,
|
|
121
123
|
providers,
|
|
122
124
|
configPath: args.configPath,
|
|
125
|
+
runtimeDir: args.runtimeDir,
|
|
123
126
|
runtime: args.runtime,
|
|
124
127
|
json: args.json,
|
|
125
128
|
commandName: "status",
|
|
126
129
|
preferRuntimeState: true,
|
|
127
130
|
});
|
|
128
131
|
const provider = target.provider;
|
|
129
|
-
const runtimeStatus = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(provider);
|
|
132
|
+
const runtimeStatus = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(provider, state, args.runtimeDir);
|
|
130
133
|
const expectedBaseUrl = (0, providers_1.buildCopilotBridgeBaseUrl)(provider.runtime);
|
|
131
134
|
if (args.providerName && state?.provider && state.provider !== args.providerName) {
|
|
132
135
|
throw (0, errors_1.cliError)("BRIDGE_PROVIDER_MISMATCH", `Bridge runtime state belongs to "${state.provider}" not "${args.providerName}".`, {
|
|
@@ -154,7 +157,7 @@ async function resolveBridgeTarget(args) {
|
|
|
154
157
|
return resolveNamedBridgeProvider(args.providers, args.requestedProviderName);
|
|
155
158
|
}
|
|
156
159
|
if (args.preferRuntimeState) {
|
|
157
|
-
const runtimeState = (0, runtime_state_repo_1.readCopilotBridgeState)();
|
|
160
|
+
const runtimeState = (0, runtime_state_repo_1.readCopilotBridgeState)(args.runtimeDir);
|
|
158
161
|
if (runtimeState?.provider && args.providers.providers[runtimeState.provider]) {
|
|
159
162
|
return resolveNamedBridgeProvider(args.providers, runtimeState.provider);
|
|
160
163
|
}
|
|
@@ -238,15 +241,15 @@ async function promptForCopilotBridgeSelection(runtime, targets, commandName) {
|
|
|
238
241
|
/**
|
|
239
242
|
* Verifies that the local Copilot bridge prerequisites are available before startup.
|
|
240
243
|
*/
|
|
241
|
-
async function requireBridgeRuntimeReadiness() {
|
|
242
|
-
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)();
|
|
244
|
+
async function requireBridgeRuntimeReadiness(runtimesDir) {
|
|
245
|
+
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)(runtimesDir);
|
|
243
246
|
if (!installStatus.installed) {
|
|
244
247
|
throw (0, errors_1.cliError)("COPILOT_SDK_MISSING", "The optional Copilot SDK runtime is not installed.", {
|
|
245
248
|
installDir: installStatus.installDir,
|
|
246
249
|
packageName: installStatus.packageName,
|
|
247
250
|
});
|
|
248
251
|
}
|
|
249
|
-
await (0, copilot_adapter_1.readCopilotAuthState)();
|
|
252
|
+
await (0, copilot_adapter_1.readCopilotAuthState)(runtimesDir);
|
|
250
253
|
}
|
|
251
254
|
/**
|
|
252
255
|
* Rewrites one Copilot bridge provider record with a recovered runtime port.
|
|
@@ -281,9 +284,7 @@ function persistRecoveredBridgePort(args) {
|
|
|
281
284
|
const document = (0, config_repo_1.readStructuredConfig)(args.configPath);
|
|
282
285
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
283
286
|
upsertModelProviders: {
|
|
284
|
-
[args.provider.profile]:
|
|
285
|
-
baseUrl: (0, providers_1.buildCopilotBridgeBaseUrl)(args.provider.runtime),
|
|
286
|
-
},
|
|
287
|
+
[args.provider.profile]: (0, providers_1.buildCopilotModelProviderProjection)(args.provider.runtime),
|
|
287
288
|
},
|
|
288
289
|
});
|
|
289
290
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
@@ -109,7 +109,7 @@ function editProvider(args) {
|
|
|
109
109
|
switchToProfile: args.switchToProfile ?? null,
|
|
110
110
|
});
|
|
111
111
|
return (0, run_mutation_1.runMutation)({
|
|
112
|
-
|
|
112
|
+
lockPath: args.lockPath,
|
|
113
113
|
backupsDir: args.backupsDir,
|
|
114
114
|
latestBackupPath: args.latestBackupPath,
|
|
115
115
|
operation: "edit",
|
package/dist/app/get-status.js
CHANGED
|
@@ -48,7 +48,7 @@ const runtime_state_repo_1 = require("../storage/runtime-state-repo");
|
|
|
48
48
|
/**
|
|
49
49
|
* Reports the current on-disk runtime state and how it maps back to managed providers.
|
|
50
50
|
*/
|
|
51
|
-
async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
51
|
+
async function getStatus(codexDir, configPath, providersPath, authPath, options) {
|
|
52
52
|
const configExists = fs.existsSync(configPath);
|
|
53
53
|
const providersExists = fs.existsSync(providersPath);
|
|
54
54
|
let currentProfile = null;
|
|
@@ -67,10 +67,12 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
const liveState = (0, runtime_state_1.inspectLiveStateDrift)(currentProfile, providers);
|
|
70
|
-
const activeProviderCandidates =
|
|
71
|
-
const activeProvider =
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
const activeProviderCandidates = liveState.mappedProviders;
|
|
71
|
+
const activeProvider = liveState.providerResolvable && providers && liveState.mappedProvider
|
|
72
|
+
? providers.providers[liveState.mappedProvider]
|
|
73
|
+
: null;
|
|
74
|
+
const copilotInstall = (0, copilot_installer_1.probeCopilotSdkInstall)(options?.runtimesDir);
|
|
75
|
+
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)(options?.runtimeDir);
|
|
74
76
|
const runtimeState = runtimeStateInspection.state;
|
|
75
77
|
const runtimeStateProvider = runtimeState && providers ? providers.providers[runtimeState.provider] ?? null : null;
|
|
76
78
|
const bridgeProbeTarget = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
|
|
@@ -86,7 +88,7 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
86
88
|
cause: runtimeStateInspection.parseError ?? "Failed to parse Copilot bridge runtime state.",
|
|
87
89
|
}
|
|
88
90
|
: bridgeProbeTarget
|
|
89
|
-
? await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(bridgeProbeTarget, runtimeState)
|
|
91
|
+
? await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(bridgeProbeTarget, runtimeState, options?.runtimeDir)
|
|
90
92
|
: runtimeState
|
|
91
93
|
? {
|
|
92
94
|
ok: false,
|
|
@@ -97,7 +99,7 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
97
99
|
}
|
|
98
100
|
: null;
|
|
99
101
|
const copilotAuth = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
|
|
100
|
-
? await (0, copilot_adapter_1.readCopilotAuthState)().catch((error) => ({
|
|
102
|
+
? await (0, copilot_adapter_1.readCopilotAuthState)(options?.runtimesDir).catch((error) => ({
|
|
101
103
|
ready: false,
|
|
102
104
|
source: "official-sdk",
|
|
103
105
|
mode: "session",
|
|
@@ -108,6 +110,9 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
108
110
|
// Surface unmanaged live state without mutating anything during a read-only status call.
|
|
109
111
|
warnings.push("Current config profile is not mapped in providers.json. Backfill would be required before treating live state as managed.");
|
|
110
112
|
}
|
|
113
|
+
if (liveState.reason === "shared-profile") {
|
|
114
|
+
warnings.push(`Current config profile "${currentProfile}" is shared by multiple providers in providers.json, so the active provider cannot be resolved uniquely.`);
|
|
115
|
+
}
|
|
111
116
|
if (runtimeStateInspection.exists && !runtimeStateInspection.valid) {
|
|
112
117
|
warnings.push(`Copilot bridge runtime state is unreadable: ${runtimeStateInspection.parseError ?? "unknown parse failure"}`);
|
|
113
118
|
}
|
|
@@ -115,13 +120,20 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
115
120
|
warnings,
|
|
116
121
|
data: {
|
|
117
122
|
codexDir,
|
|
118
|
-
storage: (0, runtime_state_1.getStorageRoles)(
|
|
123
|
+
storage: (0, runtime_state_1.getStorageRoles)({
|
|
124
|
+
codexDir,
|
|
125
|
+
providersPath,
|
|
126
|
+
configPath,
|
|
127
|
+
authPath,
|
|
128
|
+
runtimeDir: options?.runtimeDir,
|
|
129
|
+
runtimesDir: options?.runtimesDir,
|
|
130
|
+
}),
|
|
119
131
|
configExists,
|
|
120
132
|
providersExists,
|
|
121
133
|
currentProfile,
|
|
122
134
|
currentProfileMapped: liveState.profileMapped,
|
|
123
135
|
provider: liveState.mappedProvider,
|
|
124
|
-
activeProviderResolvable:
|
|
136
|
+
activeProviderResolvable: liveState.providerResolvable,
|
|
125
137
|
activeProviderCandidates,
|
|
126
138
|
runtimeProvider: activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider) ? activeProvider.runtime?.kind ?? null : null,
|
|
127
139
|
copilotSdk: {
|
|
@@ -62,7 +62,7 @@ function importProviders(args) {
|
|
|
62
62
|
(0, fs_utils_1.ensureDir)(args.codexDir);
|
|
63
63
|
const document = (0, config_repo_1.readStructuredConfig)(args.configPath);
|
|
64
64
|
return (0, run_mutation_1.runMutation)({
|
|
65
|
-
|
|
65
|
+
lockPath: args.lockPath,
|
|
66
66
|
backupsDir: args.backupsDir,
|
|
67
67
|
latestBackupPath: args.latestBackupPath,
|
|
68
68
|
operation: "import",
|
package/dist/app/init-codex.js
CHANGED
|
@@ -35,34 +35,33 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.initCodex = initCodex;
|
|
37
37
|
const fs = __importStar(require("node:fs"));
|
|
38
|
-
const errors_1 = require("../domain/errors");
|
|
39
38
|
const fs_utils_1 = require("../storage/fs-utils");
|
|
40
39
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
40
|
+
const tool_config_repo_1 = require("../storage/tool-config-repo");
|
|
41
41
|
/**
|
|
42
|
-
* Initializes
|
|
42
|
+
* Initializes the codex-switch tool home without requiring target Codex runtime files.
|
|
43
43
|
*/
|
|
44
44
|
function initCodex(args) {
|
|
45
|
-
const
|
|
46
|
-
if (!
|
|
47
|
-
|
|
48
|
-
codexDir: args.codexDir,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
if (!codexDirExists) {
|
|
52
|
-
(0, fs_utils_1.ensureDir)(args.codexDir);
|
|
45
|
+
const toolHomeExists = fs.existsSync(args.toolHomeDir);
|
|
46
|
+
if (!toolHomeExists) {
|
|
47
|
+
(0, fs_utils_1.ensureDir)(args.toolHomeDir);
|
|
53
48
|
}
|
|
49
|
+
const toolConfigExists = fs.existsSync(args.toolConfigPath);
|
|
50
|
+
const ensuredConfig = (0, tool_config_repo_1.ensureToolConfig)(args.toolConfigPath, args.version, args.defaultCodexDir ?? "");
|
|
54
51
|
const providersExists = fs.existsSync(args.providersPath);
|
|
55
52
|
if (!providersExists) {
|
|
56
53
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, { providers: {} });
|
|
57
54
|
}
|
|
58
55
|
return {
|
|
59
56
|
data: {
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
toolHomeDir: args.toolHomeDir,
|
|
58
|
+
toolConfigPath: args.toolConfigPath,
|
|
59
|
+
providersPath: args.providersPath,
|
|
60
|
+
createdToolHomeDir: !toolHomeExists,
|
|
61
|
+
createdToolConfigFile: ensuredConfig.created && !toolConfigExists,
|
|
62
62
|
createdProvidersFile: !providersExists,
|
|
63
|
+
toolConfigAlreadyExisted: toolConfigExists,
|
|
63
64
|
providersAlreadyExisted: providersExists,
|
|
64
|
-
configExists: fs.existsSync(args.configPath),
|
|
65
|
-
authExists: fs.existsSync(args.authPath),
|
|
66
65
|
},
|
|
67
66
|
};
|
|
68
67
|
}
|