@minniexcode/codex-switch 0.2.0 → 0.2.2
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 +66 -94
- package/README.CN.md +84 -139
- package/README.md +91 -151
- package/dist/app/add-provider.js +6 -83
- package/dist/app/edit-provider.js +9 -29
- package/dist/app/get-status.js +1 -77
- package/dist/app/list-providers.js +0 -2
- package/dist/app/remove-provider.js +3 -5
- package/dist/app/run-doctor.js +2 -99
- package/dist/app/setup-codex.js +0 -2
- package/dist/app/switch-provider.js +1 -74
- package/dist/cli/output.js +3 -89
- package/dist/commands/handlers.js +20 -172
- package/dist/commands/help.js +1 -4
- package/dist/commands/registry.js +6 -74
- package/dist/domain/config.js +1 -3
- package/dist/domain/providers.js +4 -92
- package/dist/domain/runtime-state.js +0 -88
- package/dist/interaction/add-interactive.js +1 -55
- package/dist/interaction/interactive.js +1 -3
- package/dist/runtime/codex-probe.js +0 -12
- package/dist/storage/codex-paths.js +0 -2
- package/docs/Design/codex-switch-v0.2.1-design.md +77 -0
- package/docs/PRD/codex-switch-prd-v0.2.1.md +82 -0
- package/docs/Tests/testing.md +32 -34
- package/docs/cli-usage.md +67 -235
- package/docs/codex-switch-command-design.md +1 -1
- package/docs/codex-switch-product-overview.md +49 -96
- package/docs/codex-switch-technical-architecture.md +37 -52
- package/package.json +1 -1
- package/dist/app/bridge.js +0 -303
- package/dist/runtime/copilot-adapter.js +0 -617
- package/dist/runtime/copilot-bridge-worker.js +0 -69
- package/dist/runtime/copilot-bridge.js +0 -1351
- package/dist/runtime/copilot-cli.js +0 -164
- package/dist/runtime/copilot-http-bridge-worker.js +0 -228
- package/dist/runtime/copilot-installer.js +0 -231
- package/dist/runtime/copilot-sdk-loader.js +0 -62
- package/dist/runtime/copilot-token.js +0 -294
- package/dist/storage/runtime-state-repo.js +0 -121
|
@@ -47,11 +47,9 @@ function removeProvider(args) {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
const switchTargetProjection = switchTarget
|
|
50
|
-
?
|
|
51
|
-
? (0, providers_1.
|
|
52
|
-
:
|
|
53
|
-
? (0, providers_1.buildDirectModelProviderProjection)(switchTarget.profile, switchTarget.baseUrl)
|
|
54
|
-
: null
|
|
50
|
+
? switchTarget.baseUrl
|
|
51
|
+
? (0, providers_1.buildModelProviderProjection)(switchTarget.profile, switchTarget.baseUrl)
|
|
52
|
+
: null
|
|
55
53
|
: null;
|
|
56
54
|
if (switchTargetName && !switchTargetProjection) {
|
|
57
55
|
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Provider "${switchTargetName}" requires base_url before it can become active.`, {
|
package/dist/app/run-doctor.js
CHANGED
|
@@ -42,10 +42,6 @@ const providers_repo_1 = require("../storage/providers-repo");
|
|
|
42
42
|
const errors_1 = require("../domain/errors");
|
|
43
43
|
const codex_probe_1 = require("../runtime/codex-probe");
|
|
44
44
|
const auth_repo_1 = require("../storage/auth-repo");
|
|
45
|
-
const providers_1 = require("../domain/providers");
|
|
46
|
-
const copilot_token_1 = require("../runtime/copilot-token");
|
|
47
|
-
const copilot_bridge_1 = require("../runtime/copilot-bridge");
|
|
48
|
-
const runtime_state_repo_1 = require("../storage/runtime-state-repo");
|
|
49
45
|
const codex_version_1 = require("../runtime/codex-version");
|
|
50
46
|
/**
|
|
51
47
|
* Performs consistency checks across config.toml, providers.json, and the local Codex CLI.
|
|
@@ -84,7 +80,6 @@ async function runDoctor(args) {
|
|
|
84
80
|
try {
|
|
85
81
|
providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
|
|
86
82
|
if (document) {
|
|
87
|
-
// Preserve domain issue codes while translating them into user-facing diagnostic messages.
|
|
88
83
|
for (const issue of (0, config_1.collectConfigConsistencyIssues)(document, providers)) {
|
|
89
84
|
issues.push({
|
|
90
85
|
...issue,
|
|
@@ -103,8 +98,6 @@ async function runDoctor(args) {
|
|
|
103
98
|
}
|
|
104
99
|
}
|
|
105
100
|
const authState = (0, auth_repo_1.readAuthFileState)(args.authPath);
|
|
106
|
-
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)(args.runtimeDir);
|
|
107
|
-
const runtimeState = runtimeStateInspection.state;
|
|
108
101
|
if (authState.exists && !authState.valid) {
|
|
109
102
|
issues.push({
|
|
110
103
|
code: "AUTH_JSON_INVALID",
|
|
@@ -112,70 +105,6 @@ async function runDoctor(args) {
|
|
|
112
105
|
file: args.authPath,
|
|
113
106
|
});
|
|
114
107
|
}
|
|
115
|
-
if (runtimeStateInspection.exists && !runtimeStateInspection.valid) {
|
|
116
|
-
issues.push({
|
|
117
|
-
code: "BRIDGE_STATE_STALE",
|
|
118
|
-
message: `Copilot bridge runtime state is unreadable: ${runtimeStateInspection.parseError ?? "unknown parse failure"}`,
|
|
119
|
-
logPath: runtimeState?.logPath ?? null,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
if (document?.currentModelProvider && providers) {
|
|
123
|
-
const matches = (0, providers_1.findProvidersByProfile)(providers, document.currentModelProvider);
|
|
124
|
-
if (matches.length === 1) {
|
|
125
|
-
const activeProvider = providers.providers[matches[0]];
|
|
126
|
-
if ((0, providers_1.isCopilotBridgeProvider)(activeProvider)) {
|
|
127
|
-
const githubToken = (0, copilot_token_1.readGithubToken)(args.toolHomeDir);
|
|
128
|
-
if (!githubToken) {
|
|
129
|
-
issues.push({
|
|
130
|
-
code: "COPILOT_AUTH_REQUIRED",
|
|
131
|
-
message: "GitHub Copilot authentication is required. Run `codexs login copilot`.",
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
try {
|
|
136
|
-
await (0, copilot_token_1.exchangeForCopilotToken)(githubToken);
|
|
137
|
-
}
|
|
138
|
-
catch (error) {
|
|
139
|
-
const normalized = (0, errors_1.normalizeError)(error);
|
|
140
|
-
issues.push({
|
|
141
|
-
code: normalized.code,
|
|
142
|
-
message: normalized.message,
|
|
143
|
-
...(normalized.details ?? {}),
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const bridge = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider, runtimeState, args.runtimeDir);
|
|
148
|
-
if (!bridge.ok) {
|
|
149
|
-
issues.push({
|
|
150
|
-
code: mapBridgeDiagnosticCode(bridge.cause),
|
|
151
|
-
message: bridge.cause,
|
|
152
|
-
...(bridge.details ?? {}),
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (runtimeState && providers) {
|
|
159
|
-
const runtimeProvider = providers.providers[runtimeState.provider] ?? null;
|
|
160
|
-
if (!runtimeProvider || !(0, providers_1.isCopilotBridgeProvider)(runtimeProvider)) {
|
|
161
|
-
issues.push({
|
|
162
|
-
code: "BRIDGE_STATE_STALE",
|
|
163
|
-
message: "Copilot bridge runtime state exists but no matching managed Copilot provider is available.",
|
|
164
|
-
...runtimeState,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
else if (!document?.currentModelProvider || runtimeProvider.profile !== document.currentModelProvider) {
|
|
168
|
-
issues.push({
|
|
169
|
-
code: "BRIDGE_STATE_STALE",
|
|
170
|
-
message: "Copilot bridge runtime state exists for a provider that is not the current active model_provider.",
|
|
171
|
-
activeModelProvider: document?.currentModelProvider ?? null,
|
|
172
|
-
runtimeProvider: runtimeState.provider,
|
|
173
|
-
runtimeProfile: runtimeProvider.profile,
|
|
174
|
-
...runtimeState,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
// Drift inspection still runs when files are missing so status output can explain partial state.
|
|
179
108
|
const drift = (0, runtime_state_1.inspectLiveStateDrift)(currentModelProvider, providers);
|
|
180
109
|
const codexCheck = (0, codex_probe_1.probeCodexRuntime)(codex_version_1.MIN_SUPPORTED_CODEX_VERSION);
|
|
181
110
|
if (!codexCheck.ok) {
|
|
@@ -199,36 +128,12 @@ async function runDoctor(args) {
|
|
|
199
128
|
healthy: issues.length === 0,
|
|
200
129
|
issues,
|
|
201
130
|
codexDir: args.codexDir,
|
|
202
|
-
storage: (0, runtime_state_1.getStorageRoles)({
|
|
203
|
-
codexDir: args.codexDir,
|
|
204
|
-
providersPath: args.providersPath,
|
|
205
|
-
configPath: args.configPath,
|
|
206
|
-
authPath: args.authPath,
|
|
207
|
-
runtimeDir: args.runtimeDir,
|
|
208
|
-
runtimesDir: args.runtimesDir,
|
|
209
|
-
}),
|
|
210
131
|
liveState: drift,
|
|
211
132
|
auth: authState,
|
|
212
|
-
copilotRuntimeState: runtimeState,
|
|
213
133
|
},
|
|
214
134
|
warnings: issues.length === 0 ? [] : [`doctor found ${issues.length} issue(s)`],
|
|
215
135
|
};
|
|
216
136
|
}
|
|
217
|
-
function mapBridgeDiagnosticCode(cause) {
|
|
218
|
-
if (cause === "Copilot bridge state manifest is missing.") {
|
|
219
|
-
return "BRIDGE_STATE_MISSING";
|
|
220
|
-
}
|
|
221
|
-
if (cause === "Copilot bridge runtime state exists but no active Copilot bridge provider is selected.") {
|
|
222
|
-
return "BRIDGE_STATE_STALE";
|
|
223
|
-
}
|
|
224
|
-
if (cause === "Copilot bridge state base URL does not match the provider runtime configuration.") {
|
|
225
|
-
return "PROVIDER_BASE_URL_MISMATCH";
|
|
226
|
-
}
|
|
227
|
-
return "BRIDGE_HEALTHCHECK_FAILED";
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Maps structured config consistency issues onto stable human-readable diagnostic text.
|
|
231
|
-
*/
|
|
232
137
|
function renderConfigIssueMessage(issue) {
|
|
233
138
|
switch (issue.code) {
|
|
234
139
|
case "MODEL_MISSING":
|
|
@@ -246,11 +151,9 @@ function renderConfigIssueMessage(issue) {
|
|
|
246
151
|
case "LEGACY_MODEL_PROVIDER_ENV_KEY":
|
|
247
152
|
return `Model provider "${issue.modelProvider}" still contains legacy env_key wiring.`;
|
|
248
153
|
case "PROVIDER_BASE_URL_MISMATCH":
|
|
249
|
-
return issue.
|
|
250
|
-
? `Direct provider "${issue.provider}" baseUrl does not match config.toml model provider "${issue.modelProvider}" base_url.`
|
|
251
|
-
: String(issue.code ?? "UNKNOWN_ISSUE");
|
|
154
|
+
return `Provider "${issue.provider}" baseUrl does not match config.toml model provider "${issue.modelProvider}" base_url.`;
|
|
252
155
|
case "AUTH_JSON_INVALID":
|
|
253
|
-
return String(issue.message ??
|
|
156
|
+
return String(issue.message ?? "auth.json is invalid.");
|
|
254
157
|
case "DESTRUCTIVE_REMOVE_BLOCKED":
|
|
255
158
|
return `Provider "${issue.provider}" cannot be removed while "${issue.activeModelProvider}" remains active.`;
|
|
256
159
|
default:
|
package/dist/app/setup-codex.js
CHANGED
|
@@ -5,8 +5,6 @@ const errors_1 = require("../domain/errors");
|
|
|
5
5
|
const config_repo_1 = require("../storage/config-repo");
|
|
6
6
|
const auth_repo_1 = require("../storage/auth-repo");
|
|
7
7
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
8
|
-
const copilot_bridge_1 = require("../runtime/copilot-bridge");
|
|
9
|
-
const copilot_token_1 = require("../runtime/copilot-token");
|
|
10
8
|
const run_mutation_1 = require("./run-mutation");
|
|
11
9
|
const providers_1 = require("../domain/providers");
|
|
12
10
|
/**
|
|
@@ -31,77 +29,6 @@ async function switchProvider(args) {
|
|
|
31
29
|
suggestion: "Run `codexs edit <provider> --model <name>` or `codexs add <provider> --model <name>`.",
|
|
32
30
|
});
|
|
33
31
|
}
|
|
34
|
-
if ((0, providers_1.isCopilotBridgeProvider)(provider)) {
|
|
35
|
-
const githubToken = (0, copilot_token_1.readGithubToken)(args.toolHomeDir);
|
|
36
|
-
if (!githubToken) {
|
|
37
|
-
throw (0, errors_1.cliError)("COPILOT_AUTH_REQUIRED", "GitHub Copilot authentication is required. Run `codexs login copilot` first.");
|
|
38
|
-
}
|
|
39
|
-
await (0, copilot_token_1.exchangeForCopilotToken)(githubToken);
|
|
40
|
-
const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(args.providerName, provider, args.runtimeDir, args.runtimesDir, args.toolHomeDir);
|
|
41
|
-
const nextProvider = bridge.portChanged
|
|
42
|
-
? (0, providers_1.cleanProviderRecord)({
|
|
43
|
-
...provider,
|
|
44
|
-
baseUrl: bridge.baseUrl,
|
|
45
|
-
runtime: {
|
|
46
|
-
...provider.runtime,
|
|
47
|
-
bridgePort: bridge.port,
|
|
48
|
-
},
|
|
49
|
-
})
|
|
50
|
-
: provider;
|
|
51
|
-
try {
|
|
52
|
-
return (0, run_mutation_1.runMutation)({
|
|
53
|
-
lockPath: args.lockPath,
|
|
54
|
-
backupsDir: args.backupsDir,
|
|
55
|
-
latestBackupPath: args.latestBackupPath,
|
|
56
|
-
operation: "switch",
|
|
57
|
-
files: [
|
|
58
|
-
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
59
|
-
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
60
|
-
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
61
|
-
],
|
|
62
|
-
mutate: () => {
|
|
63
|
-
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
64
|
-
setCurrentModel: resolvedModel,
|
|
65
|
-
setCurrentModelProvider: provider.profile,
|
|
66
|
-
upsertModelProviders: {
|
|
67
|
-
[provider.profile]: (0, providers_1.buildCopilotModelProviderProjection)(nextProvider.runtime),
|
|
68
|
-
},
|
|
69
|
-
deleteLegacyProfile: true,
|
|
70
|
-
deleteLegacyProfilesByName: [provider.profile],
|
|
71
|
-
scrubModelProviderEnvKeys: [provider.profile],
|
|
72
|
-
});
|
|
73
|
-
if (bridge.portChanged) {
|
|
74
|
-
(0, providers_repo_1.writeProvidersFile)(args.providersPath, {
|
|
75
|
-
providers: {
|
|
76
|
-
...providers.providers,
|
|
77
|
-
[args.providerName]: nextProvider,
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
82
|
-
(0, auth_repo_1.writeOpenAiApiKeyAuth)(args.authPath, provider.apiKey);
|
|
83
|
-
return {
|
|
84
|
-
provider: args.providerName,
|
|
85
|
-
model: resolvedModel,
|
|
86
|
-
modelProvider: nextProvider.profile,
|
|
87
|
-
profile: nextProvider.profile,
|
|
88
|
-
portChanged: bridge.portChanged,
|
|
89
|
-
bridgePort: bridge.port,
|
|
90
|
-
bridgeReused: bridge.reused,
|
|
91
|
-
bridgeReplaced: bridge.replaced,
|
|
92
|
-
bridgeRestartReason: bridge.restartReason ?? null,
|
|
93
|
-
bridgeLogPath: bridge.logPath,
|
|
94
|
-
};
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
if (!bridge.reused) {
|
|
100
|
-
(0, copilot_bridge_1.stopCopilotBridge)(args.runtimeDir);
|
|
101
|
-
}
|
|
102
|
-
throw error;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
32
|
return (0, run_mutation_1.runMutation)({
|
|
106
33
|
lockPath: args.lockPath,
|
|
107
34
|
backupsDir: args.backupsDir,
|
|
@@ -125,7 +52,7 @@ async function switchProvider(args) {
|
|
|
125
52
|
setCurrentModel: resolvedModel,
|
|
126
53
|
setCurrentModelProvider: provider.profile,
|
|
127
54
|
upsertModelProviders: {
|
|
128
|
-
[provider.profile]: (0, providers_1.
|
|
55
|
+
[provider.profile]: (0, providers_1.buildModelProviderProjection)(provider.profile, resolvedBaseUrl),
|
|
129
56
|
},
|
|
130
57
|
deleteLegacyProfile: true,
|
|
131
58
|
deleteLegacyProfilesByName: [provider.profile],
|
package/dist/cli/output.js
CHANGED
|
@@ -107,7 +107,7 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
107
107
|
: "";
|
|
108
108
|
const note = provider.note ? ` note=${provider.note}` : "";
|
|
109
109
|
const current = provider.isActive ? " current" : "";
|
|
110
|
-
lines.push(`${provider.name}
|
|
110
|
+
lines.push(`${provider.name}${current} -> ${provider.modelProvider}${provider.model ? ` model=${provider.model}` : ""}${tags}${note}`);
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
break;
|
|
@@ -144,12 +144,6 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
144
144
|
lines.push(` mapped provider: ${renderStatusMappedProvider(data)}`);
|
|
145
145
|
lines.push(` provider path: ${renderStatusProviderPath(data)}`);
|
|
146
146
|
lines.push(` runtime health: ${renderStatusHealth(data)}`);
|
|
147
|
-
if (data?.copilotBridgeLogPath) {
|
|
148
|
-
lines.push(` bridge log: ${String(data.copilotBridgeLogPath)}`);
|
|
149
|
-
}
|
|
150
|
-
if (data?.copilotBridgeRestartReason) {
|
|
151
|
-
lines.push(` bridge restart reason: ${String(data.copilotBridgeRestartReason)}`);
|
|
152
|
-
}
|
|
153
147
|
lines.push(` warnings: ${warnings.length}`);
|
|
154
148
|
lines.push(` next step: ${renderStatusNextStep(data, warnings)}`);
|
|
155
149
|
break;
|
|
@@ -173,15 +167,6 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
173
167
|
case "switch":
|
|
174
168
|
lines.push(`Switched to provider ${String(data?.provider ?? "")} using model provider ${String(data?.modelProvider ?? data?.profile ?? "")}.`);
|
|
175
169
|
lines.push(`Model: ${String(data?.model ?? "")}`);
|
|
176
|
-
if (data?.bridgeReplaced) {
|
|
177
|
-
lines.push(`Bridge replaced: true`);
|
|
178
|
-
}
|
|
179
|
-
if (data?.bridgeRestartReason) {
|
|
180
|
-
lines.push(`Bridge restart reason: ${String(data?.bridgeRestartReason)}`);
|
|
181
|
-
}
|
|
182
|
-
if (data?.bridgeLogPath) {
|
|
183
|
-
lines.push(`Bridge log: ${String(data?.bridgeLogPath)}`);
|
|
184
|
-
}
|
|
185
170
|
lines.push(`Backup: ${String(data?.backupPath ?? "")}`);
|
|
186
171
|
break;
|
|
187
172
|
case "import":
|
|
@@ -198,19 +183,7 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
198
183
|
lines.push(`tool home created: ${String(data?.createdToolHomeDir ?? false)}`);
|
|
199
184
|
lines.push(`tool config created: ${String(data?.createdToolConfigFile ?? false)}`);
|
|
200
185
|
lines.push(`providers registry created: ${String(data?.createdProvidersFile ?? false)}`);
|
|
201
|
-
lines.push("next step: run `codexs add
|
|
202
|
-
break;
|
|
203
|
-
case "login":
|
|
204
|
-
lines.push(`Copilot login ready: ${String(data?.authReady ?? false)}`);
|
|
205
|
-
lines.push(`upstream: ${String(data?.upstream ?? "")}`);
|
|
206
|
-
lines.push(`sdk installed: ${String(data?.sdkInstalled ?? false)}${data?.sdkInstalledNow ? " (installed now)" : ""}`);
|
|
207
|
-
lines.push(`copilot cli source: ${String(data?.cliSource ?? "not-needed")}`);
|
|
208
|
-
if (data?.cliCommand) {
|
|
209
|
-
lines.push(`copilot cli command: ${String(data?.cliCommand)}`);
|
|
210
|
-
}
|
|
211
|
-
lines.push(`login launched: ${String(data?.loginLaunched ?? false)}`);
|
|
212
|
-
lines.push(`auth ready: ${String(data?.authReady ?? false)}`);
|
|
213
|
-
lines.push("next step: run `codexs add <provider> --copilot --profile <model-provider-id>` and then `codexs switch <provider>`.");
|
|
186
|
+
lines.push("next step: run `codexs add <provider> --profile <model-provider-id> --model <model> --api-key <key> --base-url <url>`.");
|
|
214
187
|
break;
|
|
215
188
|
case "migrate":
|
|
216
189
|
lines.push(`Migrated providers in ${String(data?.codexDir ?? "")} using ${String(data?.strategy ?? "")}.`);
|
|
@@ -242,49 +215,12 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
242
215
|
const issues = data?.issues ?? [];
|
|
243
216
|
lines.push(healthy ? "Doctor summary: healthy. No action required." : `Doctor summary: ${issues.length} issue(s) need attention.`);
|
|
244
217
|
lines.push(`target runtime: ${String(data?.codexDir ?? "")}`);
|
|
245
|
-
if (data?.copilotRuntimeState && data.copilotRuntimeState.logPath) {
|
|
246
|
-
lines.push(`bridge log: ${String(data.copilotRuntimeState.logPath)}`);
|
|
247
|
-
}
|
|
248
218
|
for (const issue of issues) {
|
|
249
219
|
lines.push(`- ${String(issue.code)}: ${String(issue.message)}`);
|
|
250
220
|
lines.push(` next step: ${renderDoctorIssueNextStep(issue)}`);
|
|
251
221
|
}
|
|
252
222
|
break;
|
|
253
223
|
}
|
|
254
|
-
case "bridge-start":
|
|
255
|
-
lines.push(`Bridge ready for provider ${String(data?.provider ?? "")}.`);
|
|
256
|
-
lines.push(`Endpoint: ${String(data?.baseUrl ?? "")}`);
|
|
257
|
-
lines.push(`Reused: ${String(data?.reused ?? false)}`);
|
|
258
|
-
lines.push(`Replaced existing: ${String(data?.replaced ?? false)}`);
|
|
259
|
-
if (data?.restartReason) {
|
|
260
|
-
lines.push(`Restart reason: ${String(data?.restartReason)}`);
|
|
261
|
-
}
|
|
262
|
-
if (data?.logPath) {
|
|
263
|
-
lines.push(`Bridge log: ${String(data?.logPath)}`);
|
|
264
|
-
}
|
|
265
|
-
break;
|
|
266
|
-
case "bridge-status":
|
|
267
|
-
lines.push(`Bridge provider: ${String(data?.provider ?? "")}`);
|
|
268
|
-
lines.push(`Active: ${String(data?.active ?? false)}`);
|
|
269
|
-
lines.push(`Expected base URL: ${String(data?.expectedBaseUrl ?? "")}`);
|
|
270
|
-
lines.push(`Matches runtime state: ${String(data?.matches ?? false)}`);
|
|
271
|
-
if (data?.lastRestartReason) {
|
|
272
|
-
lines.push(`Last restart reason: ${String(data?.lastRestartReason)}`);
|
|
273
|
-
}
|
|
274
|
-
if (data?.logPath) {
|
|
275
|
-
lines.push(`Bridge log: ${String(data?.logPath)}`);
|
|
276
|
-
}
|
|
277
|
-
break;
|
|
278
|
-
case "bridge-stop":
|
|
279
|
-
lines.push(`Bridge stopped for provider ${String(data?.provider ?? "(none)")}.`);
|
|
280
|
-
lines.push(`Had runtime state: ${String(data?.hadRuntimeState ?? false)}`);
|
|
281
|
-
if (data?.lastRestartReason) {
|
|
282
|
-
lines.push(`Last restart reason: ${String(data?.lastRestartReason)}`);
|
|
283
|
-
}
|
|
284
|
-
if (data?.logPath) {
|
|
285
|
-
lines.push(`Bridge log: ${String(data?.logPath)}`);
|
|
286
|
-
}
|
|
287
|
-
break;
|
|
288
224
|
case "backups-list": {
|
|
289
225
|
const backups = data?.backups ?? [];
|
|
290
226
|
for (const backup of backups) {
|
|
@@ -312,14 +248,9 @@ function renderStatusHealth(data) {
|
|
|
312
248
|
const configExists = Boolean(data?.configExists);
|
|
313
249
|
const providersExists = Boolean(data?.providersExists);
|
|
314
250
|
const auth = data?.auth ?? {};
|
|
315
|
-
const bridge = data?.copilotBridge ?? null;
|
|
316
251
|
const issues = Array.isArray(data?.issues) ? data?.issues : [];
|
|
317
252
|
const activeProviderResolvable = data?.activeProviderResolvable !== false;
|
|
318
253
|
const liveState = data?.liveState ?? {};
|
|
319
|
-
const copilotSdk = data?.copilotSdk ?? {};
|
|
320
|
-
const copilotAuth = data?.copilotAuth ?? null;
|
|
321
|
-
const runtimeProvider = typeof data?.runtimeProvider === "string" ? data.runtimeProvider : null;
|
|
322
|
-
const activePathUsesCopilot = runtimeProvider === "copilot-sdk-bridge";
|
|
323
254
|
if (!configExists || !providersExists) {
|
|
324
255
|
return "incomplete local state";
|
|
325
256
|
}
|
|
@@ -329,15 +260,6 @@ function renderStatusHealth(data) {
|
|
|
329
260
|
if (issues.some((issue) => issue.code === "PROVIDER_BASE_URL_MISMATCH")) {
|
|
330
261
|
return "provider projection drift";
|
|
331
262
|
}
|
|
332
|
-
if (activePathUsesCopilot && copilotSdk.installed === false) {
|
|
333
|
-
return "copilot sdk missing";
|
|
334
|
-
}
|
|
335
|
-
if (activePathUsesCopilot && copilotAuth && copilotAuth.ready === false) {
|
|
336
|
-
return "copilot auth required";
|
|
337
|
-
}
|
|
338
|
-
if (activePathUsesCopilot && bridge && bridge.ok === false) {
|
|
339
|
-
return "copilot runtime needs repair";
|
|
340
|
-
}
|
|
341
263
|
if (auth.exists === false) {
|
|
342
264
|
return "auth projection missing";
|
|
343
265
|
}
|
|
@@ -363,7 +285,7 @@ function renderStatusMappedProvider(data) {
|
|
|
363
285
|
* Renders the active workflow path in status output.
|
|
364
286
|
*/
|
|
365
287
|
function renderStatusProviderPath(data) {
|
|
366
|
-
return
|
|
288
|
+
return data?.provider ? "managed provider" : "unmanaged route";
|
|
367
289
|
}
|
|
368
290
|
/**
|
|
369
291
|
* Suggests the next operator action for the human-readable status output.
|
|
@@ -389,14 +311,6 @@ function renderDoctorIssueNextStep(issue) {
|
|
|
389
311
|
return "restore or create config.toml before switching providers";
|
|
390
312
|
case "PROVIDERS_NOT_FOUND":
|
|
391
313
|
return "run `codexs init` and then add or migrate providers";
|
|
392
|
-
case "COPILOT_SDK_MISSING":
|
|
393
|
-
return "run `codexs login copilot` to install the optional Copilot runtime";
|
|
394
|
-
case "COPILOT_AUTH_REQUIRED":
|
|
395
|
-
return "run `codexs login copilot` to complete upstream authentication";
|
|
396
|
-
case "BRIDGE_STATE_STALE":
|
|
397
|
-
case "BRIDGE_STATE_MISSING":
|
|
398
|
-
case "BRIDGE_HEALTHCHECK_FAILED":
|
|
399
|
-
return "reselect the provider with `codexs switch <provider>` or inspect the bridge log/state";
|
|
400
314
|
case "UNMANAGED_ACTIVE_PROFILE":
|
|
401
315
|
return "switch to a managed provider or adopt the active route with `codexs migrate`";
|
|
402
316
|
case "LEGACY_PROFILE_SELECTOR":
|