@codexhost/cli-win32-arm64 0.16.1 → 0.17.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.
@@ -19048,6 +19048,16 @@ function snapshotFromHistory(contents, ref, cwd, profile = CODEBUDDY_RUNTIME_PRO
19048
19048
  continue;
19049
19049
  if (supportsNativeCommands && row.type === "message" && row.role === "user" && data.agent === "compact" && !manualCompactions.has(text(row.id)))
19050
19050
  continue;
19051
+ if (row.type === "message" && row.role === "user" && data.startsNewUserRequest === false && !localCommand && data.agent !== "compact" && !isNativeCompactionSummary(row)) {
19052
+ const contextOnly = body.trim().length > 0 && body.replace(/<system-reminder\b[^>]*\sdata-role=(["'])user-context\1[^>]*>[\s\S]*?<\/system-reminder>/gu, "").trim().length === 0;
19053
+ if (data.isMeta === true || contextOnly)
19054
+ continue;
19055
+ if (current) {
19056
+ if (body)
19057
+ current.input.push({ type: "text", text: body });
19058
+ continue;
19059
+ }
19060
+ }
19051
19061
  if (includeCompactionHistory && isNativeCompactionSummary(row)) {
19052
19062
  if (supportsNativeCommands && current) {
19053
19063
  const outcome = data.isCompacted === true ? { status: "succeeded" } : {
@@ -16263,6 +16263,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16263
16263
  return `${HARNESS_COMMAND_MENTION_PATH_PREFIX}${encodeURIComponent(name).replace(/[()]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`)}`;
16264
16264
  }
16265
16265
 
16266
+ // ../shared-contracts/dist/desktop-attachments.js
16267
+ var ATTACHED_FILES_HEADING = /^\s*# Files mentioned by the user:[ \t]*(?:\r?\n|$)/u;
16268
+ var REQUEST_HEADING = /(?:^|\n)## My request:[ \t]*(?:\r?\n|$)/u;
16269
+ var IMAGE_ATTACHMENT_PATTERN = /(?:^|\n)## [^\r\n]+: ((?:\/|[A-Za-z]:[\\/]|\\\\)[^\r\n]+)\r?\nImage attachment: true(?=\r?\n|$)/gu;
16270
+ var CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
16271
+ function desktopImageAttachmentPaths(text) {
16272
+ const end = text.search(REQUEST_HEADING);
16273
+ const context = end < 0 ? text : text.slice(0, end);
16274
+ if (!ATTACHED_FILES_HEADING.test(context))
16275
+ return [];
16276
+ return [...context.matchAll(IMAGE_ATTACHMENT_PATTERN)].map((match) => match[1] ?? "").filter((path) => path.length > 0 && !CONTROL_CHARACTER_PATTERN.test(path));
16277
+ }
16278
+
16266
16279
  // ../shared-contracts/dist/remote-runtime.js
16267
16280
  var RUNTIME_STATUS_METHOD = "codexhost/runtime/status";
16268
16281
  var REMOTE_UPDATE_METHOD = "codexhost/remote/update";
@@ -17371,12 +17384,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17371
17384
  if (!entry)
17372
17385
  return;
17373
17386
  entry.update((current) => {
17387
+ const { original } = entry;
17388
+ if (!original)
17389
+ return current;
17374
17390
  const settings = current.modelSettings;
17375
17391
  return settings?.model === entry.model && current.modelSettingsPersistAsDefault === false ? {
17376
17392
  ...current,
17377
- modelSettings: entry.original.modelSettings,
17378
- modelSettingsPersistAsDefault: entry.original.modelSettingsPersistAsDefault,
17379
- isManuallyChanged: entry.original.isManuallyChanged
17393
+ modelSettings: original.modelSettings,
17394
+ modelSettingsPersistAsDefault: original.modelSettingsPersistAsDefault,
17395
+ isManuallyChanged: original.isManuallyChanged
17380
17396
  } : current;
17381
17397
  });
17382
17398
  captured.delete(key);
@@ -17385,15 +17401,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17385
17401
  has(key) {
17386
17402
  return captured.has(key);
17387
17403
  },
17404
+ /** The carrier last written to this draft, or null while it keeps its native setting. */
17405
+ model(key) {
17406
+ return captured.get(key)?.model ?? null;
17407
+ },
17388
17408
  apply(key, binding, model2) {
17389
17409
  if (model2 === null) {
17390
17410
  restore(key);
17391
17411
  return;
17392
17412
  }
17393
17413
  const { update, usesAccountPreferences } = binding;
17414
+ const previous = captured.get(key);
17415
+ const entry = { update, model: model2 };
17394
17416
  update((current) => {
17395
- const previous = captured.get(key);
17396
- captured.set(key, { update, original: previous?.original ?? current, model: model2 });
17417
+ entry.original ??= previous?.original ?? current;
17397
17418
  const settings = current.modelSettings;
17398
17419
  if (settings?.model === model2 && settings.usesAccountPreferences === usesAccountPreferences && current.modelSettingsPersistAsDefault === false)
17399
17420
  return current;
@@ -17410,6 +17431,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17410
17431
  }
17411
17432
  };
17412
17433
  });
17434
+ captured.set(key, entry);
17413
17435
  },
17414
17436
  dispose() {
17415
17437
  for (const key of captured.keys())
@@ -18663,6 +18685,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18663
18685
  loaded = true;
18664
18686
  show(value);
18665
18687
  }).catch(() => {
18688
+ loaded = true;
18666
18689
  status.textContent = messages.launchPathLoadError;
18667
18690
  }).finally(() => {
18668
18691
  busy = false;
@@ -20242,7 +20265,7 @@ ${messages.harnessVersionLatest}: ${harnessVersionLabel(version2.state, messages
20242
20265
  launchPathAutomatic: "No saved override. Uses environment configuration, then automatic discovery.",
20243
20266
  launchPathSaving: "Saving\u2026",
20244
20267
  launchPathLoading: "Loading launch settings\u2026",
20245
- launchPathLoadError: "Could not load launch settings. Reopen this detail panel to retry.",
20268
+ launchPathLoadError: "Could not load launch settings. Save an installation directory or reset to automatic discovery to replace them.",
20246
20269
  launchPathSaveError: "Could not save. Enter an existing absolute installation folder on this Host and check configuration permissions.",
20247
20270
  connectionOfficialWebsite: "Visit official website",
20248
20271
  connectionOpenHarnessWeb: "Open DeepSeek Harness Web",
@@ -20521,7 +20544,7 @@ ${messages.harnessVersionLatest}: ${harnessVersionLabel(version2.state, messages
20521
20544
  launchPathAutomatic: "\u672A\u8BBE\u7F6E\u81EA\u5B9A\u4E49\u8DEF\u5F84\uFF0C\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u6216\u81EA\u52A8\u53D1\u73B0\u3002",
20522
20545
  launchPathSaving: "\u6B63\u5728\u4FDD\u5B58\u2026",
20523
20546
  launchPathLoading: "\u6B63\u5728\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\u2026",
20524
- launchPathLoadError: "\u65E0\u6CD5\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6B64\u8BE6\u60C5\u9762\u677F\u91CD\u8BD5\u3002",
20547
+ launchPathLoadError: "\u65E0\u6CD5\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\u3002\u4FDD\u5B58\u5B89\u88C5\u76EE\u5F55\u6216\u6062\u590D\u81EA\u52A8\u53D1\u73B0\u5373\u53EF\u66FF\u6362\u3002",
20525
20548
  launchPathSaveError: "\u4FDD\u5B58\u5931\u8D25\u3002\u8BF7\u586B\u5199\u6B64 Host \u4E0A\u5B9E\u9645\u5B58\u5728\u7684\u5B89\u88C5\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u5E76\u786E\u8BA4\u914D\u7F6E\u76EE\u5F55\u53EF\u5199\u3002",
20526
20549
  connectionOfficialWebsite: "\u8BBF\u95EE\u5B98\u7F51",
20527
20550
  connectionOpenHarnessWeb: "\u6253\u5F00 DeepSeek Harness Web",
@@ -25766,10 +25789,16 @@ Codex Fast mode prioritizes requests and may increase usage.`
25766
25789
  const currentRole = manager.getStreamRole?.(threadId);
25767
25790
  if (isRecord7(currentRole) && currentRole.role === "follower")
25768
25791
  return originalSteer.apply(manager, args);
25769
- if (!Array.isArray(input) || input.length === 0 || input.some(
25770
- (item) => !isRecord7(item) || item.type !== "text" || typeof item.text !== "string"
25771
- ) || !input.some((item) => isRecord7(item) && typeof item.text === "string" && item.text.trim())) {
25772
- throw new Error("External steering requires non-empty text input");
25792
+ if (!Array.isArray(input) || input.length === 0 || input.some((item) => {
25793
+ if (!isRecord7(item)) return true;
25794
+ if (item.type === "text") return typeof item.text !== "string";
25795
+ if (item.type === "localImage") return typeof item.path !== "string" || !item.path;
25796
+ if (item.type === "image") return typeof item.url !== "string" || !item.url;
25797
+ return true;
25798
+ }) || !input.some(
25799
+ (item) => isRecord7(item) && (item.type !== "text" || typeof item.text === "string" && item.text.trim())
25800
+ )) {
25801
+ throw new Error("External steering requires non-empty text or image input");
25773
25802
  }
25774
25803
  if (toolOutput != null) throw new Error("External steering cannot replace a tool response");
25775
25804
  if (!isRecord7(restoreMessage) || !isRecord7(restoreMessage.context)) {
@@ -25890,16 +25919,6 @@ Codex Fast mode prioritizes requests and may increase usage.`
25890
25919
  for (let index = 0; index < decoded.length; index += 1) bytes[index] = decoded.charCodeAt(index);
25891
25920
  return { contents: new Blob([bytes], { type: mimeType }), extension };
25892
25921
  }
25893
- function nativeImagePaths(text) {
25894
- const context = text.split("## My request:")[0] ?? "";
25895
- const start = context.indexOf("# Files mentioned by the user:");
25896
- if (start < 0) return [];
25897
- return [
25898
- ...context.slice(start).matchAll(
25899
- /(?:^|\n)## [^\r\n]+: ((?:\/|[A-Za-z]:[\\/]|\\\\)[^\r\n]+)\r?\nImage attachment: true(?=\r?\n|$)/gu
25900
- )
25901
- ].map((match) => match[1]).filter(filePath);
25902
- }
25903
25922
  function createRemoteAttachmentSender(target, hostId2, isCurrent) {
25904
25923
  const prepared = /* @__PURE__ */ new WeakMap();
25905
25924
  return (params, send) => {
@@ -25924,7 +25943,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
25924
25943
  if (cached2) return cached2.then(dispatch);
25925
25944
  const input = params.input;
25926
25945
  const text = input.filter((item) => isRecord8(item) && item.type === "text").map((item) => isRecord8(item) && typeof item.text === "string" ? item.text : "").join("\n");
25927
- const existingPaths = nativeImagePaths(text);
25946
+ const existingPaths = desktopImageAttachmentPaths(text);
25928
25947
  const prepare = async () => {
25929
25948
  if (existingPaths.length === images.length) return params;
25930
25949
  if (images.length > 20) throw new Error("Too many remote image attachments (maximum 20)");
@@ -27433,8 +27452,18 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27433
27452
  const draftKey = target[1];
27434
27453
  if (!binding || !route.policy.scopedCreation)
27435
27454
  return agent === "codex" && !draftModels.has(draftKey);
27436
- draftModels.apply(draftKey, binding, carrier ?? null);
27437
- if (route.policy.select(carrier ?? null, draftKey, binding.creationModes)) {
27455
+ const previous = draftModels.model(draftKey);
27456
+ const policyChanged = route.policy.select(carrier ?? null, draftKey, binding.creationModes);
27457
+ try {
27458
+ draftModels.apply(draftKey, binding, carrier ?? null);
27459
+ } catch (error51) {
27460
+ try {
27461
+ route.policy.select(previous, draftKey, binding.creationModes);
27462
+ } catch {
27463
+ }
27464
+ throw error51;
27465
+ }
27466
+ if (policyChanged) {
27438
27467
  modelUpdates += 1;
27439
27468
  liveStatus.modelUpdates = modelUpdates;
27440
27469
  }
@@ -30639,7 +30668,7 @@ ${detail}` : ""}`
30639
30668
  "codexhost was not detected over SSH. Install it on the remote computer or add it to the login shell PATH, then retry": "\u901A\u8FC7 SSH \u672A\u68C0\u6D4B\u5230 codexhost\u3002\u8BF7\u5728\u8FDC\u7A0B\u7535\u8111\u4E0A\u5B89\u88C5\uFF0C\u6216\u5C06\u5DF2\u5B89\u88C5\u7684 codexhost \u52A0\u5165\u767B\u5F55 shell \u7684 PATH \u540E\u91CD\u8BD5",
30640
30669
  "The active codexhost does not match the global npm installation. Uninstall only the remote service, or remove the package manually on the remote computer": "\u5F53\u524D codexhost \u4E0E npm \u5168\u5C40\u5B89\u88C5\u4F4D\u7F6E\u4E0D\u5339\u914D\u3002\u8BF7\u9009\u62E9\u4EC5\u5378\u8F7D\u8FDC\u7A0B\u670D\u52A1\uFF0C\u6216\u5728\u8FDC\u7A0B\u7535\u8111\u4E0A\u624B\u52A8\u5378\u8F7D\u8F6F\u4EF6\u5305",
30641
30670
  "The remote service was uninstalled, but removing the codexhost package failed. Check npm permissions on the remote computer and retry": "\u8FDC\u7A0B\u670D\u52A1\u5DF2\u5378\u8F7D\uFF0C\u4F46 codexhost \u8F6F\u4EF6\u5305\u5378\u8F7D\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\u8FDC\u7A0B\u7535\u8111\u4E0A\u7684 npm \u6743\u9650\u540E\u91CD\u8BD5",
30642
- "Remote Node.js is unsupported. Select Node.js 22.19 or later in the 22.x series, or Node.js 24.x": "\u8FDC\u7A0B Node.js \u7248\u672C\u4E0D\u53D7\u652F\u6301\uFF0C\u8BF7\u9009\u62E9 Node.js 22.19 \u53CA\u4EE5\u4E0A\u7684 22.x \u7248\u672C\uFF0C\u6216 Node.js 24.x",
30671
+ "Remote Node.js is unsupported. Select Node.js 22.19 or later, except 23.x": "\u8FDC\u7A0B Node.js \u7248\u672C\u4E0D\u53D7\u652F\u6301\uFF0C\u8BF7\u9009\u62E9 Node.js 22.19 \u53CA\u4EE5\u4E0A\u7248\u672C\uFF0C\u4F46\u4E0D\u5305\u62EC 23.x",
30643
30672
  "npm installation failed. Check network access and global installation permissions": "npm \u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u548C\u5168\u5C40\u5B89\u88C5\u6743\u9650",
30644
30673
  "Remote service configuration failed. Check Codex CLI and the remote desktop login": "\u8FDC\u7A0B\u670D\u52A1\u914D\u7F6E\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 Codex CLI \u4EE5\u53CA\u8FDC\u7A0B\u7535\u8111\u7684\u684C\u9762\u767B\u5F55\u72B6\u6001",
30645
30674
  "Remote service could not stop. Check the remote service before retrying": "\u8FDC\u7A0B\u670D\u52A1\u65E0\u6CD5\u505C\u6B62\uFF0C\u8BF7\u68C0\u67E5\u8FDC\u7A0B\u670D\u52A1\u540E\u91CD\u8BD5",
@@ -32071,6 +32100,30 @@ ${detail}` : ""}`
32071
32100
  };
32072
32101
  }
32073
32102
 
32103
+ // src/settings/session-import-sources.ts
32104
+ async function loadSessionImportSources(client, diagnostics, signal, refresh) {
32105
+ const { harnesses } = await client.listSessionImportSources();
32106
+ signal.throwIfAborted();
32107
+ if (!diagnostics || harnesses.length === 0) return harnesses;
32108
+ const hostId2 = client.hostId ?? "local";
32109
+ const readHost = () => diagnostics.snapshot().hosts.find((host2) => host2.hostId === hostId2);
32110
+ let host = readHost();
32111
+ const incomplete = () => !host || Boolean(host.directoryError) || harnesses.some(({ harnessId }) => {
32112
+ const status = host?.agents.find(({ agent }) => agent === harnessId)?.availability;
32113
+ return status === void 0 || status === "checking";
32114
+ });
32115
+ if (refresh || incomplete()) {
32116
+ await diagnostics.refresh(hostId2);
32117
+ signal.throwIfAborted();
32118
+ host = readHost();
32119
+ }
32120
+ if (incomplete()) throw new Error("Harness installation diagnostics are incomplete");
32121
+ const missing = new Set(
32122
+ host?.agents.filter(({ availability }) => availability === "notInstalled").map(({ agent }) => agent)
32123
+ );
32124
+ return harnesses.filter(({ harnessId }) => !missing.has(harnessId));
32125
+ }
32126
+
32074
32127
  // src/settings/session-import-page.ts
32075
32128
  function shortSessionId(value) {
32076
32129
  return value.length <= 18 ? value : `${value.slice(0, 10)}\u2026${value.slice(-6)}`;
@@ -32140,7 +32193,7 @@ ${detail}` : ""}`
32140
32193
  ...getDiagnostics()?.snapshot().hosts.map(({ hostId: hostId2 }) => hostId2) ?? [],
32141
32194
  ...current ? [current] : []
32142
32195
  ])
32143
- ];
32196
+ ].filter((hostId2) => hostId2 !== "durable");
32144
32197
  displayedHostId = current;
32145
32198
  const scrollLeft = hostOptions.scrollLeft;
32146
32199
  hostOptions.replaceChildren();
@@ -32484,10 +32537,14 @@ ${detail}` : ""}`
32484
32537
  content.append(list);
32485
32538
  updateImportActions();
32486
32539
  };
32487
- const load = () => {
32540
+ const load = (refreshDiagnostics = false) => {
32488
32541
  if (importingId !== null || context.signal.aborted) return;
32489
32542
  loadedClient = null;
32490
- const client = getClient(selectedHostId);
32543
+ let client = getClient(selectedHostId);
32544
+ if (client?.hostId === "durable") {
32545
+ selectedHostId = "local";
32546
+ client = getClient(selectedHostId);
32547
+ }
32491
32548
  renderHosts(client);
32492
32549
  listControls.setBusy(client !== null);
32493
32550
  refresh.disabled = client !== null;
@@ -32500,11 +32557,11 @@ ${detail}` : ""}`
32500
32557
  void context.runLatest(
32501
32558
  async (signal) => {
32502
32559
  if (!client) throw new RendererSessionImportUnavailableError();
32503
- const missing = new Set(
32504
- getDiagnostics()?.snapshot().hosts.find(({ hostId: hostId2 }) => hostId2 === (client.hostId ?? "local"))?.agents.filter(({ availability }) => availability === "notInstalled").map(({ agent }) => agent)
32505
- );
32506
- const harnesses = (await client.listSessionImportSources()).harnesses.filter(
32507
- ({ harnessId }) => !missing.has(harnessId)
32560
+ const harnesses = await loadSessionImportSources(
32561
+ client,
32562
+ getDiagnostics(),
32563
+ signal,
32564
+ refreshDiagnostics
32508
32565
  );
32509
32566
  const selected = harnesses.find(({ harnessId }) => harnessId === requestedHarness)?.harnessId ?? harnesses[0]?.harnessId ?? null;
32510
32567
  if (signal.aborted) throw new Error("Session import selection changed");
@@ -32555,7 +32612,7 @@ ${detail}` : ""}`
32555
32612
  load();
32556
32613
  hostButtons.find((button2) => button2.dataset.sessionImportHost === hostId2)?.focus();
32557
32614
  };
32558
- refresh.addEventListener("click", load);
32615
+ refresh.addEventListener("click", () => load(true));
32559
32616
  load();
32560
32617
  return void 0;
32561
32618
  }
@@ -42325,6 +42382,7 @@ ${usage_default}`;
42325
42382
  });
42326
42383
  const mountedByComposer = /* @__PURE__ */ new Map();
42327
42384
  const catalogRequests = /* @__PURE__ */ new WeakMap();
42385
+ const draftUsageRequests = /* @__PURE__ */ new WeakMap();
42328
42386
  const pendingReplacements = /* @__PURE__ */ new Map();
42329
42387
  let disposed = false;
42330
42388
  const disposeReasoningSoftWrap = installReasoningTranscriptSoftWrap(document);
@@ -42451,7 +42509,7 @@ ${usage_default}`;
42451
42509
  for (const mounted of mountedByComposer.values()) {
42452
42510
  if (mounted.hostId !== hostId2) continue;
42453
42511
  renderMounted(mounted);
42454
- void refreshDraftCodexUsage(mounted);
42512
+ if (controller.get(mounted.composer).agent === "codex") void refreshDraftUsage(mounted);
42455
42513
  }
42456
42514
  });
42457
42515
  });
@@ -42634,36 +42692,59 @@ ${usage_default}`;
42634
42692
  renderMounted(mounted);
42635
42693
  }
42636
42694
  };
42637
- const refreshDraftCodexUsage = async (mounted) => {
42695
+ const refreshDraftUsage = async (mounted) => {
42638
42696
  const state = controller.get(mounted.composer);
42639
- if (state.agent !== "codex" || state.phase !== "draft" || controller.isSubmissionPending(mounted.composer) || threadIdFromComposerModelTarget(mounted.modelTarget))
42697
+ if (state.phase !== "draft" || controller.isSwitching(mounted.composer) || controller.isSubmissionPending(mounted.composer) || threadIdFromComposerModelTarget(mounted.modelTarget))
42640
42698
  return;
42641
- const accounts = composerCodexAccounts(mounted.composer);
42642
- const client = accounts?.client;
42699
+ const agent = state.agent;
42700
+ const accounts = agent === "codex" ? composerCodexAccounts(mounted.composer) : null;
42643
42701
  const accountId = accounts?.readyAccountId;
42702
+ const client = composerClient(mounted);
42644
42703
  const hostId2 = mounted.hostId;
42704
+ const previous = draftUsageRequests.get(mounted);
42705
+ if (agent !== "codex" && previous?.pending && previous.client === client && previous.generation === mounted.usageRequestGeneration)
42706
+ return;
42645
42707
  const generation = ++mounted.usageRequestGeneration;
42708
+ const request = { client, generation, pending: true };
42709
+ draftUsageRequests.set(mounted, request);
42710
+ mounted.draftUsageClient = null;
42646
42711
  mounted.usage = null;
42647
42712
  mounted.accountCredits = null;
42713
+ mounted.accountCreditsSupported = false;
42648
42714
  renderMounted(mounted);
42649
- if (!accountId || !client?.inspectCodexAccountUsage) return;
42715
+ const isCurrent = () => !disposed && mounted.hostId === hostId2 && composerClient(mounted) === client && mounted.composer.isConnected && mountedByComposer.get(mounted.composer) === mounted && mounted.usageRequestGeneration === generation && controller.get(mounted.composer).agent === agent && controller.get(mounted.composer).phase === "draft" && !controller.isSwitching(mounted.composer) && !controller.isSubmissionPending(mounted.composer) && !threadIdFromComposerModelTarget(mounted.modelTarget);
42650
42716
  try {
42651
- const result = await client.inspectCodexAccountUsage({ accountId });
42652
- if (disposed || mounted.hostId !== hostId2 || composerCodexAccounts(mounted.composer) !== accounts || !mounted.composer.isConnected || mountedByComposer.get(mounted.composer) !== mounted || mounted.usageRequestGeneration !== generation || controller.get(mounted.composer).agent !== "codex" || controller.get(mounted.composer).phase !== "draft" || controller.isSubmissionPending(mounted.composer) || threadIdFromComposerModelTarget(mounted.modelTarget) || accounts.readyAccountId !== accountId || result.accountId !== accountId)
42653
- return;
42654
- mounted.usage = result.usage;
42655
- mounted.accountCredits = result.accountCredits ?? null;
42717
+ if (!client) return;
42718
+ if (agent === "codex") {
42719
+ if (!accountId || !client.inspectCodexAccountUsage) return;
42720
+ const result = await client.inspectCodexAccountUsage({ accountId });
42721
+ if (!isCurrent() || composerCodexAccounts(mounted.composer) !== accounts || accounts?.readyAccountId !== accountId || result.accountId !== accountId)
42722
+ return;
42723
+ mounted.usage = result.usage;
42724
+ mounted.accountCredits = result.accountCredits ?? null;
42725
+ } else {
42726
+ if (!client.inspectHarnessAccount) return;
42727
+ const result = await client.inspectHarnessAccount({
42728
+ harnessId: harnessIdSchema.parse(agent),
42729
+ refresh: true
42730
+ });
42731
+ if (!isCurrent() || result.harnessId !== agent) return;
42732
+ mounted.accountCredits = result.account?.credits ?? null;
42733
+ }
42734
+ mounted.draftUsageClient = client;
42656
42735
  renderMounted(mounted);
42657
42736
  } catch {
42737
+ } finally {
42738
+ request.pending = false;
42658
42739
  }
42659
42740
  };
42660
42741
  const refreshThreadUsage = async (mounted, refresh) => {
42661
42742
  const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
42662
- if (!threadId && controller.get(mounted.composer).agent === "codex") {
42663
- await refreshDraftCodexUsage(mounted);
42743
+ if (!threadId) {
42744
+ await refreshDraftUsage(mounted);
42664
42745
  return;
42665
42746
  }
42666
- if (!threadId || !modelControl) {
42747
+ if (!modelControl) {
42667
42748
  mounted.usage = null;
42668
42749
  mounted.accountCredits = null;
42669
42750
  usageRefreshAttempts.delete(mounted.composer);
@@ -43458,8 +43539,23 @@ ${usage_default}`;
43458
43539
  if (agent !== "codex" && composerAvailability(mounted)[agent] !== "ready") {
43459
43540
  return false;
43460
43541
  }
43542
+ const state = controller.get(mounted.composer);
43543
+ if (state.phase !== "draft" || controller.isSwitching(mounted.composer)) return false;
43461
43544
  controller.clearPendingSubmission(mounted.composer);
43462
- const composerId = controller.get(mounted.composer).composerId;
43545
+ const composerId = state.composerId;
43546
+ for (const candidate of mountedByComposer.values()) {
43547
+ if (controller.get(candidate.composer).composerId !== composerId) continue;
43548
+ candidate.usageRequestGeneration += 1;
43549
+ candidate.usage = null;
43550
+ candidate.accountCredits = null;
43551
+ candidate.accountCreditsSupported = false;
43552
+ usageRefreshAttempts.delete(candidate.composer);
43553
+ const timer = usageRefreshTimers.get(candidate.composer);
43554
+ if (timer !== void 0) {
43555
+ window.clearTimeout(timer);
43556
+ usageRefreshTimers.delete(candidate.composer);
43557
+ }
43558
+ }
43463
43559
  controller.invalidateModelRequests(mounted.composer);
43464
43560
  const switching = controller.switchAgent(mounted.composer, agent, {
43465
43561
  applyAgent: (nextAgent) => applyDraftAgentCarrier(mounted.composer, nextAgent),
@@ -43487,7 +43583,9 @@ ${usage_default}`;
43487
43583
  return false;
43488
43584
  } finally {
43489
43585
  for (const candidate of mountedByComposer.values()) {
43490
- if (controller.get(candidate.composer).composerId === composerId) renderMounted(candidate);
43586
+ if (controller.get(candidate.composer).composerId !== composerId) continue;
43587
+ renderMounted(candidate);
43588
+ void refreshDraftUsage(candidate);
43491
43589
  }
43492
43590
  }
43493
43591
  };
@@ -43502,7 +43600,7 @@ ${usage_default}`;
43502
43600
  for (const mounted of mountedByComposer.values()) {
43503
43601
  if (mounted.hostId !== hostId2) continue;
43504
43602
  renderMounted(mounted);
43505
- void refreshDraftCodexUsage(mounted);
43603
+ if (controller.get(mounted.composer).agent === "codex") void refreshDraftUsage(mounted);
43506
43604
  }
43507
43605
  })
43508
43606
  );
@@ -43716,6 +43814,7 @@ ${usage_default}`;
43716
43814
  void clearDraftPrewarm(mounted.composer).catch(() => void 0);
43717
43815
  }
43718
43816
  void loadExternalCatalog(mounted);
43817
+ void refreshDraftUsage(mounted);
43719
43818
  continue;
43720
43819
  }
43721
43820
  const target = controllerTarget(mounted.modelTarget, hostId2);
@@ -43744,11 +43843,18 @@ ${usage_default}`;
43744
43843
  }
43745
43844
  if (changed) sidebarAgentIcons.refresh();
43746
43845
  };
43747
- function reconcileHarnessAvailabilityHost() {
43846
+ function reconcileHarnessAvailabilityHost(retryDraftUsage = false) {
43748
43847
  for (const hostId3 of modelControl?.knownHostIds?.() ?? []) {
43749
43848
  hostHarnessAvailabilityState(hostId3);
43750
43849
  }
43751
43850
  reloadMountedOwnershipForHost();
43851
+ for (const mounted of mountedByComposer.values()) {
43852
+ const client = composerClient(mounted);
43853
+ const request = draftUsageRequests.get(mounted);
43854
+ if (controller.get(mounted.composer).agent !== "codex" && mounted.draftUsageClient !== client && (!request || request.client !== client || request.generation !== mounted.usageRequestGeneration || retryDraftUsage && !request.pending)) {
43855
+ void refreshDraftUsage(mounted);
43856
+ }
43857
+ }
43752
43858
  let connectionsChanged = false;
43753
43859
  for (const target of new Set([...mountedByComposer.values()].map((m) => m.hostId))) {
43754
43860
  if (!target) continue;
@@ -43955,6 +44061,7 @@ ${usage_default}`;
43955
44061
  accountCreditsSupported: inherited?.accountCreditsSupported ?? false,
43956
44062
  hostId: inherited?.hostId ?? hostId2,
43957
44063
  usageRequestGeneration: 0,
44064
+ draftUsageClient: null,
43958
44065
  commandRequestGeneration: 0
43959
44066
  };
43960
44067
  mountedByComposer.set(composer, mounted);
@@ -43974,7 +44081,7 @@ ${usage_default}`;
43974
44081
  } else if (state.agent !== "codex" && !isExternalConfigurationStable(mounted.modelView, mounted.permissionModeView)) {
43975
44082
  void loadExternalCatalog(mounted);
43976
44083
  }
43977
- if (!threadIdFromComposerModelTarget(modelTarget)) void refreshDraftCodexUsage(mounted);
44084
+ if (!threadIdFromComposerModelTarget(modelTarget)) void refreshDraftUsage(mounted);
43978
44085
  void refreshCommands(mounted);
43979
44086
  };
43980
44087
  const scan = () => {
@@ -44254,7 +44361,7 @@ ${usage_default}`;
44254
44361
  document.addEventListener("keydown", onKeyDown, true);
44255
44362
  document.addEventListener("click", onClick, true);
44256
44363
  const onWindowFocus = () => {
44257
- reconcileHarnessAvailabilityHost();
44364
+ reconcileHarnessAvailabilityHost(true);
44258
44365
  void loadCodexAccounts();
44259
44366
  for (const mounted of mountedByComposer.values()) {
44260
44367
  if (mounted.hostId === activeModelHostId(mounted.composer) && mounted.ownershipStatus === "error") {
@@ -44438,6 +44545,7 @@ ${usage_default}`;
44438
44545
  for (const mounted of mountedByComposer.values()) {
44439
44546
  renderMounted(mounted);
44440
44547
  void refreshCommands(mounted);
44548
+ if (controller.get(mounted.composer).agent !== "codex") void refreshDraftUsage(mounted);
44441
44549
  }
44442
44550
  },
44443
44551
  dispose() {
package/bin/codexhost.exe CHANGED
Binary file
Binary file
Binary file
Binary file