github-router 0.3.16 → 0.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -6
- package/dist/main.js +486 -121
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","FALLBACK","token","size: number","fs","process","child: ChildProcess","server","ENDPOINT_ALIASES: Record<string, Endpoint>","path","state","parts: Array<string>","x","headers: Record<string, string>","searchTimestamps: Array<number>","references: Array<{ title: string; url: string }>","handleCompletion","injectWebSearchIfNeeded","inputTokens: number | undefined","isNonStreaming","extractUserQuery","handleCompletion","headers: Record<string, string>","isWebSearchTool","body: AnyRecord","resolveModelInBody","extraHeaders: Record<string, string>","parsed: AnyRecord","sanitizeCacheControl","headers: Record<string, string>","extractUserQuery","body: AnyRecord","response: Response","streamHeaders: Record<string, string>","parsed: AnyRecord","headers: Record<string, string>","payload: ResponsesPayload","result: ResponsesApiResponse","app","srvxServer: ReturnType<typeof serve> | undefined","lastError: unknown","port: number | undefined","rateLimit: number | undefined","vars: Record<string, string>","process","server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]","serverUrl: string","resolvedModel: string | undefined","server","process","server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]","serverUrl: string","server","process","commandBlock: string"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-copilot-version.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/lib/file-log-reporter.ts","../src/lib/port.ts","../src/lib/launch.ts","../src/lib/model-validation.ts","../src/lib/proxy.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/request-log.ts","../src/lib/tokenizer.ts","../src/services/copilot/create-chat-completions.ts","../src/services/copilot/web-search.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/services/copilot/create-messages.ts","../src/routes/messages/count-tokens-handler.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/services/copilot/create-responses.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/search/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/lib/server-setup.ts","../src/claude.ts","../src/codex.ts","../src/debug.ts","../src/lib/shell.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nfunction appDir(): string {\n return path.join(os.homedir(), \".local\", \"share\", \"github-router\")\n}\n\nexport const PATHS = {\n get APP_DIR() {\n return appDir()\n },\n get GITHUB_TOKEN_PATH() {\n return path.join(appDir(), \"github_token\")\n },\n get ERROR_LOG_PATH() {\n return path.join(appDir(), \"error.log\")\n },\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import { randomBytes, randomUUID } from \"node:crypto\"\n\nimport type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n copilotApiUrl?: string\n models?: ModelsResponse\n vsCodeVersion?: string\n copilotVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n extendedBetas: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n\n // Persistent session identifiers to match VS Code fingerprint\n sessionId: string\n machineId: string\n}\n\nexport const state: State = {\n accountType: \"enterprise\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n extendedBetas: false,\n sessionId: randomUUID(),\n machineId: randomBytes(32).toString(\"hex\"),\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst DEFAULT_COPILOT_VERSION = \"0.43.2026033101\"\n\nfunction copilotVersion(state: State): string {\n return state.copilotVersion ?? DEFAULT_COPILOT_VERSION\n}\n\nconst API_VERSION = \"2025-10-01\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.copilotApiUrl ?? \"https://api.githubcopilot.com\"\nexport const copilotHeaders = (\n state: State,\n vision: boolean = false,\n integrationId: string = \"vscode-chat\",\n) => {\n const version = copilotVersion(state)\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": integrationId,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": `copilot-chat/${version}`,\n \"user-agent\": `GitHubCopilotChat/${version}`,\n \"openai-intent\": \"conversation-panel\",\n \"x-interaction-type\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n \"VScode-SessionId\": state.sessionId,\n \"VScode-MachineId\": state.machineId,\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL =\n process.env.GITHUB_API_URL ?? \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": `copilot-chat/${copilotVersion(state)}`,\n \"user-agent\": `GitHubCopilotChat/${copilotVersion(state)}`,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text().catch(() => \"\")\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = undefined\n }\n\n // Forward upstream Anthropic-format errors as-is\n if (isAnthropicError(errorJson)) {\n consola.error(\"HTTP error:\", errorJson)\n return c.json(errorJson, error.response.status as ContentfulStatusCode)\n }\n\n const message = resolveErrorMessage(errorJson, errorText)\n consola.error(\"HTTP error:\", errorJson ?? errorText)\n return c.json(\n {\n type: \"error\",\n error: {\n type: resolveErrorType(error.response.status),\n message,\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n type: \"error\",\n error: {\n type: \"api_error\",\n message: error instanceof Error ? error.message : String(error),\n },\n },\n 500,\n )\n}\n\n// Extracts error message from { message } or { error: { message } } payloads.\nfunction resolveErrorMessage(errorJson: unknown, fallback: string): string {\n if (typeof errorJson !== \"object\" || errorJson === null) return fallback\n\n const errorRecord = errorJson as Record<string, unknown>\n if (errorRecord.message !== undefined) return String(errorRecord.message)\n\n if (typeof errorRecord.error === \"object\" && errorRecord.error !== null) {\n const nestedRecord = errorRecord.error as Record<string, unknown>\n if (nestedRecord.message !== undefined) return String(nestedRecord.message)\n }\n\n return fallback\n}\n\n/**\n * Check if a parsed JSON body is already in Anthropic error format:\n * { type: \"error\", error: { type: \"...\", message: \"...\" } }\n */\nfunction isAnthropicError(json: unknown): boolean {\n if (typeof json !== \"object\" || json === null) return false\n const record = json as Record<string, unknown>\n if (record.type !== \"error\") return false\n if (typeof record.error !== \"object\" || record.error === null) return false\n const inner = record.error as Record<string, unknown>\n return typeof inner.type === \"string\" && typeof inner.message === \"string\"\n}\n\n/**\n * Map HTTP status to Anthropic error type.\n */\nfunction resolveErrorType(status: number): string {\n if (status === 400) return \"invalid_request_error\"\n if (status === 401) return \"authentication_error\"\n if (status === 403) return \"permission_error\"\n if (status === 404) return \"not_found_error\"\n if (status === 429) return \"rate_limit_error\"\n if (status === 529) return \"overloaded_error\"\n return \"api_error\"\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n const data = (await response.json()) as GetCopilotTokenResponse\n\n // Use the API base URL from the token response if available,\n // matching how VS Code determines the CAPI endpoint dynamically.\n if (data.endpoints?.api) {\n state.copilotApiUrl = data.endpoints.api\n }\n\n return data\n}\n\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n endpoints?: {\n api?: string\n proxy?: string\n telemetry?: string\n \"origin-tracker\"?: string\n }\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n max_non_streaming_output_tokens?: number\n vision?: {\n max_prompt_image_size?: number\n max_prompt_images?: number\n supported_media_types?: string[]\n }\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n streaming?: boolean\n vision?: boolean\n structured_outputs?: boolean\n adaptive_thinking?: boolean\n max_thinking_budget?: number\n min_thinking_budget?: number\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\nexport interface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n supported_endpoints?: Array<string>\n requestHeaders?: Record<string, string>\n policy?: {\n state: string\n terms: string\n }\n billing?: {\n is_premium: boolean\n multiplier: number\n restricted_to?: string[]\n }\n is_chat_default?: boolean\n is_chat_fallback?: boolean\n model_picker_category?: string\n info_messages?: Array<{ code: string; message: string }>\n}\n","const FALLBACK = \"0.43.2026033101\"\n\ninterface MarketplaceResult {\n results: Array<{\n extensions: Array<{\n versions: Array<{ version: string }>\n }>\n }>\n}\n\nexport async function getCopilotChatVersion(): Promise<string> {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery\",\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json;api-version=7.1-preview.1\",\n },\n body: JSON.stringify({\n filters: [\n {\n criteria: [{ filterType: 7, value: \"GitHub.copilot-chat\" }],\n },\n ],\n flags: 914,\n }),\n signal: controller.signal,\n },\n )\n\n if (!response.ok) return FALLBACK\n\n const data = (await response.json()) as MarketplaceResult\n const version =\n data?.results?.[0]?.extensions?.[0]?.versions?.[0]?.version\n\n return version ?? FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n","const FALLBACK = \"1.104.3\"\n\nexport async function getVSCodeVersion() {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n {\n signal: controller.signal,\n },\n )\n\n const pkgbuild = await response.text()\n const pkgverRegex = /pkgver=([0-9.]+)/\n const match = pkgbuild.match(pkgverRegex)\n\n if (match) {\n return match[1]\n }\n\n return FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getCopilotChatVersion } from \"~/services/get-copilot-version\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\n/**\n * Beta prefixes VS Code Copilot Chat v0.43 actually sends.\n * Default mode — makes proxy traffic indistinguishable from VS Code.\n */\nconst VSCODE_BETA_PREFIXES = [\n \"interleaved-thinking-\",\n \"context-management-\",\n \"advanced-tool-use-\",\n]\n\n/**\n * Extended beta prefixes for Claude CLI compatibility.\n * Enabled via --extended-betas flag. Includes all betas confirmed\n * to work with the Copilot API.\n *\n * Notably absent: output-128k- (Copilot returns 400).\n */\nconst EXTENDED_BETA_PREFIXES = [\n ...VSCODE_BETA_PREFIXES,\n \"claude-code-\",\n \"context-1m-\",\n \"effort-\",\n \"prompt-caching-\",\n \"computer-use-\",\n \"pdfs-\",\n \"max-tokens-\",\n \"token-counting-\",\n \"compact-\",\n \"structured-outputs-\",\n \"fast-mode-\",\n \"skills-\",\n \"mcp-client-\",\n \"mcp-servers-\",\n \"files-api-\",\n \"redact-thinking-\",\n \"web-search-\",\n]\n\n/**\n * Filter an `anthropic-beta` header value, keeping only beta flags\n * in the active whitelist. Uses extended prefixes when --extended-betas\n * is enabled, VS Code-only prefixes otherwise.\n * Returns the filtered comma-separated string, or undefined if nothing remains.\n */\nexport function filterBetaHeader(value: string): string | undefined {\n const prefixes = state.extendedBetas\n ? EXTENDED_BETA_PREFIXES\n : VSCODE_BETA_PREFIXES\n const filtered = value\n .split(\",\")\n .map((v) => v.trim())\n .filter(\n (v) =>\n v && prefixes.some((prefix) => v.startsWith(prefix)),\n )\n .join(\",\")\n return filtered || undefined\n}\n\n/**\n * Normalize a model ID for fuzzy comparison: lowercase, replace dots with\n * dashes, insert dash at letter→digit boundaries, and collapse repeated\n * dashes. E.g. \"gpt5.3-codex\" → \"gpt-5-3-codex\", \"GPT-5.3-Codex\" → \"gpt-5-3-codex\".\n */\nexport function normalizeModelId(id: string): string {\n return id\n .toLowerCase()\n .replace(/\\./g, \"-\")\n .replace(/([a-z])(\\d)/g, \"$1-$2\")\n .replace(/-{2,}/g, \"-\")\n}\n\n/**\n * Resolve a model name to the best available variant in the Copilot model list.\n *\n * Resolution cascade:\n * 1. Exact match\n * 2. Case-insensitive match\n * 3. Family preference (opus→1m, codex→highest version)\n * 4. Normalized match (dots→dashes, letter-digit boundaries)\n * 5. Return as-is with a warning\n */\nexport function resolveModel(modelId: string): string {\n const models = state.models?.data\n if (!models) return modelId\n\n // 1. Exact match\n if (models.some((m) => m.id === modelId)) return modelId\n\n // 2. Case-insensitive match\n const lower = modelId.toLowerCase()\n const ciMatch = models.find((m) => m.id.toLowerCase() === lower)\n if (ciMatch) return ciMatch.id\n\n // 3. Family preference — before normalization so product aliases\n // (opus→1m, codex→latest) take priority over fuzzy matches\n if (lower.includes(\"opus\")) {\n const oneM = models.find(\n (m) => m.id.includes(\"opus\") && m.id.endsWith(\"-1m\"),\n )\n if (oneM) return oneM.id\n }\n\n if (lower.includes(\"codex\")) {\n const codexModels = models.filter(\n (m) => m.id.includes(\"codex\") && !m.id.includes(\"mini\"),\n )\n if (codexModels.length > 0) {\n codexModels.sort((a, b) => b.id.localeCompare(a.id))\n return codexModels[0].id\n }\n }\n\n // 4. Normalized match (dots → dashes, letter-digit boundaries)\n const normalized = normalizeModelId(modelId)\n const normMatch = models.find(\n (m) => normalizeModelId(m.id) === normalized,\n )\n if (normMatch) return normMatch.id\n\n // 5. No match — warn and return as-is\n consola.warn(\n `Model \"${modelId}\" not found in Copilot model list. Available: ${models.map((m) => m.id).join(\", \")}`,\n )\n return modelId\n}\n\n/**\n * Resolve a codex model ID, falling back to the best available codex model.\n * Used by the codex subcommand for model selection.\n */\nexport function resolveCodexModel(modelId: string): string {\n const resolved = resolveModel(modelId)\n const models = state.models?.data\n if (!models) return resolved\n\n // Check if the resolved model exists in the model list\n if (models.some((m) => m.id === resolved)) return resolved\n\n // Fall back to the best available codex model\n const codexModels = models.filter((m) => {\n const endpoints = m.supported_endpoints ?? []\n return (\n m.id.includes(\"codex\")\n && !m.id.includes(\"mini\")\n && (endpoints.length === 0 || endpoints.includes(\"/responses\"))\n )\n })\n\n if (codexModels.length > 0) {\n codexModels.sort((a, b) => b.id.localeCompare(a.id))\n const best = codexModels[0].id\n consola.warn(`Model \"${modelId}\" not available, using \"${best}\" instead`)\n return best\n }\n\n return resolved\n}\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n\nexport const cacheCopilotVersion = async () => {\n const version = await getCopilotChatVersion()\n state.copilotVersion = version\n\n consola.info(`Using Copilot Chat version: ${version}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n const expiresAt = Date.now() + deviceCode.expires_in * 1000\n\n while (Date.now() < expiresAt) {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to poll access token:\", await response.text())\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n }\n\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n }\n\n throw new Error(\"Device code expired. Please run auth again.\")\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = Math.max((refresh_in - 60) * 1000, 1000)\n setInterval(async () => {\n consola.debug(\"Refreshing Copilot token\")\n try {\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n }\n }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(state),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","import fs from \"node:fs\"\nimport { Writable } from \"node:stream\"\n\nimport consola from \"consola\"\nimport type { ConsolaOptions, ConsolaReporter, LogObject } from \"consola\"\n\nimport { PATHS } from \"~/lib/paths\"\n\nconst MAX_LOG_BYTES = 1024 * 1024 // 1 MB\nconst DEDUP_MAX = 1000\nconst ARG_MAX_LEN = 2048\nconst DEDUP_KEY_MAX_LEN = 200\n\nconst CREDENTIAL_RE =\n /\\b(eyJ[A-Za-z0-9_-]{20,}(?:\\.[A-Za-z0-9_-]+){0,2}|gh[opsu]_[A-Za-z0-9_]{20,}|Bearer\\s+\\S{20,})\\b/g\n\nconst ALLOWED_TYPES = new Set([\"fatal\", \"error\", \"warn\"])\n\nfunction sanitize(line: string): string {\n return line.replace(CREDENTIAL_RE, \"[REDACTED]\")\n}\n\nfunction serializeArg(arg: unknown): string {\n if (typeof arg === \"string\") return arg\n if (arg instanceof Error) {\n const parts = [arg.message]\n if (arg.stack) parts.push(arg.stack)\n return parts.join(\"\\n\")\n }\n return String(arg)\n}\n\nfunction formatLogLine(logObj: LogObject): string {\n const ts = logObj.date.toISOString()\n const level = (logObj.type ?? \"error\").toUpperCase()\n const message = logObj.args\n .map((a) => {\n const s = serializeArg(a)\n return s.length > ARG_MAX_LEN ? s.slice(0, ARG_MAX_LEN) + \"…\" : s\n })\n .join(\" \")\n .replace(/\\r\\n|\\r|\\n/g, \"\\\\n\")\n\n return sanitize(`${ts} [${level}] ${message}\\n`)\n}\n\nfunction makeDedupeKey(logObj: LogObject): string {\n const firstArg =\n logObj.args.length > 0 ? serializeArg(logObj.args[0]) : \"\"\n const key = `${logObj.type}:${firstArg}`\n return key.length > DEDUP_KEY_MAX_LEN\n ? key.slice(0, DEDUP_KEY_MAX_LEN)\n : key\n}\n\nfunction rotateIfNeeded(filePath: string): void {\n let size: number\n try {\n size = fs.statSync(filePath).size\n } catch {\n return // file does not exist\n }\n if (size <= MAX_LOG_BYTES) return\n\n try {\n fs.renameSync(filePath, filePath + \".1\")\n } catch {\n // best-effort: if rename fails, continue with the existing file\n }\n}\n\nexport class FileLogReporter implements ConsolaReporter {\n private readonly filePath: string\n private readonly seen = new Set<string>()\n private writing = false\n\n constructor(filePath: string) {\n this.filePath = filePath\n rotateIfNeeded(filePath)\n }\n\n log(logObj: LogObject, _ctx: { options: ConsolaOptions }): void {\n if (!ALLOWED_TYPES.has(logObj.type)) return\n if (this.writing) return // re-entrancy guard\n\n const key = makeDedupeKey(logObj)\n if (this.seen.has(key)) return\n\n if (this.seen.size >= DEDUP_MAX) this.seen.clear()\n this.seen.add(key)\n\n const line = formatLogLine(logObj)\n\n this.writing = true\n try {\n // Always open with explicit mode to ensure 0o600 even if file was\n // deleted between writes and appendFileSync would recreate it as 0o644\n const fd = fs.openSync(this.filePath, \"a\", 0o600)\n fs.writeSync(fd, line)\n fs.closeSync(fd)\n } catch {\n // Silently discard — cannot log a logging failure\n } finally {\n this.writing = false\n }\n }\n}\n\nconst nullStream = new Writable({ write(_chunk, _encoding, cb) { cb() } })\n\n/**\n * Switch consola to file-only mode for TUI sessions.\n * Removes the terminal reporter and installs a file reporter that\n * persists errors and warnings to disk with dedup and credential scrubbing.\n *\n * Also sinks consola's stdout/stderr streams as belt-and-suspenders:\n * even if a terminal reporter is re-added, it cannot write to the terminal.\n * Crash handlers that call process.stderr.write() directly are unaffected.\n * FileLogReporter uses fs.writeSync() directly and is also unaffected.\n */\nexport function enableFileLogging(): void {\n const reporter = new FileLogReporter(PATHS.ERROR_LOG_PATH)\n consola.options.throttle = 0 // disable built-in dedup\n consola.setReporters([reporter])\n consola.options.stdout = nullStream as unknown as typeof process.stdout\n consola.options.stderr = nullStream as unknown as typeof process.stderr\n}\n","export const DEFAULT_PORT = 8787\nexport const DEFAULT_CODEX_MODEL = \"gpt-5.3-codex\"\n\nconst PORT_RANGE_MIN = 11000\nconst PORT_RANGE_MAX = 65535\n\n/** Generate a random port number in the range [11000, 65535]. */\nexport function generateRandomPort(): number {\n return (\n Math.floor(Math.random() * (PORT_RANGE_MAX - PORT_RANGE_MIN + 1))\n + PORT_RANGE_MIN\n )\n}\n","import { execFileSync, spawn, type ChildProcess } from \"node:child_process\"\nimport process from \"node:process\"\n\nimport consola from \"consola\"\n\nimport type { Server } from \"srvx\"\n\nimport { DEFAULT_CODEX_MODEL } from \"./port\"\n\nfunction commandExists(name: string): boolean {\n try {\n execFileSync(process.platform === \"win32\" ? \"where.exe\" : \"which\", [name], {\n stdio: \"ignore\",\n })\n return true\n } catch {\n return false\n }\n}\n\nexport interface LaunchTarget {\n kind: \"claude-code\" | \"codex\"\n envVars: Record<string, string>\n extraArgs: string[]\n model?: string\n}\n\nexport function buildLaunchCommand(target: LaunchTarget): {\n cmd: string[]\n env: Record<string, string | undefined>\n} {\n const cmd: string[] =\n target.kind === \"claude-code\"\n ? [\"claude\", \"--dangerously-skip-permissions\", ...target.extraArgs]\n : [\"codex\", \"--full-auto\", \"-m\", target.model ?? DEFAULT_CODEX_MODEL, ...target.extraArgs]\n\n return {\n cmd,\n env: { ...process.env, ...target.envVars },\n }\n}\n\nexport function launchChild(target: LaunchTarget, server: Server): void {\n const { cmd, env } = buildLaunchCommand(target)\n\n const executable = cmd[0]\n if (!commandExists(executable)) {\n const msg = `\"${executable}\" not found on PATH. Install it first, then try again.`\n consola.error(msg)\n process.stderr.write(msg + \"\\n\")\n process.exit(1)\n }\n\n let child: ChildProcess\n try {\n if (process.platform === \"win32\") {\n // On Windows, npm-installed binaries are .cmd scripts that need\n // shell execution. Use the full command as a single string to\n // avoid DEP0190 deprecation warning about shell + args.\n const quoted = cmd.map((a) => (a.includes(\" \") ? `\"${a}\"` : a)).join(\" \")\n child = spawn(quoted, [], {\n env,\n stdio: \"inherit\",\n shell: true,\n })\n } else {\n child = spawn(cmd[0], cmd.slice(1), {\n env,\n stdio: \"inherit\",\n })\n }\n } catch (error) {\n const msg = `Failed to launch ${executable}: ${error instanceof Error ? error.message : String(error)}`\n consola.error(msg)\n process.stderr.write(msg + \"\\n\")\n server.close(true).catch(() => {})\n process.exit(1)\n }\n\n let cleaned = false\n let exiting = false\n async function cleanup(): Promise<void> {\n if (cleaned) return\n cleaned = true\n\n try {\n child.kill()\n } catch {\n // Already exited\n }\n\n const timeout = setTimeout(() => process.exit(1), 5000)\n try {\n await server.close(true)\n } catch {\n // Server already closed\n }\n clearTimeout(timeout)\n }\n\n function exit(code: number): void {\n if (exiting) return\n exiting = true\n process.exit(code)\n }\n\n const onSignal = () => {\n cleanup().then(() => exit(130)).catch(() => exit(1))\n }\n process.on(\"SIGINT\", onSignal)\n process.on(\"SIGTERM\", onSignal)\n\n child.on(\"exit\", (exitCode, signal) => {\n // When killed by a signal, exitCode is null — derive from signal number\n const code = exitCode ?? (signal ? 128 : 1)\n cleanup().then(() => exit(code)).catch(() => exit(1))\n })\n child.on(\"error\", () => {\n cleanup().then(() => exit(1)).catch(() => exit(1))\n })\n}\n","import consola from \"consola\"\n\nimport { state } from \"./state\"\n\ntype Endpoint = \"/chat/completions\" | \"/responses\" | \"/v1/messages\"\n\nconst ENDPOINT_ALIASES: Record<string, Endpoint> = {\n \"/chat/completions\": \"/chat/completions\",\n \"/v1/chat/completions\": \"/chat/completions\",\n \"/responses\": \"/responses\",\n \"/v1/responses\": \"/responses\",\n \"/v1/messages\": \"/v1/messages\",\n}\n\n/**\n * Check whether a model supports the given endpoint, based on cached\n * `supported_endpoints` metadata from the Copilot `/models` response.\n *\n * Returns `true` (allow) when:\n * - the model is not found in the cache (don't block unknown models)\n * - the model has no `supported_endpoints` field (backward-compat)\n * - the endpoint is listed in `supported_endpoints`\n */\nexport function modelSupportsEndpoint(\n modelId: string,\n path: string,\n): boolean {\n const endpoint = ENDPOINT_ALIASES[path] ?? path\n const model = state.models?.data.find((m) => m.id === modelId)\n if (!model) return true\n\n const supported = model.supported_endpoints\n if (!supported || supported.length === 0) return true\n\n return supported.includes(endpoint)\n}\n\n/**\n * Log an error when a model is used on an endpoint it doesn't support.\n * Returns `true` if a mismatch was detected (for testing).\n */\nexport function logEndpointMismatch(\n modelId: string,\n path: string,\n): boolean {\n if (modelSupportsEndpoint(modelId, path)) return false\n\n const model = state.models?.data.find((m) => m.id === modelId)\n const supported = model?.supported_endpoints ?? []\n\n consola.error(\n `Model \"${modelId}\" does not support ${path}. `\n + `Supported endpoints: ${supported.join(\", \")}`,\n )\n return true\n}\n\n/**\n * Return model IDs that support the given endpoint.\n */\nexport function listModelsForEndpoint(path: string): string[] {\n const endpoint = ENDPOINT_ALIASES[path] ?? path\n const models = state.models?.data ?? []\n\n return models\n .filter((m) => {\n const supported = m.supported_endpoints\n if (!supported || supported.length === 0) return true\n return supported.includes(endpoint)\n })\n .map((m) => m.id)\n}\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected by user\",\n Response.json({ message: \"Request rejected by user\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n state.lastRequestTimestamp = Date.now()\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import consola from \"consola\"\n\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport interface RequestLogInfo {\n method: string\n path: string\n model?: string\n resolvedModel?: string\n inputTokens?: number\n outputTokens?: number\n status?: number\n streaming?: boolean\n errorBody?: string\n}\n\n/**\n * Format a number with K/M suffix for compact display.\n */\nfunction formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`\n return String(n)\n}\n\n/**\n * Build a context window summary: \"in:1.2K out:50 ctx:1.2K/1M (0.1%)\"\n */\nfunction formatTokenInfo(\n inputTokens: number | undefined,\n outputTokens: number | undefined,\n model: Model | undefined,\n): string | undefined {\n if (inputTokens === undefined) return undefined\n\n const parts: Array<string> = []\n const maxPrompt = model?.capabilities?.limits?.max_prompt_tokens\n\n if (maxPrompt) {\n const pct = ((inputTokens / maxPrompt) * 100).toFixed(1)\n parts.push(`in:${formatTokens(inputTokens)}/${formatTokens(maxPrompt)} (${pct}%)`)\n } else {\n parts.push(`in:${formatTokens(inputTokens)}`)\n }\n\n if (outputTokens !== undefined) {\n parts.push(`out:${formatTokens(outputTokens)}`)\n }\n\n return parts.join(\" \")\n}\n\n/**\n * Print a single summary line for a completed request.\n *\n * Examples:\n * POST /v1/messages claude-opus-4.6-1m in:1.2K/1M (0.1%) out:50 200 2.3s\n * POST /v1/messages claude-opus-4-6→claude-opus-4.6-1m in:743/1M (0.1%) 200 198ms\n * POST /v1/chat/completions claude-sonnet-4 in:15 out:16 200 2.1s stream\n */\nexport function logRequest(\n info: RequestLogInfo,\n model: Model | undefined,\n startTime: number,\n): void {\n const parts: Array<string> = []\n\n parts.push(`${info.method} ${info.path}`)\n\n // Model (show resolution arrow if remapped)\n if (info.resolvedModel && info.resolvedModel !== info.model) {\n parts.push(`${info.model}→${info.resolvedModel}`)\n } else if (info.resolvedModel ?? info.model) {\n parts.push((info.resolvedModel ?? info.model)!)\n }\n\n // Token info with context window fill\n const tokenInfo = formatTokenInfo(info.inputTokens, info.outputTokens, model)\n if (tokenInfo) {\n parts.push(tokenInfo)\n }\n\n // Status\n if (info.status !== undefined) {\n parts.push(String(info.status))\n }\n\n // Duration + streaming flag\n const elapsed = Date.now() - startTime\n const duration =\n elapsed >= 1000 ? `${(elapsed / 1000).toFixed(1)}s` : `${elapsed}ms`\n parts.push(info.streaming ? `${duration} stream` : duration)\n\n const line = parts.join(\" \")\n\n if (detectCapabilityMismatch(info, model)) {\n consola.error(`[MISMATCH] ${line}`)\n } else {\n consola.info(line)\n }\n}\n\n/**\n * Detect when the API rejects a request for token/context reasons\n * that contradict what the /models endpoint reported.\n */\nfunction detectCapabilityMismatch(\n info: RequestLogInfo,\n model: Model | undefined,\n): boolean {\n if (!info.errorBody || !model) return false\n if (!info.status || info.status < 400) return false\n\n const err = info.errorBody.toLowerCase()\n return (\n err.includes(\"token\") ||\n err.includes(\"context\") ||\n err.includes(\"too long\") ||\n err.includes(\"max_tokens\") ||\n err.includes(\"prompt is too long\")\n )\n}\n","import type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\n// Encoder type mapping\nconst ENCODING_MAP = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof ENCODING_MAP\n\n// Define encoder interface\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\n// Cache loaded encoders to avoid repeated imports\nconst encodingCache = new Map<string, Encoder>()\n\n/**\n * Calculate tokens for tool calls\n */\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\n/**\n * Calculate tokens for content parts\n */\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens for a single message\n */\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") {\n tokens += tokensPerName\n }\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens using custom algorithm\n */\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) {\n return 0\n }\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n // every reply is primed with <|start|>assistant<|message|>\n numTokens += 3\n return numTokens\n}\n\n/**\n * Get the corresponding encoder module based on encoding type\n */\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) {\n return cached\n }\n }\n\n const supportedEncoding = encoding as SupportedEncoding\n if (!(supportedEncoding in ENCODING_MAP)) {\n const fallbackModule = (await ENCODING_MAP.o200k_base()) as Encoder\n encodingCache.set(encoding, fallbackModule)\n return fallbackModule\n }\n\n const encodingModule = (await ENCODING_MAP[supportedEncoding]()) as Encoder\n encodingCache.set(encoding, encodingModule)\n return encodingModule\n}\n\n/**\n * Get tokenizer type from model information\n */\nexport const getTokenizerFromModel = (model: Model): string => {\n return model.capabilities?.tokenizer || \"o200k_base\"\n}\n\n/**\n * Get model-specific constants for token calculation\n */\nconst getModelConstants = (model: Model) => {\n return model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\" ?\n {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n}\n\n/**\n * Calculate tokens for a single parameter\n */\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n // Early return if prop is not an object\n if (typeof prop !== \"object\" || prop === null) {\n return tokens\n }\n\n // Type assertion for parameter properties\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n // Handle enum values\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n // Clean up description\n if (paramDesc.endsWith(\".\")) {\n paramDesc = paramDesc.slice(0, -1)\n }\n\n // Encode the main parameter line\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n // Handle additional properties (excluding standard ones)\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (!excludedKeys.has(propertyName)) {\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : (\n JSON.stringify(propertyValue)\n )\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for function parameters\n */\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") {\n return 0\n }\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for a single tool\n */\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) {\n fDesc = fDesc.slice(0, -1)\n }\n const line = fName + \":\" + fDesc\n tokens += encoder.encode(line).length\n if (\n typeof func.parameters === \"object\" \n && func.parameters !== null\n ) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\n/**\n * Calculate token count for tools based on model\n */\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\n/**\n * Calculate the token count of messages, supporting multiple GPT encoders\n */\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: Model,\n): Promise<{ input: number; output: number }> => {\n // Get tokenizer string\n const tokenizer = getTokenizerFromModel(model)\n\n // Get corresponding encoder module\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const simplifiedMessages = payload.messages\n const inputMessages = simplifiedMessages.filter(\n (msg) => msg.role !== \"assistant\",\n )\n const outputMessages = simplifiedMessages.filter(\n (msg) => msg.role === \"assistant\",\n )\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n modelHeaders?: Record<string, string>,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = payload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = payload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n ...modelHeaders,\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n const claudeModels = state.models?.data\n .filter((m) => m.id.startsWith(\"claude\"))\n .map((m) => m.id)\n .join(\", \") ?? \"(models not loaded)\"\n consola.error(\n `Copilot rejected model \"${payload.model}\": ${response.status} ${errorBody} (available Claude models: ${claudeModels})`,\n )\n // Re-create the response so downstream error handlers can still read the body\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Failed to create chat completions\", reconstructed)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nexport interface WebSearchResult {\n content: string\n references: Array<{ title: string; url: string }>\n}\n\ninterface ThreadsResponse {\n thread_id: string\n}\n\ninterface ThreadsMessageResponse {\n message: {\n content: string\n references: Array<{\n query?: string\n results?: Array<{\n title: string\n url: string\n reference_type: string\n }>\n }>\n }\n}\n\nconst MAX_SEARCHES_PER_SECOND = 3\nlet searchTimestamps: Array<number> = []\n\nasync function throttleSearch(): Promise<void> {\n const now = Date.now()\n searchTimestamps = searchTimestamps.filter((t) => now - t < 1000)\n if (searchTimestamps.length >= MAX_SEARCHES_PER_SECOND) {\n const waitMs = 1000 - (now - searchTimestamps[0])\n if (waitMs > 0) {\n consola.debug(`Web search rate limited, waiting ${waitMs}ms`)\n await sleep(waitMs)\n }\n }\n searchTimestamps.push(Date.now())\n}\n\nfunction threadsHeaders(): Record<string, string> {\n return copilotHeaders(state, false, \"copilot-chat\")\n}\n\nasync function createThread(): Promise<string> {\n const response = await fetch(`${copilotBaseUrl(state)}/github/chat/threads`, {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create chat thread\", response.status)\n throw new Error(`Failed to create chat thread: ${response.status}`)\n }\n\n const data = (await response.json()) as ThreadsResponse\n return data.thread_id\n}\n\nasync function sendThreadMessage(\n threadId: string,\n query: string,\n): Promise<ThreadsMessageResponse> {\n const response = await fetch(\n `${copilotBaseUrl(state)}/github/chat/threads/${threadId}/messages`,\n {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({\n content: query,\n intent: \"conversation\",\n skills: [\"web-search\"],\n references: [],\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to send thread message\", response.status)\n throw new Error(`Failed to send thread message: ${response.status}`)\n }\n\n return (await response.json()) as ThreadsMessageResponse\n}\n\nexport async function searchWeb(query: string): Promise<WebSearchResult> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n await throttleSearch()\n\n consola.info(`Web search: \"${query.slice(0, 80)}\"`)\n\n const threadId = await createThread()\n const response = await sendThreadMessage(threadId, query)\n\n const references: Array<{ title: string; url: string }> = []\n for (const ref of response.message.references ?? []) {\n if (ref.results) {\n for (const result of ref.results) {\n if (result.url && result.reference_type !== \"bing_search\") {\n references.push({ title: result.title, url: result.url })\n }\n }\n }\n }\n\n consola.debug(`Web search returned ${references.length} references`)\n\n return {\n content: response.message.content,\n references,\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish, resolveModel } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n }\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n // Find the selected model\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n logEndpointMismatch(payload.model, \"/chat/completions\")\n\n // Calculate token count\n let inputTokens: number | undefined\n try {\n if (selectedModel) {\n const tokenCount = await getTokenCount(payload, selectedModel)\n inputTokens = tokenCount.input\n }\n } catch {\n // Token counting is best-effort\n }\n\n if (isNullish(payload.max_tokens)) {\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities?.limits?.max_output_tokens,\n }\n if (debugEnabled) {\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n }\n\n const response = await createChatCompletions(payload, selectedModel?.requestHeaders).catch(\n async (error: unknown) => {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n },\n )\n const isStreaming = !isNonStreaming(response)\n\n // Extract output tokens from non-streaming response (no extra call)\n const outputTokens = !isStreaming\n ? (response as ChatCompletionResponse).usage?.completion_tokens\n : undefined\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens,\n outputTokens,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n\nasync function injectWebSearchIfNeeded(\n payload: ChatCompletionsPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some(\n (t) =>\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\",\n )\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = payload.messages.some((msg) => msg.role === \"tool\")\n const query = hasToolResult ? undefined : extractUserQuery(payload.messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n // Prepend to existing system message or inject a new one\n const systemMsg = payload.messages.find((msg) => msg.role === \"system\")\n if (systemMsg) {\n const existingContent =\n typeof systemMsg.content === \"string\" ? systemMsg.content\n : Array.isArray(systemMsg.content) ?\n systemMsg.content\n .filter((p) => p.type === \"text\")\n .map((p) => (\"text\" in p ? p.text : \"\"))\n .join(\"\\n\")\n : \"\"\n systemMsg.content = `${searchContext}\\n\\n${existingContent}`\n } else {\n payload.messages.unshift({\n role: \"system\",\n content: searchContext,\n })\n }\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Remove web_search from tools before forwarding\n payload.tools = payload.tools?.filter(\n (t) =>\n !(\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\"\n ),\n ) as typeof payload.tools\n if (payload.tools?.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n && \"type\" in payload.tool_choice\n && payload.tool_choice.type === \"function\"\n ) {\n const toolChoiceName = payload.tool_choice.function?.name\n if (\n toolChoiceName\n && !payload.tools.some((tool) => tool.function.name === toolChoiceName)\n ) {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(messages: Array<Message>): string | undefined {\n // Find the last user message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const text = msg.content.find((p) => p.type === \"text\")\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const payload = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(payload)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { randomUUID } from \"node:crypto\"\n\nimport consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Build headers that match what VS Code Copilot Chat sends to the Copilot API.\n *\n * copilotHeaders() provides: Authorization, content-type, copilot-integration-id,\n * editor-version, editor-plugin-version, user-agent, openai-intent,\n * x-github-api-version, x-request-id, x-vscode-user-agent-library-version.\n *\n * We add the remaining headers VS Code sends for /v1/messages:\n * - X-Initiator (VS Code sets dynamically; \"agent\" is safe for CLI use)\n * - anthropic-version (VS Code's Anthropic SDK sends this)\n * - X-Interaction-Id (VS Code sends a session-scoped UUID)\n *\n * We intentionally omit copilot-vision-request — VS Code only sends it when\n * images are present, and the native /v1/messages endpoint handles vision\n * without requiring the header.\n *\n * extraHeaders allows callers to forward client-supplied beta headers\n * (anthropic-beta) so Copilot enables extended features.\n */\nfunction buildHeaders(\n extraHeaders?: Record<string, string>,\n): Record<string, string> {\n const headers: Record<string, string> = {\n ...copilotHeaders(state),\n accept: \"application/json\",\n \"openai-intent\": \"messages-proxy\",\n \"x-interaction-type\": \"conversation-agent\",\n \"X-Initiator\": \"agent\",\n \"anthropic-version\": \"2023-06-01\",\n \"X-Interaction-Id\": randomUUID(),\n ...extraHeaders,\n }\n // VS Code extension v0.43+ suppresses this for /v1/messages\n delete headers[\"copilot-integration-id\"]\n return headers\n}\n\n/**\n * Forward an Anthropic Messages API request to Copilot's native /v1/messages endpoint.\n * Returns the raw Response so callers can handle streaming vs non-streaming.\n */\nexport async function createMessages(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot /v1/messages error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot messages request failed\", reconstructed)\n }\n\n return response\n}\n\n/**\n * Forward an Anthropic count_tokens request to Copilot's native endpoint.\n * Returns the raw Response.\n */\nexport async function countTokens(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot count_tokens error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot count_tokens request failed\", reconstructed)\n }\n\n return response\n}\n","import type { Context } from \"hono\"\n\nimport { logRequest } from \"~/lib/request-log\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport { state } from \"~/lib/state\"\nimport { countTokens } from \"~/services/copilot/create-messages\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Strip web_search tools from the request body before forwarding\n * to Copilot's count_tokens endpoint, which rejects unknown tool types.\n * Returns the original raw body if no web_search tools are present.\n */\nfunction stripWebSearchFromBody(rawBody: string): string {\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n\n return JSON.stringify(body)\n}\n\n/**\n * Passthrough handler for Anthropic token counting.\n * Strips web_search tools and forwards beta headers to Copilot's\n * native /v1/messages/count_tokens endpoint.\n */\nexport async function handleCountTokens(c: Context) {\n const startTime = Date.now()\n const rawBody = await c.req.text()\n const strippedBody = stripWebSearchFromBody(rawBody)\n const { body: finalBody, originalModel, resolvedModel } = resolveModelInBody(strippedBody)\n\n const extraHeaders: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) extraHeaders[\"anthropic-beta\"] = filtered\n }\n\n const modelId = resolvedModel ?? originalModel\n const selectedModel = state.models?.data.find((m) => m.id === modelId)\n\n const response = await countTokens(finalBody, {\n ...selectedModel?.requestHeaders,\n ...extraHeaders,\n })\n const responseBody = (await response.json()) as { input_tokens?: number }\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: responseBody.input_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n return c.json(responseBody)\n}\n\n/**\n * Parse the JSON body, resolve the model name, sanitize cache_control, and re-serialize.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n\n let modified = false\n if (originalModel) {\n const resolved = resolveModel(originalModel)\n if (resolved !== originalModel) {\n parsed.model = resolved\n modified = true\n }\n }\n\n const needsSanitize = rawBody.includes('\"scope\"')\n if (needsSanitize && sanitizeCacheControl(parsed)) {\n modified = true\n }\n\n const resolvedModel =\n typeof parsed.model === \"string\" ? parsed.model : originalModel\n\n return {\n body: modified ? JSON.stringify(parsed) : rawBody,\n originalModel,\n resolvedModel,\n }\n}\n\nfunction sanitizeCacheControl(body: AnyRecord): boolean {\n let stripped = false\n function stripScope(block: AnyRecord): void {\n if (block.cache_control?.scope !== undefined) {\n delete block.cache_control.scope\n if (Object.keys(block.cache_control).length === 0) {\n delete block.cache_control\n }\n stripped = true\n }\n }\n\n if (Array.isArray(body.system)) {\n for (const block of body.system) stripScope(block)\n }\n\n if (Array.isArray(body.messages)) {\n for (const msg of body.messages) {\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n stripScope(block)\n if (Array.isArray(block.content)) {\n for (const nested of block.content) stripScope(nested)\n }\n }\n }\n }\n }\n\n if (Array.isArray(body.tools)) {\n for (const tool of body.tools) stripScope(tool)\n }\n\n return stripped\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport { createMessages } from \"~/services/copilot/create-messages\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Extract whitelisted beta headers from the incoming request to forward\n * to the Copilot API. VS Code sends these to enable extended features\n * like thinking, context management, and advanced tool use.\n */\nfunction extractBetaHeaders(c: Context): Record<string, string> {\n const headers: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) headers[\"anthropic-beta\"] = filtered\n }\n return headers\n}\n\n/**\n * Extract the text content from the last user message for web search.\n * Handles both string content and content block arrays (multimodal).\n */\nfunction extractUserQuery(\n messages: Array<AnyRecord>,\n): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const textBlock = msg.content.find(\n (block: AnyRecord) => block.type === \"text\",\n )\n if (textBlock?.text) return textBlock.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Check if any user message contains tool_result content blocks,\n * indicating a follow-up turn where we should skip web search.\n * In Anthropic format, tool results are content blocks inside user messages,\n * NOT separate role: \"tool\" messages like in OpenAI format.\n */\nfunction hasToolResultContent(messages: Array<AnyRecord>): boolean {\n return messages.some(\n (msg) =>\n Array.isArray(msg.content) &&\n msg.content.some(\n (block: AnyRecord) => block.type === \"tool_result\",\n ),\n )\n}\n\n/**\n * Inject web search results into the Anthropic system field.\n * Handles three cases: absent, string, or array of content blocks.\n * When array, prepends without cache_control to preserve existing directives.\n */\nfunction injectSearchResults(\n body: AnyRecord,\n searchContext: string,\n): void {\n if (body.system === undefined || body.system === null) {\n body.system = searchContext\n } else if (typeof body.system === \"string\") {\n body.system = `${searchContext}\\n\\n${body.system}`\n } else if (Array.isArray(body.system)) {\n body.system = [\n { type: \"text\", text: searchContext },\n ...body.system,\n ]\n }\n}\n\n/**\n * Strip web_search tools from the request and clean up tool_choice.\n * Returns the modified body object.\n */\nfunction stripWebSearchTool(body: AnyRecord): void {\n if (!body.tools) return\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n // If tool_choice forced the removed web_search tool, fall back to auto\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n}\n\n/**\n * Process web search if the request contains a web_search tool.\n * Performs the search, injects results into system, and strips the tool.\n * Returns the (possibly modified) body string to forward.\n */\nasync function processWebSearch(rawBody: string): Promise<string> {\n // Fast path: skip parsing if no web_search tool present\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = hasToolResultContent(body.messages ?? [])\n const query = hasToolResult ? undefined : extractUserQuery(body.messages ?? [])\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n injectSearchResults(body, searchContext)\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Always strip web_search tool regardless of whether search succeeded\n stripWebSearchTool(body)\n\n return JSON.stringify(body)\n}\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const rawBody = await c.req.text()\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Anthropic request body:\", rawBody.slice(0, 2000))\n }\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const betaHeaders = extractBetaHeaders(c)\n const finalBody = await processWebSearch(rawBody)\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const { body: resolvedBody, originalModel, resolvedModel } = resolveModelInBody(finalBody)\n\n // Look up model metadata for context window info\n const modelId = resolvedModel ?? originalModel\n const selectedModel = state.models?.data.find(\n (m) => m.id === modelId,\n )\n\n if (modelId) logEndpointMismatch(modelId, \"/v1/messages\")\n\n // Apply default anthropic-beta for Claude models when client sends none\n const effectiveBetas = applyDefaultBetas(betaHeaders, resolvedModel ?? originalModel)\n\n let response: Response\n try {\n response = await createMessages(resolvedBody, {\n ...selectedModel?.requestHeaders,\n ...effectiveBetas,\n })\n } catch (error) {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n const isStreaming = contentType.includes(\"text/event-stream\")\n\n // Streaming: pipe the upstream SSE response body directly\n if (isStreaming) {\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: response.status,\n streaming: true,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\"Streaming response from Copilot /v1/messages\")\n }\n const streamHeaders: Record<string, string> = {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n }\n const requestId = response.headers.get(\"x-request-id\")\n if (requestId) streamHeaders[\"x-request-id\"] = requestId\n const reqId = response.headers.get(\"request-id\")\n if (reqId) streamHeaders[\"request-id\"] = reqId\n\n return new Response(response.body, {\n status: response.status,\n headers: streamHeaders,\n })\n }\n\n // Non-streaming: extract usage from response body\n const responseBody = (await response.json()) as AnyRecord\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: responseBody.usage?.input_tokens,\n outputTokens: responseBody.usage?.output_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\n \"Non-streaming response from Copilot /v1/messages:\",\n JSON.stringify(responseBody).slice(0, 2000),\n )\n }\n const xRequestId = response.headers.get(\"x-request-id\")\n if (xRequestId) c.header(\"x-request-id\", xRequestId)\n const requestIdHeader = response.headers.get(\"request-id\")\n if (requestIdHeader) c.header(\"request-id\", requestIdHeader)\n return c.json(responseBody, response.status as 200)\n}\n\n/**\n * Parse the JSON body, resolve the model name, sanitize cache_control\n * fields, and re-serialize. Returns the body string plus the original\n * and resolved model names.\n *\n * Re-serialization is skipped when no modifications are needed.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n\n let modified = false\n if (originalModel) {\n const resolved = resolveModel(originalModel)\n if (resolved !== originalModel) {\n parsed.model = resolved\n modified = true\n }\n }\n\n // Strip cache_control.scope — fast path skips when \"scope\" absent\n const needsSanitize = rawBody.includes('\"scope\"')\n if (needsSanitize && sanitizeCacheControl(parsed)) {\n modified = true\n }\n\n const resolvedModel =\n typeof parsed.model === \"string\" ? parsed.model : originalModel\n\n return {\n body: modified ? JSON.stringify(parsed) : rawBody,\n originalModel,\n resolvedModel,\n }\n}\n\n/**\n * Strip the `scope` field from all `cache_control` objects in the body.\n * Claude CLI 2.1.88+ sends {\"type\":\"ephemeral\",\"scope\":\"global\"} which\n * Copilot rejects. Mutates the parsed object in place.\n *\n * Covers: system blocks, message content blocks (including nested\n * tool_result content), and tool definitions.\n */\nfunction sanitizeCacheControl(body: AnyRecord): boolean {\n let stripped = false\n function stripScope(block: AnyRecord): void {\n if (block.cache_control?.scope !== undefined) {\n delete block.cache_control.scope\n if (Object.keys(block.cache_control).length === 0) {\n delete block.cache_control\n }\n stripped = true\n }\n }\n\n if (Array.isArray(body.system)) {\n for (const block of body.system) stripScope(block)\n }\n\n if (Array.isArray(body.messages)) {\n for (const msg of body.messages) {\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n stripScope(block)\n if (Array.isArray(block.content)) {\n for (const nested of block.content) stripScope(nested)\n }\n }\n }\n }\n }\n\n if (Array.isArray(body.tools)) {\n for (const tool of body.tools) stripScope(tool)\n }\n\n return stripped\n}\n\n/**\n * Apply default anthropic-beta values for Claude models when the client\n * (e.g. curl) sends no beta headers. Claude CLI sends its own betas,\n * so this only fires as a safety net for bare clients.\n */\nfunction applyDefaultBetas(\n betaHeaders: Record<string, string>,\n modelId?: string,\n): Record<string, string> {\n if (betaHeaders[\"anthropic-beta\"]) return betaHeaders\n if (!modelId || !modelId.startsWith(\"claude-\")) return betaHeaders\n\n return {\n ...betaHeaders,\n \"anthropic-beta\": [\n \"interleaved-thinking-2025-05-14\",\n \"context-management-2025-06-27\",\n ].join(\",\"),\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCountTokens } from \"./count-tokens-handler\"\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nmessageRoutes.post(\"/count_tokens\", async (c) => {\n try {\n return await handleCountTokens(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => ({\n id: model.id,\n object: \"model\",\n type: model.capabilities?.type ?? \"model\",\n created: 0,\n created_at: new Date(0).toISOString(),\n owned_by: model.vendor,\n display_name: model.name,\n capabilities: model.capabilities,\n supported_endpoints: model.supported_endpoints,\n preview: model.preview,\n version: model.version,\n model_picker_enabled: model.model_picker_enabled,\n policy: model.policy,\n }))\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createResponses = async (\n payload: ResponsesPayload,\n modelHeaders?: Record<string, string>,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = detectVision(payload.input)\n\n const isAgentCall = detectAgentCall(payload.input)\n\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n ...modelHeaders,\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const filteredPayload = filterUnsupportedTools(payload)\n\n const response = await fetch(`${copilotBaseUrl(state)}/responses`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(filteredPayload),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create responses\", response)\n throw new HTTPError(\"Failed to create responses\", response)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ResponsesApiResponse\n}\n\nfunction detectVision(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"content\" in item && Array.isArray(item.content)) {\n return item.content.some(\n (part: Record<string, unknown>) => part.type === \"input_image\",\n )\n }\n return false\n })\n}\n\nfunction detectAgentCall(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"role\" in item && item.role === \"assistant\") return true\n if (\n \"type\" in item\n && (item.type === \"function_call\" || item.type === \"function_call_output\")\n ) {\n return true\n }\n return false\n })\n}\n\nfunction filterUnsupportedTools(payload: ResponsesPayload): ResponsesPayload {\n if (!payload.tools || !Array.isArray(payload.tools)) return payload\n\n const supported = payload.tools.filter((tool) => {\n const isSupported = tool.type === \"function\"\n if (!isSupported) {\n consola.debug(`Stripping unsupported tool type: ${tool.type}`)\n }\n return isSupported\n })\n\n let toolChoice = payload.tool_choice\n if (supported.length === 0) {\n toolChoice = undefined\n } else if (\n toolChoice\n && typeof toolChoice === \"object\"\n ) {\n const supportedNames = new Set(\n supported.map((tool) => tool.name).filter(Boolean),\n )\n const toolChoiceName = getToolChoiceName(toolChoice)\n if (toolChoiceName && !supportedNames.has(toolChoiceName)) {\n toolChoice = undefined\n }\n }\n\n return {\n ...payload,\n tools: supported.length > 0 ? supported : undefined,\n tool_choice: toolChoice,\n }\n}\n\nfunction getToolChoiceName(\n toolChoice: NonNullable<ResponsesPayload[\"tool_choice\"]>,\n): string | undefined {\n if (typeof toolChoice !== \"object\") return undefined\n if (\n \"function\" in toolChoice\n && toolChoice.function\n && typeof toolChoice.function === \"object\"\n ) {\n return (toolChoice.function as { name?: string }).name\n }\n if (\"name\" in toolChoice) {\n return toolChoice.name\n }\n return undefined\n}\n\n// Types\n\nexport interface ResponsesInputItem {\n role?: \"user\" | \"assistant\" | \"system\"\n type?: \"message\" | \"function_call\" | \"function_call_output\"\n content?: string | Array<Record<string, unknown>>\n name?: string\n call_id?: string\n arguments?: string\n output?: string\n [key: string]: unknown\n}\n\nexport interface ResponsesTool {\n type: string\n name?: string\n description?: string\n parameters?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface ResponsesPayload {\n model: string\n input: string | Array<ResponsesInputItem>\n instructions?: string\n tools?: Array<ResponsesTool>\n tool_choice?:\n | string\n | { type: string; name?: string; function?: { name?: string } }\n max_output_tokens?: number\n temperature?: number\n top_p?: number\n stream?: boolean\n store?: boolean\n metadata?: Record<string, string>\n previous_response_id?: string\n reasoning?: { effort?: string; summary?: string }\n [key: string]: unknown\n}\n\nexport interface ResponsesApiResponse {\n id: string\n object: \"response\"\n status: string\n output: Array<unknown>\n [key: string]: unknown\n}\n","import { randomUUID } from \"node:crypto\"\nimport type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { resolveModel } from \"~/lib/utils\"\nimport {\n createResponses,\n type ResponsesApiResponse,\n type ResponsesInputItem,\n type ResponsesPayload,\n} from \"~/services/copilot/create-responses\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleResponses(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const payload = await c.req.json<ResponsesPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n \"Responses request payload:\",\n JSON.stringify(payload).slice(-400),\n )\n }\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n logEndpointMismatch(payload.model, \"/responses\")\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n const response = await createResponses(payload, selectedModel?.requestHeaders).catch(\n async (error: unknown) => {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n },\n )\n const isStreaming = !isNonStreaming(response)\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n\n if (chunk.data === \"[DONE]\") {\n break\n }\n\n if (!chunk.data) {\n continue\n }\n\n await stream.writeSSE({\n data: chunk.data,\n event: chunk.event,\n id: chunk.id?.toString(),\n })\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createResponses>>,\n): response is ResponsesApiResponse => Object.hasOwn(response, \"output\")\n\nasync function injectWebSearchIfNeeded(\n payload: ResponsesPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some((t) => t.type === \"web_search\")\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (function call results)\n if (Array.isArray(payload.input)) {\n const hasFollowUp = payload.input.some(\n (item: ResponsesInputItem) => item.type === \"function_call_output\",\n )\n if (hasFollowUp) return\n }\n\n const query = extractUserQuery(payload.input)\n if (!query) return\n\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n payload.instructions =\n payload.instructions ?\n `${searchContext}\\n\\n${payload.instructions}`\n : searchContext\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n}\n\nfunction extractUserQuery(\n input: ResponsesPayload[\"input\"],\n): string | undefined {\n if (typeof input === \"string\") return input\n if (!Array.isArray(input)) return undefined\n\n // Find the last user message\n for (let i = input.length - 1; i >= 0; i--) {\n const item = input[i]\n if (\"role\" in item && item.role === \"user\") {\n if (typeof item.content === \"string\") return item.content\n if (Array.isArray(item.content)) {\n const text = item.content.find(\n (p: Record<string, unknown>) => p.type === \"input_text\",\n )\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Compaction prompt used when GitHub Copilot API does not support\n * /responses/compact natively. Matches the prompt Codex CLI uses for\n * local (non-OpenAI) compaction.\n */\nconst COMPACTION_PROMPT = `You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.\n\nInclude:\n- Current progress and key decisions made\n- Important context, constraints, or user preferences\n- What remains to be done (clear next steps)\n- Any critical data, examples, or references needed to continue\n\nBe concise, structured, and focused on helping the next LLM seamlessly continue the work.`\n\ninterface CompactRequestPayload {\n model: string\n input: Array<Record<string, unknown>>\n instructions?: string\n [key: string]: unknown\n}\n\nexport async function handleResponsesCompact(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n if (state.manualApprove) await awaitApproval()\n\n const body = await c.req.json<CompactRequestPayload>()\n\n // Try Copilot's native compact endpoint first (future-proofs for when they add support)\n const response = await fetch(\n `${copilotBaseUrl(state)}/responses/compact`,\n {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(body),\n },\n )\n\n if (response.ok) {\n logRequest(\n { method: \"POST\", path: c.req.path, status: 200 },\n undefined,\n startTime,\n )\n return c.json(await response.json())\n }\n\n // Copilot doesn't support /responses/compact — perform synthetic compaction\n // by sending a regular /responses call with a summarization prompt\n if (response.status === 404) {\n consola.debug(\"Copilot API does not support /responses/compact, using synthetic compaction\")\n return await syntheticCompact(c, body, startTime)\n }\n\n // Other errors: throw as before\n logRequest(\n { method: \"POST\", path: c.req.path, status: response.status },\n undefined,\n startTime,\n )\n throw new HTTPError(\"Copilot responses/compact request failed\", response)\n}\n\n/**\n * Synthetic compaction: sends the conversation history to Copilot's\n * regular /responses endpoint with a compaction prompt appended,\n * then returns the model's summary in the compact response format.\n */\nasync function syntheticCompact(\n c: Context,\n body: CompactRequestPayload,\n startTime: number,\n) {\n const input = Array.isArray(body.input) ? [...body.input] : []\n\n // Append compaction prompt as the last user message\n input.push({\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text: COMPACTION_PROMPT }],\n })\n\n const payload: ResponsesPayload = {\n model: body.model,\n input: input as Array<ResponsesInputItem>,\n instructions: body.instructions,\n stream: false,\n store: false,\n }\n\n let result: ResponsesApiResponse\n try {\n result = (await createResponses(payload)) as ResponsesApiResponse\n } catch (error) {\n if (error instanceof HTTPError) {\n logRequest(\n { method: \"POST\", path: c.req.path, status: error.response.status },\n undefined,\n startTime,\n )\n }\n throw error\n }\n\n logRequest(\n { method: \"POST\", path: c.req.path, status: 200 },\n undefined,\n startTime,\n )\n\n return c.json({\n id: `resp_compact_${randomUUID().replace(/-/g, \"\").slice(0, 24)}`,\n object: \"response.compaction\",\n created_at: Math.floor(Date.now() / 1000),\n output: result.output,\n usage: result.usage ?? { input_tokens: 0, output_tokens: 0, total_tokens: 0 },\n })\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleResponses, handleResponsesCompact } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n try {\n return await handleResponses(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nresponsesRoutes.post(\"/compact\", async (c) => {\n try {\n return await handleResponsesCompact(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport const searchRoutes = new Hono()\n\nsearchRoutes.post(\"/\", async (c) => {\n try {\n const { query } = await c.req.json<{ query: string }>()\n\n if (!query || typeof query !== \"string\") {\n return c.json(\n { error: { message: \"Missing required field: query\" } },\n 400,\n )\n }\n\n const results = await searchWeb(query)\n return c.json({ results })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n if (!state.showToken) {\n return c.json(\n { error: { message: \"Token endpoint disabled\", type: \"error\" } },\n 403,\n )\n }\n\n return c.json({\n token: state.copilotToken,\n })\n})\n","import { Hono } from \"hono\"\nimport consola from \"consola\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n consola.error(\"Error fetching Copilot usage:\", error)\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { searchRoutes } from \"./routes/search/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\n// Claude CLI sends HEAD / as health check before each request\nserver.on(\"HEAD\", [\"/\"], (c) => c.body(null, 200))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/responses\", responsesRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/search\", searchRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/responses\", responsesRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\nserver.route(\"/v1/search\", searchRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n\n// Return Anthropic-format JSON for unknown endpoints\nserver.notFound((c) =>\n c.json(\n {\n type: \"error\",\n error: {\n type: \"not_found_error\",\n message: `${c.req.method} ${c.req.path} not found`,\n },\n },\n 404,\n ),\n)\n","import consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\n\nimport { ensurePaths } from \"./paths\"\nimport { generateRandomPort } from \"./port\"\nimport { initProxyFromEnv } from \"./proxy\"\nimport { state } from \"./state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./token\"\nimport { cacheModels, cacheCopilotVersion, cacheVSCodeVersion } from \"./utils\"\nimport { server as app } from \"../server\"\n\nconst MAX_PORT_RETRIES = 10\n\nexport interface ServerSetupOptions {\n port?: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n showToken: boolean\n proxyEnv: boolean\n extendedBetas: boolean\n silent: boolean\n}\n\nexport async function setupAndServe(\n options: ServerSetupOptions,\n): Promise<{ server: ReturnType<typeof serve>; serverUrl: string }> {\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n state.extendedBetas = options.extendedBetas\n\n if (process.env.COPILOT_API_URL) {\n state.copilotApiUrl = process.env.COPILOT_API_URL\n }\n\n await ensurePaths()\n await cacheVSCodeVersion()\n await cacheCopilotVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.debug(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serveOptions = {\n fetch: app.fetch as ServerHandler,\n hostname: \"127.0.0.1\",\n silent: options.silent,\n }\n\n let srvxServer: ReturnType<typeof serve> | undefined\n\n if (options.port !== undefined) {\n // Explicit port — no retry\n srvxServer = serve({ ...serveOptions, port: options.port })\n } else {\n // Random available port with retry\n let lastError: unknown\n for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {\n const candidatePort = generateRandomPort()\n try {\n srvxServer = serve({ ...serveOptions, port: candidatePort })\n break\n } catch (error) {\n lastError = error\n const isAddrInUse =\n error instanceof Error\n && (error.message.includes(\"EADDRINUSE\")\n || error.message.includes(\"address already in use\")\n || (\"code\" in error\n && (error as NodeJS.ErrnoException).code === \"EADDRINUSE\"))\n if (!isAddrInUse) throw error\n consola.debug(`Port ${candidatePort} in use, trying another...`)\n }\n }\n\n if (srvxServer === undefined) {\n throw new Error(\n `Failed to find an available port after ${MAX_PORT_RETRIES} attempts. `\n + `Specify a port with --port or free some ports. Last error: ${lastError}`,\n )\n }\n }\n\n // Wait for the server to be listening before reading the URL\n await srvxServer.ready()\n const url = srvxServer.url\n if (!url) {\n throw new Error(\"Server started but URL is not available\")\n }\n const serverUrl = url.replace(/\\/$/, \"\")\n\n return { server: srvxServer, serverUrl }\n}\n\n/** Shared CLI arg definitions for all server commands. */\nexport const sharedServerArgs = {\n port: {\n alias: \"p\",\n type: \"string\" as const,\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\" as const,\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\" as const,\n default: \"enterprise\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\" as const,\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\" as const,\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\" as const,\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\" as const,\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"show-token\": {\n type: \"boolean\" as const,\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\" as const,\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n \"extended-betas\": {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Forward extended beta headers for Claude CLI compatibility (default: VS Code-only)\",\n },\n} as const\n\nconst allowedAccountTypes = new Set([\"individual\", \"business\", \"enterprise\"])\n\n/** Parse shared server args into ServerSetupOptions fields. */\nexport function parseSharedArgs(args: Record<string, unknown>): {\n port?: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n showToken: boolean\n proxyEnv: boolean\n extendedBetas: boolean\n} {\n const portRaw = args.port as string | undefined\n let port: number | undefined\n if (portRaw !== undefined) {\n port = Number.parseInt(portRaw, 10)\n if (Number.isNaN(port) || port <= 0 || port > 65535) {\n throw new Error(\"Invalid port. Must be between 1 and 65535.\")\n }\n }\n\n const accountType = (args[\"account-type\"] as string) ?? \"enterprise\"\n if (!allowedAccountTypes.has(accountType)) {\n throw new Error(\n \"Invalid account type. Must be individual, business, or enterprise.\",\n )\n }\n\n const rateLimitRaw = args[\"rate-limit\"] as string | undefined\n let rateLimit: number | undefined\n if (rateLimitRaw !== undefined) {\n rateLimit = Number.parseInt(rateLimitRaw, 10)\n if (Number.isNaN(rateLimit) || rateLimit <= 0) {\n throw new Error(\"Invalid rate limit. Must be a positive integer.\")\n }\n }\n\n const rateLimitWait = (args.wait as boolean) && rateLimit !== undefined\n if ((args.wait as boolean) && rateLimit === undefined) {\n consola.warn(\"Rate limit wait ignored because no rate limit was set.\")\n }\n\n const githubToken =\n (args[\"github-token\"] as string | undefined) ?? process.env.GH_TOKEN\n\n return {\n port,\n verbose: args.verbose as boolean,\n accountType,\n manual: args.manual as boolean,\n rateLimit,\n rateLimitWait,\n githubToken,\n showToken: args[\"show-token\"] as boolean,\n proxyEnv: args[\"proxy-env\"] as boolean,\n extendedBetas: args[\"extended-betas\"] as boolean,\n }\n}\n\n/** Build environment variables for Claude Code. */\nexport function getClaudeCodeEnvVars(\n serverUrl: string,\n model?: string,\n): Record<string, string> {\n const vars: Record<string, string> = {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n }\n if (model) vars.ANTHROPIC_MODEL = model\n return vars\n}\n\n/** Build environment variables for Codex CLI. */\nexport function getCodexEnvVars(serverUrl: string): Record<string, string> {\n return {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n }\n}\n","import process from \"node:process\"\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { enableFileLogging } from \"./lib/file-log-reporter\"\nimport { launchChild } from \"./lib/launch\"\nimport { listModelsForEndpoint } from \"./lib/model-validation\"\nimport {\n getClaudeCodeEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { state } from \"./lib/state\"\nimport { resolveModel } from \"./lib/utils\"\n\nexport const claude = defineCommand({\n meta: {\n name: \"claude\",\n description: \"Start the proxy server and launch Claude Code\",\n },\n args: {\n ...sharedServerArgs,\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model for Claude Code\",\n },\n },\n async run({ args }) {\n if (!process.stdout.isTTY) {\n consola.error(\"The claude subcommand requires a TTY (interactive terminal).\")\n process.exit(1)\n }\n\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n let server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]\n let serverUrl: string\n try {\n const result = await setupAndServe({\n ...parsed,\n port: parsed.port, // undefined = random port\n silent: true,\n })\n server = result.server\n serverUrl = result.serverUrl\n } catch (error) {\n consola.error(\"Failed to start server:\", error instanceof Error ? error.message : error)\n process.exit(1)\n }\n\n enableFileLogging() // redirect errors/warnings to file; suppress terminal output\n\n // Validate model if overridden (warnings go to log file, not terminal)\n let resolvedModel: string | undefined\n if (args.model) {\n resolvedModel = resolveModel(args.model)\n if (resolvedModel !== args.model) {\n consola.info(`Model \"${args.model}\" resolved to \"${resolvedModel}\"`)\n }\n const modelEntry = state.models?.data.find((m) => m.id === resolvedModel)\n if (!modelEntry) {\n const available = listModelsForEndpoint(\"/v1/messages\")\n consola.warn(\n `Model \"${resolvedModel}\" not found. Available claude models: ${available.join(\", \")}`,\n )\n }\n }\n\n // Print to stderr directly — consola's terminal reporter is already gone\n process.stderr.write(`Server ready on ${serverUrl}, launching Claude Code...\\n`)\n\n const envVars = getClaudeCodeEnvVars(serverUrl, resolvedModel ?? args.model)\n const extraArgs = ((args as unknown as Record<string, unknown>)._ as string[]) ?? []\n\n launchChild(\n { kind: \"claude-code\", envVars, extraArgs, model: resolvedModel ?? args.model },\n server,\n )\n },\n})\n","import process from \"node:process\"\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { enableFileLogging } from \"./lib/file-log-reporter\"\nimport { launchChild } from \"./lib/launch\"\nimport { listModelsForEndpoint } from \"./lib/model-validation\"\nimport { DEFAULT_CODEX_MODEL } from \"./lib/port\"\nimport {\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { state } from \"./lib/state\"\nimport { resolveCodexModel } from \"./lib/utils\"\n\nexport const codex = defineCommand({\n meta: {\n name: \"codex\",\n description: \"Start the proxy server and launch Codex CLI\",\n },\n args: {\n ...sharedServerArgs,\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model for Codex CLI\",\n },\n },\n async run({ args }) {\n if (!process.stdout.isTTY) {\n consola.error(\"The codex subcommand requires a TTY (interactive terminal).\")\n process.exit(1)\n }\n\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n let server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]\n let serverUrl: string\n try {\n const result = await setupAndServe({\n ...parsed,\n port: parsed.port, // undefined = random port\n silent: true,\n })\n server = result.server\n serverUrl = result.serverUrl\n } catch (error) {\n consola.error(\"Failed to start server:\", error instanceof Error ? error.message : error)\n process.exit(1)\n }\n\n const requestedModel = args.model ?? DEFAULT_CODEX_MODEL\n\n // Resolve model before printing success message (so we show the actual model)\n // but enable file logging first so resolution warnings go to file, not terminal\n enableFileLogging()\n\n const codexModel = resolveCodexModel(requestedModel)\n if (codexModel !== requestedModel) {\n consola.info(`Model \"${requestedModel}\" resolved to \"${codexModel}\"`)\n }\n\n // Validate model exists in Copilot model list\n const modelEntry = state.models?.data.find((m) => m.id === codexModel)\n if (!modelEntry) {\n const available = listModelsForEndpoint(\"/responses\")\n consola.warn(\n `Model \"${codexModel}\" not found. Available codex models: ${available.join(\", \")}`,\n )\n } else {\n const ctx = modelEntry.capabilities?.limits?.max_context_window_tokens\n if (ctx) consola.info(`Model context window: ${ctx.toLocaleString()} tokens`)\n }\n\n // Print to stderr directly — consola's terminal reporter is already gone\n process.stderr.write(`Server ready on ${serverUrl}, launching Codex CLI (${codexModel})...\\n`)\n\n const envVars = getCodexEnvVars(serverUrl)\n const extraArgs = ((args as unknown as Record<string, unknown>)._ as string[]) ?? []\n\n launchChild(\n { kind: \"codex\", envVars, extraArgs, model: codexModel },\n server,\n )\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`github-router debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, env } = process\n\n if (platform === \"win32\") {\n // Git Bash / MSYS2 / Cygwin set SHELL even on Windows\n if (env.SHELL) {\n if (env.SHELL.endsWith(\"zsh\")) return \"zsh\"\n if (env.SHELL.endsWith(\"fish\")) return \"fish\"\n if (env.SHELL.endsWith(\"bash\")) return \"bash\"\n return \"sh\"\n }\n\n // Windows PowerShell 5.x sets this\n if (env.POWERSHELL_DISTRIBUTION_CHANNEL) return \"powershell\"\n\n // PowerShell (both 5.x and 7+/pwsh) adds user-scoped module paths\n // at runtime. The system-level PSModulePath in CMD lacks these paths.\n if (env.PSModulePath) {\n const lower = env.PSModulePath.toLowerCase()\n if (\n lower.includes(\"documents\\\\powershell\")\n || lower.includes(\"documents\\\\windowspowershell\")\n ) {\n return \"powershell\"\n }\n }\n\n return \"cmd\"\n }\n\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n}\n\nfunction quotePosixValue(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nfunction quotePowerShellValue(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${quotePowerShellValue(value)}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set \"${key}=${value}\"`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${quotePosixValue(value)}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${quotePosixValue(value)}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator =\n shell === \"cmd\" ? \" & \" : shell === \"powershell\" ? \"; \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\n\nimport { generateEnvScript } from \"./lib/shell\"\nimport { DEFAULT_CODEX_MODEL, DEFAULT_PORT } from \"./lib/port\"\nimport {\n getClaudeCodeEnvVars,\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\n\nfunction printAndCopyCommand(command: string, label: string): void {\n consola.box(`${label}\\n\\n${command}`)\n try {\n clipboard.writeSync(command)\n consola.success(`Copied ${label} command to clipboard!`)\n } catch {\n consola.warn(\"Failed to copy to clipboard. Copy the command above manually.\")\n }\n}\n\nfunction generateClaudeCodeCommand(serverUrl: string, model?: string) {\n const envVars = getClaudeCodeEnvVars(serverUrl, model)\n const command = generateEnvScript(envVars, \"claude --dangerously-skip-permissions\")\n printAndCopyCommand(command, \"Claude Code\")\n}\n\nfunction generateCodexCommand(serverUrl: string, model?: string) {\n const codexModel = model ?? DEFAULT_CODEX_MODEL\n const envVars = getCodexEnvVars(serverUrl)\n const command = generateEnvScript(envVars, `codex -m ${codexModel}`)\n printAndCopyCommand(command, \"Codex CLI\")\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the github-router server\",\n },\n args: {\n ...sharedServerArgs,\n cc: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n cx: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Codex CLI with Copilot API config\",\n },\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model (used with --cc or --cx)\",\n },\n },\n async run({ args }) {\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n const { serverUrl } = await setupAndServe({\n ...parsed,\n port: parsed.port ?? DEFAULT_PORT,\n silent: false,\n })\n\n if (args.cc) generateClaudeCodeCommand(serverUrl, args.model)\n if (args.cx) generateCodexCommand(serverUrl, args.model)\n\n consola.box(\n `🌐 Usage Viewer: https://animeshkundu.github.io/github-router/dashboard.html?endpoint=${serverUrl}/usage`,\n )\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\nimport consola from \"consola\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { claude } from \"./claude\"\nimport { codex } from \"./codex\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nprocess.on(\"unhandledRejection\", (error) => {\n consola.error(\"Unhandled rejection:\", error)\n})\n\nprocess.on(\"uncaughtException\", (error) => {\n consola.error(\"Uncaught exception:\", error)\n process.exit(1)\n})\n\nconst main = defineCommand({\n meta: {\n name: \"github-router\",\n description:\n \"A reverse proxy that exposes GitHub Copilot as OpenAI and Anthropic compatible API endpoints.\",\n },\n subCommands: { auth, start, claude, codex, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","parsed: URL","FALLBACK","token","size: number","fs","sanitized: NodeJS.ProcessEnv","process","child: ChildProcess","server","ENDPOINT_ALIASES: Record<string, Endpoint>","path","state","parts: Array<string>","x","headers: Record<string, string>","searchTimestamps: Array<number>","headers: Record<string, string>","sid: string | undefined","rpc: z.infer<typeof RpcSchema> | undefined","parsedJson: unknown","innerRaw: unknown","references: Array<{ title: string; url: string }>","handleCompletion","injectWebSearchIfNeeded","inputTokens: number | undefined","isNonStreaming","extractUserQuery","handleCompletion","isWebSearchTool","body: AnyRecord","resolveModelInBody","extraHeaders: Record<string, string>","parsed: AnyRecord","sanitizeCacheControl","headers: Record<string, string>","extractUserQuery","body: AnyRecord","response: Response","streamHeaders: Record<string, string>","parsed: AnyRecord","best: (typeof EFFORT_ORDER)[number] | undefined","headers: Record<string, string>","payload: ResponsesPayload","result: ResponsesApiResponse","app","srvxServer: ReturnType<typeof serve> | undefined","lastError: unknown","port: number | undefined","rateLimit: number | undefined","vars: Record<string, string>","process","server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]","serverUrl: string","server","process","server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]","serverUrl: string","server","process","commandBlock: string"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-copilot-version.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/lib/file-log-reporter.ts","../src/lib/port.ts","../src/lib/launch.ts","../src/lib/model-validation.ts","../src/lib/proxy.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/request-log.ts","../src/lib/tokenizer.ts","../src/services/copilot/create-chat-completions.ts","../src/services/copilot/web-search.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/services/copilot/create-messages.ts","../src/routes/messages/count-tokens-handler.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/services/copilot/create-responses.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/search/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/lib/server-setup.ts","../src/claude.ts","../src/codex.ts","../src/debug.ts","../src/lib/shell.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nfunction appDir(): string {\n return path.join(os.homedir(), \".local\", \"share\", \"github-router\")\n}\n\nexport const PATHS = {\n get APP_DIR() {\n return appDir()\n },\n get GITHUB_TOKEN_PATH() {\n return path.join(appDir(), \"github_token\")\n },\n get ERROR_LOG_PATH() {\n return path.join(appDir(), \"error.log\")\n },\n /**\n * Isolated CODEX_HOME for the spawned Codex CLI. Masks any cached\n * ChatGPT subscription login (openai/codex#2733 — cached login can\n * override OPENAI_API_KEY) so the proxy's dummy key is authoritative.\n */\n get CODEX_HOME() {\n return path.join(appDir(), \"codex-isolated\")\n },\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await fs.mkdir(PATHS.CODEX_HOME, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import { randomBytes, randomUUID } from \"node:crypto\"\n\nimport type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n copilotApiUrl?: string\n models?: ModelsResponse\n vsCodeVersion?: string\n copilotVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n extendedBetas: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n\n // Persistent session identifiers to match VS Code fingerprint\n sessionId: string\n machineId: string\n}\n\nexport const state: State = {\n accountType: \"enterprise\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n extendedBetas: false,\n sessionId: randomUUID(),\n machineId: randomBytes(32).toString(\"hex\"),\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst DEFAULT_COPILOT_VERSION = \"0.43.2026033101\"\n\nexport function copilotVersion(state: State): string {\n return state.copilotVersion ?? DEFAULT_COPILOT_VERSION\n}\n\nconst API_VERSION = \"2026-01-09\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.copilotApiUrl ?? \"https://api.githubcopilot.com\"\nexport const copilotHeaders = (\n state: State,\n vision: boolean = false,\n integrationId: string = \"vscode-chat\",\n) => {\n const version = copilotVersion(state)\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": integrationId,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": `copilot-chat/${version}`,\n \"user-agent\": `GitHubCopilotChat/${version}`,\n \"openai-intent\": \"conversation-panel\",\n \"x-interaction-type\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n \"VScode-SessionId\": state.sessionId,\n \"VScode-MachineId\": state.machineId,\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL =\n process.env.GITHUB_API_URL ?? \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": `copilot-chat/${copilotVersion(state)}`,\n \"user-agent\": `GitHubCopilotChat/${copilotVersion(state)}`,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text().catch(() => \"\")\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = undefined\n }\n\n // Map upstream context-overflow errors (413, or 400 with a known\n // overflow substring) to Anthropic's \"prompt is too long\" 400 shape so\n // Claude Code triggers self-compaction instead of bubbling the error.\n // Note: a live probe of an oversized prompt against Copilot returned\n // 200 with stop_reason:\"refusal\" rather than 413/400 — this guard is\n // defensive for the documented Anthropic contract, not load-bearing.\n if (isContextOverflow(error.response.status, errorJson, errorText)) {\n const upstream = resolveErrorMessage(errorJson, errorText)\n consola.error(\"HTTP error (mapped to overflow):\", errorJson ?? errorText)\n return c.json(\n {\n type: \"error\",\n error: {\n type: \"invalid_request_error\",\n message: `prompt is too long: ${upstream}`,\n },\n },\n 400,\n )\n }\n\n // Forward upstream Anthropic-format errors as-is\n if (isAnthropicError(errorJson)) {\n consola.error(\"HTTP error:\", errorJson)\n return c.json(errorJson, error.response.status as ContentfulStatusCode)\n }\n\n const message = resolveErrorMessage(errorJson, errorText)\n consola.error(\"HTTP error:\", errorJson ?? errorText)\n return c.json(\n {\n type: \"error\",\n error: {\n type: resolveErrorType(error.response.status),\n message,\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n type: \"error\",\n error: {\n type: \"api_error\",\n message: error instanceof Error ? error.message : String(error),\n },\n },\n 500,\n )\n}\n\n// Extracts error message from { message } or { error: { message } } payloads.\nfunction resolveErrorMessage(errorJson: unknown, fallback: string): string {\n if (typeof errorJson !== \"object\" || errorJson === null) return fallback\n\n const errorRecord = errorJson as Record<string, unknown>\n if (errorRecord.message !== undefined) return String(errorRecord.message)\n\n if (typeof errorRecord.error === \"object\" && errorRecord.error !== null) {\n const nestedRecord = errorRecord.error as Record<string, unknown>\n if (nestedRecord.message !== undefined) return String(nestedRecord.message)\n }\n\n return fallback\n}\n\n/**\n * Check if a parsed JSON body is already in Anthropic error format:\n * { type: \"error\", error: { type: \"...\", message: \"...\" } }\n */\nfunction isAnthropicError(json: unknown): boolean {\n if (typeof json !== \"object\" || json === null) return false\n const record = json as Record<string, unknown>\n if (record.type !== \"error\") return false\n if (typeof record.error !== \"object\" || record.error === null) return false\n const inner = record.error as Record<string, unknown>\n return typeof inner.type === \"string\" && typeof inner.message === \"string\"\n}\n\nconst CONTEXT_OVERFLOW_SUBSTRINGS = [\n \"prompt is too long\",\n \"context_length_exceeded\",\n \"context length exceeded\",\n \"input is too long\",\n \"maximum context length\",\n \"too many tokens\",\n]\n\n/**\n * Detect upstream context-overflow errors so we can remap them to a 400\n * \"prompt is too long\" shape that triggers Claude Code self-compaction.\n *\n * Always remaps 413 (treated as a hard payload-size signal regardless of\n * body wording). Remaps 400 only when the error text contains one of the\n * known overflow substrings — a regular 400 (e.g. \"model not found\") must\n * NOT remap.\n */\nexport function isContextOverflow(\n status: number,\n errorJson: unknown,\n errorText: string,\n): boolean {\n if (status === 413) return true\n if (status !== 400) return false\n\n const haystack = (\n errorText +\n \" \" +\n (typeof errorJson === \"object\" && errorJson !== null\n ? JSON.stringify(errorJson)\n : \"\")\n ).toLowerCase()\n\n return CONTEXT_OVERFLOW_SUBSTRINGS.some((s) => haystack.includes(s))\n}\n\n/**\n * Map HTTP status to Anthropic error type.\n */\nfunction resolveErrorType(status: number): string {\n if (status === 400) return \"invalid_request_error\"\n if (status === 401) return \"authentication_error\"\n if (status === 403) return \"permission_error\"\n if (status === 404) return \"not_found_error\"\n if (status === 429) return \"rate_limit_error\"\n if (status === 529) return \"overloaded_error\"\n return \"api_error\"\n}\n","import consola from \"consola\"\n\nimport { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Allowlist of hosts the router will trust as the Copilot API base URL.\n * Anything else returned in `endpoints.api` (e.g. via a tampered or\n * misconfigured token-exchange response) is rejected — otherwise a\n * malicious value would receive the long-lived GitHub PAT we send to\n * `/mcp` for web search (see `src/services/copilot/web-search.ts`).\n */\nconst COPILOT_HOST_ALLOWLIST = [\n \"api.githubcopilot.com\",\n \"api.individual.githubcopilot.com\",\n \"api.business.githubcopilot.com\",\n \"api.enterprise.githubcopilot.com\",\n]\n\nfunction isAllowedCopilotHost(rawUrl: string): boolean {\n let parsed: URL\n try {\n parsed = new URL(rawUrl)\n } catch {\n return false\n }\n if (parsed.protocol !== \"https:\") return false\n return COPILOT_HOST_ALLOWLIST.includes(parsed.hostname)\n}\n\nexport const getCopilotToken = async () => {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n const data = (await response.json()) as GetCopilotTokenResponse\n\n // Use the API base URL from the token response if available, matching\n // how VS Code determines the CAPI endpoint dynamically — but only when\n // it points at a github-controlled host (see allowlist above).\n // We deliberately do NOT clobber an existing `state.copilotApiUrl` in\n // the disallowed branch: when the user sets `COPILOT_API_URL` themselves\n // (e.g. for local testing or a CI mock), that's an explicit opt-in and\n // a different threat model than a tampered token-exchange response.\n // Allowlist-failing token-response values are simply ignored.\n if (data.endpoints?.api) {\n if (isAllowedCopilotHost(data.endpoints.api)) {\n state.copilotApiUrl = data.endpoints.api\n } else {\n consola.warn(\n `Refusing to honor Copilot API endpoint \"${data.endpoints.api}\" from ` +\n `the token-exchange response — not in allowlist ` +\n `(${COPILOT_HOST_ALLOWLIST.join(\", \")}). ` +\n (state.copilotApiUrl\n ? `Keeping existing override \"${state.copilotApiUrl}\".`\n : `Falling back to the default api.githubcopilot.com.`),\n )\n }\n }\n\n return data\n}\n\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n endpoints?: {\n api?: string\n proxy?: string\n telemetry?: string\n \"origin-tracker\"?: string\n }\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n max_non_streaming_output_tokens?: number\n vision?: {\n max_prompt_image_size?: number\n max_prompt_images?: number\n supported_media_types?: string[]\n }\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n streaming?: boolean\n vision?: boolean\n structured_outputs?: boolean\n adaptive_thinking?: boolean\n max_thinking_budget?: number\n min_thinking_budget?: number\n reasoning_effort?: Array<string>\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\nexport interface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n supported_endpoints?: Array<string>\n requestHeaders?: Record<string, string>\n policy?: {\n state: string\n terms: string\n }\n billing?: {\n is_premium: boolean\n multiplier: number\n restricted_to?: string[]\n }\n is_chat_default?: boolean\n is_chat_fallback?: boolean\n model_picker_category?: string\n info_messages?: Array<{ code: string; message: string }>\n}\n","const FALLBACK = \"0.43.2026033101\"\n\ninterface MarketplaceResult {\n results: Array<{\n extensions: Array<{\n versions: Array<{ version: string }>\n }>\n }>\n}\n\nexport async function getCopilotChatVersion(): Promise<string> {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery\",\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json;api-version=7.1-preview.1\",\n },\n body: JSON.stringify({\n filters: [\n {\n criteria: [{ filterType: 7, value: \"GitHub.copilot-chat\" }],\n },\n ],\n flags: 914,\n }),\n signal: controller.signal,\n },\n )\n\n if (!response.ok) return FALLBACK\n\n const data = (await response.json()) as MarketplaceResult\n const version =\n data?.results?.[0]?.extensions?.[0]?.versions?.[0]?.version\n\n return version ?? FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n","const FALLBACK = \"1.104.3\"\n\nexport async function getVSCodeVersion() {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n {\n signal: controller.signal,\n },\n )\n\n const pkgbuild = await response.text()\n const pkgverRegex = /pkgver=([0-9.]+)/\n const match = pkgbuild.match(pkgverRegex)\n\n if (match) {\n return match[1]\n }\n\n return FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getCopilotChatVersion } from \"~/services/get-copilot-version\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\n/**\n * Beta prefixes VS Code Copilot Chat v0.43 actually sends.\n * Default mode — makes proxy traffic indistinguishable from VS Code.\n */\nconst VSCODE_BETA_PREFIXES = [\n \"interleaved-thinking-\",\n \"context-management-\",\n \"advanced-tool-use-\",\n]\n\n/**\n * Extended beta prefixes for Claude CLI compatibility.\n * Enabled via --extended-betas flag. Includes all betas confirmed\n * to work with the Copilot API.\n *\n * Notably absent (Copilot 400s on these — verified live):\n * context-1m-, skills-, files-api-, code-execution-, output-128k-.\n * 1M context is unlocked by selecting `claude-opus-4.7-1m-internal`\n * as the model id, not via a beta header.\n */\nconst EXTENDED_BETA_PREFIXES = [\n ...VSCODE_BETA_PREFIXES,\n \"claude-code-\",\n \"effort-\",\n \"prompt-caching-\",\n \"computer-use-\",\n \"pdfs-\",\n \"max-tokens-\",\n \"token-counting-\",\n \"compact-\",\n \"structured-outputs-\",\n \"fast-mode-\",\n \"mcp-client-\",\n \"mcp-servers-\",\n \"redact-thinking-\",\n \"web-search-\",\n]\n\n/**\n * Filter an `anthropic-beta` header value, keeping only beta flags\n * in the active whitelist. Uses extended prefixes when --extended-betas\n * is enabled, VS Code-only prefixes otherwise.\n * Returns the filtered comma-separated string, or undefined if nothing remains.\n */\nexport function filterBetaHeader(value: string): string | undefined {\n const prefixes = state.extendedBetas\n ? EXTENDED_BETA_PREFIXES\n : VSCODE_BETA_PREFIXES\n const filtered = value\n .split(\",\")\n .map((v) => v.trim())\n .filter(\n (v) =>\n v && prefixes.some((prefix) => v.startsWith(prefix)),\n )\n .join(\",\")\n return filtered || undefined\n}\n\n/**\n * Normalize a model ID for fuzzy comparison: lowercase, replace dots with\n * dashes, insert dash at letter→digit boundaries, and collapse repeated\n * dashes. E.g. \"gpt5.3-codex\" → \"gpt-5-3-codex\", \"GPT-5.3-Codex\" → \"gpt-5-3-codex\".\n */\nexport function normalizeModelId(id: string): string {\n return id\n .toLowerCase()\n .replace(/\\./g, \"-\")\n .replace(/([a-z])(\\d)/g, \"$1-$2\")\n .replace(/-{2,}/g, \"-\")\n}\n\n/**\n * Resolve a model name to the best available variant in the Copilot model list.\n *\n * Resolution cascade:\n * 1. Exact match\n * 2. Case-insensitive match\n * 3. Family preference (opus→1m, codex→highest version)\n * 4. Normalized match (dots→dashes, letter-digit boundaries)\n * 5. Return as-is with a warning\n */\nexport function resolveModel(modelId: string): string {\n const models = state.models?.data\n if (!models) return modelId\n\n // 1. Exact match\n if (models.some((m) => m.id === modelId)) return modelId\n\n // 2. Case-insensitive match\n const lower = modelId.toLowerCase()\n const ciMatch = models.find((m) => m.id.toLowerCase() === lower)\n if (ciMatch) return ciMatch.id\n\n // 3. Family preference — before normalization so product aliases\n // (opus→1m, codex→latest) take priority over fuzzy matches\n if (lower.includes(\"opus\")) {\n // Match ...-1m or ...-1m-<anything> (e.g. claude-opus-4.7-1m-internal).\n // Prefer the 1M variant whose major.minor matches the requested version,\n // otherwise find() would silently downgrade claude-opus-4.7 to a\n // claude-opus-4.6-1m if the latter happens to come first in the list.\n // Accept both dotted (\"opus-4.7\") and dashed (\"opus-4-7\") inputs —\n // Claude Code historically sends the dashed form.\n const oneMs = models.filter(\n (m) => m.id.includes(\"opus\") && /-1m(?:$|-)/.test(m.id),\n )\n const versionMatch = lower.match(/opus-(\\d+)[.-](\\d+)/)\n const requestedVersion =\n versionMatch ? `${versionMatch[1]}.${versionMatch[2]}` : undefined\n const preferred = requestedVersion\n ? oneMs.find((m) => m.id.includes(`opus-${requestedVersion}-`))\n : undefined\n const oneM = preferred ?? oneMs[0]\n if (oneM) return oneM.id\n }\n\n if (lower.includes(\"codex\")) {\n const codexModels = models.filter(\n (m) => m.id.includes(\"codex\") && !m.id.includes(\"mini\"),\n )\n if (codexModels.length > 0) {\n codexModels.sort((a, b) => b.id.localeCompare(a.id))\n return codexModels[0].id\n }\n }\n\n // 4. Normalized match (dots → dashes, letter-digit boundaries)\n const normalized = normalizeModelId(modelId)\n const normMatch = models.find(\n (m) => normalizeModelId(m.id) === normalized,\n )\n if (normMatch) return normMatch.id\n\n // 5. No match — warn and return as-is\n consola.warn(\n `Model \"${modelId}\" not found in Copilot model list. Available: ${models.map((m) => m.id).join(\", \")}`,\n )\n return modelId\n}\n\n/**\n * Resolve a codex model ID, falling back to the best available codex model.\n * Used by the codex subcommand for model selection.\n */\nexport function resolveCodexModel(modelId: string): string {\n const resolved = resolveModel(modelId)\n const models = state.models?.data\n if (!models) return resolved\n\n // Check if the resolved model exists in the model list\n if (models.some((m) => m.id === resolved)) return resolved\n\n // Fall back to the best available codex-class model. The /responses\n // endpoint is the discriminator — gpt-5.5 dropped the -codex suffix but\n // still routes through /responses. Prefer explicit -codex ids when both\n // exist, otherwise pick the highest version-like id.\n const candidates = models.filter((m) => {\n const endpoints = m.supported_endpoints ?? []\n if (m.id.includes(\"mini\") || m.id.includes(\"nano\")) return false\n return endpoints.length === 0 || endpoints.includes(\"/responses\")\n })\n\n if (candidates.length > 0) {\n candidates.sort((a, b) => {\n const aCodex = a.id.includes(\"codex\") ? 1 : 0\n const bCodex = b.id.includes(\"codex\") ? 1 : 0\n if (aCodex !== bCodex) return bCodex - aCodex\n return b.id.localeCompare(a.id)\n })\n const best = candidates[0].id\n consola.warn(`Model \"${modelId}\" not available, using \"${best}\" instead`)\n return best\n }\n\n return resolved\n}\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n\nexport const cacheCopilotVersion = async () => {\n const version = await getCopilotChatVersion()\n state.copilotVersion = version\n\n consola.info(`Using Copilot Chat version: ${version}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n const expiresAt = Date.now() + deviceCode.expires_in * 1000\n\n while (Date.now() < expiresAt) {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to poll access token:\", await response.text())\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n }\n\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n }\n\n throw new Error(\"Device code expired. Please run auth again.\")\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = Math.max((refresh_in - 60) * 1000, 1000)\n setInterval(async () => {\n consola.debug(\"Refreshing Copilot token\")\n try {\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n }\n }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(state),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","import fs from \"node:fs\"\nimport { Writable } from \"node:stream\"\n\nimport consola from \"consola\"\nimport type { ConsolaOptions, ConsolaReporter, LogObject } from \"consola\"\n\nimport { PATHS } from \"~/lib/paths\"\n\nconst MAX_LOG_BYTES = 1024 * 1024 // 1 MB\nconst DEDUP_MAX = 1000\nconst ARG_MAX_LEN = 2048\nconst DEDUP_KEY_MAX_LEN = 200\n\nconst CREDENTIAL_RE =\n /\\b(eyJ[A-Za-z0-9_-]{20,}(?:\\.[A-Za-z0-9_-]+){0,2}|gh[opsu]_[A-Za-z0-9_]{20,}|Bearer\\s+\\S{20,})\\b/g\n\nconst ALLOWED_TYPES = new Set([\"fatal\", \"error\", \"warn\"])\n\nfunction sanitize(line: string): string {\n return line.replace(CREDENTIAL_RE, \"[REDACTED]\")\n}\n\nfunction serializeArg(arg: unknown): string {\n if (typeof arg === \"string\") return arg\n if (arg instanceof Error) {\n const parts = [arg.message]\n if (arg.stack) parts.push(arg.stack)\n return parts.join(\"\\n\")\n }\n return String(arg)\n}\n\nfunction formatLogLine(logObj: LogObject): string {\n const ts = logObj.date.toISOString()\n const level = (logObj.type ?? \"error\").toUpperCase()\n const message = logObj.args\n .map((a) => {\n const s = serializeArg(a)\n return s.length > ARG_MAX_LEN ? s.slice(0, ARG_MAX_LEN) + \"…\" : s\n })\n .join(\" \")\n .replace(/\\r\\n|\\r|\\n/g, \"\\\\n\")\n\n return sanitize(`${ts} [${level}] ${message}\\n`)\n}\n\nfunction makeDedupeKey(logObj: LogObject): string {\n const firstArg =\n logObj.args.length > 0 ? serializeArg(logObj.args[0]) : \"\"\n const key = `${logObj.type}:${firstArg}`\n return key.length > DEDUP_KEY_MAX_LEN\n ? key.slice(0, DEDUP_KEY_MAX_LEN)\n : key\n}\n\nfunction rotateIfNeeded(filePath: string): void {\n let size: number\n try {\n size = fs.statSync(filePath).size\n } catch {\n return // file does not exist\n }\n if (size <= MAX_LOG_BYTES) return\n\n try {\n fs.renameSync(filePath, filePath + \".1\")\n } catch {\n // best-effort: if rename fails, continue with the existing file\n }\n}\n\nexport class FileLogReporter implements ConsolaReporter {\n private readonly filePath: string\n private readonly seen = new Set<string>()\n private writing = false\n\n constructor(filePath: string) {\n this.filePath = filePath\n rotateIfNeeded(filePath)\n }\n\n log(logObj: LogObject, _ctx: { options: ConsolaOptions }): void {\n if (!ALLOWED_TYPES.has(logObj.type)) return\n if (this.writing) return // re-entrancy guard\n\n const key = makeDedupeKey(logObj)\n if (this.seen.has(key)) return\n\n if (this.seen.size >= DEDUP_MAX) this.seen.clear()\n this.seen.add(key)\n\n const line = formatLogLine(logObj)\n\n this.writing = true\n try {\n // Always open with explicit mode to ensure 0o600 even if file was\n // deleted between writes and appendFileSync would recreate it as 0o644\n const fd = fs.openSync(this.filePath, \"a\", 0o600)\n fs.writeSync(fd, line)\n fs.closeSync(fd)\n } catch {\n // Silently discard — cannot log a logging failure\n } finally {\n this.writing = false\n }\n }\n}\n\nconst nullStream = new Writable({ write(_chunk, _encoding, cb) { cb() } })\n\n/**\n * Switch consola to file-only mode for TUI sessions.\n * Removes the terminal reporter and installs a file reporter that\n * persists errors and warnings to disk with dedup and credential scrubbing.\n *\n * Also sinks consola's stdout/stderr streams as belt-and-suspenders:\n * even if a terminal reporter is re-added, it cannot write to the terminal.\n * Crash handlers that call process.stderr.write() directly are unaffected.\n * FileLogReporter uses fs.writeSync() directly and is also unaffected.\n */\nexport function enableFileLogging(): void {\n const reporter = new FileLogReporter(PATHS.ERROR_LOG_PATH)\n consola.options.throttle = 0 // disable built-in dedup\n consola.setReporters([reporter])\n consola.options.stdout = nullStream as unknown as typeof process.stdout\n consola.options.stderr = nullStream as unknown as typeof process.stderr\n}\n","export const DEFAULT_PORT = 8787\n\n/**\n * Default model for `github-router claude`. The Anthropic-published dashed\n * slug (`claude-opus-4-7`) — NOT the Copilot-internal slug\n * (`claude-opus-4.7-1m-internal`) — because Claude Code 2.1.126's `/model`\n * UI is backed by a hardcoded registry of Anthropic slugs, and an\n * unrecognized slug causes the menu to highlight \"Opus 4\" with a\n * \"Newer version available\" hint instead of \"Opus 4.7 (1M context)\".\n *\n * The proxy's `resolveModel` (`src/lib/utils.ts`) translates this to\n * Copilot's `claude-opus-4.7-1m-internal` (enterprise) or\n * `claude-opus-4.7` (Pro+/Business/Max) at request time via the\n * family-preference + version-match branch — round-trip covered by\n * `tests/lib-utils.test.ts:154`.\n *\n * `DEFAULT_CLAUDE_MODEL_FALLBACKS` covers major.minor regressions only;\n * 1M↔200K downgrade is handled inside the resolver, so we don't need\n * separate `-1m` entries here.\n */\nexport const DEFAULT_CLAUDE_MODEL = \"claude-opus-4-7\"\nexport const DEFAULT_CLAUDE_MODEL_FALLBACKS = [\n \"claude-opus-4-6\",\n \"claude-opus-4-5\",\n] as const\n\n/**\n * Default model for `github-router codex`. `gpt-5.5` is the new flagship\n * `/responses` model; the fallback chain handles older Copilot tiers where\n * 5.5 hasn't rolled out yet. `resolveCodexModel` provides a final\n * \"best available `/responses` model\" safety net beyond this list.\n */\nexport const DEFAULT_CODEX_MODEL = \"gpt-5.5\"\nexport const DEFAULT_CODEX_MODEL_FALLBACKS = [\n \"gpt-5.4\",\n \"gpt-5.3-codex\",\n \"gpt-5.2-codex\",\n] as const\n\nconst PORT_RANGE_MIN = 11000\nconst PORT_RANGE_MAX = 65535\n\n/** Generate a random port number in the range [11000, 65535]. */\nexport function generateRandomPort(): number {\n return (\n Math.floor(Math.random() * (PORT_RANGE_MAX - PORT_RANGE_MIN + 1))\n + PORT_RANGE_MIN\n )\n}\n","import { execFileSync, spawn, type ChildProcess } from \"node:child_process\"\nimport process from \"node:process\"\n\nimport consola from \"consola\"\n\nimport type { Server } from \"srvx\"\n\nimport { DEFAULT_CODEX_MODEL } from \"./port\"\n\n/**\n * Auth-related env keys we strip from the parent before spawning the\n * child CLI. The proxy provides its own values for everything we care\n * about (ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, OPENAI_BASE_URL,\n * OPENAI_API_KEY, CODEX_HOME, ANTHROPIC_MODEL); for the rest, we want\n * the child to behave as if the user had no parent-env auth at all.\n *\n * Why strip rather than override-with-empty-string:\n * - Claude Code emits \"Auth conflict\" warnings whenever both\n * ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY are present (regardless\n * of value, even when both are \"dummy\"). Stripping API_KEY entirely\n * suppresses the warning AND prevents an inherited real shell key\n * from leaking via x-api-key.\n * - Cloud-provider toggles (CLAUDE_CODE_USE_*) and OAUTH_TOKEN, etc.\n * are simpler dropped than overridden — a missing env var is\n * unambiguously falsy/absent in every code path that reads it.\n */\nconst STRIPPED_PARENT_ENV_KEYS = [\n // Claude Code auth surface\n \"ANTHROPIC_API_KEY\",\n \"ANTHROPIC_AUTH_TOKEN\",\n \"ANTHROPIC_BASE_URL\",\n \"ANTHROPIC_CUSTOM_HEADERS\",\n \"ANTHROPIC_MODEL\",\n \"CLAUDE_CODE_OAUTH_TOKEN\",\n \"CLAUDE_CODE_USE_BEDROCK\",\n \"CLAUDE_CODE_USE_VERTEX\",\n \"CLAUDE_CODE_USE_FOUNDRY\",\n // Defense-in-depth: prevent a parent-set CLAUDE_CONFIG_DIR (e.g. an\n // alternate test profile) from silently leaking into the proxy session.\n // The proxy sets its own value to activate per-config-dir keychain\n // isolation (see `getClaudeCodeEnvVars` doc comment).\n \"CLAUDE_CONFIG_DIR\",\n // Codex CLI auth surface\n \"OPENAI_API_KEY\",\n \"OPENAI_BASE_URL\",\n \"CODEX_HOME\",\n] as const\n\n/**\n * Strip auth-related keys from a parent-process env object. The result\n * is suitable to spread into a spawned child's env BEFORE the proxy's\n * explicit overrides, so the proxy is the only source of truth for\n * auth — and stale shell exports can't leak through.\n */\nexport function sanitizeParentEnv(\n parent: NodeJS.ProcessEnv,\n): NodeJS.ProcessEnv {\n const sanitized: NodeJS.ProcessEnv = { ...parent }\n for (const key of STRIPPED_PARENT_ENV_KEYS) {\n delete sanitized[key]\n }\n return sanitized\n}\n\nfunction commandExists(name: string): boolean {\n try {\n execFileSync(process.platform === \"win32\" ? \"where.exe\" : \"which\", [name], {\n stdio: \"ignore\",\n })\n return true\n } catch {\n return false\n }\n}\n\nexport interface LaunchTarget {\n kind: \"claude-code\" | \"codex\"\n envVars: Record<string, string>\n extraArgs: string[]\n model?: string\n}\n\nexport function buildLaunchCommand(target: LaunchTarget): {\n cmd: string[]\n env: Record<string, string | undefined>\n} {\n const cmd: string[] =\n target.kind === \"claude-code\"\n ? [\"claude\", \"--dangerously-skip-permissions\", ...target.extraArgs]\n : [\"codex\", \"--full-auto\", \"-m\", target.model ?? DEFAULT_CODEX_MODEL, ...target.extraArgs]\n\n return {\n cmd,\n env: { ...sanitizeParentEnv(process.env), ...target.envVars },\n }\n}\n\nexport function launchChild(target: LaunchTarget, server: Server): void {\n const { cmd, env } = buildLaunchCommand(target)\n\n const executable = cmd[0]\n if (!commandExists(executable)) {\n const msg = `\"${executable}\" not found on PATH. Install it first, then try again.`\n consola.error(msg)\n process.stderr.write(msg + \"\\n\")\n process.exit(1)\n }\n\n let child: ChildProcess\n try {\n if (process.platform === \"win32\") {\n // On Windows, npm-installed binaries are .cmd scripts that need\n // shell execution. Use the full command as a single string to\n // avoid DEP0190 deprecation warning about shell + args.\n const quoted = cmd.map((a) => (a.includes(\" \") ? `\"${a}\"` : a)).join(\" \")\n child = spawn(quoted, [], {\n env,\n stdio: \"inherit\",\n shell: true,\n })\n } else {\n child = spawn(cmd[0], cmd.slice(1), {\n env,\n stdio: \"inherit\",\n })\n }\n } catch (error) {\n const msg = `Failed to launch ${executable}: ${error instanceof Error ? error.message : String(error)}`\n consola.error(msg)\n process.stderr.write(msg + \"\\n\")\n server.close(true).catch(() => {})\n process.exit(1)\n }\n\n let cleaned = false\n let exiting = false\n async function cleanup(): Promise<void> {\n if (cleaned) return\n cleaned = true\n\n try {\n child.kill()\n } catch {\n // Already exited\n }\n\n const timeout = setTimeout(() => process.exit(1), 5000)\n try {\n await server.close(true)\n } catch {\n // Server already closed\n }\n clearTimeout(timeout)\n }\n\n function exit(code: number): void {\n if (exiting) return\n exiting = true\n process.exit(code)\n }\n\n const onSignal = () => {\n cleanup().then(() => exit(130)).catch(() => exit(1))\n }\n process.on(\"SIGINT\", onSignal)\n process.on(\"SIGTERM\", onSignal)\n\n child.on(\"exit\", (exitCode, signal) => {\n // When killed by a signal, exitCode is null — derive from signal number\n const code = exitCode ?? (signal ? 128 : 1)\n cleanup().then(() => exit(code)).catch(() => exit(1))\n })\n child.on(\"error\", () => {\n cleanup().then(() => exit(1)).catch(() => exit(1))\n })\n}\n","import consola from \"consola\"\n\nimport { state } from \"./state\"\n\ntype Endpoint = \"/chat/completions\" | \"/responses\" | \"/v1/messages\"\n\nconst ENDPOINT_ALIASES: Record<string, Endpoint> = {\n \"/chat/completions\": \"/chat/completions\",\n \"/v1/chat/completions\": \"/chat/completions\",\n \"/responses\": \"/responses\",\n \"/v1/responses\": \"/responses\",\n \"/v1/messages\": \"/v1/messages\",\n}\n\n/**\n * Check whether a model supports the given endpoint, based on cached\n * `supported_endpoints` metadata from the Copilot `/models` response.\n *\n * Returns `true` (allow) when:\n * - the model is not found in the cache (don't block unknown models)\n * - the model has no `supported_endpoints` field (backward-compat)\n * - the endpoint is listed in `supported_endpoints`\n */\nexport function modelSupportsEndpoint(\n modelId: string,\n path: string,\n): boolean {\n const endpoint = ENDPOINT_ALIASES[path] ?? path\n const model = state.models?.data.find((m) => m.id === modelId)\n if (!model) return true\n\n const supported = model.supported_endpoints\n if (!supported || supported.length === 0) return true\n\n return supported.includes(endpoint)\n}\n\n/**\n * Log an error when a model is used on an endpoint it doesn't support.\n * Returns `true` if a mismatch was detected (for testing).\n */\nexport function logEndpointMismatch(\n modelId: string,\n path: string,\n): boolean {\n if (modelSupportsEndpoint(modelId, path)) return false\n\n const model = state.models?.data.find((m) => m.id === modelId)\n const supported = model?.supported_endpoints ?? []\n\n consola.error(\n `Model \"${modelId}\" does not support ${path}. `\n + `Supported endpoints: ${supported.join(\", \")}`,\n )\n return true\n}\n\n/**\n * Return model IDs that support the given endpoint.\n */\nexport function listModelsForEndpoint(path: string): string[] {\n const endpoint = ENDPOINT_ALIASES[path] ?? path\n const models = state.models?.data ?? []\n\n return models\n .filter((m) => {\n const supported = m.supported_endpoints\n if (!supported || supported.length === 0) return true\n return supported.includes(endpoint)\n })\n .map((m) => m.id)\n}\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected by user\",\n Response.json({ message: \"Request rejected by user\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n state.lastRequestTimestamp = Date.now()\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import consola from \"consola\"\n\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport interface RequestLogInfo {\n method: string\n path: string\n model?: string\n resolvedModel?: string\n inputTokens?: number\n outputTokens?: number\n status?: number\n streaming?: boolean\n errorBody?: string\n}\n\n/**\n * Format a number with K/M suffix for compact display.\n */\nfunction formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`\n return String(n)\n}\n\n/**\n * Build a context window summary: \"in:1.2K out:50 ctx:1.2K/1M (0.1%)\"\n */\nfunction formatTokenInfo(\n inputTokens: number | undefined,\n outputTokens: number | undefined,\n model: Model | undefined,\n): string | undefined {\n if (inputTokens === undefined) return undefined\n\n const parts: Array<string> = []\n const maxPrompt = model?.capabilities?.limits?.max_prompt_tokens\n\n if (maxPrompt) {\n const pct = ((inputTokens / maxPrompt) * 100).toFixed(1)\n parts.push(`in:${formatTokens(inputTokens)}/${formatTokens(maxPrompt)} (${pct}%)`)\n } else {\n parts.push(`in:${formatTokens(inputTokens)}`)\n }\n\n if (outputTokens !== undefined) {\n parts.push(`out:${formatTokens(outputTokens)}`)\n }\n\n return parts.join(\" \")\n}\n\n/**\n * Print a single summary line for a completed request.\n *\n * Examples:\n * POST /v1/messages claude-opus-4.6-1m in:1.2K/1M (0.1%) out:50 200 2.3s\n * POST /v1/messages claude-opus-4-6→claude-opus-4.6-1m in:743/1M (0.1%) 200 198ms\n * POST /v1/chat/completions claude-sonnet-4 in:15 out:16 200 2.1s stream\n */\nexport function logRequest(\n info: RequestLogInfo,\n model: Model | undefined,\n startTime: number,\n): void {\n const parts: Array<string> = []\n\n parts.push(`${info.method} ${info.path}`)\n\n // Model (show resolution arrow if remapped)\n if (info.resolvedModel && info.resolvedModel !== info.model) {\n parts.push(`${info.model}→${info.resolvedModel}`)\n } else if (info.resolvedModel ?? info.model) {\n parts.push((info.resolvedModel ?? info.model)!)\n }\n\n // Token info with context window fill\n const tokenInfo = formatTokenInfo(info.inputTokens, info.outputTokens, model)\n if (tokenInfo) {\n parts.push(tokenInfo)\n }\n\n // Status\n if (info.status !== undefined) {\n parts.push(String(info.status))\n }\n\n // Duration + streaming flag\n const elapsed = Date.now() - startTime\n const duration =\n elapsed >= 1000 ? `${(elapsed / 1000).toFixed(1)}s` : `${elapsed}ms`\n parts.push(info.streaming ? `${duration} stream` : duration)\n\n const line = parts.join(\" \")\n\n if (detectCapabilityMismatch(info, model)) {\n consola.error(`[MISMATCH] ${line}`)\n } else {\n consola.info(line)\n }\n}\n\n/**\n * Detect when the API rejects a request for token/context reasons\n * that contradict what the /models endpoint reported.\n */\nfunction detectCapabilityMismatch(\n info: RequestLogInfo,\n model: Model | undefined,\n): boolean {\n if (!info.errorBody || !model) return false\n if (!info.status || info.status < 400) return false\n\n const err = info.errorBody.toLowerCase()\n return (\n err.includes(\"token\") ||\n err.includes(\"context\") ||\n err.includes(\"too long\") ||\n err.includes(\"max_tokens\") ||\n err.includes(\"prompt is too long\")\n )\n}\n","import type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\n// Encoder type mapping\nconst ENCODING_MAP = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof ENCODING_MAP\n\n// Define encoder interface\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\n// Cache loaded encoders to avoid repeated imports\nconst encodingCache = new Map<string, Encoder>()\n\n/**\n * Calculate tokens for tool calls\n */\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\n/**\n * Calculate tokens for content parts\n */\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens for a single message\n */\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") {\n tokens += tokensPerName\n }\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens using custom algorithm\n */\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) {\n return 0\n }\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n // every reply is primed with <|start|>assistant<|message|>\n numTokens += 3\n return numTokens\n}\n\n/**\n * Get the corresponding encoder module based on encoding type\n */\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) {\n return cached\n }\n }\n\n const supportedEncoding = encoding as SupportedEncoding\n if (!(supportedEncoding in ENCODING_MAP)) {\n const fallbackModule = (await ENCODING_MAP.o200k_base()) as Encoder\n encodingCache.set(encoding, fallbackModule)\n return fallbackModule\n }\n\n const encodingModule = (await ENCODING_MAP[supportedEncoding]()) as Encoder\n encodingCache.set(encoding, encodingModule)\n return encodingModule\n}\n\n/**\n * Get tokenizer type from model information\n */\nexport const getTokenizerFromModel = (model: Model): string => {\n return model.capabilities?.tokenizer || \"o200k_base\"\n}\n\n/**\n * Get model-specific constants for token calculation\n */\nconst getModelConstants = (model: Model) => {\n return model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\" ?\n {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n}\n\n/**\n * Calculate tokens for a single parameter\n */\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n // Early return if prop is not an object\n if (typeof prop !== \"object\" || prop === null) {\n return tokens\n }\n\n // Type assertion for parameter properties\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n // Handle enum values\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n // Clean up description\n if (paramDesc.endsWith(\".\")) {\n paramDesc = paramDesc.slice(0, -1)\n }\n\n // Encode the main parameter line\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n // Handle additional properties (excluding standard ones)\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (!excludedKeys.has(propertyName)) {\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : (\n JSON.stringify(propertyValue)\n )\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for function parameters\n */\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") {\n return 0\n }\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for a single tool\n */\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) {\n fDesc = fDesc.slice(0, -1)\n }\n const line = fName + \":\" + fDesc\n tokens += encoder.encode(line).length\n if (\n typeof func.parameters === \"object\" \n && func.parameters !== null\n ) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\n/**\n * Calculate token count for tools based on model\n */\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\n/**\n * Calculate the token count of messages, supporting multiple GPT encoders\n */\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: Model,\n): Promise<{ input: number; output: number }> => {\n // Get tokenizer string\n const tokenizer = getTokenizerFromModel(model)\n\n // Get corresponding encoder module\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const simplifiedMessages = payload.messages\n const inputMessages = simplifiedMessages.filter(\n (msg) => msg.role !== \"assistant\",\n )\n const outputMessages = simplifiedMessages.filter(\n (msg) => msg.role === \"assistant\",\n )\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n modelHeaders?: Record<string, string>,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = payload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = payload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n ...modelHeaders,\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n const claudeModels = state.models?.data\n .filter((m) => m.id.startsWith(\"claude\"))\n .map((m) => m.id)\n .join(\", \") ?? \"(models not loaded)\"\n consola.error(\n `Copilot rejected model \"${payload.model}\": ${response.status} ${errorBody} (available Claude models: ${claudeModels})`,\n )\n // Re-create the response so downstream error handlers can still read the body\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Failed to create chat completions\", reconstructed)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\nimport { z } from \"zod\"\n\nimport { copilotBaseUrl, copilotVersion } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nexport interface WebSearchResult {\n content: string\n references: Array<{ title: string; url: string }>\n}\n\nconst RpcSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n id: z.number().optional(),\n result: z\n .object({\n content: z\n .array(z.object({ type: z.literal(\"text\"), text: z.string() }))\n .optional(),\n isError: z.boolean().optional(),\n })\n .optional(),\n error: z\n .object({ code: z.number(), message: z.string() })\n .optional(),\n})\n\nconst InnerSchema = z.object({\n text: z.object({\n value: z.string(),\n annotations: z\n .array(\n z.object({\n url_citation: z\n .object({ title: z.string(), url: z.string() })\n .optional(),\n }),\n )\n .optional(),\n }),\n bing_searches: z.array(z.unknown()).optional(),\n})\n\nconst MAX_SEARCHES_PER_SECOND = 3\nlet searchTimestamps: Array<number> = []\n\nasync function throttleSearch(): Promise<void> {\n const now = Date.now()\n searchTimestamps = searchTimestamps.filter((t) => now - t < 1000)\n if (searchTimestamps.length >= MAX_SEARCHES_PER_SECOND) {\n const waitMs = 1000 - (now - searchTimestamps[0])\n if (waitMs > 0) {\n consola.debug(`Web search rate limited, waiting ${waitMs}ms`)\n await sleep(waitMs)\n }\n }\n searchTimestamps.push(Date.now())\n}\n\nfunction mcpHeaders(sid?: string): Record<string, string> {\n if (!state.githubToken) {\n throw new Error(\n \"GitHub token missing — re-run auth flow. Web search uses the GitHub PAT (not the Copilot token); the on-disk token at ~/.local/share/github-router/github_token must be present.\",\n )\n }\n // Match the GitHubCopilotChat/<version> User-Agent the rest of the\n // router sends (see api-config.ts:32). Sending \"github-router/<version>\"\n // breaks the VS-Code-stealth posture and broadcasts our identity to the\n // MCP server.\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.githubToken}`,\n \"content-type\": \"application/json\",\n accept: \"application/json, text/event-stream\",\n \"X-MCP-Host\": \"copilot-cli\",\n \"X-MCP-Toolsets\": \"web_search\",\n \"Mcp-Protocol-Version\": \"2025-06-18\",\n \"user-agent\": `GitHubCopilotChat/${copilotVersion(state)}`,\n }\n if (sid) headers[\"Mcp-Session-Id\"] = sid\n return headers\n}\n\nasync function postMcp(\n body: unknown,\n sid?: string,\n retry = true,\n): Promise<Response> {\n const url = `${copilotBaseUrl(state)}/mcp`\n const res = await fetch(url, {\n method: \"POST\",\n headers: mcpHeaders(sid),\n body: JSON.stringify(body),\n })\n if (!res.ok && retry && res.status >= 500) {\n await sleep(500)\n return postMcp(body, sid, false)\n }\n return res\n}\n\nexport async function searchWeb(query: string): Promise<WebSearchResult> {\n await throttleSearch()\n consola.info(`Web search (MCP): \"${query.slice(0, 80)}\"`)\n\n const callId = Math.floor(Math.random() * 1_000_000_000)\n let sid: string | undefined\n\n try {\n // 1. initialize\n const initRes = await postMcp({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"initialize\",\n params: {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n // Identify as the Copilot Chat extension, mirroring the User-Agent\n // and editor-plugin-version we send on every other request.\n clientInfo: {\n name: \"GitHubCopilotChat\",\n version: copilotVersion(state),\n },\n },\n })\n if (!initRes.ok) {\n consola.error(\"MCP initialize failed\", initRes.status)\n throw new HTTPError(\"MCP initialize failed\", initRes)\n }\n sid = initRes.headers.get(\"mcp-session-id\") ?? undefined\n if (!sid) {\n throw new HTTPError(\n \"MCP initialize: missing Mcp-Session-Id header\",\n initRes,\n )\n }\n\n // 2. notifications/initialized — server returns 202 (no body)\n const notifRes = await postMcp(\n { jsonrpc: \"2.0\", method: \"notifications/initialized\" },\n sid,\n )\n if (!notifRes.ok && notifRes.status !== 202) {\n consola.error(\"MCP notifications/initialized failed\", notifRes.status)\n throw new HTTPError(\"MCP notifications/initialized failed\", notifRes)\n }\n\n // 3. tools/call web_search — SSE stream of JSON-RPC events; match by id\n const callRes = await postMcp(\n {\n jsonrpc: \"2.0\",\n id: callId,\n method: \"tools/call\",\n params: {\n name: \"web_search\",\n arguments: { query },\n },\n },\n sid,\n )\n if (!callRes.ok) {\n consola.error(\"MCP tools/call failed\", callRes.status)\n throw new HTTPError(\"MCP tools/call failed\", callRes)\n }\n\n let rpc: z.infer<typeof RpcSchema> | undefined\n for await (const ev of events(callRes)) {\n if (!ev.data) continue\n let parsedJson: unknown\n try {\n parsedJson = JSON.parse(ev.data)\n } catch {\n continue\n }\n const parsed = RpcSchema.safeParse(parsedJson)\n if (parsed.success && parsed.data.id === callId) {\n rpc = parsed.data\n break\n }\n }\n if (!rpc) {\n throw new HTTPError(\n \"MCP tools/call: no matching response id in SSE stream\",\n callRes,\n )\n }\n if (rpc.error) {\n throw new HTTPError(\n `MCP error ${rpc.error.code}: ${rpc.error.message}`,\n callRes,\n )\n }\n if (rpc.result?.isError) {\n throw new HTTPError(\"MCP web_search tool error\", callRes)\n }\n\n const text = rpc.result?.content?.[0]?.text\n if (!text) {\n throw new HTTPError(\"MCP web_search: empty content\", callRes)\n }\n\n let innerRaw: unknown\n try {\n innerRaw = JSON.parse(text)\n } catch (err) {\n throw new HTTPError(\n `MCP web_search: inner content not JSON: ${err instanceof Error ? err.message : String(err)}`,\n callRes,\n )\n }\n // safeParse: a raw ZodError thrown here would bypass forwardError's\n // HTTPError check and surface as a generic 500 instead of an Anthropic\n // shape error. Wrap explicitly.\n const innerParsed = InnerSchema.safeParse(innerRaw)\n if (!innerParsed.success) {\n throw new HTTPError(\n `MCP web_search: inner content shape changed (${innerParsed.error.issues\n .map((i) => `${i.path.join(\".\")}: ${i.message}`)\n .join(\"; \")})`,\n callRes,\n )\n }\n const inner = innerParsed.data\n\n const references: Array<{ title: string; url: string }> = []\n for (const ann of inner.text.annotations ?? []) {\n const cite = ann.url_citation\n if (cite && !cite.url.toLowerCase().includes(\"bing.com/search\")) {\n references.push({ title: cite.title, url: cite.url })\n }\n }\n\n consola.debug(`Web search returned ${references.length} references`)\n return { content: inner.text.value, references }\n } finally {\n if (sid) {\n // Best-effort session teardown — never throw. Wrap header construction\n // in try{} too: if state.githubToken cleared between init and finally,\n // mcpHeaders(sid) throws synchronously BEFORE fetch is called and\n // .catch() never attaches, which would mask the original error.\n try {\n void fetch(`${copilotBaseUrl(state)}/mcp`, {\n method: \"DELETE\",\n headers: mcpHeaders(sid),\n }).catch(() => {\n // ignore\n })\n } catch {\n // mcpHeaders threw (token cleared); skip teardown\n }\n }\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish, resolveModel } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n }\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n // Find the selected model\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n logEndpointMismatch(payload.model, \"/chat/completions\")\n\n // Calculate token count\n let inputTokens: number | undefined\n try {\n if (selectedModel) {\n const tokenCount = await getTokenCount(payload, selectedModel)\n inputTokens = tokenCount.input\n }\n } catch {\n // Token counting is best-effort\n }\n\n if (isNullish(payload.max_tokens)) {\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities?.limits?.max_output_tokens,\n }\n if (debugEnabled) {\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n }\n\n const response = await createChatCompletions(payload, selectedModel?.requestHeaders).catch(\n async (error: unknown) => {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n },\n )\n const isStreaming = !isNonStreaming(response)\n\n // Extract output tokens from non-streaming response (no extra call)\n const outputTokens = !isStreaming\n ? (response as ChatCompletionResponse).usage?.completion_tokens\n : undefined\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens,\n outputTokens,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n\nasync function injectWebSearchIfNeeded(\n payload: ChatCompletionsPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some(\n (t) =>\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\",\n )\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = payload.messages.some((msg) => msg.role === \"tool\")\n const query = hasToolResult ? undefined : extractUserQuery(payload.messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n // Prepend to existing system message or inject a new one\n const systemMsg = payload.messages.find((msg) => msg.role === \"system\")\n if (systemMsg) {\n const existingContent =\n typeof systemMsg.content === \"string\" ? systemMsg.content\n : Array.isArray(systemMsg.content) ?\n systemMsg.content\n .filter((p) => p.type === \"text\")\n .map((p) => (\"text\" in p ? p.text : \"\"))\n .join(\"\\n\")\n : \"\"\n systemMsg.content = `${searchContext}\\n\\n${existingContent}`\n } else {\n payload.messages.unshift({\n role: \"system\",\n content: searchContext,\n })\n }\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Remove web_search from tools before forwarding\n payload.tools = payload.tools?.filter(\n (t) =>\n !(\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\"\n ),\n ) as typeof payload.tools\n if (payload.tools?.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n && \"type\" in payload.tool_choice\n && payload.tool_choice.type === \"function\"\n ) {\n const toolChoiceName = payload.tool_choice.function?.name\n if (\n toolChoiceName\n && !payload.tools.some((tool) => tool.function.name === toolChoiceName)\n ) {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(messages: Array<Message>): string | undefined {\n // Find the last user message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const text = msg.content.find((p) => p.type === \"text\")\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const payload = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(payload)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { randomUUID } from \"node:crypto\"\n\nimport consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Build headers that match what VS Code Copilot Chat sends to the Copilot API.\n *\n * copilotHeaders() provides: Authorization, content-type, copilot-integration-id,\n * editor-version, editor-plugin-version, user-agent, openai-intent,\n * x-github-api-version, x-request-id, x-vscode-user-agent-library-version.\n *\n * We add the remaining headers VS Code sends for /v1/messages:\n * - X-Initiator (VS Code sets dynamically; \"agent\" is safe for CLI use)\n * - anthropic-version (VS Code's Anthropic SDK sends this)\n * - X-Interaction-Id (VS Code sends a session-scoped UUID)\n *\n * We intentionally omit copilot-vision-request — VS Code only sends it when\n * images are present, and the native /v1/messages endpoint handles vision\n * without requiring the header.\n *\n * extraHeaders allows callers to forward client-supplied beta headers\n * (anthropic-beta) so Copilot enables extended features.\n */\nfunction buildHeaders(\n extraHeaders?: Record<string, string>,\n): Record<string, string> {\n return {\n ...copilotHeaders(state),\n accept: \"application/json\",\n \"openai-intent\": \"messages-proxy\",\n \"x-interaction-type\": \"conversation-agent\",\n \"X-Initiator\": \"agent\",\n \"anthropic-version\": \"2023-06-01\",\n \"X-Interaction-Id\": randomUUID(),\n ...extraHeaders,\n }\n}\n\n/**\n * Forward an Anthropic Messages API request to Copilot's native /v1/messages endpoint.\n * Returns the raw Response so callers can handle streaming vs non-streaming.\n */\nexport async function createMessages(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot /v1/messages error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot messages request failed\", reconstructed)\n }\n\n return response\n}\n\n/**\n * Forward an Anthropic count_tokens request to Copilot's native endpoint.\n * Returns the raw Response.\n */\nexport async function countTokens(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot count_tokens error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot count_tokens request failed\", reconstructed)\n }\n\n return response\n}\n","import type { Context } from \"hono\"\n\nimport { logRequest } from \"~/lib/request-log\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport { state } from \"~/lib/state\"\nimport { countTokens } from \"~/services/copilot/create-messages\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Strip web_search tools from the request body before forwarding\n * to Copilot's count_tokens endpoint, which rejects unknown tool types.\n * Returns the original raw body if no web_search tools are present.\n */\nfunction stripWebSearchFromBody(rawBody: string): string {\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n\n return JSON.stringify(body)\n}\n\n/**\n * Passthrough handler for Anthropic token counting.\n * Strips web_search tools and forwards beta headers to Copilot's\n * native /v1/messages/count_tokens endpoint.\n */\nexport async function handleCountTokens(c: Context) {\n const startTime = Date.now()\n const rawBody = await c.req.text()\n const strippedBody = stripWebSearchFromBody(rawBody)\n const { body: finalBody, originalModel, resolvedModel } = resolveModelInBody(strippedBody)\n\n const extraHeaders: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) extraHeaders[\"anthropic-beta\"] = filtered\n }\n\n const modelId = resolvedModel ?? originalModel\n const selectedModel = state.models?.data.find((m) => m.id === modelId)\n\n const response = await countTokens(finalBody, {\n ...selectedModel?.requestHeaders,\n ...extraHeaders,\n })\n const responseBody = (await response.json()) as { input_tokens?: number }\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: responseBody.input_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n return c.json(responseBody)\n}\n\n/**\n * Parse the JSON body, resolve the model name, sanitize cache_control, and re-serialize.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n\n let modified = false\n if (originalModel) {\n const resolved = resolveModel(originalModel)\n if (resolved !== originalModel) {\n parsed.model = resolved\n modified = true\n }\n }\n\n const needsSanitize = rawBody.includes('\"scope\"')\n if (needsSanitize && sanitizeCacheControl(parsed)) {\n modified = true\n }\n\n const resolvedModel =\n typeof parsed.model === \"string\" ? parsed.model : originalModel\n\n return {\n body: modified ? JSON.stringify(parsed) : rawBody,\n originalModel,\n resolvedModel,\n }\n}\n\nfunction sanitizeCacheControl(body: AnyRecord): boolean {\n let stripped = false\n function stripScope(block: AnyRecord): void {\n if (block.cache_control?.scope !== undefined) {\n delete block.cache_control.scope\n if (Object.keys(block.cache_control).length === 0) {\n delete block.cache_control\n }\n stripped = true\n }\n }\n\n if (Array.isArray(body.system)) {\n for (const block of body.system) stripScope(block)\n }\n\n if (Array.isArray(body.messages)) {\n for (const msg of body.messages) {\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n stripScope(block)\n if (Array.isArray(block.content)) {\n for (const nested of block.content) stripScope(nested)\n }\n }\n }\n }\n }\n\n if (Array.isArray(body.tools)) {\n for (const tool of body.tools) stripScope(tool)\n }\n\n return stripped\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport { createMessages } from \"~/services/copilot/create-messages\"\nimport type { Model } from \"~/services/copilot/get-models\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Extract whitelisted beta headers from the incoming request to forward\n * to the Copilot API. VS Code sends these to enable extended features\n * like thinking, context management, and advanced tool use.\n */\nfunction extractBetaHeaders(c: Context): Record<string, string> {\n const headers: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) headers[\"anthropic-beta\"] = filtered\n }\n return headers\n}\n\n/**\n * Extract the text content from the last user message for web search.\n * Handles both string content and content block arrays (multimodal).\n */\nfunction extractUserQuery(\n messages: Array<AnyRecord>,\n): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const textBlock = msg.content.find(\n (block: AnyRecord) => block.type === \"text\",\n )\n if (textBlock?.text) return textBlock.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Check if any user message contains tool_result content blocks,\n * indicating a follow-up turn where we should skip web search.\n * In Anthropic format, tool results are content blocks inside user messages,\n * NOT separate role: \"tool\" messages like in OpenAI format.\n */\nfunction hasToolResultContent(messages: Array<AnyRecord>): boolean {\n return messages.some(\n (msg) =>\n Array.isArray(msg.content) &&\n msg.content.some(\n (block: AnyRecord) => block.type === \"tool_result\",\n ),\n )\n}\n\n/**\n * Inject web search results into the Anthropic system field.\n * Handles three cases: absent, string, or array of content blocks.\n * When array, prepends without cache_control to preserve existing directives.\n */\nfunction injectSearchResults(\n body: AnyRecord,\n searchContext: string,\n): void {\n if (body.system === undefined || body.system === null) {\n body.system = searchContext\n } else if (typeof body.system === \"string\") {\n body.system = `${searchContext}\\n\\n${body.system}`\n } else if (Array.isArray(body.system)) {\n body.system = [\n { type: \"text\", text: searchContext },\n ...body.system,\n ]\n }\n}\n\n/**\n * Strip web_search tools from the request and clean up tool_choice.\n * Returns the modified body object.\n */\nfunction stripWebSearchTool(body: AnyRecord): void {\n if (!body.tools) return\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n // If tool_choice forced the removed web_search tool, fall back to auto\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n}\n\n/**\n * Process web search if the request contains a web_search tool.\n * Performs the search, injects results into system, and strips the tool.\n * Returns the (possibly modified) body string to forward.\n */\nasync function processWebSearch(rawBody: string): Promise<string> {\n // Fast path: skip parsing if no web_search tool present\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = hasToolResultContent(body.messages ?? [])\n const query = hasToolResult ? undefined : extractUserQuery(body.messages ?? [])\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n injectSearchResults(body, searchContext)\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Always strip web_search tool regardless of whether search succeeded\n stripWebSearchTool(body)\n\n return JSON.stringify(body)\n}\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const rawBody = await c.req.text()\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Anthropic request body:\", rawBody.slice(0, 2000))\n }\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const betaHeaders = extractBetaHeaders(c)\n const finalBody = await processWebSearch(rawBody)\n\n // Resolve model name (e.g. opus → opus-1m variant) and translate\n // thinking-mode shape for adaptive-thinking models.\n const {\n body: resolvedBody,\n originalModel,\n resolvedModel,\n selectedModel,\n } = resolveModelInBody(finalBody)\n\n const modelId = resolvedModel ?? originalModel\n if (modelId) logEndpointMismatch(modelId, \"/v1/messages\")\n\n // Apply default anthropic-beta for Claude models when client sends none\n const effectiveBetas = applyDefaultBetas(betaHeaders, resolvedModel ?? originalModel)\n\n let response: Response\n try {\n response = await createMessages(resolvedBody, {\n ...selectedModel?.requestHeaders,\n ...effectiveBetas,\n })\n } catch (error) {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n const isStreaming = contentType.includes(\"text/event-stream\")\n\n // Streaming: pipe the upstream SSE response body directly\n if (isStreaming) {\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: response.status,\n streaming: true,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\"Streaming response from Copilot /v1/messages\")\n }\n const streamHeaders: Record<string, string> = {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n }\n const requestId = response.headers.get(\"x-request-id\")\n if (requestId) streamHeaders[\"x-request-id\"] = requestId\n const reqId = response.headers.get(\"request-id\")\n if (reqId) streamHeaders[\"request-id\"] = reqId\n\n return new Response(response.body, {\n status: response.status,\n headers: streamHeaders,\n })\n }\n\n // Non-streaming: extract usage from response body\n const responseBody = (await response.json()) as AnyRecord\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: responseBody.usage?.input_tokens,\n outputTokens: responseBody.usage?.output_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\n \"Non-streaming response from Copilot /v1/messages:\",\n JSON.stringify(responseBody).slice(0, 2000),\n )\n }\n const xRequestId = response.headers.get(\"x-request-id\")\n if (xRequestId) c.header(\"x-request-id\", xRequestId)\n const requestIdHeader = response.headers.get(\"request-id\")\n if (requestIdHeader) c.header(\"request-id\", requestIdHeader)\n return c.json(responseBody, response.status as 200)\n}\n\n/**\n * Parse the JSON body, resolve the model name, sanitize cache_control\n * fields, translate thinking-mode shape for adaptive-thinking models,\n * and re-serialize. Returns the body string, original/resolved model\n * names, and the matching model metadata (if any).\n *\n * Re-serialization is skipped when no modifications are needed.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n selectedModel?: Model\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n\n let modified = false\n if (originalModel) {\n const resolved = resolveModel(originalModel)\n if (resolved !== originalModel) {\n parsed.model = resolved\n modified = true\n }\n }\n\n const resolvedModel =\n typeof parsed.model === \"string\" ? parsed.model : originalModel\n\n const selectedModel = resolvedModel\n ? state.models?.data.find((m) => m.id === resolvedModel)\n : undefined\n\n // Translate thinking-mode shape for adaptive-thinking models — Copilot\n // wants {type:\"adaptive\"} + output_config.effort, not Anthropic's\n // {type:\"enabled\", budget_tokens}.\n if (translateThinking(parsed, selectedModel)) {\n modified = true\n }\n\n // Strip cache_control.scope — fast path skips when \"scope\" absent\n const needsSanitize = rawBody.includes('\"scope\"')\n if (needsSanitize && sanitizeCacheControl(parsed)) {\n modified = true\n }\n\n return {\n body: modified ? JSON.stringify(parsed) : rawBody,\n originalModel,\n resolvedModel,\n selectedModel,\n }\n}\n\nexport const EFFORT_ORDER = [\"low\", \"medium\", \"high\", \"xhigh\"] as const\n\n/**\n * Bucket a thinking budget into a Copilot reasoning-effort string.\n * `<2000`→low, `<8000`→medium, `<24000`→high, else→xhigh.\n * Defaults missing/non-numeric budgets to 8000 (\"high\").\n */\nexport function bucketEffort(budget: unknown): (typeof EFFORT_ORDER)[number] {\n const n =\n typeof budget === \"number\" && Number.isFinite(budget) ? budget : 8000\n if (n < 2000) return \"low\"\n if (n < 8000) return \"medium\"\n if (n < 24000) return \"high\"\n return \"xhigh\"\n}\n\n/**\n * Clamp a bucketed effort to the closest value in `supported`. Ties\n * resolve to the lower-tier option (per EFFORT_ORDER).\n *\n * Iterates EFFORT_ORDER (canonical low→xhigh) so the first match on a\n * given distance is always the lower-tier value, regardless of input\n * order in `supported`.\n */\nexport function clampEffort(\n bucketed: (typeof EFFORT_ORDER)[number],\n supported: Array<string>,\n): string {\n if (supported.includes(bucketed)) return bucketed\n const targetIdx = EFFORT_ORDER.indexOf(bucketed)\n let best: (typeof EFFORT_ORDER)[number] | undefined\n let bestDist = Infinity\n for (let i = 0; i < EFFORT_ORDER.length; i++) {\n const value = EFFORT_ORDER[i]\n if (!supported.includes(value)) continue\n const dist = Math.abs(i - targetIdx)\n // strict `<` keeps the first (lower-tier) on ties\n if (dist < bestDist) {\n bestDist = dist\n best = value\n }\n }\n return best ?? bucketed\n}\n\n/**\n * Translate Anthropic-shape `thinking:{type:\"enabled\", budget_tokens}` to\n * Copilot-shape `thinking:{type:\"adaptive\"}` + `output_config.effort`\n * when the resolved model declares `adaptive_thinking: true`.\n *\n * Returns true if the body was modified. No-op when the model doesn't\n * support adaptive thinking, when thinking is missing/disabled/already\n * adaptive, or when `body` isn't a plain object. Client-supplied\n * `output_config.effort` always wins over the bucketed value.\n */\nfunction translateThinking(body: AnyRecord, model?: Model): boolean {\n if (!model?.capabilities?.supports?.adaptive_thinking) return false\n const thinking = body.thinking\n if (!thinking || typeof thinking !== \"object\") return false\n if (thinking.type !== \"enabled\") return false\n\n const bucketed = bucketEffort(thinking.budget_tokens)\n const supported = model.capabilities.supports.reasoning_effort\n const effort =\n Array.isArray(supported) && supported.length > 0\n ? clampEffort(bucketed, supported)\n : bucketed\n\n body.thinking = { type: \"adaptive\" }\n\n const existing =\n body.output_config && typeof body.output_config === \"object\"\n ? (body.output_config as AnyRecord)\n : {}\n body.output_config = {\n ...existing,\n // client-supplied effort wins\n effort: existing.effort ?? effort,\n }\n\n return true\n}\n\n/**\n * Strip the `scope` field from all `cache_control` objects in the body.\n * Claude CLI 2.1.88+ sends {\"type\":\"ephemeral\",\"scope\":\"global\"} which\n * Copilot rejects. Mutates the parsed object in place.\n *\n * Covers: system blocks, message content blocks (including nested\n * tool_result content), and tool definitions.\n */\nfunction sanitizeCacheControl(body: AnyRecord): boolean {\n let stripped = false\n function stripScope(block: AnyRecord): void {\n if (block.cache_control?.scope !== undefined) {\n delete block.cache_control.scope\n if (Object.keys(block.cache_control).length === 0) {\n delete block.cache_control\n }\n stripped = true\n }\n }\n\n if (Array.isArray(body.system)) {\n for (const block of body.system) stripScope(block)\n }\n\n if (Array.isArray(body.messages)) {\n for (const msg of body.messages) {\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n stripScope(block)\n if (Array.isArray(block.content)) {\n for (const nested of block.content) stripScope(nested)\n }\n }\n }\n }\n }\n\n if (Array.isArray(body.tools)) {\n for (const tool of body.tools) stripScope(tool)\n }\n\n return stripped\n}\n\n/**\n * Apply default anthropic-beta values for Claude models when the client\n * (e.g. curl) sends no beta headers. Claude CLI sends its own betas,\n * so this only fires as a safety net for bare clients.\n */\nfunction applyDefaultBetas(\n betaHeaders: Record<string, string>,\n modelId?: string,\n): Record<string, string> {\n if (betaHeaders[\"anthropic-beta\"]) return betaHeaders\n if (!modelId || !modelId.startsWith(\"claude-\")) return betaHeaders\n\n return {\n ...betaHeaders,\n \"anthropic-beta\": [\n \"interleaved-thinking-2025-05-14\",\n \"context-management-2025-06-27\",\n ].join(\",\"),\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCountTokens } from \"./count-tokens-handler\"\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nmessageRoutes.post(\"/count_tokens\", async (c) => {\n try {\n return await handleCountTokens(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => {\n // Pass through every upstream field (billing, is_chat_default,\n // info_messages, model_picker_category, etc.) and overlay the\n // OpenAI-compat aliases. requestHeaders is router-internal — drop it.\n const { requestHeaders, ...rest } = model\n void requestHeaders\n return {\n ...rest,\n object: \"model\",\n type: model.capabilities?.type ?? \"model\",\n created: 0,\n created_at: new Date(0).toISOString(),\n owned_by: model.vendor,\n display_name: model.name,\n }\n })\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createResponses = async (\n payload: ResponsesPayload,\n modelHeaders?: Record<string, string>,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = detectVision(payload.input)\n\n const isAgentCall = detectAgentCall(payload.input)\n\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n ...modelHeaders,\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const response = await fetch(`${copilotBaseUrl(state)}/responses`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create responses\", response)\n throw new HTTPError(\"Failed to create responses\", response)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ResponsesApiResponse\n}\n\nfunction detectVision(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"content\" in item && Array.isArray(item.content)) {\n return item.content.some(\n (part: Record<string, unknown>) => part.type === \"input_image\",\n )\n }\n return false\n })\n}\n\nfunction detectAgentCall(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"role\" in item && item.role === \"assistant\") return true\n if (\n \"type\" in item\n && (item.type === \"function_call\" || item.type === \"function_call_output\")\n ) {\n return true\n }\n return false\n })\n}\n\n// Types\n\nexport interface ResponsesInputItem {\n role?: \"user\" | \"assistant\" | \"system\"\n type?: \"message\" | \"function_call\" | \"function_call_output\"\n content?: string | Array<Record<string, unknown>>\n name?: string\n call_id?: string\n arguments?: string\n output?: string\n [key: string]: unknown\n}\n\nexport interface ResponsesTool {\n type: string\n name?: string\n description?: string\n parameters?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface ResponsesPayload {\n model: string\n input: string | Array<ResponsesInputItem>\n instructions?: string\n tools?: Array<ResponsesTool>\n tool_choice?:\n | string\n | { type: string; name?: string; function?: { name?: string } }\n max_output_tokens?: number\n temperature?: number\n top_p?: number\n stream?: boolean\n store?: boolean\n metadata?: Record<string, string>\n previous_response_id?: string\n reasoning?: { effort?: string; summary?: string }\n [key: string]: unknown\n}\n\nexport interface ResponsesApiResponse {\n id: string\n object: \"response\"\n status: string\n output: Array<unknown>\n [key: string]: unknown\n}\n","import { randomUUID } from \"node:crypto\"\nimport type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { resolveModel } from \"~/lib/utils\"\nimport {\n createResponses,\n type ResponsesApiResponse,\n type ResponsesInputItem,\n type ResponsesPayload,\n} from \"~/services/copilot/create-responses\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleResponses(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const payload = await c.req.json<ResponsesPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n \"Responses request payload:\",\n JSON.stringify(payload).slice(-400),\n )\n }\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n logEndpointMismatch(payload.model, \"/responses\")\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n const response = await createResponses(payload, selectedModel?.requestHeaders).catch(\n async (error: unknown) => {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n },\n )\n const isStreaming = !isNonStreaming(response)\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n\n if (chunk.data === \"[DONE]\") {\n break\n }\n\n if (!chunk.data) {\n continue\n }\n\n await stream.writeSSE({\n data: chunk.data,\n event: chunk.event,\n id: chunk.id?.toString(),\n })\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createResponses>>,\n): response is ResponsesApiResponse => Object.hasOwn(response, \"output\")\n\nasync function injectWebSearchIfNeeded(\n payload: ResponsesPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some((t) => t.type === \"web_search\")\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (function call results)\n if (Array.isArray(payload.input)) {\n const hasFollowUp = payload.input.some(\n (item: ResponsesInputItem) => item.type === \"function_call_output\",\n )\n if (hasFollowUp) return\n }\n\n const query = extractUserQuery(payload.input)\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n payload.instructions =\n payload.instructions ?\n `${searchContext}\\n\\n${payload.instructions}`\n : searchContext\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Strip the legacy `web_search` tool — the router fulfilled it locally via\n // /github/chat/threads, and Copilot's /responses rejects this exact type\n // (Copilot supports `web_search_preview` / `web_search_preview_2025_03_11`,\n // not bare `web_search`). Other tool types pass through unchanged.\n payload.tools = payload.tools?.filter((t) => t.type !== \"web_search\")\n if (payload.tools && payload.tools.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n ) {\n const choice = payload.tool_choice as {\n name?: string\n function?: { name?: string }\n }\n const choiceName = choice.function?.name ?? choice.name\n if (choiceName === \"web_search\") {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(\n input: ResponsesPayload[\"input\"],\n): string | undefined {\n if (typeof input === \"string\") return input\n if (!Array.isArray(input)) return undefined\n\n // Find the last user message\n for (let i = input.length - 1; i >= 0; i--) {\n const item = input[i]\n if (\"role\" in item && item.role === \"user\") {\n if (typeof item.content === \"string\") return item.content\n if (Array.isArray(item.content)) {\n const text = item.content.find(\n (p: Record<string, unknown>) => p.type === \"input_text\",\n )\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Compaction prompt used when GitHub Copilot API does not support\n * /responses/compact natively. Matches the prompt Codex CLI uses for\n * local (non-OpenAI) compaction.\n */\nconst COMPACTION_PROMPT = `You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.\n\nInclude:\n- Current progress and key decisions made\n- Important context, constraints, or user preferences\n- What remains to be done (clear next steps)\n- Any critical data, examples, or references needed to continue\n\nBe concise, structured, and focused on helping the next LLM seamlessly continue the work.`\n\ninterface CompactRequestPayload {\n model: string\n input: Array<Record<string, unknown>>\n instructions?: string\n [key: string]: unknown\n}\n\nexport async function handleResponsesCompact(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n if (state.manualApprove) await awaitApproval()\n\n const body = await c.req.json<CompactRequestPayload>()\n\n // Try Copilot's native compact endpoint first (future-proofs for when they add support)\n const response = await fetch(\n `${copilotBaseUrl(state)}/responses/compact`,\n {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(body),\n },\n )\n\n if (response.ok) {\n logRequest(\n { method: \"POST\", path: c.req.path, status: 200 },\n undefined,\n startTime,\n )\n return c.json(await response.json())\n }\n\n // Copilot doesn't support /responses/compact — perform synthetic compaction\n // by sending a regular /responses call with a summarization prompt\n if (response.status === 404) {\n consola.debug(\"Copilot API does not support /responses/compact, using synthetic compaction\")\n return await syntheticCompact(c, body, startTime)\n }\n\n // Other errors: throw as before\n logRequest(\n { method: \"POST\", path: c.req.path, status: response.status },\n undefined,\n startTime,\n )\n throw new HTTPError(\"Copilot responses/compact request failed\", response)\n}\n\n/**\n * Synthetic compaction: sends the conversation history to Copilot's\n * regular /responses endpoint with a compaction prompt appended,\n * then returns the model's summary in the compact response format.\n */\nasync function syntheticCompact(\n c: Context,\n body: CompactRequestPayload,\n startTime: number,\n) {\n const input = Array.isArray(body.input) ? [...body.input] : []\n\n // Append compaction prompt as the last user message\n input.push({\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text: COMPACTION_PROMPT }],\n })\n\n const payload: ResponsesPayload = {\n model: body.model,\n input: input as Array<ResponsesInputItem>,\n instructions: body.instructions,\n stream: false,\n store: false,\n }\n\n let result: ResponsesApiResponse\n try {\n result = (await createResponses(payload)) as ResponsesApiResponse\n } catch (error) {\n if (error instanceof HTTPError) {\n logRequest(\n { method: \"POST\", path: c.req.path, status: error.response.status },\n undefined,\n startTime,\n )\n }\n throw error\n }\n\n logRequest(\n { method: \"POST\", path: c.req.path, status: 200 },\n undefined,\n startTime,\n )\n\n return c.json({\n id: `resp_compact_${randomUUID().replace(/-/g, \"\").slice(0, 24)}`,\n object: \"response.compaction\",\n created_at: Math.floor(Date.now() / 1000),\n output: result.output,\n usage: result.usage ?? { input_tokens: 0, output_tokens: 0, total_tokens: 0 },\n })\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleResponses, handleResponsesCompact } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n try {\n return await handleResponses(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nresponsesRoutes.post(\"/compact\", async (c) => {\n try {\n return await handleResponsesCompact(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport const searchRoutes = new Hono()\n\nsearchRoutes.post(\"/\", async (c) => {\n try {\n const { query } = await c.req.json<{ query: string }>()\n\n if (!query || typeof query !== \"string\") {\n return c.json(\n { error: { message: \"Missing required field: query\" } },\n 400,\n )\n }\n\n const results = await searchWeb(query)\n return c.json({ results })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n if (!state.showToken) {\n return c.json(\n { error: { message: \"Token endpoint disabled\", type: \"error\" } },\n 403,\n )\n }\n\n return c.json({\n token: state.copilotToken,\n })\n})\n","import { Hono } from \"hono\"\nimport consola from \"consola\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n consola.error(\"Error fetching Copilot usage:\", error)\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { searchRoutes } from \"./routes/search/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\n// Claude CLI sends HEAD / as health check before each request\nserver.on(\"HEAD\", [\"/\"], (c) => c.body(null, 200))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/responses\", responsesRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/search\", searchRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/responses\", responsesRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\nserver.route(\"/v1/search\", searchRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n\n// Stub out Claude Code SDK telemetry so it doesn't 404-spam logs.\n// Copilot doesn't expose this endpoint; clients fire it best-effort.\nserver.post(\"/api/event_logging/batch\", (c) => c.body(null, 200))\n\n// Return Anthropic-format JSON for unknown endpoints\nserver.notFound((c) =>\n c.json(\n {\n type: \"error\",\n error: {\n type: \"not_found_error\",\n message: `${c.req.method} ${c.req.path} not found`,\n },\n },\n 404,\n ),\n)\n","import os from \"node:os\"\nimport path from \"node:path\"\n\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\n\nimport { PATHS, ensurePaths } from \"./paths\"\nimport { generateRandomPort } from \"./port\"\nimport { initProxyFromEnv } from \"./proxy\"\nimport { state } from \"./state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./token\"\nimport { cacheModels, cacheCopilotVersion, cacheVSCodeVersion } from \"./utils\"\nimport { server as app } from \"../server\"\n\nconst MAX_PORT_RETRIES = 10\n\nexport interface ServerSetupOptions {\n port?: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n showToken: boolean\n proxyEnv: boolean\n extendedBetas: boolean\n silent: boolean\n}\n\nexport async function setupAndServe(\n options: ServerSetupOptions,\n): Promise<{ server: ReturnType<typeof serve>; serverUrl: string }> {\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n state.extendedBetas = options.extendedBetas\n\n if (process.env.COPILOT_API_URL) {\n state.copilotApiUrl = process.env.COPILOT_API_URL\n }\n\n await ensurePaths()\n await cacheVSCodeVersion()\n await cacheCopilotVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.debug(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serveOptions = {\n fetch: app.fetch as ServerHandler,\n hostname: \"127.0.0.1\",\n silent: options.silent,\n }\n\n let srvxServer: ReturnType<typeof serve> | undefined\n\n if (options.port !== undefined) {\n // Explicit port — no retry\n srvxServer = serve({ ...serveOptions, port: options.port })\n } else {\n // Random available port with retry\n let lastError: unknown\n for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {\n const candidatePort = generateRandomPort()\n try {\n srvxServer = serve({ ...serveOptions, port: candidatePort })\n break\n } catch (error) {\n lastError = error\n const isAddrInUse =\n error instanceof Error\n && (error.message.includes(\"EADDRINUSE\")\n || error.message.includes(\"address already in use\")\n || (\"code\" in error\n && (error as NodeJS.ErrnoException).code === \"EADDRINUSE\"))\n if (!isAddrInUse) throw error\n consola.debug(`Port ${candidatePort} in use, trying another...`)\n }\n }\n\n if (srvxServer === undefined) {\n throw new Error(\n `Failed to find an available port after ${MAX_PORT_RETRIES} attempts. `\n + `Specify a port with --port or free some ports. Last error: ${lastError}`,\n )\n }\n }\n\n // Wait for the server to be listening before reading the URL\n await srvxServer.ready()\n const url = srvxServer.url\n if (!url) {\n throw new Error(\"Server started but URL is not available\")\n }\n const serverUrl = url.replace(/\\/$/, \"\")\n\n return { server: srvxServer, serverUrl }\n}\n\n/** Shared CLI arg definitions for all server commands. */\nexport const sharedServerArgs = {\n port: {\n alias: \"p\",\n type: \"string\" as const,\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\" as const,\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\" as const,\n default: \"enterprise\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\" as const,\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\" as const,\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\" as const,\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\" as const,\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"show-token\": {\n type: \"boolean\" as const,\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\" as const,\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n \"extended-betas\": {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Forward extended beta headers for Claude CLI compatibility (default: VS Code-only)\",\n },\n} as const\n\nconst allowedAccountTypes = new Set([\"individual\", \"business\", \"enterprise\"])\n\n/** Parse shared server args into ServerSetupOptions fields. */\nexport function parseSharedArgs(args: Record<string, unknown>): {\n port?: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n showToken: boolean\n proxyEnv: boolean\n extendedBetas: boolean\n} {\n const portRaw = args.port as string | undefined\n let port: number | undefined\n if (portRaw !== undefined) {\n port = Number.parseInt(portRaw, 10)\n if (Number.isNaN(port) || port <= 0 || port > 65535) {\n throw new Error(\"Invalid port. Must be between 1 and 65535.\")\n }\n }\n\n const accountType = (args[\"account-type\"] as string) ?? \"enterprise\"\n if (!allowedAccountTypes.has(accountType)) {\n throw new Error(\n \"Invalid account type. Must be individual, business, or enterprise.\",\n )\n }\n\n const rateLimitRaw = args[\"rate-limit\"] as string | undefined\n let rateLimit: number | undefined\n if (rateLimitRaw !== undefined) {\n rateLimit = Number.parseInt(rateLimitRaw, 10)\n if (Number.isNaN(rateLimit) || rateLimit <= 0) {\n throw new Error(\"Invalid rate limit. Must be a positive integer.\")\n }\n }\n\n const rateLimitWait = (args.wait as boolean) && rateLimit !== undefined\n if ((args.wait as boolean) && rateLimit === undefined) {\n consola.warn(\"Rate limit wait ignored because no rate limit was set.\")\n }\n\n const githubToken =\n (args[\"github-token\"] as string | undefined) ?? process.env.GH_TOKEN\n\n return {\n port,\n verbose: args.verbose as boolean,\n accountType,\n manual: args.manual as boolean,\n rateLimit,\n rateLimitWait,\n githubToken,\n showToken: args[\"show-token\"] as boolean,\n proxyEnv: args[\"proxy-env\"] as boolean,\n extendedBetas: args[\"extended-betas\"] as boolean,\n }\n}\n\n/**\n * Build environment variables for Claude Code.\n *\n * The parent env is sanitized of every key in `STRIPPED_PARENT_ENV_KEYS`\n * (see `src/lib/launch.ts`) BEFORE these overrides are merged in, so we\n * only need to provide the positive values.\n *\n * Auth precedence in Claude Code (https://code.claude.com/docs/en/iam):\n * 1. Cloud provider (CLAUDE_CODE_USE_BEDROCK / VERTEX / FOUNDRY) — stripped at parent.\n * 2. ANTHROPIC_AUTH_TOKEN — set here to \"dummy\"; wins over #4–#6.\n * 3. ANTHROPIC_API_KEY — stripped at parent, intentionally NOT re-set\n * (Claude Code emits an Auth conflict warning when both AUTH_TOKEN\n * and API_KEY are present, even with dummy values).\n * 4. apiKeyHelper in settings.json — beaten by #2.\n * 5. CLAUDE_CODE_OAUTH_TOKEN — stripped at parent.\n * 6. Subscription OAuth (Keychain / ~/.claude/.credentials.json) —\n * INVISIBLE to the spawned child via the CLAUDE_CONFIG_DIR trick\n * below. The credential file is left in place so `claude /logout`\n * still works outside the proxy.\n *\n * `CLAUDE_CONFIG_DIR` activates Claude Code's per-config-dir keychain\n * isolation. Per binary-grep of Claude Code 2.1.126's `iN()` function:\n *\n * function iN(H = \"\") {\n * let _ = B6(), // resolved config-dir path\n * K = !process.env.CLAUDE_CONFIG_DIR ? \"\" : `-${sha256(_).slice(0, 8)}`;\n * return `Claude Code${OAUTH_FILE_SUFFIX}${H}${K}`\n * }\n *\n * The conditional is on PRESENCE, not value. When CLAUDE_CONFIG_DIR is\n * unset (the user's normal `claude` usage), the keychain service name is\n * \"Claude Code\" and their `/login` credential is found there. When set\n * (the proxy session), the service name becomes \"Claude Code-<hash>\" —\n * the user's credential is invisible, `iCH()` returns null, and all\n * three auth-conflict warnings fire `false`. The path resolves to the\n * default config-dir, so settings.json/skills/MCP/plugins/hooks/CLAUDE.md\n * still load from `~/.claude` as normal.\n */\nexport function getClaudeCodeEnvVars(\n serverUrl: string,\n model?: string,\n): Record<string, string> {\n const vars: Record<string, string> = {\n // Route to the proxy\n ANTHROPIC_BASE_URL: serverUrl,\n // Authoritative dummy bearer; sent as `Authorization: Bearer dummy`.\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n // Activate per-config-dir keychain isolation — silences the\n // \"/login managed key\" auth-conflict warning without requiring\n // `claude /logout`. Pointing at the default $HOME/.claude is\n // intentional: it preserves all user customization (settings.json,\n // skills, MCP, hooks, CLAUDE.md, custom agents) while making the\n // keychain probe miss the user's actual credential entry.\n CLAUDE_CONFIG_DIR: path.join(os.homedir(), \".claude\"),\n // Suppress non-essential telemetry/model calls.\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n }\n if (model) vars.ANTHROPIC_MODEL = model\n return vars\n}\n\n/**\n * Build environment variables for Codex CLI.\n *\n * Like `getClaudeCodeEnvVars`, the parent env is sanitized of\n * `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `CODEX_HOME` (see\n * `STRIPPED_PARENT_ENV_KEYS` in `src/lib/launch.ts`) before these\n * overrides are merged, so a stale shell `OPENAI_API_KEY` can't leak\n * through. Codex caches a ChatGPT subscription login under\n * `$CODEX_HOME/auth.json` which can override `OPENAI_API_KEY` per\n * openai/codex#2733; pointing `CODEX_HOME` at an isolated directory\n * masks any cached login.\n */\nexport function getCodexEnvVars(serverUrl: string): Record<string, string> {\n return {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n // Isolated CODEX_HOME — masks any cached ChatGPT login (openai/codex#2733).\n CODEX_HOME: PATHS.CODEX_HOME,\n }\n}\n","import process from \"node:process\"\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { enableFileLogging } from \"./lib/file-log-reporter\"\nimport { launchChild } from \"./lib/launch\"\nimport { listModelsForEndpoint } from \"./lib/model-validation\"\nimport {\n DEFAULT_CLAUDE_MODEL,\n DEFAULT_CLAUDE_MODEL_FALLBACKS,\n} from \"./lib/port\"\nimport {\n getClaudeCodeEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { state } from \"./lib/state\"\nimport { resolveModel } from \"./lib/utils\"\n\nexport const claude = defineCommand({\n meta: {\n name: \"claude\",\n description: \"Start the proxy server and launch Claude Code\",\n },\n args: {\n ...sharedServerArgs,\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model for Claude Code\",\n },\n },\n async run({ args }) {\n if (!process.stdout.isTTY) {\n consola.error(\"The claude subcommand requires a TTY (interactive terminal).\")\n process.exit(1)\n }\n\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n let server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]\n let serverUrl: string\n try {\n const result = await setupAndServe({\n ...parsed,\n port: parsed.port, // undefined = random port\n silent: true,\n })\n server = result.server\n serverUrl = result.serverUrl\n } catch (error) {\n consola.error(\"Failed to start server:\", error instanceof Error ? error.message : error)\n process.exit(1)\n }\n\n enableFileLogging() // redirect errors/warnings to file; suppress terminal output\n\n // Two slugs flow through this code:\n // * `chosenSlug` — the value we set for `ANTHROPIC_MODEL`. Must be an\n // Anthropic-published slug (e.g. `claude-opus-4-7`) so Claude Code's\n // hardcoded `/model` registry matches it and the UI shows the right\n // menu entry. The proxy's resolver translates this back to a Copilot\n // slug at request time, so the actual upstream call still works.\n // * `resolvedSlug` — the Copilot-side slug after `resolveModel`. Used\n // only for cache-presence validation (fallback chain) and the\n // launch banner.\n //\n // For the implicit-default path only, we walk\n // DEFAULT_CLAUDE_MODEL_FALLBACKS when neither the default nor any\n // earlier fallback resolves to a model present in the Copilot cache.\n // Explicit `--model` is respected as-is — including Copilot slugs\n // (which Claude Code's UI won't recognize, but power users may want\n // for explicit pinning).\n const usingDefault = !args.model\n const requestedSlug = args.model ?? DEFAULT_CLAUDE_MODEL\n let chosenSlug = requestedSlug\n let resolvedSlug = resolveModel(chosenSlug)\n\n if (usingDefault && state.models) {\n const inCache = (slug: string) =>\n state.models?.data.some((m) => m.id === resolveModel(slug)) ?? false\n if (!inCache(chosenSlug)) {\n for (const fallback of DEFAULT_CLAUDE_MODEL_FALLBACKS) {\n if (inCache(fallback)) {\n consola.info(\n `Default model \"${chosenSlug}\" not in your Copilot model list; falling back to \"${fallback}\".`,\n )\n chosenSlug = fallback\n resolvedSlug = resolveModel(fallback)\n break\n }\n }\n }\n }\n\n if (resolvedSlug !== chosenSlug) {\n consola.info(`Model \"${chosenSlug}\" resolved to \"${resolvedSlug}\"`)\n }\n const modelEntry = state.models?.data.find((m) => m.id === resolvedSlug)\n if (!modelEntry) {\n const available = listModelsForEndpoint(\"/v1/messages\")\n consola.warn(\n `Model \"${resolvedSlug}\" not found. Available claude models: ${available.join(\", \")}`,\n )\n }\n\n // Banner shows the round-trip so the user sees both names. Claude Code's\n // UI will display the chosenSlug; Copilot upstream sees resolvedSlug.\n const banner =\n chosenSlug === resolvedSlug\n ? chosenSlug\n : `${chosenSlug} → ${resolvedSlug}`\n // Print to stderr directly — consola's terminal reporter is already gone\n process.stderr.write(`Server ready on ${serverUrl}, launching Claude Code (${banner})...\\n`)\n\n const envVars = getClaudeCodeEnvVars(serverUrl, chosenSlug)\n const extraArgs = ((args as unknown as Record<string, unknown>)._ as string[]) ?? []\n\n launchChild(\n { kind: \"claude-code\", envVars, extraArgs, model: chosenSlug },\n server,\n )\n },\n})\n","import process from \"node:process\"\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { enableFileLogging } from \"./lib/file-log-reporter\"\nimport { launchChild } from \"./lib/launch\"\nimport { listModelsForEndpoint } from \"./lib/model-validation\"\nimport {\n DEFAULT_CODEX_MODEL,\n DEFAULT_CODEX_MODEL_FALLBACKS,\n} from \"./lib/port\"\nimport {\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { state } from \"./lib/state\"\nimport { resolveCodexModel } from \"./lib/utils\"\n\nexport const codex = defineCommand({\n meta: {\n name: \"codex\",\n description: \"Start the proxy server and launch Codex CLI\",\n },\n args: {\n ...sharedServerArgs,\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model for Codex CLI\",\n },\n },\n async run({ args }) {\n if (!process.stdout.isTTY) {\n consola.error(\"The codex subcommand requires a TTY (interactive terminal).\")\n process.exit(1)\n }\n\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n let server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]\n let serverUrl: string\n try {\n const result = await setupAndServe({\n ...parsed,\n port: parsed.port, // undefined = random port\n silent: true,\n })\n server = result.server\n serverUrl = result.serverUrl\n } catch (error) {\n consola.error(\"Failed to start server:\", error instanceof Error ? error.message : error)\n process.exit(1)\n }\n\n const usingDefault = !args.model\n const requestedModel = args.model ?? DEFAULT_CODEX_MODEL\n\n // Resolve model before printing success message (so we show the actual model)\n // but enable file logging first so resolution warnings go to file, not terminal\n enableFileLogging()\n\n let codexModel = resolveCodexModel(requestedModel)\n if (codexModel !== requestedModel) {\n consola.info(`Model \"${requestedModel}\" resolved to \"${codexModel}\"`)\n }\n\n // For the implicit-default path only, walk DEFAULT_CODEX_MODEL_FALLBACKS\n // when the default isn't in the resolved Copilot model list. Layered on\n // top of resolveCodexModel's \"best /responses model\" fallback — that\n // remains the final safety net when every named fallback misses.\n if (usingDefault && state.models) {\n const inCache = (id: string) =>\n state.models?.data.some((m) => m.id === id) ?? false\n if (!inCache(codexModel)) {\n for (const fallback of DEFAULT_CODEX_MODEL_FALLBACKS) {\n const resolved = resolveCodexModel(fallback)\n if (inCache(resolved)) {\n consola.info(\n `Default model \"${codexModel}\" not in your Copilot model list; falling back to \"${resolved}\".`,\n )\n codexModel = resolved\n break\n }\n }\n }\n }\n\n // Validate model exists in Copilot model list\n const modelEntry = state.models?.data.find((m) => m.id === codexModel)\n if (!modelEntry) {\n const available = listModelsForEndpoint(\"/responses\")\n consola.warn(\n `Model \"${codexModel}\" not found. Available codex models: ${available.join(\", \")}`,\n )\n } else {\n const ctx = modelEntry.capabilities?.limits?.max_context_window_tokens\n if (ctx) consola.info(`Model context window: ${ctx.toLocaleString()} tokens`)\n }\n\n // Print to stderr directly — consola's terminal reporter is already gone\n process.stderr.write(`Server ready on ${serverUrl}, launching Codex CLI (${codexModel})...\\n`)\n\n const envVars = getCodexEnvVars(serverUrl)\n const extraArgs = ((args as unknown as Record<string, unknown>)._ as string[]) ?? []\n\n launchChild(\n { kind: \"codex\", envVars, extraArgs, model: codexModel },\n server,\n )\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`github-router debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, env } = process\n\n if (platform === \"win32\") {\n // Git Bash / MSYS2 / Cygwin set SHELL even on Windows\n if (env.SHELL) {\n if (env.SHELL.endsWith(\"zsh\")) return \"zsh\"\n if (env.SHELL.endsWith(\"fish\")) return \"fish\"\n if (env.SHELL.endsWith(\"bash\")) return \"bash\"\n return \"sh\"\n }\n\n // Windows PowerShell 5.x sets this\n if (env.POWERSHELL_DISTRIBUTION_CHANNEL) return \"powershell\"\n\n // PowerShell (both 5.x and 7+/pwsh) adds user-scoped module paths\n // at runtime. The system-level PSModulePath in CMD lacks these paths.\n if (env.PSModulePath) {\n const lower = env.PSModulePath.toLowerCase()\n if (\n lower.includes(\"documents\\\\powershell\")\n || lower.includes(\"documents\\\\windowspowershell\")\n ) {\n return \"powershell\"\n }\n }\n\n return \"cmd\"\n }\n\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n}\n\nfunction quotePosixValue(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nfunction quotePowerShellValue(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${quotePowerShellValue(value)}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set \"${key}=${value}\"`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${quotePosixValue(value)}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${quotePosixValue(value)}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator =\n shell === \"cmd\" ? \" & \" : shell === \"powershell\" ? \"; \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\n\nimport { generateEnvScript } from \"./lib/shell\"\nimport { DEFAULT_CODEX_MODEL, DEFAULT_PORT } from \"./lib/port\"\nimport {\n getClaudeCodeEnvVars,\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\n\nfunction printAndCopyCommand(command: string, label: string): void {\n consola.box(`${label}\\n\\n${command}`)\n try {\n clipboard.writeSync(command)\n consola.success(`Copied ${label} command to clipboard!`)\n } catch {\n consola.warn(\"Failed to copy to clipboard. Copy the command above manually.\")\n }\n}\n\nfunction generateClaudeCodeCommand(serverUrl: string, model?: string) {\n const envVars = getClaudeCodeEnvVars(serverUrl, model)\n const command = generateEnvScript(envVars, \"claude --dangerously-skip-permissions\")\n printAndCopyCommand(command, \"Claude Code\")\n}\n\nfunction generateCodexCommand(serverUrl: string, model?: string) {\n const codexModel = model ?? DEFAULT_CODEX_MODEL\n const envVars = getCodexEnvVars(serverUrl)\n const command = generateEnvScript(envVars, `codex -m ${codexModel}`)\n printAndCopyCommand(command, \"Codex CLI\")\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the github-router server\",\n },\n args: {\n ...sharedServerArgs,\n cc: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n cx: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Codex CLI with Copilot API config\",\n },\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model (used with --cc or --cx)\",\n },\n },\n async run({ args }) {\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n const { serverUrl } = await setupAndServe({\n ...parsed,\n port: parsed.port ?? DEFAULT_PORT,\n silent: false,\n })\n\n if (args.cc) generateClaudeCodeCommand(serverUrl, args.model)\n if (args.cx) generateCodexCommand(serverUrl, args.model)\n\n consola.box(\n `🌐 Usage Viewer: https://animeshkundu.github.io/github-router/dashboard.html?endpoint=${serverUrl}/usage`,\n )\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\nimport consola from \"consola\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { claude } from \"./claude\"\nimport { codex } from \"./codex\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nprocess.on(\"unhandledRejection\", (error) => {\n consola.error(\"Unhandled rejection:\", error)\n})\n\nprocess.on(\"uncaughtException\", (error) => {\n consola.error(\"Uncaught exception:\", error)\n process.exit(1)\n})\n\nconst main = defineCommand({\n meta: {\n name: \"github-router\",\n description:\n \"A reverse proxy that exposes GitHub Copilot as OpenAI and Anthropic compatible API endpoints.\",\n },\n subCommands: { auth, start, claude, codex, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":"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"}
|