copilot-api-plus 1.2.3 → 1.2.5

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.
@@ -1,30 +1,61 @@
1
- import { t as HTTPError } from "./error-CvwUkoEo.js";
2
- import { a as GITHUB_BASE_URL, c as copilotHeaders, i as GITHUB_APP_SCOPES, l as githubHeaders, n as state, o as GITHUB_CLIENT_ID, r as GITHUB_API_BASE_URL, s as copilotBaseUrl, t as getGitHubUser, u as standardHeaders } from "./get-user-BT7hEyDN.js";
3
1
  import consola from "consola";
4
2
  import { randomUUID } from "node:crypto";
5
3
  import fs from "node:fs/promises";
6
4
  import os from "node:os";
7
5
  import path from "node:path";
8
- //#region src/lib/paths.ts
9
- const APP_DIR = path.join(os.homedir(), ".local", "share", "copilot-api-plus");
10
- const PATHS = {
11
- APP_DIR,
12
- DATA_DIR: APP_DIR,
13
- GITHUB_TOKEN_PATH: path.join(APP_DIR, "github_token"),
14
- ACCOUNTS_PATH: path.join(APP_DIR, "accounts.json")
6
+ //#region src/lib/api-config.ts
7
+ const standardHeaders = () => ({
8
+ "content-type": "application/json",
9
+ accept: "application/json"
10
+ });
11
+ const COPILOT_VERSION = "0.38.2";
12
+ const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
13
+ const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
14
+ const API_VERSION = "2025-10-01";
15
+ const copilotBaseUrl = (source) => {
16
+ if (source.copilotApiEndpoint) return source.copilotApiEndpoint;
17
+ return source.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${source.accountType}.githubcopilot.com`;
18
+ };
19
+ const copilotHeaders = (source, vision = false) => {
20
+ const headers = {
21
+ Authorization: `Bearer ${source.copilotToken}`,
22
+ "content-type": standardHeaders()["content-type"],
23
+ "copilot-integration-id": "vscode-chat",
24
+ "editor-version": `vscode/${source.vsCodeVersion}`,
25
+ "editor-plugin-version": EDITOR_PLUGIN_VERSION,
26
+ "user-agent": USER_AGENT,
27
+ "openai-intent": "conversation-agent",
28
+ "x-interaction-type": "conversation-agent",
29
+ "x-agent-task-id": randomUUID(),
30
+ "x-github-api-version": API_VERSION,
31
+ "x-request-id": randomUUID(),
32
+ "x-vscode-user-agent-library-version": "electron-fetch"
33
+ };
34
+ if (vision) headers["copilot-vision-request"] = "true";
35
+ return headers;
36
+ };
37
+ const GITHUB_API_BASE_URL = "https://api.github.com";
38
+ const githubHeaders = (source) => ({
39
+ ...standardHeaders(),
40
+ authorization: `token ${source.githubToken}`,
41
+ "editor-version": `vscode/${source.vsCodeVersion}`,
42
+ "editor-plugin-version": EDITOR_PLUGIN_VERSION,
43
+ "user-agent": USER_AGENT,
44
+ "x-github-api-version": API_VERSION,
45
+ "x-vscode-user-agent-library-version": "electron-fetch"
46
+ });
47
+ const GITHUB_BASE_URL = "https://github.com";
48
+ const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
49
+ const GITHUB_APP_SCOPES = ["read:user"].join(" ");
50
+ //#endregion
51
+ //#region src/lib/state.ts
52
+ const state = {
53
+ accountType: "individual",
54
+ manualApprove: false,
55
+ rateLimitWait: false,
56
+ showToken: false,
57
+ multiAccountEnabled: false
15
58
  };
16
- async function ensurePaths() {
17
- await fs.mkdir(PATHS.APP_DIR, { recursive: true });
18
- await ensureFile(PATHS.GITHUB_TOKEN_PATH);
19
- }
20
- async function ensureFile(filePath) {
21
- try {
22
- await fs.access(filePath, fs.constants.W_OK);
23
- } catch {
24
- await fs.writeFile(filePath, "");
25
- await fs.chmod(filePath, 384);
26
- }
27
- }
28
59
  //#endregion
29
60
  //#region src/services/copilot/get-models.ts
30
61
  const getModels = async () => {
@@ -120,6 +151,68 @@ function findModel(modelName) {
120
151
  }
121
152
  }
122
153
  //#endregion
154
+ //#region src/lib/error.ts
155
+ var HTTPError = class extends Error {
156
+ response;
157
+ constructor(message, response) {
158
+ super(message);
159
+ this.response = response;
160
+ }
161
+ };
162
+ async function forwardError(c, error) {
163
+ if (error instanceof HTTPError) {
164
+ let errorText;
165
+ try {
166
+ errorText = await error.response.text();
167
+ } catch {
168
+ errorText = error.message;
169
+ }
170
+ if (error.response.status === 400) {} else {
171
+ let errorJson;
172
+ try {
173
+ errorJson = JSON.parse(errorText);
174
+ } catch {
175
+ errorJson = errorText;
176
+ }
177
+ consola.warn(`Error occurred: ${rootCause(error)}`);
178
+ consola.debug("HTTP error:", errorJson);
179
+ }
180
+ return c.json({ error: {
181
+ message: errorText,
182
+ type: "error"
183
+ } }, error.response.status);
184
+ }
185
+ const message = error.message || String(error);
186
+ const cause = error.cause;
187
+ if (cause) consola.error(`${message}: ${cause.message}`);
188
+ else consola.error(message);
189
+ return c.json({ error: {
190
+ message: error.message,
191
+ type: "error"
192
+ } }, 500);
193
+ }
194
+ //#endregion
195
+ //#region src/lib/paths.ts
196
+ const APP_DIR = path.join(os.homedir(), ".local", "share", "copilot-api-plus");
197
+ const PATHS = {
198
+ APP_DIR,
199
+ DATA_DIR: APP_DIR,
200
+ GITHUB_TOKEN_PATH: path.join(APP_DIR, "github_token"),
201
+ ACCOUNTS_PATH: path.join(APP_DIR, "accounts.json")
202
+ };
203
+ async function ensurePaths() {
204
+ await fs.mkdir(PATHS.APP_DIR, { recursive: true });
205
+ await ensureFile(PATHS.GITHUB_TOKEN_PATH);
206
+ }
207
+ async function ensureFile(filePath) {
208
+ try {
209
+ await fs.access(filePath, fs.constants.W_OK);
210
+ } catch {
211
+ await fs.writeFile(filePath, "");
212
+ await fs.chmod(filePath, 384);
213
+ }
214
+ }
215
+ //#endregion
123
216
  //#region src/services/github/get-copilot-token.ts
124
217
  /**
125
218
  * Fetch a short-lived Copilot JWT from the GitHub API.
@@ -176,6 +269,24 @@ const getCopilotUsage = async (githubToken) => {
176
269
  return await response.json();
177
270
  };
178
271
  //#endregion
272
+ //#region src/services/github/get-user.ts
273
+ /**
274
+ * Fetch the GitHub user profile.
275
+ *
276
+ * @param githubToken Optional explicit token. When omitted, falls back to
277
+ * the global `state.githubToken`. Prefer passing a token
278
+ * explicitly to avoid race conditions in multi-account mode.
279
+ */
280
+ async function getGitHubUser(githubToken) {
281
+ const token = githubToken ?? state.githubToken;
282
+ const response = await fetch(`${GITHUB_API_BASE_URL}/user`, { headers: {
283
+ authorization: `token ${token}`,
284
+ ...standardHeaders()
285
+ } });
286
+ if (!response.ok) throw new HTTPError("Failed to get GitHub user", response);
287
+ return await response.json();
288
+ }
289
+ //#endregion
179
290
  //#region src/lib/account-manager.ts
180
291
  const ACCOUNTS_PATH = PATHS.ACCOUNTS_PATH;
181
292
  const COOLDOWN_MS = 60 * 1e3;
@@ -354,7 +465,10 @@ var AccountManager = class {
354
465
  if (err instanceof HTTPError && err.response.status === 401) {
355
466
  this.markAccountStatus(account.id, "banned", "GitHub token invalid");
356
467
  consola.warn(`Account ${account.label}: token invalid, marked as banned`);
357
- } else consola.error(`Account ${account.label}: failed to refresh Copilot token:`, err);
468
+ } else {
469
+ consola.warn(`Account ${account.label}: failed to refresh Copilot token: ${rootCause(err)}`);
470
+ consola.debug(`Account ${account.label}: failed to refresh Copilot token:`, err);
471
+ }
358
472
  }
359
473
  }
360
474
  /**
@@ -474,160 +588,6 @@ var AccountManager = class {
474
588
  };
475
589
  const accountManager = new AccountManager();
476
590
  //#endregion
477
- //#region src/services/github/get-device-code.ts
478
- async function getDeviceCode() {
479
- const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {
480
- method: "POST",
481
- headers: standardHeaders(),
482
- body: JSON.stringify({
483
- client_id: GITHUB_CLIENT_ID,
484
- scope: GITHUB_APP_SCOPES
485
- })
486
- });
487
- if (!response.ok) throw new HTTPError("Failed to get device code", response);
488
- return await response.json();
489
- }
490
- //#endregion
491
- //#region src/services/github/poll-access-token.ts
492
- async function pollAccessToken(deviceCode) {
493
- const sleepDuration = (deviceCode.interval + 1) * 1e3;
494
- consola.debug(`Polling access token with interval of ${sleepDuration}ms`);
495
- const expirationTime = Date.now() + deviceCode.expires_in * 1e3;
496
- while (Date.now() < expirationTime) {
497
- const response = await fetch(`${GITHUB_BASE_URL}/login/oauth/access_token`, {
498
- method: "POST",
499
- headers: standardHeaders(),
500
- body: JSON.stringify({
501
- client_id: GITHUB_CLIENT_ID,
502
- device_code: deviceCode.device_code,
503
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
504
- })
505
- });
506
- if (!response.ok) {
507
- await sleep(sleepDuration);
508
- consola.error("Failed to poll access token:", await response.text());
509
- continue;
510
- }
511
- const json = await response.json();
512
- consola.debug("Polling access token response:", json);
513
- if ("access_token" in json && json.access_token) return json.access_token;
514
- if ("error" in json) switch (json.error) {
515
- case "authorization_pending":
516
- await sleep(sleepDuration);
517
- continue;
518
- case "slow_down":
519
- await sleep(sleepDuration * 2);
520
- continue;
521
- case "expired_token": throw new Error("Device code expired. Please try again.");
522
- case "access_denied": throw new Error("Authorization was denied by the user.");
523
- default: throw new Error(`Authentication failed: ${json.error_description || json.error}`);
524
- }
525
- await sleep(sleepDuration);
526
- }
527
- throw new Error("Device code expired. Please try again.");
528
- }
529
- //#endregion
530
- //#region src/lib/token.ts
531
- const readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8");
532
- const writeGithubToken = (token) => fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token, { mode: 384 });
533
- /**
534
- * Clear the stored GitHub token from disk and state.
535
- * This allows the user to logout or re-authenticate.
536
- */
537
- async function clearGithubToken() {
538
- state.githubToken = void 0;
539
- state.copilotToken = void 0;
540
- await fs.writeFile(PATHS.GITHUB_TOKEN_PATH, "");
541
- consola.info("GitHub token cleared");
542
- }
543
- /** Handle to the single-account Copilot token refresh interval. */
544
- let copilotTokenRefreshTimer;
545
- /**
546
- * Stop the single-account Copilot token refresh interval.
547
- * Called when multi-account mode is activated to avoid duplicate refreshes.
548
- */
549
- function stopCopilotTokenRefresh() {
550
- if (copilotTokenRefreshTimer) {
551
- clearInterval(copilotTokenRefreshTimer);
552
- copilotTokenRefreshTimer = void 0;
553
- consola.debug("Single-account Copilot token refresh stopped (multi-account active)");
554
- }
555
- }
556
- const setupCopilotToken = async () => {
557
- const { token, refresh_in } = await getCopilotToken();
558
- state.copilotToken = token;
559
- consola.debug("GitHub Copilot Token fetched successfully!");
560
- if (state.showToken) consola.info("Copilot token:", token);
561
- const refreshInterval = Math.max((refresh_in - 60) * 1e3, 6e4);
562
- copilotTokenRefreshTimer = setInterval(async () => {
563
- consola.debug("Refreshing Copilot token");
564
- try {
565
- await refreshCopilotToken();
566
- } catch (error) {
567
- consola.error("Failed to refresh Copilot token:", error);
568
- if (error instanceof HTTPError && error.response.status === 401) {
569
- consola.warn("GitHub token may have been revoked. Please restart and re-authenticate.");
570
- state.copilotToken = void 0;
571
- }
572
- }
573
- }, refreshInterval);
574
- };
575
- /**
576
- * Refresh the Copilot token on demand (e.g. after a 401 error).
577
- */
578
- async function refreshCopilotToken() {
579
- const { token } = await getCopilotToken();
580
- state.copilotToken = token;
581
- consola.debug("Copilot token refreshed");
582
- if (state.showToken) consola.info("Refreshed Copilot token:", token);
583
- }
584
- /**
585
- * Perform a fresh GitHub authentication flow.
586
- * Gets a device code and polls for the access token.
587
- */
588
- async function performFreshAuthentication() {
589
- consola.info("Starting GitHub authentication flow...");
590
- const response = await getDeviceCode();
591
- consola.debug("Device code response:", response);
592
- consola.info(`Please enter the code "${response.user_code}" in ${response.verification_uri}`);
593
- const token = await pollAccessToken(response);
594
- await writeGithubToken(token);
595
- state.githubToken = token;
596
- if (state.showToken) consola.info("GitHub token:", token);
597
- await logUser();
598
- }
599
- async function setupGitHubToken(options) {
600
- try {
601
- const githubToken = await readGithubToken();
602
- if (githubToken && !options?.force) {
603
- state.githubToken = githubToken;
604
- if (state.showToken) consola.info("GitHub token:", githubToken);
605
- try {
606
- await logUser();
607
- return;
608
- } catch (error) {
609
- if (error instanceof HTTPError && error.response.status === 401) {
610
- consola.warn("Stored GitHub token is invalid or expired, clearing and re-authenticating...");
611
- await clearGithubToken();
612
- } else throw error;
613
- }
614
- }
615
- consola.info("Not logged in, getting new access token");
616
- await performFreshAuthentication();
617
- } catch (error) {
618
- if (error instanceof HTTPError) {
619
- consola.error("Failed to get GitHub token:", await error.response.json());
620
- throw error;
621
- }
622
- consola.error("Failed to get GitHub token:", error);
623
- throw error;
624
- }
625
- }
626
- async function logUser() {
627
- const user = await getGitHubUser();
628
- consola.info(`Logged in as ${user.login}`);
629
- }
630
- //#endregion
631
- export { ensurePaths as _, stopCopilotTokenRefresh as a, accountManager as c, cacheVSCodeVersion as d, findModel as f, PATHS as g, sleep as h, setupGitHubToken as i, getCopilotUsage as l, rootCause as m, refreshCopilotToken as n, pollAccessToken as o, isNullish as p, setupCopilotToken as r, getDeviceCode as s, clearGithubToken as t, cacheModels as u };
591
+ export { GITHUB_BASE_URL as _, PATHS as a, copilotHeaders as b, forwardError as c, findModel as d, isNullish as f, GITHUB_APP_SCOPES as g, state as h, getCopilotToken as i, cacheModels as l, sleep as m, getGitHubUser as n, ensurePaths as o, rootCause as p, getCopilotUsage as r, HTTPError as s, accountManager as t, cacheVSCodeVersion as u, GITHUB_CLIENT_ID as v, standardHeaders as x, copilotBaseUrl as y };
632
592
 
633
- //# sourceMappingURL=token-D_wTNufW.js.map
593
+ //# sourceMappingURL=account-manager-DmXXcFBW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-manager-DmXXcFBW.js","names":["ACCOUNTS_PATH"],"sources":["../src/lib/api-config.ts","../src/lib/state.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/lib/error.ts","../src/lib/paths.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-copilot-usage.ts","../src/services/github/get-user.ts","../src/lib/account-manager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.38.2\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\n// Updated to match latest Zed implementation - 2025-10-01 returns Claude models\nconst API_VERSION = \"2025-10-01\"\n\n/**\n * Common interface for anything that can supply Copilot/GitHub credentials.\n *\n * Both `State` and `Account` satisfy this interface, so all header/URL\n * helpers can accept either without an explicit overload.\n */\nexport interface TokenSource {\n copilotToken?: string\n copilotApiEndpoint?: string\n accountType: string\n githubToken?: string\n vsCodeVersion?: string\n}\n\n// Re-export constants used by other modules for building headers manually\nexport { API_VERSION, EDITOR_PLUGIN_VERSION, USER_AGENT }\n\n// Use the API endpoint from token response if available, otherwise fall back to default\nexport const copilotBaseUrl = (source: TokenSource) => {\n if (source.copilotApiEndpoint) {\n return source.copilotApiEndpoint\n }\n return source.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${source.accountType}.githubcopilot.com`\n}\nexport const copilotHeaders = (\n source: TokenSource,\n vision: boolean = false,\n) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${source.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": \"vscode-chat\",\n \"editor-version\": `vscode/${source.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-agent\",\n \"x-interaction-type\": \"conversation-agent\",\n \"x-agent-task-id\": randomUUID(),\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 = (source: TokenSource) => ({\n ...standardHeaders(),\n authorization: `token ${source.githubToken}`,\n \"editor-version\": `vscode/${source.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 { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n copilotApiEndpoint?: string // API endpoint returned by token response\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 key authentication\n apiKeys?: Array<string>\n\n // Multi-account mode\n multiAccountEnabled: boolean\n\n // Selected models (from --claude-code setup)\n selectedModel?: string\n selectedSmallModel?: string\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n multiAccountEnabled: false,\n}\n","import { accountManager } from \"~/lib/account-manager\"\nimport {\n copilotBaseUrl,\n copilotHeaders,\n type TokenSource,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n // In multi-account mode, use the active account's token\n let source: TokenSource = state\n if (state.multiAccountEnabled && accountManager.hasAccounts()) {\n const account = accountManager.getActiveAccount()\n if (account?.copilotToken) {\n source = {\n copilotToken: account.copilotToken,\n copilotApiEndpoint: account.copilotApiEndpoint,\n accountType: account.accountType,\n githubToken: account.githubToken,\n vsCodeVersion: state.vsCodeVersion,\n }\n }\n }\n\n const url = `${copilotBaseUrl(source)}/models`\n\n const response = await fetch(url, {\n headers: copilotHeaders(source),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n const data = (await response.json()) as ModelsResponse\n\n return data\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 // Thinking/reasoning capabilities\n max_thinking_budget?: number\n min_thinking_budget?: number\n adaptive_thinking?: 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\nexport interface 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 billing?: {\n is_premium: boolean\n multiplier: number\n restricted_to?: Array<string>\n }\n}\n","const FALLBACK = \"1.104.3\"\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","import consola from \"consola\"\n\nimport type { Model } from \"~/services/copilot/get-models\"\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\n/**\n * Extract the root-cause message from an unknown thrown value.\n *\n * If the error wraps another error via the standard `cause` property, the\n * inner message is returned instead — giving a one-line summary of *why*\n * the operation failed without the noise of the full stack trace.\n */\nexport function rootCause(err: unknown): string {\n if (err instanceof Error) {\n return err.cause instanceof Error ? err.cause.message : err.message\n }\n return String(err)\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\n/**\n * Find a model in state.models using multi-strategy exact matching.\n *\n * Strategies (in order):\n * 1. Exact match on model ID\n * 2. Strip date suffix (claude-opus-4-6-20251101 → claude-opus-4-6)\n * 3. Dash to dot version (claude-opus-4-5 → claude-opus-4.5)\n * 4. Dot to dash version (claude-opus-4.5 → claude-opus-4-5)\n *\n * No fuzzy/family matching — all strategies produce deterministic exact IDs.\n */\nexport function findModel(modelName: string): Model | undefined {\n const models = state.models?.data\n if (!models || models.length === 0) {\n return undefined\n }\n\n // 1. Exact match\n const exact = models.find((m) => m.id === modelName)\n if (exact) return exact\n\n // 2. Strip date suffix\n const base = modelName.replace(/-\\d{8}$/, \"\")\n if (base !== modelName) {\n const baseMatch = models.find((m) => m.id === base)\n if (baseMatch) return baseMatch\n }\n\n // 3. Dash to dot version (4-5 → 4.5)\n const withDot = base.replace(/-(\\d+)-(\\d+)$/, \"-$1.$2\")\n if (withDot !== base) {\n const dotMatch = models.find((m) => m.id === withDot)\n if (dotMatch) return dotMatch\n }\n\n // 4. Dot to dash version (4.5 → 4-5)\n const withDash = modelName.replace(/(\\d+)\\.(\\d+)/, \"$1-$2\")\n if (withDash !== modelName) {\n const dashMatch = models.find((m) => m.id === withDash)\n if (dashMatch) return dashMatch\n }\n\n return undefined\n}\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nimport { rootCause } from \"~/lib/utils\"\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 if (error instanceof HTTPError) {\n // Try to read error body, but it may already be consumed by the caller\n let errorText: string\n try {\n errorText = await error.response.text()\n } catch {\n // Body already read — fall back to the error message\n errorText = error.message\n }\n\n // 400 errors: concise log, already detailed upstream\n if (error.response.status === 400) {\n // no extra logging, upstream already printed details\n } else {\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = errorText\n }\n consola.warn(`Error occurred: ${rootCause(error)}`)\n consola.debug(\"HTTP error:\", errorJson)\n }\n\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 // Network errors (fetch failed, TLS disconnect, etc.) — concise log\n const message = (error as Error).message || String(error)\n const cause = (error as { cause?: Error }).cause\n if (cause) {\n consola.error(`${message}: ${cause.message}`)\n } else {\n consola.error(message)\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 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-plus\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nconst ACCOUNTS_PATH = path.join(APP_DIR, \"accounts.json\")\n\nexport const PATHS = {\n APP_DIR,\n DATA_DIR: APP_DIR,\n GITHUB_TOKEN_PATH,\n ACCOUNTS_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 consola from \"consola\"\n\nimport { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Fetch a short-lived Copilot JWT from the GitHub API.\n *\n * @param githubToken Optional explicit GitHub PAT. When provided the request\n * uses this token instead of `state.githubToken` and does\n * **not** mutate global state (so multi-account callers\n * stay side-effect-free).\n */\nexport const getCopilotToken = async (githubToken?: string) => {\n const tokenToUse = githubToken ?? state.githubToken\n const isExplicitToken = githubToken !== undefined\n\n const url = `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`\n const fetchOptions: RequestInit = {\n headers: githubHeaders({\n ...state,\n githubToken: tokenToUse,\n }),\n }\n\n // Retry on transient network errors (TLS disconnect, connection timeout, etc.)\n const maxRetries = 2\n let lastError: unknown\n let response: Response | undefined\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n response = await fetch(url, fetchOptions)\n break\n } catch (error: unknown) {\n lastError = error\n if (attempt < maxRetries) {\n const delay = 1000 * (attempt + 1)\n consola.warn(\n `Token fetch error on attempt ${attempt + 1}/${maxRetries + 1}, retrying in ${delay}ms:`,\n error instanceof Error ? error.message : error,\n )\n await new Promise((r) => setTimeout(r, delay))\n }\n }\n }\n\n if (!response) {\n throw lastError\n }\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n const data = (await response.json()) as GetCopilotTokenResponse\n\n // Only write to global state when using the default token (single-account mode).\n // When an explicit githubToken is provided (multi-account), the caller is\n // responsible for storing the endpoint on its own Account object.\n if (!isExplicitToken && data.endpoints?.api) {\n // eslint-disable-next-line require-atomic-updates\n state.copilotApiEndpoint = data.endpoints.api\n }\n\n return data\n}\n\n// Full interface matching Zed's implementation\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n endpoints?: {\n api: string\n \"origin-tracker\"?: string\n proxy?: string\n telemetry?: string\n }\n annotations_enabled?: boolean\n chat_enabled?: boolean\n chat_jetbrains_enabled?: boolean\n code_quote_enabled?: boolean\n codesearch?: boolean\n copilot_ide_agent_chat_gpt4_small_prompt?: boolean\n copilotignore_enabled?: boolean\n individual?: boolean\n sku?: string\n tracking_id?: string\n limited_user_quotas?: unknown // Premium request quotas\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Fetch the authenticated user's Copilot usage / quota snapshot.\n *\n * @param githubToken Optional explicit GitHub PAT. When provided the request\n * uses this token instead of `state.githubToken`, allowing\n * multi-account callers to query any account without\n * touching global state.\n */\nexport const getCopilotUsage = async (\n githubToken?: string,\n): Promise<CopilotUsageResponse> => {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders({\n ...state,\n githubToken: githubToken ?? state.githubToken,\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}\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 { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Fetch the GitHub user profile.\n *\n * @param githubToken Optional explicit token. When omitted, falls back to\n * the global `state.githubToken`. Prefer passing a token\n * explicitly to avoid race conditions in multi-account mode.\n */\nexport async function getGitHubUser(githubToken?: string) {\n const token = githubToken ?? state.githubToken\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${token}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import consola from \"consola\"\nimport { randomUUID } from \"node:crypto\"\nimport fs from \"node:fs/promises\"\n\nimport { HTTPError } from \"~/lib/error\"\nimport { PATHS } from \"~/lib/paths\"\nimport { rootCause } from \"~/lib/utils\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type AccountStatus =\n | \"active\"\n | \"exhausted\"\n | \"rate_limited\"\n | \"banned\"\n | \"error\"\n | \"disabled\"\n\nexport interface Account {\n id: string\n label: string\n githubToken: string\n /** Short-lived Copilot JWT – kept in memory only, never persisted. */\n copilotToken?: string\n /** API endpoint extracted from the Copilot token response. */\n copilotApiEndpoint?: string\n accountType: string // \"individual\" | \"business\" | \"enterprise\"\n\n // Status\n status: AccountStatus\n statusMessage?: string\n lastUsedAt?: number\n consecutiveFailures: number\n cooldownUntil?: number\n\n // Quota snapshot (refreshed periodically)\n usage?: {\n premium_remaining: number\n premium_total: number\n chat_remaining: number\n chat_total: number\n quotaResetDate: string\n lastCheckedAt: number\n }\n\n // Metadata\n githubLogin?: string\n addedAt: number\n}\n\n// ---------------------------------------------------------------------------\n// Persistence helpers\n// ---------------------------------------------------------------------------\n\n/** Fields excluded from the JSON file (short-lived / runtime-only). */\ntype PersistedAccount = Omit<Account, \"copilotToken\">\n\nconst ACCOUNTS_PATH = PATHS.ACCOUNTS_PATH\n\n// ---------------------------------------------------------------------------\n// AccountManager\n// ---------------------------------------------------------------------------\n\nconst COOLDOWN_MS = 60 * 1000 // 60 seconds\n\nexport class AccountManager {\n private accounts: Array<Account> = []\n private refreshInterval?: ReturnType<typeof setInterval>\n private usageInterval?: ReturnType<typeof setInterval>\n\n // Debounced save\n private saveTimer?: ReturnType<typeof setTimeout>\n private savePending = false\n\n // ---------- Persistence ------------------------------------------------\n\n /**\n * Load accounts from the JSON file on disk.\n * Missing file is treated as empty list – not an error.\n */\n async loadAccounts(): Promise<void> {\n try {\n // eslint-disable-next-line unicorn/prefer-json-parse-buffer\n const raw = await fs.readFile(ACCOUNTS_PATH, \"utf8\")\n const parsed = JSON.parse(raw) as Array<PersistedAccount>\n this.accounts = parsed.map((a) => ({ ...a, copilotToken: undefined }))\n consola.info(`Loaded ${this.accounts.length} account(s) from disk`)\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n this.accounts = []\n return\n }\n consola.warn(`Failed to load accounts: ${rootCause(err)}`)\n consola.debug(\"Failed to load accounts:\", err)\n this.accounts = []\n }\n }\n\n /**\n * Persist accounts to disk. `copilotToken` is excluded because it is\n * short-lived and will be refreshed on every startup.\n */\n async saveAccounts(): Promise<void> {\n const data: Array<PersistedAccount> = this.accounts.map(\n ({ copilotToken: _dropped, ...rest }) => rest,\n )\n try {\n await fs.writeFile(ACCOUNTS_PATH, JSON.stringify(data, null, 2), {\n encoding: \"utf8\",\n mode: 0o600,\n })\n } catch (err) {\n consola.warn(`Failed to save accounts: ${rootCause(err)}`)\n consola.debug(\"Failed to save accounts:\", err)\n }\n }\n\n /** Schedule a debounced save (coalesces rapid status updates). */\n private debouncedSave(): void {\n if (this.saveTimer) return // already scheduled\n this.savePending = true\n this.saveTimer = setTimeout(async () => {\n this.saveTimer = undefined\n if (this.savePending) {\n this.savePending = false\n await this.saveAccounts()\n }\n }, 1_000)\n }\n\n // ---------- CRUD -------------------------------------------------------\n\n /**\n * Add a new account.\n *\n * 1. Validates the GitHub token by fetching user info.\n * 2. Obtains an initial Copilot token.\n * 3. Persists the account to disk.\n */\n async addAccount(\n githubToken: string,\n label: string,\n accountType: string = \"individual\",\n ): Promise<Account> {\n // 1. Validate token – get GitHub login (pass token explicitly, no state mutation)\n const user = await getGitHubUser(githubToken)\n\n // 2. Obtain Copilot token – pass token directly (no state mutation)\n const tokenData = await getCopilotToken(githubToken)\n\n const account: Account = {\n id: randomUUID(),\n label,\n githubToken,\n copilotToken: tokenData.token,\n copilotApiEndpoint: tokenData.endpoints?.api,\n accountType,\n status: \"active\",\n consecutiveFailures: 0,\n githubLogin: user.login,\n addedAt: Date.now(),\n }\n\n this.accounts.push(account)\n await this.saveAccounts()\n\n consola.success(`Account added: ${label} (${user.login})`)\n return account\n }\n\n async removeAccount(id: string): Promise<boolean> {\n const idx = this.accounts.findIndex((a) => a.id === id)\n if (idx === -1) return false\n const [removed] = this.accounts.splice(idx, 1)\n await this.saveAccounts()\n consola.info(`Account removed: ${removed.label}`)\n return true\n }\n\n getAccounts(): Array<Account> {\n return this.accounts\n }\n\n getAccountById(id: string): Account | undefined {\n return this.accounts.find((a) => a.id === id)\n }\n\n // ---------- Smart account selection ------------------------------------\n\n /**\n * Pick the best available account.\n *\n * 1. Filter out disabled, banned, exhausted, and accounts still in cooldown.\n * 2. Prefer accounts with more remaining premium quota.\n * 3. Fall back to round-robin (least-recently-used) when quotas are equal\n * or unknown.\n */\n getActiveAccount(): Account | undefined {\n const now = Date.now()\n\n const eligible = this.accounts.filter((a) => {\n if (\n a.status === \"disabled\"\n || a.status === \"banned\"\n || a.status === \"exhausted\"\n ) {\n return false\n }\n if (a.cooldownUntil && a.cooldownUntil > now) return false\n return true\n })\n\n if (eligible.length === 0) {\n // Fallback: if there is exactly one account and it's only cooling down\n // (not banned/disabled/exhausted), return it anyway. With a single\n // account there is nothing to \"switch to\", so blocking all requests\n // for the cooldown period would be a self-inflicted outage.\n if (this.accounts.length === 1) {\n const solo = this.accounts[0]\n if (\n solo.status !== \"disabled\"\n && solo.status !== \"banned\"\n && solo.status !== \"exhausted\"\n ) {\n return solo\n }\n }\n return undefined\n }\n\n eligible.sort((a, b) => {\n const aRemaining = a.usage?.premium_remaining ?? -1\n const bRemaining = b.usage?.premium_remaining ?? -1\n\n // Higher remaining quota first\n if (aRemaining !== bRemaining) return bRemaining - aRemaining\n\n // Equal / unknown → least recently used first (round-robin)\n const aUsed = a.lastUsedAt ?? 0\n const bUsed = b.lastUsedAt ?? 0\n return aUsed - bUsed\n })\n\n return eligible[0]\n }\n\n // ---------- Status management ------------------------------------------\n\n markAccountStatus(id: string, status: AccountStatus, message?: string): void {\n const account = this.getAccountById(id)\n if (!account) return\n\n account.status = status\n account.statusMessage = message\n\n switch (status) {\n case \"rate_limited\":\n case \"error\": {\n // Only apply cooldown when there are other accounts to switch to.\n // With a single account, cooldown would block ALL requests with\n // \"No available accounts\" — effectively a self-inflicted outage.\n if (this.accounts.length > 1) {\n account.cooldownUntil = Date.now() + COOLDOWN_MS\n }\n account.consecutiveFailures += 1\n\n break\n }\n case \"banned\": {\n account.consecutiveFailures += 1\n\n break\n }\n case \"active\": {\n // Recovering from a failure state — reset\n account.consecutiveFailures = 0\n account.cooldownUntil = undefined\n\n break\n }\n // No default\n }\n // \"exhausted\" and \"disabled\" don't touch consecutiveFailures\n\n this.debouncedSave()\n }\n\n markAccountSuccess(id: string): void {\n const account = this.getAccountById(id)\n if (!account) return\n\n account.consecutiveFailures = 0\n account.lastUsedAt = Date.now()\n\n if (account.status === \"error\" || account.status === \"rate_limited\") {\n account.status = \"active\"\n account.statusMessage = undefined\n account.cooldownUntil = undefined\n }\n\n this.debouncedSave()\n }\n\n // ---------- Token & usage refresh (per account) ------------------------\n\n /**\n * Refresh the short-lived Copilot JWT for a single account.\n *\n * Passes the account's GitHub token directly to `getCopilotToken()` so that\n * global `state.githubToken` is never mutated — safe for concurrent use.\n */\n async refreshAccountToken(account: Account): Promise<void> {\n try {\n const data = await getCopilotToken(account.githubToken)\n // eslint-disable-next-line require-atomic-updates\n account.copilotToken = data.token\n if (data.endpoints?.api) {\n // eslint-disable-next-line require-atomic-updates\n account.copilotApiEndpoint = data.endpoints.api\n }\n } catch (err: unknown) {\n if (err instanceof HTTPError && err.response.status === 401) {\n this.markAccountStatus(account.id, \"banned\", \"GitHub token invalid\")\n consola.warn(\n `Account ${account.label}: token invalid, marked as banned`,\n )\n } else {\n consola.warn(\n `Account ${account.label}: failed to refresh Copilot token: ${rootCause(err)}`,\n )\n consola.debug(\n `Account ${account.label}: failed to refresh Copilot token:`,\n err,\n )\n }\n }\n }\n\n /**\n * Refresh the usage / quota snapshot for a single account.\n *\n * Passes the account's GitHub token directly to `getCopilotUsage()` so that\n * global `state.githubToken` is never mutated — safe for concurrent use.\n */\n async refreshAccountUsage(account: Account): Promise<void> {\n try {\n const data = await getCopilotUsage(account.githubToken)\n const snap = data.quota_snapshots\n\n // eslint-disable-next-line require-atomic-updates\n account.usage = {\n premium_remaining: snap.premium_interactions.remaining,\n premium_total: snap.premium_interactions.entitlement,\n chat_remaining: snap.chat.remaining,\n chat_total: snap.chat.entitlement,\n quotaResetDate: data.quota_reset_date,\n lastCheckedAt: Date.now(),\n }\n\n // Transition between active ↔ exhausted\n if (account.usage.premium_remaining <= 0 && account.status === \"active\") {\n this.markAccountStatus(\n account.id,\n \"exhausted\",\n \"Premium quota exhausted\",\n )\n } else if (\n account.usage.premium_remaining > 0\n && account.status === \"exhausted\"\n ) {\n account.status = \"active\"\n account.statusMessage = undefined\n account.consecutiveFailures = 0\n this.debouncedSave()\n }\n } catch (err) {\n consola.warn(\n `Account ${account.label}: failed to refresh usage: ${rootCause(err)}`,\n )\n consola.debug(`Account ${account.label}: failed to refresh usage:`, err)\n }\n }\n\n // ---------- Background refresh -----------------------------------------\n\n /** Refresh Copilot tokens for all non-disabled accounts. */\n async refreshAllTokens(): Promise<void> {\n const targets = this.accounts.filter((a) => a.status !== \"disabled\")\n await Promise.allSettled(targets.map((a) => this.refreshAccountToken(a)))\n }\n\n /** Refresh usage snapshots for all non-disabled accounts. */\n async refreshAllUsage(): Promise<void> {\n const targets = this.accounts.filter((a) => a.status !== \"disabled\")\n await Promise.allSettled(targets.map((a) => this.refreshAccountUsage(a)))\n }\n\n /**\n * Start periodic background refresh loops.\n *\n * The initial token refresh is awaited to ensure accounts are ready before\n * the first request arrives. Usage refresh runs in the background.\n *\n * @param tokenIntervalMs Token refresh interval (default 25 min).\n * @param usageIntervalMs Usage refresh interval (default 5 min).\n */\n async startBackgroundRefresh(\n tokenIntervalMs: number = 25 * 60 * 1000,\n usageIntervalMs: number = 5 * 60 * 1000,\n ): Promise<void> {\n this.stopBackgroundRefresh()\n\n // Initial refresh — await token refresh so accounts are ready for requests\n await this.refreshAllTokens()\n void this.refreshAllUsage()\n\n this.refreshInterval = setInterval(() => {\n void this.refreshAllTokens()\n }, tokenIntervalMs)\n\n this.usageInterval = setInterval(() => {\n void this.refreshAllUsage()\n }, usageIntervalMs)\n\n consola.info(\n `Background refresh started (tokens: ${tokenIntervalMs / 60_000}m, usage: ${usageIntervalMs / 60_000}m)`,\n )\n }\n\n stopBackgroundRefresh(): void {\n if (this.refreshInterval) {\n clearInterval(this.refreshInterval)\n this.refreshInterval = undefined\n }\n if (this.usageInterval) {\n clearInterval(this.usageInterval)\n this.usageInterval = undefined\n }\n }\n\n // ---------- Helpers ----------------------------------------------------\n\n get accountCount(): number {\n return this.accounts.length\n }\n\n get activeAccountCount(): number {\n return this.accounts.filter((a) => a.status === \"active\").length\n }\n\n hasAccounts(): boolean {\n return this.accounts.length > 0\n }\n\n // ---------- Legacy migration -------------------------------------------\n\n /**\n * Create an Account entry from the legacy single-account global state.\n * Useful for seamless upgrade from single-account to multi-account mode.\n *\n * Falls back to creating a minimal entry if API validation fails — the\n * background refresh will fill in the missing data later.\n */\n async migrateFromLegacy(\n githubToken: string,\n accountType: string,\n ): Promise<Account> {\n // Check if this token is already registered\n const existing = this.accounts.find((a) => a.githubToken === githubToken)\n if (existing) {\n consola.info(\"Legacy account already migrated, skipping\")\n return existing\n }\n\n try {\n const account = await this.addAccount(\n githubToken,\n \"Primary (migrated)\",\n accountType,\n )\n consola.success(\"Legacy single-account migrated to multi-account manager\")\n return account\n } catch (error) {\n // API validation failed — create a minimal entry anyway so the account\n // is visible in the management UI. Background token/usage refresh will\n // fill in the missing data.\n consola.warn(\n \"Could not fully validate legacy account, adding with limited info:\",\n error,\n )\n\n const account: Account = {\n id: randomUUID(),\n label: \"Primary (migrated)\",\n githubToken,\n copilotToken: undefined,\n accountType,\n status: \"active\",\n consecutiveFailures: 0,\n addedAt: Date.now(),\n }\n\n this.accounts.push(account)\n await this.saveAccounts()\n return account\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton\n// ---------------------------------------------------------------------------\n\nexport const accountManager = new AccountManager()\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { s as HTTPError } from "./account-manager-DmXXcFBW.js";
2
+ export { HTTPError };
@@ -0,0 +1,2 @@
1
+ import { n as getGitHubUser } from "./account-manager-DmXXcFBW.js";
2
+ export { getGitHubUser };
package/dist/main.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { n as forwardError, t as HTTPError } from "./error-CvwUkoEo.js";
3
- import { _ as ensurePaths, a as stopCopilotTokenRefresh, c as accountManager, d as cacheVSCodeVersion, f as findModel, g as PATHS, h as sleep, i as setupGitHubToken, l as getCopilotUsage, m as rootCause, n as refreshCopilotToken, o as pollAccessToken, p as isNullish, r as setupCopilotToken, s as getDeviceCode, t as clearGithubToken, u as cacheModels } from "./token-D_wTNufW.js";
4
- import { a as GITHUB_BASE_URL, c as copilotHeaders, n as state, o as GITHUB_CLIENT_ID, s as copilotBaseUrl, u as standardHeaders } from "./get-user-BT7hEyDN.js";
2
+ import { _ as GITHUB_BASE_URL, a as PATHS, b as copilotHeaders, c as forwardError, d as findModel, f as isNullish, h as state, l as cacheModels, m as sleep, o as ensurePaths, p as rootCause, r as getCopilotUsage, s as HTTPError, t as accountManager, u as cacheVSCodeVersion, v as GITHUB_CLIENT_ID, x as standardHeaders, y as copilotBaseUrl } from "./account-manager-DmXXcFBW.js";
3
+ import { a as stopCopilotTokenRefresh, i as setupGitHubToken, n as refreshCopilotToken, o as pollAccessToken, r as setupCopilotToken, s as getDeviceCode, t as clearGithubToken } from "./token-DUSd-gxE.js";
5
4
  import { createRequire } from "node:module";
6
5
  import { defineCommand, runMain } from "citty";
7
6
  import consola from "consola";
@@ -1398,7 +1397,8 @@ accountRoutes.get("/", (c) => {
1398
1397
  const accounts = accountManager.getAccounts().map((a) => sanitiseAccount(a));
1399
1398
  return c.json({ accounts });
1400
1399
  } catch (error) {
1401
- consola.error("Error listing accounts:", error);
1400
+ consola.warn(`Error listing accounts: ${rootCause(error)}`);
1401
+ consola.debug("Error listing accounts:", error);
1402
1402
  return c.json({ error: "Failed to list accounts" }, 500);
1403
1403
  }
1404
1404
  });
@@ -1409,7 +1409,8 @@ accountRoutes.post("/", async (c) => {
1409
1409
  const account = await accountManager.addAccount(body.githubToken, body.label, body.accountType);
1410
1410
  return c.json({ account: sanitiseAccount(account) }, 201);
1411
1411
  } catch (error) {
1412
- consola.error("Error adding account:", error);
1412
+ consola.warn(`Error adding account: ${rootCause(error)}`);
1413
+ consola.debug("Error adding account:", error);
1413
1414
  return c.json({ error: "Failed to add account" }, 500);
1414
1415
  }
1415
1416
  });
@@ -1419,7 +1420,8 @@ accountRoutes.delete("/:id", async (c) => {
1419
1420
  if (!await accountManager.removeAccount(id)) return c.json({ error: "Account not found" }, 404);
1420
1421
  return c.json({ success: true });
1421
1422
  } catch (error) {
1422
- consola.error("Error removing account:", error);
1423
+ consola.warn(`Error removing account: ${rootCause(error)}`);
1424
+ consola.debug("Error removing account:", error);
1423
1425
  return c.json({ error: "Failed to remove account" }, 500);
1424
1426
  }
1425
1427
  });
@@ -1439,7 +1441,8 @@ accountRoutes.put("/:id/status", async (c) => {
1439
1441
  await accountManager.saveAccounts();
1440
1442
  return c.json({ account: sanitiseAccount(account) });
1441
1443
  } catch (error) {
1442
- consola.error("Error updating account status:", error);
1444
+ consola.warn(`Error updating account status: ${rootCause(error)}`);
1445
+ consola.debug("Error updating account status:", error);
1443
1446
  return c.json({ error: "Failed to update account status" }, 500);
1444
1447
  }
1445
1448
  });
@@ -1452,7 +1455,8 @@ accountRoutes.post("/:id/refresh", async (c) => {
1452
1455
  await accountManager.refreshAccountUsage(account);
1453
1456
  return c.json({ account: sanitiseAccount(account) });
1454
1457
  } catch (error) {
1455
- consola.error("Error refreshing account:", error);
1458
+ consola.warn(`Error refreshing account: ${rootCause(error)}`);
1459
+ consola.debug("Error refreshing account:", error);
1456
1460
  return c.json({ error: "Failed to refresh account" }, 500);
1457
1461
  }
1458
1462
  });
@@ -1461,7 +1465,8 @@ accountRoutes.post("/auth/start", async (c) => {
1461
1465
  const deviceCode = await getDeviceCode();
1462
1466
  return c.json(deviceCode);
1463
1467
  } catch (error) {
1464
- consola.error("Error starting device code flow:", error);
1468
+ consola.warn(`Error starting device code flow: ${rootCause(error)}`);
1469
+ consola.debug("Error starting device code flow:", error);
1465
1470
  return c.json({ error: "Failed to start device code authorization" }, 500);
1466
1471
  }
1467
1472
  });
@@ -1503,7 +1508,8 @@ accountRoutes.post("/auth/poll", async (c) => {
1503
1508
  }
1504
1509
  return c.json({ status: "pending" });
1505
1510
  } catch (error) {
1506
- consola.error("Error polling device code:", error);
1511
+ consola.warn(`Error polling device code: ${rootCause(error)}`);
1512
+ consola.debug("Error polling device code:", error);
1507
1513
  return c.json({ error: "Failed to poll device code authorization" }, 500);
1508
1514
  }
1509
1515
  });
@@ -1537,7 +1543,8 @@ accountRoutes.get("/usage", (c) => {
1537
1543
  accounts: accountSummaries
1538
1544
  });
1539
1545
  } catch (error) {
1540
- consola.error("Error fetching aggregated usage:", error);
1546
+ consola.warn(`Error fetching aggregated usage: ${rootCause(error)}`);
1547
+ consola.debug("Error fetching aggregated usage:", error);
1541
1548
  return c.json({ error: "Failed to fetch aggregated usage" }, 500);
1542
1549
  }
1543
1550
  });
@@ -1549,7 +1556,8 @@ modelAdminRoutes.get("/available", (c) => {
1549
1556
  const models = state.models?.data ?? [];
1550
1557
  return c.json(models);
1551
1558
  } catch (error) {
1552
- consola.error("Error fetching available models:", error);
1559
+ consola.warn(`Error fetching available models: ${rootCause(error)}`);
1560
+ consola.debug("Error fetching available models:", error);
1553
1561
  return c.json({ error: "Failed to fetch available models" }, 500);
1554
1562
  }
1555
1563
  });
@@ -1557,7 +1565,8 @@ modelAdminRoutes.get("/mapping", (c) => {
1557
1565
  try {
1558
1566
  return c.json(modelRouter.getConfig());
1559
1567
  } catch (error) {
1560
- consola.error("Error fetching model mapping:", error);
1568
+ consola.warn(`Error fetching model mapping: ${rootCause(error)}`);
1569
+ consola.debug("Error fetching model mapping:", error);
1561
1570
  return c.json({ error: "Failed to fetch model mapping" }, 500);
1562
1571
  }
1563
1572
  });
@@ -1570,7 +1579,8 @@ modelAdminRoutes.put("/mapping", async (c) => {
1570
1579
  await saveModelMappingConfig(modelRouter.getConfig());
1571
1580
  return c.json(modelRouter.getConfig());
1572
1581
  } catch (error) {
1573
- consola.error("Error updating model mapping:", error);
1582
+ consola.warn(`Error updating model mapping: ${rootCause(error)}`);
1583
+ consola.debug("Error updating model mapping:", error);
1574
1584
  return c.json({ error: "Failed to update model mapping" }, 500);
1575
1585
  }
1576
1586
  });
@@ -1578,7 +1588,8 @@ modelAdminRoutes.get("/concurrency", (c) => {
1578
1588
  try {
1579
1589
  return c.json({ concurrency: modelRouter.getConfig().concurrency });
1580
1590
  } catch (error) {
1581
- consola.error("Error fetching concurrency config:", error);
1591
+ consola.warn(`Error fetching concurrency config: ${rootCause(error)}`);
1592
+ consola.debug("Error fetching concurrency config:", error);
1582
1593
  return c.json({ error: "Failed to fetch concurrency config" }, 500);
1583
1594
  }
1584
1595
  });
@@ -1591,7 +1602,8 @@ modelAdminRoutes.put("/concurrency", async (c) => {
1591
1602
  await saveModelMappingConfig(modelRouter.getConfig());
1592
1603
  return c.json({ concurrency: modelRouter.getConfig().concurrency });
1593
1604
  } catch (error) {
1594
- consola.error("Error updating concurrency config:", error);
1605
+ consola.warn(`Error updating concurrency config: ${rootCause(error)}`);
1606
+ consola.debug("Error updating concurrency config:", error);
1595
1607
  return c.json({ error: "Failed to update concurrency config" }, 500);
1596
1608
  }
1597
1609
  });
@@ -1865,7 +1877,8 @@ async function createWithSingleAccount(payload) {
1865
1877
  body: bodyString
1866
1878
  });
1867
1879
  } catch (refreshError) {
1868
- consola.error("Failed to refresh token:", refreshError);
1880
+ consola.warn(`Failed to refresh token: ${rootCause(refreshError)}`);
1881
+ consola.debug("Failed to refresh token:", refreshError);
1869
1882
  }
1870
1883
  }
1871
1884
  if (!response.ok) {
@@ -2582,7 +2595,8 @@ async function handleCountTokens(c) {
2582
2595
  console.log("Token count:", finalTokenCount);
2583
2596
  return c.json({ input_tokens: finalTokenCount });
2584
2597
  } catch (error) {
2585
- consola.error("Error counting tokens:", error);
2598
+ consola.warn(`Error counting tokens: ${rootCause(error)}`);
2599
+ consola.debug("Error counting tokens:", error);
2586
2600
  return c.json({ input_tokens: 1 });
2587
2601
  }
2588
2602
  }
@@ -2870,7 +2884,8 @@ tokenRoute.get("/", (c) => {
2870
2884
  try {
2871
2885
  return c.json({ token: state.copilotToken });
2872
2886
  } catch (error) {
2873
- consola.error("Error fetching token:", error);
2887
+ consola.warn(`Error fetching token: ${rootCause(error)}`);
2888
+ consola.debug("Error fetching token:", error);
2874
2889
  return c.json({
2875
2890
  error: "Failed to fetch token",
2876
2891
  token: null
@@ -2892,7 +2907,8 @@ usageRoute.get("/", async (c) => {
2892
2907
  const usage = await getCopilotUsage();
2893
2908
  return c.json(usage);
2894
2909
  } catch (error) {
2895
- consola.error("Error fetching usage:", error);
2910
+ consola.warn(`Error fetching usage: ${rootCause(error)}`);
2911
+ consola.debug("Error fetching usage:", error);
2896
2912
  return c.json({ error: "Failed to fetch Copilot usage" }, 500);
2897
2913
  }
2898
2914
  });
@@ -3009,7 +3025,7 @@ async function validateGitHubToken(token) {
3009
3025
  state.githubToken = token;
3010
3026
  consola.info("Using provided GitHub token");
3011
3027
  try {
3012
- const { getGitHubUser } = await import("./get-user-BTN_-eOk.js");
3028
+ const { getGitHubUser } = await import("./get-user-DHr540ak.js");
3013
3029
  const user = await getGitHubUser();
3014
3030
  consola.info(`Logged in as ${user.login}`);
3015
3031
  } catch (error) {
@@ -3055,10 +3071,10 @@ async function runServer(options) {
3055
3071
  try {
3056
3072
  await setupCopilotToken();
3057
3073
  } catch (error) {
3058
- const { HTTPError } = await import("./error-DLqcVQL_.js");
3074
+ const { HTTPError } = await import("./error-Cc8bY0ph.js");
3059
3075
  if (error instanceof HTTPError && error.response.status === 401) {
3060
3076
  consola.error("Failed to get Copilot token - GitHub token may be invalid or Copilot access revoked");
3061
- const { clearGithubToken } = await import("./token-CxG7xLpI.js");
3077
+ const { clearGithubToken } = await import("./token-B_m1icXz.js");
3062
3078
  await clearGithubToken();
3063
3079
  consola.info("Please restart to re-authenticate");
3064
3080
  }