@minniexcode/codex-switch 0.1.5 → 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 -89
- package/dist/app/edit-provider.js +9 -29
- package/dist/app/get-status.js +1 -74
- package/dist/app/list-providers.js +0 -2
- package/dist/app/remove-provider.js +3 -5
- package/dist/app/run-doctor.js +2 -100
- package/dist/app/setup-codex.js +0 -2
- package/dist/app/switch-provider.js +1 -79
- package/dist/cli/output.js +3 -89
- package/dist/commands/handlers.js +20 -209
- 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.0-design.md +56 -0
- 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 -308
- package/dist/runtime/copilot-adapter.js +0 -612
- package/dist/runtime/copilot-bridge-worker.js +0 -69
- package/dist/runtime/copilot-bridge.js +0 -1318
- package/dist/runtime/copilot-cli.js +0 -164
- package/dist/runtime/copilot-installer.js +0 -231
- package/dist/runtime/copilot-sdk-loader.js +0 -62
- 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,11 +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_installer_1 = require("../runtime/copilot-installer");
|
|
47
|
-
const copilot_bridge_1 = require("../runtime/copilot-bridge");
|
|
48
|
-
const copilot_adapter_1 = require("../runtime/copilot-adapter");
|
|
49
|
-
const runtime_state_repo_1 = require("../storage/runtime-state-repo");
|
|
50
45
|
const codex_version_1 = require("../runtime/codex-version");
|
|
51
46
|
/**
|
|
52
47
|
* Performs consistency checks across config.toml, providers.json, and the local Codex CLI.
|
|
@@ -85,7 +80,6 @@ async function runDoctor(args) {
|
|
|
85
80
|
try {
|
|
86
81
|
providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
|
|
87
82
|
if (document) {
|
|
88
|
-
// Preserve domain issue codes while translating them into user-facing diagnostic messages.
|
|
89
83
|
for (const issue of (0, config_1.collectConfigConsistencyIssues)(document, providers)) {
|
|
90
84
|
issues.push({
|
|
91
85
|
...issue,
|
|
@@ -104,8 +98,6 @@ async function runDoctor(args) {
|
|
|
104
98
|
}
|
|
105
99
|
}
|
|
106
100
|
const authState = (0, auth_repo_1.readAuthFileState)(args.authPath);
|
|
107
|
-
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)(args.runtimeDir);
|
|
108
|
-
const runtimeState = runtimeStateInspection.state;
|
|
109
101
|
if (authState.exists && !authState.valid) {
|
|
110
102
|
issues.push({
|
|
111
103
|
code: "AUTH_JSON_INVALID",
|
|
@@ -113,70 +105,6 @@ async function runDoctor(args) {
|
|
|
113
105
|
file: args.authPath,
|
|
114
106
|
});
|
|
115
107
|
}
|
|
116
|
-
if (runtimeStateInspection.exists && !runtimeStateInspection.valid) {
|
|
117
|
-
issues.push({
|
|
118
|
-
code: "BRIDGE_STATE_STALE",
|
|
119
|
-
message: `Copilot bridge runtime state is unreadable: ${runtimeStateInspection.parseError ?? "unknown parse failure"}`,
|
|
120
|
-
logPath: runtimeState?.logPath ?? null,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
if (document?.currentModelProvider && providers) {
|
|
124
|
-
const matches = (0, providers_1.findProvidersByProfile)(providers, document.currentModelProvider);
|
|
125
|
-
if (matches.length === 1) {
|
|
126
|
-
const activeProvider = providers.providers[matches[0]];
|
|
127
|
-
if ((0, providers_1.isCopilotBridgeProvider)(activeProvider)) {
|
|
128
|
-
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)(args.runtimesDir);
|
|
129
|
-
if (!installStatus.installed) {
|
|
130
|
-
issues.push({
|
|
131
|
-
code: "COPILOT_SDK_MISSING",
|
|
132
|
-
message: "The optional Copilot SDK runtime is not installed.",
|
|
133
|
-
installDir: installStatus.installDir,
|
|
134
|
-
packageName: installStatus.packageName,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
try {
|
|
138
|
-
await (0, copilot_adapter_1.readCopilotAuthState)(args.runtimesDir);
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
const normalized = (0, errors_1.normalizeError)(error);
|
|
142
|
-
issues.push({
|
|
143
|
-
code: normalized.code,
|
|
144
|
-
message: normalized.message,
|
|
145
|
-
...(normalized.details ?? {}),
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
const bridge = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider, runtimeState, args.runtimeDir);
|
|
149
|
-
if (!bridge.ok) {
|
|
150
|
-
issues.push({
|
|
151
|
-
code: mapBridgeDiagnosticCode(bridge.cause),
|
|
152
|
-
message: bridge.cause,
|
|
153
|
-
...(bridge.details ?? {}),
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (runtimeState && providers) {
|
|
160
|
-
const runtimeProvider = providers.providers[runtimeState.provider] ?? null;
|
|
161
|
-
if (!runtimeProvider || !(0, providers_1.isCopilotBridgeProvider)(runtimeProvider)) {
|
|
162
|
-
issues.push({
|
|
163
|
-
code: "BRIDGE_STATE_STALE",
|
|
164
|
-
message: "Copilot bridge runtime state exists but no matching managed Copilot provider is available.",
|
|
165
|
-
...runtimeState,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
else if (!document?.currentModelProvider || runtimeProvider.profile !== document.currentModelProvider) {
|
|
169
|
-
issues.push({
|
|
170
|
-
code: "BRIDGE_STATE_STALE",
|
|
171
|
-
message: "Copilot bridge runtime state exists for a provider that is not the current active model_provider.",
|
|
172
|
-
activeModelProvider: document?.currentModelProvider ?? null,
|
|
173
|
-
runtimeProvider: runtimeState.provider,
|
|
174
|
-
runtimeProfile: runtimeProvider.profile,
|
|
175
|
-
...runtimeState,
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// Drift inspection still runs when files are missing so status output can explain partial state.
|
|
180
108
|
const drift = (0, runtime_state_1.inspectLiveStateDrift)(currentModelProvider, providers);
|
|
181
109
|
const codexCheck = (0, codex_probe_1.probeCodexRuntime)(codex_version_1.MIN_SUPPORTED_CODEX_VERSION);
|
|
182
110
|
if (!codexCheck.ok) {
|
|
@@ -200,36 +128,12 @@ async function runDoctor(args) {
|
|
|
200
128
|
healthy: issues.length === 0,
|
|
201
129
|
issues,
|
|
202
130
|
codexDir: args.codexDir,
|
|
203
|
-
storage: (0, runtime_state_1.getStorageRoles)({
|
|
204
|
-
codexDir: args.codexDir,
|
|
205
|
-
providersPath: args.providersPath,
|
|
206
|
-
configPath: args.configPath,
|
|
207
|
-
authPath: args.authPath,
|
|
208
|
-
runtimeDir: args.runtimeDir,
|
|
209
|
-
runtimesDir: args.runtimesDir,
|
|
210
|
-
}),
|
|
211
131
|
liveState: drift,
|
|
212
132
|
auth: authState,
|
|
213
|
-
copilotRuntimeState: runtimeState,
|
|
214
133
|
},
|
|
215
134
|
warnings: issues.length === 0 ? [] : [`doctor found ${issues.length} issue(s)`],
|
|
216
135
|
};
|
|
217
136
|
}
|
|
218
|
-
function mapBridgeDiagnosticCode(cause) {
|
|
219
|
-
if (cause === "Copilot bridge state manifest is missing.") {
|
|
220
|
-
return "BRIDGE_STATE_MISSING";
|
|
221
|
-
}
|
|
222
|
-
if (cause === "Copilot bridge runtime state exists but no active Copilot bridge provider is selected.") {
|
|
223
|
-
return "BRIDGE_STATE_STALE";
|
|
224
|
-
}
|
|
225
|
-
if (cause === "Copilot bridge state base URL does not match the provider runtime configuration.") {
|
|
226
|
-
return "PROVIDER_BASE_URL_MISMATCH";
|
|
227
|
-
}
|
|
228
|
-
return "BRIDGE_HEALTHCHECK_FAILED";
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Maps structured config consistency issues onto stable human-readable diagnostic text.
|
|
232
|
-
*/
|
|
233
137
|
function renderConfigIssueMessage(issue) {
|
|
234
138
|
switch (issue.code) {
|
|
235
139
|
case "MODEL_MISSING":
|
|
@@ -247,11 +151,9 @@ function renderConfigIssueMessage(issue) {
|
|
|
247
151
|
case "LEGACY_MODEL_PROVIDER_ENV_KEY":
|
|
248
152
|
return `Model provider "${issue.modelProvider}" still contains legacy env_key wiring.`;
|
|
249
153
|
case "PROVIDER_BASE_URL_MISMATCH":
|
|
250
|
-
return issue.
|
|
251
|
-
? `Direct provider "${issue.provider}" baseUrl does not match config.toml model provider "${issue.modelProvider}" base_url.`
|
|
252
|
-
: String(issue.code ?? "UNKNOWN_ISSUE");
|
|
154
|
+
return `Provider "${issue.provider}" baseUrl does not match config.toml model provider "${issue.modelProvider}" base_url.`;
|
|
253
155
|
case "AUTH_JSON_INVALID":
|
|
254
|
-
return String(issue.message ??
|
|
156
|
+
return String(issue.message ?? "auth.json is invalid.");
|
|
255
157
|
case "DESTRUCTIVE_REMOVE_BLOCKED":
|
|
256
158
|
return `Provider "${issue.provider}" cannot be removed while "${issue.activeModelProvider}" remains active.`;
|
|
257
159
|
default:
|
package/dist/app/setup-codex.js
CHANGED
|
@@ -5,9 +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_installer_1 = require("../runtime/copilot-installer");
|
|
10
|
-
const copilot_adapter_1 = require("../runtime/copilot-adapter");
|
|
11
8
|
const run_mutation_1 = require("./run-mutation");
|
|
12
9
|
const providers_1 = require("../domain/providers");
|
|
13
10
|
/**
|
|
@@ -32,81 +29,6 @@ async function switchProvider(args) {
|
|
|
32
29
|
suggestion: "Run `codexs edit <provider> --model <name>` or `codexs add <provider> --model <name>`.",
|
|
33
30
|
});
|
|
34
31
|
}
|
|
35
|
-
if ((0, providers_1.isCopilotBridgeProvider)(provider)) {
|
|
36
|
-
(0, copilot_installer_1.assertCopilotNodeRuntimeSupported)();
|
|
37
|
-
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)(args.runtimesDir);
|
|
38
|
-
if (!installStatus.installed) {
|
|
39
|
-
throw (0, errors_1.cliError)("COPILOT_SDK_MISSING", "The optional Copilot SDK runtime is not installed.", {
|
|
40
|
-
installDir: installStatus.installDir,
|
|
41
|
-
packageName: installStatus.packageName,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
await (0, copilot_adapter_1.readCopilotAuthState)(args.runtimesDir);
|
|
45
|
-
const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(args.providerName, provider, args.runtimeDir, args.runtimesDir);
|
|
46
|
-
const nextProvider = bridge.portChanged
|
|
47
|
-
? (0, providers_1.cleanProviderRecord)({
|
|
48
|
-
...provider,
|
|
49
|
-
baseUrl: bridge.baseUrl,
|
|
50
|
-
runtime: {
|
|
51
|
-
...provider.runtime,
|
|
52
|
-
bridgePort: bridge.port,
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
: provider;
|
|
56
|
-
try {
|
|
57
|
-
return (0, run_mutation_1.runMutation)({
|
|
58
|
-
lockPath: args.lockPath,
|
|
59
|
-
backupsDir: args.backupsDir,
|
|
60
|
-
latestBackupPath: args.latestBackupPath,
|
|
61
|
-
operation: "switch",
|
|
62
|
-
files: [
|
|
63
|
-
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
64
|
-
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
65
|
-
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
66
|
-
],
|
|
67
|
-
mutate: () => {
|
|
68
|
-
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
69
|
-
setCurrentModel: resolvedModel,
|
|
70
|
-
setCurrentModelProvider: provider.profile,
|
|
71
|
-
upsertModelProviders: {
|
|
72
|
-
[provider.profile]: (0, providers_1.buildCopilotModelProviderProjection)(nextProvider.runtime),
|
|
73
|
-
},
|
|
74
|
-
deleteLegacyProfile: true,
|
|
75
|
-
deleteLegacyProfilesByName: [provider.profile],
|
|
76
|
-
scrubModelProviderEnvKeys: [provider.profile],
|
|
77
|
-
});
|
|
78
|
-
if (bridge.portChanged) {
|
|
79
|
-
(0, providers_repo_1.writeProvidersFile)(args.providersPath, {
|
|
80
|
-
providers: {
|
|
81
|
-
...providers.providers,
|
|
82
|
-
[args.providerName]: nextProvider,
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
87
|
-
(0, auth_repo_1.writeOpenAiApiKeyAuth)(args.authPath, provider.apiKey);
|
|
88
|
-
return {
|
|
89
|
-
provider: args.providerName,
|
|
90
|
-
model: resolvedModel,
|
|
91
|
-
modelProvider: nextProvider.profile,
|
|
92
|
-
profile: nextProvider.profile,
|
|
93
|
-
portChanged: bridge.portChanged,
|
|
94
|
-
bridgePort: bridge.port,
|
|
95
|
-
bridgeReused: bridge.reused,
|
|
96
|
-
bridgeReplaced: bridge.replaced,
|
|
97
|
-
bridgeRestartReason: bridge.restartReason ?? null,
|
|
98
|
-
bridgeLogPath: bridge.logPath,
|
|
99
|
-
};
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
if (!bridge.reused) {
|
|
105
|
-
(0, copilot_bridge_1.stopCopilotBridge)(args.runtimeDir);
|
|
106
|
-
}
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
32
|
return (0, run_mutation_1.runMutation)({
|
|
111
33
|
lockPath: args.lockPath,
|
|
112
34
|
backupsDir: args.backupsDir,
|
|
@@ -130,7 +52,7 @@ async function switchProvider(args) {
|
|
|
130
52
|
setCurrentModel: resolvedModel,
|
|
131
53
|
setCurrentModelProvider: provider.profile,
|
|
132
54
|
upsertModelProviders: {
|
|
133
|
-
[provider.profile]: (0, providers_1.
|
|
55
|
+
[provider.profile]: (0, providers_1.buildModelProviderProjection)(provider.profile, resolvedBaseUrl),
|
|
134
56
|
},
|
|
135
57
|
deleteLegacyProfile: true,
|
|
136
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":
|