@karlorz/codexhost-cli-linux-arm64 0.13.3-7 → 0.14.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14700,10 +14700,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14700
14700
  var project = external_exports.string().min(1).max(4096);
14701
14701
  var usageStatisticsParamsSchema = external_exports.strictObject({
14702
14702
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14703
+ /** Display timezone for ranges, dates and hourly buckets; omitted means the Host's local zone. */
14704
+ timeZone: external_exports.string().min(1).max(128).refine((value) => {
14705
+ try {
14706
+ new Intl.DateTimeFormat("en", { timeZone: value });
14707
+ return true;
14708
+ } catch {
14709
+ return false;
14710
+ }
14711
+ }, "Unsupported usage statistics timezone").optional(),
14703
14712
  harness: harness.optional(),
14704
14713
  model: model.nullable().optional(),
14705
14714
  project: project.nullable().optional(),
14706
- /** One local date inside the range. */
14715
+ /** One date in the query timezone inside the range. */
14707
14716
  date: localDate.optional()
14708
14717
  });
14709
14718
  var usageStatisticsTotalsSchema = external_exports.strictObject({
@@ -14739,7 +14748,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14739
14748
  });
14740
14749
  var usageStatisticsResultSchema = external_exports.strictObject({
14741
14750
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14742
- /** First local date of the range; null for all time. */
14751
+ /** First date in the query timezone (Host local when omitted); null for all time. */
14743
14752
  from: localDate.nullable(),
14744
14753
  to: localDate,
14745
14754
  /** The filters these figures apply, echoed so a late answer to older filters is recognised. */
@@ -14779,7 +14788,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14779
14788
  totals: usageStatisticsTotalsSchema,
14780
14789
  /** Each date and Harness of the range: every filter except the day. */
14781
14790
  daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
14782
- /** Local weekday (0 = Sunday) and hour, all filters applied. */
14791
+ /** Weekday (0 = Sunday) and hour in the query timezone, all filters applied. */
14783
14792
  hourly: external_exports.array(external_exports.strictObject({
14784
14793
  weekday: external_exports.number().int().min(0).max(6),
14785
14794
  hour: external_exports.number().int().min(0).max(23),
@@ -14890,6 +14899,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14890
14899
  "codexhost/harness/display-settings/set",
14891
14900
  "codexhost/harness/inspect",
14892
14901
  "codexhost/harness/installation",
14902
+ "codexhost/harness/installation/start",
14903
+ "codexhost/harness/installation/status",
14893
14904
  "codexhost/harness/launch-settings/get",
14894
14905
  "codexhost/harness/launch-settings/set",
14895
14906
  "codexhost/harness/grok-computer-use/get",
@@ -14970,7 +14981,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14970
14981
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
14971
14982
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
14972
14983
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
14984
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
14985
+ var composerIndicatorsSchema = external_exports.array(external_exports.object({
14986
+ kind: external_exports.literal("countdown"),
14987
+ id: external_exports.string().min(1).max(64),
14988
+ expiresAtUnix: nonNegativeSafeIntegerSchema,
14989
+ label: indicatorTextSchema(256).optional(),
14990
+ tooltip: indicatorTextSchema(1024).optional()
14991
+ }).strict()).max(2).refine((entries) => new Set(entries.map(({ id }) => id)).size === entries.length, {
14992
+ message: "Composer indicator IDs must be unique"
14993
+ });
14973
14994
  var threadUsageSnapshotSchema = external_exports.object({
14995
+ composerIndicators: composerIndicatorsSchema.optional(),
14974
14996
  inputTokens: nonNegativeSafeIntegerSchema.optional(),
14975
14997
  cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
14976
14998
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -15232,15 +15254,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15232
15254
  defaultModeId: harnessPermissionModeIdSchema
15233
15255
  }).strict().superRefine((catalog, context) => {
15234
15256
  const ids = /* @__PURE__ */ new Set();
15235
- for (const [index, mode] of catalog.modes.entries()) {
15236
- if (ids.has(mode.id)) {
15257
+ for (const [index, mode2] of catalog.modes.entries()) {
15258
+ if (ids.has(mode2.id)) {
15237
15259
  context.addIssue({
15238
15260
  code: "custom",
15239
15261
  message: "Permission Mode IDs must be unique",
15240
15262
  path: ["modes", index, "id"]
15241
15263
  });
15242
15264
  }
15243
- ids.add(mode.id);
15265
+ ids.add(mode2.id);
15244
15266
  }
15245
15267
  if (!ids.has(catalog.defaultModeId)) {
15246
15268
  context.addIssue({
@@ -15386,7 +15408,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15386
15408
  }).strict().optional(),
15387
15409
  autonomousTurns: external_exports.object({
15388
15410
  observe: external_exports.boolean()
15389
- }).strict().optional()
15411
+ }).strict().optional(),
15412
+ /** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
15413
+ steer: external_exports.boolean().optional()
15390
15414
  }).strict();
15391
15415
  var harnessConfigurationStateSchema = external_exports.object({
15392
15416
  effectiveModel: harnessModelRefSchema.optional(),
@@ -15519,6 +15543,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15519
15543
  seen.add(thread.threadId);
15520
15544
  }
15521
15545
  });
15546
+ var threadSteeringInspectParamsSchema = external_exports.object({
15547
+ threadId: hostThreadIdSchema,
15548
+ /** The text about to be steered; a Harness command always stops and restarts. */
15549
+ text: external_exports.string().optional()
15550
+ }).strict();
15551
+ var THREAD_STEER_DELIVERY_PARAM = "codexhostSteerDelivery";
15552
+ var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
15553
+ var threadSteeringInspectResultSchema = external_exports.object({
15554
+ delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
15555
+ }).strict();
15522
15556
 
15523
15557
  // ../shared-contracts/dist/harness-plugins.js
15524
15558
  var HARNESS_PLUGIN_MANIFEST_MAX_BYTES = 32 * 1024;
@@ -15659,7 +15693,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15659
15693
  }).strict();
15660
15694
 
15661
15695
  // ../shared-contracts/dist/harness-installation.js
15662
- var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
15696
+ var HARNESS_INSTALLATION_START_METHOD = "codexhost/harness/installation/start";
15697
+ var HARNESS_INSTALLATION_STATUS_METHOD = "codexhost/harness/installation/status";
15663
15698
  var harnessInstallationParamsSchema = external_exports.object({
15664
15699
  harnessId: harnessIdSchema,
15665
15700
  action: external_exports.enum(["check", "update", "install"])
@@ -15669,6 +15704,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15669
15704
  latestVersion: external_exports.string().min(1).max(128),
15670
15705
  updateAvailable: external_exports.boolean(),
15671
15706
  canUpdate: external_exports.boolean(),
15707
+ /** Defaults to CLI; some Harnesses ship only inside a desktop application. */
15708
+ versionKind: external_exports.enum(["cli", "application"]).optional(),
15709
+ /** Official download opened by the user; does not imply an automatic installation. */
15710
+ manualUpdateUrl: external_exports.url().max(2048).refine((value) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value), "Manual updates require a credential-free HTTPS URL").optional(),
15672
15711
  // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15673
15712
  message: external_exports.string().max(2048).optional(),
15674
15713
  messageCode: external_exports.string().min(1).max(128).optional(),
@@ -15676,6 +15715,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15676
15715
  notice: harnessLocalizedTextSchema.optional(),
15677
15716
  latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15678
15717
  }).strict();
15718
+ var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
15719
+ var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
15720
+ external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
15721
+ external_exports.object({
15722
+ taskId: external_exports.string().uuid(),
15723
+ status: external_exports.literal("succeeded"),
15724
+ result: harnessInstallationStateSchema
15725
+ }).strict(),
15726
+ external_exports.object({
15727
+ taskId: external_exports.string().uuid(),
15728
+ status: external_exports.literal("failed"),
15729
+ error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
15730
+ }).strict()
15731
+ ]);
15679
15732
 
15680
15733
  // ../shared-contracts/dist/codex-accounts.js
15681
15734
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
@@ -16250,13 +16303,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16250
16303
  }
16251
16304
  function resourceNamesFromPerformance(source) {
16252
16305
  const target = source ?? (typeof performance === "undefined" ? void 0 : performance);
16253
- if (!target || typeof target.getEntriesByType !== "function") return [];
16254
- return target.getEntriesByType("resource").map((entry) => entry.name).filter((name) => typeof name === "string");
16306
+ if (!target) return [];
16307
+ const names = [];
16308
+ const push = (name) => {
16309
+ if (typeof name === "string" && name) names.push(name);
16310
+ };
16311
+ if (typeof target.getEntries === "function") {
16312
+ for (const entry of target.getEntries()) push(entry.name);
16313
+ } else if (typeof target.getEntriesByType === "function") {
16314
+ for (const entry of target.getEntriesByType("resource")) push(entry.name);
16315
+ }
16316
+ return names;
16255
16317
  }
16256
16318
  function loadedAssetNames(root, performanceSource) {
16257
16319
  const names = resourceNamesFromPerformance(performanceSource);
16258
16320
  if (!root || !("querySelectorAll" in root)) return names;
16259
- for (const element of root.querySelectorAll("script[src], link[href]")) {
16321
+ for (const element of root.querySelectorAll(
16322
+ 'script[src], link[href], link[rel="modulepreload"], link[rel="preload"]'
16323
+ )) {
16260
16324
  const value = element.getAttribute("src") ?? element.getAttribute("href");
16261
16325
  if (value) names.push(value);
16262
16326
  }
@@ -16354,8 +16418,80 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16354
16418
  const present = profiles.filter(
16355
16419
  (profile2) => [profile2.initial, profile2.shared].some((asset) => auditedAppInitialAssetPresent(names, asset))
16356
16420
  );
16421
+ if (version2 !== void 0) {
16422
+ const profile2 = profiles.find((entry) => entry.version === version2);
16423
+ if (!profile2) return void 0;
16424
+ if (present.some((entry) => entry.version !== version2)) return void 0;
16425
+ const complete = [profile2.initial, profile2.shared].every(
16426
+ (asset) => auditedAppInitialAssetPresent(names, asset)
16427
+ );
16428
+ return complete || present.length === 0 ? profile2 : void 0;
16429
+ }
16357
16430
  const profile = present.length === 1 ? present[0] : void 0;
16358
- return profile && (version2 === void 0 || profile.version === version2) && [profile.initial, profile.shared].every((asset) => auditedAppInitialAssetPresent(names, asset)) ? profile : void 0;
16431
+ return profile && [profile.initial, profile.shared].every((asset) => auditedAppInitialAssetPresent(names, asset)) ? profile : void 0;
16432
+ }
16433
+
16434
+ // src/renderer-native-chat-voice-assets.ts
16435
+ var NATIVE_CHAT_VOICE_VERSION = "26.1021.31345";
16436
+ var NATIVE_CHAT_INITIAL_ASSET = "app-initial-feb30b196d11.js";
16437
+ var START_ASSET = "entity-business-profile-reference-b68063dfc05d.js";
16438
+ var NATIVE_CHAT_VOICE_ASSETS = [
16439
+ {
16440
+ version: NATIVE_CHAT_VOICE_VERSION,
16441
+ initial: NATIVE_CHAT_INITIAL_ASSET,
16442
+ shared: "app-shared-2cae01273bae.js",
16443
+ primary: "app-primary-7d7313419f84.js",
16444
+ start: START_ASSET,
16445
+ prewarm: "voice-prewarm-d672f1245523.js",
16446
+ settings: "voice-settings-14000f5c9fc2.js"
16447
+ },
16448
+ {
16449
+ version: "26.1016.62342",
16450
+ initial: "app-initial-dddef47d6ef6.js",
16451
+ shared: "app-shared-fc3316d48427.js",
16452
+ start: "start-voice-7cbf0a39d53b.js",
16453
+ prewarm: "voice-prewarm-5d107129ac1c.js"
16454
+ },
16455
+ {
16456
+ version: "26.1016.61520",
16457
+ initial: "app-initial-c95ddb62696e.js",
16458
+ shared: "app-shared-2eda13eb7044.js",
16459
+ start: "start-voice-18b08f0acdd7.js",
16460
+ prewarm: "voice-prewarm-94271e581c1b.js"
16461
+ }
16462
+ ];
16463
+ async function loadNativeChatVoiceModules(assets, importModule) {
16464
+ const [sharedModule, initialModule, startModule, prewarm, primary] = await Promise.all(
16465
+ [assets.shared, assets.initial, assets.start, assets.prewarm, assets.primary].map(
16466
+ (asset) => asset ? importModule(`app://-/assets/${asset}`) : Promise.resolve(void 0)
16467
+ )
16468
+ );
16469
+ if (!sharedModule || !initialModule || !startModule || !prewarm) throw new Error();
16470
+ const current = assets.version === NATIVE_CHAT_VOICE_VERSION;
16471
+ const initialize = current ? primary?.um : initialModule.oT;
16472
+ const start = current ? { t: startModule.r, n: startModule.i } : startModule;
16473
+ if (typeof start.t !== "function" || typeof start.n !== "function" || typeof initialize !== "function" || typeof (current ? initialModule.qXt : initialModule.SPn) !== "function" || typeof (current ? sharedModule.XVt : sharedModule.FBt) !== "function" || typeof (current ? sharedModule.KNt : sharedModule.PNt) !== "function" || typeof prewarm.VoiceInstantConnectCacheController !== "function")
16474
+ throw new Error();
16475
+ initialize();
16476
+ start.t();
16477
+ const initial = current ? {
16478
+ MOr: initialModule.CQn,
16479
+ CDr: initialModule.PXn,
16480
+ B1n: initialModule.tdn,
16481
+ SPn: initialModule.qXt,
16482
+ oT: primary?.um,
16483
+ aT: primary?.lm,
16484
+ Ycr: initialModule.Xkn,
16485
+ Nir: initialModule.yAn,
16486
+ n0n: initialModule.ydn,
16487
+ Y1n: initialModule.fdn,
16488
+ HJt: initialModule.R2
16489
+ } : initialModule;
16490
+ const shared = current ? { Qst: sharedModule.Bst, FBt: sharedModule.XVt, PNt: sharedModule.KNt, Vot: sharedModule.Fot } : sharedModule;
16491
+ const scope = (value, brand) => value !== null && typeof value === "object" && value.__scopeBrand === brand;
16492
+ if (!scope(shared.Qst, "AppScope") || !scope(initial.MOr, "RouteScope") || !scope(initial.CDr, "ComposerScope") || !initial.B1n || !initial.aT)
16493
+ throw new Error();
16494
+ return { initial, shared, start, prewarm };
16359
16495
  }
16360
16496
 
16361
16497
  // ../desktop-control/dist/renderer-react-ownership.js
@@ -16579,27 +16715,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16579
16715
 
16580
16716
  // src/renderer-native-chat-voice.ts
16581
16717
  var HOOK_GLOBAL = "__codexhostNativeChatVoiceV1";
16582
- var NATIVE_CHAT_VOICE_VERSION = "26.1016.62342";
16583
- var NATIVE_CHAT_INITIAL_ASSET = "app-initial-dddef47d6ef6.js";
16584
- var NATIVE_CHAT_SHARED_ASSET = "app-shared-fc3316d48427.js";
16585
- var START_ASSET = "start-voice-7cbf0a39d53b.js";
16586
- var PREWARM_ASSET = "voice-prewarm-5d107129ac1c.js";
16587
- var NATIVE_CHAT_VOICE_ASSETS = [
16588
- {
16589
- version: NATIVE_CHAT_VOICE_VERSION,
16590
- initial: NATIVE_CHAT_INITIAL_ASSET,
16591
- shared: NATIVE_CHAT_SHARED_ASSET,
16592
- start: START_ASSET,
16593
- prewarm: PREWARM_ASSET
16594
- },
16595
- {
16596
- version: "26.1016.61520",
16597
- initial: "app-initial-c95ddb62696e.js",
16598
- shared: "app-shared-2eda13eb7044.js",
16599
- start: "start-voice-18b08f0acdd7.js",
16600
- prewarm: "voice-prewarm-94271e581c1b.js"
16601
- }
16602
- ];
16603
16718
  var BUTTON = "data-codexhost-chat-voice-start";
16604
16719
  var CONVERSATION_UUID = /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/i;
16605
16720
  var record2 = (value) => value !== null && typeof value === "object";
@@ -16826,19 +16941,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16826
16941
  }
16827
16942
  return;
16828
16943
  }
16829
- const [shared, initial, start, prewarm] = await Promise.all(
16830
- [assets.shared, assets.initial, assets.start, assets.prewarm].map(
16831
- (asset) => importModule(`app://-/assets/${asset}`)
16832
- )
16833
- );
16944
+ const loaded = await loadNativeChatVoiceModules(assets, importModule);
16834
16945
  if (disposed) return;
16835
- if (!shared || !initial || !start || !prewarm || typeof start.t !== "function" || typeof start.n !== "function" || typeof initial.oT !== "function" || typeof initial.SPn !== "function" || typeof shared.FBt !== "function" || typeof shared.PNt !== "function" || typeof prewarm.VoiceInstantConnectCacheController !== "function")
16836
- throw new Error();
16837
- initial.oT();
16838
- start.t();
16839
- if (!record2(shared.Qst) || !record2(initial.MOr) || !initial.B1n || !initial.aT || !record2(initial.CDr))
16840
- throw new Error();
16841
- modules = { shared, initial, start, prewarm };
16946
+ modules = loaded;
16842
16947
  }
16843
16948
  const current = findBinding();
16844
16949
  selectDraft?.();
@@ -17138,9 +17243,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17138
17243
  clearPendingSubmission(composer) {
17139
17244
  this.#pendingSubmissions.delete(this.#state(composer));
17140
17245
  }
17246
+ /** Only a draft's submission creates a Thread, so only it sets the next new-Thread Agent. */
17141
17247
  recordSubmission(composer) {
17142
17248
  const state = this.#state(composer);
17143
- this.#lastSubmittedAgent = state.agent;
17249
+ if (state.phase === "draft") this.#lastSubmittedAgent = state.agent;
17144
17250
  return state;
17145
17251
  }
17146
17252
  transfer(source, replacement, target = null) {
@@ -17307,28 +17413,54 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17307
17413
  }
17308
17414
 
17309
17415
  // src/renderer-client-owned-voice.ts
17310
- var CLIENT_OWNED_VOICE_VERSION = "26.1016.62342";
17311
- var CLIENT_OWNED_VOICE_INITIAL_ASSET = "app-initial-dddef47d6ef6.js";
17312
- var CLIENT_OWNED_VOICE_SHARED_ASSET = "app-shared-fc3316d48427.js";
17313
- var CLIENT_OWNED_VOICE_SERVICES = "ist";
17314
- var CLIENT_OWNED_VOICE_OVERLAY_ASSET = "avatar-overlay-native-page-ef8332c6a2fb.js";
17416
+ var CLIENT_OWNED_VOICE_VERSION = "26.1021.31345";
17417
+ var CLIENT_OWNED_VOICE_INITIAL_ASSET = "app-initial-feb30b196d11.js";
17418
+ var CLIENT_OWNED_VOICE_SHARED_ASSET = "app-shared-2cae01273bae.js";
17419
+ var CLIENT_OWNED_VOICE_OVERLAY_ASSET = "avatar-overlay-native-page-d549db3706f1.js";
17315
17420
  var CLIENT_OWNED_VOICE_ASSETS = [
17316
17421
  {
17317
17422
  version: CLIENT_OWNED_VOICE_VERSION,
17318
17423
  initial: CLIENT_OWNED_VOICE_INITIAL_ASSET,
17319
17424
  shared: CLIENT_OWNED_VOICE_SHARED_ASSET,
17320
- overlay: CLIENT_OWNED_VOICE_OVERLAY_ASSET
17425
+ overlay: CLIENT_OWNED_VOICE_OVERLAY_ASSET,
17426
+ fetch: "Htr",
17427
+ fetchFrom: "initial",
17428
+ bridge: "bIt",
17429
+ services: "Qot",
17430
+ capabilityInit: "l0n",
17431
+ capabilityFamily: "c0n",
17432
+ inferenceGateFamily: "Cnr"
17433
+ },
17434
+ {
17435
+ version: "26.1016.62342",
17436
+ initial: "app-initial-dddef47d6ef6.js",
17437
+ shared: "app-shared-fc3316d48427.js",
17438
+ overlay: "avatar-overlay-native-page-ef8332c6a2fb.js",
17439
+ init: "Oit",
17440
+ fetch: "Eit",
17441
+ bridge: "AFt",
17442
+ responseError: "Mit",
17443
+ services: "ist",
17444
+ capabilityInit: "njr",
17445
+ capabilityFamily: "tjr",
17446
+ inferenceGateFamily: "uBr"
17321
17447
  },
17322
17448
  {
17323
17449
  version: "26.1016.61520",
17324
17450
  initial: "app-initial-c95ddb62696e.js",
17325
17451
  shared: "app-shared-2eda13eb7044.js",
17326
- overlay: "avatar-overlay-native-page-fcc17283519a.js"
17452
+ overlay: "avatar-overlay-native-page-fcc17283519a.js",
17453
+ init: "Oit",
17454
+ fetch: "Eit",
17455
+ bridge: "AFt",
17456
+ responseError: "Mit",
17457
+ services: "ist",
17458
+ capabilityInit: "njr",
17459
+ capabilityFamily: "tjr",
17460
+ inferenceGateFamily: "uBr"
17327
17461
  }
17328
17462
  ];
17329
17463
  var SHARED_INIT = "Oit";
17330
- var SHARED_FETCH = "Eit";
17331
- var SHARED_BRIDGE = "AFt";
17332
17464
  var SHARED_RESPONSE_ERROR = "Mit";
17333
17465
  var HOOK_GLOBAL2 = "__codexhostClientOwnedVoiceV1";
17334
17466
  function object2(value) {
@@ -17439,7 +17571,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17439
17571
  var lastVoiceProductExperience;
17440
17572
  function rememberVoiceProductExperience(request) {
17441
17573
  const experience = object2(request) ? request.productExperience : void 0;
17442
- lastVoiceProductExperience = experience === "chat" || experience === "work" ? experience : void 0;
17574
+ lastVoiceProductExperience = experience === "chat" || experience === "work" || experience === "codex" ? experience : void 0;
17443
17575
  }
17444
17576
  function lastVoiceLaunchProductExperience() {
17445
17577
  return lastVoiceProductExperience;
@@ -17465,7 +17597,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17465
17597
  const experience = lastVoiceLaunchProductExperience();
17466
17598
  const chat = experience === "chat";
17467
17599
  const model2 = backendModelName(options.headers);
17468
- const work = !chat && (experience === "work" || isWorkBackendModel(model2) || workSurface());
17600
+ const work = !chat && (experience === "work" || experience === "codex" || isWorkBackendModel(model2) || workSurface());
17469
17601
  const external = !chat && (model2.startsWith("codexhost/") || externalHarness());
17470
17602
  const gateway = external || (work ? workOverride() : chatOverride());
17471
17603
  chatVoiceDebug("wham-create", {
@@ -17557,33 +17689,44 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17557
17689
  const assets = selectVoiceAssets(CLIENT_OWNED_VOICE_ASSETS, names, config2.desktopVersion);
17558
17690
  if (assets) {
17559
17691
  try {
17560
- const module = await importModule(`app://-/assets/${assets.shared}`);
17692
+ const sharedModule = await importModule(`app://-/assets/${assets.shared}`);
17693
+ const fetchFrom = "fetchFrom" in assets ? assets.fetchFrom : "shared";
17694
+ const fetchModule = fetchFrom === "initial" ? await importModule(`app://-/assets/${assets.initial}`) : sharedModule;
17561
17695
  if (disposed) return;
17562
- if (typeof module[SHARED_INIT] !== "function") throw new Error();
17563
- module[SHARED_INIT]();
17564
- const fetchClass = module[SHARED_FETCH];
17565
- const bridgeClass = module[SHARED_BRIDGE];
17696
+ const init = "init" in assets ? assets.init : SHARED_INIT;
17697
+ const fetchName = assets.fetch;
17698
+ const bridgeName = assets.bridge;
17699
+ const errorName = "responseError" in assets ? assets.responseError : SHARED_RESPONSE_ERROR;
17700
+ if (typeof init === "string" && typeof fetchModule[init] === "function") {
17701
+ fetchModule[init]();
17702
+ } else if (typeof init === "string" && typeof sharedModule[init] === "function") {
17703
+ sharedModule[init]();
17704
+ }
17705
+ const fetchClass = typeof fetchName === "string" ? fetchModule[fetchName] : void 0;
17706
+ const bridgeClass = typeof bridgeName === "string" ? sharedModule[bridgeName] : void 0;
17566
17707
  if (!object2(fetchClass) && typeof fetchClass !== "function") throw new Error();
17567
17708
  if (!object2(bridgeClass) && typeof bridgeClass !== "function") throw new Error();
17568
17709
  const client = Reflect.get(fetchClass, "getInstance").call(fetchClass);
17569
17710
  const bridge = Reflect.get(bridgeClass, "getInstance").call(bridgeClass);
17570
- if (typeof client?.fetch !== "function" || typeof bridge?.dispatchMessage !== "function" || typeof bridge?.subscribe !== "function" || typeof module[SHARED_RESPONSE_ERROR] !== "function")
17711
+ const responseError = typeof errorName === "string" && typeof sharedModule[errorName] === "function" ? sharedModule[errorName] : async (response) => {
17712
+ throw Object.assign(new Error(await response.text()), { status: response.status });
17713
+ };
17714
+ if (typeof client?.fetch !== "function" || typeof bridge?.dispatchMessage !== "function" || typeof bridge?.subscribe !== "function")
17571
17715
  throw new Error();
17572
17716
  restore = wrapClientOwnedVoiceFetch(
17573
17717
  client,
17574
17718
  bridge,
17575
17719
  () => cpaLiveVoicePreferenceAllowsInstall(target),
17576
- module[SHARED_RESPONSE_ERROR],
17720
+ responseError,
17577
17721
  () => chatLiveVoicePreferenceAllowsOverride(target),
17578
17722
  () => isWorkComposerSurface(target),
17579
17723
  () => isExternalHarnessComposer(target)
17580
17724
  );
17581
17725
  handle.status = "active";
17582
17726
  } catch {
17583
- handle.status = "unsupported";
17584
17727
  }
17585
- return;
17586
17728
  }
17729
+ if (handle.status === "active") return;
17587
17730
  if (Date.now() - started >= 6e4) {
17588
17731
  handle.status = "unsupported";
17589
17732
  return;
@@ -17649,9 +17792,63 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17649
17792
  };
17650
17793
  }
17651
17794
 
17652
- // src/codex-ssh-adapter.ts
17795
+ // src/codex-native-services.ts
17796
+ async function loadCodexNativeServices(ownerWindow, matchesServices, importModule = (url2) => import(url2)) {
17797
+ if (!ownerWindow.document || !ownerWindow.location) return null;
17798
+ const page = new URL(ownerWindow.location.href);
17799
+ const urls = /* @__PURE__ */ new Set();
17800
+ for (const link of ownerWindow.document.querySelectorAll('link[rel="modulepreload"][href]')) {
17801
+ const url2 = new URL(link.getAttribute("href") ?? "", page);
17802
+ if (url2.protocol === page.protocol && url2.host === page.host && url2.pathname.endsWith(".js") && !url2.search && !url2.hash)
17803
+ urls.add(url2.href);
17804
+ }
17805
+ const candidates = [...urls].sort(
17806
+ (a, b) => Number(b.includes("/app-shared-")) - Number(a.includes("/app-shared-"))
17807
+ );
17808
+ for (const url2 of candidates) {
17809
+ let module;
17810
+ try {
17811
+ module = await importModule(url2);
17812
+ } catch {
17813
+ continue;
17814
+ }
17815
+ const matches = new Set(Object.values(module).filter(matchesServices));
17816
+ if (matches.size > 1) throw new Error("Codex native services are unavailable in this window");
17817
+ if (matches.size === 1) return [...matches][0] ?? null;
17818
+ }
17819
+ return null;
17820
+ }
17821
+
17822
+ // src/codex-ssh-services.ts
17653
17823
  var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
17824
+ function isSshServices(value) {
17825
+ if (!record3(value) || !Object.hasOwn(value, "sshConnections") || !Object.hasOwn(value, "remoteConnections"))
17826
+ return false;
17827
+ const ssh = value.sshConnections;
17828
+ const remote = value.remoteConnections;
17829
+ return ssh != null && remote != null && typeof ssh.refresh === "function" && typeof ssh.save === "function" && typeof remote.getState === "function" && typeof remote.setAutoConnect === "function";
17830
+ }
17831
+ async function loadCodexSshServices(ownerWindow, importModule) {
17832
+ return loadCodexNativeServices(ownerWindow, isSshServices, importModule);
17833
+ }
17834
+
17835
+ // src/codex-ssh-adapter.ts
17836
+ var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
17654
17837
  function createCodexSshClient(ownerWindow) {
17838
+ let nativeServices;
17839
+ function services() {
17840
+ nativeServices ??= loadCodexSshServices(ownerWindow).then(
17841
+ (value) => {
17842
+ if (!value) nativeServices = void 0;
17843
+ return value;
17844
+ },
17845
+ (error51) => {
17846
+ nativeServices = void 0;
17847
+ throw error51;
17848
+ }
17849
+ );
17850
+ return nativeServices;
17851
+ }
17655
17852
  function request(operation, params, signal) {
17656
17853
  const bridge = ownerWindow.electronBridge;
17657
17854
  if (!bridge?.sendMessageFromView)
@@ -17659,7 +17856,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17659
17856
  if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
17660
17857
  return new Promise((resolve, reject) => {
17661
17858
  const requestId2 = ownerWindow.crypto.randomUUID();
17859
+ let settled2 = false;
17662
17860
  const finish = (error51, value) => {
17861
+ if (settled2) return;
17862
+ settled2 = true;
17663
17863
  ownerWindow.clearTimeout(timer);
17664
17864
  ownerWindow.removeEventListener("message", receive);
17665
17865
  signal?.removeEventListener("abort", abort);
@@ -17669,10 +17869,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17669
17869
  const abort = () => finish(new DOMException("Aborted", "AbortError"));
17670
17870
  const receive = (event) => {
17671
17871
  const message2 = event.data;
17672
- if (!record3(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId2)
17872
+ if (!record4(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId2)
17673
17873
  return;
17674
17874
  if (message2.responseType !== "success" || typeof message2.status !== "number" || message2.status < 200 || message2.status >= 300 || typeof message2.bodyJsonString !== "string") {
17675
- finish(new Error("Codex SSH request failed; check the native Connections settings"));
17875
+ const detail = typeof message2.error === "string" ? `: ${message2.error}` : "";
17876
+ finish(
17877
+ new Error(`Codex SSH request failed; check the native Connections settings${detail}`)
17878
+ );
17676
17879
  return;
17677
17880
  }
17678
17881
  try {
@@ -17687,30 +17890,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17687
17890
  );
17688
17891
  ownerWindow.addEventListener("message", receive);
17689
17892
  signal?.addEventListener("abort", abort, { once: true });
17690
- try {
17691
- Promise.resolve(
17692
- bridge.sendMessageFromView({
17893
+ void (async () => {
17894
+ const native = await services();
17895
+ if (settled2) return;
17896
+ if (native) {
17897
+ let result;
17898
+ switch (operation) {
17899
+ case "refresh-remote-connections":
17900
+ result = await native.sshConnections.refresh();
17901
+ break;
17902
+ case "save-codex-managed-remote-ssh-connections":
17903
+ result = await native.sshConnections.save(params);
17904
+ break;
17905
+ case "set-remote-connection-auto-connect":
17906
+ result = await native.remoteConnections.setAutoConnect(params);
17907
+ break;
17908
+ case "app-server-connection-state":
17909
+ result = await native.remoteConnections.getState(String(params.hostId));
17910
+ break;
17911
+ }
17912
+ finish(null, result);
17913
+ } else {
17914
+ await bridge.sendMessageFromView({
17693
17915
  type: "fetch",
17694
17916
  requestId: requestId2,
17695
17917
  method: "POST",
17696
17918
  url: `vscode://codex/${operation}`,
17697
17919
  body: JSON.stringify(params),
17698
17920
  reportUploadProgress: false
17699
- })
17700
- ).catch((error51) => finish(error51));
17701
- } catch (error51) {
17702
- finish(error51);
17703
- }
17921
+ });
17922
+ }
17923
+ })().catch((error51) => finish(error51));
17704
17924
  });
17705
17925
  }
17706
17926
  async function list(signal) {
17707
17927
  const result = await request("refresh-remote-connections", {}, signal);
17708
- if (!record3(result) || !Array.isArray(result.remoteConnections))
17928
+ if (!record4(result) || !Array.isArray(result.remoteConnections))
17709
17929
  throw new Error("Invalid Codex SSH connection list");
17710
17930
  return result.remoteConnections.filter(
17711
- (item) => !(record3(item) && ["wsl", "remote-control"].includes(String(item.source)))
17931
+ (item) => !(record4(item) && ["wsl", "remote-control"].includes(String(item.source)))
17712
17932
  ).map((item) => {
17713
- 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)) {
17933
+ if (!record4(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)) {
17714
17934
  throw new Error(
17715
17935
  "This Codex version uses an unsupported SSH configuration; open native settings"
17716
17936
  );
@@ -17782,11 +18002,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17782
18002
  },
17783
18003
  async state(hostId2, signal) {
17784
18004
  const result = await request("app-server-connection-state", { hostId: hostId2 }, signal);
17785
- if (!record3(result) || typeof result.state !== "string")
18005
+ if (!record4(result) || typeof result.state !== "string")
17786
18006
  throw new Error("Invalid Codex connection state");
17787
18007
  return {
17788
18008
  state: result.state,
17789
- error: typeof result.error === "string" ? result.error : record3(result.error) && typeof result.error.message === "string" ? result.error.message : null
18009
+ error: typeof result.error === "string" ? result.error : record4(result.error) && typeof result.error.message === "string" ? result.error.message : null
17790
18010
  };
17791
18011
  }
17792
18012
  };
@@ -19145,17 +19365,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19145
19365
  let busy = false;
19146
19366
  let updating = false;
19147
19367
  let unsupported = false;
19368
+ let updatePromise = null;
19148
19369
  const render = () => {
19370
+ heading.textContent = state?.versionKind === "application" ? messages.harnessVersionApplicationTitle : messages.harnessVersionTitle;
19149
19371
  current.textContent = `${messages.harnessVersionCurrent}: ${state?.currentVersion ?? "\u2014"}`;
19150
19372
  latest.textContent = `${messages.harnessVersionLatest}: ${harnessVersionLabel(state, messages.harnessVersion)}`;
19151
19373
  update.disabled = busy || signal.aborted || !state?.canUpdate || !state.updateAvailable;
19374
+ const manualUrl = !state?.canUpdate && state?.updateAvailable ? state.manualUpdateUrl : void 0;
19375
+ actions.replaceChildren(update);
19376
+ update.hidden = !busy && !signal.aborted && Boolean(manualUrl);
19377
+ if (update.hidden && manualUrl) {
19378
+ const download2 = document2.createElement("a");
19379
+ download2.className = "settings-command-button settings-command-button--secondary";
19380
+ download2.dataset.harnessVersionAction = "download-update";
19381
+ download2.textContent = messages.harnessVersionDownloadUpdate;
19382
+ download2.href = manualUrl;
19383
+ download2.target = "_blank";
19384
+ download2.rel = "noopener noreferrer";
19385
+ actions.append(download2);
19386
+ }
19152
19387
  update.textContent = state?.canUpdate && state.latestVersion !== "Unknown" && !state.updateAvailable ? messages.harnessVersionUpToDate : messages.harnessVersionUpdate;
19153
19388
  const detail = harnessVersionNote(state, messages.harnessVersion);
19154
- note.textContent = detail ? `${detail} ${messages.harnessVersionNote}` : messages.harnessVersionNote;
19389
+ note.textContent = detail ? !state?.canUpdate ? detail : `${detail} ${messages.harnessVersionNote}` : messages.harnessVersionNote;
19155
19390
  };
19156
19391
  const run = async (action) => {
19157
- if (busy || unsupported || signal.aborted) return;
19158
- if (action === "update" && (!state?.canUpdate || !state.updateAvailable)) return;
19392
+ if (busy || unsupported || signal.aborted) return false;
19393
+ if (action === "update" && (!state?.canUpdate || !state.updateAvailable)) return false;
19159
19394
  busy = true;
19160
19395
  updating = action === "update";
19161
19396
  onChange();
@@ -19163,14 +19398,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19163
19398
  render();
19164
19399
  try {
19165
19400
  const result = await client.run(action);
19166
- if (signal.aborted) return;
19401
+ if (signal.aborted) return false;
19167
19402
  state = result;
19168
19403
  status.textContent = !result.canUpdate ? messages.harnessVersionManual : action === "update" ? result.updateAvailable ? messages.harnessVersionFailed : messages.harnessVersionUpdated : "";
19404
+ return result.canUpdate && !result.updateAvailable;
19169
19405
  } catch (error51) {
19170
- if (signal.aborted) return;
19406
+ if (signal.aborted) return false;
19171
19407
  unsupported = typeof error51 === "object" && error51 !== null && "code" in error51 && (error51.code === -32601 || error51.code === -32078);
19172
19408
  status.textContent = unsupported ? messages.harnessVersionUnsupported : messages.harnessVersionFailed;
19173
19409
  if (state) state = { ...state, canUpdate: false };
19410
+ return false;
19174
19411
  } finally {
19175
19412
  busy = false;
19176
19413
  updating = false;
@@ -19180,7 +19417,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19180
19417
  }
19181
19418
  }
19182
19419
  };
19183
- update.addEventListener("click", () => void run("update"));
19420
+ const updateVersion = () => {
19421
+ updatePromise ??= run("update").finally(() => {
19422
+ updatePromise = null;
19423
+ });
19424
+ return updatePromise;
19425
+ };
19426
+ update.addEventListener("click", () => void updateVersion());
19184
19427
  const owner = document2.defaultView;
19185
19428
  let checkFrame = null;
19186
19429
  let checkTimer = null;
@@ -19215,7 +19458,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19215
19458
  get updating() {
19216
19459
  return updating;
19217
19460
  },
19218
- update: () => void run("update")
19461
+ update: updateVersion
19219
19462
  };
19220
19463
  }
19221
19464
 
@@ -19246,25 +19489,77 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19246
19489
  };
19247
19490
  }
19248
19491
 
19492
+ // src/settings/connection-updates.ts
19493
+ function createConnectionUpdates(document2, messages, signal, onChange) {
19494
+ const batches = /* @__PURE__ */ new Map();
19495
+ const eligible = (panels) => panels.filter((panel) => panel.state?.updateAvailable && panel.state.canUpdate);
19496
+ const start = async (hostId2, panels) => {
19497
+ if (signal.aborted || batches.get(hostId2)?.running) return;
19498
+ const targets = eligible(panels);
19499
+ if (!targets.length) return;
19500
+ const batch = { running: true, total: targets.length, succeeded: 0, failed: 0 };
19501
+ batches.set(hostId2, batch);
19502
+ onChange();
19503
+ await Promise.all(
19504
+ targets.map(async (panel) => {
19505
+ try {
19506
+ if (await panel.update()) batch.succeeded++;
19507
+ else batch.failed++;
19508
+ } catch {
19509
+ batch.failed++;
19510
+ }
19511
+ if (!signal.aborted) onChange();
19512
+ })
19513
+ );
19514
+ batch.running = false;
19515
+ if (!signal.aborted) onChange();
19516
+ };
19517
+ return {
19518
+ createControls(hostId2, panels) {
19519
+ const batch = batches.get(hostId2);
19520
+ const count3 = eligible(panels).length;
19521
+ const button2 = document2.createElement("button");
19522
+ button2.type = "button";
19523
+ button2.className = "settings-command-button settings-command-button--secondary settings-connection-update-all";
19524
+ button2.dataset.connectionAction = "update-all";
19525
+ button2.disabled = signal.aborted || Boolean(batch?.running) || !count3;
19526
+ button2.title = messages.harnessUpdateAllDescription;
19527
+ const label = batch?.running ? `${messages.harnessUpdateAllProgress} ${batch.succeeded + batch.failed}/${batch.total}` : count3 ? `${messages.harnessUpdateAll} (${count3})` : messages.harnessUpdateAll;
19528
+ button2.append(createRendererSettingsIcon("download", 15), label);
19529
+ button2.addEventListener("click", () => {
19530
+ if (!button2.disabled) void start(hostId2, panels);
19531
+ });
19532
+ const result = document2.createElement("p");
19533
+ result.className = "settings-connection-update-result";
19534
+ result.setAttribute("role", "status");
19535
+ result.hidden = !batch || batch.running;
19536
+ if (batch && !batch.running) {
19537
+ result.textContent = messages.harnessUpdateAllResult.replace("{succeeded}", String(batch.succeeded)).replace("{failed}", String(batch.failed));
19538
+ }
19539
+ return { button: button2, result };
19540
+ }
19541
+ };
19542
+ }
19543
+
19249
19544
  // src/settings/connections-page.ts
19250
19545
  var CODEXHOST_GITHUB_ISSUES_NEW_URL = "https://github.com/karlorz/codex-host/issues/new";
19251
- function connectionStatusLabel(availability, messages, hasError = false) {
19252
- if (availability === "updating") return messages.connectionStatusUpdating;
19253
- if (hasError && availability !== "notInstalled") return messages.connectionStatusError;
19254
- if (availability === "ready") return messages.connectionStatusReady;
19255
- if (availability === "checking") return messages.connectionStatusChecking;
19256
- if (availability === "notInstalled") return messages.connectionStatusNotInstalled;
19257
- if (availability === "unavailable" || availability === "error") {
19258
- return availability === "error" ? messages.connectionStatusError : messages.connectionStatusUnavailable;
19259
- }
19260
- return availability === "installing" ? messages.connectionStatusInstalling : messages.connectionStatusUnsupported;
19261
- }
19262
- function connectionStatusTone(availability, hasError = false) {
19263
- if (availability === "updating") return "checking";
19264
- if (hasError && availability !== "notInstalled") return "failed";
19265
- if (availability === "ready") return "ready";
19266
- if (availability === "checking" || availability === "installing") return "checking";
19267
- if (availability === "notInstalled") return "setup";
19546
+ function connectionStatusLabel(availability2, messages, hasError = false) {
19547
+ if (availability2 === "updating") return messages.connectionStatusUpdating;
19548
+ if (hasError && availability2 !== "notInstalled") return messages.connectionStatusError;
19549
+ if (availability2 === "ready") return messages.connectionStatusReady;
19550
+ if (availability2 === "checking") return messages.connectionStatusChecking;
19551
+ if (availability2 === "notInstalled") return messages.connectionStatusNotInstalled;
19552
+ if (availability2 === "unavailable" || availability2 === "error") {
19553
+ return availability2 === "error" ? messages.connectionStatusError : messages.connectionStatusUnavailable;
19554
+ }
19555
+ return availability2 === "installing" ? messages.connectionStatusInstalling : messages.connectionStatusUnsupported;
19556
+ }
19557
+ function connectionStatusTone(availability2, hasError = false) {
19558
+ if (availability2 === "updating") return "checking";
19559
+ if (hasError && availability2 !== "notInstalled") return "failed";
19560
+ if (availability2 === "ready") return "ready";
19561
+ if (availability2 === "checking" || availability2 === "installing") return "checking";
19562
+ if (availability2 === "notInstalled") return "setup";
19268
19563
  return "failed";
19269
19564
  }
19270
19565
  function diagnosticText(hostId2, item) {
@@ -19412,13 +19707,6 @@ ${error51.stderrTail}`] : []
19412
19707
  status.setAttribute("role", "cell");
19413
19708
  status.textContent = item.error?.code === "authenticationRequired" ? messages.connectionLoginRequired : item.error?.code === "configurationRequired" ? messages.connectionConfigurationRequired : connectionStatusLabel(item.availability, messages, item.error !== null);
19414
19709
  const version2 = item.version;
19415
- if (version2?.state?.updateAvailable && !version2.updating) {
19416
- const available = document2.createElement("span");
19417
- available.className = "settings-connection-version-available";
19418
- available.textContent = `${messages.harnessVersionAvailable}: ${harnessVersionLabel(version2.state, messages.harnessVersion)}`;
19419
- available.title = `${messages.harnessVersionCurrent}: ${version2.state.currentVersion ?? "\u2014"}`;
19420
- status.append(available);
19421
- }
19422
19710
  const action = document2.createElement("div");
19423
19711
  action.className = "settings-connection-row__action";
19424
19712
  action.setAttribute("role", "cell");
@@ -19448,6 +19736,14 @@ ${error51.stderrTail}`] : []
19448
19736
  });
19449
19737
  action.append(viewError);
19450
19738
  }
19739
+ if (version2?.state?.updateAvailable && !version2.updating) {
19740
+ const available = document2.createElement("span");
19741
+ available.className = "settings-connection-version-available";
19742
+ available.textContent = messages.harnessVersionAvailable;
19743
+ available.title = `${messages.harnessVersionCurrent}: ${version2.state.currentVersion ?? "\u2014"}
19744
+ ${messages.harnessVersionLatest}: ${harnessVersionLabel(version2.state, messages.harnessVersion)}`;
19745
+ action.append(available);
19746
+ }
19451
19747
  if (version2?.state?.updateAvailable && version2.state.canUpdate) {
19452
19748
  const update = document2.createElement("button");
19453
19749
  update.type = "button";
@@ -19460,7 +19756,7 @@ ${error51.stderrTail}`] : []
19460
19756
  update.addEventListener("click", (event) => {
19461
19757
  event.stopPropagation();
19462
19758
  if (update.disabled) return;
19463
- version2.update();
19759
+ void version2.update();
19464
19760
  select();
19465
19761
  });
19466
19762
  action.append(update);
@@ -19802,6 +20098,7 @@ ${error51.stderrTail}`] : []
19802
20098
  scheduleRender
19803
20099
  );
19804
20100
  const installs = diagnostics ? harnessInstallStore(diagnostics) : null;
20101
+ const updates = createConnectionUpdates(document2, messages, context.signal, scheduleRender);
19805
20102
  const runRefresh = () => {
19806
20103
  if (pending || !diagnostics) return;
19807
20104
  pending = true;
@@ -19937,8 +20234,8 @@ ${error51.stderrTail}`] : []
19937
20234
  const agent = item.agentSnapshot?.agent;
19938
20235
  if (!agent) return item;
19939
20236
  const state = installs?.get(selectedHost.hostId, agent);
19940
- const availability = state?.status ?? item.availability;
19941
- const version2 = item.agentSnapshot?.availability !== "notInstalled" && availability !== "installing" && availability !== "checking" ? versions.get(selectedHost.hostId, agent) : void 0;
20237
+ const availability2 = state?.status ?? item.availability;
20238
+ const version2 = item.agentSnapshot?.availability !== "notInstalled" && availability2 !== "installing" && availability2 !== "checking" ? versions.get(selectedHost.hostId, agent) : void 0;
19942
20239
  return {
19943
20240
  ...item,
19944
20241
  ...state ? { availability: state.status } : {},
@@ -20136,7 +20433,14 @@ ${error51.stderrTail}`] : []
20136
20433
  }
20137
20434
  const selectedItem = items.find((item) => item.key === selectedItemKey) ?? items[0];
20138
20435
  if (selectedItem) selectItem(selectedItem);
20139
- list.append(hostStrip, tableHeader, rows);
20436
+ const updateControls = updates.createControls(
20437
+ selectedHost.hostId,
20438
+ items.flatMap((item) => item.version ? [item.version] : [])
20439
+ );
20440
+ const hostHeader = document2.createElement("div");
20441
+ hostHeader.className = "settings-connection-host-header";
20442
+ hostHeader.append(hostStrip, updateControls.button);
20443
+ list.append(hostHeader, updateControls.result, tableHeader, rows);
20140
20444
  layout.append(list, inspector);
20141
20445
  content.replaceChildren(layout);
20142
20446
  disposeHostScroller = configureHostScroller(
@@ -20469,11 +20773,17 @@ ${error51.stderrTail}`] : []
20469
20773
  connectionInstallRunning: "Installing on the selected Host. You can leave this page; login or setup may still be required afterward.",
20470
20774
  harnessVersion: harnessVersionEnglish,
20471
20775
  harnessVersionTitle: "Harness CLI version",
20776
+ harnessVersionApplicationTitle: "Application version",
20472
20777
  harnessVersionCurrent: "Current version",
20473
20778
  harnessVersionLatest: "Latest version",
20474
20779
  harnessVersionChecking: "Checking versions\u2026",
20475
20780
  harnessVersionAvailable: "Update available",
20476
20781
  harnessVersionUpdate: "Update",
20782
+ harnessVersionDownloadUpdate: "Download update",
20783
+ harnessUpdateAll: "Update all",
20784
+ harnessUpdateAllProgress: "Updating",
20785
+ harnessUpdateAllDescription: "Update all eligible Harnesses on the selected Host.",
20786
+ harnessUpdateAllResult: "Updated {succeeded}; failed {failed}.",
20477
20787
  harnessVersionUpdating: "Updating\u2026",
20478
20788
  harnessVersionUpToDate: "Up to date",
20479
20789
  harnessVersionUpdated: "Update verified. New sessions will use the new version.",
@@ -20772,11 +21082,17 @@ ${error51.stderrTail}`] : []
20772
21082
  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",
20773
21083
  harnessVersion: harnessVersionChinese,
20774
21084
  harnessVersionTitle: "Harness CLI \u7248\u672C",
21085
+ harnessVersionApplicationTitle: "\u5E94\u7528\u7248\u672C",
20775
21086
  harnessVersionCurrent: "\u5F53\u524D\u7248\u672C",
20776
21087
  harnessVersionLatest: "\u6700\u65B0\u7248\u672C",
20777
21088
  harnessVersionChecking: "\u6B63\u5728\u68C0\u67E5\u7248\u672C\u2026",
20778
- harnessVersionAvailable: "\u6709\u65B0\u7248\u672C",
21089
+ harnessVersionAvailable: "\u6709\u66F4\u65B0",
20779
21090
  harnessVersionUpdate: "\u66F4\u65B0",
21091
+ harnessVersionDownloadUpdate: "\u4E0B\u8F7D\u66F4\u65B0",
21092
+ harnessUpdateAll: "\u5168\u90E8\u66F4\u65B0",
21093
+ harnessUpdateAllProgress: "\u66F4\u65B0\u4E2D",
21094
+ harnessUpdateAllDescription: "\u66F4\u65B0\u5F53\u524D Host \u4E0A\u652F\u6301\u81EA\u52A8\u66F4\u65B0\u4E14\u6709\u65B0\u7248\u672C\u7684 Harness\u3002",
21095
+ harnessUpdateAllResult: "\u5DF2\u66F4\u65B0 {succeeded} \u9879\uFF0C{failed} \u9879\u5931\u8D25\u3002",
20780
21096
  harnessVersionUpdating: "\u6B63\u5728\u66F4\u65B0\u2026",
20781
21097
  harnessVersionUpToDate: "\u5DF2\u662F\u6700\u65B0",
20782
21098
  harnessVersionUpdated: "\u5DF2\u786E\u8BA4\u66F4\u65B0\u6210\u529F\uFF0C\u65B0\u4F1A\u8BDD\u5C06\u4F7F\u7528\u65B0\u7248\u672C\u3002",
@@ -20924,18 +21240,18 @@ ${error51.stderrTail}`] : []
20924
21240
  const account = state.agent === "codex" && activeAccount ? ` \xB7 ${activeAccount.email ?? activeAccount.label}` : "";
20925
21241
  return `Agent: ${rendererAgentLabel(state.agent, plugin)}${account}${state.phase === "locked" ? " (locked)" : ""}`;
20926
21242
  }
20927
- function rendererAgentPickerView(state, adapterState, switching, agents, availability = {}, plugin) {
21243
+ function rendererAgentPickerView(state, adapterState, switching, agents, availability2 = {}, plugin) {
20928
21244
  const optionDisabled = Object.fromEntries(
20929
21245
  agents.map((agent) => [
20930
21246
  agent,
20931
- switching || state.phase === "locked" || agent !== "codex" && (adapterState !== "ready" || availability[agent] !== "ready")
21247
+ switching || state.phase === "locked" || agent !== "codex" && (adapterState !== "ready" || availability2[agent] !== "ready")
20932
21248
  ])
20933
21249
  );
20934
21250
  const downloadVisible = Object.fromEntries(
20935
- agents.filter((agent) => agent !== "codex").map((agent) => [agent, availability[agent] === "notInstalled"])
21251
+ agents.filter((agent) => agent !== "codex").map((agent) => [agent, availability2[agent] === "notInstalled"])
20936
21252
  );
20937
21253
  const errorVisible = Object.fromEntries(
20938
- agents.filter((agent) => agent !== "codex").map((agent) => [agent, availability[agent] === "error"])
21254
+ agents.filter((agent) => agent !== "codex").map((agent) => [agent, availability2[agent] === "error"])
20939
21255
  );
20940
21256
  return {
20941
21257
  label: rendererAgentLabel(state.agent, plugin),
@@ -21362,10 +21678,10 @@ ${error51.stderrTail}`] : []
21362
21678
  agents: [...enabledAgents],
21363
21679
  plugins,
21364
21680
  options,
21365
- updateAvailability(availability) {
21681
+ updateAvailability(availability2) {
21366
21682
  const next = new Set(
21367
21683
  enabledAgents.filter(
21368
- (agent) => agent !== "codex" && availability[agent] === "notInstalled"
21684
+ (agent) => agent !== "codex" && availability2[agent] === "notInstalled"
21369
21685
  )
21370
21686
  );
21371
21687
  if (next.size === notInstalled.size && [...next].every((agent) => notInstalled.has(agent))) {
@@ -21389,16 +21705,16 @@ ${error51.stderrTail}`] : []
21389
21705
  };
21390
21706
  return control;
21391
21707
  }
21392
- function renderRendererAgentPicker(control, state, adapterState, switching, availability = {}, currentCodexAccount = null, ownershipError = false) {
21708
+ function renderRendererAgentPicker(control, state, adapterState, switching, availability2 = {}, currentCodexAccount = null, ownershipError = false) {
21393
21709
  const view = rendererAgentPickerView(
21394
21710
  state,
21395
21711
  adapterState,
21396
21712
  switching,
21397
21713
  control.agents,
21398
- availability,
21714
+ availability2,
21399
21715
  control.plugins.find(({ id }) => id === state.agent)
21400
21716
  );
21401
- control.updateAvailability(availability);
21717
+ control.updateAvailability(availability2);
21402
21718
  if (control.iconSlot.dataset.agent !== state.agent) {
21403
21719
  control.iconSlot.replaceChildren(
21404
21720
  createRendererAgentIcon(
@@ -22342,8 +22658,8 @@ Codex Fast mode prioritizes requests and may increase usage.`
22342
22658
  const presentation = localizeHarnessPresentation(command, locale);
22343
22659
  return { ...presentation, description: presentation.description ?? presentation.label };
22344
22660
  }
22345
- function rendererPermissionModePresentation(mode, locale) {
22346
- return localizeHarnessPresentation(mode, locale);
22661
+ function rendererPermissionModePresentation(mode2, locale) {
22662
+ return localizeHarnessPresentation(mode2, locale);
22347
22663
  }
22348
22664
  function rendererLiveCommandsPendingNotice(locale, harnessLabel) {
22349
22665
  const harness2 = harnessLabel.replace(/\s*[((][^))]*[))]\s*$/u, "").trim() || harnessLabel;
@@ -23489,18 +23805,18 @@ Codex Fast mode prioritizes requests and may increase usage.`
23489
23805
  function rebuildOptions2(control, catalog, locale) {
23490
23806
  control.options.clear();
23491
23807
  control.menu.replaceChildren();
23492
- for (const mode of catalog.modes) {
23493
- const presentation = rendererPermissionModePresentation(mode, locale);
23808
+ for (const mode2 of catalog.modes) {
23809
+ const presentation = rendererPermissionModePresentation(mode2, locale);
23494
23810
  const button2 = document.createElement("button");
23495
23811
  button2.type = "button";
23496
- button2.dataset.permissionModeId = mode.id;
23812
+ button2.dataset.permissionModeId = mode2.id;
23497
23813
  button2.setAttribute("role", "menuitemradio");
23498
23814
  button2.className = OPTION_CLASSES2;
23499
23815
  button2.style.letterSpacing = "0";
23500
- if (mode.dangerous) button2.style.color = "var(--color-text-danger, #c2413b)";
23816
+ if (mode2.dangerous) button2.style.color = "var(--color-text-danger, #c2413b)";
23501
23817
  const modeIcon = document.createElement("span");
23502
23818
  modeIcon.className = "inline-flex h-5 w-5 shrink-0 items-center justify-center";
23503
- modeIcon.append(icon(mode.dangerous ? ShieldAlert : Shield, 17));
23819
+ modeIcon.append(icon(mode2.dangerous ? ShieldAlert : Shield, 17));
23504
23820
  const copy = document.createElement("span");
23505
23821
  copy.className = "min-w-0 flex-1";
23506
23822
  const title = document.createElement("span");
@@ -23521,7 +23837,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23521
23837
  check2.classList.add("mt-0.5", "shrink-0");
23522
23838
  check2.style.visibility = "hidden";
23523
23839
  button2.append(modeIcon, copy, check2);
23524
- control.options.set(mode.id, { button: button2, check: check2, mode });
23840
+ control.options.set(mode2.id, { button: button2, check: check2, mode: mode2 });
23525
23841
  control.menu.append(button2);
23526
23842
  }
23527
23843
  }
@@ -23923,7 +24239,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23923
24239
  })
23924
24240
  );
23925
24241
  }
23926
- if (label) label.textContent = percent2;
24242
+ if (label) label.textContent = `${Math.round(remaining)}%`;
23927
24243
  control.root.style.display = "inline-flex";
23928
24244
  control.trigger.setAttribute("aria-label", title);
23929
24245
  control.trigger.title = title;
@@ -23931,6 +24247,148 @@ Codex Fast mode prioritizes requests and may increase usage.`
23931
24247
  return true;
23932
24248
  }
23933
24249
 
24250
+ // src/renderer-composer-indicators.ts
24251
+ var SHOW_WITHIN_SECONDS = 50 * 60;
24252
+ function mountRendererComposerIndicators(composer) {
24253
+ const doc = composer.ownerDocument;
24254
+ ensureRendererTriggerChipStyle(doc);
24255
+ const root = doc.createElement("div");
24256
+ root.setAttribute("data-codexhost-composer-indicators", "true");
24257
+ applyRendererTriggerChipSqueezeRoot(root, "128px", "0");
24258
+ Object.assign(root.style, { alignItems: "center", gap: "2px", flexShrink: "100000" });
24259
+ let indicators = [];
24260
+ let locale = "en";
24261
+ let timer;
24262
+ let anchor = null;
24263
+ let contentKey = "";
24264
+ let tip = null;
24265
+ const hideTip = () => {
24266
+ tip?.remove();
24267
+ tip = null;
24268
+ };
24269
+ const showTip = (chip, textContent) => {
24270
+ hideTip();
24271
+ const el = doc.createElement("div");
24272
+ el.setAttribute("role", "tooltip");
24273
+ el.textContent = textContent;
24274
+ Object.assign(el.style, {
24275
+ position: "fixed",
24276
+ zIndex: "2147483647",
24277
+ pointerEvents: "none",
24278
+ padding: "4px 8px",
24279
+ borderRadius: "8px",
24280
+ fontSize: "12px",
24281
+ whiteSpace: "nowrap",
24282
+ background: "rgba(30, 30, 30, 0.92)",
24283
+ color: "#fff",
24284
+ visibility: "hidden"
24285
+ });
24286
+ (doc.body ?? doc.documentElement).append(el);
24287
+ const rect = chip.getBoundingClientRect();
24288
+ const width = el.offsetWidth;
24289
+ const left = Math.max(
24290
+ 4,
24291
+ Math.min(rect.left + rect.width / 2 - width / 2, window.innerWidth - width - 4)
24292
+ );
24293
+ el.style.left = `${left}px`;
24294
+ el.style.top = `${Math.max(4, rect.top - el.offsetHeight - 6)}px`;
24295
+ el.style.visibility = "visible";
24296
+ tip = el;
24297
+ };
24298
+ const refresh = () => {
24299
+ const now = Date.now() / 1e3;
24300
+ const active = indicators.filter(
24301
+ (indicator) => indicator.expiresAtUnix > now && indicator.expiresAtUnix - now <= SHOW_WITHIN_SECONDS
24302
+ );
24303
+ const nextKey = JSON.stringify([
24304
+ locale,
24305
+ active.map((indicator) => [indicator, Math.ceil((indicator.expiresAtUnix - now) / 60)])
24306
+ ]);
24307
+ if (nextKey !== contentKey) {
24308
+ contentKey = nextKey;
24309
+ hideTip();
24310
+ root.replaceChildren();
24311
+ for (const indicator of active) {
24312
+ const minutes = Math.ceil((indicator.expiresAtUnix - now) / 60);
24313
+ const remaining = locale === "zh-CN" ? `\u5269\u4F59 ${minutes} \u5206\u949F` : `${minutes}m remaining`;
24314
+ const label = indicator.label ? localizeHarnessText(indicator.label, locale) : "";
24315
+ const tooltip = indicator.tooltip ? localizeHarnessText(indicator.tooltip, locale) : "";
24316
+ const chip = doc.createElement("span");
24317
+ chip.className = TRIGGER_CHIP_CLASS;
24318
+ chip.setAttribute("data-indicator-id", indicator.id);
24319
+ const summary = [label, tooltip, remaining].filter(Boolean).join(" \xB7 ");
24320
+ chip.setAttribute("aria-label", summary);
24321
+ chip.addEventListener("mouseenter", () => showTip(chip, summary));
24322
+ chip.addEventListener("mouseleave", hideTip);
24323
+ Object.assign(chip.style, {
24324
+ height: "28px",
24325
+ padding: "0 6px",
24326
+ gap: "4px",
24327
+ fontSize: "12px",
24328
+ cursor: "default",
24329
+ flexShrink: "0"
24330
+ });
24331
+ const icon2 = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
24332
+ icon2.setAttribute("viewBox", "0 0 24 24");
24333
+ icon2.setAttribute("width", "14");
24334
+ icon2.setAttribute("height", "14");
24335
+ icon2.setAttribute("fill", "none");
24336
+ icon2.setAttribute("stroke", "currentColor");
24337
+ icon2.setAttribute("stroke-width", "1.5");
24338
+ icon2.setAttribute("aria-hidden", "true");
24339
+ const path = doc.createElementNS("http://www.w3.org/2000/svg", "path");
24340
+ path.setAttribute("d", "M12 8v4l3 2M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0");
24341
+ icon2.append(path);
24342
+ const text = doc.createElement("span");
24343
+ text.textContent = `${minutes}m`;
24344
+ chip.append(icon2, text);
24345
+ root.append(chip);
24346
+ }
24347
+ }
24348
+ const visible = active.length > 0 && anchor !== null;
24349
+ if (root.hidden === visible) root.hidden = !visible;
24350
+ const display = visible ? "inline-flex" : "none";
24351
+ if (root.style.display !== display) root.style.display = display;
24352
+ const visibility = root.scrollWidth > root.clientWidth ? "hidden" : "visible";
24353
+ if (root.style.visibility !== visibility) root.style.visibility = visibility;
24354
+ const pending = indicators.some(({ expiresAtUnix }) => expiresAtUnix > now);
24355
+ if (!pending && timer !== void 0) {
24356
+ clearInterval(timer);
24357
+ timer = void 0;
24358
+ }
24359
+ };
24360
+ const observer = new ResizeObserver(refresh);
24361
+ observer.observe(root);
24362
+ refresh();
24363
+ return {
24364
+ root,
24365
+ place(next) {
24366
+ anchor = next;
24367
+ if (!next?.parentElement) {
24368
+ anchor = null;
24369
+ root.remove();
24370
+ } else if (next.nextElementSibling !== root) {
24371
+ next.parentElement.insertBefore(root, next.nextSibling);
24372
+ }
24373
+ refresh();
24374
+ },
24375
+ render(next, nextLocale) {
24376
+ indicators = next;
24377
+ locale = nextLocale;
24378
+ refresh();
24379
+ if (timer === void 0 && indicators.some(({ expiresAtUnix }) => expiresAtUnix > Date.now() / 1e3)) {
24380
+ timer = setInterval(refresh, 6e4);
24381
+ }
24382
+ },
24383
+ dispose() {
24384
+ observer.disconnect();
24385
+ hideTip();
24386
+ if (timer !== void 0) clearInterval(timer);
24387
+ root.remove();
24388
+ }
24389
+ };
24390
+ }
24391
+
23934
24392
  // src/renderer-harness-command-control.ts
23935
24393
  var CONTROL_ATTRIBUTE2 = "data-codexhost-harness-command-control";
23936
24394
  var SVG_NS2 = "http://www.w3.org/2000/svg";
@@ -24084,7 +24542,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24084
24542
  return controlDescription(button2);
24085
24543
  }
24086
24544
  function isOwnedRendererControl(element) {
24087
- 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");
24545
+ 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");
24088
24546
  }
24089
24547
  function isComposerSubmitButton(button2) {
24090
24548
  if (button2.type === "submit") return true;
@@ -24400,6 +24858,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
24400
24858
  refreshTrailingClusterPlacement(control);
24401
24859
  refreshUsagePlacement(control);
24402
24860
  refreshCreditsPlacement(control);
24861
+ control.composerIndicators?.place(
24862
+ control.nativePermissionModeControlVerified ? control.nativePermissionModeControl?.element ?? null : null
24863
+ );
24403
24864
  setNativeControlHidden(control.nativeModelControl, hideModel);
24404
24865
  setNativeControlHidden(control.nativeContextUsageControl, false);
24405
24866
  setNativeControlHidden(control.nativePermissionModeControl, hidePermissionMode);
@@ -24434,6 +24895,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24434
24895
  onSelectPermissionMode
24435
24896
  );
24436
24897
  const credits = mountRendererCreditsControl(composerId);
24898
+ const composerIndicators = mountRendererComposerIndicators(composer);
24437
24899
  const toolbar = sendButton.parentElement;
24438
24900
  const harnessCommands = mountRendererHarnessCommandControl(
24439
24901
  toolbar ?? composer,
@@ -24481,6 +24943,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24481
24943
  nativeUsageBanner,
24482
24944
  nativePermissionModeControlVerified,
24483
24945
  credits,
24946
+ composerIndicators,
24484
24947
  usage: null,
24485
24948
  harnessCommands,
24486
24949
  sendButton,
@@ -24496,7 +24959,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24496
24959
  const props = key ? Object.getOwnPropertyDescriptor(button2, key)?.value : void 0;
24497
24960
  return typeof props === "object" && props !== null && "disabled" in props && typeof props.disabled === "boolean" ? props.disabled : fallback;
24498
24961
  }
24499
- function renderComposerAgentControl(control, state, adapterState, switching, availability = {}, modelView = { status: "idle" }, permissionModeView = { status: "idle" }, usage = null, accountCredits = null, locale = "en", currentCodexAccount = null, ownershipError = false) {
24962
+ function renderComposerAgentControl(control, state, adapterState, switching, availability2 = {}, modelView = { status: "idle" }, permissionModeView = { status: "idle" }, usage = null, accountCredits = null, locale = "en", currentCodexAccount = null, ownershipError = false) {
24500
24963
  if (control.usage === null) {
24501
24964
  control.usage = mountRendererUsageControl(control.composerId, locale);
24502
24965
  }
@@ -24523,7 +24986,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24523
24986
  state,
24524
24987
  adapterState,
24525
24988
  switching,
24526
- availability,
24989
+ availability2,
24527
24990
  currentCodexAccount,
24528
24991
  ownershipError
24529
24992
  );
@@ -24546,6 +25009,10 @@ Codex Fast mode prioritizes requests and may increase usage.`
24546
25009
  permissionModeVisible,
24547
25010
  locale
24548
25011
  );
25012
+ control.composerIndicators?.render(
25013
+ permissionModeVisible ? usage?.composerIndicators ?? [] : [],
25014
+ locale
25015
+ );
24549
25016
  if (control.usage) {
24550
25017
  renderRendererUsageControl(control.usage, usage, locale);
24551
25018
  }
@@ -24566,6 +25033,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24566
25033
  restoreNativeControl(control.nativeContextUsageControl);
24567
25034
  restoreNativeControl(control.nativeUsageBanner);
24568
25035
  restoreNativeControl(control.nativePermissionModeControl);
25036
+ control.composerIndicators?.dispose();
24569
25037
  control.credits.dispose();
24570
25038
  control.usage?.dispose();
24571
25039
  control.usage = null;
@@ -25122,6 +25590,26 @@ Codex Fast mode prioritizes requests and may increase usage.`
25122
25590
  };
25123
25591
  }
25124
25592
 
25593
+ // src/renderer-installation-client.ts
25594
+ async function runRendererInstallation(send, input) {
25595
+ const params = harnessInstallationParamsSchema.parse(input);
25596
+ const options = { priority: "background", timeoutMs: 15e3 };
25597
+ let task = harnessInstallationTaskSchema.parse(
25598
+ await send(HARNESS_INSTALLATION_START_METHOD, params, options)
25599
+ );
25600
+ const taskId = task.taskId;
25601
+ while (task.status === "running") {
25602
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 500));
25603
+ task = harnessInstallationTaskSchema.parse(
25604
+ await send(HARNESS_INSTALLATION_STATUS_METHOD, { taskId }, options)
25605
+ );
25606
+ if (task.taskId !== taskId) throw new Error("Harness installation task identity changed");
25607
+ }
25608
+ if (task.status === "failed")
25609
+ throw Object.assign(new Error(task.error.message), { code: task.error.code });
25610
+ return task.result;
25611
+ }
25612
+
25125
25613
  // src/renderer-request-sender.ts
25126
25614
  var RendererMethodUnavailableError = class extends Error {
25127
25615
  constructor(method, cause) {
@@ -25359,13 +25847,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
25359
25847
  };
25360
25848
  return Object.freeze({
25361
25849
  async installation(input) {
25362
- return harnessInstallationStateSchema.parse(
25363
- await manager.sendRequest(
25364
- HARNESS_INSTALLATION_METHOD,
25365
- harnessInstallationParamsSchema.parse(input),
25366
- { priority: "interactive" }
25367
- )
25368
- );
25850
+ return runRendererInstallation(manager.sendRequest, input);
25369
25851
  },
25370
25852
  async getHarnessDisplaySettings() {
25371
25853
  return harnessDisplaySettingsSchema.parse(
@@ -25606,6 +26088,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
25606
26088
  if (!isRecord8(target) || typeof target.getTurnCoordinator !== "function" || typeof target.getConversation !== "function") {
25607
26089
  return null;
25608
26090
  }
26091
+ if (typeof target.getStreamRole === "function") return null;
25609
26092
  const coordinator = target.getTurnCoordinator();
25610
26093
  const queue = isRecord8(coordinator) ? coordinator.serverQueue : null;
25611
26094
  if (!isRecord8(queue) || typeof queue.isEnabled !== "function") return null;
@@ -25632,6 +26115,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
25632
26115
  }
25633
26116
 
25634
26117
  // src/renderer-external-steering.ts
26118
+ var THREAD_STEERING_INSPECT_METHOD = "codexhost/thread/steering/inspect";
25635
26119
  var THREAD_OWNERSHIP_LIST_METHOD2 = "codexhost/thread/ownership/list";
25636
26120
  function isRecord9(value) {
25637
26121
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -25641,6 +26125,36 @@ Codex Fast mode prioritizes requests and may increase usage.`
25641
26125
  (key) => typeof value[key] === "function"
25642
26126
  );
25643
26127
  }
26128
+ function inputText(input) {
26129
+ if (!Array.isArray(input)) return "";
26130
+ return input.filter(
26131
+ (item) => isRecord9(item) && typeof item.text === "string"
26132
+ ).map((item) => item.text).join("\n");
26133
+ }
26134
+ function queuedFollowUpText(message2) {
26135
+ if (!isRecord9(message2)) return "";
26136
+ if (typeof message2.text === "string" && message2.text.trim()) return message2.text;
26137
+ const context = message2.context;
26138
+ if (isRecord9(context) && typeof context.prompt === "string" && context.prompt.trim()) {
26139
+ return context.prompt;
26140
+ }
26141
+ return "";
26142
+ }
26143
+ function restoreQueuedTurnStartText(manager, params) {
26144
+ if (!isManager(manager) || !isRecord9(params) || typeof params.threadId !== "string")
26145
+ return params;
26146
+ if (inputText(params.input).trim()) return params;
26147
+ const messageId = params.clientUserMessageId;
26148
+ if (typeof messageId !== "string" || !messageId) return params;
26149
+ const coordinator = manager.getTurnCoordinator();
26150
+ if (!isRecord9(coordinator) || typeof coordinator.readMessages !== "function") return params;
26151
+ const messages = coordinator.readMessages.call(coordinator, params.threadId);
26152
+ if (!Array.isArray(messages)) return params;
26153
+ const match = messages.find((message2) => isRecord9(message2) && message2.id === messageId);
26154
+ const text = queuedFollowUpText(match);
26155
+ if (!text) return params;
26156
+ return { ...params, input: [{ type: "text", text, text_elements: [] }] };
26157
+ }
25644
26158
  function submissionHost(manager) {
25645
26159
  const coordinator = manager.getTurnCoordinator();
25646
26160
  const options = isRecord9(coordinator) ? coordinator.options : null;
@@ -25656,7 +26170,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
25656
26170
  function installSteeringMethods(manager, replacements) {
25657
26171
  const originalPrototype = Object.getPrototypeOf(manager);
25658
26172
  const overrides = Object.create(originalPrototype);
25659
- const names = ["sendRequest", "steerTurn"];
26173
+ const names = Object.keys(replacements).filter(
26174
+ (name) => typeof replacements[name] === "function"
26175
+ );
25660
26176
  const descriptors = new Map(
25661
26177
  names.map((name) => [name, Object.getOwnPropertyDescriptor(manager, name)])
25662
26178
  );
@@ -25715,12 +26231,14 @@ Codex Fast mode prioritizes requests and may increase usage.`
25715
26231
  const originalSteer = manager.steerTurn;
25716
26232
  const originalSend = manager.sendRequest;
25717
26233
  const routes = /* @__PURE__ */ new Map();
26234
+ const activeTurnSteers = /* @__PURE__ */ new Map();
25718
26235
  const pending = /* @__PURE__ */ new Map();
25719
26236
  let disposed = false;
25720
26237
  const send = function(method, params, options) {
25721
26238
  if ((method === "turn/start" || method === "turn/steer") && prepareTurnInput) {
25722
26239
  params = prepareTurnInput(params);
25723
26240
  }
26241
+ if (method === "turn/start") params = restoreQueuedTurnStartText(manager, params);
25724
26242
  const messageId = isRecord9(params) ? params.clientUserMessageId : null;
25725
26243
  const route = typeof messageId === "string" && isRecord9(params) ? routes.get(`${params.threadId}\0${messageId}`) : void 0;
25726
26244
  if (method !== "turn/start" || !isRecord9(params) || !route || route.threadId !== params.threadId) {
@@ -25730,6 +26248,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
25730
26248
  return originalSend.call(manager, method, input, options);
25731
26249
  });
25732
26250
  }
26251
+ if (method === "turn/steer" && isRecord9(params) && typeof params.threadId === "string" && activeTurnSteers.has(params.threadId)) {
26252
+ params = { ...params, [THREAD_STEER_DELIVERY_PARAM]: "activeTurn" };
26253
+ }
25733
26254
  return originalSend.call(manager, method, params, options);
25734
26255
  }
25735
26256
  if (disposed) return Promise.reject(new Error("External steering binding was disposed"));
@@ -25744,7 +26265,8 @@ Codex Fast mode prioritizes requests and may increase usage.`
25744
26265
  input: params.input,
25745
26266
  additionalContext: params.additionalContext,
25746
26267
  responsesapiClientMetadata: params.responsesapiClientMetadata,
25747
- ...params[THREAD_REFERENCE_SOURCE_HOST_PARAM] !== void 0 ? { [THREAD_REFERENCE_SOURCE_HOST_PARAM]: params[THREAD_REFERENCE_SOURCE_HOST_PARAM] } : {}
26268
+ ...params[THREAD_REFERENCE_SOURCE_HOST_PARAM] !== void 0 ? { [THREAD_REFERENCE_SOURCE_HOST_PARAM]: params[THREAD_REFERENCE_SOURCE_HOST_PARAM] } : {},
26269
+ [THREAD_STEER_DELIVERY_PARAM]: "newTurn"
25748
26270
  },
25749
26271
  options
25750
26272
  )
@@ -25766,6 +26288,34 @@ Codex Fast mode prioritizes requests and may increase usage.`
25766
26288
  };
25767
26289
  });
25768
26290
  };
26291
+ const inspectDelivery = async (threadId, text) => {
26292
+ try {
26293
+ const response = await originalSend.call(manager, THREAD_STEERING_INSPECT_METHOD, {
26294
+ threadId,
26295
+ ...text !== void 0 ? { text } : {}
26296
+ });
26297
+ return threadSteeringInspectResultSchema.parse(response).delivery;
26298
+ } catch (error51) {
26299
+ if (!isUnsupportedMethod(error51, THREAD_STEERING_INSPECT_METHOD)) throw error51;
26300
+ }
26301
+ let ownershipResponse;
26302
+ try {
26303
+ ownershipResponse = await originalSend.call(manager, THREAD_OWNERSHIP_LIST_METHOD2, {
26304
+ threadIds: [threadId]
26305
+ });
26306
+ } catch (error51) {
26307
+ if (!isUnsupportedMethod(error51, THREAD_OWNERSHIP_LIST_METHOD2)) throw error51;
26308
+ await verifyNativeCodexThread(
26309
+ (method, params) => originalSend.call(manager, method, params),
26310
+ threadId
26311
+ );
26312
+ return "official";
26313
+ }
26314
+ const ownership = threadOwnershipListResultSchema.parse(ownershipResponse);
26315
+ const owner = ownership.threads.find((thread) => thread.threadId === threadId)?.owner;
26316
+ if (!owner) throw new Error("Thread ownership could not be resolved for steering");
26317
+ return owner === "codex" ? "official" : "newTurn";
26318
+ };
25769
26319
  const steer = async function(...args) {
25770
26320
  const [
25771
26321
  threadId,
@@ -25788,25 +26338,20 @@ Codex Fast mode prioritizes requests and may increase usage.`
25788
26338
  expectedTurnId = host.getActiveTurnId(threadId);
25789
26339
  } catch {
25790
26340
  }
25791
- let ownershipResponse;
25792
- try {
25793
- ownershipResponse = await originalSend.call(manager, THREAD_OWNERSHIP_LIST_METHOD2, {
25794
- threadIds: [threadId]
25795
- });
25796
- } catch (error51) {
25797
- if (!isUnsupportedMethod(error51, THREAD_OWNERSHIP_LIST_METHOD2)) throw error51;
25798
- await verifyNativeCodexThread(
25799
- (method, params) => originalSend.call(manager, method, params),
25800
- threadId
25801
- );
25802
- if (disposed) throw new Error("External steering binding was disposed");
25803
- return originalSteer.apply(manager, args);
25804
- }
25805
- const ownership = threadOwnershipListResultSchema.parse(ownershipResponse);
25806
- const owner = ownership.threads.find((thread) => thread.threadId === threadId)?.owner;
25807
- if (!owner) throw new Error("Thread ownership could not be resolved for steering");
26341
+ const text = Array.isArray(input) ? inputText(input) : void 0;
26342
+ const delivery = await inspectDelivery(threadId, text);
25808
26343
  if (disposed) throw new Error("External steering binding was disposed");
25809
- if (owner === "codex") return originalSteer.apply(manager, args);
26344
+ if (delivery === "official") return originalSteer.apply(manager, args);
26345
+ if (delivery === "activeTurn") {
26346
+ activeTurnSteers.set(threadId, (activeTurnSteers.get(threadId) ?? 0) + 1);
26347
+ try {
26348
+ return await originalSteer.apply(manager, args);
26349
+ } finally {
26350
+ const remaining = (activeTurnSteers.get(threadId) ?? 1) - 1;
26351
+ if (remaining > 0) activeTurnSteers.set(threadId, remaining);
26352
+ else activeTurnSteers.delete(threadId);
26353
+ }
26354
+ }
25810
26355
  if (!host) throw new Error("Desktop turn submission binding is unavailable");
25811
26356
  const currentRole = manager.getStreamRole?.(threadId);
25812
26357
  if (isRecord9(currentRole) && currentRole.role === "follower")
@@ -25881,10 +26426,26 @@ Codex Fast mode prioritizes requests and may increase usage.`
25881
26426
  pending.set(threadId, { messageId, fingerprint, promise: promise2 });
25882
26427
  return promise2;
25883
26428
  };
25884
- const restoreMethod = installSteeringMethods(manager, { sendRequest: send, steerTurn: steer });
26429
+ const originalRole = manager.getStreamRole;
26430
+ const getStreamRole = typeof originalRole === "function" ? (...args) => {
26431
+ const threadId = args[0];
26432
+ if (typeof threadId === "string" && typeof manager.getConversation === "function") {
26433
+ const conversation = manager.getConversation(threadId);
26434
+ if (isRecord9(conversation) && conversation.id === threadId && conversation.modelProvider === "codexhost") {
26435
+ return { role: "owner" };
26436
+ }
26437
+ }
26438
+ return originalRole.apply(manager, args);
26439
+ } : void 0;
26440
+ const restoreMethod = installSteeringMethods(manager, {
26441
+ sendRequest: send,
26442
+ steerTurn: steer,
26443
+ ...getStreamRole ? { getStreamRole } : {}
26444
+ });
25885
26445
  return () => {
25886
26446
  disposed = true;
25887
26447
  restoreMethod("steerTurn");
26448
+ if (getStreamRole) restoreMethod("getStreamRole");
25888
26449
  if (pending.size === 0) {
25889
26450
  restoreMethod("sendRequest");
25890
26451
  } else {
@@ -26051,9 +26612,9 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26051
26612
  }
26052
26613
 
26053
26614
  // src/renderer-thread-reference-capability.ts
26054
- var record4 = (value) => typeof value === "object" && value !== null;
26615
+ var record5 = (value) => typeof value === "object" && value !== null;
26055
26616
  function restoreThreadReferenceCapability(client, manager, isCurrent) {
26056
- if (!record4(manager) || !record4(manager.storage)) return client;
26617
+ if (!record5(manager) || !record5(manager.storage)) return client;
26057
26618
  const storage = manager.storage;
26058
26619
  const read = storage.readValue;
26059
26620
  const write = storage.writeValue;
@@ -26088,14 +26649,14 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26088
26649
  }
26089
26650
 
26090
26651
  // src/renderer-thread-reference-context.ts
26091
- var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
26652
+ var record6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
26092
26653
  function createThreadReferenceContext(manager, hostId2, isCurrent) {
26093
26654
  const prepared = /* @__PURE__ */ new WeakMap();
26094
26655
  return (params) => {
26095
- if (hostId2 === "local" || !record5(manager) || typeof manager.getConversation !== "function" || !record5(params) || typeof params.threadId !== "string")
26656
+ if (hostId2 === "local" || !record6(manager) || typeof manager.getConversation !== "function" || !record6(params) || typeof params.threadId !== "string")
26096
26657
  return params;
26097
26658
  const conversation = manager.getConversation.call(manager, params.threadId);
26098
- if (!record5(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
26659
+ if (!record6(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
26099
26660
  return params;
26100
26661
  if (!isCurrent()) throw new Error("Thread reference connection is no longer available");
26101
26662
  const cached2 = prepared.get(params);
@@ -26756,15 +27317,15 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26756
27317
  return Promise.resolve();
26757
27318
  }
26758
27319
  return new Promise((resolve, reject) => {
26759
- let settled = false;
27320
+ let settled2 = false;
26760
27321
  const cleanup = () => {
26761
27322
  window.clearTimeout(timeout);
26762
27323
  observer.disconnect();
26763
27324
  options.signal?.removeEventListener("abort", onAbort);
26764
27325
  };
26765
27326
  const finish = (row2) => {
26766
- if (settled) return;
26767
- settled = true;
27327
+ if (settled2) return;
27328
+ settled2 = true;
26768
27329
  cleanup();
26769
27330
  row2.click();
26770
27331
  resolve();
@@ -26774,14 +27335,14 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26774
27335
  if (row2) finish(row2);
26775
27336
  });
26776
27337
  const timeout = window.setTimeout(() => {
26777
- if (settled) return;
26778
- settled = true;
27338
+ if (settled2) return;
27339
+ settled2 = true;
26779
27340
  cleanup();
26780
27341
  reject(new Error("Thread did not appear in the sidebar"));
26781
27342
  }, options.timeoutMs ?? OPEN_THREAD_TIMEOUT_MS);
26782
27343
  const onAbort = () => {
26783
- if (settled) return;
26784
- settled = true;
27344
+ if (settled2) return;
27345
+ settled2 = true;
26785
27346
  cleanup();
26786
27347
  reject(abortError());
26787
27348
  };
@@ -27507,6 +28068,11 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27507
28068
  var GET_LOCALE_OVERRIDE_URL = "vscode://codex/get-setting";
27508
28069
  var GET_LOCALE_INFO_URL = "vscode://codex/locale-info";
27509
28070
  var DEFAULT_LOCALE_REQUEST_TIMEOUT_MS = 750;
28071
+ function isNativeLocaleServices(value) {
28072
+ if (!isRecord15(value) || !Object.hasOwn(value, "appInfo")) return false;
28073
+ const appInfo = value.appInfo;
28074
+ return appInfo != null && typeof appInfo.getLocaleInfo === "function";
28075
+ }
27510
28076
  function isRecord15(value) {
27511
28077
  return typeof value === "object" && value !== null && !Array.isArray(value);
27512
28078
  }
@@ -27552,21 +28118,21 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27552
28118
  }
27553
28119
  function sendFixedLocaleRequest(request, ownerWindow, signal, timeoutMs) {
27554
28120
  const bridge = ownerWindow.electronBridge;
27555
- if (typeof bridge?.sendMessageFromView !== "function") {
28121
+ if (request.kind !== "locale-info" && typeof bridge?.sendMessageFromView !== "function") {
27556
28122
  return Promise.reject(new Error("Codex locale bridge is unavailable"));
27557
28123
  }
27558
28124
  if (signal?.aborted) return Promise.reject(abortError2());
27559
28125
  const requestId2 = ownerWindow.crypto.randomUUID();
27560
28126
  return new Promise((resolve, reject) => {
27561
- let settled = false;
28127
+ let settled2 = false;
27562
28128
  const cleanup = () => {
27563
28129
  ownerWindow.clearTimeout(timer);
27564
28130
  ownerWindow.removeEventListener("message", onMessage);
27565
28131
  signal?.removeEventListener("abort", onAbort);
27566
28132
  };
27567
28133
  const settle = (operation) => {
27568
- if (settled) return;
27569
- settled = true;
28134
+ if (settled2) return;
28135
+ settled2 = true;
27570
28136
  cleanup();
27571
28137
  operation();
27572
28138
  };
@@ -27600,13 +28166,21 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27600
28166
  ...request.body === void 0 ? {} : { body: request.body },
27601
28167
  reportUploadProgress: false
27602
28168
  };
27603
- try {
27604
- Promise.resolve(bridge.sendMessageFromView(message2)).catch((error51) => {
27605
- settle(() => reject(error51));
27606
- });
27607
- } catch (error51) {
27608
- settle(() => reject(error51));
27609
- }
28169
+ void (async () => {
28170
+ if (request.kind === "locale-info") {
28171
+ const native = await loadCodexNativeServices(ownerWindow, isNativeLocaleServices);
28172
+ if (settled2) return;
28173
+ if (native) {
28174
+ const response = await native.appInfo.getLocaleInfo();
28175
+ settle(() => resolve(response));
28176
+ return;
28177
+ }
28178
+ }
28179
+ if (typeof bridge?.sendMessageFromView !== "function") {
28180
+ throw new Error("Codex locale bridge is unavailable");
28181
+ }
28182
+ await bridge.sendMessageFromView(message2);
28183
+ })().catch((error51) => settle(() => reject(error51)));
27610
28184
  });
27611
28185
  }
27612
28186
  async function readLocaleOverride(ownerWindow, signal, timeoutMs) {
@@ -27671,14 +28245,15 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
27671
28245
  source
27672
28246
  });
27673
28247
  }
28248
+ const documentLocale = canonicalLocale(ownerWindow.document?.documentElement?.lang);
27674
28249
  return Object.freeze({
27675
28250
  status: "fallback",
27676
28251
  mode: "unavailable",
27677
28252
  localeOverride: void 0,
27678
28253
  ideLocale: localeInfo.ideLocale,
27679
28254
  systemLocale: localeInfo.systemLocale,
27680
- preferredLocale: navigatorLocale ?? "en-US",
27681
- source: navigatorLocale ? "navigator" : "default"
28255
+ preferredLocale: documentLocale ?? navigatorLocale ?? "en-US",
28256
+ source: documentLocale ? "document" : navigatorLocale ? "navigator" : "default"
27682
28257
  });
27683
28258
  }
27684
28259
 
@@ -28167,6 +28742,34 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
28167
28742
  return names.size === 1 ? names.values().next().value ?? model2 : model2;
28168
28743
  }
28169
28744
 
28745
+ // src/console/usage/usage-hosts.ts
28746
+ var LOCAL_USAGE_HOST_ID = "local";
28747
+ function usageHostOptions(hosts, localLabel, selected) {
28748
+ const options = [{ key: LOCAL_USAGE_HOST_ID, label: localLabel }];
28749
+ const seen = /* @__PURE__ */ new Set([LOCAL_USAGE_HOST_ID]);
28750
+ const add = (hostId2, label) => {
28751
+ if (hostId2.length === 0 || seen.has(hostId2)) return;
28752
+ seen.add(hostId2);
28753
+ options.push({ key: hostId2, label: label !== void 0 && label.length > 0 ? label : hostId2 });
28754
+ };
28755
+ for (const host of hosts ?? []) add(host.hostId, host.label);
28756
+ if (!seen.has(selected)) add(selected, void 0);
28757
+ return options;
28758
+ }
28759
+ function createLatestKeyGuard() {
28760
+ let generation = 0;
28761
+ let key;
28762
+ return {
28763
+ begin(next) {
28764
+ generation += 1;
28765
+ key = next;
28766
+ const mine = generation;
28767
+ const selected = next;
28768
+ return () => generation === mine && Object.is(key, selected);
28769
+ }
28770
+ };
28771
+ }
28772
+
28170
28773
  // src/console/usage/format.ts
28171
28774
  var MEASURES = ["cost", "tokens"];
28172
28775
  function fill(template, values) {
@@ -29453,6 +30056,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29453
30056
  const range = text("range");
29454
30057
  const measure = text("measure");
29455
30058
  const granularity = text("granularity");
30059
+ const hostId2 = text("hostId");
29456
30060
  const harness2 = text("harness");
29457
30061
  const model2 = text("model");
29458
30062
  const project3 = text("project");
@@ -29461,6 +30065,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29461
30065
  ...range && USAGE_STATISTICS_RANGES.includes(range) ? { range } : {},
29462
30066
  ...measure && MEASURES.includes(measure) ? { measure } : {},
29463
30067
  ...granularity === "day" || granularity === "week" || granularity === "month" ? { granularity } : {},
30068
+ ...hostId2 !== void 0 && hostId2.length > 0 ? { hostId: hostId2 } : {},
29464
30069
  ...harness2 !== void 0 ? { harness: harness2 } : {},
29465
30070
  ...model2 !== void 0 ? { model: model2 } : {},
29466
30071
  ...project3 !== void 0 ? { project: project3 } : {},
@@ -29499,7 +30104,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29499
30104
  day.setDate(day.getDate() - (day.getDay() + 6) % 7);
29500
30105
  return isoDate(day);
29501
30106
  }
29502
- function createUsageStatisticsPage(consoleMessages2, request, pageLocale) {
30107
+ function createUsageStatisticsPage(consoleMessages2, request, pageLocale, usageHosts) {
29503
30108
  const messages = consoleMessages2.usageStatistics;
29504
30109
  return Object.freeze({
29505
30110
  id: "usage-statistics",
@@ -29508,10 +30113,12 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29508
30113
  mount(context) {
29509
30114
  const document2 = context.content.ownerDocument;
29510
30115
  const locale = pageLocale ?? (document2.documentElement.lang || "en");
30116
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
29511
30117
  const count3 = (value) => count2(value, locale);
29512
30118
  const tokenCount2 = (totals2, value) => tokenCount(totals2, value, locale);
29513
30119
  const saved = readView();
29514
30120
  const view = {
30121
+ hostId: saved.hostId ?? LOCAL_USAGE_HOST_ID,
29515
30122
  range: saved.range ?? "30d",
29516
30123
  measure: saved.measure ?? "cost",
29517
30124
  granularity: saved.granularity ?? null,
@@ -29542,7 +30149,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29542
30149
  let projectLabel = /* @__PURE__ */ new Map();
29543
30150
  const projectName = (key) => key === UNKNOWN ? messages.unknownProject : projectLabel.get(key) ?? baseName(key);
29544
30151
  const measureLabel = (measure) => measure === "cost" ? messages.cost : messages.tokens;
29545
- const dateFormat = (options) => new Intl.DateTimeFormat(locale, options);
30152
+ const dateFormat = (options) => new Intl.DateTimeFormat(locale, { ...options, timeZone });
29546
30153
  const shortDate = dateFormat({ month: "short", day: "numeric" });
29547
30154
  const longDate = dateFormat({
29548
30155
  year: "numeric",
@@ -29561,10 +30168,51 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29561
30168
  const prices = createModelPricesDialog(
29562
30169
  document2,
29563
30170
  consoleMessages2,
29564
- request,
30171
+ (method, params2) => request(method, params2, view.hostId),
29565
30172
  context.signal,
29566
30173
  load
29567
30174
  );
30175
+ let offeredHosts = usageHosts ? [] : void 0;
30176
+ const hostCombo = new ComboBox(document2, {
30177
+ label: messages.host,
30178
+ searchLabel: messages.search,
30179
+ emptyLabel: messages.noMatches,
30180
+ signal: context.signal,
30181
+ searchable: false,
30182
+ display: (option) => `${messages.host} \xB7 ${option.label}`,
30183
+ onChange: (key) => {
30184
+ if (key === view.hostId) return;
30185
+ view.hostId = key;
30186
+ view.harness = "";
30187
+ view.model = "";
30188
+ view.project = "";
30189
+ date5 = null;
30190
+ unpricedOnly = false;
30191
+ result = null;
30192
+ error51 = null;
30193
+ loadedAt = 0;
30194
+ names.clear();
30195
+ save();
30196
+ hostOptions();
30197
+ render();
30198
+ void refreshHarnessNames();
30199
+ load();
30200
+ }
30201
+ });
30202
+ const hostOptions = () => {
30203
+ const options = usageHostOptions(offeredHosts, messages.localHost, view.hostId);
30204
+ hostCombo.element.hidden = options.length < 2;
30205
+ hostCombo.update(options, view.hostId === LOCAL_USAGE_HOST_ID ? "" : view.hostId);
30206
+ };
30207
+ const offerHosts = () => {
30208
+ if (!usageHosts) return;
30209
+ void usageHosts().then((hosts) => {
30210
+ if (context.signal.aborted) return;
30211
+ offeredHosts = hosts;
30212
+ hostOptions();
30213
+ }).catch(() => void 0);
30214
+ };
30215
+ hostOptions();
29568
30216
  const updated = h(document2, "span", { className: "console-muted console-usage-updated" });
29569
30217
  const refresh = h(
29570
30218
  document2,
@@ -29577,7 +30225,10 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29577
30225
  },
29578
30226
  createRendererSettingsIcon("refresh", 16)
29579
30227
  );
29580
- refresh.addEventListener("click", () => load());
30228
+ refresh.addEventListener("click", () => {
30229
+ offerHosts();
30230
+ load();
30231
+ });
29581
30232
  const auto = new ComboBox(document2, {
29582
30233
  label: messages.autoRefresh,
29583
30234
  searchLabel: messages.search,
@@ -29616,6 +30267,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
29616
30267
  document2,
29617
30268
  "div",
29618
30269
  { className: "console-usage-toolbar" },
30270
+ hostCombo.element,
29619
30271
  updated,
29620
30272
  refresh,
29621
30273
  auto.element,
@@ -30254,7 +30906,6 @@ ${detail}` : ""}`
30254
30906
  }
30255
30907
  function hourlyPanel(data) {
30256
30908
  const singleDay = data.filters.date !== null || data.range === "today";
30257
- const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
30258
30909
  return panel(
30259
30910
  singleDay ? messages.hourlyDay : messages.hourly,
30260
30911
  hourlyChart(document2, {
@@ -30269,7 +30920,7 @@ ${detail}` : ""}`
30269
30920
  weekStartsOnMonday: !locale.startsWith("en"),
30270
30921
  labels: { cost: messages.cost, tokens: messages.tokens }
30271
30922
  }),
30272
- h(document2, "span", { className: "console-muted console-usage-zone" }, zone)
30923
+ h(document2, "span", { className: "console-muted console-usage-zone" }, timeZone)
30273
30924
  );
30274
30925
  }
30275
30926
  function sessionsPanel(title, rows, tableKey) {
@@ -30416,6 +31067,7 @@ ${detail}` : ""}`
30416
31067
  const project3 = filterValue(view.project);
30417
31068
  return {
30418
31069
  range: view.range,
31070
+ timeZone,
30419
31071
  ...view.harness ? { harness: view.harness } : {},
30420
31072
  ...model2 !== void 0 ? { model: model2 } : {},
30421
31073
  ...project3 !== void 0 ? { project: project3 } : {},
@@ -30428,10 +31080,26 @@ ${detail}` : ""}`
30428
31080
  if (result && !result.reading.complete) poll = window.setTimeout(load, POLL_MS);
30429
31081
  else if (view.autoRefreshMs > 0) poll = window.setTimeout(load, view.autoRefreshMs);
30430
31082
  }
31083
+ const harnessNamesRead = createLatestKeyGuard();
31084
+ async function refreshHarnessNames() {
31085
+ const hostId2 = view.hostId;
31086
+ const isCurrent = harnessNamesRead.begin(hostId2);
31087
+ names.clear();
31088
+ try {
31089
+ const value = await request(HARNESS_PLUGIN_LIST_METHOD2, {}, hostId2);
31090
+ if (!isCurrent()) return;
31091
+ for (const plugin of harnessPluginListResultSchema.parse(value).plugins) {
31092
+ names.set(plugin.id, plugin.name);
31093
+ }
31094
+ } catch {
31095
+ if (!isCurrent()) return;
31096
+ }
31097
+ if (!context.signal.aborted) render();
31098
+ }
30431
31099
  function load() {
30432
31100
  window.clearTimeout(poll);
30433
31101
  const requested = params();
30434
- void context.runLatest(() => request(USAGE_STATISTICS_METHOD, requested), {
31102
+ void context.runLatest(() => request(USAGE_STATISTICS_METHOD, requested, view.hostId), {
30435
31103
  success(value) {
30436
31104
  const parsed = usageStatisticsResultSchema.safeParse(value);
30437
31105
  if (parsed.success) {
@@ -30456,12 +31124,8 @@ ${detail}` : ""}`
30456
31124
  }
30457
31125
  context.content.replaceChildren(header, prices.element, filters, notices, body);
30458
31126
  render();
30459
- void request(HARNESS_PLUGIN_LIST_METHOD2, {}).then((value) => {
30460
- for (const plugin of harnessPluginListResultSchema.parse(value).plugins) {
30461
- names.set(plugin.id, plugin.name);
30462
- }
30463
- if (!context.signal.aborted) render();
30464
- }).catch(() => void 0);
31127
+ offerHosts();
31128
+ void refreshHarnessNames();
30465
31129
  load();
30466
31130
  return () => {
30467
31131
  window.clearTimeout(poll);
@@ -30567,6 +31231,8 @@ ${detail}` : ""}`
30567
31231
  harness: "Harness",
30568
31232
  model: "Model",
30569
31233
  project: "Project",
31234
+ host: "Machine",
31235
+ localHost: "This machine",
30570
31236
  filterModel: "Filter by model",
30571
31237
  filterProject: "Filter by project",
30572
31238
  unknownModel: "Unknown model",
@@ -30763,6 +31429,8 @@ ${detail}` : ""}`
30763
31429
  harness: "Harness",
30764
31430
  model: "\u6A21\u578B",
30765
31431
  project: "\u9879\u76EE",
31432
+ host: "\u673A\u5668",
31433
+ localHost: "\u672C\u673A",
30766
31434
  filterModel: "\u6309\u6A21\u578B\u7B5B\u9009",
30767
31435
  filterProject: "\u6309\u9879\u76EE\u7B5B\u9009",
30768
31436
  unknownModel: "\u672A\u77E5\u6A21\u578B",
@@ -32602,7 +33270,7 @@ ${detail}` : ""}`
32602
33270
  void context.runLatest(
32603
33271
  async (signal) => {
32604
33272
  const missing = new Set(
32605
- getDiagnostics()?.snapshot().hosts.find(({ hostId: hostId2 }) => hostId2 === "local")?.agents.filter(({ availability }) => availability === "notInstalled").map(({ agent }) => agent)
33273
+ getDiagnostics()?.snapshot().hosts.find(({ hostId: hostId2 }) => hostId2 === "local")?.agents.filter(({ availability: availability2 }) => availability2 === "notInstalled").map(({ agent }) => agent)
32606
33274
  );
32607
33275
  const harnesses = (await client.listSessionImportSources()).harnesses.filter(
32608
33276
  ({ harnessId }) => !missing.has(harnessId)
@@ -33160,7 +33828,7 @@ ${detail}` : ""}`
33160
33828
  }
33161
33829
  function defaultImportName(source, existing) {
33162
33830
  const base = source.provider === "openai-codex" ? "codex" : "grok";
33163
- const used = new Set(existing.map((record7) => record7.name));
33831
+ const used = new Set(existing.map((record11) => record11.name));
33164
33832
  const valid = (name) => credentialImportNameSchema.safeParse(name).success;
33165
33833
  if (!used.has(base)) return base;
33166
33834
  const local = source.label.includes("@") ? source.label.split("@")[0] ?? "" : "";
@@ -33183,7 +33851,7 @@ ${detail}` : ""}`
33183
33851
  const shown = (text) => accountDisplayText(text, hideEmails);
33184
33852
  const targetButtons = /* @__PURE__ */ new Map();
33185
33853
  const importedRecords = () => snapshot.targets.find((target) => target.harnessId === TARGET_HARNESS_ID)?.imports ?? [];
33186
- const sourceOf = (record7) => snapshot.sources.find((source) => source.id === record7.source.id);
33854
+ const sourceOf = (record11) => snapshot.sources.find((source) => source.id === record11.source.id);
33187
33855
  const piTarget = () => snapshot.targets.find((candidate) => candidate.harnessId === TARGET_HARNESS_ID);
33188
33856
  const compatibleSources = () => {
33189
33857
  const target = piTarget();
@@ -33221,7 +33889,7 @@ ${detail}` : ""}`
33221
33889
  sectionImport.addEventListener("click", () => {
33222
33890
  const sources = compatibleSources();
33223
33891
  const free = sources.find(
33224
- (source2) => !importedRecords().some((record7) => record7.source.id === source2.id)
33892
+ (source2) => !importedRecords().some((record11) => record11.source.id === source2.id)
33225
33893
  );
33226
33894
  const source = free ?? sources[0];
33227
33895
  if (source) openDialog("add", { source, choose: true }, SECTION_IMPORT_KEY);
@@ -33271,30 +33939,30 @@ ${detail}` : ""}`
33271
33939
  mark.append(createRendererAgentIcon(agent ?? "pi", 26, document2, pluginFor(agent ?? "pi")));
33272
33940
  return mark;
33273
33941
  };
33274
- const renderRow = (record7) => {
33942
+ const renderRow = (record11) => {
33275
33943
  const row = document2.createElement("div");
33276
33944
  row.className = "settings-pi-accounts__row";
33277
33945
  row.tabIndex = -1;
33278
- row.dataset.importName = record7.name;
33279
- row.setAttribute("aria-label", shown(record7.source.label));
33280
- const agent = record7.source.harnessId;
33946
+ row.dataset.importName = record11.name;
33947
+ row.setAttribute("aria-label", shown(record11.source.label));
33948
+ const agent = record11.source.harnessId;
33281
33949
  const mark = createMark(agent);
33282
33950
  const identity = document2.createElement("div");
33283
33951
  identity.className = "settings-pi-accounts__identity";
33284
33952
  const label = document2.createElement("strong");
33285
33953
  label.className = "settings-account-email";
33286
- label.textContent = shown(record7.source.label);
33954
+ label.textContent = shown(record11.source.label);
33287
33955
  label.title = label.textContent;
33288
33956
  label.translate = false;
33289
33957
  const meta3 = document2.createElement("div");
33290
33958
  meta3.className = "settings-account-metadata";
33291
- const source = sourceOf(record7);
33959
+ const source = sourceOf(record11);
33292
33960
  const parts = [
33293
33961
  metaPart(rendererAgentLabel(agent, pluginFor(agent)), "settings-pi-accounts__agent"),
33294
- metaPart(`${record7.name}/\u2026`, void 0, true),
33962
+ metaPart(`${record11.name}/\u2026`, void 0, true),
33295
33963
  metaPart(messages.copied)
33296
33964
  ];
33297
- const time3 = formatImportedAt(record7.importedAt);
33965
+ const time3 = formatImportedAt(record11.importedAt);
33298
33966
  if (time3) parts.push(metaPart(time3));
33299
33967
  parts.forEach((part, index) => {
33300
33968
  if (index > 0) {
@@ -33311,23 +33979,23 @@ ${detail}` : ""}`
33311
33979
  reimport.type = "button";
33312
33980
  reimport.className = "settings-account-action";
33313
33981
  reimport.textContent = messages.rowReimport;
33314
- reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record7.source.label)}`);
33982
+ reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record11.source.label)}`);
33315
33983
  reimport.disabled = busy || !source;
33316
33984
  reimport.title = messages.reimport;
33317
33985
  reimport.addEventListener("click", () => {
33318
- if (source) openDialog("reimport", { source, record: record7 }, `row:${record7.name}`);
33986
+ if (source) openDialog("reimport", { source, record: record11 }, `row:${record11.name}`);
33319
33987
  });
33320
33988
  const remove = document2.createElement("button");
33321
33989
  remove.type = "button";
33322
33990
  remove.className = "settings-account-action settings-pi-accounts__remove";
33323
33991
  remove.textContent = messages.rowRemove;
33324
- remove.setAttribute("aria-label", `${messages.remove}: ${shown(record7.source.label)}`);
33992
+ remove.setAttribute("aria-label", `${messages.remove}: ${shown(record11.source.label)}`);
33325
33993
  remove.disabled = busy;
33326
- remove.addEventListener("click", () => openDialog("remove", { record: record7 }, `row:${record7.name}`));
33994
+ remove.addEventListener("click", () => openDialog("remove", { record: record11 }, `row:${record11.name}`));
33327
33995
  if (source) actions.append(reimport);
33328
33996
  actions.append(remove);
33329
33997
  row.append(mark, identity, actions);
33330
- rows.set(record7.name, row);
33998
+ rows.set(record11.name, row);
33331
33999
  return row;
33332
34000
  };
33333
34001
  const loginTypeLabel = (type) => type === "oauth" ? messages.typeOauth : type === "api_key" ? messages.typeApiKey : messages.typeOther;
@@ -33433,7 +34101,7 @@ ${detail}` : ""}`
33433
34101
  controls.className = "settings-credential-dialog__actions";
33434
34102
  modal.append(title, body, error51, controls);
33435
34103
  let state = initial;
33436
- let mode = initialMode;
34104
+ let mode2 = initialMode;
33437
34105
  let nameInput;
33438
34106
  let nameEdited = false;
33439
34107
  let sourceRadios = [];
@@ -33480,7 +34148,7 @@ ${detail}` : ""}`
33480
34148
  const label = document2.createElement("strong");
33481
34149
  label.textContent = shown(choice.label);
33482
34150
  label.translate = false;
33483
- const existing = importedRecords().find((record7) => record7.source.id === choice.id);
34151
+ const existing = importedRecords().find((record11) => record11.source.id === choice.id);
33484
34152
  const agent = choice.harnessId;
33485
34153
  const detail = document2.createElement("span");
33486
34154
  detail.textContent = [
@@ -33521,7 +34189,7 @@ ${detail}` : ""}`
33521
34189
  const name = request.action === "list" ? void 0 : request.name;
33522
34190
  state = {
33523
34191
  source: state.source,
33524
- record: importedRecords().find((record7) => record7.name === name) ?? state.record
34192
+ record: importedRecords().find((record11) => record11.name === name) ?? state.record
33525
34193
  };
33526
34194
  show(next);
33527
34195
  } else {
@@ -33529,19 +34197,19 @@ ${detail}` : ""}`
33529
34197
  }
33530
34198
  };
33531
34199
  const show = (next) => {
33532
- mode = next;
34200
+ mode2 = next;
33533
34201
  error51.textContent = "";
33534
34202
  nameInput = void 0;
33535
34203
  sourceRadios = [];
33536
34204
  body.replaceChildren();
33537
34205
  controls.replaceChildren();
33538
- const { source, record: record7 } = state;
34206
+ const { source, record: record11 } = state;
33539
34207
  const close = () => modal.close();
33540
- if (mode === "add" || mode === "reimport") {
33541
- title.textContent = mode === "add" ? messages.add : messages.reimport;
34208
+ if (mode2 === "add" || mode2 === "reimport") {
34209
+ title.textContent = mode2 === "add" ? messages.add : messages.reimport;
33542
34210
  modal.setAttribute("aria-label", title.textContent);
33543
- const active = source ?? record7?.source;
33544
- const choices = mode === "add" && state.choose ? compatibleSources() : [];
34211
+ const active = source ?? record11?.source;
34212
+ const choices = mode2 === "add" && state.choose ? compatibleSources() : [];
33545
34213
  if (choices.length > 1) body.append(sourcePicker(choices));
33546
34214
  else if (active) body.append(line(messages.source, shown(active.label)));
33547
34215
  const input = document2.createElement("input");
@@ -33549,8 +34217,8 @@ ${detail}` : ""}`
33549
34217
  input.maxLength = 48;
33550
34218
  input.autocomplete = "off";
33551
34219
  input.spellcheck = false;
33552
- input.value = record7?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
33553
- input.readOnly = Boolean(record7);
34220
+ input.value = record11?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
34221
+ input.readOnly = Boolean(record11);
33554
34222
  input.addEventListener("input", () => {
33555
34223
  nameEdited = true;
33556
34224
  });
@@ -33562,7 +34230,7 @@ ${detail}` : ""}`
33562
34230
  label.append(caption, input);
33563
34231
  const preview = note("");
33564
34232
  const update = () => {
33565
- preview.textContent = (mode === "reimport" ? messages.reimportPreview : messages.preview).replace("{name}", input.value);
34233
+ preview.textContent = (mode2 === "reimport" ? messages.reimportPreview : messages.preview).replace("{name}", input.value);
33566
34234
  };
33567
34235
  input.addEventListener("input", update);
33568
34236
  refreshPreview = update;
@@ -33582,9 +34250,9 @@ ${detail}` : ""}`
33582
34250
  }
33583
34251
  await submit(
33584
34252
  {
33585
- action: mode === "reimport" ? "reimport" : "import",
34253
+ action: mode2 === "reimport" ? "reimport" : "import",
33586
34254
  sourceId: source2.id,
33587
- name: record7?.name ?? input.value,
34255
+ name: record11?.name ?? input.value,
33588
34256
  confirmed: true
33589
34257
  },
33590
34258
  "done"
@@ -33593,17 +34261,17 @@ ${detail}` : ""}`
33593
34261
  "primary"
33594
34262
  )
33595
34263
  );
33596
- (mode === "add" ? input : controls.children[0]).focus();
33597
- } else if (mode === "remove" && record7) {
34264
+ (mode2 === "add" ? input : controls.children[0]).focus();
34265
+ } else if (mode2 === "remove" && record11) {
33598
34266
  title.textContent = messages.remove;
33599
34267
  modal.setAttribute("aria-label", title.textContent);
33600
- body.append(note(messages.removeWarning.replace("{name}", record7.name)));
34268
+ body.append(note(messages.removeWarning.replace("{name}", record11.name)));
33601
34269
  const cancel = command(messages.cancel, close);
33602
34270
  controls.append(
33603
34271
  cancel,
33604
34272
  command(
33605
34273
  messages.remove,
33606
- () => submit({ action: "remove", name: record7.name, confirmed: true }, null),
34274
+ () => submit({ action: "remove", name: record11.name, confirmed: true }, null),
33607
34275
  "danger"
33608
34276
  )
33609
34277
  );
@@ -33611,7 +34279,7 @@ ${detail}` : ""}`
33611
34279
  } else {
33612
34280
  title.textContent = messages.doneTitle;
33613
34281
  modal.setAttribute("aria-label", title.textContent);
33614
- const name = record7?.name;
34282
+ const name = record11?.name;
33615
34283
  if (name) body.append(line(messages.entry, `${name}/\u2026`, true));
33616
34284
  body.append(note(messages.done));
33617
34285
  const done = command(messages.close, close, "primary");
@@ -33658,21 +34326,21 @@ ${detail}` : ""}`
33658
34326
  (candidate) => candidate.harnessId === TARGET_HARNESS_ID && source && candidate.providers.includes(source.provider)
33659
34327
  );
33660
34328
  if (!source || !target) return null;
33661
- const record7 = target.imports.find((candidate) => candidate.source.id === source.id);
34329
+ const record11 = target.imports.find((candidate) => candidate.source.id === source.id);
33662
34330
  const key = `${harnessId}:${accountLabel}:import`;
33663
34331
  const button2 = document2.createElement("button");
33664
34332
  button2.type = "button";
33665
34333
  button2.className = "settings-account-pi-import";
33666
34334
  button2.dataset.accountFocus = key;
33667
34335
  button2.disabled = busy;
33668
- const hint = record7 ? messages.importedHint.replace("{name}", record7.name) : messages.add;
34336
+ const hint = record11 ? messages.importedHint.replace("{name}", record11.name) : messages.add;
33669
34337
  button2.title = hint;
33670
34338
  button2.setAttribute("aria-label", hint);
33671
34339
  button2.append(createRendererAgentIcon("pi", 12, document2, pluginFor("pi")));
33672
- if (record7) {
34340
+ if (record11) {
33673
34341
  button2.dataset.state = "imported";
33674
34342
  const name = document2.createElement("code");
33675
- name.textContent = `${record7.name}/\u2026`;
34343
+ name.textContent = `${record11.name}/\u2026`;
33676
34344
  name.translate = false;
33677
34345
  button2.append(name, createRendererSettingsIcon("check", 12));
33678
34346
  } else {
@@ -33680,7 +34348,7 @@ ${detail}` : ""}`
33680
34348
  button2.append(messages.add);
33681
34349
  }
33682
34350
  button2.addEventListener("click", () => {
33683
- if (!record7) {
34351
+ if (!record11) {
33684
34352
  openDialog("add", { source }, key);
33685
34353
  return;
33686
34354
  }
@@ -33689,7 +34357,7 @@ ${detail}` : ""}`
33689
34357
  renderSection();
33690
34358
  sectionToggle.setAttribute("aria-expanded", "true");
33691
34359
  }
33692
- const row = rows.get(record7.name);
34360
+ const row = rows.get(record11.name);
33693
34361
  row?.scrollIntoView({ block: "nearest", behavior: "smooth" });
33694
34362
  row?.focus();
33695
34363
  });
@@ -34694,10 +35362,10 @@ ${detail}` : ""}`
34694
35362
  };
34695
35363
  function runBoundedRendererUpdateRequest(operation, signal, timeoutMs = RENDERER_UPDATE_REQUEST_TIMEOUT_MS) {
34696
35364
  return new Promise((resolve, reject) => {
34697
- let settled = false;
35365
+ let settled2 = false;
34698
35366
  const settle = (handler) => {
34699
- if (settled) return;
34700
- settled = true;
35367
+ if (settled2) return;
35368
+ settled2 = true;
34701
35369
  clearTimeout(timeout);
34702
35370
  signal.removeEventListener("abort", abort);
34703
35371
  handler();
@@ -35234,7 +35902,7 @@ ${detail}` : ""}`
35234
35902
  }
35235
35903
  });
35236
35904
  }
35237
- 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")), requestVoiceSettings = () => Promise.reject(new Error("Local Host connection is unavailable"))) {
35905
+ 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, requestVoiceSettings = () => Promise.reject(new Error("Local Host connection is unavailable"))) {
35238
35906
  return Object.freeze([
35239
35907
  createConnectionsSettingsPage(messages, getDiagnostics, void 0, getRemoteConnections),
35240
35908
  createRemoteConnectionsPage(messages, getRemoteConnections),
@@ -35248,7 +35916,8 @@ ${detail}` : ""}`
35248
35916
  createUsageStatisticsPage(
35249
35917
  consoleMessages(messages.locale),
35250
35918
  requestUsageStatistics,
35251
- messages.locale
35919
+ messages.locale,
35920
+ usageStatisticsHosts
35252
35921
  ),
35253
35922
  createAppearanceSettingsPage(messages, getLoadedSessionsClient),
35254
35923
  createVoiceSettingsPage(messages.locale, requestVoiceSettings, { desktop: true }),
@@ -35256,7 +35925,7 @@ ${detail}` : ""}`
35256
35925
  aboutPage(messages, getUpdateClient)
35257
35926
  ]);
35258
35927
  }
35259
- function createDefaultRendererSettingsRegistry(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread, requestUsageStatistics) {
35928
+ function createDefaultRendererSettingsRegistry(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread, requestUsageStatistics, usageStatisticsHosts) {
35260
35929
  return createRendererSettingsPageRegistry(
35261
35930
  createDefaultRendererSettingsPages(
35262
35931
  messages,
@@ -35267,7 +35936,8 @@ ${detail}` : ""}`
35267
35936
  openImportedThread,
35268
35937
  void 0,
35269
35938
  void 0,
35270
- requestUsageStatistics
35939
+ requestUsageStatistics,
35940
+ usageStatisticsHosts
35271
35941
  )
35272
35942
  );
35273
35943
  }
@@ -36041,6 +36711,20 @@ ${detail}` : ""}`
36041
36711
  gap: 18px;
36042
36712
  }
36043
36713
 
36714
+ .settings-connections-content {
36715
+ container: settings-connections / inline-size;
36716
+ }
36717
+
36718
+ @container settings-connections (max-width: 780px) {
36719
+ .settings-connections-layout {
36720
+ grid-template-columns: minmax(0, 1fr);
36721
+ }
36722
+
36723
+ .settings-connection-inspector {
36724
+ position: static;
36725
+ }
36726
+ }
36727
+
36044
36728
  .settings-connection-list,
36045
36729
  .settings-connection-inspector {
36046
36730
  overflow: hidden;
@@ -36049,14 +36733,36 @@ ${detail}` : ""}`
36049
36733
  border-radius: 10px;
36050
36734
  }
36051
36735
 
36736
+ .settings-connection-host-header {
36737
+ display: flex;
36738
+ align-items: center;
36739
+ min-width: 0;
36740
+ border-bottom: 1px solid var(--settings-divider);
36741
+ }
36742
+
36743
+ .settings-connection-update-all {
36744
+ flex: none;
36745
+ margin-right: 10px;
36746
+ white-space: nowrap;
36747
+ }
36748
+
36749
+ .settings-connection-update-result {
36750
+ margin: 0;
36751
+ padding: 7px 10px;
36752
+ color: var(--settings-muted);
36753
+ font-size: 11px;
36754
+ line-height: 18px;
36755
+ border-bottom: 1px solid var(--settings-divider);
36756
+ }
36757
+
36052
36758
  .settings-connection-host-strip {
36053
36759
  display: grid;
36760
+ flex: 1;
36054
36761
  grid-template-columns: 30px minmax(0, 1fr) 30px;
36055
36762
  align-items: center;
36056
36763
  min-width: 0;
36057
36764
  gap: 5px;
36058
36765
  padding: 9px 10px;
36059
- border-bottom: 1px solid var(--settings-divider);
36060
36766
  }
36061
36767
 
36062
36768
  .settings-connection-host-scroll {
@@ -36153,7 +36859,7 @@ ${detail}` : ""}`
36153
36859
  .settings-connection-table-header,
36154
36860
  .settings-connection-row {
36155
36861
  display: grid;
36156
- grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) 108px;
36862
+ grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) minmax(108px, max-content);
36157
36863
  align-items: center;
36158
36864
  min-width: 0;
36159
36865
  gap: 10px;
@@ -36246,15 +36952,12 @@ ${detail}` : ""}`
36246
36952
  line-height: 18px;
36247
36953
  }
36248
36954
 
36249
- .settings-connection-row__status:has(.settings-connection-version-available) {
36250
- flex-wrap: wrap;
36251
- max-width: 160px;
36252
- }
36253
-
36254
36955
  .settings-connection-version-available {
36255
- flex-basis: 100%;
36256
- color: var(--settings-focus);
36257
- overflow-wrap: anywhere;
36956
+ flex: none;
36957
+ color: var(--settings-muted);
36958
+ font-size: 10px;
36959
+ line-height: 16px;
36960
+ white-space: nowrap;
36258
36961
  }
36259
36962
 
36260
36963
  .settings-connection-row__status::before {
@@ -36293,6 +36996,7 @@ ${detail}` : ""}`
36293
36996
  justify-content: flex-end;
36294
36997
  min-width: 0;
36295
36998
  gap: 4px;
36999
+ white-space: nowrap;
36296
37000
  }
36297
37001
 
36298
37002
  .settings-connection-row__handle {
@@ -40291,7 +40995,7 @@ th[aria-sort] .console-usage-sort__mark {
40291
40995
  place();
40292
40996
  const observer = ownerWindow ? new ownerWindow.MutationObserver((records) => {
40293
40997
  const titlebar = source?.closest("[data-app-shell-titlebar]");
40294
- if (!source?.isConnected || records.some((record7) => titlebar?.contains(record7.target))) {
40998
+ if (!source?.isConnected || records.some((record11) => titlebar?.contains(record11.target))) {
40295
40999
  place();
40296
41000
  }
40297
41001
  }) : null;
@@ -40696,7 +41400,10 @@ ${usage_default}`;
40696
41400
  var UPDATE_RETRY_DELAYS_MS = [1e3, 3e3, 1e4, 3e4];
40697
41401
  function installRendererSettingsLifecycle(ownerWindow = window, options = {}) {
40698
41402
  const lifecycleController = new AbortController();
40699
- let locale = resolveRendererSettingsLocale(ownerWindow.navigator.languages);
41403
+ const documentLanguage = ownerWindow.document?.documentElement?.lang;
41404
+ let locale = resolveRendererSettingsLocale(
41405
+ documentLanguage ? [documentLanguage] : ownerWindow.navigator.languages
41406
+ );
40700
41407
  let shell = null;
40701
41408
  let trigger = null;
40702
41409
  let localeRequest = null;
@@ -40726,6 +41433,7 @@ ${usage_default}`;
40726
41433
  options.getLoadedSessionsClient ?? (() => null),
40727
41434
  options.getRemoteConnections ?? (() => null),
40728
41435
  options.requestUsageStatistics,
41436
+ options.usageStatisticsHosts,
40729
41437
  options.requestVoiceSettings
40730
41438
  );
40731
41439
  const nextShell = installRendererSettingsShell(definitions, messages, ownerWindow.document, {
@@ -40875,6 +41583,30 @@ ${usage_default}`;
40875
41583
  };
40876
41584
  }
40877
41585
 
41586
+ // src/renderer-usage-statistics-source.ts
41587
+ function createRendererUsageStatisticsSource(options) {
41588
+ return {
41589
+ async request(method, params, hostId2) {
41590
+ const route = options.routing()?.forHost(hostId2);
41591
+ if (options.disposed() || !route) {
41592
+ throw new Error(`Host connection is unavailable (${hostId2})`);
41593
+ }
41594
+ return route.manager.sendRequest(method, params);
41595
+ },
41596
+ async hosts() {
41597
+ const connections = await options.listConnections().catch(() => []);
41598
+ const names = new Map(
41599
+ connections.map((connection) => [connection.hostId, connection.displayName])
41600
+ );
41601
+ const known = options.routing()?.knownHostIds?.() ?? [];
41602
+ return [.../* @__PURE__ */ new Set([...known, ...names.keys()])].map((hostId2) => {
41603
+ const label = names.get(hostId2);
41604
+ return label === void 0 ? { hostId: hostId2 } : { hostId: hostId2, label };
41605
+ });
41606
+ }
41607
+ };
41608
+ }
41609
+
40878
41610
  // src/renderer-native-composer-controller.ts
40879
41611
  var MAX_ELEMENT_DEPTH = 4;
40880
41612
  var MAX_FIBER_DEPTH = 40;
@@ -41438,17 +42170,17 @@ ${usage_default}`;
41438
42170
 
41439
42171
  // src/renderer-binding-probe.ts
41440
42172
  var EMPTY_PLUGINS = [];
41441
- function isRetryableHarnessAvailability(availability, error51) {
41442
- return availability !== void 0 && availability !== "ready" && availability !== "notInstalled" && error51?.retryable === true;
42173
+ function isRetryableHarnessAvailability(availability2, error51) {
42174
+ return availability2 !== void 0 && availability2 !== "ready" && availability2 !== "notInstalled" && error51?.retryable === true;
41443
42175
  }
41444
- function retryableHarnessAvailabilityAgents(availability, errors) {
41445
- return Object.keys(availability).filter(
41446
- (agent) => isRetryableHarnessAvailability(availability[agent], errors[agent])
42176
+ function retryableHarnessAvailabilityAgents(availability2, errors) {
42177
+ return Object.keys(availability2).filter(
42178
+ (agent) => isRetryableHarnessAvailability(availability2[agent], errors[agent])
41447
42179
  );
41448
42180
  }
41449
- function passiveHarnessAvailabilityAgents(availability, errors) {
41450
- return Object.keys(availability).filter(
41451
- (agent) => availability[agent] === "checking" || isRetryableHarnessAvailability(availability[agent], errors[agent])
42181
+ function passiveHarnessAvailabilityAgents(availability2, errors) {
42182
+ return Object.keys(availability2).filter(
42183
+ (agent) => availability2[agent] === "checking" || isRetryableHarnessAvailability(availability2[agent], errors[agent])
41452
42184
  );
41453
42185
  }
41454
42186
  function shouldRefreshCodexAccountsForAdapterState(state) {
@@ -41809,6 +42541,11 @@ ${usage_default}`;
41809
42541
  return route.manager.sendRequest(method, params);
41810
42542
  };
41811
42543
  const stopVoiceSync = startVoiceSettingsSync(window, requestLocalSettings);
42544
+ const usageStatistics = createRendererUsageStatisticsSource({
42545
+ routing: () => window.__codexhostHostRoutingV1,
42546
+ listConnections: () => remoteConnections.ssh.list(),
42547
+ disposed: () => disposed
42548
+ });
41812
42549
  const settingsLifecycle = installRendererSettingsLifecycle(window, {
41813
42550
  requestVoiceSettings: (params) => requestLocalSettings("codexhost/voice/settings", params),
41814
42551
  getRemoteConnections: () => remoteConnections,
@@ -41816,11 +42553,8 @@ ${usage_default}`;
41816
42553
  getAccountClient: () => modelControl,
41817
42554
  getConnectionDiagnostics: () => connectionDiagnostics,
41818
42555
  getLoadedSessionsClient: () => modelClientForHost("local"),
41819
- async requestUsageStatistics(method, params) {
41820
- const route = window.__codexhostHostRoutingV1?.forHost("local");
41821
- if (disposed || !route) throw new Error("Local Host connection is unavailable");
41822
- return route.manager.sendRequest(method, params);
41823
- },
42556
+ requestUsageStatistics: usageStatistics.request,
42557
+ usageStatisticsHosts: usageStatistics.hosts,
41824
42558
  getSessionImportClient: () => {
41825
42559
  const client = modelClientForHost("local");
41826
42560
  const sources = client?.listSessionImportSources;
@@ -41917,9 +42651,10 @@ ${usage_default}`;
41917
42651
  };
41918
42652
  const notifySubmission = (composer, trigger) => {
41919
42653
  const state = controller.recordSubmission(composer);
42654
+ const createsThread = state.phase === "draft";
41920
42655
  const preferenceStorage = rendererNewThreadPreferenceStorage(activeModelHostId(composer));
41921
- writeNewThreadAgentPreference(state.agent, preferenceStorage);
41922
- if (state.agent !== "codex") {
42656
+ if (createsThread) writeNewThreadAgentPreference(state.agent, preferenceStorage);
42657
+ if (createsThread && state.agent !== "codex") {
41923
42658
  const model2 = controller.modelForAgent(composer, state.agent);
41924
42659
  if (model2) {
41925
42660
  writeNewThreadExternalConfigurationPreference(
@@ -42310,12 +43045,12 @@ ${usage_default}`;
42310
43045
  if (isDraft) mounted.hostId = requestHostId;
42311
43046
  const hostState = hostHarnessAvailabilityState(requestHostId);
42312
43047
  if (!hostState.plugins) void refreshHarnessAvailabilityForHost(requestHostId);
42313
- const availability = hostState.availability[agent] ?? (hostState.plugins ? "unavailable" : "checking");
42314
- if (availability !== "ready" && availability !== "checking") {
43048
+ const availability2 = hostState.availability[agent] ?? (hostState.plugins ? "unavailable" : "checking");
43049
+ if (availability2 !== "ready" && availability2 !== "checking") {
42315
43050
  mounted.modelView = {
42316
43051
  status: composerAdapterState(mounted) === "ready" ? "error" : "waitingForAdapter",
42317
43052
  thinkingSelectionSupported: false,
42318
- ...availability ? { error: `${agent} runtime is ${availability}` } : {}
43053
+ ...availability2 ? { error: `${agent} runtime is ${availability2}` } : {}
42319
43054
  };
42320
43055
  mounted.permissionModeView = { status: "idle" };
42321
43056
  renderMounted(mounted);
@@ -43725,8 +44460,8 @@ ${usage_default}`;
43725
44460
  readTargets: (editor) => {
43726
44461
  const composer = composerForElement(editor);
43727
44462
  const mounted = composer ? mountedByComposer.get(composer) : void 0;
43728
- const availability = mounted ? composerAvailability(mounted) : {};
43729
- return enabledAgents.filter((agent) => agent === "codex" || availability[agent] === "ready").map((agent) => {
44463
+ const availability2 = mounted ? composerAvailability(mounted) : {};
44464
+ return enabledAgents.filter((agent) => agent === "codex" || availability2[agent] === "ready").map((agent) => {
43730
44465
  const plugin = mounted?.hostId ? pluginForHost(mounted.hostId, agent) : void 0;
43731
44466
  return { agent, label: rendererAgentLabel(agent, plugin), ...plugin ? { plugin } : {} };
43732
44467
  });
@@ -43932,10 +44667,7 @@ ${usage_default}`;
43932
44667
  var HOOK_GLOBAL3 = "__codexhostExternalVoiceLaunchV1";
43933
44668
  var SHARED_ASSET = "app-shared-8bd9d0399038.js";
43934
44669
  var LAUNCH_ASSETS = [
43935
- ...CLIENT_OWNED_VOICE_ASSETS.map((profile) => ({
43936
- ...profile,
43937
- services: CLIENT_OWNED_VOICE_SERVICES
43938
- })),
44670
+ ...CLIENT_OWNED_VOICE_ASSETS,
43939
44671
  {
43940
44672
  version: AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION,
43941
44673
  initial: AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET,
@@ -43957,14 +44689,14 @@ ${usage_default}`;
43957
44689
  if (!route || route.hostId !== hostId2 || routing.forHost(hostId2) !== route) return request;
43958
44690
  const model2 = route.policy.selectedModel();
43959
44691
  if (!model2?.startsWith("codexhost/")) return request;
43960
- const mode = request.activeCollaborationMode;
43961
- if (mode !== void 0 && mode !== null && !isRecord16(mode)) return request;
43962
- const settings = isRecord16(mode) ? mode.settings : void 0;
44692
+ const mode2 = request.activeCollaborationMode;
44693
+ if (mode2 !== void 0 && mode2 !== null && !isRecord16(mode2)) return request;
44694
+ const settings = isRecord16(mode2) ? mode2.settings : void 0;
43963
44695
  if (settings !== void 0 && settings !== null && !isRecord16(settings)) return request;
43964
44696
  return {
43965
44697
  ...request,
43966
44698
  activeCollaborationMode: {
43967
- ...isRecord16(mode) ? mode : { mode: "default" },
44699
+ ...isRecord16(mode2) ? mode2 : { mode: "default" },
43968
44700
  settings: {
43969
44701
  reasoning_effort: null,
43970
44702
  developer_instructions: null,
@@ -44062,8 +44794,8 @@ ${usage_default}`;
44062
44794
  // src/renderer-voice-capability.ts
44063
44795
  var GLOBAL = "__codexhostVoiceCapabilityV1";
44064
44796
  var INFERENCE_GATE = "3683713372";
44065
- var record6 = (value) => value !== null && typeof value === "object";
44066
- var capable = (value) => record6(value) && typeof value.isLoading === "boolean" && typeof value.isError === "boolean" && typeof value.isCapable === "boolean";
44797
+ var record7 = (value) => value !== null && typeof value === "object";
44798
+ var capable = (value) => record7(value) && typeof value.isLoading === "boolean" && typeof value.isError === "boolean" && typeof value.isCapable === "boolean";
44067
44799
  var equal = (a, b) => a.isLoading === b.isLoading && a.isError === b.isError && a.isCapable === b.isCapable;
44068
44800
  function replayVoiceCapability(store, atom, gate) {
44069
44801
  const evaluate = (override) => {
@@ -44100,11 +44832,24 @@ ${usage_default}`;
44100
44832
  return null;
44101
44833
  }
44102
44834
  }
44835
+ function isFamily(value) {
44836
+ return record7(value) && record7(value.scope) && typeof value.resolve === "function";
44837
+ }
44838
+ function initializeVoiceCapabilityFamilies(module, assets) {
44839
+ const initialize = module[assets.capabilityInit];
44840
+ if (typeof initialize !== "function") throw new Error("Voice capability initializer unavailable");
44841
+ initialize();
44842
+ const family = module[assets.capabilityFamily];
44843
+ const gates = module[assets.inferenceGateFamily];
44844
+ if (!isFamily(family) || !isFamily(gates))
44845
+ throw new Error("Voice capability families unavailable");
44846
+ return { family, gates };
44847
+ }
44103
44848
  function hooks(fiber) {
44104
44849
  const result = [];
44105
44850
  const seen = /* @__PURE__ */ new Set();
44106
44851
  let hook = fiber.memoizedState;
44107
- while (record6(hook) && result.length < 4096 && !seen.has(hook)) {
44852
+ while (record7(hook) && result.length < 4096 && !seen.has(hook)) {
44108
44853
  seen.add(hook);
44109
44854
  result.push(hook);
44110
44855
  hook = hook.next;
@@ -44120,7 +44865,7 @@ ${usage_default}`;
44120
44865
  let root = ancestors[0];
44121
44866
  if (chat) {
44122
44867
  const owners = ancestors.filter(
44123
- ({ memoizedProps: props }) => record6(props) && props.isWorkConversation === false && props.isTemporaryChat === false && props.shouldBlockExternalEgress === false && props.readOnly !== true && typeof props.conversationId === "string" && record6(props.composerSelectionContext) && props.composerSelectionContext.conversationId === props.conversationId
44868
+ ({ memoizedProps: props }) => record7(props) && props.isWorkConversation === false && props.isTemporaryChat === false && props.shouldBlockExternalEgress === false && props.readOnly !== true && typeof props.conversationId === "string" && record7(props.composerSelectionContext) && props.composerSelectionContext.conversationId === props.conversationId
44124
44869
  );
44125
44870
  if (owners.length !== 1) return fibers;
44126
44871
  root = owners[0];
@@ -44132,7 +44877,7 @@ ${usage_default}`;
44132
44877
  const ancestors2 = committedReactAncestors(Object.getOwnPropertyDescriptor(element, key)?.value);
44133
44878
  const boundary = ancestors2.indexOf(root);
44134
44879
  if (boundary < 0) continue;
44135
- for (const fiber of ancestors2.slice(0, boundary + 1)) if (record6(fiber)) fibers.add(fiber);
44880
+ for (const fiber of ancestors2.slice(0, boundary + 1)) if (record7(fiber)) fibers.add(fiber);
44136
44881
  }
44137
44882
  return fibers;
44138
44883
  }
@@ -44144,7 +44889,7 @@ ${usage_default}`;
44144
44889
  allowed
44145
44890
  );
44146
44891
  }
44147
- function bindVoiceCapabilitySubscriptions(currentFibers, family, gates, allowed, realtimeOnly = false) {
44892
+ function bindVoiceCapabilitySubscriptions(currentFibers, family, gates, allowed, realtimeOnly = false, names = ["voice.realtime", "voice.thread"]) {
44148
44893
  const fibers = currentFibers();
44149
44894
  const restores = [];
44150
44895
  const bindings = [];
@@ -44153,7 +44898,7 @@ ${usage_default}`;
44153
44898
  const list = hooks(fiber);
44154
44899
  for (const memo of list) {
44155
44900
  const [signal, deps] = Array.isArray(memo.memoizedState) ? memo.memoizedState : [];
44156
- if (!record6(signal) || !Array.isArray(deps) || deps.length !== 5 || deps[3] !== family || !(deps[1] instanceof Map) || deps[2] !== void 0)
44901
+ if (!record7(signal) || !Array.isArray(deps) || deps.length !== 5 || deps[3] !== family || !(deps[1] instanceof Map) || deps[2] !== void 0)
44157
44902
  continue;
44158
44903
  const chain = deps[1];
44159
44904
  const node = chain.get(family.scope.id);
@@ -44162,7 +44907,7 @@ ${usage_default}`;
44162
44907
  const matches = [...members].filter(([, member]) => member.cacheKey === deps[0]);
44163
44908
  if (matches.length !== 1 || typeof matches[0]?.[0] !== "string") continue;
44164
44909
  const parameter = JSON.parse(matches[0][0]);
44165
- if (!record6(parameter) || Object.keys(parameter).some((key) => key !== "name" && key !== "hostId") || parameter.name !== "voice.realtime" && parameter.name !== "voice.thread" || realtimeOnly && parameter.name !== "voice.realtime" || parameter.hostId !== void 0 && parameter.hostId !== "local" || parameter.name === "voice.thread" && parameter.hostId !== "local")
44910
+ if (!record7(parameter) || Object.keys(parameter).some((key) => key !== "name" && key !== "hostId") || !names.some((name) => parameter.name === name) || realtimeOnly && parameter.name !== "voice.realtime" || parameter.hostId !== void 0 && parameter.hostId !== "local" || parameter.name === "voice.thread" && parameter.hostId !== "local")
44166
44911
  continue;
44167
44912
  const subscriptions = list.filter((hook2) => {
44168
44913
  const state = hook2.memoizedState;
@@ -44175,7 +44920,7 @@ ${usage_default}`;
44175
44920
  const effect = hook.next?.next?.memoizedState;
44176
44921
  const store = signal.store;
44177
44922
  const gate = gates.resolve(node, chain, INFERENCE_GATE)?.atom;
44178
- if (!gate || !instance || !record6(effect) || !Array.isArray(effect.deps) || effect.deps[0] !== subscriber.subscribe || typeof effect.create !== "function" || typeof instance.getSnapshot !== "function" || !capable(store.get(signal.atom)) || !capable(subscriber.getSnapshot()) || !capable(instance.getSnapshot()) || !equal(
44923
+ if (!gate || !instance || !record7(effect) || !Array.isArray(effect.deps) || effect.deps[0] !== subscriber.subscribe || typeof effect.create !== "function" || typeof instance.getSnapshot !== "function" || !capable(store.get(signal.atom)) || !capable(subscriber.getSnapshot()) || !capable(instance.getSnapshot()) || !equal(
44179
44924
  store.get(signal.atom),
44180
44925
  subscriber.getSnapshot()
44181
44926
  ) || !equal(subscriber.getSnapshot(), instance.getSnapshot()) || subscriber.createRender?.() != null)
@@ -44236,11 +44981,20 @@ ${usage_default}`;
44236
44981
  },
44237
44982
  current() {
44238
44983
  const current = [...currentFibers()].flatMap(hooks);
44239
- return bindings.every(
44240
- ({ subscriber, signal, instance }) => current.some(
44241
- (hook) => Array.isArray(hook.memoizedState) && hook.memoizedState[0] === subscriber && hook.memoizedState[1]?.[0] === signal && hook.next?.queue === instance && (!realtimeOnly || capable(hook.next?.memoizedState) && hook.next.memoizedState.isCapable)
44242
- )
44243
- );
44984
+ return bindings.every(({ subscriber, signal, instance }) => {
44985
+ try {
44986
+ const snapshot = subscriber.getSnapshot();
44987
+ const instanceSnapshot = instance.getSnapshot();
44988
+ if (!capable(snapshot) || !capable(instanceSnapshot) || !equal(snapshot, instanceSnapshot))
44989
+ return false;
44990
+ return current.some((hook) => {
44991
+ const committed = hook.next?.memoizedState;
44992
+ return Array.isArray(hook.memoizedState) && hook.memoizedState[0] === subscriber && hook.memoizedState[1]?.[0] === signal && hook.next?.queue === instance && capable(committed) && equal(committed, snapshot) && (!realtimeOnly || snapshot.isCapable);
44993
+ });
44994
+ } catch {
44995
+ return false;
44996
+ }
44997
+ });
44244
44998
  }
44245
44999
  };
44246
45000
  }
@@ -44269,7 +45023,7 @@ ${usage_default}`;
44269
45023
  target[GLOBAL] = handle;
44270
45024
  const hookActive = (key) => {
44271
45025
  const hook = target[key];
44272
- return record6(hook) && hook.status === "active";
45026
+ return record7(hook) && hook.status === "active";
44273
45027
  };
44274
45028
  const currentRoute = () => {
44275
45029
  try {
@@ -44302,8 +45056,6 @@ ${usage_default}`;
44302
45056
  `app://-/assets/${assets.initial}`
44303
45057
  );
44304
45058
  if (disposed) return;
44305
- if (typeof module.njr !== "function")
44306
- throw new Error("Voice capability exports unavailable");
44307
45059
  const composers = [
44308
45060
  ...target.document?.querySelectorAll(
44309
45061
  chatGateway() ? "[data-chatgpt-composer]" : "[data-codex-composer-root]"
@@ -44313,14 +45065,14 @@ ${usage_default}`;
44313
45065
  );
44314
45066
  if (composers.length !== 1) throw new Error("Voice composer unavailable");
44315
45067
  if (composers[0] !== composer || !binding?.current()) {
44316
- module.njr();
44317
45068
  binding?.dispose();
44318
45069
  binding = void 0;
44319
45070
  composer = composers[0];
45071
+ const { family, gates } = initializeVoiceCapabilityFamilies(module, assets);
44320
45072
  binding = bindComposerVoiceCapability(
44321
45073
  composer,
44322
- module.tjr,
44323
- module.uBr,
45074
+ family,
45075
+ gates,
44324
45076
  allowed,
44325
45077
  chatGateway()
44326
45078
  );
@@ -44341,12 +45093,515 @@ ${usage_default}`;
44341
45093
  return handle;
44342
45094
  }
44343
45095
 
45096
+ // src/renderer-voice-settings-availability.ts
45097
+ var record8 = (value) => value !== null && typeof value === "object";
45098
+ function voiceSettingsSurface(doc, page, appScope) {
45099
+ const pages = /* @__PURE__ */ new Set();
45100
+ const fibers = /* @__PURE__ */ new Set();
45101
+ const elements = /* @__PURE__ */ new Set();
45102
+ for (const section of doc.querySelectorAll("section")) {
45103
+ elements.add(section);
45104
+ for (const control of section.querySelectorAll?.("button,input") ?? []) elements.add(control);
45105
+ }
45106
+ for (const element of [...elements].slice(0, 512)) {
45107
+ const key = Object.getOwnPropertyNames(element).find((key2) => key2.startsWith("__reactFiber$"));
45108
+ const ancestors = committedReactAncestors(
45109
+ key && Object.getOwnPropertyDescriptor(element, key)?.value
45110
+ );
45111
+ const boundary = ancestors.findIndex((fiber) => fiber.type === page);
45112
+ if (boundary < 0) continue;
45113
+ pages.add(ancestors[boundary]);
45114
+ for (const fiber of ancestors.slice(0, boundary + 1)) fibers.add(fiber);
45115
+ }
45116
+ if (pages.size !== 1) return;
45117
+ const scopes = /* @__PURE__ */ new Map();
45118
+ for (const fiber of fibers)
45119
+ for (const hook of hooks(fiber)) {
45120
+ const scope2 = record8(hook.memoizedState) ? hook.memoizedState.current : void 0;
45121
+ if (record8(scope2) && scope2.scope === appScope && record8(scope2.node) && scope2.chain instanceof Map && scope2.chain.get(appScope.id) === scope2.node && typeof scope2.get === "function")
45122
+ scopes.set(scope2.node, scope2);
45123
+ }
45124
+ const scope = [...scopes.values()][0];
45125
+ return scopes.size === 1 && scope ? { scope, fibers } : void 0;
45126
+ }
45127
+ function availability(store, atom, voice, gate) {
45128
+ const native = store.get(atom);
45129
+ const projected = replayVoiceCapability(store, voice, gate);
45130
+ if (typeof native !== "boolean" || atom.write || projected?.isCapable !== true) return;
45131
+ const evaluate = (override) => {
45132
+ let remaining = 512;
45133
+ let hits = 0;
45134
+ const visiting = /* @__PURE__ */ new Set();
45135
+ const read = (dependency) => {
45136
+ if (--remaining < 0) throw new Error("Settings availability dependency limit");
45137
+ const value = store.get(dependency);
45138
+ if (dependency === voice) {
45139
+ hits += 1;
45140
+ return override ? projected : value;
45141
+ }
45142
+ if (dependency.write || visiting.has(dependency)) return value;
45143
+ visiting.add(dependency);
45144
+ try {
45145
+ return dependency.read(read);
45146
+ } finally {
45147
+ visiting.delete(dependency);
45148
+ }
45149
+ };
45150
+ return { value: read(atom), hits };
45151
+ };
45152
+ try {
45153
+ const before = evaluate(false);
45154
+ const after = evaluate(true);
45155
+ return before.hits > 0 && before.value === native && after.hits > 0 && typeof after.value === "boolean" ? after.value : void 0;
45156
+ } catch {
45157
+ return;
45158
+ }
45159
+ }
45160
+ function bindVoiceSettingsAvailability(currentFibers, store, voice, gate, allowed) {
45161
+ const candidates = [];
45162
+ for (const fiber of currentFibers())
45163
+ for (const hook2 of hooks(fiber)) {
45164
+ const [subscriber2, deps] = Array.isArray(hook2.memoizedState) ? hook2.memoizedState : [];
45165
+ if (!record8(subscriber2) || typeof subscriber2.getSnapshot !== "function" || !Array.isArray(deps) || deps.length !== 2 || deps[0] !== store || !record8(deps[1]) || typeof deps[1].read !== "function")
45166
+ continue;
45167
+ const atom2 = deps[1];
45168
+ if (availability(store, atom2, voice, gate) === true)
45169
+ candidates.push({ hook: hook2, subscriber: subscriber2, atom: atom2 });
45170
+ }
45171
+ const candidate = candidates[0];
45172
+ if (candidates.length !== 1 || !candidate)
45173
+ throw new Error("Unavailable or ambiguous Settings availability reader");
45174
+ const { hook, subscriber, atom } = candidate;
45175
+ const instance = hook.next?.queue;
45176
+ const effect = hook.next?.next?.memoizedState;
45177
+ const native = store.get(atom);
45178
+ if (!instance || typeof instance.getSnapshot !== "function" || !record8(effect) || !Array.isArray(effect.deps) || effect.deps.length !== 1 || effect.deps[0] !== subscriber.subscribe || typeof effect.create !== "function" || subscriber.getSnapshot() !== native || instance.getSnapshot() !== native || subscriber.createRender?.() != null)
45179
+ throw new Error("Unsupported Settings availability subscription");
45180
+ for (const [object3, key] of [
45181
+ [store, "sub"],
45182
+ [subscriber, "getSnapshot"],
45183
+ [instance, "getSnapshot"]
45184
+ ])
45185
+ if (Object.getOwnPropertyDescriptor(object3, key)?.writable !== true)
45186
+ throw new Error("Settings availability reader is not writable");
45187
+ let notify;
45188
+ const sub = store.sub;
45189
+ try {
45190
+ store.sub = (selected, listener) => {
45191
+ if (selected !== atom || notify) throw new Error("Unexpected Settings subscription");
45192
+ notify = listener;
45193
+ return () => {
45194
+ };
45195
+ };
45196
+ effect.create();
45197
+ } finally {
45198
+ store.sub = sub;
45199
+ }
45200
+ if (!notify) throw new Error("Settings availability listener unavailable");
45201
+ const original = subscriber.getSnapshot;
45202
+ const originalInstance = instance.getSnapshot;
45203
+ const snapshot = () => allowed() && availability(store, atom, voice, gate) === true ? true : original.call(subscriber);
45204
+ subscriber.getSnapshot = snapshot;
45205
+ instance.getSnapshot = snapshot;
45206
+ const onChange = notify;
45207
+ let disposed = false;
45208
+ const binding = {
45209
+ current() {
45210
+ try {
45211
+ const expected = subscriber.getSnapshot();
45212
+ return !disposed && expected === true && instance.getSnapshot() === expected && [...currentFibers()].flatMap(hooks).some(
45213
+ (current) => current.memoizedState && Array.isArray(current.memoizedState) && current.memoizedState[0] === subscriber && current.memoizedState[1]?.[0] === store && current.memoizedState[1]?.[1] === atom && current.next?.queue === instance && current.next.memoizedState === expected
45214
+ );
45215
+ } catch {
45216
+ return false;
45217
+ }
45218
+ },
45219
+ dispose() {
45220
+ if (disposed) return;
45221
+ disposed = true;
45222
+ if (subscriber.getSnapshot === snapshot) subscriber.getSnapshot = original;
45223
+ if (instance.getSnapshot === snapshot) instance.getSnapshot = originalInstance;
45224
+ onChange();
45225
+ }
45226
+ };
45227
+ try {
45228
+ onChange();
45229
+ } catch (error51) {
45230
+ binding.dispose();
45231
+ throw error51;
45232
+ }
45233
+ return binding;
45234
+ }
45235
+
45236
+ // src/renderer-dictation-settings.ts
45237
+ var record9 = (value) => value !== null && typeof value === "object";
45238
+ var mode = (value) => value === null || value === "os-global" || value === "app";
45239
+ function replayDictationSettingsMode(store, atom, capabilities, gate) {
45240
+ try {
45241
+ const native = store.get(atom);
45242
+ if (atom.write || !mode(native)) return;
45243
+ const replacements = new Map(
45244
+ capabilities.map((capability) => [
45245
+ capability,
45246
+ replayVoiceCapability(store, capability, gate)
45247
+ ])
45248
+ );
45249
+ const evaluate = (override) => {
45250
+ let remaining = 512;
45251
+ let hits = 0;
45252
+ const visiting = /* @__PURE__ */ new Set();
45253
+ const read = (dependency) => {
45254
+ if (--remaining < 0) throw new Error("Dictation Settings dependency limit");
45255
+ const value = store.get(dependency);
45256
+ if (replacements.has(dependency)) {
45257
+ hits += 1;
45258
+ const projected = replacements.get(dependency);
45259
+ return override && projected?.isCapable ? projected : value;
45260
+ }
45261
+ if (dependency.write || visiting.has(dependency)) return value;
45262
+ visiting.add(dependency);
45263
+ try {
45264
+ return dependency.read(read);
45265
+ } finally {
45266
+ visiting.delete(dependency);
45267
+ }
45268
+ };
45269
+ return { value: read(atom), hits };
45270
+ };
45271
+ const before = evaluate(false), after = evaluate(true);
45272
+ return before.hits > 0 && before.value === native && after.hits > 0 && mode(after.value) ? after.value : void 0;
45273
+ } catch {
45274
+ return;
45275
+ }
45276
+ }
45277
+ function bindDictationSettingsMode(currentFibers, store, atom, capabilities, gate, allowed) {
45278
+ const readers = () => [...currentFibers()].flatMap(hooks).filter((hook) => {
45279
+ const [subscriber, deps] = Array.isArray(hook.memoizedState) ? hook.memoizedState : [];
45280
+ return record9(subscriber) && typeof subscriber.getSnapshot === "function" && Array.isArray(deps) && deps.length === 2 && deps[0] === store && deps[1] === atom;
45281
+ });
45282
+ const subscriptions = readers();
45283
+ if (!subscriptions.length || replayDictationSettingsMode(store, atom, capabilities, gate) === void 0)
45284
+ throw new Error("Native Settings dictation mode unavailable");
45285
+ const restores = [];
45286
+ const bindings = [];
45287
+ try {
45288
+ for (const hook of subscriptions) {
45289
+ const subscriber = hook.memoizedState[0];
45290
+ const instance = hook.next?.queue;
45291
+ const effect = hook.next?.next?.memoizedState;
45292
+ const native = store.get(atom);
45293
+ if (!instance || typeof instance.getSnapshot !== "function" || !record9(effect) || !Array.isArray(effect.deps) || effect.deps.length !== 1 || effect.deps[0] !== subscriber.subscribe || typeof effect.create !== "function" || subscriber.getSnapshot() !== native || instance.getSnapshot() !== native || subscriber.createRender?.() != null)
45294
+ throw new Error("Unsupported Settings dictation mode subscription");
45295
+ for (const [object3, key] of [
45296
+ [store, "sub"],
45297
+ [subscriber, "getSnapshot"],
45298
+ [instance, "getSnapshot"]
45299
+ ])
45300
+ if (Object.getOwnPropertyDescriptor(object3, key)?.writable !== true)
45301
+ throw new Error("Dictation Settings reader is not writable");
45302
+ const sub = store.sub;
45303
+ let notify;
45304
+ try {
45305
+ store.sub = (selected, listener) => {
45306
+ if (selected !== atom || notify)
45307
+ throw new Error("Unexpected dictation Settings subscription");
45308
+ notify = listener;
45309
+ return () => {
45310
+ };
45311
+ };
45312
+ effect.create();
45313
+ } finally {
45314
+ store.sub = sub;
45315
+ }
45316
+ if (!notify) throw new Error("Dictation Settings listener unavailable");
45317
+ const original = subscriber.getSnapshot, originalInstance = instance.getSnapshot;
45318
+ const snapshot = () => {
45319
+ if (allowed()) {
45320
+ const projected = replayDictationSettingsMode(store, atom, capabilities, gate);
45321
+ if (projected !== void 0) return projected;
45322
+ }
45323
+ return original.call(subscriber);
45324
+ };
45325
+ subscriber.getSnapshot = snapshot;
45326
+ instance.getSnapshot = snapshot;
45327
+ const onChange = notify;
45328
+ restores.push(() => {
45329
+ if (subscriber.getSnapshot === snapshot) subscriber.getSnapshot = original;
45330
+ if (instance.getSnapshot === snapshot) instance.getSnapshot = originalInstance;
45331
+ onChange();
45332
+ });
45333
+ bindings.push({ subscriber, instance });
45334
+ onChange();
45335
+ }
45336
+ } catch (error51) {
45337
+ for (const restore of restores.reverse()) restore();
45338
+ throw error51;
45339
+ }
45340
+ return {
45341
+ current() {
45342
+ try {
45343
+ const current = readers();
45344
+ return restores.length > 0 && current.length === bindings.length && bindings.every(({ subscriber, instance }) => {
45345
+ const expected = subscriber.getSnapshot();
45346
+ return mode(expected) && instance.getSnapshot() === expected && current.some(
45347
+ (hook) => hook.memoizedState[0] === subscriber && hook.next?.queue === instance && hook.next.memoizedState === expected
45348
+ );
45349
+ });
45350
+ } catch {
45351
+ return false;
45352
+ }
45353
+ },
45354
+ dispose() {
45355
+ for (const restore of restores.splice(0).reverse()) restore();
45356
+ }
45357
+ };
45358
+ }
45359
+
45360
+ // src/renderer-voice-settings.ts
45361
+ var GLOBAL2 = "__codexhostVoiceSettingsV1";
45362
+ var MESSAGE_ID = "settings.general.realtimeVoice.unavailable.description";
45363
+ var LABEL = "Voice settings unavailable with this provider";
45364
+ var DESCRIPTION = "Your account allows voice chat. These Desktop settings require the default inference provider. Start ChatGPT Chat voice from the Chat composer.";
45365
+ var record10 = (value) => value !== null && typeof value === "object";
45366
+ var settled = (value, isCapable) => record10(value) && value.isLoading === false && value.isError === false && value.isCapable === isCapable;
45367
+ function realtimeAtoms(scope, modules) {
45368
+ const atom = modules.capability.resolve(scope.node, scope.chain, { name: "voice.realtime" }).resolve(scope.node, scope.chain);
45369
+ return {
45370
+ atom,
45371
+ gate: modules.gates.resolve(scope.node, scope.chain, INFERENCE_GATE).atom
45372
+ };
45373
+ }
45374
+ function providerBlocksVoiceSettings(scope, modules) {
45375
+ try {
45376
+ const access = scope.get(modules.access);
45377
+ if (!record10(access) || access.status !== "allowed" || !settled(scope.get(modules.capability, { name: "voice" }), true) || !settled(scope.get(modules.capability, { name: "voice.realtime" }), false))
45378
+ return false;
45379
+ const { atom, gate } = realtimeAtoms(scope, modules);
45380
+ return replayVoiceCapability(scope.node.store, atom, gate)?.isCapable === true;
45381
+ } catch {
45382
+ return false;
45383
+ }
45384
+ }
45385
+ function explainVoiceSettingsRestriction(doc, modules) {
45386
+ const descriptions = [];
45387
+ for (const element of doc.querySelectorAll("section div")) {
45388
+ if (element.childNodes.length !== 1 || element.firstChild?.nodeType !== 3) continue;
45389
+ const key = Object.getOwnPropertyNames(element).find((key2) => key2.startsWith("__reactFiber$"));
45390
+ const ancestors = committedReactAncestors(
45391
+ key && Object.getOwnPropertyDescriptor(element, key)?.value
45392
+ );
45393
+ if (!ancestors.some((fiber) => fiber.type === modules.page)) continue;
45394
+ const owner = ancestors.find(
45395
+ ({ memoizedProps: props2 }) => record10(props2) && record10(props2.description) && record10(props2.description.props) && props2.description.props.id === MESSAGE_ID && props2.control === null
45396
+ );
45397
+ const props = owner?.memoizedProps;
45398
+ if (!record10(props) || !record10(props.description) || !record10(props.description.props) || !record10(props.label) || !record10(props.label.props) || element.textContent !== props.description.props.defaultMessage)
45399
+ continue;
45400
+ const labelText = props.label.props.defaultMessage;
45401
+ if (typeof labelText !== "string") continue;
45402
+ const row = ancestors.find((fiber) => {
45403
+ const host2 = fiber.stateNode;
45404
+ return fiber.tag === 5 && host2 !== element && typeof host2?.contains === "function" && host2.contains(element) && host2.textContent?.includes(labelText);
45405
+ });
45406
+ const host = row?.stateNode;
45407
+ const labels = host ? [...host.querySelectorAll("div")].filter(
45408
+ (node) => node.childNodes.length === 1 && node.firstChild?.nodeType === 3 && node.textContent === labelText
45409
+ ) : [];
45410
+ if (labels.length !== 1) continue;
45411
+ const scopes = /* @__PURE__ */ new Map();
45412
+ for (const fiber of ancestors) {
45413
+ let hook = fiber.memoizedState;
45414
+ const seen = /* @__PURE__ */ new Set();
45415
+ while (record10(hook) && seen.size < 4096 && !seen.has(hook)) {
45416
+ seen.add(hook);
45417
+ const scope2 = record10(hook.memoizedState) ? hook.memoizedState.current : void 0;
45418
+ if (record10(scope2) && scope2.scope === modules.appScope && record10(scope2.node) && scope2.chain instanceof Map && scope2.chain.get(modules.appScope.id) === scope2.node && typeof scope2.get === "function")
45419
+ scopes.set(scope2.node, scope2);
45420
+ hook = hook.next;
45421
+ }
45422
+ }
45423
+ const label = labels[0];
45424
+ const scope = [...scopes.values()][0];
45425
+ if (scopes.size === 1 && label && scope) descriptions.push({ element, label, scope });
45426
+ }
45427
+ const current = descriptions.length === 1 ? descriptions[0] : void 0;
45428
+ if (!current) return;
45429
+ if (!providerBlocksVoiceSettings(current.scope, modules)) return;
45430
+ const changes = [
45431
+ [current.element, DESCRIPTION],
45432
+ [current.label, LABEL]
45433
+ ];
45434
+ const restores = changes.map(([element, replacement]) => {
45435
+ const text = element.firstChild;
45436
+ const previous = text.data;
45437
+ text.data = replacement;
45438
+ return () => {
45439
+ if (text.data === replacement) text.data = previous;
45440
+ };
45441
+ });
45442
+ return {
45443
+ current() {
45444
+ return changes.every(
45445
+ ([element, replacement]) => element.isConnected && element.textContent === replacement
45446
+ ) && providerBlocksVoiceSettings(current.scope, modules);
45447
+ },
45448
+ dispose() {
45449
+ for (const restore of restores) restore();
45450
+ }
45451
+ };
45452
+ }
45453
+ function restoreNativeVoiceSettings(doc, modules, enabled = () => true) {
45454
+ const surface = voiceSettingsSurface(doc, modules.page, modules.appScope);
45455
+ if (!surface || !providerBlocksVoiceSettings(surface.scope, modules)) return;
45456
+ const scope = surface.scope;
45457
+ const currentFibers = () => {
45458
+ const current = voiceSettingsSurface(doc, modules.page, modules.appScope);
45459
+ return current?.scope.node === scope.node ? current.fibers : /* @__PURE__ */ new Set();
45460
+ };
45461
+ const allowed = () => enabled() && providerBlocksVoiceSettings(scope, modules);
45462
+ const { atom, gate } = realtimeAtoms(scope, modules);
45463
+ const capability = bindVoiceCapabilitySubscriptions(
45464
+ () => new Set([...currentFibers()].filter((fiber) => fiber.type === modules.page)),
45465
+ modules.capability,
45466
+ modules.gates,
45467
+ allowed,
45468
+ false,
45469
+ ["voice.realtime", "dictation.composer", "dictation.global"]
45470
+ );
45471
+ let availability2;
45472
+ try {
45473
+ availability2 = bindVoiceSettingsAvailability(
45474
+ currentFibers,
45475
+ scope.node.store,
45476
+ atom,
45477
+ gate,
45478
+ allowed
45479
+ );
45480
+ const dictationMode = modules.dictationMode && bindDictationSettingsMode(
45481
+ currentFibers,
45482
+ scope.node.store,
45483
+ modules.dictationMode.resolve(scope.node, scope.chain),
45484
+ ["dictation.composer", "dictation.global", "dictation.chatgpt"].map(
45485
+ (name) => modules.capability.resolve(scope.node, scope.chain, { name }).resolve(scope.node, scope.chain)
45486
+ ),
45487
+ gate,
45488
+ enabled
45489
+ );
45490
+ const voiceAvailability = availability2;
45491
+ return {
45492
+ current: () => allowed() && capability.current() && voiceAvailability.current() && (dictationMode?.current() ?? true),
45493
+ dispose() {
45494
+ dictationMode?.dispose();
45495
+ voiceAvailability.dispose();
45496
+ capability.dispose();
45497
+ }
45498
+ };
45499
+ } catch (error51) {
45500
+ availability2?.dispose();
45501
+ capability.dispose();
45502
+ throw error51;
45503
+ }
45504
+ }
45505
+ function installVoiceSettingsExplanation(options = {}) {
45506
+ const target = options.target ?? globalThis;
45507
+ const globals = target;
45508
+ if (globals[GLOBAL2]) return globals[GLOBAL2];
45509
+ const config2 = readCpaLiveVoiceHookConfig(target);
45510
+ if (!config2) return { dispose() {
45511
+ } };
45512
+ if (config2.desktopVersion && config2.desktopVersion !== NATIVE_CHAT_VOICE_VERSION)
45513
+ return { dispose() {
45514
+ } };
45515
+ let disposed = false;
45516
+ let timer;
45517
+ let binding;
45518
+ let modules;
45519
+ let restored = false;
45520
+ const handle = {
45521
+ dispose() {
45522
+ disposed = true;
45523
+ if (timer !== void 0) target.clearTimeout(timer);
45524
+ binding?.dispose();
45525
+ if (globals[GLOBAL2] === handle) Reflect.deleteProperty(globals, GLOBAL2);
45526
+ }
45527
+ };
45528
+ globals[GLOBAL2] = handle;
45529
+ const tryControls = () => {
45530
+ if (!modules || !target.document) return;
45531
+ try {
45532
+ return restoreNativeVoiceSettings(
45533
+ target.document,
45534
+ modules,
45535
+ () => !!readCpaLiveVoiceHookConfig(target)
45536
+ );
45537
+ } catch {
45538
+ return void 0;
45539
+ }
45540
+ };
45541
+ const refresh = async () => {
45542
+ if (disposed) return;
45543
+ try {
45544
+ if (binding?.current()) {
45545
+ if (restored) return;
45546
+ const controls = tryControls();
45547
+ if (controls) {
45548
+ binding.dispose();
45549
+ binding = controls;
45550
+ restored = true;
45551
+ }
45552
+ return;
45553
+ }
45554
+ binding?.dispose();
45555
+ binding = void 0;
45556
+ restored = false;
45557
+ if (!modules) {
45558
+ const assets = selectVoiceAssets(
45559
+ NATIVE_CHAT_VOICE_ASSETS,
45560
+ loadedAssetNames(target.document, target.performance),
45561
+ config2.desktopVersion
45562
+ );
45563
+ if (!assets?.settings) return;
45564
+ const load = options.importModule ?? ((url2) => import(url2));
45565
+ const [initial, shared, settings] = await Promise.all(
45566
+ [assets.initial, assets.shared, assets.settings].map(
45567
+ (asset) => load(`app://-/assets/${asset}`)
45568
+ )
45569
+ );
45570
+ if (disposed) return;
45571
+ if (typeof initial.l0n !== "function" || typeof settings.VoiceSettings !== "function")
45572
+ return;
45573
+ initial.l0n();
45574
+ const dictationMode = initial.mW;
45575
+ modules = {
45576
+ appScope: shared.Bst,
45577
+ page: settings.VoiceSettings,
45578
+ access: initial.k5n,
45579
+ capability: initial.c0n,
45580
+ gates: initial.Cnr,
45581
+ ...dictationMode ? { dictationMode } : {}
45582
+ };
45583
+ }
45584
+ if (target.document) {
45585
+ binding = tryControls();
45586
+ restored = !!binding;
45587
+ if (!binding) binding = explainVoiceSettingsRestriction(target.document, modules);
45588
+ }
45589
+ } catch {
45590
+ } finally {
45591
+ if (!disposed) timer = target.setTimeout(() => void refresh(), 1e3);
45592
+ }
45593
+ };
45594
+ void refresh();
45595
+ return handle;
45596
+ }
45597
+
44344
45598
  // src/production-entry.ts
44345
45599
  installCpaLiveVoiceHook();
44346
45600
  installClientOwnedVoiceHook();
44347
45601
  installExternalVoiceLaunchHook();
44348
45602
  installNativeChatVoiceHook();
44349
45603
  installVoiceCapabilityProjection();
45604
+ installVoiceSettingsExplanation();
44350
45605
  var installBinding = () => {
44351
45606
  installRendererBinding();
44352
45607
  };