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.
- package/CHANGELOG.md +10 -1
- package/README.md +60 -15
- package/docs/images/codex-desktop-home.png +0 -0
- package/docs/images/codex-desktop-session.png +0 -0
- package/docs/multi-agent-collaboration.md +68 -68
- package/output/native-build/renderer-extension.js +2225 -1761
- package/package.json +1 -2
- package/scripts/collaboration-recovery-test.cjs +22 -2
- package/scripts/collaboration-ui-smoke.cjs +10 -5
- package/scripts/native-protocol-test.cjs +20 -0
- package/scripts/workspace-test.cjs +2 -14
- package/src/main/adapters/antigravity.js +49 -18
- package/src/main/adapters/claude.js +3 -2
- package/src/main/adapters/codex.js +10 -8
- package/src/main/adapters/dsh.js +3 -2
- package/src/main/adapters/opencode.js +21 -13
- package/src/main/adapters/pi-family.js +3 -3
- package/src/main/host/collaboration-worktree.js +63 -4
- package/src/main/host/collaboration.js +28 -2
- package/src/main/host/runtime.js +22 -1
- package/src/main/native/protocol.js +250 -24
- package/src/native-ui/desktop-control/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/index.d.ts +2 -0
- package/src/native-ui/renderer-extension/dist/types/index.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts +40 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts +8 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts +3 -1
- package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts +8 -1
- package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts +16 -0
- package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +1 -0
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/renderer-extension/src/assets/README.md +8 -38
- package/src/native-ui/renderer-extension/src/harness-mix-settings.ts +9 -1
- package/src/native-ui/renderer-extension/src/index.ts +9 -0
- package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +67 -6
- package/src/native-ui/renderer-extension/src/renderer-collab-cards.ts +198 -0
- package/src/native-ui/renderer-extension/src/renderer-credits-control.ts +32 -12
- package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +139 -46
- package/src/native-ui/renderer-extension/src/renderer-model-client.ts +7 -2
- package/src/native-ui/renderer-extension/src/renderer-usage-control.ts +34 -3
- package/src/native-ui/renderer-extension/src/settings/accounts.css +80 -4
- package/src/native-ui/renderer-extension/src/settings/connections-page.ts +68 -29
- package/src/native-ui/renderer-extension/src/settings/harness-accounts.ts +89 -28
- package/src/native-ui/renderer-extension/src/settings/localization.ts +48 -0
- package/src/native-ui/renderer-extension/src/settings/pages.ts +19 -2
- package/src/native-ui/renderer-extension/src/settings/shell.css +62 -0
- package/src/native-ui/renderer-extension/src/settings/shell.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-collab-cards.test.ts +45 -0
- package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +1 -0
- package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts +20 -6
- package/src/native-ui/shared-contracts/dist/harness-accounts.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-accounts.js +4 -1
- package/src/native-ui/shared-contracts/dist/harness-accounts.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-models.d.ts +22 -0
- package/src/native-ui/shared-contracts/dist/harness-models.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-models.js +2 -1
- package/src/native-ui/shared-contracts/dist/harness-models.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/shared-contracts/src/harness-accounts.ts +4 -1
- package/src/native-ui/shared-contracts/src/harness-models.ts +6 -1
- package/docs/images/harness-mix-home.png +0 -0
- package/docs/images/harness-mix-session.png +0 -0
- package/scripts/git-test.cjs +0 -33
- package/src/assets/icons/activity-compact.svg +0 -1
- package/src/assets/icons/activity-edit.svg +0 -1
- package/src/assets/icons/activity-terminal.svg +0 -1
- package/src/assets/icons/commands.svg +0 -1
- package/src/assets/icons/home-chat.svg +0 -1
- package/src/assets/icons/home-folder.svg +0 -1
- package/src/assets/icons/thread-fork.svg +0 -1
- package/src/main/workspace/git.js +0 -73
- package/src/main/workspace/ipc.js +0 -50
- package/src/main/workspace/terminal.js +0 -34
- package/src/native-ui/renderer-extension/src/assets/claude-agent.svg +0 -3
- package/src/native-ui/renderer-extension/src/assets/codex-logo-bright.png +0 -0
- package/src/native-ui/renderer-extension/src/assets/codex-logo-transparent.png +0 -0
- package/src/native-ui/renderer-extension/src/assets/codex-logo.png +0 -0
- package/src/native-ui/renderer-extension/src/assets/codexhost-icon.png +0 -0
- package/src/native-ui/renderer-extension/src/assets/codexhost-logo-transparent.png +0 -0
- package/src/native-ui/renderer-extension/src/assets/codexhost-logo.png +0 -0
- package/src/native-ui/renderer-extension/src/assets/codexhost-readme.svg +0 -8
- package/src/native-ui/renderer-extension/src/assets/pi-agent.svg +0 -4
- package/src/native-ui/renderer-extension/src/settings/accounts-quota-interactive.prototype.html +0 -1418
- package/src/native-ui/renderer-extension/src/settings/update-notes.preview.html +0 -491
- 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
|
-
|
|
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-
|
|
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
|
|
17237
|
+
code.textContent = commandInfo.command;
|
|
17196
17238
|
commandRow.append(code);
|
|
17197
17239
|
commandBox.append(commandLabel, commandRow);
|
|
17198
|
-
|
|
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
|
|
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
|
-
|
|
17236
|
-
|
|
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
|
|
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
|
|
20462
|
-
|
|
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
|
-
|
|
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
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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
|
|
23626
|
-
const
|
|
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 && !
|
|
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 =
|
|
23643
|
-
|
|
23644
|
-
|
|
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
|
-
|
|
23654
|
-
|
|
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
|
-
|
|
23671
|
-
|
|
23672
|
-
|
|
23673
|
-
|
|
23674
|
-
|
|
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/
|
|
23884
|
-
|
|
23885
|
-
|
|
23886
|
-
|
|
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
|
-
|
|
23899
|
-
|
|
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
|
|
24086
|
+
return null;
|
|
23902
24087
|
}
|
|
23903
|
-
function
|
|
23904
|
-
if (
|
|
23905
|
-
const
|
|
23906
|
-
const
|
|
23907
|
-
|
|
23908
|
-
|
|
23909
|
-
if (
|
|
23910
|
-
|
|
23911
|
-
|
|
23912
|
-
|
|
23913
|
-
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
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
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
|
|
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
|
-
|
|
23925
|
-
|
|
23926
|
-
|
|
23927
|
-
|
|
23928
|
-
|
|
23929
|
-
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
|
|
23933
|
-
|
|
23934
|
-
|
|
23935
|
-
|
|
23936
|
-
|
|
23937
|
-
|
|
23938
|
-
|
|
23939
|
-
|
|
23940
|
-
|
|
23941
|
-
|
|
23942
|
-
|
|
23943
|
-
|
|
23944
|
-
|
|
23945
|
-
|
|
23946
|
-
|
|
23947
|
-
|
|
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
|
-
|
|
23956
|
-
|
|
23957
|
-
|
|
23958
|
-
|
|
23959
|
-
|
|
23960
|
-
|
|
23961
|
-
|
|
23962
|
-
|
|
23963
|
-
|
|
23964
|
-
|
|
23965
|
-
|
|
23966
|
-
|
|
23967
|
-
|
|
23968
|
-
|
|
23969
|
-
|
|
23970
|
-
|
|
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
|
-
|
|
23974
|
-
|
|
23975
|
-
|
|
23976
|
-
|
|
23977
|
-
|
|
23978
|
-
|
|
23979
|
-
|
|
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
|
-
|
|
23982
|
-
|
|
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
|
-
|
|
23987
|
-
|
|
23988
|
-
|
|
23989
|
-
|
|
23990
|
-
|
|
23991
|
-
|
|
23992
|
-
|
|
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
|
-
|
|
24031
|
-
|
|
24032
|
-
|
|
24033
|
-
|
|
24034
|
-
|
|
24035
|
-
|
|
24036
|
-
|
|
24037
|
-
|
|
24038
|
-
|
|
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
|
-
|
|
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/
|
|
24100
|
-
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
|
|
24104
|
-
|
|
24105
|
-
|
|
24106
|
-
|
|
24107
|
-
|
|
24108
|
-
|
|
24109
|
-
|
|
24110
|
-
|
|
24111
|
-
return
|
|
24112
|
-
|
|
24113
|
-
|
|
24114
|
-
|
|
24115
|
-
|
|
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
|
|
24120
|
-
|
|
24121
|
-
|
|
24122
|
-
|
|
24123
|
-
|
|
24124
|
-
|
|
24125
|
-
|
|
24126
|
-
|
|
24127
|
-
|
|
24128
|
-
|
|
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
|
-
|
|
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
|
|
24556
|
-
const
|
|
24557
|
-
|
|
24558
|
-
|
|
24559
|
-
|
|
24560
|
-
|
|
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
|
-
|
|
24563
|
-
const
|
|
24564
|
-
|
|
24565
|
-
|
|
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
|
|
24572
|
-
const
|
|
24573
|
-
|
|
24574
|
-
|
|
24575
|
-
|
|
24576
|
-
|
|
24577
|
-
|
|
24578
|
-
|
|
24579
|
-
|
|
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
|
-
|
|
24582
|
-
|
|
24583
|
-
|
|
24584
|
-
|
|
24585
|
-
|
|
24586
|
-
|
|
24587
|
-
|
|
24588
|
-
|
|
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
|
-
|
|
24612
|
-
|
|
24613
|
-
|
|
24614
|
-
|
|
24615
|
-
|
|
24616
|
-
|
|
24617
|
-
|
|
24618
|
-
|
|
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
|
-
|
|
24623
|
-
|
|
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
|
-
|
|
24626
|
-
|
|
24627
|
-
|
|
24628
|
-
|
|
24629
|
-
|
|
24630
|
-
|
|
24631
|
-
|
|
24632
|
-
|
|
24633
|
-
|
|
24634
|
-
|
|
24635
|
-
|
|
24636
|
-
|
|
24637
|
-
|
|
24638
|
-
|
|
24639
|
-
|
|
24640
|
-
|
|
24641
|
-
|
|
24642
|
-
|
|
24643
|
-
|
|
24644
|
-
|
|
24645
|
-
|
|
24646
|
-
|
|
24647
|
-
|
|
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 (
|
|
24662
|
-
|
|
24663
|
-
|
|
24664
|
-
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24668
|
-
|
|
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
|
-
|
|
24673
|
-
|
|
24674
|
-
|
|
24675
|
-
|
|
24676
|
-
|
|
24677
|
-
|
|
24678
|
-
|
|
24679
|
-
|
|
24680
|
-
|
|
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
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
|
|
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
|
-
|
|
24704
|
-
|
|
24705
|
-
|
|
24706
|
-
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
|
|
24710
|
-
|
|
24711
|
-
|
|
24712
|
-
|
|
24713
|
-
|
|
24714
|
-
|
|
24715
|
-
|
|
24716
|
-
|
|
24717
|
-
|
|
24718
|
-
|
|
24719
|
-
|
|
24720
|
-
|
|
24721
|
-
|
|
24722
|
-
|
|
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
|
-
|
|
24725
|
-
|
|
24726
|
-
|
|
24727
|
-
|
|
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
|
-
|
|
24775
|
-
|
|
24776
|
-
|
|
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
|
-
|
|
24779
|
-
|
|
24780
|
-
|
|
24781
|
-
|
|
24782
|
-
|
|
24783
|
-
|
|
24784
|
-
|
|
24785
|
-
|
|
24786
|
-
|
|
24787
|
-
|
|
24788
|
-
|
|
24789
|
-
|
|
24790
|
-
|
|
24791
|
-
|
|
24792
|
-
|
|
24793
|
-
|
|
24794
|
-
|
|
24795
|
-
|
|
24796
|
-
|
|
24797
|
-
|
|
24798
|
-
|
|
24799
|
-
|
|
24800
|
-
|
|
24801
|
-
|
|
24802
|
-
|
|
24803
|
-
|
|
24804
|
-
|
|
24805
|
-
|
|
24806
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24811
|
-
|
|
24812
|
-
|
|
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
|
-
|
|
24821
|
-
|
|
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
|
-
|
|
24831
|
-
|
|
24832
|
-
|
|
24833
|
-
|
|
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
|
|
24852
|
-
|
|
24853
|
-
|
|
24854
|
-
const
|
|
24855
|
-
const
|
|
24856
|
-
|
|
24857
|
-
|
|
24858
|
-
|
|
24859
|
-
|
|
24860
|
-
|
|
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
|
-
|
|
24863
|
-
`.settings-account-row[data-account-id="${CSS.escape(accountId)}"]`
|
|
24864
|
-
) : null;
|
|
24865
|
-
(row ?? fallback).focus({ preventScroll: true });
|
|
24866
|
-
};
|
|
25283
|
+
});
|
|
24867
25284
|
}
|
|
24868
|
-
|
|
24869
|
-
|
|
24870
|
-
|
|
24871
|
-
|
|
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
|
-
|
|
24886
|
-
|
|
24887
|
-
|
|
24888
|
-
|
|
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
|
-
|
|
24921
|
-
|
|
24922
|
-
|
|
24923
|
-
|
|
24924
|
-
|
|
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
|
-
|
|
24930
|
-
|
|
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
|
-
|
|
24944
|
-
|
|
24945
|
-
|
|
24946
|
-
|
|
24947
|
-
|
|
24948
|
-
|
|
24949
|
-
|
|
24950
|
-
|
|
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
|
-
|
|
24968
|
-
|
|
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
|
-
|
|
24978
|
-
|
|
24979
|
-
|
|
24980
|
-
|
|
24981
|
-
|
|
24982
|
-
|
|
24983
|
-
|
|
24984
|
-
|
|
24985
|
-
|
|
24986
|
-
|
|
24987
|
-
|
|
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
|
-
|
|
24990
|
-
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
|
|
24994
|
-
|
|
24995
|
-
|
|
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
|
-
|
|
25002
|
-
|
|
25003
|
-
|
|
25004
|
-
|
|
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/
|
|
25022
|
-
function
|
|
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
|
|
25038
|
-
|
|
25039
|
-
|
|
25040
|
-
|
|
25041
|
-
|
|
25042
|
-
|
|
25043
|
-
|
|
25044
|
-
|
|
25045
|
-
|
|
25046
|
-
|
|
25047
|
-
|
|
25048
|
-
|
|
25049
|
-
|
|
25050
|
-
|
|
25051
|
-
|
|
25052
|
-
|
|
25053
|
-
|
|
25054
|
-
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
25058
|
-
|
|
25059
|
-
|
|
25060
|
-
|
|
25061
|
-
|
|
25062
|
-
|
|
25063
|
-
|
|
25064
|
-
|
|
25065
|
-
|
|
25066
|
-
|
|
25067
|
-
|
|
25068
|
-
|
|
25069
|
-
|
|
25070
|
-
|
|
25071
|
-
|
|
25072
|
-
|
|
25073
|
-
|
|
25074
|
-
|
|
25075
|
-
|
|
25076
|
-
|
|
25077
|
-
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25081
|
-
|
|
25082
|
-
|
|
25083
|
-
|
|
25084
|
-
|
|
25085
|
-
|
|
25086
|
-
|
|
25087
|
-
|
|
25088
|
-
|
|
25089
|
-
|
|
25090
|
-
|
|
25091
|
-
|
|
25092
|
-
|
|
25093
|
-
|
|
25094
|
-
|
|
25095
|
-
|
|
25096
|
-
|
|
25097
|
-
|
|
25098
|
-
|
|
25099
|
-
|
|
25100
|
-
|
|
25101
|
-
|
|
25102
|
-
|
|
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
|
-
|
|
25107
|
-
|
|
25434
|
+
searchForm,
|
|
25435
|
+
pagination,
|
|
25436
|
+
params() {
|
|
25437
|
+
return { query, offset, limit };
|
|
25108
25438
|
},
|
|
25109
|
-
|
|
25110
|
-
|
|
25111
|
-
|
|
25112
|
-
|
|
25439
|
+
reset() {
|
|
25440
|
+
offset = 0;
|
|
25441
|
+
total = 0;
|
|
25442
|
+
update();
|
|
25113
25443
|
},
|
|
25114
|
-
|
|
25115
|
-
|
|
25116
|
-
|
|
25117
|
-
|
|
25118
|
-
|
|
25119
|
-
|
|
25120
|
-
|
|
25121
|
-
|
|
25122
|
-
|
|
25123
|
-
|
|
25124
|
-
|
|
25125
|
-
|
|
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/
|
|
25137
|
-
function
|
|
25138
|
-
return
|
|
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
|
|
25141
|
-
|
|
25142
|
-
|
|
25143
|
-
|
|
25144
|
-
|
|
25145
|
-
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25149
|
-
|
|
25150
|
-
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
const
|
|
25154
|
-
|
|
25155
|
-
heading
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
|
|
25162
|
-
|
|
25163
|
-
|
|
25164
|
-
|
|
25165
|
-
|
|
25166
|
-
|
|
25167
|
-
|
|
25168
|
-
|
|
25169
|
-
|
|
25170
|
-
const
|
|
25171
|
-
|
|
25172
|
-
const
|
|
25173
|
-
|
|
25174
|
-
|
|
25175
|
-
|
|
25176
|
-
|
|
25177
|
-
|
|
25178
|
-
|
|
25179
|
-
|
|
25180
|
-
|
|
25181
|
-
const
|
|
25182
|
-
|
|
25183
|
-
|
|
25184
|
-
|
|
25185
|
-
|
|
25186
|
-
|
|
25187
|
-
|
|
25188
|
-
|
|
25189
|
-
|
|
25190
|
-
|
|
25191
|
-
|
|
25192
|
-
|
|
25193
|
-
|
|
25194
|
-
|
|
25195
|
-
|
|
25196
|
-
|
|
25197
|
-
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
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
|
-
|
|
25389
|
-
|
|
25390
|
-
|
|
25391
|
-
|
|
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
|
|
25394
|
-
|
|
25395
|
-
|
|
25396
|
-
|
|
25397
|
-
|
|
25398
|
-
|
|
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
|
-
|
|
25401
|
-
|
|
25402
|
-
|
|
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
|
-
|
|
25406
|
-
|
|
25407
|
-
|
|
25408
|
-
|
|
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
|
-
|
|
25431
|
-
|
|
25432
|
-
|
|
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
|
|
25507
|
-
|
|
25508
|
-
|
|
25509
|
-
|
|
25510
|
-
|
|
25511
|
-
|
|
25512
|
-
|
|
25513
|
-
|
|
25514
|
-
|
|
25515
|
-
|
|
25516
|
-
|
|
25517
|
-
|
|
25518
|
-
|
|
25519
|
-
|
|
25520
|
-
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25524
|
-
|
|
25525
|
-
|
|
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
|
-
|
|
25530
|
-
|
|
25531
|
-
|
|
25532
|
-
|
|
25533
|
-
|
|
25534
|
-
|
|
25535
|
-
|
|
25536
|
-
|
|
25537
|
-
|
|
25538
|
-
|
|
25539
|
-
|
|
25540
|
-
|
|
25541
|
-
|
|
25542
|
-
|
|
25543
|
-
|
|
25544
|
-
|
|
25545
|
-
|
|
25546
|
-
|
|
25547
|
-
|
|
25548
|
-
|
|
25549
|
-
|
|
25550
|
-
|
|
25551
|
-
}
|
|
25552
|
-
|
|
25553
|
-
|
|
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
|
-
|
|
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
|
|
25565
|
-
|
|
25566
|
-
|
|
25567
|
-
if (
|
|
25568
|
-
|
|
25569
|
-
|
|
25570
|
-
|
|
25571
|
-
|
|
25572
|
-
|
|
25573
|
-
|
|
25574
|
-
|
|
25575
|
-
|
|
25576
|
-
|
|
25577
|
-
|
|
25578
|
-
|
|
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
|
|
25590
|
-
|
|
25591
|
-
|
|
25592
|
-
|
|
25593
|
-
|
|
25594
|
-
|
|
25595
|
-
|
|
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
|
-
|
|
25598
|
-
|
|
25599
|
-
|
|
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
|
-
|
|
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
|
-
|
|
25621
|
-
|
|
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
|
|
27224
|
-
|
|
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 (!
|
|
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);
|