@minniexcode/codex-switch 0.1.1 → 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 (48) hide show
  1. package/README.CN.md +6 -4
  2. package/README.md +13 -4
  3. package/dist/app/add-provider.js +1 -0
  4. package/dist/app/bridge.js +2 -1
  5. package/dist/app/switch-provider.js +2 -1
  6. package/dist/commands/handlers.js +1 -0
  7. package/dist/domain/config.js +45 -1
  8. package/dist/domain/providers.js +1 -0
  9. package/dist/runtime/copilot-adapter.js +326 -70
  10. package/dist/runtime/copilot-bridge-worker.js +27 -2
  11. package/dist/runtime/copilot-bridge.js +192 -10
  12. package/dist/runtime/copilot-cli.js +7 -0
  13. package/dist/runtime/copilot-installer.js +59 -1
  14. package/dist/runtime/copilot-sdk-loader.js +4 -1
  15. package/docs/Design/codex-switch-v0.1.0-design.md +32 -152
  16. package/docs/Design/codex-switch-v0.1.1-design.md +15 -26
  17. package/docs/Design/codex-switch-v0.1.2-design.md +65 -0
  18. package/docs/PRD/codex-switch-prd-v0.1.0.md +65 -217
  19. package/docs/PRD/codex-switch-prd-v0.1.1.md +26 -0
  20. package/docs/PRD/codex-switch-prd-v0.1.2.md +41 -0
  21. package/docs/Tests/testing.md +1 -1
  22. package/docs/cli-usage.md +12 -4
  23. package/docs/codex-switch-command-design.md +1 -1
  24. package/docs/codex-switch-product-overview.md +7 -3
  25. package/docs/codex-switch-product-research.md +2 -2
  26. package/docs/codex-switch-technical-architecture.md +84 -1115
  27. package/package.json +1 -1
  28. package/docs/Design/codex-switch-copilot-integration-design.md +0 -517
  29. package/docs/Design/codex-switch-v0.0.10-design.md +0 -669
  30. package/docs/Design/codex-switch-v0.0.11-design.md +0 -824
  31. package/docs/Design/codex-switch-v0.0.12-design.md +0 -343
  32. package/docs/Design/codex-switch-v0.0.4-design.md +0 -874
  33. package/docs/Design/codex-switch-v0.0.5-design.md +0 -932
  34. package/docs/Design/codex-switch-v0.0.6-design.md +0 -708
  35. package/docs/Design/codex-switch-v0.0.7-design.md +0 -862
  36. package/docs/Design/codex-switch-v0.0.8-design.md +0 -132
  37. package/docs/Design/codex-switch-v0.0.9-design.md +0 -182
  38. package/docs/Design/codex-switch-v0.0.9-to-v0.0.12-roadmap.md +0 -413
  39. package/docs/PRD/codex-switch-prd-v0.0.10.md +0 -406
  40. package/docs/PRD/codex-switch-prd-v0.0.11.md +0 -577
  41. package/docs/PRD/codex-switch-prd-v0.0.12.md +0 -279
  42. package/docs/PRD/codex-switch-prd-v0.0.5-to-v0.1.0.md +0 -446
  43. package/docs/PRD/codex-switch-prd-v0.0.8.md +0 -62
  44. package/docs/PRD/codex-switch-prd-v0.0.9.md +0 -166
  45. package/docs/PRD/codex-switch-prd.md +0 -650
  46. package/docs/Tests/test-report-0.0.5.md +0 -163
  47. package/docs/Tests/test-report-0.0.7.md +0 -118
  48. package/docs/Tests/testing-bridge-v0.0.9.md +0 -367
@@ -1,16 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventEmitter = void 0;
3
4
  exports.probeCopilotSdkRuntime = probeCopilotSdkRuntime;
4
5
  exports.requireCopilotSdk = requireCopilotSdk;
5
6
  exports.readCopilotAuthState = readCopilotAuthState;
7
+ exports.createCopilotRuntimeClient = createCopilotRuntimeClient;
8
+ exports.startCopilotRuntimeClient = startCopilotRuntimeClient;
9
+ exports.stopCopilotRuntimeClient = stopCopilotRuntimeClient;
6
10
  exports.sendCopilotChatCompletion = sendCopilotChatCompletion;
11
+ const node_events_1 = require("node:events");
12
+ Object.defineProperty(exports, "EventEmitter", { enumerable: true, get: function () { return node_events_1.EventEmitter; } });
7
13
  const errors_1 = require("../domain/errors");
8
14
  const copilot_sdk_loader_1 = require("./copilot-sdk-loader");
9
15
  const copilot_installer_1 = require("./copilot-installer");
16
+ const copilot_cli_1 = require("./copilot-cli");
17
+ const DEFAULT_UPSTREAM_TIMEOUT_MS = 300000;
10
18
  /**
11
- * Probes whether the optional Copilot SDK runtime is installed and loadable.
19
+ * Probes whether the optional Copilot SDK runtime is installed, supported, and shaped correctly.
12
20
  */
13
21
  function probeCopilotSdkRuntime(runtimesDir) {
22
+ const nodeStatus = safeCopilotNodeRuntimeStatus();
23
+ if (!nodeStatus.ok) {
24
+ return nodeStatus.availability;
25
+ }
14
26
  const status = (0, copilot_installer_1.probeCopilotSdkInstall)(runtimesDir);
15
27
  if (!status.installed) {
16
28
  return {
@@ -24,6 +36,21 @@ function probeCopilotSdkRuntime(runtimesDir) {
24
36
  },
25
37
  };
26
38
  }
39
+ if (!(0, copilot_installer_1.isSupportedCopilotSdkVersion)(status.packageVersion)) {
40
+ return {
41
+ ok: false,
42
+ runtime: "copilot-sdk",
43
+ reason: "unsupported",
44
+ version: status.packageVersion ?? undefined,
45
+ cause: `The installed Copilot SDK version is unsupported. Install ${status.packageName}@${(0, copilot_installer_1.getSupportedCopilotSdkVersion)()}.`,
46
+ details: {
47
+ installDir: status.installDir,
48
+ packageName: status.packageName,
49
+ packageVersion: status.packageVersion,
50
+ supportedVersion: (0, copilot_installer_1.getSupportedCopilotSdkVersion)(),
51
+ },
52
+ };
53
+ }
27
54
  return {
28
55
  ok: true,
29
56
  runtime: "copilot-sdk",
@@ -41,55 +68,83 @@ async function requireCopilotSdk(runtimesDir) {
41
68
  return (0, copilot_sdk_loader_1.loadCopilotSdk)(runtimesDir);
42
69
  }
43
70
  /**
44
- * Probes whether the lazily installed Copilot SDK can create a usable session.
71
+ * Probes Copilot auth readiness through the SDK client status endpoint.
45
72
  */
46
73
  async function readCopilotAuthState(runtimesDir) {
47
74
  const runtime = probeCopilotSdkRuntime(runtimesDir);
48
75
  if (!runtime.ok) {
49
- throw (0, errors_1.cliError)("COPILOT_SDK_MISSING", "The optional Copilot SDK runtime is not installed.", runtime.details);
76
+ throw (0, errors_1.cliError)(runtime.reason === "unsupported" ? "COPILOT_SDK_VERSION_UNSUPPORTED" : "COPILOT_SDK_MISSING", runtime.cause, runtime.details);
50
77
  }
51
- const { client, session } = await createCopilotSession(runtimesDir);
52
- await stopCopilotClient(client);
53
- return {
54
- ready: Boolean(session),
55
- source: "official-sdk",
56
- mode: "session",
57
- };
78
+ const runtimeClient = await createCopilotRuntimeClient(runtimesDir);
79
+ try {
80
+ await startCopilotClient(runtimeClient.client);
81
+ const getAuthStatus = resolveCallable(runtimeClient.client, "getAuthStatus");
82
+ if (!getAuthStatus) {
83
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose CopilotClient.getAuthStatus().", {});
84
+ }
85
+ const status = await Promise.resolve(getAuthStatus());
86
+ if (!isAuthReady(status)) {
87
+ throw (0, errors_1.cliError)("COPILOT_AUTH_REQUIRED", "Copilot authentication is required before the local bridge can be used.", {
88
+ status,
89
+ });
90
+ }
91
+ return {
92
+ ready: true,
93
+ source: "official-sdk",
94
+ mode: "auth-status",
95
+ };
96
+ }
97
+ finally {
98
+ await stopCopilotClient(runtimeClient.client);
99
+ }
100
+ }
101
+ /**
102
+ * Creates one long-lived Copilot SDK client for bridge workers.
103
+ */
104
+ async function createCopilotRuntimeClient(runtimesDir) {
105
+ (0, copilot_installer_1.assertCopilotNodeRuntimeSupported)();
106
+ const runtime = probeCopilotSdkRuntime(runtimesDir);
107
+ if (!runtime.ok) {
108
+ throw (0, errors_1.cliError)(runtime.reason === "unsupported" ? "COPILOT_SDK_VERSION_UNSUPPORTED" : "COPILOT_SDK_MISSING", runtime.cause, runtime.details);
109
+ }
110
+ const sdk = (await requireCopilotSdk(runtimesDir));
111
+ const client = createCopilotClient(sdk, runtimesDir);
112
+ assertCopilotSdkApiContract(sdk, client);
113
+ return { sdk, client };
114
+ }
115
+ /**
116
+ * Starts a Copilot SDK client if the installed SDK exposes an explicit start hook.
117
+ */
118
+ async function startCopilotRuntimeClient(runtimeClient) {
119
+ await startCopilotClient(runtimeClient.client);
58
120
  }
59
121
  /**
60
- * Executes a single chat-completions style request through the optional Copilot SDK when available.
122
+ * Stops a Copilot SDK client.
123
+ */
124
+ async function stopCopilotRuntimeClient(runtimeClient) {
125
+ await stopCopilotClient(runtimeClient.client);
126
+ }
127
+ /**
128
+ * Executes one OpenAI-compatible request through a fresh Copilot session.
61
129
  */
62
130
  async function sendCopilotChatCompletion(args) {
63
- const { client, session, sdk } = await createCopilotSession(args.runtimesDir);
131
+ const ownsClient = !args.runtimeClient;
132
+ const runtimeClient = args.runtimeClient ?? await createCopilotRuntimeClient(args.runtimesDir);
133
+ if (ownsClient) {
134
+ await startCopilotRuntimeClient(runtimeClient);
135
+ }
136
+ let session = null;
64
137
  try {
65
- const sendAndWait = resolveCallable(session, "sendAndWait") ?? resolveCallable(sdk, "sendAndWait");
66
- if (!sendAndWait) {
67
- throw (0, errors_1.cliError)("COPILOT_SDK_UNSUPPORTED", "The installed Copilot SDK does not expose a supported sendAndWait API.", {
68
- provider: args.provider,
69
- });
70
- }
71
- const prompt = Array.isArray(args.payload.messages)
72
- ? args.payload.messages
73
- .map((entry) => {
74
- const message = entry;
75
- return `${String(message.role ?? "user")}: ${String(message.content ?? "")}`;
76
- })
77
- .join("\n")
78
- : "";
79
- const result = await Promise.resolve(sendAndWait({ model: args.payload.model, prompt }));
80
- const content = typeof result === "string"
81
- ? result
82
- : typeof result?.content === "string"
83
- ? String(result.content)
84
- : typeof result?.data === "object" &&
85
- typeof result.data.content === "string"
86
- ? String(result.data.content)
87
- : JSON.stringify(result);
138
+ session = await createCopilotSession(runtimeClient, args.payload);
139
+ const prompt = buildPrompt(args.payload);
140
+ const timeoutMs = args.timeoutMs ?? DEFAULT_UPSTREAM_TIMEOUT_MS;
141
+ const result = await sendSessionRequest(session, prompt, timeoutMs, args.onStreamEvent);
142
+ const content = extractCopilotContent(result);
88
143
  return {
89
144
  id: `copilot-${Date.now()}`,
90
145
  object: "chat.completion",
91
146
  created: Math.floor(Date.now() / 1000),
92
- model: args.payload.model ?? "copilot",
147
+ model: typeof args.payload.model === "string" ? args.payload.model : "copilot",
93
148
  choices: [
94
149
  {
95
150
  index: 0,
@@ -103,27 +158,36 @@ async function sendCopilotChatCompletion(args) {
103
158
  };
104
159
  }
105
160
  finally {
106
- await stopCopilotClient(client);
161
+ if (session) {
162
+ await disconnectCopilotSession(session);
163
+ }
164
+ if (ownsClient) {
165
+ await stopCopilotRuntimeClient(runtimeClient);
166
+ }
107
167
  }
108
168
  }
109
- async function createCopilotSession(runtimesDir) {
110
- const sdk = (await requireCopilotSdk(runtimesDir));
111
- const client = createCopilotClient(sdk);
112
- const createSession = resolveCallable(client ? client : null, "createSession") ?? resolveCallable(sdk, "createSession");
169
+ async function createCopilotSession(runtimeClient, payload) {
170
+ const createSession = resolveCallable(runtimeClient.client, "createSession");
113
171
  if (!createSession) {
114
- throw (0, errors_1.cliError)("COPILOT_SDK_UNSUPPORTED", "The installed Copilot SDK does not expose a supported createSession API.", {});
172
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose CopilotClient.createSession().", {});
115
173
  }
116
174
  try {
117
- const session = (await Promise.resolve(createSession(createSessionOptions(sdk))));
118
- return {
119
- sdk,
120
- client,
121
- session,
122
- };
175
+ const session = await Promise.resolve(createSession({
176
+ model: typeof payload.model === "string" ? payload.model : undefined,
177
+ ...createSessionOptions(runtimeClient.sdk),
178
+ }));
179
+ if (!session || typeof session !== "object") {
180
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK returned an invalid CopilotSession.", {});
181
+ }
182
+ assertCopilotSessionContract(session);
183
+ return session;
123
184
  }
124
185
  catch (error) {
186
+ if (isCliError(error)) {
187
+ throw error;
188
+ }
125
189
  if (classifyCopilotSessionError(error) === "unsupported") {
126
- throw (0, errors_1.cliError)("COPILOT_SDK_UNSUPPORTED", "The installed Copilot SDK does not expose a compatible permission-handling session API.", {
190
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose a compatible session API.", {
127
191
  cause: error instanceof Error ? error.message : String(error),
128
192
  });
129
193
  }
@@ -132,9 +196,61 @@ async function createCopilotSession(runtimesDir) {
132
196
  });
133
197
  }
134
198
  }
135
- /**
136
- * Builds the session options used consistently across auth probes and request execution.
137
- */
199
+ async function sendSessionRequest(session, prompt, timeoutMs, onStreamEvent) {
200
+ const sendAndWait = resolveCallable(session, "sendAndWait");
201
+ const send = resolveCallable(session, "send");
202
+ if (!sendAndWait && !send) {
203
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK session does not expose sendAndWait() or send().", {});
204
+ }
205
+ const deltaHandler = (event) => {
206
+ const delta = extractDelta(event);
207
+ if (delta) {
208
+ onStreamEvent?.({ type: "delta", delta });
209
+ }
210
+ };
211
+ if (onStreamEvent && session.on) {
212
+ session.on("data", deltaHandler);
213
+ session.on("message", deltaHandler);
214
+ session.on("delta", deltaHandler);
215
+ }
216
+ try {
217
+ const sendPromise = Promise.resolve(sendAndWait ? sendAndWait({ prompt }, timeoutMs) : send({ prompt }));
218
+ const result = await withTimeout(sendPromise, timeoutMs, async () => {
219
+ await abortCopilotSession(session);
220
+ });
221
+ if (onStreamEvent) {
222
+ onStreamEvent({ type: "done", text: extractCopilotContent(result) });
223
+ }
224
+ return result;
225
+ }
226
+ finally {
227
+ if (onStreamEvent && session.off) {
228
+ session.off("data", deltaHandler);
229
+ session.off("message", deltaHandler);
230
+ session.off("delta", deltaHandler);
231
+ }
232
+ }
233
+ }
234
+ async function withTimeout(promise, timeoutMs, onTimeout) {
235
+ let timeout = null;
236
+ try {
237
+ return await Promise.race([
238
+ promise,
239
+ new Promise((_resolve, reject) => {
240
+ timeout = setTimeout(() => {
241
+ void onTimeout().finally(() => {
242
+ reject((0, errors_1.cliError)("BRIDGE_UPSTREAM_TIMEOUT", "Copilot upstream request timed out.", { timeoutMs }));
243
+ });
244
+ }, timeoutMs);
245
+ }),
246
+ ]);
247
+ }
248
+ finally {
249
+ if (timeout) {
250
+ clearTimeout(timeout);
251
+ }
252
+ }
253
+ }
138
254
  function createSessionOptions(sdk) {
139
255
  const approveAll = resolveApproveAll(sdk);
140
256
  if (approveAll) {
@@ -142,35 +258,153 @@ function createSessionOptions(sdk) {
142
258
  onPermissionRequest: (request) => approveAll(request),
143
259
  };
144
260
  }
145
- return {
146
- onPermissionRequest: () => true,
147
- };
261
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose an approveAll permission handler.", {});
148
262
  }
149
- function createCopilotClient(sdk) {
263
+ function createCopilotClient(sdk, runtimesDir) {
150
264
  const ClientCtor = resolveConstructor(sdk, "CopilotClient");
151
265
  if (!ClientCtor) {
152
- return null;
266
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose CopilotClient.", {});
153
267
  }
268
+ const invocation = (0, copilot_cli_1.resolveCopilotCliInvocation)([], runtimesDir);
269
+ const clientOptions = {
270
+ copilotCommand: invocation.command,
271
+ command: invocation.command,
272
+ executable: invocation.command,
273
+ };
154
274
  try {
155
- return new ClientCtor();
275
+ return new ClientCtor(clientOptions);
156
276
  }
157
277
  catch (error) {
158
- throw (0, errors_1.cliError)("COPILOT_SDK_UNSUPPORTED", "The installed Copilot SDK CopilotClient could not be constructed.", {
278
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK CopilotClient could not be constructed.", {
159
279
  cause: error instanceof Error ? error.message : String(error),
160
280
  });
161
281
  }
162
282
  }
283
+ function assertCopilotSdkApiContract(sdk, client) {
284
+ const createSession = resolveCallable(client, "createSession");
285
+ const getAuthStatus = resolveCallable(client, "getAuthStatus");
286
+ if (!createSession || !getAuthStatus) {
287
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose the required CopilotClient API.", {
288
+ hasCreateSession: Boolean(createSession),
289
+ hasGetAuthStatus: Boolean(getAuthStatus),
290
+ });
291
+ }
292
+ if (!resolveApproveAll(sdk)) {
293
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose a supported permission handler.", {});
294
+ }
295
+ }
296
+ function assertCopilotSessionContract(session) {
297
+ const hasSendAndWait = typeof session.sendAndWait === "function";
298
+ const hasSend = typeof session.send === "function";
299
+ const hasAbort = typeof session.abort === "function";
300
+ if ((!hasSendAndWait && !hasSend) || !hasAbort) {
301
+ throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK session does not expose the required request API.", {
302
+ hasSendAndWait,
303
+ hasSend,
304
+ hasAbort,
305
+ });
306
+ }
307
+ }
308
+ async function startCopilotClient(client) {
309
+ const start = resolveCallable(client, "start");
310
+ if (start) {
311
+ await Promise.resolve(start());
312
+ }
313
+ }
163
314
  async function stopCopilotClient(client) {
164
- if (client && typeof client.stop === "function") {
165
- await Promise.resolve(client.stop());
315
+ const stop = resolveCallable(client, "stop");
316
+ if (stop) {
317
+ await Promise.resolve(stop());
166
318
  }
167
319
  }
168
- /**
169
- * Distinguishes true auth failures from SDK API-shape mismatches.
170
- */
320
+ async function abortCopilotSession(session) {
321
+ const abort = resolveCallable(session, "abort");
322
+ if (abort) {
323
+ await Promise.resolve(abort());
324
+ }
325
+ }
326
+ async function disconnectCopilotSession(session) {
327
+ const disconnect = resolveCallable(session, "disconnect");
328
+ if (disconnect) {
329
+ await Promise.resolve(disconnect());
330
+ }
331
+ }
332
+ function buildPrompt(payload) {
333
+ if (Array.isArray(payload.messages)) {
334
+ return payload.messages
335
+ .map((entry) => {
336
+ const message = entry;
337
+ return `${String(message.role ?? "user")}: ${String(message.content ?? "")}`;
338
+ })
339
+ .join("\n");
340
+ }
341
+ if (typeof payload.prompt === "string") {
342
+ return payload.prompt;
343
+ }
344
+ return "";
345
+ }
346
+ function extractCopilotContent(result) {
347
+ if (typeof result === "string") {
348
+ return result;
349
+ }
350
+ if (!result || typeof result !== "object") {
351
+ return JSON.stringify(result);
352
+ }
353
+ const record = result;
354
+ if (typeof record.content === "string") {
355
+ return record.content;
356
+ }
357
+ if (typeof record.text === "string") {
358
+ return record.text;
359
+ }
360
+ if (typeof record.message === "string") {
361
+ return record.message;
362
+ }
363
+ if (record.data && typeof record.data === "object") {
364
+ const data = record.data;
365
+ if (typeof data.content === "string") {
366
+ return data.content;
367
+ }
368
+ if (typeof data.text === "string") {
369
+ return data.text;
370
+ }
371
+ }
372
+ return JSON.stringify(result);
373
+ }
374
+ function extractDelta(event) {
375
+ if (typeof event === "string") {
376
+ return event;
377
+ }
378
+ if (!event || typeof event !== "object") {
379
+ return null;
380
+ }
381
+ const record = event;
382
+ for (const key of ["delta", "text", "content"]) {
383
+ if (typeof record[key] === "string") {
384
+ return record[key];
385
+ }
386
+ }
387
+ return null;
388
+ }
389
+ function isAuthReady(status) {
390
+ if (status === true) {
391
+ return true;
392
+ }
393
+ if (!status || typeof status !== "object") {
394
+ return false;
395
+ }
396
+ const record = status;
397
+ if (record.ready === true || record.isAuthenticated === true || record.authenticated === true) {
398
+ return true;
399
+ }
400
+ if (typeof record.status === "string" && /^(ok|ready|authenticated|logged_in)$/i.test(record.status)) {
401
+ return true;
402
+ }
403
+ return false;
404
+ }
171
405
  function classifyCopilotSessionError(error) {
172
406
  const message = error instanceof Error ? error.message : String(error);
173
- if (/onPermissionRequest/i.test(message) || /permission/i.test(message)) {
407
+ if (/onPermissionRequest|permission|sendAndWait|createSession|unsupported/i.test(message)) {
174
408
  return "unsupported";
175
409
  }
176
410
  return "auth";
@@ -200,17 +434,39 @@ function resolveConstructor(target, name) {
200
434
  }
201
435
  return null;
202
436
  }
203
- /**
204
- * Resolves the SDK-provided permission helper when available.
205
- */
206
437
  function resolveApproveAll(target) {
207
438
  const direct = target.approveAll;
208
439
  if (typeof direct === "function") {
209
440
  return direct;
210
441
  }
442
+ const permissionHandler = target.PermissionHandler;
443
+ if (permissionHandler && typeof permissionHandler === "object" && typeof permissionHandler.approveAll === "function") {
444
+ return permissionHandler.approveAll;
445
+ }
211
446
  const nestedDefault = target.default;
212
- if (nestedDefault && typeof nestedDefault.approveAll === "function") {
213
- return nestedDefault.approveAll;
447
+ if (nestedDefault) {
448
+ return resolveApproveAll(nestedDefault);
214
449
  }
215
450
  return null;
216
451
  }
452
+ function isCliError(error) {
453
+ return Boolean(error && typeof error === "object" && typeof error.code === "string");
454
+ }
455
+ function safeCopilotNodeRuntimeStatus() {
456
+ try {
457
+ (0, copilot_installer_1.assertCopilotNodeRuntimeSupported)();
458
+ return { ok: true };
459
+ }
460
+ catch (error) {
461
+ return {
462
+ ok: false,
463
+ availability: {
464
+ ok: false,
465
+ runtime: "copilot-sdk",
466
+ reason: "unsupported",
467
+ cause: error instanceof Error ? error.message : String(error),
468
+ details: isCliError(error) ? error.details : undefined,
469
+ },
470
+ };
471
+ }
472
+ }
@@ -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) {