github-router 0.3.315 → 0.3.316
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{attribution-settings-DXmmyuEE.js → attribution-settings-jcsSeVur.js} +116 -17
- package/dist/attribution-settings-jcsSeVur.js.map +1 -0
- package/dist/{auth-D8t41c5D.js → auth-JfxL9q7z.js} +3 -3
- package/dist/{auth-D8t41c5D.js.map → auth-JfxL9q7z.js.map} +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/{check-usage-BpBKOjGZ.js → check-usage-DXUEQzt_.js} +3 -3
- package/dist/{check-usage-BpBKOjGZ.js.map → check-usage-DXUEQzt_.js.map} +1 -1
- package/dist/{claude-Cmmu3-cL.js → claude-CJ4Nd2_3.js} +94 -29
- package/dist/claude-CJ4Nd2_3.js.map +1 -0
- package/dist/{codex-DqTKKoEx.js → codex-CwuLqNZF.js} +6 -6
- package/dist/codex-CwuLqNZF.js.map +1 -0
- package/dist/engine-DwrxceOS.js +2 -0
- package/dist/{gate-discovery-CPk6Z8yc.js → gate-discovery-z04ywOzB.js} +2 -2
- package/dist/{gate-discovery-CPk6Z8yc.js.map → gate-discovery-z04ywOzB.js.map} +1 -1
- package/dist/{get-copilot-usage-FSQE8szQ.js → get-copilot-usage-BMD_cJNT.js} +3 -3
- package/dist/{get-copilot-usage-FSQE8szQ.js.map → get-copilot-usage-BMD_cJNT.js.map} +1 -1
- package/dist/hooks.mjs +1 -0
- package/dist/hooks.sha256 +1 -1
- package/dist/{internal-max-dispatch-guard-l1NGYHtF.js → internal-max-dispatch-guard-BNqQ2wMc.js} +2 -2
- package/dist/{internal-max-dispatch-guard-l1NGYHtF.js.map → internal-max-dispatch-guard-BNqQ2wMc.js.map} +1 -1
- package/dist/{internal-max-dispatch-guard-BzKsY9ze.js → internal-max-dispatch-guard-Bz7a2Ntf.js} +1 -1
- package/dist/{internal-stop-hook-BKiKYeda.js → internal-stop-hook-UN1JHtjj.js} +2 -2
- package/dist/{internal-stop-hook-BKiKYeda.js.map → internal-stop-hook-UN1JHtjj.js.map} +1 -1
- package/dist/main.js +9 -9
- package/dist/{max-profile-contract-BcrMlrmo.js → max-profile-contract-Bl7I_EOC.js} +2 -2
- package/dist/{max-profile-contract-BcrMlrmo.js.map → max-profile-contract-Bl7I_EOC.js.map} +1 -1
- package/dist/{models-DgLeb-Dv.js → models-CVzyU5mJ.js} +2 -2
- package/dist/{models-DgLeb-Dv.js.map → models-CVzyU5mJ.js.map} +1 -1
- package/dist/{peer-mcp-personas-CYWJSxPK.js → peer-mcp-personas-CQ-0Piyr.js} +166 -45
- package/dist/peer-mcp-personas-CQ-0Piyr.js.map +1 -0
- package/dist/{provision-AwSjt-vR.js → provision-_R7ZMygj.js} +2 -2
- package/dist/{provision-AwSjt-vR.js.map → provision-_R7ZMygj.js.map} +1 -1
- package/dist/{serve-BG2O6Slz.js → serve-DU66K5kv.js} +7 -7
- package/dist/{serve-BG2O6Slz.js.map → serve-DU66K5kv.js.map} +1 -1
- package/dist/{server-setup-D7ABbEs1.js → server-setup-iLG8LrfL.js} +165 -27
- package/dist/server-setup-iLG8LrfL.js.map +1 -0
- package/dist/{start-Dpwpnq99.js → start-DQTcm0o_.js} +3 -3
- package/dist/{start-Dpwpnq99.js.map → start-DQTcm0o_.js.map} +1 -1
- package/dist/{state-B8adscCv.js → state-BlMpEFAt.js} +2 -1
- package/dist/{state-B8adscCv.js.map → state-BlMpEFAt.js.map} +1 -1
- package/dist/{token-ClzS23Y2.js → token-C1gthnbV.js} +2 -2
- package/dist/{token-ClzS23Y2.js.map → token-C1gthnbV.js.map} +1 -1
- package/package.json +1 -1
- package/dist/attribution-settings-DXmmyuEE.js.map +0 -1
- package/dist/claude-Cmmu3-cL.js.map +0 -1
- package/dist/codex-DqTKKoEx.js.map +0 -1
- package/dist/engine-b9XaKLp0.js +0 -2
- package/dist/peer-mcp-personas-CYWJSxPK.js.map +0 -1
- package/dist/server-setup-D7ABbEs1.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { in as provisionAndIndexColbert, rn as colbertDegradedWarning, sn as warmTreeSitterPool, tn as provisionBrowserAssets, ut as browserToolsEnabled } from "./peer-mcp-personas-CQ-0Piyr.js";
|
|
2
|
+
import { a as sharedServerArgs, i as setupAndServe, n as getCodexEnvVars, r as parseSharedArgs, s as startKeepAwake, t as getClaudeCodeEnvVars, w as runSelfUpdate } from "./server-setup-iLG8LrfL.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-
|
|
132
|
+
//# sourceMappingURL=start-DQTcm0o_.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-Dpwpnq99.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-DQTcm0o_.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). Opt-IN via --search (no-op otherwise);\n // never blocks launch, never throws.\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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"}
|
|
@@ -17,6 +17,7 @@ const state = {
|
|
|
17
17
|
fleetEnabled: false,
|
|
18
18
|
agentsEnabled: false,
|
|
19
19
|
powerBrowseEnabled: false,
|
|
20
|
+
searchEnabled: false,
|
|
20
21
|
humanlikeForce: "auto",
|
|
21
22
|
sessionId: randomUUID(),
|
|
22
23
|
machineId: randomBytes(32).toString("hex"),
|
|
@@ -48,4 +49,4 @@ Object.defineProperty(state, "peerMcpNonce", {
|
|
|
48
49
|
//#endregion
|
|
49
50
|
export { state as t };
|
|
50
51
|
|
|
51
|
-
//# sourceMappingURL=state-
|
|
52
|
+
//# sourceMappingURL=state-BlMpEFAt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-B8adscCv.js","names":[],"sources":["../src/lib/state.ts"],"sourcesContent":["import { randomBytes, randomUUID } from \"node:crypto\"\n\nimport type { ModelsResponse } from \"~/services/copilot/get-models\"\nimport type { LaunchProfileId } from \"./launch-profile\"\n\n/**\n * One authenticated `github-router claude` (or `serve`) launch's identity\n * and capability scope, keyed by `launchId` in `state.launchRegistry`.\n *\n * Replaces the earlier scalar `state.peerMcpNonce` assumption — a single\n * process-global nonce cannot express \"which profile is this caller\", so\n * a concurrent fast + standard launch (or a reconnect) had no way to keep\n * their identities from being interchangeable. Each entry carries BOTH\n * credentials a launch presents on the wire:\n *\n * - `nonce` — the `/mcp` bearer (Streamable HTTP `Authorization` header).\n * - `secret` — the `/v1/messages` identity-preflight bearer, deliberately\n * a SEPARATE credential from `nonce` so leaking one surface's token\n * (say, via a client log) does not also authenticate the other.\n *\n * `allowedGroups` / `allowedPersonas` are the narrowing declaration for\n * scoped MCP surfaces: `undefined` means UNRESTRICTED (the standard/BYO\n * launch shape today), and a concrete `ReadonlySet` is a restricted profile's\n * hard allow-list. This module only stores and looks up the declaration;\n * enforcing it against `tools/list` / `tools/call` is the MCP route\n * handler's job.\n */\nexport interface LaunchRegistryEntry {\n /** Opaque per-launch id. Primary key into `state.launchRegistry`. */\n launchId: string\n /** `/mcp` Streamable HTTP bearer for this launch. */\n nonce: string\n /**\n * Optional lead-only `/mcp` bearer for fast profile.\n * Grants access to lead-only tools such as `astra`.\n */\n leadPeersNonce?: string\n /** `/v1/messages` identity-preflight bearer for this launch. */\n secret: string\n /** Which launch profile authenticated this entry. */\n profileId: LaunchProfileId\n /** Scoped MCP group allow-list. `undefined` = unrestricted. */\n allowedGroups?: ReadonlySet<string>\n /** Persona (peers-group) tool-name allow-list. `undefined` = unrestricted. */\n allowedPersonas?: ReadonlySet<string>\n createdAt: number\n}\n\n/**\n * Registry key backing the `state.peerMcpNonce` back-compat accessor\n * below. Not a real launch id (no `registerLaunch` caller ever produces\n * this string), so it can never collide with a genuine per-launch UUID.\n */\nconst DEFAULT_LAUNCH_ID = \"__default__\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n /**\n * Where `githubToken` came from, which decides whether the proxy may\n * re-read it from disk.\n *\n * `\"file\"` — read from `PATHS.GITHUB_TOKEN_PATH`. A re-read is allowed, so\n * an out-of-band `github-router auth` heals a running proxy without a\n * restart.\n *\n * `\"explicit\"` — supplied by the operator via `--github-token` / `GH_TOKEN`.\n * The file is NEVER read on this path: silently replacing a\n * caller-supplied credential with whatever happens to be on disk would\n * override an explicit instruction. It also means \"run `github-router\n * auth`\" is false advice for this source — the remediation is to replace\n * the supplied value.\n */\n githubTokenSource?: \"file\" | \"explicit\"\n\n /**\n * Monotonic counter bumped on every SUCCESSFUL Copilot token exchange.\n *\n * This is the retry criterion for `tryRefreshAndRetry`, and it is\n * deliberately not \"did the token string change\": two consecutive\n * successful exchanges were observed returning an identical token, so a\n * string comparison would silently suppress legitimate retries. Nor is it\n * the refresh's own verdict — with requests A and B both holding a stale\n * token, A can refresh while B's later 401 is cooled down to a no-op, and\n * a verdict of \"nothing happened\" would fail B even though a good token is\n * already in `copilotToken`. Comparing generations answers the question\n * each request actually has: \"is what is in state now different from what\n * I already tried?\"\n */\n copilotTokenGeneration: number\n\n /**\n * Wall-clock ms after which `copilotToken` should be refreshed — already\n * skew-adjusted, so the per-request check is a plain `Date.now() >=` compare.\n *\n * Derived from the exchange's `refresh_in` (a DURATION) and never from its\n * absolute `expires_at`. A local clock running ahead of GitHub's would make\n * an absolute timestamp look already-past on a brand-new token and drive a\n * refresh storm; a duration is immune, because it is anchored to the same\n * clock that later reads it.\n */\n copilotTokenRefreshAt?: number\n\n /**\n * Second, WRITE-capable GitHub token for the first-mate\n * agent-orchestration surface (`--agents`). Minted by a separate\n * device-flow login against the GitHub CLI's OAuth client\n * (`GITHUB_AGENT_CLIENT_ID`, scopes `repo workflow read:org`) and\n * stored at `PATHS.GITHUB_AGENT_TOKEN_PATH`, apart from `githubToken`\n * (the Copilot App token, read:user). The first-mate GitHub service\n * layer uses this for ALL its calls (reads included, so it also works\n * on private repos). Undefined until the agent login has run.\n */\n githubAgentToken?: 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 /**\n * Opt-in flag for the browser-control MCP tools (`browser_*`). Set by\n * `setupAndServe` from the `--browse` CLI flag or\n * `GH_ROUTER_ENABLE_BROWSE=1` env var. When false, all `browser_*`\n * tools are dropped from `tools/list` AND `tools/call` returns\n * -32601 — same defense-in-depth pattern as `workerToolsEnabled()` /\n * `standInToolEnabled()`. See `browserToolsEnabled()` in\n * `src/routes/mcp/handler.ts`.\n */\n browseEnabled: boolean\n\n /**\n * Opt-in flag for the fleet session-control MCP tools (`mcp__fleet__*`).\n * Set by `setupAndServe` from the `--fleet` CLI flag or\n * `GH_ROUTER_ENABLE_FLEET=1` env var. When false, all fleet tools are\n * dropped from `tools/list` AND `tools/call` returns -32601 — same\n * defense-in-depth pattern as `workerToolsEnabled()` /\n * `standInToolEnabled()`. See `fleetToolsEnabled()` in\n * `src/lib/mcp-capabilities.ts`.\n */\n fleetEnabled: boolean\n\n /**\n * Opt-in flag for the first-mate agent-orchestration MCP tools\n * (`mcp__first-mate__*`) and the in-process GitHub cloud-agent driving\n * layer. Set by `setupAndServe` from the `--agents` CLI flag or\n * `GH_ROUTER_ENABLE_AGENTS=1`. When false, the first-mate tools are\n * dropped from `tools/list` AND `tools/call` returns -32601 — same\n * defense-in-depth pattern as `fleetToolsEnabled()`. Additionally\n * requires `state.githubAgentToken` present (the write login), so the\n * surface is invisible rather than 401-ing when unauthenticated. See\n * `agentToolsEnabled()` in `src/lib/mcp-capabilities.ts`.\n */\n agentsEnabled: boolean\n\n /**\n * When true, --power-browse was passed (or GH_ROUTER_ENABLE_POWER_BROWSE=1\n * is set). Exposes the FULL browser MCP surface (~18 tools) on /mcp,\n * including the L0/L1 primitives that hand DOM details (refs,\n * bboxes, role/name dumps) to the lead model. Default --browse mode\n * exposes only the 6 lead-model tools (act, observe, extract,\n * navigate, screenshot, open_tab). Always implies browseEnabled.\n */\n powerBrowseEnabled: boolean\n\n /**\n * Humanlike pacing override:\n * \"on\" - --humanlike CLI flag or GH_ROUTER_HUMANLIKE=1 env;\n * inject Beta-distributed inter-action delays, Bezier\n * mouse paths, per-keystroke jitter, scroll chunking\n * into every browser_* action dispatch.\n * \"off\" - GH_ROUTER_BROWSER_NO_HUMANLIKE=1; HARD disable, wins\n * over \"on\" so tests are reproducible.\n * \"auto\" - default; pacing engages only when bot-challenge\n * detection fires (Phase 4-future).\n *\n * Lead model never sees this state — it's an internal concern.\n */\n humanlikeForce: \"on\" | \"off\" | \"auto\"\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 /**\n * Keyed per-launch registry for the loopback `/mcp` endpoint AND the\n * `/v1/messages` identity preflight. Set by the `claude` subcommand\n * (via `registerLaunch` in `./launch-registry`) after `setupAndServe`\n * and before spawning Claude Code; removed by the launch's own\n * cleanup. When empty, `/mcp` rejects all requests — closes the\n * loopback-no-auth gap (DNS rebinding, malicious browser-ext native\n * messaging, sibling-process probe) exactly as the old scalar nonce\n * did when unset.\n *\n * Multiple entries coexist for concurrent fast/standard launches (or a\n * launch plus a reconnect); each is looked up by its OWN nonce/secret,\n * so two launches' authenticated identities never cross.\n */\n launchRegistry: Map<string, LaunchRegistryEntry>\n\n /**\n * @deprecated Back-compat accessor over the registry's DEFAULT_LAUNCH_ID\n * entry (profileId \"standard\", unrestricted `allowedGroups`/\n * `allowedPersonas`) — defined below via `Object.defineProperty`, not a\n * real stored field. Reading returns that entry's nonce; writing creates\n * or updates it (or deletes it on `undefined`). Exists so single-launch\n * call sites and tests that already do `state.peerMcpNonce = NONCE`\n * keep working unmodified while `checkAuth` and the identity preflight\n * consult the real keyed registry underneath. New code should call\n * `registerLaunch` / `findLaunchByNonce` / `findLaunchBySecret` from\n * `./launch-registry` directly instead of reading/writing this field.\n */\n peerMcpNonce?: string\n\n /**\n * Set by `github-router serve` (a single machine-wide control plane serving\n * many repos). When true, repo-scoped worker tools require an explicit/So-derived\n * `workspace` and must NOT silently default to the proxy launch cwd.\n */\n serveMode?: boolean\n}\n\nexport const state: State = {\n accountType: \"enterprise\",\n copilotTokenGeneration: 0,\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n extendedBetas: false,\n browseEnabled: false,\n fleetEnabled: false,\n agentsEnabled: false,\n powerBrowseEnabled: false,\n humanlikeForce: \"auto\",\n sessionId: randomUUID(),\n machineId: randomBytes(32).toString(\"hex\"),\n launchRegistry: new Map(),\n}\n\n// `peerMcpNonce` is not a plain data field — it's a live view onto\n// `state.launchRegistry.get(DEFAULT_LAUNCH_ID)`. Defined via\n// `Object.defineProperty` (rather than a class) so `state` stays the\n// plain object literal every existing importer already destructures /\n// mutates directly.\nObject.defineProperty(state, \"peerMcpNonce\", {\n enumerable: true,\n configurable: true,\n get(): string | undefined {\n return state.launchRegistry.get(DEFAULT_LAUNCH_ID)?.nonce\n },\n set(value: string | undefined) {\n if (value === undefined) {\n state.launchRegistry.delete(DEFAULT_LAUNCH_ID)\n return\n }\n const existing = state.launchRegistry.get(DEFAULT_LAUNCH_ID)\n state.launchRegistry.set(DEFAULT_LAUNCH_ID, {\n launchId: DEFAULT_LAUNCH_ID,\n nonce: value,\n // A caller that only ever touches `peerMcpNonce` exposes MCP only and has\n // no Messages identity secret.\n // Never reuse the MCP bearer across surfaces: an empty secret cannot match\n // any non-empty custom header, while registered Claude launches always use\n // `registerLaunch` with independently generated credentials.\n secret: existing?.secret ?? \"\",\n profileId: existing?.profileId ?? \"standard\",\n allowedGroups: existing?.allowedGroups,\n allowedPersonas: existing?.allowedPersonas,\n createdAt: existing?.createdAt ?? Date.now(),\n })\n },\n})\n"],"mappings":";;;;;;;AAqDA,MAAM,oBAAoB;AAoL1B,MAAa,QAAe;CAC1B,aAAa;CACb,wBAAwB;CACxB,eAAe;CACf,eAAe;CACf,WAAW;CACX,eAAe;CACf,eAAe;CACf,cAAc;CACd,eAAe;CACf,oBAAoB;CACpB,gBAAgB;CAChB,WAAW,WAAW;CACtB,WAAW,YAAY,EAAE,CAAC,CAAC,SAAS,KAAK;CACzC,gCAAgB,IAAI,IAAI;AAC1B;AAOA,OAAO,eAAe,OAAO,gBAAgB;CAC3C,YAAY;CACZ,cAAc;CACd,MAA0B;EACxB,OAAO,MAAM,eAAe,IAAI,iBAAiB,CAAC,EAAE;CACtD;CACA,IAAI,OAA2B;EAC7B,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,eAAe,OAAO,iBAAiB;GAC7C;EACF;EACA,MAAM,WAAW,MAAM,eAAe,IAAI,iBAAiB;EAC3D,MAAM,eAAe,IAAI,mBAAmB;GAC1C,UAAU;GACV,OAAO;GAMP,QAAQ,UAAU,UAAU;GAC5B,WAAW,UAAU,aAAa;GAClC,eAAe,UAAU;GACzB,iBAAiB,UAAU;GAC3B,WAAW,UAAU,aAAa,KAAK,IAAI;EAC7C,CAAC;CACH;AACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"state-BlMpEFAt.js","names":[],"sources":["../src/lib/state.ts"],"sourcesContent":["import { randomBytes, randomUUID } from \"node:crypto\"\n\nimport type { ModelsResponse } from \"~/services/copilot/get-models\"\nimport type { LaunchProfileId } from \"./launch-profile\"\n\n/**\n * One authenticated `github-router claude` (or `serve`) launch's identity\n * and capability scope, keyed by `launchId` in `state.launchRegistry`.\n *\n * Replaces the earlier scalar `state.peerMcpNonce` assumption — a single\n * process-global nonce cannot express \"which profile is this caller\", so\n * a concurrent fast + standard launch (or a reconnect) had no way to keep\n * their identities from being interchangeable. Each entry carries BOTH\n * credentials a launch presents on the wire:\n *\n * - `nonce` — the `/mcp` bearer (Streamable HTTP `Authorization` header).\n * - `secret` — the `/v1/messages` identity-preflight bearer, deliberately\n * a SEPARATE credential from `nonce` so leaking one surface's token\n * (say, via a client log) does not also authenticate the other.\n *\n * `allowedGroups` / `allowedPersonas` are the narrowing declaration for\n * scoped MCP surfaces: `undefined` means UNRESTRICTED (the standard/BYO\n * launch shape today), and a concrete `ReadonlySet` is a restricted profile's\n * hard allow-list. This module only stores and looks up the declaration;\n * enforcing it against `tools/list` / `tools/call` is the MCP route\n * handler's job.\n */\nexport interface LaunchRegistryEntry {\n /** Opaque per-launch id. Primary key into `state.launchRegistry`. */\n launchId: string\n /** `/mcp` Streamable HTTP bearer for this launch. */\n nonce: string\n /**\n * Optional lead-only `/mcp` bearer for fast profile.\n * Grants access to lead-only tools such as `astra`.\n */\n leadPeersNonce?: string\n /** `/v1/messages` identity-preflight bearer for this launch. */\n secret: string\n /** Which launch profile authenticated this entry. */\n profileId: LaunchProfileId\n /** Scoped MCP group allow-list. `undefined` = unrestricted. */\n allowedGroups?: ReadonlySet<string>\n /** Persona (peers-group) tool-name allow-list. `undefined` = unrestricted. */\n allowedPersonas?: ReadonlySet<string>\n createdAt: number\n}\n\n/**\n * Registry key backing the `state.peerMcpNonce` back-compat accessor\n * below. Not a real launch id (no `registerLaunch` caller ever produces\n * this string), so it can never collide with a genuine per-launch UUID.\n */\nconst DEFAULT_LAUNCH_ID = \"__default__\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n /**\n * Where `githubToken` came from, which decides whether the proxy may\n * re-read it from disk.\n *\n * `\"file\"` — read from `PATHS.GITHUB_TOKEN_PATH`. A re-read is allowed, so\n * an out-of-band `github-router auth` heals a running proxy without a\n * restart.\n *\n * `\"explicit\"` — supplied by the operator via `--github-token` / `GH_TOKEN`.\n * The file is NEVER read on this path: silently replacing a\n * caller-supplied credential with whatever happens to be on disk would\n * override an explicit instruction. It also means \"run `github-router\n * auth`\" is false advice for this source — the remediation is to replace\n * the supplied value.\n */\n githubTokenSource?: \"file\" | \"explicit\"\n\n /**\n * Monotonic counter bumped on every SUCCESSFUL Copilot token exchange.\n *\n * This is the retry criterion for `tryRefreshAndRetry`, and it is\n * deliberately not \"did the token string change\": two consecutive\n * successful exchanges were observed returning an identical token, so a\n * string comparison would silently suppress legitimate retries. Nor is it\n * the refresh's own verdict — with requests A and B both holding a stale\n * token, A can refresh while B's later 401 is cooled down to a no-op, and\n * a verdict of \"nothing happened\" would fail B even though a good token is\n * already in `copilotToken`. Comparing generations answers the question\n * each request actually has: \"is what is in state now different from what\n * I already tried?\"\n */\n copilotTokenGeneration: number\n\n /**\n * Wall-clock ms after which `copilotToken` should be refreshed — already\n * skew-adjusted, so the per-request check is a plain `Date.now() >=` compare.\n *\n * Derived from the exchange's `refresh_in` (a DURATION) and never from its\n * absolute `expires_at`. A local clock running ahead of GitHub's would make\n * an absolute timestamp look already-past on a brand-new token and drive a\n * refresh storm; a duration is immune, because it is anchored to the same\n * clock that later reads it.\n */\n copilotTokenRefreshAt?: number\n\n /**\n * Second, WRITE-capable GitHub token for the first-mate\n * agent-orchestration surface (`--agents`). Minted by a separate\n * device-flow login against the GitHub CLI's OAuth client\n * (`GITHUB_AGENT_CLIENT_ID`, scopes `repo workflow read:org`) and\n * stored at `PATHS.GITHUB_AGENT_TOKEN_PATH`, apart from `githubToken`\n * (the Copilot App token, read:user). The first-mate GitHub service\n * layer uses this for ALL its calls (reads included, so it also works\n * on private repos). Undefined until the agent login has run.\n */\n githubAgentToken?: 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 /**\n * Opt-in flag for the browser-control MCP tools (`browser_*`). Set by\n * `setupAndServe` from the `--browse` CLI flag or\n * `GH_ROUTER_ENABLE_BROWSE=1` env var. When false, all `browser_*`\n * tools are dropped from `tools/list` AND `tools/call` returns\n * -32601 — same defense-in-depth pattern as `workerToolsEnabled()` /\n * `standInToolEnabled()`. See `browserToolsEnabled()` in\n * `src/routes/mcp/handler.ts`.\n */\n browseEnabled: boolean\n\n /**\n * Opt-in flag for the fleet session-control MCP tools (`mcp__fleet__*`).\n * Set by `setupAndServe` from the `--fleet` CLI flag or\n * `GH_ROUTER_ENABLE_FLEET=1` env var. When false, all fleet tools are\n * dropped from `tools/list` AND `tools/call` returns -32601 — same\n * defense-in-depth pattern as `workerToolsEnabled()` /\n * `standInToolEnabled()`. See `fleetToolsEnabled()` in\n * `src/lib/mcp-capabilities.ts`.\n */\n fleetEnabled: boolean\n\n /**\n * Opt-in flag for the first-mate agent-orchestration MCP tools\n * (`mcp__first-mate__*`) and the in-process GitHub cloud-agent driving\n * layer. Set by `setupAndServe` from the `--agents` CLI flag or\n * `GH_ROUTER_ENABLE_AGENTS=1`. When false, the first-mate tools are\n * dropped from `tools/list` AND `tools/call` returns -32601 — same\n * defense-in-depth pattern as `fleetToolsEnabled()`. Additionally\n * requires `state.githubAgentToken` present (the write login), so the\n * surface is invisible rather than 401-ing when unauthenticated. See\n * `agentToolsEnabled()` in `src/lib/mcp-capabilities.ts`.\n */\n agentsEnabled: boolean\n\n /**\n * When true, --power-browse was passed (or GH_ROUTER_ENABLE_POWER_BROWSE=1\n * is set). Exposes the FULL browser MCP surface (~18 tools) on /mcp,\n * including the L0/L1 primitives that hand DOM details (refs,\n * bboxes, role/name dumps) to the lead model. Default --browse mode\n * exposes only the 6 lead-model tools (act, observe, extract,\n * navigate, screenshot, open_tab). Always implies browseEnabled.\n */\n powerBrowseEnabled: boolean\n\n /**\n * Opt-in flag for ColBERT/colgrep semantic code search. Set by\n * `setupAndServe` from the `--search` CLI flag or\n * `GH_ROUTER_ENABLE_SEMANTIC_SEARCH=1` env var. When false, no colgrep\n * binary/model is provisioned, no workspace is indexed, and the `code`\n * MCP tool serves lexical results (with `lexical-fallback` source when\n * semantic mode was requested). See `semanticSearchOptedIn()` in\n * `src/lib/colbert/index.ts`; `GH_ROUTER_DISABLE_SEMANTIC_SEARCH=1`\n * hard-disables regardless of this flag.\n */\n searchEnabled: boolean\n\n /**\n * Humanlike pacing override:\n * \"on\" - --humanlike CLI flag or GH_ROUTER_HUMANLIKE=1 env;\n * inject Beta-distributed inter-action delays, Bezier\n * mouse paths, per-keystroke jitter, scroll chunking\n * into every browser_* action dispatch.\n * \"off\" - GH_ROUTER_BROWSER_NO_HUMANLIKE=1; HARD disable, wins\n * over \"on\" so tests are reproducible.\n * \"auto\" - default; pacing engages only when bot-challenge\n * detection fires (Phase 4-future).\n *\n * Lead model never sees this state — it's an internal concern.\n */\n humanlikeForce: \"on\" | \"off\" | \"auto\"\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 /**\n * Keyed per-launch registry for the loopback `/mcp` endpoint AND the\n * `/v1/messages` identity preflight. Set by the `claude` subcommand\n * (via `registerLaunch` in `./launch-registry`) after `setupAndServe`\n * and before spawning Claude Code; removed by the launch's own\n * cleanup. When empty, `/mcp` rejects all requests — closes the\n * loopback-no-auth gap (DNS rebinding, malicious browser-ext native\n * messaging, sibling-process probe) exactly as the old scalar nonce\n * did when unset.\n *\n * Multiple entries coexist for concurrent fast/standard launches (or a\n * launch plus a reconnect); each is looked up by its OWN nonce/secret,\n * so two launches' authenticated identities never cross.\n */\n launchRegistry: Map<string, LaunchRegistryEntry>\n\n /**\n * @deprecated Back-compat accessor over the registry's DEFAULT_LAUNCH_ID\n * entry (profileId \"standard\", unrestricted `allowedGroups`/\n * `allowedPersonas`) — defined below via `Object.defineProperty`, not a\n * real stored field. Reading returns that entry's nonce; writing creates\n * or updates it (or deletes it on `undefined`). Exists so single-launch\n * call sites and tests that already do `state.peerMcpNonce = NONCE`\n * keep working unmodified while `checkAuth` and the identity preflight\n * consult the real keyed registry underneath. New code should call\n * `registerLaunch` / `findLaunchByNonce` / `findLaunchBySecret` from\n * `./launch-registry` directly instead of reading/writing this field.\n */\n peerMcpNonce?: string\n\n /**\n * Set by `github-router serve` (a single machine-wide control plane serving\n * many repos). When true, repo-scoped worker tools require an explicit/So-derived\n * `workspace` and must NOT silently default to the proxy launch cwd.\n */\n serveMode?: boolean\n}\n\nexport const state: State = {\n accountType: \"enterprise\",\n copilotTokenGeneration: 0,\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n extendedBetas: false,\n browseEnabled: false,\n fleetEnabled: false,\n agentsEnabled: false,\n powerBrowseEnabled: false,\n searchEnabled: false,\n humanlikeForce: \"auto\",\n sessionId: randomUUID(),\n machineId: randomBytes(32).toString(\"hex\"),\n launchRegistry: new Map(),\n}\n\n// `peerMcpNonce` is not a plain data field — it's a live view onto\n// `state.launchRegistry.get(DEFAULT_LAUNCH_ID)`. Defined via\n// `Object.defineProperty` (rather than a class) so `state` stays the\n// plain object literal every existing importer already destructures /\n// mutates directly.\nObject.defineProperty(state, \"peerMcpNonce\", {\n enumerable: true,\n configurable: true,\n get(): string | undefined {\n return state.launchRegistry.get(DEFAULT_LAUNCH_ID)?.nonce\n },\n set(value: string | undefined) {\n if (value === undefined) {\n state.launchRegistry.delete(DEFAULT_LAUNCH_ID)\n return\n }\n const existing = state.launchRegistry.get(DEFAULT_LAUNCH_ID)\n state.launchRegistry.set(DEFAULT_LAUNCH_ID, {\n launchId: DEFAULT_LAUNCH_ID,\n nonce: value,\n // A caller that only ever touches `peerMcpNonce` exposes MCP only and has\n // no Messages identity secret.\n // Never reuse the MCP bearer across surfaces: an empty secret cannot match\n // any non-empty custom header, while registered Claude launches always use\n // `registerLaunch` with independently generated credentials.\n secret: existing?.secret ?? \"\",\n profileId: existing?.profileId ?? \"standard\",\n allowedGroups: existing?.allowedGroups,\n allowedPersonas: existing?.allowedPersonas,\n createdAt: existing?.createdAt ?? Date.now(),\n })\n },\n})\n"],"mappings":";;;;;;;AAqDA,MAAM,oBAAoB;AAgM1B,MAAa,QAAe;CAC1B,aAAa;CACb,wBAAwB;CACxB,eAAe;CACf,eAAe;CACf,WAAW;CACX,eAAe;CACf,eAAe;CACf,cAAc;CACd,eAAe;CACf,oBAAoB;CACpB,eAAe;CACf,gBAAgB;CAChB,WAAW,WAAW;CACtB,WAAW,YAAY,EAAE,CAAC,CAAC,SAAS,KAAK;CACzC,gCAAgB,IAAI,IAAI;AAC1B;AAOA,OAAO,eAAe,OAAO,gBAAgB;CAC3C,YAAY;CACZ,cAAc;CACd,MAA0B;EACxB,OAAO,MAAM,eAAe,IAAI,iBAAiB,CAAC,EAAE;CACtD;CACA,IAAI,OAA2B;EAC7B,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,eAAe,OAAO,iBAAiB;GAC7C;EACF;EACA,MAAM,WAAW,MAAM,eAAe,IAAI,iBAAiB;EAC3D,MAAM,eAAe,IAAI,mBAAmB;GAC1C,UAAU;GACV,OAAO;GAMP,QAAQ,UAAU,UAAU;GAC5B,WAAW,UAAU,aAAa;GAClC,eAAe,UAAU;GACzB,iBAAiB,UAAU;GAC3B,WAAW,UAAU,aAAa,KAAK,IAAI;EAC7C,CAAC;CACH;AACF,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as PATHS } from "./paths-CMxlQEfQ.js";
|
|
2
|
-
import { t as state } from "./state-
|
|
2
|
+
import { t as state } from "./state-BlMpEFAt.js";
|
|
3
3
|
import consola from "consola";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
@@ -1760,4 +1760,4 @@ async function warnIfAgentScopesInsufficient() {
|
|
|
1760
1760
|
//#endregion
|
|
1761
1761
|
export { 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 };
|
|
1762
1762
|
|
|
1763
|
-
//# sourceMappingURL=token-
|
|
1763
|
+
//# sourceMappingURL=token-C1gthnbV.js.map
|