@minniexcode/codex-switch 0.2.0 → 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 (40) 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 -83
  5. package/dist/app/edit-provider.js +9 -29
  6. package/dist/app/get-status.js +1 -77
  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 -99
  10. package/dist/app/setup-codex.js +0 -2
  11. package/dist/app/switch-provider.js +1 -74
  12. package/dist/cli/output.js +3 -89
  13. package/dist/commands/handlers.js +20 -172
  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.1-design.md +77 -0
  24. package/docs/PRD/codex-switch-prd-v0.2.1.md +82 -0
  25. package/docs/Tests/testing.md +32 -34
  26. package/docs/cli-usage.md +67 -235
  27. package/docs/codex-switch-command-design.md +1 -1
  28. package/docs/codex-switch-product-overview.md +49 -96
  29. package/docs/codex-switch-technical-architecture.md +37 -52
  30. package/package.json +1 -1
  31. package/dist/app/bridge.js +0 -303
  32. package/dist/runtime/copilot-adapter.js +0 -617
  33. package/dist/runtime/copilot-bridge-worker.js +0 -69
  34. package/dist/runtime/copilot-bridge.js +0 -1351
  35. package/dist/runtime/copilot-cli.js +0 -164
  36. package/dist/runtime/copilot-http-bridge-worker.js +0 -228
  37. package/dist/runtime/copilot-installer.js +0 -231
  38. package/dist/runtime/copilot-sdk-loader.js +0 -62
  39. package/dist/runtime/copilot-token.js +0 -294
  40. package/dist/storage/runtime-state-repo.js +0 -121
@@ -1,617 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EventEmitter = void 0;
4
- exports.probeCopilotSdkRuntime = probeCopilotSdkRuntime;
5
- exports.requireCopilotSdk = requireCopilotSdk;
6
- exports.readCopilotAuthState = readCopilotAuthState;
7
- exports.createCopilotRuntimeClient = createCopilotRuntimeClient;
8
- exports.startCopilotRuntimeClient = startCopilotRuntimeClient;
9
- exports.stopCopilotRuntimeClient = stopCopilotRuntimeClient;
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; } });
13
- const errors_1 = require("../domain/errors");
14
- const copilot_sdk_loader_1 = require("./copilot-sdk-loader");
15
- const copilot_installer_1 = require("./copilot-installer");
16
- const copilot_cli_1 = require("./copilot-cli");
17
- const DEFAULT_UPSTREAM_TIMEOUT_MS = 300000;
18
- /**
19
- * Probes whether the optional Copilot SDK runtime is installed, supported, and shaped correctly.
20
- */
21
- function probeCopilotSdkRuntime(runtimesDir) {
22
- const nodeStatus = safeCopilotNodeRuntimeStatus();
23
- if (!nodeStatus.ok) {
24
- return nodeStatus.availability;
25
- }
26
- const status = (0, copilot_installer_1.probeCopilotSdkInstall)(runtimesDir);
27
- if (!status.installed) {
28
- return {
29
- ok: false,
30
- runtime: "copilot-sdk",
31
- reason: "missing",
32
- cause: "The optional Copilot SDK runtime is not installed.",
33
- details: {
34
- installDir: status.installDir,
35
- packageName: status.packageName,
36
- },
37
- };
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
- }
54
- return {
55
- ok: true,
56
- runtime: "copilot-sdk",
57
- version: status.packageVersion ?? undefined,
58
- details: {
59
- installDir: status.installDir,
60
- packageName: status.packageName,
61
- },
62
- };
63
- }
64
- /**
65
- * Loads the lazily installed Copilot SDK and returns the module.
66
- */
67
- async function requireCopilotSdk(runtimesDir) {
68
- return (0, copilot_sdk_loader_1.loadCopilotSdk)(runtimesDir);
69
- }
70
- /**
71
- * Probes Copilot auth readiness through the SDK client status endpoint.
72
- */
73
- async function readCopilotAuthState(runtimesDir) {
74
- const runtime = probeCopilotSdkRuntime(runtimesDir);
75
- if (!runtime.ok) {
76
- throw (0, errors_1.cliError)(runtime.reason === "unsupported" ? "COPILOT_SDK_VERSION_UNSUPPORTED" : "COPILOT_SDK_MISSING", runtime.cause, runtime.details);
77
- }
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);
120
- }
121
- /**
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.
129
- */
130
- async function sendCopilotChatCompletion(args) {
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;
137
- try {
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);
143
- return {
144
- id: `copilot-${Date.now()}`,
145
- object: "chat.completion",
146
- created: Math.floor(Date.now() / 1000),
147
- model: typeof args.payload.model === "string" ? args.payload.model : "copilot",
148
- choices: [
149
- {
150
- index: 0,
151
- message: {
152
- role: "assistant",
153
- content,
154
- },
155
- finish_reason: "stop",
156
- },
157
- ],
158
- };
159
- }
160
- finally {
161
- if (session) {
162
- await disconnectCopilotSession(session);
163
- }
164
- if (ownsClient) {
165
- await stopCopilotRuntimeClient(runtimeClient);
166
- }
167
- }
168
- }
169
- async function createCopilotSession(runtimeClient, payload) {
170
- const createSession = resolveCallable(runtimeClient.client, "createSession");
171
- if (!createSession) {
172
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose CopilotClient.createSession().", {});
173
- }
174
- try {
175
- const session = await Promise.resolve(createSession({
176
- model: typeof payload.model === "string" ? payload.model : undefined,
177
- streaming: true,
178
- ...createSessionOptions(runtimeClient.sdk),
179
- }));
180
- if (!session || typeof session !== "object") {
181
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK returned an invalid CopilotSession.", {});
182
- }
183
- assertCopilotSessionContract(session);
184
- return session;
185
- }
186
- catch (error) {
187
- if (isCliError(error)) {
188
- throw error;
189
- }
190
- if (classifyCopilotSessionError(error) === "unsupported") {
191
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose a compatible session API.", {
192
- cause: error instanceof Error ? error.message : String(error),
193
- });
194
- }
195
- throw (0, errors_1.cliError)("COPILOT_AUTH_REQUIRED", "Copilot authentication is required before the local bridge can be used.", {
196
- cause: error instanceof Error ? error.message : String(error),
197
- });
198
- }
199
- }
200
- async function sendSessionRequest(session, prompt, timeoutMs, onStreamEvent) {
201
- const sendAndWait = resolveCallable(session, "sendAndWait");
202
- const send = resolveCallable(session, "send");
203
- if (!sendAndWait && !send) {
204
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK session does not expose sendAndWait() or send().", {});
205
- }
206
- const deltaHandler = (event) => {
207
- const delta = extractDelta(event);
208
- if (delta) {
209
- onStreamEvent?.({ type: "delta", delta });
210
- }
211
- };
212
- const runtimeHandler = (event) => {
213
- for (const runtimeEvent of mapCopilotRuntimeEvent(event)) {
214
- onStreamEvent?.({ type: "runtime", event: runtimeEvent });
215
- if (runtimeEvent.type === "assistant.message_delta" && runtimeEvent.text.length > 0) {
216
- onStreamEvent?.({ type: "delta", delta: runtimeEvent.text });
217
- }
218
- }
219
- };
220
- if (onStreamEvent && session.on) {
221
- session.on("event", runtimeHandler);
222
- session.on("data", deltaHandler);
223
- session.on("message", deltaHandler);
224
- session.on("delta", deltaHandler);
225
- }
226
- try {
227
- const sendPromise = Promise.resolve(sendAndWait ? sendAndWait({ prompt }, timeoutMs) : send({ prompt }));
228
- const result = await withTimeout(sendPromise, timeoutMs, async () => {
229
- await abortCopilotSession(session);
230
- });
231
- if (onStreamEvent) {
232
- onStreamEvent({ type: "done", text: extractCopilotContent(result) });
233
- }
234
- return result;
235
- }
236
- finally {
237
- if (onStreamEvent && session.off) {
238
- session.off("event", runtimeHandler);
239
- session.off("data", deltaHandler);
240
- session.off("message", deltaHandler);
241
- session.off("delta", deltaHandler);
242
- }
243
- }
244
- }
245
- async function withTimeout(promise, timeoutMs, onTimeout) {
246
- let timeout = null;
247
- try {
248
- return await Promise.race([
249
- promise,
250
- new Promise((_resolve, reject) => {
251
- timeout = setTimeout(() => {
252
- void onTimeout().finally(() => {
253
- reject((0, errors_1.cliError)("BRIDGE_UPSTREAM_TIMEOUT", "Copilot upstream request timed out.", { timeoutMs }));
254
- });
255
- }, timeoutMs);
256
- }),
257
- ]);
258
- }
259
- finally {
260
- if (timeout) {
261
- clearTimeout(timeout);
262
- }
263
- }
264
- }
265
- function createSessionOptions(sdk) {
266
- const approveAll = resolveApproveAll(sdk);
267
- if (approveAll) {
268
- return {
269
- onPermissionRequest: (request) => approveAll(request),
270
- };
271
- }
272
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose an approveAll permission handler.", {});
273
- }
274
- function createCopilotClient(sdk, runtimesDir) {
275
- const ClientCtor = resolveConstructor(sdk, "CopilotClient");
276
- if (!ClientCtor) {
277
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose CopilotClient.", {});
278
- }
279
- const runtimeConnection = resolveRuntimeConnectionFactory(sdk);
280
- if (!runtimeConnection?.forStdio) {
281
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose RuntimeConnection.forStdio().", {});
282
- }
283
- const runtimeInvocation = (0, copilot_cli_1.resolveCopilotSdkRuntimeInvocation)(runtimesDir);
284
- if (!runtimeInvocation) {
285
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot runtime is missing the @github/copilot npm loader required by the SDK.", {
286
- expectedRuntimeFile: "node_modules/@github/copilot/npm-loader.js",
287
- });
288
- }
289
- try {
290
- return new ClientCtor({
291
- connection: runtimeConnection.forStdio({
292
- path: runtimeInvocation.path,
293
- args: runtimeInvocation.args,
294
- }),
295
- });
296
- }
297
- catch (error) {
298
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK CopilotClient could not be constructed.", {
299
- cause: error instanceof Error ? error.message : String(error),
300
- });
301
- }
302
- }
303
- function assertCopilotSdkApiContract(sdk, client) {
304
- const createSession = resolveCallable(client, "createSession");
305
- const getAuthStatus = resolveCallable(client, "getAuthStatus");
306
- if (!createSession || !getAuthStatus) {
307
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose the required CopilotClient API.", {
308
- hasCreateSession: Boolean(createSession),
309
- hasGetAuthStatus: Boolean(getAuthStatus),
310
- });
311
- }
312
- if (!resolveApproveAll(sdk)) {
313
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK does not expose a supported permission handler.", {});
314
- }
315
- }
316
- function assertCopilotSessionContract(session) {
317
- const hasSendAndWait = typeof session.sendAndWait === "function";
318
- const hasSend = typeof session.send === "function";
319
- const hasAbort = typeof session.abort === "function";
320
- if ((!hasSendAndWait && !hasSend) || !hasAbort) {
321
- throw (0, errors_1.cliError)("COPILOT_SDK_API_UNSUPPORTED", "The installed Copilot SDK session does not expose the required request API.", {
322
- hasSendAndWait,
323
- hasSend,
324
- hasAbort,
325
- });
326
- }
327
- }
328
- async function startCopilotClient(client) {
329
- const start = resolveCallable(client, "start");
330
- if (start) {
331
- await Promise.resolve(start());
332
- }
333
- }
334
- async function stopCopilotClient(client) {
335
- const stop = resolveCallable(client, "stop");
336
- if (stop) {
337
- await Promise.resolve(stop());
338
- }
339
- }
340
- async function abortCopilotSession(session) {
341
- const abort = resolveCallable(session, "abort");
342
- if (abort) {
343
- try {
344
- await Promise.resolve(abort());
345
- }
346
- catch {
347
- // Session may already be closed or unknown — safe to ignore
348
- }
349
- }
350
- }
351
- async function disconnectCopilotSession(session) {
352
- const disconnect = resolveCallable(session, "disconnect");
353
- if (disconnect) {
354
- await Promise.resolve(disconnect());
355
- }
356
- }
357
- function buildPrompt(payload) {
358
- if (Array.isArray(payload.messages)) {
359
- return payload.messages
360
- .map((entry) => {
361
- const message = entry;
362
- return `${String(message.role ?? "user")}: ${String(message.content ?? "")}`;
363
- })
364
- .join("\n");
365
- }
366
- if (typeof payload.prompt === "string") {
367
- return payload.prompt;
368
- }
369
- return "";
370
- }
371
- function extractCopilotContent(result) {
372
- if (typeof result === "string") {
373
- return result;
374
- }
375
- if (!result || typeof result !== "object") {
376
- return JSON.stringify(result);
377
- }
378
- const record = result;
379
- if (typeof record.content === "string") {
380
- return record.content;
381
- }
382
- if (typeof record.text === "string") {
383
- return record.text;
384
- }
385
- if (typeof record.message === "string") {
386
- return record.message;
387
- }
388
- if (record.data && typeof record.data === "object") {
389
- const data = record.data;
390
- if (typeof data.content === "string") {
391
- return data.content;
392
- }
393
- if (typeof data.text === "string") {
394
- return data.text;
395
- }
396
- }
397
- return JSON.stringify(result);
398
- }
399
- function extractDelta(event) {
400
- if (typeof event === "string") {
401
- return event;
402
- }
403
- if (!event || typeof event !== "object") {
404
- return null;
405
- }
406
- const record = event;
407
- for (const key of ["delta", "text", "content"]) {
408
- if (typeof record[key] === "string") {
409
- return record[key];
410
- }
411
- }
412
- return null;
413
- }
414
- /**
415
- * Maps SDK session events into the bridge's stable process-event contract.
416
- */
417
- function mapCopilotRuntimeEvent(event) {
418
- if (!event || typeof event !== "object") {
419
- return [];
420
- }
421
- const record = event;
422
- const sdkType = readString(record, ["type", "event", "name", "eventName"]) ?? "unknown";
423
- const normalizedType = sdkType.replace(/_/g, ".").toLowerCase();
424
- const text = readString(record, ["text", "delta", "content", "message", "summary", "description"]);
425
- const name = readString(record, ["toolName", "tool", "name"]);
426
- const requestId = readString(record, ["requestId", "id", "callId"]);
427
- const kind = readString(record, ["kind", "permission", "permissionKind"]);
428
- const success = readBoolean(record, ["success", "ok"]);
429
- const approved = readBoolean(record, ["approved", "allowed", "accepted"]);
430
- const summary = truncateForBridgeLog(text ?? summarizeUnknownObject(record), 600);
431
- if (normalizedType === "assistant.intent") {
432
- return [{ type: "assistant.intent", text: summary }];
433
- }
434
- if (normalizedType === "assistant.message.delta" || normalizedType === "assistant.message_delta") {
435
- return [{ type: "assistant.message_delta", text: text ?? "" }];
436
- }
437
- if (normalizedType === "assistant.reasoning.delta" || normalizedType === "assistant.reasoning_delta" || normalizedType === "reasoning.delta") {
438
- return [{ type: "assistant.reasoning_delta", text: summary }];
439
- }
440
- if (normalizedType === "tool.execution.start" || normalizedType === "tool.execution_start") {
441
- return [{ type: "tool.execution_start", name, requestId, summary: summary || `Tool started: ${name ?? "unknown"}` }];
442
- }
443
- if (normalizedType === "tool.execution.progress" || normalizedType === "tool.execution_progress") {
444
- return [{ type: "tool.execution_progress", name, requestId, summary }];
445
- }
446
- if (normalizedType === "tool.execution.partial.result" || normalizedType === "tool.execution.partial_result") {
447
- return [{ type: "tool.execution_partial_result", name, requestId, summary }];
448
- }
449
- if (normalizedType === "tool.execution.complete" || normalizedType === "tool.execution_complete") {
450
- return [{ type: "tool.execution_complete", name, requestId, success, summary: summary || `Tool completed: ${name ?? "unknown"}` }];
451
- }
452
- if (normalizedType === "permission.requested" || normalizedType === "permission.request") {
453
- return [{ type: "permission.requested", kind, requestId, summary: summary || `Copilot requested permission: ${kind ?? "unknown"}` }];
454
- }
455
- if (normalizedType === "permission.completed" || normalizedType === "permission.complete") {
456
- return [{ type: "permission.completed", kind, requestId, approved, summary }];
457
- }
458
- if (normalizedType === "user.input.requested" || normalizedType === "user.input_request" || normalizedType === "user_input.requested") {
459
- return [{ type: "user_input.requested", requestId, summary }];
460
- }
461
- if (normalizedType === "exit.plan.mode.requested" || normalizedType === "exit_plan_mode.requested") {
462
- return [{ type: "exit_plan_mode.requested", requestId, summary }];
463
- }
464
- if (normalizedType === "session.error" || normalizedType === "error") {
465
- return [{ type: "session.error", summary }];
466
- }
467
- if (normalizedType === "session.idle" || normalizedType === "idle") {
468
- return [{ type: "session.idle", summary: summary || "Copilot session is idle." }];
469
- }
470
- return [{ type: "session.unknown", sdkType, summary }];
471
- }
472
- function readString(record, keys) {
473
- for (const key of keys) {
474
- const value = record[key];
475
- if (typeof value === "string" && value.length > 0) {
476
- return value;
477
- }
478
- if (value && typeof value === "object") {
479
- const nested = value;
480
- for (const nestedKey of ["name", "id", "text", "content", "message", "summary"]) {
481
- if (typeof nested[nestedKey] === "string" && nested[nestedKey].length > 0) {
482
- return nested[nestedKey];
483
- }
484
- }
485
- }
486
- }
487
- return undefined;
488
- }
489
- function readBoolean(record, keys) {
490
- for (const key of keys) {
491
- if (typeof record[key] === "boolean") {
492
- return record[key];
493
- }
494
- }
495
- return undefined;
496
- }
497
- function summarizeUnknownObject(record) {
498
- return JSON.stringify(record, (key, value) => {
499
- if (isSensitiveKey(key)) {
500
- return "[redacted]";
501
- }
502
- if (typeof value === "string") {
503
- return redactSensitiveText(value);
504
- }
505
- return value;
506
- });
507
- }
508
- function redactSensitiveText(value) {
509
- if (/api[_-]?key|token|authorization|bearer\s+|sk-[a-z0-9_-]+/i.test(value)) {
510
- return "[redacted]";
511
- }
512
- return value;
513
- }
514
- function isSensitiveKey(key) {
515
- return /^(api[_-]?key|token|access[_-]?token|refresh[_-]?token|authorization|secret|password)$/i.test(key);
516
- }
517
- function truncateForBridgeLog(value, maxLength) {
518
- if (value.length <= maxLength) {
519
- return value;
520
- }
521
- return `${value.slice(0, maxLength)}... [truncated]`;
522
- }
523
- function isAuthReady(status) {
524
- if (status === true) {
525
- return true;
526
- }
527
- if (!status || typeof status !== "object") {
528
- return false;
529
- }
530
- const record = status;
531
- if (record.ready === true || record.isAuthenticated === true || record.authenticated === true) {
532
- return true;
533
- }
534
- if (typeof record.status === "string" && /^(ok|ready|authenticated|logged_in)$/i.test(record.status)) {
535
- return true;
536
- }
537
- return false;
538
- }
539
- function classifyCopilotSessionError(error) {
540
- const message = error instanceof Error ? error.message : String(error);
541
- if (/onPermissionRequest|permission|sendAndWait|createSession|unsupported/i.test(message)) {
542
- return "unsupported";
543
- }
544
- return "auth";
545
- }
546
- function resolveCallable(target, name) {
547
- if (!target) {
548
- return null;
549
- }
550
- const direct = target[name];
551
- if (typeof direct === "function") {
552
- return direct.bind(target);
553
- }
554
- const nestedDefault = target.default;
555
- if (nestedDefault && typeof nestedDefault[name] === "function") {
556
- return nestedDefault[name].bind(nestedDefault);
557
- }
558
- return null;
559
- }
560
- function resolveConstructor(target, name) {
561
- const direct = target[name];
562
- if (typeof direct === "function") {
563
- return direct;
564
- }
565
- const nestedDefault = target.default;
566
- if (nestedDefault && typeof nestedDefault[name] === "function") {
567
- return nestedDefault[name];
568
- }
569
- return null;
570
- }
571
- function resolveRuntimeConnectionFactory(target) {
572
- const direct = target.RuntimeConnection;
573
- if (direct && typeof direct === "object") {
574
- return direct;
575
- }
576
- const nestedDefault = target.default;
577
- if (nestedDefault) {
578
- return resolveRuntimeConnectionFactory(nestedDefault);
579
- }
580
- return null;
581
- }
582
- function resolveApproveAll(target) {
583
- const direct = target.approveAll;
584
- if (typeof direct === "function") {
585
- return direct;
586
- }
587
- const permissionHandler = target.PermissionHandler;
588
- if (permissionHandler && typeof permissionHandler === "object" && typeof permissionHandler.approveAll === "function") {
589
- return permissionHandler.approveAll;
590
- }
591
- const nestedDefault = target.default;
592
- if (nestedDefault) {
593
- return resolveApproveAll(nestedDefault);
594
- }
595
- return null;
596
- }
597
- function isCliError(error) {
598
- return Boolean(error && typeof error === "object" && typeof error.code === "string");
599
- }
600
- function safeCopilotNodeRuntimeStatus() {
601
- try {
602
- (0, copilot_installer_1.assertCopilotNodeRuntimeSupported)();
603
- return { ok: true };
604
- }
605
- catch (error) {
606
- return {
607
- ok: false,
608
- availability: {
609
- ok: false,
610
- runtime: "copilot-sdk",
611
- reason: "unsupported",
612
- cause: error instanceof Error ? error.message : String(error),
613
- details: isCliError(error) ? error.details : undefined,
614
- },
615
- };
616
- }
617
- }
@@ -1,69 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const copilot_bridge_1 = require("./copilot-bridge");
4
- const copilot_adapter_1 = require("./copilot-adapter");
5
- let requestQueue = Promise.resolve();
6
- /**
7
- * Writes one worker lifecycle entry to stderr so the detached parent log capture persists it.
8
- */
9
- function logWorkerEvent(message) {
10
- process.stderr.write(`[${new Date().toISOString()}] ${message}\n`);
11
- }
12
- function enqueueRequest(task) {
13
- const run = requestQueue.then(task, task);
14
- requestQueue = run.catch(() => undefined);
15
- return run;
16
- }
17
- async function main() {
18
- const provider = process.env.CODEX_SWITCH_BRIDGE_PROVIDER ?? "copilot";
19
- const host = process.env.CODEX_SWITCH_BRIDGE_HOST ?? "127.0.0.1";
20
- const port = Number(process.env.CODEX_SWITCH_BRIDGE_PORT ?? "41415");
21
- const apiKey = process.env.CODEX_SWITCH_BRIDGE_API_KEY ?? "";
22
- const runtimesDir = process.env.CODEX_SWITCH_RUNTIMES_DIR || undefined;
23
- logWorkerEvent(`worker startup provider=${provider} host=${host} port=${String(port)}`);
24
- const runtimeClient = await (0, copilot_adapter_1.createCopilotRuntimeClient)(runtimesDir);
25
- await (0, copilot_adapter_1.startCopilotRuntimeClient)(runtimeClient);
26
- const stopRuntime = () => {
27
- logWorkerEvent(`worker shutdown provider=${provider}`);
28
- void (0, copilot_adapter_1.stopCopilotRuntimeClient)(runtimeClient).finally(() => process.exit(0));
29
- };
30
- process.once("SIGINT", stopRuntime);
31
- process.once("SIGTERM", stopRuntime);
32
- await (0, copilot_bridge_1.startCopilotBridgeServer)({
33
- host,
34
- port,
35
- apiKey,
36
- executeChatCompletion: async (payload, options) => enqueueRequest(() => (0, copilot_adapter_1.sendCopilotChatCompletion)({
37
- provider,
38
- payload,
39
- runtimesDir,
40
- runtimeClient,
41
- timeoutMs: options?.timeoutMs,
42
- onStreamEvent: (event) => {
43
- if (event.type === "delta") {
44
- options?.onTextDelta?.(event.delta);
45
- }
46
- else if (event.type === "runtime") {
47
- options?.onRuntimeEvent?.(event.event);
48
- }
49
- else {
50
- options?.onTextDone?.(event.text);
51
- }
52
- },
53
- })),
54
- });
55
- logWorkerEvent(`worker ready provider=${provider} host=${host} port=${String(port)}`);
56
- }
57
- if (require.main === module) {
58
- process.on("uncaughtException", (error) => {
59
- logWorkerEvent(`worker uncaught exception: ${error.message}`);
60
- });
61
- process.on("unhandledRejection", (reason) => {
62
- logWorkerEvent(`worker unhandled rejection: ${reason instanceof Error ? reason.message : String(reason)}`);
63
- });
64
- void main().catch((error) => {
65
- logWorkerEvent(`worker startup failure: ${error instanceof Error ? error.message : String(error)}`);
66
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
67
- process.exit(1);
68
- });
69
- }