@codexhost/cli-win32-arm64 0.16.0 → 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.
Files changed (39) hide show
  1. package/README.md +2 -2
  2. package/THIRD_PARTY_NOTICES.txt +6 -2
  3. package/app/codexhost-distribution.json +1 -1
  4. package/app/console-server.mjs +59 -21
  5. package/app/console-web.js +49 -18
  6. package/app/desktop-controller.mjs +554 -34
  7. package/app/host-runtime.mjs +3436 -1846
  8. package/app/plugins/antigravity/plugin.mjs +39 -3
  9. package/app/plugins/claude-code/plugin.mjs +16 -7
  10. package/app/plugins/codebuddy/plugin.mjs +14 -1
  11. package/app/plugins/codex-usage/plugin.mjs +4 -1
  12. package/app/plugins/copilot/plugin.mjs +4 -1
  13. package/app/plugins/cursor-cli/plugin.mjs +13 -6
  14. package/app/plugins/deepseek-harness/plugin.mjs +463 -47
  15. package/app/plugins/devin/assets/icon.svg +1 -0
  16. package/app/plugins/devin/manifest.json +30 -0
  17. package/app/plugins/devin/plugin.mjs +23363 -0
  18. package/app/plugins/enabled.json +2 -0
  19. package/app/plugins/grok/plugin.mjs +476 -392
  20. package/app/plugins/hermes/plugin.mjs +457 -197
  21. package/app/plugins/kimi-code/plugin.mjs +4 -1
  22. package/app/plugins/kiro-cli/plugin.mjs +4 -1
  23. package/app/plugins/omp/plugin.mjs +4 -1
  24. package/app/plugins/opencode/plugin.mjs +4 -1
  25. package/app/plugins/pi/plugin.mjs +1464 -412
  26. package/app/plugins/qoder/plugin.mjs +9528 -8655
  27. package/app/plugins/qoder-cn/plugin.mjs +9528 -8655
  28. package/app/plugins/qwen-code/assets/icon.svg +1 -0
  29. package/app/plugins/qwen-code/manifest.json +29 -0
  30. package/app/plugins/qwen-code/plugin.mjs +29298 -0
  31. package/app/plugins/workbuddy/plugin.mjs +14 -1
  32. package/app/plugins/zcode/plugin.mjs +4 -1
  33. package/app/renderer-extension.js +510 -114
  34. package/bin/codexhost.exe +0 -0
  35. package/libexec/codexhost-node-repl.exe +0 -0
  36. package/libexec/codexhost-shim.exe +0 -0
  37. package/libexec/codexhost-updater.exe +0 -0
  38. package/licenses/Qwen-Code-SDK-LICENSE.txt +203 -0
  39. package/package.json +2 -2
@@ -15858,7 +15858,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15858
15858
  harnessId: harnessPluginIdSchema,
15859
15859
  model: harnessModelRefSchema.optional(),
15860
15860
  thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
15861
- permissionModeId: harnessPermissionModeIdSchema.optional()
15861
+ permissionModeId: harnessPermissionModeIdSchema.optional(),
15862
+ /** A draft prewarm create: stays unsubmitted until the user's first Turn.
15863
+ * Desktop forwards only the Model of a main-process prewarm to thread/start. */
15864
+ prewarm: external_exports.literal(true).optional()
15862
15865
  }).strict();
15863
15866
  function encodeHarnessPluginRoute(route) {
15864
15867
  const parsed = harnessPluginRouteSchema.parse(route);
@@ -16260,6 +16263,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16260
16263
  return `${HARNESS_COMMAND_MENTION_PATH_PREFIX}${encodeURIComponent(name).replace(/[()]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`)}`;
16261
16264
  }
16262
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
+
16263
16279
  // ../shared-contracts/dist/remote-runtime.js
16264
16280
  var RUNTIME_STATUS_METHOD = "codexhost/runtime/status";
16265
16281
  var REMOTE_UPDATE_METHOD = "codexhost/remote/update";
@@ -16350,8 +16366,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16350
16366
  if (!ownerWindow.document || !ownerWindow.location) return null;
16351
16367
  const page = new URL(ownerWindow.location.href);
16352
16368
  const urls = /* @__PURE__ */ new Set();
16353
- for (const link of ownerWindow.document.querySelectorAll('link[rel="modulepreload"][href]')) {
16354
- const url2 = new URL(link.getAttribute("href") ?? "", page);
16369
+ const catalog = Reflect.get(ownerWindow, "__codexhostLoadedModulesV1");
16370
+ let sources;
16371
+ if (catalog !== void 0) {
16372
+ if (typeof catalog !== "object" || catalog === null || !("complete" in catalog) || catalog.complete !== true || !("documentUrl" in catalog) || catalog.documentUrl !== page.href || !("urls" in catalog) || !Array.isArray(catalog.urls) || catalog.urls.length > 4096 || catalog.urls.some((url2) => typeof url2 !== "string"))
16373
+ throw new Error("Codex loaded module catalog is unavailable in this window");
16374
+ sources = catalog.urls;
16375
+ } else {
16376
+ sources = [...ownerWindow.document.querySelectorAll('link[rel="modulepreload"][href]')].map(
16377
+ (link) => link.getAttribute("href") ?? ""
16378
+ );
16379
+ }
16380
+ for (const source of sources) {
16381
+ let url2;
16382
+ try {
16383
+ url2 = new URL(source, page);
16384
+ } catch {
16385
+ continue;
16386
+ }
16355
16387
  if (url2.protocol === page.protocol && url2.host === page.host && url2.pathname.endsWith(".js") && !url2.search && !url2.hash)
16356
16388
  urls.add(url2.href);
16357
16389
  }
@@ -16369,6 +16401,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16369
16401
  for (const value of Object.values(module).filter(matchesServices)) matches.add(value);
16370
16402
  if (matches.size > 1) throw new Error("Codex native services are unavailable in this window");
16371
16403
  }
16404
+ if (catalog !== void 0 && Reflect.get(ownerWindow, "__codexhostLoadedModulesV1") !== catalog)
16405
+ throw new Error("Codex loaded module catalog changed during discovery. Try again once ready.");
16372
16406
  return [...matches][0] ?? null;
16373
16407
  }
16374
16408
 
@@ -17350,12 +17384,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17350
17384
  if (!entry)
17351
17385
  return;
17352
17386
  entry.update((current) => {
17387
+ const { original } = entry;
17388
+ if (!original)
17389
+ return current;
17353
17390
  const settings = current.modelSettings;
17354
17391
  return settings?.model === entry.model && current.modelSettingsPersistAsDefault === false ? {
17355
17392
  ...current,
17356
- modelSettings: entry.original.modelSettings,
17357
- modelSettingsPersistAsDefault: entry.original.modelSettingsPersistAsDefault,
17358
- isManuallyChanged: entry.original.isManuallyChanged
17393
+ modelSettings: original.modelSettings,
17394
+ modelSettingsPersistAsDefault: original.modelSettingsPersistAsDefault,
17395
+ isManuallyChanged: original.isManuallyChanged
17359
17396
  } : current;
17360
17397
  });
17361
17398
  captured.delete(key);
@@ -17364,15 +17401,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17364
17401
  has(key) {
17365
17402
  return captured.has(key);
17366
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
+ },
17367
17408
  apply(key, binding, model2) {
17368
17409
  if (model2 === null) {
17369
17410
  restore(key);
17370
17411
  return;
17371
17412
  }
17372
17413
  const { update, usesAccountPreferences } = binding;
17414
+ const previous = captured.get(key);
17415
+ const entry = { update, model: model2 };
17373
17416
  update((current) => {
17374
- const previous = captured.get(key);
17375
- captured.set(key, { update, original: previous?.original ?? current, model: model2 });
17417
+ entry.original ??= previous?.original ?? current;
17376
17418
  const settings = current.modelSettings;
17377
17419
  if (settings?.model === model2 && settings.usesAccountPreferences === usesAccountPreferences && current.modelSettingsPersistAsDefault === false)
17378
17420
  return current;
@@ -17389,6 +17431,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17389
17431
  }
17390
17432
  };
17391
17433
  });
17434
+ captured.set(key, entry);
17392
17435
  },
17393
17436
  dispose() {
17394
17437
  for (const key of captured.keys())
@@ -17463,14 +17506,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17463
17506
 
17464
17507
  // ../desktop-control/dist/renderer-host-discovery.js
17465
17508
  function requestManagerFromHookState(value, hostId2) {
17466
- const record8 = (candidate) => typeof candidate === "object" && candidate !== null;
17509
+ const record10 = (candidate) => typeof candidate === "object" && candidate !== null;
17467
17510
  const manager = (candidate) => {
17468
- if (!record8(candidate) || !record8(candidate.requestClient) || !record8(candidate.prewarmedThreadManager))
17511
+ if (!record10(candidate) || !record10(candidate.requestClient) || !record10(candidate.prewarmedThreadManager))
17469
17512
  return null;
17470
17513
  const bridge = candidate.requestClient;
17471
17514
  return typeof candidate.sendRequest === "function" && typeof bridge.sendRequest === "function" && typeof bridge.prewarmThreadStart === "function" && typeof bridge.enqueueRequest === "function" && typeof candidate.prewarmedThreadManager.discardAllPrewarmedThreads === "function" ? candidate : null;
17472
17515
  };
17473
- if (!record8(value))
17516
+ if (!record10(value))
17474
17517
  return null;
17475
17518
  const direct = manager(value) ?? manager(value.manager);
17476
17519
  if (direct)
@@ -17531,14 +17574,197 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17531
17574
  };
17532
17575
  }
17533
17576
 
17534
- // ../desktop-control/dist/renderer-schedule-workspace.js
17577
+ // ../desktop-control/dist/renderer-host-rpc-discovery.js
17578
+ function findRendererHostRpcFamily(store) {
17579
+ const record10 = (value) => typeof value === "object" && value !== null;
17580
+ const families = /* @__PURE__ */ new Set();
17581
+ for (const [definition, members] of store.familyBindings) {
17582
+ if (!record10(definition) || definition.kind !== "signal-family")
17583
+ continue;
17584
+ if (!record10(members) || typeof members.get !== "function")
17585
+ continue;
17586
+ for (const [hostId2, member] of members) {
17587
+ if (typeof hostId2 !== "string" || !record10(member))
17588
+ continue;
17589
+ const signal = member.value;
17590
+ if (!record10(signal) || typeof signal.get !== "function")
17591
+ continue;
17592
+ let value;
17593
+ try {
17594
+ value = signal.get();
17595
+ } catch {
17596
+ continue;
17597
+ }
17598
+ if (record10(value) && Object.keys(value).length === 2 && typeof value.status === "string" && record10(value.client) && value.client.hostId === hostId2 && "rpc" in value.client) {
17599
+ families.add(members);
17600
+ break;
17601
+ }
17602
+ }
17603
+ }
17604
+ if (families.size !== 1)
17605
+ return null;
17606
+ return { store, family: families.values().next().value };
17607
+ }
17608
+ function resolveRendererHostRpc(discovery, hostId2) {
17609
+ const record10 = (value2) => typeof value2 === "object" && value2 !== null;
17610
+ const signal = discovery.family.get(hostId2)?.value;
17611
+ if (!record10(signal) || typeof signal.get !== "function")
17612
+ return null;
17613
+ let value;
17614
+ try {
17615
+ value = signal.get();
17616
+ } catch {
17617
+ return null;
17618
+ }
17619
+ if (!record10(value) || value.status !== "ready" || !record10(value.client) || value.client.hostId !== hostId2)
17620
+ return null;
17621
+ const rpc = value.client.rpc;
17622
+ return typeof rpc === "function" || record10(rpc) ? rpc : null;
17623
+ }
17624
+
17625
+ // ../desktop-control/dist/renderer-schedule-workspace-rpc.js
17535
17626
  var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
17627
+ function localAppScope(root) {
17628
+ const scopes = /* @__PURE__ */ new Map();
17629
+ const seen = /* @__PURE__ */ new Set();
17630
+ for (const main of root.querySelectorAll("main")) {
17631
+ const keys = Object.getOwnPropertyNames(main).filter((key2) => key2.startsWith("__reactFiber$"));
17632
+ const key = keys[0];
17633
+ if (keys.length !== 1 || !key)
17634
+ continue;
17635
+ for (const fiber of committedReactAncestors(Reflect.get(main, key))) {
17636
+ if (seen.has(fiber))
17637
+ break;
17638
+ seen.add(fiber);
17639
+ let hook = fiber.memoizedState;
17640
+ for (let n = 0; record5(hook) && "next" in hook && n < 150; n++, hook = hook.next) {
17641
+ const handle = record5(hook.memoizedState) ? hook.memoizedState.current : null;
17642
+ if (!record5(handle) || !record5(handle.node) || handle.node.parent != null || !("chain" in handle) || !("scope" in handle) || typeof handle.get !== "function" || typeof handle.set !== "function" || typeof handle.watch !== "function" || !(handle.node.familyBindings instanceof Map))
17643
+ continue;
17644
+ scopes.set(handle.node, { handle, store: handle.node });
17645
+ }
17646
+ }
17647
+ }
17648
+ const scope = scopes.values().next().value;
17649
+ if (scopes.size !== 1 || !scope)
17650
+ throw new Error("Native local app scope is missing or ambiguous");
17651
+ const discovery = findRendererHostRpcFamily(scope.store);
17652
+ const rpc = discovery && resolveRendererHostRpc(discovery, "local");
17653
+ if (!discovery || !rpc)
17654
+ throw new Error("Native local app RPC is unavailable");
17655
+ return { ...scope, discovery, rpc };
17656
+ }
17657
+ async function createRpcScheduleWorkspaceThread(root, routing, route, createThread, input, signal) {
17658
+ if (!route.policy.scopedCreation)
17659
+ throw new Error("Native local chat creation is unavailable");
17660
+ const scope = localAppScope(root);
17661
+ const assertConnection = () => {
17662
+ if (routing.forHost("local")?.manager !== route.manager || resolveRendererHostRpc(scope.discovery, "local") !== scope.rpc)
17663
+ throw new Error("The local connection changed. Reopen the task dialog.");
17664
+ };
17665
+ const assertCurrent = () => {
17666
+ signal.throwIfAborted();
17667
+ assertConnection();
17668
+ };
17669
+ const request = async (method, params) => {
17670
+ assertConnection();
17671
+ return route.manager.sendRequest(method, params);
17672
+ };
17673
+ const readEmpty = async (threadId) => {
17674
+ const read = await request("thread/read", { threadId, includeTurns: false });
17675
+ if (!record5(read) || !record5(read.thread) || read.thread.id !== threadId || !record5(read.thread.status))
17676
+ throw new Error("The created chat could not be read");
17677
+ const turns = await request("thread/turns/list", { threadId, cursor: null, limit: 1 });
17678
+ const queue = await request("thread/queue/list", { threadId, cursor: null, limit: 1 });
17679
+ if (!record5(turns) || !Array.isArray(turns.data) || !("nextCursor" in turns) || !record5(queue) || !Array.isArray(queue.data) || !("nextCursor" in queue))
17680
+ throw new Error("The created chat's history or queue could not be confirmed");
17681
+ return {
17682
+ thread: read.thread,
17683
+ empty: read.thread.status.type === "idle" && turns.data.length === 0 && turns.nextCursor === null && queue.data.length === 0 && queue.nextCursor === null
17684
+ };
17685
+ };
17686
+ assertCurrent();
17687
+ let createdId = null;
17688
+ let retained = false;
17689
+ let failed = false;
17690
+ let cleanup;
17691
+ const discard = () => {
17692
+ if (!createdId || retained)
17693
+ return Promise.resolve();
17694
+ const threadId = createdId;
17695
+ return cleanup ??= (async () => {
17696
+ const { empty } = await readEmpty(threadId);
17697
+ if (!empty || retained)
17698
+ return;
17699
+ await request("thread/archive", { threadId });
17700
+ })();
17701
+ };
17702
+ const discardAfterDismissal = () => {
17703
+ void discard().catch((error51) => {
17704
+ console.error("Could not discard the unsubmitted schedule chat. Check the chat list.", error51);
17705
+ });
17706
+ };
17707
+ signal.addEventListener("abort", discardAfterDismissal, { once: true });
17708
+ const remember = (result) => {
17709
+ if (!record5(result) || result.status !== "created")
17710
+ return;
17711
+ const id = hostThreadIdSchema.safeParse(result.conversationId);
17712
+ if (!id.success)
17713
+ return;
17714
+ if (createdId && createdId !== id.data)
17715
+ throw new Error("Chat creation returned conflicting identities");
17716
+ createdId = id.data;
17717
+ if (signal.aborted || failed)
17718
+ discardAfterDismissal();
17719
+ };
17720
+ try {
17721
+ const output = await createThread({
17722
+ scope: scope.handle,
17723
+ target: { type: "project", projectId: input.workspace.id, environment: { type: "local" } },
17724
+ model: input.model,
17725
+ title: input.title,
17726
+ prompt: "",
17727
+ startWithoutFirstTurn: true,
17728
+ assertRequestCurrent: assertCurrent,
17729
+ onSettled: remember
17730
+ });
17731
+ const result = record5(output) && output.kind === "creation" ? output.result : null;
17732
+ remember(result);
17733
+ assertCurrent();
17734
+ if (!record5(result) || result.status !== "created" || !createdId || !record5(result.firstTurn) || result.firstTurn.status !== "not-requested")
17735
+ throw new Error("Chat creation was not confirmed. Check the chat list before creating another task.");
17736
+ const { thread, empty } = await readEmpty(createdId);
17737
+ const inspection = threadInspectionSchema.parse(await request("codexhost/thread/inspect", { threadId: createdId }));
17738
+ assertCurrent();
17739
+ if (!empty || thread.cwd !== input.workspace.cwd || inspection.owner !== "external" || inspection.transportModelId !== input.model)
17740
+ throw new Error("The created chat's workspace, Model or empty state could not be confirmed");
17741
+ return {
17742
+ threadId: createdId,
17743
+ discard,
17744
+ retain() {
17745
+ retained = true;
17746
+ signal.removeEventListener("abort", discardAfterDismissal);
17747
+ }
17748
+ };
17749
+ } catch (error51) {
17750
+ failed = true;
17751
+ try {
17752
+ await discard();
17753
+ } catch (cleanupError) {
17754
+ throw new Error(`${error51 instanceof Error ? error51.message : String(error51)}; Chat cleanup failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Check the chat list.`);
17755
+ }
17756
+ throw error51;
17757
+ }
17758
+ }
17759
+
17760
+ // ../desktop-control/dist/renderer-schedule-workspace.js
17761
+ var record6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
17536
17762
  function readNativeScheduleWorkspaces(root) {
17537
17763
  const projects = /* @__PURE__ */ new Map();
17538
17764
  const ambiguous = /* @__PURE__ */ new Set();
17539
17765
  const seen = /* @__PURE__ */ new Set();
17540
17766
  const add = (value) => {
17541
- if (!record5(value) || value.source !== "codex" || !record5(value.group))
17767
+ if (!record6(value) || value.source !== "codex" || !record6(value.group))
17542
17768
  return;
17543
17769
  const group = value.group;
17544
17770
  if (group.projectKind !== "local" || group.hostId != null && group.hostId !== "local" || typeof group.projectId !== "string" || !group.projectId || typeof group.label !== "string" || typeof group.path !== "string" || !Array.isArray(group.rootPaths) || !group.rootPaths.includes(group.path) || !/^(?:\/|[A-Za-z]:[\\/]|\\\\)/u.test(group.path) || group.path.includes("\0"))
@@ -17560,7 +17786,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17560
17786
  break;
17561
17787
  seen.add(fiber);
17562
17788
  const props = fiber.memoizedProps;
17563
- if (!record5(props))
17789
+ if (!record6(props))
17564
17790
  continue;
17565
17791
  add(props.project);
17566
17792
  if (props.projectByKey instanceof Map)
@@ -17571,15 +17797,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17571
17797
  return [...projects.values()].filter(({ id }) => !ambiguous.has(id));
17572
17798
  }
17573
17799
  function isNativeProjectThreadCreator(value) {
17574
- if (typeof value !== "function" || value.length !== 1)
17800
+ try {
17801
+ if (typeof value !== "function" || value.length !== 1)
17802
+ return false;
17803
+ const source = Function.prototype.toString.call(value);
17804
+ return /^async function/u.test(source) && source.includes("startWithoutFirstTurn:") && source.includes("onSettled:") && source.includes("createThread config is not supported for delegated thread creation") && source.includes("createThread serviceName is only supported for local Electron root threads outside worktrees");
17805
+ } catch {
17575
17806
  return false;
17576
- const source = Function.prototype.toString.call(value);
17577
- return /^async function/u.test(source) && source.includes("startWithoutFirstTurn:") && source.includes("onSettled:") && source.includes("createThread config is not supported for delegated thread creation") && source.includes("createThread serviceName is only supported for local Electron root threads outside worktrees");
17807
+ }
17578
17808
  }
17579
17809
  async function createNativeScheduleWorkspaceThread(root, routing, createThread, input, signal) {
17580
17810
  if (!decodeHarnessPluginRoute(input.model))
17581
17811
  throw new Error("An external Harness is required");
17582
17812
  const route = routing.forHost("local");
17813
+ if (route && Reflect.get(route.manager, "kind") === "main-process-rpc") {
17814
+ if (!readNativeScheduleWorkspaces(root).some(({ id, cwd }) => id === input.workspace.id && cwd === input.workspace.cwd))
17815
+ throw new Error("The selected workspace is no longer available");
17816
+ return createRpcScheduleWorkspaceThread(root, routing, route, createThread, input, signal);
17817
+ }
17583
17818
  const manager = route?.manager;
17584
17819
  if (!route?.policy.scopedCreation || !manager || typeof manager.getConversation !== "function" || typeof manager.archiveConversation !== "function")
17585
17820
  throw new Error("Native local chat creation is unavailable");
@@ -17594,7 +17829,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17594
17829
  }
17595
17830
  }));
17596
17831
  const scope = scopes.values().next().value;
17597
- if (scopes.size !== 1 || !record5(scope) || typeof scope.get !== "function")
17832
+ if (scopes.size !== 1 || !record6(scope) || typeof scope.get !== "function")
17598
17833
  throw new Error("Native local chat scope is missing or ambiguous");
17599
17834
  if (!readNativeScheduleWorkspaces(root).some(({ id, cwd }) => id === input.workspace.id && cwd === input.workspace.cwd))
17600
17835
  throw new Error("The selected workspace is no longer available");
@@ -17607,7 +17842,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17607
17842
  const id = createdId;
17608
17843
  released = true;
17609
17844
  const conversation2 = manager.getConversation(id);
17610
- if (!record5(conversation2) || !Array.isArray(conversation2.turns) || conversation2.turns.length || Array.isArray(conversation2.requests) && conversation2.requests.length > 0 || conversation2.pendingRequest != null)
17845
+ if (!record6(conversation2) || !Array.isArray(conversation2.turns) || conversation2.turns.length || Array.isArray(conversation2.requests) && conversation2.requests.length > 0 || conversation2.pendingRequest != null)
17611
17846
  return;
17612
17847
  void Promise.resolve().then(() => manager.archiveConversation(id, {
17613
17848
  useAppServerPins: false,
@@ -17616,7 +17851,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17616
17851
  };
17617
17852
  signal.addEventListener("abort", discard, { once: true });
17618
17853
  const remember = (result2) => {
17619
- if (!record5(result2) || result2.status !== "created")
17854
+ if (!record6(result2) || result2.status !== "created")
17620
17855
  return;
17621
17856
  const id = hostThreadIdSchema.safeParse(result2.conversationId);
17622
17857
  if (id.success)
@@ -17633,16 +17868,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17633
17868
  startWithoutFirstTurn: true,
17634
17869
  onSettled: remember
17635
17870
  });
17636
- const result = record5(output) && output.kind === "creation" ? output.result : null;
17871
+ const result = record6(output) && output.kind === "creation" ? output.result : null;
17637
17872
  remember(result);
17638
17873
  signal.throwIfAborted();
17639
- if (!record5(result) || result.status !== "created" || !createdId || !record5(result.firstTurn) || result.firstTurn.status !== "not-requested")
17874
+ if (!record6(result) || result.status !== "created" || !createdId || !record6(result.firstTurn) || result.firstTurn.status !== "not-requested")
17640
17875
  throw new Error("Chat creation was not confirmed. Check the chat list before creating another task.");
17641
17876
  if (routing.forHost("local")?.manager !== route.manager)
17642
17877
  throw new Error("The local connection changed. Reopen the task dialog.");
17643
17878
  const conversation = manager.getConversation(createdId);
17644
- const mode = record5(conversation) ? conversation.latestCollaborationMode : null;
17645
- if (!record5(conversation) || conversation.cwd !== input.workspace.cwd || !record5(mode) || !record5(mode.settings) || mode.settings.model !== input.model)
17879
+ const mode = record6(conversation) ? conversation.latestCollaborationMode : null;
17880
+ if (!record6(conversation) || conversation.cwd !== input.workspace.cwd || !record6(mode) || !record6(mode.settings) || mode.settings.model !== input.model)
17646
17881
  throw new Error("The created chat's workspace or Model could not be confirmed");
17647
17882
  return {
17648
17883
  threadId: createdId,
@@ -18450,6 +18685,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18450
18685
  loaded = true;
18451
18686
  show(value);
18452
18687
  }).catch(() => {
18688
+ loaded = true;
18453
18689
  status.textContent = messages.launchPathLoadError;
18454
18690
  }).finally(() => {
18455
18691
  busy = false;
@@ -20029,7 +20265,7 @@ ${messages.harnessVersionLatest}: ${harnessVersionLabel(version2.state, messages
20029
20265
  launchPathAutomatic: "No saved override. Uses environment configuration, then automatic discovery.",
20030
20266
  launchPathSaving: "Saving\u2026",
20031
20267
  launchPathLoading: "Loading launch settings\u2026",
20032
- 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.",
20033
20269
  launchPathSaveError: "Could not save. Enter an existing absolute installation folder on this Host and check configuration permissions.",
20034
20270
  connectionOfficialWebsite: "Visit official website",
20035
20271
  connectionOpenHarnessWeb: "Open DeepSeek Harness Web",
@@ -20308,7 +20544,7 @@ ${messages.harnessVersionLatest}: ${harnessVersionLabel(version2.state, messages
20308
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",
20309
20545
  launchPathSaving: "\u6B63\u5728\u4FDD\u5B58\u2026",
20310
20546
  launchPathLoading: "\u6B63\u5728\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\u2026",
20311
- 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",
20312
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",
20313
20549
  connectionOfficialWebsite: "\u8BBF\u95EE\u5B98\u7F51",
20314
20550
  connectionOpenHarnessWeb: "\u6253\u5F00 DeepSeek Harness Web",
@@ -25553,10 +25789,16 @@ Codex Fast mode prioritizes requests and may increase usage.`
25553
25789
  const currentRole = manager.getStreamRole?.(threadId);
25554
25790
  if (isRecord7(currentRole) && currentRole.role === "follower")
25555
25791
  return originalSteer.apply(manager, args);
25556
- if (!Array.isArray(input) || input.length === 0 || input.some(
25557
- (item) => !isRecord7(item) || item.type !== "text" || typeof item.text !== "string"
25558
- ) || !input.some((item) => isRecord7(item) && typeof item.text === "string" && item.text.trim())) {
25559
- 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");
25560
25802
  }
25561
25803
  if (toolOutput != null) throw new Error("External steering cannot replace a tool response");
25562
25804
  if (!isRecord7(restoreMessage) || !isRecord7(restoreMessage.context)) {
@@ -25677,16 +25919,6 @@ Codex Fast mode prioritizes requests and may increase usage.`
25677
25919
  for (let index = 0; index < decoded.length; index += 1) bytes[index] = decoded.charCodeAt(index);
25678
25920
  return { contents: new Blob([bytes], { type: mimeType }), extension };
25679
25921
  }
25680
- function nativeImagePaths(text) {
25681
- const context = text.split("## My request:")[0] ?? "";
25682
- const start = context.indexOf("# Files mentioned by the user:");
25683
- if (start < 0) return [];
25684
- return [
25685
- ...context.slice(start).matchAll(
25686
- /(?:^|\n)## [^\r\n]+: ((?:\/|[A-Za-z]:[\\/]|\\\\)[^\r\n]+)\r?\nImage attachment: true(?=\r?\n|$)/gu
25687
- )
25688
- ].map((match) => match[1]).filter(filePath);
25689
- }
25690
25922
  function createRemoteAttachmentSender(target, hostId2, isCurrent) {
25691
25923
  const prepared = /* @__PURE__ */ new WeakMap();
25692
25924
  return (params, send) => {
@@ -25711,7 +25943,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
25711
25943
  if (cached2) return cached2.then(dispatch);
25712
25944
  const input = params.input;
25713
25945
  const text = input.filter((item) => isRecord8(item) && item.type === "text").map((item) => isRecord8(item) && typeof item.text === "string" ? item.text : "").join("\n");
25714
- const existingPaths = nativeImagePaths(text);
25946
+ const existingPaths = desktopImageAttachmentPaths(text);
25715
25947
  const prepare = async () => {
25716
25948
  if (existingPaths.length === images.length) return params;
25717
25949
  if (images.length > 20) throw new Error("Too many remote image attachments (maximum 20)");
@@ -25792,10 +26024,72 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25792
26024
  };
25793
26025
  }
25794
26026
 
26027
+ // src/renderer-thread-reference-persistence.ts
26028
+ var record7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
26029
+ var SYNC_TIMEOUT_MS = 2e3;
26030
+ function restoreRpcThreadReferenceCapability(client, messages, isCurrent) {
26031
+ if (!record7(messages) || !record7(messages.electronBridge)) return client;
26032
+ const bridge = messages.electronBridge;
26033
+ const send = bridge.sendMessageFromView;
26034
+ if (typeof send !== "function") return client;
26035
+ const inspect = client.inspectThread.bind(client);
26036
+ const checked = /* @__PURE__ */ new Set();
26037
+ const isMissing = (key) => new Promise((resolve) => {
26038
+ const finish = (missing) => {
26039
+ clearTimeout(timer);
26040
+ messages.removeEventListener("message", listener);
26041
+ resolve(missing);
26042
+ };
26043
+ const listener = (event) => {
26044
+ if (event.source != null && event.source !== messages) return;
26045
+ const message2 = event.data;
26046
+ if (!record7(message2) || message2.type !== "persisted-atom-sync" || !record7(message2.state))
26047
+ return;
26048
+ finish(!Object.hasOwn(message2.state, key));
26049
+ };
26050
+ const timer = setTimeout(() => finish(false), SYNC_TIMEOUT_MS);
26051
+ messages.addEventListener("message", listener);
26052
+ try {
26053
+ Promise.resolve(
26054
+ send.call(bridge, { type: "persisted-atom-sync-request", responsePriority: "critical" })
26055
+ ).catch(() => finish(false));
26056
+ } catch {
26057
+ finish(false);
26058
+ }
26059
+ });
26060
+ const inspectThread = async (input) => {
26061
+ if (!isCurrent() || checked.has(input.threadId)) return inspect(input);
26062
+ checked.add(input.threadId);
26063
+ const key = `thread-reference-capability:${input.threadId}`;
26064
+ if (!await isMissing(key) || !isCurrent()) return inspect(input);
26065
+ let proven = true;
26066
+ const result = await inspect({ ...input, includeReferenceCapability: true }).catch(() => {
26067
+ proven = false;
26068
+ return inspect(input);
26069
+ });
26070
+ if (proven && result.owner === "codex" && result.supportsThreadReferences === true && isCurrent() && await isMissing(key) && isCurrent()) {
26071
+ try {
26072
+ await send.call(bridge, {
26073
+ type: "persisted-atom-update",
26074
+ key,
26075
+ value: true,
26076
+ deleted: false
26077
+ });
26078
+ } catch {
26079
+ }
26080
+ }
26081
+ return result;
26082
+ };
26083
+ return Object.freeze({ ...client, inspectThread });
26084
+ }
26085
+
25795
26086
  // src/renderer-thread-reference-capability.ts
25796
- var record6 = (value) => typeof value === "object" && value !== null;
25797
- function restoreThreadReferenceCapability(client, manager, isCurrent) {
25798
- if (!record6(manager) || !record6(manager.storage)) return client;
26087
+ var record8 = (value) => typeof value === "object" && value !== null;
26088
+ function restoreThreadReferenceCapability(client, manager, isCurrent, messages = null) {
26089
+ if (record8(manager) && manager.kind === "main-process-rpc") {
26090
+ return restoreRpcThreadReferenceCapability(client, messages, isCurrent);
26091
+ }
26092
+ if (!record8(manager) || !record8(manager.storage)) return client;
25799
26093
  const storage = manager.storage;
25800
26094
  const read = storage.readValue;
25801
26095
  const write = storage.writeValue;
@@ -25830,14 +26124,14 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25830
26124
  }
25831
26125
 
25832
26126
  // src/renderer-thread-reference-context.ts
25833
- var record7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
26127
+ var record9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25834
26128
  function createThreadReferenceContext(manager, hostId2, isCurrent) {
25835
26129
  const prepared = /* @__PURE__ */ new WeakMap();
25836
26130
  return (params) => {
25837
- if (hostId2 === "local" || !record7(manager) || typeof manager.getConversation !== "function" || !record7(params) || typeof params.threadId !== "string")
26131
+ if (hostId2 === "local" || !record9(manager) || typeof manager.getConversation !== "function" || !record9(params) || typeof params.threadId !== "string")
25838
26132
  return params;
25839
26133
  const conversation = manager.getConversation.call(manager, params.threadId);
25840
- if (!record7(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
26134
+ if (!record9(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
25841
26135
  return params;
25842
26136
  if (!isCurrent()) throw new Error("Thread reference connection is no longer available");
25843
26137
  const cached2 = prepared.get(params);
@@ -25943,7 +26237,8 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25943
26237
  const client = restoreThreadReferenceCapability(
25944
26238
  nativeClient,
25945
26239
  target,
25946
- () => !disposed && readRouting()?.forHost(route.hostId) === route
26240
+ () => !disposed && readRouting()?.forHost(route.hostId) === route,
26241
+ messages
25947
26242
  );
25948
26243
  entries.set(route.hostId, { route, client, cleanups });
25949
26244
  try {
@@ -27157,8 +27452,18 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27157
27452
  const draftKey = target[1];
27158
27453
  if (!binding || !route.policy.scopedCreation)
27159
27454
  return agent === "codex" && !draftModels.has(draftKey);
27160
- draftModels.apply(draftKey, binding, carrier ?? null);
27161
- 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) {
27162
27467
  modelUpdates += 1;
27163
27468
  liveStatus.modelUpdates = modelUpdates;
27164
27469
  }
@@ -30363,7 +30668,7 @@ ${detail}` : ""}`
30363
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",
30364
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",
30365
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",
30366
- "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",
30367
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",
30368
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",
30369
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",
@@ -31795,6 +32100,30 @@ ${detail}` : ""}`
31795
32100
  };
31796
32101
  }
31797
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
+
31798
32127
  // src/settings/session-import-page.ts
31799
32128
  function shortSessionId(value) {
31800
32129
  return value.length <= 18 ? value : `${value.slice(0, 10)}\u2026${value.slice(-6)}`;
@@ -31864,7 +32193,7 @@ ${detail}` : ""}`
31864
32193
  ...getDiagnostics()?.snapshot().hosts.map(({ hostId: hostId2 }) => hostId2) ?? [],
31865
32194
  ...current ? [current] : []
31866
32195
  ])
31867
- ];
32196
+ ].filter((hostId2) => hostId2 !== "durable");
31868
32197
  displayedHostId = current;
31869
32198
  const scrollLeft = hostOptions.scrollLeft;
31870
32199
  hostOptions.replaceChildren();
@@ -32208,10 +32537,14 @@ ${detail}` : ""}`
32208
32537
  content.append(list);
32209
32538
  updateImportActions();
32210
32539
  };
32211
- const load = () => {
32540
+ const load = (refreshDiagnostics = false) => {
32212
32541
  if (importingId !== null || context.signal.aborted) return;
32213
32542
  loadedClient = null;
32214
- const client = getClient(selectedHostId);
32543
+ let client = getClient(selectedHostId);
32544
+ if (client?.hostId === "durable") {
32545
+ selectedHostId = "local";
32546
+ client = getClient(selectedHostId);
32547
+ }
32215
32548
  renderHosts(client);
32216
32549
  listControls.setBusy(client !== null);
32217
32550
  refresh.disabled = client !== null;
@@ -32224,11 +32557,11 @@ ${detail}` : ""}`
32224
32557
  void context.runLatest(
32225
32558
  async (signal) => {
32226
32559
  if (!client) throw new RendererSessionImportUnavailableError();
32227
- const missing = new Set(
32228
- getDiagnostics()?.snapshot().hosts.find(({ hostId: hostId2 }) => hostId2 === (client.hostId ?? "local"))?.agents.filter(({ availability }) => availability === "notInstalled").map(({ agent }) => agent)
32229
- );
32230
- const harnesses = (await client.listSessionImportSources()).harnesses.filter(
32231
- ({ harnessId }) => !missing.has(harnessId)
32560
+ const harnesses = await loadSessionImportSources(
32561
+ client,
32562
+ getDiagnostics(),
32563
+ signal,
32564
+ refreshDiagnostics
32232
32565
  );
32233
32566
  const selected = harnesses.find(({ harnessId }) => harnessId === requestedHarness)?.harnessId ?? harnesses[0]?.harnessId ?? null;
32234
32567
  if (signal.aborted) throw new Error("Session import selection changed");
@@ -32279,7 +32612,7 @@ ${detail}` : ""}`
32279
32612
  load();
32280
32613
  hostButtons.find((button2) => button2.dataset.sessionImportHost === hostId2)?.focus();
32281
32614
  };
32282
- refresh.addEventListener("click", load);
32615
+ refresh.addEventListener("click", () => load(true));
32283
32616
  load();
32284
32617
  return void 0;
32285
32618
  }
@@ -32772,7 +33105,7 @@ ${detail}` : ""}`
32772
33105
  }
32773
33106
  function defaultImportName(source, existing) {
32774
33107
  const base = source.provider === "openai-codex" ? "codex" : "grok";
32775
- const used = new Set(existing.map((record8) => record8.name));
33108
+ const used = new Set(existing.map((record10) => record10.name));
32776
33109
  const valid = (name) => credentialImportNameSchema.safeParse(name).success;
32777
33110
  if (!used.has(base)) return base;
32778
33111
  const local = source.label.includes("@") ? source.label.split("@")[0] ?? "" : "";
@@ -32795,7 +33128,7 @@ ${detail}` : ""}`
32795
33128
  const shown = (text) => accountDisplayText(text, hideEmails);
32796
33129
  const targetButtons = /* @__PURE__ */ new Map();
32797
33130
  const importedRecords = () => snapshot.targets.find((target) => target.harnessId === TARGET_HARNESS_ID)?.imports ?? [];
32798
- const sourceOf = (record8) => snapshot.sources.find((source) => source.id === record8.source.id);
33131
+ const sourceOf = (record10) => snapshot.sources.find((source) => source.id === record10.source.id);
32799
33132
  const piTarget = () => snapshot.targets.find((candidate) => candidate.harnessId === TARGET_HARNESS_ID);
32800
33133
  const compatibleSources = () => {
32801
33134
  const target = piTarget();
@@ -32833,7 +33166,7 @@ ${detail}` : ""}`
32833
33166
  sectionImport.addEventListener("click", () => {
32834
33167
  const sources = compatibleSources();
32835
33168
  const free = sources.find(
32836
- (source2) => !importedRecords().some((record8) => record8.source.id === source2.id)
33169
+ (source2) => !importedRecords().some((record10) => record10.source.id === source2.id)
32837
33170
  );
32838
33171
  const source = free ?? sources[0];
32839
33172
  if (source) openDialog("add", { source, choose: true }, SECTION_IMPORT_KEY);
@@ -32883,30 +33216,30 @@ ${detail}` : ""}`
32883
33216
  mark.append(createRendererAgentIcon(agent ?? "pi", 26, document2, pluginFor(agent ?? "pi")));
32884
33217
  return mark;
32885
33218
  };
32886
- const renderRow = (record8) => {
33219
+ const renderRow = (record10) => {
32887
33220
  const row = document2.createElement("div");
32888
33221
  row.className = "settings-pi-accounts__row";
32889
33222
  row.tabIndex = -1;
32890
- row.dataset.importName = record8.name;
32891
- row.setAttribute("aria-label", shown(record8.source.label));
32892
- const agent = record8.source.harnessId;
33223
+ row.dataset.importName = record10.name;
33224
+ row.setAttribute("aria-label", shown(record10.source.label));
33225
+ const agent = record10.source.harnessId;
32893
33226
  const mark = createMark(agent);
32894
33227
  const identity = document2.createElement("div");
32895
33228
  identity.className = "settings-pi-accounts__identity";
32896
33229
  const label = document2.createElement("strong");
32897
33230
  label.className = "settings-account-email";
32898
- label.textContent = shown(record8.source.label);
33231
+ label.textContent = shown(record10.source.label);
32899
33232
  label.title = label.textContent;
32900
33233
  label.translate = false;
32901
33234
  const meta3 = document2.createElement("div");
32902
33235
  meta3.className = "settings-account-metadata";
32903
- const source = sourceOf(record8);
33236
+ const source = sourceOf(record10);
32904
33237
  const parts = [
32905
33238
  metaPart(rendererAgentLabel(agent, pluginFor(agent)), "settings-pi-accounts__agent"),
32906
- metaPart(`${record8.name}/\u2026`, void 0, true),
33239
+ metaPart(`${record10.name}/\u2026`, void 0, true),
32907
33240
  metaPart(messages.copied)
32908
33241
  ];
32909
- const time3 = formatImportedAt(record8.importedAt);
33242
+ const time3 = formatImportedAt(record10.importedAt);
32910
33243
  if (time3) parts.push(metaPart(time3));
32911
33244
  parts.forEach((part, index) => {
32912
33245
  if (index > 0) {
@@ -32923,23 +33256,23 @@ ${detail}` : ""}`
32923
33256
  reimport.type = "button";
32924
33257
  reimport.className = "settings-account-action";
32925
33258
  reimport.textContent = messages.rowReimport;
32926
- reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record8.source.label)}`);
33259
+ reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record10.source.label)}`);
32927
33260
  reimport.disabled = busy || !source;
32928
33261
  reimport.title = messages.reimport;
32929
33262
  reimport.addEventListener("click", () => {
32930
- if (source) openDialog("reimport", { source, record: record8 }, `row:${record8.name}`);
33263
+ if (source) openDialog("reimport", { source, record: record10 }, `row:${record10.name}`);
32931
33264
  });
32932
33265
  const remove = document2.createElement("button");
32933
33266
  remove.type = "button";
32934
33267
  remove.className = "settings-account-action settings-pi-accounts__remove";
32935
33268
  remove.textContent = messages.rowRemove;
32936
- remove.setAttribute("aria-label", `${messages.remove}: ${shown(record8.source.label)}`);
33269
+ remove.setAttribute("aria-label", `${messages.remove}: ${shown(record10.source.label)}`);
32937
33270
  remove.disabled = busy;
32938
- remove.addEventListener("click", () => openDialog("remove", { record: record8 }, `row:${record8.name}`));
33271
+ remove.addEventListener("click", () => openDialog("remove", { record: record10 }, `row:${record10.name}`));
32939
33272
  if (source) actions.append(reimport);
32940
33273
  actions.append(remove);
32941
33274
  row.append(mark, identity, actions);
32942
- rows.set(record8.name, row);
33275
+ rows.set(record10.name, row);
32943
33276
  return row;
32944
33277
  };
32945
33278
  const loginTypeLabel = (type) => type === "oauth" ? messages.typeOauth : type === "api_key" ? messages.typeApiKey : messages.typeOther;
@@ -33092,7 +33425,7 @@ ${detail}` : ""}`
33092
33425
  const label = document2.createElement("strong");
33093
33426
  label.textContent = shown(choice.label);
33094
33427
  label.translate = false;
33095
- const existing = importedRecords().find((record8) => record8.source.id === choice.id);
33428
+ const existing = importedRecords().find((record10) => record10.source.id === choice.id);
33096
33429
  const agent = choice.harnessId;
33097
33430
  const detail = document2.createElement("span");
33098
33431
  detail.textContent = [
@@ -33133,7 +33466,7 @@ ${detail}` : ""}`
33133
33466
  const name = request.action === "list" ? void 0 : request.name;
33134
33467
  state = {
33135
33468
  source: state.source,
33136
- record: importedRecords().find((record8) => record8.name === name) ?? state.record
33469
+ record: importedRecords().find((record10) => record10.name === name) ?? state.record
33137
33470
  };
33138
33471
  show(next);
33139
33472
  } else {
@@ -33147,12 +33480,12 @@ ${detail}` : ""}`
33147
33480
  sourceRadios = [];
33148
33481
  body.replaceChildren();
33149
33482
  controls.replaceChildren();
33150
- const { source, record: record8 } = state;
33483
+ const { source, record: record10 } = state;
33151
33484
  const close = () => modal.close();
33152
33485
  if (mode === "add" || mode === "reimport") {
33153
33486
  title.textContent = mode === "add" ? messages.add : messages.reimport;
33154
33487
  modal.setAttribute("aria-label", title.textContent);
33155
- const active = source ?? record8?.source;
33488
+ const active = source ?? record10?.source;
33156
33489
  const choices = mode === "add" && state.choose ? compatibleSources() : [];
33157
33490
  if (choices.length > 1) body.append(sourcePicker(choices));
33158
33491
  else if (active) body.append(line(messages.source, shown(active.label)));
@@ -33161,8 +33494,8 @@ ${detail}` : ""}`
33161
33494
  input.maxLength = 48;
33162
33495
  input.autocomplete = "off";
33163
33496
  input.spellcheck = false;
33164
- input.value = record8?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
33165
- input.readOnly = Boolean(record8);
33497
+ input.value = record10?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
33498
+ input.readOnly = Boolean(record10);
33166
33499
  input.addEventListener("input", () => {
33167
33500
  nameEdited = true;
33168
33501
  });
@@ -33196,7 +33529,7 @@ ${detail}` : ""}`
33196
33529
  {
33197
33530
  action: mode === "reimport" ? "reimport" : "import",
33198
33531
  sourceId: source2.id,
33199
- name: record8?.name ?? input.value,
33532
+ name: record10?.name ?? input.value,
33200
33533
  confirmed: true
33201
33534
  },
33202
33535
  "done"
@@ -33206,16 +33539,16 @@ ${detail}` : ""}`
33206
33539
  )
33207
33540
  );
33208
33541
  (mode === "add" ? input : controls.children[0]).focus();
33209
- } else if (mode === "remove" && record8) {
33542
+ } else if (mode === "remove" && record10) {
33210
33543
  title.textContent = messages.remove;
33211
33544
  modal.setAttribute("aria-label", title.textContent);
33212
- body.append(note(messages.removeWarning.replace("{name}", record8.name)));
33545
+ body.append(note(messages.removeWarning.replace("{name}", record10.name)));
33213
33546
  const cancel = command(messages.cancel, close);
33214
33547
  controls.append(
33215
33548
  cancel,
33216
33549
  command(
33217
33550
  messages.remove,
33218
- () => submit({ action: "remove", name: record8.name, confirmed: true }, null),
33551
+ () => submit({ action: "remove", name: record10.name, confirmed: true }, null),
33219
33552
  "danger"
33220
33553
  )
33221
33554
  );
@@ -33223,7 +33556,7 @@ ${detail}` : ""}`
33223
33556
  } else {
33224
33557
  title.textContent = messages.doneTitle;
33225
33558
  modal.setAttribute("aria-label", title.textContent);
33226
- const name = record8?.name;
33559
+ const name = record10?.name;
33227
33560
  if (name) body.append(line(messages.entry, `${name}/\u2026`, true));
33228
33561
  body.append(note(messages.done));
33229
33562
  const done = command(messages.close, close, "primary");
@@ -33270,21 +33603,21 @@ ${detail}` : ""}`
33270
33603
  (candidate) => candidate.harnessId === TARGET_HARNESS_ID && source && candidate.providers.includes(source.provider)
33271
33604
  );
33272
33605
  if (!source || !target) return null;
33273
- const record8 = target.imports.find((candidate) => candidate.source.id === source.id);
33606
+ const record10 = target.imports.find((candidate) => candidate.source.id === source.id);
33274
33607
  const key = `${harnessId}:${accountLabel}:import`;
33275
33608
  const button2 = document2.createElement("button");
33276
33609
  button2.type = "button";
33277
33610
  button2.className = "settings-account-pi-import";
33278
33611
  button2.dataset.accountFocus = key;
33279
33612
  button2.disabled = busy;
33280
- const hint = record8 ? messages.importedHint.replace("{name}", record8.name) : messages.add;
33613
+ const hint = record10 ? messages.importedHint.replace("{name}", record10.name) : messages.add;
33281
33614
  button2.title = hint;
33282
33615
  button2.setAttribute("aria-label", hint);
33283
33616
  button2.append(createRendererAgentIcon("pi", 12, document2, pluginFor("pi")));
33284
- if (record8) {
33617
+ if (record10) {
33285
33618
  button2.dataset.state = "imported";
33286
33619
  const name = document2.createElement("code");
33287
- name.textContent = `${record8.name}/\u2026`;
33620
+ name.textContent = `${record10.name}/\u2026`;
33288
33621
  name.translate = false;
33289
33622
  button2.append(name, createRendererSettingsIcon("check", 12));
33290
33623
  } else {
@@ -33292,7 +33625,7 @@ ${detail}` : ""}`
33292
33625
  button2.append(messages.add);
33293
33626
  }
33294
33627
  button2.addEventListener("click", () => {
33295
- if (!record8) {
33628
+ if (!record10) {
33296
33629
  openDialog("add", { source }, key);
33297
33630
  return;
33298
33631
  }
@@ -33301,7 +33634,7 @@ ${detail}` : ""}`
33301
33634
  renderSection();
33302
33635
  sectionToggle.setAttribute("aria-expanded", "true");
33303
33636
  }
33304
- const row = rows.get(record8.name);
33637
+ const row = rows.get(record10.name);
33305
33638
  row?.scrollIntoView({ block: "nearest", behavior: "smooth" });
33306
33639
  row?.focus();
33307
33640
  });
@@ -41619,7 +41952,19 @@ ${usage_default}`;
41619
41952
  update();
41620
41953
  form.requestSubmit();
41621
41954
  } catch (cause) {
41622
- attempt.error = `${cause instanceof Error ? cause.message : text("\u4F1A\u8BDD\u521B\u5EFA\u5931\u8D25\u3002", "Chat creation failed.")} ${text("\u8BF7\u5148\u68C0\u67E5\u4F1A\u8BDD\u5217\u8868\uFF0C\u52FF\u91CD\u590D\u521B\u5EFA\u3002", "Check the chat list before creating another task.")}`;
41955
+ let cleanupError = "";
41956
+ if (attempt.thread?.discard) {
41957
+ if (readNativeScheduleForm(form)?.targetThreadId === attempt.thread.threadId)
41958
+ attempt.thread.retain();
41959
+ else {
41960
+ try {
41961
+ await attempt.thread.discard();
41962
+ } catch (error52) {
41963
+ cleanupError = ` ${text("\u4F1A\u8BDD\u6E05\u7406\u5931\u8D25\uFF1A", "Chat cleanup failed:")} ${error52 instanceof Error ? error52.message : String(error52)}`;
41964
+ }
41965
+ }
41966
+ }
41967
+ attempt.error = `${cause instanceof Error ? cause.message : text("\u4F1A\u8BDD\u521B\u5EFA\u5931\u8D25\u3002", "Chat creation failed.")}${cleanupError} ${text("\u8BF7\u5148\u68C0\u67E5\u4F1A\u8BDD\u5217\u8868\uFF0C\u52FF\u91CD\u590D\u521B\u5EFA\u3002", "Check the chat list before creating another task.")}`;
41623
41968
  } finally {
41624
41969
  attempt.pending = false;
41625
41970
  if (!retired) update();
@@ -42037,6 +42382,7 @@ ${usage_default}`;
42037
42382
  });
42038
42383
  const mountedByComposer = /* @__PURE__ */ new Map();
42039
42384
  const catalogRequests = /* @__PURE__ */ new WeakMap();
42385
+ const draftUsageRequests = /* @__PURE__ */ new WeakMap();
42040
42386
  const pendingReplacements = /* @__PURE__ */ new Map();
42041
42387
  let disposed = false;
42042
42388
  const disposeReasoningSoftWrap = installReasoningTranscriptSoftWrap(document);
@@ -42163,7 +42509,7 @@ ${usage_default}`;
42163
42509
  for (const mounted of mountedByComposer.values()) {
42164
42510
  if (mounted.hostId !== hostId2) continue;
42165
42511
  renderMounted(mounted);
42166
- void refreshDraftCodexUsage(mounted);
42512
+ if (controller.get(mounted.composer).agent === "codex") void refreshDraftUsage(mounted);
42167
42513
  }
42168
42514
  });
42169
42515
  });
@@ -42346,36 +42692,59 @@ ${usage_default}`;
42346
42692
  renderMounted(mounted);
42347
42693
  }
42348
42694
  };
42349
- const refreshDraftCodexUsage = async (mounted) => {
42695
+ const refreshDraftUsage = async (mounted) => {
42350
42696
  const state = controller.get(mounted.composer);
42351
- 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))
42352
42698
  return;
42353
- const accounts = composerCodexAccounts(mounted.composer);
42354
- const client = accounts?.client;
42699
+ const agent = state.agent;
42700
+ const accounts = agent === "codex" ? composerCodexAccounts(mounted.composer) : null;
42355
42701
  const accountId = accounts?.readyAccountId;
42702
+ const client = composerClient(mounted);
42356
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;
42357
42707
  const generation = ++mounted.usageRequestGeneration;
42708
+ const request = { client, generation, pending: true };
42709
+ draftUsageRequests.set(mounted, request);
42710
+ mounted.draftUsageClient = null;
42358
42711
  mounted.usage = null;
42359
42712
  mounted.accountCredits = null;
42713
+ mounted.accountCreditsSupported = false;
42360
42714
  renderMounted(mounted);
42361
- 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);
42362
42716
  try {
42363
- const result = await client.inspectCodexAccountUsage({ accountId });
42364
- 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)
42365
- return;
42366
- mounted.usage = result.usage;
42367
- 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;
42368
42735
  renderMounted(mounted);
42369
42736
  } catch {
42737
+ } finally {
42738
+ request.pending = false;
42370
42739
  }
42371
42740
  };
42372
42741
  const refreshThreadUsage = async (mounted, refresh) => {
42373
42742
  const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
42374
- if (!threadId && controller.get(mounted.composer).agent === "codex") {
42375
- await refreshDraftCodexUsage(mounted);
42743
+ if (!threadId) {
42744
+ await refreshDraftUsage(mounted);
42376
42745
  return;
42377
42746
  }
42378
- if (!threadId || !modelControl) {
42747
+ if (!modelControl) {
42379
42748
  mounted.usage = null;
42380
42749
  mounted.accountCredits = null;
42381
42750
  usageRefreshAttempts.delete(mounted.composer);
@@ -43170,8 +43539,23 @@ ${usage_default}`;
43170
43539
  if (agent !== "codex" && composerAvailability(mounted)[agent] !== "ready") {
43171
43540
  return false;
43172
43541
  }
43542
+ const state = controller.get(mounted.composer);
43543
+ if (state.phase !== "draft" || controller.isSwitching(mounted.composer)) return false;
43173
43544
  controller.clearPendingSubmission(mounted.composer);
43174
- 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
+ }
43175
43559
  controller.invalidateModelRequests(mounted.composer);
43176
43560
  const switching = controller.switchAgent(mounted.composer, agent, {
43177
43561
  applyAgent: (nextAgent) => applyDraftAgentCarrier(mounted.composer, nextAgent),
@@ -43199,7 +43583,9 @@ ${usage_default}`;
43199
43583
  return false;
43200
43584
  } finally {
43201
43585
  for (const candidate of mountedByComposer.values()) {
43202
- 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);
43203
43589
  }
43204
43590
  }
43205
43591
  };
@@ -43214,7 +43600,7 @@ ${usage_default}`;
43214
43600
  for (const mounted of mountedByComposer.values()) {
43215
43601
  if (mounted.hostId !== hostId2) continue;
43216
43602
  renderMounted(mounted);
43217
- void refreshDraftCodexUsage(mounted);
43603
+ if (controller.get(mounted.composer).agent === "codex") void refreshDraftUsage(mounted);
43218
43604
  }
43219
43605
  })
43220
43606
  );
@@ -43428,6 +43814,7 @@ ${usage_default}`;
43428
43814
  void clearDraftPrewarm(mounted.composer).catch(() => void 0);
43429
43815
  }
43430
43816
  void loadExternalCatalog(mounted);
43817
+ void refreshDraftUsage(mounted);
43431
43818
  continue;
43432
43819
  }
43433
43820
  const target = controllerTarget(mounted.modelTarget, hostId2);
@@ -43456,11 +43843,18 @@ ${usage_default}`;
43456
43843
  }
43457
43844
  if (changed) sidebarAgentIcons.refresh();
43458
43845
  };
43459
- function reconcileHarnessAvailabilityHost() {
43846
+ function reconcileHarnessAvailabilityHost(retryDraftUsage = false) {
43460
43847
  for (const hostId3 of modelControl?.knownHostIds?.() ?? []) {
43461
43848
  hostHarnessAvailabilityState(hostId3);
43462
43849
  }
43463
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
+ }
43464
43858
  let connectionsChanged = false;
43465
43859
  for (const target of new Set([...mountedByComposer.values()].map((m) => m.hostId))) {
43466
43860
  if (!target) continue;
@@ -43667,6 +44061,7 @@ ${usage_default}`;
43667
44061
  accountCreditsSupported: inherited?.accountCreditsSupported ?? false,
43668
44062
  hostId: inherited?.hostId ?? hostId2,
43669
44063
  usageRequestGeneration: 0,
44064
+ draftUsageClient: null,
43670
44065
  commandRequestGeneration: 0
43671
44066
  };
43672
44067
  mountedByComposer.set(composer, mounted);
@@ -43686,7 +44081,7 @@ ${usage_default}`;
43686
44081
  } else if (state.agent !== "codex" && !isExternalConfigurationStable(mounted.modelView, mounted.permissionModeView)) {
43687
44082
  void loadExternalCatalog(mounted);
43688
44083
  }
43689
- if (!threadIdFromComposerModelTarget(modelTarget)) void refreshDraftCodexUsage(mounted);
44084
+ if (!threadIdFromComposerModelTarget(modelTarget)) void refreshDraftUsage(mounted);
43690
44085
  void refreshCommands(mounted);
43691
44086
  };
43692
44087
  const scan = () => {
@@ -43966,7 +44361,7 @@ ${usage_default}`;
43966
44361
  document.addEventListener("keydown", onKeyDown, true);
43967
44362
  document.addEventListener("click", onClick, true);
43968
44363
  const onWindowFocus = () => {
43969
- reconcileHarnessAvailabilityHost();
44364
+ reconcileHarnessAvailabilityHost(true);
43970
44365
  void loadCodexAccounts();
43971
44366
  for (const mounted of mountedByComposer.values()) {
43972
44367
  if (mounted.hostId === activeModelHostId(mounted.composer) && mounted.ownershipStatus === "error") {
@@ -44150,6 +44545,7 @@ ${usage_default}`;
44150
44545
  for (const mounted of mountedByComposer.values()) {
44151
44546
  renderMounted(mounted);
44152
44547
  void refreshCommands(mounted);
44548
+ if (controller.get(mounted.composer).agent !== "codex") void refreshDraftUsage(mounted);
44153
44549
  }
44154
44550
  },
44155
44551
  dispose() {