@minniexcode/codex-switch 0.1.0 → 0.1.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 (68) hide show
  1. package/README.AI.md +141 -110
  2. package/README.CN.md +215 -179
  3. package/README.md +224 -183
  4. package/dist/app/add-provider.js +16 -23
  5. package/dist/app/bridge.js +2 -1
  6. package/dist/app/edit-provider.js +30 -65
  7. package/dist/app/get-current-profile.js +15 -3
  8. package/dist/app/get-status.js +11 -8
  9. package/dist/app/list-config-profiles.js +3 -1
  10. package/dist/app/list-providers.js +10 -4
  11. package/dist/app/remove-provider.js +52 -19
  12. package/dist/app/run-doctor.js +26 -29
  13. package/dist/app/setup-codex.js +3 -3
  14. package/dist/app/show-config.js +3 -1
  15. package/dist/app/switch-provider.js +38 -6
  16. package/dist/cli/output.js +29 -19
  17. package/dist/commands/handlers.js +3 -2
  18. package/dist/commands/help.js +3 -3
  19. package/dist/commands/registry.js +29 -29
  20. package/dist/domain/config.js +293 -209
  21. package/dist/domain/providers.js +8 -0
  22. package/dist/domain/runtime-state.js +15 -15
  23. package/dist/domain/setup.js +3 -1
  24. package/dist/interaction/interactive.js +2 -2
  25. package/dist/runtime/codex-version.js +7 -0
  26. package/dist/runtime/copilot-adapter.js +326 -70
  27. package/dist/runtime/copilot-bridge-worker.js +27 -2
  28. package/dist/runtime/copilot-bridge.js +192 -10
  29. package/dist/runtime/copilot-cli.js +7 -0
  30. package/dist/runtime/copilot-installer.js +59 -1
  31. package/dist/runtime/copilot-sdk-loader.js +4 -1
  32. package/dist/storage/config-repo.js +6 -14
  33. package/docs/Design/codex-switch-v0.1.0-design.md +32 -152
  34. package/docs/Design/codex-switch-v0.1.1-design.md +22 -0
  35. package/docs/Design/codex-switch-v0.1.2-design.md +65 -0
  36. package/docs/PRD/codex-switch-prd-v0.1.0.md +65 -217
  37. package/docs/PRD/codex-switch-prd-v0.1.1.md +26 -0
  38. package/docs/PRD/codex-switch-prd-v0.1.2.md +41 -0
  39. package/docs/Reference/codex-config-reference.md +41 -0
  40. package/docs/Reference/codex-config-reference.zh-CN.md +41 -0
  41. package/docs/Tests/testing.md +1 -1
  42. package/docs/cli-usage.md +290 -223
  43. package/docs/codex-switch-command-design.md +2 -2
  44. package/docs/codex-switch-product-overview.md +18 -13
  45. package/docs/codex-switch-product-research.md +2 -2
  46. package/docs/codex-switch-technical-architecture.md +84 -1115
  47. package/package.json +2 -2
  48. package/docs/Design/codex-switch-copilot-integration-design.md +0 -517
  49. package/docs/Design/codex-switch-v0.0.10-design.md +0 -669
  50. package/docs/Design/codex-switch-v0.0.11-design.md +0 -824
  51. package/docs/Design/codex-switch-v0.0.12-design.md +0 -343
  52. package/docs/Design/codex-switch-v0.0.4-design.md +0 -874
  53. package/docs/Design/codex-switch-v0.0.5-design.md +0 -932
  54. package/docs/Design/codex-switch-v0.0.6-design.md +0 -708
  55. package/docs/Design/codex-switch-v0.0.7-design.md +0 -862
  56. package/docs/Design/codex-switch-v0.0.8-design.md +0 -132
  57. package/docs/Design/codex-switch-v0.0.9-design.md +0 -182
  58. package/docs/Design/codex-switch-v0.0.9-to-v0.0.12-roadmap.md +0 -413
  59. package/docs/PRD/codex-switch-prd-v0.0.10.md +0 -406
  60. package/docs/PRD/codex-switch-prd-v0.0.11.md +0 -577
  61. package/docs/PRD/codex-switch-prd-v0.0.12.md +0 -279
  62. package/docs/PRD/codex-switch-prd-v0.0.5-to-v0.1.0.md +0 -446
  63. package/docs/PRD/codex-switch-prd-v0.0.8.md +0 -62
  64. package/docs/PRD/codex-switch-prd-v0.0.9.md +0 -166
  65. package/docs/PRD/codex-switch-prd.md +0 -650
  66. package/docs/Tests/test-report-0.0.5.md +0 -163
  67. package/docs/Tests/test-report-0.0.7.md +0 -118
  68. package/docs/Tests/testing-bridge-v0.0.9.md +0 -367
@@ -2,19 +2,44 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const copilot_bridge_1 = require("./copilot-bridge");
4
4
  const copilot_adapter_1 = require("./copilot-adapter");
5
+ let requestQueue = Promise.resolve();
6
+ function enqueueRequest(task) {
7
+ const run = requestQueue.then(task, task);
8
+ requestQueue = run.catch(() => undefined);
9
+ return run;
10
+ }
5
11
  async function main() {
6
12
  const provider = process.env.CODEX_SWITCH_BRIDGE_PROVIDER ?? "copilot";
7
13
  const host = process.env.CODEX_SWITCH_BRIDGE_HOST ?? "127.0.0.1";
8
14
  const port = Number(process.env.CODEX_SWITCH_BRIDGE_PORT ?? "41415");
9
15
  const apiKey = process.env.CODEX_SWITCH_BRIDGE_API_KEY ?? "";
16
+ const runtimesDir = process.env.CODEX_SWITCH_RUNTIMES_DIR || undefined;
17
+ const runtimeClient = await (0, copilot_adapter_1.createCopilotRuntimeClient)(runtimesDir);
18
+ await (0, copilot_adapter_1.startCopilotRuntimeClient)(runtimeClient);
19
+ const stopRuntime = () => {
20
+ void (0, copilot_adapter_1.stopCopilotRuntimeClient)(runtimeClient).finally(() => process.exit(0));
21
+ };
22
+ process.once("SIGINT", stopRuntime);
23
+ process.once("SIGTERM", stopRuntime);
10
24
  await (0, copilot_bridge_1.startCopilotBridgeServer)({
11
25
  host,
12
26
  port,
13
27
  apiKey,
14
- executeChatCompletion: async (payload) => (0, copilot_adapter_1.sendCopilotChatCompletion)({
28
+ executeChatCompletion: async (payload, options) => enqueueRequest(() => (0, copilot_adapter_1.sendCopilotChatCompletion)({
15
29
  provider,
16
30
  payload,
17
- }),
31
+ runtimesDir,
32
+ runtimeClient,
33
+ timeoutMs: options?.timeoutMs,
34
+ onStreamEvent: (event) => {
35
+ if (event.type === "delta") {
36
+ options?.onTextDelta?.(event.delta);
37
+ }
38
+ else {
39
+ options?.onTextDone?.(event.text);
40
+ }
41
+ },
42
+ })),
18
43
  });
19
44
  }
20
45
  if (require.main === module) {
@@ -138,13 +138,13 @@ async function probeCopilotBridgeRuntime(provider, persistedState, runtimeDir) {
138
138
  /**
139
139
  * Starts or reuses a Copilot bridge worker, then verifies its health before returning.
140
140
  */
141
- async function ensureCopilotBridge(providerName, provider, runtimeDir) {
142
- return startOrReuseCopilotBridge(providerName, provider, runtimeDir);
141
+ async function ensureCopilotBridge(providerName, provider, runtimeDir, runtimesDir) {
142
+ return startOrReuseCopilotBridge(providerName, provider, runtimeDir, runtimesDir);
143
143
  }
144
144
  /**
145
145
  * Starts or reuses a Copilot bridge worker and reports the chosen port.
146
146
  */
147
- async function startOrReuseCopilotBridge(providerName, provider, runtimeDir) {
147
+ async function startOrReuseCopilotBridge(providerName, provider, runtimeDir, runtimesDir) {
148
148
  if (!(0, providers_1.isCopilotBridgeProvider)(provider)) {
149
149
  throw (0, errors_1.cliError)("RUNTIME_PROVIDER_INVALID", "Provider is not backed by a Copilot bridge runtime.", {
150
150
  provider: providerName,
@@ -208,6 +208,8 @@ async function startOrReuseCopilotBridge(providerName, provider, runtimeDir) {
208
208
  CODEX_SWITCH_BRIDGE_PORT: String(selectedPort),
209
209
  CODEX_SWITCH_BRIDGE_API_KEY: provider.apiKey,
210
210
  CODEX_SWITCH_BRIDGE_BASE_URL: selectedBaseUrl,
211
+ CODEX_SWITCH_RUNTIME_DIR: runtimeDir ?? "",
212
+ CODEX_SWITCH_RUNTIMES_DIR: runtimesDir ?? "",
211
213
  },
212
214
  });
213
215
  }
@@ -285,19 +287,35 @@ function createCopilotBridgeRequestHandler(context) {
285
287
  }
286
288
  if (method === "POST" && url === "/v1/chat/completions") {
287
289
  const body = await readJsonBody(request);
290
+ const timeoutMs = parseBridgeRequestTimeoutMs(body, "/v1/chat/completions");
288
291
  const stream = Boolean(body.stream);
289
- const payload = await context.executeChatCompletion(body);
290
292
  if (stream) {
291
293
  response.writeHead(200, {
292
294
  "content-type": "text/event-stream",
293
295
  "cache-control": "no-cache",
294
296
  connection: "keep-alive",
295
297
  });
296
- response.write(`data: ${JSON.stringify(payload)}\n\n`);
298
+ const heartbeat = startSseHeartbeat(response);
299
+ const payload = await context.executeChatCompletion(body, {
300
+ timeoutMs,
301
+ onTextDelta: (delta) => {
302
+ response.write(`data: ${JSON.stringify({
303
+ choices: [
304
+ {
305
+ index: 0,
306
+ delta: { content: delta },
307
+ finish_reason: null,
308
+ },
309
+ ],
310
+ })}\n\n`);
311
+ },
312
+ });
313
+ clearInterval(heartbeat);
297
314
  response.write("data: [DONE]\n\n");
298
315
  response.end();
299
316
  return;
300
317
  }
318
+ const payload = await context.executeChatCompletion(body, { timeoutMs });
301
319
  response.writeHead(200, { "content-type": "application/json" });
302
320
  response.end(JSON.stringify(payload));
303
321
  return;
@@ -305,20 +323,43 @@ function createCopilotBridgeRequestHandler(context) {
305
323
  if (method === "POST" && url === "/v1/responses") {
306
324
  const body = await readJsonBody(request);
307
325
  const normalized = normalizeResponsesRequest(body);
308
- const payload = await context.executeChatCompletion({
326
+ const chatPayload = {
309
327
  model: normalized.model,
310
328
  messages: normalized.messages,
311
- });
329
+ };
312
330
  if (normalized.stream) {
313
331
  response.writeHead(200, {
314
332
  "content-type": "text/event-stream",
315
333
  "cache-control": "no-cache",
316
334
  connection: "keep-alive",
317
335
  });
318
- writeResponsesStream(response, payload);
336
+ const responseId = `resp_${Date.now()}`;
337
+ const messageId = buildResponsesMessageId(responseId);
338
+ writeResponsesStreamStart(response, responseId, normalized.model, messageId);
339
+ const heartbeat = startSseHeartbeat(response);
340
+ let text = "";
341
+ const payload = await context.executeChatCompletion(chatPayload, {
342
+ timeoutMs: normalized.timeoutMs,
343
+ onTextDelta: (delta) => {
344
+ text += delta;
345
+ writeResponsesTextDelta(response, messageId, delta);
346
+ },
347
+ onTextDone: (doneText) => {
348
+ if (text.length === 0) {
349
+ text = doneText;
350
+ writeResponsesTextDelta(response, messageId, doneText);
351
+ }
352
+ },
353
+ });
354
+ clearInterval(heartbeat);
355
+ const outputText = text || getChatCompletionText(payload);
356
+ writeResponsesStreamDone(response, responseId, normalized.model, messageId, outputText);
319
357
  response.end();
320
358
  return;
321
359
  }
360
+ const payload = await context.executeChatCompletion(chatPayload, {
361
+ timeoutMs: normalized.timeoutMs,
362
+ });
322
363
  response.writeHead(200, { "content-type": "application/json" });
323
364
  response.end(JSON.stringify(buildResponsesPayload(payload)));
324
365
  return;
@@ -332,9 +373,9 @@ function createCopilotBridgeRequestHandler(context) {
332
373
  response.end(JSON.stringify({ error: { message: "Not found" } }));
333
374
  }
334
375
  catch (error) {
335
- const statusCode = isCliError(error) && error.code === "BRIDGE_UNSUPPORTED_REQUEST" ? 400 : 500;
376
+ const statusCode = mapBridgeErrorStatus(error);
336
377
  response.writeHead(statusCode, { "content-type": "application/json" });
337
- response.end(JSON.stringify({ error: { message: error instanceof Error ? error.message : String(error) } }));
378
+ response.end(JSON.stringify({ error: { message: error instanceof Error ? error.message : String(error), code: isCliError(error) ? error.code : "BRIDGE_RUNTIME_FAILURE" } }));
338
379
  }
339
380
  };
340
381
  }
@@ -354,8 +395,22 @@ function normalizeResponsesRequest(body) {
354
395
  model: payload.model,
355
396
  messages,
356
397
  stream: payload.stream === true,
398
+ timeoutMs: parseBridgeRequestTimeoutMs(body, "/v1/responses"),
357
399
  };
358
400
  }
401
+ /**
402
+ * Extracts one optional request timeout for bridge-backed completions.
403
+ */
404
+ function parseBridgeRequestTimeoutMs(body, endpoint) {
405
+ const timeoutMsValue = body.timeout_ms ?? body.timeoutMs;
406
+ if (timeoutMsValue === undefined) {
407
+ return undefined;
408
+ }
409
+ if (typeof timeoutMsValue !== "number" || !Number.isFinite(timeoutMsValue) || timeoutMsValue <= 0) {
410
+ throw (0, errors_1.cliError)("BRIDGE_UNSUPPORTED_REQUEST", `Copilot bridge ${endpoint} timeout must be a positive number when provided.`);
411
+ }
412
+ return timeoutMsValue;
413
+ }
359
414
  function normalizeResponsesInput(input) {
360
415
  if (typeof input === "string") {
361
416
  return [{ role: "user", content: input }];
@@ -575,6 +630,118 @@ function writeResponsesStream(response, payload) {
575
630
  },
576
631
  });
577
632
  }
633
+ function writeResponsesStreamStart(response, responseId, model, messageId) {
634
+ const createdAt = Math.floor(Date.now() / 1000);
635
+ const inProgressResponse = {
636
+ id: responseId,
637
+ object: "response",
638
+ created_at: createdAt,
639
+ model,
640
+ status: "in_progress",
641
+ output: [],
642
+ output_text: "",
643
+ };
644
+ writeSseEvent(response, "response.created", {
645
+ type: "response.created",
646
+ response: inProgressResponse,
647
+ });
648
+ writeSseEvent(response, "response.in_progress", {
649
+ type: "response.in_progress",
650
+ response: inProgressResponse,
651
+ });
652
+ writeSseEvent(response, "response.output_item.added", {
653
+ type: "response.output_item.added",
654
+ output_index: 0,
655
+ item: {
656
+ id: messageId,
657
+ type: "message",
658
+ status: "in_progress",
659
+ role: "assistant",
660
+ content: [],
661
+ },
662
+ });
663
+ writeSseEvent(response, "response.content_part.added", {
664
+ type: "response.content_part.added",
665
+ item_id: messageId,
666
+ output_index: 0,
667
+ content_index: 0,
668
+ part: {
669
+ type: "output_text",
670
+ text: "",
671
+ annotations: [],
672
+ },
673
+ });
674
+ }
675
+ function writeResponsesTextDelta(response, messageId, delta) {
676
+ if (delta.length === 0) {
677
+ return;
678
+ }
679
+ writeSseEvent(response, "response.output_text.delta", {
680
+ type: "response.output_text.delta",
681
+ item_id: messageId,
682
+ output_index: 0,
683
+ content_index: 0,
684
+ delta,
685
+ });
686
+ }
687
+ function writeResponsesStreamDone(response, responseId, model, messageId, outputText) {
688
+ const completedMessage = {
689
+ id: messageId,
690
+ type: "message",
691
+ status: "completed",
692
+ role: "assistant",
693
+ content: [
694
+ {
695
+ type: "output_text",
696
+ text: outputText,
697
+ annotations: [],
698
+ },
699
+ ],
700
+ };
701
+ writeSseEvent(response, "response.output_text.done", {
702
+ type: "response.output_text.done",
703
+ item_id: messageId,
704
+ output_index: 0,
705
+ content_index: 0,
706
+ text: outputText,
707
+ });
708
+ writeSseEvent(response, "response.content_part.done", {
709
+ type: "response.content_part.done",
710
+ item_id: messageId,
711
+ output_index: 0,
712
+ content_index: 0,
713
+ part: {
714
+ type: "output_text",
715
+ text: outputText,
716
+ annotations: [],
717
+ },
718
+ });
719
+ writeSseEvent(response, "response.output_item.done", {
720
+ type: "response.output_item.done",
721
+ output_index: 0,
722
+ item: completedMessage,
723
+ });
724
+ writeSseEvent(response, "response.completed", {
725
+ type: "response.completed",
726
+ response: {
727
+ id: responseId,
728
+ object: "response",
729
+ created_at: Math.floor(Date.now() / 1000),
730
+ model,
731
+ status: "completed",
732
+ output: [completedMessage],
733
+ output_text: outputText,
734
+ },
735
+ });
736
+ }
737
+ function startSseHeartbeat(response) {
738
+ return setInterval(() => {
739
+ response.write(": keep-alive\n\n");
740
+ }, 15000);
741
+ }
742
+ function getChatCompletionText(payload) {
743
+ return payload.choices?.[0]?.message?.content ?? "";
744
+ }
578
745
  /**
579
746
  * Formats and writes one server-sent event frame.
580
747
  */
@@ -594,6 +761,21 @@ function buildResponsesMessageId(responseId) {
594
761
  function isCliError(error) {
595
762
  return Boolean(error && typeof error === "object" && typeof error.code === "string");
596
763
  }
764
+ function mapBridgeErrorStatus(error) {
765
+ if (!isCliError(error)) {
766
+ return 500;
767
+ }
768
+ if (error.code === "BRIDGE_UNSUPPORTED_REQUEST") {
769
+ return 400;
770
+ }
771
+ if (error.code === "COPILOT_AUTH_REQUIRED") {
772
+ return 401;
773
+ }
774
+ if (error.code === "BRIDGE_UPSTREAM_TIMEOUT") {
775
+ return 504;
776
+ }
777
+ return 500;
778
+ }
597
779
  /**
598
780
  * Returns a stable build identifier for the compiled bridge worker bundle.
599
781
  */
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.setCopilotCliSpawnImplementation = setCopilotCliSpawnImplementation;
37
37
  exports.resetCopilotCliSpawnImplementation = resetCopilotCliSpawnImplementation;
38
38
  exports.checkCopilotCliAvailable = checkCopilotCliAvailable;
39
+ exports.resolveCopilotCliInvocation = resolveCopilotCliInvocation;
39
40
  exports.runCopilotLogin = runCopilotLogin;
40
41
  const fs = __importStar(require("node:fs"));
41
42
  const path = __importStar(require("node:path"));
@@ -78,6 +79,12 @@ function checkCopilotCliAvailable(runtimesDir) {
78
79
  command: formatInvocation(invocation),
79
80
  };
80
81
  }
82
+ /**
83
+ * Resolves the Copilot CLI invocation used by SDK clients and command probes.
84
+ */
85
+ function resolveCopilotCliInvocation(args = [], runtimesDir) {
86
+ return getCopilotInvocation(args, runtimesDir);
87
+ }
81
88
  /**
82
89
  * Launches the official `copilot login` flow in the current terminal.
83
90
  */
@@ -37,6 +37,10 @@ exports.setCopilotInstallerSpawnImplementation = setCopilotInstallerSpawnImpleme
37
37
  exports.resetCopilotInstallerSpawnImplementation = resetCopilotInstallerSpawnImplementation;
38
38
  exports.getCopilotRuntimeInstallDir = getCopilotRuntimeInstallDir;
39
39
  exports.getCopilotSdkPackageName = getCopilotSdkPackageName;
40
+ exports.getSupportedCopilotSdkVersion = getSupportedCopilotSdkVersion;
41
+ exports.getCopilotNodeRuntimeStatus = getCopilotNodeRuntimeStatus;
42
+ exports.assertCopilotNodeRuntimeSupported = assertCopilotNodeRuntimeSupported;
43
+ exports.isSupportedCopilotSdkVersion = isSupportedCopilotSdkVersion;
40
44
  exports.probeCopilotSdkInstall = probeCopilotSdkInstall;
41
45
  exports.installCopilotSdk = installCopilotSdk;
42
46
  const fs = __importStar(require("node:fs"));
@@ -45,7 +49,8 @@ const node_child_process_1 = require("node:child_process");
45
49
  const errors_1 = require("../domain/errors");
46
50
  const codex_paths_1 = require("../storage/codex-paths");
47
51
  const COPILOT_SDK_PACKAGE = "@github/copilot-sdk";
48
- const COPILOT_SDK_VERSION = "latest";
52
+ const COPILOT_SDK_VERSION = "1.0.2";
53
+ const COPILOT_MIN_NODE_MAJOR = 20;
49
54
  let spawnImplementation = node_child_process_1.spawnSync;
50
55
  /**
51
56
  * Overrides the spawn implementation for runtime installer tests.
@@ -76,6 +81,47 @@ function getCopilotRuntimeInstallDir(runtimesDir) {
76
81
  function getCopilotSdkPackageName() {
77
82
  return COPILOT_SDK_PACKAGE;
78
83
  }
84
+ /**
85
+ * Returns the supported Copilot SDK package version installed by this release.
86
+ */
87
+ function getSupportedCopilotSdkVersion() {
88
+ return COPILOT_SDK_VERSION;
89
+ }
90
+ /**
91
+ * Returns whether the active Node.js runtime can run the Copilot SDK path.
92
+ */
93
+ function getCopilotNodeRuntimeStatus(version = process.versions.node) {
94
+ const major = Number(version.split(".")[0]);
95
+ if (Number.isInteger(major) && major >= COPILOT_MIN_NODE_MAJOR) {
96
+ return { ok: true, version };
97
+ }
98
+ return {
99
+ ok: false,
100
+ version,
101
+ required: `>=${String(COPILOT_MIN_NODE_MAJOR)}`,
102
+ };
103
+ }
104
+ /**
105
+ * Fails early when a command path requires the Copilot SDK runtime under Node.js <20.
106
+ */
107
+ function assertCopilotNodeRuntimeSupported(version = process.versions.node) {
108
+ const status = getCopilotNodeRuntimeStatus(version);
109
+ if (!status.ok) {
110
+ throw (0, errors_1.cliError)("COPILOT_RUNTIME_NODE_UNSUPPORTED", "Copilot runtime support requires Node.js >=20. Direct providers continue to support Node.js >=18.", {
111
+ nodeVersion: status.version,
112
+ requiredNode: status.required,
113
+ });
114
+ }
115
+ }
116
+ /**
117
+ * Returns whether an installed Copilot SDK version is supported by this release.
118
+ */
119
+ function isSupportedCopilotSdkVersion(version) {
120
+ if (!version || version.includes("-")) {
121
+ return false;
122
+ }
123
+ return compareSemver(version, COPILOT_SDK_VERSION) >= 0;
124
+ }
79
125
  /**
80
126
  * Reports whether the optional Copilot SDK runtime is currently installed.
81
127
  */
@@ -153,6 +199,18 @@ function resolveNpmInstallCommand() {
153
199
  args: installArgs,
154
200
  };
155
201
  }
202
+ function compareSemver(left, right) {
203
+ const leftParts = left.split(".").map((part) => Number(part));
204
+ const rightParts = right.split(".").map((part) => Number(part));
205
+ for (let index = 0; index < 3; index += 1) {
206
+ const leftPart = Number.isFinite(leftParts[index]) ? leftParts[index] : 0;
207
+ const rightPart = Number.isFinite(rightParts[index]) ? rightParts[index] : 0;
208
+ if (leftPart !== rightPart) {
209
+ return leftPart > rightPart ? 1 : -1;
210
+ }
211
+ }
212
+ return 0;
213
+ }
156
214
  /**
157
215
  * Finds a locally available npm CLI script near the active Node runtime.
158
216
  */
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getCopilotSdkEntrypoint = getCopilotSdkEntrypoint;
37
37
  exports.loadCopilotSdk = loadCopilotSdk;
38
38
  const path = __importStar(require("node:path"));
39
+ const node_module_1 = require("node:module");
39
40
  const errors_1 = require("../domain/errors");
40
41
  const copilot_installer_1 = require("./copilot-installer");
41
42
  /**
@@ -55,5 +56,7 @@ async function loadCopilotSdk(runtimesDir) {
55
56
  packageName: status.packageName,
56
57
  });
57
58
  }
58
- return Promise.resolve(`${getCopilotSdkEntrypoint(runtimesDir)}`).then(s => __importStar(require(s)));
59
+ const runtimePackageJson = path.join(status.installDir, "package.json");
60
+ const runtimeRequire = (0, node_module_1.createRequire)(runtimePackageJson);
61
+ return runtimeRequire("@github/copilot-sdk");
59
62
  }
@@ -73,12 +73,12 @@ function readStructuredConfig(configPath) {
73
73
  }
74
74
  }
75
75
  /**
76
- * Reads the active top-level profile from config.toml.
76
+ * Reads the active top-level model_provider route from config.toml.
77
77
  */
78
78
  function readCurrentProfile(configPath) {
79
- const profile = readStructuredConfig(configPath).activeProfile ?? (0, config_1.parseTopLevelProfile)(readConfigFile(configPath));
79
+ const profile = readStructuredConfig(configPath).currentModelProvider;
80
80
  if (!profile) {
81
- throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", "No top-level profile is set in config.toml.", {
81
+ throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", "No top-level model_provider is set in config.toml.", {
82
82
  file: configPath,
83
83
  });
84
84
  }
@@ -91,18 +91,10 @@ function listConfigProfiles(configPath) {
91
91
  return new Set(readStructuredConfig(configPath).profiles.map((profile) => profile.name));
92
92
  }
93
93
  /**
94
- * Verifies that a provider's target profile exists before a switch operation proceeds.
94
+ * Loads config.toml for commands that project one model_provider route.
95
95
  */
96
96
  function ensureProfileExists(configPath, profile, provider) {
97
- const document = readStructuredConfig(configPath);
98
- if (!document.profiles.some((entry) => entry.name === profile)) {
99
- throw (0, errors_1.cliError)("PROFILE_NOT_FOUND", `Profile "${profile}" does not exist in config.toml.`, {
100
- file: configPath,
101
- provider,
102
- profile,
103
- });
104
- }
105
- return document;
97
+ return readStructuredConfig(configPath);
106
98
  }
107
99
  /**
108
100
  * Resolves one profile view and enforces the managed model_provider contract.
@@ -166,7 +158,7 @@ function requireModelProviderRuntimeSection(document, profile) {
166
158
  */
167
159
  function updateTopLevelProfile(configPath, configContent, profile) {
168
160
  (0, fs_utils_1.writeTextFileAtomic)(configPath, (0, config_1.applyPatchOperations)(configContent, (0, config_1.planConfigMutation)((0, config_1.parseStructuredConfig)(configContent), {
169
- setActiveProfile: profile,
161
+ setLegacyProfile: profile,
170
162
  }).operations));
171
163
  }
172
164
  /**