@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.
Files changed (39) hide show
  1. package/README.AI.md +66 -94
  2. package/README.CN.md +84 -139
  3. package/README.md +91 -151
  4. package/dist/app/add-provider.js +6 -89
  5. package/dist/app/edit-provider.js +9 -29
  6. package/dist/app/get-status.js +1 -74
  7. package/dist/app/list-providers.js +0 -2
  8. package/dist/app/remove-provider.js +3 -5
  9. package/dist/app/run-doctor.js +2 -100
  10. package/dist/app/setup-codex.js +0 -2
  11. package/dist/app/switch-provider.js +1 -79
  12. package/dist/cli/output.js +3 -89
  13. package/dist/commands/handlers.js +20 -209
  14. package/dist/commands/help.js +1 -4
  15. package/dist/commands/registry.js +6 -74
  16. package/dist/domain/config.js +1 -3
  17. package/dist/domain/providers.js +4 -92
  18. package/dist/domain/runtime-state.js +0 -88
  19. package/dist/interaction/add-interactive.js +1 -55
  20. package/dist/interaction/interactive.js +1 -3
  21. package/dist/runtime/codex-probe.js +0 -12
  22. package/dist/storage/codex-paths.js +0 -2
  23. package/docs/Design/codex-switch-v0.2.0-design.md +56 -0
  24. package/docs/Design/codex-switch-v0.2.1-design.md +77 -0
  25. package/docs/PRD/codex-switch-prd-v0.2.1.md +82 -0
  26. package/docs/Tests/testing.md +32 -34
  27. package/docs/cli-usage.md +67 -235
  28. package/docs/codex-switch-command-design.md +1 -1
  29. package/docs/codex-switch-product-overview.md +49 -96
  30. package/docs/codex-switch-technical-architecture.md +37 -52
  31. package/package.json +1 -1
  32. package/dist/app/bridge.js +0 -308
  33. package/dist/runtime/copilot-adapter.js +0 -612
  34. package/dist/runtime/copilot-bridge-worker.js +0 -69
  35. package/dist/runtime/copilot-bridge.js +0 -1318
  36. package/dist/runtime/copilot-cli.js +0 -164
  37. package/dist/runtime/copilot-installer.js +0 -231
  38. package/dist/runtime/copilot-sdk-loader.js +0 -62
  39. package/dist/storage/runtime-state-repo.js +0 -121
package/README.md CHANGED
@@ -1,162 +1,112 @@
1
- # @minniexcode/codex-switch
1
+ # codex-switch
2
2
 
3
- `@minniexcode/codex-switch` is a local-first CLI for managing and switching Codex provider and model-provider routing safely.
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 runtime, so provider management, backup flow, and runtime projection stay explicit instead of relying on manual file edits.
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
- Chinese version: [README.CN.md](./README.CN.md)
7
+ Current package version: `0.2.1`
8
8
 
9
- ## Version
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
- ## Primary Workflows
34
-
35
- Direct provider workflow:
18
+ For local development:
36
19
 
37
20
  ```bash
38
- codexs init
39
- codexs add my-provider --profile my-provider --model gpt-5.5 --base-url https://gateway.example.com/v1 --api-key sk-xxx
40
- codexs switch my-provider
41
- codexs status
42
- codexs doctor
21
+ npm install
22
+ npm run build
23
+ node dist/cli.js --help
43
24
  ```
44
25
 
45
- GitHub Copilot workflow:
26
+ Node.js `>=18` is required.
27
+
28
+ ## Primary Workflow
46
29
 
47
30
  ```bash
48
31
  codexs init
49
- codexs login copilot
50
- codexs add copilot-main --copilot --profile copilot-main --model gpt-4.1
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
- Notes:
38
+ What the workflow does:
57
39
 
58
- - `init` prepares the `codex-switch` tool home and managed state.
59
- - `login copilot` handles upstream Copilot onboarding and auth readiness.
60
- - `add --copilot` does not perform login for you; it assumes Copilot login is already ready.
61
- - For non-interactive use, pass `--profile` explicitly. In TTY mode, `add` and `edit` can prompt for missing required fields.
62
- - Copilot support is an experimental local bridge. The managed installer defaults to `@github/copilot-sdk@1.0.2`, Copilot runtime paths require Node.js `>=20`, and runtime checks separately reject older or prerelease SDK installs while validating API shape when the client or session is used.
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
- ## Runtime Routing Model
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
- For Codex `0.134.0+`, the active runtime route is selected through top-level `model` and `model_provider` in `config.toml`.
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
- ## Advanced Adopt Workflow
50
+ Current `0.2.1` command surface:
107
51
 
108
- Use `migrate` only when you already have Codex runtime state that should be adopted into managed `providers.json` state:
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 [profile]
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 add <provider> --copilot --profile <model-provider-id> --model <model>
131
- codexs edit <provider>
62
+ codexs edit <provider> [options]
132
63
  codexs switch <provider>
133
- codexs remove <provider> [--force] [--switch-to <provider>]
64
+ codexs remove <provider> --force
134
65
  codexs import <file>
135
- codexs export <file> [--force]
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
- `setup` still exists only as a deprecated compatibility entry that points callers to `init` or `migrate`.
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
- ## Runtime Model
98
+ ## Managed State
147
99
 
148
100
  Tool home:
149
101
 
150
102
  ```text
151
- ~/.config/codex-switch/
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 runtime:
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
- Key points:
117
+ Environment variables:
168
118
 
169
- - `providers.json` is the managed provider registry and lives under the tool home.
170
- - `codex-switch.json` stores tool-level metadata such as `defaultCodexDir`.
171
- - `config.toml` remains the active runtime routing file in the target Codex directory.
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
- Path controls:
123
+ ## Migration And Adoption
177
124
 
178
- - `--codex-dir <path>` targets a specific Codex runtime directory.
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
- ## Automation Notes
127
+ ```bash
128
+ codexs migrate
129
+ codexs migrate --overwrite --codex-dir ~/.codex
130
+ ```
183
131
 
184
- This CLI supports both human TTY usage and non-interactive automation.
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
- Global flags:
134
+ ## Current Non-Goals
187
135
 
188
- ```bash
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
- Operational limits:
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
- - `login copilot` requires a real TTY and does not support `--json`.
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
- ## Local Development
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
- ## Documentation
212
-
213
- - [Chinese README](./README.CN.md)
214
- - [AI README](./README.AI.md)
215
- - [Detailed CLI Usage](./docs/cli-usage.md)
216
- - [Testing Guide](./docs/Tests/testing.md)
217
- - [Product Overview](./docs/codex-switch-product-overview.md)
218
- - [PRD 0.1.0](./docs/PRD/codex-switch-prd-v0.1.0.md)
219
- - [PRD 0.1.1](./docs/PRD/codex-switch-prd-v0.1.1.md)
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.
@@ -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 (!args.copilot && (!directBaseUrl || directBaseUrl.trim() === "") && !existingModelProvider) {
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 = args.copilot
114
- ? {
115
- [args.profile]: (0, providers_1.buildCopilotModelProviderProjection)(runtime),
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 (!current.runtime) {
51
- if (!resolvedBaseUrl) {
52
- throw (0, errors_1.cliError)("MANAGED_PROFILE_FIELDS_MISSING", `Model provider "${newProfile}" requires base_url.`, {
53
- profile: newProfile,
54
- modelProvider: newProfile,
55
- missingFields: ["base_url"],
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 {
@@ -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, options) {
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 ?? [],