github-router 0.3.269 → 0.3.271

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.
Files changed (38) hide show
  1. package/dist/{attribution-settings-B1txv_Lk.js → attribution-settings-DLRQEKpU.js} +3 -3
  2. package/dist/{attribution-settings-B1txv_Lk.js.map → attribution-settings-DLRQEKpU.js.map} +1 -1
  3. package/dist/{auth-r-my7efo.js → auth-DIFbHOu0.js} +2 -2
  4. package/dist/{auth-r-my7efo.js.map → auth-DIFbHOu0.js.map} +1 -1
  5. package/dist/browser-ext/manifest.json +1 -1
  6. package/dist/{check-usage-CZr2ZkG0.js → check-usage-DfnrR-d_.js} +3 -3
  7. package/dist/{check-usage-CZr2ZkG0.js.map → check-usage-DfnrR-d_.js.map} +1 -1
  8. package/dist/{claude-BjNY0J6e.js → claude-BpQVQE0T.js} +7 -7
  9. package/dist/{claude-BjNY0J6e.js.map → claude-BpQVQE0T.js.map} +1 -1
  10. package/dist/{codex-CoRWpkHL.js → codex-CGMiGJy1.js} +5 -5
  11. package/dist/{codex-CoRWpkHL.js.map → codex-CGMiGJy1.js.map} +1 -1
  12. package/dist/engine-DUJyXWZn.js +2 -0
  13. package/dist/{gate-discovery-D-7oua8b.js → gate-discovery-BBA7cV1D.js} +2 -2
  14. package/dist/{gate-discovery-D-7oua8b.js.map → gate-discovery-BBA7cV1D.js.map} +1 -1
  15. package/dist/{get-copilot-usage-CFEpeA7E.js → get-copilot-usage-Ds09xSmH.js} +2 -2
  16. package/dist/{get-copilot-usage-CFEpeA7E.js.map → get-copilot-usage-Ds09xSmH.js.map} +1 -1
  17. package/dist/{internal-stop-hook-Db5o9RcZ.js → internal-stop-hook-CO2NDmGL.js} +2 -2
  18. package/dist/{internal-stop-hook-Db5o9RcZ.js.map → internal-stop-hook-CO2NDmGL.js.map} +1 -1
  19. package/dist/main.js +8 -8
  20. package/dist/{models-CJLt4XjP.js → models-BFQUp0ov.js} +2 -2
  21. package/dist/{models-CJLt4XjP.js.map → models-BFQUp0ov.js.map} +1 -1
  22. package/dist/{peer-mcp-personas-DSbBlgFt.js → peer-mcp-personas-CN8xaXcV.js} +377 -101
  23. package/dist/peer-mcp-personas-CN8xaXcV.js.map +1 -0
  24. package/dist/{provision-CA-xwnFu.js → provision-CiPjSx7J.js} +2 -2
  25. package/dist/{provision-CA-xwnFu.js.map → provision-CiPjSx7J.js.map} +1 -1
  26. package/dist/{serve-DHny4ewF.js → serve-CpTMr5D9.js} +6 -6
  27. package/dist/{serve-DHny4ewF.js.map → serve-CpTMr5D9.js.map} +1 -1
  28. package/dist/{server-setup-Dd293T1O.js → server-setup-B02Myghc.js} +285 -99
  29. package/dist/server-setup-B02Myghc.js.map +1 -0
  30. package/dist/{start-P2rmHBkL.js → start-CIV9eXVb.js} +3 -3
  31. package/dist/{start-P2rmHBkL.js.map → start-CIV9eXVb.js.map} +1 -1
  32. package/dist/{token-C_q95GF7.js → token-iaSGp76k.js} +303 -143
  33. package/dist/token-iaSGp76k.js.map +1 -0
  34. package/package.json +1 -1
  35. package/dist/engine-DpVC7HRL.js +0 -2
  36. package/dist/peer-mcp-personas-DSbBlgFt.js.map +0 -1
  37. package/dist/server-setup-Dd293T1O.js.map +0 -1
  38. package/dist/token-C_q95GF7.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { St as warmTreeSitterPool, Y as browserToolsEnabled, gt as provisionBrowserAssets, vt as colbertDegradedWarning, yt as provisionAndIndexColbert } from "./peer-mcp-personas-DSbBlgFt.js";
2
- import { a as sharedServerArgs, i as setupAndServe, n as getCodexEnvVars, o as startKeepAwake, r as parseSharedArgs, t as getClaudeCodeEnvVars, u as runSelfUpdate } from "./server-setup-Dd293T1O.js";
1
+ import { $ as browserToolsEnabled, Ct as provisionAndIndexColbert, Et as warmTreeSitterPool, St as colbertDegradedWarning, bt as provisionBrowserAssets } from "./peer-mcp-personas-CN8xaXcV.js";
2
+ import { a as sharedServerArgs, i as setupAndServe, n as getCodexEnvVars, o as startKeepAwake, r as parseSharedArgs, t as getClaudeCodeEnvVars, u as runSelfUpdate } from "./server-setup-B02Myghc.js";
3
3
  import { defineCommand } from "citty";
4
4
  import consola from "consola";
5
5
  import process$1 from "node:process";
@@ -129,4 +129,4 @@ const start = defineCommand({
129
129
  //#endregion
130
130
  export { start };
131
131
 
132
- //# sourceMappingURL=start-P2rmHBkL.js.map
132
+ //# sourceMappingURL=start-CIV9eXVb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"start-P2rmHBkL.js","names":["process"],"sources":["../src/lib/shell.ts","../src/start.ts"],"sourcesContent":["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 { provisionBrowserAssets } from \"./lib/browser-mcp/provision\"\nimport { browserToolsEnabled } from \"./lib/mcp-capabilities\"\nimport { colbertDegradedWarning, provisionAndIndexColbert } from \"./lib/colbert\"\nimport { startKeepAwake } from \"./lib/keep-awake\"\nimport { warmTreeSitterPool } from \"./lib/tree-sitter-pool/pool\"\nimport {\n getClaudeCodeEnvVars,\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { runSelfUpdate } from \"./lib/self-update\"\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 // Best-effort self-update (detached, applies next launch). Runs\n // after the server is listening so the bounded probe can't delay it.\n void runSelfUpdate({ selfUpdate: args[\"self-update\"] !== false })\n\n // Best-effort ColBERT semantic-search provision + background index of\n // the launch cwd (if a git repo). ON by default; never blocks launch,\n // never throws. Opt out with GH_ROUTER_DISABLE_SEMANTIC_SEARCH=1.\n void provisionAndIndexColbert()\n\n // Surface a terminally-failed semantic index to the HUMAN (see the note\n // in claude.ts). Fire-and-forget; lexical search still works.\n void colbertDegradedWarning()\n .then((warning) => {\n if (warning) process.stderr.write(`${warning}\\n`)\n })\n .catch(() => {})\n\n // Ready one tree-sitter worker in the background so the first code search\n // avoids WASM/grammar initialization. One worker keeps launch CPU bounded;\n // demand grows the pool lazily. Opt out with GH_ROUTER_DISABLE_TS_POOL_WARMUP=1.\n void warmTreeSitterPool()\n\n // Best-effort: keep the machine awake while the proxy serves (win32\n // default-on; opt out with GH_ROUTER_DISABLE_KEEP_AWAKE=1). Holds a\n // SetThreadExecutionState assertion via a persistent PowerShell\n // helper. Self-registers its own SIGINT/SIGTERM/exit reaper — load-\n // bearing here, because `start` has no launchChild/onShutdown.\n startKeepAwake()\n\n // Best-effort: materialize the browser extension + bridge into the\n // stable app-dir and stamp the running version, so a one-time \"Load\n // unpacked\" survives npx/bunx upgrades. Gated on --browse; never\n // blocks launch, never throws.\n if (browserToolsEnabled()) {\n void provisionBrowserAssets().catch((err) =>\n consola.debug(\"Browser extension provisioning failed:\", err),\n )\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"],"mappings":"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"}
1
+ {"version":3,"file":"start-CIV9eXVb.js","names":["process"],"sources":["../src/lib/shell.ts","../src/start.ts"],"sourcesContent":["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 { provisionBrowserAssets } from \"./lib/browser-mcp/provision\"\nimport { browserToolsEnabled } from \"./lib/mcp-capabilities\"\nimport { colbertDegradedWarning, provisionAndIndexColbert } from \"./lib/colbert\"\nimport { startKeepAwake } from \"./lib/keep-awake\"\nimport { warmTreeSitterPool } from \"./lib/tree-sitter-pool/pool\"\nimport {\n getClaudeCodeEnvVars,\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { runSelfUpdate } from \"./lib/self-update\"\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 // Best-effort self-update (detached, applies next launch). Runs\n // after the server is listening so the bounded probe can't delay it.\n void runSelfUpdate({ selfUpdate: args[\"self-update\"] !== false })\n\n // Best-effort ColBERT semantic-search provision + background index of\n // the launch cwd (if a git repo). ON by default; never blocks launch,\n // never throws. Opt out with GH_ROUTER_DISABLE_SEMANTIC_SEARCH=1.\n void provisionAndIndexColbert()\n\n // Surface a terminally-failed semantic index to the HUMAN (see the note\n // in claude.ts). Fire-and-forget; lexical search still works.\n void colbertDegradedWarning()\n .then((warning) => {\n if (warning) process.stderr.write(`${warning}\\n`)\n })\n .catch(() => {})\n\n // Ready one tree-sitter worker in the background so the first code search\n // avoids WASM/grammar initialization. One worker keeps launch CPU bounded;\n // demand grows the pool lazily. Opt out with GH_ROUTER_DISABLE_TS_POOL_WARMUP=1.\n void warmTreeSitterPool()\n\n // Best-effort: keep the machine awake while the proxy serves (win32\n // default-on; opt out with GH_ROUTER_DISABLE_KEEP_AWAKE=1). Holds a\n // SetThreadExecutionState assertion via a persistent PowerShell\n // helper. Self-registers its own SIGINT/SIGTERM/exit reaper — load-\n // bearing here, because `start` has no launchChild/onShutdown.\n startKeepAwake()\n\n // Best-effort: materialize the browser extension + bridge into the\n // stable app-dir and stamp the running version, so a one-time \"Load\n // unpacked\" survives npx/bunx upgrades. Gated on --browse; never\n // blocks launch, never throws.\n if (browserToolsEnabled()) {\n void provisionBrowserAssets().catch((err) =>\n consola.debug(\"Browser extension provisioning failed:\", err),\n )\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"],"mappings":"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"}
@@ -83,123 +83,6 @@ const githubAgentGraphQLHeaders = (state, features) => ({
83
83
  ...features ? { "GraphQL-Features": features } : {}
84
84
  });
85
85
  //#endregion
86
- //#region src/lib/error.ts
87
- var HTTPError = class extends Error {
88
- response;
89
- constructor(message, response) {
90
- super(message);
91
- this.response = response;
92
- }
93
- };
94
- async function forwardError(c, error) {
95
- consola.error(`Error occurred at ${c.req.path}:`, error);
96
- if (error instanceof HTTPError) {
97
- const errorText = await error.response.text().catch(() => "");
98
- let errorJson;
99
- try {
100
- errorJson = JSON.parse(errorText);
101
- } catch {
102
- errorJson = void 0;
103
- }
104
- if (isContextOverflow(error.response.status, errorJson, errorText)) {
105
- const upstream = resolveErrorMessage(errorJson, errorText);
106
- consola.error("HTTP error (mapped to overflow):", errorJson ?? errorText);
107
- return c.json({
108
- type: "error",
109
- error: {
110
- type: "invalid_request_error",
111
- message: `prompt is too long: ${upstream}`
112
- }
113
- }, 400);
114
- }
115
- const responseStatus = error.response.status === 401 ? 503 : error.response.status;
116
- if (isAnthropicError(errorJson)) {
117
- consola.error("HTTP error:", errorJson);
118
- return c.json(errorJson, responseStatus);
119
- }
120
- const message = resolveErrorMessage(errorJson, errorText);
121
- consola.error("HTTP error:", errorJson ?? errorText);
122
- return c.json({
123
- type: "error",
124
- error: {
125
- type: resolveErrorType(responseStatus),
126
- message
127
- }
128
- }, responseStatus);
129
- }
130
- return c.json({
131
- type: "error",
132
- error: {
133
- type: "api_error",
134
- message: error instanceof Error ? error.message : String(error)
135
- }
136
- }, 500);
137
- }
138
- function resolveErrorMessage(errorJson, fallback) {
139
- if (typeof errorJson !== "object" || errorJson === null) return fallback;
140
- const errorRecord = errorJson;
141
- if (errorRecord.message !== void 0) return String(errorRecord.message);
142
- if (typeof errorRecord.error === "object" && errorRecord.error !== null) {
143
- const nestedRecord = errorRecord.error;
144
- if (nestedRecord.message !== void 0) return String(nestedRecord.message);
145
- }
146
- return fallback;
147
- }
148
- /**
149
- * Check if a parsed JSON body is already in Anthropic error format:
150
- * { type: "error", error: { type: "...", message: "..." } }
151
- */
152
- function isAnthropicError(json) {
153
- if (typeof json !== "object" || json === null) return false;
154
- const record = json;
155
- if (record.type !== "error") return false;
156
- if (typeof record.error !== "object" || record.error === null) return false;
157
- const inner = record.error;
158
- return typeof inner.type === "string" && typeof inner.message === "string";
159
- }
160
- const CONTEXT_OVERFLOW_SUBSTRINGS = [
161
- "prompt is too long",
162
- "context_length_exceeded",
163
- "context length exceeded",
164
- "input is too long",
165
- "maximum context length",
166
- "too many tokens"
167
- ];
168
- /**
169
- * Detect upstream context-overflow errors so we can remap them to a 400
170
- * "prompt is too long" shape that triggers Claude Code self-compaction.
171
- *
172
- * Always remaps 413 (treated as a hard payload-size signal regardless of
173
- * body wording). Remaps 400 only when the error text contains one of the
174
- * known overflow substrings — a regular 400 (e.g. "model not found") must
175
- * NOT remap.
176
- */
177
- function isContextOverflow(status, errorJson, errorText) {
178
- if (status === 413) return true;
179
- if (status !== 400) return false;
180
- const haystack = (errorText + " " + (typeof errorJson === "object" && errorJson !== null ? JSON.stringify(errorJson) : "")).toLowerCase();
181
- return CONTEXT_OVERFLOW_SUBSTRINGS.some((s) => haystack.includes(s));
182
- }
183
- /**
184
- * Map HTTP status to Anthropic error type.
185
- *
186
- * Note: a 401 from upstream is remapped to 503 in `forwardError` BEFORE
187
- * this function is called (no-401 invariant — see comment there). The
188
- * 401 → "authentication_error" mapping below is preserved for
189
- * defensive coverage in case any code path calls `resolveErrorType`
190
- * directly with an unsanitized status.
191
- */
192
- function resolveErrorType(status) {
193
- if (status === 400) return "invalid_request_error";
194
- if (status === 401) return "authentication_error";
195
- if (status === 403) return "permission_error";
196
- if (status === 404) return "not_found_error";
197
- if (status === 429) return "rate_limit_error";
198
- if (status === 503) return "overloaded_error";
199
- if (status === 529) return "overloaded_error";
200
- return "api_error";
201
- }
202
- //#endregion
203
86
  //#region src/lib/upstream-retry.ts
204
87
  /**
205
88
  * Shared transient-failure retry for upstream calls (`src/lib/upstream-retry.ts`).
@@ -234,6 +117,154 @@ const DEFAULT_RETRY_STATUSES = [
234
117
  503,
235
118
  504
236
119
  ];
120
+ const TRANSPORT_MESSAGE_MAX = 512;
121
+ const TRANSIENT_CODES = /* @__PURE__ */ new Set([
122
+ "ECONNRESET",
123
+ "ETIMEDOUT",
124
+ "EPIPE",
125
+ "EAI_AGAIN",
126
+ "UND_ERR_CONNECT_TIMEOUT",
127
+ "UND_ERR_HEADERS_TIMEOUT",
128
+ "UND_ERR_SOCKET"
129
+ ]);
130
+ const DETERMINISTIC_CODES = /* @__PURE__ */ new Set([
131
+ "ENOTFOUND",
132
+ "ECONNREFUSED",
133
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
134
+ "SELF_SIGNED_CERT_IN_CHAIN",
135
+ "UNABLE_TO_GET_ISSUER_CERT",
136
+ "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
137
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
138
+ "CERT_HAS_EXPIRED",
139
+ "CERT_NOT_YET_VALID",
140
+ "ERR_TLS_CERT_ALTNAME_INVALID",
141
+ "ERR_TLS_CERT_SIGNATURE_ALGORITHM_UNSUPPORTED",
142
+ "ERR_SSL_WRONG_VERSION_NUMBER"
143
+ ]);
144
+ const CREDENTIAL_RE = /\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/gi;
145
+ const SECRET_ASSIGNMENT_RE = /\b(authorization|api[_-]?key|access[_-]?token|token|password)\s*[:=]\s*([^\s,;]+)/gi;
146
+ const REQUEST_BODY_RE = /\b(request\s+body|body)\s*[:=]\s*.*$/gi;
147
+ var TransportExhaustionError = class extends Error {
148
+ endpoint;
149
+ label;
150
+ attempts;
151
+ classification;
152
+ lastError;
153
+ constructor(metadata, cause) {
154
+ const target = metadata.endpoint ?? metadata.label ?? "upstream";
155
+ const lastError = {
156
+ name: sanitizeTransportText(metadata.lastError.name),
157
+ message: sanitizeTransportText(metadata.lastError.message),
158
+ code: metadata.lastError.code ? sanitizeTransportText(metadata.lastError.code) : void 0,
159
+ causeCode: metadata.lastError.causeCode ? sanitizeTransportText(metadata.lastError.causeCode) : void 0
160
+ };
161
+ const code = lastError.causeCode ?? lastError.code;
162
+ const suffix = code ? ` (${code})` : "";
163
+ super(`Upstream transport ${metadata.classification === "transient" ? "failed" : "is unreachable"} at ${sanitizeTransportText(target)} after ${metadata.attempts} attempt${metadata.attempts === 1 ? "" : "s"}: ${lastError.name}: ${lastError.message}${suffix}`, { cause });
164
+ this.name = "TransportExhaustionError";
165
+ this.endpoint = metadata.endpoint ? sanitizeTransportText(metadata.endpoint) : void 0;
166
+ this.label = metadata.label ? sanitizeTransportText(metadata.label) : void 0;
167
+ this.attempts = metadata.attempts;
168
+ this.classification = metadata.classification;
169
+ this.lastError = lastError;
170
+ }
171
+ };
172
+ function readStringProperty(value, key) {
173
+ if (typeof value !== "object" && typeof value !== "function" || value === null) return;
174
+ try {
175
+ const property = value[key];
176
+ return typeof property === "string" ? property : void 0;
177
+ } catch {
178
+ return;
179
+ }
180
+ }
181
+ function readCause(value) {
182
+ if (typeof value !== "object" && typeof value !== "function" || value === null) return;
183
+ try {
184
+ return value.cause;
185
+ } catch {
186
+ return;
187
+ }
188
+ }
189
+ function safeString(value) {
190
+ try {
191
+ return String(value);
192
+ } catch {
193
+ return "[unserializable error]";
194
+ }
195
+ }
196
+ function sanitizeTransportText(value) {
197
+ const sanitized = value.replace(/\r\n|\r|\n/g, " ").replace(CREDENTIAL_RE, "[REDACTED]").replace(SECRET_ASSIGNMENT_RE, "$1=[REDACTED]").replace(REQUEST_BODY_RE, "$1=[REDACTED]");
198
+ return sanitized.length > TRANSPORT_MESSAGE_MAX ? `${sanitized.slice(0, TRANSPORT_MESSAGE_MAX)}…` : sanitized;
199
+ }
200
+ /**
201
+ * Classify errors thrown before the first response byte. Deterministic
202
+ * connectivity/configuration signals win over generic runtime wording such as
203
+ * TypeError("fetch failed"), because the nested cause is more specific.
204
+ */
205
+ function classifyTransportError(error, opts = {}) {
206
+ const name = readStringProperty(error, "name") ?? "Error";
207
+ const rawMessage = readStringProperty(error, "message") ?? (typeof error === "string" ? error : safeString(error));
208
+ const message = sanitizeTransportText(rawMessage);
209
+ const code = readStringProperty(error, "code");
210
+ const causes = [];
211
+ const seen = /* @__PURE__ */ new Set();
212
+ let current = readCause(error);
213
+ for (let depth = 0; current !== void 0 && depth < 4; depth++) {
214
+ if ((typeof current === "object" || typeof current === "function") && current !== null) {
215
+ if (seen.has(current)) break;
216
+ seen.add(current);
217
+ }
218
+ causes.push(current);
219
+ current = readCause(current);
220
+ }
221
+ const causeCode = causes.map((cause) => readStringProperty(cause, "code")).find((value) => value !== void 0);
222
+ const codes = [code, ...causes.map((cause) => readStringProperty(cause, "code"))].filter((value) => value !== void 0).map((value) => value.toUpperCase());
223
+ const messages = [rawMessage, ...causes.map((cause) => readStringProperty(cause, "message") ?? "")].join(" ").toLowerCase();
224
+ if (opts.callerCancelled) return {
225
+ classification: "cancelled",
226
+ name,
227
+ message,
228
+ code,
229
+ causeCode
230
+ };
231
+ if (codes.some((value) => DETERMINISTIC_CODES.has(value)) || messages.includes("self signed certificate") || messages.includes("certificate has expired") || messages.includes("unable to verify the first certificate") || messages.includes("unable to get local issuer certificate") || messages.includes("hostname/ip does not match certificate") || messages.includes("tls handshake") || messages.includes("ssl routines") || messages.includes("econnrefused") || messages.includes("enotfound")) return {
232
+ classification: "deterministic",
233
+ name,
234
+ message,
235
+ code,
236
+ causeCode
237
+ };
238
+ if (name === "AbortError" || name === "TimeoutError" || name === "InactivityTimeout" || codes.some((value) => TRANSIENT_CODES.has(value)) || messages.includes("terminated") || messages.includes("fetch failed") || messages.includes("network error") || messages.includes("socket hang up") || messages.includes("socket closed") || messages.includes("econnreset") || messages.includes("etimedout") || messages.includes("epipe") || messages.includes("eai_again")) return {
239
+ classification: "transient",
240
+ name,
241
+ message,
242
+ code,
243
+ causeCode
244
+ };
245
+ return {
246
+ classification: "non_transport",
247
+ name,
248
+ message,
249
+ code,
250
+ causeCode
251
+ };
252
+ }
253
+ function transportExhaustion(error, attempts, opts, details) {
254
+ if (details.classification !== "transient" && details.classification !== "deterministic") throw new TypeError("transportExhaustion requires a transport error");
255
+ return new TransportExhaustionError({
256
+ endpoint: opts.endpoint ?? opts.label,
257
+ label: opts.label,
258
+ attempts,
259
+ classification: details.classification,
260
+ lastError: {
261
+ name: details.name,
262
+ message: details.message,
263
+ code: details.code,
264
+ causeCode: details.causeCode
265
+ }
266
+ }, error);
267
+ }
237
268
  function parseRetryAfter(headerValue) {
238
269
  if (!headerValue) return void 0;
239
270
  const secs = Number(headerValue);
@@ -241,27 +272,6 @@ function parseRetryAfter(headerValue) {
241
272
  const dateMs = Date.parse(headerValue);
242
273
  if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
243
274
  }
244
- /**
245
- * A thrown fetch error that is worth retrying — network resets, broken
246
- * pipes, DNS hiccups, and timeout aborts. NOTE: the caller must already
247
- * have ruled out a user cancel (caller signal aborted) before calling
248
- * this, since a timeout abort and a user-cancel abort look identical.
249
- */
250
- function isTransientNetworkError(err) {
251
- const e = err;
252
- if (!e) return false;
253
- if (e.name === "AbortError" || e.name === "TimeoutError") return true;
254
- const msg = (e.message ?? "").toLowerCase();
255
- if (msg.includes("terminated") || msg.includes("fetch failed") || msg.includes("network") || msg.includes("socket") || msg.includes("econnreset") || msg.includes("etimedout") || msg.includes("econnrefused") || msg.includes("epipe") || msg.includes("enotfound")) return true;
256
- const code = e.code ?? e.cause?.code;
257
- return code !== void 0 && [
258
- "ECONNRESET",
259
- "ETIMEDOUT",
260
- "ECONNREFUSED",
261
- "EPIPE",
262
- "ENOTFOUND"
263
- ].includes(code);
264
- }
265
275
  /** Sleep that resolves early (does not reject) when `signal` aborts — the
266
276
  * retry loop re-checks `signal.aborted` at the top and throws there. */
267
277
  function abortableSleep(ms, signal) {
@@ -310,11 +320,14 @@ async function fetchWithTransientRetry(doFetch, opts = {}) {
310
320
  if (res && !retryStatuses.includes(res.status)) return res;
311
321
  if (caught !== void 0) {
312
322
  if (signal?.aborted) throw caught;
313
- if (!isTransientNetworkError(caught)) throw caught;
323
+ const details = classifyTransportError(caught);
324
+ if (details.classification === "deterministic") throw transportExhaustion(caught, attempt, opts, details);
325
+ if (details.classification !== "transient") throw caught;
314
326
  }
315
327
  if (attempt >= attempts) {
316
328
  if (res) return res;
317
- throw caught;
329
+ const details = classifyTransportError(caught);
330
+ throw transportExhaustion(caught, attempt, opts, details);
318
331
  }
319
332
  const retryAfterMs = res ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
320
333
  if (res?.body) try {
@@ -364,7 +377,14 @@ async function withTransientRetry(fn, opts = {}) {
364
377
  } catch (err) {
365
378
  if (signal?.aborted) throw err;
366
379
  const status = errorStatus(err);
367
- if (!(status !== void 0 && retryStatuses.includes(status) || isTransientNetworkError(err)) || attempt >= attempts) throw err;
380
+ const details = classifyTransportError(err);
381
+ if (status !== void 0) {
382
+ if (!retryStatuses.includes(status) || attempt >= attempts) throw err;
383
+ } else {
384
+ if (details.classification === "deterministic") throw transportExhaustion(err, attempt, opts, details);
385
+ if (details.classification !== "transient") throw err;
386
+ if (attempt >= attempts) throw transportExhaustion(err, attempt, opts, details);
387
+ }
368
388
  const retryAfterMs = parseRetryAfter(err?.response?.headers?.get?.("retry-after") ?? null);
369
389
  const expCap = Math.min(maxDelayMs, baseDelayMs * 2 ** (attempt - 1));
370
390
  const delay = Math.min(maxDelayMs, retryAfterMs ?? Math.round(Math.random() * expCap));
@@ -374,6 +394,146 @@ async function withTransientRetry(fn, opts = {}) {
374
394
  }
375
395
  }
376
396
  //#endregion
397
+ //#region src/lib/error.ts
398
+ var HTTPError = class extends Error {
399
+ response;
400
+ constructor(message, response) {
401
+ super(message);
402
+ this.response = response;
403
+ }
404
+ };
405
+ async function forwardError(c, error) {
406
+ consola.error(`Error occurred at ${c.req.path}:`, error);
407
+ if (error instanceof TransportExhaustionError) {
408
+ const target = sanitizeTransportText(error.endpoint ?? error.label ?? c.req.path);
409
+ const diagnostic = formatTransportDiagnostic(error);
410
+ if (error.classification === "transient") return c.json({
411
+ type: "error",
412
+ error: {
413
+ type: "overloaded_error",
414
+ message: `Upstream transport was interrupted at ${target} after ${error.attempts} attempts; retry later. ${diagnostic}`
415
+ }
416
+ }, 503);
417
+ return c.json({
418
+ type: "error",
419
+ error: {
420
+ type: "api_error",
421
+ message: `Could not connect to upstream at ${target}. Check DNS, proxy, firewall, and TLS configuration. ${diagnostic}`
422
+ }
423
+ }, 502);
424
+ }
425
+ if (error instanceof HTTPError) {
426
+ const errorText = await error.response.text().catch(() => "");
427
+ let errorJson;
428
+ try {
429
+ errorJson = JSON.parse(errorText);
430
+ } catch {
431
+ errorJson = void 0;
432
+ }
433
+ if (isContextOverflow(error.response.status, errorJson, errorText)) {
434
+ const upstream = resolveErrorMessage(errorJson, errorText);
435
+ consola.error("HTTP error (mapped to overflow):", errorJson ?? errorText);
436
+ return c.json({
437
+ type: "error",
438
+ error: {
439
+ type: "invalid_request_error",
440
+ message: `prompt is too long: ${upstream}`
441
+ }
442
+ }, 400);
443
+ }
444
+ const responseStatus = error.response.status === 401 ? 503 : error.response.status;
445
+ if (isAnthropicError(errorJson)) {
446
+ consola.error("HTTP error:", errorJson);
447
+ return c.json(errorJson, responseStatus);
448
+ }
449
+ const message = resolveErrorMessage(errorJson, errorText);
450
+ consola.error("HTTP error:", errorJson ?? errorText);
451
+ return c.json({
452
+ type: "error",
453
+ error: {
454
+ type: resolveErrorType(responseStatus),
455
+ message
456
+ }
457
+ }, responseStatus);
458
+ }
459
+ return c.json({
460
+ type: "error",
461
+ error: {
462
+ type: "api_error",
463
+ message: error instanceof Error ? error.message : String(error)
464
+ }
465
+ }, 500);
466
+ }
467
+ function formatTransportDiagnostic(error) {
468
+ const code = error.lastError.causeCode ?? error.lastError.code;
469
+ const codeText = code ? ` (${sanitizeTransportText(code)})` : "";
470
+ return `${sanitizeTransportText(error.lastError.name)}: ${sanitizeTransportText(error.lastError.message)}${codeText}`;
471
+ }
472
+ function resolveErrorMessage(errorJson, fallback) {
473
+ if (typeof errorJson !== "object" || errorJson === null) return fallback;
474
+ const errorRecord = errorJson;
475
+ if (errorRecord.message !== void 0) return String(errorRecord.message);
476
+ if (typeof errorRecord.error === "object" && errorRecord.error !== null) {
477
+ const nestedRecord = errorRecord.error;
478
+ if (nestedRecord.message !== void 0) return String(nestedRecord.message);
479
+ }
480
+ return fallback;
481
+ }
482
+ /**
483
+ * Check if a parsed JSON body is already in Anthropic error format:
484
+ * { type: "error", error: { type: "...", message: "..." } }
485
+ */
486
+ function isAnthropicError(json) {
487
+ if (typeof json !== "object" || json === null) return false;
488
+ const record = json;
489
+ if (record.type !== "error") return false;
490
+ if (typeof record.error !== "object" || record.error === null) return false;
491
+ const inner = record.error;
492
+ return typeof inner.type === "string" && typeof inner.message === "string";
493
+ }
494
+ const CONTEXT_OVERFLOW_SUBSTRINGS = [
495
+ "prompt is too long",
496
+ "context_length_exceeded",
497
+ "context length exceeded",
498
+ "input is too long",
499
+ "maximum context length",
500
+ "too many tokens"
501
+ ];
502
+ /**
503
+ * Detect upstream context-overflow errors so we can remap them to a 400
504
+ * "prompt is too long" shape that triggers Claude Code self-compaction.
505
+ *
506
+ * Always remaps 413 (treated as a hard payload-size signal regardless of
507
+ * body wording). Remaps 400 only when the error text contains one of the
508
+ * known overflow substrings — a regular 400 (e.g. "model not found") must
509
+ * NOT remap.
510
+ */
511
+ function isContextOverflow(status, errorJson, errorText) {
512
+ if (status === 413) return true;
513
+ if (status !== 400) return false;
514
+ const haystack = (errorText + " " + (typeof errorJson === "object" && errorJson !== null ? JSON.stringify(errorJson) : "")).toLowerCase();
515
+ return CONTEXT_OVERFLOW_SUBSTRINGS.some((s) => haystack.includes(s));
516
+ }
517
+ /**
518
+ * Map HTTP status to Anthropic error type.
519
+ *
520
+ * Note: a 401 from upstream is remapped to 503 in `forwardError` BEFORE
521
+ * this function is called (no-401 invariant — see comment there). The
522
+ * 401 → "authentication_error" mapping below is preserved for
523
+ * defensive coverage in case any code path calls `resolveErrorType`
524
+ * directly with an unsanitized status.
525
+ */
526
+ function resolveErrorType(status) {
527
+ if (status === 400) return "invalid_request_error";
528
+ if (status === 401) return "authentication_error";
529
+ if (status === 403) return "permission_error";
530
+ if (status === 404) return "not_found_error";
531
+ if (status === 429) return "rate_limit_error";
532
+ if (status === 503) return "overloaded_error";
533
+ if (status === 529) return "overloaded_error";
534
+ return "api_error";
535
+ }
536
+ //#endregion
377
537
  //#region src/services/github/get-copilot-token.ts
378
538
  /**
379
539
  * Allowlist of hosts the router will trust as the Copilot API base URL.
@@ -1180,6 +1340,6 @@ async function warnIfAgentScopesInsufficient() {
1180
1340
  }
1181
1341
  }
1182
1342
  //#endregion
1183
- export { copilotHeaders as C, githubHeaders as D, githubAgentHeaders as E, state as O, copilotBaseUrl as S, githubAgentGraphQLHeaders as T, withTransientRetry as _, cacheCopilotVersion as a, GITHUB_API_BASE_URL as b, filterBetaHeader as c, resolveModel as d, sleep as f, fetchWithTransientRetry as g, isAllowedCopilotHost as h, tryRefreshAndRetry as i, isNullish as l, getGitHubUser as m, setupGitHubAgentToken as n, cacheModels as o, getModels as p, setupGitHubToken as r, cacheVSCodeVersion as s, setupCopilotToken as t, resolveCodexModel as u, HTTPError as v, copilotVersion as w, GITHUB_GRAPHQL_URL as x, forwardError as y };
1343
+ export { state as A, GITHUB_GRAPHQL_URL as C, githubAgentGraphQLHeaders as D, copilotVersion as E, githubAgentHeaders as O, GITHUB_API_BASE_URL as S, copilotHeaders as T, forwardError as _, cacheCopilotVersion as a, sanitizeTransportText as b, filterBetaHeader as c, resolveModel as d, sleep as f, HTTPError as g, isAllowedCopilotHost as h, tryRefreshAndRetry as i, githubHeaders as k, isNullish as l, getGitHubUser as m, setupGitHubAgentToken as n, cacheModels as o, getModels as p, setupGitHubToken as r, cacheVSCodeVersion as s, setupCopilotToken as t, resolveCodexModel as u, classifyTransportError as v, copilotBaseUrl as w, withTransientRetry as x, fetchWithTransientRetry as y };
1184
1344
 
1185
- //# sourceMappingURL=token-C_q95GF7.js.map
1345
+ //# sourceMappingURL=token-iaSGp76k.js.map