@minniexcode/codex-switch 0.1.5 → 0.2.2
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 +66 -94
- package/README.CN.md +84 -139
- package/README.md +91 -151
- package/dist/app/add-provider.js +6 -89
- package/dist/app/edit-provider.js +9 -29
- package/dist/app/get-status.js +1 -74
- package/dist/app/list-providers.js +0 -2
- package/dist/app/remove-provider.js +3 -5
- package/dist/app/run-doctor.js +2 -100
- package/dist/app/setup-codex.js +0 -2
- package/dist/app/switch-provider.js +1 -79
- package/dist/cli/output.js +3 -89
- package/dist/commands/handlers.js +20 -209
- package/dist/commands/help.js +1 -4
- package/dist/commands/registry.js +6 -74
- package/dist/domain/config.js +1 -3
- package/dist/domain/providers.js +4 -92
- package/dist/domain/runtime-state.js +0 -88
- package/dist/interaction/add-interactive.js +1 -55
- package/dist/interaction/interactive.js +1 -3
- package/dist/runtime/codex-probe.js +0 -12
- package/dist/storage/codex-paths.js +0 -2
- package/docs/Design/codex-switch-v0.2.0-design.md +56 -0
- package/docs/Design/codex-switch-v0.2.1-design.md +77 -0
- package/docs/PRD/codex-switch-prd-v0.2.1.md +82 -0
- package/docs/Tests/testing.md +32 -34
- package/docs/cli-usage.md +67 -235
- package/docs/codex-switch-command-design.md +1 -1
- package/docs/codex-switch-product-overview.md +49 -96
- package/docs/codex-switch-technical-architecture.md +37 -52
- package/package.json +1 -1
- package/dist/app/bridge.js +0 -308
- package/dist/runtime/copilot-adapter.js +0 -612
- package/dist/runtime/copilot-bridge-worker.js +0 -69
- package/dist/runtime/copilot-bridge.js +0 -1318
- package/dist/runtime/copilot-cli.js +0 -164
- package/dist/runtime/copilot-installer.js +0 -231
- package/dist/runtime/copilot-sdk-loader.js +0 -62
- package/dist/storage/runtime-state-repo.js +0 -121
package/README.md
CHANGED
|
@@ -1,162 +1,112 @@
|
|
|
1
|
-
#
|
|
1
|
+
# codex-switch
|
|
2
2
|
|
|
3
|
-
`@minniexcode/codex-switch` is a local-first
|
|
3
|
+
`@minniexcode/codex-switch` is a local-first provider/model-provider management CLI for Codex.
|
|
4
4
|
|
|
5
|
-
It keeps `codex-switch` tool state separate from the target Codex
|
|
5
|
+
It keeps `codex-switch` tool state separate from the target Codex directory, so managed providers, backups, and Codex `model_provider` projection are handled through explicit commands instead of manual file edits.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Current package version: `0.2.1`
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Current package version: `0.1.5`
|
|
12
|
-
|
|
13
|
-
This is the current repository development line. `0.1.5` is a Copilot Bridge process-visibility patch, focused on streaming commentary/reasoning signals, defensive SDK-event normalization, and safer redaction for unknown runtime events while keeping the provider surface unchanged.
|
|
9
|
+
`0.2.1` is the current repository development line. It is a provider-management-only consolidation release: direct OpenAI-compatible provider records are managed locally and projected into Codex config/auth files. This version does not include the previous account-login, local bridge, or background runtime experiments.
|
|
14
10
|
|
|
15
11
|
## Install
|
|
16
12
|
|
|
17
13
|
```bash
|
|
18
14
|
npm install -g @minniexcode/codex-switch
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Run without a global install:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npx @minniexcode/codex-switch --help
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Built CLI entrypoint:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
15
|
codexs --help
|
|
31
16
|
```
|
|
32
17
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Direct provider workflow:
|
|
18
|
+
For local development:
|
|
36
19
|
|
|
37
20
|
```bash
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
codexs status
|
|
42
|
-
codexs doctor
|
|
21
|
+
npm install
|
|
22
|
+
npm run build
|
|
23
|
+
node dist/cli.js --help
|
|
43
24
|
```
|
|
44
25
|
|
|
45
|
-
|
|
26
|
+
Node.js `>=18` is required.
|
|
27
|
+
|
|
28
|
+
## Primary Workflow
|
|
46
29
|
|
|
47
30
|
```bash
|
|
48
31
|
codexs init
|
|
49
|
-
codexs
|
|
50
|
-
codexs
|
|
51
|
-
codexs switch copilot-main
|
|
32
|
+
codexs add packycode --profile packycode --model gpt-5 --api-key sk-xxx --base-url https://api.example/v1
|
|
33
|
+
codexs switch packycode
|
|
52
34
|
codexs status
|
|
53
35
|
codexs doctor
|
|
54
36
|
```
|
|
55
37
|
|
|
56
|
-
|
|
38
|
+
What the workflow does:
|
|
57
39
|
|
|
58
|
-
- `init`
|
|
59
|
-
- `
|
|
60
|
-
- `
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
- `switch` projects the selected provider into the target Codex runtime as top-level `model` plus `model_provider`.
|
|
64
|
-
- `status` is the main read command after switching.
|
|
65
|
-
- `doctor` is the main repair-oriented diagnostic command.
|
|
40
|
+
- `init` creates the `codex-switch` tool home files.
|
|
41
|
+
- `add` stores a managed provider in `providers.json` and creates or updates the matching `[model_providers.<id>]` projection in `config.toml`.
|
|
42
|
+
- `switch` writes top-level `model` and `model_provider` in the target Codex config and projects `OPENAI_API_KEY` into `auth.json`.
|
|
43
|
+
- `status` summarizes current mapping, auth projection, and drift.
|
|
44
|
+
- `doctor` reports issue-first diagnostics.
|
|
66
45
|
|
|
67
|
-
|
|
46
|
+
`--profile` is a CLI alias for the managed Codex `model_provider` id. It is not the legacy Codex top-level `profile` selector.
|
|
68
47
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
`codex-switch` treats that route as the runtime contract:
|
|
72
|
-
|
|
73
|
-
- top-level `model` selects the active model id
|
|
74
|
-
- top-level `model_provider` selects the active provider route
|
|
75
|
-
- managed `[model_providers.<id>]` entries are the projected runtime provider definitions
|
|
76
|
-
- `--profile` is only an alias for the managed `model_provider` id, not the primary runtime selector
|
|
77
|
-
|
|
78
|
-
Direct-provider projection writes:
|
|
79
|
-
|
|
80
|
-
- top-level `model`
|
|
81
|
-
- top-level `model_provider`
|
|
82
|
-
- `[model_providers.<id>]`
|
|
83
|
-
- `auth.json` with `OPENAI_API_KEY`
|
|
84
|
-
|
|
85
|
-
Managed direct-provider projection does not keep `env_key` or `env_key_instructions` in the generated runtime config. `switch`, `add`, and `edit` clean old legacy projection fields before writing the active route.
|
|
86
|
-
|
|
87
|
-
For managed OpenAI-compatible routes, the projected provider entry keeps the fixed runtime shape:
|
|
88
|
-
|
|
89
|
-
```toml
|
|
90
|
-
model = "gpt-5.5"
|
|
91
|
-
model_provider = "my-provider"
|
|
92
|
-
|
|
93
|
-
[model_providers.my-provider]
|
|
94
|
-
name = "my-provider"
|
|
95
|
-
base_url = "https://gateway.example.com/v1"
|
|
96
|
-
wire_api = "responses"
|
|
97
|
-
requires_openai_auth = true
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Managed Copilot projection additionally writes:
|
|
101
|
-
|
|
102
|
-
```toml
|
|
103
|
-
stream_idle_timeout_ms = 300000
|
|
104
|
-
```
|
|
48
|
+
## Commands
|
|
105
49
|
|
|
106
|
-
|
|
50
|
+
Current `0.2.1` command surface:
|
|
107
51
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
codexs init
|
|
112
|
-
codexs migrate
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
`migrate` is an advanced adopt helper. It is not the default first step for a fresh install.
|
|
116
|
-
|
|
117
|
-
## Command Surface
|
|
118
|
-
|
|
119
|
-
```bash
|
|
52
|
+
```text
|
|
120
53
|
codexs init
|
|
121
|
-
codexs login copilot
|
|
122
54
|
codexs migrate
|
|
123
55
|
codexs list
|
|
124
56
|
codexs show <provider>
|
|
125
57
|
codexs current
|
|
126
58
|
codexs status
|
|
127
|
-
codexs config show
|
|
59
|
+
codexs config show
|
|
128
60
|
codexs config list-profiles
|
|
129
61
|
codexs add <provider> --profile <model-provider-id> --model <model> --api-key <key> [--base-url <url>]
|
|
130
|
-
codexs
|
|
131
|
-
codexs edit <provider>
|
|
62
|
+
codexs edit <provider> [options]
|
|
132
63
|
codexs switch <provider>
|
|
133
|
-
codexs remove <provider>
|
|
64
|
+
codexs remove <provider> --force
|
|
134
65
|
codexs import <file>
|
|
135
|
-
codexs export <file>
|
|
136
|
-
codexs bridge start [provider]
|
|
137
|
-
codexs bridge status [provider]
|
|
138
|
-
codexs bridge stop [provider]
|
|
66
|
+
codexs export <file>
|
|
139
67
|
codexs backups list
|
|
140
68
|
codexs rollback [backup-id]
|
|
141
69
|
codexs doctor
|
|
70
|
+
codexs setup
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`setup` is deprecated and exists only as a pointer to `init` for fresh state or `migrate` for advanced adoption of existing Codex config.
|
|
74
|
+
|
|
75
|
+
All commands accept `--json` for the standard JSON envelope where supported by the parser, and `--codex-dir <path>` to target a specific Codex directory.
|
|
76
|
+
|
|
77
|
+
## Runtime Projection
|
|
78
|
+
|
|
79
|
+
For Codex `0.134.0+`, the active route is the top-level `model` and `model_provider` in `config.toml`.
|
|
80
|
+
|
|
81
|
+
Managed OpenAI-compatible provider projection uses this shape:
|
|
82
|
+
|
|
83
|
+
```toml
|
|
84
|
+
model = "gpt-5"
|
|
85
|
+
model_provider = "packycode"
|
|
86
|
+
|
|
87
|
+
[model_providers.packycode]
|
|
88
|
+
name = "packycode"
|
|
89
|
+
base_url = "https://api.example/v1"
|
|
90
|
+
wire_api = "responses"
|
|
91
|
+
requires_openai_auth = true
|
|
142
92
|
```
|
|
143
93
|
|
|
144
|
-
`
|
|
94
|
+
`codex-switch` intentionally does not write legacy `[profiles.*]` sections for new managed providers, and it removes legacy `env_key`/`env_key_instructions` fields from managed model-provider projections when it writes them.
|
|
95
|
+
|
|
96
|
+
Authentication is projected into the target Codex `auth.json` as API-key mode with `OPENAI_API_KEY`. Do not commit real keys or private provider exports.
|
|
145
97
|
|
|
146
|
-
##
|
|
98
|
+
## Managed State
|
|
147
99
|
|
|
148
100
|
Tool home:
|
|
149
101
|
|
|
150
102
|
```text
|
|
151
|
-
~/.
|
|
103
|
+
~/.codex-switch/
|
|
152
104
|
codex-switch.json
|
|
153
105
|
providers.json
|
|
154
106
|
backups/
|
|
155
|
-
runtime/
|
|
156
|
-
runtimes/
|
|
157
107
|
```
|
|
158
108
|
|
|
159
|
-
Target Codex
|
|
109
|
+
Target Codex directory:
|
|
160
110
|
|
|
161
111
|
```text
|
|
162
112
|
~/.codex/
|
|
@@ -164,66 +114,56 @@ Target Codex runtime:
|
|
|
164
114
|
auth.json
|
|
165
115
|
```
|
|
166
116
|
|
|
167
|
-
|
|
117
|
+
Environment variables:
|
|
168
118
|
|
|
169
|
-
- `
|
|
170
|
-
- `
|
|
171
|
-
- `
|
|
172
|
-
- `auth.json` remains the active auth projection file in the target Codex directory.
|
|
173
|
-
- Direct providers rewrite `OPENAI_API_KEY` into the active runtime projection.
|
|
174
|
-
- Copilot providers keep upstream GitHub authentication in the official Copilot runtime while `codex-switch` manages local bridge state and routing.
|
|
119
|
+
- `CODEXS_HOME` overrides the `codex-switch` tool home.
|
|
120
|
+
- `CODEXS_CODEX_DIR` provides the default target Codex directory when `--codex-dir` is not passed.
|
|
121
|
+
- In development, `NODE_ENV=development` defaults to `./dev-codex/local-sandbox` when no override is set.
|
|
175
122
|
|
|
176
|
-
|
|
123
|
+
## Migration And Adoption
|
|
177
124
|
|
|
178
|
-
|
|
179
|
-
- `CODEXS_CODEX_DIR` provides the default target runtime when `--codex-dir` is not passed.
|
|
180
|
-
- `CODEXS_HOME` overrides the tool home location.
|
|
125
|
+
Use `migrate` only when you already have Codex runtime config that should be adopted into managed `providers.json` state. It is not the default fresh-install command.
|
|
181
126
|
|
|
182
|
-
|
|
127
|
+
```bash
|
|
128
|
+
codexs migrate
|
|
129
|
+
codexs migrate --overwrite --codex-dir ~/.codex
|
|
130
|
+
```
|
|
183
131
|
|
|
184
|
-
|
|
132
|
+
The development-version policy applies to `0.2.1`: old local experimental state is not automatically migrated. Clean up or re-add providers manually when moving from an older local experiment.
|
|
185
133
|
|
|
186
|
-
|
|
134
|
+
## Current Non-Goals
|
|
187
135
|
|
|
188
|
-
|
|
189
|
-
--json
|
|
190
|
-
--codex-dir <path>
|
|
191
|
-
--help
|
|
192
|
-
--version
|
|
193
|
-
```
|
|
136
|
+
`0.2.1` does not implement or reserve runtime code paths for:
|
|
194
137
|
|
|
195
|
-
|
|
138
|
+
- GitHub Copilot SDK integration.
|
|
139
|
+
- GitHub device-flow login.
|
|
140
|
+
- `login copilot`.
|
|
141
|
+
- `add --copilot`.
|
|
142
|
+
- HTTP proxy bridge or local bridge worker commands.
|
|
143
|
+
- Background runtime services, bridge logs, or bridge runtime state.
|
|
144
|
+
- Built-in third-party router packaging.
|
|
145
|
+
- Account systems or cloud sync.
|
|
146
|
+
- Automatic migration of old Copilot or bridge state.
|
|
196
147
|
|
|
197
|
-
-
|
|
198
|
-
- `migrate` remains interactive when provider adoption requires human input.
|
|
199
|
-
- Automation should pass explicit arguments and prefer `--json` for stable parsing.
|
|
148
|
+
A future release may integrate a third-party router-like capability, but `0.2.1` makes no workflow, schema, or runtime guarantee for that.
|
|
200
149
|
|
|
201
|
-
##
|
|
150
|
+
## Development
|
|
202
151
|
|
|
203
152
|
```bash
|
|
204
153
|
npm run build
|
|
205
|
-
npm test
|
|
206
154
|
npx tsc --noEmit
|
|
155
|
+
npm test
|
|
207
156
|
node dist/cli.js --help
|
|
157
|
+
node dist/cli.js --version
|
|
208
158
|
npm pack --dry-run
|
|
209
159
|
```
|
|
210
160
|
|
|
211
|
-
##
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
- [
|
|
216
|
-
- [
|
|
217
|
-
- [
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
- [PRD 0.1.2](./docs/PRD/codex-switch-prd-v0.1.2.md)
|
|
221
|
-
- [PRD 0.1.3](./docs/PRD/codex-switch-prd-v0.1.3.md)
|
|
222
|
-
- [PRD 0.1.5](./docs/PRD/codex-switch-prd-v0.1.5.md)
|
|
223
|
-
- [Design 0.1.2](./docs/Design/codex-switch-v0.1.2-design.md)
|
|
224
|
-
- [Design 0.1.3](./docs/Design/codex-switch-v0.1.3-design.md)
|
|
225
|
-
- [Design 0.1.5](./docs/Design/codex-switch-v0.1.5-design.md)
|
|
226
|
-
|
|
227
|
-
## License
|
|
228
|
-
|
|
229
|
-
MIT
|
|
161
|
+
## Fact Sources
|
|
162
|
+
|
|
163
|
+
Current fact sources:
|
|
164
|
+
|
|
165
|
+
- [PRD 0.2.1](./docs/PRD/codex-switch-prd-v0.2.1.md)
|
|
166
|
+
- [Design 0.2.1](./docs/Design/codex-switch-v0.2.1-design.md)
|
|
167
|
+
- [CLI usage](./docs/cli-usage.md)
|
|
168
|
+
|
|
169
|
+
Historical documents remain under `docs/PRD/` and `docs/Design/` for context only.
|
package/dist/app/add-provider.js
CHANGED
|
@@ -1,47 +1,11 @@
|
|
|
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
3
|
exports.addProvider = addProvider;
|
|
37
|
-
const crypto = __importStar(require("node:crypto"));
|
|
38
4
|
const providers_1 = require("../domain/providers");
|
|
39
5
|
const errors_1 = require("../domain/errors");
|
|
40
6
|
const config_repo_1 = require("../storage/config-repo");
|
|
41
7
|
const fs_utils_1 = require("../storage/fs-utils");
|
|
42
8
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
43
|
-
const copilot_adapter_1 = require("../runtime/copilot-adapter");
|
|
44
|
-
const copilot_installer_1 = require("../runtime/copilot-installer");
|
|
45
9
|
const run_mutation_1 = require("./run-mutation");
|
|
46
10
|
/**
|
|
47
11
|
* Adds a new provider record to the managed providers registry.
|
|
@@ -52,44 +16,6 @@ async function addProvider(args) {
|
|
|
52
16
|
if (providers.providers[args.providerName]) {
|
|
53
17
|
throw (0, errors_1.cliError)("INVALID_IMPORT_FILE", `Provider "${args.providerName}" already exists.`);
|
|
54
18
|
}
|
|
55
|
-
const bridgeHost = args.bridgeHost ?? "127.0.0.1";
|
|
56
|
-
const bridgePort = args.bridgePort ?? 41415;
|
|
57
|
-
const runtime = args.copilot
|
|
58
|
-
? {
|
|
59
|
-
kind: "copilot-sdk-bridge",
|
|
60
|
-
upstream: "github-copilot",
|
|
61
|
-
bridgeHost,
|
|
62
|
-
bridgePort,
|
|
63
|
-
bridgePath: "/v1",
|
|
64
|
-
premiumRequests: true,
|
|
65
|
-
authSource: "official-sdk",
|
|
66
|
-
sdkInstallMode: "lazy",
|
|
67
|
-
}
|
|
68
|
-
: undefined;
|
|
69
|
-
if (args.copilot) {
|
|
70
|
-
(0, copilot_installer_1.assertCopilotNodeRuntimeSupported)();
|
|
71
|
-
const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)(args.runtimesDir);
|
|
72
|
-
if (!installStatus.installed) {
|
|
73
|
-
throw (0, errors_1.cliError)("COPILOT_SDK_MISSING", "The optional Copilot SDK runtime is not installed. Run `codexs login copilot` first.", {
|
|
74
|
-
installDir: installStatus.installDir,
|
|
75
|
-
packageName: installStatus.packageName,
|
|
76
|
-
suggestion: "Run `codexs login copilot` to install the Copilot SDK and complete login.",
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
await (0, copilot_adapter_1.readCopilotAuthState)(args.runtimesDir);
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
const normalized = (0, errors_1.normalizeError)(error);
|
|
84
|
-
if (normalized.code === "COPILOT_AUTH_REQUIRED") {
|
|
85
|
-
throw (0, errors_1.cliError)("COPILOT_AUTH_REQUIRED", "Copilot authentication is required before a Copilot provider can be added.", {
|
|
86
|
-
...(normalized.details ?? {}),
|
|
87
|
-
suggestion: "Run `codexs login copilot` to complete GitHub Copilot login.",
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
throw error;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
19
|
const document = (0, config_repo_1.readStructuredConfig)(args.configPath);
|
|
94
20
|
const existingModelProvider = document.modelProviders.find((entry) => entry.name === args.profile);
|
|
95
21
|
const inheritedModel = document.currentModel ?? undefined;
|
|
@@ -103,33 +29,26 @@ async function addProvider(args) {
|
|
|
103
29
|
});
|
|
104
30
|
}
|
|
105
31
|
const directBaseUrl = args.baseUrl;
|
|
106
|
-
if (
|
|
32
|
+
if ((!directBaseUrl || directBaseUrl.trim() === "") && !existingModelProvider) {
|
|
107
33
|
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Model provider "${args.profile}" requires base_url.`, {
|
|
108
34
|
profile: args.profile,
|
|
109
35
|
modelProvider: args.profile,
|
|
110
36
|
missingFields: ["base_url"],
|
|
111
37
|
});
|
|
112
38
|
}
|
|
113
|
-
const upsertModelProviders =
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
: {
|
|
118
|
-
[args.profile]: (0, providers_1.buildDirectModelProviderProjection)(args.profile, (directBaseUrl ?? existingModelProvider?.baseUrl ?? "").trim()),
|
|
119
|
-
};
|
|
120
|
-
const apiKey = args.copilot ? args.bridgeApiKey ?? crypto.randomBytes(24).toString("hex") : args.apiKey;
|
|
121
|
-
const baseUrl = args.copilot ? (0, providers_1.buildCopilotBridgeBaseUrl)(runtime) : args.baseUrl ?? undefined;
|
|
39
|
+
const upsertModelProviders = {
|
|
40
|
+
[args.profile]: (0, providers_1.buildModelProviderProjection)(args.profile, (directBaseUrl ?? existingModelProvider?.baseUrl ?? "").trim()),
|
|
41
|
+
};
|
|
122
42
|
const next = {
|
|
123
43
|
providers: {
|
|
124
44
|
...providers.providers,
|
|
125
45
|
[args.providerName]: (0, providers_1.cleanProviderRecord)({
|
|
126
46
|
profile: args.profile,
|
|
127
|
-
apiKey,
|
|
47
|
+
apiKey: args.apiKey,
|
|
128
48
|
model: providerModel,
|
|
129
|
-
baseUrl,
|
|
49
|
+
baseUrl: args.baseUrl ?? undefined,
|
|
130
50
|
note: args.note ?? undefined,
|
|
131
51
|
tags: args.tags,
|
|
132
|
-
runtime,
|
|
133
52
|
}),
|
|
134
53
|
},
|
|
135
54
|
};
|
|
@@ -147,7 +66,6 @@ async function addProvider(args) {
|
|
|
147
66
|
upsertModelProviders,
|
|
148
67
|
scrubModelProviderEnvKeys: [args.profile],
|
|
149
68
|
});
|
|
150
|
-
// Persist only the normalized provider payload so later reads are deterministic.
|
|
151
69
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, next);
|
|
152
70
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
153
71
|
return {
|
|
@@ -155,7 +73,6 @@ async function addProvider(args) {
|
|
|
155
73
|
model: providerModel,
|
|
156
74
|
modelProvider: args.profile,
|
|
157
75
|
profile: args.profile,
|
|
158
|
-
runtimeKind: runtime?.kind ?? null,
|
|
159
76
|
createdProfileSections: configPlan.createdProfileSections,
|
|
160
77
|
createdModelProviderSections: configPlan.createdModelProviderSections,
|
|
161
78
|
deletedProfileSections: configPlan.deletedProfileSections,
|
|
@@ -45,35 +45,17 @@ function editProvider(args) {
|
|
|
45
45
|
const oldProfile = current.profile;
|
|
46
46
|
const newProfile = nextProfile;
|
|
47
47
|
const targetModelProviderSection = document.modelProviders.find((entry) => entry.name === newProfile) ?? null;
|
|
48
|
-
let upsertModelProviders;
|
|
49
48
|
const resolvedBaseUrl = (args.baseUrl ?? current.baseUrl ?? targetModelProviderSection?.baseUrl ?? "").trim();
|
|
50
|
-
if (!
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
upsertModelProviders = {
|
|
59
|
-
[newProfile]: (0, providers_1.buildDirectModelProviderProjection)(newProfile, resolvedBaseUrl),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
else if (targetModelProviderSection || args.profile !== undefined) {
|
|
63
|
-
upsertModelProviders = {
|
|
64
|
-
...(upsertModelProviders ?? {}),
|
|
65
|
-
[newProfile]: {
|
|
66
|
-
...(current.runtime
|
|
67
|
-
? {
|
|
68
|
-
baseUrl: current.baseUrl ?? targetModelProviderSection?.baseUrl ?? "",
|
|
69
|
-
name: "copilot",
|
|
70
|
-
requiresOpenAiAuth: true,
|
|
71
|
-
wireApi: "responses",
|
|
72
|
-
}
|
|
73
|
-
: (0, providers_1.buildDirectModelProviderProjection)(newProfile, resolvedBaseUrl)),
|
|
74
|
-
},
|
|
75
|
-
};
|
|
49
|
+
if (!resolvedBaseUrl) {
|
|
50
|
+
throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Model provider "${newProfile}" requires base_url.`, {
|
|
51
|
+
profile: newProfile,
|
|
52
|
+
modelProvider: newProfile,
|
|
53
|
+
missingFields: ["base_url"],
|
|
54
|
+
});
|
|
76
55
|
}
|
|
56
|
+
const upsertModelProviders = {
|
|
57
|
+
[newProfile]: (0, providers_1.buildModelProviderProjection)(newProfile, resolvedBaseUrl),
|
|
58
|
+
};
|
|
77
59
|
const nextRecord = (0, providers_1.cleanProviderRecord)({
|
|
78
60
|
profile: newProfile,
|
|
79
61
|
apiKey: args.apiKey ?? current.apiKey,
|
|
@@ -81,7 +63,6 @@ function editProvider(args) {
|
|
|
81
63
|
baseUrl: args.baseUrl === null ? undefined : args.baseUrl ?? current.baseUrl,
|
|
82
64
|
note: args.note === null ? undefined : args.note ?? current.note,
|
|
83
65
|
tags: args.tags ?? current.tags,
|
|
84
|
-
runtime: current.runtime,
|
|
85
66
|
});
|
|
86
67
|
const isActive = document.currentModelProvider === oldProfile;
|
|
87
68
|
return (0, run_mutation_1.runMutation)({
|
|
@@ -108,7 +89,6 @@ function editProvider(args) {
|
|
|
108
89
|
[args.providerName]: nextRecord,
|
|
109
90
|
},
|
|
110
91
|
};
|
|
111
|
-
// Write providers first so the registry and config move together inside the managed backup boundary.
|
|
112
92
|
(0, providers_repo_1.writeProvidersFile)(args.providersPath, nextProviders);
|
|
113
93
|
(0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
|
|
114
94
|
return {
|
package/dist/app/get-status.js
CHANGED
|
@@ -37,18 +37,13 @@ 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 providers_1 = require("../domain/providers");
|
|
41
40
|
const config_repo_1 = require("../storage/config-repo");
|
|
42
41
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
43
42
|
const auth_repo_1 = require("../storage/auth-repo");
|
|
44
|
-
const copilot_installer_1 = require("../runtime/copilot-installer");
|
|
45
|
-
const copilot_bridge_1 = require("../runtime/copilot-bridge");
|
|
46
|
-
const copilot_adapter_1 = require("../runtime/copilot-adapter");
|
|
47
|
-
const runtime_state_repo_1 = require("../storage/runtime-state-repo");
|
|
48
43
|
/**
|
|
49
44
|
* Reports the current on-disk runtime state and how it maps back to managed providers.
|
|
50
45
|
*/
|
|
51
|
-
async function getStatus(codexDir, configPath, providersPath, authPath
|
|
46
|
+
async function getStatus(codexDir, configPath, providersPath, authPath) {
|
|
52
47
|
const configExists = fs.existsSync(configPath);
|
|
53
48
|
const providersExists = fs.existsSync(providersPath);
|
|
54
49
|
let currentModelProvider = null;
|
|
@@ -70,72 +65,16 @@ async function getStatus(codexDir, configPath, providersPath, authPath, options)
|
|
|
70
65
|
}
|
|
71
66
|
const liveState = (0, runtime_state_1.inspectLiveStateDrift)(currentModelProvider, providers);
|
|
72
67
|
const activeProviderCandidates = liveState.mappedProviders;
|
|
73
|
-
const activeProvider = liveState.providerResolvable && providers && liveState.mappedProvider
|
|
74
|
-
? providers.providers[liveState.mappedProvider]
|
|
75
|
-
: null;
|
|
76
|
-
const copilotInstall = (0, copilot_installer_1.probeCopilotSdkInstall)(options?.runtimesDir);
|
|
77
|
-
const runtimeStateInspection = (0, runtime_state_repo_1.inspectCopilotBridgeState)(options?.runtimeDir);
|
|
78
|
-
const runtimeState = runtimeStateInspection.state;
|
|
79
|
-
const runtimeStateProvider = runtimeState && providers ? providers.providers[runtimeState.provider] ?? null : null;
|
|
80
|
-
const bridgeProbeTarget = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
|
|
81
|
-
? activeProvider
|
|
82
|
-
: runtimeStateProvider && (0, providers_1.isCopilotBridgeProvider)(runtimeStateProvider)
|
|
83
|
-
? runtimeStateProvider
|
|
84
|
-
: null;
|
|
85
|
-
const copilotBridge = !runtimeStateInspection.valid && runtimeStateInspection.exists
|
|
86
|
-
? {
|
|
87
|
-
ok: false,
|
|
88
|
-
runtime: "copilot-bridge",
|
|
89
|
-
reason: "failed",
|
|
90
|
-
cause: runtimeStateInspection.parseError ?? "Failed to parse Copilot bridge runtime state.",
|
|
91
|
-
details: {
|
|
92
|
-
logPath: runtimeState?.logPath ?? null,
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
: bridgeProbeTarget
|
|
96
|
-
? await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(bridgeProbeTarget, runtimeState, options?.runtimeDir)
|
|
97
|
-
: runtimeState
|
|
98
|
-
? {
|
|
99
|
-
ok: false,
|
|
100
|
-
runtime: "copilot-bridge",
|
|
101
|
-
reason: "failed",
|
|
102
|
-
cause: "Copilot bridge runtime state exists but no matching managed Copilot provider is active.",
|
|
103
|
-
details: {
|
|
104
|
-
...runtimeState,
|
|
105
|
-
logPath: runtimeState.logPath ?? null,
|
|
106
|
-
},
|
|
107
|
-
}
|
|
108
|
-
: null;
|
|
109
|
-
const copilotAuth = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
|
|
110
|
-
? await (0, copilot_adapter_1.readCopilotAuthState)(options?.runtimesDir).catch((error) => ({
|
|
111
|
-
ready: false,
|
|
112
|
-
source: "official-sdk",
|
|
113
|
-
mode: "session",
|
|
114
|
-
error: error instanceof Error ? error.message : String(error),
|
|
115
|
-
}))
|
|
116
|
-
: null;
|
|
117
68
|
if (liveState.canBackfillActiveProvider) {
|
|
118
|
-
// Surface unmanaged live state without mutating anything during a read-only status call.
|
|
119
69
|
warnings.push("Current config profile is not mapped in providers.json. Backfill would be required before treating live state as managed.");
|
|
120
70
|
}
|
|
121
71
|
if (liveState.reason === "shared-profile") {
|
|
122
72
|
warnings.push(`Current model provider "${currentModelProvider}" is shared by multiple providers in providers.json, so the active provider cannot be resolved uniquely.`);
|
|
123
73
|
}
|
|
124
|
-
if (runtimeStateInspection.exists && !runtimeStateInspection.valid) {
|
|
125
|
-
warnings.push(`Copilot bridge runtime state is unreadable: ${runtimeStateInspection.parseError ?? "unknown parse failure"}`);
|
|
126
|
-
}
|
|
127
74
|
return {
|
|
128
75
|
warnings,
|
|
129
76
|
data: {
|
|
130
77
|
codexDir,
|
|
131
|
-
storage: (0, runtime_state_1.getStorageRoles)({
|
|
132
|
-
codexDir,
|
|
133
|
-
providersPath,
|
|
134
|
-
configPath,
|
|
135
|
-
authPath,
|
|
136
|
-
runtimeDir: options?.runtimeDir,
|
|
137
|
-
runtimesDir: options?.runtimesDir,
|
|
138
|
-
}),
|
|
139
78
|
configExists,
|
|
140
79
|
providersExists,
|
|
141
80
|
currentModelProvider,
|
|
@@ -144,18 +83,6 @@ async function getStatus(codexDir, configPath, providersPath, authPath, options)
|
|
|
144
83
|
provider: liveState.mappedProvider,
|
|
145
84
|
activeProviderResolvable: liveState.providerResolvable,
|
|
146
85
|
activeProviderCandidates,
|
|
147
|
-
runtimeProvider: activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider) ? activeProvider.runtime?.kind ?? null : null,
|
|
148
|
-
copilotSdk: {
|
|
149
|
-
installed: copilotInstall.installed,
|
|
150
|
-
installDir: copilotInstall.installDir,
|
|
151
|
-
packageName: copilotInstall.packageName,
|
|
152
|
-
packageVersion: copilotInstall.packageVersion ?? null,
|
|
153
|
-
},
|
|
154
|
-
copilotAuth,
|
|
155
|
-
copilotBridge,
|
|
156
|
-
copilotRuntimeState: runtimeState,
|
|
157
|
-
copilotBridgeLogPath: runtimeState?.logPath ?? null,
|
|
158
|
-
copilotBridgeRestartReason: runtimeState?.lastRestartReason ?? null,
|
|
159
86
|
liveState,
|
|
160
87
|
auth: authState,
|
|
161
88
|
configProfiles: configViews,
|
|
@@ -35,7 +35,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.listProviders = listProviders;
|
|
37
37
|
const fs = __importStar(require("node:fs"));
|
|
38
|
-
const providers_1 = require("../domain/providers");
|
|
39
38
|
const runtime_state_1 = require("../domain/runtime-state");
|
|
40
39
|
const config_repo_1 = require("../storage/config-repo");
|
|
41
40
|
const providers_repo_1 = require("../storage/providers-repo");
|
|
@@ -57,7 +56,6 @@ function listProviders(providersPath, configPath) {
|
|
|
57
56
|
profile: providers.providers[name].profile,
|
|
58
57
|
modelProvider: providers.providers[name].profile,
|
|
59
58
|
model: providers.providers[name].model ?? null,
|
|
60
|
-
providerType: (0, providers_1.isCopilotBridgeProvider)(providers.providers[name]) ? "copilot" : "direct",
|
|
61
59
|
isActive: liveState.providerResolvable && liveState.mappedProvider === name,
|
|
62
60
|
note: providers.providers[name].note ?? null,
|
|
63
61
|
tags: providers.providers[name].tags ?? [],
|