@karlorz/codexhost-cli-win32-arm64 0.13.3-6 → 0.14.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/app/codexhost-distribution.json +1 -1
  3. package/app/console-server.mjs +539 -95
  4. package/app/console-web.js +879 -73
  5. package/app/cpa-live-voice-hook.js +605 -37
  6. package/app/desktop-controller.mjs +94 -9
  7. package/app/host-runtime.mjs +1662 -642
  8. package/app/plugins/antigravity/plugin.mjs +113 -13
  9. package/app/plugins/claude-code/plugin.mjs +429 -26
  10. package/app/plugins/codebuddy/plugin.mjs +139 -22
  11. package/app/plugins/codex-usage/plugin.mjs +198 -74
  12. package/app/plugins/copilot/assets/icon.png +0 -0
  13. package/app/plugins/copilot/manifest.json +26 -0
  14. package/app/plugins/copilot/plugin.mjs +34645 -0
  15. package/app/plugins/cursor-cli/plugin.mjs +20877 -44973
  16. package/app/plugins/deepseek-harness/plugin.mjs +105 -11
  17. package/app/plugins/enabled.json +1 -0
  18. package/app/plugins/grok/plugin.mjs +1073 -214
  19. package/app/plugins/hermes/plugin.mjs +102 -9
  20. package/app/plugins/kimi-code/plugin.mjs +98 -7
  21. package/app/plugins/kiro-cli/plugin.mjs +98 -7
  22. package/app/plugins/omp/plugin.mjs +2177 -2000
  23. package/app/plugins/opencode/plugin.mjs +107 -11
  24. package/app/plugins/pi/plugin.mjs +2554 -2285
  25. package/app/plugins/qoder/plugin.mjs +105 -11
  26. package/app/plugins/qoder-cn/plugin.mjs +105 -11
  27. package/app/plugins/workbuddy/plugin.mjs +400 -46
  28. package/app/plugins/zcode/plugin.mjs +106 -11
  29. package/app/renderer-extension.js +2717 -1237
  30. package/bin/codexhost.exe +0 -0
  31. package/libexec/codexhost-node-repl.exe +0 -0
  32. package/libexec/codexhost-shim.exe +0 -0
  33. package/libexec/codexhost-updater.exe +0 -0
  34. package/package.json +1 -1
@@ -14768,10 +14768,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14768
14768
  var project = external_exports.string().min(1).max(4096);
14769
14769
  var usageStatisticsParamsSchema = external_exports.strictObject({
14770
14770
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14771
+ /** Display timezone for ranges, dates and hourly buckets; omitted means the Host's local zone. */
14772
+ timeZone: external_exports.string().min(1).max(128).refine((value) => {
14773
+ try {
14774
+ new Intl.DateTimeFormat("en", { timeZone: value });
14775
+ return true;
14776
+ } catch {
14777
+ return false;
14778
+ }
14779
+ }, "Unsupported usage statistics timezone").optional(),
14771
14780
  harness: harness.optional(),
14772
14781
  model: model.nullable().optional(),
14773
14782
  project: project.nullable().optional(),
14774
- /** One local date inside the range. */
14783
+ /** One date in the query timezone inside the range. */
14775
14784
  date: localDate.optional()
14776
14785
  });
14777
14786
  var usageStatisticsTotalsSchema = external_exports.strictObject({
@@ -14807,7 +14816,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14807
14816
  });
14808
14817
  var usageStatisticsResultSchema = external_exports.strictObject({
14809
14818
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14810
- /** First local date of the range; null for all time. */
14819
+ /** First date in the query timezone (Host local when omitted); null for all time. */
14811
14820
  from: localDate.nullable(),
14812
14821
  to: localDate,
14813
14822
  /** The filters these figures apply, echoed so a late answer to older filters is recognised. */
@@ -14847,7 +14856,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14847
14856
  totals: usageStatisticsTotalsSchema,
14848
14857
  /** Each date and Harness of the range: every filter except the day. */
14849
14858
  daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
14850
- /** Local weekday (0 = Sunday) and hour, all filters applied. */
14859
+ /** Weekday (0 = Sunday) and hour in the query timezone, all filters applied. */
14851
14860
  hourly: external_exports.array(external_exports.strictObject({
14852
14861
  weekday: external_exports.number().int().min(0).max(6),
14853
14862
  hour: external_exports.number().int().min(0).max(23),
@@ -14939,8 +14948,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14939
14948
  "codexhost/harness/display-settings/set",
14940
14949
  "codexhost/harness/inspect",
14941
14950
  "codexhost/harness/installation",
14951
+ "codexhost/harness/installation/start",
14952
+ "codexhost/harness/installation/status",
14942
14953
  "codexhost/harness/launch-settings/get",
14943
14954
  "codexhost/harness/launch-settings/set",
14955
+ "codexhost/harness/grok-computer-use/get",
14956
+ "codexhost/harness/grok-computer-use/set",
14944
14957
  "codexhost/harness/web-ui/open",
14945
14958
  "codexhost/harness/accounts/sources",
14946
14959
  "codexhost/harness/accounts/list",
@@ -15016,7 +15029,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15016
15029
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
15017
15030
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
15018
15031
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
15032
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
15033
+ var composerIndicatorsSchema = external_exports.array(external_exports.object({
15034
+ kind: external_exports.literal("countdown"),
15035
+ id: external_exports.string().min(1).max(64),
15036
+ expiresAtUnix: nonNegativeSafeIntegerSchema,
15037
+ label: indicatorTextSchema(256).optional(),
15038
+ tooltip: indicatorTextSchema(1024).optional()
15039
+ }).strict()).max(2).refine((entries) => new Set(entries.map(({ id }) => id)).size === entries.length, {
15040
+ message: "Composer indicator IDs must be unique"
15041
+ });
15019
15042
  var threadUsageSnapshotSchema = external_exports.object({
15043
+ composerIndicators: composerIndicatorsSchema.optional(),
15020
15044
  inputTokens: nonNegativeSafeIntegerSchema.optional(),
15021
15045
  cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
15022
15046
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -15424,7 +15448,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15424
15448
  }).strict().optional(),
15425
15449
  autonomousTurns: external_exports.object({
15426
15450
  observe: external_exports.boolean()
15427
- }).strict().optional()
15451
+ }).strict().optional(),
15452
+ /** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
15453
+ steer: external_exports.boolean().optional()
15428
15454
  }).strict();
15429
15455
  var harnessConfigurationStateSchema = external_exports.object({
15430
15456
  effectiveModel: harnessModelRefSchema.optional(),
@@ -15472,7 +15498,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15472
15498
  var harnessInspectParamsSchema = external_exports.object({
15473
15499
  harnessId: harnessIdSchema,
15474
15500
  cwd: nonBlankTextSchema2.max(16384).optional(),
15475
- refresh: external_exports.boolean().optional()
15501
+ refresh: external_exports.boolean().optional(),
15502
+ /** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
15503
+ purpose: external_exports.literal("availability").optional()
15476
15504
  }).strict();
15477
15505
  var harnessWebUiOpenParamsSchema = external_exports.object({
15478
15506
  harnessId: harnessIdSchema
@@ -15555,6 +15583,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15555
15583
  seen.add(thread.threadId);
15556
15584
  }
15557
15585
  });
15586
+ var threadSteeringInspectParamsSchema = external_exports.object({
15587
+ threadId: hostThreadIdSchema,
15588
+ /** The text about to be steered; a Harness command always stops and restarts. */
15589
+ text: external_exports.string().optional()
15590
+ }).strict();
15591
+ var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
15592
+ var threadSteeringInspectResultSchema = external_exports.object({
15593
+ delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
15594
+ }).strict();
15558
15595
 
15559
15596
  // ../shared-contracts/dist/harness-plugins.js
15560
15597
  var HARNESS_PLUGIN_MANIFEST_MAX_BYTES = 32 * 1024;
@@ -15648,8 +15685,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15648
15685
  restartRequired: external_exports.boolean()
15649
15686
  }).strict();
15650
15687
 
15688
+ // ../shared-contracts/dist/grok-computer-use.js
15689
+ var GROK_COMPUTER_USE_GET_METHOD = "codexhost/harness/grok-computer-use/get";
15690
+ var GROK_COMPUTER_USE_SET_METHOD = "codexhost/harness/grok-computer-use/set";
15691
+ var grokComputerUseGetSchema = external_exports.object({}).strict();
15692
+ var grokComputerUseSetSchema = external_exports.object({
15693
+ enabled: external_exports.boolean().optional(),
15694
+ browser: external_exports.boolean().optional()
15695
+ }).strict().refine((value) => value.enabled !== void 0 || value.browser !== void 0, {
15696
+ message: "Expected enabled or browser"
15697
+ });
15698
+ var grokComputerUseSettingsSchema = external_exports.object({
15699
+ enabled: external_exports.boolean(),
15700
+ available: external_exports.boolean(),
15701
+ unavailableReason: external_exports.string().min(1).max(500).optional(),
15702
+ browser: external_exports.boolean().optional(),
15703
+ browserFilesPresent: external_exports.boolean().optional(),
15704
+ browserAvailable: external_exports.boolean().optional(),
15705
+ browserUnavailableReason: external_exports.string().min(1).max(500).optional(),
15706
+ applyFailed: external_exports.boolean().optional(),
15707
+ applyError: external_exports.string().min(1).max(500).optional()
15708
+ }).strict();
15709
+
15651
15710
  // ../shared-contracts/dist/harness-installation.js
15652
- var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
15711
+ var HARNESS_INSTALLATION_START_METHOD = "codexhost/harness/installation/start";
15712
+ var HARNESS_INSTALLATION_STATUS_METHOD = "codexhost/harness/installation/status";
15653
15713
  var harnessInstallationParamsSchema = external_exports.object({
15654
15714
  harnessId: harnessIdSchema,
15655
15715
  action: external_exports.enum(["check", "update", "install"])
@@ -15659,6 +15719,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15659
15719
  latestVersion: external_exports.string().min(1).max(128),
15660
15720
  updateAvailable: external_exports.boolean(),
15661
15721
  canUpdate: external_exports.boolean(),
15722
+ /** Defaults to CLI; some Harnesses ship only inside a desktop application. */
15723
+ versionKind: external_exports.enum(["cli", "application"]).optional(),
15724
+ /** Official download opened by the user; does not imply an automatic installation. */
15725
+ manualUpdateUrl: external_exports.url().max(2048).refine((value) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value), "Manual updates require a credential-free HTTPS URL").optional(),
15662
15726
  // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15663
15727
  message: external_exports.string().max(2048).optional(),
15664
15728
  messageCode: external_exports.string().min(1).max(128).optional(),
@@ -15666,6 +15730,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15666
15730
  notice: harnessLocalizedTextSchema.optional(),
15667
15731
  latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15668
15732
  }).strict();
15733
+ var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
15734
+ var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
15735
+ external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
15736
+ external_exports.object({
15737
+ taskId: external_exports.string().uuid(),
15738
+ status: external_exports.literal("succeeded"),
15739
+ result: harnessInstallationStateSchema
15740
+ }).strict(),
15741
+ external_exports.object({
15742
+ taskId: external_exports.string().uuid(),
15743
+ status: external_exports.literal("failed"),
15744
+ error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
15745
+ }).strict()
15746
+ ]);
15669
15747
 
15670
15748
  // ../shared-contracts/dist/codex-accounts.js
15671
15749
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
@@ -17089,6 +17167,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17089
17167
  if (!client.setHarnessLaunchSettings) throw new Error("Launch settings are unavailable");
17090
17168
  return client.setHarnessLaunchSettings({ harnessId: harnessIdSchema.parse(agent), path });
17091
17169
  },
17170
+ async getGrokComputerUse() {
17171
+ if (!client.getGrokComputerUse) throw new Error("Grok Computer Use settings are unavailable");
17172
+ return client.getGrokComputerUse();
17173
+ },
17174
+ async setGrokComputerUse(_hostId, update) {
17175
+ if (!client.setGrokComputerUse) throw new Error("Grok Computer Use settings are unavailable");
17176
+ return client.setGrokComputerUse(update);
17177
+ },
17092
17178
  subscribe(listener) {
17093
17179
  listeners.add(listener);
17094
17180
  return () => listeners.delete(listener);
@@ -18376,6 +18462,13 @@ th[aria-sort] .console-usage-sort__mark {
18376
18462
  save: "Save",
18377
18463
  useAutomatic: "Use automatic",
18378
18464
  saved: "Saved",
18465
+ grokComputerUse: "Grok Computer Use",
18466
+ grokComputerUseHelp: "Lets Grok control Mac apps through ChatGPT\u2019s Computer Use helper. ChatGPT Settings \u2192 Computer use still applies only to official Codex. New Grok threads pick up this switch.",
18467
+ grokComputerUseUnavailable: "ChatGPT Desktop Computer Use files were not found.",
18468
+ grokBrowser: "Grok in-app browser",
18469
+ grokBrowserHelp: "Lets Grok use ChatGPT\u2019s built-in browser (Browser Use) through cua_repl. Independent of Computer Use; official Codex Browser Use is unchanged. Grok fails closed when the in-app tab cannot be bound.",
18470
+ grokBrowserUnavailable: "ChatGPT Desktop in-app browser files were not found.",
18471
+ grokBrowserBlocked: "Saved as intent. ChatGPT Desktop does not authorize Grok to use the in-app browser.",
18379
18472
  installGuide: "Install guide",
18380
18473
  noHarness: "No Harness plugins are installed.",
18381
18474
  consoleOffline: "The console is not running",
@@ -18392,6 +18485,8 @@ th[aria-sort] .console-usage-sort__mark {
18392
18485
  harness: "Harness",
18393
18486
  model: "Model",
18394
18487
  project: "Project",
18488
+ host: "Machine",
18489
+ localHost: "This machine",
18395
18490
  filterModel: "Filter by model",
18396
18491
  filterProject: "Filter by project",
18397
18492
  unknownModel: "Unknown model",
@@ -18565,6 +18660,13 @@ th[aria-sort] .console-usage-sort__mark {
18565
18660
  save: "\u4FDD\u5B58",
18566
18661
  useAutomatic: "\u6062\u590D\u81EA\u52A8\u67E5\u627E",
18567
18662
  saved: "\u5DF2\u4FDD\u5B58",
18663
+ grokComputerUse: "Grok Computer Use",
18664
+ grokComputerUseHelp: "\u8BA9 Grok \u901A\u8FC7 ChatGPT \u7684 Computer Use \u52A9\u624B\u63A7\u5236 Mac \u5E94\u7528\u3002ChatGPT \u8BBE\u7F6E \u2192 Computer use \u4ECD\u53EA\u4F5C\u7528\u4E8E\u5B98\u65B9 Codex\u3002\u65B0\u7684 Grok \u7EBF\u7A0B\u4F1A\u8BFB\u53D6\u6B64\u5F00\u5173\u3002",
18665
+ grokComputerUseUnavailable: "\u672A\u627E\u5230 ChatGPT Desktop \u7684 Computer Use \u6587\u4EF6\u3002",
18666
+ grokBrowser: "Grok \u5185\u7F6E\u6D4F\u89C8\u5668",
18667
+ grokBrowserHelp: "\u8BA9 Grok \u901A\u8FC7 cua_repl \u4F7F\u7528 ChatGPT \u5185\u7F6E\u6D4F\u89C8\u5668\uFF08Browser Use\uFF09\u3002\u4E0E Computer Use \u76F8\u4E92\u72EC\u7ACB\uFF0C\u5B98\u65B9 Codex Browser Use \u4E0D\u53D7\u5F71\u54CD\u3002\u65E0\u6CD5\u7ED1\u5B9A\u5185\u7F6E\u6807\u7B7E\u9875\u65F6 Grok \u4F1A\u76F4\u63A5\u5931\u8D25\u3002",
18668
+ grokBrowserUnavailable: "\u672A\u627E\u5230 ChatGPT Desktop \u7684\u5185\u7F6E\u6D4F\u89C8\u5668\u6587\u4EF6\u3002",
18669
+ grokBrowserBlocked: "\u5DF2\u4FDD\u5B58\u4E3A\u610F\u5411\u3002ChatGPT Desktop \u5C1A\u672A\u6388\u6743 Grok \u4F7F\u7528\u5185\u7F6E\u6D4F\u89C8\u5668\u3002",
18568
18670
  installGuide: "\u5B89\u88C5\u8BF4\u660E",
18569
18671
  noHarness: "\u6CA1\u6709\u5DF2\u5B89\u88C5\u7684 Harness \u63D2\u4EF6\u3002",
18570
18672
  consoleOffline: "\u63A7\u5236\u53F0\u672A\u8FD0\u884C",
@@ -18581,6 +18683,8 @@ th[aria-sort] .console-usage-sort__mark {
18581
18683
  harness: "Harness",
18582
18684
  model: "\u6A21\u578B",
18583
18685
  project: "\u9879\u76EE",
18686
+ host: "\u673A\u5668",
18687
+ localHost: "\u672C\u673A",
18584
18688
  filterModel: "\u6309\u6A21\u578B\u7B5B\u9009",
18585
18689
  filterProject: "\u6309\u9879\u76EE\u7B5B\u9009",
18586
18690
  unknownModel: "\u672A\u77E5\u6A21\u578B",
@@ -18696,6 +18800,7 @@ th[aria-sort] .console-usage-sort__mark {
18696
18800
  const document2 = context.content.ownerDocument;
18697
18801
  const list = h(document2, "div", { className: "console-harness-list" });
18698
18802
  const status = /* @__PURE__ */ new Map();
18803
+ const busy = /* @__PURE__ */ new Set();
18699
18804
  let harnesses = [];
18700
18805
  const render = () => {
18701
18806
  if (harnesses.length === 0) {
@@ -18772,6 +18877,75 @@ th[aria-sort] .console-usage-sort__mark {
18772
18877
  );
18773
18878
  }
18774
18879
  }
18880
+ if (harness2.computerUse) {
18881
+ const computerUse = harness2.computerUse;
18882
+ const pending = busy.has(harness2.id);
18883
+ const post = (update) => {
18884
+ busy.add(harness2.id);
18885
+ toggle.disabled = true;
18886
+ browserToggle.disabled = true;
18887
+ void consolePost(
18888
+ "/api/harnesses/grok-computer-use",
18889
+ update
18890
+ ).then(({ harness: saved }) => {
18891
+ harnesses = harnesses.map((entry) => entry.id === saved.id ? saved : entry);
18892
+ status.set(harness2.id, messages.saved);
18893
+ }).catch(
18894
+ (error51) => status.set(harness2.id, error51 instanceof Error ? error51.message : String(error51))
18895
+ ).finally(() => {
18896
+ busy.delete(harness2.id);
18897
+ render();
18898
+ });
18899
+ };
18900
+ const toggle = h(document2, "input", {
18901
+ type: "checkbox",
18902
+ "aria-label": messages.grokComputerUse
18903
+ });
18904
+ toggle.checked = computerUse.enabled;
18905
+ toggle.disabled = pending || !computerUse.available && !computerUse.enabled;
18906
+ toggle.addEventListener("change", () => post({ enabled: toggle.checked }));
18907
+ const browserToggle = h(document2, "input", {
18908
+ type: "checkbox",
18909
+ "aria-label": messages.grokBrowser
18910
+ });
18911
+ browserToggle.checked = computerUse.browser === true;
18912
+ browserToggle.disabled = pending || computerUse.browserFilesPresent !== true && computerUse.browser !== true;
18913
+ browserToggle.addEventListener(
18914
+ "change",
18915
+ () => post({ browser: browserToggle.checked })
18916
+ );
18917
+ row.append(
18918
+ h(
18919
+ document2,
18920
+ "div",
18921
+ { className: "console-harness__path" },
18922
+ h(document2, "label", {}, toggle, ` ${messages.grokComputerUse}`)
18923
+ ),
18924
+ h(
18925
+ document2,
18926
+ "div",
18927
+ { className: "console-muted" },
18928
+ harness2.computerUse.available ? messages.grokComputerUseHelp : computerUse.unavailableReason ?? messages.grokComputerUseUnavailable
18929
+ ),
18930
+ h(
18931
+ document2,
18932
+ "div",
18933
+ { className: "console-harness__path" },
18934
+ h(document2, "label", {}, browserToggle, ` ${messages.grokBrowser}`)
18935
+ ),
18936
+ h(
18937
+ document2,
18938
+ "div",
18939
+ { className: "console-muted" },
18940
+ computerUse.browserAvailable === true ? messages.grokBrowserHelp : computerUse.browserFilesPresent === true ? computerUse.browserUnavailableReason ?? messages.grokBrowserBlocked : computerUse.browserUnavailableReason ?? messages.grokBrowserUnavailable
18941
+ )
18942
+ );
18943
+ if (status.has(harness2.id)) {
18944
+ row.append(
18945
+ h(document2, "div", { className: "console-muted" }, status.get(harness2.id) ?? "")
18946
+ );
18947
+ }
18948
+ }
18775
18949
  if (guide) {
18776
18950
  identity.append(
18777
18951
  h(
@@ -18916,6 +19090,13 @@ th[aria-sort] .console-usage-sort__mark {
18916
19090
  });
18917
19091
  }
18918
19092
 
19093
+ // src/renderer-cpa-live-voice-preference.ts
19094
+ var voiceStateOwner = globalThis;
19095
+ var { sharedRoutes, gatewayReady } = voiceStateOwner.__codexhostVoicePreferenceStateV1 ??= {
19096
+ sharedRoutes: /* @__PURE__ */ new WeakMap(),
19097
+ gatewayReady: /* @__PURE__ */ new WeakMap()
19098
+ };
19099
+
18919
19100
  // src/voice-settings-sync.ts
18920
19101
  function desktopVoiceCallActive(owner) {
18921
19102
  const hook = Reflect.get(owner, "__codexhostNativeChatVoiceV1");
@@ -19046,6 +19227,15 @@ th[aria-sort] .console-usage-sort__mark {
19046
19227
  configured: "Configured",
19047
19228
  needsSetup: "Needs setup",
19048
19229
  unknown: "Not checked",
19230
+ gatewayStatus: "Gateway configuration",
19231
+ preferencesStatus: "Preferences applied",
19232
+ hookStatus: "Desktop gateway voice integration",
19233
+ preferencesOn: "Applied",
19234
+ preferencesOff: "Not applied yet",
19235
+ hookSupported: "Supported",
19236
+ hookUnsupported: "This Desktop build is not supported for gateway voice",
19237
+ hookPending: "Attaching\u2026",
19238
+ hookDisabled: "Off",
19049
19239
  configure: "Configure",
19050
19240
  setup: "Gateway setup",
19051
19241
  setupHint: "Gateway settings use your local Codex configuration and the selected provider\u2019s credential. End voice before editing configuration. Never paste credentials here.",
@@ -19096,6 +19286,15 @@ th[aria-sort] .console-usage-sort__mark {
19096
19286
  configured: "\u5DF2\u914D\u7F6E",
19097
19287
  needsSetup: "\u9700\u8981\u914D\u7F6E",
19098
19288
  unknown: "\u672A\u68C0\u67E5",
19289
+ gatewayStatus: "\u7F51\u5173\u914D\u7F6E",
19290
+ preferencesStatus: "\u504F\u597D\u662F\u5426\u5DF2\u5E94\u7528",
19291
+ hookStatus: "Desktop \u7F51\u5173\u8BED\u97F3\u96C6\u6210",
19292
+ preferencesOn: "\u5DF2\u5E94\u7528",
19293
+ preferencesOff: "\u5C1A\u672A\u5E94\u7528",
19294
+ hookSupported: "\u652F\u6301",
19295
+ hookUnsupported: "\u5F53\u524D Desktop \u7248\u672C\u4E0D\u652F\u6301\u7F51\u5173\u8BED\u97F3",
19296
+ hookPending: "\u6B63\u5728\u63A5\u5165\u2026",
19297
+ hookDisabled: "\u5DF2\u5173\u95ED",
19099
19298
  configure: "\u914D\u7F6E",
19100
19299
  setup: "\u7F51\u5173\u914D\u7F6E",
19101
19300
  setupHint: "\u7F51\u5173\u4F7F\u7528\u672C\u5730 Codex \u914D\u7F6E\u53CA\u6240\u9009 Provider \u7684\u51ED\u636E\u3002\u7F16\u8F91\u524D\u8BF7\u7ED3\u675F\u8BED\u97F3\u3002\u8BF7\u52FF\u5728\u6B64\u7C98\u8D34\u51ED\u636E\u3002",
@@ -19295,20 +19494,30 @@ th[aria-sort] .console-usage-sort__mark {
19295
19494
  });
19296
19495
  configure.id = gateway.item.querySelector("label")?.htmlFor ?? "";
19297
19496
  configure.setAttribute("aria-expanded", String(setup));
19497
+ const gatewayReadyLabel = state.gatewayReady === null ? m.unknown : state.gatewayReady ? m.configured : m.needsSetup;
19298
19498
  const gatewayActions = h(
19299
19499
  doc,
19300
19500
  "div",
19301
19501
  { className: "settings-voice__gateway-actions" },
19502
+ h(doc, "span", {}, gatewayReadyLabel),
19503
+ configure
19504
+ );
19505
+ gateway.item.append(gatewayActions);
19506
+ config2.card.append(gateway.item);
19507
+ const hook = options.desktop ? desktopVoiceHookStatus(doc.defaultView) : "unknown";
19508
+ const hookLabel = hook === "active" ? m.hookSupported : hook === "pending" ? m.hookPending : hook === "unsupported" ? m.hookUnsupported : hook === "disabled" ? m.hookDisabled : m.unknown;
19509
+ const health = h(doc, "div", { className: "settings-voice__health" });
19510
+ health.append(
19511
+ h(doc, "p", {}, `${m.gatewayStatus}: ${gatewayReadyLabel}`),
19302
19512
  h(
19303
19513
  doc,
19304
- "span",
19514
+ "p",
19305
19515
  {},
19306
- state.gatewayReady === null ? m.unknown : state.gatewayReady ? m.configured : m.needsSetup
19516
+ `${m.preferencesStatus}: ${state.routesActive === true ? m.preferencesOn : state.routesActive === false ? m.preferencesOff : m.unknown}`
19307
19517
  ),
19308
- configure
19518
+ h(doc, "p", {}, `${m.hookStatus}: ${hookLabel}`)
19309
19519
  );
19310
- gateway.item.append(gatewayActions);
19311
- config2.card.append(gateway.item);
19520
+ config2.card.append(health);
19312
19521
  if (setup) {
19313
19522
  const details = h(
19314
19523
  doc,
@@ -19438,6 +19647,15 @@ th[aria-sort] .console-usage-sort__mark {
19438
19647
  }
19439
19648
  });
19440
19649
  }
19650
+ function desktopVoiceHookStatus(win) {
19651
+ if (!win) return "unknown";
19652
+ const value = win.__codexhostClientOwnedVoiceV1;
19653
+ if (!value || typeof value !== "object") return "unknown";
19654
+ const status = value.status;
19655
+ if (status === "active" || status === "pending" || status === "unsupported" || status === "disabled")
19656
+ return status;
19657
+ return "unknown";
19658
+ }
19441
19659
 
19442
19660
  // src/console/pages/restart-control.ts
19443
19661
  function renderRestartControl(document2, messages, state) {
@@ -19920,6 +20138,26 @@ th[aria-sort] .console-usage-sort__mark {
19920
20138
  };
19921
20139
  }
19922
20140
 
20141
+ // src/renderer-installation-client.ts
20142
+ async function runRendererInstallation(send, input) {
20143
+ const params = harnessInstallationParamsSchema.parse(input);
20144
+ const options = { priority: "background", timeoutMs: 15e3 };
20145
+ let task = harnessInstallationTaskSchema.parse(
20146
+ await send(HARNESS_INSTALLATION_START_METHOD, params, options)
20147
+ );
20148
+ const taskId = task.taskId;
20149
+ while (task.status === "running") {
20150
+ await new Promise((resolve) => globalThis.setTimeout(resolve, 500));
20151
+ task = harnessInstallationTaskSchema.parse(
20152
+ await send(HARNESS_INSTALLATION_STATUS_METHOD, { taskId }, options)
20153
+ );
20154
+ if (task.taskId !== taskId) throw new Error("Harness installation task identity changed");
20155
+ }
20156
+ if (task.status === "failed")
20157
+ throw Object.assign(new Error(task.error.message), { code: task.error.code });
20158
+ return task.result;
20159
+ }
20160
+
19923
20161
  // src/renderer-request-sender.ts
19924
20162
  var RendererMethodUnavailableError = class extends Error {
19925
20163
  constructor(method, cause) {
@@ -20068,7 +20306,15 @@ th[aria-sort] .console-usage-sort__mark {
20068
20306
  };
20069
20307
  const inspectHarness = async (input, options) => {
20070
20308
  const params = harnessInspectParamsSchema.parse(input);
20071
- const result = await manager.sendRequest(HARNESS_INSPECT_METHOD, params, options);
20309
+ let result;
20310
+ try {
20311
+ result = await manager.sendRequest(HARNESS_INSPECT_METHOD, params, options);
20312
+ } catch (error51) {
20313
+ if (!params.purpose || !isInvalidParams(error51)) throw error51;
20314
+ const full = { ...params };
20315
+ delete full.purpose;
20316
+ result = await manager.sendRequest(HARNESS_INSPECT_METHOD, full, options);
20317
+ }
20072
20318
  return harnessInspectionSchema.parse(result);
20073
20319
  };
20074
20320
  const inspectHarnessCommands = async (input) => {
@@ -20108,13 +20354,7 @@ th[aria-sort] .console-usage-sort__mark {
20108
20354
  };
20109
20355
  return Object.freeze({
20110
20356
  async installation(input) {
20111
- return harnessInstallationStateSchema.parse(
20112
- await manager.sendRequest(
20113
- HARNESS_INSTALLATION_METHOD,
20114
- harnessInstallationParamsSchema.parse(input),
20115
- { priority: "interactive" }
20116
- )
20117
- );
20357
+ return runRendererInstallation(manager.sendRequest, input);
20118
20358
  },
20119
20359
  async getHarnessDisplaySettings() {
20120
20360
  return harnessDisplaySettingsSchema.parse(
@@ -20142,6 +20382,19 @@ th[aria-sort] .console-usage-sort__mark {
20142
20382
  )
20143
20383
  );
20144
20384
  },
20385
+ async getGrokComputerUse() {
20386
+ return grokComputerUseSettingsSchema.parse(
20387
+ await manager.sendRequest(GROK_COMPUTER_USE_GET_METHOD, {})
20388
+ );
20389
+ },
20390
+ async setGrokComputerUse(update) {
20391
+ return grokComputerUseSettingsSchema.parse(
20392
+ await manager.sendRequest(
20393
+ GROK_COMPUTER_USE_SET_METHOD,
20394
+ grokComputerUseSetSchema.parse(update)
20395
+ )
20396
+ );
20397
+ },
20145
20398
  async listLoadedSessions() {
20146
20399
  return loadedSessionsSchema.parse(await manager.sendRequest(LOADED_SESSIONS_METHOD, {}));
20147
20400
  },
@@ -20330,6 +20583,9 @@ th[aria-sort] .console-usage-sort__mark {
20330
20583
  }
20331
20584
  });
20332
20585
  }
20586
+ function isInvalidParams(error51) {
20587
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === -32602;
20588
+ }
20333
20589
 
20334
20590
  // src/settings/accounts.css
20335
20591
  var accounts_default = `.settings-harness-account__logo {
@@ -21505,6 +21761,26 @@ th[aria-sort] .console-usage-sort__mark {
21505
21761
  launchPathLoading: "Loading launch settings\u2026",
21506
21762
  launchPathLoadError: "Could not load launch settings. Reopen this detail panel to retry.",
21507
21763
  launchPathSaveError: "Could not save. Enter an existing absolute installation folder on this Host and check configuration permissions.",
21764
+ grokComputerUseLabel: "Grok Computer Use",
21765
+ grokComputerUseTitle: "Computer Use",
21766
+ grokComputerUseDescription: "Let Grok control Mac apps via ChatGPT Computer Use (cua_repl).",
21767
+ grokComputerUseHelp: "ChatGPT Settings \u2192 Computer use still applies to official Codex threads. Always-allowed apps stay in that list. New Grok threads pick up this switch.",
21768
+ grokComputerUseOn: "On \xB7 available",
21769
+ grokComputerUseOff: "Off",
21770
+ grokComputerUseSaving: "Saving\u2026",
21771
+ grokComputerUseLoading: "Loading Grok Computer Use\u2026",
21772
+ grokComputerUseLoadError: "Could not load Grok Computer Use. Reopen this panel to retry.",
21773
+ grokComputerUseSaveError: "Could not save. Install ChatGPT.app with Computer Use, then try again.",
21774
+ grokComputerUseUnavailable: "ChatGPT Desktop Computer Use files were not found on this Mac.",
21775
+ grokBrowserLabel: "Grok in-app browser",
21776
+ grokBrowserTitle: "In-app browser",
21777
+ grokBrowserDescription: "Let Grok use ChatGPT's built-in browser (Browser Use) through cua_repl. Independent of Computer Use.",
21778
+ grokBrowserHelp: "Official Codex Browser Use is unchanged. Grok fails closed when ChatGPT does not authorize the connection or no in-app browser tab can be bound. The Chrome extension is a separate path.",
21779
+ grokBrowserOn: "On \xB7 browser surface enabled",
21780
+ grokBrowserOff: "Off",
21781
+ grokBrowserUnavailable: "ChatGPT Desktop in-app browser files were not found on this Mac.",
21782
+ grokBrowserBlocked: "Saved as intent. ChatGPT Desktop does not authorize Grok to use the in-app browser.",
21783
+ grokComputerUseApplyFailed: "Could not apply the saved setting to Grok config.",
21508
21784
  connectionOfficialWebsite: "Visit official website",
21509
21785
  connectionOpenHarnessWeb: "Open DeepSeek Harness Web",
21510
21786
  connectionDeepSeekTestedVersions: "Supported DSH versions: 0.1.7-rc.1, 0.1.7-rc.2, 0.2.0-rc.1, 0.2.0-rc.2, 0.2.1-rc.1 and 0.2.1-rc.2. Versions newer than 0.2.1-rc.2 can be tried, but compatibility may be limited; versions older than 0.1.7-rc.1 must be upgraded first.",
@@ -21513,10 +21789,17 @@ th[aria-sort] .console-usage-sort__mark {
21513
21789
  connectionInstallRunning: "Installing on the selected Host. You can leave this page; login or setup may still be required afterward.",
21514
21790
  harnessVersion: harnessVersionEnglish,
21515
21791
  harnessVersionTitle: "Harness CLI version",
21792
+ harnessVersionApplicationTitle: "Application version",
21516
21793
  harnessVersionCurrent: "Current version",
21517
21794
  harnessVersionLatest: "Latest version",
21518
21795
  harnessVersionChecking: "Checking versions\u2026",
21796
+ harnessVersionAvailable: "Update available",
21519
21797
  harnessVersionUpdate: "Update",
21798
+ harnessVersionDownloadUpdate: "Download update",
21799
+ harnessUpdateAll: "Update all",
21800
+ harnessUpdateAllProgress: "Updating",
21801
+ harnessUpdateAllDescription: "Update all eligible Harnesses on the selected Host.",
21802
+ harnessUpdateAllResult: "Updated {succeeded}; failed {failed}.",
21520
21803
  harnessVersionUpdating: "Updating\u2026",
21521
21804
  harnessVersionUpToDate: "Up to date",
21522
21805
  harnessVersionUpdated: "Update verified. New sessions will use the new version.",
@@ -21787,6 +22070,26 @@ th[aria-sort] .console-usage-sort__mark {
21787
22070
  launchPathLoading: "\u6B63\u5728\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\u2026",
21788
22071
  launchPathLoadError: "\u65E0\u6CD5\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6B64\u8BE6\u60C5\u9762\u677F\u91CD\u8BD5\u3002",
21789
22072
  launchPathSaveError: "\u4FDD\u5B58\u5931\u8D25\u3002\u8BF7\u586B\u5199\u6B64 Host \u4E0A\u5B9E\u9645\u5B58\u5728\u7684\u5B89\u88C5\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u5E76\u786E\u8BA4\u914D\u7F6E\u76EE\u5F55\u53EF\u5199\u3002",
22073
+ grokComputerUseLabel: "Grok Computer Use",
22074
+ grokComputerUseTitle: "Computer Use",
22075
+ grokComputerUseDescription: "\u8BA9 Grok \u901A\u8FC7 ChatGPT Computer Use\uFF08cua_repl\uFF09\u63A7\u5236 Mac \u5E94\u7528\u3002",
22076
+ grokComputerUseHelp: "ChatGPT \u8BBE\u7F6E \u2192 Computer use \u4ECD\u53EA\u4F5C\u7528\u4E8E\u5B98\u65B9 Codex \u7EBF\u7A0B\u3002Always-allowed \u5E94\u7528\u4ECD\u4FDD\u5B58\u5728\u8BE5\u5217\u8868\u3002\u65B0\u7684 Grok \u7EBF\u7A0B\u4F1A\u8BFB\u53D6\u6B64\u5F00\u5173\u3002",
22077
+ grokComputerUseOn: "\u5DF2\u5F00\u542F \xB7 \u53EF\u7528",
22078
+ grokComputerUseOff: "\u5DF2\u5173\u95ED",
22079
+ grokComputerUseSaving: "\u6B63\u5728\u4FDD\u5B58\u2026",
22080
+ grokComputerUseLoading: "\u6B63\u5728\u8BFB\u53D6 Grok Computer Use\u2026",
22081
+ grokComputerUseLoadError: "\u65E0\u6CD5\u8BFB\u53D6 Grok Computer Use\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6B64\u9762\u677F\u91CD\u8BD5\u3002",
22082
+ grokComputerUseSaveError: "\u4FDD\u5B58\u5931\u8D25\u3002\u8BF7\u5148\u5B89\u88C5\u5E26 Computer Use \u7684 ChatGPT.app\u3002",
22083
+ grokComputerUseUnavailable: "\u672C\u673A\u672A\u627E\u5230 ChatGPT Desktop \u7684 Computer Use \u6587\u4EF6\u3002",
22084
+ grokBrowserLabel: "Grok \u5185\u7F6E\u6D4F\u89C8\u5668",
22085
+ grokBrowserTitle: "\u5185\u7F6E\u6D4F\u89C8\u5668",
22086
+ grokBrowserDescription: "\u8BA9 Grok \u901A\u8FC7 cua_repl \u4F7F\u7528 ChatGPT \u5185\u7F6E\u6D4F\u89C8\u5668\uFF08Browser Use\uFF09\u3002\u4E0E Computer Use \u76F8\u4E92\u72EC\u7ACB\u3002",
22087
+ grokBrowserHelp: "\u5B98\u65B9 Codex Browser Use \u4E0D\u53D7\u5F71\u54CD\u3002ChatGPT \u4E0D\u6388\u6743\u8FDE\u63A5\u6216\u65E0\u6CD5\u7ED1\u5B9A\u5185\u7F6E\u6D4F\u89C8\u5668\u6807\u7B7E\u9875\u65F6\uFF0CGrok \u4F1A\u76F4\u63A5\u5931\u8D25\u3002Chrome \u6269\u5C55\u662F\u53E6\u4E00\u6761\u8DEF\u5F84\u3002",
22088
+ grokBrowserOn: "\u5DF2\u5F00\u542F \xB7 \u6D4F\u89C8\u5668\u80FD\u529B\u5DF2\u542F\u7528",
22089
+ grokBrowserOff: "\u5DF2\u5173\u95ED",
22090
+ grokBrowserUnavailable: "\u672C\u673A\u672A\u627E\u5230 ChatGPT Desktop \u7684\u5185\u7F6E\u6D4F\u89C8\u5668\u6587\u4EF6\u3002",
22091
+ grokBrowserBlocked: "\u5DF2\u4FDD\u5B58\u4E3A\u610F\u5411\u3002ChatGPT Desktop \u5C1A\u672A\u6388\u6743 Grok \u4F7F\u7528\u5185\u7F6E\u6D4F\u89C8\u5668\u3002",
22092
+ grokComputerUseApplyFailed: "\u65E0\u6CD5\u5C06\u5DF2\u4FDD\u5B58\u7684\u8BBE\u7F6E\u5199\u5165 Grok \u914D\u7F6E\u3002",
21790
22093
  connectionOfficialWebsite: "\u8BBF\u95EE\u5B98\u7F51",
21791
22094
  connectionOpenHarnessWeb: "\u6253\u5F00 DeepSeek Harness Web",
21792
22095
  connectionDeepSeekTestedVersions: "\u652F\u6301 DSH \u7248\u672C\uFF1A0.1.7-rc.1\u30010.1.7-rc.2\u30010.2.0-rc.1\u30010.2.0-rc.2\u30010.2.1-rc.1 \u548C 0.2.1-rc.2\u3002\u9AD8\u4E8E 0.2.1-rc.2 \u7684\u7248\u672C\u53EF\u4EE5\u5C1D\u8BD5\u8FDE\u63A5\uFF0C\u4F46\u9002\u914D\u5EA6\u53EF\u80FD\u6709\u9650\uFF1B\u4F4E\u4E8E 0.1.7-rc.1 \u7684\u7248\u672C\u9700\u8981\u5148\u5347\u7EA7\u3002",
@@ -21795,10 +22098,17 @@ th[aria-sort] .console-usage-sort__mark {
21795
22098
  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",
21796
22099
  harnessVersion: harnessVersionChinese,
21797
22100
  harnessVersionTitle: "Harness CLI \u7248\u672C",
22101
+ harnessVersionApplicationTitle: "\u5E94\u7528\u7248\u672C",
21798
22102
  harnessVersionCurrent: "\u5F53\u524D\u7248\u672C",
21799
22103
  harnessVersionLatest: "\u6700\u65B0\u7248\u672C",
21800
22104
  harnessVersionChecking: "\u6B63\u5728\u68C0\u67E5\u7248\u672C\u2026",
22105
+ harnessVersionAvailable: "\u6709\u66F4\u65B0",
21801
22106
  harnessVersionUpdate: "\u66F4\u65B0",
22107
+ harnessVersionDownloadUpdate: "\u4E0B\u8F7D\u66F4\u65B0",
22108
+ harnessUpdateAll: "\u5168\u90E8\u66F4\u65B0",
22109
+ harnessUpdateAllProgress: "\u66F4\u65B0\u4E2D",
22110
+ harnessUpdateAllDescription: "\u66F4\u65B0\u5F53\u524D Host \u4E0A\u652F\u6301\u81EA\u52A8\u66F4\u65B0\u4E14\u6709\u65B0\u7248\u672C\u7684 Harness\u3002",
22111
+ harnessUpdateAllResult: "\u5DF2\u66F4\u65B0 {succeeded} \u9879\uFF0C{failed} \u9879\u5931\u8D25\u3002",
21802
22112
  harnessVersionUpdating: "\u6B63\u5728\u66F4\u65B0\u2026",
21803
22113
  harnessVersionUpToDate: "\u5DF2\u662F\u6700\u65B0",
21804
22114
  harnessVersionUpdated: "\u5DF2\u786E\u8BA4\u66F4\u65B0\u6210\u529F\uFF0C\u65B0\u4F1A\u8BDD\u5C06\u4F7F\u7528\u65B0\u7248\u672C\u3002",
@@ -21918,6 +22228,34 @@ th[aria-sort] .console-usage-sort__mark {
21918
22228
  return names.size === 1 ? names.values().next().value ?? model2 : model2;
21919
22229
  }
21920
22230
 
22231
+ // src/console/usage/usage-hosts.ts
22232
+ var LOCAL_USAGE_HOST_ID = "local";
22233
+ function usageHostOptions(hosts, localLabel, selected) {
22234
+ const options = [{ key: LOCAL_USAGE_HOST_ID, label: localLabel }];
22235
+ const seen = /* @__PURE__ */ new Set([LOCAL_USAGE_HOST_ID]);
22236
+ const add = (hostId2, label) => {
22237
+ if (hostId2.length === 0 || seen.has(hostId2)) return;
22238
+ seen.add(hostId2);
22239
+ options.push({ key: hostId2, label: label !== void 0 && label.length > 0 ? label : hostId2 });
22240
+ };
22241
+ for (const host of hosts ?? []) add(host.hostId, host.label);
22242
+ if (!seen.has(selected)) add(selected, void 0);
22243
+ return options;
22244
+ }
22245
+ function createLatestKeyGuard() {
22246
+ let generation = 0;
22247
+ let key;
22248
+ return {
22249
+ begin(next) {
22250
+ generation += 1;
22251
+ key = next;
22252
+ const mine = generation;
22253
+ const selected = next;
22254
+ return () => generation === mine && Object.is(key, selected);
22255
+ }
22256
+ };
22257
+ }
22258
+
21921
22259
  // src/renderer-usage-control.ts
21922
22260
  var ENGLISH_USAGE_MESSAGES = Object.freeze({
21923
22261
  usage: "Usage",
@@ -23276,6 +23614,7 @@ th[aria-sort] .console-usage-sort__mark {
23276
23614
  const range = text("range");
23277
23615
  const measure = text("measure");
23278
23616
  const granularity = text("granularity");
23617
+ const hostId2 = text("hostId");
23279
23618
  const harness2 = text("harness");
23280
23619
  const model2 = text("model");
23281
23620
  const project2 = text("project");
@@ -23284,6 +23623,7 @@ th[aria-sort] .console-usage-sort__mark {
23284
23623
  ...range && USAGE_STATISTICS_RANGES.includes(range) ? { range } : {},
23285
23624
  ...measure && MEASURES.includes(measure) ? { measure } : {},
23286
23625
  ...granularity === "day" || granularity === "week" || granularity === "month" ? { granularity } : {},
23626
+ ...hostId2 !== void 0 && hostId2.length > 0 ? { hostId: hostId2 } : {},
23287
23627
  ...harness2 !== void 0 ? { harness: harness2 } : {},
23288
23628
  ...model2 !== void 0 ? { model: model2 } : {},
23289
23629
  ...project2 !== void 0 ? { project: project2 } : {},
@@ -23322,7 +23662,7 @@ th[aria-sort] .console-usage-sort__mark {
23322
23662
  day.setDate(day.getDate() - (day.getDay() + 6) % 7);
23323
23663
  return isoDate(day);
23324
23664
  }
23325
- function createUsageStatisticsPage(consoleMessages2, request, pageLocale) {
23665
+ function createUsageStatisticsPage(consoleMessages2, request, pageLocale, usageHosts) {
23326
23666
  const messages = consoleMessages2.usageStatistics;
23327
23667
  return Object.freeze({
23328
23668
  id: "usage-statistics",
@@ -23331,10 +23671,12 @@ th[aria-sort] .console-usage-sort__mark {
23331
23671
  mount(context) {
23332
23672
  const document2 = context.content.ownerDocument;
23333
23673
  const locale = pageLocale ?? (document2.documentElement.lang || "en");
23674
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
23334
23675
  const count3 = (value) => count2(value, locale);
23335
23676
  const tokenCount2 = (totals2, value) => tokenCount(totals2, value, locale);
23336
23677
  const saved = readView();
23337
23678
  const view = {
23679
+ hostId: saved.hostId ?? LOCAL_USAGE_HOST_ID,
23338
23680
  range: saved.range ?? "30d",
23339
23681
  measure: saved.measure ?? "cost",
23340
23682
  granularity: saved.granularity ?? null,
@@ -23365,7 +23707,7 @@ th[aria-sort] .console-usage-sort__mark {
23365
23707
  let projectLabel = /* @__PURE__ */ new Map();
23366
23708
  const projectName = (key) => key === UNKNOWN ? messages.unknownProject : projectLabel.get(key) ?? baseName(key);
23367
23709
  const measureLabel = (measure) => measure === "cost" ? messages.cost : messages.tokens;
23368
- const dateFormat = (options) => new Intl.DateTimeFormat(locale, options);
23710
+ const dateFormat = (options) => new Intl.DateTimeFormat(locale, { ...options, timeZone });
23369
23711
  const shortDate = dateFormat({ month: "short", day: "numeric" });
23370
23712
  const longDate = dateFormat({
23371
23713
  year: "numeric",
@@ -23384,10 +23726,51 @@ th[aria-sort] .console-usage-sort__mark {
23384
23726
  const prices = createModelPricesDialog(
23385
23727
  document2,
23386
23728
  consoleMessages2,
23387
- request,
23729
+ (method, params2) => request(method, params2, view.hostId),
23388
23730
  context.signal,
23389
23731
  load
23390
23732
  );
23733
+ let offeredHosts = usageHosts ? [] : void 0;
23734
+ const hostCombo = new ComboBox(document2, {
23735
+ label: messages.host,
23736
+ searchLabel: messages.search,
23737
+ emptyLabel: messages.noMatches,
23738
+ signal: context.signal,
23739
+ searchable: false,
23740
+ display: (option) => `${messages.host} \xB7 ${option.label}`,
23741
+ onChange: (key) => {
23742
+ if (key === view.hostId) return;
23743
+ view.hostId = key;
23744
+ view.harness = "";
23745
+ view.model = "";
23746
+ view.project = "";
23747
+ date5 = null;
23748
+ unpricedOnly = false;
23749
+ result = null;
23750
+ error51 = null;
23751
+ loadedAt = 0;
23752
+ names.clear();
23753
+ save();
23754
+ hostOptions();
23755
+ render();
23756
+ void refreshHarnessNames();
23757
+ load();
23758
+ }
23759
+ });
23760
+ const hostOptions = () => {
23761
+ const options = usageHostOptions(offeredHosts, messages.localHost, view.hostId);
23762
+ hostCombo.element.hidden = options.length < 2;
23763
+ hostCombo.update(options, view.hostId === LOCAL_USAGE_HOST_ID ? "" : view.hostId);
23764
+ };
23765
+ const offerHosts = () => {
23766
+ if (!usageHosts) return;
23767
+ void usageHosts().then((hosts) => {
23768
+ if (context.signal.aborted) return;
23769
+ offeredHosts = hosts;
23770
+ hostOptions();
23771
+ }).catch(() => void 0);
23772
+ };
23773
+ hostOptions();
23391
23774
  const updated = h(document2, "span", { className: "console-muted console-usage-updated" });
23392
23775
  const refresh = h(
23393
23776
  document2,
@@ -23400,7 +23783,10 @@ th[aria-sort] .console-usage-sort__mark {
23400
23783
  },
23401
23784
  createRendererSettingsIcon("refresh", 16)
23402
23785
  );
23403
- refresh.addEventListener("click", () => load());
23786
+ refresh.addEventListener("click", () => {
23787
+ offerHosts();
23788
+ load();
23789
+ });
23404
23790
  const auto = new ComboBox(document2, {
23405
23791
  label: messages.autoRefresh,
23406
23792
  searchLabel: messages.search,
@@ -23439,6 +23825,7 @@ th[aria-sort] .console-usage-sort__mark {
23439
23825
  document2,
23440
23826
  "div",
23441
23827
  { className: "console-usage-toolbar" },
23828
+ hostCombo.element,
23442
23829
  updated,
23443
23830
  refresh,
23444
23831
  auto.element,
@@ -24077,7 +24464,6 @@ ${detail}` : ""}`
24077
24464
  }
24078
24465
  function hourlyPanel(data) {
24079
24466
  const singleDay = data.filters.date !== null || data.range === "today";
24080
- const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
24081
24467
  return panel(
24082
24468
  singleDay ? messages.hourlyDay : messages.hourly,
24083
24469
  hourlyChart(document2, {
@@ -24092,7 +24478,7 @@ ${detail}` : ""}`
24092
24478
  weekStartsOnMonday: !locale.startsWith("en"),
24093
24479
  labels: { cost: messages.cost, tokens: messages.tokens }
24094
24480
  }),
24095
- h(document2, "span", { className: "console-muted console-usage-zone" }, zone)
24481
+ h(document2, "span", { className: "console-muted console-usage-zone" }, timeZone)
24096
24482
  );
24097
24483
  }
24098
24484
  function sessionsPanel(title, rows, tableKey) {
@@ -24239,6 +24625,7 @@ ${detail}` : ""}`
24239
24625
  const project2 = filterValue(view.project);
24240
24626
  return {
24241
24627
  range: view.range,
24628
+ timeZone,
24242
24629
  ...view.harness ? { harness: view.harness } : {},
24243
24630
  ...model2 !== void 0 ? { model: model2 } : {},
24244
24631
  ...project2 !== void 0 ? { project: project2 } : {},
@@ -24251,10 +24638,26 @@ ${detail}` : ""}`
24251
24638
  if (result && !result.reading.complete) poll = window.setTimeout(load, POLL_MS);
24252
24639
  else if (view.autoRefreshMs > 0) poll = window.setTimeout(load, view.autoRefreshMs);
24253
24640
  }
24641
+ const harnessNamesRead = createLatestKeyGuard();
24642
+ async function refreshHarnessNames() {
24643
+ const hostId2 = view.hostId;
24644
+ const isCurrent = harnessNamesRead.begin(hostId2);
24645
+ names.clear();
24646
+ try {
24647
+ const value = await request(HARNESS_PLUGIN_LIST_METHOD2, {}, hostId2);
24648
+ if (!isCurrent()) return;
24649
+ for (const plugin of harnessPluginListResultSchema.parse(value).plugins) {
24650
+ names.set(plugin.id, plugin.name);
24651
+ }
24652
+ } catch {
24653
+ if (!isCurrent()) return;
24654
+ }
24655
+ if (!context.signal.aborted) render();
24656
+ }
24254
24657
  function load() {
24255
24658
  window.clearTimeout(poll);
24256
24659
  const requested = params();
24257
- void context.runLatest(() => request(USAGE_STATISTICS_METHOD, requested), {
24660
+ void context.runLatest(() => request(USAGE_STATISTICS_METHOD, requested, view.hostId), {
24258
24661
  success(value) {
24259
24662
  const parsed = usageStatisticsResultSchema.safeParse(value);
24260
24663
  if (parsed.success) {
@@ -24279,12 +24682,8 @@ ${detail}` : ""}`
24279
24682
  }
24280
24683
  context.content.replaceChildren(header, prices.element, filters, notices, body);
24281
24684
  render();
24282
- void request(HARNESS_PLUGIN_LIST_METHOD2, {}).then((value) => {
24283
- for (const plugin of harnessPluginListResultSchema.parse(value).plugins) {
24284
- names.set(plugin.id, plugin.name);
24285
- }
24286
- if (!context.signal.aborted) render();
24287
- }).catch(() => void 0);
24685
+ offerHosts();
24686
+ void refreshHarnessNames();
24288
24687
  load();
24289
24688
  return () => {
24290
24689
  window.clearTimeout(poll);
@@ -25512,6 +25911,144 @@ ${detail}` : ""}`
25512
25911
  return section;
25513
25912
  }
25514
25913
 
25914
+ // src/settings/grok-computer-use-controls.ts
25915
+ function createGrokComputerUseControls(document2, messages, settings) {
25916
+ const section = document2.createElement("section");
25917
+ section.className = "settings-grok-computer-use";
25918
+ section.dataset.grokComputerUse = "true";
25919
+ const header = document2.createElement("div");
25920
+ header.className = "settings-grok-computer-use__header";
25921
+ const copy = document2.createElement("div");
25922
+ copy.className = "settings-grok-computer-use__copy";
25923
+ const title = document2.createElement("h3");
25924
+ title.className = "settings-grok-computer-use__title";
25925
+ title.id = "grok-computer-use-title";
25926
+ title.textContent = messages.grokComputerUseTitle;
25927
+ const description = document2.createElement("p");
25928
+ description.className = "settings-grok-computer-use__description";
25929
+ description.id = "grok-computer-use-description";
25930
+ description.textContent = messages.grokComputerUseDescription;
25931
+ copy.append(title, description);
25932
+ const input = createPreferenceSwitch(
25933
+ document2,
25934
+ "grok-computer-use-enabled",
25935
+ "grok-computer-use-description grok-computer-use-help grok-computer-use-status"
25936
+ );
25937
+ input.setAttribute("aria-labelledby", title.id);
25938
+ input.setAttribute("aria-label", messages.grokComputerUseLabel);
25939
+ header.append(copy, input);
25940
+ const help = document2.createElement("p");
25941
+ help.className = "settings-grok-computer-use__help";
25942
+ help.id = "grok-computer-use-help";
25943
+ help.textContent = messages.grokComputerUseHelp;
25944
+ const status = document2.createElement("p");
25945
+ status.className = "settings-grok-computer-use__status";
25946
+ status.id = "grok-computer-use-status";
25947
+ status.setAttribute("role", "status");
25948
+ status.setAttribute("aria-live", "polite");
25949
+ const browserHeader = document2.createElement("div");
25950
+ browserHeader.className = "settings-grok-computer-use__header settings-grok-computer-use__browser";
25951
+ const browserCopy = document2.createElement("div");
25952
+ browserCopy.className = "settings-grok-computer-use__copy";
25953
+ const browserTitle = document2.createElement("h3");
25954
+ browserTitle.className = "settings-grok-computer-use__title";
25955
+ browserTitle.id = "grok-browser-title";
25956
+ browserTitle.textContent = messages.grokBrowserTitle;
25957
+ const browserDescription = document2.createElement("p");
25958
+ browserDescription.className = "settings-grok-computer-use__description";
25959
+ browserDescription.id = "grok-browser-description";
25960
+ browserDescription.textContent = messages.grokBrowserDescription;
25961
+ browserCopy.append(browserTitle, browserDescription);
25962
+ const browserInput = createPreferenceSwitch(
25963
+ document2,
25964
+ "grok-browser-enabled",
25965
+ "grok-browser-description grok-browser-help grok-browser-status"
25966
+ );
25967
+ browserInput.setAttribute("aria-labelledby", browserTitle.id);
25968
+ browserInput.setAttribute("aria-label", messages.grokBrowserLabel);
25969
+ browserHeader.append(browserCopy, browserInput);
25970
+ const browserHelp = document2.createElement("p");
25971
+ browserHelp.className = "settings-grok-computer-use__help";
25972
+ browserHelp.id = "grok-browser-help";
25973
+ browserHelp.textContent = messages.grokBrowserHelp;
25974
+ const browserStatus = document2.createElement("p");
25975
+ browserStatus.className = "settings-grok-computer-use__status";
25976
+ browserStatus.id = "grok-browser-status";
25977
+ browserStatus.setAttribute("role", "status");
25978
+ browserStatus.setAttribute("aria-live", "polite");
25979
+ section.append(header, help, status, browserHeader, browserHelp, browserStatus);
25980
+ let busy = true;
25981
+ let loaded = false;
25982
+ let last;
25983
+ const show = (value) => {
25984
+ last = value;
25985
+ input.checked = value.enabled;
25986
+ input.disabled = busy || !loaded || !value.available && !value.enabled;
25987
+ const browserOn = value.browser === true;
25988
+ const browserFiles = value.browserFilesPresent === true;
25989
+ browserInput.checked = browserOn;
25990
+ browserInput.disabled = busy || !loaded || !browserFiles && !browserOn;
25991
+ if (!browserFiles) {
25992
+ browserStatus.dataset.state = "unavailable";
25993
+ browserStatus.textContent = value.browserUnavailableReason ?? messages.grokBrowserUnavailable;
25994
+ } else if (value.browserAvailable !== true) {
25995
+ browserStatus.dataset.state = browserOn ? "unavailable" : "off";
25996
+ browserStatus.textContent = browserOn ? value.browserUnavailableReason ?? messages.grokBrowserBlocked : messages.grokBrowserOff;
25997
+ } else {
25998
+ browserStatus.dataset.state = browserOn ? "on" : "off";
25999
+ browserStatus.textContent = browserOn ? messages.grokBrowserOn : messages.grokBrowserOff;
26000
+ }
26001
+ if (value.applyFailed) {
26002
+ status.dataset.state = "unavailable";
26003
+ status.textContent = value.applyError ?? messages.grokComputerUseApplyFailed;
26004
+ return;
26005
+ }
26006
+ if (!value.available) {
26007
+ status.dataset.state = "unavailable";
26008
+ status.textContent = value.unavailableReason ?? messages.grokComputerUseUnavailable;
26009
+ return;
26010
+ }
26011
+ status.dataset.state = value.enabled ? "on" : "off";
26012
+ status.textContent = value.enabled ? messages.grokComputerUseOn : messages.grokComputerUseOff;
26013
+ };
26014
+ const save = (update, target) => {
26015
+ if (busy || !loaded) return;
26016
+ busy = true;
26017
+ input.disabled = true;
26018
+ browserInput.disabled = true;
26019
+ target.textContent = messages.grokComputerUseSaving;
26020
+ void settings.set(update).then((value) => {
26021
+ busy = false;
26022
+ show(value);
26023
+ }).catch(() => {
26024
+ busy = false;
26025
+ if (last) show(last);
26026
+ else {
26027
+ input.disabled = false;
26028
+ browserInput.disabled = false;
26029
+ }
26030
+ target.textContent = messages.grokComputerUseSaveError;
26031
+ });
26032
+ };
26033
+ input.addEventListener("change", () => save({ enabled: input.checked }, status));
26034
+ browserInput.addEventListener(
26035
+ "change",
26036
+ () => save({ browser: browserInput.checked }, browserStatus)
26037
+ );
26038
+ status.textContent = messages.grokComputerUseLoading;
26039
+ browserStatus.textContent = messages.grokBrowserOff;
26040
+ void settings.get().then((value) => {
26041
+ loaded = true;
26042
+ busy = false;
26043
+ show(value);
26044
+ }).catch(() => {
26045
+ busy = false;
26046
+ status.textContent = messages.grokComputerUseLoadError;
26047
+ browserStatus.textContent = messages.grokComputerUseLoadError;
26048
+ });
26049
+ return section;
26050
+ }
26051
+
25515
26052
  // src/settings/harness-installation-guides.ts
25516
26053
  function harnessHasInstallCommands(plugin) {
25517
26054
  return (plugin?.installation?.commands.length ?? 0) > 0;
@@ -25663,7 +26200,7 @@ ${detail}` : ""}`
25663
26200
  }
25664
26201
 
25665
26202
  // src/settings/harness-version-panel.ts
25666
- function createHarnessVersionPanel(document2, messages, signal, agent, client) {
26203
+ function createHarnessVersionPanel(document2, messages, signal, agent, client, onChange = () => void 0) {
25667
26204
  const panel = document2.createElement("section");
25668
26205
  panel.className = "settings-harness-version";
25669
26206
  panel.dataset.harnessVersion = agent;
@@ -25689,37 +26226,67 @@ ${detail}` : ""}`
25689
26226
  panel.append(heading, versions, status, actions, note);
25690
26227
  let state;
25691
26228
  let busy = false;
26229
+ let updating = false;
25692
26230
  let unsupported = false;
26231
+ let updatePromise = null;
25693
26232
  const render = () => {
26233
+ heading.textContent = state?.versionKind === "application" ? messages.harnessVersionApplicationTitle : messages.harnessVersionTitle;
25694
26234
  current.textContent = `${messages.harnessVersionCurrent}: ${state?.currentVersion ?? "\u2014"}`;
25695
26235
  latest.textContent = `${messages.harnessVersionLatest}: ${harnessVersionLabel(state, messages.harnessVersion)}`;
25696
26236
  update.disabled = busy || signal.aborted || !state?.canUpdate || !state.updateAvailable;
26237
+ const manualUrl = !state?.canUpdate && state?.updateAvailable ? state.manualUpdateUrl : void 0;
26238
+ actions.replaceChildren(update);
26239
+ update.hidden = !busy && !signal.aborted && Boolean(manualUrl);
26240
+ if (update.hidden && manualUrl) {
26241
+ const download2 = document2.createElement("a");
26242
+ download2.className = "settings-command-button settings-command-button--secondary";
26243
+ download2.dataset.harnessVersionAction = "download-update";
26244
+ download2.textContent = messages.harnessVersionDownloadUpdate;
26245
+ download2.href = manualUrl;
26246
+ download2.target = "_blank";
26247
+ download2.rel = "noopener noreferrer";
26248
+ actions.append(download2);
26249
+ }
25697
26250
  update.textContent = state?.canUpdate && state.latestVersion !== "Unknown" && !state.updateAvailable ? messages.harnessVersionUpToDate : messages.harnessVersionUpdate;
25698
26251
  const detail = harnessVersionNote(state, messages.harnessVersion);
25699
- note.textContent = detail ? `${detail} ${messages.harnessVersionNote}` : messages.harnessVersionNote;
26252
+ note.textContent = detail ? !state?.canUpdate ? detail : `${detail} ${messages.harnessVersionNote}` : messages.harnessVersionNote;
25700
26253
  };
25701
26254
  const run = async (action) => {
25702
- if (busy || unsupported || signal.aborted) return;
25703
- if (action === "update" && (!state?.canUpdate || !state.updateAvailable)) return;
26255
+ if (busy || unsupported || signal.aborted) return false;
26256
+ if (action === "update" && (!state?.canUpdate || !state.updateAvailable)) return false;
25704
26257
  busy = true;
26258
+ updating = action === "update";
26259
+ onChange();
25705
26260
  status.textContent = action === "check" ? messages.harnessVersionChecking : messages.harnessVersionUpdating;
25706
26261
  render();
25707
26262
  try {
25708
26263
  const result = await client.run(action);
25709
- if (signal.aborted) return;
26264
+ if (signal.aborted) return false;
25710
26265
  state = result;
25711
26266
  status.textContent = !result.canUpdate ? messages.harnessVersionManual : action === "update" ? result.updateAvailable ? messages.harnessVersionFailed : messages.harnessVersionUpdated : "";
26267
+ return result.canUpdate && !result.updateAvailable;
25712
26268
  } catch (error51) {
25713
- if (signal.aborted) return;
26269
+ if (signal.aborted) return false;
25714
26270
  unsupported = typeof error51 === "object" && error51 !== null && "code" in error51 && (error51.code === -32601 || error51.code === -32078);
25715
26271
  status.textContent = unsupported ? messages.harnessVersionUnsupported : messages.harnessVersionFailed;
25716
26272
  if (state) state = { ...state, canUpdate: false };
26273
+ return false;
25717
26274
  } finally {
25718
26275
  busy = false;
25719
- if (!signal.aborted) render();
26276
+ updating = false;
26277
+ if (!signal.aborted) {
26278
+ render();
26279
+ onChange();
26280
+ }
25720
26281
  }
25721
26282
  };
25722
- update.addEventListener("click", () => void run("update"));
26283
+ const updateVersion = () => {
26284
+ updatePromise ??= run("update").finally(() => {
26285
+ updatePromise = null;
26286
+ });
26287
+ return updatePromise;
26288
+ };
26289
+ update.addEventListener("click", () => void updateVersion());
25723
26290
  const owner = document2.defaultView;
25724
26291
  let checkFrame = null;
25725
26292
  let checkTimer = null;
@@ -25746,7 +26313,95 @@ ${detail}` : ""}`
25746
26313
  } else {
25747
26314
  void run("check");
25748
26315
  }
25749
- return panel;
26316
+ return {
26317
+ element: panel,
26318
+ get state() {
26319
+ return state;
26320
+ },
26321
+ get updating() {
26322
+ return updating;
26323
+ },
26324
+ update: updateVersion
26325
+ };
26326
+ }
26327
+
26328
+ // src/settings/connection-versions.ts
26329
+ function createConnectionVersions(document2, messages, signal, diagnostics, onChange) {
26330
+ const panels = /* @__PURE__ */ new Map();
26331
+ const installation = diagnostics?.installation?.bind(diagnostics);
26332
+ return {
26333
+ get(hostId2, agent) {
26334
+ if (!installation || signal.aborted) return void 0;
26335
+ const key = JSON.stringify([hostId2, agent]);
26336
+ let panel = panels.get(key);
26337
+ if (!panel) {
26338
+ panel = createHarnessVersionPanel(
26339
+ document2,
26340
+ messages,
26341
+ signal,
26342
+ agent,
26343
+ {
26344
+ run: (action) => installation(hostId2, agent, action)
26345
+ },
26346
+ onChange
26347
+ );
26348
+ panels.set(key, panel);
26349
+ }
26350
+ return panel;
26351
+ }
26352
+ };
26353
+ }
26354
+
26355
+ // src/settings/connection-updates.ts
26356
+ function createConnectionUpdates(document2, messages, signal, onChange) {
26357
+ const batches = /* @__PURE__ */ new Map();
26358
+ const eligible = (panels) => panels.filter((panel) => panel.state?.updateAvailable && panel.state.canUpdate);
26359
+ const start = async (hostId2, panels) => {
26360
+ if (signal.aborted || batches.get(hostId2)?.running) return;
26361
+ const targets = eligible(panels);
26362
+ if (!targets.length) return;
26363
+ const batch = { running: true, total: targets.length, succeeded: 0, failed: 0 };
26364
+ batches.set(hostId2, batch);
26365
+ onChange();
26366
+ await Promise.all(
26367
+ targets.map(async (panel) => {
26368
+ try {
26369
+ if (await panel.update()) batch.succeeded++;
26370
+ else batch.failed++;
26371
+ } catch {
26372
+ batch.failed++;
26373
+ }
26374
+ if (!signal.aborted) onChange();
26375
+ })
26376
+ );
26377
+ batch.running = false;
26378
+ if (!signal.aborted) onChange();
26379
+ };
26380
+ return {
26381
+ createControls(hostId2, panels) {
26382
+ const batch = batches.get(hostId2);
26383
+ const count3 = eligible(panels).length;
26384
+ const button2 = document2.createElement("button");
26385
+ button2.type = "button";
26386
+ button2.className = "settings-command-button settings-command-button--secondary settings-connection-update-all";
26387
+ button2.dataset.connectionAction = "update-all";
26388
+ button2.disabled = signal.aborted || Boolean(batch?.running) || !count3;
26389
+ button2.title = messages.harnessUpdateAllDescription;
26390
+ const label = batch?.running ? `${messages.harnessUpdateAllProgress} ${batch.succeeded + batch.failed}/${batch.total}` : count3 ? `${messages.harnessUpdateAll} (${count3})` : messages.harnessUpdateAll;
26391
+ button2.append(createRendererSettingsIcon("download", 15), label);
26392
+ button2.addEventListener("click", () => {
26393
+ if (!button2.disabled) void start(hostId2, panels);
26394
+ });
26395
+ const result = document2.createElement("p");
26396
+ result.className = "settings-connection-update-result";
26397
+ result.setAttribute("role", "status");
26398
+ result.hidden = !batch || batch.running;
26399
+ if (batch && !batch.running) {
26400
+ result.textContent = messages.harnessUpdateAllResult.replace("{succeeded}", String(batch.succeeded)).replace("{failed}", String(batch.failed));
26401
+ }
26402
+ return { button: button2, result };
26403
+ }
26404
+ };
25750
26405
  }
25751
26406
 
25752
26407
  // src/settings/connections-page.ts
@@ -25914,6 +26569,7 @@ ${error51.stderrTail}`] : []
25914
26569
  status.dataset.connectionTone = connectionStatusTone(item.availability, item.error !== null);
25915
26570
  status.setAttribute("role", "cell");
25916
26571
  status.textContent = item.error?.code === "authenticationRequired" ? messages.connectionLoginRequired : item.error?.code === "configurationRequired" ? messages.connectionConfigurationRequired : connectionStatusLabel(item.availability, messages, item.error !== null);
26572
+ const version2 = item.version;
25917
26573
  const action = document2.createElement("div");
25918
26574
  action.className = "settings-connection-row__action";
25919
26575
  action.setAttribute("role", "cell");
@@ -25943,6 +26599,31 @@ ${error51.stderrTail}`] : []
25943
26599
  });
25944
26600
  action.append(viewError);
25945
26601
  }
26602
+ if (version2?.state?.updateAvailable && !version2.updating) {
26603
+ const available = document2.createElement("span");
26604
+ available.className = "settings-connection-version-available";
26605
+ available.textContent = messages.harnessVersionAvailable;
26606
+ available.title = `${messages.harnessVersionCurrent}: ${version2.state.currentVersion ?? "\u2014"}
26607
+ ${messages.harnessVersionLatest}: ${harnessVersionLabel(version2.state, messages.harnessVersion)}`;
26608
+ action.append(available);
26609
+ }
26610
+ if (version2?.state?.updateAvailable && version2.state.canUpdate) {
26611
+ const update = document2.createElement("button");
26612
+ update.type = "button";
26613
+ update.className = "settings-connection-install-link";
26614
+ update.dataset.connectionAction = "update";
26615
+ update.disabled = version2.updating;
26616
+ update.title = messages.harnessVersionUpdate;
26617
+ update.setAttribute("aria-label", `${messages.harnessVersionUpdate}: ${item.name}`);
26618
+ update.append(createRendererSettingsIcon("download", 17));
26619
+ update.addEventListener("click", (event) => {
26620
+ event.stopPropagation();
26621
+ if (update.disabled) return;
26622
+ void version2.update();
26623
+ select();
26624
+ });
26625
+ action.append(update);
26626
+ }
25946
26627
  if (group) {
25947
26628
  const toggle = document2.createElement("button");
25948
26629
  toggle.type = "button";
@@ -26140,6 +26821,16 @@ ${error51.stderrTail}`] : []
26140
26821
  });
26141
26822
  body.append(launchControls);
26142
26823
  }
26824
+ const getGrokComputerUse = diagnostics?.getGrokComputerUse?.bind(diagnostics);
26825
+ const setGrokComputerUse = diagnostics?.setGrokComputerUse?.bind(diagnostics);
26826
+ if (hostId2 === "local" && agent === "grok" && getGrokComputerUse && setGrokComputerUse) {
26827
+ body.append(
26828
+ createGrokComputerUseControls(document2, messages, {
26829
+ get: () => getGrokComputerUse(hostId2),
26830
+ set: (update) => setGrokComputerUse(hostId2, update)
26831
+ })
26832
+ );
26833
+ }
26143
26834
  inspector.append(body);
26144
26835
  return launchControls;
26145
26836
  }
@@ -26231,8 +26922,6 @@ ${error51.stderrTail}`] : []
26231
26922
  let selectedHostId = null;
26232
26923
  let selectedItemKey = null;
26233
26924
  let launchControls = null;
26234
- const versionPanels = /* @__PURE__ */ new Map();
26235
- const updatingVersions = /* @__PURE__ */ new Set();
26236
26925
  const hostNames = /* @__PURE__ */ new Map();
26237
26926
  let latestSnapshot = null;
26238
26927
  let disposeHostScroller = () => void 0;
@@ -26261,7 +26950,15 @@ ${error51.stderrTail}`] : []
26261
26950
  renderFrame = null;
26262
26951
  };
26263
26952
  const diagnostics = getDiagnostics();
26953
+ const versions = createConnectionVersions(
26954
+ document2,
26955
+ messages,
26956
+ context.signal,
26957
+ diagnostics,
26958
+ scheduleRender
26959
+ );
26264
26960
  const installs = diagnostics ? harnessInstallStore(diagnostics) : null;
26961
+ const updates = createConnectionUpdates(document2, messages, context.signal, scheduleRender);
26265
26962
  const runRefresh = () => {
26266
26963
  if (pending || !diagnostics) return;
26267
26964
  pending = true;
@@ -26397,10 +27094,13 @@ ${error51.stderrTail}`] : []
26397
27094
  const agent = item.agentSnapshot?.agent;
26398
27095
  if (!agent) return item;
26399
27096
  const state = installs?.get(selectedHost.hostId, agent);
27097
+ const availability = state?.status ?? item.availability;
27098
+ const version2 = item.agentSnapshot?.availability !== "notInstalled" && availability !== "installing" && availability !== "checking" ? versions.get(selectedHost.hostId, agent) : void 0;
26400
27099
  return {
26401
27100
  ...item,
26402
27101
  ...state ? { availability: state.status } : {},
26403
- ...updatingVersions.has(JSON.stringify([selectedHost.hostId, agent])) ? { availability: "updating" } : {},
27102
+ ...version2 ? { version: version2 } : {},
27103
+ ...version2?.updating ? { availability: "updating" } : {},
26404
27104
  ...state?.error ? { installError: state.error } : {},
26405
27105
  ...diagnostics?.installation && harnessHasInstallCommands(item.agentSnapshot?.plugin) ? {
26406
27106
  install: () => {
@@ -26437,30 +27137,7 @@ ${error51.stderrTail}`] : []
26437
27137
  runRefresh
26438
27138
  );
26439
27139
  launchControls = { hostId: selectedHost.hostId, itemKey: item.key, element };
26440
- const agent = item.agentSnapshot?.agent;
26441
- const installation = diagnostics?.installation?.bind(diagnostics);
26442
- if (agent && item.agentSnapshot?.availability !== "notInstalled" && item.availability !== "installing" && item.availability !== "checking" && installation) {
26443
- const key = JSON.stringify([selectedHost.hostId, agent]);
26444
- let panel = versionPanels.get(key);
26445
- if (!panel) {
26446
- const hostId2 = selectedHost.hostId;
26447
- panel = createHarnessVersionPanel(document2, messages, context.signal, agent, {
26448
- async run(action) {
26449
- if (action !== "update") return installation(hostId2, agent, action);
26450
- updatingVersions.add(key);
26451
- if (diagnostics) render(diagnostics.snapshot());
26452
- try {
26453
- return await installation(hostId2, agent, action);
26454
- } finally {
26455
- updatingVersions.delete(key);
26456
- if (!context.signal.aborted && diagnostics) render(diagnostics.snapshot());
26457
- }
26458
- }
26459
- });
26460
- versionPanels.set(key, panel);
26461
- }
26462
- inspector.append(panel);
26463
- }
27140
+ if (item.version) inspector.append(item.version.element);
26464
27141
  };
26465
27142
  const pinnedItem = items.find((item) => item.key === "renderer-adapter");
26466
27143
  if (pinnedItem) {
@@ -26616,7 +27293,14 @@ ${error51.stderrTail}`] : []
26616
27293
  }
26617
27294
  const selectedItem = items.find((item) => item.key === selectedItemKey) ?? items[0];
26618
27295
  if (selectedItem) selectItem(selectedItem);
26619
- list.append(hostStrip, tableHeader, rows);
27296
+ const updateControls = updates.createControls(
27297
+ selectedHost.hostId,
27298
+ items.flatMap((item) => item.version ? [item.version] : [])
27299
+ );
27300
+ const hostHeader = document2.createElement("div");
27301
+ hostHeader.className = "settings-connection-host-header";
27302
+ hostHeader.append(hostStrip, updateControls.button);
27303
+ list.append(hostHeader, updateControls.result, tableHeader, rows);
26620
27304
  layout.append(list, inspector);
26621
27305
  content.replaceChildren(layout);
26622
27306
  disposeHostScroller = configureHostScroller(
@@ -29789,7 +30473,7 @@ ${error51.stderrTail}`] : []
29789
30473
  }
29790
30474
  });
29791
30475
  }
29792
- 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"))) {
30476
+ 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"))) {
29793
30477
  return Object.freeze([
29794
30478
  createConnectionsSettingsPage(messages, getDiagnostics, void 0, getRemoteConnections),
29795
30479
  createRemoteConnectionsPage(messages, getRemoteConnections),
@@ -29803,7 +30487,8 @@ ${error51.stderrTail}`] : []
29803
30487
  createUsageStatisticsPage(
29804
30488
  consoleMessages(messages.locale),
29805
30489
  requestUsageStatistics,
29806
- messages.locale
30490
+ messages.locale,
30491
+ usageStatisticsHosts
29807
30492
  ),
29808
30493
  createAppearanceSettingsPage(messages, getLoadedSessionsClient),
29809
30494
  createVoiceSettingsPage(messages.locale, requestVoiceSettings, { desktop: true }),
@@ -30581,6 +31266,20 @@ ${error51.stderrTail}`] : []
30581
31266
  gap: 18px;
30582
31267
  }
30583
31268
 
31269
+ .settings-connections-content {
31270
+ container: settings-connections / inline-size;
31271
+ }
31272
+
31273
+ @container settings-connections (max-width: 780px) {
31274
+ .settings-connections-layout {
31275
+ grid-template-columns: minmax(0, 1fr);
31276
+ }
31277
+
31278
+ .settings-connection-inspector {
31279
+ position: static;
31280
+ }
31281
+ }
31282
+
30584
31283
  .settings-connection-list,
30585
31284
  .settings-connection-inspector {
30586
31285
  overflow: hidden;
@@ -30589,14 +31288,36 @@ ${error51.stderrTail}`] : []
30589
31288
  border-radius: 10px;
30590
31289
  }
30591
31290
 
31291
+ .settings-connection-host-header {
31292
+ display: flex;
31293
+ align-items: center;
31294
+ min-width: 0;
31295
+ border-bottom: 1px solid var(--settings-divider);
31296
+ }
31297
+
31298
+ .settings-connection-update-all {
31299
+ flex: none;
31300
+ margin-right: 10px;
31301
+ white-space: nowrap;
31302
+ }
31303
+
31304
+ .settings-connection-update-result {
31305
+ margin: 0;
31306
+ padding: 7px 10px;
31307
+ color: var(--settings-muted);
31308
+ font-size: 11px;
31309
+ line-height: 18px;
31310
+ border-bottom: 1px solid var(--settings-divider);
31311
+ }
31312
+
30592
31313
  .settings-connection-host-strip {
30593
31314
  display: grid;
31315
+ flex: 1;
30594
31316
  grid-template-columns: 30px minmax(0, 1fr) 30px;
30595
31317
  align-items: center;
30596
31318
  min-width: 0;
30597
31319
  gap: 5px;
30598
31320
  padding: 9px 10px;
30599
- border-bottom: 1px solid var(--settings-divider);
30600
31321
  }
30601
31322
 
30602
31323
  .settings-connection-host-scroll {
@@ -30693,7 +31414,7 @@ ${error51.stderrTail}`] : []
30693
31414
  .settings-connection-table-header,
30694
31415
  .settings-connection-row {
30695
31416
  display: grid;
30696
- grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) 108px;
31417
+ grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) minmax(108px, max-content);
30697
31418
  align-items: center;
30698
31419
  min-width: 0;
30699
31420
  gap: 10px;
@@ -30786,6 +31507,14 @@ ${error51.stderrTail}`] : []
30786
31507
  line-height: 18px;
30787
31508
  }
30788
31509
 
31510
+ .settings-connection-version-available {
31511
+ flex: none;
31512
+ color: var(--settings-muted);
31513
+ font-size: 10px;
31514
+ line-height: 16px;
31515
+ white-space: nowrap;
31516
+ }
31517
+
30789
31518
  .settings-connection-row__status::before {
30790
31519
  width: 6px;
30791
31520
  height: 6px;
@@ -30822,6 +31551,7 @@ ${error51.stderrTail}`] : []
30822
31551
  justify-content: flex-end;
30823
31552
  min-width: 0;
30824
31553
  gap: 4px;
31554
+ white-space: nowrap;
30825
31555
  }
30826
31556
 
30827
31557
  .settings-connection-row__handle {
@@ -31129,6 +31859,69 @@ ${error51.stderrTail}`] : []
31129
31859
  gap: 8px;
31130
31860
  }
31131
31861
 
31862
+ .settings-grok-computer-use {
31863
+ display: grid;
31864
+ gap: 10px;
31865
+ min-width: 0;
31866
+ margin-top: 4px;
31867
+ padding: 12px;
31868
+ background: var(--settings-surface);
31869
+ border: 1px solid var(--settings-divider);
31870
+ border-radius: 12px;
31871
+ }
31872
+
31873
+ .settings-grok-computer-use__header {
31874
+ display: flex;
31875
+ align-items: flex-start;
31876
+ justify-content: space-between;
31877
+ gap: 12px;
31878
+ }
31879
+
31880
+ .settings-grok-computer-use__copy {
31881
+ display: grid;
31882
+ gap: 4px;
31883
+ min-width: 0;
31884
+ }
31885
+
31886
+ .settings-grok-computer-use__title {
31887
+ margin: 0;
31888
+ color: var(--settings-text);
31889
+ font-size: 14px;
31890
+ font-weight: 600;
31891
+ line-height: 20px;
31892
+ }
31893
+
31894
+ .settings-grok-computer-use__description {
31895
+ margin: 0;
31896
+ color: var(--settings-muted);
31897
+ font-size: 13px;
31898
+ line-height: 18px;
31899
+ overflow-wrap: anywhere;
31900
+ }
31901
+
31902
+ .settings-grok-computer-use__help,
31903
+ .settings-grok-computer-use__status {
31904
+ margin: 0;
31905
+ color: var(--settings-subtle);
31906
+ font-size: 12px;
31907
+ line-height: 16px;
31908
+ overflow-wrap: anywhere;
31909
+ }
31910
+
31911
+ .settings-grok-computer-use__help {
31912
+ padding-top: 8px;
31913
+ border-top: 1px solid var(--settings-divider);
31914
+ }
31915
+
31916
+ .settings-grok-computer-use__browser {
31917
+ padding-top: 8px;
31918
+ border-top: 1px solid var(--settings-divider);
31919
+ }
31920
+
31921
+ .settings-grok-computer-use__status[data-state="on"] {
31922
+ color: var(--settings-success);
31923
+ }
31924
+
31132
31925
  .settings-connection-install-callout {
31133
31926
  display: grid;
31134
31927
  grid-template-columns: 28px minmax(0, 1fr);
@@ -32378,6 +33171,19 @@ ${error51.stderrTail}`] : []
32378
33171
  border-top: 1px solid var(--settings-divider);
32379
33172
  font-size: 13px;
32380
33173
  }
33174
+ .settings-voice__health {
33175
+ display: grid;
33176
+ gap: 4px;
33177
+ margin: 8px 12px 12px;
33178
+ color: var(--settings-subtle);
33179
+ font-size: 12px;
33180
+ line-height: 16px;
33181
+ }
33182
+
33183
+ .settings-voice__health p {
33184
+ margin: 0;
33185
+ }
33186
+
32381
33187
  .settings-voice__footer p,
32382
33188
  .settings-voice__hint {
32383
33189
  margin: 4px 0 0;