@omnicross/subscriptions 0.2.1 → 0.3.1

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.cjs CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkUXUMAXZJcjs = require('./chunk-UXUMAXZJ.cjs');
5
+
6
+
7
+ var _chunkB2LHAP4Fcjs = require('./chunk-B2LHAP4F.cjs');
6
8
 
7
9
 
8
10
 
@@ -125,13 +127,15 @@ var ACCOUNTS_KEY = {
125
127
  claude: "claudeAccounts",
126
128
  codex: "codexAccounts",
127
129
  gemini: "geminiAccounts",
128
- opencodego: "opencodegoAccounts"
130
+ opencodego: "opencodegoAccounts",
131
+ kimi: "kimiAccounts"
129
132
  };
130
133
  var ACTIVE_KEY = {
131
134
  claude: "activeClaudeAccountId",
132
135
  codex: "activeCodexAccountId",
133
136
  gemini: "activeGeminiAccountId",
134
- opencodego: "activeOpencodegoAccountId"
137
+ opencodego: "activeOpencodegoAccountId",
138
+ kimi: "activeKimiAccountId"
135
139
  };
136
140
  function gateSchedulable(accounts, providerId, health, now, resolvedModel, supportedModelsById) {
137
141
  if (!health && !resolvedModel || accounts.length < 2) return accounts;
@@ -421,13 +425,17 @@ var OAuthBearerAuthStrategy = (_class2 = class {
421
425
  return;
422
426
  }
423
427
  headers["Authorization"] = `Bearer ${token}`;
428
+ if (this.providerId === "kimi") {
429
+ const deviceId = await this.resolveKimiDeviceId(_optionalChain([hints, 'optionalAccess', _29 => _29.sessionKey]));
430
+ Object.assign(headers, _chunkB2LHAP4Fcjs.kimiFingerprintHeaders.call(void 0, deviceId));
431
+ }
424
432
  }
425
433
  async onUnauthorized(sessionKey) {
426
434
  const byId = await refreshSelectedAccount(this.selector, this.tokens, this.mutex, this.providerId, sessionKey);
427
435
  if (byId !== null) return byId;
428
436
  return this.mutex.run(`${this.providerId}:refresh`, async () => {
429
437
  try {
430
- return this.providerId === "codex" ? await this.tokens.refreshCodexToken() : await this.tokens.refreshGeminiToken();
438
+ return this.refreshActive();
431
439
  } catch (err) {
432
440
  console.warn(`[OAuthBearerAuthStrategy] ${this.providerId} refresh failed:`, err);
433
441
  return false;
@@ -436,8 +444,8 @@ var OAuthBearerAuthStrategy = (_class2 = class {
436
444
  }
437
445
  async describeStatus() {
438
446
  const config = await this.tokens.getFullConfig();
439
- const entry = this.providerId === "codex" ? config.codex : config.gemini;
440
- if (!_optionalChain([entry, 'optionalAccess', _29 => _29.accessToken])) {
447
+ const entry = this.tokenBlock(config);
448
+ if (!_optionalChain([entry, 'optionalAccess', _30 => _30.accessToken])) {
441
449
  return { providerId: this.providerId, ok: false, reason: "missing-credential" };
442
450
  }
443
451
  if (entry.status === "expired") {
@@ -453,22 +461,53 @@ var OAuthBearerAuthStrategy = (_class2 = class {
453
461
  /** Read the current token, refreshing in-line if it's within the lead window. */
454
462
  async resolveAccessToken() {
455
463
  const config = await this.tokens.getFullConfig();
456
- const entry = this.providerId === "codex" ? config.codex : config.gemini;
457
- if (!_optionalChain([entry, 'optionalAccess', _30 => _30.accessToken])) return null;
464
+ const entry = this.tokenBlock(config);
465
+ if (!_optionalChain([entry, 'optionalAccess', _31 => _31.accessToken])) return null;
458
466
  const expiresAtMs = entry.expiresAt ? new Date(entry.expiresAt).getTime() : 0;
459
467
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - REFRESH_LEAD_MS;
460
468
  if (expiringSoon && entry.refreshToken) {
461
469
  const refreshed = await this.mutex.run(`${this.providerId}:refresh`, async () => {
462
- return this.providerId === "codex" ? await this.tokens.refreshCodexToken() : await this.tokens.refreshGeminiToken();
470
+ return this.refreshActive();
463
471
  });
464
472
  if (!refreshed) return null;
465
473
  const fresh = await this.tokens.getFullConfig();
466
- const freshEntry = this.providerId === "codex" ? fresh.codex : fresh.gemini;
467
- return _nullishCoalesce(_optionalChain([freshEntry, 'optionalAccess', _31 => _31.accessToken]), () => ( null));
474
+ return _nullishCoalesce(_optionalChain([this, 'access', _32 => _32.tokenBlock, 'call', _33 => _33(fresh), 'optionalAccess', _34 => _34.accessToken]), () => ( null));
468
475
  }
469
476
  if (entry.status === "expired") return null;
470
477
  return entry.accessToken;
471
478
  }
479
+ /** The active account's refresh, dispatched per provider. */
480
+ refreshActive() {
481
+ switch (this.providerId) {
482
+ case "codex":
483
+ return this.tokens.refreshCodexToken();
484
+ case "gemini":
485
+ return this.tokens.refreshGeminiToken();
486
+ case "kimi":
487
+ return this.tokens.refreshKimiToken ? this.tokens.refreshKimiToken() : Promise.resolve(false);
488
+ }
489
+ }
490
+ tokenBlock(config) {
491
+ switch (this.providerId) {
492
+ case "codex":
493
+ return config.codex;
494
+ case "gemini":
495
+ return config.gemini;
496
+ case "kimi":
497
+ return config.kimi;
498
+ }
499
+ }
500
+ /**
501
+ * Best-effort device id for the fingerprint header. Selection already ran in
502
+ * `applyHeaders`; rather than re-deriving it, read the active block's id (a
503
+ * pool-served non-active account momentarily reports the active id — the
504
+ * header is per-INSTALL identity, so this is cosmetic, not auth).
505
+ */
506
+ async resolveKimiDeviceId(_sessionKey) {
507
+ void _sessionKey;
508
+ const config = await this.tokens.getFullConfig();
509
+ return _nullishCoalesce(_optionalChain([config, 'access', _35 => _35.kimi, 'optionalAccess', _36 => _36.deviceId]), () => ( _optionalChain([config, 'access', _37 => _37.kimiAccounts, 'optionalAccess', _38 => _38[0], 'optionalAccess', _39 => _39.tokens, 'access', _40 => _40.deviceId])));
510
+ }
472
511
  }, _class2);
473
512
 
474
513
  // src/auth/PassThroughAuthStrategy.ts
@@ -490,15 +529,15 @@ var PassThroughAuthStrategy = (_class3 = class {
490
529
  this.selector,
491
530
  this.tokens,
492
531
  "claude",
493
- _optionalChain([hints, 'optionalAccess', _32 => _32.sessionKey]),
532
+ _optionalChain([hints, 'optionalAccess', _41 => _41.sessionKey]),
494
533
  () => this.tokens.getValidClaudeAccessToken(),
495
534
  {
496
535
  health: this.health,
497
- reportSelection: _optionalChain([hints, 'optionalAccess', _33 => _33.reportSelection]),
498
- resolvedModel: _optionalChain([hints, 'optionalAccess', _34 => _34.resolvedModel]),
499
- preferredAccountId: _optionalChain([hints, 'optionalAccess', _35 => _35.preferredAccountId]),
500
- preferredAccountGroup: _optionalChain([hints, 'optionalAccess', _36 => _36.preferredAccountGroup]),
501
- boundAccountFallbackPolicy: _optionalChain([hints, 'optionalAccess', _37 => _37.boundAccountFallbackPolicy])
536
+ reportSelection: _optionalChain([hints, 'optionalAccess', _42 => _42.reportSelection]),
537
+ resolvedModel: _optionalChain([hints, 'optionalAccess', _43 => _43.resolvedModel]),
538
+ preferredAccountId: _optionalChain([hints, 'optionalAccess', _44 => _44.preferredAccountId]),
539
+ preferredAccountGroup: _optionalChain([hints, 'optionalAccess', _45 => _45.preferredAccountGroup]),
540
+ boundAccountFallbackPolicy: _optionalChain([hints, 'optionalAccess', _46 => _46.boundAccountFallbackPolicy])
502
541
  }
503
542
  );
504
543
  if (!token) return;
@@ -519,7 +558,7 @@ var PassThroughAuthStrategy = (_class3 = class {
519
558
  async describeStatus() {
520
559
  const config = await this.tokens.getFullConfig();
521
560
  const claude = config.claude;
522
- if (!_optionalChain([claude, 'optionalAccess', _38 => _38.accessToken])) {
561
+ if (!_optionalChain([claude, 'optionalAccess', _47 => _47.accessToken])) {
523
562
  return { providerId: "claude", ok: false, reason: "missing-credential" };
524
563
  }
525
564
  if (claude.status === "expired") {
@@ -575,22 +614,22 @@ var StaticBearerAuthStrategy = (_class5 = class {
575
614
  this.selector,
576
615
  this.tokens,
577
616
  "opencodego",
578
- _optionalChain([hints, 'optionalAccess', _39 => _39.sessionKey]),
617
+ _optionalChain([hints, 'optionalAccess', _48 => _48.sessionKey]),
579
618
  () => this.tokens.getValidOpenCodeGoApiKey(),
580
619
  {
581
620
  health: this.health,
582
- reportSelection: _optionalChain([hints, 'optionalAccess', _40 => _40.reportSelection]),
583
- resolvedModel: _optionalChain([hints, 'optionalAccess', _41 => _41.resolvedModel]),
584
- preferredAccountId: _optionalChain([hints, 'optionalAccess', _42 => _42.preferredAccountId]),
585
- preferredAccountGroup: _optionalChain([hints, 'optionalAccess', _43 => _43.preferredAccountGroup]),
586
- boundAccountFallbackPolicy: _optionalChain([hints, 'optionalAccess', _44 => _44.boundAccountFallbackPolicy])
621
+ reportSelection: _optionalChain([hints, 'optionalAccess', _49 => _49.reportSelection]),
622
+ resolvedModel: _optionalChain([hints, 'optionalAccess', _50 => _50.resolvedModel]),
623
+ preferredAccountId: _optionalChain([hints, 'optionalAccess', _51 => _51.preferredAccountId]),
624
+ preferredAccountGroup: _optionalChain([hints, 'optionalAccess', _52 => _52.preferredAccountGroup]),
625
+ boundAccountFallbackPolicy: _optionalChain([hints, 'optionalAccess', _53 => _53.boundAccountFallbackPolicy])
587
626
  }
588
627
  );
589
628
  if (!key) {
590
629
  return;
591
630
  }
592
631
  headers["Authorization"] = `Bearer ${key}`;
593
- if (_optionalChain([hints, 'optionalAccess', _45 => _45.upstreamUrl, 'optionalAccess', _46 => _46.includes, 'call', _47 => _47(ANTHROPIC_SHAPE_PATH)])) {
632
+ if (_optionalChain([hints, 'optionalAccess', _54 => _54.upstreamUrl, 'optionalAccess', _55 => _55.includes, 'call', _56 => _56(ANTHROPIC_SHAPE_PATH)])) {
594
633
  headers["x-api-key"] = key;
595
634
  }
596
635
  }
@@ -600,7 +639,7 @@ var StaticBearerAuthStrategy = (_class5 = class {
600
639
  async describeStatus() {
601
640
  const config = await this.tokens.getFullConfig();
602
641
  const oc = config.opencodego;
603
- if (!_optionalChain([oc, 'optionalAccess', _48 => _48.apiKey])) {
642
+ if (!_optionalChain([oc, 'optionalAccess', _57 => _57.apiKey])) {
604
643
  return { providerId: "opencodego", ok: false, reason: "missing-credential" };
605
644
  }
606
645
  if (oc.status === "error") {
@@ -615,7 +654,8 @@ var DISPLAY_NAMES = {
615
654
  claude: "Claude (Anthropic OAuth)",
616
655
  codex: "Codex (ChatGPT OAuth)",
617
656
  gemini: "Gemini (Google OAuth)",
618
- opencodego: "OpenCodeGo (Bearer key)"
657
+ opencodego: "OpenCodeGo (Bearer key)",
658
+ kimi: "Kimi Code (Moonshot OAuth)"
619
659
  };
620
660
  var SubscriptionAccountService = (_class6 = class {
621
661
  __init10() {this.mutex = new RefreshMutex()}
@@ -629,7 +669,8 @@ var SubscriptionAccountService = (_class6 = class {
629
669
  ["claude", new PassThroughAuthStrategy(tokens, this.mutex, this.selector, health)],
630
670
  ["codex", new OAuthBearerAuthStrategy("codex", tokens, this.mutex, this.selector, health)],
631
671
  ["gemini", new OAuthBearerAuthStrategy("gemini", tokens, this.mutex, this.selector, health)],
632
- ["opencodego", new StaticBearerAuthStrategy(tokens, this.selector, health)]
672
+ ["opencodego", new StaticBearerAuthStrategy(tokens, this.selector, health)],
673
+ ["kimi", new OAuthBearerAuthStrategy("kimi", tokens, this.mutex, this.selector, health)]
633
674
  ]);
634
675
  }
635
676
  /** Returns the strategy bound to a subscription provider, or `null` for unknown ids. */
@@ -958,11 +999,11 @@ function resolveOpenCodeGoShape(entry) {
958
999
  function resolveOpenCodeGoHalf(modelId, config) {
959
1000
  if (!config) return "go";
960
1001
  for (const entry of Object.values(_nullishCoalesce(config.modelMap, () => ( {})))) {
961
- if (_optionalChain([entry, 'optionalAccess', _49 => _49.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
1002
+ if (_optionalChain([entry, 'optionalAccess', _58 => _58.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
962
1003
  }
963
1004
  for (const list of Object.values(_nullishCoalesce(config.fallbacks, () => ( {})))) {
964
1005
  for (const entry of _nullishCoalesce(list, () => ( []))) {
965
- if (_optionalChain([entry, 'optionalAccess', _50 => _50.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
1006
+ if (_optionalChain([entry, 'optionalAccess', _59 => _59.modelId]) === modelId) return _nullishCoalesce(entry.provider, () => ( "go"));
966
1007
  }
967
1008
  }
968
1009
  return "go";
@@ -1039,7 +1080,7 @@ function hasBackgroundPattern(loweredSlices) {
1039
1080
  return containsAny(loweredSlices, BACKGROUND_KEYWORDS);
1040
1081
  }
1041
1082
  function resolveOpenCodeGoScenario(summary, config) {
1042
- const longContextThreshold = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _51 => _51.modelMap, 'optionalAccess', _52 => _52.long_context, 'optionalAccess', _53 => _53.contextThreshold]), () => ( DEFAULT_OPENCODEGO_LONG_CONTEXT_THRESHOLD));
1083
+ const longContextThreshold = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _60 => _60.modelMap, 'optionalAccess', _61 => _61.long_context, 'optionalAccess', _62 => _62.contextThreshold]), () => ( DEFAULT_OPENCODEGO_LONG_CONTEXT_THRESHOLD));
1043
1084
  if (summary.estimatedInputTokens >= longContextThreshold) {
1044
1085
  return "long_context";
1045
1086
  }
@@ -1079,7 +1120,8 @@ var SubscriptionProviderRegistry = (_class9 = class {
1079
1120
  const codex = this.accounts.getStrategy("codex");
1080
1121
  const gemini = this.accounts.getStrategy("gemini");
1081
1122
  const opencodego = this.accounts.getStrategy("opencodego");
1082
- if (!claude || !codex || !gemini || !opencodego) {
1123
+ const kimi = this.accounts.getStrategy("kimi");
1124
+ if (!claude || !codex || !gemini || !opencodego || !kimi) {
1083
1125
  throw new Error("[SubscriptionProviderRegistry] Missing strategy in SubscriptionAccountService");
1084
1126
  }
1085
1127
  this.profiles = /* @__PURE__ */ new Map([
@@ -1169,7 +1211,7 @@ var SubscriptionProviderRegistry = (_class9 = class {
1169
1211
  resolveUpstreamUrl: (model, config) => {
1170
1212
  const oc = config;
1171
1213
  const { half, shape } = resolveOpenCodeGoTarget(model, oc);
1172
- const override = half === "zen" ? _optionalChain([oc, 'optionalAccess', _54 => _54.zenBaseUrl]) : _optionalChain([oc, 'optionalAccess', _55 => _55.baseUrl]);
1214
+ const override = half === "zen" ? _optionalChain([oc, 'optionalAccess', _63 => _63.zenBaseUrl]) : _optionalChain([oc, 'optionalAccess', _64 => _64.baseUrl]);
1173
1215
  return buildOpenCodeGoUrl(half, shape, override);
1174
1216
  },
1175
1217
  // zen seam (Decision 3): vary the provider transformer chain by resolved
@@ -1187,7 +1229,7 @@ var SubscriptionProviderRegistry = (_class9 = class {
1187
1229
  modelTransformerNames: [],
1188
1230
  modelMapper: (sdkModel, summary, config) => {
1189
1231
  const scenario = resolveOpenCodeGoScenario(summary, config);
1190
- const entry = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _56 => _56.modelMap, 'optionalAccess', _57 => _57[scenario]]), () => ( _optionalChain([config, 'optionalAccess', _58 => _58.modelMap, 'optionalAccess', _59 => _59.default]))), () => ( DEFAULT_OPENCODEGO_MODEL_MAP[scenario])), () => ( DEFAULT_OPENCODEGO_MODEL_MAP.default));
1232
+ const entry = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _65 => _65.modelMap, 'optionalAccess', _66 => _66[scenario]]), () => ( _optionalChain([config, 'optionalAccess', _67 => _67.modelMap, 'optionalAccess', _68 => _68.default]))), () => ( DEFAULT_OPENCODEGO_MODEL_MAP[scenario])), () => ( DEFAULT_OPENCODEGO_MODEL_MAP.default));
1191
1233
  if (!entry) {
1192
1234
  return { resolvedModel: sdkModel, scenario };
1193
1235
  }
@@ -1205,7 +1247,7 @@ var SubscriptionProviderRegistry = (_class9 = class {
1205
1247
  // wedge permanently in half-open). When NO circuit is open this returns
1206
1248
  // the same first non-attempted entry as the prior `!attempted` filter.
1207
1249
  nextFallback: (scenario, attempted, config) => {
1208
- const list = _nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _60 => _60.fallbacks, 'optionalAccess', _61 => _61[scenario]]), () => ( DEFAULT_OPENCODEGO_FALLBACKS[scenario])), () => ( []));
1250
+ const list = _nullishCoalesce(_nullishCoalesce(_optionalChain([config, 'optionalAccess', _69 => _69.fallbacks, 'optionalAccess', _70 => _70[scenario]]), () => ( DEFAULT_OPENCODEGO_FALLBACKS[scenario])), () => ( []));
1209
1251
  for (const entry of list) {
1210
1252
  if (attempted.includes(entry.modelId)) continue;
1211
1253
  if (this.breaker.allowRequest(entry.modelId)) return entry;
@@ -1221,6 +1263,25 @@ var SubscriptionProviderRegistry = (_class9 = class {
1221
1263
  // profile sets it — claude / codex / gemini leave it UNSET (no-op).
1222
1264
  recordModelOutcome: (modelId, ok) => ok ? this.breaker.recordSuccess(modelId) : this.breaker.recordFailure(modelId)
1223
1265
  }
1266
+ ],
1267
+ [
1268
+ "kimi",
1269
+ {
1270
+ providerId: "kimi",
1271
+ displayName: "Kimi Code (Moonshot OAuth)",
1272
+ authStrategy: kimi,
1273
+ mode: "transformer",
1274
+ // Kimi Code's subscription surface speaks standard Anthropic Messages
1275
+ // at `api.kimi.com/coding/v1/messages` (plus an OpenAI chat face on
1276
+ // /chat/completions that a BYO kimi row already covers). The messages
1277
+ // URL ending in `/v1/messages` makes the core plan builder treat it as
1278
+ // same-format — the SDK's Anthropic body relays verbatim, with the
1279
+ // OAuth bearer + X-Msh-* fingerprint headers injected by the strategy.
1280
+ resolveUpstreamUrl: () => "https://api.kimi.com/coding/v1/messages",
1281
+ // Route-to only (Responses/Chat ingress): Unified → Anthropic Messages.
1282
+ providerTransformerNames: ["anthropic"],
1283
+ modelTransformerNames: []
1284
+ }
1224
1285
  ]
1225
1286
  ]);
1226
1287
  }
@@ -1308,7 +1369,7 @@ var SubscriptionDispatcher = class {
1308
1369
  scenario = mapped.scenario;
1309
1370
  req.anthropicBody.model = resolvedModel;
1310
1371
  }
1311
- const upstreamUrl = _optionalChain([this, 'access', _62 => _62.profile, 'access', _63 => _63.resolveUpstreamUrl, 'optionalCall', _64 => _64(resolvedModel, ocConfig)]);
1372
+ const upstreamUrl = _optionalChain([this, 'access', _71 => _71.profile, 'access', _72 => _72.resolveUpstreamUrl, 'optionalCall', _73 => _73(resolvedModel, ocConfig)]);
1312
1373
  if (!upstreamUrl) {
1313
1374
  throw new Error(`[SubscriptionDispatcher] profile=${this.profile.providerId} missing resolveUpstreamUrl`);
1314
1375
  }
@@ -1340,7 +1401,7 @@ var SubscriptionDispatcher = class {
1340
1401
  );
1341
1402
  try {
1342
1403
  const upstream = await this.hooks.fetchWithRetry(upstreamUrl, headers, req.anthropicBody, currentModel);
1343
- _optionalChain([this, 'access', _65 => _65.profile, 'access', _66 => _66.recordModelOutcome, 'optionalCall', _67 => _67(currentModel, true)]);
1404
+ _optionalChain([this, 'access', _74 => _74.profile, 'access', _75 => _75.recordModelOutcome, 'optionalCall', _76 => _76(currentModel, true)]);
1344
1405
  this.markHealth(usedAccountId, 200);
1345
1406
  await this.hooks.writeProxyResponse(req.res, upstream, req.isStream, req.reqId);
1346
1407
  return;
@@ -1349,7 +1410,7 @@ var SubscriptionDispatcher = class {
1349
1410
  if (handled.retryOnce) {
1350
1411
  try {
1351
1412
  const upstream = await this.hooks.fetchWithRetry(upstreamUrl, handled.headers, req.anthropicBody, currentModel);
1352
- _optionalChain([this, 'access', _68 => _68.profile, 'access', _69 => _69.recordModelOutcome, 'optionalCall', _70 => _70(currentModel, true)]);
1413
+ _optionalChain([this, 'access', _77 => _77.profile, 'access', _78 => _78.recordModelOutcome, 'optionalCall', _79 => _79(currentModel, true)]);
1353
1414
  this.markHealth(usedAccountId, 200);
1354
1415
  await this.hooks.writeProxyResponse(req.res, upstream, req.isStream, req.reqId);
1355
1416
  return;
@@ -1359,10 +1420,10 @@ var SubscriptionDispatcher = class {
1359
1420
  }
1360
1421
  }
1361
1422
  if (caughtErrorBreakerOutcome(err) === "failure") {
1362
- _optionalChain([this, 'access', _71 => _71.profile, 'access', _72 => _72.recordModelOutcome, 'optionalCall', _73 => _73(currentModel, false)]);
1423
+ _optionalChain([this, 'access', _80 => _80.profile, 'access', _81 => _81.recordModelOutcome, 'optionalCall', _82 => _82(currentModel, false)]);
1363
1424
  }
1364
1425
  this.markHealth(usedAccountId, errStatus(err), err);
1365
- const next = _optionalChain([this, 'access', _74 => _74.profile, 'access', _75 => _75.nextFallback, 'optionalCall', _76 => _76(scenario, attempted, ocConfig)]);
1426
+ const next = _optionalChain([this, 'access', _83 => _83.profile, 'access', _84 => _84.nextFallback, 'optionalCall', _85 => _85(scenario, attempted, ocConfig)]);
1366
1427
  if (!next || attempted.length >= MAX_FALLBACK_ATTEMPTS_LOCAL) {
1367
1428
  throw err;
1368
1429
  }
@@ -1376,7 +1437,7 @@ var SubscriptionDispatcher = class {
1376
1437
  }
1377
1438
  /** Standard subscription transformer chain — Codex/Gemini/OpenCodeGo OpenAI-shape. */
1378
1439
  async dispatchTransformerChain(req, upstreamUrl, resolvedModel, scenario, ocConfig, sessionKey) {
1379
- const providerNames = _nullishCoalesce(_optionalChain([this, 'access', _77 => _77.profile, 'access', _78 => _78.resolveProviderTransformerNames, 'optionalCall', _79 => _79(resolvedModel, ocConfig)]), () => ( this.profile.providerTransformerNames));
1440
+ const providerNames = _nullishCoalesce(_optionalChain([this, 'access', _86 => _86.profile, 'access', _87 => _87.resolveProviderTransformerNames, 'optionalCall', _88 => _88(resolvedModel, ocConfig)]), () => ( this.profile.providerTransformerNames));
1380
1441
  const providerTransformers = this.resolveTransformers(providerNames);
1381
1442
  const modelTransformers = this.resolveTransformers(this.profile.modelTransformerNames);
1382
1443
  const transformerProvider = {
@@ -1417,7 +1478,7 @@ var SubscriptionDispatcher = class {
1417
1478
  );
1418
1479
  try {
1419
1480
  const upstream = await this.hooks.fetchWithRetry(fetchUrl, headers, requestBody, currentModel);
1420
- _optionalChain([this, 'access', _80 => _80.profile, 'access', _81 => _81.recordModelOutcome, 'optionalCall', _82 => _82(currentModel, true)]);
1481
+ _optionalChain([this, 'access', _89 => _89.profile, 'access', _90 => _90.recordModelOutcome, 'optionalCall', _91 => _91(currentModel, true)]);
1421
1482
  this.markHealth(usedAccountId, 200);
1422
1483
  const finalResponse = await this.hooks.executor.executeResponseChain(
1423
1484
  requestBody,
@@ -1433,7 +1494,7 @@ var SubscriptionDispatcher = class {
1433
1494
  if (handled.retryOnce) {
1434
1495
  try {
1435
1496
  const upstream = await this.hooks.fetchWithRetry(fetchUrl, handled.headers, requestBody, currentModel);
1436
- _optionalChain([this, 'access', _83 => _83.profile, 'access', _84 => _84.recordModelOutcome, 'optionalCall', _85 => _85(currentModel, true)]);
1497
+ _optionalChain([this, 'access', _92 => _92.profile, 'access', _93 => _93.recordModelOutcome, 'optionalCall', _94 => _94(currentModel, true)]);
1437
1498
  this.markHealth(usedAccountId, 200);
1438
1499
  const finalResponse = await this.hooks.executor.executeResponseChain(
1439
1500
  requestBody,
@@ -1450,10 +1511,10 @@ var SubscriptionDispatcher = class {
1450
1511
  }
1451
1512
  }
1452
1513
  if (caughtErrorBreakerOutcome(err) === "failure") {
1453
- _optionalChain([this, 'access', _86 => _86.profile, 'access', _87 => _87.recordModelOutcome, 'optionalCall', _88 => _88(currentModel, false)]);
1514
+ _optionalChain([this, 'access', _95 => _95.profile, 'access', _96 => _96.recordModelOutcome, 'optionalCall', _97 => _97(currentModel, false)]);
1454
1515
  }
1455
1516
  this.markHealth(usedAccountId, errStatus(err), err);
1456
- const next = _optionalChain([this, 'access', _89 => _89.profile, 'access', _90 => _90.nextFallback, 'optionalCall', _91 => _91(scenario, attempted, ocConfig)]);
1517
+ const next = _optionalChain([this, 'access', _98 => _98.profile, 'access', _99 => _99.nextFallback, 'optionalCall', _100 => _100(scenario, attempted, ocConfig)]);
1457
1518
  if (!next || attempted.length >= MAX_FALLBACK_ATTEMPTS_LOCAL) {
1458
1519
  throw err;
1459
1520
  }
@@ -1483,7 +1544,7 @@ var SubscriptionDispatcher = class {
1483
1544
  return { firstModel: primaryModel, attempted: [] };
1484
1545
  }
1485
1546
  const skipped = [primaryModel];
1486
- const firstAdmitting = _optionalChain([this, 'access', _92 => _92.profile, 'access', _93 => _93.nextFallback, 'optionalCall', _94 => _94(scenario, skipped, ocConfig)]);
1547
+ const firstAdmitting = _optionalChain([this, 'access', _101 => _101.profile, 'access', _102 => _102.nextFallback, 'optionalCall', _103 => _103(scenario, skipped, ocConfig)]);
1487
1548
  if (firstAdmitting) {
1488
1549
  console.warn(
1489
1550
  `[AgentProxy:subscription] opencodego primary ${primaryModel} circuit open -> first admitting fallback ${firstAdmitting.modelId}`
@@ -1501,7 +1562,7 @@ var SubscriptionDispatcher = class {
1501
1562
  * successfully (caller should retry once); otherwise re-throws.
1502
1563
  */
1503
1564
  async maybeRetryAfterError(err, headers, req, resolvedModel, sessionKey) {
1504
- const status = _nullishCoalesce(_optionalChain([err, 'optionalAccess', _95 => _95.status]), () => ( 0));
1565
+ const status = _nullishCoalesce(_optionalChain([err, 'optionalAccess', _104 => _104.status]), () => ( 0));
1505
1566
  if (status !== 401) {
1506
1567
  return { retryOnce: false, headers };
1507
1568
  }
@@ -1624,11 +1685,11 @@ var SubscriptionDispatcher = class {
1624
1685
  };
1625
1686
  var MAX_FALLBACK_ATTEMPTS_LOCAL = 3;
1626
1687
  function errStatus(err) {
1627
- const status = _optionalChain([err, 'optionalAccess', _96 => _96.status]);
1688
+ const status = _optionalChain([err, 'optionalAccess', _105 => _105.status]);
1628
1689
  return typeof status === "number" ? status : null;
1629
1690
  }
1630
1691
  function errHeaders(err) {
1631
- const h = _optionalChain([err, 'optionalAccess', _97 => _97.headers]);
1692
+ const h = _optionalChain([err, 'optionalAccess', _106 => _106.headers]);
1632
1693
  if (!h) return void 0;
1633
1694
  if (typeof h.get === "function") return h;
1634
1695
  if (typeof h === "object") return h;
@@ -1636,11 +1697,11 @@ function errHeaders(err) {
1636
1697
  }
1637
1698
  function errBodyText(err) {
1638
1699
  const e = err;
1639
- const raw = typeof _optionalChain([e, 'optionalAccess', _98 => _98.bodyText]) === "string" ? e.bodyText : typeof _optionalChain([e, 'optionalAccess', _99 => _99.body]) === "string" ? e.body : void 0;
1640
- return _optionalChain([raw, 'optionalAccess', _100 => _100.slice, 'call', _101 => _101(0, 2048)]);
1700
+ const raw = typeof _optionalChain([e, 'optionalAccess', _107 => _107.bodyText]) === "string" ? e.bodyText : typeof _optionalChain([e, 'optionalAccess', _108 => _108.body]) === "string" ? e.body : void 0;
1701
+ return _optionalChain([raw, 'optionalAccess', _109 => _109.slice, 'call', _110 => _110(0, 2048)]);
1641
1702
  }
1642
1703
  function caughtErrorBreakerOutcome(err) {
1643
- const status = _optionalChain([err, 'optionalAccess', _102 => _102.status]);
1704
+ const status = _optionalChain([err, 'optionalAccess', _111 => _111.status]);
1644
1705
  if (typeof status !== "number") return "failure";
1645
1706
  if (status === 0) return "neutral";
1646
1707
  if (status >= 500 || status === 429) return "failure";
@@ -1797,7 +1858,7 @@ async function encodeInputImage(asset, signal) {
1797
1858
  try {
1798
1859
  bytes = await _imagegeneration.readImageAssetBytes.call(void 0, asset, MAX_INPUT_IMAGE_BYTES, signal);
1799
1860
  } catch (cause) {
1800
- if (_optionalChain([signal, 'optionalAccess', _103 => _103.aborted])) throw signal.reason;
1861
+ if (_optionalChain([signal, 'optionalAccess', _112 => _112.aborted])) throw signal.reason;
1801
1862
  if (cause instanceof RangeError) {
1802
1863
  throw new (0, _imagegeneration.ImageGenerationError)("image_too_large", { param: "image", cause });
1803
1864
  }
@@ -1901,8 +1962,8 @@ async function readCandidateCodexImageResponseBody(response) {
1901
1962
  }
1902
1963
  function selectVerifiedCandidateResponseMetadata(parsed, verified) {
1903
1964
  return {
1904
- ..._optionalChain([verified, 'optionalAccess', _104 => _104.usage]) && parsed.usage ? { usage: parsed.usage } : {},
1905
- ..._optionalChain([verified, 'optionalAccess', _105 => _105.revisedPrompt]) && parsed.revisedPrompt ? { revisedPrompt: parsed.revisedPrompt } : {}
1965
+ ..._optionalChain([verified, 'optionalAccess', _113 => _113.usage]) && parsed.usage ? { usage: parsed.usage } : {},
1966
+ ..._optionalChain([verified, 'optionalAccess', _114 => _114.revisedPrompt]) && parsed.revisedPrompt ? { revisedPrompt: parsed.revisedPrompt } : {}
1906
1967
  };
1907
1968
  }
1908
1969
  function protocolChanged(cause) {
@@ -2032,7 +2093,7 @@ async function parseCandidateCodexImageResponse(body, expectedCount, expectedFor
2032
2093
  return item;
2033
2094
  });
2034
2095
  const images2 = await Promise.all(rows.map((item) => createAsset(item.b64_json, expectedFormat)));
2035
- const revised2 = rows.length === 1 && typeof _optionalChain([rows, 'access', _106 => _106[0], 'optionalAccess', _107 => _107.revised_prompt]) === "string" ? rows[0].revised_prompt : void 0;
2096
+ const revised2 = rows.length === 1 && typeof _optionalChain([rows, 'access', _115 => _115[0], 'optionalAccess', _116 => _116.revised_prompt]) === "string" ? rows[0].revised_prompt : void 0;
2036
2097
  return {
2037
2098
  images: images2,
2038
2099
  revisedPrompt: revised2,
@@ -2048,7 +2109,7 @@ async function parseCandidateCodexImageResponse(body, expectedCount, expectedFor
2048
2109
  if (call.status !== "completed" || typeof call.result !== "string") return protocolChanged();
2049
2110
  return createAsset(call.result, expectedFormat);
2050
2111
  }));
2051
- const revised = calls.length === 1 && typeof _optionalChain([calls, 'access', _108 => _108[0], 'optionalAccess', _109 => _109.revised_prompt]) === "string" ? calls[0].revised_prompt : void 0;
2112
+ const revised = calls.length === 1 && typeof _optionalChain([calls, 'access', _117 => _117[0], 'optionalAccess', _118 => _118.revised_prompt]) === "string" ? calls[0].revised_prompt : void 0;
2052
2113
  return {
2053
2114
  images,
2054
2115
  revisedPrompt: revised,
@@ -2092,7 +2153,7 @@ async function parseCandidateCodexImageSse(body, expectedCount, expectedFormat)
2092
2153
  }
2093
2154
  }
2094
2155
  }
2095
- const output = _optionalChain([completedResponse, 'optionalAccess', _110 => _110.output]);
2156
+ const output = _optionalChain([completedResponse, 'optionalAccess', _119 => _119.output]);
2096
2157
  const calls = Array.isArray(output) ? output.filter(
2097
2158
  (item) => !!item && typeof item === "object" && !Array.isArray(item) && item.type === "image_generation_call"
2098
2159
  ) : [];
@@ -2103,15 +2164,15 @@ async function parseCandidateCodexImageSse(body, expectedCount, expectedFormat)
2103
2164
  return protocolChanged();
2104
2165
  }
2105
2166
  const images = await Promise.all(Array.from({ length: expectedCount }, async (_unused, index) => {
2106
- const encoded = _nullishCoalesce(_nullishCoalesce(best.get(index), () => ( completedEventResults[index])), () => ( _optionalChain([finalResults, 'access', _111 => _111[index], 'optionalAccess', _112 => _112.result])));
2167
+ const encoded = _nullishCoalesce(_nullishCoalesce(best.get(index), () => ( completedEventResults[index])), () => ( _optionalChain([finalResults, 'access', _120 => _120[index], 'optionalAccess', _121 => _121.result])));
2107
2168
  if (!encoded) return protocolChanged();
2108
2169
  return createAsset(encoded, expectedFormat);
2109
2170
  }));
2110
- const revised = calls.length === 1 && typeof _optionalChain([calls, 'access', _113 => _113[0], 'optionalAccess', _114 => _114.revised_prompt]) === "string" ? calls[0].revised_prompt : void 0;
2171
+ const revised = calls.length === 1 && typeof _optionalChain([calls, 'access', _122 => _122[0], 'optionalAccess', _123 => _123.revised_prompt]) === "string" ? calls[0].revised_prompt : void 0;
2111
2172
  return {
2112
2173
  images,
2113
2174
  revisedPrompt: revised,
2114
- usage: parseUsage(_optionalChain([completedResponse, 'optionalAccess', _115 => _115.usage]))
2175
+ usage: parseUsage(_optionalChain([completedResponse, 'optionalAccess', _124 => _124.usage]))
2115
2176
  };
2116
2177
  }
2117
2178
 
@@ -2266,7 +2327,7 @@ var CodexSubscriptionImageProvider = (_class10 = class {
2266
2327
  }
2267
2328
  schedulerGrantSignal = schedulerGrant.signal;
2268
2329
  if (schedulerGrantSignal) {
2269
- onSchedulerAbort = () => controller.abort(_optionalChain([schedulerGrantSignal, 'optionalAccess', _116 => _116.reason]));
2330
+ onSchedulerAbort = () => controller.abort(_optionalChain([schedulerGrantSignal, 'optionalAccess', _125 => _125.reason]));
2270
2331
  if (schedulerGrantSignal.aborted) onSchedulerAbort();
2271
2332
  else schedulerGrantSignal.addEventListener("abort", onSchedulerAbort, { once: true });
2272
2333
  }
@@ -2550,4 +2611,7 @@ function createCodexImageLiveVerifier(options) {
2550
2611
 
2551
2612
 
2552
2613
 
2553
- exports.DEFAULT_ACCOUNT_PRIORITY = DEFAULT_ACCOUNT_PRIORITY; exports.LAST_USED_PERSIST_THROTTLE_MS = LAST_USED_PERSIST_THROTTLE_MS; exports.SESSION_AFFINITY_TTL_MS = SESSION_AFFINITY_TTL_MS; exports.SubscriptionAccountSelector = SubscriptionAccountSelector; exports.SubscriptionAccountService = SubscriptionAccountService; exports.SubscriptionDispatcher = SubscriptionDispatcher; exports.SubscriptionProviderRegistry = SubscriptionProviderRegistry; exports.claudeOAuth = _chunkUXUMAXZJcjs.claude_exports; exports.codexOAuth = _chunkUXUMAXZJcjs.codex_exports; exports.createCodexImageLiveVerifier = createCodexImageLiveVerifier; exports.createCodexSubscriptionImageProvider = createCodexSubscriptionImageProvider; exports.geminiOAuth = _chunkUXUMAXZJcjs.gemini_exports; exports.getSubscriptionAccountService = getSubscriptionAccountService; exports.getSubscriptionProviderRegistry = getSubscriptionProviderRegistry; exports.setSubscriptionAccountService = setSubscriptionAccountService; exports.setSubscriptionProviderRegistry = setSubscriptionProviderRegistry;
2614
+
2615
+
2616
+
2617
+ exports.DEFAULT_ACCOUNT_PRIORITY = DEFAULT_ACCOUNT_PRIORITY; exports.LAST_USED_PERSIST_THROTTLE_MS = LAST_USED_PERSIST_THROTTLE_MS; exports.SESSION_AFFINITY_TTL_MS = SESSION_AFFINITY_TTL_MS; exports.SubscriptionAccountSelector = SubscriptionAccountSelector; exports.SubscriptionAccountService = SubscriptionAccountService; exports.SubscriptionDispatcher = SubscriptionDispatcher; exports.SubscriptionProviderRegistry = SubscriptionProviderRegistry; exports.claudeOAuth = _chunkB2LHAP4Fcjs.claude_exports; exports.codexOAuth = _chunkB2LHAP4Fcjs.codex_exports; exports.createCodexImageLiveVerifier = createCodexImageLiveVerifier; exports.createCodexSubscriptionImageProvider = createCodexSubscriptionImageProvider; exports.geminiOAuth = _chunkB2LHAP4Fcjs.gemini_exports; exports.getSubscriptionAccountService = getSubscriptionAccountService; exports.getSubscriptionProviderRegistry = getSubscriptionProviderRegistry; exports.kimiFingerprintHeaders = _chunkB2LHAP4Fcjs.kimiFingerprintHeaders; exports.kimiOAuth = _chunkB2LHAP4Fcjs.kimi_exports; exports.normalizeOpenCodeGoBaseUrl = normalizeOpenCodeGoBaseUrl; exports.setSubscriptionAccountService = setSubscriptionAccountService; exports.setSubscriptionProviderRegistry = setSubscriptionProviderRegistry;
package/dist/index.d.cts CHANGED
@@ -9,7 +9,7 @@ import { TransformerChainExecutor } from '@omnicross/core/transformer/Transforme
9
9
  import { TransformerService } from '@omnicross/core/transformer/TransformerService';
10
10
  import { Transformer } from '@omnicross/core/transformer/types';
11
11
  export { FetchLike } from '@omnicross/core/auth/GeminiCodeAssistProjectResolver';
12
- export { claudeOAuth, codexOAuth, geminiOAuth } from './oauth.cjs';
12
+ export { claudeOAuth, codexOAuth, geminiOAuth, kimiFingerprintHeaders, kimiOAuth } from './oauth.cjs';
13
13
  import { ImageProvider } from '@omnicross/core/image-generation';
14
14
  import { ImageCapabilityEvidenceLayer, ImageQuality, ImageBackground, ImageOutputFormat, ImageModeration } from '@omnicross/contracts/image-generation-types';
15
15
 
@@ -49,6 +49,12 @@ interface SubscriptionCredentialStore {
49
49
  refreshCodexToken(): Promise<boolean>;
50
50
  /** Force a Gemini (Google) OAuth token refresh; `true` on success. */
51
51
  refreshGeminiToken(): Promise<boolean>;
52
+ /**
53
+ * Force a Kimi Code OAuth token refresh; `true` on success. OPTIONAL for
54
+ * lightweight test doubles (the kimi strategy catches its absence like a
55
+ * failed refresh) — the daemon's store implements it.
56
+ */
57
+ refreshKimiToken?(): Promise<boolean>;
52
58
  /** Current valid OpenCodeGo static API key; `null` if none. */
53
59
  getValidOpenCodeGoApiKey(): Promise<string | null>;
54
60
  /**
@@ -351,6 +357,23 @@ declare class SubscriptionDispatcher {
351
357
  private buildRequestSummary;
352
358
  }
353
359
 
360
+ /**
361
+ * Default OpenCodeGo upstream URLs (both provider halves).
362
+ *
363
+ * There are two provider halves under the same account key:
364
+ * - GO (`opencode-go`): `https://opencode.ai/zen/go/v1/...` — chat + anthropic.
365
+ * - ZEN (`opencode-zen`): `https://opencode.ai/zen/v1/...` — chat + anthropic
366
+ * + responses + gemini (per-model colon-method).
367
+ *
368
+ * The user may override each half's host independently:
369
+ * - `OpenCodeGoTokenConfig.baseUrl` → GO half.
370
+ * - `OpenCodeGoTokenConfig.zenBaseUrl` → ZEN half.
371
+ * A go-half override NEVER redirects zen traffic and vice-versa.
372
+ */
373
+
374
+ /** Strip a trailing slash and `/v1[/]*` suffix from a user override host. */
375
+ declare function normalizeOpenCodeGoBaseUrl(base: string): string;
376
+
354
377
  /** Safe evidence request; accountId is trusted-process input and must not be logged. */
355
378
  interface CodexImageCapabilityEvidenceRequest {
356
379
  readonly accountId: string;
@@ -445,4 +468,4 @@ interface CodexImageLiveVerifier {
445
468
  }
446
469
  declare function createCodexImageLiveVerifier(options: CodexImageLiveVerifierOptions): CodexImageLiveVerifier;
447
470
 
448
- export { type CodexImageCapabilityEvidence, type CodexImageCapabilityEvidenceRequest, type CodexImageCapabilityEvidenceSource, type CodexImageCapabilityObservation, type CodexImageCapabilityObservedResponseFields, type CodexImageCapabilityTestedRequest, type CodexImageLiveVerificationRequest, type CodexImageLiveVerifier, type CodexImageLiveVerifierOptions, type CodexSubscriptionImageProviderOptions, DEFAULT_ACCOUNT_PRIORITY, type DispatchRequest, type DispatcherHooks, type ImageExecutionAccountKey, type ImageExecutionScheduler, type ImageExecutionSchedulerGrant, type ImageExecutionSchedulerRequest, LAST_USED_PERSIST_THROTTLE_MS, SESSION_AFFINITY_TTL_MS, type SchedulableAccount, type SelectInput, type SelectResult, SubscriptionAccountSelector, SubscriptionAccountService, type SubscriptionCredentialStore, SubscriptionDispatcher, SubscriptionProviderRegistry, createCodexImageLiveVerifier, createCodexSubscriptionImageProvider, getSubscriptionAccountService, getSubscriptionProviderRegistry, setSubscriptionAccountService, setSubscriptionProviderRegistry };
471
+ export { type CodexImageCapabilityEvidence, type CodexImageCapabilityEvidenceRequest, type CodexImageCapabilityEvidenceSource, type CodexImageCapabilityObservation, type CodexImageCapabilityObservedResponseFields, type CodexImageCapabilityTestedRequest, type CodexImageLiveVerificationRequest, type CodexImageLiveVerifier, type CodexImageLiveVerifierOptions, type CodexSubscriptionImageProviderOptions, DEFAULT_ACCOUNT_PRIORITY, type DispatchRequest, type DispatcherHooks, type ImageExecutionAccountKey, type ImageExecutionScheduler, type ImageExecutionSchedulerGrant, type ImageExecutionSchedulerRequest, LAST_USED_PERSIST_THROTTLE_MS, SESSION_AFFINITY_TTL_MS, type SchedulableAccount, type SelectInput, type SelectResult, SubscriptionAccountSelector, SubscriptionAccountService, type SubscriptionCredentialStore, SubscriptionDispatcher, SubscriptionProviderRegistry, createCodexImageLiveVerifier, createCodexSubscriptionImageProvider, getSubscriptionAccountService, getSubscriptionProviderRegistry, normalizeOpenCodeGoBaseUrl, setSubscriptionAccountService, setSubscriptionProviderRegistry };
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ import { TransformerChainExecutor } from '@omnicross/core/transformer/Transforme
9
9
  import { TransformerService } from '@omnicross/core/transformer/TransformerService';
10
10
  import { Transformer } from '@omnicross/core/transformer/types';
11
11
  export { FetchLike } from '@omnicross/core/auth/GeminiCodeAssistProjectResolver';
12
- export { claudeOAuth, codexOAuth, geminiOAuth } from './oauth.js';
12
+ export { claudeOAuth, codexOAuth, geminiOAuth, kimiFingerprintHeaders, kimiOAuth } from './oauth.js';
13
13
  import { ImageProvider } from '@omnicross/core/image-generation';
14
14
  import { ImageCapabilityEvidenceLayer, ImageQuality, ImageBackground, ImageOutputFormat, ImageModeration } from '@omnicross/contracts/image-generation-types';
15
15
 
@@ -49,6 +49,12 @@ interface SubscriptionCredentialStore {
49
49
  refreshCodexToken(): Promise<boolean>;
50
50
  /** Force a Gemini (Google) OAuth token refresh; `true` on success. */
51
51
  refreshGeminiToken(): Promise<boolean>;
52
+ /**
53
+ * Force a Kimi Code OAuth token refresh; `true` on success. OPTIONAL for
54
+ * lightweight test doubles (the kimi strategy catches its absence like a
55
+ * failed refresh) — the daemon's store implements it.
56
+ */
57
+ refreshKimiToken?(): Promise<boolean>;
52
58
  /** Current valid OpenCodeGo static API key; `null` if none. */
53
59
  getValidOpenCodeGoApiKey(): Promise<string | null>;
54
60
  /**
@@ -351,6 +357,23 @@ declare class SubscriptionDispatcher {
351
357
  private buildRequestSummary;
352
358
  }
353
359
 
360
+ /**
361
+ * Default OpenCodeGo upstream URLs (both provider halves).
362
+ *
363
+ * There are two provider halves under the same account key:
364
+ * - GO (`opencode-go`): `https://opencode.ai/zen/go/v1/...` — chat + anthropic.
365
+ * - ZEN (`opencode-zen`): `https://opencode.ai/zen/v1/...` — chat + anthropic
366
+ * + responses + gemini (per-model colon-method).
367
+ *
368
+ * The user may override each half's host independently:
369
+ * - `OpenCodeGoTokenConfig.baseUrl` → GO half.
370
+ * - `OpenCodeGoTokenConfig.zenBaseUrl` → ZEN half.
371
+ * A go-half override NEVER redirects zen traffic and vice-versa.
372
+ */
373
+
374
+ /** Strip a trailing slash and `/v1[/]*` suffix from a user override host. */
375
+ declare function normalizeOpenCodeGoBaseUrl(base: string): string;
376
+
354
377
  /** Safe evidence request; accountId is trusted-process input and must not be logged. */
355
378
  interface CodexImageCapabilityEvidenceRequest {
356
379
  readonly accountId: string;
@@ -445,4 +468,4 @@ interface CodexImageLiveVerifier {
445
468
  }
446
469
  declare function createCodexImageLiveVerifier(options: CodexImageLiveVerifierOptions): CodexImageLiveVerifier;
447
470
 
448
- export { type CodexImageCapabilityEvidence, type CodexImageCapabilityEvidenceRequest, type CodexImageCapabilityEvidenceSource, type CodexImageCapabilityObservation, type CodexImageCapabilityObservedResponseFields, type CodexImageCapabilityTestedRequest, type CodexImageLiveVerificationRequest, type CodexImageLiveVerifier, type CodexImageLiveVerifierOptions, type CodexSubscriptionImageProviderOptions, DEFAULT_ACCOUNT_PRIORITY, type DispatchRequest, type DispatcherHooks, type ImageExecutionAccountKey, type ImageExecutionScheduler, type ImageExecutionSchedulerGrant, type ImageExecutionSchedulerRequest, LAST_USED_PERSIST_THROTTLE_MS, SESSION_AFFINITY_TTL_MS, type SchedulableAccount, type SelectInput, type SelectResult, SubscriptionAccountSelector, SubscriptionAccountService, type SubscriptionCredentialStore, SubscriptionDispatcher, SubscriptionProviderRegistry, createCodexImageLiveVerifier, createCodexSubscriptionImageProvider, getSubscriptionAccountService, getSubscriptionProviderRegistry, setSubscriptionAccountService, setSubscriptionProviderRegistry };
471
+ export { type CodexImageCapabilityEvidence, type CodexImageCapabilityEvidenceRequest, type CodexImageCapabilityEvidenceSource, type CodexImageCapabilityObservation, type CodexImageCapabilityObservedResponseFields, type CodexImageCapabilityTestedRequest, type CodexImageLiveVerificationRequest, type CodexImageLiveVerifier, type CodexImageLiveVerifierOptions, type CodexSubscriptionImageProviderOptions, DEFAULT_ACCOUNT_PRIORITY, type DispatchRequest, type DispatcherHooks, type ImageExecutionAccountKey, type ImageExecutionScheduler, type ImageExecutionSchedulerGrant, type ImageExecutionSchedulerRequest, LAST_USED_PERSIST_THROTTLE_MS, SESSION_AFFINITY_TTL_MS, type SchedulableAccount, type SelectInput, type SelectResult, SubscriptionAccountSelector, SubscriptionAccountService, type SubscriptionCredentialStore, SubscriptionDispatcher, SubscriptionProviderRegistry, createCodexImageLiveVerifier, createCodexSubscriptionImageProvider, getSubscriptionAccountService, getSubscriptionProviderRegistry, normalizeOpenCodeGoBaseUrl, setSubscriptionAccountService, setSubscriptionProviderRegistry };