harness-mix 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/README.md +60 -15
  3. package/docs/images/codex-desktop-home.png +0 -0
  4. package/docs/images/codex-desktop-session.png +0 -0
  5. package/docs/multi-agent-collaboration.md +68 -68
  6. package/output/native-build/renderer-extension.js +2225 -1761
  7. package/package.json +1 -2
  8. package/scripts/collaboration-recovery-test.cjs +22 -2
  9. package/scripts/collaboration-ui-smoke.cjs +10 -5
  10. package/scripts/native-protocol-test.cjs +20 -0
  11. package/scripts/workspace-test.cjs +2 -14
  12. package/src/main/adapters/antigravity.js +49 -18
  13. package/src/main/adapters/claude.js +3 -2
  14. package/src/main/adapters/codex.js +10 -8
  15. package/src/main/adapters/dsh.js +3 -2
  16. package/src/main/adapters/opencode.js +21 -13
  17. package/src/main/adapters/pi-family.js +3 -3
  18. package/src/main/host/collaboration-worktree.js +63 -4
  19. package/src/main/host/collaboration.js +28 -2
  20. package/src/main/host/runtime.js +22 -1
  21. package/src/main/native/protocol.js +250 -24
  22. package/src/native-ui/desktop-control/dist/tsconfig.tsbuildinfo +1 -1
  23. package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts.map +1 -1
  24. package/src/native-ui/renderer-extension/dist/types/index.d.ts +2 -0
  25. package/src/native-ui/renderer-extension/dist/types/index.d.ts.map +1 -1
  26. package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts.map +1 -1
  27. package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts +40 -0
  28. package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts.map +1 -0
  29. package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts.map +1 -1
  30. package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts.map +1 -1
  31. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts +8 -0
  32. package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts.map +1 -1
  33. package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts.map +1 -1
  34. package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts +3 -1
  35. package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts.map +1 -1
  36. package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts +8 -1
  37. package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts.map +1 -1
  38. package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts +16 -0
  39. package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts.map +1 -1
  40. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +1 -0
  41. package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -1
  42. package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -1
  43. package/src/native-ui/renderer-extension/src/assets/README.md +8 -38
  44. package/src/native-ui/renderer-extension/src/harness-mix-settings.ts +9 -1
  45. package/src/native-ui/renderer-extension/src/index.ts +9 -0
  46. package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +67 -6
  47. package/src/native-ui/renderer-extension/src/renderer-collab-cards.ts +198 -0
  48. package/src/native-ui/renderer-extension/src/renderer-credits-control.ts +32 -12
  49. package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +139 -46
  50. package/src/native-ui/renderer-extension/src/renderer-model-client.ts +7 -2
  51. package/src/native-ui/renderer-extension/src/renderer-usage-control.ts +34 -3
  52. package/src/native-ui/renderer-extension/src/settings/accounts.css +80 -4
  53. package/src/native-ui/renderer-extension/src/settings/connections-page.ts +68 -29
  54. package/src/native-ui/renderer-extension/src/settings/harness-accounts.ts +89 -28
  55. package/src/native-ui/renderer-extension/src/settings/localization.ts +48 -0
  56. package/src/native-ui/renderer-extension/src/settings/pages.ts +19 -2
  57. package/src/native-ui/renderer-extension/src/settings/shell.css +62 -0
  58. package/src/native-ui/renderer-extension/src/settings/shell.ts +1 -1
  59. package/src/native-ui/renderer-extension/test/renderer-collab-cards.test.ts +45 -0
  60. package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +1 -0
  61. package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts +20 -6
  62. package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts.map +1 -1
  63. package/src/native-ui/shared-contracts/dist/harness-accounts.js +4 -1
  64. package/src/native-ui/shared-contracts/dist/harness-accounts.js.map +1 -1
  65. package/src/native-ui/shared-contracts/dist/harness-models.d.ts +22 -0
  66. package/src/native-ui/shared-contracts/dist/harness-models.d.ts.map +1 -1
  67. package/src/native-ui/shared-contracts/dist/harness-models.js +2 -1
  68. package/src/native-ui/shared-contracts/dist/harness-models.js.map +1 -1
  69. package/src/native-ui/shared-contracts/dist/tsconfig.tsbuildinfo +1 -1
  70. package/src/native-ui/shared-contracts/src/harness-accounts.ts +4 -1
  71. package/src/native-ui/shared-contracts/src/harness-models.ts +6 -1
  72. package/docs/images/harness-mix-home.png +0 -0
  73. package/docs/images/harness-mix-session.png +0 -0
  74. package/scripts/git-test.cjs +0 -33
  75. package/src/assets/icons/activity-compact.svg +0 -1
  76. package/src/assets/icons/activity-edit.svg +0 -1
  77. package/src/assets/icons/activity-terminal.svg +0 -1
  78. package/src/assets/icons/commands.svg +0 -1
  79. package/src/assets/icons/home-chat.svg +0 -1
  80. package/src/assets/icons/home-folder.svg +0 -1
  81. package/src/assets/icons/thread-fork.svg +0 -1
  82. package/src/main/workspace/git.js +0 -73
  83. package/src/main/workspace/ipc.js +0 -50
  84. package/src/main/workspace/terminal.js +0 -34
  85. package/src/native-ui/renderer-extension/src/assets/claude-agent.svg +0 -3
  86. package/src/native-ui/renderer-extension/src/assets/codex-logo-bright.png +0 -0
  87. package/src/native-ui/renderer-extension/src/assets/codex-logo-transparent.png +0 -0
  88. package/src/native-ui/renderer-extension/src/assets/codex-logo.png +0 -0
  89. package/src/native-ui/renderer-extension/src/assets/codexhost-icon.png +0 -0
  90. package/src/native-ui/renderer-extension/src/assets/codexhost-logo-transparent.png +0 -0
  91. package/src/native-ui/renderer-extension/src/assets/codexhost-logo.png +0 -0
  92. package/src/native-ui/renderer-extension/src/assets/codexhost-readme.svg +0 -8
  93. package/src/native-ui/renderer-extension/src/assets/pi-agent.svg +0 -4
  94. package/src/native-ui/renderer-extension/src/settings/accounts-quota-interactive.prototype.html +0 -1418
  95. package/src/native-ui/renderer-extension/src/settings/update-notes.preview.html +0 -491
  96. package/src/native-ui/renderer-extension/src/settings/windows-update.preview.html +0 -2135
@@ -15092,7 +15092,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15092
15092
  email: external_exports.string().trim().min(1).max(320).optional(),
15093
15093
  label: external_exports.string().trim().min(1).max(256).optional(),
15094
15094
  plan: external_exports.string().trim().min(1).max(128).optional(),
15095
- credits: accountCreditsSnapshotSchema
15095
+ status: external_exports.enum(["ready", "unconfigured", "not_installed"]).optional(),
15096
+ configHint: external_exports.string().max(512).optional(),
15097
+ loginCommand: external_exports.string().max(512).optional(),
15098
+ credits: accountCreditsSnapshotSchema.optional()
15096
15099
  }).strict();
15097
15100
  var harnessAccountListParamsSchema = external_exports.object({}).strict();
15098
15101
  var harnessAccountListResultSchema = external_exports.object({
@@ -15417,6 +15420,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15417
15420
  effectivePermissionModeId: harnessPermissionModeIdSchema.optional(),
15418
15421
  history: harnessHistoryCapabilitiesSchema,
15419
15422
  usage: threadUsageSnapshotSchema.optional(),
15423
+ accountCredits: accountCreditsSnapshotSchema.optional(),
15420
15424
  locked: external_exports.literal(true)
15421
15425
  }).strict();
15422
15426
  var threadInspectionSchema = external_exports.discriminatedUnion("owner", [
@@ -16898,7 +16902,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16898
16902
  "deepseek-harness": { command: "pip install deepseek-harness" },
16899
16903
  opencode: { command: "npm install -g opencode-ai" },
16900
16904
  grok: { command: "npm install -g @xai/grok-cli" },
16901
- omp: { command: "npm install -g @oh-my-prompt/omp" },
16905
+ omp: { command: "npm install -g @oh-my-pi/pi-coding-agent" },
16902
16906
  antigravity: { command: "npm install -g @google/antigravity-cli" },
16903
16907
  openclaw: { command: "npm install -g openclaw" },
16904
16908
  hermes: { command: "pip install hermes-agent" },
@@ -17183,45 +17187,72 @@ ${error51.stderrTail}`] : []
17183
17187
  copy.append(title, description);
17184
17188
  head.append(icon2, copy);
17185
17189
  const commandInfo = HARNESS_INSTALL_COMMANDS[agent];
17190
+ const actions = document2.createElement("div");
17191
+ actions.className = "settings-install-actions";
17192
+ const feedback = document2.createElement("div");
17193
+ feedback.className = "settings-install-feedback";
17194
+ const downloadLink = document2.createElement("a");
17195
+ downloadLink.href = HARNESS_INSTALL_URLS[agent];
17196
+ downloadLink.target = "_blank";
17197
+ downloadLink.rel = "noopener noreferrer";
17198
+ downloadLink.append(createRendererSettingsIcon("external-link", 15), messages.officialDownload);
17199
+ const refreshBtn = document2.createElement("button");
17200
+ refreshBtn.type = "button";
17201
+ refreshBtn.className = "settings-command-button settings-command-button--secondary";
17202
+ refreshBtn.append(createRendererSettingsIcon("diagnose", 15), messages.refreshDetection);
17203
+ refreshBtn.addEventListener("click", () => {
17204
+ void diagnostics?.refresh();
17205
+ });
17206
+ if (!commandInfo) {
17207
+ const manualCard = document2.createElement("div");
17208
+ manualCard.className = "settings-install-manual-card";
17209
+ const manualBadge = document2.createElement("div");
17210
+ manualBadge.className = "settings-install-manual-badge";
17211
+ manualBadge.textContent = messages.manualInstallTitle;
17212
+ const manualNotice = document2.createElement("p");
17213
+ manualNotice.className = "settings-install-manual-notice";
17214
+ manualNotice.textContent = messages.manualInstallNotice;
17215
+ const stepsList = document2.createElement("ol");
17216
+ stepsList.className = "settings-install-steps";
17217
+ for (const stepText of [messages.manualInstallStep1, messages.manualInstallStep2, messages.manualInstallStep3]) {
17218
+ const stepItem = document2.createElement("li");
17219
+ stepItem.textContent = stepText;
17220
+ stepsList.append(stepItem);
17221
+ }
17222
+ manualCard.append(manualBadge, manualNotice, stepsList);
17223
+ downloadLink.className = "settings-command-button";
17224
+ actions.append(downloadLink, refreshBtn);
17225
+ section.append(head, manualCard, actions, feedback);
17226
+ container.append(section);
17227
+ return;
17228
+ }
17186
17229
  const commandBox = document2.createElement("div");
17187
17230
  commandBox.className = "settings-install-command-box";
17188
- commandBox.hidden = !commandInfo;
17189
17231
  const commandLabel = document2.createElement("span");
17190
17232
  commandLabel.className = "settings-install-command-label";
17191
17233
  commandLabel.textContent = messages.installCommandLabel;
17192
17234
  const commandRow = document2.createElement("div");
17193
17235
  commandRow.className = "settings-install-command-row";
17194
17236
  const code = document2.createElement("code");
17195
- code.textContent = commandInfo?.command ?? `npm install -g ${agent}`;
17237
+ code.textContent = commandInfo.command;
17196
17238
  commandRow.append(code);
17197
17239
  commandBox.append(commandLabel, commandRow);
17198
- const actions = document2.createElement("div");
17199
- actions.className = "settings-install-actions";
17240
+ downloadLink.className = "settings-command-button settings-command-button--secondary";
17200
17241
  const installBtn = document2.createElement("button");
17201
17242
  installBtn.type = "button";
17202
- installBtn.hidden = !commandInfo;
17203
- installBtn.disabled = !commandInfo;
17204
17243
  installBtn.className = "settings-command-button";
17205
17244
  installBtn.append(createRendererSettingsIcon("download", 15), messages.oneClickInstall);
17245
+ const terminalBtn = document2.createElement("button");
17246
+ terminalBtn.type = "button";
17247
+ terminalBtn.className = "settings-command-button settings-command-button--secondary";
17248
+ terminalBtn.append(createRendererSettingsIcon("external-link", 15), messages.installInTerminal);
17249
+ terminalBtn.title = messages.installInTerminal;
17206
17250
  const copyBtn = document2.createElement("button");
17207
17251
  copyBtn.type = "button";
17208
- copyBtn.hidden = !commandInfo;
17209
17252
  copyBtn.className = "settings-command-button settings-command-button--secondary";
17210
17253
  copyBtn.append(createRendererSettingsIcon("copy", 15), messages.copyInstallCommand);
17211
- const downloadLink = document2.createElement("a");
17212
- downloadLink.className = "settings-command-button settings-command-button--secondary";
17213
- downloadLink.href = HARNESS_INSTALL_URLS[agent];
17214
- downloadLink.target = "_blank";
17215
- downloadLink.rel = "noopener noreferrer";
17216
- downloadLink.append(createRendererSettingsIcon("external-link", 15), messages.officialDownload);
17217
- const refreshBtn = document2.createElement("button");
17218
- refreshBtn.type = "button";
17219
- refreshBtn.className = "settings-command-button settings-command-button--secondary";
17220
- refreshBtn.append(createRendererSettingsIcon("diagnose", 15), messages.refreshDetection);
17221
- const feedback = document2.createElement("div");
17222
- feedback.className = "settings-install-feedback";
17223
17254
  copyBtn.addEventListener("click", () => {
17224
- const text = commandInfo?.command ?? `npm install -g ${agent}`;
17255
+ const text = commandInfo.command;
17225
17256
  const clipboard = document2.defaultView?.navigator?.clipboard;
17226
17257
  if (clipboard) {
17227
17258
  void clipboard.writeText(text).then(() => {
@@ -17232,8 +17263,12 @@ ${error51.stderrTail}`] : []
17232
17263
  });
17233
17264
  }
17234
17265
  });
17235
- refreshBtn.addEventListener("click", () => {
17236
- void diagnostics?.refresh();
17266
+ terminalBtn.addEventListener("click", () => {
17267
+ feedback.className = "settings-install-feedback settings-feedback-success";
17268
+ feedback.textContent = messages.terminalInstalling;
17269
+ if (diagnostics?.installHarness) {
17270
+ void diagnostics.installHarness(hostId, agent, { terminal: true });
17271
+ }
17237
17272
  });
17238
17273
  installBtn.addEventListener("click", () => {
17239
17274
  if (installBtn.disabled) return;
@@ -17243,7 +17278,7 @@ ${error51.stderrTail}`] : []
17243
17278
  feedback.className = "settings-install-feedback";
17244
17279
  const run = async () => {
17245
17280
  if (!diagnostics?.installHarness) {
17246
- const text = commandInfo?.command ?? `npm install -g ${agent}`;
17281
+ const text = commandInfo.command;
17247
17282
  await document2.defaultView?.navigator?.clipboard?.writeText(text);
17248
17283
  feedback.className = "settings-install-feedback settings-feedback-warning";
17249
17284
  feedback.textContent = messages.oneClickInstallFailed;
@@ -17275,7 +17310,7 @@ ${error51.stderrTail}`] : []
17275
17310
  };
17276
17311
  void run();
17277
17312
  });
17278
- actions.append(installBtn, copyBtn, downloadLink, refreshBtn);
17313
+ actions.append(installBtn, terminalBtn, copyBtn, downloadLink, refreshBtn);
17279
17314
  section.append(head, commandBox, actions, feedback);
17280
17315
  container.append(section);
17281
17316
  }
@@ -18099,6 +18134,22 @@ ${error51.stderrTail}`] : []
18099
18134
  oneClickInstalling: "Installing Harness in background...",
18100
18135
  oneClickInstallSuccess: "Installed successfully! Status refreshed.",
18101
18136
  oneClickInstallFailed: "Installation failed. Please try running the command manually.",
18137
+ installInTerminal: "Install in Terminal",
18138
+ terminalInstalling: "Installation launched in a visible terminal window. Click Refresh when done.",
18139
+ manualInstallTitle: "Standalone Application / Manual Install",
18140
+ manualInstallNotice: "This Harness is a standalone desktop application or binary and must be installed via its official installer.",
18141
+ manualInstallStep1: "1. Click the button below to visit the official website and download the installer.",
18142
+ manualInstallStep2: "2. Run the application and complete its authentication login.",
18143
+ manualInstallStep3: "3. Ensure its CLI executable is in your PATH environment variable, then click Refresh.",
18144
+ harnessAccountsPageTitle: "Harness Account Management",
18145
+ harnessAccountsPageDescription: "View and manage login status, credentials, and usage quotas for each native harness. Credentials remain stored locally by each harness.",
18146
+ harnessAccountLogin: "Log In / Authorize",
18147
+ harnessAccountLoginStarted: "Login launched in terminal window. Click Refresh when done.",
18148
+ harnessAccountConfigGuide: "Credential Guide",
18149
+ harnessAccountStatusReady: "Ready",
18150
+ harnessAccountStatusUnconfigured: "Needs Config / Not Logged In",
18151
+ harnessAccountStatusNotInstalled: "Not Installed",
18152
+ checkUpdateNow: "Check for Updates Now",
18102
18153
  installCommandLabel: "Install Command",
18103
18154
  copyInstallCommand: "Copy Command",
18104
18155
  installCommandCopied: "Command Copied",
@@ -18323,6 +18374,22 @@ ${error51.stderrTail}`] : []
18323
18374
  oneClickInstalling: "\u6B63\u5728\u540E\u53F0\u5B89\u88C5 Harness\u2026\u2026",
18324
18375
  oneClickInstallSuccess: "\u5B89\u88C5\u6210\u529F\uFF01\u72B6\u6001\u5DF2\u81EA\u52A8\u5237\u65B0\u3002",
18325
18376
  oneClickInstallFailed: "\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u5C1D\u8BD5\u590D\u5236\u4E0B\u65B9\u547D\u4EE4\u5728\u7EC8\u7AEF\u624B\u52A8\u8FD0\u884C\u3002",
18377
+ installInTerminal: "\u5728\u7EC8\u7AEF\u4E2D\u6253\u5F00\u5B89\u88C5",
18378
+ terminalInstalling: "\u5DF2\u5728\u72EC\u7ACB\u7EC8\u7AEF\u7A97\u53E3\u542F\u52A8\u5B89\u88C5\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u5B8C\u6210\u540E\u70B9\u51FB\u5237\u65B0\u68C0\u6D4B\u3002",
18379
+ manualInstallTitle: "\u72EC\u7ACB\u5B89\u88C5\u7A0B\u5E8F / \u624B\u52A8\u5B89\u88C5\u6307\u5F15",
18380
+ manualInstallNotice: "\u6B64 Harness \u4E3A\u72EC\u7ACB\u5BA2\u6237\u7AEF\u7A0B\u5E8F\u6216\u4E8C\u8FDB\u5236\u5DE5\u5177\uFF0C\u4E0D\u652F\u6301\u901A\u8FC7 npm \u4E00\u952E\u5B89\u88C5\u3002",
18381
+ manualInstallStep1: "1. \u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u524D\u5F80\u5B98\u7F51\u4E0B\u8F7D\u5B89\u88C5\u5305\u5E76\u5B8C\u6210\u5B89\u88C5\uFF1B",
18382
+ manualInstallStep2: "2. \u8FD0\u884C\u5E94\u7528\u5E76\u5728\u7EC8\u7AEF\u4E2D\u5B8C\u6210\u8BE5 Harness \u7684\u8BA4\u8BC1\u767B\u5F55\uFF1B",
18383
+ manualInstallStep3: "3. \u786E\u4FDD\u8BE5 CLI \u53EF\u6267\u884C\u6587\u4EF6\u5DF2\u52A0\u5165\u7CFB\u7EDF PATH \u73AF\u5883\u53D8\u91CF\uFF0C\u7136\u540E\u70B9\u51FB\u3010\u5237\u65B0\u68C0\u6D4B\u3011\u3002",
18384
+ harnessAccountsPageTitle: "Harness \u8D26\u53F7\u4E0E\u6388\u6743\u7BA1\u7406",
18385
+ harnessAccountsPageDescription: "\u67E5\u770B\u4E0E\u7BA1\u7406\u5404\u539F\u751F Harness \u7684\u767B\u5F55\u72B6\u6001\u3001\u6388\u6743\u51ED\u636E\u4E0E\u6A21\u578B\u7528\u91CF\u914D\u989D\u3002\u6240\u6709\u8BA4\u8BC1\u5747\u4FDD\u5B58\u5728\u672C\u5730\u539F\u751F Harness \u4E2D\uFF0CHarness Mix \u7EDD\u4E0D\u4EE3\u5B58\u60A8\u7684\u8D26\u53F7\u5BC6\u7801\u3002",
18386
+ harnessAccountLogin: "\u767B\u5F55 / \u6388\u6743",
18387
+ harnessAccountLoginStarted: "\u5DF2\u5728\u7EC8\u7AEF\u7A97\u53E3\u542F\u52A8\u767B\u5F55\u8BA4\u8BC1\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u5B8C\u6210\u540E\u70B9\u51FB\u5237\u65B0\u72B6\u6001\u3002",
18388
+ harnessAccountConfigGuide: "\u51ED\u636E\u914D\u7F6E\u6307\u5F15",
18389
+ harnessAccountStatusReady: "\u5DF2\u5C31\u7EEA",
18390
+ harnessAccountStatusUnconfigured: "\u5F85\u914D\u7F6E / \u672A\u767B\u5F55",
18391
+ harnessAccountStatusNotInstalled: "\u672A\u5B89\u88C5",
18392
+ checkUpdateNow: "\u7ACB\u5373\u68C0\u67E5\u66F4\u65B0",
18326
18393
  installCommandLabel: "\u63A8\u8350\u5B89\u88C5\u547D\u4EE4",
18327
18394
  copyInstallCommand: "\u590D\u5236\u5B89\u88C5\u547D\u4EE4",
18328
18395
  installCommandCopied: "\u5DF2\u590D\u5236\u547D\u4EE4",
@@ -20262,13 +20329,18 @@ ${error51.stderrTail}`] : []
20262
20329
  trigger.style.lineHeight = "16px";
20263
20330
  trigger.style.fontVariantNumeric = "tabular-nums";
20264
20331
  trigger.style.letterSpacing = "0";
20332
+ const ringSlot = document.createElement("span");
20333
+ ringSlot.dataset.codexhostUsageRing = "";
20334
+ ringSlot.style.display = "inline-flex";
20335
+ ringSlot.style.flex = "0 0 auto";
20336
+ ringSlot.style.alignItems = "center";
20265
20337
  const label = document.createElement("span");
20266
20338
  label.style.display = "inline-block";
20267
20339
  label.style.maxWidth = "100%";
20268
20340
  label.style.overflow = "hidden";
20269
20341
  label.style.textOverflow = "ellipsis";
20270
20342
  label.style.whiteSpace = "nowrap";
20271
- trigger.append(label);
20343
+ trigger.append(ringSlot, label);
20272
20344
  const popover = document.createElement("div");
20273
20345
  popover.id = `${composerId}-usage-popover`;
20274
20346
  popover.setAttribute("role", "dialog");
@@ -20364,14 +20436,31 @@ ${error51.stderrTail}`] : []
20364
20436
  closePopover(control);
20365
20437
  return false;
20366
20438
  }
20439
+ const ringSlot = control.trigger.querySelector("[data-codexhost-usage-ring]");
20440
+ const contextPercent = usage?.contextUsagePercent !== void 0 ? usage.contextUsagePercent : hasContext && usage?.contextWindowTokens !== void 0 && usage.contextWindowTokens > 0 ? Math.round(100 * (usage.contextUsedTokens ?? 0) / usage.contextWindowTokens * 10) / 10 : void 0;
20441
+ if (contextPercent !== void 0) {
20442
+ const tone = contextPercent >= 90 ? "hot" : contextPercent >= 70 ? "warn" : "ok";
20443
+ const color = tone === "hot" ? "#c45c4a" : tone === "warn" ? "#c9a227" : "#3d9a64";
20444
+ if (ringSlot) {
20445
+ ringSlot.replaceChildren(
20446
+ createRendererUsageRing(contextPercent, {
20447
+ size: 14,
20448
+ strokeWidth: 2.4,
20449
+ color
20450
+ })
20451
+ );
20452
+ }
20453
+ } else if (ringSlot) {
20454
+ ringSlot.replaceChildren();
20455
+ }
20456
+ const percentLabel = contextPercent !== void 0 ? `${decimal(contextPercent, 1)}%` : null;
20367
20457
  const summary = [
20458
+ percentLabel,
20368
20459
  usage?.totalCredits !== void 0 ? formatRendererCredits(usage.totalCredits) : null,
20369
20460
  cacheHitRatePercent !== void 0 ? formatRendererCacheHitRate(cacheHitRatePercent) : null,
20370
20461
  outputTokensPerSecond !== void 0 ? formatRendererTokenRate(outputTokensPerSecond, locale) : null,
20371
20462
  totalCostUsd !== void 0 ? formatRendererCost(totalCostUsd) : null
20372
20463
  ].filter((value) => value !== null);
20373
- const contextPercent = usage?.contextUsagePercent;
20374
- if (contextPercent !== void 0 && summary.length === 0) summary.push(messages.usage);
20375
20464
  if (summary.length === 0 && hasContext && usage?.contextWindowTokens !== void 0 && usage.contextWindowTokens > 0) {
20376
20465
  summary.push(
20377
20466
  formatRendererContextSummary(usage.contextUsedTokens ?? 0, usage.contextWindowTokens)
@@ -20456,13 +20545,20 @@ ${error51.stderrTail}`] : []
20456
20545
  if (product === "GrokImagine") return "Imagine";
20457
20546
  if (product === "GrokVoice") return "Voice";
20458
20547
  const messages = rendererCreditsMessages(locale);
20459
- if (product === "5-hour window") return messages.fiveHour;
20460
- if (product === "7-day window") return messages.sevenDay;
20461
- if (product.endsWith(" \xB7 5-hour window")) {
20462
- return `${product.slice(0, -"5-hour window".length)}${messages.fiveHour}`;
20548
+ if (product === "5-hour window" || product === "5h window") return messages.fiveHour;
20549
+ if (product === "7-day window" || product === "7d window") return messages.sevenDay;
20550
+ if (product === "Weekly window" || product === "weekly window") return messages.weekly;
20551
+ if (product.endsWith(" \xB7 5-hour window") || product.endsWith(" \xB7 5h window")) {
20552
+ const prefix = product.replace(/ · 5(-hour|h) window$/i, "");
20553
+ return `${prefix} \xB7 ${messages.fiveHour}`;
20463
20554
  }
20464
- if (product.endsWith(" \xB7 7-day window")) {
20465
- return `${product.slice(0, -"7-day window".length)}${messages.sevenDay}`;
20555
+ if (product.endsWith(" \xB7 7-day window") || product.endsWith(" \xB7 7d window")) {
20556
+ const prefix = product.replace(/ · 7(-day|d) window$/i, "");
20557
+ return `${prefix} \xB7 ${messages.sevenDay}`;
20558
+ }
20559
+ if (product.endsWith(" \xB7 Weekly window") || product.endsWith(" \xB7 weekly window")) {
20560
+ const prefix = product.replace(/ · (weekly|Weekly) window$/i, "");
20561
+ return `${prefix} \xB7 ${messages.weekly}`;
20466
20562
  }
20467
20563
  return product;
20468
20564
  }
@@ -20479,7 +20575,7 @@ ${error51.stderrTail}`] : []
20479
20575
  track.dataset.codexhostCreditsBar = "";
20480
20576
  track.style.height = "6px";
20481
20577
  track.style.borderRadius = "9999px";
20482
- track.style.background = "color-mix(in srgb, currentColor 16%, transparent)";
20578
+ track.style.background = "color-mix(in srgb, currentColor 12%, transparent)";
20483
20579
  track.style.overflow = "hidden";
20484
20580
  const fill = document.createElement("span");
20485
20581
  fill.style.display = "block";
@@ -20487,6 +20583,7 @@ ${error51.stderrTail}`] : []
20487
20583
  fill.style.borderRadius = "9999px";
20488
20584
  fill.style.width = `${Math.min(100, Math.max(0, usagePercent))}%`;
20489
20585
  fill.style.background = color;
20586
+ fill.style.transition = "width 0.25s ease";
20490
20587
  track.append(fill);
20491
20588
  return track;
20492
20589
  }
@@ -20496,17 +20593,21 @@ ${error51.stderrTail}`] : []
20496
20593
  }
20497
20594
  function renderCreditsHeader(credits, locale, messages) {
20498
20595
  const wrapper = document.createElement("div");
20499
- wrapper.style.marginBottom = "11px";
20596
+ wrapper.style.marginBottom = "10px";
20597
+ wrapper.style.padding = "8px 10px";
20598
+ wrapper.style.borderRadius = "10px";
20599
+ wrapper.style.background = "color-mix(in srgb, currentColor 5%, transparent)";
20600
+ wrapper.style.border = "1px solid color-mix(in srgb, currentColor 7%, transparent)";
20500
20601
  const top = document.createElement("div");
20501
20602
  top.style.display = "flex";
20502
20603
  top.style.alignItems = "flex-start";
20503
20604
  top.style.justifyContent = "space-between";
20504
20605
  top.style.gap = "12px";
20505
- top.style.marginBottom = "5px";
20606
+ top.style.marginBottom = "6px";
20506
20607
  const left = document.createElement("div");
20507
20608
  const label = document.createElement("div");
20508
20609
  label.textContent = creditsPeriodLabel(credits.periodType, locale);
20509
- label.style.fontSize = "12.5px";
20610
+ label.style.fontSize = "13px";
20510
20611
  label.style.fontWeight = "600";
20511
20612
  left.append(label);
20512
20613
  if (credits.resetsAt) {
@@ -20514,6 +20615,7 @@ ${error51.stderrTail}`] : []
20514
20615
  reset.textContent = resetLabel(credits.resetsAt, locale, messages);
20515
20616
  reset.style.fontSize = "11px";
20516
20617
  reset.style.color = "color-mix(in srgb, currentColor 62%, transparent)";
20618
+ reset.style.marginTop = "2px";
20517
20619
  left.append(reset);
20518
20620
  }
20519
20621
  const color = toneColor(rendererCreditsTone(credits.usedPercent));
@@ -20531,7 +20633,7 @@ ${error51.stderrTail}`] : []
20531
20633
  remainingLabel.style.opacity = "0.8";
20532
20634
  const remainingValue = document.createElement("span");
20533
20635
  remainingValue.textContent = formatRendererCreditsPercent(remaining);
20534
- remainingValue.style.fontSize = "26px";
20636
+ remainingValue.style.fontSize = "24px";
20535
20637
  remainingValue.style.fontWeight = "700";
20536
20638
  remainingValue.style.fontVariantNumeric = "tabular-nums";
20537
20639
  percent.append(remainingLabel, remainingValue);
@@ -20543,7 +20645,11 @@ ${error51.stderrTail}`] : []
20543
20645
  const color = toneColor(rendererCreditsTone(usagePercent));
20544
20646
  const remaining = remainingPercent(usagePercent);
20545
20647
  const tile = document.createElement("div");
20546
- tile.style.marginBottom = "11px";
20648
+ tile.style.marginBottom = "7px";
20649
+ tile.style.padding = "7px 9px";
20650
+ tile.style.borderRadius = "8px";
20651
+ tile.style.background = "color-mix(in srgb, currentColor 4%, transparent)";
20652
+ tile.style.border = "1px solid color-mix(in srgb, currentColor 6%, transparent)";
20547
20653
  const top = document.createElement("div");
20548
20654
  top.style.display = "flex";
20549
20655
  top.style.alignItems = "flex-start";
@@ -20554,17 +20660,20 @@ ${error51.stderrTail}`] : []
20554
20660
  const name = document.createElement("span");
20555
20661
  name.textContent = label;
20556
20662
  name.style.fontSize = "12px";
20663
+ name.style.fontWeight = "500";
20557
20664
  left.append(name);
20558
20665
  if (resetsAt) {
20559
20666
  const reset = document.createElement("div");
20560
20667
  reset.textContent = resetLabel(resetsAt, locale, messages);
20561
20668
  reset.style.fontSize = "10.5px";
20562
20669
  reset.style.color = "color-mix(in srgb, currentColor 62%, transparent)";
20670
+ reset.style.marginTop = "2px";
20563
20671
  left.append(reset);
20564
20672
  }
20565
20673
  const percent = document.createElement("span");
20566
20674
  percent.textContent = `${messages.remaining} ${formatRendererCreditsPercent(remaining)}`;
20567
20675
  percent.style.fontSize = "12px";
20676
+ percent.style.fontWeight = "600";
20568
20677
  percent.style.fontVariantNumeric = "tabular-nums";
20569
20678
  percent.style.color = color;
20570
20679
  top.append(left, percent);
@@ -22612,6 +22721,10 @@ ${error51.stderrTail}`] : []
22612
22721
  const result = await manager.sendRequest(HARNESS_INSTALL_METHOD, input);
22613
22722
  return result;
22614
22723
  },
22724
+ async loginHarnessAccount(input) {
22725
+ const result = await manager.sendRequest("codexhost/harness/account/login", input);
22726
+ return result;
22727
+ },
22615
22728
  async listHarnessPlugins() {
22616
22729
  return harnessPluginListResultSchema.parse(
22617
22730
  await manager.sendRequest(HARNESS_PLUGIN_LIST_METHOD, {})
@@ -23597,6 +23710,8 @@ ${error51.stderrTail}`] : []
23597
23710
  }
23598
23711
 
23599
23712
  // src/native-ui/renderer-extension/src/renderer-harness-mentions.ts
23713
+ var entryKey = (entry) => entry.kind === "agent" ? `agent:${entry.id}` : `session:${entry.id}`;
23714
+ var entryLiteral = (entry) => entry.kind === "agent" ? `@${entry.id} ` : `@[${entry.title.replace(/[\[\]()\r\n]/g, "")}](harness-mix://session/${entry.id}) `;
23600
23715
  function installHarnessMentions(load) {
23601
23716
  const menu = document.createElement("div");
23602
23717
  menu.dataset.harnessMixMentions = "true";
@@ -23616,20 +23731,56 @@ ${error51.stderrTail}`] : []
23616
23731
  let matches = [], activeKind = "agent", canDelegate = true;
23617
23732
  const catalogs = /* @__PURE__ */ new Map();
23618
23733
  const badges = /* @__PURE__ */ new Map();
23734
+ const selections = /* @__PURE__ */ new Map();
23735
+ const selectionsFor = (target) => {
23736
+ let perEditor = selections.get(target);
23737
+ if (!perEditor) {
23738
+ perEditor = /* @__PURE__ */ new Map();
23739
+ selections.set(target, perEditor);
23740
+ }
23741
+ return perEditor;
23742
+ };
23743
+ const replaceSelectionWith = (target, replacement) => {
23744
+ if (target instanceof HTMLTextAreaElement) {
23745
+ target.setSelectionRange(start, end);
23746
+ target.setRangeText(replacement, start, end, "end");
23747
+ target.dispatchEvent(new Event("input", { bubbles: true }));
23748
+ return true;
23749
+ }
23750
+ const fresh = document.createRange();
23751
+ const walker = document.createTreeWalker(target, NodeFilter.SHOW_TEXT);
23752
+ let offset = 0, foundStart = false, foundEnd = false;
23753
+ for (let node = walker.nextNode(); node; node = walker.nextNode()) {
23754
+ const length = node.textContent?.length ?? 0;
23755
+ if (!foundStart && start <= offset + length) {
23756
+ fresh.setStart(node, start - offset);
23757
+ foundStart = true;
23758
+ }
23759
+ if (foundStart && end <= offset + length) {
23760
+ fresh.setEnd(node, end - offset);
23761
+ foundEnd = true;
23762
+ break;
23763
+ }
23764
+ offset += length;
23765
+ }
23766
+ if (!foundEnd) return false;
23767
+ const selection = window.getSelection();
23768
+ selection?.removeAllRanges();
23769
+ selection?.addRange(fresh);
23770
+ document.dispatchEvent(new Event("selectionchange"));
23771
+ document.execCommand("insertText", false, replacement);
23772
+ return true;
23773
+ };
23619
23774
  const syncBadges = (target) => {
23620
23775
  for (const [old, strip2] of badges) if (!old.isConnected) {
23621
23776
  strip2.remove();
23622
23777
  badges.delete(old);
23623
23778
  catalogs.delete(old);
23624
23779
  }
23625
- const text = (target instanceof HTMLTextAreaElement ? target.value : target.textContent ?? "").replace(/```[\s\S]*?```|`[^`\n]*`/g, "");
23626
- const ids = new Set([...text.matchAll(/(?:^|[\s,。;:])@([\w-]+)(?=$|[\s,。;:])/g)].map((m) => m[1]));
23627
- const catalog = catalogs.get(target) ?? { agents: [], sessions: [] };
23628
- const selectedAgents = catalog.agents.filter((a) => ids.has(a.id));
23629
- const sessionIds = new Set([...text.matchAll(/\]\(harness-mix:\/\/session\/([A-Za-z0-9_-]+)\)/g)].map((match) => match[1]));
23630
- const selectedSessions = catalog.sessions.filter((session) => sessionIds.has(session.id));
23780
+ const perEditor = selections.get(target);
23781
+ const hasAny = !!perEditor && perEditor.size > 0;
23631
23782
  let strip = badges.get(target);
23632
- if (!strip && !selectedAgents.length && !selectedSessions.length) return;
23783
+ if (!strip && !hasAny) return;
23633
23784
  if (!strip) {
23634
23785
  strip = document.createElement("div");
23635
23786
  strip.dataset.harnessMixSelectedMentions = "true";
@@ -23639,19 +23790,48 @@ ${error51.stderrTail}`] : []
23639
23790
  badges.set(target, strip);
23640
23791
  }
23641
23792
  strip.replaceChildren();
23642
- strip.style.display = selectedAgents.length || selectedSessions.length ? "flex" : "none";
23643
- for (const agent of selectedAgents) {
23644
- const badge = document.createElement("span");
23645
- badge.style.cssText = "display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid #8883;border-radius:8px;font:12px inherit;background:#8881";
23646
- badge.append(collaborationIcon(agent.id, agent.name, 16), document.createTextNode(agent.name));
23647
- badge.title = `@${agent.id}${agent.available ? "" : " \xB7 \u672A\u5C31\u7EEA"}`;
23648
- strip.append(badge);
23649
- }
23650
- for (const session of selectedSessions) {
23793
+ strip.style.display = hasAny ? "flex" : "none";
23794
+ if (!perEditor) return;
23795
+ for (const entry of perEditor.values()) {
23651
23796
  const badge = document.createElement("span");
23797
+ badge.dataset.harnessMixMentionBadge = entry.kind === "agent" ? `agent:${entry.id}` : `session:${entry.id}`;
23652
23798
  badge.style.cssText = "display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid #8883;border-radius:8px;font:12px inherit;background:#8881";
23653
- badge.append(collaborationIcon(session.harnessId, session.harnessId, 16), document.createTextNode(session.title));
23654
- badge.title = `\u5386\u53F2\u4F1A\u8BDD \xB7 ${session.cwd}`;
23799
+ const iconWrap = document.createElement("span");
23800
+ iconWrap.style.cssText = "display:inline-flex;align-items:center;gap:6px";
23801
+ iconWrap.append(
23802
+ collaborationIcon(entry.kind === "agent" ? entry.id : entry.harnessId, entry.kind === "agent" ? entry.name : entry.title, 16),
23803
+ document.createTextNode(entry.kind === "agent" ? entry.name : entry.title)
23804
+ );
23805
+ const remove = document.createElement("button");
23806
+ remove.type = "button";
23807
+ remove.dataset.harnessMixMentionRemove = entry.kind === "agent" ? `agent:${entry.id}` : `session:${entry.id}`;
23808
+ const removeLabel = entry.kind === "agent" ? `\u79FB\u9664 ${entry.name}` : `\u79FB\u9664\u4F1A\u8BDD ${entry.title}`;
23809
+ remove.setAttribute("aria-label", removeLabel);
23810
+ remove.title = removeLabel;
23811
+ remove.textContent = "\xD7";
23812
+ remove.style.cssText = "border:0;background:transparent;color:inherit;cursor:pointer;padding:0 0 0 2px;margin:0;font:600 14px/1 inherit;opacity:.55;line-height:1;display:inline-flex;align-items:center;justify-content:center;width:14px;height:14px;border-radius:50%";
23813
+ remove.addEventListener("mouseenter", () => {
23814
+ remove.style.opacity = "1";
23815
+ remove.style.background = "#8883";
23816
+ });
23817
+ remove.addEventListener("mouseleave", () => {
23818
+ remove.style.opacity = ".55";
23819
+ remove.style.background = "transparent";
23820
+ });
23821
+ remove.addEventListener("mousedown", (event) => {
23822
+ event.preventDefault();
23823
+ event.stopPropagation();
23824
+ });
23825
+ remove.addEventListener("click", (event) => {
23826
+ event.preventDefault();
23827
+ event.stopPropagation();
23828
+ const live = selections.get(target);
23829
+ if (!live) return;
23830
+ live.delete(entryKey(entry));
23831
+ syncBadges(target);
23832
+ });
23833
+ badge.append(iconWrap, remove);
23834
+ badge.title = entry.kind === "agent" ? `@${entry.id}${entry.available ? "" : " \xB7 \u672A\u5C31\u7EEA"}` : `\u5386\u53F2\u4F1A\u8BDD \xB7 ${entry.cwd}`;
23655
23835
  strip.append(badge);
23656
23836
  }
23657
23837
  };
@@ -23664,40 +23844,13 @@ ${error51.stderrTail}`] : []
23664
23844
  const choose = (entry) => {
23665
23845
  if (!editor || (entry.kind === "agent" ? !entry.available || !canDelegate : entry.running === true)) return;
23666
23846
  const target = editor;
23667
- const inserted = entry.kind === "agent" ? `@${entry.id} ` : `@[${entry.title.replace(/[\[\]()\r\n]/g, "")}](harness-mix://session/${entry.id}) `;
23668
23847
  close();
23669
23848
  target.focus();
23670
- if (target instanceof HTMLTextAreaElement) {
23671
- target.setSelectionRange(start, end);
23672
- if (!document.execCommand("insertText", false, inserted)) {
23673
- target.setRangeText(inserted, start, end, "end");
23674
- target.dispatchEvent(new Event("input", { bubbles: true }));
23675
- }
23676
- } else if (range) {
23677
- const replacement = document.createRange();
23678
- const walker = document.createTreeWalker(target, NodeFilter.SHOW_TEXT);
23679
- let offset = 0, foundStart = false, foundEnd = false;
23680
- for (let node = walker.nextNode(); node; node = walker.nextNode()) {
23681
- const length = node.textContent?.length ?? 0;
23682
- if (!foundStart && start <= offset + length) {
23683
- replacement.setStart(node, start - offset);
23684
- foundStart = true;
23685
- }
23686
- if (foundStart && end <= offset + length) {
23687
- replacement.setEnd(node, end - offset);
23688
- foundEnd = true;
23689
- break;
23690
- }
23691
- offset += length;
23692
- }
23693
- if (!foundEnd) return;
23694
- const selection = window.getSelection();
23695
- selection?.removeAllRanges();
23696
- selection?.addRange(replacement);
23697
- document.dispatchEvent(new Event("selectionchange"));
23698
- document.execCommand("insertText", false, inserted);
23699
- }
23700
- target.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", code: "Escape", bubbles: true, cancelable: true }));
23849
+ replaceSelectionWith(target, "");
23850
+ const perEditor = selectionsFor(target);
23851
+ const key = entryKey(entry);
23852
+ if (perEditor.has(key)) perEditor.delete(key);
23853
+ else perEditor.set(key, entry);
23701
23854
  syncBadges(target);
23702
23855
  };
23703
23856
  const render = () => {
@@ -23861,9 +24014,45 @@ ${error51.stderrTail}`] : []
23861
24014
  const outside = (event) => {
23862
24015
  if (event.target instanceof Node && !menu.contains(event.target)) close();
23863
24016
  };
24017
+ const findEditorIn = (root) => {
24018
+ if (!root) return null;
24019
+ if (root.matches('textarea,[contenteditable="true"]')) return root;
24020
+ return root.querySelector('textarea,[contenteditable="true"]');
24021
+ };
24022
+ const injectMentionsInto = (target) => {
24023
+ const perEditor = selections.get(target);
24024
+ if (!perEditor || perEditor.size === 0) return false;
24025
+ const text = [...perEditor.values()].map(entryLiteral).join("");
24026
+ if (!text) return false;
24027
+ target.focus();
24028
+ if (target instanceof HTMLTextAreaElement) {
24029
+ target.value = `${text}${target.value}`;
24030
+ target.dispatchEvent(new Event("input", { bubbles: true }));
24031
+ target.dispatchEvent(new Event("change", { bubbles: true }));
24032
+ return true;
24033
+ }
24034
+ const selection = window.getSelection();
24035
+ const fresh = document.createRange();
24036
+ fresh.selectNodeContents(target);
24037
+ fresh.collapse(true);
24038
+ selection?.removeAllRanges();
24039
+ selection?.addRange(fresh);
24040
+ document.dispatchEvent(new Event("selectionchange"));
24041
+ document.execCommand("insertText", false, text);
24042
+ return true;
24043
+ };
24044
+ const onSubmitCapture = (event) => {
24045
+ const composerRoot = (event.target instanceof Element ? event.target : null)?.closest?.("[data-codex-composer-root]");
24046
+ const candidate = composerRoot ?? (event.target instanceof Element ? event.target : null);
24047
+ const editorEl = findEditorIn(candidate);
24048
+ if (!editorEl) return;
24049
+ if (!editorEl.closest("[data-codex-composer-root]")) return;
24050
+ injectMentionsInto(editorEl);
24051
+ };
23864
24052
  document.addEventListener("input", input, true);
23865
24053
  document.addEventListener("keydown", keydown, true);
23866
24054
  document.addEventListener("mousedown", outside);
24055
+ document.addEventListener("submit", onSubmitCapture, true);
23867
24056
  window.addEventListener("blur", close);
23868
24057
  return { dispose() {
23869
24058
  disposed = true;
@@ -23873,1755 +24062,1972 @@ ${error51.stderrTail}`] : []
23873
24062
  for (const strip of badges.values()) strip.remove();
23874
24063
  badges.clear();
23875
24064
  catalogs.clear();
24065
+ for (const [target, perEditor] of selections) if (!target.isConnected) selections.delete(target);
23876
24066
  document.removeEventListener("input", input, true);
23877
24067
  document.removeEventListener("keydown", keydown, true);
23878
24068
  document.removeEventListener("mousedown", outside);
24069
+ document.removeEventListener("submit", onSubmitCapture, true);
23879
24070
  window.removeEventListener("blur", close);
23880
24071
  } };
23881
24072
  }
23882
24073
 
23883
- // src/native-ui/renderer-extension/src/settings/core.ts
23884
- var SETTINGS_PAGE_ID_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
23885
- var MAX_SETTINGS_PAGE_ID_LENGTH = 48;
23886
- var MAX_SETTINGS_PAGE_LABEL_LENGTH = 64;
23887
- function normalizedPage(page) {
23888
- if (page.id.length === 0 || page.id.length > MAX_SETTINGS_PAGE_ID_LENGTH || !SETTINGS_PAGE_ID_PATTERN.test(page.id)) {
23889
- throw new Error(`Invalid settings page ID: ${page.id || "(empty)"}`);
23890
- }
23891
- const label = page.label.trim();
23892
- if (label.length === 0 || label.length > MAX_SETTINGS_PAGE_LABEL_LENGTH) {
23893
- throw new Error(`Invalid settings page label for ${page.id}`);
23894
- }
23895
- if (!isRendererSettingsIconName(page.icon)) {
23896
- throw new Error(`Unknown settings page icon for ${page.id}`);
24074
+ // src/native-ui/renderer-extension/src/renderer-collab-cards.ts
24075
+ function parseCollabPayload(text) {
24076
+ if (!text || !text.includes("child_thread_id") && !text.includes("task_id") && !text.includes("Agent \u534F\u4F5C")) {
24077
+ return null;
23897
24078
  }
23898
- if (typeof page.mount !== "function") {
23899
- throw new Error(`Settings page ${page.id} has no mount function`);
24079
+ const match = /\{[\s\S]*?"task_id"[\s\S]*?\}/.exec(text);
24080
+ if (!match) return null;
24081
+ try {
24082
+ const parsed = JSON.parse(match[0]);
24083
+ if (parsed && (parsed.task_id || parsed.child_thread_id)) return parsed;
24084
+ } catch {
23900
24085
  }
23901
- return Object.freeze({ ...page, label });
24086
+ return null;
23902
24087
  }
23903
- function createRendererSettingsPageRegistry(definitions, defaultPageId) {
23904
- if (definitions.length === 0) throw new Error("Settings page registry cannot be empty");
23905
- const resolvedDefaultPageId = defaultPageId ?? definitions[0]?.id ?? "";
23906
- const pages = definitions.map(normalizedPage);
23907
- const byId = /* @__PURE__ */ new Map();
23908
- for (const page of pages) {
23909
- if (byId.has(page.id)) throw new Error(`Duplicate settings page ID: ${page.id}`);
23910
- byId.set(page.id, page);
23911
- }
23912
- if (!byId.has(resolvedDefaultPageId)) {
23913
- throw new Error(`Default settings page is not registered: ${resolvedDefaultPageId}`);
24088
+ function formatDiffHtml(diff) {
24089
+ if (!diff) return '<div style="padding:8px;color:#888;font-size:12px">\u6682\u65E0\u6587\u4EF6\u6539\u52A8</div>';
24090
+ const lines = diff.split(/\r?\n/);
24091
+ const rows = lines.map((line) => {
24092
+ let bg = "transparent";
24093
+ let color = "inherit";
24094
+ if (line.startsWith("+") && !line.startsWith("+++")) {
24095
+ bg = "#22c55e1a";
24096
+ color = "#16a34a";
24097
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
24098
+ bg = "#ef44441a";
24099
+ color = "#dc2626";
24100
+ } else if (line.startsWith("@@")) {
24101
+ bg = "#8888881a";
24102
+ color = "#64748b";
24103
+ }
24104
+ const escaped = line.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
24105
+ return `<div style="background:${bg};color:${color};padding:1px 8px;font-family:ui-monospace,monospace;white-space:pre">${escaped || " "}</div>`;
24106
+ });
24107
+ return `<div style="font-size:12px;line-height:1.45;max-height:360px;overflow:auto;border-radius:6px;border:1px solid #8883;background:#0001;margin-top:6px">${rows.join("")}</div>`;
24108
+ }
24109
+ function installCollabCards(options = {}) {
24110
+ if (typeof document === "undefined") {
24111
+ return { scan: () => {
24112
+ }, dispose: () => {
24113
+ } };
23914
24114
  }
23915
- const frozenPages = Object.freeze([...pages]);
23916
- return Object.freeze({
23917
- pages: frozenPages,
23918
- defaultPageId: resolvedDefaultPageId,
23919
- getPage(pageId) {
23920
- return byId.get(pageId);
24115
+ let disposed = false;
24116
+ const enhancedElements = /* @__PURE__ */ new WeakSet();
24117
+ const openFn = options.openThread ?? ((threadId) => openRendererThread(threadId));
24118
+ const enhanceElement = (card, payload) => {
24119
+ if (enhancedElements.has(card)) return;
24120
+ enhancedElements.add(card);
24121
+ const strip = document.createElement("div");
24122
+ strip.className = "harness-mix-collab-actions";
24123
+ strip.style.cssText = "display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid #8882;font:13px system-ui";
24124
+ const agent = payload.agent_type || "agent";
24125
+ const icon2 = collaborationIcon(agent, agent, 18);
24126
+ strip.append(icon2);
24127
+ if (payload.child_thread_id) {
24128
+ const childId = payload.child_thread_id;
24129
+ const jumpBtn = document.createElement("button");
24130
+ jumpBtn.type = "button";
24131
+ jumpBtn.className = "harness-mix-collab-jump";
24132
+ jumpBtn.style.cssText = "display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:6px;border:1px solid #8884;background:#8881;color:inherit;font:inherit;cursor:pointer;font-size:12px";
24133
+ jumpBtn.innerHTML = `\u2197 \u67E5\u770B <b>@${agent}</b> \u4F1A\u8BDD`;
24134
+ jumpBtn.title = `\u5207\u6362\u5B9A\u4F4D\u81F3\u5B50\u4EFB\u52A1\u4F1A\u8BDD (${childId})`;
24135
+ jumpBtn.addEventListener("click", async (e) => {
24136
+ e.preventDefault();
24137
+ e.stopPropagation();
24138
+ const parsed = hostThreadIdSchema.safeParse(childId);
24139
+ if (parsed.success) {
24140
+ try {
24141
+ await openFn(parsed.data);
24142
+ } catch (err) {
24143
+ console.warn("[CollabCard] Jump to thread failed:", err);
24144
+ }
24145
+ }
24146
+ });
24147
+ strip.append(jumpBtn);
24148
+ }
24149
+ if (payload.diff || payload.workspace?.mode === "worktree") {
24150
+ const diffContainer = document.createElement("div");
24151
+ diffContainer.className = "harness-mix-collab-diff-wrap";
24152
+ diffContainer.style.cssText = "width:100%;display:none;margin-top:6px";
24153
+ if (payload.diff) {
24154
+ diffContainer.innerHTML = formatDiffHtml(payload.diff);
24155
+ }
24156
+ const toggleDiffBtn = document.createElement("button");
24157
+ toggleDiffBtn.type = "button";
24158
+ toggleDiffBtn.className = "harness-mix-collab-diff-toggle";
24159
+ toggleDiffBtn.style.cssText = "display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:6px;border:1px solid #8884;background:#8881;color:inherit;font:inherit;cursor:pointer;font-size:12px";
24160
+ toggleDiffBtn.textContent = "\u{1F50D} \u67E5\u770B\u4EA7\u7269 Diff";
24161
+ toggleDiffBtn.addEventListener("click", async (e) => {
24162
+ e.preventDefault();
24163
+ e.stopPropagation();
24164
+ const isHidden = diffContainer.style.display === "none";
24165
+ if (isHidden && !diffContainer.innerHTML.trim() && payload.child_thread_id && options.reviewWorkspace) {
24166
+ toggleDiffBtn.textContent = "\u52A0\u8F7D Diff \u4E2D\u2026";
24167
+ try {
24168
+ const review = await options.reviewWorkspace(payload.child_thread_id);
24169
+ diffContainer.innerHTML = formatDiffHtml(review.patch);
24170
+ } catch (err) {
24171
+ diffContainer.innerHTML = `<div style="padding:8px;color:#ef4444;font-size:12px">\u52A0\u8F7D Diff \u5931\u8D25: ${err?.message || err}</div>`;
24172
+ }
24173
+ }
24174
+ diffContainer.style.display = isHidden ? "block" : "none";
24175
+ toggleDiffBtn.textContent = isHidden ? "\u6536\u8D77\u4EA7\u7269 Diff" : "\u{1F50D} \u67E5\u770B\u4EA7\u7269 Diff";
24176
+ });
24177
+ strip.append(toggleDiffBtn);
24178
+ strip.append(diffContainer);
24179
+ if (payload.workspace?.mode === "worktree" && !payload.applied && options.applyWorkspace && payload.child_thread_id) {
24180
+ const applyBtn = document.createElement("button");
24181
+ applyBtn.type = "button";
24182
+ applyBtn.className = "harness-mix-collab-apply";
24183
+ applyBtn.style.cssText = "display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:6px;border:1px solid #16a34a88;background:#16a34a1a;color:#16a34a;font:inherit;cursor:pointer;font-size:12px;font-weight:500";
24184
+ applyBtn.textContent = "\u2713 \u5408\u5E76\u6539\u52A8\u5230\u4E3B\u9879\u76EE";
24185
+ applyBtn.title = "\u5C06\u8BE5\u5B50\u4EFB\u52A1\u7684\u72EC\u7ACB\u9694\u79BB\u5206\u652F\u6539\u52A8\u5E94\u7528\u5230\u4E3B\u5DE5\u4F5C\u533A";
24186
+ applyBtn.addEventListener("click", async (e) => {
24187
+ e.preventDefault();
24188
+ e.stopPropagation();
24189
+ applyBtn.disabled = true;
24190
+ applyBtn.textContent = "\u5408\u5E76\u4E2D\u2026";
24191
+ try {
24192
+ await options.applyWorkspace(payload.child_thread_id, payload.digest);
24193
+ applyBtn.textContent = "\u2713 \u5DF2\u5E94\u7528";
24194
+ applyBtn.style.border = "1px solid #8884";
24195
+ applyBtn.style.color = "#888";
24196
+ payload.applied = true;
24197
+ } catch (err) {
24198
+ applyBtn.disabled = false;
24199
+ applyBtn.textContent = "\u5408\u5E76\u5931\u8D25\uFF08\u91CD\u8BD5\uFF09";
24200
+ alert(`\u5408\u5E76\u5931\u8D25\uFF1A${err?.message || err}`);
24201
+ }
24202
+ });
24203
+ strip.append(applyBtn);
24204
+ }
23921
24205
  }
24206
+ card.append(strip);
24207
+ };
24208
+ const scan = () => {
24209
+ if (disposed) return;
24210
+ const candidates = document.querySelectorAll(
24211
+ '[data-local-conversation-item-target-ids], [data-turn-key], [data-testid*="tool"], .prose, pre'
24212
+ );
24213
+ for (const el of candidates) {
24214
+ if (enhancedElements.has(el)) continue;
24215
+ const text = el.textContent || "";
24216
+ const payload = parseCollabPayload(text);
24217
+ if (payload) {
24218
+ enhanceElement(el, payload);
24219
+ }
24220
+ }
24221
+ };
24222
+ const observer = new MutationObserver(() => scan());
24223
+ observer.observe(document.body || document.documentElement, {
24224
+ childList: true,
24225
+ subtree: true
23922
24226
  });
24227
+ scan();
24228
+ return {
24229
+ scan,
24230
+ dispose() {
24231
+ disposed = true;
24232
+ observer.disconnect();
24233
+ document.querySelectorAll(".harness-mix-collab-actions").forEach((el) => el.remove());
24234
+ }
24235
+ };
23923
24236
  }
23924
- var RendererSettingsNavigationState = class {
23925
- constructor(registry2) {
23926
- this.registry = registry2;
23927
- this.#activePageId = registry2.defaultPageId;
23928
- }
23929
- registry;
23930
- #activePageId;
23931
- get activePageId() {
23932
- return this.#activePageId;
23933
- }
23934
- select(pageId) {
23935
- if (!this.registry.getPage(pageId)) throw new Error(`Unknown settings page: ${pageId}`);
23936
- if (this.#activePageId === pageId) return false;
23937
- this.#activePageId = pageId;
23938
- return true;
23939
- }
23940
- reset() {
23941
- return this.select(this.registry.defaultPageId);
23942
- }
23943
- };
23944
- var RendererSettingsPageScope = class {
23945
- #pageController = new AbortController();
23946
- #requestController = null;
23947
- #requestGeneration = 0;
23948
- #disposed = false;
23949
- get signal() {
23950
- return this.#pageController.signal;
23951
- }
23952
- get disposed() {
23953
- return this.#disposed;
24237
+
24238
+ // src/native-ui/renderer-extension/src/settings/accounts-usage.ts
24239
+ function creditsPeriodLabel2(periodType, messages) {
24240
+ if (periodType === "weekly") return messages.accountCreditsPeriodWeekly;
24241
+ if (periodType === "monthly") return messages.accountCreditsPeriodMonthly;
24242
+ if (periodType === "five_hour") return messages.accountCreditsPeriodFiveHour;
24243
+ if (periodType === "seven_day") return messages.accountCreditsPeriodSevenDay;
24244
+ return messages.accountCreditsPeriodUnknown;
24245
+ }
24246
+ function creditsProductLabel(product, messages) {
24247
+ if (product === "GrokBuild" || product === "Build") return messages.accountCreditsBuild;
24248
+ if (product === "7-day window") return messages.accountCreditsPeriodSevenDay;
24249
+ if (product === "GrokChat") return "Chat";
24250
+ if (product === "GrokImagine") return "Imagine";
24251
+ if (product === "GrokVoice") return "Voice";
24252
+ return product;
24253
+ }
24254
+ function formatAccountCreditsReset(value, locale, now = /* @__PURE__ */ new Date()) {
24255
+ if (locale !== "zh-CN") return formatRendererCreditsReset(value, now);
24256
+ const date5 = new Date(value);
24257
+ if (Number.isNaN(date5.getTime())) return value;
24258
+ const isToday = date5.getFullYear() === now.getFullYear() && date5.getMonth() === now.getMonth() && date5.getDate() === now.getDate();
24259
+ if (isToday) {
24260
+ return `\u4ECA\u5929 ${date5.toLocaleTimeString("zh-CN", { hour: "numeric", minute: "2-digit" })}`;
23954
24261
  }
23955
- async runLatest(operation, handlers) {
23956
- if (this.#disposed) throw new Error("Settings page scope is disposed");
23957
- this.#requestController?.abort();
23958
- const controller = new AbortController();
23959
- this.#requestController = controller;
23960
- const generation = ++this.#requestGeneration;
23961
- const abortRequest = () => controller.abort();
23962
- this.signal.addEventListener("abort", abortRequest, { once: true });
23963
- try {
23964
- const value = await operation(controller.signal);
23965
- if (this.#isCurrent(controller, generation)) handlers.success(value);
23966
- } catch (error51) {
23967
- if (this.#isCurrent(controller, generation)) handlers.failure(error51);
23968
- } finally {
23969
- this.signal.removeEventListener("abort", abortRequest);
23970
- if (this.#requestController === controller) this.#requestController = null;
24262
+ return date5.toLocaleString("zh-CN", {
24263
+ month: "long",
24264
+ day: "numeric",
24265
+ hour: "numeric",
24266
+ minute: "2-digit"
24267
+ });
24268
+ }
24269
+ function resetCreditDetailLine(index, expiresAt, messages, now = /* @__PURE__ */ new Date()) {
24270
+ return messages.accountResetCreditsCardExpiry.replace("{index}", String(index)).replace("{time}", formatAccountCreditsReset(expiresAt, messages.locale, now));
24271
+ }
24272
+ function renderAccountUsage(document2, state, messages, display, onRetry) {
24273
+ if (!state) return null;
24274
+ const usage = document2.createElement("div");
24275
+ usage.className = "settings-account-usage";
24276
+ if (state.status !== "ready") {
24277
+ const message = document2.createElement("span");
24278
+ message.className = "settings-account-usage__message";
24279
+ message.textContent = state.status === "loading" ? messages.accountCreditsLoading : state.status === "error" ? messages.accountCreditsFailed : messages.accountCreditsEmpty;
24280
+ usage.append(message);
24281
+ if (state.status === "loading") usage.setAttribute("aria-busy", "true");
24282
+ if (state.status === "error") {
24283
+ const retry = document2.createElement("button");
24284
+ retry.type = "button";
24285
+ retry.className = "settings-command-button settings-command-button--secondary";
24286
+ retry.textContent = messages.accountCreditsRetry;
24287
+ retry.addEventListener("click", onRetry);
24288
+ usage.append(retry);
23971
24289
  }
24290
+ return usage;
23972
24291
  }
23973
- dispose() {
23974
- if (this.#disposed) return;
23975
- this.#disposed = true;
23976
- this.#requestGeneration += 1;
23977
- this.#requestController?.abort();
23978
- this.#requestController = null;
23979
- this.#pageController.abort();
24292
+ const credits = state.credits;
24293
+ const windows = [
24294
+ {
24295
+ label: credits.label ?? creditsPeriodLabel2(credits.periodType, messages),
24296
+ usedPercent: credits.usedPercent,
24297
+ resetsAt: credits.resetsAt
24298
+ },
24299
+ ...(credits.productUsage ?? []).map((product) => ({
24300
+ label: creditsProductLabel(product.product, messages),
24301
+ usedPercent: product.usagePercent,
24302
+ resetsAt: product.resetsAt
24303
+ }))
24304
+ ];
24305
+ for (const window2 of windows) {
24306
+ const meter = document2.createElement("div");
24307
+ meter.className = "settings-account-usage__meter";
24308
+ const label = document2.createElement("span");
24309
+ label.className = "settings-account-usage__title";
24310
+ label.textContent = window2.label;
24311
+ label.title = window2.label;
24312
+ const value = display === "remaining" ? 100 - window2.usedPercent : window2.usedPercent;
24313
+ const valueLabel = display === "remaining" ? messages.accountCreditsRemaining : messages.accountCreditsUsed;
24314
+ const tone = rendererCreditsTone(window2.usedPercent);
24315
+ const bar = document2.createElement("div");
24316
+ bar.className = `settings-account-usage__bar settings-account-usage__bar--${tone}`;
24317
+ bar.setAttribute("role", "meter");
24318
+ bar.setAttribute("aria-label", `${window2.label} \xB7 ${valueLabel}`);
24319
+ bar.setAttribute("aria-valuemin", "0");
24320
+ bar.setAttribute("aria-valuemax", "100");
24321
+ bar.setAttribute("aria-valuenow", String(value));
24322
+ const fill = document2.createElement("span");
24323
+ fill.style.width = `${Math.min(100, Math.max(0, value))}%`;
24324
+ bar.append(fill);
24325
+ const percent = document2.createElement("span");
24326
+ percent.className = `settings-account-usage__percent settings-account-usage__percent--${tone}`;
24327
+ const prefix = document2.createElement("span");
24328
+ prefix.textContent = valueLabel;
24329
+ prefix.className = "settings-account-usage__value-label";
24330
+ const number4 = document2.createElement("span");
24331
+ number4.textContent = formatRendererCreditsPercent(value);
24332
+ percent.append(prefix, number4);
24333
+ meter.append(label, bar, percent);
24334
+ if (window2.resetsAt) {
24335
+ const reset = document2.createElement("span");
24336
+ reset.className = "settings-account-usage__sub";
24337
+ reset.textContent = `${formatAccountCreditsReset(window2.resetsAt, messages.locale)} ${messages.accountCreditsReset}`;
24338
+ meter.append(reset);
24339
+ }
24340
+ usage.append(meter);
23980
24341
  }
23981
- #isCurrent(controller, generation) {
23982
- return !this.#disposed && !controller.signal.aborted && this.#requestController === controller && this.#requestGeneration === generation;
24342
+ return usage;
24343
+ }
24344
+ function renderAccountResetCredits(document2, credits, messages, options) {
24345
+ const resetCredits = credits.resetCredits;
24346
+ if (!resetCredits) return null;
24347
+ const summary = document2.createElement("button");
24348
+ summary.type = "button";
24349
+ summary.className = "settings-account-reset-summary";
24350
+ summary.setAttribute("aria-label", messages.accountResetCreditsDetails);
24351
+ summary.title = messages.accountResetCreditsDetails;
24352
+ const count = document2.createElement("span");
24353
+ count.textContent = messages.locale === "zh-CN" ? `${resetCredits.availableCount} \u5F20` : String(resetCredits.availableCount);
24354
+ summary.append(
24355
+ createRendererSettingsIcon("ticket", 16),
24356
+ count,
24357
+ createRendererSettingsIcon("chevron-right", 14)
24358
+ );
24359
+ const details = document2.createElement("div");
24360
+ details.className = "settings-account-reset-details";
24361
+ const copy = document2.createElement("div");
24362
+ const heading = document2.createElement("strong");
24363
+ heading.textContent = messages.accountResetCredits;
24364
+ copy.append(heading);
24365
+ if (resetCredits.nextExpiresAt) {
24366
+ const next = document2.createElement("p");
24367
+ next.className = "settings-account-reset-expiry";
24368
+ const reset = formatAccountCreditsReset(resetCredits.nextExpiresAt, messages.locale);
24369
+ next.textContent = messages.locale === "zh-CN" ? `\u6700\u65E9 ${reset}\u5230\u671F` : `Next expires ${reset}`;
24370
+ const remaining = Date.parse(resetCredits.nextExpiresAt) - Date.now();
24371
+ if (remaining <= 24 * 60 * 60 * 1e3) {
24372
+ next.className += remaining <= 8 * 60 * 60 * 1e3 ? " is-hot" : " is-warn";
24373
+ }
24374
+ copy.append(next);
23983
24375
  }
23984
- };
23985
-
23986
- // src/native-ui/renderer-extension/src/settings/session-import-list-controls.ts
23987
- function createSessionImportListControls(document2, messages, onChange) {
23988
- let query = "";
23989
- let offset = 0;
23990
- let limit = HARNESS_SESSION_IMPORT_DEFAULT_PAGE_SIZE;
23991
- let total = 0;
23992
- let loading = false;
23993
- let locked = false;
23994
- const searchForm = document2.createElement("form");
23995
- searchForm.className = "settings-session-import-search";
23996
- searchForm.setAttribute("role", "search");
23997
- const search = document2.createElement("input");
23998
- search.type = "search";
23999
- search.value = "";
24000
- search.maxLength = 4096;
24001
- search.placeholder = messages.sessionImportSearchPlaceholder;
24002
- search.setAttribute("aria-label", messages.sessionImportSearchPlaceholder);
24003
- search.dataset.sessionImportAction = "search-input";
24004
- const submit = document2.createElement("button");
24005
- submit.type = "submit";
24006
- submit.className = "settings-command-button settings-command-button--secondary";
24007
- submit.textContent = messages.sessionImportSearch;
24008
- submit.dataset.sessionImportAction = "search";
24009
- searchForm.append(search, submit);
24010
- searchForm.addEventListener("submit", (event) => {
24011
- event.preventDefault();
24012
- if (locked) return;
24013
- query = search.value.trim();
24014
- offset = 0;
24015
- onChange();
24016
- });
24017
- const pagination = document2.createElement("div");
24018
- pagination.className = "settings-session-import-pagination";
24019
- const pageSizeLabel = document2.createElement("label");
24020
- pageSizeLabel.textContent = messages.sessionImportPageSize;
24021
- const pageSize = document2.createElement("select");
24022
- pageSize.dataset.sessionImportAction = "page-size";
24023
- pageSize.setAttribute("aria-label", messages.sessionImportPageSize);
24024
- for (const size of [20, 50, 100]) {
24025
- const option = document2.createElement("option");
24026
- option.value = String(size);
24027
- option.textContent = String(size);
24028
- pageSize.append(option);
24376
+ if (resetCredits.expiresAt?.length) {
24377
+ const list = document2.createElement("ul");
24378
+ list.className = "settings-account-reset-list";
24379
+ for (const [index, expiresAt] of resetCredits.expiresAt.entries()) {
24380
+ const item = document2.createElement("li");
24381
+ item.textContent = resetCreditDetailLine(index + 1, expiresAt, messages);
24382
+ list.append(item);
24383
+ }
24384
+ copy.append(list);
24029
24385
  }
24030
- pageSize.value = String(limit);
24031
- pageSizeLabel.append(pageSize);
24032
- pageSize.addEventListener("change", () => {
24033
- if (locked) return;
24034
- const value = Number(pageSize.value);
24035
- if (![20, 50, 100].includes(value)) return;
24036
- limit = value;
24037
- offset = 0;
24038
- onChange();
24039
- });
24040
- const summary = document2.createElement("span");
24041
- summary.setAttribute("role", "status");
24042
- summary.dataset.sessionImportAction = "page-summary";
24043
- const previous = document2.createElement("button");
24044
- const next = document2.createElement("button");
24045
- for (const [button, label, action, direction] of [
24046
- [previous, messages.sessionImportPrevious, "previous", -1],
24047
- [next, messages.sessionImportNext, "next", 1]
24048
- ]) {
24049
- button.type = "button";
24050
- button.className = "settings-command-button settings-command-button--secondary";
24051
- button.textContent = label;
24052
- button.dataset.sessionImportAction = action;
24053
- button.addEventListener("click", () => {
24054
- if (button.disabled || locked || loading) return;
24055
- offset += direction * limit;
24056
- onChange();
24057
- });
24386
+ details.append(copy);
24387
+ if (options.onUseReset) {
24388
+ const use = document2.createElement("button");
24389
+ use.type = "button";
24390
+ use.className = "settings-command-button settings-command-button--secondary";
24391
+ use.textContent = options.usingReset ? messages.accountResetCreditsUsing : messages.accountResetCreditsUse;
24392
+ use.disabled = options.resetDisabled;
24393
+ use.addEventListener("click", options.onUseReset);
24394
+ details.append(use);
24058
24395
  }
24059
- const navigation = document2.createElement("div");
24060
- navigation.className = "settings-session-import-pagination__navigation";
24061
- navigation.append(previous, next);
24062
- pagination.append(pageSizeLabel, summary, navigation);
24063
- const update = () => {
24064
- search.disabled = locked;
24065
- submit.disabled = locked;
24066
- pageSize.disabled = locked;
24067
- previous.disabled = locked || loading || offset === 0;
24068
- next.disabled = locked || loading || offset + limit >= total;
24069
- summary.textContent = loading ? "" : messages.sessionImportPageSummary.replace("{page}", String(total ? Math.floor(offset / limit) + 1 : 0)).replace("{pages}", String(Math.ceil(total / limit))).replace("{total}", String(total));
24070
- };
24071
- update();
24072
- return {
24073
- searchForm,
24074
- pagination,
24075
- params() {
24076
- return { query, offset, limit };
24077
- },
24078
- reset() {
24079
- offset = 0;
24080
- total = 0;
24081
- update();
24082
- },
24083
- setBusy(value, lock = false) {
24084
- loading = value;
24085
- locked = lock;
24086
- update();
24087
- },
24088
- setTotal(value) {
24089
- total = value;
24090
- const lastOffset = Math.max(0, Math.ceil(total / limit) - 1) * limit;
24091
- const changed = offset > lastOffset;
24092
- if (changed) offset = lastOffset;
24093
- update();
24094
- return changed;
24095
- }
24096
- };
24396
+ return { summary, details };
24097
24397
  }
24098
24398
 
24099
- // src/native-ui/renderer-extension/src/settings/session-import-page.ts
24100
- function shortSessionId(value) {
24101
- return value.length <= 18 ? value : `${value.slice(0, 10)}\u2026${value.slice(-6)}`;
24102
- }
24103
- function createStatus(document2, message, error51 = false) {
24104
- const status = document2.createElement("div");
24105
- status.className = error51 ? "settings-session-import-status is-error" : "settings-session-import-status";
24106
- status.setAttribute("role", error51 ? "alert" : "status");
24107
- status.append(createRendererSettingsIcon(error51 ? "alert" : "download", 18));
24108
- const copy = document2.createElement("span");
24109
- copy.textContent = message;
24110
- status.append(copy);
24111
- return status;
24112
- }
24113
- function createAccessibleText(document2, message) {
24114
- const text = document2.createElement("span");
24115
- text.className = "settings-visually-hidden";
24116
- text.textContent = message;
24117
- return text;
24399
+ // src/native-ui/renderer-extension/src/settings/accounts-list.ts
24400
+ var resetDetailsSequence = 0;
24401
+ function accountPlanLabel(planType) {
24402
+ if (!planType || planType === "unknown") return null;
24403
+ if (planType === "free") return "Free";
24404
+ if (planType === "go") return "Go";
24405
+ if (planType === "plus") return "Plus";
24406
+ if (planType === "pro") return "Pro 20x";
24407
+ if (planType === "prolite") return "Pro 5x";
24408
+ if (planType === "team") return "Team";
24409
+ if (planType === "self_serve_business_prolite") return "Business Pro Lite";
24410
+ if (planType === "self_serve_business_usage_based") return "Business";
24411
+ if (planType === "business") return "Business";
24412
+ if (planType === "edu") return "Edu";
24413
+ if (planType === "edu_plus") return "Edu Plus";
24414
+ if (planType === "edu_pro") return "Edu Pro";
24415
+ return "Enterprise";
24118
24416
  }
24119
- function createSessionImportSettingsPage(messages, getClient, openImportedThread) {
24120
- return Object.freeze({
24121
- id: "session-import",
24122
- label: messages.pageLabels["session-import"],
24123
- icon: "session-import",
24124
- mount(context) {
24125
- const document2 = context.content.ownerDocument;
24126
- const header = document2.createElement("div");
24127
- header.className = "settings-session-import-header";
24128
- const heading = document2.createElement("h2");
24129
- heading.className = "settings-section-label";
24130
- heading.textContent = messages.pageLabels["session-import"];
24131
- const refresh = document2.createElement("button");
24132
- refresh.type = "button";
24133
- refresh.className = "settings-command-button settings-command-button--secondary";
24134
- refresh.dataset.sessionImportAction = "refresh";
24135
- const setRefreshLabel = (loading) => {
24136
- refresh.replaceChildren(
24137
- createRendererSettingsIcon("refresh", 15),
24138
- loading ? messages.sessionImportRefreshing : messages.sessionImportRefresh
24139
- );
24140
- };
24141
- setRefreshLabel(false);
24142
- header.append(heading, refresh);
24143
- const harness = document2.createElement("div");
24144
- harness.className = "settings-session-import-harness";
24145
- const harnessLabel = document2.createElement("span");
24146
- harnessLabel.textContent = messages.sessionImportHarness;
24147
- const harnessOptions = document2.createElement("div");
24148
- harnessOptions.className = "settings-session-import-harness__options";
24149
- harnessOptions.dataset.sessionImportHarness = "selector";
24150
- harnessOptions.setAttribute("role", "group");
24151
- harnessOptions.setAttribute("aria-label", messages.sessionImportHarness);
24152
- let selectedHarness = null;
24153
- let sources = [];
24154
- const sourceButtons = [];
24155
- const renderHarnessOptions = () => {
24156
- harnessOptions.replaceChildren();
24157
- sourceButtons.length = 0;
24158
- for (const source of sources) {
24159
- const option = document2.createElement("button");
24160
- option.type = "button";
24161
- option.className = "settings-session-import-harness__option";
24162
- option.dataset.sessionImportHarnessOption = source.harnessId;
24163
- option.textContent = source.name;
24164
- option.setAttribute("aria-pressed", String(source.harnessId === selectedHarness));
24165
- option.addEventListener("click", () => {
24166
- if (option.disabled || importingId !== null || source.harnessId === selectedHarness)
24167
- return;
24168
- selectedHarness = source.harnessId;
24169
- listControls.reset();
24170
- renderHarnessOptions();
24171
- load();
24172
- });
24173
- sourceButtons.push(option);
24174
- harnessOptions.append(option);
24175
- }
24176
- };
24177
- harness.append(harnessLabel, harnessOptions);
24178
- const description = document2.createElement("p");
24179
- description.className = "settings-page-description";
24180
- description.textContent = messages.sessionImportDescription;
24181
- const availabilityNote = document2.createElement("p");
24182
- availabilityNote.className = "settings-page-description settings-session-import-availability-note";
24183
- availabilityNote.textContent = messages.sessionImportAvailabilityNote;
24184
- const content = document2.createElement("section");
24185
- content.className = "settings-session-import-content";
24186
- const listControls = createSessionImportListControls(document2, messages, () => load());
24187
- context.content.append(
24188
- header,
24189
- harness,
24190
- description,
24191
- availabilityNote,
24192
- listControls.searchForm,
24193
- content,
24194
- listControls.pagination
24195
- );
24196
- let candidates = [];
24197
- let importingId = null;
24198
- let actions = [];
24199
- const updateImportActions = () => {
24200
- listControls.setBusy(importingId !== null, importingId !== null);
24201
- for (const button of sourceButtons) button.disabled = importingId !== null;
24202
- for (const { button, candidate } of actions) {
24203
- const importing = importingId === candidate.nativeSessionId;
24204
- button.disabled = candidate.running === true;
24205
- button.setAttribute(
24206
- "aria-disabled",
24207
- candidate.running || importingId !== null ? "true" : "false"
24208
- );
24209
- button.setAttribute("aria-busy", importing ? "true" : "false");
24210
- button.replaceChildren(
24211
- createRendererSettingsIcon("download", 15),
24212
- importing ? messages.sessionImportImporting : messages.sessionImportAction
24213
- );
24214
- }
24215
- };
24216
- const renderUnavailable = (focus = false) => {
24217
- listControls.setTotal(0);
24218
- candidates = [];
24219
- actions = [];
24220
- const status = createStatus(document2, messages.sessionImportUnavailable);
24221
- content.replaceChildren(status);
24222
- if (focus) {
24223
- status.tabIndex = -1;
24224
- status.focus();
24225
- }
24226
- };
24227
- const renderFailure = (error51, operation = "list") => {
24228
- listControls.setTotal(0);
24229
- if (error51 instanceof RendererSessionImportUnavailableError) {
24230
- renderUnavailable(operation === "import");
24231
- return;
24232
- }
24233
- actions = [];
24234
- const status = createStatus(
24235
- document2,
24236
- operation === "import" ? messages.sessionImportFailed : messages.sessionImportLoadFailed,
24237
- true
24238
- );
24239
- content.replaceChildren(status);
24240
- if (operation === "import") {
24241
- status.tabIndex = -1;
24242
- status.focus();
24243
- }
24244
- };
24245
- const renderOpenRecovery = (candidate, threadId) => {
24246
- actions = [];
24247
- refresh.disabled = false;
24248
- const recovery = document2.createElement("section");
24249
- recovery.className = "settings-session-import-recovery";
24250
- recovery.setAttribute("role", "region");
24251
- recovery.setAttribute("aria-label", messages.sessionImportImported);
24252
- recovery.tabIndex = -1;
24253
- const recoveryCopy = document2.createElement("div");
24254
- recoveryCopy.className = "settings-session-import-recovery__copy";
24255
- const title = document2.createElement("strong");
24256
- title.textContent = messages.sessionImportImported;
24257
- const explanation = document2.createElement("p");
24258
- explanation.textContent = messages.sessionImportOpenFailed;
24259
- recoveryCopy.append(title, explanation);
24260
- const path = document2.createElement("div");
24261
- path.className = "settings-session-import-recovery__path";
24262
- const cwd = document2.createElement("code");
24263
- cwd.textContent = candidate.cwd;
24264
- cwd.title = candidate.cwd;
24265
- const copyPath = document2.createElement("button");
24266
- copyPath.type = "button";
24267
- copyPath.className = "settings-command-button settings-command-button--secondary";
24268
- copyPath.dataset.sessionImportAction = "copy-project-path";
24269
- const setCopyLabel = (label) => {
24270
- copyPath.replaceChildren(createRendererSettingsIcon("copy", 15), label);
24271
- };
24272
- const showCopyFeedback = (label) => {
24273
- setCopyLabel(label);
24274
- document2.defaultView?.setTimeout(
24275
- () => setCopyLabel(messages.sessionImportCopyProjectPath),
24276
- 2e3
24277
- );
24278
- };
24279
- setCopyLabel(messages.sessionImportCopyProjectPath);
24280
- copyPath.addEventListener("click", () => {
24281
- const clipboard = document2.defaultView?.navigator.clipboard;
24282
- if (!clipboard) {
24283
- showCopyFeedback(messages.sessionImportPathCopyFailed);
24284
- return;
24285
- }
24286
- void clipboard.writeText(candidate.cwd).then(
24287
- () => showCopyFeedback(messages.sessionImportPathCopied),
24288
- () => showCopyFeedback(messages.sessionImportPathCopyFailed)
24289
- );
24290
- });
24291
- path.append(cwd, copyPath);
24292
- const retry = document2.createElement("button");
24293
- retry.type = "button";
24294
- retry.className = "settings-command-button";
24295
- retry.dataset.sessionImportAction = "retry-open";
24296
- const setRetrying = (pending) => {
24297
- listControls.setBusy(pending, pending);
24298
- for (const button of sourceButtons) button.disabled = pending;
24299
- retry.disabled = pending;
24300
- refresh.disabled = pending;
24301
- retry.setAttribute("aria-busy", pending ? "true" : "false");
24302
- retry.replaceChildren(
24303
- createRendererSettingsIcon("refresh", 15),
24304
- pending ? messages.sessionImportRetrying : messages.sessionImportRetryOpen
24305
- );
24306
- };
24307
- setRetrying(false);
24308
- retry.addEventListener("click", () => {
24309
- if (retry.disabled) return;
24310
- setRetrying(true);
24311
- void context.runLatest((signal) => openImportedThread(threadId, signal), {
24312
- success() {
24313
- setRetrying(false);
24314
- },
24315
- failure() {
24316
- renderOpenRecovery(candidate, threadId);
24317
- }
24318
- });
24319
- });
24320
- recovery.append(recoveryCopy, path, retry);
24321
- content.replaceChildren(recovery);
24322
- recovery.focus();
24323
- };
24324
- const renderCandidates = () => {
24325
- actions = [];
24326
- content.replaceChildren();
24327
- if (candidates.length === 0) {
24328
- content.append(
24329
- createStatus(
24330
- document2,
24331
- listControls.params().query ? messages.sessionImportNoMatches : messages.sessionImportEmpty
24332
- )
24333
- );
24334
- return;
24335
- }
24336
- const list = document2.createElement("div");
24337
- list.className = "settings-session-import-list";
24338
- for (const candidate of candidates) {
24339
- const row = document2.createElement("article");
24340
- row.className = "settings-session-import-row";
24341
- row.dataset.sessionImportId = candidate.nativeSessionId;
24342
- const copy = document2.createElement("div");
24343
- copy.className = "settings-session-import-row__copy";
24344
- const title = document2.createElement("strong");
24345
- title.textContent = candidate.title ?? messages.sessionImportUntitled;
24346
- const metadata = document2.createElement("span");
24347
- metadata.textContent = `${messages.sessionImportUpdatedAt}: ${new Intl.DateTimeFormat(
24348
- messages.locale === "zh-CN" ? "zh-CN" : "en",
24349
- { dateStyle: "medium", timeStyle: "short" }
24350
- ).format(new Date(candidate.updatedAt))}`;
24351
- const cwd = document2.createElement("code");
24352
- cwd.className = "settings-session-import-row__cwd";
24353
- cwd.textContent = candidate.cwd;
24354
- cwd.title = candidate.cwd;
24355
- const identity = document2.createElement("span");
24356
- identity.textContent = `${messages.sessionImportSessionId}: ${shortSessionId(candidate.nativeSessionId)}`;
24357
- identity.title = candidate.nativeSessionId;
24358
- identity.setAttribute("aria-hidden", "true");
24359
- copy.append(
24360
- title,
24361
- metadata,
24362
- cwd,
24363
- identity,
24364
- createAccessibleText(
24365
- document2,
24366
- `${messages.sessionImportSessionId}: ${candidate.nativeSessionId}`
24367
- )
24368
- );
24369
- const actionArea = document2.createElement("div");
24370
- actionArea.className = "settings-session-import-row__action";
24371
- if (candidate.running !== false) {
24372
- const running = document2.createElement("span");
24373
- running.className = "settings-session-import-running";
24374
- running.textContent = candidate.running === null ? messages.sessionImportRunningUnknown : messages.sessionImportRunning;
24375
- running.title = messages.sessionImportRunningHint;
24376
- running.setAttribute("aria-hidden", "true");
24377
- actionArea.append(
24378
- running,
24379
- createAccessibleText(
24380
- document2,
24381
- `${running.textContent}: ${messages.sessionImportRunningHint}`
24382
- )
24383
- );
24384
- }
24385
- const action = document2.createElement("button");
24386
- action.type = "button";
24387
- action.className = "settings-command-button";
24388
- action.dataset.sessionImportAction = "import";
24389
- action.addEventListener("click", () => {
24390
- if (candidate.running === true || importingId !== null || selectedHarness === null)
24391
- return;
24392
- const harnessId = selectedHarness;
24393
- const client = getClient();
24394
- if (!client) {
24395
- renderUnavailable(true);
24396
- return;
24397
- }
24398
- importingId = candidate.nativeSessionId;
24399
- refresh.disabled = true;
24400
- updateImportActions();
24401
- let committedThreadId = null;
24402
- void context.runLatest(
24403
- async (signal) => {
24404
- const result = await client.importHarnessSession({
24405
- harnessId,
24406
- nativeSessionId: candidate.nativeSessionId
24407
- });
24408
- committedThreadId = result.threadId;
24409
- if (!signal.aborted) await openImportedThread(result.threadId, signal);
24410
- },
24411
- {
24412
- success() {
24413
- importingId = null;
24414
- refresh.disabled = false;
24415
- updateImportActions();
24416
- },
24417
- failure(error51) {
24418
- importingId = null;
24419
- updateImportActions();
24420
- refresh.disabled = false;
24421
- if (committedThreadId) {
24422
- renderOpenRecovery(candidate, committedThreadId);
24423
- } else {
24424
- renderFailure(error51, "import");
24425
- }
24426
- }
24427
- }
24428
- );
24429
- });
24430
- actions.push({ button: action, candidate });
24431
- actionArea.append(action);
24432
- row.append(copy, actionArea);
24433
- list.append(row);
24434
- }
24435
- content.append(list);
24436
- updateImportActions();
24437
- };
24438
- const load = () => {
24439
- if (importingId !== null || context.signal.aborted) return;
24440
- const client = getClient();
24441
- if (!client) {
24442
- refresh.disabled = false;
24443
- setRefreshLabel(false);
24444
- renderUnavailable();
24445
- return;
24446
- }
24447
- listControls.setBusy(true);
24448
- refresh.disabled = true;
24449
- setRefreshLabel(true);
24450
- content.replaceChildren(createStatus(document2, messages.sessionImportRefreshing));
24451
- const requestedHarness = selectedHarness;
24452
- const pageParams = listControls.params();
24453
- void context.runLatest(
24454
- async (signal) => {
24455
- const result = await client.listSessionImportSources();
24456
- const selected = result.harnesses.find(({ harnessId }) => harnessId === requestedHarness)?.harnessId ?? result.harnesses[0]?.harnessId ?? null;
24457
- if (signal.aborted) throw new Error("Session import selection changed");
24458
- sources = result.harnesses;
24459
- selectedHarness = selected;
24460
- if (selected !== requestedHarness) {
24461
- listControls.reset();
24462
- pageParams.offset = 0;
24463
- }
24464
- renderHarnessOptions();
24465
- return selected ? client.listHarnessSessions({ harnessId: selected, ...pageParams }) : { candidates: [], total: 0 };
24466
- },
24467
- {
24468
- success(result) {
24469
- listControls.setBusy(false);
24470
- if (listControls.setTotal(result.total)) {
24471
- load();
24472
- return;
24473
- }
24474
- candidates = result.candidates;
24475
- refresh.disabled = false;
24476
- setRefreshLabel(false);
24477
- if (selectedHarness === null) renderUnavailable();
24478
- else renderCandidates();
24479
- },
24480
- failure(error51) {
24481
- listControls.setBusy(false);
24482
- candidates = [];
24483
- refresh.disabled = false;
24484
- setRefreshLabel(false);
24485
- renderFailure(error51);
24486
- }
24487
- }
24488
- );
24489
- };
24490
- refresh.addEventListener("click", load);
24491
- load();
24492
- return void 0;
24493
- }
24494
- });
24495
- }
24496
-
24497
- // src/native-ui/renderer-extension/src/settings/release-notes.ts
24498
- var HEADING_PATTERN = /^(#{1,6})[ \t]+(.+?)\s*$/u;
24499
- var BLOCKQUOTE_PATTERN = /^>[ \t]?(.*?)\s*$/u;
24500
- var UNORDERED_ITEM_PATTERN = /^[-*][ \t]+(.+?)\s*$/u;
24501
- var CONTINUATION_PATTERN = /^[ \t]+(.+?)\s*$/u;
24502
- var ORDERED_ITEM_PATTERN = /^\d+[.)][ \t]+(.+?)\s*$/u;
24503
- var FENCE_PATTERN = /^```([\w+-]*)\s*$/u;
24504
- var THEMATIC_BREAK_PATTERN = /^(?:---|___|\*\*\*)[ \t]*$/u;
24505
- var INLINE_PATTERN = /(`+)((?:(?!\1).)+)\1|\*\*(.+?)\*\*|\[([^\]]+)\]\(([^)\s]+)\)/gu;
24506
- function createReleaseNotesElement(document2, markdown) {
24507
- const root = document2.createElement("div");
24508
- root.className = "settings-update-notes";
24509
- appendReleaseNotesBlocks(document2, root, markdown);
24510
- return root;
24511
- }
24512
- function appendReleaseNotesBlocks(document2, root, markdown) {
24513
- const lines = markdown.replaceAll("\r\n", "\n").split("\n");
24514
- let index = 0;
24515
- while (index < lines.length) {
24516
- const line = lines[index] ?? "";
24517
- if (line.trim().length === 0) {
24518
- index += 1;
24519
- continue;
24520
- }
24521
- const fence = FENCE_PATTERN.exec(line);
24522
- if (fence) {
24523
- index = appendFencedCode(document2, root, lines, index, fence[1] ?? "");
24524
- continue;
24525
- }
24526
- const heading = HEADING_PATTERN.exec(line);
24527
- if (heading?.[1] && heading[2]) {
24528
- const tag = `h${heading[1].length}`;
24529
- const element = document2.createElement(tag);
24530
- appendInline(document2, element, heading[2]);
24531
- root.append(element);
24532
- index += 1;
24533
- continue;
24534
- }
24535
- if (BLOCKQUOTE_PATTERN.test(line)) {
24536
- index = appendBlockquote(document2, root, lines, index);
24537
- continue;
24538
- }
24539
- if (THEMATIC_BREAK_PATTERN.test(line)) {
24540
- root.append(document2.createElement("hr"));
24541
- index += 1;
24542
- continue;
24543
- }
24544
- if (UNORDERED_ITEM_PATTERN.test(line)) {
24545
- index = appendList(document2, root, lines, index, "ul", UNORDERED_ITEM_PATTERN);
24546
- continue;
24547
- }
24548
- if (ORDERED_ITEM_PATTERN.test(line)) {
24549
- index = appendList(document2, root, lines, index, "ol", ORDERED_ITEM_PATTERN);
24550
- continue;
24417
+ function accountListFocusRestorer(list, fallback) {
24418
+ const active = list.getRootNode().activeElement;
24419
+ if (!active || !list.contains(active)) return () => void 0;
24420
+ const key = active.getAttribute("data-account-focus");
24421
+ const accountId = active.closest(".settings-account-row")?.dataset.accountId;
24422
+ return () => {
24423
+ const target = key ? list.querySelector(`[data-account-focus="${CSS.escape(key)}"]`) : null;
24424
+ if (target && !target.matches(":disabled")) {
24425
+ target.focus({ preventScroll: true });
24426
+ return;
24551
24427
  }
24552
- index = appendParagraph(document2, root, lines, index);
24553
- }
24428
+ const row = accountId ? list.querySelector(
24429
+ `.settings-account-row[data-account-id="${CSS.escape(accountId)}"]`
24430
+ ) : null;
24431
+ (row ?? fallback).focus({ preventScroll: true });
24432
+ };
24554
24433
  }
24555
- function appendFencedCode(document2, root, lines, start, language) {
24556
- const body = [];
24557
- let index = start + 1;
24558
- while (index < lines.length && !FENCE_PATTERN.test(lines[index] ?? "")) {
24559
- body.push(lines[index] ?? "");
24560
- index += 1;
24434
+ function createAccountsTable(document2, messages) {
24435
+ const table = document2.createElement("table");
24436
+ table.className = "settings-account-table";
24437
+ table.setAttribute("aria-label", messages.pageLabels.accounts);
24438
+ const head = document2.createElement("thead");
24439
+ const row = document2.createElement("tr");
24440
+ for (const label of [
24441
+ messages.accountColumnAccount,
24442
+ messages.accountColumnUsage,
24443
+ messages.accountResetCredits,
24444
+ messages.accountColumnActions
24445
+ ]) {
24446
+ const cell = document2.createElement("th");
24447
+ cell.scope = "col";
24448
+ cell.textContent = label;
24449
+ row.append(cell);
24561
24450
  }
24562
- if (index < lines.length) index += 1;
24563
- const pre = document2.createElement("pre");
24564
- const code = document2.createElement("code");
24565
- if (language.length > 0) code.className = `language-${language}`;
24566
- code.textContent = body.join("\n");
24567
- pre.append(code);
24568
- root.append(pre);
24569
- return index;
24451
+ head.append(row);
24452
+ const body = document2.createElement("tbody");
24453
+ table.append(head, body);
24454
+ return { table, body };
24570
24455
  }
24571
- function appendBlockquote(document2, root, lines, start) {
24572
- const blockquote = document2.createElement("blockquote");
24573
- const content = [];
24574
- let index = start;
24575
- while (index < lines.length) {
24576
- const match = BLOCKQUOTE_PATTERN.exec(lines[index] ?? "");
24577
- if (!match) break;
24578
- content.push(match[1] ?? "");
24579
- index += 1;
24456
+ function renderAccountRows(document2, account, messages, input) {
24457
+ const row = document2.createElement("tr");
24458
+ row.className = "settings-account-row";
24459
+ row.dataset.accountId = account.accountId;
24460
+ row.dataset.accountFocus = `${account.accountId}:row`;
24461
+ row.tabIndex = -1;
24462
+ const name = codexAccountDisplayName(account);
24463
+ row.setAttribute("aria-label", name.full);
24464
+ const personCell = document2.createElement("td");
24465
+ const person = document2.createElement("div");
24466
+ person.className = "settings-account-row__person";
24467
+ const mark = document2.createElement("div");
24468
+ mark.className = "settings-account-row__mark";
24469
+ mark.setAttribute("aria-hidden", "true");
24470
+ mark.append(createRendererSettingsIcon("terminal", 17));
24471
+ const identity = document2.createElement("div");
24472
+ identity.className = "settings-account-row__identity";
24473
+ const title = document2.createElement("div");
24474
+ title.className = "settings-account-title";
24475
+ const local = document2.createElement("strong");
24476
+ local.className = "settings-account-email";
24477
+ local.textContent = name.local;
24478
+ local.title = name.full;
24479
+ title.append(local);
24480
+ if (account.active) {
24481
+ const badge = document2.createElement("span");
24482
+ badge.className = "settings-account-active";
24483
+ badge.textContent = messages.accountDefaultBadge;
24484
+ title.append(badge);
24580
24485
  }
24581
- const paragraph = document2.createElement("p");
24582
- appendInline(document2, paragraph, content.join(" ").trim());
24583
- blockquote.append(paragraph);
24584
- root.append(blockquote);
24585
- return index;
24586
- }
24587
- function appendList(document2, root, lines, start, tag, pattern) {
24588
- const list = document2.createElement(tag);
24589
- let index = start;
24590
- while (index < lines.length) {
24591
- const item = pattern.exec(lines[index] ?? "");
24592
- if (!item?.[1]) break;
24593
- const entry = document2.createElement("li");
24594
- appendInline(document2, entry, item[1]);
24595
- index += 1;
24596
- const continuationLines = [];
24597
- while (index < lines.length) {
24598
- const continuation = CONTINUATION_PATTERN.exec(lines[index] ?? "");
24599
- if (!continuation?.[1]) break;
24600
- continuationLines.push(continuation[1]);
24601
- index += 1;
24602
- }
24603
- if (continuationLines.length > 0) {
24604
- const continuation = document2.createElement("span");
24605
- continuation.className = "release-note-translation";
24606
- appendInline(document2, continuation, continuationLines.join(" "));
24607
- entry.append(continuation);
24608
- }
24609
- list.append(entry);
24486
+ identity.append(title);
24487
+ const metadata = document2.createElement("div");
24488
+ metadata.className = "settings-account-metadata";
24489
+ if (name.domain) {
24490
+ const domain2 = document2.createElement("span");
24491
+ domain2.className = "settings-account-domain";
24492
+ domain2.textContent = `@${name.domain}`;
24493
+ metadata.append(domain2);
24610
24494
  }
24611
- root.append(list);
24612
- return index;
24613
- }
24614
- function appendParagraph(document2, root, lines, start) {
24615
- const paragraphLines = [];
24616
- let index = start;
24617
- while (index < lines.length) {
24618
- const current = lines[index] ?? "";
24619
- if (current.trim().length === 0 || FENCE_PATTERN.test(current) || HEADING_PATTERN.test(current) || BLOCKQUOTE_PATTERN.test(current) || THEMATIC_BREAK_PATTERN.test(current) || UNORDERED_ITEM_PATTERN.test(current) || ORDERED_ITEM_PATTERN.test(current)) {
24620
- break;
24495
+ const planLabel = accountPlanLabel(account.planType);
24496
+ if (planLabel) {
24497
+ if (name.domain) {
24498
+ const separator = document2.createElement("span");
24499
+ separator.className = "settings-account-plan-separator";
24500
+ separator.textContent = "\xB7";
24501
+ separator.setAttribute("aria-hidden", "true");
24502
+ metadata.append(separator);
24621
24503
  }
24622
- paragraphLines.push(current.trim());
24623
- index += 1;
24504
+ const plan = document2.createElement("span");
24505
+ plan.className = account.planType === "pro" || account.planType === "prolite" ? "settings-account-plan settings-account-plan--highlighted" : "settings-account-plan";
24506
+ plan.textContent = planLabel;
24507
+ metadata.append(plan);
24624
24508
  }
24625
- const paragraph = document2.createElement("p");
24626
- paragraphLines.forEach((line, lineIndex) => {
24627
- appendInline(document2, paragraph, line);
24628
- if (lineIndex < paragraphLines.length - 1) paragraph.append(document2.createElement("br"));
24629
- });
24630
- root.append(paragraph);
24631
- return index;
24632
- }
24633
- function appendInline(document2, parent, text) {
24634
- let lastIndex = 0;
24635
- for (const match of text.matchAll(INLINE_PATTERN)) {
24636
- const index = match.index ?? 0;
24637
- if (index > lastIndex) parent.append(text.slice(lastIndex, index));
24638
- if (match[2] !== void 0) {
24639
- const code = document2.createElement("code");
24640
- code.textContent = match[2];
24641
- parent.append(code);
24642
- } else if (match[3] !== void 0) {
24643
- const strong = document2.createElement("strong");
24644
- strong.textContent = match[3];
24645
- parent.append(strong);
24646
- } else {
24647
- const href = match[5] ?? "";
24648
- if (!isSafeLink(href)) {
24649
- parent.append(match[4] ?? "");
24650
- } else {
24651
- const link = document2.createElement("a");
24652
- link.textContent = match[4] ?? "";
24653
- link.setAttribute("href", href);
24654
- link.setAttribute("target", "_blank");
24655
- link.setAttribute("rel", "noopener noreferrer");
24656
- parent.append(link);
24657
- }
24658
- }
24659
- lastIndex = index + match[0].length;
24509
+ if (metadata.childElementCount > 0) identity.append(metadata);
24510
+ person.append(mark, identity);
24511
+ personCell.append(person);
24512
+ const usageCell = document2.createElement("td");
24513
+ const usage = renderAccountUsage(document2, input.usage, messages, input.display, input.onRetry);
24514
+ if (usage) usageCell.append(usage);
24515
+ const resetCell = document2.createElement("td");
24516
+ const resetLabel2 = document2.createElement("span");
24517
+ resetLabel2.className = "settings-account-mobile-label";
24518
+ resetLabel2.textContent = messages.accountResetCredits;
24519
+ resetCell.append(resetLabel2);
24520
+ const actionsCell = document2.createElement("td");
24521
+ const actions = document2.createElement("div");
24522
+ actions.className = "settings-account-actions";
24523
+ if (!account.active) {
24524
+ const activate = document2.createElement("button");
24525
+ activate.type = "button";
24526
+ activate.className = "settings-account-action";
24527
+ activate.textContent = messages.accountUse;
24528
+ activate.dataset.accountFocus = `${account.accountId}:activate`;
24529
+ activate.disabled = input.actionsDisabled;
24530
+ activate.addEventListener("click", input.onActivate);
24531
+ actions.append(activate);
24660
24532
  }
24661
- if (lastIndex < text.length) parent.append(text.slice(lastIndex));
24662
- }
24663
- function isSafeLink(href) {
24664
- try {
24665
- const url2 = new URL(href, "https://codexhost.invalid");
24666
- return url2.protocol === "http:" || url2.protocol === "https:";
24667
- } catch {
24668
- return false;
24533
+ if (!account.email) {
24534
+ const signIn = document2.createElement("button");
24535
+ signIn.type = "button";
24536
+ signIn.className = "settings-account-action";
24537
+ signIn.textContent = messages.accountSignIn;
24538
+ signIn.dataset.accountFocus = `${account.accountId}:login`;
24539
+ signIn.disabled = input.actionsDisabled;
24540
+ signIn.addEventListener("click", input.onSignIn);
24541
+ actions.append(signIn);
24669
24542
  }
24670
- }
24671
-
24672
- // src/native-ui/renderer-extension/src/settings/accounts-usage.ts
24673
- function creditsPeriodLabel2(periodType, messages) {
24674
- if (periodType === "weekly") return messages.accountCreditsPeriodWeekly;
24675
- if (periodType === "monthly") return messages.accountCreditsPeriodMonthly;
24676
- if (periodType === "five_hour") return messages.accountCreditsPeriodFiveHour;
24677
- if (periodType === "seven_day") return messages.accountCreditsPeriodSevenDay;
24678
- return messages.accountCreditsPeriodUnknown;
24679
- }
24680
- function creditsProductLabel(product, messages) {
24681
- if (product === "GrokBuild" || product === "Build") return messages.accountCreditsBuild;
24682
- if (product === "7-day window") return messages.accountCreditsPeriodSevenDay;
24683
- if (product === "GrokChat") return "Chat";
24684
- if (product === "GrokImagine") return "Imagine";
24685
- if (product === "GrokVoice") return "Voice";
24686
- return product;
24687
- }
24688
- function formatAccountCreditsReset(value, locale, now = /* @__PURE__ */ new Date()) {
24689
- if (locale !== "zh-CN") return formatRendererCreditsReset(value, now);
24690
- const date5 = new Date(value);
24691
- if (Number.isNaN(date5.getTime())) return value;
24692
- const isToday = date5.getFullYear() === now.getFullYear() && date5.getMonth() === now.getMonth() && date5.getDate() === now.getDate();
24693
- if (isToday) {
24694
- return `\u4ECA\u5929 ${date5.toLocaleTimeString("zh-CN", { hour: "numeric", minute: "2-digit" })}`;
24543
+ if (!account.isDefault) {
24544
+ const remove = document2.createElement("button");
24545
+ remove.type = "button";
24546
+ remove.className = "settings-icon-button settings-account-delete";
24547
+ remove.title = messages.accountDelete;
24548
+ remove.dataset.accountFocus = `${account.accountId}:delete`;
24549
+ remove.setAttribute("aria-label", `${messages.accountDelete}: ${name.full}`);
24550
+ remove.disabled = input.actionsDisabled;
24551
+ remove.append(createRendererSettingsIcon("trash", 16));
24552
+ remove.addEventListener("click", input.onDelete);
24553
+ actions.append(remove);
24695
24554
  }
24696
- return date5.toLocaleString("zh-CN", {
24697
- month: "long",
24698
- day: "numeric",
24699
- hour: "numeric",
24700
- minute: "2-digit"
24555
+ actionsCell.append(actions);
24556
+ row.append(personCell, usageCell, resetCell, actionsCell);
24557
+ const reset = input.usage?.status === "ready" ? renderAccountResetCredits(document2, input.usage.credits, messages, input) : null;
24558
+ if (!reset) {
24559
+ const unknown2 = document2.createElement("span");
24560
+ unknown2.className = "settings-account-unknown";
24561
+ unknown2.textContent = "\u2014";
24562
+ unknown2.title = messages.accountResetCreditsUnknown;
24563
+ unknown2.setAttribute("aria-label", messages.accountResetCreditsUnknown);
24564
+ resetCell.append(unknown2);
24565
+ return [row];
24566
+ }
24567
+ const detailsRow = document2.createElement("tr");
24568
+ detailsRow.className = "settings-account-details-row";
24569
+ detailsRow.id = `settings-account-reset-${++resetDetailsSequence}`;
24570
+ detailsRow.hidden = !input.resetExpanded;
24571
+ const detailsCell = document2.createElement("td");
24572
+ detailsCell.colSpan = 4;
24573
+ detailsCell.append(reset.details);
24574
+ detailsRow.append(detailsCell);
24575
+ reset.summary.dataset.accountFocus = `${account.accountId}:reset`;
24576
+ reset.summary.setAttribute("aria-controls", detailsRow.id);
24577
+ reset.summary.setAttribute("aria-expanded", String(input.resetExpanded));
24578
+ reset.summary.addEventListener("click", () => {
24579
+ detailsRow.hidden = !detailsRow.hidden;
24580
+ reset.summary.setAttribute("aria-expanded", String(!detailsRow.hidden));
24581
+ input.onResetExpanded(!detailsRow.hidden);
24701
24582
  });
24583
+ resetCell.append(reset.summary);
24584
+ return [row, detailsRow];
24702
24585
  }
24703
- function resetCreditDetailLine(index, expiresAt, messages, now = /* @__PURE__ */ new Date()) {
24704
- return messages.accountResetCreditsCardExpiry.replace("{index}", String(index)).replace("{time}", formatAccountCreditsReset(expiresAt, messages.locale, now));
24705
- }
24706
- function renderAccountUsage(document2, state, messages, display, onRetry) {
24707
- if (!state) return null;
24708
- const usage = document2.createElement("div");
24709
- usage.className = "settings-account-usage";
24710
- if (state.status !== "ready") {
24711
- const message = document2.createElement("span");
24712
- message.className = "settings-account-usage__message";
24713
- message.textContent = state.status === "loading" ? messages.accountCreditsLoading : state.status === "error" ? messages.accountCreditsFailed : messages.accountCreditsEmpty;
24714
- usage.append(message);
24715
- if (state.status === "loading") usage.setAttribute("aria-busy", "true");
24716
- if (state.status === "error") {
24717
- const retry = document2.createElement("button");
24718
- retry.type = "button";
24719
- retry.className = "settings-command-button settings-command-button--secondary";
24720
- retry.textContent = messages.accountCreditsRetry;
24721
- retry.addEventListener("click", onRetry);
24722
- usage.append(retry);
24586
+
24587
+ // src/native-ui/renderer-extension/src/settings/harness-accounts.ts
24588
+ function mountHarnessAccounts(context, messages, getClient, onChange) {
24589
+ const document2 = context.content.ownerDocument;
24590
+ const section = document2.createElement("section");
24591
+ section.className = "settings-harness-accounts";
24592
+ section.hidden = true;
24593
+ const heading = document2.createElement("h2");
24594
+ heading.className = "settings-harness-accounts__title";
24595
+ heading.textContent = messages.harnessAccountsPageTitle || messages.harnessAccountsTitle;
24596
+ const list = document2.createElement("div");
24597
+ list.className = "settings-account-list";
24598
+ section.append(heading, list);
24599
+ context.content.append(section);
24600
+ let accounts = [];
24601
+ let refreshing = false;
24602
+ let query = "";
24603
+ let display = "remaining";
24604
+ let refresh;
24605
+ const render = () => {
24606
+ section.hidden = accounts.length === 0;
24607
+ list.replaceChildren();
24608
+ const visible = accounts.filter(
24609
+ (account) => `${account.harnessName} ${account.email ?? ""} ${account.label ?? ""} ${account.plan ?? ""}`.toLocaleLowerCase().includes(query)
24610
+ );
24611
+ for (const account of visible) {
24612
+ const row = document2.createElement("article");
24613
+ row.className = "settings-harness-account";
24614
+ row.dataset.harnessId = account.harnessId;
24615
+ const identity = document2.createElement("div");
24616
+ identity.className = "settings-harness-account__identity";
24617
+ const name = document2.createElement("strong");
24618
+ name.className = "settings-account-email";
24619
+ const accountName = account.email ?? account.label;
24620
+ name.textContent = accountName ?? account.harnessName;
24621
+ name.title = name.textContent;
24622
+ identity.append(name);
24623
+ const metadata = document2.createElement("div");
24624
+ metadata.className = "settings-account-metadata";
24625
+ if (accountName) {
24626
+ const harness = document2.createElement("span");
24627
+ harness.textContent = account.harnessName;
24628
+ metadata.append(harness);
24629
+ }
24630
+ if (account.plan) {
24631
+ if (accountName) {
24632
+ const separator = document2.createElement("span");
24633
+ separator.textContent = "\xB7";
24634
+ separator.setAttribute("aria-hidden", "true");
24635
+ metadata.append(separator);
24636
+ }
24637
+ const plan = document2.createElement("span");
24638
+ plan.className = "settings-account-plan";
24639
+ plan.textContent = account.plan;
24640
+ metadata.append(plan);
24641
+ }
24642
+ if (account.status) {
24643
+ if (accountName || account.plan) {
24644
+ const separator = document2.createElement("span");
24645
+ separator.textContent = "\xB7";
24646
+ separator.setAttribute("aria-hidden", "true");
24647
+ metadata.append(separator);
24648
+ }
24649
+ const statusBadge = document2.createElement("span");
24650
+ statusBadge.className = `settings-harness-account__badge settings-harness-account__badge--${account.status}`;
24651
+ statusBadge.textContent = account.status === "ready" ? messages.harnessAccountStatusReady : account.status === "not_installed" ? messages.harnessAccountStatusNotInstalled : messages.harnessAccountStatusUnconfigured;
24652
+ metadata.append(statusBadge);
24653
+ }
24654
+ if (metadata.childElementCount) identity.append(metadata);
24655
+ if (account.configHint) {
24656
+ const configHint = document2.createElement("div");
24657
+ configHint.className = "settings-harness-account__config-hint";
24658
+ configHint.title = account.configHint;
24659
+ const label = document2.createElement("span");
24660
+ label.textContent = `${messages.harnessAccountConfigGuide}: `;
24661
+ const code = document2.createElement("code");
24662
+ code.textContent = account.configHint;
24663
+ configHint.append(label, code);
24664
+ identity.append(configHint);
24665
+ }
24666
+ const usage = account.credits ? renderAccountUsage(
24667
+ document2,
24668
+ { status: "ready", credits: account.credits },
24669
+ messages,
24670
+ display,
24671
+ () => void 0
24672
+ ) : null;
24673
+ const person = document2.createElement("div");
24674
+ person.className = "settings-account-row__person";
24675
+ const agent = KNOWN_RENDERER_AGENTS.find((agent2) => agent2 === account.harnessId);
24676
+ if (agent) {
24677
+ const logo = document2.createElement("div");
24678
+ logo.className = "settings-harness-account__logo";
24679
+ logo.setAttribute("aria-hidden", "true");
24680
+ logo.append(createRendererAgentIcon(agent, 28, document2));
24681
+ person.append(logo);
24682
+ }
24683
+ person.append(identity);
24684
+ row.append(person);
24685
+ if (usage) row.append(usage);
24686
+ const actions = document2.createElement("div");
24687
+ actions.className = "settings-harness-account__actions";
24688
+ if (account.loginCommand) {
24689
+ const loginBtn = document2.createElement("button");
24690
+ loginBtn.type = "button";
24691
+ loginBtn.className = "settings-command-button settings-command-button--secondary settings-harness-account__login-btn";
24692
+ loginBtn.append(createRendererSettingsIcon("external-link", 14), messages.harnessAccountLogin);
24693
+ loginBtn.title = account.loginCommand;
24694
+ loginBtn.addEventListener("click", () => {
24695
+ const client = getClient();
24696
+ if (!client?.loginHarnessAccount) return;
24697
+ loginBtn.disabled = true;
24698
+ loginBtn.textContent = messages.harnessAccountLoginStarted;
24699
+ void client.loginHarnessAccount({ harnessId: account.harnessId }).finally(() => {
24700
+ document2.defaultView?.setTimeout(() => {
24701
+ loginBtn.disabled = false;
24702
+ loginBtn.replaceChildren(createRendererSettingsIcon("external-link", 14), messages.harnessAccountLogin);
24703
+ void refresh();
24704
+ }, 3e3);
24705
+ });
24706
+ });
24707
+ actions.append(loginBtn);
24708
+ }
24709
+ if (actions.childElementCount > 0) {
24710
+ row.append(actions);
24711
+ }
24712
+ list.append(row);
24723
24713
  }
24724
- return usage;
24725
- }
24726
- const credits = state.credits;
24727
- const windows = [
24728
- {
24729
- label: credits.label ?? creditsPeriodLabel2(credits.periodType, messages),
24730
- usedPercent: credits.usedPercent,
24731
- resetsAt: credits.resetsAt
24732
- },
24733
- ...(credits.productUsage ?? []).map((product) => ({
24734
- label: creditsProductLabel(product.product, messages),
24735
- usedPercent: product.usagePercent,
24736
- resetsAt: product.resetsAt
24737
- }))
24738
- ];
24739
- for (const window2 of windows) {
24740
- const meter = document2.createElement("div");
24741
- meter.className = "settings-account-usage__meter";
24742
- const label = document2.createElement("span");
24743
- label.className = "settings-account-usage__title";
24744
- label.textContent = window2.label;
24745
- label.title = window2.label;
24746
- const value = display === "remaining" ? 100 - window2.usedPercent : window2.usedPercent;
24747
- const valueLabel = display === "remaining" ? messages.accountCreditsRemaining : messages.accountCreditsUsed;
24748
- const tone = rendererCreditsTone(window2.usedPercent);
24749
- const bar = document2.createElement("div");
24750
- bar.className = `settings-account-usage__bar settings-account-usage__bar--${tone}`;
24751
- bar.setAttribute("role", "meter");
24752
- bar.setAttribute("aria-label", `${window2.label} \xB7 ${valueLabel}`);
24753
- bar.setAttribute("aria-valuemin", "0");
24754
- bar.setAttribute("aria-valuemax", "100");
24755
- bar.setAttribute("aria-valuenow", String(value));
24756
- const fill = document2.createElement("span");
24757
- fill.style.width = `${Math.min(100, Math.max(0, value))}%`;
24758
- bar.append(fill);
24759
- const percent = document2.createElement("span");
24760
- percent.className = `settings-account-usage__percent settings-account-usage__percent--${tone}`;
24761
- const prefix = document2.createElement("span");
24762
- prefix.textContent = valueLabel;
24763
- prefix.className = "settings-account-usage__value-label";
24764
- const number4 = document2.createElement("span");
24765
- number4.textContent = formatRendererCreditsPercent(value);
24766
- percent.append(prefix, number4);
24767
- meter.append(label, bar, percent);
24768
- if (window2.resetsAt) {
24769
- const reset = document2.createElement("span");
24770
- reset.className = "settings-account-usage__sub";
24771
- reset.textContent = `${formatAccountCreditsReset(window2.resetsAt, messages.locale)} ${messages.accountCreditsReset}`;
24772
- meter.append(reset);
24714
+ if (accounts.length && !visible.length) {
24715
+ const empty = document2.createElement("p");
24716
+ empty.className = "settings-account-empty";
24717
+ empty.textContent = messages.accountNoMatches;
24718
+ list.append(empty);
24773
24719
  }
24774
- usage.append(meter);
24775
- }
24776
- return usage;
24720
+ };
24721
+ refresh = async () => {
24722
+ if (refreshing || context.signal.aborted) return;
24723
+ const client = getClient();
24724
+ if (!client?.listHarnessAccounts) return;
24725
+ refreshing = true;
24726
+ onChange();
24727
+ try {
24728
+ const result = await client.listHarnessAccounts();
24729
+ if (!context.signal.aborted) accounts = result.accounts;
24730
+ } catch {
24731
+ if (!context.signal.aborted) accounts = [];
24732
+ } finally {
24733
+ refreshing = false;
24734
+ if (!context.signal.aborted) {
24735
+ render();
24736
+ onChange();
24737
+ }
24738
+ }
24739
+ };
24740
+ return {
24741
+ get refreshing() {
24742
+ return refreshing;
24743
+ },
24744
+ update(nextQuery, nextDisplay) {
24745
+ query = nextQuery;
24746
+ display = nextDisplay;
24747
+ render();
24748
+ },
24749
+ refresh
24750
+ };
24777
24751
  }
24778
- function renderAccountResetCredits(document2, credits, messages, options) {
24779
- const resetCredits = credits.resetCredits;
24780
- if (!resetCredits) return null;
24781
- const summary = document2.createElement("button");
24782
- summary.type = "button";
24783
- summary.className = "settings-account-reset-summary";
24784
- summary.setAttribute("aria-label", messages.accountResetCreditsDetails);
24785
- summary.title = messages.accountResetCreditsDetails;
24786
- const count = document2.createElement("span");
24787
- count.textContent = messages.locale === "zh-CN" ? `${resetCredits.availableCount} \u5F20` : String(resetCredits.availableCount);
24788
- summary.append(
24789
- createRendererSettingsIcon("ticket", 16),
24790
- count,
24791
- createRendererSettingsIcon("chevron-right", 14)
24792
- );
24793
- const details = document2.createElement("div");
24794
- details.className = "settings-account-reset-details";
24795
- const copy = document2.createElement("div");
24796
- const heading = document2.createElement("strong");
24797
- heading.textContent = messages.accountResetCredits;
24798
- copy.append(heading);
24799
- if (resetCredits.nextExpiresAt) {
24800
- const next = document2.createElement("p");
24801
- next.className = "settings-account-reset-expiry";
24802
- const reset = formatAccountCreditsReset(resetCredits.nextExpiresAt, messages.locale);
24803
- next.textContent = messages.locale === "zh-CN" ? `\u6700\u65E9 ${reset}\u5230\u671F` : `Next expires ${reset}`;
24804
- const remaining = Date.parse(resetCredits.nextExpiresAt) - Date.now();
24805
- if (remaining <= 24 * 60 * 60 * 1e3) {
24806
- next.className += remaining <= 8 * 60 * 60 * 1e3 ? " is-hot" : " is-warn";
24752
+
24753
+ // src/native-ui/renderer-extension/src/settings/accounts-page.ts
24754
+ function errorMessage(error51, fallback) {
24755
+ return error51 instanceof Error && error51.message ? error51.message : fallback;
24756
+ }
24757
+ function createAccountsSettingsPage(messages, getClient) {
24758
+ return Object.freeze({
24759
+ id: "accounts",
24760
+ label: messages.pageLabels.accounts,
24761
+ icon: "accounts",
24762
+ mount(context) {
24763
+ const document2 = context.content.ownerDocument;
24764
+ const header = document2.createElement("div");
24765
+ header.className = "settings-account-header";
24766
+ const copy = document2.createElement("div");
24767
+ const eyebrow = document2.createElement("p");
24768
+ eyebrow.className = "settings-account-eyebrow";
24769
+ eyebrow.textContent = "ACCOUNT MANAGEMENT";
24770
+ const heading = document2.createElement("h1");
24771
+ heading.className = "settings-section-label";
24772
+ heading.textContent = messages.pageLabels.accounts;
24773
+ const description = document2.createElement("p");
24774
+ description.className = "settings-page-description";
24775
+ description.textContent = messages.accountsDescription;
24776
+ copy.append(eyebrow, heading, description);
24777
+ const add = document2.createElement("button");
24778
+ add.type = "button";
24779
+ add.className = "settings-command-button";
24780
+ add.append(createRendererSettingsIcon("add", 16), messages.accountAdd);
24781
+ header.append(copy, add);
24782
+ const status = document2.createElement("p");
24783
+ status.className = "settings-account-status";
24784
+ status.setAttribute("aria-live", "polite");
24785
+ const helpRow = document2.createElement("div");
24786
+ helpRow.className = "settings-account-help-row";
24787
+ const taskHint = document2.createElement("p");
24788
+ taskHint.className = "settings-account-task-hint";
24789
+ const taskHintText = document2.createElement("span");
24790
+ taskHintText.textContent = messages.accountTaskHint;
24791
+ taskHint.append(createRendererSettingsIcon("info", 16), taskHintText);
24792
+ const help = document2.createElement("button");
24793
+ help.type = "button";
24794
+ help.className = "settings-account-help-button";
24795
+ help.append(createRendererSettingsIcon("help", 16), messages.accountLoginHelp);
24796
+ help.setAttribute("aria-expanded", "false");
24797
+ help.setAttribute("aria-controls", "settings-account-login-help");
24798
+ const deviceCodeNote = document2.createElement("p");
24799
+ deviceCodeNote.id = "settings-account-login-help";
24800
+ deviceCodeNote.className = "settings-account-device-code-note";
24801
+ deviceCodeNote.textContent = messages.accountDeviceCodePrerequisite;
24802
+ deviceCodeNote.hidden = true;
24803
+ help.addEventListener("click", () => {
24804
+ deviceCodeNote.hidden = !deviceCodeNote.hidden;
24805
+ help.setAttribute("aria-expanded", String(!deviceCodeNote.hidden));
24806
+ });
24807
+ helpRow.append(taskHint, help);
24808
+ const toolbar = document2.createElement("div");
24809
+ toolbar.className = "settings-account-toolbar";
24810
+ const connected = document2.createElement("div");
24811
+ connected.className = "settings-account-count";
24812
+ const connectedLabel = document2.createElement("span");
24813
+ connectedLabel.textContent = messages.accountConnected;
24814
+ const connectedCount = document2.createElement("span");
24815
+ connected.append(connectedLabel, connectedCount);
24816
+ const searchWrapper = document2.createElement("label");
24817
+ searchWrapper.className = "settings-account-search";
24818
+ const search = document2.createElement("input");
24819
+ search.type = "search";
24820
+ search.name = "account-search";
24821
+ search.autocomplete = "off";
24822
+ search.spellcheck = false;
24823
+ search.placeholder = messages.accountSearch;
24824
+ search.setAttribute("aria-label", messages.accountSearch);
24825
+ searchWrapper.append(createRendererSettingsIcon("search", 16), search);
24826
+ const displayControls = document2.createElement("div");
24827
+ displayControls.className = "settings-account-display-controls";
24828
+ const displayButtons = /* @__PURE__ */ new Map();
24829
+ for (const display of ["used", "remaining"]) {
24830
+ const button = document2.createElement("button");
24831
+ button.type = "button";
24832
+ button.textContent = display === "used" ? messages.accountCreditsUsed : messages.accountCreditsRemaining;
24833
+ button.addEventListener("click", () => {
24834
+ usageDisplay = display;
24835
+ render();
24836
+ });
24837
+ displayButtons.set(display, button);
24838
+ displayControls.append(button);
24839
+ }
24840
+ const refreshUsage = document2.createElement("button");
24841
+ refreshUsage.type = "button";
24842
+ refreshUsage.className = "settings-icon-button";
24843
+ refreshUsage.title = messages.accountCreditsRefresh;
24844
+ refreshUsage.setAttribute("aria-label", messages.accountCreditsRefresh);
24845
+ refreshUsage.append(createRendererSettingsIcon("refresh", 16));
24846
+ refreshUsage.addEventListener("click", () => {
24847
+ usageByAccountId.clear();
24848
+ loadUsage(accounts);
24849
+ void harnessAccounts?.refresh();
24850
+ });
24851
+ search.addEventListener("input", () => render());
24852
+ toolbar.append(connected, searchWrapper, displayControls, refreshUsage);
24853
+ const list = document2.createElement("div");
24854
+ list.className = "settings-account-list";
24855
+ const { table, body } = createAccountsTable(document2, messages);
24856
+ list.append(table);
24857
+ context.content.append(header, helpRow, deviceCodeNote, status, toolbar, list);
24858
+ let accounts = [];
24859
+ let accountCreating = false;
24860
+ let accountActivating = false;
24861
+ let deletingAccountId = null;
24862
+ let login = null;
24863
+ let loginStartingAccountId = null;
24864
+ let loginMessage = null;
24865
+ let loginRefreshTimer;
24866
+ const usageByAccountId = /* @__PURE__ */ new Map();
24867
+ let usingResetAccountId = null;
24868
+ let usageDisplay = "remaining";
24869
+ const expandedResetAccounts = /* @__PURE__ */ new Set();
24870
+ const accountBusy = () => accountCreating || accountActivating || deletingAccountId !== null || login !== null || loginStartingAccountId !== null || usingResetAccountId !== null;
24871
+ const clearLoginRefresh = () => {
24872
+ if (loginRefreshTimer === void 0) return;
24873
+ document2.defaultView?.clearTimeout(loginRefreshTimer);
24874
+ loginRefreshTimer = void 0;
24875
+ };
24876
+ const scheduleLoginRefresh = () => {
24877
+ clearLoginRefresh();
24878
+ if (!login || context.signal.aborted) return;
24879
+ loginRefreshTimer = document2.defaultView?.setTimeout(() => {
24880
+ loginRefreshTimer = void 0;
24881
+ if (!login || context.signal.aborted) return;
24882
+ void context.runLatest(
24883
+ () => client().refreshCodexAccounts?.() ?? client().listCodexAccounts(),
24884
+ {
24885
+ success(result) {
24886
+ const signedIn = result.accounts.some(
24887
+ (account) => account.accountId === login?.accountId && account.email
24888
+ );
24889
+ if (signedIn) {
24890
+ login = null;
24891
+ loginMessage = messages.accountLoginSucceeded;
24892
+ }
24893
+ setAccounts(result.accounts);
24894
+ scheduleLoginRefresh();
24895
+ },
24896
+ failure() {
24897
+ scheduleLoginRefresh();
24898
+ }
24899
+ }
24900
+ );
24901
+ }, 750);
24902
+ };
24903
+ const render = () => {
24904
+ const restoreFocus = accountListFocusRestorer(list, search);
24905
+ body.replaceChildren();
24906
+ status.textContent = loginMessage ?? "";
24907
+ connectedCount.textContent = String(accounts.filter((account) => account.email).length);
24908
+ search.disabled = login !== null || loginStartingAccountId !== null;
24909
+ for (const [display, button] of displayButtons) {
24910
+ button.setAttribute("aria-pressed", String(display === usageDisplay));
24911
+ }
24912
+ refreshUsage.disabled = (!getClient()?.inspectCodexAccountUsage || !accounts.some((account) => account.email)) && !getClient()?.listHarnessAccounts || harnessAccounts?.refreshing === true || [...usageByAccountId.values()].some((usage) => usage.status === "loading") || accountBusy();
24913
+ const query = search.value.trim().toLocaleLowerCase();
24914
+ harnessAccounts?.update(query, usageDisplay);
24915
+ const visibleAccounts = accounts.filter(
24916
+ (account) => `${account.email ?? ""} ${account.label}`.toLocaleLowerCase().includes(query)
24917
+ );
24918
+ if (visibleAccounts.length === 0) {
24919
+ const emptyRow = document2.createElement("tr");
24920
+ const emptyCell = document2.createElement("td");
24921
+ emptyCell.colSpan = 4;
24922
+ emptyCell.className = "settings-account-empty";
24923
+ emptyCell.textContent = query ? messages.accountNoMatches : messages.accountEmpty;
24924
+ emptyRow.append(emptyCell);
24925
+ body.append(emptyRow);
24926
+ }
24927
+ add.disabled = accountBusy();
24928
+ for (const account of visibleAccounts) {
24929
+ body.append(
24930
+ ...renderAccountRows(document2, account, messages, {
24931
+ usage: usageByAccountId.get(account.accountId),
24932
+ display: usageDisplay,
24933
+ actionsDisabled: accountBusy(),
24934
+ usingReset: usingResetAccountId === account.accountId,
24935
+ resetDisabled: accountBusy(),
24936
+ resetExpanded: expandedResetAccounts.has(account.accountId),
24937
+ onActivate: () => mutate(() => client().activateCodexAccount({ accountId: account.accountId })),
24938
+ onSignIn: () => startLogin(account.accountId),
24939
+ onDelete: () => deleteAccount(account.accountId),
24940
+ onRetry: () => {
24941
+ usageByAccountId.delete(account.accountId);
24942
+ loadUsage(accounts);
24943
+ },
24944
+ onResetExpanded: (open) => {
24945
+ if (open) expandedResetAccounts.add(account.accountId);
24946
+ else expandedResetAccounts.delete(account.accountId);
24947
+ },
24948
+ ...getClient()?.consumeCodexAccountResetCredit ? { onUseReset: () => useReset(account.accountId) } : {}
24949
+ })
24950
+ );
24951
+ if (login?.accountId === account.accountId) {
24952
+ const verification = document2.createElement("div");
24953
+ verification.className = "settings-account-verification";
24954
+ const prompt = document2.createElement("span");
24955
+ prompt.textContent = messages.accountVerificationDescription;
24956
+ const link = document2.createElement("a");
24957
+ link.href = login.verificationUrl;
24958
+ link.target = "_blank";
24959
+ link.rel = "noopener noreferrer";
24960
+ link.textContent = login.verificationUrl;
24961
+ link.addEventListener("click", (event) => {
24962
+ const bridge = document2.defaultView?.electronBridge;
24963
+ if (typeof bridge?.sendMessageFromView !== "function") return;
24964
+ event.preventDefault();
24965
+ void Promise.resolve(
24966
+ bridge.sendMessageFromView({
24967
+ type: "open-in-browser",
24968
+ url: login?.verificationUrl ?? link.href,
24969
+ initiator: "open_in_browser_bridge",
24970
+ openTarget: "external-browser",
24971
+ source: "manual"
24972
+ })
24973
+ ).catch(() => void 0);
24974
+ });
24975
+ const code = document2.createElement("code");
24976
+ code.textContent = login.userCode;
24977
+ const copyCode = document2.createElement("button");
24978
+ copyCode.type = "button";
24979
+ copyCode.className = "settings-command-button settings-command-button--secondary";
24980
+ copyCode.textContent = messages.accountCopyCode;
24981
+ copyCode.addEventListener("click", () => {
24982
+ void document2.defaultView?.navigator.clipboard?.writeText(login?.userCode ?? "").then(() => {
24983
+ copyCode.textContent = messages.accountCopied;
24984
+ });
24985
+ });
24986
+ const cancel = document2.createElement("button");
24987
+ cancel.type = "button";
24988
+ cancel.className = "settings-command-button settings-command-button--secondary";
24989
+ cancel.textContent = messages.accountLoginCancel;
24990
+ cancel.addEventListener(
24991
+ "click",
24992
+ () => cancelLogin(login?.accountId ?? "", login?.loginId ?? "")
24993
+ );
24994
+ verification.append(prompt, link, code, copyCode, cancel);
24995
+ const verificationRow = document2.createElement("tr");
24996
+ const verificationCell = document2.createElement("td");
24997
+ verificationCell.colSpan = 4;
24998
+ verificationCell.append(verification);
24999
+ verificationRow.append(verificationCell);
25000
+ body.append(verificationRow);
25001
+ }
25002
+ }
25003
+ restoreFocus();
25004
+ };
25005
+ const client = () => {
25006
+ const value = getClient();
25007
+ if (!value) throw new Error(messages.runtimeCapabilityNotInstalled);
25008
+ return value;
25009
+ };
25010
+ const loadUsage = (nextAccounts) => {
25011
+ const inspect = getClient()?.inspectCodexAccountUsage;
25012
+ const signedIn = nextAccounts.filter((account) => account.email);
25013
+ const keep = new Set(signedIn.map((account) => account.accountId));
25014
+ for (const accountId of [...usageByAccountId.keys()]) {
25015
+ if (!keep.has(accountId)) usageByAccountId.delete(accountId);
25016
+ }
25017
+ const pending = signedIn.filter((account) => !usageByAccountId.has(account.accountId));
25018
+ if (!inspect || pending.length === 0) {
25019
+ render();
25020
+ return;
25021
+ }
25022
+ const requests = pending.map((account) => {
25023
+ const loading = { status: "loading" };
25024
+ usageByAccountId.set(account.accountId, loading);
25025
+ return { account, loading };
25026
+ });
25027
+ render();
25028
+ void Promise.all(
25029
+ requests.map(async ({ account, loading }) => {
25030
+ try {
25031
+ const result = await inspect({ accountId: account.accountId });
25032
+ if (context.signal.aborted || usageByAccountId.get(account.accountId) !== loading)
25033
+ return;
25034
+ usageByAccountId.set(
25035
+ account.accountId,
25036
+ result.accountCredits ? { status: "ready", credits: result.accountCredits } : { status: "empty" }
25037
+ );
25038
+ } catch {
25039
+ if (context.signal.aborted || usageByAccountId.get(account.accountId) !== loading)
25040
+ return;
25041
+ usageByAccountId.set(account.accountId, { status: "error" });
25042
+ }
25043
+ render();
25044
+ })
25045
+ );
25046
+ };
25047
+ const setAccounts = (nextAccounts) => {
25048
+ accounts = nextAccounts;
25049
+ for (const accountId of expandedResetAccounts) {
25050
+ if (!accounts.some((account) => account.accountId === accountId))
25051
+ expandedResetAccounts.delete(accountId);
25052
+ }
25053
+ loadUsage(nextAccounts);
25054
+ };
25055
+ const refreshInBackground = () => {
25056
+ if (!client().refreshCodexAccounts) return;
25057
+ void context.runLatest(
25058
+ () => client().refreshCodexAccounts?.() ?? client().listCodexAccounts(),
25059
+ {
25060
+ success(result) {
25061
+ setAccounts(result.accounts);
25062
+ },
25063
+ failure() {
25064
+ }
25065
+ }
25066
+ );
25067
+ };
25068
+ const load = () => {
25069
+ void context.runLatest(() => client().listCodexAccounts(), {
25070
+ success(result) {
25071
+ loginMessage = null;
25072
+ setAccounts(result.accounts);
25073
+ refreshInBackground();
25074
+ },
25075
+ failure(error51) {
25076
+ loginMessage = errorMessage(error51, messages.accountLoadFailed);
25077
+ render();
25078
+ }
25079
+ });
25080
+ };
25081
+ const mutate = (operation) => {
25082
+ if (accountBusy()) return;
25083
+ accountActivating = true;
25084
+ render();
25085
+ void context.runLatest(() => operation(), {
25086
+ success(result) {
25087
+ accountActivating = false;
25088
+ loginMessage = null;
25089
+ setAccounts(
25090
+ accounts.map((account) => ({
25091
+ ...account.accountId === result.account.accountId ? result.account : account,
25092
+ active: account.accountId === result.account.accountId
25093
+ }))
25094
+ );
25095
+ },
25096
+ failure(error51) {
25097
+ accountActivating = false;
25098
+ loginMessage = errorMessage(error51, messages.accountLoadFailed);
25099
+ render();
25100
+ }
25101
+ });
25102
+ };
25103
+ const startLogin = (accountId) => {
25104
+ if (accountBusy()) return;
25105
+ loginStartingAccountId = accountId;
25106
+ loginMessage = messages.accountSigningIn;
25107
+ render();
25108
+ void context.runLatest(() => client().startCodexAccountLogin({ accountId }), {
25109
+ success(result) {
25110
+ loginStartingAccountId = null;
25111
+ login = result;
25112
+ loginMessage = null;
25113
+ render();
25114
+ scheduleLoginRefresh();
25115
+ },
25116
+ failure(error51) {
25117
+ loginStartingAccountId = null;
25118
+ loginMessage = errorMessage(error51, messages.accountLoginFailed);
25119
+ render();
25120
+ }
25121
+ });
25122
+ };
25123
+ const createAndLogin = () => {
25124
+ if (accountBusy()) return;
25125
+ accountCreating = true;
25126
+ loginMessage = messages.accountSigningIn;
25127
+ render();
25128
+ void context.runLatest(() => client().createCodexAccount({}), {
25129
+ success(result) {
25130
+ accountCreating = false;
25131
+ loginMessage = null;
25132
+ search.value = "";
25133
+ setAccounts([
25134
+ ...accounts.filter(({ accountId }) => accountId !== result.account.accountId),
25135
+ result.account
25136
+ ]);
25137
+ startLogin(result.account.accountId);
25138
+ },
25139
+ failure(error51) {
25140
+ accountCreating = false;
25141
+ loginMessage = errorMessage(error51, messages.accountCreateFailed);
25142
+ render();
25143
+ }
25144
+ });
25145
+ };
25146
+ const resetOutcomeMessage = (outcome) => {
25147
+ if (outcome === "reset") return messages.accountResetCreditsSucceeded;
25148
+ if (outcome === "nothingToReset") return messages.accountResetCreditsNothingToReset;
25149
+ if (outcome === "noCredit") return messages.accountResetCreditsNoCredit;
25150
+ return messages.accountResetCreditsAlreadyRedeemed;
25151
+ };
25152
+ const useReset = (accountId) => {
25153
+ const consume = getClient()?.consumeCodexAccountResetCredit;
25154
+ if (!consume || accountBusy()) return;
25155
+ if (document2.defaultView?.confirm?.(messages.accountResetCreditsConfirm) === false) return;
25156
+ usingResetAccountId = accountId;
25157
+ loginMessage = messages.accountResetCreditsUsing;
25158
+ render();
25159
+ void context.runLatest(() => consume({ accountId, idempotencyKey: crypto.randomUUID() }), {
25160
+ success(result) {
25161
+ usingResetAccountId = null;
25162
+ loginMessage = resetOutcomeMessage(result.outcome);
25163
+ if (result.accountCredits) {
25164
+ usageByAccountId.set(accountId, {
25165
+ status: "ready",
25166
+ credits: result.accountCredits
25167
+ });
25168
+ } else if (result.outcome === "reset") {
25169
+ usageByAccountId.delete(accountId);
25170
+ loadUsage(accounts);
25171
+ }
25172
+ render();
25173
+ },
25174
+ failure(error51) {
25175
+ usingResetAccountId = null;
25176
+ loginMessage = errorMessage(error51, messages.accountResetCreditsFailed);
25177
+ render();
25178
+ }
25179
+ });
25180
+ };
25181
+ const deleteAccount = (accountId) => {
25182
+ const account = accounts.find((candidate) => candidate.accountId === accountId);
25183
+ if (!account || account.isDefault || accountBusy()) return;
25184
+ if (document2.defaultView?.confirm?.(messages.accountDeleteConfirm) === false) return;
25185
+ deletingAccountId = accountId;
25186
+ loginMessage = messages.accountDeleting;
25187
+ render();
25188
+ void context.runLatest(() => client().deleteCodexAccount({ accountId }), {
25189
+ success() {
25190
+ deletingAccountId = null;
25191
+ loginMessage = null;
25192
+ setAccounts(
25193
+ accounts.filter((candidate) => candidate.accountId !== accountId).map((candidate) => ({
25194
+ ...candidate,
25195
+ active: account.active ? candidate.isDefault : candidate.active
25196
+ }))
25197
+ );
25198
+ },
25199
+ failure(error51) {
25200
+ deletingAccountId = null;
25201
+ loginMessage = errorMessage(error51, messages.accountDeleteFailed);
25202
+ render();
25203
+ }
25204
+ });
25205
+ };
25206
+ const cancelLogin = (accountId, loginId) => {
25207
+ void context.runLatest(() => client().cancelCodexAccountLogin({ accountId, loginId }), {
25208
+ success() {
25209
+ clearLoginRefresh();
25210
+ login = null;
25211
+ loginMessage = null;
25212
+ render();
25213
+ },
25214
+ failure(error51) {
25215
+ loginMessage = errorMessage(error51, messages.accountLoginFailed);
25216
+ render();
25217
+ }
25218
+ });
25219
+ };
25220
+ add.addEventListener("click", createAndLogin);
25221
+ let unsubscribe;
25222
+ try {
25223
+ unsubscribe = getClient()?.subscribeCodexAccountLogin?.((result) => {
25224
+ if (result.loginId !== login?.loginId) return;
25225
+ clearLoginRefresh();
25226
+ login = null;
25227
+ loginMessage = result.success ? messages.accountLoginSucceeded : result.error ?? messages.accountLoginFailed;
25228
+ render();
25229
+ if (result.success) load();
25230
+ });
25231
+ } catch {
25232
+ }
25233
+ const harnessAccounts = mountHarnessAccounts(context, messages, getClient, render);
25234
+ void harnessAccounts.refresh();
25235
+ load();
25236
+ return () => {
25237
+ clearLoginRefresh();
25238
+ unsubscribe?.();
25239
+ };
24807
25240
  }
24808
- copy.append(next);
25241
+ });
25242
+ }
25243
+
25244
+ // src/native-ui/renderer-extension/src/settings/core.ts
25245
+ var SETTINGS_PAGE_ID_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
25246
+ var MAX_SETTINGS_PAGE_ID_LENGTH = 48;
25247
+ var MAX_SETTINGS_PAGE_LABEL_LENGTH = 64;
25248
+ function normalizedPage(page) {
25249
+ if (page.id.length === 0 || page.id.length > MAX_SETTINGS_PAGE_ID_LENGTH || !SETTINGS_PAGE_ID_PATTERN.test(page.id)) {
25250
+ throw new Error(`Invalid settings page ID: ${page.id || "(empty)"}`);
24809
25251
  }
24810
- if (resetCredits.expiresAt?.length) {
24811
- const list = document2.createElement("ul");
24812
- list.className = "settings-account-reset-list";
24813
- for (const [index, expiresAt] of resetCredits.expiresAt.entries()) {
24814
- const item = document2.createElement("li");
24815
- item.textContent = resetCreditDetailLine(index + 1, expiresAt, messages);
24816
- list.append(item);
24817
- }
24818
- copy.append(list);
25252
+ const label = page.label.trim();
25253
+ if (label.length === 0 || label.length > MAX_SETTINGS_PAGE_LABEL_LENGTH) {
25254
+ throw new Error(`Invalid settings page label for ${page.id}`);
24819
25255
  }
24820
- details.append(copy);
24821
- if (options.onUseReset) {
24822
- const use = document2.createElement("button");
24823
- use.type = "button";
24824
- use.className = "settings-command-button settings-command-button--secondary";
24825
- use.textContent = options.usingReset ? messages.accountResetCreditsUsing : messages.accountResetCreditsUse;
24826
- use.disabled = options.resetDisabled;
24827
- use.addEventListener("click", options.onUseReset);
24828
- details.append(use);
25256
+ if (!isRendererSettingsIconName(page.icon)) {
25257
+ throw new Error(`Unknown settings page icon for ${page.id}`);
24829
25258
  }
24830
- return { summary, details };
24831
- }
24832
-
24833
- // src/native-ui/renderer-extension/src/settings/accounts-list.ts
24834
- var resetDetailsSequence = 0;
24835
- function accountPlanLabel(planType) {
24836
- if (!planType || planType === "unknown") return null;
24837
- if (planType === "free") return "Free";
24838
- if (planType === "go") return "Go";
24839
- if (planType === "plus") return "Plus";
24840
- if (planType === "pro") return "Pro 20x";
24841
- if (planType === "prolite") return "Pro 5x";
24842
- if (planType === "team") return "Team";
24843
- if (planType === "self_serve_business_prolite") return "Business Pro Lite";
24844
- if (planType === "self_serve_business_usage_based") return "Business";
24845
- if (planType === "business") return "Business";
24846
- if (planType === "edu") return "Edu";
24847
- if (planType === "edu_plus") return "Edu Plus";
24848
- if (planType === "edu_pro") return "Edu Pro";
24849
- return "Enterprise";
25259
+ if (typeof page.mount !== "function") {
25260
+ throw new Error(`Settings page ${page.id} has no mount function`);
25261
+ }
25262
+ return Object.freeze({ ...page, label });
24850
25263
  }
24851
- function accountListFocusRestorer(list, fallback) {
24852
- const active = list.getRootNode().activeElement;
24853
- if (!active || !list.contains(active)) return () => void 0;
24854
- const key = active.getAttribute("data-account-focus");
24855
- const accountId = active.closest(".settings-account-row")?.dataset.accountId;
24856
- return () => {
24857
- const target = key ? list.querySelector(`[data-account-focus="${CSS.escape(key)}"]`) : null;
24858
- if (target && !target.matches(":disabled")) {
24859
- target.focus({ preventScroll: true });
24860
- return;
25264
+ function createRendererSettingsPageRegistry(definitions, defaultPageId) {
25265
+ if (definitions.length === 0) throw new Error("Settings page registry cannot be empty");
25266
+ const resolvedDefaultPageId = defaultPageId ?? definitions[0]?.id ?? "";
25267
+ const pages = definitions.map(normalizedPage);
25268
+ const byId = /* @__PURE__ */ new Map();
25269
+ for (const page of pages) {
25270
+ if (byId.has(page.id)) throw new Error(`Duplicate settings page ID: ${page.id}`);
25271
+ byId.set(page.id, page);
25272
+ }
25273
+ if (!byId.has(resolvedDefaultPageId)) {
25274
+ throw new Error(`Default settings page is not registered: ${resolvedDefaultPageId}`);
25275
+ }
25276
+ const frozenPages = Object.freeze([...pages]);
25277
+ return Object.freeze({
25278
+ pages: frozenPages,
25279
+ defaultPageId: resolvedDefaultPageId,
25280
+ getPage(pageId) {
25281
+ return byId.get(pageId);
24861
25282
  }
24862
- const row = accountId ? list.querySelector(
24863
- `.settings-account-row[data-account-id="${CSS.escape(accountId)}"]`
24864
- ) : null;
24865
- (row ?? fallback).focus({ preventScroll: true });
24866
- };
25283
+ });
24867
25284
  }
24868
- function createAccountsTable(document2, messages) {
24869
- const table = document2.createElement("table");
24870
- table.className = "settings-account-table";
24871
- table.setAttribute("aria-label", messages.pageLabels.accounts);
24872
- const head = document2.createElement("thead");
24873
- const row = document2.createElement("tr");
24874
- for (const label of [
24875
- messages.accountColumnAccount,
24876
- messages.accountColumnUsage,
24877
- messages.accountResetCredits,
24878
- messages.accountColumnActions
24879
- ]) {
24880
- const cell = document2.createElement("th");
24881
- cell.scope = "col";
24882
- cell.textContent = label;
24883
- row.append(cell);
25285
+ var RendererSettingsNavigationState = class {
25286
+ constructor(registry2) {
25287
+ this.registry = registry2;
25288
+ this.#activePageId = registry2.defaultPageId;
24884
25289
  }
24885
- head.append(row);
24886
- const body = document2.createElement("tbody");
24887
- table.append(head, body);
24888
- return { table, body };
24889
- }
24890
- function renderAccountRows(document2, account, messages, input) {
24891
- const row = document2.createElement("tr");
24892
- row.className = "settings-account-row";
24893
- row.dataset.accountId = account.accountId;
24894
- row.dataset.accountFocus = `${account.accountId}:row`;
24895
- row.tabIndex = -1;
24896
- const name = codexAccountDisplayName(account);
24897
- row.setAttribute("aria-label", name.full);
24898
- const personCell = document2.createElement("td");
24899
- const person = document2.createElement("div");
24900
- person.className = "settings-account-row__person";
24901
- const mark = document2.createElement("div");
24902
- mark.className = "settings-account-row__mark";
24903
- mark.setAttribute("aria-hidden", "true");
24904
- mark.append(createRendererSettingsIcon("terminal", 17));
24905
- const identity = document2.createElement("div");
24906
- identity.className = "settings-account-row__identity";
24907
- const title = document2.createElement("div");
24908
- title.className = "settings-account-title";
24909
- const local = document2.createElement("strong");
24910
- local.className = "settings-account-email";
24911
- local.textContent = name.local;
24912
- local.title = name.full;
24913
- title.append(local);
24914
- if (account.active) {
24915
- const badge = document2.createElement("span");
24916
- badge.className = "settings-account-active";
24917
- badge.textContent = messages.accountDefaultBadge;
24918
- title.append(badge);
25290
+ registry;
25291
+ #activePageId;
25292
+ get activePageId() {
25293
+ return this.#activePageId;
24919
25294
  }
24920
- identity.append(title);
24921
- const metadata = document2.createElement("div");
24922
- metadata.className = "settings-account-metadata";
24923
- if (name.domain) {
24924
- const domain2 = document2.createElement("span");
24925
- domain2.className = "settings-account-domain";
24926
- domain2.textContent = `@${name.domain}`;
24927
- metadata.append(domain2);
25295
+ select(pageId) {
25296
+ if (!this.registry.getPage(pageId)) throw new Error(`Unknown settings page: ${pageId}`);
25297
+ if (this.#activePageId === pageId) return false;
25298
+ this.#activePageId = pageId;
25299
+ return true;
24928
25300
  }
24929
- const planLabel = accountPlanLabel(account.planType);
24930
- if (planLabel) {
24931
- if (name.domain) {
24932
- const separator = document2.createElement("span");
24933
- separator.className = "settings-account-plan-separator";
24934
- separator.textContent = "\xB7";
24935
- separator.setAttribute("aria-hidden", "true");
24936
- metadata.append(separator);
24937
- }
24938
- const plan = document2.createElement("span");
24939
- plan.className = account.planType === "pro" || account.planType === "prolite" ? "settings-account-plan settings-account-plan--highlighted" : "settings-account-plan";
24940
- plan.textContent = planLabel;
24941
- metadata.append(plan);
25301
+ reset() {
25302
+ return this.select(this.registry.defaultPageId);
24942
25303
  }
24943
- if (metadata.childElementCount > 0) identity.append(metadata);
24944
- person.append(mark, identity);
24945
- personCell.append(person);
24946
- const usageCell = document2.createElement("td");
24947
- const usage = renderAccountUsage(document2, input.usage, messages, input.display, input.onRetry);
24948
- if (usage) usageCell.append(usage);
24949
- const resetCell = document2.createElement("td");
24950
- const resetLabel2 = document2.createElement("span");
24951
- resetLabel2.className = "settings-account-mobile-label";
24952
- resetLabel2.textContent = messages.accountResetCredits;
24953
- resetCell.append(resetLabel2);
24954
- const actionsCell = document2.createElement("td");
24955
- const actions = document2.createElement("div");
24956
- actions.className = "settings-account-actions";
24957
- if (!account.active) {
24958
- const activate = document2.createElement("button");
24959
- activate.type = "button";
24960
- activate.className = "settings-account-action";
24961
- activate.textContent = messages.accountUse;
24962
- activate.dataset.accountFocus = `${account.accountId}:activate`;
24963
- activate.disabled = input.actionsDisabled;
24964
- activate.addEventListener("click", input.onActivate);
24965
- actions.append(activate);
25304
+ };
25305
+ var RendererSettingsPageScope = class {
25306
+ #pageController = new AbortController();
25307
+ #requestController = null;
25308
+ #requestGeneration = 0;
25309
+ #disposed = false;
25310
+ get signal() {
25311
+ return this.#pageController.signal;
24966
25312
  }
24967
- if (!account.email) {
24968
- const signIn = document2.createElement("button");
24969
- signIn.type = "button";
24970
- signIn.className = "settings-account-action";
24971
- signIn.textContent = messages.accountSignIn;
24972
- signIn.dataset.accountFocus = `${account.accountId}:login`;
24973
- signIn.disabled = input.actionsDisabled;
24974
- signIn.addEventListener("click", input.onSignIn);
24975
- actions.append(signIn);
25313
+ get disposed() {
25314
+ return this.#disposed;
24976
25315
  }
24977
- if (!account.isDefault) {
24978
- const remove = document2.createElement("button");
24979
- remove.type = "button";
24980
- remove.className = "settings-icon-button settings-account-delete";
24981
- remove.title = messages.accountDelete;
24982
- remove.dataset.accountFocus = `${account.accountId}:delete`;
24983
- remove.setAttribute("aria-label", `${messages.accountDelete}: ${name.full}`);
24984
- remove.disabled = input.actionsDisabled;
24985
- remove.append(createRendererSettingsIcon("trash", 16));
24986
- remove.addEventListener("click", input.onDelete);
24987
- actions.append(remove);
25316
+ async runLatest(operation, handlers) {
25317
+ if (this.#disposed) throw new Error("Settings page scope is disposed");
25318
+ this.#requestController?.abort();
25319
+ const controller = new AbortController();
25320
+ this.#requestController = controller;
25321
+ const generation = ++this.#requestGeneration;
25322
+ const abortRequest = () => controller.abort();
25323
+ this.signal.addEventListener("abort", abortRequest, { once: true });
25324
+ try {
25325
+ const value = await operation(controller.signal);
25326
+ if (this.#isCurrent(controller, generation)) handlers.success(value);
25327
+ } catch (error51) {
25328
+ if (this.#isCurrent(controller, generation)) handlers.failure(error51);
25329
+ } finally {
25330
+ this.signal.removeEventListener("abort", abortRequest);
25331
+ if (this.#requestController === controller) this.#requestController = null;
25332
+ }
24988
25333
  }
24989
- actionsCell.append(actions);
24990
- row.append(personCell, usageCell, resetCell, actionsCell);
24991
- const reset = input.usage?.status === "ready" ? renderAccountResetCredits(document2, input.usage.credits, messages, input) : null;
24992
- if (!reset) {
24993
- const unknown2 = document2.createElement("span");
24994
- unknown2.className = "settings-account-unknown";
24995
- unknown2.textContent = "\u2014";
24996
- unknown2.title = messages.accountResetCreditsUnknown;
24997
- unknown2.setAttribute("aria-label", messages.accountResetCreditsUnknown);
24998
- resetCell.append(unknown2);
24999
- return [row];
25334
+ dispose() {
25335
+ if (this.#disposed) return;
25336
+ this.#disposed = true;
25337
+ this.#requestGeneration += 1;
25338
+ this.#requestController?.abort();
25339
+ this.#requestController = null;
25340
+ this.#pageController.abort();
25000
25341
  }
25001
- const detailsRow = document2.createElement("tr");
25002
- detailsRow.className = "settings-account-details-row";
25003
- detailsRow.id = `settings-account-reset-${++resetDetailsSequence}`;
25004
- detailsRow.hidden = !input.resetExpanded;
25005
- const detailsCell = document2.createElement("td");
25006
- detailsCell.colSpan = 4;
25007
- detailsCell.append(reset.details);
25008
- detailsRow.append(detailsCell);
25009
- reset.summary.dataset.accountFocus = `${account.accountId}:reset`;
25010
- reset.summary.setAttribute("aria-controls", detailsRow.id);
25011
- reset.summary.setAttribute("aria-expanded", String(input.resetExpanded));
25012
- reset.summary.addEventListener("click", () => {
25013
- detailsRow.hidden = !detailsRow.hidden;
25014
- reset.summary.setAttribute("aria-expanded", String(!detailsRow.hidden));
25015
- input.onResetExpanded(!detailsRow.hidden);
25016
- });
25017
- resetCell.append(reset.summary);
25018
- return [row, detailsRow];
25019
- }
25342
+ #isCurrent(controller, generation) {
25343
+ return !this.#disposed && !controller.signal.aborted && this.#requestController === controller && this.#requestGeneration === generation;
25344
+ }
25345
+ };
25020
25346
 
25021
- // src/native-ui/renderer-extension/src/settings/harness-accounts.ts
25022
- function mountHarnessAccounts(context, messages, getClient, onChange) {
25023
- const document2 = context.content.ownerDocument;
25024
- const section = document2.createElement("section");
25025
- section.className = "settings-harness-accounts";
25026
- section.hidden = true;
25027
- const heading = document2.createElement("h2");
25028
- heading.className = "settings-harness-accounts__title";
25029
- heading.textContent = messages.harnessAccountsTitle;
25030
- const list = document2.createElement("div");
25031
- list.className = "settings-account-list";
25032
- section.append(heading, list);
25033
- context.content.append(section);
25034
- let accounts = [];
25035
- let refreshing = false;
25347
+ // src/native-ui/renderer-extension/src/settings/session-import-list-controls.ts
25348
+ function createSessionImportListControls(document2, messages, onChange) {
25036
25349
  let query = "";
25037
- let display = "remaining";
25038
- const render = () => {
25039
- section.hidden = accounts.length === 0;
25040
- list.replaceChildren();
25041
- const visible = accounts.filter(
25042
- (account) => `${account.harnessName} ${account.email ?? ""} ${account.label ?? ""} ${account.plan ?? ""}`.toLocaleLowerCase().includes(query)
25043
- );
25044
- for (const account of visible) {
25045
- const row = document2.createElement("article");
25046
- row.className = "settings-harness-account";
25047
- row.dataset.harnessId = account.harnessId;
25048
- const identity = document2.createElement("div");
25049
- identity.className = "settings-harness-account__identity";
25050
- const name = document2.createElement("strong");
25051
- name.className = "settings-account-email";
25052
- const accountName = account.email ?? account.label;
25053
- name.textContent = accountName ?? account.harnessName;
25054
- name.title = name.textContent;
25055
- identity.append(name);
25056
- const metadata = document2.createElement("div");
25057
- metadata.className = "settings-account-metadata";
25058
- if (accountName) {
25059
- const harness = document2.createElement("span");
25060
- harness.textContent = account.harnessName;
25061
- metadata.append(harness);
25062
- }
25063
- if (account.plan) {
25064
- if (accountName) {
25065
- const separator = document2.createElement("span");
25066
- separator.textContent = "\xB7";
25067
- separator.setAttribute("aria-hidden", "true");
25068
- metadata.append(separator);
25069
- }
25070
- const plan = document2.createElement("span");
25071
- plan.className = "settings-account-plan";
25072
- plan.textContent = account.plan;
25073
- metadata.append(plan);
25074
- }
25075
- if (metadata.childElementCount) identity.append(metadata);
25076
- const usage = renderAccountUsage(
25077
- document2,
25078
- { status: "ready", credits: account.credits },
25079
- messages,
25080
- display,
25081
- () => void 0
25082
- );
25083
- const person = document2.createElement("div");
25084
- person.className = "settings-account-row__person";
25085
- const agent = KNOWN_RENDERER_AGENTS.find((agent2) => agent2 === account.harnessId);
25086
- if (agent) {
25087
- const logo = document2.createElement("div");
25088
- logo.className = "settings-harness-account__logo";
25089
- logo.setAttribute("aria-hidden", "true");
25090
- logo.append(createRendererAgentIcon(agent, 28, document2));
25091
- person.append(logo);
25092
- }
25093
- person.append(identity);
25094
- row.append(person);
25095
- if (usage) row.append(usage);
25096
- list.append(row);
25097
- }
25098
- if (accounts.length && !visible.length) {
25099
- const empty = document2.createElement("p");
25100
- empty.className = "settings-account-empty";
25101
- empty.textContent = messages.accountNoMatches;
25102
- list.append(empty);
25103
- }
25350
+ let offset = 0;
25351
+ let limit = HARNESS_SESSION_IMPORT_DEFAULT_PAGE_SIZE;
25352
+ let total = 0;
25353
+ let loading = false;
25354
+ let locked = false;
25355
+ const searchForm = document2.createElement("form");
25356
+ searchForm.className = "settings-session-import-search";
25357
+ searchForm.setAttribute("role", "search");
25358
+ const search = document2.createElement("input");
25359
+ search.type = "search";
25360
+ search.value = "";
25361
+ search.maxLength = 4096;
25362
+ search.placeholder = messages.sessionImportSearchPlaceholder;
25363
+ search.setAttribute("aria-label", messages.sessionImportSearchPlaceholder);
25364
+ search.dataset.sessionImportAction = "search-input";
25365
+ const submit = document2.createElement("button");
25366
+ submit.type = "submit";
25367
+ submit.className = "settings-command-button settings-command-button--secondary";
25368
+ submit.textContent = messages.sessionImportSearch;
25369
+ submit.dataset.sessionImportAction = "search";
25370
+ searchForm.append(search, submit);
25371
+ searchForm.addEventListener("submit", (event) => {
25372
+ event.preventDefault();
25373
+ if (locked) return;
25374
+ query = search.value.trim();
25375
+ offset = 0;
25376
+ onChange();
25377
+ });
25378
+ const pagination = document2.createElement("div");
25379
+ pagination.className = "settings-session-import-pagination";
25380
+ const pageSizeLabel = document2.createElement("label");
25381
+ pageSizeLabel.textContent = messages.sessionImportPageSize;
25382
+ const pageSize = document2.createElement("select");
25383
+ pageSize.dataset.sessionImportAction = "page-size";
25384
+ pageSize.setAttribute("aria-label", messages.sessionImportPageSize);
25385
+ for (const size of [20, 50, 100]) {
25386
+ const option = document2.createElement("option");
25387
+ option.value = String(size);
25388
+ option.textContent = String(size);
25389
+ pageSize.append(option);
25390
+ }
25391
+ pageSize.value = String(limit);
25392
+ pageSizeLabel.append(pageSize);
25393
+ pageSize.addEventListener("change", () => {
25394
+ if (locked) return;
25395
+ const value = Number(pageSize.value);
25396
+ if (![20, 50, 100].includes(value)) return;
25397
+ limit = value;
25398
+ offset = 0;
25399
+ onChange();
25400
+ });
25401
+ const summary = document2.createElement("span");
25402
+ summary.setAttribute("role", "status");
25403
+ summary.dataset.sessionImportAction = "page-summary";
25404
+ const previous = document2.createElement("button");
25405
+ const next = document2.createElement("button");
25406
+ for (const [button, label, action, direction] of [
25407
+ [previous, messages.sessionImportPrevious, "previous", -1],
25408
+ [next, messages.sessionImportNext, "next", 1]
25409
+ ]) {
25410
+ button.type = "button";
25411
+ button.className = "settings-command-button settings-command-button--secondary";
25412
+ button.textContent = label;
25413
+ button.dataset.sessionImportAction = action;
25414
+ button.addEventListener("click", () => {
25415
+ if (button.disabled || locked || loading) return;
25416
+ offset += direction * limit;
25417
+ onChange();
25418
+ });
25419
+ }
25420
+ const navigation = document2.createElement("div");
25421
+ navigation.className = "settings-session-import-pagination__navigation";
25422
+ navigation.append(previous, next);
25423
+ pagination.append(pageSizeLabel, summary, navigation);
25424
+ const update = () => {
25425
+ search.disabled = locked;
25426
+ submit.disabled = locked;
25427
+ pageSize.disabled = locked;
25428
+ previous.disabled = locked || loading || offset === 0;
25429
+ next.disabled = locked || loading || offset + limit >= total;
25430
+ summary.textContent = loading ? "" : messages.sessionImportPageSummary.replace("{page}", String(total ? Math.floor(offset / limit) + 1 : 0)).replace("{pages}", String(Math.ceil(total / limit))).replace("{total}", String(total));
25104
25431
  };
25432
+ update();
25105
25433
  return {
25106
- get refreshing() {
25107
- return refreshing;
25434
+ searchForm,
25435
+ pagination,
25436
+ params() {
25437
+ return { query, offset, limit };
25108
25438
  },
25109
- update(nextQuery, nextDisplay) {
25110
- query = nextQuery;
25111
- display = nextDisplay;
25112
- render();
25439
+ reset() {
25440
+ offset = 0;
25441
+ total = 0;
25442
+ update();
25113
25443
  },
25114
- async refresh() {
25115
- if (refreshing || context.signal.aborted) return;
25116
- const client = getClient();
25117
- if (!client?.listHarnessAccounts) return;
25118
- refreshing = true;
25119
- onChange();
25120
- try {
25121
- const result = await client.listHarnessAccounts();
25122
- if (!context.signal.aborted) accounts = result.accounts;
25123
- } catch {
25124
- if (!context.signal.aborted) accounts = [];
25125
- } finally {
25126
- refreshing = false;
25127
- if (!context.signal.aborted) {
25128
- render();
25129
- onChange();
25130
- }
25131
- }
25444
+ setBusy(value, lock = false) {
25445
+ loading = value;
25446
+ locked = lock;
25447
+ update();
25448
+ },
25449
+ setTotal(value) {
25450
+ total = value;
25451
+ const lastOffset = Math.max(0, Math.ceil(total / limit) - 1) * limit;
25452
+ const changed = offset > lastOffset;
25453
+ if (changed) offset = lastOffset;
25454
+ update();
25455
+ return changed;
25132
25456
  }
25133
25457
  };
25134
25458
  }
25135
25459
 
25136
- // src/native-ui/renderer-extension/src/settings/accounts-page.ts
25137
- function errorMessage(error51, fallback) {
25138
- return error51 instanceof Error && error51.message ? error51.message : fallback;
25460
+ // src/native-ui/renderer-extension/src/settings/session-import-page.ts
25461
+ function shortSessionId(value) {
25462
+ return value.length <= 18 ? value : `${value.slice(0, 10)}\u2026${value.slice(-6)}`;
25463
+ }
25464
+ function createStatus(document2, message, error51 = false) {
25465
+ const status = document2.createElement("div");
25466
+ status.className = error51 ? "settings-session-import-status is-error" : "settings-session-import-status";
25467
+ status.setAttribute("role", error51 ? "alert" : "status");
25468
+ status.append(createRendererSettingsIcon(error51 ? "alert" : "download", 18));
25469
+ const copy = document2.createElement("span");
25470
+ copy.textContent = message;
25471
+ status.append(copy);
25472
+ return status;
25139
25473
  }
25140
- function createAccountsSettingsPage(messages, getClient) {
25141
- return Object.freeze({
25142
- id: "accounts",
25143
- label: messages.pageLabels.accounts,
25144
- icon: "accounts",
25145
- mount(context) {
25146
- const document2 = context.content.ownerDocument;
25147
- const header = document2.createElement("div");
25148
- header.className = "settings-account-header";
25149
- const copy = document2.createElement("div");
25150
- const eyebrow = document2.createElement("p");
25151
- eyebrow.className = "settings-account-eyebrow";
25152
- eyebrow.textContent = "ACCOUNT MANAGEMENT";
25153
- const heading = document2.createElement("h1");
25154
- heading.className = "settings-section-label";
25155
- heading.textContent = messages.pageLabels.accounts;
25156
- const description = document2.createElement("p");
25157
- description.className = "settings-page-description";
25158
- description.textContent = messages.accountsDescription;
25159
- copy.append(eyebrow, heading, description);
25160
- const add = document2.createElement("button");
25161
- add.type = "button";
25162
- add.className = "settings-command-button";
25163
- add.append(createRendererSettingsIcon("add", 16), messages.accountAdd);
25164
- header.append(copy, add);
25165
- const status = document2.createElement("p");
25166
- status.className = "settings-account-status";
25167
- status.setAttribute("aria-live", "polite");
25168
- const helpRow = document2.createElement("div");
25169
- helpRow.className = "settings-account-help-row";
25170
- const taskHint = document2.createElement("p");
25171
- taskHint.className = "settings-account-task-hint";
25172
- const taskHintText = document2.createElement("span");
25173
- taskHintText.textContent = messages.accountTaskHint;
25174
- taskHint.append(createRendererSettingsIcon("info", 16), taskHintText);
25175
- const help = document2.createElement("button");
25176
- help.type = "button";
25177
- help.className = "settings-account-help-button";
25178
- help.append(createRendererSettingsIcon("help", 16), messages.accountLoginHelp);
25179
- help.setAttribute("aria-expanded", "false");
25180
- help.setAttribute("aria-controls", "settings-account-login-help");
25181
- const deviceCodeNote = document2.createElement("p");
25182
- deviceCodeNote.id = "settings-account-login-help";
25183
- deviceCodeNote.className = "settings-account-device-code-note";
25184
- deviceCodeNote.textContent = messages.accountDeviceCodePrerequisite;
25185
- deviceCodeNote.hidden = true;
25186
- help.addEventListener("click", () => {
25187
- deviceCodeNote.hidden = !deviceCodeNote.hidden;
25188
- help.setAttribute("aria-expanded", String(!deviceCodeNote.hidden));
25189
- });
25190
- helpRow.append(taskHint, help);
25191
- const toolbar = document2.createElement("div");
25192
- toolbar.className = "settings-account-toolbar";
25193
- const connected = document2.createElement("div");
25194
- connected.className = "settings-account-count";
25195
- const connectedLabel = document2.createElement("span");
25196
- connectedLabel.textContent = messages.accountConnected;
25197
- const connectedCount = document2.createElement("span");
25198
- connected.append(connectedLabel, connectedCount);
25199
- const searchWrapper = document2.createElement("label");
25200
- searchWrapper.className = "settings-account-search";
25201
- const search = document2.createElement("input");
25202
- search.type = "search";
25203
- search.name = "account-search";
25204
- search.autocomplete = "off";
25205
- search.spellcheck = false;
25206
- search.placeholder = messages.accountSearch;
25207
- search.setAttribute("aria-label", messages.accountSearch);
25208
- searchWrapper.append(createRendererSettingsIcon("search", 16), search);
25209
- const displayControls = document2.createElement("div");
25210
- displayControls.className = "settings-account-display-controls";
25211
- const displayButtons = /* @__PURE__ */ new Map();
25212
- for (const display of ["used", "remaining"]) {
25213
- const button = document2.createElement("button");
25214
- button.type = "button";
25215
- button.textContent = display === "used" ? messages.accountCreditsUsed : messages.accountCreditsRemaining;
25216
- button.addEventListener("click", () => {
25217
- usageDisplay = display;
25218
- render();
25219
- });
25220
- displayButtons.set(display, button);
25221
- displayControls.append(button);
25222
- }
25223
- const refreshUsage = document2.createElement("button");
25224
- refreshUsage.type = "button";
25225
- refreshUsage.className = "settings-icon-button";
25226
- refreshUsage.title = messages.accountCreditsRefresh;
25227
- refreshUsage.setAttribute("aria-label", messages.accountCreditsRefresh);
25228
- refreshUsage.append(createRendererSettingsIcon("refresh", 16));
25229
- refreshUsage.addEventListener("click", () => {
25230
- usageByAccountId.clear();
25231
- loadUsage(accounts);
25232
- void harnessAccounts?.refresh();
25233
- });
25234
- search.addEventListener("input", () => render());
25235
- toolbar.append(connected, searchWrapper, displayControls, refreshUsage);
25236
- const list = document2.createElement("div");
25237
- list.className = "settings-account-list";
25238
- const { table, body } = createAccountsTable(document2, messages);
25239
- list.append(table);
25240
- context.content.append(header, helpRow, deviceCodeNote, status, toolbar, list);
25241
- let accounts = [];
25242
- let accountCreating = false;
25243
- let accountActivating = false;
25244
- let deletingAccountId = null;
25245
- let login = null;
25246
- let loginStartingAccountId = null;
25247
- let loginMessage = null;
25248
- let loginRefreshTimer;
25249
- const usageByAccountId = /* @__PURE__ */ new Map();
25250
- let usingResetAccountId = null;
25251
- let usageDisplay = "remaining";
25252
- const expandedResetAccounts = /* @__PURE__ */ new Set();
25253
- const accountBusy = () => accountCreating || accountActivating || deletingAccountId !== null || login !== null || loginStartingAccountId !== null || usingResetAccountId !== null;
25254
- const clearLoginRefresh = () => {
25255
- if (loginRefreshTimer === void 0) return;
25256
- document2.defaultView?.clearTimeout(loginRefreshTimer);
25257
- loginRefreshTimer = void 0;
25258
- };
25259
- const scheduleLoginRefresh = () => {
25260
- clearLoginRefresh();
25261
- if (!login || context.signal.aborted) return;
25262
- loginRefreshTimer = document2.defaultView?.setTimeout(() => {
25263
- loginRefreshTimer = void 0;
25264
- if (!login || context.signal.aborted) return;
25265
- void context.runLatest(
25266
- () => client().refreshCodexAccounts?.() ?? client().listCodexAccounts(),
25267
- {
25268
- success(result) {
25269
- const signedIn = result.accounts.some(
25270
- (account) => account.accountId === login?.accountId && account.email
25271
- );
25272
- if (signedIn) {
25273
- login = null;
25274
- loginMessage = messages.accountLoginSucceeded;
25275
- }
25276
- setAccounts(result.accounts);
25277
- scheduleLoginRefresh();
25278
- },
25279
- failure() {
25280
- scheduleLoginRefresh();
25281
- }
25282
- }
25283
- );
25284
- }, 750);
25285
- };
25286
- const render = () => {
25287
- const restoreFocus = accountListFocusRestorer(list, search);
25288
- body.replaceChildren();
25289
- status.textContent = loginMessage ?? "";
25290
- connectedCount.textContent = String(accounts.filter((account) => account.email).length);
25291
- search.disabled = login !== null || loginStartingAccountId !== null;
25292
- for (const [display, button] of displayButtons) {
25293
- button.setAttribute("aria-pressed", String(display === usageDisplay));
25294
- }
25295
- refreshUsage.disabled = (!getClient()?.inspectCodexAccountUsage || !accounts.some((account) => account.email)) && !getClient()?.listHarnessAccounts || harnessAccounts?.refreshing === true || [...usageByAccountId.values()].some((usage) => usage.status === "loading") || accountBusy();
25296
- const query = search.value.trim().toLocaleLowerCase();
25297
- harnessAccounts?.update(query, usageDisplay);
25298
- const visibleAccounts = accounts.filter(
25299
- (account) => `${account.email ?? ""} ${account.label}`.toLocaleLowerCase().includes(query)
25300
- );
25301
- if (visibleAccounts.length === 0) {
25302
- const emptyRow = document2.createElement("tr");
25303
- const emptyCell = document2.createElement("td");
25304
- emptyCell.colSpan = 4;
25305
- emptyCell.className = "settings-account-empty";
25306
- emptyCell.textContent = query ? messages.accountNoMatches : messages.accountEmpty;
25307
- emptyRow.append(emptyCell);
25308
- body.append(emptyRow);
25309
- }
25310
- add.disabled = accountBusy();
25311
- for (const account of visibleAccounts) {
25312
- body.append(
25313
- ...renderAccountRows(document2, account, messages, {
25314
- usage: usageByAccountId.get(account.accountId),
25315
- display: usageDisplay,
25316
- actionsDisabled: accountBusy(),
25317
- usingReset: usingResetAccountId === account.accountId,
25318
- resetDisabled: accountBusy(),
25319
- resetExpanded: expandedResetAccounts.has(account.accountId),
25320
- onActivate: () => mutate(() => client().activateCodexAccount({ accountId: account.accountId })),
25321
- onSignIn: () => startLogin(account.accountId),
25322
- onDelete: () => deleteAccount(account.accountId),
25323
- onRetry: () => {
25324
- usageByAccountId.delete(account.accountId);
25325
- loadUsage(accounts);
25326
- },
25327
- onResetExpanded: (open) => {
25328
- if (open) expandedResetAccounts.add(account.accountId);
25329
- else expandedResetAccounts.delete(account.accountId);
25330
- },
25331
- ...getClient()?.consumeCodexAccountResetCredit ? { onUseReset: () => useReset(account.accountId) } : {}
25332
- })
25333
- );
25334
- if (login?.accountId === account.accountId) {
25335
- const verification = document2.createElement("div");
25336
- verification.className = "settings-account-verification";
25337
- const prompt = document2.createElement("span");
25338
- prompt.textContent = messages.accountVerificationDescription;
25339
- const link = document2.createElement("a");
25340
- link.href = login.verificationUrl;
25341
- link.target = "_blank";
25342
- link.rel = "noopener noreferrer";
25343
- link.textContent = login.verificationUrl;
25344
- link.addEventListener("click", (event) => {
25345
- const bridge = document2.defaultView?.electronBridge;
25346
- if (typeof bridge?.sendMessageFromView !== "function") return;
25347
- event.preventDefault();
25348
- void Promise.resolve(
25349
- bridge.sendMessageFromView({
25350
- type: "open-in-browser",
25351
- url: login?.verificationUrl ?? link.href,
25352
- initiator: "open_in_browser_bridge",
25353
- openTarget: "external-browser",
25354
- source: "manual"
25355
- })
25356
- ).catch(() => void 0);
25357
- });
25358
- const code = document2.createElement("code");
25359
- code.textContent = login.userCode;
25360
- const copyCode = document2.createElement("button");
25361
- copyCode.type = "button";
25362
- copyCode.className = "settings-command-button settings-command-button--secondary";
25363
- copyCode.textContent = messages.accountCopyCode;
25364
- copyCode.addEventListener("click", () => {
25365
- void document2.defaultView?.navigator.clipboard?.writeText(login?.userCode ?? "").then(() => {
25366
- copyCode.textContent = messages.accountCopied;
25367
- });
25368
- });
25369
- const cancel = document2.createElement("button");
25370
- cancel.type = "button";
25371
- cancel.className = "settings-command-button settings-command-button--secondary";
25372
- cancel.textContent = messages.accountLoginCancel;
25373
- cancel.addEventListener(
25374
- "click",
25375
- () => cancelLogin(login?.accountId ?? "", login?.loginId ?? "")
25376
- );
25377
- verification.append(prompt, link, code, copyCode, cancel);
25378
- const verificationRow = document2.createElement("tr");
25379
- const verificationCell = document2.createElement("td");
25380
- verificationCell.colSpan = 4;
25381
- verificationCell.append(verification);
25382
- verificationRow.append(verificationCell);
25383
- body.append(verificationRow);
25384
- }
25474
+ function createAccessibleText(document2, message) {
25475
+ const text = document2.createElement("span");
25476
+ text.className = "settings-visually-hidden";
25477
+ text.textContent = message;
25478
+ return text;
25479
+ }
25480
+ function createSessionImportSettingsPage(messages, getClient, openImportedThread) {
25481
+ return Object.freeze({
25482
+ id: "session-import",
25483
+ label: messages.pageLabels["session-import"],
25484
+ icon: "session-import",
25485
+ mount(context) {
25486
+ const document2 = context.content.ownerDocument;
25487
+ const header = document2.createElement("div");
25488
+ header.className = "settings-session-import-header";
25489
+ const heading = document2.createElement("h2");
25490
+ heading.className = "settings-section-label";
25491
+ heading.textContent = messages.pageLabels["session-import"];
25492
+ const refresh = document2.createElement("button");
25493
+ refresh.type = "button";
25494
+ refresh.className = "settings-command-button settings-command-button--secondary";
25495
+ refresh.dataset.sessionImportAction = "refresh";
25496
+ const setRefreshLabel = (loading) => {
25497
+ refresh.replaceChildren(
25498
+ createRendererSettingsIcon("refresh", 15),
25499
+ loading ? messages.sessionImportRefreshing : messages.sessionImportRefresh
25500
+ );
25501
+ };
25502
+ setRefreshLabel(false);
25503
+ header.append(heading, refresh);
25504
+ const harness = document2.createElement("div");
25505
+ harness.className = "settings-session-import-harness";
25506
+ const harnessLabel = document2.createElement("span");
25507
+ harnessLabel.textContent = messages.sessionImportHarness;
25508
+ const harnessOptions = document2.createElement("div");
25509
+ harnessOptions.className = "settings-session-import-harness__options";
25510
+ harnessOptions.dataset.sessionImportHarness = "selector";
25511
+ harnessOptions.setAttribute("role", "group");
25512
+ harnessOptions.setAttribute("aria-label", messages.sessionImportHarness);
25513
+ let selectedHarness = null;
25514
+ let sources = [];
25515
+ const sourceButtons = [];
25516
+ const renderHarnessOptions = () => {
25517
+ harnessOptions.replaceChildren();
25518
+ sourceButtons.length = 0;
25519
+ for (const source of sources) {
25520
+ const option = document2.createElement("button");
25521
+ option.type = "button";
25522
+ option.className = "settings-session-import-harness__option";
25523
+ option.dataset.sessionImportHarnessOption = source.harnessId;
25524
+ option.textContent = source.name;
25525
+ option.setAttribute("aria-pressed", String(source.harnessId === selectedHarness));
25526
+ option.addEventListener("click", () => {
25527
+ if (option.disabled || importingId !== null || source.harnessId === selectedHarness)
25528
+ return;
25529
+ selectedHarness = source.harnessId;
25530
+ listControls.reset();
25531
+ renderHarnessOptions();
25532
+ load();
25533
+ });
25534
+ sourceButtons.push(option);
25535
+ harnessOptions.append(option);
25385
25536
  }
25386
- restoreFocus();
25387
25537
  };
25388
- const client = () => {
25389
- const value = getClient();
25390
- if (!value) throw new Error(messages.runtimeCapabilityNotInstalled);
25391
- return value;
25538
+ harness.append(harnessLabel, harnessOptions);
25539
+ const description = document2.createElement("p");
25540
+ description.className = "settings-page-description";
25541
+ description.textContent = messages.sessionImportDescription;
25542
+ const availabilityNote = document2.createElement("p");
25543
+ availabilityNote.className = "settings-page-description settings-session-import-availability-note";
25544
+ availabilityNote.textContent = messages.sessionImportAvailabilityNote;
25545
+ const content = document2.createElement("section");
25546
+ content.className = "settings-session-import-content";
25547
+ const listControls = createSessionImportListControls(document2, messages, () => load());
25548
+ context.content.append(
25549
+ header,
25550
+ harness,
25551
+ description,
25552
+ availabilityNote,
25553
+ listControls.searchForm,
25554
+ content,
25555
+ listControls.pagination
25556
+ );
25557
+ let candidates = [];
25558
+ let importingId = null;
25559
+ let actions = [];
25560
+ const updateImportActions = () => {
25561
+ listControls.setBusy(importingId !== null, importingId !== null);
25562
+ for (const button of sourceButtons) button.disabled = importingId !== null;
25563
+ for (const { button, candidate } of actions) {
25564
+ const importing = importingId === candidate.nativeSessionId;
25565
+ button.disabled = candidate.running === true;
25566
+ button.setAttribute(
25567
+ "aria-disabled",
25568
+ candidate.running || importingId !== null ? "true" : "false"
25569
+ );
25570
+ button.setAttribute("aria-busy", importing ? "true" : "false");
25571
+ button.replaceChildren(
25572
+ createRendererSettingsIcon("download", 15),
25573
+ importing ? messages.sessionImportImporting : messages.sessionImportAction
25574
+ );
25575
+ }
25392
25576
  };
25393
- const loadUsage = (nextAccounts) => {
25394
- const inspect = getClient()?.inspectCodexAccountUsage;
25395
- const signedIn = nextAccounts.filter((account) => account.email);
25396
- const keep = new Set(signedIn.map((account) => account.accountId));
25397
- for (const accountId of [...usageByAccountId.keys()]) {
25398
- if (!keep.has(accountId)) usageByAccountId.delete(accountId);
25577
+ const renderUnavailable = (focus = false) => {
25578
+ listControls.setTotal(0);
25579
+ candidates = [];
25580
+ actions = [];
25581
+ const status = createStatus(document2, messages.sessionImportUnavailable);
25582
+ content.replaceChildren(status);
25583
+ if (focus) {
25584
+ status.tabIndex = -1;
25585
+ status.focus();
25399
25586
  }
25400
- const pending = signedIn.filter((account) => !usageByAccountId.has(account.accountId));
25401
- if (!inspect || pending.length === 0) {
25402
- render();
25587
+ };
25588
+ const renderFailure = (error51, operation = "list") => {
25589
+ listControls.setTotal(0);
25590
+ if (error51 instanceof RendererSessionImportUnavailableError) {
25591
+ renderUnavailable(operation === "import");
25403
25592
  return;
25404
25593
  }
25405
- const requests = pending.map((account) => {
25406
- const loading = { status: "loading" };
25407
- usageByAccountId.set(account.accountId, loading);
25408
- return { account, loading };
25409
- });
25410
- render();
25411
- void Promise.all(
25412
- requests.map(async ({ account, loading }) => {
25413
- try {
25414
- const result = await inspect({ accountId: account.accountId });
25415
- if (context.signal.aborted || usageByAccountId.get(account.accountId) !== loading)
25416
- return;
25417
- usageByAccountId.set(
25418
- account.accountId,
25419
- result.accountCredits ? { status: "ready", credits: result.accountCredits } : { status: "empty" }
25420
- );
25421
- } catch {
25422
- if (context.signal.aborted || usageByAccountId.get(account.accountId) !== loading)
25423
- return;
25424
- usageByAccountId.set(account.accountId, { status: "error" });
25425
- }
25426
- render();
25427
- })
25594
+ actions = [];
25595
+ const status = createStatus(
25596
+ document2,
25597
+ operation === "import" ? messages.sessionImportFailed : messages.sessionImportLoadFailed,
25598
+ true
25428
25599
  );
25429
- };
25430
- const setAccounts = (nextAccounts) => {
25431
- accounts = nextAccounts;
25432
- for (const accountId of expandedResetAccounts) {
25433
- if (!accounts.some((account) => account.accountId === accountId))
25434
- expandedResetAccounts.delete(accountId);
25600
+ content.replaceChildren(status);
25601
+ if (operation === "import") {
25602
+ status.tabIndex = -1;
25603
+ status.focus();
25435
25604
  }
25436
- loadUsage(nextAccounts);
25437
- };
25438
- const refreshInBackground = () => {
25439
- if (!client().refreshCodexAccounts) return;
25440
- void context.runLatest(
25441
- () => client().refreshCodexAccounts?.() ?? client().listCodexAccounts(),
25442
- {
25443
- success(result) {
25444
- setAccounts(result.accounts);
25445
- },
25446
- failure() {
25447
- }
25448
- }
25449
- );
25450
- };
25451
- const load = () => {
25452
- void context.runLatest(() => client().listCodexAccounts(), {
25453
- success(result) {
25454
- loginMessage = null;
25455
- setAccounts(result.accounts);
25456
- refreshInBackground();
25457
- },
25458
- failure(error51) {
25459
- loginMessage = errorMessage(error51, messages.accountLoadFailed);
25460
- render();
25461
- }
25462
- });
25463
- };
25464
- const mutate = (operation) => {
25465
- if (accountBusy()) return;
25466
- accountActivating = true;
25467
- render();
25468
- void context.runLatest(() => operation(), {
25469
- success(result) {
25470
- accountActivating = false;
25471
- loginMessage = null;
25472
- setAccounts(
25473
- accounts.map((account) => ({
25474
- ...account.accountId === result.account.accountId ? result.account : account,
25475
- active: account.accountId === result.account.accountId
25476
- }))
25477
- );
25478
- },
25479
- failure(error51) {
25480
- accountActivating = false;
25481
- loginMessage = errorMessage(error51, messages.accountLoadFailed);
25482
- render();
25483
- }
25484
- });
25485
- };
25486
- const startLogin = (accountId) => {
25487
- if (accountBusy()) return;
25488
- loginStartingAccountId = accountId;
25489
- loginMessage = messages.accountSigningIn;
25490
- render();
25491
- void context.runLatest(() => client().startCodexAccountLogin({ accountId }), {
25492
- success(result) {
25493
- loginStartingAccountId = null;
25494
- login = result;
25495
- loginMessage = null;
25496
- render();
25497
- scheduleLoginRefresh();
25498
- },
25499
- failure(error51) {
25500
- loginStartingAccountId = null;
25501
- loginMessage = errorMessage(error51, messages.accountLoginFailed);
25502
- render();
25503
- }
25504
- });
25505
25605
  };
25506
- const createAndLogin = () => {
25507
- if (accountBusy()) return;
25508
- accountCreating = true;
25509
- loginMessage = messages.accountSigningIn;
25510
- render();
25511
- void context.runLatest(() => client().createCodexAccount({}), {
25512
- success(result) {
25513
- accountCreating = false;
25514
- loginMessage = null;
25515
- search.value = "";
25516
- setAccounts([
25517
- ...accounts.filter(({ accountId }) => accountId !== result.account.accountId),
25518
- result.account
25519
- ]);
25520
- startLogin(result.account.accountId);
25521
- },
25522
- failure(error51) {
25523
- accountCreating = false;
25524
- loginMessage = errorMessage(error51, messages.accountCreateFailed);
25525
- render();
25606
+ const renderOpenRecovery = (candidate, threadId) => {
25607
+ actions = [];
25608
+ refresh.disabled = false;
25609
+ const recovery = document2.createElement("section");
25610
+ recovery.className = "settings-session-import-recovery";
25611
+ recovery.setAttribute("role", "region");
25612
+ recovery.setAttribute("aria-label", messages.sessionImportImported);
25613
+ recovery.tabIndex = -1;
25614
+ const recoveryCopy = document2.createElement("div");
25615
+ recoveryCopy.className = "settings-session-import-recovery__copy";
25616
+ const title = document2.createElement("strong");
25617
+ title.textContent = messages.sessionImportImported;
25618
+ const explanation = document2.createElement("p");
25619
+ explanation.textContent = messages.sessionImportOpenFailed;
25620
+ recoveryCopy.append(title, explanation);
25621
+ const path = document2.createElement("div");
25622
+ path.className = "settings-session-import-recovery__path";
25623
+ const cwd = document2.createElement("code");
25624
+ cwd.textContent = candidate.cwd;
25625
+ cwd.title = candidate.cwd;
25626
+ const copyPath = document2.createElement("button");
25627
+ copyPath.type = "button";
25628
+ copyPath.className = "settings-command-button settings-command-button--secondary";
25629
+ copyPath.dataset.sessionImportAction = "copy-project-path";
25630
+ const setCopyLabel = (label) => {
25631
+ copyPath.replaceChildren(createRendererSettingsIcon("copy", 15), label);
25632
+ };
25633
+ const showCopyFeedback = (label) => {
25634
+ setCopyLabel(label);
25635
+ document2.defaultView?.setTimeout(
25636
+ () => setCopyLabel(messages.sessionImportCopyProjectPath),
25637
+ 2e3
25638
+ );
25639
+ };
25640
+ setCopyLabel(messages.sessionImportCopyProjectPath);
25641
+ copyPath.addEventListener("click", () => {
25642
+ const clipboard = document2.defaultView?.navigator.clipboard;
25643
+ if (!clipboard) {
25644
+ showCopyFeedback(messages.sessionImportPathCopyFailed);
25645
+ return;
25526
25646
  }
25647
+ void clipboard.writeText(candidate.cwd).then(
25648
+ () => showCopyFeedback(messages.sessionImportPathCopied),
25649
+ () => showCopyFeedback(messages.sessionImportPathCopyFailed)
25650
+ );
25527
25651
  });
25528
- };
25529
- const resetOutcomeMessage = (outcome) => {
25530
- if (outcome === "reset") return messages.accountResetCreditsSucceeded;
25531
- if (outcome === "nothingToReset") return messages.accountResetCreditsNothingToReset;
25532
- if (outcome === "noCredit") return messages.accountResetCreditsNoCredit;
25533
- return messages.accountResetCreditsAlreadyRedeemed;
25534
- };
25535
- const useReset = (accountId) => {
25536
- const consume = getClient()?.consumeCodexAccountResetCredit;
25537
- if (!consume || accountBusy()) return;
25538
- if (document2.defaultView?.confirm?.(messages.accountResetCreditsConfirm) === false) return;
25539
- usingResetAccountId = accountId;
25540
- loginMessage = messages.accountResetCreditsUsing;
25541
- render();
25542
- void context.runLatest(() => consume({ accountId, idempotencyKey: crypto.randomUUID() }), {
25543
- success(result) {
25544
- usingResetAccountId = null;
25545
- loginMessage = resetOutcomeMessage(result.outcome);
25546
- if (result.accountCredits) {
25547
- usageByAccountId.set(accountId, {
25548
- status: "ready",
25549
- credits: result.accountCredits
25550
- });
25551
- } else if (result.outcome === "reset") {
25552
- usageByAccountId.delete(accountId);
25553
- loadUsage(accounts);
25652
+ path.append(cwd, copyPath);
25653
+ const retry = document2.createElement("button");
25654
+ retry.type = "button";
25655
+ retry.className = "settings-command-button";
25656
+ retry.dataset.sessionImportAction = "retry-open";
25657
+ const setRetrying = (pending) => {
25658
+ listControls.setBusy(pending, pending);
25659
+ for (const button of sourceButtons) button.disabled = pending;
25660
+ retry.disabled = pending;
25661
+ refresh.disabled = pending;
25662
+ retry.setAttribute("aria-busy", pending ? "true" : "false");
25663
+ retry.replaceChildren(
25664
+ createRendererSettingsIcon("refresh", 15),
25665
+ pending ? messages.sessionImportRetrying : messages.sessionImportRetryOpen
25666
+ );
25667
+ };
25668
+ setRetrying(false);
25669
+ retry.addEventListener("click", () => {
25670
+ if (retry.disabled) return;
25671
+ setRetrying(true);
25672
+ void context.runLatest((signal) => openImportedThread(threadId, signal), {
25673
+ success() {
25674
+ setRetrying(false);
25675
+ },
25676
+ failure() {
25677
+ renderOpenRecovery(candidate, threadId);
25554
25678
  }
25555
- render();
25556
- },
25557
- failure(error51) {
25558
- usingResetAccountId = null;
25559
- loginMessage = errorMessage(error51, messages.accountResetCreditsFailed);
25560
- render();
25561
- }
25679
+ });
25562
25680
  });
25681
+ recovery.append(recoveryCopy, path, retry);
25682
+ content.replaceChildren(recovery);
25683
+ recovery.focus();
25563
25684
  };
25564
- const deleteAccount = (accountId) => {
25565
- const account = accounts.find((candidate) => candidate.accountId === accountId);
25566
- if (!account || account.isDefault || accountBusy()) return;
25567
- if (document2.defaultView?.confirm?.(messages.accountDeleteConfirm) === false) return;
25568
- deletingAccountId = accountId;
25569
- loginMessage = messages.accountDeleting;
25570
- render();
25571
- void context.runLatest(() => client().deleteCodexAccount({ accountId }), {
25572
- success() {
25573
- deletingAccountId = null;
25574
- loginMessage = null;
25575
- setAccounts(
25576
- accounts.filter((candidate) => candidate.accountId !== accountId).map((candidate) => ({
25577
- ...candidate,
25578
- active: account.active ? candidate.isDefault : candidate.active
25579
- }))
25685
+ const renderCandidates = () => {
25686
+ actions = [];
25687
+ content.replaceChildren();
25688
+ if (candidates.length === 0) {
25689
+ content.append(
25690
+ createStatus(
25691
+ document2,
25692
+ listControls.params().query ? messages.sessionImportNoMatches : messages.sessionImportEmpty
25693
+ )
25694
+ );
25695
+ return;
25696
+ }
25697
+ const list = document2.createElement("div");
25698
+ list.className = "settings-session-import-list";
25699
+ for (const candidate of candidates) {
25700
+ const row = document2.createElement("article");
25701
+ row.className = "settings-session-import-row";
25702
+ row.dataset.sessionImportId = candidate.nativeSessionId;
25703
+ const copy = document2.createElement("div");
25704
+ copy.className = "settings-session-import-row__copy";
25705
+ const title = document2.createElement("strong");
25706
+ title.textContent = candidate.title ?? messages.sessionImportUntitled;
25707
+ const metadata = document2.createElement("span");
25708
+ metadata.textContent = `${messages.sessionImportUpdatedAt}: ${new Intl.DateTimeFormat(
25709
+ messages.locale === "zh-CN" ? "zh-CN" : "en",
25710
+ { dateStyle: "medium", timeStyle: "short" }
25711
+ ).format(new Date(candidate.updatedAt))}`;
25712
+ const cwd = document2.createElement("code");
25713
+ cwd.className = "settings-session-import-row__cwd";
25714
+ cwd.textContent = candidate.cwd;
25715
+ cwd.title = candidate.cwd;
25716
+ const identity = document2.createElement("span");
25717
+ identity.textContent = `${messages.sessionImportSessionId}: ${shortSessionId(candidate.nativeSessionId)}`;
25718
+ identity.title = candidate.nativeSessionId;
25719
+ identity.setAttribute("aria-hidden", "true");
25720
+ copy.append(
25721
+ title,
25722
+ metadata,
25723
+ cwd,
25724
+ identity,
25725
+ createAccessibleText(
25726
+ document2,
25727
+ `${messages.sessionImportSessionId}: ${candidate.nativeSessionId}`
25728
+ )
25729
+ );
25730
+ const actionArea = document2.createElement("div");
25731
+ actionArea.className = "settings-session-import-row__action";
25732
+ if (candidate.running !== false) {
25733
+ const running = document2.createElement("span");
25734
+ running.className = "settings-session-import-running";
25735
+ running.textContent = candidate.running === null ? messages.sessionImportRunningUnknown : messages.sessionImportRunning;
25736
+ running.title = messages.sessionImportRunningHint;
25737
+ running.setAttribute("aria-hidden", "true");
25738
+ actionArea.append(
25739
+ running,
25740
+ createAccessibleText(
25741
+ document2,
25742
+ `${running.textContent}: ${messages.sessionImportRunningHint}`
25743
+ )
25580
25744
  );
25581
- },
25582
- failure(error51) {
25583
- deletingAccountId = null;
25584
- loginMessage = errorMessage(error51, messages.accountDeleteFailed);
25585
- render();
25586
25745
  }
25587
- });
25746
+ const action = document2.createElement("button");
25747
+ action.type = "button";
25748
+ action.className = "settings-command-button";
25749
+ action.dataset.sessionImportAction = "import";
25750
+ action.addEventListener("click", () => {
25751
+ if (candidate.running === true || importingId !== null || selectedHarness === null)
25752
+ return;
25753
+ const harnessId = selectedHarness;
25754
+ const client = getClient();
25755
+ if (!client) {
25756
+ renderUnavailable(true);
25757
+ return;
25758
+ }
25759
+ importingId = candidate.nativeSessionId;
25760
+ refresh.disabled = true;
25761
+ updateImportActions();
25762
+ let committedThreadId = null;
25763
+ void context.runLatest(
25764
+ async (signal) => {
25765
+ const result = await client.importHarnessSession({
25766
+ harnessId,
25767
+ nativeSessionId: candidate.nativeSessionId
25768
+ });
25769
+ committedThreadId = result.threadId;
25770
+ if (!signal.aborted) await openImportedThread(result.threadId, signal);
25771
+ },
25772
+ {
25773
+ success() {
25774
+ importingId = null;
25775
+ refresh.disabled = false;
25776
+ updateImportActions();
25777
+ },
25778
+ failure(error51) {
25779
+ importingId = null;
25780
+ updateImportActions();
25781
+ refresh.disabled = false;
25782
+ if (committedThreadId) {
25783
+ renderOpenRecovery(candidate, committedThreadId);
25784
+ } else {
25785
+ renderFailure(error51, "import");
25786
+ }
25787
+ }
25788
+ }
25789
+ );
25790
+ });
25791
+ actions.push({ button: action, candidate });
25792
+ actionArea.append(action);
25793
+ row.append(copy, actionArea);
25794
+ list.append(row);
25795
+ }
25796
+ content.append(list);
25797
+ updateImportActions();
25588
25798
  };
25589
- const cancelLogin = (accountId, loginId) => {
25590
- void context.runLatest(() => client().cancelCodexAccountLogin({ accountId, loginId }), {
25591
- success() {
25592
- clearLoginRefresh();
25593
- login = null;
25594
- loginMessage = null;
25595
- render();
25799
+ const load = () => {
25800
+ if (importingId !== null || context.signal.aborted) return;
25801
+ const client = getClient();
25802
+ if (!client) {
25803
+ refresh.disabled = false;
25804
+ setRefreshLabel(false);
25805
+ renderUnavailable();
25806
+ return;
25807
+ }
25808
+ listControls.setBusy(true);
25809
+ refresh.disabled = true;
25810
+ setRefreshLabel(true);
25811
+ content.replaceChildren(createStatus(document2, messages.sessionImportRefreshing));
25812
+ const requestedHarness = selectedHarness;
25813
+ const pageParams = listControls.params();
25814
+ void context.runLatest(
25815
+ async (signal) => {
25816
+ const result = await client.listSessionImportSources();
25817
+ const selected = result.harnesses.find(({ harnessId }) => harnessId === requestedHarness)?.harnessId ?? result.harnesses[0]?.harnessId ?? null;
25818
+ if (signal.aborted) throw new Error("Session import selection changed");
25819
+ sources = result.harnesses;
25820
+ selectedHarness = selected;
25821
+ if (selected !== requestedHarness) {
25822
+ listControls.reset();
25823
+ pageParams.offset = 0;
25824
+ }
25825
+ renderHarnessOptions();
25826
+ return selected ? client.listHarnessSessions({ harnessId: selected, ...pageParams }) : { candidates: [], total: 0 };
25596
25827
  },
25597
- failure(error51) {
25598
- loginMessage = errorMessage(error51, messages.accountLoginFailed);
25599
- render();
25828
+ {
25829
+ success(result) {
25830
+ listControls.setBusy(false);
25831
+ if (listControls.setTotal(result.total)) {
25832
+ load();
25833
+ return;
25834
+ }
25835
+ candidates = result.candidates;
25836
+ refresh.disabled = false;
25837
+ setRefreshLabel(false);
25838
+ if (selectedHarness === null) renderUnavailable();
25839
+ else renderCandidates();
25840
+ },
25841
+ failure(error51) {
25842
+ listControls.setBusy(false);
25843
+ candidates = [];
25844
+ refresh.disabled = false;
25845
+ setRefreshLabel(false);
25846
+ renderFailure(error51);
25847
+ }
25600
25848
  }
25601
- });
25849
+ );
25602
25850
  };
25603
- add.addEventListener("click", createAndLogin);
25604
- let unsubscribe;
25605
- try {
25606
- unsubscribe = getClient()?.subscribeCodexAccountLogin?.((result) => {
25607
- if (result.loginId !== login?.loginId) return;
25608
- clearLoginRefresh();
25609
- login = null;
25610
- loginMessage = result.success ? messages.accountLoginSucceeded : result.error ?? messages.accountLoginFailed;
25611
- render();
25612
- if (result.success) load();
25613
- });
25614
- } catch {
25615
- }
25616
- const harnessAccounts = mountHarnessAccounts(context, messages, getClient, render);
25617
- void harnessAccounts.refresh();
25851
+ refresh.addEventListener("click", load);
25618
25852
  load();
25619
- return () => {
25620
- clearLoginRefresh();
25621
- unsubscribe?.();
25622
- };
25853
+ return void 0;
25854
+ }
25855
+ });
25856
+ }
25857
+
25858
+ // src/native-ui/renderer-extension/src/settings/release-notes.ts
25859
+ var HEADING_PATTERN = /^(#{1,6})[ \t]+(.+?)\s*$/u;
25860
+ var BLOCKQUOTE_PATTERN = /^>[ \t]?(.*?)\s*$/u;
25861
+ var UNORDERED_ITEM_PATTERN = /^[-*][ \t]+(.+?)\s*$/u;
25862
+ var CONTINUATION_PATTERN = /^[ \t]+(.+?)\s*$/u;
25863
+ var ORDERED_ITEM_PATTERN = /^\d+[.)][ \t]+(.+?)\s*$/u;
25864
+ var FENCE_PATTERN = /^```([\w+-]*)\s*$/u;
25865
+ var THEMATIC_BREAK_PATTERN = /^(?:---|___|\*\*\*)[ \t]*$/u;
25866
+ var INLINE_PATTERN = /(`+)((?:(?!\1).)+)\1|\*\*(.+?)\*\*|\[([^\]]+)\]\(([^)\s]+)\)/gu;
25867
+ function createReleaseNotesElement(document2, markdown) {
25868
+ const root = document2.createElement("div");
25869
+ root.className = "settings-update-notes";
25870
+ appendReleaseNotesBlocks(document2, root, markdown);
25871
+ return root;
25872
+ }
25873
+ function appendReleaseNotesBlocks(document2, root, markdown) {
25874
+ const lines = markdown.replaceAll("\r\n", "\n").split("\n");
25875
+ let index = 0;
25876
+ while (index < lines.length) {
25877
+ const line = lines[index] ?? "";
25878
+ if (line.trim().length === 0) {
25879
+ index += 1;
25880
+ continue;
25881
+ }
25882
+ const fence = FENCE_PATTERN.exec(line);
25883
+ if (fence) {
25884
+ index = appendFencedCode(document2, root, lines, index, fence[1] ?? "");
25885
+ continue;
25886
+ }
25887
+ const heading = HEADING_PATTERN.exec(line);
25888
+ if (heading?.[1] && heading[2]) {
25889
+ const tag = `h${heading[1].length}`;
25890
+ const element = document2.createElement(tag);
25891
+ appendInline(document2, element, heading[2]);
25892
+ root.append(element);
25893
+ index += 1;
25894
+ continue;
25895
+ }
25896
+ if (BLOCKQUOTE_PATTERN.test(line)) {
25897
+ index = appendBlockquote(document2, root, lines, index);
25898
+ continue;
25899
+ }
25900
+ if (THEMATIC_BREAK_PATTERN.test(line)) {
25901
+ root.append(document2.createElement("hr"));
25902
+ index += 1;
25903
+ continue;
25904
+ }
25905
+ if (UNORDERED_ITEM_PATTERN.test(line)) {
25906
+ index = appendList(document2, root, lines, index, "ul", UNORDERED_ITEM_PATTERN);
25907
+ continue;
25908
+ }
25909
+ if (ORDERED_ITEM_PATTERN.test(line)) {
25910
+ index = appendList(document2, root, lines, index, "ol", ORDERED_ITEM_PATTERN);
25911
+ continue;
25912
+ }
25913
+ index = appendParagraph(document2, root, lines, index);
25914
+ }
25915
+ }
25916
+ function appendFencedCode(document2, root, lines, start, language) {
25917
+ const body = [];
25918
+ let index = start + 1;
25919
+ while (index < lines.length && !FENCE_PATTERN.test(lines[index] ?? "")) {
25920
+ body.push(lines[index] ?? "");
25921
+ index += 1;
25922
+ }
25923
+ if (index < lines.length) index += 1;
25924
+ const pre = document2.createElement("pre");
25925
+ const code = document2.createElement("code");
25926
+ if (language.length > 0) code.className = `language-${language}`;
25927
+ code.textContent = body.join("\n");
25928
+ pre.append(code);
25929
+ root.append(pre);
25930
+ return index;
25931
+ }
25932
+ function appendBlockquote(document2, root, lines, start) {
25933
+ const blockquote = document2.createElement("blockquote");
25934
+ const content = [];
25935
+ let index = start;
25936
+ while (index < lines.length) {
25937
+ const match = BLOCKQUOTE_PATTERN.exec(lines[index] ?? "");
25938
+ if (!match) break;
25939
+ content.push(match[1] ?? "");
25940
+ index += 1;
25941
+ }
25942
+ const paragraph = document2.createElement("p");
25943
+ appendInline(document2, paragraph, content.join(" ").trim());
25944
+ blockquote.append(paragraph);
25945
+ root.append(blockquote);
25946
+ return index;
25947
+ }
25948
+ function appendList(document2, root, lines, start, tag, pattern) {
25949
+ const list = document2.createElement(tag);
25950
+ let index = start;
25951
+ while (index < lines.length) {
25952
+ const item = pattern.exec(lines[index] ?? "");
25953
+ if (!item?.[1]) break;
25954
+ const entry = document2.createElement("li");
25955
+ appendInline(document2, entry, item[1]);
25956
+ index += 1;
25957
+ const continuationLines = [];
25958
+ while (index < lines.length) {
25959
+ const continuation = CONTINUATION_PATTERN.exec(lines[index] ?? "");
25960
+ if (!continuation?.[1]) break;
25961
+ continuationLines.push(continuation[1]);
25962
+ index += 1;
25963
+ }
25964
+ if (continuationLines.length > 0) {
25965
+ const continuation = document2.createElement("span");
25966
+ continuation.className = "release-note-translation";
25967
+ appendInline(document2, continuation, continuationLines.join(" "));
25968
+ entry.append(continuation);
25969
+ }
25970
+ list.append(entry);
25971
+ }
25972
+ root.append(list);
25973
+ return index;
25974
+ }
25975
+ function appendParagraph(document2, root, lines, start) {
25976
+ const paragraphLines = [];
25977
+ let index = start;
25978
+ while (index < lines.length) {
25979
+ const current = lines[index] ?? "";
25980
+ if (current.trim().length === 0 || FENCE_PATTERN.test(current) || HEADING_PATTERN.test(current) || BLOCKQUOTE_PATTERN.test(current) || THEMATIC_BREAK_PATTERN.test(current) || UNORDERED_ITEM_PATTERN.test(current) || ORDERED_ITEM_PATTERN.test(current)) {
25981
+ break;
25623
25982
  }
25983
+ paragraphLines.push(current.trim());
25984
+ index += 1;
25985
+ }
25986
+ const paragraph = document2.createElement("p");
25987
+ paragraphLines.forEach((line, lineIndex) => {
25988
+ appendInline(document2, paragraph, line);
25989
+ if (lineIndex < paragraphLines.length - 1) paragraph.append(document2.createElement("br"));
25624
25990
  });
25991
+ root.append(paragraph);
25992
+ return index;
25993
+ }
25994
+ function appendInline(document2, parent, text) {
25995
+ let lastIndex = 0;
25996
+ for (const match of text.matchAll(INLINE_PATTERN)) {
25997
+ const index = match.index ?? 0;
25998
+ if (index > lastIndex) parent.append(text.slice(lastIndex, index));
25999
+ if (match[2] !== void 0) {
26000
+ const code = document2.createElement("code");
26001
+ code.textContent = match[2];
26002
+ parent.append(code);
26003
+ } else if (match[3] !== void 0) {
26004
+ const strong = document2.createElement("strong");
26005
+ strong.textContent = match[3];
26006
+ parent.append(strong);
26007
+ } else {
26008
+ const href = match[5] ?? "";
26009
+ if (!isSafeLink(href)) {
26010
+ parent.append(match[4] ?? "");
26011
+ } else {
26012
+ const link = document2.createElement("a");
26013
+ link.textContent = match[4] ?? "";
26014
+ link.setAttribute("href", href);
26015
+ link.setAttribute("target", "_blank");
26016
+ link.setAttribute("rel", "noopener noreferrer");
26017
+ parent.append(link);
26018
+ }
26019
+ }
26020
+ lastIndex = index + match[0].length;
26021
+ }
26022
+ if (lastIndex < text.length) parent.append(text.slice(lastIndex));
26023
+ }
26024
+ function isSafeLink(href) {
26025
+ try {
26026
+ const url2 = new URL(href, "https://codexhost.invalid");
26027
+ return url2.protocol === "http:" || url2.protocol === "https:";
26028
+ } catch {
26029
+ return false;
26030
+ }
25625
26031
  }
25626
26032
 
25627
26033
  // src/native-ui/renderer-extension/src/settings/update-request.ts
@@ -25761,6 +26167,23 @@ ${error51.stderrTail}`] : []
25761
26167
  const tagline = document2.createElement("strong");
25762
26168
  tagline.className = "settings-about-tagline";
25763
26169
  tagline.textContent = messages.aboutTagline;
26170
+ const versionRow = document2.createElement("div");
26171
+ versionRow.className = "settings-about-version-row";
26172
+ const versionBadge = document2.createElement("span");
26173
+ versionBadge.className = "settings-about-version-badge";
26174
+ versionBadge.textContent = "v0.1.2";
26175
+ const checkUpdateBtn = document2.createElement("button");
26176
+ checkUpdateBtn.type = "button";
26177
+ checkUpdateBtn.className = "settings-command-button settings-command-button--secondary";
26178
+ checkUpdateBtn.append(createRendererSettingsIcon("updates", 14), messages.checkUpdateNow);
26179
+ checkUpdateBtn.addEventListener("click", () => {
26180
+ const shell = document2.querySelector("[data-codexhost-settings-shell]");
26181
+ const updatesNavBtn = (shell?.shadowRoot ?? document2).querySelector(
26182
+ 'button[data-page-id="updates"]'
26183
+ );
26184
+ updatesNavBtn?.click();
26185
+ });
26186
+ versionRow.append(versionBadge, checkUpdateBtn);
25764
26187
  const introduction = document2.createElement("div");
25765
26188
  introduction.className = "settings-about-copy";
25766
26189
  for (const paragraphText of messages.aboutParagraphs) {
@@ -25788,7 +26211,7 @@ ${error51.stderrTail}`] : []
25788
26211
  repositoryUrl
25789
26212
  );
25790
26213
  repositorySection.append(openSource, repository);
25791
- panel.append(product, tagline, introduction, starCallout, repositorySection);
26214
+ panel.append(product, tagline, versionRow, introduction, starCallout, repositorySection);
25792
26215
  context.content.append(heading, panel);
25793
26216
  return void 0;
25794
26217
  }
@@ -26126,10 +26549,10 @@ ${error51.stderrTail}`] : []
26126
26549
  }
26127
26550
 
26128
26551
  // src/native-ui/renderer-extension/src/settings/shell.css
26129
- var shell_default = ':host {\r\n --settings-bg: light-dark(#ffffff, #202020);\r\n --settings-sidebar: light-dark(#f7f7f8, #191919);\r\n --settings-panel: light-dark(#ffffff, #232323);\r\n --settings-surface: light-dark(#f6f6f6, #292929);\r\n --settings-surface-hover: light-dark(#eeeeee, #303030);\r\n --settings-inset: light-dark(#f3f3f3, #161616);\r\n --settings-text: light-dark(#0d0d0d, #ececec);\r\n --settings-muted: light-dark(#676767, #a3a3a3);\r\n --settings-subtle: light-dark(#8a8a8a, #777777);\r\n --settings-border: light-dark(rgb(13 13 13 / 9%), rgb(255 255 255 / 9%));\r\n --settings-divider: light-dark(rgb(13 13 13 / 7%), rgb(255 255 255 / 7%));\r\n --settings-hover: light-dark(rgb(13 13 13 / 5%), rgb(255 255 255 / 7%));\r\n --settings-active: light-dark(rgb(13 13 13 / 7%), rgb(255 255 255 / 9%));\r\n --settings-focus: light-dark(#0b75d1, #66aaf9);\r\n --settings-primary: light-dark(#171717, #f4f4f4);\r\n --settings-primary-hover: light-dark(#2f2f2f, #ffffff);\r\n --settings-primary-text: light-dark(#ffffff, #171717);\r\n --settings-warning: light-dark(#8a5500, #f5c96a);\r\n --settings-warning-bg: light-dark(#fff8e6, rgb(245 201 106 / 8%));\r\n --settings-warning-border: light-dark(#ead8a8, rgb(245 201 106 / 24%));\r\n --settings-danger: light-dark(#b42318, #f87171);\r\n --settings-danger-bg: light-dark(#fff1f0, rgb(239 68 68 / 8%));\r\n --settings-danger-border: light-dark(#f3c7c3, rgb(239 68 68 / 22%));\r\n --settings-success: light-dark(#16784a, #4ade80);\r\n color: var(--settings-text);\r\n color-scheme: inherit;\r\n font:\r\n 13px/1.5 system-ui,\r\n -apple-system,\r\n BlinkMacSystemFont,\r\n "Segoe UI",\r\n sans-serif;\r\n letter-spacing: 0;\r\n}\r\n\r\n*,\r\n*::before,\r\n*::after {\r\n box-sizing: border-box;\r\n letter-spacing: 0;\r\n}\r\n\r\nbutton,\r\ninput,\r\nselect {\r\n font: inherit;\r\n}\r\n\r\nbutton {\r\n color: inherit;\r\n}\r\n\r\n[hidden] {\r\n display: none !important;\r\n}\r\n\r\n.settings-visually-hidden {\r\n position: absolute;\r\n width: 1px;\r\n height: 1px;\r\n padding: 0;\r\n margin: -1px;\r\n overflow: hidden;\r\n clip-path: inset(50%);\r\n white-space: nowrap;\r\n border: 0;\r\n}\r\n\r\n.codexhost-settings-dialog {\r\n width: min(1120px, calc(100vw - 32px));\r\n height: min(780px, calc(100vh - 32px));\r\n max-width: none;\r\n max-height: none;\r\n margin: auto;\r\n padding: 0;\r\n overflow: hidden;\r\n color: var(--settings-text);\r\n background: var(--settings-bg);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 14px;\r\n box-shadow: light-dark(0 16px 42px rgb(0 0 0 / 16%), 0 20px 54px rgb(0 0 0 / 42%));\r\n}\r\n\r\n.codexhost-settings-dialog::backdrop {\r\n background: light-dark(rgb(0 0 0 / 24%), rgb(0 0 0 / 56%));\r\n backdrop-filter: blur(1px);\r\n}\r\n\r\n.settings-frame,\r\n.settings-layout {\r\n width: 100%;\r\n height: 100%;\r\n min-width: 0;\r\n min-height: 0;\r\n}\r\n\r\n.settings-frame {\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.settings-layout {\r\n flex: 1;\r\n display: grid;\r\n grid-template-columns: 184px minmax(0, 1fr);\r\n background: var(--settings-bg);\r\n}\r\n\r\n.settings-sidebar {\r\n display: flex;\r\n min-width: 0;\r\n min-height: 0;\r\n flex-direction: column;\r\n overflow: hidden;\r\n background: var(--settings-sidebar);\r\n border-right: 1px solid var(--settings-border);\r\n padding-top: 14px;\r\n}\r\n\r\n.settings-header {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n height: 48px;\r\n flex: none;\r\n padding: 0 12px;\r\n border-bottom: 1px solid var(--settings-border);\r\n}\r\n\r\n.settings-header-actions {\r\n display: flex;\r\n align-items: center;\r\n flex: none;\r\n gap: 12px;\r\n margin-left: auto;\r\n}\r\n\r\n.settings-brand {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 7px;\r\n}\r\n\r\n.settings-brand__mark {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n flex: none;\r\n color: var(--settings-text);\r\n}\r\n\r\n.settings-brand__mark .codexhost-settings-icon {\r\n width: 24px;\r\n height: 24px;\r\n object-fit: contain;\r\n}\r\n\r\n.settings-brand__copy {\r\n display: flex;\r\n min-width: 0;\r\n align-items: baseline;\r\n gap: 0;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-brand__name {\r\n overflow: hidden;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n font-weight: 600;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-brand__title {\r\n margin-left: 8px;\r\n padding-left: 8px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n font-weight: 400;\r\n border-left: 1px solid var(--settings-border);\r\n}\r\n\r\n.settings-nav {\r\n display: flex;\r\n min-width: 0;\r\n min-height: 0;\r\n flex: 1;\r\n flex-direction: column;\r\n gap: 2px;\r\n padding: 0 7px 10px;\r\n overflow-y: auto;\r\n}\r\n\r\n.settings-nav-section-label {\r\n min-height: 24px;\r\n padding: 4px 9px 2px;\r\n color: var(--settings-subtle);\r\n font-size: 11px;\r\n font-weight: 600;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-nav-section-label:not(:first-child) {\r\n margin-top: 8px;\r\n}\r\n\r\n.settings-nav-button {\r\n display: grid;\r\n grid-template-columns: 16px minmax(0, 1fr);\r\n align-items: center;\r\n width: 100%;\r\n position: relative;\r\n min-height: 34px;\r\n flex: none;\r\n gap: 9px;\r\n padding: 6px 9px;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n line-height: 20px;\r\n text-align: left;\r\n background: transparent;\r\n border: 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-nav-button .codexhost-settings-icon {\r\n width: 16px;\r\n height: 16px;\r\n opacity: 0.9;\r\n}\r\n\r\n.settings-nav-button:hover {\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-nav-button[aria-current="page"] {\r\n background: var(--settings-active);\r\n color: var(--settings-text);\r\n font-weight: 500;\r\n}\r\n\r\n.settings-nav-button span {\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-nav-star-link {\r\n margin-top: 0;\r\n color: var(--settings-text);\r\n text-decoration: none;\r\n}\r\n\r\n.settings-nav-star-link .codexhost-settings-icon {\r\n color: var(--settings-warning);\r\n}\r\n\r\n.settings-nav-star-link:hover {\r\n color: var(--settings-warning);\r\n background: var(--settings-warning-bg);\r\n}\r\n\r\n.settings-icon-button {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n flex: none;\r\n padding: 0;\r\n color: var(--settings-muted);\r\n background: transparent;\r\n border: 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-icon-button:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-icon-button:focus-visible,\r\n.settings-nav-button:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 1px;\r\n}\r\n\r\n.settings-page {\r\n display: block;\r\n position: relative;\r\n min-width: 0;\r\n min-height: 0;\r\n overflow-y: auto;\r\n background: var(--settings-bg);\r\n scrollbar-gutter: stable;\r\n}\r\n\r\n.settings-page__content {\r\n width: min(930px, calc(100% - 80px));\r\n margin-inline: auto;\r\n}\r\n\r\n.settings-page__content {\r\n min-width: 0;\r\n padding: 28px 0 36px;\r\n}\r\n\r\n.settings-section-label {\r\n min-height: auto;\r\n margin: 0;\r\n padding: 0 0 18px;\r\n color: var(--settings-text);\r\n font-size: 18px;\r\n font-weight: 600;\r\n line-height: 26px;\r\n}\r\n\r\n.settings-status-list,\r\n.settings-empty {\r\n overflow: hidden;\r\n background: var(--settings-panel);\r\n}\r\n\r\n.settings-status-row {\r\n display: grid;\r\n grid-template-columns: minmax(170px, 1fr) auto minmax(280px, 1.45fr);\r\n position: relative;\r\n align-items: center;\r\n min-height: 72px;\r\n gap: 20px;\r\n padding: 12px 0;\r\n}\r\n\r\n.settings-status-row:not(:last-child)::after {\r\n content: "";\r\n position: absolute;\r\n right: 0;\r\n bottom: 0;\r\n left: 0;\r\n height: 1px;\r\n background: var(--settings-divider);\r\n}\r\n\r\n.settings-status-row__identity {\r\n display: inline-flex;\r\n align-items: center;\r\n min-width: 0;\r\n color: var(--settings-text);\r\n gap: 10px;\r\n font-size: 14px;\r\n font-weight: 500;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-status-row__icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 36px;\r\n height: 36px;\r\n flex: none;\r\n color: var(--settings-muted);\r\n background: var(--settings-surface);\r\n border-radius: 50%;\r\n}\r\n\r\n.settings-status-badge {\r\n flex: none;\r\n padding: 3px 8px;\r\n color: var(--settings-muted);\r\n font-size: 11px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-status-row__detail {\r\n min-width: 0;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-page-description {\r\n max-width: 760px;\r\n margin: -10px 0 20px;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-session-import-header {\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: space-between;\r\n gap: 24px;\r\n}\r\n\r\n.settings-session-import-header .settings-section-label {\r\n min-width: 0;\r\n}\r\n\r\n.settings-session-import-harness {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 12px;\r\n margin: -12px 0 16px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n}\r\n\r\n.settings-session-import-harness > span {\r\n flex: none;\r\n}\r\n\r\n.settings-session-import-harness__options {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n flex: 1;\r\n gap: 6px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n scrollbar-width: none;\r\n}\r\n\r\n.settings-session-import-harness__options::-webkit-scrollbar {\r\n display: none;\r\n}\r\n\r\n.settings-session-import-harness__option {\r\n min-height: 32px;\r\n flex: none;\r\n padding: 6px 10px;\r\n color: var(--settings-muted);\r\n font: inherit;\r\n font-size: 12px;\r\n white-space: nowrap;\r\n background: rgb(255 255 255 / 4%);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-session-import-harness__option[aria-pressed="true"] {\r\n color: var(--settings-text);\r\n background: var(--settings-active);\r\n border-color: rgb(51 156 255 / 50%);\r\n}\r\n\r\n.settings-session-import-harness__option:disabled {\r\n opacity: 0.38;\r\n cursor: not-allowed;\r\n}\r\n\r\n.settings-session-import-harness__option:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-session-import-harness + .settings-page-description {\r\n margin-top: 0;\r\n margin-bottom: 4px;\r\n}\r\n\r\n.settings-session-import-availability-note {\r\n margin-top: 0;\r\n}\r\n\r\n.settings-session-import-search,\r\n.settings-session-import-pagination {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: 10px;\r\n margin: 16px 0;\r\n}\r\n\r\n.settings-session-import-search input {\r\n flex: 1;\r\n min-width: 160px;\r\n}\r\n\r\n.settings-session-import-search input,\r\n.settings-session-import-pagination select {\r\n min-height: 36px;\r\n padding: 6px 10px;\r\n color: var(--settings-text);\r\n background: var(--settings-bg);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-session-import-search input:focus-visible,\r\n.settings-session-import-pagination select:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-session-import-pagination {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n}\r\n\r\n.settings-session-import-pagination label {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.settings-session-import-pagination > span {\r\n flex: 1;\r\n min-width: 130px;\r\n}\r\n\r\n.settings-session-import-pagination__navigation {\r\n display: flex;\r\n gap: 8px;\r\n margin-left: auto;\r\n}\r\n\r\n.settings-session-import-content,\r\n.settings-session-import-list {\r\n display: grid;\r\n gap: 10px;\r\n}\r\n\r\n.settings-session-import-status {\r\n display: flex;\r\n align-items: center;\r\n min-height: 64px;\r\n gap: 12px;\r\n padding: 16px;\r\n color: var(--settings-muted);\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-session-import-status.is-error {\r\n color: #ef4444;\r\n}\r\n\r\n.settings-session-import-recovery {\r\n display: grid;\r\n justify-items: start;\r\n gap: 14px;\r\n padding: 16px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-session-import-recovery:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-session-import-recovery__copy {\r\n display: grid;\r\n gap: 4px;\r\n}\r\n\r\n.settings-session-import-recovery__copy strong {\r\n color: var(--settings-text);\r\n font-size: 14px;\r\n}\r\n\r\n.settings-session-import-recovery__copy p {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-session-import-recovery__path {\r\n display: flex;\r\n align-items: stretch;\r\n width: 100%;\r\n min-width: 0;\r\n overflow: hidden;\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-session-import-recovery__path code {\r\n min-width: 0;\r\n flex: 1;\r\n padding: 8px 10px;\r\n overflow-x: auto;\r\n color: var(--settings-text);\r\n font-size: 12px;\r\n line-height: 20px;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-session-import-recovery__path .settings-command-button {\r\n min-height: 0;\r\n flex: none;\r\n border-width: 0 0 0 1px;\r\n border-radius: 0;\r\n}\r\n\r\n.settings-session-import-row {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1fr) auto;\r\n align-items: center;\r\n gap: 20px;\r\n min-width: 0;\r\n padding: 16px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-session-import-row__copy {\r\n display: grid;\r\n min-width: 0;\r\n gap: 4px;\r\n}\r\n\r\n.settings-session-import-row__copy strong {\r\n overflow: hidden;\r\n color: var(--settings-text);\r\n font-size: 14px;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-session-import-row__copy span,\r\n.settings-session-import-row__cwd {\r\n overflow: hidden;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-session-import-row__cwd {\r\n display: block;\r\n min-width: 0;\r\n background: transparent;\r\n}\r\n\r\n.settings-session-import-row__action {\r\n display: flex;\r\n align-items: flex-end;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.settings-session-import-running {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n}\r\n\r\n.settings-preference-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 32px;\r\n min-height: 88px;\r\n padding: 18px 0;\r\n border-top: 1px solid var(--settings-divider);\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-preference-row__copy {\r\n display: flex;\r\n flex: 1 1 auto;\r\n flex-direction: column;\r\n min-width: 0;\r\n gap: 5px;\r\n}\r\n\r\n.settings-preference-row__copy strong {\r\n color: var(--settings-text);\r\n font-size: 15px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-preference-row__copy span {\r\n max-width: 680px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-preference-switch {\r\n display: inline-flex;\r\n align-items: center;\r\n width: 42px;\r\n height: 24px;\r\n flex: none;\r\n padding: 2px;\r\n border: 0;\r\n border-radius: 999px;\r\n background: var(--settings-surface-hover);\r\n cursor: pointer;\r\n transition: background 120ms ease;\r\n}\r\n\r\n.settings-preference-switch[aria-checked="true"] {\r\n justify-content: flex-end;\r\n background: var(--settings-focus);\r\n}\r\n\r\n.settings-preference-switch:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-preference-switch__thumb {\r\n width: 20px;\r\n height: 20px;\r\n border-radius: 50%;\r\n background: var(--settings-primary-text);\r\n box-shadow: 0 1px 3px rgb(0 0 0 / 24%);\r\n}\r\n\r\n.settings-connection-page-header {\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: space-between;\r\n gap: 18px;\r\n margin-bottom: 18px;\r\n}\r\n\r\n.settings-connection-page-header .settings-section-label {\r\n padding-bottom: 0;\r\n}\r\n\r\n.settings-connection-page-header .settings-page-description {\r\n margin: 5px 0 0;\r\n}\r\n\r\n.settings-connections-content,\r\n.settings-connections-layout,\r\n.settings-connection-list,\r\n.settings-connection-rows {\r\n min-width: 0;\r\n}\r\n\r\n.settings-connections-layout {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.85fr);\r\n align-items: start;\r\n gap: 18px;\r\n}\r\n\r\n.settings-connection-list,\r\n.settings-connection-inspector {\r\n overflow: hidden;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-host-strip {\r\n display: grid;\r\n grid-template-columns: 30px minmax(0, 1fr) 30px;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 5px;\r\n padding: 9px 10px;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-host-scroll {\r\n display: none;\r\n align-items: center;\r\n justify-content: center;\r\n width: 30px;\r\n height: 34px;\r\n padding: 0;\r\n color: var(--settings-muted);\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-host-strip[data-connection-host-overflow="true"]\r\n .settings-connection-host-scroll {\r\n display: inline-flex;\r\n}\r\n\r\n.settings-connection-host-strip:not([data-connection-host-overflow="true"]) {\r\n grid-template-columns: minmax(0, 1fr);\r\n}\r\n\r\n.settings-connection-host-scroll:hover:not(:disabled) {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-host-scroll:disabled {\r\n cursor: default;\r\n opacity: 0.35;\r\n}\r\n\r\n.settings-connection-host-scroll:focus-visible,\r\n.settings-connection-host-tab:focus-visible,\r\n.settings-connection-row:focus-visible,\r\n.settings-connection-install-link:focus-visible,\r\n.settings-connection-view-error:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 1px;\r\n}\r\n\r\n.settings-connection-host-tabs {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 6px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n overscroll-behavior-x: contain;\r\n scrollbar-width: none;\r\n scroll-behavior: smooth;\r\n scroll-snap-type: x proximity;\r\n touch-action: pan-x;\r\n}\r\n\r\n.settings-connection-host-tabs::-webkit-scrollbar {\r\n display: none;\r\n}\r\n\r\n.settings-connection-host-tab {\r\n display: inline-flex;\r\n align-items: center;\r\n height: 30px;\r\n min-width: max-content;\r\n flex: none;\r\n padding: 0 9px;\r\n color: var(--settings-muted);\r\n font: inherit;\r\n font-size: 12px;\r\n line-height: 18px;\r\n white-space: nowrap;\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 7px;\r\n cursor: pointer;\r\n scroll-snap-align: start;\r\n}\r\n\r\n.settings-connection-host-tab:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-host-tab[aria-selected="true"] {\r\n color: var(--settings-text);\r\n font-weight: 600;\r\n background: var(--settings-active);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-connection-table-header,\r\n.settings-connection-row {\r\n display: grid;\r\n grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) 108px;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 10px;\r\n}\r\n\r\n.settings-connection-table-header {\r\n min-height: 30px;\r\n padding: 0 10px;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n font-weight: 600;\r\n line-height: 16px;\r\n text-transform: uppercase;\r\n letter-spacing: 0.06em;\r\n background: transparent;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-row {\r\n min-height: 52px;\r\n padding: 8px 10px;\r\n cursor: pointer;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-row:last-child {\r\n border-bottom: 0;\r\n}\r\n\r\n.settings-connection-row:hover {\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-row[data-connection-selected="true"] {\r\n background: var(--settings-surface);\r\n}\r\n\r\n.settings-connection-row__identity,\r\n.settings-connection-inspector__identity {\r\n display: inline-flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 8px;\r\n color: var(--settings-text);\r\n}\r\n\r\n.settings-connection-row__identity strong,\r\n.settings-connection-inspector__identity strong {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n font-size: 12px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-row__mark {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n flex: none;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n font-weight: 700;\r\n background: var(--settings-surface);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-connection-row__mark--logo {\r\n color: var(--settings-text);\r\n background: transparent;\r\n}\r\n\r\n.settings-connection-row__mark--logo > img,\r\n.settings-connection-row__mark--logo > svg {\r\n display: block;\r\n max-width: 18px;\r\n max-height: 18px;\r\n}\r\n\r\n.settings-connection-row__status {\r\n display: inline-flex;\r\n align-items: center;\r\n width: fit-content;\r\n gap: 5px;\r\n color: var(--settings-muted);\r\n font-size: 11px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-row__status::before {\r\n width: 6px;\r\n height: 6px;\r\n flex: none;\r\n content: "";\r\n background: currentColor;\r\n border-radius: 50%;\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="ready"] {\r\n color: var(--settings-success);\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="checking"] {\r\n color: var(--settings-warning);\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="setup"] {\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="setup"]::before {\r\n background: transparent;\r\n border: 1.5px solid currentColor;\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="failed"] {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-connection-row__action {\r\n display: flex;\r\n align-items: center;\r\n justify-content: flex-end;\r\n min-width: 0;\r\n gap: 4px;\r\n}\r\n\r\n.settings-connection-row__handle {\r\n display: inline-flex;\r\n flex: none;\r\n align-items: center;\r\n justify-content: center;\r\n width: 16px;\r\n color: var(--settings-muted);\r\n cursor: grab;\r\n opacity: 0.6;\r\n}\r\n\r\n.settings-connection-row__handle:hover {\r\n opacity: 1;\r\n}\r\n\r\n.settings-connection-row[draggable="true"] {\r\n cursor: grab;\r\n}\r\n\r\n.settings-connection-row[data-connection-dragging="true"] {\r\n opacity: 0.4;\r\n}\r\n\r\n.settings-connection-row[data-connection-drop-indicator="before"] {\r\n box-shadow: inset 0 2px 0 0 var(--settings-focus);\r\n}\r\n\r\n.settings-connection-row[data-connection-drop-indicator="after"] {\r\n box-shadow: inset 0 -2px 0 0 var(--settings-focus);\r\n}\r\n\r\n.settings-connection-row__group-toggle {\r\n display: inline-flex;\r\n flex: none;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n color: var(--settings-muted);\r\n background: transparent;\r\n border: 0;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-row__group-toggle:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-group-divider {\r\n padding: 10px 12px 6px;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n font-weight: 600;\r\n line-height: 16px;\r\n text-transform: uppercase;\r\n letter-spacing: 0.06em;\r\n /* No border-top here: the row immediately above already carries its own\r\n border-bottom (it is no longer :last-child once this divider follows\r\n it), so adding one here would double the separator line. */\r\n}\r\n\r\n.settings-connection-group-more[data-connection-drag-over="true"] {\r\n background: rgb(51 156 255 / 8%);\r\n}\r\n\r\n.settings-connection-group-hint {\r\n display: grid;\r\n gap: 3px;\r\n margin: 0 12px 12px;\r\n padding: 14px 16px;\r\n text-align: center;\r\n border: 1.5px dashed var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-group-more[data-connection-drag-over="true"] .settings-connection-group-hint {\r\n border-color: var(--settings-focus);\r\n}\r\n\r\n.settings-connection-group-hint strong {\r\n color: var(--settings-text);\r\n font-size: 12.5px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-group-hint span {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 17px;\r\n}\r\n\r\n.settings-connection-group-reset {\r\n display: flex;\r\n width: 100%;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 10px 12px;\r\n color: var(--settings-muted);\r\n font: inherit;\r\n font-size: 12px;\r\n text-align: left;\r\n background: transparent;\r\n border: 0;\r\n border-top: 1px solid var(--settings-divider);\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-group-reset:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-install-link {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n color: var(--settings-focus);\r\n text-decoration: none;\r\n background: transparent;\r\n border: 1px solid transparent;\r\n border-radius: 7px;\r\n opacity: 0;\r\n transition: opacity 120ms ease;\r\n}\r\n\r\n.settings-connection-row:hover .settings-connection-install-link,\r\n.settings-connection-install-link:focus-visible {\r\n opacity: 1;\r\n}\r\n\r\n.settings-connection-install-link:hover {\r\n color: var(--settings-focus);\r\n background: var(--settings-active);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-connection-view-error {\r\n padding: 4px 7px;\r\n color: var(--settings-danger);\r\n font: inherit;\r\n font-size: 11px;\r\n line-height: 18px;\r\n background: transparent;\r\n border: 0;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-view-error:hover {\r\n color: var(--settings-danger);\r\n background: var(--settings-danger-bg);\r\n}\r\n\r\n.settings-connection-inspector {\r\n position: sticky;\r\n top: 18px;\r\n}\r\n\r\n.settings-connection-inspector__header {\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: space-between;\r\n min-width: 0;\r\n gap: 10px;\r\n padding: 12px;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-inspector__body {\r\n display: grid;\r\n min-width: 0;\r\n gap: 12px;\r\n padding: 12px;\r\n}\r\n\r\n.settings-connection-install-callout {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 14px;\r\n padding: 14px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-install-head {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 12px;\r\n min-width: 0;\r\n}\r\n\r\n.settings-connection-install-head > div {\r\n min-width: 0;\r\n flex: 1;\r\n}\r\n\r\n.settings-connection-install-callout__icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 32px;\r\n height: 32px;\r\n flex: none;\r\n color: var(--settings-focus);\r\n background: var(--settings-active);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-connection-install-callout strong,\r\n.settings-connection-install-head strong,\r\n.settings-connection-error-summary strong,\r\n.settings-connection-state-summary strong {\r\n display: block;\r\n margin: 0 0 4px;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n font-weight: 600;\r\n line-height: 19px;\r\n}\r\n\r\n.settings-connection-install-callout p,\r\n.settings-connection-install-head p,\r\n.settings-connection-error-summary p,\r\n.settings-connection-state-summary p,\r\n.settings-connection-issue-note {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-install-button {\r\n width: 100%;\r\n}\r\n\r\n.settings-connection-error-summary {\r\n padding: 13px 14px;\r\n color: var(--settings-danger);\r\n background: var(--settings-danger-bg);\r\n border: 1px solid var(--settings-danger-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-error-metadata {\r\n display: grid;\r\n gap: 7px;\r\n padding: 12px;\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 9px;\r\n}\r\n\r\n.settings-connection-detail-line {\r\n display: grid;\r\n grid-template-columns: 92px minmax(0, 1fr);\r\n gap: 10px;\r\n min-width: 0;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n line-height: 16px;\r\n}\r\n\r\n.settings-connection-detail-line code {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n color: var(--settings-text);\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n white-space: pre-wrap;\r\n}\r\n\r\n.settings-connection-error-log-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 10px;\r\n}\r\n\r\n.settings-connection-error-log-header strong {\r\n color: var(--settings-text);\r\n font-size: 11px;\r\n font-weight: 600;\r\n}\r\n\r\n.settings-connection-error-log-header .settings-command-button {\r\n min-height: 30px;\r\n padding: 5px 9px;\r\n font-size: 11px;\r\n}\r\n\r\n.settings-connection-stderr {\r\n max-height: 220px;\r\n min-width: 0;\r\n margin: 0;\r\n padding: 11px;\r\n overflow: auto;\r\n color: var(--settings-text);\r\n font:\r\n 10px/16px ui-monospace,\r\n "SFMono-Regular",\r\n Consolas,\r\n "Liberation Mono",\r\n monospace;\r\n white-space: pre-wrap;\r\n overflow-wrap: anywhere;\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 9px;\r\n}\r\n\r\n.settings-connection-error-actions {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1fr);\r\n gap: 8px;\r\n}\r\n\r\n.settings-connection-error-actions .settings-command-button {\r\n width: 100%;\r\n}\r\n\r\n.settings-connection-issue-note {\r\n margin-top: -4px;\r\n}\r\n\r\n.settings-connection-state-summary {\r\n padding: 14px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-empty {\r\n display: flex;\r\n align-items: center;\r\n min-height: 72px;\r\n padding: 12px 16px;\r\n}\r\n\r\n.settings-empty > div {\r\n display: grid;\r\n min-width: 0;\r\n gap: 2px;\r\n}\r\n\r\n.settings-empty strong {\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 19px;\r\n}\r\n\r\n.settings-empty span {\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 19px;\r\n}\r\n\r\n.settings-about-panel {\r\n display: grid;\r\n max-width: 720px;\r\n gap: 18px;\r\n padding: 24px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 12px;\r\n}\r\n\r\n.settings-about-product {\r\n color: var(--settings-text);\r\n font-size: 24px;\r\n font-weight: 700;\r\n line-height: 32px;\r\n}\r\n\r\n.settings-about-tagline {\r\n color: var(--settings-text);\r\n font-size: 16px;\r\n font-weight: 600;\r\n line-height: 24px;\r\n}\r\n\r\n.settings-about-copy {\r\n display: grid;\r\n max-width: 660px;\r\n gap: 12px;\r\n}\r\n\r\n.settings-about-copy p,\r\n.settings-about-repository p {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 21px;\r\n}\r\n\r\n.settings-about-star-callout {\r\n margin: 2px 0;\r\n color: var(--settings-warning);\r\n font-size: 14px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-about-repository {\r\n display: grid;\r\n gap: 10px;\r\n padding-top: 18px;\r\n border-top: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-about-repository-link {\r\n display: flex;\r\n align-items: center;\r\n width: fit-content;\r\n min-width: 0;\r\n max-width: 100%;\r\n gap: 8px;\r\n color: var(--settings-focus);\r\n font-size: 13px;\r\n font-weight: 600;\r\n text-decoration: none;\r\n}\r\n\r\n.settings-about-repository-link:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.settings-about-repository-link code {\r\n min-width: 0;\r\n overflow: hidden;\r\n color: var(--settings-muted);\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n font-size: 11px;\r\n font-weight: 400;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-page-error {\r\n padding: 16px;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 20px;\r\n}\r\n\r\n.settings-update-metadata {\r\n display: grid;\r\n grid-template-columns: repeat(3, minmax(0, 1fr));\r\n gap: 24px;\r\n margin-bottom: 24px;\r\n padding: 0 4px 20px;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-update-metadata__item {\r\n display: grid;\r\n min-width: 0;\r\n gap: 4px;\r\n}\r\n\r\n.settings-update-metadata__item span {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-update-metadata__item strong {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n color: var(--settings-text);\r\n font-size: 15px;\r\n font-weight: 500;\r\n line-height: 22px;\r\n}\r\n\r\n/* The only emphasis on this screen: a latest version newer than the installed one. */\r\n.settings-update-metadata__value--newer {\r\n color: var(--settings-focus);\r\n}\r\n\r\n.settings-update-panel {\r\n display: grid;\r\n gap: 12px;\r\n padding: 20px;\r\n color: var(--settings-text);\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-update-panel__head {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 8px;\r\n}\r\n\r\n.settings-update-panel__head .codexhost-settings-icon {\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-update-panel[data-update-state="available"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="downloading"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="installing"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="restarting"] .codexhost-settings-icon {\r\n color: var(--settings-focus);\r\n}\r\n\r\n.settings-update-panel[data-update-state="current"] .codexhost-settings-icon {\r\n color: var(--settings-success);\r\n}\r\n\r\n.settings-update-panel[data-update-state="failed"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="error"] .codexhost-settings-icon {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-update-panel__title {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n color: var(--settings-text);\r\n font-size: 14px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-update-summary,\r\n.settings-update-error {\r\n margin: 0;\r\n overflow-wrap: anywhere;\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-update-summary {\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-update-error {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-update-progress {\r\n width: 100%;\r\n height: 8px;\r\n accent-color: var(--settings-focus);\r\n}\r\n\r\n.settings-update-progress-detail {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n/* Release notes scroll with the page; a scroller inside a scroller traps the wheel. */\r\n.settings-update-notes-section {\r\n min-width: 0;\r\n margin-top: 24px;\r\n padding-top: 24px;\r\n border-top: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-update-notes-section:empty {\r\n display: none;\r\n}\r\n\r\n.settings-update-notes {\r\n display: grid;\r\n min-width: 0;\r\n gap: 12px;\r\n color: var(--settings-muted);\r\n font-size: 14px;\r\n line-height: 22px;\r\n overflow-wrap: anywhere;\r\n}\r\n\r\n.settings-update-notes > :first-child {\r\n margin-top: 0;\r\n}\r\n\r\n.settings-update-notes > :last-child {\r\n margin-bottom: 0;\r\n}\r\n\r\n.settings-update-notes h1,\r\n.settings-update-notes h2,\r\n.settings-update-notes h3,\r\n.settings-update-notes h4,\r\n.settings-update-notes h5,\r\n.settings-update-notes h6 {\r\n margin: 6px 0 0;\r\n color: var(--settings-text);\r\n font-weight: 600;\r\n}\r\n\r\n.settings-update-notes h1 {\r\n font-size: 18px;\r\n line-height: 26px;\r\n}\r\n\r\n.settings-update-notes h2 {\r\n font-size: 17px;\r\n line-height: 24px;\r\n}\r\n\r\n.settings-update-notes h3,\r\n.settings-update-notes h4,\r\n.settings-update-notes h5,\r\n.settings-update-notes h6 {\r\n font-size: 14px;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-update-notes p,\r\n.settings-update-notes ul,\r\n.settings-update-notes ol,\r\n.settings-update-notes pre,\r\n.settings-update-notes blockquote {\r\n margin: 0;\r\n}\r\n\r\n.settings-update-notes ul,\r\n.settings-update-notes ol {\r\n padding-left: 24px;\r\n}\r\n\r\n.settings-update-notes li {\r\n padding-left: 4px;\r\n}\r\n\r\n.settings-update-notes li::marker {\r\n color: var(--settings-muted);\r\n font-size: 0.85em;\r\n}\r\n\r\n.settings-update-notes li + li {\r\n margin-top: 14px;\r\n}\r\n\r\n.settings-update-notes .release-note-translation {\r\n display: block;\r\n margin-top: 3px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-update-notes blockquote {\r\n padding: 8px 12px;\r\n color: var(--settings-muted);\r\n border-left: 3px solid var(--settings-focus);\r\n background: var(--settings-surface);\r\n}\r\n\r\n.settings-update-notes hr {\r\n width: 100%;\r\n margin: 2px 0;\r\n border: 0;\r\n border-top: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-update-notes strong {\r\n color: var(--settings-text);\r\n font-weight: 600;\r\n}\r\n\r\n.settings-update-notes a {\r\n color: var(--settings-focus);\r\n text-decoration: none;\r\n}\r\n\r\n.settings-update-notes a:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.settings-update-notes code {\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n font-size: 12px;\r\n}\r\n\r\n.settings-update-notes :not(pre) > code {\r\n padding: 1px 5px;\r\n background: var(--settings-surface);\r\n border-radius: 4px;\r\n}\r\n\r\n.settings-update-notes pre {\r\n min-width: 0;\r\n max-width: 100%;\r\n padding: 10px 12px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n background: var(--settings-inset);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-update-notes pre code {\r\n line-height: 18px;\r\n white-space: pre-wrap;\r\n}\r\n\r\n/* Manual update sits directly under the status panel, not behind a disclosure:\r\n automatic updates can fail for machine-local reasons and this is the way out. */\r\n.settings-update-controls {\r\n display: grid;\r\n min-width: 0;\r\n gap: 10px;\r\n margin-top: 24px;\r\n}\r\n\r\n.settings-update-manual-title {\r\n color: var(--settings-text);\r\n font-size: 15px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-update-manual {\r\n display: grid;\r\n min-width: 0;\r\n gap: 8px;\r\n}\r\n\r\n.settings-update-manual[hidden] {\r\n display: none;\r\n}\r\n\r\n.settings-update-manual-description {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-update-manual-description.is-fallback {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-update-command {\r\n display: flex;\r\n align-items: stretch;\r\n min-width: 0;\r\n overflow: hidden;\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-update-command code {\r\n min-width: 0;\r\n flex: 1;\r\n padding: 9px 12px;\r\n overflow-x: auto;\r\n color: var(--settings-text);\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n font-size: 12px;\r\n line-height: 20px;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-update-command__copy {\r\n display: inline-flex;\r\n align-items: center;\r\n flex: none;\r\n gap: 6px;\r\n padding: 0 12px;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n background: transparent;\r\n border: 0;\r\n border-left: 1px solid var(--settings-border);\r\n cursor: pointer;\r\n}\r\n\r\n.settings-update-command__copy:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-update-command__copy:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: -2px;\r\n}\r\n\r\n.settings-update-actions {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 12px;\r\n flex-wrap: wrap;\r\n}\r\n\r\n.settings-command-button,\r\n.settings-update-link {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex: none;\r\n width: max-content;\r\n max-width: 100%;\r\n min-height: 30px;\r\n gap: 6px;\r\n padding: 5px 10px;\r\n white-space: nowrap;\r\n color: var(--settings-primary-text);\r\n font: inherit;\r\n font-size: 12px;\r\n text-decoration: none;\r\n background: var(--settings-primary);\r\n border: 1px solid var(--settings-primary);\r\n border-radius: 7px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-command-button--secondary,\r\n.settings-update-link {\r\n color: var(--settings-text);\r\n background: var(--settings-panel);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-command-button:hover:not(:disabled) {\r\n background: var(--settings-primary-hover);\r\n border-color: var(--settings-primary-hover);\r\n}\r\n\r\n.settings-command-button--secondary:hover:not(:disabled),\r\n.settings-update-link:hover {\r\n background: var(--settings-hover);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-command-button--danger {\r\n color: #f87171;\r\n}\r\n\r\n.settings-command-button--danger:hover:not(:disabled) {\r\n color: #fecaca;\r\n background: rgb(127 29 29 / 24%);\r\n border-color: rgb(248 113 113 / 45%);\r\n}\r\n\r\n.settings-command-button:disabled {\r\n cursor: default;\r\n opacity: 0.45;\r\n}\r\n\r\n.settings-command-button:disabled,\r\n.settings-command-button[aria-disabled="true"] {\r\n opacity: 0.55;\r\n cursor: not-allowed;\r\n filter: none;\r\n}\r\n\r\n.settings-command-button:focus-visible,\r\n.settings-update-link:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.codexhost-settings-icon {\r\n display: block;\r\n flex: none;\r\n stroke: currentColor;\r\n}\r\n\r\n@media (max-width: 720px) {\r\n .codexhost-settings-dialog {\r\n width: calc(100vw - 16px);\r\n height: calc(100vh - 16px);\r\n border-radius: 10px;\r\n }\r\n\r\n .settings-layout {\r\n grid-template-columns: minmax(0, 1fr);\r\n grid-template-rows: auto minmax(0, 1fr);\r\n }\r\n\r\n .settings-session-import-row {\r\n grid-template-columns: minmax(0, 1fr);\r\n }\r\n\r\n .settings-session-import-row__action {\r\n align-items: flex-start;\r\n }\r\n\r\n .settings-sidebar {\r\n border-right: 0;\r\n border-bottom: 1px solid var(--settings-border);\r\n }\r\n\r\n .settings-header {\r\n height: 56px;\r\n padding-inline: 14px;\r\n }\r\n\r\n .settings-sidebar {\r\n padding-top: 20px;\r\n }\r\n\r\n .settings-nav {\r\n flex: none;\r\n flex-direction: row;\r\n gap: 4px;\r\n padding: 7px 8px 8px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n }\r\n\r\n .settings-nav-section-label {\r\n display: none;\r\n }\r\n\r\n .settings-nav-button {\r\n width: auto;\r\n min-width: max-content;\r\n min-height: 34px;\r\n grid-template-columns: 16px auto;\r\n border-radius: 10px;\r\n }\r\n\r\n .settings-nav-star-link {\r\n margin-top: 0;\r\n }\r\n\r\n .settings-page__content {\r\n width: calc(100% - 40px);\r\n }\r\n\r\n .settings-page__content {\r\n padding-top: 32px;\r\n padding-bottom: 32px;\r\n }\r\n\r\n .settings-section-label {\r\n padding-bottom: 20px;\r\n font-size: 20px;\r\n line-height: 26px;\r\n }\r\n\r\n .settings-update-metadata {\r\n grid-template-columns: minmax(0, 1fr);\r\n gap: 16px;\r\n }\r\n\r\n .settings-status-row {\r\n grid-template-columns: minmax(0, 1fr) auto;\r\n gap: 16px;\r\n }\r\n\r\n .settings-account-header,\r\n .settings-connection-page-header {\r\n flex-direction: column;\r\n }\r\n\r\n .settings-account-header > .settings-command-button,\r\n .settings-connection-page-header > .settings-command-button {\r\n width: 100%;\r\n }\r\n\r\n .settings-connections-layout {\r\n grid-template-columns: minmax(0, 1fr);\r\n }\r\n\r\n .settings-connection-inspector {\r\n position: static;\r\n }\r\n\r\n .settings-status-row__detail {\r\n grid-column: 1 / -1;\r\n margin: -8px 0 0 58px;\r\n }\r\n}\r\n\r\n@media (forced-colors: active) {\r\n :host {\r\n --settings-bg: Canvas;\r\n --settings-sidebar: Canvas;\r\n --settings-panel: Canvas;\r\n --settings-surface: Canvas;\r\n --settings-surface-hover: Highlight;\r\n --settings-inset: Canvas;\r\n --settings-text: CanvasText;\r\n --settings-muted: GrayText;\r\n --settings-subtle: GrayText;\r\n --settings-border: ButtonBorder;\r\n --settings-divider: ButtonBorder;\r\n --settings-hover: Highlight;\r\n --settings-active: Highlight;\r\n --settings-focus: Highlight;\r\n --settings-primary: ButtonFace;\r\n --settings-primary-hover: Highlight;\r\n --settings-primary-text: ButtonText;\r\n --settings-warning: CanvasText;\r\n --settings-warning-bg: Canvas;\r\n --settings-warning-border: ButtonBorder;\r\n --settings-danger: CanvasText;\r\n --settings-danger-bg: Canvas;\r\n --settings-danger-border: ButtonBorder;\r\n --settings-success: CanvasText;\r\n }\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n *,\r\n *::before,\r\n *::after {\r\n scroll-behavior: auto !important;\r\n transition-duration: 0s !important;\r\n }\r\n}\r\n\r\n/* Harness Mix: Model Configuration & One-click Install */\r\n.settings-model-config-panel {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n padding: 14px;\r\n margin-top: 14px;\r\n border-radius: 8px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n}\r\n\r\n.settings-model-config-head {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n}\r\n\r\n.settings-model-config-title {\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: var(--settings-text);\r\n}\r\n\r\n.settings-model-config-description {\r\n font-size: 11px;\r\n color: var(--settings-muted);\r\n margin: 0;\r\n}\r\n\r\n.settings-model-config-loading,\r\n.settings-model-config-empty {\r\n font-size: 12px;\r\n color: var(--settings-muted);\r\n padding: 8px 0;\r\n}\r\n\r\n.settings-model-config-form {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n margin-top: 4px;\r\n}\r\n\r\n.settings-model-config-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n}\r\n\r\n.settings-model-config-label {\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--settings-muted);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.settings-model-config-select {\r\n height: 32px;\r\n padding: 0 10px;\r\n border-radius: 6px;\r\n border: 1px solid var(--settings-border);\r\n background: var(--settings-panel);\r\n color: var(--settings-text);\r\n font-size: 12px;\r\n outline: none;\r\n}\r\n\r\n.settings-model-config-select:focus {\r\n border-color: var(--settings-primary);\r\n}\r\n\r\n.settings-model-config-actions {\r\n display: flex;\r\n align-items: center;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n margin-top: 6px;\r\n}\r\n\r\n.settings-model-config-feedback {\r\n font-size: 12px;\r\n font-weight: 500;\r\n}\r\n\r\n.settings-feedback-success {\r\n color: var(--settings-success);\r\n}\r\n\r\n.settings-feedback-error {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-feedback-info {\r\n color: var(--settings-primary);\r\n}\r\n\r\n.settings-install-command-box {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n min-width: 0;\r\n margin: 0;\r\n}\r\n\r\n.settings-install-command-label {\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-install-command-row {\r\n display: flex;\r\n align-items: center;\r\n background: var(--settings-inset);\r\n padding: 8px 12px;\r\n border-radius: 6px;\r\n border: 1px solid var(--settings-border);\r\n min-width: 0;\r\n overflow-x: auto;\r\n}\r\n\r\n.settings-install-command-row code {\r\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\r\n font-size: 12px;\r\n line-height: 18px;\r\n color: var(--settings-text);\r\n user-select: all;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n}\r\n\r\n.settings-install-actions {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1fr);\r\n gap: 8px;\r\n margin-top: 4px;\r\n}\r\n\r\n.settings-install-actions .settings-command-button {\r\n width: 100%;\r\n justify-content: center;\r\n}\r\n\r\n.settings-install-feedback {\r\n font-size: 12px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n margin-top: 2px;\r\n overflow-wrap: anywhere;\r\n}\r\n';
26552
+ var shell_default = ':host {\r\n --settings-bg: light-dark(#ffffff, #202020);\r\n --settings-sidebar: light-dark(#f7f7f8, #191919);\r\n --settings-panel: light-dark(#ffffff, #232323);\r\n --settings-surface: light-dark(#f6f6f6, #292929);\r\n --settings-surface-hover: light-dark(#eeeeee, #303030);\r\n --settings-inset: light-dark(#f3f3f3, #161616);\r\n --settings-text: light-dark(#0d0d0d, #ececec);\r\n --settings-muted: light-dark(#676767, #a3a3a3);\r\n --settings-subtle: light-dark(#8a8a8a, #777777);\r\n --settings-border: light-dark(rgb(13 13 13 / 9%), rgb(255 255 255 / 9%));\r\n --settings-divider: light-dark(rgb(13 13 13 / 7%), rgb(255 255 255 / 7%));\r\n --settings-hover: light-dark(rgb(13 13 13 / 5%), rgb(255 255 255 / 7%));\r\n --settings-active: light-dark(rgb(13 13 13 / 7%), rgb(255 255 255 / 9%));\r\n --settings-focus: light-dark(#0b75d1, #66aaf9);\r\n --settings-primary: light-dark(#171717, #f4f4f4);\r\n --settings-primary-hover: light-dark(#2f2f2f, #ffffff);\r\n --settings-primary-text: light-dark(#ffffff, #171717);\r\n --settings-warning: light-dark(#8a5500, #f5c96a);\r\n --settings-warning-bg: light-dark(#fff8e6, rgb(245 201 106 / 8%));\r\n --settings-warning-border: light-dark(#ead8a8, rgb(245 201 106 / 24%));\r\n --settings-danger: light-dark(#b42318, #f87171);\r\n --settings-danger-bg: light-dark(#fff1f0, rgb(239 68 68 / 8%));\r\n --settings-danger-border: light-dark(#f3c7c3, rgb(239 68 68 / 22%));\r\n --settings-success: light-dark(#16784a, #4ade80);\r\n color: var(--settings-text);\r\n color-scheme: inherit;\r\n font:\r\n 13px/1.5 system-ui,\r\n -apple-system,\r\n BlinkMacSystemFont,\r\n "Segoe UI",\r\n sans-serif;\r\n letter-spacing: 0;\r\n}\r\n\r\n*,\r\n*::before,\r\n*::after {\r\n box-sizing: border-box;\r\n letter-spacing: 0;\r\n}\r\n\r\nbutton,\r\ninput,\r\nselect {\r\n font: inherit;\r\n}\r\n\r\nbutton {\r\n color: inherit;\r\n}\r\n\r\n[hidden] {\r\n display: none !important;\r\n}\r\n\r\n.settings-visually-hidden {\r\n position: absolute;\r\n width: 1px;\r\n height: 1px;\r\n padding: 0;\r\n margin: -1px;\r\n overflow: hidden;\r\n clip-path: inset(50%);\r\n white-space: nowrap;\r\n border: 0;\r\n}\r\n\r\n.codexhost-settings-dialog {\r\n width: min(1120px, calc(100vw - 32px));\r\n height: min(780px, calc(100vh - 32px));\r\n max-width: none;\r\n max-height: none;\r\n margin: auto;\r\n padding: 0;\r\n overflow: hidden;\r\n color: var(--settings-text);\r\n background: var(--settings-bg);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 14px;\r\n box-shadow: light-dark(0 16px 42px rgb(0 0 0 / 16%), 0 20px 54px rgb(0 0 0 / 42%));\r\n}\r\n\r\n.codexhost-settings-dialog::backdrop {\r\n background: light-dark(rgb(0 0 0 / 24%), rgb(0 0 0 / 56%));\r\n backdrop-filter: blur(1px);\r\n}\r\n\r\n.settings-frame,\r\n.settings-layout {\r\n width: 100%;\r\n height: 100%;\r\n min-width: 0;\r\n min-height: 0;\r\n}\r\n\r\n.settings-frame {\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.settings-layout {\r\n flex: 1;\r\n display: grid;\r\n grid-template-columns: 184px minmax(0, 1fr);\r\n background: var(--settings-bg);\r\n}\r\n\r\n.settings-sidebar {\r\n display: flex;\r\n min-width: 0;\r\n min-height: 0;\r\n flex-direction: column;\r\n overflow: hidden;\r\n background: var(--settings-sidebar);\r\n border-right: 1px solid var(--settings-border);\r\n padding-top: 14px;\r\n}\r\n\r\n.settings-header {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n height: 48px;\r\n flex: none;\r\n padding: 0 12px;\r\n border-bottom: 1px solid var(--settings-border);\r\n}\r\n\r\n.settings-header-actions {\r\n display: flex;\r\n align-items: center;\r\n flex: none;\r\n gap: 12px;\r\n margin-left: auto;\r\n}\r\n\r\n.settings-brand {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 7px;\r\n}\r\n\r\n.settings-brand__mark {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n flex: none;\r\n color: var(--settings-text);\r\n}\r\n\r\n.settings-brand__mark .codexhost-settings-icon {\r\n width: 24px;\r\n height: 24px;\r\n object-fit: contain;\r\n}\r\n\r\n.settings-brand__copy {\r\n display: flex;\r\n min-width: 0;\r\n align-items: baseline;\r\n gap: 0;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-brand__name {\r\n overflow: hidden;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n font-weight: 600;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-brand__title {\r\n margin-left: 8px;\r\n padding-left: 8px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n font-weight: 400;\r\n border-left: 1px solid var(--settings-border);\r\n}\r\n\r\n.settings-nav {\r\n display: flex;\r\n min-width: 0;\r\n min-height: 0;\r\n flex: 1;\r\n flex-direction: column;\r\n gap: 2px;\r\n padding: 0 7px 10px;\r\n overflow-y: auto;\r\n}\r\n\r\n.settings-nav-section-label {\r\n min-height: 24px;\r\n padding: 4px 9px 2px;\r\n color: var(--settings-subtle);\r\n font-size: 11px;\r\n font-weight: 600;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-nav-section-label:not(:first-child) {\r\n margin-top: 8px;\r\n}\r\n\r\n.settings-nav-button {\r\n display: grid;\r\n grid-template-columns: 16px minmax(0, 1fr);\r\n align-items: center;\r\n width: 100%;\r\n position: relative;\r\n min-height: 34px;\r\n flex: none;\r\n gap: 9px;\r\n padding: 6px 9px;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n line-height: 20px;\r\n text-align: left;\r\n background: transparent;\r\n border: 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-nav-button .codexhost-settings-icon {\r\n width: 16px;\r\n height: 16px;\r\n opacity: 0.9;\r\n}\r\n\r\n.settings-nav-button:hover {\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-nav-button[aria-current="page"] {\r\n background: var(--settings-active);\r\n color: var(--settings-text);\r\n font-weight: 500;\r\n}\r\n\r\n.settings-nav-button span {\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-nav-star-link {\r\n margin-top: 0;\r\n color: var(--settings-text);\r\n text-decoration: none;\r\n}\r\n\r\n.settings-nav-star-link .codexhost-settings-icon {\r\n color: var(--settings-warning);\r\n}\r\n\r\n.settings-nav-star-link:hover {\r\n color: var(--settings-warning);\r\n background: var(--settings-warning-bg);\r\n}\r\n\r\n.settings-icon-button {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 28px;\r\n height: 28px;\r\n flex: none;\r\n padding: 0;\r\n color: var(--settings-muted);\r\n background: transparent;\r\n border: 0;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-icon-button:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-icon-button:focus-visible,\r\n.settings-nav-button:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 1px;\r\n}\r\n\r\n.settings-page {\r\n display: block;\r\n position: relative;\r\n min-width: 0;\r\n min-height: 0;\r\n overflow-y: auto;\r\n background: var(--settings-bg);\r\n scrollbar-gutter: stable;\r\n}\r\n\r\n.settings-page__content {\r\n width: min(930px, calc(100% - 80px));\r\n margin-inline: auto;\r\n}\r\n\r\n.settings-page__content {\r\n min-width: 0;\r\n padding: 28px 0 36px;\r\n}\r\n\r\n.settings-section-label {\r\n min-height: auto;\r\n margin: 0;\r\n padding: 0 0 18px;\r\n color: var(--settings-text);\r\n font-size: 18px;\r\n font-weight: 600;\r\n line-height: 26px;\r\n}\r\n\r\n.settings-status-list,\r\n.settings-empty {\r\n overflow: hidden;\r\n background: var(--settings-panel);\r\n}\r\n\r\n.settings-status-row {\r\n display: grid;\r\n grid-template-columns: minmax(170px, 1fr) auto minmax(280px, 1.45fr);\r\n position: relative;\r\n align-items: center;\r\n min-height: 72px;\r\n gap: 20px;\r\n padding: 12px 0;\r\n}\r\n\r\n.settings-status-row:not(:last-child)::after {\r\n content: "";\r\n position: absolute;\r\n right: 0;\r\n bottom: 0;\r\n left: 0;\r\n height: 1px;\r\n background: var(--settings-divider);\r\n}\r\n\r\n.settings-status-row__identity {\r\n display: inline-flex;\r\n align-items: center;\r\n min-width: 0;\r\n color: var(--settings-text);\r\n gap: 10px;\r\n font-size: 14px;\r\n font-weight: 500;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-status-row__icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 36px;\r\n height: 36px;\r\n flex: none;\r\n color: var(--settings-muted);\r\n background: var(--settings-surface);\r\n border-radius: 50%;\r\n}\r\n\r\n.settings-status-badge {\r\n flex: none;\r\n padding: 3px 8px;\r\n color: var(--settings-muted);\r\n font-size: 11px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-status-row__detail {\r\n min-width: 0;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-page-description {\r\n max-width: 760px;\r\n margin: -10px 0 20px;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-session-import-header {\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: space-between;\r\n gap: 24px;\r\n}\r\n\r\n.settings-session-import-header .settings-section-label {\r\n min-width: 0;\r\n}\r\n\r\n.settings-session-import-harness {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 12px;\r\n margin: -12px 0 16px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n}\r\n\r\n.settings-session-import-harness > span {\r\n flex: none;\r\n}\r\n\r\n.settings-session-import-harness__options {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n flex: 1;\r\n gap: 6px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n scrollbar-width: none;\r\n}\r\n\r\n.settings-session-import-harness__options::-webkit-scrollbar {\r\n display: none;\r\n}\r\n\r\n.settings-session-import-harness__option {\r\n min-height: 32px;\r\n flex: none;\r\n padding: 6px 10px;\r\n color: var(--settings-muted);\r\n font: inherit;\r\n font-size: 12px;\r\n white-space: nowrap;\r\n background: rgb(255 255 255 / 4%);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-session-import-harness__option[aria-pressed="true"] {\r\n color: var(--settings-text);\r\n background: var(--settings-active);\r\n border-color: rgb(51 156 255 / 50%);\r\n}\r\n\r\n.settings-session-import-harness__option:disabled {\r\n opacity: 0.38;\r\n cursor: not-allowed;\r\n}\r\n\r\n.settings-session-import-harness__option:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-session-import-harness + .settings-page-description {\r\n margin-top: 0;\r\n margin-bottom: 4px;\r\n}\r\n\r\n.settings-session-import-availability-note {\r\n margin-top: 0;\r\n}\r\n\r\n.settings-session-import-search,\r\n.settings-session-import-pagination {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: 10px;\r\n margin: 16px 0;\r\n}\r\n\r\n.settings-session-import-search input {\r\n flex: 1;\r\n min-width: 160px;\r\n}\r\n\r\n.settings-session-import-search input,\r\n.settings-session-import-pagination select {\r\n min-height: 36px;\r\n padding: 6px 10px;\r\n color: var(--settings-text);\r\n background: var(--settings-bg);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-session-import-search input:focus-visible,\r\n.settings-session-import-pagination select:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-session-import-pagination {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n}\r\n\r\n.settings-session-import-pagination label {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.settings-session-import-pagination > span {\r\n flex: 1;\r\n min-width: 130px;\r\n}\r\n\r\n.settings-session-import-pagination__navigation {\r\n display: flex;\r\n gap: 8px;\r\n margin-left: auto;\r\n}\r\n\r\n.settings-session-import-content,\r\n.settings-session-import-list {\r\n display: grid;\r\n gap: 10px;\r\n}\r\n\r\n.settings-session-import-status {\r\n display: flex;\r\n align-items: center;\r\n min-height: 64px;\r\n gap: 12px;\r\n padding: 16px;\r\n color: var(--settings-muted);\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-session-import-status.is-error {\r\n color: #ef4444;\r\n}\r\n\r\n.settings-session-import-recovery {\r\n display: grid;\r\n justify-items: start;\r\n gap: 14px;\r\n padding: 16px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-session-import-recovery:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-session-import-recovery__copy {\r\n display: grid;\r\n gap: 4px;\r\n}\r\n\r\n.settings-session-import-recovery__copy strong {\r\n color: var(--settings-text);\r\n font-size: 14px;\r\n}\r\n\r\n.settings-session-import-recovery__copy p {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-session-import-recovery__path {\r\n display: flex;\r\n align-items: stretch;\r\n width: 100%;\r\n min-width: 0;\r\n overflow: hidden;\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-session-import-recovery__path code {\r\n min-width: 0;\r\n flex: 1;\r\n padding: 8px 10px;\r\n overflow-x: auto;\r\n color: var(--settings-text);\r\n font-size: 12px;\r\n line-height: 20px;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-session-import-recovery__path .settings-command-button {\r\n min-height: 0;\r\n flex: none;\r\n border-width: 0 0 0 1px;\r\n border-radius: 0;\r\n}\r\n\r\n.settings-session-import-row {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1fr) auto;\r\n align-items: center;\r\n gap: 20px;\r\n min-width: 0;\r\n padding: 16px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-session-import-row__copy {\r\n display: grid;\r\n min-width: 0;\r\n gap: 4px;\r\n}\r\n\r\n.settings-session-import-row__copy strong {\r\n overflow: hidden;\r\n color: var(--settings-text);\r\n font-size: 14px;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-session-import-row__copy span,\r\n.settings-session-import-row__cwd {\r\n overflow: hidden;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-session-import-row__cwd {\r\n display: block;\r\n min-width: 0;\r\n background: transparent;\r\n}\r\n\r\n.settings-session-import-row__action {\r\n display: flex;\r\n align-items: flex-end;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.settings-session-import-running {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n}\r\n\r\n.settings-preference-row {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 32px;\r\n min-height: 88px;\r\n padding: 18px 0;\r\n border-top: 1px solid var(--settings-divider);\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-preference-row__copy {\r\n display: flex;\r\n flex: 1 1 auto;\r\n flex-direction: column;\r\n min-width: 0;\r\n gap: 5px;\r\n}\r\n\r\n.settings-preference-row__copy strong {\r\n color: var(--settings-text);\r\n font-size: 15px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-preference-row__copy span {\r\n max-width: 680px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-preference-switch {\r\n display: inline-flex;\r\n align-items: center;\r\n width: 42px;\r\n height: 24px;\r\n flex: none;\r\n padding: 2px;\r\n border: 0;\r\n border-radius: 999px;\r\n background: var(--settings-surface-hover);\r\n cursor: pointer;\r\n transition: background 120ms ease;\r\n}\r\n\r\n.settings-preference-switch[aria-checked="true"] {\r\n justify-content: flex-end;\r\n background: var(--settings-focus);\r\n}\r\n\r\n.settings-preference-switch:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.settings-preference-switch__thumb {\r\n width: 20px;\r\n height: 20px;\r\n border-radius: 50%;\r\n background: var(--settings-primary-text);\r\n box-shadow: 0 1px 3px rgb(0 0 0 / 24%);\r\n}\r\n\r\n.settings-connection-page-header {\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: space-between;\r\n gap: 18px;\r\n margin-bottom: 18px;\r\n}\r\n\r\n.settings-connection-page-header .settings-section-label {\r\n padding-bottom: 0;\r\n}\r\n\r\n.settings-connection-page-header .settings-page-description {\r\n margin: 5px 0 0;\r\n}\r\n\r\n.settings-connections-content,\r\n.settings-connections-layout,\r\n.settings-connection-list,\r\n.settings-connection-rows {\r\n min-width: 0;\r\n}\r\n\r\n.settings-connections-layout {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.85fr);\r\n align-items: start;\r\n gap: 18px;\r\n}\r\n\r\n.settings-connection-list,\r\n.settings-connection-inspector {\r\n overflow: hidden;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-host-strip {\r\n display: grid;\r\n grid-template-columns: 30px minmax(0, 1fr) 30px;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 5px;\r\n padding: 9px 10px;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-host-scroll {\r\n display: none;\r\n align-items: center;\r\n justify-content: center;\r\n width: 30px;\r\n height: 34px;\r\n padding: 0;\r\n color: var(--settings-muted);\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-host-strip[data-connection-host-overflow="true"]\r\n .settings-connection-host-scroll {\r\n display: inline-flex;\r\n}\r\n\r\n.settings-connection-host-strip:not([data-connection-host-overflow="true"]) {\r\n grid-template-columns: minmax(0, 1fr);\r\n}\r\n\r\n.settings-connection-host-scroll:hover:not(:disabled) {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-host-scroll:disabled {\r\n cursor: default;\r\n opacity: 0.35;\r\n}\r\n\r\n.settings-connection-host-scroll:focus-visible,\r\n.settings-connection-host-tab:focus-visible,\r\n.settings-connection-row:focus-visible,\r\n.settings-connection-install-link:focus-visible,\r\n.settings-connection-view-error:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 1px;\r\n}\r\n\r\n.settings-connection-host-tabs {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 6px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n overscroll-behavior-x: contain;\r\n scrollbar-width: none;\r\n scroll-behavior: smooth;\r\n scroll-snap-type: x proximity;\r\n touch-action: pan-x;\r\n}\r\n\r\n.settings-connection-host-tabs::-webkit-scrollbar {\r\n display: none;\r\n}\r\n\r\n.settings-connection-host-tab {\r\n display: inline-flex;\r\n align-items: center;\r\n height: 30px;\r\n min-width: max-content;\r\n flex: none;\r\n padding: 0 9px;\r\n color: var(--settings-muted);\r\n font: inherit;\r\n font-size: 12px;\r\n line-height: 18px;\r\n white-space: nowrap;\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 7px;\r\n cursor: pointer;\r\n scroll-snap-align: start;\r\n}\r\n\r\n.settings-connection-host-tab:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-host-tab[aria-selected="true"] {\r\n color: var(--settings-text);\r\n font-weight: 600;\r\n background: var(--settings-active);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-connection-table-header,\r\n.settings-connection-row {\r\n display: grid;\r\n grid-template-columns: minmax(160px, 1fr) minmax(92px, auto) 108px;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 10px;\r\n}\r\n\r\n.settings-connection-table-header {\r\n min-height: 30px;\r\n padding: 0 10px;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n font-weight: 600;\r\n line-height: 16px;\r\n text-transform: uppercase;\r\n letter-spacing: 0.06em;\r\n background: transparent;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-row {\r\n min-height: 52px;\r\n padding: 8px 10px;\r\n cursor: pointer;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-row:last-child {\r\n border-bottom: 0;\r\n}\r\n\r\n.settings-connection-row:hover {\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-row[data-connection-selected="true"] {\r\n background: var(--settings-surface);\r\n}\r\n\r\n.settings-connection-row__identity,\r\n.settings-connection-inspector__identity {\r\n display: inline-flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 8px;\r\n color: var(--settings-text);\r\n}\r\n\r\n.settings-connection-row__identity strong,\r\n.settings-connection-inspector__identity strong {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n font-size: 12px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-row__mark {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n flex: none;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n font-weight: 700;\r\n background: var(--settings-surface);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-connection-row__mark--logo {\r\n color: var(--settings-text);\r\n background: transparent;\r\n}\r\n\r\n.settings-connection-row__mark--logo > img,\r\n.settings-connection-row__mark--logo > svg {\r\n display: block;\r\n max-width: 18px;\r\n max-height: 18px;\r\n}\r\n\r\n.settings-connection-row__status {\r\n display: inline-flex;\r\n align-items: center;\r\n width: fit-content;\r\n gap: 5px;\r\n color: var(--settings-muted);\r\n font-size: 11px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-row__status::before {\r\n width: 6px;\r\n height: 6px;\r\n flex: none;\r\n content: "";\r\n background: currentColor;\r\n border-radius: 50%;\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="ready"] {\r\n color: var(--settings-success);\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="checking"] {\r\n color: var(--settings-warning);\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="setup"] {\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="setup"]::before {\r\n background: transparent;\r\n border: 1.5px solid currentColor;\r\n}\r\n\r\n.settings-connection-row__status[data-connection-tone="failed"] {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-connection-row__action {\r\n display: flex;\r\n align-items: center;\r\n justify-content: flex-end;\r\n min-width: 0;\r\n gap: 4px;\r\n}\r\n\r\n.settings-connection-row__handle {\r\n display: inline-flex;\r\n flex: none;\r\n align-items: center;\r\n justify-content: center;\r\n width: 16px;\r\n color: var(--settings-muted);\r\n cursor: grab;\r\n opacity: 0.6;\r\n}\r\n\r\n.settings-connection-row__handle:hover {\r\n opacity: 1;\r\n}\r\n\r\n.settings-connection-row[draggable="true"] {\r\n cursor: grab;\r\n}\r\n\r\n.settings-connection-row[data-connection-dragging="true"] {\r\n opacity: 0.4;\r\n}\r\n\r\n.settings-connection-row[data-connection-drop-indicator="before"] {\r\n box-shadow: inset 0 2px 0 0 var(--settings-focus);\r\n}\r\n\r\n.settings-connection-row[data-connection-drop-indicator="after"] {\r\n box-shadow: inset 0 -2px 0 0 var(--settings-focus);\r\n}\r\n\r\n.settings-connection-row__group-toggle {\r\n display: inline-flex;\r\n flex: none;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n color: var(--settings-muted);\r\n background: transparent;\r\n border: 0;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-row__group-toggle:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-group-divider {\r\n padding: 10px 12px 6px;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n font-weight: 600;\r\n line-height: 16px;\r\n text-transform: uppercase;\r\n letter-spacing: 0.06em;\r\n /* No border-top here: the row immediately above already carries its own\r\n border-bottom (it is no longer :last-child once this divider follows\r\n it), so adding one here would double the separator line. */\r\n}\r\n\r\n.settings-connection-group-more[data-connection-drag-over="true"] {\r\n background: rgb(51 156 255 / 8%);\r\n}\r\n\r\n.settings-connection-group-hint {\r\n display: grid;\r\n gap: 3px;\r\n margin: 0 12px 12px;\r\n padding: 14px 16px;\r\n text-align: center;\r\n border: 1.5px dashed var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-group-more[data-connection-drag-over="true"] .settings-connection-group-hint {\r\n border-color: var(--settings-focus);\r\n}\r\n\r\n.settings-connection-group-hint strong {\r\n color: var(--settings-text);\r\n font-size: 12.5px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-group-hint span {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 17px;\r\n}\r\n\r\n.settings-connection-group-reset {\r\n display: flex;\r\n width: 100%;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 10px 12px;\r\n color: var(--settings-muted);\r\n font: inherit;\r\n font-size: 12px;\r\n text-align: left;\r\n background: transparent;\r\n border: 0;\r\n border-top: 1px solid var(--settings-divider);\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-group-reset:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-connection-install-link {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n color: var(--settings-focus);\r\n text-decoration: none;\r\n background: transparent;\r\n border: 1px solid transparent;\r\n border-radius: 7px;\r\n opacity: 0;\r\n transition: opacity 120ms ease;\r\n}\r\n\r\n.settings-connection-row:hover .settings-connection-install-link,\r\n.settings-connection-install-link:focus-visible {\r\n opacity: 1;\r\n}\r\n\r\n.settings-connection-install-link:hover {\r\n color: var(--settings-focus);\r\n background: var(--settings-active);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-connection-view-error {\r\n padding: 4px 7px;\r\n color: var(--settings-danger);\r\n font: inherit;\r\n font-size: 11px;\r\n line-height: 18px;\r\n background: transparent;\r\n border: 0;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-connection-view-error:hover {\r\n color: var(--settings-danger);\r\n background: var(--settings-danger-bg);\r\n}\r\n\r\n.settings-connection-inspector {\r\n position: sticky;\r\n top: 18px;\r\n}\r\n\r\n.settings-connection-inspector__header {\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: space-between;\r\n min-width: 0;\r\n gap: 10px;\r\n padding: 12px;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-connection-inspector__body {\r\n display: grid;\r\n min-width: 0;\r\n gap: 12px;\r\n padding: 12px;\r\n}\r\n\r\n.settings-connection-install-callout {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 14px;\r\n padding: 14px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-install-head {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 12px;\r\n min-width: 0;\r\n}\r\n\r\n.settings-connection-install-head > div {\r\n min-width: 0;\r\n flex: 1;\r\n}\r\n\r\n.settings-connection-install-callout__icon {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 32px;\r\n height: 32px;\r\n flex: none;\r\n color: var(--settings-focus);\r\n background: var(--settings-active);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-connection-install-callout strong,\r\n.settings-connection-install-head strong,\r\n.settings-connection-error-summary strong,\r\n.settings-connection-state-summary strong {\r\n display: block;\r\n margin: 0 0 4px;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n font-weight: 600;\r\n line-height: 19px;\r\n}\r\n\r\n.settings-connection-install-callout p,\r\n.settings-connection-install-head p,\r\n.settings-connection-error-summary p,\r\n.settings-connection-state-summary p,\r\n.settings-connection-issue-note {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-connection-install-button {\r\n width: 100%;\r\n}\r\n\r\n.settings-connection-error-summary {\r\n padding: 13px 14px;\r\n color: var(--settings-danger);\r\n background: var(--settings-danger-bg);\r\n border: 1px solid var(--settings-danger-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-connection-error-metadata {\r\n display: grid;\r\n gap: 7px;\r\n padding: 12px;\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 9px;\r\n}\r\n\r\n.settings-connection-detail-line {\r\n display: grid;\r\n grid-template-columns: 92px minmax(0, 1fr);\r\n gap: 10px;\r\n min-width: 0;\r\n color: var(--settings-muted);\r\n font-size: 10px;\r\n line-height: 16px;\r\n}\r\n\r\n.settings-connection-detail-line code {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n color: var(--settings-text);\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n white-space: pre-wrap;\r\n}\r\n\r\n.settings-connection-error-log-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n gap: 10px;\r\n}\r\n\r\n.settings-connection-error-log-header strong {\r\n color: var(--settings-text);\r\n font-size: 11px;\r\n font-weight: 600;\r\n}\r\n\r\n.settings-connection-error-log-header .settings-command-button {\r\n min-height: 30px;\r\n padding: 5px 9px;\r\n font-size: 11px;\r\n}\r\n\r\n.settings-connection-stderr {\r\n max-height: 220px;\r\n min-width: 0;\r\n margin: 0;\r\n padding: 11px;\r\n overflow: auto;\r\n color: var(--settings-text);\r\n font:\r\n 10px/16px ui-monospace,\r\n "SFMono-Regular",\r\n Consolas,\r\n "Liberation Mono",\r\n monospace;\r\n white-space: pre-wrap;\r\n overflow-wrap: anywhere;\r\n background: var(--settings-inset);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 9px;\r\n}\r\n\r\n.settings-connection-error-actions {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1fr);\r\n gap: 8px;\r\n}\r\n\r\n.settings-connection-error-actions .settings-command-button {\r\n width: 100%;\r\n}\r\n\r\n.settings-connection-issue-note {\r\n margin-top: -4px;\r\n}\r\n\r\n.settings-connection-state-summary {\r\n padding: 14px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 10px;\r\n}\r\n\r\n.settings-empty {\r\n display: flex;\r\n align-items: center;\r\n min-height: 72px;\r\n padding: 12px 16px;\r\n}\r\n\r\n.settings-empty > div {\r\n display: grid;\r\n min-width: 0;\r\n gap: 2px;\r\n}\r\n\r\n.settings-empty strong {\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n font-weight: 500;\r\n line-height: 19px;\r\n}\r\n\r\n.settings-empty span {\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 19px;\r\n}\r\n\r\n.settings-about-panel {\r\n display: grid;\r\n max-width: 720px;\r\n gap: 18px;\r\n padding: 24px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 12px;\r\n}\r\n\r\n.settings-about-product {\r\n color: var(--settings-text);\r\n font-size: 24px;\r\n font-weight: 700;\r\n line-height: 32px;\r\n}\r\n\r\n.settings-about-tagline {\r\n color: var(--settings-text);\r\n font-size: 16px;\r\n font-weight: 600;\r\n line-height: 24px;\r\n}\r\n\r\n.settings-about-version-row {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n margin: 4px 0 8px;\r\n}\r\n\r\n.settings-about-version-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: var(--settings-text);\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n padding: 4px 10px;\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-about-copy {\r\n display: grid;\r\n max-width: 660px;\r\n gap: 12px;\r\n}\r\n\r\n.settings-about-copy p,\r\n.settings-about-repository p {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 21px;\r\n}\r\n\r\n.settings-about-star-callout {\r\n margin: 2px 0;\r\n color: var(--settings-warning);\r\n font-size: 14px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-about-repository {\r\n display: grid;\r\n gap: 10px;\r\n padding-top: 18px;\r\n border-top: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-about-repository-link {\r\n display: flex;\r\n align-items: center;\r\n width: fit-content;\r\n min-width: 0;\r\n max-width: 100%;\r\n gap: 8px;\r\n color: var(--settings-focus);\r\n font-size: 13px;\r\n font-weight: 600;\r\n text-decoration: none;\r\n}\r\n\r\n.settings-about-repository-link:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.settings-about-repository-link code {\r\n min-width: 0;\r\n overflow: hidden;\r\n color: var(--settings-muted);\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n font-size: 11px;\r\n font-weight: 400;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-page-error {\r\n padding: 16px;\r\n color: var(--settings-text);\r\n font-size: 13px;\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 20px;\r\n}\r\n\r\n.settings-update-metadata {\r\n display: grid;\r\n grid-template-columns: repeat(3, minmax(0, 1fr));\r\n gap: 24px;\r\n margin-bottom: 24px;\r\n padding: 0 4px 20px;\r\n border-bottom: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-update-metadata__item {\r\n display: grid;\r\n min-width: 0;\r\n gap: 4px;\r\n}\r\n\r\n.settings-update-metadata__item span {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-update-metadata__item strong {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n color: var(--settings-text);\r\n font-size: 15px;\r\n font-weight: 500;\r\n line-height: 22px;\r\n}\r\n\r\n/* The only emphasis on this screen: a latest version newer than the installed one. */\r\n.settings-update-metadata__value--newer {\r\n color: var(--settings-focus);\r\n}\r\n\r\n.settings-update-panel {\r\n display: grid;\r\n gap: 12px;\r\n padding: 20px;\r\n color: var(--settings-text);\r\n background: var(--settings-panel);\r\n border: 1px solid var(--settings-border);\r\n border-radius: 8px;\r\n}\r\n\r\n.settings-update-panel__head {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 8px;\r\n}\r\n\r\n.settings-update-panel__head .codexhost-settings-icon {\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-update-panel[data-update-state="available"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="downloading"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="installing"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="restarting"] .codexhost-settings-icon {\r\n color: var(--settings-focus);\r\n}\r\n\r\n.settings-update-panel[data-update-state="current"] .codexhost-settings-icon {\r\n color: var(--settings-success);\r\n}\r\n\r\n.settings-update-panel[data-update-state="failed"] .codexhost-settings-icon,\r\n.settings-update-panel[data-update-state="error"] .codexhost-settings-icon {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-update-panel__title {\r\n min-width: 0;\r\n overflow-wrap: anywhere;\r\n color: var(--settings-text);\r\n font-size: 14px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-update-summary,\r\n.settings-update-error {\r\n margin: 0;\r\n overflow-wrap: anywhere;\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-update-summary {\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-update-error {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-update-progress {\r\n width: 100%;\r\n height: 8px;\r\n accent-color: var(--settings-focus);\r\n}\r\n\r\n.settings-update-progress-detail {\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n/* Release notes scroll with the page; a scroller inside a scroller traps the wheel. */\r\n.settings-update-notes-section {\r\n min-width: 0;\r\n margin-top: 24px;\r\n padding-top: 24px;\r\n border-top: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-update-notes-section:empty {\r\n display: none;\r\n}\r\n\r\n.settings-update-notes {\r\n display: grid;\r\n min-width: 0;\r\n gap: 12px;\r\n color: var(--settings-muted);\r\n font-size: 14px;\r\n line-height: 22px;\r\n overflow-wrap: anywhere;\r\n}\r\n\r\n.settings-update-notes > :first-child {\r\n margin-top: 0;\r\n}\r\n\r\n.settings-update-notes > :last-child {\r\n margin-bottom: 0;\r\n}\r\n\r\n.settings-update-notes h1,\r\n.settings-update-notes h2,\r\n.settings-update-notes h3,\r\n.settings-update-notes h4,\r\n.settings-update-notes h5,\r\n.settings-update-notes h6 {\r\n margin: 6px 0 0;\r\n color: var(--settings-text);\r\n font-weight: 600;\r\n}\r\n\r\n.settings-update-notes h1 {\r\n font-size: 18px;\r\n line-height: 26px;\r\n}\r\n\r\n.settings-update-notes h2 {\r\n font-size: 17px;\r\n line-height: 24px;\r\n}\r\n\r\n.settings-update-notes h3,\r\n.settings-update-notes h4,\r\n.settings-update-notes h5,\r\n.settings-update-notes h6 {\r\n font-size: 14px;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-update-notes p,\r\n.settings-update-notes ul,\r\n.settings-update-notes ol,\r\n.settings-update-notes pre,\r\n.settings-update-notes blockquote {\r\n margin: 0;\r\n}\r\n\r\n.settings-update-notes ul,\r\n.settings-update-notes ol {\r\n padding-left: 24px;\r\n}\r\n\r\n.settings-update-notes li {\r\n padding-left: 4px;\r\n}\r\n\r\n.settings-update-notes li::marker {\r\n color: var(--settings-muted);\r\n font-size: 0.85em;\r\n}\r\n\r\n.settings-update-notes li + li {\r\n margin-top: 14px;\r\n}\r\n\r\n.settings-update-notes .release-note-translation {\r\n display: block;\r\n margin-top: 3px;\r\n color: var(--settings-muted);\r\n font-size: 13px;\r\n line-height: 20px;\r\n}\r\n\r\n.settings-update-notes blockquote {\r\n padding: 8px 12px;\r\n color: var(--settings-muted);\r\n border-left: 3px solid var(--settings-focus);\r\n background: var(--settings-surface);\r\n}\r\n\r\n.settings-update-notes hr {\r\n width: 100%;\r\n margin: 2px 0;\r\n border: 0;\r\n border-top: 1px solid var(--settings-divider);\r\n}\r\n\r\n.settings-update-notes strong {\r\n color: var(--settings-text);\r\n font-weight: 600;\r\n}\r\n\r\n.settings-update-notes a {\r\n color: var(--settings-focus);\r\n text-decoration: none;\r\n}\r\n\r\n.settings-update-notes a:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.settings-update-notes code {\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n font-size: 12px;\r\n}\r\n\r\n.settings-update-notes :not(pre) > code {\r\n padding: 1px 5px;\r\n background: var(--settings-surface);\r\n border-radius: 4px;\r\n}\r\n\r\n.settings-update-notes pre {\r\n min-width: 0;\r\n max-width: 100%;\r\n padding: 10px 12px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n background: var(--settings-inset);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-update-notes pre code {\r\n line-height: 18px;\r\n white-space: pre-wrap;\r\n}\r\n\r\n/* Manual update sits directly under the status panel, not behind a disclosure:\r\n automatic updates can fail for machine-local reasons and this is the way out. */\r\n.settings-update-controls {\r\n display: grid;\r\n min-width: 0;\r\n gap: 10px;\r\n margin-top: 24px;\r\n}\r\n\r\n.settings-update-manual-title {\r\n color: var(--settings-text);\r\n font-size: 15px;\r\n font-weight: 600;\r\n line-height: 22px;\r\n}\r\n\r\n.settings-update-manual {\r\n display: grid;\r\n min-width: 0;\r\n gap: 8px;\r\n}\r\n\r\n.settings-update-manual[hidden] {\r\n display: none;\r\n}\r\n\r\n.settings-update-manual-description {\r\n margin: 0;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n line-height: 18px;\r\n}\r\n\r\n.settings-update-manual-description.is-fallback {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-update-command {\r\n display: flex;\r\n align-items: stretch;\r\n min-width: 0;\r\n overflow: hidden;\r\n border: 1px solid var(--settings-border);\r\n border-radius: 6px;\r\n}\r\n\r\n.settings-update-command code {\r\n min-width: 0;\r\n flex: 1;\r\n padding: 9px 12px;\r\n overflow-x: auto;\r\n color: var(--settings-text);\r\n font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;\r\n font-size: 12px;\r\n line-height: 20px;\r\n white-space: nowrap;\r\n}\r\n\r\n.settings-update-command__copy {\r\n display: inline-flex;\r\n align-items: center;\r\n flex: none;\r\n gap: 6px;\r\n padding: 0 12px;\r\n color: var(--settings-muted);\r\n font-size: 12px;\r\n background: transparent;\r\n border: 0;\r\n border-left: 1px solid var(--settings-border);\r\n cursor: pointer;\r\n}\r\n\r\n.settings-update-command__copy:hover {\r\n color: var(--settings-text);\r\n background: var(--settings-hover);\r\n}\r\n\r\n.settings-update-command__copy:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: -2px;\r\n}\r\n\r\n.settings-update-actions {\r\n display: flex;\r\n align-items: center;\r\n min-width: 0;\r\n gap: 12px;\r\n flex-wrap: wrap;\r\n}\r\n\r\n.settings-command-button,\r\n.settings-update-link {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex: none;\r\n width: max-content;\r\n max-width: 100%;\r\n min-height: 30px;\r\n gap: 6px;\r\n padding: 5px 10px;\r\n white-space: nowrap;\r\n color: var(--settings-primary-text);\r\n font: inherit;\r\n font-size: 12px;\r\n text-decoration: none;\r\n background: var(--settings-primary);\r\n border: 1px solid var(--settings-primary);\r\n border-radius: 7px;\r\n cursor: pointer;\r\n}\r\n\r\n.settings-command-button--secondary,\r\n.settings-update-link {\r\n color: var(--settings-text);\r\n background: var(--settings-panel);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-command-button:hover:not(:disabled) {\r\n background: var(--settings-primary-hover);\r\n border-color: var(--settings-primary-hover);\r\n}\r\n\r\n.settings-command-button--secondary:hover:not(:disabled),\r\n.settings-update-link:hover {\r\n background: var(--settings-hover);\r\n border-color: var(--settings-border);\r\n}\r\n\r\n.settings-command-button--danger {\r\n color: #f87171;\r\n}\r\n\r\n.settings-command-button--danger:hover:not(:disabled) {\r\n color: #fecaca;\r\n background: rgb(127 29 29 / 24%);\r\n border-color: rgb(248 113 113 / 45%);\r\n}\r\n\r\n.settings-command-button:disabled {\r\n cursor: default;\r\n opacity: 0.45;\r\n}\r\n\r\n.settings-command-button:disabled,\r\n.settings-command-button[aria-disabled="true"] {\r\n opacity: 0.55;\r\n cursor: not-allowed;\r\n filter: none;\r\n}\r\n\r\n.settings-command-button:focus-visible,\r\n.settings-update-link:focus-visible {\r\n outline: 2px solid var(--settings-focus);\r\n outline-offset: 2px;\r\n}\r\n\r\n.codexhost-settings-icon {\r\n display: block;\r\n flex: none;\r\n stroke: currentColor;\r\n}\r\n\r\n@media (max-width: 720px) {\r\n .codexhost-settings-dialog {\r\n width: calc(100vw - 16px);\r\n height: calc(100vh - 16px);\r\n border-radius: 10px;\r\n }\r\n\r\n .settings-layout {\r\n grid-template-columns: minmax(0, 1fr);\r\n grid-template-rows: auto minmax(0, 1fr);\r\n }\r\n\r\n .settings-session-import-row {\r\n grid-template-columns: minmax(0, 1fr);\r\n }\r\n\r\n .settings-session-import-row__action {\r\n align-items: flex-start;\r\n }\r\n\r\n .settings-sidebar {\r\n border-right: 0;\r\n border-bottom: 1px solid var(--settings-border);\r\n }\r\n\r\n .settings-header {\r\n height: 56px;\r\n padding-inline: 14px;\r\n }\r\n\r\n .settings-sidebar {\r\n padding-top: 20px;\r\n }\r\n\r\n .settings-nav {\r\n flex: none;\r\n flex-direction: row;\r\n gap: 4px;\r\n padding: 7px 8px 8px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n }\r\n\r\n .settings-nav-section-label {\r\n display: none;\r\n }\r\n\r\n .settings-nav-button {\r\n width: auto;\r\n min-width: max-content;\r\n min-height: 34px;\r\n grid-template-columns: 16px auto;\r\n border-radius: 10px;\r\n }\r\n\r\n .settings-nav-star-link {\r\n margin-top: 0;\r\n }\r\n\r\n .settings-page__content {\r\n width: calc(100% - 40px);\r\n }\r\n\r\n .settings-page__content {\r\n padding-top: 32px;\r\n padding-bottom: 32px;\r\n }\r\n\r\n .settings-section-label {\r\n padding-bottom: 20px;\r\n font-size: 20px;\r\n line-height: 26px;\r\n }\r\n\r\n .settings-update-metadata {\r\n grid-template-columns: minmax(0, 1fr);\r\n gap: 16px;\r\n }\r\n\r\n .settings-status-row {\r\n grid-template-columns: minmax(0, 1fr) auto;\r\n gap: 16px;\r\n }\r\n\r\n .settings-account-header,\r\n .settings-connection-page-header {\r\n flex-direction: column;\r\n }\r\n\r\n .settings-account-header > .settings-command-button,\r\n .settings-connection-page-header > .settings-command-button {\r\n width: 100%;\r\n }\r\n\r\n .settings-connections-layout {\r\n grid-template-columns: minmax(0, 1fr);\r\n }\r\n\r\n .settings-connection-inspector {\r\n position: static;\r\n }\r\n\r\n .settings-status-row__detail {\r\n grid-column: 1 / -1;\r\n margin: -8px 0 0 58px;\r\n }\r\n}\r\n\r\n@media (forced-colors: active) {\r\n :host {\r\n --settings-bg: Canvas;\r\n --settings-sidebar: Canvas;\r\n --settings-panel: Canvas;\r\n --settings-surface: Canvas;\r\n --settings-surface-hover: Highlight;\r\n --settings-inset: Canvas;\r\n --settings-text: CanvasText;\r\n --settings-muted: GrayText;\r\n --settings-subtle: GrayText;\r\n --settings-border: ButtonBorder;\r\n --settings-divider: ButtonBorder;\r\n --settings-hover: Highlight;\r\n --settings-active: Highlight;\r\n --settings-focus: Highlight;\r\n --settings-primary: ButtonFace;\r\n --settings-primary-hover: Highlight;\r\n --settings-primary-text: ButtonText;\r\n --settings-warning: CanvasText;\r\n --settings-warning-bg: Canvas;\r\n --settings-warning-border: ButtonBorder;\r\n --settings-danger: CanvasText;\r\n --settings-danger-bg: Canvas;\r\n --settings-danger-border: ButtonBorder;\r\n --settings-success: CanvasText;\r\n }\r\n}\r\n\r\n@media (prefers-reduced-motion: reduce) {\r\n *,\r\n *::before,\r\n *::after {\r\n scroll-behavior: auto !important;\r\n transition-duration: 0s !important;\r\n }\r\n}\r\n\r\n/* Harness Mix: Model Configuration & One-click Install */\r\n.settings-model-config-panel {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n padding: 14px;\r\n margin-top: 14px;\r\n border-radius: 8px;\r\n background: var(--settings-surface);\r\n border: 1px solid var(--settings-border);\r\n}\r\n\r\n.settings-model-config-head {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n}\r\n\r\n.settings-model-config-title {\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: var(--settings-text);\r\n}\r\n\r\n.settings-model-config-description {\r\n font-size: 11px;\r\n color: var(--settings-muted);\r\n margin: 0;\r\n}\r\n\r\n.settings-model-config-loading,\r\n.settings-model-config-empty {\r\n font-size: 12px;\r\n color: var(--settings-muted);\r\n padding: 8px 0;\r\n}\r\n\r\n.settings-model-config-form {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 12px;\r\n margin-top: 4px;\r\n}\r\n\r\n.settings-model-config-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n}\r\n\r\n.settings-model-config-label {\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--settings-muted);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.settings-model-config-select {\r\n height: 32px;\r\n padding: 0 10px;\r\n border-radius: 6px;\r\n border: 1px solid var(--settings-border);\r\n background: var(--settings-panel);\r\n color: var(--settings-text);\r\n font-size: 12px;\r\n outline: none;\r\n}\r\n\r\n.settings-model-config-select:focus {\r\n border-color: var(--settings-primary);\r\n}\r\n\r\n.settings-model-config-actions {\r\n display: flex;\r\n align-items: center;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n margin-top: 6px;\r\n}\r\n\r\n.settings-model-config-feedback {\r\n font-size: 12px;\r\n font-weight: 500;\r\n}\r\n\r\n.settings-feedback-success {\r\n color: var(--settings-success);\r\n}\r\n\r\n.settings-feedback-error {\r\n color: var(--settings-danger);\r\n}\r\n\r\n.settings-feedback-info {\r\n color: var(--settings-primary);\r\n}\r\n\r\n.settings-install-command-box {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n min-width: 0;\r\n margin: 0;\r\n}\r\n\r\n.settings-install-command-label {\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-install-command-row {\r\n display: flex;\r\n align-items: center;\r\n background: var(--settings-inset);\r\n padding: 8px 12px;\r\n border-radius: 6px;\r\n border: 1px solid var(--settings-border);\r\n min-width: 0;\r\n overflow-x: auto;\r\n}\r\n\r\n.settings-install-command-row code {\r\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\r\n font-size: 12px;\r\n line-height: 18px;\r\n color: var(--settings-text);\r\n user-select: all;\r\n white-space: pre-wrap;\r\n word-break: break-all;\r\n}\r\n\r\n.settings-install-actions {\r\n display: grid;\r\n grid-template-columns: minmax(0, 1fr);\r\n gap: 8px;\r\n margin-top: 4px;\r\n}\r\n\r\n.settings-install-actions .settings-command-button {\r\n width: 100%;\r\n justify-content: center;\r\n}\r\n\r\n.settings-install-feedback {\r\n font-size: 12px;\r\n font-weight: 500;\r\n line-height: 18px;\r\n margin-top: 2px;\r\n overflow-wrap: anywhere;\r\n}\r\n\r\n.settings-install-manual-card {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n background: var(--settings-inset);\r\n padding: 12px 14px;\r\n border-radius: 8px;\r\n border: 1px solid var(--settings-border);\r\n margin-top: 6px;\r\n margin-bottom: 4px;\r\n}\r\n\r\n.settings-install-manual-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--settings-accent, #10a37f);\r\n background: var(--settings-accent-subtle, rgba(16, 163, 127, 0.1));\r\n padding: 2px 8px;\r\n border-radius: 4px;\r\n width: fit-content;\r\n}\r\n\r\n.settings-install-manual-notice {\r\n font-size: 12px;\r\n line-height: 18px;\r\n color: var(--settings-text);\r\n margin: 0;\r\n}\r\n\r\n.settings-install-steps {\r\n margin: 0;\r\n padding-left: 18px;\r\n font-size: 12px;\r\n line-height: 20px;\r\n color: var(--settings-muted);\r\n}\r\n\r\n.settings-install-steps li {\r\n margin-bottom: 2px;\r\n}\r\n';
26130
26553
 
26131
26554
  // src/native-ui/renderer-extension/src/settings/accounts.css
26132
- var accounts_default = '.settings-harness-accounts {\n margin-top: 32px;\n}\n\n.settings-harness-accounts__title {\n margin: 0 0 16px;\n font-size: 14px;\n font-weight: 500;\n}\n\n.settings-harness-account__identity {\n min-width: 0;\n}\n\n.settings-harness-account__identity > .settings-account-email {\n display: block;\n max-width: 24ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-harness-account__logo {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n flex: none;\n}\n\n.settings-harness-account {\n display: grid;\n grid-template-columns: minmax(180px, 1fr) minmax(0, 2fr);\n align-items: center;\n gap: 24px;\n padding: 24px;\n}\n\n.settings-harness-account + .settings-harness-account {\n border-top: 1px solid var(--settings-border);\n}\n\n.settings-harness-account > div {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n@media (max-width: 700px) {\n .settings-harness-account {\n grid-template-columns: minmax(0, 1fr);\n padding: 16px;\n }\n}\n\n.settings-account-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 20px;\n}\n\n.settings-account-eyebrow {\n margin: 0 0 8px;\n color: var(--settings-muted);\n font-size: 11px;\n letter-spacing: 0.13em;\n}\n\n.settings-account-header > :first-child {\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.settings-account-header > .settings-command-button {\n flex: none;\n white-space: nowrap;\n margin-top: 20px;\n min-height: 36px;\n padding: 8px 12px;\n border-radius: 7px;\n}\n\n.settings-account-header .settings-section-label {\n margin: 0;\n padding: 0;\n font-size: 27px;\n line-height: 1.4;\n font-weight: 650;\n letter-spacing: -0.035em;\n}\n.settings-account-header .settings-page-description {\n margin: 8px 0 0;\n font-size: 13px;\n}\n\n.settings-account-status {\n margin: 0;\n color: var(--settings-muted);\n font-size: 12px;\n}\n.settings-account-status:empty {\n display: none;\n}\n\n.settings-account-help-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-top: 20px;\n flex-wrap: wrap;\n}\n.settings-account-task-hint {\n display: flex;\n align-items: flex-start;\n gap: 9px;\n margin: 0;\n color: var(--settings-muted);\n font-size: 12px;\n flex: 1 1 280px;\n}\n.settings-account-task-hint svg {\n flex: none;\n margin-top: 1px;\n}\n.settings-account-help-button {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 8px 12px;\n color: var(--settings-muted);\n font-size: 12px;\n background: transparent;\n border: 0;\n border-radius: 7px;\n cursor: pointer;\n}\n.settings-account-help-button:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n.settings-account-device-code-note {\n margin: 12px 0 0;\n font-size: 12px;\n padding: 10px 12px;\n color: var(--settings-warning);\n background: var(--settings-warning-bg);\n border: 1px solid var(--settings-warning-border);\n border-radius: 8px;\n}\n\n.settings-account-toolbar {\n margin-top: 27px;\n padding: 18px 0;\n border-top: 1px solid var(--settings-border);\n display: flex;\n align-items: center;\n gap: 14px;\n flex-wrap: wrap;\n}\n.settings-account-count {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n white-space: nowrap;\n}\n.settings-account-count > :last-child {\n color: var(--settings-muted);\n font-variant-numeric: tabular-nums;\n}\n.settings-account-search {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--settings-muted);\n margin-right: auto;\n min-width: 0;\n max-width: 100%;\n}\n.settings-account-search svg {\n flex: none;\n}\n.settings-account-toolbar input {\n min-width: 80px;\n width: 150px;\n max-width: 100%;\n padding: 5px 0;\n color: var(--settings-text);\n background: transparent;\n border: 0;\n font-size: 13px;\n}\n.settings-account-toolbar input::placeholder {\n color: var(--settings-muted);\n}\n.settings-account-display-controls {\n display: flex;\n padding: 3px;\n border: 1px solid var(--settings-border);\n border-radius: 7px;\n background: var(--settings-inset);\n}\n.settings-account-display-controls button {\n padding: 4px 10px;\n color: var(--settings-muted);\n background: transparent;\n border: 0;\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n}\n.settings-account-display-controls button:hover {\n color: var(--settings-text);\n}\n.settings-account-display-controls button[aria-pressed="true"] {\n color: var(--settings-text);\n background: var(--settings-active);\n}\n\n.settings-account-list {\n --account-border: light-dark(#e2e2e8, #36363b);\n --account-muted: light-dark(#676773, #a5a5af);\n border: 1px solid var(--account-border);\n border-radius: 11px;\n overflow: hidden;\n container-type: inline-size;\n}\n.settings-account-table {\n width: 100%;\n table-layout: fixed;\n border-collapse: collapse;\n font-size: 12px;\n}\n.settings-account-table th {\n padding: 13px 20px;\n color: var(--account-muted);\n background: light-dark(#f8f8fa, #202024);\n font-size: 11px;\n font-weight: 500;\n text-align: left;\n}\n.settings-account-table th:nth-child(1) {\n width: 32%;\n}\n.settings-account-table th:nth-child(2) {\n width: 38%;\n}\n.settings-account-table th:nth-child(3) {\n width: 12%;\n}\n.settings-account-table th:nth-child(4) {\n width: 18%;\n text-align: right;\n}\n.settings-account-table td {\n padding: 19px 20px;\n vertical-align: middle;\n border-top: 1px solid var(--settings-divider);\n}\n.settings-account-row {\n background: light-dark(#ffffff, #232326);\n}\n.settings-account-row:hover {\n background: light-dark(#f7f7fa, #26262a);\n}\n.settings-account-row__person {\n display: grid;\n grid-template-columns: 34px minmax(0, 1fr);\n align-items: center;\n gap: 11px;\n min-width: 0;\n}\n.settings-account-row__mark {\n display: grid;\n place-items: center;\n width: 34px;\n height: 34px;\n color: light-dark(#67558d, #c3baff);\n background: light-dark(#f0ecf7, #353044);\n border: 1px solid light-dark(#d9d0e6, #4d435f);\n border-radius: 10px;\n}\n.settings-account-row__identity {\n min-width: 0;\n}\n.settings-account-title {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n.settings-account-email {\n min-width: 0;\n overflow: hidden;\n font-size: 13px;\n font-weight: 550;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.settings-account-metadata {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 7px;\n margin-top: 4px;\n color: var(--settings-muted);\n}\n.settings-account-domain {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.settings-account-plan-separator {\n flex: none;\n}\n.settings-account-plan {\n flex: none;\n padding: 1px 6px;\n color: var(--settings-muted);\n border: 1px solid var(--settings-border);\n border-radius: 5px;\n font-size: 11px;\n white-space: nowrap;\n}\n.settings-account-plan--highlighted {\n color: light-dark(#654f91, #c8bfff);\n background: light-dark(#f2edf9, #a99bff18);\n border-color: light-dark(#d9ccea, #a99bff52);\n font-weight: 600;\n}\n.settings-account-active {\n flex: none;\n padding: 2px 7px;\n color: light-dark(#66548e, #bdb4ff);\n background: light-dark(#f4f0fb, #aca0ff12);\n border: 1px solid light-dark(#dfd5f1, #aca0ff24);\n border-radius: 5px;\n font-size: 11px;\n white-space: nowrap;\n}\n\n.settings-account-usage {\n display: grid;\n gap: 14px;\n max-width: 380px;\n}\n.settings-account-usage__meter {\n display: grid;\n grid-template-columns: 48px minmax(36px, 1fr) 96px;\n align-items: center;\n gap: 3px 10px;\n}\n:host([lang="zh-CN"]) .settings-account-usage__meter {\n grid-template-columns: 48px minmax(36px, 1fr) 72px;\n}\n\n.settings-account-usage__title {\n color: light-dark(#5d5d68, #c3c3cd);\n font-size: 12px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.settings-account-usage__percent {\n display: flex;\n align-items: baseline;\n justify-content: flex-end;\n gap: 4px;\n font-size: 14px;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n.settings-account-usage__value-label {\n color: var(--settings-muted);\n font-size: 11px;\n font-weight: 400;\n}\n.settings-account-usage__percent--warn {\n color: var(--settings-warning);\n}\n.settings-account-usage__percent--hot {\n color: var(--settings-danger);\n}\n.settings-account-usage__bar {\n height: 4px;\n overflow: hidden;\n background: light-dark(#e3e1e8, #3c3c43);\n border-radius: 4px;\n}\n.settings-account-usage__bar > span {\n display: block;\n height: 100%;\n background: light-dark(#81769e, #9993b8);\n border-radius: inherit;\n}\n.settings-account-usage__bar--warn > span {\n background: var(--settings-warning);\n}\n.settings-account-usage__bar--hot > span {\n background: var(--settings-danger);\n}\n.settings-account-usage__sub {\n grid-column: 2 / -1;\n color: var(--account-muted);\n font-size: 11px;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.settings-account-usage__message,\n.settings-account-unknown {\n color: var(--settings-muted);\n}\n.settings-account-usage > button {\n justify-self: start;\n}\n.settings-account-actions {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n}\n.settings-account-action {\n padding: 8px 10px;\n min-height: 36px;\n font-size: 12px;\n color: var(--settings-text);\n background: transparent;\n border: 1px solid transparent;\n border-radius: 7px;\n white-space: nowrap;\n cursor: pointer;\n}\n.settings-account-action:hover {\n background: var(--settings-hover);\n}\n.settings-account-action:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.settings-account-actions .settings-account-delete {\n color: var(--settings-muted);\n}\n.settings-account-actions .settings-account-delete:hover,\n.settings-account-actions .settings-account-delete:focus-visible {\n color: var(--settings-danger);\n background: var(--settings-danger-bg);\n}\n.settings-account-mobile-label {\n display: none;\n}\n.settings-account-reset-summary {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n min-height: 32px;\n padding: 3px 0;\n font-size: 12px;\n white-space: nowrap;\n color: var(--settings-text);\n background: transparent;\n border: 0;\n border-radius: 5px;\n cursor: pointer;\n}\n.settings-account-reset-summary:hover {\n background: var(--settings-hover);\n}\n.settings-account-reset-summary[aria-expanded="true"] > svg:last-child {\n transform: rotate(90deg);\n}\n.settings-account-details-row > td {\n background: var(--settings-inset);\n}\n.settings-account-reset-details {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n flex-wrap: wrap;\n}\n.settings-account-reset-details strong {\n font-size: 12px;\n}\n.settings-account-reset-expiry {\n margin: 6px 0;\n color: var(--settings-muted);\n font-size: 11px;\n}\n.settings-account-reset-expiry.is-warn {\n color: var(--settings-warning);\n}\n.settings-account-reset-expiry.is-hot {\n color: var(--settings-danger);\n}\n.settings-account-reset-list {\n margin: 8px 0 0;\n padding: 0;\n list-style: none;\n color: var(--settings-muted);\n font-size: 11px;\n}\n.settings-account-reset-list li + li {\n margin-top: 4px;\n}\n.settings-account-empty {\n text-align: center;\n color: var(--settings-muted);\n}\n.settings-account-verification {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n color: var(--settings-muted);\n}\n.settings-account-verification a {\n color: var(--settings-focus);\n overflow-wrap: anywhere;\n}\n.settings-account-verification code {\n padding: 5px 8px;\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 600;\n letter-spacing: 0.08em;\n background: var(--settings-inset);\n border-radius: 6px;\n}\n.settings-account-list :focus-visible,\n.settings-account-toolbar :focus-visible,\n.settings-account-help-button:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: -2px;\n}\n\n@container (min-width: 611px) and (max-width: 800px) {\n .settings-account-table th,\n .settings-account-table td {\n padding-left: 12px;\n padding-right: 12px;\n }\n .settings-account-table th:nth-child(1) {\n width: 30%;\n }\n .settings-account-table th:nth-child(2) {\n width: 37%;\n }\n .settings-account-table th:nth-child(4) {\n width: 21%;\n }\n}\n\n@container (max-width: 610px) {\n .settings-account-table,\n .settings-account-table tbody {\n display: block;\n }\n .settings-account-table thead {\n display: none;\n }\n .settings-account-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n padding: 16px;\n gap: 12px;\n border-bottom: 1px solid var(--settings-divider);\n }\n .settings-account-table .settings-account-row > td {\n padding: 0;\n border: 0;\n }\n .settings-account-row > td:nth-child(1),\n .settings-account-row > td:nth-child(2) {\n grid-column: 1 / -1;\n }\n .settings-account-row > td:nth-child(3) {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .settings-account-mobile-label {\n display: inline;\n color: var(--settings-muted);\n font-size: 11px;\n }\n .settings-account-usage {\n max-width: none;\n }\n .settings-account-table tr:not(.settings-account-row),\n .settings-account-table tr:not(.settings-account-row) > td {\n display: block;\n }\n}\n\n@media (forced-colors: active) {\n .settings-account-usage__bar {\n border: 1px solid CanvasText;\n }\n .settings-account-usage__bar > span {\n background: Highlight;\n }\n}\n';
26555
+ var accounts_default = '.settings-harness-accounts {\n margin-top: 32px;\n}\n\n.settings-harness-accounts__title {\n margin: 0 0 16px;\n font-size: 14px;\n font-weight: 500;\n}\n\n.settings-harness-account__identity {\n min-width: 0;\n}\n\n.settings-harness-account__identity > .settings-account-email {\n display: block;\n max-width: 24ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-harness-account__logo {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n flex: none;\n}\n\n.settings-harness-account {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 20px;\n padding: 20px 24px;\n}\n\n.settings-harness-account > .settings-account-row__person {\n flex: 1 1 280px;\n min-width: 0;\n}\n\n.settings-harness-account > .settings-account-usage {\n flex: 1 1 220px;\n min-width: 0;\n}\n\n.settings-harness-account > .settings-harness-account__actions {\n flex: 0 0 auto;\n}\n\n.settings-harness-account__badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 500;\n line-height: 16px;\n}\n\n.settings-harness-account__badge--ready {\n background: rgba(16, 185, 129, 0.12);\n color: #10b981;\n border: 1px solid rgba(16, 185, 129, 0.28);\n}\n\n.settings-harness-account__badge--unconfigured {\n background: rgba(245, 158, 11, 0.12);\n color: #f59e0b;\n border: 1px solid rgba(245, 158, 11, 0.28);\n}\n\n.settings-harness-account__badge--not_installed {\n background: rgba(156, 163, 175, 0.12);\n color: var(--settings-muted);\n border: 1px solid rgba(156, 163, 175, 0.25);\n}\n\n.settings-harness-account__config-hint {\n margin-top: 6px;\n font-size: 11px;\n color: var(--settings-muted);\n display: flex;\n align-items: center;\n gap: 4px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.settings-harness-account__config-hint code {\n font-family: ui-monospace, Consolas, monospace;\n font-size: 11px;\n background: var(--settings-surface);\n border: 1px solid var(--settings-border);\n padding: 1px 5px;\n border-radius: 4px;\n}\n\n.settings-harness-account__actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.settings-harness-account__login-btn {\n font-size: 12px;\n padding: 6px 12px;\n white-space: nowrap;\n}\n\n.settings-harness-account + .settings-harness-account {\n border-top: 1px solid var(--settings-border);\n}\n\n.settings-harness-account > div {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n@media (max-width: 700px) {\n .settings-harness-account {\n grid-template-columns: minmax(0, 1fr);\n padding: 16px;\n }\n}\n\n.settings-account-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 20px;\n}\n\n.settings-account-eyebrow {\n margin: 0 0 8px;\n color: var(--settings-muted);\n font-size: 11px;\n letter-spacing: 0.13em;\n}\n\n.settings-account-header > :first-child {\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.settings-account-header > .settings-command-button {\n flex: none;\n white-space: nowrap;\n margin-top: 20px;\n min-height: 36px;\n padding: 8px 12px;\n border-radius: 7px;\n}\n\n.settings-account-header .settings-section-label {\n margin: 0;\n padding: 0;\n font-size: 27px;\n line-height: 1.4;\n font-weight: 650;\n letter-spacing: -0.035em;\n}\n.settings-account-header .settings-page-description {\n margin: 8px 0 0;\n font-size: 13px;\n}\n\n.settings-account-status {\n margin: 0;\n color: var(--settings-muted);\n font-size: 12px;\n}\n.settings-account-status:empty {\n display: none;\n}\n\n.settings-account-help-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-top: 20px;\n flex-wrap: wrap;\n}\n.settings-account-task-hint {\n display: flex;\n align-items: flex-start;\n gap: 9px;\n margin: 0;\n color: var(--settings-muted);\n font-size: 12px;\n flex: 1 1 280px;\n}\n.settings-account-task-hint svg {\n flex: none;\n margin-top: 1px;\n}\n.settings-account-help-button {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 8px 12px;\n color: var(--settings-muted);\n font-size: 12px;\n background: transparent;\n border: 0;\n border-radius: 7px;\n cursor: pointer;\n}\n.settings-account-help-button:hover {\n color: var(--settings-text);\n background: var(--settings-hover);\n}\n.settings-account-device-code-note {\n margin: 12px 0 0;\n font-size: 12px;\n padding: 10px 12px;\n color: var(--settings-warning);\n background: var(--settings-warning-bg);\n border: 1px solid var(--settings-warning-border);\n border-radius: 8px;\n}\n\n.settings-account-toolbar {\n margin-top: 27px;\n padding: 18px 0;\n border-top: 1px solid var(--settings-border);\n display: flex;\n align-items: center;\n gap: 14px;\n flex-wrap: wrap;\n}\n.settings-account-count {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n white-space: nowrap;\n}\n.settings-account-count > :last-child {\n color: var(--settings-muted);\n font-variant-numeric: tabular-nums;\n}\n.settings-account-search {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--settings-muted);\n margin-right: auto;\n min-width: 0;\n max-width: 100%;\n}\n.settings-account-search svg {\n flex: none;\n}\n.settings-account-toolbar input {\n min-width: 80px;\n width: 150px;\n max-width: 100%;\n padding: 5px 0;\n color: var(--settings-text);\n background: transparent;\n border: 0;\n font-size: 13px;\n}\n.settings-account-toolbar input::placeholder {\n color: var(--settings-muted);\n}\n.settings-account-display-controls {\n display: flex;\n padding: 3px;\n border: 1px solid var(--settings-border);\n border-radius: 7px;\n background: var(--settings-inset);\n}\n.settings-account-display-controls button {\n padding: 4px 10px;\n color: var(--settings-muted);\n background: transparent;\n border: 0;\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n}\n.settings-account-display-controls button:hover {\n color: var(--settings-text);\n}\n.settings-account-display-controls button[aria-pressed="true"] {\n color: var(--settings-text);\n background: var(--settings-active);\n}\n\n.settings-account-list {\n --account-border: light-dark(#e2e2e8, #36363b);\n --account-muted: light-dark(#676773, #a5a5af);\n border: 1px solid var(--account-border);\n border-radius: 11px;\n overflow: hidden;\n container-type: inline-size;\n}\n.settings-account-table {\n width: 100%;\n table-layout: fixed;\n border-collapse: collapse;\n font-size: 12px;\n}\n.settings-account-table th {\n padding: 13px 20px;\n color: var(--account-muted);\n background: light-dark(#f8f8fa, #202024);\n font-size: 11px;\n font-weight: 500;\n text-align: left;\n}\n.settings-account-table th:nth-child(1) {\n width: 32%;\n}\n.settings-account-table th:nth-child(2) {\n width: 38%;\n}\n.settings-account-table th:nth-child(3) {\n width: 12%;\n}\n.settings-account-table th:nth-child(4) {\n width: 18%;\n text-align: right;\n}\n.settings-account-table td {\n padding: 19px 20px;\n vertical-align: middle;\n border-top: 1px solid var(--settings-divider);\n}\n.settings-account-row {\n background: light-dark(#ffffff, #232326);\n}\n.settings-account-row:hover {\n background: light-dark(#f7f7fa, #26262a);\n}\n.settings-account-row__person {\n display: grid;\n grid-template-columns: 34px minmax(0, 1fr);\n align-items: center;\n gap: 11px;\n min-width: 0;\n}\n.settings-account-row__mark {\n display: grid;\n place-items: center;\n width: 34px;\n height: 34px;\n color: light-dark(#67558d, #c3baff);\n background: light-dark(#f0ecf7, #353044);\n border: 1px solid light-dark(#d9d0e6, #4d435f);\n border-radius: 10px;\n}\n.settings-account-row__identity {\n min-width: 0;\n}\n.settings-account-title {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n.settings-account-email {\n min-width: 0;\n overflow: hidden;\n font-size: 13px;\n font-weight: 550;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.settings-account-metadata {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: 7px;\n margin-top: 4px;\n color: var(--settings-muted);\n}\n.settings-account-domain {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.settings-account-plan-separator {\n flex: none;\n}\n.settings-account-plan {\n flex: none;\n padding: 1px 6px;\n color: var(--settings-muted);\n border: 1px solid var(--settings-border);\n border-radius: 5px;\n font-size: 11px;\n white-space: nowrap;\n}\n.settings-account-plan--highlighted {\n color: light-dark(#654f91, #c8bfff);\n background: light-dark(#f2edf9, #a99bff18);\n border-color: light-dark(#d9ccea, #a99bff52);\n font-weight: 600;\n}\n.settings-account-active {\n flex: none;\n padding: 2px 7px;\n color: light-dark(#66548e, #bdb4ff);\n background: light-dark(#f4f0fb, #aca0ff12);\n border: 1px solid light-dark(#dfd5f1, #aca0ff24);\n border-radius: 5px;\n font-size: 11px;\n white-space: nowrap;\n}\n\n.settings-account-usage {\n display: grid;\n gap: 14px;\n max-width: 380px;\n}\n.settings-account-usage__meter {\n display: grid;\n grid-template-columns: 48px minmax(36px, 1fr) 96px;\n align-items: center;\n gap: 3px 10px;\n}\n:host([lang="zh-CN"]) .settings-account-usage__meter {\n grid-template-columns: 48px minmax(36px, 1fr) 72px;\n}\n\n.settings-account-usage__title {\n color: light-dark(#5d5d68, #c3c3cd);\n font-size: 12px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.settings-account-usage__percent {\n display: flex;\n align-items: baseline;\n justify-content: flex-end;\n gap: 4px;\n font-size: 14px;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n.settings-account-usage__value-label {\n color: var(--settings-muted);\n font-size: 11px;\n font-weight: 400;\n}\n.settings-account-usage__percent--warn {\n color: var(--settings-warning);\n}\n.settings-account-usage__percent--hot {\n color: var(--settings-danger);\n}\n.settings-account-usage__bar {\n height: 4px;\n overflow: hidden;\n background: light-dark(#e3e1e8, #3c3c43);\n border-radius: 4px;\n}\n.settings-account-usage__bar > span {\n display: block;\n height: 100%;\n background: light-dark(#81769e, #9993b8);\n border-radius: inherit;\n}\n.settings-account-usage__bar--warn > span {\n background: var(--settings-warning);\n}\n.settings-account-usage__bar--hot > span {\n background: var(--settings-danger);\n}\n.settings-account-usage__sub {\n grid-column: 2 / -1;\n color: var(--account-muted);\n font-size: 11px;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.settings-account-usage__message,\n.settings-account-unknown {\n color: var(--settings-muted);\n}\n.settings-account-usage > button {\n justify-self: start;\n}\n.settings-account-actions {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n}\n.settings-account-action {\n padding: 8px 10px;\n min-height: 36px;\n font-size: 12px;\n color: var(--settings-text);\n background: transparent;\n border: 1px solid transparent;\n border-radius: 7px;\n white-space: nowrap;\n cursor: pointer;\n}\n.settings-account-action:hover {\n background: var(--settings-hover);\n}\n.settings-account-action:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.settings-account-actions .settings-account-delete {\n color: var(--settings-muted);\n}\n.settings-account-actions .settings-account-delete:hover,\n.settings-account-actions .settings-account-delete:focus-visible {\n color: var(--settings-danger);\n background: var(--settings-danger-bg);\n}\n.settings-account-mobile-label {\n display: none;\n}\n.settings-account-reset-summary {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n min-height: 32px;\n padding: 3px 0;\n font-size: 12px;\n white-space: nowrap;\n color: var(--settings-text);\n background: transparent;\n border: 0;\n border-radius: 5px;\n cursor: pointer;\n}\n.settings-account-reset-summary:hover {\n background: var(--settings-hover);\n}\n.settings-account-reset-summary[aria-expanded="true"] > svg:last-child {\n transform: rotate(90deg);\n}\n.settings-account-details-row > td {\n background: var(--settings-inset);\n}\n.settings-account-reset-details {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n flex-wrap: wrap;\n}\n.settings-account-reset-details strong {\n font-size: 12px;\n}\n.settings-account-reset-expiry {\n margin: 6px 0;\n color: var(--settings-muted);\n font-size: 11px;\n}\n.settings-account-reset-expiry.is-warn {\n color: var(--settings-warning);\n}\n.settings-account-reset-expiry.is-hot {\n color: var(--settings-danger);\n}\n.settings-account-reset-list {\n margin: 8px 0 0;\n padding: 0;\n list-style: none;\n color: var(--settings-muted);\n font-size: 11px;\n}\n.settings-account-reset-list li + li {\n margin-top: 4px;\n}\n.settings-account-empty {\n text-align: center;\n color: var(--settings-muted);\n}\n.settings-account-verification {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n color: var(--settings-muted);\n}\n.settings-account-verification a {\n color: var(--settings-focus);\n overflow-wrap: anywhere;\n}\n.settings-account-verification code {\n padding: 5px 8px;\n color: var(--settings-text);\n font-size: 15px;\n font-weight: 600;\n letter-spacing: 0.08em;\n background: var(--settings-inset);\n border-radius: 6px;\n}\n.settings-account-list :focus-visible,\n.settings-account-toolbar :focus-visible,\n.settings-account-help-button:focus-visible {\n outline: 2px solid var(--settings-focus);\n outline-offset: -2px;\n}\n\n@container (min-width: 611px) and (max-width: 800px) {\n .settings-account-table th,\n .settings-account-table td {\n padding-left: 12px;\n padding-right: 12px;\n }\n .settings-account-table th:nth-child(1) {\n width: 30%;\n }\n .settings-account-table th:nth-child(2) {\n width: 37%;\n }\n .settings-account-table th:nth-child(4) {\n width: 21%;\n }\n}\n\n@container (max-width: 610px) {\n .settings-account-table,\n .settings-account-table tbody {\n display: block;\n }\n .settings-account-table thead {\n display: none;\n }\n .settings-account-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n padding: 16px;\n gap: 12px;\n border-bottom: 1px solid var(--settings-divider);\n }\n .settings-account-table .settings-account-row > td {\n padding: 0;\n border: 0;\n }\n .settings-account-row > td:nth-child(1),\n .settings-account-row > td:nth-child(2) {\n grid-column: 1 / -1;\n }\n .settings-account-row > td:nth-child(3) {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .settings-account-mobile-label {\n display: inline;\n color: var(--settings-muted);\n font-size: 11px;\n }\n .settings-account-usage {\n max-width: none;\n }\n .settings-account-table tr:not(.settings-account-row),\n .settings-account-table tr:not(.settings-account-row) > td {\n display: block;\n }\n}\n\n@media (forced-colors: active) {\n .settings-account-usage__bar {\n border: 1px solid CanvasText;\n }\n .settings-account-usage__bar > span {\n background: Highlight;\n }\n}\n';
26133
26556
 
26134
26557
  // src/native-ui/renderer-extension/src/settings/shell.ts
26135
26558
  var SETTINGS_SHELL_ATTRIBUTE = "data-codexhost-settings-shell";
@@ -26262,7 +26685,7 @@ ${accounts_default}`;
26262
26685
  let otherSectionAdded = false;
26263
26686
  appendNavigationSection(messages.generalSection);
26264
26687
  for (const definition of resolvedRegistry.pages) {
26265
- if (definition.id === "about" && !otherSectionAdded) {
26688
+ if ((definition.id === "updates" || definition.id === "about") && !otherSectionAdded) {
26266
26689
  appendNavigationSection(messages.otherSection);
26267
26690
  otherSectionAdded = true;
26268
26691
  }
@@ -26590,6 +27013,8 @@ ${accounts_default}`;
26590
27013
  const messages = rendererSettingsMessages(locale);
26591
27014
  const pages = [
26592
27015
  createConnectionsSettingsPage(messages, options.getConnectionDiagnostics ?? (() => null)),
27016
+ createAccountsSettingsPage(messages, options.getAccountClient ?? (() => null)),
27017
+ updatesPage(messages, options.getUpdateClient ?? (() => null)),
26593
27018
  aboutPage(messages)
26594
27019
  ];
26595
27020
  const nextShell = installRendererSettingsShell(pages, messages, ownerWindow.document);
@@ -26699,7 +27124,7 @@ ${accounts_default}`;
26699
27124
  return rendererUsageRefreshDelays[index] ?? rendererUsageRefreshDelays[0];
26700
27125
  }
26701
27126
  function externalAgentHasAccountCredits(agent) {
26702
- return agent === "codex" || agent === "grok" || agent === "claude-code";
27127
+ return agent === "codex" || agent === "grok" || agent === "claude-code" || agent === "antigravity";
26703
27128
  }
26704
27129
  function shouldRetryExternalThreadUsage(agent, usage, accountCredits = null) {
26705
27130
  if (usage === null) return true;
@@ -26989,6 +27414,17 @@ ${accounts_default}`;
26989
27414
  }) : [];
26990
27415
  return { agents, sessions, canDelegate: agents.some((agent) => agent.id === state.agent && agent.lead) };
26991
27416
  });
27417
+ const collabCards = installCollabCards({
27418
+ openThread: (threadId) => openRendererThread(threadId, { hostId: "local" }),
27419
+ reviewWorkspace: async (threadId) => {
27420
+ const client = modelClientForHost("local");
27421
+ return client?.reviewThreadWorkspace?.({ threadId }) ?? { patch: "", digest: "" };
27422
+ },
27423
+ applyWorkspace: async (threadId, digest) => {
27424
+ const client = modelClientForHost("local");
27425
+ return client?.applyThreadWorkspace?.({ threadId, digest }) ?? { patch: "", digest: "" };
27426
+ }
27427
+ });
26992
27428
  let connectionDiagnostics = null;
26993
27429
  const settingsLifecycle = installRendererSettingsLifecycle(window, {
26994
27430
  getUpdateClient: () => modelControl,
@@ -27218,13 +27654,39 @@ ${accounts_default}`;
27218
27654
  } catch {
27219
27655
  }
27220
27656
  };
27657
+ const refreshDraftExternalCredits = async (mounted) => {
27658
+ const state = controller.get(mounted.composer);
27659
+ if (state.agent === "codex" || state.phase !== "draft" || controller.isSubmissionPending(mounted.composer) || threadIdFromComposerModelTarget(mounted.modelTarget)) {
27660
+ return;
27661
+ }
27662
+ const hostId = mounted.hostId;
27663
+ const client = modelClientForHostFrom(modelControl, hostId ?? activeModelHostId());
27664
+ if (!client?.listHarnessAccounts) return;
27665
+ const harnessId = externalHarnessIds[state.agent];
27666
+ if (!harnessId) return;
27667
+ const generation = ++mounted.usageRequestGeneration;
27668
+ try {
27669
+ const result = await client.listHarnessAccounts();
27670
+ if (disposed || !mounted.composer.isConnected || mountedByComposer.get(mounted.composer) !== mounted || mounted.usageRequestGeneration !== generation || controller.get(mounted.composer).agent !== state.agent || controller.get(mounted.composer).phase !== "draft" || threadIdFromComposerModelTarget(mounted.modelTarget)) {
27671
+ return;
27672
+ }
27673
+ const match = result.accounts.find((a) => a.harnessId === harnessId);
27674
+ mounted.accountCredits = match?.credits ?? null;
27675
+ renderMounted(mounted);
27676
+ } catch {
27677
+ }
27678
+ };
27221
27679
  const refreshThreadUsage = async (mounted, refresh) => {
27222
27680
  const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
27223
- if (!threadId && controller.get(mounted.composer).agent === "codex") {
27224
- await refreshDraftCodexUsage(mounted);
27681
+ if (!threadId) {
27682
+ if (controller.get(mounted.composer).agent === "codex") {
27683
+ await refreshDraftCodexUsage(mounted);
27684
+ } else {
27685
+ await refreshDraftExternalCredits(mounted);
27686
+ }
27225
27687
  return;
27226
27688
  }
27227
- if (!threadId || !modelControl) {
27689
+ if (!modelControl) {
27228
27690
  mounted.usage = null;
27229
27691
  mounted.accountCredits = null;
27230
27692
  usageRefreshAttempts.delete(mounted.composer);
@@ -27311,6 +27773,7 @@ ${accounts_default}`;
27311
27773
  const { agent, model, thinkingOptionId, permissionModeId } = restoredThreadOwnership(inspection);
27312
27774
  if (mounted.usageRequestGeneration === usageGeneration) {
27313
27775
  mounted.usage = inspection.owner === "external" ? inspection.usage ?? null : null;
27776
+ mounted.accountCredits = inspection.owner === "external" ? inspection.accountCredits ?? null : null;
27314
27777
  }
27315
27778
  const restored = controller.restore(
27316
27779
  mounted.composer,
@@ -28309,10 +28772,10 @@ ${accounts_default}`;
28309
28772
  if (!client?.inspectHarness) throw new Error("Harness inspect is unavailable");
28310
28773
  return client.inspectHarness({ harnessId: externalHarnessIds[agent] });
28311
28774
  },
28312
- async installHarness(hostId, agent) {
28775
+ async installHarness(hostId, agent, options2) {
28313
28776
  const client = modelClientForHost(hostId);
28314
28777
  if (!client?.installHarness) throw new Error("Harness install is unavailable");
28315
- const result = await client.installHarness({ harnessId: externalHarnessIds[agent] });
28778
+ const result = await client.installHarness({ harnessId: externalHarnessIds[agent], terminal: options2?.terminal });
28316
28779
  void refreshHarnessAvailabilityForHost(hostId, true, false, true).catch(() => void 0);
28317
28780
  return result;
28318
28781
  },
@@ -28801,6 +29264,7 @@ ${accounts_default}`;
28801
29264
  mutationObserver.disconnect();
28802
29265
  sidebarAgentIcons.dispose();
28803
29266
  harnessMentions.dispose();
29267
+ collabCards.dispose();
28804
29268
  settingsLifecycle.dispose();
28805
29269
  document.removeEventListener("beforeinput", onBeforeInput, true);
28806
29270
  document.removeEventListener("submit", onSubmit, true);