dsh-dock 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.js CHANGED
@@ -41,7 +41,7 @@ __export(client_exports, {
41
41
  inject: () => inject
42
42
  });
43
43
  module.exports = __toCommonJS(client_exports);
44
- var import_react7 = __toESM(require("react"), 1);
44
+ var import_react8 = __toESM(require("react"), 1);
45
45
 
46
46
  // src/shared.js
47
47
  var import_react = __toESM(require("react"), 1);
@@ -70,9 +70,29 @@ var stateListeners = /* @__PURE__ */ new Set();
70
70
  function notifyState() {
71
71
  for (const fn of stateListeners) fn();
72
72
  }
73
+ var FEATURE_STORE_KEY = "dsh-dock/features/v1";
74
+ var featurePersist = { map: {} };
75
+ try {
76
+ if (typeof localStorage !== "undefined") {
77
+ const raw = localStorage.getItem(FEATURE_STORE_KEY);
78
+ const obj = raw ? JSON.parse(raw) : null;
79
+ if (obj && typeof obj === "object") featurePersist.map = obj;
80
+ }
81
+ } catch {
82
+ }
83
+ function persistFeatureEnabled() {
84
+ try {
85
+ if (typeof localStorage !== "undefined") localStorage.setItem(FEATURE_STORE_KEY, JSON.stringify(featurePersist.map));
86
+ } catch {
87
+ }
88
+ }
73
89
  function initFeatureState(defs) {
74
90
  for (const f of defs) {
75
- if (!featureState.has(f.id)) featureState.set(f.id, { enabled: !f.planned && f.defaultEnabled !== false, error: null });
91
+ if (featureState.has(f.id)) continue;
92
+ let enabled = !f.planned && f.defaultEnabled !== false;
93
+ const saved = featurePersist.map[f.id];
94
+ if (typeof saved === "boolean") enabled = saved;
95
+ featureState.set(f.id, { enabled, error: null });
76
96
  }
77
97
  }
78
98
  function stateOf(id) {
@@ -86,6 +106,8 @@ function stateOf(id) {
86
106
  function toggleFeature(id) {
87
107
  const st = stateOf(id);
88
108
  st.enabled = !st.enabled;
109
+ featurePersist.map[id] = st.enabled;
110
+ persistFeatureEnabled();
89
111
  notifyState();
90
112
  }
91
113
  function subscribeFeatureState(fn) {
@@ -1025,6 +1047,11 @@ function ModelsView() {
1025
1047
  import_react3.default.createElement("span", { className: "dkm-badge" }, vpDraft.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
1026
1048
  import_react3.default.createElement("span", { className: "dkm-sub" }, "\u7EAF\u6587\u672C\u6A21\u578B\u6536\u5230\u56FE\u7247\u65F6\u81EA\u52A8\u8C03\u7528\u6240\u9009\u89C6\u89C9\u6A21\u578B\u8BC6\u522B\uFF0C\u8BC6\u522B\u6587\u672C\u66FF\u6362\u56FE\u7247\uFF1B\u591A\u6A21\u6001\u6A21\u578B\u539F\u6837\u81EA\u8BC6\u522B")
1027
1049
  ),
1050
+ import_react3.default.createElement(
1051
+ "div",
1052
+ { className: "dkm-note dkm-warn" },
1053
+ "\u26A0 \u672C\u529F\u80FD\u4F1A\u8C03\u7528\u89C6\u89C9\u6A21\u578B\u8BC6\u522B\u56FE\u7247\uFF0C\u6D88\u8017 token\uFF08\u6BCF\u6B21\u8BC6\u56FE\u6309\u89C6\u89C9\u6A21\u578B\u8BA1\u8D39\uFF09\u3002\u9ED8\u8BA4\u5173\u95ED\uFF1B\u4E0D\u5F00\u542F\u5219\u63D2\u4EF6\u5176\u4F59\u529F\u80FD\u5747\u4E0D\u6D88\u8017\u4EFB\u4F55 token\u3002"
1054
+ ),
1028
1055
  import_react3.default.createElement(
1029
1056
  "div",
1030
1057
  { className: "dkm-checks" },
@@ -1182,6 +1209,7 @@ var feature2 = {
1182
1209
  description: "\u7F16\u8F91\u5404 Provider \u6A21\u578B\u76EE\u5F55\uFF1A\u8F93\u5165\u7C7B\u578B\uFF08\u6587\u672C/\u56FE\u7247 + \u6807\u6CE8\uFF09\u4E0E\u601D\u8003\u5F3A\u5EA6\u6863\u4F4D\uFF1B\u5199\u56DE\u5B98\u65B9\u914D\u7F6E\u70ED\u751F\u6548\uFF0C\u4F1A\u8BDD\u6A21\u578B\u9009\u62E9\u5668\u5373\u65F6\u53EF\u9009",
1183
1210
  css: [
1184
1211
  ".dkm-note{color:var(--dsw-alias-label-secondary);font-size:12px;}",
1212
+ ".dkm-warn{color:var(--dsw-alias-state-warning-primary);}",
1185
1213
  ".dkm-error{color:var(--dsw-alias-state-error-primary);font-size:12px;}",
1186
1214
  ".dkm-chips{display:flex;flex-wrap:wrap;gap:6px;}",
1187
1215
  ".dkm-chip{cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);border-radius:999px;padding:3px 12px;font-family:inherit;font-size:12px;}",
@@ -1302,7 +1330,6 @@ var CURATED_ACCENTS = {
1302
1330
  anthropic: "#d97757",
1303
1331
  "google-gemini": "#4285f4"
1304
1332
  };
1305
- var C_TOTAL = "#34d399";
1306
1333
  var C_GRANTED = "#22d3ee";
1307
1334
  var C_TOPUP = "#fbbf24";
1308
1335
  var C_ERR = "#f87171";
@@ -1378,10 +1405,12 @@ function BalanceView(props) {
1378
1405
  } else if (providers.length === 0) {
1379
1406
  body.push(import_react6.default.createElement("div", { key: "empty", className: "dkb-note" }, "\u6CA1\u6709\u627E\u5230\u5DF2\u914D\u7F6E\u7684\u6A21\u578B Provider"));
1380
1407
  } else {
1408
+ const rank = (p) => p.balance && p.balance.status === "ok" ? 0 : p.balance && p.balance.status === "login-required" ? 1 : 2;
1409
+ const sorted = providers.slice().sort((a, b) => rank(a) - rank(b));
1381
1410
  body.push(import_react6.default.createElement(
1382
1411
  "div",
1383
1412
  { key: "rows", className: "dkb-rows" },
1384
- providers.map((p) => {
1413
+ sorted.map((p) => {
1385
1414
  const accent = accentOf(p.id);
1386
1415
  const b = p.balance;
1387
1416
  let badge = ["\u672A\u77E5", ""];
@@ -1392,48 +1421,64 @@ function BalanceView(props) {
1392
1421
  else if (b.status === "login-required") badge = ["\u9700\u767B\u5F55", "warn"];
1393
1422
  else badge = ["\u67E5\u8BE2\u5931\u8D25", "err"];
1394
1423
  }
1395
- const sub = ["ID: " + p.id, p.api ? "api: " + p.api : null, p.baseURL ? p.baseURL : null].filter(Boolean).join(" \xB7 ");
1396
- const cells = [];
1397
1424
  let balBody = null;
1398
1425
  if (b && b.status === "ok" && b.kind === "quota") {
1399
- cells.push(import_react6.default.createElement(
1400
- "div",
1401
- { key: "q", className: "dkb-bal" },
1402
- import_react6.default.createElement("span", { className: "dkb-cur", style: { color: accent } }, "\u603B\u989D\u5EA6"),
1403
- import_react6.default.createElement("span", { className: "dkb-total", style: { color: C_TOTAL } }, "\u5269\u4F59 " + fmt(b.remaining) + (b.unit ? " " + b.unit : "")),
1404
- import_react6.default.createElement("span", { className: "dkb-part" }, "\u5DF2\u7528 " + fmt(b.used) + " / \u603B " + fmt(b.limit)),
1405
- b.resetTime ? import_react6.default.createElement("span", { className: "dkb-part" }, "\u91CD\u7F6E " + String(b.resetTime).slice(0, 16)) : null
1406
- ));
1407
- (Array.isArray(b.dims) ? b.dims : []).forEach((d, i) => {
1408
- cells.push(import_react6.default.createElement(
1426
+ const dims = Array.isArray(b.dims) ? b.dims : [];
1427
+ balBody = import_react6.default.createElement(
1428
+ import_react6.default.Fragment,
1429
+ null,
1430
+ import_react6.default.createElement(
1409
1431
  "div",
1410
- { key: "d" + i, className: "dkb-bal" },
1411
- import_react6.default.createElement("span", { className: "dkb-cur", style: { color: accent } }, d.window === "weekly" ? "\u5468\u989D\u5EA6" : "\u5C0F\u65F6\u989D\u5EA6"),
1412
- import_react6.default.createElement("span", { className: "dkb-total", style: { color: C_TOTAL } }, "\u5269\u4F59 " + fmt(d.remaining)),
1413
- import_react6.default.createElement("span", { className: "dkb-part" }, "\u5DF2\u7528 " + fmt(d.used) + " / " + fmt(d.limit)),
1414
- d.resetTime ? import_react6.default.createElement("span", { className: "dkb-part" }, "\u91CD\u7F6E " + String(d.resetTime).slice(0, 16)) : null
1415
- ));
1416
- });
1432
+ { className: "dkb-main" },
1433
+ import_react6.default.createElement("span", { className: "dkb-main-label" }, "\u5269\u4F59\u989D\u5EA6"),
1434
+ import_react6.default.createElement("span", { className: "dkb-main-value" }, fmt(b.remaining) + (b.unit ? " " + b.unit : "")),
1435
+ import_react6.default.createElement(
1436
+ "span",
1437
+ { className: "dkb-main-part" },
1438
+ "\u5DF2\u7528 " + fmt(b.used) + " / \u603B " + fmt(b.limit),
1439
+ b.resetTime ? import_react6.default.createElement("span", null, " \xB7 \u91CD\u7F6E " + String(b.resetTime).slice(0, 10)) : null
1440
+ )
1441
+ ),
1442
+ dims.map((d, i) => import_react6.default.createElement(
1443
+ "div",
1444
+ { key: "d" + i, className: "dkb-dim" },
1445
+ import_react6.default.createElement("span", { className: "dkb-dim-label" }, d.window === "weekly" ? "\u5468\u989D\u5EA6" : "\u5C0F\u65F6\u989D\u5EA6"),
1446
+ import_react6.default.createElement(
1447
+ "span",
1448
+ { className: "dkb-dim-bar" },
1449
+ import_react6.default.createElement("span", { className: "dkb-dim-fill", style: { width: (d.limit > 0 ? Math.min(100, Math.round(d.remaining / d.limit * 100)) : 0) + "%" } })
1450
+ ),
1451
+ import_react6.default.createElement("span", { className: "dkb-dim-text" }, "\u5269 " + fmt(d.remaining) + " / " + fmt(d.limit))
1452
+ ))
1453
+ );
1417
1454
  } else if (b && b.status === "ok") {
1418
1455
  const infos = Array.isArray(b.infos) ? b.infos : [];
1419
- cells.push(infos.map((i, idx) => import_react6.default.createElement(
1456
+ balBody = import_react6.default.createElement(
1420
1457
  "div",
1421
- { key: idx, className: "dkb-bal" },
1422
- import_react6.default.createElement("span", { className: "dkb-cur", style: { color: accent } }, i.currency),
1423
- import_react6.default.createElement("span", { className: "dkb-total", style: { color: C_TOTAL } }, "\u603B\u989D " + fmt(i.totalBalance)),
1424
- i.grantedBalance != null ? import_react6.default.createElement("span", { className: "dkb-part", style: { color: C_GRANTED } }, "\u8D60\u9001 " + fmt(i.grantedBalance)) : null,
1425
- i.toppedUpBalance != null ? import_react6.default.createElement("span", { className: "dkb-part", style: { color: C_TOPUP } }, "\u5145\u503C " + fmt(i.toppedUpBalance)) : null
1426
- )));
1458
+ { className: "dkb-mains" },
1459
+ infos.map((i, idx) => import_react6.default.createElement(
1460
+ "div",
1461
+ { key: idx, className: "dkb-main" },
1462
+ import_react6.default.createElement("span", { className: "dkb-main-label", style: { color: accent } }, i.currency),
1463
+ import_react6.default.createElement("span", { className: "dkb-main-value" }, fmt(i.totalBalance)),
1464
+ import_react6.default.createElement(
1465
+ "span",
1466
+ { className: "dkb-main-parts" },
1467
+ i.grantedBalance != null ? import_react6.default.createElement("span", { className: "dkb-main-part", style: { color: C_GRANTED } }, "\u8D60\u9001 " + fmt(i.grantedBalance)) : null,
1468
+ i.toppedUpBalance != null ? import_react6.default.createElement("span", { className: "dkb-main-part", style: { color: C_TOPUP } }, "\u5145\u503C " + fmt(i.toppedUpBalance)) : null
1469
+ )
1470
+ ))
1471
+ );
1427
1472
  } else if (b && b.status === "login-required" && b.consoleUrl) {
1428
1473
  balBody = import_react6.default.createElement(
1429
1474
  "div",
1430
- { className: "dkb-bal" },
1475
+ { className: "dkb-main" },
1431
1476
  import_react6.default.createElement("a", { href: b.consoleUrl, target: "_blank", rel: "noreferrer", className: "dkb-link", style: { color: accent } }, "\u53BB\u63A7\u5236\u53F0\u67E5\u770B\u4F59\u989D \u2192")
1432
1477
  );
1433
1478
  } else {
1434
- balBody = import_react6.default.createElement("div", { className: "dkb-note" }, b && b.message || "\u672A\u77E5\u72B6\u6001");
1479
+ balBody = b && b.message ? import_react6.default.createElement("div", { className: "dkb-note" }, b.message) : import_react6.default.createElement("div", { className: "dkb-note" }, "\u8BE5 Provider \u6CA1\u6709\u5DF2\u77E5\u7684\u4F59\u989D\u67E5\u8BE2\u63A5\u53E3");
1435
1480
  }
1436
- if (cells.length > 0) balBody = import_react6.default.createElement("div", { className: "dkb-rows" }, cells);
1481
+ const sub = ["ID " + p.id, p.api, p.baseURL ? p.baseURL.replace(/^https?:\/\//, "") : null].filter(Boolean).join(" \xB7 ");
1437
1482
  return import_react6.default.createElement(
1438
1483
  "div",
1439
1484
  { key: p.id, className: "dkb-row", "data-dock-provider": p.id },
@@ -1443,7 +1488,17 @@ function BalanceView(props) {
1443
1488
  import_react6.default.createElement("span", { className: "dkb-dot", style: { background: accent } }),
1444
1489
  import_react6.default.createElement("span", { className: "dkb-name", style: { color: accent } }, p.displayName),
1445
1490
  def === p.id ? import_react6.default.createElement("span", { className: "dkb-default" }, "\u9ED8\u8BA4") : null,
1446
- import_react6.default.createElement("span", { className: "dkb-badge" + (badge[1] ? " " + badge[1] : ""), style: badge[1] === "err" ? { color: C_ERR, borderColor: C_ERR } : null }, badge[0])
1491
+ import_react6.default.createElement("span", { className: "dkb-badge" + (badge[1] ? " " + badge[1] : ""), style: badge[1] === "err" ? { color: C_ERR, borderColor: C_ERR } : null }, badge[0]),
1492
+ // 模型数折叠提示(点开展开 chips)
1493
+ p.models && p.models.length > 0 ? import_react6.default.createElement("button", {
1494
+ type: "button",
1495
+ className: "dkb-models-toggle",
1496
+ title: p.models.join(", "),
1497
+ onClick: (e) => {
1498
+ const row = e.currentTarget.closest(".dkb-row");
1499
+ if (row) row.classList.toggle("dkb-models-open");
1500
+ }
1501
+ }, p.models.length + " \u4E2A\u6A21\u578B \u25BE") : null
1447
1502
  ),
1448
1503
  sub ? import_react6.default.createElement("div", { className: "dkb-sub" }, sub) : null,
1449
1504
  p.apiKeyEnv ? import_react6.default.createElement("div", { className: "dkb-sub" }, "\u5BC6\u94A5: " + p.apiKeyEnv + (p.credentialConfigured ? " \u2713" : " \u2717")) : null,
@@ -1465,7 +1520,7 @@ function BalanceView(props) {
1465
1520
  import_react6.default.createElement(
1466
1521
  "div",
1467
1522
  { className: "dkb-note" },
1468
- data && !snap.error && providers.length > 0 ? okCount + "/" + providers.length + " \u4E2A Provider \u53EF\u67E5\u4F59\u989D" : "\u6A21\u578B\u4F59\u989D \xB7 Host \u534A\u90E8\u5B9E\u65F6\u62C9\u53D6"
1523
+ data && !snap.error && providers.length > 0 ? okCount + "/" + providers.length + " \u4E2A Provider \u53EF\u67E5\u4F59\u989D\uFF08\u53EF\u67E5\u7684\u6392\u524D\u9762\uFF09" : "\u6A21\u578B\u4F59\u989D \xB7 Host \u534A\u90E8\u5B9E\u65F6\u62C9\u53D6"
1469
1524
  ),
1470
1525
  body,
1471
1526
  import_react6.default.createElement(
@@ -1571,8 +1626,9 @@ var feature5 = {
1571
1626
  css: [
1572
1627
  ".dkb-note{color:var(--dsw-alias-label-secondary);font-size:12px;}",
1573
1628
  ".dkb-error{color:var(--dsw-alias-state-error-primary);}",
1574
- ".dkb-rows{display:flex;flex-direction:column;gap:8px;}",
1575
- ".dkb-row{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:8px 10px;display:flex;flex-direction:column;gap:5px;}",
1629
+ ".dkb-rows{display:flex;flex-direction:column;gap:10px;}",
1630
+ // Provider 卡片:行距收窄、留白分层
1631
+ ".dkb-row{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 14px 12px;display:flex;flex-direction:column;gap:6px;}",
1576
1632
  ".dkb-row-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
1577
1633
  ".dkb-dot{width:8px;height:8px;border-radius:50%;flex:none;}",
1578
1634
  ".dkb-name{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary);}",
@@ -1581,13 +1637,28 @@ var feature5 = {
1581
1637
  ".dkb-badge.ok{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
1582
1638
  ".dkb-badge.warn{color:var(--dsw-alias-state-warning-primary);border-color:currentColor;}",
1583
1639
  ".dkb-badge.err{color:var(--dsw-alias-state-error-primary);border-color:currentColor;}",
1640
+ // 模型数折叠开关(点行头右侧"N 个模型 ▾"展开/收起 chips)
1641
+ ".dkb-models-toggle{margin-left:auto;cursor:pointer;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);font-family:inherit;font-size:11px;padding:1px 6px;border-radius:6px;white-space:nowrap;}",
1642
+ ".dkb-models-toggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
1643
+ ".dkb-row:not(.dkb-models-open) .dkb-chips{display:none;}",
1644
+ '.dkb-row.dkb-models-open .dkb-models-toggle::after{content:"";}',
1645
+ // 连接信息弱化单行(省略 URL 协议头、超出省略号)
1584
1646
  ".dkb-sub{color:var(--dsw-alias-label-tertiary);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
1585
- ".dkb-chips{display:flex;flex-wrap:wrap;gap:4px;}",
1647
+ ".dkb-chips{display:flex;flex-wrap:wrap;gap:4px;padding:2px 0 4px;}",
1586
1648
  ".dkb-chip{font-size:10px;border-radius:6px;padding:1px 6px;}",
1587
- ".dkb-bal{display:flex;gap:10px;flex-wrap:wrap;font-size:12px;color:var(--dsw-alias-label-primary);align-items:baseline;}",
1588
- ".dkb-cur{font-weight:600;min-width:48px;}",
1589
- ".dkb-total{font-weight:600;}",
1590
- ".dkb-part{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
1649
+ // 余额主数字卡(大号数字 + 小字辅助信息;多币种横排多卡)
1650
+ ".dkb-mains{display:flex;gap:12px;flex-wrap:wrap;}",
1651
+ ".dkb-main{display:flex;flex-direction:column;gap:2px;padding:8px 12px;border-radius:8px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);min-width:150px;}",
1652
+ ".dkb-main-label{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
1653
+ ".dkb-main-value{font-size:20px;font-weight:700;color:var(--dsw-alias-state-success-primary);font-variant-numeric:tabular-nums;line-height:1.2;}",
1654
+ ".dkb-main-parts{display:flex;gap:10px;flex-wrap:wrap;}",
1655
+ ".dkb-main-part{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
1656
+ // 配额维度条(周/小时额度:进度条 + 剩余/总量)
1657
+ ".dkb-dim{display:flex;align-items:center;gap:10px;font-size:11px;color:var(--dsw-alias-label-secondary);}",
1658
+ ".dkb-dim-label{flex:none;min-width:44px;color:var(--dsw-alias-label-tertiary);}",
1659
+ ".dkb-dim-bar{flex:1;max-width:220px;height:5px;border-radius:3px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);overflow:hidden;}",
1660
+ ".dkb-dim-fill{display:block;height:100%;border-radius:3px;background:linear-gradient(90deg,var(--dsw-alias-state-success-primary),color-mix(in srgb,var(--dsw-alias-state-success-primary) 60%,#fff));}",
1661
+ ".dkb-dim-text{flex:none;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;}",
1591
1662
  ".dkb-link{font-size:12px;text-decoration:none;}",
1592
1663
  ".dkb-link:hover{text-decoration:underline;}",
1593
1664
  ".dkb-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;color:var(--dsw-alias-label-tertiary);font-size:12px;}",
@@ -1602,15 +1673,1473 @@ var feature5 = {
1602
1673
  Chip: BalanceChip
1603
1674
  };
1604
1675
 
1605
- // src/client.jsx
1606
- var DOCK_VERSION = "0.4.0";
1607
- var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5];
1608
- var PLANNED_FEATURES = [
1609
- { id: "animation", name: "\u4EFB\u52A1\u52A8\u753B", order: 130, accent: "#f472b6", planned: true, description: "\u63A5\u5165\u8DEF\u7EBF\u56FE 0.5.0\uFF1A\u4EFB\u52A1\u8FDB\u5EA6\u52A8\u753B\u4E0E\u901A\u77E5" }
1676
+ // features/animation/view.jsx
1677
+ var import_react7 = require("react");
1678
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1679
+ function rpcCall2(method, args) {
1680
+ return fetch("/dsh-dock/animation/" + method, {
1681
+ method: "POST",
1682
+ headers: { "content-type": "application/json" },
1683
+ body: JSON.stringify(args === void 0 ? {} : args)
1684
+ }).then(async (res) => {
1685
+ const data = await res.json().catch(() => ({}));
1686
+ if (res.ok && data && data.ok === true) return data.data;
1687
+ if (res.status === 405 || res.status === 404) {
1688
+ throw new Error("\u5BBF\u4E3B\u8FDB\u7A0B\u662F\u65E7\u7248\u672C\uFF08\u6CA1\u6709\u4EFB\u52A1\u52A8\u753B\u8DEF\u7531\uFF09\uFF0C\u91CD\u542F dsh web \u540E\u91CD\u8BD5");
1689
+ }
1690
+ if (data && data.ok === false) throw new Error(data.error && data.error.message || "HTTP " + res.status);
1691
+ throw new Error("HTTP " + res.status + (data && data.error && data.error.message ? ": " + data.error.message : ""));
1692
+ });
1693
+ }
1694
+ var EFFECT_MODES = [
1695
+ { id: "flow", name: "\u6D41\u5149\u7EC6\u7EBF", desc: "\u9876\u90E8\u7EC6\u7EBF\u6D41\u5149\u5F80\u8FD4\uFF0C\u901F\u5EA6\u968F\u4EFB\u52A1\u541E\u5410\u52A0\u5FEB" },
1696
+ { id: "breathe", name: "\u547C\u5438\u5149\u70B9", desc: "\u72B6\u6001\u5FBD\u6807\u5706\u70B9\u547C\u5438\uFF0C\u8D8A\u5FD9\u547C\u5438\u8D8A\u5FEB" },
1697
+ { id: "ring", name: "\u8F68\u9053\u5149\u73AF", desc: "\u7EC6\u73AF\u7ED5\u5706\u70B9\u65CB\u8F6C\uFF0C\u8F6C\u901F\u968F\u4EFB\u52A1\u901F\u5EA6" },
1698
+ { id: "orbit", name: "\u73AF\u5C4F\u5DE1\u822A", desc: "\u4E00\u9897\u5149\u70B9\u6CBF\u5C4F\u5E55\u8FB9\u7F18\u5DE1\u822A\u6574\u5708\uFF0C\u9192\u76EE\u4E0D\u906E\u6321" },
1699
+ { id: "robot", name: "\u684C\u9762\u4F19\u4F34", desc: "\u66F4\u5177\u8C61\u7684\u4EBA\u7269\u5750\u9547\u56DB\u5C4F\u5DE5\u4F4D\uFF1A\u601D\u8003\u3001\u8F93\u51FA\u3001\u67E5\u8D44\u6599\u968F\u4EFB\u52A1\u9636\u6BB5\u5207\u6362" },
1700
+ { id: "matrix", name: "\u4EE3\u7801\u96E8", desc: "\u5B57\u7B26\u6CBF\u5C4F\u5E55\u7F13\u843D\u5982\u6570\u636E\u6D41\uFF0C\u901F\u5EA6\u968F\u4EFB\u52A1\u541E\u5410\uFF0C\u514B\u5236\u7684\u4F4E\u900F\u660E\u5EA6" },
1701
+ { id: "stars", name: "\u661F\u91CE", desc: "\u7EC6\u788E\u661F\u70B9\u7F13\u6162\u98D8\u79FB\u95EA\u70C1\uFF0C\u5B89\u9759\u8010\u770B\u7684\u80CC\u666F\u6C1B\u56F4" },
1702
+ { id: "aurora", name: "\u6781\u5149", desc: "\u5C4F\u5E55\u9876\u90E8\u67D4\u5149\u5E26\u7F13\u6162\u547C\u5438\u6D41\u52A8\uFF0C\u50CF\u6781\u5149\u62C2\u8FC7" }
1610
1703
  ];
1611
- var PLANNED_NOTES = {
1612
- animation: "\u5F85\u63A5\u5165\uFF08\u8DEF\u7EBF\u56FE 0.5.0\uFF09\uFF1A\u4EFB\u52A1\u8FDB\u5EA6\u52A8\u753B\u4E0E\u5B8C\u6210\u901A\u77E5\u3002"
1704
+ var PHASE_LABELS = { think: "\u601D\u8003\u4E2D", write: "\u8F93\u51FA\u4E2D", code: "\u7F16\u5199\u4EE3\u7801", search: "\u67E5\u8D44\u6599" };
1705
+ function phaseLabel(p) {
1706
+ return PHASE_LABELS[p] || "\u5DE5\u4F5C\u4E2D";
1707
+ }
1708
+ var END_LABELS = {
1709
+ completed: { label: "\u5B8C\u6210", cls: "ok" },
1710
+ error: { label: "\u51FA\u9519", cls: "err" },
1711
+ aborted: { label: "\u5DF2\u4E2D\u6B62", cls: "warn" },
1712
+ blocked: { label: "\u53D7\u963B", cls: "warn" },
1713
+ "max-tokens": { label: "\u8FBE\u8F93\u51FA\u4E0A\u9650", cls: "warn" },
1714
+ interrupted: { label: "\u4E2D\u65AD", cls: "warn" }
1715
+ };
1716
+ function endInfo(reason) {
1717
+ return END_LABELS[reason] || END_LABELS.completed;
1718
+ }
1719
+ function isSuccessReason(reason) {
1720
+ return !reason || reason === "completed";
1721
+ }
1722
+ function fmtNum2(n) {
1723
+ return (Number(n) || 0).toLocaleString("en-US");
1724
+ }
1725
+ function fmtCompact2(n) {
1726
+ n = Number(n) || 0;
1727
+ if (n >= 1e6) return (n / 1e6).toFixed(2) + "M";
1728
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + "K";
1729
+ return String(Math.round(n));
1730
+ }
1731
+ function fmtDur(ms) {
1732
+ const s = Math.max(0, Math.round((ms || 0) / 1e3));
1733
+ const h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60), sec = s % 60;
1734
+ if (h > 0) return h + "\u5C0F\u65F6" + m + "\u5206" + sec + "\u79D2";
1735
+ if (m > 0) return m + "\u5206" + sec + "\u79D2";
1736
+ return sec + "\u79D2";
1737
+ }
1738
+ function fmtClock(ms) {
1739
+ const s = Math.max(0, Math.floor((ms || 0) / 1e3));
1740
+ const h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60), sec = s % 60;
1741
+ const p = (x) => String(x).padStart(2, "0");
1742
+ return h > 0 ? h + ":" + p(m) + ":" + p(sec) : p(m) + ":" + p(sec);
1743
+ }
1744
+ function fmtTime2(ts) {
1745
+ if (!ts) return "";
1746
+ const d = new Date(ts);
1747
+ const p = (x) => String(x).padStart(2, "0");
1748
+ return p(d.getHours()) + ":" + p(d.getMinutes()) + ":" + p(d.getSeconds());
1749
+ }
1750
+ function truncate(str, max) {
1751
+ if (!str) return "";
1752
+ return String(str).length > max ? String(str).slice(0, max) + "\u2026" : str;
1753
+ }
1754
+ var animationStore = {
1755
+ snap: { status: null, loading: false, error: null },
1756
+ listeners: /* @__PURE__ */ new Set(),
1757
+ subscribe(fn) {
1758
+ this.listeners.add(fn);
1759
+ return () => {
1760
+ this.listeners.delete(fn);
1761
+ };
1762
+ },
1763
+ emit() {
1764
+ for (const fn of this.listeners) fn();
1765
+ },
1766
+ applyConfig(cfg) {
1767
+ if (this.snap.status) {
1768
+ this.snap = Object.assign({}, this.snap, { status: Object.assign({}, this.snap.status, { config: cfg }) });
1769
+ this.emit();
1770
+ }
1771
+ },
1772
+ refresh() {
1773
+ if (this.snap.loading) return Promise.resolve();
1774
+ this.snap = Object.assign({}, this.snap, { loading: true });
1775
+ this.emit();
1776
+ return rpcCall2("status").then((data) => {
1777
+ this.snap = { status: data, loading: false, error: null };
1778
+ this.emit();
1779
+ }).catch((e) => {
1780
+ this.snap = Object.assign({}, this.snap, { loading: false, error: e && e.message || String(e) });
1781
+ this.emit();
1782
+ });
1783
+ }
1784
+ };
1785
+ function useAnimation() {
1786
+ const [snap, setSnap] = (0, import_react7.useState)(animationStore.snap);
1787
+ (0, import_react7.useEffect)(() => animationStore.subscribe(() => setSnap(animationStore.snap)), []);
1788
+ return snap;
1789
+ }
1790
+ function useTicker(ctx, active) {
1791
+ const [, bump] = (0, import_react7.useState)(0);
1792
+ (0, import_react7.useEffect)(() => {
1793
+ if (!active) return;
1794
+ if (ctx && typeof ctx.interval === "function") return ctx.interval(bump, 1e3);
1795
+ const t = setInterval(bump, 1e3);
1796
+ return () => clearInterval(t);
1797
+ }, [active]);
1798
+ }
1799
+ function Box3(props) {
1800
+ const w = props.w, h = props.h, d = props.d;
1801
+ const faces = [
1802
+ [w, h, "translate(-50%,-50%) translateZ(" + d / 2 + "px)"],
1803
+ [w, h, "translate(-50%,-50%) rotateY(180deg) translateZ(" + d / 2 + "px)"],
1804
+ [d, h, "translate(-50%,-50%) rotateY(90deg) translateZ(" + w / 2 + "px)"],
1805
+ [d, h, "translate(-50%,-50%) rotateY(-90deg) translateZ(" + w / 2 + "px)"],
1806
+ [w, d, "translate(-50%,-50%) rotateX(90deg) translateZ(" + h / 2 + "px)"],
1807
+ [w, d, "translate(-50%,-50%) rotateX(-90deg) translateZ(" + h / 2 + "px)"]
1808
+ ];
1809
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1810
+ "span",
1811
+ {
1812
+ className: "dk3-box " + (props.cls || ""),
1813
+ style: Object.assign(
1814
+ { width: w, height: h, left: props.x - w / 2, top: props.y - h / 2 },
1815
+ props.z ? { transform: "translateZ(" + props.z + "px)" } : null,
1816
+ props.style
1817
+ ),
1818
+ children: [
1819
+ faces.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-face", style: { width: f[0], height: f[1], transform: f[2] } }, i)),
1820
+ props.children
1821
+ ]
1822
+ }
1823
+ );
1824
+ }
1825
+ function Monitor3(props) {
1826
+ const w = props.w, h = props.h;
1827
+ const lines = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
1828
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1829
+ "span",
1830
+ {
1831
+ className: "dk3-mon3 " + (props.cls || ""),
1832
+ style: { left: props.x - w / 2, top: props.y - h / 2, width: w, height: h, transform: "translateZ(" + (props.z || -3) + "px) rotateY(" + (props.ry || 0) + "deg)" },
1833
+ children: [
1834
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w, h, d: 5, cls: "dk3-frame", x: w / 2, y: h / 2 }),
1835
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-screen", style: { width: w - 4, height: h - 4, transform: "translate(-50%,-50%) translateZ(3.1px)" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-code", children: [
1836
+ lines.map((n, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}, i)),
1837
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-cur" })
1838
+ ] }) })
1839
+ ]
1840
+ }
1841
+ );
1842
+ }
1843
+ function RobotScene(props) {
1844
+ const phase = props && props.phase ? props.phase : "code";
1845
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-bot-scene", "data-phase": phase, "aria-hidden": "true", children: [
1846
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-world", children: [
1847
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 150, h: 7, d: 40, cls: "dk3-desk", x: 115, y: 78 }),
1848
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 5, h: 26, d: 32, cls: "dk3-metal dk3-leg", x: 48, y: 94 }),
1849
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 5, h: 26, d: 32, cls: "dk3-metal dk3-leg", x: 182, y: 94 }),
1850
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Monitor3, { w: 34, h: 24, x: 140, y: 60, ry: 24, cls: "left" }),
1851
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Monitor3, { w: 40, h: 30, x: 168, y: 58, ry: 0, cls: "center" }),
1852
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Monitor3, { w: 28, h: 21, x: 188, y: 62, ry: -24, cls: "right" }),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Monitor3, { w: 30, h: 20, x: 168, y: 28, ry: 0, cls: "top" }),
1854
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 16, h: 2.5, d: 9, cls: "dk3-metal dk3-kb3", x: 126, y: 73, z: 14 }),
1855
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 5, d: 4, cls: "dk3-mug", x: 140, y: 71, z: 14 }),
1856
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-person", children: [
1857
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 30, d: 22, cls: "dk3-chairback", x: 2, y: 42 }),
1858
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 20, h: 4, d: 22, cls: "dk3-chairseat", x: 12, y: 58 }),
1859
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3, h: 12, d: 3, cls: "dk3-metal", x: 12, y: 68 }),
1860
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 14, h: 2, d: 14, cls: "dk3-metal", x: 12, y: 74 }),
1861
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 13, h: 5, d: 9, cls: "dk3-pants", x: 20, y: 54 }),
1862
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 12, d: 4, cls: "dk3-pants", x: 26, y: 62 }),
1863
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 6, h: 3, d: 5, cls: "dk3-shoe", x: 28, y: 73 }),
1864
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 15, h: 20, d: 11, cls: "dk3-hood dk3-torso", x: 12, y: 36 }),
1865
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 5, h: 8, d: 9, cls: "dk3-hood dk3-hoodbump", x: 5, y: 30 }),
1866
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 3, d: 4, cls: "dk3-skin", x: 14, y: 25 }),
1867
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-head3", children: [
1868
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box3, { w: 13, h: 12, d: 12, cls: "dk3-skin dk3-headbox", x: 8, y: 10, children: [
1869
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-brows", style: { width: 10, height: 4, transform: "translate(-50%,-50%) rotateY(90deg) translateZ(6.3px)" }, children: [
1870
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1871
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1872
+ ] }),
1873
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-eyes", style: { width: 10, height: 7, transform: "translate(-50%,-50%) rotateY(90deg) translateZ(6.2px)" }, children: [
1874
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1875
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1876
+ ] }),
1877
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-nose", style: { transform: "translate(-50%,-50%) rotateY(90deg) translateZ(6.8px)" } }),
1878
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-mouth", style: { transform: "translate(-50%,-50%) rotateY(90deg) translateZ(6.2px)" } })
1879
+ ] }),
1880
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 14, h: 6, d: 13, cls: "dk3-hair", x: 8, y: 4 }),
1881
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 11, d: 13, cls: "dk3-hair", x: 2, y: 9 }),
1882
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-ear" })
1883
+ ] }),
1884
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-arm3", children: [
1885
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 11, d: 4, cls: "dk3-hood dk3-uarm", x: 2, y: 6 }),
1886
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-elbow", children: [
1887
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 11, h: 3.5, d: 3.5, cls: "dk3-hood dk3-farm", x: 6, y: 2 }),
1888
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3.5, h: 3, d: 3, cls: "dk3-skin dk3-hand", x: 12.5, y: 2 })
1889
+ ] })
1890
+ ] }),
1891
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-arm3 dk3-far", children: [
1892
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 11, d: 4, cls: "dk3-hood dk3-uarm", x: 2, y: 6 }),
1893
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-elbow", children: [
1894
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 11, h: 3.5, d: 3.5, cls: "dk3-hood dk3-farm", x: 6, y: 2 }),
1895
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3.5, h: 3, d: 3, cls: "dk3-skin dk3-hand", x: 12.5, y: 2 })
1896
+ ] })
1897
+ ] })
1898
+ ] })
1899
+ ] }),
1900
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-bubble", children: [
1901
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1903
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1904
+ ] })
1905
+ ] });
1906
+ }
1907
+ var SOUND_LIBRARY = {
1908
+ chime: { name: "\u6E05\u8106\u53CC\u97F3", notes: { done: [[659.25, 0, 0.14], [880, 0.13, 0.24]], err: [[220, 0, 0.16], [164.81, 0.15, 0.3]] } },
1909
+ ding: { name: "\u53EE", notes: { done: [[987.77, 0, 0.35]], err: [[246.94, 0, 0.4]] } },
1910
+ coin: { name: "\u91D1\u5E01", notes: { done: [[988, 0, 0.08], [1319, 0.08, 0.35], [988, 0, 0.08, "square"], [1319, 0.08, 0.3, "square"]], err: [[196, 0, 0.12], [147, 0.11, 0.35]] } },
1911
+ bell: { name: "\u949F\u58F0", notes: { done: [[523.25, 0, 0.5], [659.25, 0.02, 0.45], [783.99, 0.04, 0.4]], err: [[174.61, 0, 0.5], [130.81, 0.05, 0.5]] } },
1912
+ pulse: { name: "\u8109\u51B2", notes: { done: [[440, 0, 0.09], [440, 0.14, 0.09], [440, 0.28, 0.16]], err: [[174.61, 0, 0.1], [174.61, 0.14, 0.1], [174.61, 0.28, 0.18]] } },
1913
+ arp: { name: "\u7436\u97F3", notes: { done: [[523.25, 0, 0.12], [659.25, 0.09, 0.12], [783.99, 0.18, 0.12], [1046.5, 0.27, 0.3]], err: [[392, 0, 0.12], [329.63, 0.1, 0.12], [261.63, 0.2, 0.12], [196, 0.3, 0.32]] } }
1914
+ };
1915
+ var soundCtx = null;
1916
+ function playTone(seq) {
1917
+ try {
1918
+ if (typeof window === "undefined" || !window.AudioContext && !window.webkitAudioContext) return;
1919
+ const AC = window.AudioContext || window.webkitAudioContext;
1920
+ if (!soundCtx) soundCtx = new AC();
1921
+ if (soundCtx.state === "suspended") {
1922
+ soundCtx.resume().catch(() => {
1923
+ });
1924
+ }
1925
+ const t0 = soundCtx.currentTime;
1926
+ for (const [f, at, dur, wave] of seq) {
1927
+ const osc = soundCtx.createOscillator();
1928
+ const gain = soundCtx.createGain();
1929
+ osc.type = wave || "sine";
1930
+ osc.frequency.value = f;
1931
+ gain.gain.setValueAtTime(0, t0 + at);
1932
+ gain.gain.linearRampToValueAtTime(0.18, t0 + at + 0.015);
1933
+ gain.gain.exponentialRampToValueAtTime(1e-4, t0 + at + dur);
1934
+ osc.connect(gain).connect(soundCtx.destination);
1935
+ osc.start(t0 + at);
1936
+ osc.stop(t0 + at + dur + 0.05);
1937
+ }
1938
+ } catch {
1939
+ }
1940
+ }
1941
+ function playDoneSound(success, effect) {
1942
+ const lib = SOUND_LIBRARY[effect] || SOUND_LIBRARY.chime;
1943
+ playTone(success ? lib.notes.done : lib.notes.err);
1944
+ }
1945
+ function previewSound(effect) {
1946
+ const lib = SOUND_LIBRARY[effect] || SOUND_LIBRARY.chime;
1947
+ playTone(lib.notes.done);
1948
+ const delayed = lib.notes.err.map(([f, at, dur, wave]) => [f, at + 0.55, dur, wave]);
1949
+ playTone(delayed);
1950
+ }
1951
+ function Toast(props) {
1952
+ const t = props.t;
1953
+ const [closing, setClosing] = (0, import_react7.useState)(false);
1954
+ const close = (0, import_react7.useCallback)(() => {
1955
+ if (!closing) setClosing(true);
1956
+ }, [closing]);
1957
+ (0, import_react7.useEffect)(() => {
1958
+ if (!t.stayMs) return;
1959
+ const timer = setTimeout(close, t.stayMs);
1960
+ return () => clearTimeout(timer);
1961
+ }, []);
1962
+ (0, import_react7.useEffect)(() => {
1963
+ if (!closing) return;
1964
+ const timer = setTimeout(() => props.onClose(t.id), 240);
1965
+ return () => clearTimeout(timer);
1966
+ }, [closing]);
1967
+ const markColor = t.kind === "success" ? "var(--dsw-alias-state-success-primary,#34d399)" : t.kind === "error" ? "var(--dsw-alias-state-error-primary,#f87171)" : "var(--dsw-alias-state-warning-primary,#fbbf24)";
1968
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-toast" + (closing ? " out" : ""), children: [
1969
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-toast-head", children: [
1970
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-toast-mark", style: { background: markColor } }),
1971
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-toast-title", title: t.title, children: t.title }),
1972
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "dkan-toast-close", "aria-label": "\u5173\u95ED", onClick: close, children: "\u2715" })
1973
+ ] }),
1974
+ t.body ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-toast-body", children: t.body }) : null
1975
+ ] });
1976
+ }
1977
+ function makeBits(n, fn) {
1978
+ const arr = [];
1979
+ for (let i = 0; i < n; i++) arr.push(fn(i));
1980
+ return arr;
1981
+ }
1982
+ function BurstLayer(props) {
1983
+ const bursts = props.bursts || [];
1984
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-fxwrap", "aria-hidden": "true", children: bursts.map((b) => {
1985
+ if (b.type === "plane") {
1986
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-plane", style: { left: b.x, top: b.y }, children: "\u27A4" }, b.id);
1987
+ }
1988
+ if (b.type === "spark") {
1989
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-spark", style: { left: b.x, top: b.y }, children: b.bits.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { style: { "--dx": p.dx + "px", "--dy": p.dy + "px", background: p.c, boxShadow: "0 0 6px " + p.c } }, i)) }, b.id);
1990
+ }
1991
+ if (b.type === "streak") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-streak" }, b.id);
1992
+ if (b.type === "flash") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-flash" }, b.id);
1993
+ if (b.type === "surge") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-surge" }, b.id);
1994
+ if (b.type === "confetti") {
1995
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-confetti", children: b.bits.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { style: { left: p.l + "%", "--dx": p.dx + "px", "--r": p.r + "deg", background: p.c, boxShadow: "0 0 4px " + p.c, animationDelay: p.d + "s" } }, i)) }, b.id);
1996
+ }
1997
+ return null;
1998
+ }) });
1999
+ }
2000
+ var MATRIX_CHARS = "01</>;{}=+*#";
2001
+ function AmbientLayer(props) {
2002
+ const mode = props.mode;
2003
+ const speed = props.speed;
2004
+ const matrix = (0, import_react7.useMemo)(() => makeBits(34, () => ({
2005
+ l: Math.random() * 100,
2006
+ d: 4 + Math.random() * 6,
2007
+ delay: -Math.random() * 8,
2008
+ o: 0.28 + Math.random() * 0.34,
2009
+ s: 11 + Math.round(Math.random() * 4),
2010
+ c: MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)] + MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)] + MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)]
2011
+ })), []);
2012
+ const stars = (0, import_react7.useMemo)(() => makeBits(80, () => ({
2013
+ l: Math.random() * 100,
2014
+ t: Math.random() * 100,
2015
+ sz: 1.5 + Math.random() * 2,
2016
+ d: 2 + Math.random() * 4,
2017
+ delay: -Math.random() * 6,
2018
+ dx: (Math.random() - 0.5) * 40,
2019
+ dy: (Math.random() - 0.5) * 24
2020
+ })), []);
2021
+ if (mode === "matrix") {
2022
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-amb dkan-matrix", style: { "--dkan-speed": speed }, "aria-hidden": "true", children: matrix.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { left: p.l + "%", animationDuration: "calc(" + p.d + "s / var(--dkan-speed,1))", animationDelay: p.delay + "s", opacity: p.o, fontSize: p.s }, children: p.c }, i)) });
2023
+ }
2024
+ if (mode === "stars") {
2025
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-amb dkan-stars", style: { "--dkan-speed": speed }, "aria-hidden": "true", children: [
2026
+ stars.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dkan-star", style: { left: p.l + "%", top: p.t + "%", width: p.sz, height: p.sz, animationDuration: "calc(" + p.d + "s / var(--dkan-speed,1))", animationDelay: p.delay + "s", "--dx": p.dx + "px", "--dy": p.dy + "px" } }, i)),
2027
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-moon" }),
2028
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dkan-meteor", style: { top: "12%", left: "72%", animationDelay: "0s" } }),
2029
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dkan-meteor", style: { top: "28%", left: "88%", animationDelay: "2.8s" } }),
2030
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dkan-meteor", style: { top: "6%", left: "42%", animationDelay: "5.6s" } })
2031
+ ] });
2032
+ }
2033
+ if (mode === "aurora") {
2034
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-amb dkan-aurora", style: { "--dkan-speed": speed }, "aria-hidden": "true", children: [
2035
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2036
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2037
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2038
+ ] });
2039
+ }
2040
+ return null;
2041
+ }
2042
+ function AnimationOverlay(props) {
2043
+ const ctx = props && props.ctx;
2044
+ const snap = useAnimation();
2045
+ const [toasts, setToasts] = (0, import_react7.useState)([]);
2046
+ const [flourish, setFlourish] = (0, import_react7.useState)(null);
2047
+ const [bursts, setBursts] = (0, import_react7.useState)([]);
2048
+ const prevActiveRef = (0, import_react7.useRef)(null);
2049
+ const burstIdRef = (0, import_react7.useRef)(0);
2050
+ const pushBurst = (0, import_react7.useCallback)((type, x, y, bits) => {
2051
+ const id = ++burstIdRef.current;
2052
+ setBursts((prev) => prev.concat([{ id, type, x, y, bits }]).slice(-6));
2053
+ setTimeout(() => setBursts((prev) => prev.filter((b) => b.id !== id)), 2600);
2054
+ }, []);
2055
+ (0, import_react7.useEffect)(() => {
2056
+ if (typeof document === "undefined") return;
2057
+ const onClick = (e) => {
2058
+ const t = e.target;
2059
+ if (!t || !t.closest) return;
2060
+ const sendBtn = t.closest('button[aria-label="Send message"], button[aria-label*="\u53D1\u9001"]');
2061
+ const newSession = t.closest('button[aria-label*="New session"], button[aria-label*="\u65B0\u4F1A\u8BDD"], button[aria-label*="New Session"]');
2062
+ const workspace = t.closest('button[aria-label*="Choose workspace"], button[aria-label*="\u5DE5\u4F5C\u76EE\u5F55"], button[aria-label*="workspace"]');
2063
+ const sessionItem = t.closest('[role="treeitem"]');
2064
+ if (sendBtn) {
2065
+ pushBurst("plane", e.clientX, e.clientY);
2066
+ } else if (newSession) {
2067
+ pushBurst("spark", e.clientX, e.clientY, makeBits(10, () => ({
2068
+ dx: (Math.random() - 0.5) * 70,
2069
+ dy: (Math.random() - 0.5) * 70,
2070
+ c: ["#4d9fff", "#34d399", "#fbbf24", "#f472b6"][Math.floor(Math.random() * 4)]
2071
+ })));
2072
+ } else if (workspace) {
2073
+ pushBurst("flash");
2074
+ } else if (sessionItem) {
2075
+ pushBurst("streak");
2076
+ }
2077
+ };
2078
+ document.addEventListener("click", onClick, true);
2079
+ return () => document.removeEventListener("click", onClick, true);
2080
+ }, [pushBurst]);
2081
+ const taskCountRef = (0, import_react7.useRef)(0);
2082
+ (0, import_react7.useEffect)(() => {
2083
+ const st2 = snap.status;
2084
+ if (!st2 || !st2.active) return;
2085
+ const n = st2.active.length;
2086
+ if (n > taskCountRef.current) pushBurst("surge");
2087
+ taskCountRef.current = n;
2088
+ }, [snap.status, pushBurst]);
2089
+ (0, import_react7.useEffect)(() => {
2090
+ let stopped = false;
2091
+ let timer = null;
2092
+ const loop = async () => {
2093
+ await animationStore.refresh();
2094
+ if (stopped) return;
2095
+ const s = animationStore.snap;
2096
+ timer = setTimeout(loop, s.error ? 15e3 : s.status && s.status.active && s.status.active.length > 0 ? 2e3 : 6e3);
2097
+ };
2098
+ loop();
2099
+ const onVisible = () => {
2100
+ if (!stopped && typeof document !== "undefined" && document.visibilityState === "visible") animationStore.refresh();
2101
+ };
2102
+ document.addEventListener("visibilitychange", onVisible);
2103
+ return () => {
2104
+ stopped = true;
2105
+ if (timer) clearTimeout(timer);
2106
+ document.removeEventListener("visibilitychange", onVisible);
2107
+ };
2108
+ }, []);
2109
+ (0, import_react7.useEffect)(() => {
2110
+ const st2 = snap.status;
2111
+ if (!st2 || !st2.active) return;
2112
+ const prev = prevActiveRef.current;
2113
+ if (prev) {
2114
+ const currIds = new Set(st2.active.map((x) => x.sessionId));
2115
+ for (const task of prev) {
2116
+ if (currIds.has(task.sessionId)) continue;
2117
+ const record = (st2.recent || []).find((r) => r.sessionId === task.sessionId) || null;
2118
+ handleTaskEnd(task, record, st2.config || {});
2119
+ }
2120
+ }
2121
+ prevActiveRef.current = st2.active.slice();
2122
+ }, [snap.status]);
2123
+ const handleTaskEnd = (task, record, cfg2) => {
2124
+ const reason = record && record.endReason || "";
2125
+ const success = isSuccessReason(reason);
2126
+ const info = endInfo(reason);
2127
+ if (cfg2.animationEnabled) {
2128
+ setFlourish({ key: Date.now(), err: !success });
2129
+ if (success) {
2130
+ pushBurst("confetti", 0, 0, makeBits(18, (i) => ({
2131
+ l: 4 + i / 18 * 92 + Math.random() * 3,
2132
+ dx: (Math.random() - 0.5) * 60,
2133
+ r: Math.random() * 720 - 360,
2134
+ d: Math.random() * 0.35,
2135
+ c: ["#4d9fff", "#34d399", "#fbbf24", "#f472b6", "#a78bfa"][i % 5]
2136
+ })));
2137
+ }
2138
+ }
2139
+ if (!cfg2.notifyEnabled) return;
2140
+ const wanted = success ? cfg2.notifyOnComplete : cfg2.notifyOnError;
2141
+ if (!wanted) return;
2142
+ const models = record && record.models && record.models.length ? record.models.join(", ") : task.models && task.models.length ? task.models.join(", ") : "\u672A\u77E5\u6A21\u578B";
2143
+ const provider = record && record.provider || task.provider || "";
2144
+ const startTs = record && record.startTime || task.startTime;
2145
+ const endTs = record && record.endTime || Date.now();
2146
+ const lines = [
2147
+ "\u4EFB\u52A1\uFF1A" + (record && record.title || task.title || "(\u65E0\u6807\u9898)"),
2148
+ "\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""),
2149
+ "\u8017\u65F6\uFF1A" + fmtDur(record && record.duration || endTs - startTs) + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09",
2150
+ "\u56DE\u5408 " + (record && record.turns || task.turns || 0) + " \xB7 \u6B65\u9AA4 " + (record && record.steps || task.steps || 0) + (record && record.toolCalls || task.toolCalls ? " \xB7 \u5DE5\u5177 " + (record && record.toolCalls || task.toolCalls) + " \u6B21" : ""),
2151
+ "Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens)
2152
+ ];
2153
+ if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate(record.lastText, 140));
2154
+ if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate(record.errorMessage, 120));
2155
+ const title = success ? "\u4EFB\u52A1\u5B8C\u6210" : "\u4EFB\u52A1" + info.label;
2156
+ const toast = {
2157
+ id: Date.now() + Math.random(),
2158
+ kind: success ? "success" : info.cls === "err" ? "error" : "warn",
2159
+ title,
2160
+ body: lines.join("\n"),
2161
+ stayMs: typeof cfg2.notifyStayMs === "number" ? cfg2.notifyStayMs : 8e3
2162
+ };
2163
+ setToasts((prev) => prev.concat([toast]).slice(-4));
2164
+ if (cfg2.soundNotify !== false) playDoneSound(success, cfg2.soundEffect);
2165
+ if (cfg2.systemNotify && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
2166
+ try {
2167
+ new Notification("dsh " + title, {
2168
+ body: (record && record.title || task.title || "(\u65E0\u6807\u9898)") + " \xB7 " + fmtDur(record && record.duration || endTs - startTs),
2169
+ tag: "dsh-dock-animation-" + task.sessionId
2170
+ });
2171
+ } catch {
2172
+ }
2173
+ }
2174
+ };
2175
+ const st = snap.status;
2176
+ const cfg = st && st.config;
2177
+ const active = st && st.active ? st.active : [];
2178
+ const animOn = !!(cfg && cfg.animationEnabled && active.length > 0);
2179
+ const mode = cfg && cfg.effectMode ? cfg.effectMode : "flow";
2180
+ useTicker(ctx, animOn);
2181
+ const now = Date.now();
2182
+ const elapsed = active.length > 0 ? fmtClock(now - Math.min(...active.map((x) => x.startTime || now))) : "";
2183
+ const [panelOpen, setPanelOpen2] = (0, import_react7.useState)(false);
2184
+ (0, import_react7.useEffect)(() => {
2185
+ setPanelOpen2(panelNav.open);
2186
+ return subscribePanel(() => setPanelOpen2(panelNav.open));
2187
+ }, []);
2188
+ const [speed, setSpeed] = (0, import_react7.useState)(1);
2189
+ const speedRef = (0, import_react7.useRef)({ tokens: -1, at: 0 });
2190
+ (0, import_react7.useEffect)(() => {
2191
+ if (!st || active.length === 0) {
2192
+ speedRef.current = { tokens: -1, at: 0 };
2193
+ return;
2194
+ }
2195
+ const total = active.reduce((a, x) => a + (x.totalTokens || 0), 0);
2196
+ const t = Date.now();
2197
+ const prev = speedRef.current;
2198
+ if (prev.tokens < 0 || t - prev.at < 500) {
2199
+ speedRef.current = { tokens: total, at: t };
2200
+ return;
2201
+ }
2202
+ const rate = Math.max(0, (total - prev.tokens) / ((t - prev.at) / 1e3));
2203
+ setSpeed(Math.max(0.7, Math.min(3, 0.7 + rate / 45)));
2204
+ speedRef.current = { tokens: total, at: t };
2205
+ }, [snap.status]);
2206
+ const phase = active.length > 0 ? active.reduce((best, x) => !best || (x.phaseAt || 0) > (best.phaseAt || 0) ? x : best, null).phase : "think";
2207
+ const ambientOn = animOn && !panelOpen;
2208
+ const robotScaleFromConfig = Math.max(0.85, Math.min(2.2, Number(cfg && cfg.robotScale) || 1.35));
2209
+ const speedStyle = { "--dkan-speed": Number(speed).toFixed(2) };
2210
+ const saveRobotScale = (0, import_react7.useCallback)((robotScale) => {
2211
+ rpcCall2("config", { robotScale }).then((d) => animationStore.applyConfig(d && d.config)).catch(() => {
2212
+ });
2213
+ }, []);
2214
+ const [botPos, setBotPos] = (0, import_react7.useState)(null);
2215
+ const botPosRef = (0, import_react7.useRef)(null);
2216
+ const botDragRef = (0, import_react7.useRef)(null);
2217
+ const botResizeRef = (0, import_react7.useRef)(null);
2218
+ const [botScaleDraft, setBotScaleDraft] = (0, import_react7.useState)(null);
2219
+ const botClickBlockRef = (0, import_react7.useRef)(false);
2220
+ (0, import_react7.useEffect)(() => {
2221
+ try {
2222
+ if (typeof localStorage === "undefined") return;
2223
+ const raw = localStorage.getItem("dsh-dock/anim/robot-pos/v1");
2224
+ const p = raw ? JSON.parse(raw) : null;
2225
+ if (p && typeof p.x === "number" && typeof p.y === "number" && typeof window !== "undefined") {
2226
+ const card = document.querySelector(".dkan-botcard");
2227
+ const w = card ? card.offsetWidth : 200, h = card ? card.offsetHeight : 160;
2228
+ const x = Math.min(Math.max(8, p.x), Math.max(8, window.innerWidth - w - 8));
2229
+ const y = Math.min(Math.max(8, p.y), Math.max(8, window.innerHeight - h - 8));
2230
+ botPosRef.current = { x, y };
2231
+ setBotPos({ x, y });
2232
+ }
2233
+ } catch {
2234
+ }
2235
+ }, []);
2236
+ const onBotPointerDown = (e) => {
2237
+ if (e.button !== 0) return;
2238
+ const r = e.currentTarget.getBoundingClientRect();
2239
+ botDragRef.current = { sx: e.clientX, sy: e.clientY, ox: r.left, oy: r.top, moved: false };
2240
+ try {
2241
+ e.currentTarget.setPointerCapture(e.pointerId);
2242
+ } catch {
2243
+ }
2244
+ };
2245
+ const onBotPointerMove = (e) => {
2246
+ const d = botDragRef.current;
2247
+ if (!d || typeof window === "undefined") return;
2248
+ const dx = e.clientX - d.sx, dy = e.clientY - d.sy;
2249
+ if (!d.moved && Math.hypot(dx, dy) < 4) return;
2250
+ d.moved = true;
2251
+ const el = e.currentTarget;
2252
+ const w = el.offsetWidth || 200, h = el.offsetHeight || 160;
2253
+ const x = Math.min(Math.max(8, d.ox + dx), window.innerWidth - w - 8);
2254
+ const y = Math.min(Math.max(8, d.oy + dy), window.innerHeight - h - 8);
2255
+ botPosRef.current = { x, y };
2256
+ setBotPos({ x, y });
2257
+ };
2258
+ const onBotPointerUp = () => {
2259
+ const d = botDragRef.current;
2260
+ botDragRef.current = null;
2261
+ if (d && d.moved) {
2262
+ try {
2263
+ if (typeof localStorage !== "undefined") localStorage.setItem("dsh-dock/anim/robot-pos/v1", JSON.stringify(botPosRef.current));
2264
+ } catch {
2265
+ }
2266
+ botClickBlockRef.current = true;
2267
+ setTimeout(() => {
2268
+ botClickBlockRef.current = false;
2269
+ }, 0);
2270
+ }
2271
+ };
2272
+ const onBotResizePointerDown = (e) => {
2273
+ if (e.button !== 0) return;
2274
+ e.preventDefault();
2275
+ e.stopPropagation();
2276
+ botResizeRef.current = { sx: e.clientX, sy: e.clientY, scale: botScaleDraft == null ? robotScaleFromConfig : botScaleDraft };
2277
+ try {
2278
+ e.currentTarget.setPointerCapture(e.pointerId);
2279
+ } catch {
2280
+ }
2281
+ };
2282
+ const onBotResizePointerMove = (e) => {
2283
+ const d = botResizeRef.current;
2284
+ if (!d) return;
2285
+ e.preventDefault();
2286
+ e.stopPropagation();
2287
+ const delta = (e.clientX - d.sx + (e.clientY - d.sy)) / 2;
2288
+ const next = Math.max(0.85, Math.min(2.2, Math.round((d.scale + delta / 220) * 100) / 100));
2289
+ setBotScaleDraft(next);
2290
+ if (botPosRef.current && typeof window !== "undefined") {
2291
+ const w = 220 * next + 24, h = 132 * next + 46;
2292
+ const x = Math.min(Math.max(8, botPosRef.current.x), Math.max(8, window.innerWidth - w - 8));
2293
+ const y = Math.min(Math.max(8, botPosRef.current.y), Math.max(8, window.innerHeight - h - 8));
2294
+ botPosRef.current = { x, y };
2295
+ setBotPos({ x, y });
2296
+ }
2297
+ };
2298
+ const onBotResizePointerUp = (e) => {
2299
+ if (!botResizeRef.current) return;
2300
+ e.preventDefault();
2301
+ e.stopPropagation();
2302
+ const next = botScaleDraft == null ? robotScaleFromConfig : botScaleDraft;
2303
+ botResizeRef.current = null;
2304
+ saveRobotScale(next);
2305
+ try {
2306
+ if (botPosRef.current && typeof localStorage !== "undefined") localStorage.setItem("dsh-dock/anim/robot-pos/v1", JSON.stringify(botPosRef.current));
2307
+ } catch {
2308
+ }
2309
+ setBotScaleDraft(null);
2310
+ };
2311
+ const onBotClick = () => {
2312
+ if (botClickBlockRef.current) return;
2313
+ openPanel("animation");
2314
+ };
2315
+ const displayRobotScale = botScaleDraft == null ? robotScaleFromConfig : botScaleDraft;
2316
+ const botCardStyle = botPos ? Object.assign({}, speedStyle, { "--dkan-bot-scale": displayRobotScale, left: botPos.x, top: botPos.y, right: "auto", bottom: "auto" }) : Object.assign({}, speedStyle, { "--dkan-bot-scale": displayRobotScale });
2317
+ if (!st) return null;
2318
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2319
+ ambientOn && mode === "flow" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-line", style: speedStyle, "aria-hidden": "true" }) : null,
2320
+ ambientOn && (mode === "matrix" || mode === "stars" || mode === "aurora") ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AmbientLayer, { mode, speed: Number(speed).toFixed(2) }) : null,
2321
+ ambientOn && mode === "orbit" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-orbit", style: speedStyle, "aria-hidden": "true" }) : null,
2322
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BurstLayer, { bursts }),
2323
+ ambientOn && mode === "robot" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2324
+ "div",
2325
+ {
2326
+ className: "dkan-botcard",
2327
+ role: "button",
2328
+ tabIndex: 0,
2329
+ style: botCardStyle,
2330
+ title: active.length + " \u4E2A\u4EFB\u52A1 \xB7 " + phaseLabel(phase) + " \xB7 \u70B9\u51FB\u67E5\u770B\u4EFB\u52A1\u52A8\u753B\u9875 \xB7 \u53EF\u62D6\u52A8\u5230\u4EFB\u610F\u4F4D\u7F6E",
2331
+ onPointerDown: onBotPointerDown,
2332
+ onPointerMove: onBotPointerMove,
2333
+ onPointerUp: onBotPointerUp,
2334
+ onPointerCancel: onBotPointerUp,
2335
+ onClick: onBotClick,
2336
+ onKeyDown: (e) => {
2337
+ if (e.target === e.currentTarget && (e.key === "Enter" || e.key === " ")) {
2338
+ e.preventDefault();
2339
+ onBotClick();
2340
+ }
2341
+ },
2342
+ children: [
2343
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RobotScene, { phase }),
2344
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-bot-cap", children: [
2345
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "n", children: active.length }),
2346
+ " \u4E2A\u4EFB\u52A1",
2347
+ elapsed ? " \xB7 " + elapsed : "",
2348
+ " \xB7 ",
2349
+ phaseLabel(phase)
2350
+ ] }),
2351
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2352
+ "button",
2353
+ {
2354
+ type: "button",
2355
+ className: "dkan-bot-resize",
2356
+ "aria-label": "\u8C03\u6574\u684C\u9762\u4F19\u4F34\u5927\u5C0F",
2357
+ title: "\u62D6\u52A8\u8C03\u6574\u684C\u9762\u4F19\u4F34\u5927\u5C0F",
2358
+ onPointerDown: onBotResizePointerDown,
2359
+ onPointerMove: onBotResizePointerMove,
2360
+ onPointerUp: onBotResizePointerUp,
2361
+ onPointerCancel: onBotResizePointerUp,
2362
+ onClick: (e) => e.stopPropagation(),
2363
+ onKeyDown: (e) => {
2364
+ if (e.key !== "ArrowUp" && e.key !== "ArrowRight" && e.key !== "ArrowDown" && e.key !== "ArrowLeft") return;
2365
+ e.preventDefault();
2366
+ e.stopPropagation();
2367
+ const d = e.key === "ArrowUp" || e.key === "ArrowRight" ? 0.05 : -0.05;
2368
+ saveRobotScale(Math.max(0.85, Math.min(2.2, Math.round((displayRobotScale + d) * 100) / 100)));
2369
+ }
2370
+ }
2371
+ )
2372
+ ]
2373
+ }
2374
+ ) : null,
2375
+ ambientOn && mode !== "robot" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2376
+ "button",
2377
+ {
2378
+ type: "button",
2379
+ className: "dkan-badge",
2380
+ style: speedStyle,
2381
+ title: active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D \xB7 \u70B9\u51FB\u67E5\u770B\u4EFB\u52A1\u52A8\u753B\u9875",
2382
+ onClick: () => openPanel("animation"),
2383
+ children: [
2384
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-dotwrap", children: [
2385
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-dot" }),
2386
+ mode === "ring" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-ring" }) : null
2387
+ ] }),
2388
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-badge-txt", children: [
2389
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "n", children: active.length }),
2390
+ " \u4E2A\u4EFB\u52A1",
2391
+ elapsed ? " \xB7 " + elapsed : ""
2392
+ ] })
2393
+ ]
2394
+ }
2395
+ ) : null,
2396
+ flourish ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2397
+ "div",
2398
+ {
2399
+ className: "dkan-done" + (flourish.err ? " err" : ""),
2400
+ onAnimationEnd: () => setFlourish(null),
2401
+ "aria-hidden": "true"
2402
+ },
2403
+ flourish.key
2404
+ ) : null,
2405
+ toasts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-toasts", children: toasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Toast, { t, onClose: (id) => setToasts((prev) => prev.filter((x) => x.id !== id)) }, t.id)) }) : null
2406
+ ] });
2407
+ }
2408
+ function ModePreview({ id }) {
2409
+ if (id === "flow") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev-flow" }) });
2410
+ if (id === "ring") {
2411
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-dotwrap", children: [
2412
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-dot" }),
2413
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-ring" })
2414
+ ] }) });
2415
+ }
2416
+ if (id === "orbit") {
2417
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev dkan-prev-box", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev-orbit" }) });
2418
+ }
2419
+ if (id === "matrix") {
2420
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-prev dkan-prev-matrix", children: [
2421
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2422
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2423
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2424
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2425
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2426
+ ] });
2427
+ }
2428
+ if (id === "stars") {
2429
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-prev dkan-prev-stars", children: [
2430
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2431
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2432
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2433
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2434
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2435
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2436
+ ] });
2437
+ }
2438
+ if (id === "aurora") {
2439
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-prev dkan-prev-aurora", children: [
2440
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2441
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2442
+ ] });
2443
+ }
2444
+ if (id === "robot") {
2445
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev dkan-prev-bot", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RobotScene, { phase: "code" }) });
2446
+ }
2447
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-dotwrap dkan-breathe", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-dot" }) }) });
2448
+ }
2449
+ function TaskRow(props) {
2450
+ const t = props.t;
2451
+ const info = endInfo(t.endReason);
2452
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-task", children: [
2453
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-task-head", children: [
2454
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-task-title", title: t.title, children: t.title || "(\u65E0\u6807\u9898)" }),
2455
+ props.done ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-tag " + info.cls, children: info.label }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-tag on", children: phaseLabel(t.phase) })
2456
+ ] }),
2457
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-task-meta", children: [
2458
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: (t.models && t.models.length ? t.models.join(", ") : "\u672A\u77E5") + (t.provider ? "\uFF08" + t.provider + "\uFF09" : "") }),
2459
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: props.done ? fmtDur(t.duration) : fmtClock(t.elapsed) }),
2460
+ "turns" in t ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u56DE\u5408 " + (t.turns || 0) + " \xB7 \u6B65\u9AA4 " + (t.steps || 0) + (t.toolCalls ? " \xB7 \u5DE5\u5177 " + t.toolCalls : "") }) : null,
2461
+ t.totalTokens ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u21A7" + fmtCompact2(t.inputTokens) + " \u21A5" + fmtCompact2(t.outputTokens) }) : null,
2462
+ props.done && t.endTime ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: fmtTime2(t.endTime) }) : null
2463
+ ] }),
2464
+ props.done && t.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-task-err", children: truncate(t.errorMessage, 120) }) : null
2465
+ ] });
2466
+ }
2467
+ function AnimationView(props) {
2468
+ const ctx = props && props.ctx;
2469
+ const snap = useAnimation(ctx);
2470
+ const [cfg, setCfg] = (0, import_react7.useState)(null);
2471
+ const [saveErr, setSaveErr] = (0, import_react7.useState)("");
2472
+ const [testing, setTesting] = (0, import_react7.useState)(false);
2473
+ const [testState, setTestState] = (0, import_react7.useState)(null);
2474
+ const cfgRef = (0, import_react7.useRef)(null);
2475
+ const pendingSavesRef = (0, import_react7.useRef)(0);
2476
+ const editingWebhookRef = (0, import_react7.useRef)(false);
2477
+ (0, import_react7.useEffect)(() => {
2478
+ const c = snap.status && snap.status.config;
2479
+ if (!c) return;
2480
+ if (pendingSavesRef.current > 0 || editingWebhookRef.current) return;
2481
+ if (c !== cfgRef.current) {
2482
+ cfgRef.current = c;
2483
+ setCfg(Object.assign({}, c));
2484
+ }
2485
+ }, [snap.status]);
2486
+ (0, import_react7.useEffect)(() => {
2487
+ if (!animationStore.snap.status) animationStore.refresh();
2488
+ }, []);
2489
+ const patch = (p) => {
2490
+ setSaveErr("");
2491
+ setCfg(Object.assign({}, cfg, p));
2492
+ pendingSavesRef.current++;
2493
+ return rpcCall2("config", p).then((d) => {
2494
+ pendingSavesRef.current--;
2495
+ animationStore.applyConfig(d && d.config);
2496
+ }).catch((e) => {
2497
+ pendingSavesRef.current--;
2498
+ setSaveErr("\u4FDD\u5B58\u5931\u8D25\uFF1A" + (e && e.message || String(e)));
2499
+ });
2500
+ };
2501
+ const saveWebhook = async () => {
2502
+ if (!editingWebhookRef.current) return;
2503
+ const hook = String(cfg.dingtalkWebhook || "").trim();
2504
+ await patch({ dingtalkWebhook: hook });
2505
+ editingWebhookRef.current = false;
2506
+ const c = animationStore.snap.status && animationStore.snap.status.config;
2507
+ if (c && c !== cfgRef.current) {
2508
+ cfgRef.current = c;
2509
+ setCfg(Object.assign({}, c));
2510
+ }
2511
+ };
2512
+ const runDingtalkTest = async () => {
2513
+ setTesting(true);
2514
+ setTestState(null);
2515
+ try {
2516
+ if (editingWebhookRef.current) {
2517
+ const hook = String(cfg.dingtalkWebhook || "").trim();
2518
+ if (!hook) throw new Error("\u8BF7\u5148\u586B\u5199 Webhook \u5730\u5740");
2519
+ const d = await rpcCall2("config", { dingtalkWebhook: hook });
2520
+ animationStore.applyConfig(d && d.config);
2521
+ editingWebhookRef.current = false;
2522
+ cfgRef.current = d && d.config || cfgRef.current;
2523
+ setCfg(Object.assign({}, cfg, { dingtalkWebhook: hook }));
2524
+ }
2525
+ const r = await rpcCall2("test");
2526
+ setTestState(r && r.sent ? { ok: true, msg: "\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u53BB\u7FA4\u91CC\u770B\u770B" } : { ok: false, msg: r && r.error || "\u53D1\u9001\u5931\u8D25" });
2527
+ } catch (e) {
2528
+ setTestState({ ok: false, msg: e && e.message || String(e) });
2529
+ } finally {
2530
+ setTesting(false);
2531
+ }
2532
+ };
2533
+ const enableSystemNotify = async (next) => {
2534
+ if (next && typeof Notification !== "undefined" && Notification.permission !== "granted") {
2535
+ try {
2536
+ const perm = await Notification.requestPermission();
2537
+ if (perm !== "granted") {
2538
+ setSaveErr("\u6D4F\u89C8\u5668\u672A\u6388\u6743\u7CFB\u7EDF\u901A\u77E5\uFF08\u53EF\u5728\u5730\u5740\u680F\u6743\u9650\u8BBE\u7F6E\u91CC\u91CD\u65B0\u5141\u8BB8\uFF09");
2539
+ return;
2540
+ }
2541
+ } catch {
2542
+ setSaveErr("\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u7CFB\u7EDF\u901A\u77E5");
2543
+ return;
2544
+ }
2545
+ }
2546
+ patch({ systemNotify: next });
2547
+ };
2548
+ const st = snap.status;
2549
+ const active = st && st.active ? st.active : [];
2550
+ const recent = st && st.recent ? st.recent.slice(0, 6) : [];
2551
+ const permNote = typeof Notification === "undefined" ? "\u5F53\u524D\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u7CFB\u7EDF\u901A\u77E5" : Notification.permission === "granted" ? "\u5DF2\u6388\u6743 \xB7 \u4EC5\u9875\u9762\u540E\u53F0\u65F6\u63A8\u9001" : Notification.permission === "denied" ? "\u5DF2\u88AB\u6D4F\u89C8\u5668\u62D2\u7EDD\uFF08\u9700\u5728\u6D4F\u89C8\u5668\u6743\u9650\u8BBE\u7F6E\u91CC\u91CD\u65B0\u5141\u8BB8\uFF09" : "\u672A\u6388\u6743 \xB7 \u5F00\u542F\u65F6\u4F1A\u8BF7\u6C42\u6388\u6743\uFF0C\u4EC5\u9875\u9762\u540E\u53F0\u65F6\u63A8\u9001";
2552
+ const rows = [];
2553
+ if (!cfg) {
2554
+ rows.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: snap.error ? "\u72B6\u6001\u4E0D\u53EF\u7528\uFF1A" + snap.error : snap.loading ? "\u6B63\u5728\u62C9\u53D6\u4EFB\u52A1\u72B6\u6001\u2026" : "\u7B49\u5F85\u4EFB\u52A1\u72B6\u6001" }, "load"));
2555
+ } else {
2556
+ rows.push(
2557
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2558
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2559
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u8FD0\u884C\u52A8\u753B" }),
2560
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-sub", children: "\u4EFB\u52A1\u8FDB\u884C\u4E2D\u624D\u51FA\u73B0\uFF1B\u514B\u5236\u7684\u52A8\u6548\uFF0C\u6697/\u4EAE\u8272\u81EA\u9002\u5E94" }),
2561
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sec-sw", children: [
2562
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-swlabel" + (cfg.animationEnabled ? " on" : ""), children: cfg.animationEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
2563
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2564
+ "button",
2565
+ {
2566
+ type: "button",
2567
+ className: "dock-sw" + (cfg.animationEnabled ? " on" : ""),
2568
+ role: "switch",
2569
+ "aria-checked": cfg.animationEnabled,
2570
+ "aria-label": "\u5F00\u5173\u8FD0\u884C\u52A8\u753B",
2571
+ title: cfg.animationEnabled ? "\u5173\u95ED\u8FD0\u884C\u52A8\u753B" : "\u5F00\u542F\u8FD0\u884C\u52A8\u753B",
2572
+ onClick: () => patch({ animationEnabled: !cfg.animationEnabled })
2573
+ }
2574
+ )
2575
+ ] })
2576
+ ] }),
2577
+ cfg.animationEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2578
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-modes", children: EFFECT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2579
+ "button",
2580
+ {
2581
+ type: "button",
2582
+ className: "dkan-mode" + (cfg.effectMode === m.id ? " on" : ""),
2583
+ onClick: () => patch({ effectMode: m.id }),
2584
+ children: [
2585
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-mode-name", children: m.name }),
2586
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ModePreview, { id: m.id }),
2587
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-mode-desc", children: m.desc })
2588
+ ]
2589
+ },
2590
+ m.id
2591
+ )) }),
2592
+ cfg.effectMode === "robot" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-robot-controls", children: [
2593
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-robot-controls-head", children: [
2594
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u684C\u9762\u4F19\u4F34\u5927\u5C0F" }),
2595
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
2596
+ Math.round((Number(cfg.robotScale) || 1.35) * 100),
2597
+ "%"
2598
+ ] })
2599
+ ] }),
2600
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-robot-size-options", role: "group", "aria-label": "\u684C\u9762\u4F19\u4F34\u5927\u5C0F\u9884\u8BBE", children: [[1, "\u7D27\u51D1"], [1.35, "\u9ED8\u8BA4"], [1.7, "\u52A0\u5927"], [2.1, "\u7279\u5927"]].map(([scale, label]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2601
+ "button",
2602
+ {
2603
+ type: "button",
2604
+ className: Math.abs((Number(cfg.robotScale) || 1.35) - scale) < 0.03 ? "on" : "",
2605
+ onClick: () => patch({ robotScale: scale }),
2606
+ children: label
2607
+ },
2608
+ scale
2609
+ )) }),
2610
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-robot-slider-row", children: [
2611
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2612
+ "input",
2613
+ {
2614
+ type: "range",
2615
+ min: "0.85",
2616
+ max: "2.2",
2617
+ step: "0.05",
2618
+ value: Number(cfg.robotScale) || 1.35,
2619
+ "aria-label": "\u684C\u9762\u4F19\u4F34\u5927\u5C0F\u767E\u5206\u6BD4",
2620
+ onChange: (e) => patch({ robotScale: Number(e.target.value) })
2621
+ }
2622
+ ),
2623
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u6D6E\u5C42\u53F3\u4E0B\u89D2\u4E5F\u53EF\u76F4\u63A5\u62D6\u52A8\u7F29\u653E\uFF0C\u5927\u5C0F\u4F1A\u81EA\u52A8\u4FDD\u5B58\u3002" })
2624
+ ] })
2625
+ ] }) : null
2626
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u52A8\u753B\u5DF2\u5173\u95ED\u2014\u2014\u53EA\u4FDD\u7559\u901A\u77E5\uFF08\u6216\u5168\u90E8\u5173\u95ED\uFF09\u65F6\uFF0C\u9875\u9762\u4E0D\u4F1A\u6709\u4EFB\u4F55\u52A8\u6548\u3002" })
2627
+ ] }, "anim"),
2628
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2629
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2630
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u5B8C\u6210\u901A\u77E5" }),
2631
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-sub", children: "\u4E0E\u52A8\u753B\u4E92\u4E0D\u4F9D\u8D56\uFF0C\u53EF\u5355\u72EC\u5F00\u542F" }),
2632
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sec-sw", children: [
2633
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-swlabel" + (cfg.notifyEnabled ? " on" : ""), children: cfg.notifyEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
2634
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2635
+ "button",
2636
+ {
2637
+ type: "button",
2638
+ className: "dock-sw" + (cfg.notifyEnabled ? " on" : ""),
2639
+ role: "switch",
2640
+ "aria-checked": cfg.notifyEnabled,
2641
+ "aria-label": "\u5F00\u5173\u5B8C\u6210\u901A\u77E5",
2642
+ title: cfg.notifyEnabled ? "\u5173\u95ED\u5B8C\u6210\u901A\u77E5" : "\u5F00\u542F\u5B8C\u6210\u901A\u77E5",
2643
+ onClick: () => patch({ notifyEnabled: !cfg.notifyEnabled })
2644
+ }
2645
+ )
2646
+ ] })
2647
+ ] }),
2648
+ cfg.notifyEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-rows-narrow", children: [
2649
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2650
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u5B8C\u6210\u901A\u77E5" }),
2651
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2652
+ "button",
2653
+ {
2654
+ type: "button",
2655
+ className: "dkm-miniswitch" + (cfg.notifyOnComplete ? " on" : ""),
2656
+ onClick: () => patch({ notifyOnComplete: !cfg.notifyOnComplete }),
2657
+ children: cfg.notifyOnComplete ? "\u5F00" : "\u5173"
2658
+ }
2659
+ ),
2660
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: "\u4EFB\u52A1\u6B63\u5E38\u5B8C\u6210\u65F6\u901A\u77E5" })
2661
+ ] }),
2662
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2663
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u5F02\u5E38\u901A\u77E5" }),
2664
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2665
+ "button",
2666
+ {
2667
+ type: "button",
2668
+ className: "dkm-miniswitch" + (cfg.notifyOnError ? " on" : ""),
2669
+ onClick: () => patch({ notifyOnError: !cfg.notifyOnError }),
2670
+ children: cfg.notifyOnError ? "\u5F00" : "\u5173"
2671
+ }
2672
+ ),
2673
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: "\u51FA\u9519 / \u4E2D\u6B62 / \u8FBE\u8F93\u51FA\u4E0A\u9650\u65F6\u901A\u77E5" })
2674
+ ] }),
2675
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2676
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u505C\u7559\u65F6\u957F" }),
2677
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2678
+ "select",
2679
+ {
2680
+ className: "dkan-select",
2681
+ value: String(cfg.notifyStayMs),
2682
+ onChange: (e) => patch({ notifyStayMs: Number(e.target.value) }),
2683
+ children: [
2684
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "4000", children: "4 \u79D2" }),
2685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "8000", children: "8 \u79D2" }),
2686
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "15000", children: "15 \u79D2" }),
2687
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "30000", children: "30 \u79D2" }),
2688
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "0", children: "\u5E38\u9A7B\uFF08\u624B\u52A8\u5173\u95ED\uFF09" })
2689
+ ]
2690
+ }
2691
+ )
2692
+ ] }),
2693
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2694
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u7CFB\u7EDF\u901A\u77E5" }),
2695
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2696
+ "button",
2697
+ {
2698
+ type: "button",
2699
+ className: "dkm-miniswitch" + (cfg.systemNotify ? " on" : ""),
2700
+ onClick: () => enableSystemNotify(!cfg.systemNotify),
2701
+ children: cfg.systemNotify ? "\u5F00" : "\u5173"
2702
+ }
2703
+ ),
2704
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: permNote })
2705
+ ] }),
2706
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2707
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u63D0\u793A\u97F3" }),
2708
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2709
+ "button",
2710
+ {
2711
+ type: "button",
2712
+ className: "dkm-miniswitch" + (cfg.soundNotify !== false ? " on" : ""),
2713
+ onClick: () => patch({ soundNotify: cfg.soundNotify === false }),
2714
+ children: cfg.soundNotify !== false ? "\u5F00" : "\u5173"
2715
+ }
2716
+ ),
2717
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: "\u4EFB\u52A1\u7ED3\u675F\u65F6\u64AD\u653E\uFF08\u8BD5\u542C\u4E3A\u5148\u64AD\u5B8C\u6210\u97F3\u3001\u540E\u64AD\u5F02\u5E38\u97F3\uFF09" })
2718
+ ] }),
2719
+ cfg.soundNotify !== false ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-sounds", children: Object.keys(SOUND_LIBRARY).map((key) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2720
+ "button",
2721
+ {
2722
+ type: "button",
2723
+ className: "dkan-sound" + (cfg.soundEffect === key ? " on" : ""),
2724
+ onClick: () => patch({ soundEffect: key }),
2725
+ children: [
2726
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sound-name", children: [
2727
+ SOUND_LIBRARY[key].name,
2728
+ cfg.soundEffect === key ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sound-cur", children: "\u2713" }) : null
2729
+ ] }),
2730
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2731
+ "span",
2732
+ {
2733
+ className: "dkan-sound-play",
2734
+ role: "button",
2735
+ tabIndex: 0,
2736
+ title: "\u8BD5\u542C " + SOUND_LIBRARY[key].name,
2737
+ onClick: (e) => {
2738
+ e.stopPropagation();
2739
+ previewSound(key);
2740
+ },
2741
+ onKeyDown: (e) => {
2742
+ if (e.key === "Enter" || e.key === " ") {
2743
+ e.preventDefault();
2744
+ e.stopPropagation();
2745
+ previewSound(key);
2746
+ }
2747
+ },
2748
+ children: "\u25B6"
2749
+ }
2750
+ )
2751
+ ]
2752
+ },
2753
+ key
2754
+ )) }) : null
2755
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u901A\u77E5\u5DF2\u5173\u95ED\u2014\u2014\u4EFB\u52A1\u7ED3\u675F\u65F6\u65E2\u4E0D\u5F39\u5361\u7247\u4E5F\u4E0D\u63A8\u7CFB\u7EDF\u901A\u77E5\u3002" })
2756
+ ] }, "notify"),
2757
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2758
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2759
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u9489\u9489\u63A8\u9001" }),
2760
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-sub", children: "\u4EFB\u52A1\u7ED3\u675F\u63A8\u9001\u5230\u9489\u9489\u7FA4\u673A\u5668\u4EBA\uFF08\u5BBF\u4E3B\u76F4\u53D1\uFF0C\u6D4F\u89C8\u5668\u5173\u7740\u4E5F\u80FD\u63A8\uFF1B\u4E8B\u4EF6\u8DDF\u968F\u4E0A\u65B9\u5B8C\u6210/\u5F02\u5E38\u5F00\u5173\uFF09" }),
2761
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sec-sw", children: [
2762
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-swlabel" + (cfg.dingtalkEnabled ? " on" : ""), children: cfg.dingtalkEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
2763
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2764
+ "button",
2765
+ {
2766
+ type: "button",
2767
+ className: "dock-sw" + (cfg.dingtalkEnabled ? " on" : ""),
2768
+ role: "switch",
2769
+ "aria-checked": cfg.dingtalkEnabled,
2770
+ "aria-label": "\u5F00\u5173\u9489\u9489\u63A8\u9001",
2771
+ title: cfg.dingtalkEnabled ? "\u5173\u95ED\u9489\u9489\u63A8\u9001" : "\u5F00\u542F\u9489\u9489\u63A8\u9001",
2772
+ onClick: () => patch({ dingtalkEnabled: !cfg.dingtalkEnabled })
2773
+ }
2774
+ )
2775
+ ] })
2776
+ ] }),
2777
+ cfg.dingtalkEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-rows-narrow", children: [
2778
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row dkan-row-webhook", children: [
2779
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "Webhook" }),
2780
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2781
+ "input",
2782
+ {
2783
+ type: "text",
2784
+ className: "dkan-input",
2785
+ spellCheck: false,
2786
+ value: cfg.dingtalkWebhook || "",
2787
+ placeholder: "https://oapi.dingtalk.com/robot/send?access_token=\u2026",
2788
+ onChange: (e) => {
2789
+ editingWebhookRef.current = true;
2790
+ setCfg(Object.assign({}, cfg, { dingtalkWebhook: e.target.value }));
2791
+ }
2792
+ }
2793
+ ),
2794
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2795
+ "button",
2796
+ {
2797
+ type: "button",
2798
+ className: "dkan-btn",
2799
+ disabled: !editingWebhookRef.current,
2800
+ onClick: saveWebhook,
2801
+ children: editingWebhookRef.current ? "\u4FDD\u5B58" : "\u5DF2\u4FDD\u5B58"
2802
+ }
2803
+ )
2804
+ ] }),
2805
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2806
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u8FDE\u901A\u6D4B\u8BD5" }),
2807
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "dkan-btn", disabled: testing, onClick: runDingtalkTest, children: testing ? "\u53D1\u9001\u4E2D\u2026" : "\u53D1\u9001\u6D4B\u8BD5\u6D88\u606F" }),
2808
+ testState ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-row-sub" + (testState.ok ? " dkan-ok" : " dkan-err"), children: [
2809
+ testState.ok ? "\u2713 " : "\u2717 ",
2810
+ testState.msg
2811
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: "\u7528\u5F53\u524D\u4FDD\u5B58\u7684 Webhook \u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F" })
2812
+ ] }),
2813
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u673A\u5668\u4EBA\u521B\u5EFA\uFF1A\u9489\u9489\u7FA4 \u2192 \u8BBE\u7F6E \u2192 \u667A\u80FD\u7FA4\u52A9\u624B \u2192 \u6DFB\u52A0\u673A\u5668\u4EBA \u2192 \u81EA\u5B9A\u4E49\uFF08Webhook\uFF09\uFF0C \u5B89\u5168\u8BBE\u7F6E\u9009\u300C\u81EA\u5B9A\u4E49\u5173\u952E\u8BCD\u300D\u586B\u300C\u4EFB\u52A1\u300D\u6216\u300Cdsh\u300D\uFF08\u63A8\u9001\u6807\u9898\u542B\u300C\u4EFB\u52A1\u300D\u5373\u53EF\u547D\u4E2D\uFF09\u3002" })
2814
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u7ED3\u675F\u4E0D\u63A8\u9001\u9489\u9489\u3002" })
2815
+ ] }, "dingtalk")
2816
+ );
2817
+ }
2818
+ if (saveErr) rows.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note dkan-err", children: saveErr }, "err"));
2819
+ rows.push(
2820
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2821
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2822
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u8FD0\u884C\u72B6\u6001" }),
2823
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-sub", children: snap.error ? "\u72B6\u6001\u62C9\u53D6\u5931\u8D25\uFF1A" + snap.error : active.length > 0 ? active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D" : recent.length > 0 ? "\u7A7A\u95F2 \xB7 \u663E\u793A\u6700\u8FD1\u5B8C\u6210" : "\u7A7A\u95F2 \xB7 \u6682\u65E0\u4EFB\u52A1\u8BB0\u5F55" }),
2824
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "dkan-refresh", onClick: () => animationStore.refresh(), children: snap.loading ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0" })
2825
+ ] }),
2826
+ active.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-tasks", children: active.map((t) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TaskRow, { t }, t.sessionId)) }) : null,
2827
+ active.length === 0 && recent.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u53D1\u8D77\u65B0\u4F1A\u8BDD\u4EFB\u52A1\u540E\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u8FDB\u884C\u4E2D\u4E0E\u6700\u8FD1\u5B8C\u6210\u7684\u4EFB\u52A1\uFF1B\u52A8\u753B\u4E0E\u901A\u77E5\u540C\u65F6\u5728\u9875\u9762\u751F\u6548\u3002" }) : null,
2828
+ recent.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-tasks dkan-tasks-done", children: recent.map((t) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TaskRow, { t, done: true }, t.sessionId + ":" + t.endTime)) }) : null
2829
+ ] }, "state")
2830
+ );
2831
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-root", children: rows });
2832
+ }
2833
+ function AnimationStat(props) {
2834
+ const snap = useAnimation(props && props.ctx);
2835
+ const st = snap.status;
2836
+ if (snap.error) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-err", children: "\u4EFB\u52A1\u72B6\u6001\u4E0D\u53EF\u7528\uFF08\u5BBF\u4E3B\u9700\u91CD\u542F\u52A0\u8F7D\u52A8\u753B\u8DEF\u7531\uFF09" });
2837
+ if (!st) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u7B49\u5F85\u4EFB\u52A1\u72B6\u6001\u2026" });
2838
+ if (st.active && st.active.length > 0) {
2839
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: st.active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D \xB7 " + fmtDur(Math.max(...st.active.map((x) => x.elapsed || 0))) });
2840
+ }
2841
+ const last = st.recent && st.recent[0];
2842
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: last ? "\u7A7A\u95F2 \xB7 \u6700\u8FD1\u5B8C\u6210 " + truncate(last.title, 24) : "\u7A7A\u95F2 \xB7 \u6682\u65E0\u4EFB\u52A1\u8BB0\u5F55" });
2843
+ }
2844
+ var css2 = [
2845
+ // 顶部流光细线(3px,比首版更醒目)
2846
+ ".dkan-line{position:fixed;top:0;left:0;right:0;height:3px;z-index:9990;pointer-events:none;background:color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 30%,transparent);}",
2847
+ '.dkan-line::after{content:"";position:absolute;top:0;bottom:0;left:-42%;width:42%;background:linear-gradient(90deg,transparent,var(--dsw-alias-accent,#4d9fff) 60%,#fff);box-shadow:0 0 10px 1px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 70%,transparent);animation:dkan-flow calc(1.9s / var(--dkan-speed,1)) linear infinite;}',
2848
+ "@keyframes dkan-flow{to{left:100%}}",
2849
+ // 完成瞬间的一次性流光(成功绿 / 异常红),动画结束自动清场
2850
+ ".dkan-done{position:fixed;top:0;left:0;right:0;height:3px;z-index:9991;pointer-events:none;background:linear-gradient(90deg,transparent,var(--dsw-alias-state-success-primary,#34d399) 50%,#fff);background-size:50% 100%;background-repeat:no-repeat;animation:dkan-done 1.1s var(--ds-ease-in-out) forwards;}",
2851
+ ".dkan-done.err{background-image:linear-gradient(90deg,transparent,var(--dsw-alias-state-error-primary,#f87171) 50%,#fff);}",
2852
+ "@keyframes dkan-done{0%{background-position:-60% 0;opacity:0}25%{opacity:1}100%{background-position:160% 0;opacity:0}}",
2853
+ // 环屏巡航:光点沿屏幕边缘转一整圈
2854
+ ".dkan-orbit{position:fixed;top:0;left:0;width:12px;height:12px;z-index:9990;pointer-events:none;border-radius:50%;background:var(--dsw-alias-accent,#4d9fff);box-shadow:0 0 14px 4px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 60%,transparent),0 0 30px 8px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 25%,transparent);animation:dkan-orbit calc(14s / var(--dkan-speed,1)) linear infinite;}",
2855
+ "@keyframes dkan-orbit{0%{top:0;left:0}25%{top:0;left:calc(100vw - 12px)}50%{top:calc(100vh - 12px);left:calc(100vw - 12px)}75%{top:calc(100vh - 12px);left:0}100%{top:0;left:0}}",
2856
+ // ===== 氛围动效 =====
2857
+ ".dkan-amb{position:fixed;inset:0;z-index:9989;pointer-events:none;overflow:hidden;}",
2858
+ // 代码雨:字符列缓落(提亮加大,速度随吞吐)
2859
+ ".dkan-matrix span{position:absolute;top:-12%;writing-mode:vertical-rl;font-family:var(--ds-font-family-code,monospace);color:var(--dsw-alias-accent,#4d9fff);text-shadow:0 0 6px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 60%,transparent);animation:dkan-fall linear infinite;will-change:transform;}",
2860
+ "@keyframes dkan-fall{to{transform:translateY(125vh)}}",
2861
+ // 星野:星点缓慢飘移 + 闪烁(加亮加发光)+ 月亮 + 流星
2862
+ ".dkan-stars .dkan-star{position:absolute;border-radius:50%;background:#cfe3ff;box-shadow:0 0 4px 1px color-mix(in srgb,#8ab6ff 55%,transparent);animation:dkan-star ease-in-out infinite alternate;}",
2863
+ "@keyframes dkan-star{0%{opacity:.3;transform:translate(0,0)}50%{opacity:1}100%{opacity:.45;transform:translate(var(--dx),var(--dy))}}",
2864
+ // 月亮:右上弯月(radial-gradient 咬出月牙,透明区不遮挡背景;外圈柔光晕)
2865
+ ".dkan-moon{position:absolute;top:9%;right:10%;width:36px;height:36px;border-radius:50%;background:radial-gradient(circle at 66% 34%,transparent 0 44%,#fdf6d8 46%,#e8d9a0 78%,#d8c78a);box-shadow:0 0 18px 4px color-mix(in srgb,#fdf6d8 35%,transparent),0 0 44px 12px color-mix(in srgb,#fdf6d8 15%,transparent);}",
2866
+ // 流星:斜向划过的光带(亮头 + 渐隐尾),周期出现
2867
+ ".dkan-meteor{position:absolute;width:110px;height:2px;border-radius:2px;background:linear-gradient(90deg,#fff,color-mix(in srgb,#8ab6ff 60%,transparent) 40%,transparent);transform:rotate(35deg);transform-origin:left center;opacity:0;animation:dkan-meteor 8.4s linear infinite;}",
2868
+ '.dkan-meteor::before{content:"";position:absolute;left:-2px;top:-2px;width:6px;height:6px;border-radius:50%;background:#fff;box-shadow:0 0 8px 2px color-mix(in srgb,#cfe3ff 70%,transparent);}',
2869
+ "@keyframes dkan-meteor{0%{opacity:0;transform:rotate(35deg) translateX(0)}3%{opacity:1}10%{opacity:0;transform:rotate(35deg) translateX(46vh)}100%{opacity:0;transform:rotate(35deg) translateX(46vh)}}",
2870
+ // 极光:顶部柔光带呼吸流动(加浓)
2871
+ ".dkan-aurora i{position:absolute;top:-40%;left:-20%;width:70%;height:80%;border-radius:50%;filter:blur(50px);opacity:.32;animation:dkan-aurora ease-in-out infinite alternate;}",
2872
+ ".dkan-aurora i:nth-child(1){background:#4d9fff;}",
2873
+ ".dkan-aurora i:nth-child(2){background:#34d399;left:20%;animation-delay:-2s;}",
2874
+ ".dkan-aurora i:nth-child(3){background:#a78bfa;left:55%;animation-delay:-4s;}",
2875
+ "@keyframes dkan-aurora{0%{transform:translateX(-8%) scaleY(1)}100%{transform:translateX(10%) scaleY(1.3)}}",
2876
+ // ===== 交互反馈层 =====
2877
+ ".dkan-fxwrap{position:fixed;inset:0;z-index:9992;pointer-events:none;overflow:hidden;}",
2878
+ ".dkan-fx{position:absolute;}",
2879
+ // 纸飞机:从点击处向右上飞出淡出(加大加亮)
2880
+ ".dkan-fx-plane{color:var(--dsw-alias-accent,#4d9fff);font-size:24px;text-shadow:0 0 8px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 70%,transparent);animation:dkan-plane 1.2s var(--ds-ease-in-out) forwards;}",
2881
+ "@keyframes dkan-plane{0%{opacity:0;transform:translate(0,0) rotate(-20deg) scale(.6)}15%{opacity:1;transform:translate(20px,-14px) rotate(-20deg) scale(1.1)}100%{opacity:0;transform:translate(240px,-160px) rotate(-20deg) scale(1)}}",
2882
+ // 火花:粒子四散(加大加多散得更开)
2883
+ ".dkan-fx-spark i{position:absolute;width:7px;height:7px;border-radius:50%;box-shadow:0 0 6px currentColor;animation:dkan-spark .9s var(--ds-ease-in-out) forwards;}",
2884
+ "@keyframes dkan-spark{0%{opacity:1;transform:translate(0,0) scale(1)}100%{opacity:0;transform:translate(var(--dx),var(--dy)) scale(.4)}}",
2885
+ // 流光:横向扫过(切会话,加高加亮)
2886
+ ".dkan-fx-streak{top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,var(--dsw-alias-accent,#4d9fff) 50%,#fff);background-size:45% 100%;background-repeat:no-repeat;box-shadow:0 0 12px 2px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 50%,transparent);animation:dkan-streak 1s var(--ds-ease-in-out) forwards;}",
2887
+ "@keyframes dkan-streak{0%{background-position:-50% 0;opacity:0}20%{opacity:1}100%{background-position:150% 0;opacity:0}}",
2888
+ // 微光:全屏柔光一闪(切工作目录,加浓)
2889
+ ".dkan-fx-flash{inset:0;background:radial-gradient(ellipse at center,color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 26%,transparent),transparent 75%);animation:dkan-flash .8s var(--ds-ease-in-out) forwards;}",
2890
+ "@keyframes dkan-flash{0%{opacity:0}30%{opacity:1}100%{opacity:0}}",
2891
+ // 光涌:底部向上涌起(任务开始,加高加浓)
2892
+ ".dkan-fx-surge{left:0;right:0;bottom:0;height:42%;background:linear-gradient(0deg,color-mix(in srgb,var(--dsw-alias-state-success-primary,#34d399) 38%,transparent),transparent);animation:dkan-surge 1.2s var(--ds-ease-in-out) forwards;}",
2893
+ "@keyframes dkan-surge{0%{opacity:0;transform:translateY(45%)}30%{opacity:1}100%{opacity:0;transform:translateY(-35%)}}",
2894
+ // 彩带:顶部飘落(任务完成庆祝,加大加多)
2895
+ ".dkan-fx-confetti{inset:0;}",
2896
+ ".dkan-fx-confetti i{position:absolute;top:-14px;width:8px;height:13px;border-radius:2px;box-shadow:0 0 4px currentColor;animation:dkan-confetti 2s var(--ds-ease-in-out) forwards;}",
2897
+ "@keyframes dkan-confetti{0%{opacity:1;transform:translateY(0) rotate(0)}100%{opacity:0;transform:translateY(75vh) translateX(var(--dx)) rotate(var(--r))}}",
2898
+ // 右下角状态徽标(玻璃拟态,可点击);抬到 dsh 输入卡上方避免重叠错位
2899
+ ".dkan-badge{position:fixed;right:20px;bottom:calc(var(--dsh-composer-height,152px) + 20px);z-index:9990;display:inline-flex;align-items:center;gap:8px;padding:7px 14px;border-radius:999px;cursor:pointer;border:1px solid var(--dsw-alias-border-l1);background:color-mix(in srgb,var(--dsw-alias-bg-layer-2) 78%,transparent);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);box-shadow:0 6px 24px rgb(0 0 0 / .16);color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;line-height:18px;pointer-events:auto;animation:dkan-rise .3s var(--ds-ease-in-out);transition:color .15s var(--ds-ease-in-out);}",
2900
+ ".dkan-badge:hover{color:var(--dsw-alias-label-primary);}",
2901
+ ".dkan-badge .n{color:var(--dsw-alias-label-primary);font-weight:600;}",
2902
+ "@keyframes dkan-rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}",
2903
+ // 徽标圆点与两种动效(呼吸 / 轨道环)
2904
+ ".dkan-dotwrap{position:relative;width:16px;height:16px;flex:none;display:inline-flex;align-items:center;justify-content:center;}",
2905
+ ".dkan-dot{width:9px;height:9px;border-radius:50%;background:var(--dsw-alias-accent,#4d9fff);box-shadow:0 0 8px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 55%,transparent);}",
2906
+ ".dkan-breathe .dkan-dot{animation:dkan-breathe calc(2.6s / var(--dkan-speed,1)) ease-in-out infinite;}",
2907
+ "@keyframes dkan-breathe{0%,100%{transform:scale(1);opacity:.55}50%{transform:scale(1.6);opacity:1}}",
2908
+ ".dkan-ring{position:absolute;inset:0;border-radius:50%;background:conic-gradient(from 0deg,transparent 0 68%,var(--dsw-alias-accent,#4d9fff) 92%,#fff);-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 2px));mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 2px));animation:dkan-spin calc(2.2s / var(--dkan-speed,1)) linear infinite;opacity:.9;}",
2909
+ "@keyframes dkan-spin{to{transform:rotate(360deg)}}",
2910
+ // 通知卡片栈(右上角)
2911
+ ".dkan-toasts{position:fixed;top:16px;right:16px;z-index:9995;display:flex;flex-direction:column;gap:8px;width:min(380px,calc(100vw - 32px));}",
2912
+ ".dkan-toast{border-radius:12px;padding:12px 14px;pointer-events:auto;background:color-mix(in srgb,var(--dsw-alias-bg-layer-2) 88%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid var(--dsw-alias-border-l1);box-shadow:0 10px 36px rgb(0 0 0 / .22);animation:dkan-toast-in .32s var(--ds-ease-in-out);}",
2913
+ ".dkan-toast.out{animation:dkan-toast-out .24s var(--ds-ease-in-out) forwards;}",
2914
+ "@keyframes dkan-toast-in{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}",
2915
+ "@keyframes dkan-toast-out{to{opacity:0;transform:translateX(10px)}}",
2916
+ ".dkan-toast-head{display:flex;align-items:center;gap:8px;margin-bottom:4px;}",
2917
+ ".dkan-toast-mark{width:8px;height:8px;border-radius:50%;flex:none;}",
2918
+ ".dkan-toast-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
2919
+ ".dkan-toast-close{cursor:pointer;flex:none;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:6px;width:22px;height:22px;font-size:11px;line-height:1;display:inline-flex;align-items:center;justify-content:center;font-family:inherit;}",
2920
+ ".dkan-toast-close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
2921
+ ".dkan-toast-body{font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.7;white-space:pre-line;word-break:break-word;}",
2922
+ // 面板页布局
2923
+ ".dkan-root{display:flex;flex-direction:column;gap:10px;}",
2924
+ ".dkan-note{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.6;}",
2925
+ ".dkan-err{color:var(--dsw-alias-state-error-primary);}",
2926
+ ".dkan-sec{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:10px 12px;display:flex;flex-direction:column;gap:8px;}",
2927
+ ".dkan-sec-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
2928
+ ".dkan-sec-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary);flex:none;}",
2929
+ ".dkan-sec-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);flex:1;min-width:120px;}",
2930
+ ".dkan-sec-sw{margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:8px;}",
2931
+ ".dkan-sec-swlabel{font-size:11px;color:var(--dsw-alias-label-tertiary);white-space:nowrap;}",
2932
+ ".dkan-sec-swlabel.on{color:var(--dsw-alias-state-success-primary);}",
2933
+ ".dkan-refresh{cursor:pointer;flex:none;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:2px 10px;font-family:inherit;font-size:12px;}",
2934
+ ".dkan-refresh:hover{background:var(--dsw-alias-interactive-bg-hover);}",
2935
+ // 模式选择卡(带缩微预览)
2936
+ ".dkan-modes{display:flex;gap:8px;flex-wrap:wrap;}",
2937
+ ".dkan-mode{flex:1;min-width:150px;display:flex;flex-direction:column;gap:6px;padding:10px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2);cursor:pointer;font-family:inherit;text-align:left;transition:border-color .15s var(--ds-ease-in-out);}",
2938
+ ".dkan-mode:hover{border-color:var(--dsw-alias-accent,#4d9fff);}",
2939
+ ".dkan-mode.on{border-color:var(--dsw-alias-accent,#4d9fff);box-shadow:0 0 0 1px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 40%,transparent);}",
2940
+ ".dkan-mode-name{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:6px;}",
2941
+ '.dkan-mode.on .dkan-mode-name::after{content:"\u2713";color:var(--dsw-alias-accent,#4d9fff);}',
2942
+ ".dkan-mode-desc{font-size:11px;color:var(--dsw-alias-label-tertiary);line-height:1.5;}",
2943
+ ".dkan-robot-controls{display:flex;flex-direction:column;gap:8px;padding:9px 10px;border:1px solid color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 28%,var(--dsw-alias-border-l1));border-radius:9px;background:color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 5%,var(--dsw-alias-bg-layer-2));}",
2944
+ ".dkan-robot-controls-head{display:flex;align-items:center;justify-content:space-between;font-size:12px;color:var(--dsw-alias-label-primary);}",
2945
+ ".dkan-robot-controls-head strong{font-variant-numeric:tabular-nums;color:var(--dsw-alias-accent,#4d9fff);}",
2946
+ ".dkan-robot-size-options{display:flex;gap:6px;flex-wrap:wrap;}",
2947
+ ".dkan-robot-size-options button{cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;padding:3px 10px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font:inherit;font-size:11px;}",
2948
+ ".dkan-robot-size-options button:hover,.dkan-robot-size-options button.on{border-color:var(--dsw-alias-accent,#4d9fff);color:var(--dsw-alias-label-primary);}",
2949
+ ".dkan-robot-slider-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap;font-size:11px;color:var(--dsw-alias-label-tertiary);}",
2950
+ ".dkan-robot-slider-row input{accent-color:var(--dsw-alias-accent,#4d9fff);width:min(240px,100%);}",
2951
+ ".dkan-prev{height:30px;border-radius:6px;background:var(--dsw-alias-bg-layer-1);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;}",
2952
+ ".dkan-prev-flow{position:absolute;top:0;left:0;right:0;height:3px;background:color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 30%,transparent);}",
2953
+ '.dkan-prev-flow::after{content:"";position:absolute;top:0;bottom:0;left:-40%;width:40%;background:linear-gradient(90deg,transparent,var(--dsw-alias-accent,#4d9fff));animation:dkan-flow 1.9s linear infinite;}',
2954
+ ".dkan-prev-box{--dkan-speed:1;}",
2955
+ ".dkan-prev-orbit{position:absolute;top:3px;left:3px;width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-accent,#4d9fff);box-shadow:0 0 7px 2px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 55%,transparent);animation:dkan-prev-orbit 3s linear infinite;}",
2956
+ "@keyframes dkan-prev-orbit{0%{top:3px;left:3px}25%{top:3px;left:calc(100% - 10px)}50%{top:calc(100% - 10px);left:calc(100% - 10px)}75%{top:calc(100% - 10px);left:3px}100%{top:3px;left:3px}}",
2957
+ // 预览:代码雨(字符列下落)
2958
+ ".dkan-prev-matrix i{position:absolute;top:-100%;writing-mode:vertical-rl;font-size:8px;font-family:var(--ds-font-family-code,monospace);color:var(--dsw-alias-accent,#4d9fff);opacity:.5;animation:dkan-prev-fall 2.2s linear infinite;}",
2959
+ ".dkan-prev-matrix i:nth-child(1){left:12%;}",
2960
+ ".dkan-prev-matrix i:nth-child(2){left:32%;animation-delay:-.6s;}",
2961
+ ".dkan-prev-matrix i:nth-child(3){left:52%;animation-delay:-1.2s;}",
2962
+ ".dkan-prev-matrix i:nth-child(4){left:72%;animation-delay:-.3s;}",
2963
+ ".dkan-prev-matrix i:nth-child(5){left:88%;animation-delay:-1.6s;}",
2964
+ '.dkan-prev-matrix i::after{content:"01</>";}',
2965
+ "@keyframes dkan-prev-fall{to{transform:translateY(300%)}}",
2966
+ // 预览:星野(星点闪烁)
2967
+ ".dkan-prev-stars i{position:absolute;width:2px;height:2px;border-radius:50%;background:var(--dsw-alias-label-secondary);animation:dkan-prev-star 1.6s ease-in-out infinite alternate;}",
2968
+ ".dkan-prev-stars i:nth-child(1){left:15%;top:25%;}",
2969
+ ".dkan-prev-stars i:nth-child(2){left:40%;top:60%;animation-delay:-.4s;}",
2970
+ ".dkan-prev-stars i:nth-child(3){left:60%;top:30%;animation-delay:-.8s;}",
2971
+ ".dkan-prev-stars i:nth-child(4){left:80%;top:55%;animation-delay:-1.2s;}",
2972
+ ".dkan-prev-stars i:nth-child(5){left:28%;top:70%;animation-delay:-.6s;}",
2973
+ ".dkan-prev-stars i:nth-child(6){left:70%;top:75%;animation-delay:-1s;}",
2974
+ "@keyframes dkan-prev-star{0%{opacity:.2}100%{opacity:.9}}",
2975
+ // 预览:极光(柔光带呼吸)
2976
+ ".dkan-prev-aurora i{position:absolute;top:-30%;width:60%;height:120%;border-radius:50%;filter:blur(8px);opacity:.35;animation:dkan-prev-aurora 2.4s ease-in-out infinite alternate;}",
2977
+ ".dkan-prev-aurora i:nth-child(1){left:5%;background:#4d9fff;}",
2978
+ ".dkan-prev-aurora i:nth-child(2){left:45%;background:#34d399;animation-delay:-1.2s;}",
2979
+ "@keyframes dkan-prev-aurora{0%{transform:translateX(-10%)}100%{transform:translateX(15%)}}",
2980
+ ".dkan-prev-bot{height:92px;justify-content:center;}",
2981
+ ".dkan-prev-bot .dkan-bot-scene{--dkan-bot-scale:1;transform:scale(.56);transform-origin:center;}",
2982
+ // ===== 桌面伙伴:具象人物 + 四屏工位(尺寸可调,整卡可拖拽) =====
2983
+ // 卡片:玻璃拟态;默认停泊右下(dsh 输入卡上方),拖动后位置持久化、可放屏幕任意处
2984
+ ".dkan-botcard{--dkan-bot-scale:1.35;position:fixed;right:20px;bottom:calc(var(--dsh-composer-height,152px) + 20px);z-index:9990;display:flex;flex-direction:column;gap:6px;padding:10px 12px;border-radius:16px;cursor:grab;border:1px solid var(--dsw-alias-border-l1);background:color-mix(in srgb,var(--dsw-alias-bg-layer-2) 86%,transparent);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 12px 36px rgb(0 0 0 / .22);color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;pointer-events:auto;touch-action:none;user-select:none;animation:dkan-rise .3s var(--ds-ease-in-out);}",
2985
+ ".dkan-botcard:hover,.dkan-botcard:focus-visible{border-color:var(--dsw-alias-accent,#4d9fff);outline:none;}",
2986
+ ".dkan-botcard.dkan-dragging{cursor:grabbing;animation:none;}",
2987
+ ".dkan-botcard .n{color:var(--dsw-alias-label-primary);font-weight:600;}",
2988
+ ".dkan-bot-cap{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:18px;}",
2989
+ ".dkan-bot-resize{position:absolute;right:7px;bottom:7px;width:15px;height:15px;padding:0;border:0;border-radius:4px;background:linear-gradient(135deg,transparent 0 42%,var(--dsw-alias-label-tertiary) 44% 51%,transparent 53% 62%,var(--dsw-alias-label-tertiary) 64% 71%,transparent 73%);cursor:nwse-resize;touch-action:none;opacity:.72;}",
2990
+ ".dkan-bot-resize:hover,.dkan-bot-resize:focus-visible{opacity:1;outline:1px solid var(--dsw-alias-accent,#4d9fff);outline-offset:1px;}",
2991
+ // ===== 3D 场景(CSS 长方体拼装:世界层统一 3/4 视角——俯视 + 侧身面向镜头) =====
2992
+ ".dkan-bot-scene{position:relative;width:calc(220px * var(--dkan-bot-scale,1));height:calc(132px * var(--dkan-bot-scale,1));perspective:calc(620px * var(--dkan-bot-scale,1));perspective-origin:55% 18%;--dk3-side:#7c8ba0;--dk3-side-hi:#a9b8ca;--dk3-side-dk:#4c5870;--dk3-screen:#0d1526;--dkan-code-a:#4ade80;--dkan-code-b:#60a5fa;--dkan-code-c:#fbbf24;}",
2993
+ ".dk3-world{position:absolute;left:0;top:0;width:220px;height:132px;transform-style:preserve-3d;transform-origin:top left;transform:scale(var(--dkan-bot-scale,1)) rotateX(-15deg) rotateY(-30deg);}",
2994
+ ".dk3-box{position:absolute;transform-style:preserve-3d;}",
2995
+ ".dk3-face{position:absolute;left:50%;top:50%;display:block;background:var(--dk3-side);backface-visibility:hidden;border-radius:1px;}",
2996
+ // 金属件着色:顶面亮、底面暗,正/侧面中调(3D 光感)
2997
+ ".dk3-metal .dk3-face{background:linear-gradient(180deg,#93a5ba,#71809a);}",
2998
+ ".dk3-metal .dk3-face:nth-child(5){background:linear-gradient(180deg,var(--dk3-side-hi),#9dadc2);}",
2999
+ ".dk3-metal .dk3-face:nth-child(6){background:var(--dk3-side-dk);}",
3000
+ // 书桌与桌腿
3001
+ ".dk3-desk .dk3-face{background:linear-gradient(180deg,#9db0c6,#7f92aa);}",
3002
+ ".dk3-desk .dk3-face:nth-child(5){background:#c3d2e2;}",
3003
+ // 显示器(薄盒 + 贴在前面的屏幕;组内扇形微转,整组后撤出桌沿)
3004
+ ".dk3-mon3{position:absolute;transform-style:preserve-3d;}",
3005
+ ".dk3-frame .dk3-face{background:#3a465b;}",
3006
+ ".dk3-frame .dk3-face:nth-child(5){background:#55647d;}",
3007
+ ".dk3-screen{position:absolute;left:50%;top:50%;background:var(--dk3-screen);border-radius:2px;overflow:hidden;transition:opacity .4s var(--ds-ease-in-out),box-shadow .4s var(--ds-ease-in-out);}",
3008
+ // 屏幕内容:代码块整体向上滚动(10 行=5 行×2 循环,滚半程无缝接回)+ 闪烁光标,速度随 --dkan-speed
3009
+ ".dk3-code{position:absolute;left:0;top:0;right:0;display:block;animation:dk3-scroll calc(5s / var(--dkan-speed,1)) linear infinite;}",
3010
+ ".dk3-code i{display:block;height:2px;border-radius:1px;margin:2px 3px 0;background:var(--dkan-code-b);opacity:.55;}",
3011
+ ".dk3-code i:nth-child(5n+1){width:58%;background:var(--dkan-code-a);}",
3012
+ ".dk3-code i:nth-child(5n+2){width:82%;}",
3013
+ ".dk3-code i:nth-child(5n+3){width:46%;background:var(--dkan-code-c);}",
3014
+ ".dk3-code i:nth-child(5n+4){width:72%;}",
3015
+ ".dk3-code i:nth-child(5n){width:54%;background:var(--dkan-code-a);}",
3016
+ ".dk3-cur{position:absolute;left:3px;bottom:2px;width:4px;height:2px;background:var(--dkan-code-b);animation:dkan-blink3 1s steps(1) infinite;}",
3017
+ "@keyframes dk3-scroll{to{transform:translateY(-50%)}}",
3018
+ // 人物组(坐在桌子中间近镜头侧 z=30,侧身面朝 +X 三屏;不会被桌体遮挡)
3019
+ ".dk3-person{position:absolute;left:96px;top:14px;width:44px;height:64px;transform-style:preserve-3d;transform:translateZ(30px);}",
3020
+ // 动漫人物配色:皮肤/头发/卫衣/裤子
3021
+ ".dk3-skin .dk3-face{background:linear-gradient(180deg,#ffd9b8,#f3b98d);}",
3022
+ ".dk3-skin .dk3-face:nth-child(5){background:#ffe3c9;}",
3023
+ ".dk3-hair .dk3-face{background:linear-gradient(180deg,#5b4632,#3f3021);}",
3024
+ ".dk3-hair .dk3-face:nth-child(5){background:#6b543c;}",
3025
+ ".dk3-hood .dk3-face{background:linear-gradient(180deg,#7c8ba0,#5b6a80);}",
3026
+ ".dk3-hood .dk3-face:nth-child(5){background:#93a5ba;}",
3027
+ ".dk3-pants .dk3-face{background:linear-gradient(180deg,#3d4a5c,#2c3646);}",
3028
+ ".dk3-pants .dk3-face:nth-child(5){background:#4a5a70;}",
3029
+ // 人物细节:圆角 + 鞋 + 咖啡杯 + 嘴
3030
+ ".dk3-headbox .dk3-face{border-radius:3px;}",
3031
+ ".dk3-torso .dk3-face{border-radius:3px;}",
3032
+ ".dk3-hair .dk3-face{border-radius:2px;}",
3033
+ ".dk3-shoe .dk3-face{background:#20262f;border-radius:2px;}",
3034
+ ".dk3-mug .dk3-face{background:#c2703d;border-radius:1px;}",
3035
+ ".dk3-mug .dk3-face:nth-child(5){background:#e08a52;}",
3036
+ ".dk3-mouth{position:absolute;left:50%;top:78%;width:5px;height:1.5px;border-radius:1px;background:#b5766a;}",
3037
+ // 椅子
3038
+ ".dk3-chairback .dk3-face{background:linear-gradient(180deg,#3f4c60,#2c3648);}",
3039
+ ".dk3-chairseat .dk3-face{background:#33415a;}",
3040
+ // 头组(俯仰=rotateZ,左右看=rotateY);眼睛贴在 +X 面板上
3041
+ ".dk3-head3{position:absolute;left:14px;top:2px;width:17px;height:20px;transform-style:preserve-3d;transform-origin:50% 85%;transition:transform .25s var(--ds-ease-in-out);}",
3042
+ ".dk3-brows{position:absolute;left:50%;top:30%;display:flex;gap:3px;align-items:center;justify-content:center;}",
3043
+ ".dk3-brows i{width:3px;height:1px;border-radius:2px;background:#4a3428;}",
3044
+ ".dk3-eyes{position:absolute;left:50%;top:52%;display:flex;gap:3px;align-items:center;justify-content:center;}",
3045
+ ".dk3-eyes i{width:3px;height:4px;border-radius:50%;background:radial-gradient(circle at 60% 35%,#fff 0 .5px,#2b3442 .8px);animation:dkan-blink3 4.6s infinite;}",
3046
+ ".dk3-nose{position:absolute;left:50%;top:64%;width:2px;height:2px;border-radius:50%;background:#d99277;}",
3047
+ ".dk3-ear{position:absolute;left:-1px;top:11px;width:3px;height:5px;border-radius:50%;background:#f3b98d;transform:translateZ(2px);}",
3048
+ "@keyframes dkan-blink3{0%,91%,100%{transform:scaleY(1)}94%{transform:scaleY(.15)}}",
3049
+ // 手臂:肩组挂躯干前上,肘组在其下端(前臂+手伸向键盘);write/code 时肘部高频敲击
3050
+ ".dk3-arm3{position:absolute;left:20px;top:30px;width:16px;height:16px;transform-style:preserve-3d;}",
3051
+ ".dk3-elbow{position:absolute;left:0;top:10px;width:15px;height:5px;transform-style:preserve-3d;transform-origin:2px 2px;}",
3052
+ ".dk3-far{transform:translateZ(-8px);filter:brightness(.62);}",
3053
+ // 思考泡泡(贴镜头 2D 层,think 阶段显示)
3054
+ ".dkan-bubble{position:absolute;left:80px;top:4px;display:none;gap:3px;padding:4px 6px;border-radius:8px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);box-shadow:0 2px 6px rgb(0 0 0 / .15);z-index:3;}",
3055
+ ".dkan-bubble i{width:4px;height:4px;border-radius:50%;background:var(--dsw-alias-label-tertiary);animation:dkan-bubdot 1.2s ease-in-out infinite;}",
3056
+ ".dkan-bubble i:nth-child(2){animation-delay:.2s;}",
3057
+ ".dkan-bubble i:nth-child(3){animation-delay:.4s;}",
3058
+ "@keyframes dkan-bubdot{0%,100%{opacity:.25;transform:translateY(0)}50%{opacity:1;transform:translateY(-2px)}}",
3059
+ // ===== 阶段驱动(data-phase 四态,host 由 chunk 流实时同步) =====
3060
+ // think:屏幕调暗 + 仰头苦想 + 泡泡浮现
3061
+ ".dkan-bot-scene[data-phase=think] .dk3-screen{opacity:.32;}",
3062
+ ".dkan-bot-scene[data-phase=think] .dkan-bubble{display:inline-flex;}",
3063
+ ".dkan-bot-scene[data-phase=think] .dk3-head3{animation:dkan-think-head 1.8s ease-in-out infinite alternate;}",
3064
+ ".dkan-bot-scene[data-phase=think] .dk3-arm3:not(.dk3-far){animation:dkan-think-arm 1.8s ease-in-out infinite alternate;}",
3065
+ ".dkan-bot-scene[data-phase=think] .dk3-arm3.dk3-far{animation:dkan-think-arm-far 1.8s ease-in-out infinite alternate;}",
3066
+ "@keyframes dkan-think-head{from{transform:rotateZ(-12deg) translateY(-1px)}to{transform:rotateZ(-22deg) translate(3px,-4px)}}",
3067
+ "@keyframes dkan-think-arm{from{transform:rotateZ(-4deg)}to{transform:rotateZ(-34deg) translate(1px,-8px)}}",
3068
+ "@keyframes dkan-think-arm-far{from{transform:translateZ(-8px) rotateZ(-2deg)}to{transform:translateZ(-8px) rotateZ(-24deg) translate(1px,-7px)}}",
3069
+ // write/code:中屏高亮代码滚动 + 肘部高频敲击 + 低头专注
3070
+ ".dkan-bot-scene[data-phase=write] .dk3-mon3.center .dk3-screen,.dkan-bot-scene[data-phase=code] .dk3-mon3.center .dk3-screen{opacity:1;box-shadow:0 0 10px color-mix(in srgb,var(--dkan-code-b,#60a5fa) 45%,transparent);}",
3071
+ ".dkan-bot-scene[data-phase=write] .dk3-mon3.center .dk3-code,.dkan-bot-scene[data-phase=code] .dk3-mon3.center .dk3-code{animation-duration:calc(2.2s / var(--dkan-speed,1));}",
3072
+ ".dkan-bot-scene[data-phase=write] .dk3-arm3:not(.dk3-far),.dkan-bot-scene[data-phase=code] .dk3-arm3:not(.dk3-far){animation:dkan-output-arm calc(.46s / var(--dkan-speed,1)) ease-in-out infinite alternate;}",
3073
+ ".dkan-bot-scene[data-phase=write] .dk3-arm3.dk3-far,.dkan-bot-scene[data-phase=code] .dk3-arm3.dk3-far{animation:dkan-output-arm-far calc(.46s / var(--dkan-speed,1)) ease-in-out infinite alternate;}",
3074
+ ".dkan-bot-scene[data-phase=write] .dk3-elbow,.dkan-bot-scene[data-phase=code] .dk3-elbow{animation:dkan-type3 calc(.22s / var(--dkan-speed,1)) ease-in-out infinite alternate;}",
3075
+ ".dkan-bot-scene[data-phase=write] .dk3-arm3.dk3-far .dk3-elbow,.dkan-bot-scene[data-phase=code] .dk3-arm3.dk3-far .dk3-elbow{animation-delay:.11s;}",
3076
+ "@keyframes dkan-type3{from{transform:rotate(12deg) translateY(-1px)}to{transform:rotate(-14deg) translateY(2px)}}",
3077
+ "@keyframes dkan-output-arm{from{transform:rotateZ(7deg) translateY(0)}to{transform:rotateZ(-13deg) translateY(4px)}}",
3078
+ "@keyframes dkan-output-arm-far{from{transform:translateZ(-8px) rotateZ(5deg)}to{transform:translateZ(-8px) rotateZ(-11deg) translateY(4px)}}",
3079
+ ".dkan-bot-scene[data-phase=write] .dk3-head3,.dkan-bot-scene[data-phase=code] .dk3-head3{animation:dkan-output-head calc(.8s / var(--dkan-speed,1)) ease-in-out infinite alternate;}",
3080
+ "@keyframes dkan-output-head{from{transform:rotateZ(4deg) translateY(0)}to{transform:rotateZ(10deg) translate(2px,2px)}}",
3081
+ // search:侧屏高亮 + 滚动加速 + 头部左右扫视(一会忙这个一会看那个)
3082
+ ".dkan-bot-scene[data-phase=search] .dk3-mon3.left .dk3-screen,.dkan-bot-scene[data-phase=search] .dk3-mon3.right .dk3-screen{opacity:1;box-shadow:0 0 8px color-mix(in srgb,var(--dkan-code-a,#4ade80) 40%,transparent);}",
3083
+ ".dkan-bot-scene[data-phase=search] .dk3-mon3.left .dk3-code,.dkan-bot-scene[data-phase=search] .dk3-mon3.right .dk3-code{animation-duration:calc(1.6s / var(--dkan-speed,1));}",
3084
+ ".dkan-bot-scene[data-phase=search] .dk3-head3{animation:dkan-scan3 3.4s ease-in-out infinite;}",
3085
+ "@keyframes dkan-scan3{0%,16%{transform:rotateZ(3deg) rotateY(-38deg)}30%,48%{transform:rotateZ(3deg) rotateY(6deg)}62%,80%{transform:rotateZ(3deg) rotateY(38deg)}100%{transform:rotateZ(3deg) rotateY(-38deg)}}",
3086
+ "@media (prefers-reduced-motion:reduce){.dkan-botcard *{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;}}",
3087
+ // 通知子选项行
3088
+ ".dkan-rows-narrow{display:flex;flex-direction:column;gap:6px;}",
3089
+ ".dkan-row{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dsw-alias-label-secondary);flex-wrap:wrap;}",
3090
+ ".dkan-row-label{flex:none;min-width:60px;color:var(--dsw-alias-label-primary);}",
3091
+ ".dkan-row-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
3092
+ ".dkm-miniswitch{cursor:pointer;flex:none;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 12px;font-family:inherit;font-size:11px;line-height:18px;}",
3093
+ ".dkm-miniswitch.on{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
3094
+ ".dkan-select{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:3px 8px;font-size:12px;font-family:inherit;}",
3095
+ // 音效选择卡(名称 + 播放键;选中态描边)
3096
+ ".dkan-sounds{display:flex;gap:6px;flex-wrap:wrap;}",
3097
+ ".dkan-sound{flex:1;min-width:104px;display:flex;align-items:center;justify-content:space-between;gap:6px;padding:6px 10px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-2);cursor:pointer;font-family:inherit;transition:border-color .15s var(--ds-ease-in-out);}",
3098
+ ".dkan-sound:hover{border-color:var(--dsw-alias-accent,#4d9fff);}",
3099
+ ".dkan-sound.on{border-color:var(--dsw-alias-accent,#4d9fff);box-shadow:0 0 0 1px color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 40%,transparent);}",
3100
+ ".dkan-sound-name{font-size:12px;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:5px;}",
3101
+ ".dkan-sound-cur{color:var(--dsw-alias-accent,#4d9fff);font-size:11px;}",
3102
+ ".dkan-sound-play{flex:none;cursor:pointer;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:1;border-radius:50%;width:20px;height:20px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--dsw-alias-border-l2);}",
3103
+ ".dkan-sound-play:hover{color:var(--dsw-alias-label-primary);border-color:currentColor;}",
3104
+ ".dkan-input{flex:1;min-width:220px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:4px 8px;font-size:12px;font-family:inherit;}",
3105
+ ".dkan-input:focus{outline:none;border-color:var(--dsw-alias-accent,#4d9fff);}",
3106
+ ".dkan-row-webhook{flex-wrap:nowrap;}",
3107
+ ".dkan-row-webhook .dkan-input{min-width:0;}",
3108
+ ".dkan-btn{cursor:pointer;flex:none;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:4px 12px;font-family:inherit;font-size:12px;}",
3109
+ ".dkan-btn:hover{background:var(--dsw-alias-interactive-bg-hover);}",
3110
+ ".dkan-btn[disabled]{opacity:.5;cursor:default;}",
3111
+ ".dkan-ok{color:var(--dsw-alias-state-success-primary);}",
3112
+ // 任务列表
3113
+ ".dkan-tasks{display:flex;flex-direction:column;gap:6px;}",
3114
+ ".dkan-tasks-done{border-top:1px dashed var(--dsw-alias-border-l2);padding-top:6px;}",
3115
+ ".dkan-task{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 10px;display:flex;flex-direction:column;gap:3px;}",
3116
+ ".dkan-task-head{display:flex;align-items:center;gap:8px;min-width:0;}",
3117
+ ".dkan-task-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
3118
+ ".dkan-task-meta{display:flex;gap:10px;flex-wrap:wrap;font-size:11px;color:var(--dsw-alias-label-tertiary);}",
3119
+ ".dkan-task-err{font-size:11px;color:var(--dsw-alias-state-error-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
3120
+ ".dkan-tag{flex:none;font-size:10px;border-radius:999px;padding:0 8px;color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);}",
3121
+ ".dkan-tag.on{color:var(--dsw-alias-accent,#4d9fff);border-color:currentColor;}",
3122
+ ".dkan-tag.ok{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
3123
+ ".dkan-tag.err{color:var(--dsw-alias-state-error-primary);border-color:currentColor;}",
3124
+ ".dkan-tag.warn{color:var(--dsw-alias-state-warning-primary);border-color:currentColor;}"
3125
+ ].join("\n");
3126
+ var feature6 = {
3127
+ id: "animation",
3128
+ name: "\u4EFB\u52A1\u52A8\u753B",
3129
+ order: 130,
3130
+ accent: "#f472b6",
3131
+ description: "\u4EFB\u52A1\u8FD0\u884C\u52A8\u753B\uFF08\u6D41\u5149\u7EC6\u7EBF/\u547C\u5438\u5149\u70B9/\u8F68\u9053\u5149\u73AF\uFF09\u4E0E\u5B8C\u6210\u901A\u77E5\uFF0C\u4E24\u7EC4\u5F00\u5173\u72EC\u7ACB\u3001\u914D\u7F6E\u6301\u4E45\u5316",
3132
+ css: css2,
3133
+ View: AnimationView,
3134
+ HomeStat: AnimationStat,
3135
+ Overlay: AnimationOverlay
1613
3136
  };
3137
+
3138
+ // src/client.jsx
3139
+ var DOCK_VERSION = "0.5.0";
3140
+ var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6];
3141
+ var PLANNED_FEATURES = [];
3142
+ var PLANNED_NOTES = {};
1614
3143
  var externalDefs = [];
1615
3144
  var externalListeners = /* @__PURE__ */ new Set();
1616
3145
  function notifyExternal() {
@@ -1633,6 +3162,7 @@ var dockBridge = {
1633
3162
  css: typeof def.css === "string" ? def.css : "",
1634
3163
  View: def.View,
1635
3164
  HomeStat: typeof def.HomeStat === "function" ? def.HomeStat : null,
3165
+ Overlay: typeof def.Overlay === "function" ? def.Overlay : null,
1636
3166
  external: true,
1637
3167
  package: typeof def.package === "string" ? def.package : ""
1638
3168
  };
@@ -1717,9 +3247,22 @@ var SHELL_CSS = [
1717
3247
  ".dockh-card:hover,.dockh-card:focus-visible{border-color:var(--dsw-alias-accent,#4d9fff);outline:none;}",
1718
3248
  ".dockh-head{display:flex;align-items:center;gap:8px;}",
1719
3249
  ".dockh-name{font-weight:600;flex:none;}",
1720
- ".dockh-badge{margin-left:auto;flex:none;font-size:11px;border-radius:999px;padding:0 8px;color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);}",
1721
- ".dockh-badge.on{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
1722
- ".dockh-badge.off{border-style:dashed;}",
3250
+ ".dockh-badge{flex:none;font-size:11px;border-radius:999px;padding:0 8px;color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);}",
3251
+ // 状态标识(非交互:圆点+文字,与可点的开关一眼区分)
3252
+ ".dockh-status{margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--dsw-alias-label-tertiary);white-space:nowrap;}",
3253
+ ".dockh-sdot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--dsw-alias-state-success-primary,#34d399);box-shadow:0 0 4px color-mix(in srgb,var(--dsw-alias-state-success-primary,#34d399) 55%,transparent);}",
3254
+ ".dockh-status.off .dockh-sdot{background:transparent;border:1.5px solid var(--dsw-alias-label-tertiary);box-shadow:none;opacity:.75;}",
3255
+ ".dockh-status.plan .dockh-sdot{background:transparent;border:1.5px dashed var(--dsw-alias-label-tertiary);box-shadow:none;}",
3256
+ // iOS 风滑动开关(首页卡片 / 弹层页脚 / 设置页共用的启停控件)
3257
+ ".dock-sw{flex:none;position:relative;width:34px;height:19px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);cursor:pointer;padding:0;transition:background .18s var(--ds-ease-in-out),border-color .18s var(--ds-ease-in-out);}",
3258
+ '.dock-sw::after{content:"";position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgb(0 0 0 / .35);transition:transform .18s var(--ds-ease-in-out);}',
3259
+ ".dock-sw:hover{border-color:var(--dsw-alias-accent,#4d9fff);}",
3260
+ ".dock-sw.on{background:var(--dsw-alias-state-success-primary,#34d399);border-color:transparent;}",
3261
+ ".dock-sw.on::after{transform:translateX(15px);}",
3262
+ // 弹层页脚:文字标签 + 开关 成组
3263
+ ".dockm-foot-sw{margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:8px;}",
3264
+ ".dockm-foot-swlabel{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
3265
+ ".dockm-foot-swlabel.on{color:var(--dsw-alias-state-success-primary);}",
1723
3266
  ".dockh-desc{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5;}",
1724
3267
  ".dockh-stat{color:var(--dsw-alias-label-tertiary);font-size:12px;border-top:1px solid var(--dsw-alias-border-l1);padding-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
1725
3268
  ".dockh-foot{display:flex;align-items:center;gap:8px;}",
@@ -1756,8 +3299,8 @@ function ensureCss() {
1756
3299
  }
1757
3300
  }
1758
3301
  function useExternalVersion() {
1759
- const [, bump] = import_react7.default.useReducer((n) => n + 1, 0);
1760
- import_react7.default.useEffect(() => {
3302
+ const [, bump] = import_react8.default.useReducer((n) => n + 1, 0);
3303
+ import_react8.default.useEffect(() => {
1761
3304
  externalListeners.add(bump);
1762
3305
  return () => {
1763
3306
  externalListeners.delete(bump);
@@ -1766,20 +3309,20 @@ function useExternalVersion() {
1766
3309
  }
1767
3310
  var lastGeom = { x: null, y: null, w: null, h: null };
1768
3311
  function DockIcon() {
1769
- return import_react7.default.createElement(
3312
+ return import_react8.default.createElement(
1770
3313
  "svg",
1771
3314
  { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.3, "aria-hidden": true },
1772
- import_react7.default.createElement("rect", { x: 2.5, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
1773
- import_react7.default.createElement("rect", { x: 9, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
1774
- import_react7.default.createElement("rect", { x: 2.5, y: 9, width: 4.4, height: 4.4, rx: 1.2 }),
1775
- import_react7.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
3315
+ import_react8.default.createElement("rect", { x: 2.5, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
3316
+ import_react8.default.createElement("rect", { x: 9, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
3317
+ import_react8.default.createElement("rect", { x: 2.5, y: 9, width: 4.4, height: 4.4, rx: 1.2 }),
3318
+ import_react8.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
1776
3319
  );
1777
3320
  }
1778
3321
  function DockEntry(props) {
1779
3322
  const wide = !!props.wide;
1780
- const [open, setOpen] = import_react7.default.useState(panelNav.open);
1781
- import_react7.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
1782
- return import_react7.default.createElement("button", {
3323
+ const [open, setOpen] = import_react8.default.useState(panelNav.open);
3324
+ import_react8.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
3325
+ return import_react8.default.createElement("button", {
1783
3326
  type: "button",
1784
3327
  className: "docke2-btn" + (open ? " docke2-on" : ""),
1785
3328
  style: wide ? { marginLeft: "auto", transform: "translateY(46px)", zIndex: 1, height: 42, lineHeight: "42px", padding: "0 12px" } : { transform: "translateY(44px)", zIndex: 1, width: 36, height: 36, justifyContent: "center", padding: 0 },
@@ -1787,20 +3330,20 @@ function DockEntry(props) {
1787
3330
  "aria-label": "\u529F\u80FD\u575E",
1788
3331
  "aria-expanded": open,
1789
3332
  onClick: () => setPanelOpen(!open)
1790
- }, import_react7.default.createElement(DockIcon, null), wide ? import_react7.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
3333
+ }, import_react8.default.createElement(DockIcon, null), wide ? import_react8.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
1791
3334
  }
1792
3335
  function DockModal() {
1793
- const [nav, setNav] = import_react7.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
1794
- import_react7.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
3336
+ const [nav, setNav] = import_react8.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
3337
+ import_react8.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
1795
3338
  const open = nav.open || typeof document === "undefined";
1796
3339
  const active = nav.active;
1797
3340
  const setActive = navigatePanel;
1798
3341
  const navParams = nav.params;
1799
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
3342
+ const [, force] = import_react8.default.useReducer((n) => n + 1, 0);
1800
3343
  useExternalVersion();
1801
- const [win, setWin] = import_react7.default.useState(() => ({ mode: "normal", x: null, y: null, w: null, h: null }));
1802
- const dlgRef = import_react7.default.useRef(null);
1803
- import_react7.default.useEffect(() => {
3344
+ const [win, setWin] = import_react8.default.useState(() => ({ mode: "normal", x: null, y: null, w: null, h: null }));
3345
+ const dlgRef = import_react8.default.useRef(null);
3346
+ import_react8.default.useEffect(() => {
1804
3347
  if (lastGeom.w) setWin({ mode: "normal", x: lastGeom.x, y: lastGeom.y, w: lastGeom.w, h: lastGeom.h });
1805
3348
  }, []);
1806
3349
  function beginDrag(e, type) {
@@ -1838,13 +3381,13 @@ function DockModal() {
1838
3381
  const mod = isHome ? null : MODULES.find((m) => m.id === active) || MODULES[0];
1839
3382
  const st = mod ? stateOf(mod.id) : null;
1840
3383
  const View = mod ? mod.View : null;
1841
- const viewNode = mod && View ? import_react7.default.createElement(
3384
+ const viewNode = mod && View ? import_react8.default.createElement(
1842
3385
  "div",
1843
3386
  { className: "dockm-view" },
1844
- import_react7.default.createElement(
1845
- mod.external ? FeatureBoundary : import_react7.default.Fragment,
3387
+ import_react8.default.createElement(
3388
+ mod.external ? FeatureBoundary : import_react8.default.Fragment,
1846
3389
  null,
1847
- import_react7.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
3390
+ import_react8.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
1848
3391
  )
1849
3392
  ) : null;
1850
3393
  const enabledCount = MODULES.filter((m) => {
@@ -1858,10 +3401,10 @@ function DockModal() {
1858
3401
  width: win.w != null ? win.w : void 0,
1859
3402
  height: win.mode === "min" ? "auto" : win.h != null ? win.h : void 0
1860
3403
  } : null;
1861
- return import_react7.default.createElement(
3404
+ return import_react8.default.createElement(
1862
3405
  "div",
1863
3406
  { className: "dockm-backdrop", onClick: () => setPanelOpen(false) },
1864
- import_react7.default.createElement(
3407
+ import_react8.default.createElement(
1865
3408
  "div",
1866
3409
  {
1867
3410
  className: "dockm-dialog" + (win.mode === "max" ? " dockm-max" : "") + (win.mode === "min" ? " dockm-min" : ""),
@@ -1869,41 +3412,41 @@ function DockModal() {
1869
3412
  ref: dlgRef,
1870
3413
  onClick: (e) => e.stopPropagation()
1871
3414
  },
1872
- import_react7.default.createElement(
3415
+ import_react8.default.createElement(
1873
3416
  "div",
1874
3417
  {
1875
3418
  className: "dockm-head",
1876
3419
  onPointerDown: (e) => beginDrag(e, "move"),
1877
3420
  onDoubleClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
1878
3421
  },
1879
- import_react7.default.createElement(DockIcon, null),
1880
- import_react7.default.createElement("span", { className: "dockm-title" }, "\u529F\u80FD\u575E"),
1881
- import_react7.default.createElement("span", { className: "dockm-sub" }, "dsh-dock \xB7 \u4E5F\u53EF\u5728 \u8BBE\u7F6E \u2192 \u529F\u80FD\u575E \u6253\u5F00\u7BA1\u7406\u9875"),
1882
- import_react7.default.createElement(
3422
+ import_react8.default.createElement(DockIcon, null),
3423
+ import_react8.default.createElement("span", { className: "dockm-title" }, "\u529F\u80FD\u575E"),
3424
+ import_react8.default.createElement("span", { className: "dockm-sub" }, "dsh-dock \xB7 \u4E5F\u53EF\u5728 \u8BBE\u7F6E \u2192 \u529F\u80FD\u575E \u6253\u5F00\u7BA1\u7406\u9875"),
3425
+ import_react8.default.createElement(
1883
3426
  "span",
1884
3427
  { className: "dockm-ctrls" },
1885
- import_react7.default.createElement("button", {
3428
+ import_react8.default.createElement("button", {
1886
3429
  type: "button",
1887
3430
  className: "dockm-win",
1888
3431
  title: win.mode === "min" ? "\u8FD8\u539F" : "\u6700\u5C0F\u5316",
1889
3432
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "min" ? "normal" : "min" }))
1890
3433
  }, "\u2581"),
1891
- import_react7.default.createElement("button", {
3434
+ import_react8.default.createElement("button", {
1892
3435
  type: "button",
1893
3436
  className: "dockm-win",
1894
3437
  title: win.mode === "max" ? "\u8FD8\u539F" : "\u6700\u5927\u5316",
1895
3438
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
1896
3439
  }, win.mode === "max" ? "\u2750" : "\u25A2"),
1897
- import_react7.default.createElement("button", { type: "button", className: "dockm-close", "aria-label": "\u5173\u95ED", title: "\u5173\u95ED", onClick: () => setPanelOpen(false) }, "\u2715")
3440
+ import_react8.default.createElement("button", { type: "button", className: "dockm-close", "aria-label": "\u5173\u95ED", title: "\u5173\u95ED", onClick: () => setPanelOpen(false) }, "\u2715")
1898
3441
  )
1899
3442
  ),
1900
- import_react7.default.createElement(
3443
+ import_react8.default.createElement(
1901
3444
  "div",
1902
3445
  { className: "dockm-body" },
1903
- import_react7.default.createElement(
3446
+ import_react8.default.createElement(
1904
3447
  "nav",
1905
3448
  { className: "dockm-nav", "aria-label": "\u529F\u80FD\u6A21\u5757" },
1906
- import_react7.default.createElement(
3449
+ import_react8.default.createElement(
1907
3450
  "button",
1908
3451
  {
1909
3452
  type: "button",
@@ -1911,10 +3454,10 @@ function DockModal() {
1911
3454
  className: "dockm-nav-item" + (isHome ? " on" : ""),
1912
3455
  onClick: () => setActive("home")
1913
3456
  },
1914
- import_react7.default.createElement("span", { className: "dockm-navhome" }, import_react7.default.createElement(DockIcon, null)),
1915
- import_react7.default.createElement("span", null, "\u9996\u9875")
3457
+ import_react8.default.createElement("span", { className: "dockm-navhome" }, import_react8.default.createElement(DockIcon, null)),
3458
+ import_react8.default.createElement("span", null, "\u9996\u9875")
1916
3459
  ),
1917
- MODULES.map((m) => import_react7.default.createElement(
3460
+ MODULES.map((m) => import_react8.default.createElement(
1918
3461
  "button",
1919
3462
  {
1920
3463
  type: "button",
@@ -1922,81 +3465,98 @@ function DockModal() {
1922
3465
  className: "dockm-nav-item" + (m.id === active ? " on" : ""),
1923
3466
  onClick: () => setActive(m.id)
1924
3467
  },
1925
- import_react7.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
1926
- import_react7.default.createElement("span", null, m.name),
1927
- m.planned ? import_react7.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
1928
- m.external ? import_react7.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8") : null
3468
+ import_react8.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
3469
+ import_react8.default.createElement("span", null, m.name),
3470
+ m.planned ? import_react8.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
3471
+ m.external ? import_react8.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8") : null
1929
3472
  ))
1930
3473
  ),
1931
- import_react7.default.createElement(
3474
+ import_react8.default.createElement(
1932
3475
  "div",
1933
3476
  { className: "dockm-content" },
1934
- import_react7.default.createElement(
3477
+ import_react8.default.createElement(
1935
3478
  "div",
1936
3479
  { className: "dockm-content-head" },
1937
- import_react7.default.createElement(
3480
+ import_react8.default.createElement(
1938
3481
  "div",
1939
3482
  { className: "dockm-name" },
1940
- isHome ? import_react7.default.createElement("span", { className: "dockm-navhome" }, import_react7.default.createElement(DockIcon, null)) : import_react7.default.createElement("span", { className: "dockm-dot", style: { background: mod.accent } }),
3483
+ isHome ? import_react8.default.createElement("span", { className: "dockm-navhome" }, import_react8.default.createElement(DockIcon, null)) : import_react8.default.createElement("span", { className: "dockm-dot", style: { background: mod.accent } }),
1941
3484
  isHome ? "\u9996\u9875" : mod.name,
1942
- !isHome && mod.planned ? import_react7.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
1943
- !isHome && mod.external ? import_react7.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8\u5305" + (mod.package ? " \xB7 " + mod.package : "")) : null
3485
+ !isHome && mod.planned ? import_react8.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
3486
+ !isHome && mod.external ? import_react8.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8\u5305" + (mod.package ? " \xB7 " + mod.package : "")) : null
1944
3487
  ),
1945
- import_react7.default.createElement(
3488
+ import_react8.default.createElement(
1946
3489
  "div",
1947
3490
  { className: "dockm-desc" },
1948
3491
  isHome ? "\u6240\u6709\u5B50\u529F\u80FD\u603B\u63FD\uFF1A\u8FD0\u884C\u72B6\u6001\u3001\u6982\u8981\u4E0E\u5FEB\u6377\u5F00\u5173\uFF0C\u70B9\u51FB\u5361\u7247\u8FDB\u5165\u5BF9\u5E94\u529F\u80FD\u9875\u3002" : mod.description
1949
3492
  )
1950
3493
  ),
1951
- isHome ? import_react7.default.createElement("div", { className: "dockm-view" }, import_react7.default.createElement(HomeView, { ctx: ctxRef.current, onOpen: setActive, onToggle: force })) : mod.planned ? import_react7.default.createElement("div", { className: "dockm-note" }, PLANNED_NOTES[mod.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st && st.enabled && viewNode ? viewNode : st && st.error ? import_react7.default.createElement("div", { className: "dockm-note dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : import_react7.default.createElement("div", { className: "dockm-note" }, "\u8BE5\u529F\u80FD\u5F53\u524D\u4E3A\u505C\u7528\u72B6\u6001\uFF08\u8BB0\u5FC6\u6001\u968F\u9875\u9762\u751F\u547D\u5468\u671F\uFF0C0.5.0 \u8D77\u6301\u4E45\u5316\uFF09"),
1952
- import_react7.default.createElement(
3494
+ isHome ? import_react8.default.createElement("div", { className: "dockm-view" }, import_react8.default.createElement(HomeView, { ctx: ctxRef.current, onOpen: setActive, onToggle: force })) : mod.planned ? import_react8.default.createElement("div", { className: "dockm-note" }, PLANNED_NOTES[mod.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st && st.enabled && viewNode ? viewNode : st && st.error ? import_react8.default.createElement("div", { className: "dockm-note dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : import_react8.default.createElement("div", { className: "dockm-note" }, "\u8BE5\u529F\u80FD\u5F53\u524D\u4E3A\u505C\u7528\u72B6\u6001\uFF08\u5F00\u5173\u5DF2\u6301\u4E45\u5316\uFF0C\u91CD\u542F\u540E\u4FDD\u6301\uFF09"),
3495
+ import_react8.default.createElement(
1953
3496
  "div",
1954
3497
  { className: "dockm-foot" },
1955
- import_react7.default.createElement("span", null, isHome ? "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u5171 " + MODULES.length + " \u4E2A\u529F\u80FD\u6A21\u5757\uFF0C" + enabledCount + " \u4E2A\u5DF2\u542F\u7528" : "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u65B0\u529F\u80FD\u6309\u8DEF\u7EBF\u56FE\u8FFD\u52A0"),
1956
- !isHome && mod && !mod.planned && st ? import_react7.default.createElement("button", {
1957
- type: "button",
1958
- className: "dockm-switch" + (st.enabled ? " on" : ""),
1959
- onClick: () => {
1960
- toggleFeature(mod.id);
1961
- force();
1962
- }
1963
- }, st.enabled ? "\u5DF2\u542F\u7528\uFF08\u70B9\u51FB\u505C\u7528\uFF09" : "\u5DF2\u505C\u7528\uFF08\u70B9\u51FB\u542F\u7528\uFF09") : null,
1964
- !isHome && mod && typeof mod.Chip === "function" ? import_react7.default.createElement("button", {
1965
- type: "button",
1966
- className: "dockm-switch" + (chipShown(mod.id) ? " on" : ""),
1967
- title: "\u63A7\u5236\u4F1A\u8BDD\u8F93\u5165\u533A\uFF08\u6A21\u578B\u9009\u62E9\u5668\u5DE6\u4FA7\uFF09\u662F\u5426\u663E\u793A\u672C\u529F\u80FD\u7684\u968F\u8EAB\u5C0F\u63A7\u4EF6",
1968
- onClick: () => {
1969
- setChipShown(mod.id, !chipShown(mod.id));
1970
- force();
1971
- }
1972
- }, chipShown(mod.id) ? "\u4F1A\u8BDD\u9875\u663E\u793A\u4E2D" : "\u4F1A\u8BDD\u9875\u5DF2\u9690\u85CF") : null
3498
+ import_react8.default.createElement("span", null, isHome ? "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u5171 " + MODULES.length + " \u4E2A\u529F\u80FD\u6A21\u5757\uFF0C" + enabledCount + " \u4E2A\u5DF2\u542F\u7528" : "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u65B0\u529F\u80FD\u6309\u8DEF\u7EBF\u56FE\u8FFD\u52A0"),
3499
+ !isHome && mod && !mod.planned && st ? import_react8.default.createElement(
3500
+ "span",
3501
+ { className: "dockm-foot-sw" },
3502
+ import_react8.default.createElement("span", { className: "dockm-foot-swlabel" + (st.enabled ? " on" : "") }, st.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
3503
+ import_react8.default.createElement("button", {
3504
+ type: "button",
3505
+ className: "dock-sw" + (st.enabled ? " on" : ""),
3506
+ role: "switch",
3507
+ "aria-checked": !!st.enabled,
3508
+ "aria-label": (st.enabled ? "\u505C\u7528" : "\u542F\u7528") + mod.name,
3509
+ title: st.enabled ? "\u505C\u7528\u300C" + mod.name + "\u300D" : "\u542F\u7528\u300C" + mod.name + "\u300D",
3510
+ onClick: () => {
3511
+ toggleFeature(mod.id);
3512
+ force();
3513
+ }
3514
+ })
3515
+ ) : null,
3516
+ !isHome && mod && typeof mod.Chip === "function" ? import_react8.default.createElement(
3517
+ "span",
3518
+ { className: "dockm-foot-sw" },
3519
+ import_react8.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(mod.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
3520
+ import_react8.default.createElement("button", {
3521
+ type: "button",
3522
+ className: "dock-sw" + (chipShown(mod.id) ? " on" : ""),
3523
+ role: "switch",
3524
+ "aria-checked": chipShown(mod.id),
3525
+ "aria-label": (chipShown(mod.id) ? "\u9690\u85CF" : "\u663E\u793A") + mod.name + "\u7684\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6",
3526
+ title: "\u63A7\u5236\u4F1A\u8BDD\u8F93\u5165\u533A\uFF08\u6A21\u578B\u9009\u62E9\u5668\u5DE6\u4FA7\uFF09\u662F\u5426\u663E\u793A\u672C\u529F\u80FD\u7684\u968F\u8EAB\u5C0F\u63A7\u4EF6",
3527
+ onClick: () => {
3528
+ setChipShown(mod.id, !chipShown(mod.id));
3529
+ force();
3530
+ }
3531
+ })
3532
+ ) : null
1973
3533
  )
1974
3534
  )
1975
3535
  ),
1976
- win.mode === "normal" ? import_react7.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
3536
+ win.mode === "normal" ? import_react8.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
1977
3537
  )
1978
3538
  );
1979
3539
  }
1980
3540
  function HomeView(props) {
1981
3541
  const ctx = props && props.ctx;
1982
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
3542
+ const [, force] = import_react8.default.useReducer((n) => n + 1, 0);
1983
3543
  useExternalVersion();
1984
3544
  const open = (id) => {
1985
3545
  if (props && typeof props.onOpen === "function") props.onOpen(id);
1986
3546
  };
1987
- return import_react7.default.createElement(
3547
+ return import_react8.default.createElement(
1988
3548
  "div",
1989
3549
  { className: "dockh-grid" },
1990
3550
  allModules().map((m) => {
1991
3551
  const st = stateOf(m.id);
1992
3552
  const enabled = !!(st && st.enabled);
1993
3553
  const Stat = m.HomeStat;
1994
- const statNode = m.planned ? import_react7.default.createElement("span", null, PLANNED_NOTES[m.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : enabled && Stat ? import_react7.default.createElement(
1995
- m.external ? FeatureBoundary : import_react7.default.Fragment,
3554
+ const statNode = m.planned ? import_react8.default.createElement("span", null, PLANNED_NOTES[m.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : enabled && Stat ? import_react8.default.createElement(
3555
+ m.external ? FeatureBoundary : import_react8.default.Fragment,
1996
3556
  null,
1997
- import_react7.default.createElement(Stat, { ctx })
1998
- ) : import_react7.default.createElement("span", null, "\u5DF2\u505C\u7528\uFF0C\u542F\u7528\u540E\u5728\u6B64\u5C55\u793A\u8FD0\u884C\u6982\u8981");
1999
- return import_react7.default.createElement(
3557
+ import_react8.default.createElement(Stat, { ctx })
3558
+ ) : import_react8.default.createElement("span", null, "\u5DF2\u505C\u7528\uFF0C\u542F\u7528\u540E\u5728\u6B64\u5C55\u793A\u8FD0\u884C\u6982\u8981");
3559
+ return import_react8.default.createElement(
2000
3560
  "div",
2001
3561
  {
2002
3562
  key: m.id,
@@ -2011,34 +3571,41 @@ function HomeView(props) {
2011
3571
  }
2012
3572
  }
2013
3573
  },
2014
- import_react7.default.createElement(
3574
+ import_react8.default.createElement(
2015
3575
  "div",
2016
3576
  { className: "dockh-head" },
2017
- import_react7.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
2018
- import_react7.default.createElement("span", { className: "dockh-name" }, m.name),
2019
- m.external ? import_react7.default.createElement("span", { className: "dockh-badge", title: m.package || void 0 }, "\u5916\u90E8") : null,
2020
- import_react7.default.createElement(
3577
+ import_react8.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
3578
+ import_react8.default.createElement("span", { className: "dockh-name" }, m.name),
3579
+ m.external ? import_react8.default.createElement("span", { className: "dockh-badge", title: m.package || void 0 }, "\u5916\u90E8") : null,
3580
+ // 状态标识:圆点 + 文字(纯展示,与开关视觉区分)
3581
+ import_react8.default.createElement(
2021
3582
  "span",
2022
- { className: "dockh-badge" + (m.planned ? "" : enabled ? " on" : " off") },
2023
- m.planned ? "\u89C4\u5212\u4E2D" : enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"
2024
- )
2025
- ),
2026
- import_react7.default.createElement("div", { className: "dockh-desc" }, m.description),
2027
- import_react7.default.createElement("div", { className: "dockh-stat" }, statNode),
2028
- import_react7.default.createElement(
2029
- "div",
2030
- { className: "dockh-foot" },
2031
- import_react7.default.createElement("span", { className: "dockh-go" }, "\u67E5\u770B\u8BE6\u60C5 \u2192"),
2032
- m.planned ? null : import_react7.default.createElement("button", {
3583
+ { className: "dockh-status" + (m.planned ? " plan" : enabled ? "" : " off") },
3584
+ import_react8.default.createElement("span", { className: "dockh-sdot" }),
3585
+ import_react8.default.createElement("span", null, m.planned ? "\u89C4\u5212\u4E2D" : enabled ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u505C\u7528")
3586
+ ),
3587
+ // 启停开关(规划中的功能不显示)
3588
+ m.planned ? null : import_react8.default.createElement("button", {
2033
3589
  type: "button",
2034
- className: "dockm-switch" + (enabled ? " on" : ""),
3590
+ className: "dock-sw" + (enabled ? " on" : ""),
3591
+ role: "switch",
3592
+ "aria-checked": enabled,
3593
+ "aria-label": (enabled ? "\u505C\u7528" : "\u542F\u7528") + m.name,
3594
+ title: enabled ? "\u505C\u7528\u300C" + m.name + "\u300D" : "\u542F\u7528\u300C" + m.name + "\u300D",
2035
3595
  onClick: (e) => {
2036
3596
  e.stopPropagation();
2037
3597
  toggleFeature(m.id);
2038
3598
  if (props && typeof props.onToggle === "function") props.onToggle();
2039
3599
  force();
2040
3600
  }
2041
- }, enabled ? "\u505C\u7528" : "\u542F\u7528")
3601
+ })
3602
+ ),
3603
+ import_react8.default.createElement("div", { className: "dockh-desc" }, m.description),
3604
+ import_react8.default.createElement("div", { className: "dockh-stat" }, statNode),
3605
+ import_react8.default.createElement(
3606
+ "div",
3607
+ { className: "dockh-foot" },
3608
+ import_react8.default.createElement("span", { className: "dockh-go" }, "\u67E5\u770B\u8BE6\u60C5 \u2192")
2042
3609
  )
2043
3610
  );
2044
3611
  })
@@ -2046,16 +3613,16 @@ function HomeView(props) {
2046
3613
  }
2047
3614
  function DockPanel() {
2048
3615
  const ctx = ctxRef.current;
2049
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
3616
+ const [, force] = import_react8.default.useReducer((n) => n + 1, 0);
2050
3617
  useExternalVersion();
2051
3618
  const toggle = (id) => {
2052
3619
  toggleFeature(id);
2053
3620
  force();
2054
3621
  };
2055
- return import_react7.default.createElement(
3622
+ return import_react8.default.createElement(
2056
3623
  "div",
2057
3624
  { className: "dock-root" },
2058
- import_react7.default.createElement(
3625
+ import_react8.default.createElement(
2059
3626
  "div",
2060
3627
  { className: "dock-intro" },
2061
3628
  "\u529F\u80FD\u575E\uFF08dsh-dock\uFF09\xB7 \u6240\u6709\u5C0F\u529F\u80FD\u96C6\u4E2D\u5728\u8FD9\u4E00\u4E2A\u9762\u677F\u91CC\u7BA1\u7406\u3002v0.4.0 \u8D77\u6BCF\u4E2A\u529F\u80FD\u662F\u72EC\u7ACB\u6A21\u5757\uFF08features/<id>/\uFF09\uFF0C",
@@ -2064,50 +3631,64 @@ function DockPanel() {
2064
3631
  allModules().map((f) => {
2065
3632
  const st = stateOf(f.id);
2066
3633
  const View = f.View;
2067
- const viewNode = !f.planned && st.enabled && View ? import_react7.default.createElement(
3634
+ const viewNode = !f.planned && st.enabled && View ? import_react8.default.createElement(
2068
3635
  "div",
2069
3636
  { className: "dock-body" },
2070
- import_react7.default.createElement(
2071
- f.external ? FeatureBoundary : import_react7.default.Fragment,
3637
+ import_react8.default.createElement(
3638
+ f.external ? FeatureBoundary : import_react8.default.Fragment,
2072
3639
  null,
2073
- import_react7.default.createElement(View, { ctx, feature: f })
3640
+ import_react8.default.createElement(View, { ctx, feature: f })
2074
3641
  )
2075
3642
  ) : null;
2076
- return import_react7.default.createElement(
3643
+ return import_react8.default.createElement(
2077
3644
  "div",
2078
3645
  { className: "dock-card", key: f.id },
2079
- import_react7.default.createElement(
3646
+ import_react8.default.createElement(
2080
3647
  "div",
2081
3648
  { className: "dock-card-head" },
2082
- import_react7.default.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
2083
- import_react7.default.createElement("span", { className: "dock-name" }, f.name),
2084
- import_react7.default.createElement("span", { className: "dock-desc" }, f.description + (f.external ? "\uFF08\u6765\u81EA\u5916\u90E8\u5305" + (f.package ? " " + f.package : "") + "\uFF09" : "")),
2085
- f.planned ? import_react7.default.createElement("span", { className: "dock-badge" }, "\u89C4\u5212\u4E2D") : import_react7.default.createElement("button", {
2086
- className: "dock-switch" + (st.enabled ? " on" : ""),
3649
+ import_react8.default.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
3650
+ import_react8.default.createElement("span", { className: "dock-name" }, f.name),
3651
+ import_react8.default.createElement("span", { className: "dock-desc" }, f.description + (f.external ? "\uFF08\u6765\u81EA\u5916\u90E8\u5305" + (f.package ? " " + f.package : "") + "\uFF09" : "")),
3652
+ f.planned ? import_react8.default.createElement("span", { className: "dock-badge" }, "\u89C4\u5212\u4E2D") : import_react8.default.createElement("button", {
3653
+ type: "button",
3654
+ className: "dock-sw" + (st.enabled ? " on" : ""),
3655
+ role: "switch",
3656
+ "aria-checked": st.enabled,
3657
+ "aria-label": (st.enabled ? "\u505C\u7528" : "\u542F\u7528") + f.name,
3658
+ title: st.enabled ? "\u505C\u7528\u300C" + f.name + "\u300D" : "\u542F\u7528\u300C" + f.name + "\u300D",
2087
3659
  onClick: () => toggle(f.id)
2088
- }, st.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
2089
- !f.planned && typeof f.Chip === "function" ? import_react7.default.createElement("button", {
2090
- className: "dock-switch" + (chipShown(f.id) ? " on" : ""),
2091
- title: "\u63A7\u5236\u4F1A\u8BDD\u8F93\u5165\u533A\uFF08\u6A21\u578B\u9009\u62E9\u5668\u5DE6\u4FA7\uFF09\u662F\u5426\u663E\u793A\u672C\u529F\u80FD\u7684\u968F\u8EAB\u5C0F\u63A7\u4EF6",
2092
- onClick: () => {
2093
- setChipShown(f.id, !chipShown(f.id));
2094
- force();
2095
- }
2096
- }, chipShown(f.id) ? "\u4F1A\u8BDD\u9875\u663E\u793A" : "\u4F1A\u8BDD\u9875\u9690\u85CF") : null
3660
+ }),
3661
+ !f.planned && typeof f.Chip === "function" ? import_react8.default.createElement(
3662
+ "span",
3663
+ { className: "dockm-foot-sw" },
3664
+ import_react8.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(f.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
3665
+ import_react8.default.createElement("button", {
3666
+ type: "button",
3667
+ className: "dock-sw" + (chipShown(f.id) ? " on" : ""),
3668
+ role: "switch",
3669
+ "aria-checked": chipShown(f.id),
3670
+ "aria-label": (chipShown(f.id) ? "\u9690\u85CF" : "\u663E\u793A") + f.name + "\u7684\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6",
3671
+ title: "\u63A7\u5236\u4F1A\u8BDD\u8F93\u5165\u533A\uFF08\u6A21\u578B\u9009\u62E9\u5668\u5DE6\u4FA7\uFF09\u662F\u5426\u663E\u793A\u672C\u529F\u80FD\u7684\u968F\u8EAB\u5C0F\u63A7\u4EF6",
3672
+ onClick: () => {
3673
+ setChipShown(f.id, !chipShown(f.id));
3674
+ force();
3675
+ }
3676
+ })
3677
+ ) : null
2097
3678
  ),
2098
- f.planned ? import_react7.default.createElement("div", { className: "dock-body" }, PLANNED_NOTES[f.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st.error ? import_react7.default.createElement("div", { className: "dock-body dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : null,
3679
+ f.planned ? import_react8.default.createElement("div", { className: "dock-body" }, PLANNED_NOTES[f.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st.error ? import_react8.default.createElement("div", { className: "dock-body dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : null,
2099
3680
  viewNode
2100
3681
  );
2101
3682
  })
2102
3683
  );
2103
3684
  }
2104
3685
  function DockChips(props) {
2105
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
2106
- import_react7.default.useEffect(() => subscribeFeatureState(() => force()), []);
3686
+ const [, force] = import_react8.default.useReducer((n) => n + 1, 0);
3687
+ import_react8.default.useEffect(() => subscribeFeatureState(() => force()), []);
2107
3688
  const items = [];
2108
3689
  for (const f of allModules()) {
2109
3690
  if (f.planned || !stateOf(f.id).enabled || !chipShown(f.id) || typeof f.Chip !== "function") continue;
2110
- items.push(import_react7.default.createElement(f.Chip, {
3691
+ items.push(import_react8.default.createElement(f.Chip, {
2111
3692
  key: f.id,
2112
3693
  ctx: props.ctx,
2113
3694
  feature: f,
@@ -2117,7 +3698,23 @@ function DockChips(props) {
2117
3698
  }));
2118
3699
  }
2119
3700
  if (items.length === 0) return null;
2120
- return import_react7.default.createElement("div", { className: "dockchip-row" }, items);
3701
+ return import_react8.default.createElement("div", { className: "dockchip-row" }, items);
3702
+ }
3703
+ function FeatureOverlays() {
3704
+ const [, force] = import_react8.default.useReducer((n) => n + 1, 0);
3705
+ useExternalVersion();
3706
+ import_react8.default.useEffect(() => subscribeFeatureState(() => force()), []);
3707
+ const items = [];
3708
+ for (const f of allModules()) {
3709
+ if (f.planned || !stateOf(f.id).enabled || typeof f.Overlay !== "function") continue;
3710
+ items.push(import_react8.default.createElement(
3711
+ FeatureBoundary,
3712
+ { key: f.id },
3713
+ import_react8.default.createElement(f.Overlay, { ctx: ctxRef.current, feature: f })
3714
+ ));
3715
+ }
3716
+ if (items.length === 0) return null;
3717
+ return import_react8.default.createElement(import_react8.default.Fragment, null, items);
2121
3718
  }
2122
3719
  var ctxRef = { current: null };
2123
3720
  function apply(ctx) {
@@ -2128,19 +3725,23 @@ function apply(ctx) {
2128
3725
  if (slots === void 0) return;
2129
3726
  slots.inject("sidebar.footer.action", () => slots.register(
2130
3727
  { name: "sidebar.footer.action", id: "dsh-dock", order: 1, label: "\u529F\u80FD\u575E" },
2131
- (props) => import_react7.default.createElement(DockEntry, props)
3728
+ (props) => import_react8.default.createElement(DockEntry, props)
2132
3729
  ));
2133
3730
  slots.inject("shell.overlay", () => slots.register(
2134
3731
  { name: "shell.overlay", id: "dsh-dock-panel", order: 21, label: "\u529F\u80FD\u575E\u9762\u677F" },
2135
- () => import_react7.default.createElement(DockModal, null)
3732
+ () => import_react8.default.createElement(DockModal, null)
3733
+ ));
3734
+ slots.inject("shell.overlay", () => slots.register(
3735
+ { name: "shell.overlay", id: "dsh-dock-feature-overlays", order: 22, label: "\u529F\u80FD\u575E\u5168\u5C40\u6D6E\u5C42" },
3736
+ () => import_react8.default.createElement(FeatureOverlays, null)
2136
3737
  ));
2137
3738
  slots.inject("settings.section", () => slots.register(
2138
3739
  { name: "settings.section", id: "dsh-dock", order: 90, label: "\u529F\u80FD\u575E" },
2139
- () => import_react7.default.createElement(DockPanel, null)
3740
+ () => import_react8.default.createElement(DockPanel, null)
2140
3741
  ));
2141
3742
  slots.inject("conversation.input.left", () => slots.register(
2142
3743
  { name: "conversation.input.left", id: "dsh-dock-chips", order: 10, label: "\u529F\u80FD\u575E" },
2143
- (zone) => import_react7.default.createElement(DockChips, Object.assign({}, zone, { ctx: ctxRef.current }))
3744
+ (zone) => import_react8.default.createElement(DockChips, Object.assign({}, zone, { ctx: ctxRef.current }))
2144
3745
  ));
2145
3746
  }
2146
3747
  var inject = ["timer"];