@minniexcode/codex-switch 0.0.5 → 0.0.7
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 -2
- package/README.md +44 -100
- package/dist/app/add-provider.js +28 -4
- package/dist/app/edit-provider.js +47 -19
- package/dist/app/export-providers.js +2 -2
- package/dist/app/get-current-profile.js +1 -1
- package/dist/app/get-status.js +10 -3
- package/dist/app/import-providers.js +15 -7
- package/dist/app/init-codex.js +68 -0
- package/dist/app/list-backups.js +1 -1
- package/dist/app/list-config-profiles.js +3 -2
- package/dist/app/list-providers.js +2 -1
- package/dist/app/remove-provider.js +2 -2
- package/dist/app/rollback-backup.js +1 -1
- package/dist/app/rollback-latest.js +1 -1
- package/dist/app/run-doctor.js +83 -6
- package/dist/app/run-mutation.js +2 -2
- package/dist/app/setup-codex.js +21 -12
- package/dist/app/show-config.js +11 -3
- package/dist/app/show-provider.js +1 -1
- package/dist/app/switch-provider.js +16 -9
- package/dist/cli/add-interactive.js +7 -104
- package/dist/cli/args.js +6 -135
- package/dist/cli/help.js +8 -313
- package/dist/cli/interactive.js +17 -225
- package/dist/cli/output.js +21 -6
- package/dist/cli/prompt.js +4 -106
- package/dist/cli.js +10 -404
- package/dist/commands/args.js +132 -0
- package/dist/commands/dispatch.js +16 -0
- package/dist/commands/handlers.js +460 -0
- package/dist/commands/help.js +120 -0
- package/dist/commands/registry.js +351 -0
- package/dist/commands/types.js +2 -0
- package/dist/domain/config.js +235 -21
- package/dist/domain/providers.js +16 -2
- package/dist/domain/setup.js +1 -0
- package/dist/infra/backup-repo.js +9 -206
- package/dist/infra/codex-cli.js +9 -126
- package/dist/infra/codex-paths.js +6 -67
- package/dist/infra/config-repo.js +59 -0
- package/dist/infra/fs-utils.js +8 -93
- package/dist/infra/lock-repo.js +4 -95
- package/dist/infra/providers-repo.js +8 -94
- package/dist/interaction/add-interactive.js +99 -0
- package/dist/interaction/interactive.js +289 -0
- package/dist/interaction/prompt.js +110 -0
- package/dist/runtime/codex-cli.js +130 -0
- package/dist/runtime/codex-probe.js +57 -0
- package/dist/runtime/types.js +2 -0
- package/dist/storage/auth-repo.js +160 -0
- package/dist/storage/backup-repo.js +210 -0
- package/dist/storage/codex-paths.js +71 -0
- package/dist/storage/config-repo.js +266 -0
- package/dist/storage/fs-utils.js +97 -0
- package/dist/storage/lock-repo.js +99 -0
- package/dist/storage/providers-repo.js +98 -0
- package/docs/Design/codex-switch-v0.0.5-design.md +32 -22
- package/docs/Design/codex-switch-v0.0.6-design.md +708 -0
- package/docs/Design/codex-switch-v0.0.7-design.md +862 -0
- package/docs/PRD/codex-switch-prd-v0.0.5-to-v0.1.0.md +227 -89
- package/docs/PRD/codex-switch-prd-v0.1.0.md +200 -226
- package/docs/PRD/codex-switch-prd.md +1 -1
- package/docs/Reference/codex-config-reference.md +604 -0
- package/docs/Reference/codex-config-reference.zh-CN.md +633 -0
- package/docs/cli-usage.md +78 -29
- package/docs/codex-switch-technical-architecture.md +73 -4
- package/docs/test-report-0.0.5.md +163 -0
- package/docs/test-report-0.0.7.md +118 -0
- package/docs/testing.md +151 -0
- package/package.json +1 -1
package/README.AI.md
CHANGED
|
@@ -17,7 +17,8 @@ Primary goals:
|
|
|
17
17
|
## Main Command Surface
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
codexs
|
|
20
|
+
codexs init
|
|
21
|
+
codexs migrate
|
|
21
22
|
codexs list
|
|
22
23
|
codexs show <provider>
|
|
23
24
|
codexs current
|
|
@@ -92,11 +93,12 @@ codexs status --json
|
|
|
92
93
|
Current package version in this repository:
|
|
93
94
|
|
|
94
95
|
```text
|
|
95
|
-
0.0.
|
|
96
|
+
0.0.7
|
|
96
97
|
```
|
|
97
98
|
|
|
98
99
|
Recent version summary:
|
|
99
100
|
|
|
101
|
+
- `0.0.7`: command-surface refactor, env_key/auth-mirror model corrections, and the `setup` split into `init` plus `migrate`
|
|
100
102
|
- `0.0.4`: setup/show/edit/backups list/specific rollback/import merge and clearer CLI semantics
|
|
101
103
|
- `0.0.3`: interactive TTY flows and improved help
|
|
102
104
|
- `0.0.2`: mutation orchestration, backups, rollback, locks, drift detection improvements
|
|
@@ -107,4 +109,5 @@ Recent version summary:
|
|
|
107
109
|
- Prefer `--json` when invoking commands programmatically
|
|
108
110
|
- Treat `providers.json` as sensitive because it may contain API keys
|
|
109
111
|
- Do not assume silent write-back from runtime files into `providers.json`
|
|
112
|
+
- Prefer `init` for repeatable machine setup and `migrate` for human-led adopt flows
|
|
110
113
|
- Use `docs/` for deeper product and architecture context
|
package/README.md
CHANGED
|
@@ -1,38 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
## @minniexcode/codex-switch
|
|
2
2
|
|
|
3
3
|
`codex-switch` is a local-first CLI for managing and switching Codex provider/profile configuration safely.
|
|
4
4
|
|
|
5
|
-
`codex-switch` 是一个本地优先的 CLI,用来安全地管理和切换 Codex 的 provider/profile 配置。
|
|
6
|
-
|
|
7
5
|
It is designed for users who work with multiple Codex providers, API keys, or profiles and want a repeatable, backup-first workflow instead of manually editing files under `~/.codex/`.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
中文版: [README.CN.md](./README.CN.md)
|
|
10
8
|
|
|
11
|
-
## Overview
|
|
9
|
+
## Overview
|
|
12
10
|
|
|
13
11
|
What it does:
|
|
14
12
|
|
|
15
|
-
- Initialize `providers.json`
|
|
13
|
+
- Initialize an empty managed `providers.json`
|
|
14
|
+
- Migrate unmanaged runtime profiles from an existing Codex directory
|
|
16
15
|
- List, show, add, edit, and remove provider records
|
|
17
16
|
- Switch the active provider/profile safely
|
|
18
17
|
- Import and export provider definitions
|
|
19
18
|
- Run diagnostics and detect local drift
|
|
20
|
-
- List backups and
|
|
21
|
-
|
|
22
|
-
它可以完成的事情:
|
|
23
|
-
|
|
24
|
-
- 从现有 Codex 目录初始化 `providers.json`
|
|
25
|
-
- 查看、新增、编辑、删除 provider 记录
|
|
26
|
-
- 安全切换当前激活的 provider/profile
|
|
27
|
-
- 导入和导出 provider 配置
|
|
28
|
-
- 运行诊断并识别本地配置漂移
|
|
29
|
-
- 查看备份并回滚到之前的受管状态
|
|
30
|
-
|
|
31
|
-
Current version: `0.0.4`
|
|
19
|
+
- List backups and roll back to a previous managed state
|
|
32
20
|
|
|
33
|
-
|
|
21
|
+
Current version: `0.0.7`
|
|
34
22
|
|
|
35
|
-
## Install
|
|
23
|
+
## Install
|
|
36
24
|
|
|
37
25
|
Install globally:
|
|
38
26
|
|
|
@@ -46,42 +34,19 @@ Or run directly:
|
|
|
46
34
|
npx @minniexcode/codex-switch --help
|
|
47
35
|
```
|
|
48
36
|
|
|
49
|
-
全局安装:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
npm install -g @minniexcode/codex-switch
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
或者直接运行:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
npx @minniexcode/codex-switch --help
|
|
59
|
-
```
|
|
60
|
-
|
|
61
37
|
CLI entry:
|
|
62
38
|
|
|
63
39
|
```bash
|
|
64
40
|
codexs --help
|
|
65
41
|
```
|
|
66
42
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
codexs --help
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Quick Start | 快速开始
|
|
43
|
+
## Quick Start
|
|
74
44
|
|
|
75
45
|
Take over an existing Codex directory:
|
|
76
46
|
|
|
77
47
|
```bash
|
|
78
|
-
codexs
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
接管当前已有的 Codex 目录:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
codexs setup
|
|
48
|
+
codexs init
|
|
49
|
+
codexs migrate
|
|
85
50
|
```
|
|
86
51
|
|
|
87
52
|
Inspect managed providers:
|
|
@@ -91,13 +56,6 @@ codexs list
|
|
|
91
56
|
codexs show my-provider
|
|
92
57
|
```
|
|
93
58
|
|
|
94
|
-
查看已管理的 provider:
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
codexs list
|
|
98
|
-
codexs show my-provider
|
|
99
|
-
```
|
|
100
|
-
|
|
101
59
|
Add and switch:
|
|
102
60
|
|
|
103
61
|
```bash
|
|
@@ -105,13 +63,6 @@ codexs add my-provider --profile my-provider --api-key sk-xxx
|
|
|
105
63
|
codexs switch my-provider
|
|
106
64
|
```
|
|
107
65
|
|
|
108
|
-
新增并切换:
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
codexs add my-provider --profile my-provider --api-key sk-xxx
|
|
112
|
-
codexs switch my-provider
|
|
113
|
-
```
|
|
114
|
-
|
|
115
66
|
Check runtime state:
|
|
116
67
|
|
|
117
68
|
```bash
|
|
@@ -120,18 +71,11 @@ codexs status
|
|
|
120
71
|
codexs doctor
|
|
121
72
|
```
|
|
122
73
|
|
|
123
|
-
|
|
74
|
+
## Common Commands
|
|
124
75
|
|
|
125
76
|
```bash
|
|
126
|
-
codexs
|
|
127
|
-
codexs
|
|
128
|
-
codexs doctor
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Common Commands | 常用命令
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
codexs setup
|
|
77
|
+
codexs init
|
|
78
|
+
codexs migrate
|
|
135
79
|
codexs list
|
|
136
80
|
codexs show <provider>
|
|
137
81
|
codexs current
|
|
@@ -151,22 +95,15 @@ Command help:
|
|
|
151
95
|
|
|
152
96
|
```bash
|
|
153
97
|
codexs help switch
|
|
98
|
+
codexs help init
|
|
99
|
+
codexs help migrate
|
|
154
100
|
codexs help setup
|
|
155
101
|
```
|
|
156
102
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
codexs help switch
|
|
161
|
-
codexs help setup
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## How It Works | 工作方式
|
|
103
|
+
## How It Works
|
|
165
104
|
|
|
166
105
|
By default, `codex-switch` operates on `~/.codex/`, and you can override the target with `--codex-dir`.
|
|
167
106
|
|
|
168
|
-
`codex-switch` 默认围绕 `~/.codex/` 工作,也可以通过 `--codex-dir` 指向其他目录。
|
|
169
|
-
|
|
170
107
|
Managed files:
|
|
171
108
|
|
|
172
109
|
```text
|
|
@@ -177,23 +114,20 @@ Managed files:
|
|
|
177
114
|
backups/
|
|
178
115
|
```
|
|
179
116
|
|
|
180
|
-
|
|
117
|
+
Notes:
|
|
181
118
|
|
|
182
119
|
- `providers.json` is the managed provider registry
|
|
183
120
|
- `config.toml` and `auth.json` represent runtime state
|
|
184
121
|
- mutating commands back up before writing
|
|
185
122
|
- rollback is available after failed or undesired changes
|
|
186
123
|
|
|
187
|
-
|
|
188
|
-
- `config.toml` 和 `auth.json` 代表当前运行态
|
|
189
|
-
- 所有写操作都会先备份再写入
|
|
190
|
-
- 变更失败或结果不符合预期时可以回滚
|
|
191
|
-
|
|
192
|
-
## Automation | 自动化
|
|
124
|
+
## Automation
|
|
193
125
|
|
|
194
126
|
This CLI supports both human TTY use and non-interactive automation.
|
|
195
127
|
|
|
196
|
-
|
|
128
|
+
Current exceptions:
|
|
129
|
+
- `init` is automation-friendly and idempotent, but still returns a structured error in non-interactive or `--json` mode when the resolved target directory does not exist.
|
|
130
|
+
- `migrate` remains intentionally TTY-only for adopt initialization. It requires interactive profile selection and provider detail collection, and non-interactive/`--json` runs fail fast with a structured error.
|
|
197
131
|
|
|
198
132
|
Recommended global flags:
|
|
199
133
|
|
|
@@ -204,28 +138,38 @@ Recommended global flags:
|
|
|
204
138
|
--version
|
|
205
139
|
```
|
|
206
140
|
|
|
207
|
-
|
|
141
|
+
Recommendations:
|
|
208
142
|
|
|
209
143
|
- use `--json` for stable machine-readable output
|
|
210
144
|
- pass all required arguments explicitly in scripts or CI
|
|
211
145
|
- use `--codex-dir <path>` for sandbox or test environments
|
|
212
146
|
|
|
213
|
-
|
|
214
|
-
- 在非交互环境中显式传入所有必需参数
|
|
215
|
-
- 在测试环境中优先配合 `--codex-dir <path>` 使用
|
|
147
|
+
## Testing
|
|
216
148
|
|
|
217
|
-
|
|
149
|
+
Build and test locally:
|
|
218
150
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
151
|
+
```bash
|
|
152
|
+
npm run build
|
|
153
|
+
npm test
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The repository includes a development fixture under `dev-codex/local-sandbox` plus dedicated test docs:
|
|
157
|
+
|
|
158
|
+
- [Testing Guide](./docs/testing.md)
|
|
159
|
+
- [Test Report for 0.0.5](./docs/test-report-0.0.5.md)
|
|
160
|
+
|
|
161
|
+
## Documentation
|
|
162
|
+
|
|
163
|
+
- [Chinese README](./README.CN.md)
|
|
223
164
|
- [AI README](./README.AI.md)
|
|
224
|
-
- [
|
|
165
|
+
- [Detailed CLI Usage](./docs/cli-usage.md)
|
|
166
|
+
- [Testing Guide](./docs/testing.md)
|
|
167
|
+
- [Test Report for 0.0.5](./docs/test-report-0.0.5.md)
|
|
225
168
|
- [Product Overview](./docs/codex-switch-product-overview.md)
|
|
226
169
|
- [Technical Architecture](./docs/codex-switch-technical-architecture.md)
|
|
227
|
-
- [0.0.
|
|
170
|
+
- [Design Doc 0.0.5](./docs/Design/codex-switch-v0.0.5-design.md)
|
|
171
|
+
- [Design Doc 0.0.4](./docs/Design/codex-switch-v0.0.4-design.md)
|
|
228
172
|
|
|
229
|
-
## License
|
|
173
|
+
## License
|
|
230
174
|
|
|
231
175
|
MIT
|
package/dist/app/add-provider.js
CHANGED
|
@@ -4,9 +4,10 @@ exports.addProvider = addProvider;
|
|
|
4
4
|
const config_1 = require("../domain/config");
|
|
5
5
|
const providers_1 = require("../domain/providers");
|
|
6
6
|
const errors_1 = require("../domain/errors");
|
|
7
|
-
const config_repo_1 = require("../
|
|
8
|
-
const fs_utils_1 = require("../
|
|
9
|
-
const providers_repo_1 = require("../
|
|
7
|
+
const config_repo_1 = require("../storage/config-repo");
|
|
8
|
+
const fs_utils_1 = require("../storage/fs-utils");
|
|
9
|
+
const providers_repo_1 = require("../storage/providers-repo");
|
|
10
|
+
const auth_repo_1 = require("../storage/auth-repo");
|
|
10
11
|
const run_mutation_1 = require("./run-mutation");
|
|
11
12
|
/**
|
|
12
13
|
* Adds a new provider record to the managed providers registry.
|
|
@@ -19,6 +20,7 @@ function addProvider(args) {
|
|
|
19
20
|
}
|
|
20
21
|
const document = (0, config_repo_1.readStructuredConfig)(args.configPath);
|
|
21
22
|
const existingProfile = document.profiles.find((profile) => profile.name === args.profile);
|
|
23
|
+
const existingModelProvider = document.modelProviders.find((entry) => entry.name === args.profile);
|
|
22
24
|
if (!existingProfile && !args.createProfile) {
|
|
23
25
|
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Profile "${args.profile}" does not exist in config.toml.`, {
|
|
24
26
|
profile: args.profile,
|
|
@@ -29,16 +31,29 @@ function addProvider(args) {
|
|
|
29
31
|
? {
|
|
30
32
|
[args.profile]: (0, config_1.validateManagedProfileCreation)(args.profile, {
|
|
31
33
|
model: args.model ?? undefined,
|
|
32
|
-
|
|
34
|
+
modelProvider: args.profile,
|
|
33
35
|
}),
|
|
34
36
|
}
|
|
35
37
|
: undefined;
|
|
38
|
+
const upsertModelProviders = !existingModelProvider && args.createProfile
|
|
39
|
+
? {
|
|
40
|
+
[args.profile]: {
|
|
41
|
+
baseUrl: args.baseUrl ?? undefined,
|
|
42
|
+
envKey: (0, config_1.buildManagedProfileEnvKey)(args.profile),
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
: undefined;
|
|
46
|
+
if (existingProfile) {
|
|
47
|
+
(0, config_repo_1.requireManagedProfileRuntime)(document, providers, args.profile);
|
|
48
|
+
}
|
|
49
|
+
const envKey = existingModelProvider?.envKey ?? (0, config_1.buildManagedProfileEnvKey)(args.profile);
|
|
36
50
|
const next = {
|
|
37
51
|
providers: {
|
|
38
52
|
...providers.providers,
|
|
39
53
|
[args.providerName]: (0, providers_1.cleanProviderRecord)({
|
|
40
54
|
profile: args.profile,
|
|
41
55
|
apiKey: args.apiKey,
|
|
56
|
+
envKey,
|
|
42
57
|
baseUrl: args.baseUrl ?? undefined,
|
|
43
58
|
note: args.note ?? undefined,
|
|
44
59
|
tags: args.tags,
|
|
@@ -53,18 +68,27 @@ function addProvider(args) {
|
|
|
53
68
|
files: [
|
|
54
69
|
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
55
70
|
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
71
|
+
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
56
72
|
],
|
|
57
73
|
mutate: () => {
|
|
58
74
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
59
75
|
upsertProfiles,
|
|
76
|
+
upsertModelProviders,
|
|
60
77
|
});
|
|
61
78
|
// Persist only the normalized provider payload so later reads are deterministic.
|
|
62
79
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, next);
|
|
63
80
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
81
|
+
if (document.activeProfile === args.profile) {
|
|
82
|
+
const activeProviderName = (0, config_repo_1.resolveActiveProviderName)(document, next);
|
|
83
|
+
const existingAuth = (0, auth_repo_1.readAuthFileIfExists)(args.authPath);
|
|
84
|
+
(0, auth_repo_1.writeAuthFile)(args.authPath, next.providers[activeProviderName], existingAuth ?? undefined);
|
|
85
|
+
}
|
|
64
86
|
return {
|
|
65
87
|
provider: args.providerName,
|
|
66
88
|
profile: args.profile,
|
|
89
|
+
envKey,
|
|
67
90
|
createdProfileSections: configPlan.createdProfileSections,
|
|
91
|
+
createdModelProviderSections: configPlan.createdModelProviderSections,
|
|
68
92
|
deletedProfileSections: configPlan.deletedProfileSections,
|
|
69
93
|
keptSharedProfiles: [],
|
|
70
94
|
switchedActiveProfile: configPlan.switchedActiveProfile,
|
|
@@ -4,9 +4,10 @@ exports.editProvider = editProvider;
|
|
|
4
4
|
const errors_1 = require("../domain/errors");
|
|
5
5
|
const config_1 = require("../domain/config");
|
|
6
6
|
const providers_1 = require("../domain/providers");
|
|
7
|
-
const config_repo_1 = require("../
|
|
8
|
-
const fs_utils_1 = require("../
|
|
9
|
-
const providers_repo_1 = require("../
|
|
7
|
+
const config_repo_1 = require("../storage/config-repo");
|
|
8
|
+
const fs_utils_1 = require("../storage/fs-utils");
|
|
9
|
+
const providers_repo_1 = require("../storage/providers-repo");
|
|
10
|
+
const auth_repo_1 = require("../storage/auth-repo");
|
|
10
11
|
const run_mutation_1 = require("./run-mutation");
|
|
11
12
|
/**
|
|
12
13
|
* Updates selected fields on a single managed provider.
|
|
@@ -23,13 +24,7 @@ function editProvider(args) {
|
|
|
23
24
|
});
|
|
24
25
|
}
|
|
25
26
|
const updatedFields = [];
|
|
26
|
-
const
|
|
27
|
-
profile: args.profile ?? current.profile,
|
|
28
|
-
apiKey: args.apiKey ?? current.apiKey,
|
|
29
|
-
baseUrl: args.baseUrl === null ? undefined : args.baseUrl ?? current.baseUrl,
|
|
30
|
-
note: args.note === null ? undefined : args.note ?? current.note,
|
|
31
|
-
tags: args.tags ?? current.tags,
|
|
32
|
-
});
|
|
27
|
+
const nextProfile = args.profile ?? current.profile;
|
|
33
28
|
if (args.profile !== undefined && args.profile !== current.profile) {
|
|
34
29
|
updatedFields.push("profile");
|
|
35
30
|
}
|
|
@@ -46,10 +41,12 @@ function editProvider(args) {
|
|
|
46
41
|
updatedFields.push("tags");
|
|
47
42
|
}
|
|
48
43
|
const oldProfile = current.profile;
|
|
49
|
-
const newProfile =
|
|
44
|
+
const newProfile = nextProfile;
|
|
50
45
|
const targetSection = document.profiles.find((profile) => profile.name === newProfile) ?? null;
|
|
46
|
+
const targetModelProviderSection = document.modelProviders.find((entry) => entry.name === newProfile) ?? null;
|
|
51
47
|
const targetProfileExists = Boolean(targetSection);
|
|
52
48
|
let upsertProfiles;
|
|
49
|
+
let upsertModelProviders;
|
|
53
50
|
if (!targetProfileExists) {
|
|
54
51
|
if (!args.createProfile) {
|
|
55
52
|
throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Profile "${newProfile}" does not exist in config.toml.`, {
|
|
@@ -60,24 +57,44 @@ function editProvider(args) {
|
|
|
60
57
|
upsertProfiles = {
|
|
61
58
|
[newProfile]: (0, config_1.validateManagedProfileCreation)(newProfile, {
|
|
62
59
|
model: args.model ?? undefined,
|
|
63
|
-
|
|
60
|
+
modelProvider: newProfile,
|
|
64
61
|
}),
|
|
65
62
|
};
|
|
63
|
+
upsertModelProviders = {
|
|
64
|
+
[newProfile]: {
|
|
65
|
+
baseUrl: args.baseUrl ?? undefined,
|
|
66
|
+
envKey: (0, config_1.buildManagedProfileEnvKey)(newProfile),
|
|
67
|
+
},
|
|
68
|
+
};
|
|
66
69
|
}
|
|
67
|
-
else
|
|
70
|
+
else {
|
|
71
|
+
(0, config_repo_1.requireManagedProfileRuntime)(document, providers, newProfile);
|
|
72
|
+
}
|
|
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
|
+
const nextRecord = (0, providers_1.cleanProviderRecord)({
|
|
80
|
+
profile: newProfile,
|
|
81
|
+
apiKey: args.apiKey ?? current.apiKey,
|
|
82
|
+
envKey: nextEnvKey,
|
|
83
|
+
baseUrl: args.baseUrl === null ? undefined : args.baseUrl ?? current.baseUrl,
|
|
84
|
+
note: args.note === null ? undefined : args.note ?? current.note,
|
|
85
|
+
tags: args.tags ?? current.tags,
|
|
86
|
+
});
|
|
87
|
+
if (targetProfileExists && args.model !== undefined) {
|
|
68
88
|
upsertProfiles = {
|
|
69
89
|
[newProfile]: {
|
|
70
90
|
...(args.model !== undefined && args.model !== null ? { model: args.model } : {}),
|
|
71
|
-
...(args.baseUrl !== undefined && args.baseUrl !== null ? { baseUrl: args.baseUrl } : {}),
|
|
72
91
|
},
|
|
73
92
|
};
|
|
74
93
|
if (args.model !== undefined && (targetSection?.model !== args.model) && !updatedFields.includes("model")) {
|
|
75
94
|
updatedFields.push("model");
|
|
76
95
|
}
|
|
77
|
-
if (args.baseUrl !== undefined && targetSection?.baseUrl !== args.baseUrl && !updatedFields.includes("baseUrl")) {
|
|
78
|
-
updatedFields.push("baseUrl");
|
|
79
|
-
}
|
|
80
96
|
}
|
|
97
|
+
// Compute profile link ownership after the edit so lifecycle planning can decide whether sections stay, move, or delete.
|
|
81
98
|
const remainingLinksByProfile = new Map();
|
|
82
99
|
for (const [name, provider] of Object.entries(providers.providers)) {
|
|
83
100
|
if (name === args.providerName) {
|
|
@@ -108,24 +125,35 @@ function editProvider(args) {
|
|
|
108
125
|
files: [
|
|
109
126
|
{ absolutePath: args.providersPath, relativePath: "providers.json" },
|
|
110
127
|
{ absolutePath: args.configPath, relativePath: "config.toml" },
|
|
128
|
+
{ absolutePath: args.authPath, relativePath: "auth.json" },
|
|
111
129
|
],
|
|
112
130
|
mutate: () => {
|
|
113
131
|
const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
|
|
114
132
|
upsertProfiles,
|
|
133
|
+
upsertModelProviders,
|
|
115
134
|
deleteProfiles: lifecycle.deletedProfileSections,
|
|
116
135
|
setActiveProfile: lifecycle.nextActiveProfile,
|
|
117
136
|
});
|
|
118
|
-
|
|
137
|
+
const nextProviders = {
|
|
119
138
|
providers: {
|
|
120
139
|
...providers.providers,
|
|
121
140
|
[args.providerName]: nextRecord,
|
|
122
141
|
},
|
|
123
|
-
}
|
|
142
|
+
};
|
|
143
|
+
// Write providers first so the registry and config move together inside the managed backup boundary.
|
|
144
|
+
(0, providers_repo_1.writeProvidersFile)(args.providersPath, nextProviders);
|
|
124
145
|
(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
|
+
}
|
|
125
152
|
return {
|
|
126
153
|
provider: args.providerName,
|
|
127
154
|
updatedFields,
|
|
128
155
|
createdProfileSections: configPlan.createdProfileSections,
|
|
156
|
+
createdModelProviderSections: configPlan.createdModelProviderSections,
|
|
129
157
|
deletedProfileSections: configPlan.deletedProfileSections,
|
|
130
158
|
keptSharedProfiles: lifecycle.keptSharedProfiles,
|
|
131
159
|
switchedActiveProfile: lifecycle.switchedActiveProfile,
|
|
@@ -37,8 +37,8 @@ exports.exportProviders = exportProviders;
|
|
|
37
37
|
const fs = __importStar(require("node:fs"));
|
|
38
38
|
const path = __importStar(require("node:path"));
|
|
39
39
|
const errors_1 = require("../domain/errors");
|
|
40
|
-
const fs_utils_1 = require("../
|
|
41
|
-
const providers_repo_1 = require("../
|
|
40
|
+
const fs_utils_1 = require("../storage/fs-utils");
|
|
41
|
+
const providers_repo_1 = require("../storage/providers-repo");
|
|
42
42
|
/**
|
|
43
43
|
* Exports the current providers registry to a user-specified file.
|
|
44
44
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCurrentProfile = getCurrentProfile;
|
|
4
|
-
const config_repo_1 = require("../
|
|
4
|
+
const config_repo_1 = require("../storage/config-repo");
|
|
5
5
|
/**
|
|
6
6
|
* Returns the currently active top-level Codex profile.
|
|
7
7
|
*/
|
package/dist/app/get-status.js
CHANGED
|
@@ -37,12 +37,14 @@ exports.getStatus = getStatus;
|
|
|
37
37
|
const fs = __importStar(require("node:fs"));
|
|
38
38
|
const config_1 = require("../domain/config");
|
|
39
39
|
const runtime_state_1 = require("../domain/runtime-state");
|
|
40
|
-
const
|
|
41
|
-
const
|
|
40
|
+
const providers_1 = require("../domain/providers");
|
|
41
|
+
const config_repo_1 = require("../storage/config-repo");
|
|
42
|
+
const providers_repo_1 = require("../storage/providers-repo");
|
|
43
|
+
const auth_repo_1 = require("../storage/auth-repo");
|
|
42
44
|
/**
|
|
43
45
|
* Reports the current on-disk runtime state and how it maps back to managed providers.
|
|
44
46
|
*/
|
|
45
|
-
function getStatus(codexDir, configPath, providersPath) {
|
|
47
|
+
function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
46
48
|
const configExists = fs.existsSync(configPath);
|
|
47
49
|
const providersExists = fs.existsSync(providersPath);
|
|
48
50
|
let currentProfile = null;
|
|
@@ -50,6 +52,7 @@ function getStatus(codexDir, configPath, providersPath) {
|
|
|
50
52
|
const providers = providersExists ? (0, providers_repo_1.readProvidersFile)(providersPath) : null;
|
|
51
53
|
let configViews = [];
|
|
52
54
|
let consistencyIssues = [];
|
|
55
|
+
const authState = (0, auth_repo_1.readManagedAuthState)(authPath);
|
|
53
56
|
if (configExists) {
|
|
54
57
|
const document = (0, config_repo_1.readStructuredConfig)(configPath);
|
|
55
58
|
currentProfile = document.activeProfile;
|
|
@@ -60,6 +63,7 @@ function getStatus(codexDir, configPath, providersPath) {
|
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
const liveState = (0, runtime_state_1.inspectLiveStateDrift)(currentProfile, providers);
|
|
66
|
+
const activeProviderCandidates = currentProfile && providers ? (0, providers_1.findProvidersByProfile)(providers, currentProfile) : [];
|
|
63
67
|
if (liveState.canBackfillActiveProvider) {
|
|
64
68
|
// Surface unmanaged live state without mutating anything during a read-only status call.
|
|
65
69
|
warnings.push("Current config profile is not mapped in providers.json. Backfill would be required before treating live state as managed.");
|
|
@@ -74,7 +78,10 @@ function getStatus(codexDir, configPath, providersPath) {
|
|
|
74
78
|
currentProfile,
|
|
75
79
|
currentProfileMapped: liveState.profileMapped,
|
|
76
80
|
provider: liveState.mappedProvider,
|
|
81
|
+
activeProviderResolvable: activeProviderCandidates.length === 1,
|
|
82
|
+
activeProviderCandidates,
|
|
77
83
|
liveState,
|
|
84
|
+
auth: authState,
|
|
78
85
|
configProfiles: configViews,
|
|
79
86
|
issues: consistencyIssues,
|
|
80
87
|
},
|
|
@@ -39,9 +39,9 @@ const path = __importStar(require("node:path"));
|
|
|
39
39
|
const config_1 = require("../domain/config");
|
|
40
40
|
const providers_1 = require("../domain/providers");
|
|
41
41
|
const errors_1 = require("../domain/errors");
|
|
42
|
-
const config_repo_1 = require("../
|
|
43
|
-
const fs_utils_1 = require("../
|
|
44
|
-
const providers_repo_1 = require("../
|
|
42
|
+
const config_repo_1 = require("../storage/config-repo");
|
|
43
|
+
const fs_utils_1 = require("../storage/fs-utils");
|
|
44
|
+
const providers_repo_1 = require("../storage/providers-repo");
|
|
45
45
|
const run_mutation_1 = require("./run-mutation");
|
|
46
46
|
/**
|
|
47
47
|
* Imports provider definitions from an external JSON file into the managed registry.
|
|
@@ -83,13 +83,21 @@ function importProviders(args) {
|
|
|
83
83
|
const missingViews = nextViews.filter((view) => view.source === "orphaned-reference");
|
|
84
84
|
const repairedProfiles = [];
|
|
85
85
|
const upsertProfiles = missingViews.reduce((accumulator, view) => {
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
88
|
-
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", "Import would create provider references to missing config profiles that need model and
|
|
86
|
+
const sourceView = currentViews.find((entry) => entry.name === view.name) ?? null;
|
|
87
|
+
if (!sourceView?.model) {
|
|
88
|
+
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", "Import would create provider references to missing config profiles that need model and matching model_provider sections.", {
|
|
89
89
|
profilesNeedingRepair: missingViews.map((entry) => entry.name).sort(),
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
-
|
|
92
|
+
if (sourceView.modelProvider !== view.name || !sourceView.baseUrl) {
|
|
93
|
+
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", "Import would create provider references to missing config profiles without matching model_provider runtime sections.", {
|
|
94
|
+
profilesNeedingRepair: missingViews.map((entry) => entry.name).sort(),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
accumulator[view.name] = (0, config_1.validateManagedProfileCreation)(view.name, {
|
|
98
|
+
model: sourceView.model,
|
|
99
|
+
modelProvider: view.name,
|
|
100
|
+
});
|
|
93
101
|
repairedProfiles.push(view.name);
|
|
94
102
|
return accumulator;
|
|
95
103
|
}, {});
|
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.initCodex = initCodex;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const errors_1 = require("../domain/errors");
|
|
39
|
+
const fs_utils_1 = require("../storage/fs-utils");
|
|
40
|
+
const providers_repo_1 = require("../storage/providers-repo");
|
|
41
|
+
/**
|
|
42
|
+
* Initializes a Codex directory for managed providers.json usage without requiring live Codex state.
|
|
43
|
+
*/
|
|
44
|
+
function initCodex(args) {
|
|
45
|
+
const codexDirExists = fs.existsSync(args.codexDir);
|
|
46
|
+
if (!codexDirExists && !args.createCodexDir) {
|
|
47
|
+
throw (0, errors_1.cliError)("CODEX_DIR_NOT_FOUND", "The requested Codex directory does not exist.", {
|
|
48
|
+
codexDir: args.codexDir,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (!codexDirExists) {
|
|
52
|
+
(0, fs_utils_1.ensureDir)(args.codexDir);
|
|
53
|
+
}
|
|
54
|
+
const providersExists = fs.existsSync(args.providersPath);
|
|
55
|
+
if (!providersExists) {
|
|
56
|
+
(0, providers_repo_1.writeProvidersFile)(args.providersPath, { providers: {} });
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
data: {
|
|
60
|
+
codexDir: args.codexDir,
|
|
61
|
+
createdCodexDir: !codexDirExists,
|
|
62
|
+
createdProvidersFile: !providersExists,
|
|
63
|
+
providersAlreadyExisted: providersExists,
|
|
64
|
+
configExists: fs.existsSync(args.configPath),
|
|
65
|
+
authExists: fs.existsSync(args.authPath),
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
package/dist/app/list-backups.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listBackupEntries = listBackupEntries;
|
|
4
|
-
const backup_repo_1 = require("../
|
|
4
|
+
const backup_repo_1 = require("../storage/backup-repo");
|
|
5
5
|
/**
|
|
6
6
|
* Lists backup manifests available under the managed Codex backups directory.
|
|
7
7
|
*/
|