@minniexcode/codex-switch 0.0.9 → 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 +0 -11
- package/dist/app/bridge.js +0 -1
- package/dist/app/edit-provider.js +1 -17
- package/dist/app/get-status.js +24 -9
- package/dist/app/list-providers.js +0 -1
- package/dist/app/run-doctor.js +11 -36
- package/dist/app/setup-codex.js +27 -17
- package/dist/app/show-config.js +1 -5
- package/dist/app/switch-provider.js +5 -20
- package/dist/cli/output.js +4 -6
- package/dist/cli.js +1 -1
- package/dist/commands/handlers.js +192 -39
- package/dist/commands/registry.js +7 -5
- 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.js +2 -2
- 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/PRD/codex-switch-prd-v0.0.10.md +406 -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/README.AI.md
CHANGED
|
@@ -54,7 +54,8 @@ Shared flags:
|
|
|
54
54
|
Operational model:
|
|
55
55
|
|
|
56
56
|
- `providers.json` is the management-state source of truth
|
|
57
|
-
- `config.toml`
|
|
57
|
+
- `config.toml` is the managed runtime-routing file
|
|
58
|
+
- `auth.json` is the active auth projection file for direct providers and is also inspected by status/doctor
|
|
58
59
|
- `backups/latest.json` tracks the latest rollback state
|
|
59
60
|
- mutating commands should back up first and run under a lightweight file lock
|
|
60
61
|
|
|
@@ -93,12 +94,13 @@ codexs status --json
|
|
|
93
94
|
Current package version in this repository:
|
|
94
95
|
|
|
95
96
|
```text
|
|
96
|
-
0.0.
|
|
97
|
+
0.0.10
|
|
97
98
|
```
|
|
98
99
|
|
|
99
100
|
Recent version summary:
|
|
100
101
|
|
|
101
|
-
- `0.0.
|
|
102
|
+
- `0.0.10`: `init` / `migrate` command split finalized, `setup` deprecated, and the managed provider model reduced to static profile plus `base_url` configuration
|
|
103
|
+
- `0.0.7`: command-surface refactor, env_key/auth-mirror model corrections, and the initial `setup` split toward `init` plus `migrate`
|
|
102
104
|
- `0.0.4`: setup/show/edit/backups list/specific rollback/import merge and clearer CLI semantics
|
|
103
105
|
- `0.0.3`: interactive TTY flows and improved help
|
|
104
106
|
- `0.0.2`: mutation orchestration, backups, rollback, locks, drift detection improvements
|
package/README.CN.md
CHANGED
|
@@ -17,30 +17,43 @@
|
|
|
17
17
|
|
|
18
18
|
## 现在可以做什么
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
当前命令面如下:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
+
codexs init
|
|
24
|
+
codexs migrate
|
|
23
25
|
codexs list
|
|
26
|
+
codexs show <provider>
|
|
24
27
|
codexs current
|
|
25
|
-
codexs switch <provider>
|
|
26
28
|
codexs status
|
|
29
|
+
codexs edit <provider>
|
|
30
|
+
codexs switch <provider>
|
|
27
31
|
codexs import <file>
|
|
28
32
|
codexs export <file>
|
|
29
33
|
codexs add <provider>
|
|
30
34
|
codexs remove <provider>
|
|
35
|
+
codexs backups list
|
|
31
36
|
codexs doctor
|
|
32
37
|
codexs rollback
|
|
38
|
+
codexs setup
|
|
33
39
|
```
|
|
34
40
|
|
|
35
41
|
对应能力包括:
|
|
36
42
|
|
|
43
|
+
- 初始化空的受管 `providers.json`
|
|
44
|
+
- 从已有 `config.toml` adopt 可管理的 runtime profile
|
|
37
45
|
- 查看本地已管理的 provider
|
|
46
|
+
- 查看单个 provider 详情
|
|
38
47
|
- 查看当前激活的 profile
|
|
48
|
+
- 查看本地运行态摘要
|
|
49
|
+
- 编辑已有 provider
|
|
39
50
|
- 安全切换 provider
|
|
40
51
|
- 导入和导出 provider 映射
|
|
41
52
|
- 新增和删除 provider
|
|
53
|
+
- 查看备份列表
|
|
42
54
|
- 检查配置漂移和常见本地问题
|
|
43
55
|
- 在变更前自动备份,并在失败时回滚
|
|
56
|
+
- 保留 `setup` 作为弃用入口,并引导到 `init` / `migrate`
|
|
44
57
|
|
|
45
58
|
## 简单用法
|
|
46
59
|
|
|
@@ -65,6 +78,8 @@ codexs --help
|
|
|
65
78
|
典型使用方式:
|
|
66
79
|
|
|
67
80
|
```bash
|
|
81
|
+
codexs init
|
|
82
|
+
codexs migrate
|
|
68
83
|
codexs list
|
|
69
84
|
codexs current
|
|
70
85
|
codexs add my-provider --profile my-provider --api-key sk-xxx
|
|
@@ -111,7 +126,8 @@ codexs status --json
|
|
|
111
126
|
存储模型:
|
|
112
127
|
|
|
113
128
|
- `providers.json` 是管理态的单一事实来源
|
|
114
|
-
- `config.toml`
|
|
129
|
+
- `config.toml` 是受管的运行时路由文件
|
|
130
|
+
- `auth.json` 是独立的 Codex 认证状态文件,`status` / `doctor` 只读检查它
|
|
115
131
|
- `backups/latest.json` 记录最近一次可回滚窗口
|
|
116
132
|
|
|
117
133
|
注意:`providers.json` 可能包含 API key,应视为本地敏感文件。
|
|
@@ -128,6 +144,12 @@ codexs status --json
|
|
|
128
144
|
|
|
129
145
|
## 最近 3 个版本更新
|
|
130
146
|
|
|
147
|
+
### 0.0.10
|
|
148
|
+
|
|
149
|
+
- 正式拆分 `setup`:新增 `init` 和 `migrate`,`setup` 变为弃用命令
|
|
150
|
+
- 增加 `show`、`edit`、`backups list` 等对当前命令面的整理
|
|
151
|
+
- 清理 provider/runtime 管理语义,CLI 只负责静态 profile 与 `base_url` 层配置
|
|
152
|
+
|
|
131
153
|
### 0.0.3
|
|
132
154
|
|
|
133
155
|
- 为 `add`、`switch`、`remove`、`import`、`export`、`rollback` 增加了交互式 TTY 流程
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ What it does:
|
|
|
18
18
|
- Run diagnostics and detect local drift
|
|
19
19
|
- List backups and roll back to a previous managed state
|
|
20
20
|
|
|
21
|
-
Current version: `0.0.
|
|
21
|
+
Current version: `0.0.10`
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
@@ -117,7 +117,8 @@ Managed files:
|
|
|
117
117
|
Notes:
|
|
118
118
|
|
|
119
119
|
- `providers.json` is the managed provider registry
|
|
120
|
-
- `config.toml`
|
|
120
|
+
- `config.toml` is the managed runtime-routing file
|
|
121
|
+
- `auth.json` is the active auth projection file; direct-provider switches rewrite `OPENAI_API_KEY`, while `status` and `doctor` inspect its state
|
|
121
122
|
- mutating commands back up before writing
|
|
122
123
|
- rollback is available after failed or undesired changes
|
|
123
124
|
|
package/dist/app/add-provider.js
CHANGED
|
@@ -41,7 +41,6 @@ const errors_1 = require("../domain/errors");
|
|
|
41
41
|
const config_repo_1 = require("../storage/config-repo");
|
|
42
42
|
const fs_utils_1 = require("../storage/fs-utils");
|
|
43
43
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
44
|
-
const auth_repo_1 = require("../storage/auth-repo");
|
|
45
44
|
const copilot_installer_1 = require("../runtime/copilot-installer");
|
|
46
45
|
const run_mutation_1 = require("./run-mutation");
|
|
47
46
|
/**
|
|
@@ -102,14 +101,12 @@ function addProvider(args) {
|
|
|
102
101
|
? {
|
|
103
102
|
[args.profile]: {
|
|
104
103
|
baseUrl: args.copilot ? (0, providers_1.buildCopilotBridgeBaseUrl)(runtime) : args.baseUrl ?? undefined,
|
|
105
|
-
envKey: (0, config_1.buildManagedProfileEnvKey)(args.profile),
|
|
106
104
|
},
|
|
107
105
|
}
|
|
108
106
|
: undefined;
|
|
109
107
|
if (existingProfile) {
|
|
110
108
|
(0, config_repo_1.requireManagedProfileRuntime)(document, providers, args.profile);
|
|
111
109
|
}
|
|
112
|
-
const envKey = existingModelProvider?.envKey ?? (0, config_1.buildManagedProfileEnvKey)(args.profile);
|
|
113
110
|
const apiKey = args.copilot ? args.bridgeApiKey ?? crypto.randomBytes(24).toString("hex") : args.apiKey;
|
|
114
111
|
const baseUrl = args.copilot ? (0, providers_1.buildCopilotBridgeBaseUrl)(runtime) : args.baseUrl ?? undefined;
|
|
115
112
|
const next = {
|
|
@@ -118,7 +115,6 @@ function addProvider(args) {
|
|
|
118
115
|
[args.providerName]: (0, providers_1.cleanProviderRecord)({
|
|
119
116
|
profile: args.profile,
|
|
120
117
|
apiKey,
|
|
121
|
-
envKey,
|
|
122
118
|
baseUrl,
|
|
123
119
|
note: args.note ?? undefined,
|
|
124
120
|
tags: args.tags,
|
|
@@ -134,7 +130,6 @@ function addProvider(args) {
|
|
|
134
130
|
files: [
|
|
135
131
|
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
136
132
|
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
137
|
-
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
138
133
|
],
|
|
139
134
|
mutate: () => {
|
|
140
135
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
@@ -144,15 +139,9 @@ function addProvider(args) {
|
|
|
144
139
|
// Persist only the normalized provider payload so later reads are deterministic.
|
|
145
140
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, next);
|
|
146
141
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
147
|
-
if (document.activeProfile === args.profile) {
|
|
148
|
-
const activeProviderName = (0, config_repo_1.resolveActiveProviderName)(document, next);
|
|
149
|
-
const existingAuth = (0, auth_repo_1.readAuthFileIfExists)(args.authPath);
|
|
150
|
-
(0, auth_repo_1.writeAuthFile)(args.authPath, next.providers[activeProviderName], existingAuth ?? undefined);
|
|
151
|
-
}
|
|
152
142
|
return {
|
|
153
143
|
provider: args.providerName,
|
|
154
144
|
profile: args.profile,
|
|
155
|
-
envKey,
|
|
156
145
|
runtimeKind: runtime?.kind ?? null,
|
|
157
146
|
createdProfileSections: configPlan.createdProfileSections,
|
|
158
147
|
createdModelProviderSections: configPlan.createdModelProviderSections,
|
package/dist/app/bridge.js
CHANGED
|
@@ -283,7 +283,6 @@ function persistRecoveredBridgePort(args) {
|
|
|
283
283
|
upsertModelProviders: {
|
|
284
284
|
[args.provider.profile]: {
|
|
285
285
|
baseUrl: (0, providers_1.buildCopilotBridgeBaseUrl)(args.provider.runtime),
|
|
286
|
-
envKey: (0, config_repo_1.requireRuntimeEnvKey)(document, args.provider.profile),
|
|
287
286
|
},
|
|
288
287
|
},
|
|
289
288
|
});
|
|
@@ -7,7 +7,6 @@ const providers_1 = require("../domain/providers");
|
|
|
7
7
|
const config_repo_1 = require("../storage/config-repo");
|
|
8
8
|
const fs_utils_1 = require("../storage/fs-utils");
|
|
9
9
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
10
|
-
const auth_repo_1 = require("../storage/auth-repo");
|
|
11
10
|
const run_mutation_1 = require("./run-mutation");
|
|
12
11
|
/**
|
|
13
12
|
* Updates selected fields on a single managed provider.
|
|
@@ -63,23 +62,15 @@ function editProvider(args) {
|
|
|
63
62
|
upsertModelProviders = {
|
|
64
63
|
[newProfile]: {
|
|
65
64
|
baseUrl: args.baseUrl ?? undefined,
|
|
66
|
-
envKey: (0, config_1.buildManagedProfileEnvKey)(newProfile),
|
|
67
65
|
},
|
|
68
66
|
};
|
|
69
67
|
}
|
|
70
68
|
else {
|
|
71
69
|
(0, config_repo_1.requireManagedProfileRuntime)(document, providers, newProfile);
|
|
72
70
|
}
|
|
73
|
-
const nextEnvKey = args.profile !== undefined && args.profile !== current.profile
|
|
74
|
-
? targetModelProviderSection?.envKey ?? (0, config_1.buildManagedProfileEnvKey)(newProfile)
|
|
75
|
-
: current.envKey;
|
|
76
|
-
if (nextEnvKey !== current.envKey) {
|
|
77
|
-
updatedFields.push("envKey");
|
|
78
|
-
}
|
|
79
71
|
const nextRecord = (0, providers_1.cleanProviderRecord)({
|
|
80
72
|
profile: newProfile,
|
|
81
73
|
apiKey: args.apiKey ?? current.apiKey,
|
|
82
|
-
envKey: nextEnvKey,
|
|
83
74
|
baseUrl: args.baseUrl === null ? undefined : args.baseUrl ?? current.baseUrl,
|
|
84
75
|
note: args.note === null ? undefined : args.note ?? current.note,
|
|
85
76
|
tags: args.tags ?? current.tags,
|
|
@@ -90,7 +81,7 @@ function editProvider(args) {
|
|
|
90
81
|
...(args.model !== undefined && args.model !== null ? { model: args.model } : {}),
|
|
91
82
|
},
|
|
92
83
|
};
|
|
93
|
-
if (args.model !== undefined &&
|
|
84
|
+
if (args.model !== undefined && targetSection?.model !== args.model && !updatedFields.includes("model")) {
|
|
94
85
|
updatedFields.push("model");
|
|
95
86
|
}
|
|
96
87
|
}
|
|
@@ -125,7 +116,6 @@ function editProvider(args) {
|
|
|
125
116
|
files: [
|
|
126
117
|
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
127
118
|
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
128
|
-
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
129
119
|
],
|
|
130
120
|
mutate: () => {
|
|
131
121
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
@@ -143,12 +133,6 @@ function editProvider(args) {
|
|
|
143
133
|
// Write providers first so the registry and config move together inside the managed backup boundary.
|
|
144
134
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, nextProviders);
|
|
145
135
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
146
|
-
const updatedDocument = (0, config_repo_1.readStructuredConfig)(args.configPath);
|
|
147
|
-
if (updatedDocument.activeProfile) {
|
|
148
|
-
const activeProviderName = (0, config_repo_1.resolveActiveProviderName)(updatedDocument, nextProviders);
|
|
149
|
-
const existingAuth = (0, auth_repo_1.readAuthFileIfExists)(args.authPath);
|
|
150
|
-
(0, auth_repo_1.writeAuthFile)(args.authPath, nextProviders.providers[activeProviderName], existingAuth ?? undefined);
|
|
151
|
-
}
|
|
152
136
|
return {
|
|
153
137
|
provider: args.providerName,
|
|
154
138
|
updatedFields,
|
package/dist/app/get-status.js
CHANGED
|
@@ -56,7 +56,7 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
56
56
|
const providers = providersExists ? (0, providers_repo_1.readProvidersFile)(providersPath) : null;
|
|
57
57
|
let configViews = [];
|
|
58
58
|
let consistencyIssues = [];
|
|
59
|
-
const authState = (0, auth_repo_1.
|
|
59
|
+
const authState = (0, auth_repo_1.readAuthFileState)(authPath);
|
|
60
60
|
if (configExists) {
|
|
61
61
|
const document = (0, config_repo_1.readStructuredConfig)(configPath);
|
|
62
62
|
currentProfile = document.activeProfile;
|
|
@@ -70,20 +70,32 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
70
70
|
const activeProviderCandidates = currentProfile && providers ? (0, providers_1.findProvidersByProfile)(providers, currentProfile) : [];
|
|
71
71
|
const activeProvider = activeProviderCandidates.length === 1 && providers ? providers.providers[activeProviderCandidates[0]] : null;
|
|
72
72
|
const copilotInstall = (0, copilot_installer_1.probeCopilotSdkInstall)();
|
|
73
|
-
const
|
|
73
|
+
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)();
|
|
74
|
+
const runtimeState = runtimeStateInspection.state;
|
|
74
75
|
const runtimeStateProvider = runtimeState && providers ? providers.providers[runtimeState.provider] ?? null : null;
|
|
75
76
|
const bridgeProbeTarget = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
|
|
76
77
|
? activeProvider
|
|
77
78
|
: runtimeStateProvider && (0, providers_1.isCopilotBridgeProvider)(runtimeStateProvider)
|
|
78
79
|
? runtimeStateProvider
|
|
79
80
|
: null;
|
|
80
|
-
const copilotBridge =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
const copilotBridge = !runtimeStateInspection.valid && runtimeStateInspection.exists
|
|
82
|
+
? {
|
|
83
|
+
ok: false,
|
|
84
|
+
runtime: "copilot-bridge",
|
|
85
|
+
reason: "failed",
|
|
86
|
+
cause: runtimeStateInspection.parseError ?? "Failed to parse Copilot bridge runtime state.",
|
|
87
|
+
}
|
|
88
|
+
: bridgeProbeTarget
|
|
89
|
+
? await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(bridgeProbeTarget, runtimeState)
|
|
90
|
+
: runtimeState
|
|
91
|
+
? {
|
|
92
|
+
ok: false,
|
|
93
|
+
runtime: "copilot-bridge",
|
|
94
|
+
reason: "failed",
|
|
95
|
+
cause: "Copilot bridge runtime state exists but no matching managed Copilot provider is active.",
|
|
96
|
+
details: runtimeState,
|
|
97
|
+
}
|
|
98
|
+
: null;
|
|
87
99
|
const copilotAuth = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
|
|
88
100
|
? await (0, copilot_adapter_1.readCopilotAuthState)().catch((error) => ({
|
|
89
101
|
ready: false,
|
|
@@ -96,6 +108,9 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
|
96
108
|
// Surface unmanaged live state without mutating anything during a read-only status call.
|
|
97
109
|
warnings.push("Current config profile is not mapped in providers.json. Backfill would be required before treating live state as managed.");
|
|
98
110
|
}
|
|
111
|
+
if (runtimeStateInspection.exists && !runtimeStateInspection.valid) {
|
|
112
|
+
warnings.push(`Copilot bridge runtime state is unreadable: ${runtimeStateInspection.parseError ?? "unknown parse failure"}`);
|
|
113
|
+
}
|
|
99
114
|
return {
|
|
100
115
|
warnings,
|
|
101
116
|
data: {
|
|
@@ -11,7 +11,6 @@ function listProviders(providersPath) {
|
|
|
11
11
|
const items = names.map((name) => ({
|
|
12
12
|
name,
|
|
13
13
|
profile: providers.providers[name].profile,
|
|
14
|
-
envKey: providers.providers[name].envKey,
|
|
15
14
|
note: providers.providers[name].note ?? null,
|
|
16
15
|
tags: providers.providers[name].tags ?? [],
|
|
17
16
|
}));
|
package/dist/app/run-doctor.js
CHANGED
|
@@ -102,8 +102,9 @@ async function runDoctor(args) {
|
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
const authState = (0, auth_repo_1.
|
|
106
|
-
const
|
|
105
|
+
const authState = (0, auth_repo_1.readAuthFileState)(args.authPath);
|
|
106
|
+
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)();
|
|
107
|
+
const runtimeState = runtimeStateInspection.state;
|
|
107
108
|
if (authState.exists && !authState.valid) {
|
|
108
109
|
issues.push({
|
|
109
110
|
code: "AUTH_JSON_INVALID",
|
|
@@ -111,34 +112,16 @@ async function runDoctor(args) {
|
|
|
111
112
|
file: args.authPath,
|
|
112
113
|
});
|
|
113
114
|
}
|
|
115
|
+
if (runtimeStateInspection.exists && !runtimeStateInspection.valid) {
|
|
116
|
+
issues.push({
|
|
117
|
+
code: "BRIDGE_STATE_STALE",
|
|
118
|
+
message: `Copilot bridge runtime state is unreadable: ${runtimeStateInspection.parseError ?? "unknown parse failure"}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
114
121
|
if (document?.activeProfile && providers) {
|
|
115
122
|
const matches = (0, providers_1.findProvidersByProfile)(providers, document.activeProfile);
|
|
116
123
|
if (matches.length === 1) {
|
|
117
124
|
const activeProvider = providers.providers[matches[0]];
|
|
118
|
-
const payload = authState.payload ?? {};
|
|
119
|
-
const actualKeys = authState.managedSecretKeys;
|
|
120
|
-
if (authState.authMode !== null && authState.authMode !== "apikey") {
|
|
121
|
-
issues.push({
|
|
122
|
-
code: "AUTH_JSON_INVALID",
|
|
123
|
-
message: `auth.json auth_mode must be "apikey", found "${authState.authMode}".`,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
if (!actualKeys.includes(activeProvider.envKey) || actualKeys.length !== 1) {
|
|
127
|
-
issues.push({
|
|
128
|
-
code: "AUTH_JSON_ENV_KEY_MISMATCH",
|
|
129
|
-
message: `auth.json managed env key does not match active provider "${matches[0]}".`,
|
|
130
|
-
provider: matches[0],
|
|
131
|
-
expectedEnvKey: activeProvider.envKey,
|
|
132
|
-
actualEnvKeys: actualKeys,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
if (payload[activeProvider.envKey] !== activeProvider.apiKey) {
|
|
136
|
-
issues.push({
|
|
137
|
-
code: "AUTH_JSON_APIKEY_MISMATCH",
|
|
138
|
-
message: `auth.json secret value does not match active provider "${matches[0]}".`,
|
|
139
|
-
provider: matches[0],
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
125
|
if ((0, providers_1.isCopilotBridgeProvider)(activeProvider)) {
|
|
143
126
|
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)();
|
|
144
127
|
if (!installStatus.installed) {
|
|
@@ -160,7 +143,7 @@ async function runDoctor(args) {
|
|
|
160
143
|
...(normalized.details ?? {}),
|
|
161
144
|
});
|
|
162
145
|
}
|
|
163
|
-
const bridge = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider);
|
|
146
|
+
const bridge = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider, runtimeState);
|
|
164
147
|
if (!bridge.ok) {
|
|
165
148
|
issues.push({
|
|
166
149
|
code: mapBridgeDiagnosticCode(bridge.cause),
|
|
@@ -255,18 +238,10 @@ function renderConfigIssueMessage(issue) {
|
|
|
255
238
|
return `Model provider section "${issue.modelProvider}" for profile "${issue.profile}" is missing from config.toml.`;
|
|
256
239
|
case "MODEL_PROVIDER_BASE_URL_MISSING":
|
|
257
240
|
return `Model provider section "${issue.modelProvider}" for profile "${issue.profile}" is missing base_url.`;
|
|
258
|
-
case "MODEL_PROVIDER_ENV_KEY_MISSING":
|
|
259
|
-
return `Model provider section "${issue.modelProvider}" for profile "${issue.profile}" is missing env_key.`;
|
|
260
|
-
case "PROVIDER_ENV_KEY_MISMATCH":
|
|
261
|
-
return `Provider "${issue.provider}" envKey does not match runtime env_key for profile "${issue.profile}".`;
|
|
262
241
|
case "ACTIVE_PROVIDER_UNRESOLVED":
|
|
263
|
-
return `Active profile "${issue.profile}" maps to multiple providers
|
|
242
|
+
return `Active profile "${issue.profile}" maps to multiple providers, so the active managed provider cannot be resolved uniquely.`;
|
|
264
243
|
case "AUTH_JSON_INVALID":
|
|
265
244
|
return String(issue.message ?? issue.reason ?? "auth.json is invalid.");
|
|
266
|
-
case "AUTH_JSON_ENV_KEY_MISMATCH":
|
|
267
|
-
return `auth.json managed env key does not match provider "${String(issue.provider ?? "")}".`;
|
|
268
|
-
case "AUTH_JSON_APIKEY_MISMATCH":
|
|
269
|
-
return `auth.json secret does not match provider "${String(issue.provider ?? "")}".`;
|
|
270
245
|
case "DESTRUCTIVE_REMOVE_BLOCKED":
|
|
271
246
|
return `Provider "${issue.provider}" cannot be removed while "${issue.activeProfile}" remains active.`;
|
|
272
247
|
default:
|
package/dist/app/setup-codex.js
CHANGED
|
@@ -42,7 +42,6 @@ const codex_cli_1 = require("../runtime/codex-cli");
|
|
|
42
42
|
const config_repo_1 = require("../storage/config-repo");
|
|
43
43
|
const fs_utils_1 = require("../storage/fs-utils");
|
|
44
44
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
45
|
-
const auth_repo_1 = require("../storage/auth-repo");
|
|
46
45
|
const run_doctor_1 = require("./run-doctor");
|
|
47
46
|
const run_mutation_1 = require("./run-mutation");
|
|
48
47
|
const MIN_CODEX_VERSION = "0.0.1";
|
|
@@ -70,30 +69,46 @@ async function migrateCodex(args) {
|
|
|
70
69
|
});
|
|
71
70
|
}
|
|
72
71
|
const document = (0, config_repo_1.readStructuredConfig)(args.configPath);
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
.filter((view) => view.source === "unmanaged" && view.model && view.modelProvider === view.name && view.baseUrl && view.envKey)
|
|
77
|
-
.map((view) => view.name)
|
|
78
|
-
.sort();
|
|
72
|
+
const currentProviders = (0, providers_repo_1.readProvidersFileIfExists)(args.providersPath);
|
|
73
|
+
const profileViews = (0, config_1.buildManagedProfileViews)(document, currentProviders);
|
|
74
|
+
const adoptability = (0, setup_1.collectMigrateAdoptability)(document, currentProviders);
|
|
79
75
|
if (profileViews.length === 0) {
|
|
80
76
|
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", "No profiles were found in config.toml.", {
|
|
81
77
|
file: args.configPath,
|
|
82
78
|
});
|
|
83
79
|
}
|
|
84
|
-
|
|
80
|
+
if (adoptability.adoptableProfiles.length === 0) {
|
|
81
|
+
throw (0, errors_1.cliError)("MIGRATE_NO_ADOPTABLE_PROFILES", "No adoptable profiles were found for migrate.", {
|
|
82
|
+
availableProfiles: adoptability.availableProfiles,
|
|
83
|
+
adoptableProfiles: adoptability.adoptableProfiles,
|
|
84
|
+
blockingReasonsByProfile: adoptability.blockingReasonsByProfile,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const invalidAdoptProfiles = args.adoptProfiles.filter((profile) => !adoptability.adoptableProfiles.includes(profile));
|
|
85
88
|
if (invalidAdoptProfiles.length > 0) {
|
|
86
|
-
throw (0, errors_1.cliError)("INVALID_ARGUMENT", "migrate only adopts unmanaged profiles that already contain model, model_provider, and matching model_providers base_url
|
|
89
|
+
throw (0, errors_1.cliError)("INVALID_ARGUMENT", "migrate only adopts unmanaged profiles that already contain model, model_provider, and matching model_providers base_url.", {
|
|
87
90
|
invalidProfiles: invalidAdoptProfiles.sort(),
|
|
88
|
-
|
|
91
|
+
availableProfiles: adoptability.availableProfiles,
|
|
92
|
+
adoptableProfiles: adoptability.adoptableProfiles,
|
|
93
|
+
blockingReasonsByProfile: adoptability.blockingReasonsByProfile,
|
|
89
94
|
});
|
|
90
95
|
}
|
|
91
96
|
if (args.adoptProfiles.length === 0) {
|
|
92
97
|
throw (0, errors_1.cliError)("INVALID_ARGUMENT", "migrate requires at least one explicit profile to adopt.", {
|
|
93
|
-
|
|
98
|
+
availableProfiles: adoptability.availableProfiles,
|
|
99
|
+
adoptableProfiles: adoptability.adoptableProfiles,
|
|
100
|
+
blockingReasonsByProfile: adoptability.blockingReasonsByProfile,
|
|
94
101
|
});
|
|
95
102
|
}
|
|
96
|
-
const
|
|
103
|
+
const runtimeByProfile = profileViews.reduce((accumulator, view) => {
|
|
104
|
+
if (view.source === "unmanaged") {
|
|
105
|
+
accumulator[view.name] = {
|
|
106
|
+
baseUrl: view.baseUrl ?? undefined,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return accumulator;
|
|
110
|
+
}, {});
|
|
111
|
+
const drafts = (0, setup_1.buildSetupDrafts)(args.adoptProfiles, args.providerDetailsByProfile, runtimeByProfile);
|
|
97
112
|
const incompleteProfiles = (0, setup_1.findIncompleteSetupProfiles)(drafts);
|
|
98
113
|
if (incompleteProfiles.length > 0) {
|
|
99
114
|
throw (0, errors_1.cliError)("INVALID_ARGUMENT", "migrate requires complete provider data for every selected profile.", {
|
|
@@ -101,7 +116,6 @@ async function migrateCodex(args) {
|
|
|
101
116
|
});
|
|
102
117
|
}
|
|
103
118
|
(0, fs_utils_1.ensureDir)(args.codexDir);
|
|
104
|
-
const currentProviders = (0, providers_repo_1.readProvidersFileIfExists)(args.providersPath);
|
|
105
119
|
const providersExists = fs.existsSync(args.providersPath);
|
|
106
120
|
if (providersExists && args.strategy !== "merge" && args.strategy !== "overwrite") {
|
|
107
121
|
throw (0, errors_1.cliError)("PROVIDERS_ALREADY_EXISTS", "providers.json already exists.", {
|
|
@@ -123,16 +137,12 @@ async function migrateCodex(args) {
|
|
|
123
137
|
files: [
|
|
124
138
|
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
125
139
|
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
126
|
-
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
127
140
|
],
|
|
128
141
|
mutate: () => {
|
|
129
142
|
// migrate currently preserves config structure and only asserts that the file remains writable inside the mutation flow.
|
|
130
143
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {});
|
|
131
144
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, finalProviders);
|
|
132
145
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
133
|
-
const activeProviderName = (0, config_repo_1.resolveActiveProviderName)(document, finalProviders);
|
|
134
|
-
const existingAuth = (0, auth_repo_1.readAuthFileIfExists)(args.authPath);
|
|
135
|
-
(0, auth_repo_1.writeAuthFile)(args.authPath, finalProviders.providers[activeProviderName], existingAuth ?? undefined);
|
|
136
146
|
return {
|
|
137
147
|
codexDir: args.codexDir,
|
|
138
148
|
strategy: args.strategy,
|
package/dist/app/show-config.js
CHANGED
|
@@ -31,11 +31,7 @@ function showConfig(args) {
|
|
|
31
31
|
selectedProfile,
|
|
32
32
|
profiles: profiles.map((profile) => ({
|
|
33
33
|
...profile,
|
|
34
|
-
|
|
35
|
-
providerName,
|
|
36
|
-
envKey: providers.providers[providerName].envKey,
|
|
37
|
-
matchesRuntime: providers.providers[providerName].envKey === profile.envKey,
|
|
38
|
-
})),
|
|
34
|
+
linkedProviderNames: (0, providers_1.findProvidersByProfile)(providers, profile.name),
|
|
39
35
|
})),
|
|
40
36
|
},
|
|
41
37
|
};
|
|
@@ -4,14 +4,14 @@ exports.switchProvider = switchProvider;
|
|
|
4
4
|
const errors_1 = require("../domain/errors");
|
|
5
5
|
const providers_1 = require("../domain/providers");
|
|
6
6
|
const config_repo_1 = require("../storage/config-repo");
|
|
7
|
-
const providers_repo_1 = require("../storage/providers-repo");
|
|
8
7
|
const auth_repo_1 = require("../storage/auth-repo");
|
|
8
|
+
const providers_repo_1 = require("../storage/providers-repo");
|
|
9
9
|
const copilot_bridge_1 = require("../runtime/copilot-bridge");
|
|
10
10
|
const copilot_installer_1 = require("../runtime/copilot-installer");
|
|
11
11
|
const copilot_adapter_1 = require("../runtime/copilot-adapter");
|
|
12
12
|
const run_mutation_1 = require("./run-mutation");
|
|
13
13
|
/**
|
|
14
|
-
* Switches the active Codex profile
|
|
14
|
+
* Switches the active Codex profile to the target provider.
|
|
15
15
|
*/
|
|
16
16
|
async function switchProvider(args) {
|
|
17
17
|
const providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
|
|
@@ -22,15 +22,6 @@ async function switchProvider(args) {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
const document = (0, config_repo_1.ensureProfileExists)(args.configPath, provider.profile, args.providerName);
|
|
25
|
-
const envKey = (0, config_repo_1.requireRuntimeEnvKey)(document, provider.profile);
|
|
26
|
-
if (provider.envKey !== envKey) {
|
|
27
|
-
throw (0, errors_1.cliError)("PROVIDER_ENV_KEY_MISMATCH", `Provider "${args.providerName}" envKey does not match runtime env_key.`, {
|
|
28
|
-
provider: args.providerName,
|
|
29
|
-
profile: provider.profile,
|
|
30
|
-
providerEnvKey: provider.envKey,
|
|
31
|
-
runtimeEnvKey: envKey,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
25
|
if ((0, providers_1.isCopilotBridgeProvider)(provider)) {
|
|
35
26
|
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)();
|
|
36
27
|
if (!installStatus.installed) {
|
|
@@ -58,8 +49,8 @@ async function switchProvider(args) {
|
|
|
58
49
|
latestBackupPath: args.latestBackupPath,
|
|
59
50
|
operation: "switch",
|
|
60
51
|
files: [
|
|
52
|
+
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
61
53
|
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
62
|
-
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
63
54
|
],
|
|
64
55
|
mutate: () => {
|
|
65
56
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
@@ -68,7 +59,6 @@ async function switchProvider(args) {
|
|
|
68
59
|
? {
|
|
69
60
|
[provider.profile]: {
|
|
70
61
|
baseUrl: (0, providers_1.buildCopilotBridgeBaseUrl)(nextProvider.runtime),
|
|
71
|
-
envKey,
|
|
72
62
|
},
|
|
73
63
|
}
|
|
74
64
|
: undefined,
|
|
@@ -82,12 +72,9 @@ async function switchProvider(args) {
|
|
|
82
72
|
});
|
|
83
73
|
}
|
|
84
74
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
85
|
-
const existingAuth = (0, auth_repo_1.readAuthFileIfExists)(args.authPath);
|
|
86
|
-
(0, auth_repo_1.writeAuthFile)(args.authPath, nextProvider, existingAuth ?? undefined);
|
|
87
75
|
return {
|
|
88
76
|
provider: args.providerName,
|
|
89
77
|
profile: nextProvider.profile,
|
|
90
|
-
envKey: nextProvider.envKey,
|
|
91
78
|
portChanged: bridge.portChanged,
|
|
92
79
|
bridgePort: bridge.port,
|
|
93
80
|
};
|
|
@@ -107,20 +94,18 @@ async function switchProvider(args) {
|
|
|
107
94
|
latestBackupPath: args.latestBackupPath,
|
|
108
95
|
operation: "switch",
|
|
109
96
|
files: [
|
|
110
|
-
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
111
97
|
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
98
|
+
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
112
99
|
],
|
|
113
100
|
mutate: () => {
|
|
114
101
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
115
102
|
setActiveProfile: provider.profile,
|
|
116
103
|
});
|
|
117
104
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
118
|
-
|
|
119
|
-
(0, auth_repo_1.writeAuthFile)(args.authPath, provider, existingAuth ?? undefined);
|
|
105
|
+
(0, auth_repo_1.writeOpenAiApiKeyAuth)(args.authPath, provider.apiKey);
|
|
120
106
|
return {
|
|
121
107
|
provider: args.providerName,
|
|
122
108
|
profile: provider.profile,
|
|
123
|
-
envKey: provider.envKey,
|
|
124
109
|
};
|
|
125
110
|
},
|
|
126
111
|
});
|
package/dist/cli/output.js
CHANGED
|
@@ -90,8 +90,7 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
90
90
|
? ` tags=${provider.tags.join(",")}`
|
|
91
91
|
: "";
|
|
92
92
|
const note = provider.note ? ` note=${provider.note}` : "";
|
|
93
|
-
|
|
94
|
-
lines.push(`${provider.name} -> ${provider.profile}${envKey}${tags}${note}`);
|
|
93
|
+
lines.push(`${provider.name} -> ${provider.profile}${tags}${note}`);
|
|
95
94
|
}
|
|
96
95
|
}
|
|
97
96
|
break;
|
|
@@ -101,7 +100,6 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
101
100
|
lines.push(`Provider: ${String(data?.providerName ?? "")}`);
|
|
102
101
|
lines.push(`profile: ${String(provider.profile ?? "")}`);
|
|
103
102
|
lines.push(`apiKey: ${String(provider.apiKey ?? "")}`);
|
|
104
|
-
lines.push(`envKey: ${String(provider.envKey ?? "")}`);
|
|
105
103
|
if (provider.baseUrl) {
|
|
106
104
|
lines.push(`baseUrl: ${String(provider.baseUrl)}`);
|
|
107
105
|
}
|
|
@@ -125,14 +123,15 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
125
123
|
lines.push(`activeProviderResolvable: ${String(data?.activeProviderResolvable ?? false)}`);
|
|
126
124
|
const auth = data?.auth ?? {};
|
|
127
125
|
lines.push(`authExists: ${String(auth.exists ?? false)}`);
|
|
128
|
-
lines.push(`
|
|
126
|
+
lines.push(`authValid: ${String(auth.valid ?? false)}`);
|
|
127
|
+
lines.push(`authMode: ${String(auth.authMode ?? "")}`);
|
|
129
128
|
lines.push(`issues: ${Array.isArray(data?.issues) ? (data?.issues).length : 0}`);
|
|
130
129
|
break;
|
|
131
130
|
case "config-show": {
|
|
132
131
|
lines.push(`activeProfile: ${String(data?.activeProfile ?? "")}`);
|
|
133
132
|
const profiles = data?.profiles ?? [];
|
|
134
133
|
for (const profile of profiles) {
|
|
135
|
-
lines.push(`${String(profile.name)} managed=${String(profile.managed)} active=${String(profile.isActive)} source=${String(profile.source)} model=${String(profile.model ?? "")} modelProvider=${String(profile.modelProvider ?? "")} baseUrl=${String(profile.baseUrl ?? "")}
|
|
134
|
+
lines.push(`${String(profile.name)} managed=${String(profile.managed)} active=${String(profile.isActive)} source=${String(profile.source)} model=${String(profile.model ?? "")} modelProvider=${String(profile.modelProvider ?? "")} baseUrl=${String(profile.baseUrl ?? "")}`);
|
|
136
135
|
}
|
|
137
136
|
break;
|
|
138
137
|
}
|
|
@@ -145,7 +144,6 @@ function renderHumanSuccess(command, data, warnings) {
|
|
|
145
144
|
}
|
|
146
145
|
case "switch":
|
|
147
146
|
lines.push(`Switched to provider ${String(data?.provider ?? "")} using profile ${String(data?.profile ?? "")}.`);
|
|
148
|
-
lines.push(`envKey: ${String(data?.envKey ?? "")}`);
|
|
149
147
|
lines.push(`Backup: ${String(data?.backupPath ?? "")}`);
|
|
150
148
|
break;
|
|
151
149
|
case "import":
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ const args_1 = require("./commands/args");
|
|
|
9
9
|
const help_1 = require("./commands/help");
|
|
10
10
|
const errors_1 = require("./domain/errors");
|
|
11
11
|
const output_1 = require("./cli/output");
|
|
12
|
-
const VERSION = "0.0.
|
|
12
|
+
const VERSION = require("../package.json").version ?? "0.0.0";
|
|
13
13
|
/**
|
|
14
14
|
* Prints the command help text to stdout.
|
|
15
15
|
*/
|