opencode-anthropic-multi-account 0.2.24 → 0.2.25

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/index.js CHANGED
@@ -10,11 +10,11 @@ import {
10
10
  cc_derived_defaults_default,
11
11
  checkCCCompat,
12
12
  createMinimalClient,
13
+ data_default,
13
14
  debugLog,
14
15
  detectCliVersion,
15
16
  detectDrift,
16
17
  detectOAuthConfig,
17
- fingerprint_data_default,
18
18
  formatWaitTime,
19
19
  getAccountLabel,
20
20
  getConfig,
@@ -25,11 +25,11 @@ import {
25
25
  showToast,
26
26
  sleep,
27
27
  updateConfigField
28
- } from "./chunk-2SN3UVSM.js";
29
- import "./chunk-RAX4SFCO.js";
28
+ } from "./chunk-II7N6KHL.js";
29
+ import "./chunk-3CTML5AX.js";
30
30
 
31
31
  // src/index.ts
32
- import { tool } from "@opencode-ai/plugin";
32
+ import { tool } from "@opencode-ai/plugin/tool";
33
33
  import {
34
34
  CascadeStateManager,
35
35
  loadPoolChainConfig,
@@ -37,10 +37,10 @@ import {
37
37
  PoolManager
38
38
  } from "opencode-multi-account-core";
39
39
 
40
- // src/account-manager.ts
40
+ // src/accounts/manager.ts
41
41
  import { createAccountManagerForProvider } from "opencode-multi-account-core";
42
42
 
43
- // src/claims.ts
43
+ // src/accounts/claims.ts
44
44
  import { createClaimsManager } from "opencode-multi-account-core";
45
45
  var claimsManager = createClaimsManager(CLAIMS_FILENAME);
46
46
  var {
@@ -50,12 +50,12 @@ var {
50
50
  writeClaim
51
51
  } = claimsManager;
52
52
 
53
- // src/anthropic-oauth.ts
53
+ // src/oauth/anthropic-oauth.ts
54
54
  import { exec } from "child_process";
55
55
  import * as v3 from "valibot";
56
56
 
57
- // src/cc-derived-profile.ts
58
- var bundledTemplate = fingerprint_data_default;
57
+ // src/claude-code/derived-profile.ts
58
+ var bundledTemplate = data_default;
59
59
  var derivedDefaults = cc_derived_defaults_default;
60
60
  var DEFAULT_BASE_API_URL = derivedDefaults.request?.baseApiUrl || "https://api.anthropic.com";
61
61
  var DEFAULT_ANTHROPIC_VERSION = bundledTemplate.header_values?.["anthropic-version"] || derivedDefaults.request?.anthropicVersion || "2023-06-01";
@@ -90,7 +90,7 @@ async function loadCCDerivedAuthProfile() {
90
90
  };
91
91
  }
92
92
 
93
- // src/oauth-callback-server.ts
93
+ // src/oauth/callback-server.ts
94
94
  import { createServer } from "http";
95
95
  var DEFAULT_TIMEOUT_MS = 3e5;
96
96
  var SUCCESS_REDIRECT_URL = "https://platform.claude.com/oauth/code/success?app=claude-code";
@@ -186,7 +186,7 @@ function startCallbackServer(options) {
186
186
  });
187
187
  }
188
188
 
189
- // src/oauth-pkce.ts
189
+ // src/oauth/pkce.ts
190
190
  import { createHash, randomBytes } from "crypto";
191
191
  function base64url(buffer) {
192
192
  return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
@@ -200,7 +200,7 @@ function generateState() {
200
200
  return base64url(randomBytes(32));
201
201
  }
202
202
 
203
- // src/token-node-request.ts
203
+ // src/oauth/token-node-request.ts
204
204
  import * as childProcess from "child_process";
205
205
  function buildNodeTokenRequestScript() {
206
206
  return `
@@ -259,7 +259,7 @@ request.end();
259
259
  async function defaultRunNodeTokenRequest(options) {
260
260
  const script = buildNodeTokenRequestScript();
261
261
  const contentType = options.contentType ?? "application/json";
262
- return await new Promise((resolve, reject) => {
262
+ return new Promise((resolve, reject) => {
263
263
  childProcess.execFile(
264
264
  options.executable,
265
265
  ["-e", script],
@@ -292,13 +292,13 @@ async function defaultRunNodeTokenRequest(options) {
292
292
  }
293
293
  var nodeTokenRequestRunner = defaultRunNodeTokenRequest;
294
294
  async function runNodeTokenRequest(options) {
295
- return await nodeTokenRequestRunner(options);
295
+ return nodeTokenRequestRunner(options);
296
296
  }
297
297
 
298
298
  // src/usage.ts
299
299
  import * as v2 from "valibot";
300
300
 
301
- // src/types.ts
301
+ // src/shared/types.ts
302
302
  import * as v from "valibot";
303
303
  var OAuthCredentialsSchema = v.object({
304
304
  type: v.literal("oauth"),
@@ -461,7 +461,7 @@ function getPlanLabel(account) {
461
461
  return PLAN_LABELS[account.planTier] ?? account.planTier.charAt(0).toUpperCase() + account.planTier.slice(1);
462
462
  }
463
463
 
464
- // src/anthropic-oauth.ts
464
+ // src/oauth/anthropic-oauth.ts
465
465
  var TOKEN_REQUEST_EXECUTABLE = process.env.OPENCODE_REFRESH_NODE_EXECUTABLE || "node";
466
466
  var browserExec = (command, callback) => {
467
467
  exec(command, callback);
@@ -509,6 +509,18 @@ function openBrowser(url) {
509
509
  } catch {
510
510
  }
511
511
  }
512
+ function buildAuthorizeUrl(params) {
513
+ const url = new URL(params.authorizeUrl);
514
+ url.searchParams.set("code", "true");
515
+ url.searchParams.set("client_id", params.clientId);
516
+ url.searchParams.set("response_type", "code");
517
+ url.searchParams.set("redirect_uri", params.redirectUri);
518
+ url.searchParams.set("scope", params.scopes);
519
+ url.searchParams.set("code_challenge", params.codeChallenge);
520
+ url.searchParams.set("code_challenge_method", "S256");
521
+ url.searchParams.set("state", params.state);
522
+ return url.toString();
523
+ }
512
524
  async function postTokenEndpoint(contentType, body, timeoutMs = TOKEN_REFRESH_TIMEOUT_MS, userAgent) {
513
525
  const derivedProfile = await loadCCDerivedAuthProfile();
514
526
  const oauthConfig = derivedProfile.oauthConfig;
@@ -561,16 +573,14 @@ async function loginWithOAuth(callbacks) {
561
573
  const { port, waitForCode, stop } = await callbackServerStarter({ expectedState: state });
562
574
  const redirectUri = `http://localhost:${port}/callback`;
563
575
  try {
564
- const authorizeUrl = `${cfg.authorizeUrl}?${new URLSearchParams({
565
- code: "true",
566
- client_id: cfg.clientId,
567
- response_type: "code",
568
- redirect_uri: redirectUri,
569
- scope: cfg.scopes,
570
- code_challenge: codeChallenge,
571
- code_challenge_method: "S256",
576
+ const authorizeUrl = buildAuthorizeUrl({
577
+ authorizeUrl: cfg.authorizeUrl,
578
+ clientId: cfg.clientId,
579
+ scopes: cfg.scopes,
580
+ redirectUri,
581
+ codeChallenge,
572
582
  state
573
- }).toString()}`;
583
+ });
574
584
  callbacks.onAuth({
575
585
  url: authorizeUrl,
576
586
  instructions: "Complete authorization in your browser."
@@ -636,7 +646,7 @@ async function refreshWithOAuth(currentRefreshToken) {
636
646
  return patch;
637
647
  }
638
648
 
639
- // src/token.ts
649
+ // src/oauth/token.ts
640
650
  var PERMANENT_FAILURE_MESSAGE_PATTERNS = [
641
651
  /\binvalid_grant\b/i,
642
652
  /\binvalid_scope\b/i,
@@ -659,8 +669,7 @@ async function refreshToken(currentRefreshToken, accountId, client) {
659
669
  return { ok: true, patch };
660
670
  } catch (error) {
661
671
  const message = error instanceof Error ? error.message : String(error);
662
- const hasPermanentMessage = PERMANENT_FAILURE_MESSAGE_PATTERNS.some((pattern) => pattern.test(message));
663
- const isPermanent = hasPermanentMessage;
672
+ const isPermanent = PERMANENT_FAILURE_MESSAGE_PATTERNS.some((pattern) => pattern.test(message));
664
673
  await client.app.log({
665
674
  body: {
666
675
  service: ANTHROPIC_OAUTH_ADAPTER.serviceLogName,
@@ -679,7 +688,7 @@ async function refreshToken(currentRefreshToken, accountId, client) {
679
688
  return refreshPromise;
680
689
  }
681
690
 
682
- // src/account-manager.ts
691
+ // src/accounts/manager.ts
683
692
  var AccountManager = createAccountManagerForProvider({
684
693
  providerAuthId: "anthropic",
685
694
  getConfig,
@@ -690,10 +699,10 @@ var AccountManager = createAccountManagerForProvider({
690
699
  writeClaim
691
700
  });
692
701
 
693
- // src/executor.ts
702
+ // src/runtime/executor.ts
694
703
  import { createExecutorForProvider as createExecutorForProvider2, getClearedOAuthBody } from "opencode-multi-account-core";
695
704
 
696
- // src/rate-limit.ts
705
+ // src/accounts/rate-limit.ts
697
706
  import { createRateLimitHandlers } from "opencode-multi-account-core";
698
707
  var {
699
708
  fetchUsageLimits,
@@ -708,7 +717,7 @@ var {
708
717
  showToast
709
718
  });
710
719
 
711
- // src/pool-chain-executor.ts
720
+ // src/runtime/pool-chain.ts
712
721
  import { createExecutorForProvider } from "opencode-multi-account-core";
713
722
  function buildCascadePrompt(input, init) {
714
723
  if (typeof init?.body === "string" && init.body.length > 0) {
@@ -793,7 +802,7 @@ async function executeWithPoolChainRotation(manager, runtimeFactory, poolManager
793
802
  }
794
803
  }
795
804
 
796
- // src/executor.ts
805
+ // src/runtime/executor.ts
797
806
  var { executeWithAccountRotation: executeWithCoreAccountRotation } = createExecutorForProvider2("Anthropic", {
798
807
  handleRateLimitResponse: async (manager, client, account, response) => handleRateLimitResponse(
799
808
  manager,
@@ -845,22 +854,22 @@ async function executeWithAccountRotation(manager, runtimeFactory, client, input
845
854
  }
846
855
  }
847
856
 
848
- // src/ui/ansi.ts
857
+ // src/auth-ux/menu/ansi.ts
849
858
  import {
850
859
  ANSI,
851
860
  isTTY,
852
861
  parseKey
853
862
  } from "opencode-multi-account-core";
854
863
 
855
- // src/ui/select.ts
864
+ // src/auth-ux/menu/select.ts
856
865
  import {
857
866
  select
858
867
  } from "opencode-multi-account-core";
859
868
 
860
- // src/ui/confirm.ts
869
+ // src/auth-ux/menu/confirm.ts
861
870
  import { confirm } from "opencode-multi-account-core";
862
871
 
863
- // src/ui/auth-menu.ts
872
+ // src/auth-ux/menu/menu.ts
864
873
  function formatRelativeTime(timestamp) {
865
874
  if (!timestamp) return "never";
866
875
  const days = Math.floor((Date.now() - timestamp) / 864e5);
@@ -904,12 +913,10 @@ function buildAccountMenuItem(account) {
904
913
  const label = getAccountLabel(account);
905
914
  const status = getAccountStatus(account);
906
915
  const badge = STATUS_BADGE[status];
907
- const fullLabel = `${label} ${badge}`;
908
916
  return {
909
- label: fullLabel,
917
+ label: `${label} ${badge}`,
910
918
  hint: account.lastUsed ? `used ${formatRelativeTime(account.lastUsed)}` : "",
911
- value: account,
912
- disabled: false
919
+ value: account
913
920
  };
914
921
  }
915
922
  async function showAuthMenu(accounts) {
@@ -1064,7 +1071,7 @@ function printQuotaError(account, error) {
1064
1071
  `);
1065
1072
  }
1066
1073
 
1067
- // src/account-store.ts
1074
+ // src/accounts/store.ts
1068
1075
  import {
1069
1076
  AccountStore as CoreAccountStore
1070
1077
  } from "opencode-multi-account-core";
@@ -1074,9 +1081,8 @@ var AccountStore = class extends CoreAccountStore {
1074
1081
  }
1075
1082
  };
1076
1083
 
1077
- // src/auth-handler.ts
1084
+ // src/auth-ux/handler.ts
1078
1085
  import { randomUUID } from "crypto";
1079
- import { exec as exec2 } from "child_process";
1080
1086
  function makeFailedFlowResult(message) {
1081
1087
  return {
1082
1088
  url: "",
@@ -1162,7 +1168,7 @@ function wrapCallbackWithManagerSync(result, manager) {
1162
1168
  \u2139\uFE0F Account already exists in multi-auth pool (${countAfter} total).
1163
1169
  `);
1164
1170
  } else {
1165
- await persistFallback(auth);
1171
+ await persistFallback(auth, email);
1166
1172
  console.log("\n\u2705 Account saved.\n");
1167
1173
  }
1168
1174
  }
@@ -1170,12 +1176,13 @@ function wrapCallbackWithManagerSync(result, manager) {
1170
1176
  }
1171
1177
  };
1172
1178
  }
1173
- async function persistFallback(auth) {
1179
+ async function persistFallback(auth, email) {
1174
1180
  try {
1175
1181
  const store = new AccountStore();
1176
1182
  const now2 = Date.now();
1177
1183
  const account = {
1178
1184
  uuid: randomUUID(),
1185
+ email,
1179
1186
  refreshToken: auth.refresh,
1180
1187
  accessToken: auth.access,
1181
1188
  expiresAt: auth.expires,
@@ -1350,7 +1357,7 @@ Retrying authentication for ${label}...
1350
1357
  return { triggerOAuth: false };
1351
1358
  }
1352
1359
 
1353
- // src/proactive-refresh.ts
1360
+ // src/accounts/proactive-refresh.ts
1354
1361
  import { createProactiveRefreshQueueForProvider } from "opencode-multi-account-core";
1355
1362
  var ProactiveRefreshQueue = createProactiveRefreshQueueForProvider({
1356
1363
  providerAuthId: "anthropic",
@@ -1360,13 +1367,13 @@ var ProactiveRefreshQueue = createProactiveRefreshQueueForProvider({
1360
1367
  debugLog
1361
1368
  });
1362
1369
 
1363
- // src/runtime-factory.ts
1370
+ // src/runtime/factory.ts
1364
1371
  import { TokenRefreshError } from "opencode-multi-account-core";
1365
1372
 
1366
- // src/request-transform.ts
1373
+ // src/request/transform.ts
1367
1374
  import { randomUUID as randomUUID4 } from "crypto";
1368
1375
 
1369
- // src/model-config.ts
1376
+ // src/model/config.ts
1370
1377
  function splitBetaFlags(value) {
1371
1378
  return value.split(",").map((entry) => entry.trim()).filter(Boolean);
1372
1379
  }
@@ -1392,7 +1399,7 @@ function getModelOverride(modelId) {
1392
1399
  return null;
1393
1400
  }
1394
1401
 
1395
- // src/betas.ts
1402
+ // src/request/betas.ts
1396
1403
  var LONG_CONTEXT_BETAS = config.longContextBetas;
1397
1404
  var OAUTH_BETA = "oauth-2025-04-20";
1398
1405
  var excludedBetas = /* @__PURE__ */ new Map();
@@ -1449,8 +1456,8 @@ function supports1mContext(modelId) {
1449
1456
  if (!versionMatch) {
1450
1457
  return false;
1451
1458
  }
1452
- const major = Number.parseInt(versionMatch[2] ?? "0", 10);
1453
- const minor = Number.parseInt(versionMatch[3] ?? "0", 10);
1459
+ const major = Number.parseInt(versionMatch[2], 10);
1460
+ const minor = Number.parseInt(versionMatch[3], 10);
1454
1461
  const effectiveMinor = minor > 99 ? 0 : minor;
1455
1462
  return major > 4 || major === 4 && effectiveMinor >= 6;
1456
1463
  }
@@ -1482,7 +1489,7 @@ function getModelBetas(modelId, excluded) {
1482
1489
  return betas.filter((beta) => !excluded.has(beta));
1483
1490
  }
1484
1491
 
1485
- // src/claude-identity.ts
1492
+ // src/claude-code/identity.ts
1486
1493
  import { readFileSync, readdirSync } from "fs";
1487
1494
  import { homedir } from "os";
1488
1495
  import { join } from "path";
@@ -1526,22 +1533,19 @@ function loadClaudeIdentity() {
1526
1533
  if (testOverrideIdentity) {
1527
1534
  return testOverrideIdentity;
1528
1535
  }
1529
- try {
1530
- for (const path of getCandidatePaths()) {
1531
- const identity = parseIdentityFile(path);
1532
- if (identity) {
1533
- return identity;
1534
- }
1536
+ for (const path of getCandidatePaths()) {
1537
+ const identity = parseIdentityFile(path);
1538
+ if (identity) {
1539
+ return identity;
1535
1540
  }
1536
- } catch {
1537
1541
  }
1538
1542
  return EMPTY_IDENTITY;
1539
1543
  }
1540
1544
 
1541
- // src/upstream-request.ts
1545
+ // src/request/upstream-request.ts
1542
1546
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
1543
1547
 
1544
- // src/model-capabilities.ts
1548
+ // src/model/capabilities.ts
1545
1549
  var runtimeModelCapabilities = /* @__PURE__ */ new Map();
1546
1550
  function isRecord(value) {
1547
1551
  return typeof value === "object" && value !== null;
@@ -1584,7 +1588,7 @@ function getRuntimeModelCapability(modelId) {
1584
1588
  return runtimeModelCapabilities.get(normalizeModelId(modelId));
1585
1589
  }
1586
1590
 
1587
- // src/upstream-request.ts
1591
+ // src/request/upstream-request.ts
1588
1592
  var BILLING_SEED = "59cf53e54c78";
1589
1593
  var SESSION_IDLE_ROTATE_MS = 15 * 60 * 1e3;
1590
1594
  var MAX_TOOL_RESULT_TEXT_LENGTH = 30 * 1024;
@@ -1806,33 +1810,26 @@ var ADAPTIVE_THINKING_MODEL_MATCHERS = [
1806
1810
  (modelId) => /claude-opus-4[-._]([7-9]|\d{2,})/.test(modelId)
1807
1811
  ];
1808
1812
  var DEFAULT_MAX_OUTPUT_TOKENS = 32e3;
1809
- function normalizeModelId2(modelId) {
1810
- return modelId.trim().toLowerCase();
1811
- }
1812
1813
  function supportsAdaptiveThinking(modelId) {
1813
1814
  const runtimeCapability = getRuntimeModelCapability(modelId);
1814
1815
  if (typeof runtimeCapability?.supportsThinking === "boolean") {
1815
1816
  return runtimeCapability.supportsThinking;
1816
1817
  }
1817
- const normalized = normalizeModelId2(modelId);
1818
+ const normalized = modelId.trim().toLowerCase();
1818
1819
  if (normalized.includes("haiku")) {
1819
1820
  return false;
1820
1821
  }
1821
1822
  return ADAPTIVE_THINKING_MODEL_MATCHERS.some((matches) => matches(normalized));
1822
1823
  }
1823
- function getModelMaxOutputTokens() {
1824
- return DEFAULT_MAX_OUTPUT_TOKENS;
1825
- }
1826
1824
  function resolveMaxTokens(requestedMaxTokens) {
1827
- const modelCap = getModelMaxOutputTokens();
1828
1825
  if (typeof requestedMaxTokens !== "number" || !Number.isFinite(requestedMaxTokens)) {
1829
- return modelCap;
1826
+ return DEFAULT_MAX_OUTPUT_TOKENS;
1830
1827
  }
1831
1828
  const normalized = Math.floor(requestedMaxTokens);
1832
1829
  if (normalized <= 0) {
1833
- return modelCap;
1830
+ return DEFAULT_MAX_OUTPUT_TOKENS;
1834
1831
  }
1835
- return Math.min(normalized, modelCap);
1832
+ return Math.min(normalized, DEFAULT_MAX_OUTPUT_TOKENS);
1836
1833
  }
1837
1834
  function normalizeSystemTexts(system) {
1838
1835
  if (typeof system === "string") {
@@ -1927,7 +1924,7 @@ function getReverseName(name, reverseLookup) {
1927
1924
  if (reverseLookup instanceof Map) {
1928
1925
  return reverseLookup.get(name) ?? name;
1929
1926
  }
1930
- return typeof reverseLookup[name] === "string" ? String(reverseLookup[name]) : name;
1927
+ return typeof reverseLookup[name] === "string" ? reverseLookup[name] : name;
1931
1928
  }
1932
1929
  function reverseMapToolUseNames(value, reverseLookup) {
1933
1930
  if (Array.isArray(value)) {
@@ -2150,7 +2147,7 @@ function createStreamingReverseMapper(response, reverseLookup) {
2150
2147
  });
2151
2148
  }
2152
2149
 
2153
- // src/tool-flow.ts
2150
+ // src/tools/flow.ts
2154
2151
  import { createHash as createHash3 } from "crypto";
2155
2152
  var TOOL_MASK_PREFIX = "tool_";
2156
2153
  function isRecord3(value) {
@@ -2275,7 +2272,7 @@ function applyOutboundToolFlow(parsed, claudeToolNames) {
2275
2272
  };
2276
2273
  }
2277
2274
 
2278
- // src/upstream-headers.ts
2275
+ // src/request/headers.ts
2279
2276
  import { randomUUID as randomUUID3 } from "crypto";
2280
2277
  var UPSTREAM_TIMEOUT_MS = 3e5;
2281
2278
  var STAINLESS_PACKAGE_VERSION = "0.81.0";
@@ -2360,7 +2357,7 @@ function filterBillableBetas(betas) {
2360
2357
  ).join(",");
2361
2358
  }
2362
2359
 
2363
- // src/request-transform.ts
2360
+ // src/request/transform.ts
2364
2361
  function applyRequestToolMasking(parsed, claudeToolNames) {
2365
2362
  return applyOutboundToolFlow(parsed, claudeToolNames);
2366
2363
  }
@@ -2407,7 +2404,7 @@ function extractToolNamesFromRequestBody(body) {
2407
2404
  }
2408
2405
  }
2409
2406
 
2410
- // src/tool-observation.ts
2407
+ // src/tools/observation.ts
2411
2408
  import { promises as fs } from "fs";
2412
2409
  import { dirname, join as join2 } from "path";
2413
2410
  var OBSERVED_TOOL_FILE = "anthropic-observed-tools.json";
@@ -2454,7 +2451,7 @@ async function recordObservedToolNames(toolNames) {
2454
2451
  await saveObservedToolInventory(inventory);
2455
2452
  }
2456
2453
 
2457
- // src/error-utils.ts
2454
+ // src/shared/error-utils.ts
2458
2455
  function sanitizeError(err) {
2459
2456
  const msg = err instanceof Error ? err.message : String(err);
2460
2457
  return msg.replace(/sk-ant-[a-zA-Z0-9_-]+/g, "[REDACTED]").replace(/eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g, "[REDACTED_JWT]").replace(/Bearer\s+[^\s,;]+/gi, "Bearer [REDACTED]");
@@ -2498,10 +2495,10 @@ function enrich429(body, headers) {
2498
2495
  }
2499
2496
  }
2500
2497
 
2501
- // src/pacing.ts
2498
+ // src/runtime/pacing.ts
2502
2499
  function pickNonNegativeInt(...values) {
2503
2500
  for (const v4 of values) {
2504
- if (v4 === void 0 || v4 === null) continue;
2501
+ if (v4 === void 0) continue;
2505
2502
  const n = typeof v4 === "number" ? v4 : Number.parseInt(v4, 10);
2506
2503
  if (Number.isFinite(n) && n >= 0) return n;
2507
2504
  }
@@ -2523,7 +2520,7 @@ function resolvePacingConfig(explicit = {}, env = process.env) {
2523
2520
  return { minGapMs: minGap, jitterMs: jitter };
2524
2521
  }
2525
2522
 
2526
- // src/runtime-factory.ts
2523
+ // src/runtime/factory.ts
2527
2524
  var TOKEN_REFRESH_PERMANENT_FAILURE_STATUS = 401;
2528
2525
  function mergeHeaders(target, headers) {
2529
2526
  if (!headers) {
@@ -2840,7 +2837,7 @@ var AccountRuntimeFactory = class {
2840
2837
  }
2841
2838
  };
2842
2839
 
2843
- // src/bootstrap-auth.ts
2840
+ // src/oauth/bootstrap.ts
2844
2841
  import { promises as fs2 } from "fs";
2845
2842
  import { join as join3 } from "path";
2846
2843
  import { getConfigDir as getConfigDir2 } from "opencode-multi-account-core";
@@ -2860,7 +2857,7 @@ function selectBootstrapAccount(accounts, activeAccountUuid) {
2860
2857
  const firstUsableAccount = completeAccounts.find(
2861
2858
  (account) => account.enabled !== false && account.isAuthDisabled !== true
2862
2859
  );
2863
- return firstUsableAccount ?? completeAccounts[0] ?? null;
2860
+ return firstUsableAccount ?? completeAccounts[0];
2864
2861
  }
2865
2862
  async function readCurrentAuth(providerId) {
2866
2863
  const authPath = join3(getConfigDir2(), AUTH_JSON_FILENAME);
@@ -3065,6 +3062,52 @@ var ClaudeMultiAuthPlugin = async (ctx) => {
3065
3062
  accessToken
3066
3063
  });
3067
3064
  };
3065
+ const ensurePoolInfrastructure = () => {
3066
+ if (!poolManager || !cascadeStateManager) {
3067
+ poolManager = new PoolManager();
3068
+ poolManager.loadPools(poolChainConfig.pools);
3069
+ cascadeStateManager = new CascadeStateManager();
3070
+ }
3071
+ };
3072
+ const createAuthLoaderResult = (activeManager) => ({
3073
+ apiKey: "",
3074
+ "chat.headers": async (input, output) => {
3075
+ if (input.provider?.info?.id !== ANTHROPIC_OAUTH_ADAPTER.authProviderId) return;
3076
+ const sessionId2 = getUpstreamSessionId();
3077
+ applyOrderedHeaders(output, {
3078
+ ...output.headers,
3079
+ ...getStaticHeaders(),
3080
+ ...getPerRequestHeaders(sessionId2),
3081
+ "anthropic-beta": getBetaHeader()
3082
+ });
3083
+ },
3084
+ async fetch(input, init) {
3085
+ if (!activeManager || !runtimeFactory) {
3086
+ stopHeartbeat();
3087
+ return fetch(input, init);
3088
+ }
3089
+ if (activeManager.getAccountCount() === 0) {
3090
+ stopHeartbeat();
3091
+ throw new Error(
3092
+ "No Anthropic accounts configured. Run `opencode auth login` to add an account."
3093
+ );
3094
+ }
3095
+ ensureHeartbeat(activeManager.getActiveAccount()?.accessToken);
3096
+ ensurePoolInfrastructure();
3097
+ return executeWithAccountRotation(
3098
+ activeManager,
3099
+ runtimeFactory,
3100
+ client,
3101
+ input,
3102
+ init,
3103
+ {
3104
+ poolManager,
3105
+ cascadeStateManager,
3106
+ poolChainConfig
3107
+ }
3108
+ );
3109
+ }
3110
+ });
3068
3111
  const startupDrift = detectDrift(template);
3069
3112
  if (startupDrift.drifted) {
3070
3113
  client.app.log({
@@ -3315,48 +3358,8 @@ var ClaudeMultiAuthPlugin = async (ctx) => {
3315
3358
  }
3316
3359
  const authProfile2 = await loadCCDerivedAuthProfile();
3317
3360
  return {
3318
- apiKey: "",
3319
- baseURL: authProfile2.apiV1BaseUrl,
3320
- "chat.headers": async (input, output) => {
3321
- if (input.provider?.info?.id !== ANTHROPIC_OAUTH_ADAPTER.authProviderId) return;
3322
- const sessionId2 = getUpstreamSessionId();
3323
- applyOrderedHeaders(output, {
3324
- ...output.headers,
3325
- ...getStaticHeaders(),
3326
- ...getPerRequestHeaders(sessionId2),
3327
- "anthropic-beta": getBetaHeader()
3328
- });
3329
- },
3330
- async fetch(input, init) {
3331
- if (!manager || !runtimeFactory) {
3332
- stopHeartbeat();
3333
- return fetch(input, init);
3334
- }
3335
- if (manager.getAccountCount() === 0) {
3336
- stopHeartbeat();
3337
- throw new Error(
3338
- "No Anthropic accounts configured. Run `opencode auth login` to add an account."
3339
- );
3340
- }
3341
- ensureHeartbeat(manager.getActiveAccount()?.accessToken);
3342
- if (!poolManager || !cascadeStateManager) {
3343
- poolManager = new PoolManager();
3344
- poolManager.loadPools(poolChainConfig.pools);
3345
- cascadeStateManager = new CascadeStateManager();
3346
- }
3347
- return executeWithAccountRotation(
3348
- manager,
3349
- runtimeFactory,
3350
- client,
3351
- input,
3352
- init,
3353
- {
3354
- poolManager,
3355
- cascadeStateManager,
3356
- poolChainConfig
3357
- }
3358
- );
3359
- }
3361
+ ...createAuthLoaderResult(manager),
3362
+ baseURL: authProfile2.apiV1BaseUrl
3360
3363
  };
3361
3364
  }
3362
3365
  for (const model of Object.values(providerModels)) {
@@ -3396,48 +3399,8 @@ var ClaudeMultiAuthPlugin = async (ctx) => {
3396
3399
  }
3397
3400
  const authProfile = await loadCCDerivedAuthProfile();
3398
3401
  return {
3399
- apiKey: "",
3400
- baseURL: authProfile.apiV1BaseUrl,
3401
- "chat.headers": async (input, output) => {
3402
- if (input.provider?.info?.id !== ANTHROPIC_OAUTH_ADAPTER.authProviderId) return;
3403
- const sessionId2 = getUpstreamSessionId();
3404
- applyOrderedHeaders(output, {
3405
- ...output.headers,
3406
- ...getStaticHeaders(),
3407
- ...getPerRequestHeaders(sessionId2),
3408
- "anthropic-beta": getBetaHeader()
3409
- });
3410
- },
3411
- async fetch(input, init) {
3412
- if (!initializedManager || !runtimeFactory) {
3413
- stopHeartbeat();
3414
- return fetch(input, init);
3415
- }
3416
- if (initializedManager.getAccountCount() === 0) {
3417
- stopHeartbeat();
3418
- throw new Error(
3419
- "No Anthropic accounts configured. Run `opencode auth login` to add an account."
3420
- );
3421
- }
3422
- ensureHeartbeat(initializedManager.getActiveAccount()?.accessToken);
3423
- if (!poolManager || !cascadeStateManager) {
3424
- poolManager = new PoolManager();
3425
- poolManager.loadPools(poolChainConfig.pools);
3426
- cascadeStateManager = new CascadeStateManager();
3427
- }
3428
- return executeWithAccountRotation(
3429
- initializedManager,
3430
- runtimeFactory,
3431
- client,
3432
- input,
3433
- init,
3434
- {
3435
- poolManager,
3436
- cascadeStateManager,
3437
- poolChainConfig
3438
- }
3439
- );
3440
- }
3402
+ ...createAuthLoaderResult(initializedManager),
3403
+ baseURL: authProfile.apiV1BaseUrl
3441
3404
  };
3442
3405
  }
3443
3406
  }