@jeffreycao/copilot-api 1.12.0 → 1.12.3

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 CHANGED
@@ -561,6 +561,42 @@ Why these fields matter:
561
561
  - `model`, `small_model`, and `agent.*.model` let you keep `gpt-5.4` for build/plan work while routing exploration and background work to `gpt-5-mini`.
562
562
  - If you enable `auth.apiKeys` in this AI gateway, replace `dummy` with a real key. Otherwise any placeholder value is fine.
563
563
 
564
+ ## Using with Codex
565
+
566
+ This AI gateway can also power Codex.
567
+
568
+ ### Codex `config.toml` Reference
569
+
570
+ Add the following `[model_providers.copilot_api]` section to your Codex `~/.codex/config.toml`:
571
+
572
+ ```toml
573
+ model_provider = "copilot_api"
574
+ model_reasoning_summary = "auto"
575
+ model_verbosity = "medium"
576
+ model_context_window = 272000
577
+ model_auto_compact_token_limit = 244800
578
+
579
+ [model_providers.copilot_api]
580
+ name = "OpenAI"
581
+ base_url = "http://localhost:4141"
582
+ env_key = "GITHUB_COPILOT_API_KEY"
583
+ requires_openai_auth = true
584
+ supports_websockets = false
585
+ wire_api = "responses"
586
+ request_max_retries = 3
587
+ stream_max_retries = 1
588
+ stream_idle_timeout_ms = 300000
589
+
590
+ [features]
591
+ remote_compaction_v2 = true
592
+
593
+ [analytics]
594
+ enabled = false
595
+ ```
596
+
597
+ > [!NOTE]
598
+ > This configuration is specific to Codex and the GitHub Copilot provider. `name` must be set to `"OpenAI"`. It can help mitigate Codex local compact cache miss issues. If you have enabled `useResponsesApiContextManagement` (Responses API context management compaction), `remote_compaction_v2` or local compact is generally not triggered, but it may still occur when tool results return a large number of tokens.
599
+
564
600
  ## Plugin Integrations
565
601
 
566
602
  Plugin integrations are available for Claude Code and opencode.
package/README.zh-CN.md CHANGED
@@ -565,6 +565,42 @@ npx @jeffreycao/copilot-api@latest --oauth-app=opencode start
565
565
  - `model`、`small_model` 与 `agent.*.model` 让你可以把 `gpt-5.4` 用于 build/plan,同时把探索和后台工作路由到 `gpt-5-mini`。
566
566
  - 如果你在此代理中启用了 `auth.apiKeys`,请把 `dummy` 替换为真实 key;否则任意占位值都可以。
567
567
 
568
+ ## 与 Codex 一起使用
569
+
570
+ 这个 AI gateway 也可以为 Codex 提供后端能力。
571
+
572
+ ### Codex `config.toml` 参考配置
573
+
574
+ 把以下 `[model_providers.copilot_api]` 段加入你的 Codex `~/.codex/config.toml`:
575
+
576
+ ```toml
577
+ model_provider = "copilot_api"
578
+ model_reasoning_summary = "auto"
579
+ model_verbosity = "medium"
580
+ model_context_window = 272000
581
+ model_auto_compact_token_limit = 244800
582
+
583
+ [model_providers.copilot_api]
584
+ name = "OpenAI"
585
+ base_url = "http://localhost:4141"
586
+ env_key = "GITHUB_COPILOT_API_KEY"
587
+ requires_openai_auth = true
588
+ supports_websockets = false
589
+ wire_api = "responses"
590
+ request_max_retries = 3
591
+ stream_max_retries = 1
592
+ stream_idle_timeout_ms = 300000
593
+
594
+ [features]
595
+ remote_compaction_v2 = true
596
+
597
+ [analytics]
598
+ enabled = false
599
+ ```
600
+
601
+ > [!NOTE]
602
+ > 此配置仅限于 Codex 与 GitHub Copilot provider。`name` 一定要配置为 `"OpenAI"`。它可以缓解 Codex local compact 不命中缓存的问题。如果你已开启 `useResponsesApiContextManagement`(Responses API context management 压缩),通常不会走到 `remote_compaction_v2` 或者 local compact,但如果工具返回 tokens 过大,仍有可能触发。
603
+
568
604
  <a id="plugin-integrations"></a>
569
605
 
570
606
  ## 插件集成
@@ -1,5 +1,5 @@
1
1
  import { S as ensurePaths, x as PATHS } from "./config-DA-Jdm0G.js";
2
- import { A as loginCodex, R as state, a as setupGitHubToken, n as persistCodexCredentials } from "./token-Nj-1C8tP.js";
2
+ import { A as loginCodex, R as state, a as setupGitHubToken, n as persistCodexCredentials } from "./token-BiWRaRze.js";
3
3
  import { defineCommand } from "citty";
4
4
  import consola from "consola";
5
5
  //#region src/auth.ts
@@ -71,6 +71,7 @@ async function loginWithProvider(provider) {
71
71
  await loginWithCodex();
72
72
  }
73
73
  async function runAuthLogin(options) {
74
+ (await import("./tls-CaLAeSaF.js")).enableSystemCACompat();
74
75
  if (options.verbose) {
75
76
  consola.level = 5;
76
77
  consola.info("Verbose logging enabled");
@@ -113,4 +114,4 @@ const auth = defineCommand({
113
114
  //#endregion
114
115
  export { auth };
115
116
 
116
- //# sourceMappingURL=auth-DIHsuzzC.js.map
117
+ //# sourceMappingURL=auth-hKS7kdCx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-DIHsuzzC.js","names":[],"sources":["../src/auth.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { loginCodex } from \"./lib/oauth/codex\"\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { persistCodexCredentials, setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n provider?: string\n verbose: boolean\n showToken: boolean\n}\n\nconst authArgs = {\n provider: {\n type: \"string\",\n description: \"Provider to log in with (copilot or codex)\",\n },\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 provider access token on auth\",\n },\n} as const\n\nconst BUILTIN_PROVIDER_NAMES = [\"copilot\", \"codex\"] as const\n\ntype BuiltinProviderName = (typeof BUILTIN_PROVIDER_NAMES)[number]\n\nconst BUILTIN_PROVIDER_LABELS: Record<BuiltinProviderName, string> = {\n copilot: \"GitHub Copilot\",\n codex: \"OpenAI Codex\",\n}\n\nfunction isBuiltinProviderName(\n providerName: string,\n): providerName is BuiltinProviderName {\n return BUILTIN_PROVIDER_NAMES.includes(providerName as BuiltinProviderName)\n}\n\nasync function resolveProviderSelection(\n providerArg: string | undefined,\n): Promise<BuiltinProviderName> {\n const availableProviders = [...BUILTIN_PROVIDER_NAMES]\n\n if (providerArg !== undefined) {\n const providerName = providerArg.trim()\n if (!isBuiltinProviderName(providerName)) {\n throw new Error(\n `Unknown provider '${providerArg}'. Expected one of: ${availableProviders.join(\", \")}`,\n )\n }\n return providerName\n }\n\n if (availableProviders.length === 1) {\n return availableProviders[0]\n }\n\n const provider = await consola.prompt(\"Select a provider to log in with\", {\n type: \"select\",\n options: availableProviders.map((providerName) => ({\n label: `${BUILTIN_PROVIDER_LABELS[providerName]} (${providerName})`,\n value: providerName,\n })),\n })\n\n if (!provider || !isBuiltinProviderName(provider)) {\n throw new Error(\"No provider selected\")\n }\n\n return provider\n}\n\nasync function loginWithCodex(): Promise<void> {\n const credentials = await loginCodex({\n onAuth(info) {\n consola.info(\"Open the following URL to authenticate with Codex:\")\n consola.log(info.url)\n if (info.instructions) {\n consola.info(info.instructions)\n }\n },\n onPrompt(message) {\n return consola.prompt(message, {\n type: \"text\",\n })\n },\n onProgress(message) {\n consola.debug(message)\n },\n })\n\n await persistCodexCredentials(credentials, { enableProvider: true })\n consola.success(\n `Codex provider config written to ${PATHS.CONFIG_PATH} and credentials written to ${PATHS.CODEX_CREDENTIAL_PATH}`,\n )\n}\n\nasync function loginWithProvider(provider: BuiltinProviderName): Promise<void> {\n if (provider === \"copilot\") {\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n return\n }\n\n await loginWithCodex()\n}\n\nexport async function runAuthLogin(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 const provider = await resolveProviderSelection(options.provider)\n\n consola.info(`Logging in with ${BUILTIN_PROVIDER_LABELS[provider]}`)\n await loginWithProvider(provider)\n}\n\nconst authLogin = defineCommand({\n meta: {\n name: \"login\",\n description: \"Authenticate a builtin provider without running the server\",\n },\n args: authArgs,\n run({ args }) {\n return runAuthLogin({\n provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run authentication flows without running the server\",\n },\n args: authArgs,\n subCommands: {\n login: authLogin,\n },\n run({ args }) {\n if ((args._[0] ?? \"\").trim()) {\n return\n }\n\n return runAuthLogin({\n provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n"],"mappings":";;;;;AAgBA,MAAM,WAAW;CACf,UAAU;EACR,MAAM;EACN,aAAa;EACd;CACD,SAAS;EACP,OAAO;EACP,MAAM;EACN,SAAS;EACT,aAAa;EACd;CACD,cAAc;EACZ,MAAM;EACN,SAAS;EACT,aAAa;EACd;CACF;AAED,MAAM,yBAAyB,CAAC,WAAW,QAAQ;AAInD,MAAM,0BAA+D;CACnE,SAAS;CACT,OAAO;CACR;AAED,SAAS,sBACP,cACqC;CACrC,OAAO,uBAAuB,SAAS,aAAoC;;AAG7E,eAAe,yBACb,aAC8B;CAC9B,MAAM,qBAAqB,CAAC,GAAG,uBAAuB;CAEtD,IAAI,gBAAgB,KAAA,GAAW;EAC7B,MAAM,eAAe,YAAY,MAAM;EACvC,IAAI,CAAC,sBAAsB,aAAa,EACtC,MAAM,IAAI,MACR,qBAAqB,YAAY,sBAAsB,mBAAmB,KAAK,KAAK,GACrF;EAEH,OAAO;;CAGT,IAAI,mBAAmB,WAAW,GAChC,OAAO,mBAAmB;CAG5B,MAAM,WAAW,MAAM,QAAQ,OAAO,oCAAoC;EACxE,MAAM;EACN,SAAS,mBAAmB,KAAK,kBAAkB;GACjD,OAAO,GAAG,wBAAwB,cAAc,IAAI,aAAa;GACjE,OAAO;GACR,EAAE;EACJ,CAAC;CAEF,IAAI,CAAC,YAAY,CAAC,sBAAsB,SAAS,EAC/C,MAAM,IAAI,MAAM,uBAAuB;CAGzC,OAAO;;AAGT,eAAe,iBAAgC;CAmB7C,MAAM,wBAAwB,MAlBJ,WAAW;EACnC,OAAO,MAAM;GACX,QAAQ,KAAK,qDAAqD;GAClE,QAAQ,IAAI,KAAK,IAAI;GACrB,IAAI,KAAK,cACP,QAAQ,KAAK,KAAK,aAAa;;EAGnC,SAAS,SAAS;GAChB,OAAO,QAAQ,OAAO,SAAS,EAC7B,MAAM,QACP,CAAC;;EAEJ,WAAW,SAAS;GAClB,QAAQ,MAAM,QAAQ;;EAEzB,CAAC,EAEyC,EAAE,gBAAgB,MAAM,CAAC;CACpE,QAAQ,QACN,oCAAoC,MAAM,YAAY,8BAA8B,MAAM,wBAC3F;;AAGH,eAAe,kBAAkB,UAA8C;CAC7E,IAAI,aAAa,WAAW;EAC1B,MAAM,iBAAiB,EAAE,OAAO,MAAM,CAAC;EACvC,QAAQ,QAAQ,2BAA2B,MAAM,kBAAkB;EACnE;;CAGF,MAAM,gBAAgB;;AAGxB,eAAsB,aAAa,SAAwC;CACzE,IAAI,QAAQ,SAAS;EACnB,QAAQ,QAAQ;EAChB,QAAQ,KAAK,0BAA0B;;CAGzC,MAAM,YAAY,QAAQ;CAE1B,MAAM,aAAa;CACnB,MAAM,WAAW,MAAM,yBAAyB,QAAQ,SAAS;CAEjE,QAAQ,KAAK,mBAAmB,wBAAwB,YAAY;CACpE,MAAM,kBAAkB,SAAS;;AAkBnC,MAAa,OAAO,cAAc;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;CACN,aAAa,EACX,OAtBc,cAAc;EAC9B,MAAM;GACJ,MAAM;GACN,aAAa;GACd;EACD,MAAM;EACN,IAAI,EAAE,QAAQ;GACZ,OAAO,aAAa;IAClB,UAAU,KAAK;IACf,SAAS,KAAK;IACd,WAAW,KAAK;IACjB,CAAC;;EAEL,CASU,EACR;CACD,IAAI,EAAE,QAAQ;EACZ,KAAK,KAAK,EAAE,MAAM,IAAI,MAAM,EAC1B;EAGF,OAAO,aAAa;GAClB,UAAU,KAAK;GACf,SAAS,KAAK;GACd,WAAW,KAAK;GACjB,CAAC;;CAEL,CAAC"}
1
+ {"version":3,"file":"auth-hKS7kdCx.js","names":[],"sources":["../src/auth.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { loginCodex } from \"./lib/oauth/codex\"\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { persistCodexCredentials, setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n provider?: string\n verbose: boolean\n showToken: boolean\n}\n\nconst authArgs = {\n provider: {\n type: \"string\",\n description: \"Provider to log in with (copilot or codex)\",\n },\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 provider access token on auth\",\n },\n} as const\n\nconst BUILTIN_PROVIDER_NAMES = [\"copilot\", \"codex\"] as const\n\ntype BuiltinProviderName = (typeof BUILTIN_PROVIDER_NAMES)[number]\n\nconst BUILTIN_PROVIDER_LABELS: Record<BuiltinProviderName, string> = {\n copilot: \"GitHub Copilot\",\n codex: \"OpenAI Codex\",\n}\n\nfunction isBuiltinProviderName(\n providerName: string,\n): providerName is BuiltinProviderName {\n return BUILTIN_PROVIDER_NAMES.includes(providerName as BuiltinProviderName)\n}\n\nasync function resolveProviderSelection(\n providerArg: string | undefined,\n): Promise<BuiltinProviderName> {\n const availableProviders = [...BUILTIN_PROVIDER_NAMES]\n\n if (providerArg !== undefined) {\n const providerName = providerArg.trim()\n if (!isBuiltinProviderName(providerName)) {\n throw new Error(\n `Unknown provider '${providerArg}'. Expected one of: ${availableProviders.join(\", \")}`,\n )\n }\n return providerName\n }\n\n if (availableProviders.length === 1) {\n return availableProviders[0]\n }\n\n const provider = await consola.prompt(\"Select a provider to log in with\", {\n type: \"select\",\n options: availableProviders.map((providerName) => ({\n label: `${BUILTIN_PROVIDER_LABELS[providerName]} (${providerName})`,\n value: providerName,\n })),\n })\n\n if (!provider || !isBuiltinProviderName(provider)) {\n throw new Error(\"No provider selected\")\n }\n\n return provider\n}\n\nasync function loginWithCodex(): Promise<void> {\n const credentials = await loginCodex({\n onAuth(info) {\n consola.info(\"Open the following URL to authenticate with Codex:\")\n consola.log(info.url)\n if (info.instructions) {\n consola.info(info.instructions)\n }\n },\n onPrompt(message) {\n return consola.prompt(message, {\n type: \"text\",\n })\n },\n onProgress(message) {\n consola.debug(message)\n },\n })\n\n await persistCodexCredentials(credentials, { enableProvider: true })\n consola.success(\n `Codex provider config written to ${PATHS.CONFIG_PATH} and credentials written to ${PATHS.CODEX_CREDENTIAL_PATH}`,\n )\n}\n\nasync function loginWithProvider(provider: BuiltinProviderName): Promise<void> {\n if (provider === \"copilot\") {\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n return\n }\n\n await loginWithCodex()\n}\n\nexport async function runAuthLogin(options: RunAuthOptions): Promise<void> {\n const tlsModule = await import(\"./lib/tls\")\n tlsModule.enableSystemCACompat()\n\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 const provider = await resolveProviderSelection(options.provider)\n\n consola.info(`Logging in with ${BUILTIN_PROVIDER_LABELS[provider]}`)\n await loginWithProvider(provider)\n}\n\nconst authLogin = defineCommand({\n meta: {\n name: \"login\",\n description: \"Authenticate a builtin provider without running the server\",\n },\n args: authArgs,\n run({ args }) {\n return runAuthLogin({\n provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run authentication flows without running the server\",\n },\n args: authArgs,\n subCommands: {\n login: authLogin,\n },\n run({ args }) {\n if ((args._[0] ?? \"\").trim()) {\n return\n }\n\n return runAuthLogin({\n provider: args.provider,\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n"],"mappings":";;;;;AAgBA,MAAM,WAAW;CACf,UAAU;EACR,MAAM;EACN,aAAa;EACd;CACD,SAAS;EACP,OAAO;EACP,MAAM;EACN,SAAS;EACT,aAAa;EACd;CACD,cAAc;EACZ,MAAM;EACN,SAAS;EACT,aAAa;EACd;CACF;AAED,MAAM,yBAAyB,CAAC,WAAW,QAAQ;AAInD,MAAM,0BAA+D;CACnE,SAAS;CACT,OAAO;CACR;AAED,SAAS,sBACP,cACqC;CACrC,OAAO,uBAAuB,SAAS,aAAoC;;AAG7E,eAAe,yBACb,aAC8B;CAC9B,MAAM,qBAAqB,CAAC,GAAG,uBAAuB;CAEtD,IAAI,gBAAgB,KAAA,GAAW;EAC7B,MAAM,eAAe,YAAY,MAAM;EACvC,IAAI,CAAC,sBAAsB,aAAa,EACtC,MAAM,IAAI,MACR,qBAAqB,YAAY,sBAAsB,mBAAmB,KAAK,KAAK,GACrF;EAEH,OAAO;;CAGT,IAAI,mBAAmB,WAAW,GAChC,OAAO,mBAAmB;CAG5B,MAAM,WAAW,MAAM,QAAQ,OAAO,oCAAoC;EACxE,MAAM;EACN,SAAS,mBAAmB,KAAK,kBAAkB;GACjD,OAAO,GAAG,wBAAwB,cAAc,IAAI,aAAa;GACjE,OAAO;GACR,EAAE;EACJ,CAAC;CAEF,IAAI,CAAC,YAAY,CAAC,sBAAsB,SAAS,EAC/C,MAAM,IAAI,MAAM,uBAAuB;CAGzC,OAAO;;AAGT,eAAe,iBAAgC;CAmB7C,MAAM,wBAAwB,MAlBJ,WAAW;EACnC,OAAO,MAAM;GACX,QAAQ,KAAK,qDAAqD;GAClE,QAAQ,IAAI,KAAK,IAAI;GACrB,IAAI,KAAK,cACP,QAAQ,KAAK,KAAK,aAAa;;EAGnC,SAAS,SAAS;GAChB,OAAO,QAAQ,OAAO,SAAS,EAC7B,MAAM,QACP,CAAC;;EAEJ,WAAW,SAAS;GAClB,QAAQ,MAAM,QAAQ;;EAEzB,CAAC,EAEyC,EAAE,gBAAgB,MAAM,CAAC;CACpE,QAAQ,QACN,oCAAoC,MAAM,YAAY,8BAA8B,MAAM,wBAC3F;;AAGH,eAAe,kBAAkB,UAA8C;CAC7E,IAAI,aAAa,WAAW;EAC1B,MAAM,iBAAiB,EAAE,OAAO,MAAM,CAAC;EACvC,QAAQ,QAAQ,2BAA2B,MAAM,kBAAkB;EACnE;;CAGF,MAAM,gBAAgB;;AAGxB,eAAsB,aAAa,SAAwC;CAEzE,CAAA,MADwB,OAAO,sBACrB,sBAAsB;CAEhC,IAAI,QAAQ,SAAS;EACnB,QAAQ,QAAQ;EAChB,QAAQ,KAAK,0BAA0B;;CAGzC,MAAM,YAAY,QAAQ;CAE1B,MAAM,aAAa;CACnB,MAAM,WAAW,MAAM,yBAAyB,QAAQ,SAAS;CAEjE,QAAQ,KAAK,mBAAmB,wBAAwB,YAAY;CACpE,MAAM,kBAAkB,SAAS;;AAkBnC,MAAa,OAAO,cAAc;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;CACN,aAAa,EACX,OAtBc,cAAc;EAC9B,MAAM;GACJ,MAAM;GACN,aAAa;GACd;EACD,MAAM;EACN,IAAI,EAAE,QAAQ;GACZ,OAAO,aAAa;IAClB,UAAU,KAAK;IACf,SAAS,KAAK;IACd,WAAW,KAAK;IACjB,CAAC;;EAEL,CASU,EACR;CACD,IAAI,EAAE,QAAQ;EACZ,KAAK,KAAK,EAAE,MAAM,IAAI,MAAM,EAC1B;EAGF,OAAO,aAAa;GAClB,UAAU,KAAK;GACf,SAAS,KAAK;GACd,WAAW,KAAK;GACjB,CAAC;;CAEL,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { S as ensurePaths } from "./config-DA-Jdm0G.js";
2
- import { _ as getCopilotUsage, a as setupGitHubToken } from "./token-Nj-1C8tP.js";
2
+ import { _ as getCopilotUsage, a as setupGitHubToken } from "./token-BiWRaRze.js";
3
3
  import { defineCommand } from "citty";
4
4
  import consola from "consola";
5
5
  //#region src/check-usage.ts
@@ -9,6 +9,7 @@ const checkUsage = defineCommand({
9
9
  description: "Show current GitHub Copilot usage/quota information"
10
10
  },
11
11
  async run() {
12
+ (await import("./tls-CaLAeSaF.js")).enableSystemCACompat();
12
13
  await ensurePaths();
13
14
  await setupGitHubToken();
14
15
  try {
@@ -39,4 +40,4 @@ const checkUsage = defineCommand({
39
40
  //#endregion
40
41
  export { checkUsage };
41
42
 
42
- //# sourceMappingURL=check-usage-De_AMKLc.js.map
43
+ //# sourceMappingURL=check-usage-Cq76N0LH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-usage-Cq76N0LH.js","names":[],"sources":["../src/check-usage.ts"],"sourcesContent":["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 const tlsModule = await import(\"./lib/tls\")\n tlsModule.enableSystemCACompat()\n\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"],"mappings":";;;;;AAUA,MAAa,aAAa,cAAc;CACtC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,MAAM;EAEV,CAAA,MADwB,OAAO,sBACrB,sBAAsB;EAEhC,MAAM,aAAa;EACnB,MAAM,kBAAkB;EACxB,IAAI;GACF,MAAM,QAAQ,MAAM,iBAAiB;GACrC,MAAM,UAAU,MAAM,gBAAgB;GACtC,MAAM,eAAe,QAAQ;GAC7B,MAAM,cAAc,eAAe,QAAQ;GAC3C,MAAM,qBACJ,eAAe,IAAK,cAAc,eAAgB,MAAM;GAC1D,MAAM,0BAA0B,QAAQ;GAGxC,SAAS,eAAe,MAAc,MAA+B;IACnE,IAAI,CAAC,MAAM,OAAO,GAAG,KAAK;IAC1B,MAAM,QAAQ,KAAK;IACnB,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,cAAc,QAAQ,IAAK,OAAO,QAAS,MAAM;IACvD,MAAM,mBAAmB,KAAK;IAC9B,OAAO,GAAG,KAAK,IAAI,KAAK,GAAG,MAAM,SAAS,YAAY,QAAQ,EAAE,CAAC,UAAU,iBAAiB,QAAQ,EAAE,CAAC;;GAGzG,MAAM,cAAc,YAAY,YAAY,GAAG,aAAa,SAAS,mBAAmB,QAAQ,EAAE,CAAC,UAAU,wBAAwB,QAAQ,EAAE,CAAC;GAChJ,MAAM,WAAW,eAAe,QAAQ,MAAM,gBAAgB,KAAK;GACnE,MAAM,kBAAkB,eACtB,eACA,MAAM,gBAAgB,YACvB;GAED,QAAQ,IACN,wBAAwB,MAAM,aAAa,mBACtB,MAAM,iBAAiB,iBAEnC,YAAY,MACZ,SAAS,MACT,kBACV;WACM,KAAK;GACZ,QAAQ,MAAM,kCAAkC,IAAI;GACpD,QAAQ,KAAK,EAAE;;;CAGpB,CAAC"}
package/dist/main.js CHANGED
@@ -39,11 +39,11 @@ if (typeof args["api-home"] === "string") process.env.COPILOT_API_HOME = args["a
39
39
  if (typeof args["oauth-app"] === "string") process.env.COPILOT_API_OAUTH_APP = args["oauth-app"];
40
40
  if (typeof args["enterprise-url"] === "string") process.env.COPILOT_API_ENTERPRISE_URL = args["enterprise-url"];
41
41
  bindElectronFetch();
42
- const { auth } = await import("./auth-DIHsuzzC.js");
43
- const { checkUsage } = await import("./check-usage-De_AMKLc.js");
42
+ const { auth } = await import("./auth-hKS7kdCx.js");
43
+ const { checkUsage } = await import("./check-usage-Cq76N0LH.js");
44
44
  const { debug } = await import("./debug-BiX0ewij.js");
45
- const { mcp } = await import("./mcp-DZgcvqQY.js");
46
- const { start } = await import("./start-BAHLvLkh.js");
45
+ const { mcp } = await import("./mcp-CTb-DbQH.js");
46
+ const { start } = await import("./start-C4Lm5vjd.js");
47
47
  await runMain(defineCommand({
48
48
  meta: {
49
49
  name: "copilot-api",
@@ -1,4 +1,4 @@
1
- import { n as createMcpToolSearchSentinel } from "./tool-search-wA-fLduL.js";
1
+ import { n as createMcpToolSearchSentinel } from "./tool-search-D3SN0jX-.js";
2
2
  import { defineCommand } from "citty";
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -34,4 +34,4 @@ const mcp = defineCommand({
34
34
  //#endregion
35
35
  export { mcp };
36
36
 
37
- //# sourceMappingURL=mcp-DZgcvqQY.js.map
37
+ //# sourceMappingURL=mcp-CTb-DbQH.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-DZgcvqQY.js","names":[],"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"\nimport { defineCommand } from \"citty\"\nimport { z } from \"zod\"\n\nimport { createMcpToolSearchSentinel } from \"./lib/tool-search\"\n\nconst SERVER_NAME = \"tool_search\"\nconst SERVER_VERSION = \"1.0.0\"\n\nexport const runMcpServer = async (): Promise<void> => {\n const server = new McpServer({\n name: SERVER_NAME,\n version: SERVER_VERSION,\n })\n\n server.registerTool(\n \"search\",\n {\n title: \"Tool Search Bridge\",\n description:\n \"Load deferred tools by exact name through the Copilot API tool_search bridge.\",\n inputSchema: {\n names: z\n .string()\n .describe(\n 'Comma-separated exact deferred tool names to load, for example \"TaskList,TaskGet,mcp__fetch__fetch\".',\n ),\n },\n _meta: {\n \"anthropic/alwaysLoad\": true,\n },\n },\n ({ names }) => ({\n content: [\n {\n type: \"text\",\n text: createMcpToolSearchSentinel(names),\n },\n ],\n }),\n )\n\n await server.connect(new StdioServerTransport())\n}\n\nexport const mcp = defineCommand({\n meta: {\n name: \"mcp\",\n description: \"Start the Copilot API MCP tool_search bridge over stdio\",\n },\n run() {\n return runMcpServer()\n },\n})\n"],"mappings":";;;;;;AASA,MAAM,cAAc;AACpB,MAAM,iBAAiB;AAEvB,MAAa,eAAe,YAA2B;CACrD,MAAM,SAAS,IAAI,UAAU;EAC3B,MAAM;EACN,SAAS;EACV,CAAC;CAEF,OAAO,aACL,UACA;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,OAAO,EACJ,QAAQ,CACR,SACC,yGACD,EACJ;EACD,OAAO,EACL,wBAAwB,MACzB;EACF,GACA,EAAE,aAAa,EACd,SAAS,CACP;EACE,MAAM;EACN,MAAM,4BAA4B,MAAM;EACzC,CACF,EACF,EACF;CAED,MAAM,OAAO,QAAQ,IAAI,sBAAsB,CAAC;;AAGlD,MAAa,MAAM,cAAc;CAC/B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,OAAO,cAAc;;CAExB,CAAC"}
1
+ {"version":3,"file":"mcp-CTb-DbQH.js","names":[],"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"\nimport { defineCommand } from \"citty\"\nimport { z } from \"zod\"\n\nimport { createMcpToolSearchSentinel } from \"./lib/tool-search\"\n\nconst SERVER_NAME = \"tool_search\"\nconst SERVER_VERSION = \"1.0.0\"\n\nexport const runMcpServer = async (): Promise<void> => {\n const server = new McpServer({\n name: SERVER_NAME,\n version: SERVER_VERSION,\n })\n\n server.registerTool(\n \"search\",\n {\n title: \"Tool Search Bridge\",\n description:\n \"Load deferred tools by exact name through the Copilot API tool_search bridge.\",\n inputSchema: {\n names: z\n .string()\n .describe(\n 'Comma-separated exact deferred tool names to load, for example \"TaskList,TaskGet,mcp__fetch__fetch\".',\n ),\n },\n _meta: {\n \"anthropic/alwaysLoad\": true,\n },\n },\n ({ names }) => ({\n content: [\n {\n type: \"text\",\n text: createMcpToolSearchSentinel(names),\n },\n ],\n }),\n )\n\n await server.connect(new StdioServerTransport())\n}\n\nexport const mcp = defineCommand({\n meta: {\n name: \"mcp\",\n description: \"Start the Copilot API MCP tool_search bridge over stdio\",\n },\n run() {\n return runMcpServer()\n },\n})\n"],"mappings":";;;;;;AASA,MAAM,cAAc;AACpB,MAAM,iBAAiB;AAEvB,MAAa,eAAe,YAA2B;CACrD,MAAM,SAAS,IAAI,UAAU;EAC3B,MAAM;EACN,SAAS;EACV,CAAC;CAEF,OAAO,aACL,UACA;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,OAAO,EACJ,QAAQ,CACR,SACC,yGACD,EACJ;EACD,OAAO,EACL,wBAAwB,MACzB;EACF,GACA,EAAE,aAAa,EACd,SAAS,CACP;EACE,MAAM;EACN,MAAM,4BAA4B,MAAM;EACzC,CACF,EACF,EACF;CAED,MAAM,OAAO,QAAQ,IAAI,sBAAsB,CAAC;;AAGlD,MAAa,MAAM,cAAc;CAC/B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,OAAO,cAAc;;CAExB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { a as getMessageApiWebSearchModel, c as getProviderConfig, d as getSmallModel, f as isMessagesApiEnabled, h as isResponsesApiWebSocketEnabled, i as getExtraPromptForModel, l as getRawProviderConfig, m as isResponsesApiWebSearchEnabled, n as getClaudeTokenMultiplier, o as getModelMappings, p as isResponsesApiContextManagementEnabled, r as getConfig, s as getModelResponsesApiCompactThreshold$1, t as getAnthropicApiKey, u as getReasoningEffortForModel, v as resolveMappedModel, x as PATHS, y as setModelMappings } from "./config-DA-Jdm0G.js";
2
- import { B as forwardError, C as prepareMessageProxyHeaders, E as compactMessageSections, F as createPooledWebSocketStream, I as createWebSocketUrl, M as generateTraceId, N as requestContext, O as compactSystemPromptStarts, P as resolveTraceId$1, R as state, S as prepareInteractionHeaders, T as compactAutoContinuePromptStarts, _ as getCopilotUsage, b as copilotWebSocketHeaders, d as generateRequestIdFromPayload, f as getRootSessionId, g as sleep, h as parseUserIdMetadata, j as forwardCodexResponses, m as isNullish, p as getUUID, r as setupCodexToken, s as cacheModels, v as copilotBaseUrl, x as prepareForCompact, y as copilotHeaders, z as HTTPError } from "./token-Nj-1C8tP.js";
3
- import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, d as shouldEnableResponsesToolSearch, i as isBridgeToolSearchName, l as resolveBridgeToolSearchName, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as selectDeferredToolsByNames } from "./tool-search-wA-fLduL.js";
2
+ import { B as forwardError, C as prepareMessageProxyHeaders, E as compactMessageSections, F as createPooledWebSocketStream, I as createWebSocketUrl, M as generateTraceId, N as requestContext, O as compactSystemPromptStarts, P as resolveTraceId$1, R as state, S as prepareInteractionHeaders, T as compactAutoContinuePromptStarts, _ as getCopilotUsage, b as copilotWebSocketHeaders, d as generateRequestIdFromPayload, f as getRootSessionId, g as sleep, h as parseUserIdMetadata, j as forwardCodexResponses, m as isNullish, p as getUUID, r as setupCodexToken, s as cacheModels, v as copilotBaseUrl, x as prepareForCompact, y as copilotHeaders, z as HTTPError } from "./token-BiWRaRze.js";
3
+ import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, d as shouldEnableResponsesToolSearch, i as isBridgeToolSearchName, l as resolveBridgeToolSearchName, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as selectDeferredToolsByNames } from "./tool-search-D3SN0jX-.js";
4
4
  import consola from "consola";
5
5
  import { createHash } from "node:crypto";
6
6
  import { events } from "fetch-event-stream";
@@ -11,6 +11,7 @@ import { z } from "zod";
11
11
  import { Hono } from "hono";
12
12
  import { cors } from "hono/cors";
13
13
  import { logger } from "hono/logger";
14
+ import { decompress } from "fzstd";
14
15
  import { streamSSE } from "hono/streaming";
15
16
  import util from "node:util";
16
17
  //#region src/lib/request-auth.ts
@@ -84,6 +85,58 @@ const traceIdMiddleware = async (c, next) => {
84
85
  });
85
86
  };
86
87
  //#endregion
88
+ //#region src/lib/zstd-request.ts
89
+ const ZSTD_CONTENT_ENCODING = "zstd";
90
+ const INVALID_BODY_STATUS = 400;
91
+ let nodeZlibPromise = null;
92
+ const zstdDecompressionMiddleware = async (c, next) => {
93
+ if (c.req.header("content-encoding")?.trim().toLowerCase() !== ZSTD_CONTENT_ENCODING) return next();
94
+ try {
95
+ const decompressedBody = await decompressZstd(new Uint8Array(await c.req.raw.arrayBuffer()));
96
+ const headers = new Headers(c.req.raw.headers);
97
+ headers.delete("content-encoding");
98
+ headers.delete("content-length");
99
+ c.req.raw = new Request(c.req.raw.url, {
100
+ body: decompressedBody,
101
+ headers,
102
+ method: c.req.raw.method,
103
+ signal: c.req.raw.signal
104
+ });
105
+ c.req.bodyCache = {};
106
+ } catch {
107
+ return c.json({ error: {
108
+ message: "Failed to decompress zstd request body.",
109
+ type: "invalid_request_error"
110
+ } }, INVALID_BODY_STATUS);
111
+ }
112
+ return next();
113
+ };
114
+ const decompressZstd = async (input) => {
115
+ const bun = getBunRuntime();
116
+ if (bun?.zstdDecompress) return toUint8Array(await bun.zstdDecompress(input));
117
+ const nodeZlib = await getNodeZlib();
118
+ if (nodeZlib?.zstdDecompress) return new Promise((resolve, reject) => {
119
+ nodeZlib.zstdDecompress?.(input, (error, result) => {
120
+ if (error) {
121
+ reject(error);
122
+ return;
123
+ }
124
+ resolve(toUint8Array(result));
125
+ });
126
+ });
127
+ return decompress(input);
128
+ };
129
+ const getBunRuntime = () => globalThis.Bun;
130
+ const getNodeZlib = async () => {
131
+ nodeZlibPromise ??= import("node:zlib").then((module) => module).catch(() => null);
132
+ return nodeZlibPromise;
133
+ };
134
+ const toUint8Array = (data) => {
135
+ if (data instanceof Uint8Array) return data;
136
+ if (data instanceof ArrayBuffer) return new Uint8Array(data);
137
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
138
+ };
139
+ //#endregion
87
140
  //#region src/lib/approval.ts
88
141
  const awaitApproval = async () => {
89
142
  if (!await consola.prompt(`Accept incoming request?`, { type: "confirm" })) throw new HTTPError("Request rejected", Response.json({ message: "Request rejected" }, { status: 403 }));
@@ -6167,6 +6220,7 @@ server.use("/admin/*", createAuthMiddleware({
6167
6220
  allowUnauthenticatedPaths: [],
6168
6221
  allowWhenNoApiKeys: false
6169
6222
  }));
6223
+ server.use(zstdDecompressionMiddleware);
6170
6224
  server.get("/", (c) => c.text("Server running"));
6171
6225
  server.get("/usage-viewer", (c) => {
6172
6226
  const usageViewerFileUrl = new URL("../pages/index.html", import.meta.url);
@@ -6191,4 +6245,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
6191
6245
  //#endregion
6192
6246
  export { server };
6193
6247
 
6194
- //# sourceMappingURL=server-f_gmacXT.js.map
6248
+ //# sourceMappingURL=server-KVt1BdTD.js.map