@eddyskywalker/dsh-chatgpt-subscription 0.3.9 → 0.4.0

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/lib/client.js +386 -99
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +711 -102
  5. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  6. package/lib/types/client/antigravity/AntigravitySection.d.ts.map +1 -1
  7. package/lib/types/client/antigravity/locales.d.ts +78 -0
  8. package/lib/types/client/antigravity/locales.d.ts.map +1 -1
  9. package/lib/types/client/antigravity/styles.d.ts.map +1 -1
  10. package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -1
  11. package/lib/types/client/command-code/locales.d.ts +12 -6
  12. package/lib/types/client/command-code/locales.d.ts.map +1 -1
  13. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  14. package/lib/types/client/kimi-code/locales.d.ts +12 -6
  15. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  16. package/lib/types/client/locales.d.ts +9 -3
  17. package/lib/types/client/locales.d.ts.map +1 -1
  18. package/lib/types/host/antigravity/account-pool.d.ts +50 -0
  19. package/lib/types/host/antigravity/account-pool.d.ts.map +1 -0
  20. package/lib/types/host/antigravity/adapter.d.ts +3 -1
  21. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  22. package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
  23. package/lib/types/host/antigravity/oauth.d.ts +1 -1
  24. package/lib/types/host/antigravity/oauth.d.ts.map +1 -1
  25. package/lib/types/host/antigravity/routes.d.ts +3 -2
  26. package/lib/types/host/antigravity/routes.d.ts.map +1 -1
  27. package/lib/types/host/antigravity/token-store.d.ts +3 -0
  28. package/lib/types/host/antigravity/token-store.d.ts.map +1 -1
  29. package/lib/types/host/command-code/adapter.d.ts.map +1 -1
  30. package/lib/types/host/command-code/mapper.d.ts.map +1 -1
  31. package/lib/types/host/command-code/routes.d.ts +1 -1
  32. package/lib/types/host/command-code/routes.d.ts.map +1 -1
  33. package/lib/types/host/command-code/token-store.d.ts +3 -0
  34. package/lib/types/host/command-code/token-store.d.ts.map +1 -1
  35. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  36. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  37. package/lib/types/host/kimi-code/routes.d.ts +1 -1
  38. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  39. package/lib/types/host/kimi-code/token-store.d.ts +3 -0
  40. package/lib/types/host/kimi-code/token-store.d.ts.map +1 -1
  41. package/lib/types/host/model-catalog.d.ts.map +1 -1
  42. package/lib/types/host/preferences.d.ts.map +1 -1
  43. package/lib/types/host/token-store-windows.d.ts.map +1 -1
  44. package/lib/types/index.d.ts +1 -0
  45. package/lib/types/index.d.ts.map +1 -1
  46. package/lib/types/shared/antigravity-contracts.d.ts +18 -0
  47. package/lib/types/shared/antigravity-contracts.d.ts.map +1 -1
  48. package/lib/types/shared/command-code-contracts.d.ts +2 -0
  49. package/lib/types/shared/command-code-contracts.d.ts.map +1 -1
  50. package/lib/types/shared/contracts.d.ts +2 -0
  51. package/lib/types/shared/contracts.d.ts.map +1 -1
  52. package/lib/types/shared/kimi-code-contracts.d.ts +2 -0
  53. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
  54. package/lib/types/shared/preferences.d.ts.map +1 -1
  55. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -192,7 +192,9 @@ function resolveCodexFallbackModel(model) {
192
192
  const PROVIDER_ID$3 = CODEX_CHATGPT_PROVIDER_ID;
193
193
  const PROVIDER_NAME$3 = "Codex(ChatGPT 订阅)";
194
194
  function listCodexModels(preferences) {
195
- const visible = new Set(preferences?.status().visibleModelIds ?? CODEX_MODEL_CATALOG.map((entry) => entry.id));
195
+ const status = preferences?.status();
196
+ if (status?.enabled === false) return [];
197
+ const visible = new Set(status?.visibleModelIds ?? CODEX_MODEL_CATALOG.map((entry) => entry.id));
196
198
  return CODEX_MODEL_CATALOG.filter((entry) => visible.has(entry.id)).map((entry) => ({
197
199
  provider: PROVIDER_ID$3,
198
200
  id: entry.id,
@@ -1597,6 +1599,7 @@ var ProxyManager = class {
1597
1599
  //#region src/shared/preferences.ts
1598
1600
  const PREFERENCES_NAMESPACE = "dsh-chatgpt-subscription";
1599
1601
  const DEFAULT_PREFERENCES = {
1602
+ enabled: true,
1600
1603
  quickQuotaVisible: false,
1601
1604
  fastMode: false,
1602
1605
  outputVerbosity: null,
@@ -1630,6 +1633,7 @@ function isProxyMode(value) {
1630
1633
  function registerPreferenceStore(settings) {
1631
1634
  const ns = SettingsModule.settingsNamespace ? SettingsModule.settingsNamespace(PREFERENCES_NAMESPACE) : PREFERENCES_NAMESPACE;
1632
1635
  return new SettingsPreferenceStore(settings.register.call(settings, ns, z.object({
1636
+ enabled: z.boolean().default(DEFAULT_PREFERENCES.enabled ?? true),
1633
1637
  quickQuotaVisible: z.boolean().default(DEFAULT_PREFERENCES.quickQuotaVisible),
1634
1638
  fastMode: z.boolean().default(DEFAULT_PREFERENCES.fastMode),
1635
1639
  outputVerbosity: z.union([
@@ -1671,6 +1675,7 @@ var SettingsPreferenceStore = class {
1671
1675
  }
1672
1676
  async update(patch) {
1673
1677
  const normalized = {};
1678
+ if (patch.enabled !== void 0) normalized.enabled = patch.enabled;
1674
1679
  if (patch.quickQuotaVisible !== void 0) normalized.quickQuotaVisible = patch.quickQuotaVisible;
1675
1680
  if (patch.fastMode !== void 0) normalized.fastMode = patch.fastMode;
1676
1681
  if (patch.outputVerbosity !== void 0) {
@@ -1682,7 +1687,7 @@ var SettingsPreferenceStore = class {
1682
1687
  normalized.reasoningSummary = patch.reasoningSummary;
1683
1688
  }
1684
1689
  if (patch.visibleModelIds !== void 0) {
1685
- if (patch.visibleModelIds.length === 0 || !patch.visibleModelIds.every(isCodexModelId)) throw new PreferenceError("At least one supported Codex model must be visible.");
1690
+ if (!patch.visibleModelIds.every(isCodexModelId)) throw new PreferenceError("Unsupported Codex model.");
1686
1691
  normalized.visibleModelIds = [...new Set(patch.visibleModelIds)];
1687
1692
  }
1688
1693
  if (patch.searchProvider !== void 0) {
@@ -3435,8 +3440,12 @@ function isRecord$6(value) {
3435
3440
  }
3436
3441
  function readPreferencesUpdate(value, current) {
3437
3442
  const patch = {};
3443
+ if ("enabled" in value) {
3444
+ if (typeof value.enabled !== "boolean") throw new PreferenceError("enabled must be a boolean.");
3445
+ patch.enabled = value.enabled;
3446
+ }
3438
3447
  if ("visibleModelIds" in value) {
3439
- if (!Array.isArray(value.visibleModelIds) || value.visibleModelIds.length === 0 || !value.visibleModelIds.every(isCodexModelId)) throw new PreferenceError("visibleModelIds must contain at least one supported Codex model.");
3448
+ if (!Array.isArray(value.visibleModelIds) || !value.visibleModelIds.every(isCodexModelId)) throw new PreferenceError("visibleModelIds must be an array of supported Codex models.");
3440
3449
  patch.visibleModelIds = [...new Set(value.visibleModelIds)];
3441
3450
  }
3442
3451
  if ("quickQuotaVisible" in value) {
@@ -3730,6 +3739,9 @@ function isMissing(error) {
3730
3739
  //#region src/host/token-store-windows.ts
3731
3740
  const PROTECT_SCRIPT = String.raw`
3732
3741
  $ErrorActionPreference = 'Stop'
3742
+ [Console]::InputEncoding = [Text.Encoding]::UTF8
3743
+ [Console]::OutputEncoding = [Text.Encoding]::UTF8
3744
+ $OutputEncoding = [Text.Encoding]::UTF8
3733
3745
  Add-Type -AssemblyName System.Security
3734
3746
  $path = $env:DSH_CODEX_TOKEN_PATH
3735
3747
  $plain = [Console]::In.ReadToEnd()
@@ -3751,6 +3763,9 @@ try {
3751
3763
  `;
3752
3764
  const UNPROTECT_SCRIPT = String.raw`
3753
3765
  $ErrorActionPreference = 'Stop'
3766
+ [Console]::InputEncoding = [Text.Encoding]::UTF8
3767
+ [Console]::OutputEncoding = [Text.Encoding]::UTF8
3768
+ $OutputEncoding = [Text.Encoding]::UTF8
3754
3769
  Add-Type -AssemblyName System.Security
3755
3770
  $path = $env:DSH_CODEX_TOKEN_PATH
3756
3771
  if (-not [IO.File]::Exists($path)) { exit 3 }
@@ -4358,6 +4373,7 @@ const ANTIGRAVITY_PREFERENCES_NAMESPACE = "dsh-antigravity";
4358
4373
  function registerAntigravityPreferenceStore(settings, fallbackStore = new FileModelSettingsStore$1()) {
4359
4374
  if (!settings) return {
4360
4375
  status: () => ({
4376
+ enabled: true,
4361
4377
  enabledModelIds: MODELS.map((m) => m.id),
4362
4378
  catalogModels: [],
4363
4379
  contextWindowOverrides: {},
@@ -4367,6 +4383,7 @@ function registerAntigravityPreferenceStore(settings, fallbackStore = new FileMo
4367
4383
  };
4368
4384
  const ns = SettingsModule.settingsNamespace ? SettingsModule.settingsNamespace(ANTIGRAVITY_PREFERENCES_NAMESPACE) : ANTIGRAVITY_PREFERENCES_NAMESPACE;
4369
4385
  const scope = settings.register.call(settings, ns, z.object({
4386
+ enabled: z.boolean().default(true),
4370
4387
  enabledModelIds: z.array(z.string()).default(MODELS.map((m) => m.id)),
4371
4388
  contextWindowOverrides: z.dict(z.number()).default({}),
4372
4389
  defaultReasoningEffort: z.union([
@@ -4380,6 +4397,7 @@ function registerAntigravityPreferenceStore(settings, fallbackStore = new FileMo
4380
4397
  status: () => {
4381
4398
  const val = scope.get();
4382
4399
  return {
4400
+ enabled: val.enabled !== false,
4383
4401
  enabledModelIds: val.enabledModelIds,
4384
4402
  catalogModels: [],
4385
4403
  contextWindowOverrides: val.contextWindowOverrides,
@@ -4389,6 +4407,7 @@ function registerAntigravityPreferenceStore(settings, fallbackStore = new FileMo
4389
4407
  update: async (patch) => {
4390
4408
  const current = scope.get();
4391
4409
  const normalized = {
4410
+ enabled: patch.enabled !== void 0 ? patch.enabled : current.enabled !== false,
4392
4411
  enabledModelIds: patch.enabledModelIds ?? current.enabledModelIds,
4393
4412
  contextWindowOverrides: patch.contextWindowOverrides ? {
4394
4413
  ...current.contextWindowOverrides,
@@ -4534,15 +4553,21 @@ var FileModelSettingsStore$1 = class {
4534
4553
  const parsed = JSON.parse(content);
4535
4554
  if (typeof parsed === "object" && parsed !== null) {
4536
4555
  const record = parsed;
4556
+ const enabledModelIds = Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : MODELS.map((m) => m.id);
4557
+ const catalogModels = Array.isArray(record.catalogModels) ? record.catalogModels : [];
4558
+ const contextWindowOverrides = typeof record.contextWindowOverrides === "object" && record.contextWindowOverrides !== null ? record.contextWindowOverrides : {};
4559
+ const defaultReasoningEffort = record.defaultReasoningEffort === "low" || record.defaultReasoningEffort === "medium" || record.defaultReasoningEffort === "high" ? record.defaultReasoningEffort : null;
4537
4560
  return {
4538
- enabledModelIds: Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : MODELS.map((m) => m.id),
4539
- catalogModels: Array.isArray(record.catalogModels) ? record.catalogModels : [],
4540
- contextWindowOverrides: typeof record.contextWindowOverrides === "object" && record.contextWindowOverrides !== null ? record.contextWindowOverrides : {},
4541
- defaultReasoningEffort: record.defaultReasoningEffort === "low" || record.defaultReasoningEffort === "medium" || record.defaultReasoningEffort === "high" ? record.defaultReasoningEffort : null
4561
+ enabled: record.enabled !== false,
4562
+ enabledModelIds,
4563
+ catalogModels,
4564
+ contextWindowOverrides,
4565
+ defaultReasoningEffort
4542
4566
  };
4543
4567
  }
4544
4568
  } catch {}
4545
4569
  return {
4570
+ enabled: true,
4546
4571
  enabledModelIds: MODELS.map((m) => m.id),
4547
4572
  catalogModels: [],
4548
4573
  contextWindowOverrides: {},
@@ -4559,6 +4584,7 @@ var FileModelSettingsStore$1 = class {
4559
4584
  const current = await this.read();
4560
4585
  const next = {
4561
4586
  ...current,
4587
+ ...patch.enabled !== void 0 ? { enabled: patch.enabled } : {},
4562
4588
  ...patch.enabledModelIds !== void 0 ? { enabledModelIds: patch.enabledModelIds } : {},
4563
4589
  ...patch.contextWindowOverrides !== void 0 ? { contextWindowOverrides: {
4564
4590
  ...current.contextWindowOverrides || {},
@@ -5065,7 +5091,7 @@ async function exchangeOAuthCode(code, verifier, callbackUrl, fetchFn = fetch, s
5065
5091
  email
5066
5092
  };
5067
5093
  }
5068
- async function beginWebLogin$1(store, fetchFn = fetch, signal) {
5094
+ async function beginWebLogin$1(store, fetchFn = fetch, signal, onSave) {
5069
5095
  if (webLoginFlow$2.status === "pending") return { ...webLoginFlow$2 };
5070
5096
  const { verifier, challenge } = generatePKCE();
5071
5097
  const state = base64Url(randomBytes(32));
@@ -5097,6 +5123,7 @@ async function beginWebLogin$1(store, fetchFn = fetch, signal) {
5097
5123
  webLoginFlow$2.progress = stage;
5098
5124
  });
5099
5125
  await store.write(credentials);
5126
+ if (onSave) await onSave(credentials).catch(() => void 0);
5100
5127
  webLoginFlow$2.status = "complete";
5101
5128
  webLoginFlow$2.email = credentials.email;
5102
5129
  webLoginFlow$2.completedAt = Date.now();
@@ -5317,9 +5344,13 @@ function attachmentLabel$2(block) {
5317
5344
  function collectImageRefs$2(content, refs) {
5318
5345
  if (!Array.isArray(content)) return;
5319
5346
  for (const block of content) {
5320
- if (!isRecord$4(block) || block.type !== "image") continue;
5321
- const attachment = attachmentOf$2(block);
5322
- if (attachment) refs.set(attachment.attachmentId, attachment);
5347
+ if (!isRecord$4(block)) continue;
5348
+ if (block.type === "image") {
5349
+ const attachment = attachmentOf$2(block);
5350
+ if (attachment) refs.set(attachment.attachmentId, attachment);
5351
+ continue;
5352
+ }
5353
+ if (block.type === "tool-result") collectImageRefs$2(block.content, refs);
5323
5354
  }
5324
5355
  }
5325
5356
  function isAbort$2(error, signal) {
@@ -5488,6 +5519,24 @@ function contentToUserParts(content, images) {
5488
5519
  }
5489
5520
  return parts;
5490
5521
  }
5522
+ /**
5523
+ * Image parts for one tool result, flattened the same way so a nested
5524
+ * `tool-result` cannot hide one. Gemini's `functionResponse` has nowhere to put
5525
+ * an image, so these become `inlineData` siblings on the same user content.
5526
+ */
5527
+ function toolResultImageParts(blocks, images) {
5528
+ if (!Array.isArray(blocks)) return [];
5529
+ const parts = [];
5530
+ for (const block of blocks) {
5531
+ if (!isRecord$4(block)) continue;
5532
+ if (block.type === "image") {
5533
+ parts.push(imageBlockToPart(block, images) ?? { text: unavailableImageText$2(block) });
5534
+ continue;
5535
+ }
5536
+ if (block.type === "tool-result") parts.push(...toolResultImageParts(block.content, images));
5537
+ }
5538
+ return parts;
5539
+ }
5491
5540
  function toolResultText$2(blocks) {
5492
5541
  if (!Array.isArray(blocks)) return "";
5493
5542
  return blocks.map((block) => {
@@ -5573,7 +5622,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
5573
5622
  }
5574
5623
  return parts;
5575
5624
  }
5576
- function pushToolResult(contents, result, toolCalls, model, runtimeModel) {
5625
+ function pushToolResult(contents, result, toolCalls, model, runtimeModel, images = NO_RESOLVED_IMAGES$2) {
5577
5626
  const toolCallId = String(result.toolCallId || "");
5578
5627
  const call = toolCalls.get(toolCallId);
5579
5628
  const toolName = call?.name || "unknown";
@@ -5584,11 +5633,12 @@ function pushToolResult(contents, result, toolCalls, model, runtimeModel) {
5584
5633
  response: result.isError ? { error: responseText } : { output: responseText },
5585
5634
  ...wireId ? { id: wireId } : {}
5586
5635
  } };
5636
+ const extraParts = toolResultImageParts(result.content, images);
5587
5637
  const last = contents[contents.length - 1];
5588
- if (last?.role === GEMINI_ROLE.user && last.parts.some((entry) => "functionResponse" in entry)) last.parts.push(part);
5638
+ if (last?.role === GEMINI_ROLE.user && last.parts.some((entry) => "functionResponse" in entry)) last.parts.push(part, ...extraParts);
5589
5639
  else contents.push({
5590
5640
  role: GEMINI_ROLE.user,
5591
- parts: [part]
5641
+ parts: [part, ...extraParts]
5592
5642
  });
5593
5643
  }
5594
5644
  function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAGES$2) {
@@ -5617,7 +5667,7 @@ function convertMessages(options, model, runtimeModel, images = NO_RESOLVED_IMAG
5617
5667
  role: GEMINI_ROLE.user,
5618
5668
  parts: userParts
5619
5669
  });
5620
- for (const b of content) if (isRecord$4(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel);
5670
+ for (const b of content) if (isRecord$4(b) && b.type === "tool-result") pushToolResult(contents, b, toolCalls, model, runtimeModel, images);
5621
5671
  }
5622
5672
  return contents;
5623
5673
  }
@@ -5904,6 +5954,259 @@ function closeStream$2(state) {
5904
5954
  return out;
5905
5955
  }
5906
5956
  //#endregion
5957
+ //#region src/host/antigravity/account-pool.ts
5958
+ function poolPath() {
5959
+ return path.join(dshHomeDir(), "storages", "antigravity-pool.json");
5960
+ }
5961
+ function parseAntigravityPoolData(value) {
5962
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("Antigravity pool payload is invalid");
5963
+ const record = value;
5964
+ const strategy = record.rotationStrategy === "round-robin" ? "round-robin" : "sequential";
5965
+ const activeAccountId = typeof record.activeAccountId === "string" ? record.activeAccountId : void 0;
5966
+ const rawAccounts = Array.isArray(record.accounts) ? record.accounts : [];
5967
+ const accounts = [];
5968
+ for (const item of rawAccounts) {
5969
+ if (typeof item !== "object" || item === null) continue;
5970
+ const r = item;
5971
+ if (typeof r.id !== "string") continue;
5972
+ const credentials = parseAntigravityCredentials(r.credentials);
5973
+ const acc = {
5974
+ id: r.id,
5975
+ alias: typeof r.alias === "string" ? r.alias : credentials.email || "账号",
5976
+ credentials,
5977
+ addedAt: typeof r.addedAt === "number" ? r.addedAt : Date.now(),
5978
+ isPrimary: r.isPrimary === true
5979
+ };
5980
+ if (typeof r.email === "string") acc.email = r.email;
5981
+ else if (credentials.email) acc.email = credentials.email;
5982
+ if (typeof r.projectId === "string") acc.projectId = r.projectId;
5983
+ else if (credentials.projectId) acc.projectId = credentials.projectId;
5984
+ if (typeof r.planLabel === "string") acc.planLabel = r.planLabel;
5985
+ if (typeof r.lastUsedAt === "number") acc.lastUsedAt = r.lastUsedAt;
5986
+ if (typeof r.cooldownUntil === "number") acc.cooldownUntil = r.cooldownUntil;
5987
+ if (typeof r.cooldownReason === "string") acc.cooldownReason = r.cooldownReason;
5988
+ accounts.push(acc);
5989
+ }
5990
+ const res = {
5991
+ version: 1,
5992
+ rotationStrategy: strategy,
5993
+ accounts
5994
+ };
5995
+ if (activeAccountId) res.activeAccountId = activeAccountId;
5996
+ return res;
5997
+ }
5998
+ function poolCredentialAccount(filePath) {
5999
+ return createHash("sha256").update(path.resolve(filePath)).digest("hex");
6000
+ }
6001
+ function createPoolCredentialBackend(filePath) {
6002
+ if (process.platform === "win32") return new WindowsDpapiCredentialStore(`${filePath}.dpapi`, parseAntigravityPoolData);
6003
+ if (process.platform === "darwin") return new MacKeychainCredentialStore("dsh-antigravity-pool", poolCredentialAccount(filePath), parseAntigravityPoolData);
6004
+ if (process.platform === "linux") return new SecretServiceCredentialStore("dsh-antigravity-pool", poolCredentialAccount(filePath), parseAntigravityPoolData);
6005
+ throw new Error("Antigravity pool encrypted storage requires Windows, macOS, or Linux.");
6006
+ }
6007
+ const poolOperations = /* @__PURE__ */ new Map();
6008
+ var AccountPoolStore = class {
6009
+ filePath;
6010
+ backend;
6011
+ legacyStore;
6012
+ constructor(filePath = poolPath(), backend = createPoolCredentialBackend(filePath), legacyStore = new FileCredentialStore$1()) {
6013
+ this.filePath = filePath;
6014
+ this.backend = backend;
6015
+ this.legacyStore = legacyStore;
6016
+ }
6017
+ path() {
6018
+ if (process.platform === "win32") return `${this.filePath}.dpapi`;
6019
+ return `${process.platform === "darwin" ? "Keychain" : "Secret Service"}: dsh-antigravity-pool/${poolCredentialAccount(this.filePath)}`;
6020
+ }
6021
+ serialize(operation) {
6022
+ const key = path.resolve(this.filePath);
6023
+ const result = (poolOperations.get(key) || Promise.resolve()).then(operation);
6024
+ const settled = result.then(() => void 0, () => void 0);
6025
+ poolOperations.set(key, settled);
6026
+ settled.then(() => {
6027
+ if (poolOperations.get(key) === settled) poolOperations.delete(key);
6028
+ });
6029
+ return result;
6030
+ }
6031
+ async saveVerified(data) {
6032
+ const normalized = parseAntigravityPoolData(data);
6033
+ await this.backend.save(normalized);
6034
+ if (!isDeepStrictEqual(await this.backend.load(), normalized)) throw new Error("Antigravity pool encrypted verification failed");
6035
+ }
6036
+ read() {
6037
+ return this.serialize(async () => {
6038
+ let current = null;
6039
+ try {
6040
+ current = await this.backend.load();
6041
+ } catch {}
6042
+ if (current !== null && Array.isArray(current.accounts) && current.accounts.length > 0) return current;
6043
+ try {
6044
+ const legacy = await this.legacyStore.read();
6045
+ if (legacy && (legacy.access || legacy.access_token || legacy.refresh || legacy.refresh_token)) {
6046
+ const defaultAccount = {
6047
+ id: "acc_primary",
6048
+ alias: legacy.email || "主账号",
6049
+ email: legacy.email,
6050
+ projectId: legacy.projectId,
6051
+ credentials: legacy,
6052
+ addedAt: Date.now(),
6053
+ isPrimary: true
6054
+ };
6055
+ return {
6056
+ version: 1,
6057
+ activeAccountId: "acc_primary",
6058
+ rotationStrategy: current?.rotationStrategy || "sequential",
6059
+ accounts: [defaultAccount]
6060
+ };
6061
+ }
6062
+ } catch {}
6063
+ return current || {
6064
+ version: 1,
6065
+ rotationStrategy: "sequential",
6066
+ accounts: []
6067
+ };
6068
+ });
6069
+ }
6070
+ write(data) {
6071
+ return this.serialize(() => this.saveVerified(parseAntigravityPoolData(data)));
6072
+ }
6073
+ async listAccounts() {
6074
+ const data = await this.read();
6075
+ const now = Date.now();
6076
+ return data.accounts.map((acc) => {
6077
+ const expires = acc.credentials.expires || acc.credentials.expires_at;
6078
+ return {
6079
+ id: acc.id,
6080
+ alias: acc.alias,
6081
+ email: acc.email,
6082
+ projectId: acc.projectId,
6083
+ planLabel: acc.planLabel,
6084
+ isPrimary: acc.isPrimary === true,
6085
+ lastUsedAt: acc.lastUsedAt,
6086
+ cooldownUntil: acc.cooldownUntil && acc.cooldownUntil > now ? acc.cooldownUntil : void 0,
6087
+ cooldownReason: acc.cooldownUntil && acc.cooldownUntil > now ? acc.cooldownReason : void 0,
6088
+ expiresAt: expires
6089
+ };
6090
+ });
6091
+ }
6092
+ async addAccount(credentials, alias) {
6093
+ const data = await this.read();
6094
+ const email = credentials.email;
6095
+ const existingIndex = email ? data.accounts.findIndex((a) => a.email === email) : -1;
6096
+ const id = existingIndex >= 0 ? data.accounts[existingIndex].id : `acc_${randomBytes(6).toString("hex")}`;
6097
+ const isPrimary = data.accounts.length === 0 || existingIndex >= 0 && data.accounts[existingIndex].isPrimary;
6098
+ const account = {
6099
+ id,
6100
+ alias: alias?.trim() || email || `账号 ${data.accounts.length + 1}`,
6101
+ email,
6102
+ projectId: credentials.projectId,
6103
+ credentials,
6104
+ addedAt: Date.now(),
6105
+ isPrimary: !!isPrimary
6106
+ };
6107
+ if (existingIndex >= 0) data.accounts[existingIndex] = {
6108
+ ...data.accounts[existingIndex],
6109
+ ...account,
6110
+ isPrimary: data.accounts[existingIndex].isPrimary
6111
+ };
6112
+ else data.accounts.push(account);
6113
+ if (!data.activeAccountId || account.isPrimary) data.activeAccountId = account.id;
6114
+ await this.write(data);
6115
+ if (account.isPrimary) this.legacyStore.write(credentials).catch(() => void 0);
6116
+ return account;
6117
+ }
6118
+ async setPrimary(accountId) {
6119
+ const data = await this.read();
6120
+ for (const a of data.accounts) a.isPrimary = a.id === accountId;
6121
+ const primary = data.accounts.find((a) => a.isPrimary);
6122
+ if (primary) {
6123
+ data.activeAccountId = primary.id;
6124
+ this.legacyStore.write(primary.credentials).catch(() => void 0);
6125
+ }
6126
+ await this.write(data);
6127
+ }
6128
+ async setAlias(accountId, alias) {
6129
+ const data = await this.read();
6130
+ const target = data.accounts.find((a) => a.id === accountId);
6131
+ if (target && alias.trim()) {
6132
+ target.alias = alias.trim();
6133
+ await this.write(data);
6134
+ }
6135
+ }
6136
+ async deleteAccount(accountId) {
6137
+ const data = await this.read();
6138
+ const wasPrimary = data.accounts.find((a) => a.id === accountId)?.isPrimary;
6139
+ data.accounts = data.accounts.filter((a) => a.id !== accountId);
6140
+ if (wasPrimary && data.accounts.length > 0) {
6141
+ data.accounts[0].isPrimary = true;
6142
+ this.legacyStore.write(data.accounts[0].credentials).catch(() => void 0);
6143
+ } else if (data.accounts.length === 0) this.legacyStore.delete().catch(() => void 0);
6144
+ if (data.activeAccountId === accountId) data.activeAccountId = data.accounts.find((a) => a.isPrimary)?.id ?? data.accounts[0]?.id;
6145
+ await this.write(data);
6146
+ }
6147
+ async setStrategy(strategy) {
6148
+ const data = await this.read();
6149
+ data.rotationStrategy = strategy;
6150
+ await this.write(data);
6151
+ }
6152
+ async markCooldown(accountId, durationMs, reason) {
6153
+ const data = await this.read();
6154
+ const target = data.accounts.find((a) => a.id === accountId);
6155
+ if (target) {
6156
+ target.cooldownUntil = Date.now() + Math.max(1e4, durationMs);
6157
+ target.cooldownReason = reason;
6158
+ await this.write(data);
6159
+ }
6160
+ }
6161
+ async clearCooldown(accountId) {
6162
+ const data = await this.read();
6163
+ const target = data.accounts.find((a) => a.id === accountId);
6164
+ if (target) {
6165
+ target.cooldownUntil = void 0;
6166
+ target.cooldownReason = void 0;
6167
+ await this.write(data);
6168
+ }
6169
+ }
6170
+ async hasAnotherAvailableAccount(triedAccountIds) {
6171
+ const data = await this.read();
6172
+ const now = Date.now();
6173
+ return data.accounts.some((a) => !triedAccountIds.has(a.id) && (!a.cooldownUntil || a.cooldownUntil <= now));
6174
+ }
6175
+ async getEffectiveAccount(excludeIds, fetchFn = fetch) {
6176
+ const data = await this.read();
6177
+ if (data.accounts.length === 0) throw new Error("未登录 Antigravity 账号,请在「设置 → Antigravity」中添加并登录账号。");
6178
+ const now = Date.now();
6179
+ const eligible = data.accounts.filter((a) => (!excludeIds || !excludeIds.has(a.id)) && (!a.cooldownUntil || a.cooldownUntil <= now));
6180
+ if (eligible.length === 0) {
6181
+ let shortest = Infinity;
6182
+ for (const a of data.accounts) if (a.cooldownUntil && a.cooldownUntil > now) shortest = Math.min(shortest, a.cooldownUntil - now);
6183
+ const waitMins = Number.isFinite(shortest) ? Math.ceil(shortest / 6e4) : 15;
6184
+ throw new LlmError(`全部 ${data.accounts.length} 个 Antigravity 账号均处于配额限制或冷却中 (429)。最短预计在 ${waitMins} 分钟后解除冷却。`, "RATE_LIMIT", { status: 429 });
6185
+ }
6186
+ let selected;
6187
+ if (data.rotationStrategy === "round-robin") selected = [...eligible].sort((a, b) => (a.lastUsedAt || 0) - (b.lastUsedAt || 0))[0];
6188
+ else selected = eligible.find((a) => a.isPrimary) || eligible[0];
6189
+ const creds = selected.credentials;
6190
+ const expires = creds.expires || creds.expires_at || 0;
6191
+ if (!(creds.access || creds.access_token) || expires <= now + 6e4) {
6192
+ const refreshed = await refreshAntigravityToken(creds, fetchFn);
6193
+ selected.credentials = refreshed;
6194
+ selected.projectId = refreshed.projectId || selected.projectId;
6195
+ const idx = data.accounts.findIndex((a) => a.id === selected.id);
6196
+ if (idx >= 0) data.accounts[idx] = selected;
6197
+ if (selected.isPrimary) this.legacyStore.write(refreshed).catch(() => void 0);
6198
+ }
6199
+ selected.lastUsedAt = now;
6200
+ data.activeAccountId = selected.id;
6201
+ await this.write(data);
6202
+ return {
6203
+ account: selected,
6204
+ token: selected.credentials.access || selected.credentials.access_token,
6205
+ projectId: selected.projectId || selected.credentials.projectId
6206
+ };
6207
+ }
6208
+ };
6209
+ //#endregion
5907
6210
  //#region src/host/antigravity/adapter.ts
5908
6211
  function resolveDefaultReasoningEffort$2(efforts, configuredEffort) {
5909
6212
  if (configuredEffort && efforts.includes(configuredEffort)) return ReasoningEffortId(configuredEffort);
@@ -5916,12 +6219,14 @@ var AntigravityAdapter = class extends LlmAdapter {
5916
6219
  modelSettings;
5917
6220
  preferences;
5918
6221
  options;
5919
- constructor(store = new FileCredentialStore$1(), modelSettings = new FileModelSettingsStore$1(), preferences, options = {}) {
6222
+ accountPool;
6223
+ constructor(store = new FileCredentialStore$1(), modelSettings = new FileModelSettingsStore$1(), preferences, options = {}, accountPool) {
5920
6224
  super();
5921
6225
  this.store = store;
5922
6226
  this.modelSettings = modelSettings;
5923
6227
  this.preferences = preferences;
5924
6228
  this.options = options;
6229
+ this.accountPool = accountPool ?? new AccountPoolStore(void 0, void 0, store);
5925
6230
  }
5926
6231
  providerInfo(provider) {
5927
6232
  return {
@@ -5934,6 +6239,7 @@ var AntigravityAdapter = class extends LlmAdapter {
5934
6239
  async listModels(provider) {
5935
6240
  const prov = provider || "antigravity";
5936
6241
  const settings = this.preferences ? this.preferences.status() : await this.modelSettings.read();
6242
+ if (settings.enabled === false) return [];
5937
6243
  const enabledSet = new Set(settings.enabledModelIds);
5938
6244
  const available = MODELS.filter((m) => enabledSet.has(m.id));
5939
6245
  const overrides = settings.contextWindowOverrides || {};
@@ -6004,8 +6310,6 @@ var AntigravityAdapter = class extends LlmAdapter {
6004
6310
  }
6005
6311
  async *requestStream(options, model, signal) {
6006
6312
  const fetchFn = this.options.fetchFn ?? fetch;
6007
- const { token, projectId: defaultProj } = await ensureApiKey(this.store, fetchFn);
6008
- const projectId = defaultProj || "antigravity-default";
6009
6313
  const effort = String(options.reasoningEffort || "medium").toLowerCase();
6010
6314
  const routing = ROUTING[model.id];
6011
6315
  const initialRuntime = routing?.routing[effort] || routing?.defaultRequestId || model.id;
@@ -6017,26 +6321,54 @@ var AntigravityAdapter = class extends LlmAdapter {
6017
6321
  }
6018
6322
  const requestOptions = offloadOldestRequestImages$2(options);
6019
6323
  const images = await resolveRequestImages$2(requestOptions, this.options.attachments, signal);
6324
+ const triedAccountIds = /* @__PURE__ */ new Set();
6020
6325
  let response;
6021
- for (const runtimeModel of candidates) {
6022
- const body = JSON.stringify(buildRequest$2(requestOptions, model, projectId, runtimeModel, effort, images));
6023
- const headers = {
6024
- ...antigravityHeaders(token),
6025
- ...model.id.startsWith("claude-") ? { "anthropic-beta": "interleaved-thinking-2025-05-14" } : {}
6026
- };
6027
- for (const endpoint of endpointCandidates()) try {
6028
- response = await fetchFn(`${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
6029
- method: "POST",
6030
- headers,
6031
- body,
6032
- signal
6033
- });
6034
- if (response.ok || response.status === 400) break;
6035
- if (response.status === 404) break;
6036
- } catch (err) {
6037
- if (signal.aborted) throw new LlmError("Antigravity request aborted", "ABORTED", { cause: err });
6326
+ while (true) {
6327
+ let eff;
6328
+ try {
6329
+ eff = await this.accountPool.getEffectiveAccount(triedAccountIds, fetchFn);
6330
+ } catch (poolErr) {
6331
+ const poolData = await this.accountPool.read().catch(() => null);
6332
+ if (!poolData || poolData.accounts.length === 0) {
6333
+ const { token, projectId: defaultProj } = await ensureApiKey(this.store, fetchFn);
6334
+ eff = {
6335
+ account: { id: "legacy" },
6336
+ token,
6337
+ projectId: defaultProj
6338
+ };
6339
+ } else throw poolErr;
6340
+ }
6341
+ const { account, token, projectId: defaultProj } = eff;
6342
+ const projectId = defaultProj || "antigravity-default";
6343
+ triedAccountIds.add(account.id);
6344
+ for (const runtimeModel of candidates) {
6345
+ const body = JSON.stringify(buildRequest$2(requestOptions, model, projectId, runtimeModel, effort, images));
6346
+ const headers = {
6347
+ ...antigravityHeaders(token),
6348
+ ...model.id.startsWith("claude-") ? { "anthropic-beta": "interleaved-thinking-2025-05-14" } : {}
6349
+ };
6350
+ for (const endpoint of endpointCandidates()) try {
6351
+ response = await fetchFn(`${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
6352
+ method: "POST",
6353
+ headers,
6354
+ body,
6355
+ signal
6356
+ });
6357
+ if (response.ok || response.status === 400) break;
6358
+ if (response.status === 404) break;
6359
+ } catch (err) {
6360
+ if (signal.aborted) throw new LlmError("Antigravity request aborted", "ABORTED", { cause: err });
6361
+ }
6362
+ if (response && (response.ok || response.status === 400)) break;
6363
+ }
6364
+ if (response && response.status === 429) {
6365
+ const retryAfterHeader = response.headers.get("retry-after");
6366
+ const retryAfterSec = retryAfterHeader ? Number(retryAfterHeader) : NaN;
6367
+ const cooldownMs = Number.isFinite(retryAfterSec) && retryAfterSec > 0 ? retryAfterSec * 1e3 : 900 * 1e3;
6368
+ await this.accountPool.markCooldown(account.id, cooldownMs, "429 Rate Limit");
6369
+ if (await this.accountPool.hasAnotherAvailableAccount(triedAccountIds)) continue;
6038
6370
  }
6039
- if (response && (response.ok || response.status === 400)) break;
6371
+ break;
6040
6372
  }
6041
6373
  if (!response || !response.ok) {
6042
6374
  const status = response?.status ?? 500;
@@ -6104,7 +6436,7 @@ async function readRequestJson$2(request) {
6104
6436
  request.on("error", reject);
6105
6437
  });
6106
6438
  }
6107
- async function getAntigravityWebStatus(store, modelSettings, preferences) {
6439
+ async function getAntigravityWebStatus(store, modelSettings, preferences, accountPool = new AccountPoolStore(void 0, void 0, store)) {
6108
6440
  const credentials = await store.read();
6109
6441
  const settings = preferences ? preferences.status() : await modelSettings.read();
6110
6442
  const quota = getCachedQuota();
@@ -6118,20 +6450,27 @@ async function getAntigravityWebStatus(store, modelSettings, preferences) {
6118
6450
  contextWindow: overrides[m.id] || m.contextWindow,
6119
6451
  reasoningEfforts: m.reasoningEfforts
6120
6452
  }));
6453
+ const accounts = await accountPool.listAccounts().catch(() => []);
6454
+ const poolData = await accountPool.read().catch(() => null);
6455
+ const activeAccount = accounts.find((a) => a.id === poolData?.activeAccountId) || accounts[0];
6121
6456
  return {
6122
- authenticated: !!(credentials?.access || credentials?.access_token),
6123
- email: credentials?.email,
6124
- projectId: credentials?.projectId,
6125
- hasCredentials: !!credentials,
6457
+ enabled: settings.enabled !== false,
6458
+ authenticated: accounts.length > 0 || !!(credentials?.access || credentials?.access_token),
6459
+ email: activeAccount?.email || credentials?.email,
6460
+ projectId: activeAccount?.projectId || credentials?.projectId,
6461
+ hasCredentials: accounts.length > 0 || !!credentials,
6126
6462
  storagePath: store.path(),
6127
6463
  lastFetchedAt: quota?.fetchedAt,
6128
6464
  quota,
6129
6465
  models,
6130
6466
  contextWindowOverrides: overrides,
6131
- defaultReasoningEffort: settings.defaultReasoningEffort || null
6467
+ defaultReasoningEffort: settings.defaultReasoningEffort || null,
6468
+ accounts,
6469
+ activeAccountId: poolData?.activeAccountId || activeAccount?.id,
6470
+ rotationStrategy: poolData?.rotationStrategy || "sequential"
6132
6471
  };
6133
6472
  }
6134
- function registerAntigravityRoutes(ctx, store, modelSettings, preferences, fetchFn = fetch) {
6473
+ function registerAntigravityRoutes(ctx, store, modelSettings, preferences, fetchFn = fetch, accountPool = new AccountPoolStore(void 0, void 0, store)) {
6135
6474
  return ctx.webServer.register({
6136
6475
  kind: "prefix",
6137
6476
  path: "/antigravity/api",
@@ -6146,14 +6485,16 @@ function registerAntigravityRoutes(ctx, store, modelSettings, preferences, fetch
6146
6485
  if (authenticated && (!cached || Date.now() - (cached.fetchedAt || 0) > 12e4)) await fetchAccountQuota(store, modelSettings, fetchFn).catch(() => void 0);
6147
6486
  return sendJson$3(response, 200, {
6148
6487
  ok: true,
6149
- value: await getAntigravityWebStatus(store, modelSettings, preferences)
6488
+ value: await getAntigravityWebStatus(store, modelSettings, preferences, accountPool)
6150
6489
  });
6151
6490
  }
6152
- if (path === "login") {
6491
+ if (path === "login" || path === "accounts/login") {
6153
6492
  if (request.method !== "POST") return sendMethodNotAllowed$2(response);
6154
6493
  return sendJson$3(response, 200, {
6155
6494
  ok: true,
6156
- value: await beginWebLogin$1(store, fetchFn)
6495
+ value: await beginWebLogin$1(store, fetchFn, void 0, async (creds) => {
6496
+ await accountPool.addAccount(creds);
6497
+ })
6157
6498
  });
6158
6499
  }
6159
6500
  if (path === "login/status") {
@@ -6163,13 +6504,33 @@ function registerAntigravityRoutes(ctx, store, modelSettings, preferences, fetch
6163
6504
  value: getWebLoginStatus$2()
6164
6505
  });
6165
6506
  }
6507
+ if (path === "accounts") {
6508
+ if (request.method === "GET") return sendJson$3(response, 200, {
6509
+ ok: true,
6510
+ value: await accountPool.listAccounts()
6511
+ });
6512
+ if (request.method === "POST") {
6513
+ const body = await readRequestJson$2(request);
6514
+ const action = String(body.action || "");
6515
+ if (action === "set-primary" && typeof body.accountId === "string") await accountPool.setPrimary(body.accountId);
6516
+ else if (action === "set-alias" && typeof body.accountId === "string" && typeof body.alias === "string") await accountPool.setAlias(body.accountId, body.alias);
6517
+ else if (action === "delete" && typeof body.accountId === "string") await accountPool.deleteAccount(body.accountId);
6518
+ else if (action === "strategy" && (body.strategy === "sequential" || body.strategy === "round-robin")) await accountPool.setStrategy(body.strategy);
6519
+ else if (action === "clear-cooldown" && typeof body.accountId === "string") await accountPool.clearCooldown(body.accountId);
6520
+ return sendJson$3(response, 200, {
6521
+ ok: true,
6522
+ value: await getAntigravityWebStatus(store, modelSettings, preferences, accountPool)
6523
+ });
6524
+ }
6525
+ return sendMethodNotAllowed$2(response);
6526
+ }
6166
6527
  if (path === "quota") {
6167
6528
  if (request.method !== "GET" && request.method !== "POST") return sendMethodNotAllowed$2(response);
6168
6529
  const quota = await fetchAccountQuota(store, modelSettings, fetchFn, true);
6169
6530
  return sendJson$3(response, 200, {
6170
6531
  ok: true,
6171
6532
  value: {
6172
- ...await getAntigravityWebStatus(store, modelSettings, preferences),
6533
+ ...await getAntigravityWebStatus(store, modelSettings, preferences, accountPool),
6173
6534
  quota
6174
6535
  }
6175
6536
  });
@@ -6181,32 +6542,39 @@ function registerAntigravityRoutes(ctx, store, modelSettings, preferences, fetch
6181
6542
  else await modelSettings.updateSettings(body);
6182
6543
  return sendJson$3(response, 200, {
6183
6544
  ok: true,
6184
- value: await getAntigravityWebStatus(store, modelSettings, preferences)
6545
+ value: await getAntigravityWebStatus(store, modelSettings, preferences, accountPool)
6185
6546
  });
6186
6547
  }
6187
6548
  if (path === "models") {
6188
6549
  if (request.method === "GET") return sendJson$3(response, 200, {
6189
6550
  ok: true,
6190
- value: (await getAntigravityWebStatus(store, modelSettings, preferences)).models
6551
+ value: (await getAntigravityWebStatus(store, modelSettings, preferences, accountPool)).models
6191
6552
  });
6192
6553
  if (request.method === "POST") {
6193
6554
  const body = await readRequestJson$2(request);
6194
- if (Array.isArray(body.enabledModelIds) || body.contextWindowOverrides || body.defaultReasoningEffort !== void 0) if (preferences) await preferences.update(body);
6555
+ if (Array.isArray(body.enabledModelIds) || body.enabled !== void 0 || body.contextWindowOverrides || body.defaultReasoningEffort !== void 0) if (preferences) await preferences.update(body);
6195
6556
  else await modelSettings.updateSettings(body);
6196
6557
  return sendJson$3(response, 200, {
6197
6558
  ok: true,
6198
- value: await getAntigravityWebStatus(store, modelSettings, preferences)
6559
+ value: await getAntigravityWebStatus(store, modelSettings, preferences, accountPool)
6199
6560
  });
6200
6561
  }
6201
6562
  return sendMethodNotAllowed$2(response);
6202
6563
  }
6203
6564
  if (path === "logout") {
6204
6565
  if (request.method !== "POST") return sendMethodNotAllowed$2(response);
6205
- await store.delete();
6566
+ const body = await readRequestJson$2(request).catch(() => ({}));
6567
+ const targetId = typeof body.accountId === "string" ? body.accountId : void 0;
6568
+ if (targetId) await accountPool.deleteAccount(targetId);
6569
+ else {
6570
+ const poolData = await accountPool.read().catch(() => null);
6571
+ if (poolData?.activeAccountId) await accountPool.deleteAccount(poolData.activeAccountId);
6572
+ else await store.delete();
6573
+ }
6206
6574
  clearCachedQuota();
6207
6575
  return sendJson$3(response, 200, {
6208
6576
  ok: true,
6209
- value: await getAntigravityWebStatus(store, modelSettings)
6577
+ value: await getAntigravityWebStatus(store, modelSettings, preferences, accountPool)
6210
6578
  });
6211
6579
  }
6212
6580
  return sendJson$3(response, 404, {
@@ -7230,6 +7598,7 @@ const DEFAULT_ENABLED_MODEL_IDS$1 = FALLBACK_MODELS$1.map((model) => model.id);
7230
7598
  function registerCommandCodePreferenceStore(settings, fallbackStore = new FileModelSettingsStore()) {
7231
7599
  if (!settings) return {
7232
7600
  status: () => ({
7601
+ enabled: true,
7233
7602
  enabledModelIds: [...DEFAULT_ENABLED_MODEL_IDS$1],
7234
7603
  catalogModels: [],
7235
7604
  contextWindowOverrides: {},
@@ -7239,6 +7608,7 @@ function registerCommandCodePreferenceStore(settings, fallbackStore = new FileMo
7239
7608
  };
7240
7609
  const ns = SettingsModule.settingsNamespace ? SettingsModule.settingsNamespace(COMMAND_CODE_PREFERENCES_NAMESPACE) : COMMAND_CODE_PREFERENCES_NAMESPACE;
7241
7610
  const scope = settings.register.call(settings, ns, z.object({
7611
+ enabled: z.boolean().default(true),
7242
7612
  enabledModelIds: z.array(z.string()).default([...DEFAULT_ENABLED_MODEL_IDS$1]),
7243
7613
  contextWindowOverrides: z.dict(z.number()).default({}),
7244
7614
  defaultReasoningEffort: z.union([...COMMAND_CODE_REASONING_EFFORTS.map((effort) => z.const(effort)), z.const(null)]).default(null)
@@ -7247,6 +7617,7 @@ function registerCommandCodePreferenceStore(settings, fallbackStore = new FileMo
7247
7617
  status: () => {
7248
7618
  const value = scope.get();
7249
7619
  return {
7620
+ enabled: value.enabled !== false,
7250
7621
  enabledModelIds: value.enabledModelIds,
7251
7622
  catalogModels: [],
7252
7623
  contextWindowOverrides: value.contextWindowOverrides,
@@ -7256,6 +7627,7 @@ function registerCommandCodePreferenceStore(settings, fallbackStore = new FileMo
7256
7627
  update: async (patch) => {
7257
7628
  const current = scope.get();
7258
7629
  const normalized = {
7630
+ enabled: patch.enabled !== void 0 ? patch.enabled : current.enabled !== false,
7259
7631
  enabledModelIds: patch.enabledModelIds ?? current.enabledModelIds,
7260
7632
  contextWindowOverrides: patch.contextWindowOverrides ? {
7261
7633
  ...current.contextWindowOverrides,
@@ -7411,15 +7783,21 @@ var FileModelSettingsStore = class {
7411
7783
  const parsed = JSON.parse(content);
7412
7784
  if (typeof parsed === "object" && parsed !== null) {
7413
7785
  const record = parsed;
7786
+ const enabledModelIds = Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : [...DEFAULT_ENABLED_MODEL_IDS$1];
7787
+ const catalogModels = Array.isArray(record.catalogModels) ? record.catalogModels : [];
7788
+ const contextWindowOverrides = typeof record.contextWindowOverrides === "object" && record.contextWindowOverrides !== null ? record.contextWindowOverrides : {};
7789
+ const defaultReasoningEffort = isReasoningEffort$1(record.defaultReasoningEffort) ? record.defaultReasoningEffort : null;
7414
7790
  return {
7415
- enabledModelIds: Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : [...DEFAULT_ENABLED_MODEL_IDS$1],
7416
- catalogModels: Array.isArray(record.catalogModels) ? record.catalogModels : [],
7417
- contextWindowOverrides: typeof record.contextWindowOverrides === "object" && record.contextWindowOverrides !== null ? record.contextWindowOverrides : {},
7418
- defaultReasoningEffort: isReasoningEffort$1(record.defaultReasoningEffort) ? record.defaultReasoningEffort : null
7791
+ enabled: record.enabled !== false,
7792
+ enabledModelIds,
7793
+ catalogModels,
7794
+ contextWindowOverrides,
7795
+ defaultReasoningEffort
7419
7796
  };
7420
7797
  }
7421
7798
  } catch {}
7422
7799
  return {
7800
+ enabled: true,
7423
7801
  enabledModelIds: [...DEFAULT_ENABLED_MODEL_IDS$1],
7424
7802
  catalogModels: [],
7425
7803
  contextWindowOverrides: {},
@@ -7436,6 +7814,7 @@ var FileModelSettingsStore = class {
7436
7814
  const current = await this.read();
7437
7815
  const next = {
7438
7816
  ...current,
7817
+ ...patch.enabled !== void 0 ? { enabled: patch.enabled } : {},
7439
7818
  ...patch.enabledModelIds !== void 0 ? { enabledModelIds: patch.enabledModelIds } : {},
7440
7819
  ...patch.contextWindowOverrides !== void 0 ? { contextWindowOverrides: {
7441
7820
  ...current.contextWindowOverrides,
@@ -8342,9 +8721,13 @@ function attachmentLabel$1(block) {
8342
8721
  function collectImageRefs$1(content, refs) {
8343
8722
  if (!Array.isArray(content)) return;
8344
8723
  for (const block of content) {
8345
- if (!isRecord$2(block) || block.type !== "image") continue;
8346
- const attachment = attachmentOf$1(block);
8347
- if (attachment) refs.set(attachment.attachmentId, attachment);
8724
+ if (!isRecord$2(block)) continue;
8725
+ if (block.type === "image") {
8726
+ const attachment = attachmentOf$1(block);
8727
+ if (attachment) refs.set(attachment.attachmentId, attachment);
8728
+ continue;
8729
+ }
8730
+ if (block.type === "tool-result") collectImageRefs$1(block.content, refs);
8348
8731
  }
8349
8732
  }
8350
8733
  function base64Length$1(bytes) {
@@ -8482,6 +8865,83 @@ function toolResultText$1(blocks) {
8482
8865
  return "";
8483
8866
  }).join("");
8484
8867
  }
8868
+ /**
8869
+ * Anthropic `tool_result` content for one tool result, or `undefined` when the
8870
+ * result carries no image. Returning `undefined` is what keeps a plain tool
8871
+ * result a byte-identical string on the wire: the image-less path never changes
8872
+ * shape, so only results that actually hold pixels take the block-array form.
8873
+ */
8874
+ function toolResultBlocks$1(blocks, images) {
8875
+ if (!Array.isArray(blocks)) return void 0;
8876
+ const out = [];
8877
+ let hasImage = false;
8878
+ for (const block of blocks) {
8879
+ if (!isRecord$2(block)) continue;
8880
+ if (block.type === "text" && typeof block.text === "string") {
8881
+ out.push({
8882
+ type: "text",
8883
+ text: sanitizeText$1(block.text)
8884
+ });
8885
+ continue;
8886
+ }
8887
+ if (block.type === "image") {
8888
+ hasImage = true;
8889
+ const inline = imageBlockToInline$1(block, images);
8890
+ if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$1.has(inline.mediaType)) out.push({
8891
+ type: "image",
8892
+ source: {
8893
+ type: "base64",
8894
+ media_type: inline.mediaType,
8895
+ data: inline.data
8896
+ }
8897
+ });
8898
+ else out.push({
8899
+ type: "text",
8900
+ text: unavailableImageText$1(block)
8901
+ });
8902
+ continue;
8903
+ }
8904
+ if (block.type === "tool-result") {
8905
+ const nested = toolResultBlocks$1(block.content, images);
8906
+ if (nested) {
8907
+ hasImage = true;
8908
+ out.push(...nested);
8909
+ }
8910
+ }
8911
+ }
8912
+ if (!hasImage) return void 0;
8913
+ if (out[0]?.type !== "text") out.unshift({
8914
+ type: "text",
8915
+ text: ""
8916
+ });
8917
+ return out;
8918
+ }
8919
+ /**
8920
+ * OpenAI `image_url` blocks for one tool result. A `role: "tool"` message can
8921
+ * only carry text, so these ride on a `user` message appended after the run of
8922
+ * tool messages rather than inside it.
8923
+ */
8924
+ function toolResultImageBlocks$1(blocks, images) {
8925
+ if (!Array.isArray(blocks)) return [];
8926
+ const out = [];
8927
+ for (const block of blocks) {
8928
+ if (!isRecord$2(block)) continue;
8929
+ if (block.type === "image") {
8930
+ const inline = imageBlockToInline$1(block, images);
8931
+ if (inline && SUPPORTED_IMAGE_MEDIA_TYPES$1.has(inline.mediaType)) out.push({
8932
+ type: "image_url",
8933
+ image_url: { url: `data:${inline.mediaType};base64,${inline.data}` }
8934
+ });
8935
+ else out.push({
8936
+ type: "text",
8937
+ text: unavailableImageText$1(block)
8938
+ });
8939
+ continue;
8940
+ }
8941
+ if (block.type === "tool-result") out.push(...toolResultImageBlocks$1(block.content, images));
8942
+ }
8943
+ return out;
8944
+ }
8485
8945
  function toolCallArguments$1(raw) {
8486
8946
  if (typeof raw === "string") return raw;
8487
8947
  if (raw === void 0 || raw === null) return "{}";
@@ -8578,14 +9038,27 @@ function buildOpenAIRequest$1(options, images = NO_RESOLVED_IMAGES$1) {
8578
9038
  role: "system",
8579
9039
  content: system
8580
9040
  });
8581
- for (const message of nonSystemMessages$1(options)) {
9041
+ const conversation = nonSystemMessages$1(options);
9042
+ for (let index = 0; index < conversation.length; index++) {
9043
+ const message = conversation[index];
8582
9044
  if (isToolResultMessage$1(message)) {
8583
- const block = message.content[0];
8584
- const callId = isRecord$2(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
8585
- messages.push({
8586
- role: "tool",
8587
- tool_call_id: callId,
8588
- content: toolResultText$1(message.content)
9045
+ const imageBlocks = [];
9046
+ while (index < conversation.length && isToolResultMessage$1(conversation[index])) {
9047
+ const current = conversation[index];
9048
+ const block = current.content[0];
9049
+ const callId = isRecord$2(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
9050
+ messages.push({
9051
+ role: "tool",
9052
+ tool_call_id: callId,
9053
+ content: toolResultText$1(current.content)
9054
+ });
9055
+ imageBlocks.push(...toolResultImageBlocks$1(current.content, images));
9056
+ index += 1;
9057
+ }
9058
+ index -= 1;
9059
+ if (imageBlocks.length > 0) messages.push({
9060
+ role: "user",
9061
+ content: imageBlocks
8589
9062
  });
8590
9063
  continue;
8591
9064
  }
@@ -8657,10 +9130,11 @@ function anthropicUserContent$1(message, images) {
8657
9130
  });
8658
9131
  } else if (block.type === "tool-result") {
8659
9132
  const callId = typeof block.toolCallId === "string" ? block.toolCallId : "";
9133
+ const resultBlocks = toolResultBlocks$1(block.content, images);
8660
9134
  blocks.push({
8661
9135
  type: "tool_result",
8662
9136
  tool_use_id: callId,
8663
- content: toolResultText$1(block.content),
9137
+ content: resultBlocks ?? toolResultText$1(block.content),
8664
9138
  ...block.isError === true ? { is_error: true } : {}
8665
9139
  });
8666
9140
  }
@@ -9238,9 +9712,10 @@ var CommandCodeAdapter = class extends LlmAdapter {
9238
9712
  async listModels(provider) {
9239
9713
  const prov = provider || "command-code";
9240
9714
  const settings = await this.settings();
9715
+ if (settings.enabled === false) return [];
9241
9716
  const catalog = await this.catalog();
9242
9717
  const enabled = new Set(settings.enabledModelIds);
9243
- return (enabled.size === 0 ? catalog : catalog.filter((model) => enabled.has(model.id))).map((model) => ({
9718
+ return catalog.filter((model) => enabled.has(model.id)).map((model) => ({
9244
9719
  provider: prov,
9245
9720
  id: model.id,
9246
9721
  name: model.name ?? model.id,
@@ -9865,14 +10340,13 @@ function fallbackCatalog$1() {
9865
10340
  * "everything currently offered" keeps a first run from hiding the whole
9866
10341
  * catalog behind an unedited default. Any explicit edit is honoured exactly.
9867
10342
  */
9868
- function resolveEnabledModelIds$1(stored, catalog) {
10343
+ function resolveEnabledModelIds$1(stored, catalog, enabled = true) {
10344
+ if (!enabled) return [];
9869
10345
  const catalogIds = catalog.map((model) => model.id);
9870
10346
  const shippedDefaults = new Set(FALLBACK_MODELS$1.map((model) => model.id));
9871
- const isUntouchedDefault = stored.length > 0 && stored.length === shippedDefaults.size && stored.every((id) => shippedDefaults.has(id));
9872
- if (stored.length === 0 || isUntouchedDefault) return catalogIds;
10347
+ if (stored.length > 0 && stored.length === shippedDefaults.size && stored.every((id) => shippedDefaults.has(id))) return catalogIds;
9873
10348
  const known = new Set(catalogIds);
9874
- const kept = stored.filter((id) => known.has(id));
9875
- return kept.length === 0 ? catalogIds : kept;
10349
+ return stored.filter((id) => known.has(id));
9876
10350
  }
9877
10351
  function readOption$1(value, fallback) {
9878
10352
  return typeof value === "function" ? value() : value ?? fallback;
@@ -9887,9 +10361,11 @@ async function getCommandCodeWebStatus(store, modelSettings, preferences, option
9887
10361
  apiEnv
9888
10362
  });
9889
10363
  const catalog = live.length > 0 ? live : fallbackCatalog$1();
9890
- const models = buildModelOptions$1(catalog, resolveEnabledModelIds$1(settings.enabledModelIds, catalog), settings.contextWindowOverrides);
10364
+ const enabled = settings.enabled !== false;
10365
+ const models = buildModelOptions$1(catalog, resolveEnabledModelIds$1(settings.enabledModelIds, catalog, enabled), settings.contextWindowOverrides);
9891
10366
  const quota = getCachedQuota$1();
9892
10367
  return {
10368
+ enabled,
9893
10369
  authenticated: credentials !== null,
9894
10370
  hasCredentials: credentials !== null,
9895
10371
  storagePath: store.path(),
@@ -10021,6 +10497,7 @@ function registerCommandCodeRoutes(ctx, store, modelSettings, preferences, optio
10021
10497
  });
10022
10498
  const body = await readRequestJson$1(request);
10023
10499
  const patch = {};
10500
+ if (typeof body.enabled === "boolean") patch.enabled = body.enabled;
10024
10501
  if (Array.isArray(body.enabledModelIds)) patch.enabledModelIds = body.enabledModelIds.filter((id) => typeof id === "string");
10025
10502
  if (typeof body.contextWindowOverrides === "object" && body.contextWindowOverrides !== null) {
10026
10503
  const overrides = {};
@@ -10367,6 +10844,7 @@ const DEFAULT_ENABLED_MODEL_IDS = FALLBACK_MODELS.map((model) => model.id);
10367
10844
  function registerKimiCodePreferenceStore(settings, fallbackStore = new FileModelSettingsStore$2()) {
10368
10845
  if (!settings) return {
10369
10846
  status: () => ({
10847
+ enabled: true,
10370
10848
  enabledModelIds: [...DEFAULT_ENABLED_MODEL_IDS],
10371
10849
  catalogModels: [],
10372
10850
  contextWindowOverrides: {},
@@ -10376,6 +10854,7 @@ function registerKimiCodePreferenceStore(settings, fallbackStore = new FileModel
10376
10854
  };
10377
10855
  const ns = SettingsModule.settingsNamespace ? SettingsModule.settingsNamespace(KIMI_CODE_PREFERENCES_NAMESPACE) : KIMI_CODE_PREFERENCES_NAMESPACE;
10378
10856
  const scope = settings.register.call(settings, ns, z.object({
10857
+ enabled: z.boolean().default(true),
10379
10858
  enabledModelIds: z.array(z.string()).default([...DEFAULT_ENABLED_MODEL_IDS]),
10380
10859
  contextWindowOverrides: z.dict(z.number()).default({}),
10381
10860
  defaultReasoningEffort: z.union([...KIMI_CODE_REASONING_EFFORTS.map((effort) => z.const(effort)), z.const(null)]).default(null)
@@ -10384,6 +10863,7 @@ function registerKimiCodePreferenceStore(settings, fallbackStore = new FileModel
10384
10863
  status: () => {
10385
10864
  const value = scope.get();
10386
10865
  return {
10866
+ enabled: value.enabled !== false,
10387
10867
  enabledModelIds: value.enabledModelIds,
10388
10868
  catalogModels: [],
10389
10869
  contextWindowOverrides: value.contextWindowOverrides,
@@ -10393,6 +10873,7 @@ function registerKimiCodePreferenceStore(settings, fallbackStore = new FileModel
10393
10873
  update: async (patch) => {
10394
10874
  const current = scope.get();
10395
10875
  const normalized = {
10876
+ enabled: patch.enabled !== void 0 ? patch.enabled : current.enabled !== false,
10396
10877
  enabledModelIds: patch.enabledModelIds ?? current.enabledModelIds,
10397
10878
  contextWindowOverrides: patch.contextWindowOverrides ? {
10398
10879
  ...current.contextWindowOverrides,
@@ -10583,15 +11064,21 @@ var FileModelSettingsStore$2 = class {
10583
11064
  const parsed = JSON.parse(content);
10584
11065
  if (typeof parsed === "object" && parsed !== null) {
10585
11066
  const record = parsed;
11067
+ const enabledModelIds = Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : [...DEFAULT_ENABLED_MODEL_IDS];
11068
+ const catalogModels = Array.isArray(record.catalogModels) ? record.catalogModels : [];
11069
+ const contextWindowOverrides = typeof record.contextWindowOverrides === "object" && record.contextWindowOverrides !== null ? record.contextWindowOverrides : {};
11070
+ const defaultReasoningEffort = isReasoningEffort(record.defaultReasoningEffort) ? record.defaultReasoningEffort : null;
10586
11071
  return {
10587
- enabledModelIds: Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : [...DEFAULT_ENABLED_MODEL_IDS],
10588
- catalogModels: Array.isArray(record.catalogModels) ? record.catalogModels : [],
10589
- contextWindowOverrides: typeof record.contextWindowOverrides === "object" && record.contextWindowOverrides !== null ? record.contextWindowOverrides : {},
10590
- defaultReasoningEffort: isReasoningEffort(record.defaultReasoningEffort) ? record.defaultReasoningEffort : null
11072
+ enabled: record.enabled !== false,
11073
+ enabledModelIds,
11074
+ catalogModels,
11075
+ contextWindowOverrides,
11076
+ defaultReasoningEffort
10591
11077
  };
10592
11078
  }
10593
11079
  } catch {}
10594
11080
  return {
11081
+ enabled: true,
10595
11082
  enabledModelIds: [...DEFAULT_ENABLED_MODEL_IDS],
10596
11083
  catalogModels: [],
10597
11084
  contextWindowOverrides: {},
@@ -10608,6 +11095,7 @@ var FileModelSettingsStore$2 = class {
10608
11095
  const current = await this.read();
10609
11096
  const next = {
10610
11097
  ...current,
11098
+ ...patch.enabled !== void 0 ? { enabled: patch.enabled } : {},
10611
11099
  ...patch.enabledModelIds !== void 0 ? { enabledModelIds: patch.enabledModelIds } : {},
10612
11100
  ...patch.contextWindowOverrides !== void 0 ? { contextWindowOverrides: {
10613
11101
  ...current.contextWindowOverrides,
@@ -12138,9 +12626,13 @@ function attachmentLabel(block) {
12138
12626
  function collectImageRefs(content, refs) {
12139
12627
  if (!Array.isArray(content)) return;
12140
12628
  for (const block of content) {
12141
- if (!isRecord(block) || block.type !== "image") continue;
12142
- const attachment = attachmentOf(block);
12143
- if (attachment) refs.set(attachment.attachmentId, attachment);
12629
+ if (!isRecord(block)) continue;
12630
+ if (block.type === "image") {
12631
+ const attachment = attachmentOf(block);
12632
+ if (attachment) refs.set(attachment.attachmentId, attachment);
12633
+ continue;
12634
+ }
12635
+ if (block.type === "tool-result") collectImageRefs(block.content, refs);
12144
12636
  }
12145
12637
  }
12146
12638
  function base64Length(bytes) {
@@ -12417,6 +12909,83 @@ function toolResultText(blocks) {
12417
12909
  return "";
12418
12910
  }).join("");
12419
12911
  }
12912
+ /**
12913
+ * Anthropic `tool_result` content for one tool result, or `undefined` when the
12914
+ * result carries no image. Returning `undefined` is what keeps a plain tool
12915
+ * result a byte-identical string on the wire: the image-less path never changes
12916
+ * shape, so only results that actually hold pixels take the block-array form.
12917
+ */
12918
+ function toolResultBlocks(blocks, images) {
12919
+ if (!Array.isArray(blocks)) return void 0;
12920
+ const out = [];
12921
+ let hasImage = false;
12922
+ for (const block of blocks) {
12923
+ if (!isRecord(block)) continue;
12924
+ if (block.type === "text" && typeof block.text === "string") {
12925
+ out.push({
12926
+ type: "text",
12927
+ text: sanitizeText(block.text)
12928
+ });
12929
+ continue;
12930
+ }
12931
+ if (block.type === "image") {
12932
+ hasImage = true;
12933
+ const inline = imageBlockToInline(block, images);
12934
+ if (inline && SUPPORTED_IMAGE_MEDIA_TYPES.has(inline.mediaType)) out.push({
12935
+ type: "image",
12936
+ source: {
12937
+ type: "base64",
12938
+ media_type: inline.mediaType,
12939
+ data: inline.data
12940
+ }
12941
+ });
12942
+ else out.push({
12943
+ type: "text",
12944
+ text: unavailableImageText(block)
12945
+ });
12946
+ continue;
12947
+ }
12948
+ if (block.type === "tool-result") {
12949
+ const nested = toolResultBlocks(block.content, images);
12950
+ if (nested) {
12951
+ hasImage = true;
12952
+ out.push(...nested);
12953
+ }
12954
+ }
12955
+ }
12956
+ if (!hasImage) return void 0;
12957
+ if (out[0]?.type !== "text") out.unshift({
12958
+ type: "text",
12959
+ text: ""
12960
+ });
12961
+ return out;
12962
+ }
12963
+ /**
12964
+ * OpenAI `image_url` blocks for one tool result. A `role: "tool"` message can
12965
+ * only carry text, so these ride on a `user` message appended after the run of
12966
+ * tool messages rather than inside it.
12967
+ */
12968
+ function toolResultImageBlocks(blocks, images) {
12969
+ if (!Array.isArray(blocks)) return [];
12970
+ const out = [];
12971
+ for (const block of blocks) {
12972
+ if (!isRecord(block)) continue;
12973
+ if (block.type === "image") {
12974
+ const inline = imageBlockToInline(block, images);
12975
+ if (inline && SUPPORTED_IMAGE_MEDIA_TYPES.has(inline.mediaType)) out.push({
12976
+ type: "image_url",
12977
+ image_url: { url: `data:${inline.mediaType};base64,${inline.data}` }
12978
+ });
12979
+ else out.push({
12980
+ type: "text",
12981
+ text: unavailableImageText(block)
12982
+ });
12983
+ continue;
12984
+ }
12985
+ if (block.type === "tool-result") out.push(...toolResultImageBlocks(block.content, images));
12986
+ }
12987
+ return out;
12988
+ }
12420
12989
  function toolCallArguments(raw) {
12421
12990
  if (typeof raw === "string") return raw;
12422
12991
  if (raw === void 0 || raw === null) return "{}";
@@ -12789,16 +13358,33 @@ function buildOpenAIRequest(options, images = NO_RESOLVED_IMAGES, preserveThinki
12789
13358
  }
12790
13359
  };
12791
13360
  flushSlots(0);
12792
- for (const message of nonSystemMessages(options)) {
13361
+ const conversation = nonSystemMessages(options);
13362
+ for (let index = 0; index < conversation.length; index++) {
13363
+ const message = conversation[index];
12793
13364
  flushSlots(nonSystemIndex);
12794
13365
  nonSystemIndex += 1;
12795
13366
  if (isToolResultMessage(message)) {
12796
- const block = message.content[0];
12797
- const callId = isRecord(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
12798
- messages.push({
12799
- role: "tool",
12800
- tool_call_id: clampToolCallId(callId),
12801
- content: toolResultText(message.content)
13367
+ const imageBlocks = [];
13368
+ while (index < conversation.length && isToolResultMessage(conversation[index])) {
13369
+ const current = conversation[index];
13370
+ if (index > 0) {
13371
+ flushSlots(nonSystemIndex);
13372
+ nonSystemIndex += 1;
13373
+ }
13374
+ const block = current.content[0];
13375
+ const callId = isRecord(block) && typeof block.toolCallId === "string" ? block.toolCallId : "";
13376
+ messages.push({
13377
+ role: "tool",
13378
+ tool_call_id: clampToolCallId(callId),
13379
+ content: toolResultText(current.content)
13380
+ });
13381
+ imageBlocks.push(...toolResultImageBlocks(current.content, images));
13382
+ index += 1;
13383
+ }
13384
+ index -= 1;
13385
+ if (imageBlocks.length > 0) messages.push({
13386
+ role: "user",
13387
+ content: imageBlocks
12802
13388
  });
12803
13389
  continue;
12804
13390
  }
@@ -12903,10 +13489,11 @@ function anthropicUserContent(message, images) {
12903
13489
  });
12904
13490
  } else if (block.type === "tool-result") {
12905
13491
  const callId = typeof block.toolCallId === "string" ? block.toolCallId : "";
13492
+ const resultBlocks = toolResultBlocks(block.content, images);
12906
13493
  blocks.push({
12907
13494
  type: "tool_result",
12908
13495
  tool_use_id: clampToolCallId(callId),
12909
- content: toolResultText(block.content),
13496
+ content: resultBlocks ?? toolResultText(block.content),
12910
13497
  ...block.isError === true ? { is_error: true } : {}
12911
13498
  });
12912
13499
  }
@@ -13665,9 +14252,10 @@ var KimiCodeAdapter = class extends LlmAdapter {
13665
14252
  async listModels(provider) {
13666
14253
  const prov = provider || "kimi-code";
13667
14254
  const settings = await this.settings();
14255
+ if (settings.enabled === false) return [];
13668
14256
  const catalog = await this.catalog();
13669
14257
  const enabled = new Set(settings.enabledModelIds);
13670
- return (enabled.size === 0 ? catalog : catalog.filter((model) => enabled.has(model.id))).map((model) => ({
14258
+ return catalog.filter((model) => enabled.has(model.id)).map((model) => ({
13671
14259
  provider: prov,
13672
14260
  id: model.id,
13673
14261
  name: model.name ?? model.id,
@@ -13867,14 +14455,13 @@ function fallbackCatalog() {
13867
14455
  * "everything currently offered" keeps a first run from hiding the whole
13868
14456
  * catalog behind an unedited default. Any explicit edit is honoured exactly.
13869
14457
  */
13870
- function resolveEnabledModelIds(stored, catalog) {
14458
+ function resolveEnabledModelIds(stored, catalog, enabled = true) {
14459
+ if (!enabled) return [];
13871
14460
  const catalogIds = catalog.map((model) => model.id);
13872
14461
  const shippedDefaults = new Set(FALLBACK_MODELS.map((model) => model.id));
13873
- const isUntouchedDefault = stored.length > 0 && stored.length === shippedDefaults.size && stored.every((id) => shippedDefaults.has(id));
13874
- if (stored.length === 0 || isUntouchedDefault) return catalogIds;
14462
+ if (stored.length > 0 && stored.length === shippedDefaults.size && stored.every((id) => shippedDefaults.has(id))) return catalogIds;
13875
14463
  const known = new Set(catalogIds);
13876
- const kept = stored.filter((id) => known.has(id));
13877
- return kept.length === 0 ? catalogIds : kept;
14464
+ return stored.filter((id) => known.has(id));
13878
14465
  }
13879
14466
  function readOption(value, fallback) {
13880
14467
  return typeof value === "function" ? value() : value ?? fallback;
@@ -13891,10 +14478,12 @@ async function getKimiCodeWebStatus(store, modelSettings, preferences, options =
13891
14478
  accessToken: credentials?.accessToken
13892
14479
  }).catch(() => []);
13893
14480
  const catalog = live.length > 0 ? live : fallbackCatalog();
13894
- const models = buildModelOptions(catalog, resolveEnabledModelIds(settings.enabledModelIds, catalog), settings.contextWindowOverrides);
14481
+ const enabled = settings.enabled !== false;
14482
+ const models = buildModelOptions(catalog, resolveEnabledModelIds(settings.enabledModelIds, catalog, enabled), settings.contextWindowOverrides);
13895
14483
  const quota = getCachedQuota$2();
13896
14484
  const account = quota?.account ?? (credentials === null ? null : accountFromCredentials(credentials));
13897
14485
  return {
14486
+ enabled,
13898
14487
  authenticated: credentials !== null,
13899
14488
  hasCredentials: credentials !== null,
13900
14489
  storagePath: store.path(),
@@ -14047,6 +14636,7 @@ function registerKimiCodeRoutes(ctx, store, modelSettings, preferences, options
14047
14636
  });
14048
14637
  const body = await readRequestJson(request);
14049
14638
  const patch = {};
14639
+ if (typeof body.enabled === "boolean") patch.enabled = body.enabled;
14050
14640
  if (Array.isArray(body.enabledModelIds)) patch.enabledModelIds = body.enabledModelIds.filter((id) => typeof id === "string");
14051
14641
  if (typeof body.contextWindowOverrides === "object" && body.contextWindowOverrides !== null) {
14052
14642
  const overrides = {};
@@ -15852,6 +16442,7 @@ function apply(ctx, pluginConfig = {}) {
15852
16442
  const store = createPlatformTokenStore();
15853
16443
  const preferences = registerPreferenceStore(ctx.settings);
15854
16444
  const antigravityStore = new FileCredentialStore$1();
16445
+ const antigravityAccountPool = new AccountPoolStore(void 0, void 0, antigravityStore);
15855
16446
  const antigravityModelSettings = new FileModelSettingsStore$1();
15856
16447
  const antigravityPreferences = registerAntigravityPreferenceStore(ctx.settings, antigravityModelSettings);
15857
16448
  const commandCodeStore = new FileCredentialStore();
@@ -15894,9 +16485,25 @@ function apply(ctx, pluginConfig = {}) {
15894
16485
  const antigravityAdapter = new AntigravityAdapter(antigravityStore, antigravityModelSettings, antigravityPreferences, {
15895
16486
  fetchFn: proxyFetch,
15896
16487
  attachments: ctx.attachments
15897
- });
15898
- const disposeAntigravityAdapter = ctx.llm.registerAdapter([PROVIDER_ID$2], antigravityAdapter);
15899
- const disposeAntigravityRoutes = registerAntigravityRoutes(ctx, antigravityStore, antigravityModelSettings, antigravityPreferences, proxyFetch);
16488
+ }, antigravityAccountPool);
16489
+ let antigravityRegistration;
16490
+ let antigravityConflict = null;
16491
+ const claimAntigravityRoute = () => {
16492
+ if (antigravityRegistration !== void 0) return;
16493
+ try {
16494
+ antigravityRegistration = ctx.llm.registerAdapter([PROVIDER_ID$2], antigravityAdapter);
16495
+ if (antigravityConflict !== null) ctx.logger.info(`[dsh-chatgpt-subscription] Antigravity route "${PROVIDER_ID$2}" is now served by this plugin`);
16496
+ antigravityConflict = null;
16497
+ } catch (error) {
16498
+ antigravityConflict = error instanceof Error ? error.message : String(error);
16499
+ ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID$2}" is already owned by another adapter; Antigravity models keep being served by that one until its configuration is removed (${antigravityConflict})`);
16500
+ }
16501
+ };
16502
+ claimAntigravityRoute();
16503
+ const antigravityRouteWatch = typeof ctx.on === "function" ? ctx.on("llm/adapters-updated", () => {
16504
+ claimAntigravityRoute();
16505
+ }) : void 0;
16506
+ const disposeAntigravityRoutes = registerAntigravityRoutes(ctx, antigravityStore, antigravityModelSettings, antigravityPreferences, proxyFetch, antigravityAccountPool);
15900
16507
  const disposeCommandCodeRoutes = registerCommandCodeRoutes(ctx, commandCodeStore, commandCodeModelSettings, commandCodePreferences, {
15901
16508
  fetchFn: proxyFetch,
15902
16509
  serving: () => commandCodeRegistration !== void 0,
@@ -16019,7 +16626,9 @@ function apply(ctx, pluginConfig = {}) {
16019
16626
  disposeAdapter();
16020
16627
  disposeRoutes();
16021
16628
  disposeAntigravityRoutes();
16022
- disposeAntigravityAdapter();
16629
+ releaseHandle(antigravityRouteWatch);
16630
+ antigravityRegistration?.();
16631
+ antigravityRegistration = void 0;
16023
16632
  disposeCommandCodeRoutes();
16024
16633
  releaseHandle(commandCodeRouteWatch);
16025
16634
  commandCodeRegistration?.();
@@ -16045,4 +16654,4 @@ function localWebServerBaseUrl(host, port) {
16045
16654
  return `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
16046
16655
  }
16047
16656
  //#endregion
16048
- export { AntigravityAdapter, CodexChatGptAdapter, CommandCodeAdapter, FileCredentialStore as CommandCodeCredentialStore, FileModelSettingsStore as CommandCodeModelSettingsStore, Config, DEFAULT_SUBAGENT_INHERIT_TOOLS, FileCredentialStore$1 as FileCredentialStore, FileModelSettingsStore$1 as FileModelSettingsStore, KIMI_CODE_MODELS, KIMI_CODE_RETRY_POLICY_CONFIG, KimiCodeAdapter, FileCredentialStore$2 as KimiCodeCredentialStore, FileModelSettingsStore$2 as KimiCodeModelSettingsStore, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, RELAY_PROBE_ENV, RELAY_PROBE_FILE_ENV, RELAY_PROBE_FILE_NAME, RELAY_PROBE_MAX_BYTES, RELAY_SOURCE_KINDS, RelayProbe, ResponsesClient, SUBAGENT_MODEL_SELECTION_NAMESPACE, SUBAGENT_POLICY_EVENT, SearchProviderSwitcher, UsageService, WindowsDpapiTokenStore, apply, auditChildRoutes, auditedRoutesOf, authorizedRoutesFor, beginWebLogin as beginKimiCodeLogin, beginWebLogin$1 as beginWebLogin, childRoutesOf, classifyKimiFailure, clearCachedQuota, clearCachedQuota$1 as clearCommandCodeQuota, clearCachedQuota$2 as clearKimiCodeQuota, credentialPath as commandCodeCredentialPath, modelSettingsPath as commandCodeModelSettingsPath, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createFileRelayProbeSink, createPlatformTokenStore, createSubagentAuthorization, credentialPath$1 as credentialPath, delegationDenialReason, delegationModeOf, detectSystemProxy, effectiveRouteOf, ensureAccessToken as ensureKimiCodeAccessToken, fetchAccountQuota, fetchAccountQuota$1 as fetchCommandCodeQuota, fetchAccountQuota$2 as fetchKimiCodeQuota, fetchUserInfo as fetchKimiCodeUserInfo, getCachedQuota, getWebLoginStatus as getCommandCodeLoginStatus, getCachedQuota$1 as getCommandCodeQuota, getCommandCodeWebStatus, getWebLoginStatus$1 as getKimiCodeLoginStatus, getCachedQuota$2 as getKimiCodeQuota, getKimiCodeWebStatus, inheritOverrideReason, inheritRouteDenialReason, inheritedRouteOf, inject, installRelayProbe, installSubagentModelAuthorization, credentialPath$2 as kimiCodeCredentialPath, kimiCodeModelDef, modelSettingsPath$1 as kimiCodeModelSettingsPath, loadProviderModels as loadCommandCodeModels, loadProviderModels$1 as loadKimiCodeModels, loginAndSave, mapCodexUsage, modelSettingsPath$2 as modelSettingsPath, normalizeDelegationToolNames, normalizeInheritToolNames, parseAllowedRoutes, parseCodexUsage, parseResponsesStream, policyRoutesOf, readChildDescriptor, refreshAntigravityToken, refreshAccessToken as refreshKimiCodeToken, registerCommandCodePreferenceStore, registerCommandCodeRoutes, registerKimiCodePreferenceStore, registerKimiCodeRoutes, relayProbeEnabled, relayProbeEnvFile, relayProbeEnvValue, relayProbeLogPath, requestDeviceAuthorization as requestKimiCodeDeviceAuthorization, resolveRegion as resolveKimiCodeRegion, saveApiKey as saveCommandCodeApiKey, beginWebLogin$2 as startCommandCodeLogin, subagentModelSelectionPreference, unauthorizedRouteReason, validateAuthorizationScope, validateDelegationToolNames, validateInheritToolNames, violationText };
16657
+ export { AccountPoolStore, AntigravityAdapter, CodexChatGptAdapter, CommandCodeAdapter, FileCredentialStore as CommandCodeCredentialStore, FileModelSettingsStore as CommandCodeModelSettingsStore, Config, DEFAULT_SUBAGENT_INHERIT_TOOLS, FileCredentialStore$1 as FileCredentialStore, FileModelSettingsStore$1 as FileModelSettingsStore, KIMI_CODE_MODELS, KIMI_CODE_RETRY_POLICY_CONFIG, KimiCodeAdapter, FileCredentialStore$2 as KimiCodeCredentialStore, FileModelSettingsStore$2 as KimiCodeModelSettingsStore, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, RELAY_PROBE_ENV, RELAY_PROBE_FILE_ENV, RELAY_PROBE_FILE_NAME, RELAY_PROBE_MAX_BYTES, RELAY_SOURCE_KINDS, RelayProbe, ResponsesClient, SUBAGENT_MODEL_SELECTION_NAMESPACE, SUBAGENT_POLICY_EVENT, SearchProviderSwitcher, UsageService, WindowsDpapiTokenStore, apply, auditChildRoutes, auditedRoutesOf, authorizedRoutesFor, beginWebLogin as beginKimiCodeLogin, beginWebLogin$1 as beginWebLogin, childRoutesOf, classifyKimiFailure, clearCachedQuota, clearCachedQuota$1 as clearCommandCodeQuota, clearCachedQuota$2 as clearKimiCodeQuota, credentialPath as commandCodeCredentialPath, modelSettingsPath as commandCodeModelSettingsPath, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createFileRelayProbeSink, createPlatformTokenStore, createSubagentAuthorization, credentialPath$1 as credentialPath, delegationDenialReason, delegationModeOf, detectSystemProxy, effectiveRouteOf, ensureAccessToken as ensureKimiCodeAccessToken, fetchAccountQuota, fetchAccountQuota$1 as fetchCommandCodeQuota, fetchAccountQuota$2 as fetchKimiCodeQuota, fetchUserInfo as fetchKimiCodeUserInfo, getCachedQuota, getWebLoginStatus as getCommandCodeLoginStatus, getCachedQuota$1 as getCommandCodeQuota, getCommandCodeWebStatus, getWebLoginStatus$1 as getKimiCodeLoginStatus, getCachedQuota$2 as getKimiCodeQuota, getKimiCodeWebStatus, inheritOverrideReason, inheritRouteDenialReason, inheritedRouteOf, inject, installRelayProbe, installSubagentModelAuthorization, credentialPath$2 as kimiCodeCredentialPath, kimiCodeModelDef, modelSettingsPath$1 as kimiCodeModelSettingsPath, loadProviderModels as loadCommandCodeModels, loadProviderModels$1 as loadKimiCodeModels, loginAndSave, mapCodexUsage, modelSettingsPath$2 as modelSettingsPath, normalizeDelegationToolNames, normalizeInheritToolNames, parseAllowedRoutes, parseCodexUsage, parseResponsesStream, policyRoutesOf, readChildDescriptor, refreshAntigravityToken, refreshAccessToken as refreshKimiCodeToken, registerCommandCodePreferenceStore, registerCommandCodeRoutes, registerKimiCodePreferenceStore, registerKimiCodeRoutes, relayProbeEnabled, relayProbeEnvFile, relayProbeEnvValue, relayProbeLogPath, requestDeviceAuthorization as requestKimiCodeDeviceAuthorization, resolveRegion as resolveKimiCodeRegion, saveApiKey as saveCommandCodeApiKey, beginWebLogin$2 as startCommandCodeLogin, subagentModelSelectionPreference, unauthorizedRouteReason, validateAuthorizationScope, validateDelegationToolNames, validateInheritToolNames, violationText };