@nick3/copilot-api 1.4.6 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{account-DhQb2A6q.js → account-CipKmikF.js} +2 -2
- package/dist/account-CipKmikF.js.map +1 -0
- package/dist/{accounts-manager-B8Y2Y4ab.js → accounts-manager-DhwGrhHF.js} +40 -43
- package/dist/accounts-manager-DhwGrhHF.js.map +1 -0
- package/dist/{accounts-registry-c7rs5Ed9.js → accounts-registry-CQYvRe65.js} +3 -3
- package/dist/{accounts-registry-c7rs5Ed9.js.map → accounts-registry-CQYvRe65.js.map} +1 -1
- package/dist/admin/assets/{index-BFvCJZIK.js → index-B-G_GrPI.js} +7 -7
- package/dist/admin/index.html +1 -1
- package/dist/{auth-Bt0FGr8C.js → auth-BtUQnU2m.js} +6 -6
- package/dist/{auth-Bt0FGr8C.js.map → auth-BtUQnU2m.js.map} +1 -1
- package/dist/{check-usage-By-sJOch.js → check-usage-DiomC9Dl.js} +6 -5
- package/dist/check-usage-DiomC9Dl.js.map +1 -0
- package/dist/{debug-hQJWwXtC.js → debug-BzR5ZQUk.js} +3 -3
- package/dist/{debug-hQJWwXtC.js.map → debug-BzR5ZQUk.js.map} +1 -1
- package/dist/{get-copilot-token-Q4FXtOE9.js → get-copilot-token-DN1P6qll.js} +3 -3
- package/dist/{get-copilot-token-Q4FXtOE9.js.map → get-copilot-token-DN1P6qll.js.map} +1 -1
- package/dist/main.js +6 -7
- package/dist/main.js.map +1 -1
- package/dist/{paths-DoT4SZ8f.js → paths-Cvzy-eLX.js} +2 -2
- package/dist/{paths-DoT4SZ8f.js.map → paths-Cvzy-eLX.js.map} +1 -1
- package/dist/{poll-access-token-Cp_DfHGH.js → poll-access-token-BrRUFB1F.js} +3 -3
- package/dist/{poll-access-token-Cp_DfHGH.js.map → poll-access-token-BrRUFB1F.js.map} +1 -1
- package/dist/{server-Cln-GCLU.js → server-D9M_wFyO.js} +86 -105
- package/dist/server-D9M_wFyO.js.map +1 -0
- package/dist/{start-DH-QnZxL.js → start-D3yEfZnW.js} +15 -17
- package/dist/{start-DH-QnZxL.js.map → start-D3yEfZnW.js.map} +1 -1
- package/dist/{utils-SV0FyqXk.js → utils-53JWve7i.js} +52 -19
- package/dist/utils-53JWve7i.js.map +1 -0
- package/package.json +3 -1
- package/dist/account-DhQb2A6q.js.map +0 -1
- package/dist/accounts-manager-B8Y2Y4ab.js.map +0 -1
- package/dist/check-usage-By-sJOch.js.map +0 -1
- package/dist/server-Cln-GCLU.js.map +0 -1
- package/dist/utils-SV0FyqXk.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ensurePaths } from "./paths-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { parseAccountType } from "./account-
|
|
5
|
-
import { getDeviceCode, pollAccessToken } from "./poll-access-token-
|
|
6
|
-
import "./get-copilot-token-
|
|
7
|
-
import {
|
|
1
|
+
import { r as ensurePaths } from "./paths-Cvzy-eLX.js";
|
|
2
|
+
import { l as saveAccountToken, t as addAccountToRegistry } from "./accounts-registry-CQYvRe65.js";
|
|
3
|
+
import { D as state, f as getGitHubUser, i as cacheVsCodeSessionId, r as cacheVSCodeVersion, t as cacheMacMachineId } from "./utils-53JWve7i.js";
|
|
4
|
+
import { t as parseAccountType } from "./account-CipKmikF.js";
|
|
5
|
+
import { n as getDeviceCode, t as pollAccessToken } from "./poll-access-token-BrRUFB1F.js";
|
|
6
|
+
import "./get-copilot-token-DN1P6qll.js";
|
|
7
|
+
import { b as mergeConfigWithDefaults, m as isAccountAffinityEnabled, t as accountsManager, u as getModelRefreshIntervalMs } from "./accounts-manager-DhwGrhHF.js";
|
|
8
8
|
import { defineCommand } from "citty";
|
|
9
9
|
import consola from "consola";
|
|
10
10
|
import clipboard from "clipboardy";
|
|
@@ -66,8 +66,7 @@ function getShell() {
|
|
|
66
66
|
const { platform, ppid, env } = process$1;
|
|
67
67
|
if (platform === "win32") {
|
|
68
68
|
try {
|
|
69
|
-
|
|
70
|
-
if (execSync(command, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
|
|
69
|
+
if (execSync(`wmic process get ParentProcessId,Name | findstr "${ppid}"`, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
|
|
71
70
|
} catch {
|
|
72
71
|
return "cmd";
|
|
73
72
|
}
|
|
@@ -145,16 +144,15 @@ async function setupClaudeCode(models, serverUrl) {
|
|
|
145
144
|
type: "select",
|
|
146
145
|
options: models.data.map((model) => model.id)
|
|
147
146
|
});
|
|
148
|
-
const selectedSmallModel = await consola.prompt("Select a small model to use with Claude Code", {
|
|
149
|
-
type: "select",
|
|
150
|
-
options: models.data.map((model) => model.id)
|
|
151
|
-
});
|
|
152
147
|
const command = generateEnvScript({
|
|
153
148
|
ANTHROPIC_BASE_URL: serverUrl,
|
|
154
149
|
ANTHROPIC_AUTH_TOKEN: "dummy",
|
|
155
150
|
ANTHROPIC_MODEL: selectedModel,
|
|
156
151
|
ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,
|
|
157
|
-
ANTHROPIC_DEFAULT_HAIKU_MODEL:
|
|
152
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: await consola.prompt("Select a small model to use with Claude Code", {
|
|
153
|
+
type: "select",
|
|
154
|
+
options: models.data.map((model) => model.id)
|
|
155
|
+
}),
|
|
158
156
|
DISABLE_NON_ESSENTIAL_MODEL_CALLS: "1",
|
|
159
157
|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
|
|
160
158
|
CLAUDE_CODE_ATTRIBUTION_HEADER: "0",
|
|
@@ -211,7 +209,7 @@ async function runServer(options) {
|
|
|
211
209
|
await setupClaudeCode(models, serverUrl);
|
|
212
210
|
}
|
|
213
211
|
consola.box(`🌐 Admin UI: ${serverUrl}/admin`);
|
|
214
|
-
const { server } = await import("./server-
|
|
212
|
+
const { server } = await import("./server-D9M_wFyO.js");
|
|
215
213
|
serve({
|
|
216
214
|
fetch: server.fetch,
|
|
217
215
|
port: options.port,
|
|
@@ -306,5 +304,5 @@ const start = defineCommand({
|
|
|
306
304
|
});
|
|
307
305
|
|
|
308
306
|
//#endregion
|
|
309
|
-
export { start };
|
|
310
|
-
//# sourceMappingURL=start-
|
|
307
|
+
export { runServer, start };
|
|
308
|
+
//# sourceMappingURL=start-D3yEfZnW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-DH-QnZxL.js","names":["process","commandBlock: string","accountType: AccountType"],"sources":["../src/lib/proxy.ts","../src/lib/shell.ts","../src/start.ts"],"sourcesContent":["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 isAccountAffinityEnabled,\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 {\n cacheMacMachineId,\n cacheVSCodeVersion,\n cacheVsCodeSessionId,\n} 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\nfunction logClaudeCodeTip(): void {\n consola.log(\n \"\\n💡 Tip: The --claude-code flag simply generates a clipboard command for launching Claude Code. \\n\"\n + \"All models remain fully accessible without this flag, just configure the model ID directly in your settings.json file.\",\n )\n}\n\ntype AvailableModels = NonNullable<\n ReturnType<typeof accountsManager.getFirstAccountModels>\n>\n\nasync function setupClaudeCode(\n models: AvailableModels,\n serverUrl: string,\n): Promise<void> {\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_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n CLAUDE_CODE_ATTRIBUTION_HEADER: \"0\",\n CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION: \"false\",\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\nexport async function runServer(options: RunServerOptions): Promise<void> {\n // Ensure config is merged with defaults at startup\n mergeConfigWithDefaults()\n accountsManager.setAccountAffinityEnabled(isAccountAffinityEnabled())\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 cacheMacMachineId()\n cacheVsCodeSessionId()\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 logClaudeCodeTip()\n invariant(models, \"Models should be loaded by now\")\n await setupClaudeCode(models, serverUrl)\n }\n\n consola.box(`🌐 Admin UI: ${serverUrl}/admin`)\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"start-D3yEfZnW.js","names":["process","commandBlock: string","accountType: AccountType"],"sources":["../src/lib/proxy.ts","../src/lib/shell.ts","../src/start.ts"],"sourcesContent":["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 isAccountAffinityEnabled,\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 {\n cacheMacMachineId,\n cacheVSCodeVersion,\n cacheVsCodeSessionId,\n} 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\nfunction logClaudeCodeTip(): void {\n consola.log(\n \"\\n💡 Tip: The --claude-code flag simply generates a clipboard command for launching Claude Code. \\n\"\n + \"All models remain fully accessible without this flag, just configure the model ID directly in your settings.json file.\",\n )\n}\n\ntype AvailableModels = NonNullable<\n ReturnType<typeof accountsManager.getFirstAccountModels>\n>\n\nasync function setupClaudeCode(\n models: AvailableModels,\n serverUrl: string,\n): Promise<void> {\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_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n CLAUDE_CODE_ATTRIBUTION_HEADER: \"0\",\n CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION: \"false\",\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\nexport async function runServer(options: RunServerOptions): Promise<void> {\n // Ensure config is merged with defaults at startup\n mergeConfigWithDefaults()\n accountsManager.setAccountAffinityEnabled(isAccountAffinityEnabled())\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 cacheMacMachineId()\n cacheVsCodeSessionId()\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 logClaudeCodeTip()\n invariant(models, \"Models should be loaded by now\")\n await setupClaudeCode(models, serverUrl)\n }\n\n consola.box(`🌐 Admin UI: ${serverUrl}/admin`)\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"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { PATHS } from "./paths-
|
|
1
|
+
import { t as PATHS } from "./paths-Cvzy-eLX.js";
|
|
2
2
|
import consola from "consola";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import { networkInterfaces } from "node:os";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
7
|
|
|
7
8
|
//#region src/lib/state.ts
|
|
8
9
|
const state = {
|
|
@@ -22,11 +23,30 @@ function accountFromState() {
|
|
|
22
23
|
return {
|
|
23
24
|
githubToken: state.githubToken,
|
|
24
25
|
copilotToken: state.copilotToken,
|
|
26
|
+
...state.copilotApiUrl !== void 0 ? { copilotApiUrl: state.copilotApiUrl } : {},
|
|
25
27
|
accountType: state.accountType,
|
|
26
28
|
vsCodeVersion: state.vsCodeVersion
|
|
27
29
|
};
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/lib/request-context.ts
|
|
34
|
+
const TRACE_ID_MAX_LENGTH = 64;
|
|
35
|
+
const TRACE_ID_PATTERN = /^\w[\w.-]*$/;
|
|
36
|
+
const asyncLocalStorage = new AsyncLocalStorage();
|
|
37
|
+
const requestContext = {
|
|
38
|
+
getStore: () => asyncLocalStorage.getStore(),
|
|
39
|
+
run: (context, callback) => asyncLocalStorage.run(context, callback)
|
|
40
|
+
};
|
|
41
|
+
function generateTraceId() {
|
|
42
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
43
|
+
}
|
|
44
|
+
function resolveTraceId(traceId) {
|
|
45
|
+
const candidate = traceId?.trim();
|
|
46
|
+
if (!candidate || candidate.length > TRACE_ID_MAX_LENGTH || !TRACE_ID_PATTERN.test(candidate)) return generateTraceId();
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
49
|
+
|
|
30
50
|
//#endregion
|
|
31
51
|
//#region src/lib/api-config.ts
|
|
32
52
|
const isOpencodeOauthApp = () => {
|
|
@@ -52,9 +72,15 @@ const getOpencodeOauthHeaders = () => {
|
|
|
52
72
|
return {
|
|
53
73
|
Accept: "application/json",
|
|
54
74
|
"Content-Type": "application/json",
|
|
55
|
-
"User-Agent": "opencode/1.3.
|
|
75
|
+
"User-Agent": "opencode/1.3.9 ai-sdk/provider-utils/4.0.21 runtime/bun/1.3.11, opencode/1.3.9"
|
|
56
76
|
};
|
|
57
77
|
};
|
|
78
|
+
const normalizeOpencodeUserAgent = (userAgent) => {
|
|
79
|
+
const candidate = userAgent.trim();
|
|
80
|
+
const opencodeProduct = candidate.match(/^opencode\/[^\s,]+/u)?.[0];
|
|
81
|
+
if (!opencodeProduct || candidate.includes(`, ${opencodeProduct}`)) return candidate;
|
|
82
|
+
return `${candidate}, ${opencodeProduct}`;
|
|
83
|
+
};
|
|
58
84
|
const getOauthUrls = () => {
|
|
59
85
|
const githubBaseUrl = getGitHubBaseUrl();
|
|
60
86
|
return {
|
|
@@ -96,6 +122,8 @@ const API_VERSION = "2025-10-01";
|
|
|
96
122
|
const copilotBaseUrl = (account) => {
|
|
97
123
|
const enterpriseDomain = getEnterpriseDomain();
|
|
98
124
|
if (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;
|
|
125
|
+
if (isOpencodeOauthApp()) return "https://api.githubcopilot.com";
|
|
126
|
+
if (account.copilotApiUrl) return account.copilotApiUrl;
|
|
99
127
|
return account.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${account.accountType}.githubcopilot.com`;
|
|
100
128
|
};
|
|
101
129
|
const copilotHeaders = (account, vision = false, requestId) => {
|
|
@@ -105,6 +133,8 @@ const copilotHeaders = (account, vision = false, requestId) => {
|
|
|
105
133
|
...getOpencodeOauthHeaders(),
|
|
106
134
|
"Openai-Intent": "conversation-edits"
|
|
107
135
|
};
|
|
136
|
+
const userAgent = requestContext.getStore()?.userAgent.trim();
|
|
137
|
+
if (userAgent?.startsWith("opencode/")) headers$1["User-Agent"] = normalizeOpencodeUserAgent(userAgent);
|
|
108
138
|
if (vision) headers$1["Copilot-Vision-Request"] = "true";
|
|
109
139
|
return headers$1;
|
|
110
140
|
}
|
|
@@ -129,15 +159,21 @@ const copilotHeaders = (account, vision = false, requestId) => {
|
|
|
129
159
|
return headers;
|
|
130
160
|
};
|
|
131
161
|
const GITHUB_API_BASE_URL = "https://api.github.com";
|
|
132
|
-
const githubHeaders = (account) =>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
162
|
+
const githubHeaders = (account) => {
|
|
163
|
+
if (isOpencodeOauthApp()) return {
|
|
164
|
+
Authorization: `Bearer ${account.githubToken}`,
|
|
165
|
+
...getOpencodeOauthHeaders()
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
...standardHeaders(),
|
|
169
|
+
authorization: `token ${account.githubToken}`,
|
|
170
|
+
"editor-version": `vscode/${account.vsCodeVersion}`,
|
|
171
|
+
"editor-plugin-version": EDITOR_PLUGIN_VERSION,
|
|
172
|
+
"user-agent": USER_AGENT,
|
|
173
|
+
"x-github-api-version": API_VERSION,
|
|
174
|
+
"x-vscode-user-agent-library-version": "electron-fetch"
|
|
175
|
+
};
|
|
176
|
+
};
|
|
141
177
|
const GITHUB_BASE_URL = "https://github.com";
|
|
142
178
|
const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
|
|
143
179
|
const GITHUB_APP_SCOPES = ["read:user"].join(" ");
|
|
@@ -281,8 +317,7 @@ const stopVsCodeSessionRefreshLoop = () => {
|
|
|
281
317
|
}
|
|
282
318
|
};
|
|
283
319
|
const scheduleSessionIdRefresh = () => {
|
|
284
|
-
const
|
|
285
|
-
const delay = SESSION_REFRESH_BASE_MS + randomDelay;
|
|
320
|
+
const delay = SESSION_REFRESH_BASE_MS + Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS);
|
|
286
321
|
consola.debug(`Scheduling next VSCode session ID refresh in ${Math.round(delay / 1e3)} seconds`);
|
|
287
322
|
stopVsCodeSessionRefreshLoop();
|
|
288
323
|
vsCodeSessionRefreshTimer = setTimeout(() => {
|
|
@@ -321,11 +356,9 @@ const parseUserIdMetadata = (userId) => {
|
|
|
321
356
|
const legacySafetyIdentifier = userId.match(/user_([^_]+)_account/)?.[1] ?? null;
|
|
322
357
|
const legacySessionId = userId.match(/_session_(.+)$/)?.[1] ?? null;
|
|
323
358
|
const parsedUserId = legacySafetyIdentifier && legacySessionId ? null : parseJsonUserId(userId);
|
|
324
|
-
const safetyIdentifier = legacySafetyIdentifier ?? getUserIdJsonField(parsedUserId, "device_id") ?? getUserIdJsonField(parsedUserId, "account_uuid");
|
|
325
|
-
const sessionId = legacySessionId ?? getUserIdJsonField(parsedUserId, "session_id");
|
|
326
359
|
return {
|
|
327
|
-
safetyIdentifier,
|
|
328
|
-
sessionId
|
|
360
|
+
safetyIdentifier: legacySafetyIdentifier ?? getUserIdJsonField(parsedUserId, "device_id") ?? getUserIdJsonField(parsedUserId, "account_uuid"),
|
|
361
|
+
sessionId: legacySessionId ?? getUserIdJsonField(parsedUserId, "session_id")
|
|
329
362
|
};
|
|
330
363
|
};
|
|
331
364
|
const findLastUserContent = (messages) => {
|
|
@@ -366,5 +399,5 @@ const getUUID = (content) => {
|
|
|
366
399
|
};
|
|
367
400
|
|
|
368
401
|
//#endregion
|
|
369
|
-
export {
|
|
370
|
-
//# sourceMappingURL=utils-
|
|
402
|
+
export { prepareInteractionHeaders as C, state as D, accountFromState as E, prepareForCompact as S, resolveTraceId as T, copilotHeaders as _, generateRequestIdFromPayload as a, getOauthUrls as b, isNullish as c, getModels as d, getGitHubUser as f, copilotBaseUrl as g, forwardError as h, cacheVsCodeSessionId as i, parseUserIdMetadata as l, HTTPError as m, cacheModels as n, getRootSessionId as o, getCopilotUsage as p, cacheVSCodeVersion as r, getUUID as s, cacheMacMachineId as t, sleep as u, getGitHubApiBaseUrl as v, requestContext as w, githubHeaders as x, getOauthAppConfig as y };
|
|
403
|
+
//# sourceMappingURL=utils-53JWve7i.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-53JWve7i.js","names":["state: State","headers: Record<string, string>","headers","errorJson: unknown","vsCodeSessionRefreshTimer: ReturnType<typeof setTimeout> | null","parsed: unknown"],"sources":["../src/lib/state.ts","../src/lib/request-context.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-usage.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts"],"sourcesContent":["import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nimport type { AccountContext, AccountType } from \"./types/account\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: AccountType\n models?: ModelsResponse\n vsCodeVersion?: string\n\n macMachineId?: string\n vsCodeSessionId?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n verbose: boolean\n\n copilotApiUrl?: string\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n verbose: false,\n}\n\n/**\n * Create an AccountContext from the current global state.\n * This is a compatibility layer for transitioning to multi-account support.\n * @throws Error if githubToken is not set in state\n */\nexport function accountFromState(): AccountContext {\n if (!state.githubToken) {\n throw new Error(\"GitHub token not set in state\")\n }\n return {\n githubToken: state.githubToken,\n copilotToken: state.copilotToken,\n ...(state.copilotApiUrl !== undefined ?\n { copilotApiUrl: state.copilotApiUrl }\n : {}),\n accountType: state.accountType,\n vsCodeVersion: state.vsCodeVersion,\n }\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\"\n\nexport interface RequestContext {\n traceId: string\n startTime: number\n userAgent: string\n}\n\nconst TRACE_ID_MAX_LENGTH = 64\nconst TRACE_ID_PATTERN = /^\\w[\\w.-]*$/\n\nconst asyncLocalStorage = new AsyncLocalStorage<RequestContext>()\n\nexport const requestContext = {\n getStore: () => asyncLocalStorage.getStore(),\n run: <T>(context: RequestContext, callback: () => T) =>\n asyncLocalStorage.run(context, callback),\n}\n\nexport function generateTraceId(): string {\n const timestamp = Date.now().toString(36)\n const random = Math.random().toString(36).slice(2, 8)\n return `${timestamp}-${random}`\n}\n\nexport function resolveTraceId(traceId: string | null | undefined): string {\n const candidate = traceId?.trim()\n\n if (\n !candidate\n || candidate.length > TRACE_ID_MAX_LENGTH\n || !TRACE_ID_PATTERN.test(candidate)\n ) {\n return generateTraceId()\n }\n\n return candidate\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { AccountContext } from \"./types/account\"\n\nimport { requestContext } from \"./request-context\"\nimport { state } from \"./state\"\n\nexport const isOpencodeOauthApp = (): boolean => {\n return process.env.COPILOT_API_OAUTH_APP?.trim() === \"opencode\"\n}\n\nexport const normalizeDomain = (input: string): string => {\n return input\n .trim()\n .replace(/^https?:\\/\\//u, \"\")\n .replace(/\\/+$/u, \"\")\n}\n\nexport const getEnterpriseDomain = (): string | null => {\n const raw = (process.env.COPILOT_API_ENTERPRISE_URL ?? \"\").trim()\n if (!raw) return null\n const normalized = normalizeDomain(raw)\n return normalized || null\n}\n\nexport const getGitHubBaseUrl = (): string => {\n const resolvedDomain = getEnterpriseDomain()\n return resolvedDomain ? `https://${resolvedDomain}` : GITHUB_BASE_URL\n}\n\nexport const getGitHubApiBaseUrl = (): string => {\n const resolvedDomain = getEnterpriseDomain()\n return resolvedDomain ? `https://api.${resolvedDomain}` : GITHUB_API_BASE_URL\n}\n\nconst getOpencodeOauthHeaders = (): Record<string, string> => {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\":\n \"opencode/1.3.9 ai-sdk/provider-utils/4.0.21 runtime/bun/1.3.11, opencode/1.3.9\",\n }\n}\n\nconst normalizeOpencodeUserAgent = (userAgent: string): string => {\n const candidate = userAgent.trim()\n const opencodeProduct = candidate.match(/^opencode\\/[^\\s,]+/u)?.[0]\n\n if (!opencodeProduct || candidate.includes(`, ${opencodeProduct}`)) {\n return candidate\n }\n\n return `${candidate}, ${opencodeProduct}`\n}\n\nexport const getOauthUrls = (): {\n deviceCodeUrl: string\n accessTokenUrl: string\n} => {\n const githubBaseUrl = getGitHubBaseUrl()\n\n return {\n deviceCodeUrl: `${githubBaseUrl}/login/device/code`,\n accessTokenUrl: `${githubBaseUrl}/login/oauth/access_token`,\n }\n}\n\ninterface OauthAppConfig {\n clientId: string\n headers: Record<string, string>\n scope: string\n}\n\nexport const getOauthAppConfig = (): OauthAppConfig => {\n if (isOpencodeOauthApp()) {\n return {\n clientId: OPENCODE_GITHUB_CLIENT_ID,\n headers: getOpencodeOauthHeaders(),\n scope: GITHUB_APP_SCOPES,\n }\n }\n\n return {\n clientId: GITHUB_CLIENT_ID,\n headers: standardHeaders(),\n scope: GITHUB_APP_SCOPES,\n }\n}\n\nexport const prepareForCompact = (\n headers: Record<string, string>,\n isCompact?: boolean,\n) => {\n if (isCompact) {\n headers[\"x-initiator\"] = \"agent\"\n }\n}\n\nexport const prepareInteractionHeaders = (\n sessionId: string | undefined,\n isSubagent: boolean,\n headers: Record<string, string>,\n) => {\n const sendInteractionHeaders = !isOpencodeOauthApp()\n\n if (isSubagent) {\n headers[\"x-initiator\"] = \"agent\"\n if (sendInteractionHeaders) {\n headers[\"x-interaction-type\"] = \"conversation-subagent\"\n }\n }\n\n if (sessionId && sendInteractionHeaders) {\n headers[\"x-interaction-id\"] = sessionId\n }\n}\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\nconst API_VERSION = \"2025-10-01\"\n\nexport const copilotBaseUrl = (account: AccountContext): string => {\n const enterpriseDomain = getEnterpriseDomain()\n if (enterpriseDomain) {\n return `https://copilot-api.${enterpriseDomain}`\n }\n\n if (isOpencodeOauthApp()) {\n return \"https://api.githubcopilot.com\"\n }\n\n if (account.copilotApiUrl) {\n return account.copilotApiUrl\n }\n\n return account.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${account.accountType}.githubcopilot.com`\n}\n\nexport const copilotHeaders = (\n account: AccountContext,\n vision: boolean = false,\n requestId?: string,\n) => {\n if (isOpencodeOauthApp()) {\n const token = account.copilotToken ?? account.githubToken\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n ...getOpencodeOauthHeaders(),\n \"Openai-Intent\": \"conversation-edits\",\n }\n\n const userAgent = requestContext.getStore()?.userAgent.trim()\n if (userAgent?.startsWith(\"opencode/\")) {\n headers[\"User-Agent\"] = normalizeOpencodeUserAgent(userAgent)\n }\n\n if (vision) headers[\"Copilot-Vision-Request\"] = \"true\"\n\n return headers\n }\n\n const resolvedRequestId = requestId ?? randomUUID()\n const headers: Record<string, string> = {\n Authorization: `Bearer ${account.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": \"vscode-chat\",\n \"editor-version\": `vscode/${account.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-agent\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": resolvedRequestId,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n \"x-agent-task-id\": resolvedRequestId,\n \"x-interaction-type\": \"conversation-agent\",\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n if (state.macMachineId) {\n headers[\"vscode-machineid\"] = state.macMachineId\n }\n\n if (state.vsCodeSessionId) {\n headers[\"vscode-sessionid\"] = state.vsCodeSessionId\n }\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (account: AccountContext) => {\n if (isOpencodeOauthApp()) {\n return {\n Authorization: `Bearer ${account.githubToken}`,\n ...getOpencodeOauthHeaders(),\n }\n }\n\n return {\n ...standardHeaders(),\n authorization: `token ${account.githubToken}`,\n \"editor-version\": `vscode/${account.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}\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\nexport const OPENCODE_GITHUB_CLIENT_ID = \"Ov23li8tweQw6odWQebz\"\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n if (error.response.status === 429) {\n for (const [name, value] of error.response.headers) {\n const lowerName = name.toLowerCase()\n if (lowerName === \"retry-after\" || lowerName.startsWith(\"x-\")) {\n c.header(name, value)\n }\n }\n }\n\n const errorText = await error.response.text()\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = errorText\n }\n consola.error(\"HTTP error:\", errorJson)\n return c.json(\n {\n error: {\n message: errorText,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: (error as Error).message,\n type: \"error\",\n },\n },\n 500,\n )\n}\n","import type { AccountContext } from \"~/lib/types/account\"\n\nimport { getGitHubApiBaseUrl, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { accountFromState } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (\n account?: AccountContext,\n): Promise<CopilotUsageResponse> => {\n const ctx = account ?? accountFromState()\n const response = await fetch(\n `${getGitHubApiBaseUrl()}/copilot_internal/user`,\n {\n headers: githubHeaders(ctx),\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 login: string\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 endpoints: {\n api: string\n telemetry: string\n }\n}\n","import type { AccountContext } from \"~/lib/types/account\"\n\nimport { getGitHubApiBaseUrl, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser(account?: AccountContext) {\n // Use provided account or fall back to state (for legacy compatibility)\n const token = account?.githubToken ?? state.githubToken\n if (!token) {\n throw new Error(\"GitHub token not set\")\n }\n\n const response = await fetch(`${getGitHubApiBaseUrl()}/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\nexport interface GithubUserResponse {\n login: string\n}\n","import fs from \"node:fs/promises\"\n\nimport type { AccountContext } from \"~/lib/types/account\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { PATHS } from \"~/lib/paths\"\nimport { accountFromState } from \"~/lib/state\"\n\nexport const getModels = async (account?: AccountContext) => {\n const ctx = account ?? accountFromState()\n const response = await fetch(`${copilotBaseUrl(ctx)}/models`, {\n headers: copilotHeaders(ctx),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n const models = (await response.json()) as ModelsResponse\n\n // Persist models response for debugging/inspection.\n // Best effort: do not fail startup if the local write fails.\n try {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await fs.writeFile(\n PATHS.MODELS_PATH,\n `${JSON.stringify(models, null, 2)}\\n`,\n {\n encoding: \"utf8\",\n mode: 0o600,\n },\n )\n } catch {\n // ignore\n }\n\n return models\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 max_thinking_budget?: number\n min_thinking_budget?: number\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n streaming?: boolean\n structured_outputs?: boolean\n vision?: boolean\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\ninterface ModelBilling {\n is_premium?: boolean\n multiplier?: number\n}\n\nexport interface Model {\n billing?: ModelBilling\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 supported_endpoints?: Array<string>\n}\n","const FALLBACK = \"1.110.1\"\n\nexport async function getVSCodeVersion() {\n await Promise.resolve()\n return FALLBACK\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { createHash, randomUUID } from \"node:crypto\"\nimport { networkInterfaces } from \"node:os\"\n\nimport type { AnthropicMessagesPayload } from \"~/routes/messages/anthropic-types\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = {\n ...models,\n data: models.data.filter(\n (model) =>\n model.model_picker_enabled || model.capabilities.type === \"embeddings\",\n ),\n }\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\nconst invalidMacAddresses = new Set([\n \"00:00:00:00:00:00\",\n \"ff:ff:ff:ff:ff:ff\",\n \"ac:de:48:00:11:22\",\n])\n\nfunction validateMacAddress(candidate: string): boolean {\n const tempCandidate = candidate.replaceAll(\"-\", \":\").toLowerCase()\n return !invalidMacAddresses.has(tempCandidate)\n}\n\nexport function getMac(): string | null {\n const ifaces = networkInterfaces()\n // eslint-disable-next-line guard-for-in\n for (const name in ifaces) {\n const networkInterface = ifaces[name]\n if (networkInterface) {\n for (const { mac } of networkInterface) {\n if (validateMacAddress(mac)) {\n return mac\n }\n }\n }\n }\n return null\n}\n\nexport const cacheMacMachineId = () => {\n const macAddress = getMac() ?? randomUUID()\n state.macMachineId = createHash(\"sha256\")\n .update(macAddress, \"utf8\")\n .digest(\"hex\")\n consola.debug(`Using machine ID: ${state.macMachineId}`)\n}\n\nconst SESSION_REFRESH_BASE_MS = 60 * 60 * 1000\nconst SESSION_REFRESH_JITTER_MS = 20 * 60 * 1000\nlet vsCodeSessionRefreshTimer: ReturnType<typeof setTimeout> | null = null\n\nconst generateSessionId = () => {\n state.vsCodeSessionId = randomUUID() + Date.now().toString()\n consola.debug(`Generated VSCode session ID: ${state.vsCodeSessionId}`)\n}\n\nexport const stopVsCodeSessionRefreshLoop = () => {\n if (vsCodeSessionRefreshTimer) {\n clearTimeout(vsCodeSessionRefreshTimer)\n vsCodeSessionRefreshTimer = null\n }\n}\n\nconst scheduleSessionIdRefresh = () => {\n const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS)\n const delay = SESSION_REFRESH_BASE_MS + randomDelay\n consola.debug(\n `Scheduling next VSCode session ID refresh in ${Math.round(\n delay / 1000,\n )} seconds`,\n )\n\n stopVsCodeSessionRefreshLoop()\n vsCodeSessionRefreshTimer = setTimeout(() => {\n try {\n generateSessionId()\n } catch (error) {\n consola.error(\"Failed to refresh session ID, rescheduling...\", error)\n } finally {\n scheduleSessionIdRefresh()\n }\n }, delay)\n}\n\nexport const cacheVsCodeSessionId = () => {\n stopVsCodeSessionRefreshLoop()\n generateSessionId()\n scheduleSessionIdRefresh()\n}\n\ninterface PayloadMessage {\n role?: string\n content?: string | Array<{ type?: string; text?: string }> | null\n type?: string\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null\n\nconst getUserIdJsonField = (\n userIdPayload: Record<string, unknown> | null,\n field: string,\n): string | null => {\n const value = userIdPayload?.[field]\n return typeof value === \"string\" && value.length > 0 ? value : null\n}\n\nconst parseJsonUserId = (userId: string): Record<string, unknown> | null => {\n try {\n const parsed: unknown = JSON.parse(userId)\n return isRecord(parsed) ? parsed : null\n } catch {\n return null\n }\n}\n\nexport const parseUserIdMetadata = (\n userId: string | undefined,\n): { safetyIdentifier: string | null; sessionId: string | null } => {\n if (!userId || typeof userId !== \"string\") {\n return { safetyIdentifier: null, sessionId: null }\n }\n\n const legacySafetyIdentifier =\n userId.match(/user_([^_]+)_account/)?.[1] ?? null\n const legacySessionId = userId.match(/_session_(.+)$/)?.[1] ?? null\n\n const parsedUserId =\n legacySafetyIdentifier && legacySessionId ? null : parseJsonUserId(userId)\n\n const safetyIdentifier =\n legacySafetyIdentifier\n ?? getUserIdJsonField(parsedUserId, \"device_id\")\n ?? getUserIdJsonField(parsedUserId, \"account_uuid\")\n const sessionId =\n legacySessionId ?? getUserIdJsonField(parsedUserId, \"session_id\")\n\n return { safetyIdentifier, sessionId }\n}\n\nconst findLastUserContent = (\n messages: Array<PayloadMessage>,\n): string | null => {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\" && msg.content) {\n if (typeof msg.content === \"string\") {\n return msg.content\n } else if (Array.isArray(msg.content)) {\n const array = msg.content\n .filter((n) => n.type !== \"tool_result\")\n .map((n) => ({ ...n, cache_control: undefined }))\n if (array.length > 0) {\n return JSON.stringify(array)\n }\n }\n }\n }\n return null\n}\n\nexport const generateRequestIdFromPayload = (\n payload: {\n messages: string | Array<PayloadMessage> | undefined\n },\n sessionId?: string,\n): string => {\n const messages = payload.messages\n if (messages) {\n const lastUserContent =\n typeof messages === \"string\" ? messages : findLastUserContent(messages)\n\n if (lastUserContent) {\n return getUUID(\n (sessionId ?? \"\") + (state.macMachineId ?? \"\") + lastUserContent,\n )\n }\n }\n\n return randomUUID()\n}\n\nexport const getRootSessionId = (\n anthropicPayload: AnthropicMessagesPayload,\n c: Context,\n): string | undefined => {\n const userId = anthropicPayload.metadata?.user_id\n const sessionId =\n userId ?\n parseUserIdMetadata(userId).sessionId || undefined\n : c.req.header(\"x-session-id\")\n\n return sessionId ? getUUID(sessionId) : sessionId\n}\n\nexport const getUUID = (content: string): string => {\n const uuidBytes = createHash(\"sha256\")\n .update(content)\n .digest()\n .subarray(0, 16)\n\n uuidBytes[6] = (uuidBytes[6] & 0x0f) | 0x40\n uuidBytes[8] = (uuidBytes[8] & 0x3f) | 0x80\n\n const uuidHex = uuidBytes.toString(\"hex\")\n\n return `${uuidHex.slice(0, 8)}-${uuidHex.slice(8, 12)}-${uuidHex.slice(12, 16)}-${uuidHex.slice(16, 20)}-${uuidHex.slice(20)}`\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nick3/copilot-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code Or Codex Or Opencode!",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"proxy",
|
|
@@ -55,12 +55,14 @@
|
|
|
55
55
|
"srvx": "^0.8.9",
|
|
56
56
|
"tiny-invariant": "^1.3.3",
|
|
57
57
|
"undici": "^7.16.0",
|
|
58
|
+
"winreg": "^1.2.5",
|
|
58
59
|
"zod": "^4.1.11"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"@echristian/eslint-config": "^0.0.54",
|
|
62
63
|
"@types/bun": "^1.2.23",
|
|
63
64
|
"@types/proxy-from-env": "^1.0.4",
|
|
65
|
+
"@types/winreg": "^1.2.36",
|
|
64
66
|
"baseline-browser-mapping": "^2.9.19",
|
|
65
67
|
"bumpp": "^10.2.3",
|
|
66
68
|
"eslint": "^9.37.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"account-DhQb2A6q.js","names":["ACCOUNT_TYPE_VALUES: ReadonlyArray<AccountType>"],"sources":["../src/lib/types/account.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 /** Whether this account allows overage billing (enterprise feature) */\n overagePermitted?: 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"],"mappings":";AAOA,MAAaA,sBAAkD;CAC7D;CACA;CACA;CACD;AAED,SAAgB,cAAc,OAAsC;AAClE,QACE,OAAO,UAAU,YACb,oBAA8C,SAAS,MAAM;;AAIrE,SAAgB,iBAAiB,OAA6B;AAC5D,KAAI,CAAC,cAAc,MAAM,CACvB,OAAM,IAAI,MACR,yBAAyB,OAAO,MAAM,CAAC,kBAAkB,oBAAoB,KAC3E,KACD,GACF;AAEH,QAAO"}
|