@nick3/copilot-api 1.5.5 → 1.5.6

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025-, Erick Christian Purwanto, and a number of other contributors
3
+ Copyright (c) 2025-, Erick Christian Purwanto, Cao Zhiyuan, Nick Liu, and a number of other contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -19,14 +19,13 @@ English | [中文](./README_CN.md)
19
19
  >
20
20
  > Use this proxy responsibly to avoid account restrictions.
21
21
 
22
- [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/E1E519XS7W)
23
-
24
22
  ---
25
23
 
26
24
  > [!NOTE]
27
25
  > [opencode](https://github.com/sst/opencode) already ships with a built-in GitHub Copilot provider, so you may not need this project for basic usage. This proxy is still useful if you want OpenCode to talk to Copilot through `@ai-sdk/anthropic`, preserve Anthropic Messages semantics for tool use, prefer the native Messages API over Chat Completions API for Claude-family models, use gpt phase-aware commentary, or optimize premium requests.
28
26
 
29
27
  ---
28
+
30
29
  ## Important Notes
31
30
 
32
31
  > [!IMPORTANT]
@@ -370,12 +369,36 @@ The `<target>` can be either the account ID (GitHub username) or a 1-based index
370
369
  - **providers:** Global upstream provider map. Each provider key (for example `custom`) becomes a route prefix (`/custom/v1/messages`). Currently only `type: "anthropic"` is supported.
371
370
  - `enabled` defaults to `true` if omitted.
372
371
  - `baseUrl` should be provider API base URL without trailing `/v1/messages`.
373
- - `apiKey` is used as upstream `x-api-key`.
372
+ - `apiKey` is used as the upstream credential value.
373
+ - `authType` (optional): Controls how `apiKey` is sent upstream. Supports `x-api-key` (default) and `authorization`. When set to `authorization`, the proxy sends `Authorization: Bearer <apiKey>`.
374
374
  - `adjustInputTokens` (optional): When `true`, the proxy will adjust the `input_tokens` in the usage response by subtracting `cache_read_input_tokens` and `cache_creation_input_tokens`.
375
375
  - `models` (optional): Per-model configuration map. Each key is a model ID (matching the model name in requests), and the value is:
376
376
  - `temperature` (optional): Default temperature value used when the request does not specify one.
377
377
  - `topP` (optional): Default top_p value used when the request does not specify one.
378
378
  - `topK` (optional): Default top_k value used when the request does not specify one.
379
+
380
+ Example provider config:
381
+
382
+ ```json
383
+ {
384
+ "providers": {
385
+ "custom": {
386
+ "type": "anthropic",
387
+ "enabled": true,
388
+ "baseUrl": "https://your-provider.example",
389
+ "apiKey": "sk-your-provider-key",
390
+ "authType": "x-api-key",
391
+ "adjustInputTokens": false,
392
+ "models": {
393
+ "kimi-k2.5": {
394
+ "temperature": 1,
395
+ "topP": 0.95
396
+ }
397
+ }
398
+ }
399
+ }
400
+ }
401
+ ```
379
402
  - **responsesApiContextManagementModels:** List of model IDs that should receive Responses API `context_management` compaction instructions. Use this when a model supports server-side context management and you want the proxy to keep only the latest compaction carrier on follow-up turns.
380
403
  - **smallModel:** Fallback model used for tool-less warmup messages, compact/background requests, and other short housekeeping turns (for example from Claude Code or OpenCode) to avoid spending premium requests; defaults to `gpt-5-mini`. If original names are blocked and this points to an aliased target, it resolves to the preferred alias.
381
404
  - **accountAffinity:** Enable sticky account routing based on session identity. When enabled, requests from the same session for the same model are routed to the account that last handled them successfully. Applies to both free and premium models. Defaults to `true`. Set to `false` to use sequential routing for all models.
@@ -354,6 +354,12 @@ function isForceAgentEnabled() {
354
354
  function normalizeProviderBaseUrl(url) {
355
355
  return url.trim().replace(/\/+$/u, "");
356
356
  }
357
+ function resolveProviderAuthType(providerName, authType) {
358
+ if (authType === void 0 || authType === "x-api-key") return "x-api-key";
359
+ if (authType === "authorization") return authType;
360
+ consola.warn(`Provider ${providerName} has invalid authType '${authType}', ignoring provider`);
361
+ return null;
362
+ }
357
363
  function getProviderConfig(name) {
358
364
  const providerName = name.trim();
359
365
  if (!providerName) return null;
@@ -366,6 +372,8 @@ function getProviderConfig(name) {
366
372
  }
367
373
  const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? "");
368
374
  const apiKey = (provider.apiKey ?? "").trim();
375
+ const authType = resolveProviderAuthType(providerName, provider.authType);
376
+ if (!authType) return null;
369
377
  if (!baseUrl || !apiKey) {
370
378
  consola.warn(`Provider ${providerName} is enabled but missing baseUrl or apiKey`);
371
379
  return null;
@@ -375,6 +383,7 @@ function getProviderConfig(name) {
375
383
  type: PROVIDER_TYPE_ANTHROPIC,
376
384
  baseUrl,
377
385
  apiKey,
386
+ authType,
378
387
  models: provider.models,
379
388
  adjustInputTokens: provider.adjustInputTokens
380
389
  };
@@ -591,6 +600,12 @@ const WATCHER_RESTART_MAX_DELAY_MS = 60 * 1e3;
591
600
  const SESSION_REFRESH_BASE_MS = 3600 * 1e3;
592
601
  /** Session refresh jitter window in milliseconds. */
593
602
  const SESSION_REFRESH_JITTER_MS = 1200 * 1e3;
603
+ /** Minimum delay between account initializations in milliseconds. */
604
+ const INIT_STAGGER_MIN_MS = 2e3;
605
+ /** Maximum delay between account initializations in milliseconds. */
606
+ const INIT_STAGGER_MAX_MS = 5e3;
607
+ /** Random jitter window added to token refresh delay in milliseconds. */
608
+ const TOKEN_REFRESH_JITTER_MS = 3e4;
594
609
  /** Manages multiple GitHub Copilot accounts at runtime. */
595
610
  var AccountsManager = class {
596
611
  accounts = /* @__PURE__ */ new Map();
@@ -610,6 +625,7 @@ var AccountsManager = class {
610
625
  registryWatcherRestartTimer;
611
626
  registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS;
612
627
  isReloading = false;
628
+ currentReloadPromise;
613
629
  /** Initialize accounts manager (load registry, migrate legacy token). */
614
630
  async initialize(vsCodeVersion) {
615
631
  this.vsCodeVersion = vsCodeVersion;
@@ -632,12 +648,21 @@ var AccountsManager = class {
632
648
  this.accounts.set(meta.id, runtime);
633
649
  this.accountOrder.push(meta.id);
634
650
  }
635
- for (const account of this.accounts.values()) try {
636
- await this.initializeAccount(account);
637
- } catch (error) {
638
- consola.error(`Failed to initialize account ${account.id}:`, error);
639
- account.failed = true;
640
- account.failureReason = String(error);
651
+ let isFirstAccount = true;
652
+ for (const account of this.accounts.values()) {
653
+ if (!isFirstAccount) {
654
+ const staggerDelay = INIT_STAGGER_MIN_MS + Math.floor(Math.random() * (INIT_STAGGER_MAX_MS - INIT_STAGGER_MIN_MS));
655
+ consola.debug(`Staggering initialization of account ${account.id} by ${staggerDelay}ms`);
656
+ await new Promise((resolve) => setTimeout(resolve, staggerDelay));
657
+ }
658
+ isFirstAccount = false;
659
+ try {
660
+ await this.initializeAccount(account);
661
+ } catch (error) {
662
+ consola.error(`Failed to initialize account ${account.id}:`, error);
663
+ account.failed = true;
664
+ account.failureReason = String(error);
665
+ }
641
666
  }
642
667
  consola.info(`Loaded ${this.accounts.size} account(s)`);
643
668
  this.startRegistryWatcher();
@@ -651,7 +676,10 @@ var AccountsManager = class {
651
676
  this.scheduleModelsRefresh();
652
677
  }
653
678
  computeTokenRefreshDelayMs(refreshInSeconds) {
654
- return Math.max((refreshInSeconds - 60) * 1e3, 1e3);
679
+ const baseDelay = Math.max((refreshInSeconds - 60) * 1e3, 1e3);
680
+ const jitter = Math.floor(Math.random() * TOKEN_REFRESH_JITTER_MS);
681
+ const maxSafeDelay = Math.max(refreshInSeconds * 1e3 - 1e3, 1e3);
682
+ return Math.min(baseDelay + jitter, maxSafeDelay);
655
683
  }
656
684
  computeSessionRefreshDelayMs() {
657
685
  return SESSION_REFRESH_BASE_MS + Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS);
@@ -1298,6 +1326,19 @@ var AccountsManager = class {
1298
1326
  }
1299
1327
  }
1300
1328
  /**
1329
+ * Immediately reload the registry, bypassing the debounce delay.
1330
+ * If a reload is already running, waits for it to complete and then
1331
+ * runs another reload to ensure the latest changes are captured.
1332
+ */
1333
+ async reloadRegistryNow() {
1334
+ if (this.reloadDebounceTimer) {
1335
+ clearTimeout(this.reloadDebounceTimer);
1336
+ this.reloadDebounceTimer = void 0;
1337
+ }
1338
+ if (this.currentReloadPromise) await this.currentReloadPromise;
1339
+ await this.reloadRegistry();
1340
+ }
1341
+ /**
1301
1342
  * Schedule a registry reload with debouncing.
1302
1343
  */
1303
1344
  scheduleReload() {
@@ -1314,26 +1355,30 @@ var AccountsManager = class {
1314
1355
  async reloadRegistry() {
1315
1356
  if (this.isReloading) return;
1316
1357
  this.isReloading = true;
1317
- try {
1318
- const newMetas = await listAccountsFromRegistry();
1319
- const newIds = new Set(newMetas.map((m) => m.id));
1320
- const currentIds = new Set(this.accountOrder);
1321
- const added = [];
1322
- const removed = [];
1323
- const updated = [];
1324
- this.removeDeletedAccounts(currentIds, newIds, removed);
1325
- for (const meta of newMetas) if (!currentIds.has(meta.id)) await this.addNewAccount(meta, added);
1326
- await this.reinitializeUpdatedAccounts(newMetas, currentIds, updated);
1327
- this.accountOrder = newMetas.map((m) => m.id).filter((id) => this.accounts.has(id));
1328
- this.loadBalanceCursor = 0;
1329
- this.logRegistryReloadChanges(added, removed, updated);
1330
- } catch (error) {
1331
- consola.error("Failed to reload registry:", error);
1332
- this.shutdown();
1333
- process.exit(1);
1334
- } finally {
1335
- this.isReloading = false;
1336
- }
1358
+ this.currentReloadPromise = (async () => {
1359
+ try {
1360
+ const newMetas = await listAccountsFromRegistry();
1361
+ const newIds = new Set(newMetas.map((m) => m.id));
1362
+ const currentIds = new Set(this.accountOrder);
1363
+ const added = [];
1364
+ const removed = [];
1365
+ const updated = [];
1366
+ this.removeDeletedAccounts(currentIds, newIds, removed);
1367
+ for (const meta of newMetas) if (!currentIds.has(meta.id)) await this.addNewAccount(meta, added);
1368
+ await this.reinitializeUpdatedAccounts(newMetas, currentIds, updated);
1369
+ this.accountOrder = newMetas.map((m) => m.id).filter((id) => this.accounts.has(id));
1370
+ this.loadBalanceCursor = 0;
1371
+ this.logRegistryReloadChanges(added, removed, updated);
1372
+ } catch (error) {
1373
+ consola.error("Failed to reload registry:", error);
1374
+ this.shutdown();
1375
+ process.exit(1);
1376
+ } finally {
1377
+ this.isReloading = false;
1378
+ this.currentReloadPromise = void 0;
1379
+ }
1380
+ })();
1381
+ await this.currentReloadPromise;
1337
1382
  }
1338
1383
  removeDeletedAccounts(currentIds, newIds, removed) {
1339
1384
  for (const id of currentIds) if (!newIds.has(id)) {
@@ -1446,4 +1491,4 @@ const accountsManager = new AccountsManager();
1446
1491
 
1447
1492
  //#endregion
1448
1493
  export { isMessagesApiEnabled as _, getClaudeTokenMultiplier as a, mergeConfigWithDefaults as b, getModelAliases as c, getProviderConfig as d, getReasoningEffortForModel as f, isMessageStartInputTokensFallbackEnabled as g, isForceAgentEnabled as h, getAnthropicApiKey as i, getModelAliasesInfo as l, isAccountAffinityEnabled as m, PROVIDER_TYPE_ANTHROPIC as n, getConfig as o, getSmallModel as p, getAliasTargetSet as r, getExtraPromptForModel as s, accountsManager as t, getModelRefreshIntervalMs as u, isResponsesApiContextManagementModel as v, shouldCompactUseSmallModel as x, isResponsesApiWebSearchEnabled as y };
1449
- //# sourceMappingURL=accounts-manager-BevCBoaF.js.map
1494
+ //# sourceMappingURL=accounts-manager-BE-Dq5Wn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts-manager-BE-Dq5Wn.js","names":["defaultConfig: AppConfig","cachedConfig: AppConfig | null","normalizedTarget","normalized: ModelAliasInfoMap","normalized: ModelAliasMap","runtime: AccountRuntime","accounts: Array<AccountRuntime>","overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined","statuses: Array<{\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n }>","allAccounts: Array<AccountRuntime>","added: Array<string>","removed: Array<string>","updated: Array<string>","changes: Array<string>"],"sources":["../src/lib/config.ts","../src/lib/account-affinity.ts","../src/lib/accounts-manager-auth.ts","../src/lib/accounts-manager-quota.ts","../src/lib/accounts-manager.ts"],"sourcesContent":["import consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport { PATHS } from \"./paths\"\n\nexport interface AppConfig {\n auth?: {\n apiKeys?: Array<string>\n }\n providers?: Record<string, ProviderConfig>\n extraPrompts?: Record<string, string>\n smallModel?: string\n accountAffinity?: boolean\n /** @deprecated */\n apiKey?: string\n responsesApiContextManagementModels?: Array<string>\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n modelAliases?: Record<string, { target: string; allowOriginal?: boolean }>\n allowOriginalModelNamesForAliases?: boolean\n useFunctionApplyPatch?: boolean\n forceAgent?: boolean\n compactUseSmallModel?: boolean\n messageStartInputTokensFallback?: boolean\n modelRefreshIntervalHours?: number\n useMessagesApi?: boolean\n anthropicApiKey?: string\n useResponsesApiWebSearch?: boolean\n claudeTokenMultiplier?: number\n}\n\nexport interface ModelConfig {\n temperature?: number\n topP?: number\n topK?: number\n}\n\nexport const PROVIDER_TYPE_ANTHROPIC = \"anthropic\" as const\n\nexport type ProviderType = typeof PROVIDER_TYPE_ANTHROPIC\n\nexport type ProviderAuthType = \"authorization\" | \"x-api-key\"\n\nexport interface ProviderConfig {\n type?: string\n enabled?: boolean\n baseUrl?: string\n apiKey?: string\n authType?: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nexport interface ResolvedProviderConfig {\n name: string\n type: ProviderType\n baseUrl: string\n apiKey: string\n authType: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nconst gpt5ExplorationPrompt = `## Exploration and reading files\n- **Think first.** Before any tool call, decide ALL files/resources you will need.\n- **Batch everything.** If you need multiple files (even from different places), read them together.\n- **multi_tool_use.parallel** Use multi_tool_use.parallel to parallelize tool calls and only this.\n- **Only make sequential calls if you truly cannot know the next file without seeing a result first.**\n- **Workflow:** (a) plan all needed reads → (b) issue one parallel batch → (c) analyze results → (d) repeat if new, unpredictable reads arise.`\n\nconst gpt5CommentaryPrompt = `# Working with the user\n\nYou interact with the user through a terminal. You have 2 ways of communicating with the users: \n- Share intermediary updates in \\`commentary\\` channel. \n- After you have completed all your work, send a message to the \\`final\\` channel. \n\n## Intermediary updates\n\n- Intermediary updates go to the \\`commentary\\` channel.\n- User updates are short updates while you are working, they are NOT final answers.\n- You use 1-2 sentence user updates to communicate progress and new information to the user as you are doing work.\n- Do not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements (“Done —”, “Got it”, “Great question, ”) or framing phrases.\n- You provide user updates frequently, every 20s.\n- Before exploring or doing substantial work, you start with a user update acknowledging the request and explaining your first step. You should include your understanding of the user request and explain what you will do. Avoid commenting on the request or using starters such as \"Got it -\" or \"Understood -\" etc.\n- When exploring, e.g. searching, reading files, you provide user updates as you go, every 20s, explaining what context you are gathering and what you've learned. Vary your sentence structure when providing these updates to avoid sounding repetitive - in particular, don't start each sentence the same way.\n- After you have sufficient context, and the work is substantial, you provide a longer plan (this is the only user update that may be longer than 2 sentences and can contain formatting).\n- Before performing file edits of any kind, you provide updates explaining what edits you are making.\n- As you are thinking, you very frequently provide updates even if not taking any actions, informing the user of your progress. You interrupt your thinking and send multiple updates in a row if thinking for more than 100 words.\n- Tone of your updates MUST match your personality.`\n\nconst defaultConfig: AppConfig = {\n auth: {\n apiKeys: [],\n },\n providers: {},\n extraPrompts: {\n \"gpt-5-mini\": gpt5ExplorationPrompt,\n \"gpt-5.3-codex\": gpt5CommentaryPrompt,\n \"gpt-5.4-mini\": gpt5CommentaryPrompt,\n \"gpt-5.4\": gpt5CommentaryPrompt,\n },\n smallModel: \"gpt-5-mini\",\n accountAffinity: true,\n responsesApiContextManagementModels: [],\n modelReasoningEfforts: {\n \"gpt-5-mini\": \"low\",\n \"gpt-5.3-codex\": \"xhigh\",\n \"gpt-5.4-mini\": \"xhigh\",\n \"gpt-5.4\": \"xhigh\",\n },\n allowOriginalModelNamesForAliases: false,\n useFunctionApplyPatch: true,\n forceAgent: false,\n compactUseSmallModel: true,\n messageStartInputTokensFallback: false,\n modelRefreshIntervalHours: 24,\n useMessagesApi: true,\n useResponsesApiWebSearch: true,\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction normalizeAuthApiKeys(value: unknown): Array<string> {\n if (!Array.isArray(value)) return []\n\n return [\n ...new Set(\n value\n .filter((item): item is string => typeof item === \"string\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0),\n ),\n ]\n}\n\nfunction normalizeModelRefreshIntervalHours(\n value: unknown,\n): number | undefined {\n if (typeof value !== \"number\") return undefined\n if (!Number.isFinite(value)) return undefined\n if (value < 0) return undefined\n return value\n}\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK)\n return\n } catch {\n // Fall through to try creating the default config file.\n }\n\n try {\n fs.mkdirSync(PATHS.APP_DIR, { recursive: true })\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n try {\n fs.chmodSync(PATHS.CONFIG_PATH, 0o600)\n } catch {\n // Ignore chmod errors (e.g. unsupported filesystem).\n }\n } catch {\n // Best-effort only: if we can't create the file, reads will fall back to defaults.\n }\n}\n\nfunction readConfigFromDisk(): AppConfig {\n ensureConfigFile()\n try {\n const raw = fs.readFileSync(PATHS.CONFIG_PATH, \"utf8\")\n if (!raw.trim()) {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n return defaultConfig\n }\n return JSON.parse(raw) as AppConfig\n } catch (error) {\n consola.error(\"Failed to read config file, using default config\", error)\n return defaultConfig\n }\n}\n\nfunction mergeDefaultConfig(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const extraPrompts = config.extraPrompts ?? {}\n const defaultExtraPrompts = defaultConfig.extraPrompts ?? {}\n const modelReasoningEfforts = config.modelReasoningEfforts ?? {}\n const defaultModelReasoningEfforts = defaultConfig.modelReasoningEfforts ?? {}\n const hasForceAgent = typeof config.forceAgent === \"boolean\"\n const defaultForceAgent = defaultConfig.forceAgent ?? false\n\n const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter(\n (model) => !Object.hasOwn(extraPrompts, model),\n )\n\n const missingReasoningEffortModels = Object.keys(\n defaultModelReasoningEfforts,\n ).filter((model) => !Object.hasOwn(modelReasoningEfforts, model))\n\n const hasExtraPromptChanges = missingExtraPromptModels.length > 0\n const hasReasoningEffortChanges = missingReasoningEffortModels.length > 0\n const hasForceAgentChanges = !hasForceAgent\n\n if (\n !hasExtraPromptChanges\n && !hasReasoningEffortChanges\n && !hasForceAgentChanges\n ) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n extraPrompts: {\n ...defaultExtraPrompts,\n ...extraPrompts,\n },\n modelReasoningEfforts: {\n ...defaultModelReasoningEfforts,\n ...modelReasoningEfforts,\n },\n forceAgent: hasForceAgent ? config.forceAgent : defaultForceAgent,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAuth(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const authConfig = isPlainObject(config.auth) ? config.auth : undefined\n const rawApiKeys =\n Array.isArray(authConfig?.apiKeys) ? authConfig.apiKeys : undefined\n const normalizedApiKeys = normalizeAuthApiKeys(rawApiKeys)\n const nextAuth = { apiKeys: normalizedApiKeys }\n\n if (authConfig && JSON.stringify(authConfig) === JSON.stringify(nextAuth)) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n auth: nextAuth,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAccountAffinity(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n // Migration: map old freeModelLoadBalancing to accountAffinity\n const raw = config as Record<string, unknown>\n const hasOld = typeof raw.freeModelLoadBalancing === \"boolean\"\n const hasNew = typeof config.accountAffinity === \"boolean\"\n\n if (hasOld) {\n const next = { ...config } as Record<string, unknown>\n if (!hasNew) {\n next.accountAffinity = raw.freeModelLoadBalancing\n }\n delete next.freeModelLoadBalancing\n return { mergedConfig: next as AppConfig, changed: true }\n }\n\n if (hasNew) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n accountAffinity: defaultConfig.accountAffinity ?? true,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultModelRefreshInterval(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeModelRefreshIntervalHours(\n config.modelRefreshIntervalHours,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n modelRefreshIntervalHours: defaultConfig.modelRefreshIntervalHours ?? 24,\n },\n changed: true,\n }\n}\n\ntype ConfigMergeResult = {\n mergedConfig: AppConfig\n changed: boolean\n}\n\ntype ConfigMergeFn = (config: AppConfig) => ConfigMergeResult\n\nfunction applyConfigMerges(\n config: AppConfig,\n mergeFns: ReadonlyArray<ConfigMergeFn>,\n): ConfigMergeResult {\n return mergeFns.reduce<ConfigMergeResult>(\n (acc, mergeFn) => {\n const result = mergeFn(acc.mergedConfig)\n return {\n mergedConfig: result.mergedConfig,\n changed: acc.changed || result.changed,\n }\n },\n { mergedConfig: config, changed: false },\n )\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n\n const { mergedConfig, changed } = applyConfigMerges(config, [\n mergeDefaultAuth,\n mergeDefaultConfig,\n mergeDefaultAccountAffinity,\n mergeDefaultModelRefreshInterval,\n ])\n\n if (changed) {\n try {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(mergedConfig, null, 2)}\\n`,\n \"utf8\",\n )\n } catch (writeError) {\n consola.warn(\"Failed to write merged config defaults\", writeError)\n }\n }\n\n cachedConfig = mergedConfig\n return mergedConfig\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= readConfigFromDisk()\n return cachedConfig\n}\n\ntype ModelAliasSpec = {\n target: string\n allowOriginal?: boolean\n}\n\ntype ModelAliasMap = Record<string, string>\n\ntype ModelAliasInfoMap = Record<string, ModelAliasSpec>\n\ntype ModelAliasRawMap = Record<string, unknown>\n\nfunction normalizeAliasKey(value: string): string | null {\n const trimmed = value.trim().toLowerCase()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasTarget(value: string): string | null {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasSpec(value: unknown): ModelAliasSpec | null {\n if (typeof value === \"string\") {\n const normalizedTarget = normalizeAliasTarget(value)\n return normalizedTarget ? { target: normalizedTarget } : null\n }\n if (!value || typeof value !== \"object\") {\n return null\n }\n\n const targetValue = (value as { target?: unknown }).target\n if (typeof targetValue !== \"string\") {\n return null\n }\n\n const normalizedTarget = normalizeAliasTarget(targetValue)\n if (!normalizedTarget) {\n return null\n }\n\n const allowOriginalValue = (value as { allowOriginal?: unknown })\n .allowOriginal\n const allowOriginal =\n typeof allowOriginalValue === \"boolean\" ? allowOriginalValue : undefined\n return { target: normalizedTarget, allowOriginal }\n}\n\nexport function getModelAliasesInfo(): ModelAliasInfoMap {\n const config = getConfig()\n const raw = (config.modelAliases ?? {}) as ModelAliasRawMap\n const normalized: ModelAliasInfoMap = {}\n\n for (const [alias, rawSpec] of Object.entries(raw)) {\n const normalizedAlias = normalizeAliasKey(alias)\n const normalizedSpec = normalizeAliasSpec(rawSpec)\n if (!normalizedAlias || !normalizedSpec) {\n continue\n }\n if (!Object.hasOwn(normalized, normalizedAlias)) {\n normalized[normalizedAlias] = normalizedSpec\n }\n }\n\n return normalized\n}\n\nexport function getModelAliases(): ModelAliasMap {\n const info = getModelAliasesInfo()\n const normalized: ModelAliasMap = {}\n\n for (const [alias, spec] of Object.entries(info)) {\n normalized[alias] = spec.target\n }\n\n return normalized\n}\n\nexport function resolveModelAlias(modelId: string): string {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return modelId\n const aliases = getModelAliases()\n return aliases[normalized] ?? modelId\n}\n\nexport function isOriginalModelNameAllowedForAliases(): boolean {\n const config = getConfig()\n return config.allowOriginalModelNamesForAliases ?? false\n}\n\nexport function getAliasTargetSet(): Set<string> {\n const aliases = getModelAliasesInfo()\n const allowOriginalDefault = isOriginalModelNameAllowedForAliases()\n const targetAllowMap = new Map<string, boolean>()\n\n for (const { target, allowOriginal } of Object.values(aliases)) {\n const normalizedTarget = target.toLowerCase()\n const effectiveAllow = allowOriginal ?? allowOriginalDefault\n const currentAllow = targetAllowMap.get(normalizedTarget)\n if (currentAllow === true) {\n continue\n }\n if (effectiveAllow) {\n targetAllowMap.set(normalizedTarget, true)\n } else if (currentAllow === undefined) {\n targetAllowMap.set(normalizedTarget, false)\n }\n }\n\n const blockedTargets = new Set<string>()\n for (const [target, allowed] of targetAllowMap.entries()) {\n if (!allowed) {\n blockedTargets.add(target)\n }\n }\n\n return blockedTargets\n}\n\nexport function isOriginalModelNameAllowedForTarget(modelId: string): boolean {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return true\n const blockedTargets = getAliasTargetSet()\n return !blockedTargets.has(normalized)\n}\n\nexport function getPreferredAliasForTarget(modelId: string): string | null {\n const aliases = getModelAliases()\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n return aliasKeys[0] ?? null\n}\n\nfunction getAliasKeysForTarget(\n target: string,\n aliases: ModelAliasMap,\n): Array<string> {\n const normalizedTarget = target.toLowerCase()\n return Object.entries(aliases)\n .filter(([, model]) => model.toLowerCase() === normalizedTarget)\n .map(([alias]) => alias)\n .sort()\n}\n\nfunction getAliasFallbackValue<T extends string>(\n record: Record<string, T> | undefined,\n modelId: string,\n aliases: ModelAliasMap,\n): T | undefined {\n if (!record) return undefined\n\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n if (aliasKeys.length === 0) return undefined\n\n const recordByAlias = new Map<string, T>()\n for (const [key, value] of Object.entries(record)) {\n const normalized = normalizeAliasKey(key)\n if (normalized) {\n recordByAlias.set(normalized, value)\n }\n }\n\n for (const alias of aliasKeys) {\n const value = recordByAlias.get(alias)\n if (value !== undefined) {\n return value\n }\n }\n\n return undefined\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n const direct = config.extraPrompts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(config.extraPrompts, model, aliases)\n return fallback ?? \"\"\n}\n\nexport function getSmallModel(): string {\n const config = getConfig()\n const model = config.smallModel ?? \"gpt-5-mini\"\n if (isOriginalModelNameAllowedForTarget(model)) {\n return model\n }\n\n return getPreferredAliasForTarget(model) ?? model\n}\n\nexport function isAccountAffinityEnabled(): boolean {\n const config = getConfig()\n return config.accountAffinity ?? true\n}\n\nexport function getModelRefreshIntervalHours(): number {\n const config = getConfig()\n const normalized = normalizeModelRefreshIntervalHours(\n config.modelRefreshIntervalHours,\n )\n return normalized ?? defaultConfig.modelRefreshIntervalHours ?? 24\n}\n\nexport function getModelRefreshIntervalMs(): number {\n const hours = getModelRefreshIntervalHours()\n if (!Number.isFinite(hours) || hours <= 0) return 0\n return hours * 60 * 60 * 1000\n}\n\nexport function isMessageStartInputTokensFallbackEnabled(): boolean {\n const config = getConfig()\n return config.messageStartInputTokensFallback ?? false\n}\n\nexport function shouldCompactUseSmallModel(): boolean {\n const config = getConfig()\n return config.compactUseSmallModel ?? true\n}\n\nexport function getResponsesApiContextManagementModels(): Array<string> {\n const config = getConfig()\n return (\n config.responsesApiContextManagementModels\n ?? defaultConfig.responsesApiContextManagementModels\n ?? []\n )\n}\n\nexport function isResponsesApiContextManagementModel(model: string): boolean {\n return getResponsesApiContextManagementModels().includes(model)\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n const direct = config.modelReasoningEfforts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(\n config.modelReasoningEfforts,\n model,\n aliases,\n )\n return fallback ?? \"high\"\n}\n\nexport function isForceAgentEnabled(): boolean {\n const config = getConfig()\n return config.forceAgent ?? false\n}\n\nexport function normalizeProviderBaseUrl(url: string): string {\n return url.trim().replace(/\\/+$/u, \"\")\n}\n\nfunction resolveProviderAuthType(\n providerName: string,\n authType?: string,\n): ProviderAuthType | null {\n if (authType === undefined || authType === \"x-api-key\") {\n return \"x-api-key\"\n }\n\n if (authType === \"authorization\") {\n return authType\n }\n\n consola.warn(\n `Provider ${providerName} has invalid authType '${authType}', ignoring provider`,\n )\n return null\n}\n\nexport function getProviderConfig(name: string): ResolvedProviderConfig | null {\n const providerName = name.trim()\n if (!providerName) {\n return null\n }\n\n const config = getConfig()\n const provider = config.providers?.[providerName]\n if (!provider) {\n return null\n }\n\n if (provider.enabled === false) {\n return null\n }\n\n const type = provider.type ?? PROVIDER_TYPE_ANTHROPIC\n if (type !== PROVIDER_TYPE_ANTHROPIC) {\n consola.warn(\n `Provider ${providerName} is ignored because only anthropic type is supported`,\n )\n return null\n }\n\n const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? \"\")\n const apiKey = (provider.apiKey ?? \"\").trim()\n const authType = resolveProviderAuthType(providerName, provider.authType)\n if (!authType) {\n return null\n }\n if (!baseUrl || !apiKey) {\n consola.warn(\n `Provider ${providerName} is enabled but missing baseUrl or apiKey`,\n )\n return null\n }\n\n return {\n name: providerName,\n type: PROVIDER_TYPE_ANTHROPIC,\n baseUrl,\n apiKey,\n authType,\n models: provider.models,\n adjustInputTokens: provider.adjustInputTokens,\n }\n}\n\nexport function listEnabledProviders(): Array<string> {\n const config = getConfig()\n const providerNames = Object.keys(config.providers ?? {})\n return providerNames.filter((name) => getProviderConfig(name) !== null)\n}\n\nexport function isMessagesApiEnabled(): boolean {\n const config = getConfig()\n return config.useMessagesApi ?? true\n}\n\nexport function getAnthropicApiKey(): string | undefined {\n const config = getConfig()\n return config.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY ?? undefined\n}\n\nexport function isResponsesApiWebSearchEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiWebSearch ?? true\n}\n\nexport function getClaudeTokenMultiplier(): number {\n const config = getConfig()\n return config.claudeTokenMultiplier ?? 1.15\n}\n","import type { AccountRuntime } from \"~/lib/types/account\"\n\nexport interface AffinityContext {\n requestId?: string\n}\n\ninterface AffinityCacheEntry {\n accountId: string\n expiresAt: number\n}\n\nconst DEFAULT_MAX_ENTRIES = 10_000\nconst DEFAULT_TTL_MS = 60 * 60 * 1000 // 1 hour\n\n/**\n * In-memory LRU cache with TTL for account affinity mappings.\n *\n * Uses Map insertion order for LRU eviction: accessed/updated entries are\n * deleted and re-inserted so they move to the \"newest\" end.\n */\nexport class AccountAffinityCache {\n private readonly cache = new Map<string, AffinityCacheEntry>()\n private readonly maxEntries: number\n private readonly ttlMs: number\n\n constructor(maxEntries = DEFAULT_MAX_ENTRIES, ttlMs = DEFAULT_TTL_MS) {\n this.maxEntries = maxEntries\n this.ttlMs = ttlMs\n }\n\n /** Look up the preferred account ID for a cache key. Returns undefined if not found or expired. */\n get(key: string): string | undefined {\n const entry = this.cache.get(key)\n if (!entry) {\n return undefined\n }\n\n if (Date.now() >= entry.expiresAt) {\n this.cache.delete(key)\n return undefined\n }\n\n return entry.accountId\n }\n\n /** Record a successful account mapping. Refreshes TTL and moves the entry to the newest position. */\n set(key: string, accountId: string): void {\n // Delete first so re-insertion moves it to the newest position (LRU).\n this.cache.delete(key)\n\n // Evict oldest entries if at capacity.\n while (this.cache.size >= this.maxEntries) {\n const oldest = this.cache.keys().next()\n if (oldest.done) break\n this.cache.delete(oldest.value)\n }\n\n this.cache.set(key, {\n accountId,\n expiresAt: Date.now() + this.ttlMs,\n })\n }\n\n /** Remove a specific entry. */\n delete(key: string): boolean {\n return this.cache.delete(key)\n }\n\n /** Remove all entries. */\n clear(): void {\n this.cache.clear()\n }\n\n /** Current number of entries (including potentially expired ones). */\n get size(): number {\n return this.cache.size\n }\n}\n\n/**\n * Extract the affinity key from the request context.\n * Uses the upstream request ID which is deterministic for the same user message.\n */\nexport function extractAffinityKey(\n context: AffinityContext,\n): string | undefined {\n return context.requestId?.trim() || undefined\n}\n\n/**\n * Build the full cache key by combining the affinity key with the model ID.\n * This prevents cross-model pollution (same session requesting different models\n * can be routed to different accounts).\n */\nexport function buildAffinityCacheKey(\n affinityKey: string,\n modelId: string,\n): string {\n return `${affinityKey}:${modelId}`\n}\n\n/**\n * Check whether an account is a valid affinity candidate.\n * An account is valid if it is not failed and is present in the provided\n * runtime list.\n */\nexport function isAffinityAccountUsable(\n accountId: string,\n accounts: ReadonlyArray<AccountRuntime>,\n): AccountRuntime | undefined {\n const account = accounts.find((a) => a.id === accountId)\n if (!account) return undefined\n if (account.failed) return undefined\n return account\n}\n","import consola from \"consola\"\n\nimport type {\n AccountContext,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\nimport type { QuotaDetail } from \"~/services/github/get-copilot-usage\"\n\nexport type AuthSnapshot = Readonly<{\n githubToken: string\n accountType: AccountType\n}>\n\nexport const takeAuthSnapshot = (account: AccountRuntime): AuthSnapshot => ({\n githubToken: account.githubToken,\n accountType: account.accountType,\n})\n\nexport const isAuthSnapshotCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n): boolean =>\n account.githubToken === snapshot.githubToken\n && account.accountType === snapshot.accountType\n\nexport const isSameAuthSnapshot = (\n a: AuthSnapshot | undefined,\n b: AuthSnapshot,\n): boolean => {\n if (!a) return false\n return a.githubToken === b.githubToken && a.accountType === b.accountType\n}\n\nexport const toAccountContextFromSnapshot = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken?: string,\n): AccountContext => ({\n accountLogin: account.accountLogin,\n githubToken: snapshot.githubToken,\n copilotToken,\n ...(account.copilotApiUrl !== undefined ?\n { copilotApiUrl: account.copilotApiUrl }\n : {}),\n accountType: snapshot.accountType,\n vsCodeVersion: account.vsCodeVersion,\n clientDeviceId: account.clientDeviceId,\n clientMachineId: account.clientMachineId,\n clientSessionId: account.clientSessionId,\n})\n\nexport const applyCopilotTokenIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = copilotToken\n return true\n}\n\nexport const applyModelsIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n models: AccountRuntime[\"models\"],\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.models = models\n return true\n}\n\nexport const applyTokenRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n token: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = token\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const applyTokenRefreshFailureIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n error: unknown,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.failed = true\n account.failureReason = String(error)\n return true\n}\n\nexport const applyQuotaRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n result: {\n premium: QuotaDetail\n copilotApiUrl?: string\n },\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n const { premium, copilotApiUrl } = result\n\n account.premiumEntitlement = premium.entitlement\n account.premiumRemaining = premium.remaining\n account.unlimited = premium.unlimited\n account.overagePermitted = premium.overage_permitted\n if (copilotApiUrl) {\n account.copilotApiUrl = copilotApiUrl\n }\n account.lastQuotaFetch = Date.now()\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const setAccountFailedState = (\n account: AccountRuntime,\n reason: string,\n): void => {\n account.failed = true\n account.failureReason = reason\n consola.warn(`Account ${account.id} marked as failed: ${reason}`)\n}\n\nexport const applyUnauthorizedIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n reason: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n setAccountFailedState(account, reason)\n return true\n}\n","import type { AccountRuntime } from \"~/lib/types/account\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport type QuotaReservation = Readonly<{ id: symbol }>\n\nexport const getCostUnits = (model: Model): number => {\n // Per user decision: missing billing => treat as free (costUnits = 0)\n const billing = model.billing\n if (!billing) {\n return 0\n }\n\n if (billing.is_premium !== true) {\n return 0\n }\n\n const multiplier = billing.multiplier\n if (\n typeof multiplier !== \"number\"\n || !Number.isFinite(multiplier)\n || multiplier <= 0\n ) {\n return 1\n }\n\n return multiplier\n}\n\nexport const getEffectivePremiumRemaining = (\n account: AccountRuntime,\n): number | undefined => {\n if (account.premiumRemaining === undefined) {\n return undefined\n }\n\n const reserved = account.premiumReserved ?? 0\n return account.premiumRemaining - reserved\n}\n\nexport const reservePremiumUnits = (\n account: AccountRuntime,\n units: number,\n): QuotaReservation | undefined => {\n if (units <= 0) {\n return undefined\n }\n\n const id = Symbol(\"quotaReservation\")\n\n if (!account.premiumReservations) {\n account.premiumReservations = new Map()\n }\n\n account.premiumReservations.set(id, units)\n account.premiumReserved = (account.premiumReserved ?? 0) + units\n\n return { id }\n}\n\nexport const releasePremiumReservation = (\n account: AccountRuntime,\n reservation?: QuotaReservation,\n): void => {\n if (!reservation) {\n return\n }\n\n const reservations = account.premiumReservations\n if (!reservations) {\n return\n }\n\n const reservedUnits = reservations.get(reservation.id)\n if (reservedUnits === undefined) {\n return\n }\n\n reservations.delete(reservation.id)\n\n const nextReserved = (account.premiumReserved ?? 0) - reservedUnits\n account.premiumReserved = Math.max(0, nextReserved)\n\n if (reservations.size === 0) {\n account.premiumReservations = undefined\n }\n}\n","/* eslint-disable max-lines */\nimport consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport type {\n AccountContext,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\n\nimport {\n AccountAffinityCache,\n buildAffinityCacheKey,\n extractAffinityKey,\n isAffinityAccountUsable,\n type AffinityContext,\n} from \"~/lib/account-affinity\"\nimport { resolveModelAlias } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { getModels, type Model } from \"~/services/copilot/get-models\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\n\nimport {\n buildIdentityKey,\n createAccountSessionId,\n getCurrentIdentityEnvironment,\n} from \"./account-client-identity\"\nimport {\n applyCopilotTokenIfCurrent,\n applyModelsIfCurrent,\n applyQuotaRefreshSuccessIfCurrent,\n applyTokenRefreshFailureIfCurrent,\n applyTokenRefreshSuccessIfCurrent,\n applyUnauthorizedIfCurrent,\n isAuthSnapshotCurrent,\n isSameAuthSnapshot,\n setAccountFailedState,\n takeAuthSnapshot,\n toAccountContextFromSnapshot,\n type AuthSnapshot,\n} from \"./accounts-manager-auth\"\nimport {\n getCostUnits,\n getEffectivePremiumRemaining,\n releasePremiumReservation,\n reservePremiumUnits,\n type QuotaReservation,\n} from \"./accounts-manager-quota\"\nimport {\n hasLegacyToken,\n hasRegistry,\n ensureAccountClientIdentity,\n listAccountsFromRegistry,\n loadAccountToken,\n readLegacyToken,\n saveAccountToken,\n addAccountToRegistry,\n} from \"./accounts-registry\"\nimport { PATHS } from \"./paths\"\n\n/** Quota cache TTL in milliseconds (45 seconds) for pre-request selection. */\nconst QUOTA_CACHE_TTL = 45 * 1000\n\n/** Debounce delay for registry reload in milliseconds */\nconst RELOAD_DEBOUNCE_MS = 500\n\n/** Registry watcher restart initial delay in milliseconds */\nconst WATCHER_RESTART_INITIAL_DELAY_MS = 1000\n/** Registry watcher restart max delay in milliseconds */\nconst WATCHER_RESTART_MAX_DELAY_MS = 60 * 1000\n/** Session refresh base interval in milliseconds. */\nconst SESSION_REFRESH_BASE_MS = 60 * 60 * 1000\n/** Session refresh jitter window in milliseconds. */\nconst SESSION_REFRESH_JITTER_MS = 20 * 60 * 1000\n\n/** Minimum delay between account initializations in milliseconds. */\nconst INIT_STAGGER_MIN_MS = 2000\n/** Maximum delay between account initializations in milliseconds. */\nconst INIT_STAGGER_MAX_MS = 5000\n/** Random jitter window added to token refresh delay in milliseconds. */\nconst TOKEN_REFRESH_JITTER_MS = 30_000\n\nexport interface AccountRequestCandidate {\n modelId: string\n endpoint: string\n}\n\nexport type { QuotaReservation } from \"./accounts-manager-quota\"\nexport type { AffinityContext } from \"~/lib/account-affinity\"\n\nexport type SelectAccountForRequestFailureReason =\n | \"NO_ACCOUNTS\"\n | \"MODEL_NOT_SUPPORTED\"\n | \"NO_QUOTA\"\n\ntype SelectAccountForRequestSuccess = {\n ok: true\n account: AccountRuntime\n selectedModel: Model\n endpoint: string\n costUnits: number\n reservation?: QuotaReservation\n /** Call after a successful upstream response to persist the affinity mapping. */\n confirmAffinity?: () => void\n /** Whether this selection was served from the affinity cache. */\n affinityHit?: boolean\n /** The cache key used for affinity lookup (e.g. `\"session-1:claude-sonnet-4\"`). */\n affinityCacheKey?: string\n}\n\nexport type SelectAccountForRequestResult =\n | SelectAccountForRequestSuccess\n | {\n ok: false\n reason: SelectAccountForRequestFailureReason\n }\n\n/** Manages multiple GitHub Copilot accounts at runtime. */\nexport class AccountsManager {\n private accounts: Map<string, AccountRuntime> = new Map()\n private accountOrder: Array<string> = []\n private temporaryAccount?: AccountRuntime\n private vsCodeVersion?: string\n private accountAffinityEnabled = true\n private affinityCache = new AccountAffinityCache()\n private loadBalanceCursor = 0\n\n private quotaRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private modelsRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private tokenRefreshEnabledAccounts = new WeakSet<AccountRuntime>()\n private modelsRefreshTimer?: ReturnType<typeof setTimeout>\n private modelsRefreshIntervalMs = 0\n\n // Registry file watcher for hot reload\n private registryWatcher?: fs.FSWatcher\n private reloadDebounceTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n private isReloading = false\n private currentReloadPromise?: Promise<void>\n\n /** Initialize accounts manager (load registry, migrate legacy token). */\n async initialize(vsCodeVersion?: string): Promise<void> {\n this.vsCodeVersion = vsCodeVersion\n\n // Check if we need to migrate legacy token\n const hasReg = await hasRegistry()\n const hasLegacy = await hasLegacyToken()\n\n if (!hasReg && hasLegacy) {\n await this.migrateLegacyToken()\n }\n\n // Load accounts from registry\n const accountMetas = await listAccountsFromRegistry()\n\n for (const meta of accountMetas) {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping`)\n continue\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n accountLogin: meta.id,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n this.accounts.set(meta.id, runtime)\n this.accountOrder.push(meta.id)\n }\n\n // Initialize Copilot tokens for all accounts (staggered to avoid burst traffic)\n let isFirstAccount = true\n for (const account of this.accounts.values()) {\n if (!isFirstAccount) {\n const staggerDelay =\n INIT_STAGGER_MIN_MS\n + Math.floor(\n Math.random() * (INIT_STAGGER_MAX_MS - INIT_STAGGER_MIN_MS),\n )\n consola.debug(\n `Staggering initialization of account ${account.id} by ${staggerDelay}ms`,\n )\n await new Promise((resolve) => setTimeout(resolve, staggerDelay))\n }\n isFirstAccount = false\n\n try {\n await this.initializeAccount(account)\n } catch (error) {\n consola.error(`Failed to initialize account ${account.id}:`, error)\n account.failed = true\n account.failureReason = String(error)\n }\n }\n\n consola.info(`Loaded ${this.accounts.size} account(s)`)\n\n // Start watching the registry file for hot reload\n this.startRegistryWatcher()\n }\n\n setAccountAffinityEnabled(enabled: boolean): void {\n this.accountAffinityEnabled = enabled\n if (!enabled) {\n this.affinityCache.clear()\n }\n }\n\n setModelsRefreshIntervalMs(intervalMs: number): void {\n this.modelsRefreshIntervalMs =\n Number.isFinite(intervalMs) && intervalMs > 0 ? intervalMs : 0\n this.scheduleModelsRefresh()\n }\n\n private computeTokenRefreshDelayMs(refreshInSeconds: number): number {\n const baseDelay = Math.max((refreshInSeconds - 60) * 1000, 1000)\n const jitter = Math.floor(Math.random() * TOKEN_REFRESH_JITTER_MS)\n // Ensure the jittered delay doesn't exceed the token's validity window\n const maxSafeDelay = Math.max(refreshInSeconds * 1000 - 1000, 1000)\n return Math.min(baseDelay + jitter, maxSafeDelay)\n }\n\n private computeSessionRefreshDelayMs(): number {\n const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS)\n return SESSION_REFRESH_BASE_MS + randomDelay\n }\n\n private resolveAccountLogin(account: AccountRuntime): string {\n return account.accountLogin ?? account.id\n }\n\n private commitAccountIdentity(\n account: AccountRuntime,\n {\n identityKey,\n login,\n deviceId,\n machineId,\n }: {\n identityKey: string\n login: string\n deviceId: string\n machineId: string\n },\n ): void {\n account.accountLogin = login\n account.identityKey = identityKey\n account.clientDeviceId = deviceId\n account.clientMachineId = machineId\n }\n\n private async applyAccountIdentity(account: AccountRuntime): Promise<void> {\n const login = this.resolveAccountLogin(account)\n const { oauthApp, enterpriseDomain } = getCurrentIdentityEnvironment()\n const identityKey = buildIdentityKey({\n login,\n oauthApp,\n enterpriseDomain,\n })\n const identity = await ensureAccountClientIdentity({\n login,\n oauthApp,\n enterpriseDomain,\n })\n\n this.commitAccountIdentity(account, {\n identityKey,\n login,\n deviceId: identity.deviceId,\n machineId: identity.machineId,\n })\n\n if (!account.clientSessionId) {\n account.clientSessionId = createAccountSessionId()\n consola.debug(\n `Generated VSCode session ID for account ${account.id}: ${account.clientSessionId}`,\n )\n }\n\n this.startSessionRefresh(account)\n }\n\n private shouldContinueTokenRefresh(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n ): boolean {\n return (\n this.tokenRefreshEnabledAccounts.has(account)\n && isAuthSnapshotCurrent(account, snapshot)\n )\n }\n\n private async runTokenRefreshTick(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n refreshInSeconds: number,\n ): Promise<void> {\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n try {\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(ctx)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n const applied = applyTokenRefreshSuccessIfCurrent(\n account,\n snapshot,\n token,\n )\n if (!applied) {\n return\n }\n\n consola.debug(`Refreshed token for account ${account.id}`)\n\n // Schedule next refresh using the new refresh interval.\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refresh_in)\n } catch (error) {\n consola.error(`Failed to refresh token for ${account.id}:`, error)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n applyTokenRefreshFailureIfCurrent(account, snapshot, error)\n\n // Retry using the previous refresh interval (best effort).\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refreshInSeconds)\n }\n }\n\n private finalizeQuotaRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.quotaRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingQuota = false\n account.quotaRefreshPromise = undefined\n this.quotaRefreshSnapshotByAccount.delete(account)\n }\n\n /** Initialize a single account. */\n private async initializeAccount(account: AccountRuntime): Promise<void> {\n await this.applyAccountIdentity(account)\n const snapshot = takeAuthSnapshot(account)\n\n try {\n // Get Copilot token\n const tokenCtx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(tokenCtx)\n\n if (!applyCopilotTokenIfCurrent(account, snapshot, token)) {\n return\n }\n\n // Resolve the account-specific Copilot endpoint before the first models fetch.\n await this.refreshQuota(account)\n\n // Start token refresh timer\n this.startTokenRefresh(account, refresh_in)\n\n // Get models\n const modelsCtx = toAccountContextFromSnapshot(account, snapshot, token)\n const models = await getModels(modelsCtx)\n\n if (!applyModelsIfCurrent(account, snapshot, models)) {\n return\n }\n account.lastModelsFetch = Date.now()\n\n consola.debug(`Account ${account.id} initialized`)\n } catch (error) {\n // Ignore stale results if registry hot reload changed auth.\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return\n }\n\n throw error\n }\n }\n\n /** Migrate legacy github_token to the new multi-account system. */\n private async migrateLegacyToken(): Promise<void> {\n const token = await readLegacyToken()\n if (!token) return\n\n try {\n // Get user info to determine the account ID\n const user = await getGitHubUser({\n githubToken: token,\n accountType: \"individual\",\n })\n const id = user.login\n\n // Save token to new location\n await saveAccountToken(id, token)\n\n // Add to registry\n await addAccountToRegistry({\n id,\n accountType: \"individual\",\n addedAt: Date.now(),\n })\n\n consola.info(`Migrated legacy token to account: ${id}`)\n } catch (error) {\n consola.error(\"Failed to migrate legacy token:\", error)\n }\n }\n\n /** Start token refresh timer for an account. */\n private startTokenRefresh(\n account: AccountRuntime,\n refreshInSeconds: number,\n ): void {\n // Stop existing timer if any\n this.stopTokenRefresh(account)\n\n this.tokenRefreshEnabledAccounts.add(account)\n\n const snapshot = takeAuthSnapshot(account)\n const delayMs = this.computeTokenRefreshDelayMs(refreshInSeconds)\n\n account.refreshTimer = setTimeout(() => {\n void this.runTokenRefreshTick(account, snapshot, refreshInSeconds)\n }, delayMs)\n }\n\n /** Stop token refresh timer for an account. */\n private stopTokenRefresh(account: AccountRuntime): void {\n this.tokenRefreshEnabledAccounts.delete(account)\n\n if (account.refreshTimer) {\n clearTimeout(account.refreshTimer)\n account.refreshTimer = undefined\n }\n }\n\n /** Stop all token refresh timers. */\n private stopAllTokenRefresh(): void {\n for (const account of this.accounts.values()) {\n this.stopTokenRefresh(account)\n }\n if (this.temporaryAccount) {\n this.stopTokenRefresh(this.temporaryAccount)\n }\n }\n\n private startSessionRefresh(account: AccountRuntime): void {\n this.stopSessionRefresh(account)\n\n const delayMs = this.computeSessionRefreshDelayMs()\n consola.debug(\n `Scheduling next VSCode session ID refresh for ${account.id} in ${Math.round(\n delayMs / 1000,\n )} seconds`,\n )\n\n account.sessionRefreshTimer = setTimeout(() => {\n try {\n account.clientSessionId = createAccountSessionId()\n consola.debug(\n `Refreshed VSCode session ID for account ${account.id}: ${account.clientSessionId}`,\n )\n } catch (error) {\n consola.error(\n `Failed to refresh VSCode session ID for ${account.id}, rescheduling...`,\n error,\n )\n } finally {\n this.startSessionRefresh(account)\n }\n }, delayMs)\n }\n\n private stopSessionRefresh(account: AccountRuntime): void {\n if (account.sessionRefreshTimer) {\n clearTimeout(account.sessionRefreshTimer)\n account.sessionRefreshTimer = undefined\n }\n }\n\n private stopAllSessionRefresh(): void {\n for (const account of this.accounts.values()) {\n this.stopSessionRefresh(account)\n }\n\n if (this.temporaryAccount) {\n this.stopSessionRefresh(this.temporaryAccount)\n }\n }\n\n private scheduleModelsRefresh(): void {\n this.stopModelsRefresh()\n\n if (!this.modelsRefreshIntervalMs || this.modelsRefreshIntervalMs <= 0) {\n return\n }\n\n this.modelsRefreshTimer = setTimeout(() => {\n void this.runModelsRefreshTick()\n }, this.modelsRefreshIntervalMs)\n }\n\n private stopModelsRefresh(): void {\n if (this.modelsRefreshTimer) {\n clearTimeout(this.modelsRefreshTimer)\n this.modelsRefreshTimer = undefined\n }\n }\n\n private async runModelsRefreshTick(): Promise<void> {\n try {\n await this.refreshAllModels()\n } catch (error) {\n consola.error(\"Failed to refresh models:\", error)\n } finally {\n this.scheduleModelsRefresh()\n }\n }\n\n private finalizeModelsRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.modelsRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingModels = false\n account.modelsRefreshPromise = undefined\n this.modelsRefreshSnapshotByAccount.delete(account)\n }\n\n private async refreshModels(account: AccountRuntime): Promise<void> {\n if (!account.copilotToken) {\n consola.debug(\n `Skip model refresh for ${account.id}: missing Copilot token`,\n )\n return\n }\n\n const snapshot = takeAuthSnapshot(account)\n\n if (account.modelsRefreshPromise) {\n const existingSnapshot = this.modelsRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.modelsRefreshPromise\n return\n }\n }\n\n account.isRefreshingModels = true\n\n const ctx = toAccountContextFromSnapshot(\n account,\n snapshot,\n account.copilotToken,\n )\n\n const promise = (async () => {\n try {\n const models = await getModels(ctx)\n const applied = applyModelsIfCurrent(account, snapshot, models)\n if (applied) {\n account.lastModelsFetch = Date.now()\n }\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh models for ${account.id}:`, error)\n }\n })()\n\n account.modelsRefreshPromise = promise\n this.modelsRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeModelsRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n private async refreshAllModels(): Promise<void> {\n const accounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n accounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n accounts.push(account)\n }\n }\n\n if (accounts.length === 0) {\n return\n }\n\n await Promise.allSettled(\n accounts.map((account) => this.refreshModels(account)),\n )\n }\n\n /** Refresh quota information for an account. */\n async refreshQuota(account: AccountRuntime): Promise<void> {\n const snapshot = takeAuthSnapshot(account)\n\n if (account.quotaRefreshPromise) {\n const existingSnapshot = this.quotaRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.quotaRefreshPromise\n return\n }\n }\n\n account.isRefreshingQuota = true\n\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const promise = (async () => {\n try {\n const usage = await getCopilotUsage(ctx)\n const premium = usage.quota_snapshots.premium_interactions\n applyQuotaRefreshSuccessIfCurrent(account, snapshot, {\n premium,\n copilotApiUrl: usage.endpoints.api,\n })\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh quota for ${account.id}:`, error)\n // Don't mark as failed for non-401 quota refresh errors\n }\n })()\n\n account.quotaRefreshPromise = promise\n this.quotaRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeQuotaRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n /** Check if quota cache is expired. */\n private isQuotaCacheExpired(account: AccountRuntime): boolean {\n if (!account.lastQuotaFetch) return true\n return Date.now() - account.lastQuotaFetch > QUOTA_CACHE_TTL\n }\n\n private isAccountFailed(account: AccountRuntime): boolean {\n return account.failed === true\n }\n\n private useOverageFallback(fallback: {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }): SelectAccountForRequestSuccess {\n const reservation = reservePremiumUnits(\n fallback.account,\n fallback.costUnits,\n )\n return {\n ok: true,\n account: fallback.account,\n selectedModel: fallback.model,\n endpoint: fallback.endpoint,\n costUnits: fallback.costUnits,\n reservation,\n }\n }\n\n private isModelSupportedForEndpoint(model: Model, endpoint: string): boolean {\n if (endpoint === \"/responses\") {\n return model.supported_endpoints?.includes(endpoint) ?? false\n }\n\n const supported = model.supported_endpoints\n if (!supported) {\n return true\n }\n\n return supported.includes(endpoint)\n }\n\n private pickSupportedCandidate(\n account: AccountRuntime,\n candidates: Array<AccountRequestCandidate>,\n ): { candidate: AccountRequestCandidate; model: Model } | null {\n const models = account.models?.data\n if (!models) {\n return null\n }\n\n for (const candidate of candidates) {\n const model = models.find((m) => m.id === candidate.modelId)\n if (!model) {\n continue\n }\n\n if (!this.isModelSupportedForEndpoint(model, candidate.endpoint)) {\n continue\n }\n\n return { candidate, model }\n }\n\n return null\n }\n\n private async selectAccountForCandidates(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n if (orderedAccounts.length === 0) {\n return { ok: false, reason: \"NO_ACCOUNTS\" }\n }\n\n let supportedCandidateFound = false\n let overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined\n\n for (const account of orderedAccounts) {\n if (this.isAccountFailed(account)) {\n continue\n }\n\n const supported = this.pickSupportedCandidate(account, candidates)\n if (!supported) {\n continue\n }\n\n supportedCandidateFound = true\n\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n if (costUnits <= 0) {\n // Free model: sequential routing (first available account).\n // When account affinity is enabled, the caller (selectAccountForRequest)\n // handles cache lookup/write-back; this path only runs on cache miss.\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n if (!account.unlimited && this.isQuotaCacheExpired(account)) {\n await this.refreshQuota(account)\n }\n\n if (this.isAccountFailed(account)) {\n continue\n }\n\n if (account.unlimited) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n // Check if account has sufficient quota.\n const effectiveRemaining = getEffectivePremiumRemaining(account)\n if (effectiveRemaining !== undefined && effectiveRemaining < costUnits) {\n // Insufficient quota - store as overage fallback if permitted, but keep\n // looking for accounts with quota to avoid unnecessary overage charges.\n if (account.overagePermitted && !overageFallback) {\n overageFallback = {\n account,\n model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n continue\n }\n\n const reservation = reservePremiumUnits(account, costUnits)\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n reservation,\n }\n }\n\n if (!supportedCandidateFound) {\n return { ok: false, reason: \"MODEL_NOT_SUPPORTED\" }\n }\n\n // No account with quota found - use overage fallback if available.\n return overageFallback ?\n this.useOverageFallback(overageFallback)\n : { ok: false, reason: \"NO_QUOTA\" }\n }\n\n /**\n * Try to use a preferred (affinity) account for the request.\n * Returns a successful selection if the account is usable; null otherwise.\n */\n\n private async tryAffinityAccount(\n preferredAccountId: string,\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestSuccess | null> {\n const account = isAffinityAccountUsable(preferredAccountId, orderedAccounts)\n if (!account) {\n return null\n }\n\n // Try original candidates first, then alias-resolved candidates.\n const supported =\n this.pickSupportedCandidate(account, candidates)\n ?? this.pickAliasFallbackCandidate(account, candidates)\n if (!supported) {\n return null\n }\n\n return this.validateAffinityQuota(account, supported)\n }\n\n /**\n * Resolve model aliases and try to pick a supported candidate.\n * Returns null if no alias differs or the account doesn't support the alias.\n */\n private pickAliasFallbackCandidate(\n account: AccountRuntime,\n candidates: Array<AccountRequestCandidate>,\n ): { candidate: AccountRequestCandidate; model: Model } | null {\n const aliasCandidates = candidates.map((candidate) => {\n const modelId = resolveModelAlias(candidate.modelId)\n if (modelId === candidate.modelId) return candidate\n return { ...candidate, modelId }\n })\n const aliasChanged = aliasCandidates.some(\n (candidate, index) => candidate.modelId !== candidates[index].modelId,\n )\n if (!aliasChanged) return null\n\n return this.pickSupportedCandidate(account, aliasCandidates)\n }\n\n /**\n * Validate quota for an affinity candidate. Free models pass immediately;\n * premium models go through quota refresh / reservation.\n */\n private async validateAffinityQuota(\n account: AccountRuntime,\n supported: { candidate: AccountRequestCandidate; model: Model },\n ): Promise<SelectAccountForRequestSuccess | null> {\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n // Free model — no quota checks needed.\n if (costUnits <= 0) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n // Premium model — validate quota.\n if (!account.unlimited && this.isQuotaCacheExpired(account)) {\n await this.refreshQuota(account)\n }\n\n if (this.isAccountFailed(account)) {\n return null\n }\n\n if (account.unlimited) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n const effectiveRemaining = getEffectivePremiumRemaining(account)\n if (effectiveRemaining !== undefined && effectiveRemaining < costUnits) {\n return null\n }\n\n const reservation = reservePremiumUnits(account, costUnits)\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n reservation,\n }\n }\n\n /**\n * Select an available account for a specific request (model + endpoint).\n * When account affinity is enabled, routes to the previously successful account\n * for the same affinity key + model combination.\n * Uses reservation to avoid oversubscribing premium quota under concurrency.\n */\n async selectAccountForRequest(\n candidates: Array<AccountRequestCandidate>,\n affinityContext?: AffinityContext,\n ): Promise<SelectAccountForRequestResult> {\n if (candidates.length === 0) {\n throw new Error(\"selectAccountForRequest requires at least one candidate\")\n }\n\n const orderedAccounts = [\n ...(this.temporaryAccount ? [this.temporaryAccount] : []),\n ...this.accountOrder\n .map((id) => this.accounts.get(id))\n .filter((account): account is AccountRuntime => account !== undefined),\n ]\n\n // Resolve the affinity key once — reused for both lookup and write-back.\n const affinityKey =\n this.accountAffinityEnabled && affinityContext ?\n extractAffinityKey(affinityContext)\n : undefined\n\n const modelKey = candidates[0].modelId\n const cacheKey =\n affinityKey ? buildAffinityCacheKey(affinityKey, modelKey) : undefined\n\n // Step 1: Try the preferred (affinity) account.\n if (cacheKey) {\n const preferredId = this.affinityCache.get(cacheKey)\n if (preferredId) {\n const affinityResult = await this.tryAffinityAccount(\n preferredId,\n orderedAccounts,\n candidates,\n )\n if (affinityResult) {\n affinityResult.affinityHit = true\n affinityResult.affinityCacheKey = cacheKey\n affinityResult.confirmAffinity = () => {\n if (!this.accountAffinityEnabled) return\n this.affinityCache.set(cacheKey, affinityResult.account.id)\n }\n return affinityResult\n }\n }\n }\n\n // Step 2: Cache miss — rotate accounts for load balancing when affinity is enabled.\n const accountsForSelection =\n this.accountAffinityEnabled && orderedAccounts.length > 1 ?\n this.rotateAccounts(orderedAccounts)\n : orderedAccounts\n\n const result = await this.selectWithAliasFallback(\n accountsForSelection,\n candidates,\n )\n\n if (result.ok) {\n this.loadBalanceCursor++\n }\n\n // Attach confirmAffinity callback so the handler can persist the mapping on success.\n if (result.ok && cacheKey) {\n const successResult = result\n successResult.confirmAffinity = () => {\n if (!this.accountAffinityEnabled) return\n this.affinityCache.set(cacheKey, successResult.account.id)\n }\n }\n\n return result\n }\n\n /**\n * Rotate the accounts array by the current load-balance cursor for round-robin distribution.\n * This ensures cache-miss requests are spread across accounts instead of always hitting the first.\n */\n private rotateAccounts(\n accounts: Array<AccountRuntime>,\n ): Array<AccountRuntime> {\n const start = this.loadBalanceCursor % accounts.length\n if (start === 0) return accounts\n return [...accounts.slice(start), ...accounts.slice(0, start)]\n }\n\n /**\n * Normal account selection with alias fallback.\n * Extracted to keep selectAccountForRequest readable after adding affinity logic.\n */\n private async selectWithAliasFallback(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n const primary = await this.selectAccountForCandidates(\n orderedAccounts,\n candidates,\n )\n if (primary.ok || primary.reason !== \"MODEL_NOT_SUPPORTED\") {\n return primary\n }\n\n const aliasCandidates = candidates.map((candidate) => {\n const modelId = resolveModelAlias(candidate.modelId)\n if (modelId === candidate.modelId) return candidate\n return { ...candidate, modelId }\n })\n const aliasChanged = aliasCandidates.some(\n (candidate, index) => candidate.modelId !== candidates[index].modelId,\n )\n if (!aliasChanged) {\n return primary\n }\n\n return this.selectAccountForCandidates(orderedAccounts, aliasCandidates)\n }\n\n /**\n * Finalize quota after a request completes.\n * This releases any in-flight reservation and refreshes the actual quota from the API.\n */\n async finalizeQuota(\n account: AccountRuntime,\n reservation?: QuotaReservation,\n ): Promise<void> {\n releasePremiumReservation(account, reservation)\n\n try {\n await this.refreshQuota(account)\n } catch (error) {\n consola.debug(`Failed to finalize quota for ${account.id}:`, error)\n }\n }\n\n /**\n * Mark an account as failed.\n */\n markAccountFailed(id: string, reason: string): void {\n const account = this.accounts.get(id)\n if (account) {\n setAccountFailedState(account, reason)\n return\n }\n\n if (this.temporaryAccount && this.temporaryAccount.id === id) {\n setAccountFailedState(this.temporaryAccount, reason)\n }\n }\n\n /**\n * Get status of all accounts.\n */\n getAccountStatus(): Array<{\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n }> {\n const statuses: Array<{\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n }> = []\n\n if (this.temporaryAccount) {\n statuses.push({\n id: \"(temporary)\",\n entitlement: this.temporaryAccount.premiumEntitlement,\n remaining: this.temporaryAccount.premiumRemaining,\n unlimited: this.temporaryAccount.unlimited,\n overagePermitted: this.temporaryAccount.overagePermitted,\n failed: this.temporaryAccount.failed,\n failureReason: this.temporaryAccount.failureReason,\n })\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n statuses.push({\n id: account.id,\n entitlement: account.premiumEntitlement,\n remaining: account.premiumRemaining,\n unlimited: account.unlimited,\n overagePermitted: account.overagePermitted,\n failed: account.failed,\n failureReason: account.failureReason,\n })\n }\n }\n\n return statuses\n }\n\n /**\n * Set a temporary account from a GitHub token (--github-token).\n * This account takes priority over registered accounts.\n */\n async setTemporaryAccount(\n githubToken: string,\n accountType: AccountType,\n ): Promise<void> {\n const user = await getGitHubUser({ githubToken, accountType })\n\n if (this.temporaryAccount) {\n this.stopTokenRefresh(this.temporaryAccount)\n this.stopSessionRefresh(this.temporaryAccount)\n }\n\n const runtime: AccountRuntime = {\n id: \"(temporary)\",\n accountLogin: user.login,\n accountType,\n addedAt: Date.now(),\n githubToken,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.temporaryAccount = runtime\n consola.info(\"Temporary account initialized\")\n } catch (error) {\n consola.error(\"Failed to initialize temporary account:\", error)\n throw error\n }\n }\n\n /**\n * Check if any accounts are available.\n */\n hasAccounts(): boolean {\n return this.accounts.size > 0 || this.temporaryAccount !== undefined\n }\n\n /**\n * Get the first available account's models.\n * Used for caching models in legacy compatibility mode.\n */\n getFirstAccountModels(): AccountRuntime[\"models\"] {\n if (this.temporaryAccount?.models) {\n return this.temporaryAccount.models\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account?.models) {\n return account.models\n }\n }\n\n return undefined\n }\n\n /**\n * Get account context by index.\n * Index 0 is the temporary account (if exists), otherwise the first registered account.\n * Returns null if index is out of bounds.\n */\n getAccountContextByIndex(index: number): AccountContext | null {\n // Build the same order as getAccountStatus()\n const allAccounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n allAccounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n allAccounts.push(account)\n }\n }\n\n if (index < 0 || index >= allAccounts.length) {\n return null\n }\n\n return this.toAccountContext(allAccounts[index])\n }\n\n /**\n * Get the total number of accounts (including temporary).\n */\n getAccountCount(): number {\n return (this.temporaryAccount ? 1 : 0) + this.accountOrder.length\n }\n\n /**\n * Convert AccountRuntime to AccountContext for service calls.\n */\n private toAccountContext(account: AccountRuntime): AccountContext {\n return {\n accountLogin: account.accountLogin,\n githubToken: account.githubToken,\n copilotToken: account.copilotToken,\n ...(account.copilotApiUrl !== undefined ?\n { copilotApiUrl: account.copilotApiUrl }\n : {}),\n accountType: account.accountType,\n vsCodeVersion: account.vsCodeVersion,\n clientDeviceId: account.clientDeviceId,\n clientMachineId: account.clientMachineId,\n clientSessionId: account.clientSessionId,\n }\n }\n\n /**\n * Start watching the registry file for changes.\n * Enables hot reload of accounts when the file is modified.\n */\n private startRegistryWatcher(): void {\n // Stop existing watcher if any\n this.stopRegistryWatcher()\n\n try {\n this.registryWatcher = fs.watch(\n PATHS.ACCOUNTS_REGISTRY_PATH,\n (eventType) => {\n // Only react to 'change' events (file content modified)\n if (eventType === \"change\") {\n this.scheduleReload()\n }\n },\n )\n\n // Successful start: reset restart backoff.\n this.registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n\n // Handle watcher errors (e.g., file deleted)\n this.registryWatcher.on(\"error\", (error) => {\n consola.debug(\"Registry watcher error:\", error)\n\n const delayMs = this.registryWatcherRestartDelayMs\n this.registryWatcherRestartDelayMs = Math.min(\n this.registryWatcherRestartDelayMs * 2,\n WATCHER_RESTART_MAX_DELAY_MS,\n )\n\n // Close broken watcher to avoid repeated error events.\n this.stopRegistryWatcher()\n\n // Try to restart the watcher after a delay (with backoff)\n this.registryWatcherRestartTimer = setTimeout(() => {\n this.registryWatcherRestartTimer = undefined\n this.startRegistryWatcher()\n }, delayMs)\n\n consola.debug(`Restarting registry watcher in ${delayMs}ms`)\n })\n\n consola.debug(\"Started registry file watcher\")\n } catch (error) {\n consola.warn(\"Failed to start registry watcher:\", error)\n }\n }\n\n /**\n * Immediately reload the registry, bypassing the debounce delay.\n * If a reload is already running, waits for it to complete and then\n * runs another reload to ensure the latest changes are captured.\n */\n async reloadRegistryNow(): Promise<void> {\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n this.reloadDebounceTimer = undefined\n }\n // Wait for any in-progress reload before starting a fresh one\n if (this.currentReloadPromise) {\n await this.currentReloadPromise\n }\n await this.reloadRegistry()\n }\n\n /**\n * Schedule a registry reload with debouncing.\n */\n private scheduleReload(): void {\n // Clear existing timer\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n }\n\n // Schedule reload after debounce delay\n this.reloadDebounceTimer = setTimeout(() => {\n void this.reloadRegistry()\n }, RELOAD_DEBOUNCE_MS)\n }\n\n /**\n * Reload the registry and perform incremental updates.\n * Adds new accounts, removes deleted ones, and reinitializes existing accounts\n * when token/accountType changes.\n */\n private async reloadRegistry(): Promise<void> {\n // Prevent concurrent reloads\n if (this.isReloading) {\n return\n }\n this.isReloading = true\n\n this.currentReloadPromise = (async () => {\n try {\n const newMetas = await listAccountsFromRegistry()\n const newIds = new Set(newMetas.map((m) => m.id))\n const currentIds = new Set(this.accountOrder)\n\n // Track changes for logging\n const added: Array<string> = []\n const removed: Array<string> = []\n const updated: Array<string> = []\n\n this.removeDeletedAccounts(currentIds, newIds, removed)\n\n // Add new accounts (newIds - currentIds)\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n await this.addNewAccount(meta, added)\n }\n }\n\n // Update existing accounts when meta/token changed\n await this.reinitializeUpdatedAccounts(newMetas, currentIds, updated)\n\n // Update accountOrder to reflect new order\n this.accountOrder = newMetas\n .map((m) => m.id)\n .filter((id) => this.accounts.has(id))\n\n // Reset load-balance cursor on account list/order changes.\n this.loadBalanceCursor = 0\n\n this.logRegistryReloadChanges(added, removed, updated)\n } catch (error) {\n consola.error(\"Failed to reload registry:\", error)\n this.shutdown()\n process.exit(1)\n } finally {\n this.isReloading = false\n this.currentReloadPromise = undefined\n }\n })()\n\n await this.currentReloadPromise\n }\n\n private removeDeletedAccounts(\n currentIds: Set<string>,\n newIds: Set<string>,\n removed: Array<string>,\n ): void {\n for (const id of currentIds) {\n if (!newIds.has(id)) {\n const account = this.accounts.get(id)\n if (!account) {\n continue\n }\n\n this.stopTokenRefresh(account)\n this.stopSessionRefresh(account)\n this.accounts.delete(id)\n removed.push(id)\n }\n }\n }\n\n private async reinitializeUpdatedAccounts(\n newMetas: Array<{ id: string; accountType: AccountType; addedAt: number }>,\n currentIds: Set<string>,\n updated: Array<string>,\n ): Promise<void> {\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n continue\n }\n\n const account = this.accounts.get(meta.id)\n if (!account) {\n continue\n }\n\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping update`)\n continue\n }\n\n const accountTypeChanged = account.accountType !== meta.accountType\n const tokenChanged = account.githubToken !== token\n const addedAtChanged = account.addedAt !== meta.addedAt\n\n // Keep runtime metadata in sync with the registry.\n if (accountTypeChanged) {\n account.accountType = meta.accountType\n }\n if (addedAtChanged) {\n account.addedAt = meta.addedAt\n }\n account.accountLogin = meta.id\n if (tokenChanged) {\n account.githubToken = token\n }\n\n if (!accountTypeChanged && !tokenChanged) {\n continue\n }\n\n try {\n await this.initializeAccount(account)\n updated.push(meta.id)\n } catch (error) {\n consola.error(\n `Failed to reinitialize account ${meta.id} after update:`,\n error,\n )\n account.failed = true\n account.failureReason = String(error)\n updated.push(`${meta.id} (failed)`)\n }\n }\n }\n\n private logRegistryReloadChanges(\n added: Array<string>,\n removed: Array<string>,\n updated: Array<string>,\n ): void {\n if (added.length === 0 && removed.length === 0 && updated.length === 0) {\n return\n }\n\n const changes: Array<string> = []\n if (added.length > 0) {\n changes.push(`added: ${added.join(\", \")}`)\n }\n if (removed.length > 0) {\n changes.push(`removed: ${removed.join(\", \")}`)\n }\n if (updated.length > 0) {\n changes.push(`updated: ${updated.join(\", \")}`)\n }\n\n consola.info(\n `Registry reloaded (${changes.join(\"; \")}). Total: ${this.accounts.size} account(s)`,\n )\n }\n\n /**\n * Helper to add a new account during reload.\n */\n private async addNewAccount(\n meta: { id: string; accountType: AccountType; addedAt: number },\n added: Array<string>,\n ): Promise<void> {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for new account ${meta.id}, skipping`)\n return\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n accountLogin: meta.id,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.accounts.set(meta.id, runtime)\n added.push(meta.id)\n } catch (error) {\n consola.error(`Failed to initialize new account ${meta.id}:`, error)\n runtime.failed = true\n runtime.failureReason = String(error)\n this.accounts.set(meta.id, runtime)\n added.push(`${meta.id} (failed)`)\n }\n }\n\n /**\n * Stop the registry file watcher.\n */\n private stopRegistryWatcher(): void {\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n this.reloadDebounceTimer = undefined\n }\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n if (this.registryWatcher) {\n this.registryWatcher.close()\n this.registryWatcher = undefined\n }\n }\n\n /**\n * Shutdown the manager and clean up resources.\n */\n shutdown(): void {\n this.stopRegistryWatcher()\n this.stopAllTokenRefresh()\n this.stopAllSessionRefresh()\n this.stopModelsRefresh()\n this.affinityCache.clear()\n this.loadBalanceCursor = 0\n this.accounts.clear()\n this.accountOrder = []\n this.temporaryAccount = undefined\n }\n}\n\n/** Singleton instance of AccountsManager */\nexport const accountsManager = new AccountsManager()\n"],"mappings":"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"}