dsh-dock 0.4.1 → 0.6.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_react9 = __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) {
@@ -700,7 +722,7 @@ function TokenLogChip(props) {
700
722
  }, [sid]);
701
723
  if (!sid) return null;
702
724
  const t = snap.totals;
703
- const label = snap.err && !t ? snap.err.includes("\u91CD\u542F") ? "\u7528\u91CF\xB7\u9700\u91CD\u542F\u5BBF\u4E3B" : "\u7528\u91CF\xB7\u5931\u8D25" : t ? "\u26C1 " + fmtCompact(t.totalTokens) + (t.cost > 0 ? " \xB7 " + fmtCost(t.cost) : "") : "\u26C1 \u2026";
725
+ const label = snap.err && !t ? snap.err.includes("\u91CD\u542F") ? "\u7528\u91CF\xB7\u9700\u91CD\u542F\u5BBF\u4E3B" : "\u7528\u91CF\xB7\u5931\u8D25" : t ? "\u26C1 " + fmtCompact(t.totalTokens) + (t.cost > 0 ? " \xB7 $" + t.cost.toFixed(2) : "") : "\u26C1 \u2026";
704
726
  const title = t ? "\u672C\u4F1A\u8BDD " + fmtNum(t.calls) + " \u6B21\u8C03\u7528 \xB7 " + fmtNum(t.totalTokens) + " Token \xB7 " + fmtCost(t.cost) + "\uFF08\u4F30\u7B97\uFF09\n\u70B9\u51FB\u5728\u529F\u80FD\u575E\u67E5\u770B\u7528\u91CF\u8BB0\u5F55" : (snap.err ? snap.err + "\n" : "") + "\u70B9\u51FB\u5728\u529F\u80FD\u575E\u67E5\u770B\u7528\u91CF\u8BB0\u5F55";
705
727
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
706
728
  "button",
@@ -746,8 +768,8 @@ var modelsStore = {
746
768
  },
747
769
  load() {
748
770
  if (this.snap.loading) return;
749
- this.set({ loading: true });
750
- fetch("/dsh-dock/models", { signal: AbortSignal.timeout(2e4) }).then((res) => res.ok ? res.json() : Promise.reject(new Error("\u6A21\u578B\u76EE\u5F55\u63A5\u53E3 HTTP " + res.status))).then((data) => this.set({ data, loading: false, error: null })).catch((e) => this.set({ loading: false, error: e && e.message || String(e) }));
771
+ this.set({ loading: true, error: null });
772
+ fetch("/dsh-dock/models", { cache: "no-store", signal: AbortSignal.timeout(2e4) }).then((res) => res.ok ? res.json() : Promise.reject(new Error("\u6A21\u578B\u76EE\u5F55\u63A5\u53E3 HTTP " + res.status))).then((data) => this.set({ data, loading: false, error: null })).catch((e) => this.set({ loading: false, error: e && e.message || String(e) }));
751
773
  }
752
774
  };
753
775
  function useModels() {
@@ -804,6 +826,14 @@ function ModelsView() {
804
826
  const [vpDirty, setVpDirty] = import_react3.default.useState(false);
805
827
  const [vpSaving, setVpSaving] = import_react3.default.useState(false);
806
828
  const [vpMsg, setVpMsg] = import_react3.default.useState(null);
829
+ const [vpDirectExpanded, setVpDirectExpanded] = import_react3.default.useState(false);
830
+ import_react3.default.useEffect(() => {
831
+ modelsStore.load();
832
+ }, []);
833
+ const refreshModels = () => {
834
+ setBuiltKey(null);
835
+ modelsStore.load();
836
+ };
807
837
  const cur = providers.length > 0 ? providers.find((p) => p.id === selId) || providers[0] : null;
808
838
  const wantKey = cur ? cur.id + ":" + String(data && data.generatedAt || 0) : null;
809
839
  if (cur && builtKey !== wantKey) {
@@ -922,7 +952,7 @@ function ModelsView() {
922
952
  {
923
953
  key: v,
924
954
  className: "dkm-check",
925
- title: v === "image" ? "\u52FE\u9009=\u7AEF\u70B9\u539F\u751F\u652F\u6301\u56FE\u7247\uFF08\u539F\u56FE\u76F4\u53D1\uFF0C\u56FE\u7247\u7406\u89E3\u4EE3\u7406\u8DF3\u8FC7\uFF09\uFF1B\u7EAF\u6587\u672C\u6A21\u578B\u52FF\u52FE\u2014\u2014\u6536\u56FE\u4F1A\u81EA\u52A8\u4EA4\u7ED9\u56FE\u7247\u7406\u89E3\u4EE3\u7406\u8BC6\u522B" : null
955
+ title: v === "image" ? "\u7531\u4F60\u58F0\u660E\u8BE5\u7AEF\u70B9\u652F\u6301\u56FE\u7247\uFF1A\u4FDD\u5B58\u540E\u539F\u56FE\u76F4\u53D1\uFF0C\u5E76\u53EF\u4F5C\u4E3A\u89C6\u89C9\u6A21\u578B\u5019\u9009\u3002\u7CFB\u7EDF\u4E0D\u4F1A\u66FF\u4F60\u731C\u6D4B\uFF1B\u7AEF\u70B9\u5B9E\u9645\u4E0D\u652F\u6301\u65F6\u53D6\u6D88\u52FE\u9009\u5373\u53EF\u6062\u590D\u8D70\u56FE\u7247\u7406\u89E3\u4EE3\u7406" : null
926
956
  },
927
957
  import_react3.default.createElement("input", {
928
958
  type: "checkbox",
@@ -985,6 +1015,14 @@ function ModelsView() {
985
1015
  )
986
1016
  );
987
1017
  const body = [];
1018
+ if (data) {
1019
+ body.push(import_react3.default.createElement(
1020
+ "div",
1021
+ { key: "refresh", className: "dkm-topbar" },
1022
+ import_react3.default.createElement("span", { className: "dkm-sub" }, "\u5DF2\u8F7D\u5165 " + providers.length + " \u4E2A Provider\uFF1B\u5728 DSH \u539F\u751F\u6A21\u578B\u8BBE\u7F6E\u4E2D\u65B0\u589E\u540E\uFF0C\u8FD4\u56DE\u672C\u9875\u4F1A\u81EA\u52A8\u66F4\u65B0"),
1023
+ import_react3.default.createElement("button", { type: "button", className: "dkb-refresh", disabled: snap.loading || saving, onClick: refreshModels }, snap.loading ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0\u6A21\u578B\u76EE\u5F55")
1024
+ ));
1025
+ }
988
1026
  if (snap.error) {
989
1027
  body.push(import_react3.default.createElement(
990
1028
  "div",
@@ -1003,13 +1041,23 @@ function ModelsView() {
1003
1041
  ));
1004
1042
  }
1005
1043
  if (data && data.visionProxy !== void 0 && vpDraft) {
1006
- const effInput = (m) => (m.runtimeInput && m.runtimeInput.length > 0 ? m.runtimeInput : m.input) || [];
1044
+ const runtimeImage = (m) => Array.isArray(m.runtimeInput) && m.runtimeInput.indexOf("image") >= 0;
1045
+ const declaredImage = (m) => Array.isArray(m.input) && m.input.indexOf("image") >= 0;
1007
1046
  const vpDirect = [];
1008
1047
  const vpProxied = [];
1009
1048
  for (const p of providers) {
1010
1049
  for (const m of p.models || []) {
1011
- const item = { key: p.id + "/" + m.id, label: (p.displayName || p.id) + " / " + (m.name || m.id), model: m.name || m.id };
1012
- (effInput(m).indexOf("image") >= 0 ? vpDirect : vpProxied).push(item);
1050
+ const declared = declaredImage(m);
1051
+ const runtime = runtimeImage(m);
1052
+ const source = declared ? "\u4F60\u5DF2\u6807\u8BB0\u56FE\u7247" : runtime ? "\u8FD0\u884C\u65F6\u8BC6\u522B" : "\u672A\u6807\u8BB0\u56FE\u7247";
1053
+ const item = {
1054
+ key: p.id + "/" + m.id,
1055
+ label: (p.displayName || p.id) + " / " + (m.name || m.id) + "\uFF08" + source + "\uFF09",
1056
+ model: m.name || m.id,
1057
+ source,
1058
+ declared
1059
+ };
1060
+ (declared || runtime ? vpDirect : vpProxied).push(item);
1013
1061
  }
1014
1062
  }
1015
1063
  const vpCandidates = vpDirect.slice();
@@ -1025,6 +1073,11 @@ function ModelsView() {
1025
1073
  import_react3.default.createElement("span", { className: "dkm-badge" }, vpDraft.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
1026
1074
  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
1075
  ),
1076
+ import_react3.default.createElement(
1077
+ "div",
1078
+ { className: "dkm-note dkm-warn" },
1079
+ "\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"
1080
+ ),
1028
1081
  import_react3.default.createElement(
1029
1082
  "div",
1030
1083
  { className: "dkm-checks" },
@@ -1059,23 +1112,37 @@ function ModelsView() {
1059
1112
  !vpKnown && vpDraft.provider ? import_react3.default.createElement("option", { value: vpKey }, vpDraft.provider + " / " + vpDraft.model + "\uFF08\u5F53\u524D\uFF09") : null,
1060
1113
  vpCandidates.map((c) => import_react3.default.createElement("option", { key: c.key, value: c.key }, c.label))
1061
1114
  ),
1062
- vpCandidates.length === 0 ? import_react3.default.createElement("span", { className: "dkm-sub" }, "\u76EE\u5F55\u91CC\u6682\u65E0\u591A\u6A21\u6001\u6A21\u578B\u2014\u2014\u5148\u5728\u4E0B\u65B9\u7ED9\u771F\xB7\u591A\u6A21\u6001\u6A21\u578B\u52FE\u9009\u300C\u56FE\u7247\u300D\u8F93\u5165\u7C7B\u578B") : null
1115
+ vpCandidates.length === 0 ? import_react3.default.createElement("span", { className: "dkm-sub" }, "\u8FD8\u6CA1\u6709\u6807\u8BB0\u56FE\u7247\u80FD\u529B\u7684\u6A21\u578B\u2014\u2014\u5728\u4E0B\u65B9\u7ED9\u4F60\u786E\u8BA4\u652F\u6301\u56FE\u7247\u7684\u6A21\u578B\u52FE\u9009\u300C\u56FE\u7247\u300D\u5E76\u4FDD\u5B58") : null
1063
1116
  ),
1064
1117
  import_react3.default.createElement(
1065
1118
  "div",
1066
1119
  { className: "dkm-sub" },
1067
- "\u5224\u5B9A\u4E0E\u5B98\u65B9\u8FD0\u884C\u65F6\u540C\u6E90\uFF1A\u300C\u56FE\u7247\u300D\u52FE\u9009\uFF08\u6216\u76EE\u5F55\u9ED8\u8BA4\uFF09= \u7AEF\u70B9\u539F\u751F\u652F\u6301\u3001\u539F\u56FE\u76F4\u53D1\uFF1B\u5176\u4F59\u6A21\u578B\u6536\u56FE\u81EA\u52A8\u8D70\u89C6\u89C9\u6A21\u578B\u3002\u6CE8\u610F\uFF1A\u82E5\u7AEF\u70B9\u5B9E\u9645\u4E0D\u8BA4\u56FE\u5374\u52FE\u4E86\u300C\u56FE\u7247\u300D\uFF0C\u6A21\u578B\u4F1A\u770B\u4E0D\u89C1\u56FE\u7247\u3001\u8F6C\u800C\u7528\u5DE5\u5177\u778E\u6298\u817E\u2014\u2014\u4E0D\u786E\u5B9A\u5C31\u4E0D\u8981\u52FE\uFF0C\u4EA4\u7ED9\u4EE3\u7406\u3002"
1120
+ "\u4EE5\u4F60\u5728\u4E0B\u65B9\u52FE\u9009\u7684\u300C\u56FE\u7247\u300D\u4E3A\u51C6\uFF1B\u8FD0\u884C\u65F6\u8BC6\u522B\u53EA\u662F\u8F85\u52A9\u63D0\u793A\u3002\u5B83\u4E0D\u4EE3\u8868\u5DF2\u8054\u7F51\u5B9E\u6D4B\u53EF\u8C03\u7528\uFF0C\u5B9E\u9645\u53EF\u7528\u6027\u4ECD\u53D6\u51B3\u4E8E Provider \u51ED\u636E\u3001\u989D\u5EA6\u4E0E\u4E0A\u6E38\u670D\u52A1\u3002\u82E5\u7AEF\u70B9\u5B9E\u9645\u4E0D\u8BA4\u56FE\uFF0C\u53D6\u6D88\u8BE5\u6A21\u578B\u7684\u300C\u56FE\u7247\u300D\u52FE\u9009\u5373\u53EF\u6062\u590D\u8D70\u56FE\u7247\u7406\u89E3\u4EE3\u7406\u3002"
1068
1121
  ),
1069
1122
  vpDirect.length > 0 ? import_react3.default.createElement(
1070
1123
  "div",
1071
- { className: "dkm-checks" },
1072
- import_react3.default.createElement("span", { className: "dkm-label" }, "\u539F\u56FE\u76F4\u53D1\uFF08\u591A\u6A21\u6001\uFF0C" + vpDirect.length + "\uFF09\uFF1A"),
1073
- vpDirect.map((c) => import_react3.default.createElement("span", { key: c.key, className: "dkm-chip", title: c.key }, c.model))
1124
+ { className: "dkm-capabilities" },
1125
+ import_react3.default.createElement(
1126
+ "div",
1127
+ { className: "dkm-checks" },
1128
+ import_react3.default.createElement("span", { className: "dkm-label" }, "\u539F\u56FE\u76F4\u53D1\u5019\u9009\uFF08\u4F60\u7684\u6807\u8BB0\u4F18\u5148\uFF0C" + vpDirect.length + "\uFF09\uFF1A"),
1129
+ import_react3.default.createElement("button", {
1130
+ type: "button",
1131
+ className: "dkm-mini",
1132
+ "aria-expanded": vpDirectExpanded,
1133
+ onClick: () => setVpDirectExpanded(!vpDirectExpanded)
1134
+ }, vpDirectExpanded ? "\u6536\u8D77\u5217\u8868" : "\u5C55\u5F00\u5217\u8868")
1135
+ ),
1136
+ vpDirectExpanded ? import_react3.default.createElement(
1137
+ "div",
1138
+ { className: "dkm-checks dkm-capability-list" },
1139
+ vpDirect.map((c) => import_react3.default.createElement("span", { key: c.key, className: "dkm-chip", title: c.key + " \xB7 " + c.source }, c.model))
1140
+ ) : null
1074
1141
  ) : null,
1075
1142
  vpProxied.length > 0 ? import_react3.default.createElement(
1076
1143
  "div",
1077
1144
  { className: "dkm-checks" },
1078
- import_react3.default.createElement("span", { className: "dkm-label" }, "\u8D70\u89C6\u89C9\u4EE3\u7406\uFF08\u7EAF\u6587\u672C\uFF0C" + vpProxied.length + "\uFF09\uFF1A"),
1145
+ import_react3.default.createElement("span", { className: "dkm-label" }, "\u8D70\u89C6\u89C9\u4EE3\u7406\uFF08\u672A\u6807\u8BB0\u56FE\u7247\uFF0C" + vpProxied.length + "\uFF09\uFF1A"),
1079
1146
  import_react3.default.createElement("span", { className: "dkm-sub" }, vpProxied.map((c) => c.model).join("\u3001"))
1080
1147
  ) : null,
1081
1148
  import_react3.default.createElement(
@@ -1155,10 +1222,7 @@ function ModelsView() {
1155
1222
  { className: "dkm-savebar" },
1156
1223
  import_react3.default.createElement("span", { className: "dkm-msg" }, dirty ? "\u6709\u672A\u4FDD\u5B58\u7684\u4FEE\u6539" : "\u65E0\u672A\u4FDD\u5B58\u4FEE\u6539"),
1157
1224
  import_react3.default.createElement("button", { type: "button", className: "dkm-save", disabled: !dirty || saving, onClick: save }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u5199\u56DE\u5B98\u65B9\u914D\u7F6E"),
1158
- import_react3.default.createElement("button", { type: "button", className: "dkb-refresh", disabled: saving, onClick: () => {
1159
- setBuiltKey(null);
1160
- modelsStore.load();
1161
- } }, "\u91CD\u65B0\u62C9\u53D6"),
1225
+ import_react3.default.createElement("button", { type: "button", className: "dkb-refresh", disabled: saving || snap.loading, onClick: refreshModels }, snap.loading ? "\u5237\u65B0\u4E2D\u2026" : "\u91CD\u65B0\u62C9\u53D6"),
1162
1226
  msg ? import_react3.default.createElement("span", { className: "dkm-msg " + (msg.ok ? "ok" : "err") }, msg.text) : null
1163
1227
  )
1164
1228
  ));
@@ -1182,6 +1246,7 @@ var feature2 = {
1182
1246
  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
1247
  css: [
1184
1248
  ".dkm-note{color:var(--dsw-alias-label-secondary);font-size:12px;}",
1249
+ ".dkm-warn{color:var(--dsw-alias-state-warning-primary);}",
1185
1250
  ".dkm-error{color:var(--dsw-alias-state-error-primary);font-size:12px;}",
1186
1251
  ".dkm-chips{display:flex;flex-wrap:wrap;gap:6px;}",
1187
1252
  ".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;}",
@@ -1216,6 +1281,9 @@ var feature2 = {
1216
1281
  ".dkm-msg.ok{color:var(--dsw-alias-state-success-primary);}",
1217
1282
  ".dkm-msg.err{color:var(--dsw-alias-state-error-primary);}",
1218
1283
  ".dkm-list{display:flex;flex-direction:column;gap:8px;}",
1284
+ ".dkm-topbar{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;}",
1285
+ ".dkm-capabilities{display:flex;flex-direction:column;gap:6px;}",
1286
+ ".dkm-capability-list{max-height:168px;overflow:auto;padding:2px 0 2px 2px;}",
1219
1287
  ".dkm-ro{color:var(--dsw-alias-label-secondary);font-size:12px;}",
1220
1288
  ".dkm-mini{cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-family:inherit;font-size:11px;flex:none;}",
1221
1289
  ".dkm-mini:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary);}",
@@ -1258,40 +1326,64 @@ var feature3 = {
1258
1326
 
1259
1327
  // features/theme/view.js
1260
1328
  var import_react5 = __toESM(require("react"), 1);
1261
- function readThemeLabel(ctx) {
1329
+ var import_react6 = require("react");
1330
+ var PREFERENCE_LABELS = { light: "\u4EAE\u8272", dark: "\u6697\u8272", system: "\u8DDF\u968F\u7CFB\u7EDF" };
1331
+ var THEME_LABELS = { light: "\u4EAE\u8272", dark: "\u6697\u8272" };
1332
+ function readThemeInfo(ctx) {
1262
1333
  const theme = ctx && ctx.get ? ctx.get("theme") : void 0;
1263
- if (theme === void 0) return { err: "theme \u670D\u52A1\u4E0D\u53EF\u7528" };
1334
+ if (!theme || typeof theme.getTheme !== "function") return { err: "theme \u670D\u52A1\u4E0D\u53EF\u7528" };
1264
1335
  let snap = null;
1265
1336
  try {
1266
1337
  snap = theme.getTheme();
1267
1338
  } catch (err) {
1268
1339
  return { err: "\u8BFB\u53D6\u5931\u8D25\uFF1A" + String(err && err.message || err) };
1269
1340
  }
1270
- const label = snap && typeof snap.id === "string" ? snap.id : snap && typeof snap.name === "string" ? snap.name : "\u672A\u77E5";
1341
+ const preference = snap && typeof snap.preference === "string" ? snap.preference : "";
1342
+ const activeId = snap && snap.active && typeof snap.active.id === "string" ? snap.active.id : "";
1343
+ const label = (PREFERENCE_LABELS[preference] || preference || "\u672A\u77E5") + (activeId && activeId !== preference && THEME_LABELS[activeId] ? "\uFF08\u5B9E\u9645" + THEME_LABELS[activeId] + "\uFF09" : "");
1271
1344
  return { label };
1272
1345
  }
1346
+ function useThemeInfo(ctx) {
1347
+ const [info, setInfo] = (0, import_react6.useState)(() => readThemeInfo(ctx));
1348
+ (0, import_react6.useEffect)(() => {
1349
+ let off = null;
1350
+ try {
1351
+ if (ctx && typeof ctx.on === "function") {
1352
+ off = ctx.on("theme/change", () => setInfo(readThemeInfo(ctx)));
1353
+ }
1354
+ } catch {
1355
+ }
1356
+ return () => {
1357
+ try {
1358
+ if (typeof off === "function") off();
1359
+ } catch {
1360
+ }
1361
+ };
1362
+ }, [ctx]);
1363
+ return info;
1364
+ }
1273
1365
  function ThemeView(props) {
1274
- const r = readThemeLabel(props && props.ctx);
1366
+ const r = useThemeInfo(props && props.ctx);
1275
1367
  if (r.err) return import_react5.default.createElement("div", null, r.err);
1276
1368
  return import_react5.default.createElement("div", null, "\u5F53\u524D\u4E3B\u9898\uFF1A" + r.label);
1277
1369
  }
1278
1370
  function ThemeStat(props) {
1279
- const r = readThemeLabel(props && props.ctx);
1371
+ const r = useThemeInfo(props && props.ctx);
1280
1372
  if (r.err) return import_react5.default.createElement("span", null, r.err);
1281
- return import_react5.default.createElement("span", null, "\u5F53\u524D\u4E3B\u9898\uFF1A" + r.label);
1373
+ return import_react5.default.createElement("span", null, "\u4E3B\u9898\uFF1A" + r.label);
1282
1374
  }
1283
1375
  var feature4 = {
1284
1376
  id: "theme",
1285
1377
  name: "\u4E3B\u9898\u4FE1\u606F",
1286
1378
  order: 150,
1287
1379
  accent: "#a78bfa",
1288
- description: "\u793A\u4F8B\u529F\u80FD\uFF1A\u8BFB\u53D6\u5F53\u524D\u4E3B\u9898\u5FEB\u7167\uFF08\u7EAF Client\uFF09",
1380
+ description: "\u8BFB\u53D6\u5F53\u524D\u4E3B\u9898\u5FEB\u7167\uFF1A\u504F\u597D\u4E0E\u5B9E\u9645\u751F\u6548\u4E3B\u9898\uFF08\u7EAF Client\uFF0C\u4E3B\u9898\u5207\u6362\u5B9E\u65F6\u5237\u65B0\uFF09",
1289
1381
  View: ThemeView,
1290
1382
  HomeStat: ThemeStat
1291
1383
  };
1292
1384
 
1293
1385
  // features/balance/view.js
1294
- var import_react6 = __toESM(require("react"), 1);
1386
+ var import_react7 = __toESM(require("react"), 1);
1295
1387
  var ACCENT_PALETTE = ["#4d9fff", "#34d399", "#fbbf24", "#a78bfa", "#f472b6", "#38bdf8", "#fb923c", "#4ade80", "#e879f9", "#22d3ee"];
1296
1388
  var CURATED_ACCENTS = {
1297
1389
  "deepseek-official": "#4d9fff",
@@ -1302,7 +1394,6 @@ var CURATED_ACCENTS = {
1302
1394
  anthropic: "#d97757",
1303
1395
  "google-gemini": "#4285f4"
1304
1396
  };
1305
- var C_TOTAL = "#34d399";
1306
1397
  var C_GRANTED = "#22d3ee";
1307
1398
  var C_TOPUP = "#fbbf24";
1308
1399
  var C_ERR = "#f87171";
@@ -1334,8 +1425,8 @@ var balanceStore = {
1334
1425
  }
1335
1426
  };
1336
1427
  function useBalance(ctx) {
1337
- const [snap, setSnap] = import_react6.default.useState(balanceStore.snap);
1338
- import_react6.default.useEffect(() => {
1428
+ const [snap, setSnap] = import_react7.default.useState(balanceStore.snap);
1429
+ import_react7.default.useEffect(() => {
1339
1430
  const off = balanceStore.subscribe(() => setSnap(balanceStore.snap));
1340
1431
  if (!balanceStore.snap.data && !balanceStore.snap.loading) balanceStore.load();
1341
1432
  const disposer = ctx && typeof ctx.interval === "function" ? ctx.interval(() => balanceStore.load(), 5 * 60 * 1e3) : null;
@@ -1349,7 +1440,7 @@ function useBalance(ctx) {
1349
1440
  function BalanceView(props) {
1350
1441
  const snap = useBalance(props && props.ctx);
1351
1442
  const load = () => balanceStore.load();
1352
- import_react6.default.useEffect(() => {
1443
+ import_react7.default.useEffect(() => {
1353
1444
  const pid = props && props.params && props.params.provider;
1354
1445
  if (!pid || typeof document === "undefined") return;
1355
1446
  const t = setTimeout(() => {
@@ -1372,16 +1463,18 @@ function BalanceView(props) {
1372
1463
  const def = data && data.default ? data.default.provider : null;
1373
1464
  const body = [];
1374
1465
  if (snap.error) {
1375
- body.push(import_react6.default.createElement("div", { key: "err", className: "dkb-note dkb-error" }, "\u4F59\u989D\u67E5\u8BE2\u5931\u8D25\uFF1A" + snap.error));
1466
+ body.push(import_react7.default.createElement("div", { key: "err", className: "dkb-note dkb-error" }, "\u4F59\u989D\u67E5\u8BE2\u5931\u8D25\uFF1A" + snap.error));
1376
1467
  } else if (!data) {
1377
- body.push(import_react6.default.createElement("div", { key: "loading", className: "dkb-note" }, snap.loading ? "\u6B63\u5728\u62C9\u53D6\u4F59\u989D\u2026" : "\u8FD8\u6CA1\u6709\u6570\u636E\uFF0C\u70B9\u51FB\u4E0B\u65B9\u5237\u65B0"));
1468
+ body.push(import_react7.default.createElement("div", { key: "loading", className: "dkb-note" }, snap.loading ? "\u6B63\u5728\u62C9\u53D6\u4F59\u989D\u2026" : "\u8FD8\u6CA1\u6709\u6570\u636E\uFF0C\u70B9\u51FB\u4E0B\u65B9\u5237\u65B0"));
1378
1469
  } else if (providers.length === 0) {
1379
- body.push(import_react6.default.createElement("div", { key: "empty", className: "dkb-note" }, "\u6CA1\u6709\u627E\u5230\u5DF2\u914D\u7F6E\u7684\u6A21\u578B Provider"));
1470
+ body.push(import_react7.default.createElement("div", { key: "empty", className: "dkb-note" }, "\u6CA1\u6709\u627E\u5230\u5DF2\u914D\u7F6E\u7684\u6A21\u578B Provider"));
1380
1471
  } else {
1381
- body.push(import_react6.default.createElement(
1472
+ const rank = (p) => p.balance && p.balance.status === "ok" ? 0 : p.balance && p.balance.status === "login-required" ? 1 : 2;
1473
+ const sorted = providers.slice().sort((a, b) => rank(a) - rank(b));
1474
+ body.push(import_react7.default.createElement(
1382
1475
  "div",
1383
1476
  { key: "rows", className: "dkb-rows" },
1384
- providers.map((p) => {
1477
+ sorted.map((p) => {
1385
1478
  const accent = accentOf(p.id);
1386
1479
  const b = p.balance;
1387
1480
  let badge = ["\u672A\u77E5", ""];
@@ -1392,66 +1485,92 @@ function BalanceView(props) {
1392
1485
  else if (b.status === "login-required") badge = ["\u9700\u767B\u5F55", "warn"];
1393
1486
  else badge = ["\u67E5\u8BE2\u5931\u8D25", "err"];
1394
1487
  }
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
1488
  let balBody = null;
1398
1489
  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(
1490
+ const dims = Array.isArray(b.dims) ? b.dims : [];
1491
+ balBody = import_react7.default.createElement(
1492
+ import_react7.default.Fragment,
1493
+ null,
1494
+ import_react7.default.createElement(
1409
1495
  "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
- });
1496
+ { className: "dkb-main" },
1497
+ import_react7.default.createElement("span", { className: "dkb-main-label" }, "\u5269\u4F59\u989D\u5EA6"),
1498
+ import_react7.default.createElement("span", { className: "dkb-main-value" }, fmt(b.remaining) + (b.unit ? " " + b.unit : "")),
1499
+ import_react7.default.createElement(
1500
+ "span",
1501
+ { className: "dkb-main-part" },
1502
+ "\u5DF2\u7528 " + fmt(b.used) + " / \u603B " + fmt(b.limit),
1503
+ b.resetTime ? import_react7.default.createElement("span", null, " \xB7 \u91CD\u7F6E " + String(b.resetTime).slice(0, 10)) : null
1504
+ )
1505
+ ),
1506
+ dims.map((d, i) => import_react7.default.createElement(
1507
+ "div",
1508
+ { key: "d" + i, className: "dkb-dim" },
1509
+ import_react7.default.createElement("span", { className: "dkb-dim-label" }, d.window === "weekly" ? "\u5468\u989D\u5EA6" : "\u5C0F\u65F6\u989D\u5EA6"),
1510
+ import_react7.default.createElement(
1511
+ "span",
1512
+ { className: "dkb-dim-bar" },
1513
+ import_react7.default.createElement("span", { className: "dkb-dim-fill", style: { width: (d.limit > 0 ? Math.min(100, Math.round(d.remaining / d.limit * 100)) : 0) + "%" } })
1514
+ ),
1515
+ import_react7.default.createElement("span", { className: "dkb-dim-text" }, "\u5269 " + fmt(d.remaining) + " / " + fmt(d.limit))
1516
+ ))
1517
+ );
1417
1518
  } else if (b && b.status === "ok") {
1418
1519
  const infos = Array.isArray(b.infos) ? b.infos : [];
1419
- cells.push(infos.map((i, idx) => import_react6.default.createElement(
1520
+ balBody = import_react7.default.createElement(
1420
1521
  "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
- )));
1522
+ { className: "dkb-mains" },
1523
+ infos.map((i, idx) => import_react7.default.createElement(
1524
+ "div",
1525
+ { key: idx, className: "dkb-main" },
1526
+ import_react7.default.createElement("span", { className: "dkb-main-label", style: { color: accent } }, i.currency),
1527
+ import_react7.default.createElement("span", { className: "dkb-main-value" }, fmt(i.totalBalance)),
1528
+ import_react7.default.createElement(
1529
+ "span",
1530
+ { className: "dkb-main-parts" },
1531
+ i.grantedBalance != null ? import_react7.default.createElement("span", { className: "dkb-main-part", style: { color: C_GRANTED } }, "\u8D60\u9001 " + fmt(i.grantedBalance)) : null,
1532
+ i.toppedUpBalance != null ? import_react7.default.createElement("span", { className: "dkb-main-part", style: { color: C_TOPUP } }, "\u5145\u503C " + fmt(i.toppedUpBalance)) : null
1533
+ )
1534
+ ))
1535
+ );
1427
1536
  } else if (b && b.status === "login-required" && b.consoleUrl) {
1428
- balBody = import_react6.default.createElement(
1537
+ balBody = import_react7.default.createElement(
1429
1538
  "div",
1430
- { className: "dkb-bal" },
1431
- 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")
1539
+ { className: "dkb-main" },
1540
+ import_react7.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
1541
  );
1433
1542
  } else {
1434
- balBody = import_react6.default.createElement("div", { className: "dkb-note" }, b && b.message || "\u672A\u77E5\u72B6\u6001");
1543
+ balBody = b && b.message ? import_react7.default.createElement("div", { className: "dkb-note" }, b.message) : import_react7.default.createElement("div", { className: "dkb-note" }, "\u8BE5 Provider \u6CA1\u6709\u5DF2\u77E5\u7684\u4F59\u989D\u67E5\u8BE2\u63A5\u53E3");
1435
1544
  }
1436
- if (cells.length > 0) balBody = import_react6.default.createElement("div", { className: "dkb-rows" }, cells);
1437
- return import_react6.default.createElement(
1545
+ const sub = ["ID " + p.id, p.api, p.baseURL ? p.baseURL.replace(/^https?:\/\//, "") : null].filter(Boolean).join(" \xB7 ");
1546
+ return import_react7.default.createElement(
1438
1547
  "div",
1439
1548
  { key: p.id, className: "dkb-row", "data-dock-provider": p.id },
1440
- import_react6.default.createElement(
1549
+ import_react7.default.createElement(
1441
1550
  "div",
1442
1551
  { className: "dkb-row-head" },
1443
- import_react6.default.createElement("span", { className: "dkb-dot", style: { background: accent } }),
1444
- import_react6.default.createElement("span", { className: "dkb-name", style: { color: accent } }, p.displayName),
1445
- 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])
1552
+ import_react7.default.createElement("span", { className: "dkb-dot", style: { background: accent } }),
1553
+ import_react7.default.createElement("span", { className: "dkb-name", style: { color: accent } }, p.displayName),
1554
+ def === p.id ? import_react7.default.createElement("span", { className: "dkb-default" }, "\u9ED8\u8BA4") : null,
1555
+ import_react7.default.createElement("span", { className: "dkb-badge" + (badge[1] ? " " + badge[1] : ""), style: badge[1] === "err" ? { color: C_ERR, borderColor: C_ERR } : null }, badge[0]),
1556
+ // 模型数折叠提示(点开展开 chips)
1557
+ p.models && p.models.length > 0 ? import_react7.default.createElement("button", {
1558
+ type: "button",
1559
+ className: "dkb-models-toggle",
1560
+ title: p.models.join(", "),
1561
+ onClick: (e) => {
1562
+ const row = e.currentTarget.closest(".dkb-row");
1563
+ if (row) row.classList.toggle("dkb-models-open");
1564
+ }
1565
+ }, p.models.length + " \u4E2A\u6A21\u578B \u25BE") : null
1447
1566
  ),
1448
- sub ? import_react6.default.createElement("div", { className: "dkb-sub" }, sub) : null,
1449
- p.apiKeyEnv ? import_react6.default.createElement("div", { className: "dkb-sub" }, "\u5BC6\u94A5: " + p.apiKeyEnv + (p.credentialConfigured ? " \u2713" : " \u2717")) : null,
1450
- p.models && p.models.length > 0 ? import_react6.default.createElement(
1567
+ sub ? import_react7.default.createElement("div", { className: "dkb-sub" }, sub) : null,
1568
+ p.apiKeyEnv ? import_react7.default.createElement("div", { className: "dkb-sub" }, "\u5BC6\u94A5: " + p.apiKeyEnv + (p.credentialConfigured ? " \u2713" : " \u2717")) : null,
1569
+ p.models && p.models.length > 0 ? import_react7.default.createElement(
1451
1570
  "div",
1452
1571
  { className: "dkb-chips" },
1453
- p.models.slice(0, 8).map((m) => import_react6.default.createElement("span", { key: m, className: "dkb-chip", style: { border: "1px solid " + accent, color: accent, background: accent + "1a" } }, m)),
1454
- p.models.length > 8 ? import_react6.default.createElement("span", { key: "more", className: "dkb-chip" }, "+" + (p.models.length - 8)) : null
1572
+ p.models.slice(0, 8).map((m) => import_react7.default.createElement("span", { key: m, className: "dkb-chip", style: { border: "1px solid " + accent, color: accent, background: accent + "1a" } }, m)),
1573
+ p.models.length > 8 ? import_react7.default.createElement("span", { key: "more", className: "dkb-chip" }, "+" + (p.models.length - 8)) : null
1455
1574
  ) : null,
1456
1575
  balBody
1457
1576
  );
@@ -1459,20 +1578,20 @@ function BalanceView(props) {
1459
1578
  ));
1460
1579
  }
1461
1580
  const now = new Date(data && data.generatedAt ? data.generatedAt : Date.now());
1462
- return import_react6.default.createElement(
1581
+ return import_react7.default.createElement(
1463
1582
  "div",
1464
1583
  { className: "dkb-rows" },
1465
- import_react6.default.createElement(
1584
+ import_react7.default.createElement(
1466
1585
  "div",
1467
1586
  { 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"
1587
+ 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
1588
  ),
1470
1589
  body,
1471
- import_react6.default.createElement(
1590
+ import_react7.default.createElement(
1472
1591
  "div",
1473
1592
  { className: "dkb-foot" },
1474
- import_react6.default.createElement("span", null, snap.loading ? "\u5237\u65B0\u4E2D\u2026" : "\u66F4\u65B0\u4E8E " + now.toLocaleTimeString()),
1475
- import_react6.default.createElement("button", { type: "button", className: "dkb-refresh", onClick: load }, "\u5237\u65B0")
1593
+ import_react7.default.createElement("span", null, snap.loading ? "\u5237\u65B0\u4E2D\u2026" : "\u66F4\u65B0\u4E8E " + now.toLocaleTimeString()),
1594
+ import_react7.default.createElement("button", { type: "button", className: "dkb-refresh", onClick: load }, "\u5237\u65B0")
1476
1595
  )
1477
1596
  );
1478
1597
  }
@@ -1480,14 +1599,14 @@ function BalanceStat(props) {
1480
1599
  const snap = useBalance(props && props.ctx);
1481
1600
  const data = snap.data;
1482
1601
  const providers = data && Array.isArray(data.providers) ? data.providers : [];
1483
- if (snap.error) return import_react6.default.createElement("span", { className: "dockm-err" }, "\u4F59\u989D\u67E5\u8BE2\u5931\u8D25\uFF08\u70B9\u51FB\u8FDB\u5165\u67E5\u770B\u8BE6\u60C5\uFF09");
1484
- if (!data) return import_react6.default.createElement("span", null, snap.loading ? "\u6B63\u5728\u62C9\u53D6\u4F59\u989D\u2026" : "\u7B49\u5F85\u62C9\u53D6\u4F59\u989D");
1602
+ if (snap.error) return import_react7.default.createElement("span", { className: "dockm-err" }, "\u4F59\u989D\u67E5\u8BE2\u5931\u8D25\uFF08\u70B9\u51FB\u8FDB\u5165\u67E5\u770B\u8BE6\u60C5\uFF09");
1603
+ if (!data) return import_react7.default.createElement("span", null, snap.loading ? "\u6B63\u5728\u62C9\u53D6\u4F59\u989D\u2026" : "\u7B49\u5F85\u62C9\u53D6\u4F59\u989D");
1485
1604
  const ok = providers.filter((p) => p.balance && p.balance.status === "ok").length;
1486
- return import_react6.default.createElement("span", null, providers.length + " \u4E2A Provider \xB7 " + ok + " \u4E2A\u53EF\u67E5\u4F59\u989D");
1605
+ return import_react7.default.createElement("span", null, providers.length + " \u4E2A Provider \xB7 " + ok + " \u4E2A\u53EF\u67E5\u4F59\u989D");
1487
1606
  }
1488
1607
  function useCurrentProvider(ctx, sessionId) {
1489
- const [cur, setCur] = import_react6.default.useState(null);
1490
- import_react6.default.useEffect(() => {
1608
+ const [cur, setCur] = import_react7.default.useState(null);
1609
+ import_react7.default.useEffect(() => {
1491
1610
  let alive = true, off = null;
1492
1611
  try {
1493
1612
  const models = ctx && ctx.get ? ctx.get("modelDirectories") : void 0;
@@ -1549,7 +1668,7 @@ function BalanceChip(props) {
1549
1668
  const text = snap.error ? "\u4F59\u989D\xB7\u5931\u8D25" : !data ? snap.loading ? "\u4F59\u989D \u2026" : "\u4F59\u989D \u2014" : cur ? chipBalanceText(cur) : "\u4F59\u989D \u2014";
1550
1669
  const selModel = sel && (sel.model || sel.selected && sel.selected.model) || null;
1551
1670
  const title = cur ? (cur.displayName || cur.id) + (selModel ? " \xB7 \u5F53\u524D\u6A21\u578B " + selModel : "") + " \xB7 \u70B9\u51FB\u5728\u529F\u80FD\u575E\u67E5\u770B\u4F59\u989D\u8BE6\u60C5" : "\u70B9\u51FB\u6253\u5F00\u529F\u80FD\u575E \xB7 \u6A21\u578B\u4F59\u989D";
1552
- return import_react6.default.createElement(
1671
+ return import_react7.default.createElement(
1553
1672
  "button",
1554
1673
  {
1555
1674
  type: "button",
@@ -1558,8 +1677,8 @@ function BalanceChip(props) {
1558
1677
  "aria-label": "\u6A21\u578B\u4F59\u989D",
1559
1678
  onClick: () => openPanel("balance", def ? { provider: def } : null)
1560
1679
  },
1561
- import_react6.default.createElement("span", { className: "dockchip-dot", style: { background: accent } }),
1562
- import_react6.default.createElement("span", null, text)
1680
+ import_react7.default.createElement("span", { className: "dockchip-dot", style: { background: accent } }),
1681
+ import_react7.default.createElement("span", null, text)
1563
1682
  );
1564
1683
  }
1565
1684
  var feature5 = {
@@ -1571,8 +1690,9 @@ var feature5 = {
1571
1690
  css: [
1572
1691
  ".dkb-note{color:var(--dsw-alias-label-secondary);font-size:12px;}",
1573
1692
  ".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;}",
1693
+ ".dkb-rows{display:flex;flex-direction:column;gap:10px;}",
1694
+ // Provider 卡片:行距收窄、留白分层
1695
+ ".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
1696
  ".dkb-row-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
1577
1697
  ".dkb-dot{width:8px;height:8px;border-radius:50%;flex:none;}",
1578
1698
  ".dkb-name{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary);}",
@@ -1581,13 +1701,28 @@ var feature5 = {
1581
1701
  ".dkb-badge.ok{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
1582
1702
  ".dkb-badge.warn{color:var(--dsw-alias-state-warning-primary);border-color:currentColor;}",
1583
1703
  ".dkb-badge.err{color:var(--dsw-alias-state-error-primary);border-color:currentColor;}",
1704
+ // 模型数折叠开关(点行头右侧"N 个模型 ▾"展开/收起 chips)
1705
+ ".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;}",
1706
+ ".dkb-models-toggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
1707
+ ".dkb-row:not(.dkb-models-open) .dkb-chips{display:none;}",
1708
+ '.dkb-row.dkb-models-open .dkb-models-toggle::after{content:"";}',
1709
+ // 连接信息弱化单行(省略 URL 协议头、超出省略号)
1584
1710
  ".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;}",
1711
+ ".dkb-chips{display:flex;flex-wrap:wrap;gap:4px;padding:2px 0 4px;}",
1586
1712
  ".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);}",
1713
+ // 余额主数字卡(大号数字 + 小字辅助信息;多币种横排多卡)
1714
+ ".dkb-mains{display:flex;gap:12px;flex-wrap:wrap;}",
1715
+ ".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;}",
1716
+ ".dkb-main-label{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
1717
+ ".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;}",
1718
+ ".dkb-main-parts{display:flex;gap:10px;flex-wrap:wrap;}",
1719
+ ".dkb-main-part{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
1720
+ // 配额维度条(周/小时额度:进度条 + 剩余/总量)
1721
+ ".dkb-dim{display:flex;align-items:center;gap:10px;font-size:11px;color:var(--dsw-alias-label-secondary);}",
1722
+ ".dkb-dim-label{flex:none;min-width:44px;color:var(--dsw-alias-label-tertiary);}",
1723
+ ".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;}",
1724
+ ".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));}",
1725
+ ".dkb-dim-text{flex:none;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;}",
1591
1726
  ".dkb-link{font-size:12px;text-decoration:none;}",
1592
1727
  ".dkb-link:hover{text-decoration:underline;}",
1593
1728
  ".dkb-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;color:var(--dsw-alias-label-tertiary);font-size:12px;}",
@@ -1602,15 +1737,1678 @@ var feature5 = {
1602
1737
  Chip: BalanceChip
1603
1738
  };
1604
1739
 
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" }
1740
+ // features/animation/view.jsx
1741
+ var import_react8 = require("react");
1742
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1743
+ function rpcCall2(method, args) {
1744
+ return fetch("/dsh-dock/animation/" + method, {
1745
+ method: "POST",
1746
+ headers: { "content-type": "application/json" },
1747
+ body: JSON.stringify(args === void 0 ? {} : args)
1748
+ }).then(async (res) => {
1749
+ const data = await res.json().catch(() => ({}));
1750
+ if (res.ok && data && data.ok === true) return data.data;
1751
+ if (res.status === 405 || res.status === 404) {
1752
+ 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");
1753
+ }
1754
+ if (data && data.ok === false) throw new Error(data.error && data.error.message || "HTTP " + res.status);
1755
+ throw new Error("HTTP " + res.status + (data && data.error && data.error.message ? ": " + data.error.message : ""));
1756
+ });
1757
+ }
1758
+ var EFFECT_MODES = [
1759
+ { 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" },
1760
+ { id: "breathe", name: "\u547C\u5438\u5149\u70B9", desc: "\u9192\u76EE\u547C\u5438\u5149\u70B9\u5E26\u6269\u6563\u5149\u6655\uFF1A\u989C\u8272\u968F\u4EFB\u52A1\u9636\u6BB5\uFF08\u601D\u8003\u84DD/\u8F93\u51FA\u7EFF/\u4EE3\u7801\u6A59/\u67E5\u8D44\u6599\u9752\uFF09\uFF0C\u547C\u5438\u968F\u541E\u5410\u52A0\u5FEB" },
1761
+ { id: "ring", name: "\u8F68\u9053\u5149\u73AF", desc: "\u7EC6\u73AF\u7ED5\u5706\u70B9\u65CB\u8F6C\uFF0C\u8F6C\u901F\u968F\u4EFB\u52A1\u901F\u5EA6" },
1762
+ { 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" },
1763
+ { id: "robot", name: "\u684C\u9762\u4F19\u4F34", desc: "\u771F\u4EBA\u5316\u53CC\u5DE5\u4F4D\uFF1A\u67E5\u8D44\u6599\u770B\u5DE6\u5C4F\u3001\u5199\u5165/\u6539\u4EE3\u7801\u79FB\u5230\u53F3\u5C4F\uFF1B\u5EA7\u6905\u548C\u8F6C\u5934\u968F\u5B9E\u65F6\u4EFB\u52A1\u8282\u594F\u52A0\u901F" },
1764
+ { 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" },
1765
+ { 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" },
1766
+ { 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
1767
  ];
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"
1768
+ var PHASE_LABELS = { think: "\u601D\u8003\u4E2D", write: "\u8F93\u51FA\u4E2D", code: "\u7F16\u5199\u4EE3\u7801", search: "\u67E5\u8D44\u6599" };
1769
+ function phaseLabel(p) {
1770
+ return PHASE_LABELS[p] || "\u5DE5\u4F5C\u4E2D";
1771
+ }
1772
+ var PHASE_COLORS = { think: "#60a5fa", write: "#34d399", code: "#fbbf24", search: "#2dd4bf" };
1773
+ function phaseColor(p) {
1774
+ return PHASE_COLORS[p] || "#4d9fff";
1775
+ }
1776
+ var END_LABELS = {
1777
+ completed: { label: "\u5B8C\u6210", cls: "ok" },
1778
+ error: { label: "\u51FA\u9519", cls: "err" },
1779
+ aborted: { label: "\u5DF2\u4E2D\u6B62", cls: "warn" },
1780
+ blocked: { label: "\u53D7\u963B", cls: "warn" },
1781
+ "max-tokens": { label: "\u8FBE\u8F93\u51FA\u4E0A\u9650", cls: "warn" },
1782
+ interrupted: { label: "\u4E2D\u65AD", cls: "warn" }
1613
1783
  };
1784
+ function endInfo(reason) {
1785
+ return END_LABELS[reason] || END_LABELS.completed;
1786
+ }
1787
+ function isSuccessReason(reason) {
1788
+ return !reason || reason === "completed";
1789
+ }
1790
+ function fmtNum2(n) {
1791
+ return (Number(n) || 0).toLocaleString("en-US");
1792
+ }
1793
+ function fmtCompact2(n) {
1794
+ n = Number(n) || 0;
1795
+ if (n >= 1e6) return (n / 1e6).toFixed(2) + "M";
1796
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + "K";
1797
+ return String(Math.round(n));
1798
+ }
1799
+ function fmtDur(ms) {
1800
+ const s = Math.max(0, Math.round((ms || 0) / 1e3));
1801
+ const h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60), sec = s % 60;
1802
+ if (h > 0) return h + "\u5C0F\u65F6" + m + "\u5206" + sec + "\u79D2";
1803
+ if (m > 0) return m + "\u5206" + sec + "\u79D2";
1804
+ return sec + "\u79D2";
1805
+ }
1806
+ function fmtClock(ms) {
1807
+ const s = Math.max(0, Math.floor((ms || 0) / 1e3));
1808
+ const h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60), sec = s % 60;
1809
+ const p = (x) => String(x).padStart(2, "0");
1810
+ return h > 0 ? h + ":" + p(m) + ":" + p(sec) : p(m) + ":" + p(sec);
1811
+ }
1812
+ function fmtTime2(ts) {
1813
+ if (!ts) return "";
1814
+ const d = new Date(ts);
1815
+ const p = (x) => String(x).padStart(2, "0");
1816
+ return p(d.getHours()) + ":" + p(d.getMinutes()) + ":" + p(d.getSeconds());
1817
+ }
1818
+ function truncate(str, max) {
1819
+ if (!str) return "";
1820
+ return String(str).length > max ? String(str).slice(0, max) + "\u2026" : str;
1821
+ }
1822
+ var animationStore = {
1823
+ snap: { status: null, loading: false, error: null },
1824
+ listeners: /* @__PURE__ */ new Set(),
1825
+ subscribe(fn) {
1826
+ this.listeners.add(fn);
1827
+ return () => {
1828
+ this.listeners.delete(fn);
1829
+ };
1830
+ },
1831
+ emit() {
1832
+ for (const fn of this.listeners) fn();
1833
+ },
1834
+ applyConfig(cfg) {
1835
+ if (this.snap.status) {
1836
+ this.snap = Object.assign({}, this.snap, { status: Object.assign({}, this.snap.status, { config: cfg }) });
1837
+ this.emit();
1838
+ }
1839
+ },
1840
+ refresh() {
1841
+ if (this.snap.loading) return Promise.resolve();
1842
+ this.snap = Object.assign({}, this.snap, { loading: true });
1843
+ this.emit();
1844
+ return rpcCall2("status").then((data) => {
1845
+ this.snap = { status: data, loading: false, error: null };
1846
+ this.emit();
1847
+ }).catch((e) => {
1848
+ this.snap = Object.assign({}, this.snap, { loading: false, error: e && e.message || String(e) });
1849
+ this.emit();
1850
+ });
1851
+ }
1852
+ };
1853
+ function useAnimation() {
1854
+ const [snap, setSnap] = (0, import_react8.useState)(animationStore.snap);
1855
+ (0, import_react8.useEffect)(() => animationStore.subscribe(() => setSnap(animationStore.snap)), []);
1856
+ return snap;
1857
+ }
1858
+ function useTicker(ctx, active) {
1859
+ const [, bump] = (0, import_react8.useState)(0);
1860
+ (0, import_react8.useEffect)(() => {
1861
+ if (!active) return;
1862
+ if (ctx && typeof ctx.interval === "function") return ctx.interval(bump, 1e3);
1863
+ const t = setInterval(bump, 1e3);
1864
+ return () => clearInterval(t);
1865
+ }, [active]);
1866
+ }
1867
+ function Box3(props) {
1868
+ const w = props.w, h = props.h, d = props.d;
1869
+ const faces = [
1870
+ [w, h, "translate(-50%,-50%) translateZ(" + d / 2 + "px)"],
1871
+ [w, h, "translate(-50%,-50%) rotateY(180deg) translateZ(" + d / 2 + "px)"],
1872
+ [d, h, "translate(-50%,-50%) rotateY(90deg) translateZ(" + w / 2 + "px)"],
1873
+ [d, h, "translate(-50%,-50%) rotateY(-90deg) translateZ(" + w / 2 + "px)"],
1874
+ [w, d, "translate(-50%,-50%) rotateX(90deg) translateZ(" + h / 2 + "px)"],
1875
+ [w, d, "translate(-50%,-50%) rotateX(-90deg) translateZ(" + h / 2 + "px)"]
1876
+ ];
1877
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1878
+ "span",
1879
+ {
1880
+ className: "dk3-box " + (props.cls || ""),
1881
+ style: Object.assign(
1882
+ { width: w, height: h, left: props.x - w / 2, top: props.y - h / 2 },
1883
+ props.z ? { transform: "translateZ(" + props.z + "px)" } : null,
1884
+ props.style
1885
+ ),
1886
+ children: [
1887
+ 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)),
1888
+ props.children
1889
+ ]
1890
+ }
1891
+ );
1892
+ }
1893
+ function Monitor3(props) {
1894
+ const w = props.w, h = props.h;
1895
+ const searchScreen = props.mode === "search";
1896
+ const lines = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
1897
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1898
+ "span",
1899
+ {
1900
+ className: "dk3-mon3 " + (props.cls || ""),
1901
+ 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)" },
1902
+ children: [
1903
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w, h, d: 5, cls: "dk3-frame", x: w / 2, y: h / 2 }),
1904
+ /* @__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: searchScreen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-search-ui", children: [
1905
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-search-box", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("b", {}) }),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-search-results", children: lines.slice(0, 6).map((n, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}, i)) })
1907
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-code", children: [
1908
+ lines.map((n, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}, i)),
1909
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-cur" })
1910
+ ] }) })
1911
+ ]
1912
+ }
1913
+ );
1914
+ }
1915
+ function RobotScene(props) {
1916
+ const phase = props && props.phase ? props.phase : "code";
1917
+ const tasks = Array.isArray(props && props.tasks) ? props.tasks : null;
1918
+ const n = tasks ? Math.max(1, Math.min(3, tasks.length)) : 1;
1919
+ const station = phase === "search" ? "left" : phase === "write" || phase === "code" ? "right" : "center";
1920
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-bot-scene", "data-phase": phase, "data-station": station, "data-tasks": tasks ? String(n) : void 0, "aria-hidden": "true", children: [
1921
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-world", children: [
1922
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 134, h: 7, d: 38, cls: "dk3-desk", x: 145, y: 76 }),
1923
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 5, h: 24, d: 30, cls: "dk3-metal dk3-leg", x: 84, y: 89 }),
1924
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 5, h: 24, d: 30, cls: "dk3-metal dk3-leg", x: 206, y: 89 }),
1925
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Monitor3, { w: 34, h: 24, x: 140, y: 59, ry: 20, cls: "left", mode: "search" }),
1926
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Monitor3, { w: 42, h: 30, x: 180, y: 57, ry: -16, cls: "right" }),
1927
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Monitor3, { w: 28, h: 18, x: 160, y: 31, ry: 0, cls: "top" }),
1928
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 16, h: 2.5, d: 9, cls: "dk3-metal dk3-kb3", x: 130, y: 71, z: 14 }),
1929
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 2.5, d: 6, cls: "dk3-metal dk3-mouse3", x: 141, y: 71, z: 14 }),
1930
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 5, d: 4, cls: "dk3-mug", x: 154, y: 69, z: 14 }),
1931
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 16, h: 2.5, d: 9, cls: "dk3-metal dk3-kb3", x: 170, y: 71, z: 14 }),
1932
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 2.5, d: 6, cls: "dk3-metal dk3-mouse3", x: 181, y: 71, z: 14 }),
1933
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-person", children: [
1934
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 20, d: 20, cls: "dk3-chairback", x: 2, y: 47 }),
1935
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 18, h: 4, d: 20, cls: "dk3-chairseat", x: 12, y: 59 }),
1936
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3, h: 9, d: 3, cls: "dk3-metal", x: 12, y: 66 }),
1937
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 13, h: 2, d: 13, cls: "dk3-metal", x: 12, y: 71 }),
1938
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3, h: 3, d: 3, cls: "dk3-wheel", x: 6, y: 74 }),
1939
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3, h: 3, d: 3, cls: "dk3-wheel", x: 18, y: 74 }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 12, h: 5, d: 9, cls: "dk3-pants", x: 20, y: 54 }),
1941
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 10, d: 4, cls: "dk3-pants", x: 26, y: 62 }),
1942
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 6, h: 3, d: 5, cls: "dk3-shoe", x: 28, y: 70 }),
1943
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-upper3", children: [
1944
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 18, h: 5, d: 12, cls: "dk3-hood dk3-shoulders3", x: 13, y: 30 }),
1945
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 15, h: 14, d: 11, cls: "dk3-hood dk3-torso dk3-chest3", x: 12, y: 38 }),
1946
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 12, h: 7, d: 10, cls: "dk3-hood dk3-torso dk3-waist3", x: 12, y: 47 }),
1947
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 5, h: 8, d: 9, cls: "dk3-hood dk3-hoodbump", x: 5, y: 32 }),
1948
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 5, h: 7, d: 5, cls: "dk3-skin dk3-neck3", x: 14, y: 24 }),
1949
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 8, h: 3, d: 8, cls: "dk3-collar3", x: 14, y: 28 }),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-head3", children: [
1951
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box3, { w: 12, h: 11, d: 11, cls: "dk3-skin dk3-cranium", x: 8, y: 8, children: [
1952
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-brows", style: { width: 9, height: 4, transform: "translate(-50%,-50%) rotateY(90deg) translateZ(5.8px)" }, children: [
1953
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1954
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1955
+ ] }),
1956
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-eyes", style: { width: 9, height: 6, transform: "translate(-50%,-50%) rotateY(90deg) translateZ(5.7px)" }, children: [
1957
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1958
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1959
+ ] }),
1960
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-nose", style: { transform: "translate(-50%,-50%) rotateY(90deg) translateZ(6.1px)" } })
1961
+ ] }),
1962
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 9, h: 7, d: 9, cls: "dk3-skin dk3-jaw3", x: 8.5, y: 14, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-mouth", style: { transform: "translate(-50%,-50%) rotateY(90deg) translateZ(4.7px)" } }) }),
1963
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 12, h: 5, d: 12, cls: "dk3-hair dk3-hair-crown", x: 8, y: 3.5 }),
1964
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 8, d: 11, cls: "dk3-hair dk3-hair-back", x: 3, y: 7.5 }),
1965
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-fringe3", children: [
1966
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1967
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1968
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1969
+ ] }),
1970
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dk3-ear" })
1971
+ ] }),
1972
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-arm3 dk3-near", children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 11, d: 4, cls: "dk3-hood dk3-uarm", x: 2, y: 6 }),
1974
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-elbow", children: [
1975
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 10, h: 3.5, d: 3.5, cls: "dk3-hood dk3-farm", x: 5.5, y: 2 }),
1976
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-wrist3", children: [
1977
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3.5, h: 3, d: 3, cls: "dk3-skin dk3-hand", x: 2, y: 2 }),
1978
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-fingers3", children: [
1979
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1980
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1981
+ ] })
1982
+ ] })
1983
+ ] })
1984
+ ] }),
1985
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-arm3 dk3-far", children: [
1986
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 4, h: 11, d: 4, cls: "dk3-hood dk3-uarm", x: 2, y: 6 }),
1987
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-elbow", children: [
1988
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 10, h: 3.5, d: 3.5, cls: "dk3-hood dk3-farm", x: 5.5, y: 2 }),
1989
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dk3-wrist3", children: [
1990
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box3, { w: 3.5, h: 3, d: 3, cls: "dk3-skin dk3-hand", x: 2, y: 2 }),
1991
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dk3-fingers3", children: [
1992
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
1993
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
1994
+ ] })
1995
+ ] })
1996
+ ] })
1997
+ ] })
1998
+ ] })
1999
+ ] })
2000
+ ] }),
2001
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-bubble", children: [
2002
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2003
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2004
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2005
+ ] })
2006
+ ] });
2007
+ }
2008
+ var SOUND_LIBRARY = {
2009
+ 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]] } },
2010
+ ding: { name: "\u53EE", notes: { done: [[987.77, 0, 0.35]], err: [[246.94, 0, 0.4]] } },
2011
+ 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]] } },
2012
+ 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]] } },
2013
+ 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]] } },
2014
+ 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]] } }
2015
+ };
2016
+ var soundCtx = null;
2017
+ function playTone(seq) {
2018
+ try {
2019
+ if (typeof window === "undefined" || !window.AudioContext && !window.webkitAudioContext) return;
2020
+ const AC = window.AudioContext || window.webkitAudioContext;
2021
+ if (!soundCtx) soundCtx = new AC();
2022
+ if (soundCtx.state === "suspended") {
2023
+ soundCtx.resume().catch(() => {
2024
+ });
2025
+ }
2026
+ const t0 = soundCtx.currentTime;
2027
+ for (const [f, at, dur, wave] of seq) {
2028
+ const osc = soundCtx.createOscillator();
2029
+ const gain = soundCtx.createGain();
2030
+ osc.type = wave || "sine";
2031
+ osc.frequency.value = f;
2032
+ gain.gain.setValueAtTime(0, t0 + at);
2033
+ gain.gain.linearRampToValueAtTime(0.18, t0 + at + 0.015);
2034
+ gain.gain.exponentialRampToValueAtTime(1e-4, t0 + at + dur);
2035
+ osc.connect(gain).connect(soundCtx.destination);
2036
+ osc.start(t0 + at);
2037
+ osc.stop(t0 + at + dur + 0.05);
2038
+ }
2039
+ } catch {
2040
+ }
2041
+ }
2042
+ function playDoneSound(success, effect) {
2043
+ const lib = SOUND_LIBRARY[effect] || SOUND_LIBRARY.chime;
2044
+ playTone(success ? lib.notes.done : lib.notes.err);
2045
+ }
2046
+ function previewSound(effect) {
2047
+ const lib = SOUND_LIBRARY[effect] || SOUND_LIBRARY.chime;
2048
+ playTone(lib.notes.done);
2049
+ const delayed = lib.notes.err.map(([f, at, dur, wave]) => [f, at + 0.55, dur, wave]);
2050
+ playTone(delayed);
2051
+ }
2052
+ function Toast(props) {
2053
+ const t = props.t;
2054
+ const [closing, setClosing] = (0, import_react8.useState)(false);
2055
+ const close = (0, import_react8.useCallback)(() => {
2056
+ if (!closing) setClosing(true);
2057
+ }, [closing]);
2058
+ (0, import_react8.useEffect)(() => {
2059
+ if (!t.stayMs) return;
2060
+ const timer = setTimeout(close, t.stayMs);
2061
+ return () => clearTimeout(timer);
2062
+ }, []);
2063
+ (0, import_react8.useEffect)(() => {
2064
+ if (!closing) return;
2065
+ const timer = setTimeout(() => props.onClose(t.id), 240);
2066
+ return () => clearTimeout(timer);
2067
+ }, [closing]);
2068
+ 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)";
2069
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-toast" + (closing ? " out" : ""), children: [
2070
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-toast-head", children: [
2071
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-toast-mark", style: { background: markColor } }),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-toast-title", title: t.title, children: t.title }),
2073
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "dkan-toast-close", "aria-label": "\u5173\u95ED", onClick: close, children: "\u2715" })
2074
+ ] }),
2075
+ t.body ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-toast-body", children: t.body }) : null
2076
+ ] });
2077
+ }
2078
+ function makeBits(n, fn) {
2079
+ const arr = [];
2080
+ for (let i = 0; i < n; i++) arr.push(fn(i));
2081
+ return arr;
2082
+ }
2083
+ function BurstLayer(props) {
2084
+ const bursts = props.bursts || [];
2085
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-fxwrap", "aria-hidden": "true", children: bursts.map((b) => {
2086
+ if (b.type === "plane") {
2087
+ 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);
2088
+ }
2089
+ if (b.type === "spark") {
2090
+ 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);
2091
+ }
2092
+ if (b.type === "streak") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-streak" }, b.id);
2093
+ if (b.type === "flash") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-flash" }, b.id);
2094
+ if (b.type === "surge") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-fx dkan-fx-surge" }, b.id);
2095
+ if (b.type === "confetti") {
2096
+ 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);
2097
+ }
2098
+ return null;
2099
+ }) });
2100
+ }
2101
+ var MATRIX_CHARS = "01</>;{}=+*#";
2102
+ function AmbientLayer(props) {
2103
+ const mode = props.mode;
2104
+ const speed = props.speed;
2105
+ const matrix = (0, import_react8.useMemo)(() => makeBits(34, () => ({
2106
+ l: Math.random() * 100,
2107
+ d: 4 + Math.random() * 6,
2108
+ delay: -Math.random() * 8,
2109
+ o: 0.28 + Math.random() * 0.34,
2110
+ s: 11 + Math.round(Math.random() * 4),
2111
+ 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)]
2112
+ })), []);
2113
+ const stars = (0, import_react8.useMemo)(() => makeBits(80, () => ({
2114
+ l: Math.random() * 100,
2115
+ t: Math.random() * 100,
2116
+ sz: 1.5 + Math.random() * 2,
2117
+ d: 2 + Math.random() * 4,
2118
+ delay: -Math.random() * 6,
2119
+ dx: (Math.random() - 0.5) * 40,
2120
+ dy: (Math.random() - 0.5) * 24
2121
+ })), []);
2122
+ if (mode === "matrix") {
2123
+ 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)) });
2124
+ }
2125
+ if (mode === "stars") {
2126
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-amb dkan-stars", style: { "--dkan-speed": speed }, "aria-hidden": "true", children: [
2127
+ 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)),
2128
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-moon" }),
2129
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dkan-meteor", style: { top: "12%", left: "72%", animationDelay: "0s" } }),
2130
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dkan-meteor", style: { top: "28%", left: "88%", animationDelay: "2.8s" } }),
2131
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dkan-meteor", style: { top: "6%", left: "42%", animationDelay: "5.6s" } })
2132
+ ] });
2133
+ }
2134
+ if (mode === "aurora") {
2135
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-amb dkan-aurora", style: { "--dkan-speed": speed }, "aria-hidden": "true", children: [
2136
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2137
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2138
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2139
+ ] });
2140
+ }
2141
+ return null;
2142
+ }
2143
+ function AnimationOverlay(props) {
2144
+ const ctx = props && props.ctx;
2145
+ const snap = useAnimation();
2146
+ const [toasts, setToasts] = (0, import_react8.useState)([]);
2147
+ const [flourish, setFlourish] = (0, import_react8.useState)(null);
2148
+ const [bursts, setBursts] = (0, import_react8.useState)([]);
2149
+ const prevActiveRef = (0, import_react8.useRef)(null);
2150
+ const burstIdRef = (0, import_react8.useRef)(0);
2151
+ const pushBurst = (0, import_react8.useCallback)((type, x, y, bits) => {
2152
+ const id = ++burstIdRef.current;
2153
+ setBursts((prev) => prev.concat([{ id, type, x, y, bits }]).slice(-6));
2154
+ setTimeout(() => setBursts((prev) => prev.filter((b) => b.id !== id)), 2600);
2155
+ }, []);
2156
+ (0, import_react8.useEffect)(() => {
2157
+ if (typeof document === "undefined") return;
2158
+ const onClick = (e) => {
2159
+ const t = e.target;
2160
+ if (!t || !t.closest) return;
2161
+ const sendBtn = t.closest('button[aria-label="Send message"], button[aria-label*="\u53D1\u9001"]');
2162
+ const newSession = t.closest('button[aria-label*="New session"], button[aria-label*="\u65B0\u4F1A\u8BDD"], button[aria-label*="New Session"]');
2163
+ const workspace = t.closest('button[aria-label*="Choose workspace"], button[aria-label*="\u5DE5\u4F5C\u76EE\u5F55"], button[aria-label*="workspace"]');
2164
+ const sessionItem = t.closest('[role="treeitem"]');
2165
+ if (sendBtn) {
2166
+ pushBurst("plane", e.clientX, e.clientY);
2167
+ } else if (newSession) {
2168
+ pushBurst("spark", e.clientX, e.clientY, makeBits(10, () => ({
2169
+ dx: (Math.random() - 0.5) * 70,
2170
+ dy: (Math.random() - 0.5) * 70,
2171
+ c: ["#4d9fff", "#34d399", "#fbbf24", "#f472b6"][Math.floor(Math.random() * 4)]
2172
+ })));
2173
+ } else if (workspace) {
2174
+ pushBurst("flash");
2175
+ } else if (sessionItem) {
2176
+ pushBurst("streak");
2177
+ }
2178
+ };
2179
+ document.addEventListener("click", onClick, true);
2180
+ return () => document.removeEventListener("click", onClick, true);
2181
+ }, [pushBurst]);
2182
+ const taskCountRef = (0, import_react8.useRef)(0);
2183
+ (0, import_react8.useEffect)(() => {
2184
+ const st2 = snap.status;
2185
+ if (!st2 || !st2.active) return;
2186
+ const n = st2.active.length;
2187
+ if (n > taskCountRef.current) pushBurst("surge");
2188
+ taskCountRef.current = n;
2189
+ }, [snap.status, pushBurst]);
2190
+ (0, import_react8.useEffect)(() => {
2191
+ let stopped = false;
2192
+ let timer = null;
2193
+ const loop = async () => {
2194
+ await animationStore.refresh();
2195
+ if (stopped) return;
2196
+ const s = animationStore.snap;
2197
+ timer = setTimeout(loop, s.error ? 15e3 : s.status && s.status.active && s.status.active.length > 0 ? 850 : 6e3);
2198
+ };
2199
+ loop();
2200
+ const onVisible = () => {
2201
+ if (!stopped && typeof document !== "undefined" && document.visibilityState === "visible") animationStore.refresh();
2202
+ };
2203
+ document.addEventListener("visibilitychange", onVisible);
2204
+ return () => {
2205
+ stopped = true;
2206
+ if (timer) clearTimeout(timer);
2207
+ document.removeEventListener("visibilitychange", onVisible);
2208
+ };
2209
+ }, []);
2210
+ (0, import_react8.useEffect)(() => {
2211
+ const st2 = snap.status;
2212
+ if (!st2 || !st2.active) return;
2213
+ const prev = prevActiveRef.current;
2214
+ if (prev) {
2215
+ const currIds = new Set(st2.active.map((x) => x.sessionId));
2216
+ for (const task of prev) {
2217
+ if (currIds.has(task.sessionId)) continue;
2218
+ const record = (st2.recent || []).find((r) => r.sessionId === task.sessionId) || null;
2219
+ handleTaskEnd(task, record, st2.config || {});
2220
+ }
2221
+ }
2222
+ prevActiveRef.current = st2.active.slice();
2223
+ }, [snap.status]);
2224
+ const handleTaskEnd = (task, record, cfg2) => {
2225
+ const reason = record && record.endReason || "";
2226
+ const success = isSuccessReason(reason);
2227
+ const info = endInfo(reason);
2228
+ if (cfg2.animationEnabled) {
2229
+ setFlourish({ key: Date.now(), err: !success });
2230
+ if (success) {
2231
+ pushBurst("confetti", 0, 0, makeBits(18, (i) => ({
2232
+ l: 4 + i / 18 * 92 + Math.random() * 3,
2233
+ dx: (Math.random() - 0.5) * 60,
2234
+ r: Math.random() * 720 - 360,
2235
+ d: Math.random() * 0.35,
2236
+ c: ["#4d9fff", "#34d399", "#fbbf24", "#f472b6", "#a78bfa"][i % 5]
2237
+ })));
2238
+ }
2239
+ }
2240
+ if (!cfg2.notifyEnabled) return;
2241
+ const wanted = success ? cfg2.notifyOnComplete : cfg2.notifyOnError;
2242
+ if (!wanted) return;
2243
+ const models = record && record.models && record.models.length ? record.models.join(", ") : task.models && task.models.length ? task.models.join(", ") : "\u672A\u77E5\u6A21\u578B";
2244
+ const provider = record && record.provider || task.provider || "";
2245
+ const startTs = record && record.startTime || task.startTime;
2246
+ const endTs = record && record.endTime || Date.now();
2247
+ const lines = [
2248
+ "\u4EFB\u52A1\uFF1A" + (record && record.title || task.title || "(\u65E0\u6807\u9898)"),
2249
+ "\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""),
2250
+ "\u8017\u65F6\uFF1A" + fmtDur(record && record.duration || endTs - startTs) + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09",
2251
+ "\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" : ""),
2252
+ "Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens)
2253
+ ];
2254
+ if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate(record.lastText, 140));
2255
+ if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate(record.errorMessage, 120));
2256
+ const title = success ? "\u4EFB\u52A1\u5B8C\u6210" : "\u4EFB\u52A1" + info.label;
2257
+ const toast = {
2258
+ id: Date.now() + Math.random(),
2259
+ kind: success ? "success" : info.cls === "err" ? "error" : "warn",
2260
+ title,
2261
+ body: lines.join("\n"),
2262
+ stayMs: typeof cfg2.notifyStayMs === "number" ? cfg2.notifyStayMs : 8e3
2263
+ };
2264
+ setToasts((prev) => prev.concat([toast]).slice(-4));
2265
+ if (cfg2.soundNotify !== false) playDoneSound(success, cfg2.soundEffect);
2266
+ if (cfg2.systemNotify && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
2267
+ try {
2268
+ new Notification("dsh " + title, {
2269
+ body: (record && record.title || task.title || "(\u65E0\u6807\u9898)") + " \xB7 " + fmtDur(record && record.duration || endTs - startTs),
2270
+ tag: "dsh-dock-animation-" + task.sessionId
2271
+ });
2272
+ } catch {
2273
+ }
2274
+ }
2275
+ };
2276
+ const st = snap.status;
2277
+ const cfg = st && st.config;
2278
+ const active = st && st.active ? st.active : [];
2279
+ const animOn = !!(cfg && cfg.animationEnabled && active.length > 0);
2280
+ const mode = cfg && cfg.effectMode ? cfg.effectMode : "flow";
2281
+ const phase = active.length > 0 ? active.reduce((best, x) => !best || (x.phaseAt || 0) > (best.phaseAt || 0) ? x : best, null).phase : "think";
2282
+ useTicker(ctx, animOn);
2283
+ const now = Date.now();
2284
+ const elapsed = active.length > 0 ? fmtClock(now - Math.min(...active.map((x) => x.startTime || now))) : "";
2285
+ const [panelOpen, setPanelOpen2] = (0, import_react8.useState)(false);
2286
+ (0, import_react8.useEffect)(() => {
2287
+ setPanelOpen2(panelNav.open);
2288
+ return subscribePanel(() => setPanelOpen2(panelNav.open));
2289
+ }, []);
2290
+ const [speed, setSpeed] = (0, import_react8.useState)(1);
2291
+ const speedRef = (0, import_react8.useRef)({ ticks: -1, at: 0 });
2292
+ (0, import_react8.useEffect)(() => {
2293
+ if (!st || active.length === 0) {
2294
+ speedRef.current = { ticks: -1, at: 0 };
2295
+ setSpeed(1);
2296
+ return;
2297
+ }
2298
+ const ticks = active.reduce((a, x) => a + (x.motionTicks || 0), 0);
2299
+ const t = Date.now();
2300
+ const prev = speedRef.current;
2301
+ if (prev.ticks < 0 || t - prev.at < 300) {
2302
+ speedRef.current = { ticks, at: t };
2303
+ return;
2304
+ }
2305
+ const rate = Math.max(0, (ticks - prev.ticks) / ((t - prev.at) / 1e3));
2306
+ const phaseBoost = phase === "write" || phase === "code" ? 0.28 : phase === "search" ? 0.18 : 0;
2307
+ const next = Math.max(0.9, Math.min(4, Number((0.9 + rate / 14 + phaseBoost).toFixed(2))));
2308
+ setSpeed((current) => Math.abs(current - next) < 0.03 ? current : next);
2309
+ speedRef.current = { ticks, at: t };
2310
+ }, [snap.status]);
2311
+ const ambientOn = animOn && !panelOpen;
2312
+ const robotScaleFromConfig = Math.max(0.85, Math.min(2.2, Number(cfg && cfg.robotScale) || 1.35));
2313
+ const speedStyle = { "--dkan-speed": Number(speed).toFixed(2) };
2314
+ const saveRobotScale = (0, import_react8.useCallback)((robotScale) => {
2315
+ rpcCall2("config", { robotScale }).then((d) => animationStore.applyConfig(d && d.config)).catch(() => {
2316
+ });
2317
+ }, []);
2318
+ const [botPos, setBotPos] = (0, import_react8.useState)(null);
2319
+ const botPosRef = (0, import_react8.useRef)(null);
2320
+ const botDragRef = (0, import_react8.useRef)(null);
2321
+ const botResizeRef = (0, import_react8.useRef)(null);
2322
+ const [botScaleDraft, setBotScaleDraft] = (0, import_react8.useState)(null);
2323
+ const botClickBlockRef = (0, import_react8.useRef)(false);
2324
+ (0, import_react8.useEffect)(() => {
2325
+ try {
2326
+ if (typeof localStorage === "undefined") return;
2327
+ const raw = localStorage.getItem("dsh-dock/anim/robot-pos/v1");
2328
+ const p = raw ? JSON.parse(raw) : null;
2329
+ if (p && typeof p.x === "number" && typeof p.y === "number" && typeof window !== "undefined") {
2330
+ const card = document.querySelector(".dkan-botcard");
2331
+ const w = card ? card.offsetWidth : 200, h = card ? card.offsetHeight : 160;
2332
+ const x = Math.min(Math.max(8, p.x), Math.max(8, window.innerWidth - w - 8));
2333
+ const y = Math.min(Math.max(8, p.y), Math.max(8, window.innerHeight - h - 8));
2334
+ botPosRef.current = { x, y };
2335
+ setBotPos({ x, y });
2336
+ }
2337
+ } catch {
2338
+ }
2339
+ }, []);
2340
+ const onBotPointerDown = (e) => {
2341
+ if (e.button !== 0) return;
2342
+ const r = e.currentTarget.getBoundingClientRect();
2343
+ botDragRef.current = { sx: e.clientX, sy: e.clientY, ox: r.left, oy: r.top, moved: false };
2344
+ try {
2345
+ e.currentTarget.setPointerCapture(e.pointerId);
2346
+ } catch {
2347
+ }
2348
+ };
2349
+ const onBotPointerMove = (e) => {
2350
+ const d = botDragRef.current;
2351
+ if (!d || typeof window === "undefined") return;
2352
+ const dx = e.clientX - d.sx, dy = e.clientY - d.sy;
2353
+ if (!d.moved && Math.hypot(dx, dy) < 4) return;
2354
+ d.moved = true;
2355
+ const el = e.currentTarget;
2356
+ const w = el.offsetWidth || 200, h = el.offsetHeight || 160;
2357
+ const x = Math.min(Math.max(8, d.ox + dx), window.innerWidth - w - 8);
2358
+ const y = Math.min(Math.max(8, d.oy + dy), window.innerHeight - h - 8);
2359
+ botPosRef.current = { x, y };
2360
+ setBotPos({ x, y });
2361
+ };
2362
+ const onBotPointerUp = () => {
2363
+ const d = botDragRef.current;
2364
+ botDragRef.current = null;
2365
+ if (d && d.moved) {
2366
+ try {
2367
+ if (typeof localStorage !== "undefined") localStorage.setItem("dsh-dock/anim/robot-pos/v1", JSON.stringify(botPosRef.current));
2368
+ } catch {
2369
+ }
2370
+ botClickBlockRef.current = true;
2371
+ setTimeout(() => {
2372
+ botClickBlockRef.current = false;
2373
+ }, 0);
2374
+ }
2375
+ };
2376
+ const onBotResizePointerDown = (e) => {
2377
+ if (e.button !== 0) return;
2378
+ e.preventDefault();
2379
+ e.stopPropagation();
2380
+ botResizeRef.current = { sx: e.clientX, sy: e.clientY, scale: botScaleDraft == null ? robotScaleFromConfig : botScaleDraft };
2381
+ try {
2382
+ e.currentTarget.setPointerCapture(e.pointerId);
2383
+ } catch {
2384
+ }
2385
+ };
2386
+ const onBotResizePointerMove = (e) => {
2387
+ const d = botResizeRef.current;
2388
+ if (!d) return;
2389
+ e.preventDefault();
2390
+ e.stopPropagation();
2391
+ const delta = (e.clientX - d.sx + (e.clientY - d.sy)) / 2;
2392
+ const next = Math.max(0.85, Math.min(2.2, Math.round((d.scale + delta / 220) * 100) / 100));
2393
+ setBotScaleDraft(next);
2394
+ if (botPosRef.current && typeof window !== "undefined") {
2395
+ const w = 220 * next + 24, h = 132 * next + 46;
2396
+ const x = Math.min(Math.max(8, botPosRef.current.x), Math.max(8, window.innerWidth - w - 8));
2397
+ const y = Math.min(Math.max(8, botPosRef.current.y), Math.max(8, window.innerHeight - h - 8));
2398
+ botPosRef.current = { x, y };
2399
+ setBotPos({ x, y });
2400
+ }
2401
+ };
2402
+ const onBotResizePointerUp = (e) => {
2403
+ if (!botResizeRef.current) return;
2404
+ e.preventDefault();
2405
+ e.stopPropagation();
2406
+ const next = botScaleDraft == null ? robotScaleFromConfig : botScaleDraft;
2407
+ botResizeRef.current = null;
2408
+ saveRobotScale(next);
2409
+ try {
2410
+ if (botPosRef.current && typeof localStorage !== "undefined") localStorage.setItem("dsh-dock/anim/robot-pos/v1", JSON.stringify(botPosRef.current));
2411
+ } catch {
2412
+ }
2413
+ setBotScaleDraft(null);
2414
+ };
2415
+ const onBotClick = () => {
2416
+ if (botClickBlockRef.current) return;
2417
+ openPanel("animation");
2418
+ };
2419
+ const displayRobotScale = botScaleDraft == null ? robotScaleFromConfig : botScaleDraft;
2420
+ 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 });
2421
+ if (!st) return null;
2422
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2423
+ ambientOn && mode === "flow" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-line", style: speedStyle, "aria-hidden": "true" }) : null,
2424
+ ambientOn && (mode === "matrix" || mode === "stars" || mode === "aurora") ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AmbientLayer, { mode, speed: Number(speed).toFixed(2) }) : null,
2425
+ ambientOn && mode === "orbit" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-orbit", style: speedStyle, "aria-hidden": "true" }) : null,
2426
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BurstLayer, { bursts }),
2427
+ ambientOn && mode === "robot" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2428
+ "div",
2429
+ {
2430
+ className: "dkan-botcard",
2431
+ role: "button",
2432
+ tabIndex: 0,
2433
+ style: botCardStyle,
2434
+ 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",
2435
+ onPointerDown: onBotPointerDown,
2436
+ onPointerMove: onBotPointerMove,
2437
+ onPointerUp: onBotPointerUp,
2438
+ onPointerCancel: onBotPointerUp,
2439
+ onClick: onBotClick,
2440
+ onKeyDown: (e) => {
2441
+ if (e.target === e.currentTarget && (e.key === "Enter" || e.key === " ")) {
2442
+ e.preventDefault();
2443
+ onBotClick();
2444
+ }
2445
+ },
2446
+ children: [
2447
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RobotScene, { phase, tasks: active }),
2448
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-bot-cap", children: [
2449
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "n", children: active.length }),
2450
+ " \u4E2A\u4EFB\u52A1",
2451
+ elapsed ? " \xB7 " + elapsed : "",
2452
+ " \xB7 ",
2453
+ phaseLabel(phase)
2454
+ ] }),
2455
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2456
+ "button",
2457
+ {
2458
+ type: "button",
2459
+ className: "dkan-bot-resize",
2460
+ "aria-label": "\u8C03\u6574\u684C\u9762\u4F19\u4F34\u5927\u5C0F",
2461
+ title: "\u62D6\u52A8\u8C03\u6574\u684C\u9762\u4F19\u4F34\u5927\u5C0F",
2462
+ onPointerDown: onBotResizePointerDown,
2463
+ onPointerMove: onBotResizePointerMove,
2464
+ onPointerUp: onBotResizePointerUp,
2465
+ onPointerCancel: onBotResizePointerUp,
2466
+ onClick: (e) => e.stopPropagation(),
2467
+ onKeyDown: (e) => {
2468
+ if (e.key !== "ArrowUp" && e.key !== "ArrowRight" && e.key !== "ArrowDown" && e.key !== "ArrowLeft") return;
2469
+ e.preventDefault();
2470
+ e.stopPropagation();
2471
+ const d = e.key === "ArrowUp" || e.key === "ArrowRight" ? 0.05 : -0.05;
2472
+ saveRobotScale(Math.max(0.85, Math.min(2.2, Math.round((displayRobotScale + d) * 100) / 100)));
2473
+ }
2474
+ }
2475
+ )
2476
+ ]
2477
+ }
2478
+ ) : null,
2479
+ ambientOn && mode !== "robot" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2480
+ "button",
2481
+ {
2482
+ type: "button",
2483
+ className: "dkan-badge" + (mode === "breathe" ? " dkan-badge-breathe" : ""),
2484
+ style: Object.assign({}, speedStyle, { "--dkan-phase": phaseColor(phase) }),
2485
+ title: active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D \xB7 " + phaseLabel(phase) + " \xB7 \u70B9\u51FB\u67E5\u770B\u4EFB\u52A1\u52A8\u753B\u9875",
2486
+ onClick: () => openPanel("animation"),
2487
+ children: [
2488
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-dotwrap", children: [
2489
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-dot" }),
2490
+ mode === "breathe" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-halo" }) : null,
2491
+ mode === "ring" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-ring" }) : null
2492
+ ] }),
2493
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-badge-txt", children: [
2494
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "n", children: active.length }),
2495
+ " \u4E2A\u4EFB\u52A1",
2496
+ elapsed ? " \xB7 " + elapsed : "",
2497
+ " \xB7 ",
2498
+ phaseLabel(phase)
2499
+ ] })
2500
+ ]
2501
+ }
2502
+ ) : null,
2503
+ flourish ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2504
+ "div",
2505
+ {
2506
+ className: "dkan-done" + (flourish.err ? " err" : ""),
2507
+ onAnimationEnd: () => setFlourish(null),
2508
+ "aria-hidden": "true"
2509
+ },
2510
+ flourish.key
2511
+ ) : null,
2512
+ 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
2513
+ ] });
2514
+ }
2515
+ function ModePreview({ id }) {
2516
+ 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" }) });
2517
+ if (id === "ring") {
2518
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-dotwrap", children: [
2519
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-dot" }),
2520
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-ring" })
2521
+ ] }) });
2522
+ }
2523
+ if (id === "orbit") {
2524
+ 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" }) });
2525
+ }
2526
+ if (id === "matrix") {
2527
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-prev dkan-prev-matrix", children: [
2528
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2529
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2530
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2531
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2532
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2533
+ ] });
2534
+ }
2535
+ if (id === "stars") {
2536
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-prev dkan-prev-stars", children: [
2537
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2538
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2539
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2540
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2541
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2542
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2543
+ ] });
2544
+ }
2545
+ if (id === "aurora") {
2546
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-prev dkan-prev-aurora", children: [
2547
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
2548
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {})
2549
+ ] });
2550
+ }
2551
+ if (id === "robot") {
2552
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev dkan-prev-bot", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RobotScene, { phase: "code" }) });
2553
+ }
2554
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-prev", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-dotwrap dkan-breathe", children: [
2555
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-dot" }),
2556
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-halo" })
2557
+ ] }) });
2558
+ }
2559
+ function TaskRow(props) {
2560
+ const t = props.t;
2561
+ const info = endInfo(t.endReason);
2562
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-task", children: [
2563
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-task-head", children: [
2564
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-task-title", title: t.title, children: t.title || "(\u65E0\u6807\u9898)" }),
2565
+ 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) })
2566
+ ] }),
2567
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-task-meta", children: [
2568
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: (t.models && t.models.length ? t.models.join(", ") : "\u672A\u77E5") + (t.provider ? "\uFF08" + t.provider + "\uFF09" : "") }),
2569
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: props.done ? fmtDur(t.duration) : fmtClock(t.elapsed) }),
2570
+ "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,
2571
+ t.totalTokens ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u21A7" + fmtCompact2(t.inputTokens) + " \u21A5" + fmtCompact2(t.outputTokens) }) : null,
2572
+ props.done && t.endTime ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: fmtTime2(t.endTime) }) : null
2573
+ ] }),
2574
+ props.done && t.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-task-err", children: truncate(t.errorMessage, 120) }) : null
2575
+ ] });
2576
+ }
2577
+ function AnimationView(props) {
2578
+ const ctx = props && props.ctx;
2579
+ const snap = useAnimation(ctx);
2580
+ const [cfg, setCfg] = (0, import_react8.useState)(null);
2581
+ const [saveErr, setSaveErr] = (0, import_react8.useState)("");
2582
+ const [testing, setTesting] = (0, import_react8.useState)(false);
2583
+ const [testState, setTestState] = (0, import_react8.useState)(null);
2584
+ const [feishuTestState, setFeishuTestState] = (0, import_react8.useState)(null);
2585
+ const [feishuTesting, setFeishuTesting] = (0, import_react8.useState)(false);
2586
+ const cfgRef = (0, import_react8.useRef)(null);
2587
+ const pendingSavesRef = (0, import_react8.useRef)(0);
2588
+ const editingWebhookRef = (0, import_react8.useRef)(false);
2589
+ const editingFeishuRef = (0, import_react8.useRef)(false);
2590
+ (0, import_react8.useEffect)(() => {
2591
+ const c = snap.status && snap.status.config;
2592
+ if (!c) return;
2593
+ if (pendingSavesRef.current > 0 || editingWebhookRef.current || editingFeishuRef.current) return;
2594
+ if (c !== cfgRef.current) {
2595
+ cfgRef.current = c;
2596
+ setCfg(Object.assign({}, c));
2597
+ }
2598
+ }, [snap.status]);
2599
+ (0, import_react8.useEffect)(() => {
2600
+ if (!animationStore.snap.status) animationStore.refresh();
2601
+ }, []);
2602
+ const patch = (p) => {
2603
+ setSaveErr("");
2604
+ setCfg(Object.assign({}, cfg, p));
2605
+ pendingSavesRef.current++;
2606
+ return rpcCall2("config", p).then((d) => {
2607
+ pendingSavesRef.current--;
2608
+ animationStore.applyConfig(d && d.config);
2609
+ }).catch((e) => {
2610
+ pendingSavesRef.current--;
2611
+ setSaveErr("\u4FDD\u5B58\u5931\u8D25\uFF1A" + (e && e.message || String(e)));
2612
+ });
2613
+ };
2614
+ const saveWebhook = async () => {
2615
+ if (!editingWebhookRef.current) return;
2616
+ const hook = String(cfg.dingtalkWebhook || "").trim();
2617
+ await patch({ dingtalkWebhook: hook });
2618
+ editingWebhookRef.current = false;
2619
+ const c = animationStore.snap.status && animationStore.snap.status.config;
2620
+ if (c && c !== cfgRef.current) {
2621
+ cfgRef.current = c;
2622
+ setCfg(Object.assign({}, c));
2623
+ }
2624
+ };
2625
+ const saveFeishuWebhook = async () => {
2626
+ if (!editingFeishuRef.current) return;
2627
+ const hook = String(cfg.feishuWebhook || "").trim();
2628
+ await patch({ feishuWebhook: hook });
2629
+ editingFeishuRef.current = false;
2630
+ const c = animationStore.snap.status && animationStore.snap.status.config;
2631
+ if (c && c !== cfgRef.current) {
2632
+ cfgRef.current = c;
2633
+ setCfg(Object.assign({}, c));
2634
+ }
2635
+ };
2636
+ const runDingtalkTest = async () => {
2637
+ setTesting(true);
2638
+ setTestState(null);
2639
+ try {
2640
+ if (editingWebhookRef.current) {
2641
+ const hook = String(cfg.dingtalkWebhook || "").trim();
2642
+ if (!hook) throw new Error("\u8BF7\u5148\u586B\u5199 Webhook \u5730\u5740");
2643
+ const d = await rpcCall2("config", { dingtalkWebhook: hook });
2644
+ animationStore.applyConfig(d && d.config);
2645
+ editingWebhookRef.current = false;
2646
+ cfgRef.current = d && d.config || cfgRef.current;
2647
+ setCfg(Object.assign({}, cfg, { dingtalkWebhook: hook }));
2648
+ }
2649
+ const r = await rpcCall2("test");
2650
+ 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" });
2651
+ } catch (e) {
2652
+ setTestState({ ok: false, msg: e && e.message || String(e) });
2653
+ } finally {
2654
+ setTesting(false);
2655
+ }
2656
+ };
2657
+ const runFeishuTest = async () => {
2658
+ setFeishuTesting(true);
2659
+ setFeishuTestState(null);
2660
+ try {
2661
+ if (editingFeishuRef.current) {
2662
+ const hook = String(cfg.feishuWebhook || "").trim();
2663
+ if (!hook) throw new Error("\u8BF7\u5148\u586B\u5199 Webhook \u5730\u5740");
2664
+ const d = await rpcCall2("config", { feishuWebhook: hook });
2665
+ animationStore.applyConfig(d && d.config);
2666
+ editingFeishuRef.current = false;
2667
+ cfgRef.current = d && d.config || cfgRef.current;
2668
+ setCfg(Object.assign({}, cfg, { feishuWebhook: hook }));
2669
+ }
2670
+ const r = await rpcCall2("test", { target: "feishu" });
2671
+ setFeishuTestState(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" });
2672
+ } catch (e) {
2673
+ setFeishuTestState({ ok: false, msg: e && e.message || String(e) });
2674
+ } finally {
2675
+ setFeishuTesting(false);
2676
+ }
2677
+ };
2678
+ const enableSystemNotify = async (next) => {
2679
+ if (next && typeof Notification !== "undefined" && Notification.permission !== "granted") {
2680
+ try {
2681
+ const perm = await Notification.requestPermission();
2682
+ if (perm !== "granted") {
2683
+ 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");
2684
+ return;
2685
+ }
2686
+ } catch {
2687
+ setSaveErr("\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u7CFB\u7EDF\u901A\u77E5");
2688
+ return;
2689
+ }
2690
+ }
2691
+ patch({ systemNotify: next });
2692
+ };
2693
+ const st = snap.status;
2694
+ const active = st && st.active ? st.active : [];
2695
+ const recent = st && st.recent ? st.recent.slice(0, 6) : [];
2696
+ 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";
2697
+ const rows = [];
2698
+ if (!cfg) {
2699
+ 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"));
2700
+ } else {
2701
+ rows.push(
2702
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2703
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2704
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u8FD0\u884C\u52A8\u753B" }),
2705
+ /* @__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" }),
2706
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sec-sw", children: [
2707
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-swlabel" + (cfg.animationEnabled ? " on" : ""), children: cfg.animationEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
2708
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2709
+ "button",
2710
+ {
2711
+ type: "button",
2712
+ className: "dock-sw" + (cfg.animationEnabled ? " on" : ""),
2713
+ role: "switch",
2714
+ "aria-checked": cfg.animationEnabled,
2715
+ "aria-label": "\u5F00\u5173\u8FD0\u884C\u52A8\u753B",
2716
+ title: cfg.animationEnabled ? "\u5173\u95ED\u8FD0\u884C\u52A8\u753B" : "\u5F00\u542F\u8FD0\u884C\u52A8\u753B",
2717
+ onClick: () => patch({ animationEnabled: !cfg.animationEnabled })
2718
+ }
2719
+ )
2720
+ ] })
2721
+ ] }),
2722
+ cfg.animationEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2723
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-modes", children: EFFECT_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2724
+ "button",
2725
+ {
2726
+ type: "button",
2727
+ className: "dkan-mode" + (cfg.effectMode === m.id ? " on" : ""),
2728
+ onClick: () => patch({ effectMode: m.id }),
2729
+ children: [
2730
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-mode-name", children: m.name }),
2731
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ModePreview, { id: m.id }),
2732
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-mode-desc", children: m.desc })
2733
+ ]
2734
+ },
2735
+ m.id
2736
+ )) }),
2737
+ cfg.effectMode === "robot" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-robot-controls", children: [
2738
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-robot-controls-head", children: [
2739
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u684C\u9762\u4F19\u4F34\u5927\u5C0F" }),
2740
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
2741
+ Math.round((Number(cfg.robotScale) || 1.35) * 100),
2742
+ "%"
2743
+ ] })
2744
+ ] }),
2745
+ /* @__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)(
2746
+ "button",
2747
+ {
2748
+ type: "button",
2749
+ className: Math.abs((Number(cfg.robotScale) || 1.35) - scale) < 0.03 ? "on" : "",
2750
+ onClick: () => patch({ robotScale: scale }),
2751
+ children: label
2752
+ },
2753
+ scale
2754
+ )) }),
2755
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-robot-slider-row", children: [
2756
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2757
+ "input",
2758
+ {
2759
+ type: "range",
2760
+ min: "0.85",
2761
+ max: "2.2",
2762
+ step: "0.05",
2763
+ value: Number(cfg.robotScale) || 1.35,
2764
+ "aria-label": "\u684C\u9762\u4F19\u4F34\u5927\u5C0F\u767E\u5206\u6BD4",
2765
+ onChange: (e) => patch({ robotScale: Number(e.target.value) })
2766
+ }
2767
+ ),
2768
+ /* @__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" })
2769
+ ] })
2770
+ ] }) : null
2771
+ ] }) : /* @__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" })
2772
+ ] }, "anim"),
2773
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2775
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u5B8C\u6210\u901A\u77E5" }),
2776
+ /* @__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" }),
2777
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sec-sw", children: [
2778
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-swlabel" + (cfg.notifyEnabled ? " on" : ""), children: cfg.notifyEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
2779
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2780
+ "button",
2781
+ {
2782
+ type: "button",
2783
+ className: "dock-sw" + (cfg.notifyEnabled ? " on" : ""),
2784
+ role: "switch",
2785
+ "aria-checked": cfg.notifyEnabled,
2786
+ "aria-label": "\u5F00\u5173\u5B8C\u6210\u901A\u77E5",
2787
+ title: cfg.notifyEnabled ? "\u5173\u95ED\u5B8C\u6210\u901A\u77E5" : "\u5F00\u542F\u5B8C\u6210\u901A\u77E5",
2788
+ onClick: () => patch({ notifyEnabled: !cfg.notifyEnabled })
2789
+ }
2790
+ )
2791
+ ] })
2792
+ ] }),
2793
+ cfg.notifyEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-rows-narrow", children: [
2794
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2795
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u5B8C\u6210\u901A\u77E5" }),
2796
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2797
+ "button",
2798
+ {
2799
+ type: "button",
2800
+ className: "dkm-miniswitch" + (cfg.notifyOnComplete ? " on" : ""),
2801
+ onClick: () => patch({ notifyOnComplete: !cfg.notifyOnComplete }),
2802
+ children: cfg.notifyOnComplete ? "\u5F00" : "\u5173"
2803
+ }
2804
+ ),
2805
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: "\u4EFB\u52A1\u6B63\u5E38\u5B8C\u6210\u65F6\u901A\u77E5" })
2806
+ ] }),
2807
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2808
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u5F02\u5E38\u901A\u77E5" }),
2809
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2810
+ "button",
2811
+ {
2812
+ type: "button",
2813
+ className: "dkm-miniswitch" + (cfg.notifyOnError ? " on" : ""),
2814
+ onClick: () => patch({ notifyOnError: !cfg.notifyOnError }),
2815
+ children: cfg.notifyOnError ? "\u5F00" : "\u5173"
2816
+ }
2817
+ ),
2818
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: "\u51FA\u9519 / \u4E2D\u6B62 / \u8FBE\u8F93\u51FA\u4E0A\u9650\u65F6\u901A\u77E5" })
2819
+ ] }),
2820
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2821
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u505C\u7559\u65F6\u957F" }),
2822
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2823
+ "select",
2824
+ {
2825
+ className: "dkan-select",
2826
+ value: String(cfg.notifyStayMs),
2827
+ onChange: (e) => patch({ notifyStayMs: Number(e.target.value) }),
2828
+ children: [
2829
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "4000", children: "4 \u79D2" }),
2830
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "8000", children: "8 \u79D2" }),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "15000", children: "15 \u79D2" }),
2832
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "30000", children: "30 \u79D2" }),
2833
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "0", children: "\u5E38\u9A7B\uFF08\u624B\u52A8\u5173\u95ED\uFF09" })
2834
+ ]
2835
+ }
2836
+ )
2837
+ ] }),
2838
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2839
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u7CFB\u7EDF\u901A\u77E5" }),
2840
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2841
+ "button",
2842
+ {
2843
+ type: "button",
2844
+ className: "dkm-miniswitch" + (cfg.systemNotify ? " on" : ""),
2845
+ onClick: () => enableSystemNotify(!cfg.systemNotify),
2846
+ children: cfg.systemNotify ? "\u5F00" : "\u5173"
2847
+ }
2848
+ ),
2849
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-sub", children: permNote })
2850
+ ] }),
2851
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2852
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u63D0\u793A\u97F3" }),
2853
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2854
+ "button",
2855
+ {
2856
+ type: "button",
2857
+ className: "dkm-miniswitch" + (cfg.soundNotify !== false ? " on" : ""),
2858
+ onClick: () => patch({ soundNotify: cfg.soundNotify === false }),
2859
+ children: cfg.soundNotify !== false ? "\u5F00" : "\u5173"
2860
+ }
2861
+ ),
2862
+ /* @__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" })
2863
+ ] }),
2864
+ 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)(
2865
+ "button",
2866
+ {
2867
+ type: "button",
2868
+ className: "dkan-sound" + (cfg.soundEffect === key ? " on" : ""),
2869
+ onClick: () => patch({ soundEffect: key }),
2870
+ children: [
2871
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sound-name", children: [
2872
+ SOUND_LIBRARY[key].name,
2873
+ cfg.soundEffect === key ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sound-cur", children: "\u2713" }) : null
2874
+ ] }),
2875
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2876
+ "span",
2877
+ {
2878
+ className: "dkan-sound-play",
2879
+ role: "button",
2880
+ tabIndex: 0,
2881
+ title: "\u8BD5\u542C " + SOUND_LIBRARY[key].name,
2882
+ onClick: (e) => {
2883
+ e.stopPropagation();
2884
+ previewSound(key);
2885
+ },
2886
+ onKeyDown: (e) => {
2887
+ if (e.key === "Enter" || e.key === " ") {
2888
+ e.preventDefault();
2889
+ e.stopPropagation();
2890
+ previewSound(key);
2891
+ }
2892
+ },
2893
+ children: "\u25B6"
2894
+ }
2895
+ )
2896
+ ]
2897
+ },
2898
+ key
2899
+ )) }) : null
2900
+ ] }) : /* @__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" })
2901
+ ] }, "notify"),
2902
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2903
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2904
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u9489\u9489\u63A8\u9001" }),
2905
+ /* @__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" }),
2906
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sec-sw", children: [
2907
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-swlabel" + (cfg.dingtalkEnabled ? " on" : ""), children: cfg.dingtalkEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
2908
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2909
+ "button",
2910
+ {
2911
+ type: "button",
2912
+ className: "dock-sw" + (cfg.dingtalkEnabled ? " on" : ""),
2913
+ role: "switch",
2914
+ "aria-checked": cfg.dingtalkEnabled,
2915
+ "aria-label": "\u5F00\u5173\u9489\u9489\u63A8\u9001",
2916
+ title: cfg.dingtalkEnabled ? "\u5173\u95ED\u9489\u9489\u63A8\u9001" : "\u5F00\u542F\u9489\u9489\u63A8\u9001",
2917
+ onClick: () => patch({ dingtalkEnabled: !cfg.dingtalkEnabled })
2918
+ }
2919
+ )
2920
+ ] })
2921
+ ] }),
2922
+ cfg.dingtalkEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-rows-narrow", children: [
2923
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row dkan-row-webhook", children: [
2924
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "Webhook" }),
2925
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2926
+ "input",
2927
+ {
2928
+ type: "text",
2929
+ className: "dkan-input",
2930
+ spellCheck: false,
2931
+ value: cfg.dingtalkWebhook || "",
2932
+ placeholder: "https://oapi.dingtalk.com/robot/send?access_token=\u2026",
2933
+ onChange: (e) => {
2934
+ editingWebhookRef.current = true;
2935
+ setCfg(Object.assign({}, cfg, { dingtalkWebhook: e.target.value }));
2936
+ }
2937
+ }
2938
+ ),
2939
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2940
+ "button",
2941
+ {
2942
+ type: "button",
2943
+ className: "dkan-btn",
2944
+ disabled: !editingWebhookRef.current,
2945
+ onClick: saveWebhook,
2946
+ children: editingWebhookRef.current ? "\u4FDD\u5B58" : "\u5DF2\u4FDD\u5B58"
2947
+ }
2948
+ )
2949
+ ] }),
2950
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
2951
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u8FDE\u901A\u6D4B\u8BD5" }),
2952
+ /* @__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" }),
2953
+ testState ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-row-sub" + (testState.ok ? " dkan-ok" : " dkan-err"), children: [
2954
+ testState.ok ? "\u2713 " : "\u2717 ",
2955
+ testState.msg
2956
+ ] }) : /* @__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" })
2957
+ ] }),
2958
+ /* @__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" })
2959
+ ] }) : /* @__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" })
2960
+ ] }, "dingtalk"),
2961
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
2962
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
2963
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u98DE\u4E66\u63A8\u9001" }),
2964
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-sub", children: "\u4EFB\u52A1\u7ED3\u675F\u63A8\u9001\u5230\u98DE\u4E66\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" }),
2965
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-sec-sw", children: [
2966
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-swlabel" + (cfg.feishuEnabled ? " on" : ""), children: cfg.feishuEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
2967
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2968
+ "button",
2969
+ {
2970
+ type: "button",
2971
+ className: "dock-sw" + (cfg.feishuEnabled ? " on" : ""),
2972
+ role: "switch",
2973
+ "aria-checked": cfg.feishuEnabled,
2974
+ "aria-label": "\u5F00\u5173\u98DE\u4E66\u63A8\u9001",
2975
+ title: cfg.feishuEnabled ? "\u5173\u95ED\u98DE\u4E66\u63A8\u9001" : "\u5F00\u542F\u98DE\u4E66\u63A8\u9001",
2976
+ onClick: () => patch({ feishuEnabled: !cfg.feishuEnabled })
2977
+ }
2978
+ )
2979
+ ] })
2980
+ ] }),
2981
+ cfg.feishuEnabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-rows-narrow", children: [
2982
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row dkan-row-webhook", children: [
2983
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "Webhook" }),
2984
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2985
+ "input",
2986
+ {
2987
+ type: "text",
2988
+ className: "dkan-input",
2989
+ spellCheck: false,
2990
+ value: cfg.feishuWebhook || "",
2991
+ placeholder: "https://open.feishu.cn/open-apis/bot/v2/hook/\u2026",
2992
+ onChange: (e) => {
2993
+ editingFeishuRef.current = true;
2994
+ setCfg(Object.assign({}, cfg, { feishuWebhook: e.target.value }));
2995
+ }
2996
+ }
2997
+ ),
2998
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2999
+ "button",
3000
+ {
3001
+ type: "button",
3002
+ className: "dkan-btn",
3003
+ disabled: !editingFeishuRef.current,
3004
+ onClick: saveFeishuWebhook,
3005
+ children: editingFeishuRef.current ? "\u4FDD\u5B58" : "\u5DF2\u4FDD\u5B58"
3006
+ }
3007
+ )
3008
+ ] }),
3009
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-row", children: [
3010
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-row-label", children: "\u8FDE\u901A\u6D4B\u8BD5" }),
3011
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "dkan-btn", disabled: feishuTesting, onClick: runFeishuTest, children: feishuTesting ? "\u53D1\u9001\u4E2D\u2026" : "\u53D1\u9001\u6D4B\u8BD5\u6D88\u606F" }),
3012
+ feishuTestState ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-row-sub" + (feishuTestState.ok ? " dkan-ok" : " dkan-err"), children: [
3013
+ feishuTestState.ok ? "\u2713 " : "\u2717 ",
3014
+ feishuTestState.msg
3015
+ ] }) : /* @__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" })
3016
+ ] }),
3017
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u673A\u5668\u4EBA\u521B\u5EFA\uFF1A\u98DE\u4E66\u7FA4 \u2192 \u8BBE\u7F6E \u2192 \u7FA4\u673A\u5668\u4EBA \u2192 \u6DFB\u52A0\u673A\u5668\u4EBA \u2192 \u81EA\u5B9A\u4E49\u673A\u5668\u4EBA\uFF08\u83B7\u53D6 Webhook \u5730\u5740\uFF09\uFF1B \u5B89\u5168\u8BBE\u7F6E\u5982\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" })
3018
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u7ED3\u675F\u4E0D\u63A8\u9001\u98DE\u4E66\u3002" })
3019
+ ] }, "feishu")
3020
+ );
3021
+ }
3022
+ if (saveErr) rows.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note dkan-err", children: saveErr }, "err"));
3023
+ rows.push(
3024
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec", children: [
3025
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-sec-head", children: [
3026
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "dkan-sec-title", children: "\u8FD0\u884C\u72B6\u6001" }),
3027
+ /* @__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" }),
3028
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "dkan-refresh", onClick: () => animationStore.refresh(), children: snap.loading ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0" })
3029
+ ] }),
3030
+ 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,
3031
+ 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,
3032
+ 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
3033
+ ] }, "state")
3034
+ );
3035
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-root", children: rows });
3036
+ }
3037
+ function AnimationStat(props) {
3038
+ const snap = useAnimation(props && props.ctx);
3039
+ const st = snap.status;
3040
+ 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" });
3041
+ if (!st) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u7B49\u5F85\u4EFB\u52A1\u72B6\u6001\u2026" });
3042
+ if (st.active && st.active.length > 0) {
3043
+ 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))) });
3044
+ }
3045
+ const last = st.recent && st.recent[0];
3046
+ 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" });
3047
+ }
3048
+ var css2 = [
3049
+ // 顶部流光细线(3px,比首版更醒目)
3050
+ ".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);}",
3051
+ '.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;}',
3052
+ "@keyframes dkan-flow{to{left:100%}}",
3053
+ // 完成瞬间的一次性流光(成功绿 / 异常红),动画结束自动清场
3054
+ ".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;}",
3055
+ ".dkan-done.err{background-image:linear-gradient(90deg,transparent,var(--dsw-alias-state-error-primary,#f87171) 50%,#fff);}",
3056
+ "@keyframes dkan-done{0%{background-position:-60% 0;opacity:0}25%{opacity:1}100%{background-position:160% 0;opacity:0}}",
3057
+ // 环屏巡航:光点沿屏幕边缘转一整圈
3058
+ ".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;}",
3059
+ "@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}}",
3060
+ // ===== 氛围动效 =====
3061
+ ".dkan-amb{position:fixed;inset:0;z-index:9989;pointer-events:none;overflow:hidden;}",
3062
+ // pointer-events 不继承:全屏装饰层的子粒子(星点/流星/极光/火花/彩带)必须各自透明于点击
3063
+ ".dkan-amb *,.dkan-fxwrap *{pointer-events:none;}",
3064
+ // 代码雨:字符列缓落(提亮加大,速度随吞吐)
3065
+ ".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;}",
3066
+ "@keyframes dkan-fall{to{transform:translateY(125vh)}}",
3067
+ // 星野:星点缓慢飘移 + 闪烁(加亮加发光)+ 月亮 + 流星
3068
+ ".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;}",
3069
+ "@keyframes dkan-star{0%{opacity:.3;transform:translate(0,0)}50%{opacity:1}100%{opacity:.45;transform:translate(var(--dx),var(--dy))}}",
3070
+ // 月亮:右上弯月(radial-gradient 咬出月牙,透明区不遮挡背景;外圈柔光晕)
3071
+ ".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);}",
3072
+ // 流星:斜向划过的光带(亮头 + 渐隐尾),周期出现
3073
+ ".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;}",
3074
+ '.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);}',
3075
+ "@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)}}",
3076
+ // 极光:顶部柔光带呼吸流动(加浓)
3077
+ ".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;}",
3078
+ ".dkan-aurora i:nth-child(1){background:#4d9fff;}",
3079
+ ".dkan-aurora i:nth-child(2){background:#34d399;left:20%;animation-delay:-2s;}",
3080
+ ".dkan-aurora i:nth-child(3){background:#a78bfa;left:55%;animation-delay:-4s;}",
3081
+ "@keyframes dkan-aurora{0%{transform:translateX(-8%) scaleY(1)}100%{transform:translateX(10%) scaleY(1.3)}}",
3082
+ // ===== 交互反馈层 =====
3083
+ ".dkan-fxwrap{position:fixed;inset:0;z-index:9992;pointer-events:none;overflow:hidden;}",
3084
+ ".dkan-fx{position:absolute;}",
3085
+ // 纸飞机:从点击处向右上飞出淡出(加大加亮)
3086
+ ".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;}",
3087
+ "@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)}}",
3088
+ // 火花:粒子四散(加大加多散得更开)
3089
+ ".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;}",
3090
+ "@keyframes dkan-spark{0%{opacity:1;transform:translate(0,0) scale(1)}100%{opacity:0;transform:translate(var(--dx),var(--dy)) scale(.4)}}",
3091
+ // 流光:横向扫过(切会话,加高加亮)
3092
+ ".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;}",
3093
+ "@keyframes dkan-streak{0%{background-position:-50% 0;opacity:0}20%{opacity:1}100%{background-position:150% 0;opacity:0}}",
3094
+ // 微光:全屏柔光一闪(切工作目录,加浓)
3095
+ ".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;}",
3096
+ "@keyframes dkan-flash{0%{opacity:0}30%{opacity:1}100%{opacity:0}}",
3097
+ // 光涌:底部向上涌起(任务开始,加高加浓)
3098
+ ".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;}",
3099
+ "@keyframes dkan-surge{0%{opacity:0;transform:translateY(45%)}30%{opacity:1}100%{opacity:0;transform:translateY(-35%)}}",
3100
+ // 彩带:顶部飘落(任务完成庆祝,加大加多)
3101
+ ".dkan-fx-confetti{inset:0;}",
3102
+ ".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;}",
3103
+ "@keyframes dkan-confetti{0%{opacity:1;transform:translateY(0) rotate(0)}100%{opacity:0;transform:translateY(75vh) translateX(var(--dx)) rotate(var(--r))}}",
3104
+ // 右下角状态徽标(玻璃拟态,可点击);抬到 dsh 输入卡上方避免重叠错位
3105
+ ".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);}",
3106
+ ".dkan-badge:hover{color:var(--dsw-alias-label-primary);}",
3107
+ ".dkan-badge .n{color:var(--dsw-alias-label-primary);font-weight:600;}",
3108
+ "@keyframes dkan-rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}",
3109
+ // 徽标圆点与两种动效(呼吸 / 轨道环)
3110
+ ".dkan-dotwrap{position:relative;width:20px;height:20px;flex:none;display:inline-flex;align-items:center;justify-content:center;}",
3111
+ ".dkan-dot{width:12px;height:12px;border-radius:50%;background:var(--dkan-phase,var(--dsw-alias-accent,#4d9fff));box-shadow:0 0 10px color-mix(in srgb,var(--dkan-phase,var(--dsw-alias-accent,#4d9fff)) 70%,transparent);transition:background .4s var(--ds-ease-in-out),box-shadow .4s var(--ds-ease-in-out);}",
3112
+ ".dkan-breathe .dkan-dot{animation:dkan-breathe calc(2.2s / var(--dkan-speed,1)) ease-in-out infinite;}",
3113
+ "@keyframes dkan-breathe{0%,100%{transform:scale(1);opacity:.5}50%{transform:scale(1.7);opacity:1}}",
3114
+ // 呼吸光晕:向外扩散的波纹环,与圆点同频(颜色随阶段)
3115
+ ".dkan-halo{position:absolute;inset:0;border-radius:50%;border:2px solid var(--dkan-phase,var(--dsw-alias-accent,#4d9fff));animation:dkan-halo calc(2.2s / var(--dkan-speed,1)) ease-out infinite;}",
3116
+ "@keyframes dkan-halo{0%{transform:scale(.5);opacity:.9}70%{transform:scale(1.5);opacity:.25}100%{transform:scale(1.7);opacity:0}}",
3117
+ // breathe 模式徽标更醒目:阶段色描边 + 呼吸辉光
3118
+ ".dkan-badge-breathe{border-color:color-mix(in srgb,var(--dkan-phase,#4d9fff) 55%,transparent);animation:dkan-rise .3s var(--ds-ease-in-out),dkan-badge-breathe calc(2.2s / var(--dkan-speed,1)) ease-in-out infinite;}",
3119
+ "@keyframes dkan-badge-breathe{0%,100%{box-shadow:0 0 6px color-mix(in srgb,var(--dkan-phase,#4d9fff) 22%,transparent),0 6px 24px rgb(0 0 0 / .16)}50%{box-shadow:0 0 18px color-mix(in srgb,var(--dkan-phase,#4d9fff) 55%,transparent),0 6px 24px rgb(0 0 0 / .16)}}",
3120
+ ".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;}",
3121
+ "@keyframes dkan-spin{to{transform:rotate(360deg)}}",
3122
+ // 通知卡片栈(右上角)
3123
+ ".dkan-toasts{position:fixed;top:16px;right:16px;z-index:9995;display:flex;flex-direction:column;gap:8px;width:min(380px,calc(100vw - 32px));}",
3124
+ ".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);}",
3125
+ ".dkan-toast.out{animation:dkan-toast-out .24s var(--ds-ease-in-out) forwards;}",
3126
+ "@keyframes dkan-toast-in{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}",
3127
+ "@keyframes dkan-toast-out{to{opacity:0;transform:translateX(10px)}}",
3128
+ ".dkan-toast-head{display:flex;align-items:center;gap:8px;margin-bottom:4px;}",
3129
+ ".dkan-toast-mark{width:8px;height:8px;border-radius:50%;flex:none;}",
3130
+ ".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;}",
3131
+ ".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;}",
3132
+ ".dkan-toast-close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
3133
+ ".dkan-toast-body{font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.7;white-space:pre-line;word-break:break-word;}",
3134
+ // 面板页布局
3135
+ ".dkan-root{display:flex;flex-direction:column;gap:10px;}",
3136
+ ".dkan-note{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.6;}",
3137
+ ".dkan-err{color:var(--dsw-alias-state-error-primary);}",
3138
+ ".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;}",
3139
+ ".dkan-sec-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
3140
+ ".dkan-sec-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary);flex:none;}",
3141
+ ".dkan-sec-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);flex:1;min-width:120px;}",
3142
+ ".dkan-sec-sw{margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:8px;}",
3143
+ ".dkan-sec-swlabel{font-size:11px;color:var(--dsw-alias-label-tertiary);white-space:nowrap;}",
3144
+ ".dkan-sec-swlabel.on{color:var(--dsw-alias-state-success-primary);}",
3145
+ ".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;}",
3146
+ ".dkan-refresh:hover{background:var(--dsw-alias-interactive-bg-hover);}",
3147
+ // 模式选择卡(带缩微预览)
3148
+ ".dkan-modes{display:flex;gap:8px;flex-wrap:wrap;}",
3149
+ ".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);}",
3150
+ ".dkan-mode:hover{border-color:var(--dsw-alias-accent,#4d9fff);}",
3151
+ ".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);}",
3152
+ ".dkan-mode-name{font-size:12px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:6px;}",
3153
+ '.dkan-mode.on .dkan-mode-name::after{content:"\u2713";color:var(--dsw-alias-accent,#4d9fff);}',
3154
+ ".dkan-mode-desc{font-size:11px;color:var(--dsw-alias-label-tertiary);line-height:1.5;}",
3155
+ ".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));}",
3156
+ ".dkan-robot-controls-head{display:flex;align-items:center;justify-content:space-between;font-size:12px;color:var(--dsw-alias-label-primary);}",
3157
+ ".dkan-robot-controls-head strong{font-variant-numeric:tabular-nums;color:var(--dsw-alias-accent,#4d9fff);}",
3158
+ ".dkan-robot-size-options{display:flex;gap:6px;flex-wrap:wrap;}",
3159
+ ".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;}",
3160
+ ".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);}",
3161
+ ".dkan-robot-slider-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap;font-size:11px;color:var(--dsw-alias-label-tertiary);}",
3162
+ ".dkan-robot-slider-row input{accent-color:var(--dsw-alias-accent,#4d9fff);width:min(240px,100%);}",
3163
+ ".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;}",
3164
+ ".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);}",
3165
+ '.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;}',
3166
+ ".dkan-prev-box{--dkan-speed:1;}",
3167
+ ".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;}",
3168
+ "@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}}",
3169
+ // 预览:代码雨(字符列下落)
3170
+ ".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;}",
3171
+ ".dkan-prev-matrix i:nth-child(1){left:12%;}",
3172
+ ".dkan-prev-matrix i:nth-child(2){left:32%;animation-delay:-.6s;}",
3173
+ ".dkan-prev-matrix i:nth-child(3){left:52%;animation-delay:-1.2s;}",
3174
+ ".dkan-prev-matrix i:nth-child(4){left:72%;animation-delay:-.3s;}",
3175
+ ".dkan-prev-matrix i:nth-child(5){left:88%;animation-delay:-1.6s;}",
3176
+ '.dkan-prev-matrix i::after{content:"01</>";}',
3177
+ "@keyframes dkan-prev-fall{to{transform:translateY(300%)}}",
3178
+ // 预览:星野(星点闪烁)
3179
+ ".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;}",
3180
+ ".dkan-prev-stars i:nth-child(1){left:15%;top:25%;}",
3181
+ ".dkan-prev-stars i:nth-child(2){left:40%;top:60%;animation-delay:-.4s;}",
3182
+ ".dkan-prev-stars i:nth-child(3){left:60%;top:30%;animation-delay:-.8s;}",
3183
+ ".dkan-prev-stars i:nth-child(4){left:80%;top:55%;animation-delay:-1.2s;}",
3184
+ ".dkan-prev-stars i:nth-child(5){left:28%;top:70%;animation-delay:-.6s;}",
3185
+ ".dkan-prev-stars i:nth-child(6){left:70%;top:75%;animation-delay:-1s;}",
3186
+ "@keyframes dkan-prev-star{0%{opacity:.2}100%{opacity:.9}}",
3187
+ // 预览:极光(柔光带呼吸)
3188
+ ".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;}",
3189
+ ".dkan-prev-aurora i:nth-child(1){left:5%;background:#4d9fff;}",
3190
+ ".dkan-prev-aurora i:nth-child(2){left:45%;background:#34d399;animation-delay:-1.2s;}",
3191
+ "@keyframes dkan-prev-aurora{0%{transform:translateX(-10%)}100%{transform:translateX(15%)}}",
3192
+ ".dkan-prev-bot{height:92px;justify-content:center;}",
3193
+ ".dkan-prev-bot .dkan-bot-scene{--dkan-bot-scale:1;transform:scale(.56);transform-origin:center;}",
3194
+ // ===== 桌面伙伴:具象人物 + 紧凑双工位(尺寸可调,整卡可拖拽) =====
3195
+ // 卡片:玻璃拟态;默认停泊右下(dsh 输入卡上方),拖动后位置持久化、可放屏幕任意处
3196
+ ".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);}",
3197
+ ".dkan-botcard:hover,.dkan-botcard:focus-visible{border-color:var(--dsw-alias-accent,#4d9fff);outline:none;}",
3198
+ ".dkan-botcard.dkan-dragging{cursor:grabbing;animation:none;}",
3199
+ ".dkan-botcard .n{color:var(--dsw-alias-label-primary);font-weight:600;}",
3200
+ ".dkan-bot-cap{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:18px;}",
3201
+ ".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;}",
3202
+ ".dkan-bot-resize:hover,.dkan-bot-resize:focus-visible{opacity:1;outline:1px solid var(--dsw-alias-accent,#4d9fff);outline-offset:1px;}",
3203
+ // ===== 3D 场景(CSS 长方体拼装:世界层统一 3/4 视角——俯视 + 侧身面向镜头) =====
3204
+ ".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;}",
3205
+ ".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);}",
3206
+ ".dk3-box{position:absolute;transform-style:preserve-3d;}",
3207
+ ".dk3-face{position:absolute;left:50%;top:50%;display:block;background:var(--dk3-side);backface-visibility:hidden;border-radius:1px;}",
3208
+ // 金属件着色:顶面亮、底面暗,正/侧面中调(3D 光感)
3209
+ ".dk3-metal .dk3-face{background:linear-gradient(180deg,#93a5ba,#71809a);}",
3210
+ ".dk3-metal .dk3-face:nth-child(5){background:linear-gradient(180deg,var(--dk3-side-hi),#9dadc2);}",
3211
+ ".dk3-metal .dk3-face:nth-child(6){background:var(--dk3-side-dk);}",
3212
+ // 书桌与桌腿
3213
+ ".dk3-desk .dk3-face{background:linear-gradient(180deg,#9db0c6,#7f92aa);}",
3214
+ ".dk3-desk .dk3-face:nth-child(5){background:#c3d2e2;}",
3215
+ // 显示器(薄盒 + 贴在前面的屏幕;组内扇形微转,整组后撤出桌沿)
3216
+ ".dk3-mon3{position:absolute;transform-style:preserve-3d;}",
3217
+ ".dk3-frame .dk3-face{background:#3a465b;}",
3218
+ ".dk3-frame .dk3-face:nth-child(5){background:#55647d;}",
3219
+ ".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);}",
3220
+ // 屏幕内容:代码块整体向上滚动(10 行=5 行×2 循环,滚半程无缝接回)+ 闪烁光标,速度随 --dkan-speed
3221
+ ".dk3-code{position:absolute;left:0;top:0;right:0;display:block;animation:dk3-scroll calc(5s / var(--dkan-speed,1)) linear infinite;}",
3222
+ ".dk3-code i{display:block;height:2px;border-radius:1px;margin:2px 3px 0;background:var(--dkan-code-b);opacity:.55;}",
3223
+ ".dk3-code i:nth-child(5n+1){width:58%;background:var(--dkan-code-a);}",
3224
+ ".dk3-code i:nth-child(5n+2){width:82%;}",
3225
+ ".dk3-code i:nth-child(5n+3){width:46%;background:var(--dkan-code-c);}",
3226
+ ".dk3-code i:nth-child(5n+4){width:72%;}",
3227
+ ".dk3-code i:nth-child(5n){width:54%;background:var(--dkan-code-a);}",
3228
+ ".dk3-cur{position:absolute;left:3px;bottom:2px;width:4px;height:2px;background:var(--dkan-code-b);animation:dkan-blink3 1s steps(1) infinite;}",
3229
+ // 左屏检索视图:搜索框、放大镜与结果条,和右侧代码编辑器明确区分
3230
+ ".dk3-search-ui{position:absolute;inset:3px;display:block;overflow:hidden;}",
3231
+ ".dk3-search-box{display:block;height:5px;margin:0 1px 3px;border:1px solid color-mix(in srgb,var(--dkan-code-a) 72%,#d7fff4);border-radius:2px;box-sizing:border-box;}",
3232
+ ".dk3-search-box b{display:block;width:2px;height:2px;margin:1px 0 0 2px;border:1px solid var(--dkan-code-a);border-radius:50%;position:relative;}",
3233
+ ".dk3-search-box b:after{content:'';position:absolute;width:2px;height:1px;background:var(--dkan-code-a);right:-2px;bottom:-1px;transform:rotate(45deg);transform-origin:left center;}",
3234
+ ".dk3-search-results{display:block;animation:dk3-search-scroll calc(2.1s / var(--dkan-speed,1)) linear infinite;}",
3235
+ ".dk3-search-results i{display:block;height:2px;margin:2px 1px 0;border-radius:1px;background:var(--dkan-code-a);opacity:.72;}",
3236
+ ".dk3-search-results i:nth-child(2n){width:74%;background:var(--dkan-code-b);}",
3237
+ ".dk3-search-results i:nth-child(3n){width:48%;background:var(--dkan-code-c);}",
3238
+ "@keyframes dk3-search-scroll{to{transform:translateY(-5px)}}",
3239
+ "@keyframes dk3-scroll{to{transform:translateY(-50%)}}",
3240
+ // 人物与椅子始终正对桌面:工位切换只横移,不再旋转整个人和座椅。
3241
+ ".dk3-person{--dk3-seat-x:22px;position:absolute;left:98px;top:14px;width:44px;height:61px;transform-style:preserve-3d;transform:translateZ(30px) translateX(var(--dk3-seat-x));transition:transform max(.18s,calc(.38s / var(--dkan-speed,1))) cubic-bezier(.23,1,.32,1);will-change:transform;}",
3242
+ ".dkan-bot-scene[data-station=left] .dk3-person{--dk3-seat-x:0px;}",
3243
+ ".dkan-bot-scene[data-station=center] .dk3-person{--dk3-seat-x:22px;}",
3244
+ ".dkan-bot-scene[data-station=right] .dk3-person{--dk3-seat-x:44px;}",
3245
+ // 上身以髋部为旋转原点;只做前后倾,始终朝向桌面。
3246
+ ".dk3-upper3{position:absolute;inset:0;transform-style:preserve-3d;transform-origin:12px 52px;transform:translateZ(0);transition:transform .24s cubic-bezier(.77,0,.175,1);will-change:transform;}",
3247
+ // 动漫人物配色:皮肤/头发/卫衣/裤子
3248
+ ".dk3-skin .dk3-face{background:linear-gradient(180deg,#ffd9b8,#f3b98d);}",
3249
+ ".dk3-skin .dk3-face:nth-child(5){background:#ffe3c9;}",
3250
+ ".dk3-hair .dk3-face{background:linear-gradient(180deg,#5b4632,#3f3021);}",
3251
+ ".dk3-hair .dk3-face:nth-child(5){background:#6b543c;}",
3252
+ ".dk3-hood .dk3-face{background:linear-gradient(180deg,#7c8ba0,#5b6a80);}",
3253
+ ".dk3-hood .dk3-face:nth-child(5){background:#93a5ba;}",
3254
+ ".dk3-pants .dk3-face{background:linear-gradient(180deg,#3d4a5c,#2c3646);}",
3255
+ ".dk3-pants .dk3-face:nth-child(5){background:#4a5a70;}",
3256
+ // 人物细节:收窄下颌、连续肩颈、短侧渐层发型
3257
+ ".dk3-cranium .dk3-face{border-radius:42% 46% 38% 36%;}",
3258
+ ".dk3-jaw3 .dk3-face{border-radius:30% 30% 48% 48%;}",
3259
+ ".dk3-neck3 .dk3-face{border-radius:2px;}",
3260
+ ".dk3-collar3 .dk3-face{background:linear-gradient(180deg,#516176,#374459);border-radius:3px;}",
3261
+ ".dk3-shoulders3 .dk3-face{border-radius:4px;}",
3262
+ ".dk3-chest3 .dk3-face{border-radius:4px;}",
3263
+ ".dk3-waist3 .dk3-face{border-radius:3px;}",
3264
+ ".dk3-hair .dk3-face{border-radius:2px;}",
3265
+ ".dk3-hair-crown .dk3-face{border-radius:48% 42% 28% 30%;}",
3266
+ ".dk3-hair-back .dk3-face{background:linear-gradient(180deg,#493727,#2f241b);border-radius:46% 24% 38% 44%;}",
3267
+ ".dk3-shoe .dk3-face{background:#20262f;border-radius:2px;}",
3268
+ ".dk3-mug .dk3-face{background:#c2703d;border-radius:1px;}",
3269
+ ".dk3-mug .dk3-face:nth-child(5){background:#e08a52;}",
3270
+ ".dk3-mouth{position:absolute;left:50%;top:64%;width:3.5px;height:1px;border-radius:2px;background:#a9635c;}",
3271
+ // 椅子
3272
+ ".dk3-chairback .dk3-face{background:linear-gradient(180deg,#3f4c60,#2c3648);}",
3273
+ ".dk3-chairseat .dk3-face{background:#33415a;}",
3274
+ // 头组与颈部中心均为 x=14;只让头部观察左右屏,身体和椅子不转向。
3275
+ ".dk3-head3{--dk3-head-turn:rotateY(0deg);position:absolute;left:6px;top:3px;width:17px;height:21px;transform-style:preserve-3d;transform-origin:8px 18px;transform:var(--dk3-head-turn);transition:transform max(.18s,calc(.22s / var(--dkan-speed,1))) cubic-bezier(.23,1,.32,1);will-change:transform;}",
3276
+ ".dkan-bot-scene[data-station=left] .dk3-head3{--dk3-head-turn:rotateY(-18deg);}",
3277
+ ".dkan-bot-scene[data-station=center] .dk3-head3{--dk3-head-turn:rotateY(0deg);}",
3278
+ ".dkan-bot-scene[data-station=right] .dk3-head3{--dk3-head-turn:rotateY(14deg);}",
3279
+ ".dk3-brows{position:absolute;left:50%;top:29%;display:flex;gap:2.5px;align-items:center;justify-content:center;}",
3280
+ ".dk3-brows i{width:3.5px;height:1px;border-radius:2px;background:#3a2a21;transform:rotate(-7deg);}",
3281
+ ".dk3-brows i+ i{transform:rotate(7deg);}",
3282
+ ".dk3-eyes{position:absolute;left:50%;top:51%;display:flex;gap:2.5px;align-items:center;justify-content:center;}",
3283
+ ".dk3-eyes i{width:3.5px;height:2.5px;border-radius:50%;background:radial-gradient(circle at 62% 30%,#fff 0 .5px,#263141 .8px 1.7px,#111827 1.9px);animation:dkan-blink3 4.8s infinite;}",
3284
+ ".dk3-nose{position:absolute;left:50%;top:66%;width:2px;height:3px;border-radius:60% 40% 55% 45%;background:linear-gradient(90deg,#e7a67e,#c77f67);}",
3285
+ ".dk3-ear{position:absolute;left:1px;top:10px;width:3px;height:5px;border-radius:52% 44% 48% 52%;background:linear-gradient(90deg,#edaa82,#ffd2ad);transform:translateZ(2px);}",
3286
+ ".dk3-fringe3{position:absolute;left:13px;top:4px;width:5px;height:7px;transform-style:preserve-3d;transform:rotateY(90deg) translateZ(5.8px);}",
3287
+ ".dk3-fringe3 i{position:absolute;top:0;width:2px;height:6px;border-radius:70% 25% 60% 30%;background:linear-gradient(180deg,#6b5239,#392b20);transform-origin:top center;}",
3288
+ ".dk3-fringe3 i:nth-child(1){left:0;transform:rotate(-18deg);height:5px;}",
3289
+ ".dk3-fringe3 i:nth-child(2){left:1.8px;transform:rotate(-6deg);height:6px;}",
3290
+ ".dk3-fringe3 i:nth-child(3){left:3.5px;transform:rotate(12deg);height:4px;}",
3291
+ "@keyframes dkan-blink3{0%,91%,100%{transform:scaleY(1)}94%{transform:scaleY(.15)}}",
3292
+ // 手臂按肩→肘→腕分段,旋转原点位于真实关节连接处。
3293
+ ".dk3-arm3{position:absolute;left:20px;top:30px;width:16px;height:16px;transform-style:preserve-3d;transform-origin:2px 2px;will-change:transform;}",
3294
+ ".dk3-elbow{position:absolute;left:0;top:10px;width:15px;height:5px;transform-style:preserve-3d;transform-origin:1px 2px;will-change:transform;}",
3295
+ ".dk3-wrist3{position:absolute;left:9.5px;top:0;width:6px;height:5px;transform-style:preserve-3d;transform-origin:1px 2px;will-change:transform;}",
3296
+ ".dk3-fingers3{position:absolute;left:3px;top:1px;width:4px;height:3px;transform:translateZ(2px);}",
3297
+ ".dk3-fingers3 i{position:absolute;left:0;width:4px;height:.8px;border-radius:2px;background:#f2b58d;}",
3298
+ ".dk3-fingers3 i+ i{top:1.4px;width:3.5px;}",
3299
+ ".dk3-far{transform:translateZ(-7px);filter:brightness(.72);}",
3300
+ // 思考泡泡(贴镜头 2D 层,think 阶段显示)
3301
+ ".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;}",
3302
+ ".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;}",
3303
+ ".dkan-bubble i:nth-child(2){animation-delay:.2s;}",
3304
+ ".dkan-bubble i:nth-child(3){animation-delay:.4s;}",
3305
+ "@keyframes dkan-bubdot{0%,100%{opacity:.25;transform:translateY(0)}50%{opacity:1;transform:translateY(-2px)}}",
3306
+ // ===== 多任务工位(data-tasks=活跃任务数,上限 3) =====
3307
+ // 椅子滚轮
3308
+ ".dk3-wheel .dk3-face{background:#1c232e;border-radius:50%;}",
3309
+ // 有活跃任务时,未轮到的侧工位稍暗;多任务则两个工位均保持可见。
3310
+ ".dkan-bot-scene[data-tasks] .dk3-mon3.left .dk3-screen,.dkan-bot-scene[data-tasks] .dk3-mon3.right .dk3-screen{opacity:.3;}",
3311
+ // 2 个及以上任务:左右工位同时点亮(各自带辉光、代码滚动加速)。
3312
+ '.dkan-bot-scene[data-tasks="2"] .dk3-mon3.left .dk3-screen,.dkan-bot-scene[data-tasks="2"] .dk3-mon3.right .dk3-screen,.dkan-bot-scene[data-tasks="3"] .dk3-mon3.left .dk3-screen,.dkan-bot-scene[data-tasks="3"] .dk3-mon3.right .dk3-screen{opacity:1;box-shadow:0 0 8px color-mix(in srgb,var(--dkan-code-b,#60a5fa) 42%,transparent);}',
3313
+ '.dkan-bot-scene[data-tasks="2"] .dk3-mon3.left .dk3-code,.dkan-bot-scene[data-tasks="2"] .dk3-mon3.right .dk3-code,.dkan-bot-scene[data-tasks="3"] .dk3-mon3.left .dk3-code,.dkan-bot-scene[data-tasks="3"] .dk3-mon3.right .dk3-code{animation-duration:calc(2.6s / var(--dkan-speed,1));}',
3314
+ // 座椅移动期间滚轮跟随任务节奏转动;思考中停下,避免无意义的常驻运动。
3315
+ ".dkan-bot-scene[data-station=left] .dk3-wheel,.dkan-bot-scene[data-station=right] .dk3-wheel{animation:dkan-wheel calc(.46s / var(--dkan-speed,1)) linear infinite;transform-origin:center;}",
3316
+ "@keyframes dkan-wheel{to{transform:rotateZ(360deg)}}",
3317
+ // ===== 阶段驱动(data-phase 四态,host 由 chunk 流实时同步) =====
3318
+ // think:上身轻靠、近侧手托下巴、远侧手留在桌面;动作有停顿而不是机械往返。
3319
+ ".dkan-bot-scene[data-phase=think] .dk3-screen{opacity:.32;}",
3320
+ ".dkan-bot-scene[data-phase=think] .dkan-bubble{display:inline-flex;}",
3321
+ ".dkan-bot-scene[data-phase=think] .dk3-upper3{animation:dkan-think-upper max(1.8s,calc(2.4s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3322
+ ".dkan-bot-scene[data-phase=think] .dk3-head3{animation:dkan-think-head max(1.8s,calc(2.4s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3323
+ ".dkan-bot-scene[data-phase=think] .dk3-arm3.dk3-near{animation:dkan-think-near max(1.8s,calc(2.4s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3324
+ ".dkan-bot-scene[data-phase=think] .dk3-arm3.dk3-far{transform:translateZ(-7px) rotateZ(3deg);}",
3325
+ ".dkan-bot-scene[data-phase=think] .dk3-near .dk3-elbow{transform:rotateZ(-28deg) translateY(-1px);}",
3326
+ ".dkan-bot-scene[data-phase=think] .dk3-near .dk3-wrist3{transform:rotateZ(-18deg) translateY(-1px);}",
3327
+ "@keyframes dkan-think-upper{0%,44%{transform:rotateZ(-1deg) translateY(0)}62%,100%{transform:rotateZ(-1.8deg) translateY(-.5px)}}",
3328
+ "@keyframes dkan-think-head{0%,44%{transform:var(--dk3-head-turn) rotateZ(-3deg)}62%,100%{transform:var(--dk3-head-turn) rotateZ(-6deg) translateY(-.5px)}}",
3329
+ "@keyframes dkan-think-near{0%,44%{transform:rotateZ(-31deg) translate(-8px,-14.5px)}62%,100%{transform:rotateZ(-34deg) translate(-8.5px,-15px)}}",
3330
+ // write/code:身体仍面向桌面,仅轻微前倾;主要由手腕和手指敲击。
3331
+ ".dkan-bot-scene[data-phase=write] .dk3-mon3.right .dk3-screen,.dkan-bot-scene[data-phase=code] .dk3-mon3.right .dk3-screen{opacity:1;box-shadow:0 0 11px color-mix(in srgb,var(--dkan-code-b,#60a5fa) 52%,transparent);}",
3332
+ ".dkan-bot-scene[data-phase=write] .dk3-mon3.right .dk3-code,.dkan-bot-scene[data-phase=code] .dk3-mon3.right .dk3-code{animation-duration:calc(1.35s / var(--dkan-speed,1));}",
3333
+ ".dkan-bot-scene[data-phase=write] .dk3-upper3,.dkan-bot-scene[data-phase=code] .dk3-upper3{animation:dkan-code-upper max(1.2s,calc(2.4s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3334
+ ".dkan-bot-scene[data-phase=write] .dk3-arm3.dk3-near,.dkan-bot-scene[data-phase=code] .dk3-arm3.dk3-near{transform:rotateZ(3deg);}",
3335
+ ".dkan-bot-scene[data-phase=write] .dk3-arm3.dk3-far,.dkan-bot-scene[data-phase=code] .dk3-arm3.dk3-far{transform:translateZ(-7px) rotateZ(1deg);}",
3336
+ ".dkan-bot-scene[data-phase=write] .dk3-elbow,.dkan-bot-scene[data-phase=code] .dk3-elbow{animation:dkan-type-elbow max(.28s,calc(.58s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3337
+ ".dkan-bot-scene[data-phase=write] .dk3-wrist3,.dkan-bot-scene[data-phase=code] .dk3-wrist3{animation:dkan-type-wrist max(.18s,calc(.29s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3338
+ ".dkan-bot-scene[data-phase=write] .dk3-far .dk3-elbow,.dkan-bot-scene[data-phase=code] .dk3-far .dk3-elbow{animation-delay:-.09s;animation-duration:max(.3s,calc(.63s / var(--dkan-speed,1)));}",
3339
+ ".dkan-bot-scene[data-phase=write] .dk3-far .dk3-wrist3,.dkan-bot-scene[data-phase=code] .dk3-far .dk3-wrist3{animation-delay:-.09s;animation-duration:max(.2s,calc(.33s / var(--dkan-speed,1)));}",
3340
+ ".dkan-bot-scene[data-phase=write] .dk3-head3,.dkan-bot-scene[data-phase=code] .dk3-head3{animation:dkan-output-head max(1.2s,calc(2.4s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3341
+ "@keyframes dkan-code-upper{0%,38%{transform:rotateZ(2deg) translate(1px,0)}62%,100%{transform:rotateZ(3deg) translate(1px,1px)}}",
3342
+ "@keyframes dkan-type-elbow{0%,38%{transform:rotateZ(-4deg)}62%,100%{transform:rotateZ(5deg) translateY(1px)}}",
3343
+ "@keyframes dkan-type-wrist{0%,34%{transform:rotateZ(-2deg) translateY(0)}62%,100%{transform:rotateZ(3deg) translateY(1.5px)}}",
3344
+ "@keyframes dkan-output-head{0%,46%,100%{transform:var(--dk3-head-turn) rotateZ(3deg)}58%{transform:var(--dk3-head-turn) rotateZ(5deg) translateY(1px)}}",
3345
+ // search:身体正对桌面,头看左屏,近侧手腕小幅操作鼠标。
3346
+ ".dkan-bot-scene[data-phase=search] .dk3-mon3.left .dk3-screen{opacity:1;box-shadow:0 0 10px color-mix(in srgb,var(--dkan-code-a,#4ade80) 52%,transparent);}",
3347
+ ".dkan-bot-scene[data-phase=search] .dk3-mon3.left .dk3-search-results{animation-duration:calc(1.05s / var(--dkan-speed,1));}",
3348
+ ".dkan-bot-scene[data-phase=search] .dk3-upper3{transform:rotateZ(2deg) translateY(1px);}",
3349
+ ".dkan-bot-scene[data-phase=search] .dk3-head3{animation:dkan-search-head max(.72s,calc(1.15s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3350
+ ".dkan-bot-scene[data-phase=search] .dk3-near .dk3-wrist3{animation:dkan-search-wrist max(.45s,calc(.72s / var(--dkan-speed,1))) cubic-bezier(.77,0,.175,1) infinite;}",
3351
+ ".dkan-bot-scene[data-phase=search] .dk3-far{transform:translateZ(-7px) rotateZ(2deg);}",
3352
+ "@keyframes dkan-search-head{0%,28%{transform:var(--dk3-head-turn) rotateZ(1deg)}48%,68%{transform:var(--dk3-head-turn) rotateZ(6deg) translate(1px,1px)}88%,100%{transform:var(--dk3-head-turn) rotateZ(2deg)}}",
3353
+ "@keyframes dkan-search-wrist{0%,34%{transform:translateX(-1px)}62%,100%{transform:translateX(1.5px)}}",
3354
+ // 减少动态时停止空间位移,保留屏幕亮暗与思考状态的淡入反馈。
3355
+ "@media (prefers-reduced-motion:reduce){.dk3-person,.dk3-upper3,.dk3-head3,.dk3-arm3,.dk3-elbow,.dk3-wrist3,.dk3-wheel,.dk3-code,.dk3-search-results{animation:none!important;transition:none!important}.dk3-screen,.dkan-bubble{transition:opacity .2s cubic-bezier(.23,1,.32,1)!important}}",
3356
+ // 通知子选项行
3357
+ ".dkan-rows-narrow{display:flex;flex-direction:column;gap:6px;}",
3358
+ ".dkan-row{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dsw-alias-label-secondary);flex-wrap:wrap;}",
3359
+ ".dkan-row-label{flex:none;min-width:60px;color:var(--dsw-alias-label-primary);}",
3360
+ ".dkan-row-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
3361
+ ".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;}",
3362
+ ".dkm-miniswitch.on{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
3363
+ ".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;}",
3364
+ // 音效选择卡(名称 + 播放键;选中态描边)
3365
+ ".dkan-sounds{display:flex;gap:6px;flex-wrap:wrap;}",
3366
+ ".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);}",
3367
+ ".dkan-sound:hover{border-color:var(--dsw-alias-accent,#4d9fff);}",
3368
+ ".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);}",
3369
+ ".dkan-sound-name{font-size:12px;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:5px;}",
3370
+ ".dkan-sound-cur{color:var(--dsw-alias-accent,#4d9fff);font-size:11px;}",
3371
+ ".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);}",
3372
+ ".dkan-sound-play:hover{color:var(--dsw-alias-label-primary);border-color:currentColor;}",
3373
+ ".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;}",
3374
+ ".dkan-input:focus{outline:none;border-color:var(--dsw-alias-accent,#4d9fff);}",
3375
+ ".dkan-row-webhook{flex-wrap:nowrap;}",
3376
+ ".dkan-row-webhook .dkan-input{min-width:0;}",
3377
+ ".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;}",
3378
+ ".dkan-btn:hover{background:var(--dsw-alias-interactive-bg-hover);}",
3379
+ ".dkan-btn[disabled]{opacity:.5;cursor:default;}",
3380
+ ".dkan-ok{color:var(--dsw-alias-state-success-primary);}",
3381
+ // 任务列表
3382
+ ".dkan-tasks{display:flex;flex-direction:column;gap:6px;}",
3383
+ ".dkan-tasks-done{border-top:1px dashed var(--dsw-alias-border-l2);padding-top:6px;}",
3384
+ ".dkan-task{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 10px;display:flex;flex-direction:column;gap:3px;}",
3385
+ ".dkan-task-head{display:flex;align-items:center;gap:8px;min-width:0;}",
3386
+ ".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;}",
3387
+ ".dkan-task-meta{display:flex;gap:10px;flex-wrap:wrap;font-size:11px;color:var(--dsw-alias-label-tertiary);}",
3388
+ ".dkan-task-err{font-size:11px;color:var(--dsw-alias-state-error-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
3389
+ ".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);}",
3390
+ ".dkan-tag.on{color:var(--dsw-alias-accent,#4d9fff);border-color:currentColor;}",
3391
+ ".dkan-tag.ok{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
3392
+ ".dkan-tag.err{color:var(--dsw-alias-state-error-primary);border-color:currentColor;}",
3393
+ ".dkan-tag.warn{color:var(--dsw-alias-state-warning-primary);border-color:currentColor;}"
3394
+ ].join("\n");
3395
+ var feature6 = {
3396
+ id: "animation",
3397
+ name: "\u4EFB\u52A1\u52A8\u753B",
3398
+ order: 130,
3399
+ accent: "#f472b6",
3400
+ 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",
3401
+ css: css2,
3402
+ View: AnimationView,
3403
+ HomeStat: AnimationStat,
3404
+ Overlay: AnimationOverlay
3405
+ };
3406
+
3407
+ // src/client.jsx
3408
+ var DOCK_VERSION = "0.5.0";
3409
+ var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6];
3410
+ var PLANNED_FEATURES = [];
3411
+ var PLANNED_NOTES = {};
1614
3412
  var externalDefs = [];
1615
3413
  var externalListeners = /* @__PURE__ */ new Set();
1616
3414
  function notifyExternal() {
@@ -1633,6 +3431,7 @@ var dockBridge = {
1633
3431
  css: typeof def.css === "string" ? def.css : "",
1634
3432
  View: def.View,
1635
3433
  HomeStat: typeof def.HomeStat === "function" ? def.HomeStat : null,
3434
+ Overlay: typeof def.Overlay === "function" ? def.Overlay : null,
1636
3435
  external: true,
1637
3436
  package: typeof def.package === "string" ? def.package : ""
1638
3437
  };
@@ -1671,9 +3470,13 @@ var SHELL_CSS = [
1671
3470
  ".dock-badge{flex:none;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:3px 10px;font-size:12px;}",
1672
3471
  ".dock-body{border-top:1px solid var(--dsw-alias-border-l1);padding-top:8px;color:var(--dsw-alias-label-secondary);display:flex;flex-direction:column;gap:4px;}",
1673
3472
  // 侧栏入口按钮(docke2- 前缀)+ 功能坞弹出面板(dockm- 前缀,仿 dsh 设置的居中模态:遮罩 + 对话框,左导航 + 右内容)
1674
- ".docke2-btn{box-sizing:border-box;cursor:pointer;display:inline-flex;align-items:center;gap:6px;border:none;background:transparent;color:var(--dsw-alias-label-secondary);border-radius:10px;height:32px;font-family:inherit;font-size:13px;line-height:32px;transition:background .15s var(--ds-ease-in-out),color .15s var(--ds-ease-in-out);}",
1675
- ".docke2-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
3473
+ // 侧栏入口按钮(docke2- 前缀):与 dsh 设置按钮(.VOzbGW_trigger)几何逐条对齐——
3474
+ // 宽栏同为整宽左对齐行按钮(高 42、margin 4/-2、padding 0 10px 0 8px、圆角 12),窄栏同为 36 圆钮居中,
3475
+ // 使两按钮上下成列、左右边缘完全对齐(此前右对齐/叠放都会错位)。
3476
+ ".docke2-btn{box-sizing:border-box;cursor:pointer;display:flex;align-items:center;gap:8px;border:none;background:transparent;color:var(--dsw-alias-label-primary);border-radius:12px;width:calc(100% + 4px);height:42px;margin:4px -2px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;transition:background .15s var(--ds-ease-in-out),color .15s var(--ds-ease-in-out);}",
3477
+ ".docke2-btn:hover{background:var(--dsw-alias-interactive-bg-hover);}",
1676
3478
  ".docke2-btn.docke2-on{color:var(--dsw-alias-accent,#4d9fff);background:var(--dsw-alias-accent-soft,color-mix(in srgb,var(--dsw-alias-accent,#4d9fff) 12%,transparent));}",
3479
+ ".docke2-btn.docke2-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;border-radius:50%;justify-content:center;gap:0;}",
1677
3480
  ".docke2-label{white-space:nowrap;overflow:hidden;}",
1678
3481
  ".dockm-backdrop{position:fixed;inset:0;z-index:80;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--dsw-alias-bg-layer-1) 55%,transparent);backdrop-filter:blur(4px);pointer-events:auto;animation:dockm-fade .15s var(--ds-ease-in-out);}",
1679
3482
  "@keyframes dockm-fade{from{opacity:0}to{opacity:1}}",
@@ -1717,16 +3520,36 @@ var SHELL_CSS = [
1717
3520
  ".dockh-card:hover,.dockh-card:focus-visible{border-color:var(--dsw-alias-accent,#4d9fff);outline:none;}",
1718
3521
  ".dockh-head{display:flex;align-items:center;gap:8px;}",
1719
3522
  ".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;}",
3523
+ ".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);}",
3524
+ // 状态标识(非交互:圆点+文字,与可点的开关一眼区分)
3525
+ ".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;}",
3526
+ ".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);}",
3527
+ ".dockh-status.off .dockh-sdot{background:transparent;border:1.5px solid var(--dsw-alias-label-tertiary);box-shadow:none;opacity:.75;}",
3528
+ ".dockh-status.plan .dockh-sdot{background:transparent;border:1.5px dashed var(--dsw-alias-label-tertiary);box-shadow:none;}",
3529
+ // iOS 风滑动开关(首页卡片 / 弹层页脚 / 设置页共用的启停控件)
3530
+ ".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);}",
3531
+ '.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);}',
3532
+ ".dock-sw:hover{border-color:var(--dsw-alias-accent,#4d9fff);}",
3533
+ ".dock-sw.on{background:var(--dsw-alias-state-success-primary,#34d399);border-color:transparent;}",
3534
+ ".dock-sw.on::after{transform:translateX(15px);}",
3535
+ // 弹层页脚:文字标签 + 开关 成组
3536
+ ".dockm-foot-sw{margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:8px;}",
3537
+ ".dockm-foot-swlabel{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
3538
+ ".dockm-foot-swlabel.on{color:var(--dsw-alias-state-success-primary);}",
1723
3539
  ".dockh-desc{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5;}",
1724
3540
  ".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
3541
  ".dockh-foot{display:flex;align-items:center;gap:8px;}",
1726
3542
  ".dockh-go{color:var(--dsw-alias-label-tertiary);font-size:11px;}",
1727
3543
  // 会话输入区工具行 chips(dockchip- 前缀):余额/用量随身小控件,挂在模型选择器左侧
1728
- ".dockchip-row{display:inline-flex;align-items:center;gap:4px;min-width:0;}",
1729
- ".dockchip{display:inline-flex;align-items:center;gap:5px;cursor:pointer;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:8px;padding:2px 8px;font-family:inherit;font-size:11px;line-height:18px;white-space:nowrap;transition:background .15s var(--ds-ease-in-out),color .15s var(--ds-ease-in-out);}",
3544
+ // 溢出兼容(两层防护,缺一不可):
3545
+ // 1) 宽度上限:宿主 .row 是 flex-wrap:wrap 且换行优先于收缩,chips 一长 tools 整行变宽,
3546
+ // 右侧模型选择器/发送键被挤到第二行(左右错位)。宿主 .row 带 container-type:inline-size,
3547
+ // 用容器单位 cqw 让上限随输入卡宽度自适应(窄卡少占、宽卡多占);不支持 cqw 的老内核退回固定 280px。
3548
+ // 2) 截断:超限部分用省略号截断(完整数值在 title 悬浮提示里),防 chips 凸出输入卡圆角(悬空)。
3549
+ ".dockchip-row{display:inline-flex;align-items:center;gap:4px;min-width:0;flex:0 1 auto;overflow:hidden;max-width:280px;}",
3550
+ "@supports (width:1cqw){.dockchip-row{max-width:min(280px,36cqw);}}",
3551
+ ".dockchip{display:inline-flex;align-items:center;gap:5px;cursor:pointer;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:8px;padding:2px 8px;font-family:inherit;font-size:11px;line-height:18px;white-space:nowrap;min-width:0;overflow:hidden;transition:background .15s var(--ds-ease-in-out),color .15s var(--ds-ease-in-out);}",
3552
+ ".dockchip > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}",
1730
3553
  ".dockchip:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
1731
3554
  ".dockchip .dockchip-dot{width:6px;height:6px;border-radius:50%;flex:none;}",
1732
3555
  ".dockchip.err{color:var(--dsw-alias-state-error-primary);}"
@@ -1756,8 +3579,8 @@ function ensureCss() {
1756
3579
  }
1757
3580
  }
1758
3581
  function useExternalVersion() {
1759
- const [, bump] = import_react7.default.useReducer((n) => n + 1, 0);
1760
- import_react7.default.useEffect(() => {
3582
+ const [, bump] = import_react9.default.useReducer((n) => n + 1, 0);
3583
+ import_react9.default.useEffect(() => {
1761
3584
  externalListeners.add(bump);
1762
3585
  return () => {
1763
3586
  externalListeners.delete(bump);
@@ -1765,42 +3588,42 @@ function useExternalVersion() {
1765
3588
  }, []);
1766
3589
  }
1767
3590
  var lastGeom = { x: null, y: null, w: null, h: null };
1768
- function DockIcon() {
1769
- return import_react7.default.createElement(
3591
+ function DockIcon(props) {
3592
+ const size = props && props.size || 16;
3593
+ return import_react9.default.createElement(
1770
3594
  "svg",
1771
- { 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 })
3595
+ { width: size, height: size, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.3, "aria-hidden": true },
3596
+ import_react9.default.createElement("rect", { x: 2.5, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
3597
+ import_react9.default.createElement("rect", { x: 9, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
3598
+ import_react9.default.createElement("rect", { x: 2.5, y: 9, width: 4.4, height: 4.4, rx: 1.2 }),
3599
+ import_react9.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
1776
3600
  );
1777
3601
  }
1778
3602
  function DockEntry(props) {
1779
3603
  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", {
3604
+ const [open, setOpen] = import_react9.default.useState(panelNav.open);
3605
+ import_react9.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
3606
+ return import_react9.default.createElement("button", {
1783
3607
  type: "button",
1784
- className: "docke2-btn" + (open ? " docke2-on" : ""),
1785
- 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 },
3608
+ className: "docke2-btn" + (open ? " docke2-on" : "") + (wide ? "" : " docke2-rail"),
1786
3609
  title: "\u529F\u80FD\u575E",
1787
3610
  "aria-label": "\u529F\u80FD\u575E",
1788
3611
  "aria-expanded": open,
1789
3612
  onClick: () => setPanelOpen(!open)
1790
- }, import_react7.default.createElement(DockIcon, null), wide ? import_react7.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
3613
+ }, import_react9.default.createElement(DockIcon, { size: wide ? 16 : 18 }), wide ? import_react9.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
1791
3614
  }
1792
3615
  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 })), []);
3616
+ const [nav, setNav] = import_react9.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
3617
+ import_react9.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
1795
3618
  const open = nav.open || typeof document === "undefined";
1796
3619
  const active = nav.active;
1797
3620
  const setActive = navigatePanel;
1798
3621
  const navParams = nav.params;
1799
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
3622
+ const [, force] = import_react9.default.useReducer((n) => n + 1, 0);
1800
3623
  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(() => {
3624
+ const [win, setWin] = import_react9.default.useState(() => ({ mode: "normal", x: null, y: null, w: null, h: null }));
3625
+ const dlgRef = import_react9.default.useRef(null);
3626
+ import_react9.default.useEffect(() => {
1804
3627
  if (lastGeom.w) setWin({ mode: "normal", x: lastGeom.x, y: lastGeom.y, w: lastGeom.w, h: lastGeom.h });
1805
3628
  }, []);
1806
3629
  function beginDrag(e, type) {
@@ -1838,13 +3661,13 @@ function DockModal() {
1838
3661
  const mod = isHome ? null : MODULES.find((m) => m.id === active) || MODULES[0];
1839
3662
  const st = mod ? stateOf(mod.id) : null;
1840
3663
  const View = mod ? mod.View : null;
1841
- const viewNode = mod && View ? import_react7.default.createElement(
3664
+ const viewNode = mod && View ? import_react9.default.createElement(
1842
3665
  "div",
1843
3666
  { className: "dockm-view" },
1844
- import_react7.default.createElement(
1845
- mod.external ? FeatureBoundary : import_react7.default.Fragment,
3667
+ import_react9.default.createElement(
3668
+ mod.external ? FeatureBoundary : import_react9.default.Fragment,
1846
3669
  null,
1847
- import_react7.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
3670
+ import_react9.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
1848
3671
  )
1849
3672
  ) : null;
1850
3673
  const enabledCount = MODULES.filter((m) => {
@@ -1858,10 +3681,10 @@ function DockModal() {
1858
3681
  width: win.w != null ? win.w : void 0,
1859
3682
  height: win.mode === "min" ? "auto" : win.h != null ? win.h : void 0
1860
3683
  } : null;
1861
- return import_react7.default.createElement(
3684
+ return import_react9.default.createElement(
1862
3685
  "div",
1863
3686
  { className: "dockm-backdrop", onClick: () => setPanelOpen(false) },
1864
- import_react7.default.createElement(
3687
+ import_react9.default.createElement(
1865
3688
  "div",
1866
3689
  {
1867
3690
  className: "dockm-dialog" + (win.mode === "max" ? " dockm-max" : "") + (win.mode === "min" ? " dockm-min" : ""),
@@ -1869,41 +3692,41 @@ function DockModal() {
1869
3692
  ref: dlgRef,
1870
3693
  onClick: (e) => e.stopPropagation()
1871
3694
  },
1872
- import_react7.default.createElement(
3695
+ import_react9.default.createElement(
1873
3696
  "div",
1874
3697
  {
1875
3698
  className: "dockm-head",
1876
3699
  onPointerDown: (e) => beginDrag(e, "move"),
1877
3700
  onDoubleClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
1878
3701
  },
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(
3702
+ import_react9.default.createElement(DockIcon, null),
3703
+ import_react9.default.createElement("span", { className: "dockm-title" }, "\u529F\u80FD\u575E"),
3704
+ import_react9.default.createElement("span", { className: "dockm-sub" }, "dsh-dock \xB7 \u4E5F\u53EF\u5728 \u8BBE\u7F6E \u2192 \u529F\u80FD\u575E \u6253\u5F00\u7BA1\u7406\u9875"),
3705
+ import_react9.default.createElement(
1883
3706
  "span",
1884
3707
  { className: "dockm-ctrls" },
1885
- import_react7.default.createElement("button", {
3708
+ import_react9.default.createElement("button", {
1886
3709
  type: "button",
1887
3710
  className: "dockm-win",
1888
3711
  title: win.mode === "min" ? "\u8FD8\u539F" : "\u6700\u5C0F\u5316",
1889
3712
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "min" ? "normal" : "min" }))
1890
3713
  }, "\u2581"),
1891
- import_react7.default.createElement("button", {
3714
+ import_react9.default.createElement("button", {
1892
3715
  type: "button",
1893
3716
  className: "dockm-win",
1894
3717
  title: win.mode === "max" ? "\u8FD8\u539F" : "\u6700\u5927\u5316",
1895
3718
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
1896
3719
  }, 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")
3720
+ import_react9.default.createElement("button", { type: "button", className: "dockm-close", "aria-label": "\u5173\u95ED", title: "\u5173\u95ED", onClick: () => setPanelOpen(false) }, "\u2715")
1898
3721
  )
1899
3722
  ),
1900
- import_react7.default.createElement(
3723
+ import_react9.default.createElement(
1901
3724
  "div",
1902
3725
  { className: "dockm-body" },
1903
- import_react7.default.createElement(
3726
+ import_react9.default.createElement(
1904
3727
  "nav",
1905
3728
  { className: "dockm-nav", "aria-label": "\u529F\u80FD\u6A21\u5757" },
1906
- import_react7.default.createElement(
3729
+ import_react9.default.createElement(
1907
3730
  "button",
1908
3731
  {
1909
3732
  type: "button",
@@ -1911,10 +3734,10 @@ function DockModal() {
1911
3734
  className: "dockm-nav-item" + (isHome ? " on" : ""),
1912
3735
  onClick: () => setActive("home")
1913
3736
  },
1914
- import_react7.default.createElement("span", { className: "dockm-navhome" }, import_react7.default.createElement(DockIcon, null)),
1915
- import_react7.default.createElement("span", null, "\u9996\u9875")
3737
+ import_react9.default.createElement("span", { className: "dockm-navhome" }, import_react9.default.createElement(DockIcon, null)),
3738
+ import_react9.default.createElement("span", null, "\u9996\u9875")
1916
3739
  ),
1917
- MODULES.map((m) => import_react7.default.createElement(
3740
+ MODULES.map((m) => import_react9.default.createElement(
1918
3741
  "button",
1919
3742
  {
1920
3743
  type: "button",
@@ -1922,81 +3745,98 @@ function DockModal() {
1922
3745
  className: "dockm-nav-item" + (m.id === active ? " on" : ""),
1923
3746
  onClick: () => setActive(m.id)
1924
3747
  },
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
3748
+ import_react9.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
3749
+ import_react9.default.createElement("span", null, m.name),
3750
+ m.planned ? import_react9.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
3751
+ m.external ? import_react9.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8") : null
1929
3752
  ))
1930
3753
  ),
1931
- import_react7.default.createElement(
3754
+ import_react9.default.createElement(
1932
3755
  "div",
1933
3756
  { className: "dockm-content" },
1934
- import_react7.default.createElement(
3757
+ import_react9.default.createElement(
1935
3758
  "div",
1936
3759
  { className: "dockm-content-head" },
1937
- import_react7.default.createElement(
3760
+ import_react9.default.createElement(
1938
3761
  "div",
1939
3762
  { 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 } }),
3763
+ isHome ? import_react9.default.createElement("span", { className: "dockm-navhome" }, import_react9.default.createElement(DockIcon, null)) : import_react9.default.createElement("span", { className: "dockm-dot", style: { background: mod.accent } }),
1941
3764
  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
3765
+ !isHome && mod.planned ? import_react9.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
3766
+ !isHome && mod.external ? import_react9.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8\u5305" + (mod.package ? " \xB7 " + mod.package : "")) : null
1944
3767
  ),
1945
- import_react7.default.createElement(
3768
+ import_react9.default.createElement(
1946
3769
  "div",
1947
3770
  { className: "dockm-desc" },
1948
3771
  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
3772
  )
1950
3773
  ),
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(
3774
+ isHome ? import_react9.default.createElement("div", { className: "dockm-view" }, import_react9.default.createElement(HomeView, { ctx: ctxRef.current, onOpen: setActive, onToggle: force })) : mod.planned ? import_react9.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_react9.default.createElement("div", { className: "dockm-note dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : import_react9.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"),
3775
+ import_react9.default.createElement(
1953
3776
  "div",
1954
3777
  { 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
3778
+ import_react9.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"),
3779
+ !isHome && mod && !mod.planned && st ? import_react9.default.createElement(
3780
+ "span",
3781
+ { className: "dockm-foot-sw" },
3782
+ import_react9.default.createElement("span", { className: "dockm-foot-swlabel" + (st.enabled ? " on" : "") }, st.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
3783
+ import_react9.default.createElement("button", {
3784
+ type: "button",
3785
+ className: "dock-sw" + (st.enabled ? " on" : ""),
3786
+ role: "switch",
3787
+ "aria-checked": !!st.enabled,
3788
+ "aria-label": (st.enabled ? "\u505C\u7528" : "\u542F\u7528") + mod.name,
3789
+ title: st.enabled ? "\u505C\u7528\u300C" + mod.name + "\u300D" : "\u542F\u7528\u300C" + mod.name + "\u300D",
3790
+ onClick: () => {
3791
+ toggleFeature(mod.id);
3792
+ force();
3793
+ }
3794
+ })
3795
+ ) : null,
3796
+ !isHome && mod && typeof mod.Chip === "function" ? import_react9.default.createElement(
3797
+ "span",
3798
+ { className: "dockm-foot-sw" },
3799
+ import_react9.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(mod.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
3800
+ import_react9.default.createElement("button", {
3801
+ type: "button",
3802
+ className: "dock-sw" + (chipShown(mod.id) ? " on" : ""),
3803
+ role: "switch",
3804
+ "aria-checked": chipShown(mod.id),
3805
+ "aria-label": (chipShown(mod.id) ? "\u9690\u85CF" : "\u663E\u793A") + mod.name + "\u7684\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6",
3806
+ 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",
3807
+ onClick: () => {
3808
+ setChipShown(mod.id, !chipShown(mod.id));
3809
+ force();
3810
+ }
3811
+ })
3812
+ ) : null
1973
3813
  )
1974
3814
  )
1975
3815
  ),
1976
- win.mode === "normal" ? import_react7.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
3816
+ win.mode === "normal" ? import_react9.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
1977
3817
  )
1978
3818
  );
1979
3819
  }
1980
3820
  function HomeView(props) {
1981
3821
  const ctx = props && props.ctx;
1982
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
3822
+ const [, force] = import_react9.default.useReducer((n) => n + 1, 0);
1983
3823
  useExternalVersion();
1984
3824
  const open = (id) => {
1985
3825
  if (props && typeof props.onOpen === "function") props.onOpen(id);
1986
3826
  };
1987
- return import_react7.default.createElement(
3827
+ return import_react9.default.createElement(
1988
3828
  "div",
1989
3829
  { className: "dockh-grid" },
1990
3830
  allModules().map((m) => {
1991
3831
  const st = stateOf(m.id);
1992
3832
  const enabled = !!(st && st.enabled);
1993
3833
  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,
3834
+ const statNode = m.planned ? import_react9.default.createElement("span", null, PLANNED_NOTES[m.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : enabled && Stat ? import_react9.default.createElement(
3835
+ m.external ? FeatureBoundary : import_react9.default.Fragment,
1996
3836
  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(
3837
+ import_react9.default.createElement(Stat, { ctx })
3838
+ ) : import_react9.default.createElement("span", null, "\u5DF2\u505C\u7528\uFF0C\u542F\u7528\u540E\u5728\u6B64\u5C55\u793A\u8FD0\u884C\u6982\u8981");
3839
+ return import_react9.default.createElement(
2000
3840
  "div",
2001
3841
  {
2002
3842
  key: m.id,
@@ -2011,34 +3851,41 @@ function HomeView(props) {
2011
3851
  }
2012
3852
  }
2013
3853
  },
2014
- import_react7.default.createElement(
3854
+ import_react9.default.createElement(
2015
3855
  "div",
2016
3856
  { 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(
3857
+ import_react9.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
3858
+ import_react9.default.createElement("span", { className: "dockh-name" }, m.name),
3859
+ m.external ? import_react9.default.createElement("span", { className: "dockh-badge", title: m.package || void 0 }, "\u5916\u90E8") : null,
3860
+ // 状态标识:圆点 + 文字(纯展示,与开关视觉区分)
3861
+ import_react9.default.createElement(
2021
3862
  "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", {
3863
+ { className: "dockh-status" + (m.planned ? " plan" : enabled ? "" : " off") },
3864
+ import_react9.default.createElement("span", { className: "dockh-sdot" }),
3865
+ import_react9.default.createElement("span", null, m.planned ? "\u89C4\u5212\u4E2D" : enabled ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u505C\u7528")
3866
+ ),
3867
+ // 启停开关(规划中的功能不显示)
3868
+ m.planned ? null : import_react9.default.createElement("button", {
2033
3869
  type: "button",
2034
- className: "dockm-switch" + (enabled ? " on" : ""),
3870
+ className: "dock-sw" + (enabled ? " on" : ""),
3871
+ role: "switch",
3872
+ "aria-checked": enabled,
3873
+ "aria-label": (enabled ? "\u505C\u7528" : "\u542F\u7528") + m.name,
3874
+ title: enabled ? "\u505C\u7528\u300C" + m.name + "\u300D" : "\u542F\u7528\u300C" + m.name + "\u300D",
2035
3875
  onClick: (e) => {
2036
3876
  e.stopPropagation();
2037
3877
  toggleFeature(m.id);
2038
3878
  if (props && typeof props.onToggle === "function") props.onToggle();
2039
3879
  force();
2040
3880
  }
2041
- }, enabled ? "\u505C\u7528" : "\u542F\u7528")
3881
+ })
3882
+ ),
3883
+ import_react9.default.createElement("div", { className: "dockh-desc" }, m.description),
3884
+ import_react9.default.createElement("div", { className: "dockh-stat" }, statNode),
3885
+ import_react9.default.createElement(
3886
+ "div",
3887
+ { className: "dockh-foot" },
3888
+ import_react9.default.createElement("span", { className: "dockh-go" }, "\u67E5\u770B\u8BE6\u60C5 \u2192")
2042
3889
  )
2043
3890
  );
2044
3891
  })
@@ -2046,16 +3893,16 @@ function HomeView(props) {
2046
3893
  }
2047
3894
  function DockPanel() {
2048
3895
  const ctx = ctxRef.current;
2049
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
3896
+ const [, force] = import_react9.default.useReducer((n) => n + 1, 0);
2050
3897
  useExternalVersion();
2051
3898
  const toggle = (id) => {
2052
3899
  toggleFeature(id);
2053
3900
  force();
2054
3901
  };
2055
- return import_react7.default.createElement(
3902
+ return import_react9.default.createElement(
2056
3903
  "div",
2057
3904
  { className: "dock-root" },
2058
- import_react7.default.createElement(
3905
+ import_react9.default.createElement(
2059
3906
  "div",
2060
3907
  { className: "dock-intro" },
2061
3908
  "\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 +3911,64 @@ function DockPanel() {
2064
3911
  allModules().map((f) => {
2065
3912
  const st = stateOf(f.id);
2066
3913
  const View = f.View;
2067
- const viewNode = !f.planned && st.enabled && View ? import_react7.default.createElement(
3914
+ const viewNode = !f.planned && st.enabled && View ? import_react9.default.createElement(
2068
3915
  "div",
2069
3916
  { className: "dock-body" },
2070
- import_react7.default.createElement(
2071
- f.external ? FeatureBoundary : import_react7.default.Fragment,
3917
+ import_react9.default.createElement(
3918
+ f.external ? FeatureBoundary : import_react9.default.Fragment,
2072
3919
  null,
2073
- import_react7.default.createElement(View, { ctx, feature: f })
3920
+ import_react9.default.createElement(View, { ctx, feature: f })
2074
3921
  )
2075
3922
  ) : null;
2076
- return import_react7.default.createElement(
3923
+ return import_react9.default.createElement(
2077
3924
  "div",
2078
3925
  { className: "dock-card", key: f.id },
2079
- import_react7.default.createElement(
3926
+ import_react9.default.createElement(
2080
3927
  "div",
2081
3928
  { 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" : ""),
3929
+ import_react9.default.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
3930
+ import_react9.default.createElement("span", { className: "dock-name" }, f.name),
3931
+ import_react9.default.createElement("span", { className: "dock-desc" }, f.description + (f.external ? "\uFF08\u6765\u81EA\u5916\u90E8\u5305" + (f.package ? " " + f.package : "") + "\uFF09" : "")),
3932
+ f.planned ? import_react9.default.createElement("span", { className: "dock-badge" }, "\u89C4\u5212\u4E2D") : import_react9.default.createElement("button", {
3933
+ type: "button",
3934
+ className: "dock-sw" + (st.enabled ? " on" : ""),
3935
+ role: "switch",
3936
+ "aria-checked": st.enabled,
3937
+ "aria-label": (st.enabled ? "\u505C\u7528" : "\u542F\u7528") + f.name,
3938
+ title: st.enabled ? "\u505C\u7528\u300C" + f.name + "\u300D" : "\u542F\u7528\u300C" + f.name + "\u300D",
2087
3939
  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
3940
+ }),
3941
+ !f.planned && typeof f.Chip === "function" ? import_react9.default.createElement(
3942
+ "span",
3943
+ { className: "dockm-foot-sw" },
3944
+ import_react9.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(f.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
3945
+ import_react9.default.createElement("button", {
3946
+ type: "button",
3947
+ className: "dock-sw" + (chipShown(f.id) ? " on" : ""),
3948
+ role: "switch",
3949
+ "aria-checked": chipShown(f.id),
3950
+ "aria-label": (chipShown(f.id) ? "\u9690\u85CF" : "\u663E\u793A") + f.name + "\u7684\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6",
3951
+ 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",
3952
+ onClick: () => {
3953
+ setChipShown(f.id, !chipShown(f.id));
3954
+ force();
3955
+ }
3956
+ })
3957
+ ) : null
2097
3958
  ),
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,
3959
+ f.planned ? import_react9.default.createElement("div", { className: "dock-body" }, PLANNED_NOTES[f.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st.error ? import_react9.default.createElement("div", { className: "dock-body dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : null,
2099
3960
  viewNode
2100
3961
  );
2101
3962
  })
2102
3963
  );
2103
3964
  }
2104
3965
  function DockChips(props) {
2105
- const [, force] = import_react7.default.useReducer((n) => n + 1, 0);
2106
- import_react7.default.useEffect(() => subscribeFeatureState(() => force()), []);
3966
+ const [, force] = import_react9.default.useReducer((n) => n + 1, 0);
3967
+ import_react9.default.useEffect(() => subscribeFeatureState(() => force()), []);
2107
3968
  const items = [];
2108
3969
  for (const f of allModules()) {
2109
3970
  if (f.planned || !stateOf(f.id).enabled || !chipShown(f.id) || typeof f.Chip !== "function") continue;
2110
- items.push(import_react7.default.createElement(f.Chip, {
3971
+ items.push(import_react9.default.createElement(f.Chip, {
2111
3972
  key: f.id,
2112
3973
  ctx: props.ctx,
2113
3974
  feature: f,
@@ -2117,7 +3978,23 @@ function DockChips(props) {
2117
3978
  }));
2118
3979
  }
2119
3980
  if (items.length === 0) return null;
2120
- return import_react7.default.createElement("div", { className: "dockchip-row" }, items);
3981
+ return import_react9.default.createElement("div", { className: "dockchip-row" }, items);
3982
+ }
3983
+ function FeatureOverlays() {
3984
+ const [, force] = import_react9.default.useReducer((n) => n + 1, 0);
3985
+ useExternalVersion();
3986
+ import_react9.default.useEffect(() => subscribeFeatureState(() => force()), []);
3987
+ const items = [];
3988
+ for (const f of allModules()) {
3989
+ if (f.planned || !stateOf(f.id).enabled || typeof f.Overlay !== "function") continue;
3990
+ items.push(import_react9.default.createElement(
3991
+ FeatureBoundary,
3992
+ { key: f.id },
3993
+ import_react9.default.createElement(f.Overlay, { ctx: ctxRef.current, feature: f })
3994
+ ));
3995
+ }
3996
+ if (items.length === 0) return null;
3997
+ return import_react9.default.createElement(import_react9.default.Fragment, null, items);
2121
3998
  }
2122
3999
  var ctxRef = { current: null };
2123
4000
  function apply(ctx) {
@@ -2128,19 +4005,23 @@ function apply(ctx) {
2128
4005
  if (slots === void 0) return;
2129
4006
  slots.inject("sidebar.footer.action", () => slots.register(
2130
4007
  { name: "sidebar.footer.action", id: "dsh-dock", order: 1, label: "\u529F\u80FD\u575E" },
2131
- (props) => import_react7.default.createElement(DockEntry, props)
4008
+ (props) => import_react9.default.createElement(DockEntry, props)
2132
4009
  ));
2133
4010
  slots.inject("shell.overlay", () => slots.register(
2134
4011
  { name: "shell.overlay", id: "dsh-dock-panel", order: 21, label: "\u529F\u80FD\u575E\u9762\u677F" },
2135
- () => import_react7.default.createElement(DockModal, null)
4012
+ () => import_react9.default.createElement(DockModal, null)
4013
+ ));
4014
+ slots.inject("shell.overlay", () => slots.register(
4015
+ { name: "shell.overlay", id: "dsh-dock-feature-overlays", order: 22, label: "\u529F\u80FD\u575E\u5168\u5C40\u6D6E\u5C42" },
4016
+ () => import_react9.default.createElement(FeatureOverlays, null)
2136
4017
  ));
2137
4018
  slots.inject("settings.section", () => slots.register(
2138
4019
  { name: "settings.section", id: "dsh-dock", order: 90, label: "\u529F\u80FD\u575E" },
2139
- () => import_react7.default.createElement(DockPanel, null)
4020
+ () => import_react9.default.createElement(DockPanel, null)
2140
4021
  ));
2141
4022
  slots.inject("conversation.input.left", () => slots.register(
2142
4023
  { 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 }))
4024
+ (zone) => import_react9.default.createElement(DockChips, Object.assign({}, zone, { ctx: ctxRef.current }))
2144
4025
  ));
2145
4026
  }
2146
4027
  var inject = ["timer"];