@minniexcode/codex-switch 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.AI.md +5 -3
- package/README.CN.md +25 -3
- package/README.md +3 -2
- package/dist/app/add-provider.js +1 -12
- package/dist/app/bridge.js +295 -0
- package/dist/app/edit-provider.js +1 -17
- package/dist/app/get-status.js +32 -2
- package/dist/app/list-providers.js +0 -1
- package/dist/app/run-doctor.js +45 -38
- package/dist/app/setup-codex.js +27 -17
- package/dist/app/show-config.js +1 -5
- package/dist/app/switch-provider.js +33 -20
- package/dist/cli/output.js +4 -6
- package/dist/cli.js +1 -1
- package/dist/commands/handlers.js +223 -39
- package/dist/commands/help.js +1 -0
- package/dist/commands/registry.js +48 -4
- package/dist/domain/config.js +4 -68
- package/dist/domain/providers.js +0 -5
- package/dist/domain/runtime-state.js +2 -1
- package/dist/domain/setup.js +58 -3
- package/dist/interaction/add-interactive.js +55 -1
- package/dist/interaction/interactive.js +1 -5
- package/dist/runtime/copilot-adapter.js +44 -1
- package/dist/runtime/copilot-bridge-worker.js +1 -1
- package/dist/runtime/copilot-bridge.js +60 -19
- package/dist/runtime/copilot-cli.js +70 -0
- package/dist/runtime/copilot-installer.js +49 -2
- package/dist/storage/auth-repo.js +28 -77
- package/dist/storage/config-repo.js +1 -36
- package/dist/storage/runtime-state-repo.js +32 -0
- package/docs/Design/codex-switch-copilot-integration-design.md +517 -0
- package/docs/Design/codex-switch-v0.0.10-design.md +669 -0
- package/docs/Design/codex-switch-v0.0.9-design.md +182 -0
- package/docs/PRD/codex-switch-prd-v0.0.10.md +406 -0
- package/docs/PRD/codex-switch-prd-v0.0.9.md +166 -0
- package/docs/Tests/testing-bridge-v0.0.9.md +367 -0
- package/docs/cli-usage.md +38 -14
- package/docs/codex-switch-product-overview.md +2 -2
- package/docs/codex-switch-technical-architecture.md +6 -5
- package/package.json +1 -1
- /package/docs/{test-report-0.0.5.md → Tests/test-report-0.0.5.md} +0 -0
- /package/docs/{test-report-0.0.7.md → Tests/test-report-0.0.7.md} +0 -0
- /package/docs/{testing.md → Tests/testing.md} +0 -0
|
@@ -34,15 +34,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.readAuthFileIfExists = readAuthFileIfExists;
|
|
37
|
-
exports.
|
|
38
|
-
exports.
|
|
39
|
-
exports.writeAuthFile = writeAuthFile;
|
|
40
|
-
exports.extractManagedAuthFingerprint = extractManagedAuthFingerprint;
|
|
41
|
-
exports.readManagedAuthState = readManagedAuthState;
|
|
37
|
+
exports.readAuthFileState = readAuthFileState;
|
|
38
|
+
exports.writeOpenAiApiKeyAuth = writeOpenAiApiKeyAuth;
|
|
42
39
|
const fs = __importStar(require("node:fs"));
|
|
43
40
|
const errors_1 = require("../domain/errors");
|
|
44
|
-
const fs_utils_1 = require("./fs-utils");
|
|
45
|
-
const LEGACY_MANAGED_SECRET_KEYS = new Set(["api_key"]);
|
|
46
41
|
/**
|
|
47
42
|
* Reads auth.json when it exists and returns null otherwise.
|
|
48
43
|
*/
|
|
@@ -61,84 +56,27 @@ function readAuthFileIfExists(authPath) {
|
|
|
61
56
|
}
|
|
62
57
|
}
|
|
63
58
|
/**
|
|
64
|
-
*
|
|
59
|
+
* Reads auth.json into a neutral file-state summary for status and doctor.
|
|
65
60
|
*/
|
|
66
|
-
function
|
|
67
|
-
return {
|
|
68
|
-
auth_mode: "apikey",
|
|
69
|
-
[provider.envKey]: provider.apiKey,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Builds the next auth.json object while preserving unmanaged metadata.
|
|
74
|
-
*/
|
|
75
|
-
function buildManagedAuthJson(provider, existingAuthJson) {
|
|
76
|
-
const nextManaged = buildManagedAuthPayload(provider);
|
|
77
|
-
const result = {};
|
|
78
|
-
if (existingAuthJson && typeof existingAuthJson === "object" && !Array.isArray(existingAuthJson)) {
|
|
79
|
-
for (const [key, value] of Object.entries(existingAuthJson)) {
|
|
80
|
-
if (key === "auth_mode" || LEGACY_MANAGED_SECRET_KEYS.has(key) || looksLikeManagedSecretKey(key)) {
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
result[key] = value;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
result.auth_mode = nextManaged.auth_mode;
|
|
87
|
-
result[provider.envKey] = provider.apiKey;
|
|
88
|
-
return result;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Writes auth.json atomically using the managed mirror strategy.
|
|
92
|
-
*/
|
|
93
|
-
function writeAuthFile(authPath, provider, existingAuthJson) {
|
|
94
|
-
(0, fs_utils_1.writeTextFileAtomic)(authPath, `${JSON.stringify(buildManagedAuthJson(provider, existingAuthJson), null, 2)}\n`);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Extracts a lightweight fingerprint used by doctor/status.
|
|
98
|
-
*/
|
|
99
|
-
function extractManagedAuthFingerprint(input) {
|
|
100
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
101
|
-
return {
|
|
102
|
-
authMode: null,
|
|
103
|
-
managedSecretKeys: [],
|
|
104
|
-
payload: null,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
const payload = input;
|
|
108
|
-
const authMode = typeof payload.auth_mode === "string" ? payload.auth_mode : null;
|
|
109
|
-
const managedSecretKeys = Object.keys(payload)
|
|
110
|
-
.filter((key) => key !== "auth_mode" && looksLikeManagedSecretKey(key))
|
|
111
|
-
.sort();
|
|
112
|
-
return {
|
|
113
|
-
authMode,
|
|
114
|
-
managedSecretKeys,
|
|
115
|
-
payload,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Reads auth.json into a doctor-friendly managed state summary.
|
|
120
|
-
*/
|
|
121
|
-
function readManagedAuthState(authPath) {
|
|
61
|
+
function readAuthFileState(authPath) {
|
|
122
62
|
if (!fs.existsSync(authPath)) {
|
|
123
63
|
return {
|
|
124
64
|
exists: false,
|
|
125
65
|
valid: false,
|
|
126
66
|
parseError: null,
|
|
127
67
|
authMode: null,
|
|
128
|
-
managedSecretKeys: [],
|
|
129
|
-
payload: null,
|
|
130
68
|
};
|
|
131
69
|
}
|
|
132
70
|
try {
|
|
133
71
|
const payload = readAuthFileIfExists(authPath);
|
|
134
|
-
const
|
|
72
|
+
const authMode = payload && typeof payload === "object" && !Array.isArray(payload) && typeof payload.auth_mode === "string"
|
|
73
|
+
? String(payload.auth_mode)
|
|
74
|
+
: null;
|
|
135
75
|
return {
|
|
136
76
|
exists: true,
|
|
137
|
-
valid: Boolean(
|
|
77
|
+
valid: Boolean(payload && typeof payload === "object" && !Array.isArray(payload)),
|
|
138
78
|
parseError: null,
|
|
139
|
-
authMode
|
|
140
|
-
managedSecretKeys: fingerprint.managedSecretKeys,
|
|
141
|
-
payload: fingerprint.payload,
|
|
79
|
+
authMode,
|
|
142
80
|
};
|
|
143
81
|
}
|
|
144
82
|
catch (error) {
|
|
@@ -147,14 +85,27 @@ function readManagedAuthState(authPath) {
|
|
|
147
85
|
valid: false,
|
|
148
86
|
parseError: (0, errors_1.normalizeError)(error).message,
|
|
149
87
|
authMode: null,
|
|
150
|
-
managedSecretKeys: [],
|
|
151
|
-
payload: null,
|
|
152
88
|
};
|
|
153
89
|
}
|
|
154
90
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Writes the active direct-provider auth projection expected by Codex.
|
|
93
|
+
* Invalid or missing existing auth.json content is replaced with a minimal valid object.
|
|
94
|
+
*/
|
|
95
|
+
function writeOpenAiApiKeyAuth(authPath, apiKey) {
|
|
96
|
+
let next = {};
|
|
97
|
+
if (fs.existsSync(authPath)) {
|
|
98
|
+
try {
|
|
99
|
+
const payload = JSON.parse(fs.readFileSync(authPath, "utf8"));
|
|
100
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
101
|
+
next = { ...payload };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
next = {};
|
|
106
|
+
}
|
|
158
107
|
}
|
|
159
|
-
|
|
108
|
+
next.auth_mode = "apikey";
|
|
109
|
+
next.OPENAI_API_KEY = apiKey;
|
|
110
|
+
fs.writeFileSync(authPath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
|
|
160
111
|
}
|
|
@@ -40,7 +40,6 @@ exports.listConfigProfiles = listConfigProfiles;
|
|
|
40
40
|
exports.ensureProfileExists = ensureProfileExists;
|
|
41
41
|
exports.requireManagedProfileRuntime = requireManagedProfileRuntime;
|
|
42
42
|
exports.requireModelProviderRuntimeSection = requireModelProviderRuntimeSection;
|
|
43
|
-
exports.requireRuntimeEnvKey = requireRuntimeEnvKey;
|
|
44
43
|
exports.resolveActiveProviderName = resolveActiveProviderName;
|
|
45
44
|
exports.updateTopLevelProfile = updateTopLevelProfile;
|
|
46
45
|
exports.createConfigMutationPlan = createConfigMutationPlan;
|
|
@@ -143,13 +142,6 @@ function requireManagedProfileRuntime(document, providers, profile) {
|
|
|
143
142
|
missingFields: ["base_url"],
|
|
144
143
|
});
|
|
145
144
|
}
|
|
146
|
-
if (!modelProviderSection.envKey) {
|
|
147
|
-
throw (0, errors_1.cliError)("MODEL_PROVIDER_ENV_KEY_MISSING", `Model provider "${view.modelProvider}" requires env_key.`, {
|
|
148
|
-
profile,
|
|
149
|
-
modelProvider: view.modelProvider,
|
|
150
|
-
missingFields: ["env_key"],
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
145
|
return view;
|
|
154
146
|
}
|
|
155
147
|
/**
|
|
@@ -170,33 +162,6 @@ function requireModelProviderRuntimeSection(document, profile) {
|
|
|
170
162
|
missingFields: ["base_url"],
|
|
171
163
|
});
|
|
172
164
|
}
|
|
173
|
-
if (!modelProviderSection.envKey) {
|
|
174
|
-
throw (0, errors_1.cliError)("MODEL_PROVIDER_ENV_KEY_MISSING", `Model provider "${profile}" requires env_key.`, {
|
|
175
|
-
profile,
|
|
176
|
-
modelProvider: profile,
|
|
177
|
-
missingFields: ["env_key"],
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Returns the runtime env_key for one profile or throws a typed error.
|
|
183
|
-
*/
|
|
184
|
-
function requireRuntimeEnvKey(document, profile) {
|
|
185
|
-
const modelProviderSection = document.modelProviders.find((entry) => entry.name === profile);
|
|
186
|
-
if (!modelProviderSection) {
|
|
187
|
-
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Model provider "${profile}" does not exist in config.toml.`, {
|
|
188
|
-
profile,
|
|
189
|
-
modelProvider: profile,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
if (!modelProviderSection.envKey) {
|
|
193
|
-
throw (0, errors_1.cliError)("MODEL_PROVIDER_ENV_KEY_MISSING", `Model provider "${profile}" requires env_key.`, {
|
|
194
|
-
profile,
|
|
195
|
-
modelProvider: profile,
|
|
196
|
-
missingFields: ["env_key"],
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
return modelProviderSection.envKey;
|
|
200
165
|
}
|
|
201
166
|
/**
|
|
202
167
|
* Resolves the current active provider and requires the mapping to be unique.
|
|
@@ -212,7 +177,7 @@ function resolveActiveProviderName(document, providers) {
|
|
|
212
177
|
});
|
|
213
178
|
}
|
|
214
179
|
if (matches.length > 1) {
|
|
215
|
-
throw (0, errors_1.cliError)("ACTIVE_PROVIDER_UNRESOLVED", `Active profile "${document.activeProfile}" maps to multiple providers.`, {
|
|
180
|
+
throw (0, errors_1.cliError)("ACTIVE_PROVIDER_UNRESOLVED", `Active profile "${document.activeProfile}" maps to multiple providers, so the active managed provider is ambiguous.`, {
|
|
216
181
|
profile: document.activeProfile,
|
|
217
182
|
providers: matches,
|
|
218
183
|
});
|
|
@@ -35,11 +35,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getCopilotBridgeStatePath = getCopilotBridgeStatePath;
|
|
37
37
|
exports.readCopilotBridgeState = readCopilotBridgeState;
|
|
38
|
+
exports.inspectCopilotBridgeState = inspectCopilotBridgeState;
|
|
38
39
|
exports.writeCopilotBridgeState = writeCopilotBridgeState;
|
|
39
40
|
exports.clearCopilotBridgeState = clearCopilotBridgeState;
|
|
40
41
|
const fs = __importStar(require("node:fs"));
|
|
41
42
|
const os = __importStar(require("node:os"));
|
|
42
43
|
const path = __importStar(require("node:path"));
|
|
44
|
+
const errors_1 = require("../domain/errors");
|
|
43
45
|
const fs_utils_1 = require("./fs-utils");
|
|
44
46
|
/**
|
|
45
47
|
* Returns the user-level runtime state file used by Copilot bridge helpers.
|
|
@@ -61,6 +63,36 @@ function readCopilotBridgeState() {
|
|
|
61
63
|
}
|
|
62
64
|
return JSON.parse(fs.readFileSync(statePath, "utf8"));
|
|
63
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Safely inspects the runtime-state file for status/doctor style read paths.
|
|
68
|
+
*/
|
|
69
|
+
function inspectCopilotBridgeState() {
|
|
70
|
+
const statePath = getCopilotBridgeStatePath();
|
|
71
|
+
if (!fs.existsSync(statePath)) {
|
|
72
|
+
return {
|
|
73
|
+
exists: false,
|
|
74
|
+
valid: false,
|
|
75
|
+
parseError: null,
|
|
76
|
+
state: null,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return {
|
|
81
|
+
exists: true,
|
|
82
|
+
valid: true,
|
|
83
|
+
parseError: null,
|
|
84
|
+
state: readCopilotBridgeState(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
exists: true,
|
|
90
|
+
valid: false,
|
|
91
|
+
parseError: (0, errors_1.normalizeError)(error).message,
|
|
92
|
+
state: null,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
64
96
|
/**
|
|
65
97
|
* Persists the Copilot bridge state manifest.
|
|
66
98
|
*/
|