@codexhost/cli-win32-arm64 0.3.4 → 0.4.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.
@@ -15014,7 +15014,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15014
15014
  productUsage: external_exports.array(accountCreditsProductUsageSchema).min(1).optional()
15015
15015
  }).strict();
15016
15016
  var threadUsageInspectionParamsSchema = external_exports.object({
15017
- threadId: hostThreadIdSchema
15017
+ threadId: hostThreadIdSchema,
15018
+ refresh: external_exports.literal("exact").optional()
15018
15019
  }).strict();
15019
15020
  var threadUsageInspectionSchema = external_exports.object({
15020
15021
  threadId: hostThreadIdSchema,
@@ -16558,6 +16559,86 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16558
16559
  ["path", { d: "M12 16h.01" }]
16559
16560
  ];
16560
16561
 
16562
+ // src/renderer-harness-localization.ts
16563
+ var ENGLISH_HARNESS_MESSAGES = Object.freeze({
16564
+ commands: "Commands",
16565
+ harnessCommands: "Harness commands",
16566
+ textArgument: "Text",
16567
+ permissionMode: "Permission mode",
16568
+ permissions: "Permissions",
16569
+ loadingPermissions: "Loading permissions...",
16570
+ selecting: "Selecting...",
16571
+ permissionsUnavailable: "Permissions unavailable"
16572
+ });
16573
+ var CHINESE_HARNESS_MESSAGES = Object.freeze({
16574
+ commands: "\u547D\u4EE4",
16575
+ harnessCommands: "Harness \u547D\u4EE4",
16576
+ textArgument: "\u6587\u672C",
16577
+ permissionMode: "\u6743\u9650\u6A21\u5F0F",
16578
+ permissions: "\u6743\u9650",
16579
+ loadingPermissions: "\u6B63\u5728\u52A0\u8F7D\u6743\u9650...",
16580
+ selecting: "\u6B63\u5728\u9009\u62E9...",
16581
+ permissionsUnavailable: "\u6743\u9650\u4E0D\u53EF\u7528"
16582
+ });
16583
+ var CHINESE_PERMISSION_MODE_LABELS = /* @__PURE__ */ new Map([
16584
+ ["Always ask", "\u59CB\u7EC8\u8BE2\u95EE"],
16585
+ ["Write", "\u5199\u5165"],
16586
+ ["Full access", "\u5B8C\u5168\u8BBF\u95EE"],
16587
+ ["Plan mode", "\u89C4\u5212\u6A21\u5F0F"],
16588
+ ["Default", "\u9ED8\u8BA4"],
16589
+ ["Accept edits", "\u63A5\u53D7\u7F16\u8F91"],
16590
+ ["Auto mode", "\u81EA\u52A8\u6A21\u5F0F"],
16591
+ ["Bypass permissions", "\u7ED5\u8FC7\u6743\u9650"],
16592
+ ["Ask", "\u8BE2\u95EE"],
16593
+ ["Auto", "\u81EA\u52A8"],
16594
+ ["Always approve", "\u59CB\u7EC8\u6279\u51C6"]
16595
+ ]);
16596
+ var CHINESE_PERMISSION_MODE_DESCRIPTIONS = /* @__PURE__ */ new Map([
16597
+ [
16598
+ "Automatically allow reads and ask before write or execution actions.",
16599
+ "\u81EA\u52A8\u5141\u8BB8\u8BFB\u53D6\uFF1B\u5199\u5165\u6216\u6267\u884C\u64CD\u4F5C\u524D\u8BE2\u95EE\u3002"
16600
+ ],
16601
+ [
16602
+ "Automatically allow reads and writes; ask before execution actions.",
16603
+ "\u81EA\u52A8\u5141\u8BB8\u8BFB\u53D6\u548C\u5199\u5165\uFF1B\u6267\u884C\u64CD\u4F5C\u524D\u8BE2\u95EE\u3002"
16604
+ ],
16605
+ ["Run all tool actions without approval prompts.", "\u65E0\u9700\u6279\u51C6\u63D0\u793A\u5373\u53EF\u8FD0\u884C\u6240\u6709\u5DE5\u5177\u64CD\u4F5C\u3002"],
16606
+ ["Analyze and plan without executing tools.", "\u4EC5\u5206\u6790\u548C\u89C4\u5212\uFF0C\u4E0D\u6267\u884C\u5DE5\u5177\u3002"],
16607
+ ["Ask before edits and other protected actions.", "\u7F16\u8F91\u548C\u5176\u4ED6\u53D7\u4FDD\u62A4\u64CD\u4F5C\u524D\u8BE2\u95EE\u3002"],
16608
+ ["Allow file edits and ask for other protected actions.", "\u5141\u8BB8\u6587\u4EF6\u7F16\u8F91\uFF1B\u5176\u4ED6\u53D7\u4FDD\u62A4\u64CD\u4F5C\u524D\u8BE2\u95EE\u3002"],
16609
+ ["Let Claude classify permission requests.", "\u7531 Claude \u5224\u65AD\u6743\u9650\u8BF7\u6C42\u3002"],
16610
+ ["Skip Claude Code permission checks.", "\u8DF3\u8FC7 Claude Code \u6743\u9650\u68C0\u67E5\u3002"],
16611
+ [
16612
+ "Use Grok Build's default interactive approval policy.",
16613
+ "\u4F7F\u7528 Grok Build \u7684\u9ED8\u8BA4\u4EA4\u4E92\u5F0F\u6279\u51C6\u7B56\u7565\u3002"
16614
+ ],
16615
+ ["Ask before protected tool actions.", "\u6267\u884C\u53D7\u4FDD\u62A4\u7684\u5DE5\u5177\u64CD\u4F5C\u524D\u8BE2\u95EE\u3002"],
16616
+ [
16617
+ "Let Grok Build decide which tool actions may run automatically.",
16618
+ "\u7531 Grok Build \u51B3\u5B9A\u54EA\u4E9B\u5DE5\u5177\u64CD\u4F5C\u53EF\u81EA\u52A8\u8FD0\u884C\u3002"
16619
+ ],
16620
+ ["Approve all tool actions without prompting.", "\u65E0\u9700\u63D0\u793A\u5373\u53EF\u6279\u51C6\u6240\u6709\u5DE5\u5177\u64CD\u4F5C\u3002"]
16621
+ ]);
16622
+ function rendererHarnessMessages(locale) {
16623
+ return locale === "zh-CN" ? CHINESE_HARNESS_MESSAGES : ENGLISH_HARNESS_MESSAGES;
16624
+ }
16625
+ function rendererHarnessCommandPresentation(command, locale) {
16626
+ if (locale === "zh-CN" && command.invocation === "/compact") {
16627
+ return { label: "\u538B\u7F29\u4E0A\u4E0B\u6587", description: "\u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\u4E0A\u4E0B\u6587" };
16628
+ }
16629
+ return {
16630
+ label: command.label,
16631
+ description: command.description ?? command.label
16632
+ };
16633
+ }
16634
+ function rendererPermissionModePresentation(mode, locale) {
16635
+ if (locale !== "zh-CN") return { label: mode.label, description: mode.description };
16636
+ return {
16637
+ label: CHINESE_PERMISSION_MODE_LABELS.get(mode.label) ?? mode.label,
16638
+ description: mode.description === void 0 ? void 0 : CHINESE_PERMISSION_MODE_DESCRIPTIONS.get(mode.description) ?? mode.description
16639
+ };
16640
+ }
16641
+
16561
16642
  // src/renderer-permission-mode-picker.ts
16562
16643
  var MENU_CLASSES2 = "fixed z-50 overflow-hidden rounded-lg bg-token-dropdown-background/95 text-token-foreground shadow-lg ring-[0.5px] ring-token-border backdrop-blur-xl";
16563
16644
  var OPTION_CLASSES2 = "flex w-full cursor-interaction items-start gap-2 rounded-md px-2 py-2 text-left text-sm text-token-foreground outline-none enabled:hover:bg-token-list-hover-background enabled:active:bg-token-foreground/15 disabled:cursor-not-allowed disabled:opacity-40";
@@ -16584,13 +16665,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16584
16665
  if (view.status === "unsupported") return true;
16585
16666
  return (view.status === "ready" || view.status === "error") && selectedMode(view) !== void 0;
16586
16667
  }
16587
- function rendererPermissionModeLabel(view) {
16668
+ function rendererPermissionModeLabel(view, locale = "en") {
16588
16669
  const selected = selectedMode(view);
16589
- if (selected) return selected.label;
16590
- if (view.status === "loading") return "Loading permissions...";
16591
- if (view.status === "selecting") return "Selecting...";
16592
- if (view.status === "error") return "Permissions unavailable";
16593
- return "Permissions";
16670
+ if (selected) return rendererPermissionModePresentation(selected, locale).label;
16671
+ const messages = rendererHarnessMessages(locale);
16672
+ if (view.status === "loading") return messages.loadingPermissions;
16673
+ if (view.status === "selecting") return messages.selecting;
16674
+ if (view.status === "error") return messages.permissionsUnavailable;
16675
+ return messages.permissions;
16594
16676
  }
16595
16677
  function positionMenu(control) {
16596
16678
  const rect = control.trigger.getBoundingClientRect();
@@ -16605,7 +16687,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16605
16687
  control.trigger.style.maxWidth = "min(220px, 34vw)";
16606
16688
  control.trigger.style.letterSpacing = "0";
16607
16689
  }
16608
- function mountRendererPermissionModePicker(composerId, onSelect) {
16690
+ function mountRendererPermissionModePicker(composerId, onSelect, locale = "en") {
16609
16691
  ensureRendererTriggerChipStyle(document);
16610
16692
  const root = document.createElement("div");
16611
16693
  root.setAttribute("data-codexhost-permission-mode-control", composerId);
@@ -16637,7 +16719,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16637
16719
  const menu = document.createElement("div");
16638
16720
  menu.id = `${composerId}-permission-mode-menu`;
16639
16721
  menu.setAttribute("role", "menu");
16640
- menu.setAttribute("aria-label", "Permission mode");
16722
+ menu.setAttribute("aria-label", rendererHarnessMessages(locale).permissionMode);
16641
16723
  menu.setAttribute("popover", "auto");
16642
16724
  menu.hidden = typeof menu.showPopover !== "function";
16643
16725
  menu.className = MENU_CLASSES2;
@@ -16727,6 +16809,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16727
16809
  label,
16728
16810
  menu,
16729
16811
  options,
16812
+ locale,
16730
16813
  close,
16731
16814
  dispose() {
16732
16815
  close();
@@ -16743,10 +16826,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16743
16826
  syncRendererPermissionModeTriggerClass(control);
16744
16827
  return control;
16745
16828
  }
16746
- function rebuildOptions2(control, catalog) {
16829
+ function rebuildOptions2(control, catalog, locale) {
16747
16830
  control.options.clear();
16748
16831
  control.menu.replaceChildren();
16749
16832
  for (const mode of catalog.modes) {
16833
+ const presentation = rendererPermissionModePresentation(mode, locale);
16750
16834
  const button = document.createElement("button");
16751
16835
  button.type = "button";
16752
16836
  button.dataset.permissionModeId = mode.id;
@@ -16760,13 +16844,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16760
16844
  const copy = document.createElement("span");
16761
16845
  copy.className = "min-w-0 flex-1";
16762
16846
  const title = document.createElement("span");
16763
- title.textContent = mode.label;
16847
+ title.textContent = presentation.label;
16764
16848
  title.className = "block font-medium";
16765
16849
  title.style.letterSpacing = "0";
16766
16850
  copy.append(title);
16767
- if (mode.description) {
16851
+ if (presentation.description) {
16768
16852
  const description = document.createElement("span");
16769
- description.textContent = mode.description;
16853
+ description.textContent = presentation.description;
16770
16854
  description.className = "mt-0.5 block text-xs text-token-text-tertiary";
16771
16855
  description.style.lineHeight = "16px";
16772
16856
  description.style.letterSpacing = "0";
@@ -16781,7 +16865,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16781
16865
  control.menu.append(button);
16782
16866
  }
16783
16867
  }
16784
- function renderRendererPermissionModePicker(control, view, visible) {
16868
+ function renderRendererPermissionModePicker(control, view, visible, locale = control.locale) {
16869
+ control.locale = locale;
16870
+ const messages = rendererHarnessMessages(locale);
16871
+ control.menu.setAttribute("aria-label", messages.permissionMode);
16785
16872
  control.root.style.display = visible ? "inline-flex" : "none";
16786
16873
  control.root.style.alignItems = "center";
16787
16874
  control.root.style.alignSelf = "center";
@@ -16792,15 +16879,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16792
16879
  control.close();
16793
16880
  return;
16794
16881
  }
16795
- const signature = JSON.stringify(view.catalog);
16882
+ const signature = `${locale}:${JSON.stringify(view.catalog)}`;
16796
16883
  if (view.catalog && control.root.dataset.catalogSignature !== signature) {
16797
- rebuildOptions2(control, view.catalog);
16884
+ rebuildOptions2(control, view.catalog, locale);
16798
16885
  control.root.dataset.catalogSignature = signature;
16799
16886
  }
16800
- const label = rendererPermissionModeLabel(view);
16887
+ const label = rendererPermissionModeLabel(view, locale);
16801
16888
  if (control.label.textContent !== label) control.label.textContent = label;
16802
16889
  control.trigger.title = view.error ? `${label}: ${view.error}` : label;
16803
- control.trigger.setAttribute("aria-label", `Permission mode: ${label}`);
16890
+ control.trigger.setAttribute("aria-label", `${messages.permissionMode}: ${label}`);
16804
16891
  control.trigger.disabled = view.status === "loading" || view.status === "selecting" || view.catalog === void 0;
16805
16892
  control.trigger.setAttribute("aria-busy", String(view.status === "selecting"));
16806
16893
  if (control.trigger.disabled) control.close();
@@ -16813,6 +16900,51 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16813
16900
  }
16814
16901
 
16815
16902
  // src/renderer-usage-control.ts
16903
+ var ENGLISH_USAGE_MESSAGES = Object.freeze({
16904
+ usage: "Usage",
16905
+ context: "Context",
16906
+ latestCacheHit: "Latest cache hit",
16907
+ outputSpeed: "Output speed",
16908
+ cacheRead: "Cache read",
16909
+ cacheWrite: "Cache write",
16910
+ reasoning: "Reasoning",
16911
+ totalTokens: "Total tokens",
16912
+ inputOutput: "Input / output",
16913
+ fiveHourLimit: "5-hour limit",
16914
+ sevenDayLimit: "7-day limit",
16915
+ sessionCostEstimate: "Session cost estimate",
16916
+ threadUsage: "Thread Usage",
16917
+ threadUsageDetails: "Thread Usage details",
16918
+ contextSummary: "context",
16919
+ tokensSummary: "tokens",
16920
+ tokensPerSecond: "tok/s",
16921
+ fiveHourSummary: "5h",
16922
+ sevenDaySummary: "7d"
16923
+ });
16924
+ var CHINESE_USAGE_MESSAGES = Object.freeze({
16925
+ usage: "\u7528\u91CF",
16926
+ context: "\u4E0A\u4E0B\u6587",
16927
+ latestCacheHit: "\u6700\u8FD1\u7F13\u5B58\u547D\u4E2D\u7387",
16928
+ outputSpeed: "\u8F93\u51FA\u901F\u5EA6",
16929
+ cacheRead: "\u7F13\u5B58\u8BFB\u53D6",
16930
+ cacheWrite: "\u7F13\u5B58\u5199\u5165",
16931
+ reasoning: "\u63A8\u7406",
16932
+ totalTokens: "Token \u603B\u6570",
16933
+ inputOutput: "\u8F93\u5165 / \u8F93\u51FA",
16934
+ fiveHourLimit: "5 \u5C0F\u65F6\u9650\u989D",
16935
+ sevenDayLimit: "7 \u5929\u9650\u989D",
16936
+ sessionCostEstimate: "\u4F1A\u8BDD\u8D39\u7528\u4F30\u7B97",
16937
+ threadUsage: "\u5BF9\u8BDD\u7528\u91CF",
16938
+ threadUsageDetails: "\u5BF9\u8BDD\u7528\u91CF\u8BE6\u60C5",
16939
+ contextSummary: "\u4E0A\u4E0B\u6587",
16940
+ tokensSummary: "Token",
16941
+ tokensPerSecond: "Token/\u79D2",
16942
+ fiveHourSummary: "5 \u5C0F\u65F6",
16943
+ sevenDaySummary: "7 \u5929"
16944
+ });
16945
+ function rendererUsageMessages(locale) {
16946
+ return locale === "zh-CN" ? CHINESE_USAGE_MESSAGES : ENGLISH_USAGE_MESSAGES;
16947
+ }
16816
16948
  function decimal(value, fractionDigits) {
16817
16949
  return value.toFixed(fractionDigits).replace(/\.?0+$/u, "");
16818
16950
  }
@@ -16822,14 +16954,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16822
16954
  function formatRendererCost(value) {
16823
16955
  return `$${value.toFixed(3)}`;
16824
16956
  }
16825
- function formatRendererTokenRate(value) {
16826
- return `${decimal(value, 1)} tok/s`;
16957
+ function formatRendererTokenRate(value, locale = "en") {
16958
+ return `${decimal(value, 1)} ${rendererUsageMessages(locale).tokensPerSecond}`;
16827
16959
  }
16828
16960
  function formatRendererTokenCount(value) {
16829
16961
  const sign = value < 0 ? "-" : "";
16830
16962
  const absolute = Math.abs(value);
16831
16963
  if (absolute < 1e3) return `${sign}${Math.round(absolute)}`;
16832
- return `${sign}${decimal(absolute / 1e3, 1)}k`;
16964
+ if (absolute < 1e6) return `${sign}${decimal(absolute / 1e3, 1)}k`;
16965
+ if (absolute < 1e9) return `${sign}${decimal(absolute / 1e6, 1)}M`;
16966
+ return `${sign}${decimal(absolute / 1e9, 1)}B`;
16833
16967
  }
16834
16968
  function formatRendererCreditsPercent(value) {
16835
16969
  return `${decimal(value, 1)}%`;
@@ -16871,20 +17005,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16871
17005
  svg.append(track, fill);
16872
17006
  return svg;
16873
17007
  }
16874
- function formatRendererPlanReset(unixSeconds) {
17008
+ function formatRendererPlanReset(unixSeconds, locale) {
16875
17009
  const date5 = new Date(unixSeconds * 1e3);
16876
17010
  if (Number.isNaN(date5.getTime())) return "";
16877
- return date5.toLocaleString(void 0, {
17011
+ return date5.toLocaleString(locale === "zh-CN" ? "zh-CN" : void 0, {
16878
17012
  month: "long",
16879
17013
  day: "numeric",
16880
17014
  hour: "numeric",
16881
17015
  minute: "2-digit"
16882
17016
  });
16883
17017
  }
16884
- function formatRendererPlanWindow(usedPercent, resetsAtUnix) {
17018
+ function formatRendererPlanWindow(usedPercent, resetsAtUnix, locale) {
16885
17019
  const percent = formatRendererCreditsPercent(usedPercent);
16886
17020
  if (resetsAtUnix === void 0) return percent;
16887
- const reset = formatRendererPlanReset(resetsAtUnix);
17021
+ const reset = formatRendererPlanReset(resetsAtUnix, locale);
16888
17022
  return reset.length > 0 ? `${percent} \xB7 ${reset}` : percent;
16889
17023
  }
16890
17024
  function rendererUsageTriggerMaxWidth() {
@@ -16916,10 +17050,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16916
17050
  row.append(labelElement, valueElement);
16917
17051
  parent.append(row);
16918
17052
  }
16919
- function renderDetails(popover, usage) {
17053
+ function renderDetails(popover, usage, messages, locale) {
16920
17054
  popover.replaceChildren();
16921
17055
  const heading = document.createElement("div");
16922
- heading.textContent = "Usage";
17056
+ heading.textContent = messages.usage;
16923
17057
  heading.style.fontWeight = "600";
16924
17058
  heading.style.marginBottom = "6px";
16925
17059
  popover.append(heading);
@@ -16927,55 +17061,75 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16927
17061
  const contextPercent = usage.contextWindowTokens > 0 ? usage.contextUsedTokens / usage.contextWindowTokens * 100 : null;
16928
17062
  addDetailRow(
16929
17063
  popover,
16930
- "Context",
17064
+ messages.context,
16931
17065
  contextPercent === null ? `/${formatRendererTokenCount(usage.contextWindowTokens)}` : `${decimal(contextPercent, 1)}% / ${formatRendererTokenCount(usage.contextWindowTokens)}`
16932
17066
  );
16933
17067
  }
16934
17068
  if (usage?.cacheHitRatePercent !== void 0) {
16935
17069
  addDetailRow(
16936
17070
  popover,
16937
- "Latest cache hit",
17071
+ messages.latestCacheHit,
16938
17072
  formatRendererCacheHitRate(usage.cacheHitRatePercent)
16939
17073
  );
16940
17074
  }
16941
17075
  if (usage?.outputTokensPerSecond !== void 0) {
16942
- addDetailRow(popover, "Output speed", formatRendererTokenRate(usage.outputTokensPerSecond));
17076
+ addDetailRow(
17077
+ popover,
17078
+ messages.outputSpeed,
17079
+ formatRendererTokenRate(usage.outputTokensPerSecond, locale)
17080
+ );
16943
17081
  }
16944
17082
  if (usage?.cachedInputTokens !== void 0) {
16945
- addDetailRow(popover, "Cache read", formatRendererTokenCount(usage.cachedInputTokens));
17083
+ addDetailRow(popover, messages.cacheRead, formatRendererTokenCount(usage.cachedInputTokens));
16946
17084
  }
16947
17085
  if (usage?.cacheWriteInputTokens !== void 0) {
16948
- addDetailRow(popover, "Cache write", formatRendererTokenCount(usage.cacheWriteInputTokens));
17086
+ addDetailRow(
17087
+ popover,
17088
+ messages.cacheWrite,
17089
+ formatRendererTokenCount(usage.cacheWriteInputTokens)
17090
+ );
16949
17091
  }
16950
17092
  if (usage?.reasoningOutputTokens !== void 0) {
16951
- addDetailRow(popover, "Reasoning", formatRendererTokenCount(usage.reasoningOutputTokens));
17093
+ addDetailRow(
17094
+ popover,
17095
+ messages.reasoning,
17096
+ formatRendererTokenCount(usage.reasoningOutputTokens)
17097
+ );
16952
17098
  }
16953
17099
  if (usage?.totalTokens !== void 0) {
16954
- addDetailRow(popover, "Total tokens", formatRendererTokenCount(usage.totalTokens));
17100
+ addDetailRow(popover, messages.totalTokens, formatRendererTokenCount(usage.totalTokens));
16955
17101
  }
16956
17102
  if (usage?.inputTokens !== void 0 || usage?.outputTokens !== void 0) {
16957
17103
  addDetailRow(
16958
17104
  popover,
16959
- "Input / output",
17105
+ messages.inputOutput,
16960
17106
  `${formatRendererTokenCount(usage.inputTokens ?? 0)} / ${formatRendererTokenCount(usage.outputTokens ?? 0)}`
16961
17107
  );
16962
17108
  }
16963
17109
  if (usage?.planFiveHourUsedPercent !== void 0) {
16964
17110
  addDetailRow(
16965
17111
  popover,
16966
- "5-hour limit",
16967
- formatRendererPlanWindow(usage.planFiveHourUsedPercent, usage.planFiveHourResetsAtUnix)
17112
+ messages.fiveHourLimit,
17113
+ formatRendererPlanWindow(
17114
+ usage.planFiveHourUsedPercent,
17115
+ usage.planFiveHourResetsAtUnix,
17116
+ locale
17117
+ )
16968
17118
  );
16969
17119
  }
16970
17120
  if (usage?.planSevenDayUsedPercent !== void 0) {
16971
17121
  addDetailRow(
16972
17122
  popover,
16973
- "7-day limit",
16974
- formatRendererPlanWindow(usage.planSevenDayUsedPercent, usage.planSevenDayResetsAtUnix)
17123
+ messages.sevenDayLimit,
17124
+ formatRendererPlanWindow(
17125
+ usage.planSevenDayUsedPercent,
17126
+ usage.planSevenDayResetsAtUnix,
17127
+ locale
17128
+ )
16975
17129
  );
16976
17130
  }
16977
17131
  if (usage?.totalCostUsd !== void 0) {
16978
- addDetailRow(popover, "Session cost estimate", formatRendererCost(usage.totalCostUsd));
17132
+ addDetailRow(popover, messages.sessionCostEstimate, formatRendererCost(usage.totalCostUsd));
16979
17133
  }
16980
17134
  }
16981
17135
  function popoverIsOpen(popover) {
@@ -17003,19 +17157,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17003
17157
  control.trigger.setAttribute("aria-expanded", "false");
17004
17158
  }
17005
17159
  function openPopover(control) {
17160
+ const wasOpen = control.trigger.getAttribute("aria-expanded") === "true";
17006
17161
  positionPopover(control);
17007
17162
  control.popover.hidden = false;
17008
17163
  if (typeof control.popover.showPopover === "function" && !popoverIsOpen(control.popover)) {
17009
17164
  control.popover.showPopover();
17010
17165
  }
17011
17166
  control.trigger.setAttribute("aria-expanded", "true");
17167
+ if (!wasOpen) control.onOpen?.();
17012
17168
  }
17013
17169
  function togglePopover(control) {
17014
17170
  if (control.trigger.getAttribute("aria-expanded") === "true") closePopover(control);
17015
17171
  else openPopover(control);
17016
17172
  }
17017
- function mountRendererUsageControl(composerId) {
17173
+ function mountRendererUsageControl(composerId, locale = "en") {
17018
17174
  ensureRendererTriggerChipStyle(document);
17175
+ const messages = rendererUsageMessages(locale);
17019
17176
  const root = document.createElement("div");
17020
17177
  root.dataset.codexhostUsageControl = composerId;
17021
17178
  root.className = "relative min-w-0";
@@ -17030,8 +17187,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17030
17187
  trigger.type = "button";
17031
17188
  trigger.setAttribute("aria-haspopup", "dialog");
17032
17189
  trigger.setAttribute("aria-expanded", "false");
17033
- trigger.setAttribute("aria-label", "Thread Usage");
17034
- trigger.title = "Thread Usage";
17190
+ trigger.setAttribute("aria-label", messages.threadUsage);
17191
+ trigger.title = messages.threadUsage;
17035
17192
  trigger.style.color = "var(--color-text-tertiary, #8f8f8f)";
17036
17193
  trigger.style.gap = "4px";
17037
17194
  trigger.style.width = "fit-content";
@@ -17053,7 +17210,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17053
17210
  const popover = document.createElement("div");
17054
17211
  popover.id = `${composerId}-usage-popover`;
17055
17212
  popover.setAttribute("role", "dialog");
17056
- popover.setAttribute("aria-label", "Thread Usage details");
17213
+ popover.setAttribute("aria-label", messages.threadUsageDetails);
17057
17214
  popover.setAttribute("popover", "auto");
17058
17215
  popover.hidden = typeof popover.showPopover !== "function";
17059
17216
  popover.style.position = "fixed";
@@ -17073,6 +17230,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17073
17230
  popover,
17074
17231
  anchor: null,
17075
17232
  label,
17233
+ locale,
17234
+ onOpen: null,
17076
17235
  dispose() {
17077
17236
  closePopover(control);
17078
17237
  if (closeTimer !== null) window.clearTimeout(closeTimer);
@@ -17126,7 +17285,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17126
17285
  document.body.append(popover);
17127
17286
  return control;
17128
17287
  }
17129
- function renderRendererUsageControl(control, usage) {
17288
+ function renderRendererUsageControl(control, usage, locale = control.locale) {
17289
+ control.locale = locale;
17290
+ const messages = rendererUsageMessages(locale);
17291
+ control.popover.setAttribute("aria-label", messages.threadUsageDetails);
17130
17292
  const cacheHitRatePercent = usage?.cacheHitRatePercent;
17131
17293
  const outputTokensPerSecond = usage?.outputTokensPerSecond;
17132
17294
  const totalCostUsd = usage?.totalCostUsd;
@@ -17141,34 +17303,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17141
17303
  }
17142
17304
  const summary = [
17143
17305
  cacheHitRatePercent !== void 0 ? formatRendererCacheHitRate(cacheHitRatePercent) : null,
17144
- outputTokensPerSecond !== void 0 ? formatRendererTokenRate(outputTokensPerSecond) : null,
17306
+ outputTokensPerSecond !== void 0 ? formatRendererTokenRate(outputTokensPerSecond, locale) : null,
17145
17307
  totalCostUsd !== void 0 ? formatRendererCost(totalCostUsd) : null
17146
17308
  ].filter((value) => value !== null);
17147
17309
  if (summary.length === 0 && hasContext && usage?.contextWindowTokens !== void 0 && usage.contextWindowTokens > 0) {
17148
17310
  summary.push(
17149
- `${decimal((usage.contextUsedTokens ?? 0) / usage.contextWindowTokens * 100, 1)}% context`
17311
+ `${decimal((usage.contextUsedTokens ?? 0) / usage.contextWindowTokens * 100, 1)}% ${messages.contextSummary}`
17150
17312
  );
17151
17313
  }
17152
17314
  if (summary.length === 0 && usage?.totalTokens !== void 0) {
17153
- summary.push(`${formatRendererTokenCount(usage.totalTokens)} tokens`);
17315
+ summary.push(`${formatRendererTokenCount(usage.totalTokens)} ${messages.tokensSummary}`);
17154
17316
  }
17155
17317
  if (summary.length === 0 && hasTokenUsage) {
17156
17318
  summary.push(
17157
- `${formatRendererTokenCount((usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0))} tokens`
17319
+ `${formatRendererTokenCount((usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0))} ${messages.tokensSummary}`
17158
17320
  );
17159
17321
  }
17160
17322
  if (summary.length === 0 && hasPlanLimit) {
17161
17323
  summary.push(
17162
- usage?.planFiveHourUsedPercent !== void 0 ? `5h ${formatRendererCreditsPercent(usage.planFiveHourUsedPercent)}` : `7d ${formatRendererCreditsPercent(usage?.planSevenDayUsedPercent ?? 0)}`
17324
+ usage?.planFiveHourUsedPercent !== void 0 ? `${messages.fiveHourSummary} ${formatRendererCreditsPercent(usage.planFiveHourUsedPercent)}` : `${messages.sevenDaySummary} ${formatRendererCreditsPercent(usage?.planSevenDayUsedPercent ?? 0)}`
17163
17325
  );
17164
17326
  }
17165
17327
  const compactSummary = summary.join(" \xB7 ");
17166
- const accessibleSummary = `Thread Usage: ${compactSummary}`;
17328
+ const accessibleSummary = `${messages.threadUsage}: ${compactSummary}`;
17167
17329
  control.trigger.style.maxWidth = rendererUsageTriggerMaxWidth();
17168
17330
  control.trigger.setAttribute("aria-label", accessibleSummary);
17169
17331
  control.trigger.title = accessibleSummary;
17170
17332
  control.label.textContent = compactSummary;
17171
- renderDetails(control.popover, usage);
17333
+ renderDetails(control.popover, usage, messages, locale);
17172
17334
  return true;
17173
17335
  }
17174
17336
 
@@ -17507,12 +17669,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17507
17669
  }
17508
17670
  return svg;
17509
17671
  }
17510
- function menuItem(ownerDocument, command, onSelect) {
17672
+ function menuItem(ownerDocument, command, locale, messages, onSelect) {
17673
+ const presentation = rendererHarnessCommandPresentation(command, locale);
17511
17674
  const item = ownerDocument.createElement("button");
17512
17675
  item.type = "button";
17513
17676
  item.setAttribute("role", "menuitem");
17514
17677
  item.setAttribute("data-command-id", command.id);
17515
- item.setAttribute("aria-label", `${command.invocation} ${command.label}`);
17678
+ item.setAttribute("aria-label", `${command.invocation} ${presentation.label}`);
17516
17679
  item.style.display = "flex";
17517
17680
  item.style.alignItems = "center";
17518
17681
  item.style.width = "100%";
@@ -17543,14 +17706,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17543
17706
  title.style.font = "600 13px/18px system-ui, sans-serif";
17544
17707
  title.style.whiteSpace = "nowrap";
17545
17708
  const description = ownerDocument.createElement("span");
17546
- description.textContent = command.description ?? command.label;
17709
+ description.textContent = presentation.description;
17547
17710
  description.style.overflow = "hidden";
17548
17711
  description.style.color = "rgba(127, 127, 127, 0.9)";
17549
17712
  description.style.font = "400 11px/16px system-ui, sans-serif";
17550
17713
  description.style.textOverflow = "ellipsis";
17551
17714
  description.style.whiteSpace = "nowrap";
17552
17715
  const hint = ownerDocument.createElement("span");
17553
- hint.textContent = command.argumentMode === "text" ? "Text" : "\u21B5";
17716
+ hint.textContent = command.argumentMode === "text" ? messages.textArgument : "\u21B5";
17554
17717
  hint.style.flex = "0 0 auto";
17555
17718
  hint.style.color = "rgba(127, 127, 127, 0.75)";
17556
17719
  hint.style.font = "400 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace";
@@ -17576,8 +17739,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17576
17739
  button.style.cursor = "pointer";
17577
17740
  button.style.whiteSpace = "nowrap";
17578
17741
  }
17579
- function mountRendererHarnessCommandControl(parent, insertBefore, onCommandSelected) {
17742
+ function mountRendererHarnessCommandControl(parent, insertBefore, onCommandSelected, initialLocale = "en") {
17580
17743
  const ownerDocument = parent.ownerDocument;
17744
+ let locale = initialLocale;
17745
+ let messages = rendererHarnessMessages(locale);
17581
17746
  const root = ownerDocument.createElement("div");
17582
17747
  root.setAttribute(CONTROL_ATTRIBUTE2, "true");
17583
17748
  root.style.display = "inline-flex";
@@ -17587,15 +17752,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17587
17752
  trigger.type = "button";
17588
17753
  trigger.setAttribute("aria-haspopup", "menu");
17589
17754
  trigger.setAttribute("aria-expanded", "false");
17590
- trigger.setAttribute("aria-label", "Harness commands");
17591
- trigger.title = "Harness commands";
17755
+ trigger.setAttribute("aria-label", messages.harnessCommands);
17756
+ trigger.title = messages.harnessCommands;
17592
17757
  setButtonClass(trigger);
17593
17758
  trigger.append(commandIcon(ownerDocument));
17594
17759
  root.append(trigger);
17595
17760
  const menu = ownerDocument.createElement("div");
17596
17761
  menu.setAttribute(MENU_ATTRIBUTE, "true");
17597
17762
  menu.setAttribute("role", "menu");
17598
- menu.setAttribute("aria-label", "Harness commands");
17763
+ menu.setAttribute("aria-label", messages.harnessCommands);
17599
17764
  menu.hidden = true;
17600
17765
  menu.style.position = "fixed";
17601
17766
  menu.style.inset = "auto";
@@ -17673,12 +17838,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17673
17838
  const renderItems = () => {
17674
17839
  menu.replaceChildren();
17675
17840
  const header = ownerDocument.createElement("div");
17676
- header.textContent = "Commands";
17841
+ header.textContent = messages.commands;
17677
17842
  header.style.padding = "5px 8px 4px";
17678
17843
  header.style.color = "rgba(127, 127, 127, 0.75)";
17679
17844
  header.style.font = "600 11px/16px system-ui, sans-serif";
17680
17845
  menu.append(header);
17681
- items = commands.map((command) => menuItem(ownerDocument, command, () => select(command)));
17846
+ items = commands.map(
17847
+ (command) => menuItem(ownerDocument, command, locale, messages, () => select(command))
17848
+ );
17682
17849
  menu.append(...items);
17683
17850
  activeIndex = Math.min(activeIndex, Math.max(0, items.length - 1));
17684
17851
  if (executingCommandId !== null) {
@@ -17776,6 +17943,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17776
17943
  trigger.style.opacity = commandId !== null ? "0.65" : "1";
17777
17944
  syncTriggerBackground();
17778
17945
  },
17946
+ setLocale(nextLocale) {
17947
+ if (locale === nextLocale) return;
17948
+ locale = nextLocale;
17949
+ messages = rendererHarnessMessages(locale);
17950
+ trigger.setAttribute("aria-label", messages.harnessCommands);
17951
+ trigger.title = messages.harnessCommands;
17952
+ menu.setAttribute("aria-label", messages.harnessCommands);
17953
+ renderItems();
17954
+ },
17779
17955
  close,
17780
17956
  dispose() {
17781
17957
  if (disposed) return;
@@ -18134,9 +18310,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18134
18310
  refreshCreditsPlacement(control);
18135
18311
  return control;
18136
18312
  }
18137
- function renderComposerAgentControl(control, state, adapterState, switching, availability = {}, modelView = { status: "idle" }, permissionModeView = { status: "idle" }, usage = null, accountCredits = null) {
18313
+ function renderComposerAgentControl(control, state, adapterState, switching, availability = {}, modelView = { status: "idle" }, permissionModeView = { status: "idle" }, usage = null, accountCredits = null, locale = "en") {
18138
18314
  if (control.usage === null) {
18139
- control.usage = mountRendererUsageControl(control.composerId);
18315
+ control.usage = mountRendererUsageControl(control.composerId, locale);
18140
18316
  }
18141
18317
  const selectedModel = modelView.selected;
18142
18318
  const selectedCatalogModel = modelView.catalog?.models.find(
@@ -18172,9 +18348,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18172
18348
  renderRendererPermissionModePicker(
18173
18349
  control.permissionModePicker,
18174
18350
  permissionModeView,
18175
- permissionModeVisible
18351
+ permissionModeVisible,
18352
+ locale
18176
18353
  );
18177
- if (control.usage) renderRendererUsageControl(control.usage, usage);
18354
+ if (control.usage) renderRendererUsageControl(control.usage, usage, locale);
18355
+ control.harnessCommands.setLocale(locale);
18178
18356
  renderRendererCreditsControl(control.credits, accountCredits);
18179
18357
  }
18180
18358
  function disposeComposerAgentControl(control) {
@@ -18675,7 +18853,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18675
18853
  const parsed = hostThreadIdSchema.safeParse(params.threadId);
18676
18854
  return parsed.success ? parsed.data : null;
18677
18855
  }
18678
- function usageNotificationTarget(manager) {
18856
+ function notificationTarget(manager) {
18679
18857
  if (typeof manager.addNotificationCallback === "function") return manager;
18680
18858
  const nested = manager.requestClient;
18681
18859
  return nested && typeof nested.addNotificationCallback === "function" ? nested : null;
@@ -18776,7 +18954,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18776
18954
  },
18777
18955
  inspectThreadUsage,
18778
18956
  subscribeThreadUsage(listener) {
18779
- const notifications = usageNotificationTarget(manager);
18957
+ const notifications = notificationTarget(manager);
18780
18958
  if (!notifications?.addNotificationCallback) {
18781
18959
  throw new Error("Renderer Usage notification callback is unavailable");
18782
18960
  }
@@ -18952,19 +19130,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18952
19130
  ...thinking?.success ? { thinkingOptionId: thinking.data } : {}
18953
19131
  };
18954
19132
  }
18955
- function deepSeekHarnessTransportModelId(model) {
18956
- if (!model) return DEEPSEEK_HARNESS_TRANSPORT_MODEL_ID;
18957
- return `${DEEPSEEK_HARNESS_TRANSPORT_MODEL_PREFIX}${harnessModelRefSchema.parse(model).id}`;
19133
+ function deepSeekHarnessTransportModelId(model, permissionModeId) {
19134
+ if (!model) {
19135
+ if (permissionModeId) {
19136
+ throw new Error("DeepSeek Harness transport Permission Mode requires a Model Ref");
19137
+ }
19138
+ return DEEPSEEK_HARNESS_TRANSPORT_MODEL_ID;
19139
+ }
19140
+ const parsedPermissionModeId = permissionModeId ? harnessPermissionModeIdSchema.parse(permissionModeId) : void 0;
19141
+ return `${DEEPSEEK_HARNESS_TRANSPORT_MODEL_PREFIX}${harnessModelRefSchema.parse(model).id}${parsedPermissionModeId ? `@${parsedPermissionModeId}` : ""}`;
18958
19142
  }
18959
19143
  function decodeDeepSeekHarnessTransportModelId(value) {
18960
19144
  if (value === DEEPSEEK_HARNESS_TRANSPORT_MODEL_ID) return {};
18961
19145
  if (typeof value !== "string" || !value.startsWith(DEEPSEEK_HARNESS_TRANSPORT_MODEL_PREFIX)) {
18962
19146
  return null;
18963
19147
  }
18964
- const model = harnessModelRefSchema.safeParse({
18965
- id: value.slice(DEEPSEEK_HARNESS_TRANSPORT_MODEL_PREFIX.length)
18966
- });
18967
- return model.success ? { model: model.data } : null;
19148
+ const components = value.slice(DEEPSEEK_HARNESS_TRANSPORT_MODEL_PREFIX.length).split("@");
19149
+ if (components.length < 1 || components.length > 2) return null;
19150
+ const [modelId, permissionModeId] = components;
19151
+ if (components.length === 2 && !permissionModeId) return null;
19152
+ const model = harnessModelRefSchema.safeParse({ id: modelId });
19153
+ if (!model.success) return null;
19154
+ const permissionMode = permissionModeId ? harnessPermissionModeIdSchema.safeParse(permissionModeId) : null;
19155
+ if (permissionMode && !permissionMode.success) return null;
19156
+ return {
19157
+ model: model.data,
19158
+ ...permissionMode?.success ? { permissionModeId: permissionMode.data } : {}
19159
+ };
18968
19160
  }
18969
19161
  function decodePiTransportModelId(value) {
18970
19162
  if (value === PI_TRANSPORT_MODEL_ID) return {};
@@ -19141,12 +19333,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19141
19333
  const hostId = target.getHostId?.() ?? bridge.hostId;
19142
19334
  return typeof hostId === "string" && hostId.length > 0 ? hostId : null;
19143
19335
  }
19336
+ function isRendererRequestTarget(value) {
19337
+ if (!isRecord5(value) || typeof value.sendRequest !== "function") return false;
19338
+ return isCurrentRequestBridge(value.requestClient ?? value);
19339
+ }
19340
+ function hasPolicyRequestTarget(policy) {
19341
+ return "requestTarget" in policy;
19342
+ }
19343
+ function exactRendererRequestTarget(policy) {
19344
+ if (typeof policy.requestTarget !== "function") return null;
19345
+ try {
19346
+ const target = policy.requestTarget();
19347
+ if (!isRendererRequestTarget(target) || prewarmTargetHostId(target) !== policy.hostId) {
19348
+ return null;
19349
+ }
19350
+ return [target];
19351
+ } catch {
19352
+ return null;
19353
+ }
19354
+ }
19144
19355
  function rendererRequestTargetsForHost(targets, hostId) {
19145
19356
  const matching = targets.filter((target) => prewarmTargetHostId(target) === hostId);
19146
19357
  return matching.length === 1 ? matching : null;
19147
19358
  }
19148
19359
  function activeRendererDraftPrewarmTargets(policy, targets) {
19149
19360
  if (!isDraftPrewarmPolicyReady(policy)) return null;
19361
+ if (hasPolicyRequestTarget(policy)) return exactRendererRequestTarget(policy);
19150
19362
  return rendererRequestTargetsForHost(targets, policy.hostId);
19151
19363
  }
19152
19364
  function resolveRendererRequestRoute(policy, discoveredTargets, previous) {
@@ -19154,13 +19366,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19154
19366
  if (isDraftPrewarmPolicyReady(policy) && activeTargets) {
19155
19367
  return { policy, targets: activeTargets };
19156
19368
  }
19369
+ if (isDraftPrewarmPolicyReady(policy) && hasPolicyRequestTarget(policy)) return null;
19157
19370
  return discoveredTargets.length === 0 && isDraftPrewarmPolicyReady(policy) && previous?.policy === policy ? previous : null;
19158
19371
  }
19159
19372
  function createRendererRequestRouteResolver(readPolicy, discoverTargets) {
19160
19373
  let route = null;
19161
19374
  return {
19162
19375
  resolve() {
19163
- route = resolveRendererRequestRoute(readPolicy(), discoverTargets(), route);
19376
+ const policy = readPolicy();
19377
+ const discoveredTargets = isDraftPrewarmPolicyReady(policy) && hasPolicyRequestTarget(policy) ? [] : discoverTargets();
19378
+ route = resolveRendererRequestRoute(policy, discoveredTargets, route);
19164
19379
  return route;
19165
19380
  },
19166
19381
  clear() {
@@ -19181,7 +19396,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19181
19396
  }
19182
19397
  }
19183
19398
  function modelSelectionForAgent(officialSelection, reasoningEffort, agent, model, thinkingOptionId, permissionModeId) {
19184
- const transportModelId = agent === "pi" ? piTransportModelId(model, thinkingOptionId) : agent === "claude-code" ? claudeTransportModelId(model, permissionModeId, thinkingOptionId) : agent === "deepseek-harness" ? deepSeekHarnessTransportModelId(model) : agent === "grok" ? grokTransportModelId(model, permissionModeId, thinkingOptionId) : agent === "omp" ? ompTransportModelId(model, thinkingOptionId) : transportModelIdForAgent(agent);
19399
+ const transportModelId = agent === "pi" ? piTransportModelId(model, thinkingOptionId) : agent === "claude-code" ? claudeTransportModelId(model, permissionModeId, thinkingOptionId) : agent === "deepseek-harness" ? deepSeekHarnessTransportModelId(model, permissionModeId) : agent === "grok" ? grokTransportModelId(model, permissionModeId, thinkingOptionId) : agent === "omp" ? ompTransportModelId(model, thinkingOptionId) : transportModelIdForAgent(agent);
19185
19400
  return transportModelId ? { model: transportModelId, reasoningEffort } : officialSelection;
19186
19401
  }
19187
19402
  function installCurrentRendererAdapter() {
@@ -19211,7 +19426,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19211
19426
  () => window.__codexhostDraftPrewarmPolicyV1,
19212
19427
  () => findActivePrewarmTargets(document)
19213
19428
  );
19214
- const currentRequestRoute = () => requestRouteResolver.resolve();
19215
19429
  const clientsByTarget = /* @__PURE__ */ new WeakMap();
19216
19430
  const modelClientForTargets = (targets) => {
19217
19431
  const target = targets[0];
@@ -19222,8 +19436,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19222
19436
  if (client) clientsByTarget.set(target, client);
19223
19437
  return client;
19224
19438
  };
19439
+ let activeRoutePolicy = null;
19440
+ let activeRouteClient = null;
19441
+ const syncActiveRoute = (route) => {
19442
+ const policy = route?.policy ?? null;
19443
+ const client = route ? modelClientForTargets(route.targets) : null;
19444
+ if (activeRoutePolicy === policy && activeRouteClient === client) return client;
19445
+ activeRoutePolicy = policy;
19446
+ activeRouteClient = client;
19447
+ return client;
19448
+ };
19449
+ const currentRequestRoute = () => {
19450
+ const route = requestRouteResolver.resolve();
19451
+ syncActiveRoute(route);
19452
+ return route;
19453
+ };
19225
19454
  const currentModelClient = () => {
19226
- const client = modelClientForTargets(currentRequestRoute()?.targets ?? []);
19455
+ const client = currentRequestRoute() ? activeRouteClient : null;
19227
19456
  if (!client) throw new Error("Renderer Model request manager is unavailable");
19228
19457
  usageSubscription.connect(client);
19229
19458
  return client;
@@ -19231,6 +19460,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19231
19460
  const modelControl = Object.freeze({
19232
19461
  currentHostId: () => currentRequestRoute()?.policy.hostId ?? null,
19233
19462
  clientForHost(hostId) {
19463
+ const route = currentRequestRoute();
19464
+ if (route?.policy.hostId === hostId) return modelClientForTargets(route.targets);
19465
+ const policy = window.__codexhostDraftPrewarmPolicyV1;
19466
+ if (isDraftPrewarmPolicyReady(policy) && hasPolicyRequestTarget(policy)) return null;
19234
19467
  const targets = rendererRequestTargetsForHost(findActivePrewarmTargets(document), hostId);
19235
19468
  return modelClientForTargets(targets ?? []);
19236
19469
  },
@@ -19264,25 +19497,76 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19264
19497
  });
19265
19498
  let routingPolicy = null;
19266
19499
  let policyTimer = null;
19500
+ let policyRecaptureObserver = null;
19501
+ let hasCapturedRoutingPolicy = false;
19502
+ let selectedRoutingPolicy = null;
19503
+ let selectedCarrier = null;
19267
19504
  let desiredCarrier = null;
19505
+ const stopPolicyCapture = () => {
19506
+ if (policyTimer === null) return;
19507
+ window.clearInterval(policyTimer);
19508
+ policyTimer = null;
19509
+ };
19510
+ const stopPolicyRecapture = () => {
19511
+ policyRecaptureObserver?.disconnect();
19512
+ policyRecaptureObserver = null;
19513
+ };
19268
19514
  const captureRoutingPolicy = () => {
19269
19515
  const route = currentRequestRoute();
19270
19516
  if (!route) return false;
19271
19517
  routingPolicy = route.policy;
19272
- routingPolicy.select(desiredCarrier);
19273
- if (policyTimer !== null) {
19274
- window.clearInterval(policyTimer);
19275
- policyTimer = null;
19518
+ stopPolicyRecapture();
19519
+ if (selectedRoutingPolicy !== routingPolicy || selectedCarrier !== desiredCarrier) {
19520
+ try {
19521
+ routingPolicy.select(desiredCarrier);
19522
+ } catch {
19523
+ updateStatus("installing", "draft-routing-policy-unavailable", null);
19524
+ return false;
19525
+ }
19526
+ selectedRoutingPolicy = routingPolicy;
19527
+ selectedCarrier = desiredCarrier;
19276
19528
  }
19529
+ hasCapturedRoutingPolicy = true;
19530
+ stopPolicyCapture();
19277
19531
  updateStatus("ready", "ready", "request-bridge");
19278
19532
  return true;
19279
19533
  };
19534
+ const startPolicyCapture = () => {
19535
+ stopPolicyCapture();
19536
+ policyTimer = window.setInterval(captureRoutingPolicy, DRAFT_PREWARM_POLICY_POLL_INTERVAL_MS);
19537
+ };
19538
+ const startPolicyRecapture = () => {
19539
+ stopPolicyRecapture();
19540
+ policyRecaptureObserver = new MutationObserver(() => {
19541
+ captureRoutingPolicy();
19542
+ });
19543
+ policyRecaptureObserver.observe(document.documentElement, {
19544
+ attributes: true,
19545
+ attributeFilter: ["hidden", "aria-hidden", "data-codex-composer-root"],
19546
+ characterData: true,
19547
+ childList: true,
19548
+ subtree: true
19549
+ });
19550
+ };
19280
19551
  if (!captureRoutingPolicy()) {
19281
19552
  updateStatus("installing", "draft-routing-policy-unavailable", null);
19282
- policyTimer = window.setInterval(captureRoutingPolicy, DRAFT_PREWARM_POLICY_POLL_INTERVAL_MS);
19553
+ const policy = window.__codexhostDraftPrewarmPolicyV1;
19554
+ if (!isDraftPrewarmPolicyReady(policy) || !hasPolicyRequestTarget(policy)) {
19555
+ startPolicyCapture();
19556
+ }
19283
19557
  }
19284
19558
  const handleRoutingPolicyChange = () => {
19285
- captureRoutingPolicy();
19559
+ stopPolicyRecapture();
19560
+ if (captureRoutingPolicy()) return;
19561
+ const policy = window.__codexhostDraftPrewarmPolicyV1;
19562
+ if (isDraftPrewarmPolicyReady(policy) && hasPolicyRequestTarget(policy)) {
19563
+ stopPolicyCapture();
19564
+ }
19565
+ if (!hasCapturedRoutingPolicy) return;
19566
+ updateStatus("installing", "draft-routing-policy-unavailable", null);
19567
+ if (isDraftPrewarmPolicyReady(policy) && !hasPolicyRequestTarget(policy)) {
19568
+ startPolicyRecapture();
19569
+ }
19286
19570
  };
19287
19571
  window.addEventListener("codexhost:draft-prewarm-policy-changed", handleRoutingPolicyChange);
19288
19572
  const applyAgent = (agent, model, thinkingOptionId, permissionModeId) => {
@@ -19301,9 +19585,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19301
19585
  const route = currentRequestRoute();
19302
19586
  if (!route) return false;
19303
19587
  routingPolicy = route.policy;
19304
- if (route.policy.select(desiredCarrier)) {
19305
- modelUpdates += 1;
19306
- liveStatus.modelUpdates = modelUpdates;
19588
+ try {
19589
+ if (route.policy.select(desiredCarrier)) {
19590
+ modelUpdates += 1;
19591
+ liveStatus.modelUpdates = modelUpdates;
19592
+ }
19593
+ selectedRoutingPolicy = route.policy;
19594
+ selectedCarrier = desiredCarrier;
19595
+ } catch {
19596
+ updateStatus("installing", "draft-routing-policy-unavailable", null);
19597
+ return false;
19307
19598
  }
19308
19599
  return true;
19309
19600
  };
@@ -19314,16 +19605,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19314
19605
  dispose() {
19315
19606
  if (disposed) return;
19316
19607
  disposed = true;
19317
- if (policyTimer !== null) window.clearInterval(policyTimer);
19608
+ stopPolicyCapture();
19609
+ stopPolicyRecapture();
19318
19610
  window.removeEventListener(
19319
19611
  "codexhost:draft-prewarm-policy-changed",
19320
19612
  handleRoutingPolicyChange
19321
19613
  );
19322
- routingPolicy?.select(null);
19614
+ const activeRoutingPolicy = routingPolicy;
19323
19615
  routingPolicy = null;
19324
19616
  requestRouteResolver.clear();
19325
- forkControl.dispose();
19326
- usageSubscription.dispose();
19617
+ const cleanups = [
19618
+ () => activeRoutingPolicy?.select(null),
19619
+ () => syncActiveRoute(null),
19620
+ () => forkControl.dispose(),
19621
+ () => usageSubscription.dispose()
19622
+ ];
19623
+ for (const cleanup of cleanups) {
19624
+ try {
19625
+ cleanup();
19626
+ } catch {
19627
+ }
19628
+ }
19327
19629
  }
19328
19630
  };
19329
19631
  }
@@ -19646,11 +19948,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19646
19948
  close: "Close settings",
19647
19949
  starOnGitHub: "Give us a Star~",
19648
19950
  sectionsLabel: "Settings sections",
19951
+ generalSection: "General",
19952
+ otherSection: "Other",
19649
19953
  pageUnavailable: "Page unavailable",
19650
19954
  inDevelopment: "In development",
19651
19955
  notAvailable: "Not available",
19652
19956
  runtimeCapabilityNotInstalled: "This runtime capability is not installed yet.",
19653
- connectionsDescription: "Inspect the adapter and each Agent runtime used by the picker. Failed checks keep their error details here.",
19957
+ connectionsDescription: "View runtime status by Host. Select an item to inspect details or complete its setup.",
19654
19958
  connectionAdapter: "Renderer adapter",
19655
19959
  connectionHosts: "Hosts",
19656
19960
  connectionLocalHost: "Local",
@@ -19659,9 +19963,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19659
19963
  connectionReason: "Reason",
19660
19964
  connectionRefresh: "Run connection diagnostics",
19661
19965
  connectionRefreshing: "Running diagnostics...",
19662
- connectionViewDetails: "View details",
19966
+ connectionViewError: "View error",
19663
19967
  connectionCopyDetails: "Copy diagnostics",
19664
- connectionCopyAll: "Copy all diagnostics",
19665
19968
  connectionCopied: "Copied",
19666
19969
  connectionCopyFailed: "Copy failed",
19667
19970
  connectionErrorCode: "Error code",
@@ -19678,6 +19981,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19678
19981
  connectionStatusError: "Error",
19679
19982
  connectionStatusInstalling: "Installing",
19680
19983
  connectionStatusUnsupported: "Unsupported",
19984
+ connectionComponent: "Component",
19985
+ connectionStatus: "Status",
19986
+ connectionHostsScrollLeft: "Show previous Hosts",
19987
+ connectionHostsScrollRight: "Show more Hosts",
19988
+ connectionOpenInstallation: "Open official installation page",
19989
+ connectionInstall: "Install",
19990
+ connectionInstallDescription: "This Harness was not detected. Follow its official installation guide, then return here and run the check again.",
19991
+ connectionErrorTitle: "Connection check failed",
19992
+ connectionErrorLog: "Error log",
19993
+ connectionOpenIssue: "Open GitHub Issue",
19994
+ connectionIssueDescription: "Copy the error log and include the Host and reproduction steps when reporting the issue.",
19995
+ connectionReadyDescription: "This component is available on the selected Host.",
19996
+ connectionUnavailableDescription: "This component is not currently available on the selected Host.",
19997
+ enabled: "Enabled",
19998
+ disabled: "Disabled",
19681
19999
  openSettings: "Open codexhost settings",
19682
20000
  settingsButtonTitle: "codexhost settings",
19683
20001
  settingsUnavailableTitle: "codexhost settings unavailable",
@@ -19690,7 +20008,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19690
20008
  updateLatestVersion: "Latest version",
19691
20009
  updateUpToDate: "You are up to date.",
19692
20010
  updateAvailable: "A new version is available.",
19693
- updateAndRestart: "Update and restart",
20011
+ updateWindowsManualRequired: "Automatic updates are unavailable on Windows. Update manually below.",
20012
+ updateAndRestart: "Update",
19694
20013
  updateChecking: "Checking for updates...",
19695
20014
  updateDownloading: "Downloading update...",
19696
20015
  updatePreparing: "Preparing update...",
@@ -19703,13 +20022,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19703
20022
  updateFailed: "Update failed.",
19704
20023
  updateRetry: "Retry",
19705
20024
  updateManualNpmDescription: "To update manually, quit codexhost and run this command:",
20025
+ updateWindowsNpmDescription: "Automatic updates are unavailable on Windows. Quit codexhost and run this command in a terminal:",
20026
+ updateWindowsInstallerDescription: "Automatic updates are unavailable on Windows. Download and run the installer for this system.",
20027
+ updateManualTitle: "Manual update",
20028
+ updateManualFallbackDescription: "The automatic update did not complete. Run this command in a terminal instead, then quit Codex and relaunch it with codexhost.",
20029
+ updateCopyCommand: "Copy",
20030
+ updateCommandCopied: "Copied",
20031
+ updateCopyFailed: "Copy failed",
19706
20032
  updateDownloadFromReleases: "Download from GitHub Releases",
20033
+ updateDownloadWindowsInstaller: "Download Windows installer",
20034
+ aboutTagline: "Run Pi and other Harnesses in Codex Desktop",
20035
+ aboutParagraphs: Object.freeze([
20036
+ "We believe Codex Desktop offers the best desktop development experience available today.",
20037
+ "But Codex is not the only excellent Agent Harness. Some developers prefer Claude Code or Pi Agent.",
20038
+ "codexhost lets you choose the Agent that actually executes tasks inside Codex Desktop, while preserving the native Codex experience and enabling them to collaborate."
20039
+ ]),
20040
+ aboutOpenSource: "codexhost is an open-source project. The source code is available at:",
20041
+ aboutStarCallout: "\u2B50 If this project helps you, please give us a Star! \u2B50",
20042
+ aboutRepository: "Open-source repository",
19707
20043
  pageLabels: Object.freeze({
19708
20044
  connections: "Connections",
19709
- "model-pool": "Model Pool",
19710
- routes: "Routes",
19711
- gateway: "Gateway",
19712
- updates: "Updates"
20045
+ updates: "Updates",
20046
+ about: "About"
19713
20047
  })
19714
20048
  });
19715
20049
  var CHINESE_MESSAGES = Object.freeze({
@@ -19718,11 +20052,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19718
20052
  close: "\u5173\u95ED\u8BBE\u7F6E",
19719
20053
  starOnGitHub: "\u70B9\u4E2A Star~",
19720
20054
  sectionsLabel: "\u8BBE\u7F6E\u5206\u7C7B",
20055
+ generalSection: "\u901A\u7528",
20056
+ otherSection: "\u5176\u4ED6",
19721
20057
  pageUnavailable: "\u9875\u9762\u4E0D\u53EF\u7528",
19722
20058
  inDevelopment: "\u5F00\u53D1\u4E2D",
19723
20059
  notAvailable: "\u6682\u4E0D\u53EF\u7528",
19724
20060
  runtimeCapabilityNotInstalled: "\u8FD0\u884C\u65F6\u5C1A\u672A\u5B89\u88C5\u8BE5\u9879\u80FD\u529B\uFF0C\u56E0\u6B64\u6682\u4E0D\u53EF\u7528\u3002",
19725
- connectionsDescription: "\u67E5\u770B\u9002\u914D\u5668\u548C Agent \u8FD0\u884C\u65F6\u7684\u771F\u5B9E\u68C0\u67E5\u7ED3\u679C\u3002\u5931\u8D25\u68C0\u67E5\u4F1A\u4FDD\u7559\u9519\u8BEF\u8BE6\u60C5\uFF0C\u65B9\u4FBF\u6392\u67E5\u65E0\u6CD5\u9009\u62E9\u7684\u95EE\u9898\u3002",
20061
+ connectionsDescription: "\u6309 Host \u67E5\u770B\u8FD0\u884C\u65F6\u72B6\u6001\u3002\u9009\u62E9\u4E00\u9879\uFF0C\u5728\u53F3\u4FA7\u68C0\u67E5\u8BE6\u60C5\u6216\u5B8C\u6210\u914D\u7F6E\u3002",
19726
20062
  connectionAdapter: "Renderer \u9002\u914D\u5668",
19727
20063
  connectionHosts: "Host \u5217\u8868",
19728
20064
  connectionLocalHost: "\u672C\u5730",
@@ -19731,9 +20067,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19731
20067
  connectionReason: "\u539F\u56E0",
19732
20068
  connectionRefresh: "\u91CD\u65B0\u8BCA\u65AD\u8FDE\u63A5",
19733
20069
  connectionRefreshing: "\u6B63\u5728\u8BCA\u65AD...",
19734
- connectionViewDetails: "\u67E5\u770B\u8BE6\u60C5",
20070
+ connectionViewError: "\u67E5\u770B\u9519\u8BEF",
19735
20071
  connectionCopyDetails: "\u590D\u5236\u8BCA\u65AD\u4FE1\u606F",
19736
- connectionCopyAll: "\u590D\u5236\u5168\u90E8\u8BCA\u65AD\u4FE1\u606F",
19737
20072
  connectionCopied: "\u5DF2\u590D\u5236",
19738
20073
  connectionCopyFailed: "\u590D\u5236\u5931\u8D25",
19739
20074
  connectionErrorCode: "\u9519\u8BEF\u7801",
@@ -19750,6 +20085,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19750
20085
  connectionStatusError: "\u9519\u8BEF",
19751
20086
  connectionStatusInstalling: "\u5B89\u88C5\u4E2D",
19752
20087
  connectionStatusUnsupported: "\u4E0D\u652F\u6301",
20088
+ connectionComponent: "\u7EC4\u4EF6",
20089
+ connectionStatus: "\u72B6\u6001",
20090
+ connectionHostsScrollLeft: "\u67E5\u770B\u524D\u9762\u7684 Host",
20091
+ connectionHostsScrollRight: "\u67E5\u770B\u66F4\u591A Host",
20092
+ connectionOpenInstallation: "\u524D\u5F80\u5B98\u65B9\u5B89\u88C5\u9875\u9762",
20093
+ connectionInstall: "\u5B89\u88C5",
20094
+ connectionInstallDescription: "\u5C1A\u672A\u68C0\u6D4B\u5230\u8BE5 Harness\u3002\u8BF7\u6309\u7167\u5B98\u65B9\u5B89\u88C5\u6307\u5357\u5B8C\u6210\u5B89\u88C5\uFF0C\u7136\u540E\u8FD4\u56DE\u6B64\u9875\u9762\u91CD\u65B0\u68C0\u67E5\u3002",
20095
+ connectionErrorTitle: "\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25",
20096
+ connectionErrorLog: "\u9519\u8BEF\u65E5\u5FD7",
20097
+ connectionOpenIssue: "\u63D0\u4EA4 GitHub Issue",
20098
+ connectionIssueDescription: "\u63D0\u4EA4\u524D\u8BF7\u590D\u5236\u9519\u8BEF\u65E5\u5FD7\uFF0C\u5E76\u5728 Issue \u4E2D\u8BF4\u660E\u5F53\u524D Host \u4E0E\u590D\u73B0\u6B65\u9AA4\u3002",
20099
+ connectionReadyDescription: "\u8BE5\u7EC4\u4EF6\u5728\u5F53\u524D Host \u4E0A\u53EF\u7528\u3002",
20100
+ connectionUnavailableDescription: "\u8BE5\u7EC4\u4EF6\u5F53\u524D\u65E0\u6CD5\u5728\u6240\u9009 Host \u4E0A\u4F7F\u7528\u3002",
20101
+ enabled: "\u5DF2\u5F00\u542F",
20102
+ disabled: "\u5DF2\u5173\u95ED",
19753
20103
  openSettings: "\u6253\u5F00 codexhost \u8BBE\u7F6E",
19754
20104
  settingsButtonTitle: "codexhost \u8BBE\u7F6E",
19755
20105
  settingsUnavailableTitle: "codexhost \u8BBE\u7F6E\u4E0D\u53EF\u7528",
@@ -19762,7 +20112,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19762
20112
  updateLatestVersion: "\u6700\u65B0\u7248\u672C",
19763
20113
  updateUpToDate: "\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C\u3002",
19764
20114
  updateAvailable: "\u6709\u65B0\u7248\u672C\u53EF\u7528\u3002",
19765
- updateAndRestart: "\u66F4\u65B0\u5E76\u91CD\u542F",
20115
+ updateWindowsManualRequired: "Windows \u6682\u4E0D\u652F\u6301\u81EA\u52A8\u66F4\u65B0\uFF0C\u8BF7\u5728\u4E0B\u65B9\u624B\u52A8\u66F4\u65B0\u3002",
20116
+ updateAndRestart: "\u66F4\u65B0",
19766
20117
  updateChecking: "\u6B63\u5728\u68C0\u67E5\u66F4\u65B0...",
19767
20118
  updateDownloading: "\u6B63\u5728\u4E0B\u8F7D\u66F4\u65B0...",
19768
20119
  updatePreparing: "\u6B63\u5728\u51C6\u5907\u66F4\u65B0...",
@@ -19775,13 +20126,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19775
20126
  updateFailed: "\u66F4\u65B0\u5931\u8D25\u3002",
19776
20127
  updateRetry: "\u91CD\u8BD5",
19777
20128
  updateManualNpmDescription: "\u5982\u9700\u624B\u52A8\u66F4\u65B0\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u3002\u66F4\u65B0\u5B8C\u6210\u540E\uFF0C\u8BF7\u9000\u51FA Codex \u5E76\u901A\u8FC7 codexhost \u91CD\u65B0\u542F\u52A8\u3002",
20129
+ updateWindowsNpmDescription: "Windows \u6682\u4E0D\u652F\u6301\u81EA\u52A8\u66F4\u65B0\u3002\u8BF7\u9000\u51FA codexhost\uFF0C\u5728\u7EC8\u7AEF\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u5B8C\u6210\u66F4\u65B0\u3002",
20130
+ updateWindowsInstallerDescription: "Windows \u6682\u4E0D\u652F\u6301\u81EA\u52A8\u66F4\u65B0\u3002\u8BF7\u4E0B\u8F7D\u5E76\u8FD0\u884C\u9002\u7528\u4E8E\u5F53\u524D\u7CFB\u7EDF\u7684\u5B89\u88C5\u5305\u3002",
20131
+ updateManualTitle: "\u624B\u52A8\u66F4\u65B0",
20132
+ updateManualFallbackDescription: "\u81EA\u52A8\u66F4\u65B0\u672A\u80FD\u5B8C\u6210\uFF0C\u8BF7\u6539\u7528\u4E0B\u5217\u547D\u4EE4\u5728\u7EC8\u7AEF\u624B\u52A8\u66F4\u65B0\u3002\u5B8C\u6210\u540E\u8BF7\u9000\u51FA Codex \u5E76\u901A\u8FC7 codexhost \u91CD\u65B0\u542F\u52A8\u3002",
20133
+ updateCopyCommand: "\u590D\u5236",
20134
+ updateCommandCopied: "\u5DF2\u590D\u5236",
20135
+ updateCopyFailed: "\u590D\u5236\u5931\u8D25",
19778
20136
  updateDownloadFromReleases: "\u524D\u5F80 GitHub Releases \u4E0B\u8F7D",
20137
+ updateDownloadWindowsInstaller: "\u4E0B\u8F7D Windows \u5B89\u88C5\u5305",
20138
+ aboutTagline: "\u5728 Codex Desktop \u4E2D\u8FD0\u884C Pi \u548C\u5176\u4ED6 Harness",
20139
+ aboutParagraphs: Object.freeze([
20140
+ "\u6211\u4EEC\u8BA4\u4E3A Codex Desktop \u63D0\u4F9B\u4E86\u76EE\u524D\u6700\u597D\u7684\u684C\u9762\u5F00\u53D1\u4EA4\u4E92\u4F53\u9A8C\u3002",
20141
+ "\u4F46 Codex \u5E76\u4E0D\u662F\u552F\u4E00\u4F18\u79C0\u7684 Agent Harness\uFF0C\u4E5F\u6709\u4EBA\u504F\u597D Claude Code \u548C Pi Agent\u3002",
20142
+ "codexhost \u8BA9\u4F60\u5728 Codex Desktop \u4E2D\u9009\u62E9\u771F\u6B63\u6267\u884C\u4EFB\u52A1\u7684 Agent\uFF0C\u540C\u65F6\u4FDD\u7559 Codex \u7684\u539F\u751F\u4F53\u9A8C\uFF0C\u5E76\u8BA9\u5B83\u4EEC\u534F\u4F5C\u5B8C\u6210\u4EFB\u52A1\u3002"
20143
+ ]),
20144
+ aboutOpenSource: "codexhost \u662F\u4E00\u4E2A\u5F00\u6E90\u9879\u76EE\uFF0C\u5F00\u6E90\u5730\u5740\uFF1A",
20145
+ aboutStarCallout: "\u2B50 \u5982\u679C\u8FD9\u4E2A\u9879\u76EE\u5BF9\u4F60\u6709\u5E2E\u52A9\uFF0C\u8BF7\u7ED9\u6211\u4EEC\u4E00\u4E2A Star\uFF01\u2B50",
20146
+ aboutRepository: "\u5F00\u6E90\u4ED3\u5E93",
19779
20147
  pageLabels: Object.freeze({
19780
20148
  connections: "\u8FDE\u63A5",
19781
- "model-pool": "\u6A21\u578B\u6C60",
19782
- routes: "\u8DEF\u7531",
19783
- gateway: "\u7F51\u5173",
19784
- updates: "\u66F4\u65B0"
20149
+ updates: "\u66F4\u65B0",
20150
+ about: "\u5173\u4E8E"
19785
20151
  })
19786
20152
  });
19787
20153
  var DEFAULT_RENDERER_SETTINGS_MESSAGES = ENGLISH_MESSAGES;
@@ -19835,6 +20201,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19835
20201
  ["path", { d: "M12 13.5V8" }]
19836
20202
  ];
19837
20203
 
20204
+ // ../../node_modules/lucide/dist/esm/icons/circle-check.mjs
20205
+ var CircleCheck = [
20206
+ ["circle", { cx: "12", cy: "12", r: "10" }],
20207
+ ["path", { d: "m9 12 2 2 4-4" }]
20208
+ ];
20209
+
20210
+ // ../../node_modules/lucide/dist/esm/icons/chevron-left.mjs
20211
+ var ChevronLeft = [["path", { d: "m15 18-6-6 6-6" }]];
20212
+
20213
+ // ../../node_modules/lucide/dist/esm/icons/chevron-right.mjs
20214
+ var ChevronRight = [["path", { d: "m9 18 6-6-6-6" }]];
20215
+
19838
20216
  // ../../node_modules/lucide/dist/esm/icons/circle-off.mjs
19839
20217
  var CircleOff = [
19840
20218
  ["path", { d: "m2 2 20 20" }],
@@ -19862,6 +20240,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19862
20240
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }]
19863
20241
  ];
19864
20242
 
20243
+ // ../../node_modules/lucide/dist/esm/icons/info.mjs
20244
+ var Info = [
20245
+ ["circle", { cx: "12", cy: "12", r: "10" }],
20246
+ ["path", { d: "M12 16v-4" }],
20247
+ ["path", { d: "M12 8h.01" }]
20248
+ ];
20249
+
19865
20250
  // ../../node_modules/lucide/dist/esm/icons/languages.mjs
19866
20251
  var Languages = [
19867
20252
  ["path", { d: "m5 8 6 6" }],
@@ -19935,6 +20320,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19935
20320
  ]
19936
20321
  ];
19937
20322
 
20323
+ // ../../node_modules/lucide/dist/esm/icons/triangle-alert.mjs
20324
+ var TriangleAlert = [
20325
+ ["path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }],
20326
+ ["path", { d: "M12 9v4" }],
20327
+ ["path", { d: "M12 17h.01" }]
20328
+ ];
20329
+
19938
20330
  // ../../node_modules/lucide/dist/esm/icons/x.mjs
19939
20331
  var X = [
19940
20332
  ["path", { d: "M18 6 6 18" }],
@@ -19955,11 +20347,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19955
20347
  "routes",
19956
20348
  "gateway",
19957
20349
  "updates",
20350
+ "about",
19958
20351
  "external-link",
19959
20352
  "refresh",
19960
20353
  "unavailable",
20354
+ "alert",
20355
+ "check",
19961
20356
  "diagnose",
19962
- "copy"
20357
+ "copy",
20358
+ "download",
20359
+ "chevron-left",
20360
+ "chevron-right"
19963
20361
  ];
19964
20362
  var iconNodes = {
19965
20363
  settings: Settings,
@@ -19971,11 +20369,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
19971
20369
  routes: Route,
19972
20370
  gateway: Network,
19973
20371
  updates: Download,
20372
+ about: Info,
19974
20373
  "external-link": ExternalLink,
19975
20374
  refresh: RefreshCw,
19976
20375
  unavailable: CircleOff,
20376
+ alert: TriangleAlert,
20377
+ check: CircleCheck,
19977
20378
  diagnose: Stethoscope,
19978
- copy: Copy
20379
+ copy: Copy,
20380
+ download: Download,
20381
+ "chevron-left": ChevronLeft,
20382
+ "chevron-right": ChevronRight
19979
20383
  };
19980
20384
  function isRendererSettingsIconName(value) {
19981
20385
  return RENDERER_SETTINGS_ICON_NAMES.includes(value);
@@ -20108,101 +20512,650 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
20108
20512
  }
20109
20513
  };
20110
20514
 
20111
- // src/settings/release-notes.ts
20112
- var HEADING_PATTERN = /^(#{1,6})[ \t]+(.+?)\s*$/u;
20113
- var BLOCKQUOTE_PATTERN = /^>[ \t]?(.*?)\s*$/u;
20114
- var UNORDERED_ITEM_PATTERN = /^[-*][ \t]+(.+?)\s*$/u;
20115
- var CONTINUATION_PATTERN = /^[ \t]+(.+?)\s*$/u;
20116
- var ORDERED_ITEM_PATTERN = /^\d+[.)][ \t]+(.+?)\s*$/u;
20117
- var FENCE_PATTERN = /^```([\w+-]*)\s*$/u;
20118
- var THEMATIC_BREAK_PATTERN = /^(?:---|___|\*\*\*)[ \t]*$/u;
20119
- var INLINE_PATTERN = /(`+)((?:(?!\1).)+)\1|\*\*(.+?)\*\*|\[([^\]]+)\]\(([^)\s]+)\)/gu;
20120
- function createReleaseNotesElement(document2, markdown) {
20121
- const root = document2.createElement("div");
20122
- root.className = "settings-update-notes";
20123
- appendReleaseNotesBlocks(document2, root, markdown);
20124
- return root;
20515
+ // src/settings/connections-page.ts
20516
+ var CODEXHOST_GITHUB_ISSUES_NEW_URL = "https://github.com/BytePioneer-AI/codex-host/issues/new";
20517
+ var HARNESS_INSTALL_URLS = Object.freeze({
20518
+ pi: "https://pi.dev/",
20519
+ "claude-code": "https://code.claude.com/docs/en/quickstart",
20520
+ "deepseek-harness": "https://deepseek-harness.github.io/deepseek-harness/",
20521
+ grok: "https://grok.com/",
20522
+ omp: "https://github.com/can1357/oh-my-pi"
20523
+ });
20524
+ function connectionStatusLabel(availability, messages, hasError = false) {
20525
+ if (hasError && availability !== "notInstalled") return messages.connectionStatusError;
20526
+ if (availability === "ready") return messages.connectionStatusReady;
20527
+ if (availability === "checking") return messages.connectionStatusChecking;
20528
+ if (availability === "notInstalled") return messages.connectionStatusNotInstalled;
20529
+ if (availability === "unavailable" || availability === "error") {
20530
+ return availability === "error" ? messages.connectionStatusError : messages.connectionStatusUnavailable;
20531
+ }
20532
+ return availability === "installing" ? messages.connectionStatusInstalling : messages.connectionStatusUnsupported;
20125
20533
  }
20126
- function appendReleaseNotesBlocks(document2, root, markdown) {
20127
- const lines = markdown.replaceAll("\r\n", "\n").split("\n");
20128
- let index = 0;
20129
- while (index < lines.length) {
20130
- const line = lines[index] ?? "";
20131
- if (line.trim().length === 0) {
20132
- index += 1;
20133
- continue;
20134
- }
20135
- const fence = FENCE_PATTERN.exec(line);
20136
- if (fence) {
20137
- index = appendFencedCode(document2, root, lines, index, fence[1] ?? "");
20138
- continue;
20139
- }
20140
- const heading = HEADING_PATTERN.exec(line);
20141
- if (heading?.[1] && heading[2]) {
20142
- const tag = `h${heading[1].length}`;
20143
- const element = document2.createElement(tag);
20144
- appendInline(document2, element, heading[2]);
20145
- root.append(element);
20146
- index += 1;
20147
- continue;
20148
- }
20149
- if (BLOCKQUOTE_PATTERN.test(line)) {
20150
- index = appendBlockquote(document2, root, lines, index);
20151
- continue;
20152
- }
20153
- if (THEMATIC_BREAK_PATTERN.test(line)) {
20154
- root.append(document2.createElement("hr"));
20155
- index += 1;
20156
- continue;
20157
- }
20158
- if (UNORDERED_ITEM_PATTERN.test(line)) {
20159
- index = appendList(document2, root, lines, index, "ul", UNORDERED_ITEM_PATTERN);
20160
- continue;
20161
- }
20162
- if (ORDERED_ITEM_PATTERN.test(line)) {
20163
- index = appendList(document2, root, lines, index, "ol", ORDERED_ITEM_PATTERN);
20164
- continue;
20165
- }
20166
- index = appendParagraph(document2, root, lines, index);
20534
+ function connectionStatusTone(availability, hasError = false) {
20535
+ if (hasError && availability !== "notInstalled") return "failed";
20536
+ if (availability === "ready") return "ready";
20537
+ if (availability === "checking" || availability === "installing") return "checking";
20538
+ if (availability === "notInstalled") return "setup";
20539
+ return "failed";
20540
+ }
20541
+ function diagnosticText(hostId, item) {
20542
+ const error51 = item.error;
20543
+ return [
20544
+ "codexhost connection diagnostics",
20545
+ `host: ${hostId}`,
20546
+ `agent: ${item.name}`,
20547
+ `status: ${item.availability}`,
20548
+ ...error51 ? [
20549
+ `error.code: ${error51.code}`,
20550
+ `error.message: ${error51.message}`,
20551
+ `retryable: ${error51.retryable}`,
20552
+ ...error51.stage ? [`stage: ${error51.stage}`] : [],
20553
+ ...error51.durationMs !== void 0 ? [`durationMs: ${error51.durationMs}`] : [],
20554
+ ...error51.diagnostic ? [`diagnostic: ${error51.diagnostic}`] : [],
20555
+ ...error51.stderrTail ? [`stderr:
20556
+ ${error51.stderrTail}`] : []
20557
+ ] : []
20558
+ ].join("\n");
20559
+ }
20560
+ function detailLine(document2, label, value) {
20561
+ const line = document2.createElement("div");
20562
+ line.className = "settings-connection-detail-line";
20563
+ const name = document2.createElement("span");
20564
+ name.textContent = label;
20565
+ const content = document2.createElement("code");
20566
+ content.textContent = value;
20567
+ line.append(name, content);
20568
+ return line;
20569
+ }
20570
+ function setCopyButtonLabel(button, label) {
20571
+ button.replaceChildren(createRendererSettingsIcon("copy", 16), label);
20572
+ }
20573
+ function showCopyButtonFeedback(button, label, restoreLabel) {
20574
+ setCopyButtonLabel(button, label);
20575
+ button.ownerDocument.defaultView?.setTimeout(() => {
20576
+ setCopyButtonLabel(button, restoreLabel);
20577
+ }, 2e3);
20578
+ }
20579
+ function copyDiagnosticsToClipboard(document2, button, report, messages, restoreLabel) {
20580
+ const clipboard = document2.defaultView?.navigator.clipboard;
20581
+ if (!clipboard) {
20582
+ showCopyButtonFeedback(button, messages.connectionCopyFailed, restoreLabel);
20583
+ return;
20167
20584
  }
20585
+ void clipboard.writeText(report).then(
20586
+ () => showCopyButtonFeedback(button, messages.connectionCopied, restoreLabel),
20587
+ () => showCopyButtonFeedback(button, messages.connectionCopyFailed, restoreLabel)
20588
+ );
20168
20589
  }
20169
- function appendFencedCode(document2, root, lines, start, language) {
20170
- const body = [];
20171
- let index = start + 1;
20172
- while (index < lines.length && !FENCE_PATTERN.test(lines[index] ?? "")) {
20173
- body.push(lines[index] ?? "");
20174
- index += 1;
20590
+ function connectionHostName(hostId, messages) {
20591
+ if (hostId === "local") return messages.connectionLocalHost;
20592
+ const separator = hostId.lastIndexOf(":");
20593
+ const encodedName = separator >= 0 ? hostId.slice(separator + 1) : hostId;
20594
+ try {
20595
+ return decodeURIComponent(encodedName);
20596
+ } catch {
20597
+ return encodedName;
20175
20598
  }
20176
- if (index < lines.length) index += 1;
20177
- const pre = document2.createElement("pre");
20178
- const code = document2.createElement("code");
20179
- if (language.length > 0) code.className = `language-${language}`;
20180
- code.textContent = body.join("\n");
20181
- pre.append(code);
20182
- root.append(pre);
20183
- return index;
20184
20599
  }
20185
- function appendBlockquote(document2, root, lines, start) {
20186
- const blockquote = document2.createElement("blockquote");
20187
- const content = [];
20188
- let index = start;
20189
- while (index < lines.length) {
20190
- const match = BLOCKQUOTE_PATTERN.exec(lines[index] ?? "");
20191
- if (!match) break;
20192
- content.push(match[1] ?? "");
20193
- index += 1;
20600
+ function createHostScrollButton(document2, direction, messages) {
20601
+ const button = document2.createElement("button");
20602
+ button.type = "button";
20603
+ button.className = "settings-connection-host-scroll";
20604
+ button.dataset.connectionHostScroll = direction;
20605
+ const label = direction === "left" ? messages.connectionHostsScrollLeft : messages.connectionHostsScrollRight;
20606
+ button.setAttribute("aria-label", label);
20607
+ button.title = label;
20608
+ button.append(
20609
+ createRendererSettingsIcon(direction === "left" ? "chevron-left" : "chevron-right", 16)
20610
+ );
20611
+ return button;
20612
+ }
20613
+ function configureHostScroller(document2, strip, tabs, left, right) {
20614
+ const maxScrollLeft = () => Math.max(0, (tabs.scrollWidth || 0) - (tabs.clientWidth || 0));
20615
+ const updateButtons = () => {
20616
+ const maximum = maxScrollLeft();
20617
+ strip.dataset.connectionHostOverflow = String(maximum > 1);
20618
+ left.disabled = tabs.scrollLeft <= 1;
20619
+ right.disabled = maximum <= 1 || tabs.scrollLeft >= maximum - 1;
20620
+ };
20621
+ const scroll = (direction) => {
20622
+ const distance = Math.max(180, Math.round((tabs.clientWidth || 250) * 0.72));
20623
+ if (typeof tabs.scrollBy === "function") {
20624
+ tabs.scrollBy({ left: direction * distance, behavior: "smooth" });
20625
+ } else {
20626
+ tabs.scrollLeft += direction * distance;
20627
+ updateButtons();
20628
+ }
20629
+ };
20630
+ const onLeft = () => scroll(-1);
20631
+ const onRight = () => scroll(1);
20632
+ const onWheel = (event) => {
20633
+ const delta = Math.abs(event.deltaX) > Math.abs(event.deltaY) ? event.deltaX : event.deltaY;
20634
+ const maximum = maxScrollLeft();
20635
+ const canScroll = delta < 0 ? tabs.scrollLeft > 1 : tabs.scrollLeft < maximum - 1;
20636
+ if (!delta || maximum <= 1 || !canScroll) return;
20637
+ event.preventDefault();
20638
+ tabs.scrollLeft += delta;
20639
+ };
20640
+ left.addEventListener("click", onLeft);
20641
+ right.addEventListener("click", onRight);
20642
+ tabs.addEventListener("scroll", updateButtons, { passive: true });
20643
+ tabs.addEventListener("wheel", onWheel, { passive: false });
20644
+ const ownerWindow = document2.defaultView;
20645
+ ownerWindow?.addEventListener("resize", updateButtons);
20646
+ ownerWindow?.setTimeout(updateButtons, 0);
20647
+ updateButtons();
20648
+ return () => {
20649
+ left.removeEventListener("click", onLeft);
20650
+ right.removeEventListener("click", onRight);
20651
+ tabs.removeEventListener("scroll", updateButtons);
20652
+ tabs.removeEventListener("wheel", onWheel);
20653
+ ownerWindow?.removeEventListener("resize", updateButtons);
20654
+ };
20655
+ }
20656
+ function createConnectionIdentityIcon(document2, item, size) {
20657
+ const container = document2.createElement("span");
20658
+ container.className = item.agentSnapshot ? "settings-connection-row__mark settings-connection-row__mark--logo" : "settings-connection-row__mark";
20659
+ container.setAttribute("aria-hidden", "true");
20660
+ if (item.agentSnapshot) {
20661
+ container.append(createRendererAgentIcon(item.agentSnapshot.agent, size, document2));
20662
+ } else {
20663
+ container.textContent = "CH";
20194
20664
  }
20195
- const paragraph = document2.createElement("p");
20196
- appendInline(document2, paragraph, content.join(" ").trim());
20197
- blockquote.append(paragraph);
20198
- root.append(blockquote);
20199
- return index;
20665
+ return container;
20200
20666
  }
20201
- function appendList(document2, root, lines, start, tag, pattern) {
20202
- const list = document2.createElement(tag);
20203
- let index = start;
20204
- while (index < lines.length) {
20205
- const item = pattern.exec(lines[index] ?? "");
20667
+ function createConnectionRow(document2, item, messages, selected, select) {
20668
+ const row = document2.createElement("div");
20669
+ row.className = "settings-connection-row";
20670
+ row.dataset.connectionItem = item.key;
20671
+ row.dataset.connectionSelected = String(selected);
20672
+ row.tabIndex = selected ? 0 : -1;
20673
+ row.setAttribute("role", "row");
20674
+ const identity = document2.createElement("div");
20675
+ identity.className = "settings-connection-row__identity";
20676
+ identity.setAttribute("role", "cell");
20677
+ const label = document2.createElement("strong");
20678
+ label.textContent = item.name;
20679
+ identity.append(createConnectionIdentityIcon(document2, item, 19), label);
20680
+ const status = document2.createElement("span");
20681
+ status.className = "settings-connection-row__status";
20682
+ status.dataset.connectionTone = connectionStatusTone(item.availability, item.error !== null);
20683
+ status.setAttribute("role", "cell");
20684
+ status.textContent = connectionStatusLabel(item.availability, messages, item.error !== null);
20685
+ const action = document2.createElement("div");
20686
+ action.className = "settings-connection-row__action";
20687
+ action.setAttribute("role", "cell");
20688
+ if (item.agentSnapshot?.availability === "notInstalled") {
20689
+ const install = document2.createElement("a");
20690
+ install.className = "settings-connection-install-link";
20691
+ install.href = HARNESS_INSTALL_URLS[item.agentSnapshot.agent];
20692
+ install.target = "_blank";
20693
+ install.rel = "noopener noreferrer";
20694
+ install.setAttribute("aria-label", `${messages.connectionOpenInstallation}: ${item.name}`);
20695
+ install.title = messages.connectionOpenInstallation;
20696
+ install.append(createRendererSettingsIcon("download", 17));
20697
+ action.append(install);
20698
+ } else if (item.error) {
20699
+ const viewError = document2.createElement("button");
20700
+ viewError.type = "button";
20701
+ viewError.className = "settings-connection-view-error";
20702
+ viewError.textContent = messages.connectionViewError;
20703
+ viewError.addEventListener("click", (event) => {
20704
+ event.stopPropagation();
20705
+ select();
20706
+ });
20707
+ action.append(viewError);
20708
+ }
20709
+ row.addEventListener("click", (event) => {
20710
+ const target = event.target;
20711
+ if (target?.closest?.("a")) return;
20712
+ select();
20713
+ });
20714
+ row.addEventListener("keydown", (event) => {
20715
+ if (event.key !== "Enter" && event.key !== " ") return;
20716
+ event.preventDefault();
20717
+ select();
20718
+ });
20719
+ row.append(identity, status, action);
20720
+ return row;
20721
+ }
20722
+ function createInspectorHeader(document2, item, messages) {
20723
+ const header = document2.createElement("header");
20724
+ header.className = "settings-connection-inspector__header";
20725
+ const identity = document2.createElement("div");
20726
+ identity.className = "settings-connection-inspector__identity";
20727
+ const title = document2.createElement("strong");
20728
+ title.textContent = item.name;
20729
+ identity.append(createConnectionIdentityIcon(document2, item, 20), title);
20730
+ const status = document2.createElement("span");
20731
+ status.className = "settings-connection-row__status";
20732
+ status.dataset.connectionTone = connectionStatusTone(item.availability, item.error !== null);
20733
+ status.textContent = connectionStatusLabel(item.availability, messages, item.error !== null);
20734
+ header.append(identity, status);
20735
+ return header;
20736
+ }
20737
+ function renderConnectionInspector(document2, inspector, item, hostId, messages) {
20738
+ inspector.replaceChildren(createInspectorHeader(document2, item, messages));
20739
+ const body = document2.createElement("div");
20740
+ body.className = "settings-connection-inspector__body";
20741
+ if (item.agentSnapshot?.availability === "notInstalled") {
20742
+ const callout = document2.createElement("div");
20743
+ callout.className = "settings-connection-install-callout";
20744
+ const icon2 = document2.createElement("span");
20745
+ icon2.className = "settings-connection-install-callout__icon";
20746
+ icon2.append(createRendererSettingsIcon("download", 18));
20747
+ const copy = document2.createElement("div");
20748
+ const title = document2.createElement("strong");
20749
+ title.textContent = `${messages.connectionInstall} ${item.name}`;
20750
+ const description = document2.createElement("p");
20751
+ description.textContent = messages.connectionInstallDescription;
20752
+ copy.append(title, description);
20753
+ callout.append(icon2, copy);
20754
+ const install = document2.createElement("a");
20755
+ install.className = "settings-command-button settings-connection-install-button";
20756
+ install.href = HARNESS_INSTALL_URLS[item.agentSnapshot.agent];
20757
+ install.target = "_blank";
20758
+ install.rel = "noopener noreferrer";
20759
+ install.append(
20760
+ messages.connectionOpenInstallation,
20761
+ createRendererSettingsIcon("external-link", 14)
20762
+ );
20763
+ body.append(callout, install);
20764
+ } else if (item.error) {
20765
+ const summary = document2.createElement("div");
20766
+ summary.className = "settings-connection-error-summary";
20767
+ const title = document2.createElement("strong");
20768
+ title.textContent = messages.connectionErrorTitle;
20769
+ const description = document2.createElement("p");
20770
+ description.textContent = item.error.message;
20771
+ summary.append(title, description);
20772
+ const metadata = document2.createElement("div");
20773
+ metadata.className = "settings-connection-error-metadata";
20774
+ metadata.append(
20775
+ detailLine(document2, messages.connectionErrorCode, item.error.code),
20776
+ detailLine(document2, messages.connectionRetryable, String(item.error.retryable))
20777
+ );
20778
+ if (item.error.stage) {
20779
+ metadata.append(detailLine(document2, messages.connectionFailureStage, item.error.stage));
20780
+ }
20781
+ if (item.error.durationMs !== void 0) {
20782
+ metadata.append(
20783
+ detailLine(document2, messages.connectionDuration, `${item.error.durationMs} ms`)
20784
+ );
20785
+ }
20786
+ if (item.error.diagnostic) {
20787
+ metadata.append(detailLine(document2, messages.connectionDiagnostic, item.error.diagnostic));
20788
+ }
20789
+ const logHeader = document2.createElement("div");
20790
+ logHeader.className = "settings-connection-error-log-header";
20791
+ const logTitle = document2.createElement("strong");
20792
+ logTitle.textContent = messages.connectionErrorLog;
20793
+ const copy = document2.createElement("button");
20794
+ copy.type = "button";
20795
+ copy.className = "settings-command-button settings-command-button--secondary";
20796
+ setCopyButtonLabel(copy, messages.connectionCopyDetails);
20797
+ const report = diagnosticText(hostId, item);
20798
+ copy.addEventListener("click", () => {
20799
+ copyDiagnosticsToClipboard(document2, copy, report, messages, messages.connectionCopyDetails);
20800
+ });
20801
+ logHeader.append(logTitle, copy);
20802
+ const log = document2.createElement("pre");
20803
+ log.className = "settings-connection-stderr";
20804
+ log.textContent = item.error.stderrTail ?? item.error.diagnostic ?? report;
20805
+ const actions = document2.createElement("div");
20806
+ actions.className = "settings-connection-error-actions";
20807
+ const issue2 = document2.createElement("a");
20808
+ issue2.className = "settings-command-button settings-command-button--secondary";
20809
+ issue2.href = CODEXHOST_GITHUB_ISSUES_NEW_URL;
20810
+ issue2.target = "_blank";
20811
+ issue2.rel = "noopener noreferrer";
20812
+ issue2.append(messages.connectionOpenIssue, createRendererSettingsIcon("external-link", 14));
20813
+ actions.append(issue2);
20814
+ const issueNote = document2.createElement("p");
20815
+ issueNote.className = "settings-connection-issue-note";
20816
+ issueNote.textContent = messages.connectionIssueDescription;
20817
+ body.append(summary, metadata, logHeader, log, actions, issueNote);
20818
+ } else {
20819
+ const status = document2.createElement("div");
20820
+ status.className = "settings-connection-state-summary";
20821
+ const title = document2.createElement("strong");
20822
+ title.textContent = connectionStatusLabel(item.availability, messages);
20823
+ const description = document2.createElement("p");
20824
+ description.textContent = item.availability === "ready" ? messages.connectionReadyDescription : messages.connectionUnavailableDescription;
20825
+ status.append(title, description);
20826
+ body.append(status);
20827
+ }
20828
+ inspector.append(body);
20829
+ }
20830
+ function connectionItems(snapshot, host, messages) {
20831
+ return [
20832
+ {
20833
+ key: "renderer-adapter",
20834
+ name: messages.connectionAdapter,
20835
+ availability: snapshot.adapter.state,
20836
+ error: null
20837
+ },
20838
+ ...host.agents.map((agent) => ({
20839
+ key: agent.agent,
20840
+ name: RENDERER_AGENT_LABELS[agent.agent],
20841
+ availability: agent.availability,
20842
+ error: agent.availability === "notInstalled" ? null : agent.error,
20843
+ agentSnapshot: agent
20844
+ }))
20845
+ ];
20846
+ }
20847
+ function createConnectionsSettingsPage(messages, getDiagnostics) {
20848
+ return Object.freeze({
20849
+ id: "connections",
20850
+ label: messages.pageLabels.connections,
20851
+ icon: "connections",
20852
+ mount(context) {
20853
+ const document2 = context.content.ownerDocument;
20854
+ const header = document2.createElement("div");
20855
+ header.className = "settings-connection-page-header";
20856
+ const headingCopy = document2.createElement("div");
20857
+ const heading = document2.createElement("div");
20858
+ heading.className = "settings-section-label";
20859
+ heading.textContent = messages.pageLabels.connections;
20860
+ const description = document2.createElement("p");
20861
+ description.className = "settings-page-description";
20862
+ description.textContent = messages.connectionsDescription;
20863
+ headingCopy.append(heading, description);
20864
+ const refresh = document2.createElement("button");
20865
+ refresh.type = "button";
20866
+ refresh.className = "settings-command-button settings-command-button--secondary";
20867
+ refresh.dataset.connectionAction = "refresh";
20868
+ refresh.append(createRendererSettingsIcon("diagnose", 16), messages.connectionRefresh);
20869
+ header.append(headingCopy, refresh);
20870
+ const content = document2.createElement("div");
20871
+ content.className = "settings-connections-content";
20872
+ context.content.append(header, content);
20873
+ let pending = false;
20874
+ let selectedHostId = null;
20875
+ let selectedItemKey = null;
20876
+ let latestSnapshot = null;
20877
+ let disposeHostScroller = () => void 0;
20878
+ const diagnostics = getDiagnostics();
20879
+ const runRefresh = () => {
20880
+ if (pending || !diagnostics) return;
20881
+ pending = true;
20882
+ refresh.disabled = true;
20883
+ refresh.replaceChildren(
20884
+ createRendererSettingsIcon("diagnose", 16),
20885
+ messages.connectionRefreshing
20886
+ );
20887
+ void context.runLatest(() => diagnostics.refresh(), {
20888
+ success() {
20889
+ pending = false;
20890
+ refresh.disabled = false;
20891
+ refresh.replaceChildren(
20892
+ createRendererSettingsIcon("diagnose", 16),
20893
+ messages.connectionRefresh
20894
+ );
20895
+ render(diagnostics.snapshot());
20896
+ },
20897
+ failure(error51) {
20898
+ pending = false;
20899
+ refresh.disabled = false;
20900
+ refresh.replaceChildren(
20901
+ createRendererSettingsIcon("diagnose", 16),
20902
+ messages.connectionRefresh
20903
+ );
20904
+ const snapshot = diagnostics.snapshot();
20905
+ render({
20906
+ ...snapshot,
20907
+ hosts: snapshot.hosts.map((host) => ({
20908
+ ...host,
20909
+ agents: host.agents.map((agent) => ({
20910
+ ...agent,
20911
+ availability: "error",
20912
+ error: {
20913
+ code: "internalError",
20914
+ message: error51 instanceof Error ? error51.message : String(error51),
20915
+ retryable: true,
20916
+ stage: "request"
20917
+ }
20918
+ }))
20919
+ }))
20920
+ });
20921
+ }
20922
+ });
20923
+ };
20924
+ const render = (snapshot) => {
20925
+ latestSnapshot = snapshot;
20926
+ disposeHostScroller();
20927
+ disposeHostScroller = () => void 0;
20928
+ content.replaceChildren();
20929
+ if (!snapshot) {
20930
+ const empty = document2.createElement("div");
20931
+ empty.className = "settings-empty";
20932
+ empty.textContent = messages.connectionNoRuntime;
20933
+ content.append(empty);
20934
+ return;
20935
+ }
20936
+ const selectedHost = (selectedHostId ? snapshot.hosts.find((host) => host.hostId === selectedHostId) : void 0) ?? snapshot.hosts.find((host) => host.active) ?? snapshot.hosts.find((host) => host.hostId === "local") ?? snapshot.hosts[0];
20937
+ if (!selectedHost) return;
20938
+ selectedHostId = selectedHost.hostId;
20939
+ const layout = document2.createElement("div");
20940
+ layout.className = "settings-connections-layout";
20941
+ const list = document2.createElement("section");
20942
+ list.className = "settings-connection-list";
20943
+ const hostStrip = document2.createElement("div");
20944
+ hostStrip.className = "settings-connection-host-strip";
20945
+ const scrollLeft = createHostScrollButton(document2, "left", messages);
20946
+ const tabs = document2.createElement("div");
20947
+ tabs.className = "settings-connection-host-tabs";
20948
+ tabs.setAttribute("role", "tablist");
20949
+ tabs.setAttribute("aria-label", messages.connectionHosts);
20950
+ const scrollRight = createHostScrollButton(document2, "right", messages);
20951
+ const panelId = "codexhost-settings-connection-host-panel";
20952
+ snapshot.hosts.forEach((host, index) => {
20953
+ const tab = document2.createElement("button");
20954
+ tab.type = "button";
20955
+ tab.className = "settings-connection-host-tab";
20956
+ tab.dataset.connectionHostTab = host.hostId;
20957
+ tab.dataset.connectionHostActive = String(host.active);
20958
+ tab.setAttribute("role", "tab");
20959
+ tab.setAttribute("aria-controls", panelId);
20960
+ tab.setAttribute("aria-selected", String(host.hostId === selectedHost.hostId));
20961
+ tab.tabIndex = host.hostId === selectedHost.hostId ? 0 : -1;
20962
+ const hostName = connectionHostName(host.hostId, messages);
20963
+ tab.textContent = hostName;
20964
+ tab.title = host.active ? `${hostName} \xB7 ${messages.connectionActiveHost}` : hostName;
20965
+ tab.addEventListener("click", () => {
20966
+ selectedHostId = host.hostId;
20967
+ render(latestSnapshot);
20968
+ });
20969
+ tab.addEventListener("keydown", (event) => {
20970
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
20971
+ event.preventDefault();
20972
+ const direction = event.key === "ArrowRight" ? 1 : -1;
20973
+ const next = snapshot.hosts[(index + direction + snapshot.hosts.length) % snapshot.hosts.length];
20974
+ if (!next) return;
20975
+ selectedHostId = next.hostId;
20976
+ render(latestSnapshot);
20977
+ const nextTab = [
20978
+ ...content.querySelectorAll("[data-connection-host-tab]")
20979
+ ].find((candidate) => candidate.dataset.connectionHostTab === next.hostId);
20980
+ nextTab?.focus();
20981
+ });
20982
+ tabs.append(tab);
20983
+ });
20984
+ hostStrip.append(scrollLeft, tabs, scrollRight);
20985
+ const tableHeader = document2.createElement("div");
20986
+ tableHeader.className = "settings-connection-table-header";
20987
+ tableHeader.setAttribute("role", "row");
20988
+ const componentHeading = document2.createElement("span");
20989
+ componentHeading.textContent = messages.connectionComponent;
20990
+ componentHeading.setAttribute("role", "columnheader");
20991
+ const statusHeading = document2.createElement("span");
20992
+ statusHeading.textContent = messages.connectionStatus;
20993
+ statusHeading.setAttribute("role", "columnheader");
20994
+ const actionHeading = document2.createElement("span");
20995
+ actionHeading.setAttribute("aria-hidden", "true");
20996
+ tableHeader.append(componentHeading, statusHeading, actionHeading);
20997
+ const rows = document2.createElement("div");
20998
+ rows.className = "settings-connection-rows";
20999
+ rows.id = panelId;
21000
+ rows.dataset.connectionHost = selectedHost.hostId;
21001
+ rows.setAttribute("role", "rowgroup");
21002
+ const inspector = document2.createElement("aside");
21003
+ inspector.className = "settings-connection-inspector";
21004
+ inspector.setAttribute("aria-live", "polite");
21005
+ const items = connectionItems(snapshot, selectedHost, messages);
21006
+ if (!items.some((item) => item.key === selectedItemKey)) {
21007
+ selectedItemKey = items.find(
21008
+ (item) => item.agentSnapshot?.availability === "notInstalled" || item.error !== null
21009
+ )?.key ?? items[0]?.key ?? null;
21010
+ }
21011
+ const rowElements = /* @__PURE__ */ new Map();
21012
+ const selectItem = (item) => {
21013
+ selectedItemKey = item.key;
21014
+ for (const [key, row] of rowElements) {
21015
+ const selected = key === item.key;
21016
+ row.dataset.connectionSelected = String(selected);
21017
+ row.tabIndex = selected ? 0 : -1;
21018
+ }
21019
+ renderConnectionInspector(document2, inspector, item, selectedHost.hostId, messages);
21020
+ };
21021
+ for (const item of items) {
21022
+ const row = createConnectionRow(
21023
+ document2,
21024
+ item,
21025
+ messages,
21026
+ item.key === selectedItemKey,
21027
+ () => selectItem(item)
21028
+ );
21029
+ rowElements.set(item.key, row);
21030
+ rows.append(row);
21031
+ }
21032
+ const selectedItem = items.find((item) => item.key === selectedItemKey) ?? items[0];
21033
+ if (selectedItem) selectItem(selectedItem);
21034
+ list.append(hostStrip, tableHeader, rows);
21035
+ layout.append(list, inspector);
21036
+ content.append(layout);
21037
+ disposeHostScroller = configureHostScroller(
21038
+ document2,
21039
+ hostStrip,
21040
+ tabs,
21041
+ scrollLeft,
21042
+ scrollRight
21043
+ );
21044
+ const selectedTab = [...tabs.children].find(
21045
+ (child) => child.getAttribute("aria-selected") === "true"
21046
+ );
21047
+ selectedTab?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
21048
+ };
21049
+ render(diagnostics?.snapshot() ?? null);
21050
+ if (!diagnostics) {
21051
+ refresh.disabled = true;
21052
+ return void 0;
21053
+ }
21054
+ refresh.addEventListener("click", runRefresh);
21055
+ const unsubscribe = diagnostics.subscribe(() => render(diagnostics.snapshot()));
21056
+ return () => {
21057
+ disposeHostScroller();
21058
+ unsubscribe();
21059
+ };
21060
+ }
21061
+ });
21062
+ }
21063
+
21064
+ // src/settings/release-notes.ts
21065
+ var HEADING_PATTERN = /^(#{1,6})[ \t]+(.+?)\s*$/u;
21066
+ var BLOCKQUOTE_PATTERN = /^>[ \t]?(.*?)\s*$/u;
21067
+ var UNORDERED_ITEM_PATTERN = /^[-*][ \t]+(.+?)\s*$/u;
21068
+ var CONTINUATION_PATTERN = /^[ \t]+(.+?)\s*$/u;
21069
+ var ORDERED_ITEM_PATTERN = /^\d+[.)][ \t]+(.+?)\s*$/u;
21070
+ var FENCE_PATTERN = /^```([\w+-]*)\s*$/u;
21071
+ var THEMATIC_BREAK_PATTERN = /^(?:---|___|\*\*\*)[ \t]*$/u;
21072
+ var INLINE_PATTERN = /(`+)((?:(?!\1).)+)\1|\*\*(.+?)\*\*|\[([^\]]+)\]\(([^)\s]+)\)/gu;
21073
+ function createReleaseNotesElement(document2, markdown) {
21074
+ const root = document2.createElement("div");
21075
+ root.className = "settings-update-notes";
21076
+ appendReleaseNotesBlocks(document2, root, markdown);
21077
+ return root;
21078
+ }
21079
+ function appendReleaseNotesBlocks(document2, root, markdown) {
21080
+ const lines = markdown.replaceAll("\r\n", "\n").split("\n");
21081
+ let index = 0;
21082
+ while (index < lines.length) {
21083
+ const line = lines[index] ?? "";
21084
+ if (line.trim().length === 0) {
21085
+ index += 1;
21086
+ continue;
21087
+ }
21088
+ const fence = FENCE_PATTERN.exec(line);
21089
+ if (fence) {
21090
+ index = appendFencedCode(document2, root, lines, index, fence[1] ?? "");
21091
+ continue;
21092
+ }
21093
+ const heading = HEADING_PATTERN.exec(line);
21094
+ if (heading?.[1] && heading[2]) {
21095
+ const tag = `h${heading[1].length}`;
21096
+ const element = document2.createElement(tag);
21097
+ appendInline(document2, element, heading[2]);
21098
+ root.append(element);
21099
+ index += 1;
21100
+ continue;
21101
+ }
21102
+ if (BLOCKQUOTE_PATTERN.test(line)) {
21103
+ index = appendBlockquote(document2, root, lines, index);
21104
+ continue;
21105
+ }
21106
+ if (THEMATIC_BREAK_PATTERN.test(line)) {
21107
+ root.append(document2.createElement("hr"));
21108
+ index += 1;
21109
+ continue;
21110
+ }
21111
+ if (UNORDERED_ITEM_PATTERN.test(line)) {
21112
+ index = appendList(document2, root, lines, index, "ul", UNORDERED_ITEM_PATTERN);
21113
+ continue;
21114
+ }
21115
+ if (ORDERED_ITEM_PATTERN.test(line)) {
21116
+ index = appendList(document2, root, lines, index, "ol", ORDERED_ITEM_PATTERN);
21117
+ continue;
21118
+ }
21119
+ index = appendParagraph(document2, root, lines, index);
21120
+ }
21121
+ }
21122
+ function appendFencedCode(document2, root, lines, start, language) {
21123
+ const body = [];
21124
+ let index = start + 1;
21125
+ while (index < lines.length && !FENCE_PATTERN.test(lines[index] ?? "")) {
21126
+ body.push(lines[index] ?? "");
21127
+ index += 1;
21128
+ }
21129
+ if (index < lines.length) index += 1;
21130
+ const pre = document2.createElement("pre");
21131
+ const code = document2.createElement("code");
21132
+ if (language.length > 0) code.className = `language-${language}`;
21133
+ code.textContent = body.join("\n");
21134
+ pre.append(code);
21135
+ root.append(pre);
21136
+ return index;
21137
+ }
21138
+ function appendBlockquote(document2, root, lines, start) {
21139
+ const blockquote = document2.createElement("blockquote");
21140
+ const content = [];
21141
+ let index = start;
21142
+ while (index < lines.length) {
21143
+ const match = BLOCKQUOTE_PATTERN.exec(lines[index] ?? "");
21144
+ if (!match) break;
21145
+ content.push(match[1] ?? "");
21146
+ index += 1;
21147
+ }
21148
+ const paragraph = document2.createElement("p");
21149
+ appendInline(document2, paragraph, content.join(" ").trim());
21150
+ blockquote.append(paragraph);
21151
+ root.append(blockquote);
21152
+ return index;
21153
+ }
21154
+ function appendList(document2, root, lines, start, tag, pattern) {
21155
+ const list = document2.createElement(tag);
21156
+ let index = start;
21157
+ while (index < lines.length) {
21158
+ const item = pattern.exec(lines[index] ?? "");
20206
21159
  if (!item?.[1]) break;
20207
21160
  const entry = document2.createElement("li");
20208
21161
  appendInline(document2, entry, item[1]);
@@ -20265,424 +21218,107 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
20265
21218
  const link = document2.createElement("a");
20266
21219
  link.textContent = match[4] ?? "";
20267
21220
  link.setAttribute("href", href);
20268
- link.setAttribute("target", "_blank");
20269
- link.setAttribute("rel", "noopener noreferrer");
20270
- parent.append(link);
20271
- }
20272
- }
20273
- lastIndex = index + match[0].length;
20274
- }
20275
- if (lastIndex < text.length) parent.append(text.slice(lastIndex));
20276
- }
20277
- function isSafeLink(href) {
20278
- try {
20279
- const url2 = new URL(href, "https://codexhost.invalid");
20280
- return url2.protocol === "http:" || url2.protocol === "https:";
20281
- } catch {
20282
- return false;
20283
- }
20284
- }
20285
-
20286
- // src/settings/update-request.ts
20287
- var RENDERER_UPDATE_REQUEST_TIMEOUT_MS = 15e3;
20288
- var RendererUpdateRequestTimeoutError = class extends Error {
20289
- constructor() {
20290
- super("Update request timed out");
20291
- this.name = "RendererUpdateRequestTimeoutError";
20292
- }
20293
- };
20294
- function runBoundedRendererUpdateRequest(operation, signal, timeoutMs = RENDERER_UPDATE_REQUEST_TIMEOUT_MS) {
20295
- return new Promise((resolve, reject) => {
20296
- let settled = false;
20297
- const settle = (handler) => {
20298
- if (settled) return;
20299
- settled = true;
20300
- clearTimeout(timeout);
20301
- signal.removeEventListener("abort", abort);
20302
- handler();
20303
- };
20304
- const timeout = setTimeout(() => {
20305
- settle(() => reject(new RendererUpdateRequestTimeoutError()));
20306
- }, timeoutMs);
20307
- const abort = () => {
20308
- settle(() => reject(new Error("Update request was aborted")));
20309
- };
20310
- const rejectRequest = (error51) => {
20311
- settle(() => reject(error51));
20312
- };
20313
- if (signal.aborted) {
20314
- abort();
20315
- return;
20316
- }
20317
- signal.addEventListener("abort", abort, { once: true });
20318
- try {
20319
- void operation().then(
20320
- (value) => settle(() => resolve(value)),
20321
- (error51) => rejectRequest(error51)
20322
- );
20323
- } catch (error51) {
20324
- rejectRequest(error51);
20325
- }
20326
- });
20327
- }
20328
-
20329
- // src/settings/pages.ts
20330
- var CODEXHOST_RELEASES_LATEST_URL = "https://github.com/BytePioneer-AI/codex-host/releases/latest";
20331
- var CODEXHOST_NPM_MANUAL_UPDATE_COMMAND = "npm install -g @codexhost/cli@latest";
20332
- var DEFAULT_RENDERER_SETTINGS_PAGE_IDS = [
20333
- "connections",
20334
- "model-pool",
20335
- "routes",
20336
- "gateway",
20337
- "updates"
20338
- ];
20339
- function appendUnavailableStatus(content, messages) {
20340
- const status = content.ownerDocument.createElement("div");
20341
- status.className = "settings-empty";
20342
- const copy = content.ownerDocument.createElement("div");
20343
- const title = content.ownerDocument.createElement("strong");
20344
- title.textContent = messages.inDevelopment;
20345
- copy.append(title);
20346
- status.append(copy);
20347
- content.append(status);
20348
- }
20349
- function unavailablePage(id, messages) {
20350
- return Object.freeze({
20351
- id,
20352
- label: messages.pageLabels[id],
20353
- icon: id,
20354
- mount(context) {
20355
- appendUnavailableStatus(context.content, messages);
20356
- return void 0;
20357
- }
20358
- });
20359
- }
20360
- function connectionStatusLabel(availability, messages) {
20361
- if (availability === "ready") return messages.connectionStatusReady;
20362
- if (availability === "checking") return messages.connectionStatusChecking;
20363
- if (availability === "notInstalled") return messages.connectionStatusNotInstalled;
20364
- if (availability === "unavailable" || availability === "error") {
20365
- return availability === "error" ? messages.connectionStatusError : messages.connectionStatusUnavailable;
20366
- }
20367
- return availability === "installing" ? messages.connectionStatusInstalling : messages.connectionStatusUnsupported;
20368
- }
20369
- function connectionStatusTone(availability) {
20370
- if (availability === "ready") return "ready";
20371
- if (availability === "checking" || availability === "installing") return "checking";
20372
- return "failed";
20373
- }
20374
- function diagnosticText(hostId, name, snapshot) {
20375
- const error51 = snapshot.error;
20376
- const lines = [
20377
- "codexhost connection diagnostics",
20378
- `host: ${hostId}`,
20379
- `agent: ${name}`,
20380
- `status: ${snapshot.availability}`,
20381
- ...error51 ? [
20382
- `error.code: ${error51.code}`,
20383
- `error.message: ${error51.message}`,
20384
- `retryable: ${error51.retryable}`,
20385
- ...error51.stage ? [`stage: ${error51.stage}`] : [],
20386
- ...error51.durationMs !== void 0 ? [`durationMs: ${error51.durationMs}`] : [],
20387
- ...error51.diagnostic ? [`diagnostic: ${error51.diagnostic}`] : [],
20388
- ...error51.stderrTail ? [`stderr:
20389
- ${error51.stderrTail}`] : []
20390
- ] : []
20391
- ];
20392
- return lines.join("\n");
20393
- }
20394
- function detailLine(document2, label, value) {
20395
- const line = document2.createElement("div");
20396
- line.className = "settings-connection-detail-line";
20397
- const name = document2.createElement("span");
20398
- name.textContent = label;
20399
- const content = document2.createElement("code");
20400
- content.textContent = value;
20401
- line.append(name, content);
20402
- return line;
20403
- }
20404
- function setCopyButtonLabel(button, label) {
20405
- button.replaceChildren(createRendererSettingsIcon("copy", 16), label);
20406
- }
20407
- function showCopyButtonFeedback(button, label, restoreLabel) {
20408
- setCopyButtonLabel(button, label);
20409
- button.ownerDocument.defaultView?.setTimeout(() => {
20410
- setCopyButtonLabel(button, restoreLabel);
20411
- }, 2e3);
20412
- }
20413
- function copyDiagnosticsToClipboard(document2, button, report, messages, restoreLabel) {
20414
- const clipboard = document2.defaultView?.navigator.clipboard;
20415
- if (!clipboard) {
20416
- showCopyButtonFeedback(button, messages.connectionCopyFailed, restoreLabel);
20417
- return;
20418
- }
20419
- void clipboard.writeText(report).then(
20420
- () => showCopyButtonFeedback(button, messages.connectionCopied, restoreLabel),
20421
- () => showCopyButtonFeedback(button, messages.connectionCopyFailed, restoreLabel)
20422
- );
20423
- }
20424
- function appendConnectionRow(document2, parent, name, availability, detail, error51, messages, rowAttribute, diagnosticSnapshot, diagnosticHostId) {
20425
- const row = document2.createElement("div");
20426
- row.className = "settings-connection-row";
20427
- if (rowAttribute) row.dataset.connectionAgent = rowAttribute;
20428
- const identity = document2.createElement("div");
20429
- identity.className = "settings-connection-row__identity";
20430
- const dot = document2.createElement("span");
20431
- dot.className = "settings-connection-row__dot";
20432
- dot.dataset.connectionTone = connectionStatusTone(availability);
20433
- dot.setAttribute("aria-hidden", "true");
20434
- const label = document2.createElement("strong");
20435
- label.textContent = name;
20436
- identity.append(dot, label);
20437
- const status = document2.createElement("span");
20438
- status.className = "settings-status-badge";
20439
- status.dataset.connectionTone = connectionStatusTone(availability);
20440
- status.textContent = connectionStatusLabel(availability, messages);
20441
- const detailElement = document2.createElement("div");
20442
- detailElement.className = "settings-connection-row__detail";
20443
- const summary = document2.createElement("span");
20444
- summary.className = "settings-connection-row__reason";
20445
- summary.textContent = error51 ? `${messages.connectionReason}: ${error51.code}: ${error51.message}` : detail ? `${messages.connectionReason}: ${detail}` : "";
20446
- detailElement.append(summary);
20447
- let toggle = null;
20448
- if (error51) {
20449
- toggle = document2.createElement("button");
20450
- toggle.type = "button";
20451
- toggle.className = "settings-connection-details-toggle";
20452
- toggle.textContent = messages.connectionViewDetails;
20453
- toggle.setAttribute("aria-expanded", "true");
20454
- detailElement.append(toggle);
20455
- }
20456
- const details = document2.createElement("div");
20457
- details.className = "settings-connection-details";
20458
- details.hidden = !error51;
20459
- if (error51) {
20460
- details.append(
20461
- detailLine(document2, messages.connectionErrorCode, error51.code),
20462
- detailLine(document2, messages.connectionErrorMessage, error51.message),
20463
- detailLine(document2, messages.connectionRetryable, String(error51.retryable))
20464
- );
20465
- if (error51.stage)
20466
- details.append(detailLine(document2, messages.connectionFailureStage, error51.stage));
20467
- if (error51.durationMs !== void 0) {
20468
- details.append(detailLine(document2, messages.connectionDuration, `${error51.durationMs} ms`));
20469
- }
20470
- if (error51.diagnostic)
20471
- details.append(detailLine(document2, messages.connectionDiagnostic, error51.diagnostic));
20472
- if (error51.stderrTail) {
20473
- const stderr = document2.createElement("pre");
20474
- stderr.className = "settings-connection-stderr";
20475
- stderr.textContent = error51.stderrTail;
20476
- details.append(stderr);
20477
- }
20478
- const copy = document2.createElement("button");
20479
- copy.type = "button";
20480
- copy.className = "settings-command-button settings-command-button--secondary";
20481
- setCopyButtonLabel(copy, messages.connectionCopyDetails);
20482
- copy.addEventListener("click", () => {
20483
- if (!diagnosticSnapshot) return;
20484
- copyDiagnosticsToClipboard(
20485
- document2,
20486
- copy,
20487
- diagnosticText(diagnosticHostId ?? "unknown", name, diagnosticSnapshot),
20488
- messages,
20489
- messages.connectionCopyDetails
20490
- );
20491
- });
20492
- details.append(copy);
20493
- }
20494
- if (toggle) {
20495
- toggle.addEventListener("click", () => {
20496
- details.hidden = !details.hidden;
20497
- toggle?.setAttribute("aria-expanded", String(!details.hidden));
20498
- });
21221
+ link.setAttribute("target", "_blank");
21222
+ link.setAttribute("rel", "noopener noreferrer");
21223
+ parent.append(link);
21224
+ }
21225
+ }
21226
+ lastIndex = index + match[0].length;
20499
21227
  }
20500
- row.append(identity, status, detailElement, details);
20501
- parent.append(row);
21228
+ if (lastIndex < text.length) parent.append(text.slice(lastIndex));
20502
21229
  }
20503
- function connectionHostLabel(hostId, active, messages) {
20504
- const activeLabel = active ? ` \xB7 ${messages.connectionActiveHost}` : "";
20505
- if (hostId === "local") return `${messages.connectionLocalHost}${activeLabel}`;
20506
- const separator = hostId.lastIndexOf(":");
20507
- const encodedName = separator >= 0 ? hostId.slice(separator + 1) : hostId;
20508
- let name = encodedName;
21230
+ function isSafeLink(href) {
20509
21231
  try {
20510
- name = decodeURIComponent(encodedName);
21232
+ const url2 = new URL(href, "https://codexhost.invalid");
21233
+ return url2.protocol === "http:" || url2.protocol === "https:";
20511
21234
  } catch {
21235
+ return false;
20512
21236
  }
20513
- return `${messages.connectionRemoteHost}: ${name}${activeLabel}`;
20514
21237
  }
20515
- function connectionsPage(messages, getDiagnostics) {
20516
- return Object.freeze({
20517
- id: "connections",
20518
- label: messages.pageLabels.connections,
20519
- icon: "connections",
20520
- mount(context) {
20521
- const document2 = context.content.ownerDocument;
20522
- const heading = document2.createElement("div");
20523
- heading.className = "settings-section-label";
20524
- heading.textContent = messages.pageLabels.connections;
20525
- const description = document2.createElement("p");
20526
- description.className = "settings-page-description";
20527
- description.textContent = messages.connectionsDescription;
20528
- const actions = document2.createElement("div");
20529
- actions.className = "settings-connection-actions";
20530
- const refresh = document2.createElement("button");
20531
- refresh.type = "button";
20532
- refresh.className = "settings-command-button settings-command-button--secondary";
20533
- refresh.dataset.connectionAction = "refresh";
20534
- refresh.append(createRendererSettingsIcon("diagnose", 16), messages.connectionRefresh);
20535
- const copyAll = document2.createElement("button");
20536
- copyAll.type = "button";
20537
- copyAll.className = "settings-command-button settings-command-button--secondary";
20538
- copyAll.dataset.connectionAction = "copy-all";
20539
- copyAll.append(createRendererSettingsIcon("copy", 16), messages.connectionCopyAll);
20540
- actions.append(refresh, copyAll);
20541
- const content = document2.createElement("div");
20542
- content.className = "settings-connection-list";
20543
- context.content.append(heading, description, actions, content);
20544
- let pending = false;
20545
- let selectedHostId = "local";
20546
- let latestSnapshot = null;
20547
- const render = (snapshot) => {
20548
- latestSnapshot = snapshot;
20549
- content.replaceChildren();
20550
- if (!snapshot) {
20551
- const empty = document2.createElement("div");
20552
- empty.className = "settings-empty";
20553
- empty.textContent = messages.connectionNoRuntime;
20554
- content.append(empty);
20555
- return;
20556
- }
20557
- appendConnectionRow(
20558
- document2,
20559
- content,
20560
- messages.connectionAdapter,
20561
- snapshot.adapter.state,
20562
- `reason=${snapshot.adapter.reason}, hook=${snapshot.adapter.hook ?? "none"}`,
20563
- null,
20564
- messages,
20565
- "renderer-adapter"
20566
- );
20567
- const selectedHost = snapshot.hosts.find((host) => host.hostId === selectedHostId) ?? snapshot.hosts.find((host) => host.hostId === "local") ?? snapshot.hosts[0];
20568
- if (!selectedHost) return;
20569
- selectedHostId = selectedHost.hostId;
20570
- const tabs = document2.createElement("div");
20571
- tabs.className = "settings-connection-host-tabs";
20572
- tabs.setAttribute("role", "tablist");
20573
- tabs.setAttribute("aria-label", messages.connectionHosts);
20574
- const hostSection = document2.createElement("section");
20575
- hostSection.className = "settings-connection-host";
20576
- hostSection.dataset.connectionHost = selectedHost.hostId;
20577
- hostSection.setAttribute("role", "tabpanel");
20578
- const panelId = "codexhost-settings-connection-host-panel";
20579
- hostSection.id = panelId;
20580
- for (const host of snapshot.hosts) {
20581
- const tab = document2.createElement("button");
20582
- tab.type = "button";
20583
- tab.className = "settings-connection-host-tab";
20584
- tab.dataset.connectionHostTab = host.hostId;
20585
- tab.setAttribute("role", "tab");
20586
- tab.setAttribute("aria-controls", panelId);
20587
- tab.setAttribute("aria-selected", String(host.hostId === selectedHost.hostId));
20588
- tab.tabIndex = host.hostId === selectedHost.hostId ? 0 : -1;
20589
- tab.textContent = connectionHostLabel(host.hostId, host.active, messages);
20590
- tab.addEventListener("click", () => {
20591
- selectedHostId = host.hostId;
20592
- render(latestSnapshot);
20593
- });
20594
- tabs.append(tab);
20595
- }
20596
- for (const agent of selectedHost.agents) {
20597
- appendConnectionRow(
20598
- document2,
20599
- hostSection,
20600
- RENDERER_AGENT_LABELS[agent.agent],
20601
- agent.availability,
20602
- null,
20603
- agent.error,
20604
- messages,
20605
- agent.agent,
20606
- agent,
20607
- selectedHost.hostId
20608
- );
20609
- }
20610
- content.append(tabs, hostSection);
20611
- };
20612
- const diagnostics = getDiagnostics();
20613
- render(diagnostics?.snapshot() ?? null);
20614
- if (!diagnostics) {
20615
- copyAll.disabled = true;
20616
- return void 0;
20617
- }
20618
- copyAll.addEventListener("click", () => {
20619
- const snapshot = diagnostics.snapshot();
20620
- const report = snapshot.hosts.flatMap(
20621
- (host) => host.agents.map(
20622
- (agent) => diagnosticText(host.hostId, RENDERER_AGENT_LABELS[agent.agent], agent)
20623
- )
20624
- ).join("\n\n");
20625
- copyDiagnosticsToClipboard(document2, copyAll, report, messages, messages.connectionCopyAll);
20626
- });
20627
- const unsubscribe = diagnostics.subscribe(() => render(diagnostics.snapshot()));
20628
- refresh.addEventListener("click", () => {
20629
- if (pending) return;
20630
- pending = true;
20631
- refresh.disabled = true;
20632
- refresh.replaceChildren(
20633
- createRendererSettingsIcon("diagnose", 16),
20634
- messages.connectionRefreshing
20635
- );
20636
- void context.runLatest(() => diagnostics.refresh(), {
20637
- success() {
20638
- pending = false;
20639
- refresh.disabled = false;
20640
- refresh.replaceChildren(
20641
- createRendererSettingsIcon("diagnose", 16),
20642
- messages.connectionRefresh
20643
- );
20644
- render(diagnostics.snapshot());
20645
- },
20646
- failure(error51) {
20647
- pending = false;
20648
- refresh.disabled = false;
20649
- refresh.replaceChildren(
20650
- createRendererSettingsIcon("diagnose", 16),
20651
- messages.connectionRefresh
20652
- );
20653
- const snapshot = diagnostics.snapshot();
20654
- render({
20655
- ...snapshot,
20656
- hosts: snapshot.hosts.map((host) => ({
20657
- ...host,
20658
- agents: host.agents.map((agent) => ({
20659
- ...agent,
20660
- availability: "error",
20661
- error: {
20662
- code: "internalError",
20663
- message: error51 instanceof Error ? error51.message : String(error51),
20664
- retryable: true,
20665
- stage: "request"
20666
- }
20667
- }))
20668
- }))
20669
- });
20670
- }
20671
- });
20672
- });
20673
- return unsubscribe;
21238
+
21239
+ // src/settings/update-request.ts
21240
+ var RENDERER_UPDATE_REQUEST_TIMEOUT_MS = 15e3;
21241
+ var RendererUpdateRequestTimeoutError = class extends Error {
21242
+ constructor() {
21243
+ super("Update request timed out");
21244
+ this.name = "RendererUpdateRequestTimeoutError";
21245
+ }
21246
+ };
21247
+ function runBoundedRendererUpdateRequest(operation, signal, timeoutMs = RENDERER_UPDATE_REQUEST_TIMEOUT_MS) {
21248
+ return new Promise((resolve, reject) => {
21249
+ let settled = false;
21250
+ const settle = (handler) => {
21251
+ if (settled) return;
21252
+ settled = true;
21253
+ clearTimeout(timeout);
21254
+ signal.removeEventListener("abort", abort);
21255
+ handler();
21256
+ };
21257
+ const timeout = setTimeout(() => {
21258
+ settle(() => reject(new RendererUpdateRequestTimeoutError()));
21259
+ }, timeoutMs);
21260
+ const abort = () => {
21261
+ settle(() => reject(new Error("Update request was aborted")));
21262
+ };
21263
+ const rejectRequest = (error51) => {
21264
+ settle(() => reject(error51));
21265
+ };
21266
+ if (signal.aborted) {
21267
+ abort();
21268
+ return;
21269
+ }
21270
+ signal.addEventListener("abort", abort, { once: true });
21271
+ try {
21272
+ void operation().then(
21273
+ (value) => settle(() => resolve(value)),
21274
+ (error51) => rejectRequest(error51)
21275
+ );
21276
+ } catch (error51) {
21277
+ rejectRequest(error51);
20674
21278
  }
20675
21279
  });
20676
21280
  }
20677
- function versionRow(context, label, version2) {
20678
- const row = context.content.ownerDocument.createElement("div");
20679
- row.className = "settings-update-version-row";
20680
- const name = context.content.ownerDocument.createElement("span");
20681
- name.textContent = label;
20682
- const value = context.content.ownerDocument.createElement("strong");
20683
- value.textContent = `v${version2}`;
20684
- row.append(name, value);
20685
- return row;
21281
+
21282
+ // src/settings/pages.ts
21283
+ var CODEXHOST_GITHUB_REPOSITORY_URL = "https://github.com/BytePioneer-AI/codex-host";
21284
+ var CODEXHOST_RELEASES_LATEST_URL = `${CODEXHOST_GITHUB_REPOSITORY_URL}/releases/latest`;
21285
+ var CODEXHOST_NPM_MANUAL_UPDATE_COMMAND = "npm install -g @codexhost/cli@latest";
21286
+ function rendererUserAgentData(navigator2) {
21287
+ return navigator2.userAgentData;
21288
+ }
21289
+ function isWindowsRenderer(window2) {
21290
+ const navigator2 = window2?.navigator;
21291
+ if (!navigator2) return false;
21292
+ const identity = `${rendererUserAgentData(navigator2)?.platform ?? ""} ${navigator2.platform ?? ""} ${navigator2.userAgent}`;
21293
+ return /windows|win32|win64/iu.test(identity);
21294
+ }
21295
+ function windowsInstallerDownloadUrl(window2, version2) {
21296
+ const navigator2 = window2?.navigator;
21297
+ const hints = navigator2 ? rendererUserAgentData(navigator2) : void 0;
21298
+ const identity = `${hints?.architecture ?? ""} ${hints?.platform ?? ""} ${navigator2?.platform ?? ""} ${navigator2?.userAgent ?? ""}`;
21299
+ const architecture = /arm64|aarch64|\barm\b/iu.test(identity) ? "arm64" : "x64";
21300
+ return `https://github.com/BytePioneer-AI/codex-host/releases/download/v${version2}/codexhost-${version2}-windows-${architecture}.exe`;
21301
+ }
21302
+ function panelIconName(view) {
21303
+ if (view === "failed" || view === "error") return "alert";
21304
+ if (view === "unavailable") return "unavailable";
21305
+ if (view === "current") return "check";
21306
+ return "updates";
21307
+ }
21308
+ function createPanelHead(document2, view, title) {
21309
+ const head = document2.createElement("div");
21310
+ head.className = "settings-update-panel__head";
21311
+ const label = document2.createElement("strong");
21312
+ label.className = "settings-update-panel__title";
21313
+ label.textContent = title;
21314
+ head.append(createRendererSettingsIcon(panelIconName(view), 16), label);
21315
+ return head;
21316
+ }
21317
+ function createPanelActions(document2, ...buttons) {
21318
+ const actions = document2.createElement("div");
21319
+ actions.className = "settings-update-actions";
21320
+ actions.append(...buttons);
21321
+ return actions;
20686
21322
  }
20687
21323
  function installationLabel(installation, messages) {
20688
21324
  if (installation === "npm") return messages.updateInstallationNpm;
@@ -20719,6 +21355,57 @@ ${error51.stderrTail}`] : []
20719
21355
  }
20720
21356
  return `${scaled.toFixed(scaled >= 10 ? 0 : 1)} ${unit}`;
20721
21357
  }
21358
+ function aboutPage(messages) {
21359
+ return Object.freeze({
21360
+ id: "about",
21361
+ label: messages.pageLabels.about,
21362
+ icon: "about",
21363
+ mount(context) {
21364
+ const document2 = context.content.ownerDocument;
21365
+ const heading = document2.createElement("div");
21366
+ heading.className = "settings-section-label";
21367
+ heading.textContent = messages.pageLabels.about;
21368
+ const panel = document2.createElement("section");
21369
+ panel.className = "settings-about-panel";
21370
+ const product = document2.createElement("strong");
21371
+ product.className = "settings-about-product";
21372
+ product.textContent = "CodexHost";
21373
+ const tagline = document2.createElement("strong");
21374
+ tagline.className = "settings-about-tagline";
21375
+ tagline.textContent = messages.aboutTagline;
21376
+ const introduction = document2.createElement("div");
21377
+ introduction.className = "settings-about-copy";
21378
+ for (const paragraphText of messages.aboutParagraphs) {
21379
+ const paragraph = document2.createElement("p");
21380
+ paragraph.textContent = paragraphText;
21381
+ introduction.append(paragraph);
21382
+ }
21383
+ const starCallout = document2.createElement("p");
21384
+ starCallout.className = "settings-about-star-callout";
21385
+ starCallout.textContent = messages.aboutStarCallout;
21386
+ const repositorySection = document2.createElement("div");
21387
+ repositorySection.className = "settings-about-repository";
21388
+ const openSource = document2.createElement("p");
21389
+ openSource.textContent = messages.aboutOpenSource;
21390
+ const repository = document2.createElement("a");
21391
+ repository.className = "settings-about-repository-link";
21392
+ repository.href = CODEXHOST_GITHUB_REPOSITORY_URL;
21393
+ repository.target = "_blank";
21394
+ repository.rel = "noopener noreferrer";
21395
+ const repositoryUrl = document2.createElement("code");
21396
+ repositoryUrl.textContent = CODEXHOST_GITHUB_REPOSITORY_URL;
21397
+ repository.append(
21398
+ createRendererSettingsIcon("external-link", 14),
21399
+ messages.aboutRepository,
21400
+ repositoryUrl
21401
+ );
21402
+ repositorySection.append(openSource, repository);
21403
+ panel.append(product, tagline, introduction, starCallout, repositorySection);
21404
+ context.content.append(heading, panel);
21405
+ return void 0;
21406
+ }
21407
+ });
21408
+ }
20722
21409
  function updatesPage(messages, getClient) {
20723
21410
  return Object.freeze({
20724
21411
  id: "updates",
@@ -20726,37 +21413,90 @@ ${error51.stderrTail}`] : []
20726
21413
  icon: "updates",
20727
21414
  mount(context) {
20728
21415
  const document2 = context.content.ownerDocument;
21416
+ const windows = isWindowsRenderer(document2.defaultView);
20729
21417
  const heading = document2.createElement("div");
20730
21418
  heading.className = "settings-section-label";
20731
21419
  heading.textContent = messages.pageLabels.updates;
20732
21420
  const metadata = document2.createElement("div");
20733
21421
  metadata.className = "settings-update-metadata";
20734
- const currentVersion = document2.createElement("div");
20735
- currentVersion.className = "settings-update-metadata__item";
20736
- const currentVersionLabel = document2.createElement("span");
20737
- currentVersionLabel.textContent = messages.updateCurrentVersion;
20738
- const currentVersionValue = document2.createElement("strong");
20739
- currentVersionValue.textContent = "-";
20740
- currentVersion.append(currentVersionLabel, currentVersionValue);
20741
- const installation = document2.createElement("div");
20742
- installation.className = "settings-update-metadata__item";
20743
- const installationName = document2.createElement("span");
20744
- installationName.textContent = messages.updateInstallation;
20745
- const installationValue = document2.createElement("strong");
20746
- installationValue.textContent = "-";
20747
- installation.append(installationName, installationValue);
20748
- metadata.append(currentVersion, installation);
21422
+ const createMetadataItem = (label) => {
21423
+ const item = document2.createElement("div");
21424
+ item.className = "settings-update-metadata__item";
21425
+ const name = document2.createElement("span");
21426
+ name.textContent = label;
21427
+ const value = document2.createElement("strong");
21428
+ value.textContent = "-";
21429
+ item.append(name, value);
21430
+ metadata.append(item);
21431
+ return value;
21432
+ };
21433
+ const currentVersionValue = createMetadataItem(messages.updateCurrentVersion);
21434
+ const latestVersionValue = createMetadataItem(messages.updateLatestVersion);
21435
+ const installationValue = createMetadataItem(messages.updateInstallation);
20749
21436
  const panel = document2.createElement("section");
20750
21437
  panel.className = "settings-update-panel";
20751
21438
  panel.setAttribute("aria-live", "polite");
21439
+ const controls = document2.createElement("div");
21440
+ controls.className = "settings-update-controls";
21441
+ const manualTitle = document2.createElement("div");
21442
+ manualTitle.className = "settings-update-manual-title";
21443
+ manualTitle.textContent = messages.updateManualTitle;
20752
21444
  const manualNpm = document2.createElement("div");
20753
21445
  manualNpm.className = "settings-update-manual";
20754
21446
  manualNpm.hidden = true;
20755
- const manualNpmDescription = document2.createElement("span");
21447
+ const manualNpmDescription = document2.createElement("p");
21448
+ manualNpmDescription.className = "settings-update-manual-description";
20756
21449
  manualNpmDescription.textContent = messages.updateManualNpmDescription;
21450
+ const manualNpmCommandRow = document2.createElement("div");
21451
+ manualNpmCommandRow.className = "settings-update-command";
20757
21452
  const manualNpmCommand = document2.createElement("code");
20758
21453
  manualNpmCommand.textContent = CODEXHOST_NPM_MANUAL_UPDATE_COMMAND;
20759
- manualNpm.append(manualNpmDescription, manualNpmCommand);
21454
+ const copyCommand = document2.createElement("button");
21455
+ copyCommand.type = "button";
21456
+ copyCommand.className = "settings-update-command__copy";
21457
+ const setCopyLabel = (label) => {
21458
+ copyCommand.replaceChildren(createRendererSettingsIcon("copy", 14), label);
21459
+ };
21460
+ setCopyLabel(messages.updateCopyCommand);
21461
+ copyCommand.addEventListener("click", () => {
21462
+ const clipboard = document2.defaultView?.navigator.clipboard;
21463
+ const restore = (label) => {
21464
+ setCopyLabel(label);
21465
+ document2.defaultView?.setTimeout(() => setCopyLabel(messages.updateCopyCommand), 2e3);
21466
+ };
21467
+ if (!clipboard) {
21468
+ restore(messages.updateCopyFailed);
21469
+ return;
21470
+ }
21471
+ void clipboard.writeText(CODEXHOST_NPM_MANUAL_UPDATE_COMMAND).then(
21472
+ () => restore(messages.updateCommandCopied),
21473
+ () => restore(messages.updateCopyFailed)
21474
+ );
21475
+ });
21476
+ manualNpmCommandRow.append(manualNpmCommand, copyCommand);
21477
+ manualNpm.append(manualNpmDescription, manualNpmCommandRow);
21478
+ const manualWindowsInstaller = document2.createElement("div");
21479
+ manualWindowsInstaller.className = "settings-update-manual";
21480
+ manualWindowsInstaller.hidden = true;
21481
+ const manualWindowsInstallerDescription = document2.createElement("p");
21482
+ manualWindowsInstallerDescription.className = "settings-update-manual-description";
21483
+ manualWindowsInstallerDescription.textContent = messages.updateWindowsInstallerDescription;
21484
+ const manualWindowsInstallerActions = document2.createElement("div");
21485
+ manualWindowsInstallerActions.className = "settings-update-actions";
21486
+ const manualWindowsInstallerLink = document2.createElement("a");
21487
+ manualWindowsInstallerLink.className = "settings-update-link";
21488
+ manualWindowsInstallerLink.href = CODEXHOST_RELEASES_LATEST_URL;
21489
+ manualWindowsInstallerLink.target = "_blank";
21490
+ manualWindowsInstallerLink.rel = "noopener noreferrer";
21491
+ manualWindowsInstallerLink.append(
21492
+ messages.updateDownloadWindowsInstaller,
21493
+ createRendererSettingsIcon("external-link", 14)
21494
+ );
21495
+ manualWindowsInstallerActions.append(manualWindowsInstallerLink);
21496
+ manualWindowsInstaller.append(
21497
+ manualWindowsInstallerDescription,
21498
+ manualWindowsInstallerActions
21499
+ );
20760
21500
  const actions = document2.createElement("div");
20761
21501
  actions.className = "settings-update-actions";
20762
21502
  const releaseLink = document2.createElement("a");
@@ -20769,7 +21509,14 @@ ${error51.stderrTail}`] : []
20769
21509
  createRendererSettingsIcon("external-link", 14)
20770
21510
  );
20771
21511
  actions.append(releaseLink);
20772
- context.content.append(heading, metadata, panel, manualNpm, actions);
21512
+ controls.append(manualTitle, manualNpm, manualWindowsInstaller, actions);
21513
+ const notes = document2.createElement("div");
21514
+ notes.className = "settings-update-notes-section";
21515
+ context.content.append(heading, metadata, panel, controls, notes);
21516
+ const setManualFallback = (fallback) => {
21517
+ manualNpmDescription.textContent = windows ? messages.updateWindowsNpmDescription : fallback ? messages.updateManualFallbackDescription : messages.updateManualNpmDescription;
21518
+ manualNpmDescription.className = fallback ? "settings-update-manual-description is-fallback" : "settings-update-manual-description";
21519
+ };
20773
21520
  let pollTimer;
20774
21521
  let pollAttempts = 0;
20775
21522
  let pending = false;
@@ -20782,11 +21529,11 @@ ${error51.stderrTail}`] : []
20782
21529
  const renderUnavailable = (detail) => {
20783
21530
  panel.dataset.updateState = "unavailable";
20784
21531
  panel.replaceChildren();
20785
- const title = document2.createElement("strong");
20786
- title.textContent = messages.notAvailable;
20787
- const copy = document2.createElement("span");
21532
+ const copy = document2.createElement("p");
21533
+ copy.className = "settings-update-summary";
20788
21534
  copy.textContent = detail;
20789
- panel.append(title, copy);
21535
+ panel.append(createPanelHead(document2, "unavailable", messages.notAvailable), copy);
21536
+ notes.replaceChildren();
20790
21537
  };
20791
21538
  const renderRequestFailure = (error51) => {
20792
21539
  renderPendingStatus(
@@ -20822,9 +21569,8 @@ ${error51.stderrTail}`] : []
20822
21569
  const renderPendingStatus = (status, message, viewPhase = status?.phase ?? "pending") => {
20823
21570
  panel.dataset.updateState = viewPhase;
20824
21571
  panel.replaceChildren();
20825
- const state = document2.createElement("strong");
20826
- state.textContent = message;
20827
- panel.append(state);
21572
+ panel.append(createPanelHead(document2, viewPhase, message));
21573
+ setManualFallback(viewPhase === "failed");
20828
21574
  if (status?.phase === "downloading" && status.totalBytes !== void 0 && status.downloadedBytes !== void 0) {
20829
21575
  const progress = document2.createElement("progress");
20830
21576
  progress.className = "settings-update-progress";
@@ -20846,7 +21592,7 @@ ${error51.stderrTail}`] : []
20846
21592
  retry.className = "settings-command-button";
20847
21593
  retry.append(createRendererSettingsIcon("refresh", 16), messages.updateRetry);
20848
21594
  retry.addEventListener("click", () => void load());
20849
- panel.append(retry);
21595
+ panel.append(createPanelActions(document2, retry));
20850
21596
  }
20851
21597
  };
20852
21598
  const start = (client) => {
@@ -20873,8 +21619,19 @@ ${error51.stderrTail}`] : []
20873
21619
  };
20874
21620
  const renderCheck = (result, client) => {
20875
21621
  currentVersionValue.textContent = `v${result.currentVersion}`;
21622
+ latestVersionValue.textContent = result.latestVersion ? `v${result.latestVersion}` : "-";
21623
+ latestVersionValue.className = result.updateAvailable ? "settings-update-metadata__value--newer" : "";
20876
21624
  installationValue.textContent = installationLabel(result.installation, messages);
20877
21625
  manualNpm.hidden = result.installation !== "npm";
21626
+ manualWindowsInstaller.hidden = !windows || result.installation !== "windows-installer";
21627
+ releaseLink.hidden = windows;
21628
+ manualTitle.hidden = windows && !["npm", "windows-installer"].includes(result.installation ?? "");
21629
+ if (windows && result.installation === "windows-installer" && result.latestVersion) {
21630
+ manualWindowsInstallerLink.href = windowsInstallerDownloadUrl(
21631
+ document2.defaultView,
21632
+ result.latestVersion
21633
+ );
21634
+ }
20878
21635
  if (result.releaseNotesUrl) releaseLink.href = result.releaseNotesUrl;
20879
21636
  const operationMessage = statusMessage(result.status, messages);
20880
21637
  if (isPendingStatus(result.status)) {
@@ -20882,42 +21639,53 @@ ${error51.stderrTail}`] : []
20882
21639
  scheduleStatusPoll(client, true);
20883
21640
  return;
20884
21641
  }
20885
- panel.dataset.updateState = result.error ? "error" : result.updateAvailable ? "available" : "current";
21642
+ const actionableStatus = result.status?.phase === "failed" && result.status.version === result.latestVersion ? result.status : null;
21643
+ const view = result.error ? "error" : result.updateAvailable ? "available" : "current";
21644
+ panel.dataset.updateState = view;
20886
21645
  panel.replaceChildren();
20887
- if (result.latestVersion) {
20888
- panel.append(versionRow(context, messages.updateLatestVersion, result.latestVersion));
21646
+ setManualFallback(Boolean(result.error) || actionableStatus !== null);
21647
+ if (result.error || !result.updateAvailable || windows || actionableStatus) {
21648
+ panel.append(
21649
+ createPanelHead(
21650
+ document2,
21651
+ view,
21652
+ actionableStatus ? statusMessage(actionableStatus, messages) ?? messages.updateFailed : result.error ? messages.updateFailed : result.updateAvailable ? messages.updateWindowsManualRequired : messages.updateUpToDate
21653
+ )
21654
+ );
20889
21655
  }
20890
- const summary = document2.createElement("p");
20891
- summary.className = "settings-update-summary";
20892
- summary.textContent = operationMessage ?? (result.error ? messages.updateFailed : result.updateAvailable ? messages.updateAvailable : messages.updateUpToDate);
20893
- panel.append(summary);
20894
- if (result.releaseNotes) {
20895
- panel.append(createReleaseNotesElement(document2, result.releaseNotes));
21656
+ if (actionableStatus?.error) {
21657
+ const error51 = document2.createElement("p");
21658
+ error51.className = "settings-update-error";
21659
+ error51.textContent = actionableStatus.error;
21660
+ panel.append(error51);
20896
21661
  }
20897
- if (result.status?.phase === "failed" && result.status.error) {
21662
+ if (result.error) {
20898
21663
  const error51 = document2.createElement("p");
20899
21664
  error51.className = "settings-update-error";
20900
- error51.textContent = result.status.error;
21665
+ error51.textContent = result.error;
20901
21666
  panel.append(error51);
20902
21667
  }
20903
- if (result.updateAvailable && result.installationAvailable) {
21668
+ const buttons = [];
21669
+ if (!windows && result.updateAvailable && result.installationAvailable) {
20904
21670
  const update = document2.createElement("button");
20905
21671
  update.type = "button";
20906
21672
  update.className = "settings-command-button";
20907
21673
  update.append(createRendererSettingsIcon("updates", 16), messages.updateAndRestart);
20908
21674
  update.addEventListener("click", () => start(client));
20909
- panel.append(update);
21675
+ buttons.push(update);
20910
21676
  }
20911
21677
  if (result.error) {
20912
- const error51 = document2.createElement("p");
20913
- error51.className = "settings-update-error";
20914
- error51.textContent = result.error;
20915
21678
  const retry = document2.createElement("button");
20916
21679
  retry.type = "button";
20917
21680
  retry.className = "settings-command-button settings-command-button--secondary";
20918
21681
  retry.append(createRendererSettingsIcon("refresh", 16), messages.updateRetry);
20919
21682
  retry.addEventListener("click", () => void load());
20920
- panel.append(error51, retry);
21683
+ buttons.push(retry);
21684
+ }
21685
+ if (buttons.length > 0) panel.append(createPanelActions(document2, ...buttons));
21686
+ notes.replaceChildren();
21687
+ if (result.releaseNotes) {
21688
+ notes.append(createReleaseNotesElement(document2, result.releaseNotes));
20921
21689
  }
20922
21690
  };
20923
21691
  const load = () => {
@@ -20948,13 +21716,10 @@ ${error51.stderrTail}`] : []
20948
21716
  });
20949
21717
  }
20950
21718
  function createDefaultRendererSettingsPages(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null) {
20951
- const unavailableIds = DEFAULT_RENDERER_SETTINGS_PAGE_IDS.filter(
20952
- (id) => id !== "updates" && id !== "connections"
20953
- );
20954
21719
  return Object.freeze([
20955
- connectionsPage(messages, getDiagnostics),
20956
- ...unavailableIds.map((id) => unavailablePage(id, messages)),
20957
- updatesPage(messages, getUpdateClient)
21720
+ createConnectionsSettingsPage(messages, getDiagnostics),
21721
+ updatesPage(messages, getUpdateClient),
21722
+ aboutPage(messages)
20958
21723
  ]);
20959
21724
  }
20960
21725
  function createDefaultRendererSettingsRegistry(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null) {
@@ -20964,11 +21729,10 @@ ${error51.stderrTail}`] : []
20964
21729
  }
20965
21730
 
20966
21731
  // src/settings/shell.css
20967
- var shell_default = ':host {\n --settings-bg: #181818;\n --settings-sidebar: #1c1c1c;\n --settings-panel: transparent;\n --settings-text: #f5f5f5;\n --settings-muted: #a1a1a1;\n --settings-border: rgb(255 255 255 / 10%);\n --settings-divider: rgb(255 255 255 / 10%);\n --settings-hover: rgb(255 255 255 / 6%);\n --settings-active: rgb(51 156 255 / 12%);\n --settings-focus: #339cff;\n color: var(--settings-text);\n color-scheme: dark;\n font:\n 14px/1.5 system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n letter-spacing: 0;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n letter-spacing: 0;\n}\n\nbutton,\ninput,\nselect {\n font: inherit;\n}\n\nbutton {\n color: inherit;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.codexhost-settings-dialog {\n width: min(1120px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 32px));\n max-width: none;\n max-height: none;\n margin: auto;\n padding: 0;\n overflow: hidden;\n color: var(--settings-text);\n background: var(--settings-bg);\n border: 1px solid var(--settings-border);\n border-radius: 12px;\n box-shadow: 0 24px 64px rgb(0 0 0 / 38%);\n}\n\n.codexhost-settings-dialog::backdrop {\n background: rgb(0 0 0 / 52%);\n}\n\n.settings-frame,\n.settings-layout {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n}\n\n.settings-frame {\n display: flex;\n flex-direction: column;\n}\n\n.settings-layout {\n flex: 1;\n display: grid;\n grid-template-columns: 240px minmax(0, 1fr);\n background: var(--settings-bg);\n}\n\n.settings-sidebar {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n background: var(--settings-sidebar);\n border-right: 1px solid var(--settings-border);\n padding-top: 28px;\n}\n\n.settings-header {\n display: flex;\n align-items: center;\n min-width: 0;\n height: 64px;\n flex: none;\n padding: 0 16px;\n border-bottom: 1px solid var(--settings-border);\n}\n\n.settings-header-actions {\n display: flex;\n align-items: center;\n flex: none;\n gap: 12px;\n margin-left: auto;\n}\n\n.settings-icon-button.settings-star-link {\n width: auto;\n gap: 6px;\n padding-inline: 8px;\n font-size: 12px;\n line-height: 18px;\n text-decoration: none;\n border: 2px dashed #f5c542;\n white-space: nowrap;\n}\n\n.settings-star-link .codexhost-settings-icon {\n color: #f5c542;\n fill: currentColor;\n stroke: currentColor;\n}\n\n.settings-brand {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 8px;\n}\n\n.settings-brand__mark {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n flex: none;\n color: var(--settings-text);\n}\n\n.settings-brand__mark .codexhost-settings-icon {\n width: 32px;\n height: 32px;\n object-fit: contain;\n}\n\n.settings-brand__copy {\n display: flex;\n min-width: 0;\n align-items: baseline;\n gap: 0;\n line-height: 20px;\n}\n\n.settings-brand__name {\n overflow: hidden;\n color: var(--settings-text);\n font-size: 14px;\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-brand__title {\n margin-left: 14px;\n padding-left: 14px;\n color: var(--settings-muted);\n font-size: 14px;\n font-weight: 400;\n border-left: 1px solid var(--settings-border);\n}\n\n.settings-nav {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 4px;\n padding: 0 12px 16px;\n overflow-y: auto;\n}\n\n.settings-nav-button {\n display: grid;\n grid-template-columns: 16px minmax(0, 1fr);\n align-items: center;\n width: 100%;\n position: relative;\n min-height: 40px;\n flex: none;\n gap: 12px;\n padding: 8px 12px;\n color: var(--settings-text);\n font-size: 14px;\n line-height: 21px;\n text-align: left;\n background: transparent;\n border: 0;\n border-radius: 10px;\n cursor: pointer;\n}\n\n.settings-nav-button .codexhost-settings-icon {\n width: 18px;\n height: 18px;\n opacity: 0.9;\n}\n\n.settings-nav-button:hover {\n background: var(--settings-hover);\n}\n\n.settings-nav-button[aria-current="page"] {\n background: var(--settings-active);\n color: var(--settings-focus);\n}\n\n.settings-nav-button[aria-current="page"]::before {\n position: absolute;\n left: 0;\n width: 3px;\n height: 22px;\n content: "";\n background: var(--settings-focus);\n border-radius: 0 3px 3px 0;\n}\n\n.settings-nav-button span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n flex: none;\n padding: 0;\n color: var(--settings-muted);\n background: transparent;\n border: 0;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.settings-icon-button:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n\n.settings-icon-button:focus-visible,\n.settings-nav-button:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 1px;\n}\n\n.settings-page {\n display: block;\n position: relative;\n min-width: 0;\n min-height: 0;\n overflow-y: auto;\n background: var(--settings-bg);\n scrollbar-gutter: stable;\n}\n\n.settings-page__content {\n width: min(930px, calc(100% - 80px));\n margin-inline: auto;\n}\n\n.settings-page__content {\n min-width: 0;\n padding: 44px 0 56px;\n}\n\n.settings-section-label {\n min-height: auto;\n padding: 0 0 28px;\n color: var(--settings-text);\n font-size: 24px;\n font-weight: 600;\n line-height: 30px;\n}\n\n.settings-status-list,\n.settings-empty {\n overflow: hidden;\n background: var(--settings-panel);\n}\n\n.settings-status-row {\n display: grid;\n grid-template-columns: minmax(170px, 1fr) auto minmax(280px, 1.45fr);\n position: relative;\n align-items: center;\n min-height: 88px;\n gap: 28px;\n padding: 16px 0;\n}\n\n.settings-status-row:not(:last-child)::after {\n content: "";\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 1px;\n background: var(--settings-divider);\n}\n\n.settings-status-row__identity {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n color: var(--settings-text);\n gap: 14px;\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n.settings-status-row__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n flex: none;\n color: var(--settings-muted);\n background: rgb(255 255 255 / 7%);\n border-radius: 50%;\n}\n\n.settings-status-badge {\n flex: none;\n padding: 5px 12px;\n color: var(--settings-muted);\n font-size: 13px;\n font-weight: 500;\n line-height: 18px;\n background: rgb(255 255 255 / 9%);\n border: 1px solid rgb(255 255 255 / 6%);\n border-radius: 6px;\n}\n\n.settings-status-row__detail {\n min-width: 0;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-page-description {\n max-width: 760px;\n margin: -12px 0 24px;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-connection-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-bottom: 16px;\n}\n\n.settings-connection-list {\n min-width: 0;\n border-top: 1px solid var(--settings-divider);\n}\n\n.settings-connection-host-tabs {\n display: flex;\n gap: 6px;\n padding: 20px 0 8px;\n overflow-x: auto;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-connection-host-tab {\n flex: none;\n padding: 7px 12px;\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: var(--settings-muted);\n font: inherit;\n font-size: 13px;\n line-height: 18px;\n cursor: pointer;\n}\n\n.settings-connection-host-tab:hover {\n background: var(--settings-hover);\n color: var(--settings-text);\n}\n\n.settings-connection-host-tab[aria-selected="true"] {\n background: var(--settings-active);\n color: var(--settings-text);\n font-weight: 600;\n}\n\n.settings-connection-host-tab:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: -2px;\n}\n\n.settings-connection-row {\n display: grid;\n grid-template-columns: minmax(180px, 1fr) auto minmax(260px, 1.5fr);\n align-items: center;\n min-width: 0;\n min-height: 76px;\n gap: 24px;\n padding: 14px 0;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-connection-row__identity {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n gap: 10px;\n color: var(--settings-text);\n font-size: 14px;\n line-height: 20px;\n}\n\n.settings-connection-row__identity strong {\n min-width: 0;\n overflow-wrap: anywhere;\n font-weight: 500;\n}\n\n.settings-connection-row__dot {\n width: 9px;\n height: 9px;\n flex: none;\n border-radius: 50%;\n background: var(--settings-muted);\n}\n\n.settings-connection-row__dot[data-connection-tone="ready"] {\n background: #22c55e;\n}\n\n.settings-connection-row__dot[data-connection-tone="checking"] {\n background: #f5c542;\n}\n\n.settings-connection-row__dot[data-connection-tone="failed"] {\n background: #ef4444;\n}\n\n.settings-status-badge[data-connection-tone="ready"] {\n color: #4ade80;\n}\n\n.settings-status-badge[data-connection-tone="checking"] {\n color: #f5c542;\n}\n\n.settings-status-badge[data-connection-tone="failed"] {\n color: #f87171;\n}\n\n.settings-connection-row__detail {\n display: grid;\n min-width: 0;\n align-items: center;\n gap: 2px 12px;\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-connection-row__reason {\n min-width: 0;\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n.settings-connection-details-toggle {\n width: fit-content;\n padding: 0;\n color: var(--settings-focus);\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n background: transparent;\n border: 0;\n cursor: pointer;\n}\n\n.settings-connection-details-toggle:hover {\n text-decoration: underline;\n}\n\n.settings-connection-details {\n display: grid;\n grid-column: 1 / -1;\n gap: 6px;\n min-width: 0;\n margin: 4px 0 2px 32px;\n padding: 12px;\n color: var(--settings-muted);\n background: rgb(255 255 255 / 4%);\n border-left: 2px solid #ef4444;\n border-radius: 4px;\n}\n\n.settings-connection-detail-line {\n display: grid;\n grid-template-columns: 112px minmax(0, 1fr);\n gap: 12px;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-connection-detail-line span {\n color: var(--settings-muted);\n}\n\n.settings-connection-detail-line code {\n min-width: 0;\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n white-space: pre-wrap;\n}\n\n.settings-connection-stderr {\n max-height: 220px;\n min-width: 0;\n margin: 4px 0 0;\n padding: 10px;\n overflow: auto;\n color: #fca5a5;\n font:\n 12px/18px ui-monospace,\n "SFMono-Regular",\n Consolas,\n "Liberation Mono",\n monospace;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n background: rgb(0 0 0 / 28%);\n border-radius: 4px;\n}\n\n.settings-connection-details .settings-command-button {\n justify-self: start;\n min-height: 30px;\n font-size: 12px;\n}\n\n.settings-connection-row__detail time {\n color: var(--settings-muted);\n opacity: 0.8;\n}\n\n.settings-empty {\n display: flex;\n align-items: center;\n min-height: 72px;\n padding: 12px 16px;\n}\n\n.settings-empty > div {\n display: grid;\n min-width: 0;\n gap: 2px;\n}\n\n.settings-empty strong {\n color: var(--settings-text);\n font-size: 13px;\n font-weight: 500;\n line-height: 19px;\n}\n\n.settings-empty span {\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 19px;\n}\n\n.settings-page-error {\n padding: 16px;\n color: var(--settings-text);\n font-size: 13px;\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 20px;\n}\n\n.settings-update-metadata {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 24px;\n margin-bottom: 24px;\n padding: 0 4px 20px;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-update-metadata__item {\n display: grid;\n min-width: 0;\n gap: 4px;\n}\n\n.settings-update-metadata__item span {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-metadata__item strong {\n min-width: 0;\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n.settings-update-panel {\n display: grid;\n gap: 16px;\n min-height: 128px;\n padding: 20px;\n color: var(--settings-text);\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 8px;\n}\n\n.settings-update-panel > strong,\n.settings-update-panel > span,\n.settings-update-summary,\n.settings-update-error {\n margin: 0;\n overflow-wrap: anywhere;\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-update-panel > span,\n.settings-update-summary {\n color: var(--settings-muted);\n}\n\n.settings-update-error {\n color: #ef4444;\n}\n\n.settings-update-progress {\n width: 100%;\n height: 8px;\n accent-color: #238be8;\n}\n\n.settings-update-progress-detail {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-notes {\n display: grid;\n min-width: 0;\n gap: 12px;\n color: var(--settings-muted);\n font-size: 14px;\n line-height: 22px;\n overflow-wrap: anywhere;\n}\n\n.settings-update-notes > :first-child {\n margin-top: 0;\n}\n\n.settings-update-notes > :last-child {\n margin-bottom: 0;\n}\n\n.settings-update-notes h1,\n.settings-update-notes h2,\n.settings-update-notes h3,\n.settings-update-notes h4,\n.settings-update-notes h5,\n.settings-update-notes h6 {\n margin: 6px 0 0;\n color: var(--settings-text);\n font-weight: 600;\n}\n\n.settings-update-notes h1 {\n font-size: 18px;\n line-height: 26px;\n}\n\n.settings-update-notes h2 {\n font-size: 17px;\n line-height: 24px;\n}\n\n.settings-update-notes h3,\n.settings-update-notes h4,\n.settings-update-notes h5,\n.settings-update-notes h6 {\n font-size: 14px;\n line-height: 22px;\n}\n\n.settings-update-notes p,\n.settings-update-notes ul,\n.settings-update-notes ol,\n.settings-update-notes pre,\n.settings-update-notes blockquote {\n margin: 0;\n}\n\n.settings-update-notes ul,\n.settings-update-notes ol {\n padding-left: 24px;\n}\n\n.settings-update-notes li {\n padding-left: 4px;\n}\n\n.settings-update-notes li::marker {\n color: var(--settings-muted);\n font-size: 0.85em;\n}\n\n.settings-update-notes li + li {\n margin-top: 14px;\n}\n\n.settings-update-notes .release-note-translation {\n display: block;\n margin-top: 3px;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-update-notes blockquote {\n padding: 8px 12px;\n color: var(--settings-muted);\n border-left: 3px solid var(--settings-focus);\n background: rgb(255 255 255 / 4%);\n}\n\n.settings-update-notes hr {\n width: 100%;\n margin: 2px 0;\n border: 0;\n border-top: 1px solid var(--settings-divider);\n}\n\n.settings-update-notes strong {\n color: var(--settings-text);\n font-weight: 600;\n}\n\n.settings-update-notes a {\n color: #7cb8ff;\n text-decoration: none;\n}\n\n.settings-update-notes a:hover {\n text-decoration: underline;\n}\n\n.settings-update-notes code {\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n font-size: 12px;\n}\n\n.settings-update-notes :not(pre) > code {\n padding: 1px 5px;\n background: rgb(255 255 255 / 8%);\n border-radius: 4px;\n}\n\n.settings-update-notes pre {\n min-width: 0;\n max-width: 100%;\n padding: 10px 12px;\n overflow-x: auto;\n overflow-y: hidden;\n background: rgb(0 0 0 / 28%);\n border-radius: 6px;\n}\n\n.settings-update-notes pre code {\n line-height: 18px;\n white-space: pre-wrap;\n}\n\n.settings-update-version-row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: 20px;\n min-height: 32px;\n color: var(--settings-muted);\n font-size: 13px;\n}\n\n.settings-update-version-row strong {\n color: var(--settings-text);\n font-size: 15px;\n}\n\n.settings-update-manual {\n display: grid;\n min-width: 0;\n gap: 6px;\n margin-top: 14px;\n padding-inline: 4px;\n}\n\n.settings-update-manual[hidden] {\n display: none;\n}\n\n.settings-update-manual span {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-manual code {\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-actions {\n display: flex;\n min-width: 0;\n margin-top: 16px;\n}\n\n.settings-command-button,\n.settings-update-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: fit-content;\n min-height: 36px;\n gap: 8px;\n padding: 8px 12px;\n color: white;\n font: inherit;\n font-size: 13px;\n text-decoration: none;\n background: #1677d2;\n border: 1px solid #238be8;\n border-radius: 6px;\n cursor: pointer;\n}\n\n.settings-command-button--secondary,\n.settings-update-link {\n color: var(--settings-text);\n background: transparent;\n border-color: var(--settings-border);\n}\n\n.settings-command-button:hover,\n.settings-update-link:hover {\n filter: brightness(1.08);\n}\n\n.settings-command-button:focus-visible,\n.settings-update-link:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 2px;\n}\n\n.codexhost-settings-icon {\n display: block;\n flex: none;\n stroke: currentColor;\n}\n\n@media (max-width: 720px) {\n .codexhost-settings-dialog {\n width: calc(100vw - 16px);\n height: calc(100vh - 16px);\n border-radius: 10px;\n }\n\n .settings-layout {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n\n .settings-sidebar {\n border-right: 0;\n border-bottom: 1px solid var(--settings-border);\n }\n\n .settings-header {\n height: 56px;\n padding-inline: 14px;\n }\n\n .settings-icon-button.settings-star-link {\n width: 28px;\n padding: 0;\n }\n\n .settings-star-link span {\n display: none;\n }\n\n .settings-sidebar {\n padding-top: 20px;\n }\n\n .settings-nav {\n flex: none;\n flex-direction: row;\n gap: 4px;\n padding: 7px 8px 8px;\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n .settings-nav-button {\n width: auto;\n min-width: max-content;\n min-height: 34px;\n grid-template-columns: 16px auto;\n border-radius: 10px;\n }\n\n .settings-page__content {\n width: calc(100% - 40px);\n }\n\n .settings-page__content {\n padding-top: 32px;\n padding-bottom: 32px;\n }\n\n .settings-section-label {\n padding-bottom: 20px;\n font-size: 20px;\n line-height: 26px;\n }\n\n .settings-status-row {\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 16px;\n }\n\n .settings-connection-row {\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 10px 16px;\n }\n\n .settings-connection-row__detail {\n grid-column: 1 / -1;\n }\n\n .settings-status-row__detail {\n grid-column: 1 / -1;\n margin: -8px 0 0 58px;\n }\n}\n\n@media (forced-colors: active) {\n :host,\n :host([data-theme="dark"]) {\n --settings-bg: Canvas;\n --settings-sidebar: Canvas;\n --settings-panel: Canvas;\n --settings-text: CanvasText;\n --settings-muted: GrayText;\n --settings-border: ButtonBorder;\n --settings-divider: ButtonBorder;\n --settings-hover: Highlight;\n --settings-active: Highlight;\n --settings-focus: Highlight;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n scroll-behavior: auto !important;\n }\n}\n';
21732
+ var shell_default = ':host {\n --settings-bg: #181818;\n --settings-sidebar: #1c1c1c;\n --settings-panel: transparent;\n --settings-text: #f5f5f5;\n --settings-muted: #a1a1a1;\n --settings-border: rgb(255 255 255 / 10%);\n --settings-divider: rgb(255 255 255 / 10%);\n --settings-hover: rgb(255 255 255 / 6%);\n --settings-active: rgb(51 156 255 / 12%);\n --settings-focus: #339cff;\n color: var(--settings-text);\n color-scheme: dark;\n font:\n 14px/1.5 system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n letter-spacing: 0;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n letter-spacing: 0;\n}\n\nbutton,\ninput,\nselect {\n font: inherit;\n}\n\nbutton {\n color: inherit;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.codexhost-settings-dialog {\n width: min(1120px, calc(100vw - 32px));\n height: min(780px, calc(100vh - 32px));\n max-width: none;\n max-height: none;\n margin: auto;\n padding: 0;\n overflow: hidden;\n color: var(--settings-text);\n background: var(--settings-bg);\n border: 1px solid var(--settings-border);\n border-radius: 12px;\n box-shadow: 0 24px 64px rgb(0 0 0 / 38%);\n}\n\n.codexhost-settings-dialog::backdrop {\n background: rgb(0 0 0 / 52%);\n}\n\n.settings-frame,\n.settings-layout {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n}\n\n.settings-frame {\n display: flex;\n flex-direction: column;\n}\n\n.settings-layout {\n flex: 1;\n display: grid;\n grid-template-columns: 240px minmax(0, 1fr);\n background: var(--settings-bg);\n}\n\n.settings-sidebar {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n background: var(--settings-sidebar);\n border-right: 1px solid var(--settings-border);\n padding-top: 28px;\n}\n\n.settings-header {\n display: flex;\n align-items: center;\n min-width: 0;\n height: 64px;\n flex: none;\n padding: 0 16px;\n border-bottom: 1px solid var(--settings-border);\n}\n\n.settings-header-actions {\n display: flex;\n align-items: center;\n flex: none;\n gap: 12px;\n margin-left: auto;\n}\n\n.settings-brand {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 8px;\n}\n\n.settings-brand__mark {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n flex: none;\n color: var(--settings-text);\n}\n\n.settings-brand__mark .codexhost-settings-icon {\n width: 32px;\n height: 32px;\n object-fit: contain;\n}\n\n.settings-brand__copy {\n display: flex;\n min-width: 0;\n align-items: baseline;\n gap: 0;\n line-height: 20px;\n}\n\n.settings-brand__name {\n overflow: hidden;\n color: var(--settings-text);\n font-size: 14px;\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-brand__title {\n margin-left: 14px;\n padding-left: 14px;\n color: var(--settings-muted);\n font-size: 14px;\n font-weight: 400;\n border-left: 1px solid var(--settings-border);\n}\n\n.settings-nav {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 4px;\n padding: 0 12px 16px;\n overflow-y: auto;\n}\n\n.settings-nav-section-label {\n min-height: 28px;\n padding: 7px 12px 3px;\n color: #777;\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n}\n\n.settings-nav-section-label:not(:first-child) {\n margin-top: 14px;\n}\n\n.settings-nav-button {\n display: grid;\n grid-template-columns: 16px minmax(0, 1fr);\n align-items: center;\n width: 100%;\n position: relative;\n min-height: 48px;\n flex: none;\n gap: 14px;\n padding: 10px 14px;\n color: var(--settings-text);\n font-size: 14px;\n line-height: 21px;\n text-align: left;\n background: transparent;\n border: 0;\n border-radius: 12px;\n cursor: pointer;\n}\n\n.settings-nav-button .codexhost-settings-icon {\n width: 18px;\n height: 18px;\n opacity: 0.9;\n}\n\n.settings-nav-button:hover {\n background: var(--settings-hover);\n}\n\n.settings-nav-button[aria-current="page"] {\n background: var(--settings-active);\n color: var(--settings-focus);\n}\n\n.settings-nav-button[aria-current="page"]::before {\n position: absolute;\n left: 0;\n width: 3px;\n height: 22px;\n content: "";\n background: var(--settings-focus);\n border-radius: 0 3px 3px 0;\n}\n\n.settings-nav-button span {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-nav-star-link {\n margin-top: 0;\n color: var(--settings-text);\n text-decoration: none;\n}\n\n.settings-nav-star-link .codexhost-settings-icon {\n color: #f5c542;\n}\n\n.settings-nav-star-link:hover {\n color: #fff4bd;\n background: rgb(245 197 66 / 8%);\n}\n\n.settings-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n flex: none;\n padding: 0;\n color: var(--settings-muted);\n background: transparent;\n border: 0;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.settings-icon-button:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n\n.settings-icon-button:focus-visible,\n.settings-nav-button:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 1px;\n}\n\n.settings-page {\n display: block;\n position: relative;\n min-width: 0;\n min-height: 0;\n overflow-y: auto;\n background: var(--settings-bg);\n scrollbar-gutter: stable;\n}\n\n.settings-page__content {\n width: min(930px, calc(100% - 80px));\n margin-inline: auto;\n}\n\n.settings-page__content {\n min-width: 0;\n padding: 44px 0 56px;\n}\n\n.settings-section-label {\n min-height: auto;\n padding: 0 0 28px;\n color: var(--settings-text);\n font-size: 24px;\n font-weight: 600;\n line-height: 30px;\n}\n\n.settings-status-list,\n.settings-empty {\n overflow: hidden;\n background: var(--settings-panel);\n}\n\n.settings-status-row {\n display: grid;\n grid-template-columns: minmax(170px, 1fr) auto minmax(280px, 1.45fr);\n position: relative;\n align-items: center;\n min-height: 88px;\n gap: 28px;\n padding: 16px 0;\n}\n\n.settings-status-row:not(:last-child)::after {\n content: "";\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 1px;\n background: var(--settings-divider);\n}\n\n.settings-status-row__identity {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n color: var(--settings-text);\n gap: 14px;\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n.settings-status-row__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n flex: none;\n color: var(--settings-muted);\n background: rgb(255 255 255 / 7%);\n border-radius: 50%;\n}\n\n.settings-status-badge {\n flex: none;\n padding: 5px 12px;\n color: var(--settings-muted);\n font-size: 13px;\n font-weight: 500;\n line-height: 18px;\n background: rgb(255 255 255 / 9%);\n border: 1px solid rgb(255 255 255 / 6%);\n border-radius: 6px;\n}\n\n.settings-status-row__detail {\n min-width: 0;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-page-description {\n max-width: 760px;\n margin: -12px 0 24px;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-preference-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 32px;\n min-height: 88px;\n padding: 18px 0;\n border-top: 1px solid var(--settings-divider);\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-preference-row__copy {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-width: 0;\n gap: 5px;\n}\n\n.settings-preference-row__copy strong {\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 600;\n line-height: 22px;\n}\n\n.settings-preference-row__copy span {\n max-width: 680px;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-preference-switch {\n display: inline-flex;\n align-items: center;\n width: 42px;\n height: 24px;\n flex: none;\n padding: 2px;\n border: 0;\n border-radius: 999px;\n background: rgb(255 255 255 / 16%);\n cursor: pointer;\n transition: background 120ms ease;\n}\n\n.settings-preference-switch[aria-checked="true"] {\n justify-content: flex-end;\n background: var(--settings-focus);\n}\n\n.settings-preference-switch:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 2px;\n}\n\n.settings-preference-switch__thumb {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: white;\n box-shadow: 0 1px 3px rgb(0 0 0 / 35%);\n}\n\n.settings-connection-page-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 24px;\n margin-bottom: 24px;\n}\n\n.settings-connection-page-header .settings-section-label {\n padding-bottom: 0;\n}\n\n.settings-connection-page-header .settings-page-description {\n margin: 8px 0 0;\n}\n\n.settings-connections-content,\n.settings-connections-layout,\n.settings-connection-list,\n.settings-connection-rows {\n min-width: 0;\n}\n\n.settings-connections-layout {\n display: grid;\n grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.85fr);\n align-items: start;\n gap: 18px;\n}\n\n.settings-connection-list,\n.settings-connection-inspector {\n overflow: hidden;\n background: rgb(255 255 255 / 2%);\n border: 1px solid var(--settings-border);\n border-radius: 12px;\n}\n\n.settings-connection-host-strip {\n display: grid;\n grid-template-columns: 30px minmax(0, 1fr) 30px;\n align-items: center;\n min-width: 0;\n gap: 6px;\n padding: 12px;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-connection-host-scroll {\n display: none;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 34px;\n padding: 0;\n color: var(--settings-muted);\n background: rgb(0 0 0 / 18%);\n border: 1px solid var(--settings-border);\n border-radius: 8px;\n cursor: pointer;\n}\n\n.settings-connection-host-strip[data-connection-host-overflow="true"]\n .settings-connection-host-scroll {\n display: inline-flex;\n}\n\n.settings-connection-host-strip:not([data-connection-host-overflow="true"]) {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.settings-connection-host-scroll:hover:not(:disabled) {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n\n.settings-connection-host-scroll:disabled {\n cursor: default;\n opacity: 0.35;\n}\n\n.settings-connection-host-scroll:focus-visible,\n.settings-connection-host-tab:focus-visible,\n.settings-connection-row:focus-visible,\n.settings-connection-install-link:focus-visible,\n.settings-connection-view-error:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 1px;\n}\n\n.settings-connection-host-tabs {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 6px;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n scrollbar-width: none;\n scroll-behavior: smooth;\n scroll-snap-type: x proximity;\n touch-action: pan-x;\n}\n\n.settings-connection-host-tabs::-webkit-scrollbar {\n display: none;\n}\n\n.settings-connection-host-tab {\n display: inline-flex;\n align-items: center;\n height: 34px;\n min-width: max-content;\n flex: none;\n padding: 0 11px;\n color: var(--settings-muted);\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n white-space: nowrap;\n background: rgb(0 0 0 / 18%);\n border: 1px solid var(--settings-border);\n border-radius: 8px;\n cursor: pointer;\n scroll-snap-align: start;\n}\n\n.settings-connection-host-tab:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n\n.settings-connection-host-tab[aria-selected="true"] {\n color: #e8f3ff;\n font-weight: 600;\n background: var(--settings-active);\n border-color: rgb(51 156 255 / 50%);\n}\n\n.settings-connection-table-header,\n.settings-connection-row {\n display: grid;\n grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) 82px;\n align-items: center;\n min-width: 0;\n gap: 14px;\n}\n\n.settings-connection-table-header {\n min-height: 36px;\n padding: 0 12px;\n color: var(--settings-muted);\n font-size: 10px;\n font-weight: 600;\n line-height: 16px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n background: rgb(255 255 255 / 2%);\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-connection-row {\n min-height: 64px;\n padding: 10px 12px;\n cursor: pointer;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-connection-row:last-child {\n border-bottom: 0;\n}\n\n.settings-connection-row:hover {\n background: var(--settings-hover);\n}\n\n.settings-connection-row[data-connection-selected="true"] {\n background: var(--settings-active);\n}\n\n.settings-connection-row__identity,\n.settings-connection-inspector__identity {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n gap: 9px;\n color: var(--settings-text);\n}\n\n.settings-connection-row__identity strong,\n.settings-connection-inspector__identity strong {\n min-width: 0;\n overflow-wrap: anywhere;\n font-size: 13px;\n font-weight: 600;\n line-height: 19px;\n}\n\n.settings-connection-row__mark {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n flex: none;\n color: #d4d8de;\n font-size: 10px;\n font-weight: 700;\n background: rgb(255 255 255 / 6%);\n border-radius: 7px;\n}\n\n.settings-connection-row__mark--logo {\n color: var(--settings-text);\n background: transparent;\n}\n\n.settings-connection-row__mark--logo > img,\n.settings-connection-row__mark--logo > svg {\n display: block;\n max-width: 22px;\n max-height: 22px;\n}\n\n.settings-connection-row__status {\n display: inline-flex;\n align-items: center;\n width: fit-content;\n gap: 6px;\n color: var(--settings-muted);\n font-size: 12px;\n font-weight: 500;\n line-height: 18px;\n}\n\n.settings-connection-row__status::before {\n width: 7px;\n height: 7px;\n flex: none;\n content: "";\n background: currentColor;\n border-radius: 50%;\n}\n\n.settings-connection-row__status[data-connection-tone="ready"] {\n color: #4ade80;\n}\n\n.settings-connection-row__status[data-connection-tone="checking"] {\n color: #f5c542;\n}\n\n.settings-connection-row__status[data-connection-tone="setup"] {\n color: var(--settings-muted);\n}\n\n.settings-connection-row__status[data-connection-tone="setup"]::before {\n background: transparent;\n border: 1.5px solid currentColor;\n}\n\n.settings-connection-row__status[data-connection-tone="failed"] {\n color: #f87171;\n}\n\n.settings-connection-row__action {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n min-width: 0;\n}\n\n.settings-connection-install-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n color: var(--settings-focus);\n text-decoration: none;\n background: transparent;\n border: 1px solid transparent;\n border-radius: 7px;\n}\n\n.settings-connection-install-link:hover {\n color: #8cc5ff;\n background: rgb(51 156 255 / 10%);\n border-color: rgb(51 156 255 / 22%);\n}\n\n.settings-connection-view-error {\n padding: 4px 7px;\n color: #f87171;\n font: inherit;\n font-size: 11px;\n line-height: 18px;\n background: transparent;\n border: 0;\n border-radius: 6px;\n cursor: pointer;\n}\n\n.settings-connection-view-error:hover {\n color: #fca5a5;\n background: rgb(239 68 68 / 9%);\n}\n\n.settings-connection-inspector {\n position: sticky;\n top: 24px;\n}\n\n.settings-connection-inspector__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n min-width: 0;\n gap: 12px;\n padding: 16px;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-connection-inspector__body {\n display: grid;\n min-width: 0;\n gap: 14px;\n padding: 16px;\n}\n\n.settings-connection-install-callout {\n display: grid;\n grid-template-columns: 32px minmax(0, 1fr);\n gap: 10px;\n padding: 14px;\n background: linear-gradient(rgb(51 156 255 / 8%), rgb(51 156 255 / 4%));\n border: 1px solid rgb(51 156 255 / 20%);\n border-radius: 10px;\n}\n\n.settings-connection-install-callout__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n color: var(--settings-focus);\n background: var(--settings-active);\n border-radius: 8px;\n}\n\n.settings-connection-install-callout strong,\n.settings-connection-error-summary strong,\n.settings-connection-state-summary strong {\n display: block;\n margin: 0 0 4px;\n color: var(--settings-text);\n font-size: 13px;\n font-weight: 600;\n line-height: 19px;\n}\n\n.settings-connection-install-callout p,\n.settings-connection-error-summary p,\n.settings-connection-state-summary p,\n.settings-connection-issue-note {\n margin: 0;\n color: var(--settings-muted);\n font-size: 11px;\n line-height: 17px;\n}\n\n.settings-connection-install-button {\n width: 100%;\n}\n\n.settings-connection-error-summary {\n padding: 13px 14px;\n color: #fecaca;\n background: rgb(239 68 68 / 7%);\n border: 1px solid rgb(239 68 68 / 20%);\n border-radius: 10px;\n}\n\n.settings-connection-error-metadata {\n display: grid;\n gap: 7px;\n padding: 12px;\n background: rgb(0 0 0 / 18%);\n border: 1px solid var(--settings-border);\n border-radius: 9px;\n}\n\n.settings-connection-detail-line {\n display: grid;\n grid-template-columns: 92px minmax(0, 1fr);\n gap: 10px;\n min-width: 0;\n color: var(--settings-muted);\n font-size: 10px;\n line-height: 16px;\n}\n\n.settings-connection-detail-line code {\n min-width: 0;\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n white-space: pre-wrap;\n}\n\n.settings-connection-error-log-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n}\n\n.settings-connection-error-log-header strong {\n color: var(--settings-text);\n font-size: 11px;\n font-weight: 600;\n}\n\n.settings-connection-error-log-header .settings-command-button {\n min-height: 30px;\n padding: 5px 9px;\n font-size: 11px;\n}\n\n.settings-connection-stderr {\n max-height: 220px;\n min-width: 0;\n margin: 0;\n padding: 11px;\n overflow: auto;\n color: #e3e5e8;\n font:\n 10px/16px ui-monospace,\n "SFMono-Regular",\n Consolas,\n "Liberation Mono",\n monospace;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n background: rgb(0 0 0 / 28%);\n border: 1px solid var(--settings-border);\n border-radius: 9px;\n}\n\n.settings-connection-error-actions {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: 8px;\n}\n\n.settings-connection-error-actions .settings-command-button {\n width: 100%;\n}\n\n.settings-connection-issue-note {\n margin-top: -4px;\n}\n\n.settings-connection-state-summary {\n padding: 14px;\n background: rgb(255 255 255 / 3%);\n border: 1px solid var(--settings-border);\n border-radius: 10px;\n}\n\n.settings-empty {\n display: flex;\n align-items: center;\n min-height: 72px;\n padding: 12px 16px;\n}\n\n.settings-empty > div {\n display: grid;\n min-width: 0;\n gap: 2px;\n}\n\n.settings-empty strong {\n color: var(--settings-text);\n font-size: 13px;\n font-weight: 500;\n line-height: 19px;\n}\n\n.settings-empty span {\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 19px;\n}\n\n.settings-about-panel {\n display: grid;\n max-width: 720px;\n gap: 18px;\n padding: 28px;\n background: rgb(255 255 255 / 2%);\n border: 1px solid var(--settings-border);\n border-radius: 12px;\n}\n\n.settings-about-product {\n color: var(--settings-text);\n font-size: 24px;\n font-weight: 700;\n line-height: 32px;\n}\n\n.settings-about-tagline {\n color: var(--settings-text);\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n}\n\n.settings-about-copy {\n display: grid;\n max-width: 660px;\n gap: 12px;\n}\n\n.settings-about-copy p,\n.settings-about-repository p {\n margin: 0;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 21px;\n}\n\n.settings-about-star-callout {\n margin: 2px 0;\n color: #f5c542;\n font-size: 14px;\n font-weight: 600;\n line-height: 22px;\n}\n\n.settings-about-repository {\n display: grid;\n gap: 10px;\n padding-top: 18px;\n border-top: 1px solid var(--settings-divider);\n}\n\n.settings-about-repository-link {\n display: flex;\n align-items: center;\n width: fit-content;\n min-width: 0;\n max-width: 100%;\n gap: 8px;\n color: #7cb8ff;\n font-size: 13px;\n font-weight: 600;\n text-decoration: none;\n}\n\n.settings-about-repository-link:hover {\n text-decoration: underline;\n}\n\n.settings-about-repository-link code {\n min-width: 0;\n overflow: hidden;\n color: var(--settings-muted);\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n font-size: 11px;\n font-weight: 400;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-page-error {\n padding: 16px;\n color: var(--settings-text);\n font-size: 13px;\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 20px;\n}\n\n.settings-update-metadata {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 24px;\n margin-bottom: 24px;\n padding: 0 4px 20px;\n border-bottom: 1px solid var(--settings-divider);\n}\n\n.settings-update-metadata__item {\n display: grid;\n min-width: 0;\n gap: 4px;\n}\n\n.settings-update-metadata__item span {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-metadata__item strong {\n min-width: 0;\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 500;\n line-height: 22px;\n}\n\n/* The only emphasis on this screen: a latest version newer than the installed one. */\n.settings-update-metadata__value--newer {\n color: #4aa3f0;\n}\n\n.settings-update-panel {\n display: grid;\n gap: 12px;\n padding: 20px;\n color: var(--settings-text);\n background: var(--settings-panel);\n border: 1px solid var(--settings-border);\n border-radius: 8px;\n}\n\n.settings-update-panel__head {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 8px;\n}\n\n.settings-update-panel__head .codexhost-settings-icon {\n color: var(--settings-muted);\n}\n\n.settings-update-panel[data-update-state="available"] .codexhost-settings-icon,\n.settings-update-panel[data-update-state="downloading"] .codexhost-settings-icon,\n.settings-update-panel[data-update-state="installing"] .codexhost-settings-icon,\n.settings-update-panel[data-update-state="restarting"] .codexhost-settings-icon {\n color: #4aa3f0;\n}\n\n.settings-update-panel[data-update-state="current"] .codexhost-settings-icon {\n color: #4ade80;\n}\n\n.settings-update-panel[data-update-state="failed"] .codexhost-settings-icon,\n.settings-update-panel[data-update-state="error"] .codexhost-settings-icon {\n color: #ef4444;\n}\n\n.settings-update-panel__title {\n min-width: 0;\n overflow-wrap: anywhere;\n color: var(--settings-text);\n font-size: 14px;\n font-weight: 600;\n line-height: 22px;\n}\n\n.settings-update-summary,\n.settings-update-error {\n margin: 0;\n overflow-wrap: anywhere;\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-update-summary {\n color: var(--settings-muted);\n}\n\n.settings-update-error {\n color: #ef4444;\n}\n\n.settings-update-progress {\n width: 100%;\n height: 8px;\n accent-color: #238be8;\n}\n\n.settings-update-progress-detail {\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n/* Release notes scroll with the page; a scroller inside a scroller traps the wheel. */\n.settings-update-notes-section {\n min-width: 0;\n margin-top: 24px;\n padding-top: 24px;\n border-top: 1px solid var(--settings-divider);\n}\n\n.settings-update-notes-section:empty {\n display: none;\n}\n\n.settings-update-notes {\n display: grid;\n min-width: 0;\n gap: 12px;\n color: var(--settings-muted);\n font-size: 14px;\n line-height: 22px;\n overflow-wrap: anywhere;\n}\n\n.settings-update-notes > :first-child {\n margin-top: 0;\n}\n\n.settings-update-notes > :last-child {\n margin-bottom: 0;\n}\n\n.settings-update-notes h1,\n.settings-update-notes h2,\n.settings-update-notes h3,\n.settings-update-notes h4,\n.settings-update-notes h5,\n.settings-update-notes h6 {\n margin: 6px 0 0;\n color: var(--settings-text);\n font-weight: 600;\n}\n\n.settings-update-notes h1 {\n font-size: 18px;\n line-height: 26px;\n}\n\n.settings-update-notes h2 {\n font-size: 17px;\n line-height: 24px;\n}\n\n.settings-update-notes h3,\n.settings-update-notes h4,\n.settings-update-notes h5,\n.settings-update-notes h6 {\n font-size: 14px;\n line-height: 22px;\n}\n\n.settings-update-notes p,\n.settings-update-notes ul,\n.settings-update-notes ol,\n.settings-update-notes pre,\n.settings-update-notes blockquote {\n margin: 0;\n}\n\n.settings-update-notes ul,\n.settings-update-notes ol {\n padding-left: 24px;\n}\n\n.settings-update-notes li {\n padding-left: 4px;\n}\n\n.settings-update-notes li::marker {\n color: var(--settings-muted);\n font-size: 0.85em;\n}\n\n.settings-update-notes li + li {\n margin-top: 14px;\n}\n\n.settings-update-notes .release-note-translation {\n display: block;\n margin-top: 3px;\n color: var(--settings-muted);\n font-size: 13px;\n line-height: 20px;\n}\n\n.settings-update-notes blockquote {\n padding: 8px 12px;\n color: var(--settings-muted);\n border-left: 3px solid var(--settings-focus);\n background: rgb(255 255 255 / 4%);\n}\n\n.settings-update-notes hr {\n width: 100%;\n margin: 2px 0;\n border: 0;\n border-top: 1px solid var(--settings-divider);\n}\n\n.settings-update-notes strong {\n color: var(--settings-text);\n font-weight: 600;\n}\n\n.settings-update-notes a {\n color: #7cb8ff;\n text-decoration: none;\n}\n\n.settings-update-notes a:hover {\n text-decoration: underline;\n}\n\n.settings-update-notes code {\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n font-size: 12px;\n}\n\n.settings-update-notes :not(pre) > code {\n padding: 1px 5px;\n background: rgb(255 255 255 / 8%);\n border-radius: 4px;\n}\n\n.settings-update-notes pre {\n min-width: 0;\n max-width: 100%;\n padding: 10px 12px;\n overflow-x: auto;\n overflow-y: hidden;\n background: rgb(0 0 0 / 28%);\n border-radius: 6px;\n}\n\n.settings-update-notes pre code {\n line-height: 18px;\n white-space: pre-wrap;\n}\n\n/* Manual update sits directly under the status panel, not behind a disclosure:\n automatic updates can fail for machine-local reasons and this is the way out. */\n.settings-update-controls {\n display: grid;\n min-width: 0;\n gap: 10px;\n margin-top: 24px;\n}\n\n.settings-update-manual-title {\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 600;\n line-height: 22px;\n}\n\n.settings-update-manual {\n display: grid;\n min-width: 0;\n gap: 8px;\n}\n\n.settings-update-manual[hidden] {\n display: none;\n}\n\n.settings-update-manual-description {\n margin: 0;\n color: var(--settings-muted);\n font-size: 12px;\n line-height: 18px;\n}\n\n.settings-update-manual-description.is-fallback {\n color: #ef4444;\n}\n\n.settings-update-command {\n display: flex;\n align-items: stretch;\n min-width: 0;\n overflow: hidden;\n border: 1px solid var(--settings-border);\n border-radius: 6px;\n}\n\n.settings-update-command code {\n min-width: 0;\n flex: 1;\n padding: 9px 12px;\n overflow-x: auto;\n color: var(--settings-text);\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\n font-size: 12px;\n line-height: 20px;\n white-space: nowrap;\n}\n\n.settings-update-command__copy {\n display: inline-flex;\n align-items: center;\n flex: none;\n gap: 6px;\n padding: 0 12px;\n color: var(--settings-muted);\n font-size: 12px;\n background: transparent;\n border: 0;\n border-left: 1px solid var(--settings-border);\n cursor: pointer;\n}\n\n.settings-update-command__copy:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n\n.settings-update-command__copy:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: -2px;\n}\n\n.settings-update-actions {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.settings-command-button,\n.settings-update-link {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: fit-content;\n min-height: 36px;\n gap: 8px;\n padding: 8px 12px;\n color: white;\n font: inherit;\n font-size: 13px;\n text-decoration: none;\n background: #1677d2;\n border: 1px solid #238be8;\n border-radius: 6px;\n cursor: pointer;\n}\n\n.settings-command-button--secondary,\n.settings-update-link {\n color: var(--settings-text);\n background: transparent;\n border-color: var(--settings-border);\n}\n\n.settings-command-button:hover,\n.settings-update-link:hover {\n filter: brightness(1.08);\n}\n\n.settings-command-button:focus-visible,\n.settings-update-link:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: 2px;\n}\n\n.codexhost-settings-icon {\n display: block;\n flex: none;\n stroke: currentColor;\n}\n\n@media (max-width: 720px) {\n .codexhost-settings-dialog {\n width: calc(100vw - 16px);\n height: calc(100vh - 16px);\n border-radius: 10px;\n }\n\n .settings-layout {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr);\n }\n\n .settings-sidebar {\n border-right: 0;\n border-bottom: 1px solid var(--settings-border);\n }\n\n .settings-header {\n height: 56px;\n padding-inline: 14px;\n }\n\n .settings-sidebar {\n padding-top: 20px;\n }\n\n .settings-nav {\n flex: none;\n flex-direction: row;\n gap: 4px;\n padding: 7px 8px 8px;\n overflow-x: auto;\n overflow-y: hidden;\n }\n\n .settings-nav-section-label {\n display: none;\n }\n\n .settings-nav-button {\n width: auto;\n min-width: max-content;\n min-height: 34px;\n grid-template-columns: 16px auto;\n border-radius: 10px;\n }\n\n .settings-nav-star-link {\n margin-top: 0;\n }\n\n .settings-page__content {\n width: calc(100% - 40px);\n }\n\n .settings-page__content {\n padding-top: 32px;\n padding-bottom: 32px;\n }\n\n .settings-section-label {\n padding-bottom: 20px;\n font-size: 20px;\n line-height: 26px;\n }\n\n .settings-update-metadata {\n grid-template-columns: minmax(0, 1fr);\n gap: 16px;\n }\n\n .settings-status-row {\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 16px;\n }\n\n .settings-connection-page-header {\n flex-direction: column;\n }\n\n .settings-connection-page-header > .settings-command-button {\n width: 100%;\n }\n\n .settings-connections-layout {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .settings-connection-inspector {\n position: static;\n }\n\n .settings-status-row__detail {\n grid-column: 1 / -1;\n margin: -8px 0 0 58px;\n }\n}\n\n@media (forced-colors: active) {\n :host,\n :host([data-theme="dark"]) {\n --settings-bg: Canvas;\n --settings-sidebar: Canvas;\n --settings-panel: Canvas;\n --settings-text: CanvasText;\n --settings-muted: GrayText;\n --settings-border: ButtonBorder;\n --settings-divider: ButtonBorder;\n --settings-hover: Highlight;\n --settings-active: Highlight;\n --settings-focus: Highlight;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n scroll-behavior: auto !important;\n }\n}\n';
20968
21733
 
20969
21734
  // src/settings/shell.ts
20970
21735
  var SETTINGS_SHELL_ATTRIBUTE = "data-codexhost-settings-shell";
20971
- var CODEXHOST_GITHUB_REPOSITORY_URL = "https://github.com/BytePioneer-AI/codex-host";
20972
21736
  function isRendererSettingsDialogSupported(dialog) {
20973
21737
  return typeof dialog.showModal === "function" && typeof dialog.close === "function";
20974
21738
  }
@@ -21015,23 +21779,13 @@ ${error51.stderrTail}`] : []
21015
21779
  brand.append(brandMark, brandCopy);
21016
21780
  const headerActions = ownerDocument.createElement("div");
21017
21781
  headerActions.className = "settings-header-actions";
21018
- const starLink = ownerDocument.createElement("a");
21019
- starLink.className = "settings-icon-button settings-star-link";
21020
- starLink.href = CODEXHOST_GITHUB_REPOSITORY_URL;
21021
- starLink.target = "_blank";
21022
- starLink.rel = "noopener noreferrer";
21023
- starLink.setAttribute("aria-label", messages.starOnGitHub);
21024
- starLink.title = messages.starOnGitHub;
21025
- const starLabel = ownerDocument.createElement("span");
21026
- starLabel.textContent = messages.starOnGitHub;
21027
- starLink.append(createRendererSettingsIcon("star", 16), starLabel);
21028
21782
  const closeButton = ownerDocument.createElement("button");
21029
21783
  closeButton.type = "button";
21030
21784
  closeButton.className = "settings-icon-button";
21031
21785
  closeButton.setAttribute("aria-label", messages.close);
21032
21786
  closeButton.title = messages.close;
21033
21787
  closeButton.append(createRendererSettingsIcon("close", 18));
21034
- headerActions.append(starLink, closeButton);
21788
+ headerActions.append(closeButton);
21035
21789
  header.append(brand, headerActions);
21036
21790
  const layout = ownerDocument.createElement("div");
21037
21791
  layout.className = "settings-layout";
@@ -21097,7 +21851,19 @@ ${error51.stderrTail}`] : []
21097
21851
  renderMountFailure();
21098
21852
  }
21099
21853
  };
21854
+ const appendNavigationSection = (label) => {
21855
+ const section = ownerDocument.createElement("div");
21856
+ section.className = "settings-nav-section-label";
21857
+ section.textContent = label;
21858
+ navigation.append(section);
21859
+ };
21860
+ let otherSectionAdded = false;
21861
+ appendNavigationSection(messages.generalSection);
21100
21862
  for (const definition of resolvedRegistry.pages) {
21863
+ if (definition.id === "about" && !otherSectionAdded) {
21864
+ appendNavigationSection(messages.otherSection);
21865
+ otherSectionAdded = true;
21866
+ }
21101
21867
  const button = ownerDocument.createElement("button");
21102
21868
  button.type = "button";
21103
21869
  button.className = "settings-nav-button";
@@ -21109,6 +21875,18 @@ ${error51.stderrTail}`] : []
21109
21875
  navigationButtons.set(definition.id, button);
21110
21876
  navigation.append(button);
21111
21877
  }
21878
+ const starLink = ownerDocument.createElement("a");
21879
+ starLink.className = "settings-nav-button settings-nav-star-link";
21880
+ starLink.href = CODEXHOST_GITHUB_REPOSITORY_URL;
21881
+ starLink.target = "_blank";
21882
+ starLink.rel = "noopener noreferrer";
21883
+ starLink.setAttribute("aria-label", messages.starOnGitHub);
21884
+ starLink.title = messages.starOnGitHub;
21885
+ starLink.append(createRendererSettingsIcon("star", 17));
21886
+ const starLabel = ownerDocument.createElement("span");
21887
+ starLabel.textContent = messages.starOnGitHub;
21888
+ starLink.append(starLabel);
21889
+ navigation.append(starLink);
21112
21890
  const supported = isRendererSettingsDialogSupported(dialog);
21113
21891
  const focusActiveNavigation = () => {
21114
21892
  navigationButtons.get(navigationState.activePageId)?.focus();
@@ -21450,6 +22228,7 @@ ${error51.stderrTail}`] : []
21450
22228
  trigger = null;
21451
22229
  shell = null;
21452
22230
  const mounted = mount();
22231
+ options.onLocaleChange?.(locale);
21453
22232
  if (reopen) {
21454
22233
  const opener = mounted.trigger.root?.querySelector("button") ?? void 0;
21455
22234
  mounted.shell.openSettings(opener, activePageId);
@@ -21562,23 +22341,6 @@ ${error51.stderrTail}`] : []
21562
22341
  };
21563
22342
  }
21564
22343
 
21565
- // src/compatibility-update.ts
21566
- async function startCompatibilityUpdate(client) {
21567
- if (!client) return "unavailable";
21568
- try {
21569
- const check2 = await client.checkUpdate();
21570
- if (check2.updateAvailable && check2.installationAvailable) {
21571
- void client.startUpdate().catch(() => void 0);
21572
- return "update-started";
21573
- }
21574
- if (check2.error === null && check2.latestVersion !== null && check2.currentVersion === check2.latestVersion) {
21575
- return "current";
21576
- }
21577
- } catch {
21578
- }
21579
- return "unavailable";
21580
- }
21581
-
21582
22344
  // src/renderer-binding-probe.ts
21583
22345
  var externalHarnessIds = {
21584
22346
  pi: harnessIdSchema.parse("pi"),
@@ -21608,6 +22370,9 @@ ${error51.stderrTail}`] : []
21608
22370
  );
21609
22371
  }
21610
22372
  var rendererUsageRefreshDelays = [250, 500, 1e3, 2e3, 4e3, 8e3];
22373
+ function refreshConnectionHosts(hostIds, refreshHost) {
22374
+ return Promise.all([...hostIds].map((hostId) => refreshHost(hostId))).then(() => void 0);
22375
+ }
21611
22376
  function rendererUsageRefreshDelay(attempt) {
21612
22377
  const index = Math.max(0, Math.min(Math.trunc(attempt), rendererUsageRefreshDelays.length - 1));
21613
22378
  return rendererUsageRefreshDelays[index] ?? rendererUsageRefreshDelays[0];
@@ -21632,6 +22397,13 @@ ${error51.stderrTail}`] : []
21632
22397
  function draftPermissionMode(catalog, requested) {
21633
22398
  return catalog.modes.find(({ id }) => id === requested)?.id ?? catalog.modes.find(({ id }) => id === catalog.defaultModeId)?.id ?? catalog.defaultModeId;
21634
22399
  }
22400
+ function lockedPermissionMode(catalog, effective, carrier) {
22401
+ const restored = effective ?? carrier;
22402
+ if (restored && !catalog.modes.some(({ id }) => id === restored)) {
22403
+ throw new Error("Existing Thread Permission Mode is absent from the current Catalog");
22404
+ }
22405
+ return restored;
22406
+ }
21635
22407
  function shouldPersistNewThreadConfigurationSelection(phase) {
21636
22408
  return phase === "draft";
21637
22409
  }
@@ -21698,7 +22470,12 @@ ${error51.stderrTail}`] : []
21698
22470
  throw new Error("DeepSeek Harness Thread reported an incompatible transport Model");
21699
22471
  }
21700
22472
  const model = inspection.effectiveModel ?? transportSelection.model;
21701
- return { agent: "deepseek-harness", ...model ? { model } : {} };
22473
+ const permissionModeId = inspection.effectivePermissionModeId ?? transportSelection.permissionModeId;
22474
+ return {
22475
+ agent: "deepseek-harness",
22476
+ ...model ? { model } : {},
22477
+ ...permissionModeId ? { permissionModeId } : {}
22478
+ };
21702
22479
  }
21703
22480
  throw new Error("Thread owner is not a Renderer Agent");
21704
22481
  }
@@ -21805,7 +22582,10 @@ ${error51.stderrTail}`] : []
21805
22582
  let connectionDiagnostics = null;
21806
22583
  const settingsLifecycle = installRendererSettingsLifecycle(window, {
21807
22584
  getUpdateClient: () => modelControl,
21808
- getConnectionDiagnostics: () => connectionDiagnostics
22585
+ getConnectionDiagnostics: () => connectionDiagnostics,
22586
+ onLocaleChange() {
22587
+ for (const mounted of mountedByComposer.values()) renderMounted(mounted);
22588
+ }
21809
22589
  });
21810
22590
  let adapterStatus = {
21811
22591
  state: "installing",
@@ -21884,8 +22664,15 @@ ${error51.stderrTail}`] : []
21884
22664
  mounted.modelView,
21885
22665
  mounted.permissionModeView,
21886
22666
  mounted.usage,
21887
- mounted.accountCredits
22667
+ mounted.accountCredits,
22668
+ settingsLifecycle.locale
21888
22669
  );
22670
+ if (mounted.control.usage) {
22671
+ mounted.control.usage.onOpen = () => {
22672
+ if (controller.get(mounted.composer).agent === "codex") return;
22673
+ void refreshThreadUsage(mounted, "exact");
22674
+ };
22675
+ }
21889
22676
  };
21890
22677
  const refreshCommands = async (mounted) => {
21891
22678
  const state = controller.get(mounted.composer);
@@ -21931,7 +22718,7 @@ ${error51.stderrTail}`] : []
21931
22718
  renderMounted(mounted);
21932
22719
  }
21933
22720
  };
21934
- const refreshThreadUsage = async (mounted) => {
22721
+ const refreshThreadUsage = async (mounted, refresh) => {
21935
22722
  const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
21936
22723
  if (!threadId || !modelControl) {
21937
22724
  mounted.usage = null;
@@ -21942,7 +22729,10 @@ ${error51.stderrTail}`] : []
21942
22729
  }
21943
22730
  const generation = ++mounted.usageRequestGeneration;
21944
22731
  try {
21945
- const result = await modelControl.inspectThreadUsage({ threadId });
22732
+ const result = await modelControl.inspectThreadUsage({
22733
+ threadId,
22734
+ ...refresh ? { refresh } : {}
22735
+ });
21946
22736
  if (disposed || mountedByComposer.get(mounted.composer) !== mounted || !mounted.composer.isConnected || mounted.usageRequestGeneration !== generation || threadIdFromComposerModelTarget(mounted.modelTarget) !== threadId || result.threadId !== threadId) {
21947
22737
  return;
21948
22738
  }
@@ -22163,11 +22953,15 @@ ${error51.stderrTail}`] : []
22163
22953
  throw new Error("External Harness omitted its Permission Mode catalog");
22164
22954
  }
22165
22955
  mounted.permissionModeView = { status: "loading", catalog: permissionModes };
22166
- const effectivePermissionModeId = current.phase === "locked" ? mounted.threadConfiguration?.effectivePermissionModeId : void 0;
22956
+ const restoredPermissionModeId = current.phase === "locked" ? lockedPermissionMode(
22957
+ permissionModes,
22958
+ mounted.threadConfiguration?.effectivePermissionModeId,
22959
+ previousPermissionModeId
22960
+ ) : void 0;
22167
22961
  const preferredPermissionModeId = preferredConfiguration?.permissionModeId ?? (agent === "claude-code" ? readClaudePermissionModePreference(permissionModes) : void 0);
22168
22962
  selectedPermissionModeId = draftPermissionMode(
22169
22963
  permissionModes,
22170
- effectivePermissionModeId ?? previousPermissionModeId ?? preferredPermissionModeId
22964
+ restoredPermissionModeId ?? previousPermissionModeId ?? preferredPermissionModeId
22171
22965
  );
22172
22966
  mounted.permissionModeView = {
22173
22967
  status: "loading",
@@ -22875,10 +23669,10 @@ ${error51.stderrTail}`] : []
22875
23669
  };
22876
23670
  },
22877
23671
  refresh() {
22878
- for (const hostId of harnessAvailabilityByHost.keys()) {
22879
- void refreshHarnessAvailabilityForHost(hostId, true, false, true);
22880
- }
22881
- return Promise.resolve();
23672
+ return refreshConnectionHosts(
23673
+ harnessAvailabilityByHost.keys(),
23674
+ (hostId) => refreshHarnessAvailabilityForHost(hostId, true, false, true)
23675
+ );
22882
23676
  },
22883
23677
  subscribe(listener) {
22884
23678
  connectionListeners.add(listener);
@@ -23259,9 +24053,6 @@ ${error51.stderrTail}`] : []
23259
24053
  ...permissionModeId ? { permissionModeId } : {}
23260
24054
  };
23261
24055
  },
23262
- requestCompatibilityUpdate() {
23263
- return startCompatibilityUpdate(modelControl);
23264
- },
23265
24056
  setAdapter(status, dispose, applyAgent, nextModelControl) {
23266
24057
  usageNotificationDispose?.();
23267
24058
  usageNotificationDispose = null;
@@ -23389,10 +24180,14 @@ lucide/dist/esm/icons/chevron-down.mjs:
23389
24180
  lucide/dist/esm/icons/shield.mjs:
23390
24181
  lucide/dist/esm/icons/shield-alert.mjs:
23391
24182
  lucide/dist/esm/icons/boxes.mjs:
24183
+ lucide/dist/esm/icons/circle-check.mjs:
24184
+ lucide/dist/esm/icons/chevron-left.mjs:
24185
+ lucide/dist/esm/icons/chevron-right.mjs:
23392
24186
  lucide/dist/esm/icons/circle-off.mjs:
23393
24187
  lucide/dist/esm/icons/copy.mjs:
23394
24188
  lucide/dist/esm/icons/download.mjs:
23395
24189
  lucide/dist/esm/icons/external-link.mjs:
24190
+ lucide/dist/esm/icons/info.mjs:
23396
24191
  lucide/dist/esm/icons/languages.mjs:
23397
24192
  lucide/dist/esm/icons/network.mjs:
23398
24193
  lucide/dist/esm/icons/plug-zap.mjs:
@@ -23401,6 +24196,7 @@ lucide/dist/esm/icons/route.mjs:
23401
24196
  lucide/dist/esm/icons/settings.mjs:
23402
24197
  lucide/dist/esm/icons/stethoscope.mjs:
23403
24198
  lucide/dist/esm/icons/star.mjs:
24199
+ lucide/dist/esm/icons/triangle-alert.mjs:
23404
24200
  lucide/dist/esm/icons/x.mjs:
23405
24201
  (**
23406
24202
  * @license lucide v1.28.0 - ISC