cicy-desktop 2.1.77 → 2.1.79
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/README.md +21 -18
- package/bin/cicy-desktop +7 -7
- package/build/icon.icns +0 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/build/icon.svg +8 -18
- package/build/icons/icon-1024.png +0 -0
- package/build/icons/icon-128.png +0 -0
- package/build/icons/icon-16.png +0 -0
- package/build/icons/icon-24.png +0 -0
- package/build/icons/icon-256.png +0 -0
- package/build/icons/icon-32.png +0 -0
- package/build/icons/icon-48.png +0 -0
- package/build/icons/icon-512.png +0 -0
- package/build/icons/icon-64.png +0 -0
- package/build/icons/icon-96.png +0 -0
- package/build/icons/trayTemplate-16.png +0 -0
- package/build/icons/trayTemplate-16@2x.png +0 -0
- package/build/icons/trayTemplate-22.png +0 -0
- package/build/icons/trayTemplate-22@2x.png +0 -0
- package/build/icons/trayTemplate-32.png +0 -0
- package/build/icons/trayTemplate-32@2x.png +0 -0
- package/build/trayTemplate.png +0 -0
- package/build/trayTemplate.svg +11 -12
- package/build/trayTemplate@2x.png +0 -0
- package/package.json +6 -6
- package/src/backends/auth-loopback.js +17 -6
- package/src/backends/homepage-preload.js +22 -0
- package/src/backends/homepage-react/assets/index-CKpaMBKz.css +1 -0
- package/src/backends/homepage-react/assets/index-CSsNZgC5.js +365 -0
- package/src/backends/homepage-react/favicon-256.png +0 -0
- package/src/backends/homepage-react/favicon.svg +12 -0
- package/src/backends/homepage-react/index.html +4 -2
- package/src/backends/homepage-window.js +52 -7
- package/src/backends/ipc.js +57 -0
- package/src/backends/local-teams.js +114 -15
- package/src/backends/login-success.html +96 -0
- package/src/backends/sidecar-ipc.js +11 -0
- package/src/backends/webview-preload.js +5 -3
- package/src/backends/window-manager.js +13 -3
- package/src/chrome/chrome-launcher.js +5 -4
- package/src/chrome/debugger-port-resolver.js +1 -1
- package/src/cloud/cloud-client.js +435 -0
- package/src/cluster/types.js +0 -5
- package/src/extension/inject.js +1 -1
- package/src/main.js +329 -74
- package/src/master/chrome-config.js +2 -2
- package/src/preload-rpc.js +1 -1
- package/src/profiles/profile-store.js +321 -0
- package/src/profiles/trusted-origins-store.js +95 -0
- package/src/server/worker-observability-routes.js +0 -2
- package/src/sidecar/cicy-code.js +84 -23
- package/src/sidecar/localbin.js +20 -3
- package/src/sidecar/native.js +3 -3
- package/src/sidecar/version.js +45 -0
- package/src/tabbrowser/newtab-protocol.js +54 -0
- package/src/tabbrowser/tab-browser.html +151 -0
- package/src/tabbrowser/tab-shell-preload.js +28 -0
- package/src/tabbrowser/tab-shell.html +227 -0
- package/src/tools/account-tools.js +191 -25
- package/src/tools/chrome-tools.js +173 -37
- package/src/tools/device-tools.js +25 -0
- package/src/tools/index.js +2 -0
- package/src/tools/tab-browser-tools.js +453 -0
- package/src/tools/window-tools.js +64 -7
- package/src/utils/brand-host-electron.js +159 -0
- package/src/utils/context-menu-options.js +80 -0
- package/src/utils/cookie-logins.js +58 -0
- package/src/utils/ip-probe.js +50 -0
- package/src/utils/rpc-audit.js +53 -0
- package/src/utils/rpc-guard.js +189 -0
- package/src/utils/window-monitor.js +5 -15
- package/src/utils/window-registry.js +210 -0
- package/src/utils/window-thumbnails.js +126 -0
- package/src/utils/window-utils.js +192 -107
- package/workers/render/index.html +2 -0
- package/workers/render/package-lock.json +6 -6
- package/workers/render/public/favicon-256.png +0 -0
- package/workers/render/public/favicon.svg +12 -0
- package/workers/render/src/App.css +163 -33
- package/workers/render/src/App.jsx +756 -126
- package/src/backends/artifact-ipc.js +0 -142
- package/src/backends/homepage-react/assets/index-CPH-S8uU.css +0 -1
- package/src/backends/homepage-react/assets/index-DuWX0iug.js +0 -365
- package/src/cluster/artifact-registry.js +0 -61
package/README.md
CHANGED
|
@@ -131,11 +131,11 @@ the Electron main process loads into the primary BrowserWindow.
|
|
|
131
131
|
|
|
132
132
|
### Where it's served from
|
|
133
133
|
|
|
134
|
-
- **
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
HTTP team-assistant webview without mixed-content issues
|
|
134
|
+
- **All platforms (Win/Mac/Linux)**: local
|
|
135
|
+
`file:///.../src/backends/homepage-react/index.html` (a synced copy of
|
|
136
|
+
`workers/render/dist/`). `pickHomepageURL()` returns this unconditionally —
|
|
137
|
+
the bundled `file://` SPA works offline, is fast, and lets the homepage
|
|
138
|
+
embed the HTTP team-assistant webview without mixed-content issues.
|
|
139
139
|
- **Dev**: set `CICY_HOMEPAGE_URL=http://localhost:8173` to load the live
|
|
140
140
|
vite dev server instead. See "Dev workflow" below.
|
|
141
141
|
|
|
@@ -146,8 +146,6 @@ the Electron main process loads into the primary BrowserWindow.
|
|
|
146
146
|
cd workers/render && npm run build
|
|
147
147
|
# copy into the file:// SPA folder cicy-desktop's main process loads from
|
|
148
148
|
rsync -av --delete dist/ ../../src/backends/homepage-react/
|
|
149
|
-
# deploy CF Worker (Windows users hit this URL)
|
|
150
|
-
npx wrangler deploy
|
|
151
149
|
```
|
|
152
150
|
|
|
153
151
|
### Dev workflow
|
|
@@ -186,25 +184,30 @@ Vite HMR picks it up instantly. No Electron restart for React/CSS edits.
|
|
|
186
184
|
|
|
187
185
|
`src/backends/homepage-window.js` URL priority:
|
|
188
186
|
1. `CICY_HOMEPAGE_URL` env (dev override) → falls back to `file://` on load failure
|
|
189
|
-
2.
|
|
190
|
-
3. Mac/Linux → bundled `file://src/backends/homepage-react/index.html`
|
|
187
|
+
2. All platforms → bundled `file://src/backends/homepage-react/index.html`
|
|
191
188
|
|
|
192
|
-
### Shipping SPA changes to Windows
|
|
189
|
+
### Shipping SPA changes to Windows (hotpatch)
|
|
193
190
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
Windows loads the same local `file://` SPA as Mac/Linux — the running
|
|
192
|
+
npm-global install reads `src/backends/homepage-react/`. So shipping a SPA
|
|
193
|
+
change = sync the files, **not** redeploy a Worker (there is no remote
|
|
194
|
+
homepage Worker for Windows anymore):
|
|
197
195
|
|
|
198
196
|
```bash
|
|
197
|
+
# build + mirror into the file:// folder
|
|
199
198
|
cd workers/render && npm run build
|
|
200
|
-
CLOUDFLARE_ACCOUNT_ID=$(jq -r .cf.prod.account_id ~/cicy-ai/global.json) \
|
|
201
|
-
CLOUDFLARE_API_TOKEN=$(jq -r .cf.prod.api_token ~/cicy-ai/global.json) \
|
|
202
|
-
npx wrangler deploy
|
|
203
|
-
# Mirror dist/ into the file:// folder so Mac packaged builds match
|
|
204
199
|
rsync -av --delete dist/ ../../src/backends/homepage-react/
|
|
200
|
+
# package backend + SPA and push to the Windows box
|
|
201
|
+
cd ../.. && tar czf /tmp/cicy-hotpatch.tgz src build bin package.json
|
|
202
|
+
scp /tmp/cicy-hotpatch.tgz win:'C:/Users/Administrator/cicy-hotpatch.tgz'
|
|
203
|
+
ssh win 'cd /d "C:\Users\Administrator\AppData\Roaming\npm\node_modules\cicy-desktop" && tar -xzf C:\Users\Administrator\cicy-hotpatch.tgz'
|
|
204
|
+
# relaunch in the *interactive* session (session 0 can't paint a GUI window)
|
|
205
|
+
ssh win 'schtasks /run /tn StartElectron'
|
|
205
206
|
```
|
|
206
207
|
|
|
207
|
-
|
|
208
|
+
The `StartElectron` scheduled task is set to "interactive only" so the
|
|
209
|
+
relaunched window appears on the user's RDP desktop. `bin/cicy-desktop`
|
|
210
|
+
always opens `--remote-debugging-port=9221`, so verify the reload over CDP.
|
|
208
211
|
|
|
209
212
|
## Canonical config
|
|
210
213
|
|
package/bin/cicy-desktop
CHANGED
|
@@ -323,7 +323,7 @@ function killAllElectronProcesses() {
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
function hardCleanupBeforeStart({ masterPort, workerPort }) {
|
|
326
|
-
console.log(
|
|
326
|
+
console.log("🧹 Cleaning up previous instance…");
|
|
327
327
|
killListenersByPort(masterPort);
|
|
328
328
|
killListenersByPort(workerPort);
|
|
329
329
|
killAllElectronProcesses();
|
|
@@ -738,8 +738,7 @@ async function startWorker({ workerPort, masterBaseUrl, token, workerUiUrl }) {
|
|
|
738
738
|
|
|
739
739
|
async function startWorkerOnly({ workerPort }) {
|
|
740
740
|
const tokenManager = new MasterTokenManager();
|
|
741
|
-
|
|
742
|
-
const workerUiUrl = `http://localhost:${workerPort}/console/chrome?token=${token}`;
|
|
741
|
+
tokenManager.getToken(); // ensure the token file exists before the worker reads it
|
|
743
742
|
|
|
744
743
|
writeClusterState({
|
|
745
744
|
masterPid: null,
|
|
@@ -750,8 +749,11 @@ async function startWorkerOnly({ workerPort }) {
|
|
|
750
749
|
startedAt: new Date().toISOString(),
|
|
751
750
|
});
|
|
752
751
|
|
|
753
|
-
|
|
754
|
-
|
|
752
|
+
// The worker HTTP server on :PORT is skipped by default (see main.js —
|
|
753
|
+
// httpEnabled=automationEnabled), so don't advertise http://localhost:PORT or
|
|
754
|
+
// the /console/chrome UI: those URLs are dead unless CICY_DESKTOP_HTTP=1/--mcp.
|
|
755
|
+
// Renderer RPC goes through electronRPC injected in preload, not this port.
|
|
756
|
+
console.log("🚀 Starting CiCy Desktop…");
|
|
755
757
|
console.log(`📄 Token file: ${tokenManager.getConfigPath()}`);
|
|
756
758
|
console.log("🛑 Press Ctrl+C to stop processes started by this command");
|
|
757
759
|
|
|
@@ -827,8 +829,6 @@ async function startMasterCluster({ masterPort, workerPort }) {
|
|
|
827
829
|
});
|
|
828
830
|
|
|
829
831
|
console.log(`🚀 Target master ${masterBaseUrl}`);
|
|
830
|
-
console.log(`🚀 Target worker http://localhost:${workerPort}`);
|
|
831
|
-
console.log(`🪟 Worker UI ${workerUiUrl}`);
|
|
832
832
|
console.log(`📄 Token file: ${tokenManager.getConfigPath()}`);
|
|
833
833
|
|
|
834
834
|
const masterRunning = await checkMaster(masterBaseUrl);
|
package/build/icon.icns
CHANGED
|
Binary file
|
package/build/icon.ico
CHANGED
|
Binary file
|
package/build/icon.png
CHANGED
|
Binary file
|
package/build/icon.svg
CHANGED
|
@@ -1,22 +1,12 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" fill="none">
|
|
2
2
|
<defs>
|
|
3
|
-
<linearGradient id="
|
|
4
|
-
<stop
|
|
5
|
-
<stop offset="
|
|
3
|
+
<linearGradient id="cicyMark" x1="16" y1="12" x2="80" y2="84" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#60A5FA"/>
|
|
5
|
+
<stop offset="0.55" stop-color="#2563EB"/>
|
|
6
|
+
<stop offset="1" stop-color="#1E3A8A"/>
|
|
6
7
|
</linearGradient>
|
|
7
8
|
</defs>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<!-- Bold rounded "C" in soft cream/white (matches cicy.svg's #FFF7ED) -->
|
|
13
|
-
<path d="M716 372
|
|
14
|
-
C 670 320, 600 290, 520 290
|
|
15
|
-
C 380 290, 280 392, 280 512
|
|
16
|
-
C 280 632, 380 734, 520 734
|
|
17
|
-
C 600 734, 670 704, 716 652"
|
|
18
|
-
stroke="#FFF7ED"
|
|
19
|
-
stroke-width="120"
|
|
20
|
-
stroke-linecap="round"
|
|
21
|
-
fill="none"/>
|
|
9
|
+
<path d="M48 11L39.5 33.3L16 29.5L31 48L16 66.5L39.5 62.7L48 85L56.5 62.7L80 66.5L65 48L80 29.5L56.5 33.3Z"
|
|
10
|
+
fill="url(#cicyMark)" stroke="url(#cicyMark)" stroke-width="8"
|
|
11
|
+
stroke-linejoin="round" stroke-linecap="round"/>
|
|
22
12
|
</svg>
|
|
Binary file
|
package/build/icons/icon-128.png
CHANGED
|
Binary file
|
package/build/icons/icon-16.png
CHANGED
|
Binary file
|
package/build/icons/icon-24.png
CHANGED
|
Binary file
|
package/build/icons/icon-256.png
CHANGED
|
Binary file
|
package/build/icons/icon-32.png
CHANGED
|
Binary file
|
package/build/icons/icon-48.png
CHANGED
|
Binary file
|
package/build/icons/icon-512.png
CHANGED
|
Binary file
|
package/build/icons/icon-64.png
CHANGED
|
Binary file
|
package/build/icons/icon-96.png
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/build/trayTemplate.png
CHANGED
|
Binary file
|
package/build/trayTemplate.svg
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
stroke-width="
|
|
11
|
-
stroke-linecap="round"
|
|
12
|
-
fill="none"/>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" fill="none">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="cicyMark" x1="16" y1="12" x2="80" y2="84" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#60A5FA"/>
|
|
5
|
+
<stop offset="0.55" stop-color="#2563EB"/>
|
|
6
|
+
<stop offset="1" stop-color="#1E3A8A"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
</defs>
|
|
9
|
+
<path d="M48 11L39.5 33.3L16 29.5L31 48L16 66.5L39.5 62.7L48 85L56.5 62.7L80 66.5L65 48L80 29.5L56.5 33.3Z"
|
|
10
|
+
fill="#000000" stroke="#000000" stroke-width="8"
|
|
11
|
+
stroke-linejoin="round" stroke-linecap="round"/>
|
|
13
12
|
</svg>
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cicy-desktop",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.79",
|
|
4
4
|
"description": "CiCy - AI-powered operating system browser",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -133,11 +133,11 @@
|
|
|
133
133
|
},
|
|
134
134
|
"//optionalDependencies": "Runtime Bundle v1 (主人指令): platform binaries delivered by `npm i -g cicy-desktop` itself — npm installs only the current-platform subpackage (os/cpu pinned in each), so first start seeds the runtime store with ZERO network, ZERO npx. Windows packages are named *-windows-* (npm spam filter 403s new names containing win32). cicy-msys2 added once published.",
|
|
135
135
|
"optionalDependencies": {
|
|
136
|
-
"cicy-code-darwin-x64": "2.
|
|
137
|
-
"cicy-code-darwin-arm64": "2.
|
|
138
|
-
"cicy-code-linux-x64": "2.
|
|
139
|
-
"cicy-code-linux-arm64": "2.
|
|
140
|
-
"cicy-code-windows-x64": "2.
|
|
136
|
+
"cicy-code-darwin-x64": "2.3.0",
|
|
137
|
+
"cicy-code-darwin-arm64": "2.3.0",
|
|
138
|
+
"cicy-code-linux-x64": "2.3.0",
|
|
139
|
+
"cicy-code-linux-arm64": "2.3.0",
|
|
140
|
+
"cicy-code-windows-x64": "2.3.0",
|
|
141
141
|
"cicy-mihomo-darwin-x64": "1.10.4",
|
|
142
142
|
"cicy-mihomo-darwin-arm64": "1.10.4",
|
|
143
143
|
"cicy-mihomo-linux-x64": "1.10.4",
|
|
@@ -18,10 +18,26 @@
|
|
|
18
18
|
const http = require("http");
|
|
19
19
|
const crypto = require("crypto");
|
|
20
20
|
const os = require("os");
|
|
21
|
+
const fs = require("fs");
|
|
22
|
+
const path = require("path");
|
|
21
23
|
const { shell } = require("electron");
|
|
22
24
|
const log = require("electron-log");
|
|
23
25
|
|
|
24
26
|
const LOGIN_BASE = "https://cicy-ai.com/login";
|
|
27
|
+
|
|
28
|
+
// Styled /cb success page (dark, CiCy-branded — matches the landing). Shipped
|
|
29
|
+
// alongside this module so it works in the packaged app; falls back to a plain
|
|
30
|
+
// inline page if the file is somehow missing.
|
|
31
|
+
const SUCCESS_FALLBACK = `<!doctype html><meta charset="utf-8">
|
|
32
|
+
<body style="font-family:-apple-system,sans-serif;text-align:center;padding:60px;color:#222;background:#f7f8fa">
|
|
33
|
+
<h1 style="color:#10b981;margin-bottom:8px">登录成功 ✓</h1>
|
|
34
|
+
<p style="opacity:.7">请回到 CiCy Desktop 继续使用。</p>
|
|
35
|
+
<p style="opacity:.4;font-size:13px;margin-top:32px">此页面可以安全关闭。</p>
|
|
36
|
+
</body>`;
|
|
37
|
+
const SUCCESS_HTML = (() => {
|
|
38
|
+
try { return fs.readFileSync(path.join(__dirname, "login-success.html"), "utf8"); }
|
|
39
|
+
catch (e) { log.warn(`[auth-loopback] success page load failed, using fallback: ${e.message}`); return SUCCESS_FALLBACK; }
|
|
40
|
+
})();
|
|
25
41
|
// 120 s — per w-10032 cloud spec. Cloud-side fallback when /exchange fails
|
|
26
42
|
// is to redirect to /team/dashboard, NOT back to our loopback, so the
|
|
27
43
|
// listener never sees a result and must self-time-out instead of hanging
|
|
@@ -100,12 +116,7 @@ async function startLogin({ onResult } = {}) {
|
|
|
100
116
|
}
|
|
101
117
|
|
|
102
118
|
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
103
|
-
res.end(
|
|
104
|
-
<body style="font-family:-apple-system,sans-serif;text-align:center;padding:60px;color:#222;background:#f7f8fa">
|
|
105
|
-
<h1 style="color:#10b981;margin-bottom:8px">登录成功 ✓</h1>
|
|
106
|
-
<p style="opacity:.7">请回到 CiCy Desktop 继续使用。</p>
|
|
107
|
-
<p style="opacity:.4;font-size:13px;margin-top:32px">此页面可以关闭。</p>
|
|
108
|
-
</body>`);
|
|
119
|
+
res.end(SUCCESS_HTML);
|
|
109
120
|
try { onResult && onResult({ token, state, reused, accessToken, userId }); } catch {}
|
|
110
121
|
setTimeout(() => shutdown("login complete"), 500);
|
|
111
122
|
});
|
|
@@ -109,6 +109,7 @@ contextBridge.exposeInMainWorld("cicy", {
|
|
|
109
109
|
// or Docker (Windows) — no in-app downloader. Only lifecycle + status remain.
|
|
110
110
|
sidecar: {
|
|
111
111
|
status: () => logInvoke("sidecar:status"),
|
|
112
|
+
versions: () => logInvoke("sidecar:versions"),
|
|
112
113
|
start: () => logInvoke("sidecar:start"),
|
|
113
114
|
stop: () => logInvoke("sidecar:stop"),
|
|
114
115
|
restart: () => logInvoke("sidecar:restart"),
|
|
@@ -152,6 +153,26 @@ contextBridge.exposeInMainWorld("cicy", {
|
|
|
152
153
|
clipboard: {
|
|
153
154
|
write: (text) => logInvoke("clipboard:write", text),
|
|
154
155
|
},
|
|
156
|
+
// Trusted-origins allowlist (Chrome-style site settings). Sites listed here may
|
|
157
|
+
// receive the electronRPC bridge in profile 0 = run commands on this machine,
|
|
158
|
+
// so the settings UI must warn loudly. list() returns [{host, builtin}], add/
|
|
159
|
+
// remove return { ok, origins?:[{host,builtin}], error? } and take effect live.
|
|
160
|
+
trustedOrigins: {
|
|
161
|
+
list: () => logInvoke("trustedOrigins:list"),
|
|
162
|
+
add: (host) => logInvoke("trustedOrigins:add", host),
|
|
163
|
+
remove: (host) => logInvoke("trustedOrigins:remove", host),
|
|
164
|
+
},
|
|
165
|
+
// Read-only RPC audit log viewer (~/cicy-ai/db/rpc-audit.log). tail(limit)
|
|
166
|
+
// returns { ok, entries:[{ts,kind,...}] newest-first, path }.
|
|
167
|
+
rpcAudit: {
|
|
168
|
+
tail: (limit) => logInvoke("rpcAudit:tail", { limit }),
|
|
169
|
+
},
|
|
170
|
+
// Open / reload a URL as a TAB in profile 0 (homepage cards open like the local
|
|
171
|
+
// card — current profile, not a new window / system browser).
|
|
172
|
+
tabs: {
|
|
173
|
+
open: (url, title) => logInvoke("tabs:open", { url, title }),
|
|
174
|
+
reload: (url, title) => logInvoke("tabs:reload", { url, title }),
|
|
175
|
+
},
|
|
155
176
|
|
|
156
177
|
// ------- new bridges (last rebuild!) -------
|
|
157
178
|
app: {
|
|
@@ -207,6 +228,7 @@ contextBridge.exposeInMainWorld("cicy", {
|
|
|
207
228
|
remove: (id) => logInvoke("localTeams:remove", id),
|
|
208
229
|
update: (id, patch) => logInvoke("localTeams:update", { id, patch }),
|
|
209
230
|
upgrade: (id) => logInvoke("localTeams:upgrade", id),
|
|
231
|
+
syncCloud: () => logInvoke("localTeams:syncCloud"),
|
|
210
232
|
// Subscribe to relay requests forwarded from a child <webview>
|
|
211
233
|
// (the Team Helper webview, via webview-preload.js). Each fire
|
|
212
234
|
// delivers {reqId, msg:{type, ...payload}}; the renderer is
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--accent: #5b8df7;--accent-soft: rgba(91,141,247,.16);--accent-line: rgba(91,141,247,.32);--accent-text: #a5c4ff;--ok: #4ade80;--danger: #f7a3a3;--text: #e5e7eb;--text-dim: #9da7b3;--text-mute: #6b7280;--line: rgba(255,255,255,.08)}*{box-sizing:border-box}html,body,#root{margin:0;height:100%}html,body{overflow:hidden}body{font-family:-apple-system,BlinkMacSystemFont,PingFang SC,Segoe UI,Roboto,Helvetica Neue,sans-serif;background:#07080c;color:#e5e7eb;-webkit-font-smoothing:antialiased}.shell{position:relative;min-height:100vh;display:flex;align-items:center;justify-content:center;overflow:hidden;-webkit-app-region:drag}.shell--app{align-items:stretch;justify-content:stretch;flex-direction:row;background:linear-gradient(180deg,#0b0d13,#07080c);overflow:hidden;-webkit-app-region:no-drag}.shell__left{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;overflow:hidden}.helper-aside{flex:0 0 auto;position:relative;background:#0f1115;border-left:1px solid rgba(255,255,255,.06);display:flex;flex-direction:column;min-width:320px;z-index:1}.helper-aside,.helper-aside *,.shell--app .main{-webkit-app-region:no-drag}.shell--app .topbar{-webkit-app-region:drag}.shell--app .topbar .user-chip,.shell--app .topbar .user-chip *,.shell--app .topbar .btn-ghost{-webkit-app-region:no-drag}.glow{position:absolute;top:-40%;right:-40%;bottom:-40%;left:-40%;z-index:0;pointer-events:none;background:radial-gradient(closest-side,rgba(91,141,247,.2),transparent 60%),radial-gradient(closest-side at 30% 70%,rgba(167,139,250,.13),transparent 65%);filter:blur(30px)}.card{-webkit-app-region:no-drag;position:relative;z-index:1;width:380px;padding:36px 36px 28px;background:linear-gradient(180deg,#141820d9,#0d1016d9);border:1px solid rgba(255,255,255,.06);border-radius:16px;box-shadow:0 1px #ffffff0a inset,0 30px 60px #0006;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);display:flex;flex-direction:column;align-items:center;gap:18px}.brand{display:flex;align-items:center;gap:12px;align-self:stretch}.brand-mark{width:40px;height:40px;border-radius:12px;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);box-shadow:0 8px 20px #5b8df759}.brand-mark.sm{width:28px;height:28px;border-radius:8px;box-shadow:none}.brand-mark.sm svg{width:16px;height:16px}.brand-text{line-height:1.2}.brand-name{font-weight:600;font-size:15px}.brand-sub{font-size:12px;color:#9ca3af;margin-top:2px}.tagline{margin:4px 0 0;color:#c7cdd6;font-size:13.5px;text-align:center;line-height:1.55}.btn-primary{-webkit-app-region:no-drag;margin-top:4px;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:42px;display:inline-flex;align-items:center;justify-content:center;gap:8px;background:linear-gradient(180deg,#5b8df7,#4570d8);color:#fff;border:0;border-radius:10px;font-size:14px;font-weight:500;letter-spacing:.2px;cursor:pointer;box-shadow:0 1px #ffffff2e inset,0 -1px #0000002e inset,0 10px 22px #5b8df747;transition:transform 80ms ease,filter .12s ease}.btn-primary:hover{filter:brightness(1.08)}.btn-primary:active{transform:translateY(1px)}.btn-primary:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.btn-ghost{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:6px 14px;font-size:12.5px;cursor:pointer;transition:color .12s ease,border-color .12s ease,background .12s ease}.btn-ghost.sm{padding:4px 10px;font-size:11.5px}.btn-ghost:hover{color:#e5e7eb;background:#ffffff0a;border-color:#ffffff24}.btn-ghost:disabled{opacity:.4;cursor:default}.hint{margin:0;font-size:11.5px;color:#6b7280}.spinner-row{display:inline-flex;align-items:center;gap:8px;color:#c7cdd6;font-size:13px}.spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{width:100%;font-size:12px;color:#fca5a5;background:#ef444414;border:1px solid rgba(239,68,68,.18);padding:8px 12px;border-radius:8px;text-align:center;line-height:1.5}.topbar{-webkit-app-region:drag;position:relative;flex:0 0 auto;z-index:10;display:flex;align-items:center;justify-content:space-between;padding:14px 24px 12px;background:#08090e99;border-bottom:1px solid rgba(255,255,255,.05);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}[data-platform=darwin][data-fullscreen="0"] .topbar{padding-top:34px}.brand-mini{display:inline-flex;align-items:center;gap:10px}.brand-mini .brand-name{font-size:14px}.user-chip{-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:10px}.welcome{font-size:12px;color:var(--text-dim);padding:4px 10px;border-radius:999px;background:#ffffff0d;border:1px solid var(--line);animation:fadein .2s ease}@keyframes fadein{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}.avatar{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);font-size:12px;font-weight:600;color:#fff}.user-name{font-size:13px;color:#c7cdd6}.user-chip{position:relative}.user-chip__trigger{-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:8px;border:1px solid transparent;background:transparent;border-radius:999px;padding:3px 8px 3px 3px;cursor:pointer;transition:.12s}.user-chip__trigger:hover,.user-chip__trigger.is-open{background:#ffffff0f;border-color:#ffffff1f}.user-chip__caret{font-size:10px;color:#8a93a3;transition:transform .12s}.user-chip__trigger.is-open .user-chip__caret{transform:rotate(180deg)}.user-chip__menu{position:absolute;top:38px;right:0;z-index:30;min-width:200px;padding:6px;background:#1b2027;border:1px solid rgba(255,255,255,.12);border-radius:12px;box-shadow:0 12px 34px #00000080;display:flex;flex-direction:column;gap:2px;animation:fadein .14s ease}.user-chip__menu-item{text-align:left;width:100%;border:none;background:transparent;color:#d1d5db;border-radius:8px;padding:9px 11px;font-size:13px;cursor:pointer;transition:.12s}.user-chip__menu-item:hover{background:#ffffff12;color:#fff}.user-chip__menu-item.is-danger{color:#f7a3a3}.user-chip__menu-item.is-danger:hover{background:#ef444429;color:#fff}.user-chip__menu-sep{height:1px;margin:4px 2px;background:#ffffff14}.user-chip__mitm-row{display:flex;align-items:center;justify-content:space-between;gap:10px;cursor:default}.user-chip__mitm-row:hover{background:transparent}.user-chip__mitm-label{font-size:13px;color:var(--text)}.mini-switch{-webkit-app-region:no-drag;position:relative;flex:0 0 auto;width:36px;height:20px;padding:0;border-radius:999px;border:1px solid var(--line);background:#ffffff14;cursor:pointer;transition:background .16s ease,border-color .16s ease}.mini-switch.is-on{background:var(--accent);border-color:var(--accent)}.mini-switch.is-busy{opacity:.6;cursor:default}.mini-switch:disabled{cursor:default}.mini-switch__knob{position:absolute;top:1px;left:1px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000073;transition:transform .16s ease}.mini-switch.is-on .mini-switch__knob{transform:translate(16px)}.mini-switch.is-busy .mini-switch__knob{animation:spin 1s linear infinite}.user-chip__mitm-note{margin:0 4px;padding:2px 4px 6px;font-size:11px;color:var(--text-mute)}.user-chip__mitm-err{margin:2px 4px 6px;padding:5px 8px;font-size:11px;color:var(--danger);background:#ef44441a;border-radius:6px;line-height:1.4}.bcard__top-right{display:inline-flex;align-items:center;gap:6px}.bcard__billing-btn{-webkit-app-region:no-drag;border:1px solid var(--line);background:transparent;color:var(--text-dim);border-radius:7px;padding:3px 9px;font-size:11px;cursor:pointer;transition:color .12s,border-color .12s,background .12s}.bcard__billing-btn:hover{color:var(--accent-text);border-color:var(--accent-line);background:var(--accent-soft)}.glow--app{inset:-10% -10% auto -10%;height:50vh;background:radial-gradient(closest-side at 75% 0%,rgba(91,141,247,.18),transparent 65%),radial-gradient(closest-side at 20% 10%,rgba(167,139,250,.1),transparent 60%);filter:blur(40px)}.main{position:relative;z-index:1;padding:22px 32px 48px;width:100%;display:flex;flex-direction:column;gap:16px;flex:1 1 auto;min-height:0;overflow-y:auto}.main::-webkit-scrollbar{width:8px}.main::-webkit-scrollbar-track{background:transparent}.main::-webkit-scrollbar-thumb{background:#7d87964d;border-radius:999px;border:2px solid transparent;background-clip:padding-box}.main::-webkit-scrollbar-thumb:hover{background-color:#7d87968c}.app__tabs{display:inline-flex;align-items:center;gap:4px;padding:4px;background:#1418208c;border:1px solid rgba(255,255,255,.06);border-radius:10px;align-self:flex-start;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.app__tab{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:0;border-radius:7px;padding:6px 14px;font-size:12.5px;font-weight:500;letter-spacing:.15px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:color .12s ease,background .12s ease}.app__tab:hover{color:#e5e7eb;background:#ffffff0a}.app__tab.is-active{color:#fff;background:#5b8df72e;box-shadow:0 0 0 1px #5b8df74d inset}.app__tab-count{font-size:10.5px;color:#9ca3af;background:#ffffff0f;padding:1px 6px;border-radius:999px;min-width:18px;text-align:center}.app__tab.is-active .app__tab-count{background:#5b8df74d;color:#fff}.app__tabsrow{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%}.app__add-team{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;flex:none;color:#5b8df7;font-weight:600;font-size:12.5px;background:#5b8df71a;border:1px solid rgba(91,141,247,.35);border-radius:9px;padding:7px 14px;transition:color .12s ease,background .12s ease,border-color .12s ease}.app__add-team:hover{color:#fff;background:#5b8df738;border-color:#5b8df7a6}.app__grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.add-card{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:200px;height:200px;background:transparent;border:1.5px dashed rgba(255,255,255,.12);border-radius:14px;color:#9ca3af;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;transition:border-color .16s ease,color .16s ease,background .16s ease}.add-card:hover{border-color:#5b8df780;color:#e5e7eb;background:#5b8df70d}.add-card__plus{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;background:#ffffff0a;font-size:22px;font-weight:300;color:inherit}.add-card__label{font-size:13px;font-weight:500}.bcard--helper{background:linear-gradient(160deg,#5b8df729,#a78bfa24 60%,#1418208c);border-color:#a78bfa40}.bcard--helper .bcard__accent{background:linear-gradient(90deg,#5b8df7,#a78bfa);opacity:1}.bcard--helper:hover{border-color:#a78bfa73}.bcard__pill--helper{background:#a78bfa2e;border-color:#a78bfa4d;color:#c4b5fd;font-size:11px;font-weight:600;letter-spacing:.2px}.bcard__helper-icon{font-size:12px;filter:grayscale(.2)}.bcard__badge--free{background:#34d39926;color:#34d399;border:1px solid rgba(52,211,153,.3)}.bcard__badge--trial{background:#ffffff0f;color:var(--text-dim);border:1px solid var(--line);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard__badge--local{background:#5b8df72e;color:#a5c4ff;border:1px solid rgba(91,141,247,.35);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard--helper .bcard__name{color:#f3f4f6}.bcard__desc{margin:4px 0 0;font-size:11.5px;line-height:1.5;color:#c7cdd6;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.bcard__fineprint{margin:4px 0 0;font-size:10.5px;color:#9ca3af;opacity:.8}.bcard__cta--helper{background:#ffffff0d;box-shadow:none}.bcard__cta--helper:hover{background:var(--accent-soft)}.helper-aside__top{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 10px;border-bottom:1px solid rgba(255,255,255,.05)}.helper-aside__title{font-size:12.5px;font-weight:600;color:#c7cdd6}.helper-aside__close{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:#6b7280;font-size:20px;line-height:1;width:26px;height:26px;border-radius:6px;cursor:pointer;transition:color .12s ease,background .12s ease}.helper-aside__close:hover{color:#e5e7eb;background:#ffffff0f}.helper-modal__backdrop{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:transparent;z-index:20;animation:fadein .14s ease;padding:16px;pointer-events:auto}.helper-modal{width:min(360px,100%);background:linear-gradient(180deg,#1f2733,#1a2029);border:1px solid rgba(255,255,255,.1);border-radius:12px;padding:20px 22px 16px;color:#e5e7eb;box-shadow:0 24px 48px -12px #0009,0 1px #ffffff14 inset;animation:fadein .18s ease}.helper-modal__title{font-size:14px;font-weight:600;color:#f3f4f6;margin-bottom:8px}.helper-modal__desc{font-size:12.5px;line-height:1.6;color:#b6bcc6;margin-bottom:18px}.helper-modal__desc code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11.5px;padding:1px 6px;background:#ffffff14;border:1px solid rgba(255,255,255,.08);border-radius:4px;color:#e7eaef}.helper-modal__actions{display:flex;align-items:center;justify-content:flex-end;gap:8px}.helper-modal__btn{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#ffffff0f;color:#d2d6dd;border:1px solid rgba(255,255,255,.1);border-radius:7px;padding:7px 14px;font-size:12.5px;font-weight:500;cursor:pointer;transition:background .12s ease,color .12s ease,transform 80ms ease}.helper-modal__btn:hover{background:#ffffff1a;color:#fff}.helper-modal__btn:active{transform:translateY(1px)}.helper-modal__btn--ghost{background:transparent;border-color:transparent;color:#ffffff8c;margin-right:auto;padding-left:4px;padding-right:4px}.helper-modal__btn--ghost:hover{background:transparent;color:#ffffffd9}.helper-modal__btn--primary{background:linear-gradient(180deg,#5b8df7,#4570d8);border-color:#ffffff2e;color:#fff}.helper-modal__btn--primary:hover{background:linear-gradient(180deg,#6c9af9,#5a82e0)}.helper-modal__btn:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.helper-placeholder{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:32px 40px;text-align:center;color:#9ca3af}.helper-placeholder__mark{font-size:48px;line-height:1;filter:grayscale(.2);opacity:.85}.helper-placeholder__title{margin:0;font-size:16px;font-weight:600;color:#e5e7eb}.helper-placeholder__sub{margin:0;font-size:12.5px;line-height:1.6;color:#9ca3af;max-width:320px}.helper-placeholder__note{margin-top:8px;font-size:11px;color:#6b7280;padding:4px 10px;background:#ffffff08;border:1px solid rgba(255,255,255,.06);border-radius:999px}.helper-placeholder__note code{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11px;color:#c7cdd6}.section{background:linear-gradient(180deg,#141820b8,#0d1016b8);border:1px solid rgba(255,255,255,.06);border-radius:14px;box-shadow:0 1px #ffffff0a inset,0 14px 30px #00000052;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);padding:18px 18px 16px}.section-head{display:flex;align-items:center;gap:8px;padding:0 4px 14px;border-bottom:1px solid rgba(255,255,255,.04);margin-bottom:14px}.section-icon{font-size:14px;opacity:.8}.section-head h2{margin:0;font-size:13.5px;font-weight:600;color:#e5e7eb;letter-spacing:.2px}.section-sub{font-size:12px;color:#6b7280}.section-body{display:flex;flex-direction:column;gap:10px}.grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.bcard{position:relative;width:200px;height:200px;background:#1418208c;border:1px solid rgba(255,255,255,.07);border-radius:14px;padding:16px;display:flex;flex-direction:column;overflow:hidden;transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease;--brand: #5b8df7;--accent-cloud: #f59e0b;--accent-custom: #8b5cf6}.bcard:hover{transform:translateY(-2px);border-color:#ffffff24;box-shadow:0 12px 32px -10px #00000073,0 1px #ffffff0a inset}.bcard__accent{position:absolute;top:0;left:0;right:0;height:3px;background:var(--brand);opacity:.9}.bcard--cloud .bcard__accent{background:var(--accent-cloud)}.bcard--custom .bcard__accent{background:var(--accent-custom)}.bcard--online:before{content:"";position:absolute;bottom:-40%;right:-20%;width:140%;height:100%;background:radial-gradient(circle at center,rgba(91,141,247,.22) 0%,transparent 60%);pointer-events:none;opacity:.55}.bcard--cloud.bcard--online:before{background:radial-gradient(circle at center,rgba(245,158,11,.22) 0%,transparent 60%)}.bcard--custom.bcard--online:before{background:radial-gradient(circle at center,rgba(139,92,246,.22) 0%,transparent 60%)}.bcard__top{display:flex;align-items:center;justify-content:space-between;position:relative;z-index:5}.bcard__pill{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:#08090eb3;border:1px solid rgba(255,255,255,.07);border-radius:999px;color:#9ca3af}.bcard__pill svg{display:block}.bcard__dot{width:7px;height:7px;border-radius:50%;background:#6b7280;flex-shrink:0}.bcard__dot[data-tone=ok]{background:#34d399;box-shadow:0 0 0 2px #34d39940}.bcard__dot[data-tone=off]{background:#6b7280}.bcard__dot[data-tone=warn]{background:#fbbf24;box-shadow:0 0 0 2px #fbbf2440}.bcard__dot[data-tone=err]{background:#f87171;box-shadow:0 0 0 2px #f8717140}.bcard__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--accent-soft);color:var(--accent-text);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px}.bcard__body{flex:1;display:flex;flex-direction:column;gap:4px;padding-top:12px;padding-bottom:12px;position:relative;z-index:1;min-width:0}.bcard__name{margin:0;font-size:17px;font-weight:700;color:#e5e7eb;letter-spacing:-.015em;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__host{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,monospace;font-size:11px;color:#9ca3af;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__meta{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.bcard__chip{font-size:10.5px;color:#9ca3af;background:#ffffff08;border:1px solid rgba(255,255,255,.06);padding:2px 7px;border-radius:999px}.bcard__cta{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;height:38px;border:1px solid var(--line);border-radius:9px;background:#ffffff0d;color:var(--text);font-size:13px;font-weight:600;letter-spacing:.1px;cursor:pointer;transition:transform 80ms ease,background .14s ease,border-color .14s ease,color .14s ease;box-shadow:none}.bcard--cloud .bcard__cta,.bcard--custom .bcard__cta{background:#ffffff0d;box-shadow:none}.bcard__cta:hover{background:var(--accent-soft);border-color:var(--accent-line);color:var(--accent-text)}.bcard__cta:active{transform:translateY(1px)}.bcard__cta:disabled{background:#ffffff08;color:#6b7280;cursor:not-allowed;box-shadow:none;border:1px solid rgba(255,255,255,.06)}.empty{font-size:12.5px;color:#6b7280;padding:14px 16px;background:#ffffff05;border:1px dashed rgba(255,255,255,.08);border-radius:10px}.bcard__menuwrap{position:relative}.bcard__kebab{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid transparent;border-radius:8px;background:transparent;color:#8b949e;cursor:pointer;transition:.15s}.bcard__kebab:hover:not(:disabled){color:#e6edf3;background:#ffffff0f;border-color:#ffffff1f}.bcard__kebab:disabled{opacity:.5;cursor:default}.bcard__kebab.has-dot{color:#e6edf3}.bcard__kebab.has-dot:after{content:"";position:absolute;top:3px;right:3px;width:7px;height:7px;border-radius:50%;background:#f59e0b;box-shadow:0 0 0 2px #0f1115}.bcard__menu{position:absolute;top:32px;right:0;z-index:20;min-width:150px;padding:5px;background:#1b2027;border:1px solid rgba(255,255,255,.12);border-radius:10px;box-shadow:0 10px 30px #00000073;display:flex;flex-direction:column;gap:2px}.bcard__menu-item{text-align:left;width:100%;border:none;background:transparent;color:#d1d5db;border-radius:7px;padding:7px 10px;font-size:12.5px;cursor:pointer;transition:.12s}.bcard__menu-item:hover{background:#ffffff12;color:#fff}.bcard__menu-item.is-accent{color:var(--accent-text);font-weight:600}.bcard__menu-item.is-accent:hover{background:var(--accent-soft);color:#c7dbff}.bcard__menu-item.is-danger{color:#f7a3a3}.bcard__menu-item.is-danger:hover{background:#ef444429;color:#fff}.bcard__menu--portal{z-index:9990}.bcard__menu--portal .bcard__menu-item{white-space:normal;word-break:break-word}.docker-setup{margin-bottom:14px;padding:14px 16px;background:linear-gradient(180deg,#5b8df714,#14182080);border:1px solid rgba(91,141,247,.22);border-radius:12px}.docker-setup__head{display:flex;flex-direction:column;gap:3px;margin-bottom:12px}.docker-setup__title{font-size:13.5px;font-weight:600;color:#e6edf3}.docker-setup__sub{font-size:11.5px;color:#9ca3af;line-height:1.5}.docker-setup__steps{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.docker-step{display:flex;align-items:center;gap:8px;font-size:12px;color:#9ca3af}.docker-step__dot{width:8px;height:8px;border-radius:50%;flex:none;background:#3a4150;transition:.2s}.docker-step__label{color:#c7cdd6;min-width:96px}.docker-step__msg{color:#8b949e;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docker-step__pct{margin-left:auto;font-variant-numeric:tabular-nums;color:#5b8df7;flex:none}.docker-step.is-running .docker-step__dot{background:#5b8df7;box-shadow:0 0 0 3px #5b8df72e;animation:dpulse 1.2s ease-in-out infinite}.docker-step.is-running .docker-step__label{color:#e6edf3}.docker-step.is-done .docker-step__dot,.docker-step.is-skip .docker-step__dot{background:#10b981}.docker-step.is-skip{opacity:.7}.docker-step.is-retry .docker-step__dot{background:#f59e0b}.docker-step.is-error .docker-step__dot{background:#ef4444;box-shadow:0 0 0 3px #ef444426}.docker-step.is-error .docker-step__msg{color:#f7a3a3}@keyframes dpulse{0%,to{opacity:1}50%{opacity:.45}}.docker-setup__actions{display:flex;gap:8px;align-items:center}.docker-setup__actions .btn-primary{width:auto;padding:7px 16px;font-size:12.5px}.bcard__ver{font-size:11px;color:#8b949e;font-variant-numeric:tabular-nums}.bcard__chip--new{color:var(--accent-text);background:var(--accent-soft);border-color:var(--accent-line)}.bcard__opmsg{display:flex;align-items:center;gap:6px;margin-top:9px;font-size:11.5px;color:#9ca3af;word-break:break-word}.toast-host{position:fixed;right:16px;bottom:16px;z-index:9999;display:flex;flex-direction:column;gap:8px;max-width:min(360px,calc(100vw - 32px));pointer-events:none}.toast{pointer-events:auto;position:relative;display:flex;flex-direction:column;gap:6px;padding:10px 30px 10px 12px;font-size:12.5px;line-height:1.4;color:var(--text, #e6eaf0);background:#161a21f5;border:1px solid rgba(125,135,150,.22);border-left:3px solid var(--accent, #3b82f6);border-radius:10px;box-shadow:0 8px 28px #0000006b;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);animation:toast-in .18s ease}@keyframes toast-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.toast[data-status=error]{border-left-color:#f87171}.toast[data-status=error] .toast__msg{color:#f87171}.toast[data-status=done]{border-left-color:#4ade80}.toast[data-status=done] .toast__msg{color:#4ade80}.toast__msg{word-break:break-word}.toast__x{position:absolute;top:6px;right:8px;background:none;border:none;cursor:pointer;padding:0;font-size:15px;line-height:1;color:var(--text-dim, #9da7b3)}.toast__x:hover{color:var(--text, #e6eaf0)}.toast__bar{display:block;height:4px;border-radius:2px;background:#7d879640;overflow:hidden}.toast__bar>span{display:block;height:100%;border-radius:2px;background:var(--accent, #3b82f6);transition:width .25s ease}.drawer-scrim{position:fixed;top:0;right:0;bottom:0;left:0;z-index:10000;display:flex;align-items:flex-end;justify-content:center;background:#06080c80;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);animation:drawer-fade .18s ease}@keyframes drawer-fade{0%{opacity:0}to{opacity:1}}.drawer{width:min(560px,calc(100vw - 24px));max-height:76vh;display:flex;flex-direction:column;margin-bottom:12px;background:#14181ffa;border:1px solid rgba(125,135,150,.2);border-radius:16px 16px 12px 12px;box-shadow:0 -10px 44px #00000080;overflow:hidden;animation:drawer-up .24s cubic-bezier(.22,1,.36,1)}@keyframes drawer-up{0%{opacity:0;transform:translateY(28px)}to{opacity:1;transform:none}}.drawer__head{display:flex;align-items:center;justify-content:space-between;padding:14px 14px 12px 16px;border-bottom:1px solid rgba(125,135,150,.14)}.drawer__title{display:flex;align-items:center;gap:11px}.drawer__spark{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:8px;font-size:14px;font-weight:700;background:#5b8df729;color:var(--brand, #5b8df7)}.drawer__spark--done{background:#4ade8029;color:#4ade80}.drawer__spark--error{background:#f8717129;color:#f87171}.drawer__h{font-size:13.5px;font-weight:650;color:var(--text, #e6eaf0)}.drawer__sub{font-size:11.5px;color:var(--text-dim, #9da7b3);margin-top:1px}.drawer__x{background:none;border:none;cursor:pointer;padding:2px 6px;font-size:19px;line-height:1;color:var(--text-dim, #9da7b3);border-radius:6px}.drawer__x:hover:not(:disabled){color:var(--text, #e6eaf0);background:#7d87961f}.drawer__x:disabled{opacity:.35;cursor:default}.drawer__steps{display:flex;align-items:center;gap:0;padding:14px 18px 4px}.drawer__step{display:flex;align-items:center;gap:7px;color:var(--text-dim, #9da7b3);font-size:12px}.drawer__step-dot{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;font-size:11px;font-weight:700;border:1.5px solid rgba(125,135,150,.35);color:var(--text-dim, #9da7b3);background:transparent;flex:none}.drawer__step-bar{width:30px;height:1.5px;background:#7d879640;margin:0 8px}.drawer__step.is-active .drawer__step-dot{border-color:var(--brand, #5b8df7);color:var(--brand, #5b8df7);box-shadow:0 0 0 3px #5b8df72e}.drawer__step.is-active .drawer__step-label{color:var(--text, #e6eaf0)}.drawer__step.is-done .drawer__step-dot{border-color:#4ade80;color:#06210f;background:#4ade80}.drawer__step.is-done .drawer__step-bar{background:#4ade8080}.drawer__step.is-error .drawer__step-dot{border-color:#f87171;color:#f87171}.drawer__log{flex:1;min-height:96px;overflow-y:auto;margin:10px 14px;padding:10px 12px;background:#0a0c10b3;border:1px solid rgba(125,135,150,.12);border-radius:10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;line-height:1.7}.drawer__log-empty{color:var(--text-dim, #9da7b3)}.drawer__line{display:flex;align-items:baseline;gap:8px;padding:1px 0}.drawer__t{color:#6b7686;flex:none;font-variant-numeric:tabular-nums}.drawer__badge{flex:none;padding:0 6px;border-radius:4px;font-size:10px;font-weight:600;background:#5b8df729;color:#8fb0f5}.drawer__badge--swap{background:#f59e0b29;color:#f5b342}.drawer__badge--done{background:#4ade8029;color:#6ee79b}.drawer__linemsg{color:var(--text, #e6eaf0);word-break:break-word}.drawer__line[data-status=error] .drawer__linemsg{color:#f87171}.drawer__line[data-status=done] .drawer__linemsg{color:#6ee79b}.drawer__line[data-status=skip] .drawer__linemsg{color:var(--text-dim, #9da7b3)}.drawer__hint{margin:0 14px 8px;padding:8px 12px;background:#f59e0b1a;border:1px solid rgba(245,158,11,.28);border-radius:8px;color:#f5b342;font-size:11.5px;line-height:1.5}.drawer__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid rgba(125,135,150,.14)}.drawer__foot-status{font-size:12.5px;color:var(--text-dim, #9da7b3);margin-right:auto}.drawer__foot-status.is-error{color:#f87171}.drawer__foot-status.is-done{color:#4ade80}.drawer__btn{padding:7px 16px;border-radius:8px;cursor:pointer;font-size:12.5px;font-weight:550;background:#7d879624;border:1px solid rgba(125,135,150,.2);color:var(--text, #e6eaf0)}.drawer__btn:hover{background:#7d879638}.drawer__btn.is-accent{background:var(--brand, #5b8df7);border-color:var(--brand, #5b8df7);color:#fff}.drawer__btn.is-accent:hover{filter:brightness(1.08)}.mitm-card{border:1px solid rgba(125,135,150,.22);border-radius:12px;padding:14px 16px;margin-bottom:14px;background:#1e242e66}.mitm-card--on{border-color:#4ade8059;background:#16281e66}.mitm-pill{position:fixed;top:64px;right:16px;z-index:9998;-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:8px;padding:4px 6px 4px 11px;border-radius:999px;width:fit-content;max-width:calc(100vw - 32px);background:#141e18d9;border:1px solid rgba(74,222,128,.3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);box-shadow:0 4px 14px #0000004d;font-size:12px;line-height:1}.mitm-pill__dot{width:7px;height:7px;border-radius:50%;flex:none;background:#4ade80;box-shadow:0 0 0 3px #4ade8029}.mitm-pill__dot[data-busy="1"]{background:#9da7b3;box-shadow:0 0 0 3px #9da7b329}.mitm-pill__text{color:var(--text-dim, #9da7b3);white-space:nowrap}.mitm-pill__off{background:none;border:none;cursor:pointer;color:#6b7686;font-size:11.5px;padding:3px 7px;border-radius:999px}.mitm-pill__off:hover{color:#f87171;background:#f871711a}.mitm-card__head{display:flex;align-items:center;gap:8px;margin-bottom:6px}.mitm-card__dot{width:8px;height:8px;border-radius:50%;background:#9da7b3;flex:0 0 auto}.mitm-card__dot[data-state=on]{background:#4ade80;box-shadow:0 0 6px #4ade8099}.mitm-card__dot[data-state=warn]{background:#fbbf24}.mitm-card__dot[data-state=off]{background:#60a5fa}.mitm-card__title{font-size:14px;font-weight:600;color:var(--text, #e6edf3)}.mitm-card__desc{font-size:12.5px;line-height:1.5;color:var(--text-dim, #9da7b3);margin:0 0 10px}.mitm-card__note{color:#fbbf24}.mitm-card__error{font-size:12px;color:#f87171;margin-bottom:8px}.mitm-card__actions{display:flex;gap:8px}.mitm-card__btn{font-size:13px;padding:7px 16px;border-radius:8px;border:none;cursor:pointer;background:var(--accent, #3b82f6);color:#fff;font-weight:500}.mitm-card__btn:disabled{opacity:.6;cursor:default}.mitm-card__btn--ghost{background:transparent;border:1px solid rgba(125,135,150,.35);color:var(--text-dim, #9da7b3)}.mitm-card__sub{color:var(--text-dim, #9da7b3);opacity:.8;font-size:11.5px}.terms-gate{display:flex;align-items:center;justify-content:center;padding:24px}.terms-gate__panel,.terms-gate__panel *{-webkit-app-region:no-drag}.terms-gate__panel{position:relative;z-index:1;width:min(680px,94vw);max-height:90vh;display:flex;flex-direction:column;background:#141921eb;border:1px solid rgba(125,135,150,.22);border-radius:16px;padding:28px 30px;box-shadow:0 24px 60px #00000080}.terms-gate__title{font-size:20px;font-weight:700;margin:0 0 4px;color:var(--text, #e6edf3)}.terms-gate__subtitle{font-size:13px;color:var(--text-dim, #9da7b3);margin:0 0 16px}.terms-gate__body{overflow-y:auto;flex:1 1 auto;min-height:0;padding-right:8px;border-top:1px solid rgba(125,135,150,.15);border-bottom:1px solid rgba(125,135,150,.15);padding-top:14px;padding-bottom:14px}.terms-gate__h2{font-size:14px;font-weight:600;margin:0 0 10px;color:var(--text, #e6edf3)}.terms-gate__summary{margin:0 0 14px;padding-left:20px}.terms-gate__summary li{font-size:13px;line-height:1.6;color:var(--text-dim, #c2cbd6);margin-bottom:8px}.terms-gate__viewfull{background:none;border:none;color:var(--accent, #3b82f6);cursor:pointer;font-size:13px;padding:4px 0;text-decoration:underline}.terms-gate__fulltext{white-space:pre-wrap;word-break:break-word;font-size:12px;line-height:1.6;color:var(--text-dim, #b3bcc8);background:#0003;border-radius:8px;padding:14px;margin:10px 0 0;font-family:inherit}.terms-gate__scrollhint{font-size:12px;color:#fbbf24;text-align:center;margin:12px 0 0}.terms-gate__actions{display:flex;gap:12px;justify-content:flex-end;margin-top:18px}.terms-gate__btn{font-size:14px;padding:10px 22px;border-radius:9px;border:none;cursor:pointer;background:var(--accent, #3b82f6);color:#fff;font-weight:600}.terms-gate__btn:disabled{opacity:.45;cursor:not-allowed}.terms-gate__btn--ghost{background:transparent;border:1px solid rgba(125,135,150,.35);color:var(--text-dim, #9da7b3);font-weight:500}
|