@codexhost/cli-win32-arm64 0.13.3 → 0.15.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 (33) hide show
  1. package/README.md +1 -1
  2. package/app/codexhost-distribution.json +1 -1
  3. package/app/console-server.mjs +109 -11
  4. package/app/console-web.js +649 -132
  5. package/app/desktop-controller.mjs +120 -12
  6. package/app/host-runtime.mjs +1124 -293
  7. package/app/plugins/antigravity/plugin.mjs +431 -66
  8. package/app/plugins/claude-code/plugin.mjs +761 -139
  9. package/app/plugins/codebuddy/plugin.mjs +322 -68
  10. package/app/plugins/codex-usage/plugin.mjs +249 -102
  11. package/app/plugins/copilot/assets/icon.png +0 -0
  12. package/app/plugins/copilot/manifest.json +26 -0
  13. package/app/plugins/copilot/plugin.mjs +34591 -0
  14. package/app/plugins/cursor-cli/plugin.mjs +21011 -44970
  15. package/app/plugins/deepseek-harness/plugin.mjs +160 -43
  16. package/app/plugins/enabled.json +1 -0
  17. package/app/plugins/grok/plugin.mjs +565 -107
  18. package/app/plugins/hermes/plugin.mjs +128 -12
  19. package/app/plugins/kimi-code/plugin.mjs +136 -22
  20. package/app/plugins/kiro-cli/plugin.mjs +136 -22
  21. package/app/plugins/omp/plugin.mjs +2236 -2036
  22. package/app/plugins/opencode/plugin.mjs +187 -68
  23. package/app/plugins/pi/plugin.mjs +2621 -2304
  24. package/app/plugins/qoder/plugin.mjs +153 -36
  25. package/app/plugins/qoder-cn/plugin.mjs +153 -36
  26. package/app/plugins/workbuddy/plugin.mjs +583 -92
  27. package/app/plugins/zcode/plugin.mjs +183 -40
  28. package/app/renderer-extension.js +1758 -392
  29. package/bin/codexhost.exe +0 -0
  30. package/libexec/codexhost-node-repl.exe +0 -0
  31. package/libexec/codexhost-shim.exe +0 -0
  32. package/libexec/codexhost-updater.exe +0 -0
  33. package/package.json +1 -1
@@ -178,9 +178,10 @@
178
178
  clearPendingSubmission(composer) {
179
179
  this.#pendingSubmissions.delete(this.#state(composer));
180
180
  }
181
+ /** Only a draft's submission creates a Thread, so only it sets the next new-Thread Agent. */
181
182
  recordSubmission(composer) {
182
183
  const state = this.#state(composer);
183
- this.#lastSubmittedAgent = state.agent;
184
+ if (state.phase === "draft") this.#lastSubmittedAgent = state.agent;
184
185
  return state;
185
186
  }
186
187
  transfer(source, replacement, target = null) {
@@ -3265,10 +3266,10 @@
3265
3266
  const shape = def.shape;
3266
3267
  const propValues = {};
3267
3268
  for (const key in shape) {
3268
- const field = shape[key]._zod;
3269
- if (field.values) {
3269
+ const field2 = shape[key]._zod;
3270
+ if (field2.values) {
3270
3271
  propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
3271
- for (const v of field.values)
3272
+ for (const v of field2.values)
3272
3273
  propValues[key].add(v);
3273
3274
  }
3274
3275
  }
@@ -14930,10 +14931,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14930
14931
  var project = external_exports.string().min(1).max(4096);
14931
14932
  var usageStatisticsParamsSchema = external_exports.strictObject({
14932
14933
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14934
+ /** Display timezone for ranges, dates and hourly buckets; omitted means the Host's local zone. */
14935
+ timeZone: external_exports.string().min(1).max(128).refine((value) => {
14936
+ try {
14937
+ new Intl.DateTimeFormat("en", { timeZone: value });
14938
+ return true;
14939
+ } catch {
14940
+ return false;
14941
+ }
14942
+ }, "Unsupported usage statistics timezone").optional(),
14933
14943
  harness: harness.optional(),
14934
14944
  model: model.nullable().optional(),
14935
14945
  project: project.nullable().optional(),
14936
- /** One local date inside the range. */
14946
+ /** One date in the query timezone inside the range. */
14937
14947
  date: localDate.optional()
14938
14948
  });
14939
14949
  var usageStatisticsTotalsSchema = external_exports.strictObject({
@@ -14969,7 +14979,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14969
14979
  });
14970
14980
  var usageStatisticsResultSchema = external_exports.strictObject({
14971
14981
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14972
- /** First local date of the range; null for all time. */
14982
+ /** First date in the query timezone (Host local when omitted); null for all time. */
14973
14983
  from: localDate.nullable(),
14974
14984
  to: localDate,
14975
14985
  /** The filters these figures apply, echoed so a late answer to older filters is recognised. */
@@ -15009,7 +15019,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15009
15019
  totals: usageStatisticsTotalsSchema,
15010
15020
  /** Each date and Harness of the range: every filter except the day. */
15011
15021
  daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
15012
- /** Local weekday (0 = Sunday) and hour, all filters applied. */
15022
+ /** Weekday (0 = Sunday) and hour in the query timezone, all filters applied. */
15013
15023
  hourly: external_exports.array(external_exports.strictObject({
15014
15024
  weekday: external_exports.number().int().min(0).max(6),
15015
15025
  hour: external_exports.number().int().min(0).max(23),
@@ -15049,6 +15059,53 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15049
15059
  var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
15050
15060
  var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
15051
15061
 
15062
+ // ../shared-contracts/dist/thread-questions.js
15063
+ var THREAD_QUESTIONS_LIST_METHOD = "codexhost/thread/questions/list";
15064
+ var THREAD_QUESTION_RESPOND_METHOD = "codexhost/thread/question/respond";
15065
+ var field = external_exports.discriminatedUnion("type", [
15066
+ external_exports.object({
15067
+ id: external_exports.string().min(1),
15068
+ type: external_exports.literal("choice"),
15069
+ prompt: external_exports.string(),
15070
+ options: external_exports.array(external_exports.object({
15071
+ value: external_exports.string().min(1),
15072
+ label: external_exports.string(),
15073
+ description: external_exports.string().optional()
15074
+ })).min(1),
15075
+ multiple: external_exports.boolean(),
15076
+ allowOther: external_exports.boolean(),
15077
+ optional: external_exports.boolean()
15078
+ }),
15079
+ external_exports.object({
15080
+ id: external_exports.string().min(1),
15081
+ type: external_exports.literal("text"),
15082
+ prompt: external_exports.string(),
15083
+ multiline: external_exports.boolean(),
15084
+ secret: external_exports.literal(false),
15085
+ optional: external_exports.boolean(),
15086
+ placeholder: external_exports.string().optional(),
15087
+ prefill: external_exports.string().optional()
15088
+ })
15089
+ ]);
15090
+ var threadQuestionSchema = external_exports.object({
15091
+ interactionId: external_exports.string().min(1),
15092
+ turnId: external_exports.string().min(1),
15093
+ title: external_exports.string().optional(),
15094
+ questions: external_exports.array(field).min(1)
15095
+ }).refine(({ questions }) => questions.some((q) => q.type === "choice" && q.multiple), {
15096
+ message: "Shared cards require at least one multi-select question"
15097
+ });
15098
+ var threadQuestionsListParamsSchema = external_exports.strictObject({ threadId: external_exports.string().min(1) });
15099
+ var threadQuestionsResultSchema = external_exports.object({ questions: external_exports.array(threadQuestionSchema) });
15100
+ var threadQuestionRespondParamsSchema = external_exports.strictObject({
15101
+ threadId: external_exports.string().min(1),
15102
+ turnId: external_exports.string().min(1),
15103
+ interactionId: external_exports.string().min(1),
15104
+ answers: external_exports.record(external_exports.string(), external_exports.array(external_exports.string())),
15105
+ cancelled: external_exports.boolean().default(false)
15106
+ });
15107
+ var threadQuestionRespondResultSchema = external_exports.object({ accepted: external_exports.literal(true) });
15108
+
15052
15109
  // ../shared-contracts/dist/console.js
15053
15110
  var consoleAnnouncementSchema = external_exports.strictObject({
15054
15111
  title: external_exports.string().trim().min(1).max(200),
@@ -15070,6 +15127,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15070
15127
  "codexhost/harness/display-settings/set",
15071
15128
  "codexhost/harness/inspect",
15072
15129
  "codexhost/harness/installation",
15130
+ "codexhost/harness/installation/start",
15131
+ "codexhost/harness/installation/status",
15073
15132
  "codexhost/harness/launch-settings/get",
15074
15133
  "codexhost/harness/launch-settings/set",
15075
15134
  "codexhost/harness/web-ui/open",
@@ -15148,7 +15207,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15148
15207
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
15149
15208
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
15150
15209
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
15210
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
15211
+ var composerIndicatorsSchema = external_exports.array(external_exports.object({
15212
+ kind: external_exports.literal("countdown"),
15213
+ id: external_exports.string().min(1).max(64),
15214
+ expiresAtUnix: nonNegativeSafeIntegerSchema,
15215
+ label: indicatorTextSchema(256).optional(),
15216
+ tooltip: indicatorTextSchema(1024).optional()
15217
+ }).strict()).max(2).refine((entries) => new Set(entries.map(({ id }) => id)).size === entries.length, {
15218
+ message: "Composer indicator IDs must be unique"
15219
+ });
15151
15220
  var threadUsageSnapshotSchema = external_exports.object({
15221
+ composerIndicators: composerIndicatorsSchema.optional(),
15152
15222
  inputTokens: nonNegativeSafeIntegerSchema.optional(),
15153
15223
  cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
15154
15224
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -15564,7 +15634,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15564
15634
  }).strict().optional(),
15565
15635
  autonomousTurns: external_exports.object({
15566
15636
  observe: external_exports.boolean()
15567
- }).strict().optional()
15637
+ }).strict().optional(),
15638
+ /** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
15639
+ steer: external_exports.boolean().optional()
15568
15640
  }).strict();
15569
15641
  var harnessConfigurationStateSchema = external_exports.object({
15570
15642
  effectiveModel: harnessModelRefSchema.optional(),
@@ -15612,7 +15684,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15612
15684
  var harnessInspectParamsSchema = external_exports.object({
15613
15685
  harnessId: harnessIdSchema,
15614
15686
  cwd: nonBlankTextSchema2.max(16384).optional(),
15615
- refresh: external_exports.boolean().optional()
15687
+ refresh: external_exports.boolean().optional(),
15688
+ /** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
15689
+ purpose: external_exports.literal("availability").optional()
15616
15690
  }).strict();
15617
15691
  var harnessWebUiOpenParamsSchema = external_exports.object({
15618
15692
  harnessId: harnessIdSchema
@@ -15695,6 +15769,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15695
15769
  seen.add(thread.threadId);
15696
15770
  }
15697
15771
  });
15772
+ var threadSteeringInspectParamsSchema = external_exports.object({
15773
+ threadId: hostThreadIdSchema,
15774
+ /** The text about to be steered; a Harness command always stops and restarts. */
15775
+ text: external_exports.string().optional()
15776
+ }).strict();
15777
+ var THREAD_STEER_DELIVERY_PARAM = "codexhostSteerDelivery";
15778
+ var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
15779
+ var threadSteeringInspectResultSchema = external_exports.object({
15780
+ delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
15781
+ }).strict();
15698
15782
 
15699
15783
  // ../shared-contracts/dist/harness-plugins.js
15700
15784
  var HARNESS_PLUGIN_MANIFEST_MAX_BYTES = 32 * 1024;
@@ -15813,7 +15897,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15813
15897
  }).strict();
15814
15898
 
15815
15899
  // ../shared-contracts/dist/harness-installation.js
15816
- var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
15900
+ var HARNESS_INSTALLATION_START_METHOD = "codexhost/harness/installation/start";
15901
+ var HARNESS_INSTALLATION_STATUS_METHOD = "codexhost/harness/installation/status";
15817
15902
  var harnessInstallationParamsSchema = external_exports.object({
15818
15903
  harnessId: harnessIdSchema,
15819
15904
  action: external_exports.enum(["check", "update", "install"])
@@ -15823,6 +15908,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15823
15908
  latestVersion: external_exports.string().min(1).max(128),
15824
15909
  updateAvailable: external_exports.boolean(),
15825
15910
  canUpdate: external_exports.boolean(),
15911
+ /** Defaults to CLI; some Harnesses ship only inside a desktop application. */
15912
+ versionKind: external_exports.enum(["cli", "application"]).optional(),
15913
+ /** Official download opened by the user; does not imply an automatic installation. */
15914
+ manualUpdateUrl: external_exports.url().max(2048).refine((value) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value), "Manual updates require a credential-free HTTPS URL").optional(),
15826
15915
  // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15827
15916
  message: external_exports.string().max(2048).optional(),
15828
15917
  messageCode: external_exports.string().min(1).max(128).optional(),
@@ -15830,6 +15919,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15830
15919
  notice: harnessLocalizedTextSchema.optional(),
15831
15920
  latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15832
15921
  }).strict();
15922
+ var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
15923
+ var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
15924
+ external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
15925
+ external_exports.object({
15926
+ taskId: external_exports.string().uuid(),
15927
+ status: external_exports.literal("succeeded"),
15928
+ result: harnessInstallationStateSchema
15929
+ }).strict(),
15930
+ external_exports.object({
15931
+ taskId: external_exports.string().uuid(),
15932
+ status: external_exports.literal("failed"),
15933
+ error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
15934
+ }).strict()
15935
+ ]);
15833
15936
 
15834
15937
  // ../shared-contracts/dist/codex-accounts.js
15835
15938
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
@@ -16240,9 +16343,63 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16240
16343
  // ../shared-contracts/dist/index.js
16241
16344
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
16242
16345
 
16243
- // src/codex-ssh-adapter.ts
16346
+ // src/codex-native-services.ts
16347
+ async function loadCodexNativeServices(ownerWindow, matchesServices, importModule = (url2) => import(url2)) {
16348
+ if (!ownerWindow.document || !ownerWindow.location) return null;
16349
+ const page = new URL(ownerWindow.location.href);
16350
+ const urls = /* @__PURE__ */ new Set();
16351
+ for (const link of ownerWindow.document.querySelectorAll('link[rel="modulepreload"][href]')) {
16352
+ const url2 = new URL(link.getAttribute("href") ?? "", page);
16353
+ if (url2.protocol === page.protocol && url2.host === page.host && url2.pathname.endsWith(".js") && !url2.search && !url2.hash)
16354
+ urls.add(url2.href);
16355
+ }
16356
+ const candidates = [...urls].sort(
16357
+ (a, b) => Number(b.includes("/app-shared-")) - Number(a.includes("/app-shared-"))
16358
+ );
16359
+ const matches = /* @__PURE__ */ new Set();
16360
+ for (const url2 of candidates) {
16361
+ let module;
16362
+ try {
16363
+ module = await importModule(url2);
16364
+ } catch {
16365
+ continue;
16366
+ }
16367
+ for (const value of Object.values(module).filter(matchesServices)) matches.add(value);
16368
+ if (matches.size > 1) throw new Error("Codex native services are unavailable in this window");
16369
+ }
16370
+ return [...matches][0] ?? null;
16371
+ }
16372
+
16373
+ // src/codex-ssh-services.ts
16244
16374
  var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
16375
+ function isSshServices(value) {
16376
+ if (!record2(value) || !Object.hasOwn(value, "sshConnections") || !Object.hasOwn(value, "remoteConnections"))
16377
+ return false;
16378
+ const ssh = value.sshConnections;
16379
+ const remote = value.remoteConnections;
16380
+ return ssh != null && remote != null && typeof ssh.refresh === "function" && typeof ssh.save === "function" && typeof remote.getState === "function" && typeof remote.setAutoConnect === "function";
16381
+ }
16382
+ async function loadCodexSshServices(ownerWindow, importModule) {
16383
+ return loadCodexNativeServices(ownerWindow, isSshServices, importModule);
16384
+ }
16385
+
16386
+ // src/codex-ssh-adapter.ts
16387
+ var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
16245
16388
  function createCodexSshClient(ownerWindow) {
16389
+ let nativeServices;
16390
+ function services() {
16391
+ nativeServices ??= loadCodexSshServices(ownerWindow).then(
16392
+ (value) => {
16393
+ if (!value) nativeServices = void 0;
16394
+ return value;
16395
+ },
16396
+ (error51) => {
16397
+ nativeServices = void 0;
16398
+ throw error51;
16399
+ }
16400
+ );
16401
+ return nativeServices;
16402
+ }
16246
16403
  function request(operation, params, signal) {
16247
16404
  const bridge = ownerWindow.electronBridge;
16248
16405
  if (!bridge?.sendMessageFromView)
@@ -16250,7 +16407,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16250
16407
  if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
16251
16408
  return new Promise((resolve, reject) => {
16252
16409
  const requestId = ownerWindow.crypto.randomUUID();
16410
+ let settled = false;
16253
16411
  const finish = (error51, value) => {
16412
+ if (settled) return;
16413
+ settled = true;
16254
16414
  ownerWindow.clearTimeout(timer);
16255
16415
  ownerWindow.removeEventListener("message", receive);
16256
16416
  signal?.removeEventListener("abort", abort);
@@ -16260,10 +16420,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16260
16420
  const abort = () => finish(new DOMException("Aborted", "AbortError"));
16261
16421
  const receive = (event) => {
16262
16422
  const message2 = event.data;
16263
- if (!record2(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId)
16423
+ if (!record3(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId)
16264
16424
  return;
16265
16425
  if (message2.responseType !== "success" || typeof message2.status !== "number" || message2.status < 200 || message2.status >= 300 || typeof message2.bodyJsonString !== "string") {
16266
- finish(new Error("Codex SSH request failed; check the native Connections settings"));
16426
+ const detail = typeof message2.error === "string" ? `: ${message2.error}` : "";
16427
+ finish(
16428
+ new Error(`Codex SSH request failed; check the native Connections settings${detail}`)
16429
+ );
16267
16430
  return;
16268
16431
  }
16269
16432
  try {
@@ -16278,30 +16441,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16278
16441
  );
16279
16442
  ownerWindow.addEventListener("message", receive);
16280
16443
  signal?.addEventListener("abort", abort, { once: true });
16281
- try {
16282
- Promise.resolve(
16283
- bridge.sendMessageFromView({
16444
+ void (async () => {
16445
+ const native = await services();
16446
+ if (settled) return;
16447
+ if (native) {
16448
+ let result;
16449
+ switch (operation) {
16450
+ case "refresh-remote-connections":
16451
+ result = await native.sshConnections.refresh();
16452
+ break;
16453
+ case "save-codex-managed-remote-ssh-connections":
16454
+ result = await native.sshConnections.save(params);
16455
+ break;
16456
+ case "set-remote-connection-auto-connect":
16457
+ result = await native.remoteConnections.setAutoConnect(params);
16458
+ break;
16459
+ case "app-server-connection-state":
16460
+ result = await native.remoteConnections.getState(String(params.hostId));
16461
+ break;
16462
+ }
16463
+ finish(null, result);
16464
+ } else {
16465
+ await bridge.sendMessageFromView({
16284
16466
  type: "fetch",
16285
16467
  requestId,
16286
16468
  method: "POST",
16287
16469
  url: `vscode://codex/${operation}`,
16288
16470
  body: JSON.stringify(params),
16289
16471
  reportUploadProgress: false
16290
- })
16291
- ).catch((error51) => finish(error51));
16292
- } catch (error51) {
16293
- finish(error51);
16294
- }
16472
+ });
16473
+ }
16474
+ })().catch((error51) => finish(error51));
16295
16475
  });
16296
16476
  }
16297
16477
  async function list(signal) {
16298
16478
  const result = await request("refresh-remote-connections", {}, signal);
16299
- if (!record2(result) || !Array.isArray(result.remoteConnections))
16479
+ if (!record3(result) || !Array.isArray(result.remoteConnections))
16300
16480
  throw new Error("Invalid Codex SSH connection list");
16301
16481
  return result.remoteConnections.filter(
16302
- (item) => !(record2(item) && ["wsl", "remote-control"].includes(String(item.source)))
16482
+ (item) => !(record3(item) && ["wsl", "remote-control"].includes(String(item.source)))
16303
16483
  ).map((item) => {
16304
- if (!record2(item) || typeof item.hostId !== "string" || typeof item.displayName !== "string" || !["codex-managed", "discovered"].includes(String(item.source)) || typeof item.sshHost !== "string" || typeof item.autoConnect !== "boolean" || !(item.sshAlias == null || typeof item.sshAlias === "string") || !(item.identity == null || typeof item.identity === "string") || !(item.sshPort == null || Number.isInteger(item.sshPort) && Number(item.sshPort) > 0 && Number(item.sshPort) <= 65535)) {
16484
+ if (!record3(item) || typeof item.hostId !== "string" || typeof item.displayName !== "string" || !["codex-managed", "discovered"].includes(String(item.source)) || typeof item.sshHost !== "string" || typeof item.autoConnect !== "boolean" || !(item.sshAlias == null || typeof item.sshAlias === "string") || !(item.identity == null || typeof item.identity === "string") || !(item.sshPort == null || Number.isInteger(item.sshPort) && Number(item.sshPort) > 0 && Number(item.sshPort) <= 65535)) {
16305
16485
  throw new Error(
16306
16486
  "This Codex version uses an unsupported SSH configuration; open native settings"
16307
16487
  );
@@ -16373,11 +16553,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16373
16553
  },
16374
16554
  async state(hostId2, signal) {
16375
16555
  const result = await request("app-server-connection-state", { hostId: hostId2 }, signal);
16376
- if (!record2(result) || typeof result.state !== "string")
16556
+ if (!record3(result) || typeof result.state !== "string")
16377
16557
  throw new Error("Invalid Codex connection state");
16378
16558
  return {
16379
16559
  state: result.state,
16380
- error: typeof result.error === "string" ? result.error : record2(result.error) && typeof result.error.message === "string" ? result.error.message : null
16560
+ error: typeof result.error === "string" ? result.error : record3(result.error) && typeof result.error.message === "string" ? result.error.message : null
16381
16561
  };
16382
16562
  }
16383
16563
  };
@@ -16455,6 +16635,545 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16455
16635
  return control;
16456
16636
  }
16457
16637
 
16638
+ // ../../node_modules/lucide/dist/esm/defaultAttributes.mjs
16639
+ var defaultAttributes = {
16640
+ xmlns: "http://www.w3.org/2000/svg",
16641
+ width: 24,
16642
+ height: 24,
16643
+ viewBox: "0 0 24 24",
16644
+ fill: "none",
16645
+ stroke: "currentColor",
16646
+ "stroke-width": 2,
16647
+ "stroke-linecap": "round",
16648
+ "stroke-linejoin": "round"
16649
+ };
16650
+
16651
+ // ../../node_modules/lucide/dist/esm/createElement.mjs
16652
+ var createSVGElement = ([tag, attrs, children]) => {
16653
+ const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
16654
+ Object.keys(attrs).forEach((name) => {
16655
+ element.setAttribute(name, String(attrs[name]));
16656
+ });
16657
+ if (children?.length) {
16658
+ children.forEach((child) => {
16659
+ const childElement = createSVGElement(child);
16660
+ element.appendChild(childElement);
16661
+ });
16662
+ }
16663
+ return element;
16664
+ };
16665
+ var createElement = (iconNode, customAttrs = {}) => {
16666
+ const tag = "svg";
16667
+ const attrs = {
16668
+ ...defaultAttributes,
16669
+ ...customAttrs
16670
+ };
16671
+ return createSVGElement([tag, attrs, iconNode]);
16672
+ };
16673
+
16674
+ // ../../node_modules/lucide/dist/esm/icons/check.mjs
16675
+ var Check = [["path", { d: "M20 6 9 17l-5-5" }]];
16676
+
16677
+ // ../../node_modules/lucide/dist/esm/icons/message-circle-question-mark.mjs
16678
+ var MessageCircleQuestionMark = [
16679
+ [
16680
+ "path",
16681
+ {
16682
+ d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719"
16683
+ }
16684
+ ],
16685
+ ["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" }],
16686
+ ["path", { d: "M12 17h.01" }]
16687
+ ];
16688
+
16689
+ // ../../node_modules/lucide/dist/esm/icons/pencil.mjs
16690
+ var Pencil = [
16691
+ [
16692
+ "path",
16693
+ {
16694
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"
16695
+ }
16696
+ ],
16697
+ ["path", { d: "m15 5 4 4" }]
16698
+ ];
16699
+
16700
+ // ../../node_modules/lucide/dist/esm/icons/x.mjs
16701
+ var X = [
16702
+ ["path", { d: "M18 6 6 18" }],
16703
+ ["path", { d: "m6 6 12 12" }]
16704
+ ];
16705
+
16706
+ // src/renderer-question-card-style.ts
16707
+ var QUESTION_CARD_CSS = `
16708
+ :host {
16709
+ display: block;
16710
+ min-width: 0;
16711
+ margin: 8px 0;
16712
+ color-scheme: inherit;
16713
+ --question-text: light-dark(#171717, #ececec);
16714
+ --question-muted: light-dark(#737373, #a3a3a3);
16715
+ --question-border: light-dark(rgb(0 0 0 / 8%), rgb(255 255 255 / 8%));
16716
+ --question-selected: light-dark(#e9e9e9, #333333);
16717
+ --question-primary: light-dark(#202020, #ececec);
16718
+ --question-primary-text: light-dark(#fff, #171717);
16719
+ }
16720
+ *, ::before, ::after { box-sizing: border-box; }
16721
+ .card {
16722
+ display: flex;
16723
+ flex-direction: column;
16724
+ max-height: min(60vh, 560px);
16725
+ overflow: hidden;
16726
+ padding: 16px 12px 12px;
16727
+ border: 1px solid var(--question-border);
16728
+ border-radius: 24px;
16729
+ background: light-dark(#f7f7f7, #262626);
16730
+ color: var(--question-text);
16731
+ font: 13px/1.5 system-ui, sans-serif;
16732
+ }
16733
+ .title { display: flex; align-items: center; gap: 10px; flex-shrink: 0; margin: 0 6px 14px; color: var(--question-muted); font-weight: 400; }
16734
+ .question-icon { display: inline-flex; justify-content: center; align-items: center; width: 16px; height: 16px; flex-shrink: 0; }
16735
+ svg { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
16736
+ .body { min-height: 0; overflow: auto; }
16737
+ fieldset { min-width: 0; border: 0; padding: 0; margin: 0 0 14px; }
16738
+ fieldset:last-child { margin-bottom: 0; }
16739
+ legend { width: 100%; padding: 0 6px; margin-bottom: 14px; font: inherit; }
16740
+ .hint { color: var(--question-muted); font-size: 12px; margin: -10px 6px 10px; }
16741
+ .option {
16742
+ position: relative;
16743
+ display: flex;
16744
+ align-items: flex-start;
16745
+ gap: 10px;
16746
+ min-height: 34px;
16747
+ padding: 6px;
16748
+ margin: 2px 0;
16749
+ border-radius: 12px;
16750
+ cursor: pointer;
16751
+ background: transparent;
16752
+ overflow-wrap: anywhere;
16753
+ }
16754
+ .option:hover, .option:has(:checked) { background: var(--question-selected); }
16755
+ input[type=checkbox], input[type=radio] {
16756
+ appearance: none;
16757
+ display: block;
16758
+ flex: 0 0 21px;
16759
+ width: 21px;
16760
+ height: 21px;
16761
+ margin: 0;
16762
+ padding: 0;
16763
+ border: 1px solid var(--question-border);
16764
+ border-radius: 5px;
16765
+ background: light-dark(#ededed, #303030);
16766
+ cursor: pointer;
16767
+ }
16768
+ .shortcut { position: absolute; top: 6px; left: 6px; width: 21px; height: 21px; text-align: center; line-height: 21px; color: var(--question-muted); pointer-events: none; font-size: 12px; }
16769
+ .option-copy { flex: 1; min-width: 0; white-space: pre-wrap; }
16770
+ .option-name { display: block; font-weight: 400; }
16771
+ .description { display: block; color: var(--question-muted); font-size: 12px; margin-top: 1px; }
16772
+ .selected-indicator { align-self: center; visibility: hidden; color: var(--question-muted); padding-right: 4px; }
16773
+ :checked ~ .selected-indicator { visibility: visible; }
16774
+ .other { align-items: center; flex: 1; min-width: 0; margin: 0; }
16775
+ .other input[type=checkbox], .other input[type=radio] { background: transparent; border-color: transparent; }
16776
+ .other:has(:checked), .other:focus-within { background: var(--question-selected); }
16777
+ .other:has(:checked) .pencil { color: var(--question-text); }
16778
+ .pencil { display: flex; align-items: center; justify-content: center; }
16779
+ .other-copy { display: flex; flex: 1; min-width: 0; }
16780
+ input:not([type=checkbox]):not([type=radio]), textarea {
16781
+ appearance: none;
16782
+ display: block;
16783
+ min-width: 0;
16784
+ width: 100%;
16785
+ padding: 6px;
16786
+ border: 1px solid var(--question-border);
16787
+ border-radius: 8px;
16788
+ background: transparent;
16789
+ color: var(--question-text);
16790
+ font: inherit;
16791
+ }
16792
+ .other-copy input:not([type=checkbox]):not([type=radio]) { border: 0; padding: 0; }
16793
+ textarea { min-height: 60px; resize: vertical; }
16794
+ input::placeholder, textarea::placeholder { color: var(--question-muted); opacity: .65; }
16795
+ input:focus-visible, textarea:focus-visible, button:focus-visible {
16796
+ outline: 2px solid var(--question-muted);
16797
+ outline-offset: 2px;
16798
+ }
16799
+ .other-copy input:focus-visible { outline: none; }
16800
+ .other:has(input:focus-visible) { outline: 2px solid var(--question-muted); outline-offset: -2px; }
16801
+ .error { flex-shrink: 0; color: light-dark(#b42318, #ffaaa3); font-size: 12px; }
16802
+ .error:not(:empty) { margin: 8px 6px 0; }
16803
+ .footer { display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin-top: 8px; }
16804
+ .actions { display: flex; justify-content: flex-end; gap: 8px; margin-left: auto; flex-shrink: 0; }
16805
+ button {
16806
+ appearance: none;
16807
+ min-height: 28px;
16808
+ padding: 3px 10px;
16809
+ border: 1px solid var(--question-border);
16810
+ border-radius: 999px;
16811
+ background: transparent;
16812
+ color: var(--question-text);
16813
+ font: inherit;
16814
+ font-weight: 400;
16815
+ cursor: pointer;
16816
+ }
16817
+ button:hover { background: var(--question-selected); }
16818
+ button.primary { background: var(--question-primary); color: var(--question-primary-text); border-color: transparent; }
16819
+ button.primary:hover { opacity: .85; }
16820
+ button.dismiss { display: flex; align-items: center; justify-content: center; border: 0; padding: 0; min-height: 24px; width: 24px; margin-left: auto; color: var(--question-muted); }
16821
+ :disabled { cursor: wait; opacity: .5; }
16822
+ @media (max-width: 420px) { .footer { flex-wrap: wrap; } .footer > .other { flex-basis: 100%; } }
16823
+ @media (forced-colors: active) {
16824
+ .card, input, textarea { background: Canvas; color: CanvasText; }
16825
+ button, .card, input[type=checkbox], input[type=radio] { border-color: ButtonBorder; }
16826
+ .option:has(:checked) { outline: 1px solid Highlight; outline-offset: -1px; }
16827
+ button.primary { background: Highlight; color: HighlightText; }
16828
+ }
16829
+ `;
16830
+
16831
+ // src/renderer-question-card.ts
16832
+ function createQuestionCard(document2, question, submit, initial = {}) {
16833
+ const icon2 = (node) => document2.adoptNode(
16834
+ createElement(node, {
16835
+ width: 16,
16836
+ height: 16,
16837
+ "aria-hidden": "true",
16838
+ focusable: "false"
16839
+ })
16840
+ );
16841
+ const selectedIndicator = () => {
16842
+ const selected = document2.createElement("span");
16843
+ selected.className = "selected-indicator";
16844
+ selected.setAttribute("aria-hidden", "true");
16845
+ selected.append(icon2(Check));
16846
+ return selected;
16847
+ };
16848
+ const root = document2.createElement("section");
16849
+ root.dataset.codexhostQuestion = question.interactionId;
16850
+ root.setAttribute("aria-label", question.title ?? "Question");
16851
+ root.addEventListener("keydown", (event) => {
16852
+ event.stopPropagation();
16853
+ if (event.key === "Enter" && event.composedPath()[0] instanceof HTMLInputElement)
16854
+ event.preventDefault();
16855
+ });
16856
+ const shadow = root.attachShadow({ mode: "open" });
16857
+ const style = document2.createElement("style");
16858
+ style.textContent = QUESTION_CARD_CSS;
16859
+ const surface = document2.createElement("div");
16860
+ surface.className = "card";
16861
+ shadow.append(style, surface);
16862
+ const title = document2.createElement("div");
16863
+ title.className = "title";
16864
+ const titleIcon = document2.createElement("span");
16865
+ titleIcon.className = "question-icon";
16866
+ titleIcon.append(icon2(MessageCircleQuestionMark));
16867
+ titleIcon.setAttribute("aria-hidden", "true");
16868
+ const titleText = document2.createElement("span");
16869
+ titleText.textContent = question.title?.trim() || "Question";
16870
+ const dismiss = document2.createElement("button");
16871
+ dismiss.type = "button";
16872
+ dismiss.className = "dismiss";
16873
+ dismiss.append(icon2(X));
16874
+ dismiss.setAttribute("aria-label", "Dismiss question");
16875
+ title.append(titleIcon, titleText, dismiss);
16876
+ const body = document2.createElement("div");
16877
+ body.className = "body";
16878
+ surface.append(title, body);
16879
+ const footer = document2.createElement("div");
16880
+ footer.className = "footer";
16881
+ const readers = /* @__PURE__ */ new Map();
16882
+ const controls = [dismiss];
16883
+ const validOther = [];
16884
+ for (const [index, field2] of question.questions.entries()) {
16885
+ const group = document2.createElement("fieldset");
16886
+ const legend = document2.createElement("legend");
16887
+ legend.textContent = field2.prompt;
16888
+ group.append(legend);
16889
+ const saved = initial[field2.id] ?? [];
16890
+ if (field2.type === "text") {
16891
+ const input = document2.createElement(field2.multiline ? "textarea" : "input");
16892
+ input.value = saved[0] ?? field2.prefill ?? "";
16893
+ input.placeholder = field2.placeholder ?? "Your answer";
16894
+ input.setAttribute("aria-label", field2.prompt);
16895
+ controls.push(input);
16896
+ group.append(input);
16897
+ readers.set(field2.id, () => input.value.trim() ? [input.value] : []);
16898
+ } else {
16899
+ const hint = document2.createElement("div");
16900
+ hint.className = "hint";
16901
+ hint.textContent = "Select all that apply";
16902
+ if (field2.multiple) group.append(hint);
16903
+ const inputs = [];
16904
+ const name = `codexhost-${question.interactionId}-${index}`;
16905
+ for (const [optionIndex, option] of field2.options.entries()) {
16906
+ const label = document2.createElement("label");
16907
+ label.className = "option";
16908
+ const input = document2.createElement("input");
16909
+ input.type = field2.multiple ? "checkbox" : "radio";
16910
+ input.name = name;
16911
+ input.value = option.value;
16912
+ input.checked = saved.includes(option.value);
16913
+ const shortcut = document2.createElement("span");
16914
+ shortcut.className = "shortcut";
16915
+ shortcut.setAttribute("aria-hidden", "true");
16916
+ shortcut.textContent = String(optionIndex + 1);
16917
+ const selected = selectedIndicator();
16918
+ const text = document2.createElement("span");
16919
+ text.className = "option-copy";
16920
+ const optionName = document2.createElement("span");
16921
+ optionName.className = "option-name";
16922
+ optionName.textContent = option.label;
16923
+ text.append(optionName);
16924
+ if (option.description) {
16925
+ const description = document2.createElement("span");
16926
+ description.className = "description";
16927
+ description.textContent = option.description;
16928
+ text.append(description);
16929
+ }
16930
+ label.append(input, shortcut, text, selected);
16931
+ group.append(label);
16932
+ inputs.push(input);
16933
+ controls.push(input);
16934
+ }
16935
+ let other;
16936
+ let notes;
16937
+ if (field2.allowOther) {
16938
+ const label = document2.createElement("label");
16939
+ label.className = "option other";
16940
+ other = document2.createElement("input");
16941
+ other.type = field2.multiple ? "checkbox" : "radio";
16942
+ other.name = name;
16943
+ other.setAttribute("aria-label", `Other: ${field2.prompt}`);
16944
+ const unknown2 = saved.find(
16945
+ (value) => !field2.options.some((option) => option.value === value)
16946
+ );
16947
+ other.checked = unknown2 !== void 0;
16948
+ notes = document2.createElement("input");
16949
+ notes.value = unknown2 ?? "";
16950
+ notes.placeholder = "Or write your own response";
16951
+ notes.setAttribute("aria-label", `${field2.prompt}: Other`);
16952
+ const checkbox = other;
16953
+ const otherText = notes;
16954
+ validOther.push(() => !checkbox.checked || otherText.value.trim().length > 0);
16955
+ notes.addEventListener("input", () => {
16956
+ checkbox.checked = true;
16957
+ });
16958
+ const copy = document2.createElement("span");
16959
+ copy.className = "other-copy";
16960
+ copy.append(notes);
16961
+ const pencil = document2.createElement("span");
16962
+ pencil.className = "shortcut pencil";
16963
+ pencil.append(icon2(Pencil));
16964
+ pencil.setAttribute("aria-hidden", "true");
16965
+ const selected = selectedIndicator();
16966
+ label.append(other, pencil, copy, selected);
16967
+ if (question.questions.length === 1) footer.append(label);
16968
+ else group.append(label);
16969
+ controls.push(other, notes);
16970
+ }
16971
+ readers.set(field2.id, () => [
16972
+ ...inputs.filter((input) => input.checked).map((input) => input.value),
16973
+ ...other?.checked && notes?.value.trim() ? [notes.value] : []
16974
+ ]);
16975
+ }
16976
+ body.append(group);
16977
+ }
16978
+ const error51 = document2.createElement("div");
16979
+ error51.setAttribute("role", "alert");
16980
+ error51.className = "error";
16981
+ const actions = document2.createElement("div");
16982
+ actions.className = "actions";
16983
+ const readAnswers = () => Object.fromEntries([...readers].map(([id, read]) => [id, read()]));
16984
+ let busy = false;
16985
+ const send = async (cancelled) => {
16986
+ if (busy) return;
16987
+ const answers = cancelled ? {} : readAnswers();
16988
+ if (!cancelled && validOther.some((valid) => !valid())) {
16989
+ error51.textContent = "Type an answer for each selected Other option.";
16990
+ return;
16991
+ }
16992
+ if (!cancelled && question.questions.some((field2) => !field2.optional && !answers[field2.id]?.length)) {
16993
+ error51.textContent = "Answer each required question before submitting.";
16994
+ return;
16995
+ }
16996
+ busy = true;
16997
+ error51.textContent = "";
16998
+ for (const control of controls) control.disabled = true;
16999
+ try {
17000
+ await submit(answers, cancelled);
17001
+ } catch {
17002
+ error51.textContent = "Could not submit. The question may have closed. Try again if it is still available.";
17003
+ } finally {
17004
+ busy = false;
17005
+ for (const control of controls) control.disabled = false;
17006
+ }
17007
+ };
17008
+ for (const [label, cancelled] of [
17009
+ ["Skip", true],
17010
+ ["Send", false]
17011
+ ]) {
17012
+ const button2 = document2.createElement("button");
17013
+ button2.type = "button";
17014
+ button2.textContent = label;
17015
+ if (!cancelled) button2.className = "primary";
17016
+ button2.addEventListener("click", () => {
17017
+ void send(cancelled);
17018
+ });
17019
+ controls.push(button2);
17020
+ actions.append(button2);
17021
+ }
17022
+ dismiss.addEventListener("click", () => {
17023
+ void send(true);
17024
+ });
17025
+ footer.append(actions);
17026
+ surface.append(error51, footer);
17027
+ return {
17028
+ root,
17029
+ readAnswers,
17030
+ dispose() {
17031
+ root.remove();
17032
+ }
17033
+ };
17034
+ }
17035
+
17036
+ // src/renderer-request-sender.ts
17037
+ var RendererMethodUnavailableError = class extends Error {
17038
+ constructor(method, cause) {
17039
+ super(`${method} is unsupported on this Host connection`, { cause });
17040
+ this.method = method;
17041
+ this.name = "RendererMethodUnavailableError";
17042
+ }
17043
+ method;
17044
+ code = -32601;
17045
+ };
17046
+ function isUnsupportedMethod(error51, method) {
17047
+ if (typeof error51 !== "object" || error51 === null) return false;
17048
+ const code = "code" in error51 ? error51.code : void 0;
17049
+ const message2 = "message" in error51 ? error51.message : void 0;
17050
+ return code === -32601 || code === -32600 && typeof message2 === "string" && message2.startsWith(`Invalid request: unknown variant \`${method}\``);
17051
+ }
17052
+ function createRendererRequestSender(send) {
17053
+ const unsupported = /* @__PURE__ */ new Map();
17054
+ return async (method, params, options) => {
17055
+ const known = unsupported.get(method);
17056
+ if (known) throw known;
17057
+ try {
17058
+ return await (options === void 0 ? send(method, params) : send(method, params, options));
17059
+ } catch (error51) {
17060
+ if (!method.startsWith("codexhost/") || !isUnsupportedMethod(error51, method)) throw error51;
17061
+ const unavailable = new RendererMethodUnavailableError(method, error51);
17062
+ unsupported.set(method, unavailable);
17063
+ throw unavailable;
17064
+ }
17065
+ };
17066
+ }
17067
+
17068
+ // src/renderer-questions.ts
17069
+ function same(a, b) {
17070
+ return a?.hostId === b?.hostId && a?.threadId === b?.threadId && a?.composer === b?.composer && a?.route === b?.route;
17071
+ }
17072
+ function installRendererQuestions(window2, readContext) {
17073
+ let disposed = false;
17074
+ let inFlight = false;
17075
+ let revision = 0;
17076
+ let context = null;
17077
+ let card = null;
17078
+ let cardKey = null;
17079
+ const unsupported = /* @__PURE__ */ new WeakSet();
17080
+ const drafts = /* @__PURE__ */ new Map();
17081
+ const clear = (retain = true) => {
17082
+ if (retain && card && cardKey) {
17083
+ drafts.set(cardKey, card.readAnswers());
17084
+ const oldest = drafts.keys().next().value;
17085
+ if (drafts.size > 50 && oldest !== void 0) drafts.delete(oldest);
17086
+ }
17087
+ card?.dispose();
17088
+ card = null;
17089
+ cardKey = null;
17090
+ };
17091
+ const refresh = async () => {
17092
+ if (disposed) return;
17093
+ const next = readContext();
17094
+ if (!same(context, next)) {
17095
+ clear();
17096
+ context = next;
17097
+ revision++;
17098
+ }
17099
+ const current = context;
17100
+ if (!current || inFlight || unsupported.has(current.route)) return;
17101
+ const startedRevision = revision;
17102
+ inFlight = true;
17103
+ try {
17104
+ const raw = await current.route.sendRequest(
17105
+ THREAD_QUESTIONS_LIST_METHOD,
17106
+ { threadId: current.threadId },
17107
+ { priority: "background", timeoutMs: 5e3 }
17108
+ );
17109
+ if (disposed || revision !== startedRevision || !same(current, readContext())) return;
17110
+ const question = threadQuestionsResultSchema.parse(raw).questions[0];
17111
+ if (!question) {
17112
+ if (cardKey) drafts.delete(cardKey);
17113
+ clear(false);
17114
+ return;
17115
+ }
17116
+ const key = JSON.stringify([
17117
+ current.hostId,
17118
+ current.threadId,
17119
+ question.turnId,
17120
+ question.interactionId
17121
+ ]);
17122
+ if (cardKey === key && card?.root.isConnected) return;
17123
+ clear(cardKey === key);
17124
+ cardKey = key;
17125
+ card = createQuestionCard(
17126
+ current.composer.ownerDocument,
17127
+ question,
17128
+ async (answers, cancelled) => {
17129
+ if (disposed || !same(current, readContext()) || cardKey !== key)
17130
+ throw new Error("Question owner changed");
17131
+ const raw2 = await current.route.sendRequest(
17132
+ THREAD_QUESTION_RESPOND_METHOD,
17133
+ {
17134
+ threadId: current.threadId,
17135
+ turnId: question.turnId,
17136
+ interactionId: question.interactionId,
17137
+ answers,
17138
+ cancelled
17139
+ },
17140
+ { priority: "interactive", timeoutMs: 1e4 }
17141
+ );
17142
+ threadQuestionRespondResultSchema.parse(raw2);
17143
+ drafts.delete(key);
17144
+ if (same(current, context)) {
17145
+ revision++;
17146
+ if (cardKey === key) clear(false);
17147
+ }
17148
+ },
17149
+ drafts.get(key)
17150
+ );
17151
+ current.composer.before(card.root);
17152
+ } catch (error51) {
17153
+ if (isUnsupportedMethod(error51, THREAD_QUESTIONS_LIST_METHOD)) unsupported.add(current.route);
17154
+ if (revision === startedRevision && same(current, context)) clear();
17155
+ } finally {
17156
+ inFlight = false;
17157
+ }
17158
+ };
17159
+ const timer = window2.setInterval(() => {
17160
+ void refresh();
17161
+ }, 750);
17162
+ void refresh();
17163
+ return {
17164
+ refresh,
17165
+ refreshContext() {
17166
+ if (!same(context, readContext()) || card && !card.root.isConnected) void refresh();
17167
+ },
17168
+ dispose() {
17169
+ disposed = true;
17170
+ window2.clearInterval(timer);
17171
+ clear(false);
17172
+ drafts.clear();
17173
+ }
17174
+ };
17175
+ }
17176
+
16458
17177
  // ../desktop-control/dist/renderer-react-ownership.js
16459
17178
  var REACT_FIBER_WALK_LIMIT_EVENT = "codexhost:react-fiber-walk-limit";
16460
17179
  function committedReactAncestors(value) {
@@ -16784,42 +17503,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16784
17503
  return fallback;
16785
17504
  }
16786
17505
 
16787
- // ../../node_modules/lucide/dist/esm/defaultAttributes.mjs
16788
- var defaultAttributes = {
16789
- xmlns: "http://www.w3.org/2000/svg",
16790
- width: 24,
16791
- height: 24,
16792
- viewBox: "0 0 24 24",
16793
- fill: "none",
16794
- stroke: "currentColor",
16795
- "stroke-width": 2,
16796
- "stroke-linecap": "round",
16797
- "stroke-linejoin": "round"
16798
- };
16799
-
16800
- // ../../node_modules/lucide/dist/esm/createElement.mjs
16801
- var createSVGElement = ([tag, attrs, children]) => {
16802
- const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
16803
- Object.keys(attrs).forEach((name) => {
16804
- element.setAttribute(name, String(attrs[name]));
16805
- });
16806
- if (children?.length) {
16807
- children.forEach((child) => {
16808
- const childElement = createSVGElement(child);
16809
- element.appendChild(childElement);
16810
- });
16811
- }
16812
- return element;
16813
- };
16814
- var createElement = (iconNode, customAttrs = {}) => {
16815
- const tag = "svg";
16816
- const attrs = {
16817
- ...defaultAttributes,
16818
- ...customAttrs
16819
- };
16820
- return createSVGElement([tag, attrs, iconNode]);
16821
- };
16822
-
16823
17506
  // ../../node_modules/lucide/dist/esm/icons/boxes.mjs
16824
17507
  var Boxes = [
16825
17508
  [
@@ -17124,12 +17807,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17124
17807
  ["path", { d: "M12 17h.01" }]
17125
17808
  ];
17126
17809
 
17127
- // ../../node_modules/lucide/dist/esm/icons/x.mjs
17128
- var X = [
17129
- ["path", { d: "M18 6 6 18" }],
17130
- ["path", { d: "m6 6 12 12" }]
17131
- ];
17132
-
17133
17810
  // ../../node_modules/lucide/dist/esm/icons/users.mjs
17134
17811
  var Users = [
17135
17812
  ["path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }],
@@ -17553,7 +18230,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17553
18230
  }
17554
18231
 
17555
18232
  // src/settings/harness-version-panel.ts
17556
- function createHarnessVersionPanel(document2, messages, signal, agent, client) {
18233
+ function createHarnessVersionPanel(document2, messages, signal, agent, client, onChange = () => void 0) {
17557
18234
  const panel = document2.createElement("section");
17558
18235
  panel.className = "settings-harness-version";
17559
18236
  panel.dataset.harnessVersion = agent;
@@ -17579,37 +18256,67 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17579
18256
  panel.append(heading, versions, status, actions, note);
17580
18257
  let state;
17581
18258
  let busy = false;
18259
+ let updating = false;
17582
18260
  let unsupported = false;
18261
+ let updatePromise = null;
17583
18262
  const render = () => {
18263
+ heading.textContent = state?.versionKind === "application" ? messages.harnessVersionApplicationTitle : messages.harnessVersionTitle;
17584
18264
  current.textContent = `${messages.harnessVersionCurrent}: ${state?.currentVersion ?? "\u2014"}`;
17585
18265
  latest.textContent = `${messages.harnessVersionLatest}: ${harnessVersionLabel(state, messages.harnessVersion)}`;
17586
18266
  update.disabled = busy || signal.aborted || !state?.canUpdate || !state.updateAvailable;
18267
+ const manualUrl = !state?.canUpdate && state?.updateAvailable ? state.manualUpdateUrl : void 0;
18268
+ actions.replaceChildren(update);
18269
+ update.hidden = !busy && !signal.aborted && Boolean(manualUrl);
18270
+ if (update.hidden && manualUrl) {
18271
+ const download2 = document2.createElement("a");
18272
+ download2.className = "settings-command-button settings-command-button--secondary";
18273
+ download2.dataset.harnessVersionAction = "download-update";
18274
+ download2.textContent = messages.harnessVersionDownloadUpdate;
18275
+ download2.href = manualUrl;
18276
+ download2.target = "_blank";
18277
+ download2.rel = "noopener noreferrer";
18278
+ actions.append(download2);
18279
+ }
17587
18280
  update.textContent = state?.canUpdate && state.latestVersion !== "Unknown" && !state.updateAvailable ? messages.harnessVersionUpToDate : messages.harnessVersionUpdate;
17588
18281
  const detail = harnessVersionNote(state, messages.harnessVersion);
17589
- note.textContent = detail ? `${detail} ${messages.harnessVersionNote}` : messages.harnessVersionNote;
18282
+ note.textContent = detail ? !state?.canUpdate ? detail : `${detail} ${messages.harnessVersionNote}` : messages.harnessVersionNote;
17590
18283
  };
17591
18284
  const run = async (action) => {
17592
- if (busy || unsupported || signal.aborted) return;
17593
- if (action === "update" && (!state?.canUpdate || !state.updateAvailable)) return;
18285
+ if (busy || unsupported || signal.aborted) return false;
18286
+ if (action === "update" && (!state?.canUpdate || !state.updateAvailable)) return false;
17594
18287
  busy = true;
18288
+ updating = action === "update";
18289
+ onChange();
17595
18290
  status.textContent = action === "check" ? messages.harnessVersionChecking : messages.harnessVersionUpdating;
17596
18291
  render();
17597
18292
  try {
17598
18293
  const result = await client.run(action);
17599
- if (signal.aborted) return;
18294
+ if (signal.aborted) return false;
17600
18295
  state = result;
17601
18296
  status.textContent = !result.canUpdate ? messages.harnessVersionManual : action === "update" ? result.updateAvailable ? messages.harnessVersionFailed : messages.harnessVersionUpdated : "";
18297
+ return result.canUpdate && !result.updateAvailable;
17602
18298
  } catch (error51) {
17603
- if (signal.aborted) return;
18299
+ if (signal.aborted) return false;
17604
18300
  unsupported = typeof error51 === "object" && error51 !== null && "code" in error51 && (error51.code === -32601 || error51.code === -32078);
17605
18301
  status.textContent = unsupported ? messages.harnessVersionUnsupported : messages.harnessVersionFailed;
17606
18302
  if (state) state = { ...state, canUpdate: false };
18303
+ return false;
17607
18304
  } finally {
17608
18305
  busy = false;
17609
- if (!signal.aborted) render();
18306
+ updating = false;
18307
+ if (!signal.aborted) {
18308
+ render();
18309
+ onChange();
18310
+ }
17610
18311
  }
17611
18312
  };
17612
- update.addEventListener("click", () => void run("update"));
18313
+ const updateVersion = () => {
18314
+ updatePromise ??= run("update").finally(() => {
18315
+ updatePromise = null;
18316
+ });
18317
+ return updatePromise;
18318
+ };
18319
+ update.addEventListener("click", () => void updateVersion());
17613
18320
  const owner = document2.defaultView;
17614
18321
  let checkFrame = null;
17615
18322
  let checkTimer = null;
@@ -17636,7 +18343,95 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17636
18343
  } else {
17637
18344
  void run("check");
17638
18345
  }
17639
- return panel;
18346
+ return {
18347
+ element: panel,
18348
+ get state() {
18349
+ return state;
18350
+ },
18351
+ get updating() {
18352
+ return updating;
18353
+ },
18354
+ update: updateVersion
18355
+ };
18356
+ }
18357
+
18358
+ // src/settings/connection-versions.ts
18359
+ function createConnectionVersions(document2, messages, signal, diagnostics, onChange) {
18360
+ const panels = /* @__PURE__ */ new Map();
18361
+ const installation = diagnostics?.installation?.bind(diagnostics);
18362
+ return {
18363
+ get(hostId2, agent) {
18364
+ if (!installation || signal.aborted) return void 0;
18365
+ const key = JSON.stringify([hostId2, agent]);
18366
+ let panel = panels.get(key);
18367
+ if (!panel) {
18368
+ panel = createHarnessVersionPanel(
18369
+ document2,
18370
+ messages,
18371
+ signal,
18372
+ agent,
18373
+ {
18374
+ run: (action) => installation(hostId2, agent, action)
18375
+ },
18376
+ onChange
18377
+ );
18378
+ panels.set(key, panel);
18379
+ }
18380
+ return panel;
18381
+ }
18382
+ };
18383
+ }
18384
+
18385
+ // src/settings/connection-updates.ts
18386
+ function createConnectionUpdates(document2, messages, signal, onChange) {
18387
+ const batches = /* @__PURE__ */ new Map();
18388
+ const eligible = (panels) => panels.filter((panel) => panel.state?.updateAvailable && panel.state.canUpdate);
18389
+ const start = async (hostId2, panels) => {
18390
+ if (signal.aborted || batches.get(hostId2)?.running) return;
18391
+ const targets = eligible(panels);
18392
+ if (!targets.length) return;
18393
+ const batch = { running: true, total: targets.length, succeeded: 0, failed: 0 };
18394
+ batches.set(hostId2, batch);
18395
+ onChange();
18396
+ await Promise.all(
18397
+ targets.map(async (panel) => {
18398
+ try {
18399
+ if (await panel.update()) batch.succeeded++;
18400
+ else batch.failed++;
18401
+ } catch {
18402
+ batch.failed++;
18403
+ }
18404
+ if (!signal.aborted) onChange();
18405
+ })
18406
+ );
18407
+ batch.running = false;
18408
+ if (!signal.aborted) onChange();
18409
+ };
18410
+ return {
18411
+ createControls(hostId2, panels) {
18412
+ const batch = batches.get(hostId2);
18413
+ const count3 = eligible(panels).length;
18414
+ const button2 = document2.createElement("button");
18415
+ button2.type = "button";
18416
+ button2.className = "settings-command-button settings-command-button--secondary settings-connection-update-all";
18417
+ button2.dataset.connectionAction = "update-all";
18418
+ button2.disabled = signal.aborted || Boolean(batch?.running) || !count3;
18419
+ button2.title = messages.harnessUpdateAllDescription;
18420
+ const label = batch?.running ? `${messages.harnessUpdateAllProgress} ${batch.succeeded + batch.failed}/${batch.total}` : count3 ? `${messages.harnessUpdateAll} (${count3})` : messages.harnessUpdateAll;
18421
+ button2.append(createRendererSettingsIcon("download", 15), label);
18422
+ button2.addEventListener("click", () => {
18423
+ if (!button2.disabled) void start(hostId2, panels);
18424
+ });
18425
+ const result = document2.createElement("p");
18426
+ result.className = "settings-connection-update-result";
18427
+ result.setAttribute("role", "status");
18428
+ result.hidden = !batch || batch.running;
18429
+ if (batch && !batch.running) {
18430
+ result.textContent = messages.harnessUpdateAllResult.replace("{succeeded}", String(batch.succeeded)).replace("{failed}", String(batch.failed));
18431
+ }
18432
+ return { button: button2, result };
18433
+ }
18434
+ };
17640
18435
  }
17641
18436
 
17642
18437
  // src/settings/connections-page.ts
@@ -17804,6 +18599,7 @@ ${error51.stderrTail}`] : []
17804
18599
  status.dataset.connectionTone = connectionStatusTone(item.availability, item.error !== null);
17805
18600
  status.setAttribute("role", "cell");
17806
18601
  status.textContent = item.error?.code === "authenticationRequired" ? messages.connectionLoginRequired : item.error?.code === "configurationRequired" ? messages.connectionConfigurationRequired : connectionStatusLabel(item.availability, messages, item.error !== null);
18602
+ const version2 = item.version;
17807
18603
  const action = document2.createElement("div");
17808
18604
  action.className = "settings-connection-row__action";
17809
18605
  action.setAttribute("role", "cell");
@@ -17833,6 +18629,31 @@ ${error51.stderrTail}`] : []
17833
18629
  });
17834
18630
  action.append(viewError);
17835
18631
  }
18632
+ if (version2?.state?.updateAvailable && !version2.updating) {
18633
+ const available = document2.createElement("span");
18634
+ available.className = "settings-connection-version-available";
18635
+ available.textContent = messages.harnessVersionAvailable;
18636
+ available.title = `${messages.harnessVersionCurrent}: ${version2.state.currentVersion ?? "\u2014"}
18637
+ ${messages.harnessVersionLatest}: ${harnessVersionLabel(version2.state, messages.harnessVersion)}`;
18638
+ action.append(available);
18639
+ }
18640
+ if (version2?.state?.updateAvailable && version2.state.canUpdate) {
18641
+ const update = document2.createElement("button");
18642
+ update.type = "button";
18643
+ update.className = "settings-connection-install-link";
18644
+ update.dataset.connectionAction = "update";
18645
+ update.disabled = version2.updating;
18646
+ update.title = messages.harnessVersionUpdate;
18647
+ update.setAttribute("aria-label", `${messages.harnessVersionUpdate}: ${item.name}`);
18648
+ update.append(createRendererSettingsIcon("download", 17));
18649
+ update.addEventListener("click", (event) => {
18650
+ event.stopPropagation();
18651
+ if (update.disabled) return;
18652
+ void version2.update();
18653
+ select();
18654
+ });
18655
+ action.append(update);
18656
+ }
17836
18657
  if (group) {
17837
18658
  const toggle = document2.createElement("button");
17838
18659
  toggle.type = "button";
@@ -18124,8 +18945,6 @@ ${error51.stderrTail}`] : []
18124
18945
  let selectedHostId = null;
18125
18946
  let selectedItemKey = null;
18126
18947
  let launchControls = null;
18127
- const versionPanels = /* @__PURE__ */ new Map();
18128
- const updatingVersions = /* @__PURE__ */ new Set();
18129
18948
  const hostNames = /* @__PURE__ */ new Map();
18130
18949
  let latestSnapshot = null;
18131
18950
  let disposeHostScroller = () => void 0;
@@ -18154,7 +18973,15 @@ ${error51.stderrTail}`] : []
18154
18973
  renderFrame = null;
18155
18974
  };
18156
18975
  const diagnostics = getDiagnostics();
18976
+ const versions = createConnectionVersions(
18977
+ document2,
18978
+ messages,
18979
+ context.signal,
18980
+ diagnostics,
18981
+ scheduleRender
18982
+ );
18157
18983
  const installs = diagnostics ? harnessInstallStore(diagnostics) : null;
18984
+ const updates = createConnectionUpdates(document2, messages, context.signal, scheduleRender);
18158
18985
  const runRefresh = () => {
18159
18986
  if (pending || !diagnostics) return;
18160
18987
  pending = true;
@@ -18290,10 +19117,13 @@ ${error51.stderrTail}`] : []
18290
19117
  const agent = item.agentSnapshot?.agent;
18291
19118
  if (!agent) return item;
18292
19119
  const state = installs?.get(selectedHost.hostId, agent);
19120
+ const availability = state?.status ?? item.availability;
19121
+ const version2 = item.agentSnapshot?.availability !== "notInstalled" && availability !== "installing" && availability !== "checking" ? versions.get(selectedHost.hostId, agent) : void 0;
18293
19122
  return {
18294
19123
  ...item,
18295
19124
  ...state ? { availability: state.status } : {},
18296
- ...updatingVersions.has(JSON.stringify([selectedHost.hostId, agent])) ? { availability: "updating" } : {},
19125
+ ...version2 ? { version: version2 } : {},
19126
+ ...version2?.updating ? { availability: "updating" } : {},
18297
19127
  ...state?.error ? { installError: state.error } : {},
18298
19128
  ...diagnostics?.installation && harnessHasInstallCommands(item.agentSnapshot?.plugin) ? {
18299
19129
  install: () => {
@@ -18330,30 +19160,7 @@ ${error51.stderrTail}`] : []
18330
19160
  runRefresh
18331
19161
  );
18332
19162
  launchControls = { hostId: selectedHost.hostId, itemKey: item.key, element };
18333
- const agent = item.agentSnapshot?.agent;
18334
- const installation = diagnostics?.installation?.bind(diagnostics);
18335
- if (agent && item.agentSnapshot?.availability !== "notInstalled" && item.availability !== "installing" && item.availability !== "checking" && installation) {
18336
- const key = JSON.stringify([selectedHost.hostId, agent]);
18337
- let panel = versionPanels.get(key);
18338
- if (!panel) {
18339
- const hostId2 = selectedHost.hostId;
18340
- panel = createHarnessVersionPanel(document2, messages, context.signal, agent, {
18341
- async run(action) {
18342
- if (action !== "update") return installation(hostId2, agent, action);
18343
- updatingVersions.add(key);
18344
- if (diagnostics) render(diagnostics.snapshot());
18345
- try {
18346
- return await installation(hostId2, agent, action);
18347
- } finally {
18348
- updatingVersions.delete(key);
18349
- if (!context.signal.aborted && diagnostics) render(diagnostics.snapshot());
18350
- }
18351
- }
18352
- });
18353
- versionPanels.set(key, panel);
18354
- }
18355
- inspector.append(panel);
18356
- }
19163
+ if (item.version) inspector.append(item.version.element);
18357
19164
  };
18358
19165
  const pinnedItem = items.find((item) => item.key === "renderer-adapter");
18359
19166
  if (pinnedItem) {
@@ -18509,7 +19316,14 @@ ${error51.stderrTail}`] : []
18509
19316
  }
18510
19317
  const selectedItem = items.find((item) => item.key === selectedItemKey) ?? items[0];
18511
19318
  if (selectedItem) selectItem(selectedItem);
18512
- list.append(hostStrip, tableHeader, rows);
19319
+ const updateControls = updates.createControls(
19320
+ selectedHost.hostId,
19321
+ items.flatMap((item) => item.version ? [item.version] : [])
19322
+ );
19323
+ const hostHeader = document2.createElement("div");
19324
+ hostHeader.className = "settings-connection-host-header";
19325
+ hostHeader.append(hostStrip, updateControls.button);
19326
+ list.append(hostHeader, updateControls.result, tableHeader, rows);
18513
19327
  layout.append(list, inspector);
18514
19328
  content.replaceChildren(layout);
18515
19329
  disposeHostScroller = configureHostScroller(
@@ -18696,12 +19510,13 @@ ${error51.stderrTail}`] : []
18696
19510
  notAvailable: "Not available",
18697
19511
  runtimeCapabilityNotInstalled: "This runtime capability is not installed yet.",
18698
19512
  sessionImportHarness: "Harness",
19513
+ sessionImportSelectHost: "Select the Host to import sessions from",
18699
19514
  sessionImportDescription: "Sessions keep their original project path. If a folder is not in the Codex sidebar, add it as a project first. Original history remains managed by the Harness.",
18700
- sessionImportAvailabilityNote: "Available Harnesses come from the local Host. If activity is unknown, close the session in its native client before importing to avoid concurrent writes.",
19515
+ sessionImportAvailabilityNote: "Available Harnesses come from the selected Host. If activity is unknown, close the session in its native client before importing to avoid concurrent writes.",
18701
19516
  sessionImportRefresh: "Refresh",
18702
- sessionImportRefreshing: "Loading local sessions...",
18703
- sessionImportUnavailable: "Session import is unavailable for this local Harness or its current protocol. Update the Host/plugin or choose another Harness.",
18704
- sessionImportEmpty: "No local sessions are available to import.",
19517
+ sessionImportRefreshing: "Loading sessions from the selected Host...",
19518
+ sessionImportUnavailable: "Session import is unavailable for this Harness or the selected Host protocol. Update the Host/plugin or choose another Harness.",
19519
+ sessionImportEmpty: "No sessions are available to import on the selected Host.",
18705
19520
  sessionImportSearch: "Search",
18706
19521
  sessionImportSearchPlaceholder: "Search titles, session IDs or project paths",
18707
19522
  sessionImportNoMatches: "No sessions match your search.",
@@ -18709,7 +19524,7 @@ ${error51.stderrTail}`] : []
18709
19524
  sessionImportPrevious: "Previous",
18710
19525
  sessionImportNext: "Next",
18711
19526
  sessionImportPageSummary: "Page {page} of {pages} \xB7 {total} sessions",
18712
- sessionImportLoadFailed: "Local sessions could not be loaded. Check directory access or duplicate session IDs, then retry.",
19527
+ sessionImportLoadFailed: "Sessions could not be loaded from the selected Host. Check directory access or duplicate session IDs, then retry.",
18713
19528
  sessionImportFailed: "The session could not be imported.",
18714
19529
  sessionImportUntitled: "Untitled session",
18715
19530
  sessionImportUpdatedAt: "Updated",
@@ -18814,10 +19629,17 @@ ${error51.stderrTail}`] : []
18814
19629
  connectionInstallRunning: "Installing on the selected Host. You can leave this page; login or setup may still be required afterward.",
18815
19630
  harnessVersion: harnessVersionEnglish,
18816
19631
  harnessVersionTitle: "Harness CLI version",
19632
+ harnessVersionApplicationTitle: "Application version",
18817
19633
  harnessVersionCurrent: "Current version",
18818
19634
  harnessVersionLatest: "Latest version",
18819
19635
  harnessVersionChecking: "Checking versions\u2026",
19636
+ harnessVersionAvailable: "Update available",
18820
19637
  harnessVersionUpdate: "Update",
19638
+ harnessVersionDownloadUpdate: "Download update",
19639
+ harnessUpdateAll: "Update all",
19640
+ harnessUpdateAllProgress: "Updating",
19641
+ harnessUpdateAllDescription: "Update all eligible Harnesses on the selected Host.",
19642
+ harnessUpdateAllResult: "Updated {succeeded}; failed {failed}.",
18821
19643
  harnessVersionUpdating: "Updating\u2026",
18822
19644
  harnessVersionUpToDate: "Up to date",
18823
19645
  harnessVersionUpdated: "Update verified. New sessions will use the new version.",
@@ -18969,12 +19791,13 @@ ${error51.stderrTail}`] : []
18969
19791
  notAvailable: "\u6682\u4E0D\u53EF\u7528",
18970
19792
  runtimeCapabilityNotInstalled: "\u8FD0\u884C\u65F6\u5C1A\u672A\u5B89\u88C5\u8BE5\u9879\u80FD\u529B\uFF0C\u56E0\u6B64\u6682\u4E0D\u53EF\u7528\u3002",
18971
19793
  sessionImportHarness: "Harness",
19794
+ sessionImportSelectHost: "\u8BF7\u9009\u62E9\u8981\u5BFC\u5165\u4F1A\u8BDD\u7684 Host",
18972
19795
  sessionImportDescription: "\u4F1A\u8BDD\u5C06\u4FDD\u7559\u539F\u59CB\u9879\u76EE\u8DEF\u5F84\uFF1B\u82E5\u8BE5\u6587\u4EF6\u5939\u5C1A\u672A\u51FA\u73B0\u5728 Codex \u4FA7\u680F\uFF0C\u8BF7\u5148\u5C06\u5176\u6DFB\u52A0\u4E3A\u9879\u76EE\u3002\u539F\u59CB\u5386\u53F2\u4ECD\u7531 Harness \u7BA1\u7406\u3002",
18973
- sessionImportAvailabilityNote: "\u53EF\u9009 Harness \u6765\u81EA\u672C\u5730 Host\u3002\u8FD0\u884C\u72B6\u6001\u672A\u77E5\u65F6\uFF0C\u8BF7\u5148\u5728\u539F\u751F\u5BA2\u6237\u7AEF\u5173\u95ED\u8BE5\u4F1A\u8BDD\u518D\u5BFC\u5165\uFF0C\u907F\u514D\u540C\u65F6\u5199\u5165\u3002",
19796
+ sessionImportAvailabilityNote: "\u53EF\u9009 Harness \u6765\u81EA\u5F53\u524D Host\u3002\u8FD0\u884C\u72B6\u6001\u672A\u77E5\u65F6\uFF0C\u8BF7\u5148\u5728\u539F\u751F\u5BA2\u6237\u7AEF\u5173\u95ED\u8BE5\u4F1A\u8BDD\u518D\u5BFC\u5165\uFF0C\u907F\u514D\u540C\u65F6\u5199\u5165\u3002",
18974
19797
  sessionImportRefresh: "\u5237\u65B0",
18975
- sessionImportRefreshing: "\u6B63\u5728\u8BFB\u53D6\u672C\u5730\u4F1A\u8BDD\u2026\u2026",
18976
- sessionImportUnavailable: "\u672C\u5730 Harness \u6216\u5F53\u524D\u534F\u8BAE\u6682\u4E0D\u652F\u6301\u4F1A\u8BDD\u5BFC\u5165\uFF0C\u8BF7\u66F4\u65B0 Host/\u63D2\u4EF6\u6216\u9009\u62E9\u5176\u4ED6 Harness\u3002",
18977
- sessionImportEmpty: "\u6CA1\u6709\u53EF\u5BFC\u5165\u7684\u672C\u5730\u4F1A\u8BDD\u3002",
19798
+ sessionImportRefreshing: "\u6B63\u5728\u8BFB\u53D6\u5F53\u524D Host \u4E0A\u7684\u4F1A\u8BDD\u2026\u2026",
19799
+ sessionImportUnavailable: "\u8BE5 Harness \u6216\u5F53\u524D Host \u534F\u8BAE\u6682\u4E0D\u652F\u6301\u4F1A\u8BDD\u5BFC\u5165\uFF0C\u8BF7\u66F4\u65B0 Host/\u63D2\u4EF6\u6216\u9009\u62E9\u5176\u4ED6 Harness\u3002",
19800
+ sessionImportEmpty: "\u5F53\u524D Host \u4E0A\u6CA1\u6709\u53EF\u5BFC\u5165\u7684\u4F1A\u8BDD\u3002",
18978
19801
  sessionImportSearch: "\u641C\u7D22",
18979
19802
  sessionImportSearchPlaceholder: "\u641C\u7D22\u6807\u9898\u3001\u4F1A\u8BDD ID \u6216\u9879\u76EE\u8DEF\u5F84",
18980
19803
  sessionImportNoMatches: "\u6CA1\u6709\u5339\u914D\u7684\u4F1A\u8BDD\u3002",
@@ -18982,7 +19805,7 @@ ${error51.stderrTail}`] : []
18982
19805
  sessionImportPrevious: "\u4E0A\u4E00\u9875",
18983
19806
  sessionImportNext: "\u4E0B\u4E00\u9875",
18984
19807
  sessionImportPageSummary: "\u7B2C {page} / {pages} \u9875 \xB7 \u5171 {total} \u6761",
18985
- sessionImportLoadFailed: "\u65E0\u6CD5\u8BFB\u53D6\u672C\u5730\u4F1A\u8BDD\uFF0C\u8BF7\u68C0\u67E5\u76EE\u5F55\u8BBF\u95EE\u6743\u9650\u6216\u91CD\u590D\u7684\u4F1A\u8BDD ID \u540E\u91CD\u8BD5\u3002",
19808
+ sessionImportLoadFailed: "\u65E0\u6CD5\u8BFB\u53D6\u5F53\u524D Host \u4E0A\u7684\u4F1A\u8BDD\uFF0C\u8BF7\u68C0\u67E5\u76EE\u5F55\u8BBF\u95EE\u6743\u9650\u6216\u91CD\u590D\u7684\u4F1A\u8BDD ID \u540E\u91CD\u8BD5\u3002",
18986
19809
  sessionImportFailed: "\u65E0\u6CD5\u5BFC\u5165\u8BE5\u4F1A\u8BDD\u3002",
18987
19810
  sessionImportUntitled: "\u672A\u547D\u540D\u4F1A\u8BDD",
18988
19811
  sessionImportUpdatedAt: "\u66F4\u65B0\u65F6\u95F4",
@@ -19087,10 +19910,17 @@ ${error51.stderrTail}`] : []
19087
19910
  connectionInstallRunning: "\u6B63\u5728\u6240\u9009 Host \u4E0A\u5B89\u88C5\uFF0C\u79BB\u5F00\u9875\u9762\u4E0D\u4F1A\u4E2D\u65AD\u3002\u5B89\u88C5\u540E\u53EF\u80FD\u4ECD\u9700\u767B\u5F55\u6216\u914D\u7F6E\u3002",
19088
19911
  harnessVersion: harnessVersionChinese,
19089
19912
  harnessVersionTitle: "Harness CLI \u7248\u672C",
19913
+ harnessVersionApplicationTitle: "\u5E94\u7528\u7248\u672C",
19090
19914
  harnessVersionCurrent: "\u5F53\u524D\u7248\u672C",
19091
19915
  harnessVersionLatest: "\u6700\u65B0\u7248\u672C",
19092
19916
  harnessVersionChecking: "\u6B63\u5728\u68C0\u67E5\u7248\u672C\u2026",
19917
+ harnessVersionAvailable: "\u6709\u66F4\u65B0",
19093
19918
  harnessVersionUpdate: "\u66F4\u65B0",
19919
+ harnessVersionDownloadUpdate: "\u4E0B\u8F7D\u66F4\u65B0",
19920
+ harnessUpdateAll: "\u5168\u90E8\u66F4\u65B0",
19921
+ harnessUpdateAllProgress: "\u66F4\u65B0\u4E2D",
19922
+ harnessUpdateAllDescription: "\u66F4\u65B0\u5F53\u524D Host \u4E0A\u652F\u6301\u81EA\u52A8\u66F4\u65B0\u4E14\u6709\u65B0\u7248\u672C\u7684 Harness\u3002",
19923
+ harnessUpdateAllResult: "\u5DF2\u66F4\u65B0 {succeeded} \u9879\uFF0C{failed} \u9879\u5931\u8D25\u3002",
19094
19924
  harnessVersionUpdating: "\u6B63\u5728\u66F4\u65B0\u2026",
19095
19925
  harnessVersionUpToDate: "\u5DF2\u662F\u6700\u65B0",
19096
19926
  harnessVersionUpdated: "\u5DF2\u786E\u8BA4\u66F4\u65B0\u6210\u529F\uFF0C\u65B0\u4F1A\u8BDD\u5C06\u4F7F\u7528\u65B0\u7248\u672C\u3002",
@@ -19803,6 +20633,8 @@ ${error51.stderrTail}`] : []
19803
20633
  var STYLE_ATTRIBUTE = "data-codexhost-trigger-chip-style";
19804
20634
  var TRIGGER_CHIP_CLASS = "codexhost-trigger-chip";
19805
20635
  var TRIGGER_CHIP_ROOT_CLASS = "codexhost-trigger-chip-root";
20636
+ var COMPACT_COMPOSER_ATTRIBUTE = "data-codexhost-compact-composer";
20637
+ var COMPACT_COMPOSER_WIDTH = 420;
19806
20638
  var TRIGGER_CHIP_SQUEEZE_MIN_WIDTH = "48px";
19807
20639
  function rendererModelTriggerMaxWidth() {
19808
20640
  return "min(200px, 26vw)";
@@ -19832,6 +20664,23 @@ ${error51.stderrTail}`] : []
19832
20664
  trigger.style.maxWidth = "100%";
19833
20665
  trigger.style.overflow = "hidden";
19834
20666
  }
20667
+ function observeRendererCompactComposer(composer) {
20668
+ const update = () => {
20669
+ const width = composer.getBoundingClientRect().width;
20670
+ if (width > 0) {
20671
+ composer.toggleAttribute(COMPACT_COMPOSER_ATTRIBUTE, width <= COMPACT_COMPOSER_WIDTH);
20672
+ }
20673
+ };
20674
+ update();
20675
+ if (typeof ResizeObserver === "undefined")
20676
+ return () => composer.removeAttribute(COMPACT_COMPOSER_ATTRIBUTE);
20677
+ const observer = new ResizeObserver(update);
20678
+ observer.observe(composer, { box: "border-box" });
20679
+ return () => {
20680
+ observer.disconnect();
20681
+ composer.removeAttribute(COMPACT_COMPOSER_ATTRIBUTE);
20682
+ };
20683
+ }
19835
20684
  function ensureRendererTriggerChipStyle(ownerDocument) {
19836
20685
  if (ownerDocument.querySelector(`style[${STYLE_ATTRIBUTE}]`)) return;
19837
20686
  const style = ownerDocument.createElement("style");
@@ -19870,10 +20719,55 @@ ${error51.stderrTail}`] : []
19870
20719
  cursor: not-allowed;
19871
20720
  opacity: 0.4;
19872
20721
  }
20722
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-model-control] [data-codexhost-model-thinking] {
20723
+ display: none !important;
20724
+ }
20725
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-permission-mode-control] {
20726
+ min-width: 30px !important;
20727
+ max-width: 30px !important;
20728
+ }
20729
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-permission-mode-control] .${TRIGGER_CHIP_CLASS} {
20730
+ padding-inline: 6px !important;
20731
+ }
20732
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-permission-label],
20733
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-permission-chevron],
20734
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-credits-label],
20735
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-usage-label] {
20736
+ display: none !important;
20737
+ }
20738
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-permission-mode-control]:has([data-codexhost-permission-lock]:not([hidden])) [data-codexhost-permission-shield],
20739
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-permission-mode-control]:has([data-codexhost-permission-error]:not([hidden])) [data-codexhost-permission-shield] {
20740
+ display: none !important;
20741
+ }
20742
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-credits-control],
20743
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-usage-control] {
20744
+ min-width: 28px !important;
20745
+ max-width: 28px !important;
20746
+ }
20747
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-credits-control] .${TRIGGER_CHIP_CLASS},
20748
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-usage-control] .${TRIGGER_CHIP_CLASS} {
20749
+ padding-inline: 6px !important;
20750
+ }
20751
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-usage-icon] {
20752
+ display: inline-flex !important;
20753
+ }
20754
+ [${COMPACT_COMPOSER_ATTRIBUTE}] [data-codexhost-agent-control] {
20755
+ margin-inline: 0 !important;
20756
+ }
19873
20757
  `;
19874
20758
  (ownerDocument.head ?? ownerDocument.documentElement).append(style);
19875
20759
  }
19876
20760
 
20761
+ // ../../node_modules/lucide/dist/esm/icons/activity.mjs
20762
+ var Activity = [
20763
+ [
20764
+ "path",
20765
+ {
20766
+ d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"
20767
+ }
20768
+ ]
20769
+ ];
20770
+
19877
20771
  // src/renderer-usage-control.ts
19878
20772
  var ENGLISH_USAGE_MESSAGES = Object.freeze({
19879
20773
  usage: "Usage",
@@ -20227,13 +21121,19 @@ ${error51.stderrTail}`] : []
20227
21121
  trigger.style.lineHeight = "16px";
20228
21122
  trigger.style.fontVariantNumeric = "tabular-nums";
20229
21123
  trigger.style.letterSpacing = "0";
21124
+ const icon2 = document.createElement("span");
21125
+ icon2.dataset.codexhostUsageIcon = "";
21126
+ icon2.style.display = "none";
21127
+ icon2.style.alignItems = "center";
21128
+ icon2.append(createElement(Activity, { width: 16, height: 16, "aria-hidden": "true" }));
20230
21129
  const label = document.createElement("span");
21130
+ label.dataset.codexhostUsageLabel = "";
20231
21131
  label.style.display = "inline-block";
20232
21132
  label.style.maxWidth = "100%";
20233
21133
  label.style.overflow = "hidden";
20234
21134
  label.style.textOverflow = "ellipsis";
20235
21135
  label.style.whiteSpace = "nowrap";
20236
- trigger.append(label);
21136
+ trigger.append(icon2, label);
20237
21137
  const popover = document.createElement("div");
20238
21138
  popover.id = `${composerId}-usage-popover`;
20239
21139
  popover.setAttribute("role", "dialog");
@@ -21099,6 +21999,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
21099
21999
  label.style.textOverflow = "ellipsis";
21100
22000
  label.style.whiteSpace = "nowrap";
21101
22001
  const thinkingLabel = document.createElement("span");
22002
+ thinkingLabel.dataset.codexhostModelThinking = "";
21102
22003
  thinkingLabel.style.color = "var(--color-text-tertiary, #8f8f8f)";
21103
22004
  thinkingLabel.style.flex = "0 1 auto";
21104
22005
  thinkingLabel.style.maxWidth = "72px";
@@ -21544,9 +22445,6 @@ Codex Fast mode prioritizes requests and may increase usage.`
21544
22445
  syncModelSelectionNotice(control, view, locale);
21545
22446
  }
21546
22447
 
21547
- // ../../node_modules/lucide/dist/esm/icons/check.mjs
21548
- var Check = [["path", { d: "M20 6 9 17l-5-5" }]];
21549
-
21550
22448
  // ../../node_modules/lucide/dist/esm/icons/lock.mjs
21551
22449
  var Lock = [
21552
22450
  ["rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2" }],
@@ -21661,9 +22559,11 @@ Codex Fast mode prioritizes requests and may increase usage.`
21661
22559
  trigger.className = TRIGGER_CHIP_CLASS;
21662
22560
  applyRendererTriggerChipSqueezeTrigger(trigger);
21663
22561
  const shield = document.createElement("span");
22562
+ shield.dataset.codexhostPermissionShield = "";
21664
22563
  shield.className = "inline-flex shrink-0 items-center";
21665
22564
  shield.append(icon(Shield, 15));
21666
22565
  const label = document.createElement("span");
22566
+ label.dataset.codexhostPermissionLabel = "";
21667
22567
  label.className = "truncate";
21668
22568
  label.style.flex = "1 1 auto";
21669
22569
  label.style.minWidth = "0";
@@ -21671,15 +22571,18 @@ Codex Fast mode prioritizes requests and may increase usage.`
21671
22571
  label.style.textOverflow = "ellipsis";
21672
22572
  label.style.whiteSpace = "nowrap";
21673
22573
  const chevron = document.createElement("span");
22574
+ chevron.dataset.codexhostPermissionChevron = "";
21674
22575
  chevron.className = "inline-flex shrink-0 items-center";
21675
22576
  chevron.style.color = "var(--color-text-tertiary, #8f8f8f)";
21676
22577
  chevron.append(icon(ChevronDown, 14));
21677
22578
  const lockMark = document.createElement("span");
22579
+ lockMark.dataset.codexhostPermissionLock = "";
21678
22580
  lockMark.className = "inline-flex shrink-0 items-center";
21679
22581
  lockMark.style.color = "var(--color-text-tertiary, #8f8f8f)";
21680
22582
  lockMark.hidden = true;
21681
22583
  lockMark.append(icon(Lock, 14));
21682
22584
  const errorMark = document.createElement("span");
22585
+ errorMark.dataset.codexhostPermissionError = "";
21683
22586
  errorMark.className = "inline-flex shrink-0 items-center";
21684
22587
  errorMark.style.color = "var(--color-text-danger, #c2413b)";
21685
22588
  errorMark.hidden = true;
@@ -22236,7 +23139,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22236
23139
  })
22237
23140
  );
22238
23141
  }
22239
- if (label) label.textContent = percent2;
23142
+ if (label) label.textContent = `${Math.round(remaining)}%`;
22240
23143
  control.root.style.display = "inline-flex";
22241
23144
  control.trigger.setAttribute("aria-label", title);
22242
23145
  control.trigger.title = title;
@@ -22244,6 +23147,163 @@ Codex Fast mode prioritizes requests and may increase usage.`
22244
23147
  return true;
22245
23148
  }
22246
23149
 
23150
+ // src/renderer-composer-indicators.ts
23151
+ var SHOW_WITHIN_SECONDS = 50 * 60;
23152
+ function mountRendererComposerIndicators(composer) {
23153
+ const doc = composer.ownerDocument;
23154
+ ensureRendererTriggerChipStyle(doc);
23155
+ const root = doc.createElement("div");
23156
+ root.setAttribute("data-codexhost-composer-indicators", "true");
23157
+ applyRendererTriggerChipSqueezeRoot(root, "128px", "0");
23158
+ Object.assign(root.style, { alignItems: "center", gap: "2px", flexShrink: "100000" });
23159
+ let indicators = [];
23160
+ let locale = "en";
23161
+ let timer;
23162
+ let anchor = null;
23163
+ let contentKey = "";
23164
+ let tip = null;
23165
+ const hideTip = () => {
23166
+ tip?.remove();
23167
+ tip = null;
23168
+ };
23169
+ const showTip = (chip, textContent) => {
23170
+ hideTip();
23171
+ const el = doc.createElement("div");
23172
+ el.setAttribute("role", "tooltip");
23173
+ el.textContent = textContent;
23174
+ Object.assign(el.style, {
23175
+ position: "fixed",
23176
+ zIndex: "2147483647",
23177
+ pointerEvents: "none",
23178
+ padding: "4px 8px",
23179
+ borderRadius: "8px",
23180
+ fontSize: "12px",
23181
+ whiteSpace: "nowrap",
23182
+ background: "rgba(30, 30, 30, 0.92)",
23183
+ color: "#fff",
23184
+ visibility: "hidden"
23185
+ });
23186
+ (doc.body ?? doc.documentElement).append(el);
23187
+ const rect = chip.getBoundingClientRect();
23188
+ const width = el.offsetWidth;
23189
+ const left = Math.max(
23190
+ 4,
23191
+ Math.min(rect.left + rect.width / 2 - width / 2, window.innerWidth - width - 4)
23192
+ );
23193
+ el.style.left = `${left}px`;
23194
+ el.style.top = `${Math.max(4, rect.top - el.offsetHeight - 6)}px`;
23195
+ el.style.visibility = "visible";
23196
+ tip = el;
23197
+ };
23198
+ const refresh = () => {
23199
+ const now = Date.now() / 1e3;
23200
+ const active = indicators.filter(
23201
+ (indicator) => indicator.expiresAtUnix > now && indicator.expiresAtUnix - now <= SHOW_WITHIN_SECONDS
23202
+ );
23203
+ const nextKey = JSON.stringify([
23204
+ locale,
23205
+ active.map((indicator) => [indicator, Math.ceil((indicator.expiresAtUnix - now) / 60)])
23206
+ ]);
23207
+ if (nextKey !== contentKey) {
23208
+ contentKey = nextKey;
23209
+ hideTip();
23210
+ root.replaceChildren();
23211
+ for (const indicator of active) {
23212
+ const minutes = Math.ceil((indicator.expiresAtUnix - now) / 60);
23213
+ const remaining = locale === "zh-CN" ? `\u5269\u4F59 ${minutes} \u5206\u949F` : `${minutes}m remaining`;
23214
+ const label = indicator.label ? localizeHarnessText(indicator.label, locale) : "";
23215
+ const tooltip = indicator.tooltip ? localizeHarnessText(indicator.tooltip, locale) : "";
23216
+ const chip = doc.createElement("span");
23217
+ chip.className = TRIGGER_CHIP_CLASS;
23218
+ chip.setAttribute("data-indicator-id", indicator.id);
23219
+ const summary = [label, tooltip, remaining].filter(Boolean).join(" \xB7 ");
23220
+ chip.setAttribute("aria-label", summary);
23221
+ chip.addEventListener("mouseenter", () => showTip(chip, summary));
23222
+ chip.addEventListener("mouseleave", hideTip);
23223
+ Object.assign(chip.style, {
23224
+ height: "28px",
23225
+ padding: "0 6px",
23226
+ gap: "4px",
23227
+ fontSize: "12px",
23228
+ cursor: "default",
23229
+ flexShrink: "0"
23230
+ });
23231
+ const icon2 = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
23232
+ icon2.setAttribute("viewBox", "0 0 24 24");
23233
+ icon2.setAttribute("width", "14");
23234
+ icon2.setAttribute("height", "14");
23235
+ icon2.setAttribute("fill", "none");
23236
+ icon2.setAttribute("stroke", "currentColor");
23237
+ icon2.setAttribute("stroke-width", "1.5");
23238
+ icon2.setAttribute("aria-hidden", "true");
23239
+ const path = doc.createElementNS("http://www.w3.org/2000/svg", "path");
23240
+ path.setAttribute("d", "M12 8v4l3 2M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0");
23241
+ icon2.append(path);
23242
+ const text = doc.createElement("span");
23243
+ text.textContent = `${minutes}m`;
23244
+ chip.append(icon2, text);
23245
+ root.append(chip);
23246
+ }
23247
+ }
23248
+ const visible = active.length > 0 && anchor !== null;
23249
+ if (root.hidden === visible) root.hidden = !visible;
23250
+ const display = visible ? "inline-flex" : "none";
23251
+ if (root.style.display !== display) root.style.display = display;
23252
+ const visibility = root.scrollWidth > root.clientWidth ? "hidden" : "visible";
23253
+ if (root.style.visibility !== visibility) root.style.visibility = visibility;
23254
+ const pending = indicators.some(({ expiresAtUnix }) => expiresAtUnix > now);
23255
+ if (!pending && timer !== void 0) {
23256
+ clearInterval(timer);
23257
+ timer = void 0;
23258
+ }
23259
+ };
23260
+ const observer = new ResizeObserver(refresh);
23261
+ observer.observe(root);
23262
+ refresh();
23263
+ return {
23264
+ root,
23265
+ place(next) {
23266
+ anchor = next;
23267
+ if (!next?.parentElement) {
23268
+ anchor = null;
23269
+ root.remove();
23270
+ } else if (next.nextElementSibling !== root) {
23271
+ next.parentElement.insertBefore(root, next.nextSibling);
23272
+ }
23273
+ refresh();
23274
+ },
23275
+ render(next, nextLocale) {
23276
+ indicators = next;
23277
+ locale = nextLocale;
23278
+ refresh();
23279
+ if (timer === void 0 && indicators.some(({ expiresAtUnix }) => expiresAtUnix > Date.now() / 1e3)) {
23280
+ timer = setInterval(refresh, 6e4);
23281
+ }
23282
+ },
23283
+ dispose() {
23284
+ observer.disconnect();
23285
+ hideTip();
23286
+ if (timer !== void 0) clearInterval(timer);
23287
+ root.remove();
23288
+ }
23289
+ };
23290
+ }
23291
+
23292
+ // src/renderer-composer-request.ts
23293
+ var NATIVE_COMPOSER_REQUEST_ATTRIBUTES = [
23294
+ "data-codex-composer-request-navigation",
23295
+ "data-codex-composer-request"
23296
+ ];
23297
+ var NATIVE_REQUEST_SELECTOR = NATIVE_COMPOSER_REQUEST_ATTRIBUTES.map(
23298
+ (attribute) => `[${attribute}]`
23299
+ ).join(", ");
23300
+ function isNativeComposerRequest(element) {
23301
+ return element.closest(NATIVE_REQUEST_SELECTOR) !== null;
23302
+ }
23303
+ function hasNativeComposerRequest(composer) {
23304
+ return isNativeComposerRequest(composer) || composer.querySelector(NATIVE_REQUEST_SELECTOR) !== null;
23305
+ }
23306
+
22247
23307
  // src/renderer-harness-command-control.ts
22248
23308
  var CONTROL_ATTRIBUTE2 = "data-codexhost-harness-command-control";
22249
23309
  var SVG_NS2 = "http://www.w3.org/2000/svg";
@@ -22376,7 +23436,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22376
23436
  return controlDescription(button2);
22377
23437
  }
22378
23438
  function isOwnedRendererControl(element) {
22379
- return element.hasAttribute(CONTROL_ATTRIBUTE) || element.hasAttribute("data-codexhost-model-control") || element.hasAttribute("data-codexhost-permission-mode-control") || element.hasAttribute("data-codexhost-usage-control") || element.hasAttribute("data-codexhost-credits-control") || element.hasAttribute("data-codexhost-harness-command-control");
23439
+ return element.hasAttribute(CONTROL_ATTRIBUTE) || element.hasAttribute("data-codexhost-model-control") || element.hasAttribute("data-codexhost-permission-mode-control") || element.hasAttribute("data-codexhost-usage-control") || element.hasAttribute("data-codexhost-credits-control") || element.hasAttribute("data-codexhost-composer-indicators") || element.hasAttribute("data-codexhost-harness-command-control");
22380
23440
  }
22381
23441
  function isComposerSubmitButton(button2) {
22382
23442
  if (button2.type === "submit") return true;
@@ -22405,10 +23465,13 @@ Codex Fast mode prioritizes requests and may increase usage.`
22405
23465
  const buttons = [...element.querySelectorAll("button")];
22406
23466
  return buttons.length > 0 && buttons.every((button2) => isComposerTrailingActionButton(button2));
22407
23467
  }
23468
+ function composerButtonsWithin(root) {
23469
+ return [...root.querySelectorAll("button")].filter(
23470
+ (button2) => !isNativeComposerRequest(button2)
23471
+ );
23472
+ }
22408
23473
  function sendButtonWithin(root) {
22409
- return [...root.querySelectorAll("button")].find(
22410
- (button2) => isComposerSubmitButton(button2)
22411
- ) ?? null;
23474
+ return composerButtonsWithin(root).find(isComposerSubmitButton) ?? null;
22412
23475
  }
22413
23476
  function leftmostTrailingSibling(container, before) {
22414
23477
  for (const child of container.children) {
@@ -22451,7 +23514,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22451
23514
  }
22452
23515
  function composerForElement(element) {
22453
23516
  const composer = element.closest(CODEX_COMPOSER_SELECTOR);
22454
- return composer && !isOrbitComposer(composer) ? composer : null;
23517
+ return composer && !hasNativeComposerRequest(composer) && !isOrbitComposer(composer) ? composer : null;
22455
23518
  }
22456
23519
  function isRecord(value) {
22457
23520
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -22575,7 +23638,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22575
23638
  return root?.parentElement ? root : null;
22576
23639
  }
22577
23640
  function lastNativeButtonWithin(composer) {
22578
- const buttons = [...composer.querySelectorAll("button")];
23641
+ const buttons = composerButtonsWithin(composer);
22579
23642
  for (let index = buttons.length - 1; index >= 0; index -= 1) {
22580
23643
  const button2 = buttons[index];
22581
23644
  if (button2 && !isInsideOwnedRendererControl(button2, composer)) return button2;
@@ -22589,6 +23652,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22589
23652
  return false;
22590
23653
  }
22591
23654
  function refreshSendButton(control) {
23655
+ if (hasNativeComposerRequest(control.composer)) return null;
22592
23656
  const current = control.sendButton;
22593
23657
  if (current?.isConnected && control.composer.contains(current)) return current;
22594
23658
  const replacement = sendButtonWithin(control.composer) ?? (current && !isComposerSubmitButton(current) ? lastNativeButtonWithin(control.composer) : null);
@@ -22674,6 +23738,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
22674
23738
  refreshTrailingClusterPlacement(control);
22675
23739
  refreshUsagePlacement(control);
22676
23740
  refreshCreditsPlacement(control);
23741
+ control.composerIndicators?.place(
23742
+ control.nativePermissionModeControlVerified ? control.nativePermissionModeControl?.element ?? null : null
23743
+ );
22677
23744
  setNativeControlHidden(control.nativeModelControl, hideModel);
22678
23745
  setNativeControlHidden(control.nativeContextUsageControl, false);
22679
23746
  setNativeControlHidden(control.nativePermissionModeControl, hidePermissionMode);
@@ -22700,6 +23767,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22700
23767
  onSelectPermissionMode
22701
23768
  );
22702
23769
  const credits = mountRendererCreditsControl(composerId);
23770
+ const composerIndicators = mountRendererComposerIndicators(composer);
22703
23771
  const toolbar = sendButton.parentElement;
22704
23772
  const harnessCommands = mountRendererHarnessCommandControl(
22705
23773
  toolbar ?? composer,
@@ -22746,6 +23814,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22746
23814
  nativeContextUsageControl,
22747
23815
  nativePermissionModeControlVerified,
22748
23816
  credits,
23817
+ composerIndicators,
22749
23818
  usage: null,
22750
23819
  harnessCommands,
22751
23820
  sendButton,
@@ -22754,6 +23823,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22754
23823
  refreshTrailingClusterPlacement(control);
22755
23824
  refreshUsagePlacement(control);
22756
23825
  refreshCreditsPlacement(control);
23826
+ control.stopCompactLayout = observeRendererCompactComposer(composer);
22757
23827
  return control;
22758
23828
  }
22759
23829
  function nativeSendDisabled(button2, fallback) {
@@ -22811,6 +23881,10 @@ Codex Fast mode prioritizes requests and may increase usage.`
22811
23881
  permissionModeVisible,
22812
23882
  locale
22813
23883
  );
23884
+ control.composerIndicators?.render(
23885
+ permissionModeVisible ? usage?.composerIndicators ?? [] : [],
23886
+ locale
23887
+ );
22814
23888
  if (control.usage) {
22815
23889
  renderRendererUsageControl(control.usage, usage, locale);
22816
23890
  }
@@ -22821,6 +23895,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22821
23895
  return state.agent !== "codex" && adapterState === "ready" && !submissionBlocked;
22822
23896
  }
22823
23897
  function disposeComposerAgentControl(control) {
23898
+ control.stopCompactLayout?.();
22824
23899
  if (control.sendDisabledBeforeSwitch !== null) {
22825
23900
  control.sendButton.disabled = nativeSendDisabled(
22826
23901
  control.sendButton,
@@ -22830,6 +23905,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22830
23905
  restoreNativeControl(control.nativeModelControl);
22831
23906
  restoreNativeControl(control.nativeContextUsageControl);
22832
23907
  restoreNativeControl(control.nativePermissionModeControl);
23908
+ control.composerIndicators?.dispose();
22833
23909
  control.credits.dispose();
22834
23910
  control.usage?.dispose();
22835
23911
  control.usage = null;
@@ -23384,36 +24460,24 @@ Codex Fast mode prioritizes requests and may increase usage.`
23384
24460
  };
23385
24461
  }
23386
24462
 
23387
- // src/renderer-request-sender.ts
23388
- var RendererMethodUnavailableError = class extends Error {
23389
- constructor(method, cause) {
23390
- super(`${method} is unsupported on this Host connection`, { cause });
23391
- this.method = method;
23392
- this.name = "RendererMethodUnavailableError";
24463
+ // src/renderer-installation-client.ts
24464
+ async function runRendererInstallation(send, input) {
24465
+ const params = harnessInstallationParamsSchema.parse(input);
24466
+ const options = { priority: "background", timeoutMs: 15e3 };
24467
+ let task = harnessInstallationTaskSchema.parse(
24468
+ await send(HARNESS_INSTALLATION_START_METHOD, params, options)
24469
+ );
24470
+ const taskId = task.taskId;
24471
+ while (task.status === "running") {
24472
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 500));
24473
+ task = harnessInstallationTaskSchema.parse(
24474
+ await send(HARNESS_INSTALLATION_STATUS_METHOD, { taskId }, options)
24475
+ );
24476
+ if (task.taskId !== taskId) throw new Error("Harness installation task identity changed");
23393
24477
  }
23394
- method;
23395
- code = -32601;
23396
- };
23397
- function isUnsupportedMethod(error51, method) {
23398
- if (typeof error51 !== "object" || error51 === null) return false;
23399
- const code = "code" in error51 ? error51.code : void 0;
23400
- const message2 = "message" in error51 ? error51.message : void 0;
23401
- return code === -32601 || code === -32600 && typeof message2 === "string" && message2.startsWith(`Invalid request: unknown variant \`${method}\``);
23402
- }
23403
- function createRendererRequestSender(send) {
23404
- const unsupported = /* @__PURE__ */ new Map();
23405
- return async (method, params, options) => {
23406
- const known = unsupported.get(method);
23407
- if (known) throw known;
23408
- try {
23409
- return await (options === void 0 ? send(method, params) : send(method, params, options));
23410
- } catch (error51) {
23411
- if (!method.startsWith("codexhost/") || !isUnsupportedMethod(error51, method)) throw error51;
23412
- const unavailable = new RendererMethodUnavailableError(method, error51);
23413
- unsupported.set(method, unavailable);
23414
- throw unavailable;
23415
- }
23416
- };
24478
+ if (task.status === "failed")
24479
+ throw Object.assign(new Error(task.error.message), { code: task.error.code });
24480
+ return task.result;
23417
24481
  }
23418
24482
 
23419
24483
  // src/renderer-native-thread.ts
@@ -23573,7 +24637,15 @@ Codex Fast mode prioritizes requests and may increase usage.`
23573
24637
  };
23574
24638
  const inspectHarness = async (input, options) => {
23575
24639
  const params = harnessInspectParamsSchema.parse(input);
23576
- const result = await manager.sendRequest(HARNESS_INSPECT_METHOD, params, options);
24640
+ let result;
24641
+ try {
24642
+ result = await manager.sendRequest(HARNESS_INSPECT_METHOD, params, options);
24643
+ } catch (error51) {
24644
+ if (!params.purpose || !isInvalidParams(error51)) throw error51;
24645
+ const full = { ...params };
24646
+ delete full.purpose;
24647
+ result = await manager.sendRequest(HARNESS_INSPECT_METHOD, full, options);
24648
+ }
23577
24649
  return harnessInspectionSchema.parse(result);
23578
24650
  };
23579
24651
  const inspectHarnessCommands = async (input) => {
@@ -23613,13 +24685,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23613
24685
  };
23614
24686
  return Object.freeze({
23615
24687
  async installation(input) {
23616
- return harnessInstallationStateSchema.parse(
23617
- await manager.sendRequest(
23618
- HARNESS_INSTALLATION_METHOD,
23619
- harnessInstallationParamsSchema.parse(input),
23620
- { priority: "interactive" }
23621
- )
23622
- );
24688
+ return runRendererInstallation(manager.sendRequest, input);
23623
24689
  },
23624
24690
  async getHarnessDisplaySettings() {
23625
24691
  return harnessDisplaySettingsSchema.parse(
@@ -23835,6 +24901,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
23835
24901
  }
23836
24902
  });
23837
24903
  }
24904
+ function isInvalidParams(error51) {
24905
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === -32602;
24906
+ }
23838
24907
 
23839
24908
  // src/renderer-external-queue.ts
23840
24909
  function isRecord6(value) {
@@ -23870,6 +24939,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23870
24939
  }
23871
24940
 
23872
24941
  // src/renderer-external-steering.ts
24942
+ var THREAD_STEERING_INSPECT_METHOD = "codexhost/thread/steering/inspect";
23873
24943
  var THREAD_OWNERSHIP_LIST_METHOD2 = "codexhost/thread/ownership/list";
23874
24944
  function isRecord7(value) {
23875
24945
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -23953,6 +25023,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23953
25023
  const originalSteer = manager.steerTurn;
23954
25024
  const originalSend = manager.sendRequest;
23955
25025
  const routes = /* @__PURE__ */ new Map();
25026
+ const activeTurnSteers = /* @__PURE__ */ new Map();
23956
25027
  const pending = /* @__PURE__ */ new Map();
23957
25028
  let disposed = false;
23958
25029
  const send = function(method, params, options) {
@@ -23968,6 +25039,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
23968
25039
  return originalSend.call(manager, method, input, options);
23969
25040
  });
23970
25041
  }
25042
+ if (method === "turn/steer" && isRecord7(params) && typeof params.threadId === "string" && activeTurnSteers.has(params.threadId)) {
25043
+ params = { ...params, [THREAD_STEER_DELIVERY_PARAM]: "activeTurn" };
25044
+ }
23971
25045
  return originalSend.call(manager, method, params, options);
23972
25046
  }
23973
25047
  if (disposed) return Promise.reject(new Error("External steering binding was disposed"));
@@ -23982,7 +25056,8 @@ Codex Fast mode prioritizes requests and may increase usage.`
23982
25056
  input: params.input,
23983
25057
  additionalContext: params.additionalContext,
23984
25058
  responsesapiClientMetadata: params.responsesapiClientMetadata,
23985
- ...params[THREAD_REFERENCE_SOURCE_HOST_PARAM] !== void 0 ? { [THREAD_REFERENCE_SOURCE_HOST_PARAM]: params[THREAD_REFERENCE_SOURCE_HOST_PARAM] } : {}
25059
+ ...params[THREAD_REFERENCE_SOURCE_HOST_PARAM] !== void 0 ? { [THREAD_REFERENCE_SOURCE_HOST_PARAM]: params[THREAD_REFERENCE_SOURCE_HOST_PARAM] } : {},
25060
+ [THREAD_STEER_DELIVERY_PARAM]: "newTurn"
23986
25061
  },
23987
25062
  options
23988
25063
  )
@@ -24004,6 +25079,34 @@ Codex Fast mode prioritizes requests and may increase usage.`
24004
25079
  };
24005
25080
  });
24006
25081
  };
25082
+ const inspectDelivery = async (threadId, text) => {
25083
+ try {
25084
+ const response = await originalSend.call(manager, THREAD_STEERING_INSPECT_METHOD, {
25085
+ threadId,
25086
+ ...text !== void 0 ? { text } : {}
25087
+ });
25088
+ return threadSteeringInspectResultSchema.parse(response).delivery;
25089
+ } catch (error51) {
25090
+ if (!isUnsupportedMethod(error51, THREAD_STEERING_INSPECT_METHOD)) throw error51;
25091
+ }
25092
+ let ownershipResponse;
25093
+ try {
25094
+ ownershipResponse = await originalSend.call(manager, THREAD_OWNERSHIP_LIST_METHOD2, {
25095
+ threadIds: [threadId]
25096
+ });
25097
+ } catch (error51) {
25098
+ if (!isUnsupportedMethod(error51, THREAD_OWNERSHIP_LIST_METHOD2)) throw error51;
25099
+ await verifyNativeCodexThread(
25100
+ (method, params) => originalSend.call(manager, method, params),
25101
+ threadId
25102
+ );
25103
+ return "official";
25104
+ }
25105
+ const ownership = threadOwnershipListResultSchema.parse(ownershipResponse);
25106
+ const owner = ownership.threads.find((thread) => thread.threadId === threadId)?.owner;
25107
+ if (!owner) throw new Error("Thread ownership could not be resolved for steering");
25108
+ return owner === "codex" ? "official" : "newTurn";
25109
+ };
24007
25110
  const steer = async function(...args) {
24008
25111
  const [
24009
25112
  threadId,
@@ -24026,25 +25129,20 @@ Codex Fast mode prioritizes requests and may increase usage.`
24026
25129
  expectedTurnId = host.getActiveTurnId(threadId);
24027
25130
  } catch {
24028
25131
  }
24029
- let ownershipResponse;
24030
- try {
24031
- ownershipResponse = await originalSend.call(manager, THREAD_OWNERSHIP_LIST_METHOD2, {
24032
- threadIds: [threadId]
24033
- });
24034
- } catch (error51) {
24035
- if (!isUnsupportedMethod(error51, THREAD_OWNERSHIP_LIST_METHOD2)) throw error51;
24036
- await verifyNativeCodexThread(
24037
- (method, params) => originalSend.call(manager, method, params),
24038
- threadId
24039
- );
24040
- if (disposed) throw new Error("External steering binding was disposed");
24041
- return originalSteer.apply(manager, args);
24042
- }
24043
- const ownership = threadOwnershipListResultSchema.parse(ownershipResponse);
24044
- const owner = ownership.threads.find((thread) => thread.threadId === threadId)?.owner;
24045
- if (!owner) throw new Error("Thread ownership could not be resolved for steering");
25132
+ const text = Array.isArray(input) ? input.filter((item) => isRecord7(item) && typeof item.text === "string").map((item) => item.text).join("\n") : void 0;
25133
+ const delivery = await inspectDelivery(threadId, text);
24046
25134
  if (disposed) throw new Error("External steering binding was disposed");
24047
- if (owner === "codex") return originalSteer.apply(manager, args);
25135
+ if (delivery === "official") return originalSteer.apply(manager, args);
25136
+ if (delivery === "activeTurn") {
25137
+ activeTurnSteers.set(threadId, (activeTurnSteers.get(threadId) ?? 0) + 1);
25138
+ try {
25139
+ return await originalSteer.apply(manager, args);
25140
+ } finally {
25141
+ const remaining = (activeTurnSteers.get(threadId) ?? 1) - 1;
25142
+ if (remaining > 0) activeTurnSteers.set(threadId, remaining);
25143
+ else activeTurnSteers.delete(threadId);
25144
+ }
25145
+ }
24048
25146
  if (!host) throw new Error("Desktop turn submission binding is unavailable");
24049
25147
  const currentRole = manager.getStreamRole?.(threadId);
24050
25148
  if (isRecord7(currentRole) && currentRole.role === "follower")
@@ -24289,9 +25387,9 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24289
25387
  }
24290
25388
 
24291
25389
  // src/renderer-thread-reference-capability.ts
24292
- var record3 = (value) => typeof value === "object" && value !== null;
25390
+ var record4 = (value) => typeof value === "object" && value !== null;
24293
25391
  function restoreThreadReferenceCapability(client, manager, isCurrent) {
24294
- if (!record3(manager) || !record3(manager.storage)) return client;
25392
+ if (!record4(manager) || !record4(manager.storage)) return client;
24295
25393
  const storage = manager.storage;
24296
25394
  const read = storage.readValue;
24297
25395
  const write = storage.writeValue;
@@ -24326,14 +25424,14 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24326
25424
  }
24327
25425
 
24328
25426
  // src/renderer-thread-reference-context.ts
24329
- var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25427
+ var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
24330
25428
  function createThreadReferenceContext(manager, hostId2, isCurrent) {
24331
25429
  const prepared = /* @__PURE__ */ new WeakMap();
24332
25430
  return (params) => {
24333
- if (hostId2 === "local" || !record4(manager) || typeof manager.getConversation !== "function" || !record4(params) || typeof params.threadId !== "string")
25431
+ if (hostId2 === "local" || !record5(manager) || typeof manager.getConversation !== "function" || !record5(params) || typeof params.threadId !== "string")
24334
25432
  return params;
24335
25433
  const conversation = manager.getConversation.call(manager, params.threadId);
24336
- if (!record4(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
25434
+ if (!record5(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
24337
25435
  return params;
24338
25436
  if (!isCurrent()) throw new Error("Thread reference connection is no longer available");
24339
25437
  const cached2 = prepared.get(params);
@@ -25852,9 +26950,17 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25852
26950
  }
25853
26951
 
25854
26952
  // src/codex-locale-adapter.ts
25855
- var GET_LOCALE_OVERRIDE_URL = "vscode://codex/get-setting";
25856
- var GET_LOCALE_INFO_URL = "vscode://codex/locale-info";
25857
26953
  var DEFAULT_LOCALE_REQUEST_TIMEOUT_MS = 750;
26954
+ function isNativeLocaleServices(value) {
26955
+ if (!isRecord14(value) || !Object.hasOwn(value, "appInfo")) return false;
26956
+ const appInfo = value.appInfo;
26957
+ return appInfo != null && typeof appInfo.getLocaleInfo === "function";
26958
+ }
26959
+ function isNativeSettingsServices(value) {
26960
+ if (!isRecord14(value) || !Object.hasOwn(value, "settings")) return false;
26961
+ const settings = value.settings;
26962
+ return typeof settings?.read === "function" && typeof settings?.write === "function";
26963
+ }
25858
26964
  function isRecord14(value) {
25859
26965
  return typeof value === "object" && value !== null && !Array.isArray(value);
25860
26966
  }
@@ -25876,19 +26982,19 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25876
26982
  function abortError2() {
25877
26983
  return new DOMException("The operation was aborted", "AbortError");
25878
26984
  }
25879
- function parseLocaleOverride(value) {
25880
- if (!isRecord14(value) || !("value" in value)) {
25881
- throw new Error("Codex locale override response is malformed");
26985
+ function parseLocaleOverride(response) {
26986
+ if (!isRecord14(response) || !Object.hasOwn(response, "effective")) {
26987
+ throw new Error("Codex native locale override response is malformed");
25882
26988
  }
25883
- if (value.value === null) return { value: null };
25884
- const locale = canonicalLocale(value.value);
26989
+ if (response.effective === null) return null;
26990
+ const locale = canonicalLocale(response.effective);
25885
26991
  if (!locale) throw new Error("Codex locale override is invalid");
25886
- return { value: locale };
26992
+ return locale;
25887
26993
  }
25888
- function optionalLocale(value, field) {
26994
+ function optionalLocale(value, field2) {
25889
26995
  if (value === void 0 || value === null) return void 0;
25890
26996
  const locale = canonicalLocale(value);
25891
- if (!locale) throw new Error(`Codex ${field} is invalid`);
26997
+ if (!locale) throw new Error(`Codex ${field2} is invalid`);
25892
26998
  return locale;
25893
26999
  }
25894
27000
  function parseLocaleInfo(value) {
@@ -25898,87 +27004,39 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25898
27004
  systemLocale: optionalLocale(value.systemLocale, "system locale")
25899
27005
  };
25900
27006
  }
25901
- function sendFixedLocaleRequest(request, ownerWindow, signal, timeoutMs) {
25902
- const bridge = ownerWindow.electronBridge;
25903
- if (typeof bridge?.sendMessageFromView !== "function") {
25904
- return Promise.reject(new Error("Codex locale bridge is unavailable"));
25905
- }
27007
+ function requestNativeLocale(ownerWindow, signal, timeoutMs, matchesServices, invoke) {
25906
27008
  if (signal?.aborted) return Promise.reject(abortError2());
25907
- const requestId = ownerWindow.crypto.randomUUID();
25908
27009
  return new Promise((resolve, reject) => {
25909
27010
  let settled = false;
25910
- const cleanup = () => {
25911
- ownerWindow.clearTimeout(timer);
25912
- ownerWindow.removeEventListener("message", onMessage);
25913
- signal?.removeEventListener("abort", onAbort);
25914
- };
27011
+ let nativeRequest;
25915
27012
  const settle = (operation) => {
25916
27013
  if (settled) return;
25917
27014
  settled = true;
25918
- cleanup();
25919
- operation();
25920
- };
25921
- const onAbort = () => settle(() => reject(abortError2()));
25922
- const onMessage = (event) => {
25923
- const message3 = event.data;
25924
- if (!isRecord14(message3) || message3.type !== "fetch-response") return;
25925
- if (message3.requestId !== requestId) return;
25926
- if (message3.responseType !== "success" || typeof message3.status !== "number" || message3.status < 200 || message3.status >= 300 || typeof message3.bodyJsonString !== "string") {
25927
- settle(() => reject(new Error("Codex locale request failed")));
25928
- return;
25929
- }
27015
+ ownerWindow.clearTimeout(timer);
27016
+ signal?.removeEventListener("abort", onAbort);
25930
27017
  try {
25931
- const body = JSON.parse(message3.bodyJsonString);
25932
- settle(() => resolve(body));
25933
- } catch {
25934
- settle(() => reject(new Error("Codex locale response is not valid JSON")));
27018
+ nativeRequest?.[Symbol.dispose]?.();
27019
+ operation();
27020
+ } catch (error51) {
27021
+ reject(error51);
25935
27022
  }
25936
27023
  };
27024
+ const onAbort = () => settle(() => reject(abortError2()));
25937
27025
  const timer = ownerWindow.setTimeout(
25938
27026
  () => settle(() => reject(new Error("Codex locale request timed out"))),
25939
27027
  timeoutMs
25940
27028
  );
25941
- ownerWindow.addEventListener("message", onMessage);
25942
27029
  signal?.addEventListener("abort", onAbort, { once: true });
25943
- const message2 = {
25944
- type: "fetch",
25945
- requestId,
25946
- method: "POST",
25947
- url: request.url,
25948
- ...request.body === void 0 ? {} : { body: request.body },
25949
- reportUploadProgress: false
25950
- };
25951
- try {
25952
- Promise.resolve(bridge.sendMessageFromView(message2)).catch((error51) => {
25953
- settle(() => reject(error51));
25954
- });
25955
- } catch (error51) {
25956
- settle(() => reject(error51));
25957
- }
27030
+ void (async () => {
27031
+ const native = await loadCodexNativeServices(ownerWindow, matchesServices);
27032
+ if (settled) return;
27033
+ if (!native) throw new Error("Codex native locale services are unavailable");
27034
+ nativeRequest = invoke(native);
27035
+ const response = await nativeRequest;
27036
+ settle(() => resolve(response));
27037
+ })().catch((error51) => settle(() => reject(error51)));
25958
27038
  });
25959
27039
  }
25960
- async function readLocaleOverride(ownerWindow, signal, timeoutMs) {
25961
- const response = await sendFixedLocaleRequest(
25962
- {
25963
- kind: "locale-override",
25964
- url: GET_LOCALE_OVERRIDE_URL,
25965
- body: JSON.stringify({ key: "localeOverride" })
25966
- },
25967
- ownerWindow,
25968
- signal,
25969
- timeoutMs
25970
- );
25971
- return parseLocaleOverride(response);
25972
- }
25973
- async function readLocaleInfo(ownerWindow, signal, timeoutMs) {
25974
- const response = await sendFixedLocaleRequest(
25975
- { kind: "locale-info", url: GET_LOCALE_INFO_URL },
25976
- ownerWindow,
25977
- signal,
25978
- timeoutMs
25979
- );
25980
- return parseLocaleInfo(response);
25981
- }
25982
27040
  async function readCodexLocaleSettings(options = {}) {
25983
27041
  const ownerWindow = options.ownerWindow ?? window;
25984
27042
  const timeoutMs = options.timeoutMs ?? DEFAULT_LOCALE_REQUEST_TIMEOUT_MS;
@@ -25987,13 +27045,25 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25987
27045
  }
25988
27046
  if (options.signal?.aborted) throw abortError2();
25989
27047
  const [overrideResult, localeInfoResult] = await Promise.allSettled([
25990
- readLocaleOverride(ownerWindow, options.signal, timeoutMs),
25991
- readLocaleInfo(ownerWindow, options.signal, timeoutMs)
27048
+ requestNativeLocale(
27049
+ ownerWindow,
27050
+ options.signal,
27051
+ timeoutMs,
27052
+ isNativeSettingsServices,
27053
+ (native) => native.settings.read("localeOverride")
27054
+ ).then(parseLocaleOverride),
27055
+ requestNativeLocale(
27056
+ ownerWindow,
27057
+ options.signal,
27058
+ timeoutMs,
27059
+ isNativeLocaleServices,
27060
+ (native) => native.appInfo.getLocaleInfo()
27061
+ ).then(parseLocaleInfo)
25992
27062
  ]);
25993
27063
  if (options.signal?.aborted) throw abortError2();
25994
27064
  const navigatorLocale = firstNavigatorLocale(ownerWindow);
25995
27065
  const overrideKnown = overrideResult.status === "fulfilled";
25996
- const localeOverride = overrideKnown ? overrideResult.value.value : void 0;
27066
+ const localeOverride = overrideKnown ? overrideResult.value : void 0;
25997
27067
  const localeInfo = localeInfoResult.status === "fulfilled" ? localeInfoResult.value : { ideLocale: void 0, systemLocale: void 0 };
25998
27068
  if (typeof localeOverride === "string") {
25999
27069
  return Object.freeze({
@@ -26064,6 +27134,34 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26064
27134
  return names.size === 1 ? names.values().next().value ?? model2 : model2;
26065
27135
  }
26066
27136
 
27137
+ // src/console/usage/usage-hosts.ts
27138
+ var LOCAL_USAGE_HOST_ID = "local";
27139
+ function usageHostOptions(hosts, localLabel, selected) {
27140
+ const options = [{ key: LOCAL_USAGE_HOST_ID, label: localLabel }];
27141
+ const seen = /* @__PURE__ */ new Set([LOCAL_USAGE_HOST_ID]);
27142
+ const add = (hostId2, label) => {
27143
+ if (hostId2.length === 0 || seen.has(hostId2)) return;
27144
+ seen.add(hostId2);
27145
+ options.push({ key: hostId2, label: label !== void 0 && label.length > 0 ? label : hostId2 });
27146
+ };
27147
+ for (const host of hosts ?? []) add(host.hostId, host.label);
27148
+ if (!seen.has(selected)) add(selected, void 0);
27149
+ return options;
27150
+ }
27151
+ function createLatestKeyGuard() {
27152
+ let generation = 0;
27153
+ let key;
27154
+ return {
27155
+ begin(next) {
27156
+ generation += 1;
27157
+ key = next;
27158
+ const mine = generation;
27159
+ const selected = next;
27160
+ return () => generation === mine && Object.is(key, selected);
27161
+ }
27162
+ };
27163
+ }
27164
+
26067
27165
  // src/console/usage/format.ts
26068
27166
  var MEASURES = ["cost", "tokens"];
26069
27167
  function fill(template, values) {
@@ -26310,7 +27408,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26310
27408
  var DECIMAL = /^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/iu;
26311
27409
  function modelPriceDraft(key, price) {
26312
27410
  const prices = Object.fromEntries(
26313
- MODEL_PRICE_FIELDS.map((field) => [field, price?.[field]?.toString() ?? ""])
27411
+ MODEL_PRICE_FIELDS.map((field2) => [field2, price?.[field2]?.toString() ?? ""])
26314
27412
  );
26315
27413
  return { model: key, prices };
26316
27414
  }
@@ -26321,18 +27419,18 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26321
27419
  return { error: { kind: "duplicate", key } };
26322
27420
  }
26323
27421
  const price = {};
26324
- for (const field of MODEL_PRICE_FIELDS) {
26325
- const text = draft.prices[field].trim();
27422
+ for (const field2 of MODEL_PRICE_FIELDS) {
27423
+ const text = draft.prices[field2].trim();
26326
27424
  if (text === "") {
26327
- if (field === "input" || field === "output")
26328
- return { error: { kind: "priceRequired", field } };
27425
+ if (field2 === "input" || field2 === "output")
27426
+ return { error: { kind: "priceRequired", field: field2 } };
26329
27427
  continue;
26330
27428
  }
26331
27429
  const value = Number(text);
26332
27430
  if (!DECIMAL.test(text) || !Number.isFinite(value)) {
26333
- return { error: { kind: "priceInvalid", field } };
27431
+ return { error: { kind: "priceInvalid", field: field2 } };
26334
27432
  }
26335
- price[field] = value;
27433
+ price[field2] = value;
26336
27434
  }
26337
27435
  return {
26338
27436
  change: {
@@ -26352,7 +27450,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26352
27450
  }
26353
27451
  function formatPrice(messages, price) {
26354
27452
  return MODEL_PRICE_FIELDS.map(
26355
- (field) => `${messages.fields[field]} ${price[field] ?? messages.unset}`
27453
+ (field2) => `${messages.fields[field2]} ${price[field2] ?? messages.unset}`
26356
27454
  ).join(" \xB7 ");
26357
27455
  }
26358
27456
  function draftErrorText(messages, error51) {
@@ -26420,18 +27518,18 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26420
27518
  function renderEditor(modelId, view, isCurrent) {
26421
27519
  const existing = view.entries.find((entry) => entry.key === modelId);
26422
27520
  const draft = modelPriceDraft(modelId, existing?.price ?? null);
26423
- const field = (label, value, placeholder = "") => h(document2, "input", {
27521
+ const field2 = (label, value, placeholder = "") => h(document2, "input", {
26424
27522
  type: "text",
26425
27523
  className: "console-input",
26426
27524
  value,
26427
27525
  placeholder,
26428
27526
  "aria-label": label
26429
27527
  });
26430
- const model2 = field(messages.model, modelId);
27528
+ const model2 = field2(messages.model, modelId);
26431
27529
  model2.readOnly = true;
26432
27530
  const prices = Object.fromEntries(
26433
27531
  MODEL_PRICE_FIELDS.map((name) => {
26434
- const input = field(
27532
+ const input = field2(
26435
27533
  messages.fields[name],
26436
27534
  draft.prices[name],
26437
27535
  name === "input" || name === "output" ? messages.required : messages.notSet
@@ -27243,8 +28341,8 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27243
28341
  for (const cell of options.cells) {
27244
28342
  const key = options.singleDay ? cell.hour : cell.weekday * 24 + cell.hour;
27245
28343
  const totals2 = byHour.get(key) ?? emptyTotals();
27246
- for (const field of Object.keys(totals2))
27247
- totals2[field] += cell.totals[field];
28344
+ for (const field2 of Object.keys(totals2))
28345
+ totals2[field2] += cell.totals[field2];
27248
28346
  byHour.set(key, totals2);
27249
28347
  }
27250
28348
  const max = Math.max(0, ...[...byHour.values()].map((totals2) => measured(totals2, measure)));
@@ -27350,6 +28448,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27350
28448
  const range = text("range");
27351
28449
  const measure = text("measure");
27352
28450
  const granularity = text("granularity");
28451
+ const hostId2 = text("hostId");
27353
28452
  const harness2 = text("harness");
27354
28453
  const model2 = text("model");
27355
28454
  const project3 = text("project");
@@ -27358,6 +28457,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27358
28457
  ...range && USAGE_STATISTICS_RANGES.includes(range) ? { range } : {},
27359
28458
  ...measure && MEASURES.includes(measure) ? { measure } : {},
27360
28459
  ...granularity === "day" || granularity === "week" || granularity === "month" ? { granularity } : {},
28460
+ ...hostId2 !== void 0 && hostId2.length > 0 ? { hostId: hostId2 } : {},
27361
28461
  ...harness2 !== void 0 ? { harness: harness2 } : {},
27362
28462
  ...model2 !== void 0 ? { model: model2 } : {},
27363
28463
  ...project3 !== void 0 ? { project: project3 } : {},
@@ -27396,7 +28496,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27396
28496
  day.setDate(day.getDate() - (day.getDay() + 6) % 7);
27397
28497
  return isoDate(day);
27398
28498
  }
27399
- function createUsageStatisticsPage(consoleMessages2, request, pageLocale) {
28499
+ function createUsageStatisticsPage(consoleMessages2, request, pageLocale, usageHosts) {
27400
28500
  const messages = consoleMessages2.usageStatistics;
27401
28501
  return Object.freeze({
27402
28502
  id: "usage-statistics",
@@ -27405,10 +28505,12 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27405
28505
  mount(context) {
27406
28506
  const document2 = context.content.ownerDocument;
27407
28507
  const locale = pageLocale ?? (document2.documentElement.lang || "en");
28508
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
27408
28509
  const count3 = (value) => count2(value, locale);
27409
28510
  const tokenCount2 = (totals2, value) => tokenCount(totals2, value, locale);
27410
28511
  const saved = readView();
27411
28512
  const view = {
28513
+ hostId: saved.hostId ?? LOCAL_USAGE_HOST_ID,
27412
28514
  range: saved.range ?? "30d",
27413
28515
  measure: saved.measure ?? "cost",
27414
28516
  granularity: saved.granularity ?? null,
@@ -27439,7 +28541,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27439
28541
  let projectLabel = /* @__PURE__ */ new Map();
27440
28542
  const projectName = (key) => key === UNKNOWN ? messages.unknownProject : projectLabel.get(key) ?? baseName(key);
27441
28543
  const measureLabel = (measure) => measure === "cost" ? messages.cost : messages.tokens;
27442
- const dateFormat = (options) => new Intl.DateTimeFormat(locale, options);
28544
+ const dateFormat = (options) => new Intl.DateTimeFormat(locale, { ...options, timeZone });
27443
28545
  const shortDate = dateFormat({ month: "short", day: "numeric" });
27444
28546
  const longDate = dateFormat({
27445
28547
  year: "numeric",
@@ -27458,10 +28560,51 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27458
28560
  const prices = createModelPricesDialog(
27459
28561
  document2,
27460
28562
  consoleMessages2,
27461
- request,
28563
+ (method, params2) => request(method, params2, view.hostId),
27462
28564
  context.signal,
27463
28565
  load
27464
28566
  );
28567
+ let offeredHosts = usageHosts ? [] : void 0;
28568
+ const hostCombo = new ComboBox(document2, {
28569
+ label: messages.host,
28570
+ searchLabel: messages.search,
28571
+ emptyLabel: messages.noMatches,
28572
+ signal: context.signal,
28573
+ searchable: false,
28574
+ display: (option) => `${messages.host} \xB7 ${option.label}`,
28575
+ onChange: (key) => {
28576
+ if (key === view.hostId) return;
28577
+ view.hostId = key;
28578
+ view.harness = "";
28579
+ view.model = "";
28580
+ view.project = "";
28581
+ date5 = null;
28582
+ unpricedOnly = false;
28583
+ result = null;
28584
+ error51 = null;
28585
+ loadedAt = 0;
28586
+ names.clear();
28587
+ save();
28588
+ hostOptions();
28589
+ render();
28590
+ void refreshHarnessNames();
28591
+ load();
28592
+ }
28593
+ });
28594
+ const hostOptions = () => {
28595
+ const options = usageHostOptions(offeredHosts, messages.localHost, view.hostId);
28596
+ hostCombo.element.hidden = options.length < 2;
28597
+ hostCombo.update(options, view.hostId === LOCAL_USAGE_HOST_ID ? "" : view.hostId);
28598
+ };
28599
+ const offerHosts = () => {
28600
+ if (!usageHosts) return;
28601
+ void usageHosts().then((hosts) => {
28602
+ if (context.signal.aborted) return;
28603
+ offeredHosts = hosts;
28604
+ hostOptions();
28605
+ }).catch(() => void 0);
28606
+ };
28607
+ hostOptions();
27465
28608
  const updated = h(document2, "span", { className: "console-muted console-usage-updated" });
27466
28609
  const refresh = h(
27467
28610
  document2,
@@ -27474,7 +28617,10 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27474
28617
  },
27475
28618
  createRendererSettingsIcon("refresh", 16)
27476
28619
  );
27477
- refresh.addEventListener("click", () => load());
28620
+ refresh.addEventListener("click", () => {
28621
+ offerHosts();
28622
+ load();
28623
+ });
27478
28624
  const auto = new ComboBox(document2, {
27479
28625
  label: messages.autoRefresh,
27480
28626
  searchLabel: messages.search,
@@ -27513,6 +28659,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27513
28659
  document2,
27514
28660
  "div",
27515
28661
  { className: "console-usage-toolbar" },
28662
+ hostCombo.element,
27516
28663
  updated,
27517
28664
  refresh,
27518
28665
  auto.element,
@@ -27558,8 +28705,8 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27558
28705
  save();
27559
28706
  load();
27560
28707
  }
27561
- function toggleFilter(field, key) {
27562
- view[field] = view[field] === key ? "" : key;
28708
+ function toggleFilter(field2, key) {
28709
+ view[field2] = view[field2] === key ? "" : key;
27563
28710
  changed();
27564
28711
  }
27565
28712
  function selectDate(next) {
@@ -27975,8 +29122,8 @@ ${messages.creditsCoverage}: ${value.reportedRequests} / ${row.requests}` : void
27975
29122
  }
27976
29123
  ];
27977
29124
  }
27978
- function rowFilter(field, key, label, detail) {
27979
- const selected = view[field] === key;
29125
+ function rowFilter(field2, key, label, detail) {
29126
+ const selected = view[field2] === key;
27980
29127
  const button2 = focusKey(
27981
29128
  h(
27982
29129
  document2,
@@ -27990,9 +29137,9 @@ ${detail}` : ""}`
27990
29137
  },
27991
29138
  label
27992
29139
  ),
27993
- `${field}:row:${key}`
29140
+ `${field2}:row:${key}`
27994
29141
  );
27995
- button2.addEventListener("click", () => toggleFilter(field, key));
29142
+ button2.addEventListener("click", () => toggleFilter(field2, key));
27996
29143
  return button2;
27997
29144
  }
27998
29145
  function panel(title, content, extra = null, wide = false) {
@@ -28151,7 +29298,6 @@ ${detail}` : ""}`
28151
29298
  }
28152
29299
  function hourlyPanel(data) {
28153
29300
  const singleDay = data.filters.date !== null || data.range === "today";
28154
- const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
28155
29301
  return panel(
28156
29302
  singleDay ? messages.hourlyDay : messages.hourly,
28157
29303
  hourlyChart(document2, {
@@ -28166,7 +29312,7 @@ ${detail}` : ""}`
28166
29312
  weekStartsOnMonday: !locale.startsWith("en"),
28167
29313
  labels: { cost: messages.cost, tokens: messages.tokens }
28168
29314
  }),
28169
- h(document2, "span", { className: "console-muted console-usage-zone" }, zone)
29315
+ h(document2, "span", { className: "console-muted console-usage-zone" }, timeZone)
28170
29316
  );
28171
29317
  }
28172
29318
  function sessionsPanel(title, rows, tableKey) {
@@ -28313,6 +29459,7 @@ ${detail}` : ""}`
28313
29459
  const project3 = filterValue(view.project);
28314
29460
  return {
28315
29461
  range: view.range,
29462
+ timeZone,
28316
29463
  ...view.harness ? { harness: view.harness } : {},
28317
29464
  ...model2 !== void 0 ? { model: model2 } : {},
28318
29465
  ...project3 !== void 0 ? { project: project3 } : {},
@@ -28325,10 +29472,26 @@ ${detail}` : ""}`
28325
29472
  if (result && !result.reading.complete) poll = window.setTimeout(load, POLL_MS);
28326
29473
  else if (view.autoRefreshMs > 0) poll = window.setTimeout(load, view.autoRefreshMs);
28327
29474
  }
29475
+ const harnessNamesRead = createLatestKeyGuard();
29476
+ async function refreshHarnessNames() {
29477
+ const hostId2 = view.hostId;
29478
+ const isCurrent = harnessNamesRead.begin(hostId2);
29479
+ names.clear();
29480
+ try {
29481
+ const value = await request(HARNESS_PLUGIN_LIST_METHOD2, {}, hostId2);
29482
+ if (!isCurrent()) return;
29483
+ for (const plugin of harnessPluginListResultSchema.parse(value).plugins) {
29484
+ names.set(plugin.id, plugin.name);
29485
+ }
29486
+ } catch {
29487
+ if (!isCurrent()) return;
29488
+ }
29489
+ if (!context.signal.aborted) render();
29490
+ }
28328
29491
  function load() {
28329
29492
  window.clearTimeout(poll);
28330
29493
  const requested = params();
28331
- void context.runLatest(() => request(USAGE_STATISTICS_METHOD, requested), {
29494
+ void context.runLatest(() => request(USAGE_STATISTICS_METHOD, requested, view.hostId), {
28332
29495
  success(value) {
28333
29496
  const parsed = usageStatisticsResultSchema.safeParse(value);
28334
29497
  if (parsed.success) {
@@ -28353,12 +29516,8 @@ ${detail}` : ""}`
28353
29516
  }
28354
29517
  context.content.replaceChildren(header, prices.element, filters, notices, body);
28355
29518
  render();
28356
- void request(HARNESS_PLUGIN_LIST_METHOD2, {}).then((value) => {
28357
- for (const plugin of harnessPluginListResultSchema.parse(value).plugins) {
28358
- names.set(plugin.id, plugin.name);
28359
- }
28360
- if (!context.signal.aborted) render();
28361
- }).catch(() => void 0);
29519
+ offerHosts();
29520
+ void refreshHarnessNames();
28362
29521
  load();
28363
29522
  return () => {
28364
29523
  window.clearTimeout(poll);
@@ -28451,6 +29610,8 @@ ${detail}` : ""}`
28451
29610
  harness: "Harness",
28452
29611
  model: "Model",
28453
29612
  project: "Project",
29613
+ host: "Machine",
29614
+ localHost: "This machine",
28454
29615
  filterModel: "Filter by model",
28455
29616
  filterProject: "Filter by project",
28456
29617
  unknownModel: "Unknown model",
@@ -28634,6 +29795,8 @@ ${detail}` : ""}`
28634
29795
  harness: "Harness",
28635
29796
  model: "\u6A21\u578B",
28636
29797
  project: "\u9879\u76EE",
29798
+ host: "\u673A\u5668",
29799
+ localHost: "\u672C\u673A",
28637
29800
  filterModel: "\u6309\u6A21\u578B\u7B5B\u9009",
28638
29801
  filterProject: "\u6309\u9879\u76EE\u7B5B\u9009",
28639
29802
  unknownModel: "\u672A\u77E5\u6A21\u578B",
@@ -29175,8 +30338,8 @@ ${detail}` : ""}`
29175
30338
  return input;
29176
30339
  }
29177
30340
  function createNumberField(document2, input) {
29178
- const field = document2.createElement("div");
29179
- field.className = "flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-settings-border bg-settings-surface px-2.5 transition-colors focus-within:border-settings-focus data-[invalid=true]:border-settings-danger";
30341
+ const field2 = document2.createElement("div");
30342
+ field2.className = "flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-settings-border bg-settings-surface px-2.5 transition-colors focus-within:border-settings-focus data-[invalid=true]:border-settings-danger";
29180
30343
  const control = document2.createElement("input");
29181
30344
  control.type = "number";
29182
30345
  control.id = input.id;
@@ -29189,8 +30352,8 @@ ${detail}` : ""}`
29189
30352
  unit.className = "text-xs text-settings-muted";
29190
30353
  unit.setAttribute("aria-hidden", "true");
29191
30354
  unit.textContent = input.unit;
29192
- field.append(control, unit);
29193
- return { field, control };
30355
+ field2.append(control, unit);
30356
+ return { field: field2, control };
29194
30357
  }
29195
30358
 
29196
30359
  // src/settings/remote-connections-dialogs.ts
@@ -29274,7 +30437,7 @@ ${detail}` : ""}`
29274
30437
  );
29275
30438
  if (!dialog) return;
29276
30439
  const document2 = options.container.ownerDocument;
29277
- const field = (label, value, placeholder = "", hint = "") => {
30440
+ const field2 = (label, value, placeholder = "", hint = "") => {
29278
30441
  const wrapper = remoteElement(document2, "div", "settings-credential-dialog__field");
29279
30442
  const input = remoteElement(document2, "input");
29280
30443
  input.id = preferenceId("remote-field");
@@ -29294,13 +30457,13 @@ ${detail}` : ""}`
29294
30457
  dialog.body.append(wrapper);
29295
30458
  return input;
29296
30459
  };
29297
- const name = field(t("\u540D\u79F0", "Name"), previous?.displayName ?? "");
30460
+ const name = field2(t("\u540D\u79F0", "Name"), previous?.displayName ?? "");
29298
30461
  name.required = true;
29299
30462
  const addressHint = t(
29300
30463
  "user@hostname\uFF0C\u6216 ~/.ssh/config \u4E2D\u7684\u4E3B\u673A\u522B\u540D",
29301
30464
  "user@hostname, or a host alias from ~/.ssh/config"
29302
30465
  );
29303
- const hostname3 = field(
30466
+ const hostname3 = field2(
29304
30467
  t("SSH \u5730\u5740", "SSH address"),
29305
30468
  previous?.sshHost ?? "",
29306
30469
  "user@hostname",
@@ -29309,7 +30472,7 @@ ${detail}` : ""}`
29309
30472
  hostname3.required = true;
29310
30473
  hostname3.pattern = "[^\\s\\-]\\S*";
29311
30474
  hostname3.title = addressHint;
29312
- const port = field(
30475
+ const port = field2(
29313
30476
  t("\u7AEF\u53E3\uFF08\u53EF\u9009\uFF09", "Port (optional)"),
29314
30477
  previous?.sshPort?.toString() ?? "",
29315
30478
  "22"
@@ -29318,7 +30481,7 @@ ${detail}` : ""}`
29318
30481
  port.min = "1";
29319
30482
  port.max = "65535";
29320
30483
  port.step = "1";
29321
- const identity = field(
30484
+ const identity = field2(
29322
30485
  t("\u79C1\u94A5\u8DEF\u5F84\uFF08\u53EF\u9009\uFF09", "Identity file (optional)"),
29323
30486
  previous?.identity ?? "",
29324
30487
  "~/.ssh/id_ed25519"
@@ -30235,6 +31398,50 @@ ${detail}` : ""}`
30235
31398
  };
30236
31399
  setRefreshLabel(false);
30237
31400
  header.append(heading, refresh);
31401
+ let selectedHostId;
31402
+ let availableHostIds = [];
31403
+ let displayedHostId = "";
31404
+ let hostsLocked = false;
31405
+ const hostButtons = [];
31406
+ const hostLabel = document2.createElement("div");
31407
+ hostLabel.className = "settings-session-import-host";
31408
+ const hostCaption = document2.createElement("span");
31409
+ hostCaption.textContent = "Host";
31410
+ const hostOptions = document2.createElement("div");
31411
+ hostOptions.className = "settings-connection-host-tabs";
31412
+ hostOptions.setAttribute("role", "group");
31413
+ hostOptions.setAttribute("aria-label", "Host");
31414
+ hostLabel.append(hostCaption, hostOptions);
31415
+ const lockHosts = (locked) => {
31416
+ hostsLocked = locked;
31417
+ for (const button2 of hostButtons) button2.disabled = locked;
31418
+ };
31419
+ const renderHosts = (client) => {
31420
+ const current = selectedHostId ?? (client ? client.hostId ?? "local" : "");
31421
+ availableHostIds = [
31422
+ .../* @__PURE__ */ new Set([
31423
+ ...getDiagnostics()?.snapshot().hosts.map(({ hostId: hostId2 }) => hostId2) ?? [],
31424
+ ...current ? [current] : []
31425
+ ])
31426
+ ];
31427
+ displayedHostId = current;
31428
+ const scrollLeft = hostOptions.scrollLeft;
31429
+ hostOptions.replaceChildren();
31430
+ hostButtons.length = 0;
31431
+ for (const hostId2 of availableHostIds) {
31432
+ const button2 = document2.createElement("button");
31433
+ button2.type = "button";
31434
+ button2.className = "settings-connection-host-tab";
31435
+ button2.dataset.sessionImportHost = hostId2;
31436
+ button2.textContent = connectionHostName(hostId2, messages);
31437
+ button2.setAttribute("aria-pressed", String(hostId2 === current));
31438
+ button2.disabled = hostsLocked;
31439
+ button2.addEventListener("click", () => selectHost(hostId2));
31440
+ hostButtons.push(button2);
31441
+ hostOptions.append(button2);
31442
+ }
31443
+ hostOptions.scrollLeft = scrollLeft;
31444
+ };
30238
31445
  const harness2 = document2.createElement("div");
30239
31446
  harness2.className = "settings-session-import-harness";
30240
31447
  const harnessLabel = document2.createElement("span");
@@ -30295,6 +31502,7 @@ ${detail}` : ""}`
30295
31502
  const listControls = createSessionImportListControls(document2, messages, () => load());
30296
31503
  context.content.append(
30297
31504
  header,
31505
+ hostLabel,
30298
31506
  harness2,
30299
31507
  description,
30300
31508
  availabilityNote,
@@ -30304,9 +31512,11 @@ ${detail}` : ""}`
30304
31512
  listControls.pagination
30305
31513
  );
30306
31514
  let candidates = [];
31515
+ let loadedClient = null;
30307
31516
  let importingId = null;
30308
31517
  let actions = [];
30309
31518
  const updateImportActions = () => {
31519
+ lockHosts(importingId !== null);
30310
31520
  listControls.setBusy(importingId !== null, importingId !== null);
30311
31521
  for (const button2 of sourceButtons) button2.disabled = importingId !== null;
30312
31522
  for (const { button: button2, candidate } of actions) {
@@ -30327,7 +31537,10 @@ ${detail}` : ""}`
30327
31537
  listControls.setTotal(0);
30328
31538
  candidates = [];
30329
31539
  actions = [];
30330
- const status = createStatus(document2, messages.sessionImportUnavailable);
31540
+ const status = createStatus(
31541
+ document2,
31542
+ !displayedHostId && availableHostIds.length > 1 ? messages.sessionImportSelectHost : messages.sessionImportUnavailable
31543
+ );
30331
31544
  content.replaceChildren(status);
30332
31545
  if (focus) {
30333
31546
  status.tabIndex = -1;
@@ -30352,7 +31565,7 @@ ${detail}` : ""}`
30352
31565
  status.focus();
30353
31566
  }
30354
31567
  };
30355
- const renderOpenRecovery = (candidate, threadId) => {
31568
+ const renderOpenRecovery = (candidate, threadId, hostId2) => {
30356
31569
  if (!openImportedThread) return;
30357
31570
  actions = [];
30358
31571
  refresh.disabled = false;
@@ -30405,6 +31618,7 @@ ${detail}` : ""}`
30405
31618
  retry.className = "settings-command-button";
30406
31619
  retry.dataset.sessionImportAction = "retry-open";
30407
31620
  const setRetrying = (pending) => {
31621
+ lockHosts(pending);
30408
31622
  listControls.setBusy(pending, pending);
30409
31623
  for (const button2 of sourceButtons) button2.disabled = pending;
30410
31624
  retry.disabled = pending;
@@ -30419,12 +31633,12 @@ ${detail}` : ""}`
30419
31633
  retry.addEventListener("click", () => {
30420
31634
  if (retry.disabled) return;
30421
31635
  setRetrying(true);
30422
- void context.runLatest((signal) => openImportedThread(threadId, signal), {
31636
+ void context.runLatest((signal) => openImportedThread(threadId, signal, hostId2), {
30423
31637
  success() {
30424
31638
  setRetrying(false);
30425
31639
  },
30426
31640
  failure() {
30427
- renderOpenRecovery(candidate, threadId);
31641
+ renderOpenRecovery(candidate, threadId, hostId2);
30428
31642
  }
30429
31643
  });
30430
31644
  });
@@ -30501,7 +31715,7 @@ ${detail}` : ""}`
30501
31715
  if (candidate.running === true || importingId !== null || selectedHarness === null)
30502
31716
  return;
30503
31717
  const harnessId = selectedHarness;
30504
- const client = getClient();
31718
+ const client = loadedClient;
30505
31719
  if (!client) {
30506
31720
  renderUnavailable(true);
30507
31721
  return;
@@ -30519,7 +31733,7 @@ ${detail}` : ""}`
30519
31733
  });
30520
31734
  committedThreadId = result.threadId;
30521
31735
  if (!signal.aborted && openImportedThread)
30522
- await openImportedThread(result.threadId, signal);
31736
+ await openImportedThread(result.threadId, signal, client.hostId);
30523
31737
  },
30524
31738
  {
30525
31739
  success() {
@@ -30537,7 +31751,7 @@ ${detail}` : ""}`
30537
31751
  updateImportActions();
30538
31752
  refresh.disabled = false;
30539
31753
  if (committedThreadId) {
30540
- renderOpenRecovery(candidate, committedThreadId);
31754
+ renderOpenRecovery(candidate, committedThreadId, client.hostId);
30541
31755
  } else {
30542
31756
  renderFailure(error51, "import");
30543
31757
  }
@@ -30555,23 +31769,22 @@ ${detail}` : ""}`
30555
31769
  };
30556
31770
  const load = () => {
30557
31771
  if (importingId !== null || context.signal.aborted) return;
30558
- const client = getClient();
30559
- if (!client) {
30560
- refresh.disabled = false;
30561
- setRefreshLabel(false);
30562
- renderUnavailable();
30563
- return;
30564
- }
30565
- listControls.setBusy(true);
30566
- refresh.disabled = true;
30567
- setRefreshLabel(true);
30568
- content.replaceChildren(createStatus(document2, messages.sessionImportRefreshing));
31772
+ loadedClient = null;
31773
+ const client = getClient(selectedHostId);
31774
+ renderHosts(client);
31775
+ listControls.setBusy(client !== null);
31776
+ refresh.disabled = client !== null;
31777
+ setRefreshLabel(client !== null);
31778
+ if (client)
31779
+ content.replaceChildren(createStatus(document2, messages.sessionImportRefreshing));
31780
+ else renderUnavailable();
30569
31781
  const requestedHarness = selectedHarness;
30570
31782
  const pageParams = listControls.params();
30571
31783
  void context.runLatest(
30572
31784
  async (signal) => {
31785
+ if (!client) throw new RendererSessionImportUnavailableError();
30573
31786
  const missing = new Set(
30574
- getDiagnostics()?.snapshot().hosts.find(({ hostId: hostId2 }) => hostId2 === "local")?.agents.filter(({ availability }) => availability === "notInstalled").map(({ agent }) => agent)
31787
+ getDiagnostics()?.snapshot().hosts.find(({ hostId: hostId2 }) => hostId2 === (client.hostId ?? "local"))?.agents.filter(({ availability }) => availability === "notInstalled").map(({ agent }) => agent)
30575
31788
  );
30576
31789
  const harnesses = (await client.listSessionImportSources()).harnesses.filter(
30577
31790
  ({ harnessId }) => !missing.has(harnessId)
@@ -30589,6 +31802,7 @@ ${detail}` : ""}`
30589
31802
  },
30590
31803
  {
30591
31804
  success(result) {
31805
+ loadedClient = client;
30592
31806
  listControls.setBusy(false);
30593
31807
  if (listControls.setTotal(result.total)) {
30594
31808
  load();
@@ -30601,6 +31815,7 @@ ${detail}` : ""}`
30601
31815
  else renderCandidates();
30602
31816
  },
30603
31817
  failure(error51) {
31818
+ loadedClient = null;
30604
31819
  listControls.setBusy(false);
30605
31820
  candidates = [];
30606
31821
  refresh.disabled = false;
@@ -30610,6 +31825,19 @@ ${detail}` : ""}`
30610
31825
  }
30611
31826
  );
30612
31827
  };
31828
+ const selectHost = (hostId2) => {
31829
+ if (hostsLocked || !availableHostIds.includes(hostId2) || hostId2 === selectedHostId) return;
31830
+ selectedHostId = hostId2;
31831
+ selectedHarness = null;
31832
+ sources = [];
31833
+ candidates = [];
31834
+ actions = [];
31835
+ importStatus.replaceChildren();
31836
+ listControls.reset();
31837
+ renderHarnessOptions();
31838
+ load();
31839
+ hostButtons.find((button2) => button2.dataset.sessionImportHost === hostId2)?.focus();
31840
+ };
30613
31841
  refresh.addEventListener("click", load);
30614
31842
  load();
30615
31843
  return void 0;
@@ -30750,14 +31978,14 @@ ${detail}` : ""}`
30750
31978
  description: messages.idleReleaseTimeoutDescription,
30751
31979
  controlId: minutesId
30752
31980
  });
30753
- const { field, control: minutes } = createNumberField(document2, {
31981
+ const { field: field2, control: minutes } = createNumberField(document2, {
30754
31982
  id: minutesId,
30755
31983
  describedBy: timeout.description.id,
30756
31984
  unit: messages.idleReleaseMinutes,
30757
31985
  min: IDLE_RELEASE_TIMEOUT_MINUTES_MIN,
30758
31986
  max: IDLE_RELEASE_TIMEOUT_MINUTES_MAX
30759
31987
  });
30760
- timeout.item.append(field);
31988
+ timeout.item.append(field2);
30761
31989
  timeout.item.id = preferenceId("idle-release-timeout");
30762
31990
  enabled.setAttribute("aria-controls", timeout.item.id);
30763
31991
  card.append(toggle.item, timeout.item);
@@ -30778,7 +32006,7 @@ ${detail}` : ""}`
30778
32006
  statusText.textContent = value === "applied" ? "" : statusMessages[value];
30779
32007
  };
30780
32008
  const setInvalid = (invalid) => {
30781
- field.dataset.invalid = String(invalid);
32009
+ field2.dataset.invalid = String(invalid);
30782
32010
  timeout.description.dataset.invalid = String(invalid);
30783
32011
  timeout.description.textContent = invalid ? messages.idleReleaseInvalid : messages.idleReleaseTimeoutDescription;
30784
32012
  minutes.setAttribute("aria-invalid", String(invalid));
@@ -31103,7 +32331,7 @@ ${detail}` : ""}`
31103
32331
  }
31104
32332
  function defaultImportName(source, existing) {
31105
32333
  const base = source.provider === "openai-codex" ? "codex" : "grok";
31106
- const used = new Set(existing.map((record5) => record5.name));
32334
+ const used = new Set(existing.map((record6) => record6.name));
31107
32335
  const valid = (name) => credentialImportNameSchema.safeParse(name).success;
31108
32336
  if (!used.has(base)) return base;
31109
32337
  const local = source.label.includes("@") ? source.label.split("@")[0] ?? "" : "";
@@ -31126,7 +32354,7 @@ ${detail}` : ""}`
31126
32354
  const shown = (text) => accountDisplayText(text, hideEmails);
31127
32355
  const targetButtons = /* @__PURE__ */ new Map();
31128
32356
  const importedRecords = () => snapshot.targets.find((target) => target.harnessId === TARGET_HARNESS_ID)?.imports ?? [];
31129
- const sourceOf = (record5) => snapshot.sources.find((source) => source.id === record5.source.id);
32357
+ const sourceOf = (record6) => snapshot.sources.find((source) => source.id === record6.source.id);
31130
32358
  const piTarget = () => snapshot.targets.find((candidate) => candidate.harnessId === TARGET_HARNESS_ID);
31131
32359
  const compatibleSources = () => {
31132
32360
  const target = piTarget();
@@ -31164,7 +32392,7 @@ ${detail}` : ""}`
31164
32392
  sectionImport.addEventListener("click", () => {
31165
32393
  const sources = compatibleSources();
31166
32394
  const free = sources.find(
31167
- (source2) => !importedRecords().some((record5) => record5.source.id === source2.id)
32395
+ (source2) => !importedRecords().some((record6) => record6.source.id === source2.id)
31168
32396
  );
31169
32397
  const source = free ?? sources[0];
31170
32398
  if (source) openDialog("add", { source, choose: true }, SECTION_IMPORT_KEY);
@@ -31214,30 +32442,30 @@ ${detail}` : ""}`
31214
32442
  mark.append(createRendererAgentIcon(agent ?? "pi", 26, document2, pluginFor(agent ?? "pi")));
31215
32443
  return mark;
31216
32444
  };
31217
- const renderRow = (record5) => {
32445
+ const renderRow = (record6) => {
31218
32446
  const row = document2.createElement("div");
31219
32447
  row.className = "settings-pi-accounts__row";
31220
32448
  row.tabIndex = -1;
31221
- row.dataset.importName = record5.name;
31222
- row.setAttribute("aria-label", shown(record5.source.label));
31223
- const agent = record5.source.harnessId;
32449
+ row.dataset.importName = record6.name;
32450
+ row.setAttribute("aria-label", shown(record6.source.label));
32451
+ const agent = record6.source.harnessId;
31224
32452
  const mark = createMark(agent);
31225
32453
  const identity = document2.createElement("div");
31226
32454
  identity.className = "settings-pi-accounts__identity";
31227
32455
  const label = document2.createElement("strong");
31228
32456
  label.className = "settings-account-email";
31229
- label.textContent = shown(record5.source.label);
32457
+ label.textContent = shown(record6.source.label);
31230
32458
  label.title = label.textContent;
31231
32459
  label.translate = false;
31232
32460
  const meta3 = document2.createElement("div");
31233
32461
  meta3.className = "settings-account-metadata";
31234
- const source = sourceOf(record5);
32462
+ const source = sourceOf(record6);
31235
32463
  const parts = [
31236
32464
  metaPart(rendererAgentLabel(agent, pluginFor(agent)), "settings-pi-accounts__agent"),
31237
- metaPart(`${record5.name}/\u2026`, void 0, true),
32465
+ metaPart(`${record6.name}/\u2026`, void 0, true),
31238
32466
  metaPart(messages.copied)
31239
32467
  ];
31240
- const time3 = formatImportedAt(record5.importedAt);
32468
+ const time3 = formatImportedAt(record6.importedAt);
31241
32469
  if (time3) parts.push(metaPart(time3));
31242
32470
  parts.forEach((part, index) => {
31243
32471
  if (index > 0) {
@@ -31254,23 +32482,23 @@ ${detail}` : ""}`
31254
32482
  reimport.type = "button";
31255
32483
  reimport.className = "settings-account-action";
31256
32484
  reimport.textContent = messages.rowReimport;
31257
- reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record5.source.label)}`);
32485
+ reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record6.source.label)}`);
31258
32486
  reimport.disabled = busy || !source;
31259
32487
  reimport.title = messages.reimport;
31260
32488
  reimport.addEventListener("click", () => {
31261
- if (source) openDialog("reimport", { source, record: record5 }, `row:${record5.name}`);
32489
+ if (source) openDialog("reimport", { source, record: record6 }, `row:${record6.name}`);
31262
32490
  });
31263
32491
  const remove = document2.createElement("button");
31264
32492
  remove.type = "button";
31265
32493
  remove.className = "settings-account-action settings-pi-accounts__remove";
31266
32494
  remove.textContent = messages.rowRemove;
31267
- remove.setAttribute("aria-label", `${messages.remove}: ${shown(record5.source.label)}`);
32495
+ remove.setAttribute("aria-label", `${messages.remove}: ${shown(record6.source.label)}`);
31268
32496
  remove.disabled = busy;
31269
- remove.addEventListener("click", () => openDialog("remove", { record: record5 }, `row:${record5.name}`));
32497
+ remove.addEventListener("click", () => openDialog("remove", { record: record6 }, `row:${record6.name}`));
31270
32498
  if (source) actions.append(reimport);
31271
32499
  actions.append(remove);
31272
32500
  row.append(mark, identity, actions);
31273
- rows.set(record5.name, row);
32501
+ rows.set(record6.name, row);
31274
32502
  return row;
31275
32503
  };
31276
32504
  const loginTypeLabel = (type) => type === "oauth" ? messages.typeOauth : type === "api_key" ? messages.typeApiKey : messages.typeOther;
@@ -31423,7 +32651,7 @@ ${detail}` : ""}`
31423
32651
  const label = document2.createElement("strong");
31424
32652
  label.textContent = shown(choice.label);
31425
32653
  label.translate = false;
31426
- const existing = importedRecords().find((record5) => record5.source.id === choice.id);
32654
+ const existing = importedRecords().find((record6) => record6.source.id === choice.id);
31427
32655
  const agent = choice.harnessId;
31428
32656
  const detail = document2.createElement("span");
31429
32657
  detail.textContent = [
@@ -31464,7 +32692,7 @@ ${detail}` : ""}`
31464
32692
  const name = request.action === "list" ? void 0 : request.name;
31465
32693
  state = {
31466
32694
  source: state.source,
31467
- record: importedRecords().find((record5) => record5.name === name) ?? state.record
32695
+ record: importedRecords().find((record6) => record6.name === name) ?? state.record
31468
32696
  };
31469
32697
  show(next);
31470
32698
  } else {
@@ -31478,12 +32706,12 @@ ${detail}` : ""}`
31478
32706
  sourceRadios = [];
31479
32707
  body.replaceChildren();
31480
32708
  controls.replaceChildren();
31481
- const { source, record: record5 } = state;
32709
+ const { source, record: record6 } = state;
31482
32710
  const close = () => modal.close();
31483
32711
  if (mode === "add" || mode === "reimport") {
31484
32712
  title.textContent = mode === "add" ? messages.add : messages.reimport;
31485
32713
  modal.setAttribute("aria-label", title.textContent);
31486
- const active = source ?? record5?.source;
32714
+ const active = source ?? record6?.source;
31487
32715
  const choices = mode === "add" && state.choose ? compatibleSources() : [];
31488
32716
  if (choices.length > 1) body.append(sourcePicker(choices));
31489
32717
  else if (active) body.append(line(messages.source, shown(active.label)));
@@ -31492,8 +32720,8 @@ ${detail}` : ""}`
31492
32720
  input.maxLength = 48;
31493
32721
  input.autocomplete = "off";
31494
32722
  input.spellcheck = false;
31495
- input.value = record5?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
31496
- input.readOnly = Boolean(record5);
32723
+ input.value = record6?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
32724
+ input.readOnly = Boolean(record6);
31497
32725
  input.addEventListener("input", () => {
31498
32726
  nameEdited = true;
31499
32727
  });
@@ -31527,7 +32755,7 @@ ${detail}` : ""}`
31527
32755
  {
31528
32756
  action: mode === "reimport" ? "reimport" : "import",
31529
32757
  sourceId: source2.id,
31530
- name: record5?.name ?? input.value,
32758
+ name: record6?.name ?? input.value,
31531
32759
  confirmed: true
31532
32760
  },
31533
32761
  "done"
@@ -31537,16 +32765,16 @@ ${detail}` : ""}`
31537
32765
  )
31538
32766
  );
31539
32767
  (mode === "add" ? input : controls.children[0]).focus();
31540
- } else if (mode === "remove" && record5) {
32768
+ } else if (mode === "remove" && record6) {
31541
32769
  title.textContent = messages.remove;
31542
32770
  modal.setAttribute("aria-label", title.textContent);
31543
- body.append(note(messages.removeWarning.replace("{name}", record5.name)));
32771
+ body.append(note(messages.removeWarning.replace("{name}", record6.name)));
31544
32772
  const cancel = command(messages.cancel, close);
31545
32773
  controls.append(
31546
32774
  cancel,
31547
32775
  command(
31548
32776
  messages.remove,
31549
- () => submit({ action: "remove", name: record5.name, confirmed: true }, null),
32777
+ () => submit({ action: "remove", name: record6.name, confirmed: true }, null),
31550
32778
  "danger"
31551
32779
  )
31552
32780
  );
@@ -31554,7 +32782,7 @@ ${detail}` : ""}`
31554
32782
  } else {
31555
32783
  title.textContent = messages.doneTitle;
31556
32784
  modal.setAttribute("aria-label", title.textContent);
31557
- const name = record5?.name;
32785
+ const name = record6?.name;
31558
32786
  if (name) body.append(line(messages.entry, `${name}/\u2026`, true));
31559
32787
  body.append(note(messages.done));
31560
32788
  const done = command(messages.close, close, "primary");
@@ -31601,21 +32829,21 @@ ${detail}` : ""}`
31601
32829
  (candidate) => candidate.harnessId === TARGET_HARNESS_ID && source && candidate.providers.includes(source.provider)
31602
32830
  );
31603
32831
  if (!source || !target) return null;
31604
- const record5 = target.imports.find((candidate) => candidate.source.id === source.id);
32832
+ const record6 = target.imports.find((candidate) => candidate.source.id === source.id);
31605
32833
  const key = `${harnessId}:${accountLabel}:import`;
31606
32834
  const button2 = document2.createElement("button");
31607
32835
  button2.type = "button";
31608
32836
  button2.className = "settings-account-pi-import";
31609
32837
  button2.dataset.accountFocus = key;
31610
32838
  button2.disabled = busy;
31611
- const hint = record5 ? messages.importedHint.replace("{name}", record5.name) : messages.add;
32839
+ const hint = record6 ? messages.importedHint.replace("{name}", record6.name) : messages.add;
31612
32840
  button2.title = hint;
31613
32841
  button2.setAttribute("aria-label", hint);
31614
32842
  button2.append(createRendererAgentIcon("pi", 12, document2, pluginFor("pi")));
31615
- if (record5) {
32843
+ if (record6) {
31616
32844
  button2.dataset.state = "imported";
31617
32845
  const name = document2.createElement("code");
31618
- name.textContent = `${record5.name}/\u2026`;
32846
+ name.textContent = `${record6.name}/\u2026`;
31619
32847
  name.translate = false;
31620
32848
  button2.append(name, createRendererSettingsIcon("check", 12));
31621
32849
  } else {
@@ -31623,7 +32851,7 @@ ${detail}` : ""}`
31623
32851
  button2.append(messages.add);
31624
32852
  }
31625
32853
  button2.addEventListener("click", () => {
31626
- if (!record5) {
32854
+ if (!record6) {
31627
32855
  openDialog("add", { source }, key);
31628
32856
  return;
31629
32857
  }
@@ -31632,7 +32860,7 @@ ${detail}` : ""}`
31632
32860
  renderSection();
31633
32861
  sectionToggle.setAttribute("aria-expanded", "true");
31634
32862
  }
31635
- const row = rows.get(record5.name);
32863
+ const row = rows.get(record6.name);
31636
32864
  row?.scrollIntoView({ block: "nearest", behavior: "smooth" });
31637
32865
  row?.focus();
31638
32866
  });
@@ -33177,7 +34405,7 @@ ${detail}` : ""}`
33177
34405
  }
33178
34406
  });
33179
34407
  }
33180
- function createDefaultRendererSettingsPages(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread = () => Promise.reject(new Error("Imported Thread navigation is unavailable")), getLoadedSessionsClient = () => null, getRemoteConnections = () => null, requestUsageStatistics = () => Promise.reject(new Error("Local Host connection is unavailable"))) {
34408
+ function createDefaultRendererSettingsPages(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread = () => Promise.reject(new Error("Imported Thread navigation is unavailable")), getLoadedSessionsClient = () => null, getRemoteConnections = () => null, requestUsageStatistics = () => Promise.reject(new Error("Local Host connection is unavailable")), usageStatisticsHosts) {
33181
34409
  return Object.freeze([
33182
34410
  createConnectionsSettingsPage(messages, getDiagnostics, void 0, getRemoteConnections),
33183
34411
  createRemoteConnectionsPage(messages, getRemoteConnections),
@@ -33191,14 +34419,15 @@ ${detail}` : ""}`
33191
34419
  createUsageStatisticsPage(
33192
34420
  consoleMessages(messages.locale),
33193
34421
  requestUsageStatistics,
33194
- messages.locale
34422
+ messages.locale,
34423
+ usageStatisticsHosts
33195
34424
  ),
33196
34425
  createAppearanceSettingsPage(messages, getLoadedSessionsClient),
33197
34426
  updatesPage(messages, getUpdateClient),
33198
34427
  aboutPage(messages, getUpdateClient)
33199
34428
  ]);
33200
34429
  }
33201
- function createDefaultRendererSettingsRegistry(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread, requestUsageStatistics) {
34430
+ function createDefaultRendererSettingsRegistry(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread, requestUsageStatistics, usageStatisticsHosts) {
33202
34431
  return createRendererSettingsPageRegistry(
33203
34432
  createDefaultRendererSettingsPages(
33204
34433
  messages,
@@ -33209,7 +34438,8 @@ ${detail}` : ""}`
33209
34438
  openImportedThread,
33210
34439
  void 0,
33211
34440
  void 0,
33212
- requestUsageStatistics
34441
+ requestUsageStatistics,
34442
+ usageStatisticsHosts
33213
34443
  )
33214
34444
  );
33215
34445
  }
@@ -33765,6 +34995,41 @@ ${detail}` : ""}`
33765
34995
  margin-top: 0;
33766
34996
  }
33767
34997
 
34998
+ .settings-session-import-host {
34999
+ display: flex;
35000
+ align-items: center;
35001
+ min-width: 0;
35002
+ gap: 12px;
35003
+ margin: -12px 0 12px;
35004
+ color: var(--settings-muted);
35005
+ font-size: 13px;
35006
+ }
35007
+
35008
+ .settings-session-import-host > span,
35009
+ .settings-session-import-host + .settings-session-import-harness > span {
35010
+ flex: none;
35011
+ min-width: 60px;
35012
+ }
35013
+
35014
+ .settings-session-import-host > .settings-connection-host-tabs {
35015
+ flex: 1;
35016
+ }
35017
+
35018
+ .settings-session-import-host .settings-connection-host-tab {
35019
+ height: 34px;
35020
+ padding: 0 12px;
35021
+ font-size: 13px;
35022
+ }
35023
+
35024
+ .settings-session-import-host .settings-connection-host-tab:disabled {
35025
+ opacity: 0.38;
35026
+ cursor: not-allowed;
35027
+ }
35028
+
35029
+ .settings-session-import-host + .settings-session-import-harness {
35030
+ margin-top: 0;
35031
+ }
35032
+
33768
35033
  .settings-session-import-search,
33769
35034
  .settings-session-import-pagination {
33770
35035
  display: flex;
@@ -33983,6 +35248,20 @@ ${detail}` : ""}`
33983
35248
  gap: 18px;
33984
35249
  }
33985
35250
 
35251
+ .settings-connections-content {
35252
+ container: settings-connections / inline-size;
35253
+ }
35254
+
35255
+ @container settings-connections (max-width: 780px) {
35256
+ .settings-connections-layout {
35257
+ grid-template-columns: minmax(0, 1fr);
35258
+ }
35259
+
35260
+ .settings-connection-inspector {
35261
+ position: static;
35262
+ }
35263
+ }
35264
+
33986
35265
  .settings-connection-list,
33987
35266
  .settings-connection-inspector {
33988
35267
  overflow: hidden;
@@ -33991,14 +35270,36 @@ ${detail}` : ""}`
33991
35270
  border-radius: 10px;
33992
35271
  }
33993
35272
 
35273
+ .settings-connection-host-header {
35274
+ display: flex;
35275
+ align-items: center;
35276
+ min-width: 0;
35277
+ border-bottom: 1px solid var(--settings-divider);
35278
+ }
35279
+
35280
+ .settings-connection-update-all {
35281
+ flex: none;
35282
+ margin-right: 10px;
35283
+ white-space: nowrap;
35284
+ }
35285
+
35286
+ .settings-connection-update-result {
35287
+ margin: 0;
35288
+ padding: 7px 10px;
35289
+ color: var(--settings-muted);
35290
+ font-size: 11px;
35291
+ line-height: 18px;
35292
+ border-bottom: 1px solid var(--settings-divider);
35293
+ }
35294
+
33994
35295
  .settings-connection-host-strip {
33995
35296
  display: grid;
35297
+ flex: 1;
33996
35298
  grid-template-columns: 30px minmax(0, 1fr) 30px;
33997
35299
  align-items: center;
33998
35300
  min-width: 0;
33999
35301
  gap: 5px;
34000
35302
  padding: 9px 10px;
34001
- border-bottom: 1px solid var(--settings-divider);
34002
35303
  }
34003
35304
 
34004
35305
  .settings-connection-host-scroll {
@@ -34085,7 +35386,8 @@ ${detail}` : ""}`
34085
35386
  background: var(--settings-hover);
34086
35387
  }
34087
35388
 
34088
- .settings-connection-host-tab[aria-selected="true"] {
35389
+ .settings-connection-host-tab[aria-selected="true"],
35390
+ .settings-connection-host-tab[aria-pressed="true"] {
34089
35391
  color: var(--settings-text);
34090
35392
  font-weight: 600;
34091
35393
  background: var(--settings-active);
@@ -34095,7 +35397,7 @@ ${detail}` : ""}`
34095
35397
  .settings-connection-table-header,
34096
35398
  .settings-connection-row {
34097
35399
  display: grid;
34098
- grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) 108px;
35400
+ grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) minmax(108px, max-content);
34099
35401
  align-items: center;
34100
35402
  min-width: 0;
34101
35403
  gap: 10px;
@@ -34188,6 +35490,14 @@ ${detail}` : ""}`
34188
35490
  line-height: 18px;
34189
35491
  }
34190
35492
 
35493
+ .settings-connection-version-available {
35494
+ flex: none;
35495
+ color: var(--settings-muted);
35496
+ font-size: 10px;
35497
+ line-height: 16px;
35498
+ white-space: nowrap;
35499
+ }
35500
+
34191
35501
  .settings-connection-row__status::before {
34192
35502
  width: 6px;
34193
35503
  height: 6px;
@@ -34224,6 +35534,7 @@ ${detail}` : ""}`
34224
35534
  justify-content: flex-end;
34225
35535
  min-width: 0;
34226
35536
  gap: 4px;
35537
+ white-space: nowrap;
34227
35538
  }
34228
35539
 
34229
35540
  .settings-connection-row__handle {
@@ -38372,16 +39683,17 @@ ${usage_default}`;
38372
39683
  options.getConnectionDiagnostics ?? (() => null),
38373
39684
  options.getAccountClient ?? (() => null),
38374
39685
  options.getSessionImportClient ?? (() => null),
38375
- async (threadId, signal) => {
39686
+ async (threadId, signal, hostId2) => {
38376
39687
  if (!options.openImportedThread) {
38377
39688
  throw new Error("Imported Thread navigation is unavailable");
38378
39689
  }
38379
- await options.openImportedThread(threadId, signal);
39690
+ await options.openImportedThread(threadId, signal, hostId2);
38380
39691
  if (!disposed && !signal.aborted) shell?.close();
38381
39692
  },
38382
39693
  options.getLoadedSessionsClient ?? (() => null),
38383
39694
  options.getRemoteConnections ?? (() => null),
38384
- options.requestUsageStatistics
39695
+ options.requestUsageStatistics,
39696
+ options.usageStatisticsHosts
38385
39697
  );
38386
39698
  const nextShell = installRendererSettingsShell(definitions, messages, ownerWindow.document, {
38387
39699
  onOpenChange(open) {
@@ -38530,6 +39842,30 @@ ${usage_default}`;
38530
39842
  };
38531
39843
  }
38532
39844
 
39845
+ // src/renderer-usage-statistics-source.ts
39846
+ function createRendererUsageStatisticsSource(options) {
39847
+ return {
39848
+ async request(method, params, hostId2) {
39849
+ const route = options.routing()?.forHost(hostId2);
39850
+ if (options.disposed() || !route) {
39851
+ throw new Error(`Host connection is unavailable (${hostId2})`);
39852
+ }
39853
+ return route.manager.sendRequest(method, params);
39854
+ },
39855
+ async hosts() {
39856
+ const connections = await options.listConnections().catch(() => []);
39857
+ const names = new Map(
39858
+ connections.map((connection) => [connection.hostId, connection.displayName])
39859
+ );
39860
+ const known = options.routing()?.knownHostIds?.() ?? [];
39861
+ return [.../* @__PURE__ */ new Set([...known, ...names.keys()])].map((hostId2) => {
39862
+ const label = names.get(hostId2);
39863
+ return label === void 0 ? { hostId: hostId2 } : { hostId: hostId2, label };
39864
+ });
39865
+ }
39866
+ };
39867
+ }
39868
+
38533
39869
  // src/renderer-native-composer-controller.ts
38534
39870
  var MAX_ELEMENT_DEPTH = 4;
38535
39871
  var MAX_FIBER_DEPTH = 40;
@@ -39365,9 +40701,13 @@ ${usage_default}`;
39365
40701
  function mutationMayAffectComposer(mutation) {
39366
40702
  const target = mutation.target instanceof Element ? mutation.target : mutation.target.parentElement;
39367
40703
  if (!target) return true;
39368
- if (mutation.type === "attributes" && mutation.attributeName === "data-codex-composer-root")
40704
+ if (mutation.type === "attributes" && (mutation.attributeName === "data-codex-composer-root" || NATIVE_COMPOSER_REQUEST_ATTRIBUTES.some((attribute) => attribute === mutation.attributeName)))
39369
40705
  return true;
39370
- if (mutation.type !== "attributes" && editorForElement(target)) return false;
40706
+ if (mutation.type !== "attributes" && editorForElement(target)) {
40707
+ return mutation.type === "childList" && [...mutation.addedNodes, ...mutation.removedNodes].some(
40708
+ (node) => node instanceof Element && hasNativeComposerRequest(node)
40709
+ );
40710
+ }
39371
40711
  if (target.closest(CODEX_COMPOSER_SELECTOR)) return true;
39372
40712
  if (mutation.type === "characterData") return false;
39373
40713
  if (!target.closest(
@@ -39458,30 +40798,35 @@ ${usage_default}`;
39458
40798
  });
39459
40799
  let connectionDiagnostics = null;
39460
40800
  const remoteConnections = createRemoteConnectionsControl(window, modelClientForHost);
40801
+ const usageStatistics = createRendererUsageStatisticsSource({
40802
+ routing: () => window.__codexhostHostRoutingV1,
40803
+ listConnections: () => remoteConnections.ssh.list(),
40804
+ disposed: () => disposed
40805
+ });
39461
40806
  const settingsLifecycle = installRendererSettingsLifecycle(window, {
39462
40807
  getRemoteConnections: () => remoteConnections,
39463
40808
  getUpdateClient: () => modelControl,
39464
40809
  getAccountClient: () => modelControl,
39465
40810
  getConnectionDiagnostics: () => connectionDiagnostics,
39466
40811
  getLoadedSessionsClient: () => modelClientForHost("local"),
39467
- async requestUsageStatistics(method, params) {
39468
- const route = window.__codexhostHostRoutingV1?.forHost("local");
39469
- if (disposed || !route) throw new Error("Local Host connection is unavailable");
39470
- return route.manager.sendRequest(method, params);
39471
- },
39472
- getSessionImportClient: () => {
39473
- const client = modelClientForHost("local");
40812
+ requestUsageStatistics: usageStatistics.request,
40813
+ usageStatisticsHosts: usageStatistics.hosts,
40814
+ getSessionImportClient: (requestedHostId) => {
40815
+ const hostId2 = requestedHostId ?? activeModelHostId();
40816
+ if (!hostId2) return null;
40817
+ const client = modelClientForHost(hostId2);
39474
40818
  const sources = client?.listSessionImportSources;
39475
40819
  const list = client?.listHarnessSessions;
39476
40820
  const importSession = client?.importHarnessSession;
39477
40821
  if (!sources || !list || !importSession) return null;
39478
40822
  return {
40823
+ hostId: hostId2,
39479
40824
  listSessionImportSources: () => sources(),
39480
40825
  listHarnessSessions: (input) => list(input),
39481
40826
  importHarnessSession: (input) => importSession(input)
39482
40827
  };
39483
40828
  },
39484
- openImportedThread: (threadId, signal) => openRendererThread(threadId, { hostId: "local", signal }),
40829
+ openImportedThread: (threadId, signal, hostId2) => openRendererThread(threadId, { hostId: hostId2 ?? "local", signal }),
39485
40830
  onLocaleChange() {
39486
40831
  for (const mounted of mountedByComposer.values()) renderMounted(mounted);
39487
40832
  }
@@ -39552,7 +40897,7 @@ ${usage_default}`;
39552
40897
  const ownershipRecovery = /* @__PURE__ */ new WeakMap();
39553
40898
  const modelRecovery = /* @__PURE__ */ new WeakMap();
39554
40899
  const isRetainedComposer = (mounted) => mounted.composer.isConnected && mounted.composer.matches(CODEX_COMPOSER_SELECTOR) && mountedByComposer.get(mounted.composer) === mounted;
39555
- const isMountedComposer = (composer) => composer.isConnected && composer.matches(CODEX_COMPOSER_SELECTOR) && orbitComposerKind(composer) === "codex" && mountedByComposer.has(composer);
40900
+ const isMountedComposer = (composer) => composer.isConnected && composer.matches(CODEX_COMPOSER_SELECTOR) && !hasNativeComposerRequest(composer) && orbitComposerKind(composer) === "codex" && mountedByComposer.has(composer);
39556
40901
  const isCurrentModelRequest = (mounted, generation) => isMountedComposer(mounted.composer) && mountedByComposer.get(mounted.composer) === mounted && controller.isCurrentModelRequest(mounted.composer, generation);
39557
40902
  const isCurrentOwnershipRequest = (mounted, generation) => isMountedComposer(mounted.composer) && mountedByComposer.get(mounted.composer) === mounted && controller.isCurrentOwnershipRequest(mounted.composer, generation);
39558
40903
  const finishModelRequest = (mounted, generation) => {
@@ -39565,9 +40910,10 @@ ${usage_default}`;
39565
40910
  };
39566
40911
  const notifySubmission = (composer, trigger) => {
39567
40912
  const state = controller.recordSubmission(composer);
40913
+ const createsThread = state.phase === "draft";
39568
40914
  const preferenceStorage = rendererNewThreadPreferenceStorage(activeModelHostId(composer));
39569
- writeNewThreadAgentPreference(state.agent, preferenceStorage);
39570
- if (state.agent !== "codex") {
40915
+ if (createsThread) writeNewThreadAgentPreference(state.agent, preferenceStorage);
40916
+ if (createsThread && state.agent !== "codex") {
39571
40917
  const model2 = controller.modelForAgent(composer, state.agent);
39572
40918
  if (model2) {
39573
40919
  writeNewThreadExternalConfigurationPreference(
@@ -40706,7 +42052,7 @@ ${usage_default}`;
40706
42052
  let webUiAvailable = false;
40707
42053
  try {
40708
42054
  const inspection = await client.inspectHarness(
40709
- { harnessId: harnessIdSchema.parse(agent), refresh },
42055
+ { harnessId: harnessIdSchema.parse(agent), refresh, purpose: "availability" },
40710
42056
  { priority: "background" }
40711
42057
  );
40712
42058
  status = inspection.status === "ready" ? "ready" : inspection.status;
@@ -40946,10 +42292,10 @@ ${usage_default}`;
40946
42292
  }
40947
42293
  };
40948
42294
  const mount = (composer) => {
40949
- if (mountedByComposer.has(composer) || !composer.isConnected || orbitComposerKind(composer) !== "codex" || !composer.matches(CODEX_COMPOSER_SELECTOR)) {
42295
+ if (mountedByComposer.has(composer) || !composer.isConnected || hasNativeComposerRequest(composer) || orbitComposerKind(composer) !== "codex" || !composer.matches(CODEX_COMPOSER_SELECTOR)) {
40950
42296
  return;
40951
42297
  }
40952
- const allButtons = [...composer.querySelectorAll("button")];
42298
+ const allButtons = composerButtonsWithin(composer);
40953
42299
  const sendButton = sendButtonWithin(composer) ?? allButtons.at(-1) ?? null;
40954
42300
  if (!sendButton) return;
40955
42301
  const modelTarget = findComposerModelTarget(composer);
@@ -41044,7 +42390,7 @@ ${usage_default}`;
41044
42390
  const sourceState = controller.get(replacement.source.composer);
41045
42391
  const replacementTarget = findComposerModelTarget(target);
41046
42392
  const replacementHostId = activeModelHostId(target);
41047
- if (orbitComposerKind(target) !== "codex" || !shouldTransferComposerState(
42393
+ if (hasNativeComposerRequest(target) || orbitComposerKind(target) !== "codex" || !shouldTransferComposerState(
41048
42394
  replacement.sourceModelTarget,
41049
42395
  replacementTarget,
41050
42396
  sourceState.phase,
@@ -41061,7 +42407,7 @@ ${usage_default}`;
41061
42407
  }
41062
42408
  for (const [composer, mounted] of mountedByComposer) {
41063
42409
  const kind = orbitComposerKind(composer);
41064
- if (!composer.isConnected || kind === "orbit" || !composer.matches(CODEX_COMPOSER_SELECTOR) || !mounted.control.root.isConnected) {
42410
+ if (!composer.isConnected || hasNativeComposerRequest(composer) || kind === "orbit" || !composer.matches(CODEX_COMPOSER_SELECTOR) || !mounted.control.root.isConnected) {
41065
42411
  mounted.usageRequestGeneration += 1;
41066
42412
  usageRefreshAttempts.delete(composer);
41067
42413
  const timer = usageRefreshTimers.get(composer);
@@ -41110,6 +42456,7 @@ ${usage_default}`;
41110
42456
  void refreshHarnessAvailability();
41111
42457
  }
41112
42458
  pendingReplacements.clear();
42459
+ questions.refreshContext();
41113
42460
  };
41114
42461
  const scheduleScan = (refreshTargets = false) => {
41115
42462
  refreshTargetsOnNextScan ||= refreshTargets;
@@ -41293,7 +42640,12 @@ ${usage_default}`;
41293
42640
  };
41294
42641
  mutationObserver.observe(document.documentElement, {
41295
42642
  attributes: true,
41296
- attributeFilter: ["hidden", "aria-hidden", "data-codex-composer-root"],
42643
+ attributeFilter: [
42644
+ "hidden",
42645
+ "aria-hidden",
42646
+ "data-codex-composer-root",
42647
+ ...NATIVE_COMPOSER_REQUEST_ATTRIBUTES
42648
+ ],
41297
42649
  characterData: true,
41298
42650
  childList: true,
41299
42651
  subtree: true
@@ -41390,6 +42742,16 @@ ${usage_default}`;
41390
42742
  const connectedComposers = () => [...mountedByComposer.values()].filter(
41391
42743
  (mounted) => isMountedComposer(mounted.composer) && mounted.control.root.isConnected
41392
42744
  );
42745
+ const questions = installRendererQuestions(window, () => {
42746
+ const visible = connectedComposers().filter(
42747
+ (mounted2) => mounted2.composer.getClientRects().length > 0 && window.getComputedStyle(mounted2.composer).visibility === "visible" && !mounted2.composer.closest('[hidden], [inert], [aria-hidden="true"]') && controller.get(mounted2.composer).agent !== "codex"
42748
+ );
42749
+ const mounted = visible.length === 1 ? visible[0] : void 0;
42750
+ const threadId = mounted ? threadIdFromComposerModelTarget(findComposerModelTarget(mounted.composer)) : null;
42751
+ const hostId2 = mounted?.hostId;
42752
+ const route = hostId2 ? window.__codexhostHostRoutingV1?.forHost(hostId2) : null;
42753
+ return mounted && threadId && hostId2 && route ? { hostId: hostId2, threadId, composer: mounted.composer, route: route.manager } : null;
42754
+ });
41393
42755
  const api = {
41394
42756
  remoteConnections: (request) => handleRemoteConnectionsRequest(remoteConnections, request),
41395
42757
  currentThreadId() {
@@ -41481,6 +42843,7 @@ ${usage_default}`;
41481
42843
  dispose() {
41482
42844
  if (disposed) return;
41483
42845
  disposed = true;
42846
+ questions.dispose();
41484
42847
  usageNotificationDispose();
41485
42848
  adapterDispose?.();
41486
42849
  adapterDispose = null;
@@ -41561,6 +42924,10 @@ ${usage_default}`;
41561
42924
 
41562
42925
  lucide/dist/esm/defaultAttributes.mjs:
41563
42926
  lucide/dist/esm/createElement.mjs:
42927
+ lucide/dist/esm/icons/check.mjs:
42928
+ lucide/dist/esm/icons/message-circle-question-mark.mjs:
42929
+ lucide/dist/esm/icons/pencil.mjs:
42930
+ lucide/dist/esm/icons/x.mjs:
41564
42931
  lucide/dist/esm/icons/boxes.mjs:
41565
42932
  lucide/dist/esm/icons/circle-check.mjs:
41566
42933
  lucide/dist/esm/icons/chevron-down.mjs:
@@ -41596,11 +42963,10 @@ lucide/dist/esm/icons/terminal.mjs:
41596
42963
  lucide/dist/esm/icons/scroll-text.mjs:
41597
42964
  lucide/dist/esm/icons/search.mjs:
41598
42965
  lucide/dist/esm/icons/circle-question-mark.mjs:
41599
- lucide/dist/esm/icons/x.mjs:
41600
42966
  lucide/dist/esm/icons/users.mjs:
41601
42967
  lucide/dist/esm/icons/plus.mjs:
41602
42968
  lucide/dist/esm/icons/circle-alert.mjs:
41603
- lucide/dist/esm/icons/check.mjs:
42969
+ lucide/dist/esm/icons/activity.mjs:
41604
42970
  lucide/dist/esm/icons/lock.mjs:
41605
42971
  lucide/dist/esm/icons/shield.mjs:
41606
42972
  lucide/dist/esm/icons/shield-alert.mjs: