@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
|
@@ -1,16 +1,59 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.listProviders = listProviders;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const providers_1 = require("../domain/providers");
|
|
39
|
+
const runtime_state_1 = require("../domain/runtime-state");
|
|
40
|
+
const config_repo_1 = require("../storage/config-repo");
|
|
4
41
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
5
42
|
/**
|
|
6
43
|
* Returns the sorted list of configured providers for display.
|
|
7
44
|
*/
|
|
8
|
-
function listProviders(providersPath) {
|
|
45
|
+
function listProviders(providersPath, configPath) {
|
|
9
46
|
const providers = (0, providers_repo_1.readProvidersFile)(providersPath);
|
|
10
47
|
const names = Object.keys(providers.providers).sort();
|
|
48
|
+
const currentProfile = configPath && fs.existsSync(configPath)
|
|
49
|
+
? (0, config_repo_1.readStructuredConfig)(configPath).activeProfile
|
|
50
|
+
: null;
|
|
51
|
+
const liveState = (0, runtime_state_1.inspectLiveStateDrift)(currentProfile, providers);
|
|
11
52
|
const items = names.map((name) => ({
|
|
12
53
|
name,
|
|
13
54
|
profile: providers.providers[name].profile,
|
|
55
|
+
providerType: (0, providers_1.isCopilotBridgeProvider)(providers.providers[name]) ? "copilot" : "direct",
|
|
56
|
+
isActive: liveState.providerResolvable && liveState.mappedProvider === name,
|
|
14
57
|
note: providers.providers[name].note ?? null,
|
|
15
58
|
tags: providers.providers[name].tags ?? [],
|
|
16
59
|
}));
|
|
@@ -18,6 +61,10 @@ function listProviders(providersPath) {
|
|
|
18
61
|
data: {
|
|
19
62
|
providers: items,
|
|
20
63
|
count: items.length,
|
|
64
|
+
currentProfile,
|
|
65
|
+
activeProvider: liveState.mappedProvider,
|
|
66
|
+
activeProviderResolvable: liveState.providerResolvable,
|
|
67
|
+
activeProviderCandidates: liveState.mappedProviders,
|
|
21
68
|
},
|
|
22
69
|
};
|
|
23
70
|
}
|
|
@@ -34,7 +34,7 @@ function removeProvider(args) {
|
|
|
34
34
|
switchToProfile: args.switchToProfile ?? null,
|
|
35
35
|
});
|
|
36
36
|
return (0, run_mutation_1.runMutation)({
|
|
37
|
-
|
|
37
|
+
lockPath: args.lockPath,
|
|
38
38
|
backupsDir: args.backupsDir,
|
|
39
39
|
latestBackupPath: args.latestBackupPath,
|
|
40
40
|
operation: "remove",
|
package/dist/app/run-doctor.js
CHANGED
|
@@ -103,7 +103,7 @@ async function runDoctor(args) {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
const authState = (0, auth_repo_1.readAuthFileState)(args.authPath);
|
|
106
|
-
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)();
|
|
106
|
+
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)(args.runtimeDir);
|
|
107
107
|
const runtimeState = runtimeStateInspection.state;
|
|
108
108
|
if (authState.exists && !authState.valid) {
|
|
109
109
|
issues.push({
|
|
@@ -123,7 +123,7 @@ async function runDoctor(args) {
|
|
|
123
123
|
if (matches.length === 1) {
|
|
124
124
|
const activeProvider = providers.providers[matches[0]];
|
|
125
125
|
if ((0, providers_1.isCopilotBridgeProvider)(activeProvider)) {
|
|
126
|
-
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)();
|
|
126
|
+
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)(args.runtimesDir);
|
|
127
127
|
if (!installStatus.installed) {
|
|
128
128
|
issues.push({
|
|
129
129
|
code: "COPILOT_SDK_MISSING",
|
|
@@ -133,7 +133,7 @@ async function runDoctor(args) {
|
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
135
|
try {
|
|
136
|
-
await (0, copilot_adapter_1.readCopilotAuthState)();
|
|
136
|
+
await (0, copilot_adapter_1.readCopilotAuthState)(args.runtimesDir);
|
|
137
137
|
}
|
|
138
138
|
catch (error) {
|
|
139
139
|
const normalized = (0, errors_1.normalizeError)(error);
|
|
@@ -143,7 +143,7 @@ async function runDoctor(args) {
|
|
|
143
143
|
...(normalized.details ?? {}),
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
|
-
const bridge = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider, runtimeState);
|
|
146
|
+
const bridge = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider, runtimeState, args.runtimeDir);
|
|
147
147
|
if (!bridge.ok) {
|
|
148
148
|
issues.push({
|
|
149
149
|
code: mapBridgeDiagnosticCode(bridge.cause),
|
|
@@ -198,7 +198,14 @@ async function runDoctor(args) {
|
|
|
198
198
|
healthy: issues.length === 0,
|
|
199
199
|
issues,
|
|
200
200
|
codexDir: args.codexDir,
|
|
201
|
-
storage: (0, runtime_state_1.getStorageRoles)(
|
|
201
|
+
storage: (0, runtime_state_1.getStorageRoles)({
|
|
202
|
+
codexDir: args.codexDir,
|
|
203
|
+
providersPath: args.providersPath,
|
|
204
|
+
configPath: args.configPath,
|
|
205
|
+
authPath: args.authPath,
|
|
206
|
+
runtimeDir: args.runtimeDir,
|
|
207
|
+
runtimesDir: args.runtimesDir,
|
|
208
|
+
}),
|
|
202
209
|
liveState: drift,
|
|
203
210
|
auth: authState,
|
|
204
211
|
},
|
package/dist/app/run-mutation.js
CHANGED
|
@@ -8,8 +8,9 @@ const lock_repo_1 = require("../storage/lock-repo");
|
|
|
8
8
|
* Runs a write operation under a lock with automatic backup and rollback handling.
|
|
9
9
|
*/
|
|
10
10
|
function runMutation(args) {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const lockPath = args.lockPath ?? require("node:path").join(args.codexDir ?? process.cwd(), ".codex-switch.lock");
|
|
12
|
+
return (0, lock_repo_1.withCodexLock)(lockPath, args.operation, () => {
|
|
13
|
+
const backup = (0, backup_repo_1.createBackup)(args.backupsDir, args.operation, args.files);
|
|
13
14
|
try {
|
|
14
15
|
const data = args.mutate({ backup });
|
|
15
16
|
// Record the successful backup only after the mutation completes.
|
package/dist/app/setup-codex.js
CHANGED
|
@@ -130,7 +130,7 @@ async function migrateCodex(args) {
|
|
|
130
130
|
};
|
|
131
131
|
const finalProviders = args.strategy === "merge" ? (0, providers_repo_1.mergeProviders)(currentProviders, nextProviders) : nextProviders;
|
|
132
132
|
const result = (0, run_mutation_1.runMutation)({
|
|
133
|
-
|
|
133
|
+
lockPath: args.lockPath,
|
|
134
134
|
backupsDir: args.backupsDir,
|
|
135
135
|
latestBackupPath: args.latestBackupPath,
|
|
136
136
|
operation: "migrate",
|
|
@@ -163,6 +163,8 @@ async function migrateCodex(args) {
|
|
|
163
163
|
configPath: args.configPath,
|
|
164
164
|
providersPath: args.providersPath,
|
|
165
165
|
authPath: args.authPath,
|
|
166
|
+
runtimeDir: args.runtimeDir,
|
|
167
|
+
runtimesDir: args.runtimesDir,
|
|
166
168
|
});
|
|
167
169
|
return {
|
|
168
170
|
data: {
|
|
@@ -23,15 +23,15 @@ async function switchProvider(args) {
|
|
|
23
23
|
}
|
|
24
24
|
const document = (0, config_repo_1.ensureProfileExists)(args.configPath, provider.profile, args.providerName);
|
|
25
25
|
if ((0, providers_1.isCopilotBridgeProvider)(provider)) {
|
|
26
|
-
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)();
|
|
26
|
+
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)(args.runtimesDir);
|
|
27
27
|
if (!installStatus.installed) {
|
|
28
28
|
throw (0, errors_1.cliError)("COPILOT_SDK_MISSING", "The optional Copilot SDK runtime is not installed.", {
|
|
29
29
|
installDir: installStatus.installDir,
|
|
30
30
|
packageName: installStatus.packageName,
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
-
await (0, copilot_adapter_1.readCopilotAuthState)();
|
|
34
|
-
const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(args.providerName, provider);
|
|
33
|
+
await (0, copilot_adapter_1.readCopilotAuthState)(args.runtimesDir);
|
|
34
|
+
const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(args.providerName, provider, args.runtimeDir);
|
|
35
35
|
const nextProvider = bridge.portChanged
|
|
36
36
|
? (0, providers_1.cleanProviderRecord)({
|
|
37
37
|
...provider,
|
|
@@ -44,24 +44,21 @@ async function switchProvider(args) {
|
|
|
44
44
|
: provider;
|
|
45
45
|
try {
|
|
46
46
|
return (0, run_mutation_1.runMutation)({
|
|
47
|
-
|
|
47
|
+
lockPath: args.lockPath,
|
|
48
48
|
backupsDir: args.backupsDir,
|
|
49
49
|
latestBackupPath: args.latestBackupPath,
|
|
50
50
|
operation: "switch",
|
|
51
51
|
files: [
|
|
52
|
+
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
52
53
|
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
53
54
|
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
54
55
|
],
|
|
55
56
|
mutate: () => {
|
|
56
57
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
57
58
|
setActiveProfile: provider.profile,
|
|
58
|
-
upsertModelProviders:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
baseUrl: (0, providers_1.buildCopilotBridgeBaseUrl)(nextProvider.runtime),
|
|
62
|
-
},
|
|
63
|
-
}
|
|
64
|
-
: undefined,
|
|
59
|
+
upsertModelProviders: {
|
|
60
|
+
[provider.profile]: (0, providers_1.buildCopilotModelProviderProjection)(nextProvider.runtime),
|
|
61
|
+
},
|
|
65
62
|
});
|
|
66
63
|
if (bridge.portChanged) {
|
|
67
64
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, {
|
|
@@ -72,6 +69,7 @@ async function switchProvider(args) {
|
|
|
72
69
|
});
|
|
73
70
|
}
|
|
74
71
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
72
|
+
(0, auth_repo_1.writeOpenAiApiKeyAuth)(args.authPath, provider.apiKey);
|
|
75
73
|
return {
|
|
76
74
|
provider: args.providerName,
|
|
77
75
|
profile: nextProvider.profile,
|
|
@@ -83,13 +81,13 @@ async function switchProvider(args) {
|
|
|
83
81
|
}
|
|
84
82
|
catch (error) {
|
|
85
83
|
if (!bridge.reused) {
|
|
86
|
-
(0, copilot_bridge_1.stopCopilotBridge)();
|
|
84
|
+
(0, copilot_bridge_1.stopCopilotBridge)(args.runtimeDir);
|
|
87
85
|
}
|
|
88
86
|
throw error;
|
|
89
87
|
}
|
|
90
88
|
}
|
|
91
89
|
return (0, run_mutation_1.runMutation)({
|
|
92
|
-
|
|
90
|
+
lockPath: args.lockPath,
|
|
93
91
|
backupsDir: args.backupsDir,
|
|
94
92
|
latestBackupPath: args.latestBackupPath,
|
|
95
93
|
operation: "switch",
|
package/dist/cli/output.js
CHANGED
|
@@ -85,12 +85,22 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
85
85
|
lines.push("No providers configured.");
|
|
86
86
|
}
|
|
87
87
|
else {
|
|
88
|
+
const currentProfile = typeof data?.currentProfile === "string" ? data.currentProfile : null;
|
|
89
|
+
const activeProviderResolvable = data?.activeProviderResolvable !== false;
|
|
90
|
+
const activeCandidates = Array.isArray(data?.activeProviderCandidates) ? data?.activeProviderCandidates : [];
|
|
91
|
+
if (currentProfile) {
|
|
92
|
+
lines.push(`Current profile: ${currentProfile}`);
|
|
93
|
+
if (!activeProviderResolvable && activeCandidates.length > 1) {
|
|
94
|
+
lines.push(`Current provider: ambiguous (${activeCandidates.join(", ")})`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
88
97
|
for (const provider of providers) {
|
|
89
98
|
const tags = Array.isArray(provider.tags) && provider.tags.length > 0
|
|
90
99
|
? ` tags=${provider.tags.join(",")}`
|
|
91
100
|
: "";
|
|
92
101
|
const note = provider.note ? ` note=${provider.note}` : "";
|
|
93
|
-
|
|
102
|
+
const current = provider.isActive ? " current" : "";
|
|
103
|
+
lines.push(`${provider.name} [${String(provider.providerType ?? "direct")}]${current} -> ${provider.profile}${tags}${note}`);
|
|
94
104
|
}
|
|
95
105
|
}
|
|
96
106
|
break;
|
|
@@ -115,17 +125,15 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
115
125
|
lines.push(`Current profile: ${String(data?.profile ?? "")}`);
|
|
116
126
|
break;
|
|
117
127
|
case "status":
|
|
118
|
-
lines.push(
|
|
119
|
-
lines.push(`
|
|
120
|
-
lines.push(`
|
|
121
|
-
lines.push(`
|
|
122
|
-
lines.push(`
|
|
123
|
-
lines.push(`
|
|
124
|
-
|
|
125
|
-
lines.push(`
|
|
126
|
-
lines.push(`
|
|
127
|
-
lines.push(`authMode: ${String(auth.authMode ?? "")}`);
|
|
128
|
-
lines.push(`issues: ${Array.isArray(data?.issues) ? (data?.issues).length : 0}`);
|
|
128
|
+
lines.push("Status summary:");
|
|
129
|
+
lines.push(` target runtime: ${String(data?.codexDir ?? "")}`);
|
|
130
|
+
lines.push(` tool home: ${String(data?.storage?.toolHome?.root ?? "")}`);
|
|
131
|
+
lines.push(` current profile: ${String(data?.currentProfile ?? "(none)")}`);
|
|
132
|
+
lines.push(` mapped provider: ${renderStatusMappedProvider(data)}`);
|
|
133
|
+
lines.push(` provider path: ${renderStatusProviderPath(data)}`);
|
|
134
|
+
lines.push(` runtime health: ${renderStatusHealth(data)}`);
|
|
135
|
+
lines.push(` warnings: ${warnings.length}`);
|
|
136
|
+
lines.push(` next step: ${renderStatusNextStep(data, warnings)}`);
|
|
129
137
|
break;
|
|
130
138
|
case "config-show": {
|
|
131
139
|
lines.push(`activeProfile: ${String(data?.activeProfile ?? "")}`);
|
|
@@ -153,10 +161,26 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
153
161
|
lines.push(`Exported providers to ${String(data?.exportedTo ?? "")}.`);
|
|
154
162
|
break;
|
|
155
163
|
case "init":
|
|
156
|
-
lines.push(
|
|
157
|
-
lines.push(`
|
|
158
|
-
lines.push(`
|
|
159
|
-
lines.push(`
|
|
164
|
+
lines.push("Initialized codex-switch tool home.");
|
|
165
|
+
lines.push(`tool home: ${String(data?.toolHomeDir ?? "")}`);
|
|
166
|
+
lines.push(`tool config: ${String(data?.toolConfigPath ?? "")}`);
|
|
167
|
+
lines.push(`providers registry: ${String(data?.providersPath ?? "")}`);
|
|
168
|
+
lines.push(`tool home created: ${String(data?.createdToolHomeDir ?? false)}`);
|
|
169
|
+
lines.push(`tool config created: ${String(data?.createdToolConfigFile ?? false)}`);
|
|
170
|
+
lines.push(`providers registry created: ${String(data?.createdProvidersFile ?? false)}`);
|
|
171
|
+
lines.push("next step: run `codexs add ...` for a direct provider, or `codexs login copilot` before `add --copilot`.");
|
|
172
|
+
break;
|
|
173
|
+
case "login":
|
|
174
|
+
lines.push(`Copilot login ready: ${String(data?.authReady ?? false)}`);
|
|
175
|
+
lines.push(`upstream: ${String(data?.upstream ?? "")}`);
|
|
176
|
+
lines.push(`sdk installed: ${String(data?.sdkInstalled ?? false)}${data?.sdkInstalledNow ? " (installed now)" : ""}`);
|
|
177
|
+
lines.push(`copilot cli source: ${String(data?.cliSource ?? "not-needed")}`);
|
|
178
|
+
if (data?.cliCommand) {
|
|
179
|
+
lines.push(`copilot cli command: ${String(data?.cliCommand)}`);
|
|
180
|
+
}
|
|
181
|
+
lines.push(`login launched: ${String(data?.loginLaunched ?? false)}`);
|
|
182
|
+
lines.push(`auth ready: ${String(data?.authReady ?? false)}`);
|
|
183
|
+
lines.push("next step: run `codexs add <provider> --copilot --profile <name>` and then `codexs switch <provider>`.");
|
|
160
184
|
break;
|
|
161
185
|
case "migrate":
|
|
162
186
|
lines.push(`Migrated providers in ${String(data?.codexDir ?? "")} using ${String(data?.strategy ?? "")}.`);
|
|
@@ -185,10 +209,12 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
185
209
|
break;
|
|
186
210
|
case "doctor": {
|
|
187
211
|
const healthy = Boolean(data?.healthy);
|
|
188
|
-
lines.push(healthy ? "No issues found." : "Issues found:");
|
|
189
212
|
const issues = data?.issues ?? [];
|
|
213
|
+
lines.push(healthy ? "Doctor summary: healthy. No action required." : `Doctor summary: ${issues.length} issue(s) need attention.`);
|
|
214
|
+
lines.push(`target runtime: ${String(data?.codexDir ?? "")}`);
|
|
190
215
|
for (const issue of issues) {
|
|
191
|
-
lines.push(
|
|
216
|
+
lines.push(`- ${String(issue.code)}: ${String(issue.message)}`);
|
|
217
|
+
lines.push(` next step: ${renderDoctorIssueNextStep(issue)}`);
|
|
192
218
|
}
|
|
193
219
|
break;
|
|
194
220
|
}
|
|
@@ -212,6 +238,107 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
212
238
|
}
|
|
213
239
|
return lines;
|
|
214
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Summarizes runtime health for the human-readable status output.
|
|
243
|
+
*/
|
|
244
|
+
function renderStatusHealth(data) {
|
|
245
|
+
const configExists = Boolean(data?.configExists);
|
|
246
|
+
const providersExists = Boolean(data?.providersExists);
|
|
247
|
+
const auth = data?.auth ?? {};
|
|
248
|
+
const bridge = data?.copilotBridge ?? null;
|
|
249
|
+
const issues = Array.isArray(data?.issues) ? data?.issues : [];
|
|
250
|
+
const activeProviderResolvable = data?.activeProviderResolvable !== false;
|
|
251
|
+
const liveState = data?.liveState ?? {};
|
|
252
|
+
const copilotSdk = data?.copilotSdk ?? {};
|
|
253
|
+
const copilotAuth = data?.copilotAuth ?? null;
|
|
254
|
+
const runtimeProvider = typeof data?.runtimeProvider === "string" ? data.runtimeProvider : null;
|
|
255
|
+
const activePathUsesCopilot = runtimeProvider === "copilot-sdk-bridge";
|
|
256
|
+
if (!configExists || !providersExists) {
|
|
257
|
+
return "incomplete local state";
|
|
258
|
+
}
|
|
259
|
+
if (!activeProviderResolvable || liveState.reason === "shared-profile") {
|
|
260
|
+
return "active provider ambiguous";
|
|
261
|
+
}
|
|
262
|
+
if (issues.some((issue) => issue.code === "UNMANAGED_ACTIVE_PROFILE")) {
|
|
263
|
+
return "active profile unmanaged";
|
|
264
|
+
}
|
|
265
|
+
if (issues.some((issue) => issue.code === "ACTIVE_PROVIDER_UNRESOLVED")) {
|
|
266
|
+
return "active provider ambiguous";
|
|
267
|
+
}
|
|
268
|
+
if (activePathUsesCopilot && copilotSdk.installed === false) {
|
|
269
|
+
return "copilot sdk missing";
|
|
270
|
+
}
|
|
271
|
+
if (activePathUsesCopilot && copilotAuth && copilotAuth.ready === false) {
|
|
272
|
+
return "copilot auth required";
|
|
273
|
+
}
|
|
274
|
+
if (activePathUsesCopilot && bridge && bridge.ok === false) {
|
|
275
|
+
return "copilot runtime needs repair";
|
|
276
|
+
}
|
|
277
|
+
if (auth.exists === false) {
|
|
278
|
+
return "auth projection missing";
|
|
279
|
+
}
|
|
280
|
+
if (auth.valid === false) {
|
|
281
|
+
return "auth projection invalid";
|
|
282
|
+
}
|
|
283
|
+
return "ok";
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Renders the mapped provider line without claiming a unique winner for shared profiles.
|
|
287
|
+
*/
|
|
288
|
+
function renderStatusMappedProvider(data) {
|
|
289
|
+
if (typeof data?.provider === "string" && data.provider.length > 0) {
|
|
290
|
+
return data.provider;
|
|
291
|
+
}
|
|
292
|
+
const candidates = Array.isArray(data?.activeProviderCandidates) ? data?.activeProviderCandidates : [];
|
|
293
|
+
if (candidates.length > 1) {
|
|
294
|
+
return `(ambiguous: ${candidates.join(", ")})`;
|
|
295
|
+
}
|
|
296
|
+
return "(unmanaged or unresolved)";
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Renders the active workflow path in status output.
|
|
300
|
+
*/
|
|
301
|
+
function renderStatusProviderPath(data) {
|
|
302
|
+
return typeof data?.runtimeProvider === "string" && data.runtimeProvider === "copilot-sdk-bridge" ? "copilot" : "direct";
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Suggests the next operator action for the human-readable status output.
|
|
306
|
+
*/
|
|
307
|
+
function renderStatusNextStep(data, warnings) {
|
|
308
|
+
if (warnings.length > 0) {
|
|
309
|
+
return "run `codexs doctor` to inspect warnings before the next write command";
|
|
310
|
+
}
|
|
311
|
+
if (!data?.provider) {
|
|
312
|
+
return "run `codexs switch <provider>` after adding or adopting a managed provider";
|
|
313
|
+
}
|
|
314
|
+
return "run `codexs doctor` if you need a deeper diagnostic pass";
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Turns structured doctor issue codes into repair-oriented next steps.
|
|
318
|
+
*/
|
|
319
|
+
function renderDoctorIssueNextStep(issue) {
|
|
320
|
+
switch (issue.code) {
|
|
321
|
+
case "CONFIG_NOT_FOUND":
|
|
322
|
+
return "restore or create config.toml before switching providers";
|
|
323
|
+
case "PROVIDERS_NOT_FOUND":
|
|
324
|
+
return "run `codexs init` and then add or migrate providers";
|
|
325
|
+
case "COPILOT_SDK_MISSING":
|
|
326
|
+
return "run `codexs login copilot` to install the optional Copilot runtime";
|
|
327
|
+
case "COPILOT_AUTH_REQUIRED":
|
|
328
|
+
return "run `codexs login copilot` to complete upstream authentication";
|
|
329
|
+
case "BRIDGE_STATE_STALE":
|
|
330
|
+
case "BRIDGE_STATE_MISSING":
|
|
331
|
+
case "BRIDGE_HEALTHCHECK_FAILED":
|
|
332
|
+
return "reselect the provider with `codexs switch <provider>` or inspect bridge state";
|
|
333
|
+
case "UNMANAGED_ACTIVE_PROFILE":
|
|
334
|
+
return "switch to a managed provider or adopt the active profile with `codexs migrate`";
|
|
335
|
+
case "ACTIVE_PROVIDER_UNRESOLVED":
|
|
336
|
+
case "SHARED_PROFILE_REFERENCE":
|
|
337
|
+
return "make provider-to-profile mappings unique before relying on current-provider detection";
|
|
338
|
+
default:
|
|
339
|
+
return "inspect the issue details and rerun `codexs doctor` after fixing the state";
|
|
340
|
+
}
|
|
341
|
+
}
|
|
215
342
|
/**
|
|
216
343
|
* Writes one rendered line to either stdout or stderr.
|
|
217
344
|
*/
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
37
|
exports.printHelp = printHelp;
|
|
5
38
|
exports.printVersion = printVersion;
|
|
6
39
|
exports.main = main;
|
|
7
|
-
const dispatch_1 = require("./commands/dispatch");
|
|
8
40
|
const args_1 = require("./commands/args");
|
|
9
41
|
const help_1 = require("./commands/help");
|
|
10
42
|
const errors_1 = require("./domain/errors");
|
|
@@ -49,7 +81,7 @@ function main() {
|
|
|
49
81
|
command: parsed.command,
|
|
50
82
|
options: parsed.globalOptions,
|
|
51
83
|
};
|
|
52
|
-
(
|
|
84
|
+
Promise.resolve().then(() => __importStar(require("./commands/dispatch"))).then(({ executeCommand }) => executeCommand(ctx, parsed))
|
|
53
85
|
.then((result) => {
|
|
54
86
|
(0, output_1.outputSuccess)(ctx, result);
|
|
55
87
|
})
|
package/dist/commands/args.js
CHANGED
|
@@ -11,7 +11,7 @@ const registry_1 = require("./registry");
|
|
|
11
11
|
*/
|
|
12
12
|
function parseArgs(argv) {
|
|
13
13
|
let json = false;
|
|
14
|
-
let codexDir =
|
|
14
|
+
let codexDir = null;
|
|
15
15
|
let codexDirExplicit = false;
|
|
16
16
|
const remaining = [];
|
|
17
17
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -105,7 +105,7 @@ function defaultParsed(command, overrides) {
|
|
|
105
105
|
positionals: [],
|
|
106
106
|
globalOptions: {
|
|
107
107
|
json: overrides?.json ?? false,
|
|
108
|
-
codexDir: overrides?.codexDir ??
|
|
108
|
+
codexDir: overrides?.codexDir ?? null,
|
|
109
109
|
codexDirExplicit: false,
|
|
110
110
|
},
|
|
111
111
|
commandOptions: new Map(),
|
|
@@ -1,8 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.executeCommand = executeCommand;
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
4
38
|
const errors_1 = require("../domain/errors");
|
|
5
39
|
const prompt_1 = require("../interaction/prompt");
|
|
40
|
+
const codex_paths_1 = require("../storage/codex-paths");
|
|
41
|
+
const tool_config_repo_1 = require("../storage/tool-config-repo");
|
|
6
42
|
const registry_1 = require("./registry");
|
|
7
43
|
/**
|
|
8
44
|
* Resolves the shared command definition and executes its registered handler.
|
|
@@ -12,5 +48,9 @@ async function executeCommand(ctx, parsed, runtime = (0, prompt_1.createPromptRu
|
|
|
12
48
|
if (!definition) {
|
|
13
49
|
throw (0, errors_1.cliError)("UNKNOWN_COMMAND", `Unknown command: ${ctx.command}`);
|
|
14
50
|
}
|
|
51
|
+
const toolHomeDir = (0, codex_paths_1.resolveCodexSwitchHome)();
|
|
52
|
+
const toolConfigPath = path.join(toolHomeDir, "codex-switch.json");
|
|
53
|
+
const toolConfig = (0, tool_config_repo_1.readToolConfigIfExists)(toolConfigPath);
|
|
54
|
+
ctx.options.codexDir = (0, codex_paths_1.resolveCodexDir)(ctx.options.codexDir ?? undefined, toolConfig);
|
|
15
55
|
return definition.handler(ctx, parsed, runtime);
|
|
16
56
|
}
|