@openhoo/hoopilot 2.1.4 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/cli.js +127 -52
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +118 -50
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/auth-store.ts","../src/auth.ts","../src/copilot.ts","../src/github-device.ts","../src/logger.ts","../src/server.ts","../src/openai.ts","../src/anthropic.ts","../src/dashboard.ts","../src/metrics.ts","../src/version.ts","../src/update.ts","../src/update-core.ts"],"sourcesContent":["#!/usr/bin/env bun\n\nimport { spawn } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { CopilotAuthError, DEFAULT_COPILOT_API_BASE_URL, STORED_TOKEN_TTL_MS } from \"./auth\";\nimport { authStorePath, writeStoredCopilotAuth } from \"./auth-store\";\nimport { main as codexxMain } from \"./codexx\";\nimport {\n ALLOWED_COPILOT_API_HOSTS,\n applyCopilotHeaders,\n CopilotClient,\n normalizeCopilotUsage,\n parseRateLimitHeaders,\n} from \"./copilot\";\nimport {\n type GithubCopilotDeviceLoginOptions,\n type GithubCopilotDeviceLoginResult,\n githubCopilotDeviceLogin,\n} from \"./github-device\";\nimport { createHoopilotLogger, noopLogger, parseLogFormat, parseLogLevel } from \"./logger\";\nimport { startHoopilotServer } from \"./server\";\nimport type {\n CopilotAccess,\n CopilotQuota,\n CopilotUsage,\n FetchLike,\n GithubRateLimit,\n HoopilotLogger,\n HoopilotServerOptions,\n Logger,\n} from \"./types\";\nimport { cleanupOldBinary, maybeNotifyUpdate, runUpdate } from \"./update\";\nimport {\n envValue,\n errorMessage,\n isTrustedTokenBaseUrl,\n modelIdsFromResponse,\n parseStreamingProxyMode,\n trimTrailingSlash,\n truncatedResponseText,\n} from \"./util\";\nimport { getVersion, IS_STANDALONE_BINARY } from \"./version\";\n\ninterface ParsedArgs extends HoopilotServerOptions {\n help?: boolean;\n noUpdateCheck?: boolean;\n printToken?: boolean;\n version?: boolean;\n}\n\ntype DeviceLogin = (\n options: GithubCopilotDeviceLoginOptions,\n) => Promise<GithubCopilotDeviceLoginResult>;\n\ninterface RunLoginOptions extends HoopilotServerOptions {\n deviceLogin?: DeviceLogin;\n printToken?: boolean;\n}\n\ninterface VerifyCopilotOAuthTokenOptions {\n copilotApiBaseUrl?: string;\n env?: NodeJS.ProcessEnv;\n fetch?: FetchLike;\n}\n\nexport async function main(argv = Bun.argv.slice(2)): Promise<void> {\n // Clear any leftover \".old\" binary from a prior Windows self-update.\n cleanupOldBinary();\n\n const command = argv[0];\n if (command === \"update\" || command === \"upgrade\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n const logger = commandLogger(args, command);\n await runUpdate(await getVersion(), logger);\n return;\n }\n if (command === \"codexx\") {\n await codexxMain(argv.slice(1), process.env);\n return;\n }\n if (command === \"login\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n args.logger = commandLogger(args, \"login\", args.printToken ? process.stderr : undefined);\n await runLogin(args);\n return;\n }\n if (command === \"models\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n args.logger = commandLogger(args, \"models\");\n await runModels(args);\n return;\n }\n if (command === \"usage\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n args.logger = commandLogger(args, \"usage\");\n await runUsage(args);\n return;\n }\n\n const args = withRuntimeEnv(parseArgs(argv));\n if (await printMetaOption(args)) {\n return;\n }\n\n const logger = commandLogger(args, \"serve\");\n args.logger = logger;\n const started = startHoopilotServer(args);\n logger.info(\n {\n baseUrl: `${started.url}/v1`,\n event: \"server.started\",\n url: started.url,\n },\n \"hoopilot server started\",\n );\n\n if (!args.noUpdateCheck) {\n // Non-blocking: prints a notice from the previous check and refreshes the\n // cache in the background. The running server keeps the refresh alive.\n // Env-based disabling (HOOPILOT_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER, CI, …)\n // is handled centrally by isUpdateCheckDisabled inside maybeNotifyUpdate.\n void maybeNotifyUpdate(\n await getVersion(),\n IS_STANDALONE_BINARY ? \"binary\" : \"npm\",\n logger.child({ component: \"update\" }),\n );\n }\n}\n\nasync function printMetaOption(args: ParsedArgs): Promise<boolean> {\n if (args.help) {\n console.log(helpText(await getVersion()));\n return true;\n }\n if (args.version) {\n console.log(await getVersion());\n return true;\n }\n return false;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const args: ParsedArgs = {};\n const rest = [...argv];\n if (rest[0] === \"serve\") {\n rest.shift();\n }\n\n while (rest.length > 0) {\n const arg = rest.shift();\n if (!arg) {\n continue;\n }\n if (arg === \"--help\" || arg === \"-h\") {\n args.help = true;\n continue;\n }\n if (arg === \"--version\" || arg === \"-v\") {\n args.version = true;\n continue;\n }\n if (arg === \"--allow-unauthenticated\") {\n args.allowUnauthenticated = true;\n continue;\n }\n if (arg === \"--no-update-check\") {\n args.noUpdateCheck = true;\n continue;\n }\n if (arg === \"--print-key\" || arg === \"--print-token\") {\n args.printToken = true;\n continue;\n }\n\n if (!arg.startsWith(\"-\")) {\n throw new Error(`Unknown argument: ${arg}.`);\n }\n\n const [name, inlineValue] = splitOption(arg);\n switch (name) {\n case \"--api-key\":\n args.apiKey = optionValue(name, inlineValue, rest);\n break;\n case \"--api-key-file\":\n args.apiKey = readApiKeyFile(optionValue(name, inlineValue, rest));\n break;\n case \"--auth-file\":\n args.authStorePath = optionValue(name, inlineValue, rest);\n break;\n case \"--copilot-api-base-url\":\n args.copilotApiBaseUrl = optionValue(name, inlineValue, rest);\n break;\n case \"--log-format\":\n args.logFormat = parseLogFormat(optionValue(name, inlineValue, rest));\n break;\n case \"--log-level\":\n args.logLevel = parseLogLevel(optionValue(name, inlineValue, rest));\n break;\n case \"--stream-mode\":\n args.streamingProxyMode = parseStreamingProxyMode(optionValue(name, inlineValue, rest));\n break;\n case \"--host\":\n args.host = optionValue(name, inlineValue, rest);\n break;\n case \"--port\":\n case \"-p\": {\n const value = optionValue(name, inlineValue, rest);\n args.port = Number(value);\n if (!Number.isInteger(args.port) || args.port <= 0 || args.port > 65_535) {\n throw new Error(`Invalid port: ${value}.`);\n }\n break;\n }\n default:\n throw new Error(`Unknown option: ${name}.`);\n }\n }\n\n return args;\n}\n\nfunction optionValue(name: string, inlineValue: string | undefined, rest: string[]): string {\n const value = inlineValue ?? rest.shift();\n if (!value) {\n throw new Error(`Missing value for ${name}.`);\n }\n return value;\n}\n\nfunction splitOption(arg: string): [string, string | undefined] {\n const separator = arg.indexOf(\"=\");\n if (separator === -1) {\n return [arg, undefined];\n }\n return [arg.slice(0, separator), arg.slice(separator + 1)];\n}\n\nfunction readApiKeyFile(path: string): string {\n const value = readFileSync(path, \"utf8\").trim();\n if (!value) {\n throw new Error(`API key file is empty: ${path}.`);\n }\n return value;\n}\n\nexport async function runLogin(options: RunLoginOptions = {}): Promise<void> {\n const logger = options.logger?.child({ component: \"auth\" }) ?? noopLogger;\n const status = loginStatusLogger(Boolean(options.printToken));\n logger.debug({ event: \"auth.login.started\" }, \"starting github copilot browser login\");\n status.info(\"Starting GitHub Copilot browser login...\");\n const deviceLogin = options.deviceLogin ?? githubCopilotDeviceLogin;\n const login = await deviceLogin({\n env: options.env,\n logger: status,\n openBrowser: openBrowserBestEffort,\n });\n\n status.info(\"Checking GitHub Copilot access...\");\n const access = await verifyCopilotOAuthToken(login.token, options);\n logger.debug(\n { apiBaseUrl: access.apiBaseUrl, event: \"auth.login.verified\" },\n \"github copilot oauth token verified\",\n );\n const path = options.authStorePath ?? authStorePath(options.env);\n writeStoredCopilotAuth(\n {\n apiBaseUrl: access.apiBaseUrl,\n githubDomain: login.domain,\n source: \"github-device-oauth\",\n token: login.token,\n },\n path,\n );\n logger.debug({ authStorePath: path, event: \"auth.login.stored\" }, \"copilot credential stored\");\n status.info(`Copilot OAuth credential stored at ${path}`);\n status.info(\"Copilot authentication ready.\");\n if (options.printToken) {\n console.log(login.token);\n }\n}\n\nexport async function runModels(options: HoopilotServerOptions = {}): Promise<string[]> {\n const logger = options.logger?.child({ component: \"models\" }) ?? noopLogger;\n logger.debug({ event: \"models.list.started\" }, \"fetching github copilot models\");\n\n const response = await new CopilotClient(options).models();\n if (!response.ok) {\n await throwForCopilotResponse(response, \"GitHub Copilot API model list\");\n }\n\n const ids = modelIdsFromResponse(await response.json().catch(() => undefined));\n if (ids.length === 0) {\n throw new Error(\"GitHub Copilot API returned no model IDs.\");\n }\n\n logger.debug(\n { count: ids.length, event: \"models.list.succeeded\" },\n \"github copilot models fetched\",\n );\n for (const id of ids) {\n console.log(id);\n }\n return ids;\n}\n\nexport async function runUsage(options: HoopilotServerOptions = {}): Promise<CopilotUsage> {\n const logger = options.logger?.child({ component: \"usage\" }) ?? noopLogger;\n logger.debug({ event: \"usage.fetch.started\" }, \"fetching github copilot quota\");\n\n const response = await new CopilotClient(options).usage();\n if (!response.ok) {\n await throwForCopilotResponse(response, \"GitHub Copilot usage request\");\n }\n\n const rateLimit = parseRateLimitHeaders(response.headers);\n const usage = normalizeCopilotUsage(await response.json().catch(() => ({})));\n logger.debug(\n { event: \"usage.fetch.succeeded\", plan: usage.plan },\n \"github copilot quota fetched\",\n );\n for (const line of formatCopilotUsage(usage)) {\n console.log(line);\n }\n if (rateLimit) {\n console.log(formatGithubRateLimit(rateLimit));\n }\n return usage;\n}\n\nfunction formatGithubRateLimit(rateLimit: GithubRateLimit): string {\n const parts: string[] = [];\n if (rateLimit.remaining !== undefined && rateLimit.limit !== undefined) {\n parts.push(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);\n } else if (rateLimit.remaining !== undefined) {\n parts.push(`${rateLimit.remaining} requests remaining`);\n } else if (rateLimit.used !== undefined) {\n parts.push(`${rateLimit.used} requests used`);\n }\n if (rateLimit.resetEpochSeconds !== undefined) {\n parts.push(`resets ${new Date(rateLimit.resetEpochSeconds * 1000).toISOString()}`);\n }\n if (rateLimit.retryAfterSeconds !== undefined) {\n parts.push(`retry after ${rateLimit.retryAfterSeconds}s`);\n }\n const detail = parts.length > 0 ? parts.join(\", \") : \"n/a\";\n const resource =\n rateLimit.resource && rateLimit.resource !== \"unknown\" ? ` (${rateLimit.resource})` : \"\";\n return `GitHub API rate limit${resource}: ${detail}`;\n}\n\nfunction formatCopilotUsage(usage: CopilotUsage): string[] {\n const lines: string[] = [];\n if (usage.plan) {\n lines.push(`Plan: ${usage.plan}`);\n }\n if (usage.quotaResetDate) {\n lines.push(`Quota resets: ${usage.quotaResetDate}`);\n }\n\n const order = [\"premium_interactions\", \"chat\", \"completions\"];\n const names = Object.keys(usage.quotas).sort(\n (a, b) => quotaRank(order, a) - quotaRank(order, b) || a.localeCompare(b),\n );\n for (const name of names) {\n const quota = usage.quotas[name];\n if (quota) {\n lines.push(`${quotaLabel(name)}: ${formatQuota(quota)}`);\n }\n }\n if (lines.length === 0) {\n lines.push(\"No GitHub Copilot quota information available for this account.\");\n }\n return lines;\n}\n\nfunction quotaRank(order: string[], name: string): number {\n const index = order.indexOf(name);\n return index === -1 ? order.length : index;\n}\n\nfunction quotaLabel(name: string): string {\n switch (name) {\n case \"premium_interactions\":\n return \"Premium requests\";\n case \"chat\":\n return \"Chat\";\n case \"completions\":\n return \"Completions\";\n default:\n return name;\n }\n}\n\nfunction formatQuota(quota: CopilotQuota): string {\n if (quota.unlimited) {\n return \"unlimited\";\n }\n const parts: string[] = [];\n if (quota.used !== undefined && quota.entitlement !== undefined) {\n parts.push(`${roundQuota(quota.used)}/${roundQuota(quota.entitlement)} used`);\n } else if (quota.remaining !== undefined) {\n parts.push(`${roundQuota(quota.remaining)} remaining`);\n }\n if (quota.percentRemaining !== undefined) {\n parts.push(`${roundQuota(quota.percentRemaining)}% remaining`);\n }\n if (quota.overageCount) {\n parts.push(`${roundQuota(quota.overageCount)} overage`);\n }\n return parts.length > 0 ? parts.join(\", \") : \"n/a\";\n}\n\nfunction roundQuota(value: number): number {\n return Number.isInteger(value) ? value : Math.round(value * 10) / 10;\n}\n\nexport async function verifyCopilotOAuthToken(\n token: string,\n options: VerifyCopilotOAuthTokenOptions = {},\n): Promise<CopilotAccess> {\n const apiBaseUrl = trimTrailingSlash(\n options.copilotApiBaseUrl ??\n envValue(options.env?.COPILOT_API_BASE_URL) ??\n DEFAULT_COPILOT_API_BASE_URL,\n );\n const allowUnsafeUpstream = envValue(options.env?.HOOPILOT_ALLOW_UNSAFE_UPSTREAM) === \"1\";\n if (!isTrustedTokenBaseUrl(apiBaseUrl, ALLOWED_COPILOT_API_HOSTS, allowUnsafeUpstream)) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to an untrusted Copilot API host: ${apiBaseUrl}`,\n );\n }\n const fetcher = options.fetch ?? fetch;\n const response = await fetcher(`${apiBaseUrl}/models`, {\n headers: applyCopilotHeaders(new Headers(), token),\n method: \"GET\",\n });\n\n if (!response.ok) {\n await throwForCopilotResponse(response, \"GitHub Copilot API verification\");\n }\n\n return {\n apiBaseUrl,\n expiresAtMs: Date.now() + STORED_TOKEN_TTL_MS,\n source: \"github-copilot-oauth\",\n token,\n };\n}\n\n/** Throw a labeled error for a failed Copilot response, mapping 401/403 to {@link CopilotAuthError}. */\nasync function throwForCopilotResponse(response: Response, label: string): Promise<never> {\n const message = `${label} failed with ${response.status}: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\n}\n\ntype BrowserOpenerChild = {\n on(event: \"error\", listener: (error: Error) => void): unknown;\n unref(): void;\n};\n\ntype BrowserOpenerSpawn = (\n command: string,\n args: string[],\n options: {\n detached: true;\n stdio: \"ignore\";\n },\n) => BrowserOpenerChild;\n\nexport function openBrowserBestEffort(url: string, spawnOpener: BrowserOpenerSpawn = spawn): void {\n const platform = process.platform;\n const command = platform === \"win32\" ? \"cmd\" : platform === \"darwin\" ? \"open\" : \"xdg-open\";\n const args = platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n try {\n const child = spawnOpener(command, args, {\n detached: true,\n stdio: \"ignore\",\n });\n child.on(\"error\", () => {\n // The device login code and URL were already printed.\n });\n child.unref();\n } catch {\n // The device login code and URL were already printed.\n }\n}\n\nfunction withRuntimeEnv(args: ParsedArgs): ParsedArgs {\n return { ...args, env: process.env };\n}\n\nfunction commandLogger(\n args: ParsedArgs,\n command: string,\n stream?: { write(message: string): unknown },\n): HoopilotLogger {\n return createHoopilotLogger({\n env: args.env,\n format: args.logFormat,\n level: args.logLevel,\n stream,\n }).child({ command, component: \"cli\" });\n}\n\nfunction loginStatusLogger(writeSecretsToStdout: boolean): Logger {\n if (writeSecretsToStdout) {\n return {\n error: (message) => console.error(message),\n info: (message) => console.error(message),\n warn: (message) => console.error(message),\n };\n }\n return {\n error: (message) => console.error(message),\n info: (message) => console.log(message),\n warn: (message) => console.warn(message),\n };\n}\n\nfunction helpText(version: string): string {\n return `hoopilot ${version}\n\nOpenAI-compatible proxy for GitHub Copilot.\n\nUsage:\n hoopilot [serve] [options]\n hoopilot codexx [codex options] [prompt]\n hoopilot login [options]\n hoopilot models [options]\n hoopilot usage [options]\n hoopilot update\n npx @openhoo/hoopilot [options]\n\nCommands:\n serve Start the proxy server (default)\n codexx Run Codex through the local Hoopilot server\n login Sign in through GitHub OAuth in a browser and verify Copilot access\n models List available GitHub Copilot model IDs\n usage Show GitHub Copilot quota and premium-request usage\n update, upgrade Update hoopilot to the latest release\n\nWhile the server runs, GET /metrics exposes Prometheus metrics (request counts,\ntoken usage, latency) and GET /v1/usage returns those metrics plus live Copilot\nquota as JSON. Open GET /dashboard in a browser for a live usage and status view.\n\nOptions:\n -p, --port <port> Port to listen on. Default: 4141\n --host <host> Host to listen on. Default: 127.0.0.1\n --api-key <key> Require clients to send Authorization: Bearer <key> or x-api-key: <key>\n --api-key-file <path> Read the local API key from a file instead of argv\n --auth-file <path> OAuth credential store path\n --copilot-api-base-url <url> Copilot API base URL override\n --print-key Login: print the received OAuth token to stdout\n --log-level <level> trace, debug, info, warn, error, fatal, or silent\n --log-format <format> json or pretty. Default: pretty\n --stream-mode <mode> auto, live, or buffer. Auto buffers Windows standalone streams.\n --no-update-check Do not check GitHub for a newer release\n --allow-unauthenticated Allow non-loopback bind without --api-key\n -h, --help Show help\n -v, --version Show version\n\nEnvironment:\n HOOPILOT_API_KEY\n HOOPILOT_AUTH_FILE\n HOOPILOT_GITHUB_CLIENT_ID\n HOOPILOT_GITHUB_DOMAIN\n HOOPILOT_LOG_FORMAT json or pretty. Default: pretty\n HOOPILOT_LOG_LEVEL trace, debug, info, warn, error, fatal, or silent\n HOOPILOT_STREAM_MODE auto, live, or buffer\n COPILOT_API_BASE_URL\n HOOPILOT_GITHUB_API_BASE_URL GitHub REST base for the usage/quota lookup. Default: https://api.github.com\n HOOPILOT_ALLOW_UNSAFE_UPSTREAM Set to 1 to allow nonstandard HTTPS token hosts\n HOOPILOT_NO_UPDATE_CHECK Set to disable update checks (also NO_UPDATE_NOTIFIER)\n`;\n}\n\nif (import.meta.main) {\n main().catch((error: unknown) => {\n console.error(errorMessage(error));\n process.exit(1);\n });\n}\n","import { chmodSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { asRecord, envValue } from \"./util\";\n\nexport class StoredCopilotAuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StoredCopilotAuthError\";\n }\n}\n\nexport interface StoredCopilotAuth {\n apiBaseUrl?: string;\n createdAt?: string;\n githubDomain?: string;\n source?: string;\n token: string;\n}\n\nexport function authStorePath(env: NodeJS.ProcessEnv = process.env): string {\n const explicit = envValue(env.HOOPILOT_AUTH_FILE);\n if (explicit) {\n return explicit;\n }\n\n const xdg = envValue(env.XDG_CONFIG_HOME);\n if (xdg) {\n return join(xdg, \"hoopilot\", \"auth.json\");\n }\n const appdata = envValue(env.APPDATA);\n if (appdata) {\n return join(appdata, \"hoopilot\", \"auth.json\");\n }\n const home = envValue(env.HOME);\n if (!home) {\n throw new StoredCopilotAuthError(\n \"Cannot resolve Hoopilot auth file path without HOOPILOT_AUTH_FILE, XDG_CONFIG_HOME, APPDATA, or HOME.\",\n );\n }\n const base = join(home, \".config\");\n return join(base, \"hoopilot\", \"auth.json\");\n}\n\nexport function readStoredCopilotAuth(path = authStorePath()): StoredCopilotAuth | undefined {\n let text: string;\n try {\n text = readFileSync(path, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw new StoredCopilotAuthError(`Could not read Hoopilot auth file at ${path}.`);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new StoredCopilotAuthError(\n `Hoopilot auth file at ${path} is not valid JSON. Run \\`hoopilot login\\` to replace it.`,\n );\n }\n\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new StoredCopilotAuthError(`Hoopilot auth file at ${path} must contain a JSON object.`);\n }\n const record = asRecord(parsed);\n const token = typeof record.token === \"string\" ? record.token.trim() : \"\";\n if (!token) {\n throw new StoredCopilotAuthError(`Hoopilot auth file at ${path} does not contain a token.`);\n }\n return {\n apiBaseUrl: typeof record.apiBaseUrl === \"string\" ? record.apiBaseUrl : undefined,\n createdAt: typeof record.createdAt === \"string\" ? record.createdAt : undefined,\n githubDomain: typeof record.githubDomain === \"string\" ? record.githubDomain : undefined,\n source: typeof record.source === \"string\" ? record.source : undefined,\n token,\n };\n}\n\nexport function writeStoredCopilotAuth(auth: StoredCopilotAuth, path = authStorePath()): void {\n mkdirSync(dirname(path), { recursive: true });\n const data = `${JSON.stringify(\n {\n ...auth,\n createdAt: auth.createdAt ?? new Date().toISOString(),\n },\n null,\n 2,\n )}\\n`;\n // Write to a sibling temp file, then rename into place so a crash or full\n // disk mid-write can never leave a truncated credential file behind.\n const tmpPath = `${path}.${process.pid}.tmp`;\n writeFileSync(tmpPath, data, { mode: 0o600 });\n try {\n renameSync(tmpPath, path);\n } catch (error) {\n // Don't leave the orphaned temp credential behind if the rename fails.\n try {\n rmSync(tmpPath, { force: true });\n } catch {\n // best-effort cleanup; surface the original failure below\n }\n throw error;\n }\n try {\n chmodSync(path, 0o600);\n } catch {\n // chmod is best-effort on Windows.\n }\n}\n","import {\n readStoredCopilotAuth,\n type StoredCopilotAuth,\n StoredCopilotAuthError,\n} from \"./auth-store\";\nimport type { CopilotAccess, CopilotAuthOptions } from \"./types\";\nimport { envValue, trimTrailingSlash } from \"./util\";\n\nexport const DEFAULT_COPILOT_API_BASE_URL = \"https://api.githubcopilot.com\";\nconst REFRESH_SKEW_MS = 60_000;\nexport const STORED_TOKEN_TTL_MS = 10 * 60_000;\n\nexport class CopilotAuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CopilotAuthError\";\n }\n}\n\nexport class CopilotAuth {\n readonly #authStorePath?: string;\n readonly #copilotApiBaseUrl: string;\n readonly #hasCopilotApiBaseUrlOverride: boolean;\n #cachedAccess?: CopilotAccess;\n\n constructor(options: CopilotAuthOptions = {}) {\n const envAuthStorePath = envValue(options.env?.HOOPILOT_AUTH_FILE);\n const envCopilotApiBaseUrl = envValue(options.env?.COPILOT_API_BASE_URL);\n this.#authStorePath = options.authStorePath ?? envAuthStorePath;\n this.#hasCopilotApiBaseUrlOverride = Boolean(options.copilotApiBaseUrl ?? envCopilotApiBaseUrl);\n this.#copilotApiBaseUrl = trimTrailingSlash(\n options.copilotApiBaseUrl ?? envCopilotApiBaseUrl ?? DEFAULT_COPILOT_API_BASE_URL,\n );\n }\n\n async getAccess(): Promise<CopilotAccess> {\n if (this.#cachedAccess && this.#cachedAccess.expiresAtMs - REFRESH_SKEW_MS > Date.now()) {\n return this.#cachedAccess;\n }\n\n let stored: StoredCopilotAuth | undefined;\n try {\n stored = readStoredCopilotAuth(this.#authStorePath);\n } catch (error) {\n if (error instanceof StoredCopilotAuthError) {\n throw new CopilotAuthError(error.message);\n }\n throw error;\n }\n if (stored) {\n this.#cachedAccess = {\n apiBaseUrl: trimTrailingSlash(\n this.#hasCopilotApiBaseUrlOverride\n ? this.#copilotApiBaseUrl\n : (stored.apiBaseUrl ?? this.#copilotApiBaseUrl),\n ),\n expiresAtMs: Date.now() + STORED_TOKEN_TTL_MS,\n source: \"github-copilot-oauth\",\n token: stored.token,\n };\n return this.#cachedAccess;\n }\n\n throw new CopilotAuthError(\n \"No GitHub Copilot OAuth credential found. Run `hoopilot login` to sign in through your browser.\",\n );\n }\n}\n","import { CopilotAuth } from \"./auth\";\nimport type {\n CopilotAuthOptions,\n CopilotQuota,\n CopilotUsage,\n FetchLike,\n GithubRateLimit,\n JsonObject,\n} from \"./types\";\nimport {\n asRecord,\n envValue,\n firstNumber,\n isTrustedTokenBaseUrl,\n removeUndefined,\n trimTrailingSlash,\n} from \"./util\";\n\n/** Default GitHub REST host that serves the `copilot_internal/user` quota route. */\nexport const DEFAULT_GITHUB_API_BASE_URL = \"https://api.github.com\";\nexport const ALLOWED_COPILOT_API_HOSTS = [\"api.githubcopilot.com\"] as const;\nconst ALLOWED_GITHUB_API_HOSTS = [\"api.github.com\"] as const;\n\n/**\n * API version sent to the GitHub `copilot_internal` endpoints. This is a\n * different surface from the Copilot completions API (`x-github-api-version`\n * `2026-06-01`), so it is pinned separately and bumped independently.\n */\nexport const COPILOT_USAGE_API_VERSION = \"2025-04-01\";\n\n// Editor-identity strings spoofed to GitHub Copilot. Deliberately pinned (not\n// derived from the package version) and shared by both header builders below.\nconst EDITOR_PLUGIN_VERSION = \"hoopilot/0.1.0\";\nconst EDITOR_VERSION = \"Hoopilot/0.1.0\";\nconst HOOPILOT_USER_AGENT = \"hoopilot/0.1.0\";\nconst DEFAULT_UPSTREAM_TIMEOUT_MS = 120_000;\nconst DEFAULT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS = 120_000;\n\nexport class CopilotUpstreamTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CopilotUpstreamTimeoutError\";\n }\n}\n\n/**\n * Set the GitHub Copilot API request headers on `headers`, leaving any\n * caller-provided `accept` intact. Single source of truth for the pinned\n * integration id, editor/plugin versions, and API version so the proxy client\n * and the login-time verification call cannot drift apart.\n */\nexport function applyCopilotHeaders(headers: Headers, token: string): Headers {\n headers.set(\"accept\", headers.get(\"accept\") ?? \"application/json\");\n headers.set(\"authorization\", `Bearer ${token}`);\n headers.set(\"copilot-integration-id\", \"vscode-chat\");\n headers.set(\"editor-plugin-version\", EDITOR_PLUGIN_VERSION);\n headers.set(\"editor-version\", EDITOR_VERSION);\n headers.set(\"openai-intent\", \"conversation-panel\");\n headers.set(\"user-agent\", HOOPILOT_USER_AGENT);\n headers.set(\"x-github-api-version\", \"2026-06-01\");\n return headers;\n}\n\n/**\n * Set headers for the GitHub REST `copilot_internal/user` quota call. This host\n * is `api.github.com` (not the Copilot API host) and expects the `token` auth\n * scheme with the raw stored OAuth token — not the `Bearer` scheme used by the\n * Copilot completion endpoints.\n */\nexport function applyGithubApiHeaders(headers: Headers, token: string): Headers {\n headers.set(\"accept\", headers.get(\"accept\") ?? \"application/json\");\n headers.set(\"authorization\", `token ${token}`);\n headers.set(\"editor-plugin-version\", EDITOR_PLUGIN_VERSION);\n headers.set(\"editor-version\", EDITOR_VERSION);\n headers.set(\"user-agent\", HOOPILOT_USER_AGENT);\n headers.set(\"x-github-api-version\", COPILOT_USAGE_API_VERSION);\n return headers;\n}\n\n/**\n * Parse the GitHub REST `x-ratelimit-*` headers (plus `retry-after`) off a\n * response into a {@link GithubRateLimit}. `api.github.com` returns these on\n * every reply, so the proxy reads its GitHub API budget from the quota call it\n * already makes — no extra request is spent. Returns undefined when the response\n * carries no rate-limit headers (for example the Copilot completion host, which\n * does not emit them today) so callers record nothing rather than a phantom row.\n */\nexport function parseRateLimitHeaders(\n headers: Headers,\n nowMs: number = Date.now(),\n): GithubRateLimit | undefined {\n const limit = headerInt(headers, \"x-ratelimit-limit\");\n const remaining = headerInt(headers, \"x-ratelimit-remaining\");\n const used = headerInt(headers, \"x-ratelimit-used\");\n const resetEpochSeconds = headerInt(headers, \"x-ratelimit-reset\");\n const retryAfterSeconds = headerInt(headers, \"retry-after\");\n if (\n limit === undefined &&\n remaining === undefined &&\n used === undefined &&\n resetEpochSeconds === undefined &&\n retryAfterSeconds === undefined\n ) {\n return undefined;\n }\n return removeUndefined({\n limit,\n observedAtMs: nowMs,\n remaining,\n resetEpochSeconds,\n resource: headers.get(\"x-ratelimit-resource\")?.trim() || \"unknown\",\n retryAfterSeconds,\n used,\n });\n}\n\n// Parse a non-negative integer header (the rate-limit headers are all integers;\n// retry-after is integer seconds on GitHub's secondary limits). A missing or\n// malformed header yields undefined so it is simply omitted from the result.\nfunction headerInt(headers: Headers, name: string): number | undefined {\n const raw = headers.get(name);\n if (raw === null) {\n return undefined;\n }\n const value = Number.parseInt(raw.trim(), 10);\n return Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nexport class CopilotClient {\n readonly #auth: CopilotAuth;\n readonly #allowUnsafeUpstream: boolean;\n readonly #fetch: FetchLike;\n readonly #githubApiBaseUrl: string;\n readonly #upstreamStreamIdleTimeoutMs: number;\n readonly #upstreamTimeoutMs: number;\n\n constructor(options: CopilotAuthOptions = {}) {\n this.#auth = new CopilotAuth(options);\n this.#allowUnsafeUpstream = envValue(options.env?.HOOPILOT_ALLOW_UNSAFE_UPSTREAM) === \"1\";\n this.#fetch = options.fetch ?? fetch;\n this.#githubApiBaseUrl = trimTrailingSlash(\n options.githubApiBaseUrl ??\n envValue(options.env?.HOOPILOT_GITHUB_API_BASE_URL) ??\n DEFAULT_GITHUB_API_BASE_URL,\n );\n this.#upstreamTimeoutMs = parseTimeoutMs(\n options.upstreamTimeoutMs,\n options.env?.HOOPILOT_UPSTREAM_TIMEOUT_MS,\n DEFAULT_UPSTREAM_TIMEOUT_MS,\n \"HOOPILOT_UPSTREAM_TIMEOUT_MS\",\n );\n this.#upstreamStreamIdleTimeoutMs = parseTimeoutMs(\n options.upstreamStreamIdleTimeoutMs,\n options.env?.HOOPILOT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS,\n DEFAULT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS,\n \"HOOPILOT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS\",\n );\n }\n\n /**\n * Fetch the Copilot account's quota / premium-request usage from the GitHub\n * REST `copilot_internal/user` endpoint. The stored device-flow OAuth token is\n * accepted directly here — no Copilot token exchange is required to read quota.\n */\n async usage(signal?: AbortSignal): Promise<Response> {\n // The quota call sends the raw, long-lived OAuth token. Never transmit it\n // over plaintext to a non-loopback host, so a misconfigured base URL cannot\n // exfiltrate the credential.\n if (\n !isTrustedTokenBaseUrl(\n this.#githubApiBaseUrl,\n ALLOWED_GITHUB_API_HOSTS,\n this.#allowUnsafeUpstream,\n )\n ) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to an untrusted GitHub API host: ${this.#githubApiBaseUrl}`,\n );\n }\n const access = await this.#auth.getAccess();\n const headers = applyGithubApiHeaders(new Headers(), access.token);\n return this.#fetchWithTimeout(`${this.#githubApiBaseUrl}/copilot_internal/user`, {\n headers,\n method: \"GET\",\n signal,\n });\n }\n\n async chatCompletions(body: JsonObject, signal?: AbortSignal): Promise<Response> {\n return this.fetchCopilot(\"/chat/completions\", {\n body: JSON.stringify(body),\n headers: {\n \"content-type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n }\n\n async responses(body: string, signal?: AbortSignal): Promise<Response> {\n return this.fetchCopilot(\"/responses\", {\n body,\n headers: {\n \"content-type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n }\n\n async models(signal?: AbortSignal): Promise<Response> {\n return this.fetchCopilot(\"/models\", {\n headers: {\n accept: \"application/json\",\n },\n method: \"GET\",\n signal,\n });\n }\n\n async fetchCopilot(path: string, init: RequestInit): Promise<Response> {\n const access = await this.#auth.getAccess();\n if (\n !isTrustedTokenBaseUrl(\n access.apiBaseUrl,\n ALLOWED_COPILOT_API_HOSTS,\n this.#allowUnsafeUpstream,\n )\n ) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to an untrusted Copilot API host: ${access.apiBaseUrl}`,\n );\n }\n const headers = applyCopilotHeaders(new Headers(init.headers), access.token);\n\n return this.#fetchWithTimeout(`${access.apiBaseUrl}${path}`, {\n ...init,\n headers,\n });\n }\n\n async #fetchWithTimeout(input: string, init: RequestInit): Promise<Response> {\n const timeout = abortSignalWithTimeout(init.signal ?? undefined, this.#upstreamTimeoutMs);\n try {\n const response = await this.#fetch(input, {\n ...init,\n signal: timeout.signal,\n });\n return responseWithStreamIdleTimeout(response, this.#upstreamStreamIdleTimeoutMs, input);\n } catch (error) {\n if (timeout.timedOut()) {\n throw new CopilotUpstreamTimeoutError(\n `Copilot upstream request timed out after ${this.#upstreamTimeoutMs} ms before response headers arrived.`,\n );\n }\n throw error;\n } finally {\n timeout.cleanup();\n }\n }\n}\n\nfunction parseTimeoutMs(\n optionValue: number | undefined,\n envRaw: string | undefined,\n fallback: number,\n name: string,\n): number {\n const raw = optionValue ?? envValue(envRaw);\n if (raw === undefined) {\n return fallback;\n }\n const value = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`${name} must be a non-negative integer number of milliseconds.`);\n }\n return value;\n}\n\nfunction abortSignalWithTimeout(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { cleanup: () => void; signal: AbortSignal | undefined; timedOut: () => boolean } {\n if (timeoutMs === 0) {\n return { cleanup: () => {}, signal: parent, timedOut: () => false };\n }\n\n const controller = new AbortController();\n let timedOut = false;\n const timer = setTimeout(() => {\n if (controller.signal.aborted) {\n return;\n }\n timedOut = true;\n controller.abort(\n new CopilotUpstreamTimeoutError(`Copilot upstream request timed out after ${timeoutMs} ms.`),\n );\n }, timeoutMs);\n const onAbort = () => controller.abort(parent?.reason);\n if (parent?.aborted) {\n controller.abort(parent.reason);\n } else {\n parent?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n return {\n cleanup: () => {\n clearTimeout(timer);\n parent?.removeEventListener(\"abort\", onAbort);\n },\n signal: controller.signal,\n timedOut: () => timedOut,\n };\n}\n\nfunction responseWithStreamIdleTimeout(\n response: Response,\n idleTimeoutMs: number,\n input: string,\n): Response {\n if (!response.body || idleTimeoutMs === 0) {\n return response;\n }\n return new Response(streamWithIdleTimeout(response.body, idleTimeoutMs, input), {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\nfunction streamWithIdleTimeout(\n body: ReadableStream<Uint8Array>,\n idleTimeoutMs: number,\n input: string,\n): ReadableStream<Uint8Array> {\n const reader = body.getReader();\n let released = false;\n const release = () => {\n if (!released) {\n released = true;\n reader.releaseLock();\n }\n };\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const read = reader.read();\n read.catch(() => {});\n try {\n const result = await Promise.race([\n read,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(\n new CopilotUpstreamTimeoutError(\n `Copilot upstream stream was idle for ${idleTimeoutMs} ms while reading ${input}.`,\n ),\n );\n }, idleTimeoutMs);\n }),\n ]);\n if (timer) {\n clearTimeout(timer);\n }\n if (result.done) {\n controller.close();\n release();\n return;\n }\n controller.enqueue(result.value);\n } catch (error) {\n if (timer) {\n clearTimeout(timer);\n }\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n release();\n }\n },\n async cancel(reason) {\n try {\n await reader.cancel(reason);\n } finally {\n release();\n }\n },\n });\n}\n\n/**\n * Normalize a `copilot_internal/user` response into {@link CopilotUsage}. Handles\n * both the paid-plan shape (`quota_snapshots.{chat,completions,premium_interactions}`)\n * and the free-plan shape (`limited_user_quotas` remaining + `monthly_quotas`\n * allowance). `remaining` may be fractional and negative under permitted overage,\n * so `used` is derived as `max(0, entitlement - remaining)`.\n */\nexport function normalizeCopilotUsage(body: unknown): CopilotUsage {\n const record = asRecord(body);\n const quotas: Record<string, CopilotQuota> = {};\n\n const snapshots = asRecord(record.quota_snapshots);\n for (const [category, detail] of Object.entries(snapshots)) {\n quotas[category] = normalizeQuotaDetail(asRecord(detail));\n }\n\n if (Object.keys(quotas).length === 0) {\n const remaining = asRecord(record.limited_user_quotas);\n const monthly = asRecord(record.monthly_quotas);\n for (const category of new Set([...Object.keys(remaining), ...Object.keys(monthly)])) {\n const entitlement = numberOrUndefined(monthly[category]);\n const left = numberOrUndefined(remaining[category]);\n quotas[category] = removeUndefined({\n entitlement,\n percentRemaining:\n entitlement !== undefined && entitlement > 0 && left !== undefined\n ? (left / entitlement) * 100\n : undefined,\n remaining: left,\n used: usedFrom(entitlement, left),\n });\n }\n }\n\n return removeUndefined({\n accessTypeSku: stringOrUndefined(record.access_type_sku),\n chatEnabled: typeof record.chat_enabled === \"boolean\" ? record.chat_enabled : undefined,\n plan: stringOrUndefined(record.copilot_plan),\n quotaResetDate:\n stringOrUndefined(record.quota_reset_date) ??\n stringOrUndefined(record.quota_reset_date_utc) ??\n stringOrUndefined(record.limited_user_reset_date),\n quotas,\n });\n}\n\nfunction normalizeQuotaDetail(detail: JsonObject): CopilotQuota {\n const entitlement = numberOrUndefined(detail.entitlement);\n const overageCount = numberOrUndefined(detail.overage_count);\n const remaining =\n numberOrUndefined(detail.remaining) ?? numberOrUndefined(detail.quota_remaining);\n return removeUndefined({\n entitlement,\n hasQuota: typeof detail.has_quota === \"boolean\" ? detail.has_quota : undefined,\n overageCount,\n overageEntitlement: numberOrUndefined(detail.overage_entitlement),\n overagePermitted:\n typeof detail.overage_permitted === \"boolean\" ? detail.overage_permitted : undefined,\n percentRemaining: numberOrUndefined(detail.percent_remaining),\n quotaId: stringOrUndefined(detail.quota_id),\n quotaResetAt: stringOrUndefined(detail.quota_reset_at),\n remaining,\n timestampUtc: stringOrUndefined(detail.timestamp_utc),\n tokenBasedBilling:\n typeof detail.token_based_billing === \"boolean\" ? detail.token_based_billing : undefined,\n unlimited: typeof detail.unlimited === \"boolean\" ? detail.unlimited : undefined,\n used: usedFrom(entitlement, remaining, overageCount),\n });\n}\n\nfunction usedFrom(\n entitlement: number | undefined,\n remaining: number | undefined,\n overageCount?: number,\n): number | undefined {\n if (entitlement === undefined || remaining === undefined) {\n return undefined;\n }\n const base = entitlement - remaining;\n const overage = remaining === 0 ? (overageCount ?? 0) : 0;\n return Math.max(0, base + overage);\n}\n\n// Single-argument case of the shared firstNumber helper.\nconst numberOrUndefined = firstNumber;\n\nfunction stringOrUndefined(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n","import { setTimeout as sleep } from \"node:timers/promises\";\nimport type { FetchLike, Logger } from \"./types\";\nimport { envValue, truncatedResponseText } from \"./util\";\n\nexport const DEFAULT_GITHUB_COPILOT_CLIENT_ID = \"Ov23li8tweQw6odWQebz\";\nconst DEFAULT_GITHUB_DOMAIN = \"github.com\";\nconst DEVICE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst POLLING_SAFETY_MARGIN_MS = 3_000;\nconst REQUEST_TIMEOUT_MS = 15_000;\n\nexport interface GithubCopilotDeviceLoginOptions {\n clientId?: string;\n domain?: string;\n env?: NodeJS.ProcessEnv;\n fetch?: FetchLike;\n logger?: Logger;\n openBrowser?: (url: string) => void | Promise<void>;\n sleep?: (ms: number) => Promise<void>;\n}\n\nexport interface GithubCopilotDeviceLoginResult {\n domain: string;\n token: string;\n}\n\ninterface DeviceCodeResponse {\n device_code?: string;\n expires_in?: number;\n interval?: number;\n user_code?: string;\n verification_uri?: string;\n}\n\ninterface DeviceTokenResponse {\n access_token?: string;\n error?: string;\n error_description?: string;\n interval?: number;\n}\n\nexport async function githubCopilotDeviceLogin(\n options: GithubCopilotDeviceLoginOptions = {},\n): Promise<GithubCopilotDeviceLoginResult> {\n const env = options.env ?? process.env;\n const fetcher = options.fetch ?? fetch;\n const sleeper = options.sleep ?? sleep;\n const domain = normalizeDomain(\n options.domain ?? envValue(env.HOOPILOT_GITHUB_DOMAIN) ?? DEFAULT_GITHUB_DOMAIN,\n );\n const clientId =\n options.clientId ??\n envValue(env.HOOPILOT_GITHUB_CLIENT_ID) ??\n envValue(env.COPILOT_GITHUB_CLIENT_ID) ??\n DEFAULT_GITHUB_COPILOT_CLIENT_ID;\n\n const device = await requestDeviceCode(fetcher, domain, clientId);\n const verificationUrl = device.verification_uri;\n const userCode = device.user_code;\n const deviceCode = device.device_code;\n if (!verificationUrl || !userCode || !deviceCode) {\n throw new Error(\"GitHub device authorization response is missing required fields.\");\n }\n\n options.logger?.info(`First copy your one-time code: ${userCode}`);\n options.logger?.info(`Open ${verificationUrl} in your browser to authorize Hoopilot.`);\n await options.openBrowser?.(verificationUrl);\n\n return {\n domain,\n token: await pollForAccessToken(fetcher, sleeper, domain, clientId, {\n deviceCode,\n expiresIn: positiveSeconds(device.expires_in, 900),\n interval: positiveSeconds(device.interval, 5),\n }),\n };\n}\n\nasync function requestDeviceCode(\n fetcher: FetchLike,\n domain: string,\n clientId: string,\n): Promise<DeviceCodeResponse> {\n const response = await fetcher(`https://${domain}/login/device/code`, {\n body: JSON.stringify({\n client_id: clientId,\n scope: \"read:user\",\n }),\n headers: oauthHeaders(),\n method: \"POST\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!response.ok) {\n throw new Error(\n `GitHub device authorization failed with ${response.status}: ${await truncatedResponseText(\n response,\n )}`,\n );\n }\n return parseJsonResponse<DeviceCodeResponse>(\n response,\n \"GitHub device authorization response was not valid JSON\",\n );\n}\n\nasync function pollForAccessToken(\n fetcher: FetchLike,\n sleeper: (ms: number) => Promise<void>,\n domain: string,\n clientId: string,\n device: { deviceCode: string; expiresIn: number; interval: number },\n): Promise<string> {\n let intervalMs = device.interval * 1000 + POLLING_SAFETY_MARGIN_MS;\n const deadline = Date.now() + device.expiresIn * 1000;\n\n while (Date.now() < deadline) {\n await sleeper(intervalMs);\n const response = await fetcher(`https://${domain}/login/oauth/access_token`, {\n body: JSON.stringify({\n client_id: clientId,\n device_code: device.deviceCode,\n grant_type: DEVICE_GRANT_TYPE,\n }),\n headers: oauthHeaders(),\n method: \"POST\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(\n `GitHub device token exchange failed with ${response.status}: ${await truncatedResponseText(\n response,\n )}`,\n );\n }\n\n const data = await parseJsonResponse<DeviceTokenResponse>(\n response,\n \"GitHub device token response was not valid JSON\",\n );\n if (data.access_token) {\n return data.access_token;\n }\n\n if (data.error === \"authorization_pending\") {\n continue;\n }\n if (data.error === \"slow_down\") {\n intervalMs =\n positiveSeconds(data.interval, device.interval + 5) * 1000 + POLLING_SAFETY_MARGIN_MS;\n continue;\n }\n if (data.error === \"expired_token\") {\n throw new Error(\"GitHub device login expired. Run `hoopilot login` again.\");\n }\n if (data.error === \"access_denied\") {\n throw new Error(\"GitHub device login was cancelled.\");\n }\n if (data.error) {\n throw new Error(data.error_description || `GitHub device login failed: ${data.error}`);\n }\n }\n\n throw new Error(\"GitHub device login timed out. Run `hoopilot login` again.\");\n}\n\nfunction oauthHeaders(): Headers {\n const headers = new Headers();\n headers.set(\"accept\", \"application/json\");\n headers.set(\"content-type\", \"application/json\");\n headers.set(\"user-agent\", \"hoopilot\");\n return headers;\n}\n\nfunction normalizeDomain(value: string): string {\n const raw = value.trim();\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(raw) ? raw : `https://${raw}`;\n let url: URL;\n try {\n url = new URL(withScheme);\n } catch {\n throw new Error(`Invalid GitHub domain: ${value}.`);\n }\n if (\n (url.protocol !== \"https:\" && url.protocol !== \"http:\") ||\n url.username ||\n url.password ||\n !url.hostname ||\n (url.pathname !== \"\" && url.pathname !== \"/\") ||\n url.search ||\n url.hash\n ) {\n throw new Error(`Invalid GitHub domain: ${value}. Provide only a hostname.`);\n }\n return url.host;\n}\n\nfunction positiveSeconds(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n\nasync function parseJsonResponse<T>(response: Response, context: string): Promise<T> {\n const text = await response.text();\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch {\n throw new Error(`${context}: ${text.slice(0, 500)}`);\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${context}: ${text.slice(0, 500)}`);\n }\n return value as T;\n}\n","import pino from \"pino\";\nimport pretty from \"pino-pretty\";\nimport type {\n HoopilotLogger,\n HoopilotLoggerOptions,\n LogFields,\n LogFormat,\n LogLevel,\n} from \"./types\";\nimport { envValue } from \"./util\";\n\nexport const DEFAULT_LOG_FORMAT: LogFormat = \"pretty\";\nexport const DEFAULT_LOG_LEVEL: LogLevel = \"info\";\n\nconst LOG_FORMATS = [\"json\", \"pretty\"] as const;\nconst LOG_LEVELS = [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\", \"silent\"] as const;\nconst REDACT_PATHS = [\n \"apiKey\",\n \"authorization\",\n \"cookie\",\n \"headers.authorization\",\n \"headers.Authorization\",\n \"headers.cookie\",\n \"headers.Cookie\",\n \"headers.x-api-key\",\n \"headers.X-Api-Key\",\n \"token\",\n \"*.apiKey\",\n \"*.authorization\",\n \"*.cookie\",\n \"*.token\",\n \"*.headers.authorization\",\n \"*.headers.Authorization\",\n \"*.headers.cookie\",\n \"*.headers.Cookie\",\n \"*.headers.x-api-key\",\n \"*.headers.X-Api-Key\",\n];\n\nexport const noopLogger: HoopilotLogger = {\n child: () => noopLogger,\n debug: () => {},\n error: () => {},\n fatal: () => {},\n info: () => {},\n trace: () => {},\n warn: () => {},\n};\n\nexport function createHoopilotLogger(options: HoopilotLoggerOptions = {}): HoopilotLogger {\n const env = options.env ?? process.env;\n const level = parseLogLevel(options.level ?? envValue(env.HOOPILOT_LOG_LEVEL));\n const format = parseLogFormat(options.format ?? envValue(env.HOOPILOT_LOG_FORMAT));\n const pinoOptions: pino.LoggerOptions = {\n base: {\n service: \"hoopilot\",\n ...options.base,\n },\n level,\n redact: {\n censor: \"[Redacted]\",\n paths: REDACT_PATHS,\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n };\n\n if (format === \"pretty\") {\n return asHoopilotLogger(\n pino(\n pinoOptions,\n pretty({\n // Probe the same sink we write to (stdout / fd 1), so colors are not\n // emitted into a redirected file when only stderr is a TTY. A custom\n // stream's TTY-ness is unknown, so default to no color there.\n colorize: options.colorize ?? (options.stream ? false : process.stdout.isTTY),\n destination: options.stream ?? 1,\n ignore: \"pid,hostname\",\n singleLine: true,\n translateTime: \"SYS:standard\",\n }),\n ),\n );\n }\n\n if (options.stream) {\n return asHoopilotLogger(pino(pinoOptions, options.stream as pino.DestinationStream));\n }\n return asHoopilotLogger(pino(pinoOptions));\n}\n\n// Cast pino's Logger to HoopilotLogger through a checked assignment, so a drift\n// in either type surfaces as a compile error here instead of being masked by an\n// unchecked `as` at each call site.\nfunction asHoopilotLogger(logger: pino.Logger): HoopilotLogger {\n return logger;\n}\n\nexport function parseLogFormat(value: string | undefined): LogFormat {\n if (!value) {\n return DEFAULT_LOG_FORMAT;\n }\n if (isLogFormat(value)) {\n return value;\n }\n throw new Error(`Invalid log format: ${value}. Expected one of: ${LOG_FORMATS.join(\", \")}.`);\n}\n\nexport function parseLogLevel(value: string | undefined): LogLevel {\n if (!value) {\n return DEFAULT_LOG_LEVEL;\n }\n if (isLogLevel(value)) {\n return value;\n }\n throw new Error(`Invalid log level: ${value}. Expected one of: ${LOG_LEVELS.join(\", \")}.`);\n}\n\nexport function shouldCreateLogger(options: {\n env?: NodeJS.ProcessEnv;\n logFormat?: string;\n logger?: HoopilotLogger;\n logLevel?: string;\n}): boolean {\n return Boolean(\n options.logger ||\n options.logFormat ||\n options.logLevel ||\n envValue(options.env?.HOOPILOT_LOG_FORMAT) ||\n envValue(options.env?.HOOPILOT_LOG_LEVEL),\n );\n}\n\n/** Build structured log fields describing an error, for the `err` log key. */\nexport function errorDetails(error: unknown): LogFields {\n if (error instanceof Error) {\n return {\n message: error.message,\n name: error.name,\n stack: error.stack,\n };\n }\n return { message: String(error) };\n}\n\nfunction isLogFormat(value: string): value is LogFormat {\n return (LOG_FORMATS as readonly string[]).includes(value);\n}\n\nfunction isLogLevel(value: string): value is LogLevel {\n return (LOG_LEVELS as readonly string[]).includes(value);\n}\n","import { createHash, timingSafeEqual } from \"node:crypto\";\nimport { Elysia } from \"elysia\";\nimport {\n AnthropicCompatibilityError,\n anthropicMessagesToResponsesRequest,\n estimateAnthropicMessageTokens,\n responsesResponseToAnthropicMessage,\n responsesSseTextToAnthropicSseText,\n responsesStreamToAnthropicStream,\n} from \"./anthropic\";\nimport { CopilotAuthError } from \"./auth\";\nimport {\n CopilotClient,\n CopilotUpstreamTimeoutError,\n normalizeCopilotUsage,\n parseRateLimitHeaders,\n} from \"./copilot\";\nimport { DASHBOARD_HTML } from \"./dashboard\";\nimport { createHoopilotLogger, errorDetails, noopLogger, shouldCreateLogger } from \"./logger\";\nimport {\n MetricsRegistry,\n observeResponseUsage,\n PROMETHEUS_CONTENT_TYPE,\n recordResponseTextUsage,\n} from \"./metrics\";\nimport {\n chatCompletionToCompletion,\n completionSseTextFromChatSseText,\n completionStreamFromChatStream,\n completionsRequestToChatCompletion,\n extractTokenUsage,\n fallbackModels,\n isResponsesCompactionRequest,\n normalizeChatCompletionRequest,\n normalizeModelsResponse,\n normalizeRequestedModel,\n normalizeResponsesRequestForCopilotBody,\n OpenAICompatibilityError,\n responsesCompactionRequestBody,\n responsesCompactionResponse,\n responsesCompactionResult,\n responsesCompactionSseText,\n responsesRequestNeedsCopilotNormalization,\n} from \"./openai\";\nimport type {\n CopilotUsage,\n HoopilotLogger,\n HoopilotServerOptions,\n JsonObject,\n LogFields,\n StartedHoopilotServer,\n StreamingProxyMode,\n TokenUsage,\n UsageResponseBody,\n} from \"./types\";\nimport {\n asRecord,\n envValue,\n errorMessage,\n isLoopbackHostname,\n parseStreamingProxyMode,\n safeJsonParse,\n} from \"./util\";\nimport { getVersion, IS_STANDALONE_BINARY } from \"./version\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 4141;\nconst FORBIDDEN_BROWSER_ORIGIN_MESSAGE =\n \"Cross-origin browser requests are blocked unless the Origin is loopback or listed in HOOPILOT_ALLOWED_ORIGINS.\";\n// API keys we ship in docs/examples as placeholders. They are effectively public,\n// so refusing them on non-loopback binds keeps a credential-backed proxy from being\n// reachable on a network with a guessable key.\nconst WELL_KNOWN_DEMO_API_KEYS = new Set([\"local-key\"]);\nconst INVALID_JSON_MESSAGE = \"Request body must be valid JSON.\";\nconst JSON_OBJECT_MESSAGE = \"Request body must be a JSON object.\";\nconst MAX_REQUEST_BODY_BYTES = 16 * 1024 * 1024;\nconst REQUEST_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;\nconst REQUEST_TOO_LARGE_MESSAGE = `Request body must be ${MAX_REQUEST_BODY_BYTES} bytes or smaller.`;\nconst USAGE_CACHE_TTL_MS = 60_000;\n\ninterface UsageReadResult {\n copilot?: CopilotUsage;\n error?: string;\n}\n\ntype UsageReader = (signal?: AbortSignal) => Promise<UsageReadResult>;\ntype TokenRecorder = (model: string, usage: TokenUsage) => void;\ntype ExtractionRecorder = (extracted: boolean) => void;\n\nclass RequestBodyTooLargeError extends Error {\n constructor() {\n super(REQUEST_TOO_LARGE_MESSAGE);\n this.name = \"RequestBodyTooLargeError\";\n }\n}\n\n// Typed body-parse failures so onError discriminates them by `instanceof` like\n// the other handler errors, instead of matching on the message string.\nclass InvalidJsonError extends Error {\n constructor() {\n super(INVALID_JSON_MESSAGE);\n this.name = \"InvalidJsonError\";\n }\n}\n\nclass JsonNotObjectError extends Error {\n constructor() {\n super(JSON_OBJECT_MESSAGE);\n this.name = \"JsonNotObjectError\";\n }\n}\n\nexport function createHoopilotHandler(\n options: HoopilotServerOptions = {},\n): (request: Request) => Promise<Response> {\n const client = new CopilotClient(options);\n const apiKey = options.apiKey ?? envValue(options.env?.HOOPILOT_API_KEY);\n const allowedOrigins = parseAllowedOrigins(options.env);\n const logger = serverLogger(options);\n const metrics = options.metrics ?? new MetricsRegistry();\n const readUsage = createUsageReader(client, metrics);\n const recordTokens: TokenRecorder = (model, usage) => metrics.recordTokens(model, usage);\n const recordExtraction: ExtractionRecorder = (extracted) =>\n metrics.recordTokenExtraction(extracted);\n const bufferProxyBodies = shouldBufferProxyBodies(resolveStreamingProxyMode(options));\n\n // Per-request channel into the Elysia lifecycle. The bookend below builds the\n // child logger once (with the canonical request id and the original path) and\n // stashes it here keyed by the request object, which Elysia passes through by\n // identity to onRequest/handlers/onError — so the id in the response header and\n // every log line agree without recomputing (or regenerating) it inside Elysia.\n const requestContext = new WeakMap<Request, RequestContext>();\n const app = buildApp({\n apiKey,\n allowedOrigins,\n bufferProxyBodies,\n client,\n metrics,\n readUsage,\n recordExtraction,\n recordTokens,\n requestContext,\n });\n\n return async (request: Request): Promise<Response> => {\n const startedAt = performance.now();\n const url = new URL(request.url);\n const apiPath = canonicalApiPath(url.pathname);\n const requestId = requestIdFor(request);\n const route = routeFor(request.method, apiPath);\n const requestLogger = logger.child({\n method: request.method,\n path: url.pathname,\n requestId,\n route,\n });\n metrics.startRequest();\n const origin = request.headers.get(\"origin\")?.trim() || undefined;\n const corsOrigin = resolveCorsAllowOrigin(origin, allowedOrigins);\n\n // Elysia owns routing, body-parse control, the pre-routing gates, and error\n // mapping. The cross-cutting bookend stays out here so it runs on EVERY\n // response — routed, gated, 404, or thrown — regardless of Elysia's\n // short-circuit semantics (an onRequest gate skips mapResponse/onAfterResponse):\n // metrics.startRequest() above pairs with the metrics.observe() that\n // finishResponse() schedules, and the per-request child logger reaches the\n // Elysia lifecycle through `requestContext`.\n const inner = normalizeInnerRequest(request, apiPath, url);\n requestContext.set(inner, {\n apiPath,\n logger: requestLogger,\n origin,\n originalPath: url.pathname,\n });\n\n let response: Response;\n try {\n response = await app.handle(inner);\n } catch (error) {\n // Elysia resolves handler and hook throws through onError, so this only\n // catches a failure inside onError itself — still finish so the in-flight\n // gauge opened by startRequest() above is always balanced.\n requestLogger.error(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request failed\",\n );\n response = jsonError(500, \"internal_error\", errorMessage(error));\n }\n\n return finishResponse(response, {\n corsOrigin,\n logger: requestLogger,\n method: request.method,\n metrics,\n requestId,\n route,\n startedAt,\n closeConnection: bufferProxyBodies,\n trackStreamingBody: !bufferProxyBodies,\n });\n };\n}\n\n// Request-scoped data the bookend computes once and threads into the Elysia\n// lifecycle, keyed by the request object (see the WeakMap note above). Carrying\n// apiPath/origin here lets the onRequest gate reuse them instead of re-parsing\n// the URL, and originalPath lets the 404 message report the caller's path rather\n// than the canonicalized inner path the router matched against.\ninterface RequestContext {\n apiPath: string;\n logger: HoopilotLogger;\n origin: string | undefined;\n originalPath: string;\n}\n\ninterface ServerDeps {\n apiKey: string | undefined;\n allowedOrigins: ReadonlySet<string>;\n bufferProxyBodies: boolean;\n client: CopilotClient;\n metrics: MetricsRegistry;\n readUsage: UsageReader;\n recordExtraction: ExtractionRecorder;\n recordTokens: TokenRecorder;\n requestContext: WeakMap<Request, RequestContext>;\n}\n\n// Build the Elysia application once per handler factory (closing over deps), then\n// drive it per request with app.handle() from the bookend above. Route handlers\n// return the raw Response objects the existing helpers build — Elysia passes a\n// returned Response through untouched (no header injection, no re-serialization),\n// so the wire format stays byte-identical. This passthrough holds only because the\n// handlers never write to Elysia's `set` (headers/status/cookie) or `store`: doing so\n// would route the response back through mapResponse and re-serialize it, drifting the\n// bytes. Each handler reads its per-request\n// child logger from `requestContext` rather than recomputing it, which keeps the\n// request id and the original request path consistent between header and logs.\n// POST routes set `parse: \"none\"` so Elysia never consumes the body: the handlers\n// stream it themselves under the 16 MB cap (readRequestText) and forward the raw\n// bytes upstream verbatim.\nfunction buildApp(deps: ServerDeps) {\n const {\n apiKey,\n allowedOrigins,\n bufferProxyBodies,\n client,\n metrics,\n readUsage,\n recordExtraction,\n recordTokens,\n requestContext,\n } = deps;\n\n // Recover the request-scoped context the bookend stashed (keyed by request\n // identity — Elysia passes the same Request object through every hook/handler).\n // A miss should never happen: the bookend always populates it before\n // app.handle(). The fallback recomputes from the request purely as a crash\n // guard so an unexpected re-wrapped request degrades instead of throwing.\n const contextFor = (request: Request): RequestContext => {\n const stored = requestContext.get(request);\n if (stored) {\n return stored;\n }\n const originalPath = new URL(request.url).pathname;\n return {\n apiPath: canonicalApiPath(originalPath),\n logger: noopLogger,\n origin: request.headers.get(\"origin\")?.trim() || undefined,\n originalPath,\n };\n };\n const loggerFor = (request: Request): HoopilotLogger => contextFor(request).logger;\n const noBody = { parse: \"none\" } as const;\n\n return (\n new Elysia()\n // Pre-routing gate, in the exact order the hand-rolled handler used: block\n // cross-origin browser requests, answer CORS preflight, serve the dashboard\n // before the API-key gate, then enforce the gate. Returning a Response\n // short-circuits routing; the bookend still decorates it via finishResponse.\n .onRequest(({ request }) => {\n const { apiPath, logger, origin } = contextFor(request);\n\n const browserOrigin = forbiddenBrowserOrigin(origin, request, allowedOrigins);\n if (browserOrigin) {\n logger.warn(\n { event: \"http.request.forbidden_origin\", origin: browserOrigin },\n \"blocked cross-origin browser request\",\n );\n return jsonError(403, \"forbidden_origin\", FORBIDDEN_BROWSER_ORIGIN_MESSAGE);\n }\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders() });\n }\n // The dashboard is a static, secret-free HTML shell. Serve it before the\n // API-key gate so a browser can open it by navigation (which cannot send\n // an Authorization header). The data it renders comes from /v1/usage,\n // which stays behind the gate; cross-origin access is blocked above.\n if (request.method === \"GET\" && apiPath === \"/dashboard\") {\n return dashboardResponse();\n }\n if (!isAuthorized(request, apiKey)) {\n logger.warn({ event: \"http.request.unauthorized\" }, \"invalid hoopilot api key\");\n return jsonError(401, \"invalid_api_key\", \"Invalid or missing Hoopilot API key.\");\n }\n })\n // Reproduce the hand-rolled catch block: map the typed errors the handlers\n // throw (and Elysia's NOT_FOUND) onto the same status/code/log events.\n // Registered before the routes: Elysia applies an error hook only to routes\n // declared after it, so a trailing onError would never see handler throws.\n .onError(({ code, error, request }) => {\n const { logger, originalPath } = contextFor(request);\n if (code === \"NOT_FOUND\") {\n // Report the caller's original path, not the canonicalized inner path\n // the router matched, so an unknown `/foo/` 404s as `/foo/` (matching\n // the pre-Elysia handler) rather than the slash-stripped `/foo`.\n return jsonError(404, \"not_found\", `No route for ${request.method} ${originalPath}.`);\n }\n if (error instanceof CopilotAuthError) {\n logger.warn(\n { err: errorDetails(error), event: \"copilot.auth.missing\" },\n \"copilot auth failed\",\n );\n return jsonError(401, \"copilot_auth_error\", error.message);\n }\n const message = errorMessage(error);\n if (error instanceof InvalidJsonError || error instanceof JsonNotObjectError) {\n logger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body was not usable json\",\n );\n return jsonError(400, \"invalid_request_error\", message);\n }\n if (\n error instanceof OpenAICompatibilityError ||\n error instanceof AnthropicCompatibilityError\n ) {\n logger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body used unsupported compatibility fields\",\n );\n return jsonError(400, \"invalid_request_error\", message);\n }\n if (error instanceof RequestBodyTooLargeError) {\n logger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body exceeded size limit\",\n );\n return jsonError(413, \"request_too_large\", message);\n }\n if (error instanceof CopilotUpstreamTimeoutError) {\n logger.warn(\n { err: errorDetails(error), event: \"copilot.request.timeout\" },\n \"copilot upstream request timed out\",\n );\n return jsonError(504, \"copilot_timeout\", message);\n }\n logger.error({ err: errorDetails(error), event: \"http.request.failed\" }, \"request failed\");\n return jsonError(500, \"internal_error\", message);\n })\n .get(\"/\", () => jsonResponse({ name: \"hoopilot\", object: \"health\", status: \"ok\" }))\n .get(\"/healthz\", () => jsonResponse({ name: \"hoopilot\", object: \"health\", status: \"ok\" }))\n .get(\"/metrics\", () => metricsResponse(metrics))\n .get(\"/v1/usage\", ({ request }) => handleUsage(metrics, readUsage, request.signal))\n .get(\"/v1/models\", ({ request }) =>\n handleModels(client, metrics, request.signal, loggerFor(request)),\n )\n .get(\"/v1/responses\", () => websocketUnsupportedResponse())\n .post(\n \"/v1/messages\",\n ({ request }) =>\n handleAnthropicMessages(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n .post(\n \"/v1/messages/count_tokens\",\n ({ request }) => handleAnthropicCountTokens(request),\n noBody,\n )\n .post(\n \"/v1/chat/completions\",\n ({ request }) =>\n handleChatCompletions(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n .post(\n \"/v1/completions\",\n ({ request }) =>\n handleCompletions(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n .post(\n \"/v1/responses/compact\",\n ({ request }) =>\n handleResponsesCompact(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n ),\n noBody,\n )\n .post(\n \"/v1/responses\",\n ({ request }) =>\n handleResponses(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n );\n}\n\n// Normalize the path the Elysia router matches against — map bare aliases like\n// `/responses` onto `/v1/responses` and strip trailing slashes (reusing the\n// single-source canonicalApiPath table) — while leaving the request's body\n// stream and abort signal intact for the handlers. Bun's Request constructor\n// copies the body and makes the new signal follow the original's abort, so the\n// clone forwards bytes and cancels upstream on disconnect exactly as before.\n// Returns the request unchanged when no rewrite is needed.\nfunction normalizeInnerRequest(request: Request, canonicalPath: string, url: URL): Request {\n if (canonicalPath === url.pathname) {\n return request;\n }\n const target = new URL(url);\n target.pathname = canonicalPath;\n const init: RequestInit & { duplex?: \"half\" } = {\n headers: request.headers,\n method: request.method,\n signal: request.signal,\n };\n if (request.body) {\n init.body = request.body;\n init.duplex = \"half\";\n }\n return new Request(target, init);\n}\n\nexport function startHoopilotServer(options: HoopilotServerOptions = {}): StartedHoopilotServer {\n const host = options.host ?? envValue(options.env?.HOST) ?? DEFAULT_HOST;\n const port = normalizeServerPort(options.port ?? envValue(options.env?.PORT) ?? DEFAULT_PORT);\n const apiKey = options.apiKey ?? envValue(options.env?.HOOPILOT_API_KEY);\n const allowUnauthenticated =\n options.allowUnauthenticated ?? envValue(options.env?.HOOPILOT_ALLOW_UNAUTHENTICATED) === \"1\";\n\n if (!isLoopbackHost(host)) {\n if (!apiKey && !allowUnauthenticated) {\n throw new Error(\n \"Refusing to listen on a non-loopback host without HOOPILOT_API_KEY. Set an API key or pass --allow-unauthenticated.\",\n );\n }\n if (apiKey && isWellKnownDemoApiKey(apiKey)) {\n throw new Error(\n \"Refusing to listen on a non-loopback host with a well-known demo HOOPILOT_API_KEY. Set a strong, unique API key.\",\n );\n }\n }\n\n const server = Bun.serve({\n fetch: createHoopilotHandler({\n ...options,\n apiKey,\n host,\n port,\n }),\n hostname: host,\n port,\n });\n\n return {\n server,\n url: `http://${urlHost(host)}:${server.port}`,\n };\n}\n\nasync function handleAnthropicMessages(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const anthropicRequest = await readJson(request);\n const responsesRequest = anthropicMessagesToResponsesRequest(anthropicRequest);\n const upstream = await client.responses(JSON.stringify(responsesRequest), request.signal);\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const model = normalizeRequestedModel(responsesRequest.model);\n\n if (isStreamingResponse(upstream) && upstream.body) {\n if (bufferProxyBodies) {\n const text = await upstream.text();\n recordResponseTextUsage(text, true, model, recordTokens, recordExtraction);\n return proxyResponse(\n responseFromText(upstream, responsesSseTextToAnthropicSseText(text, { model })),\n );\n }\n const observed = observeResponseUsage(\n upstream,\n model,\n recordTokens,\n request.signal,\n recordExtraction,\n );\n if (!observed.body) {\n return proxyResponse(observed);\n }\n return proxyResponse(\n new Response(responsesStreamToAnthropicStream(observed.body, { model }), {\n headers: observed.headers,\n status: observed.status,\n statusText: observed.statusText,\n }),\n );\n }\n\n const body = asRecord(await upstream.json());\n const usage = extractTokenUsage(body.usage);\n if (usage) {\n const responseModel = typeof body.model === \"string\" ? body.model.trim() : \"\";\n recordTokens(responseModel || model, usage);\n }\n recordExtraction(usage !== undefined);\n return jsonResponse(responsesResponseToAnthropicMessage(body, model));\n}\n\nasync function handleAnthropicCountTokens(request: Request): Promise<Response> {\n const body = await readJson(request);\n return jsonResponse(estimateAnthropicMessageTokens(body));\n}\n\nasync function handleModels(\n client: CopilotClient,\n metrics: MetricsRegistry,\n signal: AbortSignal,\n logger: HoopilotLogger,\n): Promise<Response> {\n const upstream = await client.models(signal);\n metrics.recordUpstream(\"/models\", upstream.ok);\n if (!upstream.ok) {\n if (isUpstreamAuthStatus(upstream.status)) {\n return proxyError(upstream, logger);\n }\n logger.warn(\n {\n event: \"copilot.models.fallback\",\n upstreamPath: \"/models\",\n upstreamStatus: upstream.status,\n },\n \"falling back to built-in model list\",\n );\n return jsonResponse({ data: fallbackModels(), object: \"list\" });\n }\n logUpstreamSuccess(logger, \"/models\", upstream.status);\n return jsonResponse(normalizeModelsResponse(await upstream.json()));\n}\n\nasync function handleChatCompletions(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const chatRequest = normalizeChatCompletionRequest(await readJson(request));\n const upstream = await client.chatCompletions(chatRequest, request.signal);\n metrics.recordUpstream(\"/chat/completions\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/chat/completions\", upstream.status);\n const model = normalizeRequestedModel(chatRequest.model);\n return proxyResponse(\n await responseWithObservedUsage(\n upstream,\n model,\n recordTokens,\n request.signal,\n bufferProxyBodies,\n recordExtraction,\n ),\n );\n}\n\nasync function handleCompletions(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const body = await readJson(request);\n const upstream = await client.chatCompletions(\n completionsRequestToChatCompletion(body),\n request.signal,\n );\n metrics.recordUpstream(\"/chat/completions\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/chat/completions\", upstream.status);\n const model = normalizeRequestedModel(body.model);\n // A streaming request yields chat-completion SSE; convert each chunk to the\n // legacy completions stream shape instead of calling .json() on the body.\n if (isStreamingResponse(upstream) && upstream.body) {\n if (bufferProxyBodies) {\n const upstreamText = await upstream.text();\n recordResponseTextUsage(upstreamText, true, model, recordTokens, recordExtraction);\n const text = completionSseTextFromChatSseText(upstreamText);\n return proxyResponse(responseFromText(upstream, text));\n }\n return proxyResponse(\n observeResponseUsage(\n new Response(completionStreamFromChatStream(upstream.body), {\n headers: upstream.headers,\n status: upstream.status,\n statusText: upstream.statusText,\n }),\n model,\n recordTokens,\n request.signal,\n recordExtraction,\n ),\n );\n }\n const completion = asRecord(await upstream.json());\n const usage = extractTokenUsage(completion.usage);\n if (usage) {\n const responseModel = typeof completion.model === \"string\" ? completion.model.trim() : \"\";\n recordTokens(responseModel || model, usage);\n }\n recordExtraction(usage !== undefined);\n return jsonResponse(chatCompletionToCompletion(completion));\n}\n\nasync function handleResponses(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const { json, text: body } = await readJsonText(request);\n if (isResponsesCompactionRequest(json)) {\n return handleResponsesCompactionV2(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n json,\n request,\n logger,\n );\n }\n\n const upstream = await client.responses(\n responsesRequestNeedsCopilotNormalization(json)\n ? normalizeResponsesRequestForCopilotBody(json)\n : body,\n request.signal,\n );\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const model = normalizeRequestedModel(json.model);\n return proxyResponse(\n await responseWithObservedUsage(\n upstream,\n model,\n recordTokens,\n request.signal,\n bufferProxyBodies,\n recordExtraction,\n ),\n );\n}\n\n/**\n * Codex's remote context compaction (`POST /responses/compact`, used when the\n * model provider is named \"OpenAI\" or is Azure) is a proprietary OpenAI surface\n * that Copilot does not expose, and Codex has no client-side fallback — a 404\n * there hard-fails compaction. Satisfy it by running the supplied Responses-API\n * payload through Copilot's `/responses` as a unary request and returning the\n * `{ output }` document Codex expects, so the conversation history is replaced\n * with a real model-produced summary instead of erroring out.\n */\nasync function handleResponsesCompact(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n): Promise<Response> {\n const body = await readJson(request);\n const upstream = await client.responses(responsesCompactionRequestBody(body), request.signal);\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const isSse = isStreamingResponse(upstream);\n const text = await upstream.text();\n recordResponseTextUsage(\n text,\n isSse,\n normalizeRequestedModel(body.model),\n recordTokens,\n recordExtraction,\n );\n return jsonResponse(responsesCompactionResult(text, isSse));\n}\n\nasync function handleResponsesCompactionV2(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n json: JsonObject,\n request: Request,\n logger: HoopilotLogger,\n): Promise<Response> {\n const upstream = await client.responses(responsesCompactionRequestBody(json), request.signal);\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const isSse = isStreamingResponse(upstream);\n const text = await upstream.text();\n const model = normalizeRequestedModel(json.model);\n recordResponseTextUsage(text, isSse, model, recordTokens, recordExtraction);\n if (json.stream === true) {\n return textResponse(responsesCompactionSseText(text, isSse, model), \"text/event-stream\");\n }\n return jsonResponse(responsesCompactionResponse(text, isSse, model));\n}\n\nasync function responseWithObservedUsage(\n response: Response,\n fallbackModel: string,\n recordTokens: TokenRecorder,\n signal: AbortSignal,\n bufferBody: boolean,\n recordExtraction: ExtractionRecorder,\n): Promise<Response> {\n const isSse = isStreamingResponse(response);\n if (bufferBody && response.body) {\n const text = await response.text();\n recordResponseTextUsage(text, isSse, fallbackModel, recordTokens, recordExtraction);\n return responseFromText(response, text);\n }\n return observeResponseUsage(response, fallbackModel, recordTokens, signal, recordExtraction);\n}\n\nfunction responseFromText(source: Response, text: string): Response {\n return new Response(text, {\n headers: source.headers,\n status: source.status,\n statusText: source.statusText,\n });\n}\n\nasync function proxyError(upstream: Response, logger: HoopilotLogger): Promise<Response> {\n const text = await upstream.text();\n if (isUpstreamAuthStatus(upstream.status)) {\n logger.warn(\n { event: \"copilot.auth.rejected\", upstreamStatus: upstream.status },\n \"copilot rejected credential or account access\",\n );\n return jsonError(401, \"copilot_auth_error\", upstreamAuthMessage(text || upstream.statusText));\n }\n logger.warn(\n { event: \"copilot.request.failed\", upstreamStatus: upstream.status },\n \"copilot upstream request failed\",\n );\n return upstreamErrorResponse(upstream.status, text || upstream.statusText);\n}\n\nfunction proxyResponse(upstream: Response): Response {\n const headers = new Headers(upstream.headers);\n headers.delete(\"content-encoding\");\n headers.delete(\"content-length\");\n headers.delete(\"transfer-encoding\");\n for (const [key, value] of Object.entries(corsHeaders())) {\n headers.set(key, value);\n }\n return new Response(upstream.body, {\n headers,\n status: upstream.status,\n statusText: upstream.statusText,\n });\n}\n\nasync function readJson(request: Request): Promise<JsonObject> {\n const text = await readRequestText(request);\n return parseJsonObject(text);\n}\n\nfunction parseJsonObject(text: string): JsonObject {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new InvalidJsonError();\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new JsonNotObjectError();\n }\n return parsed as JsonObject;\n}\n\nasync function readJsonText(request: Request): Promise<{ json: JsonObject; text: string }> {\n const text = await readRequestText(request);\n return { json: parseJsonObject(text), text };\n}\n\nasync function readRequestText(request: Request): Promise<string> {\n const contentLength = request.headers.get(\"content-length\");\n if (contentLength) {\n const declaredBytes = Number(contentLength);\n if (Number.isFinite(declaredBytes) && declaredBytes > MAX_REQUEST_BODY_BYTES) {\n throw new RequestBodyTooLargeError();\n }\n }\n\n const body = request.body;\n if (!body) {\n return \"\";\n }\n\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let bytes = 0;\n let text = \"\";\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return `${text}${decoder.decode()}`;\n }\n bytes += value.byteLength;\n if (bytes > MAX_REQUEST_BODY_BYTES) {\n await reader.cancel().catch(() => {});\n throw new RequestBodyTooLargeError();\n }\n text += decoder.decode(value, { stream: true });\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction jsonResponse(body: object, status = 200): Response {\n return new Response(JSON.stringify(body), {\n headers: {\n ...corsHeaders(),\n \"content-type\": \"application/json; charset=utf-8\",\n },\n status,\n });\n}\n\nfunction textResponse(body: string, contentType: string, status = 200): Response {\n return new Response(body, {\n headers: {\n ...corsHeaders(),\n \"content-type\": `${contentType}; charset=utf-8`,\n },\n status,\n });\n}\n\nfunction jsonError(status: number, code: string, message: string): Response {\n return jsonResponse(\n {\n error: {\n code,\n message,\n type: code,\n },\n },\n status,\n );\n}\n\nfunction upstreamErrorResponse(status: number, text: string): Response {\n const parsedError = asRecord(asRecord(safeJsonParse(text)).error);\n if (Object.keys(parsedError).length > 0) {\n return jsonResponse({ error: parsedError }, status);\n }\n return jsonError(status, \"copilot_error\", text);\n}\n\nfunction websocketUnsupportedResponse(): Response {\n const response = jsonError(\n 426,\n \"websocket_not_supported\",\n \"Hoopilot does not support Responses WebSocket transport; retry with HTTP Responses API.\",\n );\n response.headers.set(\"upgrade\", \"websocket\");\n return response;\n}\n\n// CORS headers shared by every response. The `access-control-allow-origin` value\n// is intentionally omitted here and set per-request by `finishResponse`, so the\n// proxy only advertises access to origins it actually allows (loopback or\n// HOOPILOT_ALLOWED_ORIGINS) instead of a blanket wildcard.\nfunction corsHeaders(): Record<string, string> {\n return {\n \"access-control-allow-headers\":\n \"anthropic-beta, anthropic-dangerous-direct-browser-access, anthropic-version, authorization, content-type, x-api-key, x-request-id\",\n \"access-control-allow-methods\": \"GET, POST, OPTIONS\",\n \"access-control-expose-headers\": \"x-request-id\",\n };\n}\n\n// Compare two secrets in constant time. Both sides are hashed to a fixed-width\n// digest first so neither the key length nor a prefix match leaks via timing.\nfunction secretEquals(candidate: string, secret: string): boolean {\n const a = createHash(\"sha256\").update(candidate).digest();\n const b = createHash(\"sha256\").update(secret).digest();\n return timingSafeEqual(a, b);\n}\n\nfunction isAuthorized(request: Request, apiKey: string | undefined): boolean {\n if (!apiKey) {\n return true;\n }\n const authorization = request.headers.get(\"authorization\") ?? \"\";\n const bearer = authorization.match(/^Bearer\\s+(.+)$/i)?.[1];\n return (\n (bearer !== undefined && secretEquals(bearer, apiKey)) ||\n secretEquals(request.headers.get(\"x-api-key\") ?? \"\", apiKey)\n );\n}\n\n// Block cross-origin browser requests regardless of whether an API key is set.\n// The proxy holds a GitHub OAuth credential and is meant for local CLI/tool\n// clients, never for arbitrary web pages: a malicious site must not be able to\n// drive it even if it knows (or guesses) the local API key. Loopback origins and\n// any origin in HOOPILOT_ALLOWED_ORIGINS are allowed through to the key check.\nfunction forbiddenBrowserOrigin(\n origin: string | undefined,\n request: Request,\n allowedOrigins: ReadonlySet<string>,\n): string | undefined {\n if (origin) {\n return isAllowedOrigin(origin, allowedOrigins) ? undefined : origin;\n }\n\n const fetchSite = request.headers.get(\"sec-fetch-site\")?.toLowerCase();\n return fetchSite === \"cross-site\" ? \"cross-site\" : undefined;\n}\n\n// Parse the comma-separated HOOPILOT_ALLOWED_ORIGINS allowlist into a normalized\n// set of exact origins (scheme + host + optional port), lower-cased for matching.\nfunction parseAllowedOrigins(env: NodeJS.ProcessEnv | undefined): ReadonlySet<string> {\n const raw = envValue(env?.HOOPILOT_ALLOWED_ORIGINS);\n if (!raw) {\n return new Set();\n }\n return new Set(\n raw\n .split(\",\")\n .map((value) => value.trim().toLowerCase())\n .filter((value) => value.length > 0),\n );\n}\n\nfunction isAllowedOrigin(origin: string, allowedOrigins: ReadonlySet<string>): boolean {\n return isLoopbackOrigin(origin) || allowedOrigins.has(origin.toLowerCase());\n}\n\n// Resolve the `access-control-allow-origin` value for a response. Allowed browser\n// origins are echoed back (so the page can read the response); a request with no\n// Origin is a non-browser client where the value is inert, so we keep `*`;\n// disallowed origins get no header (they are also blocked with a 403), so a\n// malicious page cannot read even an error body.\nfunction resolveCorsAllowOrigin(\n origin: string | undefined,\n allowedOrigins: ReadonlySet<string>,\n): string | undefined {\n if (!origin) {\n return \"*\";\n }\n return isAllowedOrigin(origin, allowedOrigins) ? origin : undefined;\n}\n\nfunction isWellKnownDemoApiKey(apiKey: string): boolean {\n return WELL_KNOWN_DEMO_API_KEYS.has(apiKey.trim().toLowerCase());\n}\n\nfunction isUpstreamAuthStatus(status: number): boolean {\n return status === 401 || status === 403;\n}\n\nfunction upstreamAuthMessage(message: string): string {\n return `GitHub Copilot rejected the credential or account access: ${message}`;\n}\n\nfunction isLoopbackHost(host: string): boolean {\n return isLoopbackHostname(host);\n}\n\nfunction urlHost(host: string): string {\n return host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host;\n}\n\nfunction isLoopbackOrigin(origin: string): boolean {\n try {\n return isLoopbackHost(new URL(origin).hostname.toLowerCase());\n } catch {\n return false;\n }\n}\n\nfunction normalizeServerPort(value: number | string): number {\n const port = Number(value);\n if (!Number.isInteger(port) || port < 0 || port > 65_535) {\n throw new Error(`Invalid port: ${value}.`);\n }\n return port;\n}\n\nfunction serverLogger(options: HoopilotServerOptions): HoopilotLogger {\n if (options.logger) {\n return options.logger.child({ component: \"server\" });\n }\n if (shouldCreateLogger(options)) {\n return createHoopilotLogger({\n env: options.env,\n format: options.logFormat,\n level: options.logLevel,\n }).child({ component: \"server\" });\n }\n return noopLogger;\n}\n\nfunction resolveStreamingProxyMode(options: HoopilotServerOptions): StreamingProxyMode {\n const value =\n options.streamingProxyMode ??\n envValue(options.env?.HOOPILOT_STREAM_MODE) ??\n envValue(options.env?.HOOPILOT_STREAMING_PROXY_MODE) ??\n \"auto\";\n return parseStreamingProxyMode(value);\n}\n\nfunction shouldBufferProxyBodies(mode: StreamingProxyMode): boolean {\n if (mode === \"buffer\") {\n return true;\n }\n if (mode === \"live\") {\n return false;\n }\n return process.platform === \"win32\" && IS_STANDALONE_BINARY;\n}\n\nfunction finishResponse(\n response: Response,\n options: {\n closeConnection: boolean;\n corsOrigin: string | undefined;\n logger: HoopilotLogger;\n method: string;\n metrics: MetricsRegistry;\n requestId: string;\n route: string;\n startedAt: number;\n trackStreamingBody: boolean;\n },\n): Response {\n const withRequestId = responseWithRequestId(\n response,\n options.requestId,\n options.closeConnection,\n options.corsOrigin,\n );\n const stream = isStreamingResponse(withRequestId);\n const status = withRequestId.status;\n // Record metrics and log when the response is truly done. For a streamed body\n // that is when the client finishes receiving (or aborts) — so the in-flight\n // gauge and duration histogram reflect the full serving lifetime, not just the\n // time to upstream headers.\n const complete = (): void => {\n const durationMs = Math.round((performance.now() - options.startedAt) * 100) / 100;\n options.metrics.observe({ durationMs, method: options.method, route: options.route, status });\n logRequestCompleted(options.logger, status, stream, durationMs);\n };\n\n if (stream && withRequestId.body && options.trackStreamingBody) {\n return new Response(trackStreamCompletion(withRequestId.body, complete), {\n headers: withRequestId.headers,\n status,\n statusText: withRequestId.statusText,\n });\n }\n complete();\n return withRequestId;\n}\n\nfunction responseWithRequestId(\n response: Response,\n requestId: string,\n closeConnection: boolean,\n corsOrigin: string | undefined,\n): Response {\n const headers = new Headers(response.headers);\n headers.set(\"x-request-id\", requestId);\n if (corsOrigin) {\n headers.set(\"access-control-allow-origin\", corsOrigin);\n // A specific (non-wildcard) origin makes the response origin-dependent, so\n // mark it Vary: Origin to keep shared caches from serving it to others.\n if (corsOrigin !== \"*\") {\n headers.append(\"vary\", \"Origin\");\n }\n } else {\n headers.delete(\"access-control-allow-origin\");\n }\n if (closeConnection) {\n headers.set(\"connection\", \"close\");\n }\n return new Response(response.body, {\n headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\n// Re-stream `body`, invoking `onComplete` exactly once when the stream finishes,\n// is cancelled (client disconnect), or errors — so callers can measure the true\n// end of a streamed response.\nfunction trackStreamCompletion(\n body: ReadableStream<Uint8Array>,\n onComplete: () => void,\n): ReadableStream<Uint8Array> {\n const reader = body.getReader();\n let fired = false;\n // Release the source reader's lock on every terminal path so it is never\n // leaked. Idempotent: the first terminal branch wins.\n const release = (): void => {\n if (fired) {\n return;\n }\n fired = true;\n onComplete();\n reader.releaseLock();\n };\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n release();\n return;\n }\n controller.enqueue(value);\n } catch (error) {\n release();\n controller.error(error);\n }\n },\n async cancel(reason) {\n if (!fired) {\n fired = true;\n onComplete();\n }\n // The lock must be released after the cancel settles, not before, so a\n // pending read is not orphaned mid-cancel.\n try {\n await reader.cancel(reason);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nfunction logRequestCompleted(\n logger: HoopilotLogger,\n status: number,\n stream: boolean,\n durationMs: number,\n): void {\n const fields: LogFields = {\n durationMs,\n event: \"http.request.completed\",\n status,\n stream,\n };\n if (status >= 500) {\n logger.error(fields, \"request completed with server error\");\n return;\n }\n if (status >= 400) {\n logger.warn(fields, \"request completed with client error\");\n return;\n }\n logger.info(fields, \"request completed\");\n}\n\nfunction requestIdFor(request: Request): string {\n const existing = request.headers.get(\"x-request-id\")?.trim();\n return existing && REQUEST_ID_PATTERN.test(existing) ? existing : crypto.randomUUID();\n}\n\nfunction canonicalApiPath(path: string): string {\n const withoutTrailingSlash = path.length > 1 ? path.replace(/\\/+$/, \"\") : path;\n switch (withoutTrailingSlash) {\n case \"/models\":\n return \"/v1/models\";\n case \"/chat/completions\":\n return \"/v1/chat/completions\";\n case \"/completions\":\n return \"/v1/completions\";\n case \"/messages\":\n return \"/v1/messages\";\n case \"/messages/count_tokens\":\n return \"/v1/messages/count_tokens\";\n case \"/responses\":\n return \"/v1/responses\";\n case \"/responses/compact\":\n return \"/v1/responses/compact\";\n case \"/usage\":\n return \"/v1/usage\";\n default:\n return withoutTrailingSlash;\n }\n}\n\n// Single source of truth mapping (method, path) to a stable route name. Both the\n// request dispatch (switch on `route`) and routeFor() derive from this table, so\n// adding or renaming a route only touches one list. Names double as metrics and\n// log labels, so they must stay stable.\nconst API_ROUTES: ReadonlyArray<{ method: string; path: string; name: string }> = [\n { method: \"GET\", path: \"/\", name: \"health\" },\n { method: \"GET\", path: \"/healthz\", name: \"health\" },\n { method: \"GET\", path: \"/dashboard\", name: \"dashboard\" },\n { method: \"GET\", path: \"/metrics\", name: \"metrics\" },\n { method: \"GET\", path: \"/v1/usage\", name: \"usage\" },\n { method: \"GET\", path: \"/v1/models\", name: \"models\" },\n { method: \"GET\", path: \"/v1/responses\", name: \"responses_websocket\" },\n { method: \"POST\", path: \"/v1/messages\", name: \"anthropic_messages\" },\n { method: \"POST\", path: \"/v1/messages/count_tokens\", name: \"anthropic_count_tokens\" },\n { method: \"POST\", path: \"/v1/chat/completions\", name: \"chat_completions\" },\n { method: \"POST\", path: \"/v1/completions\", name: \"completions\" },\n { method: \"POST\", path: \"/v1/responses/compact\", name: \"responses_compact\" },\n { method: \"POST\", path: \"/v1/responses\", name: \"responses\" },\n];\n\nfunction routeFor(method: string, path: string): string {\n if (method === \"OPTIONS\") {\n return \"cors.preflight\";\n }\n return (\n API_ROUTES.find((entry) => entry.method === method && entry.path === path)?.name ?? \"not_found\"\n );\n}\n\nfunction isStreamingResponse(response: Response): boolean {\n return response.headers.get(\"content-type\")?.includes(\"text/event-stream\") ?? false;\n}\n\nfunction logUpstreamSuccess(logger: HoopilotLogger, upstreamPath: string, status: number): void {\n logger.debug(\n {\n event: \"copilot.request.completed\",\n upstreamPath,\n upstreamStatus: status,\n },\n \"copilot upstream request completed\",\n );\n}\n\nfunction metricsResponse(metrics: MetricsRegistry): Response {\n return new Response(metrics.renderPrometheus(), {\n headers: {\n ...corsHeaders(),\n \"content-type\": PROMETHEUS_CONTENT_TYPE,\n },\n status: 200,\n });\n}\n\n// Serve the self-contained dashboard HTML. The per-request CORS and request-id\n// headers are layered on by finishResponse; the page itself embeds no secrets.\n// A strict CSP and frame-busting headers harden the page even though it handles\n// the local API key in the browser: it loads zero external resources and only\n// fetches the same-origin /v1/usage, so 'self'/'unsafe-inline' suffice, and\n// frame-ancestors/X-Frame-Options close any clickjacking surface on engines that\n// do not send Sec-Fetch-Metadata (which the cross-origin block relies on).\nfunction dashboardResponse(): Response {\n return new Response(DASHBOARD_HTML, {\n headers: {\n ...corsHeaders(),\n \"content-security-policy\":\n \"default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'\",\n \"content-type\": \"text/html; charset=utf-8\",\n \"referrer-policy\": \"no-referrer\",\n \"x-content-type-options\": \"nosniff\",\n \"x-frame-options\": \"DENY\",\n },\n status: 200,\n });\n}\n\nasync function handleUsage(\n metrics: MetricsRegistry,\n readUsage: UsageReader,\n signal: AbortSignal,\n): Promise<Response> {\n const { copilot, error } = await readUsage(signal);\n const proxy = metrics.snapshot();\n const body: UsageResponseBody = {\n copilot: copilot ?? null,\n object: \"usage\",\n proxy,\n version: await getVersion(),\n };\n if (error) {\n body.copilot_error = error;\n }\n return jsonResponse(body);\n}\n\n/**\n * Build a memoizing reader for the Copilot quota. The result is cached for\n * {@link USAGE_CACHE_TTL_MS} so repeated `/v1/usage` scrapes do not hammer\n * GitHub's REST rate limit, and missing credentials or upstream errors surface\n * as an `error` string rather than failing the whole response.\n */\nexport function createUsageReader(\n client: CopilotClient,\n metrics: MetricsRegistry,\n now: () => number = Date.now,\n ttlMs = USAGE_CACHE_TTL_MS,\n): UsageReader {\n const usagePath = \"/copilot_internal/user\";\n let cache: { atMs: number; value: CopilotUsage } | undefined;\n return async (signal) => {\n if (cache && now() - cache.atMs < ttlMs) {\n return { copilot: cache.value };\n }\n try {\n const upstream = await client.usage(signal);\n metrics.recordUpstream(usagePath, upstream.ok);\n // api.github.com returns the x-ratelimit-* budget on every reply — on the\n // error path too, where retry-after / a spent budget is the useful signal —\n // so capture it off the quota call without spending an extra request.\n metrics.recordGithubRateLimit(parseRateLimitHeaders(upstream.headers, now()));\n if (!upstream.ok) {\n return { error: `GitHub Copilot usage request failed with ${upstream.status}.` };\n }\n const value = normalizeCopilotUsage(await upstream.json().catch(() => ({})));\n cache = { atMs: now(), value };\n metrics.recordCopilotQuota(value);\n return { copilot: value };\n } catch (error) {\n if (error instanceof CopilotAuthError) {\n return { error: error.message };\n }\n metrics.recordUpstream(usagePath, false);\n return { error: errorMessage(error) };\n }\n };\n}\n","import type { JsonObject, TokenUsage } from \"./types\";\nimport {\n asRecord,\n firstNumber,\n parseJsonObject,\n randomId,\n removeUndefined,\n safeJsonParse,\n} from \"./util\";\n\nexport const DEFAULT_MODEL = \"gpt-4.1\";\n\ninterface ResponseStreamOptions {\n model: string;\n responseId?: string;\n}\n\nconst COMPACTION_SUMMARIZATION_PROMPT = `You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.\n\nInclude:\n- Current progress and key decisions made\n- Important context, constraints, or user preferences\n- What remains to be done (clear next steps)\n- Any critical data, examples, or references needed to continue\n\nBe concise, structured, and focused on helping the next LLM seamlessly continue the work.`;\n\nconst COMPACTION_SUMMARY_PREFIX =\n \"Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:\";\n\ninterface AccumulatedToolCall {\n arguments: string;\n id: string;\n index?: number;\n itemId: string;\n name: string;\n outputIndex: number;\n}\n\nexport class OpenAICompatibilityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OpenAICompatibilityError\";\n }\n}\n\nexport function responsesRequestToChatCompletion(request: JsonObject): JsonObject {\n const messages: unknown[] = [];\n const instructions = contentToText(request.instructions);\n if (instructions) {\n messages.push({ content: instructions, role: \"system\" });\n }\n\n for (const message of inputToMessages(request.input)) {\n messages.push(message);\n }\n\n return removeUndefined({\n frequency_penalty: request.frequency_penalty,\n max_tokens: request.max_output_tokens ?? request.max_tokens,\n messages,\n metadata: request.metadata,\n model: normalizeRequestedModel(request.model),\n presence_penalty: request.presence_penalty,\n reasoning_effort: asRecord(request.reasoning).effort,\n response_format: asRecord(request.text).format,\n seed: request.seed,\n stream: request.stream === true,\n temperature: request.temperature,\n tool_choice: chatToolChoice(request.tool_choice),\n tools: chatTools(request.tools),\n top_p: request.top_p,\n });\n}\n\nexport function normalizeChatCompletionRequest(request: JsonObject): JsonObject {\n return removeUndefined({\n ...request,\n model: normalizeRequestedModel(request.model),\n });\n}\n\nexport function completionsRequestToChatCompletion(request: JsonObject): JsonObject {\n assertSupportedLegacyCompletionRequest(request);\n return removeUndefined({\n frequency_penalty: request.frequency_penalty,\n logit_bias: request.logit_bias,\n max_tokens: request.max_tokens,\n messages: [{ content: legacyPromptToText(request.prompt), role: \"user\" }],\n model: normalizeRequestedModel(request.model),\n n: request.n,\n presence_penalty: request.presence_penalty,\n seed: request.seed,\n stop: request.stop,\n stream: request.stream === true,\n stream_options: request.stream_options,\n temperature: request.temperature,\n top_p: request.top_p,\n user: request.user,\n });\n}\n\nexport function normalizeRequestedModel(model: unknown): string {\n const requested = contentToText(model).trim();\n return requested || DEFAULT_MODEL;\n}\n\nexport function chatCompletionToResponse(completion: JsonObject, responseId?: string): JsonObject {\n const id = responseId ?? `resp_${randomId()}`;\n const choice = firstChoice(completion);\n const message = asRecord(choice.message);\n const model = contentToText(completion.model) || DEFAULT_MODEL;\n const output = outputItemsFromMessage(message);\n const usage = responseUsage(completion.usage);\n\n return removeUndefined({\n created_at: epochSeconds(),\n error: null,\n id,\n incomplete_details: null,\n instructions: null,\n max_output_tokens: null,\n metadata: {},\n model,\n object: \"response\",\n output,\n output_text: outputText(output),\n parallel_tool_calls: true,\n status: \"completed\",\n temperature: null,\n tool_choice: \"auto\",\n tools: [],\n top_p: null,\n usage,\n });\n}\n\n/**\n * Reduce a Copilot `/responses` result into the `{ output }` document Codex's\n * remote-compaction client (`POST /responses/compact`) deserializes. Codex keeps\n * only assistant/user message items from `output` and discards everything else,\n * so a Responses `output` array passes through verbatim; when the upstream only\n * exposes `output_text` (or, for a stream it did not honor `stream: false` on,\n * `output_text` deltas) a single assistant message is synthesized instead. The\n * input may be a unary JSON body or an SSE stream, so both framings are handled.\n */\nexport function responsesCompactionResult(upstreamText: string, isSse: boolean): JsonObject {\n const summary = compactionSummaryText(upstreamText, isSse);\n return { output: [compactionSummaryOutputMessageItem(summary)] };\n}\n\nexport function isResponsesCompactionRequest(request: JsonObject): boolean {\n return responseInputItems(request.input).some(\n (item) => contentToText(asRecord(item).type) === \"compaction_trigger\",\n );\n}\n\nexport function responsesCompactionRequestBody(request: JsonObject): string {\n return JSON.stringify(\n removeUndefined({\n ...request,\n input: [\n ...compactionInputItemsForCopilot(request.input),\n {\n content: [{ text: COMPACTION_SUMMARIZATION_PROMPT, type: \"input_text\" }],\n role: \"user\",\n type: \"message\",\n },\n ],\n parallel_tool_calls: false,\n stream: false,\n tool_choice: \"none\",\n tools: [],\n }),\n );\n}\n\nexport function normalizeResponsesRequestForCopilotBody(request: JsonObject): string {\n return JSON.stringify(\n removeUndefined({\n ...request,\n input: normalizeCompactionInputForCopilot(request.input, { dropTrigger: false }),\n }),\n );\n}\n\nexport function responsesRequestNeedsCopilotNormalization(request: JsonObject): boolean {\n return responseInputItems(request.input).some((item) => {\n const type = contentToText(asRecord(item).type);\n return type === \"compaction\" || type === \"compaction_summary\" || type === \"context_compaction\";\n });\n}\n\nexport function responsesCompactionResponse(\n upstreamText: string,\n isSse: boolean,\n model: string,\n): JsonObject {\n const output = [compactionOutputItem(compactionSummaryText(upstreamText, isSse))];\n return removeUndefined({\n created_at: epochSeconds(),\n error: null,\n id: `resp_${randomId()}`,\n incomplete_details: null,\n instructions: null,\n max_output_tokens: null,\n metadata: {},\n model,\n object: \"response\",\n output,\n output_text: \"\",\n parallel_tool_calls: false,\n status: \"completed\",\n temperature: null,\n tool_choice: \"none\",\n tools: [],\n top_p: null,\n });\n}\n\nexport function responsesCompactionSseText(\n upstreamText: string,\n isSse: boolean,\n model: string,\n): string {\n const responseId = `resp_${randomId()}`;\n const item = compactionOutputItem(compactionSummaryText(upstreamText, isSse));\n const createdAt = epochSeconds();\n let sequenceNumber = 0;\n const event = (name: string, data: JsonObject | \"[DONE]\") =>\n encodeSse(name, data === \"[DONE]\" ? data : { ...data, sequence_number: sequenceNumber++ });\n\n return [\n event(\"response.created\", {\n response: baseStreamResponse(responseId, model, createdAt, \"in_progress\", []),\n type: \"response.created\",\n }),\n event(\"response.output_item.done\", {\n item,\n output_index: 0,\n type: \"response.output_item.done\",\n }),\n event(\"response.completed\", {\n response: baseStreamResponse(responseId, model, createdAt, \"completed\", [item]),\n type: \"response.completed\",\n }),\n event(\"done\", \"[DONE]\"),\n ].join(\"\");\n}\n\nfunction compactionSummaryText(upstreamText: string, isSse: boolean): string {\n const summary = isSse\n ? compactionSummaryTextFromResponsesSse(upstreamText)\n : compactionSummaryTextFromResponse(asRecord(safeJsonParse(upstreamText)));\n return summary.trim() || \"(no summary available)\";\n}\n\nfunction compactionSummaryTextFromResponse(response: JsonObject): string {\n const output = Array.isArray(response.output)\n ? response.output.map((item) => asRecord(item))\n : [];\n const compaction = output.find((item) => contentToText(item.type) === \"compaction\");\n if (compaction) {\n return contentToText(compaction.encrypted_content);\n }\n const text = outputText(output);\n if (text) {\n return text;\n }\n return contentToText(response.output_text);\n}\n\nfunction compactionSummaryTextFromResponsesSse(text: string): string {\n let deltas = \"\";\n let completedResponse: JsonObject | undefined;\n for (const block of text.split(/\\r?\\n\\r?\\n/)) {\n const data = block\n .split(/\\r?\\n/)\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trim())\n .join(\"\");\n if (!data || data === \"[DONE]\") {\n continue;\n }\n const record = asRecord(safeJsonParse(data));\n const type = contentToText(record.type);\n if (type === \"response.output_text.delta\") {\n deltas += contentToText(record.delta);\n } else if (type === \"response.completed\" || type === \"response.incomplete\") {\n completedResponse = asRecord(record.response);\n }\n }\n if (completedResponse) {\n const summary = compactionSummaryTextFromResponse(completedResponse);\n if (summary) {\n return summary;\n }\n }\n return deltas;\n}\n\nexport function chatCompletionToCompletion(completion: JsonObject): JsonObject {\n return removeUndefined({\n choices: completionChoices(completion).map((choice, index) => {\n const message = asRecord(choice.message);\n return {\n finish_reason: choice.finish_reason ?? \"stop\",\n index: typeof choice.index === \"number\" ? choice.index : index,\n logprobs: choice.logprobs ?? null,\n text: contentToText(choice.text) || contentToText(message.content),\n };\n }),\n created: completion.created ?? epochSeconds(),\n id: completion.id ?? `cmpl_${randomId()}`,\n model: completion.model ?? DEFAULT_MODEL,\n object: \"text_completion\",\n system_fingerprint: completion.system_fingerprint,\n usage: completion.usage,\n });\n}\n\nexport function completionStreamFromChatStream(\n chatStream: ReadableStream<Uint8Array>,\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let sawTerminalEvent = false;\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueue = (data: JsonObject | \"[DONE]\") => {\n controller.enqueue(encoder.encode(encodeDataSse(data)));\n };\n const markTerminal = () => {\n sawTerminalEvent = true;\n };\n const reader = chatStream.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n buffer += decoder.decode(result.value, { stream: true });\n const blocks = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = blocks.pop() ?? \"\";\n for (const block of blocks) {\n processCompletionSseBlock(block, enqueue, markTerminal);\n }\n }\n const tail = `${buffer}${decoder.decode()}`;\n if (tail.trim()) {\n processCompletionSseBlock(tail, enqueue, markTerminal);\n }\n if (!sawTerminalEvent) {\n enqueue(\"[DONE]\");\n }\n controller.close();\n } catch (error) {\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nexport function completionSseTextFromChatSseText(text: string): string {\n const chunks: string[] = [];\n let sawTerminalEvent = false;\n const enqueue = (data: JsonObject | \"[DONE]\") => {\n chunks.push(encodeDataSse(data));\n };\n const markTerminal = () => {\n sawTerminalEvent = true;\n };\n\n for (const block of text.split(/\\r?\\n\\r?\\n/)) {\n if (block.trim()) {\n processCompletionSseBlock(block, enqueue, markTerminal);\n }\n }\n if (!sawTerminalEvent) {\n enqueue(\"[DONE]\");\n }\n return chunks.join(\"\");\n}\n\nexport function normalizeModelsResponse(upstream: unknown): JsonObject {\n const record = asRecord(upstream);\n const data = Array.isArray(record.data) ? record.data : Array.isArray(upstream) ? upstream : [];\n const models = data\n .map((model) => asRecord(model))\n .filter((model) => typeof model.id === \"string\")\n .map((model) => ({\n created: model.created ?? 0,\n id: model.id,\n object: \"model\",\n owned_by: model.owned_by ?? \"github-copilot\",\n }));\n\n return {\n data: models.length > 0 ? models : fallbackModels(),\n object: \"list\",\n };\n}\n\nexport function fallbackModels(): Array<JsonObject> {\n return [\n {\n created: 0,\n id: DEFAULT_MODEL,\n object: \"model\",\n owned_by: \"github-copilot\",\n },\n ];\n}\n\nexport function responsesStreamFromChatStream(\n chatStream: ReadableStream<Uint8Array>,\n options: ResponseStreamOptions,\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const decoder = new TextDecoder();\n const responseId = options.responseId ?? `resp_${randomId()}`;\n const messageId = `msg_${randomId()}`;\n const createdAt = epochSeconds();\n let buffer = \"\";\n let text = \"\";\n let messageOutputIndex: number | undefined;\n let nextOutputIndex = 0;\n let sequenceNumber = 0;\n const tools = new Map<number, AccumulatedToolCall>();\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueue = (event: string, data: JsonObject | \"[DONE]\") => {\n controller.enqueue(\n encoder.encode(\n encodeSse(\n event,\n data === \"[DONE]\" ? data : { ...data, sequence_number: sequenceNumber++ },\n ),\n ),\n );\n };\n\n enqueue(\"response.created\", {\n response: baseStreamResponse(responseId, options.model, createdAt, \"in_progress\", []),\n type: \"response.created\",\n });\n\n const ensureMessageStarted = () => {\n if (messageOutputIndex !== undefined) {\n return;\n }\n messageOutputIndex = nextOutputIndex++;\n enqueue(\"response.output_item.added\", {\n item: {\n content: [],\n id: messageId,\n role: \"assistant\",\n status: \"in_progress\",\n type: \"message\",\n },\n output_index: messageOutputIndex,\n type: \"response.output_item.added\",\n });\n enqueue(\"response.content_part.added\", {\n content_index: 0,\n item_id: messageId,\n output_index: messageOutputIndex,\n part: {\n annotations: [],\n text: \"\",\n type: \"output_text\",\n },\n type: \"response.content_part.added\",\n });\n };\n\n const appendText = (delta: string) => {\n ensureMessageStarted();\n text += delta;\n enqueue(\"response.output_text.delta\", {\n content_index: 0,\n delta,\n item_id: messageId,\n output_index: messageOutputIndex ?? 0,\n type: \"response.output_text.delta\",\n });\n };\n\n const appendToolCall = (toolCall: JsonObject) => {\n const fn = asRecord(toolCall.function);\n const index = typeof toolCall.index === \"number\" ? toolCall.index : tools.size;\n let existing = tools.get(index);\n const isNew = !existing;\n existing ??= {\n arguments: \"\",\n id: contentToText(toolCall.id) || `call_${randomId()}`,\n index,\n itemId: `fc_${randomId()}`,\n name: \"\",\n outputIndex: nextOutputIndex++,\n };\n existing.id = contentToText(toolCall.id) || existing.id;\n existing.name += contentToText(fn.name);\n tools.set(index, existing);\n\n if (isNew) {\n enqueue(\"response.output_item.added\", {\n item: functionCallItem(existing, \"in_progress\"),\n output_index: existing.outputIndex,\n type: \"response.output_item.added\",\n });\n }\n\n const argumentDelta = contentToText(fn.arguments);\n if (argumentDelta) {\n existing.arguments += argumentDelta;\n enqueue(\"response.function_call_arguments.delta\", {\n delta: argumentDelta,\n item_id: existing.itemId,\n output_index: existing.outputIndex,\n type: \"response.function_call_arguments.delta\",\n });\n }\n };\n\n const reader = chatStream.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n buffer += decoder.decode(result.value, { stream: true });\n const lines = buffer.split(/\\r?\\n/);\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n processChatSseLine(line, { appendText, appendToolCall });\n }\n }\n if (buffer) {\n processChatSseLine(buffer, { appendText, appendToolCall });\n }\n\n // Build the output items once so the ids emitted in the per-tool stream\n // events match the ids embedded in the final response.completed payload.\n const outputEntries: Array<[number, JsonObject]> = [];\n if (messageOutputIndex !== undefined) {\n const item = messageOutputItem(text, messageId);\n outputEntries.push([messageOutputIndex, item]);\n enqueue(\"response.output_text.done\", {\n content_index: 0,\n item_id: messageId,\n output_index: messageOutputIndex,\n text,\n type: \"response.output_text.done\",\n });\n enqueue(\"response.content_part.done\", {\n content_index: 0,\n item_id: messageId,\n output_index: messageOutputIndex,\n part: {\n annotations: [],\n text,\n type: \"output_text\",\n },\n type: \"response.content_part.done\",\n });\n enqueue(\"response.output_item.done\", {\n item,\n output_index: messageOutputIndex,\n type: \"response.output_item.done\",\n });\n }\n\n for (const tool of [...tools.values()].sort((a, b) => a.outputIndex - b.outputIndex)) {\n const item = functionCallItem(tool);\n const outputIndex = tool.outputIndex;\n outputEntries.push([outputIndex, item]);\n enqueue(\"response.function_call_arguments.done\", {\n arguments: tool.arguments,\n item_id: item.id,\n output_index: outputIndex,\n type: \"response.function_call_arguments.done\",\n });\n enqueue(\"response.output_item.done\", {\n item,\n output_index: outputIndex,\n type: \"response.output_item.done\",\n });\n }\n\n const output = outputEntries\n .sort(([left], [right]) => left - right)\n .map(([, item]) => item);\n\n enqueue(\"response.completed\", {\n response: baseStreamResponse(responseId, options.model, createdAt, \"completed\", output),\n type: \"response.completed\",\n });\n enqueue(\"done\", \"[DONE]\");\n controller.close();\n } catch (error) {\n // Tear down the upstream body so an output-side error/abort cannot leak it.\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nfunction inputToMessages(input: unknown): JsonObject[] {\n if (typeof input === \"string\") {\n return [{ content: input, role: \"user\" }];\n }\n if (!Array.isArray(input)) {\n return [];\n }\n\n const messages: JsonObject[] = [];\n for (const item of input) {\n const record = asRecord(item);\n const type = contentToText(record.type);\n if (type === \"function_call_output\") {\n messages.push({\n content: contentToText(record.output),\n role: \"tool\",\n tool_call_id: contentToText(record.call_id),\n });\n continue;\n }\n if (type === \"function_call\") {\n messages.push({\n role: \"assistant\",\n tool_calls: [\n {\n function: {\n arguments: contentToText(record.arguments),\n name: contentToText(record.name),\n },\n id: contentToText(record.call_id) || contentToText(record.id),\n type: \"function\",\n },\n ],\n });\n continue;\n }\n if (type && type !== \"message\") {\n unsupportedResponsesFeature(`input item type \"${type}\"`);\n }\n const role = responsesRoleToChatRole(contentToText(record.role));\n const content = chatMessageContent(record.content);\n if (role && content !== undefined) {\n messages.push({ content, role });\n }\n }\n return messages;\n}\n\nfunction chatMessageContent(content: unknown): string | Array<JsonObject> | undefined {\n if (typeof content === \"string\") {\n return content;\n }\n if (!Array.isArray(content)) {\n if (content === undefined || content === null) {\n return undefined;\n }\n unsupportedResponsesFeature(\"non-array message content objects\");\n }\n\n const parts: JsonObject[] = [];\n for (const part of content) {\n const record = asRecord(part);\n const type = contentToText(record.type);\n if (type === \"input_text\" || type === \"output_text\" || type === \"text\") {\n parts.push({ text: contentToText(record.text), type: \"text\" });\n continue;\n }\n if (type === \"input_image\") {\n if (contentToText(record.file_id)) {\n unsupportedResponsesFeature(\"input_image file_id parts\");\n }\n const imageUrl = contentToText(record.image_url);\n if (!imageUrl) {\n unsupportedResponsesFeature(\"input_image parts without image_url\");\n }\n const image: JsonObject = { url: imageUrl };\n const detail = contentToText(record.detail);\n if (detail) {\n image.detail = detail;\n }\n parts.push({ image_url: image, type: \"image_url\" });\n continue;\n }\n if (type === \"input_file\") {\n unsupportedResponsesFeature(\"input_file parts\");\n }\n if (type === \"input_audio\") {\n unsupportedResponsesFeature(\"input_audio parts\");\n }\n unsupportedResponsesFeature(`content part type \"${type || \"unknown\"}\"`);\n }\n\n if (parts.length === 0) {\n return undefined;\n }\n if (parts.every((part) => part.type === \"text\")) {\n return parts.map((part) => contentToText(part.text)).join(\"\\n\");\n }\n return parts;\n}\n\nfunction legacyPromptToText(prompt: unknown): string {\n if (typeof prompt === \"string\") {\n return prompt;\n }\n if (Array.isArray(prompt) && prompt.length === 1 && typeof prompt[0] === \"string\") {\n return prompt[0];\n }\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility supports exactly one string prompt per request.\",\n );\n}\n\nfunction assertSupportedLegacyCompletionRequest(request: JsonObject): void {\n if (request.echo === true) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support echo=true.\",\n );\n }\n if (typeof request.best_of === \"number\" && request.best_of > 1) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support best_of greater than 1.\",\n );\n }\n if (typeof request.logprobs === \"number\" && request.logprobs > 0) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support legacy logprobs.\",\n );\n }\n if (contentToText(request.suffix)) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support suffix.\",\n );\n }\n}\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (typeof content === \"number\" || typeof content === \"boolean\") {\n return String(content);\n }\n if (Array.isArray(content)) {\n return content\n .map((item) => contentToText(item))\n .filter(Boolean)\n .join(\"\\n\");\n }\n if (content && typeof content === \"object\") {\n const record = content as Record<string, unknown>;\n if (typeof record.text === \"string\") {\n return record.text;\n }\n if (typeof record.output_text === \"string\") {\n return record.output_text;\n }\n return JSON.stringify(content);\n }\n return \"\";\n}\n\nfunction responsesRoleToChatRole(role: string): string | undefined {\n if (!role) {\n return \"user\";\n }\n if (\n role === \"assistant\" ||\n role === \"developer\" ||\n role === \"system\" ||\n role === \"tool\" ||\n role === \"user\"\n ) {\n return role === \"developer\" ? \"system\" : role;\n }\n unsupportedResponsesFeature(`message role \"${role}\"`);\n}\n\nfunction chatTools(tools: unknown): JsonObject[] | undefined {\n if (!Array.isArray(tools)) {\n return undefined;\n }\n const converted = tools.map((tool) => {\n const record = asRecord(tool);\n const type = contentToText(record.type);\n if (type !== \"function\") {\n unsupportedResponsesFeature(`tool type \"${type || \"unknown\"}\"`);\n }\n return {\n function: removeUndefined({\n description: record.description,\n name: record.name,\n parameters: record.parameters,\n strict: record.strict,\n }),\n type: \"function\",\n };\n });\n return converted.length > 0 ? converted : undefined;\n}\n\nfunction chatToolChoice(toolChoice: unknown): unknown {\n if (typeof toolChoice === \"string\" || toolChoice === undefined) {\n return toolChoice;\n }\n const record = asRecord(toolChoice);\n const type = contentToText(record.type);\n if (type === \"function\" && typeof record.name === \"string\") {\n return { function: { name: record.name }, type: \"function\" };\n }\n unsupportedResponsesFeature(`tool_choice type \"${type || \"unknown\"}\"`);\n}\n\nfunction unsupportedResponsesFeature(feature: string): never {\n throw new OpenAICompatibilityError(\n `Hoopilot Responses-to-chat compatibility does not support ${feature}.`,\n );\n}\n\nfunction outputItemsFromMessage(message: Record<string, unknown>): JsonObject[] {\n const output: JsonObject[] = [];\n const text = contentToText(message.content);\n if (text) {\n output.push(messageOutputItem(text));\n }\n const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];\n for (const toolCall of toolCalls) {\n const record = asRecord(toolCall);\n const fn = asRecord(record.function);\n output.push(\n functionCallItem({\n arguments: contentToText(fn.arguments),\n id: contentToText(record.id) || `call_${randomId()}`,\n name: contentToText(fn.name),\n }),\n );\n }\n return output;\n}\n\nfunction messageOutputItem(text: string, id = `msg_${randomId()}`): JsonObject {\n return {\n content: [\n {\n annotations: [],\n text,\n type: \"output_text\",\n },\n ],\n id,\n role: \"assistant\",\n status: \"completed\",\n type: \"message\",\n };\n}\n\nfunction compactionSummaryOutputMessageItem(text: string): JsonObject {\n return compactionSummaryMessageItem(text, `msg_${randomId()}`);\n}\n\nfunction compactionSummaryInputMessageItem(text: string): JsonObject {\n return compactionSummaryMessageItem(text);\n}\n\nfunction compactionSummaryMessageItem(text: string, id?: string): JsonObject {\n return removeUndefined({\n content: [\n {\n text: `${COMPACTION_SUMMARY_PREFIX}\\n${text}`,\n type: \"input_text\",\n },\n ],\n id,\n role: \"user\",\n type: \"message\",\n });\n}\n\nfunction compactionOutputItem(text: string, id = `cmpct_${randomId()}`): JsonObject {\n return {\n encrypted_content: text,\n id,\n type: \"compaction\",\n };\n}\n\nfunction normalizeCompactionInputForCopilot(\n input: unknown,\n options: { dropTrigger: boolean },\n): unknown {\n const items = responseInputItems(input);\n if (items.length === 0) {\n return input;\n }\n\n const normalized: unknown[] = [];\n for (const item of items) {\n const record = asRecord(item);\n const type = contentToText(record.type);\n if (type === \"compaction_trigger\" && options.dropTrigger) {\n continue;\n }\n if (type === \"compaction\" || type === \"compaction_summary\" || type === \"context_compaction\") {\n const text = contentToText(record.encrypted_content);\n if (text) {\n normalized.push(compactionSummaryInputMessageItem(text));\n }\n continue;\n }\n normalized.push(item);\n }\n return normalized;\n}\n\nfunction compactionInputItemsForCopilot(input: unknown): unknown[] {\n if (Array.isArray(input)) {\n return normalizeCompactionInputForCopilot(input, { dropTrigger: true }) as unknown[];\n }\n const text = contentToText(input);\n return text\n ? [\n {\n content: [{ text, type: \"input_text\" }],\n role: \"user\",\n type: \"message\",\n },\n ]\n : [];\n}\n\nfunction responseInputItems(input: unknown): unknown[] {\n return Array.isArray(input) ? input : [];\n}\n\nfunction functionCallItem(\n tool: { arguments: string; id: string; itemId?: string; name: string },\n status: \"in_progress\" | \"completed\" = \"completed\",\n): JsonObject {\n return {\n arguments: tool.arguments,\n call_id: tool.id,\n id: tool.itemId ?? `fc_${randomId()}`,\n name: tool.name,\n status,\n type: \"function_call\",\n };\n}\n\nfunction outputText(output: JsonObject[]): string {\n return output\n .flatMap((item) => {\n const content = item.content;\n return Array.isArray(content) ? content : [];\n })\n .map((part) => contentToText(asRecord(part).text))\n .filter(Boolean)\n .join(\"\");\n}\n\nfunction responseUsage(usage: unknown): JsonObject | null {\n const record = asRecord(usage);\n if (Object.keys(record).length === 0) {\n return null;\n }\n const inputTokens = record.prompt_tokens;\n const outputTokens = record.completion_tokens;\n return removeUndefined({\n input_tokens: inputTokens,\n input_tokens_details: responseUsageDetails(record.prompt_tokens_details, inputTokens, {\n cached_tokens: 0,\n }),\n output_tokens: outputTokens,\n output_tokens_details: responseUsageDetails(record.completion_tokens_details, outputTokens, {\n reasoning_tokens: 0,\n }),\n total_tokens: record.total_tokens,\n });\n}\n\nfunction responseUsageDetails(\n value: unknown,\n tokenCount: unknown,\n fallback: JsonObject,\n): JsonObject | undefined {\n const record = asRecord(value);\n if (Object.keys(record).length > 0) {\n return record;\n }\n return typeof tokenCount === \"number\" && Number.isFinite(tokenCount) ? fallback : undefined;\n}\n\n/**\n * Normalize an upstream `usage` object into {@link TokenUsage}. Accepts both the\n * Chat Completions shape (`prompt_tokens`/`completion_tokens`) and the Responses\n * shape (`input_tokens`/`output_tokens`), and pulls nested reasoning/cached\n * details when present. Returns undefined when no token counts are available so\n * callers can distinguish \"no usage reported\" from \"zero tokens\".\n */\nexport function extractTokenUsage(usage: unknown): TokenUsage | undefined {\n const record = asRecord(usage);\n const prompt = firstNumber(record.prompt_tokens, record.input_tokens);\n const completion = firstNumber(record.completion_tokens, record.output_tokens);\n const total = firstNumber(record.total_tokens);\n if (prompt === undefined && completion === undefined && total === undefined) {\n return undefined;\n }\n const promptTokens = prompt ?? 0;\n const completionTokens = completion ?? 0;\n const reasoning = firstNumber(\n asRecord(record.completion_tokens_details).reasoning_tokens,\n asRecord(record.output_tokens_details).reasoning_tokens,\n );\n const cached = firstNumber(\n record.cache_read_input_tokens,\n asRecord(record.prompt_tokens_details).cached_tokens,\n asRecord(record.input_tokens_details).cached_tokens,\n );\n const result: TokenUsage = {\n completionTokens,\n promptTokens,\n totalTokens: total ?? promptTokens + completionTokens,\n };\n if (cached !== undefined) {\n result.cachedTokens = cached;\n }\n if (reasoning !== undefined) {\n result.reasoningTokens = reasoning;\n }\n return result;\n}\n\nfunction firstChoice(completion: JsonObject): Record<string, unknown> {\n return completionChoices(completion)[0] ?? {};\n}\n\nfunction completionChoices(completion: JsonObject): Array<Record<string, unknown>> {\n const choices = Array.isArray(completion.choices) ? completion.choices : [];\n return choices.map((choice) => asRecord(choice));\n}\n\nfunction processCompletionSseBlock(\n block: string,\n enqueue: (data: JsonObject | \"[DONE]\") => void,\n markTerminal: () => void,\n): void {\n let event = \"message\";\n const dataLines: string[] = [];\n for (const line of block.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"event:\")) {\n event = trimmed.slice(\"event:\".length).trim() || event;\n } else if (trimmed.startsWith(\"data:\")) {\n dataLines.push(trimmed.slice(\"data:\".length).trim());\n }\n }\n const data = dataLines.join(\"\\n\");\n if (!data) {\n return;\n }\n if (data === \"[DONE]\") {\n markTerminal();\n enqueue(\"[DONE]\");\n return;\n }\n\n const parsed = parseJsonObject(data);\n if (!parsed) {\n return;\n }\n const error = completionStreamError(event, parsed);\n if (error) {\n markTerminal();\n enqueue({ error });\n return;\n }\n const choices = completionChoices(parsed)\n .map((choice, index) => {\n const delta = asRecord(choice.delta);\n const text = contentToText(delta.content);\n const finishReason = choice.finish_reason ?? null;\n if (!text && finishReason === null) {\n return undefined;\n }\n return {\n finish_reason: finishReason,\n index: typeof choice.index === \"number\" ? choice.index : index,\n logprobs: choice.logprobs ?? null,\n text,\n };\n })\n .filter((choice) => choice !== undefined);\n const usage = asRecord(parsed.usage);\n const hasUsage = Object.keys(usage).length > 0;\n if (choices.length === 0 && !hasUsage) {\n return;\n }\n\n enqueue(\n removeUndefined({\n choices,\n created: typeof parsed.created === \"number\" ? parsed.created : epochSeconds(),\n id: contentToText(parsed.id) || `cmpl_${randomId()}`,\n model: contentToText(parsed.model) || DEFAULT_MODEL,\n object: \"text_completion\",\n usage: hasUsage ? usage : undefined,\n }),\n );\n}\n\nfunction completionStreamError(event: string, parsed: JsonObject): JsonObject | undefined {\n const responseError = asRecord(asRecord(parsed.response).error);\n const directError = asRecord(parsed.error);\n const error =\n Object.keys(directError).length > 0\n ? directError\n : Object.keys(responseError).length > 0\n ? responseError\n : undefined;\n if (error) {\n return error;\n }\n if (event === \"error\" || parsed.type === \"response.failed\") {\n return removeUndefined({\n code: contentToText(parsed.code) || undefined,\n message: contentToText(parsed.message) || \"Upstream streaming request failed.\",\n type: contentToText(parsed.type) || \"upstream_stream_error\",\n });\n }\n return undefined;\n}\n\nfunction processChatSseLine(\n line: string,\n handlers: {\n appendText: (delta: string) => void;\n appendToolCall: (toolCall: JsonObject) => void;\n },\n): void {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) {\n return;\n }\n const data = trimmed.slice(\"data:\".length).trim();\n if (!data || data === \"[DONE]\") {\n return;\n }\n\n const parsed = parseJsonObject(data);\n if (!parsed) {\n return;\n }\n const choice = firstChoice(parsed);\n const delta = asRecord(choice.delta);\n const content = contentToText(delta.content);\n if (content) {\n handlers.appendText(content);\n }\n\n const toolCalls = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];\n for (const toolCall of toolCalls) {\n handlers.appendToolCall(asRecord(toolCall));\n }\n}\n\nfunction baseStreamResponse(\n id: string,\n model: string,\n createdAt: number,\n status: \"in_progress\" | \"completed\",\n output: JsonObject[],\n): JsonObject {\n return {\n created_at: createdAt,\n error: null,\n id,\n incomplete_details: null,\n instructions: null,\n max_output_tokens: null,\n metadata: {},\n model,\n object: \"response\",\n output,\n parallel_tool_calls: true,\n status,\n temperature: null,\n tool_choice: \"auto\",\n tools: [],\n top_p: null,\n };\n}\n\nfunction encodeSse(event: string, data: JsonObject | \"[DONE]\"): string {\n if (data === \"[DONE]\") {\n return \"data: [DONE]\\n\\n\";\n }\n return `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n}\n\nfunction encodeDataSse(data: JsonObject | \"[DONE]\"): string {\n if (data === \"[DONE]\") {\n return \"data: [DONE]\\n\\n\";\n }\n return `data: ${JSON.stringify(data)}\\n\\n`;\n}\n\nfunction epochSeconds(): number {\n return Math.floor(Date.now() / 1000);\n}\n","import { normalizeRequestedModel } from \"./openai\";\nimport type { JsonObject } from \"./types\";\nimport { asRecord, firstNumber, parseJsonObject, randomId, removeUndefined } from \"./util\";\n\ninterface AnthropicStreamOptions {\n model: string;\n messageId?: string;\n}\n\ninterface StreamBlock {\n index: number;\n sentText: string;\n stopped: boolean;\n type: \"text\" | \"tool_use\";\n}\n\ninterface AnthropicStreamState {\n blocks: Map<string, StreamBlock>;\n completed: boolean;\n messageId: string;\n model: string;\n nextBlockIndex: number;\n sawToolUse: boolean;\n started: boolean;\n usage: JsonObject;\n}\n\nexport class AnthropicCompatibilityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AnthropicCompatibilityError\";\n }\n}\n\nexport function anthropicMessagesToResponsesRequest(request: JsonObject): JsonObject {\n const system = anthropicSystemToResponses(request.system);\n const response = removeUndefined({\n input: [...system.input, ...anthropicMessagesToResponsesInput(request.messages)],\n instructions: system.instructions,\n max_output_tokens:\n typeof request.max_tokens === \"number\" && Number.isFinite(request.max_tokens)\n ? request.max_tokens\n : undefined,\n metadata: request.metadata,\n model: normalizeRequestedModel(request.model),\n parallel_tool_calls: asRecord(request.tool_choice).disable_parallel_tool_use !== true,\n reasoning: anthropicThinkingToReasoning(request.thinking),\n stop: anthropicStopSequences(request.stop_sequences),\n stream: request.stream === true,\n temperature: request.temperature,\n tool_choice: anthropicToolChoice(request.tool_choice),\n tools: anthropicTools(request.tools),\n top_p: request.top_p,\n });\n applyCacheControlToLastBlock(response, anthropicCacheControl(request.cache_control));\n return response;\n}\n\nexport function responsesResponseToAnthropicMessage(\n response: JsonObject,\n fallbackModel: string,\n): JsonObject {\n const content = anthropicContentFromResponsesOutput(response);\n const usage = anthropicUsage(response.usage);\n return {\n content,\n id: textValue(response.id) || `msg_${randomId()}`,\n model: textValue(response.model) || fallbackModel,\n role: \"assistant\",\n stop_reason: anthropicStopReason(response, content),\n stop_sequence: null,\n type: \"message\",\n usage,\n };\n}\n\nexport function responsesStreamToAnthropicStream(\n stream: ReadableStream<Uint8Array>,\n options: AnthropicStreamOptions,\n): ReadableStream<Uint8Array> {\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n let buffer = \"\";\n const state = createAnthropicStreamState(options);\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueue = (event: string, data: JsonObject) => {\n controller.enqueue(encoder.encode(encodeSse(event, data)));\n };\n const reader = stream.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n buffer += decoder.decode(result.value, { stream: true });\n const blocks = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = blocks.pop() ?? \"\";\n for (const block of blocks) {\n processResponsesSseBlock(block, state, enqueue);\n }\n }\n const tail = `${buffer}${decoder.decode()}`;\n if (tail.trim()) {\n processResponsesSseBlock(tail, state, enqueue);\n }\n finishAnthropicStream(state, enqueue);\n controller.close();\n } catch (error) {\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nexport function responsesSseTextToAnthropicSseText(\n text: string,\n options: AnthropicStreamOptions,\n): string {\n const chunks: string[] = [];\n const state = createAnthropicStreamState(options);\n const enqueue = (event: string, data: JsonObject) => {\n chunks.push(encodeSse(event, data));\n };\n\n for (const block of text.split(/\\r?\\n\\r?\\n/)) {\n if (block.trim()) {\n processResponsesSseBlock(block, state, enqueue);\n }\n }\n finishAnthropicStream(state, enqueue);\n return chunks.join(\"\");\n}\n\nexport function estimateAnthropicMessageTokens(request: JsonObject): JsonObject {\n const chars =\n estimatedTextSize(request.system) +\n estimatedTextSize(request.messages) +\n estimatedTextSize(request.tools) +\n estimatedTextSize(request.tool_choice) +\n estimatedTextSize(request.thinking);\n const messageCount = Array.isArray(request.messages) ? request.messages.length : 1;\n const toolCount = Array.isArray(request.tools) ? request.tools.length : 0;\n const inputTokens = Math.max(1, Math.ceil(chars / 4) + messageCount * 4 + toolCount * 16);\n return {\n input_tokens: inputTokens,\n total_tokens: inputTokens,\n };\n}\n\nfunction createAnthropicStreamState(options: AnthropicStreamOptions): AnthropicStreamState {\n return {\n blocks: new Map(),\n completed: false,\n messageId: options.messageId ?? `msg_${randomId()}`,\n model: options.model,\n nextBlockIndex: 0,\n sawToolUse: false,\n started: false,\n usage: anthropicUsage(undefined),\n };\n}\n\nfunction anthropicMessagesToResponsesInput(messages: unknown): JsonObject[] {\n if (!Array.isArray(messages)) {\n throw new AnthropicCompatibilityError(\"Anthropic Messages requests require messages[].\");\n }\n\n const input: JsonObject[] = [];\n let fallbackToolCallIndex = 0;\n for (const message of messages) {\n const record = asRecord(message);\n const role = anthropicRole(record.role);\n const parts = anthropicContentParts(record.content);\n const messageParts: JsonObject[] = [];\n const flushMessage = () => {\n if (messageParts.length === 0) {\n return;\n }\n input.push({\n content: [...messageParts],\n role,\n type: \"message\",\n });\n messageParts.length = 0;\n };\n\n for (const part of parts) {\n const type = textValue(part.type) || \"text\";\n if (type === \"text\") {\n const text = textValue(part.text);\n if (text) {\n messageParts.push(\n removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n text,\n type: role === \"assistant\" ? \"output_text\" : \"input_text\",\n }),\n );\n }\n continue;\n }\n if (type === \"image\") {\n if (role !== \"user\") {\n throw new AnthropicCompatibilityError(\n \"Anthropic image content is only supported for user messages.\",\n );\n }\n messageParts.push(anthropicImageToResponsesPart(part));\n continue;\n }\n if (type === \"tool_use\") {\n flushMessage();\n input.push(\n removeUndefined({\n arguments: JSON.stringify(asRecord(part.input)),\n cache_control: anthropicCacheControl(part.cache_control),\n call_id: textValue(part.id) || `call_hoopilot_${fallbackToolCallIndex++}`,\n name: textValue(part.name),\n type: \"function_call\",\n }),\n );\n continue;\n }\n if (type === \"tool_result\") {\n flushMessage();\n input.push(\n removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n call_id: textValue(part.tool_use_id),\n output: anthropicToolResultOutput(part.content),\n type: \"function_call_output\",\n }),\n );\n continue;\n }\n if (type === \"thinking\" || type === \"redacted_thinking\") {\n continue;\n }\n throw new AnthropicCompatibilityError(\n `Anthropic content block type \"${type}\" is not supported.`,\n );\n }\n flushMessage();\n }\n return input;\n}\n\nfunction anthropicRole(value: unknown): \"assistant\" | \"user\" {\n const role = textValue(value);\n if (role === \"assistant\" || role === \"user\") {\n return role;\n }\n if (!role) {\n return \"user\";\n }\n throw new AnthropicCompatibilityError(`Anthropic message role \"${role}\" is not supported.`);\n}\n\nfunction anthropicContentParts(content: unknown): JsonObject[] {\n if (typeof content === \"string\") {\n return [{ text: content, type: \"text\" }];\n }\n if (Array.isArray(content)) {\n return content.map((part) =>\n typeof part === \"string\" ? { text: part, type: \"text\" } : asRecord(part),\n );\n }\n if (content === undefined || content === null) {\n return [];\n }\n return [asRecord(content)];\n}\n\nfunction anthropicImageToResponsesPart(part: JsonObject): JsonObject {\n const source = asRecord(part.source);\n const sourceType = textValue(source.type);\n if (sourceType === \"base64\") {\n const mediaType = textValue(source.media_type) || \"image/png\";\n const data = textValue(source.data);\n if (!data) {\n throw new AnthropicCompatibilityError(\"Anthropic base64 image content requires source.data.\");\n }\n return removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n detail: \"auto\",\n image_url: `data:${mediaType};base64,${data}`,\n type: \"input_image\",\n });\n }\n if (sourceType === \"url\") {\n const url = textValue(source.url);\n if (!url) {\n throw new AnthropicCompatibilityError(\"Anthropic URL image content requires source.url.\");\n }\n return removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n detail: \"auto\",\n image_url: url,\n type: \"input_image\",\n });\n }\n throw new AnthropicCompatibilityError(\n `Anthropic image source type \"${sourceType || \"unknown\"}\" is not supported.`,\n );\n}\n\nfunction anthropicToolResultOutput(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n const record = asRecord(part);\n return textValue(record.text) || textValue(record.content) || JSON.stringify(part);\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n if (content === undefined || content === null) {\n return \"\";\n }\n return typeof content === \"object\" ? JSON.stringify(content) : String(content);\n}\n\nfunction anthropicSystemToResponses(system: unknown): {\n input: JsonObject[];\n instructions?: string;\n} {\n if (typeof system === \"string\") {\n return { input: [], instructions: system || undefined };\n }\n if (!Array.isArray(system)) {\n return { input: [] };\n }\n const parts = system\n .map((part) => anthropicSystemPartToResponsesPart(part))\n .filter((part): part is JsonObject => part !== undefined);\n if (parts.length === 0) {\n return { input: [] };\n }\n if (parts.some((part) => part.cache_control !== undefined)) {\n return {\n input: [\n {\n content: parts,\n role: \"system\",\n type: \"message\",\n },\n ],\n };\n }\n const text = parts\n .map((part) => textValue(part.text))\n .filter(Boolean)\n .join(\"\\n\");\n return { input: [], instructions: text || undefined };\n}\n\nfunction anthropicSystemPartToResponsesPart(part: unknown): JsonObject | undefined {\n const record = asRecord(part);\n const text = textValue(record.text) || textValue(part);\n if (!text) {\n return undefined;\n }\n return removeUndefined({\n cache_control: anthropicCacheControl(record.cache_control),\n text,\n type: \"input_text\",\n });\n}\n\nfunction anthropicTools(tools: unknown): JsonObject[] | undefined {\n if (!Array.isArray(tools)) {\n return undefined;\n }\n const converted = tools.map((tool) => {\n const record = asRecord(tool);\n return removeUndefined({\n cache_control: anthropicCacheControl(record.cache_control),\n description: record.description,\n name: record.name,\n parameters: record.input_schema,\n strict: record.strict,\n type: \"function\",\n });\n });\n return converted.length > 0 ? converted : undefined;\n}\n\nfunction anthropicCacheControl(value: unknown): JsonObject | undefined {\n if (value === undefined || value === null) {\n return undefined;\n }\n const record = asRecord(value);\n const type = textValue(record.type);\n if (type !== \"ephemeral\") {\n throw new AnthropicCompatibilityError(\n `Anthropic cache_control type \"${type || \"unknown\"}\" is not supported.`,\n );\n }\n const ttl = textValue(record.ttl);\n if (ttl && ttl !== \"5m\" && ttl !== \"1h\") {\n throw new AnthropicCompatibilityError(`Anthropic cache_control ttl \"${ttl}\" is not supported.`);\n }\n return removeUndefined({\n ttl: ttl || undefined,\n type,\n });\n}\n\nfunction applyCacheControlToLastBlock(request: JsonObject, cacheControl: JsonObject | undefined) {\n if (!cacheControl) {\n return;\n }\n const input = Array.isArray(request.input) ? request.input : [];\n for (let itemIndex = input.length - 1; itemIndex >= 0; itemIndex -= 1) {\n const item = asRecord(input[itemIndex]);\n const content = Array.isArray(item.content) ? item.content : [];\n for (let partIndex = content.length - 1; partIndex >= 0; partIndex -= 1) {\n const part = asRecord(content[partIndex]);\n if (part.cache_control === undefined && isCacheableResponsesPart(part)) {\n part.cache_control = cacheControl;\n return;\n }\n }\n }\n const tools = Array.isArray(request.tools) ? request.tools : [];\n for (let index = tools.length - 1; index >= 0; index -= 1) {\n const tool = asRecord(tools[index]);\n if (tool.cache_control === undefined) {\n tool.cache_control = cacheControl;\n return;\n }\n }\n}\n\nfunction isCacheableResponsesPart(part: JsonObject): boolean {\n const type = textValue(part.type);\n return (\n type === \"input_text\" || type === \"output_text\" || type === \"text\" || type === \"input_image\"\n );\n}\n\nfunction anthropicToolChoice(toolChoice: unknown): unknown {\n if (toolChoice === undefined || toolChoice === null) {\n return undefined;\n }\n const record = asRecord(toolChoice);\n const type = textValue(record.type);\n if (type === \"auto\") {\n return \"auto\";\n }\n if (type === \"any\") {\n return \"required\";\n }\n if (type === \"none\") {\n return \"none\";\n }\n if (type === \"tool\") {\n return { name: textValue(record.name), type: \"function\" };\n }\n throw new AnthropicCompatibilityError(\n `Anthropic tool_choice type \"${type || \"unknown\"}\" is not supported.`,\n );\n}\n\nfunction anthropicThinkingToReasoning(thinking: unknown): JsonObject | undefined {\n const record = asRecord(thinking);\n if (Object.keys(record).length === 0) {\n return undefined;\n }\n const type = textValue(record.type);\n if (type && type !== \"enabled\") {\n return undefined;\n }\n const budget = typeof record.budget_tokens === \"number\" ? record.budget_tokens : 0;\n return {\n effort: budget >= 16_000 ? \"high\" : budget >= 4_000 ? \"medium\" : \"low\",\n };\n}\n\nfunction anthropicStopSequences(stopSequences: unknown): unknown {\n if (!Array.isArray(stopSequences) || stopSequences.length === 0) {\n return undefined;\n }\n return stopSequences.map((sequence) => textValue(sequence)).filter(Boolean);\n}\n\nfunction anthropicContentFromResponsesOutput(response: JsonObject): JsonObject[] {\n const content: JsonObject[] = [];\n const output = Array.isArray(response.output) ? response.output : [];\n for (const item of output) {\n const record = asRecord(item);\n const type = textValue(record.type);\n if (type === \"message\") {\n const parts = Array.isArray(record.content) ? record.content : [];\n for (const part of parts) {\n const partRecord = asRecord(part);\n const text = textValue(partRecord.text) || textValue(partRecord.output_text);\n if (text) {\n content.push({ text, type: \"text\" });\n }\n }\n continue;\n }\n if (type === \"function_call\") {\n content.push({\n id: textValue(record.call_id) || textValue(record.id) || `call_${randomId()}`,\n input: parseToolInput(textValue(record.arguments)),\n name: textValue(record.name),\n type: \"tool_use\",\n });\n }\n }\n\n if (content.length === 0) {\n const outputText = textValue(response.output_text);\n if (outputText) {\n content.push({ text: outputText, type: \"text\" });\n }\n }\n return content;\n}\n\nfunction anthropicStopReason(response: JsonObject, content: JsonObject[]): string {\n if (content.some((part) => part.type === \"tool_use\")) {\n return \"tool_use\";\n }\n const incompleteReason = textValue(asRecord(response.incomplete_details).reason);\n if (textValue(response.status) === \"incomplete\" || incompleteReason === \"max_output_tokens\") {\n return \"max_tokens\";\n }\n return \"end_turn\";\n}\n\nfunction anthropicUsage(usage: unknown): JsonObject {\n const record = asRecord(usage);\n const inputTokens = firstNumber(record.input_tokens, record.prompt_tokens) ?? 0;\n const outputTokens = firstNumber(record.output_tokens, record.completion_tokens) ?? 0;\n const details = asRecord(record.input_tokens_details);\n return removeUndefined({\n cache_creation_input_tokens: firstNumber(record.cache_creation_input_tokens),\n cache_read_input_tokens:\n firstNumber(record.cache_read_input_tokens, details.cached_tokens) ?? undefined,\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n });\n}\n\nfunction processResponsesSseBlock(\n block: string,\n state: AnthropicStreamState,\n enqueue: (event: string, data: JsonObject) => void,\n): void {\n const { data, event } = parseSseBlock(block);\n if (!data || data === \"[DONE]\") {\n return;\n }\n const parsed = parseJsonObject(data);\n if (!parsed) {\n return;\n }\n const type = textValue(parsed.type) || event;\n if (type === \"response.created\") {\n const response = asRecord(parsed.response);\n state.messageId = textValue(response.id) || state.messageId;\n state.model = textValue(response.model) || state.model;\n startAnthropicMessage(state, enqueue);\n return;\n }\n if (type === \"response.output_item.added\") {\n const item = asRecord(parsed.item);\n if (textValue(item.type) === \"function_call\") {\n ensureToolBlock(state, parsed, item, enqueue);\n }\n return;\n }\n if (type === \"response.output_text.delta\") {\n const blockState = ensureTextBlock(state, parsed, enqueue);\n const delta = textValue(parsed.delta);\n if (delta) {\n blockState.sentText += delta;\n enqueue(\"content_block_delta\", {\n delta: { text: delta, type: \"text_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n return;\n }\n if (type === \"response.output_text.done\" || type === \"response.content_part.done\") {\n const blockState = ensureTextBlock(state, parsed, enqueue);\n const text = textValue(parsed.text) || textValue(asRecord(parsed.part).text);\n if (text && !blockState.sentText) {\n blockState.sentText = text;\n enqueue(\"content_block_delta\", {\n delta: { text, type: \"text_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n stopBlock(blockState, enqueue);\n return;\n }\n if (type === \"response.function_call_arguments.delta\") {\n const blockState = ensureToolBlock(state, parsed, {}, enqueue);\n const delta = textValue(parsed.delta);\n if (delta) {\n blockState.sentText += delta;\n enqueue(\"content_block_delta\", {\n delta: { partial_json: delta, type: \"input_json_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n return;\n }\n if (type === \"response.function_call_arguments.done\") {\n const blockState = ensureToolBlock(state, parsed, {}, enqueue);\n const args = textValue(parsed.arguments);\n if (args && !blockState.sentText) {\n blockState.sentText = args;\n enqueue(\"content_block_delta\", {\n delta: { partial_json: args, type: \"input_json_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n stopBlock(blockState, enqueue);\n return;\n }\n if (type === \"response.output_item.done\") {\n const item = asRecord(parsed.item);\n if (textValue(item.type) === \"function_call\") {\n const blockState = ensureToolBlock(state, parsed, item, enqueue);\n const args = textValue(item.arguments);\n if (args && !blockState.sentText) {\n blockState.sentText = args;\n enqueue(\"content_block_delta\", {\n delta: { partial_json: args, type: \"input_json_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n stopBlock(blockState, enqueue);\n }\n return;\n }\n if (type === \"response.completed\") {\n const response = asRecord(parsed.response);\n state.model = textValue(response.model) || state.model;\n state.usage = anthropicUsage(response.usage);\n finishAnthropicStream(state, enqueue);\n return;\n }\n if (type === \"response.failed\" || event === \"error\") {\n const error = asRecord(asRecord(parsed.response).error);\n enqueue(\"error\", {\n error: {\n message: textValue(error.message) || textValue(parsed.message) || \"Upstream stream failed.\",\n type: textValue(error.type) || \"api_error\",\n },\n type: \"error\",\n });\n state.completed = true;\n }\n}\n\nfunction startAnthropicMessage(\n state: AnthropicStreamState,\n enqueue: (event: string, data: JsonObject) => void,\n): void {\n if (state.started) {\n return;\n }\n state.started = true;\n enqueue(\"message_start\", {\n message: {\n content: [],\n id: state.messageId,\n model: state.model,\n role: \"assistant\",\n stop_reason: null,\n stop_sequence: null,\n type: \"message\",\n usage: anthropicUsage(undefined),\n },\n type: \"message_start\",\n });\n}\n\nfunction finishAnthropicStream(\n state: AnthropicStreamState,\n enqueue: (event: string, data: JsonObject) => void,\n): void {\n if (state.completed) {\n return;\n }\n startAnthropicMessage(state, enqueue);\n for (const block of [...state.blocks.values()].sort((left, right) => left.index - right.index)) {\n stopBlock(block, enqueue);\n }\n enqueue(\"message_delta\", {\n delta: {\n stop_reason: state.sawToolUse ? \"tool_use\" : \"end_turn\",\n stop_sequence: null,\n },\n type: \"message_delta\",\n usage: state.usage,\n });\n enqueue(\"message_stop\", { type: \"message_stop\" });\n state.completed = true;\n}\n\nfunction ensureTextBlock(\n state: AnthropicStreamState,\n payload: JsonObject,\n enqueue: (event: string, data: JsonObject) => void,\n): StreamBlock {\n startAnthropicMessage(state, enqueue);\n const key = `text:${indexValue(payload.output_index)}:${indexValue(payload.content_index)}`;\n let block = state.blocks.get(key);\n if (!block) {\n block = { index: state.nextBlockIndex++, sentText: \"\", stopped: false, type: \"text\" };\n state.blocks.set(key, block);\n enqueue(\"content_block_start\", {\n content_block: { text: \"\", type: \"text\" },\n index: block.index,\n type: \"content_block_start\",\n });\n }\n return block;\n}\n\nfunction ensureToolBlock(\n state: AnthropicStreamState,\n payload: JsonObject,\n item: JsonObject,\n enqueue: (event: string, data: JsonObject) => void,\n): StreamBlock {\n startAnthropicMessage(state, enqueue);\n state.sawToolUse = true;\n const key = `tool:${indexValue(payload.output_index)}`;\n let block = state.blocks.get(key);\n if (!block) {\n block = { index: state.nextBlockIndex++, sentText: \"\", stopped: false, type: \"tool_use\" };\n state.blocks.set(key, block);\n enqueue(\"content_block_start\", {\n content_block: {\n id: textValue(item.call_id) || textValue(item.id) || `call_${randomId()}`,\n input: {},\n name: textValue(item.name),\n type: \"tool_use\",\n },\n index: block.index,\n type: \"content_block_start\",\n });\n }\n return block;\n}\n\nfunction stopBlock(block: StreamBlock, enqueue: (event: string, data: JsonObject) => void): void {\n if (block.stopped) {\n return;\n }\n block.stopped = true;\n enqueue(\"content_block_stop\", {\n index: block.index,\n type: \"content_block_stop\",\n });\n}\n\nfunction parseSseBlock(block: string): { data: string; event: string } {\n let event = \"message\";\n const data: string[] = [];\n for (const line of block.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"event:\")) {\n event = trimmed.slice(\"event:\".length).trim() || event;\n } else if (trimmed.startsWith(\"data:\")) {\n data.push(trimmed.slice(\"data:\".length).trim());\n }\n }\n return { data: data.join(\"\\n\"), event };\n}\n\nfunction parseToolInput(argumentsText: string): JsonObject {\n const parsed = parseJsonObject(argumentsText);\n return parsed ?? {};\n}\n\nfunction estimatedTextSize(value: unknown): number {\n if (value === undefined || value === null) {\n return 0;\n }\n if (typeof value === \"string\") {\n return value.length;\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value).length;\n }\n if (Array.isArray(value)) {\n return value.reduce((sum, item) => sum + estimatedTextSize(item), 0);\n }\n if (typeof value === \"object\") {\n return Object.values(value).reduce((sum, item) => sum + estimatedTextSize(item), 0);\n }\n return 0;\n}\n\nfunction textValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return \"\";\n}\n\nfunction indexValue(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction encodeSse(event: string, data: JsonObject): string {\n return `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n}\n","// The hoopilot live dashboard: a single self-contained HTML document served at\n// GET /dashboard. It is intentionally dependency-free — all CSS and JS are inline\n// and there are no external fonts, images, or scripts — so it works fully offline,\n// inside a compiled standalone binary, and behind restrictive proxies. The page\n// polls GET /v1/usage on an interval and renders proxy status + Copilot quota,\n// computing per-second rates client-side from successive snapshots.\n//\n// Authored as a plain string (not a loader-imported asset) so it bundles with zero\n// configuration across `bun run`, tsup/esbuild, and `bun build --compile`. The\n// embedded source therefore avoids backticks and template substitutions.\nexport const DASHBOARD_HTML = `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<meta name=\"color-scheme\" content=\"dark light\" />\n<title>hoopilot · dashboard</title>\n<style>\n:root {\n --bg-0:#0b0e14; --bg-1:#11151c; --bg-2:#171c25; --bg-3:#1f2630;\n --border:#262d38; --border-strong:#37404d;\n --text-0:#e6edf3; --text-1:#9aa7b4; --text-2:#5e6b78; --text-dim:#3a434e; --text-inv:#0b0e14;\n --accent:#4ea1ff; --accent-2:#56d4dd; --accent-soft:rgba(78,161,255,.14);\n --amber:#f5b042;\n --ok:#3fb950; --warn:#d8a13a; --danger:#f0556a; --info:#a371f7; --cache:#7c8cff;\n --spark:#4ea1ff; --spark-fill:color-mix(in srgb, var(--accent) 14%, transparent);\n --grid-line:rgba(255,255,255,.05);\n --flash:color-mix(in srgb, var(--accent) 22%, transparent);\n --flash-up:color-mix(in srgb, var(--ok) 22%, transparent);\n --flash-down:color-mix(in srgb, var(--danger) 22%, transparent);\n --c1:#4ea1ff; --c2:#3fb950; --c3:#d8a13a; --c4:#a371f7; --c5:#56d4dd; --c6:#f0556a;\n --mono: ui-monospace, \"SF Mono\", \"Cascadia Code\", \"JetBrains Mono\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace;\n --sans: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, system-ui, sans-serif;\n}\n@media (prefers-color-scheme: light) {\n :root:not([data-theme=\"dark\"]) {\n --bg-0:#f6f8fa; --bg-1:#ffffff; --bg-2:#f0f3f6; --bg-3:#e9edf1;\n --border:#d0d7de; --border-strong:#b6bec8;\n --text-0:#1f2328; --text-1:#5a6570; --text-2:#8a96a3; --text-dim:#bcc2c9; --text-inv:#ffffff;\n --accent:#0969da; --accent-2:#0a7ea4; --accent-soft:rgba(9,105,218,.12);\n --amber:#b5730a;\n --ok:#1a7f37; --warn:#9a6700; --danger:#cf222e; --info:#8250df; --cache:#5563e0;\n --spark:#0969da; --spark-fill:color-mix(in srgb, var(--accent) 12%, transparent);\n --grid-line:rgba(0,0,0,.06);\n --flash:color-mix(in srgb, var(--accent) 16%, transparent);\n --flash-up:color-mix(in srgb, var(--ok) 16%, transparent);\n --flash-down:color-mix(in srgb, var(--danger) 16%, transparent);\n --c1:#0969da; --c2:#1a7f37; --c3:#9a6700; --c4:#8250df; --c5:#0a7ea4; --c6:#cf222e;\n }\n}\n[data-theme=\"light\"] {\n --bg-0:#f6f8fa; --bg-1:#ffffff; --bg-2:#f0f3f6; --bg-3:#e9edf1;\n --border:#d0d7de; --border-strong:#b6bec8;\n --text-0:#1f2328; --text-1:#5a6570; --text-2:#8a96a3; --text-dim:#bcc2c9; --text-inv:#ffffff;\n --accent:#0969da; --accent-2:#0a7ea4; --accent-soft:rgba(9,105,218,.12);\n --amber:#b5730a;\n --ok:#1a7f37; --warn:#9a6700; --danger:#cf222e; --info:#8250df; --cache:#5563e0;\n --spark:#0969da; --spark-fill:color-mix(in srgb, var(--accent) 12%, transparent);\n --grid-line:rgba(0,0,0,.06);\n --flash:color-mix(in srgb, var(--accent) 16%, transparent);\n --flash-up:color-mix(in srgb, var(--ok) 16%, transparent);\n --flash-down:color-mix(in srgb, var(--danger) 16%, transparent);\n --c1:#0969da; --c2:#1a7f37; --c3:#9a6700; --c4:#8250df; --c5:#0a7ea4; --c6:#cf222e;\n}\n* { box-sizing: border-box; }\nhtml, body { margin:0; padding:0; }\nbody {\n background: var(--bg-0); color: var(--text-0); font-family: var(--sans);\n font-size: 13px; line-height: 1.4; -webkit-font-smoothing: antialiased;\n}\n.mono { font-family: var(--mono); font-variant-numeric: tabular-nums slashed-zero; }\n.num { font-family: var(--mono); font-variant-numeric: tabular-nums slashed-zero; }\n.shell { max-width: 1280px; margin: 0 auto; padding: 0 24px 28px; }\n@media (min-width: 1080px) { .shell { border-left:1px solid var(--border); border-right:1px solid var(--border); } }\n@media (max-width: 680px) { .shell { padding: 0 12px 24px; } }\n\n/* header */\nheader.bar {\n position: sticky; top: 0; z-index: 20; background: var(--bg-1);\n border-bottom: 1px solid var(--border); height: 48px;\n}\n.bar-in { max-width:1280px; margin:0 auto; height:48px; padding:0 24px; display:flex; align-items:center; gap:12px; }\n@media (max-width:680px){ .bar-in{ padding:0 12px; gap:8px; } }\n.wordmark { font-family: var(--mono); font-weight:700; font-size:14px; color:var(--text-0); letter-spacing:-.01em; }\n.caret { display:inline-block; width:7px; height:15px; background:var(--amber); margin-left:3px; vertical-align:-2px; animation: blink 1.1s steps(1) infinite; }\n.chip { font-family: var(--mono); font-size:11px; padding:2px 7px; border-radius:10px; background:var(--bg-3); color:var(--text-1); white-space:nowrap; }\n.chip.plan-pro { background:var(--accent-soft); color:var(--accent); }\n.chip.plan-business { background:color-mix(in srgb, var(--info) 16%, transparent); color:var(--info); }\n.chip.plan-free, .chip.plan-offline { background:var(--bg-3); color:var(--text-2); }\n.spacer { flex:1; }\n.pill { display:inline-flex; align-items:center; gap:6px; font-size:11px; font-family:var(--mono); padding:3px 9px; border-radius:11px; background:var(--bg-3); color:var(--text-1); }\n.dot { width:7px; height:7px; border-radius:50%; background:var(--text-2); flex:none; }\n.pill.live .dot { background:var(--ok); }\n.pill.paused .dot { background:var(--text-2); }\n.pill.reconnect { color:var(--warn); } .pill.reconnect .dot { background:var(--warn); }\n.pill.authkey { color:var(--warn); } .pill.authkey .dot { background:var(--warn); }\n.heartbeat { animation: hb .5s ease-out; }\n.updated { font-family:var(--mono); font-size:11px; color:var(--text-2); white-space:nowrap; }\n.updated.warn { color:var(--warn); } .updated.danger { color:var(--danger); }\n.seg { display:inline-flex; border:1px solid var(--border); border-radius:6px; overflow:hidden; }\n.seg button { background:transparent; color:var(--text-1); border:0; font-family:var(--mono); font-size:11px; padding:3px 8px; cursor:pointer; }\n.seg button + button { border-left:1px solid var(--border); }\n.seg button.active { background:var(--accent); color:var(--text-inv); }\n.iconbtn { background:transparent; border:1px solid var(--border); border-radius:6px; color:var(--text-1); cursor:pointer; font-size:13px; line-height:1; padding:4px 7px; min-width:30px; }\n.iconbtn:hover { background:var(--bg-3); }\nbutton:focus-visible, input:focus-visible, .seg button:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }\n#scanbar { position:absolute; left:0; bottom:-1px; height:1px; width:100%; overflow:hidden; }\n#scanbar::after { content:\"\"; position:absolute; left:0; top:0; height:1px; width:40%;\n background:linear-gradient(90deg, transparent, var(--accent), transparent);\n animation: scan var(--scan-ms, 4000ms) linear infinite; }\nheader.bar.paused #scanbar::after, header.bar.frozen #scanbar::after { animation-play-state:paused; opacity:.35; }\n\n/* disconnect banner */\n#banner { display:none; margin-top:10px; padding:7px 12px; border-radius:5px; font-family:var(--mono); font-size:12px;\n background:color-mix(in srgb, var(--danger) 16%, transparent); color:var(--danger); border:1px solid color-mix(in srgb, var(--danger) 40%, transparent); }\n#banner.ok { background:color-mix(in srgb, var(--ok) 16%, transparent); color:var(--ok); border-color:color-mix(in srgb, var(--ok) 40%, transparent); }\n#banner.show { display:block; }\n\n/* hero strip */\n.hero { display:grid; grid-template-columns:repeat(4,1fr); margin:18px 0 16px; }\n.vital { padding:6px 18px; }\n.vital + .vital { border-left:1px solid var(--border); }\n.vital .eyebrow { font-size:10px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--text-1); }\n.vital .vnum { font-family:var(--mono); font-variant-numeric:tabular-nums slashed-zero; font-weight:600; font-size:clamp(2rem,5vw,3.25rem); line-height:1.02; letter-spacing:-.02em; color:var(--text-0); }\n.vital .vsub { font-size:11px; color:var(--text-2); min-height:14px; }\n.vital .vspark { display:block; width:100%; height:24px; margin-top:4px; }\n.vital.active { }\n.vital.active .eyebrow { color:var(--accent); }\n@media (max-width:1079px){ .hero{ grid-template-columns:repeat(2,1fr); } .vital:nth-child(3){ border-left:0; } .vital:nth-child(n+3){ border-top:1px solid var(--border); padding-top:12px; } }\n@media (max-width:600px){ .hero{ grid-template-columns:1fr; } .vital + .vital{ border-left:0; border-top:1px solid var(--border); } }\n\n/* grid + panels */\n.grid { display:grid; grid-template-columns:repeat(12,1fr); gap:12px; }\n.panel { position:relative; background:var(--bg-1); border:1px solid var(--border); border-radius:4px; padding:16px 12px 12px; min-width:0; }\n.panel > .ptitle { position:absolute; top:-8px; left:10px; padding:0 6px; background:var(--bg-1);\n font-family:var(--mono); font-size:11px; font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:var(--text-1); }\n.span5{ grid-column:span 5; } .span3{ grid-column:span 3; } .span4{ grid-column:span 4; }\n.span7{ grid-column:span 7; } .span8{ grid-column:span 8; }\n@media (max-width:1079px){ .grid{ grid-template-columns:repeat(6,1fr); }\n .span5,.span7,.span8{ grid-column:span 6; } .span3{ grid-column:span 3; } .span4{ grid-column:span 6; } }\n@media (max-width:680px){ .grid{ grid-template-columns:1fr; }\n .span3,.span4,.span5,.span7,.span8{ grid-column:span 1; } }\n\n.headline { font-family:var(--mono); font-variant-numeric:tabular-nums slashed-zero; font-weight:600; font-size:22px; line-height:1.1; }\n.cap { font-size:11px; color:var(--text-2); }\n.stack-bar { display:flex; height:8px; border-radius:4px; overflow:hidden; background:var(--bg-3); margin:8px 0; }\n.stack-bar i { display:block; height:100%; }\n.stack-bar.empty { outline:1px dashed var(--border); background:transparent; }\n\ntable.tbl { width:100%; border-collapse:collapse; font-family:var(--mono); font-variant-numeric:tabular-nums slashed-zero; font-size:12px; }\n.scrollx { overflow-x:auto; }\ntable.tbl th { font-size:10px; font-weight:600; text-transform:uppercase; color:var(--text-2); text-align:right; padding:4px 6px; border-bottom:1px solid var(--border); white-space:nowrap; }\ntable.tbl th.l { text-align:left; }\ntable.tbl td { padding:3px 6px; text-align:right; white-space:nowrap; border-bottom:1px solid color-mix(in srgb, var(--border) 55%, transparent); }\ntable.tbl td.l { text-align:left; max-width:160px; overflow:hidden; text-overflow:ellipsis; }\ntable.tbl tr:hover td { background:var(--bg-2); }\ntable.tbl tr.total td { border-top:1px solid var(--border-strong); border-bottom:0; font-weight:600; color:var(--text-0); }\n.minibar { display:inline-block; height:6px; border-radius:3px; background:var(--accent); vertical-align:middle; min-width:1px; }\n.ghost td { color:var(--text-2); text-align:center; }\n.reasoning { color:var(--info); } .cached { color:var(--cache); }\n\n.legend { display:flex; flex-wrap:wrap; gap:4px 14px; margin-top:8px; }\n.legend .li { display:flex; align-items:center; gap:6px; font-family:var(--mono); font-size:11px; color:var(--text-1); }\n.legend .sw { width:8px; height:8px; border-radius:2px; flex:none; }\n\n.lat-trio { display:flex; gap:18px; align-items:baseline; }\n.lat-trio .b { font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:20px; font-weight:600; }\n.lat-trio .b small { display:block; font-size:10px; font-weight:600; text-transform:uppercase; color:var(--text-2); letter-spacing:.05em; }\n.lat-p95 { color:var(--info); }\n.lat-track { position:relative; height:22px; margin-top:10px; }\n.lat-track .line { position:absolute; top:11px; left:0; right:0; height:1px; background:var(--border); }\n.lat-track .tick { position:absolute; top:5px; width:2px; height:12px; border-radius:1px; }\n.lat-track .tick.p50 { background:var(--accent); } .lat-track .tick.p95 { background:var(--info); }\n.lat-track .tlab { position:absolute; top:-2px; font-family:var(--mono); font-size:9px; color:var(--text-2); transform:translateX(-50%); }\ndetails.routes { margin-top:10px; } details.routes summary { cursor:pointer; font-size:11px; color:var(--text-2); font-family:var(--mono); }\n\n.qrow { margin:10px 0; } .qrow .qhead { display:flex; justify-content:space-between; align-items:baseline; font-size:12px; }\n.qrow .qname { color:var(--text-1); } .qrow .qval { font-family:var(--mono); font-variant-numeric:tabular-nums; color:var(--text-0); }\n.qbar { position:relative; height:8px; border-radius:4px; background:var(--bg-3); margin-top:5px; overflow:hidden; }\n.qbar i { position:absolute; left:0; top:0; height:100%; border-radius:4px; }\n.qbar.over i.ext { background:repeating-linear-gradient(45deg, var(--danger), var(--danger) 3px, transparent 3px, transparent 6px); }\n.inf { font-family:var(--mono); font-size:12px; color:var(--ok); }\n.emptybox { border:1px solid var(--border); border-radius:5px; padding:14px; text-align:center; color:var(--text-2); }\n.emptybox .keyglyph { font-size:20px; color:var(--text-1); }\n.emptybox h4 { margin:8px 0 4px; font-family:var(--sans); font-size:13px; color:var(--text-1); font-weight:600; }\n.emptybox .errline { font-family:var(--mono); font-size:11px; color:var(--text-2); word-break:break-word; margin:4px 0; }\n.prompt { font-family:var(--mono); font-size:12px; color:var(--text-1); }\n\n.upblocks { display:flex; gap:18px; }\n.upblk { } .upblk .v { font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:20px; font-weight:600; }\n.upblk .k { font-size:10px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-2); }\n.upblk.err.hot { color:var(--danger); }\n.rate { font-family:var(--mono); font-size:12px; } .rate.warn{ color:var(--warn);} .rate.danger{ color:var(--danger);} .rate.ok{ color:var(--ok); }\n#up-spark, #thru-svg { display:block; width:100%; }\n#up-spark { height:30px; margin-top:8px; }\n#thru-svg { height:88px; margin-top:6px; }\n.flag { font-family:var(--mono); font-size:10px; color:var(--text-2); }\n\nfooter.foot { margin-top:14px; padding-top:10px; border-top:1px solid var(--border); display:flex; flex-wrap:wrap; gap:4px 14px;\n font-family:var(--mono); font-size:11px; color:var(--text-2); }\nfooter.foot .end { margin-left:auto; }\n@media (max-width:680px){ footer.foot .end{ margin-left:0; } }\n\n.skel { color:var(--text-dim); }\n.flash { animation: flash .6s ease-out; } .flash-up { animation: flashup .6s ease-out; } .flash-down { animation: flashdown .6s ease-out; }\n\n/* auth takeover */\n#auth { display:none; }\n#auth.show { display:flex; justify-content:center; padding:64px 16px; }\n.authcard { width:100%; max-width:420px; background:var(--bg-1); border:1px solid var(--border); border-radius:6px; padding:22px 18px; position:relative; }\n.authcard h3 { margin:0 0 10px; font-family:var(--mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase; color:var(--text-1); }\n.authcard p { font-size:12px; color:var(--text-2); margin:0 0 14px; }\n.authcard .row { display:flex; gap:8px; }\n.authcard input { flex:1; background:var(--bg-0); border:1px solid var(--border); border-radius:5px; color:var(--text-0); font-family:var(--mono); font-size:13px; padding:8px 10px; }\n.authcard input.bad { border-color:var(--danger); }\n.authcard button { background:var(--accent); color:var(--text-inv); border:0; border-radius:5px; font-family:var(--mono); font-size:12px; padding:0 14px; cursor:pointer; }\n.authcard .err { color:var(--danger); font-family:var(--mono); font-size:11px; min-height:14px; margin-top:8px; }\n.authcard .clear { position:absolute; top:14px; right:16px; font-size:11px; color:var(--text-2); cursor:pointer; }\n.dim { opacity:.45; filter:grayscale(.4); transition:opacity .2s, filter .2s; }\n\n@keyframes blink { 50% { opacity:0; } }\n@keyframes scan { 0%{ transform:translateX(-100%);} 100%{ transform:translateX(350%);} }\n@keyframes hb { 0%{ transform:scale(1);} 35%{ transform:scale(1.7);} 100%{ transform:scale(1);} }\n@keyframes flash { from{ background:var(--flash);} to{ background:transparent;} }\n@keyframes flashup { from{ background:var(--flash-up);} to{ background:transparent;} }\n@keyframes flashdown { from{ background:var(--flash-down);} to{ background:transparent;} }\n@media (prefers-reduced-motion: reduce) {\n .caret { animation:none; } #scanbar::after { animation:none; opacity:.3; }\n .heartbeat { animation:none; }\n .flash, .flash-up, .flash-down { animation:none; box-shadow: inset 2px 0 0 var(--accent); }\n}\n</style>\n</head>\n<body>\n<header class=\"bar\" id=\"bar\">\n <div class=\"bar-in\">\n <span class=\"wordmark\">hoopilot<span class=\"caret\" aria-hidden=\"true\"></span></span>\n <span class=\"chip\" id=\"version-chip\">v···</span>\n <span class=\"chip plan-offline\" id=\"plan-chip\">— offline</span>\n <span class=\"spacer\"></span>\n <span class=\"pill\" id=\"conn-pill\" aria-live=\"polite\"><span class=\"dot\" id=\"conn-dot\"></span><span id=\"conn-text\">connecting</span></span>\n <span class=\"updated\" id=\"updated\"></span>\n <span class=\"seg\" id=\"seg\" role=\"group\" aria-label=\"Refresh interval\">\n <button data-ms=\"2000\">2s</button><button data-ms=\"4000\" class=\"active\">4s</button><button data-ms=\"10000\">10s</button>\n </span>\n <button class=\"iconbtn\" id=\"btn-pause\" title=\"Pause / resume\" aria-label=\"Pause or resume\">❚❚</button>\n <button class=\"iconbtn\" id=\"btn-theme\" title=\"Theme: auto / dark / light\" aria-label=\"Cycle theme\">A</button>\n </div>\n <div id=\"scanbar\" aria-hidden=\"true\"></div>\n</header>\n\n<div class=\"shell\">\n <div id=\"banner\" role=\"status\" aria-live=\"polite\"></div>\n\n <section id=\"content\">\n <section class=\"hero\" aria-label=\"Vitals\">\n <div class=\"vital\" id=\"v-req\"><div class=\"eyebrow\">Req / s</div><div class=\"vnum skel\" id=\"req-num\">···</div><div class=\"vsub\" id=\"req-sub\"></div><svg class=\"vspark\" id=\"req-spark\" viewBox=\"0 0 200 24\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--ok)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/><circle r=\"1.6\" fill=\"var(--ok)\" style=\"display:none\"/></svg></div>\n <div class=\"vital\" id=\"v-tok\"><div class=\"eyebrow\">Tokens / s</div><div class=\"vnum skel\" id=\"tok-num\">···</div><div class=\"vsub\" id=\"tok-sub\"></div><svg class=\"vspark\" id=\"tok-spark\" viewBox=\"0 0 200 24\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--accent)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/><circle r=\"1.6\" fill=\"var(--accent)\" style=\"display:none\"/></svg></div>\n <div class=\"vital\" id=\"v-inflight\"><div class=\"eyebrow\">In‑flight</div><div class=\"vnum skel\" id=\"inflight-num\">···</div><div class=\"vsub\" id=\"inflight-sub\"></div><svg class=\"vspark\" id=\"inflight-spark\" viewBox=\"0 0 200 24\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--accent-2)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/><circle r=\"1.6\" fill=\"var(--accent-2)\" style=\"display:none\"/></svg></div>\n <div class=\"vital\" id=\"v-uptime\"><div class=\"eyebrow\">Uptime</div><div class=\"vnum skel\" id=\"uptime-num\">···</div><div class=\"vsub\" id=\"uptime-sub\"></div></div>\n </section>\n\n <section class=\"grid\">\n <div class=\"panel span5\"><span class=\"ptitle\">┤ Proxy · requests ┠</span>\n <div class=\"headline\"><span id=\"req-total\" class=\"skel\">···</span> <span class=\"cap\">requests</span></div>\n <div class=\"stack-bar empty\" id=\"route-sharebar\"></div>\n <div class=\"stack-bar empty\" id=\"status-healthbar\"></div>\n <div class=\"scrollx\"><table class=\"tbl\"><thead><tr><th class=\"l\">Route</th><th>Count</th><th>%</th><th style=\"width:60px\"> </th></tr></thead><tbody id=\"routes-body\"><tr class=\"ghost\"><td colspan=\"4\">loading…</td></tr></tbody></table></div>\n </div>\n\n <div class=\"panel span3\"><span class=\"ptitle\">┤ Status ┠</span>\n <div class=\"headline\"><span id=\"error-rate\" class=\"skel\">···</span> <span class=\"cap\">err rate</span></div>\n <div class=\"stack-bar empty\" id=\"status-bar\"></div>\n <div class=\"legend\" id=\"status-legend\"></div>\n </div>\n\n <div class=\"panel span4\"><span class=\"ptitle\">┤ Latency · ms ┠</span>\n <div class=\"lat-trio\">\n <div class=\"b\"><small>p50</small><span id=\"lat-p50\" class=\"skel\">·</span></div>\n <div class=\"b lat-p95\"><small>p95</small><span id=\"lat-p95\" class=\"skel\">·</span></div>\n <div class=\"b\"><small>avg</small><span id=\"lat-avg\" class=\"skel\">·</span></div>\n <div class=\"b\"><small>obs</small><span id=\"lat-count\" class=\"skel\">·</span></div>\n </div>\n <div class=\"lat-track\" id=\"lat-track\"><div class=\"line\"></div></div>\n <details class=\"routes\"><summary>by route</summary><div class=\"scrollx\"><table class=\"tbl\"><thead><tr><th class=\"l\">Route</th><th>avg ms</th><th>count</th></tr></thead><tbody id=\"lat-routes\"></tbody></table></div></details>\n </div>\n\n <div class=\"panel span7\"><span class=\"ptitle\">┤ Tokens · by model ┠</span>\n <div class=\"headline\"><span id=\"tok-total\" class=\"skel\">···</span> <span class=\"cap\">tokens · <span id=\"tok-cache\">cache ·%</span></span></div>\n <div class=\"stack-bar empty\" id=\"tok-mixbar\"></div>\n <div class=\"legend\" id=\"tok-legend\"></div>\n <div class=\"scrollx\" style=\"margin-top:8px\"><table class=\"tbl\"><thead><tr><th class=\"l\">Model</th><th>prompt</th><th>compl</th><th>reason</th><th>cached</th><th>total</th><th>reqs</th></tr></thead><tbody id=\"tok-body\"><tr class=\"ghost\"><td colspan=\"7\">no token usage yet</td></tr></tbody></table></div>\n </div>\n\n <div class=\"panel span5\"><span class=\"ptitle\">┤ Copilot · quota ┠</span>\n <div id=\"copilot-body\"><div class=\"emptybox skel\">loading…</div></div>\n </div>\n\n <div class=\"panel span4\"><span class=\"ptitle\">┤ Upstream · copilot edge ┠</span>\n <div class=\"upblocks\">\n <div class=\"upblk\"><div class=\"v\" id=\"up-total\">·</div><div class=\"k\">calls</div></div>\n <div class=\"upblk err\" id=\"up-errblk\"><div class=\"v\" id=\"up-errors\">·</div><div class=\"k\">errors</div></div>\n <div class=\"upblk\"><div class=\"v rate\" id=\"up-rate\">·</div><div class=\"k\">err rate</div></div>\n </div>\n <svg id=\"up-spark\" viewBox=\"0 0 320 30\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--danger)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/></svg>\n <div class=\"flag\" id=\"up-flag\"></div>\n </div>\n\n <div class=\"panel span8\"><span class=\"ptitle\">┤ Throughput ┠</span>\n <div class=\"cap\"><span style=\"color:var(--accent)\">■</span> tokens/s <span id=\"thru-tok\" class=\"num\"></span> <span style=\"color:var(--accent-2)\">■</span> req/s <span id=\"thru-req\" class=\"num\"></span> <span class=\"end\" id=\"thru-peak\" style=\"float:right\"></span></div>\n <svg id=\"thru-svg\" viewBox=\"0 0 320 88\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\n <defs><linearGradient id=\"thrugrad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0%\" stop-color=\"var(--accent)\" stop-opacity=\"0.28\"/><stop offset=\"100%\" stop-color=\"var(--accent)\" stop-opacity=\"0\"/></linearGradient></defs>\n <line class=\"grid\" x1=\"0\" y1=\"22\" x2=\"320\" y2=\"22\" stroke=\"var(--grid-line)\"/>\n <line class=\"grid\" x1=\"0\" y1=\"44\" x2=\"320\" y2=\"44\" stroke=\"var(--grid-line)\"/>\n <line class=\"grid\" x1=\"0\" y1=\"66\" x2=\"320\" y2=\"66\" stroke=\"var(--grid-line)\"/>\n <path id=\"thru-tok-area\" fill=\"url(#thrugrad)\" stroke=\"none\"/>\n <path id=\"thru-tok-line\" fill=\"none\" stroke=\"var(--accent)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/>\n <path id=\"thru-req-line\" fill=\"none\" stroke=\"var(--accent-2)\" stroke-width=\"1.2\" vector-effect=\"non-scaling-stroke\" opacity=\"0.9\"/>\n </svg>\n </div>\n </section>\n </section>\n\n <section id=\"auth\" aria-live=\"polite\">\n <div class=\"authcard\">\n <span class=\"clear\" id=\"auth-clear\" style=\"display:none\">clear key</span>\n <h3>┤ Auth required ┠</h3>\n <p>This hoopilot proxy requires an API key. It is stored locally in your browser and sent as <span class=\"mono\">x-api-key</span>.</p>\n <div class=\"row\"><input id=\"auth-input\" type=\"password\" placeholder=\"x-api-key\" autocomplete=\"off\" spellcheck=\"false\" /><button id=\"auth-connect\">connect</button></div>\n <div class=\"err\" id=\"auth-err\"></div>\n </div>\n </section>\n\n <footer class=\"foot\">\n <span id=\"foot-started\">started ·</span>\n <span id=\"foot-uptime\">uptime ·</span>\n <span id=\"foot-total\">· req</span>\n <span id=\"foot-tokens\">· tokens</span>\n <span id=\"foot-upstream\">upstream ·</span>\n <span class=\"end\" id=\"foot-cadence\"></span>\n </footer>\n</div>\n\n<script>\n(function(){\n \"use strict\";\n var byId = function(id){ return document.getElementById(id); };\n var CAP = 60;\n\n // ---- persistent state ----\n var LS = window.localStorage;\n var apiKey = \"\";\n try { apiKey = LS.getItem(\"hoopilot.apiKey\") || \"\"; } catch (e) { apiKey = \"\"; }\n var theme = \"auto\";\n try { theme = LS.getItem(\"hoopilot.theme\") || \"auto\"; } catch (e) { theme = \"auto\"; }\n var intervalMs = 4000;\n try { var sv = parseInt(LS.getItem(\"hoopilot.intervalMs\") || \"\", 10); if (sv === 2000 || sv === 4000 || sv === 10000) intervalMs = sv; } catch (e) {}\n\n // ---- runtime state ----\n var paused = false;\n var timer = null;\n var inflightFetch = null;\n var lastSuccessAt = 0;\n var prevSample = null; // { t, reqTotal, tokTotal, upTotal, startedAt }\n var lastRender = {}; // for change-flash\n var backoffMs = 0;\n var lastUptime = null; // seconds; ticked locally between polls\n var hist = { req:[], tok:[], inflight:[], up:[] };\n\n // ---- formatting helpers ----\n function humanInt(n){\n if (n === null || n === undefined || !isFinite(n)) return \"0\";\n var a = Math.abs(n);\n if (a >= 1000000) return (n/1000000).toFixed(a >= 10000000 ? 0 : 1) + \"M\";\n if (a >= 1000) return (n/1000).toFixed(a >= 10000 ? 0 : 1) + \"k\";\n return String(Math.round(n));\n }\n function rate(n){\n if (n === null || n === undefined || !isFinite(n)) return \"0\";\n if (n >= 100) return String(Math.round(n));\n if (n >= 10) return n.toFixed(1);\n return n.toFixed(2);\n }\n function pct(n){ if (!isFinite(n)) return \"0%\"; return (n >= 10 ? Math.round(n) : Math.round(n*10)/10) + \"%\"; }\n function fmtMs(n){ if (n === null || n === undefined || !isFinite(n) || n <= 0) return \"0\"; if (n >= 1000) return (n/1000).toFixed(2) + \"s\"; if (n >= 100) return String(Math.round(n)); return Math.round(n*10)/10 + \"\"; }\n function pad2(n){ return (n < 10 ? \"0\" : \"\") + n; }\n function fmtUptime(sec){\n sec = Math.max(0, Math.floor(sec));\n var d = Math.floor(sec/86400); sec -= d*86400;\n var h = Math.floor(sec/3600); sec -= h*3600;\n var m = Math.floor(sec/60); var s = sec - m*60;\n if (d > 0) return d + \"d \" + pad2(h) + \":\" + pad2(m);\n if (h > 0) return h + \":\" + pad2(m) + \":\" + pad2(s);\n return m + \":\" + pad2(s);\n }\n function titleize(key){\n var map = { premium_interactions:\"Premium requests\", chat:\"Chat\", completions:\"Completions\", code_review:\"Code review\" };\n if (map[key]) return map[key];\n return key.split(\"_\").map(function(w){ return w ? w.charAt(0).toUpperCase() + w.slice(1) : w; }).join(\" \");\n }\n function relTime(iso){\n var t = Date.parse(iso); if (!isFinite(t)) return iso || \"\";\n var s = Math.max(0, Math.round((Date.now() - t)/1000));\n return fmtUptime(s) + \" ago\";\n }\n function clearEl(el){ while (el && el.firstChild) el.removeChild(el.firstChild); }\n function mk(tag, cls, txt){ var e = document.createElement(tag); if (cls) e.className = cls; if (txt !== undefined && txt !== null) e.textContent = txt; return e; }\n\n // Set numeric text and flash on discrete change.\n function setNum(id, value, kind, num){\n var el = byId(id); if (!el) return;\n el.classList.remove(\"skel\");\n var s = String(value);\n if (el.textContent !== s){\n el.textContent = s;\n // Compare on the raw number (num) when provided, so directional flash works\n // even when value is a pre-formatted display string.\n var n = (num !== undefined) ? num : value;\n var prev = lastRender[id];\n if (prev !== undefined){\n var cls = \"flash\";\n if (kind === \"delta\" && typeof n === \"number\" && typeof prev === \"number\"){\n cls = n > prev ? \"flash-up\" : (n < prev ? \"flash-down\" : null);\n }\n if (cls){ el.classList.remove(\"flash\",\"flash-up\",\"flash-down\"); void el.offsetWidth; el.classList.add(cls); }\n }\n lastRender[id] = n;\n }\n }\n function setText(id, s){ var el = byId(id); if (el){ el.classList.remove(\"skel\"); el.textContent = s; } }\n\n // ---- sparkline rendering ----\n function pushHist(arr, v){ arr.push(v); if (arr.length > CAP) arr.shift(); }\n function buildSpark(values, w, h){\n var pts = []; for (var i=0;i<values.length;i++){ if (isFinite(values[i])) pts.push({ i:i, v:values[i] }); }\n if (pts.length < 2) return null;\n var min = Infinity, max = -Infinity;\n for (var j=0;j<values.length;j++){ var v = values[j]; if (isFinite(v)){ if (v<min) min=v; if (v>max) max=v; } }\n var flat = (max - min) <= 0;\n var pad = flat ? 1 : (max - min) * 0.05; var lo = min - pad, hi = max + pad; var span = hi - lo; if (span <= 0) span = 1;\n var n = values.length;\n var line = \"\", lastX = 0, lastY = 0, started = false;\n for (var k=0;k<n;k++){\n var val = values[k]; if (!isFinite(val)) continue;\n var x = (n === 1) ? w : (k * (w/(n-1)));\n var norm = flat ? 0.5 : (val - lo)/span;\n var y = h - norm*(h-2) - 1;\n line += (started ? \" L\" : \"M\") + x.toFixed(2) + \",\" + y.toFixed(2);\n lastX = x; lastY = y; started = true;\n }\n var area = line + \" L\" + lastX.toFixed(2) + \",\" + h + \" L0,\" + h + \" Z\";\n return { line:line, area:area, lastX:lastX, lastY:lastY };\n }\n function drawSpark(svgId, values){\n var svg = byId(svgId); if (!svg) return;\n var vb = svg.viewBox.baseVal; var w = vb.width || 200, h = vb.height || 24;\n var sp = buildSpark(values, w, h);\n var line = svg.querySelector(\".line\"), area = svg.querySelector(\".area\"), dot = svg.querySelector(\"circle\");\n if (!sp){ if (line) line.setAttribute(\"d\",\"\"); if (area) area.setAttribute(\"d\",\"\"); if (dot) dot.style.display = \"none\"; return; }\n if (line) line.setAttribute(\"d\", sp.line);\n if (area) area.setAttribute(\"d\", sp.area);\n if (dot){ dot.setAttribute(\"cx\", sp.lastX.toFixed(2)); dot.setAttribute(\"cy\", sp.lastY.toFixed(2)); dot.style.display = \"\"; }\n }\n\n // ---- theme ----\n function applyTheme(){\n var root = document.documentElement;\n if (theme === \"dark\") root.setAttribute(\"data-theme\",\"dark\");\n else if (theme === \"light\") root.setAttribute(\"data-theme\",\"light\");\n else root.removeAttribute(\"data-theme\");\n byId(\"btn-theme\").textContent = theme === \"dark\" ? \"D\" : (theme === \"light\" ? \"L\" : \"A\");\n }\n byId(\"btn-theme\").addEventListener(\"click\", function(){\n theme = theme === \"auto\" ? \"dark\" : (theme === \"dark\" ? \"light\" : \"auto\");\n try { LS.setItem(\"hoopilot.theme\", theme); } catch (e) {}\n applyTheme();\n });\n\n // ---- interval + pause ----\n function setActiveSeg(){\n var btns = byId(\"seg\").querySelectorAll(\"button\");\n for (var i=0;i<btns.length;i++){ btns[i].classList.toggle(\"active\", parseInt(btns[i].getAttribute(\"data-ms\"),10) === intervalMs); }\n document.documentElement.style.setProperty(\"--scan-ms\", intervalMs + \"ms\");\n }\n byId(\"seg\").addEventListener(\"click\", function(ev){\n var b = ev.target.closest ? ev.target.closest(\"button\") : null; if (!b) return;\n intervalMs = parseInt(b.getAttribute(\"data-ms\"),10) || 4000;\n try { LS.setItem(\"hoopilot.intervalMs\", String(intervalMs)); } catch (e) {}\n setActiveSeg();\n if (!paused){ schedule(0); }\n });\n byId(\"btn-pause\").addEventListener(\"click\", function(){\n paused = !paused;\n byId(\"btn-pause\").innerHTML = paused ? \"▶\" : \"❚❚\";\n byId(\"bar\").classList.toggle(\"paused\", paused);\n if (paused){ if (timer){ clearTimeout(timer); timer = null; } setPill(\"paused\",\"PAUSED\",false); }\n else { setPill(\"live\",\"LIVE\",false); schedule(0); }\n });\n\n // ---- connection pill / banner ----\n function setPill(kind, text, beat){\n var pill = byId(\"conn-pill\"); var dot = byId(\"conn-dot\");\n pill.className = \"pill \" + kind;\n byId(\"conn-text\").textContent = text;\n if (beat && dot){ dot.classList.remove(\"heartbeat\"); void dot.offsetWidth; dot.classList.add(\"heartbeat\"); }\n }\n function showBanner(text, ok){\n var b = byId(\"banner\"); b.textContent = text; b.className = \"show\" + (ok ? \" ok\" : \"\");\n if (ok){ setTimeout(function(){ b.classList.remove(\"show\"); }, 2000); }\n }\n function hideBanner(){ byId(\"banner\").classList.remove(\"show\"); }\n function setDimmed(on){ byId(\"content\").classList.toggle(\"dim\", on); }\n\n // ---- auth takeover ----\n function showAuth(rejected){\n byId(\"content\").style.display = \"none\";\n byId(\"auth\").classList.add(\"show\");\n setPill(\"authkey\",\"API KEY\",false);\n byId(\"auth-err\").textContent = rejected ? \"key rejected\" : \"\";\n byId(\"auth-input\").classList.toggle(\"bad\", !!rejected);\n byId(\"auth-clear\").style.display = apiKey ? \"\" : \"none\";\n byId(\"auth-input\").focus();\n }\n function hideAuth(){ byId(\"auth\").classList.remove(\"show\"); byId(\"content\").style.display = \"\"; }\n byId(\"auth-connect\").addEventListener(\"click\", function(){\n var v = byId(\"auth-input\").value.trim(); if (!v) return;\n apiKey = v; try { LS.setItem(\"hoopilot.apiKey\", apiKey); } catch (e) {}\n hideAuth(); schedule(0);\n });\n byId(\"auth-input\").addEventListener(\"keydown\", function(ev){ if (ev.key === \"Enter\") byId(\"auth-connect\").click(); });\n byId(\"auth-clear\").addEventListener(\"click\", function(){\n apiKey = \"\"; try { LS.removeItem(\"hoopilot.apiKey\"); } catch (e) {}\n byId(\"auth-input\").value = \"\"; byId(\"auth-clear\").style.display = \"none\"; byId(\"auth-input\").focus();\n });\n\n // ---- the poll loop (setTimeout-chained, never setInterval) ----\n var pollGen = 0;\n function schedule(delay){\n if (timer){ clearTimeout(timer); }\n if (paused) return;\n timer = setTimeout(poll, delay === undefined ? intervalMs : delay);\n }\n function poll(){\n if (paused) return;\n // A new poll supersedes any in-flight one. Bump the generation so the old\n // request's settled handlers (including its abort rejection) become no-ops\n // and never flash a false \"disconnected\".\n pollGen += 1; var myGen = pollGen;\n if (inflightFetch){ try { inflightFetch.abort(); } catch (e) {} }\n var ctrl = new AbortController(); inflightFetch = ctrl;\n var to = setTimeout(function(){ try { ctrl.abort(); } catch (e) {} }, 3000);\n var headers = { \"accept\":\"application/json\" };\n if (apiKey) headers[\"x-api-key\"] = apiKey;\n fetch(\"/v1/usage\", { headers: headers, signal: ctrl.signal, cache:\"no-store\" }).then(function(res){\n clearTimeout(to);\n if (myGen !== pollGen) return null;\n if (res.status === 401 || res.status === 403){ inflightFetch = null; showAuth(!!apiKey); return null; }\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n return res.json();\n }).then(function(data){\n if (myGen !== pollGen || data === null || paused) return;\n inflightFetch = null;\n onData(data);\n backoffMs = 0; lastSuccessAt = Date.now();\n hideAuth(); setDimmed(false); hideBanner();\n setPill(\"live\",\"LIVE\",true);\n byId(\"bar\").classList.remove(\"frozen\");\n schedule(intervalMs);\n }).catch(function(err){\n clearTimeout(to);\n if (myGen !== pollGen || paused) return;\n inflightFetch = null;\n onDisconnect(err);\n });\n }\n function onDisconnect(err){\n setPill(\"reconnect\",\"RECONNECTING\",false);\n setDimmed(true);\n byId(\"bar\").classList.add(\"frozen\");\n backoffMs = backoffMs ? Math.min(Math.round(backoffMs * 1.5), 30000) : intervalMs;\n showBanner(\"Disconnected (\" + (err && err.message ? err.message : \"no response\") + \") \\\\u2014 retrying in \" + Math.round(backoffMs/1000) + \"s\", false);\n schedule(backoffMs);\n }\n\n // ---- main render ----\n function onData(usage){\n var proxy = usage.proxy || {};\n var now = Date.now();\n\n setText(\"version-chip\", \"v\" + (usage.version || \"?\"));\n\n // rates\n var reqTotal = (proxy.requests && proxy.requests.total) || 0;\n var tokTotal = (proxy.tokens && proxy.tokens.total) || 0;\n var upTotal = (proxy.upstream && proxy.upstream.total) || 0;\n var startedAt = proxy.startedAt || \"\";\n var reqPerSec = NaN, tokPerSec = NaN, upDelta = 0, restarted = false;\n if (prevSample){\n var dt = (now - prevSample.t)/1000;\n if (prevSample.startedAt && startedAt && prevSample.startedAt !== startedAt) restarted = true;\n if (reqTotal < prevSample.reqTotal || tokTotal < prevSample.tokTotal) restarted = true;\n if (restarted){ reqPerSec = 0; tokPerSec = 0; upDelta = 0; }\n else if (dt > 0 && isFinite(dt)){\n reqPerSec = Math.max(0, (reqTotal - prevSample.reqTotal)/dt);\n tokPerSec = Math.max(0, (tokTotal - prevSample.tokTotal)/dt);\n upDelta = Math.max(0, upTotal - prevSample.upTotal);\n }\n }\n prevSample = { t:now, reqTotal:reqTotal, tokTotal:tokTotal, upTotal:upTotal, startedAt:startedAt };\n\n // hero vitals\n if (isFinite(reqPerSec)){ pushHist(hist.req, reqPerSec); setNum(\"req-num\", rate(reqPerSec)); } else setText(\"req-num\",\"\\\\u2014\");\n if (isFinite(tokPerSec)){ pushHist(hist.tok, tokPerSec); setNum(\"tok-num\", humanInt(tokPerSec)); } else setText(\"tok-num\",\"\\\\u2014\");\n var inflight = proxy.inFlight || 0;\n pushHist(hist.inflight, inflight); setNum(\"inflight-num\", String(inflight), \"delta\", inflight);\n byId(\"v-inflight\").classList.toggle(\"active\", inflight > 0);\n setText(\"uptime-num\", fmtUptime(proxy.uptimeSeconds || 0));\n\n setText(\"req-sub\", hist.req.length ? (\"avg \" + rate(avg(hist.req)) + \"/s\") : \"warming up\");\n setText(\"tok-sub\", hist.tok.length ? (\"peak \" + humanInt(Math.max.apply(null, hist.tok)) + \"/s\") : \"warming up\");\n setText(\"inflight-sub\", inflight + \" now\");\n setText(\"uptime-sub\", startedAt ? (\"since \" + relTime(startedAt)) : \"\");\n\n drawSpark(\"req-spark\", hist.req);\n drawSpark(\"tok-spark\", hist.tok);\n drawSpark(\"inflight-spark\", hist.inflight);\n\n renderRequests(proxy);\n renderStatus(proxy);\n renderLatency(proxy.latency || {});\n renderTokens(proxy.tokens || {});\n renderCopilot(usage);\n renderUpstream(proxy.upstream || {}, upDelta, restarted);\n renderThroughput();\n renderFooter(usage, proxy);\n\n setNum(\"req-total\", humanInt(reqTotal));\n setNum(\"tok-total\", humanInt(tokTotal));\n lastUptime = proxy.uptimeSeconds || 0;\n }\n\n function avg(arr){ if (!arr.length) return 0; var s = 0; for (var i=0;i<arr.length;i++) s += arr[i]; return s/arr.length; }\n\n var ROUTE_COLORS = [\"var(--c1)\",\"var(--c2)\",\"var(--c3)\",\"var(--c4)\",\"var(--c5)\",\"var(--c6)\"];\n function renderRequests(proxy){\n var byRoute = (proxy.requests && proxy.requests.byRoute) || {};\n var total = (proxy.requests && proxy.requests.total) || 0;\n var rows = Object.keys(byRoute).map(function(k){ return { k:k, v:byRoute[k] }; }).sort(function(a,b){ return b.v - a.v; });\n var share = byId(\"route-sharebar\"); clearEl(share); share.className = \"stack-bar\" + (total ? \"\" : \" empty\");\n var body = byId(\"routes-body\"); clearEl(body);\n if (!rows.length){ var tr = mk(\"tr\",\"ghost\"); var td = mk(\"td\",null,\"no requests yet\"); td.colSpan = 4; tr.appendChild(td); body.appendChild(tr); return; }\n rows.forEach(function(r, idx){\n var p = total ? (r.v/total*100) : 0;\n var seg = mk(\"i\"); seg.style.width = p + \"%\"; seg.style.background = ROUTE_COLORS[idx % ROUTE_COLORS.length]; seg.title = r.k + \" \" + pct(p); share.appendChild(seg);\n var tr = mk(\"tr\");\n var name = mk(\"td\",\"l\", r.k); name.title = r.k; tr.appendChild(name);\n tr.appendChild(mk(\"td\",null, humanInt(r.v)));\n tr.appendChild(mk(\"td\",null, pct(p)));\n var btd = mk(\"td\"); var bar = mk(\"span\",\"minibar\"); bar.style.width = Math.max(2, p) + \"%\"; bar.style.background = ROUTE_COLORS[idx % ROUTE_COLORS.length]; btd.appendChild(bar); tr.appendChild(btd);\n body.appendChild(tr);\n });\n var tot = mk(\"tr\",\"total\"); tot.appendChild(mk(\"td\",\"l\",\"total\")); tot.appendChild(mk(\"td\",null, humanInt(total))); tot.appendChild(mk(\"td\",null,\"100%\")); tot.appendChild(mk(\"td\")); body.appendChild(tot);\n }\n\n function statusClass(code){ var c = String(code).charAt(0); if (c === \"2\") return \"ok\"; if (c === \"3\") return \"info\"; if (c === \"4\") return \"warn\"; if (c === \"5\") return \"danger\"; return \"muted\"; }\n function statusColor(cls){ return cls === \"ok\" ? \"var(--ok)\" : cls === \"info\" ? \"var(--info)\" : cls === \"warn\" ? \"var(--warn)\" : cls === \"danger\" ? \"var(--danger)\" : \"var(--text-2)\"; }\n function renderStatus(proxy){\n var byStatus = (proxy.requests && proxy.requests.byStatus) || {};\n var total = 0, errs = 0; var groups = { ok:0, info:0, warn:0, danger:0, muted:0 };\n var codes = Object.keys(byStatus).map(function(k){ return { k:k, v:byStatus[k] }; }).sort(function(a,b){ return b.v - a.v; });\n codes.forEach(function(c){ total += c.v; var cls = statusClass(c.k); groups[cls] += c.v; if (cls === \"warn\" || cls === \"danger\") errs += c.v; });\n var bar = byId(\"status-bar\"); clearEl(bar); bar.className = \"stack-bar\" + (total ? \"\" : \" empty\");\n [\"ok\",\"info\",\"warn\",\"danger\",\"muted\"].forEach(function(cls){ if (groups[cls] > 0){ var seg = mk(\"i\"); seg.style.width = (groups[cls]/total*100) + \"%\"; seg.style.background = statusColor(cls); bar.appendChild(seg); } });\n var leg = byId(\"status-legend\"); clearEl(leg);\n if (!codes.length){ leg.appendChild(mk(\"span\",\"li\",\"no requests yet\")); }\n codes.forEach(function(c){ var li = mk(\"span\",\"li\"); var sw = mk(\"span\",\"sw\"); sw.style.background = statusColor(statusClass(c.k)); li.appendChild(sw); li.appendChild(mk(\"span\",null, c.k + \" \" + humanInt(c.v))); leg.appendChild(li); });\n var er = total ? (errs/total*100) : 0;\n setNum(\"error-rate\", pct(er));\n var el = byId(\"error-rate\"); el.style.color = er > 5 ? \"var(--danger)\" : er > 1 ? \"var(--warn)\" : \"var(--ok)\";\n }\n\n function renderLatency(lat){\n setText(\"lat-p50\", fmtMs(lat.p50Ms)); setText(\"lat-avg\", fmtMs(lat.avgMs)); setText(\"lat-count\", humanInt(lat.count || 0));\n var p95 = byId(\"lat-p95\"); p95.classList.remove(\"skel\"); p95.textContent = fmtMs(lat.p95Ms);\n p95.style.color = (lat.p50Ms > 0 && lat.p95Ms > 2*lat.p50Ms) ? \"var(--warn)\" : \"var(--info)\";\n // track: position p50 and p95 across 0..(p95*1.15)\n var track = byId(\"lat-track\"); var old = track.querySelectorAll(\".tick,.tlab\"); for (var i=0;i<old.length;i++) old[i].remove();\n var maxv = Math.max(lat.p95Ms || 0, lat.avgMs || 0, 1) * 1.15;\n function place(v, cls){ if (!isFinite(v) || v <= 0) return; var x = Math.min(100, v/maxv*100); var t = mk(\"div\",\"tick \" + cls); t.style.left = x + \"%\"; track.appendChild(t); var lab = mk(\"div\",\"tlab\", fmtMs(v)); lab.style.left = x + \"%\"; track.appendChild(lab); }\n place(lat.p50Ms, \"p50\"); place(lat.p95Ms, \"p95\");\n var lr = byId(\"lat-routes\"); clearEl(lr);\n var byRoute = lat.byRoute || {}; var rows = Object.keys(byRoute).map(function(k){ return { k:k, v:byRoute[k] }; }).sort(function(a,b){ return (b.v.avgMs||0) - (a.v.avgMs||0); });\n rows.forEach(function(r){ var tr = mk(\"tr\"); var n = mk(\"td\",\"l\", r.k); n.title = r.k; tr.appendChild(n); tr.appendChild(mk(\"td\",null, fmtMs(r.v.avgMs))); tr.appendChild(mk(\"td\",null, humanInt(r.v.count||0))); lr.appendChild(tr); });\n }\n\n function renderTokens(tok){\n var prompt = tok.prompt||0, completion = tok.completion||0, reasoning = tok.reasoning||0, cached = tok.cached||0;\n var sum = prompt + completion + reasoning;\n var bar = byId(\"tok-mixbar\"); clearEl(bar); bar.className = \"stack-bar\" + (sum ? \"\" : \" empty\");\n var parts = [ [\"prompt\", prompt, \"var(--text-1)\"], [\"completion\", completion, \"var(--accent)\"], [\"reasoning\", reasoning, \"var(--info)\"] ];\n parts.forEach(function(p){ if (sum && p[1] > 0){ var seg = mk(\"i\"); seg.style.width = (p[1]/sum*100) + \"%\"; seg.style.background = p[2]; seg.title = p[0]; bar.appendChild(seg); } });\n var leg = byId(\"tok-legend\"); clearEl(leg);\n var legParts = parts.concat([[\"cached\", cached, \"var(--cache)\"]]);\n legParts.forEach(function(p){ var li = mk(\"span\",\"li\"); var sw = mk(\"span\",\"sw\"); sw.style.background = p[2]; li.appendChild(sw); var den = (p[0] === \"cached\") ? prompt : sum; var sh = den ? \" \" + pct(p[1]/den*100) : \"\"; li.appendChild(mk(\"span\",null, p[0] + \" \" + humanInt(p[1]) + sh)); leg.appendChild(li); });\n var cacheRate = prompt ? (cached/prompt*100) : 0; setText(\"tok-cache\", \"cache \" + pct(cacheRate));\n var body = byId(\"tok-body\"); clearEl(body);\n var byModel = tok.byModel || {}; var rows = Object.keys(byModel).map(function(k){ return { k:k, v:byModel[k] }; }).sort(function(a,b){ return (b.v.total||0) - (a.v.total||0); });\n if (!rows.length){ var tr = mk(\"tr\",\"ghost\"); var td = mk(\"td\",null,\"no token usage yet\"); td.colSpan = 7; tr.appendChild(td); body.appendChild(tr); return; }\n rows.forEach(function(r){ var m = r.v; var tr = mk(\"tr\"); var n = mk(\"td\",\"l\", r.k); n.title = r.k; tr.appendChild(n);\n tr.appendChild(mk(\"td\",null, humanInt(m.prompt||0))); tr.appendChild(mk(\"td\",null, humanInt(m.completion||0)));\n tr.appendChild(mk(\"td\",\"reasoning\", humanInt(m.reasoning||0))); tr.appendChild(mk(\"td\",\"cached\", humanInt(m.cached||0)));\n tr.appendChild(mk(\"td\",null, humanInt(m.total||0))); tr.appendChild(mk(\"td\",null, humanInt(m.requests||0))); body.appendChild(tr); });\n }\n\n function planClass(plan){ if (!plan) return \"plan-offline\"; if (plan.indexOf(\"pro\") >= 0) return \"plan-pro\"; if (plan.indexOf(\"business\") >= 0 || plan.indexOf(\"enterprise\") >= 0) return \"plan-business\"; return \"plan-free\"; }\n function renderCopilot(usage){\n var box = byId(\"copilot-body\"); clearEl(box);\n var cp = usage.copilot; var planChip = byId(\"plan-chip\");\n if (!cp){\n planChip.className = \"chip plan-offline\"; planChip.textContent = \"\\\\u2014 offline\";\n var eb = mk(\"div\",\"emptybox\"); eb.appendChild(mk(\"div\",\"keyglyph\",\"\\\\u26bf\"));\n eb.appendChild(mk(\"h4\",null,\"Copilot not connected\"));\n if (usage.copilot_error) eb.appendChild(mk(\"div\",\"errline\", usage.copilot_error));\n eb.appendChild(mk(\"div\",\"prompt\",\"$ hoopilot login\"));\n box.appendChild(eb); return;\n }\n planChip.className = \"chip \" + planClass(cp.plan); planChip.textContent = cp.plan || \"copilot\";\n var head = mk(\"div\",\"cap\");\n var bits = [];\n if (cp.accessTypeSku) bits.push(cp.accessTypeSku);\n if (cp.chatEnabled !== undefined) bits.push(cp.chatEnabled ? \"chat on\" : \"chat off\");\n if (cp.quotaResetDate) bits.push(\"resets \" + cp.quotaResetDate);\n head.textContent = bits.join(\" \\\\u00b7 \"); box.appendChild(head);\n var quotas = cp.quotas || {}; var keys = Object.keys(quotas);\n if (!keys.length){ box.appendChild(mk(\"div\",\"cap\",\"No metered quotas reported.\")); return; }\n var order = { premium_interactions:0, chat:1, completions:2 };\n keys.sort(function(a,b){ var ra = order[a]===undefined?9:order[a], rb = order[b]===undefined?9:order[b]; return ra-rb || a.localeCompare(b); });\n keys.forEach(function(k){\n var q = quotas[k]; var row = mk(\"div\",\"qrow\");\n var hd = mk(\"div\",\"qhead\"); hd.appendChild(mk(\"span\",\"qname\", titleize(k)));\n if (q.unlimited){ hd.appendChild(mk(\"span\",\"inf\",\"\\\\u221e unlimited\")); row.appendChild(hd); box.appendChild(row); return; }\n var ent = q.entitlement, rem = q.remaining, used = q.used;\n var usedPct = (q.percentRemaining !== undefined) ? (100 - q.percentRemaining) : ((ent && used !== undefined) ? (used/ent*100) : 0);\n usedPct = Math.max(0, Math.min(100, usedPct));\n var valTxt = (used !== undefined && ent !== undefined) ? (humanInt(used) + \" / \" + humanInt(ent)) : (rem !== undefined ? (humanInt(rem) + \" left\") : pct(100-usedPct) + \" left\");\n hd.appendChild(mk(\"span\",\"qval\", valTxt)); row.appendChild(hd);\n var bar = mk(\"div\",\"qbar\"); var fill = mk(\"i\"); fill.style.width = usedPct + \"%\";\n fill.style.background = usedPct > 85 ? \"var(--danger)\" : usedPct > 60 ? \"var(--warn)\" : \"var(--ok)\"; bar.appendChild(fill);\n if (q.overageCount && q.overagePermitted){ bar.classList.add(\"over\"); var ext = mk(\"i\",\"ext\"); ext.style.left = \"100%\"; ext.style.width = \"8%\"; bar.appendChild(ext); }\n row.appendChild(bar);\n if (q.overageCount){ var ov = mk(\"div\",\"flag\", humanInt(q.overageCount) + \" overage\" + (q.tokenBasedBilling ? \" \\\\u00b7 token billing\" : \"\")); row.appendChild(ov); }\n box.appendChild(row);\n });\n }\n\n function renderUpstream(up, delta, restarted){\n setNum(\"up-total\", humanInt(up.total||0));\n setNum(\"up-errors\", humanInt(up.errors||0), \"delta\", up.errors||0);\n var er = up.total ? (up.errors/up.total*100) : 0;\n var rt = byId(\"up-rate\"); rt.textContent = pct(er); rt.className = \"v rate \" + (er > 5 ? \"danger\" : er > 1 ? \"warn\" : \"ok\");\n byId(\"up-errblk\").classList.toggle(\"hot\", (up.errors||0) > 0);\n pushHist(hist.up, delta||0); drawSpark(\"up-spark\", hist.up);\n byId(\"up-flag\").textContent = restarted ? \"\\\\u21bb restarted\" : \"\";\n }\n\n function renderThroughput(){\n drawDual(\"thru-tok-line\",\"thru-tok-area\", hist.tok, true);\n drawDual(\"thru-req-line\", null, hist.req, false);\n setText(\"thru-tok\", hist.tok.length ? rate(hist.tok[hist.tok.length-1]) : \"\\\\u2014\");\n setText(\"thru-req\", hist.req.length ? rate(hist.req[hist.req.length-1]) : \"\\\\u2014\");\n var peakTok = hist.tok.length ? Math.max.apply(null, hist.tok) : 0;\n setText(\"thru-peak\", \"peak \" + humanInt(peakTok) + \" tok/s\");\n }\n function drawDual(lineId, areaId, values, withArea){\n var svg = byId(\"thru-svg\"); var vb = svg.viewBox.baseVal; var w = vb.width, h = vb.height;\n var sp = buildSpark(values, w, h);\n var line = byId(lineId); var area = areaId ? byId(areaId) : null;\n if (!sp){ if (line) line.setAttribute(\"d\",\"\"); if (area) area.setAttribute(\"d\",\"\"); return; }\n if (line) line.setAttribute(\"d\", sp.line);\n if (area && withArea) area.setAttribute(\"d\", sp.area);\n }\n\n function renderFooter(usage, proxy){\n setText(\"foot-started\", proxy.startedAt ? (\"started \" + new Date(proxy.startedAt).toLocaleString()) : \"started \\\\u2014\");\n setText(\"foot-uptime\", \"uptime \" + fmtUptime(proxy.uptimeSeconds||0));\n setText(\"foot-total\", humanInt((proxy.requests && proxy.requests.total)||0) + \" req\");\n setText(\"foot-tokens\", humanInt((proxy.tokens && proxy.tokens.total)||0) + \" tokens\");\n var up = proxy.upstream || {}; setText(\"foot-upstream\", \"upstream \" + humanInt(up.total||0) + \" / \" + humanInt(up.errors||0) + \" err\");\n setText(\"foot-cadence\", \"polling /v1/usage every \" + Math.round(intervalMs/1000) + \"s \\\\u00b7 GET /dashboard\");\n }\n\n // ---- 1s freshness + uptime ticker (independent of the poll loop) ----\n setInterval(function(){\n if (lastSuccessAt){\n var ago = Math.round((Date.now() - lastSuccessAt)/1000);\n var u = byId(\"updated\"); u.textContent = \"updated \" + ago + \"s ago\";\n // Staleness only matters while polling; a deliberate pause is not \"stale\".\n u.className = \"updated\" + (paused ? \"\" : ago > intervalMs/1000*4 ? \" danger\" : ago > intervalMs/1000*2 ? \" warn\" : \"\");\n }\n // Tick uptime locally between polls so the seconds advance smoothly; each\n // successful poll re-seeds lastUptime from the authoritative server value.\n if (!paused && lastUptime !== null){\n lastUptime += 1;\n byId(\"uptime-num\").textContent = fmtUptime(lastUptime);\n var fu = byId(\"foot-uptime\"); if (fu) fu.textContent = \"uptime \" + fmtUptime(lastUptime);\n }\n }, 1000);\n\n // ---- boot ----\n applyTheme(); setActiveSeg();\n setPill(\"\",\"CONNECTING\",false);\n poll();\n})();\n</script>\n</body>\n</html>\n`;\n","import { extractTokenUsage } from \"./openai\";\nimport type {\n CopilotQuota,\n CopilotUsage,\n GithubRateLimit,\n GithubRateLimitSnapshot,\n LatencySnapshot,\n MetricsSnapshot,\n ModelTokenTotals,\n RequestObservation,\n RouteLatency,\n TokenUsage,\n} from \"./types\";\nimport { asRecord, safeJsonParse } from \"./util\";\n\n/** Content-Type for the Prometheus text exposition format (version 0.0.4). */\nexport const PROMETHEUS_CONTENT_TYPE = \"text/plain; version=0.0.4; charset=utf-8\";\n\n/** Upper bounds (seconds) for the request-duration histogram buckets. */\nconst DURATION_BUCKETS_SECONDS = [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60] as const;\n\n/** Cap on bytes buffered or scanned while extracting usage from a response body. */\nconst USAGE_BUFFER_LIMIT_BYTES = 16 * 1024 * 1024;\n\n/** Bound the distinct model labels so a hostile client cannot blow up cardinality. */\nconst MAX_TRACKED_MODELS = 200;\nconst MAX_MODEL_LABEL_LENGTH = 200;\n\n/** GitHub exposes a small fixed set of rate-limit resources; bound it anyway. */\nconst MAX_TRACKED_RATELIMIT_RESOURCES = 32;\n\n// Unit separator (ASCII 0x1f): joins label parts; cannot collide with a label value.\nconst LABEL_SEPARATOR = \"\\u001f\";\nconst UNKNOWN_MODEL = \"unknown\";\n\ninterface RouteDuration {\n buckets: number[];\n count: number;\n sum: number;\n}\n\nfunction emptyModelTotals(): ModelTokenTotals {\n return { cached: 0, completion: 0, prompt: 0, reasoning: 0, requests: 0, total: 0 };\n}\n\n/**\n * In-process metrics for the running proxy. Counters are monotonic for the life\n * of the process and reset on restart, which Prometheus handles natively. The\n * registry is intentionally allocation-light and synchronous; the single-\n * threaded event loop makes its mutations atomic with respect to each request.\n */\nexport class MetricsRegistry {\n readonly #startedAtMs: number;\n #inFlight = 0;\n #requests = new Map<string, number>();\n #durations = new Map<string, RouteDuration>();\n #tokens = new Map<string, ModelTokenTotals>();\n #upstream = new Map<string, number>();\n #copilotQuota?: CopilotUsage;\n #githubRateLimit = new Map<string, GithubRateLimit>();\n #extraction = { extracted: 0, missing: 0 };\n\n constructor(options: { now?: () => number } = {}) {\n this.#startedAtMs = (options.now ?? Date.now)();\n }\n\n /** Mark a request as started; pair with exactly one {@link observe}. */\n startRequest(): void {\n this.#inFlight += 1;\n }\n\n /** Record a completed request and clear its in-flight slot. */\n observe(observation: RequestObservation): void {\n if (this.#inFlight > 0) {\n this.#inFlight -= 1;\n }\n const key = labelKey(observation.route, observation.method, String(observation.status));\n this.#requests.set(key, (this.#requests.get(key) ?? 0) + 1);\n this.#observeDuration(observation.route, observation.durationMs / 1000);\n }\n\n /**\n * Record whether one upstream completion reported token usage. `missing`\n * counts responses that carried no usage object — most often streamed Chat\n * Completions sent without `stream_options: {\"include_usage\": true}` — so a\n * rising miss rate flags clients whose token usage is going unaccounted.\n */\n recordTokenExtraction(extracted: boolean): void {\n if (extracted) {\n this.#extraction.extracted += 1;\n } else {\n this.#extraction.missing += 1;\n }\n }\n\n /** Accumulate token counts for a model from one upstream completion. */\n recordTokens(model: string, usage: TokenUsage): void {\n const name = this.#modelLabel(model);\n const totals = this.#tokens.get(name) ?? emptyModelTotals();\n totals.requests += 1;\n totals.prompt += nonNegative(usage.promptTokens);\n totals.completion += nonNegative(usage.completionTokens);\n totals.total += nonNegative(usage.totalTokens);\n totals.reasoning += nonNegative(usage.reasoningTokens ?? 0);\n totals.cached += nonNegative(usage.cachedTokens ?? 0);\n this.#tokens.set(name, totals);\n }\n\n /** Record one upstream Copilot call and whether it succeeded. */\n recordUpstream(path: string, ok: boolean): void {\n const key = labelKey(path, ok ? \"ok\" : \"error\");\n this.#upstream.set(key, (this.#upstream.get(key) ?? 0) + 1);\n }\n\n /** Store the latest Copilot quota so /metrics can expose it as gauges. */\n recordCopilotQuota(usage: CopilotUsage): void {\n this.#copilotQuota = usage;\n }\n\n /**\n * Store the latest GitHub REST rate-limit budget, keyed by its resource bucket.\n * A no-op when `rateLimit` is undefined (the response carried no rate-limit\n * headers) so callers can pass {@link parseRateLimitHeaders} output directly.\n */\n recordGithubRateLimit(rateLimit: GithubRateLimit | undefined): void {\n if (!rateLimit) {\n return;\n }\n const resource = this.#rateLimitResource(rateLimit.resource);\n this.#githubRateLimit.set(resource, { ...rateLimit, resource });\n }\n\n // Clean a raw value into a bounded exposition-format label: cap its length,\n // strip characters that would corrupt the format, and fold overflow past the\n // cardinality limit into UNKNOWN_MODEL so the series count stays bounded.\n #boundedLabel(\n value: string,\n tracked: { has(key: string): boolean; size: number },\n maxEntries: number,\n ): string {\n const cleaned = cleanLabel(value).slice(0, MAX_MODEL_LABEL_LENGTH) || UNKNOWN_MODEL;\n if (!tracked.has(cleaned) && tracked.size >= maxEntries) {\n return UNKNOWN_MODEL;\n }\n return cleaned;\n }\n\n // The model can originate from a (possibly hostile) client request.\n #modelLabel(model: string): string {\n return this.#boundedLabel(model, this.#tokens, MAX_TRACKED_MODELS);\n }\n\n // The resource comes from a trusted upstream header, but is bounded the same way.\n #rateLimitResource(resource: string): string {\n return this.#boundedLabel(resource, this.#githubRateLimit, MAX_TRACKED_RATELIMIT_RESOURCES);\n }\n\n #observeDuration(route: string, seconds: number): void {\n const value = Number.isFinite(seconds) && seconds >= 0 ? seconds : 0;\n const entry = this.#durations.get(route) ?? {\n buckets: new Array(DURATION_BUCKETS_SECONDS.length).fill(0),\n count: 0,\n sum: 0,\n };\n entry.count += 1;\n entry.sum += value;\n // Values larger than the last bucket bound only appear in the +Inf bucket,\n // which renderPrometheus derives from entry.count.\n const index = DURATION_BUCKETS_SECONDS.findIndex((bound) => value <= bound);\n if (index !== -1) {\n entry.buckets[index] = (entry.buckets[index] ?? 0) + 1;\n }\n this.#durations.set(route, entry);\n }\n\n /** A JSON-friendly view of the current counters. */\n snapshot(now: () => number = Date.now): MetricsSnapshot {\n const byRoute: Record<string, number> = {};\n const byStatus: Record<string, number> = {};\n let requestsTotal = 0;\n for (const [key, count] of this.#requests) {\n const [route = \"\", , status = \"\"] = key.split(LABEL_SEPARATOR);\n byRoute[route] = (byRoute[route] ?? 0) + count;\n byStatus[status] = (byStatus[status] ?? 0) + count;\n requestsTotal += count;\n }\n\n const byModel: Record<string, ModelTokenTotals> = {};\n const tokenTotals = { cached: 0, completion: 0, prompt: 0, reasoning: 0, total: 0 };\n for (const [model, totals] of this.#tokens) {\n byModel[model] = { ...totals };\n tokenTotals.prompt += totals.prompt;\n tokenTotals.completion += totals.completion;\n tokenTotals.total += totals.total;\n tokenTotals.reasoning += totals.reasoning;\n tokenTotals.cached += totals.cached;\n }\n\n let upstreamTotal = 0;\n let upstreamErrors = 0;\n for (const [key, count] of this.#upstream) {\n upstreamTotal += count;\n if (key.endsWith(`${LABEL_SEPARATOR}error`)) {\n upstreamErrors += count;\n }\n }\n\n const githubRateLimit: Record<string, GithubRateLimitSnapshot> = {};\n for (const [resource, rateLimit] of this.#githubRateLimit) {\n githubRateLimit[resource] = toRateLimitSnapshot(rateLimit);\n }\n\n return {\n githubRateLimit,\n inFlight: this.#inFlight,\n latency: this.#latencySnapshot(),\n requests: { byRoute, byStatus, total: requestsTotal },\n startedAt: new Date(this.#startedAtMs).toISOString(),\n tokens: { byModel, extraction: { ...this.#extraction }, ...tokenTotals },\n upstream: { errors: upstreamErrors, total: upstreamTotal },\n uptimeSeconds: Math.max(0, Math.round((now() - this.#startedAtMs) / 1000)),\n };\n }\n\n // Summarize the duration histogram into a JSON latency view: per-route count and\n // exact average, plus overall average and estimated p50/p95. The percentiles come\n // from the buckets aggregated across routes, so they share /metrics' resolution.\n #latencySnapshot(): LatencySnapshot {\n const byRoute: Record<string, RouteLatency> = {};\n const aggregateBuckets = new Array<number>(DURATION_BUCKETS_SECONDS.length).fill(0);\n let totalCount = 0;\n let totalSum = 0;\n for (const [route, entry] of this.#durations) {\n byRoute[route] = {\n avgMs: entry.count > 0 ? round2((entry.sum / entry.count) * 1000) : 0,\n count: entry.count,\n };\n totalCount += entry.count;\n totalSum += entry.sum;\n for (let i = 0; i < aggregateBuckets.length; i += 1) {\n aggregateBuckets[i] = (aggregateBuckets[i] ?? 0) + (entry.buckets[i] ?? 0);\n }\n }\n return {\n avgMs: totalCount > 0 ? round2((totalSum / totalCount) * 1000) : 0,\n byRoute,\n count: totalCount,\n p50Ms: round2(\n quantileFromBuckets(aggregateBuckets, DURATION_BUCKETS_SECONDS, totalCount, 0.5) * 1000,\n ),\n p95Ms: round2(\n quantileFromBuckets(aggregateBuckets, DURATION_BUCKETS_SECONDS, totalCount, 0.95) * 1000,\n ),\n };\n }\n\n /** Render the Prometheus text exposition format (version 0.0.4). */\n renderPrometheus(now: () => number = Date.now): string {\n const lines: string[] = [];\n\n lines.push(\"# HELP hoopilot_process_start_time_seconds Unix epoch when the proxy started.\");\n lines.push(\"# TYPE hoopilot_process_start_time_seconds gauge\");\n lines.push(`hoopilot_process_start_time_seconds ${this.#startedAtMs / 1000}`);\n\n lines.push(\"# HELP hoopilot_uptime_seconds Seconds since the proxy started.\");\n lines.push(\"# TYPE hoopilot_uptime_seconds gauge\");\n lines.push(`hoopilot_uptime_seconds ${Math.max(0, (now() - this.#startedAtMs) / 1000)}`);\n\n lines.push(\"# HELP hoopilot_requests_in_flight Requests currently being served.\");\n lines.push(\"# TYPE hoopilot_requests_in_flight gauge\");\n lines.push(`hoopilot_requests_in_flight ${this.#inFlight}`);\n\n lines.push(\"# HELP hoopilot_requests_total Completed requests by route, method, and status.\");\n lines.push(\"# TYPE hoopilot_requests_total counter\");\n for (const [key, count] of this.#requests) {\n const [route = \"\", method = \"\", status = \"\"] = key.split(LABEL_SEPARATOR);\n lines.push(`hoopilot_requests_total${labels({ method, route, status })} ${count}`);\n }\n\n lines.push(\n \"# HELP hoopilot_upstream_requests_total Copilot upstream calls by path and outcome.\",\n );\n lines.push(\"# TYPE hoopilot_upstream_requests_total counter\");\n for (const [key, count] of this.#upstream) {\n const [path = \"\", outcome = \"\"] = key.split(LABEL_SEPARATOR);\n lines.push(`hoopilot_upstream_requests_total${labels({ outcome, path })} ${count}`);\n }\n\n lines.push(\n \"# HELP hoopilot_tokens_total Tokens reported by upstream usage, by model and type.\",\n );\n lines.push(\"# TYPE hoopilot_tokens_total counter\");\n for (const [model, totals] of this.#tokens) {\n lines.push(`hoopilot_tokens_total${labels({ model, type: \"prompt\" })} ${totals.prompt}`);\n lines.push(\n `hoopilot_tokens_total${labels({ model, type: \"completion\" })} ${totals.completion}`,\n );\n lines.push(\n `hoopilot_tokens_total${labels({ model, type: \"reasoning\" })} ${totals.reasoning}`,\n );\n lines.push(`hoopilot_tokens_total${labels({ model, type: \"cached\" })} ${totals.cached}`);\n }\n\n lines.push(\"# HELP hoopilot_model_requests_total Completions with usage observed, by model.\");\n lines.push(\"# TYPE hoopilot_model_requests_total counter\");\n for (const [model, totals] of this.#tokens) {\n lines.push(`hoopilot_model_requests_total${labels({ model })} ${totals.requests}`);\n }\n\n lines.push(\n \"# HELP hoopilot_token_extraction_total Completions by whether upstream reported token usage.\",\n );\n lines.push(\"# TYPE hoopilot_token_extraction_total counter\");\n lines.push(\n `hoopilot_token_extraction_total${labels({ outcome: \"extracted\" })} ${this.#extraction.extracted}`,\n );\n lines.push(\n `hoopilot_token_extraction_total${labels({ outcome: \"missing\" })} ${this.#extraction.missing}`,\n );\n\n lines.push(\"# HELP hoopilot_request_duration_seconds Request duration by route.\");\n lines.push(\"# TYPE hoopilot_request_duration_seconds histogram\");\n for (const [route, entry] of this.#durations) {\n let cumulative = 0;\n for (let i = 0; i < DURATION_BUCKETS_SECONDS.length; i += 1) {\n cumulative += entry.buckets[i] ?? 0;\n const le = formatNumber(DURATION_BUCKETS_SECONDS[i] ?? 0);\n lines.push(\n `hoopilot_request_duration_seconds_bucket${labels({ le, route })} ${cumulative}`,\n );\n }\n lines.push(\n `hoopilot_request_duration_seconds_bucket${labels({ le: \"+Inf\", route })} ${entry.count}`,\n );\n lines.push(`hoopilot_request_duration_seconds_sum${labels({ route })} ${entry.sum}`);\n lines.push(`hoopilot_request_duration_seconds_count${labels({ route })} ${entry.count}`);\n }\n\n this.#renderGithubRateLimit(lines);\n this.#renderCopilotQuota(lines);\n\n return `${lines.join(\"\\n\")}\\n`;\n }\n\n #renderGithubRateLimit(lines: string[]): void {\n const entries = [...this.#githubRateLimit.values()];\n if (entries.length === 0) {\n return;\n }\n\n const gauge = (\n suffix: string,\n help: string,\n pick: (rateLimit: GithubRateLimit) => number | undefined,\n ): void => {\n const present = entries.filter((rateLimit) => pick(rateLimit) !== undefined);\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_github_ratelimit_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_github_ratelimit_${suffix} gauge`);\n for (const rateLimit of present) {\n lines.push(\n `hoopilot_github_ratelimit_${suffix}${labels({ resource: rateLimit.resource })} ${pick(rateLimit)}`,\n );\n }\n };\n\n gauge(\"limit\", \"GitHub REST API request ceiling for the resource window.\", (r) => r.limit);\n gauge(\"remaining\", \"Requests remaining in the GitHub REST API window.\", (r) => r.remaining);\n gauge(\"used\", \"Requests used in the GitHub REST API window.\", (r) => r.used);\n gauge(\n \"reset_timestamp_seconds\",\n \"Unix epoch when the GitHub REST API window resets.\",\n (r) => r.resetEpochSeconds,\n );\n gauge(\n \"retry_after_seconds\",\n \"Seconds to wait after a GitHub secondary-limit response.\",\n (r) => r.retryAfterSeconds,\n );\n }\n\n #renderCopilotQuota(lines: string[]): void {\n const usage = this.#copilotQuota;\n if (!usage) {\n return;\n }\n const categories = Object.entries(usage.quotas);\n\n const gauge = (\n suffix: string,\n help: string,\n pick: (quota: CopilotQuota) => number | undefined,\n ): void => {\n const present = categories.filter(([, quota]) => pick(quota) !== undefined);\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);\n for (const [category, quota] of present) {\n lines.push(`hoopilot_copilot_quota_${suffix}${labels({ category })} ${pick(quota)}`);\n }\n };\n\n gauge(\"remaining\", \"Remaining quota for the Copilot category.\", (q) => q.remaining);\n gauge(\"entitlement\", \"Quota entitlement for the Copilot category.\", (q) => q.entitlement);\n gauge(\"used\", \"Used quota (entitlement minus remaining) for the category.\", (q) => q.used);\n gauge(\"overage_count\", \"Overage count for the Copilot category.\", (q) => q.overageCount);\n gauge(\n \"overage_entitlement\",\n \"Overage entitlement for the Copilot category.\",\n (q) => q.overageEntitlement,\n );\n gauge(\n \"percent_remaining\",\n \"Percent of quota remaining for the Copilot category.\",\n (q) => q.percentRemaining,\n );\n booleanGauge(\n \"unlimited\",\n \"Whether the Copilot quota category is unlimited.\",\n (q) => q.unlimited,\n );\n booleanGauge(\n \"overage_permitted\",\n \"Whether overage is permitted for the Copilot category.\",\n (q) => q.overagePermitted,\n );\n booleanGauge(\"has_quota\", \"Whether the Copilot quota category has a quota.\", (q) => q.hasQuota);\n booleanGauge(\n \"token_based_billing\",\n \"Whether the Copilot quota category uses token-based billing.\",\n (q) => q.tokenBasedBilling,\n );\n dateGauge(\n \"category_reset_timestamp_seconds\",\n \"Unix epoch of the Copilot category-specific quota reset.\",\n (q) => q.quotaResetAt,\n );\n dateGauge(\n \"category_snapshot_timestamp_seconds\",\n \"Unix epoch of the Copilot category quota snapshot.\",\n (q) => q.timestampUtc,\n );\n\n const resetMs = usage.quotaResetDate ? Date.parse(usage.quotaResetDate) : Number.NaN;\n if (Number.isFinite(resetMs)) {\n lines.push(\n \"# HELP hoopilot_copilot_quota_reset_timestamp_seconds Unix epoch of the next reset.\",\n );\n lines.push(\"# TYPE hoopilot_copilot_quota_reset_timestamp_seconds gauge\");\n lines.push(`hoopilot_copilot_quota_reset_timestamp_seconds ${resetMs / 1000}`);\n }\n\n if (usage.plan || usage.accessTypeSku) {\n lines.push(\"# HELP hoopilot_copilot_info Copilot plan metadata as a constant-1 info gauge.\");\n lines.push(\"# TYPE hoopilot_copilot_info gauge\");\n lines.push(\n `hoopilot_copilot_info${labels({\n access_type_sku: usage.accessTypeSku ?? \"\",\n plan: usage.plan ?? \"\",\n })} 1`,\n );\n }\n\n function booleanGauge(\n suffix: string,\n help: string,\n pick: (quota: CopilotQuota) => boolean | undefined,\n ): void {\n const present = categories.filter(([, quota]) => pick(quota) !== undefined);\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);\n for (const [category, quota] of present) {\n lines.push(\n `hoopilot_copilot_quota_${suffix}${labels({ category })} ${pick(quota) ? 1 : 0}`,\n );\n }\n }\n\n function dateGauge(\n suffix: string,\n help: string,\n pick: (quota: CopilotQuota) => string | undefined,\n ): void {\n const present = categories\n .map(([category, quota]) => [category, Date.parse(pick(quota) ?? \"\")] as const)\n .filter(([, timestamp]) => Number.isFinite(timestamp));\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);\n for (const [category, timestamp] of present) {\n lines.push(`hoopilot_copilot_quota_${suffix}${labels({ category })} ${timestamp / 1000}`);\n }\n }\n }\n}\n\n/**\n * Tee `response`'s body so the client receives an unchanged copy while a\n * background reader extracts token usage. Returns a new Response carrying the\n * client-facing branch and the original status/headers. Usage extraction never\n * throws into the client stream: a parse failure or an aborted client simply\n * yields no usage. When the body is absent the response is returned untouched.\n *\n * Pass the request's `signal` so a client disconnect cancels the observer\n * branch; combined with the runtime cancelling the client branch, that releases\n * the shared upstream connection instead of draining it in the background.\n */\nexport function observeResponseUsage(\n response: Response,\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n signal?: AbortSignal,\n onOutcome?: (extracted: boolean) => void,\n): Response {\n const body = response.body;\n if (!body) {\n return response;\n }\n const [clientBranch, observerBranch] = body.tee();\n const isSse = response.headers.get(\"content-type\")?.includes(\"text/event-stream\") ?? false;\n void consumeUsage(observerBranch, isSse, fallbackModel, onUsage, signal, onOutcome).catch(\n () => {},\n );\n return new Response(clientBranch, {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\n/** Extract and record token usage from an already-buffered response body. */\nexport function recordResponseTextUsage(\n text: string,\n isSse: boolean,\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n onOutcome?: (extracted: boolean) => void,\n): void {\n const accumulator = createUsageAccumulator(fallbackModel, onUsage, onOutcome);\n if (isSse) {\n for (const line of text.split(/\\r?\\n/)) {\n considerSseLine(line, accumulator.consider);\n }\n } else {\n const parsed = safeJsonParse(text);\n if (parsed !== undefined) {\n accumulator.consider(parsed);\n }\n }\n accumulator.finish();\n}\n\nasync function consumeUsage(\n stream: ReadableStream<Uint8Array>,\n isSse: boolean,\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n signal?: AbortSignal,\n onOutcome?: (extracted: boolean) => void,\n): Promise<void> {\n const reader = stream.getReader();\n const onAbort = () => {\n reader.cancel().catch(() => {});\n };\n if (signal?.aborted) {\n reader.cancel().catch(() => {});\n } else {\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n const decoder = new TextDecoder();\n // A client disconnect cancels the reader mid-stream; don't count that as a\n // missing-usage completion — only record outcomes for streams we finished.\n const guardedOutcome = onOutcome\n ? (extracted: boolean) => {\n if (!signal?.aborted) {\n onOutcome(extracted);\n }\n }\n : undefined;\n const accumulator = createUsageAccumulator(fallbackModel, onUsage, guardedOutcome);\n let buffer = \"\";\n let bufferedBytes = 0;\n let overflowed = false;\n\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n const chunk = decoder.decode(result.value, { stream: true });\n if (isSse) {\n buffer += chunk;\n const lines = buffer.split(/\\r?\\n/);\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n considerSseLine(line, accumulator.consider);\n }\n // Drop a pathologically long newline-less line so the buffer stays bounded.\n if (buffer.length > USAGE_BUFFER_LIMIT_BYTES) {\n buffer = \"\";\n }\n } else if (!overflowed) {\n bufferedBytes += result.value.byteLength;\n if (bufferedBytes > USAGE_BUFFER_LIMIT_BYTES) {\n overflowed = true;\n buffer = \"\";\n } else {\n buffer += chunk;\n }\n }\n }\n // Flush any trailing bytes the streaming decoder is still holding.\n const finalBuffer = buffer + decoder.decode();\n if (isSse) {\n if (finalBuffer) {\n considerSseLine(finalBuffer, accumulator.consider);\n }\n } else if (!overflowed && finalBuffer) {\n const parsed = safeJsonParse(finalBuffer);\n if (parsed !== undefined) {\n accumulator.consider(parsed);\n }\n }\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n reader.releaseLock();\n }\n\n accumulator.finish();\n}\n\nfunction createUsageAccumulator(\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n onOutcome?: (extracted: boolean) => void,\n): { consider: (payload: unknown) => void; finish: () => void } {\n let model = fallbackModel;\n let usage: TokenUsage | undefined;\n return {\n consider(payload) {\n const record = asRecord(payload);\n const found =\n extractTokenUsage(record.usage) ?? extractTokenUsage(asRecord(record.response).usage);\n if (found) {\n usage = found;\n }\n const candidateModel = modelText(record.model) || modelText(asRecord(record.response).model);\n if (candidateModel) {\n model = candidateModel;\n }\n },\n finish() {\n if (usage) {\n onUsage(model, usage);\n }\n onOutcome?.(usage !== undefined);\n },\n };\n}\n\nfunction considerSseLine(line: string, consider: (payload: unknown) => void): void {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) {\n return;\n }\n const data = trimmed.slice(\"data:\".length).trim();\n if (!data || data === \"[DONE]\") {\n return;\n }\n const parsed = safeJsonParse(data);\n if (parsed !== undefined) {\n consider(parsed);\n }\n}\n\nfunction modelText(value: unknown): string {\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction nonNegative(value: number): number {\n return Number.isFinite(value) && value > 0 ? value : 0;\n}\n\nfunction round2(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\n// Estimate a latency quantile from histogram bucket counts via Prometheus-style\n// linear interpolation within the bucket the target rank lands in. `bucketCounts[i]`\n// is the number of observations in `(bounds[i-1], bounds[i]]`; observations above the\n// last finite bound live only in the implicit +Inf bucket, for which that bound is\n// returned. Returns seconds.\nfunction quantileFromBuckets(\n bucketCounts: number[],\n bounds: readonly number[],\n count: number,\n q: number,\n): number {\n if (count <= 0) {\n return 0;\n }\n const rank = q * count;\n let cumulative = 0;\n for (let i = 0; i < bounds.length; i += 1) {\n const inBucket = bucketCounts[i] ?? 0;\n if (inBucket > 0 && cumulative + inBucket >= rank) {\n const lower = i === 0 ? 0 : (bounds[i - 1] ?? 0);\n const upper = bounds[i] ?? lower;\n return lower + (upper - lower) * ((rank - cumulative) / inBucket);\n }\n cumulative += inBucket;\n }\n return bounds[bounds.length - 1] ?? 0;\n}\n\n// Drop ASCII control characters (and DEL) that would corrupt the Prometheus\n// exposition format, then trim. Used for labels sourced from an upstream header,\n// mirroring the control-char stripping applied to client-supplied model labels.\nfunction cleanLabel(value: string): string {\n let result = \"\";\n for (const char of value) {\n const code = char.charCodeAt(0);\n if (code > 0x1f && code !== 0x7f) {\n result += char;\n }\n }\n return result.trim();\n}\n\n// Convert the internal rate-limit record into its JSON snapshot shape: the epoch\n// reset and observation times become ISO strings, and absent fields stay absent.\nfunction toRateLimitSnapshot(rateLimit: GithubRateLimit): GithubRateLimitSnapshot {\n const snapshot: GithubRateLimitSnapshot = {\n observedAt: new Date(rateLimit.observedAtMs).toISOString(),\n };\n if (rateLimit.limit !== undefined) {\n snapshot.limit = rateLimit.limit;\n }\n if (rateLimit.remaining !== undefined) {\n snapshot.remaining = rateLimit.remaining;\n }\n if (rateLimit.used !== undefined) {\n snapshot.used = rateLimit.used;\n }\n if (rateLimit.resetEpochSeconds !== undefined) {\n snapshot.resetAt = new Date(rateLimit.resetEpochSeconds * 1000).toISOString();\n }\n if (rateLimit.retryAfterSeconds !== undefined) {\n snapshot.retryAfterSeconds = rateLimit.retryAfterSeconds;\n }\n return snapshot;\n}\n\nfunction labelKey(...parts: string[]): string {\n return parts.join(LABEL_SEPARATOR);\n}\n\nfunction labels(pairs: Record<string, string>): string {\n const entries = Object.entries(pairs);\n if (entries.length === 0) {\n return \"\";\n }\n const rendered = entries.map(([name, value]) => `${name}=\"${escapeLabelValue(value)}\"`);\n return `{${rendered.join(\",\")}}`;\n}\n\nfunction escapeLabelValue(value: string): string {\n return value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\");\n}\n\nfunction formatNumber(value: number): string {\n return Number.isInteger(value) ? value.toString() : String(value);\n}\n","import { asRecord } from \"./util\";\n\n// Build-time constants. For standalone binaries these identifiers are replaced\n// at compile time via `bun build --compile --define 'HOOPILOT_VERSION=\"x.y.z\"'`\n// (see scripts/build-binaries.sh). In dev runs and the npm package they are not\n// defined, so `typeof` is \"undefined\" and we fall back to reading package.json.\ndeclare const HOOPILOT_VERSION: string;\ndeclare const HOOPILOT_TARGET: string;\n\n/** Version baked into a standalone binary, or undefined for npm/dev installs. */\nexport const BAKED_VERSION: string | undefined =\n typeof HOOPILOT_VERSION !== \"undefined\" ? HOOPILOT_VERSION : undefined;\n\n/**\n * Release asset suffix baked into a standalone binary (e.g. \"linux-x64-musl\",\n * \"windows-x64\", \"darwin-arm64\"), or undefined for npm/dev installs. Lets the\n * self-updater fetch the exact asset variant it was built from.\n */\nexport const BAKED_TARGET: string | undefined =\n typeof HOOPILOT_TARGET !== \"undefined\" ? HOOPILOT_TARGET : undefined;\n\n/** True when running as a `bun build --compile` standalone executable. */\nexport const IS_STANDALONE_BINARY: boolean = BAKED_VERSION !== undefined;\n\nlet cachedVersion: string | undefined;\n\n/** Resolve the running version, preferring the baked value for binaries. */\nexport async function getVersion(): Promise<string> {\n if (cachedVersion !== undefined) {\n return cachedVersion;\n }\n let resolved: string;\n if (BAKED_VERSION) {\n resolved = BAKED_VERSION;\n } else {\n try {\n const manifest = asRecord(await Bun.file(new URL(\"../package.json\", import.meta.url)).json());\n const version = manifest.version;\n resolved = typeof version === \"string\" ? version : \"0.0.0\";\n } catch {\n resolved = \"0.0.0\";\n }\n }\n cachedVersion = resolved;\n return resolved;\n}\n","// Self-update and update-notification orchestration. The pure decision logic\n// lives in update-core.ts; this module performs the network and filesystem I/O.\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport {\n chmodSync,\n copyFileSync,\n existsSync,\n mkdirSync,\n realpathSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { errorDetails } from \"./logger\";\nimport type { HoopilotLogger } from \"./types\";\nimport {\n assetNameFor,\n assetSuffixFor,\n checksumFor,\n codexxShimFiles,\n formatUpdateNotice,\n type InstallKind,\n isOutdated,\n isUpdateCheckDisabled,\n type LatestRelease,\n latestReleaseApiUrl,\n parseLatestRelease,\n parseState,\n resolveCacheDir,\n shouldCleanupOldBinary,\n shouldRefresh,\n type UpdateState,\n upgradeCommandFor,\n} from \"./update-core\";\nimport { errorMessage } from \"./util\";\nimport { BAKED_TARGET, IS_STANDALONE_BINARY } from \"./version\";\n\nconst REQUEST_TIMEOUT_MS = 8_000;\n// Binary and checksum downloads share one generous timeout, distinct from the\n// short metadata-request timeout that uses REQUEST_TIMEOUT_MS directly.\nconst DOWNLOAD_TIMEOUT_MS = REQUEST_TIMEOUT_MS * 10;\nconst SHA256SUMS = \"SHA256SUMS\";\n\nfunction userAgent(version: string): string {\n return `hoopilot/${version}`;\n}\n\nfunction cacheDir(): string {\n return resolveCacheDir(process.env, process.platform, homedir(), join);\n}\n\nfunction stateFilePath(): string {\n return join(cacheDir(), \"update-check.json\");\n}\n\nasync function readStateSafe(): Promise<UpdateState> {\n try {\n return parseState(await readFile(stateFilePath(), \"utf8\"));\n } catch {\n return { lastCheck: 0, latestVersion: null, etag: null };\n }\n}\n\nasync function writeStateSafe(state: UpdateState): Promise<void> {\n try {\n mkdirSync(cacheDir(), { recursive: true });\n await writeFile(stateFilePath(), JSON.stringify(state), \"utf8\");\n } catch {\n // best effort: a read-only cache dir must never break the CLI\n }\n}\n\ninterface FetchResult {\n status: number;\n etag: string | null;\n release: LatestRelease | null;\n}\n\nasync function fetchLatest(version: string, etag?: string | null): Promise<FetchResult | null> {\n try {\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github+json\",\n \"User-Agent\": userAgent(version),\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n };\n if (etag) {\n headers[\"If-None-Match\"] = etag;\n }\n const response = await fetch(latestReleaseApiUrl(), {\n headers,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (response.status === 304) {\n return { status: 304, etag: etag ?? null, release: null };\n }\n if (!response.ok) {\n return { status: response.status, etag: null, release: null };\n }\n return {\n status: response.status,\n etag: response.headers.get(\"etag\"),\n release: parseLatestRelease(await response.json()),\n };\n } catch {\n return null; // offline / timeout: caller leaves state untouched\n }\n}\n\n/**\n * Print a notice if a previously-cached check found a newer release, then kick\n * off a throttled background refresh. Never blocks on the network and never\n * throws. Intended to be called (unawaited is fine) from the serve path.\n */\nexport async function maybeNotifyUpdate(\n currentVersion: string,\n kind: InstallKind,\n logger?: HoopilotLogger,\n): Promise<void> {\n if (isUpdateCheckDisabled(process.env, Boolean(process.stderr.isTTY))) {\n logger?.debug({ event: \"update.check.skipped\" }, \"update check skipped\");\n return;\n }\n const state = await readStateSafe();\n if (state.latestVersion && isOutdated(currentVersion, state.latestVersion)) {\n logger?.debug(\n {\n currentVersion,\n event: \"update.notice.cached\",\n installKind: kind,\n latestVersion: state.latestVersion,\n },\n \"showing cached update notice\",\n );\n process.stderr.write(formatUpdateNotice(currentVersion, state.latestVersion, kind));\n }\n if (shouldRefresh(state.lastCheck, Date.now())) {\n logger?.debug({ event: \"update.check.refresh_queued\" }, \"queued update check refresh\");\n void refreshState(currentVersion, state.etag ?? null, logger).catch((error: unknown) => {\n logger?.debug(\n { err: errorDetails(error), event: \"update.check.refresh_failed\" },\n \"update check refresh failed\",\n );\n });\n }\n}\n\nasync function refreshState(\n currentVersion: string,\n etag: string | null,\n logger?: HoopilotLogger,\n): Promise<void> {\n const result = await fetchLatest(currentVersion, etag);\n if (!result) {\n logger?.debug({ event: \"update.check.unavailable\" }, \"update check unavailable\");\n return; // network error: keep prior state\n }\n if (result.status === 304) {\n const prev = await readStateSafe();\n await writeStateSafe({ ...prev, lastCheck: Date.now() });\n logger?.debug({ event: \"update.check.not_modified\" }, \"latest release unchanged\");\n return;\n }\n if (result.release) {\n await writeStateSafe({\n lastCheck: Date.now(),\n latestVersion: result.release.version,\n etag: result.etag,\n });\n logger?.debug(\n { event: \"update.check.updated\", latestVersion: result.release.version },\n \"updated cached latest release state\",\n );\n }\n}\n\nfunction detectInstallKind(): InstallKind {\n return IS_STANDALONE_BINARY ? \"binary\" : \"npm\";\n}\n\nfunction detectMusl(): boolean {\n if (process.platform !== \"linux\") {\n return false;\n }\n try {\n const report = process.report?.getReport?.() as\n | { header?: Record<string, unknown> }\n | undefined;\n if (report?.header && \"glibcVersionRuntime\" in report.header) {\n return !report.header.glibcVersionRuntime;\n }\n } catch {\n // fall through to file-based detection\n }\n try {\n if (existsSync(\"/etc/alpine-release\")) {\n return true;\n }\n const ldd = execFileSync(\"ldd\", [\"--version\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: 2_000,\n });\n return /musl/i.test(ldd);\n } catch {\n return false;\n }\n}\n\nasync function downloadToFile(url: string, dest: string, version: string): Promise<void> {\n const response = await fetch(url, {\n headers: { \"User-Agent\": userAgent(version) },\n redirect: \"follow\",\n signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n });\n if (!response.ok || !response.body) {\n throw new Error(`Download failed (${response.status}) for ${url}`);\n }\n // Stream the body straight to disk instead of buffering the whole binary.\n await Bun.write(dest, response);\n}\n\nasync function sha256File(path: string): Promise<string> {\n return createHash(\"sha256\")\n .update(await readFile(path))\n .digest(\"hex\");\n}\n\nasync function verifyChecksum(\n release: LatestRelease,\n assetName: string,\n file: string,\n version: string,\n): Promise<void> {\n const sums = release.assets.find((asset) => asset.name === SHA256SUMS);\n if (!sums) {\n // Fail closed: never overwrite the running binary with an unverified download.\n throw new Error(\n `Release ${release.tag} has no ${SHA256SUMS}; refusing to install an unverified binary.`,\n );\n }\n const response = await fetch(sums.url, {\n headers: { \"User-Agent\": userAgent(version) },\n redirect: \"follow\",\n signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n });\n if (!response.ok) {\n throw new Error(`Could not download ${SHA256SUMS} (${response.status}).`);\n }\n const expected = checksumFor(await response.text(), assetName);\n if (!expected) {\n throw new Error(`No checksum for ${assetName} in ${SHA256SUMS}.`);\n }\n const actual = await sha256File(file);\n if (actual.toLowerCase() !== expected) {\n throw new Error(`Checksum mismatch for ${assetName}: expected ${expected}, got ${actual}.`);\n }\n}\n\nfunction swapBinary(tmpFile: string, exePath: string): void {\n if (process.platform === \"win32\") {\n // A running .exe cannot be overwritten, but it can be renamed aside.\n const oldExe = `${exePath}.old`;\n try {\n rmSync(oldExe, { force: true });\n } catch {\n // a previous .old may still be locked; the new name still wins below\n }\n renameSync(exePath, oldExe);\n const restore = () => {\n try {\n renameSync(oldExe, exePath); // put the working binary back\n } catch {\n // nothing more we can do\n }\n };\n try {\n renameSync(tmpFile, exePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EXDEV\") {\n try {\n copyFileSync(tmpFile, exePath);\n } catch (copyError) {\n restore();\n throw copyError;\n }\n } else {\n restore();\n throw error;\n }\n }\n return;\n }\n // Unix: atomic rename over the running file; the old inode stays mapped until exit.\n try {\n renameSync(tmpFile, exePath);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EXDEV\") {\n copyFileSync(tmpFile, exePath);\n chmodSync(exePath, 0o755);\n } else if (code === \"EACCES\" || code === \"EPERM\") {\n throw new Error(\n `No permission to update ${exePath}. Re-run with sudo, or reinstall to a writable directory.`,\n );\n } else {\n throw error;\n }\n }\n}\n\nfunction refreshCodexxShim(dir: string, logger?: HoopilotLogger): void {\n try {\n for (const file of codexxShimFiles(process.platform)) {\n const path = join(dir, file.name);\n writeFileSync(path, file.content, \"utf8\");\n if (file.executable) {\n chmodSync(path, 0o755);\n }\n }\n } catch (error) {\n logger?.warn(\n { err: errorDetails(error), event: \"update.codexx_shim_failed\" },\n \"could not refresh codexx shim\",\n );\n console.warn(`Updated hoopilot, but could not refresh the codexx shim: ${errorMessage(error)}`);\n }\n}\n\n/** Remove the leftover \".old\" binary from a prior Windows self-update. */\nexport function cleanupOldBinary(): void {\n if (!shouldCleanupOldBinary(process.platform, IS_STANDALONE_BINARY)) {\n return;\n }\n try {\n rmSync(`${realpathSync(process.execPath)}.old`, { force: true });\n } catch {\n // still locked or already gone\n }\n}\n\n/** Implements the `hoopilot update` command. */\nexport async function runUpdate(currentVersion: string, logger?: HoopilotLogger): Promise<void> {\n cleanupOldBinary();\n const kind = detectInstallKind();\n logger?.debug({ currentVersion, event: \"update.started\", installKind: kind }, \"update started\");\n\n if (kind !== \"binary\") {\n console.log(`hoopilot ${currentVersion} was installed via npm.`);\n console.log(`Update with: ${upgradeCommandFor(\"npm\")}`);\n return;\n }\n\n console.log(`hoopilot ${currentVersion} — checking for updates...`);\n const result = await fetchLatest(currentVersion);\n const release = result?.release ?? null;\n if (!release) {\n throw new Error(\"Could not reach GitHub to check for the latest release.\");\n }\n if (!isOutdated(currentVersion, release.version)) {\n logger?.debug(\n { currentVersion, event: \"update.already_current\", latestVersion: release.version },\n \"hoopilot is already up to date\",\n );\n console.log(`Already up to date (latest: ${release.version}).`);\n return;\n }\n\n const suffix = BAKED_TARGET ?? assetSuffixFor(process.platform, process.arch, detectMusl());\n const assetName = assetNameFor(suffix);\n const asset = release.assets.find((entry) => entry.name === assetName);\n if (!asset) {\n const available = release.assets.map((entry) => entry.name).join(\", \") || \"none\";\n throw new Error(`Release ${release.tag} has no asset \"${assetName}\". Available: ${available}.`);\n }\n\n console.log(`Updating ${currentVersion} → ${release.version} (${assetName})...`);\n logger?.debug(\n {\n assetName,\n currentVersion,\n event: \"update.installing\",\n latestVersion: release.version,\n },\n \"installing update\",\n );\n const exePath = realpathSync(process.execPath);\n const tmpFile = join(dirname(exePath), `.hoopilot-update-${process.pid}.tmp`);\n try {\n await downloadToFile(asset.url, tmpFile, currentVersion);\n await verifyChecksum(release, assetName, tmpFile, currentVersion);\n if (process.platform !== \"win32\") {\n chmodSync(tmpFile, 0o755);\n }\n swapBinary(tmpFile, exePath);\n refreshCodexxShim(dirname(exePath), logger);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EACCES\" || code === \"EPERM\") {\n throw new Error(\n `No permission to update ${exePath}. Re-run with sudo, or reinstall to a writable directory (e.g. set HOOPILOT_INSTALL_DIR).`,\n );\n }\n throw error;\n } finally {\n try {\n rmSync(tmpFile, { force: true });\n } catch {\n // already moved into place or never created\n }\n }\n\n console.log(`Updated hoopilot to ${release.version}.`);\n logger?.debug(\n { currentVersion, event: \"update.completed\", latestVersion: release.version },\n \"update completed\",\n );\n if (process.platform === \"win32\") {\n console.log(\"Restart hoopilot to run the new version.\");\n }\n}\n","// Pure, dependency-free logic for version checks and self-update decisions.\n// Everything here is side-effect free so it can be unit tested without network\n// or filesystem access; the I/O orchestration lives in update.ts.\n\nconst REPO_OWNER = \"openhoo\";\nconst REPO_NAME = \"hoopilot\";\nexport const REPO = `${REPO_OWNER}/${REPO_NAME}`;\nexport const NPM_PACKAGE = \"@openhoo/hoopilot\";\n\n/** How a copy of hoopilot was installed. */\nexport type InstallKind = \"binary\" | \"npm\";\n\n/** How often the background update check is allowed to hit GitHub. */\nexport const UPDATE_CHECK_INTERVAL_MS = 1000 * 60 * 60 * 24; // 24h\n\n/** Persisted state for the throttled update check. */\nexport interface UpdateState {\n lastCheck: number;\n latestVersion: string | null;\n etag: string | null;\n}\n\nexport interface CodexxShimFile {\n content: string;\n executable: boolean;\n name: string;\n}\n\ninterface SemVer {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nfunction parseSemver(input: string): SemVer | null {\n const value = String(input)\n .trim()\n .replace(/^[v=]+/, \"\");\n const match = value.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+[0-9A-Za-z.-]+)?$/);\n if (!match) {\n return null;\n }\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n // Build metadata (everything after \"+\") is intentionally dropped.\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\nfunction comparePrerelease(a: string[], b: string[]): -1 | 0 | 1 {\n if (a.length === 0 && b.length === 0) {\n return 0;\n }\n // A release outranks an otherwise-equal prerelease.\n if (a.length === 0) {\n return 1;\n }\n if (b.length === 0) {\n return -1;\n }\n const len = Math.max(a.length, b.length);\n for (let i = 0; i < len; i++) {\n const x = a[i];\n const y = b[i];\n // The version with more prerelease fields has higher precedence.\n if (x === undefined) {\n return -1;\n }\n if (y === undefined) {\n return 1;\n }\n const xNumeric = /^\\d+$/.test(x);\n const yNumeric = /^\\d+$/.test(y);\n if (xNumeric && yNumeric) {\n const diff = Number(x) - Number(y);\n if (diff !== 0) {\n return diff < 0 ? -1 : 1;\n }\n } else if (xNumeric) {\n return -1; // numeric identifiers sort lower than alphanumeric\n } else if (yNumeric) {\n return 1;\n } else if (x !== y) {\n return x < y ? -1 : 1; // ASCII lexical\n }\n }\n return 0;\n}\n\n/**\n * Compare two semantic versions. Returns -1 if a < b, 0 if equal, 1 if a > b.\n * Tolerates a leading \"v\"/\"=\", ignores build metadata, honors prerelease\n * precedence, and sorts unparseable input low so a bad value never throws.\n */\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const pa = parseSemver(a);\n const pb = parseSemver(b);\n if (!pa || !pb) {\n if (!pa && !pb) {\n return 0;\n }\n return pa ? 1 : -1;\n }\n if (pa.major !== pb.major) {\n return pa.major < pb.major ? -1 : 1;\n }\n if (pa.minor !== pb.minor) {\n return pa.minor < pb.minor ? -1 : 1;\n }\n if (pa.patch !== pb.patch) {\n return pa.patch < pb.patch ? -1 : 1;\n }\n return comparePrerelease(pa.prerelease, pb.prerelease);\n}\n\n/** True when `latest` is a strictly newer release than `current`. */\nexport function isOutdated(current: string, latest: string): boolean {\n return compareSemver(current, latest) < 0;\n}\n\n/** Strip a leading \"v\" from a git tag to get a bare version string. */\nexport function versionFromTag(tag: string): string {\n return tag.trim().replace(/^v/, \"\");\n}\n\n/**\n * Compute the release asset suffix for a platform/arch, e.g. \"linux-x64-musl\",\n * \"darwin-arm64\", \"windows-x64\". `platform`/`arch` use Node's process values.\n */\nexport function assetSuffixFor(platform: string, arch: string, isMusl: boolean): string {\n const os = platform === \"win32\" ? \"windows\" : platform === \"darwin\" ? \"darwin\" : \"linux\";\n const cpu = arch === \"arm64\" || arch === \"aarch64\" ? \"arm64\" : \"x64\";\n const libc = os === \"linux\" && isMusl ? \"-musl\" : \"\";\n return `${os}-${cpu}${libc}`;\n}\n\n/** Full release asset file name for a suffix (adds .exe for Windows). */\nexport function assetNameFor(suffix: string): string {\n const name = `hoopilot-${suffix}`;\n return suffix.startsWith(\"windows-\") ? `${name}.exe` : name;\n}\n\n/** Whether automatic update checks should be skipped, per env + TTY. */\nexport function isUpdateCheckDisabled(\n env: Record<string, string | undefined>,\n isTty: boolean,\n): boolean {\n if (env.HOOPILOT_NO_UPDATE_CHECK || env.NO_UPDATE_NOTIFIER) {\n return true;\n }\n if (env.NODE_ENV === \"test\") {\n return true;\n }\n if (!isTty) {\n return true; // piped / non-interactive output\n }\n if (\n (env.CI && env.CI !== \"false\") ||\n env.CONTINUOUS_INTEGRATION ||\n env.GITHUB_ACTIONS ||\n env.BUILD_NUMBER ||\n env.RUN_ID\n ) {\n return true;\n }\n return false;\n}\n\n/** Whether the background check is due again given the last check time. */\nexport function shouldRefresh(\n lastCheck: number,\n now: number,\n intervalMs = UPDATE_CHECK_INTERVAL_MS,\n): boolean {\n return now - lastCheck >= intervalMs;\n}\n\n/** The command a user runs to upgrade, depending on how they installed. */\nexport function upgradeCommandFor(kind: InstallKind): string {\n return kind === \"binary\"\n ? \"hoopilot update\"\n : `npm install -g ${NPM_PACKAGE}@latest (or: bun add -g ${NPM_PACKAGE})`;\n}\n\n/** Whether it is safe to remove a leftover Windows self-update backup. */\nexport function shouldCleanupOldBinary(platform: string, isStandaloneBinary: boolean): boolean {\n return platform === \"win32\" && isStandaloneBinary;\n}\n\n/** Files that expose the standalone `codexx` command next to the `hoopilot` binary. */\nexport function codexxShimFiles(platform: string): CodexxShimFile[] {\n if (platform === \"win32\") {\n return [\n {\n content: `$ErrorActionPreference = 'Stop'\n$hoopilot = Join-Path $PSScriptRoot 'hoopilot.exe'\n& $hoopilot codexx @args\nexit $LASTEXITCODE\n`,\n executable: false,\n name: \"codexx.ps1\",\n },\n {\n content: `@echo off\nsetlocal\nwhere pwsh >nul 2>nul\nif %ERRORLEVEL% EQU 0 (\n pwsh -NoProfile -ExecutionPolicy Bypass -File \"%~dp0codexx.ps1\" %*\n) else (\n powershell -NoProfile -ExecutionPolicy Bypass -File \"%~dp0codexx.ps1\" %*\n)\nexit /b %ERRORLEVEL%\n`,\n executable: false,\n name: \"codexx.cmd\",\n },\n ];\n }\n return [\n {\n content: `#!/bin/sh\nset -eu\nscript_dir=$(CDPATH= cd \"$(dirname \"$0\")\" && pwd)\nexec \"$script_dir/hoopilot\" codexx \"$@\"\n`,\n executable: true,\n name: \"codexx\",\n },\n ];\n}\n\n/** Render the \"update available\" notice printed to stderr. */\nexport function formatUpdateNotice(current: string, latest: string, kind: InstallKind): string {\n return (\n `\\nUpdate available for hoopilot: ${current} → ${latest}\\n` +\n `Run: ${upgradeCommandFor(kind)}\\n\\n`\n );\n}\n\n/** Parse the persisted update-check state, tolerating any malformed input. */\nexport function parseState(text: string): UpdateState {\n try {\n const data: unknown = JSON.parse(text);\n const record = (data && typeof data === \"object\" ? data : {}) as Record<string, unknown>;\n return {\n lastCheck: typeof record.lastCheck === \"number\" ? record.lastCheck : 0,\n latestVersion: typeof record.latestVersion === \"string\" ? record.latestVersion : null,\n etag: typeof record.etag === \"string\" ? record.etag : null,\n };\n } catch {\n return { lastCheck: 0, latestVersion: null, etag: null };\n }\n}\n\nexport interface ReleaseAsset {\n name: string;\n url: string;\n}\n\nexport interface LatestRelease {\n version: string;\n tag: string;\n assets: Array<ReleaseAsset>;\n}\n\n/** Parse the GitHub `releases/latest` response into the fields we need. */\nexport function parseLatestRelease(json: unknown): LatestRelease | null {\n if (!json || typeof json !== \"object\") {\n return null;\n }\n const record = json as Record<string, unknown>;\n const tag = typeof record.tag_name === \"string\" ? record.tag_name : undefined;\n if (!tag) {\n return null;\n }\n const assets: Array<ReleaseAsset> = [];\n if (Array.isArray(record.assets)) {\n for (const item of record.assets) {\n if (item && typeof item === \"object\") {\n const asset = item as Record<string, unknown>;\n if (typeof asset.name === \"string\" && typeof asset.browser_download_url === \"string\") {\n assets.push({ name: asset.name, url: asset.browser_download_url });\n }\n }\n }\n }\n return { version: versionFromTag(tag), tag, assets };\n}\n\n/** Find a checksum line for `fileName` in a `sha256sum`-style SHA256SUMS file. */\nexport function checksumFor(sumsText: string, fileName: string): string | undefined {\n for (const line of sumsText.split(/\\r?\\n/)) {\n const match = line.trim().match(/^([0-9a-fA-F]{64})\\s+\\*?(.+)$/);\n if (match?.[1] && match[2]?.trim() === fileName) {\n return match[1].toLowerCase();\n }\n }\n return undefined;\n}\n\n/**\n * Resolve the per-OS cache directory (no deps). Mirrors env-paths conventions:\n * Windows -> %LOCALAPPDATA%, macOS -> ~/Library/Caches, else $XDG_CACHE_HOME||~/.cache.\n */\nexport function resolveCacheDir(\n env: Record<string, string | undefined>,\n platform: string,\n homedir: string,\n join: (...parts: string[]) => string,\n): string {\n if (platform === \"win32\") {\n const base = env.LOCALAPPDATA || join(homedir, \"AppData\", \"Local\");\n return join(base, \"hoopilot\");\n }\n if (platform === \"darwin\") {\n return join(homedir, \"Library\", \"Caches\", \"hoopilot\");\n }\n const base = env.XDG_CACHE_HOME || join(homedir, \".cache\");\n return join(base, \"hoopilot\");\n}\n\n/** Stable redirect URL that downloads an asset from the latest release. */\nexport function latestDownloadUrl(asset: string): string {\n return `https://github.com/${REPO}/releases/latest/download/${asset}`;\n}\n\n/** GitHub REST endpoint for the latest release. */\nexport function latestReleaseApiUrl(): string {\n return `https://api.github.com/repos/${REPO}/releases/latest`;\n}\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["readFileSync","optionValue","encodeSse","outputText","parseJsonObject","createHash","chmodSync","mkdirSync","renameSync","rmSync","writeFileSync","dirname","join","homedir","join","base","REQUEST_TIMEOUT_MS","join","mkdirSync","createHash","rmSync","renameSync","chmodSync","writeFileSync","dirname","main","args","logger","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/auth-store.ts","../src/auth.ts","../src/copilot.ts","../src/github-device.ts","../src/logger.ts","../src/server.ts","../src/openai.ts","../src/anthropic.ts","../src/dashboard.ts","../src/metrics.ts","../src/version.ts","../src/update.ts","../src/update-core.ts"],"sourcesContent":["#!/usr/bin/env bun\n\nimport { spawn } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { CopilotAuthError, DEFAULT_COPILOT_API_BASE_URL, STORED_TOKEN_TTL_MS } from \"./auth\";\nimport { authStorePath, writeStoredCopilotAuth } from \"./auth-store\";\nimport { main as codexxMain } from \"./codexx\";\nimport {\n ALLOWED_COPILOT_API_HOSTS,\n applyCopilotHeaders,\n CopilotClient,\n normalizeCopilotUsage,\n parseRateLimitHeaders,\n} from \"./copilot\";\nimport {\n type GithubCopilotDeviceLoginOptions,\n type GithubCopilotDeviceLoginResult,\n githubCopilotDeviceLogin,\n} from \"./github-device\";\nimport { createHoopilotLogger, noopLogger, parseLogFormat, parseLogLevel } from \"./logger\";\nimport { startHoopilotServer } from \"./server\";\nimport type {\n CopilotAccess,\n CopilotQuota,\n CopilotUsage,\n FetchLike,\n GithubRateLimit,\n HoopilotLogger,\n HoopilotServerOptions,\n Logger,\n} from \"./types\";\nimport { cleanupOldBinary, maybeNotifyUpdate, runUpdate } from \"./update\";\nimport {\n envValue,\n errorMessage,\n isTrustedTokenBaseUrl,\n modelIdsFromResponse,\n parseStreamingProxyMode,\n trimTrailingSlash,\n truncatedResponseText,\n} from \"./util\";\nimport { getVersion, IS_STANDALONE_BINARY } from \"./version\";\n\ninterface ParsedArgs extends HoopilotServerOptions {\n help?: boolean;\n noUpdateCheck?: boolean;\n printToken?: boolean;\n version?: boolean;\n}\n\ntype DeviceLogin = (\n options: GithubCopilotDeviceLoginOptions,\n) => Promise<GithubCopilotDeviceLoginResult>;\n\ninterface RunLoginOptions extends HoopilotServerOptions {\n deviceLogin?: DeviceLogin;\n printToken?: boolean;\n}\n\ninterface VerifyCopilotOAuthTokenOptions {\n copilotApiBaseUrl?: string;\n env?: NodeJS.ProcessEnv;\n fetch?: FetchLike;\n}\n\nexport async function main(argv = Bun.argv.slice(2)): Promise<void> {\n // Clear any leftover \".old\" binary from a prior Windows self-update.\n cleanupOldBinary();\n\n const command = argv[0];\n if (command === \"update\" || command === \"upgrade\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n const logger = commandLogger(args, command);\n await runUpdate(await getVersion(), logger);\n return;\n }\n if (command === \"codexx\") {\n await codexxMain(argv.slice(1), process.env);\n return;\n }\n if (command === \"login\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n args.logger = commandLogger(args, \"login\", args.printToken ? process.stderr : undefined);\n await runLogin(args);\n return;\n }\n if (command === \"models\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n args.logger = commandLogger(args, \"models\");\n await runModels(args);\n return;\n }\n if (command === \"usage\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (await printMetaOption(args)) {\n return;\n }\n args.logger = commandLogger(args, \"usage\");\n await runUsage(args);\n return;\n }\n\n const args = withRuntimeEnv(parseArgs(argv));\n if (await printMetaOption(args)) {\n return;\n }\n\n const logger = commandLogger(args, \"serve\");\n args.logger = logger;\n const started = startHoopilotServer(args);\n logger.info(\n {\n baseUrl: `${started.url}/v1`,\n event: \"server.started\",\n url: started.url,\n },\n \"hoopilot server started\",\n );\n\n if (!args.noUpdateCheck) {\n // Non-blocking: prints a notice from the previous check and refreshes the\n // cache in the background. The running server keeps the refresh alive.\n // Env-based disabling (HOOPILOT_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER, CI, …)\n // is handled centrally by isUpdateCheckDisabled inside maybeNotifyUpdate.\n void maybeNotifyUpdate(\n await getVersion(),\n IS_STANDALONE_BINARY ? \"binary\" : \"npm\",\n logger.child({ component: \"update\" }),\n );\n }\n}\n\nasync function printMetaOption(args: ParsedArgs): Promise<boolean> {\n if (args.help) {\n console.log(helpText(await getVersion()));\n return true;\n }\n if (args.version) {\n console.log(await getVersion());\n return true;\n }\n return false;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const args: ParsedArgs = {};\n const rest = [...argv];\n if (rest[0] === \"serve\") {\n rest.shift();\n }\n\n while (rest.length > 0) {\n const arg = rest.shift();\n if (!arg) {\n continue;\n }\n if (arg === \"--help\" || arg === \"-h\") {\n args.help = true;\n continue;\n }\n if (arg === \"--version\" || arg === \"-v\") {\n args.version = true;\n continue;\n }\n if (arg === \"--allow-unauthenticated\") {\n args.allowUnauthenticated = true;\n continue;\n }\n if (arg === \"--no-update-check\") {\n args.noUpdateCheck = true;\n continue;\n }\n if (arg === \"--print-key\" || arg === \"--print-token\") {\n args.printToken = true;\n continue;\n }\n\n if (!arg.startsWith(\"-\")) {\n throw new Error(`Unknown argument: ${arg}.`);\n }\n\n const [name, inlineValue] = splitOption(arg);\n switch (name) {\n case \"--api-key\":\n args.apiKey = optionValue(name, inlineValue, rest);\n break;\n case \"--api-key-file\":\n args.apiKey = readApiKeyFile(optionValue(name, inlineValue, rest));\n break;\n case \"--auth-file\":\n args.authStorePath = optionValue(name, inlineValue, rest);\n break;\n case \"--copilot-api-base-url\":\n args.copilotApiBaseUrl = optionValue(name, inlineValue, rest);\n break;\n case \"--log-format\":\n args.logFormat = parseLogFormat(optionValue(name, inlineValue, rest));\n break;\n case \"--log-level\":\n args.logLevel = parseLogLevel(optionValue(name, inlineValue, rest));\n break;\n case \"--stream-mode\":\n args.streamingProxyMode = parseStreamingProxyMode(optionValue(name, inlineValue, rest));\n break;\n case \"--host\":\n args.host = optionValue(name, inlineValue, rest);\n break;\n case \"--port\":\n case \"-p\": {\n const value = optionValue(name, inlineValue, rest);\n args.port = Number(value);\n if (!Number.isInteger(args.port) || args.port <= 0 || args.port > 65_535) {\n throw new Error(`Invalid port: ${value}.`);\n }\n break;\n }\n default:\n throw new Error(`Unknown option: ${name}.`);\n }\n }\n\n return args;\n}\n\nfunction optionValue(name: string, inlineValue: string | undefined, rest: string[]): string {\n const value = inlineValue ?? rest.shift();\n if (!value) {\n throw new Error(`Missing value for ${name}.`);\n }\n return value;\n}\n\nfunction splitOption(arg: string): [string, string | undefined] {\n const separator = arg.indexOf(\"=\");\n if (separator === -1) {\n return [arg, undefined];\n }\n return [arg.slice(0, separator), arg.slice(separator + 1)];\n}\n\nfunction readApiKeyFile(path: string): string {\n const value = readFileSync(path, \"utf8\").trim();\n if (!value) {\n throw new Error(`API key file is empty: ${path}.`);\n }\n return value;\n}\n\nexport async function runLogin(options: RunLoginOptions = {}): Promise<void> {\n const logger = options.logger?.child({ component: \"auth\" }) ?? noopLogger;\n const status = loginStatusLogger(Boolean(options.printToken));\n logger.debug({ event: \"auth.login.started\" }, \"starting github copilot browser login\");\n status.info(\"Starting GitHub Copilot browser login...\");\n const deviceLogin = options.deviceLogin ?? githubCopilotDeviceLogin;\n const login = await deviceLogin({\n env: options.env,\n logger: status,\n openBrowser: openBrowserBestEffort,\n });\n\n status.info(\"Checking GitHub Copilot access...\");\n const access = await verifyCopilotOAuthToken(login.token, options);\n logger.debug(\n { apiBaseUrl: access.apiBaseUrl, event: \"auth.login.verified\" },\n \"github copilot oauth token verified\",\n );\n const path = options.authStorePath ?? authStorePath(options.env);\n writeStoredCopilotAuth(\n {\n apiBaseUrl: access.apiBaseUrl,\n githubDomain: login.domain,\n source: \"github-device-oauth\",\n token: login.token,\n },\n path,\n );\n logger.debug({ authStorePath: path, event: \"auth.login.stored\" }, \"copilot credential stored\");\n status.info(`Copilot OAuth credential stored at ${path}`);\n status.info(\"Copilot authentication ready.\");\n if (options.printToken) {\n console.log(login.token);\n }\n}\n\nexport async function runModels(options: HoopilotServerOptions = {}): Promise<string[]> {\n const logger = options.logger?.child({ component: \"models\" }) ?? noopLogger;\n logger.debug({ event: \"models.list.started\" }, \"fetching github copilot models\");\n\n const response = await new CopilotClient(options).models();\n if (!response.ok) {\n await throwForCopilotResponse(response, \"GitHub Copilot API model list\");\n }\n\n const ids = modelIdsFromResponse(await response.json().catch(() => undefined));\n if (ids.length === 0) {\n throw new Error(\"GitHub Copilot API returned no model IDs.\");\n }\n\n logger.debug(\n { count: ids.length, event: \"models.list.succeeded\" },\n \"github copilot models fetched\",\n );\n for (const id of ids) {\n console.log(id);\n }\n return ids;\n}\n\nexport async function runUsage(options: HoopilotServerOptions = {}): Promise<CopilotUsage> {\n const logger = options.logger?.child({ component: \"usage\" }) ?? noopLogger;\n logger.debug({ event: \"usage.fetch.started\" }, \"fetching github copilot quota\");\n\n const response = await new CopilotClient(options).usage();\n if (!response.ok) {\n await throwForCopilotResponse(response, \"GitHub Copilot usage request\");\n }\n\n const rateLimit = parseRateLimitHeaders(response.headers);\n const usage = normalizeCopilotUsage(await response.json().catch(() => ({})));\n logger.debug(\n { event: \"usage.fetch.succeeded\", plan: usage.plan },\n \"github copilot quota fetched\",\n );\n for (const line of formatCopilotUsage(usage)) {\n console.log(line);\n }\n if (rateLimit) {\n console.log(formatGithubRateLimit(rateLimit));\n }\n return usage;\n}\n\nfunction formatGithubRateLimit(rateLimit: GithubRateLimit): string {\n const parts: string[] = [];\n if (rateLimit.remaining !== undefined && rateLimit.limit !== undefined) {\n parts.push(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);\n } else if (rateLimit.remaining !== undefined) {\n parts.push(`${rateLimit.remaining} requests remaining`);\n } else if (rateLimit.used !== undefined) {\n parts.push(`${rateLimit.used} requests used`);\n }\n if (rateLimit.resetEpochSeconds !== undefined) {\n parts.push(`resets ${new Date(rateLimit.resetEpochSeconds * 1000).toISOString()}`);\n }\n if (rateLimit.retryAfterSeconds !== undefined) {\n parts.push(`retry after ${rateLimit.retryAfterSeconds}s`);\n }\n const detail = parts.length > 0 ? parts.join(\", \") : \"n/a\";\n const resource =\n rateLimit.resource && rateLimit.resource !== \"unknown\" ? ` (${rateLimit.resource})` : \"\";\n return `GitHub API rate limit${resource}: ${detail}`;\n}\n\nfunction formatCopilotUsage(usage: CopilotUsage): string[] {\n const lines: string[] = [];\n if (usage.plan) {\n lines.push(`Plan: ${usage.plan}`);\n }\n if (usage.quotaResetDate) {\n lines.push(`Quota resets: ${usage.quotaResetDate}`);\n }\n\n const order = [\"premium_interactions\", \"chat\", \"completions\"];\n const names = Object.keys(usage.quotas).sort(\n (a, b) => quotaRank(order, a) - quotaRank(order, b) || a.localeCompare(b),\n );\n for (const name of names) {\n const quota = usage.quotas[name];\n if (quota) {\n lines.push(`${quotaLabel(name)}: ${formatQuota(quota)}`);\n }\n }\n if (lines.length === 0) {\n lines.push(\"No GitHub Copilot quota information available for this account.\");\n }\n return lines;\n}\n\nfunction quotaRank(order: string[], name: string): number {\n const index = order.indexOf(name);\n return index === -1 ? order.length : index;\n}\n\nfunction quotaLabel(name: string): string {\n switch (name) {\n case \"premium_interactions\":\n return \"Premium requests\";\n case \"chat\":\n return \"Chat\";\n case \"completions\":\n return \"Completions\";\n default:\n return name;\n }\n}\n\nfunction formatQuota(quota: CopilotQuota): string {\n if (quota.unlimited) {\n return \"unlimited\";\n }\n const parts: string[] = [];\n if (quota.used !== undefined && quota.entitlement !== undefined) {\n parts.push(`${roundQuota(quota.used)}/${roundQuota(quota.entitlement)} used`);\n } else if (quota.remaining !== undefined) {\n parts.push(`${roundQuota(quota.remaining)} remaining`);\n }\n if (quota.percentRemaining !== undefined) {\n parts.push(`${roundQuota(quota.percentRemaining)}% remaining`);\n }\n if (quota.overageCount) {\n parts.push(`${roundQuota(quota.overageCount)} overage`);\n }\n return parts.length > 0 ? parts.join(\", \") : \"n/a\";\n}\n\nfunction roundQuota(value: number): number {\n return Number.isInteger(value) ? value : Math.round(value * 10) / 10;\n}\n\nexport async function verifyCopilotOAuthToken(\n token: string,\n options: VerifyCopilotOAuthTokenOptions = {},\n): Promise<CopilotAccess> {\n const apiBaseUrl = trimTrailingSlash(\n options.copilotApiBaseUrl ??\n envValue(options.env?.COPILOT_API_BASE_URL) ??\n DEFAULT_COPILOT_API_BASE_URL,\n );\n const allowUnsafeUpstream = envValue(options.env?.HOOPILOT_ALLOW_UNSAFE_UPSTREAM) === \"1\";\n if (!isTrustedTokenBaseUrl(apiBaseUrl, ALLOWED_COPILOT_API_HOSTS, allowUnsafeUpstream)) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to an untrusted Copilot API host: ${apiBaseUrl}`,\n );\n }\n const fetcher = options.fetch ?? fetch;\n const response = await fetcher(`${apiBaseUrl}/models`, {\n headers: applyCopilotHeaders(new Headers(), token),\n method: \"GET\",\n });\n\n if (!response.ok) {\n await throwForCopilotResponse(response, \"GitHub Copilot API verification\");\n }\n\n return {\n apiBaseUrl,\n expiresAtMs: Date.now() + STORED_TOKEN_TTL_MS,\n source: \"github-copilot-oauth\",\n token,\n };\n}\n\n/** Throw a labeled error for a failed Copilot response, mapping 401/403 to {@link CopilotAuthError}. */\nasync function throwForCopilotResponse(response: Response, label: string): Promise<never> {\n const message = `${label} failed with ${response.status}: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\n}\n\ntype BrowserOpenerChild = {\n on(event: \"error\", listener: (error: Error) => void): unknown;\n unref(): void;\n};\n\ntype BrowserOpenerSpawn = (\n command: string,\n args: string[],\n options: {\n detached: true;\n stdio: \"ignore\";\n },\n) => BrowserOpenerChild;\n\nexport function openBrowserBestEffort(url: string, spawnOpener: BrowserOpenerSpawn = spawn): void {\n const platform = process.platform;\n const command = platform === \"win32\" ? \"cmd\" : platform === \"darwin\" ? \"open\" : \"xdg-open\";\n const args = platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n try {\n const child = spawnOpener(command, args, {\n detached: true,\n stdio: \"ignore\",\n });\n child.on(\"error\", () => {\n // The device login code and URL were already printed.\n });\n child.unref();\n } catch {\n // The device login code and URL were already printed.\n }\n}\n\nfunction withRuntimeEnv(args: ParsedArgs): ParsedArgs {\n return { ...args, env: process.env };\n}\n\nfunction commandLogger(\n args: ParsedArgs,\n command: string,\n stream?: { write(message: string): unknown },\n): HoopilotLogger {\n return createHoopilotLogger({\n env: args.env,\n format: args.logFormat,\n level: args.logLevel,\n stream,\n }).child({ command, component: \"cli\" });\n}\n\nfunction loginStatusLogger(writeSecretsToStdout: boolean): Logger {\n if (writeSecretsToStdout) {\n return {\n error: (message) => console.error(message),\n info: (message) => console.error(message),\n warn: (message) => console.error(message),\n };\n }\n return {\n error: (message) => console.error(message),\n info: (message) => console.log(message),\n warn: (message) => console.warn(message),\n };\n}\n\nfunction helpText(version: string): string {\n return `hoopilot ${version}\n\nOpenAI-compatible proxy for GitHub Copilot.\n\nUsage:\n hoopilot [serve] [options]\n hoopilot codexx [codex options] [prompt]\n hoopilot login [options]\n hoopilot models [options]\n hoopilot usage [options]\n hoopilot update\n npx @openhoo/hoopilot [options]\n\nCommands:\n serve Start the proxy server (default)\n codexx Run Codex through the local Hoopilot server\n login Sign in through GitHub OAuth in a browser and verify Copilot access\n models List available GitHub Copilot model IDs\n usage Show GitHub Copilot quota and premium-request usage\n update, upgrade Update hoopilot to the latest release\n\nWhile the server runs, GET /metrics exposes Prometheus metrics (request counts,\ntoken usage, latency) and GET /v1/usage returns those metrics plus live Copilot\nquota as JSON. Open GET /dashboard in a browser for a live usage and status view.\n\nOptions:\n -p, --port <port> Port to listen on. Default: 4141\n --host <host> Host to listen on. Default: 127.0.0.1\n --api-key <key> Require clients to send Authorization: Bearer <key> or x-api-key: <key>\n Non-loopback binds require at least 24 characters.\n --api-key-file <path> Read the local API key from a file instead of argv\n --auth-file <path> OAuth credential store path\n --copilot-api-base-url <url> Copilot API base URL override\n --print-key Login: print the received OAuth token to stdout\n --log-level <level> trace, debug, info, warn, error, fatal, or silent\n --log-format <format> json or pretty. Default: pretty\n --stream-mode <mode> auto, live, or buffer. Auto buffers Windows standalone streams.\n --no-update-check Do not check GitHub for a newer release\n --allow-unauthenticated Allow non-loopback bind without --api-key\n -h, --help Show help\n -v, --version Show version\n\nEnvironment:\n HOOPILOT_API_KEY\n HOOPILOT_AUTH_FILE\n HOOPILOT_GITHUB_CLIENT_ID\n HOOPILOT_GITHUB_DOMAIN\n HOOPILOT_LOG_FORMAT json or pretty. Default: pretty\n HOOPILOT_LOG_LEVEL trace, debug, info, warn, error, fatal, or silent\n HOOPILOT_STREAM_MODE auto, live, or buffer\n COPILOT_API_BASE_URL\n HOOPILOT_GITHUB_API_BASE_URL GitHub REST base for the usage/quota lookup. Default: https://api.github.com\n HOOPILOT_ALLOW_UNSAFE_UPSTREAM Set to 1 to allow nonstandard HTTPS token hosts\n HOOPILOT_NO_UPDATE_CHECK Set to disable update checks (also NO_UPDATE_NOTIFIER)\n`;\n}\n\nif (import.meta.main) {\n main().catch((error: unknown) => {\n console.error(errorMessage(error));\n process.exit(1);\n });\n}\n","import { chmodSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { asRecord, envValue } from \"./util\";\n\nexport class StoredCopilotAuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StoredCopilotAuthError\";\n }\n}\n\nexport interface StoredCopilotAuth {\n apiBaseUrl?: string;\n createdAt?: string;\n githubDomain?: string;\n source?: string;\n token: string;\n}\n\nexport function authStorePath(env: NodeJS.ProcessEnv = process.env): string {\n const explicit = envValue(env.HOOPILOT_AUTH_FILE);\n if (explicit) {\n return explicit;\n }\n\n const xdg = envValue(env.XDG_CONFIG_HOME);\n if (xdg) {\n return join(xdg, \"hoopilot\", \"auth.json\");\n }\n const appdata = envValue(env.APPDATA);\n if (appdata) {\n return join(appdata, \"hoopilot\", \"auth.json\");\n }\n const home = envValue(env.HOME);\n if (!home) {\n throw new StoredCopilotAuthError(\n \"Cannot resolve Hoopilot auth file path without HOOPILOT_AUTH_FILE, XDG_CONFIG_HOME, APPDATA, or HOME.\",\n );\n }\n const base = join(home, \".config\");\n return join(base, \"hoopilot\", \"auth.json\");\n}\n\nexport function readStoredCopilotAuth(path = authStorePath()): StoredCopilotAuth | undefined {\n let text: string;\n try {\n text = readFileSync(path, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw new StoredCopilotAuthError(`Could not read Hoopilot auth file at ${path}.`);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new StoredCopilotAuthError(\n `Hoopilot auth file at ${path} is not valid JSON. Run \\`hoopilot login\\` to replace it.`,\n );\n }\n\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new StoredCopilotAuthError(`Hoopilot auth file at ${path} must contain a JSON object.`);\n }\n const record = asRecord(parsed);\n const token = typeof record.token === \"string\" ? record.token.trim() : \"\";\n if (!token) {\n throw new StoredCopilotAuthError(`Hoopilot auth file at ${path} does not contain a token.`);\n }\n return {\n apiBaseUrl: typeof record.apiBaseUrl === \"string\" ? record.apiBaseUrl : undefined,\n createdAt: typeof record.createdAt === \"string\" ? record.createdAt : undefined,\n githubDomain: typeof record.githubDomain === \"string\" ? record.githubDomain : undefined,\n source: typeof record.source === \"string\" ? record.source : undefined,\n token,\n };\n}\n\nexport function writeStoredCopilotAuth(auth: StoredCopilotAuth, path = authStorePath()): void {\n mkdirSync(dirname(path), { recursive: true });\n const data = `${JSON.stringify(\n {\n ...auth,\n createdAt: auth.createdAt ?? new Date().toISOString(),\n },\n null,\n 2,\n )}\\n`;\n // Write to a sibling temp file, then rename into place so a crash or full\n // disk mid-write can never leave a truncated credential file behind.\n const tmpPath = `${path}.${process.pid}.tmp`;\n writeFileSync(tmpPath, data, { mode: 0o600 });\n try {\n renameSync(tmpPath, path);\n } catch (error) {\n // Don't leave the orphaned temp credential behind if the rename fails.\n try {\n rmSync(tmpPath, { force: true });\n } catch {\n // best-effort cleanup; surface the original failure below\n }\n throw error;\n }\n try {\n chmodSync(path, 0o600);\n } catch {\n // chmod is best-effort on Windows.\n }\n}\n","import {\n readStoredCopilotAuth,\n type StoredCopilotAuth,\n StoredCopilotAuthError,\n} from \"./auth-store\";\nimport type { CopilotAccess, CopilotAuthOptions } from \"./types\";\nimport { envValue, trimTrailingSlash } from \"./util\";\n\nexport const DEFAULT_COPILOT_API_BASE_URL = \"https://api.githubcopilot.com\";\nconst REFRESH_SKEW_MS = 60_000;\nexport const STORED_TOKEN_TTL_MS = 10 * 60_000;\n\nexport class CopilotAuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CopilotAuthError\";\n }\n}\n\nexport class CopilotAuth {\n readonly #authStorePath?: string;\n readonly #copilotApiBaseUrl: string;\n readonly #hasCopilotApiBaseUrlOverride: boolean;\n #cachedAccess?: CopilotAccess;\n\n constructor(options: CopilotAuthOptions = {}) {\n const envAuthStorePath = envValue(options.env?.HOOPILOT_AUTH_FILE);\n const envCopilotApiBaseUrl = envValue(options.env?.COPILOT_API_BASE_URL);\n this.#authStorePath = options.authStorePath ?? envAuthStorePath;\n this.#hasCopilotApiBaseUrlOverride = Boolean(options.copilotApiBaseUrl ?? envCopilotApiBaseUrl);\n this.#copilotApiBaseUrl = trimTrailingSlash(\n options.copilotApiBaseUrl ?? envCopilotApiBaseUrl ?? DEFAULT_COPILOT_API_BASE_URL,\n );\n }\n\n async getAccess(): Promise<CopilotAccess> {\n if (this.#cachedAccess && this.#cachedAccess.expiresAtMs - REFRESH_SKEW_MS > Date.now()) {\n return this.#cachedAccess;\n }\n\n let stored: StoredCopilotAuth | undefined;\n try {\n stored = readStoredCopilotAuth(this.#authStorePath);\n } catch (error) {\n if (error instanceof StoredCopilotAuthError) {\n throw new CopilotAuthError(error.message);\n }\n throw error;\n }\n if (stored) {\n this.#cachedAccess = {\n apiBaseUrl: trimTrailingSlash(\n this.#hasCopilotApiBaseUrlOverride\n ? this.#copilotApiBaseUrl\n : (stored.apiBaseUrl ?? this.#copilotApiBaseUrl),\n ),\n expiresAtMs: Date.now() + STORED_TOKEN_TTL_MS,\n source: \"github-copilot-oauth\",\n token: stored.token,\n };\n return this.#cachedAccess;\n }\n\n throw new CopilotAuthError(\n \"No GitHub Copilot OAuth credential found. Run `hoopilot login` to sign in through your browser.\",\n );\n }\n}\n","import { CopilotAuth } from \"./auth\";\nimport type {\n CopilotAuthOptions,\n CopilotQuota,\n CopilotUsage,\n FetchLike,\n GithubRateLimit,\n JsonObject,\n} from \"./types\";\nimport {\n asRecord,\n envValue,\n firstNumber,\n isTrustedTokenBaseUrl,\n removeUndefined,\n trimTrailingSlash,\n} from \"./util\";\n\n/** Default GitHub REST host that serves the `copilot_internal/user` quota route. */\nexport const DEFAULT_GITHUB_API_BASE_URL = \"https://api.github.com\";\nexport const ALLOWED_COPILOT_API_HOSTS = [\"api.githubcopilot.com\"] as const;\nconst ALLOWED_GITHUB_API_HOSTS = [\"api.github.com\"] as const;\n\n/**\n * API version sent to the GitHub `copilot_internal` endpoints. This is a\n * different surface from the Copilot completions API (`x-github-api-version`\n * `2026-06-01`), so it is pinned separately and bumped independently.\n */\nexport const COPILOT_USAGE_API_VERSION = \"2025-04-01\";\n\n// Editor-identity strings spoofed to GitHub Copilot. Deliberately pinned (not\n// derived from the package version) and shared by both header builders below.\nconst EDITOR_PLUGIN_VERSION = \"hoopilot/0.1.0\";\nconst EDITOR_VERSION = \"Hoopilot/0.1.0\";\nconst HOOPILOT_USER_AGENT = \"hoopilot/0.1.0\";\nconst DEFAULT_UPSTREAM_TIMEOUT_MS = 120_000;\nconst DEFAULT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS = 120_000;\n\nexport class CopilotUpstreamTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CopilotUpstreamTimeoutError\";\n }\n}\n\n/**\n * Set the GitHub Copilot API request headers on `headers`, leaving any\n * caller-provided `accept` intact. Single source of truth for the pinned\n * integration id, editor/plugin versions, and API version so the proxy client\n * and the login-time verification call cannot drift apart.\n */\nexport function applyCopilotHeaders(headers: Headers, token: string): Headers {\n headers.set(\"accept\", headers.get(\"accept\") ?? \"application/json\");\n headers.set(\"authorization\", `Bearer ${token}`);\n headers.set(\"copilot-integration-id\", \"vscode-chat\");\n headers.set(\"editor-plugin-version\", EDITOR_PLUGIN_VERSION);\n headers.set(\"editor-version\", EDITOR_VERSION);\n headers.set(\"openai-intent\", \"conversation-panel\");\n headers.set(\"user-agent\", HOOPILOT_USER_AGENT);\n headers.set(\"x-github-api-version\", \"2026-06-01\");\n return headers;\n}\n\n/**\n * Set headers for the GitHub REST `copilot_internal/user` quota call. This host\n * is `api.github.com` (not the Copilot API host) and expects the `token` auth\n * scheme with the raw stored OAuth token — not the `Bearer` scheme used by the\n * Copilot completion endpoints.\n */\nexport function applyGithubApiHeaders(headers: Headers, token: string): Headers {\n headers.set(\"accept\", headers.get(\"accept\") ?? \"application/json\");\n headers.set(\"authorization\", `token ${token}`);\n headers.set(\"editor-plugin-version\", EDITOR_PLUGIN_VERSION);\n headers.set(\"editor-version\", EDITOR_VERSION);\n headers.set(\"user-agent\", HOOPILOT_USER_AGENT);\n headers.set(\"x-github-api-version\", COPILOT_USAGE_API_VERSION);\n return headers;\n}\n\n/**\n * Parse the GitHub REST `x-ratelimit-*` headers (plus `retry-after`) off a\n * response into a {@link GithubRateLimit}. `api.github.com` returns these on\n * every reply, so the proxy reads its GitHub API budget from the quota call it\n * already makes — no extra request is spent. Returns undefined when the response\n * carries no rate-limit headers (for example the Copilot completion host, which\n * does not emit them today) so callers record nothing rather than a phantom row.\n */\nexport function parseRateLimitHeaders(\n headers: Headers,\n nowMs: number = Date.now(),\n): GithubRateLimit | undefined {\n const limit = headerInt(headers, \"x-ratelimit-limit\");\n const remaining = headerInt(headers, \"x-ratelimit-remaining\");\n const used = headerInt(headers, \"x-ratelimit-used\");\n const resetEpochSeconds = headerInt(headers, \"x-ratelimit-reset\");\n const retryAfterSeconds = headerInt(headers, \"retry-after\");\n if (\n limit === undefined &&\n remaining === undefined &&\n used === undefined &&\n resetEpochSeconds === undefined &&\n retryAfterSeconds === undefined\n ) {\n return undefined;\n }\n return removeUndefined({\n limit,\n observedAtMs: nowMs,\n remaining,\n resetEpochSeconds,\n resource: headers.get(\"x-ratelimit-resource\")?.trim() || \"unknown\",\n retryAfterSeconds,\n used,\n });\n}\n\n// Parse a non-negative integer header (the rate-limit headers are all integers;\n// retry-after is integer seconds on GitHub's secondary limits). A missing or\n// malformed header yields undefined so it is simply omitted from the result.\nfunction headerInt(headers: Headers, name: string): number | undefined {\n const raw = headers.get(name);\n if (raw === null) {\n return undefined;\n }\n const value = Number.parseInt(raw.trim(), 10);\n return Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nexport class CopilotClient {\n readonly #auth: CopilotAuth;\n readonly #allowUnsafeUpstream: boolean;\n readonly #fetch: FetchLike;\n readonly #githubApiBaseUrl: string;\n readonly #upstreamStreamIdleTimeoutMs: number;\n readonly #upstreamTimeoutMs: number;\n\n constructor(options: CopilotAuthOptions = {}) {\n this.#auth = new CopilotAuth(options);\n this.#allowUnsafeUpstream = envValue(options.env?.HOOPILOT_ALLOW_UNSAFE_UPSTREAM) === \"1\";\n this.#fetch = options.fetch ?? fetch;\n this.#githubApiBaseUrl = trimTrailingSlash(\n options.githubApiBaseUrl ??\n envValue(options.env?.HOOPILOT_GITHUB_API_BASE_URL) ??\n DEFAULT_GITHUB_API_BASE_URL,\n );\n this.#upstreamTimeoutMs = parseTimeoutMs(\n options.upstreamTimeoutMs,\n options.env?.HOOPILOT_UPSTREAM_TIMEOUT_MS,\n DEFAULT_UPSTREAM_TIMEOUT_MS,\n \"HOOPILOT_UPSTREAM_TIMEOUT_MS\",\n );\n this.#upstreamStreamIdleTimeoutMs = parseTimeoutMs(\n options.upstreamStreamIdleTimeoutMs,\n options.env?.HOOPILOT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS,\n DEFAULT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS,\n \"HOOPILOT_UPSTREAM_STREAM_IDLE_TIMEOUT_MS\",\n );\n }\n\n /**\n * Fetch the Copilot account's quota / premium-request usage from the GitHub\n * REST `copilot_internal/user` endpoint. The stored device-flow OAuth token is\n * accepted directly here — no Copilot token exchange is required to read quota.\n */\n async usage(signal?: AbortSignal): Promise<Response> {\n // The quota call sends the raw, long-lived OAuth token. Never transmit it\n // over plaintext to a non-loopback host, so a misconfigured base URL cannot\n // exfiltrate the credential.\n if (\n !isTrustedTokenBaseUrl(\n this.#githubApiBaseUrl,\n ALLOWED_GITHUB_API_HOSTS,\n this.#allowUnsafeUpstream,\n )\n ) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to an untrusted GitHub API host: ${this.#githubApiBaseUrl}`,\n );\n }\n const access = await this.#auth.getAccess();\n const headers = applyGithubApiHeaders(new Headers(), access.token);\n return this.#fetchWithTimeout(`${this.#githubApiBaseUrl}/copilot_internal/user`, {\n headers,\n method: \"GET\",\n signal,\n });\n }\n\n async chatCompletions(body: JsonObject, signal?: AbortSignal): Promise<Response> {\n return this.fetchCopilot(\"/chat/completions\", {\n body: JSON.stringify(body),\n headers: {\n \"content-type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n }\n\n async responses(body: string, signal?: AbortSignal): Promise<Response> {\n return this.fetchCopilot(\"/responses\", {\n body,\n headers: {\n \"content-type\": \"application/json\",\n },\n method: \"POST\",\n signal,\n });\n }\n\n async models(signal?: AbortSignal): Promise<Response> {\n return this.fetchCopilot(\"/models\", {\n headers: {\n accept: \"application/json\",\n },\n method: \"GET\",\n signal,\n });\n }\n\n async fetchCopilot(path: string, init: RequestInit): Promise<Response> {\n const access = await this.#auth.getAccess();\n if (\n !isTrustedTokenBaseUrl(\n access.apiBaseUrl,\n ALLOWED_COPILOT_API_HOSTS,\n this.#allowUnsafeUpstream,\n )\n ) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to an untrusted Copilot API host: ${access.apiBaseUrl}`,\n );\n }\n const headers = applyCopilotHeaders(new Headers(init.headers), access.token);\n\n return this.#fetchWithTimeout(`${access.apiBaseUrl}${path}`, {\n ...init,\n headers,\n });\n }\n\n async #fetchWithTimeout(input: string, init: RequestInit): Promise<Response> {\n const timeout = abortSignalWithTimeout(init.signal ?? undefined, this.#upstreamTimeoutMs);\n try {\n const response = await this.#fetch(input, {\n ...init,\n signal: timeout.signal,\n });\n return responseWithStreamIdleTimeout(response, this.#upstreamStreamIdleTimeoutMs, input);\n } catch (error) {\n if (timeout.timedOut()) {\n throw new CopilotUpstreamTimeoutError(\n `Copilot upstream request timed out after ${this.#upstreamTimeoutMs} ms before response headers arrived.`,\n );\n }\n throw error;\n } finally {\n timeout.cleanup();\n }\n }\n}\n\nfunction parseTimeoutMs(\n optionValue: number | undefined,\n envRaw: string | undefined,\n fallback: number,\n name: string,\n): number {\n const raw = optionValue ?? envValue(envRaw);\n if (raw === undefined) {\n return fallback;\n }\n const value = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`${name} must be a non-negative integer number of milliseconds.`);\n }\n return value;\n}\n\nfunction abortSignalWithTimeout(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { cleanup: () => void; signal: AbortSignal | undefined; timedOut: () => boolean } {\n if (timeoutMs === 0) {\n return { cleanup: () => {}, signal: parent, timedOut: () => false };\n }\n\n const controller = new AbortController();\n let timedOut = false;\n const timer = setTimeout(() => {\n if (controller.signal.aborted) {\n return;\n }\n timedOut = true;\n controller.abort(\n new CopilotUpstreamTimeoutError(`Copilot upstream request timed out after ${timeoutMs} ms.`),\n );\n }, timeoutMs);\n const onAbort = () => controller.abort(parent?.reason);\n if (parent?.aborted) {\n controller.abort(parent.reason);\n } else {\n parent?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n return {\n cleanup: () => {\n clearTimeout(timer);\n parent?.removeEventListener(\"abort\", onAbort);\n },\n signal: controller.signal,\n timedOut: () => timedOut,\n };\n}\n\nfunction responseWithStreamIdleTimeout(\n response: Response,\n idleTimeoutMs: number,\n input: string,\n): Response {\n if (!response.body || idleTimeoutMs === 0) {\n return response;\n }\n return new Response(streamWithIdleTimeout(response.body, idleTimeoutMs, input), {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\nfunction streamWithIdleTimeout(\n body: ReadableStream<Uint8Array>,\n idleTimeoutMs: number,\n input: string,\n): ReadableStream<Uint8Array> {\n const reader = body.getReader();\n let released = false;\n const release = () => {\n if (!released) {\n released = true;\n reader.releaseLock();\n }\n };\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const read = reader.read();\n read.catch(() => {});\n try {\n const result = await Promise.race([\n read,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(\n new CopilotUpstreamTimeoutError(\n `Copilot upstream stream was idle for ${idleTimeoutMs} ms while reading ${input}.`,\n ),\n );\n }, idleTimeoutMs);\n }),\n ]);\n if (timer) {\n clearTimeout(timer);\n }\n if (result.done) {\n controller.close();\n release();\n return;\n }\n controller.enqueue(result.value);\n } catch (error) {\n if (timer) {\n clearTimeout(timer);\n }\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n release();\n }\n },\n async cancel(reason) {\n try {\n await reader.cancel(reason);\n } finally {\n release();\n }\n },\n });\n}\n\n/**\n * Normalize a `copilot_internal/user` response into {@link CopilotUsage}. Handles\n * both the paid-plan shape (`quota_snapshots.{chat,completions,premium_interactions}`)\n * and the free-plan shape (`limited_user_quotas` remaining + `monthly_quotas`\n * allowance). `remaining` may be fractional and negative under permitted overage,\n * so `used` is derived as `max(0, entitlement - remaining)`.\n */\nexport function normalizeCopilotUsage(body: unknown): CopilotUsage {\n const record = asRecord(body);\n const quotas: Record<string, CopilotQuota> = {};\n\n const snapshots = asRecord(record.quota_snapshots);\n for (const [category, detail] of Object.entries(snapshots)) {\n quotas[category] = normalizeQuotaDetail(asRecord(detail));\n }\n\n if (Object.keys(quotas).length === 0) {\n const remaining = asRecord(record.limited_user_quotas);\n const monthly = asRecord(record.monthly_quotas);\n for (const category of new Set([...Object.keys(remaining), ...Object.keys(monthly)])) {\n const entitlement = numberOrUndefined(monthly[category]);\n const left = numberOrUndefined(remaining[category]);\n quotas[category] = removeUndefined({\n entitlement,\n percentRemaining:\n entitlement !== undefined && entitlement > 0 && left !== undefined\n ? (left / entitlement) * 100\n : undefined,\n remaining: left,\n used: usedFrom(entitlement, left),\n });\n }\n }\n\n return removeUndefined({\n accessTypeSku: stringOrUndefined(record.access_type_sku),\n chatEnabled: typeof record.chat_enabled === \"boolean\" ? record.chat_enabled : undefined,\n plan: stringOrUndefined(record.copilot_plan),\n quotaResetDate:\n stringOrUndefined(record.quota_reset_date) ??\n stringOrUndefined(record.quota_reset_date_utc) ??\n stringOrUndefined(record.limited_user_reset_date),\n quotas,\n });\n}\n\nfunction normalizeQuotaDetail(detail: JsonObject): CopilotQuota {\n const entitlement = numberOrUndefined(detail.entitlement);\n const overageCount = numberOrUndefined(detail.overage_count);\n const remaining =\n numberOrUndefined(detail.remaining) ?? numberOrUndefined(detail.quota_remaining);\n return removeUndefined({\n entitlement,\n hasQuota: typeof detail.has_quota === \"boolean\" ? detail.has_quota : undefined,\n overageCount,\n overageEntitlement: numberOrUndefined(detail.overage_entitlement),\n overagePermitted:\n typeof detail.overage_permitted === \"boolean\" ? detail.overage_permitted : undefined,\n percentRemaining: numberOrUndefined(detail.percent_remaining),\n quotaId: stringOrUndefined(detail.quota_id),\n quotaResetAt: stringOrUndefined(detail.quota_reset_at),\n remaining,\n timestampUtc: stringOrUndefined(detail.timestamp_utc),\n tokenBasedBilling:\n typeof detail.token_based_billing === \"boolean\" ? detail.token_based_billing : undefined,\n unlimited: typeof detail.unlimited === \"boolean\" ? detail.unlimited : undefined,\n used: usedFrom(entitlement, remaining, overageCount),\n });\n}\n\nfunction usedFrom(\n entitlement: number | undefined,\n remaining: number | undefined,\n overageCount?: number,\n): number | undefined {\n if (entitlement === undefined || remaining === undefined) {\n return undefined;\n }\n const base = entitlement - remaining;\n const overage = remaining === 0 ? (overageCount ?? 0) : 0;\n return Math.max(0, base + overage);\n}\n\n// Single-argument case of the shared firstNumber helper.\nconst numberOrUndefined = firstNumber;\n\nfunction stringOrUndefined(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n","import { setTimeout as sleep } from \"node:timers/promises\";\nimport type { FetchLike, Logger } from \"./types\";\nimport { envValue, truncatedResponseText } from \"./util\";\n\nexport const DEFAULT_GITHUB_COPILOT_CLIENT_ID = \"Ov23li8tweQw6odWQebz\";\nconst DEFAULT_GITHUB_DOMAIN = \"github.com\";\nconst DEVICE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst POLLING_SAFETY_MARGIN_MS = 3_000;\nconst REQUEST_TIMEOUT_MS = 15_000;\n\nexport interface GithubCopilotDeviceLoginOptions {\n clientId?: string;\n domain?: string;\n env?: NodeJS.ProcessEnv;\n fetch?: FetchLike;\n logger?: Logger;\n openBrowser?: (url: string) => void | Promise<void>;\n sleep?: (ms: number) => Promise<void>;\n}\n\nexport interface GithubCopilotDeviceLoginResult {\n domain: string;\n token: string;\n}\n\ninterface DeviceCodeResponse {\n device_code?: string;\n expires_in?: number;\n interval?: number;\n user_code?: string;\n verification_uri?: string;\n}\n\ninterface DeviceTokenResponse {\n access_token?: string;\n error?: string;\n error_description?: string;\n interval?: number;\n}\n\nexport async function githubCopilotDeviceLogin(\n options: GithubCopilotDeviceLoginOptions = {},\n): Promise<GithubCopilotDeviceLoginResult> {\n const env = options.env ?? process.env;\n const fetcher = options.fetch ?? fetch;\n const sleeper = options.sleep ?? sleep;\n const domain = normalizeDomain(\n options.domain ?? envValue(env.HOOPILOT_GITHUB_DOMAIN) ?? DEFAULT_GITHUB_DOMAIN,\n );\n const clientId =\n options.clientId ??\n envValue(env.HOOPILOT_GITHUB_CLIENT_ID) ??\n envValue(env.COPILOT_GITHUB_CLIENT_ID) ??\n DEFAULT_GITHUB_COPILOT_CLIENT_ID;\n\n const device = await requestDeviceCode(fetcher, domain, clientId);\n const verificationUrl = device.verification_uri;\n const userCode = device.user_code;\n const deviceCode = device.device_code;\n if (!verificationUrl || !userCode || !deviceCode) {\n throw new Error(\"GitHub device authorization response is missing required fields.\");\n }\n\n options.logger?.info(`First copy your one-time code: ${userCode}`);\n options.logger?.info(`Open ${verificationUrl} in your browser to authorize Hoopilot.`);\n await options.openBrowser?.(verificationUrl);\n\n return {\n domain,\n token: await pollForAccessToken(fetcher, sleeper, domain, clientId, {\n deviceCode,\n expiresIn: positiveSeconds(device.expires_in, 900),\n interval: positiveSeconds(device.interval, 5),\n }),\n };\n}\n\nasync function requestDeviceCode(\n fetcher: FetchLike,\n domain: string,\n clientId: string,\n): Promise<DeviceCodeResponse> {\n const response = await fetcher(`https://${domain}/login/device/code`, {\n body: JSON.stringify({\n client_id: clientId,\n scope: \"read:user\",\n }),\n headers: oauthHeaders(),\n method: \"POST\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (!response.ok) {\n throw new Error(\n `GitHub device authorization failed with ${response.status}: ${await truncatedResponseText(\n response,\n )}`,\n );\n }\n return parseJsonResponse<DeviceCodeResponse>(\n response,\n \"GitHub device authorization response was not valid JSON\",\n );\n}\n\nasync function pollForAccessToken(\n fetcher: FetchLike,\n sleeper: (ms: number) => Promise<void>,\n domain: string,\n clientId: string,\n device: { deviceCode: string; expiresIn: number; interval: number },\n): Promise<string> {\n let intervalMs = device.interval * 1000 + POLLING_SAFETY_MARGIN_MS;\n const deadline = Date.now() + device.expiresIn * 1000;\n\n while (Date.now() < deadline) {\n await sleeper(intervalMs);\n const response = await fetcher(`https://${domain}/login/oauth/access_token`, {\n body: JSON.stringify({\n client_id: clientId,\n device_code: device.deviceCode,\n grant_type: DEVICE_GRANT_TYPE,\n }),\n headers: oauthHeaders(),\n method: \"POST\",\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(\n `GitHub device token exchange failed with ${response.status}: ${await truncatedResponseText(\n response,\n )}`,\n );\n }\n\n const data = await parseJsonResponse<DeviceTokenResponse>(\n response,\n \"GitHub device token response was not valid JSON\",\n );\n if (data.access_token) {\n return data.access_token;\n }\n\n if (data.error === \"authorization_pending\") {\n continue;\n }\n if (data.error === \"slow_down\") {\n intervalMs =\n positiveSeconds(data.interval, device.interval + 5) * 1000 + POLLING_SAFETY_MARGIN_MS;\n continue;\n }\n if (data.error === \"expired_token\") {\n throw new Error(\"GitHub device login expired. Run `hoopilot login` again.\");\n }\n if (data.error === \"access_denied\") {\n throw new Error(\"GitHub device login was cancelled.\");\n }\n if (data.error) {\n throw new Error(data.error_description || `GitHub device login failed: ${data.error}`);\n }\n }\n\n throw new Error(\"GitHub device login timed out. Run `hoopilot login` again.\");\n}\n\nfunction oauthHeaders(): Headers {\n const headers = new Headers();\n headers.set(\"accept\", \"application/json\");\n headers.set(\"content-type\", \"application/json\");\n headers.set(\"user-agent\", \"hoopilot\");\n return headers;\n}\n\nfunction normalizeDomain(value: string): string {\n const raw = value.trim();\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(raw) ? raw : `https://${raw}`;\n let url: URL;\n try {\n url = new URL(withScheme);\n } catch {\n throw new Error(`Invalid GitHub domain: ${value}.`);\n }\n if (\n (url.protocol !== \"https:\" && url.protocol !== \"http:\") ||\n url.username ||\n url.password ||\n !url.hostname ||\n (url.pathname !== \"\" && url.pathname !== \"/\") ||\n url.search ||\n url.hash\n ) {\n throw new Error(`Invalid GitHub domain: ${value}. Provide only a hostname.`);\n }\n return url.host;\n}\n\nfunction positiveSeconds(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n\nasync function parseJsonResponse<T>(response: Response, context: string): Promise<T> {\n const text = await response.text();\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch {\n throw new Error(`${context}: ${text.slice(0, 500)}`);\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${context}: ${text.slice(0, 500)}`);\n }\n return value as T;\n}\n","import pino from \"pino\";\nimport pretty from \"pino-pretty\";\nimport type {\n HoopilotLogger,\n HoopilotLoggerOptions,\n LogFields,\n LogFormat,\n LogLevel,\n} from \"./types\";\nimport { envValue } from \"./util\";\n\nexport const DEFAULT_LOG_FORMAT: LogFormat = \"pretty\";\nexport const DEFAULT_LOG_LEVEL: LogLevel = \"info\";\n\nconst LOG_FORMATS = [\"json\", \"pretty\"] as const;\nconst LOG_LEVELS = [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\", \"silent\"] as const;\nconst REDACT_PATHS = [\n \"apiKey\",\n \"authorization\",\n \"cookie\",\n \"headers.authorization\",\n \"headers.Authorization\",\n \"headers.cookie\",\n \"headers.Cookie\",\n \"headers.x-api-key\",\n \"headers.X-Api-Key\",\n \"token\",\n \"*.apiKey\",\n \"*.authorization\",\n \"*.cookie\",\n \"*.token\",\n \"*.headers.authorization\",\n \"*.headers.Authorization\",\n \"*.headers.cookie\",\n \"*.headers.Cookie\",\n \"*.headers.x-api-key\",\n \"*.headers.X-Api-Key\",\n];\n\nexport const noopLogger: HoopilotLogger = {\n child: () => noopLogger,\n debug: () => {},\n error: () => {},\n fatal: () => {},\n info: () => {},\n trace: () => {},\n warn: () => {},\n};\n\nexport function createHoopilotLogger(options: HoopilotLoggerOptions = {}): HoopilotLogger {\n const env = options.env ?? process.env;\n const level = parseLogLevel(options.level ?? envValue(env.HOOPILOT_LOG_LEVEL));\n const format = parseLogFormat(options.format ?? envValue(env.HOOPILOT_LOG_FORMAT));\n const pinoOptions: pino.LoggerOptions = {\n base: {\n service: \"hoopilot\",\n ...options.base,\n },\n level,\n redact: {\n censor: \"[Redacted]\",\n paths: REDACT_PATHS,\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n };\n\n if (format === \"pretty\") {\n return asHoopilotLogger(\n pino(\n pinoOptions,\n pretty({\n // Probe the same sink we write to (stdout / fd 1), so colors are not\n // emitted into a redirected file when only stderr is a TTY. A custom\n // stream's TTY-ness is unknown, so default to no color there.\n colorize: options.colorize ?? (options.stream ? false : process.stdout.isTTY),\n destination: options.stream ?? 1,\n ignore: \"pid,hostname\",\n singleLine: true,\n translateTime: \"SYS:standard\",\n }),\n ),\n );\n }\n\n if (options.stream) {\n return asHoopilotLogger(pino(pinoOptions, options.stream as pino.DestinationStream));\n }\n return asHoopilotLogger(pino(pinoOptions));\n}\n\n// Cast pino's Logger to HoopilotLogger through a checked assignment, so a drift\n// in either type surfaces as a compile error here instead of being masked by an\n// unchecked `as` at each call site.\nfunction asHoopilotLogger(logger: pino.Logger): HoopilotLogger {\n return logger;\n}\n\nexport function parseLogFormat(value: string | undefined): LogFormat {\n if (!value) {\n return DEFAULT_LOG_FORMAT;\n }\n if (isLogFormat(value)) {\n return value;\n }\n throw new Error(`Invalid log format: ${value}. Expected one of: ${LOG_FORMATS.join(\", \")}.`);\n}\n\nexport function parseLogLevel(value: string | undefined): LogLevel {\n if (!value) {\n return DEFAULT_LOG_LEVEL;\n }\n if (isLogLevel(value)) {\n return value;\n }\n throw new Error(`Invalid log level: ${value}. Expected one of: ${LOG_LEVELS.join(\", \")}.`);\n}\n\nexport function shouldCreateLogger(options: {\n env?: NodeJS.ProcessEnv;\n logFormat?: string;\n logger?: HoopilotLogger;\n logLevel?: string;\n}): boolean {\n return Boolean(\n options.logger ||\n options.logFormat ||\n options.logLevel ||\n envValue(options.env?.HOOPILOT_LOG_FORMAT) ||\n envValue(options.env?.HOOPILOT_LOG_LEVEL),\n );\n}\n\n/** Build structured log fields describing an error, for the `err` log key. */\nexport function errorDetails(error: unknown): LogFields {\n if (error instanceof Error) {\n return {\n message: error.message,\n name: error.name,\n stack: error.stack,\n };\n }\n return { message: String(error) };\n}\n\nfunction isLogFormat(value: string): value is LogFormat {\n return (LOG_FORMATS as readonly string[]).includes(value);\n}\n\nfunction isLogLevel(value: string): value is LogLevel {\n return (LOG_LEVELS as readonly string[]).includes(value);\n}\n","import { createHash, timingSafeEqual } from \"node:crypto\";\nimport { Elysia } from \"elysia\";\nimport {\n AnthropicCompatibilityError,\n anthropicMessagesToResponsesRequest,\n estimateAnthropicMessageTokens,\n responsesResponseToAnthropicMessage,\n responsesSseTextToAnthropicSseText,\n responsesStreamToAnthropicStream,\n} from \"./anthropic\";\nimport { CopilotAuthError } from \"./auth\";\nimport {\n CopilotClient,\n CopilotUpstreamTimeoutError,\n normalizeCopilotUsage,\n parseRateLimitHeaders,\n} from \"./copilot\";\nimport { DASHBOARD_HTML } from \"./dashboard\";\nimport { createHoopilotLogger, errorDetails, noopLogger, shouldCreateLogger } from \"./logger\";\nimport {\n MetricsRegistry,\n observeResponseUsage,\n PROMETHEUS_CONTENT_TYPE,\n recordResponseTextUsage,\n} from \"./metrics\";\nimport {\n chatCompletionToCompletion,\n completionSseTextFromChatSseText,\n completionStreamFromChatStream,\n completionsRequestToChatCompletion,\n extractTokenUsage,\n fallbackModels,\n isResponsesCompactionRequest,\n normalizeChatCompletionRequest,\n normalizeModelsResponse,\n normalizeRequestedModel,\n normalizeResponsesRequestForCopilotBody,\n OpenAICompatibilityError,\n responsesCompactionRequestBody,\n responsesCompactionResponse,\n responsesCompactionResult,\n responsesCompactionSseText,\n responsesRequestNeedsCopilotNormalization,\n} from \"./openai\";\nimport type {\n CopilotUsage,\n HoopilotLogger,\n HoopilotServerOptions,\n JsonObject,\n LogFields,\n StartedHoopilotServer,\n StreamingProxyMode,\n TokenUsage,\n UsageResponseBody,\n} from \"./types\";\nimport {\n asRecord,\n envValue,\n errorMessage,\n isLoopbackHostname,\n parseStreamingProxyMode,\n safeJsonParse,\n} from \"./util\";\nimport { getVersion, IS_STANDALONE_BINARY } from \"./version\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 4141;\nconst FORBIDDEN_BROWSER_ORIGIN_MESSAGE =\n \"Cross-origin browser requests are blocked unless the Origin is loopback or listed in HOOPILOT_ALLOWED_ORIGINS.\";\nconst MIN_NON_LOOPBACK_API_KEY_LENGTH = 24;\n// API keys we ship in docs/examples as placeholders. They are effectively public,\n// so refusing them on non-loopback binds keeps a credential-backed proxy from being\n// reachable on a network with a guessable key.\nconst WELL_KNOWN_DEMO_API_KEYS = new Set([\n \"changeme\",\n \"demo\",\n \"example\",\n \"hoopilot\",\n \"local-key\",\n \"password\",\n \"password123\",\n \"secret\",\n \"test\",\n]);\nconst INVALID_JSON_MESSAGE = \"Request body must be valid JSON.\";\nconst JSON_OBJECT_MESSAGE = \"Request body must be a JSON object.\";\nconst MAX_REQUEST_BODY_BYTES = 16 * 1024 * 1024;\nconst REQUEST_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;\nconst REQUEST_TOO_LARGE_MESSAGE = `Request body must be ${MAX_REQUEST_BODY_BYTES} bytes or smaller.`;\nconst USAGE_CACHE_TTL_MS = 60_000;\n\ninterface UsageReadResult {\n copilot?: CopilotUsage;\n error?: string;\n}\n\ntype UsageReader = (signal?: AbortSignal) => Promise<UsageReadResult>;\ntype TokenRecorder = (model: string, usage: TokenUsage) => void;\ntype ExtractionRecorder = (extracted: boolean) => void;\n\nclass RequestBodyTooLargeError extends Error {\n constructor() {\n super(REQUEST_TOO_LARGE_MESSAGE);\n this.name = \"RequestBodyTooLargeError\";\n }\n}\n\n// Typed body-parse failures so onError discriminates them by `instanceof` like\n// the other handler errors, instead of matching on the message string.\nclass InvalidJsonError extends Error {\n constructor() {\n super(INVALID_JSON_MESSAGE);\n this.name = \"InvalidJsonError\";\n }\n}\n\nclass JsonNotObjectError extends Error {\n constructor() {\n super(JSON_OBJECT_MESSAGE);\n this.name = \"JsonNotObjectError\";\n }\n}\n\nexport function createHoopilotHandler(\n options: HoopilotServerOptions = {},\n): (request: Request) => Promise<Response> {\n const client = new CopilotClient(options);\n const apiKey = options.apiKey ?? envValue(options.env?.HOOPILOT_API_KEY);\n const allowedOrigins = parseAllowedOrigins(options.env);\n const logger = serverLogger(options);\n const metrics = options.metrics ?? new MetricsRegistry();\n const readUsage = createUsageReader(client, metrics);\n const recordTokens: TokenRecorder = (model, usage) => metrics.recordTokens(model, usage);\n const recordExtraction: ExtractionRecorder = (extracted) =>\n metrics.recordTokenExtraction(extracted);\n const bufferProxyBodies = shouldBufferProxyBodies(resolveStreamingProxyMode(options));\n\n // Per-request channel into the Elysia lifecycle. The bookend below builds the\n // child logger once (with the canonical request id and the original path) and\n // stashes it here keyed by the request object, which Elysia passes through by\n // identity to onRequest/handlers/onError — so the id in the response header and\n // every log line agree without recomputing (or regenerating) it inside Elysia.\n const requestContext = new WeakMap<Request, RequestContext>();\n const app = buildApp({\n apiKey,\n allowedOrigins,\n bufferProxyBodies,\n client,\n metrics,\n readUsage,\n recordExtraction,\n recordTokens,\n requestContext,\n });\n\n return async (request: Request): Promise<Response> => {\n const startedAt = performance.now();\n const url = new URL(request.url);\n const apiPath = canonicalApiPath(url.pathname);\n const requestId = requestIdFor(request);\n const route = routeFor(request.method, apiPath);\n const requestLogger = logger.child({\n method: request.method,\n path: url.pathname,\n requestId,\n route,\n });\n metrics.startRequest();\n const origin = request.headers.get(\"origin\")?.trim() || undefined;\n const corsOrigin = resolveCorsAllowOrigin(origin, allowedOrigins);\n\n // Elysia owns routing, body-parse control, the pre-routing gates, and error\n // mapping. The cross-cutting bookend stays out here so it runs on EVERY\n // response — routed, gated, 404, or thrown — regardless of Elysia's\n // short-circuit semantics (an onRequest gate skips mapResponse/onAfterResponse):\n // metrics.startRequest() above pairs with the metrics.observe() that\n // finishResponse() schedules, and the per-request child logger reaches the\n // Elysia lifecycle through `requestContext`.\n const inner = normalizeInnerRequest(request, apiPath, url);\n requestContext.set(inner, {\n apiPath,\n logger: requestLogger,\n origin,\n originalPath: url.pathname,\n });\n\n let response: Response;\n try {\n response = await app.handle(inner);\n } catch (error) {\n // Elysia resolves handler and hook throws through onError, so this only\n // catches a failure inside onError itself — still finish so the in-flight\n // gauge opened by startRequest() above is always balanced.\n requestLogger.error(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request failed\",\n );\n response = jsonError(500, \"internal_error\", errorMessage(error));\n }\n\n return finishResponse(response, {\n corsOrigin,\n logger: requestLogger,\n method: request.method,\n metrics,\n requestId,\n route,\n startedAt,\n closeConnection: bufferProxyBodies,\n trackStreamingBody: !bufferProxyBodies,\n });\n };\n}\n\n// Request-scoped data the bookend computes once and threads into the Elysia\n// lifecycle, keyed by the request object (see the WeakMap note above). Carrying\n// apiPath/origin here lets the onRequest gate reuse them instead of re-parsing\n// the URL, and originalPath lets the 404 message report the caller's path rather\n// than the canonicalized inner path the router matched against.\ninterface RequestContext {\n apiPath: string;\n logger: HoopilotLogger;\n origin: string | undefined;\n originalPath: string;\n}\n\ninterface ServerDeps {\n apiKey: string | undefined;\n allowedOrigins: ReadonlySet<string>;\n bufferProxyBodies: boolean;\n client: CopilotClient;\n metrics: MetricsRegistry;\n readUsage: UsageReader;\n recordExtraction: ExtractionRecorder;\n recordTokens: TokenRecorder;\n requestContext: WeakMap<Request, RequestContext>;\n}\n\n// Build the Elysia application once per handler factory (closing over deps), then\n// drive it per request with app.handle() from the bookend above. Route handlers\n// return the raw Response objects the existing helpers build — Elysia passes a\n// returned Response through untouched (no header injection, no re-serialization),\n// so the wire format stays byte-identical. This passthrough holds only because the\n// handlers never write to Elysia's `set` (headers/status/cookie) or `store`: doing so\n// would route the response back through mapResponse and re-serialize it, drifting the\n// bytes. Each handler reads its per-request\n// child logger from `requestContext` rather than recomputing it, which keeps the\n// request id and the original request path consistent between header and logs.\n// POST routes set `parse: \"none\"` so Elysia never consumes the body: the handlers\n// stream it themselves under the 16 MB cap (readRequestText) and forward the raw\n// bytes upstream verbatim.\nfunction buildApp(deps: ServerDeps) {\n const {\n apiKey,\n allowedOrigins,\n bufferProxyBodies,\n client,\n metrics,\n readUsage,\n recordExtraction,\n recordTokens,\n requestContext,\n } = deps;\n\n // Recover the request-scoped context the bookend stashed (keyed by request\n // identity — Elysia passes the same Request object through every hook/handler).\n // A miss should never happen: the bookend always populates it before\n // app.handle(). The fallback recomputes from the request purely as a crash\n // guard so an unexpected re-wrapped request degrades instead of throwing.\n const contextFor = (request: Request): RequestContext => {\n const stored = requestContext.get(request);\n if (stored) {\n return stored;\n }\n const originalPath = new URL(request.url).pathname;\n return {\n apiPath: canonicalApiPath(originalPath),\n logger: noopLogger,\n origin: request.headers.get(\"origin\")?.trim() || undefined,\n originalPath,\n };\n };\n const loggerFor = (request: Request): HoopilotLogger => contextFor(request).logger;\n const noBody = { parse: \"none\" } as const;\n\n return (\n new Elysia()\n // Pre-routing gate, in the exact order the hand-rolled handler used: block\n // cross-origin browser requests, answer CORS preflight, serve the dashboard\n // before the API-key gate, then enforce the gate. Returning a Response\n // short-circuits routing; the bookend still decorates it via finishResponse.\n .onRequest(({ request }) => {\n const { apiPath, logger, origin } = contextFor(request);\n\n const browserOrigin = forbiddenBrowserOrigin(origin, request, allowedOrigins);\n if (browserOrigin) {\n logger.warn(\n { event: \"http.request.forbidden_origin\", origin: browserOrigin },\n \"blocked cross-origin browser request\",\n );\n return jsonError(403, \"forbidden_origin\", FORBIDDEN_BROWSER_ORIGIN_MESSAGE);\n }\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders() });\n }\n // The dashboard is a static, secret-free HTML shell. Serve it before the\n // API-key gate so a browser can open it by navigation (which cannot send\n // an Authorization header). The data it renders comes from /v1/usage,\n // which stays behind the gate; cross-origin access is blocked above.\n if (request.method === \"GET\" && apiPath === \"/dashboard\") {\n return dashboardResponse();\n }\n if (!isAuthorized(request, apiKey)) {\n logger.warn({ event: \"http.request.unauthorized\" }, \"invalid hoopilot api key\");\n return jsonError(401, \"invalid_api_key\", \"Invalid or missing Hoopilot API key.\");\n }\n })\n // Reproduce the hand-rolled catch block: map the typed errors the handlers\n // throw (and Elysia's NOT_FOUND) onto the same status/code/log events.\n // Registered before the routes: Elysia applies an error hook only to routes\n // declared after it, so a trailing onError would never see handler throws.\n .onError(({ code, error, request }) => {\n const { logger, originalPath } = contextFor(request);\n if (code === \"NOT_FOUND\") {\n // Report the caller's original path, not the canonicalized inner path\n // the router matched, so an unknown `/foo/` 404s as `/foo/` (matching\n // the pre-Elysia handler) rather than the slash-stripped `/foo`.\n return jsonError(404, \"not_found\", `No route for ${request.method} ${originalPath}.`);\n }\n if (error instanceof CopilotAuthError) {\n logger.warn(\n { err: errorDetails(error), event: \"copilot.auth.missing\" },\n \"copilot auth failed\",\n );\n return jsonError(401, \"copilot_auth_error\", error.message);\n }\n const message = errorMessage(error);\n if (error instanceof InvalidJsonError || error instanceof JsonNotObjectError) {\n logger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body was not usable json\",\n );\n return jsonError(400, \"invalid_request_error\", message);\n }\n if (\n error instanceof OpenAICompatibilityError ||\n error instanceof AnthropicCompatibilityError\n ) {\n logger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body used unsupported compatibility fields\",\n );\n return jsonError(400, \"invalid_request_error\", message);\n }\n if (error instanceof RequestBodyTooLargeError) {\n logger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body exceeded size limit\",\n );\n return jsonError(413, \"request_too_large\", message);\n }\n if (error instanceof CopilotUpstreamTimeoutError) {\n logger.warn(\n { err: errorDetails(error), event: \"copilot.request.timeout\" },\n \"copilot upstream request timed out\",\n );\n return jsonError(504, \"copilot_timeout\", message);\n }\n logger.error({ err: errorDetails(error), event: \"http.request.failed\" }, \"request failed\");\n return jsonError(500, \"internal_error\", message);\n })\n .get(\"/\", () => jsonResponse({ name: \"hoopilot\", object: \"health\", status: \"ok\" }))\n .get(\"/healthz\", () => jsonResponse({ name: \"hoopilot\", object: \"health\", status: \"ok\" }))\n .get(\"/metrics\", () => metricsResponse(metrics))\n .get(\"/v1/usage\", ({ request }) => handleUsage(metrics, readUsage, request.signal))\n .get(\"/v1/models\", ({ request }) =>\n handleModels(client, metrics, request.signal, loggerFor(request)),\n )\n .get(\"/v1/responses\", () => websocketUnsupportedResponse())\n .post(\n \"/v1/messages\",\n ({ request }) =>\n handleAnthropicMessages(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n .post(\n \"/v1/messages/count_tokens\",\n ({ request }) => handleAnthropicCountTokens(request),\n noBody,\n )\n .post(\n \"/v1/chat/completions\",\n ({ request }) =>\n handleChatCompletions(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n .post(\n \"/v1/completions\",\n ({ request }) =>\n handleCompletions(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n .post(\n \"/v1/responses/compact\",\n ({ request }) =>\n handleResponsesCompact(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n ),\n noBody,\n )\n .post(\n \"/v1/responses\",\n ({ request }) =>\n handleResponses(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n request,\n loggerFor(request),\n bufferProxyBodies,\n ),\n noBody,\n )\n );\n}\n\n// Normalize the path the Elysia router matches against — map bare aliases like\n// `/responses` onto `/v1/responses` and strip trailing slashes (reusing the\n// single-source canonicalApiPath table) — while leaving the request's body\n// stream and abort signal intact for the handlers. Bun's Request constructor\n// copies the body and makes the new signal follow the original's abort, so the\n// clone forwards bytes and cancels upstream on disconnect exactly as before.\n// Returns the request unchanged when no rewrite is needed.\nfunction normalizeInnerRequest(request: Request, canonicalPath: string, url: URL): Request {\n if (canonicalPath === url.pathname) {\n return request;\n }\n const target = new URL(url);\n target.pathname = canonicalPath;\n const init: RequestInit & { duplex?: \"half\" } = {\n headers: request.headers,\n method: request.method,\n signal: request.signal,\n };\n if (request.body) {\n init.body = request.body;\n init.duplex = \"half\";\n }\n return new Request(target, init);\n}\n\nexport function startHoopilotServer(options: HoopilotServerOptions = {}): StartedHoopilotServer {\n const host = options.host ?? envValue(options.env?.HOST) ?? DEFAULT_HOST;\n const port = normalizeServerPort(options.port ?? envValue(options.env?.PORT) ?? DEFAULT_PORT);\n const apiKey = options.apiKey ?? envValue(options.env?.HOOPILOT_API_KEY);\n const allowUnauthenticated =\n options.allowUnauthenticated ?? envValue(options.env?.HOOPILOT_ALLOW_UNAUTHENTICATED) === \"1\";\n\n if (!isLoopbackHost(host)) {\n if (!apiKey && !allowUnauthenticated) {\n throw new Error(\n \"Refusing to listen on a non-loopback host without HOOPILOT_API_KEY. Set an API key or pass --allow-unauthenticated.\",\n );\n }\n const rejection = apiKey ? apiKeyRejectionReason(apiKey) : undefined;\n if (rejection) {\n throw new Error(`Refusing to listen on a non-loopback host: ${rejection}`);\n }\n }\n\n const server = Bun.serve({\n fetch: createHoopilotHandler({\n ...options,\n apiKey,\n host,\n port,\n }),\n hostname: host,\n port,\n });\n\n return {\n server,\n url: `http://${urlHost(host)}:${server.port}`,\n };\n}\n\nasync function handleAnthropicMessages(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const anthropicRequest = await readJson(request);\n const responsesRequest = anthropicMessagesToResponsesRequest(anthropicRequest);\n const upstream = await client.responses(JSON.stringify(responsesRequest), request.signal);\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const model = normalizeRequestedModel(responsesRequest.model);\n\n if (isStreamingResponse(upstream) && upstream.body) {\n if (bufferProxyBodies) {\n const text = await upstream.text();\n recordResponseTextUsage(text, true, model, recordTokens, recordExtraction);\n return proxyResponse(\n responseFromText(upstream, responsesSseTextToAnthropicSseText(text, { model })),\n );\n }\n const observed = observeResponseUsage(\n upstream,\n model,\n recordTokens,\n request.signal,\n recordExtraction,\n );\n if (!observed.body) {\n return proxyResponse(observed);\n }\n return proxyResponse(\n new Response(responsesStreamToAnthropicStream(observed.body, { model }), {\n headers: observed.headers,\n status: observed.status,\n statusText: observed.statusText,\n }),\n );\n }\n\n const body = asRecord(await upstream.json());\n const usage = extractTokenUsage(body.usage);\n if (usage) {\n const responseModel = typeof body.model === \"string\" ? body.model.trim() : \"\";\n recordTokens(responseModel || model, usage);\n }\n recordExtraction(usage !== undefined);\n return jsonResponse(responsesResponseToAnthropicMessage(body, model));\n}\n\nasync function handleAnthropicCountTokens(request: Request): Promise<Response> {\n const body = await readJson(request);\n return jsonResponse(estimateAnthropicMessageTokens(body));\n}\n\nasync function handleModels(\n client: CopilotClient,\n metrics: MetricsRegistry,\n signal: AbortSignal,\n logger: HoopilotLogger,\n): Promise<Response> {\n const upstream = await client.models(signal);\n metrics.recordUpstream(\"/models\", upstream.ok);\n if (!upstream.ok) {\n if (isUpstreamAuthStatus(upstream.status)) {\n return proxyError(upstream, logger);\n }\n logger.warn(\n {\n event: \"copilot.models.fallback\",\n upstreamPath: \"/models\",\n upstreamStatus: upstream.status,\n },\n \"falling back to built-in model list\",\n );\n return jsonResponse({ data: fallbackModels(), object: \"list\" });\n }\n logUpstreamSuccess(logger, \"/models\", upstream.status);\n return jsonResponse(normalizeModelsResponse(await upstream.json()));\n}\n\nasync function handleChatCompletions(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const chatRequest = normalizeChatCompletionRequest(await readJson(request));\n const upstream = await client.chatCompletions(chatRequest, request.signal);\n metrics.recordUpstream(\"/chat/completions\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/chat/completions\", upstream.status);\n const model = normalizeRequestedModel(chatRequest.model);\n return proxyResponse(\n await responseWithObservedUsage(\n upstream,\n model,\n recordTokens,\n request.signal,\n bufferProxyBodies,\n recordExtraction,\n ),\n );\n}\n\nasync function handleCompletions(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const body = await readJson(request);\n const upstream = await client.chatCompletions(\n completionsRequestToChatCompletion(body),\n request.signal,\n );\n metrics.recordUpstream(\"/chat/completions\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/chat/completions\", upstream.status);\n const model = normalizeRequestedModel(body.model);\n // A streaming request yields chat-completion SSE; convert each chunk to the\n // legacy completions stream shape instead of calling .json() on the body.\n if (isStreamingResponse(upstream) && upstream.body) {\n if (bufferProxyBodies) {\n const upstreamText = await upstream.text();\n recordResponseTextUsage(upstreamText, true, model, recordTokens, recordExtraction);\n const text = completionSseTextFromChatSseText(upstreamText);\n return proxyResponse(responseFromText(upstream, text));\n }\n return proxyResponse(\n observeResponseUsage(\n new Response(completionStreamFromChatStream(upstream.body), {\n headers: upstream.headers,\n status: upstream.status,\n statusText: upstream.statusText,\n }),\n model,\n recordTokens,\n request.signal,\n recordExtraction,\n ),\n );\n }\n const completion = asRecord(await upstream.json());\n const usage = extractTokenUsage(completion.usage);\n if (usage) {\n const responseModel = typeof completion.model === \"string\" ? completion.model.trim() : \"\";\n recordTokens(responseModel || model, usage);\n }\n recordExtraction(usage !== undefined);\n return jsonResponse(chatCompletionToCompletion(completion));\n}\n\nasync function handleResponses(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n bufferProxyBodies: boolean,\n): Promise<Response> {\n const { json, text: body } = await readJsonText(request);\n if (isResponsesCompactionRequest(json)) {\n return handleResponsesCompactionV2(\n client,\n metrics,\n recordTokens,\n recordExtraction,\n json,\n request,\n logger,\n );\n }\n\n const upstream = await client.responses(\n responsesRequestNeedsCopilotNormalization(json)\n ? normalizeResponsesRequestForCopilotBody(json)\n : body,\n request.signal,\n );\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const model = normalizeRequestedModel(json.model);\n return proxyResponse(\n await responseWithObservedUsage(\n upstream,\n model,\n recordTokens,\n request.signal,\n bufferProxyBodies,\n recordExtraction,\n ),\n );\n}\n\n/**\n * Codex's remote context compaction (`POST /responses/compact`, used when the\n * model provider is named \"OpenAI\" or is Azure) is a proprietary OpenAI surface\n * that Copilot does not expose, and Codex has no client-side fallback — a 404\n * there hard-fails compaction. Satisfy it by running the supplied Responses-API\n * payload through Copilot's `/responses` as a unary request and returning the\n * `{ output }` document Codex expects, so the conversation history is replaced\n * with a real model-produced summary instead of erroring out.\n */\nasync function handleResponsesCompact(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n request: Request,\n logger: HoopilotLogger,\n): Promise<Response> {\n const body = await readJson(request);\n const upstream = await client.responses(responsesCompactionRequestBody(body), request.signal);\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const isSse = isStreamingResponse(upstream);\n const text = await upstream.text();\n recordResponseTextUsage(\n text,\n isSse,\n normalizeRequestedModel(body.model),\n recordTokens,\n recordExtraction,\n );\n return jsonResponse(responsesCompactionResult(text, isSse));\n}\n\nasync function handleResponsesCompactionV2(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n recordExtraction: ExtractionRecorder,\n json: JsonObject,\n request: Request,\n logger: HoopilotLogger,\n): Promise<Response> {\n const upstream = await client.responses(responsesCompactionRequestBody(json), request.signal);\n metrics.recordUpstream(\"/responses\", upstream.ok);\n if (!upstream.ok) {\n return proxyError(upstream, logger);\n }\n logUpstreamSuccess(logger, \"/responses\", upstream.status);\n const isSse = isStreamingResponse(upstream);\n const text = await upstream.text();\n const model = normalizeRequestedModel(json.model);\n recordResponseTextUsage(text, isSse, model, recordTokens, recordExtraction);\n if (json.stream === true) {\n return textResponse(responsesCompactionSseText(text, isSse, model), \"text/event-stream\");\n }\n return jsonResponse(responsesCompactionResponse(text, isSse, model));\n}\n\nasync function responseWithObservedUsage(\n response: Response,\n fallbackModel: string,\n recordTokens: TokenRecorder,\n signal: AbortSignal,\n bufferBody: boolean,\n recordExtraction: ExtractionRecorder,\n): Promise<Response> {\n const isSse = isStreamingResponse(response);\n if (bufferBody && response.body) {\n const text = await response.text();\n recordResponseTextUsage(text, isSse, fallbackModel, recordTokens, recordExtraction);\n return responseFromText(response, text);\n }\n return observeResponseUsage(response, fallbackModel, recordTokens, signal, recordExtraction);\n}\n\nfunction responseFromText(source: Response, text: string): Response {\n return new Response(text, {\n headers: source.headers,\n status: source.status,\n statusText: source.statusText,\n });\n}\n\nasync function proxyError(upstream: Response, logger: HoopilotLogger): Promise<Response> {\n const text = await upstream.text();\n if (isUpstreamAuthStatus(upstream.status)) {\n logger.warn(\n { event: \"copilot.auth.rejected\", upstreamStatus: upstream.status },\n \"copilot rejected credential or account access\",\n );\n return jsonError(401, \"copilot_auth_error\", upstreamAuthMessage(text || upstream.statusText));\n }\n logger.warn(\n { event: \"copilot.request.failed\", upstreamStatus: upstream.status },\n \"copilot upstream request failed\",\n );\n return upstreamErrorResponse(upstream.status, text || upstream.statusText);\n}\n\nfunction proxyResponse(upstream: Response): Response {\n const headers = new Headers(upstream.headers);\n headers.delete(\"content-encoding\");\n headers.delete(\"content-length\");\n headers.delete(\"transfer-encoding\");\n for (const [key, value] of Object.entries(corsHeaders())) {\n headers.set(key, value);\n }\n return new Response(upstream.body, {\n headers,\n status: upstream.status,\n statusText: upstream.statusText,\n });\n}\n\nasync function readJson(request: Request): Promise<JsonObject> {\n const text = await readRequestText(request);\n return parseJsonObject(text);\n}\n\nfunction parseJsonObject(text: string): JsonObject {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new InvalidJsonError();\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new JsonNotObjectError();\n }\n return parsed as JsonObject;\n}\n\nasync function readJsonText(request: Request): Promise<{ json: JsonObject; text: string }> {\n const text = await readRequestText(request);\n return { json: parseJsonObject(text), text };\n}\n\nasync function readRequestText(request: Request): Promise<string> {\n const contentLength = request.headers.get(\"content-length\");\n if (contentLength) {\n const declaredBytes = Number(contentLength);\n if (Number.isFinite(declaredBytes) && declaredBytes > MAX_REQUEST_BODY_BYTES) {\n throw new RequestBodyTooLargeError();\n }\n }\n\n const body = request.body;\n if (!body) {\n return \"\";\n }\n\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let bytes = 0;\n const chunks: string[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n const tail = decoder.decode();\n if (tail) {\n chunks.push(tail);\n }\n return chunks.join(\"\");\n }\n bytes += value.byteLength;\n if (bytes > MAX_REQUEST_BODY_BYTES) {\n await reader.cancel().catch(() => {});\n throw new RequestBodyTooLargeError();\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction jsonResponse(body: object, status = 200): Response {\n return new Response(JSON.stringify(body), {\n headers: {\n ...corsHeaders(),\n \"content-type\": \"application/json; charset=utf-8\",\n },\n status,\n });\n}\n\nfunction textResponse(body: string, contentType: string, status = 200): Response {\n return new Response(body, {\n headers: {\n ...corsHeaders(),\n \"content-type\": `${contentType}; charset=utf-8`,\n },\n status,\n });\n}\n\nfunction jsonError(status: number, code: string, message: string): Response {\n return jsonResponse(\n {\n error: {\n code,\n message,\n type: code,\n },\n },\n status,\n );\n}\n\nfunction upstreamErrorResponse(status: number, text: string): Response {\n const parsedError = asRecord(asRecord(safeJsonParse(text)).error);\n if (Object.keys(parsedError).length > 0) {\n return jsonResponse({ error: parsedError }, status);\n }\n return jsonError(status, \"copilot_error\", text);\n}\n\nfunction websocketUnsupportedResponse(): Response {\n const response = jsonError(\n 426,\n \"websocket_not_supported\",\n \"Hoopilot does not support Responses WebSocket transport; retry with HTTP Responses API.\",\n );\n response.headers.set(\"upgrade\", \"websocket\");\n return response;\n}\n\n// CORS headers shared by every response. The `access-control-allow-origin` value\n// is intentionally omitted here and set per-request by `finishResponse`, so the\n// proxy only advertises access to origins it actually allows (loopback or\n// HOOPILOT_ALLOWED_ORIGINS) instead of a blanket wildcard.\nfunction corsHeaders(): Record<string, string> {\n return {\n \"access-control-allow-headers\":\n \"anthropic-beta, anthropic-dangerous-direct-browser-access, anthropic-version, authorization, content-type, x-api-key, x-request-id\",\n \"access-control-allow-methods\": \"GET, POST, OPTIONS\",\n \"access-control-expose-headers\": \"x-request-id\",\n };\n}\n\n// Compare two secrets in constant time. Both sides are hashed to a fixed-width\n// digest first so neither the key length nor a prefix match leaks via timing.\nfunction secretEquals(candidate: string, secret: string): boolean {\n const a = createHash(\"sha256\").update(candidate).digest();\n const b = createHash(\"sha256\").update(secret).digest();\n return timingSafeEqual(a, b);\n}\n\nfunction isAuthorized(request: Request, apiKey: string | undefined): boolean {\n if (!apiKey) {\n return true;\n }\n const authorization = request.headers.get(\"authorization\") ?? \"\";\n const bearer = authorization.match(/^Bearer\\s+(.+)$/i)?.[1];\n return (\n (bearer !== undefined && secretEquals(bearer, apiKey)) ||\n secretEquals(request.headers.get(\"x-api-key\") ?? \"\", apiKey)\n );\n}\n\n// Block cross-origin browser requests regardless of whether an API key is set.\n// The proxy holds a GitHub OAuth credential and is meant for local CLI/tool\n// clients, never for arbitrary web pages: a malicious site must not be able to\n// drive it even if it knows (or guesses) the local API key. Loopback origins and\n// any origin in HOOPILOT_ALLOWED_ORIGINS are allowed through to the key check.\nfunction forbiddenBrowserOrigin(\n origin: string | undefined,\n request: Request,\n allowedOrigins: ReadonlySet<string>,\n): string | undefined {\n if (origin) {\n return isAllowedOrigin(origin, allowedOrigins) ? undefined : origin;\n }\n\n const fetchSite = request.headers.get(\"sec-fetch-site\")?.toLowerCase();\n return fetchSite === \"cross-site\" ? \"cross-site\" : undefined;\n}\n\n// Parse the comma-separated HOOPILOT_ALLOWED_ORIGINS allowlist into a normalized\n// set of exact origins (scheme + host + optional port), lower-cased for matching.\nfunction parseAllowedOrigins(env: NodeJS.ProcessEnv | undefined): ReadonlySet<string> {\n const raw = envValue(env?.HOOPILOT_ALLOWED_ORIGINS);\n if (!raw) {\n return new Set();\n }\n return new Set(\n raw\n .split(\",\")\n .map((value) => value.trim().toLowerCase())\n .filter((value) => value.length > 0),\n );\n}\n\nfunction isAllowedOrigin(origin: string, allowedOrigins: ReadonlySet<string>): boolean {\n return isLoopbackOrigin(origin) || allowedOrigins.has(origin.toLowerCase());\n}\n\n// Resolve the `access-control-allow-origin` value for a response. Allowed browser\n// origins are echoed back (so the page can read the response); a request with no\n// Origin is a non-browser client where the value is inert, so we keep `*`;\n// disallowed origins get no header (they are also blocked with a 403), so a\n// malicious page cannot read even an error body.\nfunction resolveCorsAllowOrigin(\n origin: string | undefined,\n allowedOrigins: ReadonlySet<string>,\n): string | undefined {\n if (!origin) {\n return \"*\";\n }\n return isAllowedOrigin(origin, allowedOrigins) ? origin : undefined;\n}\n\nfunction apiKeyRejectionReason(apiKey: string): string | undefined {\n const normalized = apiKey.trim();\n if (WELL_KNOWN_DEMO_API_KEYS.has(normalized.toLowerCase())) {\n return \"HOOPILOT_API_KEY is a well-known demo value. Set a strong, unique API key.\";\n }\n if (normalized.length < MIN_NON_LOOPBACK_API_KEY_LENGTH) {\n return `HOOPILOT_API_KEY must be at least ${MIN_NON_LOOPBACK_API_KEY_LENGTH} characters when listening on a non-loopback host.`;\n }\n if (/^(.)\\1+$/.test(normalized)) {\n return \"HOOPILOT_API_KEY must not be a repeated single character. Set a strong, unique API key.\";\n }\n return undefined;\n}\n\nfunction isUpstreamAuthStatus(status: number): boolean {\n return status === 401 || status === 403;\n}\n\nfunction upstreamAuthMessage(message: string): string {\n return `GitHub Copilot rejected the credential or account access: ${message}`;\n}\n\nfunction isLoopbackHost(host: string): boolean {\n return isLoopbackHostname(host);\n}\n\nfunction urlHost(host: string): string {\n return host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host;\n}\n\nfunction isLoopbackOrigin(origin: string): boolean {\n try {\n return isLoopbackHost(new URL(origin).hostname.toLowerCase());\n } catch {\n return false;\n }\n}\n\nfunction normalizeServerPort(value: number | string): number {\n const port = Number(value);\n if (!Number.isInteger(port) || port < 0 || port > 65_535) {\n throw new Error(`Invalid port: ${value}.`);\n }\n return port;\n}\n\nfunction serverLogger(options: HoopilotServerOptions): HoopilotLogger {\n if (options.logger) {\n return options.logger.child({ component: \"server\" });\n }\n if (shouldCreateLogger(options)) {\n return createHoopilotLogger({\n env: options.env,\n format: options.logFormat,\n level: options.logLevel,\n }).child({ component: \"server\" });\n }\n return noopLogger;\n}\n\nfunction resolveStreamingProxyMode(options: HoopilotServerOptions): StreamingProxyMode {\n const value =\n options.streamingProxyMode ??\n envValue(options.env?.HOOPILOT_STREAM_MODE) ??\n envValue(options.env?.HOOPILOT_STREAMING_PROXY_MODE) ??\n \"auto\";\n return parseStreamingProxyMode(value);\n}\n\nfunction shouldBufferProxyBodies(mode: StreamingProxyMode): boolean {\n if (mode === \"buffer\") {\n return true;\n }\n if (mode === \"live\") {\n return false;\n }\n return process.platform === \"win32\" && IS_STANDALONE_BINARY;\n}\n\nfunction finishResponse(\n response: Response,\n options: {\n closeConnection: boolean;\n corsOrigin: string | undefined;\n logger: HoopilotLogger;\n method: string;\n metrics: MetricsRegistry;\n requestId: string;\n route: string;\n startedAt: number;\n trackStreamingBody: boolean;\n },\n): Response {\n const withRequestId = responseWithRequestId(\n response,\n options.requestId,\n options.closeConnection,\n options.corsOrigin,\n );\n const stream = isStreamingResponse(withRequestId);\n const status = withRequestId.status;\n // Record metrics and log when the response is truly done. For a streamed body\n // that is when the client finishes receiving (or aborts) — so the in-flight\n // gauge and duration histogram reflect the full serving lifetime, not just the\n // time to upstream headers.\n const complete = (): void => {\n const durationMs = Math.round((performance.now() - options.startedAt) * 100) / 100;\n options.metrics.observe({ durationMs, method: options.method, route: options.route, status });\n logRequestCompleted(options.logger, status, stream, durationMs);\n };\n\n if (stream && withRequestId.body && options.trackStreamingBody) {\n return new Response(trackStreamCompletion(withRequestId.body, complete), {\n headers: withRequestId.headers,\n status,\n statusText: withRequestId.statusText,\n });\n }\n complete();\n return withRequestId;\n}\n\nfunction responseWithRequestId(\n response: Response,\n requestId: string,\n closeConnection: boolean,\n corsOrigin: string | undefined,\n): Response {\n const headers = new Headers(response.headers);\n headers.set(\"x-request-id\", requestId);\n if (corsOrigin) {\n headers.set(\"access-control-allow-origin\", corsOrigin);\n // A specific (non-wildcard) origin makes the response origin-dependent, so\n // mark it Vary: Origin to keep shared caches from serving it to others.\n if (corsOrigin !== \"*\") {\n headers.append(\"vary\", \"Origin\");\n }\n } else {\n headers.delete(\"access-control-allow-origin\");\n }\n if (closeConnection) {\n headers.set(\"connection\", \"close\");\n }\n return new Response(response.body, {\n headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\n// Re-stream `body`, invoking `onComplete` exactly once when the stream finishes,\n// is cancelled (client disconnect), or errors — so callers can measure the true\n// end of a streamed response.\nfunction trackStreamCompletion(\n body: ReadableStream<Uint8Array>,\n onComplete: () => void,\n): ReadableStream<Uint8Array> {\n const reader = body.getReader();\n let fired = false;\n // Release the source reader's lock on every terminal path so it is never\n // leaked. Idempotent: the first terminal branch wins.\n const release = (): void => {\n if (fired) {\n return;\n }\n fired = true;\n onComplete();\n reader.releaseLock();\n };\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n release();\n return;\n }\n controller.enqueue(value);\n } catch (error) {\n release();\n controller.error(error);\n }\n },\n async cancel(reason) {\n if (!fired) {\n fired = true;\n onComplete();\n }\n // The lock must be released after the cancel settles, not before, so a\n // pending read is not orphaned mid-cancel.\n try {\n await reader.cancel(reason);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nfunction logRequestCompleted(\n logger: HoopilotLogger,\n status: number,\n stream: boolean,\n durationMs: number,\n): void {\n const fields: LogFields = {\n durationMs,\n event: \"http.request.completed\",\n status,\n stream,\n };\n if (status >= 500) {\n logger.error(fields, \"request completed with server error\");\n return;\n }\n if (status >= 400) {\n logger.warn(fields, \"request completed with client error\");\n return;\n }\n logger.info(fields, \"request completed\");\n}\n\nfunction requestIdFor(request: Request): string {\n const existing = request.headers.get(\"x-request-id\")?.trim();\n return existing && REQUEST_ID_PATTERN.test(existing) ? existing : crypto.randomUUID();\n}\n\nfunction canonicalApiPath(path: string): string {\n const withoutTrailingSlash = path.length > 1 ? path.replace(/\\/+$/, \"\") : path;\n switch (withoutTrailingSlash) {\n case \"/models\":\n return \"/v1/models\";\n case \"/chat/completions\":\n return \"/v1/chat/completions\";\n case \"/completions\":\n return \"/v1/completions\";\n case \"/messages\":\n return \"/v1/messages\";\n case \"/messages/count_tokens\":\n return \"/v1/messages/count_tokens\";\n case \"/responses\":\n return \"/v1/responses\";\n case \"/responses/compact\":\n return \"/v1/responses/compact\";\n case \"/usage\":\n return \"/v1/usage\";\n default:\n return withoutTrailingSlash;\n }\n}\n\n// Single source of truth mapping (method, path) to a stable route name. Both the\n// request dispatch (switch on `route`) and routeFor() derive from this table, so\n// adding or renaming a route only touches one list. Names double as metrics and\n// log labels, so they must stay stable.\nconst API_ROUTES: ReadonlyArray<{ method: string; path: string; name: string }> = [\n { method: \"GET\", path: \"/\", name: \"health\" },\n { method: \"GET\", path: \"/healthz\", name: \"health\" },\n { method: \"GET\", path: \"/dashboard\", name: \"dashboard\" },\n { method: \"GET\", path: \"/metrics\", name: \"metrics\" },\n { method: \"GET\", path: \"/v1/usage\", name: \"usage\" },\n { method: \"GET\", path: \"/v1/models\", name: \"models\" },\n { method: \"GET\", path: \"/v1/responses\", name: \"responses_websocket\" },\n { method: \"POST\", path: \"/v1/messages\", name: \"anthropic_messages\" },\n { method: \"POST\", path: \"/v1/messages/count_tokens\", name: \"anthropic_count_tokens\" },\n { method: \"POST\", path: \"/v1/chat/completions\", name: \"chat_completions\" },\n { method: \"POST\", path: \"/v1/completions\", name: \"completions\" },\n { method: \"POST\", path: \"/v1/responses/compact\", name: \"responses_compact\" },\n { method: \"POST\", path: \"/v1/responses\", name: \"responses\" },\n];\n\nfunction routeFor(method: string, path: string): string {\n if (method === \"OPTIONS\") {\n return \"cors.preflight\";\n }\n return (\n API_ROUTES.find((entry) => entry.method === method && entry.path === path)?.name ?? \"not_found\"\n );\n}\n\nfunction isStreamingResponse(response: Response): boolean {\n return response.headers.get(\"content-type\")?.includes(\"text/event-stream\") ?? false;\n}\n\nfunction logUpstreamSuccess(logger: HoopilotLogger, upstreamPath: string, status: number): void {\n logger.debug(\n {\n event: \"copilot.request.completed\",\n upstreamPath,\n upstreamStatus: status,\n },\n \"copilot upstream request completed\",\n );\n}\n\nfunction metricsResponse(metrics: MetricsRegistry): Response {\n return new Response(metrics.renderPrometheus(), {\n headers: {\n ...corsHeaders(),\n \"content-type\": PROMETHEUS_CONTENT_TYPE,\n },\n status: 200,\n });\n}\n\n// Serve the self-contained dashboard HTML. The per-request CORS and request-id\n// headers are layered on by finishResponse; the page itself embeds no secrets.\n// A strict CSP and frame-busting headers harden the page even though it handles\n// the local API key in the browser: it loads zero external resources and only\n// fetches the same-origin /v1/usage, so 'self'/'unsafe-inline' suffice, and\n// frame-ancestors/X-Frame-Options close any clickjacking surface on engines that\n// do not send Sec-Fetch-Metadata (which the cross-origin block relies on).\nfunction dashboardResponse(): Response {\n return new Response(DASHBOARD_HTML, {\n headers: {\n ...corsHeaders(),\n \"content-security-policy\":\n \"default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'\",\n \"content-type\": \"text/html; charset=utf-8\",\n \"referrer-policy\": \"no-referrer\",\n \"x-content-type-options\": \"nosniff\",\n \"x-frame-options\": \"DENY\",\n },\n status: 200,\n });\n}\n\nasync function handleUsage(\n metrics: MetricsRegistry,\n readUsage: UsageReader,\n signal: AbortSignal,\n): Promise<Response> {\n const { copilot, error } = await readUsage(signal);\n const proxy = metrics.snapshot();\n const body: UsageResponseBody = {\n copilot: copilot ?? null,\n object: \"usage\",\n proxy,\n version: await getVersion(),\n };\n if (error) {\n body.copilot_error = error;\n }\n return jsonResponse(body);\n}\n\n/**\n * Build a memoizing reader for the Copilot quota. The result is cached for\n * {@link USAGE_CACHE_TTL_MS} so repeated `/v1/usage` scrapes do not hammer\n * GitHub's REST rate limit, and missing credentials or upstream errors surface\n * as an `error` string rather than failing the whole response.\n */\nexport function createUsageReader(\n client: CopilotClient,\n metrics: MetricsRegistry,\n now: () => number = Date.now,\n ttlMs = USAGE_CACHE_TTL_MS,\n): UsageReader {\n const usagePath = \"/copilot_internal/user\";\n let cache: { atMs: number; value: CopilotUsage } | undefined;\n return async (signal) => {\n if (cache && now() - cache.atMs < ttlMs) {\n return { copilot: cache.value };\n }\n try {\n const upstream = await client.usage(signal);\n metrics.recordUpstream(usagePath, upstream.ok);\n // api.github.com returns the x-ratelimit-* budget on every reply — on the\n // error path too, where retry-after / a spent budget is the useful signal —\n // so capture it off the quota call without spending an extra request.\n metrics.recordGithubRateLimit(parseRateLimitHeaders(upstream.headers, now()));\n if (!upstream.ok) {\n return { error: `GitHub Copilot usage request failed with ${upstream.status}.` };\n }\n const value = normalizeCopilotUsage(await upstream.json().catch(() => ({})));\n cache = { atMs: now(), value };\n metrics.recordCopilotQuota(value);\n return { copilot: value };\n } catch (error) {\n if (error instanceof CopilotAuthError) {\n return { error: error.message };\n }\n metrics.recordUpstream(usagePath, false);\n return { error: errorMessage(error) };\n }\n };\n}\n","import type { JsonObject, TokenUsage } from \"./types\";\nimport {\n asRecord,\n firstNumber,\n parseJsonObject,\n randomId,\n removeUndefined,\n safeJsonParse,\n} from \"./util\";\n\nexport const DEFAULT_MODEL = \"gpt-4.1\";\n\ninterface ResponseStreamOptions {\n model: string;\n responseId?: string;\n}\n\nconst COMPACTION_SUMMARIZATION_PROMPT = `You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.\n\nInclude:\n- Current progress and key decisions made\n- Important context, constraints, or user preferences\n- What remains to be done (clear next steps)\n- Any critical data, examples, or references needed to continue\n\nBe concise, structured, and focused on helping the next LLM seamlessly continue the work.`;\n\nconst COMPACTION_SUMMARY_PREFIX =\n \"Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:\";\n\ninterface AccumulatedToolCall {\n arguments: string;\n id: string;\n index?: number;\n itemId: string;\n name: string;\n outputIndex: number;\n}\n\nexport class OpenAICompatibilityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OpenAICompatibilityError\";\n }\n}\n\nexport function responsesRequestToChatCompletion(request: JsonObject): JsonObject {\n const messages: unknown[] = [];\n const instructions = contentToText(request.instructions);\n if (instructions) {\n messages.push({ content: instructions, role: \"system\" });\n }\n\n for (const message of inputToMessages(request.input)) {\n messages.push(message);\n }\n\n return removeUndefined({\n frequency_penalty: request.frequency_penalty,\n max_tokens: request.max_output_tokens ?? request.max_tokens,\n messages,\n metadata: request.metadata,\n model: normalizeRequestedModel(request.model),\n presence_penalty: request.presence_penalty,\n reasoning_effort: asRecord(request.reasoning).effort,\n response_format: asRecord(request.text).format,\n seed: request.seed,\n stream: request.stream === true,\n temperature: request.temperature,\n tool_choice: chatToolChoice(request.tool_choice),\n tools: chatTools(request.tools),\n top_p: request.top_p,\n });\n}\n\nexport function normalizeChatCompletionRequest(request: JsonObject): JsonObject {\n return removeUndefined({\n ...request,\n model: normalizeRequestedModel(request.model),\n });\n}\n\nexport function completionsRequestToChatCompletion(request: JsonObject): JsonObject {\n assertSupportedLegacyCompletionRequest(request);\n return removeUndefined({\n frequency_penalty: request.frequency_penalty,\n logit_bias: request.logit_bias,\n max_tokens: request.max_tokens,\n messages: [{ content: legacyPromptToText(request.prompt), role: \"user\" }],\n model: normalizeRequestedModel(request.model),\n n: request.n,\n presence_penalty: request.presence_penalty,\n seed: request.seed,\n stop: request.stop,\n stream: request.stream === true,\n stream_options: request.stream_options,\n temperature: request.temperature,\n top_p: request.top_p,\n user: request.user,\n });\n}\n\nexport function normalizeRequestedModel(model: unknown): string {\n const requested = contentToText(model).trim();\n return requested || DEFAULT_MODEL;\n}\n\nexport function chatCompletionToResponse(completion: JsonObject, responseId?: string): JsonObject {\n const id = responseId ?? `resp_${randomId()}`;\n const choice = firstChoice(completion);\n const message = asRecord(choice.message);\n const model = contentToText(completion.model) || DEFAULT_MODEL;\n const output = outputItemsFromMessage(message);\n const usage = responseUsage(completion.usage);\n\n return removeUndefined({\n created_at: epochSeconds(),\n error: null,\n id,\n incomplete_details: null,\n instructions: null,\n max_output_tokens: null,\n metadata: {},\n model,\n object: \"response\",\n output,\n output_text: outputText(output),\n parallel_tool_calls: true,\n status: \"completed\",\n temperature: null,\n tool_choice: \"auto\",\n tools: [],\n top_p: null,\n usage,\n });\n}\n\n/**\n * Reduce a Copilot `/responses` result into the `{ output }` document Codex's\n * remote-compaction client (`POST /responses/compact`) deserializes. Codex keeps\n * only assistant/user message items from `output` and discards everything else,\n * so a Responses `output` array passes through verbatim; when the upstream only\n * exposes `output_text` (or, for a stream it did not honor `stream: false` on,\n * `output_text` deltas) a single assistant message is synthesized instead. The\n * input may be a unary JSON body or an SSE stream, so both framings are handled.\n */\nexport function responsesCompactionResult(upstreamText: string, isSse: boolean): JsonObject {\n const summary = compactionSummaryText(upstreamText, isSse);\n return { output: [compactionSummaryOutputMessageItem(summary)] };\n}\n\nexport function isResponsesCompactionRequest(request: JsonObject): boolean {\n return responseInputItems(request.input).some(\n (item) => contentToText(asRecord(item).type) === \"compaction_trigger\",\n );\n}\n\nexport function responsesCompactionRequestBody(request: JsonObject): string {\n return JSON.stringify(\n removeUndefined({\n ...request,\n input: [\n ...compactionInputItemsForCopilot(request.input),\n {\n content: [{ text: COMPACTION_SUMMARIZATION_PROMPT, type: \"input_text\" }],\n role: \"user\",\n type: \"message\",\n },\n ],\n parallel_tool_calls: false,\n stream: false,\n tool_choice: \"none\",\n tools: [],\n }),\n );\n}\n\nexport function normalizeResponsesRequestForCopilotBody(request: JsonObject): string {\n return JSON.stringify(\n removeUndefined({\n ...request,\n input: normalizeCompactionInputForCopilot(request.input, { dropTrigger: false }),\n }),\n );\n}\n\nexport function responsesRequestNeedsCopilotNormalization(request: JsonObject): boolean {\n return responseInputItems(request.input).some((item) => {\n const type = contentToText(asRecord(item).type);\n return type === \"compaction\" || type === \"compaction_summary\" || type === \"context_compaction\";\n });\n}\n\nexport function responsesCompactionResponse(\n upstreamText: string,\n isSse: boolean,\n model: string,\n): JsonObject {\n const output = [compactionOutputItem(compactionSummaryText(upstreamText, isSse))];\n return removeUndefined({\n created_at: epochSeconds(),\n error: null,\n id: `resp_${randomId()}`,\n incomplete_details: null,\n instructions: null,\n max_output_tokens: null,\n metadata: {},\n model,\n object: \"response\",\n output,\n output_text: \"\",\n parallel_tool_calls: false,\n status: \"completed\",\n temperature: null,\n tool_choice: \"none\",\n tools: [],\n top_p: null,\n });\n}\n\nexport function responsesCompactionSseText(\n upstreamText: string,\n isSse: boolean,\n model: string,\n): string {\n const responseId = `resp_${randomId()}`;\n const item = compactionOutputItem(compactionSummaryText(upstreamText, isSse));\n const createdAt = epochSeconds();\n let sequenceNumber = 0;\n const event = (name: string, data: JsonObject | \"[DONE]\") =>\n encodeSse(name, data === \"[DONE]\" ? data : { ...data, sequence_number: sequenceNumber++ });\n\n return [\n event(\"response.created\", {\n response: baseStreamResponse(responseId, model, createdAt, \"in_progress\", []),\n type: \"response.created\",\n }),\n event(\"response.output_item.done\", {\n item,\n output_index: 0,\n type: \"response.output_item.done\",\n }),\n event(\"response.completed\", {\n response: baseStreamResponse(responseId, model, createdAt, \"completed\", [item]),\n type: \"response.completed\",\n }),\n event(\"done\", \"[DONE]\"),\n ].join(\"\");\n}\n\nfunction compactionSummaryText(upstreamText: string, isSse: boolean): string {\n const summary = isSse\n ? compactionSummaryTextFromResponsesSse(upstreamText)\n : compactionSummaryTextFromResponse(asRecord(safeJsonParse(upstreamText)));\n return summary.trim() || \"(no summary available)\";\n}\n\nfunction compactionSummaryTextFromResponse(response: JsonObject): string {\n const output = Array.isArray(response.output)\n ? response.output.map((item) => asRecord(item))\n : [];\n const compaction = output.find((item) => contentToText(item.type) === \"compaction\");\n if (compaction) {\n return contentToText(compaction.encrypted_content);\n }\n const text = outputText(output);\n if (text) {\n return text;\n }\n return contentToText(response.output_text);\n}\n\nfunction compactionSummaryTextFromResponsesSse(text: string): string {\n let deltas = \"\";\n let completedResponse: JsonObject | undefined;\n for (const block of text.split(/\\r?\\n\\r?\\n/)) {\n const data = block\n .split(/\\r?\\n/)\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trim())\n .join(\"\");\n if (!data || data === \"[DONE]\") {\n continue;\n }\n const record = asRecord(safeJsonParse(data));\n const type = contentToText(record.type);\n if (type === \"response.output_text.delta\") {\n deltas += contentToText(record.delta);\n } else if (type === \"response.completed\" || type === \"response.incomplete\") {\n completedResponse = asRecord(record.response);\n }\n }\n if (completedResponse) {\n const summary = compactionSummaryTextFromResponse(completedResponse);\n if (summary) {\n return summary;\n }\n }\n return deltas;\n}\n\nexport function chatCompletionToCompletion(completion: JsonObject): JsonObject {\n return removeUndefined({\n choices: completionChoices(completion).map((choice, index) => {\n const message = asRecord(choice.message);\n return {\n finish_reason: choice.finish_reason ?? \"stop\",\n index: typeof choice.index === \"number\" ? choice.index : index,\n logprobs: choice.logprobs ?? null,\n text: contentToText(choice.text) || contentToText(message.content),\n };\n }),\n created: completion.created ?? epochSeconds(),\n id: completion.id ?? `cmpl_${randomId()}`,\n model: completion.model ?? DEFAULT_MODEL,\n object: \"text_completion\",\n system_fingerprint: completion.system_fingerprint,\n usage: completion.usage,\n });\n}\n\nexport function completionStreamFromChatStream(\n chatStream: ReadableStream<Uint8Array>,\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let sawTerminalEvent = false;\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueue = (data: JsonObject | \"[DONE]\") => {\n controller.enqueue(encoder.encode(encodeDataSse(data)));\n };\n const markTerminal = () => {\n sawTerminalEvent = true;\n };\n const reader = chatStream.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n buffer += decoder.decode(result.value, { stream: true });\n const blocks = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = blocks.pop() ?? \"\";\n for (const block of blocks) {\n processCompletionSseBlock(block, enqueue, markTerminal);\n }\n }\n const tail = `${buffer}${decoder.decode()}`;\n if (tail.trim()) {\n processCompletionSseBlock(tail, enqueue, markTerminal);\n }\n if (!sawTerminalEvent) {\n enqueue(\"[DONE]\");\n }\n controller.close();\n } catch (error) {\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nexport function completionSseTextFromChatSseText(text: string): string {\n const chunks: string[] = [];\n let sawTerminalEvent = false;\n const enqueue = (data: JsonObject | \"[DONE]\") => {\n chunks.push(encodeDataSse(data));\n };\n const markTerminal = () => {\n sawTerminalEvent = true;\n };\n\n for (const block of text.split(/\\r?\\n\\r?\\n/)) {\n if (block.trim()) {\n processCompletionSseBlock(block, enqueue, markTerminal);\n }\n }\n if (!sawTerminalEvent) {\n enqueue(\"[DONE]\");\n }\n return chunks.join(\"\");\n}\n\nexport function normalizeModelsResponse(upstream: unknown): JsonObject {\n const record = asRecord(upstream);\n const data = Array.isArray(record.data) ? record.data : Array.isArray(upstream) ? upstream : [];\n const models = data\n .map((model) => asRecord(model))\n .filter((model) => typeof model.id === \"string\")\n .map((model) => ({\n created: model.created ?? 0,\n id: model.id,\n object: \"model\",\n owned_by: model.owned_by ?? \"github-copilot\",\n }));\n\n return {\n data: models.length > 0 ? models : fallbackModels(),\n object: \"list\",\n };\n}\n\nexport function fallbackModels(): Array<JsonObject> {\n return [\n {\n created: 0,\n id: DEFAULT_MODEL,\n object: \"model\",\n owned_by: \"github-copilot\",\n },\n ];\n}\n\nexport function responsesStreamFromChatStream(\n chatStream: ReadableStream<Uint8Array>,\n options: ResponseStreamOptions,\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const decoder = new TextDecoder();\n const responseId = options.responseId ?? `resp_${randomId()}`;\n const messageId = `msg_${randomId()}`;\n const createdAt = epochSeconds();\n let buffer = \"\";\n let text = \"\";\n let messageOutputIndex: number | undefined;\n let nextOutputIndex = 0;\n let sequenceNumber = 0;\n const tools = new Map<number, AccumulatedToolCall>();\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueue = (event: string, data: JsonObject | \"[DONE]\") => {\n controller.enqueue(\n encoder.encode(\n encodeSse(\n event,\n data === \"[DONE]\" ? data : { ...data, sequence_number: sequenceNumber++ },\n ),\n ),\n );\n };\n\n enqueue(\"response.created\", {\n response: baseStreamResponse(responseId, options.model, createdAt, \"in_progress\", []),\n type: \"response.created\",\n });\n\n const ensureMessageStarted = () => {\n if (messageOutputIndex !== undefined) {\n return;\n }\n messageOutputIndex = nextOutputIndex++;\n enqueue(\"response.output_item.added\", {\n item: {\n content: [],\n id: messageId,\n role: \"assistant\",\n status: \"in_progress\",\n type: \"message\",\n },\n output_index: messageOutputIndex,\n type: \"response.output_item.added\",\n });\n enqueue(\"response.content_part.added\", {\n content_index: 0,\n item_id: messageId,\n output_index: messageOutputIndex,\n part: {\n annotations: [],\n text: \"\",\n type: \"output_text\",\n },\n type: \"response.content_part.added\",\n });\n };\n\n const appendText = (delta: string) => {\n ensureMessageStarted();\n text += delta;\n enqueue(\"response.output_text.delta\", {\n content_index: 0,\n delta,\n item_id: messageId,\n output_index: messageOutputIndex ?? 0,\n type: \"response.output_text.delta\",\n });\n };\n\n const appendToolCall = (toolCall: JsonObject) => {\n const fn = asRecord(toolCall.function);\n const index = typeof toolCall.index === \"number\" ? toolCall.index : tools.size;\n let existing = tools.get(index);\n const isNew = !existing;\n existing ??= {\n arguments: \"\",\n id: contentToText(toolCall.id) || `call_${randomId()}`,\n index,\n itemId: `fc_${randomId()}`,\n name: \"\",\n outputIndex: nextOutputIndex++,\n };\n existing.id = contentToText(toolCall.id) || existing.id;\n existing.name += contentToText(fn.name);\n tools.set(index, existing);\n\n if (isNew) {\n enqueue(\"response.output_item.added\", {\n item: functionCallItem(existing, \"in_progress\"),\n output_index: existing.outputIndex,\n type: \"response.output_item.added\",\n });\n }\n\n const argumentDelta = contentToText(fn.arguments);\n if (argumentDelta) {\n existing.arguments += argumentDelta;\n enqueue(\"response.function_call_arguments.delta\", {\n delta: argumentDelta,\n item_id: existing.itemId,\n output_index: existing.outputIndex,\n type: \"response.function_call_arguments.delta\",\n });\n }\n };\n\n const reader = chatStream.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n buffer += decoder.decode(result.value, { stream: true });\n const lines = buffer.split(/\\r?\\n/);\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n processChatSseLine(line, { appendText, appendToolCall });\n }\n }\n if (buffer) {\n processChatSseLine(buffer, { appendText, appendToolCall });\n }\n\n // Build the output items once so the ids emitted in the per-tool stream\n // events match the ids embedded in the final response.completed payload.\n const outputEntries: Array<[number, JsonObject]> = [];\n if (messageOutputIndex !== undefined) {\n const item = messageOutputItem(text, messageId);\n outputEntries.push([messageOutputIndex, item]);\n enqueue(\"response.output_text.done\", {\n content_index: 0,\n item_id: messageId,\n output_index: messageOutputIndex,\n text,\n type: \"response.output_text.done\",\n });\n enqueue(\"response.content_part.done\", {\n content_index: 0,\n item_id: messageId,\n output_index: messageOutputIndex,\n part: {\n annotations: [],\n text,\n type: \"output_text\",\n },\n type: \"response.content_part.done\",\n });\n enqueue(\"response.output_item.done\", {\n item,\n output_index: messageOutputIndex,\n type: \"response.output_item.done\",\n });\n }\n\n for (const tool of [...tools.values()].sort((a, b) => a.outputIndex - b.outputIndex)) {\n const item = functionCallItem(tool);\n const outputIndex = tool.outputIndex;\n outputEntries.push([outputIndex, item]);\n enqueue(\"response.function_call_arguments.done\", {\n arguments: tool.arguments,\n item_id: item.id,\n output_index: outputIndex,\n type: \"response.function_call_arguments.done\",\n });\n enqueue(\"response.output_item.done\", {\n item,\n output_index: outputIndex,\n type: \"response.output_item.done\",\n });\n }\n\n const output = outputEntries\n .sort(([left], [right]) => left - right)\n .map(([, item]) => item);\n\n enqueue(\"response.completed\", {\n response: baseStreamResponse(responseId, options.model, createdAt, \"completed\", output),\n type: \"response.completed\",\n });\n enqueue(\"done\", \"[DONE]\");\n controller.close();\n } catch (error) {\n // Tear down the upstream body so an output-side error/abort cannot leak it.\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nfunction inputToMessages(input: unknown): JsonObject[] {\n if (typeof input === \"string\") {\n return [{ content: input, role: \"user\" }];\n }\n if (!Array.isArray(input)) {\n return [];\n }\n\n const messages: JsonObject[] = [];\n for (const item of input) {\n const record = asRecord(item);\n const type = contentToText(record.type);\n if (type === \"function_call_output\") {\n messages.push({\n content: contentToText(record.output),\n role: \"tool\",\n tool_call_id: contentToText(record.call_id),\n });\n continue;\n }\n if (type === \"function_call\") {\n messages.push({\n role: \"assistant\",\n tool_calls: [\n {\n function: {\n arguments: contentToText(record.arguments),\n name: contentToText(record.name),\n },\n id: contentToText(record.call_id) || contentToText(record.id),\n type: \"function\",\n },\n ],\n });\n continue;\n }\n if (type && type !== \"message\") {\n unsupportedResponsesFeature(`input item type \"${type}\"`);\n }\n const role = responsesRoleToChatRole(contentToText(record.role));\n const content = chatMessageContent(record.content);\n if (role && content !== undefined) {\n messages.push({ content, role });\n }\n }\n return messages;\n}\n\nfunction chatMessageContent(content: unknown): string | Array<JsonObject> | undefined {\n if (typeof content === \"string\") {\n return content;\n }\n if (!Array.isArray(content)) {\n if (content === undefined || content === null) {\n return undefined;\n }\n unsupportedResponsesFeature(\"non-array message content objects\");\n }\n\n const parts: JsonObject[] = [];\n for (const part of content) {\n const record = asRecord(part);\n const type = contentToText(record.type);\n if (type === \"input_text\" || type === \"output_text\" || type === \"text\") {\n parts.push({ text: contentToText(record.text), type: \"text\" });\n continue;\n }\n if (type === \"input_image\") {\n if (contentToText(record.file_id)) {\n unsupportedResponsesFeature(\"input_image file_id parts\");\n }\n const imageUrl = contentToText(record.image_url);\n if (!imageUrl) {\n unsupportedResponsesFeature(\"input_image parts without image_url\");\n }\n const image: JsonObject = { url: imageUrl };\n const detail = contentToText(record.detail);\n if (detail) {\n image.detail = detail;\n }\n parts.push({ image_url: image, type: \"image_url\" });\n continue;\n }\n if (type === \"input_file\") {\n unsupportedResponsesFeature(\"input_file parts\");\n }\n if (type === \"input_audio\") {\n unsupportedResponsesFeature(\"input_audio parts\");\n }\n unsupportedResponsesFeature(`content part type \"${type || \"unknown\"}\"`);\n }\n\n if (parts.length === 0) {\n return undefined;\n }\n if (parts.every((part) => part.type === \"text\")) {\n return parts.map((part) => contentToText(part.text)).join(\"\\n\");\n }\n return parts;\n}\n\nfunction legacyPromptToText(prompt: unknown): string {\n if (typeof prompt === \"string\") {\n return prompt;\n }\n if (Array.isArray(prompt) && prompt.length === 1 && typeof prompt[0] === \"string\") {\n return prompt[0];\n }\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility supports exactly one string prompt per request.\",\n );\n}\n\nfunction assertSupportedLegacyCompletionRequest(request: JsonObject): void {\n if (request.echo === true) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support echo=true.\",\n );\n }\n if (typeof request.best_of === \"number\" && request.best_of > 1) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support best_of greater than 1.\",\n );\n }\n if (typeof request.logprobs === \"number\" && request.logprobs > 0) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support legacy logprobs.\",\n );\n }\n if (contentToText(request.suffix)) {\n throw new OpenAICompatibilityError(\n \"Hoopilot legacy completions compatibility does not support suffix.\",\n );\n }\n}\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (typeof content === \"number\" || typeof content === \"boolean\") {\n return String(content);\n }\n if (Array.isArray(content)) {\n return content\n .map((item) => contentToText(item))\n .filter(Boolean)\n .join(\"\\n\");\n }\n if (content && typeof content === \"object\") {\n const record = content as Record<string, unknown>;\n if (typeof record.text === \"string\") {\n return record.text;\n }\n if (typeof record.output_text === \"string\") {\n return record.output_text;\n }\n return JSON.stringify(content);\n }\n return \"\";\n}\n\nfunction responsesRoleToChatRole(role: string): string | undefined {\n if (!role) {\n return \"user\";\n }\n if (\n role === \"assistant\" ||\n role === \"developer\" ||\n role === \"system\" ||\n role === \"tool\" ||\n role === \"user\"\n ) {\n return role === \"developer\" ? \"system\" : role;\n }\n unsupportedResponsesFeature(`message role \"${role}\"`);\n}\n\nfunction chatTools(tools: unknown): JsonObject[] | undefined {\n if (!Array.isArray(tools)) {\n return undefined;\n }\n const converted = tools.map((tool) => {\n const record = asRecord(tool);\n const type = contentToText(record.type);\n if (type !== \"function\") {\n unsupportedResponsesFeature(`tool type \"${type || \"unknown\"}\"`);\n }\n return {\n function: removeUndefined({\n description: record.description,\n name: record.name,\n parameters: record.parameters,\n strict: record.strict,\n }),\n type: \"function\",\n };\n });\n return converted.length > 0 ? converted : undefined;\n}\n\nfunction chatToolChoice(toolChoice: unknown): unknown {\n if (typeof toolChoice === \"string\" || toolChoice === undefined) {\n return toolChoice;\n }\n const record = asRecord(toolChoice);\n const type = contentToText(record.type);\n if (type === \"function\" && typeof record.name === \"string\") {\n return { function: { name: record.name }, type: \"function\" };\n }\n unsupportedResponsesFeature(`tool_choice type \"${type || \"unknown\"}\"`);\n}\n\nfunction unsupportedResponsesFeature(feature: string): never {\n throw new OpenAICompatibilityError(\n `Hoopilot Responses-to-chat compatibility does not support ${feature}.`,\n );\n}\n\nfunction outputItemsFromMessage(message: Record<string, unknown>): JsonObject[] {\n const output: JsonObject[] = [];\n const text = contentToText(message.content);\n if (text) {\n output.push(messageOutputItem(text));\n }\n const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];\n for (const toolCall of toolCalls) {\n const record = asRecord(toolCall);\n const fn = asRecord(record.function);\n output.push(\n functionCallItem({\n arguments: contentToText(fn.arguments),\n id: contentToText(record.id) || `call_${randomId()}`,\n name: contentToText(fn.name),\n }),\n );\n }\n return output;\n}\n\nfunction messageOutputItem(text: string, id = `msg_${randomId()}`): JsonObject {\n return {\n content: [\n {\n annotations: [],\n text,\n type: \"output_text\",\n },\n ],\n id,\n role: \"assistant\",\n status: \"completed\",\n type: \"message\",\n };\n}\n\nfunction compactionSummaryOutputMessageItem(text: string): JsonObject {\n return compactionSummaryMessageItem(text, `msg_${randomId()}`);\n}\n\nfunction compactionSummaryInputMessageItem(text: string): JsonObject {\n return compactionSummaryMessageItem(text);\n}\n\nfunction compactionSummaryMessageItem(text: string, id?: string): JsonObject {\n return removeUndefined({\n content: [\n {\n text: `${COMPACTION_SUMMARY_PREFIX}\\n${text}`,\n type: \"input_text\",\n },\n ],\n id,\n role: \"user\",\n type: \"message\",\n });\n}\n\nfunction compactionOutputItem(text: string, id = `cmpct_${randomId()}`): JsonObject {\n return {\n encrypted_content: text,\n id,\n type: \"compaction\",\n };\n}\n\nfunction normalizeCompactionInputForCopilot(\n input: unknown,\n options: { dropTrigger: boolean },\n): unknown {\n const items = responseInputItems(input);\n if (items.length === 0) {\n return input;\n }\n\n const normalized: unknown[] = [];\n for (const item of items) {\n const record = asRecord(item);\n const type = contentToText(record.type);\n if (type === \"compaction_trigger\" && options.dropTrigger) {\n continue;\n }\n if (type === \"compaction\" || type === \"compaction_summary\" || type === \"context_compaction\") {\n const text = contentToText(record.encrypted_content);\n if (text) {\n normalized.push(compactionSummaryInputMessageItem(text));\n }\n continue;\n }\n normalized.push(item);\n }\n return normalized;\n}\n\nfunction compactionInputItemsForCopilot(input: unknown): unknown[] {\n if (Array.isArray(input)) {\n return normalizeCompactionInputForCopilot(input, { dropTrigger: true }) as unknown[];\n }\n const text = contentToText(input);\n return text\n ? [\n {\n content: [{ text, type: \"input_text\" }],\n role: \"user\",\n type: \"message\",\n },\n ]\n : [];\n}\n\nfunction responseInputItems(input: unknown): unknown[] {\n return Array.isArray(input) ? input : [];\n}\n\nfunction functionCallItem(\n tool: { arguments: string; id: string; itemId?: string; name: string },\n status: \"in_progress\" | \"completed\" = \"completed\",\n): JsonObject {\n return {\n arguments: tool.arguments,\n call_id: tool.id,\n id: tool.itemId ?? `fc_${randomId()}`,\n name: tool.name,\n status,\n type: \"function_call\",\n };\n}\n\nfunction outputText(output: JsonObject[]): string {\n return output\n .flatMap((item) => {\n const content = item.content;\n return Array.isArray(content) ? content : [];\n })\n .map((part) => contentToText(asRecord(part).text))\n .filter(Boolean)\n .join(\"\");\n}\n\nfunction responseUsage(usage: unknown): JsonObject | null {\n const record = asRecord(usage);\n if (Object.keys(record).length === 0) {\n return null;\n }\n const inputTokens = record.prompt_tokens;\n const outputTokens = record.completion_tokens;\n return removeUndefined({\n input_tokens: inputTokens,\n input_tokens_details: responseUsageDetails(record.prompt_tokens_details, inputTokens, {\n cached_tokens: 0,\n }),\n output_tokens: outputTokens,\n output_tokens_details: responseUsageDetails(record.completion_tokens_details, outputTokens, {\n reasoning_tokens: 0,\n }),\n total_tokens: record.total_tokens,\n });\n}\n\nfunction responseUsageDetails(\n value: unknown,\n tokenCount: unknown,\n fallback: JsonObject,\n): JsonObject | undefined {\n const record = asRecord(value);\n if (Object.keys(record).length > 0) {\n return record;\n }\n return typeof tokenCount === \"number\" && Number.isFinite(tokenCount) ? fallback : undefined;\n}\n\n/**\n * Normalize an upstream `usage` object into {@link TokenUsage}. Accepts both the\n * Chat Completions shape (`prompt_tokens`/`completion_tokens`) and the Responses\n * shape (`input_tokens`/`output_tokens`), and pulls nested reasoning/cached\n * details when present. Returns undefined when no token counts are available so\n * callers can distinguish \"no usage reported\" from \"zero tokens\".\n */\nexport function extractTokenUsage(usage: unknown): TokenUsage | undefined {\n const record = asRecord(usage);\n const prompt = firstNumber(record.prompt_tokens, record.input_tokens);\n const completion = firstNumber(record.completion_tokens, record.output_tokens);\n const total = firstNumber(record.total_tokens);\n if (prompt === undefined && completion === undefined && total === undefined) {\n return undefined;\n }\n const promptTokens = prompt ?? 0;\n const completionTokens = completion ?? 0;\n const reasoning = firstNumber(\n asRecord(record.completion_tokens_details).reasoning_tokens,\n asRecord(record.output_tokens_details).reasoning_tokens,\n );\n const cached = firstNumber(\n record.cache_read_input_tokens,\n asRecord(record.prompt_tokens_details).cached_tokens,\n asRecord(record.input_tokens_details).cached_tokens,\n );\n const result: TokenUsage = {\n completionTokens,\n promptTokens,\n totalTokens: total ?? promptTokens + completionTokens,\n };\n if (cached !== undefined) {\n result.cachedTokens = cached;\n }\n if (reasoning !== undefined) {\n result.reasoningTokens = reasoning;\n }\n return result;\n}\n\nfunction firstChoice(completion: JsonObject): Record<string, unknown> {\n return completionChoices(completion)[0] ?? {};\n}\n\nfunction completionChoices(completion: JsonObject): Array<Record<string, unknown>> {\n const choices = Array.isArray(completion.choices) ? completion.choices : [];\n return choices.map((choice) => asRecord(choice));\n}\n\nfunction processCompletionSseBlock(\n block: string,\n enqueue: (data: JsonObject | \"[DONE]\") => void,\n markTerminal: () => void,\n): void {\n let event = \"message\";\n const dataLines: string[] = [];\n for (const line of block.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"event:\")) {\n event = trimmed.slice(\"event:\".length).trim() || event;\n } else if (trimmed.startsWith(\"data:\")) {\n dataLines.push(trimmed.slice(\"data:\".length).trim());\n }\n }\n const data = dataLines.join(\"\\n\");\n if (!data) {\n return;\n }\n if (data === \"[DONE]\") {\n markTerminal();\n enqueue(\"[DONE]\");\n return;\n }\n\n const parsed = parseJsonObject(data);\n if (!parsed) {\n return;\n }\n const error = completionStreamError(event, parsed);\n if (error) {\n markTerminal();\n enqueue({ error });\n return;\n }\n const choices = completionChoices(parsed)\n .map((choice, index) => {\n const delta = asRecord(choice.delta);\n const text = contentToText(delta.content);\n const finishReason = choice.finish_reason ?? null;\n if (!text && finishReason === null) {\n return undefined;\n }\n return {\n finish_reason: finishReason,\n index: typeof choice.index === \"number\" ? choice.index : index,\n logprobs: choice.logprobs ?? null,\n text,\n };\n })\n .filter((choice) => choice !== undefined);\n const usage = asRecord(parsed.usage);\n const hasUsage = Object.keys(usage).length > 0;\n if (choices.length === 0 && !hasUsage) {\n return;\n }\n\n enqueue(\n removeUndefined({\n choices,\n created: typeof parsed.created === \"number\" ? parsed.created : epochSeconds(),\n id: contentToText(parsed.id) || `cmpl_${randomId()}`,\n model: contentToText(parsed.model) || DEFAULT_MODEL,\n object: \"text_completion\",\n usage: hasUsage ? usage : undefined,\n }),\n );\n}\n\nfunction completionStreamError(event: string, parsed: JsonObject): JsonObject | undefined {\n const responseError = asRecord(asRecord(parsed.response).error);\n const directError = asRecord(parsed.error);\n const error =\n Object.keys(directError).length > 0\n ? directError\n : Object.keys(responseError).length > 0\n ? responseError\n : undefined;\n if (error) {\n return error;\n }\n if (event === \"error\" || parsed.type === \"response.failed\") {\n return removeUndefined({\n code: contentToText(parsed.code) || undefined,\n message: contentToText(parsed.message) || \"Upstream streaming request failed.\",\n type: contentToText(parsed.type) || \"upstream_stream_error\",\n });\n }\n return undefined;\n}\n\nfunction processChatSseLine(\n line: string,\n handlers: {\n appendText: (delta: string) => void;\n appendToolCall: (toolCall: JsonObject) => void;\n },\n): void {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) {\n return;\n }\n const data = trimmed.slice(\"data:\".length).trim();\n if (!data || data === \"[DONE]\") {\n return;\n }\n\n const parsed = parseJsonObject(data);\n if (!parsed) {\n return;\n }\n const choice = firstChoice(parsed);\n const delta = asRecord(choice.delta);\n const content = contentToText(delta.content);\n if (content) {\n handlers.appendText(content);\n }\n\n const toolCalls = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];\n for (const toolCall of toolCalls) {\n handlers.appendToolCall(asRecord(toolCall));\n }\n}\n\nfunction baseStreamResponse(\n id: string,\n model: string,\n createdAt: number,\n status: \"in_progress\" | \"completed\",\n output: JsonObject[],\n): JsonObject {\n return {\n created_at: createdAt,\n error: null,\n id,\n incomplete_details: null,\n instructions: null,\n max_output_tokens: null,\n metadata: {},\n model,\n object: \"response\",\n output,\n parallel_tool_calls: true,\n status,\n temperature: null,\n tool_choice: \"auto\",\n tools: [],\n top_p: null,\n };\n}\n\nfunction encodeSse(event: string, data: JsonObject | \"[DONE]\"): string {\n if (data === \"[DONE]\") {\n return \"data: [DONE]\\n\\n\";\n }\n return `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n}\n\nfunction encodeDataSse(data: JsonObject | \"[DONE]\"): string {\n if (data === \"[DONE]\") {\n return \"data: [DONE]\\n\\n\";\n }\n return `data: ${JSON.stringify(data)}\\n\\n`;\n}\n\nfunction epochSeconds(): number {\n return Math.floor(Date.now() / 1000);\n}\n","import { normalizeRequestedModel } from \"./openai\";\nimport type { JsonObject } from \"./types\";\nimport { asRecord, firstNumber, parseJsonObject, randomId, removeUndefined } from \"./util\";\n\ninterface AnthropicStreamOptions {\n model: string;\n messageId?: string;\n}\n\ninterface StreamBlock {\n index: number;\n sentText: string;\n stopped: boolean;\n type: \"text\" | \"tool_use\";\n}\n\ninterface AnthropicStreamState {\n blocks: Map<string, StreamBlock>;\n completed: boolean;\n messageId: string;\n model: string;\n nextBlockIndex: number;\n sawToolUse: boolean;\n started: boolean;\n usage: JsonObject;\n}\n\nexport class AnthropicCompatibilityError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AnthropicCompatibilityError\";\n }\n}\n\nexport function anthropicMessagesToResponsesRequest(request: JsonObject): JsonObject {\n const system = anthropicSystemToResponses(request.system);\n const response = removeUndefined({\n input: [...system.input, ...anthropicMessagesToResponsesInput(request.messages)],\n instructions: system.instructions,\n max_output_tokens:\n typeof request.max_tokens === \"number\" && Number.isFinite(request.max_tokens)\n ? request.max_tokens\n : undefined,\n metadata: request.metadata,\n model: normalizeRequestedModel(request.model),\n parallel_tool_calls: asRecord(request.tool_choice).disable_parallel_tool_use !== true,\n reasoning: anthropicThinkingToReasoning(request.thinking),\n stop: anthropicStopSequences(request.stop_sequences),\n stream: request.stream === true,\n temperature: request.temperature,\n tool_choice: anthropicToolChoice(request.tool_choice),\n tools: anthropicTools(request.tools),\n top_p: request.top_p,\n });\n applyCacheControlToLastBlock(response, anthropicCacheControl(request.cache_control));\n return response;\n}\n\nexport function responsesResponseToAnthropicMessage(\n response: JsonObject,\n fallbackModel: string,\n): JsonObject {\n const content = anthropicContentFromResponsesOutput(response);\n const usage = anthropicUsage(response.usage);\n return {\n content,\n id: textValue(response.id) || `msg_${randomId()}`,\n model: textValue(response.model) || fallbackModel,\n role: \"assistant\",\n stop_reason: anthropicStopReason(response, content),\n stop_sequence: null,\n type: \"message\",\n usage,\n };\n}\n\nexport function responsesStreamToAnthropicStream(\n stream: ReadableStream<Uint8Array>,\n options: AnthropicStreamOptions,\n): ReadableStream<Uint8Array> {\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n let buffer = \"\";\n const state = createAnthropicStreamState(options);\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const enqueue = (event: string, data: JsonObject) => {\n controller.enqueue(encoder.encode(encodeSse(event, data)));\n };\n const reader = stream.getReader();\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) {\n break;\n }\n buffer += decoder.decode(result.value, { stream: true });\n const blocks = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = blocks.pop() ?? \"\";\n for (const block of blocks) {\n processResponsesSseBlock(block, state, enqueue);\n }\n }\n const tail = `${buffer}${decoder.decode()}`;\n if (tail.trim()) {\n processResponsesSseBlock(tail, state, enqueue);\n }\n finishAnthropicStream(state, enqueue);\n controller.close();\n } catch (error) {\n await reader.cancel(error).catch(() => {});\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n\nexport function responsesSseTextToAnthropicSseText(\n text: string,\n options: AnthropicStreamOptions,\n): string {\n const chunks: string[] = [];\n const state = createAnthropicStreamState(options);\n const enqueue = (event: string, data: JsonObject) => {\n chunks.push(encodeSse(event, data));\n };\n\n for (const block of text.split(/\\r?\\n\\r?\\n/)) {\n if (block.trim()) {\n processResponsesSseBlock(block, state, enqueue);\n }\n }\n finishAnthropicStream(state, enqueue);\n return chunks.join(\"\");\n}\n\nexport function estimateAnthropicMessageTokens(request: JsonObject): JsonObject {\n const chars =\n estimatedTextSize(request.system) +\n estimatedTextSize(request.messages) +\n estimatedTextSize(request.tools) +\n estimatedTextSize(request.tool_choice) +\n estimatedTextSize(request.thinking);\n const messageCount = Array.isArray(request.messages) ? request.messages.length : 1;\n const toolCount = Array.isArray(request.tools) ? request.tools.length : 0;\n const inputTokens = Math.max(1, Math.ceil(chars / 4) + messageCount * 4 + toolCount * 16);\n return {\n input_tokens: inputTokens,\n total_tokens: inputTokens,\n };\n}\n\nfunction createAnthropicStreamState(options: AnthropicStreamOptions): AnthropicStreamState {\n return {\n blocks: new Map(),\n completed: false,\n messageId: options.messageId ?? `msg_${randomId()}`,\n model: options.model,\n nextBlockIndex: 0,\n sawToolUse: false,\n started: false,\n usage: anthropicUsage(undefined),\n };\n}\n\nfunction anthropicMessagesToResponsesInput(messages: unknown): JsonObject[] {\n if (!Array.isArray(messages)) {\n throw new AnthropicCompatibilityError(\"Anthropic Messages requests require messages[].\");\n }\n\n const input: JsonObject[] = [];\n let fallbackToolCallIndex = 0;\n for (const message of messages) {\n const record = asRecord(message);\n const role = anthropicRole(record.role);\n const parts = anthropicContentParts(record.content);\n const messageParts: JsonObject[] = [];\n const flushMessage = () => {\n if (messageParts.length === 0) {\n return;\n }\n input.push({\n content: [...messageParts],\n role,\n type: \"message\",\n });\n messageParts.length = 0;\n };\n\n for (const part of parts) {\n const type = textValue(part.type) || \"text\";\n if (type === \"text\") {\n const text = textValue(part.text);\n if (text) {\n messageParts.push(\n removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n text,\n type: role === \"assistant\" ? \"output_text\" : \"input_text\",\n }),\n );\n }\n continue;\n }\n if (type === \"image\") {\n if (role !== \"user\") {\n throw new AnthropicCompatibilityError(\n \"Anthropic image content is only supported for user messages.\",\n );\n }\n messageParts.push(anthropicImageToResponsesPart(part));\n continue;\n }\n if (type === \"tool_use\") {\n flushMessage();\n input.push(\n removeUndefined({\n arguments: JSON.stringify(asRecord(part.input)),\n cache_control: anthropicCacheControl(part.cache_control),\n call_id: textValue(part.id) || `call_hoopilot_${fallbackToolCallIndex++}`,\n name: textValue(part.name),\n type: \"function_call\",\n }),\n );\n continue;\n }\n if (type === \"tool_result\") {\n flushMessage();\n input.push(\n removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n call_id: textValue(part.tool_use_id),\n output: anthropicToolResultOutput(part.content),\n type: \"function_call_output\",\n }),\n );\n continue;\n }\n if (type === \"thinking\" || type === \"redacted_thinking\") {\n continue;\n }\n throw new AnthropicCompatibilityError(\n `Anthropic content block type \"${type}\" is not supported.`,\n );\n }\n flushMessage();\n }\n return input;\n}\n\nfunction anthropicRole(value: unknown): \"assistant\" | \"user\" {\n const role = textValue(value);\n if (role === \"assistant\" || role === \"user\") {\n return role;\n }\n if (!role) {\n return \"user\";\n }\n throw new AnthropicCompatibilityError(`Anthropic message role \"${role}\" is not supported.`);\n}\n\nfunction anthropicContentParts(content: unknown): JsonObject[] {\n if (typeof content === \"string\") {\n return [{ text: content, type: \"text\" }];\n }\n if (Array.isArray(content)) {\n return content.map((part) =>\n typeof part === \"string\" ? { text: part, type: \"text\" } : asRecord(part),\n );\n }\n if (content === undefined || content === null) {\n return [];\n }\n return [asRecord(content)];\n}\n\nfunction anthropicImageToResponsesPart(part: JsonObject): JsonObject {\n const source = asRecord(part.source);\n const sourceType = textValue(source.type);\n if (sourceType === \"base64\") {\n const mediaType = textValue(source.media_type) || \"image/png\";\n const data = textValue(source.data);\n if (!data) {\n throw new AnthropicCompatibilityError(\"Anthropic base64 image content requires source.data.\");\n }\n return removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n detail: \"auto\",\n image_url: `data:${mediaType};base64,${data}`,\n type: \"input_image\",\n });\n }\n if (sourceType === \"url\") {\n const url = textValue(source.url);\n if (!url) {\n throw new AnthropicCompatibilityError(\"Anthropic URL image content requires source.url.\");\n }\n return removeUndefined({\n cache_control: anthropicCacheControl(part.cache_control),\n detail: \"auto\",\n image_url: url,\n type: \"input_image\",\n });\n }\n throw new AnthropicCompatibilityError(\n `Anthropic image source type \"${sourceType || \"unknown\"}\" is not supported.`,\n );\n}\n\nfunction anthropicToolResultOutput(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n const record = asRecord(part);\n return textValue(record.text) || textValue(record.content) || JSON.stringify(part);\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n if (content === undefined || content === null) {\n return \"\";\n }\n return typeof content === \"object\" ? JSON.stringify(content) : String(content);\n}\n\nfunction anthropicSystemToResponses(system: unknown): {\n input: JsonObject[];\n instructions?: string;\n} {\n if (typeof system === \"string\") {\n return { input: [], instructions: system || undefined };\n }\n if (!Array.isArray(system)) {\n return { input: [] };\n }\n const parts = system\n .map((part) => anthropicSystemPartToResponsesPart(part))\n .filter((part): part is JsonObject => part !== undefined);\n if (parts.length === 0) {\n return { input: [] };\n }\n if (parts.some((part) => part.cache_control !== undefined)) {\n return {\n input: [\n {\n content: parts,\n role: \"system\",\n type: \"message\",\n },\n ],\n };\n }\n const text = parts\n .map((part) => textValue(part.text))\n .filter(Boolean)\n .join(\"\\n\");\n return { input: [], instructions: text || undefined };\n}\n\nfunction anthropicSystemPartToResponsesPart(part: unknown): JsonObject | undefined {\n const record = asRecord(part);\n const text = textValue(record.text) || textValue(part);\n if (!text) {\n return undefined;\n }\n return removeUndefined({\n cache_control: anthropicCacheControl(record.cache_control),\n text,\n type: \"input_text\",\n });\n}\n\nfunction anthropicTools(tools: unknown): JsonObject[] | undefined {\n if (!Array.isArray(tools)) {\n return undefined;\n }\n const converted = tools.map((tool) => {\n const record = asRecord(tool);\n return removeUndefined({\n cache_control: anthropicCacheControl(record.cache_control),\n description: record.description,\n name: record.name,\n parameters: record.input_schema,\n strict: record.strict,\n type: \"function\",\n });\n });\n return converted.length > 0 ? converted : undefined;\n}\n\nfunction anthropicCacheControl(value: unknown): JsonObject | undefined {\n if (value === undefined || value === null) {\n return undefined;\n }\n const record = asRecord(value);\n const type = textValue(record.type);\n if (type !== \"ephemeral\") {\n throw new AnthropicCompatibilityError(\n `Anthropic cache_control type \"${type || \"unknown\"}\" is not supported.`,\n );\n }\n const ttl = textValue(record.ttl);\n if (ttl && ttl !== \"5m\" && ttl !== \"1h\") {\n throw new AnthropicCompatibilityError(`Anthropic cache_control ttl \"${ttl}\" is not supported.`);\n }\n return removeUndefined({\n ttl: ttl || undefined,\n type,\n });\n}\n\nfunction applyCacheControlToLastBlock(request: JsonObject, cacheControl: JsonObject | undefined) {\n if (!cacheControl) {\n return;\n }\n const input = Array.isArray(request.input) ? request.input : [];\n for (let itemIndex = input.length - 1; itemIndex >= 0; itemIndex -= 1) {\n const item = asRecord(input[itemIndex]);\n const content = Array.isArray(item.content) ? item.content : [];\n for (let partIndex = content.length - 1; partIndex >= 0; partIndex -= 1) {\n const part = asRecord(content[partIndex]);\n if (part.cache_control === undefined && isCacheableResponsesPart(part)) {\n part.cache_control = cacheControl;\n return;\n }\n }\n }\n const tools = Array.isArray(request.tools) ? request.tools : [];\n for (let index = tools.length - 1; index >= 0; index -= 1) {\n const tool = asRecord(tools[index]);\n if (tool.cache_control === undefined) {\n tool.cache_control = cacheControl;\n return;\n }\n }\n}\n\nfunction isCacheableResponsesPart(part: JsonObject): boolean {\n const type = textValue(part.type);\n return (\n type === \"input_text\" || type === \"output_text\" || type === \"text\" || type === \"input_image\"\n );\n}\n\nfunction anthropicToolChoice(toolChoice: unknown): unknown {\n if (toolChoice === undefined || toolChoice === null) {\n return undefined;\n }\n const record = asRecord(toolChoice);\n const type = textValue(record.type);\n if (type === \"auto\") {\n return \"auto\";\n }\n if (type === \"any\") {\n return \"required\";\n }\n if (type === \"none\") {\n return \"none\";\n }\n if (type === \"tool\") {\n return { name: textValue(record.name), type: \"function\" };\n }\n throw new AnthropicCompatibilityError(\n `Anthropic tool_choice type \"${type || \"unknown\"}\" is not supported.`,\n );\n}\n\nfunction anthropicThinkingToReasoning(thinking: unknown): JsonObject | undefined {\n const record = asRecord(thinking);\n if (Object.keys(record).length === 0) {\n return undefined;\n }\n const type = textValue(record.type);\n if (type && type !== \"enabled\") {\n return undefined;\n }\n const budget = typeof record.budget_tokens === \"number\" ? record.budget_tokens : 0;\n return {\n effort: budget >= 16_000 ? \"high\" : budget >= 4_000 ? \"medium\" : \"low\",\n };\n}\n\nfunction anthropicStopSequences(stopSequences: unknown): unknown {\n if (!Array.isArray(stopSequences) || stopSequences.length === 0) {\n return undefined;\n }\n return stopSequences.map((sequence) => textValue(sequence)).filter(Boolean);\n}\n\nfunction anthropicContentFromResponsesOutput(response: JsonObject): JsonObject[] {\n const content: JsonObject[] = [];\n const output = Array.isArray(response.output) ? response.output : [];\n for (const item of output) {\n const record = asRecord(item);\n const type = textValue(record.type);\n if (type === \"message\") {\n const parts = Array.isArray(record.content) ? record.content : [];\n for (const part of parts) {\n const partRecord = asRecord(part);\n const text = textValue(partRecord.text) || textValue(partRecord.output_text);\n if (text) {\n content.push({ text, type: \"text\" });\n }\n }\n continue;\n }\n if (type === \"function_call\") {\n content.push({\n id: textValue(record.call_id) || textValue(record.id) || `call_${randomId()}`,\n input: parseToolInput(textValue(record.arguments)),\n name: textValue(record.name),\n type: \"tool_use\",\n });\n }\n }\n\n if (content.length === 0) {\n const outputText = textValue(response.output_text);\n if (outputText) {\n content.push({ text: outputText, type: \"text\" });\n }\n }\n return content;\n}\n\nfunction anthropicStopReason(response: JsonObject, content: JsonObject[]): string {\n if (content.some((part) => part.type === \"tool_use\")) {\n return \"tool_use\";\n }\n const incompleteReason = textValue(asRecord(response.incomplete_details).reason);\n if (textValue(response.status) === \"incomplete\" || incompleteReason === \"max_output_tokens\") {\n return \"max_tokens\";\n }\n return \"end_turn\";\n}\n\nfunction anthropicUsage(usage: unknown): JsonObject {\n const record = asRecord(usage);\n const inputTokens = firstNumber(record.input_tokens, record.prompt_tokens) ?? 0;\n const outputTokens = firstNumber(record.output_tokens, record.completion_tokens) ?? 0;\n const details = asRecord(record.input_tokens_details);\n return removeUndefined({\n cache_creation_input_tokens: firstNumber(record.cache_creation_input_tokens),\n cache_read_input_tokens:\n firstNumber(record.cache_read_input_tokens, details.cached_tokens) ?? undefined,\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n });\n}\n\nfunction processResponsesSseBlock(\n block: string,\n state: AnthropicStreamState,\n enqueue: (event: string, data: JsonObject) => void,\n): void {\n const { data, event } = parseSseBlock(block);\n if (!data || data === \"[DONE]\") {\n return;\n }\n const parsed = parseJsonObject(data);\n if (!parsed) {\n return;\n }\n const type = textValue(parsed.type) || event;\n if (type === \"response.created\") {\n const response = asRecord(parsed.response);\n state.messageId = textValue(response.id) || state.messageId;\n state.model = textValue(response.model) || state.model;\n startAnthropicMessage(state, enqueue);\n return;\n }\n if (type === \"response.output_item.added\") {\n const item = asRecord(parsed.item);\n if (textValue(item.type) === \"function_call\") {\n ensureToolBlock(state, parsed, item, enqueue);\n }\n return;\n }\n if (type === \"response.output_text.delta\") {\n const blockState = ensureTextBlock(state, parsed, enqueue);\n const delta = textValue(parsed.delta);\n if (delta) {\n blockState.sentText += delta;\n enqueue(\"content_block_delta\", {\n delta: { text: delta, type: \"text_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n return;\n }\n if (type === \"response.output_text.done\" || type === \"response.content_part.done\") {\n const blockState = ensureTextBlock(state, parsed, enqueue);\n const text = textValue(parsed.text) || textValue(asRecord(parsed.part).text);\n if (text && !blockState.sentText) {\n blockState.sentText = text;\n enqueue(\"content_block_delta\", {\n delta: { text, type: \"text_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n stopBlock(blockState, enqueue);\n return;\n }\n if (type === \"response.function_call_arguments.delta\") {\n const blockState = ensureToolBlock(state, parsed, {}, enqueue);\n const delta = textValue(parsed.delta);\n if (delta) {\n blockState.sentText += delta;\n enqueue(\"content_block_delta\", {\n delta: { partial_json: delta, type: \"input_json_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n return;\n }\n if (type === \"response.function_call_arguments.done\") {\n const blockState = ensureToolBlock(state, parsed, {}, enqueue);\n const args = textValue(parsed.arguments);\n if (args && !blockState.sentText) {\n blockState.sentText = args;\n enqueue(\"content_block_delta\", {\n delta: { partial_json: args, type: \"input_json_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n stopBlock(blockState, enqueue);\n return;\n }\n if (type === \"response.output_item.done\") {\n const item = asRecord(parsed.item);\n if (textValue(item.type) === \"function_call\") {\n const blockState = ensureToolBlock(state, parsed, item, enqueue);\n const args = textValue(item.arguments);\n if (args && !blockState.sentText) {\n blockState.sentText = args;\n enqueue(\"content_block_delta\", {\n delta: { partial_json: args, type: \"input_json_delta\" },\n index: blockState.index,\n type: \"content_block_delta\",\n });\n }\n stopBlock(blockState, enqueue);\n }\n return;\n }\n if (type === \"response.completed\") {\n const response = asRecord(parsed.response);\n state.model = textValue(response.model) || state.model;\n state.usage = anthropicUsage(response.usage);\n finishAnthropicStream(state, enqueue);\n return;\n }\n if (type === \"response.failed\" || event === \"error\") {\n const error = asRecord(asRecord(parsed.response).error);\n enqueue(\"error\", {\n error: {\n message: textValue(error.message) || textValue(parsed.message) || \"Upstream stream failed.\",\n type: textValue(error.type) || \"api_error\",\n },\n type: \"error\",\n });\n state.completed = true;\n }\n}\n\nfunction startAnthropicMessage(\n state: AnthropicStreamState,\n enqueue: (event: string, data: JsonObject) => void,\n): void {\n if (state.started) {\n return;\n }\n state.started = true;\n enqueue(\"message_start\", {\n message: {\n content: [],\n id: state.messageId,\n model: state.model,\n role: \"assistant\",\n stop_reason: null,\n stop_sequence: null,\n type: \"message\",\n usage: anthropicUsage(undefined),\n },\n type: \"message_start\",\n });\n}\n\nfunction finishAnthropicStream(\n state: AnthropicStreamState,\n enqueue: (event: string, data: JsonObject) => void,\n): void {\n if (state.completed) {\n return;\n }\n startAnthropicMessage(state, enqueue);\n for (const block of [...state.blocks.values()].sort((left, right) => left.index - right.index)) {\n stopBlock(block, enqueue);\n }\n enqueue(\"message_delta\", {\n delta: {\n stop_reason: state.sawToolUse ? \"tool_use\" : \"end_turn\",\n stop_sequence: null,\n },\n type: \"message_delta\",\n usage: state.usage,\n });\n enqueue(\"message_stop\", { type: \"message_stop\" });\n state.completed = true;\n}\n\nfunction ensureTextBlock(\n state: AnthropicStreamState,\n payload: JsonObject,\n enqueue: (event: string, data: JsonObject) => void,\n): StreamBlock {\n startAnthropicMessage(state, enqueue);\n const key = `text:${indexValue(payload.output_index)}:${indexValue(payload.content_index)}`;\n let block = state.blocks.get(key);\n if (!block) {\n block = { index: state.nextBlockIndex++, sentText: \"\", stopped: false, type: \"text\" };\n state.blocks.set(key, block);\n enqueue(\"content_block_start\", {\n content_block: { text: \"\", type: \"text\" },\n index: block.index,\n type: \"content_block_start\",\n });\n }\n return block;\n}\n\nfunction ensureToolBlock(\n state: AnthropicStreamState,\n payload: JsonObject,\n item: JsonObject,\n enqueue: (event: string, data: JsonObject) => void,\n): StreamBlock {\n startAnthropicMessage(state, enqueue);\n state.sawToolUse = true;\n const key = `tool:${indexValue(payload.output_index)}`;\n let block = state.blocks.get(key);\n if (!block) {\n block = { index: state.nextBlockIndex++, sentText: \"\", stopped: false, type: \"tool_use\" };\n state.blocks.set(key, block);\n enqueue(\"content_block_start\", {\n content_block: {\n id: textValue(item.call_id) || textValue(item.id) || `call_${randomId()}`,\n input: {},\n name: textValue(item.name),\n type: \"tool_use\",\n },\n index: block.index,\n type: \"content_block_start\",\n });\n }\n return block;\n}\n\nfunction stopBlock(block: StreamBlock, enqueue: (event: string, data: JsonObject) => void): void {\n if (block.stopped) {\n return;\n }\n block.stopped = true;\n enqueue(\"content_block_stop\", {\n index: block.index,\n type: \"content_block_stop\",\n });\n}\n\nfunction parseSseBlock(block: string): { data: string; event: string } {\n let event = \"message\";\n const data: string[] = [];\n for (const line of block.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"event:\")) {\n event = trimmed.slice(\"event:\".length).trim() || event;\n } else if (trimmed.startsWith(\"data:\")) {\n data.push(trimmed.slice(\"data:\".length).trim());\n }\n }\n return { data: data.join(\"\\n\"), event };\n}\n\nfunction parseToolInput(argumentsText: string): JsonObject {\n const parsed = parseJsonObject(argumentsText);\n return parsed ?? {};\n}\n\nfunction estimatedTextSize(value: unknown): number {\n if (value === undefined || value === null) {\n return 0;\n }\n if (typeof value === \"string\") {\n return value.length;\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value).length;\n }\n if (Array.isArray(value)) {\n return value.reduce((sum, item) => sum + estimatedTextSize(item), 0);\n }\n if (typeof value === \"object\") {\n return Object.values(value).reduce((sum, item) => sum + estimatedTextSize(item), 0);\n }\n return 0;\n}\n\nfunction textValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return \"\";\n}\n\nfunction indexValue(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction encodeSse(event: string, data: JsonObject): string {\n return `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n}\n","// The hoopilot live dashboard: a single self-contained HTML document served at\n// GET /dashboard. It is intentionally dependency-free — all CSS and JS are inline\n// and there are no external fonts, images, or scripts — so it works fully offline,\n// inside a compiled standalone binary, and behind restrictive proxies. The page\n// polls GET /v1/usage on an interval and renders proxy status + Copilot quota,\n// computing per-second rates client-side from successive snapshots.\n//\n// Authored as a plain string (not a loader-imported asset) so it bundles with zero\n// configuration across `bun run`, tsup/esbuild, and `bun build --compile`. The\n// embedded source therefore avoids backticks and template substitutions.\nexport const DASHBOARD_HTML = `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<meta name=\"color-scheme\" content=\"dark light\" />\n<title>hoopilot · dashboard</title>\n<style>\n:root {\n --bg-0:#0b0e14; --bg-1:#11151c; --bg-2:#171c25; --bg-3:#1f2630;\n --border:#262d38; --border-strong:#37404d;\n --text-0:#e6edf3; --text-1:#9aa7b4; --text-2:#5e6b78; --text-dim:#3a434e; --text-inv:#0b0e14;\n --accent:#4ea1ff; --accent-2:#56d4dd; --accent-soft:rgba(78,161,255,.14);\n --amber:#f5b042;\n --ok:#3fb950; --warn:#d8a13a; --danger:#f0556a; --info:#a371f7; --cache:#7c8cff;\n --spark:#4ea1ff; --spark-fill:color-mix(in srgb, var(--accent) 14%, transparent);\n --grid-line:rgba(255,255,255,.05);\n --flash:color-mix(in srgb, var(--accent) 22%, transparent);\n --flash-up:color-mix(in srgb, var(--ok) 22%, transparent);\n --flash-down:color-mix(in srgb, var(--danger) 22%, transparent);\n --c1:#4ea1ff; --c2:#3fb950; --c3:#d8a13a; --c4:#a371f7; --c5:#56d4dd; --c6:#f0556a;\n --mono: ui-monospace, \"SF Mono\", \"Cascadia Code\", \"JetBrains Mono\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace;\n --sans: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, system-ui, sans-serif;\n}\n@media (prefers-color-scheme: light) {\n :root:not([data-theme=\"dark\"]) {\n --bg-0:#f6f8fa; --bg-1:#ffffff; --bg-2:#f0f3f6; --bg-3:#e9edf1;\n --border:#d0d7de; --border-strong:#b6bec8;\n --text-0:#1f2328; --text-1:#5a6570; --text-2:#8a96a3; --text-dim:#bcc2c9; --text-inv:#ffffff;\n --accent:#0969da; --accent-2:#0a7ea4; --accent-soft:rgba(9,105,218,.12);\n --amber:#b5730a;\n --ok:#1a7f37; --warn:#9a6700; --danger:#cf222e; --info:#8250df; --cache:#5563e0;\n --spark:#0969da; --spark-fill:color-mix(in srgb, var(--accent) 12%, transparent);\n --grid-line:rgba(0,0,0,.06);\n --flash:color-mix(in srgb, var(--accent) 16%, transparent);\n --flash-up:color-mix(in srgb, var(--ok) 16%, transparent);\n --flash-down:color-mix(in srgb, var(--danger) 16%, transparent);\n --c1:#0969da; --c2:#1a7f37; --c3:#9a6700; --c4:#8250df; --c5:#0a7ea4; --c6:#cf222e;\n }\n}\n[data-theme=\"light\"] {\n --bg-0:#f6f8fa; --bg-1:#ffffff; --bg-2:#f0f3f6; --bg-3:#e9edf1;\n --border:#d0d7de; --border-strong:#b6bec8;\n --text-0:#1f2328; --text-1:#5a6570; --text-2:#8a96a3; --text-dim:#bcc2c9; --text-inv:#ffffff;\n --accent:#0969da; --accent-2:#0a7ea4; --accent-soft:rgba(9,105,218,.12);\n --amber:#b5730a;\n --ok:#1a7f37; --warn:#9a6700; --danger:#cf222e; --info:#8250df; --cache:#5563e0;\n --spark:#0969da; --spark-fill:color-mix(in srgb, var(--accent) 12%, transparent);\n --grid-line:rgba(0,0,0,.06);\n --flash:color-mix(in srgb, var(--accent) 16%, transparent);\n --flash-up:color-mix(in srgb, var(--ok) 16%, transparent);\n --flash-down:color-mix(in srgb, var(--danger) 16%, transparent);\n --c1:#0969da; --c2:#1a7f37; --c3:#9a6700; --c4:#8250df; --c5:#0a7ea4; --c6:#cf222e;\n}\n* { box-sizing: border-box; }\nhtml, body { margin:0; padding:0; }\nbody {\n background: var(--bg-0); color: var(--text-0); font-family: var(--sans);\n font-size: 13px; line-height: 1.4; -webkit-font-smoothing: antialiased;\n}\n.mono { font-family: var(--mono); font-variant-numeric: tabular-nums slashed-zero; }\n.num { font-family: var(--mono); font-variant-numeric: tabular-nums slashed-zero; }\n.shell { max-width: 1280px; margin: 0 auto; padding: 0 24px 28px; }\n@media (min-width: 1080px) { .shell { border-left:1px solid var(--border); border-right:1px solid var(--border); } }\n@media (max-width: 680px) { .shell { padding: 0 12px 24px; } }\n\n/* header */\nheader.bar {\n position: sticky; top: 0; z-index: 20; background: var(--bg-1);\n border-bottom: 1px solid var(--border); height: 48px;\n}\n.bar-in { max-width:1280px; margin:0 auto; height:48px; padding:0 24px; display:flex; align-items:center; gap:12px; }\n@media (max-width:680px){ .bar-in{ padding:0 12px; gap:8px; } }\n.wordmark { font-family: var(--mono); font-weight:700; font-size:14px; color:var(--text-0); letter-spacing:-.01em; }\n.caret { display:inline-block; width:7px; height:15px; background:var(--amber); margin-left:3px; vertical-align:-2px; animation: blink 1.1s steps(1) infinite; }\n.chip { font-family: var(--mono); font-size:11px; padding:2px 7px; border-radius:10px; background:var(--bg-3); color:var(--text-1); white-space:nowrap; }\n.chip.plan-pro { background:var(--accent-soft); color:var(--accent); }\n.chip.plan-business { background:color-mix(in srgb, var(--info) 16%, transparent); color:var(--info); }\n.chip.plan-free, .chip.plan-offline { background:var(--bg-3); color:var(--text-2); }\n.spacer { flex:1; }\n.pill { display:inline-flex; align-items:center; gap:6px; font-size:11px; font-family:var(--mono); padding:3px 9px; border-radius:11px; background:var(--bg-3); color:var(--text-1); }\n.dot { width:7px; height:7px; border-radius:50%; background:var(--text-2); flex:none; }\n.pill.live .dot { background:var(--ok); }\n.pill.paused .dot { background:var(--text-2); }\n.pill.reconnect { color:var(--warn); } .pill.reconnect .dot { background:var(--warn); }\n.pill.authkey { color:var(--warn); } .pill.authkey .dot { background:var(--warn); }\n.heartbeat { animation: hb .5s ease-out; }\n.updated { font-family:var(--mono); font-size:11px; color:var(--text-2); white-space:nowrap; }\n.updated.warn { color:var(--warn); } .updated.danger { color:var(--danger); }\n.seg { display:inline-flex; border:1px solid var(--border); border-radius:6px; overflow:hidden; }\n.seg button { background:transparent; color:var(--text-1); border:0; font-family:var(--mono); font-size:11px; padding:3px 8px; cursor:pointer; }\n.seg button + button { border-left:1px solid var(--border); }\n.seg button.active { background:var(--accent); color:var(--text-inv); }\n.iconbtn { background:transparent; border:1px solid var(--border); border-radius:6px; color:var(--text-1); cursor:pointer; font-size:13px; line-height:1; padding:4px 7px; min-width:30px; }\n.iconbtn:hover { background:var(--bg-3); }\nbutton:focus-visible, input:focus-visible, .seg button:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }\n#scanbar { position:absolute; left:0; bottom:-1px; height:1px; width:100%; overflow:hidden; }\n#scanbar::after { content:\"\"; position:absolute; left:0; top:0; height:1px; width:40%;\n background:linear-gradient(90deg, transparent, var(--accent), transparent);\n animation: scan var(--scan-ms, 4000ms) linear infinite; }\nheader.bar.paused #scanbar::after, header.bar.frozen #scanbar::after { animation-play-state:paused; opacity:.35; }\n\n/* disconnect banner */\n#banner { display:none; margin-top:10px; padding:7px 12px; border-radius:5px; font-family:var(--mono); font-size:12px;\n background:color-mix(in srgb, var(--danger) 16%, transparent); color:var(--danger); border:1px solid color-mix(in srgb, var(--danger) 40%, transparent); }\n#banner.ok { background:color-mix(in srgb, var(--ok) 16%, transparent); color:var(--ok); border-color:color-mix(in srgb, var(--ok) 40%, transparent); }\n#banner.show { display:block; }\n\n/* hero strip */\n.hero { display:grid; grid-template-columns:repeat(4,1fr); margin:18px 0 16px; }\n.vital { padding:6px 18px; }\n.vital + .vital { border-left:1px solid var(--border); }\n.vital .eyebrow { font-size:10px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--text-1); }\n.vital .vnum { font-family:var(--mono); font-variant-numeric:tabular-nums slashed-zero; font-weight:600; font-size:clamp(2rem,5vw,3.25rem); line-height:1.02; letter-spacing:-.02em; color:var(--text-0); }\n.vital .vsub { font-size:11px; color:var(--text-2); min-height:14px; }\n.vital .vspark { display:block; width:100%; height:24px; margin-top:4px; }\n.vital.active { }\n.vital.active .eyebrow { color:var(--accent); }\n@media (max-width:1079px){ .hero{ grid-template-columns:repeat(2,1fr); } .vital:nth-child(3){ border-left:0; } .vital:nth-child(n+3){ border-top:1px solid var(--border); padding-top:12px; } }\n@media (max-width:600px){ .hero{ grid-template-columns:1fr; } .vital + .vital{ border-left:0; border-top:1px solid var(--border); } }\n\n/* grid + panels */\n.grid { display:grid; grid-template-columns:repeat(12,1fr); gap:12px; }\n.panel { position:relative; background:var(--bg-1); border:1px solid var(--border); border-radius:4px; padding:16px 12px 12px; min-width:0; }\n.panel > .ptitle { position:absolute; top:-8px; left:10px; padding:0 6px; background:var(--bg-1);\n font-family:var(--mono); font-size:11px; font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:var(--text-1); }\n.span5{ grid-column:span 5; } .span3{ grid-column:span 3; } .span4{ grid-column:span 4; }\n.span7{ grid-column:span 7; } .span8{ grid-column:span 8; }\n@media (max-width:1079px){ .grid{ grid-template-columns:repeat(6,1fr); }\n .span5,.span7,.span8{ grid-column:span 6; } .span3{ grid-column:span 3; } .span4{ grid-column:span 6; } }\n@media (max-width:680px){ .grid{ grid-template-columns:1fr; }\n .span3,.span4,.span5,.span7,.span8{ grid-column:span 1; } }\n\n.headline { font-family:var(--mono); font-variant-numeric:tabular-nums slashed-zero; font-weight:600; font-size:22px; line-height:1.1; }\n.cap { font-size:11px; color:var(--text-2); }\n.stack-bar { display:flex; height:8px; border-radius:4px; overflow:hidden; background:var(--bg-3); margin:8px 0; }\n.stack-bar i { display:block; height:100%; }\n.stack-bar.empty { outline:1px dashed var(--border); background:transparent; }\n\ntable.tbl { width:100%; border-collapse:collapse; font-family:var(--mono); font-variant-numeric:tabular-nums slashed-zero; font-size:12px; }\n.scrollx { overflow-x:auto; }\ntable.tbl th { font-size:10px; font-weight:600; text-transform:uppercase; color:var(--text-2); text-align:right; padding:4px 6px; border-bottom:1px solid var(--border); white-space:nowrap; }\ntable.tbl th.l { text-align:left; }\ntable.tbl td { padding:3px 6px; text-align:right; white-space:nowrap; border-bottom:1px solid color-mix(in srgb, var(--border) 55%, transparent); }\ntable.tbl td.l { text-align:left; max-width:160px; overflow:hidden; text-overflow:ellipsis; }\ntable.tbl tr:hover td { background:var(--bg-2); }\ntable.tbl tr.total td { border-top:1px solid var(--border-strong); border-bottom:0; font-weight:600; color:var(--text-0); }\n.minibar { display:inline-block; height:6px; border-radius:3px; background:var(--accent); vertical-align:middle; min-width:1px; }\n.ghost td { color:var(--text-2); text-align:center; }\n.reasoning { color:var(--info); } .cached { color:var(--cache); }\n\n.legend { display:flex; flex-wrap:wrap; gap:4px 14px; margin-top:8px; }\n.legend .li { display:flex; align-items:center; gap:6px; font-family:var(--mono); font-size:11px; color:var(--text-1); }\n.legend .sw { width:8px; height:8px; border-radius:2px; flex:none; }\n\n.lat-trio { display:flex; gap:18px; align-items:baseline; }\n.lat-trio .b { font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:20px; font-weight:600; }\n.lat-trio .b small { display:block; font-size:10px; font-weight:600; text-transform:uppercase; color:var(--text-2); letter-spacing:.05em; }\n.lat-p95 { color:var(--info); }\n.lat-track { position:relative; height:22px; margin-top:10px; }\n.lat-track .line { position:absolute; top:11px; left:0; right:0; height:1px; background:var(--border); }\n.lat-track .tick { position:absolute; top:5px; width:2px; height:12px; border-radius:1px; }\n.lat-track .tick.p50 { background:var(--accent); } .lat-track .tick.p95 { background:var(--info); }\n.lat-track .tlab { position:absolute; top:-2px; font-family:var(--mono); font-size:9px; color:var(--text-2); transform:translateX(-50%); }\ndetails.routes { margin-top:10px; } details.routes summary { cursor:pointer; font-size:11px; color:var(--text-2); font-family:var(--mono); }\n\n.qrow { margin:10px 0; } .qrow .qhead { display:flex; justify-content:space-between; align-items:baseline; font-size:12px; }\n.qrow .qname { color:var(--text-1); } .qrow .qval { font-family:var(--mono); font-variant-numeric:tabular-nums; color:var(--text-0); }\n.qbar { position:relative; height:8px; border-radius:4px; background:var(--bg-3); margin-top:5px; overflow:hidden; }\n.qbar i { position:absolute; left:0; top:0; height:100%; border-radius:4px; }\n.qbar.over i.ext { background:repeating-linear-gradient(45deg, var(--danger), var(--danger) 3px, transparent 3px, transparent 6px); }\n.inf { font-family:var(--mono); font-size:12px; color:var(--ok); }\n.emptybox { border:1px solid var(--border); border-radius:5px; padding:14px; text-align:center; color:var(--text-2); }\n.emptybox .keyglyph { font-size:20px; color:var(--text-1); }\n.emptybox h4 { margin:8px 0 4px; font-family:var(--sans); font-size:13px; color:var(--text-1); font-weight:600; }\n.emptybox .errline { font-family:var(--mono); font-size:11px; color:var(--text-2); word-break:break-word; margin:4px 0; }\n.prompt { font-family:var(--mono); font-size:12px; color:var(--text-1); }\n\n.upblocks { display:flex; gap:18px; }\n.upblk { } .upblk .v { font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:20px; font-weight:600; }\n.upblk .k { font-size:10px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-2); }\n.upblk.err.hot { color:var(--danger); }\n.rate { font-family:var(--mono); font-size:12px; } .rate.warn{ color:var(--warn);} .rate.danger{ color:var(--danger);} .rate.ok{ color:var(--ok); }\n#up-spark, #thru-svg { display:block; width:100%; }\n#up-spark { height:30px; margin-top:8px; }\n#thru-svg { height:88px; margin-top:6px; }\n.flag { font-family:var(--mono); font-size:10px; color:var(--text-2); }\n\nfooter.foot { margin-top:14px; padding-top:10px; border-top:1px solid var(--border); display:flex; flex-wrap:wrap; gap:4px 14px;\n font-family:var(--mono); font-size:11px; color:var(--text-2); }\nfooter.foot .end { margin-left:auto; }\n@media (max-width:680px){ footer.foot .end{ margin-left:0; } }\n\n.skel { color:var(--text-dim); }\n.flash { animation: flash .6s ease-out; } .flash-up { animation: flashup .6s ease-out; } .flash-down { animation: flashdown .6s ease-out; }\n\n/* auth takeover */\n#auth { display:none; }\n#auth.show { display:flex; justify-content:center; padding:64px 16px; }\n.authcard { width:100%; max-width:420px; background:var(--bg-1); border:1px solid var(--border); border-radius:6px; padding:22px 18px; position:relative; }\n.authcard h3 { margin:0 0 10px; font-family:var(--mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase; color:var(--text-1); }\n.authcard p { font-size:12px; color:var(--text-2); margin:0 0 14px; }\n.authcard .row { display:flex; gap:8px; }\n.authcard input { flex:1; background:var(--bg-0); border:1px solid var(--border); border-radius:5px; color:var(--text-0); font-family:var(--mono); font-size:13px; padding:8px 10px; }\n.authcard input.bad { border-color:var(--danger); }\n.authcard button { background:var(--accent); color:var(--text-inv); border:0; border-radius:5px; font-family:var(--mono); font-size:12px; padding:0 14px; cursor:pointer; }\n.authcard .err { color:var(--danger); font-family:var(--mono); font-size:11px; min-height:14px; margin-top:8px; }\n.authcard .clear { position:absolute; top:14px; right:16px; font-size:11px; color:var(--text-2); cursor:pointer; }\n.dim { opacity:.45; filter:grayscale(.4); transition:opacity .2s, filter .2s; }\n\n@keyframes blink { 50% { opacity:0; } }\n@keyframes scan { 0%{ transform:translateX(-100%);} 100%{ transform:translateX(350%);} }\n@keyframes hb { 0%{ transform:scale(1);} 35%{ transform:scale(1.7);} 100%{ transform:scale(1);} }\n@keyframes flash { from{ background:var(--flash);} to{ background:transparent;} }\n@keyframes flashup { from{ background:var(--flash-up);} to{ background:transparent;} }\n@keyframes flashdown { from{ background:var(--flash-down);} to{ background:transparent;} }\n@media (prefers-reduced-motion: reduce) {\n .caret { animation:none; } #scanbar::after { animation:none; opacity:.3; }\n .heartbeat { animation:none; }\n .flash, .flash-up, .flash-down { animation:none; box-shadow: inset 2px 0 0 var(--accent); }\n}\n</style>\n</head>\n<body>\n<header class=\"bar\" id=\"bar\">\n <div class=\"bar-in\">\n <span class=\"wordmark\">hoopilot<span class=\"caret\" aria-hidden=\"true\"></span></span>\n <span class=\"chip\" id=\"version-chip\">v···</span>\n <span class=\"chip plan-offline\" id=\"plan-chip\">— offline</span>\n <span class=\"spacer\"></span>\n <span class=\"pill\" id=\"conn-pill\" aria-live=\"polite\"><span class=\"dot\" id=\"conn-dot\"></span><span id=\"conn-text\">connecting</span></span>\n <span class=\"updated\" id=\"updated\"></span>\n <span class=\"seg\" id=\"seg\" role=\"group\" aria-label=\"Refresh interval\">\n <button data-ms=\"2000\">2s</button><button data-ms=\"4000\" class=\"active\">4s</button><button data-ms=\"10000\">10s</button>\n </span>\n <button class=\"iconbtn\" id=\"btn-pause\" title=\"Pause / resume\" aria-label=\"Pause or resume\">❚❚</button>\n <button class=\"iconbtn\" id=\"btn-theme\" title=\"Theme: auto / dark / light\" aria-label=\"Cycle theme\">A</button>\n </div>\n <div id=\"scanbar\" aria-hidden=\"true\"></div>\n</header>\n\n<div class=\"shell\">\n <div id=\"banner\" role=\"status\" aria-live=\"polite\"></div>\n\n <section id=\"content\">\n <section class=\"hero\" aria-label=\"Vitals\">\n <div class=\"vital\" id=\"v-req\"><div class=\"eyebrow\">Req / s</div><div class=\"vnum skel\" id=\"req-num\">···</div><div class=\"vsub\" id=\"req-sub\"></div><svg class=\"vspark\" id=\"req-spark\" viewBox=\"0 0 200 24\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--ok)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/><circle r=\"1.6\" fill=\"var(--ok)\" style=\"display:none\"/></svg></div>\n <div class=\"vital\" id=\"v-tok\"><div class=\"eyebrow\">Tokens / s</div><div class=\"vnum skel\" id=\"tok-num\">···</div><div class=\"vsub\" id=\"tok-sub\"></div><svg class=\"vspark\" id=\"tok-spark\" viewBox=\"0 0 200 24\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--accent)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/><circle r=\"1.6\" fill=\"var(--accent)\" style=\"display:none\"/></svg></div>\n <div class=\"vital\" id=\"v-inflight\"><div class=\"eyebrow\">In‑flight</div><div class=\"vnum skel\" id=\"inflight-num\">···</div><div class=\"vsub\" id=\"inflight-sub\"></div><svg class=\"vspark\" id=\"inflight-spark\" viewBox=\"0 0 200 24\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--accent-2)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/><circle r=\"1.6\" fill=\"var(--accent-2)\" style=\"display:none\"/></svg></div>\n <div class=\"vital\" id=\"v-uptime\"><div class=\"eyebrow\">Uptime</div><div class=\"vnum skel\" id=\"uptime-num\">···</div><div class=\"vsub\" id=\"uptime-sub\"></div></div>\n </section>\n\n <section class=\"grid\">\n <div class=\"panel span5\"><span class=\"ptitle\">┤ Proxy · requests ┠</span>\n <div class=\"headline\"><span id=\"req-total\" class=\"skel\">···</span> <span class=\"cap\">requests</span></div>\n <div class=\"stack-bar empty\" id=\"route-sharebar\"></div>\n <div class=\"stack-bar empty\" id=\"status-healthbar\"></div>\n <div class=\"scrollx\"><table class=\"tbl\"><thead><tr><th class=\"l\">Route</th><th>Count</th><th>%</th><th style=\"width:60px\"> </th></tr></thead><tbody id=\"routes-body\"><tr class=\"ghost\"><td colspan=\"4\">loading…</td></tr></tbody></table></div>\n </div>\n\n <div class=\"panel span3\"><span class=\"ptitle\">┤ Status ┠</span>\n <div class=\"headline\"><span id=\"error-rate\" class=\"skel\">···</span> <span class=\"cap\">err rate</span></div>\n <div class=\"stack-bar empty\" id=\"status-bar\"></div>\n <div class=\"legend\" id=\"status-legend\"></div>\n </div>\n\n <div class=\"panel span4\"><span class=\"ptitle\">┤ Latency · ms ┠</span>\n <div class=\"lat-trio\">\n <div class=\"b\"><small>p50</small><span id=\"lat-p50\" class=\"skel\">·</span></div>\n <div class=\"b lat-p95\"><small>p95</small><span id=\"lat-p95\" class=\"skel\">·</span></div>\n <div class=\"b\"><small>avg</small><span id=\"lat-avg\" class=\"skel\">·</span></div>\n <div class=\"b\"><small>obs</small><span id=\"lat-count\" class=\"skel\">·</span></div>\n </div>\n <div class=\"lat-track\" id=\"lat-track\"><div class=\"line\"></div></div>\n <details class=\"routes\"><summary>by route</summary><div class=\"scrollx\"><table class=\"tbl\"><thead><tr><th class=\"l\">Route</th><th>avg ms</th><th>count</th></tr></thead><tbody id=\"lat-routes\"></tbody></table></div></details>\n </div>\n\n <div class=\"panel span7\"><span class=\"ptitle\">┤ Tokens · by model ┠</span>\n <div class=\"headline\"><span id=\"tok-total\" class=\"skel\">···</span> <span class=\"cap\">tokens · <span id=\"tok-cache\">cache ·%</span></span></div>\n <div class=\"stack-bar empty\" id=\"tok-mixbar\"></div>\n <div class=\"legend\" id=\"tok-legend\"></div>\n <div class=\"scrollx\" style=\"margin-top:8px\"><table class=\"tbl\"><thead><tr><th class=\"l\">Model</th><th>prompt</th><th>compl</th><th>reason</th><th>cached</th><th>total</th><th>reqs</th></tr></thead><tbody id=\"tok-body\"><tr class=\"ghost\"><td colspan=\"7\">no token usage yet</td></tr></tbody></table></div>\n </div>\n\n <div class=\"panel span5\"><span class=\"ptitle\">┤ Copilot · quota ┠</span>\n <div id=\"copilot-body\"><div class=\"emptybox skel\">loading…</div></div>\n </div>\n\n <div class=\"panel span4\"><span class=\"ptitle\">┤ Upstream · copilot edge ┠</span>\n <div class=\"upblocks\">\n <div class=\"upblk\"><div class=\"v\" id=\"up-total\">·</div><div class=\"k\">calls</div></div>\n <div class=\"upblk err\" id=\"up-errblk\"><div class=\"v\" id=\"up-errors\">·</div><div class=\"k\">errors</div></div>\n <div class=\"upblk\"><div class=\"v rate\" id=\"up-rate\">·</div><div class=\"k\">err rate</div></div>\n </div>\n <svg id=\"up-spark\" viewBox=\"0 0 320 30\" preserveAspectRatio=\"none\" aria-hidden=\"true\"><path class=\"area\" fill=\"var(--spark-fill)\" stroke=\"none\"/><path class=\"line\" fill=\"none\" stroke=\"var(--danger)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/></svg>\n <div class=\"flag\" id=\"up-flag\"></div>\n </div>\n\n <div class=\"panel span8\"><span class=\"ptitle\">┤ Throughput ┠</span>\n <div class=\"cap\"><span style=\"color:var(--accent)\">■</span> tokens/s <span id=\"thru-tok\" class=\"num\"></span> <span style=\"color:var(--accent-2)\">■</span> req/s <span id=\"thru-req\" class=\"num\"></span> <span class=\"end\" id=\"thru-peak\" style=\"float:right\"></span></div>\n <svg id=\"thru-svg\" viewBox=\"0 0 320 88\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\n <defs><linearGradient id=\"thrugrad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0%\" stop-color=\"var(--accent)\" stop-opacity=\"0.28\"/><stop offset=\"100%\" stop-color=\"var(--accent)\" stop-opacity=\"0\"/></linearGradient></defs>\n <line class=\"grid\" x1=\"0\" y1=\"22\" x2=\"320\" y2=\"22\" stroke=\"var(--grid-line)\"/>\n <line class=\"grid\" x1=\"0\" y1=\"44\" x2=\"320\" y2=\"44\" stroke=\"var(--grid-line)\"/>\n <line class=\"grid\" x1=\"0\" y1=\"66\" x2=\"320\" y2=\"66\" stroke=\"var(--grid-line)\"/>\n <path id=\"thru-tok-area\" fill=\"url(#thrugrad)\" stroke=\"none\"/>\n <path id=\"thru-tok-line\" fill=\"none\" stroke=\"var(--accent)\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\"/>\n <path id=\"thru-req-line\" fill=\"none\" stroke=\"var(--accent-2)\" stroke-width=\"1.2\" vector-effect=\"non-scaling-stroke\" opacity=\"0.9\"/>\n </svg>\n </div>\n </section>\n </section>\n\n <section id=\"auth\" aria-live=\"polite\">\n <div class=\"authcard\">\n <span class=\"clear\" id=\"auth-clear\" style=\"display:none\">clear key</span>\n <h3>┤ Auth required ┠</h3>\n <p>This hoopilot proxy requires an API key. It is stored locally in your browser and sent as <span class=\"mono\">x-api-key</span>.</p>\n <div class=\"row\"><input id=\"auth-input\" type=\"password\" placeholder=\"x-api-key\" autocomplete=\"off\" spellcheck=\"false\" /><button id=\"auth-connect\">connect</button></div>\n <div class=\"err\" id=\"auth-err\"></div>\n </div>\n </section>\n\n <footer class=\"foot\">\n <span id=\"foot-started\">started ·</span>\n <span id=\"foot-uptime\">uptime ·</span>\n <span id=\"foot-total\">· req</span>\n <span id=\"foot-tokens\">· tokens</span>\n <span id=\"foot-upstream\">upstream ·</span>\n <span class=\"end\" id=\"foot-cadence\"></span>\n </footer>\n</div>\n\n<script>\n(function(){\n \"use strict\";\n var byId = function(id){ return document.getElementById(id); };\n var CAP = 60;\n\n // ---- persistent state ----\n var LS = window.localStorage;\n var apiKey = \"\";\n try { apiKey = LS.getItem(\"hoopilot.apiKey\") || \"\"; } catch (e) { apiKey = \"\"; }\n var theme = \"auto\";\n try { theme = LS.getItem(\"hoopilot.theme\") || \"auto\"; } catch (e) { theme = \"auto\"; }\n var intervalMs = 4000;\n try { var sv = parseInt(LS.getItem(\"hoopilot.intervalMs\") || \"\", 10); if (sv === 2000 || sv === 4000 || sv === 10000) intervalMs = sv; } catch (e) {}\n\n // ---- runtime state ----\n var paused = false;\n var timer = null;\n var inflightFetch = null;\n var lastSuccessAt = 0;\n var prevSample = null; // { t, reqTotal, tokTotal, upTotal, startedAt }\n var lastRender = {}; // for change-flash\n var backoffMs = 0;\n var lastUptime = null; // seconds; ticked locally between polls\n var hist = { req:[], tok:[], inflight:[], up:[] };\n\n // ---- formatting helpers ----\n function humanInt(n){\n if (n === null || n === undefined || !isFinite(n)) return \"0\";\n var a = Math.abs(n);\n if (a >= 1000000) return (n/1000000).toFixed(a >= 10000000 ? 0 : 1) + \"M\";\n if (a >= 1000) return (n/1000).toFixed(a >= 10000 ? 0 : 1) + \"k\";\n return String(Math.round(n));\n }\n function rate(n){\n if (n === null || n === undefined || !isFinite(n)) return \"0\";\n if (n >= 100) return String(Math.round(n));\n if (n >= 10) return n.toFixed(1);\n return n.toFixed(2);\n }\n function pct(n){ if (!isFinite(n)) return \"0%\"; return (n >= 10 ? Math.round(n) : Math.round(n*10)/10) + \"%\"; }\n function fmtMs(n){ if (n === null || n === undefined || !isFinite(n) || n <= 0) return \"0\"; if (n >= 1000) return (n/1000).toFixed(2) + \"s\"; if (n >= 100) return String(Math.round(n)); return Math.round(n*10)/10 + \"\"; }\n function pad2(n){ return (n < 10 ? \"0\" : \"\") + n; }\n function fmtUptime(sec){\n sec = Math.max(0, Math.floor(sec));\n var d = Math.floor(sec/86400); sec -= d*86400;\n var h = Math.floor(sec/3600); sec -= h*3600;\n var m = Math.floor(sec/60); var s = sec - m*60;\n if (d > 0) return d + \"d \" + pad2(h) + \":\" + pad2(m);\n if (h > 0) return h + \":\" + pad2(m) + \":\" + pad2(s);\n return m + \":\" + pad2(s);\n }\n function titleize(key){\n var map = { premium_interactions:\"Premium requests\", chat:\"Chat\", completions:\"Completions\", code_review:\"Code review\" };\n if (map[key]) return map[key];\n return key.split(\"_\").map(function(w){ return w ? w.charAt(0).toUpperCase() + w.slice(1) : w; }).join(\" \");\n }\n function relTime(iso){\n var t = Date.parse(iso); if (!isFinite(t)) return iso || \"\";\n var s = Math.max(0, Math.round((Date.now() - t)/1000));\n return fmtUptime(s) + \" ago\";\n }\n function clearEl(el){ while (el && el.firstChild) el.removeChild(el.firstChild); }\n function mk(tag, cls, txt){ var e = document.createElement(tag); if (cls) e.className = cls; if (txt !== undefined && txt !== null) e.textContent = txt; return e; }\n\n // Set numeric text and flash on discrete change.\n function setNum(id, value, kind, num){\n var el = byId(id); if (!el) return;\n el.classList.remove(\"skel\");\n var s = String(value);\n if (el.textContent !== s){\n el.textContent = s;\n // Compare on the raw number (num) when provided, so directional flash works\n // even when value is a pre-formatted display string.\n var n = (num !== undefined) ? num : value;\n var prev = lastRender[id];\n if (prev !== undefined){\n var cls = \"flash\";\n if (kind === \"delta\" && typeof n === \"number\" && typeof prev === \"number\"){\n cls = n > prev ? \"flash-up\" : (n < prev ? \"flash-down\" : null);\n }\n if (cls){ el.classList.remove(\"flash\",\"flash-up\",\"flash-down\"); void el.offsetWidth; el.classList.add(cls); }\n }\n lastRender[id] = n;\n }\n }\n function setText(id, s){ var el = byId(id); if (el){ el.classList.remove(\"skel\"); el.textContent = s; } }\n\n // ---- sparkline rendering ----\n function pushHist(arr, v){ arr.push(v); if (arr.length > CAP) arr.shift(); }\n function buildSpark(values, w, h){\n var pts = []; for (var i=0;i<values.length;i++){ if (isFinite(values[i])) pts.push({ i:i, v:values[i] }); }\n if (pts.length < 2) return null;\n var min = Infinity, max = -Infinity;\n for (var j=0;j<values.length;j++){ var v = values[j]; if (isFinite(v)){ if (v<min) min=v; if (v>max) max=v; } }\n var flat = (max - min) <= 0;\n var pad = flat ? 1 : (max - min) * 0.05; var lo = min - pad, hi = max + pad; var span = hi - lo; if (span <= 0) span = 1;\n var n = values.length;\n var line = \"\", lastX = 0, lastY = 0, started = false;\n for (var k=0;k<n;k++){\n var val = values[k]; if (!isFinite(val)) continue;\n var x = (n === 1) ? w : (k * (w/(n-1)));\n var norm = flat ? 0.5 : (val - lo)/span;\n var y = h - norm*(h-2) - 1;\n line += (started ? \" L\" : \"M\") + x.toFixed(2) + \",\" + y.toFixed(2);\n lastX = x; lastY = y; started = true;\n }\n var area = line + \" L\" + lastX.toFixed(2) + \",\" + h + \" L0,\" + h + \" Z\";\n return { line:line, area:area, lastX:lastX, lastY:lastY };\n }\n function drawSpark(svgId, values){\n var svg = byId(svgId); if (!svg) return;\n var vb = svg.viewBox.baseVal; var w = vb.width || 200, h = vb.height || 24;\n var sp = buildSpark(values, w, h);\n var line = svg.querySelector(\".line\"), area = svg.querySelector(\".area\"), dot = svg.querySelector(\"circle\");\n if (!sp){ if (line) line.setAttribute(\"d\",\"\"); if (area) area.setAttribute(\"d\",\"\"); if (dot) dot.style.display = \"none\"; return; }\n if (line) line.setAttribute(\"d\", sp.line);\n if (area) area.setAttribute(\"d\", sp.area);\n if (dot){ dot.setAttribute(\"cx\", sp.lastX.toFixed(2)); dot.setAttribute(\"cy\", sp.lastY.toFixed(2)); dot.style.display = \"\"; }\n }\n\n // ---- theme ----\n function applyTheme(){\n var root = document.documentElement;\n if (theme === \"dark\") root.setAttribute(\"data-theme\",\"dark\");\n else if (theme === \"light\") root.setAttribute(\"data-theme\",\"light\");\n else root.removeAttribute(\"data-theme\");\n byId(\"btn-theme\").textContent = theme === \"dark\" ? \"D\" : (theme === \"light\" ? \"L\" : \"A\");\n }\n byId(\"btn-theme\").addEventListener(\"click\", function(){\n theme = theme === \"auto\" ? \"dark\" : (theme === \"dark\" ? \"light\" : \"auto\");\n try { LS.setItem(\"hoopilot.theme\", theme); } catch (e) {}\n applyTheme();\n });\n\n // ---- interval + pause ----\n function setActiveSeg(){\n var btns = byId(\"seg\").querySelectorAll(\"button\");\n for (var i=0;i<btns.length;i++){ btns[i].classList.toggle(\"active\", parseInt(btns[i].getAttribute(\"data-ms\"),10) === intervalMs); }\n document.documentElement.style.setProperty(\"--scan-ms\", intervalMs + \"ms\");\n }\n byId(\"seg\").addEventListener(\"click\", function(ev){\n var b = ev.target.closest ? ev.target.closest(\"button\") : null; if (!b) return;\n intervalMs = parseInt(b.getAttribute(\"data-ms\"),10) || 4000;\n try { LS.setItem(\"hoopilot.intervalMs\", String(intervalMs)); } catch (e) {}\n setActiveSeg();\n if (!paused){ schedule(0); }\n });\n byId(\"btn-pause\").addEventListener(\"click\", function(){\n paused = !paused;\n byId(\"btn-pause\").innerHTML = paused ? \"▶\" : \"❚❚\";\n byId(\"bar\").classList.toggle(\"paused\", paused);\n if (paused){ if (timer){ clearTimeout(timer); timer = null; } setPill(\"paused\",\"PAUSED\",false); }\n else { setPill(\"live\",\"LIVE\",false); schedule(0); }\n });\n\n // ---- connection pill / banner ----\n function setPill(kind, text, beat){\n var pill = byId(\"conn-pill\"); var dot = byId(\"conn-dot\");\n pill.className = \"pill \" + kind;\n byId(\"conn-text\").textContent = text;\n if (beat && dot){ dot.classList.remove(\"heartbeat\"); void dot.offsetWidth; dot.classList.add(\"heartbeat\"); }\n }\n function showBanner(text, ok){\n var b = byId(\"banner\"); b.textContent = text; b.className = \"show\" + (ok ? \" ok\" : \"\");\n if (ok){ setTimeout(function(){ b.classList.remove(\"show\"); }, 2000); }\n }\n function hideBanner(){ byId(\"banner\").classList.remove(\"show\"); }\n function setDimmed(on){ byId(\"content\").classList.toggle(\"dim\", on); }\n\n // ---- auth takeover ----\n function showAuth(rejected){\n byId(\"content\").style.display = \"none\";\n byId(\"auth\").classList.add(\"show\");\n setPill(\"authkey\",\"API KEY\",false);\n byId(\"auth-err\").textContent = rejected ? \"key rejected\" : \"\";\n byId(\"auth-input\").classList.toggle(\"bad\", !!rejected);\n byId(\"auth-clear\").style.display = apiKey ? \"\" : \"none\";\n byId(\"auth-input\").focus();\n }\n function hideAuth(){ byId(\"auth\").classList.remove(\"show\"); byId(\"content\").style.display = \"\"; }\n byId(\"auth-connect\").addEventListener(\"click\", function(){\n var v = byId(\"auth-input\").value.trim(); if (!v) return;\n apiKey = v; try { LS.setItem(\"hoopilot.apiKey\", apiKey); } catch (e) {}\n hideAuth(); schedule(0);\n });\n byId(\"auth-input\").addEventListener(\"keydown\", function(ev){ if (ev.key === \"Enter\") byId(\"auth-connect\").click(); });\n byId(\"auth-clear\").addEventListener(\"click\", function(){\n apiKey = \"\"; try { LS.removeItem(\"hoopilot.apiKey\"); } catch (e) {}\n byId(\"auth-input\").value = \"\"; byId(\"auth-clear\").style.display = \"none\"; byId(\"auth-input\").focus();\n });\n\n // ---- the poll loop (setTimeout-chained, never setInterval) ----\n var pollGen = 0;\n function schedule(delay){\n if (timer){ clearTimeout(timer); }\n if (paused) return;\n timer = setTimeout(poll, delay === undefined ? intervalMs : delay);\n }\n function poll(){\n if (paused) return;\n // A new poll supersedes any in-flight one. Bump the generation so the old\n // request's settled handlers (including its abort rejection) become no-ops\n // and never flash a false \"disconnected\".\n pollGen += 1; var myGen = pollGen;\n if (inflightFetch){ try { inflightFetch.abort(); } catch (e) {} }\n var ctrl = new AbortController(); inflightFetch = ctrl;\n var to = setTimeout(function(){ try { ctrl.abort(); } catch (e) {} }, 3000);\n var headers = { \"accept\":\"application/json\" };\n if (apiKey) headers[\"x-api-key\"] = apiKey;\n fetch(\"/v1/usage\", { headers: headers, signal: ctrl.signal, cache:\"no-store\" }).then(function(res){\n clearTimeout(to);\n if (myGen !== pollGen) return null;\n if (res.status === 401 || res.status === 403){ inflightFetch = null; showAuth(!!apiKey); return null; }\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n return res.json();\n }).then(function(data){\n if (myGen !== pollGen || data === null || paused) return;\n inflightFetch = null;\n onData(data);\n backoffMs = 0; lastSuccessAt = Date.now();\n hideAuth(); setDimmed(false); hideBanner();\n setPill(\"live\",\"LIVE\",true);\n byId(\"bar\").classList.remove(\"frozen\");\n schedule(intervalMs);\n }).catch(function(err){\n clearTimeout(to);\n if (myGen !== pollGen || paused) return;\n inflightFetch = null;\n onDisconnect(err);\n });\n }\n function onDisconnect(err){\n setPill(\"reconnect\",\"RECONNECTING\",false);\n setDimmed(true);\n byId(\"bar\").classList.add(\"frozen\");\n backoffMs = backoffMs ? Math.min(Math.round(backoffMs * 1.5), 30000) : intervalMs;\n showBanner(\"Disconnected (\" + (err && err.message ? err.message : \"no response\") + \") \\\\u2014 retrying in \" + Math.round(backoffMs/1000) + \"s\", false);\n schedule(backoffMs);\n }\n\n // ---- main render ----\n function onData(usage){\n var proxy = usage.proxy || {};\n var now = Date.now();\n\n setText(\"version-chip\", \"v\" + (usage.version || \"?\"));\n\n // rates\n var reqTotal = (proxy.requests && proxy.requests.total) || 0;\n var tokTotal = (proxy.tokens && proxy.tokens.total) || 0;\n var upTotal = (proxy.upstream && proxy.upstream.total) || 0;\n var startedAt = proxy.startedAt || \"\";\n var reqPerSec = NaN, tokPerSec = NaN, upDelta = 0, restarted = false;\n if (prevSample){\n var dt = (now - prevSample.t)/1000;\n if (prevSample.startedAt && startedAt && prevSample.startedAt !== startedAt) restarted = true;\n if (reqTotal < prevSample.reqTotal || tokTotal < prevSample.tokTotal) restarted = true;\n if (restarted){ reqPerSec = 0; tokPerSec = 0; upDelta = 0; }\n else if (dt > 0 && isFinite(dt)){\n reqPerSec = Math.max(0, (reqTotal - prevSample.reqTotal)/dt);\n tokPerSec = Math.max(0, (tokTotal - prevSample.tokTotal)/dt);\n upDelta = Math.max(0, upTotal - prevSample.upTotal);\n }\n }\n prevSample = { t:now, reqTotal:reqTotal, tokTotal:tokTotal, upTotal:upTotal, startedAt:startedAt };\n\n // hero vitals\n if (isFinite(reqPerSec)){ pushHist(hist.req, reqPerSec); setNum(\"req-num\", rate(reqPerSec)); } else setText(\"req-num\",\"\\\\u2014\");\n if (isFinite(tokPerSec)){ pushHist(hist.tok, tokPerSec); setNum(\"tok-num\", humanInt(tokPerSec)); } else setText(\"tok-num\",\"\\\\u2014\");\n var inflight = proxy.inFlight || 0;\n pushHist(hist.inflight, inflight); setNum(\"inflight-num\", String(inflight), \"delta\", inflight);\n byId(\"v-inflight\").classList.toggle(\"active\", inflight > 0);\n setText(\"uptime-num\", fmtUptime(proxy.uptimeSeconds || 0));\n\n setText(\"req-sub\", hist.req.length ? (\"avg \" + rate(avg(hist.req)) + \"/s\") : \"warming up\");\n setText(\"tok-sub\", hist.tok.length ? (\"peak \" + humanInt(Math.max.apply(null, hist.tok)) + \"/s\") : \"warming up\");\n setText(\"inflight-sub\", inflight + \" now\");\n setText(\"uptime-sub\", startedAt ? (\"since \" + relTime(startedAt)) : \"\");\n\n drawSpark(\"req-spark\", hist.req);\n drawSpark(\"tok-spark\", hist.tok);\n drawSpark(\"inflight-spark\", hist.inflight);\n\n renderRequests(proxy);\n renderStatus(proxy);\n renderLatency(proxy.latency || {});\n renderTokens(proxy.tokens || {});\n renderCopilot(usage);\n renderUpstream(proxy.upstream || {}, upDelta, restarted);\n renderThroughput();\n renderFooter(usage, proxy);\n\n setNum(\"req-total\", humanInt(reqTotal));\n setNum(\"tok-total\", humanInt(tokTotal));\n lastUptime = proxy.uptimeSeconds || 0;\n }\n\n function avg(arr){ if (!arr.length) return 0; var s = 0; for (var i=0;i<arr.length;i++) s += arr[i]; return s/arr.length; }\n\n var ROUTE_COLORS = [\"var(--c1)\",\"var(--c2)\",\"var(--c3)\",\"var(--c4)\",\"var(--c5)\",\"var(--c6)\"];\n function renderRequests(proxy){\n var byRoute = (proxy.requests && proxy.requests.byRoute) || {};\n var total = (proxy.requests && proxy.requests.total) || 0;\n var rows = Object.keys(byRoute).map(function(k){ return { k:k, v:byRoute[k] }; }).sort(function(a,b){ return b.v - a.v; });\n var share = byId(\"route-sharebar\"); clearEl(share); share.className = \"stack-bar\" + (total ? \"\" : \" empty\");\n var body = byId(\"routes-body\"); clearEl(body);\n if (!rows.length){ var tr = mk(\"tr\",\"ghost\"); var td = mk(\"td\",null,\"no requests yet\"); td.colSpan = 4; tr.appendChild(td); body.appendChild(tr); return; }\n rows.forEach(function(r, idx){\n var p = total ? (r.v/total*100) : 0;\n var seg = mk(\"i\"); seg.style.width = p + \"%\"; seg.style.background = ROUTE_COLORS[idx % ROUTE_COLORS.length]; seg.title = r.k + \" \" + pct(p); share.appendChild(seg);\n var tr = mk(\"tr\");\n var name = mk(\"td\",\"l\", r.k); name.title = r.k; tr.appendChild(name);\n tr.appendChild(mk(\"td\",null, humanInt(r.v)));\n tr.appendChild(mk(\"td\",null, pct(p)));\n var btd = mk(\"td\"); var bar = mk(\"span\",\"minibar\"); bar.style.width = Math.max(2, p) + \"%\"; bar.style.background = ROUTE_COLORS[idx % ROUTE_COLORS.length]; btd.appendChild(bar); tr.appendChild(btd);\n body.appendChild(tr);\n });\n var tot = mk(\"tr\",\"total\"); tot.appendChild(mk(\"td\",\"l\",\"total\")); tot.appendChild(mk(\"td\",null, humanInt(total))); tot.appendChild(mk(\"td\",null,\"100%\")); tot.appendChild(mk(\"td\")); body.appendChild(tot);\n }\n\n function statusClass(code){ var c = String(code).charAt(0); if (c === \"2\") return \"ok\"; if (c === \"3\") return \"info\"; if (c === \"4\") return \"warn\"; if (c === \"5\") return \"danger\"; return \"muted\"; }\n function statusColor(cls){ return cls === \"ok\" ? \"var(--ok)\" : cls === \"info\" ? \"var(--info)\" : cls === \"warn\" ? \"var(--warn)\" : cls === \"danger\" ? \"var(--danger)\" : \"var(--text-2)\"; }\n function renderStatus(proxy){\n var byStatus = (proxy.requests && proxy.requests.byStatus) || {};\n var total = 0, errs = 0; var groups = { ok:0, info:0, warn:0, danger:0, muted:0 };\n var codes = Object.keys(byStatus).map(function(k){ return { k:k, v:byStatus[k] }; }).sort(function(a,b){ return b.v - a.v; });\n codes.forEach(function(c){ total += c.v; var cls = statusClass(c.k); groups[cls] += c.v; if (cls === \"warn\" || cls === \"danger\") errs += c.v; });\n var bar = byId(\"status-bar\"); clearEl(bar); bar.className = \"stack-bar\" + (total ? \"\" : \" empty\");\n [\"ok\",\"info\",\"warn\",\"danger\",\"muted\"].forEach(function(cls){ if (groups[cls] > 0){ var seg = mk(\"i\"); seg.style.width = (groups[cls]/total*100) + \"%\"; seg.style.background = statusColor(cls); bar.appendChild(seg); } });\n var leg = byId(\"status-legend\"); clearEl(leg);\n if (!codes.length){ leg.appendChild(mk(\"span\",\"li\",\"no requests yet\")); }\n codes.forEach(function(c){ var li = mk(\"span\",\"li\"); var sw = mk(\"span\",\"sw\"); sw.style.background = statusColor(statusClass(c.k)); li.appendChild(sw); li.appendChild(mk(\"span\",null, c.k + \" \" + humanInt(c.v))); leg.appendChild(li); });\n var er = total ? (errs/total*100) : 0;\n setNum(\"error-rate\", pct(er));\n var el = byId(\"error-rate\"); el.style.color = er > 5 ? \"var(--danger)\" : er > 1 ? \"var(--warn)\" : \"var(--ok)\";\n }\n\n function renderLatency(lat){\n setText(\"lat-p50\", fmtMs(lat.p50Ms)); setText(\"lat-avg\", fmtMs(lat.avgMs)); setText(\"lat-count\", humanInt(lat.count || 0));\n var p95 = byId(\"lat-p95\"); p95.classList.remove(\"skel\"); p95.textContent = fmtMs(lat.p95Ms);\n p95.style.color = (lat.p50Ms > 0 && lat.p95Ms > 2*lat.p50Ms) ? \"var(--warn)\" : \"var(--info)\";\n // track: position p50 and p95 across 0..(p95*1.15)\n var track = byId(\"lat-track\"); var old = track.querySelectorAll(\".tick,.tlab\"); for (var i=0;i<old.length;i++) old[i].remove();\n var maxv = Math.max(lat.p95Ms || 0, lat.avgMs || 0, 1) * 1.15;\n function place(v, cls){ if (!isFinite(v) || v <= 0) return; var x = Math.min(100, v/maxv*100); var t = mk(\"div\",\"tick \" + cls); t.style.left = x + \"%\"; track.appendChild(t); var lab = mk(\"div\",\"tlab\", fmtMs(v)); lab.style.left = x + \"%\"; track.appendChild(lab); }\n place(lat.p50Ms, \"p50\"); place(lat.p95Ms, \"p95\");\n var lr = byId(\"lat-routes\"); clearEl(lr);\n var byRoute = lat.byRoute || {}; var rows = Object.keys(byRoute).map(function(k){ return { k:k, v:byRoute[k] }; }).sort(function(a,b){ return (b.v.avgMs||0) - (a.v.avgMs||0); });\n rows.forEach(function(r){ var tr = mk(\"tr\"); var n = mk(\"td\",\"l\", r.k); n.title = r.k; tr.appendChild(n); tr.appendChild(mk(\"td\",null, fmtMs(r.v.avgMs))); tr.appendChild(mk(\"td\",null, humanInt(r.v.count||0))); lr.appendChild(tr); });\n }\n\n function renderTokens(tok){\n var prompt = tok.prompt||0, completion = tok.completion||0, reasoning = tok.reasoning||0, cached = tok.cached||0;\n var sum = prompt + completion + reasoning;\n var bar = byId(\"tok-mixbar\"); clearEl(bar); bar.className = \"stack-bar\" + (sum ? \"\" : \" empty\");\n var parts = [ [\"prompt\", prompt, \"var(--text-1)\"], [\"completion\", completion, \"var(--accent)\"], [\"reasoning\", reasoning, \"var(--info)\"] ];\n parts.forEach(function(p){ if (sum && p[1] > 0){ var seg = mk(\"i\"); seg.style.width = (p[1]/sum*100) + \"%\"; seg.style.background = p[2]; seg.title = p[0]; bar.appendChild(seg); } });\n var leg = byId(\"tok-legend\"); clearEl(leg);\n var legParts = parts.concat([[\"cached\", cached, \"var(--cache)\"]]);\n legParts.forEach(function(p){ var li = mk(\"span\",\"li\"); var sw = mk(\"span\",\"sw\"); sw.style.background = p[2]; li.appendChild(sw); var den = (p[0] === \"cached\") ? prompt : sum; var sh = den ? \" \" + pct(p[1]/den*100) : \"\"; li.appendChild(mk(\"span\",null, p[0] + \" \" + humanInt(p[1]) + sh)); leg.appendChild(li); });\n var cacheRate = prompt ? (cached/prompt*100) : 0; setText(\"tok-cache\", \"cache \" + pct(cacheRate));\n var body = byId(\"tok-body\"); clearEl(body);\n var byModel = tok.byModel || {}; var rows = Object.keys(byModel).map(function(k){ return { k:k, v:byModel[k] }; }).sort(function(a,b){ return (b.v.total||0) - (a.v.total||0); });\n if (!rows.length){ var tr = mk(\"tr\",\"ghost\"); var td = mk(\"td\",null,\"no token usage yet\"); td.colSpan = 7; tr.appendChild(td); body.appendChild(tr); return; }\n rows.forEach(function(r){ var m = r.v; var tr = mk(\"tr\"); var n = mk(\"td\",\"l\", r.k); n.title = r.k; tr.appendChild(n);\n tr.appendChild(mk(\"td\",null, humanInt(m.prompt||0))); tr.appendChild(mk(\"td\",null, humanInt(m.completion||0)));\n tr.appendChild(mk(\"td\",\"reasoning\", humanInt(m.reasoning||0))); tr.appendChild(mk(\"td\",\"cached\", humanInt(m.cached||0)));\n tr.appendChild(mk(\"td\",null, humanInt(m.total||0))); tr.appendChild(mk(\"td\",null, humanInt(m.requests||0))); body.appendChild(tr); });\n }\n\n function planClass(plan){ if (!plan) return \"plan-offline\"; if (plan.indexOf(\"pro\") >= 0) return \"plan-pro\"; if (plan.indexOf(\"business\") >= 0 || plan.indexOf(\"enterprise\") >= 0) return \"plan-business\"; return \"plan-free\"; }\n function renderCopilot(usage){\n var box = byId(\"copilot-body\"); clearEl(box);\n var cp = usage.copilot; var planChip = byId(\"plan-chip\");\n if (!cp){\n planChip.className = \"chip plan-offline\"; planChip.textContent = \"\\\\u2014 offline\";\n var eb = mk(\"div\",\"emptybox\"); eb.appendChild(mk(\"div\",\"keyglyph\",\"\\\\u26bf\"));\n eb.appendChild(mk(\"h4\",null,\"Copilot not connected\"));\n if (usage.copilot_error) eb.appendChild(mk(\"div\",\"errline\", usage.copilot_error));\n eb.appendChild(mk(\"div\",\"prompt\",\"$ hoopilot login\"));\n box.appendChild(eb); return;\n }\n planChip.className = \"chip \" + planClass(cp.plan); planChip.textContent = cp.plan || \"copilot\";\n var head = mk(\"div\",\"cap\");\n var bits = [];\n if (cp.accessTypeSku) bits.push(cp.accessTypeSku);\n if (cp.chatEnabled !== undefined) bits.push(cp.chatEnabled ? \"chat on\" : \"chat off\");\n if (cp.quotaResetDate) bits.push(\"resets \" + cp.quotaResetDate);\n head.textContent = bits.join(\" \\\\u00b7 \"); box.appendChild(head);\n var quotas = cp.quotas || {}; var keys = Object.keys(quotas);\n if (!keys.length){ box.appendChild(mk(\"div\",\"cap\",\"No metered quotas reported.\")); return; }\n var order = { premium_interactions:0, chat:1, completions:2 };\n keys.sort(function(a,b){ var ra = order[a]===undefined?9:order[a], rb = order[b]===undefined?9:order[b]; return ra-rb || a.localeCompare(b); });\n keys.forEach(function(k){\n var q = quotas[k]; var row = mk(\"div\",\"qrow\");\n var hd = mk(\"div\",\"qhead\"); hd.appendChild(mk(\"span\",\"qname\", titleize(k)));\n if (q.unlimited){ hd.appendChild(mk(\"span\",\"inf\",\"\\\\u221e unlimited\")); row.appendChild(hd); box.appendChild(row); return; }\n var ent = q.entitlement, rem = q.remaining, used = q.used;\n var usedPct = (q.percentRemaining !== undefined) ? (100 - q.percentRemaining) : ((ent && used !== undefined) ? (used/ent*100) : 0);\n usedPct = Math.max(0, Math.min(100, usedPct));\n var valTxt = (used !== undefined && ent !== undefined) ? (humanInt(used) + \" / \" + humanInt(ent)) : (rem !== undefined ? (humanInt(rem) + \" left\") : pct(100-usedPct) + \" left\");\n hd.appendChild(mk(\"span\",\"qval\", valTxt)); row.appendChild(hd);\n var bar = mk(\"div\",\"qbar\"); var fill = mk(\"i\"); fill.style.width = usedPct + \"%\";\n fill.style.background = usedPct > 85 ? \"var(--danger)\" : usedPct > 60 ? \"var(--warn)\" : \"var(--ok)\"; bar.appendChild(fill);\n if (q.overageCount && q.overagePermitted){ bar.classList.add(\"over\"); var ext = mk(\"i\",\"ext\"); ext.style.left = \"100%\"; ext.style.width = \"8%\"; bar.appendChild(ext); }\n row.appendChild(bar);\n if (q.overageCount){ var ov = mk(\"div\",\"flag\", humanInt(q.overageCount) + \" overage\" + (q.tokenBasedBilling ? \" \\\\u00b7 token billing\" : \"\")); row.appendChild(ov); }\n box.appendChild(row);\n });\n }\n\n function renderUpstream(up, delta, restarted){\n setNum(\"up-total\", humanInt(up.total||0));\n setNum(\"up-errors\", humanInt(up.errors||0), \"delta\", up.errors||0);\n var er = up.total ? (up.errors/up.total*100) : 0;\n var rt = byId(\"up-rate\"); rt.textContent = pct(er); rt.className = \"v rate \" + (er > 5 ? \"danger\" : er > 1 ? \"warn\" : \"ok\");\n byId(\"up-errblk\").classList.toggle(\"hot\", (up.errors||0) > 0);\n pushHist(hist.up, delta||0); drawSpark(\"up-spark\", hist.up);\n byId(\"up-flag\").textContent = restarted ? \"\\\\u21bb restarted\" : \"\";\n }\n\n function renderThroughput(){\n drawDual(\"thru-tok-line\",\"thru-tok-area\", hist.tok, true);\n drawDual(\"thru-req-line\", null, hist.req, false);\n setText(\"thru-tok\", hist.tok.length ? rate(hist.tok[hist.tok.length-1]) : \"\\\\u2014\");\n setText(\"thru-req\", hist.req.length ? rate(hist.req[hist.req.length-1]) : \"\\\\u2014\");\n var peakTok = hist.tok.length ? Math.max.apply(null, hist.tok) : 0;\n setText(\"thru-peak\", \"peak \" + humanInt(peakTok) + \" tok/s\");\n }\n function drawDual(lineId, areaId, values, withArea){\n var svg = byId(\"thru-svg\"); var vb = svg.viewBox.baseVal; var w = vb.width, h = vb.height;\n var sp = buildSpark(values, w, h);\n var line = byId(lineId); var area = areaId ? byId(areaId) : null;\n if (!sp){ if (line) line.setAttribute(\"d\",\"\"); if (area) area.setAttribute(\"d\",\"\"); return; }\n if (line) line.setAttribute(\"d\", sp.line);\n if (area && withArea) area.setAttribute(\"d\", sp.area);\n }\n\n function renderFooter(usage, proxy){\n setText(\"foot-started\", proxy.startedAt ? (\"started \" + new Date(proxy.startedAt).toLocaleString()) : \"started \\\\u2014\");\n setText(\"foot-uptime\", \"uptime \" + fmtUptime(proxy.uptimeSeconds||0));\n setText(\"foot-total\", humanInt((proxy.requests && proxy.requests.total)||0) + \" req\");\n setText(\"foot-tokens\", humanInt((proxy.tokens && proxy.tokens.total)||0) + \" tokens\");\n var up = proxy.upstream || {}; setText(\"foot-upstream\", \"upstream \" + humanInt(up.total||0) + \" / \" + humanInt(up.errors||0) + \" err\");\n setText(\"foot-cadence\", \"polling /v1/usage every \" + Math.round(intervalMs/1000) + \"s \\\\u00b7 GET /dashboard\");\n }\n\n // ---- 1s freshness + uptime ticker (independent of the poll loop) ----\n setInterval(function(){\n if (lastSuccessAt){\n var ago = Math.round((Date.now() - lastSuccessAt)/1000);\n var u = byId(\"updated\"); u.textContent = \"updated \" + ago + \"s ago\";\n // Staleness only matters while polling; a deliberate pause is not \"stale\".\n u.className = \"updated\" + (paused ? \"\" : ago > intervalMs/1000*4 ? \" danger\" : ago > intervalMs/1000*2 ? \" warn\" : \"\");\n }\n // Tick uptime locally between polls so the seconds advance smoothly; each\n // successful poll re-seeds lastUptime from the authoritative server value.\n if (!paused && lastUptime !== null){\n lastUptime += 1;\n byId(\"uptime-num\").textContent = fmtUptime(lastUptime);\n var fu = byId(\"foot-uptime\"); if (fu) fu.textContent = \"uptime \" + fmtUptime(lastUptime);\n }\n }, 1000);\n\n // ---- boot ----\n applyTheme(); setActiveSeg();\n setPill(\"\",\"CONNECTING\",false);\n poll();\n})();\n</script>\n</body>\n</html>\n`;\n","import { extractTokenUsage } from \"./openai\";\nimport type {\n CopilotQuota,\n CopilotUsage,\n GithubRateLimit,\n GithubRateLimitSnapshot,\n LatencySnapshot,\n MetricsSnapshot,\n ModelTokenTotals,\n RequestObservation,\n RouteLatency,\n TokenUsage,\n} from \"./types\";\nimport { asRecord, safeJsonParse } from \"./util\";\n\n/** Content-Type for the Prometheus text exposition format (version 0.0.4). */\nexport const PROMETHEUS_CONTENT_TYPE = \"text/plain; version=0.0.4; charset=utf-8\";\n\n/** Upper bounds (seconds) for the request-duration histogram buckets. */\nconst DURATION_BUCKETS_SECONDS = [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60] as const;\n\n/** Cap on bytes buffered or scanned while extracting usage from a response body. */\nconst USAGE_BUFFER_LIMIT_BYTES = 16 * 1024 * 1024;\n\n/** Bound the distinct model labels so a hostile client cannot blow up cardinality. */\nconst MAX_TRACKED_MODELS = 200;\nconst MAX_MODEL_LABEL_LENGTH = 200;\n\n/** GitHub exposes a small fixed set of rate-limit resources; bound it anyway. */\nconst MAX_TRACKED_RATELIMIT_RESOURCES = 32;\n\n// Unit separator (ASCII 0x1f): joins label parts; cannot collide with a label value.\nconst LABEL_SEPARATOR = \"\\u001f\";\nconst UNKNOWN_MODEL = \"unknown\";\n\ninterface RouteDuration {\n buckets: number[];\n count: number;\n sum: number;\n}\n\nfunction emptyModelTotals(): ModelTokenTotals {\n return { cached: 0, completion: 0, prompt: 0, reasoning: 0, requests: 0, total: 0 };\n}\n\n/**\n * In-process metrics for the running proxy. Counters are monotonic for the life\n * of the process and reset on restart, which Prometheus handles natively. The\n * registry is intentionally allocation-light and synchronous; the single-\n * threaded event loop makes its mutations atomic with respect to each request.\n */\nexport class MetricsRegistry {\n readonly #startedAtMs: number;\n #inFlight = 0;\n #requests = new Map<string, number>();\n #durations = new Map<string, RouteDuration>();\n #tokens = new Map<string, ModelTokenTotals>();\n #upstream = new Map<string, number>();\n #copilotQuota?: CopilotUsage;\n #githubRateLimit = new Map<string, GithubRateLimit>();\n #extraction = { extracted: 0, missing: 0 };\n\n constructor(options: { now?: () => number } = {}) {\n this.#startedAtMs = (options.now ?? Date.now)();\n }\n\n /** Mark a request as started; pair with exactly one {@link observe}. */\n startRequest(): void {\n this.#inFlight += 1;\n }\n\n /** Record a completed request and clear its in-flight slot. */\n observe(observation: RequestObservation): void {\n if (this.#inFlight > 0) {\n this.#inFlight -= 1;\n }\n const key = labelKey(observation.route, observation.method, String(observation.status));\n this.#requests.set(key, (this.#requests.get(key) ?? 0) + 1);\n this.#observeDuration(observation.route, observation.durationMs / 1000);\n }\n\n /**\n * Record whether one upstream completion reported token usage. `missing`\n * counts responses that carried no usage object — most often streamed Chat\n * Completions sent without `stream_options: {\"include_usage\": true}` — so a\n * rising miss rate flags clients whose token usage is going unaccounted.\n */\n recordTokenExtraction(extracted: boolean): void {\n if (extracted) {\n this.#extraction.extracted += 1;\n } else {\n this.#extraction.missing += 1;\n }\n }\n\n /** Accumulate token counts for a model from one upstream completion. */\n recordTokens(model: string, usage: TokenUsage): void {\n const name = this.#modelLabel(model);\n const totals = this.#tokens.get(name) ?? emptyModelTotals();\n totals.requests += 1;\n totals.prompt += nonNegative(usage.promptTokens);\n totals.completion += nonNegative(usage.completionTokens);\n totals.total += nonNegative(usage.totalTokens);\n totals.reasoning += nonNegative(usage.reasoningTokens ?? 0);\n totals.cached += nonNegative(usage.cachedTokens ?? 0);\n this.#tokens.set(name, totals);\n }\n\n /** Record one upstream Copilot call and whether it succeeded. */\n recordUpstream(path: string, ok: boolean): void {\n const key = labelKey(path, ok ? \"ok\" : \"error\");\n this.#upstream.set(key, (this.#upstream.get(key) ?? 0) + 1);\n }\n\n /** Store the latest Copilot quota so /metrics can expose it as gauges. */\n recordCopilotQuota(usage: CopilotUsage): void {\n this.#copilotQuota = usage;\n }\n\n /**\n * Store the latest GitHub REST rate-limit budget, keyed by its resource bucket.\n * A no-op when `rateLimit` is undefined (the response carried no rate-limit\n * headers) so callers can pass {@link parseRateLimitHeaders} output directly.\n */\n recordGithubRateLimit(rateLimit: GithubRateLimit | undefined): void {\n if (!rateLimit) {\n return;\n }\n const resource = this.#rateLimitResource(rateLimit.resource);\n this.#githubRateLimit.set(resource, { ...rateLimit, resource });\n }\n\n // Clean a raw value into a bounded exposition-format label: cap its length,\n // strip characters that would corrupt the format, and fold overflow past the\n // cardinality limit into UNKNOWN_MODEL so the series count stays bounded.\n #boundedLabel(\n value: string,\n tracked: { has(key: string): boolean; size: number },\n maxEntries: number,\n ): string {\n const cleaned = cleanLabel(value).slice(0, MAX_MODEL_LABEL_LENGTH) || UNKNOWN_MODEL;\n if (!tracked.has(cleaned) && tracked.size >= maxEntries) {\n return UNKNOWN_MODEL;\n }\n return cleaned;\n }\n\n // The model can originate from a (possibly hostile) client request.\n #modelLabel(model: string): string {\n return this.#boundedLabel(model, this.#tokens, MAX_TRACKED_MODELS);\n }\n\n // The resource comes from a trusted upstream header, but is bounded the same way.\n #rateLimitResource(resource: string): string {\n return this.#boundedLabel(resource, this.#githubRateLimit, MAX_TRACKED_RATELIMIT_RESOURCES);\n }\n\n #observeDuration(route: string, seconds: number): void {\n const value = Number.isFinite(seconds) && seconds >= 0 ? seconds : 0;\n const entry = this.#durations.get(route) ?? {\n buckets: new Array(DURATION_BUCKETS_SECONDS.length).fill(0),\n count: 0,\n sum: 0,\n };\n entry.count += 1;\n entry.sum += value;\n // Values larger than the last bucket bound only appear in the +Inf bucket,\n // which renderPrometheus derives from entry.count.\n const index = DURATION_BUCKETS_SECONDS.findIndex((bound) => value <= bound);\n if (index !== -1) {\n entry.buckets[index] = (entry.buckets[index] ?? 0) + 1;\n }\n this.#durations.set(route, entry);\n }\n\n /** A JSON-friendly view of the current counters. */\n snapshot(now: () => number = Date.now): MetricsSnapshot {\n const byRoute: Record<string, number> = {};\n const byStatus: Record<string, number> = {};\n let requestsTotal = 0;\n for (const [key, count] of this.#requests) {\n const [route = \"\", , status = \"\"] = key.split(LABEL_SEPARATOR);\n byRoute[route] = (byRoute[route] ?? 0) + count;\n byStatus[status] = (byStatus[status] ?? 0) + count;\n requestsTotal += count;\n }\n\n const byModel: Record<string, ModelTokenTotals> = {};\n const tokenTotals = { cached: 0, completion: 0, prompt: 0, reasoning: 0, total: 0 };\n for (const [model, totals] of this.#tokens) {\n byModel[model] = { ...totals };\n tokenTotals.prompt += totals.prompt;\n tokenTotals.completion += totals.completion;\n tokenTotals.total += totals.total;\n tokenTotals.reasoning += totals.reasoning;\n tokenTotals.cached += totals.cached;\n }\n\n let upstreamTotal = 0;\n let upstreamErrors = 0;\n for (const [key, count] of this.#upstream) {\n upstreamTotal += count;\n if (key.endsWith(`${LABEL_SEPARATOR}error`)) {\n upstreamErrors += count;\n }\n }\n\n const githubRateLimit: Record<string, GithubRateLimitSnapshot> = {};\n for (const [resource, rateLimit] of this.#githubRateLimit) {\n githubRateLimit[resource] = toRateLimitSnapshot(rateLimit);\n }\n\n return {\n githubRateLimit,\n inFlight: this.#inFlight,\n latency: this.#latencySnapshot(),\n requests: { byRoute, byStatus, total: requestsTotal },\n startedAt: new Date(this.#startedAtMs).toISOString(),\n tokens: { byModel, extraction: { ...this.#extraction }, ...tokenTotals },\n upstream: { errors: upstreamErrors, total: upstreamTotal },\n uptimeSeconds: Math.max(0, Math.round((now() - this.#startedAtMs) / 1000)),\n };\n }\n\n // Summarize the duration histogram into a JSON latency view: per-route count and\n // exact average, plus overall average and estimated p50/p95. The percentiles come\n // from the buckets aggregated across routes, so they share /metrics' resolution.\n #latencySnapshot(): LatencySnapshot {\n const byRoute: Record<string, RouteLatency> = {};\n const aggregateBuckets = new Array<number>(DURATION_BUCKETS_SECONDS.length).fill(0);\n let totalCount = 0;\n let totalSum = 0;\n for (const [route, entry] of this.#durations) {\n byRoute[route] = {\n avgMs: entry.count > 0 ? round2((entry.sum / entry.count) * 1000) : 0,\n count: entry.count,\n };\n totalCount += entry.count;\n totalSum += entry.sum;\n for (let i = 0; i < aggregateBuckets.length; i += 1) {\n aggregateBuckets[i] = (aggregateBuckets[i] ?? 0) + (entry.buckets[i] ?? 0);\n }\n }\n return {\n avgMs: totalCount > 0 ? round2((totalSum / totalCount) * 1000) : 0,\n byRoute,\n count: totalCount,\n p50Ms: round2(\n quantileFromBuckets(aggregateBuckets, DURATION_BUCKETS_SECONDS, totalCount, 0.5) * 1000,\n ),\n p95Ms: round2(\n quantileFromBuckets(aggregateBuckets, DURATION_BUCKETS_SECONDS, totalCount, 0.95) * 1000,\n ),\n };\n }\n\n /** Render the Prometheus text exposition format (version 0.0.4). */\n renderPrometheus(now: () => number = Date.now): string {\n const lines: string[] = [];\n\n lines.push(\"# HELP hoopilot_process_start_time_seconds Unix epoch when the proxy started.\");\n lines.push(\"# TYPE hoopilot_process_start_time_seconds gauge\");\n lines.push(`hoopilot_process_start_time_seconds ${this.#startedAtMs / 1000}`);\n\n lines.push(\"# HELP hoopilot_uptime_seconds Seconds since the proxy started.\");\n lines.push(\"# TYPE hoopilot_uptime_seconds gauge\");\n lines.push(`hoopilot_uptime_seconds ${Math.max(0, (now() - this.#startedAtMs) / 1000)}`);\n\n lines.push(\"# HELP hoopilot_requests_in_flight Requests currently being served.\");\n lines.push(\"# TYPE hoopilot_requests_in_flight gauge\");\n lines.push(`hoopilot_requests_in_flight ${this.#inFlight}`);\n\n lines.push(\"# HELP hoopilot_requests_total Completed requests by route, method, and status.\");\n lines.push(\"# TYPE hoopilot_requests_total counter\");\n for (const [key, count] of this.#requests) {\n const [route = \"\", method = \"\", status = \"\"] = key.split(LABEL_SEPARATOR);\n lines.push(`hoopilot_requests_total${labels({ method, route, status })} ${count}`);\n }\n\n lines.push(\n \"# HELP hoopilot_upstream_requests_total Copilot upstream calls by path and outcome.\",\n );\n lines.push(\"# TYPE hoopilot_upstream_requests_total counter\");\n for (const [key, count] of this.#upstream) {\n const [path = \"\", outcome = \"\"] = key.split(LABEL_SEPARATOR);\n lines.push(`hoopilot_upstream_requests_total${labels({ outcome, path })} ${count}`);\n }\n\n lines.push(\n \"# HELP hoopilot_tokens_total Tokens reported by upstream usage, by model and type.\",\n );\n lines.push(\"# TYPE hoopilot_tokens_total counter\");\n for (const [model, totals] of this.#tokens) {\n lines.push(`hoopilot_tokens_total${labels({ model, type: \"prompt\" })} ${totals.prompt}`);\n lines.push(\n `hoopilot_tokens_total${labels({ model, type: \"completion\" })} ${totals.completion}`,\n );\n lines.push(\n `hoopilot_tokens_total${labels({ model, type: \"reasoning\" })} ${totals.reasoning}`,\n );\n lines.push(`hoopilot_tokens_total${labels({ model, type: \"cached\" })} ${totals.cached}`);\n }\n\n lines.push(\"# HELP hoopilot_model_requests_total Completions with usage observed, by model.\");\n lines.push(\"# TYPE hoopilot_model_requests_total counter\");\n for (const [model, totals] of this.#tokens) {\n lines.push(`hoopilot_model_requests_total${labels({ model })} ${totals.requests}`);\n }\n\n lines.push(\n \"# HELP hoopilot_token_extraction_total Completions by whether upstream reported token usage.\",\n );\n lines.push(\"# TYPE hoopilot_token_extraction_total counter\");\n lines.push(\n `hoopilot_token_extraction_total${labels({ outcome: \"extracted\" })} ${this.#extraction.extracted}`,\n );\n lines.push(\n `hoopilot_token_extraction_total${labels({ outcome: \"missing\" })} ${this.#extraction.missing}`,\n );\n\n lines.push(\"# HELP hoopilot_request_duration_seconds Request duration by route.\");\n lines.push(\"# TYPE hoopilot_request_duration_seconds histogram\");\n for (const [route, entry] of this.#durations) {\n let cumulative = 0;\n for (let i = 0; i < DURATION_BUCKETS_SECONDS.length; i += 1) {\n cumulative += entry.buckets[i] ?? 0;\n const le = formatNumber(DURATION_BUCKETS_SECONDS[i] ?? 0);\n lines.push(\n `hoopilot_request_duration_seconds_bucket${labels({ le, route })} ${cumulative}`,\n );\n }\n lines.push(\n `hoopilot_request_duration_seconds_bucket${labels({ le: \"+Inf\", route })} ${entry.count}`,\n );\n lines.push(`hoopilot_request_duration_seconds_sum${labels({ route })} ${entry.sum}`);\n lines.push(`hoopilot_request_duration_seconds_count${labels({ route })} ${entry.count}`);\n }\n\n this.#renderGithubRateLimit(lines);\n this.#renderCopilotQuota(lines);\n\n return `${lines.join(\"\\n\")}\\n`;\n }\n\n #renderGithubRateLimit(lines: string[]): void {\n const entries = [...this.#githubRateLimit.values()];\n if (entries.length === 0) {\n return;\n }\n\n const gauge = (\n suffix: string,\n help: string,\n pick: (rateLimit: GithubRateLimit) => number | undefined,\n ): void => {\n const present = entries.filter((rateLimit) => pick(rateLimit) !== undefined);\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_github_ratelimit_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_github_ratelimit_${suffix} gauge`);\n for (const rateLimit of present) {\n lines.push(\n `hoopilot_github_ratelimit_${suffix}${labels({ resource: rateLimit.resource })} ${pick(rateLimit)}`,\n );\n }\n };\n\n gauge(\"limit\", \"GitHub REST API request ceiling for the resource window.\", (r) => r.limit);\n gauge(\"remaining\", \"Requests remaining in the GitHub REST API window.\", (r) => r.remaining);\n gauge(\"used\", \"Requests used in the GitHub REST API window.\", (r) => r.used);\n gauge(\n \"reset_timestamp_seconds\",\n \"Unix epoch when the GitHub REST API window resets.\",\n (r) => r.resetEpochSeconds,\n );\n gauge(\n \"retry_after_seconds\",\n \"Seconds to wait after a GitHub secondary-limit response.\",\n (r) => r.retryAfterSeconds,\n );\n }\n\n #renderCopilotQuota(lines: string[]): void {\n const usage = this.#copilotQuota;\n if (!usage) {\n return;\n }\n const categories = Object.entries(usage.quotas);\n\n const gauge = (\n suffix: string,\n help: string,\n pick: (quota: CopilotQuota) => number | undefined,\n ): void => {\n const present = categories.filter(([, quota]) => pick(quota) !== undefined);\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);\n for (const [category, quota] of present) {\n lines.push(`hoopilot_copilot_quota_${suffix}${labels({ category })} ${pick(quota)}`);\n }\n };\n\n gauge(\"remaining\", \"Remaining quota for the Copilot category.\", (q) => q.remaining);\n gauge(\"entitlement\", \"Quota entitlement for the Copilot category.\", (q) => q.entitlement);\n gauge(\"used\", \"Used quota (entitlement minus remaining) for the category.\", (q) => q.used);\n gauge(\"overage_count\", \"Overage count for the Copilot category.\", (q) => q.overageCount);\n gauge(\n \"overage_entitlement\",\n \"Overage entitlement for the Copilot category.\",\n (q) => q.overageEntitlement,\n );\n gauge(\n \"percent_remaining\",\n \"Percent of quota remaining for the Copilot category.\",\n (q) => q.percentRemaining,\n );\n booleanGauge(\n \"unlimited\",\n \"Whether the Copilot quota category is unlimited.\",\n (q) => q.unlimited,\n );\n booleanGauge(\n \"overage_permitted\",\n \"Whether overage is permitted for the Copilot category.\",\n (q) => q.overagePermitted,\n );\n booleanGauge(\"has_quota\", \"Whether the Copilot quota category has a quota.\", (q) => q.hasQuota);\n booleanGauge(\n \"token_based_billing\",\n \"Whether the Copilot quota category uses token-based billing.\",\n (q) => q.tokenBasedBilling,\n );\n dateGauge(\n \"category_reset_timestamp_seconds\",\n \"Unix epoch of the Copilot category-specific quota reset.\",\n (q) => q.quotaResetAt,\n );\n dateGauge(\n \"category_snapshot_timestamp_seconds\",\n \"Unix epoch of the Copilot category quota snapshot.\",\n (q) => q.timestampUtc,\n );\n\n const resetMs = usage.quotaResetDate ? Date.parse(usage.quotaResetDate) : Number.NaN;\n if (Number.isFinite(resetMs)) {\n lines.push(\n \"# HELP hoopilot_copilot_quota_reset_timestamp_seconds Unix epoch of the next reset.\",\n );\n lines.push(\"# TYPE hoopilot_copilot_quota_reset_timestamp_seconds gauge\");\n lines.push(`hoopilot_copilot_quota_reset_timestamp_seconds ${resetMs / 1000}`);\n }\n\n if (usage.plan || usage.accessTypeSku) {\n lines.push(\"# HELP hoopilot_copilot_info Copilot plan metadata as a constant-1 info gauge.\");\n lines.push(\"# TYPE hoopilot_copilot_info gauge\");\n lines.push(\n `hoopilot_copilot_info${labels({\n access_type_sku: usage.accessTypeSku ?? \"\",\n plan: usage.plan ?? \"\",\n })} 1`,\n );\n }\n\n function booleanGauge(\n suffix: string,\n help: string,\n pick: (quota: CopilotQuota) => boolean | undefined,\n ): void {\n const present = categories.filter(([, quota]) => pick(quota) !== undefined);\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);\n for (const [category, quota] of present) {\n lines.push(\n `hoopilot_copilot_quota_${suffix}${labels({ category })} ${pick(quota) ? 1 : 0}`,\n );\n }\n }\n\n function dateGauge(\n suffix: string,\n help: string,\n pick: (quota: CopilotQuota) => string | undefined,\n ): void {\n const present = categories\n .map(([category, quota]) => [category, Date.parse(pick(quota) ?? \"\")] as const)\n .filter(([, timestamp]) => Number.isFinite(timestamp));\n if (present.length === 0) {\n return;\n }\n lines.push(`# HELP hoopilot_copilot_quota_${suffix} ${help}`);\n lines.push(`# TYPE hoopilot_copilot_quota_${suffix} gauge`);\n for (const [category, timestamp] of present) {\n lines.push(`hoopilot_copilot_quota_${suffix}${labels({ category })} ${timestamp / 1000}`);\n }\n }\n }\n}\n\n/**\n * Wrap `response`'s body so the client receives unchanged bytes while the same\n * read pass extracts token usage. Returns a new Response carrying the observed\n * body and the original status/headers. Usage extraction never throws into the\n * client stream: a parse failure or an aborted client simply yields no usage.\n * When the body is absent the response is returned untouched.\n *\n * Pass the request's `signal` so a client disconnect cancels the observer\n * branch; combined with the runtime cancelling the client branch, that releases\n * the shared upstream connection instead of draining it in the background.\n */\nexport function observeResponseUsage(\n response: Response,\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n signal?: AbortSignal,\n onOutcome?: (extracted: boolean) => void,\n): Response {\n const body = response.body;\n if (!body) {\n return response;\n }\n const isSse = response.headers.get(\"content-type\")?.includes(\"text/event-stream\") ?? false;\n return new Response(\n streamWithUsageObservation(body, isSse, fallbackModel, onUsage, signal, onOutcome),\n {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n },\n );\n}\n\n/** Extract and record token usage from an already-buffered response body. */\nexport function recordResponseTextUsage(\n text: string,\n isSse: boolean,\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n onOutcome?: (extracted: boolean) => void,\n): void {\n const accumulator = createUsageAccumulator(fallbackModel, onUsage, onOutcome);\n if (isSse) {\n for (const line of text.split(/\\r?\\n/)) {\n considerSseLine(line, accumulator.consider);\n }\n } else {\n const parsed = safeJsonParse(text);\n if (parsed !== undefined) {\n accumulator.consider(parsed);\n }\n }\n accumulator.finish();\n}\n\nfunction streamWithUsageObservation(\n stream: ReadableStream<Uint8Array>,\n isSse: boolean,\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n signal?: AbortSignal,\n onOutcome?: (extracted: boolean) => void,\n): ReadableStream<Uint8Array> {\n const reader = stream.getReader();\n let aborted = signal?.aborted ?? false;\n let released = false;\n const onAbort = () => {\n aborted = true;\n reader.cancel().catch(() => {});\n };\n if (aborted) {\n reader.cancel().catch(() => {});\n } else {\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n const decoder = new TextDecoder();\n // A client disconnect cancels the reader mid-stream; don't count that as a\n // missing-usage completion — only record outcomes for streams we finished.\n const guardedOutcome = onOutcome\n ? (extracted: boolean) => {\n if (!aborted) {\n onOutcome(extracted);\n }\n }\n : undefined;\n const accumulator = createUsageAccumulator(fallbackModel, onUsage, guardedOutcome);\n let buffer = \"\";\n let bufferedBytes = 0;\n let overflowed = false;\n\n const release = (): void => {\n if (released) {\n return;\n }\n released = true;\n signal?.removeEventListener(\"abort\", onAbort);\n reader.releaseLock();\n };\n\n const observeChunk = (chunkBytes: Uint8Array): void => {\n const chunk = decoder.decode(chunkBytes, { stream: true });\n if (isSse) {\n buffer += chunk;\n const lines = buffer.split(/\\r?\\n/);\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n considerSseLine(line, accumulator.consider);\n }\n // Drop a pathologically long newline-less line so the buffer stays bounded.\n if (buffer.length > USAGE_BUFFER_LIMIT_BYTES) {\n buffer = \"\";\n }\n return;\n }\n if (overflowed) {\n return;\n }\n bufferedBytes += chunkBytes.byteLength;\n if (bufferedBytes > USAGE_BUFFER_LIMIT_BYTES) {\n overflowed = true;\n buffer = \"\";\n return;\n }\n buffer += chunk;\n };\n\n const finishObservation = (): void => {\n const finalBuffer = buffer + decoder.decode();\n if (isSse) {\n if (finalBuffer) {\n considerSseLine(finalBuffer, accumulator.consider);\n }\n } else if (!overflowed && finalBuffer) {\n const parsed = safeJsonParse(finalBuffer);\n if (parsed !== undefined) {\n accumulator.consider(parsed);\n }\n }\n if (!aborted) {\n safeFinishAccumulator(accumulator);\n }\n };\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n const result = await reader.read().catch((error: unknown) => {\n release();\n controller.error(error);\n return undefined;\n });\n if (!result) {\n return;\n }\n if (result.done) {\n finishObservation();\n controller.close();\n release();\n return;\n }\n try {\n observeChunk(result.value);\n } catch {\n // Metrics extraction is best-effort and must not affect the client body.\n }\n controller.enqueue(result.value);\n },\n async cancel(reason) {\n aborted = true;\n try {\n await reader.cancel(reason);\n } finally {\n release();\n }\n },\n });\n}\n\nfunction createUsageAccumulator(\n fallbackModel: string,\n onUsage: (model: string, usage: TokenUsage) => void,\n onOutcome?: (extracted: boolean) => void,\n): { consider: (payload: unknown) => void; finish: () => void } {\n let model = fallbackModel;\n let usage: TokenUsage | undefined;\n return {\n consider(payload) {\n const record = asRecord(payload);\n const found =\n extractTokenUsage(record.usage) ?? extractTokenUsage(asRecord(record.response).usage);\n if (found) {\n usage = found;\n }\n const candidateModel = modelText(record.model) || modelText(asRecord(record.response).model);\n if (candidateModel) {\n model = candidateModel;\n }\n },\n finish() {\n if (usage) {\n onUsage(model, usage);\n }\n onOutcome?.(usage !== undefined);\n },\n };\n}\n\nfunction safeFinishAccumulator(accumulator: { finish: () => void }): void {\n try {\n accumulator.finish();\n } catch {\n // Best-effort metrics extraction must never disturb the proxied response.\n }\n}\n\nfunction considerSseLine(line: string, consider: (payload: unknown) => void): void {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) {\n return;\n }\n const data = trimmed.slice(\"data:\".length).trim();\n if (!data || data === \"[DONE]\") {\n return;\n }\n const parsed = safeJsonParse(data);\n if (parsed !== undefined) {\n consider(parsed);\n }\n}\n\nfunction modelText(value: unknown): string {\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction nonNegative(value: number): number {\n return Number.isFinite(value) && value > 0 ? value : 0;\n}\n\nfunction round2(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\n// Estimate a latency quantile from histogram bucket counts via Prometheus-style\n// linear interpolation within the bucket the target rank lands in. `bucketCounts[i]`\n// is the number of observations in `(bounds[i-1], bounds[i]]`; observations above the\n// last finite bound live only in the implicit +Inf bucket, for which that bound is\n// returned. Returns seconds.\nfunction quantileFromBuckets(\n bucketCounts: number[],\n bounds: readonly number[],\n count: number,\n q: number,\n): number {\n if (count <= 0) {\n return 0;\n }\n const rank = q * count;\n let cumulative = 0;\n for (let i = 0; i < bounds.length; i += 1) {\n const inBucket = bucketCounts[i] ?? 0;\n if (inBucket > 0 && cumulative + inBucket >= rank) {\n const lower = i === 0 ? 0 : (bounds[i - 1] ?? 0);\n const upper = bounds[i] ?? lower;\n return lower + (upper - lower) * ((rank - cumulative) / inBucket);\n }\n cumulative += inBucket;\n }\n return bounds[bounds.length - 1] ?? 0;\n}\n\n// Drop ASCII control characters (and DEL) that would corrupt the Prometheus\n// exposition format, then trim. Used for labels sourced from an upstream header,\n// mirroring the control-char stripping applied to client-supplied model labels.\nfunction cleanLabel(value: string): string {\n let result = \"\";\n for (const char of value) {\n const code = char.charCodeAt(0);\n if (code > 0x1f && code !== 0x7f) {\n result += char;\n }\n }\n return result.trim();\n}\n\n// Convert the internal rate-limit record into its JSON snapshot shape: the epoch\n// reset and observation times become ISO strings, and absent fields stay absent.\nfunction toRateLimitSnapshot(rateLimit: GithubRateLimit): GithubRateLimitSnapshot {\n const snapshot: GithubRateLimitSnapshot = {\n observedAt: new Date(rateLimit.observedAtMs).toISOString(),\n };\n if (rateLimit.limit !== undefined) {\n snapshot.limit = rateLimit.limit;\n }\n if (rateLimit.remaining !== undefined) {\n snapshot.remaining = rateLimit.remaining;\n }\n if (rateLimit.used !== undefined) {\n snapshot.used = rateLimit.used;\n }\n if (rateLimit.resetEpochSeconds !== undefined) {\n snapshot.resetAt = new Date(rateLimit.resetEpochSeconds * 1000).toISOString();\n }\n if (rateLimit.retryAfterSeconds !== undefined) {\n snapshot.retryAfterSeconds = rateLimit.retryAfterSeconds;\n }\n return snapshot;\n}\n\nfunction labelKey(...parts: string[]): string {\n return parts.join(LABEL_SEPARATOR);\n}\n\nfunction labels(pairs: Record<string, string>): string {\n const entries = Object.entries(pairs);\n if (entries.length === 0) {\n return \"\";\n }\n const rendered = entries.map(([name, value]) => `${name}=\"${escapeLabelValue(value)}\"`);\n return `{${rendered.join(\",\")}}`;\n}\n\nfunction escapeLabelValue(value: string): string {\n return value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\");\n}\n\nfunction formatNumber(value: number): string {\n return Number.isInteger(value) ? value.toString() : String(value);\n}\n","import { asRecord } from \"./util\";\n\n// Build-time constants. For standalone binaries these identifiers are replaced\n// at compile time via `bun build --compile --define 'HOOPILOT_VERSION=\"x.y.z\"'`\n// (see scripts/build-binaries.sh). In dev runs and the npm package they are not\n// defined, so `typeof` is \"undefined\" and we fall back to reading package.json.\ndeclare const HOOPILOT_VERSION: string;\ndeclare const HOOPILOT_TARGET: string;\n\n/** Version baked into a standalone binary, or undefined for npm/dev installs. */\nexport const BAKED_VERSION: string | undefined =\n typeof HOOPILOT_VERSION !== \"undefined\" ? HOOPILOT_VERSION : undefined;\n\n/**\n * Release asset suffix baked into a standalone binary (e.g. \"linux-x64-musl\",\n * \"windows-x64\", \"darwin-arm64\"), or undefined for npm/dev installs. Lets the\n * self-updater fetch the exact asset variant it was built from.\n */\nexport const BAKED_TARGET: string | undefined =\n typeof HOOPILOT_TARGET !== \"undefined\" ? HOOPILOT_TARGET : undefined;\n\n/** True when running as a `bun build --compile` standalone executable. */\nexport const IS_STANDALONE_BINARY: boolean = BAKED_VERSION !== undefined;\n\nlet cachedVersion: string | undefined;\n\n/** Resolve the running version, preferring the baked value for binaries. */\nexport async function getVersion(): Promise<string> {\n if (cachedVersion !== undefined) {\n return cachedVersion;\n }\n let resolved: string;\n if (BAKED_VERSION) {\n resolved = BAKED_VERSION;\n } else {\n try {\n const manifest = asRecord(await Bun.file(new URL(\"../package.json\", import.meta.url)).json());\n const version = manifest.version;\n resolved = typeof version === \"string\" ? version : \"0.0.0\";\n } catch {\n resolved = \"0.0.0\";\n }\n }\n cachedVersion = resolved;\n return resolved;\n}\n","// Self-update and update-notification orchestration. The pure decision logic\n// lives in update-core.ts; this module performs the network and filesystem I/O.\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport {\n chmodSync,\n copyFileSync,\n existsSync,\n mkdirSync,\n realpathSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { errorDetails } from \"./logger\";\nimport type { HoopilotLogger } from \"./types\";\nimport {\n assetNameFor,\n assetSuffixFor,\n checksumFor,\n codexxShimFiles,\n formatUpdateNotice,\n type InstallKind,\n isOutdated,\n isUpdateCheckDisabled,\n type LatestRelease,\n latestReleaseApiUrl,\n parseLatestRelease,\n parseState,\n resolveCacheDir,\n shouldCleanupOldBinary,\n shouldRefresh,\n type UpdateState,\n upgradeCommandFor,\n} from \"./update-core\";\nimport { errorMessage } from \"./util\";\nimport { BAKED_TARGET, IS_STANDALONE_BINARY } from \"./version\";\n\nconst REQUEST_TIMEOUT_MS = 8_000;\n// Binary and checksum downloads share one generous timeout, distinct from the\n// short metadata-request timeout that uses REQUEST_TIMEOUT_MS directly.\nconst DOWNLOAD_TIMEOUT_MS = REQUEST_TIMEOUT_MS * 10;\nconst SHA256SUMS = \"SHA256SUMS\";\n\nfunction userAgent(version: string): string {\n return `hoopilot/${version}`;\n}\n\nfunction cacheDir(): string {\n return resolveCacheDir(process.env, process.platform, homedir(), join);\n}\n\nfunction stateFilePath(): string {\n return join(cacheDir(), \"update-check.json\");\n}\n\nasync function readStateSafe(): Promise<UpdateState> {\n try {\n return parseState(await readFile(stateFilePath(), \"utf8\"));\n } catch {\n return { lastCheck: 0, latestVersion: null, etag: null };\n }\n}\n\nasync function writeStateSafe(state: UpdateState): Promise<void> {\n try {\n mkdirSync(cacheDir(), { recursive: true });\n await writeFile(stateFilePath(), JSON.stringify(state), \"utf8\");\n } catch {\n // best effort: a read-only cache dir must never break the CLI\n }\n}\n\ninterface FetchResult {\n status: number;\n etag: string | null;\n release: LatestRelease | null;\n}\n\nasync function fetchLatest(version: string, etag?: string | null): Promise<FetchResult | null> {\n try {\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github+json\",\n \"User-Agent\": userAgent(version),\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n };\n if (etag) {\n headers[\"If-None-Match\"] = etag;\n }\n const response = await fetch(latestReleaseApiUrl(), {\n headers,\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n if (response.status === 304) {\n return { status: 304, etag: etag ?? null, release: null };\n }\n if (!response.ok) {\n return { status: response.status, etag: null, release: null };\n }\n return {\n status: response.status,\n etag: response.headers.get(\"etag\"),\n release: parseLatestRelease(await response.json()),\n };\n } catch {\n return null; // offline / timeout: caller leaves state untouched\n }\n}\n\n/**\n * Print a notice if a previously-cached check found a newer release, then kick\n * off a throttled background refresh. Never blocks on the network and never\n * throws. Intended to be called (unawaited is fine) from the serve path.\n */\nexport async function maybeNotifyUpdate(\n currentVersion: string,\n kind: InstallKind,\n logger?: HoopilotLogger,\n): Promise<void> {\n if (isUpdateCheckDisabled(process.env, Boolean(process.stderr.isTTY))) {\n logger?.debug({ event: \"update.check.skipped\" }, \"update check skipped\");\n return;\n }\n const state = await readStateSafe();\n if (state.latestVersion && isOutdated(currentVersion, state.latestVersion)) {\n logger?.debug(\n {\n currentVersion,\n event: \"update.notice.cached\",\n installKind: kind,\n latestVersion: state.latestVersion,\n },\n \"showing cached update notice\",\n );\n process.stderr.write(formatUpdateNotice(currentVersion, state.latestVersion, kind));\n }\n if (shouldRefresh(state.lastCheck, Date.now())) {\n logger?.debug({ event: \"update.check.refresh_queued\" }, \"queued update check refresh\");\n void refreshState(currentVersion, state.etag ?? null, logger).catch((error: unknown) => {\n logger?.debug(\n { err: errorDetails(error), event: \"update.check.refresh_failed\" },\n \"update check refresh failed\",\n );\n });\n }\n}\n\nasync function refreshState(\n currentVersion: string,\n etag: string | null,\n logger?: HoopilotLogger,\n): Promise<void> {\n const result = await fetchLatest(currentVersion, etag);\n if (!result) {\n logger?.debug({ event: \"update.check.unavailable\" }, \"update check unavailable\");\n return; // network error: keep prior state\n }\n if (result.status === 304) {\n const prev = await readStateSafe();\n await writeStateSafe({ ...prev, lastCheck: Date.now() });\n logger?.debug({ event: \"update.check.not_modified\" }, \"latest release unchanged\");\n return;\n }\n if (result.release) {\n await writeStateSafe({\n lastCheck: Date.now(),\n latestVersion: result.release.version,\n etag: result.etag,\n });\n logger?.debug(\n { event: \"update.check.updated\", latestVersion: result.release.version },\n \"updated cached latest release state\",\n );\n }\n}\n\nfunction detectInstallKind(): InstallKind {\n return IS_STANDALONE_BINARY ? \"binary\" : \"npm\";\n}\n\nfunction detectMusl(): boolean {\n if (process.platform !== \"linux\") {\n return false;\n }\n try {\n const report = process.report?.getReport?.() as\n | { header?: Record<string, unknown> }\n | undefined;\n if (report?.header && \"glibcVersionRuntime\" in report.header) {\n return !report.header.glibcVersionRuntime;\n }\n } catch {\n // fall through to file-based detection\n }\n try {\n if (existsSync(\"/etc/alpine-release\")) {\n return true;\n }\n const ldd = execFileSync(\"ldd\", [\"--version\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: 2_000,\n });\n return /musl/i.test(ldd);\n } catch {\n return false;\n }\n}\n\nasync function downloadToFile(url: string, dest: string, version: string): Promise<void> {\n const response = await fetch(url, {\n headers: { \"User-Agent\": userAgent(version) },\n redirect: \"follow\",\n signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n });\n if (!response.ok || !response.body) {\n throw new Error(`Download failed (${response.status}) for ${url}`);\n }\n // Stream the body straight to disk instead of buffering the whole binary.\n await Bun.write(dest, response);\n}\n\nasync function sha256File(path: string): Promise<string> {\n return createHash(\"sha256\")\n .update(await readFile(path))\n .digest(\"hex\");\n}\n\nasync function verifyChecksum(\n release: LatestRelease,\n assetName: string,\n file: string,\n version: string,\n): Promise<void> {\n const sums = release.assets.find((asset) => asset.name === SHA256SUMS);\n if (!sums) {\n // Fail closed: never overwrite the running binary with an unverified download.\n throw new Error(\n `Release ${release.tag} has no ${SHA256SUMS}; refusing to install an unverified binary.`,\n );\n }\n const response = await fetch(sums.url, {\n headers: { \"User-Agent\": userAgent(version) },\n redirect: \"follow\",\n signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n });\n if (!response.ok) {\n throw new Error(`Could not download ${SHA256SUMS} (${response.status}).`);\n }\n const expected = checksumFor(await response.text(), assetName);\n if (!expected) {\n throw new Error(`No checksum for ${assetName} in ${SHA256SUMS}.`);\n }\n const actual = await sha256File(file);\n if (actual.toLowerCase() !== expected) {\n throw new Error(`Checksum mismatch for ${assetName}: expected ${expected}, got ${actual}.`);\n }\n}\n\nfunction swapBinary(tmpFile: string, exePath: string): void {\n if (process.platform === \"win32\") {\n // A running .exe cannot be overwritten, but it can be renamed aside.\n const oldExe = `${exePath}.old`;\n try {\n rmSync(oldExe, { force: true });\n } catch {\n // a previous .old may still be locked; the new name still wins below\n }\n renameSync(exePath, oldExe);\n const restore = () => {\n try {\n renameSync(oldExe, exePath); // put the working binary back\n } catch {\n // nothing more we can do\n }\n };\n try {\n renameSync(tmpFile, exePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EXDEV\") {\n try {\n copyFileSync(tmpFile, exePath);\n } catch (copyError) {\n restore();\n throw copyError;\n }\n } else {\n restore();\n throw error;\n }\n }\n return;\n }\n // Unix: atomic rename over the running file; the old inode stays mapped until exit.\n try {\n renameSync(tmpFile, exePath);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EXDEV\") {\n copyFileSync(tmpFile, exePath);\n chmodSync(exePath, 0o755);\n } else if (code === \"EACCES\" || code === \"EPERM\") {\n throw new Error(\n `No permission to update ${exePath}. Re-run with sudo, or reinstall to a writable directory.`,\n );\n } else {\n throw error;\n }\n }\n}\n\nfunction refreshCodexxShim(dir: string, logger?: HoopilotLogger): void {\n try {\n for (const file of codexxShimFiles(process.platform)) {\n const path = join(dir, file.name);\n writeFileSync(path, file.content, \"utf8\");\n if (file.executable) {\n chmodSync(path, 0o755);\n }\n }\n } catch (error) {\n logger?.warn(\n { err: errorDetails(error), event: \"update.codexx_shim_failed\" },\n \"could not refresh codexx shim\",\n );\n console.warn(`Updated hoopilot, but could not refresh the codexx shim: ${errorMessage(error)}`);\n }\n}\n\n/** Remove the leftover \".old\" binary from a prior Windows self-update. */\nexport function cleanupOldBinary(): void {\n if (!shouldCleanupOldBinary(process.platform, IS_STANDALONE_BINARY)) {\n return;\n }\n try {\n rmSync(`${realpathSync(process.execPath)}.old`, { force: true });\n } catch {\n // still locked or already gone\n }\n}\n\n/** Implements the `hoopilot update` command. */\nexport async function runUpdate(currentVersion: string, logger?: HoopilotLogger): Promise<void> {\n cleanupOldBinary();\n const kind = detectInstallKind();\n logger?.debug({ currentVersion, event: \"update.started\", installKind: kind }, \"update started\");\n\n if (kind !== \"binary\") {\n console.log(`hoopilot ${currentVersion} was installed via npm.`);\n console.log(`Update with: ${upgradeCommandFor(\"npm\")}`);\n return;\n }\n\n console.log(`hoopilot ${currentVersion} — checking for updates...`);\n const result = await fetchLatest(currentVersion);\n const release = result?.release ?? null;\n if (!release) {\n throw new Error(\"Could not reach GitHub to check for the latest release.\");\n }\n if (!isOutdated(currentVersion, release.version)) {\n logger?.debug(\n { currentVersion, event: \"update.already_current\", latestVersion: release.version },\n \"hoopilot is already up to date\",\n );\n console.log(`Already up to date (latest: ${release.version}).`);\n return;\n }\n\n const suffix = BAKED_TARGET ?? assetSuffixFor(process.platform, process.arch, detectMusl());\n const assetName = assetNameFor(suffix);\n const asset = release.assets.find((entry) => entry.name === assetName);\n if (!asset) {\n const available = release.assets.map((entry) => entry.name).join(\", \") || \"none\";\n throw new Error(`Release ${release.tag} has no asset \"${assetName}\". Available: ${available}.`);\n }\n\n console.log(`Updating ${currentVersion} → ${release.version} (${assetName})...`);\n logger?.debug(\n {\n assetName,\n currentVersion,\n event: \"update.installing\",\n latestVersion: release.version,\n },\n \"installing update\",\n );\n const exePath = realpathSync(process.execPath);\n const tmpFile = join(dirname(exePath), `.hoopilot-update-${process.pid}.tmp`);\n try {\n await downloadToFile(asset.url, tmpFile, currentVersion);\n await verifyChecksum(release, assetName, tmpFile, currentVersion);\n if (process.platform !== \"win32\") {\n chmodSync(tmpFile, 0o755);\n }\n swapBinary(tmpFile, exePath);\n refreshCodexxShim(dirname(exePath), logger);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EACCES\" || code === \"EPERM\") {\n throw new Error(\n `No permission to update ${exePath}. Re-run with sudo, or reinstall to a writable directory (e.g. set HOOPILOT_INSTALL_DIR).`,\n );\n }\n throw error;\n } finally {\n try {\n rmSync(tmpFile, { force: true });\n } catch {\n // already moved into place or never created\n }\n }\n\n console.log(`Updated hoopilot to ${release.version}.`);\n logger?.debug(\n { currentVersion, event: \"update.completed\", latestVersion: release.version },\n \"update completed\",\n );\n if (process.platform === \"win32\") {\n console.log(\"Restart hoopilot to run the new version.\");\n }\n}\n","// Pure, dependency-free logic for version checks and self-update decisions.\n// Everything here is side-effect free so it can be unit tested without network\n// or filesystem access; the I/O orchestration lives in update.ts.\n\nconst REPO_OWNER = \"openhoo\";\nconst REPO_NAME = \"hoopilot\";\nexport const REPO = `${REPO_OWNER}/${REPO_NAME}`;\nexport const NPM_PACKAGE = \"@openhoo/hoopilot\";\n\n/** How a copy of hoopilot was installed. */\nexport type InstallKind = \"binary\" | \"npm\";\n\n/** How often the background update check is allowed to hit GitHub. */\nexport const UPDATE_CHECK_INTERVAL_MS = 1000 * 60 * 60 * 24; // 24h\n\n/** Persisted state for the throttled update check. */\nexport interface UpdateState {\n lastCheck: number;\n latestVersion: string | null;\n etag: string | null;\n}\n\nexport interface CodexxShimFile {\n content: string;\n executable: boolean;\n name: string;\n}\n\ninterface SemVer {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nfunction parseSemver(input: string): SemVer | null {\n const value = String(input)\n .trim()\n .replace(/^[v=]+/, \"\");\n const match = value.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+[0-9A-Za-z.-]+)?$/);\n if (!match) {\n return null;\n }\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n // Build metadata (everything after \"+\") is intentionally dropped.\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\nfunction comparePrerelease(a: string[], b: string[]): -1 | 0 | 1 {\n if (a.length === 0 && b.length === 0) {\n return 0;\n }\n // A release outranks an otherwise-equal prerelease.\n if (a.length === 0) {\n return 1;\n }\n if (b.length === 0) {\n return -1;\n }\n const len = Math.max(a.length, b.length);\n for (let i = 0; i < len; i++) {\n const x = a[i];\n const y = b[i];\n // The version with more prerelease fields has higher precedence.\n if (x === undefined) {\n return -1;\n }\n if (y === undefined) {\n return 1;\n }\n const xNumeric = /^\\d+$/.test(x);\n const yNumeric = /^\\d+$/.test(y);\n if (xNumeric && yNumeric) {\n const diff = Number(x) - Number(y);\n if (diff !== 0) {\n return diff < 0 ? -1 : 1;\n }\n } else if (xNumeric) {\n return -1; // numeric identifiers sort lower than alphanumeric\n } else if (yNumeric) {\n return 1;\n } else if (x !== y) {\n return x < y ? -1 : 1; // ASCII lexical\n }\n }\n return 0;\n}\n\n/**\n * Compare two semantic versions. Returns -1 if a < b, 0 if equal, 1 if a > b.\n * Tolerates a leading \"v\"/\"=\", ignores build metadata, honors prerelease\n * precedence, and sorts unparseable input low so a bad value never throws.\n */\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const pa = parseSemver(a);\n const pb = parseSemver(b);\n if (!pa || !pb) {\n if (!pa && !pb) {\n return 0;\n }\n return pa ? 1 : -1;\n }\n if (pa.major !== pb.major) {\n return pa.major < pb.major ? -1 : 1;\n }\n if (pa.minor !== pb.minor) {\n return pa.minor < pb.minor ? -1 : 1;\n }\n if (pa.patch !== pb.patch) {\n return pa.patch < pb.patch ? -1 : 1;\n }\n return comparePrerelease(pa.prerelease, pb.prerelease);\n}\n\n/** True when `latest` is a strictly newer release than `current`. */\nexport function isOutdated(current: string, latest: string): boolean {\n return compareSemver(current, latest) < 0;\n}\n\n/** Strip a leading \"v\" from a git tag to get a bare version string. */\nexport function versionFromTag(tag: string): string {\n return tag.trim().replace(/^v/, \"\");\n}\n\n/**\n * Compute the release asset suffix for a platform/arch, e.g. \"linux-x64-musl\",\n * \"darwin-arm64\", \"windows-x64\". `platform`/`arch` use Node's process values.\n */\nexport function assetSuffixFor(platform: string, arch: string, isMusl: boolean): string {\n const os =\n platform === \"linux\"\n ? \"linux\"\n : platform === \"win32\"\n ? \"windows\"\n : platform === \"darwin\"\n ? \"darwin\"\n : undefined;\n if (!os) {\n throw new Error(`Unsupported platform for standalone updates: ${platform}.`);\n }\n\n const cpu =\n arch === \"x64\" || arch === \"amd64\"\n ? \"x64\"\n : arch === \"arm64\" || arch === \"aarch64\"\n ? \"arm64\"\n : undefined;\n if (!cpu) {\n throw new Error(`Unsupported architecture for standalone updates: ${arch}.`);\n }\n\n const libc = os === \"linux\" && isMusl ? \"-musl\" : \"\";\n return `${os}-${cpu}${libc}`;\n}\n\n/** Full release asset file name for a suffix (adds .exe for Windows). */\nexport function assetNameFor(suffix: string): string {\n const name = `hoopilot-${suffix}`;\n return suffix.startsWith(\"windows-\") ? `${name}.exe` : name;\n}\n\n/** Whether automatic update checks should be skipped, per env + TTY. */\nexport function isUpdateCheckDisabled(\n env: Record<string, string | undefined>,\n isTty: boolean,\n): boolean {\n if (env.HOOPILOT_NO_UPDATE_CHECK || env.NO_UPDATE_NOTIFIER) {\n return true;\n }\n if (env.NODE_ENV === \"test\") {\n return true;\n }\n if (!isTty) {\n return true; // piped / non-interactive output\n }\n if (\n (env.CI && env.CI !== \"false\") ||\n env.CONTINUOUS_INTEGRATION ||\n env.GITHUB_ACTIONS ||\n env.BUILD_NUMBER ||\n env.RUN_ID\n ) {\n return true;\n }\n return false;\n}\n\n/** Whether the background check is due again given the last check time. */\nexport function shouldRefresh(\n lastCheck: number,\n now: number,\n intervalMs = UPDATE_CHECK_INTERVAL_MS,\n): boolean {\n return now - lastCheck >= intervalMs;\n}\n\n/** The command a user runs to upgrade, depending on how they installed. */\nexport function upgradeCommandFor(kind: InstallKind): string {\n return kind === \"binary\"\n ? \"hoopilot update\"\n : `npm install -g ${NPM_PACKAGE}@latest (or: bun add -g ${NPM_PACKAGE})`;\n}\n\n/** Whether it is safe to remove a leftover Windows self-update backup. */\nexport function shouldCleanupOldBinary(platform: string, isStandaloneBinary: boolean): boolean {\n return platform === \"win32\" && isStandaloneBinary;\n}\n\n/** Files that expose the standalone `codexx` command next to the `hoopilot` binary. */\nexport function codexxShimFiles(platform: string): CodexxShimFile[] {\n if (platform === \"win32\") {\n return [\n {\n content: `$ErrorActionPreference = 'Stop'\n$hoopilot = Join-Path $PSScriptRoot 'hoopilot.exe'\n& $hoopilot codexx @args\nexit $LASTEXITCODE\n`,\n executable: false,\n name: \"codexx.ps1\",\n },\n {\n content: `@echo off\nsetlocal\nwhere pwsh >nul 2>nul\nif %ERRORLEVEL% EQU 0 (\n pwsh -NoProfile -ExecutionPolicy Bypass -File \"%~dp0codexx.ps1\" %*\n) else (\n powershell -NoProfile -ExecutionPolicy Bypass -File \"%~dp0codexx.ps1\" %*\n)\nexit /b %ERRORLEVEL%\n`,\n executable: false,\n name: \"codexx.cmd\",\n },\n ];\n }\n return [\n {\n content: `#!/bin/sh\nset -eu\nscript_dir=$(CDPATH= cd \"$(dirname \"$0\")\" && pwd)\nexec \"$script_dir/hoopilot\" codexx \"$@\"\n`,\n executable: true,\n name: \"codexx\",\n },\n ];\n}\n\n/** Render the \"update available\" notice printed to stderr. */\nexport function formatUpdateNotice(current: string, latest: string, kind: InstallKind): string {\n return (\n `\\nUpdate available for hoopilot: ${current} → ${latest}\\n` +\n `Run: ${upgradeCommandFor(kind)}\\n\\n`\n );\n}\n\n/** Parse the persisted update-check state, tolerating any malformed input. */\nexport function parseState(text: string): UpdateState {\n try {\n const data: unknown = JSON.parse(text);\n const record = (data && typeof data === \"object\" ? data : {}) as Record<string, unknown>;\n return {\n lastCheck: typeof record.lastCheck === \"number\" ? record.lastCheck : 0,\n latestVersion: typeof record.latestVersion === \"string\" ? record.latestVersion : null,\n etag: typeof record.etag === \"string\" ? record.etag : null,\n };\n } catch {\n return { lastCheck: 0, latestVersion: null, etag: null };\n }\n}\n\nexport interface ReleaseAsset {\n name: string;\n url: string;\n}\n\nexport interface LatestRelease {\n version: string;\n tag: string;\n assets: Array<ReleaseAsset>;\n}\n\n/** Parse the GitHub `releases/latest` response into the fields we need. */\nexport function parseLatestRelease(json: unknown): LatestRelease | null {\n if (!json || typeof json !== \"object\") {\n return null;\n }\n const record = json as Record<string, unknown>;\n const tag = typeof record.tag_name === \"string\" ? record.tag_name : undefined;\n if (!tag) {\n return null;\n }\n const assets: Array<ReleaseAsset> = [];\n if (Array.isArray(record.assets)) {\n for (const item of record.assets) {\n if (item && typeof item === \"object\") {\n const asset = item as Record<string, unknown>;\n if (typeof asset.name === \"string\" && typeof asset.browser_download_url === \"string\") {\n assets.push({ name: asset.name, url: asset.browser_download_url });\n }\n }\n }\n }\n return { version: versionFromTag(tag), tag, assets };\n}\n\n/** Find a checksum line for `fileName` in a `sha256sum`-style SHA256SUMS file. */\nexport function checksumFor(sumsText: string, fileName: string): string | undefined {\n for (const line of sumsText.split(/\\r?\\n/)) {\n const match = line.trim().match(/^([0-9a-fA-F]{64})\\s+\\*?(.+)$/);\n if (match?.[1] && match[2]?.trim() === fileName) {\n return match[1].toLowerCase();\n }\n }\n return undefined;\n}\n\n/**\n * Resolve the per-OS cache directory (no deps). Mirrors env-paths conventions:\n * Windows -> %LOCALAPPDATA%, macOS -> ~/Library/Caches, else $XDG_CACHE_HOME||~/.cache.\n */\nexport function resolveCacheDir(\n env: Record<string, string | undefined>,\n platform: string,\n homedir: string,\n join: (...parts: string[]) => string,\n): string {\n if (platform === \"win32\") {\n const base = env.LOCALAPPDATA || join(homedir, \"AppData\", \"Local\");\n return join(base, \"hoopilot\");\n }\n if (platform === \"darwin\") {\n return join(homedir, \"Library\", \"Caches\", \"hoopilot\");\n }\n const base = env.XDG_CACHE_HOME || join(homedir, \".cache\");\n return join(base, \"hoopilot\");\n}\n\n/** Stable redirect URL that downloads an asset from the latest release. */\nexport function latestDownloadUrl(asset: string): string {\n return `https://github.com/${REPO}/releases/latest/download/${asset}`;\n}\n\n/** GitHub REST endpoint for the latest release. */\nexport function latestReleaseApiUrl(): string {\n return `https://api.github.com/repos/${REPO}/releases/latest`;\n}\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["readFileSync","optionValue","encodeSse","outputText","parseJsonObject","createHash","chmodSync","mkdirSync","renameSync","rmSync","writeFileSync","dirname","join","homedir","join","base","REQUEST_TIMEOUT_MS","join","mkdirSync","createHash","rmSync","renameSync","chmodSync","writeFileSync","dirname","main","args","logger","readFileSync"]}
|