ghc-proxy 0.5.4 → 0.5.7

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/main.mjs CHANGED
@@ -5389,7 +5389,8 @@ const configFileSchema = object({
5389
5389
  to: string()
5390
5390
  })).optional(),
5391
5391
  contextUpgrade: boolean().optional(),
5392
- contextUpgradeTokenThreshold: number().int().positive().optional()
5392
+ contextUpgradeTokenThreshold: number().int().positive().optional(),
5393
+ gheDomain: string().optional()
5393
5394
  }).passthrough();
5394
5395
  const KNOWN_CONFIG_KEYS = new Set(Object.keys(configFileSchema.shape));
5395
5396
  let cachedConfig = {};
@@ -5499,6 +5500,105 @@ async function applyConfigFilePermissions(filePath) {
5499
5500
  }
5500
5501
  }
5501
5502
 
5503
+ //#endregion
5504
+ //#region src/lib/api-config.ts
5505
+ function standardHeaders() {
5506
+ return {
5507
+ "content-type": "application/json",
5508
+ "accept": "application/json"
5509
+ };
5510
+ }
5511
+ const COPILOT_VERSION = "0.26.7";
5512
+ const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
5513
+ const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
5514
+ const API_VERSION = "2025-04-01";
5515
+ const TRAILING_SLASHES_RE$1 = /\/+$/;
5516
+ /** Headers shared by both Copilot and GitHub API requests (editor identity + versioning) */
5517
+ function editorHeaders(config) {
5518
+ return {
5519
+ "editor-version": `vscode/${config.vsCodeVersion ?? "unknown"}`,
5520
+ "editor-plugin-version": EDITOR_PLUGIN_VERSION,
5521
+ "user-agent": USER_AGENT,
5522
+ "x-github-api-version": API_VERSION,
5523
+ "x-vscode-user-agent-library-version": "electron-fetch"
5524
+ };
5525
+ }
5526
+ function copilotBaseUrl(config) {
5527
+ if (config.copilotApiBase) return config.copilotApiBase.replace(TRAILING_SLASHES_RE$1, "");
5528
+ return config.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${config.accountType}.githubcopilot.com`;
5529
+ }
5530
+ function copilotHeaders(auth, config, options = {}) {
5531
+ const requestContext = options.requestContext;
5532
+ const headers = {
5533
+ "Authorization": `Bearer ${auth.copilotToken}`,
5534
+ "content-type": standardHeaders()["content-type"],
5535
+ "copilot-integration-id": "vscode-chat",
5536
+ ...editorHeaders(config),
5537
+ "openai-intent": "conversation-panel",
5538
+ "x-request-id": randomUUID()
5539
+ };
5540
+ if (options.vision) headers["copilot-vision-request"] = "true";
5541
+ if (options.initiator) headers["X-Initiator"] = options.initiator;
5542
+ if (requestContext?.interactionType) headers["X-Interaction-Type"] = requestContext.interactionType;
5543
+ if (requestContext?.agentTaskId) headers["X-Agent-Task-Id"] = requestContext.agentTaskId;
5544
+ if (requestContext?.parentAgentTaskId) headers["X-Parent-Agent-Id"] = requestContext.parentAgentTaskId;
5545
+ if (requestContext?.clientSessionId) headers["X-Client-Session-Id"] = requestContext.clientSessionId;
5546
+ if (requestContext?.interactionId) headers["X-Interaction-Id"] = requestContext.interactionId;
5547
+ if (requestContext?.clientMachineId) headers["X-Client-Machine-Id"] = requestContext.clientMachineId;
5548
+ return headers;
5549
+ }
5550
+ const GITHUB_API_BASE_URL = "https://api.github.com";
5551
+ function githubHeaders(auth, config) {
5552
+ return {
5553
+ ...standardHeaders(),
5554
+ authorization: `token ${auth.githubToken}`,
5555
+ ...editorHeaders(config)
5556
+ };
5557
+ }
5558
+ const GITHUB_BASE_URL = "https://github.com";
5559
+ const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
5560
+ const GITHUB_APP_SCOPES = ["read:user"].join(" ");
5561
+
5562
+ //#endregion
5563
+ //#region src/lib/ghe-domain.ts
5564
+ const GHE_SUFFIX = ".ghe.com";
5565
+ /**
5566
+ * Normalize a GHE domain input to a lowercase bare domain.
5567
+ *
5568
+ * Accepted inputs: `company.ghe.com`, `https://company.ghe.com`,
5569
+ * `https://Company.GHE.com/`, etc.
5570
+ *
5571
+ * @returns Bare lowercase domain, e.g. `company.ghe.com`
5572
+ * @throws {Error} If the input is empty or does not end with `.ghe.com`
5573
+ */
5574
+ function normalizeGheDomain(input) {
5575
+ const trimmed = input.trim();
5576
+ if (!trimmed) throw new Error("GHE domain must not be empty");
5577
+ let domain;
5578
+ try {
5579
+ domain = (trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`)).hostname.toLowerCase();
5580
+ } catch {
5581
+ throw new Error(`Invalid GHE domain: ${trimmed}`);
5582
+ }
5583
+ if (!domain.endsWith(GHE_SUFFIX) || domain === GHE_SUFFIX.slice(1)) throw new Error(`GHE domain must end with ${GHE_SUFFIX} (got "${domain}")`);
5584
+ return domain;
5585
+ }
5586
+ /**
5587
+ * Build GitHub base URL and API base URL for a given GHE domain,
5588
+ * or return the public GitHub defaults when no domain is provided.
5589
+ */
5590
+ function buildGitHubUrls(gheDomain) {
5591
+ if (!gheDomain) return {
5592
+ baseUrl: GITHUB_BASE_URL,
5593
+ apiBaseUrl: GITHUB_API_BASE_URL
5594
+ };
5595
+ const domain = normalizeGheDomain(gheDomain);
5596
+ return {
5597
+ baseUrl: `https://${domain}`,
5598
+ apiBaseUrl: `https://api.${domain}`
5599
+ };
5600
+ }
5601
+
5502
5602
  //#endregion
5503
5603
  //#region node_modules/fetch-event-stream/esm/deps/jsr.io/@std/streams/0.221.0/text_line_stream.js
5504
5604
  /**
@@ -5624,65 +5724,6 @@ async function* events(res, signal) {
5624
5724
  }
5625
5725
  }
5626
5726
 
5627
- //#endregion
5628
- //#region src/lib/api-config.ts
5629
- function standardHeaders() {
5630
- return {
5631
- "content-type": "application/json",
5632
- "accept": "application/json"
5633
- };
5634
- }
5635
- const COPILOT_VERSION = "0.26.7";
5636
- const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
5637
- const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
5638
- const API_VERSION = "2025-04-01";
5639
- const TRAILING_SLASHES_RE$1 = /\/+$/;
5640
- /** Headers shared by both Copilot and GitHub API requests (editor identity + versioning) */
5641
- function editorHeaders(config) {
5642
- return {
5643
- "editor-version": `vscode/${config.vsCodeVersion ?? "unknown"}`,
5644
- "editor-plugin-version": EDITOR_PLUGIN_VERSION,
5645
- "user-agent": USER_AGENT,
5646
- "x-github-api-version": API_VERSION,
5647
- "x-vscode-user-agent-library-version": "electron-fetch"
5648
- };
5649
- }
5650
- function copilotBaseUrl(config) {
5651
- if (config.copilotApiBase) return config.copilotApiBase.replace(TRAILING_SLASHES_RE$1, "");
5652
- return config.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${config.accountType}.githubcopilot.com`;
5653
- }
5654
- function copilotHeaders(auth, config, options = {}) {
5655
- const requestContext = options.requestContext;
5656
- const headers = {
5657
- "Authorization": `Bearer ${auth.copilotToken}`,
5658
- "content-type": standardHeaders()["content-type"],
5659
- "copilot-integration-id": "vscode-chat",
5660
- ...editorHeaders(config),
5661
- "openai-intent": "conversation-panel",
5662
- "x-request-id": randomUUID()
5663
- };
5664
- if (options.vision) headers["copilot-vision-request"] = "true";
5665
- if (options.initiator) headers["X-Initiator"] = options.initiator;
5666
- if (requestContext?.interactionType) headers["X-Interaction-Type"] = requestContext.interactionType;
5667
- if (requestContext?.agentTaskId) headers["X-Agent-Task-Id"] = requestContext.agentTaskId;
5668
- if (requestContext?.parentAgentTaskId) headers["X-Parent-Agent-Id"] = requestContext.parentAgentTaskId;
5669
- if (requestContext?.clientSessionId) headers["X-Client-Session-Id"] = requestContext.clientSessionId;
5670
- if (requestContext?.interactionId) headers["X-Interaction-Id"] = requestContext.interactionId;
5671
- if (requestContext?.clientMachineId) headers["X-Client-Machine-Id"] = requestContext.clientMachineId;
5672
- return headers;
5673
- }
5674
- const GITHUB_API_BASE_URL = "https://api.github.com";
5675
- function githubHeaders(auth, config) {
5676
- return {
5677
- ...standardHeaders(),
5678
- authorization: `token ${auth.githubToken}`,
5679
- ...editorHeaders(config)
5680
- };
5681
- }
5682
- const GITHUB_BASE_URL = "https://github.com";
5683
- const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
5684
- const GITHUB_APP_SCOPES = ["read:user"].join(" ");
5685
-
5686
5727
  //#endregion
5687
5728
  //#region src/lib/error.ts
5688
5729
  /**
@@ -5915,13 +5956,13 @@ var GitHubClient = class {
5915
5956
  return await response.json();
5916
5957
  }
5917
5958
  async getCopilotUsage() {
5918
- return this.requestJson(`${GITHUB_API_BASE_URL}/copilot_internal/user`, { headers: githubHeaders(this.auth, this.config) }, "Failed to get Copilot usage");
5959
+ return this.requestJson(`${this.config.githubApiBaseUrl ?? GITHUB_API_BASE_URL}/copilot_internal/user`, { headers: githubHeaders(this.auth, this.config) }, "Failed to get Copilot usage");
5919
5960
  }
5920
5961
  async getCopilotToken() {
5921
- return this.requestJson(`${GITHUB_API_BASE_URL}/copilot_internal/v2/token`, { headers: githubHeaders(this.auth, this.config) }, "Failed to get Copilot token");
5962
+ return this.requestJson(`${this.config.githubApiBaseUrl ?? GITHUB_API_BASE_URL}/copilot_internal/v2/token`, { headers: githubHeaders(this.auth, this.config) }, "Failed to get Copilot token");
5922
5963
  }
5923
5964
  async getDeviceCode() {
5924
- return this.requestJson(`${GITHUB_BASE_URL}/login/device/code`, {
5965
+ return this.requestJson(`${this.config.githubBaseUrl ?? GITHUB_BASE_URL}/login/device/code`, {
5925
5966
  method: "POST",
5926
5967
  headers: standardHeaders(),
5927
5968
  body: JSON.stringify({
@@ -5935,7 +5976,7 @@ var GitHubClient = class {
5935
5976
  const sleepDuration = (deviceCode.interval + 1) * 1e3;
5936
5977
  consola.debug(`Polling access token with interval of ${sleepDuration}ms`);
5937
5978
  for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {
5938
- const response = await this.fetchImpl(`${GITHUB_BASE_URL}/login/oauth/access_token`, {
5979
+ const response = await this.fetchImpl(`${this.config.githubBaseUrl ?? GITHUB_BASE_URL}/login/oauth/access_token`, {
5939
5980
  method: "POST",
5940
5981
  headers: standardHeaders(),
5941
5982
  body: JSON.stringify({
@@ -5957,7 +5998,7 @@ var GitHubClient = class {
5957
5998
  throw new Error("Device code authorization timed out");
5958
5999
  }
5959
6000
  async getGitHubUser() {
5960
- return this.requestJson(`${GITHUB_API_BASE_URL}/user`, { headers: {
6001
+ return this.requestJson(`${this.config.githubApiBaseUrl ?? GITHUB_API_BASE_URL}/user`, { headers: {
5961
6002
  authorization: `token ${this.auth.githubToken}`,
5962
6003
  ...standardHeaders()
5963
6004
  } }, "Failed to get GitHub user");
@@ -6277,10 +6318,13 @@ const state = {
6277
6318
  responsesEmulator: responsesEmulatorState
6278
6319
  };
6279
6320
  function getClientConfig() {
6321
+ const { baseUrl, apiBaseUrl } = buildGitHubUrls(state.auth.gheDomain);
6280
6322
  return {
6281
6323
  accountType: state.config.accountType,
6282
6324
  vsCodeVersion: state.cache.vsCodeVersion,
6283
- copilotApiBase: state.auth.copilotApiBase
6325
+ copilotApiBase: state.auth.copilotApiBase,
6326
+ githubBaseUrl: baseUrl,
6327
+ githubApiBaseUrl: apiBaseUrl
6284
6328
  };
6285
6329
  }
6286
6330
  function createCopilotClient() {
@@ -6296,6 +6340,33 @@ async function cacheVSCodeVersion() {
6296
6340
  consola.debug(`Using VSCode version: ${response}`);
6297
6341
  }
6298
6342
 
6343
+ //#endregion
6344
+ //#region src/lib/retry.ts
6345
+ /**
6346
+ * Retry an async operation with exponential backoff.
6347
+ * Delay schedule: baseDelayMs * 2^attempt (0-indexed), e.g. 5s, 10s, 20s, 40s.
6348
+ */
6349
+ async function retryWithBackoff(fn, options) {
6350
+ const maxRetries = options?.maxRetries ?? 4;
6351
+ const baseDelayMs = options?.baseDelayMs ?? 5e3;
6352
+ const shouldRetry = options?.shouldRetry ?? (() => true);
6353
+ const onRetry = options?.onRetry;
6354
+ let lastError;
6355
+ for (let attempt = 0; attempt <= maxRetries; attempt++) try {
6356
+ return await fn();
6357
+ } catch (error) {
6358
+ lastError = error;
6359
+ if (!shouldRetry(error) || attempt >= maxRetries) throw error;
6360
+ const delay = baseDelayMs * 2 ** attempt;
6361
+ onRetry?.(error, attempt, delay);
6362
+ await sleep(delay);
6363
+ }
6364
+ throw lastError;
6365
+ }
6366
+ function formatErrorMessage(error) {
6367
+ return error instanceof Error ? error.message : String(error);
6368
+ }
6369
+
6299
6370
  //#endregion
6300
6371
  //#region src/lib/token.ts
6301
6372
  const TRAILING_SLASHES_RE = /\/+$/;
@@ -6310,25 +6381,38 @@ async function setupCopilotToken() {
6310
6381
  consola.debug("GitHub Copilot Token fetched successfully!");
6311
6382
  if (state.config.showToken) consola.info("Copilot token:", response.token);
6312
6383
  const refreshInterval = (response.refresh_in - 60) * 1e3;
6313
- const refreshCopilotToken = async () => {
6314
- consola.debug("Refreshing Copilot token");
6315
- try {
6316
- const refreshed = await githubClient.getCopilotToken();
6317
- applyCopilotTokenState(refreshed);
6318
- consola.debug("Copilot token refreshed");
6319
- if (state.config.showToken) consola.info("Refreshed Copilot token:", refreshed.token);
6320
- } catch (error) {
6321
- consola.error("Failed to refresh Copilot token:", error);
6322
- }
6384
+ const scheduleRefresh = () => {
6385
+ setTimeout(() => {
6386
+ refreshCopilotToken(githubClient).then(scheduleRefresh);
6387
+ }, refreshInterval);
6323
6388
  };
6324
- setInterval(() => {
6325
- refreshCopilotToken();
6326
- }, refreshInterval);
6389
+ scheduleRefresh();
6390
+ }
6391
+ async function refreshCopilotToken(githubClient) {
6392
+ consola.debug("Refreshing Copilot token");
6393
+ try {
6394
+ const refreshed = await retryWithBackoff(() => githubClient.getCopilotToken(), {
6395
+ shouldRetry: (error) => !(error instanceof HTTPError) || isTransientHttpError(error),
6396
+ onRetry: (error, attempt, delayMs) => {
6397
+ consola.warn(`Token refresh failed (attempt ${attempt + 1}), retrying in ${delayMs / 1e3}s:`, formatErrorMessage(error));
6398
+ }
6399
+ });
6400
+ applyCopilotTokenState(refreshed);
6401
+ consola.debug("Copilot token refreshed");
6402
+ if (state.config.showToken) consola.info("Refreshed Copilot token:", refreshed.token);
6403
+ } catch (error) {
6404
+ consola.error("Failed to refresh Copilot token:", error);
6405
+ }
6327
6406
  }
6328
6407
  async function setupGitHubToken(options) {
6329
6408
  try {
6330
6409
  await ensureVSCodeVersion();
6331
6410
  const githubToken = getCachedConfig().githubToken?.trim() || "";
6411
+ if (githubToken && !options?.force && isDomainChanged()) {
6412
+ consola.warn("GHE domain changed — cached token is for a different GitHub instance. Re-authenticating...");
6413
+ await setupGitHubToken({ force: true });
6414
+ return;
6415
+ }
6332
6416
  if (githubToken && !options?.force) {
6333
6417
  state.auth.githubToken = githubToken;
6334
6418
  if (state.config.showToken) consola.info("GitHub token:", githubToken);
@@ -6352,6 +6436,7 @@ async function setupGitHubToken(options) {
6352
6436
  const token = await githubClient.pollAccessToken(response);
6353
6437
  await writeGithubToken(token);
6354
6438
  state.auth.githubToken = token;
6439
+ await writeConfigField("gheDomain", state.auth.gheDomain);
6355
6440
  if (state.config.showToken) consola.info("GitHub token:", token);
6356
6441
  await logUser();
6357
6442
  } catch (error) {
@@ -6366,6 +6451,17 @@ async function setupGitHubToken(options) {
6366
6451
  function isAuthError(error) {
6367
6452
  return error instanceof HTTPError && (error.status === 401 || error.status === 403);
6368
6453
  }
6454
+ const TRANSIENT_HTTP_STATUSES = new Set([
6455
+ 408,
6456
+ 429,
6457
+ 500,
6458
+ 502,
6459
+ 503,
6460
+ 504
6461
+ ]);
6462
+ function isTransientHttpError(error) {
6463
+ return TRANSIENT_HTTP_STATUSES.has(error.status);
6464
+ }
6369
6465
  async function logUser() {
6370
6466
  const user = await createGitHubClient().getGitHubUser();
6371
6467
  state.cache.githubLogin = user.login;
@@ -6382,6 +6478,13 @@ function normalizeCopilotApiBase(value) {
6382
6478
  if (!value) return;
6383
6479
  return value.replace(TRAILING_SLASHES_RE, "");
6384
6480
  }
6481
+ /**
6482
+ * Detects whether the runtime GHE domain differs from the previously persisted one.
6483
+ * Both `undefined` means "public github.com" → no change → returns false.
6484
+ */
6485
+ function isDomainChanged() {
6486
+ return state.auth.gheDomain !== getCachedConfig().gheDomain;
6487
+ }
6385
6488
  async function ensureVSCodeVersion() {
6386
6489
  if (!state.cache.vsCodeVersion) await cacheVSCodeVersion();
6387
6490
  }
@@ -6396,6 +6499,9 @@ async function runAuth(options) {
6396
6499
  state.config.showToken = options.showToken;
6397
6500
  await ensurePaths();
6398
6501
  await readConfig();
6502
+ state.auth.gheDomain = getCachedConfig().gheDomain;
6503
+ if (options.gheDomain !== void 0) state.auth.gheDomain = options.gheDomain ? normalizeGheDomain(options.gheDomain) : void 0;
6504
+ if (state.auth.gheDomain && state.config.accountType === "individual") state.config.accountType = "enterprise";
6399
6505
  await cacheVSCodeVersion();
6400
6506
  await setupGitHubToken({ force: true });
6401
6507
  consola.success("GitHub token written to config.json");
@@ -6416,12 +6522,18 @@ const auth = defineCommand({
6416
6522
  type: "boolean",
6417
6523
  default: false,
6418
6524
  description: "Show GitHub token on auth"
6525
+ },
6526
+ "ghe-domain": {
6527
+ alias: "ghe",
6528
+ type: "string",
6529
+ description: "Company GHE domain for GitHub Enterprise Cloud (e.g. company.ghe.com)"
6419
6530
  }
6420
6531
  },
6421
6532
  run({ args }) {
6422
6533
  return runAuth({
6423
6534
  verbose: args.verbose,
6424
- showToken: args["show-token"]
6535
+ showToken: args["show-token"],
6536
+ gheDomain: args["ghe-domain"]
6425
6537
  });
6426
6538
  }
6427
6539
  });
@@ -6436,6 +6548,7 @@ const checkUsage = defineCommand({
6436
6548
  async run() {
6437
6549
  await ensurePaths();
6438
6550
  await readConfig();
6551
+ state.auth.gheDomain = getCachedConfig().gheDomain;
6439
6552
  await cacheVSCodeVersion();
6440
6553
  await setupGitHubToken();
6441
6554
  try {
@@ -6466,7 +6579,7 @@ const checkUsage = defineCommand({
6466
6579
 
6467
6580
  //#endregion
6468
6581
  //#region src/lib/version.ts
6469
- const VERSION = "0.5.4";
6582
+ const VERSION = "0.5.7";
6470
6583
 
6471
6584
  //#endregion
6472
6585
  //#region src/debug.ts
@@ -6495,6 +6608,7 @@ async function checkConfigExists() {
6495
6608
  }
6496
6609
  }
6497
6610
  async function getDebugInfo() {
6611
+ await readConfig();
6498
6612
  const configExists = await checkConfigExists();
6499
6613
  return {
6500
6614
  version: VERSION,
@@ -6504,7 +6618,8 @@ async function getDebugInfo() {
6504
6618
  CONFIG_PATH: PATHS.CONFIG_PATH
6505
6619
  },
6506
6620
  configExists,
6507
- tokenExists: hasToken()
6621
+ tokenExists: hasToken(),
6622
+ gheDomain: getCachedConfig().gheDomain
6508
6623
  };
6509
6624
  }
6510
6625
  function printDebugInfoPlain(info) {
@@ -6518,7 +6633,8 @@ Paths:
6518
6633
  - CONFIG_PATH: ${info.paths.CONFIG_PATH}
6519
6634
 
6520
6635
  Config exists: ${info.configExists ? "Yes" : "No"}
6521
- Token exists: ${info.tokenExists ? "Yes" : "No"}`);
6636
+ Token exists: ${info.tokenExists ? "Yes" : "No"}
6637
+ GHE Domain: ${info.gheDomain ?? "none"}`);
6522
6638
  }
6523
6639
  async function runDebug(options) {
6524
6640
  const debugInfo = await getDebugInfo();
@@ -46809,20 +46925,29 @@ const methodColors = {
46809
46925
  function colorizeMethod(method) {
46810
46926
  return colorize(methodColors[method] ?? "white", method);
46811
46927
  }
46928
+ function getEffectiveModel(info) {
46929
+ return info.steps.length > 0 ? info.steps.at(-1).result : info.originalModel ?? "-";
46930
+ }
46931
+ function appendModelStep(info, tag, newModel) {
46932
+ if (newModel === getEffectiveModel(info)) return info;
46933
+ return {
46934
+ originalModel: info.originalModel,
46935
+ steps: [...info.steps, {
46936
+ tag,
46937
+ result: newModel
46938
+ }]
46939
+ };
46940
+ }
46812
46941
  function formatModelMapping(info) {
46813
46942
  if (!info) return "";
46814
- const { originalModel, rewrittenModel, mappedModel } = info;
46815
- if (!originalModel && !rewrittenModel && !mappedModel) return "";
46816
- const parts = [];
46817
- const displayOriginal = originalModel ?? "-";
46818
- parts.push(colorize("blueBright", displayOriginal));
46819
- if (rewrittenModel && rewrittenModel !== displayOriginal) {
46820
- parts.push(colorize("dim", "~>"));
46821
- parts.push(colorize("cyanBright", rewrittenModel));
46822
- }
46823
- if (mappedModel && mappedModel !== (rewrittenModel ?? displayOriginal)) {
46824
- parts.push(colorize("dim", "→"));
46825
- parts.push(colorize("greenBright", mappedModel));
46943
+ const { originalModel, steps } = info;
46944
+ if (!originalModel && steps.length === 0) return "";
46945
+ const parts = [colorize("blueBright", originalModel ?? "-")];
46946
+ for (let i = 0; i < steps.length; i++) {
46947
+ const step = steps[i];
46948
+ const isLast = i === steps.length - 1;
46949
+ parts.push(colorize("dim", `-[${step.tag}]->`));
46950
+ parts.push(colorize(isLast ? "greenBright" : "cyanBright", step.result));
46826
46951
  }
46827
46952
  return ` ${colorize("dim", "model=")}${parts.join(" ")}`;
46828
46953
  }
@@ -48499,13 +48624,15 @@ function rewriteModel(modelId) {
48499
48624
  if (userRules) {
48500
48625
  for (const rule of userRules) if (matchesGlob(rule.from, modelId)) return {
48501
48626
  originalModel: modelId,
48502
- model: normalizeToKnownModel(rule.to) ?? rule.to
48627
+ model: normalizeToKnownModel(rule.to) ?? rule.to,
48628
+ reason: "CONFIG_REWRITE"
48503
48629
  };
48504
48630
  }
48505
48631
  const normalized = normalizeToKnownModel(modelId);
48506
48632
  if (normalized && normalized !== modelId) return {
48507
48633
  originalModel: modelId,
48508
- model: normalized
48634
+ model: normalized,
48635
+ reason: "AUTO_CORRECT"
48509
48636
  };
48510
48637
  return {
48511
48638
  originalModel: modelId,
@@ -49209,8 +49336,13 @@ const responsesReasoningSummarySchema = object({
49209
49336
  const responsesReasoningInputSchema = object({
49210
49337
  id: string().optional(),
49211
49338
  type: literal("reasoning"),
49212
- summary: array(responsesReasoningSummarySchema),
49213
- encrypted_content: string().min(1)
49339
+ summary: array(responsesReasoningSummarySchema).optional(),
49340
+ encrypted_content: string().nullable().optional(),
49341
+ status: _enum([
49342
+ "in_progress",
49343
+ "completed",
49344
+ "incomplete"
49345
+ ]).optional()
49214
49346
  }).loose();
49215
49347
  const responsesCompactionInputSchema = object({
49216
49348
  id: string().min(1),
@@ -49443,7 +49575,11 @@ async function handleCompletionCore({ body, signal, headers }) {
49443
49575
  const requestContext = normalizeChatRequestContext(payload, headers);
49444
49576
  consola.debug("Request payload:", JSON.stringify(payload).slice(-400));
49445
49577
  const rewrite = applyModelRewrite(payload);
49446
- const originalModel = rewrite.originalModel;
49578
+ const steps = [];
49579
+ if (rewrite.reason) steps.push({
49580
+ tag: rewrite.reason,
49581
+ result: rewrite.model
49582
+ });
49447
49583
  const selectedModel = findModelById(payload.model);
49448
49584
  try {
49449
49585
  if (selectedModel) {
@@ -49462,11 +49598,10 @@ async function handleCompletionCore({ body, signal, headers }) {
49462
49598
  }
49463
49599
  const upstreamSignal = createUpstreamSignalFromConfig(signal);
49464
49600
  const plan = adapter.toCapiPlan(payload, { requestContext });
49465
- const modelMapping = {
49466
- originalModel,
49467
- rewrittenModel: rewrite.model,
49468
- mappedModel: plan.resolvedModel
49469
- };
49601
+ const modelMapping = appendModelStep({
49602
+ originalModel: rewrite.originalModel,
49603
+ steps
49604
+ }, "MODEL_RESOLVE", plan.resolvedModel);
49470
49605
  const transport = new CopilotTransport(createCopilotClient());
49471
49606
  consola.debug("Streaming response");
49472
49607
  return {
@@ -50843,10 +50978,6 @@ const responsesApiEntry = {
50843
50978
  if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
50844
50979
  throw error;
50845
50980
  }
50846
- const modelMapping = {
50847
- originalModel: ctx.modelMapping.originalModel,
50848
- mappedModel: responsesPayload.model
50849
- };
50850
50981
  applyContextManagement(responsesPayload, ctx.selectedModel?.capabilities.limits.max_prompt_tokens);
50851
50982
  compactInputByLatestCompaction(responsesPayload);
50852
50983
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
@@ -50857,7 +50988,7 @@ const responsesApiEntry = {
50857
50988
  signal: ctx.upstreamSignal.signal,
50858
50989
  requestContext: ctx.requestContext
50859
50990
  }), ctx.upstreamSignal),
50860
- modelMapping
50991
+ modelMapping: ctx.modelMapping
50861
50992
  };
50862
50993
  }
50863
50994
  };
@@ -50873,10 +51004,7 @@ const chatCompletionsEntry = {
50873
51004
  if (error instanceof TranslationFailure) throw fromTranslationFailure(error);
50874
51005
  throw error;
50875
51006
  }
50876
- const modelMapping = {
50877
- originalModel: ctx.modelMapping.originalModel,
50878
- mappedModel: plan.resolvedModel
50879
- };
51007
+ const modelMapping = appendModelStep(ctx.modelMapping, "MODEL_RESOLVE", plan.resolvedModel);
50880
51008
  consola.debug("Claude Code requested model:", ctx.anthropicPayload.model, "-> Copilot model:", plan.resolvedModel);
50881
51009
  if (consola.level >= 4) consola.debug("Planned Copilot request payload:", JSON.stringify(plan.payload));
50882
51010
  return {
@@ -50926,17 +51054,33 @@ async function handleMessagesCore({ body, signal, headers }) {
50926
51054
  const requestContext = normalizeAnthropicRequestContext(anthropicPayload, headers);
50927
51055
  if (consola.level >= 4) consola.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
50928
51056
  const rewrite = applyModelRewrite(anthropicPayload);
51057
+ const steps = [];
51058
+ if (rewrite.reason) steps.push({
51059
+ tag: rewrite.reason,
51060
+ result: rewrite.model
51061
+ });
50929
51062
  const betaResult = processAnthropicBetaHeader(headers.get("anthropic-beta"), anthropicPayload.model);
50930
51063
  if (betaResult.upgradeTarget) {
50931
51064
  consola.debug(`Beta header context upgrade: ${anthropicPayload.model} → ${betaResult.upgradeTarget}`);
50932
51065
  anthropicPayload.model = betaResult.upgradeTarget;
51066
+ steps.push({
51067
+ tag: "BETA_UPGRADE",
51068
+ result: betaResult.upgradeTarget
51069
+ });
50933
51070
  }
50934
51071
  const anthropicBetaHeader = betaResult.header;
50935
51072
  const modelRouting = applyMessagesModelPolicy(anthropicPayload, { betaUpgraded: !!betaResult.upgradeTarget });
51073
+ if (modelRouting.reason === "context-upgrade") steps.push({
51074
+ tag: "CONTEXT_UPGRADE",
51075
+ result: modelRouting.routedModel
51076
+ });
51077
+ else if (modelRouting.reason === "compact") steps.push({
51078
+ tag: "COMPACT",
51079
+ result: modelRouting.routedModel
51080
+ });
50936
51081
  const modelMapping = {
50937
51082
  originalModel: rewrite.originalModel,
50938
- rewrittenModel: rewrite.model,
50939
- mappedModel: modelRouting.routedModel
51083
+ steps
50940
51084
  };
50941
51085
  if (modelRouting.reason) consola.debug(`Routed anthropic request via ${modelRouting.reason}:`, `${modelRouting.originalModel} -> ${modelRouting.routedModel}`);
50942
51086
  const selectedModel = findModelById(anthropicPayload.model);
@@ -50970,8 +51114,10 @@ async function handleMessagesCore({ body, signal, headers }) {
50970
51114
  upstreamSignal: retrySignal,
50971
51115
  modelMapping: {
50972
51116
  originalModel: rewrite.originalModel,
50973
- rewrittenModel: rewrite.model,
50974
- mappedModel: upgradeTarget
51117
+ steps: [...steps, {
51118
+ tag: "RETRY_UPGRADE",
51119
+ result: upgradeTarget
51120
+ }]
50975
51121
  }
50976
51122
  });
50977
51123
  }
@@ -51388,8 +51534,10 @@ async function handleResponsesCore({ body, signal, headers }) {
51388
51534
  result,
51389
51535
  modelMapping: {
51390
51536
  originalModel: rewrite.originalModel,
51391
- rewrittenModel: rewrite.model,
51392
- mappedModel: effectivePayload.model
51537
+ steps: rewrite.reason ? [{
51538
+ tag: rewrite.reason,
51539
+ result: rewrite.model
51540
+ }] : []
51393
51541
  }
51394
51542
  };
51395
51543
  }
@@ -51635,7 +51783,7 @@ function createServer(options) {
51635
51783
  const model = body && typeof body === "object" && "model" in body ? body.model : void 0;
51636
51784
  if (typeof model === "string") setRequestModelMapping(request, {
51637
51785
  originalModel: model,
51638
- mappedModel: model
51786
+ steps: []
51639
51787
  });
51640
51788
  }).onAfterResponse(({ request, requestStart, set }) => {
51641
51789
  const elapsed = formatElapsed(requestStart);
@@ -51701,6 +51849,9 @@ async function runServer(options) {
51701
51849
  state.config.upstreamTimeoutSeconds = options.upstreamTimeoutSeconds;
51702
51850
  await ensurePaths();
51703
51851
  await readConfig();
51852
+ state.auth.gheDomain = getCachedConfig().gheDomain;
51853
+ if (options.gheDomain !== void 0) state.auth.gheDomain = options.gheDomain ? normalizeGheDomain(options.gheDomain) : void 0;
51854
+ if (state.auth.gheDomain && state.config.accountType === "individual") state.config.accountType = "enterprise";
51704
51855
  await cacheVSCodeVersion();
51705
51856
  if (!options.githubToken) await setupGitHubToken();
51706
51857
  await setupCopilotToken();
@@ -51792,6 +51943,11 @@ const start = defineCommand({
51792
51943
  type: "string",
51793
51944
  default: "1800",
51794
51945
  description: "Upstream request timeout in seconds (0 to disable)"
51946
+ },
51947
+ "ghe-domain": {
51948
+ alias: "ghe",
51949
+ type: "string",
51950
+ description: "Company GHE domain for GitHub Enterprise Cloud (e.g. company.ghe.com)"
51795
51951
  }
51796
51952
  },
51797
51953
  run({ args }) {
@@ -51810,7 +51966,8 @@ const start = defineCommand({
51810
51966
  showToken: args["show-token"],
51811
51967
  proxyEnv: args["proxy-env"],
51812
51968
  idleTimeoutSeconds,
51813
- upstreamTimeoutSeconds
51969
+ upstreamTimeoutSeconds,
51970
+ gheDomain: args["ghe-domain"]
51814
51971
  });
51815
51972
  }
51816
51973
  });