@minniexcode/codex-switch 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.AI.md +68 -73
- package/README.CN.md +108 -111
- package/README.md +87 -80
- package/dist/app/add-provider.js +29 -15
- package/dist/app/bridge.js +15 -14
- package/dist/app/edit-provider.js +1 -1
- package/dist/app/get-status.js +21 -9
- package/dist/app/import-providers.js +1 -1
- package/dist/app/init-codex.js +13 -14
- package/dist/app/list-providers.js +48 -1
- package/dist/app/remove-provider.js +1 -1
- package/dist/app/run-doctor.js +12 -5
- package/dist/app/run-mutation.js +3 -2
- package/dist/app/setup-codex.js +3 -1
- package/dist/app/switch-provider.js +11 -13
- package/dist/cli/output.js +145 -18
- package/dist/cli.js +34 -2
- package/dist/commands/args.js +2 -2
- package/dist/commands/dispatch.js +40 -0
- package/dist/commands/handlers.js +130 -161
- package/dist/commands/help.js +11 -5
- package/dist/commands/registry.js +42 -20
- package/dist/domain/backups.js +4 -4
- package/dist/domain/config.js +110 -5
- package/dist/domain/providers.js +12 -0
- package/dist/domain/runtime-state.js +111 -13
- package/dist/infra/config-repo.js +16 -206
- package/dist/interaction/interactive.js +16 -6
- package/dist/runtime/copilot-adapter.js +12 -12
- package/dist/runtime/copilot-bridge.js +394 -45
- package/dist/runtime/copilot-cli.js +84 -12
- package/dist/runtime/copilot-installer.js +10 -9
- package/dist/runtime/copilot-sdk-loader.js +5 -5
- package/dist/storage/backup-repo.js +4 -4
- package/dist/storage/codex-paths.js +34 -8
- package/dist/storage/config-repo.js +0 -23
- package/dist/storage/lock-repo.js +2 -4
- package/dist/storage/runtime-state-repo.js +14 -13
- package/dist/storage/tool-config-repo.js +111 -0
- package/docs/Design/codex-switch-v0.0.11-design.md +824 -0
- package/docs/Design/codex-switch-v0.0.12-design.md +343 -0
- package/docs/PRD/codex-switch-prd-v0.0.11.md +577 -0
- package/docs/PRD/codex-switch-prd-v0.0.12.md +279 -0
- package/docs/PRD/codex-switch-prd-v0.1.0.md +125 -237
- package/docs/Tests/testing.md +39 -112
- package/docs/cli-usage.md +135 -565
- package/docs/codex-switch-command-design.md +3 -0
- package/docs/codex-switch-product-overview.md +52 -207
- package/docs/codex-switch-technical-architecture.md +3 -0
- package/package.json +1 -1
- package/dist/app/rollback-latest.js +0 -26
package/dist/domain/config.js
CHANGED
|
@@ -117,8 +117,15 @@ function parseStructuredConfig(configContent) {
|
|
|
117
117
|
name: modelProviderHeaderMatch[1],
|
|
118
118
|
sectionStart: line.start,
|
|
119
119
|
sectionEnd: configContent.length,
|
|
120
|
+
managedFieldInsertIndex: configContent.length,
|
|
120
121
|
baseUrlValueRange: null,
|
|
121
122
|
baseUrl: null,
|
|
123
|
+
nameValueRange: null,
|
|
124
|
+
providerName: null,
|
|
125
|
+
requiresOpenAiAuthValueRange: null,
|
|
126
|
+
requiresOpenAiAuth: null,
|
|
127
|
+
wireApiValueRange: null,
|
|
128
|
+
wireApi: null,
|
|
122
129
|
};
|
|
123
130
|
modelProviders.push(currentModelProvider);
|
|
124
131
|
inRoot = false;
|
|
@@ -173,6 +180,30 @@ function parseStructuredConfig(configContent) {
|
|
|
173
180
|
end: line.start + baseUrlMatch.valueEnd,
|
|
174
181
|
};
|
|
175
182
|
}
|
|
183
|
+
const nameMatch = matchKeyValueLine(line.content, "name");
|
|
184
|
+
if (nameMatch) {
|
|
185
|
+
currentModelProvider.providerName = nameMatch.value;
|
|
186
|
+
currentModelProvider.nameValueRange = {
|
|
187
|
+
start: line.start + nameMatch.valueStart,
|
|
188
|
+
end: line.start + nameMatch.valueEnd,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const requiresOpenAiAuthMatch = matchBooleanKeyValueLine(line.content, "requires_openai_auth");
|
|
192
|
+
if (requiresOpenAiAuthMatch) {
|
|
193
|
+
currentModelProvider.requiresOpenAiAuth = requiresOpenAiAuthMatch.value;
|
|
194
|
+
currentModelProvider.requiresOpenAiAuthValueRange = {
|
|
195
|
+
start: line.start + requiresOpenAiAuthMatch.valueStart,
|
|
196
|
+
end: line.start + requiresOpenAiAuthMatch.valueEnd,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const wireApiMatch = matchKeyValueLine(line.content, "wire_api");
|
|
200
|
+
if (wireApiMatch) {
|
|
201
|
+
currentModelProvider.wireApi = wireApiMatch.value;
|
|
202
|
+
currentModelProvider.wireApiValueRange = {
|
|
203
|
+
start: line.start + wireApiMatch.valueStart,
|
|
204
|
+
end: line.start + wireApiMatch.valueEnd,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
176
207
|
}
|
|
177
208
|
}
|
|
178
209
|
return {
|
|
@@ -184,7 +215,10 @@ function parseStructuredConfig(configContent) {
|
|
|
184
215
|
...profile,
|
|
185
216
|
managedFieldInsertIndex: findManagedFieldInsertIndex(configContent, profile.sectionStart, profile.sectionEnd),
|
|
186
217
|
})),
|
|
187
|
-
modelProviders
|
|
218
|
+
modelProviders: modelProviders.map((provider) => ({
|
|
219
|
+
...provider,
|
|
220
|
+
managedFieldInsertIndex: findManagedFieldInsertIndex(configContent, provider.sectionStart, provider.sectionEnd),
|
|
221
|
+
})),
|
|
188
222
|
};
|
|
189
223
|
}
|
|
190
224
|
/**
|
|
@@ -445,6 +479,7 @@ function planConfigMutation(document, args) {
|
|
|
445
479
|
const section = modelProviderSectionMap.get(profileName);
|
|
446
480
|
if (!section) {
|
|
447
481
|
const baseUrl = fields.baseUrl?.trim() ?? "";
|
|
482
|
+
const providerName = fields.name?.trim() ?? "";
|
|
448
483
|
if (!baseUrl) {
|
|
449
484
|
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Model provider "${profileName}" requires base_url.`, {
|
|
450
485
|
profile: profileName,
|
|
@@ -457,11 +492,16 @@ function planConfigMutation(document, args) {
|
|
|
457
492
|
const prefix = document.rawText.length > 0 && !document.rawText.endsWith(document.lineEnding)
|
|
458
493
|
? document.lineEnding
|
|
459
494
|
: "";
|
|
495
|
+
const requiresOpenAiAuth = fields.requiresOpenAiAuth;
|
|
496
|
+
const wireApi = fields.wireApi?.trim() ?? "";
|
|
460
497
|
operations.push({
|
|
461
498
|
kind: "insert-at",
|
|
462
499
|
index: document.rawText.length,
|
|
463
500
|
text: `${prefix}[model_providers.${profileName}]${document.lineEnding}` +
|
|
464
|
-
`base_url = ${JSON.stringify(baseUrl)}${document.lineEnding}
|
|
501
|
+
`base_url = ${JSON.stringify(baseUrl)}${document.lineEnding}` +
|
|
502
|
+
(providerName ? `name = ${JSON.stringify(providerName)}${document.lineEnding}` : "") +
|
|
503
|
+
(requiresOpenAiAuth !== undefined ? `requires_openai_auth = ${String(requiresOpenAiAuth)}${document.lineEnding}` : "") +
|
|
504
|
+
(wireApi ? `wire_api = ${JSON.stringify(wireApi)}${document.lineEnding}` : ""),
|
|
465
505
|
});
|
|
466
506
|
createdModelProviderSections.push(profileName);
|
|
467
507
|
continue;
|
|
@@ -545,11 +585,14 @@ function planSectionFieldMutation(document, section, fields, operations) {
|
|
|
545
585
|
return updated;
|
|
546
586
|
}
|
|
547
587
|
/**
|
|
548
|
-
* Plans
|
|
588
|
+
* Plans managed field updates for one model_providers section.
|
|
549
589
|
*/
|
|
550
590
|
function planModelProviderFieldMutation(section, fields, operations) {
|
|
551
591
|
let updated = false;
|
|
552
592
|
const baseUrlText = fields.baseUrl !== undefined ? JSON.stringify(fields.baseUrl) : null;
|
|
593
|
+
const nameText = fields.name !== undefined ? JSON.stringify(fields.name) : null;
|
|
594
|
+
const requiresOpenAiAuthText = fields.requiresOpenAiAuth !== undefined ? String(fields.requiresOpenAiAuth) : null;
|
|
595
|
+
const wireApiText = fields.wireApi !== undefined ? JSON.stringify(fields.wireApi) : null;
|
|
553
596
|
const inserts = [];
|
|
554
597
|
if (baseUrlText !== null && section.baseUrlValueRange) {
|
|
555
598
|
if (section.baseUrl !== fields.baseUrl) {
|
|
@@ -564,14 +607,59 @@ function planModelProviderFieldMutation(section, fields, operations) {
|
|
|
564
607
|
}
|
|
565
608
|
else if (baseUrlText !== null) {
|
|
566
609
|
inserts.push(`base_url = ${baseUrlText}`);
|
|
610
|
+
updated = true;
|
|
611
|
+
}
|
|
612
|
+
if (nameText !== null && section.nameValueRange) {
|
|
613
|
+
if (section.providerName !== fields.name) {
|
|
614
|
+
operations.push({
|
|
615
|
+
kind: "replace-range",
|
|
616
|
+
start: section.nameValueRange.start,
|
|
617
|
+
end: section.nameValueRange.end,
|
|
618
|
+
text: nameText,
|
|
619
|
+
});
|
|
620
|
+
updated = true;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
else if (nameText !== null) {
|
|
624
|
+
inserts.push(`name = ${nameText}`);
|
|
625
|
+
updated = true;
|
|
626
|
+
}
|
|
627
|
+
if (requiresOpenAiAuthText !== null && section.requiresOpenAiAuthValueRange) {
|
|
628
|
+
if (section.requiresOpenAiAuth !== fields.requiresOpenAiAuth) {
|
|
629
|
+
operations.push({
|
|
630
|
+
kind: "replace-range",
|
|
631
|
+
start: section.requiresOpenAiAuthValueRange.start,
|
|
632
|
+
end: section.requiresOpenAiAuthValueRange.end,
|
|
633
|
+
text: requiresOpenAiAuthText,
|
|
634
|
+
});
|
|
635
|
+
updated = true;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else if (requiresOpenAiAuthText !== null) {
|
|
639
|
+
inserts.push(`requires_openai_auth = ${requiresOpenAiAuthText}`);
|
|
640
|
+
updated = true;
|
|
641
|
+
}
|
|
642
|
+
if (wireApiText !== null && section.wireApiValueRange) {
|
|
643
|
+
if (section.wireApi !== fields.wireApi) {
|
|
644
|
+
operations.push({
|
|
645
|
+
kind: "replace-range",
|
|
646
|
+
start: section.wireApiValueRange.start,
|
|
647
|
+
end: section.wireApiValueRange.end,
|
|
648
|
+
text: wireApiText,
|
|
649
|
+
});
|
|
650
|
+
updated = true;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else if (wireApiText !== null) {
|
|
654
|
+
inserts.push(`wire_api = ${wireApiText}`);
|
|
655
|
+
updated = true;
|
|
567
656
|
}
|
|
568
657
|
if (inserts.length > 0) {
|
|
569
658
|
operations.push({
|
|
570
659
|
kind: "insert-at",
|
|
571
|
-
index: section.
|
|
660
|
+
index: section.managedFieldInsertIndex,
|
|
572
661
|
text: `${inserts.join("\n")}\n`,
|
|
573
662
|
});
|
|
574
|
-
updated = true;
|
|
575
663
|
}
|
|
576
664
|
return updated;
|
|
577
665
|
}
|
|
@@ -616,6 +704,23 @@ function matchKeyValueLine(line, key) {
|
|
|
616
704
|
valueEnd,
|
|
617
705
|
};
|
|
618
706
|
}
|
|
707
|
+
function matchBooleanKeyValueLine(line, key) {
|
|
708
|
+
const match = line.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*(true|false)\\s*(#.*)?$`));
|
|
709
|
+
if (!match || match.index === undefined) {
|
|
710
|
+
return null;
|
|
711
|
+
}
|
|
712
|
+
const value = match[1] === "true";
|
|
713
|
+
const valueStart = line.indexOf(match[1], match.index);
|
|
714
|
+
if (valueStart === -1) {
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
const valueEnd = valueStart + match[1].length;
|
|
718
|
+
return {
|
|
719
|
+
value,
|
|
720
|
+
valueStart,
|
|
721
|
+
valueEnd,
|
|
722
|
+
};
|
|
723
|
+
}
|
|
619
724
|
function findManagedFieldInsertIndex(rawText, sectionStart, sectionEnd) {
|
|
620
725
|
const sectionText = rawText.slice(sectionStart, sectionEnd);
|
|
621
726
|
const lines = splitWithOffsets(sectionText);
|
package/dist/domain/providers.js
CHANGED
|
@@ -9,6 +9,7 @@ exports.maskSecret = maskSecret;
|
|
|
9
9
|
exports.isRuntimeBackedProvider = isRuntimeBackedProvider;
|
|
10
10
|
exports.isCopilotBridgeProvider = isCopilotBridgeProvider;
|
|
11
11
|
exports.buildCopilotBridgeBaseUrl = buildCopilotBridgeBaseUrl;
|
|
12
|
+
exports.buildCopilotModelProviderProjection = buildCopilotModelProviderProjection;
|
|
12
13
|
/**
|
|
13
14
|
* Validates and normalizes unknown JSON into the providers.json domain model.
|
|
14
15
|
*/
|
|
@@ -150,6 +151,17 @@ function isCopilotBridgeProvider(provider) {
|
|
|
150
151
|
function buildCopilotBridgeBaseUrl(runtime) {
|
|
151
152
|
return `http://${runtime.bridgeHost}:${runtime.bridgePort}${runtime.bridgePath}`;
|
|
152
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Builds the Codex-facing custom model_provider projection for the managed Copilot bridge.
|
|
156
|
+
*/
|
|
157
|
+
function buildCopilotModelProviderProjection(runtime) {
|
|
158
|
+
return {
|
|
159
|
+
baseUrl: buildCopilotBridgeBaseUrl(runtime),
|
|
160
|
+
name: "copilot",
|
|
161
|
+
requiresOpenAiAuth: true,
|
|
162
|
+
wireApi: "responses",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
153
165
|
/**
|
|
154
166
|
* Validates one runtime-backed provider block.
|
|
155
167
|
*/
|
|
@@ -1,16 +1,92 @@
|
|
|
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.getStorageRoles = getStorageRoles;
|
|
4
37
|
exports.inspectLiveStateDrift = inspectLiveStateDrift;
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
5
39
|
/**
|
|
6
40
|
* Returns the stable storage contract used by the CLI.
|
|
7
41
|
*/
|
|
8
|
-
function getStorageRoles() {
|
|
42
|
+
function getStorageRoles(args) {
|
|
43
|
+
const toolHomeDir = path.dirname(path.resolve(args.providersPath));
|
|
44
|
+
const backupsDir = path.join(toolHomeDir, "backups");
|
|
45
|
+
const runtimeDir = args.runtimeDir ? path.resolve(args.runtimeDir) : path.join(toolHomeDir, "runtime");
|
|
46
|
+
const runtimesDir = args.runtimesDir ? path.resolve(args.runtimesDir) : path.join(toolHomeDir, "runtimes");
|
|
9
47
|
return {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
48
|
+
toolHome: {
|
|
49
|
+
root: toolHomeDir,
|
|
50
|
+
toolConfig: path.join(toolHomeDir, "codex-switch.json"),
|
|
51
|
+
providers: path.resolve(args.providersPath),
|
|
52
|
+
backupsDir,
|
|
53
|
+
latestBackup: path.join(backupsDir, "latest.json"),
|
|
54
|
+
runtimeStateDir: runtimeDir,
|
|
55
|
+
runtimeInstallDir: runtimesDir,
|
|
56
|
+
},
|
|
57
|
+
targetRuntime: {
|
|
58
|
+
root: path.resolve(args.codexDir),
|
|
59
|
+
config: path.resolve(args.configPath),
|
|
60
|
+
auth: path.resolve(args.authPath),
|
|
61
|
+
},
|
|
62
|
+
managementSSOT: {
|
|
63
|
+
scope: "toolHome",
|
|
64
|
+
path: path.resolve(args.providersPath),
|
|
65
|
+
},
|
|
66
|
+
runtimeMirrors: [
|
|
67
|
+
{
|
|
68
|
+
scope: "targetRuntime",
|
|
69
|
+
path: path.resolve(args.configPath),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
authStateFile: {
|
|
73
|
+
scope: "targetRuntime",
|
|
74
|
+
path: path.resolve(args.authPath),
|
|
75
|
+
},
|
|
76
|
+
rollbackState: {
|
|
77
|
+
scope: "toolHome",
|
|
78
|
+
path: path.join(backupsDir, "latest.json"),
|
|
79
|
+
},
|
|
80
|
+
runtimeState: {
|
|
81
|
+
scope: "toolHome",
|
|
82
|
+
path: runtimeDir,
|
|
83
|
+
managedBackup: false,
|
|
84
|
+
},
|
|
85
|
+
runtimeInstall: {
|
|
86
|
+
scope: "toolHome",
|
|
87
|
+
path: runtimesDir,
|
|
88
|
+
managedBackup: false,
|
|
89
|
+
},
|
|
14
90
|
};
|
|
15
91
|
}
|
|
16
92
|
/**
|
|
@@ -21,7 +97,9 @@ function inspectLiveStateDrift(currentProfile, providers) {
|
|
|
21
97
|
return {
|
|
22
98
|
currentProfile,
|
|
23
99
|
mappedProvider: null,
|
|
100
|
+
mappedProviders: [],
|
|
24
101
|
profileMapped: false,
|
|
102
|
+
providerResolvable: false,
|
|
25
103
|
canBackfillActiveProvider: false,
|
|
26
104
|
reason: providers ? "profile-missing" : "config-missing",
|
|
27
105
|
};
|
|
@@ -30,27 +108,47 @@ function inspectLiveStateDrift(currentProfile, providers) {
|
|
|
30
108
|
return {
|
|
31
109
|
currentProfile,
|
|
32
110
|
mappedProvider: null,
|
|
111
|
+
mappedProviders: [],
|
|
33
112
|
profileMapped: false,
|
|
113
|
+
providerResolvable: false,
|
|
34
114
|
canBackfillActiveProvider: false,
|
|
35
115
|
reason: "providers-missing",
|
|
36
116
|
};
|
|
37
117
|
}
|
|
118
|
+
const mappedProviders = [];
|
|
38
119
|
for (const [name, provider] of Object.entries(providers.providers)) {
|
|
39
|
-
// A direct profile match means the runtime state is still managed.
|
|
40
120
|
if (provider.profile === currentProfile) {
|
|
41
|
-
|
|
42
|
-
currentProfile,
|
|
43
|
-
mappedProvider: name,
|
|
44
|
-
profileMapped: true,
|
|
45
|
-
canBackfillActiveProvider: false,
|
|
46
|
-
reason: "ok",
|
|
47
|
-
};
|
|
121
|
+
mappedProviders.push(name);
|
|
48
122
|
}
|
|
49
123
|
}
|
|
124
|
+
if (mappedProviders.length === 1) {
|
|
125
|
+
return {
|
|
126
|
+
currentProfile,
|
|
127
|
+
mappedProvider: mappedProviders[0],
|
|
128
|
+
mappedProviders,
|
|
129
|
+
profileMapped: true,
|
|
130
|
+
providerResolvable: true,
|
|
131
|
+
canBackfillActiveProvider: false,
|
|
132
|
+
reason: "ok",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (mappedProviders.length > 1) {
|
|
136
|
+
return {
|
|
137
|
+
currentProfile,
|
|
138
|
+
mappedProvider: null,
|
|
139
|
+
mappedProviders,
|
|
140
|
+
profileMapped: true,
|
|
141
|
+
providerResolvable: false,
|
|
142
|
+
canBackfillActiveProvider: false,
|
|
143
|
+
reason: "shared-profile",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
50
146
|
return {
|
|
51
147
|
currentProfile,
|
|
52
148
|
mappedProvider: null,
|
|
149
|
+
mappedProviders: [],
|
|
53
150
|
profileMapped: false,
|
|
151
|
+
providerResolvable: false,
|
|
54
152
|
canBackfillActiveProvider: true,
|
|
55
153
|
reason: "provider-unmapped",
|
|
56
154
|
};
|
|
@@ -1,208 +1,18 @@
|
|
|
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
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.readConfigFile =
|
|
37
|
-
|
|
38
|
-
exports
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
exports.
|
|
42
|
-
exports.
|
|
43
|
-
exports.
|
|
44
|
-
exports.
|
|
45
|
-
exports.
|
|
46
|
-
exports.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const codex_paths_1 = require("./codex-paths");
|
|
53
|
-
const fs_utils_1 = require("./fs-utils");
|
|
54
|
-
/**
|
|
55
|
-
* Reads config.toml and throws a typed error when the file is missing.
|
|
56
|
-
*/
|
|
57
|
-
function readConfigFile(configPath) {
|
|
58
|
-
return (0, fs_utils_1.readRequiredFile)(configPath, "CONFIG_NOT_FOUND", "config.toml");
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Reads and parses config.toml into the managed structured document shape.
|
|
62
|
-
*/
|
|
63
|
-
function readStructuredConfig(configPath) {
|
|
64
|
-
const content = readConfigFile(configPath);
|
|
65
|
-
try {
|
|
66
|
-
return (0, config_1.parseStructuredConfig)(content);
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
throw (0, errors_1.cliError)("CONFIG_PARSE_ERROR", "Failed to parse config.toml.", {
|
|
70
|
-
file: configPath,
|
|
71
|
-
cause: (0, errors_1.normalizeError)(error).message,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Reads the active top-level profile from config.toml.
|
|
77
|
-
*/
|
|
78
|
-
function readCurrentProfile(configPath) {
|
|
79
|
-
const profile = readStructuredConfig(configPath).activeProfile ?? (0, config_1.parseTopLevelProfile)(readConfigFile(configPath));
|
|
80
|
-
if (!profile) {
|
|
81
|
-
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", "No top-level profile is set in config.toml.", {
|
|
82
|
-
file: configPath,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
return profile;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Lists all named profile sections declared in config.toml.
|
|
89
|
-
*/
|
|
90
|
-
function listConfigProfiles(configPath) {
|
|
91
|
-
return new Set(readStructuredConfig(configPath).profiles.map((profile) => profile.name));
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Verifies that a provider's target profile exists before a switch operation proceeds.
|
|
95
|
-
*/
|
|
96
|
-
function ensureProfileExists(configPath, profile, provider) {
|
|
97
|
-
const document = readStructuredConfig(configPath);
|
|
98
|
-
if (!document.profiles.some((entry) => entry.name === profile)) {
|
|
99
|
-
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Profile "${profile}" does not exist in config.toml.`, {
|
|
100
|
-
file: configPath,
|
|
101
|
-
provider,
|
|
102
|
-
profile,
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
return document;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Resolves one profile view and enforces the managed model_provider contract.
|
|
109
|
-
*/
|
|
110
|
-
function requireManagedProfileRuntime(document, providers, profile) {
|
|
111
|
-
const view = (0, config_1.buildManagedProfileViews)(document, providers).find((entry) => entry.name === profile);
|
|
112
|
-
if (!view) {
|
|
113
|
-
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Profile "${profile}" does not exist in config.toml.`, {
|
|
114
|
-
profile,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
if (!view.modelProvider) {
|
|
118
|
-
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Managed profile "${profile}" requires model_provider.`, {
|
|
119
|
-
profile,
|
|
120
|
-
missingFields: ["model_provider"],
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
if (view.modelProvider !== profile) {
|
|
124
|
-
throw (0, errors_1.cliError)("INVALID_ARGUMENT", `Managed profile "${profile}" must use the same model_provider name.`, {
|
|
125
|
-
profile,
|
|
126
|
-
modelProvider: view.modelProvider,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
const modelProviderSection = document.modelProviders.find((entry) => entry.name === view.modelProvider);
|
|
130
|
-
if (!modelProviderSection) {
|
|
131
|
-
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Model provider "${view.modelProvider}" does not exist in config.toml.`, {
|
|
132
|
-
profile,
|
|
133
|
-
modelProvider: view.modelProvider,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
if (!modelProviderSection.baseUrl) {
|
|
137
|
-
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Model provider "${view.modelProvider}" requires base_url.`, {
|
|
138
|
-
profile,
|
|
139
|
-
modelProvider: view.modelProvider,
|
|
140
|
-
missingFields: ["base_url"],
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
return view;
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Verifies that a same-named model_provider runtime section exists and has base_url.
|
|
147
|
-
*/
|
|
148
|
-
function requireModelProviderRuntimeSection(document, profile) {
|
|
149
|
-
const modelProviderSection = document.modelProviders.find((entry) => entry.name === profile);
|
|
150
|
-
if (!modelProviderSection) {
|
|
151
|
-
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Model provider "${profile}" does not exist in config.toml.`, {
|
|
152
|
-
profile,
|
|
153
|
-
modelProvider: profile,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
if (!modelProviderSection.baseUrl) {
|
|
157
|
-
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Model provider "${profile}" requires base_url.`, {
|
|
158
|
-
profile,
|
|
159
|
-
modelProvider: profile,
|
|
160
|
-
missingFields: ["base_url"],
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Rewrites config.toml so the requested profile becomes the active top-level profile.
|
|
166
|
-
*/
|
|
167
|
-
function updateTopLevelProfile(configPath, configContent, profile) {
|
|
168
|
-
(0, fs_utils_1.writeTextFileAtomic)(configPath, (0, config_1.applyPatchOperations)(configContent, (0, config_1.planConfigMutation)((0, config_1.parseStructuredConfig)(configContent), {
|
|
169
|
-
setActiveProfile: profile,
|
|
170
|
-
}).operations));
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Exposes the config mutation planner to application services.
|
|
174
|
-
*/
|
|
175
|
-
function createConfigMutationPlan(document, args) {
|
|
176
|
-
return (0, config_1.planConfigMutation)(document, args);
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Applies a previously generated mutation plan to config.toml in one write.
|
|
180
|
-
*/
|
|
181
|
-
function applyConfigMutation(configPath, document, plan) {
|
|
182
|
-
(0, fs_utils_1.writeTextFileAtomic)(configPath, (0, config_1.applyPatchOperations)(document.rawText, plan.operations));
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Finds candidate Codex directories in a stable, non-recursive order.
|
|
186
|
-
*/
|
|
187
|
-
function findCodexDirCandidates(explicitCodexDir) {
|
|
188
|
-
if (explicitCodexDir) {
|
|
189
|
-
return [(0, codex_paths_1.resolveCodexDir)(explicitCodexDir)];
|
|
190
|
-
}
|
|
191
|
-
const candidates = new Set();
|
|
192
|
-
const ordered = [];
|
|
193
|
-
const envCandidate = process.env[codex_paths_1.CODEX_DIR_ENV_NAME];
|
|
194
|
-
if (envCandidate) {
|
|
195
|
-
ordered.push((0, codex_paths_1.resolveCodexDir)(envCandidate));
|
|
196
|
-
}
|
|
197
|
-
if (process.env.NODE_ENV === "development") {
|
|
198
|
-
ordered.push(path.resolve(process.cwd(), "dev-codex", "local-sandbox"));
|
|
199
|
-
}
|
|
200
|
-
ordered.push(path.join(os.homedir(), ".codex"));
|
|
201
|
-
for (const candidate of ordered) {
|
|
202
|
-
if (!candidate || candidates.has(candidate) || !fs.existsSync(candidate)) {
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
candidates.add(candidate);
|
|
206
|
-
}
|
|
207
|
-
return [...candidates];
|
|
208
|
-
}
|
|
3
|
+
exports.updateTopLevelProfile = exports.requireModelProviderRuntimeSection = exports.requireManagedProfileRuntime = exports.readStructuredConfig = exports.readCurrentProfile = exports.readConfigFile = exports.listConfigProfiles = exports.findCodexDirCandidates = exports.ensureProfileExists = exports.createConfigMutationPlan = exports.applyConfigMutation = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Compatibility facade that re-exports config repository helpers from storage.
|
|
6
|
+
*/
|
|
7
|
+
var config_repo_1 = require("../storage/config-repo");
|
|
8
|
+
Object.defineProperty(exports, "applyConfigMutation", { enumerable: true, get: function () { return config_repo_1.applyConfigMutation; } });
|
|
9
|
+
Object.defineProperty(exports, "createConfigMutationPlan", { enumerable: true, get: function () { return config_repo_1.createConfigMutationPlan; } });
|
|
10
|
+
Object.defineProperty(exports, "ensureProfileExists", { enumerable: true, get: function () { return config_repo_1.ensureProfileExists; } });
|
|
11
|
+
Object.defineProperty(exports, "findCodexDirCandidates", { enumerable: true, get: function () { return config_repo_1.findCodexDirCandidates; } });
|
|
12
|
+
Object.defineProperty(exports, "listConfigProfiles", { enumerable: true, get: function () { return config_repo_1.listConfigProfiles; } });
|
|
13
|
+
Object.defineProperty(exports, "readConfigFile", { enumerable: true, get: function () { return config_repo_1.readConfigFile; } });
|
|
14
|
+
Object.defineProperty(exports, "readCurrentProfile", { enumerable: true, get: function () { return config_repo_1.readCurrentProfile; } });
|
|
15
|
+
Object.defineProperty(exports, "readStructuredConfig", { enumerable: true, get: function () { return config_repo_1.readStructuredConfig; } });
|
|
16
|
+
Object.defineProperty(exports, "requireManagedProfileRuntime", { enumerable: true, get: function () { return config_repo_1.requireManagedProfileRuntime; } });
|
|
17
|
+
Object.defineProperty(exports, "requireModelProviderRuntimeSection", { enumerable: true, get: function () { return config_repo_1.requireModelProviderRuntimeSection; } });
|
|
18
|
+
Object.defineProperty(exports, "updateTopLevelProfile", { enumerable: true, get: function () { return config_repo_1.updateTopLevelProfile; } });
|
|
@@ -52,7 +52,10 @@ const fs = __importStar(require("node:fs"));
|
|
|
52
52
|
const path = __importStar(require("node:path"));
|
|
53
53
|
const errors_1 = require("../domain/errors");
|
|
54
54
|
const backups_1 = require("../domain/backups");
|
|
55
|
+
const providers_1 = require("../domain/providers");
|
|
56
|
+
const runtime_state_1 = require("../domain/runtime-state");
|
|
55
57
|
const codex_paths_1 = require("../storage/codex-paths");
|
|
58
|
+
const config_repo_1 = require("../storage/config-repo");
|
|
56
59
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
57
60
|
const backup_repo_1 = require("../storage/backup-repo");
|
|
58
61
|
const add_interactive_1 = require("./add-interactive");
|
|
@@ -65,15 +68,22 @@ function canPrompt(runtime, jsonMode) {
|
|
|
65
68
|
/**
|
|
66
69
|
* Prompts the user to choose one configured provider when a command omitted its target.
|
|
67
70
|
*/
|
|
68
|
-
async function promptForProviderSelection(runtime, providersPath, message) {
|
|
71
|
+
async function promptForProviderSelection(runtime, providersPath, configPath, message) {
|
|
69
72
|
const providers = (0, providers_repo_1.readProvidersFile)(providersPath);
|
|
73
|
+
const currentProfile = fs.existsSync(configPath) ? (0, config_repo_1.readStructuredConfig)(configPath).activeProfile : null;
|
|
74
|
+
const liveState = (0, runtime_state_1.inspectLiveStateDrift)(currentProfile, providers);
|
|
70
75
|
const choices = Object.entries(providers.providers)
|
|
71
76
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
72
|
-
.map(([providerName, provider]) =>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
.map(([providerName, provider]) => {
|
|
78
|
+
const providerType = (0, providers_1.isCopilotBridgeProvider)(provider) ? "copilot" : "direct";
|
|
79
|
+
const currentMarker = liveState.providerResolvable && liveState.mappedProvider === providerName ? " | current" : "";
|
|
80
|
+
const ambiguousMarker = !liveState.providerResolvable && liveState.mappedProviders.includes(providerName) ? " | current=ambiguous" : "";
|
|
81
|
+
return {
|
|
82
|
+
value: providerName,
|
|
83
|
+
label: providerName,
|
|
84
|
+
hint: `profile=${provider.profile} | type=${providerType}${currentMarker}${ambiguousMarker}`,
|
|
85
|
+
};
|
|
86
|
+
});
|
|
77
87
|
if (choices.length === 0) {
|
|
78
88
|
throw (0, errors_1.cliError)("PROVIDER_NOT_FOUND", "No providers are configured.");
|
|
79
89
|
}
|