@nick3/copilot-api 1.0.3 → 1.0.7

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.
@@ -18,8 +18,8 @@
18
18
  }
19
19
  })()
20
20
  </script>
21
- <script type="module" crossorigin src="/admin/assets/index-CFHE7_Zc.js"></script>
22
- <link rel="stylesheet" crossorigin href="/admin/assets/index-DwLAH2FE.css">
21
+ <script type="module" crossorigin src="/admin/assets/index-DT3yCFaa.js"></script>
22
+ <link rel="stylesheet" crossorigin href="/admin/assets/index-D-pIr-q0.css">
23
23
  </head>
24
24
  <body>
25
25
  <div id="root"></div>
package/dist/main.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { GITHUB_APP_SCOPES, GITHUB_BASE_URL, GITHUB_CLIENT_ID, HTTPError, PATHS, accountsManager, addAccountToRegistry, cacheVSCodeVersion, ensurePaths, getCopilotUsage, getGitHubUser, isFreeModelLoadBalancingEnabled, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, sleep, standardHeaders, state } from "./accounts-manager-CxuKJ4qv.js";
2
+ import { GITHUB_APP_SCOPES, GITHUB_BASE_URL, GITHUB_CLIENT_ID, HTTPError, PATHS, accountsManager, addAccountToRegistry, cacheVSCodeVersion, ensurePaths, getCopilotUsage, getGitHubUser, getModelRefreshIntervalMs, isFreeModelLoadBalancingEnabled, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, sleep, standardHeaders, state } from "./accounts-manager-CJtqVqDx.js";
3
3
  import { defineCommand, runMain } from "citty";
4
4
  import consola from "consola";
5
5
  import fs from "node:fs/promises";
@@ -572,6 +572,7 @@ async function runAuthFlow(accountType) {
572
572
  async function runServer(options) {
573
573
  mergeConfigWithDefaults();
574
574
  accountsManager.setFreeModelLoadBalancingEnabled(isFreeModelLoadBalancingEnabled());
575
+ accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
575
576
  if (options.proxyEnv) initProxyFromEnv();
576
577
  state.verbose = options.verbose;
577
578
  if (options.verbose) {
@@ -595,6 +596,7 @@ async function runServer(options) {
595
596
  await runAuthFlow(options.accountType);
596
597
  accountsManager.shutdown();
597
598
  await accountsManager.initialize(state.vsCodeVersion);
599
+ accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
598
600
  } catch (error) {
599
601
  consola.error("Failed to add account:", error);
600
602
  process.exit(1);
@@ -631,7 +633,7 @@ async function runServer(options) {
631
633
  }
632
634
  }
633
635
  consola.box(`🌐 Usage Viewer: https://ericc-ch.github.io/copilot-api?endpoint=${serverUrl}/usage`);
634
- const { server } = await import("./server-D05YP0C0.js");
636
+ const { server } = await import("./server-B3FY9yH2.js");
635
637
  serve({
636
638
  fetch: server.fetch,
637
639
  port: options.port,
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":["ACCOUNT_TYPE_VALUES: ReadonlyArray<AccountType>","accountType: AccountType","accountToRemove: { id: string; index: number } | undefined","process","commandBlock: string","accountType: AccountType"],"sources":["../src/lib/types/account.ts","../src/services/github/get-device-code.ts","../src/services/github/poll-access-token.ts","../src/auth.ts","../src/lib/token.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/proxy.ts","../src/lib/shell.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\n/**\n * Account type for GitHub Copilot subscription.\n */\nexport type AccountType = \"individual\" | \"business\" | \"enterprise\"\n\nexport const ACCOUNT_TYPE_VALUES: ReadonlyArray<AccountType> = [\n \"individual\",\n \"business\",\n \"enterprise\",\n]\n\nexport function isAccountType(value: unknown): value is AccountType {\n return (\n typeof value === \"string\"\n && (ACCOUNT_TYPE_VALUES as ReadonlyArray<string>).includes(value)\n )\n}\n\nexport function parseAccountType(value: unknown): AccountType {\n if (!isAccountType(value)) {\n throw new Error(\n `Invalid account type: ${String(value)}. Valid values: ${ACCOUNT_TYPE_VALUES.join(\n \", \",\n )}`,\n )\n }\n return value\n}\n\n/**\n * Metadata for a registered account, stored in the registry file.\n */\nexport interface AccountMeta {\n /** GitHub login (username) */\n id: string\n /** Account subscription type */\n accountType: AccountType\n /** Timestamp when the account was added */\n addedAt: number\n}\n\n/**\n * Registry file structure for storing account metadata.\n */\nexport interface AccountRegistry {\n /** Schema version for future migrations */\n version: 1\n /** Ordered list of accounts (order = priority) */\n accounts: Array<AccountMeta>\n}\n\n/**\n * Runtime state for an account, including tokens and quota information.\n */\nexport interface AccountRuntime extends AccountMeta {\n /** GitHub personal access token */\n githubToken: string\n /** Copilot API token (obtained from GitHub) */\n copilotToken?: string\n /** VS Code version for API headers */\n vsCodeVersion?: string\n /** Cached available models for this account */\n models?: ModelsResponse\n /** Total premium interactions quota entitlement */\n premiumEntitlement?: number\n /** Remaining premium interactions quota */\n premiumRemaining?: number\n /** Reserved premium interaction units for in-flight requests */\n premiumReserved?: number\n /** Internal reservation map for idempotent release */\n premiumReservations?: Map<symbol, number>\n /** Whether this account has unlimited quota */\n unlimited?: boolean\n /** Timestamp of last quota fetch */\n lastQuotaFetch?: number\n /** Token refresh timer reference */\n refreshTimer?: ReturnType<typeof setInterval>\n /** Whether this account has failed (e.g., 401 error) */\n failed?: boolean\n /** Failure reason if failed */\n failureReason?: string\n /** Whether quota refresh is in progress (prevents concurrent refreshes) */\n isRefreshingQuota?: boolean\n /** Promise for an in-flight quota refresh (allows concurrent callers to await the same refresh) */\n quotaRefreshPromise?: Promise<void>\n}\n\n/**\n * Context required for making API calls on behalf of an account.\n * This is a subset of AccountRuntime used by service functions.\n */\nexport interface AccountContext {\n /** GitHub personal access token */\n githubToken: string\n /** Copilot API token */\n copilotToken?: string\n /** Account subscription type */\n accountType: AccountType\n /** VS Code version for API headers */\n vsCodeVersion?: 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\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\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 })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\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 consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\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 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 },\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 }\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport {\n addAccountToRegistry,\n listAccountsFromRegistry,\n loadAccountToken,\n removeAccountFromRegistry,\n removeAccountToken,\n saveAccountToken,\n saveRegistry,\n} from \"./lib/accounts-registry\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport {\n parseAccountType,\n type AccountMeta,\n type AccountType,\n} from \"./lib/types/account\"\nimport { getCopilotUsage } from \"./services/github/get-copilot-usage\"\nimport { getDeviceCode } from \"./services/github/get-device-code\"\nimport { getGitHubUser } from \"./services/github/get-user\"\nimport { pollAccessToken } from \"./services/github/poll-access-token\"\n\n/**\n * Fetch quota info for an account (used by auth ls -q)\n */\nasync function fetchQuotaInfo(account: AccountMeta): Promise<string> {\n try {\n const token = await loadAccountToken(account.id)\n if (!token) {\n return \" | Quota: (no token)\"\n }\n\n const usage = await getCopilotUsage({\n githubToken: token,\n accountType: account.accountType,\n })\n const premium = usage.quota_snapshots.premium_interactions\n\n return premium.unlimited ?\n \" | Quota: unlimited\"\n : ` | Quota: ${premium.remaining}/${premium.entitlement}`\n } catch (error) {\n consola.debug(`Failed to fetch quota for ${account.id}:`, error)\n return \" | Quota: (failed to fetch)\"\n }\n}\n\n/**\n * auth add - Add a new GitHub Copilot account\n */\nconst authAdd = defineCommand({\n meta: {\n name: \"add\",\n description: \"Add a new GitHub Copilot account\",\n },\n args: {\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type (individual, business, enterprise)\",\n },\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 after auth\",\n },\n },\n async run({ args }) {\n if (args.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = args[\"show-token\"]\n\n let accountType: AccountType\n try {\n accountType = parseAccountType(args[\"account-type\"])\n } catch (error) {\n consola.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n\n await ensurePaths()\n\n // Start device code flow\n consola.info(\"Starting GitHub device code authentication...\")\n const deviceResponse = await getDeviceCode()\n consola.debug(\"Device code response:\", deviceResponse)\n\n consola.info(\n `Please enter the code \"${deviceResponse.user_code}\" at ${deviceResponse.verification_uri}`,\n )\n\n // Poll for access token\n const token = await pollAccessToken(deviceResponse)\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n\n // Get user info to determine account ID\n const user = await getGitHubUser({ githubToken: token, accountType })\n const accountId = user.login\n\n // Save token and check if account already exists\n await saveAccountToken(accountId, token)\n const existingAccounts = await listAccountsFromRegistry()\n const alreadyExists = existingAccounts.some((acc) => acc.id === accountId)\n\n if (alreadyExists) {\n // Touch registry file so a running server can hot-reload updated tokens.\n await saveRegistry({ version: 1, accounts: existingAccounts })\n\n consola.success(\n `Account \"${accountId}\" already exists. Token has been updated.`,\n )\n } else {\n await addAccountToRegistry({\n id: accountId,\n accountType,\n addedAt: Date.now(),\n })\n consola.success(`Account \"${accountId}\" added successfully!`)\n }\n\n consola.info(`Account type: ${accountType}`)\n },\n})\n\n/**\n * auth ls - List all registered accounts\n */\nconst authLs = defineCommand({\n meta: {\n name: \"ls\",\n description: \"List all registered accounts\",\n },\n args: {\n \"show-quota\": {\n alias: \"q\",\n type: \"boolean\",\n default: false,\n description: \"Show quota information (requires API call)\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n },\n async run({ args }) {\n if (args.verbose) {\n consola.level = 5\n }\n\n await ensurePaths()\n\n const accounts = await listAccountsFromRegistry()\n\n if (accounts.length === 0) {\n consola.info(\"No accounts registered. Use 'auth add' to add an account.\")\n return\n }\n\n consola.info(`Found ${accounts.length} account(s):\\n`)\n\n for (const [i, account] of accounts.entries()) {\n const addedDate = new Date(account.addedAt).toLocaleString()\n\n const quotaInfo = args[\"show-quota\"] ? await fetchQuotaInfo(account) : \"\"\n\n console.log(\n ` ${i + 1}. ${account.id} (${account.accountType})${quotaInfo}`,\n )\n console.log(` Added: ${addedDate}\\n`)\n }\n },\n})\n\n/**\n * auth rm - Remove an account\n */\nconst authRm = defineCommand({\n meta: {\n name: \"rm\",\n description: \"Remove an account\",\n },\n args: {\n target: {\n type: \"positional\",\n description: \"Account ID or index (1-based)\",\n required: true,\n },\n force: {\n alias: \"f\",\n type: \"boolean\",\n default: false,\n description: \"Skip confirmation prompt\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n },\n async run({ args }) {\n if (args.verbose) {\n consola.level = 5\n }\n\n await ensurePaths()\n\n const target = args.target\n const accounts = await listAccountsFromRegistry()\n\n if (accounts.length === 0) {\n consola.error(\"No accounts to remove.\")\n return\n }\n\n // Determine account to remove (by ID or index)\n let accountToRemove: { id: string; index: number } | undefined\n\n // Try parsing as index (1-based)\n const index = Number.parseInt(target, 10)\n if (!Number.isNaN(index) && index >= 1 && index <= accounts.length) {\n accountToRemove = { id: accounts[index - 1].id, index: index - 1 }\n } else {\n // Try finding by ID\n const foundIndex = accounts.findIndex((acc) => acc.id === target)\n if (foundIndex !== -1) {\n accountToRemove = { id: accounts[foundIndex].id, index: foundIndex }\n }\n }\n\n if (!accountToRemove) {\n consola.error(`Account \"${target}\" not found.`)\n consola.info(\"Use 'auth ls' to see available accounts.\")\n return\n }\n\n // Confirmation\n if (!args.force) {\n const confirmed = await consola.prompt(\n `Are you sure you want to remove account \"${accountToRemove.id}\"?`,\n { type: \"confirm\" },\n )\n if (!confirmed) {\n consola.info(\"Cancelled.\")\n return\n }\n }\n\n // Remove token file and registry entry\n await removeAccountToken(accountToRemove.id)\n await removeAccountFromRegistry(accountToRemove.id)\n\n consola.success(`Account \"${accountToRemove.id}\" removed.`)\n },\n})\n\n/**\n * Main auth command with subcommands\n */\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Manage GitHub Copilot accounts\",\n },\n subCommands: {\n add: authAdd,\n ls: authLs,\n rm: authRm,\n },\n args: {\n // Legacy args for backward compatibility (when no subcommand)\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type (individual, business, enterprise)\",\n },\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 after auth\",\n },\n },\n async run(ctx) {\n // Check if a subcommand was specified in rawArgs.\n // Only treat the *first* raw arg as a subcommand to avoid false positives\n // when flags accept values like \"add\"/\"ls\"/\"rm\".\n const firstArg = ctx.rawArgs[0]\n const hasSubCommand =\n firstArg === \"add\" || firstArg === \"ls\" || firstArg === \"rm\"\n\n // Backward compatibility: if no subcommand, run 'add'\n if (!hasSubCommand && authAdd.run) {\n await authAdd.run(ctx)\n }\n },\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","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 // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\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 consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\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","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { accountsManager } from \"./lib/accounts-manager\"\nimport { addAccountToRegistry, saveAccountToken } from \"./lib/accounts-registry\"\nimport {\n isFreeModelLoadBalancingEnabled,\n mergeConfigWithDefaults,\n} from \"./lib/config\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { parseAccountType, type AccountType } from \"./lib/types/account\"\nimport { cacheVSCodeVersion } from \"./lib/utils\"\nimport { getDeviceCode } from \"./services/github/get-device-code\"\nimport { getGitHubUser } from \"./services/github/get-user\"\nimport { pollAccessToken } from \"./services/github/poll-access-token\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: AccountType\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\n/**\n * Run the interactive authentication flow to add a new account.\n * Called automatically when no accounts are found.\n */\nasync function runAuthFlow(accountType: AccountType): Promise<void> {\n consola.warn(\"No accounts found. Starting authentication flow...\")\n\n // Start device code flow\n const deviceResponse = await getDeviceCode()\n consola.info(\n `Please enter the code \"${deviceResponse.user_code}\" at ${deviceResponse.verification_uri}`,\n )\n\n // Poll for access token\n const token = await pollAccessToken(deviceResponse)\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n\n // Get user info to determine account ID\n const user = await getGitHubUser({\n githubToken: token,\n accountType,\n })\n const accountId = user.login\n\n // Save token and add to registry\n await saveAccountToken(accountId, token)\n await addAccountToRegistry({\n id: accountId,\n accountType,\n addedAt: Date.now(),\n })\n\n consola.success(`Account \"${accountId}\" added successfully!`)\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n // Ensure config is merged with defaults at startup\n mergeConfigWithDefaults()\n accountsManager.setFreeModelLoadBalancingEnabled(\n isFreeModelLoadBalancingEnabled(),\n )\n\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n state.verbose = options.verbose\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\n await ensurePaths()\n await cacheVSCodeVersion()\n\n // Initialize accounts manager with VS Code version\n await accountsManager.initialize(state.vsCodeVersion)\n\n // If --github-token is provided, set it as a temporary (high priority) account\n if (options.githubToken) {\n await accountsManager.setTemporaryAccount(\n options.githubToken,\n options.accountType,\n )\n consola.info(\"Using provided GitHub token as temporary account\")\n }\n\n // Check if we have any accounts, if not, start the auth flow\n if (!accountsManager.hasAccounts()) {\n try {\n await runAuthFlow(options.accountType)\n\n // Re-initialize accounts manager with the new account\n accountsManager.shutdown()\n await accountsManager.initialize(state.vsCodeVersion)\n } catch (error) {\n consola.error(\"Failed to add account:\", error)\n process.exit(1)\n }\n }\n\n // Get models from the first available account\n const models = accountsManager.getFirstAccountModels()\n\n consola.info(\n `Available models: \\n${models?.data.map((model) => `- ${model.id}`).join(\"\\n\") ?? \"(no models loaded)\"}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) {\n invariant(models, \"Models should be loaded by now\")\n\n const selectedModel = await consola.prompt(\n \"Select a model to use with Claude Code\",\n {\n type: \"select\",\n options: models.data.map((model) => model.id),\n },\n )\n\n const selectedSmallModel = await consola.prompt(\n \"Select a small model to use with Claude Code\",\n {\n type: \"select\",\n options: models.data.map((model) => model.id),\n },\n )\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\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 const { server } = await import(\"./server\")\n\n serve({\n fetch: server.fetch as ServerHandler,\n port: options.port,\n bun: {\n idleTimeout: 0,\n },\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 \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\",\n default: false,\n description: \"Initialize proxy from environment variables\",\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 let accountType: AccountType\n try {\n accountType = parseAccountType(args[\"account-type\"])\n } catch (error) {\n consola.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n\n return runServer({\n port: Number.parseInt(args.port, 10),\n verbose: args.verbose,\n accountType,\n manual: args.manual,\n rateLimit,\n rateLimitWait: args.wait,\n githubToken: args[\"github-token\"],\n claudeCode: args[\"claude-code\"],\n showToken: args[\"show-token\"],\n proxyEnv: args[\"proxy-env\"],\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":["ACCOUNT_TYPE_VALUES: ReadonlyArray<AccountType>","accountType: AccountType","accountToRemove: { id: string; index: number } | undefined","process","commandBlock: string","accountType: AccountType"],"sources":["../src/lib/types/account.ts","../src/services/github/get-device-code.ts","../src/services/github/poll-access-token.ts","../src/auth.ts","../src/lib/token.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/proxy.ts","../src/lib/shell.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\n/**\n * Account type for GitHub Copilot subscription.\n */\nexport type AccountType = \"individual\" | \"business\" | \"enterprise\"\n\nexport const ACCOUNT_TYPE_VALUES: ReadonlyArray<AccountType> = [\n \"individual\",\n \"business\",\n \"enterprise\",\n]\n\nexport function isAccountType(value: unknown): value is AccountType {\n return (\n typeof value === \"string\"\n && (ACCOUNT_TYPE_VALUES as ReadonlyArray<string>).includes(value)\n )\n}\n\nexport function parseAccountType(value: unknown): AccountType {\n if (!isAccountType(value)) {\n throw new Error(\n `Invalid account type: ${String(value)}. Valid values: ${ACCOUNT_TYPE_VALUES.join(\n \", \",\n )}`,\n )\n }\n return value\n}\n\n/**\n * Metadata for a registered account, stored in the registry file.\n */\nexport interface AccountMeta {\n /** GitHub login (username) */\n id: string\n /** Account subscription type */\n accountType: AccountType\n /** Timestamp when the account was added */\n addedAt: number\n}\n\n/**\n * Registry file structure for storing account metadata.\n */\nexport interface AccountRegistry {\n /** Schema version for future migrations */\n version: 1\n /** Ordered list of accounts (order = priority) */\n accounts: Array<AccountMeta>\n}\n\n/**\n * Runtime state for an account, including tokens and quota information.\n */\nexport interface AccountRuntime extends AccountMeta {\n /** GitHub personal access token */\n githubToken: string\n /** Copilot API token (obtained from GitHub) */\n copilotToken?: string\n /** VS Code version for API headers */\n vsCodeVersion?: string\n /** Cached available models for this account */\n models?: ModelsResponse\n /** Timestamp of last models fetch */\n lastModelsFetch?: number\n /** Whether models refresh is in progress */\n isRefreshingModels?: boolean\n /** Promise for an in-flight models refresh */\n modelsRefreshPromise?: Promise<void>\n /** Total premium interactions quota entitlement */\n premiumEntitlement?: number\n /** Remaining premium interactions quota */\n premiumRemaining?: number\n /** Reserved premium interaction units for in-flight requests */\n premiumReserved?: number\n /** Internal reservation map for idempotent release */\n premiumReservations?: Map<symbol, number>\n /** Whether this account has unlimited quota */\n unlimited?: boolean\n /** Timestamp of last quota fetch */\n lastQuotaFetch?: number\n /** Token refresh timer reference */\n refreshTimer?: ReturnType<typeof setInterval>\n /** Whether this account has failed (e.g., 401 error) */\n failed?: boolean\n /** Failure reason if failed */\n failureReason?: string\n /** Whether quota refresh is in progress (prevents concurrent refreshes) */\n isRefreshingQuota?: boolean\n /** Promise for an in-flight quota refresh (allows concurrent callers to await the same refresh) */\n quotaRefreshPromise?: Promise<void>\n}\n\n/**\n * Context required for making API calls on behalf of an account.\n * This is a subset of AccountRuntime used by service functions.\n */\nexport interface AccountContext {\n /** GitHub personal access token */\n githubToken: string\n /** Copilot API token */\n copilotToken?: string\n /** Account subscription type */\n accountType: AccountType\n /** VS Code version for API headers */\n vsCodeVersion?: 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\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\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 })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\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 consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\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 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 },\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 }\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport {\n addAccountToRegistry,\n listAccountsFromRegistry,\n loadAccountToken,\n removeAccountFromRegistry,\n removeAccountToken,\n saveAccountToken,\n saveRegistry,\n} from \"./lib/accounts-registry\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport {\n parseAccountType,\n type AccountMeta,\n type AccountType,\n} from \"./lib/types/account\"\nimport { getCopilotUsage } from \"./services/github/get-copilot-usage\"\nimport { getDeviceCode } from \"./services/github/get-device-code\"\nimport { getGitHubUser } from \"./services/github/get-user\"\nimport { pollAccessToken } from \"./services/github/poll-access-token\"\n\n/**\n * Fetch quota info for an account (used by auth ls -q)\n */\nasync function fetchQuotaInfo(account: AccountMeta): Promise<string> {\n try {\n const token = await loadAccountToken(account.id)\n if (!token) {\n return \" | Quota: (no token)\"\n }\n\n const usage = await getCopilotUsage({\n githubToken: token,\n accountType: account.accountType,\n })\n const premium = usage.quota_snapshots.premium_interactions\n\n return premium.unlimited ?\n \" | Quota: unlimited\"\n : ` | Quota: ${premium.remaining}/${premium.entitlement}`\n } catch (error) {\n consola.debug(`Failed to fetch quota for ${account.id}:`, error)\n return \" | Quota: (failed to fetch)\"\n }\n}\n\n/**\n * auth add - Add a new GitHub Copilot account\n */\nconst authAdd = defineCommand({\n meta: {\n name: \"add\",\n description: \"Add a new GitHub Copilot account\",\n },\n args: {\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type (individual, business, enterprise)\",\n },\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 after auth\",\n },\n },\n async run({ args }) {\n if (args.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = args[\"show-token\"]\n\n let accountType: AccountType\n try {\n accountType = parseAccountType(args[\"account-type\"])\n } catch (error) {\n consola.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n\n await ensurePaths()\n\n // Start device code flow\n consola.info(\"Starting GitHub device code authentication...\")\n const deviceResponse = await getDeviceCode()\n consola.debug(\"Device code response:\", deviceResponse)\n\n consola.info(\n `Please enter the code \"${deviceResponse.user_code}\" at ${deviceResponse.verification_uri}`,\n )\n\n // Poll for access token\n const token = await pollAccessToken(deviceResponse)\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n\n // Get user info to determine account ID\n const user = await getGitHubUser({ githubToken: token, accountType })\n const accountId = user.login\n\n // Save token and check if account already exists\n await saveAccountToken(accountId, token)\n const existingAccounts = await listAccountsFromRegistry()\n const alreadyExists = existingAccounts.some((acc) => acc.id === accountId)\n\n if (alreadyExists) {\n // Touch registry file so a running server can hot-reload updated tokens.\n await saveRegistry({ version: 1, accounts: existingAccounts })\n\n consola.success(\n `Account \"${accountId}\" already exists. Token has been updated.`,\n )\n } else {\n await addAccountToRegistry({\n id: accountId,\n accountType,\n addedAt: Date.now(),\n })\n consola.success(`Account \"${accountId}\" added successfully!`)\n }\n\n consola.info(`Account type: ${accountType}`)\n },\n})\n\n/**\n * auth ls - List all registered accounts\n */\nconst authLs = defineCommand({\n meta: {\n name: \"ls\",\n description: \"List all registered accounts\",\n },\n args: {\n \"show-quota\": {\n alias: \"q\",\n type: \"boolean\",\n default: false,\n description: \"Show quota information (requires API call)\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n },\n async run({ args }) {\n if (args.verbose) {\n consola.level = 5\n }\n\n await ensurePaths()\n\n const accounts = await listAccountsFromRegistry()\n\n if (accounts.length === 0) {\n consola.info(\"No accounts registered. Use 'auth add' to add an account.\")\n return\n }\n\n consola.info(`Found ${accounts.length} account(s):\\n`)\n\n for (const [i, account] of accounts.entries()) {\n const addedDate = new Date(account.addedAt).toLocaleString()\n\n const quotaInfo = args[\"show-quota\"] ? await fetchQuotaInfo(account) : \"\"\n\n console.log(\n ` ${i + 1}. ${account.id} (${account.accountType})${quotaInfo}`,\n )\n console.log(` Added: ${addedDate}\\n`)\n }\n },\n})\n\n/**\n * auth rm - Remove an account\n */\nconst authRm = defineCommand({\n meta: {\n name: \"rm\",\n description: \"Remove an account\",\n },\n args: {\n target: {\n type: \"positional\",\n description: \"Account ID or index (1-based)\",\n required: true,\n },\n force: {\n alias: \"f\",\n type: \"boolean\",\n default: false,\n description: \"Skip confirmation prompt\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n },\n async run({ args }) {\n if (args.verbose) {\n consola.level = 5\n }\n\n await ensurePaths()\n\n const target = args.target\n const accounts = await listAccountsFromRegistry()\n\n if (accounts.length === 0) {\n consola.error(\"No accounts to remove.\")\n return\n }\n\n // Determine account to remove (by ID or index)\n let accountToRemove: { id: string; index: number } | undefined\n\n // Try parsing as index (1-based)\n const index = Number.parseInt(target, 10)\n if (!Number.isNaN(index) && index >= 1 && index <= accounts.length) {\n accountToRemove = { id: accounts[index - 1].id, index: index - 1 }\n } else {\n // Try finding by ID\n const foundIndex = accounts.findIndex((acc) => acc.id === target)\n if (foundIndex !== -1) {\n accountToRemove = { id: accounts[foundIndex].id, index: foundIndex }\n }\n }\n\n if (!accountToRemove) {\n consola.error(`Account \"${target}\" not found.`)\n consola.info(\"Use 'auth ls' to see available accounts.\")\n return\n }\n\n // Confirmation\n if (!args.force) {\n const confirmed = await consola.prompt(\n `Are you sure you want to remove account \"${accountToRemove.id}\"?`,\n { type: \"confirm\" },\n )\n if (!confirmed) {\n consola.info(\"Cancelled.\")\n return\n }\n }\n\n // Remove token file and registry entry\n await removeAccountToken(accountToRemove.id)\n await removeAccountFromRegistry(accountToRemove.id)\n\n consola.success(`Account \"${accountToRemove.id}\" removed.`)\n },\n})\n\n/**\n * Main auth command with subcommands\n */\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Manage GitHub Copilot accounts\",\n },\n subCommands: {\n add: authAdd,\n ls: authLs,\n rm: authRm,\n },\n args: {\n // Legacy args for backward compatibility (when no subcommand)\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type (individual, business, enterprise)\",\n },\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 after auth\",\n },\n },\n async run(ctx) {\n // Check if a subcommand was specified in rawArgs.\n // Only treat the *first* raw arg as a subcommand to avoid false positives\n // when flags accept values like \"add\"/\"ls\"/\"rm\".\n const firstArg = ctx.rawArgs[0]\n const hasSubCommand =\n firstArg === \"add\" || firstArg === \"ls\" || firstArg === \"rm\"\n\n // Backward compatibility: if no subcommand, run 'add'\n if (!hasSubCommand && authAdd.run) {\n await authAdd.run(ctx)\n }\n },\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","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 // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\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 consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\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","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { accountsManager } from \"./lib/accounts-manager\"\nimport { addAccountToRegistry, saveAccountToken } from \"./lib/accounts-registry\"\nimport {\n getModelRefreshIntervalMs,\n isFreeModelLoadBalancingEnabled,\n mergeConfigWithDefaults,\n} from \"./lib/config\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { parseAccountType, type AccountType } from \"./lib/types/account\"\nimport { cacheVSCodeVersion } from \"./lib/utils\"\nimport { getDeviceCode } from \"./services/github/get-device-code\"\nimport { getGitHubUser } from \"./services/github/get-user\"\nimport { pollAccessToken } from \"./services/github/poll-access-token\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: AccountType\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\n/**\n * Run the interactive authentication flow to add a new account.\n * Called automatically when no accounts are found.\n */\nasync function runAuthFlow(accountType: AccountType): Promise<void> {\n consola.warn(\"No accounts found. Starting authentication flow...\")\n\n // Start device code flow\n const deviceResponse = await getDeviceCode()\n consola.info(\n `Please enter the code \"${deviceResponse.user_code}\" at ${deviceResponse.verification_uri}`,\n )\n\n // Poll for access token\n const token = await pollAccessToken(deviceResponse)\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n\n // Get user info to determine account ID\n const user = await getGitHubUser({\n githubToken: token,\n accountType,\n })\n const accountId = user.login\n\n // Save token and add to registry\n await saveAccountToken(accountId, token)\n await addAccountToRegistry({\n id: accountId,\n accountType,\n addedAt: Date.now(),\n })\n\n consola.success(`Account \"${accountId}\" added successfully!`)\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n // Ensure config is merged with defaults at startup\n mergeConfigWithDefaults()\n accountsManager.setFreeModelLoadBalancingEnabled(\n isFreeModelLoadBalancingEnabled(),\n )\n accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs())\n\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n state.verbose = options.verbose\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\n await ensurePaths()\n await cacheVSCodeVersion()\n\n // Initialize accounts manager with VS Code version\n await accountsManager.initialize(state.vsCodeVersion)\n\n // If --github-token is provided, set it as a temporary (high priority) account\n if (options.githubToken) {\n await accountsManager.setTemporaryAccount(\n options.githubToken,\n options.accountType,\n )\n consola.info(\"Using provided GitHub token as temporary account\")\n }\n\n // Check if we have any accounts, if not, start the auth flow\n if (!accountsManager.hasAccounts()) {\n try {\n await runAuthFlow(options.accountType)\n\n // Re-initialize accounts manager with the new account\n accountsManager.shutdown()\n await accountsManager.initialize(state.vsCodeVersion)\n accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs())\n } catch (error) {\n consola.error(\"Failed to add account:\", error)\n process.exit(1)\n }\n }\n\n // Get models from the first available account\n const models = accountsManager.getFirstAccountModels()\n\n consola.info(\n `Available models: \\n${models?.data.map((model) => `- ${model.id}`).join(\"\\n\") ?? \"(no models loaded)\"}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) {\n invariant(models, \"Models should be loaded by now\")\n\n const selectedModel = await consola.prompt(\n \"Select a model to use with Claude Code\",\n {\n type: \"select\",\n options: models.data.map((model) => model.id),\n },\n )\n\n const selectedSmallModel = await consola.prompt(\n \"Select a small model to use with Claude Code\",\n {\n type: \"select\",\n options: models.data.map((model) => model.id),\n },\n )\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\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 const { server } = await import(\"./server\")\n\n serve({\n fetch: server.fetch as ServerHandler,\n port: options.port,\n bun: {\n idleTimeout: 0,\n },\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 \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\",\n default: false,\n description: \"Initialize proxy from environment variables\",\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 let accountType: AccountType\n try {\n accountType = parseAccountType(args[\"account-type\"])\n } catch (error) {\n consola.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n }\n\n return runServer({\n port: Number.parseInt(args.port, 10),\n verbose: args.verbose,\n accountType,\n manual: args.manual,\n rateLimit,\n rateLimitWait: args.wait,\n githubToken: args[\"github-token\"],\n claudeCode: args[\"claude-code\"],\n showToken: args[\"show-token\"],\n proxyEnv: args[\"proxy-env\"],\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,4 +1,4 @@
1
- import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isNullish, listAccountsFromRegistry, mergeConfigWithDefaults, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-CxuKJ4qv.js";
1
+ import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, listAccountsFromRegistry, mergeConfigWithDefaults, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-CJtqVqDx.js";
2
2
  import consola from "consola";
3
3
  import fs, { readFile } from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -714,7 +714,9 @@ const CONFIG_KEYS = new Set([
714
714
  "allowOriginalModelNamesForAliases",
715
715
  "useFunctionApplyPatch",
716
716
  "forceAgent",
717
- "compactUseSmallModel"
717
+ "compactUseSmallModel",
718
+ "messageStartInputTokensFallback",
719
+ "modelRefreshIntervalHours"
718
720
  ]);
719
721
  const REASONING_EFFORTS = new Set([
720
722
  "none",
@@ -747,6 +749,12 @@ function parseOptionalBoolean(value, field) {
747
749
  if (typeof value !== "boolean") return { error: `${field} must be a boolean` };
748
750
  return { value };
749
751
  }
752
+ function parseOptionalNonNegativeNumber(value, field) {
753
+ if (value === null || value === void 0) return { clear: true };
754
+ if (typeof value !== "number") return { error: `${field} must be a number` };
755
+ if (!Number.isFinite(value) || value < 0) return { error: `${field} must be a non-negative number` };
756
+ return { value };
757
+ }
750
758
  function parseStringRecord(value, field) {
751
759
  if (value === null || value === void 0) return { clear: true };
752
760
  if (!isPlainObject(value)) return { error: `${field} must be an object with string values` };
@@ -831,6 +839,15 @@ function applyOptionalBoolean(next, key, value) {
831
839
  }
832
840
  next[key] = parsed.value;
833
841
  }
842
+ function applyOptionalNumber(next, key, value) {
843
+ const parsed = parseOptionalNonNegativeNumber(value, key);
844
+ if ("error" in parsed) return parsed.error;
845
+ if ("clear" in parsed) {
846
+ next[key] = void 0;
847
+ return;
848
+ }
849
+ next[key] = parsed.value;
850
+ }
834
851
  function applyExtraPrompts(next, value) {
835
852
  const parsed = parseStringRecord(value, "extraPrompts");
836
853
  if ("error" in parsed) return parsed.error;
@@ -895,6 +912,12 @@ function applyConfigPatch(base, input) {
895
912
  case "compactUseSmallModel":
896
913
  error = applyOptionalBoolean(next, "compactUseSmallModel", value);
897
914
  break;
915
+ case "messageStartInputTokensFallback":
916
+ error = applyOptionalBoolean(next, "messageStartInputTokensFallback", value);
917
+ break;
918
+ case "modelRefreshIntervalHours":
919
+ error = applyOptionalNumber(next, "modelRefreshIntervalHours", value);
920
+ break;
898
921
  default: return { error: `Unsupported config key: ${rawKey}` };
899
922
  }
900
923
  if (error) return { error };
@@ -966,6 +989,7 @@ adminApiRoutes.post("/config", async (c) => {
966
989
  await writeConfigFile(result.config);
967
990
  const merged = mergeConfigWithDefaults();
968
991
  accountsManager.setFreeModelLoadBalancingEnabled(isFreeModelLoadBalancingEnabled());
992
+ accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
969
993
  return c.json({
970
994
  ...merged,
971
995
  _configPath: PATHS.CONFIG_PATH
@@ -990,6 +1014,102 @@ adminApiRoutes.get("/models", (c) => {
990
1014
  });
991
1015
  }
992
1016
  });
1017
+ function parseNonEmptyString(value) {
1018
+ if (typeof value !== "string") return null;
1019
+ const trimmed = value.trim();
1020
+ return trimmed.length > 0 ? trimmed : null;
1021
+ }
1022
+ function parseOptionalFiniteNumber(value) {
1023
+ if (typeof value !== "number") return void 0;
1024
+ return Number.isFinite(value) ? value : void 0;
1025
+ }
1026
+ function toBooleanOrUndefined(value) {
1027
+ return typeof value === "boolean" ? value : void 0;
1028
+ }
1029
+ function parseStringArray(value) {
1030
+ if (!Array.isArray(value)) return void 0;
1031
+ const out = value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
1032
+ return out.length > 0 ? out : void 0;
1033
+ }
1034
+ function parseBilling(value) {
1035
+ if (!isPlainObject(value)) return void 0;
1036
+ const multiplier = parseOptionalFiniteNumber(value.multiplier);
1037
+ const is_premium = toBooleanOrUndefined(value.is_premium);
1038
+ if (multiplier === void 0 && is_premium === void 0) return void 0;
1039
+ return {
1040
+ multiplier,
1041
+ is_premium
1042
+ };
1043
+ }
1044
+ function parseCapabilities(value) {
1045
+ if (!isPlainObject(value)) return {
1046
+ limits: {},
1047
+ supports: {}
1048
+ };
1049
+ const limitsRaw = isPlainObject(value.limits) ? value.limits : void 0;
1050
+ const supportsRaw = isPlainObject(value.supports) ? value.supports : void 0;
1051
+ return {
1052
+ limits: {
1053
+ max_context_window_tokens: parseOptionalFiniteNumber(limitsRaw?.max_context_window_tokens),
1054
+ max_prompt_tokens: parseOptionalFiniteNumber(limitsRaw?.max_prompt_tokens),
1055
+ max_output_tokens: parseOptionalFiniteNumber(limitsRaw?.max_output_tokens)
1056
+ },
1057
+ supports: {
1058
+ tool_calls: toBooleanOrUndefined(supportsRaw?.tool_calls),
1059
+ parallel_tool_calls: toBooleanOrUndefined(supportsRaw?.parallel_tool_calls),
1060
+ structured_outputs: toBooleanOrUndefined(supportsRaw?.structured_outputs),
1061
+ streaming: toBooleanOrUndefined(supportsRaw?.streaming),
1062
+ vision: toBooleanOrUndefined(supportsRaw?.vision)
1063
+ }
1064
+ };
1065
+ }
1066
+ function parseAdminModelDetailsItem(raw, aliasesByTarget) {
1067
+ if (!isPlainObject(raw)) return null;
1068
+ const id = parseNonEmptyString(raw.id);
1069
+ if (!id) return null;
1070
+ const name = parseNonEmptyString(raw.name) ?? id;
1071
+ const preview = toBooleanOrUndefined(raw.preview) ?? false;
1072
+ return {
1073
+ id,
1074
+ name,
1075
+ preview,
1076
+ billing: parseBilling(raw.billing),
1077
+ supported_endpoints: parseStringArray(raw.supported_endpoints),
1078
+ capabilities: parseCapabilities(raw.capabilities),
1079
+ aliases: aliasesByTarget.get(id.toLowerCase()) ?? []
1080
+ };
1081
+ }
1082
+ adminApiRoutes.get("/models/details", (c) => {
1083
+ try {
1084
+ const accountModels = accountsManager.getFirstAccountModels();
1085
+ const aliasInfo = getModelAliasesInfo();
1086
+ const aliasesByTarget = /* @__PURE__ */ new Map();
1087
+ for (const [alias, spec] of Object.entries(aliasInfo)) {
1088
+ const targetKey = spec.target.toLowerCase();
1089
+ const current = aliasesByTarget.get(targetKey);
1090
+ if (current) current.push(alias);
1091
+ else aliasesByTarget.set(targetKey, [alias]);
1092
+ }
1093
+ for (const aliases of aliasesByTarget.values()) aliases.sort();
1094
+ const rawModels = [];
1095
+ if (Array.isArray(accountModels?.data)) rawModels.push(...accountModels.data);
1096
+ const itemsById = /* @__PURE__ */ new Map();
1097
+ for (const raw of rawModels) {
1098
+ const item = parseAdminModelDetailsItem(raw, aliasesByTarget);
1099
+ if (!item) continue;
1100
+ if (itemsById.has(item.id)) continue;
1101
+ itemsById.set(item.id, item);
1102
+ }
1103
+ const items = Array.from(itemsById.values()).sort((a, b) => a.id.localeCompare(b.id));
1104
+ return c.json({ items });
1105
+ } catch (error) {
1106
+ console.error("Failed to load model details.", error);
1107
+ return jsonError(c, 500, {
1108
+ message: "Failed to load model details.",
1109
+ type: "internal_error"
1110
+ });
1111
+ }
1112
+ });
993
1113
  adminApiRoutes.get("/accounts", async (c) => {
994
1114
  const url = new URL(c.req.url, "http://local");
995
1115
  const sinceMs = Number(url.searchParams.get("since_ms") ?? "");
@@ -3151,7 +3271,15 @@ const isWarmupProbeRequest = (payload) => {
3151
3271
  if (!lastMsg || lastMsg.role !== "user" || !Array.isArray(lastMsg.content)) return false;
3152
3272
  const lastBlock = lastMsg.content.at(-1);
3153
3273
  if (!lastBlock || lastBlock.type !== "text") return false;
3154
- return lastBlock.text.trim().toLowerCase() === "warmup" && lastBlock.cache_control?.type === "ephemeral";
3274
+ const text = lastBlock.text.trim().toLowerCase();
3275
+ if (!(lastBlock.cache_control?.type === "ephemeral")) return false;
3276
+ if (text === "warmup") return true;
3277
+ if (text === "hello") {
3278
+ const preludeBlocks = lastMsg.content.slice(0, -1);
3279
+ if (preludeBlocks.length === 0) return false;
3280
+ return preludeBlocks.every((block) => block.type === "text" && block.text.trimStart().toLowerCase().startsWith("<system-reminder"));
3281
+ }
3282
+ return false;
3155
3283
  };
3156
3284
  const handleSelectionFailure = (context) => {
3157
3285
  const { c, store, requestId, startedAtMs, method, path: path$2, streamRequested, clientModel, clientIp, clientIpSource, userAgent, userId, safetyIdentifier, promptCacheKey, initiator, selection } = context;
@@ -3934,7 +4062,8 @@ const createMessages = async (payload, account, options) => {
3934
4062
  ...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
3935
4063
  "X-Initiator": initiator
3936
4064
  };
3937
- if (options?.anthropicBetaHeader) headers["anthropic-beta"] = options.anthropicBetaHeader;
4065
+ const filteredBeta = options?.anthropicBetaHeader?.split(",").map((item) => item.trim()).filter((item) => item !== "claude-code-20250219").join(",");
4066
+ if (filteredBeta) headers["anthropic-beta"] = filteredBeta;
3938
4067
  else if (payload.thinking?.budget_tokens) headers["anthropic-beta"] = "interleaved-thinking-2025-05-14";
3939
4068
  const response = await fetch(`${copilotBaseUrl(ctx)}/v1/messages`, {
3940
4069
  method: "POST",
@@ -4319,7 +4448,8 @@ async function handleCompletion(c) {
4319
4448
  c,
4320
4449
  anthropicPayload,
4321
4450
  anthropicBetaHeader: anthropicBeta ?? void 0,
4322
- instr
4451
+ instr,
4452
+ selectedModel
4323
4453
  });
4324
4454
  if (endpoint === RESPONSES_ENDPOINT$1) return await handleWithResponsesApi({
4325
4455
  c,
@@ -4359,8 +4489,9 @@ const handleWithChatCompletions = async (params) => {
4359
4489
  instr
4360
4490
  });
4361
4491
  logger$2.debug("Streaming response from Copilot");
4362
- const estimatedInputTokens = await estimateInputTokens(openAIPayload, selectedModel, logger$2);
4363
- const historicalUsage = instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
4492
+ const fallbackEnabled = isMessageStartInputTokensFallbackEnabled();
4493
+ const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$2) : void 0;
4494
+ const historicalUsage = fallbackEnabled && instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
4364
4495
  promptCacheKey: instr.promptCacheKey,
4365
4496
  safetyIdentifier: instr.safetyIdentifier,
4366
4497
  clientModel: instr.clientModel
@@ -4398,8 +4529,9 @@ const handleWithResponsesApi = async (params) => {
4398
4529
  }
4399
4530
  if (responsesPayload.stream && isAsyncIterable$1(response)) {
4400
4531
  logger$2.debug("Streaming response from Copilot (Responses API)");
4401
- const estimatedInputTokens = await estimateInputTokens(openAIPayload, selectedModel, logger$2);
4402
- const historicalUsage = instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
4532
+ const fallbackEnabled = isMessageStartInputTokensFallbackEnabled();
4533
+ const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$2) : void 0;
4534
+ const historicalUsage = fallbackEnabled && instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
4403
4535
  promptCacheKey: instr.promptCacheKey,
4404
4536
  safetyIdentifier: instr.safetyIdentifier,
4405
4537
  clientModel: instr.clientModel
@@ -4837,11 +4969,16 @@ async function streamMessagesAndLog(params) {
4837
4969
  }
4838
4970
  }
4839
4971
  const handleWithMessagesApi = async (params) => {
4840
- const { c, anthropicPayload, anthropicBetaHeader, instr } = params;
4972
+ const { c, anthropicPayload, anthropicBetaHeader, instr, selectedModel } = params;
4841
4973
  for (const msg of anthropicPayload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
4842
4974
  if (block.type !== "thinking") return true;
4843
4975
  return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
4844
4976
  });
4977
+ if (selectedModel.capabilities.supports.adaptive_thinking) {
4978
+ anthropicPayload.thinking = { type: "adaptive" };
4979
+ anthropicPayload.output_config = { effort: getAnthropicEffortForModel(anthropicPayload.model) };
4980
+ }
4981
+ logger$2.debug("Translated Messages payload:", JSON.stringify(anthropicPayload));
4845
4982
  const ctx = toAccountContext(instr.account);
4846
4983
  const upstreamRequestId = randomUUID();
4847
4984
  instr.initiator = getMessagesInitiator(anthropicPayload);
@@ -4875,6 +5012,12 @@ const handleWithMessagesApi = async (params) => {
4875
5012
  };
4876
5013
  const isNonStreaming = (response) => Object.hasOwn(response, "choices");
4877
5014
  const isAsyncIterable$1 = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
5015
+ const getAnthropicEffortForModel = (model) => {
5016
+ const reasoningEffort = getReasoningEffortForModel(model);
5017
+ if (reasoningEffort === "xhigh") return "max";
5018
+ if (reasoningEffort === "none" || reasoningEffort === "minimal") return "low";
5019
+ return reasoningEffort;
5020
+ };
4878
5021
  const isCompactRequest = (anthropicPayload) => {
4879
5022
  const system = anthropicPayload.system;
4880
5023
  if (typeof system === "string") return system.startsWith(compactSystemPromptStart);
@@ -5510,4 +5653,4 @@ server.route("/v1/messages", messageRoutes);
5510
5653
 
5511
5654
  //#endregion
5512
5655
  export { server };
5513
- //# sourceMappingURL=server-D05YP0C0.js.map
5656
+ //# sourceMappingURL=server-B3FY9yH2.js.map