@openhoo/hoopilot 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/auth-store.ts","../src/util.ts","../src/auth.ts","../src/copilot.ts","../src/github-device.ts","../src/logger.ts","../src/openai.ts","../src/metrics.ts","../src/server.ts","../src/update.ts","../src/update-core.ts","../src/version.ts"],"sourcesContent":["#!/usr/bin/env bun\n\nimport { spawn } from \"node:child_process\";\nimport { CopilotAuthError, DEFAULT_COPILOT_API_BASE_URL } from \"./auth\";\nimport { authStorePath, writeStoredCopilotAuth } from \"./auth-store\";\nimport { applyCopilotHeaders, CopilotClient, normalizeCopilotUsage } from \"./copilot\";\nimport { githubCopilotDeviceLogin } 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 HoopilotLogger,\n HoopilotServerOptions,\n} from \"./types\";\nimport { cleanupOldBinary, maybeNotifyUpdate, runUpdate } from \"./update\";\nimport { asRecord, trimTrailingSlash, truncatedResponseText } from \"./util\";\nimport { getVersion, IS_STANDALONE_BINARY } from \"./version\";\n\ninterface ParsedArgs extends HoopilotServerOptions {\n help?: boolean;\n noUpdateCheck?: boolean;\n version?: 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 (args.help) {\n console.log(helpText(await getVersion()));\n return;\n }\n const logger = commandLogger(args, command);\n await runUpdate(await getVersion(), logger);\n return;\n }\n if (command === \"login\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (args.help) {\n console.log(helpText(await getVersion()));\n return;\n }\n args.logger = commandLogger(args, \"login\");\n await runLogin(args);\n return;\n }\n if (command === \"models\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (args.help) {\n console.log(helpText(await getVersion()));\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 (args.help) {\n console.log(helpText(await getVersion()));\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 (args.help) {\n console.log(helpText(await getVersion()));\n return;\n }\n if (args.version) {\n console.log(await getVersion());\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\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\n const [name, inlineValue] = arg.split(\"=\", 2);\n const value = inlineValue ?? rest.shift();\n if (!value) {\n throw new Error(`Missing value for ${arg}.`);\n }\n\n switch (name) {\n case \"--api-key\":\n args.apiKey = value;\n break;\n case \"--auth-file\":\n args.authStorePath = value;\n break;\n case \"--copilot-api-base-url\":\n args.copilotApiBaseUrl = value;\n break;\n case \"--log-format\":\n args.logFormat = parseLogFormat(value);\n break;\n case \"--log-level\":\n args.logLevel = parseLogLevel(value);\n break;\n case \"--host\":\n args.host = value;\n break;\n case \"--port\":\n case \"-p\":\n args.port = Number(value);\n if (!Number.isInteger(args.port) || args.port <= 0) {\n throw new Error(`Invalid port: ${value}.`);\n }\n break;\n default:\n throw new Error(`Unknown option: ${name}.`);\n }\n }\n\n return args;\n}\n\nasync function runLogin(options: HoopilotServerOptions = {}): Promise<void> {\n const logger = options.logger?.child({ component: \"auth\" }) ?? noopLogger;\n logger.debug({ event: \"auth.login.started\" }, \"starting github copilot browser login\");\n console.log(\"Starting GitHub Copilot browser login...\");\n const login = await githubCopilotDeviceLogin({\n env: options.env,\n logger: console,\n openBrowser: openBrowserBestEffort,\n });\n\n console.log(\"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 console.log(`Copilot OAuth credential stored at ${path}`);\n console.log(\"Copilot authentication ready.\");\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 const message = `GitHub Copilot API model list failed with ${\n response.status\n }: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\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 const message = `GitHub Copilot usage request failed with ${\n response.status\n }: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\n }\n\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 return usage;\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 ?? options.env?.COPILOT_API_BASE_URL ?? DEFAULT_COPILOT_API_BASE_URL,\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 const message = `GitHub Copilot API verification failed with ${\n response.status\n }: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\n }\n\n return {\n apiBaseUrl,\n expiresAtMs: Date.now() + 10 * 60_000,\n source: \"github-copilot-oauth\",\n token,\n };\n}\n\nfunction openBrowserBestEffort(url: string): 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 = spawn(command, args, {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n } catch {\n // The device login code and URL were already printed.\n }\n}\n\nfunction modelIdsFromResponse(body: unknown): string[] {\n const record = asRecord(body);\n const data = Array.isArray(record.data) ? record.data : Array.isArray(body) ? body : [];\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const model of data) {\n const id = asRecord(model).id;\n if (typeof id !== \"string\" || id.length === 0 || seen.has(id)) {\n continue;\n }\n seen.add(id);\n ids.push(id);\n }\n return ids;\n}\n\nfunction withRuntimeEnv(args: ParsedArgs): ParsedArgs {\n return { ...args, env: process.env };\n}\n\nfunction commandLogger(args: ParsedArgs, command: string): HoopilotLogger {\n return createHoopilotLogger({\n env: args.env,\n format: args.logFormat,\n level: args.logLevel,\n }).child({ command, component: \"cli\" });\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 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 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.\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 --auth-file <path> OAuth credential store path\n --copilot-api-base-url <url> Copilot API base URL override\n --log-level <level> trace, debug, info, warn, error, fatal, or silent\n --log-format <format> json or pretty. Default: pretty\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 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_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(error instanceof Error ? error.message : String(error));\n process.exit(1);\n });\n}\n","import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\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 if (env.HOOPILOT_AUTH_FILE) {\n return env.HOOPILOT_AUTH_FILE;\n }\n\n const base =\n env.XDG_CONFIG_HOME ??\n env.APPDATA ??\n (env.HOME ? join(env.HOME, \".config\") : join(process.cwd(), \".config\"));\n return join(base, \"hoopilot\", \"auth.json\");\n}\n\nexport function readStoredCopilotAuth(path = authStorePath()): StoredCopilotAuth | undefined {\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\"));\n if (!parsed || typeof parsed !== \"object\") {\n return undefined;\n }\n const token = typeof parsed.token === \"string\" ? parsed.token.trim() : \"\";\n if (!token) {\n return undefined;\n }\n return {\n apiBaseUrl: typeof parsed.apiBaseUrl === \"string\" ? parsed.apiBaseUrl : undefined,\n createdAt: typeof parsed.createdAt === \"string\" ? parsed.createdAt : undefined,\n githubDomain: typeof parsed.githubDomain === \"string\" ? parsed.githubDomain : undefined,\n source: typeof parsed.source === \"string\" ? parsed.source : undefined,\n token,\n };\n } catch {\n return undefined;\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 renameSync(tmpPath, path);\n try {\n chmodSync(path, 0o600);\n } catch {\n // chmod is best-effort on Windows.\n }\n}\n","import type { JsonObject } from \"./types\";\n\n/** Remove any trailing slashes from a URL or path string. */\nexport function trimTrailingSlash(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\n/** Read a response body as text, truncated to keep error messages bounded. */\nexport async function truncatedResponseText(response: Response, max = 500): Promise<string> {\n const text = await response.text();\n return text.slice(0, max);\n}\n\n/** Narrow an unknown value to a plain object, returning {} for arrays/primitives/null. */\nexport function asRecord(value: unknown): JsonObject {\n return value && typeof value === \"object\" && !Array.isArray(value) ? (value as JsonObject) : {};\n}\n","import { readStoredCopilotAuth } from \"./auth-store\";\nimport type { CopilotAccess, CopilotAuthOptions } from \"./types\";\nimport { trimTrailingSlash } from \"./util\";\n\nexport const DEFAULT_COPILOT_API_BASE_URL = \"https://api.githubcopilot.com\";\nconst REFRESH_SKEW_MS = 60_000;\nconst 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 #cachedAccess?: CopilotAccess;\n\n constructor(options: CopilotAuthOptions = {}) {\n this.#authStorePath = options.authStorePath ?? options.env?.HOOPILOT_AUTH_FILE;\n this.#copilotApiBaseUrl = trimTrailingSlash(\n options.copilotApiBaseUrl ??\n options.env?.COPILOT_API_BASE_URL ??\n 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 const stored = readStoredCopilotAuth(this.#authStorePath);\n if (stored) {\n return this.#cacheAccess({\n apiBaseUrl: trimTrailingSlash(stored.apiBaseUrl ?? this.#copilotApiBaseUrl),\n expiresAtMs: Date.now() + STORED_TOKEN_TTL_MS,\n source: \"github-copilot-oauth\",\n token: stored.token,\n });\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 #cacheAccess(access: CopilotAccess): CopilotAccess {\n this.#cachedAccess = access;\n return access;\n }\n}\n","import { CopilotAuth } from \"./auth\";\nimport type {\n CopilotAuthOptions,\n CopilotQuota,\n CopilotUsage,\n FetchLike,\n JsonObject,\n} from \"./types\";\nimport { asRecord, trimTrailingSlash } 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\";\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/**\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\", \"hoopilot/0.1.0\");\n headers.set(\"editor-version\", \"Hoopilot/0.1.0\");\n headers.set(\"openai-intent\", \"conversation-panel\");\n headers.set(\"user-agent\", \"hoopilot/0.1.0\");\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\", \"hoopilot/0.1.0\");\n headers.set(\"editor-version\", \"Hoopilot/0.1.0\");\n headers.set(\"user-agent\", \"hoopilot/0.1.0\");\n headers.set(\"x-github-api-version\", COPILOT_USAGE_API_VERSION);\n return headers;\n}\n\nexport class CopilotClient {\n readonly #auth: CopilotAuth;\n readonly #fetch: FetchLike;\n readonly #githubApiBaseUrl: string;\n\n constructor(options: CopilotAuthOptions = {}) {\n this.#auth = new CopilotAuth(options);\n this.#fetch = options.fetch ?? fetch;\n this.#githubApiBaseUrl = trimTrailingSlash(\n options.githubApiBaseUrl ??\n options.env?.HOOPILOT_GITHUB_API_BASE_URL ??\n DEFAULT_GITHUB_API_BASE_URL,\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 (!isHttpsOrLoopback(this.#githubApiBaseUrl)) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to a non-HTTPS host: ${this.#githubApiBaseUrl}`,\n );\n }\n const access = await this.#auth.getAccess();\n const headers = applyGithubApiHeaders(new Headers(), access.token);\n return this.#fetch(`${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 const headers = applyCopilotHeaders(new Headers(init.headers), access.token);\n\n return this.#fetch(`${access.apiBaseUrl}${path}`, {\n ...init,\n headers,\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] = removeUndefinedQuota({\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 removeUndefinedUsage({\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 remaining =\n numberOrUndefined(detail.remaining) ?? numberOrUndefined(detail.quota_remaining);\n return removeUndefinedQuota({\n entitlement,\n overageCount: numberOrUndefined(detail.overage_count),\n overagePermitted:\n typeof detail.overage_permitted === \"boolean\" ? detail.overage_permitted : undefined,\n percentRemaining: numberOrUndefined(detail.percent_remaining),\n remaining,\n unlimited: typeof detail.unlimited === \"boolean\" ? detail.unlimited : undefined,\n used: usedFrom(entitlement, remaining),\n });\n}\n\nfunction usedFrom(\n entitlement: number | undefined,\n remaining: number | undefined,\n): number | undefined {\n if (entitlement === undefined || remaining === undefined) {\n return undefined;\n }\n return Math.max(0, entitlement - remaining);\n}\n\n/** True for https URLs, or http only on loopback hosts (used by tests). */\nfunction isHttpsOrLoopback(rawUrl: string): boolean {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n return false;\n }\n if (url.protocol === \"https:\") {\n return true;\n }\n return (\n url.protocol === \"http:\" &&\n (url.hostname === \"127.0.0.1\" || url.hostname === \"localhost\" || url.hostname === \"::1\")\n );\n}\n\nfunction numberOrUndefined(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction stringOrUndefined(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction removeUndefinedQuota(quota: CopilotQuota): CopilotQuota {\n return Object.fromEntries(\n Object.entries(quota).filter(([, value]) => value !== undefined),\n ) as CopilotQuota;\n}\n\nfunction removeUndefinedUsage(usage: CopilotUsage): CopilotUsage {\n const entries = Object.entries(usage).filter(([, value]) => value !== undefined);\n return Object.fromEntries(entries) as unknown as CopilotUsage;\n}\n","import { setTimeout as sleep } from \"node:timers/promises\";\nimport type { FetchLike, Logger } from \"./types\";\nimport { 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 ?? env.HOOPILOT_GITHUB_DOMAIN ?? DEFAULT_GITHUB_DOMAIN,\n );\n const clientId =\n options.clientId ??\n env.HOOPILOT_GITHUB_CLIENT_ID ??\n 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 return value.replace(/^https?:\\/\\//, \"\").replace(/\\/+$/, \"\");\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 try {\n return JSON.parse(text) as T;\n } catch {\n throw new Error(`${context}: ${text.slice(0, 500)}`);\n }\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\";\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 ?? env.HOOPILOT_LOG_LEVEL);\n const format = parseLogFormat(options.format ?? 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 pino(\n pinoOptions,\n pretty({\n colorize: options.colorize ?? process.stderr.isTTY,\n destination: options.stream ?? 1,\n ignore: \"pid,hostname\",\n singleLine: true,\n translateTime: \"SYS:standard\",\n }),\n ) as HoopilotLogger;\n }\n\n if (options.stream) {\n return pino(pinoOptions, options.stream as pino.DestinationStream) as HoopilotLogger;\n }\n return pino(pinoOptions) as HoopilotLogger;\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 options.env?.HOOPILOT_LOG_FORMAT ||\n 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 type { JsonObject, TokenUsage } from \"./types\";\nimport { asRecord } from \"./util\";\n\nexport const DEFAULT_MODEL = \"gpt-4.1\";\n\ninterface ResponseStreamOptions {\n model: string;\n responseId?: string;\n}\n\ninterface AccumulatedToolCall {\n arguments: string;\n id: string;\n index: number;\n name: string;\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 return removeUndefined({\n max_tokens: request.max_tokens,\n messages: [{ content: promptToText(request.prompt), role: \"user\" }],\n model: normalizeRequestedModel(request.model),\n stream: request.stream === true,\n temperature: request.temperature,\n top_p: request.top_p,\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\nexport function chatCompletionToCompletion(completion: JsonObject): JsonObject {\n const choice = firstChoice(completion);\n const message = asRecord(choice.message);\n return removeUndefined({\n choices: [\n {\n finish_reason: choice.finish_reason ?? \"stop\",\n index: 0,\n logprobs: null,\n 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 usage: completion.usage,\n });\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 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(encoder.encode(encodeSse(event, data)));\n };\n\n enqueue(\"response.created\", {\n response: baseStreamResponse(responseId, options.model, createdAt, \"in_progress\", []),\n type: \"response.created\",\n });\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: 0,\n type: \"response.output_item.added\",\n });\n enqueue(\"response.content_part.added\", {\n content_index: 0,\n item_id: messageId,\n output_index: 0,\n part: {\n annotations: [],\n text: \"\",\n type: \"output_text\",\n },\n type: \"response.content_part.added\",\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(messageId, line, enqueue, tools, (delta) => {\n text += delta;\n });\n }\n }\n if (buffer) {\n processChatSseLine(messageId, buffer, enqueue, tools, (delta) => {\n text += delta;\n });\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 toolItems = [...tools.values()].map(functionCallItem);\n const output = [messageOutputItem(text, messageId), ...toolItems];\n enqueue(\"response.output_text.done\", {\n content_index: 0,\n item_id: messageId,\n output_index: 0,\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: 0,\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: output[0],\n output_index: 0,\n type: \"response.output_item.done\",\n });\n\n toolItems.forEach((item, index) => {\n const outputIndex = index + 1;\n enqueue(\"response.output_item.added\", {\n item,\n output_index: outputIndex,\n type: \"response.output_item.added\",\n });\n enqueue(\"response.function_call_arguments.done\", {\n arguments: item.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 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): unknown[] {\n if (typeof input === \"string\") {\n return [{ content: input, role: \"user\" }];\n }\n if (!Array.isArray(input)) {\n return [];\n }\n\n const messages: unknown[] = [];\n for (const item of input) {\n const record = asRecord(item);\n if (record.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 (record.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 const role = roleToChatRole(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 return contentToText(content) || undefined;\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 }\n if (type === \"input_image\") {\n const imageUrl = contentToText(record.image_url);\n if (imageUrl) {\n parts.push({ image_url: { url: imageUrl }, type: \"image_url\" });\n }\n }\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 promptToText(prompt: unknown): string {\n if (Array.isArray(prompt)) {\n return prompt.map((item) => contentToText(item)).join(\"\\n\");\n }\n return contentToText(prompt);\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 roleToChatRole(role: string): string | undefined {\n if (role === \"assistant\" || role === \"developer\" || role === \"system\" || role === \"tool\") {\n return role === \"developer\" ? \"system\" : role;\n }\n return \"user\";\n}\n\nfunction chatTools(tools: unknown): unknown[] | undefined {\n if (!Array.isArray(tools)) {\n return undefined;\n }\n const converted = tools\n .map((tool) => asRecord(tool))\n .filter((tool) => tool.type === \"function\")\n .map((tool) => ({\n function: removeUndefined({\n description: tool.description,\n name: tool.name,\n parameters: tool.parameters,\n strict: tool.strict,\n }),\n type: \"function\",\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 if (record.type === \"function\" && typeof record.name === \"string\") {\n return { function: { name: record.name }, type: \"function\" };\n }\n return toolChoice;\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 index: output.length,\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 functionCallItem(tool: AccumulatedToolCall): JsonObject {\n return {\n arguments: tool.arguments,\n call_id: tool.id,\n id: `fc_${randomId()}`,\n name: tool.name,\n status: \"completed\",\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 return removeUndefined({\n input_tokens: record.prompt_tokens,\n input_tokens_details: record.prompt_tokens_details,\n output_tokens: record.completion_tokens,\n output_tokens_details: record.completion_tokens_details,\n total_tokens: record.total_tokens,\n });\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 asRecord(record.prompt_tokens_details).cached_tokens,\n asRecord(record.input_tokens_details).cached_tokens,\n );\n return removeUndefined({\n cachedTokens: cached,\n completionTokens,\n promptTokens,\n reasoningTokens: reasoning,\n totalTokens: total ?? promptTokens + completionTokens,\n }) as unknown as TokenUsage;\n}\n\nfunction firstNumber(...values: unknown[]): number | undefined {\n for (const value of values) {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n }\n return undefined;\n}\n\nfunction firstChoice(completion: JsonObject): Record<string, unknown> {\n const choices = Array.isArray(completion.choices) ? completion.choices : [];\n return asRecord(choices[0]);\n}\n\nfunction processChatSseLine(\n messageId: string,\n line: string,\n enqueue: (event: string, data: JsonObject | \"[DONE]\") => void,\n tools: Map<number, AccumulatedToolCall>,\n appendText: (delta: string) => void,\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 = parseJson(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 appendText(content);\n enqueue(\"response.output_text.delta\", {\n content_index: 0,\n delta: content,\n item_id: messageId,\n output_index: 0,\n type: \"response.output_text.delta\",\n });\n }\n\n const toolCalls = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];\n for (const toolCall of toolCalls) {\n const record = asRecord(toolCall);\n const fn = asRecord(record.function);\n const index = typeof record.index === \"number\" ? record.index : tools.size;\n const existing = tools.get(index) ?? {\n arguments: \"\",\n id: contentToText(record.id) || `call_${randomId()}`,\n index,\n name: \"\",\n };\n existing.id = contentToText(record.id) || existing.id;\n existing.name += contentToText(fn.name);\n existing.arguments += contentToText(fn.arguments);\n tools.set(index, existing);\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 parseJson(data: string): JsonObject | undefined {\n try {\n return asRecord(JSON.parse(data));\n } catch {\n return undefined;\n }\n}\n\nfunction removeUndefined(record: JsonObject): JsonObject {\n return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));\n}\n\nfunction randomId(): string {\n return crypto.randomUUID().replaceAll(\"-\", \"\");\n}\n\nfunction epochSeconds(): number {\n return Math.floor(Date.now() / 1000);\n}\n","import { extractTokenUsage } from \"./openai\";\nimport type {\n CopilotUsage,\n MetricsSnapshot,\n ModelTokenTotals,\n RequestObservation,\n TokenUsage,\n} from \"./types\";\nimport { asRecord } 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// 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\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 /** 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 // Sanitize the model into a bounded, control-char-free label. The model can\n // originate from a client request, so cap its length, strip characters that\n // would corrupt the exposition format, and fold overflow past the cardinality\n // limit into UNKNOWN_MODEL to keep the series count bounded.\n #modelLabel(model: string): string {\n const cleaned =\n model\n // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control chars is the intent.\n .replace(/[\\u0000-\\u001f\\u007f]/g, \"\")\n .trim()\n .slice(0, MAX_MODEL_LABEL_LENGTH) || UNKNOWN_MODEL;\n if (!this.#tokens.has(cleaned) && this.#tokens.size >= MAX_TRACKED_MODELS) {\n return UNKNOWN_MODEL;\n }\n return cleaned;\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 return {\n inFlight: this.#inFlight,\n requests: { byRoute, byStatus, total: requestsTotal },\n startedAt: new Date(this.#startedAtMs).toISOString(),\n tokens: { byModel, ...tokenTotals },\n upstream: { errors: upstreamErrors, total: upstreamTotal },\n uptimeSeconds: Math.max(0, Math.round((now() - this.#startedAtMs) / 1000)),\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(\"# 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.#renderCopilotQuota(lines);\n\n return `${lines.join(\"\\n\")}\\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: (typeof categories)[number][1]) => 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(\n \"percent_remaining\",\n \"Percent of quota remaining for the Copilot category.\",\n (q) => q.percentRemaining,\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}\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): 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).catch(() => {});\n return new Response(clientBranch, {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\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): 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 let model = fallbackModel;\n let usage: TokenUsage | undefined;\n let buffer = \"\";\n let bufferedBytes = 0;\n let overflowed = false;\n\n const consider = (payload: unknown): void => {\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\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, 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, consider);\n }\n } else if (!overflowed && finalBuffer) {\n const parsed = safeParse(finalBuffer);\n if (parsed !== undefined) {\n consider(parsed);\n }\n }\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n reader.releaseLock();\n }\n\n if (usage) {\n onUsage(model, usage);\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 = safeParse(data);\n if (parsed !== undefined) {\n consider(parsed);\n }\n}\n\nfunction safeParse(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\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 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 { CopilotAuthError } from \"./auth\";\nimport { CopilotClient, normalizeCopilotUsage } from \"./copilot\";\nimport { createHoopilotLogger, errorDetails, noopLogger, shouldCreateLogger } from \"./logger\";\nimport { MetricsRegistry, observeResponseUsage, PROMETHEUS_CONTENT_TYPE } from \"./metrics\";\nimport {\n chatCompletionToCompletion,\n completionsRequestToChatCompletion,\n extractTokenUsage,\n fallbackModels,\n normalizeChatCompletionRequest,\n normalizeModelsResponse,\n normalizeRequestedModel,\n} from \"./openai\";\nimport type {\n CopilotUsage,\n HoopilotLogger,\n HoopilotServerOptions,\n JsonObject,\n LogFields,\n StartedHoopilotServer,\n TokenUsage,\n} from \"./types\";\nimport { asRecord } from \"./util\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 4141;\nconst INVALID_JSON_MESSAGE = \"Request body must be valid JSON.\";\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;\n\nexport function createHoopilotHandler(\n options: HoopilotServerOptions = {},\n): (request: Request) => Promise<Response> {\n const client = new CopilotClient(options);\n const apiKey = options.apiKey ?? options.env?.HOOPILOT_API_KEY;\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\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 finish = (response: Response): Response =>\n finishResponse(response, {\n logger: requestLogger,\n method: request.method,\n metrics,\n requestId,\n route,\n startedAt,\n });\n\n if (request.method === \"OPTIONS\") {\n return finish(new Response(null, { headers: corsHeaders() }));\n }\n\n if (!isAuthorized(request, apiKey)) {\n requestLogger.warn({ event: \"http.request.unauthorized\" }, \"invalid hoopilot api key\");\n return finish(jsonError(401, \"invalid_api_key\", \"Invalid or missing Hoopilot API key.\"));\n }\n\n try {\n if (request.method === \"GET\" && (apiPath === \"/\" || apiPath === \"/healthz\")) {\n return finish(jsonResponse({ name: \"hoopilot\", object: \"health\", status: \"ok\" }));\n }\n if (request.method === \"GET\" && apiPath === \"/metrics\") {\n return finish(metricsResponse(metrics));\n }\n if (request.method === \"GET\" && apiPath === \"/v1/usage\") {\n return finish(await handleUsage(metrics, readUsage, request.signal));\n }\n if (request.method === \"GET\" && apiPath === \"/v1/responses\") {\n return finish(websocketUnsupportedResponse());\n }\n if (request.method === \"GET\" && apiPath === \"/v1/models\") {\n return finish(await handleModels(client, metrics, request.signal, requestLogger));\n }\n if (request.method === \"POST\" && apiPath === \"/v1/chat/completions\") {\n return finish(\n await handleChatCompletions(client, metrics, recordTokens, request, requestLogger),\n );\n }\n if (request.method === \"POST\" && apiPath === \"/v1/completions\") {\n return finish(\n await handleCompletions(client, metrics, recordTokens, request, requestLogger),\n );\n }\n if (request.method === \"POST\" && apiPath === \"/v1/responses\") {\n return finish(await handleResponses(client, metrics, recordTokens, request, requestLogger));\n }\n return finish(jsonError(404, \"not_found\", `No route for ${request.method} ${url.pathname}.`));\n } catch (error) {\n if (error instanceof CopilotAuthError) {\n requestLogger.warn(\n { err: errorDetails(error), event: \"copilot.auth.missing\" },\n \"copilot auth failed\",\n );\n return finish(jsonError(401, \"copilot_auth_error\", error.message));\n }\n const message = errorMessage(error);\n if (message === INVALID_JSON_MESSAGE) {\n requestLogger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body was invalid json\",\n );\n return finish(jsonError(400, \"invalid_request_error\", message));\n } else {\n requestLogger.error(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request failed\",\n );\n }\n return finish(jsonError(500, \"internal_error\", message));\n }\n };\n}\n\nexport function startHoopilotServer(options: HoopilotServerOptions = {}): StartedHoopilotServer {\n const host = options.host ?? options.env?.HOST ?? DEFAULT_HOST;\n const port = Number(options.port ?? options.env?.PORT ?? DEFAULT_PORT);\n const apiKey = options.apiKey ?? options.env?.HOOPILOT_API_KEY;\n const allowUnauthenticated =\n options.allowUnauthenticated ?? options.env?.HOOPILOT_ALLOW_UNAUTHENTICATED === \"1\";\n\n if (!isLoopbackHost(host) && !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\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://${host}:${server.port}`,\n };\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 request: Request,\n logger: HoopilotLogger,\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(observeResponseUsage(upstream, model, recordTokens, request.signal));\n}\n\nasync function handleCompletions(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n request: Request,\n logger: HoopilotLogger,\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 an SSE body; calling .json() on it would throw a\n // 500. Pass the stream straight through and only convert non-streaming bodies.\n if (isStreamingResponse(upstream)) {\n return proxyResponse(observeResponseUsage(upstream, model, recordTokens, request.signal));\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 return jsonResponse(chatCompletionToCompletion(completion));\n}\n\nasync function handleResponses(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n request: Request,\n logger: HoopilotLogger,\n): Promise<Response> {\n const body = await readJsonText(request);\n const upstream = await client.responses(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 model = normalizeRequestedModel(asRecord(safeParseJson(body)).model);\n return proxyResponse(observeResponseUsage(upstream, model, recordTokens, request.signal));\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 jsonError(upstream.status, \"copilot_error\", 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 try {\n return asRecord(await request.json());\n } catch {\n throw new Error(INVALID_JSON_MESSAGE);\n }\n}\n\nasync function readJsonText(request: Request): Promise<string> {\n const text = await request.text();\n try {\n JSON.parse(text);\n return text;\n } catch {\n throw new Error(INVALID_JSON_MESSAGE);\n }\n}\n\nfunction jsonResponse(body: JsonObject, 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 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 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\nfunction corsHeaders(): Record<string, string> {\n return {\n \"access-control-allow-headers\": \"authorization, content-type, x-api-key\",\n \"access-control-allow-methods\": \"GET, POST, OPTIONS\",\n \"access-control-allow-origin\": \"*\",\n };\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 bearer === apiKey || request.headers.get(\"x-api-key\") === apiKey;\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 host === \"localhost\" || host === \"127.0.0.1\" || host === \"::1\";\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\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 finishResponse(\n response: Response,\n options: {\n logger: HoopilotLogger;\n method: string;\n metrics: MetricsRegistry;\n requestId: string;\n route: string;\n startedAt: number;\n },\n): Response {\n const withRequestId = responseWithRequestId(response, options.requestId);\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) {\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(response: Response, requestId: string): Response {\n const headers = new Headers(response.headers);\n headers.set(\"x-request-id\", requestId);\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 const fire = (): void => {\n if (!fired) {\n fired = true;\n onComplete();\n }\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 fire();\n return;\n }\n controller.enqueue(value);\n } catch (error) {\n fire();\n controller.error(error);\n }\n },\n cancel(reason) {\n fire();\n return reader.cancel(reason);\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 || 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 \"/responses\":\n return \"/v1/responses\";\n case \"/usage\":\n return \"/v1/usage\";\n default:\n return withoutTrailingSlash;\n }\n}\n\nfunction routeFor(method: string, path: string): string {\n if (method === \"OPTIONS\") {\n return \"cors.preflight\";\n }\n if (method === \"GET\" && (path === \"/\" || path === \"/healthz\")) {\n return \"health\";\n }\n if (method === \"GET\" && path === \"/metrics\") {\n return \"metrics\";\n }\n if (method === \"GET\" && path === \"/v1/usage\") {\n return \"usage\";\n }\n if (method === \"GET\" && path === \"/v1/models\") {\n return \"models\";\n }\n if (method === \"POST\" && path === \"/v1/chat/completions\") {\n return \"chat_completions\";\n }\n if (method === \"POST\" && path === \"/v1/completions\") {\n return \"completions\";\n }\n if (method === \"POST\" && path === \"/v1/responses\") {\n return \"responses\";\n }\n if (method === \"GET\" && path === \"/v1/responses\") {\n return \"responses_websocket\";\n }\n return \"not_found\";\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\nasync function handleUsage(\n metrics: MetricsRegistry,\n readUsage: UsageReader,\n signal: AbortSignal,\n): Promise<Response> {\n const proxy = metrics.snapshot();\n const { copilot, error } = await readUsage(signal);\n const body: JsonObject = { copilot: copilot ?? null, object: \"usage\", proxy };\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 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 metrics.recordUpstream(usagePath, false);\n if (error instanceof CopilotAuthError) {\n return { error: error.message };\n }\n return { error: errorMessage(error) };\n }\n };\n}\n\nfunction safeParseJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\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} 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 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 { BAKED_TARGET, IS_STANDALONE_BINARY } from \"./version\";\n\nconst REQUEST_TIMEOUT_MS = 8_000;\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(REQUEST_TIMEOUT_MS * 10),\n });\n if (!response.ok || !response.body) {\n throw new Error(`Download failed (${response.status}) for ${url}`);\n }\n await writeFile(dest, new Uint8Array(await response.arrayBuffer()));\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(REQUEST_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\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 } 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\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/** 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 = JSON.parse(text) as Partial<UpdateState>;\n return {\n lastCheck: typeof data.lastCheck === \"number\" ? data.lastCheck : 0,\n latestVersion: typeof data.latestVersion === \"string\" ? data.latestVersion : null,\n etag: typeof data.etag === \"string\" ? data.etag : null,\n };\n } catch {\n return { lastCheck: 0, latestVersion: null, etag: null };\n }\n}\n\nexport interface LatestRelease {\n version: string;\n tag: string;\n assets: Array<{ name: string; url: string }>;\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<{ name: string; url: string }> = [];\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","// 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 = await Bun.file(new URL(\"../package.json\", import.meta.url)).json();\n resolved = typeof manifest.version === \"string\" ? manifest.version : \"0.0.0\";\n } catch {\n resolved = \"0.0.0\";\n }\n }\n cachedVersion = resolved;\n return resolved;\n}\n"],"mappings":";;;AAEA,SAAS,aAAa;;;ACFtB,SAAS,WAAW,WAAW,cAAc,YAAY,qBAAqB;AAC9E,SAAS,SAAS,YAAY;AAUvB,SAAS,cAAc,MAAyB,QAAQ,KAAa;AAC1E,MAAI,IAAI,oBAAoB;AAC1B,WAAO,IAAI;AAAA,EACb;AAEA,QAAM,OACJ,IAAI,mBACJ,IAAI,YACH,IAAI,OAAO,KAAK,IAAI,MAAM,SAAS,IAAI,KAAK,QAAQ,IAAI,GAAG,SAAS;AACvE,SAAO,KAAK,MAAM,YAAY,WAAW;AAC3C;AAEO,SAAS,sBAAsB,OAAO,cAAc,GAAkC;AAC3F,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AACpD,QAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,OAAO,OAAO,UAAU,WAAW,OAAO,MAAM,KAAK,IAAI;AACvE,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,YAAY,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;AAAA,MACxE,WAAW,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAAA,MACrE,cAAc,OAAO,OAAO,iBAAiB,WAAW,OAAO,eAAe;AAAA,MAC9E,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,uBAAuB,MAAyB,OAAO,cAAc,GAAS;AAC5F,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,QAAM,OAAO,GAAG,KAAK;AAAA,IACnB;AAAA,MACE,GAAG;AAAA,MACH,WAAW,KAAK,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACtD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA;AAGD,QAAM,UAAU,GAAG,IAAI,IAAI,QAAQ,GAAG;AACtC,gBAAc,SAAS,MAAM,EAAE,MAAM,IAAM,CAAC;AAC5C,aAAW,SAAS,IAAI;AACxB,MAAI;AACF,cAAU,MAAM,GAAK;AAAA,EACvB,QAAQ;AAAA,EAER;AACF;;;AC9DO,SAAS,kBAAkB,OAAuB;AACvD,SAAO,MAAM,QAAQ,QAAQ,EAAE;AACjC;AAGA,eAAsB,sBAAsB,UAAoB,MAAM,KAAsB;AAC1F,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,SAAO,KAAK,MAAM,GAAG,GAAG;AAC1B;AAGO,SAAS,SAAS,OAA4B;AACnD,SAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAAK,QAAuB,CAAC;AAChG;;;ACZO,IAAM,+BAA+B;AAC5C,IAAM,kBAAkB;AACxB,IAAM,sBAAsB,KAAK;AAE1B,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,cAAN,MAAkB;AAAA,EACd;AAAA,EACA;AAAA,EACT;AAAA,EAEA,YAAY,UAA8B,CAAC,GAAG;AAC5C,SAAK,iBAAiB,QAAQ,iBAAiB,QAAQ,KAAK;AAC5D,SAAK,qBAAqB;AAAA,MACxB,QAAQ,qBACN,QAAQ,KAAK,wBACb;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,MAAM,YAAoC;AACxC,QAAI,KAAK,iBAAiB,KAAK,cAAc,cAAc,kBAAkB,KAAK,IAAI,GAAG;AACvF,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,SAAS,sBAAsB,KAAK,cAAc;AACxD,QAAI,QAAQ;AACV,aAAO,KAAK,aAAa;AAAA,QACvB,YAAY,kBAAkB,OAAO,cAAc,KAAK,kBAAkB;AAAA,QAC1E,aAAa,KAAK,IAAI,IAAI;AAAA,QAC1B,QAAQ;AAAA,QACR,OAAO,OAAO;AAAA,MAChB,CAAC;AAAA,IACH;AAEA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa,QAAsC;AACjD,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AACF;;;AC1CO,IAAM,8BAA8B;AAOpC,IAAM,4BAA4B;AAQlC,SAAS,oBAAoB,SAAkB,OAAwB;AAC5E,UAAQ,IAAI,UAAU,QAAQ,IAAI,QAAQ,KAAK,kBAAkB;AACjE,UAAQ,IAAI,iBAAiB,UAAU,KAAK,EAAE;AAC9C,UAAQ,IAAI,0BAA0B,aAAa;AACnD,UAAQ,IAAI,yBAAyB,gBAAgB;AACrD,UAAQ,IAAI,kBAAkB,gBAAgB;AAC9C,UAAQ,IAAI,iBAAiB,oBAAoB;AACjD,UAAQ,IAAI,cAAc,gBAAgB;AAC1C,UAAQ,IAAI,wBAAwB,YAAY;AAChD,SAAO;AACT;AAQO,SAAS,sBAAsB,SAAkB,OAAwB;AAC9E,UAAQ,IAAI,UAAU,QAAQ,IAAI,QAAQ,KAAK,kBAAkB;AACjE,UAAQ,IAAI,iBAAiB,SAAS,KAAK,EAAE;AAC7C,UAAQ,IAAI,yBAAyB,gBAAgB;AACrD,UAAQ,IAAI,kBAAkB,gBAAgB;AAC9C,UAAQ,IAAI,cAAc,gBAAgB;AAC1C,UAAQ,IAAI,wBAAwB,yBAAyB;AAC7D,SAAO;AACT;AAEO,IAAM,gBAAN,MAAoB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,UAA8B,CAAC,GAAG;AAC5C,SAAK,QAAQ,IAAI,YAAY,OAAO;AACpC,SAAK,SAAS,QAAQ,SAAS;AAC/B,SAAK,oBAAoB;AAAA,MACvB,QAAQ,oBACN,QAAQ,KAAK,gCACb;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAM,QAAyC;AAInD,QAAI,CAAC,kBAAkB,KAAK,iBAAiB,GAAG;AAC9C,YAAM,IAAI;AAAA,QACR,gEAAgE,KAAK,iBAAiB;AAAA,MACxF;AAAA,IACF;AACA,UAAM,SAAS,MAAM,KAAK,MAAM,UAAU;AAC1C,UAAM,UAAU,sBAAsB,IAAI,QAAQ,GAAG,OAAO,KAAK;AACjE,WAAO,KAAK,OAAO,GAAG,KAAK,iBAAiB,0BAA0B;AAAA,MACpE;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,gBAAgB,MAAkB,QAAyC;AAC/E,WAAO,KAAK,aAAa,qBAAqB;AAAA,MAC5C,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,UAAU,MAAc,QAAyC;AACrE,WAAO,KAAK,aAAa,cAAc;AAAA,MACrC;AAAA,MACA,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,QAAyC;AACpD,WAAO,KAAK,aAAa,WAAW;AAAA,MAClC,SAAS;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,MAAc,MAAsC;AACrE,UAAM,SAAS,MAAM,KAAK,MAAM,UAAU;AAC1C,UAAM,UAAU,oBAAoB,IAAI,QAAQ,KAAK,OAAO,GAAG,OAAO,KAAK;AAE3E,WAAO,KAAK,OAAO,GAAG,OAAO,UAAU,GAAG,IAAI,IAAI;AAAA,MAChD,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;AASO,SAAS,sBAAsB,MAA6B;AACjE,QAAM,SAAS,SAAS,IAAI;AAC5B,QAAM,SAAuC,CAAC;AAE9C,QAAM,YAAY,SAAS,OAAO,eAAe;AACjD,aAAW,CAAC,UAAU,MAAM,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC1D,WAAO,QAAQ,IAAI,qBAAqB,SAAS,MAAM,CAAC;AAAA,EAC1D;AAEA,MAAI,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG;AACpC,UAAM,YAAY,SAAS,OAAO,mBAAmB;AACrD,UAAM,UAAU,SAAS,OAAO,cAAc;AAC9C,eAAW,YAAY,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,SAAS,GAAG,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,GAAG;AACpF,YAAM,cAAc,kBAAkB,QAAQ,QAAQ,CAAC;AACvD,YAAM,OAAO,kBAAkB,UAAU,QAAQ,CAAC;AAClD,aAAO,QAAQ,IAAI,qBAAqB;AAAA,QACtC;AAAA,QACA,kBACE,gBAAgB,UAAa,cAAc,KAAK,SAAS,SACpD,OAAO,cAAe,MACvB;AAAA,QACN,WAAW;AAAA,QACX,MAAM,SAAS,aAAa,IAAI;AAAA,MAClC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,qBAAqB;AAAA,IAC1B,eAAe,kBAAkB,OAAO,eAAe;AAAA,IACvD,aAAa,OAAO,OAAO,iBAAiB,YAAY,OAAO,eAAe;AAAA,IAC9E,MAAM,kBAAkB,OAAO,YAAY;AAAA,IAC3C,gBACE,kBAAkB,OAAO,gBAAgB,KACzC,kBAAkB,OAAO,oBAAoB,KAC7C,kBAAkB,OAAO,uBAAuB;AAAA,IAClD;AAAA,EACF,CAAC;AACH;AAEA,SAAS,qBAAqB,QAAkC;AAC9D,QAAM,cAAc,kBAAkB,OAAO,WAAW;AACxD,QAAM,YACJ,kBAAkB,OAAO,SAAS,KAAK,kBAAkB,OAAO,eAAe;AACjF,SAAO,qBAAqB;AAAA,IAC1B;AAAA,IACA,cAAc,kBAAkB,OAAO,aAAa;AAAA,IACpD,kBACE,OAAO,OAAO,sBAAsB,YAAY,OAAO,oBAAoB;AAAA,IAC7E,kBAAkB,kBAAkB,OAAO,iBAAiB;AAAA,IAC5D;AAAA,IACA,WAAW,OAAO,OAAO,cAAc,YAAY,OAAO,YAAY;AAAA,IACtE,MAAM,SAAS,aAAa,SAAS;AAAA,EACvC,CAAC;AACH;AAEA,SAAS,SACP,aACA,WACoB;AACpB,MAAI,gBAAgB,UAAa,cAAc,QAAW;AACxD,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,GAAG,cAAc,SAAS;AAC5C;AAGA,SAAS,kBAAkB,QAAyB;AAClD,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,MAAM;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,IAAI,aAAa,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,SACE,IAAI,aAAa,YAChB,IAAI,aAAa,eAAe,IAAI,aAAa,eAAe,IAAI,aAAa;AAEtF;AAEA,SAAS,kBAAkB,OAAoC;AAC7D,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAEA,SAAS,kBAAkB,OAAoC;AAC7D,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAEA,SAAS,qBAAqB,OAAmC;AAC/D,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AAAA,EACjE;AACF;AAEA,SAAS,qBAAqB,OAAmC;AAC/D,QAAM,UAAU,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AAC/E,SAAO,OAAO,YAAY,OAAO;AACnC;;;ACjPA,SAAS,cAAc,aAAa;AAI7B,IAAM,mCAAmC;AAChD,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAC1B,IAAM,2BAA2B;AACjC,IAAM,qBAAqB;AAgC3B,eAAsB,yBACpB,UAA2C,CAAC,GACH;AACzC,QAAM,MAAM,QAAQ,OAAO,QAAQ;AACnC,QAAM,UAAU,QAAQ,SAAS;AACjC,QAAM,UAAU,QAAQ,SAAS;AACjC,QAAM,SAAS;AAAA,IACb,QAAQ,UAAU,IAAI,0BAA0B;AAAA,EAClD;AACA,QAAM,WACJ,QAAQ,YACR,IAAI,6BACJ,IAAI,4BACJ;AAEF,QAAM,SAAS,MAAM,kBAAkB,SAAS,QAAQ,QAAQ;AAChE,QAAM,kBAAkB,OAAO;AAC/B,QAAM,WAAW,OAAO;AACxB,QAAM,aAAa,OAAO;AAC1B,MAAI,CAAC,mBAAmB,CAAC,YAAY,CAAC,YAAY;AAChD,UAAM,IAAI,MAAM,kEAAkE;AAAA,EACpF;AAEA,UAAQ,QAAQ,KAAK,kCAAkC,QAAQ,EAAE;AACjE,UAAQ,QAAQ,KAAK,QAAQ,eAAe,yCAAyC;AACrF,QAAM,QAAQ,cAAc,eAAe;AAE3C,SAAO;AAAA,IACL;AAAA,IACA,OAAO,MAAM,mBAAmB,SAAS,SAAS,QAAQ,UAAU;AAAA,MAClE;AAAA,MACA,WAAW,gBAAgB,OAAO,YAAY,GAAG;AAAA,MACjD,UAAU,gBAAgB,OAAO,UAAU,CAAC;AAAA,IAC9C,CAAC;AAAA,EACH;AACF;AAEA,eAAe,kBACb,SACA,QACA,UAC6B;AAC7B,QAAM,WAAW,MAAM,QAAQ,WAAW,MAAM,sBAAsB;AAAA,IACpE,MAAM,KAAK,UAAU;AAAA,MACnB,WAAW;AAAA,MACX,OAAO;AAAA,IACT,CAAC;AAAA,IACD,SAAS,aAAa;AAAA,IACtB,QAAQ;AAAA,IACR,QAAQ,YAAY,QAAQ,kBAAkB;AAAA,EAChD,CAAC;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,2CAA2C,SAAS,MAAM,KAAK,MAAM;AAAA,QACnE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,mBACb,SACA,SACA,QACA,UACA,QACiB;AACjB,MAAI,aAAa,OAAO,WAAW,MAAO;AAC1C,QAAM,WAAW,KAAK,IAAI,IAAI,OAAO,YAAY;AAEjD,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,UAAM,QAAQ,UAAU;AACxB,UAAM,WAAW,MAAM,QAAQ,WAAW,MAAM,6BAA6B;AAAA,MAC3E,MAAM,KAAK,UAAU;AAAA,QACnB,WAAW;AAAA,QACX,aAAa,OAAO;AAAA,QACpB,YAAY;AAAA,MACd,CAAC;AAAA,MACD,SAAS,aAAa;AAAA,MACtB,QAAQ;AAAA,MACR,QAAQ,YAAY,QAAQ,kBAAkB;AAAA,IAChD,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI;AAAA,QACR,4CAA4C,SAAS,MAAM,KAAK,MAAM;AAAA,UACpE;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA;AAAA,IACF;AACA,QAAI,KAAK,cAAc;AACrB,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,KAAK,UAAU,yBAAyB;AAC1C;AAAA,IACF;AACA,QAAI,KAAK,UAAU,aAAa;AAC9B,mBACE,gBAAgB,KAAK,UAAU,OAAO,WAAW,CAAC,IAAI,MAAO;AAC/D;AAAA,IACF;AACA,QAAI,KAAK,UAAU,iBAAiB;AAClC,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AACA,QAAI,KAAK,UAAU,iBAAiB;AAClC,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,QAAI,KAAK,OAAO;AACd,YAAM,IAAI,MAAM,KAAK,qBAAqB,+BAA+B,KAAK,KAAK,EAAE;AAAA,IACvF;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,4DAA4D;AAC9E;AAEA,SAAS,eAAwB;AAC/B,QAAM,UAAU,IAAI,QAAQ;AAC5B,UAAQ,IAAI,UAAU,kBAAkB;AACxC,UAAQ,IAAI,gBAAgB,kBAAkB;AAC9C,UAAQ,IAAI,cAAc,UAAU;AACpC,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,SAAO,MAAM,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,QAAQ,EAAE;AAC7D;AAEA,SAAS,gBAAgB,OAAgB,UAA0B;AACjE,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAQ;AACpF;AAEA,eAAe,kBAAqB,UAAoB,SAA6B;AACnF,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,UAAM,IAAI,MAAM,GAAG,OAAO,KAAK,KAAK,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,EACrD;AACF;;;AC5LA,OAAO,UAAU;AACjB,OAAO,YAAY;AASZ,IAAM,qBAAgC;AACtC,IAAM,oBAA8B;AAE3C,IAAM,cAAc,CAAC,QAAQ,QAAQ;AACrC,IAAM,aAAa,CAAC,SAAS,SAAS,QAAQ,QAAQ,SAAS,SAAS,QAAQ;AAChF,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,aAA6B;AAAA,EACxC,OAAO,MAAM;AAAA,EACb,OAAO,MAAM;AAAA,EAAC;AAAA,EACd,OAAO,MAAM;AAAA,EAAC;AAAA,EACd,OAAO,MAAM;AAAA,EAAC;AAAA,EACd,MAAM,MAAM;AAAA,EAAC;AAAA,EACb,OAAO,MAAM;AAAA,EAAC;AAAA,EACd,MAAM,MAAM;AAAA,EAAC;AACf;AAEO,SAAS,qBAAqB,UAAiC,CAAC,GAAmB;AACxF,QAAM,MAAM,QAAQ,OAAO,QAAQ;AACnC,QAAM,QAAQ,cAAc,QAAQ,SAAS,IAAI,kBAAkB;AACnE,QAAM,SAAS,eAAe,QAAQ,UAAU,IAAI,mBAAmB;AACvE,QAAM,cAAkC;AAAA,IACtC,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,GAAG,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,IACA,WAAW,KAAK,iBAAiB;AAAA,EACnC;AAEA,MAAI,WAAW,UAAU;AACvB,WAAO;AAAA,MACL;AAAA,MACA,OAAO;AAAA,QACL,UAAU,QAAQ,YAAY,QAAQ,OAAO;AAAA,QAC7C,aAAa,QAAQ,UAAU;AAAA,QAC/B,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,eAAe;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,QAAQ,QAAQ;AAClB,WAAO,KAAK,aAAa,QAAQ,MAAgC;AAAA,EACnE;AACA,SAAO,KAAK,WAAW;AACzB;AAEO,SAAS,eAAe,OAAsC;AACnE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,MAAI,YAAY,KAAK,GAAG;AACtB,WAAO;AAAA,EACT;AACA,QAAM,IAAI,MAAM,uBAAuB,KAAK,sBAAsB,YAAY,KAAK,IAAI,CAAC,GAAG;AAC7F;AAEO,SAAS,cAAc,OAAqC;AACjE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,MAAI,WAAW,KAAK,GAAG;AACrB,WAAO;AAAA,EACT;AACA,QAAM,IAAI,MAAM,sBAAsB,KAAK,sBAAsB,WAAW,KAAK,IAAI,CAAC,GAAG;AAC3F;AAEO,SAAS,mBAAmB,SAKvB;AACV,SAAO;AAAA,IACL,QAAQ,UACN,QAAQ,aACR,QAAQ,YACR,QAAQ,KAAK,uBACb,QAAQ,KAAK;AAAA,EACjB;AACF;AAGO,SAAS,aAAa,OAA2B;AACtD,MAAI,iBAAiB,OAAO;AAC1B,WAAO;AAAA,MACL,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,IACf;AAAA,EACF;AACA,SAAO,EAAE,SAAS,OAAO,KAAK,EAAE;AAClC;AAEA,SAAS,YAAY,OAAmC;AACtD,SAAQ,YAAkC,SAAS,KAAK;AAC1D;AAEA,SAAS,WAAW,OAAkC;AACpD,SAAQ,WAAiC,SAAS,KAAK;AACzD;;;ACtIO,IAAM,gBAAgB;AA2CtB,SAAS,+BAA+B,SAAiC;AAC9E,SAAO,gBAAgB;AAAA,IACrB,GAAG;AAAA,IACH,OAAO,wBAAwB,QAAQ,KAAK;AAAA,EAC9C,CAAC;AACH;AAEO,SAAS,mCAAmC,SAAiC;AAClF,SAAO,gBAAgB;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,UAAU,CAAC,EAAE,SAAS,aAAa,QAAQ,MAAM,GAAG,MAAM,OAAO,CAAC;AAAA,IAClE,OAAO,wBAAwB,QAAQ,KAAK;AAAA,IAC5C,QAAQ,QAAQ,WAAW;AAAA,IAC3B,aAAa,QAAQ;AAAA,IACrB,OAAO,QAAQ;AAAA,EACjB,CAAC;AACH;AAEO,SAAS,wBAAwB,OAAwB;AAC9D,QAAM,YAAY,cAAc,KAAK,EAAE,KAAK;AAC5C,SAAO,aAAa;AACtB;AAgCO,SAAS,2BAA2B,YAAoC;AAC7E,QAAM,SAAS,YAAY,UAAU;AACrC,QAAM,UAAU,SAAS,OAAO,OAAO;AACvC,SAAO,gBAAgB;AAAA,IACrB,SAAS;AAAA,MACP;AAAA,QACE,eAAe,OAAO,iBAAiB;AAAA,QACvC,OAAO;AAAA,QACP,UAAU;AAAA,QACV,MAAM,cAAc,QAAQ,OAAO;AAAA,MACrC;AAAA,IACF;AAAA,IACA,SAAS,WAAW,WAAW,aAAa;AAAA,IAC5C,IAAI,WAAW,MAAM,QAAQ,SAAS,CAAC;AAAA,IACvC,OAAO,WAAW,SAAS;AAAA,IAC3B,QAAQ;AAAA,IACR,OAAO,WAAW;AAAA,EACpB,CAAC;AACH;AAEO,SAAS,wBAAwB,UAA+B;AACrE,QAAM,SAAS,SAAS,QAAQ;AAChC,QAAM,OAAO,MAAM,QAAQ,OAAO,IAAI,IAAI,OAAO,OAAO,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC;AAC9F,QAAM,SAAS,KACZ,IAAI,CAAC,UAAU,SAAS,KAAK,CAAC,EAC9B,OAAO,CAAC,UAAU,OAAO,MAAM,OAAO,QAAQ,EAC9C,IAAI,CAAC,WAAW;AAAA,IACf,SAAS,MAAM,WAAW;AAAA,IAC1B,IAAI,MAAM;AAAA,IACV,QAAQ;AAAA,IACR,UAAU,MAAM,YAAY;AAAA,EAC9B,EAAE;AAEJ,SAAO;AAAA,IACL,MAAM,OAAO,SAAS,IAAI,SAAS,eAAe;AAAA,IAClD,QAAQ;AAAA,EACV;AACF;AAEO,SAAS,iBAAoC;AAClD,SAAO;AAAA,IACL;AAAA,MACE,SAAS;AAAA,MACT,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAmNA,SAAS,aAAa,QAAyB;AAC7C,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,IAAI,CAAC,SAAS,cAAc,IAAI,CAAC,EAAE,KAAK,IAAI;AAAA,EAC5D;AACA,SAAO,cAAc,MAAM;AAC7B;AAEA,SAAS,cAAc,SAA0B;AAC/C,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,YAAY,YAAY,OAAO,YAAY,WAAW;AAC/D,WAAO,OAAO,OAAO;AAAA,EACvB;AACA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,WAAO,QACJ,IAAI,CAAC,SAAS,cAAc,IAAI,CAAC,EACjC,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,EACd;AACA,MAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,UAAM,SAAS;AACf,QAAI,OAAO,OAAO,SAAS,UAAU;AACnC,aAAO,OAAO;AAAA,IAChB;AACA,QAAI,OAAO,OAAO,gBAAgB,UAAU;AAC1C,aAAO,OAAO;AAAA,IAChB;AACA,WAAO,KAAK,UAAU,OAAO;AAAA,EAC/B;AACA,SAAO;AACT;AAwHO,SAAS,kBAAkB,OAAwC;AACxE,QAAM,SAAS,SAAS,KAAK;AAC7B,QAAM,SAAS,YAAY,OAAO,eAAe,OAAO,YAAY;AACpE,QAAM,aAAa,YAAY,OAAO,mBAAmB,OAAO,aAAa;AAC7E,QAAM,QAAQ,YAAY,OAAO,YAAY;AAC7C,MAAI,WAAW,UAAa,eAAe,UAAa,UAAU,QAAW;AAC3E,WAAO;AAAA,EACT;AACA,QAAM,eAAe,UAAU;AAC/B,QAAM,mBAAmB,cAAc;AACvC,QAAM,YAAY;AAAA,IAChB,SAAS,OAAO,yBAAyB,EAAE;AAAA,IAC3C,SAAS,OAAO,qBAAqB,EAAE;AAAA,EACzC;AACA,QAAM,SAAS;AAAA,IACb,SAAS,OAAO,qBAAqB,EAAE;AAAA,IACvC,SAAS,OAAO,oBAAoB,EAAE;AAAA,EACxC;AACA,SAAO,gBAAgB;AAAA,IACrB,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB,aAAa,SAAS,eAAe;AAAA,EACvC,CAAC;AACH;AAEA,SAAS,eAAe,QAAuC;AAC7D,aAAW,SAAS,QAAQ;AAC1B,QAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GAAG;AACvD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,YAAiD;AACpE,QAAM,UAAU,MAAM,QAAQ,WAAW,OAAO,IAAI,WAAW,UAAU,CAAC;AAC1E,SAAO,SAAS,QAAQ,CAAC,CAAC;AAC5B;AAgGA,SAAS,gBAAgB,QAAgC;AACvD,SAAO,OAAO,YAAY,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS,CAAC;AAC7F;AAEA,SAAS,WAAmB;AAC1B,SAAO,OAAO,WAAW,EAAE,WAAW,KAAK,EAAE;AAC/C;AAEA,SAAS,eAAuB;AAC9B,SAAO,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACrC;;;ACnoBO,IAAM,0BAA0B;AAGvC,IAAM,2BAA2B,CAAC,MAAM,KAAK,MAAM,KAAK,GAAG,KAAK,GAAG,IAAI,IAAI,EAAE;AAG7E,IAAM,2BAA2B,KAAK,OAAO;AAG7C,IAAM,qBAAqB;AAC3B,IAAM,yBAAyB;AAG/B,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AAQtB,SAAS,mBAAqC;AAC5C,SAAO,EAAE,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO,EAAE;AACpF;AAQO,IAAM,kBAAN,MAAsB;AAAA,EAClB;AAAA,EACT,YAAY;AAAA,EACZ,YAAY,oBAAI,IAAoB;AAAA,EACpC,aAAa,oBAAI,IAA2B;AAAA,EAC5C,UAAU,oBAAI,IAA8B;AAAA,EAC5C,YAAY,oBAAI,IAAoB;AAAA,EACpC;AAAA,EAEA,YAAY,UAAkC,CAAC,GAAG;AAChD,SAAK,gBAAgB,QAAQ,OAAO,KAAK,KAAK;AAAA,EAChD;AAAA;AAAA,EAGA,eAAqB;AACnB,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGA,QAAQ,aAAuC;AAC7C,QAAI,KAAK,YAAY,GAAG;AACtB,WAAK,aAAa;AAAA,IACpB;AACA,UAAM,MAAM,SAAS,YAAY,OAAO,YAAY,QAAQ,OAAO,YAAY,MAAM,CAAC;AACtF,SAAK,UAAU,IAAI,MAAM,KAAK,UAAU,IAAI,GAAG,KAAK,KAAK,CAAC;AAC1D,SAAK,iBAAiB,YAAY,OAAO,YAAY,aAAa,GAAI;AAAA,EACxE;AAAA;AAAA,EAGA,aAAa,OAAe,OAAyB;AACnD,UAAM,OAAO,KAAK,YAAY,KAAK;AACnC,UAAM,SAAS,KAAK,QAAQ,IAAI,IAAI,KAAK,iBAAiB;AAC1D,WAAO,YAAY;AACnB,WAAO,UAAU,YAAY,MAAM,YAAY;AAC/C,WAAO,cAAc,YAAY,MAAM,gBAAgB;AACvD,WAAO,SAAS,YAAY,MAAM,WAAW;AAC7C,WAAO,aAAa,YAAY,MAAM,mBAAmB,CAAC;AAC1D,WAAO,UAAU,YAAY,MAAM,gBAAgB,CAAC;AACpD,SAAK,QAAQ,IAAI,MAAM,MAAM;AAAA,EAC/B;AAAA;AAAA,EAGA,eAAe,MAAc,IAAmB;AAC9C,UAAM,MAAM,SAAS,MAAM,KAAK,OAAO,OAAO;AAC9C,SAAK,UAAU,IAAI,MAAM,KAAK,UAAU,IAAI,GAAG,KAAK,KAAK,CAAC;AAAA,EAC5D;AAAA;AAAA,EAGA,mBAAmB,OAA2B;AAC5C,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,OAAuB;AACjC,UAAM,UACJ,MAEG,QAAQ,0BAA0B,EAAE,EACpC,KAAK,EACL,MAAM,GAAG,sBAAsB,KAAK;AACzC,QAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,QAAQ,oBAAoB;AACzE,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,OAAe,SAAuB;AACrD,UAAM,QAAQ,OAAO,SAAS,OAAO,KAAK,WAAW,IAAI,UAAU;AACnE,UAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,KAAK;AAAA,MAC1C,SAAS,IAAI,MAAM,yBAAyB,MAAM,EAAE,KAAK,CAAC;AAAA,MAC1D,OAAO;AAAA,MACP,KAAK;AAAA,IACP;AACA,UAAM,SAAS;AACf,UAAM,OAAO;AAGb,UAAM,QAAQ,yBAAyB,UAAU,CAAC,UAAU,SAAS,KAAK;AAC1E,QAAI,UAAU,IAAI;AAChB,YAAM,QAAQ,KAAK,KAAK,MAAM,QAAQ,KAAK,KAAK,KAAK;AAAA,IACvD;AACA,SAAK,WAAW,IAAI,OAAO,KAAK;AAAA,EAClC;AAAA;AAAA,EAGA,SAAS,MAAoB,KAAK,KAAsB;AACtD,UAAM,UAAkC,CAAC;AACzC,UAAM,WAAmC,CAAC;AAC1C,QAAI,gBAAgB;AACpB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,YAAM,CAAC,QAAQ,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,MAAM,eAAe;AAC7D,cAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,KAAK;AACzC,eAAS,MAAM,KAAK,SAAS,MAAM,KAAK,KAAK;AAC7C,uBAAiB;AAAA,IACnB;AAEA,UAAM,UAA4C,CAAC;AACnD,UAAM,cAAc,EAAE,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,EAAE;AAClF,eAAW,CAAC,OAAO,MAAM,KAAK,KAAK,SAAS;AAC1C,cAAQ,KAAK,IAAI,EAAE,GAAG,OAAO;AAC7B,kBAAY,UAAU,OAAO;AAC7B,kBAAY,cAAc,OAAO;AACjC,kBAAY,SAAS,OAAO;AAC5B,kBAAY,aAAa,OAAO;AAChC,kBAAY,UAAU,OAAO;AAAA,IAC/B;AAEA,QAAI,gBAAgB;AACpB,QAAI,iBAAiB;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,uBAAiB;AACjB,UAAI,IAAI,SAAS,GAAG,eAAe,OAAO,GAAG;AAC3C,0BAAkB;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,UAAU,KAAK;AAAA,MACf,UAAU,EAAE,SAAS,UAAU,OAAO,cAAc;AAAA,MACpD,WAAW,IAAI,KAAK,KAAK,YAAY,EAAE,YAAY;AAAA,MACnD,QAAQ,EAAE,SAAS,GAAG,YAAY;AAAA,MAClC,UAAU,EAAE,QAAQ,gBAAgB,OAAO,cAAc;AAAA,MACzD,eAAe,KAAK,IAAI,GAAG,KAAK,OAAO,IAAI,IAAI,KAAK,gBAAgB,GAAI,CAAC;AAAA,IAC3E;AAAA,EACF;AAAA;AAAA,EAGA,iBAAiB,MAAoB,KAAK,KAAa;AACrD,UAAM,QAAkB,CAAC;AAEzB,UAAM,KAAK,+EAA+E;AAC1F,UAAM,KAAK,kDAAkD;AAC7D,UAAM,KAAK,uCAAuC,KAAK,eAAe,GAAI,EAAE;AAE5E,UAAM,KAAK,iEAAiE;AAC5E,UAAM,KAAK,sCAAsC;AACjD,UAAM,KAAK,2BAA2B,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,gBAAgB,GAAI,CAAC,EAAE;AAEvF,UAAM,KAAK,qEAAqE;AAChF,UAAM,KAAK,0CAA0C;AACrD,UAAM,KAAK,+BAA+B,KAAK,SAAS,EAAE;AAE1D,UAAM,KAAK,iFAAiF;AAC5F,UAAM,KAAK,wCAAwC;AACnD,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,YAAM,CAAC,QAAQ,IAAI,SAAS,IAAI,SAAS,EAAE,IAAI,IAAI,MAAM,eAAe;AACxE,YAAM,KAAK,0BAA0B,OAAO,EAAE,QAAQ,OAAO,OAAO,CAAC,CAAC,IAAI,KAAK,EAAE;AAAA,IACnF;AAEA,UAAM;AAAA,MACJ;AAAA,IACF;AACA,UAAM,KAAK,iDAAiD;AAC5D,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,YAAM,CAAC,OAAO,IAAI,UAAU,EAAE,IAAI,IAAI,MAAM,eAAe;AAC3D,YAAM,KAAK,mCAAmC,OAAO,EAAE,SAAS,KAAK,CAAC,CAAC,IAAI,KAAK,EAAE;AAAA,IACpF;AAEA,UAAM;AAAA,MACJ;AAAA,IACF;AACA,UAAM,KAAK,sCAAsC;AACjD,eAAW,CAAC,OAAO,MAAM,KAAK,KAAK,SAAS;AAC1C,YAAM,KAAK,wBAAwB,OAAO,EAAE,OAAO,MAAM,SAAS,CAAC,CAAC,IAAI,OAAO,MAAM,EAAE;AACvF,YAAM;AAAA,QACJ,wBAAwB,OAAO,EAAE,OAAO,MAAM,aAAa,CAAC,CAAC,IAAI,OAAO,UAAU;AAAA,MACpF;AACA,YAAM;AAAA,QACJ,wBAAwB,OAAO,EAAE,OAAO,MAAM,YAAY,CAAC,CAAC,IAAI,OAAO,SAAS;AAAA,MAClF;AACA,YAAM,KAAK,wBAAwB,OAAO,EAAE,OAAO,MAAM,SAAS,CAAC,CAAC,IAAI,OAAO,MAAM,EAAE;AAAA,IACzF;AAEA,UAAM,KAAK,iFAAiF;AAC5F,UAAM,KAAK,8CAA8C;AACzD,eAAW,CAAC,OAAO,MAAM,KAAK,KAAK,SAAS;AAC1C,YAAM,KAAK,gCAAgC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,OAAO,QAAQ,EAAE;AAAA,IACnF;AAEA,UAAM,KAAK,qEAAqE;AAChF,UAAM,KAAK,oDAAoD;AAC/D,eAAW,CAAC,OAAO,KAAK,KAAK,KAAK,YAAY;AAC5C,UAAI,aAAa;AACjB,eAAS,IAAI,GAAG,IAAI,yBAAyB,QAAQ,KAAK,GAAG;AAC3D,sBAAc,MAAM,QAAQ,CAAC,KAAK;AAClC,cAAM,KAAK,aAAa,yBAAyB,CAAC,KAAK,CAAC;AACxD,cAAM;AAAA,UACJ,2CAA2C,OAAO,EAAE,IAAI,MAAM,CAAC,CAAC,IAAI,UAAU;AAAA,QAChF;AAAA,MACF;AACA,YAAM;AAAA,QACJ,2CAA2C,OAAO,EAAE,IAAI,QAAQ,MAAM,CAAC,CAAC,IAAI,MAAM,KAAK;AAAA,MACzF;AACA,YAAM,KAAK,wCAAwC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,MAAM,GAAG,EAAE;AACnF,YAAM,KAAK,0CAA0C,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,MAAM,KAAK,EAAE;AAAA,IACzF;AAEA,SAAK,oBAAoB,KAAK;AAE9B,WAAO,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA;AAAA,EAC5B;AAAA,EAEA,oBAAoB,OAAuB;AACzC,UAAM,QAAQ,KAAK;AACnB,QAAI,CAAC,OAAO;AACV;AAAA,IACF;AACA,UAAM,aAAa,OAAO,QAAQ,MAAM,MAAM;AAE9C,UAAM,QAAQ,CACZ,QACA,MACA,SACS;AACT,YAAM,UAAU,WAAW,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,KAAK,KAAK,MAAM,MAAS;AAC1E,UAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,MACF;AACA,YAAM,KAAK,iCAAiC,MAAM,IAAI,IAAI,EAAE;AAC5D,YAAM,KAAK,iCAAiC,MAAM,QAAQ;AAC1D,iBAAW,CAAC,UAAU,KAAK,KAAK,SAAS;AACvC,cAAM,KAAK,0BAA0B,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE;AAAA,MACrF;AAAA,IACF;AAEA,UAAM,aAAa,6CAA6C,CAAC,MAAM,EAAE,SAAS;AAClF,UAAM,eAAe,+CAA+C,CAAC,MAAM,EAAE,WAAW;AACxF,UAAM,QAAQ,8DAA8D,CAAC,MAAM,EAAE,IAAI;AACzF;AAAA,MACE;AAAA,MACA;AAAA,MACA,CAAC,MAAM,EAAE;AAAA,IACX;AAEA,UAAM,UAAU,MAAM,iBAAiB,KAAK,MAAM,MAAM,cAAc,IAAI,OAAO;AACjF,QAAI,OAAO,SAAS,OAAO,GAAG;AAC5B,YAAM;AAAA,QACJ;AAAA,MACF;AACA,YAAM,KAAK,6DAA6D;AACxE,YAAM,KAAK,kDAAkD,UAAU,GAAI,EAAE;AAAA,IAC/E;AAEA,QAAI,MAAM,QAAQ,MAAM,eAAe;AACrC,YAAM,KAAK,gFAAgF;AAC3F,YAAM,KAAK,oCAAoC;AAC/C,YAAM;AAAA,QACJ,wBAAwB,OAAO;AAAA,UAC7B,iBAAiB,MAAM,iBAAiB;AAAA,UACxC,MAAM,MAAM,QAAQ;AAAA,QACtB,CAAC,CAAC;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAaO,SAAS,qBACd,UACA,eACA,SACA,QACU;AACV,QAAM,OAAO,SAAS;AACtB,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,QAAM,CAAC,cAAc,cAAc,IAAI,KAAK,IAAI;AAChD,QAAM,QAAQ,SAAS,QAAQ,IAAI,cAAc,GAAG,SAAS,mBAAmB,KAAK;AACrF,OAAK,aAAa,gBAAgB,OAAO,eAAe,SAAS,MAAM,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AACvF,SAAO,IAAI,SAAS,cAAc;AAAA,IAChC,SAAS,SAAS;AAAA,IAClB,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,EACvB,CAAC;AACH;AAEA,eAAe,aACb,QACA,OACA,eACA,SACA,QACe;AACf,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,MAAM;AACpB,WAAO,OAAO,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAChC;AACA,MAAI,QAAQ,SAAS;AACnB,WAAO,OAAO,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAChC,OAAO;AACL,YAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3D;AAEA,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,QAAQ;AACZ,MAAI;AACJ,MAAI,SAAS;AACb,MAAI,gBAAgB;AACpB,MAAI,aAAa;AAEjB,QAAM,WAAW,CAAC,YAA2B;AAC3C,UAAM,SAAS,SAAS,OAAO;AAC/B,UAAM,QACJ,kBAAkB,OAAO,KAAK,KAAK,kBAAkB,SAAS,OAAO,QAAQ,EAAE,KAAK;AACtF,QAAI,OAAO;AACT,cAAQ;AAAA,IACV;AACA,UAAM,iBAAiB,UAAU,OAAO,KAAK,KAAK,UAAU,SAAS,OAAO,QAAQ,EAAE,KAAK;AAC3F,QAAI,gBAAgB;AAClB,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI;AACF,WAAO,MAAM;AACX,YAAM,SAAS,MAAM,OAAO,KAAK;AACjC,UAAI,OAAO,MAAM;AACf;AAAA,MACF;AACA,YAAM,QAAQ,QAAQ,OAAO,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAC3D,UAAI,OAAO;AACT,kBAAU;AACV,cAAM,QAAQ,OAAO,MAAM,OAAO;AAClC,iBAAS,MAAM,IAAI,KAAK;AACxB,mBAAW,QAAQ,OAAO;AACxB,0BAAgB,MAAM,QAAQ;AAAA,QAChC;AAEA,YAAI,OAAO,SAAS,0BAA0B;AAC5C,mBAAS;AAAA,QACX;AAAA,MACF,WAAW,CAAC,YAAY;AACtB,yBAAiB,OAAO,MAAM;AAC9B,YAAI,gBAAgB,0BAA0B;AAC5C,uBAAa;AACb,mBAAS;AAAA,QACX,OAAO;AACL,oBAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAEA,UAAM,cAAc,SAAS,QAAQ,OAAO;AAC5C,QAAI,OAAO;AACT,UAAI,aAAa;AACf,wBAAgB,aAAa,QAAQ;AAAA,MACvC;AAAA,IACF,WAAW,CAAC,cAAc,aAAa;AACrC,YAAM,SAAS,UAAU,WAAW;AACpC,UAAI,WAAW,QAAW;AACxB,iBAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF,UAAE;AACA,YAAQ,oBAAoB,SAAS,OAAO;AAC5C,WAAO,YAAY;AAAA,EACrB;AAEA,MAAI,OAAO;AACT,YAAQ,OAAO,KAAK;AAAA,EACtB;AACF;AAEA,SAAS,gBAAgB,MAAc,UAA4C;AACjF,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAQ,WAAW,OAAO,GAAG;AAChC;AAAA,EACF;AACA,QAAM,OAAO,QAAQ,MAAM,QAAQ,MAAM,EAAE,KAAK;AAChD,MAAI,CAAC,QAAQ,SAAS,UAAU;AAC9B;AAAA,EACF;AACA,QAAM,SAAS,UAAU,IAAI;AAC7B,MAAI,WAAW,QAAW;AACxB,aAAS,MAAM;AAAA,EACjB;AACF;AAEA,SAAS,UAAU,MAAuB;AACxC,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,OAAwB;AACzC,SAAO,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;AACpD;AAEA,SAAS,YAAY,OAAuB;AAC1C,SAAO,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAQ;AACvD;AAEA,SAAS,YAAY,OAAyB;AAC5C,SAAO,MAAM,KAAK,eAAe;AACnC;AAEA,SAAS,OAAO,OAAuC;AACrD,QAAM,UAAU,OAAO,QAAQ,KAAK;AACpC,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,GAAG,IAAI,KAAK,iBAAiB,KAAK,CAAC,GAAG;AACtF,SAAO,IAAI,SAAS,KAAK,GAAG,CAAC;AAC/B;AAEA,SAAS,iBAAiB,OAAuB;AAC/C,SAAO,MACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK;AACzB;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,OAAO,UAAU,KAAK,IAAI,MAAM,SAAS,IAAI,OAAO,KAAK;AAClE;;;AClcA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,uBAAuB;AAC7B,IAAM,qBAAqB;AAUpB,SAAS,sBACd,UAAiC,CAAC,GACO;AACzC,QAAM,SAAS,IAAI,cAAc,OAAO;AACxC,QAAM,SAAS,QAAQ,UAAU,QAAQ,KAAK;AAC9C,QAAM,SAAS,aAAa,OAAO;AACnC,QAAM,UAAU,QAAQ,WAAW,IAAI,gBAAgB;AACvD,QAAM,YAAY,kBAAkB,QAAQ,OAAO;AACnD,QAAM,eAA8B,CAAC,OAAO,UAAU,QAAQ,aAAa,OAAO,KAAK;AAEvF,SAAO,OAAO,YAAwC;AACpD,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,UAAM,UAAU,iBAAiB,IAAI,QAAQ;AAC7C,UAAM,YAAY,aAAa,OAAO;AACtC,UAAM,QAAQ,SAAS,QAAQ,QAAQ,OAAO;AAC9C,UAAM,gBAAgB,OAAO,MAAM;AAAA,MACjC,QAAQ,QAAQ;AAAA,MAChB,MAAM,IAAI;AAAA,MACV;AAAA,MACA;AAAA,IACF,CAAC;AACD,YAAQ,aAAa;AACrB,UAAM,SAAS,CAAC,aACd,eAAe,UAAU;AAAA,MACvB,QAAQ;AAAA,MACR,QAAQ,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAEH,QAAI,QAAQ,WAAW,WAAW;AAChC,aAAO,OAAO,IAAI,SAAS,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC;AAAA,IAC9D;AAEA,QAAI,CAAC,aAAa,SAAS,MAAM,GAAG;AAClC,oBAAc,KAAK,EAAE,OAAO,4BAA4B,GAAG,0BAA0B;AACrF,aAAO,OAAO,UAAU,KAAK,mBAAmB,sCAAsC,CAAC;AAAA,IACzF;AAEA,QAAI;AACF,UAAI,QAAQ,WAAW,UAAU,YAAY,OAAO,YAAY,aAAa;AAC3E,eAAO,OAAO,aAAa,EAAE,MAAM,YAAY,QAAQ,UAAU,QAAQ,KAAK,CAAC,CAAC;AAAA,MAClF;AACA,UAAI,QAAQ,WAAW,SAAS,YAAY,YAAY;AACtD,eAAO,OAAO,gBAAgB,OAAO,CAAC;AAAA,MACxC;AACA,UAAI,QAAQ,WAAW,SAAS,YAAY,aAAa;AACvD,eAAO,OAAO,MAAM,YAAY,SAAS,WAAW,QAAQ,MAAM,CAAC;AAAA,MACrE;AACA,UAAI,QAAQ,WAAW,SAAS,YAAY,iBAAiB;AAC3D,eAAO,OAAO,6BAA6B,CAAC;AAAA,MAC9C;AACA,UAAI,QAAQ,WAAW,SAAS,YAAY,cAAc;AACxD,eAAO,OAAO,MAAM,aAAa,QAAQ,SAAS,QAAQ,QAAQ,aAAa,CAAC;AAAA,MAClF;AACA,UAAI,QAAQ,WAAW,UAAU,YAAY,wBAAwB;AACnE,eAAO;AAAA,UACL,MAAM,sBAAsB,QAAQ,SAAS,cAAc,SAAS,aAAa;AAAA,QACnF;AAAA,MACF;AACA,UAAI,QAAQ,WAAW,UAAU,YAAY,mBAAmB;AAC9D,eAAO;AAAA,UACL,MAAM,kBAAkB,QAAQ,SAAS,cAAc,SAAS,aAAa;AAAA,QAC/E;AAAA,MACF;AACA,UAAI,QAAQ,WAAW,UAAU,YAAY,iBAAiB;AAC5D,eAAO,OAAO,MAAM,gBAAgB,QAAQ,SAAS,cAAc,SAAS,aAAa,CAAC;AAAA,MAC5F;AACA,aAAO,OAAO,UAAU,KAAK,aAAa,gBAAgB,QAAQ,MAAM,IAAI,IAAI,QAAQ,GAAG,CAAC;AAAA,IAC9F,SAAS,OAAO;AACd,UAAI,iBAAiB,kBAAkB;AACrC,sBAAc;AAAA,UACZ,EAAE,KAAK,aAAa,KAAK,GAAG,OAAO,uBAAuB;AAAA,UAC1D;AAAA,QACF;AACA,eAAO,OAAO,UAAU,KAAK,sBAAsB,MAAM,OAAO,CAAC;AAAA,MACnE;AACA,YAAM,UAAU,aAAa,KAAK;AAClC,UAAI,YAAY,sBAAsB;AACpC,sBAAc;AAAA,UACZ,EAAE,KAAK,aAAa,KAAK,GAAG,OAAO,sBAAsB;AAAA,UACzD;AAAA,QACF;AACA,eAAO,OAAO,UAAU,KAAK,yBAAyB,OAAO,CAAC;AAAA,MAChE,OAAO;AACL,sBAAc;AAAA,UACZ,EAAE,KAAK,aAAa,KAAK,GAAG,OAAO,sBAAsB;AAAA,UACzD;AAAA,QACF;AAAA,MACF;AACA,aAAO,OAAO,UAAU,KAAK,kBAAkB,OAAO,CAAC;AAAA,IACzD;AAAA,EACF;AACF;AAEO,SAAS,oBAAoB,UAAiC,CAAC,GAA0B;AAC9F,QAAM,OAAO,QAAQ,QAAQ,QAAQ,KAAK,QAAQ;AAClD,QAAM,OAAO,OAAO,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,YAAY;AACrE,QAAM,SAAS,QAAQ,UAAU,QAAQ,KAAK;AAC9C,QAAM,uBACJ,QAAQ,wBAAwB,QAAQ,KAAK,mCAAmC;AAElF,MAAI,CAAC,eAAe,IAAI,KAAK,CAAC,UAAU,CAAC,sBAAsB;AAC7D,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,IAAI,MAAM;AAAA,IACvB,OAAO,sBAAsB;AAAA,MAC3B,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,IACD,UAAU;AAAA,IACV;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,KAAK,UAAU,IAAI,IAAI,OAAO,IAAI;AAAA,EACpC;AACF;AAEA,eAAe,aACb,QACA,SACA,QACA,QACmB;AACnB,QAAM,WAAW,MAAM,OAAO,OAAO,MAAM;AAC3C,UAAQ,eAAe,WAAW,SAAS,EAAE;AAC7C,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,qBAAqB,SAAS,MAAM,GAAG;AACzC,aAAO,WAAW,UAAU,MAAM;AAAA,IACpC;AACA,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,cAAc;AAAA,QACd,gBAAgB,SAAS;AAAA,MAC3B;AAAA,MACA;AAAA,IACF;AACA,WAAO,aAAa,EAAE,MAAM,eAAe,GAAG,QAAQ,OAAO,CAAC;AAAA,EAChE;AACA,qBAAmB,QAAQ,WAAW,SAAS,MAAM;AACrD,SAAO,aAAa,wBAAwB,MAAM,SAAS,KAAK,CAAC,CAAC;AACpE;AAEA,eAAe,sBACb,QACA,SACA,cACA,SACA,QACmB;AACnB,QAAM,cAAc,+BAA+B,MAAM,SAAS,OAAO,CAAC;AAC1E,QAAM,WAAW,MAAM,OAAO,gBAAgB,aAAa,QAAQ,MAAM;AACzE,UAAQ,eAAe,qBAAqB,SAAS,EAAE;AACvD,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,WAAW,UAAU,MAAM;AAAA,EACpC;AACA,qBAAmB,QAAQ,qBAAqB,SAAS,MAAM;AAC/D,QAAM,QAAQ,wBAAwB,YAAY,KAAK;AACvD,SAAO,cAAc,qBAAqB,UAAU,OAAO,cAAc,QAAQ,MAAM,CAAC;AAC1F;AAEA,eAAe,kBACb,QACA,SACA,cACA,SACA,QACmB;AACnB,QAAM,OAAO,MAAM,SAAS,OAAO;AACnC,QAAM,WAAW,MAAM,OAAO;AAAA,IAC5B,mCAAmC,IAAI;AAAA,IACvC,QAAQ;AAAA,EACV;AACA,UAAQ,eAAe,qBAAqB,SAAS,EAAE;AACvD,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,WAAW,UAAU,MAAM;AAAA,EACpC;AACA,qBAAmB,QAAQ,qBAAqB,SAAS,MAAM;AAC/D,QAAM,QAAQ,wBAAwB,KAAK,KAAK;AAGhD,MAAI,oBAAoB,QAAQ,GAAG;AACjC,WAAO,cAAc,qBAAqB,UAAU,OAAO,cAAc,QAAQ,MAAM,CAAC;AAAA,EAC1F;AACA,QAAM,aAAa,SAAS,MAAM,SAAS,KAAK,CAAC;AACjD,QAAM,QAAQ,kBAAkB,WAAW,KAAK;AAChD,MAAI,OAAO;AACT,UAAM,gBAAgB,OAAO,WAAW,UAAU,WAAW,WAAW,MAAM,KAAK,IAAI;AACvF,iBAAa,iBAAiB,OAAO,KAAK;AAAA,EAC5C;AACA,SAAO,aAAa,2BAA2B,UAAU,CAAC;AAC5D;AAEA,eAAe,gBACb,QACA,SACA,cACA,SACA,QACmB;AACnB,QAAM,OAAO,MAAM,aAAa,OAAO;AACvC,QAAM,WAAW,MAAM,OAAO,UAAU,MAAM,QAAQ,MAAM;AAC5D,UAAQ,eAAe,cAAc,SAAS,EAAE;AAChD,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,WAAW,UAAU,MAAM;AAAA,EACpC;AACA,qBAAmB,QAAQ,cAAc,SAAS,MAAM;AACxD,QAAM,QAAQ,wBAAwB,SAAS,cAAc,IAAI,CAAC,EAAE,KAAK;AACzE,SAAO,cAAc,qBAAqB,UAAU,OAAO,cAAc,QAAQ,MAAM,CAAC;AAC1F;AAEA,eAAe,WAAW,UAAoB,QAA2C;AACvF,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,MAAI,qBAAqB,SAAS,MAAM,GAAG;AACzC,WAAO;AAAA,MACL,EAAE,OAAO,yBAAyB,gBAAgB,SAAS,OAAO;AAAA,MAClE;AAAA,IACF;AACA,WAAO,UAAU,KAAK,sBAAsB,oBAAoB,QAAQ,SAAS,UAAU,CAAC;AAAA,EAC9F;AACA,SAAO;AAAA,IACL,EAAE,OAAO,0BAA0B,gBAAgB,SAAS,OAAO;AAAA,IACnE;AAAA,EACF;AACA,SAAO,UAAU,SAAS,QAAQ,iBAAiB,QAAQ,SAAS,UAAU;AAChF;AAEA,SAAS,cAAc,UAA8B;AACnD,QAAM,UAAU,IAAI,QAAQ,SAAS,OAAO;AAC5C,UAAQ,OAAO,kBAAkB;AACjC,UAAQ,OAAO,gBAAgB;AAC/B,UAAQ,OAAO,mBAAmB;AAClC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,CAAC,GAAG;AACxD,YAAQ,IAAI,KAAK,KAAK;AAAA,EACxB;AACA,SAAO,IAAI,SAAS,SAAS,MAAM;AAAA,IACjC;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,EACvB,CAAC;AACH;AAEA,eAAe,SAAS,SAAuC;AAC7D,MAAI;AACF,WAAO,SAAS,MAAM,QAAQ,KAAK,CAAC;AAAA,EACtC,QAAQ;AACN,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AACF;AAEA,eAAe,aAAa,SAAmC;AAC7D,QAAM,OAAO,MAAM,QAAQ,KAAK;AAChC,MAAI;AACF,SAAK,MAAM,IAAI;AACf,WAAO;AAAA,EACT,QAAQ;AACN,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AACF;AAEA,SAAS,aAAa,MAAkB,SAAS,KAAe;AAC9D,SAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,IACxC,SAAS;AAAA,MACP,GAAG,YAAY;AAAA,MACf,gBAAgB;AAAA,IAClB;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,SAAS,UAAU,QAAgB,MAAc,SAA2B;AAC1E,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,+BAAyC;AAChD,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,WAAS,QAAQ,IAAI,WAAW,WAAW;AAC3C,SAAO;AACT;AAEA,SAAS,cAAsC;AAC7C,SAAO;AAAA,IACL,gCAAgC;AAAA,IAChC,gCAAgC;AAAA,IAChC,+BAA+B;AAAA,EACjC;AACF;AAEA,SAAS,aAAa,SAAkB,QAAqC;AAC3E,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,QAAM,gBAAgB,QAAQ,QAAQ,IAAI,eAAe,KAAK;AAC9D,QAAM,SAAS,cAAc,MAAM,kBAAkB,IAAI,CAAC;AAC1D,SAAO,WAAW,UAAU,QAAQ,QAAQ,IAAI,WAAW,MAAM;AACnE;AAEA,SAAS,qBAAqB,QAAyB;AACrD,SAAO,WAAW,OAAO,WAAW;AACtC;AAEA,SAAS,oBAAoB,SAAyB;AACpD,SAAO,6DAA6D,OAAO;AAC7E;AAEA,SAAS,eAAe,MAAuB;AAC7C,SAAO,SAAS,eAAe,SAAS,eAAe,SAAS;AAClE;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,SAAS,aAAa,SAAgD;AACpE,MAAI,QAAQ,QAAQ;AAClB,WAAO,QAAQ,OAAO,MAAM,EAAE,WAAW,SAAS,CAAC;AAAA,EACrD;AACA,MAAI,mBAAmB,OAAO,GAAG;AAC/B,WAAO,qBAAqB;AAAA,MAC1B,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,IACjB,CAAC,EAAE,MAAM,EAAE,WAAW,SAAS,CAAC;AAAA,EAClC;AACA,SAAO;AACT;AAEA,SAAS,eACP,UACA,SAQU;AACV,QAAM,gBAAgB,sBAAsB,UAAU,QAAQ,SAAS;AACvE,QAAM,SAAS,oBAAoB,aAAa;AAChD,QAAM,SAAS,cAAc;AAK7B,QAAM,WAAW,MAAY;AAC3B,UAAM,aAAa,KAAK,OAAO,YAAY,IAAI,IAAI,QAAQ,aAAa,GAAG,IAAI;AAC/E,YAAQ,QAAQ,QAAQ,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,OAAO,OAAO,CAAC;AAC5F,wBAAoB,QAAQ,QAAQ,QAAQ,QAAQ,UAAU;AAAA,EAChE;AAEA,MAAI,UAAU,cAAc,MAAM;AAChC,WAAO,IAAI,SAAS,sBAAsB,cAAc,MAAM,QAAQ,GAAG;AAAA,MACvE,SAAS,cAAc;AAAA,MACvB;AAAA,MACA,YAAY,cAAc;AAAA,IAC5B,CAAC;AAAA,EACH;AACA,WAAS;AACT,SAAO;AACT;AAEA,SAAS,sBAAsB,UAAoB,WAA6B;AAC9E,QAAM,UAAU,IAAI,QAAQ,SAAS,OAAO;AAC5C,UAAQ,IAAI,gBAAgB,SAAS;AACrC,SAAO,IAAI,SAAS,SAAS,MAAM;AAAA,IACjC;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,EACvB,CAAC;AACH;AAKA,SAAS,sBACP,MACA,YAC4B;AAC5B,QAAM,SAAS,KAAK,UAAU;AAC9B,MAAI,QAAQ;AACZ,QAAM,OAAO,MAAY;AACvB,QAAI,CAAC,OAAO;AACV,cAAQ;AACR,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO,IAAI,eAA2B;AAAA,IACpC,MAAM,KAAK,YAAY;AACrB,UAAI;AACF,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,MAAM;AACR,qBAAW,MAAM;AACjB,eAAK;AACL;AAAA,QACF;AACA,mBAAW,QAAQ,KAAK;AAAA,MAC1B,SAAS,OAAO;AACd,aAAK;AACL,mBAAW,MAAM,KAAK;AAAA,MACxB;AAAA,IACF;AAAA,IACA,OAAO,QAAQ;AACb,WAAK;AACL,aAAO,OAAO,OAAO,MAAM;AAAA,IAC7B;AAAA,EACF,CAAC;AACH;AAEA,SAAS,oBACP,QACA,QACA,QACA,YACM;AACN,QAAM,SAAoB;AAAA,IACxB;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACA,MAAI,UAAU,KAAK;AACjB,WAAO,MAAM,QAAQ,qCAAqC;AAC1D;AAAA,EACF;AACA,MAAI,UAAU,KAAK;AACjB,WAAO,KAAK,QAAQ,qCAAqC;AACzD;AAAA,EACF;AACA,SAAO,KAAK,QAAQ,mBAAmB;AACzC;AAEA,SAAS,aAAa,SAA0B;AAC9C,QAAM,WAAW,QAAQ,QAAQ,IAAI,cAAc,GAAG,KAAK;AAC3D,SAAO,YAAY,OAAO,WAAW;AACvC;AAEA,SAAS,iBAAiB,MAAsB;AAC9C,QAAM,uBAAuB,KAAK,SAAS,IAAI,KAAK,QAAQ,QAAQ,EAAE,IAAI;AAC1E,UAAQ,sBAAsB;AAAA,IAC5B,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,SAAS,QAAgB,MAAsB;AACtD,MAAI,WAAW,WAAW;AACxB,WAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,SAAS,OAAO,SAAS,aAAa;AAC7D,WAAO;AAAA,EACT;AACA,MAAI,WAAW,SAAS,SAAS,YAAY;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,WAAW,SAAS,SAAS,aAAa;AAC5C,WAAO;AAAA,EACT;AACA,MAAI,WAAW,SAAS,SAAS,cAAc;AAC7C,WAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,SAAS,wBAAwB;AACxD,WAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,SAAS,mBAAmB;AACnD,WAAO;AAAA,EACT;AACA,MAAI,WAAW,UAAU,SAAS,iBAAiB;AACjD,WAAO;AAAA,EACT;AACA,MAAI,WAAW,SAAS,SAAS,iBAAiB;AAChD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,UAA6B;AACxD,SAAO,SAAS,QAAQ,IAAI,cAAc,GAAG,SAAS,mBAAmB,KAAK;AAChF;AAEA,SAAS,mBAAmB,QAAwB,cAAsB,QAAsB;AAC9F,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP;AAAA,MACA,gBAAgB;AAAA,IAClB;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,SAAoC;AAC3D,SAAO,IAAI,SAAS,QAAQ,iBAAiB,GAAG;AAAA,IAC9C,SAAS;AAAA,MACP,GAAG,YAAY;AAAA,MACf,gBAAgB;AAAA,IAClB;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AACH;AAEA,eAAe,YACb,SACA,WACA,QACmB;AACnB,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,EAAE,SAAS,MAAM,IAAI,MAAM,UAAU,MAAM;AACjD,QAAM,OAAmB,EAAE,SAAS,WAAW,MAAM,QAAQ,SAAS,MAAM;AAC5E,MAAI,OAAO;AACT,SAAK,gBAAgB;AAAA,EACvB;AACA,SAAO,aAAa,IAAI;AAC1B;AAQO,SAAS,kBACd,QACA,SACA,MAAoB,KAAK,KACzB,QAAQ,oBACK;AACb,QAAM,YAAY;AAClB,MAAI;AACJ,SAAO,OAAO,WAAW;AACvB,QAAI,SAAS,IAAI,IAAI,MAAM,OAAO,OAAO;AACvC,aAAO,EAAE,SAAS,MAAM,MAAM;AAAA,IAChC;AACA,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,MAAM,MAAM;AAC1C,cAAQ,eAAe,WAAW,SAAS,EAAE;AAC7C,UAAI,CAAC,SAAS,IAAI;AAChB,eAAO,EAAE,OAAO,4CAA4C,SAAS,MAAM,IAAI;AAAA,MACjF;AACA,YAAM,QAAQ,sBAAsB,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC;AAC3E,cAAQ,EAAE,MAAM,IAAI,GAAG,MAAM;AAC7B,cAAQ,mBAAmB,KAAK;AAChC,aAAO,EAAE,SAAS,MAAM;AAAA,IAC1B,SAAS,OAAO;AACd,cAAQ,eAAe,WAAW,KAAK;AACvC,UAAI,iBAAiB,kBAAkB;AACrC,eAAO,EAAE,OAAO,MAAM,QAAQ;AAAA,MAChC;AACA,aAAO,EAAE,OAAO,aAAa,KAAK,EAAE;AAAA,IACtC;AAAA,EACF;AACF;AAEA,SAAS,cAAc,MAAuB;AAC5C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACpnBA,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B;AAAA,EACE,aAAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,OACK;AACP,SAAS,UAAU,iBAAiB;AACpC,SAAS,eAAe;AACxB,SAAS,WAAAC,UAAS,QAAAC,aAAY;;;ACX9B,IAAM,aAAa;AACnB,IAAM,YAAY;AACX,IAAM,OAAO,GAAG,UAAU,IAAI,SAAS;AACvC,IAAM,cAAc;AAMpB,IAAM,2BAA2B,MAAO,KAAK,KAAK;AAgBzD,SAAS,YAAY,OAA8B;AACjD,QAAM,QAAQ,OAAO,KAAK,EACvB,KAAK,EACL,QAAQ,UAAU,EAAE;AACvB,QAAM,QAAQ,MAAM,MAAM,kEAAkE;AAC5F,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,OAAO,OAAO,MAAM,CAAC,CAAC;AAAA,IACtB,OAAO,OAAO,MAAM,CAAC,CAAC;AAAA,IACtB,OAAO,OAAO,MAAM,CAAC,CAAC;AAAA;AAAA,IAEtB,YAAY,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;AAAA,EAChD;AACF;AAEA,SAAS,kBAAkB,GAAa,GAAyB;AAC/D,MAAI,EAAE,WAAW,KAAK,EAAE,WAAW,GAAG;AACpC,WAAO;AAAA,EACT;AAEA,MAAI,EAAE,WAAW,GAAG;AAClB,WAAO;AAAA,EACT;AACA,MAAI,EAAE,WAAW,GAAG;AAClB,WAAO;AAAA,EACT;AACA,QAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AACvC,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,UAAM,IAAI,EAAE,CAAC;AACb,UAAM,IAAI,EAAE,CAAC;AAEb,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAW;AACnB,aAAO;AAAA,IACT;AACA,UAAM,WAAW,QAAQ,KAAK,CAAC;AAC/B,UAAM,WAAW,QAAQ,KAAK,CAAC;AAC/B,QAAI,YAAY,UAAU;AACxB,YAAM,OAAO,OAAO,CAAC,IAAI,OAAO,CAAC;AACjC,UAAI,SAAS,GAAG;AACd,eAAO,OAAO,IAAI,KAAK;AAAA,MACzB;AAAA,IACF,WAAW,UAAU;AACnB,aAAO;AAAA,IACT,WAAW,UAAU;AACnB,aAAO;AAAA,IACT,WAAW,MAAM,GAAG;AAClB,aAAO,IAAI,IAAI,KAAK;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,cAAc,GAAW,GAAuB;AAC9D,QAAM,KAAK,YAAY,CAAC;AACxB,QAAM,KAAK,YAAY,CAAC;AACxB,MAAI,CAAC,MAAM,CAAC,IAAI;AACd,QAAI,CAAC,MAAM,CAAC,IAAI;AACd,aAAO;AAAA,IACT;AACA,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,MAAI,GAAG,UAAU,GAAG,OAAO;AACzB,WAAO,GAAG,QAAQ,GAAG,QAAQ,KAAK;AAAA,EACpC;AACA,MAAI,GAAG,UAAU,GAAG,OAAO;AACzB,WAAO,GAAG,QAAQ,GAAG,QAAQ,KAAK;AAAA,EACpC;AACA,MAAI,GAAG,UAAU,GAAG,OAAO;AACzB,WAAO,GAAG,QAAQ,GAAG,QAAQ,KAAK;AAAA,EACpC;AACA,SAAO,kBAAkB,GAAG,YAAY,GAAG,UAAU;AACvD;AAGO,SAAS,WAAW,SAAiB,QAAyB;AACnE,SAAO,cAAc,SAAS,MAAM,IAAI;AAC1C;AAGO,SAAS,eAAe,KAAqB;AAClD,SAAO,IAAI,KAAK,EAAE,QAAQ,MAAM,EAAE;AACpC;AAMO,SAAS,eAAe,UAAkB,MAAc,QAAyB;AACtF,QAAM,KAAK,aAAa,UAAU,YAAY,aAAa,WAAW,WAAW;AACjF,QAAM,MAAM,SAAS,WAAW,SAAS,YAAY,UAAU;AAC/D,QAAM,OAAO,OAAO,WAAW,SAAS,UAAU;AAClD,SAAO,GAAG,EAAE,IAAI,GAAG,GAAG,IAAI;AAC5B;AAGO,SAAS,aAAa,QAAwB;AACnD,QAAM,OAAO,YAAY,MAAM;AAC/B,SAAO,OAAO,WAAW,UAAU,IAAI,GAAG,IAAI,SAAS;AACzD;AAGO,SAAS,sBACd,KACA,OACS;AACT,MAAI,IAAI,4BAA4B,IAAI,oBAAoB;AAC1D,WAAO;AAAA,EACT;AACA,MAAI,IAAI,aAAa,QAAQ;AAC3B,WAAO;AAAA,EACT;AACA,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,MACG,IAAI,MAAM,IAAI,OAAO,WACtB,IAAI,0BACJ,IAAI,kBACJ,IAAI,gBACJ,IAAI,QACJ;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,SAAS,cACd,WACA,KACA,aAAa,0BACJ;AACT,SAAO,MAAM,aAAa;AAC5B;AAGO,SAAS,kBAAkB,MAA2B;AAC3D,SAAO,SAAS,WACZ,oBACA,kBAAkB,WAAW,4BAA4B,WAAW;AAC1E;AAGO,SAAS,uBAAuB,UAAkB,oBAAsC;AAC7F,SAAO,aAAa,WAAW;AACjC;AAGO,SAAS,mBAAmB,SAAiB,QAAgB,MAA2B;AAC7F,SACE;AAAA,iCAAoC,OAAO,WAAM,MAAM;AAAA,OAC/C,kBAAkB,IAAI,CAAC;AAAA;AAAA;AAEnC;AAGO,SAAS,WAAW,MAA2B;AACpD,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,WAAO;AAAA,MACL,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAAA,MACjE,eAAe,OAAO,KAAK,kBAAkB,WAAW,KAAK,gBAAgB;AAAA,MAC7E,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,IACpD;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,WAAW,GAAG,eAAe,MAAM,MAAM,KAAK;AAAA,EACzD;AACF;AASO,SAAS,mBAAmB,MAAqC;AACtE,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AACA,QAAM,SAAS;AACf,QAAM,MAAM,OAAO,OAAO,aAAa,WAAW,OAAO,WAAW;AACpE,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,QAAM,SAA+C,CAAC;AACtD,MAAI,MAAM,QAAQ,OAAO,MAAM,GAAG;AAChC,eAAW,QAAQ,OAAO,QAAQ;AAChC,UAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,cAAM,QAAQ;AACd,YAAI,OAAO,MAAM,SAAS,YAAY,OAAO,MAAM,yBAAyB,UAAU;AACpF,iBAAO,KAAK,EAAE,MAAM,MAAM,MAAM,KAAK,MAAM,qBAAqB,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,SAAS,eAAe,GAAG,GAAG,KAAK,OAAO;AACrD;AAGO,SAAS,YAAY,UAAkB,UAAsC;AAClF,aAAW,QAAQ,SAAS,MAAM,OAAO,GAAG;AAC1C,UAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,+BAA+B;AAC/D,QAAI,QAAQ,CAAC,KAAK,MAAM,CAAC,GAAG,KAAK,MAAM,UAAU;AAC/C,aAAO,MAAM,CAAC,EAAE,YAAY;AAAA,IAC9B;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,gBACd,KACA,UACAC,UACAC,OACQ;AACR,MAAI,aAAa,SAAS;AACxB,UAAMC,QAAO,IAAI,gBAAgBD,MAAKD,UAAS,WAAW,OAAO;AACjE,WAAOC,MAAKC,OAAM,UAAU;AAAA,EAC9B;AACA,MAAI,aAAa,UAAU;AACzB,WAAOD,MAAKD,UAAS,WAAW,UAAU,UAAU;AAAA,EACtD;AACA,QAAM,OAAO,IAAI,kBAAkBC,MAAKD,UAAS,QAAQ;AACzD,SAAOC,MAAK,MAAM,UAAU;AAC9B;AAQO,SAAS,sBAA8B;AAC5C,SAAO,gCAAgC,IAAI;AAC7C;;;AC9QO,IAAM,gBACX,OAAO,qBAAqB,cAAc,mBAAmB;AAOxD,IAAM,eACX,OAAO,oBAAoB,cAAc,kBAAkB;AAGtD,IAAM,uBAAgC,kBAAkB;AAE/D,IAAI;AAGJ,eAAsB,aAA8B;AAClD,MAAI,kBAAkB,QAAW;AAC/B,WAAO;AAAA,EACT;AACA,MAAI;AACJ,MAAI,eAAe;AACjB,eAAW;AAAA,EACb,OAAO;AACL,QAAI;AACF,YAAM,WAAW,MAAM,IAAI,KAAK,IAAI,IAAI,mBAAmB,YAAY,GAAG,CAAC,EAAE,KAAK;AAClF,iBAAW,OAAO,SAAS,YAAY,WAAW,SAAS,UAAU;AAAA,IACvE,QAAQ;AACN,iBAAW;AAAA,IACb;AAAA,EACF;AACA,kBAAgB;AAChB,SAAO;AACT;;;AFJA,IAAME,sBAAqB;AAC3B,IAAM,aAAa;AAEnB,SAAS,UAAU,SAAyB;AAC1C,SAAO,YAAY,OAAO;AAC5B;AAEA,SAAS,WAAmB;AAC1B,SAAO,gBAAgB,QAAQ,KAAK,QAAQ,UAAU,QAAQ,GAAGC,KAAI;AACvE;AAEA,SAAS,gBAAwB;AAC/B,SAAOA,MAAK,SAAS,GAAG,mBAAmB;AAC7C;AAEA,eAAe,gBAAsC;AACnD,MAAI;AACF,WAAO,WAAW,MAAM,SAAS,cAAc,GAAG,MAAM,CAAC;AAAA,EAC3D,QAAQ;AACN,WAAO,EAAE,WAAW,GAAG,eAAe,MAAM,MAAM,KAAK;AAAA,EACzD;AACF;AAEA,eAAe,eAAe,OAAmC;AAC/D,MAAI;AACF,IAAAC,WAAU,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACzC,UAAM,UAAU,cAAc,GAAG,KAAK,UAAU,KAAK,GAAG,MAAM;AAAA,EAChE,QAAQ;AAAA,EAER;AACF;AAQA,eAAe,YAAY,SAAiB,MAAmD;AAC7F,MAAI;AACF,UAAM,UAAkC;AAAA,MACtC,QAAQ;AAAA,MACR,cAAc,UAAU,OAAO;AAAA,MAC/B,wBAAwB;AAAA,IAC1B;AACA,QAAI,MAAM;AACR,cAAQ,eAAe,IAAI;AAAA,IAC7B;AACA,UAAM,WAAW,MAAM,MAAM,oBAAoB,GAAG;AAAA,MAClD;AAAA,MACA,QAAQ,YAAY,QAAQF,mBAAkB;AAAA,IAChD,CAAC;AACD,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO,EAAE,QAAQ,KAAK,MAAM,QAAQ,MAAM,SAAS,KAAK;AAAA,IAC1D;AACA,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO,EAAE,QAAQ,SAAS,QAAQ,MAAM,MAAM,SAAS,KAAK;AAAA,IAC9D;AACA,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,MAAM,SAAS,QAAQ,IAAI,MAAM;AAAA,MACjC,SAAS,mBAAmB,MAAM,SAAS,KAAK,CAAC;AAAA,IACnD;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,eAAsB,kBACpB,gBACA,MACA,QACe;AACf,MAAI,sBAAsB,QAAQ,KAAK,QAAQ,QAAQ,OAAO,KAAK,CAAC,GAAG;AACrE,YAAQ,MAAM,EAAE,OAAO,uBAAuB,GAAG,sBAAsB;AACvE;AAAA,EACF;AACA,QAAM,QAAQ,MAAM,cAAc;AAClC,MAAI,MAAM,iBAAiB,WAAW,gBAAgB,MAAM,aAAa,GAAG;AAC1E,YAAQ;AAAA,MACN;AAAA,QACE;AAAA,QACA,OAAO;AAAA,QACP,aAAa;AAAA,QACb,eAAe,MAAM;AAAA,MACvB;AAAA,MACA;AAAA,IACF;AACA,YAAQ,OAAO,MAAM,mBAAmB,gBAAgB,MAAM,eAAe,IAAI,CAAC;AAAA,EACpF;AACA,MAAI,cAAc,MAAM,WAAW,KAAK,IAAI,CAAC,GAAG;AAC9C,YAAQ,MAAM,EAAE,OAAO,8BAA8B,GAAG,6BAA6B;AACrF,SAAK,aAAa,gBAAgB,MAAM,QAAQ,MAAM,MAAM,EAAE,MAAM,CAAC,UAAmB;AACtF,cAAQ;AAAA,QACN,EAAE,KAAK,aAAa,KAAK,GAAG,OAAO,8BAA8B;AAAA,QACjE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,eAAe,aACb,gBACA,MACA,QACe;AACf,QAAM,SAAS,MAAM,YAAY,gBAAgB,IAAI;AACrD,MAAI,CAAC,QAAQ;AACX,YAAQ,MAAM,EAAE,OAAO,2BAA2B,GAAG,0BAA0B;AAC/E;AAAA,EACF;AACA,MAAI,OAAO,WAAW,KAAK;AACzB,UAAM,OAAO,MAAM,cAAc;AACjC,UAAM,eAAe,EAAE,GAAG,MAAM,WAAW,KAAK,IAAI,EAAE,CAAC;AACvD,YAAQ,MAAM,EAAE,OAAO,4BAA4B,GAAG,0BAA0B;AAChF;AAAA,EACF;AACA,MAAI,OAAO,SAAS;AAClB,UAAM,eAAe;AAAA,MACnB,WAAW,KAAK,IAAI;AAAA,MACpB,eAAe,OAAO,QAAQ;AAAA,MAC9B,MAAM,OAAO;AAAA,IACf,CAAC;AACD,YAAQ;AAAA,MACN,EAAE,OAAO,wBAAwB,eAAe,OAAO,QAAQ,QAAQ;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,oBAAiC;AACxC,SAAO,uBAAuB,WAAW;AAC3C;AAEA,SAAS,aAAsB;AAC7B,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,QAAQ,QAAQ,YAAY;AAG3C,QAAI,QAAQ,UAAU,yBAAyB,OAAO,QAAQ;AAC5D,aAAO,CAAC,OAAO,OAAO;AAAA,IACxB;AAAA,EACF,QAAQ;AAAA,EAER;AACA,MAAI;AACF,QAAI,WAAW,qBAAqB,GAAG;AACrC,aAAO;AAAA,IACT;AACA,UAAM,MAAM,aAAa,OAAO,CAAC,WAAW,GAAG;AAAA,MAC7C,UAAU;AAAA,MACV,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,SAAS;AAAA,IACX,CAAC;AACD,WAAO,QAAQ,KAAK,GAAG;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,eAAe,KAAa,MAAc,SAAgC;AACvF,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,SAAS,EAAE,cAAc,UAAU,OAAO,EAAE;AAAA,IAC5C,UAAU;AAAA,IACV,QAAQ,YAAY,QAAQA,sBAAqB,EAAE;AAAA,EACrD,CAAC;AACD,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAClC,UAAM,IAAI,MAAM,oBAAoB,SAAS,MAAM,SAAS,GAAG,EAAE;AAAA,EACnE;AACA,QAAM,UAAU,MAAM,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC,CAAC;AACpE;AAEA,eAAe,WAAW,MAA+B;AACvD,SAAO,WAAW,QAAQ,EACvB,OAAO,MAAM,SAAS,IAAI,CAAC,EAC3B,OAAO,KAAK;AACjB;AAEA,eAAe,eACb,SACA,WACA,MACA,SACe;AACf,QAAM,OAAO,QAAQ,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,UAAU;AACrE,MAAI,CAAC,MAAM;AAET,UAAM,IAAI;AAAA,MACR,WAAW,QAAQ,GAAG,WAAW,UAAU;AAAA,IAC7C;AAAA,EACF;AACA,QAAM,WAAW,MAAM,MAAM,KAAK,KAAK;AAAA,IACrC,SAAS,EAAE,cAAc,UAAU,OAAO,EAAE;AAAA,IAC5C,UAAU;AAAA,IACV,QAAQ,YAAY,QAAQA,mBAAkB;AAAA,EAChD,CAAC;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,sBAAsB,UAAU,KAAK,SAAS,MAAM,IAAI;AAAA,EAC1E;AACA,QAAM,WAAW,YAAY,MAAM,SAAS,KAAK,GAAG,SAAS;AAC7D,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,mBAAmB,SAAS,OAAO,UAAU,GAAG;AAAA,EAClE;AACA,QAAM,SAAS,MAAM,WAAW,IAAI;AACpC,MAAI,OAAO,YAAY,MAAM,UAAU;AACrC,UAAM,IAAI,MAAM,yBAAyB,SAAS,cAAc,QAAQ,SAAS,MAAM,GAAG;AAAA,EAC5F;AACF;AAEA,SAAS,WAAW,SAAiB,SAAuB;AAC1D,MAAI,QAAQ,aAAa,SAAS;AAEhC,UAAM,SAAS,GAAG,OAAO;AACzB,QAAI;AACF,aAAO,QAAQ,EAAE,OAAO,KAAK,CAAC;AAAA,IAChC,QAAQ;AAAA,IAER;AACA,IAAAG,YAAW,SAAS,MAAM;AAC1B,UAAM,UAAU,MAAM;AACpB,UAAI;AACF,QAAAA,YAAW,QAAQ,OAAO;AAAA,MAC5B,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI;AACF,MAAAA,YAAW,SAAS,OAAO;AAAA,IAC7B,SAAS,OAAO;AACd,UAAK,MAAgC,SAAS,SAAS;AACrD,YAAI;AACF,uBAAa,SAAS,OAAO;AAAA,QAC/B,SAAS,WAAW;AAClB,kBAAQ;AACR,gBAAM;AAAA,QACR;AAAA,MACF,OAAO;AACL,gBAAQ;AACR,cAAM;AAAA,MACR;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI;AACF,IAAAA,YAAW,SAAS,OAAO;AAAA,EAC7B,SAAS,OAAO;AACd,UAAM,OAAQ,MAAgC;AAC9C,QAAI,SAAS,SAAS;AACpB,mBAAa,SAAS,OAAO;AAC7B,MAAAC,WAAU,SAAS,GAAK;AAAA,IAC1B,WAAW,SAAS,YAAY,SAAS,SAAS;AAChD,YAAM,IAAI;AAAA,QACR,2BAA2B,OAAO;AAAA,MACpC;AAAA,IACF,OAAO;AACL,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAGO,SAAS,mBAAyB;AACvC,MAAI,CAAC,uBAAuB,QAAQ,UAAU,oBAAoB,GAAG;AACnE;AAAA,EACF;AACA,MAAI;AACF,WAAO,GAAG,aAAa,QAAQ,QAAQ,CAAC,QAAQ,EAAE,OAAO,KAAK,CAAC;AAAA,EACjE,QAAQ;AAAA,EAER;AACF;AAGA,eAAsB,UAAU,gBAAwB,QAAwC;AAC9F,mBAAiB;AACjB,QAAM,OAAO,kBAAkB;AAC/B,UAAQ,MAAM,EAAE,gBAAgB,OAAO,kBAAkB,aAAa,KAAK,GAAG,gBAAgB;AAE9F,MAAI,SAAS,UAAU;AACrB,YAAQ,IAAI,YAAY,cAAc,yBAAyB;AAC/D,YAAQ,IAAI,gBAAgB,kBAAkB,KAAK,CAAC,EAAE;AACtD;AAAA,EACF;AAEA,UAAQ,IAAI,YAAY,cAAc,iCAA4B;AAClE,QAAM,SAAS,MAAM,YAAY,cAAc;AAC/C,QAAM,UAAU,QAAQ,WAAW;AACnC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,MAAI,CAAC,WAAW,gBAAgB,QAAQ,OAAO,GAAG;AAChD,YAAQ;AAAA,MACN,EAAE,gBAAgB,OAAO,0BAA0B,eAAe,QAAQ,QAAQ;AAAA,MAClF;AAAA,IACF;AACA,YAAQ,IAAI,+BAA+B,QAAQ,OAAO,IAAI;AAC9D;AAAA,EACF;AAEA,QAAM,SAAS,gBAAgB,eAAe,QAAQ,UAAU,QAAQ,MAAM,WAAW,CAAC;AAC1F,QAAM,YAAY,aAAa,MAAM;AACrC,QAAM,QAAQ,QAAQ,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,SAAS;AACrE,MAAI,CAAC,OAAO;AACV,UAAM,YAAY,QAAQ,OAAO,IAAI,CAAC,UAAU,MAAM,IAAI,EAAE,KAAK,IAAI,KAAK;AAC1E,UAAM,IAAI,MAAM,WAAW,QAAQ,GAAG,kBAAkB,SAAS,iBAAiB,SAAS,GAAG;AAAA,EAChG;AAEA,UAAQ,IAAI,YAAY,cAAc,WAAM,QAAQ,OAAO,KAAK,SAAS,MAAM;AAC/E,UAAQ;AAAA,IACN;AAAA,MACE;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,eAAe,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,aAAa,QAAQ,QAAQ;AAC7C,QAAM,UAAUH,MAAKI,SAAQ,OAAO,GAAG,oBAAoB,QAAQ,GAAG,MAAM;AAC5E,MAAI;AACF,UAAM,eAAe,MAAM,KAAK,SAAS,cAAc;AACvD,UAAM,eAAe,SAAS,WAAW,SAAS,cAAc;AAChE,QAAI,QAAQ,aAAa,SAAS;AAChC,MAAAD,WAAU,SAAS,GAAK;AAAA,IAC1B;AACA,eAAW,SAAS,OAAO;AAAA,EAC7B,SAAS,OAAO;AACd,UAAM,OAAQ,MAAgC;AAC9C,QAAI,SAAS,YAAY,SAAS,SAAS;AACzC,YAAM,IAAI;AAAA,QACR,2BAA2B,OAAO;AAAA,MACpC;AAAA,IACF;AACA,UAAM;AAAA,EACR,UAAE;AACA,QAAI;AACF,aAAO,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,IACjC,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,UAAQ,IAAI,uBAAuB,QAAQ,OAAO,GAAG;AACrD,UAAQ;AAAA,IACN,EAAE,gBAAgB,OAAO,oBAAoB,eAAe,QAAQ,QAAQ;AAAA,IAC5E;AAAA,EACF;AACA,MAAI,QAAQ,aAAa,SAAS;AAChC,YAAQ,IAAI,0CAA0C;AAAA,EACxD;AACF;;;AV5WA,eAAsB,KAAK,OAAO,IAAI,KAAK,MAAM,CAAC,GAAkB;AAElE,mBAAiB;AAEjB,QAAM,UAAU,KAAK,CAAC;AACtB,MAAI,YAAY,YAAY,YAAY,WAAW;AACjD,UAAME,QAAO,eAAe,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC;AACpD,QAAIA,MAAK,MAAM;AACb,cAAQ,IAAI,SAAS,MAAM,WAAW,CAAC,CAAC;AACxC;AAAA,IACF;AACA,UAAMC,UAAS,cAAcD,OAAM,OAAO;AAC1C,UAAM,UAAU,MAAM,WAAW,GAAGC,OAAM;AAC1C;AAAA,EACF;AACA,MAAI,YAAY,SAAS;AACvB,UAAMD,QAAO,eAAe,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC;AACpD,QAAIA,MAAK,MAAM;AACb,cAAQ,IAAI,SAAS,MAAM,WAAW,CAAC,CAAC;AACxC;AAAA,IACF;AACA,IAAAA,MAAK,SAAS,cAAcA,OAAM,OAAO;AACzC,UAAM,SAASA,KAAI;AACnB;AAAA,EACF;AACA,MAAI,YAAY,UAAU;AACxB,UAAMA,QAAO,eAAe,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC;AACpD,QAAIA,MAAK,MAAM;AACb,cAAQ,IAAI,SAAS,MAAM,WAAW,CAAC,CAAC;AACxC;AAAA,IACF;AACA,IAAAA,MAAK,SAAS,cAAcA,OAAM,QAAQ;AAC1C,UAAM,UAAUA,KAAI;AACpB;AAAA,EACF;AACA,MAAI,YAAY,SAAS;AACvB,UAAMA,QAAO,eAAe,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC;AACpD,QAAIA,MAAK,MAAM;AACb,cAAQ,IAAI,SAAS,MAAM,WAAW,CAAC,CAAC;AACxC;AAAA,IACF;AACA,IAAAA,MAAK,SAAS,cAAcA,OAAM,OAAO;AACzC,UAAM,SAASA,KAAI;AACnB;AAAA,EACF;AAEA,QAAM,OAAO,eAAe,UAAU,IAAI,CAAC;AAC3C,MAAI,KAAK,MAAM;AACb,YAAQ,IAAI,SAAS,MAAM,WAAW,CAAC,CAAC;AACxC;AAAA,EACF;AACA,MAAI,KAAK,SAAS;AAChB,YAAQ,IAAI,MAAM,WAAW,CAAC;AAC9B;AAAA,EACF;AAEA,QAAM,SAAS,cAAc,MAAM,OAAO;AAC1C,OAAK,SAAS;AACd,QAAM,UAAU,oBAAoB,IAAI;AACxC,SAAO;AAAA,IACL;AAAA,MACE,SAAS,GAAG,QAAQ,GAAG;AAAA,MACvB,OAAO;AAAA,MACP,KAAK,QAAQ;AAAA,IACf;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,eAAe;AAKvB,SAAK;AAAA,MACH,MAAM,WAAW;AAAA,MACjB,uBAAuB,WAAW;AAAA,MAClC,OAAO,MAAM,EAAE,WAAW,SAAS,CAAC;AAAA,IACtC;AAAA,EACF;AACF;AAEO,SAAS,UAAU,MAA4B;AACpD,QAAM,OAAmB,CAAC;AAC1B,QAAM,OAAO,CAAC,GAAG,IAAI;AACrB,MAAI,KAAK,CAAC,MAAM,SAAS;AACvB,SAAK,MAAM;AAAA,EACb;AAEA,SAAO,KAAK,SAAS,GAAG;AACtB,UAAM,MAAM,KAAK,MAAM;AACvB,QAAI,CAAC,KAAK;AACR;AAAA,IACF;AACA,QAAI,QAAQ,YAAY,QAAQ,MAAM;AACpC,WAAK,OAAO;AACZ;AAAA,IACF;AACA,QAAI,QAAQ,eAAe,QAAQ,MAAM;AACvC,WAAK,UAAU;AACf;AAAA,IACF;AACA,QAAI,QAAQ,2BAA2B;AACrC,WAAK,uBAAuB;AAC5B;AAAA,IACF;AACA,QAAI,QAAQ,qBAAqB;AAC/B,WAAK,gBAAgB;AACrB;AAAA,IACF;AAEA,UAAM,CAAC,MAAM,WAAW,IAAI,IAAI,MAAM,KAAK,CAAC;AAC5C,UAAM,QAAQ,eAAe,KAAK,MAAM;AACxC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,qBAAqB,GAAG,GAAG;AAAA,IAC7C;AAEA,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,aAAK,SAAS;AACd;AAAA,MACF,KAAK;AACH,aAAK,gBAAgB;AACrB;AAAA,MACF,KAAK;AACH,aAAK,oBAAoB;AACzB;AAAA,MACF,KAAK;AACH,aAAK,YAAY,eAAe,KAAK;AACrC;AAAA,MACF,KAAK;AACH,aAAK,WAAW,cAAc,KAAK;AACnC;AAAA,MACF,KAAK;AACH,aAAK,OAAO;AACZ;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,aAAK,OAAO,OAAO,KAAK;AACxB,YAAI,CAAC,OAAO,UAAU,KAAK,IAAI,KAAK,KAAK,QAAQ,GAAG;AAClD,gBAAM,IAAI,MAAM,iBAAiB,KAAK,GAAG;AAAA,QAC3C;AACA;AAAA,MACF;AACE,cAAM,IAAI,MAAM,mBAAmB,IAAI,GAAG;AAAA,IAC9C;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAe,SAAS,UAAiC,CAAC,GAAkB;AAC1E,QAAM,SAAS,QAAQ,QAAQ,MAAM,EAAE,WAAW,OAAO,CAAC,KAAK;AAC/D,SAAO,MAAM,EAAE,OAAO,qBAAqB,GAAG,uCAAuC;AACrF,UAAQ,IAAI,0CAA0C;AACtD,QAAM,QAAQ,MAAM,yBAAyB;AAAA,IAC3C,KAAK,QAAQ;AAAA,IACb,QAAQ;AAAA,IACR,aAAa;AAAA,EACf,CAAC;AAED,UAAQ,IAAI,mCAAmC;AAC/C,QAAM,SAAS,MAAM,wBAAwB,MAAM,OAAO,OAAO;AACjE,SAAO;AAAA,IACL,EAAE,YAAY,OAAO,YAAY,OAAO,sBAAsB;AAAA,IAC9D;AAAA,EACF;AACA,QAAM,OAAO,QAAQ,iBAAiB,cAAc,QAAQ,GAAG;AAC/D;AAAA,IACE;AAAA,MACE,YAAY,OAAO;AAAA,MACnB,cAAc,MAAM;AAAA,MACpB,QAAQ;AAAA,MACR,OAAO,MAAM;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACA,SAAO,MAAM,EAAE,eAAe,MAAM,OAAO,oBAAoB,GAAG,2BAA2B;AAC7F,UAAQ,IAAI,sCAAsC,IAAI,EAAE;AACxD,UAAQ,IAAI,+BAA+B;AAC7C;AAEA,eAAsB,UAAU,UAAiC,CAAC,GAAsB;AACtF,QAAM,SAAS,QAAQ,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC,KAAK;AACjE,SAAO,MAAM,EAAE,OAAO,sBAAsB,GAAG,gCAAgC;AAE/E,QAAM,WAAW,MAAM,IAAI,cAAc,OAAO,EAAE,OAAO;AACzD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,UAAU,6CACd,SAAS,MACX,KAAK,MAAM,sBAAsB,QAAQ,CAAC;AAC1C,QAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,YAAM,IAAI,iBAAiB,OAAO;AAAA,IACpC;AACA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,QAAM,MAAM,qBAAqB,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,MAAS,CAAC;AAC7E,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,SAAO;AAAA,IACL,EAAE,OAAO,IAAI,QAAQ,OAAO,wBAAwB;AAAA,IACpD;AAAA,EACF;AACA,aAAW,MAAM,KAAK;AACpB,YAAQ,IAAI,EAAE;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAsB,SAAS,UAAiC,CAAC,GAA0B;AACzF,QAAM,SAAS,QAAQ,QAAQ,MAAM,EAAE,WAAW,QAAQ,CAAC,KAAK;AAChE,SAAO,MAAM,EAAE,OAAO,sBAAsB,GAAG,+BAA+B;AAE9E,QAAM,WAAW,MAAM,IAAI,cAAc,OAAO,EAAE,MAAM;AACxD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,UAAU,4CACd,SAAS,MACX,KAAK,MAAM,sBAAsB,QAAQ,CAAC;AAC1C,QAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,YAAM,IAAI,iBAAiB,OAAO;AAAA,IACpC;AACA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,QAAM,QAAQ,sBAAsB,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC;AAC3E,SAAO;AAAA,IACL,EAAE,OAAO,yBAAyB,MAAM,MAAM,KAAK;AAAA,IACnD;AAAA,EACF;AACA,aAAW,QAAQ,mBAAmB,KAAK,GAAG;AAC5C,YAAQ,IAAI,IAAI;AAAA,EAClB;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,OAA+B;AACzD,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM,MAAM;AACd,UAAM,KAAK,SAAS,MAAM,IAAI,EAAE;AAAA,EAClC;AACA,MAAI,MAAM,gBAAgB;AACxB,UAAM,KAAK,iBAAiB,MAAM,cAAc,EAAE;AAAA,EACpD;AAEA,QAAM,QAAQ,CAAC,wBAAwB,QAAQ,aAAa;AAC5D,QAAM,QAAQ,OAAO,KAAK,MAAM,MAAM,EAAE;AAAA,IACtC,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC,IAAI,UAAU,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC;AAAA,EAC1E;AACA,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,MAAM,OAAO,IAAI;AAC/B,QAAI,OAAO;AACT,YAAM,KAAK,GAAG,WAAW,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE;AAAA,IACzD;AAAA,EACF;AACA,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,KAAK,iEAAiE;AAAA,EAC9E;AACA,SAAO;AACT;AAEA,SAAS,UAAU,OAAiB,MAAsB;AACxD,QAAM,QAAQ,MAAM,QAAQ,IAAI;AAChC,SAAO,UAAU,KAAK,MAAM,SAAS;AACvC;AAEA,SAAS,WAAW,MAAsB;AACxC,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,YAAY,OAA6B;AAChD,MAAI,MAAM,WAAW;AACnB,WAAO;AAAA,EACT;AACA,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM,SAAS,UAAa,MAAM,gBAAgB,QAAW;AAC/D,UAAM,KAAK,GAAG,WAAW,MAAM,IAAI,CAAC,IAAI,WAAW,MAAM,WAAW,CAAC,OAAO;AAAA,EAC9E,WAAW,MAAM,cAAc,QAAW;AACxC,UAAM,KAAK,GAAG,WAAW,MAAM,SAAS,CAAC,YAAY;AAAA,EACvD;AACA,MAAI,MAAM,qBAAqB,QAAW;AACxC,UAAM,KAAK,GAAG,WAAW,MAAM,gBAAgB,CAAC,aAAa;AAAA,EAC/D;AACA,MAAI,MAAM,cAAc;AACtB,UAAM,KAAK,GAAG,WAAW,MAAM,YAAY,CAAC,UAAU;AAAA,EACxD;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;AAEA,SAAS,WAAW,OAAuB;AACzC,SAAO,OAAO,UAAU,KAAK,IAAI,QAAQ,KAAK,MAAM,QAAQ,EAAE,IAAI;AACpE;AAEA,eAAsB,wBACpB,OACA,UAA0C,CAAC,GACnB;AACxB,QAAM,aAAa;AAAA,IACjB,QAAQ,qBAAqB,QAAQ,KAAK,wBAAwB;AAAA,EACpE;AACA,QAAM,UAAU,QAAQ,SAAS;AACjC,QAAM,WAAW,MAAM,QAAQ,GAAG,UAAU,WAAW;AAAA,IACrD,SAAS,oBAAoB,IAAI,QAAQ,GAAG,KAAK;AAAA,IACjD,QAAQ;AAAA,EACV,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,UAAU,+CACd,SAAS,MACX,KAAK,MAAM,sBAAsB,QAAQ,CAAC;AAC1C,QAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,YAAM,IAAI,iBAAiB,OAAO;AAAA,IACpC;AACA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,KAAK,IAAI,IAAI,KAAK;AAAA,IAC/B,QAAQ;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,sBAAsB,KAAmB;AAChD,QAAM,WAAW,QAAQ;AACzB,QAAM,UAAU,aAAa,UAAU,QAAQ,aAAa,WAAW,SAAS;AAChF,QAAM,OAAO,aAAa,UAAU,CAAC,MAAM,SAAS,IAAI,GAAG,IAAI,CAAC,GAAG;AACnE,MAAI;AACF,UAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,MACjC,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AACD,UAAM,MAAM;AAAA,EACd,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,qBAAqB,MAAyB;AACrD,QAAM,SAAS,SAAS,IAAI;AAC5B,QAAM,OAAO,MAAM,QAAQ,OAAO,IAAI,IAAI,OAAO,OAAO,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC;AACtF,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAgB,CAAC;AACvB,aAAW,SAAS,MAAM;AACxB,UAAM,KAAK,SAAS,KAAK,EAAE;AAC3B,QAAI,OAAO,OAAO,YAAY,GAAG,WAAW,KAAK,KAAK,IAAI,EAAE,GAAG;AAC7D;AAAA,IACF;AACA,SAAK,IAAI,EAAE;AACX,QAAI,KAAK,EAAE;AAAA,EACb;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAA8B;AACpD,SAAO,EAAE,GAAG,MAAM,KAAK,QAAQ,IAAI;AACrC;AAEA,SAAS,cAAc,MAAkB,SAAiC;AACxE,SAAO,qBAAqB;AAAA,IAC1B,KAAK,KAAK;AAAA,IACV,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK;AAAA,EACd,CAAC,EAAE,MAAM,EAAE,SAAS,WAAW,MAAM,CAAC;AACxC;AAEA,SAAS,SAAS,SAAyB;AACzC,SAAO,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+C5B;AAEA,IAAI,YAAY,MAAM;AACpB,OAAK,EAAE,MAAM,CAAC,UAAmB;AAC/B,YAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACpE,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","names":["chmodSync","mkdirSync","renameSync","dirname","join","homedir","join","base","REQUEST_TIMEOUT_MS","join","mkdirSync","renameSync","chmodSync","dirname","args","logger"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/auth-store.ts","../src/util.ts","../src/auth.ts","../src/copilot.ts","../src/github-device.ts","../src/logger.ts","../src/openai.ts","../src/metrics.ts","../src/server.ts","../src/update.ts","../src/update-core.ts","../src/version.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 } from \"./auth\";\nimport { authStorePath, writeStoredCopilotAuth } from \"./auth-store\";\nimport { main as codexxMain } from \"./codexx\";\nimport { applyCopilotHeaders, CopilotClient, normalizeCopilotUsage } from \"./copilot\";\nimport { githubCopilotDeviceLogin } 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 HoopilotLogger,\n HoopilotServerOptions,\n} from \"./types\";\nimport { cleanupOldBinary, maybeNotifyUpdate, runUpdate } from \"./update\";\nimport { asRecord, isHttpsOrLoopbackUrl, trimTrailingSlash, truncatedResponseText } from \"./util\";\nimport { getVersion, IS_STANDALONE_BINARY } from \"./version\";\n\ninterface ParsedArgs extends HoopilotServerOptions {\n help?: boolean;\n noUpdateCheck?: boolean;\n version?: 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 (args.help) {\n console.log(helpText(await getVersion()));\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 (args.help) {\n console.log(helpText(await getVersion()));\n return;\n }\n args.logger = commandLogger(args, \"login\");\n await runLogin(args);\n return;\n }\n if (command === \"models\") {\n const args = withRuntimeEnv(parseArgs(argv.slice(1)));\n if (args.help) {\n console.log(helpText(await getVersion()));\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 (args.help) {\n console.log(helpText(await getVersion()));\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 (args.help) {\n console.log(helpText(await getVersion()));\n return;\n }\n if (args.version) {\n console.log(await getVersion());\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\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\n const [name, inlineValue] = splitOption(arg);\n const value = inlineValue ?? rest.shift();\n if (!value) {\n throw new Error(`Missing value for ${arg}.`);\n }\n\n switch (name) {\n case \"--api-key\":\n args.apiKey = value;\n break;\n case \"--api-key-file\":\n args.apiKey = readApiKeyFile(value);\n break;\n case \"--auth-file\":\n args.authStorePath = value;\n break;\n case \"--copilot-api-base-url\":\n args.copilotApiBaseUrl = value;\n break;\n case \"--log-format\":\n args.logFormat = parseLogFormat(value);\n break;\n case \"--log-level\":\n args.logLevel = parseLogLevel(value);\n break;\n case \"--host\":\n args.host = value;\n break;\n case \"--port\":\n case \"-p\":\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 default:\n throw new Error(`Unknown option: ${name}.`);\n }\n }\n\n return args;\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\nasync function runLogin(options: HoopilotServerOptions = {}): Promise<void> {\n const logger = options.logger?.child({ component: \"auth\" }) ?? noopLogger;\n logger.debug({ event: \"auth.login.started\" }, \"starting github copilot browser login\");\n console.log(\"Starting GitHub Copilot browser login...\");\n const login = await githubCopilotDeviceLogin({\n env: options.env,\n logger: console,\n openBrowser: openBrowserBestEffort,\n });\n\n console.log(\"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 console.log(`Copilot OAuth credential stored at ${path}`);\n console.log(\"Copilot authentication ready.\");\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 const message = `GitHub Copilot API model list failed with ${\n response.status\n }: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\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 const message = `GitHub Copilot usage request failed with ${\n response.status\n }: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\n }\n\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 return usage;\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 ?? options.env?.COPILOT_API_BASE_URL ?? DEFAULT_COPILOT_API_BASE_URL,\n );\n if (!isHttpsOrLoopbackUrl(apiBaseUrl)) {\n throw new Error(`Refusing to send the GitHub OAuth token to a non-HTTPS host: ${apiBaseUrl}`);\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 const message = `GitHub Copilot API verification failed with ${\n response.status\n }: ${await truncatedResponseText(response)}`;\n if (response.status === 401 || response.status === 403) {\n throw new CopilotAuthError(message);\n }\n throw new Error(message);\n }\n\n return {\n apiBaseUrl,\n expiresAtMs: Date.now() + 10 * 60_000,\n source: \"github-copilot-oauth\",\n token,\n };\n}\n\nfunction openBrowserBestEffort(url: string): 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 = spawn(command, args, {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n } catch {\n // The device login code and URL were already printed.\n }\n}\n\nfunction modelIdsFromResponse(body: unknown): string[] {\n const record = asRecord(body);\n const data = Array.isArray(record.data) ? record.data : Array.isArray(body) ? body : [];\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const model of data) {\n const id = asRecord(model).id;\n if (typeof id !== \"string\" || id.length === 0 || seen.has(id)) {\n continue;\n }\n seen.add(id);\n ids.push(id);\n }\n return ids;\n}\n\nfunction withRuntimeEnv(args: ParsedArgs): ParsedArgs {\n return { ...args, env: process.env };\n}\n\nfunction commandLogger(args: ParsedArgs, command: string): HoopilotLogger {\n return createHoopilotLogger({\n env: args.env,\n format: args.logFormat,\n level: args.logLevel,\n }).child({ command, component: \"cli\" });\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.\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 --log-level <level> trace, debug, info, warn, error, fatal, or silent\n --log-format <format> json or pretty. Default: pretty\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 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_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(error instanceof Error ? error.message : String(error));\n process.exit(1);\n });\n}\n","import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\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 if (env.HOOPILOT_AUTH_FILE) {\n return env.HOOPILOT_AUTH_FILE;\n }\n\n const base =\n env.XDG_CONFIG_HOME ??\n env.APPDATA ??\n (env.HOME ? join(env.HOME, \".config\") : join(process.cwd(), \".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 = parsed as Record<string, unknown>;\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 renameSync(tmpPath, path);\n try {\n chmodSync(path, 0o600);\n } catch {\n // chmod is best-effort on Windows.\n }\n}\n","import type { JsonObject } from \"./types\";\n\n/** Remove any trailing slashes from a URL or path string. */\nexport function trimTrailingSlash(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\n/** True for HTTPS URLs, or HTTP only on loopback hosts used by local tests/dev. */\nexport function isHttpsOrLoopbackUrl(rawUrl: string): boolean {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n return false;\n }\n if (url.protocol === \"https:\") {\n return true;\n }\n return (\n url.protocol === \"http:\" &&\n (url.hostname === \"127.0.0.1\" ||\n url.hostname === \"localhost\" ||\n url.hostname === \"::1\" ||\n url.hostname === \"[::1]\")\n );\n}\n\n/** Read a response body as text, truncated to keep error messages bounded. */\nexport async function truncatedResponseText(response: Response, max = 500): Promise<string> {\n const text = await response.text();\n return text.slice(0, max);\n}\n\n/** Narrow an unknown value to a plain object, returning {} for arrays/primitives/null. */\nexport function asRecord(value: unknown): JsonObject {\n return value && typeof value === \"object\" && !Array.isArray(value) ? (value as JsonObject) : {};\n}\n","import {\n readStoredCopilotAuth,\n type StoredCopilotAuth,\n StoredCopilotAuthError,\n} from \"./auth-store\";\nimport type { CopilotAccess, CopilotAuthOptions } from \"./types\";\nimport { trimTrailingSlash } from \"./util\";\n\nexport const DEFAULT_COPILOT_API_BASE_URL = \"https://api.githubcopilot.com\";\nconst REFRESH_SKEW_MS = 60_000;\nconst 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 #cachedAccess?: CopilotAccess;\n\n constructor(options: CopilotAuthOptions = {}) {\n this.#authStorePath = options.authStorePath ?? options.env?.HOOPILOT_AUTH_FILE;\n this.#copilotApiBaseUrl = trimTrailingSlash(\n options.copilotApiBaseUrl ??\n options.env?.COPILOT_API_BASE_URL ??\n 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 return this.#cacheAccess({\n apiBaseUrl: trimTrailingSlash(stored.apiBaseUrl ?? this.#copilotApiBaseUrl),\n expiresAtMs: Date.now() + STORED_TOKEN_TTL_MS,\n source: \"github-copilot-oauth\",\n token: stored.token,\n });\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 #cacheAccess(access: CopilotAccess): CopilotAccess {\n this.#cachedAccess = access;\n return access;\n }\n}\n","import { CopilotAuth } from \"./auth\";\nimport type {\n CopilotAuthOptions,\n CopilotQuota,\n CopilotUsage,\n FetchLike,\n JsonObject,\n} from \"./types\";\nimport { asRecord, isHttpsOrLoopbackUrl, trimTrailingSlash } 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\";\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/**\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\", \"hoopilot/0.1.0\");\n headers.set(\"editor-version\", \"Hoopilot/0.1.0\");\n headers.set(\"openai-intent\", \"conversation-panel\");\n headers.set(\"user-agent\", \"hoopilot/0.1.0\");\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\", \"hoopilot/0.1.0\");\n headers.set(\"editor-version\", \"Hoopilot/0.1.0\");\n headers.set(\"user-agent\", \"hoopilot/0.1.0\");\n headers.set(\"x-github-api-version\", COPILOT_USAGE_API_VERSION);\n return headers;\n}\n\nexport class CopilotClient {\n readonly #auth: CopilotAuth;\n readonly #fetch: FetchLike;\n readonly #githubApiBaseUrl: string;\n\n constructor(options: CopilotAuthOptions = {}) {\n this.#auth = new CopilotAuth(options);\n this.#fetch = options.fetch ?? fetch;\n this.#githubApiBaseUrl = trimTrailingSlash(\n options.githubApiBaseUrl ??\n options.env?.HOOPILOT_GITHUB_API_BASE_URL ??\n DEFAULT_GITHUB_API_BASE_URL,\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 (!isHttpsOrLoopbackUrl(this.#githubApiBaseUrl)) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to a non-HTTPS host: ${this.#githubApiBaseUrl}`,\n );\n }\n const access = await this.#auth.getAccess();\n const headers = applyGithubApiHeaders(new Headers(), access.token);\n return this.#fetch(`${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 (!isHttpsOrLoopbackUrl(access.apiBaseUrl)) {\n throw new Error(\n `Refusing to send the GitHub OAuth token to a non-HTTPS host: ${access.apiBaseUrl}`,\n );\n }\n const headers = applyCopilotHeaders(new Headers(init.headers), access.token);\n\n return this.#fetch(`${access.apiBaseUrl}${path}`, {\n ...init,\n headers,\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] = removeUndefinedQuota({\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 removeUndefinedUsage({\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 remaining =\n numberOrUndefined(detail.remaining) ?? numberOrUndefined(detail.quota_remaining);\n return removeUndefinedQuota({\n entitlement,\n overageCount: numberOrUndefined(detail.overage_count),\n overagePermitted:\n typeof detail.overage_permitted === \"boolean\" ? detail.overage_permitted : undefined,\n percentRemaining: numberOrUndefined(detail.percent_remaining),\n remaining,\n unlimited: typeof detail.unlimited === \"boolean\" ? detail.unlimited : undefined,\n used: usedFrom(entitlement, remaining),\n });\n}\n\nfunction usedFrom(\n entitlement: number | undefined,\n remaining: number | undefined,\n): number | undefined {\n if (entitlement === undefined || remaining === undefined) {\n return undefined;\n }\n return Math.max(0, entitlement - remaining);\n}\n\nfunction numberOrUndefined(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction stringOrUndefined(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction removeUndefinedQuota(quota: CopilotQuota): CopilotQuota {\n return Object.fromEntries(\n Object.entries(quota).filter(([, value]) => value !== undefined),\n ) as CopilotQuota;\n}\n\nfunction removeUndefinedUsage(usage: CopilotUsage): CopilotUsage {\n const entries = Object.entries(usage).filter(([, value]) => value !== undefined);\n return Object.fromEntries(entries) as unknown as CopilotUsage;\n}\n","import { setTimeout as sleep } from \"node:timers/promises\";\nimport type { FetchLike, Logger } from \"./types\";\nimport { 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 ?? env.HOOPILOT_GITHUB_DOMAIN ?? DEFAULT_GITHUB_DOMAIN,\n );\n const clientId =\n options.clientId ??\n env.HOOPILOT_GITHUB_CLIENT_ID ??\n 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 return value.replace(/^https?:\\/\\//, \"\").replace(/\\/+$/, \"\");\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 try {\n return JSON.parse(text) as T;\n } catch {\n throw new Error(`${context}: ${text.slice(0, 500)}`);\n }\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\";\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 ?? env.HOOPILOT_LOG_LEVEL);\n const format = parseLogFormat(options.format ?? 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 pino(\n pinoOptions,\n pretty({\n colorize: options.colorize ?? process.stderr.isTTY,\n destination: options.stream ?? 1,\n ignore: \"pid,hostname\",\n singleLine: true,\n translateTime: \"SYS:standard\",\n }),\n ) as HoopilotLogger;\n }\n\n if (options.stream) {\n return pino(pinoOptions, options.stream as pino.DestinationStream) as HoopilotLogger;\n }\n return pino(pinoOptions) as HoopilotLogger;\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 options.env?.HOOPILOT_LOG_FORMAT ||\n 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 type { JsonObject, TokenUsage } from \"./types\";\nimport { asRecord } from \"./util\";\n\nexport const DEFAULT_MODEL = \"gpt-4.1\";\n\ninterface ResponseStreamOptions {\n model: string;\n responseId?: string;\n}\n\ninterface AccumulatedToolCall {\n arguments: string;\n id: string;\n index: number;\n itemId?: string;\n name: string;\n outputIndex?: number;\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 return removeUndefined({\n max_tokens: request.max_tokens,\n messages: [{ content: promptToText(request.prompt), role: \"user\" }],\n model: normalizeRequestedModel(request.model),\n stream: request.stream === true,\n temperature: request.temperature,\n top_p: request.top_p,\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\nexport function chatCompletionToCompletion(completion: JsonObject): JsonObject {\n const choice = firstChoice(completion);\n const message = asRecord(choice.message);\n return removeUndefined({\n choices: [\n {\n finish_reason: choice.finish_reason ?? \"stop\",\n index: 0,\n logprobs: null,\n 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 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 sawDone = 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 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 processCompletionSseLine(line, enqueue, () => {\n sawDone = true;\n });\n }\n }\n if (buffer) {\n processCompletionSseLine(buffer, enqueue, () => {\n sawDone = true;\n });\n }\n if (!sawDone) {\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 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 ?? 0,\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 ?? 0,\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(\n (a, b) => (a.outputIndex ?? 0) - (b.outputIndex ?? 0),\n )) {\n const item = functionCallItem(tool);\n const outputIndex = tool.outputIndex ?? 0;\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): unknown[] {\n if (typeof input === \"string\") {\n return [{ content: input, role: \"user\" }];\n }\n if (!Array.isArray(input)) {\n return [];\n }\n\n const messages: unknown[] = [];\n for (const item of input) {\n const record = asRecord(item);\n if (record.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 (record.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 const role = roleToChatRole(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 return contentToText(content) || undefined;\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 }\n if (type === \"input_image\") {\n const imageUrl = contentToText(record.image_url);\n if (imageUrl) {\n parts.push({ image_url: { url: imageUrl }, type: \"image_url\" });\n }\n }\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 promptToText(prompt: unknown): string {\n if (Array.isArray(prompt)) {\n return prompt.map((item) => contentToText(item)).join(\"\\n\");\n }\n return contentToText(prompt);\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 roleToChatRole(role: string): string | undefined {\n if (role === \"assistant\" || role === \"developer\" || role === \"system\" || role === \"tool\") {\n return role === \"developer\" ? \"system\" : role;\n }\n return \"user\";\n}\n\nfunction chatTools(tools: unknown): unknown[] | undefined {\n if (!Array.isArray(tools)) {\n return undefined;\n }\n const converted = tools\n .map((tool) => asRecord(tool))\n .filter((tool) => tool.type === \"function\")\n .map((tool) => ({\n function: removeUndefined({\n description: tool.description,\n name: tool.name,\n parameters: tool.parameters,\n strict: tool.strict,\n }),\n type: \"function\",\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 if (record.type === \"function\" && typeof record.name === \"string\") {\n return { function: { name: record.name }, type: \"function\" };\n }\n return toolChoice;\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 index: output.length,\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 functionCallItem(\n tool: AccumulatedToolCall,\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 asRecord(record.prompt_tokens_details).cached_tokens,\n asRecord(record.input_tokens_details).cached_tokens,\n );\n return removeUndefined({\n cachedTokens: cached,\n completionTokens,\n promptTokens,\n reasoningTokens: reasoning,\n totalTokens: total ?? promptTokens + completionTokens,\n }) as unknown as TokenUsage;\n}\n\nfunction firstNumber(...values: unknown[]): number | undefined {\n for (const value of values) {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n }\n return undefined;\n}\n\nfunction firstChoice(completion: JsonObject): Record<string, unknown> {\n const choices = Array.isArray(completion.choices) ? completion.choices : [];\n return asRecord(choices[0]);\n}\n\nfunction processCompletionSseLine(\n line: string,\n enqueue: (data: JsonObject | \"[DONE]\") => void,\n markDone: () => void,\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) {\n return;\n }\n if (data === \"[DONE]\") {\n markDone();\n enqueue(\"[DONE]\");\n return;\n }\n\n const parsed = parseJson(data);\n if (!parsed) {\n return;\n }\n const choice = firstChoice(parsed);\n const delta = asRecord(choice.delta);\n const text = contentToText(delta.content);\n const finishReason = choice.finish_reason ?? null;\n const usage = asRecord(parsed.usage);\n const hasUsage = Object.keys(usage).length > 0;\n if (!text && finishReason === null && !hasUsage) {\n return;\n }\n\n enqueue(\n removeUndefined({\n choices:\n text || finishReason !== null\n ? [\n {\n finish_reason: finishReason,\n index: typeof choice.index === \"number\" ? choice.index : 0,\n logprobs: null,\n text,\n },\n ]\n : [],\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 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 = parseJson(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 parseJson(data: string): JsonObject | undefined {\n try {\n return asRecord(JSON.parse(data));\n } catch {\n return undefined;\n }\n}\n\nfunction removeUndefined(record: JsonObject): JsonObject {\n return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));\n}\n\nfunction randomId(): string {\n return crypto.randomUUID().replaceAll(\"-\", \"\");\n}\n\nfunction epochSeconds(): number {\n return Math.floor(Date.now() / 1000);\n}\n","import { extractTokenUsage } from \"./openai\";\nimport type {\n CopilotUsage,\n MetricsSnapshot,\n ModelTokenTotals,\n RequestObservation,\n TokenUsage,\n} from \"./types\";\nimport { asRecord } 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// 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\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 /** 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 // Sanitize the model into a bounded, control-char-free label. The model can\n // originate from a client request, so cap its length, strip characters that\n // would corrupt the exposition format, and fold overflow past the cardinality\n // limit into UNKNOWN_MODEL to keep the series count bounded.\n #modelLabel(model: string): string {\n const cleaned =\n model\n // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control chars is the intent.\n .replace(/[\\u0000-\\u001f\\u007f]/g, \"\")\n .trim()\n .slice(0, MAX_MODEL_LABEL_LENGTH) || UNKNOWN_MODEL;\n if (!this.#tokens.has(cleaned) && this.#tokens.size >= MAX_TRACKED_MODELS) {\n return UNKNOWN_MODEL;\n }\n return cleaned;\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 return {\n inFlight: this.#inFlight,\n requests: { byRoute, byStatus, total: requestsTotal },\n startedAt: new Date(this.#startedAtMs).toISOString(),\n tokens: { byModel, ...tokenTotals },\n upstream: { errors: upstreamErrors, total: upstreamTotal },\n uptimeSeconds: Math.max(0, Math.round((now() - this.#startedAtMs) / 1000)),\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(\"# 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.#renderCopilotQuota(lines);\n\n return `${lines.join(\"\\n\")}\\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: (typeof categories)[number][1]) => 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(\n \"percent_remaining\",\n \"Percent of quota remaining for the Copilot category.\",\n (q) => q.percentRemaining,\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}\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): 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).catch(() => {});\n return new Response(clientBranch, {\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n });\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): 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 let model = fallbackModel;\n let usage: TokenUsage | undefined;\n let buffer = \"\";\n let bufferedBytes = 0;\n let overflowed = false;\n\n const consider = (payload: unknown): void => {\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\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, 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, consider);\n }\n } else if (!overflowed && finalBuffer) {\n const parsed = safeParse(finalBuffer);\n if (parsed !== undefined) {\n consider(parsed);\n }\n }\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n reader.releaseLock();\n }\n\n if (usage) {\n onUsage(model, usage);\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 = safeParse(data);\n if (parsed !== undefined) {\n consider(parsed);\n }\n}\n\nfunction safeParse(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\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 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 { CopilotAuthError } from \"./auth\";\nimport { CopilotClient, normalizeCopilotUsage } from \"./copilot\";\nimport { createHoopilotLogger, errorDetails, noopLogger, shouldCreateLogger } from \"./logger\";\nimport { MetricsRegistry, observeResponseUsage, PROMETHEUS_CONTENT_TYPE } from \"./metrics\";\nimport {\n chatCompletionToCompletion,\n completionStreamFromChatStream,\n completionsRequestToChatCompletion,\n extractTokenUsage,\n fallbackModels,\n normalizeChatCompletionRequest,\n normalizeModelsResponse,\n normalizeRequestedModel,\n} from \"./openai\";\nimport type {\n CopilotUsage,\n HoopilotLogger,\n HoopilotServerOptions,\n JsonObject,\n LogFields,\n StartedHoopilotServer,\n TokenUsage,\n} from \"./types\";\nimport { asRecord } from \"./util\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 4141;\nconst FORBIDDEN_BROWSER_ORIGIN_MESSAGE =\n \"Browser-origin requests require HOOPILOT_API_KEY unless the Origin is loopback.\";\nconst INVALID_JSON_MESSAGE = \"Request body must be valid JSON.\";\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;\n\nexport function createHoopilotHandler(\n options: HoopilotServerOptions = {},\n): (request: Request) => Promise<Response> {\n const client = new CopilotClient(options);\n const apiKey = options.apiKey ?? options.env?.HOOPILOT_API_KEY;\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\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 finish = (response: Response): Response =>\n finishResponse(response, {\n logger: requestLogger,\n method: request.method,\n metrics,\n requestId,\n route,\n startedAt,\n });\n\n const browserOrigin = forbiddenBrowserOrigin(request, apiKey);\n if (browserOrigin) {\n requestLogger.warn(\n { event: \"http.request.forbidden_origin\", origin: browserOrigin },\n \"blocked unauthenticated browser-origin request\",\n );\n return finish(jsonError(403, \"forbidden_origin\", FORBIDDEN_BROWSER_ORIGIN_MESSAGE));\n }\n\n if (request.method === \"OPTIONS\") {\n return finish(new Response(null, { headers: corsHeaders() }));\n }\n\n if (!isAuthorized(request, apiKey)) {\n requestLogger.warn({ event: \"http.request.unauthorized\" }, \"invalid hoopilot api key\");\n return finish(jsonError(401, \"invalid_api_key\", \"Invalid or missing Hoopilot API key.\"));\n }\n\n try {\n if (request.method === \"GET\" && (apiPath === \"/\" || apiPath === \"/healthz\")) {\n return finish(jsonResponse({ name: \"hoopilot\", object: \"health\", status: \"ok\" }));\n }\n if (request.method === \"GET\" && apiPath === \"/metrics\") {\n return finish(metricsResponse(metrics));\n }\n if (request.method === \"GET\" && apiPath === \"/v1/usage\") {\n return finish(await handleUsage(metrics, readUsage, request.signal));\n }\n if (request.method === \"GET\" && apiPath === \"/v1/responses\") {\n return finish(websocketUnsupportedResponse());\n }\n if (request.method === \"GET\" && apiPath === \"/v1/models\") {\n return finish(await handleModels(client, metrics, request.signal, requestLogger));\n }\n if (request.method === \"POST\" && apiPath === \"/v1/chat/completions\") {\n return finish(\n await handleChatCompletions(client, metrics, recordTokens, request, requestLogger),\n );\n }\n if (request.method === \"POST\" && apiPath === \"/v1/completions\") {\n return finish(\n await handleCompletions(client, metrics, recordTokens, request, requestLogger),\n );\n }\n if (request.method === \"POST\" && apiPath === \"/v1/responses\") {\n return finish(await handleResponses(client, metrics, recordTokens, request, requestLogger));\n }\n return finish(jsonError(404, \"not_found\", `No route for ${request.method} ${url.pathname}.`));\n } catch (error) {\n if (error instanceof CopilotAuthError) {\n requestLogger.warn(\n { err: errorDetails(error), event: \"copilot.auth.missing\" },\n \"copilot auth failed\",\n );\n return finish(jsonError(401, \"copilot_auth_error\", error.message));\n }\n const message = errorMessage(error);\n if (message === INVALID_JSON_MESSAGE) {\n requestLogger.warn(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request body was invalid json\",\n );\n return finish(jsonError(400, \"invalid_request_error\", message));\n } else {\n requestLogger.error(\n { err: errorDetails(error), event: \"http.request.failed\" },\n \"request failed\",\n );\n }\n return finish(jsonError(500, \"internal_error\", message));\n }\n };\n}\n\nexport function startHoopilotServer(options: HoopilotServerOptions = {}): StartedHoopilotServer {\n const host = options.host ?? options.env?.HOST ?? DEFAULT_HOST;\n const port = normalizeServerPort(options.port ?? options.env?.PORT ?? DEFAULT_PORT);\n const apiKey = options.apiKey ?? options.env?.HOOPILOT_API_KEY;\n const allowUnauthenticated =\n options.allowUnauthenticated ?? options.env?.HOOPILOT_ALLOW_UNAUTHENTICATED === \"1\";\n\n if (!isLoopbackHost(host) && !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\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://${host}:${server.port}`,\n };\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 request: Request,\n logger: HoopilotLogger,\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(observeResponseUsage(upstream, model, recordTokens, request.signal));\n}\n\nasync function handleCompletions(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n request: Request,\n logger: HoopilotLogger,\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 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 ),\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 return jsonResponse(chatCompletionToCompletion(completion));\n}\n\nasync function handleResponses(\n client: CopilotClient,\n metrics: MetricsRegistry,\n recordTokens: TokenRecorder,\n request: Request,\n logger: HoopilotLogger,\n): Promise<Response> {\n const body = await readJsonText(request);\n const upstream = await client.responses(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 model = normalizeRequestedModel(asRecord(safeParseJson(body)).model);\n return proxyResponse(observeResponseUsage(upstream, model, recordTokens, request.signal));\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 try {\n return asRecord(await request.json());\n } catch {\n throw new Error(INVALID_JSON_MESSAGE);\n }\n}\n\nasync function readJsonText(request: Request): Promise<string> {\n const text = await request.text();\n try {\n JSON.parse(text);\n return text;\n } catch {\n throw new Error(INVALID_JSON_MESSAGE);\n }\n}\n\nfunction jsonResponse(body: JsonObject, 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 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(safeParseJson(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\nfunction corsHeaders(): Record<string, string> {\n return {\n \"access-control-allow-headers\": \"authorization, content-type, x-api-key\",\n \"access-control-allow-methods\": \"GET, POST, OPTIONS\",\n \"access-control-allow-origin\": \"*\",\n };\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 bearer === apiKey || request.headers.get(\"x-api-key\") === apiKey;\n}\n\nfunction forbiddenBrowserOrigin(request: Request, apiKey: string | undefined): string | undefined {\n if (apiKey) {\n return undefined;\n }\n\n const origin = request.headers.get(\"origin\")?.trim();\n if (origin) {\n return isLoopbackOrigin(origin) ? undefined : origin;\n }\n\n const fetchSite = request.headers.get(\"sec-fetch-site\")?.toLowerCase();\n return fetchSite === \"cross-site\" ? \"cross-site\" : 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 host === \"localhost\" || host === \"127.0.0.1\" || host === \"::1\" || host === \"[::1]\";\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 errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\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 finishResponse(\n response: Response,\n options: {\n logger: HoopilotLogger;\n method: string;\n metrics: MetricsRegistry;\n requestId: string;\n route: string;\n startedAt: number;\n },\n): Response {\n const withRequestId = responseWithRequestId(response, options.requestId);\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) {\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(response: Response, requestId: string): Response {\n const headers = new Headers(response.headers);\n headers.set(\"x-request-id\", requestId);\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 const fire = (): void => {\n if (!fired) {\n fired = true;\n onComplete();\n }\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 fire();\n return;\n }\n controller.enqueue(value);\n } catch (error) {\n fire();\n controller.error(error);\n }\n },\n cancel(reason) {\n fire();\n return reader.cancel(reason);\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 || 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 \"/responses\":\n return \"/v1/responses\";\n case \"/usage\":\n return \"/v1/usage\";\n default:\n return withoutTrailingSlash;\n }\n}\n\nfunction routeFor(method: string, path: string): string {\n if (method === \"OPTIONS\") {\n return \"cors.preflight\";\n }\n if (method === \"GET\" && (path === \"/\" || path === \"/healthz\")) {\n return \"health\";\n }\n if (method === \"GET\" && path === \"/metrics\") {\n return \"metrics\";\n }\n if (method === \"GET\" && path === \"/v1/usage\") {\n return \"usage\";\n }\n if (method === \"GET\" && path === \"/v1/models\") {\n return \"models\";\n }\n if (method === \"POST\" && path === \"/v1/chat/completions\") {\n return \"chat_completions\";\n }\n if (method === \"POST\" && path === \"/v1/completions\") {\n return \"completions\";\n }\n if (method === \"POST\" && path === \"/v1/responses\") {\n return \"responses\";\n }\n if (method === \"GET\" && path === \"/v1/responses\") {\n return \"responses_websocket\";\n }\n return \"not_found\";\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\nasync function handleUsage(\n metrics: MetricsRegistry,\n readUsage: UsageReader,\n signal: AbortSignal,\n): Promise<Response> {\n const proxy = metrics.snapshot();\n const { copilot, error } = await readUsage(signal);\n const body: JsonObject = { copilot: copilot ?? null, object: \"usage\", proxy };\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 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 metrics.recordUpstream(usagePath, false);\n if (error instanceof CopilotAuthError) {\n return { error: error.message };\n }\n return { error: errorMessage(error) };\n }\n };\n}\n\nfunction safeParseJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\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 { BAKED_TARGET, IS_STANDALONE_BINARY } from \"./version\";\n\nconst REQUEST_TIMEOUT_MS = 8_000;\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(REQUEST_TIMEOUT_MS * 10),\n });\n if (!response.ok || !response.body) {\n throw new Error(`Download failed (${response.status}) for ${url}`);\n }\n await writeFile(dest, new Uint8Array(await response.arrayBuffer()));\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(REQUEST_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\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\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 = JSON.parse(text) as Partial<UpdateState>;\n return {\n lastCheck: typeof data.lastCheck === \"number\" ? data.lastCheck : 0,\n latestVersion: typeof data.latestVersion === \"string\" ? data.latestVersion : null,\n etag: typeof data.etag === \"string\" ? data.etag : null,\n };\n } catch {\n return { lastCheck: 0, latestVersion: null, etag: null };\n }\n}\n\nexport interface LatestRelease {\n version: string;\n tag: string;\n assets: Array<{ name: string; url: string }>;\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<{ name: string; url: string }> = [];\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","// 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 = await Bun.file(new URL(\"../package.json\", import.meta.url)).json();\n resolved = typeof manifest.version === \"string\" ? manifest.version : \"0.0.0\";\n } catch {\n resolved = \"0.0.0\";\n }\n }\n cachedVersion = resolved;\n return resolved;\n}\n"],"mappings":"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","names":["readFileSync","chmodSync","mkdirSync","renameSync","writeFileSync","dirname","join","homedir","join","base","REQUEST_TIMEOUT_MS","join","mkdirSync","renameSync","chmodSync","writeFileSync","errorMessage","dirname","main","args","logger","readFileSync"]}