copilot-api-node20 0.5.14-node20 → 0.6.0

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.
package/dist/main.js CHANGED
@@ -4,6 +4,7 @@ import consola from "consola";
4
4
  import fs from "node:fs/promises";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
+ import { EventEmitter } from "node:events";
7
8
  import { randomUUID } from "node:crypto";
8
9
  import clipboard from "clipboardy";
9
10
  import process$1 from "node:process";
@@ -16,6 +17,7 @@ import { logger } from "hono/logger";
16
17
  import { streamSSE } from "hono/streaming";
17
18
  import { countTokens } from "gpt-tokenizer/model/gpt-4o";
18
19
  import { events } from "fetch-event-stream";
20
+ import { request } from "undici";
19
21
 
20
22
  //#region src/lib/paths.ts
21
23
  const APP_DIR = path.join(os.homedir(), ".local", "share", "copilot-api");
@@ -43,8 +45,151 @@ const state = {
43
45
  accountType: "individual",
44
46
  manualApprove: false,
45
47
  rateLimitWait: false,
46
- showToken: false
48
+ showToken: false,
49
+ connectivity: {
50
+ enabled: true,
51
+ probeEndpoints: [
52
+ "https://api.github.com",
53
+ "https://www.google.com",
54
+ "https://1.1.1.1"
55
+ ],
56
+ fastProbeInterval: 5e3,
57
+ slowProbeInterval: 6e4,
58
+ timeoutMs: 5e3,
59
+ jitterMaxMs: 1e3,
60
+ connectionPooling: true,
61
+ dnsCache: true
62
+ }
63
+ };
64
+
65
+ //#endregion
66
+ //#region src/lib/connectivity.ts
67
+ var ConnectivityMonitor = class extends EventEmitter {
68
+ isOnline = true;
69
+ lastChecked = (/* @__PURE__ */ new Date()).toISOString();
70
+ consecutiveFailures = 0;
71
+ lastErrorType;
72
+ lastErrorMessage;
73
+ lastSuccessfulEndpoint;
74
+ endpointFailureStats = {};
75
+ checkInterval;
76
+ abortController;
77
+ start() {
78
+ if (!state.connectivity.enabled) {
79
+ consola.debug("Connectivity monitoring disabled");
80
+ return;
81
+ }
82
+ consola.info("Starting connectivity monitor", {
83
+ probeEndpoints: state.connectivity.probeEndpoints,
84
+ fastInterval: state.connectivity.fastProbeInterval
85
+ });
86
+ this.scheduleNextCheck();
87
+ const cleanup = () => {
88
+ this.stop();
89
+ process.exit(0);
90
+ };
91
+ process.on("SIGINT", cleanup);
92
+ process.on("SIGTERM", cleanup);
93
+ }
94
+ stop() {
95
+ consola.debug("Stopping connectivity monitor");
96
+ if (this.checkInterval) {
97
+ clearTimeout(this.checkInterval);
98
+ this.checkInterval = void 0;
99
+ }
100
+ if (this.abortController) {
101
+ this.abortController.abort();
102
+ this.abortController = void 0;
103
+ }
104
+ }
105
+ scheduleNextCheck() {
106
+ if (this.checkInterval) clearTimeout(this.checkInterval);
107
+ const baseInterval = this.isOnline ? state.connectivity.slowProbeInterval : state.connectivity.fastProbeInterval;
108
+ const jitter = Math.random() * state.connectivity.jitterMaxMs;
109
+ const interval = baseInterval + jitter;
110
+ this.checkInterval = setTimeout(() => {
111
+ this.performConnectivityCheck();
112
+ }, interval);
113
+ }
114
+ async performConnectivityCheck() {
115
+ this.abortController = new AbortController();
116
+ const timeoutId = setTimeout(() => this.abortController?.abort(), state.connectivity.timeoutMs);
117
+ try {
118
+ let success = false;
119
+ for (const endpoint of state.connectivity.probeEndpoints) try {
120
+ const response = await fetch(endpoint, {
121
+ method: "HEAD",
122
+ signal: this.abortController.signal,
123
+ headers: {
124
+ "User-Agent": "copilot-api-connectivity-monitor/1.0",
125
+ ...state.connectivity.dnsCache && { "Cache-Control": "max-age=300" }
126
+ }
127
+ });
128
+ if (response.ok) {
129
+ success = true;
130
+ this.lastSuccessfulEndpoint = endpoint;
131
+ break;
132
+ }
133
+ } catch (error) {
134
+ this.endpointFailureStats[endpoint] = (this.endpointFailureStats[endpoint] || 0) + 1;
135
+ consola.debug(`Probe failed for ${endpoint}:`, error);
136
+ }
137
+ this.updateConnectivityState(success);
138
+ } catch (error) {
139
+ this.handleConnectivityError(error);
140
+ } finally {
141
+ clearTimeout(timeoutId);
142
+ this.scheduleNextCheck();
143
+ }
144
+ }
145
+ updateConnectivityState(isOnline) {
146
+ const wasOnline = this.isOnline;
147
+ this.isOnline = isOnline;
148
+ this.lastChecked = (/* @__PURE__ */ new Date()).toISOString();
149
+ if (isOnline) {
150
+ if (this.consecutiveFailures > 0) consola.info(`Connectivity restored after ${this.consecutiveFailures} failures`);
151
+ this.consecutiveFailures = 0;
152
+ this.lastErrorType = void 0;
153
+ this.lastErrorMessage = void 0;
154
+ if (!wasOnline) this.emit("online");
155
+ } else {
156
+ this.consecutiveFailures++;
157
+ if (wasOnline) {
158
+ consola.warn("Connectivity lost");
159
+ this.emit("offline");
160
+ }
161
+ }
162
+ }
163
+ handleConnectivityError(error) {
164
+ this.lastErrorType = error.name;
165
+ this.lastErrorMessage = error.message;
166
+ consola.error("Connectivity check failed:", error);
167
+ this.updateConnectivityState(false);
168
+ }
169
+ getConnectivityStats() {
170
+ return {
171
+ isOnline: this.isOnline,
172
+ lastChecked: this.lastChecked,
173
+ consecutiveFailures: this.consecutiveFailures,
174
+ lastErrorType: this.lastErrorType,
175
+ lastErrorMessage: this.lastErrorMessage
176
+ };
177
+ }
178
+ getPerformanceStats() {
179
+ const currentInterval = this.isOnline ? state.connectivity.slowProbeInterval : state.connectivity.fastProbeInterval;
180
+ const nextCheckEstimate = new Date(Date.now() + currentInterval + Math.random() * state.connectivity.jitterMaxMs).toISOString();
181
+ return {
182
+ currentInterval,
183
+ nextCheckEstimate,
184
+ lastSuccessfulEndpoint: this.lastSuccessfulEndpoint,
185
+ endpointFailureStats: { ...this.endpointFailureStats },
186
+ jitterEnabled: state.connectivity.jitterMaxMs > 0,
187
+ connectionPooling: state.connectivity.connectionPooling,
188
+ dnsCache: state.connectivity.dnsCache
189
+ };
190
+ }
47
191
  };
192
+ const connectivityMonitor = new ConnectivityMonitor();
48
193
 
49
194
  //#endregion
50
195
  //#region src/lib/api-config.ts
@@ -52,10 +197,10 @@ const standardHeaders = () => ({
52
197
  "content-type": "application/json",
53
198
  accept: "application/json"
54
199
  });
55
- const COPILOT_VERSION = "0.26.7";
200
+ const COPILOT_VERSION = "0.32.2025093001";
56
201
  const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
57
202
  const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
58
- const API_VERSION = "2025-04-01";
203
+ const API_VERSION = "2025-08-20";
59
204
  const copilotBaseUrl = (state$1) => state$1.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${state$1.accountType}.githubcopilot.com`;
60
205
  const copilotHeaders = (state$1, vision = false) => {
61
206
  const headers = {
@@ -65,8 +210,9 @@ const copilotHeaders = (state$1, vision = false) => {
65
210
  "editor-version": `vscode/${state$1.vsCodeVersion}`,
66
211
  "editor-plugin-version": EDITOR_PLUGIN_VERSION,
67
212
  "user-agent": USER_AGENT,
68
- "openai-intent": "conversation-panel",
213
+ "openai-intent": "model-access",
69
214
  "x-github-api-version": API_VERSION,
215
+ "x-interaction-type": "model-access",
70
216
  "x-request-id": randomUUID(),
71
217
  "x-vscode-user-agent-library-version": "electron-fetch"
72
218
  };
@@ -208,26 +354,10 @@ const getModels = async () => {
208
354
 
209
355
  //#endregion
210
356
  //#region src/services/get-vscode-version.ts
211
- const FALLBACK = "1.98.1";
212
- async function getVSCodeVersion() {
213
- const controller = new AbortController();
214
- const timeout = setTimeout(() => {
215
- controller.abort();
216
- }, 5e3);
217
- try {
218
- const response = await fetch("https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin", { signal: controller.signal });
219
- const pkgbuild = await response.text();
220
- const pkgverRegex = /pkgver=([0-9.]+)/;
221
- const match = pkgbuild.match(pkgverRegex);
222
- if (match) return match[1];
223
- return FALLBACK;
224
- } catch {
225
- return FALLBACK;
226
- } finally {
227
- clearTimeout(timeout);
228
- }
357
+ function getVSCodeVersion() {
358
+ return "1.105.0-insider";
229
359
  }
230
- await getVSCodeVersion();
360
+ getVSCodeVersion();
231
361
 
232
362
  //#endregion
233
363
  //#region src/lib/utils.ts
@@ -292,6 +422,25 @@ async function pollAccessToken(deviceCode) {
292
422
 
293
423
  //#endregion
294
424
  //#region src/lib/token.ts
425
+ let tokenRefreshInterval;
426
+ let isRefreshPending = false;
427
+ let onlineHandler;
428
+ let offlineHandler;
429
+ function cleanupTokenManagement() {
430
+ consola.debug("Cleaning up token management");
431
+ if (tokenRefreshInterval) {
432
+ clearInterval(tokenRefreshInterval);
433
+ tokenRefreshInterval = void 0;
434
+ }
435
+ if (onlineHandler) {
436
+ connectivityMonitor.off("online", onlineHandler);
437
+ onlineHandler = void 0;
438
+ }
439
+ if (offlineHandler) {
440
+ connectivityMonitor.off("offline", offlineHandler);
441
+ offlineHandler = void 0;
442
+ }
443
+ }
295
444
  const readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8");
296
445
  const writeGithubToken = (token) => fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token);
297
446
  const setupCopilotToken = async () => {
@@ -300,18 +449,52 @@ const setupCopilotToken = async () => {
300
449
  consola.debug("GitHub Copilot Token fetched successfully!");
301
450
  if (state.showToken) consola.info("Copilot token:", token);
302
451
  const refreshInterval = (refresh_in - 60) * 1e3;
303
- setInterval(async () => {
304
- consola.debug("Refreshing Copilot token");
452
+ const refreshTokenWithRetry = async (maxRetries = 5, baseDelay = 1e3, reason = "scheduled") => {
453
+ if (isRefreshPending) {
454
+ consola.debug("Token refresh already in progress, skipping");
455
+ return;
456
+ }
457
+ isRefreshPending = true;
305
458
  try {
306
- const { token: token$1 } = await getCopilotToken();
307
- state.copilotToken = token$1;
308
- consola.debug("Copilot token refreshed");
309
- if (state.showToken) consola.info("Refreshed Copilot token:", token$1);
310
- } catch (error) {
311
- consola.error("Failed to refresh Copilot token:", error);
312
- throw error;
459
+ for (let attempt = 1; attempt <= maxRetries; attempt++) try {
460
+ consola.debug(`Refreshing Copilot token (${reason}, attempt ${attempt}/${maxRetries})`);
461
+ const { token: token$1 } = await getCopilotToken();
462
+ state.copilotToken = token$1;
463
+ consola.debug("Copilot token refreshed successfully");
464
+ if (state.showToken) consola.info("Refreshed Copilot token:", token$1);
465
+ return;
466
+ } catch (error) {
467
+ const isLastAttempt = attempt === maxRetries;
468
+ consola.error(`Failed to refresh Copilot token (attempt ${attempt}/${maxRetries}):`, error);
469
+ if (isLastAttempt) {
470
+ consola.error("All token refresh attempts failed. Service may be unavailable until next scheduled refresh.");
471
+ return;
472
+ }
473
+ const delay = baseDelay * Math.pow(2, attempt - 1);
474
+ consola.debug(`Retrying token refresh in ${delay}ms...`);
475
+ await new Promise((resolve) => setTimeout(resolve, delay));
476
+ }
477
+ } finally {
478
+ isRefreshPending = false;
313
479
  }
480
+ };
481
+ tokenRefreshInterval = setInterval(() => {
482
+ refreshTokenWithRetry(5, 1e3, "scheduled").catch((error) => {
483
+ consola.error("Unexpected error in scheduled token refresh:", error);
484
+ });
314
485
  }, refreshInterval);
486
+ connectivityMonitor.start();
487
+ onlineHandler = () => {
488
+ consola.debug("Network connectivity restored, attempting immediate token refresh");
489
+ refreshTokenWithRetry(3, 500, "network-restored").catch((error) => {
490
+ consola.error("Unexpected error in network-restored token refresh:", error);
491
+ });
492
+ };
493
+ offlineHandler = () => {
494
+ consola.debug("Network connectivity lost");
495
+ };
496
+ connectivityMonitor.on("online", onlineHandler);
497
+ connectivityMonitor.on("offline", offlineHandler);
315
498
  };
316
499
  async function setupGitHubToken(options) {
317
500
  try {
@@ -444,7 +627,7 @@ const checkUsage = defineCommand({
444
627
  async function getPackageVersion() {
445
628
  try {
446
629
  const packageJsonPath = new URL("../package.json", import.meta.url).pathname;
447
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
630
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath));
448
631
  return packageJson.version;
449
632
  } catch {
450
633
  return "unknown";
@@ -635,12 +818,39 @@ const getTokenCount = (messages) => {
635
818
  };
636
819
  };
637
820
 
821
+ //#endregion
822
+ //#region src/lib/sanitize.ts
823
+ /**
824
+ * Sanitizes JSON payloads by removing ANSI escape sequences and invisible Unicode characters
825
+ * that can cause GitHub Copilot API to return 400 Bad Request errors.
826
+ */
827
+ /**
828
+ * Removes ANSI escape sequences and problematic Unicode characters from a string
829
+ */
830
+ function sanitizeString(str) {
831
+ return str.replaceAll(/\x1b\[[0-9;]*[a-z]/gi, "").replaceAll(/\x1b\[[0-9;]*m/g, "").replaceAll(/\x1b\[[\d;]*[HfA-DsuJKmhlp]/g, "").replaceAll(/[\x00-\x08\v\f\x0E-\x1F\x7F]/g, "").replaceAll(/[\u200B-\u200D\uFEFF]/g, "").replaceAll(/[\u2060-\u2064]/g, "").replaceAll(/[\u206A-\u206F]/g, "").replaceAll(/[\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/g, "").replaceAll(/[\uFFF0-\uFFFF]/g, "");
832
+ }
833
+ /**
834
+ * Recursively sanitizes all string values in an object or array
835
+ */
836
+ function sanitizePayload(payload) {
837
+ if (typeof payload === "string") return sanitizeString(payload);
838
+ if (Array.isArray(payload)) return payload.map((item) => sanitizePayload(item));
839
+ if (payload && typeof payload === "object") {
840
+ const sanitized = {};
841
+ for (const [key, value] of Object.entries(payload)) sanitized[key] = sanitizePayload(value);
842
+ return sanitized;
843
+ }
844
+ return payload;
845
+ }
846
+
638
847
  //#endregion
639
848
  //#region src/services/copilot/create-chat-completions.ts
640
849
  const createChatCompletions = async (payload) => {
641
850
  if (!state.copilotToken) throw new Error("Copilot token not found");
642
- const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x$1) => x$1.type === "image_url"));
643
- const isAgentCall = payload.messages.some((msg) => ["assistant", "tool"].includes(msg.role));
851
+ const sanitizedPayload = sanitizePayload(payload);
852
+ const enableVision = sanitizedPayload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x$1) => x$1.type === "image_url"));
853
+ const isAgentCall = sanitizedPayload.messages.some((msg) => ["assistant", "tool"].includes(msg.role));
644
854
  const headers = {
645
855
  ...copilotHeaders(state, enableVision),
646
856
  "X-Initiator": isAgentCall ? "agent" : "user"
@@ -651,17 +861,24 @@ const createChatCompletions = async (payload) => {
651
861
  controller.abort();
652
862
  }, timeoutMs);
653
863
  try {
654
- const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {
864
+ const { statusCode, headers: responseHeaders, body } = await request(`${copilotBaseUrl(state)}/chat/completions`, {
655
865
  method: "POST",
656
866
  headers,
657
- body: JSON.stringify(payload),
658
- signal: controller.signal
867
+ body: JSON.stringify(sanitizedPayload),
868
+ signal: controller.signal,
869
+ headersTimeout: timeoutMs,
870
+ bodyTimeout: timeoutMs * 3,
871
+ connectTimeout: timeoutMs
872
+ });
873
+ const response = new Response(body, {
874
+ status: statusCode,
875
+ headers: responseHeaders
659
876
  });
660
877
  if (!response.ok) {
661
878
  consola.error("Failed to create chat completions", response);
662
879
  throw new HTTPError("Failed to create chat completions", response);
663
880
  }
664
- if (payload.stream) return events(response);
881
+ if (sanitizedPayload.stream) return events(response);
665
882
  return await response.json();
666
883
  } finally {
667
884
  clearTimeout(timeout);
@@ -807,7 +1024,7 @@ function handleUserMessage(message) {
807
1024
  for (const block of toolResultBlocks) newMessages.push({
808
1025
  role: "tool",
809
1026
  tool_call_id: block.tool_use_id,
810
- content: block.content
1027
+ content: mapContent(block.content)
811
1028
  });
812
1029
  if (otherBlocks.length > 0) newMessages.push({
813
1030
  role: "user",
@@ -1193,7 +1410,38 @@ server.post("/v1/messages/count_tokens", (c) => c.json({ input_tokens: 1 }));
1193
1410
 
1194
1411
  //#endregion
1195
1412
  //#region src/start.ts
1413
+ const cleanupFunctions = [];
1414
+ function setupGracefulShutdown() {
1415
+ const cleanup = async () => {
1416
+ consola.info("Gracefully shutting down...");
1417
+ for (const cleanupFn of cleanupFunctions) try {
1418
+ await cleanupFn();
1419
+ } catch (error) {
1420
+ consola.error("Error during cleanup:", error);
1421
+ }
1422
+ consola.info("Shutdown complete");
1423
+ process$1.exit(0);
1424
+ };
1425
+ process$1.on("SIGINT", cleanup);
1426
+ process$1.on("SIGTERM", cleanup);
1427
+ process$1.on("uncaughtException", (error) => {
1428
+ consola.error("Uncaught exception:", error);
1429
+ cleanup().finally(() => process$1.exit(1));
1430
+ });
1431
+ process$1.on("unhandledRejection", (reason, promise) => {
1432
+ consola.error("Unhandled promise rejection at:", promise, "reason:", reason);
1433
+ cleanup().finally(() => process$1.exit(1));
1434
+ });
1435
+ }
1196
1436
  async function runServer(options) {
1437
+ setupGracefulShutdown();
1438
+ cleanupFunctions.push(() => {
1439
+ consola.debug("Cleaning up connectivity monitor");
1440
+ connectivityMonitor.stop();
1441
+ }, () => {
1442
+ consola.debug("Cleaning up token management");
1443
+ cleanupTokenManagement();
1444
+ });
1197
1445
  if (options.verbose) {
1198
1446
  consola.level = 5;
1199
1447
  consola.info("Verbose logging enabled");
@@ -1205,6 +1453,7 @@ async function runServer(options) {
1205
1453
  state.rateLimitWait = options.rateLimitWait;
1206
1454
  state.showToken = options.showToken;
1207
1455
  state.timeoutMs = options.timeout;
1456
+ state.connectivity.enabled = !options.disableConnectivityMonitoring;
1208
1457
  await ensurePaths();
1209
1458
  await cacheVSCodeVersion();
1210
1459
  if (options.githubToken) {
@@ -1338,6 +1587,11 @@ const start = defineCommand({
1338
1587
  alias: "t",
1339
1588
  type: "string",
1340
1589
  description: "API timeout in milliseconds (default: 120000)"
1590
+ },
1591
+ "disable-connectivity-monitoring": {
1592
+ type: "boolean",
1593
+ default: false,
1594
+ description: "Disable automatic network connectivity monitoring for token refresh"
1341
1595
  }
1342
1596
  },
1343
1597
  run({ args }) {
@@ -1357,7 +1611,8 @@ const start = defineCommand({
1357
1611
  model: args.model,
1358
1612
  smallModel: args["small-model"],
1359
1613
  showToken: args["show-token"],
1360
- timeout
1614
+ timeout,
1615
+ disableConnectivityMonitoring: args["disable-connectivity-monitoring"]
1361
1616
  });
1362
1617
  }
1363
1618
  });
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","token","process","commandBlock: string","state","outputMessages: typeof simplifiedMessages","x","headers: Record<string, string>","handleCompletion","isNonStreaming","handleCompletion","newMessages: Array<Message>","contentParts: Array<ContentPart>","allTextBlocks: Array<AnthropicTextBlock>","allToolUseBlocks: Array<AnthropicToolUseBlock>","stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null","state","events: Array<AnthropicStreamEventData>","events","streamState: AnthropicStreamState","events","selectedModel: string","selectedSmallModel: string"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/shell.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/tokenizer.ts","../src/services/copilot/create-chat-completions.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/routes/messages/utils.ts","../src/routes/messages/non-stream-translation.ts","../src/routes/messages/stream-translation.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst APP_DIR = path.join(os.homedir(), \".local\", \"share\", \"copilot-api\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n models?: ModelsResponse\n vsCodeVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n\n // API timeout configuration\n timeoutMs?: number\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.26.7\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\nconst API_VERSION = \"2025-04-01\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${state.accountType}.githubcopilot.com`\nexport const copilotHeaders = (state: State, vision: boolean = false) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": \"vscode-chat\",\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text()\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = errorText\n }\n consola.error(\"HTTP error:\", errorJson)\n return c.json(\n {\n error: {\n message: errorText,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: (error as Error).message,\n type: \"error\",\n },\n },\n 500,\n )\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n signal: controller.signal,\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n return (await response.json()) as GetCopilotTokenResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\n// Trimmed for the sake of simplicity\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n signal: controller.signal,\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n signal: controller.signal,\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\ninterface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n policy?: {\n state: string\n terms: string\n }\n}\n","const FALLBACK = \"1.98.1\"\n\nexport async function getVSCodeVersion() {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n {\n signal: controller.signal,\n },\n )\n\n const pkgbuild = await response.text()\n const pkgverRegex = /pkgver=([0-9.]+)/\n const match = pkgbuild.match(pkgverRegex)\n\n if (match) {\n return match[1]\n }\n\n return FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n\n while (true) {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n signal: controller.signal,\n },\n )\n\n if (!response.ok) {\n await sleep(sleepDuration)\n consola.error(\"Failed to poll access token:\", await response.text())\n\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n } else {\n await sleep(sleepDuration)\n }\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n consola.error(\"Access token polling timed out\")\n await sleep(sleepDuration)\n continue\n }\n throw error\n } finally {\n clearTimeout(timeout)\n }\n }\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = (refresh_in - 60) * 1000\n setInterval(async () => {\n consola.debug(\"Refreshing Copilot token\")\n try {\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n throw error\n }\n }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(state),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n const packageJson = JSON.parse(\n await fs.readFile(packageJsonPath, \"utf8\"),\n ) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`copilot-api debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import { execSync } from \"node:child_process\"\nimport process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, ppid, env } = process\n\n if (platform === \"win32\") {\n try {\n const command = `wmic process get ParentProcessId,Name | findstr \"${ppid}\"`\n const parentProcess = execSync(command, { stdio: \"pipe\" }).toString()\n\n if (parentProcess.toLowerCase().includes(\"powershell.exe\")) {\n return \"powershell\"\n }\n } catch {\n return \"cmd\"\n }\n\n return \"cmd\"\n } else {\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n }\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${value}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set ${key}=${value}`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${value}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${value}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator = shell === \"cmd\" ? \" & \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected\",\n Response.json({ message: \"Request rejected\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n // eslint-disable-next-line require-atomic-updates\n state.lastRequestTimestamp = now\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import { countTokens } from \"gpt-tokenizer/model/gpt-4o\"\n\nimport type { Message } from \"~/services/copilot/create-chat-completions\"\n\nexport const getTokenCount = (messages: Array<Message>) => {\n const simplifiedMessages = messages.map((message) => {\n let content = \"\"\n if (typeof message.content === \"string\") {\n content = message.content\n } else if (Array.isArray(message.content)) {\n content = message.content\n .filter((part) => part.type === \"text\")\n .map((part) => (part as { text: string }).text)\n .join(\"\")\n }\n return { ...message, content }\n })\n\n let inputMessages = simplifiedMessages.filter((message) => {\n return message.role !== \"tool\"\n })\n let outputMessages: typeof simplifiedMessages = []\n\n const lastMessage = simplifiedMessages.at(-1)\n\n if (lastMessage?.role === \"assistant\") {\n inputMessages = simplifiedMessages.slice(0, -1)\n outputMessages = [lastMessage]\n }\n\n // @ts-expect-error TS can't infer from arr.filter()\n const inputTokens = countTokens(inputMessages)\n // @ts-expect-error TS can't infer from arr.filter()\n const outputTokens = countTokens(outputMessages)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = payload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = payload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create chat completions\", response)\n throw new HTTPError(\"Failed to create chat completions\", response)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n} from \"~/services/copilot/create-chat-completions\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n\n consola.info(\"Current token count:\", getTokenCount(payload.messages))\n\n if (state.manualApprove) await awaitApproval()\n\n if (isNullish(payload.max_tokens)) {\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities.limits.max_output_tokens,\n }\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n\n const response = await createChatCompletions(payload)\n\n if (isNonStreaming(response)) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const paylod = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(paylod)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { type AnthropicResponse } from \"./anthropic-types\"\n\nexport function mapOpenAIStopReasonToAnthropic(\n finishReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null,\n): AnthropicResponse[\"stop_reason\"] {\n if (finishReason === null) {\n return null\n }\n const stopReasonMap = {\n stop: \"end_turn\",\n length: \"max_tokens\",\n tool_calls: \"tool_use\",\n content_filter: \"end_turn\",\n } as const\n return stopReasonMap[finishReason]\n}\n","import {\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type ContentPart,\n type Message,\n type TextPart,\n type Tool,\n type ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\n\nimport {\n type AnthropicAssistantContentBlock,\n type AnthropicAssistantMessage,\n type AnthropicMessage,\n type AnthropicMessagesPayload,\n type AnthropicResponse,\n type AnthropicTextBlock,\n type AnthropicThinkingBlock,\n type AnthropicTool,\n type AnthropicToolResultBlock,\n type AnthropicToolUseBlock,\n type AnthropicUserContentBlock,\n type AnthropicUserMessage,\n} from \"./anthropic-types\"\nimport { mapOpenAIStopReasonToAnthropic } from \"./utils\"\n\n// Payload translation\n\nexport function translateToOpenAI(\n payload: AnthropicMessagesPayload,\n): ChatCompletionsPayload {\n return {\n model: translateModelName(payload.model),\n messages: translateAnthropicMessagesToOpenAI(\n payload.messages,\n payload.system,\n ),\n max_tokens: payload.max_tokens,\n stop: payload.stop_sequences,\n stream: payload.stream,\n temperature: payload.temperature,\n top_p: payload.top_p,\n user: payload.metadata?.user_id,\n tools: translateAnthropicToolsToOpenAI(payload.tools),\n tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice),\n }\n}\n\nfunction translateModelName(model: string): string {\n // Subagent requests use a specific model number which Copilot doesn't support\n if (model.startsWith(\"claude-sonnet-4-\")) {\n return model.replace(/^claude-sonnet-4-.*/, \"claude-sonnet-4\")\n } else if (model.startsWith(\"claude-opus-\")) {\n return model.replace(/^claude-opus-4-.*/, \"claude-opus-4\")\n }\n return model\n}\n\nfunction translateAnthropicMessagesToOpenAI(\n anthropicMessages: Array<AnthropicMessage>,\n system: string | Array<AnthropicTextBlock> | undefined,\n): Array<Message> {\n const systemMessages = handleSystemPrompt(system)\n\n const otherMessages = anthropicMessages.flatMap((message) =>\n message.role === \"user\" ?\n handleUserMessage(message)\n : handleAssistantMessage(message),\n )\n\n return [...systemMessages, ...otherMessages]\n}\n\nfunction handleSystemPrompt(\n system: string | Array<AnthropicTextBlock> | undefined,\n): Array<Message> {\n if (!system) {\n return []\n }\n\n if (typeof system === \"string\") {\n return [{ role: \"system\", content: system }]\n } else {\n const systemText = system.map((block) => block.text).join(\"\\n\\n\")\n return [{ role: \"system\", content: systemText }]\n }\n}\n\nfunction handleUserMessage(message: AnthropicUserMessage): Array<Message> {\n const newMessages: Array<Message> = []\n\n if (Array.isArray(message.content)) {\n const toolResultBlocks = message.content.filter(\n (block): block is AnthropicToolResultBlock =>\n block.type === \"tool_result\",\n )\n const otherBlocks = message.content.filter(\n (block) => block.type !== \"tool_result\",\n )\n\n // Tool results must come first to maintain protocol: tool_use -> tool_result -> user\n for (const block of toolResultBlocks) {\n newMessages.push({\n role: \"tool\",\n tool_call_id: block.tool_use_id,\n content: block.content,\n })\n }\n\n if (otherBlocks.length > 0) {\n newMessages.push({\n role: \"user\",\n content: mapContent(otherBlocks),\n })\n }\n } else {\n newMessages.push({\n role: \"user\",\n content: mapContent(message.content),\n })\n }\n\n return newMessages\n}\n\nfunction handleAssistantMessage(\n message: AnthropicAssistantMessage,\n): Array<Message> {\n if (!Array.isArray(message.content)) {\n return [\n {\n role: \"assistant\",\n content: mapContent(message.content),\n },\n ]\n }\n\n const toolUseBlocks = message.content.filter(\n (block): block is AnthropicToolUseBlock => block.type === \"tool_use\",\n )\n\n const textBlocks = message.content.filter(\n (block): block is AnthropicTextBlock => block.type === \"text\",\n )\n\n const thinkingBlocks = message.content.filter(\n (block): block is AnthropicThinkingBlock => block.type === \"thinking\",\n )\n\n // Combine text and thinking blocks, as OpenAI doesn't have separate thinking blocks\n const allTextContent = [\n ...textBlocks.map((b) => b.text),\n ...thinkingBlocks.map((b) => b.thinking),\n ].join(\"\\n\\n\")\n\n return toolUseBlocks.length > 0 ?\n [\n {\n role: \"assistant\",\n content: allTextContent || null,\n tool_calls: toolUseBlocks.map((toolUse) => ({\n id: toolUse.id,\n type: \"function\",\n function: {\n name: toolUse.name,\n arguments: JSON.stringify(toolUse.input),\n },\n })),\n },\n ]\n : [\n {\n role: \"assistant\",\n content: mapContent(message.content),\n },\n ]\n}\n\nfunction mapContent(\n content:\n | string\n | Array<AnthropicUserContentBlock | AnthropicAssistantContentBlock>,\n): string | Array<ContentPart> | null {\n if (typeof content === \"string\") {\n return content\n }\n if (!Array.isArray(content)) {\n return null\n }\n\n const hasImage = content.some((block) => block.type === \"image\")\n if (!hasImage) {\n return content\n .filter(\n (block): block is AnthropicTextBlock | AnthropicThinkingBlock =>\n block.type === \"text\" || block.type === \"thinking\",\n )\n .map((block) => (block.type === \"text\" ? block.text : block.thinking))\n .join(\"\\n\\n\")\n }\n\n const contentParts: Array<ContentPart> = []\n for (const block of content) {\n switch (block.type) {\n case \"text\": {\n contentParts.push({ type: \"text\", text: block.text })\n\n break\n }\n case \"thinking\": {\n contentParts.push({ type: \"text\", text: block.thinking })\n\n break\n }\n case \"image\": {\n contentParts.push({\n type: \"image_url\",\n image_url: {\n url: `data:${block.source.media_type};base64,${block.source.data}`,\n },\n })\n\n break\n }\n // No default\n }\n }\n return contentParts\n}\n\nfunction translateAnthropicToolsToOpenAI(\n anthropicTools: Array<AnthropicTool> | undefined,\n): Array<Tool> | undefined {\n if (!anthropicTools) {\n return undefined\n }\n return anthropicTools.map((tool) => ({\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.input_schema,\n },\n }))\n}\n\nfunction translateAnthropicToolChoiceToOpenAI(\n anthropicToolChoice: AnthropicMessagesPayload[\"tool_choice\"],\n): ChatCompletionsPayload[\"tool_choice\"] {\n if (!anthropicToolChoice) {\n return undefined\n }\n\n switch (anthropicToolChoice.type) {\n case \"auto\": {\n return \"auto\"\n }\n case \"any\": {\n return \"required\"\n }\n case \"tool\": {\n if (anthropicToolChoice.name) {\n return {\n type: \"function\",\n function: { name: anthropicToolChoice.name },\n }\n }\n return undefined\n }\n case \"none\": {\n return \"none\"\n }\n default: {\n return undefined\n }\n }\n}\n\n// Response translation\n\nexport function translateToAnthropic(\n response: ChatCompletionResponse,\n): AnthropicResponse {\n // Merge content from all choices\n const allTextBlocks: Array<AnthropicTextBlock> = []\n const allToolUseBlocks: Array<AnthropicToolUseBlock> = []\n let stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null =\n null // default\n stopReason = response.choices[0]?.finish_reason ?? stopReason\n\n // Process all choices to extract text and tool use blocks\n for (const choice of response.choices) {\n const textBlocks = getAnthropicTextBlocks(choice.message.content)\n const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls)\n\n allTextBlocks.push(...textBlocks)\n allToolUseBlocks.push(...toolUseBlocks)\n\n // Use the finish_reason from the first choice, or prioritize tool_calls\n if (choice.finish_reason === \"tool_calls\" || stopReason === \"stop\") {\n stopReason = choice.finish_reason\n }\n }\n\n // Note: GitHub Copilot doesn't generate thinking blocks, so we don't include them in responses\n\n return {\n id: response.id,\n type: \"message\",\n role: \"assistant\",\n model: response.model,\n content: [...allTextBlocks, ...allToolUseBlocks],\n stop_reason: mapOpenAIStopReasonToAnthropic(stopReason),\n stop_sequence: null,\n usage: {\n input_tokens: response.usage?.prompt_tokens ?? 0,\n output_tokens: response.usage?.completion_tokens ?? 0,\n },\n }\n}\n\nfunction getAnthropicTextBlocks(\n messageContent: Message[\"content\"],\n): Array<AnthropicTextBlock> {\n if (typeof messageContent === \"string\") {\n return [{ type: \"text\", text: messageContent }]\n }\n\n if (Array.isArray(messageContent)) {\n return messageContent\n .filter((part): part is TextPart => part.type === \"text\")\n .map((part) => ({ type: \"text\", text: part.text }))\n }\n\n return []\n}\n\nfunction getAnthropicToolUseBlocks(\n toolCalls: Array<ToolCall> | undefined,\n): Array<AnthropicToolUseBlock> {\n if (!toolCalls) {\n return []\n }\n return toolCalls.map((toolCall) => ({\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.function.name,\n input: JSON.parse(toolCall.function.arguments) as Record<string, unknown>,\n }))\n}\n","import { type ChatCompletionChunk } from \"~/services/copilot/create-chat-completions\"\n\nimport {\n type AnthropicStreamEventData,\n type AnthropicStreamState,\n} from \"./anthropic-types\"\nimport { mapOpenAIStopReasonToAnthropic } from \"./utils\"\n\nfunction isToolBlockOpen(state: AnthropicStreamState): boolean {\n if (!state.contentBlockOpen) {\n return false\n }\n // Check if the current block index corresponds to any known tool call\n return Object.values(state.toolCalls).some(\n (tc) => tc.anthropicBlockIndex === state.contentBlockIndex,\n )\n}\n\n// eslint-disable-next-line max-lines-per-function, complexity\nexport function translateChunkToAnthropicEvents(\n chunk: ChatCompletionChunk,\n state: AnthropicStreamState,\n): Array<AnthropicStreamEventData> {\n const events: Array<AnthropicStreamEventData> = []\n\n if (chunk.choices.length === 0) {\n return events\n }\n\n const choice = chunk.choices[0]\n const { delta } = choice\n\n if (!state.messageStartSent) {\n events.push({\n type: \"message_start\",\n message: {\n id: chunk.id,\n type: \"message\",\n role: \"assistant\",\n content: [],\n model: chunk.model,\n stop_reason: null,\n stop_sequence: null,\n usage: {\n input_tokens: chunk.usage?.prompt_tokens ?? 0,\n output_tokens: 0, // Will be updated in message_delta when finished\n },\n },\n })\n state.messageStartSent = true\n }\n\n if (delta.content) {\n if (isToolBlockOpen(state)) {\n // A tool block was open, so close it before starting a text block.\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockIndex++\n state.contentBlockOpen = false\n }\n\n if (!state.contentBlockOpen) {\n events.push({\n type: \"content_block_start\",\n index: state.contentBlockIndex,\n content_block: {\n type: \"text\",\n text: \"\",\n },\n })\n state.contentBlockOpen = true\n }\n\n events.push({\n type: \"content_block_delta\",\n index: state.contentBlockIndex,\n delta: {\n type: \"text_delta\",\n text: delta.content,\n },\n })\n }\n\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n if (toolCall.id && toolCall.function?.name) {\n // New tool call starting.\n if (state.contentBlockOpen) {\n // Close any previously open block.\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockIndex++\n state.contentBlockOpen = false\n }\n\n const anthropicBlockIndex = state.contentBlockIndex\n state.toolCalls[toolCall.index] = {\n id: toolCall.id,\n name: toolCall.function.name,\n anthropicBlockIndex,\n }\n\n events.push({\n type: \"content_block_start\",\n index: anthropicBlockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.function.name,\n input: {},\n },\n })\n state.contentBlockOpen = true\n }\n\n if (toolCall.function?.arguments) {\n const toolCallInfo = state.toolCalls[toolCall.index]\n // Tool call can still be empty\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (toolCallInfo) {\n events.push({\n type: \"content_block_delta\",\n index: toolCallInfo.anthropicBlockIndex,\n delta: {\n type: \"input_json_delta\",\n partial_json: toolCall.function.arguments,\n },\n })\n }\n }\n }\n }\n\n if (choice.finish_reason) {\n if (state.contentBlockOpen) {\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockOpen = false\n }\n\n events.push(\n {\n type: \"message_delta\",\n delta: {\n stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),\n stop_sequence: null,\n },\n usage: {\n input_tokens: chunk.usage?.prompt_tokens ?? 0,\n output_tokens: chunk.usage?.completion_tokens ?? 0,\n ...(chunk.usage?.prompt_tokens_details?.cached_tokens\n !== undefined && {\n cache_read_input_tokens:\n chunk.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n },\n {\n type: \"message_stop\",\n },\n )\n }\n\n return events\n}\n\nexport function translateErrorToAnthropicErrorEvent(): AnthropicStreamEventData {\n return {\n type: \"error\",\n error: {\n type: \"api_error\",\n message: \"An unexpected error occurred during streaming.\",\n },\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport {\n createChatCompletions,\n type ChatCompletionChunk,\n type ChatCompletionResponse,\n} from \"~/services/copilot/create-chat-completions\"\n\nimport {\n type AnthropicMessagesPayload,\n type AnthropicStreamState,\n} from \"./anthropic-types\"\nimport {\n translateToAnthropic,\n translateToOpenAI,\n} from \"./non-stream-translation\"\nimport { translateChunkToAnthropicEvents } from \"./stream-translation\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n const anthropicPayload = await c.req.json<AnthropicMessagesPayload>()\n consola.debug(\"Anthropic request payload:\", JSON.stringify(anthropicPayload))\n\n const openAIPayload = translateToOpenAI(anthropicPayload)\n consola.debug(\n \"Translated OpenAI request payload:\",\n JSON.stringify(openAIPayload),\n )\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const response = await createChatCompletions(openAIPayload)\n\n if (isNonStreaming(response)) {\n consola.debug(\n \"Non-streaming response from Copilot:\",\n JSON.stringify(response).slice(-400),\n )\n const anthropicResponse = translateToAnthropic(response)\n consola.debug(\n \"Translated Anthropic response:\",\n JSON.stringify(anthropicResponse),\n )\n return c.json(anthropicResponse)\n }\n\n consola.debug(\"Streaming response from Copilot\")\n return streamSSE(c, async (stream) => {\n const streamState: AnthropicStreamState = {\n messageStartSent: false,\n contentBlockIndex: 0,\n contentBlockOpen: false,\n toolCalls: {},\n }\n\n for await (const rawEvent of response) {\n consola.debug(\"Copilot raw stream event:\", JSON.stringify(rawEvent))\n if (rawEvent.data === \"[DONE]\") {\n break\n }\n\n if (!rawEvent.data) {\n continue\n }\n\n const chunk = JSON.parse(rawEvent.data) as ChatCompletionChunk\n const events = translateChunkToAnthropicEvents(chunk, streamState)\n\n for (const event of events) {\n consola.debug(\"Translated Anthropic event:\", JSON.stringify(event))\n await stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n })\n }\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => ({\n id: model.id,\n object: \"model\",\n type: \"model\",\n created: 0, // No date available from source\n created_at: new Date(0).toISOString(), // No date available from source\n owned_by: model.vendor,\n display_name: model.name,\n }))\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n try {\n return c.json({\n token: state.copilotToken,\n })\n } catch (error) {\n console.error(\"Error fetching token:\", error)\n return c.json({ error: \"Failed to fetch token\", token: null }, 500)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n console.error(\"Error fetching Copilot usage:\", error)\n return c.json({ error: \"Failed to fetch Copilot usage\" }, 500)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\nimport { logger } from \"hono/logger\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(logger())\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\nserver.post(\"/v1/messages/count_tokens\", (c) => c.json({ input_tokens: 1 }))\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport process from \"node:process\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport { cacheModels, cacheVSCodeVersion } from \"./lib/utils\"\nimport { server } from \"./server\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n showToken: boolean\n model?: string\n smallModel?: string\n timeout?: number\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n state.timeoutMs = options.timeout\n\n await ensurePaths()\n await cacheVSCodeVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.info(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) {\n invariant(state.models, \"Models should be loaded by now\")\n\n let selectedModel: string\n let selectedSmallModel: string\n\n // Check if models are provided via command line\n if (options.model && options.smallModel) {\n // Validate provided models\n const availableModelIds = state.models.data.map((model) => model.id)\n\n if (!availableModelIds.includes(options.model)) {\n consola.error(`Invalid model: ${options.model}`)\n consola.info(`Available models: \\n${availableModelIds.join(\"\\n\")}`)\n process.exit(1)\n }\n\n if (!availableModelIds.includes(options.smallModel)) {\n consola.error(`Invalid small model: ${options.smallModel}`)\n consola.info(`Available models: \\n${availableModelIds.join(\"\\n\")}`)\n process.exit(1)\n }\n\n selectedModel = options.model\n selectedSmallModel = options.smallModel\n consola.info(`Using model: ${selectedModel}`)\n consola.info(`Using small model: ${selectedSmallModel}`)\n } else if (options.model || options.smallModel) {\n // If only one model is provided, show error\n consola.error(\n \"Both --model and --small-model must be specified when using command-line model selection\",\n )\n process.exit(1)\n } else {\n // Fall back to interactive selection\n selectedModel = await consola.prompt(\n \"Select a model to use with Claude Code\",\n {\n type: \"select\",\n options: state.models.data.map((model) => model.id),\n },\n )\n\n selectedSmallModel = await consola.prompt(\n \"Select a small model to use with Claude Code\",\n {\n type: \"select\",\n options: state.models.data.map((model) => model.id),\n },\n )\n }\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n },\n \"claude\",\n )\n\n try {\n clipboard.writeSync(command)\n consola.success(\"Copied Claude Code command to clipboard!\")\n } catch {\n consola.warn(\n \"Failed to copy to clipboard. Here is the Claude Code command:\",\n )\n consola.log(command)\n }\n }\n\n consola.box(\n `🌐 Usage Viewer: https://ericc-ch.github.io/copilot-api?endpoint=${serverUrl}/usage`,\n )\n\n serve({\n fetch: server.fetch as ServerHandler,\n port: options.port,\n })\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the Copilot API server\",\n },\n args: {\n port: {\n alias: \"p\",\n type: \"string\",\n default: \"4141\",\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\",\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\",\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\",\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\",\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"claude-code\": {\n alias: \"c\",\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Model to use with Claude Code (requires --claude-code)\",\n },\n \"small-model\": {\n alias: \"s\",\n type: \"string\",\n description:\n \"Small/fast model to use with Claude Code (requires --claude-code)\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n timeout: {\n alias: \"t\",\n type: \"string\",\n description: \"API timeout in milliseconds (default: 120000)\",\n },\n },\n run({ args }) {\n const rateLimitRaw = args[\"rate-limit\"]\n const rateLimit =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n rateLimitRaw === undefined ? undefined : Number.parseInt(rateLimitRaw, 10)\n\n const timeoutRaw = args.timeout\n const timeout =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n timeoutRaw === undefined ? 120000 : Number.parseInt(timeoutRaw, 10)\n\n return runServer({\n port: Number.parseInt(args.port, 10),\n verbose: args.verbose,\n accountType: args[\"account-type\"],\n manual: args.manual,\n rateLimit,\n rateLimitWait: args.wait,\n githubToken: args[\"github-token\"],\n claudeCode: args[\"claude-code\"],\n model: args.model,\n smallModel: args[\"small-model\"],\n showToken: args[\"show-token\"],\n timeout,\n })\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nconst main = defineCommand({\n meta: {\n name: \"copilot-api\",\n description:\n \"A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.\",\n },\n subCommands: { auth, start, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":"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"}
1
+ {"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","tokenRefreshInterval: NodeJS.Timeout | undefined","onlineHandler: (() => void) | undefined","offlineHandler: (() => void) | undefined","token","process","commandBlock: string","state","outputMessages: typeof simplifiedMessages","x","headers: Record<string, string>","handleCompletion","isNonStreaming","handleCompletion","newMessages: Array<Message>","contentParts: Array<ContentPart>","allTextBlocks: Array<AnthropicTextBlock>","allToolUseBlocks: Array<AnthropicToolUseBlock>","stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null","state","events: Array<AnthropicStreamEventData>","events","streamState: AnthropicStreamState","events","cleanupFunctions: Array<() => void | Promise<void>>","process","selectedModel: string","selectedSmallModel: string"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/connectivity.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/shell.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/tokenizer.ts","../src/lib/sanitize.ts","../src/services/copilot/create-chat-completions.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/routes/messages/utils.ts","../src/routes/messages/non-stream-translation.ts","../src/routes/messages/stream-translation.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst APP_DIR = path.join(os.homedir(), \".local\", \"share\", \"copilot-api\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface ConnectivityConfig {\n enabled: boolean\n probeEndpoints: Array<string>\n fastProbeInterval: number\n slowProbeInterval: number\n timeoutMs: number\n jitterMaxMs: number\n connectionPooling: boolean\n dnsCache: boolean\n}\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n models?: ModelsResponse\n vsCodeVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n\n // API timeout configuration\n timeoutMs?: number\n\n // Connectivity monitoring configuration\n connectivity: ConnectivityConfig\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n connectivity: {\n enabled: true,\n probeEndpoints: [\n \"https://api.github.com\",\n \"https://www.google.com\",\n \"https://1.1.1.1\",\n ],\n fastProbeInterval: 5000, // 5 seconds when offline\n slowProbeInterval: 60000, // 1 minute when online\n timeoutMs: 5000,\n jitterMaxMs: 1000, // 0-1 second random jitter\n connectionPooling: true, // Enable HTTP/2 connection pooling\n dnsCache: true, // Enable DNS caching headers\n },\n}\n","import { EventEmitter } from \"node:events\"\n\nimport consola from \"consola\"\n\nimport { state } from \"./state\"\n\ninterface ConnectivityStats {\n isOnline: boolean\n lastChecked: string\n consecutiveFailures: number\n lastErrorType?: string\n lastErrorMessage?: string\n}\n\ninterface PerformanceStats {\n currentInterval: number\n nextCheckEstimate: string\n lastSuccessfulEndpoint?: string\n endpointFailureStats: Record<string, number>\n jitterEnabled: boolean\n connectionPooling: boolean\n dnsCache: boolean\n}\n\nclass ConnectivityMonitor extends EventEmitter {\n private isOnline = true\n private lastChecked = new Date().toISOString()\n private consecutiveFailures = 0\n private lastErrorType?: string\n private lastErrorMessage?: string\n private lastSuccessfulEndpoint?: string\n private endpointFailureStats: Record<string, number> = {}\n private checkInterval?: NodeJS.Timeout\n private abortController?: AbortController\n\n start(): void {\n if (!state.connectivity.enabled) {\n consola.debug(\"Connectivity monitoring disabled\")\n return\n }\n\n consola.info(\"Starting connectivity monitor\", {\n probeEndpoints: state.connectivity.probeEndpoints,\n fastInterval: state.connectivity.fastProbeInterval,\n })\n\n this.scheduleNextCheck()\n\n // Cleanup on process termination\n const cleanup = () => {\n this.stop()\n process.exit(0)\n }\n\n process.on(\"SIGINT\", cleanup)\n process.on(\"SIGTERM\", cleanup)\n }\n\n stop(): void {\n consola.debug(\"Stopping connectivity monitor\")\n\n if (this.checkInterval) {\n clearTimeout(this.checkInterval)\n this.checkInterval = undefined\n }\n\n if (this.abortController) {\n this.abortController.abort()\n this.abortController = undefined\n }\n }\n\n private scheduleNextCheck(): void {\n if (this.checkInterval) {\n clearTimeout(this.checkInterval)\n }\n\n const baseInterval = this.isOnline\n ? state.connectivity.slowProbeInterval\n : state.connectivity.fastProbeInterval\n\n // Add jitter to prevent thundering herd\n const jitter = Math.random() * state.connectivity.jitterMaxMs\n const interval = baseInterval + jitter\n\n this.checkInterval = setTimeout(() => {\n this.performConnectivityCheck()\n }, interval)\n }\n\n private async performConnectivityCheck(): Promise<void> {\n this.abortController = new AbortController()\n const timeoutId = setTimeout(\n () => this.abortController?.abort(),\n state.connectivity.timeoutMs,\n )\n\n try {\n let success = false\n\n for (const endpoint of state.connectivity.probeEndpoints) {\n try {\n const response = await fetch(endpoint, {\n method: \"HEAD\",\n signal: this.abortController.signal,\n headers: {\n \"User-Agent\": \"copilot-api-connectivity-monitor/1.0\",\n ...(state.connectivity.dnsCache && {\n \"Cache-Control\": \"max-age=300\",\n }),\n },\n })\n\n if (response.ok) {\n success = true\n this.lastSuccessfulEndpoint = endpoint\n break\n }\n } catch (error) {\n this.endpointFailureStats[endpoint] =\n (this.endpointFailureStats[endpoint] || 0) + 1\n\n consola.debug(`Probe failed for ${endpoint}:`, error)\n }\n }\n\n this.updateConnectivityState(success)\n } catch (error) {\n this.handleConnectivityError(error as Error)\n } finally {\n clearTimeout(timeoutId)\n this.scheduleNextCheck()\n }\n }\n\n private updateConnectivityState(isOnline: boolean): void {\n const wasOnline = this.isOnline\n this.isOnline = isOnline\n this.lastChecked = new Date().toISOString()\n\n if (isOnline) {\n if (this.consecutiveFailures > 0) {\n consola.info(`Connectivity restored after ${this.consecutiveFailures} failures`)\n }\n this.consecutiveFailures = 0\n this.lastErrorType = undefined\n this.lastErrorMessage = undefined\n\n if (!wasOnline) {\n this.emit(\"online\")\n }\n } else {\n this.consecutiveFailures++\n\n if (wasOnline) {\n consola.warn(\"Connectivity lost\")\n this.emit(\"offline\")\n }\n }\n }\n\n private handleConnectivityError(error: Error): void {\n this.lastErrorType = error.name\n this.lastErrorMessage = error.message\n\n consola.error(\"Connectivity check failed:\", error)\n this.updateConnectivityState(false)\n }\n\n getConnectivityStats(): ConnectivityStats {\n return {\n isOnline: this.isOnline,\n lastChecked: this.lastChecked,\n consecutiveFailures: this.consecutiveFailures,\n lastErrorType: this.lastErrorType,\n lastErrorMessage: this.lastErrorMessage,\n }\n }\n\n getPerformanceStats(): PerformanceStats {\n const currentInterval = this.isOnline\n ? state.connectivity.slowProbeInterval\n : state.connectivity.fastProbeInterval\n\n const nextCheckEstimate = new Date(\n Date.now() + currentInterval + Math.random() * state.connectivity.jitterMaxMs,\n ).toISOString()\n\n return {\n currentInterval,\n nextCheckEstimate,\n lastSuccessfulEndpoint: this.lastSuccessfulEndpoint,\n endpointFailureStats: { ...this.endpointFailureStats },\n jitterEnabled: state.connectivity.jitterMaxMs > 0,\n connectionPooling: state.connectivity.connectionPooling,\n dnsCache: state.connectivity.dnsCache,\n }\n }\n}\n\nexport const connectivityMonitor = new ConnectivityMonitor()\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.32.2025093001\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\nconst API_VERSION = \"2025-08-20\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${state.accountType}.githubcopilot.com`\nexport const copilotHeaders = (state: State, vision: boolean = false) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": \"vscode-chat\",\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"model-access\",\n \"x-github-api-version\": API_VERSION,\n \"x-interaction-type\": \"model-access\",\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text()\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = errorText\n }\n consola.error(\"HTTP error:\", errorJson)\n return c.json(\n {\n error: {\n message: errorText,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: (error as Error).message,\n type: \"error\",\n },\n },\n 500,\n )\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n signal: controller.signal,\n },\n )\n\n if (!response.ok)\n throw new HTTPError(\"Failed to get Copilot token\", response)\n\n return (await response.json()) as GetCopilotTokenResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\n// Trimmed for the sake of simplicity\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n signal: controller.signal,\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n signal: controller.signal,\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\ninterface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n policy?: {\n state: string\n terms: string\n }\n}\n","export function getVSCodeVersion() {\n return \"1.105.0-insider\"\n}\n\ngetVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n\n while (true) {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n signal: controller.signal,\n },\n )\n\n if (!response.ok) {\n await sleep(sleepDuration)\n consola.error(\"Failed to poll access token:\", await response.text())\n\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n } else {\n await sleep(sleepDuration)\n }\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n consola.error(\"Access token polling timed out\")\n await sleep(sleepDuration)\n continue\n }\n throw error\n } finally {\n clearTimeout(timeout)\n }\n }\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { connectivityMonitor } from \"~/lib/connectivity\"\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\n// Track cleanup resources for token management\nlet tokenRefreshInterval: NodeJS.Timeout | undefined\nlet isRefreshPending = false\n\n// Event listener functions that can be removed\nlet onlineHandler: (() => void) | undefined\nlet offlineHandler: (() => void) | undefined\n\n// Cleanup function to be called on shutdown\nexport function cleanupTokenManagement() {\n consola.debug(\"Cleaning up token management\")\n\n // Clear the refresh interval\n if (tokenRefreshInterval) {\n clearInterval(tokenRefreshInterval)\n tokenRefreshInterval = undefined\n }\n\n // Remove event listeners\n if (onlineHandler) {\n connectivityMonitor.off(\"online\", onlineHandler)\n onlineHandler = undefined\n }\n\n if (offlineHandler) {\n connectivityMonitor.off(\"offline\", offlineHandler)\n offlineHandler = undefined\n }\n}\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = (refresh_in - 60) * 1000\n\n const refreshTokenWithRetry = async (\n maxRetries = 5,\n baseDelay = 1000,\n reason = \"scheduled\",\n ) => {\n if (isRefreshPending) {\n consola.debug(\"Token refresh already in progress, skipping\")\n return\n }\n\n isRefreshPending = true\n try {\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n consola.debug(\n `Refreshing Copilot token (${reason}, attempt ${attempt}/${maxRetries})`,\n )\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed successfully\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n return // Success - exit retry loop\n } catch (error) {\n const isLastAttempt = attempt === maxRetries\n consola.error(\n `Failed to refresh Copilot token (attempt ${attempt}/${maxRetries}):`,\n error,\n )\n\n if (isLastAttempt) {\n consola.error(\n \"All token refresh attempts failed. Service may be unavailable until next scheduled refresh.\",\n )\n return // Give up after max retries\n }\n\n // Exponential backoff: wait 1s, 2s, 4s, 8s, 16s\n const delay = baseDelay * Math.pow(2, attempt - 1)\n consola.debug(`Retrying token refresh in ${delay}ms...`)\n await new Promise((resolve) => setTimeout(resolve, delay))\n }\n }\n } finally {\n isRefreshPending = false\n }\n }\n\n // Set up scheduled token refresh\n tokenRefreshInterval = setInterval(() => {\n // Don't await to prevent blocking the interval timer\n refreshTokenWithRetry(5, 1000, \"scheduled\").catch((error) => {\n consola.error(\"Unexpected error in scheduled token refresh:\", error)\n })\n }, refreshInterval)\n\n // Start connectivity monitoring\n connectivityMonitor.start()\n\n // Create event handler functions that can be properly removed\n onlineHandler = () => {\n consola.debug(\n \"Network connectivity restored, attempting immediate token refresh\",\n )\n // Attempt immediate refresh when network comes back\n refreshTokenWithRetry(3, 500, \"network-restored\").catch((error) => {\n consola.error(\n \"Unexpected error in network-restored token refresh:\",\n error,\n )\n })\n }\n\n offlineHandler = () => {\n consola.debug(\"Network connectivity lost\")\n }\n\n // Listen for network restoration events\n connectivityMonitor.on(\"online\", onlineHandler)\n connectivityMonitor.on(\"offline\", offlineHandler)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/user`,\n {\n headers: githubHeaders(state),\n signal: controller.signal,\n },\n )\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`copilot-api debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import { execSync } from \"node:child_process\"\nimport process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, ppid, env } = process\n\n if (platform === \"win32\") {\n try {\n const command = `wmic process get ParentProcessId,Name | findstr \"${ppid}\"`\n const parentProcess = execSync(command, { stdio: \"pipe\" }).toString()\n\n if (parentProcess.toLowerCase().includes(\"powershell.exe\")) {\n return \"powershell\"\n }\n } catch {\n return \"cmd\"\n }\n\n return \"cmd\"\n } else {\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n }\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${value}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set ${key}=${value}`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${value}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${value}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator = shell === \"cmd\" ? \" & \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected\",\n Response.json({ message: \"Request rejected\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n // eslint-disable-next-line require-atomic-updates\n state.lastRequestTimestamp = now\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import { countTokens } from \"gpt-tokenizer/model/gpt-4o\"\n\nimport type { Message } from \"~/services/copilot/create-chat-completions\"\n\nexport const getTokenCount = (messages: Array<Message>) => {\n const simplifiedMessages = messages.map((message) => {\n let content = \"\"\n if (typeof message.content === \"string\") {\n content = message.content\n } else if (Array.isArray(message.content)) {\n content = message.content\n .filter((part) => part.type === \"text\")\n .map((part) => (part as { text: string }).text)\n .join(\"\")\n }\n return { ...message, content }\n })\n\n let inputMessages = simplifiedMessages.filter((message) => {\n return message.role !== \"tool\"\n })\n let outputMessages: typeof simplifiedMessages = []\n\n const lastMessage = simplifiedMessages.at(-1)\n\n if (lastMessage?.role === \"assistant\") {\n inputMessages = simplifiedMessages.slice(0, -1)\n outputMessages = [lastMessage]\n }\n\n // @ts-expect-error TS can't infer from arr.filter()\n const inputTokens = countTokens(inputMessages)\n // @ts-expect-error TS can't infer from arr.filter()\n const outputTokens = countTokens(outputMessages)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","/**\n * Sanitizes JSON payloads by removing ANSI escape sequences and invisible Unicode characters\n * that can cause GitHub Copilot API to return 400 Bad Request errors.\n */\n\n/**\n * Removes ANSI escape sequences and problematic Unicode characters from a string\n */\nexport function sanitizeString(str: string): string {\n return (\n str\n // Remove ANSI escape sequences (e.g., \\x1b[31m, \\x1b[0m, etc.)\n .replaceAll(/\\x1b\\[[0-9;]*[a-z]/gi, \"\")\n // Remove other ANSI sequences that might use different patterns\n .replaceAll(/\\x1b\\[[0-9;]*m/g, \"\")\n .replaceAll(/\\x1b\\[[\\d;]*[HfA-DsuJKmhlp]/g, \"\")\n // Remove other control characters except newlines (\\n), tabs (\\t), and carriage returns (\\r)\n .replaceAll(/[\\x00-\\x08\\v\\f\\x0E-\\x1F\\x7F]/g, \"\")\n // Remove invisible Unicode characters\n .replaceAll(/[\\u200B-\\u200D\\uFEFF]/g, \"\") // Zero-width spaces, BOM\n .replaceAll(/[\\u2060-\\u2064]/g, \"\") // Word joiner, invisible separator\n .replaceAll(/[\\u206A-\\u206F]/g, \"\") // Various invisible formatting characters\n // Remove other problematic invisible characters\n .replaceAll(/[\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/g, \"\") // Various space characters\n // Remove any remaining non-printable characters that might cause JSON parsing issues\n .replaceAll(/[\\uFFF0-\\uFFFF]/g, \"\")\n ) // Specials block\n}\n\n/**\n * Recursively sanitizes all string values in an object or array\n */\nexport function sanitizePayload<T>(payload: T): T {\n if (typeof payload === \"string\") {\n return sanitizeString(payload) as T\n }\n\n if (Array.isArray(payload)) {\n return payload.map((item) => sanitizePayload(item)) as T\n }\n\n if (payload && typeof payload === \"object\") {\n const sanitized = {} as T\n for (const [key, value] of Object.entries(payload)) {\n ;(sanitized as any)[key] = sanitizePayload(value)\n }\n return sanitized\n }\n\n return payload\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\nimport { request } from \"undici\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { sanitizePayload } from \"~/lib/sanitize\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n // Sanitize payload to remove ANSI escape sequences and problematic Unicode characters\n const sanitizedPayload = sanitizePayload(payload)\n\n const enableVision = sanitizedPayload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = sanitizedPayload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const { statusCode, headers: responseHeaders, body } = await request(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(sanitizedPayload),\n signal: controller.signal,\n // Set undici-specific timeouts\n headersTimeout: timeoutMs,\n bodyTimeout: timeoutMs * 3, // Triple the body timeout for streaming\n connectTimeout: timeoutMs,\n })\n\n // Create a Response-like object for compatibility\n const response = new Response(body, {\n status: statusCode,\n headers: responseHeaders as HeadersInit,\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create chat completions\", response)\n throw new HTTPError(\"Failed to create chat completions\", response)\n }\n\n if (sanitizedPayload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n} from \"~/services/copilot/create-chat-completions\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n\n consola.info(\"Current token count:\", getTokenCount(payload.messages))\n\n if (state.manualApprove) await awaitApproval()\n\n if (isNullish(payload.max_tokens)) {\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities.limits.max_output_tokens,\n }\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n\n const response = await createChatCompletions(payload)\n\n if (isNonStreaming(response)) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n // Setup timeout with AbortController\n const controller = new AbortController()\n const timeoutMs = state.timeoutMs ?? 120000 // Default to 2 minutes\n const timeout = setTimeout(() => {\n controller.abort()\n }, timeoutMs)\n\n try {\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n\n if (!response.ok)\n throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const paylod = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(paylod)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { type AnthropicResponse } from \"./anthropic-types\"\n\nexport function mapOpenAIStopReasonToAnthropic(\n finishReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null,\n): AnthropicResponse[\"stop_reason\"] {\n if (finishReason === null) {\n return null\n }\n const stopReasonMap = {\n stop: \"end_turn\",\n length: \"max_tokens\",\n tool_calls: \"tool_use\",\n content_filter: \"end_turn\",\n } as const\n return stopReasonMap[finishReason]\n}\n","import {\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type ContentPart,\n type Message,\n type TextPart,\n type Tool,\n type ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\n\nimport {\n type AnthropicAssistantContentBlock,\n type AnthropicAssistantMessage,\n type AnthropicMessage,\n type AnthropicMessagesPayload,\n type AnthropicResponse,\n type AnthropicTextBlock,\n type AnthropicThinkingBlock,\n type AnthropicTool,\n type AnthropicToolResultBlock,\n type AnthropicToolUseBlock,\n type AnthropicUserContentBlock,\n type AnthropicUserMessage,\n} from \"./anthropic-types\"\nimport { mapOpenAIStopReasonToAnthropic } from \"./utils\"\n\n// Payload translation\n\nexport function translateToOpenAI(\n payload: AnthropicMessagesPayload,\n): ChatCompletionsPayload {\n return {\n model: translateModelName(payload.model),\n messages: translateAnthropicMessagesToOpenAI(\n payload.messages,\n payload.system,\n ),\n max_tokens: payload.max_tokens,\n stop: payload.stop_sequences,\n stream: payload.stream,\n temperature: payload.temperature,\n top_p: payload.top_p,\n user: payload.metadata?.user_id,\n tools: translateAnthropicToolsToOpenAI(payload.tools),\n tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice),\n }\n}\n\nfunction translateModelName(model: string): string {\n // Subagent requests use a specific model number which Copilot doesn't support\n if (model.startsWith(\"claude-sonnet-4-\")) {\n return model.replace(/^claude-sonnet-4-.*/, \"claude-sonnet-4\")\n } else if (model.startsWith(\"claude-opus-\")) {\n return model.replace(/^claude-opus-4-.*/, \"claude-opus-4\")\n }\n return model\n}\n\nfunction translateAnthropicMessagesToOpenAI(\n anthropicMessages: Array<AnthropicMessage>,\n system: string | Array<AnthropicTextBlock> | undefined,\n): Array<Message> {\n const systemMessages = handleSystemPrompt(system)\n\n const otherMessages = anthropicMessages.flatMap((message) =>\n message.role === \"user\" ?\n handleUserMessage(message)\n : handleAssistantMessage(message),\n )\n\n return [...systemMessages, ...otherMessages]\n}\n\nfunction handleSystemPrompt(\n system: string | Array<AnthropicTextBlock> | undefined,\n): Array<Message> {\n if (!system) {\n return []\n }\n\n if (typeof system === \"string\") {\n return [{ role: \"system\", content: system }]\n } else {\n const systemText = system.map((block) => block.text).join(\"\\n\\n\")\n return [{ role: \"system\", content: systemText }]\n }\n}\n\nfunction handleUserMessage(message: AnthropicUserMessage): Array<Message> {\n const newMessages: Array<Message> = []\n\n if (Array.isArray(message.content)) {\n const toolResultBlocks = message.content.filter(\n (block): block is AnthropicToolResultBlock =>\n block.type === \"tool_result\",\n )\n const otherBlocks = message.content.filter(\n (block) => block.type !== \"tool_result\",\n )\n\n // Tool results must come first to maintain protocol: tool_use -> tool_result -> user\n for (const block of toolResultBlocks) {\n newMessages.push({\n role: \"tool\",\n tool_call_id: block.tool_use_id,\n content: mapContent(block.content),\n })\n }\n\n if (otherBlocks.length > 0) {\n newMessages.push({\n role: \"user\",\n content: mapContent(otherBlocks),\n })\n }\n } else {\n newMessages.push({\n role: \"user\",\n content: mapContent(message.content),\n })\n }\n\n return newMessages\n}\n\nfunction handleAssistantMessage(\n message: AnthropicAssistantMessage,\n): Array<Message> {\n if (!Array.isArray(message.content)) {\n return [\n {\n role: \"assistant\",\n content: mapContent(message.content),\n },\n ]\n }\n\n const toolUseBlocks = message.content.filter(\n (block): block is AnthropicToolUseBlock => block.type === \"tool_use\",\n )\n\n const textBlocks = message.content.filter(\n (block): block is AnthropicTextBlock => block.type === \"text\",\n )\n\n const thinkingBlocks = message.content.filter(\n (block): block is AnthropicThinkingBlock => block.type === \"thinking\",\n )\n\n // Combine text and thinking blocks, as OpenAI doesn't have separate thinking blocks\n const allTextContent = [\n ...textBlocks.map((b) => b.text),\n ...thinkingBlocks.map((b) => b.thinking),\n ].join(\"\\n\\n\")\n\n return toolUseBlocks.length > 0 ?\n [\n {\n role: \"assistant\",\n content: allTextContent || null,\n tool_calls: toolUseBlocks.map((toolUse) => ({\n id: toolUse.id,\n type: \"function\",\n function: {\n name: toolUse.name,\n arguments: JSON.stringify(toolUse.input),\n },\n })),\n },\n ]\n : [\n {\n role: \"assistant\",\n content: mapContent(message.content),\n },\n ]\n}\n\nfunction mapContent(\n content:\n | string\n | Array<AnthropicUserContentBlock | AnthropicAssistantContentBlock>,\n): string | Array<ContentPart> | null {\n if (typeof content === \"string\") {\n return content\n }\n if (!Array.isArray(content)) {\n return null\n }\n\n const hasImage = content.some((block) => block.type === \"image\")\n if (!hasImage) {\n return content\n .filter(\n (block): block is AnthropicTextBlock | AnthropicThinkingBlock =>\n block.type === \"text\" || block.type === \"thinking\",\n )\n .map((block) => (block.type === \"text\" ? block.text : block.thinking))\n .join(\"\\n\\n\")\n }\n\n const contentParts: Array<ContentPart> = []\n for (const block of content) {\n switch (block.type) {\n case \"text\": {\n contentParts.push({ type: \"text\", text: block.text })\n\n break\n }\n case \"thinking\": {\n contentParts.push({ type: \"text\", text: block.thinking })\n\n break\n }\n case \"image\": {\n contentParts.push({\n type: \"image_url\",\n image_url: {\n url: `data:${block.source.media_type};base64,${block.source.data}`,\n },\n })\n\n break\n }\n // No default\n }\n }\n return contentParts\n}\n\nfunction translateAnthropicToolsToOpenAI(\n anthropicTools: Array<AnthropicTool> | undefined,\n): Array<Tool> | undefined {\n if (!anthropicTools) {\n return undefined\n }\n return anthropicTools.map((tool) => ({\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.input_schema,\n },\n }))\n}\n\nfunction translateAnthropicToolChoiceToOpenAI(\n anthropicToolChoice: AnthropicMessagesPayload[\"tool_choice\"],\n): ChatCompletionsPayload[\"tool_choice\"] {\n if (!anthropicToolChoice) {\n return undefined\n }\n\n switch (anthropicToolChoice.type) {\n case \"auto\": {\n return \"auto\"\n }\n case \"any\": {\n return \"required\"\n }\n case \"tool\": {\n if (anthropicToolChoice.name) {\n return {\n type: \"function\",\n function: { name: anthropicToolChoice.name },\n }\n }\n return undefined\n }\n case \"none\": {\n return \"none\"\n }\n default: {\n return undefined\n }\n }\n}\n\n// Response translation\n\nexport function translateToAnthropic(\n response: ChatCompletionResponse,\n): AnthropicResponse {\n // Merge content from all choices\n const allTextBlocks: Array<AnthropicTextBlock> = []\n const allToolUseBlocks: Array<AnthropicToolUseBlock> = []\n let stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null =\n null // default\n stopReason = response.choices[0]?.finish_reason ?? stopReason\n\n // Process all choices to extract text and tool use blocks\n for (const choice of response.choices) {\n const textBlocks = getAnthropicTextBlocks(choice.message.content)\n const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls)\n\n allTextBlocks.push(...textBlocks)\n allToolUseBlocks.push(...toolUseBlocks)\n\n // Use the finish_reason from the first choice, or prioritize tool_calls\n if (choice.finish_reason === \"tool_calls\" || stopReason === \"stop\") {\n stopReason = choice.finish_reason\n }\n }\n\n // Note: GitHub Copilot doesn't generate thinking blocks, so we don't include them in responses\n\n return {\n id: response.id,\n type: \"message\",\n role: \"assistant\",\n model: response.model,\n content: [...allTextBlocks, ...allToolUseBlocks],\n stop_reason: mapOpenAIStopReasonToAnthropic(stopReason),\n stop_sequence: null,\n usage: {\n input_tokens: response.usage?.prompt_tokens ?? 0,\n output_tokens: response.usage?.completion_tokens ?? 0,\n },\n }\n}\n\nfunction getAnthropicTextBlocks(\n messageContent: Message[\"content\"],\n): Array<AnthropicTextBlock> {\n if (typeof messageContent === \"string\") {\n return [{ type: \"text\", text: messageContent }]\n }\n\n if (Array.isArray(messageContent)) {\n return messageContent\n .filter((part): part is TextPart => part.type === \"text\")\n .map((part) => ({ type: \"text\", text: part.text }))\n }\n\n return []\n}\n\nfunction getAnthropicToolUseBlocks(\n toolCalls: Array<ToolCall> | undefined,\n): Array<AnthropicToolUseBlock> {\n if (!toolCalls) {\n return []\n }\n return toolCalls.map((toolCall) => ({\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.function.name,\n input: JSON.parse(toolCall.function.arguments) as Record<string, unknown>,\n }))\n}\n","import { type ChatCompletionChunk } from \"~/services/copilot/create-chat-completions\"\n\nimport {\n type AnthropicStreamEventData,\n type AnthropicStreamState,\n} from \"./anthropic-types\"\nimport { mapOpenAIStopReasonToAnthropic } from \"./utils\"\n\nfunction isToolBlockOpen(state: AnthropicStreamState): boolean {\n if (!state.contentBlockOpen) {\n return false\n }\n // Check if the current block index corresponds to any known tool call\n return Object.values(state.toolCalls).some(\n (tc) => tc.anthropicBlockIndex === state.contentBlockIndex,\n )\n}\n\n// eslint-disable-next-line max-lines-per-function, complexity\nexport function translateChunkToAnthropicEvents(\n chunk: ChatCompletionChunk,\n state: AnthropicStreamState,\n): Array<AnthropicStreamEventData> {\n const events: Array<AnthropicStreamEventData> = []\n\n if (chunk.choices.length === 0) {\n return events\n }\n\n const choice = chunk.choices[0]\n const { delta } = choice\n\n if (!state.messageStartSent) {\n events.push({\n type: \"message_start\",\n message: {\n id: chunk.id,\n type: \"message\",\n role: \"assistant\",\n content: [],\n model: chunk.model,\n stop_reason: null,\n stop_sequence: null,\n usage: {\n input_tokens: chunk.usage?.prompt_tokens ?? 0,\n output_tokens: 0, // Will be updated in message_delta when finished\n },\n },\n })\n state.messageStartSent = true\n }\n\n if (delta.content) {\n if (isToolBlockOpen(state)) {\n // A tool block was open, so close it before starting a text block.\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockIndex++\n state.contentBlockOpen = false\n }\n\n if (!state.contentBlockOpen) {\n events.push({\n type: \"content_block_start\",\n index: state.contentBlockIndex,\n content_block: {\n type: \"text\",\n text: \"\",\n },\n })\n state.contentBlockOpen = true\n }\n\n events.push({\n type: \"content_block_delta\",\n index: state.contentBlockIndex,\n delta: {\n type: \"text_delta\",\n text: delta.content,\n },\n })\n }\n\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n if (toolCall.id && toolCall.function?.name) {\n // New tool call starting.\n if (state.contentBlockOpen) {\n // Close any previously open block.\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockIndex++\n state.contentBlockOpen = false\n }\n\n const anthropicBlockIndex = state.contentBlockIndex\n state.toolCalls[toolCall.index] = {\n id: toolCall.id,\n name: toolCall.function.name,\n anthropicBlockIndex,\n }\n\n events.push({\n type: \"content_block_start\",\n index: anthropicBlockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.function.name,\n input: {},\n },\n })\n state.contentBlockOpen = true\n }\n\n if (toolCall.function?.arguments) {\n const toolCallInfo = state.toolCalls[toolCall.index]\n // Tool call can still be empty\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (toolCallInfo) {\n events.push({\n type: \"content_block_delta\",\n index: toolCallInfo.anthropicBlockIndex,\n delta: {\n type: \"input_json_delta\",\n partial_json: toolCall.function.arguments,\n },\n })\n }\n }\n }\n }\n\n if (choice.finish_reason) {\n if (state.contentBlockOpen) {\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockOpen = false\n }\n\n events.push(\n {\n type: \"message_delta\",\n delta: {\n stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),\n stop_sequence: null,\n },\n usage: {\n input_tokens: chunk.usage?.prompt_tokens ?? 0,\n output_tokens: chunk.usage?.completion_tokens ?? 0,\n ...(chunk.usage?.prompt_tokens_details?.cached_tokens\n !== undefined && {\n cache_read_input_tokens:\n chunk.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n },\n {\n type: \"message_stop\",\n },\n )\n }\n\n return events\n}\n\nexport function translateErrorToAnthropicErrorEvent(): AnthropicStreamEventData {\n return {\n type: \"error\",\n error: {\n type: \"api_error\",\n message: \"An unexpected error occurred during streaming.\",\n },\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport {\n createChatCompletions,\n type ChatCompletionChunk,\n type ChatCompletionResponse,\n} from \"~/services/copilot/create-chat-completions\"\n\nimport {\n type AnthropicMessagesPayload,\n type AnthropicStreamState,\n} from \"./anthropic-types\"\nimport {\n translateToAnthropic,\n translateToOpenAI,\n} from \"./non-stream-translation\"\nimport { translateChunkToAnthropicEvents } from \"./stream-translation\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n const anthropicPayload = await c.req.json<AnthropicMessagesPayload>()\n consola.debug(\"Anthropic request payload:\", JSON.stringify(anthropicPayload))\n\n const openAIPayload = translateToOpenAI(anthropicPayload)\n consola.debug(\n \"Translated OpenAI request payload:\",\n JSON.stringify(openAIPayload),\n )\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const response = await createChatCompletions(openAIPayload)\n\n if (isNonStreaming(response)) {\n consola.debug(\n \"Non-streaming response from Copilot:\",\n JSON.stringify(response).slice(-400),\n )\n const anthropicResponse = translateToAnthropic(response)\n consola.debug(\n \"Translated Anthropic response:\",\n JSON.stringify(anthropicResponse),\n )\n return c.json(anthropicResponse)\n }\n\n consola.debug(\"Streaming response from Copilot\")\n return streamSSE(c, async (stream) => {\n const streamState: AnthropicStreamState = {\n messageStartSent: false,\n contentBlockIndex: 0,\n contentBlockOpen: false,\n toolCalls: {},\n }\n\n for await (const rawEvent of response) {\n consola.debug(\"Copilot raw stream event:\", JSON.stringify(rawEvent))\n if (rawEvent.data === \"[DONE]\") {\n break\n }\n\n if (!rawEvent.data) {\n continue\n }\n\n const chunk = JSON.parse(rawEvent.data) as ChatCompletionChunk\n const events = translateChunkToAnthropicEvents(chunk, streamState)\n\n for (const event of events) {\n consola.debug(\"Translated Anthropic event:\", JSON.stringify(event))\n await stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n })\n }\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => ({\n id: model.id,\n object: \"model\",\n type: \"model\",\n created: 0, // No date available from source\n created_at: new Date(0).toISOString(), // No date available from source\n owned_by: model.vendor,\n display_name: model.name,\n }))\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n try {\n return c.json({\n token: state.copilotToken,\n })\n } catch (error) {\n console.error(\"Error fetching token:\", error)\n return c.json({ error: \"Failed to fetch token\", token: null }, 500)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n console.error(\"Error fetching Copilot usage:\", error)\n return c.json({ error: \"Failed to fetch Copilot usage\" }, 500)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\nimport { logger } from \"hono/logger\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(logger())\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\nserver.post(\"/v1/messages/count_tokens\", (c) => c.json({ input_tokens: 1 }))\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport process from \"node:process\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { connectivityMonitor } from \"./lib/connectivity\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport {\n setupCopilotToken,\n setupGitHubToken,\n cleanupTokenManagement,\n} from \"./lib/token\"\nimport { cacheModels, cacheVSCodeVersion } from \"./lib/utils\"\nimport { server } from \"./server\"\n\n// Track cleanup functions to call on exit\nconst cleanupFunctions: Array<() => void | Promise<void>> = []\n\n// Setup process signal handlers for graceful shutdown\nfunction setupGracefulShutdown() {\n const cleanup = async () => {\n consola.info(\"Gracefully shutting down...\")\n\n // Run all cleanup functions\n for (const cleanupFn of cleanupFunctions) {\n try {\n await cleanupFn()\n } catch (error) {\n consola.error(\"Error during cleanup:\", error)\n }\n }\n\n consola.info(\"Shutdown complete\")\n process.exit(0)\n }\n\n // Handle SIGINT (Ctrl+C) and SIGTERM\n process.on(\"SIGINT\", cleanup)\n process.on(\"SIGTERM\", cleanup)\n\n // Handle uncaught exceptions and unhandled promise rejections\n process.on(\"uncaughtException\", (error) => {\n consola.error(\"Uncaught exception:\", error)\n cleanup().finally(() => process.exit(1))\n })\n\n process.on(\"unhandledRejection\", (reason, promise) => {\n consola.error(\"Unhandled promise rejection at:\", promise, \"reason:\", reason)\n cleanup().finally(() => process.exit(1))\n })\n}\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n showToken: boolean\n model?: string\n smallModel?: string\n timeout?: number\n disableConnectivityMonitoring: boolean\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n // Setup graceful shutdown handlers early\n setupGracefulShutdown()\n\n // Register connectivity monitor cleanup\n cleanupFunctions.push(\n () => {\n consola.debug(\"Cleaning up connectivity monitor\")\n connectivityMonitor.stop()\n },\n () => {\n consola.debug(\"Cleaning up token management\")\n cleanupTokenManagement()\n },\n )\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n state.timeoutMs = options.timeout\n state.connectivity.enabled = !options.disableConnectivityMonitoring\n\n await ensurePaths()\n await cacheVSCodeVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.info(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) {\n invariant(state.models, \"Models should be loaded by now\")\n\n let selectedModel: string\n let selectedSmallModel: string\n\n // Check if models are provided via command line\n if (options.model && options.smallModel) {\n // Validate provided models\n const availableModelIds = state.models.data.map((model) => model.id)\n\n if (!availableModelIds.includes(options.model)) {\n consola.error(`Invalid model: ${options.model}`)\n consola.info(`Available models: \\n${availableModelIds.join(\"\\n\")}`)\n process.exit(1)\n }\n\n if (!availableModelIds.includes(options.smallModel)) {\n consola.error(`Invalid small model: ${options.smallModel}`)\n consola.info(`Available models: \\n${availableModelIds.join(\"\\n\")}`)\n process.exit(1)\n }\n\n selectedModel = options.model\n selectedSmallModel = options.smallModel\n consola.info(`Using model: ${selectedModel}`)\n consola.info(`Using small model: ${selectedSmallModel}`)\n } else if (options.model || options.smallModel) {\n // If only one model is provided, show error\n consola.error(\n \"Both --model and --small-model must be specified when using command-line model selection\",\n )\n process.exit(1)\n } else {\n // Fall back to interactive selection\n selectedModel = await consola.prompt(\n \"Select a model to use with Claude Code\",\n {\n type: \"select\",\n options: state.models.data.map((model) => model.id),\n },\n )\n\n selectedSmallModel = await consola.prompt(\n \"Select a small model to use with Claude Code\",\n {\n type: \"select\",\n options: state.models.data.map((model) => model.id),\n },\n )\n }\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n },\n \"claude\",\n )\n\n try {\n clipboard.writeSync(command)\n consola.success(\"Copied Claude Code command to clipboard!\")\n } catch {\n consola.warn(\n \"Failed to copy to clipboard. Here is the Claude Code command:\",\n )\n consola.log(command)\n }\n }\n\n consola.box(\n `🌐 Usage Viewer: https://ericc-ch.github.io/copilot-api?endpoint=${serverUrl}/usage`,\n )\n\n serve({\n fetch: server.fetch as ServerHandler,\n port: options.port,\n })\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the Copilot API server\",\n },\n args: {\n port: {\n alias: \"p\",\n type: \"string\",\n default: \"4141\",\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\",\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\",\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\",\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\",\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"claude-code\": {\n alias: \"c\",\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Model to use with Claude Code (requires --claude-code)\",\n },\n \"small-model\": {\n alias: \"s\",\n type: \"string\",\n description:\n \"Small/fast model to use with Claude Code (requires --claude-code)\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n timeout: {\n alias: \"t\",\n type: \"string\",\n description: \"API timeout in milliseconds (default: 120000)\",\n },\n \"disable-connectivity-monitoring\": {\n type: \"boolean\",\n default: false,\n description:\n \"Disable automatic network connectivity monitoring for token refresh\",\n },\n },\n run({ args }) {\n const rateLimitRaw = args[\"rate-limit\"]\n const rateLimit =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n rateLimitRaw === undefined ? undefined : Number.parseInt(rateLimitRaw, 10)\n\n const timeoutRaw = args.timeout\n const timeout =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n timeoutRaw === undefined ? 120000 : Number.parseInt(timeoutRaw, 10)\n\n return runServer({\n port: Number.parseInt(args.port, 10),\n verbose: args.verbose,\n accountType: args[\"account-type\"],\n manual: args.manual,\n rateLimit,\n rateLimitWait: args.wait,\n githubToken: args[\"github-token\"],\n claudeCode: args[\"claude-code\"],\n model: args.model,\n smallModel: args[\"small-model\"],\n showToken: args[\"show-token\"],\n timeout,\n disableConnectivityMonitoring: args[\"disable-connectivity-monitoring\"],\n })\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nconst main = defineCommand({\n meta: {\n name: \"copilot-api\",\n description:\n \"A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.\",\n },\n subCommands: { auth, start, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,UAAU,KAAK,KAAK,GAAG,WAAW,UAAU,SAAS;AAE3D,MAAM,oBAAoB,KAAK,KAAK,SAAS;AAE7C,MAAa,QAAQ;CACnB;CACA;;AAGF,eAAsB,cAA6B;AACjD,OAAM,GAAG,MAAM,MAAM,SAAS,EAAE,WAAW;AAC3C,OAAM,WAAW,MAAM;;AAGzB,eAAe,WAAW,UAAiC;AACzD,KAAI;AACF,QAAM,GAAG,OAAO,UAAU,GAAG,UAAU;SACjC;AACN,QAAM,GAAG,UAAU,UAAU;AAC7B,QAAM,GAAG,MAAM,UAAU;;;;;;ACa7B,MAAaA,QAAe;CAC1B,aAAa;CACb,eAAe;CACf,eAAe;CACf,WAAW;CACX,cAAc;EACZ,SAAS;EACT,gBAAgB;GACd;GACA;GACA;;EAEF,mBAAmB;EACnB,mBAAmB;EACnB,WAAW;EACX,aAAa;EACb,mBAAmB;EACnB,UAAU;;;;;;AC7Bd,IAAM,sBAAN,cAAkC,aAAa;CAC7C,AAAQ,WAAW;CACnB,AAAQ,+BAAc,IAAI,QAAO;CACjC,AAAQ,sBAAsB;CAC9B,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,uBAA+C;CACvD,AAAQ;CACR,AAAQ;CAER,QAAc;AACZ,MAAI,CAAC,MAAM,aAAa,SAAS;AAC/B,WAAQ,MAAM;AACd;;AAGF,UAAQ,KAAK,iCAAiC;GAC5C,gBAAgB,MAAM,aAAa;GACnC,cAAc,MAAM,aAAa;;AAGnC,OAAK;EAGL,MAAM,gBAAgB;AACpB,QAAK;AACL,WAAQ,KAAK;;AAGf,UAAQ,GAAG,UAAU;AACrB,UAAQ,GAAG,WAAW;;CAGxB,OAAa;AACX,UAAQ,MAAM;AAEd,MAAI,KAAK,eAAe;AACtB,gBAAa,KAAK;AAClB,QAAK,gBAAgB;;AAGvB,MAAI,KAAK,iBAAiB;AACxB,QAAK,gBAAgB;AACrB,QAAK,kBAAkB;;;CAI3B,AAAQ,oBAA0B;AAChC,MAAI,KAAK,cACP,cAAa,KAAK;EAGpB,MAAM,eAAe,KAAK,WACtB,MAAM,aAAa,oBACnB,MAAM,aAAa;EAGvB,MAAM,SAAS,KAAK,WAAW,MAAM,aAAa;EAClD,MAAM,WAAW,eAAe;AAEhC,OAAK,gBAAgB,iBAAiB;AACpC,QAAK;KACJ;;CAGL,MAAc,2BAA0C;AACtD,OAAK,kBAAkB,IAAI;EAC3B,MAAM,YAAY,iBACV,KAAK,iBAAiB,SAC5B,MAAM,aAAa;AAGrB,MAAI;GACF,IAAI,UAAU;AAEd,QAAK,MAAM,YAAY,MAAM,aAAa,eACxC,KAAI;IACF,MAAM,WAAW,MAAM,MAAM,UAAU;KACrC,QAAQ;KACR,QAAQ,KAAK,gBAAgB;KAC7B,SAAS;MACP,cAAc;MACd,GAAI,MAAM,aAAa,YAAY,EACjC,iBAAiB;;;AAKvB,QAAI,SAAS,IAAI;AACf,eAAU;AACV,UAAK,yBAAyB;AAC9B;;YAEK,OAAO;AACd,SAAK,qBAAqB,aACvB,KAAK,qBAAqB,aAAa,KAAK;AAE/C,YAAQ,MAAM,oBAAoB,SAAS,IAAI;;AAInD,QAAK,wBAAwB;WACtB,OAAO;AACd,QAAK,wBAAwB;YACrB;AACR,gBAAa;AACb,QAAK;;;CAIT,AAAQ,wBAAwB,UAAyB;EACvD,MAAM,YAAY,KAAK;AACvB,OAAK,WAAW;AAChB,OAAK,+BAAc,IAAI,QAAO;AAE9B,MAAI,UAAU;AACZ,OAAI,KAAK,sBAAsB,EAC7B,SAAQ,KAAK,+BAA+B,KAAK,oBAAoB;AAEvE,QAAK,sBAAsB;AAC3B,QAAK,gBAAgB;AACrB,QAAK,mBAAmB;AAExB,OAAI,CAAC,UACH,MAAK,KAAK;SAEP;AACL,QAAK;AAEL,OAAI,WAAW;AACb,YAAQ,KAAK;AACb,SAAK,KAAK;;;;CAKhB,AAAQ,wBAAwB,OAAoB;AAClD,OAAK,gBAAgB,MAAM;AAC3B,OAAK,mBAAmB,MAAM;AAE9B,UAAQ,MAAM,8BAA8B;AAC5C,OAAK,wBAAwB;;CAG/B,uBAA0C;AACxC,SAAO;GACL,UAAU,KAAK;GACf,aAAa,KAAK;GAClB,qBAAqB,KAAK;GAC1B,eAAe,KAAK;GACpB,kBAAkB,KAAK;;;CAI3B,sBAAwC;EACtC,MAAM,kBAAkB,KAAK,WACzB,MAAM,aAAa,oBACnB,MAAM,aAAa;EAEvB,MAAM,oBAAoB,IAAI,KAC5B,KAAK,QAAQ,kBAAkB,KAAK,WAAW,MAAM,aAAa,aAClE;AAEF,SAAO;GACL;GACA;GACA,wBAAwB,KAAK;GAC7B,sBAAsB,EAAE,GAAG,KAAK;GAChC,eAAe,MAAM,aAAa,cAAc;GAChD,mBAAmB,MAAM,aAAa;GACtC,UAAU,MAAM,aAAa;;;;AAKnC,MAAa,sBAAsB,IAAI;;;;ACpMvC,MAAa,yBAAyB;CACpC,gBAAgB;CAChB,QAAQ;;AAGV,MAAM,kBAAkB;AACxB,MAAM,wBAAwB,gBAAgB;AAC9C,MAAM,aAAa,qBAAqB;AAExC,MAAM,cAAc;AAEpB,MAAa,kBAAkB,YAC7BC,QAAM,gBAAgB,eACpB,kCACA,eAAeA,QAAM,YAAY;AACrC,MAAa,kBAAkB,SAAc,SAAkB,UAAU;CACvE,MAAMC,UAAkC;EACtC,eAAe,UAAUD,QAAM;EAC/B,gBAAgB,kBAAkB;EAClC,0BAA0B;EAC1B,kBAAkB,UAAUA,QAAM;EAClC,yBAAyB;EACzB,cAAc;EACd,iBAAiB;EACjB,wBAAwB;EACxB,sBAAsB;EACtB,gBAAgB;EAChB,uCAAuC;;AAGzC,KAAI,OAAQ,SAAQ,4BAA4B;AAEhD,QAAO;;AAGT,MAAa,sBAAsB;AACnC,MAAa,iBAAiB,aAAkB;CAC9C,GAAG;CACH,eAAe,SAASA,QAAM;CAC9B,kBAAkB,UAAUA,QAAM;CAClC,yBAAyB;CACzB,cAAc;CACd,wBAAwB;CACxB,uCAAuC;;AAGzC,MAAa,kBAAkB;AAC/B,MAAa,mBAAmB;AAChC,MAAa,oBAAoB,CAAC,aAAa,KAAK;;;;AC/CpD,IAAa,YAAb,cAA+B,MAAM;CACnC;CAEA,YAAY,SAAiB,UAAoB;AAC/C,QAAM;AACN,OAAK,WAAW;;;AAIpB,eAAsB,aAAa,GAAY,OAAgB;AAC7D,SAAQ,MAAM,mBAAmB;AAEjC,KAAI,iBAAiB,WAAW;EAC9B,MAAM,YAAY,MAAM,MAAM,SAAS;EACvC,IAAIE;AACJ,MAAI;AACF,eAAY,KAAK,MAAM;UACjB;AACN,eAAY;;AAEd,UAAQ,MAAM,eAAe;AAC7B,SAAO,EAAE,KACP,EACE,OAAO;GACL,SAAS;GACT,MAAM;OAGV,MAAM,SAAS;;AAInB,QAAO,EAAE,KACP,EACE,OAAO;EACL,SAAU,MAAgB;EAC1B,MAAM;MAGV;;;;;ACxCJ,MAAa,kBAAkB,YAAY;CAEzC,MAAM,aAAa,IAAI;CACvB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,UAAU,iBAAiB;AAC/B,aAAW;IACV;AAEH,KAAI;EACF,MAAM,WAAW,MAAM,MACrB,GAAG,oBAAoB,6BACvB;GACE,SAAS,cAAc;GACvB,QAAQ,WAAW;;AAIvB,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,UAAU,+BAA+B;AAErD,SAAQ,MAAM,SAAS;WACf;AACR,eAAa;;;;;;ACjBjB,eAAsB,gBAA6C;CAEjE,MAAM,aAAa,IAAI;CACvB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,UAAU,iBAAiB;AAC/B,aAAW;IACV;AAEH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,gBAAgB,qBAAqB;GACnE,QAAQ;GACR,SAAS;GACT,MAAM,KAAK,UAAU;IACnB,WAAW;IACX,OAAO;;GAET,QAAQ,WAAW;;AAGrB,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,6BAA6B;AAEnE,SAAQ,MAAM,SAAS;WACf;AACR,eAAa;;;;;;AC5BjB,eAAsB,gBAAgB;CAEpC,MAAM,aAAa,IAAI;CACvB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,UAAU,iBAAiB;AAC/B,aAAW;IACV;AAEH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,oBAAoB,QAAQ;GAC1D,SAAS;IACP,eAAe,SAAS,MAAM;IAC9B,GAAG;;GAEL,QAAQ,WAAW;;AAGrB,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,6BAA6B;AAEnE,SAAQ,MAAM,SAAS;WACf;AACR,eAAa;;;;;;ACrBjB,MAAa,YAAY,YAAY;CAEnC,MAAM,aAAa,IAAI;CACvB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,UAAU,iBAAiB;AAC/B,aAAW;IACV;AAEH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,eAAe,OAAO,UAAU;GAC9D,SAAS,eAAe;GACxB,QAAQ,WAAW;;AAGrB,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,wBAAwB;AAE9D,SAAQ,MAAM,SAAS;WACf;AACR,eAAa;;;;;;ACtBjB,SAAgB,mBAAmB;AACjC,QAAO;;AAGT;;;;ACGA,MAAa,SAAS,OACpB,IAAI,SAAS,YAAY;AACvB,YAAW,SAAS;;AAGxB,MAAa,aAAa,UACxB,UAAU,QAAQ,UAAU;AAE9B,eAAsB,cAA6B;CACjD,MAAM,SAAS,MAAM;AACrB,OAAM,SAAS;;AAGjB,MAAa,qBAAqB,YAAY;CAC5C,MAAM,WAAW,MAAM;AACvB,OAAM,gBAAgB;AAEtB,SAAQ,KAAK,yBAAyB;;;;;ACZxC,eAAsB,gBACpB,YACiB;CAGjB,MAAM,iBAAiB,WAAW,WAAW,KAAK;AAClD,SAAQ,MAAM,yCAAyC,cAAc;AAErE,QAAO,MAAM;EAEX,MAAM,aAAa,IAAI;EACvB,MAAM,YAAY,MAAM,aAAa;EACrC,MAAM,UAAU,iBAAiB;AAC/B,cAAW;KACV;AAEH,MAAI;GACF,MAAM,WAAW,MAAM,MACrB,GAAG,gBAAgB,4BACnB;IACE,QAAQ;IACR,SAAS;IACT,MAAM,KAAK,UAAU;KACnB,WAAW;KACX,aAAa,WAAW;KACxB,YAAY;;IAEd,QAAQ,WAAW;;AAIvB,OAAI,CAAC,SAAS,IAAI;AAChB,UAAM,MAAM;AACZ,YAAQ,MAAM,gCAAgC,MAAM,SAAS;AAE7D;;GAGF,MAAM,OAAO,MAAM,SAAS;AAC5B,WAAQ,MAAM,kCAAkC;GAEhD,MAAM,EAAE,iBAAiB;AAEzB,OAAI,aACF,QAAO;OAEP,OAAM,MAAM;WAEP,OAAO;AACd,OAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACzD,YAAQ,MAAM;AACd,UAAM,MAAM;AACZ;;AAEF,SAAM;YACE;AACR,gBAAa;;;;;;;ACtDnB,IAAIC;AACJ,IAAI,mBAAmB;AAGvB,IAAIC;AACJ,IAAIC;AAGJ,SAAgB,yBAAyB;AACvC,SAAQ,MAAM;AAGd,KAAI,sBAAsB;AACxB,gBAAc;AACd,yBAAuB;;AAIzB,KAAI,eAAe;AACjB,sBAAoB,IAAI,UAAU;AAClC,kBAAgB;;AAGlB,KAAI,gBAAgB;AAClB,sBAAoB,IAAI,WAAW;AACnC,mBAAiB;;;AAIrB,MAAM,wBAAwB,GAAG,SAAS,MAAM,mBAAmB;AAEnE,MAAM,oBAAoB,UACxB,GAAG,UAAU,MAAM,mBAAmB;AAExC,MAAa,oBAAoB,YAAY;CAC3C,MAAM,EAAE,OAAO,eAAe,MAAM;AACpC,OAAM,eAAe;AAGrB,SAAQ,MAAM;AACd,KAAI,MAAM,UACR,SAAQ,KAAK,kBAAkB;CAGjC,MAAM,mBAAmB,aAAa,MAAM;CAE5C,MAAM,wBAAwB,OAC5B,aAAa,GACb,YAAY,KACZ,SAAS,gBACN;AACH,MAAI,kBAAkB;AACpB,WAAQ,MAAM;AACd;;AAGF,qBAAmB;AACnB,MAAI;AACF,QAAK,IAAI,UAAU,GAAG,WAAW,YAAY,UAC3C,KAAI;AACF,YAAQ,MACN,6BAA6B,OAAO,YAAY,QAAQ,GAAG,WAAW;IAExE,MAAM,EAAE,mBAAU,MAAM;AACxB,UAAM,eAAeC;AACrB,YAAQ,MAAM;AACd,QAAI,MAAM,UACR,SAAQ,KAAK,4BAA4BA;AAE3C;YACO,OAAO;IACd,MAAM,gBAAgB,YAAY;AAClC,YAAQ,MACN,4CAA4C,QAAQ,GAAG,WAAW,KAClE;AAGF,QAAI,eAAe;AACjB,aAAQ,MACN;AAEF;;IAIF,MAAM,QAAQ,YAAY,KAAK,IAAI,GAAG,UAAU;AAChD,YAAQ,MAAM,6BAA6B,MAAM;AACjD,UAAM,IAAI,SAAS,YAAY,WAAW,SAAS;;YAG/C;AACR,sBAAmB;;;AAKvB,wBAAuB,kBAAkB;AAEvC,wBAAsB,GAAG,KAAM,aAAa,OAAO,UAAU;AAC3D,WAAQ,MAAM,gDAAgD;;IAE/D;AAGH,qBAAoB;AAGpB,uBAAsB;AACpB,UAAQ,MACN;AAGF,wBAAsB,GAAG,KAAK,oBAAoB,OAAO,UAAU;AACjE,WAAQ,MACN,uDACA;;;AAKN,wBAAuB;AACrB,UAAQ,MAAM;;AAIhB,qBAAoB,GAAG,UAAU;AACjC,qBAAoB,GAAG,WAAW;;AAOpC,eAAsB,iBACpB,SACe;AACf,KAAI;EACF,MAAM,cAAc,MAAM;AAE1B,MAAI,eAAe,CAAC,SAAS,OAAO;AAClC,SAAM,cAAc;AACpB,OAAI,MAAM,UACR,SAAQ,KAAK,iBAAiB;AAEhC,SAAM;AAEN;;AAGF,UAAQ,KAAK;EACb,MAAM,WAAW,MAAM;AACvB,UAAQ,MAAM,yBAAyB;AAEvC,UAAQ,KACN,0BAA0B,SAAS,UAAU,OAAO,SAAS;EAG/D,MAAM,QAAQ,MAAM,gBAAgB;AACpC,QAAM,iBAAiB;AACvB,QAAM,cAAc;AAEpB,MAAI,MAAM,UACR,SAAQ,KAAK,iBAAiB;AAEhC,QAAM;UACC,OAAO;AACd,MAAI,iBAAiB,WAAW;AAC9B,WAAQ,MAAM,+BAA+B,MAAM,MAAM,SAAS;AAClE,SAAM;;AAGR,UAAQ,MAAM,+BAA+B;AAC7C,QAAM;;;AAIV,eAAe,UAAU;CACvB,MAAM,OAAO,MAAM;AACnB,SAAQ,KAAK,gBAAgB,KAAK;;;;;AClLpC,eAAsB,QAAQ,SAAwC;AACpE,KAAI,QAAQ,SAAS;AACnB,UAAQ,QAAQ;AAChB,UAAQ,KAAK;;AAGf,OAAM,YAAY,QAAQ;AAE1B,OAAM;AACN,OAAM,iBAAiB,EAAE,OAAO;AAChC,SAAQ,QAAQ,2BAA2B,MAAM;;AAGnD,MAAa,OAAO,cAAc;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;;CAEf,MAAM;EACJ,SAAS;GACP,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;;EAEf,cAAc;GACZ,MAAM;GACN,SAAS;GACT,aAAa;;;CAGjB,IAAI,EAAE,QAAQ;AACZ,SAAO,QAAQ;GACb,SAAS,KAAK;GACd,WAAW,KAAK;;;;;;;AC5CtB,MAAa,kBAAkB,YAA2C;CAExE,MAAM,aAAa,IAAI;CACvB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,UAAU,iBAAiB;AAC/B,aAAW;IACV;AAEH,KAAI;EACF,MAAM,WAAW,MAAM,MACrB,GAAG,oBAAoB,yBACvB;GACE,SAAS,cAAc;GACvB,QAAQ,WAAW;;AAIvB,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,UAAU,+BAA+B;AAGrD,SAAQ,MAAM,SAAS;WACf;AACR,eAAa;;;;;;ACjBjB,MAAa,aAAa,cAAc;CACtC,MAAM;EACJ,MAAM;EACN,aAAa;;CAEf,MAAM,MAAM;AACV,QAAM;AACN,QAAM;AACN,MAAI;GACF,MAAM,QAAQ,MAAM;GACpB,MAAM,UAAU,MAAM,gBAAgB;GACtC,MAAM,eAAe,QAAQ;GAC7B,MAAM,cAAc,eAAe,QAAQ;GAC3C,MAAM,qBACJ,eAAe,IAAK,cAAc,eAAgB,MAAM;GAC1D,MAAM,0BAA0B,QAAQ;GAGxC,SAAS,eAAe,MAAc,MAA+B;AACnE,QAAI,CAAC,KAAM,QAAO,GAAG,KAAK;IAC1B,MAAM,QAAQ,KAAK;IACnB,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,cAAc,QAAQ,IAAK,OAAO,QAAS,MAAM;IACvD,MAAM,mBAAmB,KAAK;AAC9B,WAAO,GAAG,KAAK,IAAI,KAAK,GAAG,MAAM,SAAS,YAAY,QAAQ,GAAG,UAAU,iBAAiB,QAAQ,GAAG;;GAGzG,MAAM,cAAc,YAAY,YAAY,GAAG,aAAa,SAAS,mBAAmB,QAAQ,GAAG,UAAU,wBAAwB,QAAQ,GAAG;GAChJ,MAAM,WAAW,eAAe,QAAQ,MAAM,gBAAgB;GAC9D,MAAM,kBAAkB,eACtB,eACA,MAAM,gBAAgB;AAGxB,WAAQ,IACN,wBAAwB,MAAM,aAAa,mBACtB,MAAM,iBAAiB,iBAEnC,YAAY,MACZ,SAAS,MACT;WAEJ,KAAK;AACZ,WAAQ,MAAM,kCAAkC;AAChD,WAAQ,KAAK;;;;;;;AC1BnB,eAAe,oBAAqC;AAClD,KAAI;EACF,MAAM,kBAAkB,IAAI,IAAI,mBAAmB,OAAO,KAAK,KAAK;EACpE,MAAM,cAAc,KAAK,MAAM,MAAM,GAAG,SAAS;AAGjD,SAAO,YAAY;SACb;AACN,SAAO;;;AAIX,SAAS,iBAAiB;CACxB,MAAM,QAAQ,OAAO,QAAQ;AAE7B,QAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,SAAS,QAAQ,IAAI,UAAU,QAAQ,QAAQ,MAAM;EACrD,UAAU,GAAG;EACb,MAAM,GAAG;;;AAIb,eAAe,mBAAqC;AAClD,KAAI;EACF,MAAM,QAAQ,MAAM,GAAG,KAAK,MAAM;AAClC,MAAI,CAAC,MAAM,SAAU,QAAO;EAE5B,MAAM,UAAU,MAAM,GAAG,SAAS,MAAM,mBAAmB;AAC3D,SAAO,QAAQ,OAAO,SAAS;SACzB;AACN,SAAO;;;AAIX,eAAe,eAAmC;CAChD,MAAM,CAAC,SAAS,eAAe,MAAM,QAAQ,IAAI,CAC/C,qBACA;AAGF,QAAO;EACL;EACA,SAAS;EACT,OAAO;GACL,SAAS,MAAM;GACf,mBAAmB,MAAM;;EAE3B;;;AAIJ,SAAS,oBAAoB,MAAuB;AAClD,SAAQ,KAAK;;WAEJ,KAAK,QAAQ;WACb,KAAK,QAAQ,KAAK,GAAG,KAAK,QAAQ,QAAQ,IAAI,KAAK,QAAQ,SAAS,GAAG,KAAK,QAAQ,KAAK;;;aAGvF,KAAK,MAAM,QAAQ;uBACT,KAAK,MAAM,kBAAkB;;gBAEpC,KAAK,cAAc,QAAQ;;AAG3C,SAAS,mBAAmB,MAAuB;AACjD,SAAQ,IAAI,KAAK,UAAU,MAAM,MAAM;;AAGzC,eAAsB,SAAS,SAAyC;CACtE,MAAM,YAAY,MAAM;AAExB,KAAI,QAAQ,KACV,oBAAmB;KAEnB,qBAAoB;;AAIxB,MAAa,QAAQ,cAAc;CACjC,MAAM;EACJ,MAAM;EACN,aAAa;;CAEf,MAAM,EACJ,MAAM;EACJ,MAAM;EACN,SAAS;EACT,aAAa;;CAGjB,IAAI,EAAE,QAAQ;AACZ,SAAO,SAAS,EACd,MAAM,KAAK;;;;;;ACnHjB,SAAS,WAAsB;CAC7B,MAAM,EAAE,UAAU,MAAM,QAAQC;AAEhC,KAAI,aAAa,SAAS;AACxB,MAAI;GACF,MAAM,UAAU,oDAAoD,KAAK;GACzE,MAAM,gBAAgB,SAAS,SAAS,EAAE,OAAO,UAAU;AAE3D,OAAI,cAAc,cAAc,SAAS,kBACvC,QAAO;UAEH;AACN,UAAO;;AAGT,SAAO;QACF;EACL,MAAM,YAAY,IAAI;AACtB,MAAI,WAAW;AACb,OAAI,UAAU,SAAS,OAAQ,QAAO;AACtC,OAAI,UAAU,SAAS,QAAS,QAAO;AACvC,OAAI,UAAU,SAAS,QAAS,QAAO;;AAGzC,SAAO;;;;;;;;;;AAWX,SAAgB,kBACd,SACA,eAAuB,IACf;CACR,MAAM,QAAQ;CACd,MAAM,kBAAkB,OAAO,QAAQ,SAAS,QAC7C,GAAG,WAAW,UAAU;CAG3B,IAAIC;AAEJ,SAAQ,OAAR;EACE,KAAK;AACH,kBAAe,gBACZ,KAAK,CAAC,KAAK,WAAW,QAAQ,IAAI,KAAK,SACvC,KAAK;AACR;EAEF,KAAK;AACH,kBAAe,gBACZ,KAAK,CAAC,KAAK,WAAW,OAAO,IAAI,GAAG,SACpC,KAAK;AACR;EAEF,KAAK;AACH,kBAAe,gBACZ,KAAK,CAAC,KAAK,WAAW,WAAW,IAAI,GAAG,SACxC,KAAK;AACR;EAEF,SAAS;GAEP,MAAM,cAAc,gBACjB,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,SAChC,KAAK;AACR,kBAAe,gBAAgB,SAAS,IAAI,UAAU,gBAAgB;AACtE;;;AAIJ,KAAI,gBAAgB,cAAc;EAChC,MAAM,YAAY,UAAU,QAAQ,QAAQ;AAC5C,SAAO,GAAG,eAAe,YAAY;;AAGvC,QAAO,gBAAgB;;;;;AClFzB,MAAa,gBAAgB,YAAY;CACvC,MAAM,WAAW,MAAM,QAAQ,OAAO,4BAA4B,EAChE,MAAM;AAGR,KAAI,CAAC,SACH,OAAM,IAAI,UACR,oBACA,SAAS,KAAK,EAAE,SAAS,sBAAsB,EAAE,QAAQ;;;;;ACL/D,eAAsB,eAAe,SAAc;AACjD,KAAIC,QAAM,qBAAqB,OAAW;CAE1C,MAAM,MAAM,KAAK;AAEjB,KAAI,CAACA,QAAM,sBAAsB;AAC/B,UAAM,uBAAuB;AAC7B;;CAGF,MAAM,kBAAkB,MAAMA,QAAM,wBAAwB;AAE5D,KAAI,iBAAiBA,QAAM,kBAAkB;AAC3C,UAAM,uBAAuB;AAC7B;;CAGF,MAAM,kBAAkB,KAAK,KAAKA,QAAM,mBAAmB;AAE3D,KAAI,CAACA,QAAM,eAAe;AACxB,UAAQ,KACN,qCAAqC,gBAAgB;AAEvD,QAAM,IAAI,UACR,uBACA,SAAS,KAAK,EAAE,SAAS,yBAAyB,EAAE,QAAQ;;CAIhE,MAAM,aAAa,kBAAkB;AACrC,SAAQ,KACN,+BAA+B,gBAAgB;AAEjD,OAAM,MAAM;AAEZ,SAAM,uBAAuB;AAC7B,SAAQ,KAAK;;;;;ACvCf,MAAa,iBAAiB,aAA6B;CACzD,MAAM,qBAAqB,SAAS,KAAK,YAAY;EACnD,IAAI,UAAU;AACd,MAAI,OAAO,QAAQ,YAAY,SAC7B,WAAU,QAAQ;WACT,MAAM,QAAQ,QAAQ,SAC/B,WAAU,QAAQ,QACf,QAAQ,SAAS,KAAK,SAAS,QAC/B,KAAK,SAAU,KAA0B,MACzC,KAAK;AAEV,SAAO;GAAE,GAAG;GAAS;;;CAGvB,IAAI,gBAAgB,mBAAmB,QAAQ,YAAY;AACzD,SAAO,QAAQ,SAAS;;CAE1B,IAAIC,iBAA4C;CAEhD,MAAM,cAAc,mBAAmB,GAAG;AAE1C,KAAI,aAAa,SAAS,aAAa;AACrC,kBAAgB,mBAAmB,MAAM,GAAG;AAC5C,mBAAiB,CAAC;;CAIpB,MAAM,cAAc,YAAY;CAEhC,MAAM,eAAe,YAAY;AAEjC,QAAO;EACL,OAAO;EACP,QAAQ;;;;;;;;;;;;;AC7BZ,SAAgB,eAAe,KAAqB;AAClD,QACE,IAEG,WAAW,wBAAwB,IAEnC,WAAW,mBAAmB,IAC9B,WAAW,gCAAgC,IAE3C,WAAW,iCAAiC,IAE5C,WAAW,0BAA0B,IACrC,WAAW,oBAAoB,IAC/B,WAAW,oBAAoB,IAE/B,WAAW,wDAAwD,IAEnE,WAAW,oBAAoB;;;;;AAOtC,SAAgB,gBAAmB,SAAe;AAChD,KAAI,OAAO,YAAY,SACrB,QAAO,eAAe;AAGxB,KAAI,MAAM,QAAQ,SAChB,QAAO,QAAQ,KAAK,SAAS,gBAAgB;AAG/C,KAAI,WAAW,OAAO,YAAY,UAAU;EAC1C,MAAM,YAAY;AAClB,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SACvC,CAAC,UAAkB,OAAO,gBAAgB;AAE7C,SAAO;;AAGT,QAAO;;;;;ACxCT,MAAa,wBAAwB,OACnC,YACG;AACH,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM;CAGzC,MAAM,mBAAmB,gBAAgB;CAEzC,MAAM,eAAe,iBAAiB,SAAS,MAC5C,MACC,OAAO,EAAE,YAAY,YAClB,EAAE,SAAS,MAAM,QAAMC,IAAE,SAAS;CAKzC,MAAM,cAAc,iBAAiB,SAAS,MAAM,QAClD,CAAC,aAAa,QAAQ,SAAS,IAAI;CAIrC,MAAMC,UAAkC;EACtC,GAAG,eAAe,OAAO;EACzB,eAAe,cAAc,UAAU;;CAIzC,MAAM,aAAa,IAAI;CACvB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,UAAU,iBAAiB;AAC/B,aAAW;IACV;AAEH,KAAI;EACF,MAAM,EAAE,YAAY,SAAS,iBAAiB,SAAS,MAAM,QAAQ,GAAG,eAAe,OAAO,oBAAoB;GAChH,QAAQ;GACR;GACA,MAAM,KAAK,UAAU;GACrB,QAAQ,WAAW;GAEnB,gBAAgB;GAChB,aAAa,YAAY;GACzB,gBAAgB;;EAIlB,MAAM,WAAW,IAAI,SAAS,MAAM;GAClC,QAAQ;GACR,SAAS;;AAGX,MAAI,CAAC,SAAS,IAAI;AAChB,WAAQ,MAAM,qCAAqC;AACnD,SAAM,IAAI,UAAU,qCAAqC;;AAG3D,MAAI,iBAAiB,OACnB,QAAO,OAAO;AAGhB,SAAQ,MAAM,SAAS;WACf;AACR,eAAa;;;;;;ACvDjB,eAAsBC,mBAAiB,GAAY;AACjD,OAAM,eAAe;CAErB,IAAI,UAAU,MAAM,EAAE,IAAI;AAC1B,SAAQ,MAAM,oBAAoB,KAAK,UAAU,SAAS,MAAM;AAEhE,SAAQ,KAAK,wBAAwB,cAAc,QAAQ;AAE3D,KAAI,MAAM,cAAe,OAAM;AAE/B,KAAI,UAAU,QAAQ,aAAa;EACjC,MAAM,gBAAgB,MAAM,QAAQ,KAAK,MACtC,UAAU,MAAM,OAAO,QAAQ;AAGlC,YAAU;GACR,GAAG;GACH,YAAY,eAAe,aAAa,OAAO;;AAEjD,UAAQ,MAAM,sBAAsB,KAAK,UAAU,QAAQ;;CAG7D,MAAM,WAAW,MAAM,sBAAsB;AAE7C,KAAIC,iBAAe,WAAW;AAC5B,UAAQ,MAAM,2BAA2B,KAAK,UAAU;AACxD,SAAO,EAAE,KAAK;;AAGhB,SAAQ,MAAM;AACd,QAAO,UAAU,GAAG,OAAO,WAAW;AACpC,aAAW,MAAM,SAAS,UAAU;AAClC,WAAQ,MAAM,oBAAoB,KAAK,UAAU;AACjD,SAAM,OAAO,SAAS;;;;AAK5B,MAAMA,oBACJ,aACuC,OAAO,OAAO,UAAU;;;;AClDjE,MAAa,mBAAmB,IAAI;AAEpC,iBAAiB,KAAK,KAAK,OAAO,MAAM;AACtC,KAAI;AACF,SAAO,MAAMC,mBAAiB;UACvB,OAAO;AACd,SAAO,MAAM,aAAa,GAAG;;;;;;ACRjC,MAAa,mBAAmB,OAAO,YAA8B;AACnE,KAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM;CAGzC,MAAM,aAAa,IAAI;CACvB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,UAAU,iBAAiB;AAC/B,aAAW;IACV;AAEH,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,eAAe,OAAO,cAAc;GAClE,QAAQ;GACR,SAAS,eAAe;GACxB,MAAM,KAAK,UAAU;GACrB,QAAQ,WAAW;;AAGrB,MAAI,CAAC,SAAS,GACZ,OAAM,IAAI,UAAU,+BAA+B;AAErD,SAAQ,MAAM,SAAS;WACf;AACR,eAAa;;;;;;ACnBjB,MAAa,kBAAkB,IAAI;AAEnC,gBAAgB,KAAK,KAAK,OAAO,MAAM;AACrC,KAAI;EACF,MAAM,SAAS,MAAM,EAAE,IAAI;EAC3B,MAAM,WAAW,MAAM,iBAAiB;AAExC,SAAO,EAAE,KAAK;UACP,OAAO;AACd,SAAO,MAAM,aAAa,GAAG;;;;;;ACfjC,SAAgB,+BACd,cACkC;AAClC,KAAI,iBAAiB,KACnB,QAAO;CAET,MAAM,gBAAgB;EACpB,MAAM;EACN,QAAQ;EACR,YAAY;EACZ,gBAAgB;;AAElB,QAAO,cAAc;;;;;ACcvB,SAAgB,kBACd,SACwB;AACxB,QAAO;EACL,OAAO,mBAAmB,QAAQ;EAClC,UAAU,mCACR,QAAQ,UACR,QAAQ;EAEV,YAAY,QAAQ;EACpB,MAAM,QAAQ;EACd,QAAQ,QAAQ;EAChB,aAAa,QAAQ;EACrB,OAAO,QAAQ;EACf,MAAM,QAAQ,UAAU;EACxB,OAAO,gCAAgC,QAAQ;EAC/C,aAAa,qCAAqC,QAAQ;;;AAI9D,SAAS,mBAAmB,OAAuB;AAEjD,KAAI,MAAM,WAAW,oBACnB,QAAO,MAAM,QAAQ,uBAAuB;UACnC,MAAM,WAAW,gBAC1B,QAAO,MAAM,QAAQ,qBAAqB;AAE5C,QAAO;;AAGT,SAAS,mCACP,mBACA,QACgB;CAChB,MAAM,iBAAiB,mBAAmB;CAE1C,MAAM,gBAAgB,kBAAkB,SAAS,YAC/C,QAAQ,SAAS,SACf,kBAAkB,WAClB,uBAAuB;AAG3B,QAAO,CAAC,GAAG,gBAAgB,GAAG;;AAGhC,SAAS,mBACP,QACgB;AAChB,KAAI,CAAC,OACH,QAAO;AAGT,KAAI,OAAO,WAAW,SACpB,QAAO,CAAC;EAAE,MAAM;EAAU,SAAS;;MAC9B;EACL,MAAM,aAAa,OAAO,KAAK,UAAU,MAAM,MAAM,KAAK;AAC1D,SAAO,CAAC;GAAE,MAAM;GAAU,SAAS;;;;AAIvC,SAAS,kBAAkB,SAA+C;CACxE,MAAMC,cAA8B;AAEpC,KAAI,MAAM,QAAQ,QAAQ,UAAU;EAClC,MAAM,mBAAmB,QAAQ,QAAQ,QACtC,UACC,MAAM,SAAS;EAEnB,MAAM,cAAc,QAAQ,QAAQ,QACjC,UAAU,MAAM,SAAS;AAI5B,OAAK,MAAM,SAAS,iBAClB,aAAY,KAAK;GACf,MAAM;GACN,cAAc,MAAM;GACpB,SAAS,WAAW,MAAM;;AAI9B,MAAI,YAAY,SAAS,EACvB,aAAY,KAAK;GACf,MAAM;GACN,SAAS,WAAW;;OAIxB,aAAY,KAAK;EACf,MAAM;EACN,SAAS,WAAW,QAAQ;;AAIhC,QAAO;;AAGT,SAAS,uBACP,SACgB;AAChB,KAAI,CAAC,MAAM,QAAQ,QAAQ,SACzB,QAAO,CACL;EACE,MAAM;EACN,SAAS,WAAW,QAAQ;;CAKlC,MAAM,gBAAgB,QAAQ,QAAQ,QACnC,UAA0C,MAAM,SAAS;CAG5D,MAAM,aAAa,QAAQ,QAAQ,QAChC,UAAuC,MAAM,SAAS;CAGzD,MAAM,iBAAiB,QAAQ,QAAQ,QACpC,UAA2C,MAAM,SAAS;CAI7D,MAAM,iBAAiB,CACrB,GAAG,WAAW,KAAK,MAAM,EAAE,OAC3B,GAAG,eAAe,KAAK,MAAM,EAAE,WAC/B,KAAK;AAEP,QAAO,cAAc,SAAS,IAC1B,CACE;EACE,MAAM;EACN,SAAS,kBAAkB;EAC3B,YAAY,cAAc,KAAK,aAAa;GAC1C,IAAI,QAAQ;GACZ,MAAM;GACN,UAAU;IACR,MAAM,QAAQ;IACd,WAAW,KAAK,UAAU,QAAQ;;;MAK1C,CACE;EACE,MAAM;EACN,SAAS,WAAW,QAAQ;;;AAKtC,SAAS,WACP,SAGoC;AACpC,KAAI,OAAO,YAAY,SACrB,QAAO;AAET,KAAI,CAAC,MAAM,QAAQ,SACjB,QAAO;CAGT,MAAM,WAAW,QAAQ,MAAM,UAAU,MAAM,SAAS;AACxD,KAAI,CAAC,SACH,QAAO,QACJ,QACE,UACC,MAAM,SAAS,UAAU,MAAM,SAAS,YAE3C,KAAK,UAAW,MAAM,SAAS,SAAS,MAAM,OAAO,MAAM,UAC3D,KAAK;CAGV,MAAMC,eAAmC;AACzC,MAAK,MAAM,SAAS,QAClB,SAAQ,MAAM,MAAd;EACE,KAAK;AACH,gBAAa,KAAK;IAAE,MAAM;IAAQ,MAAM,MAAM;;AAE9C;EAEF,KAAK;AACH,gBAAa,KAAK;IAAE,MAAM;IAAQ,MAAM,MAAM;;AAE9C;EAEF,KAAK;AACH,gBAAa,KAAK;IAChB,MAAM;IACN,WAAW,EACT,KAAK,QAAQ,MAAM,OAAO,WAAW,UAAU,MAAM,OAAO;;AAIhE;;AAKN,QAAO;;AAGT,SAAS,gCACP,gBACyB;AACzB,KAAI,CAAC,eACH,QAAO;AAET,QAAO,eAAe,KAAK,UAAU;EACnC,MAAM;EACN,UAAU;GACR,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,YAAY,KAAK;;;;AAKvB,SAAS,qCACP,qBACuC;AACvC,KAAI,CAAC,oBACH,QAAO;AAGT,SAAQ,oBAAoB,MAA5B;EACE,KAAK,OACH,QAAO;EAET,KAAK,MACH,QAAO;EAET,KAAK;AACH,OAAI,oBAAoB,KACtB,QAAO;IACL,MAAM;IACN,UAAU,EAAE,MAAM,oBAAoB;;AAG1C,UAAO;EAET,KAAK,OACH,QAAO;EAET,QACE,QAAO;;;AAOb,SAAgB,qBACd,UACmB;CAEnB,MAAMC,gBAA2C;CACjD,MAAMC,mBAAiD;CACvD,IAAIC,aACF;AACF,cAAa,SAAS,QAAQ,IAAI,iBAAiB;AAGnD,MAAK,MAAM,UAAU,SAAS,SAAS;EACrC,MAAM,aAAa,uBAAuB,OAAO,QAAQ;EACzD,MAAM,gBAAgB,0BAA0B,OAAO,QAAQ;AAE/D,gBAAc,KAAK,GAAG;AACtB,mBAAiB,KAAK,GAAG;AAGzB,MAAI,OAAO,kBAAkB,gBAAgB,eAAe,OAC1D,cAAa,OAAO;;AAMxB,QAAO;EACL,IAAI,SAAS;EACb,MAAM;EACN,MAAM;EACN,OAAO,SAAS;EAChB,SAAS,CAAC,GAAG,eAAe,GAAG;EAC/B,aAAa,+BAA+B;EAC5C,eAAe;EACf,OAAO;GACL,cAAc,SAAS,OAAO,iBAAiB;GAC/C,eAAe,SAAS,OAAO,qBAAqB;;;;AAK1D,SAAS,uBACP,gBAC2B;AAC3B,KAAI,OAAO,mBAAmB,SAC5B,QAAO,CAAC;EAAE,MAAM;EAAQ,MAAM;;AAGhC,KAAI,MAAM,QAAQ,gBAChB,QAAO,eACJ,QAAQ,SAA2B,KAAK,SAAS,QACjD,KAAK,UAAU;EAAE,MAAM;EAAQ,MAAM,KAAK;;AAG/C,QAAO;;AAGT,SAAS,0BACP,WAC8B;AAC9B,KAAI,CAAC,UACH,QAAO;AAET,QAAO,UAAU,KAAK,cAAc;EAClC,MAAM;EACN,IAAI,SAAS;EACb,MAAM,SAAS,SAAS;EACxB,OAAO,KAAK,MAAM,SAAS,SAAS;;;;;;ACnVxC,SAAS,gBAAgB,SAAsC;AAC7D,KAAI,CAACC,QAAM,iBACT,QAAO;AAGT,QAAO,OAAO,OAAOA,QAAM,WAAW,MACnC,OAAO,GAAG,wBAAwBA,QAAM;;AAK7C,SAAgB,gCACd,OACA,SACiC;CACjC,MAAMC,WAA0C;AAEhD,KAAI,MAAM,QAAQ,WAAW,EAC3B,QAAOC;CAGT,MAAM,SAAS,MAAM,QAAQ;CAC7B,MAAM,EAAE,UAAU;AAElB,KAAI,CAACF,QAAM,kBAAkB;AAC3B,WAAO,KAAK;GACV,MAAM;GACN,SAAS;IACP,IAAI,MAAM;IACV,MAAM;IACN,MAAM;IACN,SAAS;IACT,OAAO,MAAM;IACb,aAAa;IACb,eAAe;IACf,OAAO;KACL,cAAc,MAAM,OAAO,iBAAiB;KAC5C,eAAe;;;;AAIrB,UAAM,mBAAmB;;AAG3B,KAAI,MAAM,SAAS;AACjB,MAAI,gBAAgBA,UAAQ;AAE1B,YAAO,KAAK;IACV,MAAM;IACN,OAAOA,QAAM;;AAEf,WAAM;AACN,WAAM,mBAAmB;;AAG3B,MAAI,CAACA,QAAM,kBAAkB;AAC3B,YAAO,KAAK;IACV,MAAM;IACN,OAAOA,QAAM;IACb,eAAe;KACb,MAAM;KACN,MAAM;;;AAGV,WAAM,mBAAmB;;AAG3B,WAAO,KAAK;GACV,MAAM;GACN,OAAOA,QAAM;GACb,OAAO;IACL,MAAM;IACN,MAAM,MAAM;;;;AAKlB,KAAI,MAAM,WACR,MAAK,MAAM,YAAY,MAAM,YAAY;AACvC,MAAI,SAAS,MAAM,SAAS,UAAU,MAAM;AAE1C,OAAIA,QAAM,kBAAkB;AAE1B,aAAO,KAAK;KACV,MAAM;KACN,OAAOA,QAAM;;AAEf,YAAM;AACN,YAAM,mBAAmB;;GAG3B,MAAM,sBAAsBA,QAAM;AAClC,WAAM,UAAU,SAAS,SAAS;IAChC,IAAI,SAAS;IACb,MAAM,SAAS,SAAS;IACxB;;AAGF,YAAO,KAAK;IACV,MAAM;IACN,OAAO;IACP,eAAe;KACb,MAAM;KACN,IAAI,SAAS;KACb,MAAM,SAAS,SAAS;KACxB,OAAO;;;AAGX,WAAM,mBAAmB;;AAG3B,MAAI,SAAS,UAAU,WAAW;GAChC,MAAM,eAAeA,QAAM,UAAU,SAAS;AAG9C,OAAI,aACF,UAAO,KAAK;IACV,MAAM;IACN,OAAO,aAAa;IACpB,OAAO;KACL,MAAM;KACN,cAAc,SAAS,SAAS;;;;;AAQ5C,KAAI,OAAO,eAAe;AACxB,MAAIA,QAAM,kBAAkB;AAC1B,YAAO,KAAK;IACV,MAAM;IACN,OAAOA,QAAM;;AAEf,WAAM,mBAAmB;;AAG3B,WAAO,KACL;GACE,MAAM;GACN,OAAO;IACL,aAAa,+BAA+B,OAAO;IACnD,eAAe;;GAEjB,OAAO;IACL,cAAc,MAAM,OAAO,iBAAiB;IAC5C,eAAe,MAAM,OAAO,qBAAqB;IACjD,GAAI,MAAM,OAAO,uBAAuB,kBAClC,UAAa,EACjB,yBACE,MAAM,MAAM,sBAAsB;;KAI1C,EACE,MAAM;;AAKZ,QAAOE;;;;;ACjJT,eAAsB,iBAAiB,GAAY;AACjD,OAAM,eAAe;CAErB,MAAM,mBAAmB,MAAM,EAAE,IAAI;AACrC,SAAQ,MAAM,8BAA8B,KAAK,UAAU;CAE3D,MAAM,gBAAgB,kBAAkB;AACxC,SAAQ,MACN,sCACA,KAAK,UAAU;AAGjB,KAAI,MAAM,cACR,OAAM;CAGR,MAAM,WAAW,MAAM,sBAAsB;AAE7C,KAAI,eAAe,WAAW;AAC5B,UAAQ,MACN,wCACA,KAAK,UAAU,UAAU,MAAM;EAEjC,MAAM,oBAAoB,qBAAqB;AAC/C,UAAQ,MACN,kCACA,KAAK,UAAU;AAEjB,SAAO,EAAE,KAAK;;AAGhB,SAAQ,MAAM;AACd,QAAO,UAAU,GAAG,OAAO,WAAW;EACpC,MAAMC,cAAoC;GACxC,kBAAkB;GAClB,mBAAmB;GACnB,kBAAkB;GAClB,WAAW;;AAGb,aAAW,MAAM,YAAY,UAAU;AACrC,WAAQ,MAAM,6BAA6B,KAAK,UAAU;AAC1D,OAAI,SAAS,SAAS,SACpB;AAGF,OAAI,CAAC,SAAS,KACZ;GAGF,MAAM,QAAQ,KAAK,MAAM,SAAS;GAClC,MAAMC,WAAS,gCAAgC,OAAO;AAEtD,QAAK,MAAM,SAASA,UAAQ;AAC1B,YAAQ,MAAM,+BAA+B,KAAK,UAAU;AAC5D,UAAM,OAAO,SAAS;KACpB,OAAO,MAAM;KACb,MAAM,KAAK,UAAU;;;;;;AAO/B,MAAM,kBACJ,aACuC,OAAO,OAAO,UAAU;;;;ACpFjE,MAAa,gBAAgB,IAAI;AAEjC,cAAc,KAAK,KAAK,OAAO,MAAM;AACnC,KAAI;AACF,SAAO,MAAM,iBAAiB;UACvB,OAAO;AACd,SAAO,MAAM,aAAa,GAAG;;;;;;ACNjC,MAAa,cAAc,IAAI;AAE/B,YAAY,IAAI,KAAK,OAAO,MAAM;AAChC,KAAI;AACF,MAAI,CAAC,MAAM,OAET,OAAM;EAGR,MAAM,SAAS,MAAM,QAAQ,KAAK,KAAK,WAAW;GAChD,IAAI,MAAM;GACV,QAAQ;GACR,MAAM;GACN,SAAS;GACT,6BAAY,IAAI,KAAK,IAAG;GACxB,UAAU,MAAM;GAChB,cAAc,MAAM;;AAGtB,SAAO,EAAE,KAAK;GACZ,QAAQ;GACR,MAAM;GACN,UAAU;;UAEL,OAAO;AACd,SAAO,MAAM,aAAa,GAAG;;;;;;AC3BjC,MAAa,aAAa,IAAI;AAE9B,WAAW,IAAI,MAAM,MAAM;AACzB,KAAI;AACF,SAAO,EAAE,KAAK,EACZ,OAAO,MAAM;UAER,OAAO;AACd,UAAQ,MAAM,yBAAyB;AACvC,SAAO,EAAE,KAAK;GAAE,OAAO;GAAyB,OAAO;KAAQ;;;;;;ACTnE,MAAa,aAAa,IAAI;AAE9B,WAAW,IAAI,KAAK,OAAO,MAAM;AAC/B,KAAI;EACF,MAAM,QAAQ,MAAM;AACpB,SAAO,EAAE,KAAK;UACP,OAAO;AACd,UAAQ,MAAM,iCAAiC;AAC/C,SAAO,EAAE,KAAK,EAAE,OAAO,mCAAmC;;;;;;ACD9D,MAAa,SAAS,IAAI;AAE1B,OAAO,IAAI;AACX,OAAO,IAAI;AAEX,OAAO,IAAI,MAAM,MAAM,EAAE,KAAK;AAE9B,OAAO,MAAM,qBAAqB;AAClC,OAAO,MAAM,WAAW;AACxB,OAAO,MAAM,eAAe;AAC5B,OAAO,MAAM,UAAU;AACvB,OAAO,MAAM,UAAU;AAGvB,OAAO,MAAM,wBAAwB;AACrC,OAAO,MAAM,cAAc;AAC3B,OAAO,MAAM,kBAAkB;AAG/B,OAAO,MAAM,gBAAgB;AAC7B,OAAO,KAAK,8BAA8B,MAAM,EAAE,KAAK,EAAE,cAAc;;;;ACTvE,MAAMC,mBAAsD;AAG5D,SAAS,wBAAwB;CAC/B,MAAM,UAAU,YAAY;AAC1B,UAAQ,KAAK;AAGb,OAAK,MAAM,aAAa,iBACtB,KAAI;AACF,SAAM;WACC,OAAO;AACd,WAAQ,MAAM,yBAAyB;;AAI3C,UAAQ,KAAK;AACb,YAAQ,KAAK;;AAIf,WAAQ,GAAG,UAAU;AACrB,WAAQ,GAAG,WAAW;AAGtB,WAAQ,GAAG,sBAAsB,UAAU;AACzC,UAAQ,MAAM,uBAAuB;AACrC,YAAU,cAAcC,UAAQ,KAAK;;AAGvC,WAAQ,GAAG,uBAAuB,QAAQ,YAAY;AACpD,UAAQ,MAAM,mCAAmC,SAAS,WAAW;AACrE,YAAU,cAAcA,UAAQ,KAAK;;;AAoBzC,eAAsB,UAAU,SAA0C;AAExE;AAGA,kBAAiB,WACT;AACJ,UAAQ,MAAM;AACd,sBAAoB;UAEhB;AACJ,UAAQ,MAAM;AACd;;AAIJ,KAAI,QAAQ,SAAS;AACnB,UAAQ,QAAQ;AAChB,UAAQ,KAAK;;AAGf,OAAM,cAAc,QAAQ;AAC5B,KAAI,QAAQ,gBAAgB,aAC1B,SAAQ,KAAK,SAAS,QAAQ,YAAY;AAG5C,OAAM,gBAAgB,QAAQ;AAC9B,OAAM,mBAAmB,QAAQ;AACjC,OAAM,gBAAgB,QAAQ;AAC9B,OAAM,YAAY,QAAQ;AAC1B,OAAM,YAAY,QAAQ;AAC1B,OAAM,aAAa,UAAU,CAAC,QAAQ;AAEtC,OAAM;AACN,OAAM;AAEN,KAAI,QAAQ,aAAa;AACvB,QAAM,cAAc,QAAQ;AAC5B,UAAQ,KAAK;OAEb,OAAM;AAGR,OAAM;AACN,OAAM;AAEN,SAAQ,KACN,uBAAuB,MAAM,QAAQ,KAAK,KAAK,UAAU,KAAK,MAAM,MAAM,KAAK;CAGjF,MAAM,YAAY,oBAAoB,QAAQ;AAE9C,KAAI,QAAQ,YAAY;AACtB,YAAU,MAAM,QAAQ;EAExB,IAAIC;EACJ,IAAIC;AAGJ,MAAI,QAAQ,SAAS,QAAQ,YAAY;GAEvC,MAAM,oBAAoB,MAAM,OAAO,KAAK,KAAK,UAAU,MAAM;AAEjE,OAAI,CAAC,kBAAkB,SAAS,QAAQ,QAAQ;AAC9C,YAAQ,MAAM,kBAAkB,QAAQ;AACxC,YAAQ,KAAK,uBAAuB,kBAAkB,KAAK;AAC3D,cAAQ,KAAK;;AAGf,OAAI,CAAC,kBAAkB,SAAS,QAAQ,aAAa;AACnD,YAAQ,MAAM,wBAAwB,QAAQ;AAC9C,YAAQ,KAAK,uBAAuB,kBAAkB,KAAK;AAC3D,cAAQ,KAAK;;AAGf,mBAAgB,QAAQ;AACxB,wBAAqB,QAAQ;AAC7B,WAAQ,KAAK,gBAAgB;AAC7B,WAAQ,KAAK,sBAAsB;aAC1B,QAAQ,SAAS,QAAQ,YAAY;AAE9C,WAAQ,MACN;AAEF,aAAQ,KAAK;SACR;AAEL,mBAAgB,MAAM,QAAQ,OAC5B,0CACA;IACE,MAAM;IACN,SAAS,MAAM,OAAO,KAAK,KAAK,UAAU,MAAM;;AAIpD,wBAAqB,MAAM,QAAQ,OACjC,gDACA;IACE,MAAM;IACN,SAAS,MAAM,OAAO,KAAK,KAAK,UAAU,MAAM;;;EAKtD,MAAM,UAAU,kBACd;GACE,oBAAoB;GACpB,sBAAsB;GACtB,iBAAiB;GACjB,4BAA4B;KAE9B;AAGF,MAAI;AACF,aAAU,UAAU;AACpB,WAAQ,QAAQ;UACV;AACN,WAAQ,KACN;AAEF,WAAQ,IAAI;;;AAIhB,SAAQ,IACN,oEAAoE,UAAU;AAGhF,OAAM;EACJ,OAAO,OAAO;EACd,MAAM,QAAQ;;;AAIlB,MAAa,QAAQ,cAAc;CACjC,MAAM;EACJ,MAAM;EACN,aAAa;;CAEf,MAAM;EACJ,MAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;;EAEf,SAAS;GACP,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;;EAEf,gBAAgB;GACd,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;;EAEf,QAAQ;GACN,MAAM;GACN,SAAS;GACT,aAAa;;EAEf,cAAc;GACZ,OAAO;GACP,MAAM;GACN,aAAa;;EAEf,MAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,aACE;;EAEJ,gBAAgB;GACd,OAAO;GACP,MAAM;GACN,aACE;;EAEJ,eAAe;GACb,OAAO;GACP,MAAM;GACN,SAAS;GACT,aACE;;EAEJ,OAAO;GACL,OAAO;GACP,MAAM;GACN,aAAa;;EAEf,eAAe;GACb,OAAO;GACP,MAAM;GACN,aACE;;EAEJ,cAAc;GACZ,MAAM;GACN,SAAS;GACT,aAAa;;EAEf,SAAS;GACP,OAAO;GACP,MAAM;GACN,aAAa;;EAEf,mCAAmC;GACjC,MAAM;GACN,SAAS;GACT,aACE;;;CAGN,IAAI,EAAE,QAAQ;EACZ,MAAM,eAAe,KAAK;EAC1B,MAAM,YAEJ,iBAAiB,SAAY,SAAY,OAAO,SAAS,cAAc;EAEzE,MAAM,aAAa,KAAK;EACxB,MAAM,UAEJ,eAAe,SAAY,OAAS,OAAO,SAAS,YAAY;AAElE,SAAO,UAAU;GACf,MAAM,OAAO,SAAS,KAAK,MAAM;GACjC,SAAS,KAAK;GACd,aAAa,KAAK;GAClB,QAAQ,KAAK;GACb;GACA,eAAe,KAAK;GACpB,aAAa,KAAK;GAClB,YAAY,KAAK;GACjB,OAAO,KAAK;GACZ,YAAY,KAAK;GACjB,WAAW,KAAK;GAChB;GACA,+BAA+B,KAAK;;;;;;;AClT1C,MAAM,OAAO,cAAc;CACzB,MAAM;EACJ,MAAM;EACN,aACE;;CAEJ,aAAa;EAAE;EAAM;EAAO,eAAe;EAAY;;;AAGzD,MAAM,QAAQ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "copilot-api-node20",
3
- "version": "0.5.14-node20",
3
+ "version": "0.6.0",
4
4
  "description": "Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code! (Node v20+ fork)",
5
5
  "keywords": [
6
6
  "proxy",
@@ -48,7 +48,8 @@
48
48
  "gpt-tokenizer": "^3.0.1",
49
49
  "hono": "^4.9.4",
50
50
  "srvx": "^0.6.0",
51
- "tiny-invariant": "^1.3.3"
51
+ "tiny-invariant": "^1.3.3",
52
+ "undici": "^7.16.0"
52
53
  },
53
54
  "devDependencies": {
54
55
  "@echristian/eslint-config": "^0.0.53",