@minniexcode/codex-switch 0.0.8 → 0.0.9

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.
@@ -54,7 +54,7 @@ function addProvider(args) {
54
54
  throw (0, errors_1.cliError)("INVALID_IMPORT_FILE", `Provider "${args.providerName}" already exists.`);
55
55
  }
56
56
  const bridgeHost = args.bridgeHost ?? "127.0.0.1";
57
- const bridgePort = args.bridgePort ?? 4141;
57
+ const bridgePort = args.bridgePort ?? 41415;
58
58
  const runtime = args.copilot
59
59
  ? {
60
60
  kind: "copilot-sdk-bridge",
@@ -0,0 +1,296 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startBridge = startBridge;
4
+ exports.stopBridge = stopBridge;
5
+ exports.statusBridge = statusBridge;
6
+ const errors_1 = require("../domain/errors");
7
+ const providers_1 = require("../domain/providers");
8
+ const config_repo_1 = require("../storage/config-repo");
9
+ const providers_repo_1 = require("../storage/providers-repo");
10
+ const interactive_1 = require("../interaction/interactive");
11
+ const copilot_bridge_1 = require("../runtime/copilot-bridge");
12
+ const runtime_state_repo_1 = require("../storage/runtime-state-repo");
13
+ const copilot_installer_1 = require("../runtime/copilot-installer");
14
+ const copilot_adapter_1 = require("../runtime/copilot-adapter");
15
+ const DEFAULT_BRIDGE_PORT = 41415;
16
+ /**
17
+ * Starts or reuses the managed Copilot bridge for one provider.
18
+ */
19
+ async function startBridge(args) {
20
+ const providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
21
+ const target = await resolveBridgeTarget({
22
+ requestedProviderName: args.providerName ?? null,
23
+ providers,
24
+ configPath: args.configPath,
25
+ runtime: args.runtime,
26
+ json: args.json,
27
+ commandName: "start",
28
+ preferRuntimeState: false,
29
+ });
30
+ await requireBridgeRuntimeReadiness();
31
+ const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(target.providerName, target.provider);
32
+ const nextProvider = bridge.portChanged ? rewriteBridgeProviderPort(target.provider, bridge.port) : target.provider;
33
+ if (bridge.portChanged) {
34
+ try {
35
+ persistRecoveredBridgePort({
36
+ providersPath: args.providersPath,
37
+ configPath: args.configPath,
38
+ providers,
39
+ providerName: target.providerName,
40
+ previousProvider: target.provider,
41
+ provider: nextProvider,
42
+ });
43
+ }
44
+ catch (error) {
45
+ if (!bridge.reused) {
46
+ (0, copilot_bridge_1.stopCopilotBridge)();
47
+ }
48
+ throw error;
49
+ }
50
+ }
51
+ return {
52
+ data: {
53
+ provider: target.providerName,
54
+ profile: nextProvider.profile,
55
+ baseUrl: (0, providers_1.buildCopilotBridgeBaseUrl)(nextProvider.runtime),
56
+ host: bridge.host,
57
+ port: bridge.port,
58
+ reused: bridge.reused,
59
+ portChanged: bridge.portChanged,
60
+ defaultPort: DEFAULT_BRIDGE_PORT,
61
+ },
62
+ };
63
+ }
64
+ /**
65
+ * Stops the managed Copilot bridge.
66
+ */
67
+ async function stopBridge(args) {
68
+ const providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
69
+ const state = (0, runtime_state_repo_1.readCopilotBridgeState)();
70
+ if (!state && !args.providerName) {
71
+ return {
72
+ data: {
73
+ provider: null,
74
+ stopped: true,
75
+ hadRuntimeState: false,
76
+ },
77
+ };
78
+ }
79
+ if (!state && args.providerName) {
80
+ resolveNamedBridgeProvider(providers, args.providerName);
81
+ return {
82
+ data: {
83
+ provider: args.providerName,
84
+ stopped: true,
85
+ hadRuntimeState: false,
86
+ },
87
+ };
88
+ }
89
+ const target = await resolveBridgeTarget({
90
+ requestedProviderName: args.providerName ?? null,
91
+ providers,
92
+ configPath: args.configPath,
93
+ runtime: args.runtime,
94
+ json: args.json,
95
+ commandName: "stop",
96
+ preferRuntimeState: true,
97
+ });
98
+ if (args.providerName && state?.provider && state.provider !== args.providerName) {
99
+ throw (0, errors_1.cliError)("BRIDGE_PROVIDER_MISMATCH", `Bridge runtime state belongs to "${state.provider}" not "${args.providerName}".`, {
100
+ stateProvider: state.provider,
101
+ requestedProvider: args.providerName,
102
+ });
103
+ }
104
+ (0, copilot_bridge_1.stopCopilotBridge)();
105
+ return {
106
+ data: {
107
+ provider: target.providerName,
108
+ stopped: true,
109
+ hadRuntimeState: Boolean(state),
110
+ },
111
+ };
112
+ }
113
+ /**
114
+ * Reports the managed Copilot bridge state.
115
+ */
116
+ async function statusBridge(args) {
117
+ const providers = (0, providers_repo_1.readProvidersFile)(args.providersPath);
118
+ const state = (0, runtime_state_repo_1.readCopilotBridgeState)();
119
+ const target = await resolveBridgeTarget({
120
+ requestedProviderName: args.providerName ?? null,
121
+ providers,
122
+ configPath: args.configPath,
123
+ runtime: args.runtime,
124
+ json: args.json,
125
+ commandName: "status",
126
+ preferRuntimeState: true,
127
+ });
128
+ const provider = target.provider;
129
+ const runtimeStatus = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(provider);
130
+ const expectedBaseUrl = (0, providers_1.buildCopilotBridgeBaseUrl)(provider.runtime);
131
+ if (args.providerName && state?.provider && state.provider !== args.providerName) {
132
+ throw (0, errors_1.cliError)("BRIDGE_PROVIDER_MISMATCH", `Bridge runtime state belongs to "${state.provider}" not "${args.providerName}".`, {
133
+ stateProvider: state.provider,
134
+ requestedProvider: args.providerName,
135
+ });
136
+ }
137
+ return {
138
+ data: {
139
+ provider: target.providerName,
140
+ profile: provider.profile,
141
+ runtimeState: state,
142
+ expectedBaseUrl,
143
+ matches: Boolean(state && state.provider === target.providerName && state.baseUrl === expectedBaseUrl),
144
+ active: runtimeStatus.ok,
145
+ health: runtimeStatus,
146
+ },
147
+ };
148
+ }
149
+ /**
150
+ * Resolves the Copilot provider target for one bridge command.
151
+ */
152
+ async function resolveBridgeTarget(args) {
153
+ if (args.requestedProviderName) {
154
+ return resolveNamedBridgeProvider(args.providers, args.requestedProviderName);
155
+ }
156
+ if (args.preferRuntimeState) {
157
+ const runtimeState = (0, runtime_state_repo_1.readCopilotBridgeState)();
158
+ if (runtimeState?.provider && args.providers.providers[runtimeState.provider]) {
159
+ return resolveNamedBridgeProvider(args.providers, runtimeState.provider);
160
+ }
161
+ }
162
+ const activeTarget = resolveActiveCopilotBridgeProvider(args.providers, args.configPath);
163
+ if (activeTarget) {
164
+ return activeTarget;
165
+ }
166
+ const copilotTargets = listCopilotBridgeProviders(args.providers);
167
+ if (copilotTargets.length === 1) {
168
+ return copilotTargets[0];
169
+ }
170
+ if ((0, interactive_1.canPrompt)(args.runtime, args.json)) {
171
+ const selected = await promptForCopilotBridgeSelection(args.runtime, copilotTargets, args.commandName);
172
+ return resolveNamedBridgeProvider(args.providers, selected);
173
+ }
174
+ throw (0, errors_1.cliError)("BRIDGE_TARGET_UNRESOLVED", `Unable to resolve a Copilot provider for bridge ${args.commandName}.`, {
175
+ availableProviders: copilotTargets.map((entry) => entry.providerName),
176
+ });
177
+ }
178
+ /**
179
+ * Resolves the active provider when the current top-level profile maps to one Copilot bridge provider.
180
+ */
181
+ function resolveActiveCopilotBridgeProvider(providers, configPath) {
182
+ try {
183
+ const currentProfile = (0, config_repo_1.readCurrentProfile)(configPath);
184
+ const matches = Object.entries(providers.providers)
185
+ .filter(([, provider]) => provider.profile === currentProfile && (0, providers_1.isCopilotBridgeProvider)(provider))
186
+ .sort(([left], [right]) => left.localeCompare(right));
187
+ if (matches.length === 1) {
188
+ return {
189
+ providerName: matches[0][0],
190
+ provider: matches[0][1],
191
+ };
192
+ }
193
+ }
194
+ catch {
195
+ return null;
196
+ }
197
+ return null;
198
+ }
199
+ /**
200
+ * Resolves one named provider and enforces the Copilot bridge runtime kind.
201
+ */
202
+ function resolveNamedBridgeProvider(providers, providerName) {
203
+ const provider = providers.providers[providerName];
204
+ if (!provider) {
205
+ throw (0, errors_1.cliError)("PROVIDER_NOT_FOUND", `Provider "${providerName}" was not found.`, {
206
+ provider: providerName,
207
+ });
208
+ }
209
+ if (!(0, providers_1.isCopilotBridgeProvider)(provider)) {
210
+ throw (0, errors_1.cliError)("BRIDGE_PROVIDER_MISMATCH", `Provider "${providerName}" is not a Copilot bridge provider.`, {
211
+ provider: providerName,
212
+ });
213
+ }
214
+ return { providerName, provider };
215
+ }
216
+ /**
217
+ * Lists all configured Copilot bridge providers in stable order.
218
+ */
219
+ function listCopilotBridgeProviders(providers) {
220
+ return Object.entries(providers.providers)
221
+ .filter(([, provider]) => (0, providers_1.isCopilotBridgeProvider)(provider))
222
+ .sort(([left], [right]) => left.localeCompare(right))
223
+ .map(([providerName, provider]) => ({ providerName, provider }));
224
+ }
225
+ /**
226
+ * Uses a Copilot-only provider picker instead of the generic provider selector.
227
+ */
228
+ async function promptForCopilotBridgeSelection(runtime, targets, commandName) {
229
+ if (targets.length === 0) {
230
+ throw (0, errors_1.cliError)("BRIDGE_TARGET_UNRESOLVED", `No Copilot bridge providers are configured for bridge ${commandName}.`);
231
+ }
232
+ return runtime.selectOne(`Choose a Copilot provider to ${commandName}`, targets.map((target) => ({
233
+ value: target.providerName,
234
+ label: target.providerName,
235
+ hint: target.provider.profile,
236
+ })));
237
+ }
238
+ /**
239
+ * Verifies that the local Copilot bridge prerequisites are available before startup.
240
+ */
241
+ async function requireBridgeRuntimeReadiness() {
242
+ const installStatus = (0, copilot_installer_1.probeCopilotSdkInstall)();
243
+ if (!installStatus.installed) {
244
+ throw (0, errors_1.cliError)("COPILOT_SDK_MISSING", "The optional Copilot SDK runtime is not installed.", {
245
+ installDir: installStatus.installDir,
246
+ packageName: installStatus.packageName,
247
+ });
248
+ }
249
+ await (0, copilot_adapter_1.readCopilotAuthState)();
250
+ }
251
+ /**
252
+ * Rewrites one Copilot bridge provider record with a recovered runtime port.
253
+ */
254
+ function rewriteBridgeProviderPort(provider, port) {
255
+ return (0, providers_1.cleanProviderRecord)({
256
+ ...provider,
257
+ baseUrl: `http://${provider.runtime.bridgeHost}:${port}${provider.runtime.bridgePath}`,
258
+ runtime: {
259
+ ...provider.runtime,
260
+ bridgePort: port,
261
+ },
262
+ });
263
+ }
264
+ /**
265
+ * Persists the recovered bridge port to both providers.json and config.toml.
266
+ */
267
+ function persistRecoveredBridgePort(args) {
268
+ const previousProviders = {
269
+ providers: {
270
+ ...args.providers.providers,
271
+ },
272
+ };
273
+ const nextProviders = {
274
+ providers: {
275
+ ...args.providers.providers,
276
+ [args.providerName]: args.provider,
277
+ },
278
+ };
279
+ (0, providers_repo_1.writeProvidersFile)(args.providersPath, nextProviders);
280
+ try {
281
+ const document = (0, config_repo_1.readStructuredConfig)(args.configPath);
282
+ const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
283
+ upsertModelProviders: {
284
+ [args.provider.profile]: {
285
+ baseUrl: (0, providers_1.buildCopilotBridgeBaseUrl)(args.provider.runtime),
286
+ envKey: (0, config_repo_1.requireRuntimeEnvKey)(document, args.provider.profile),
287
+ },
288
+ },
289
+ });
290
+ (0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
291
+ }
292
+ catch (error) {
293
+ (0, providers_repo_1.writeProvidersFile)(args.providersPath, previousProviders);
294
+ throw error;
295
+ }
296
+ }
@@ -44,6 +44,7 @@ const auth_repo_1 = require("../storage/auth-repo");
44
44
  const copilot_installer_1 = require("../runtime/copilot-installer");
45
45
  const copilot_bridge_1 = require("../runtime/copilot-bridge");
46
46
  const copilot_adapter_1 = require("../runtime/copilot-adapter");
47
+ const runtime_state_repo_1 = require("../storage/runtime-state-repo");
47
48
  /**
48
49
  * Reports the current on-disk runtime state and how it maps back to managed providers.
49
50
  */
@@ -69,7 +70,20 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
69
70
  const activeProviderCandidates = currentProfile && providers ? (0, providers_1.findProvidersByProfile)(providers, currentProfile) : [];
70
71
  const activeProvider = activeProviderCandidates.length === 1 && providers ? providers.providers[activeProviderCandidates[0]] : null;
71
72
  const copilotInstall = (0, copilot_installer_1.probeCopilotSdkInstall)();
72
- const copilotBridge = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider) ? await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider) : null;
73
+ const runtimeState = (0, runtime_state_repo_1.readCopilotBridgeState)();
74
+ const runtimeStateProvider = runtimeState && providers ? providers.providers[runtimeState.provider] ?? null : null;
75
+ const bridgeProbeTarget = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
76
+ ? activeProvider
77
+ : runtimeStateProvider && (0, providers_1.isCopilotBridgeProvider)(runtimeStateProvider)
78
+ ? runtimeStateProvider
79
+ : null;
80
+ const copilotBridge = bridgeProbeTarget ? await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(bridgeProbeTarget) : runtimeState ? {
81
+ ok: false,
82
+ runtime: "copilot-bridge",
83
+ reason: "failed",
84
+ cause: "Copilot bridge runtime state exists but no matching managed Copilot provider is active.",
85
+ details: runtimeState,
86
+ } : null;
73
87
  const copilotAuth = activeProvider && (0, providers_1.isCopilotBridgeProvider)(activeProvider)
74
88
  ? await (0, copilot_adapter_1.readCopilotAuthState)().catch((error) => ({
75
89
  ready: false,
@@ -103,6 +117,7 @@ async function getStatus(codexDir, configPath, providersPath, authPath) {
103
117
  },
104
118
  copilotAuth,
105
119
  copilotBridge,
120
+ copilotRuntimeState: runtimeState,
106
121
  liveState,
107
122
  auth: authState,
108
123
  configProfiles: configViews,
@@ -46,6 +46,7 @@ const providers_1 = require("../domain/providers");
46
46
  const copilot_installer_1 = require("../runtime/copilot-installer");
47
47
  const copilot_bridge_1 = require("../runtime/copilot-bridge");
48
48
  const copilot_adapter_1 = require("../runtime/copilot-adapter");
49
+ const runtime_state_repo_1 = require("../storage/runtime-state-repo");
49
50
  /**
50
51
  * Performs consistency checks across config.toml, providers.json, and the local Codex CLI.
51
52
  */
@@ -102,6 +103,7 @@ async function runDoctor(args) {
102
103
  }
103
104
  }
104
105
  const authState = (0, auth_repo_1.readManagedAuthState)(args.authPath);
106
+ const runtimeState = (0, runtime_state_repo_1.readCopilotBridgeState)();
105
107
  if (authState.exists && !authState.valid) {
106
108
  issues.push({
107
109
  code: "AUTH_JSON_INVALID",
@@ -161,9 +163,7 @@ async function runDoctor(args) {
161
163
  const bridge = await (0, copilot_bridge_1.probeCopilotBridgeRuntime)(activeProvider);
162
164
  if (!bridge.ok) {
163
165
  issues.push({
164
- code: bridge.cause === "Copilot bridge state base URL does not match the provider runtime configuration."
165
- ? "PROVIDER_BASE_URL_MISMATCH"
166
- : "BRIDGE_HEALTHCHECK_FAILED",
166
+ code: mapBridgeDiagnosticCode(bridge.cause),
167
167
  message: bridge.cause,
168
168
  ...(bridge.details ?? {}),
169
169
  });
@@ -171,6 +171,26 @@ async function runDoctor(args) {
171
171
  }
172
172
  }
173
173
  }
174
+ if (runtimeState && providers) {
175
+ const runtimeProvider = providers.providers[runtimeState.provider] ?? null;
176
+ if (!runtimeProvider || !(0, providers_1.isCopilotBridgeProvider)(runtimeProvider)) {
177
+ issues.push({
178
+ code: "BRIDGE_STATE_STALE",
179
+ message: "Copilot bridge runtime state exists but no matching managed Copilot provider is available.",
180
+ ...runtimeState,
181
+ });
182
+ }
183
+ else if (!document?.activeProfile || runtimeProvider.profile !== document.activeProfile) {
184
+ issues.push({
185
+ code: "BRIDGE_STATE_STALE",
186
+ message: "Copilot bridge runtime state exists for a provider that is not the current active profile.",
187
+ activeProfile: document?.activeProfile ?? null,
188
+ runtimeProvider: runtimeState.provider,
189
+ runtimeProfile: runtimeProvider.profile,
190
+ ...runtimeState,
191
+ });
192
+ }
193
+ }
174
194
  // Drift inspection still runs when files are missing so status output can explain partial state.
175
195
  const drift = (0, runtime_state_1.inspectLiveStateDrift)(currentProfile, providers);
176
196
  const codexCheck = (0, codex_probe_1.probeCodexRuntime)();
@@ -202,6 +222,18 @@ async function runDoctor(args) {
202
222
  warnings: issues.length === 0 ? [] : [`doctor found ${issues.length} issue(s)`],
203
223
  };
204
224
  }
225
+ function mapBridgeDiagnosticCode(cause) {
226
+ if (cause === "Copilot bridge state manifest is missing.") {
227
+ return "BRIDGE_STATE_MISSING";
228
+ }
229
+ if (cause === "Copilot bridge runtime state exists but no active Copilot bridge provider is selected.") {
230
+ return "BRIDGE_STATE_STALE";
231
+ }
232
+ if (cause === "Copilot bridge state base URL does not match the provider runtime configuration.") {
233
+ return "PROVIDER_BASE_URL_MISMATCH";
234
+ }
235
+ return "BRIDGE_HEALTHCHECK_FAILED";
236
+ }
205
237
  /**
206
238
  * Maps structured config consistency issues onto stable human-readable diagnostic text.
207
239
  */
@@ -41,6 +41,16 @@ async function switchProvider(args) {
41
41
  }
42
42
  await (0, copilot_adapter_1.readCopilotAuthState)();
43
43
  const bridge = await (0, copilot_bridge_1.ensureCopilotBridge)(args.providerName, provider);
44
+ const nextProvider = bridge.portChanged
45
+ ? (0, providers_1.cleanProviderRecord)({
46
+ ...provider,
47
+ baseUrl: bridge.baseUrl,
48
+ runtime: {
49
+ ...provider.runtime,
50
+ bridgePort: bridge.port,
51
+ },
52
+ })
53
+ : provider;
44
54
  try {
45
55
  return (0, run_mutation_1.runMutation)({
46
56
  codexDir: args.codexDir,
@@ -54,14 +64,32 @@ async function switchProvider(args) {
54
64
  mutate: () => {
55
65
  const configPlan = (0, config_repo_1.createConfigMutationPlan)(document, {
56
66
  setActiveProfile: provider.profile,
67
+ upsertModelProviders: bridge.portChanged
68
+ ? {
69
+ [provider.profile]: {
70
+ baseUrl: (0, providers_1.buildCopilotBridgeBaseUrl)(nextProvider.runtime),
71
+ envKey,
72
+ },
73
+ }
74
+ : undefined,
57
75
  });
76
+ if (bridge.portChanged) {
77
+ (0, providers_repo_1.writeProvidersFile)(args.providersPath, {
78
+ providers: {
79
+ ...providers.providers,
80
+ [args.providerName]: nextProvider,
81
+ },
82
+ });
83
+ }
58
84
  (0, config_repo_1.applyConfigMutation)(args.configPath, document, configPlan);
59
85
  const existingAuth = (0, auth_repo_1.readAuthFileIfExists)(args.authPath);
60
- (0, auth_repo_1.writeAuthFile)(args.authPath, provider, existingAuth ?? undefined);
86
+ (0, auth_repo_1.writeAuthFile)(args.authPath, nextProvider, existingAuth ?? undefined);
61
87
  return {
62
88
  provider: args.providerName,
63
- profile: provider.profile,
64
- envKey: provider.envKey,
89
+ profile: nextProvider.profile,
90
+ envKey: nextProvider.envKey,
91
+ portChanged: bridge.portChanged,
92
+ bridgePort: bridge.port,
65
93
  };
66
94
  },
67
95
  });
@@ -48,6 +48,7 @@ const list_providers_1 = require("../app/list-providers");
48
48
  const remove_provider_1 = require("../app/remove-provider");
49
49
  const rollback_backup_1 = require("../app/rollback-backup");
50
50
  const run_doctor_1 = require("../app/run-doctor");
51
+ const bridge_1 = require("../app/bridge");
51
52
  const setup_codex_1 = require("../app/setup-codex");
52
53
  const show_config_1 = require("../app/show-config");
53
54
  const show_provider_1 = require("../app/show-provider");
@@ -90,6 +91,36 @@ async function handleRegisteredCommand(ctx, parsed, runtime = (0, prompt_1.creat
90
91
  return (0, get_current_profile_1.getCurrentProfile)(paths.configPath);
91
92
  case "status":
92
93
  return (0, get_status_1.getStatus)(paths.codexDir, paths.configPath, paths.providersPath, paths.authPath);
94
+ case "bridge-start": {
95
+ const providerName = parsed.positionals[0] ?? null;
96
+ return (0, bridge_1.startBridge)({
97
+ providersPath: paths.providersPath,
98
+ configPath: paths.configPath,
99
+ providerName,
100
+ runtime,
101
+ json: ctx.options.json,
102
+ });
103
+ }
104
+ case "bridge-stop": {
105
+ const providerName = parsed.positionals[0] ?? null;
106
+ return (0, bridge_1.stopBridge)({
107
+ providersPath: paths.providersPath,
108
+ configPath: paths.configPath,
109
+ providerName,
110
+ runtime,
111
+ json: ctx.options.json,
112
+ });
113
+ }
114
+ case "bridge-status": {
115
+ const providerName = parsed.positionals[0] ?? null;
116
+ return (0, bridge_1.statusBridge)({
117
+ providersPath: paths.providersPath,
118
+ configPath: paths.configPath,
119
+ providerName,
120
+ runtime,
121
+ json: ctx.options.json,
122
+ });
123
+ }
93
124
  case "init": {
94
125
  let codexDir = ctx.options.codexDir;
95
126
  const candidates = (0, config_repo_1.findCodexDirCandidates)(ctx.options.codexDirExplicit ? ctx.options.codexDir : null);
@@ -63,6 +63,7 @@ function buildHelpText(commandName) {
63
63
  " codexs migrate",
64
64
  " codexs list",
65
65
  " codexs switch",
66
+ " codexs bridge start",
66
67
  " codexs add packycode --profile packycode --api-key sk-xxx",
67
68
  " codexs config show",
68
69
  " codexs remove freemodel",
@@ -41,6 +41,48 @@ exports.COMMANDS = [
41
41
  ],
42
42
  examples: ["codexs config list-profiles", "codexs config list-profiles --json"],
43
43
  },
44
+ {
45
+ id: "bridge-start",
46
+ tokens: ["bridge", "start"],
47
+ handler: handlers_1.handleRegisteredCommand,
48
+ group: "write",
49
+ summary: "Start or reuse the managed Copilot bridge.",
50
+ usage: ["codexs bridge start [provider] [--json] [--codex-dir <path>]"],
51
+ details: [
52
+ "Resolves a Copilot bridge provider by explicit name, active provider, sole provider, or TTY selection.",
53
+ "Reuses a healthy bridge for the same provider and replaces a different managed provider when needed.",
54
+ "If the preferred port is occupied, automatically selects another free 5-digit port and persists it.",
55
+ ],
56
+ examples: ["codexs bridge start", "codexs bridge start copilot-main"],
57
+ },
58
+ {
59
+ id: "bridge-stop",
60
+ tokens: ["bridge", "stop"],
61
+ handler: handlers_1.handleRegisteredCommand,
62
+ group: "recovery",
63
+ summary: "Stop the managed Copilot bridge.",
64
+ usage: ["codexs bridge stop [provider] [--json] [--codex-dir <path>]"],
65
+ details: [
66
+ "Prefers the runtime-state instance when present and uses an explicit provider as a guard.",
67
+ "Clears the runtime-state manifest without mutating providers.json or auth.json.",
68
+ "Is idempotent when no managed bridge is currently running.",
69
+ ],
70
+ examples: ["codexs bridge stop", "codexs bridge stop copilot-main"],
71
+ },
72
+ {
73
+ id: "bridge-status",
74
+ tokens: ["bridge", "status"],
75
+ handler: handlers_1.handleRegisteredCommand,
76
+ group: "read",
77
+ summary: "Inspect the managed Copilot bridge.",
78
+ usage: ["codexs bridge status [provider] [--json] [--codex-dir <path>]"],
79
+ details: [
80
+ "Reports runtime-state, provider binding, and whether the live worker matches the expected provider.",
81
+ "Prefers the runtime-state instance when one is present.",
82
+ "Uses an explicit provider as a guard instead of silently switching targets.",
83
+ ],
84
+ examples: ["codexs bridge status", "codexs bridge status copilot-main"],
85
+ },
44
86
  {
45
87
  id: "init",
46
88
  tokens: ["init"],
@@ -5,7 +5,7 @@ const copilot_adapter_1 = require("./copilot-adapter");
5
5
  async function main() {
6
6
  const provider = process.env.CODEX_SWITCH_BRIDGE_PROVIDER ?? "copilot";
7
7
  const host = process.env.CODEX_SWITCH_BRIDGE_HOST ?? "127.0.0.1";
8
- const port = Number(process.env.CODEX_SWITCH_BRIDGE_PORT ?? "4141");
8
+ const port = Number(process.env.CODEX_SWITCH_BRIDGE_PORT ?? "41415");
9
9
  const apiKey = process.env.CODEX_SWITCH_BRIDGE_API_KEY ?? "";
10
10
  await (0, copilot_bridge_1.startCopilotBridgeServer)({
11
11
  host,