dsh-dock 0.19.0 → 0.21.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
@@ -2295,6 +2295,51 @@ function subscribePanel(fn) {
2295
2295
  navListeners.delete(fn);
2296
2296
  };
2297
2297
  }
2298
+ function taskApprovals(task) {
2299
+ return task && Array.isArray(task.approvals) ? task.approvals : [];
2300
+ }
2301
+ function taskQuestions(task) {
2302
+ return task && Array.isArray(task.questions) ? task.questions : [];
2303
+ }
2304
+ function taskWaiting(task) {
2305
+ return taskApprovals(task).length > 0 || taskQuestions(task).length > 0;
2306
+ }
2307
+ function waitingCountOf(active) {
2308
+ return (active || []).reduce((n, t) => n + taskApprovals(t).length + taskQuestions(t).length, 0);
2309
+ }
2310
+ var TASK_STALL_MS = 18e3;
2311
+ var TASK_BUSY_MS = 18e4;
2312
+ function numOf(v) {
2313
+ const n = Number(v);
2314
+ return Number.isFinite(n) && n > 0 ? n : 0;
2315
+ }
2316
+ function taskActivityAt(task) {
2317
+ if (!task) return 0;
2318
+ return Math.max(numOf(task.lastActivityAt), numOf(task.lastMotionAt), numOf(task.phaseAt));
2319
+ }
2320
+ function taskBusy(task, now, capMs) {
2321
+ if (!task) return false;
2322
+ const at = typeof now === "number" ? now : Date.now();
2323
+ const cap = typeof capMs === "number" && capMs > 0 ? capMs : TASK_BUSY_MS;
2324
+ if (task.compacting === true) {
2325
+ const since = numOf(task.compactStartedAt);
2326
+ if (!since || at - since < cap) return true;
2327
+ }
2328
+ if (typeof task.pendingTool === "string" && task.pendingTool) {
2329
+ const since = numOf(task.toolStartedAt);
2330
+ if (!since || at - since < cap) return true;
2331
+ }
2332
+ return false;
2333
+ }
2334
+ function taskStalled(task, now, thresholdMs) {
2335
+ if (!task || taskWaiting(task) || taskBusy(task, now)) return 0;
2336
+ const at = typeof now === "number" ? now : Date.now();
2337
+ const limit = typeof thresholdMs === "number" && thresholdMs > 0 ? thresholdMs : TASK_STALL_MS;
2338
+ const lastAct = taskActivityAt(task);
2339
+ if (!lastAct) return 0;
2340
+ const stalled = at - lastAct;
2341
+ return stalled >= limit ? stalled : 0;
2342
+ }
2298
2343
 
2299
2344
  // features/tokenlog/view.jsx
2300
2345
  var import_react2 = __toESM(require("react"), 1);
@@ -3698,7 +3743,10 @@ function TokenLogChip(props) {
3698
3743
  if (!sid) return null;
3699
3744
  const t = snap.totals;
3700
3745
  const gone = isTokenlogRouteGone();
3701
- const label = gone ? "\u7528\u91CF\xB7\u672A\u542F\u7528" : snap.err && !t ? snap.err.includes("\u91CD\u542F") || snap.err.includes("\u542F\u7528") ? "\u7528\u91CF\xB7\u672A\u542F\u7528" : "\u7528\u91CF\xB7\u5931\u8D25" : t ? "\u26C1 " + fmtCompact(t.totalTokens) + (t.cost > 0 ? " \xB7 " + fmtCostCny(t.cost, snap.rate) : "") : "\u26C1 \u2026";
3746
+ const hasData = !!t && !gone && !(snap.err && !t);
3747
+ const labelIcon = hasData ? "\u26C1 " : "";
3748
+ const labelMain = gone ? "\u7528\u91CF\xB7\u672A\u542F\u7528" : snap.err && !t ? snap.err.includes("\u91CD\u542F") || snap.err.includes("\u542F\u7528") ? "\u7528\u91CF\xB7\u672A\u542F\u7528" : "\u7528\u91CF\xB7\u5931\u8D25" : t ? fmtCompact(t.totalTokens) : "\u2026";
3749
+ const labelExtra = hasData && t.cost > 0 ? " \xB7 " + fmtCostCny(t.cost, snap.rate) : "";
3702
3750
  const title = gone ? routeGoneMessage() + "\n\uFF08\u53EF\u5728\u529F\u80FD\u575E\u91CC\u542F\u7528\u300C\u7528\u91CF\u8BB0\u5F55\u300D\uFF09" : t ? "\u672C\u4F1A\u8BDD " + fmtNum(t.calls) + " \u6B21\u8C03\u7528 \xB7 " + fmtNum(t.totalTokens) + " Token \xB7 " + fmtCostCny(t.cost, snap.rate) + "\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";
3703
3751
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
3704
3752
  "button",
@@ -3710,7 +3758,9 @@ function TokenLogChip(props) {
3710
3758
  onClick: () => openPanel("tokenlog", { sessionId: sid, navAt: Date.now() }),
3711
3759
  children: [
3712
3760
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dockchip-dot", style: { background: gone ? "var(--dsw-alias-label-tertiary,#8b95ab)" : "var(--dk-warn)" } }),
3713
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })
3761
+ labelIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dockchip-ic", children: labelIcon }) : null,
3762
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: labelMain }),
3763
+ labelExtra ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dockchip-x", children: labelExtra }) : null
3714
3764
  ]
3715
3765
  }
3716
3766
  );
@@ -5393,10 +5443,10 @@ function chipBalanceText(p) {
5393
5443
  const b = p && p.balance;
5394
5444
  if (!b) return "\u4F59\u989D \u2026";
5395
5445
  if (b.status !== "ok") {
5396
- if (b.status === "login-required") return "\u4F59\u989D\xB7\u9700\u767B\u5F55";
5397
- if (b.status === "no-credential") return "\u4F59\u989D\xB7\u65E0\u5BC6\u94A5";
5398
- if (b.status === "unsupported") return "\u4F59\u989D\xB7\u4E0D\u652F\u6301";
5399
- return "\u4F59\u989D\xB7\u67E5\u8BE2\u5931\u8D25";
5446
+ if (b.status === "login-required") return "\u4F59\u989D \u9700\u767B\u5F55";
5447
+ if (b.status === "no-credential") return "\u4F59\u989D \u65E0\u5BC6\u94A5";
5448
+ if (b.status === "unsupported") return "\u4F59\u989D \u4E0D\u652F\u6301";
5449
+ return "\u4F59\u989D \u67E5\u8BE2\u5931\u8D25";
5400
5450
  }
5401
5451
  if (b.kind === "quota") {
5402
5452
  const v2 = Number(b.remaining);
@@ -5419,9 +5469,10 @@ function BalanceChip(props) {
5419
5469
  const def = selProvider || (data && data.default ? data.default.provider : null);
5420
5470
  const cur = def ? providers.find((p) => p.id === def) : null;
5421
5471
  const accent = cur ? accentOf(cur.id) : "#64748b";
5422
- const text = snap.error ? "\u4F59\u989D\xB7\u5931\u8D25" : !data ? snap.loading ? "\u4F59\u989D \u2026" : "\u4F59\u989D \u2014" : cur ? chipBalanceText(cur) : "\u4F59\u989D \u2014";
5472
+ const text = snap.error ? "\u4F59\u989D \u5931\u8D25" : !data ? snap.loading ? "\u4F59\u989D \u2026" : "\u4F59\u989D \u2014" : cur ? chipBalanceText(cur) : "\u4F59\u989D \u2014";
5423
5473
  const selModel = sel && (sel.model || sel.selected && sel.selected.model) || null;
5424
5474
  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";
5475
+ const mm = /^(余额 )([\s\S]*)$/.exec(text);
5425
5476
  return import_react8.default.createElement(
5426
5477
  "button",
5427
5478
  {
@@ -5432,7 +5483,8 @@ function BalanceChip(props) {
5432
5483
  onClick: () => openPanel("balance", def ? { provider: def } : null)
5433
5484
  },
5434
5485
  import_react8.default.createElement("span", { className: "dockchip-dot", style: { background: accent } }),
5435
- import_react8.default.createElement("span", null, text)
5486
+ mm ? import_react8.default.createElement("span", { className: "dockchip-pre" }, mm[1]) : null,
5487
+ import_react8.default.createElement("span", null, mm ? mm[2] : text)
5436
5488
  );
5437
5489
  }
5438
5490
  var feature6 = {
@@ -6200,13 +6252,15 @@ function MissionDeparture(props) {
6200
6252
  }
6201
6253
  function ProgrammingStuck(props) {
6202
6254
  const waiting = !!props.waiting;
6255
+ const task = props.task;
6256
+ const label = !waiting ? "\u7F16\u7A0B\u7B49\u5F85\u4E2D" : taskApprovals(task).length > 0 ? "\u7B49\u5F85\u786E\u8BA4" : "\u7B49\u5F85\u56DE\u7B54";
6203
6257
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-space-stuck" + (waiting ? " waiting" : ""), "aria-hidden": "true", children: [
6204
6258
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FreighterHull, { units: 3, empty: true }),
6205
6259
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-stuck-code", children: [
6206
6260
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
6207
6261
  `{ }`
6208
6262
  ] }),
6209
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: waiting ? "\u7B49\u5F85\u786E\u8BA4" : "\u7F16\u7A0B\u7B49\u5F85\u4E2D" }),
6263
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: label }),
6210
6264
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("small", { children: truncate(props.task && props.task.title || "\u5DE5\u5177\u6682\u65E0\u65B0\u54CD\u5E94", 28) })
6211
6265
  ] });
6212
6266
  }
@@ -6359,7 +6413,8 @@ function AnimationOverlay(props) {
6359
6413
  const animOn = !!(cfg && cfg.animationEnabled && active.length > 0);
6360
6414
  const mode = cfg && cfg.effectMode ? cfg.effectMode : "flow";
6361
6415
  const phase = active.length > 0 ? active.reduce((best, x) => !best || (x.phaseAt || 0) > (best.phaseAt || 0) ? x : best, null).phase : "think";
6362
- const waitingTask = active.find((x) => Array.isArray(x.approvals) && x.approvals.length > 0) || null;
6416
+ const waitingTask = active.find((x) => taskWaiting(x)) || null;
6417
+ const waitWord = waitingTask && taskApprovals(waitingTask).length === 0 ? "\u7B49\u5F85\u56DE\u7B54" : "\u7B49\u5F85\u786E\u8BA4";
6363
6418
  const sessionTitleRef = (0, import_react9.useRef)({ at: 0, title: "" });
6364
6419
  const currentTitle = (0, import_react9.useMemo)(() => {
6365
6420
  const c = sessionTitleRef.current;
@@ -6370,7 +6425,7 @@ function AnimationOverlay(props) {
6370
6425
  return c.title;
6371
6426
  }, [snap.status]);
6372
6427
  const onScreenTasks = (0, import_react9.useMemo)(() => active.filter((x) => taskOnScreen(x, currentTitle)), [active, currentTitle]);
6373
- const waitingTaskOnScreen = onScreenTasks.find((x) => Array.isArray(x.approvals) && x.approvals.length > 0) || null;
6428
+ const waitingTaskOnScreen = onScreenTasks.find((x) => taskWaiting(x)) || null;
6374
6429
  useTicker(ctx, animOn);
6375
6430
  const now = Date.now();
6376
6431
  const elapsed = active.length > 0 ? fmtClock(now - Math.min(...active.map((x) => x.startTime || now))) : "";
@@ -6404,7 +6459,7 @@ function AnimationOverlay(props) {
6404
6459
  const spaceModeOn = !!(cfg && cfg.animationEnabled && mode === "space" && !panelOpen);
6405
6460
  const spaceDocks = useSpaceDocks(spaceModeOn);
6406
6461
  const spaceGalaxies = spaceModeOn && spaceDocks ? spaceGalaxyLayout() : null;
6407
- const stuckTask = onScreenTasks.find((task) => task.phase === "code" && now - (task.lastActivityAt || task.phaseAt || now) >= 18e3) || null;
6462
+ const stuckTask = onScreenTasks.find((task) => task.phase === "code" && taskStalled(task, now, 18e3)) || null;
6408
6463
  const robotScaleFromConfig = Math.max(0.85, Math.min(2.2, Number(cfg && cfg.robotScale) || 1.35));
6409
6464
  const speedStyle = { "--dkan-speed": Number(speed).toFixed(2) };
6410
6465
  const saveRobotScale = (0, import_react9.useCallback)((robotScale) => {
@@ -6519,7 +6574,7 @@ function AnimationOverlay(props) {
6519
6574
  ambientOn && mode === "flow" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-line", style: speedStyle, "aria-hidden": "true" }) : null,
6520
6575
  ambientOn && AMBIENT_EFFECT_MODES.has(mode) && (mode !== "space" || spaceGalaxies) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AmbientLayer, { mode, phase, speed: Number(speed).toFixed(2), tasks: active, galaxies: spaceGalaxies }) : null,
6521
6576
  spaceModeOn && spaceDocks && active.length === 0 && deliveries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReadyFreighter, { dock: spaceDocks.ready }) : null,
6522
- spaceModeOn && stuckTask ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ProgrammingStuck, { task: stuckTask, waiting: !!(stuckTask.approvals && stuckTask.approvals.length) }) : null,
6577
+ spaceModeOn && stuckTask ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ProgrammingStuck, { task: stuckTask, waiting: taskWaiting(stuckTask) }) : null,
6523
6578
  !panelOpen ? departures.map((departure) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MissionDeparture, { departure }, departure.id)) : null,
6524
6579
  ambientOn && mode === "orbit" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-orbit", style: speedStyle, "aria-hidden": "true" }) : null,
6525
6580
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BurstLayer, { bursts }),
@@ -6530,7 +6585,7 @@ function AnimationOverlay(props) {
6530
6585
  role: "button",
6531
6586
  tabIndex: 0,
6532
6587
  style: Object.assign({}, botCardStyle, waitingTask ? { "--dkan-phase": "#b45309" } : null),
6533
- title: active.length + " \u4E2A\u4EFB\u52A1 \xB7 " + (waitingTask ? "\u7B49\u5F85\u786E\u8BA4" : phaseLabel(phase)) + " \xB7 \u70B9\u51FB\u67E5\u770B\u4EFB\u52A1\u52A8\u753B\u9875 \xB7 \u53EF\u62D6\u52A8\u5230\u4EFB\u610F\u4F4D\u7F6E",
6588
+ title: active.length + " \u4E2A\u4EFB\u52A1 \xB7 " + (waitingTask ? waitWord : phaseLabel(phase)) + " \xB7 \u70B9\u51FB\u67E5\u770B\u4EFB\u52A1\u52A8\u753B\u9875 \xB7 \u53EF\u62D6\u52A8\u5230\u4EFB\u610F\u4F4D\u7F6E",
6534
6589
  onPointerDown: onBotPointerDown,
6535
6590
  onPointerMove: onBotPointerMove,
6536
6591
  onPointerUp: onBotPointerUp,
@@ -6549,7 +6604,7 @@ function AnimationOverlay(props) {
6549
6604
  " \u4E2A\u4EFB\u52A1",
6550
6605
  elapsed ? " \xB7 " + elapsed : "",
6551
6606
  " \xB7 ",
6552
- waitingTask ? "\u7B49\u5F85\u786E\u8BA4" : phaseLabel(phase)
6607
+ waitingTask ? waitWord : phaseLabel(phase)
6553
6608
  ] }),
6554
6609
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
6555
6610
  "button",
@@ -6581,7 +6636,7 @@ function AnimationOverlay(props) {
6581
6636
  type: "button",
6582
6637
  className: "dkan-badge" + (mode === "breathe" ? " dkan-badge-breathe" : ""),
6583
6638
  style: Object.assign({}, speedStyle, { "--dkan-phase": phaseColor(waitingTask ? "code" : phase) }),
6584
- title: active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D \xB7 " + (waitingTask ? "\u7B49\u5F85\u786E\u8BA4" : phaseLabel(phase)) + " \xB7 \u70B9\u51FB\u67E5\u770B\u4EFB\u52A1\u52A8\u753B\u9875",
6639
+ title: active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D \xB7 " + (waitingTask ? waitWord : phaseLabel(phase)) + " \xB7 \u70B9\u51FB\u67E5\u770B\u4EFB\u52A1\u52A8\u753B\u9875",
6585
6640
  onClick: () => openPanel("animation"),
6586
6641
  children: [
6587
6642
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-dotwrap", children: [
@@ -6594,7 +6649,7 @@ function AnimationOverlay(props) {
6594
6649
  " \u4E2A\u4EFB\u52A1",
6595
6650
  elapsed ? " \xB7 " + elapsed : "",
6596
6651
  " \xB7 ",
6597
- waitingTask ? "\u7B49\u5F85\u786E\u8BA4" : phaseLabel(phase)
6652
+ waitingTask ? waitWord : phaseLabel(phase)
6598
6653
  ] })
6599
6654
  ]
6600
6655
  }
@@ -6776,7 +6831,7 @@ function AnimationView(props) {
6776
6831
  }
6777
6832
  if (saveErr) rows.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note dkan-err", children: saveErr }, "err"));
6778
6833
  rows.push(
6779
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u4EFB\u52A1\u8FD0\u884C\u72B6\u6001\uFF08\u8FDB\u884C\u4E2D\u4EFB\u52A1\u3001\u9636\u6BB5\u3001Token\u3001\u7B49\u5F85\u786E\u8BA4\u4E0E\u6700\u8FD1\u5B8C\u6210\uFF09\u5DF2\u72EC\u7ACB\u6210\u5DE6\u4FA7\u300C\u8FD0\u884C\u72B6\u6001\u300D\u83DC\u5355\uFF1B\u672C\u9875\u53EA\u8D1F\u8D23\u52A8\u6548\u3002" }, "hint")
6834
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note", children: "\u4EFB\u52A1\u8FD0\u884C\u72B6\u6001\uFF08\u8FDB\u884C\u4E2D\u4EFB\u52A1\u3001\u9636\u6BB5\u3001Token\u3001\u7B49\u4EBA\u4ECB\u5165\uFF08\u7B49\u6279\u51C6 / \u7B49\u56DE\u7B54\uFF09\u4E0E\u6700\u8FD1\u5B8C\u6210\uFF09\u5DF2\u72EC\u7ACB\u6210\u5DE6\u4FA7\u300C\u8FD0\u884C\u72B6\u6001\u300D\u83DC\u5355\uFF1B\u672C\u9875\u53EA\u8D1F\u8D23\u52A8\u6548\u3002" }, "hint")
6780
6835
  );
6781
6836
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-root", children: rows });
6782
6837
  }
@@ -7295,6 +7350,174 @@ function utterCtor() {
7295
7350
  function voiceSupported() {
7296
7351
  return synthOf() !== null && utterCtor() !== null;
7297
7352
  }
7353
+ var VOICE_CLIENT_KEY = "dsh-dock/notify/voice-client/v1";
7354
+ function voiceClientEnabled() {
7355
+ try {
7356
+ if (typeof localStorage === "undefined") return true;
7357
+ return localStorage.getItem(VOICE_CLIENT_KEY) !== "0";
7358
+ } catch {
7359
+ return true;
7360
+ }
7361
+ }
7362
+ function setVoiceClientEnabled(on) {
7363
+ try {
7364
+ if (typeof localStorage !== "undefined") localStorage.setItem(VOICE_CLIENT_KEY, on ? "1" : "0");
7365
+ } catch {
7366
+ }
7367
+ }
7368
+ function voiceAllowed(cfg) {
7369
+ return !!cfg && cfg.voiceNotify === true && voiceClientEnabled();
7370
+ }
7371
+ function useVoiceClientEnabled() {
7372
+ const [on, setOn] = (0, import_react10.useState)(() => voiceClientEnabled());
7373
+ (0, import_react10.useEffect)(() => {
7374
+ const sync = () => setOn(voiceClientEnabled());
7375
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") return void 0;
7376
+ window.addEventListener("storage", sync);
7377
+ return () => {
7378
+ if (typeof window.removeEventListener === "function") window.removeEventListener("storage", sync);
7379
+ };
7380
+ }, []);
7381
+ const set = (0, import_react10.useCallback)((next) => {
7382
+ const v = next !== false;
7383
+ setVoiceClientEnabled(v);
7384
+ setOn(v);
7385
+ if (!v) {
7386
+ const s = synthOf();
7387
+ if (s) {
7388
+ try {
7389
+ s.cancel();
7390
+ } catch {
7391
+ }
7392
+ }
7393
+ }
7394
+ }, []);
7395
+ return [on, set];
7396
+ }
7397
+ var CONFIG_SOURCE_KEY = "dsh-dock/notify/config-source/v1";
7398
+ var CLIENT_CONFIG_KEY = "dsh-dock/notify/client-config/v1";
7399
+ var CLIENT_CONFIG_FIELDS = [
7400
+ "notifyOnComplete",
7401
+ "notifyOnError",
7402
+ "notifyOnConfirm",
7403
+ "notifyOnStuck",
7404
+ "notifyCards",
7405
+ "cardMode",
7406
+ "notifyStayMs",
7407
+ "soundNotify",
7408
+ "soundEffect",
7409
+ "systemNotify",
7410
+ "voiceMode",
7411
+ "voiceOnComplete",
7412
+ "voiceOnError",
7413
+ "voiceOnConfirm",
7414
+ "voiceOnStuck",
7415
+ "voiceRate",
7416
+ "voiceVolume",
7417
+ "voiceLang",
7418
+ "voiceURI"
7419
+ ];
7420
+ function notifyConfigSource() {
7421
+ try {
7422
+ if (typeof localStorage === "undefined") return "server";
7423
+ return localStorage.getItem(CONFIG_SOURCE_KEY) === "client" ? "client" : "server";
7424
+ } catch {
7425
+ return "server";
7426
+ }
7427
+ }
7428
+ function setNotifyConfigSource(source) {
7429
+ try {
7430
+ if (typeof localStorage !== "undefined") localStorage.setItem(CONFIG_SOURCE_KEY, source === "client" ? "client" : "server");
7431
+ } catch {
7432
+ }
7433
+ }
7434
+ function readClientNotifyConfig() {
7435
+ try {
7436
+ if (typeof localStorage === "undefined") return null;
7437
+ const raw = localStorage.getItem(CLIENT_CONFIG_KEY);
7438
+ const obj = raw ? JSON.parse(raw) : null;
7439
+ return obj && typeof obj === "object" && !Array.isArray(obj) ? obj : null;
7440
+ } catch {
7441
+ return null;
7442
+ }
7443
+ }
7444
+ function writeClientNotifyConfig(cfg) {
7445
+ try {
7446
+ if (typeof localStorage !== "undefined") localStorage.setItem(CLIENT_CONFIG_KEY, JSON.stringify(cfg || {}));
7447
+ } catch {
7448
+ }
7449
+ }
7450
+ function pickClientConfig(serverCfg) {
7451
+ const src = serverCfg || {};
7452
+ const out = {};
7453
+ for (const key of CLIENT_CONFIG_FIELDS) {
7454
+ if (src[key] !== void 0) out[key] = src[key];
7455
+ }
7456
+ const matrix = {};
7457
+ const m = src.eventMatrix;
7458
+ if (m && typeof m === "object") {
7459
+ for (const [key, value] of Object.entries(m)) {
7460
+ if (typeof value === "boolean" && /^(card|sound|system|voice):/.test(key)) matrix[key] = value;
7461
+ }
7462
+ }
7463
+ out.eventMatrix = matrix;
7464
+ return out;
7465
+ }
7466
+ function mergeClientNotifyConfig(serverCfg, localCfg) {
7467
+ const server = serverCfg || {};
7468
+ const cfg = Object.assign({}, server, localCfg || {});
7469
+ for (const key of ["dingtalkEnabled", "dingtalkWebhook", "feishuEnabled", "feishuWebhook", "pushMode"]) {
7470
+ cfg[key] = server[key];
7471
+ }
7472
+ cfg.voiceNotify = server.voiceNotify === true;
7473
+ const matrix = Object.assign({}, server.eventMatrix || {});
7474
+ const localMatrix = localCfg && localCfg.eventMatrix || {};
7475
+ for (const [key, value] of Object.entries(localMatrix)) {
7476
+ if (typeof value === "boolean" && /^(card|sound|system|voice):/.test(key)) matrix[key] = value;
7477
+ }
7478
+ cfg.eventMatrix = matrix;
7479
+ return cfg;
7480
+ }
7481
+ function effectiveNotifyConfig(serverCfg) {
7482
+ const server = serverCfg || {};
7483
+ if (notifyConfigSource() !== "client") return server;
7484
+ const local = readClientNotifyConfig();
7485
+ if (!local) return server;
7486
+ return mergeClientNotifyConfig(server, local);
7487
+ }
7488
+ function useNotifyConfigSource() {
7489
+ const [source, setSource] = (0, import_react10.useState)(() => notifyConfigSource());
7490
+ const set = (0, import_react10.useCallback)((next) => {
7491
+ const value = next === "client" ? "client" : "server";
7492
+ setNotifyConfigSource(value);
7493
+ setSource(value);
7494
+ }, []);
7495
+ return [source, set];
7496
+ }
7497
+ var EVENT_CONFIG_KEY = {
7498
+ complete: "notifyOnComplete",
7499
+ error: "notifyOnError",
7500
+ confirm: "notifyOnConfirm",
7501
+ stuck: "notifyOnStuck"
7502
+ };
7503
+ var VOICE_EVENT_KEY = {
7504
+ complete: "voiceOnComplete",
7505
+ error: "voiceOnError",
7506
+ confirm: "voiceOnConfirm",
7507
+ stuck: "voiceOnStuck"
7508
+ };
7509
+ function eventEnabled(cfg, channel, event) {
7510
+ const key = channel + ":" + event;
7511
+ const matrix = cfg && cfg.eventMatrix;
7512
+ if (matrix && typeof matrix === "object" && typeof matrix[key] === "boolean") return matrix[key];
7513
+ if (channel === "voice") return !cfg || cfg[VOICE_EVENT_KEY[event]] !== false;
7514
+ return !cfg || cfg[EVENT_CONFIG_KEY[event]] !== false;
7515
+ }
7516
+ function withEventMatrix(cfg, channel, event, on) {
7517
+ const matrix = Object.assign({}, cfg && cfg.eventMatrix || {});
7518
+ matrix[channel + ":" + event] = !!on;
7519
+ return matrix;
7520
+ }
7298
7521
  function localVoices() {
7299
7522
  const s = synthOf();
7300
7523
  if (!s) return [];
@@ -7469,6 +7692,25 @@ function confirmBroadcastText(task, approval, cfg) {
7469
7692
  parts.push("\u6B63\u5728\u7B49\u5F85\u4F60\u6279\u51C6" + (scene ? "\u6267\u884C" + scene : "") + "\uFF0C\u5DE5\u5177\u662F" + tool + "\uFF0C\u8BF7\u56DE\u5230\u4F1A\u8BDD\u5904\u7406\u3002");
7470
7693
  return parts.join("");
7471
7694
  }
7695
+ function questionBroadcastText(task, question, cfg) {
7696
+ const mode = voiceTone(cfg);
7697
+ if (mode === "brief") return "\u4EFB\u52A1\u9700\u8981\u4F60\u56DE\u7B54";
7698
+ const who = task && task.title ? "\u4EFB\u52A1\u300C" + truncate2(task.title, 30) + "\u300D" : "\u4EFB\u52A1";
7699
+ const head = question && question.header || "";
7700
+ const body = question && question.question || "";
7701
+ const what = body ? truncate2(body.replace(/[#*_`>\[\]()!]/g, ""), 40) : "";
7702
+ if (mode === "medium") {
7703
+ const tail = what ? "\uFF1A" + what : head ? "\uFF1A" + head : "";
7704
+ return who + "\u5728\u7B49\u4F60\u56DE\u7B54" + tail + "\u3002";
7705
+ }
7706
+ const parts = [];
7707
+ if (task && task.title) parts.push("\u4EFB\u52A1\uFF1A" + truncate2(task.title, 30) + "\u3002");
7708
+ parts.push(what ? "\u6B63\u5728\u7B49\u4F60\u56DE\u7B54\u95EE\u9898\uFF1A" + what + "\u3002" : "\u6B63\u5728\u7B49\u4F60\u56DE\u7B54\u95EE\u9898\u3002");
7709
+ const count = question && question.count || 0;
7710
+ if (count > 1) parts.push("\u5171 " + count + " \u4E2A\u95EE\u9898\u3002");
7711
+ parts.push("\u8BF7\u56DE\u5230\u4F1A\u8BDD\u9009\u62E9\u7B54\u6848\u3002");
7712
+ return parts.join("");
7713
+ }
7472
7714
  function stuckBroadcastText(task, cfg) {
7473
7715
  const mode = voiceTone(cfg);
7474
7716
  const where = (task && task.isSubtask ? "\u5B50\u4EFB\u52A1" : "\u4E3B\u4EFB\u52A1") + (task && task.title ? "\u300C" + truncate2(task.title, 30) + "\u300D" : "");
@@ -7485,6 +7727,10 @@ function stuckBroadcastText(task, cfg) {
7485
7727
  return parts.join("");
7486
7728
  }
7487
7729
  var STUCK_MS = 18e3;
7730
+ function stuckMsOf(cfg) {
7731
+ const v = cfg && Number(cfg.stuckMs);
7732
+ return Number.isFinite(v) && v > 0 ? v : STUCK_MS;
7733
+ }
7488
7734
  var notifyStore = {
7489
7735
  snap: { status: null, loading: false, error: null },
7490
7736
  listeners: /* @__PURE__ */ new Set(),
@@ -7503,6 +7749,12 @@ var notifyStore = {
7503
7749
  this.emit();
7504
7750
  }
7505
7751
  },
7752
+ // 本机配置/配置来源变化:状态对象换一个浅拷贝,让订阅方(尤其浮层的 effect)重算。
7753
+ touch() {
7754
+ if (!this.snap.status) return;
7755
+ this.snap = Object.assign({}, this.snap, { status: Object.assign({}, this.snap.status) });
7756
+ this.emit();
7757
+ },
7506
7758
  refresh() {
7507
7759
  if (this.snap.loading) return Promise.resolve();
7508
7760
  this.snap = Object.assign({}, this.snap, { loading: true });
@@ -7644,15 +7896,16 @@ function NotifyOverlay(props) {
7644
7896
  const [stackHover, setStackHover] = (0, import_react10.useState)(false);
7645
7897
  const prevActiveRef = (0, import_react10.useRef)(null);
7646
7898
  const remindedApprovalsRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
7899
+ const remindedQuestionsRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
7647
7900
  const toastSeqRef = (0, import_react10.useRef)(0);
7648
7901
  const pushToast = (0, import_react10.useCallback)((toast) => {
7649
7902
  const st = notifyStore.snap.status;
7650
- const cfg = st && st.config;
7903
+ const cfg = st ? effectiveNotifyConfig(st.config) : null;
7651
7904
  if (cfg && cfg.notifyCards === false) return;
7652
7905
  setToasts((prev) => prev.concat([toast]).slice(-12));
7653
7906
  }, []);
7654
7907
  (0, import_react10.useEffect)(() => {
7655
- const cfg = snap.status && snap.status.config;
7908
+ const cfg = snap.status ? effectiveNotifyConfig(snap.status.config) : null;
7656
7909
  if (cfg && cfg.notifyCards === false) setToasts((prev) => prev.length ? [] : prev);
7657
7910
  }, [snap.status]);
7658
7911
  (0, import_react10.useEffect)(() => {
@@ -7684,7 +7937,7 @@ function NotifyOverlay(props) {
7684
7937
  for (const task of prev) {
7685
7938
  if (currIds.has(task.sessionId)) continue;
7686
7939
  const record = (st.recent || []).find((r) => r.sessionId === task.sessionId) || null;
7687
- handleTaskEnd(task, record, st.config || {});
7940
+ handleTaskEnd(task, record, effectiveNotifyConfig(st.config || {}));
7688
7941
  }
7689
7942
  }
7690
7943
  prevActiveRef.current = st.active.slice();
@@ -7692,13 +7945,13 @@ function NotifyOverlay(props) {
7692
7945
  (0, import_react10.useEffect)(() => {
7693
7946
  const st = snap.status;
7694
7947
  if (!st || !st.active) return;
7695
- const cfg = st.config || {};
7948
+ const cfg = effectiveNotifyConfig(st.config || {});
7696
7949
  const activeIds = new Set(st.active.map((x) => x.sessionId));
7697
7950
  for (const [sid, seen] of remindedApprovalsRef.current) {
7698
7951
  if (!activeIds.has(sid)) remindedApprovalsRef.current.delete(sid);
7699
7952
  }
7700
7953
  for (const task of st.active) {
7701
- const approvals = Array.isArray(task.approvals) ? task.approvals : [];
7954
+ const approvals = taskApprovals(task);
7702
7955
  if (approvals.length === 0) continue;
7703
7956
  let seen = remindedApprovalsRef.current.get(task.sessionId);
7704
7957
  if (!seen) {
@@ -7708,10 +7961,10 @@ function NotifyOverlay(props) {
7708
7961
  const fresh = approvals.filter((a) => a && !seen.has(a.id));
7709
7962
  if (fresh.length === 0) continue;
7710
7963
  for (const a of fresh) seen.add(a.id);
7711
- if (cfg.voiceNotify === true && cfg.voiceOnConfirm !== false) {
7964
+ if (voiceAllowed(cfg) && eventEnabled(cfg, "voice", "confirm")) {
7712
7965
  speakVoice(confirmBroadcastText(task, fresh[0], cfg), cfg);
7713
7966
  }
7714
- if (cfg.notifyOnConfirm === false) continue;
7967
+ if (!eventEnabled(cfg, "card", "confirm")) continue;
7715
7968
  const toolName = fresh[0].toolName || "";
7716
7969
  const scene = toolLabel(toolName);
7717
7970
  const tone = cardTone(cfg);
@@ -7737,8 +7990,8 @@ function NotifyOverlay(props) {
7737
7990
  // 下面的对账 effect 据此自动收起卡片(处理完就不该再占着右上角)。
7738
7991
  approvalKeys: fresh.filter((a) => a && a.id).map((a) => task.sessionId + "|" + a.id)
7739
7992
  });
7740
- if (cfg.soundNotify !== false) playAskSound(cfg.soundEffect);
7741
- if (cfg.systemNotify && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
7993
+ if (cfg.soundNotify !== false && eventEnabled(cfg, "sound", "confirm")) playAskSound(cfg.soundEffect);
7994
+ if (cfg.systemNotify && eventEnabled(cfg, "system", "confirm") && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
7742
7995
  try {
7743
7996
  new Notification("dsh \u4EFB\u52A1\u9700\u8981\u786E\u8BA4", {
7744
7997
  body: (task.title || "(\u65E0\u6807\u9898)") + " \xB7 " + (toolName || "\u5DE5\u5177") + " \u7B49\u5F85\u786E\u8BA4",
@@ -7749,19 +8002,74 @@ function NotifyOverlay(props) {
7749
8002
  }
7750
8003
  }
7751
8004
  }, [snap.status]);
8005
+ (0, import_react10.useEffect)(() => {
8006
+ const st = snap.status;
8007
+ if (!st || !st.active) return;
8008
+ const cfg = effectiveNotifyConfig(st.config || {});
8009
+ const activeIds = new Set(st.active.map((x) => x.sessionId));
8010
+ for (const [sid, seen] of remindedQuestionsRef.current) {
8011
+ if (!activeIds.has(sid)) remindedQuestionsRef.current.delete(sid);
8012
+ }
8013
+ for (const task of st.active) {
8014
+ const questions = taskQuestions(task);
8015
+ if (questions.length === 0) continue;
8016
+ let seen = remindedQuestionsRef.current.get(task.sessionId);
8017
+ if (!seen) {
8018
+ seen = /* @__PURE__ */ new Set();
8019
+ remindedQuestionsRef.current.set(task.sessionId, seen);
8020
+ }
8021
+ const fresh = questions.filter((q) => q && q.id && !seen.has(q.id));
8022
+ if (fresh.length === 0) continue;
8023
+ for (const q of fresh) seen.add(q.id);
8024
+ if (voiceAllowed(cfg) && eventEnabled(cfg, "voice", "confirm")) {
8025
+ speakVoice(questionBroadcastText(task, fresh[0], cfg), cfg);
8026
+ }
8027
+ if (!eventEnabled(cfg, "card", "confirm")) continue;
8028
+ const tone = cardTone(cfg);
8029
+ const head = fresh[0].header || "";
8030
+ const body = fresh[0].question || "";
8031
+ const lines = ["\u4EFB\u52A1\uFF1A" + (task.title || "(\u65E0\u6807\u9898)")];
8032
+ if (body) lines.push((head ? head + "\uFF1A" : "\u95EE\u9898\uFF1A") + truncate2(body, 140));
8033
+ else if (head) lines.push("\u95EE\u9898\uFF1A" + head);
8034
+ const count = fresh[0].count || 0;
8035
+ if (count > 1) lines.push(tone === "brief" ? "\u5171 " + count + " \u4E2A\u95EE\u9898" : "\u5171 " + count + " \u4E2A\u95EE\u9898\u7B49\u4F60\u9009\u62E9");
8036
+ if (tone === "detailed") lines.push("\u8BF7\u5728\u4F1A\u8BDD\u91CC\u9009\u597D\u7B54\u6848\u540E\u7EE7\u7EED");
8037
+ pushToast({
8038
+ id: ++toastSeqRef.current,
8039
+ kind: "confirm",
8040
+ title: "\u4EFB\u52A1\u9700\u8981\u4F60\u56DE\u7B54",
8041
+ body: lines.join("\n"),
8042
+ // 点卡片直达该会话去选答案(与需确认卡同哲学:问题没答完卡片就该在)
8043
+ sessionId: task.sessionId || "",
8044
+ sessionTitle: task.title || "",
8045
+ // 与这批提问绑定:回答落地后宿主把它们移出 questions,下面的对账 effect 据此收起
8046
+ questionKeys: fresh.map((q) => task.sessionId + "|" + q.id)
8047
+ });
8048
+ if (cfg.soundNotify !== false && eventEnabled(cfg, "sound", "confirm")) playAskSound(cfg.soundEffect);
8049
+ if (cfg.systemNotify && eventEnabled(cfg, "system", "confirm") && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
8050
+ try {
8051
+ new Notification("dsh \u4EFB\u52A1\u9700\u8981\u4F60\u56DE\u7B54", {
8052
+ body: (task.title || "(\u65E0\u6807\u9898)") + " \xB7 " + (head || "\u6709\u4E00\u95EE\u5728\u7B49\u4F60\u9009\u62E9"),
8053
+ tag: "dsh-dock-question-" + task.sessionId
8054
+ });
8055
+ } catch {
8056
+ }
8057
+ }
8058
+ }
8059
+ }, [snap.status]);
7752
8060
  (0, import_react10.useEffect)(() => {
7753
8061
  const st = snap.status;
7754
8062
  if (!st || !st.active) return;
7755
8063
  const live = /* @__PURE__ */ new Set();
7756
8064
  for (const task of st.active) {
7757
- const approvals = Array.isArray(task.approvals) ? task.approvals : [];
7758
- for (const a of approvals) if (a && a.id) live.add(task.sessionId + "|" + a.id);
8065
+ for (const a of taskApprovals(task)) if (a && a.id) live.add(task.sessionId + "|" + a.id);
8066
+ for (const q of taskQuestions(task)) if (q && q.id) live.add(task.sessionId + "|" + q.id);
7759
8067
  }
7760
8068
  setToasts((prev) => {
7761
8069
  let changed = false;
7762
8070
  const next = prev.map((x) => {
7763
8071
  if (x.kind !== "confirm" || x.closing) return x;
7764
- const keys = Array.isArray(x.approvalKeys) ? x.approvalKeys : [];
8072
+ const keys = [].concat(Array.isArray(x.approvalKeys) ? x.approvalKeys : []).concat(Array.isArray(x.questionKeys) ? x.questionKeys : []);
7765
8073
  if (keys.length === 0 || keys.some((k) => live.has(k))) return x;
7766
8074
  changed = true;
7767
8075
  return Object.assign({}, x, { closing: true });
@@ -7793,7 +8101,7 @@ function NotifyOverlay(props) {
7793
8101
  (0, import_react10.useEffect)(() => {
7794
8102
  const st = snap.status;
7795
8103
  if (!st || !st.active) return;
7796
- const cfg = st.config || {};
8104
+ const cfg = effectiveNotifyConfig(st.config || {});
7797
8105
  const now = st.now || Date.now();
7798
8106
  const activeIds = new Set(st.active.map((x) => x.sessionId));
7799
8107
  for (const sid of Array.from(stuckSeenRef.current.keys())) {
@@ -7804,8 +8112,7 @@ function NotifyOverlay(props) {
7804
8112
  if (t.isSubtask && t.parentSessionId) parentsWaitingOnSubtask.add(t.parentSessionId);
7805
8113
  }
7806
8114
  for (const task of st.active) {
7807
- const approvals = Array.isArray(task.approvals) ? task.approvals : [];
7808
- if (approvals.length > 0) {
8115
+ if (taskWaiting(task)) {
7809
8116
  stuckSeenRef.current.delete(task.sessionId);
7810
8117
  continue;
7811
8118
  }
@@ -7813,16 +8120,16 @@ function NotifyOverlay(props) {
7813
8120
  continue;
7814
8121
  }
7815
8122
  if (parentsWaitingOnSubtask.has(task.sessionId)) continue;
7816
- const lastAct = task.lastActivityAt || task.phaseAt || 0;
7817
- if (!lastAct || now - lastAct < STUCK_MS) continue;
8123
+ const lastAct = taskActivityAt(task);
8124
+ const stuckMs = taskStalled(task, now, stuckMsOf(cfg));
8125
+ if (!stuckMs) continue;
7818
8126
  const prev = stuckSeenRef.current.get(task.sessionId);
7819
8127
  if (prev === lastAct) continue;
7820
8128
  stuckSeenRef.current.set(task.sessionId, lastAct);
7821
- const stuckMs = now - lastAct;
7822
- if (cfg.voiceNotify === true && cfg.voiceOnStuck !== false) {
8129
+ if (voiceAllowed(cfg) && eventEnabled(cfg, "voice", "stuck")) {
7823
8130
  speakVoice(stuckBroadcastText(task, Object.assign({}, cfg, { stuckMs })), cfg);
7824
8131
  }
7825
- if (cfg.notifyOnStuck === false) continue;
8132
+ if (!eventEnabled(cfg, "card", "stuck")) continue;
7826
8133
  const label = task.isSubtask ? "\u5B50\u4EFB\u52A1" : "\u4E3B\u4EFB\u52A1";
7827
8134
  const title = task.title || "(\u65E0\u6807\u9898)";
7828
8135
  const tool = task.lastToolName || "";
@@ -7856,7 +8163,7 @@ function NotifyOverlay(props) {
7856
8163
  const next = prev.map((x) => {
7857
8164
  if (x.kind !== "stuck" || x.closing) return x;
7858
8165
  const task = byId.get(x.sessionId);
7859
- const stillStalled = !!task && (task.lastActivityAt || task.phaseAt || 0) === x.stuckAt && (Array.isArray(task.approvals) ? task.approvals.length : 0) === 0;
8166
+ const stillStalled = !!task && taskActivityAt(task) === x.stuckAt && !taskWaiting(task);
7860
8167
  if (stillStalled) return x;
7861
8168
  changed = true;
7862
8169
  return Object.assign({}, x, { closing: true });
@@ -7868,43 +8175,48 @@ function NotifyOverlay(props) {
7868
8175
  const reason = record && record.endReason || "";
7869
8176
  const success = isSuccessReason2(reason);
7870
8177
  const info = endInfo(reason);
7871
- const wanted = success ? cfg.notifyOnComplete : cfg.notifyOnError;
7872
- if (cfg.voiceNotify === true && (success ? cfg.voiceOnComplete !== false : cfg.voiceOnError !== false)) {
8178
+ const event = success ? "complete" : "error";
8179
+ const cardWanted = eventEnabled(cfg, "card", event);
8180
+ const soundWanted = cfg.soundNotify !== false && eventEnabled(cfg, "sound", event);
8181
+ const systemWanted = !!cfg.systemNotify && eventEnabled(cfg, "system", event);
8182
+ if (voiceAllowed(cfg) && eventEnabled(cfg, "voice", event)) {
7873
8183
  speakVoice(endBroadcastText(success, record, task, cfg), cfg);
7874
8184
  }
7875
- if (wanted === false) return;
7876
8185
  const models = record && record.models && record.models.length ? record.models.join(", ") : task.models && task.models.length ? task.models.join(", ") : "\u672A\u77E5\u6A21\u578B";
7877
8186
  const provider = record && record.provider || task.provider || "";
7878
8187
  const startTs = record && record.startTime || task.startTime;
7879
8188
  const endTs = record && record.endTime || Date.now();
7880
- const tone = cardTone(cfg);
7881
8189
  const durText = fmtDur(record && record.duration || endTs - startTs);
7882
- const lines = ["\u4EFB\u52A1\uFF1A" + (record && record.title || task.title || "(\u65E0\u6807\u9898)")];
7883
- if (tone !== "brief") lines.push("\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""));
7884
- lines.push(tone === "brief" ? "\u8017\u65F6\uFF1A" + durText : "\u8017\u65F6\uFF1A" + durText + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09");
7885
- if (tone === "detailed") {
7886
- lines.push("\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" : ""));
7887
- lines.push("Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens));
7888
- if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate2(record.lastText, 140));
7889
- if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate2(record.errorMessage, 120));
7890
- }
7891
8190
  const title = success ? "\u4EFB\u52A1\u5B8C\u6210" : "\u4EFB\u52A1" + info.label;
7892
- pushToast({
7893
- id: ++toastSeqRef.current,
7894
- kind: success ? "success" : info.cls === "err" ? "error" : "warn",
7895
- title,
7896
- body: lines.join("\n"),
7897
- // 绑定会话:点卡片直达该会话;用户点进这个会话(侧栏选中)也视为
7898
- // 看到了结果,巡检 effect 据此自动收起卡片。没看过就一直挂着。
7899
- // sessionId 是权威标识(跳转/对账都用它),标题只作旧宿主回退。
7900
- sessionId: task.sessionId || "",
7901
- sessionTitle: record && record.title || task.title || ""
7902
- });
7903
- if (cfg.soundNotify !== false) playDoneSound(success, cfg.soundEffect);
7904
- if (cfg.systemNotify && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
8191
+ const showTitle = record && record.title || task.title || "(\u65E0\u6807\u9898)";
8192
+ if (cardWanted) {
8193
+ const tone = cardTone(cfg);
8194
+ const lines = ["\u4EFB\u52A1\uFF1A" + showTitle];
8195
+ if (tone !== "brief") lines.push("\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""));
8196
+ lines.push(tone === "brief" ? "\u8017\u65F6\uFF1A" + durText : "\u8017\u65F6\uFF1A" + durText + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09");
8197
+ if (tone === "detailed") {
8198
+ lines.push("\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" : ""));
8199
+ lines.push("Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens));
8200
+ if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate2(record.lastText, 140));
8201
+ if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate2(record.errorMessage, 120));
8202
+ }
8203
+ pushToast({
8204
+ id: ++toastSeqRef.current,
8205
+ kind: success ? "success" : info.cls === "err" ? "error" : "warn",
8206
+ title,
8207
+ body: lines.join("\n"),
8208
+ // 绑定会话:点卡片直达该会话;用户点进这个会话(侧栏选中)也视为
8209
+ // 看到了结果,巡检 effect 据此自动收起卡片。没看过就一直挂着。
8210
+ // sessionId 是权威标识(跳转/对账都用它),标题只作旧宿主回退。
8211
+ sessionId: task.sessionId || "",
8212
+ sessionTitle: showTitle
8213
+ });
8214
+ }
8215
+ if (soundWanted) playDoneSound(success, cfg.soundEffect);
8216
+ if (systemWanted && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
7905
8217
  try {
7906
8218
  new Notification("dsh " + title, {
7907
- body: (record && record.title || task.title || "(\u65E0\u6807\u9898)") + " \xB7 " + fmtDur(record && record.duration || endTs - startTs),
8219
+ body: showTitle + " \xB7 " + durText,
7908
8220
  tag: "dsh-dock-notify-" + task.sessionId
7909
8221
  });
7910
8222
  } catch {
@@ -7932,10 +8244,115 @@ function NotifyOverlay(props) {
7932
8244
  }
7933
8245
  );
7934
8246
  }
8247
+ var MATRIX_COLUMNS = [
8248
+ { id: "card", label: "\u9875\u5185\u5361\u7247" },
8249
+ { id: "sound", label: "\u63D0\u793A\u97F3" },
8250
+ { id: "system", label: "\u7CFB\u7EDF\u901A\u77E5" },
8251
+ { id: "voice", label: "\u8BED\u97F3\u64AD\u62A5" },
8252
+ { id: "dingtalk", label: "\u9489\u9489" },
8253
+ { id: "feishu", label: "\u98DE\u4E66" }
8254
+ ];
8255
+ var MATRIX_EVENTS = [
8256
+ { id: "complete", label: "\u5B8C\u6210", desc: "\u4EFB\u52A1\u6B63\u5E38\u7ED3\u675F" },
8257
+ { id: "error", label: "\u5F02\u5E38", desc: "\u51FA\u9519 / \u4E2D\u6B62 / \u53D7\u963B / \u8FBE\u4E0A\u9650" },
8258
+ { id: "confirm", label: "\u9700\u786E\u8BA4 / \u9700\u56DE\u7B54", desc: "\u5DE5\u5177\u7B49\u6279\u51C6\u3001\u63D0\u95EE\u7B49\u56DE\u7B54" },
8259
+ { id: "stuck", label: "\u5361\u4F4F", desc: "\u7F16\u7A0B\u9636\u6BB5\u957F\u65F6\u95F4\u65E0\u6D3B\u52A8" }
8260
+ ];
8261
+ var MATRIX_SUPPORT = {
8262
+ card: ["complete", "error", "confirm", "stuck"],
8263
+ sound: ["complete", "error", "confirm"],
8264
+ system: ["complete", "error", "confirm"],
8265
+ voice: ["complete", "error", "confirm", "stuck"],
8266
+ dingtalk: ["complete", "error"],
8267
+ feishu: ["complete", "error"]
8268
+ };
8269
+ var MODE_OPTIONS = [["brief", "\u7B80\u6D01"], ["medium", "\u9002\u4E2D"], ["detailed", "\u8BE6\u7EC6"]];
8270
+ function ModePicker(props) {
8271
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-modes", children: MODE_OPTIONS.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8272
+ "button",
8273
+ {
8274
+ type: "button",
8275
+ className: "dknt-miniswitch" + (props.value === value ? " on" : ""),
8276
+ title: props.title ? props.title + "\uFF08" + label + "\uFF09" : label,
8277
+ onClick: () => props.onChange(value),
8278
+ children: label
8279
+ },
8280
+ value
8281
+ )) });
8282
+ }
8283
+ function channelMasterOn(cfg, channel, voiceClientOn) {
8284
+ if (!cfg) return false;
8285
+ if (channel === "card") return cfg.notifyCards !== false;
8286
+ if (channel === "sound") return cfg.soundNotify !== false;
8287
+ if (channel === "system") return !!cfg.systemNotify;
8288
+ if (channel === "voice") return cfg.voiceNotify === true && voiceClientOn;
8289
+ if (channel === "dingtalk") return !!cfg.dingtalkEnabled;
8290
+ if (channel === "feishu") return !!cfg.feishuEnabled;
8291
+ return false;
8292
+ }
8293
+ function EventMatrix(props) {
8294
+ const { cfg, source, voiceClientOn, patch } = props;
8295
+ const toggle = (channel, event, on) => patch({ eventMatrix: withEventMatrix(cfg, channel, event, on) });
8296
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-matrix-wrap", children: [
8297
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-matrix", children: [
8298
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-matrix-row dknt-matrix-head", children: [
8299
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-matrix-event", children: "\u901A\u77E5\u4E8B\u4EF6" }),
8300
+ MATRIX_COLUMNS.map((column) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-matrix-col" + (channelMasterOn(cfg, column.id, voiceClientOn) ? " on" : ""), children: [
8301
+ column.label,
8302
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("em", { children: channelMasterOn(cfg, column.id, voiceClientOn) ? "\u5F00" : "\u5173" })
8303
+ ] }, column.id))
8304
+ ] }),
8305
+ MATRIX_EVENTS.map((ev) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-matrix-row", children: [
8306
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-matrix-event", children: [
8307
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("b", { children: ev.label }),
8308
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: ev.desc })
8309
+ ] }),
8310
+ MATRIX_COLUMNS.map((column) => {
8311
+ const supported = MATRIX_SUPPORT[column.id].indexOf(ev.id) !== -1;
8312
+ const serverOnly = source === "client" && (column.id === "dingtalk" || column.id === "feishu");
8313
+ if (!supported) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-cell dknt-cell-na", title: "\u8BE5\u6E20\u9053\u4E0D\u652F\u6301\u6B64\u4E8B\u4EF6", children: "\u2014" }, column.id);
8314
+ const on = eventEnabled(cfg, column.id, ev.id);
8315
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8316
+ "button",
8317
+ {
8318
+ type: "button",
8319
+ className: "dknt-cell" + (on ? " on" : "") + (serverOnly ? " disabled" : ""),
8320
+ role: "checkbox",
8321
+ "aria-checked": on,
8322
+ disabled: serverOnly,
8323
+ title: serverOnly ? "\u7FA4\u673A\u5668\u4EBA\u63A8\u9001\u7531\u670D\u52A1\u7AEF\u6267\u884C\uFF0C\u8BF7\u5207\u6362\u5230\u300C\u670D\u52A1\u7AEF\u914D\u7F6E\u300D\u4FEE\u6539" : on ? "\u53D6\u6D88\u8BE5\u4E8B\u4EF6\u901A\u8FC7\u6B64\u6E20\u9053\u63D0\u9192" : "\u8BA9\u8BE5\u4E8B\u4EF6\u901A\u8FC7\u6B64\u6E20\u9053\u63D0\u9192",
8324
+ onClick: () => {
8325
+ if (!serverOnly) toggle(column.id, ev.id, !on);
8326
+ },
8327
+ children: on ? "\u2713" : ""
8328
+ },
8329
+ column.id
8330
+ );
8331
+ })
8332
+ ] }, ev.id))
8333
+ ] }),
8334
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-matrix-legend", children: [
8335
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
8336
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "dknt-dot on" }),
8337
+ " \u5DF2\u52FE\u9009"
8338
+ ] }),
8339
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
8340
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "dknt-dot" }),
8341
+ " \u672A\u52FE\u9009"
8342
+ ] }),
8343
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "\u300C\u2014\u300D= \u8BE5\u6E20\u9053\u4E0D\u652F\u6301\u6B64\u4E8B\u4EF6" }),
8344
+ source === "client" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "\u9489\u9489 / \u98DE\u4E66\u4E3A\u670D\u52A1\u7AEF\u63A8\u9001\uFF0C\u9700\u5207\u56DE\u300C\u670D\u52A1\u7AEF\u914D\u7F6E\u300D\u4FEE\u6539" }) : null
8345
+ ] })
8346
+ ] });
8347
+ }
7935
8348
  function NotifyView(props) {
7936
8349
  const snap = useNotify();
7937
8350
  const voices = useLocalVoices();
7938
- const [cfg, setCfg] = (0, import_react10.useState)(null);
8351
+ const [voiceClientOn, setVoiceClientOn] = useVoiceClientEnabled();
8352
+ const [source, setSource] = useNotifyConfigSource();
8353
+ const [tab, setTab] = (0, import_react10.useState)("events");
8354
+ const [clientCfg, setClientCfg] = (0, import_react10.useState)(() => readClientNotifyConfig());
8355
+ const [serverDraft, setServerDraft] = (0, import_react10.useState)(null);
7939
8356
  const [saveErr, setSaveErr] = (0, import_react10.useState)("");
7940
8357
  const [testing, setTesting] = (0, import_react10.useState)(false);
7941
8358
  const [testState, setTestState] = (0, import_react10.useState)(null);
@@ -7945,21 +8362,36 @@ function NotifyView(props) {
7945
8362
  const pendingSavesRef = (0, import_react10.useRef)(0);
7946
8363
  const editingWebhookRef = (0, import_react10.useRef)(false);
7947
8364
  const editingFeishuRef = (0, import_react10.useRef)(false);
8365
+ const serverCfg = snap.status && snap.status.config;
7948
8366
  (0, import_react10.useEffect)(() => {
7949
- const c = snap.status && snap.status.config;
7950
- if (!c) return;
8367
+ if (!serverCfg) return;
7951
8368
  if (pendingSavesRef.current > 0 || editingWebhookRef.current || editingFeishuRef.current) return;
7952
- if (c !== cfgRef.current) {
7953
- cfgRef.current = c;
7954
- setCfg(Object.assign({}, c));
8369
+ if (serverCfg !== cfgRef.current) {
8370
+ cfgRef.current = serverCfg;
8371
+ setServerDraft(Object.assign({}, serverCfg));
7955
8372
  }
7956
8373
  }, [snap.status]);
8374
+ (0, import_react10.useEffect)(() => {
8375
+ if (source !== "client" || clientCfg || !serverCfg) return;
8376
+ const clone = pickClientConfig(serverCfg);
8377
+ writeClientNotifyConfig(clone);
8378
+ setClientCfg(clone);
8379
+ }, [source, clientCfg, serverCfg]);
7957
8380
  (0, import_react10.useEffect)(() => {
7958
8381
  if (!notifyStore.snap.status) notifyStore.refresh();
7959
8382
  }, []);
8383
+ const cfg = source === "client" ? clientCfg ? mergeClientNotifyConfig(serverCfg, clientCfg) : null : serverDraft || serverCfg;
7960
8384
  const patch = (p) => {
7961
8385
  setSaveErr("");
7962
- setCfg(Object.assign({}, cfg, p));
8386
+ if (source === "client") {
8387
+ const base = clientCfg || (serverCfg ? pickClientConfig(serverCfg) : {});
8388
+ const next = Object.assign({}, base, p);
8389
+ writeClientNotifyConfig(next);
8390
+ setClientCfg(next);
8391
+ notifyStore.touch();
8392
+ return Promise.resolve();
8393
+ }
8394
+ setServerDraft(Object.assign({}, cfg, p));
7963
8395
  pendingSavesRef.current++;
7964
8396
  return rpcCall3("config", p).then((d) => {
7965
8397
  pendingSavesRef.current--;
@@ -7969,6 +8401,22 @@ function NotifyView(props) {
7969
8401
  setSaveErr("\u4FDD\u5B58\u5931\u8D25\uFF1A" + (e && e.message || String(e)));
7970
8402
  });
7971
8403
  };
8404
+ const chooseSource = (next) => {
8405
+ if (next === "client" && !clientCfg && serverCfg) {
8406
+ const clone = pickClientConfig(serverCfg);
8407
+ writeClientNotifyConfig(clone);
8408
+ setClientCfg(clone);
8409
+ }
8410
+ setSource(next);
8411
+ notifyStore.touch();
8412
+ };
8413
+ const copyFromServer = () => {
8414
+ if (!serverCfg) return;
8415
+ const clone = pickClientConfig(serverCfg);
8416
+ writeClientNotifyConfig(clone);
8417
+ setClientCfg(clone);
8418
+ notifyStore.touch();
8419
+ };
7972
8420
  const saveWebhook = async () => {
7973
8421
  if (!editingWebhookRef.current) return;
7974
8422
  const hook = String(cfg.dingtalkWebhook || "").trim();
@@ -7977,7 +8425,7 @@ function NotifyView(props) {
7977
8425
  const c = notifyStore.snap.status && notifyStore.snap.status.config;
7978
8426
  if (c && c !== cfgRef.current) {
7979
8427
  cfgRef.current = c;
7980
- setCfg(Object.assign({}, c));
8428
+ setServerDraft(Object.assign({}, c));
7981
8429
  }
7982
8430
  };
7983
8431
  const saveFeishuWebhook = async () => {
@@ -7988,7 +8436,7 @@ function NotifyView(props) {
7988
8436
  const c = notifyStore.snap.status && notifyStore.snap.status.config;
7989
8437
  if (c && c !== cfgRef.current) {
7990
8438
  cfgRef.current = c;
7991
- setCfg(Object.assign({}, c));
8439
+ setServerDraft(Object.assign({}, c));
7992
8440
  }
7993
8441
  };
7994
8442
  const runDingtalkTest = async () => {
@@ -8002,7 +8450,7 @@ function NotifyView(props) {
8002
8450
  notifyStore.applyConfig(d && d.config);
8003
8451
  editingWebhookRef.current = false;
8004
8452
  cfgRef.current = d && d.config || cfgRef.current;
8005
- setCfg(Object.assign({}, cfg, { dingtalkWebhook: hook }));
8453
+ setServerDraft(Object.assign({}, cfg, { dingtalkWebhook: hook }));
8006
8454
  }
8007
8455
  const r = await rpcCall3("test");
8008
8456
  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" });
@@ -8023,7 +8471,7 @@ function NotifyView(props) {
8023
8471
  notifyStore.applyConfig(d && d.config);
8024
8472
  editingFeishuRef.current = false;
8025
8473
  cfgRef.current = d && d.config || cfgRef.current;
8026
- setCfg(Object.assign({}, cfg, { feishuWebhook: hook }));
8474
+ setServerDraft(Object.assign({}, cfg, { feishuWebhook: hook }));
8027
8475
  }
8028
8476
  const r = await rpcCall3("test", { target: "feishu" });
8029
8477
  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" });
@@ -8054,481 +8502,530 @@ function NotifyView(props) {
8054
8502
  rows.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: snap.error ? "\u72B6\u6001\u4E0D\u53EF\u7528\uFF1A" + snap.error : snap.loading ? "\u6B63\u5728\u62C9\u53D6\u901A\u77E5\u72B6\u6001\u2026" : "\u7B49\u5F85\u901A\u77E5\u72B6\u6001" }, "load"));
8055
8503
  } else {
8056
8504
  rows.push(
8057
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8058
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8059
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u901A\u77E5\u4E8B\u4EF6" }),
8060
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u54EA\u4E9B\u65F6\u523B\u63D0\u9192\u4F60\uFF1B\u4E0E\u3010\u4EFB\u52A1\u52A8\u753B\u3011\u7684\u52A8\u6548\u4E92\u4E0D\u4F9D\u8D56" })
8505
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-source", children: [
8506
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-source-info", children: [
8507
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-source-title", children: "\u914D\u7F6E\u6765\u6E90" }),
8508
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-source-sub", children: source === "server" ? "\u8BBE\u7F6E\u4FDD\u5B58\u5728\u670D\u52A1\u7AEF\uFF0C\u6240\u6709\u6D4F\u89C8\u5668/\u8BBE\u5907\u5171\u4EAB" : "\u8BBE\u7F6E\u53EA\u4FDD\u5B58\u5728\u5F53\u524D\u6D4F\u89C8\u5668\uFF0C\u4E0D\u5F71\u54CD\u5176\u4ED6\u4EBA" })
8061
8509
  ] }),
8062
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8063
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8064
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u9875\u5185\u5361\u7247" }),
8065
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8066
- "button",
8067
- {
8068
- type: "button",
8069
- className: "dknt-miniswitch" + (cfg.notifyCards !== false ? " on" : ""),
8070
- onClick: () => patch({ notifyCards: cfg.notifyCards === false }),
8071
- children: cfg.notifyCards !== false ? "\u5F00" : "\u5173"
8072
- }
8073
- ),
8074
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u53F3\u4FA7\u901A\u77E5\u5361\u7247\u603B\u5F00\u5173\uFF1A\u5173\u95ED\u540E\u4E0B\u9762\u5404\u7C7B\u5361\u7247\uFF08\u5B8C\u6210 / \u5F02\u5E38 / \u9700\u786E\u8BA4 / \u5361\u4F4F\uFF09\u4E00\u5F8B\u4E0D\u5F39\uFF0C\u5DF2\u6302\u7740\u7684\u4E00\u5E76\u6536\u8D77\uFF1B\u8BED\u97F3\u64AD\u62A5\u3001\u63D0\u793A\u97F3\u3001\u7CFB\u7EDF\u901A\u77E5\u3001\u9489\u9489\u98DE\u4E66\u63A8\u9001\u4E0D\u53D7\u5F71\u54CD" })
8075
- ] }),
8076
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8077
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5B8C\u6210\u901A\u77E5" }),
8078
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8079
- "button",
8080
- {
8081
- type: "button",
8082
- className: "dknt-miniswitch" + (cfg.notifyOnComplete ? " on" : ""),
8083
- onClick: () => patch({ notifyOnComplete: !cfg.notifyOnComplete }),
8084
- children: cfg.notifyOnComplete ? "\u5F00" : "\u5173"
8085
- }
8086
- ),
8087
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u4EFB\u52A1\u6B63\u5E38\u5B8C\u6210\u65F6\u901A\u77E5" })
8088
- ] }),
8089
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8090
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5F02\u5E38\u901A\u77E5" }),
8091
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8092
- "button",
8093
- {
8094
- type: "button",
8095
- className: "dknt-miniswitch" + (cfg.notifyOnError ? " on" : ""),
8096
- onClick: () => patch({ notifyOnError: !cfg.notifyOnError }),
8097
- children: cfg.notifyOnError ? "\u5F00" : "\u5173"
8098
- }
8099
- ),
8100
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u51FA\u9519 / \u4E2D\u6B62 / \u8FBE\u8F93\u51FA\u4E0A\u9650\u65F6\u901A\u77E5" })
8101
- ] }),
8102
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8103
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u9700\u786E\u8BA4\u63D0\u9192" }),
8104
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8105
- "button",
8106
- {
8107
- type: "button",
8108
- className: "dknt-miniswitch" + (cfg.notifyOnConfirm !== false ? " on" : ""),
8109
- onClick: () => patch({ notifyOnConfirm: cfg.notifyOnConfirm === false }),
8110
- children: cfg.notifyOnConfirm !== false ? "\u5F00" : "\u5173"
8111
- }
8112
- ),
8113
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u5DE5\u5177\u7B49\u5F85\u4F60\u6279\u51C6\u65F6\u5F39\u5361\u7247\u5E76\u54CD\u786E\u8BA4\u97F3\uFF1B\u5BA1\u6279\u5904\u7406\u5B8C\u81EA\u52A8\u6536\u8D77\uFF0C\u6CA1\u5904\u7406\u5B8C\u5C31\u4E00\u76F4\u663E\u793A\uFF08\u70B9\u5361\u7247\u76F4\u8FBE\u4F1A\u8BDD\uFF09" })
8114
- ] }),
8115
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8116
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u4F4F\u63D0\u9192" }),
8117
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8118
- "button",
8119
- {
8120
- type: "button",
8121
- className: "dknt-miniswitch" + (cfg.notifyOnStuck !== false ? " on" : ""),
8122
- onClick: () => patch({ notifyOnStuck: cfg.notifyOnStuck === false }),
8123
- children: cfg.notifyOnStuck !== false ? "\u5F00" : "\u5173"
8124
- }
8125
- ),
8126
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7F16\u7A0B\u9636\u6BB5 18 \u79D2\u6CA1\u6709\u52A8\u9759\u65F6\u5F39\u5361\u7247\uFF0C\u5199\u660E\u662F\u4E3B\u4EFB\u52A1\u8FD8\u662F\u5B50\u4EFB\u52A1\u3001\u505C\u6EDE\u4E86\u591A\u4E45\u3001\u6700\u540E\u5728\u6267\u884C\u4EC0\u4E48\uFF1B\u6062\u590D\u6D3B\u52A8 / \u4EFB\u52A1\u7ED3\u675F\u81EA\u52A8\u6536\u8D77\uFF0C\u540C\u4E00\u505C\u70B9\u53EA\u5F39\u4E00\u6B21\uFF08\u8BED\u97F3\u64AD\u62A5\u8D70\u300C\u8BED\u97F3\u64AD\u62A5\u300D\u533A\u7684\u5361\u4F4F\u5F00\u5173\uFF0C\u4E92\u4E0D\u5E72\u6270\uFF09" })
8127
- ] })
8128
- ] })
8129
- ] }, "events"),
8130
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8131
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8132
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u63D0\u9192\u65B9\u5F0F" }),
8133
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u9875\u5185\u5361\u7247\u3001\u63D0\u793A\u97F3\u3001\u6D4F\u89C8\u5668\u7CFB\u7EDF\u901A\u77E5\u53EF\u81EA\u7531\u7EC4\u5408" })
8510
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-seg", role: "group", "aria-label": "\u901A\u77E5\u914D\u7F6E\u6765\u6E90", children: [
8511
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8512
+ "button",
8513
+ {
8514
+ type: "button",
8515
+ className: "dknt-seg-btn" + (source === "server" ? " on" : ""),
8516
+ "aria-pressed": source === "server",
8517
+ onClick: () => chooseSource("server"),
8518
+ children: "\u670D\u52A1\u7AEF\u914D\u7F6E"
8519
+ }
8520
+ ),
8521
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8522
+ "button",
8523
+ {
8524
+ type: "button",
8525
+ className: "dknt-seg-btn" + (source === "client" ? " on" : ""),
8526
+ "aria-pressed": source === "client",
8527
+ onClick: () => chooseSource("client"),
8528
+ children: "\u672C\u673A\u914D\u7F6E"
8529
+ }
8530
+ )
8134
8531
  ] }),
8135
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8136
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8137
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u7247\u53E3\u5F84" }),
8138
- [["brief", "\u7B80\u6D01"], ["medium", "\u9002\u4E2D"], ["detailed", "\u8BE6\u7EC6"]].map(([v, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8139
- "button",
8140
- {
8141
- type: "button",
8142
- className: "dknt-miniswitch" + (cardTone(cfg) === v ? " on" : ""),
8143
- style: { marginRight: 6 },
8144
- title: "\u53F3\u4FA7\u901A\u77E5\u5361\u7247\u6B63\u6587\u6309" + label + "\u6863\u663E\u793A",
8145
- onClick: () => patch({ cardMode: v }),
8146
- children: label
8147
- },
8148
- v
8149
- )),
8150
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u53F3\u4FA7\u5361\u7247\u6B63\u6587\u5199\u591A\u5C11\uFF08\u4E0E\u5404\u7C7B\u578B\u5F00\u5173\u3001\u8BED\u97F3\u64AD\u62A5\u4E92\u4E0D\u5F71\u54CD\uFF09\uFF1A\u7B80\u6D01\uFF1D\u4EFB\u52A1\u4E0E\u8017\u65F6 / \u8C01\u5361\u4F4F\uFF1B\u9002\u4E2D\uFF1D\u52A0\u6A21\u578B\u3001\u8D77\u6B62\u65F6\u95F4\u3001\u505C\u6EDE\u65F6\u957F\uFF1B\u8BE6\u7EC6\uFF1D\u5168\u90E8\uFF08\u56DE\u5408\u6B65\u9AA4\u3001Token\u3001\u6458\u8981\u6216\u9519\u8BEF\u3001\u6700\u540E\u52A8\u4F5C\uFF09" })
8532
+ source === "client" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dknt-btn", onClick: copyFromServer, children: "\u4ECE\u670D\u52A1\u7AEF\u590D\u5236" }) : null
8533
+ ] }, "source"),
8534
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-tabs", role: "tablist", "aria-label": "\u4EFB\u52A1\u901A\u77E5\u8BBE\u7F6E", children: [
8535
+ ["events", "\u6309\u4E8B\u4EF6\u63D0\u9192"],
8536
+ ["channels", "\u6309\u6E20\u9053\u8BBE\u7F6E"],
8537
+ ["robots", "\u7FA4\u673A\u5668\u4EBA"]
8538
+ ].map(([id, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8539
+ "button",
8540
+ {
8541
+ type: "button",
8542
+ role: "tab",
8543
+ "aria-selected": tab === id,
8544
+ className: "dknt-tab" + (tab === id ? " on" : ""),
8545
+ onClick: () => setTab(id),
8546
+ children: label
8547
+ },
8548
+ id
8549
+ )) }, "tabs")
8550
+ );
8551
+ if (tab === "events") {
8552
+ rows.push(
8553
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8554
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8555
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u901A\u77E5\u4E8B\u4EF6" }),
8556
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u7EB5\u5411\u662F\u901A\u77E5\u4E8B\u4EF6\u3001\u6A2A\u5411\u662F\u901A\u77E5\u6E20\u9053\uFF1B\u52FE\u9009\u8868\u793A\u300C\u8FD9\u4E2A\u4E8B\u4EF6\u7528\u8FD9\u4E2A\u6E20\u9053\u63D0\u9192\u300D\u3002\u6E20\u9053\u7684\u603B\u5F00\u5173\u548C\u8BE6\u7EC6\u8BBE\u7F6E\u5728\u540C\u9875\u300C\u6309\u6E20\u9053\u8BBE\u7F6E\u300D\u3002" })
8151
8557
  ] }),
8152
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8153
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u7247\u6536\u7EB3" }),
8154
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u6240\u6709\u5361\u7247\u90FD\u4E0D\u8D85\u65F6\u81EA\u52A8\u6D88\u5931\uFF1A\u7ED3\u675F\u5361\u7247\u6CA1\u770B\u8FC7\u5C31\u4E00\u76F4\u6302\u7740\uFF08\u540E\u53F0\u8DD1\u5B8C\u7684\u5207\u56DE\u6765\u4E5F\u5728\uFF09\uFF0C\u70B9\u5361\u7247\u76F4\u8FBE\u5BF9\u5E94\u4F1A\u8BDD\uFF0C\u6216\u70B9\u8FDB\u8BE5\u4F1A\u8BDD\uFF0C\u5361\u7247\u81EA\u52A8\u6536\u8D77\uFF1B\u9700\u786E\u8BA4\u5361\u7247\u6302\u5230\u5BA1\u6279\u5904\u7406\u5B8C\uFF1B\u5361\u4F4F\u5361\u7247\u6302\u5230\u6062\u590D\u6D3B\u52A8\u30023 \u5F20\u53CA\u4EE5\u4E0A\u81EA\u52A8\u53E0\u653E\u6210\u6807\u9898\u6761\uFF0C\u9F20\u6807\u79FB\u4E0A\u53BB\u6574\u4F53\u5C55\u5F00\uFF1B\u8981\u6574\u4F53\u4E0D\u5F39\u770B\u4E0A\u9762\u300C\u9875\u5185\u5361\u7247\u300D\u603B\u5F00\u5173" })
8558
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(EventMatrix, { cfg, source, voiceClientOn, patch }),
8559
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u300C\u9700\u786E\u8BA4 / \u9700\u56DE\u7B54\u300D\u5305\u542B\u5DE5\u5177\u7B49\u5F85\u6279\u51C6\u4E0E\u4F1A\u8BDD\u63D0\u95EE\u7B49\u5F85\u56DE\u7B54\u4E24\u79CD\u300C\u505C\u5728\u539F\u5730\u7B49\u4EBA\u300D\uFF1B\u300C\u5361\u4F4F\u300D\u53EA\u5728\u7F16\u7A0B\u9636\u6BB5\u957F\u65F6\u95F4\u6CA1\u6709\u52A8\u9759\u65F6\u89E6\u53D1\uFF0C\u7B49\u6279\u51C6\u3001\u7B49\u56DE\u7B54\u3001\u547D\u4EE4\u5728\u8DD1\u3001\u6B63\u5728\u538B\u7F29\u4E0A\u4E0B\u6587\u90FD\u4E0D\u7B97\u5361\u4F4F\u3002" })
8560
+ ] }, "events")
8561
+ );
8562
+ } else if (tab === "channels") {
8563
+ rows.push(
8564
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channels", children: [
8565
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel", children: [
8566
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-head", children: [
8567
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-title-wrap", children: [
8568
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-title", children: "\u9875\u5185\u5361\u7247" }),
8569
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-sub", children: "\u53F3\u4FA7\u6D6E\u5C42\u901A\u77E5\u5361\uFF1B\u70B9\u5361\u7247\u76F4\u8FBE\u5BF9\u5E94\u4F1A\u8BDD" })
8570
+ ] }),
8571
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8572
+ "button",
8573
+ {
8574
+ type: "button",
8575
+ className: "dock-sw" + (cfg.notifyCards !== false ? " on" : ""),
8576
+ role: "switch",
8577
+ "aria-checked": cfg.notifyCards !== false,
8578
+ "aria-label": "\u5F00\u5173\u9875\u5185\u5361\u7247",
8579
+ onClick: () => patch({ notifyCards: cfg.notifyCards === false })
8580
+ }
8581
+ )
8582
+ ] }),
8583
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-body", children: [
8584
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8585
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u6B63\u6587\u53E3\u5F84" }),
8586
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModePicker, { value: cardTone(cfg), title: "\u9875\u5185\u5361\u7247\u6B63\u6587", onChange: (v) => patch({ cardMode: v }) }),
8587
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7B80\u6D01\uFF1D\u4EFB\u52A1\u4E0E\u8017\u65F6 / \u8C01\u5361\u4F4F\uFF1B\u9002\u4E2D\uFF1D\u52A0\u6A21\u578B\u3001\u8D77\u6B62\u65F6\u95F4\u3001\u505C\u6EDE\u65F6\u957F\uFF1B\u8BE6\u7EC6\uFF1D\u5168\u90E8\uFF08\u56DE\u5408\u6B65\u9AA4\u3001Token\u3001\u6458\u8981\u6216\u9519\u8BEF\u3001\u6700\u540E\u52A8\u4F5C\uFF09" })
8588
+ ] }),
8589
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8590
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u7247\u6536\u7EB3" }),
8591
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u6240\u6709\u5361\u7247\u90FD\u4E0D\u8D85\u65F6\u81EA\u52A8\u6D88\u5931\uFF1A\u7ED3\u675F\u5361\u6CA1\u770B\u8FC7\u5C31\u4E00\u76F4\u6302\u7740\uFF0C\u70B9\u5361\u7247\u6216\u70B9\u8FDB\u4F1A\u8BDD\u540E\u6536\u8D77\uFF1B\u9700\u786E\u8BA4\u5361\u6302\u5230\u5904\u7406\u5B8C\uFF1B\u5361\u4F4F\u5361\u6302\u5230\u6062\u590D\u6D3B\u52A8\u30023 \u5F20\u53CA\u4EE5\u4E0A\u81EA\u52A8\u53E0\u653E\u6210\u6807\u9898\u6761\uFF0C\u9F20\u6807\u79FB\u4E0A\u53BB\u6574\u4F53\u5C55\u5F00\u3002" })
8592
+ ] }),
8593
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8594
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u4E8B\u4EF6\u8303\u56F4" }),
8595
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u5728\u300C\u6309\u4E8B\u4EF6\u63D0\u9192\u300D\u7684\u9875\u5185\u5361\u7247\u5217\u91CC\u52FE\u9009\u3002" })
8596
+ ] })
8597
+ ] })
8155
8598
  ] }),
8156
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8157
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u7CFB\u7EDF\u901A\u77E5" }),
8158
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8159
- "button",
8160
- {
8161
- type: "button",
8162
- className: "dknt-miniswitch" + (cfg.systemNotify ? " on" : ""),
8163
- onClick: () => enableSystemNotify(!cfg.systemNotify),
8164
- children: cfg.systemNotify ? "\u5F00" : "\u5173"
8165
- }
8166
- ),
8167
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: permNote })
8599
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel", children: [
8600
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-head", children: [
8601
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-title-wrap", children: [
8602
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-title", children: "\u63D0\u793A\u97F3" }),
8603
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-sub", children: "\u4EFB\u52A1\u7ED3\u675F / \u9700\u786E\u8BA4\u65F6\u64AD\u653E\uFF0C6 \u79CD\u97F3\u6548\u53EF\u9009" })
8604
+ ] }),
8605
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8606
+ "button",
8607
+ {
8608
+ type: "button",
8609
+ className: "dock-sw" + (cfg.soundNotify !== false ? " on" : ""),
8610
+ role: "switch",
8611
+ "aria-checked": cfg.soundNotify !== false,
8612
+ "aria-label": "\u5F00\u5173\u63D0\u793A\u97F3",
8613
+ onClick: () => patch({ soundNotify: cfg.soundNotify === false })
8614
+ }
8615
+ )
8616
+ ] }),
8617
+ cfg.soundNotify !== false ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-body", children: [
8618
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-sounds", children: Object.keys(SOUND_LIBRARY).map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8619
+ "button",
8620
+ {
8621
+ type: "button",
8622
+ className: "dknt-sound" + (cfg.soundEffect === key ? " on" : ""),
8623
+ onClick: () => patch({ soundEffect: key }),
8624
+ children: [
8625
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sound-name", children: [
8626
+ SOUND_LIBRARY[key].name,
8627
+ cfg.soundEffect === key ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sound-cur", children: "\u2713" }) : null
8628
+ ] }),
8629
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8630
+ "span",
8631
+ {
8632
+ className: "dknt-sound-play",
8633
+ role: "button",
8634
+ tabIndex: 0,
8635
+ title: "\u8BD5\u542C " + SOUND_LIBRARY[key].name,
8636
+ onClick: (e) => {
8637
+ e.stopPropagation();
8638
+ previewSound(key);
8639
+ },
8640
+ onKeyDown: (e) => {
8641
+ if (e.key === "Enter" || e.key === " ") {
8642
+ e.preventDefault();
8643
+ e.stopPropagation();
8644
+ previewSound(key);
8645
+ }
8646
+ },
8647
+ children: "\u25B6"
8648
+ }
8649
+ )
8650
+ ]
8651
+ },
8652
+ key
8653
+ )) }),
8654
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8655
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u4E8B\u4EF6\u8303\u56F4" }),
8656
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u5728\u300C\u6309\u4E8B\u4EF6\u63D0\u9192\u300D\u7684\u63D0\u793A\u97F3\u5217\u91CC\u52FE\u9009\uFF08\u652F\u6301\u5B8C\u6210 / \u5F02\u5E38 / \u9700\u786E\u8BA4\uFF1B\u5361\u4F4F\u6CA1\u6709\u63D0\u793A\u97F3\uFF09\u3002" })
8657
+ ] })
8658
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-channel-off", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u4E8B\u4EF6\u4E0D\u64AD\u653E\u63D0\u793A\u97F3\u3002" })
8168
8659
  ] }),
8169
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8170
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u63D0\u793A\u97F3" }),
8171
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8172
- "button",
8173
- {
8174
- type: "button",
8175
- className: "dknt-miniswitch" + (cfg.soundNotify !== false ? " on" : ""),
8176
- onClick: () => patch({ soundNotify: cfg.soundNotify === false }),
8177
- children: cfg.soundNotify !== false ? "\u5F00" : "\u5173"
8178
- }
8179
- ),
8180
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u4EFB\u52A1\u7ED3\u675F/\u9700\u786E\u8BA4\u65F6\u64AD\u653E\uFF08\u8BD5\u542C\u4E3A\u5148\u64AD\u5B8C\u6210\u97F3\u3001\u540E\u64AD\u5F02\u5E38\u97F3\uFF09" })
8660
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel", children: [
8661
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-head", children: [
8662
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-title-wrap", children: [
8663
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-title", children: "\u7CFB\u7EDF\u901A\u77E5" }),
8664
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-sub", children: "\u6D4F\u89C8\u5668\u7CFB\u7EDF\u901A\u77E5\uFF0C\u4EC5\u9875\u9762\u5728\u540E\u53F0\u65F6\u63A8\u9001" })
8665
+ ] }),
8666
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8667
+ "button",
8668
+ {
8669
+ type: "button",
8670
+ className: "dock-sw" + (cfg.systemNotify ? " on" : ""),
8671
+ role: "switch",
8672
+ "aria-checked": cfg.systemNotify,
8673
+ "aria-label": "\u5F00\u5173\u7CFB\u7EDF\u901A\u77E5",
8674
+ onClick: () => enableSystemNotify(!cfg.systemNotify)
8675
+ }
8676
+ )
8677
+ ] }),
8678
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-body", children: [
8679
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8680
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u6743\u9650" }),
8681
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: permNote })
8682
+ ] }),
8683
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8684
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u4E8B\u4EF6\u8303\u56F4" }),
8685
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u5728\u300C\u6309\u4E8B\u4EF6\u63D0\u9192\u300D\u7684\u7CFB\u7EDF\u901A\u77E5\u5217\u91CC\u52FE\u9009\uFF08\u652F\u6301\u5B8C\u6210 / \u5F02\u5E38 / \u9700\u786E\u8BA4\uFF1B\u5361\u4F4F\u6CA1\u6709\u7CFB\u7EDF\u901A\u77E5\uFF09\u3002" })
8686
+ ] })
8687
+ ] })
8181
8688
  ] }),
8182
- cfg.soundNotify !== false ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-sounds", children: Object.keys(SOUND_LIBRARY).map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8183
- "button",
8184
- {
8185
- type: "button",
8186
- className: "dknt-sound" + (cfg.soundEffect === key ? " on" : ""),
8187
- onClick: () => patch({ soundEffect: key }),
8188
- children: [
8189
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sound-name", children: [
8190
- SOUND_LIBRARY[key].name,
8191
- cfg.soundEffect === key ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sound-cur", children: "\u2713" }) : null
8689
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel", children: [
8690
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-head", children: [
8691
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-title-wrap", children: [
8692
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-title", children: "\u8BED\u97F3\u64AD\u62A5" }),
8693
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-sub", children: "\u7528\u6D4F\u89C8\u5668\u8BED\u97F3\uFF08TTS\uFF09\u8BF4\u4E00\u53E5\u8BDD\uFF1B\u670D\u52A1\u7AEF\u603B\u5F00\u5173 + \u672C\u673A\u5F00\u5173\u90FD\u5F00\u624D\u64AD\u62A5" })
8694
+ ] }),
8695
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8696
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.voiceNotify ? " on" : ""), children: cfg.voiceNotify ? "\u670D\u52A1\u7AEF\uFF1A\u5DF2\u5F00\u542F" : "\u670D\u52A1\u7AEF\uFF1A\u5DF2\u5173\u95ED" }),
8697
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8698
+ "button",
8699
+ {
8700
+ type: "button",
8701
+ className: "dock-sw" + (cfg.voiceNotify ? " on" : ""),
8702
+ role: "switch",
8703
+ "aria-checked": cfg.voiceNotify,
8704
+ "aria-label": "\u5F00\u5173\u8BED\u97F3\u64AD\u62A5\uFF08\u670D\u52A1\u7AEF\u603B\u5F00\u5173\uFF09",
8705
+ disabled: source === "client",
8706
+ title: source === "client" ? "\u670D\u52A1\u7AEF\u603B\u5F00\u5173\u9700\u5207\u6362\u5230\u300C\u670D\u52A1\u7AEF\u914D\u7F6E\u300D\u4FEE\u6539" : cfg.voiceNotify ? "\u5173\u95ED\u8BED\u97F3\u64AD\u62A5\uFF08\u670D\u52A1\u7AEF\u603B\u5F00\u5173\uFF09" : "\u5F00\u542F\u8BED\u97F3\u64AD\u62A5\uFF08\u670D\u52A1\u7AEF\u603B\u5F00\u5173\uFF09",
8707
+ onClick: () => {
8708
+ if (source !== "client") patch({ voiceNotify: !cfg.voiceNotify });
8709
+ }
8710
+ }
8711
+ )
8712
+ ] })
8713
+ ] }),
8714
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-body", children: [
8715
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8716
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u672C\u673A\u64AD\u62A5" }),
8717
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8718
+ "button",
8719
+ {
8720
+ type: "button",
8721
+ className: "dknt-miniswitch" + (voiceClientOn ? " on" : ""),
8722
+ role: "switch",
8723
+ "aria-checked": voiceClientOn,
8724
+ "aria-label": "\u5F00\u5173\u672C\u673A\u8BED\u97F3\u64AD\u62A5",
8725
+ title: voiceClientOn ? "\u5173\u95ED\u672C\u673A\u8BED\u97F3\u64AD\u62A5" : "\u5F00\u542F\u672C\u673A\u8BED\u97F3\u64AD\u62A5",
8726
+ onClick: () => setVoiceClientOn(!voiceClientOn),
8727
+ children: voiceClientOn ? "\u5F00" : "\u5173"
8728
+ }
8729
+ ),
8730
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: voiceClientOn ? "\u672C\u6D4F\u89C8\u5668\u4F1A\u64AD\u62A5\uFF08\u8BBE\u7F6E\u4FDD\u5B58\u5728\u5F53\u524D\u6D4F\u89C8\u5668\uFF1B\u670D\u52A1\u7AEF\u603B\u5F00\u5173\u5173\u95ED\u65F6\u4E0D\u751F\u6548\uFF09" : "\u672C\u6D4F\u89C8\u5668\u4E0D\u64AD\u62A5\uFF08\u8BBE\u7F6E\u4FDD\u5B58\u5728\u5F53\u524D\u6D4F\u89C8\u5668\uFF0C\u4E0D\u5F71\u54CD\u5176\u4ED6\u6D4F\u89C8\u5668\uFF09" })
8731
+ ] }),
8732
+ cfg.voiceNotify ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
8733
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8734
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u53E3\u5F84" }),
8735
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModePicker, { value: voiceTone(cfg), title: "\u8BED\u97F3\u64AD\u62A5", onChange: (v) => patch({ voiceMode: v }) }),
8736
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7B80\u6D01\uFF1A\u4E00\u53E5\u300C\u4EFB\u52A1\u5B8C\u6210 / \u4EFB\u52A1\u505C\u6B62\u4E86 / \u4EFB\u52A1\u9700\u8981\u6388\u6743 / \u4E3B\u4EFB\u52A1\uFF08\u6216\u5B50\u4EFB\u52A1\uFF09\xB7\u6807\u9898 \u5361\u4F4F\u4E86\u300D\uFF1B\u9002\u4E2D\uFF1A\u70B9\u540D\u4EFB\u52A1\uFF0C\u7ED3\u675F\u5E26\u539F\u56E0\u4E0E\u8017\u65F6\u3001\u5361\u4F4F\u5E26\u505C\u6EDE\u65F6\u957F\uFF1B\u8BE6\u7EC6\uFF1A\u7ED3\u675F\u5E26\u56DE\u5408\u7EDF\u8BA1\u4E0E\u56DE\u590D\u6458\u8981\uFF0C\u9700\u6388\u6743\u5E26\u5DE5\u5177\u540D\uFF0C\u5361\u4F4F\u5E26\u6700\u540E\u52A8\u4F5C\u3002" })
8737
+ ] }),
8738
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8739
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u4E8B\u4EF6" }),
8740
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u5728\u300C\u6309\u4E8B\u4EF6\u63D0\u9192\u300D\u7684\u8BED\u97F3\u64AD\u62A5\u5217\u91CC\u52FE\u9009\uFF08\u652F\u6301\u5B8C\u6210 / \u5F02\u5E38 / \u9700\u786E\u8BA4 / \u5361\u4F4F\uFF09\u3002" })
8741
+ ] }),
8742
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8743
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BED\u901F" }),
8744
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8745
+ "input",
8746
+ {
8747
+ type: "range",
8748
+ min: "0.5",
8749
+ max: "2",
8750
+ step: "0.05",
8751
+ value: String(cfg.voiceRate || 1),
8752
+ "aria-label": "\u64AD\u62A5\u8BED\u901F",
8753
+ style: { width: 120, accentColor: "var(--dk-accent)" },
8754
+ onChange: (e) => patch({ voiceRate: Number(e.target.value) || 1 })
8755
+ }
8756
+ ),
8757
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub", children: [
8758
+ Number(cfg.voiceRate || 1).toFixed(2),
8759
+ "\xD7\uFF08\u64AD\u62A5\u6BD4\u6B63\u6587\u6717\u8BFB\u7565\u5FEB\u66F4\u5229\u843D\uFF09"
8760
+ ] })
8761
+ ] }),
8762
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8763
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u97F3\u91CF" }),
8764
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8765
+ "input",
8766
+ {
8767
+ type: "range",
8768
+ min: "0",
8769
+ max: "1",
8770
+ step: "0.05",
8771
+ value: String(cfg.voiceVolume == null ? 1 : cfg.voiceVolume),
8772
+ "aria-label": "\u64AD\u62A5\u97F3\u91CF",
8773
+ style: { width: 120, accentColor: "var(--dk-accent)" },
8774
+ onChange: (e) => patch({ voiceVolume: Number(e.target.value) })
8775
+ }
8776
+ ),
8777
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub", children: [
8778
+ Math.round((cfg.voiceVolume == null ? 1 : cfg.voiceVolume) * 100),
8779
+ "%"
8780
+ ] })
8192
8781
  ] }),
8782
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8783
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u97F3\u8272" }),
8784
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8785
+ "select",
8786
+ {
8787
+ className: "dknt-input",
8788
+ style: { maxWidth: 260 },
8789
+ value: cfg.voiceURI || "",
8790
+ "aria-label": "\u64AD\u62A5\u97F3\u8272",
8791
+ onChange: (e) => patch({ voiceURI: e.target.value }),
8792
+ children: [
8793
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u81EA\u52A8\uFF08\u6309\u8BED\u8A00\u6311\uFF09" }),
8794
+ (() => {
8795
+ const zh = [], other = [];
8796
+ for (const v of voices) {
8797
+ if (!v || !v.voiceURI) continue;
8798
+ if (/^zh/i.test(String(v.lang || ""))) zh.push(v);
8799
+ else other.push(v);
8800
+ }
8801
+ const groups = [];
8802
+ if (zh.length) groups.push(["\u4E2D\u6587\u97F3\u8272", zh]);
8803
+ if (other.length) groups.push(["\u5176\u4ED6\u97F3\u8272", other]);
8804
+ return groups.map(([gname, vs]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("optgroup", { label: gname, children: vs.map((v) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: v.voiceURI, children: (v.name || v.voiceURI) + "\uFF08" + (v.lang || "?") + "\uFF09" }, v.voiceURI)) }, gname));
8805
+ })()
8806
+ ]
8807
+ }
8808
+ ),
8809
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: voices.length ? "\u97F3\u8272\u662F\u672C\u673A\u6D4F\u89C8\u5668\u7ED9\u7684\uFF0C\u6362\u8BBE\u5907\u53EF\u80FD\u8981\u91CD\u9009\uFF1B\u672C\u673A\u627E\u4E0D\u5230\u6240\u9009\u97F3\u8272\u65F6\u81EA\u52A8\u6309\u8BED\u8A00\u56DE\u843D" : "\u672C\u673A\u6682\u672A\u8BFB\u5230\u97F3\u8272\uFF08\u7CFB\u7EDF\u8BED\u97F3\u672A\u88C5/\u672A\u542F\u7528\uFF09\uFF0C\u5C06\u6309\u8BED\u8A00\u81EA\u52A8\u6311" })
8810
+ ] }),
8811
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8812
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BD5\u542C" }),
8813
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8814
+ "button",
8815
+ {
8816
+ type: "button",
8817
+ className: "dknt-btn",
8818
+ disabled: !voiceSupported(),
8819
+ onClick: () => {
8820
+ const preview = Object.assign({}, cfg, { voiceNotify: true });
8821
+ speakVoice(endBroadcastText(true, { title: "\u793A\u4F8B\u4EFB\u52A1", duration: 125e3, turns: 3, steps: 9, toolCalls: 4, lastText: "\u597D\u7684\uFF0C\u4E09\u4EFD\u6587\u6863\u90FD\u5DF2\u66F4\u65B0\u5B8C\u6BD5\u3002" }, null, preview), preview);
8822
+ },
8823
+ children: "\u64AD\u4E00\u53E5"
8824
+ }
8825
+ ),
8826
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8827
+ "button",
8828
+ {
8829
+ type: "button",
8830
+ className: "dknt-btn",
8831
+ disabled: !voiceSupported(),
8832
+ onClick: () => {
8833
+ const preview = Object.assign({}, cfg, { voiceNotify: true });
8834
+ speakVoice(confirmBroadcastText({ title: "\u793A\u4F8B\u4EFB\u52A1" }, { toolName: "pwsh" }, preview), preview);
8835
+ },
8836
+ children: "\u9700\u6388\u6743"
8837
+ }
8838
+ ),
8839
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: voiceSupported() ? "\u6D4F\u89C8\u5668\u8BED\u97F3\u5408\u6210\uFF08\u4E0E\u3010\u8BED\u97F3\u6717\u8BFB\u3011\u540C\u4E00\u5957\u58F0\u97F3\uFF0C\u72EC\u7ACB\u5F00\u5173\uFF1B\u6253\u65AD\u5F0F\u2014\u2014\u64AD\u62A5\u4FE1\u65F6\u6B63\u5728\u6717\u8BFB\u7684\u6B63\u6587\u4F1A\u8BA9\u4F4D\uFF09" : "\u672C\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u8BED\u97F3\u5408\u6210\uFF08speechSynthesis \u4E0D\u53EF\u7528\uFF09" })
8840
+ ] }),
8841
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8842
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BED\u8A00" }),
8843
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8844
+ "select",
8845
+ {
8846
+ className: "dknt-input",
8847
+ style: { maxWidth: 180 },
8848
+ value: cfg.voiceLang || "",
8849
+ "aria-label": "\u64AD\u62A5\u8BED\u8A00",
8850
+ onChange: (e) => patch({ voiceLang: e.target.value }),
8851
+ children: [
8852
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u81EA\u52A8\uFF08\u4E2D\u6587\u4F18\u5148\uFF09" }),
8853
+ ["zh-CN", "zh-TW", "en-US", "en-GB", "ja-JP", "ko-KR"].map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: l, children: l }, l))
8854
+ ]
8855
+ }
8856
+ ),
8857
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u672A\u6307\u5B9A\u97F3\u8272\u65F6\u6309\u8BED\u8A00\u81EA\u52A8\u6311\uFF1B\u5DF2\u9009\u97F3\u8272\u7684\u8BED\u8A00\u4F1A\u8986\u76D6\u8FD9\u91CC" })
8858
+ ] })
8859
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-channel-off", children: "\u670D\u52A1\u7AEF\u603B\u5F00\u5173\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u4E8B\u4EF6\u4E0D\u64AD\u62A5\u8BED\u97F3\uFF1B\u4E0A\u9762\u7684\u300C\u672C\u673A\u64AD\u62A5\u300D\u53EA\u51B3\u5B9A\u672C\u6D4F\u89C8\u5668\u662F\u5426\u51FA\u58F0\u3002" })
8860
+ ] })
8861
+ ] })
8862
+ ] }, "channels")
8863
+ );
8864
+ } else {
8865
+ rows.push(
8866
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channels", children: [
8867
+ source === "client" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note dknt-note-box", children: "\u7FA4\u673A\u5668\u4EBA\u63A8\u9001\u7531\u670D\u52A1\u7AEF\u6267\u884C\uFF0C\u59CB\u7EC8\u4F7F\u7528\u670D\u52A1\u7AEF\u914D\u7F6E\uFF1B\u8BF7\u5207\u6362\u5230\u300C\u670D\u52A1\u7AEF\u914D\u7F6E\u300D\u4FEE\u6539\u3002" }) : null,
8868
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel", children: [
8869
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-head", children: [
8870
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-title-wrap", children: [
8871
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-title", children: "\u9489\u9489\u63A8\u9001" }),
8872
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-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\uFF09" })
8873
+ ] }),
8874
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8875
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.dingtalkEnabled ? " on" : ""), children: cfg.dingtalkEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
8193
8876
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8194
- "span",
8877
+ "button",
8195
8878
  {
8196
- className: "dknt-sound-play",
8197
- role: "button",
8198
- tabIndex: 0,
8199
- title: "\u8BD5\u542C " + SOUND_LIBRARY[key].name,
8200
- onClick: (e) => {
8201
- e.stopPropagation();
8202
- previewSound(key);
8203
- },
8204
- onKeyDown: (e) => {
8205
- if (e.key === "Enter" || e.key === " ") {
8206
- e.preventDefault();
8207
- e.stopPropagation();
8208
- previewSound(key);
8209
- }
8210
- },
8211
- children: "\u25B6"
8879
+ type: "button",
8880
+ className: "dock-sw" + (cfg.dingtalkEnabled ? " on" : ""),
8881
+ role: "switch",
8882
+ "aria-checked": cfg.dingtalkEnabled,
8883
+ "aria-label": "\u5F00\u5173\u9489\u9489\u63A8\u9001",
8884
+ disabled: source === "client",
8885
+ onClick: () => {
8886
+ if (source !== "client") patch({ dingtalkEnabled: !cfg.dingtalkEnabled });
8887
+ }
8888
+ }
8889
+ )
8890
+ ] })
8891
+ ] }),
8892
+ source === "client" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-channel-off", children: "\u672C\u673A\u914D\u7F6E\u6A21\u5F0F\u4E0D\u4FEE\u6539\u7FA4\u673A\u5668\u4EBA\uFF1B\u5207\u56DE\u670D\u52A1\u7AEF\u914D\u7F6E\u540E\u53EF\u7F16\u8F91 Webhook\u3002" }) : !cfg.dingtalkEnabled ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-channel-off", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u7ED3\u675F\u4E0D\u63A8\u9001\u9489\u9489\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-body", children: [
8893
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8894
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u6D88\u606F\u53E3\u5F84" }),
8895
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModePicker, { value: cfg.pushMode || "detailed", title: "\u9489\u9489\u6D88\u606F", onChange: (v) => patch({ pushMode: v }) }),
8896
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7B80\u6D01\uFF1D\u4EFB\u52A1\u4E0E\u7ED3\u679C\uFF1B\u9002\u4E2D\uFF1D\u52A0\u6A21\u578B/\u8017\u65F6\uFF1B\u8BE6\u7EC6\uFF1D\u518D\u52A0\u56DE\u5408\u3001Token \u4E0E\u6458\u8981\u3002" })
8897
+ ] }),
8898
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row dknt-row-webhook", children: [
8899
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "Webhook" }),
8900
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8901
+ "input",
8902
+ {
8903
+ type: "text",
8904
+ className: "dknt-input",
8905
+ spellCheck: false,
8906
+ value: cfg.dingtalkWebhook || "",
8907
+ placeholder: "https://oapi.dingtalk.com/robot/send?access_token=\u2026",
8908
+ onChange: (e) => {
8909
+ editingWebhookRef.current = true;
8910
+ setServerDraft(Object.assign({}, cfg, { dingtalkWebhook: e.target.value }));
8911
+ }
8912
+ }
8913
+ ),
8914
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8915
+ "button",
8916
+ {
8917
+ type: "button",
8918
+ className: "dknt-btn",
8919
+ disabled: !editingWebhookRef.current,
8920
+ onClick: saveWebhook,
8921
+ children: editingWebhookRef.current ? "\u4FDD\u5B58" : "\u5DF2\u4FDD\u5B58"
8212
8922
  }
8213
8923
  )
8214
- ]
8215
- },
8216
- key
8217
- )) }) : null
8218
- ] })
8219
- ] }, "style"),
8220
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8221
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8222
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u8BED\u97F3\u64AD\u62A5" }),
8223
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u4EFB\u52A1\u5B8C\u6210 / \u505C\u6B62 / \u9700\u8981\u6388\u6743 / \u5361\u4F4F\u65F6\u7528\u6D4F\u89C8\u5668\u8BED\u97F3\uFF08TTS\uFF09\u8BF4\u4E00\u53E5\u8BDD\uFF1B\u4E0E\u63D0\u793A\u97F3\u3001\u7CFB\u7EDF\u901A\u77E5\u4E92\u4E0D\u51B2\u7A81" }),
8224
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8225
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.voiceNotify ? " on" : ""), children: cfg.voiceNotify ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
8226
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8227
- "button",
8228
- {
8229
- type: "button",
8230
- className: "dock-sw" + (cfg.voiceNotify ? " on" : ""),
8231
- role: "switch",
8232
- "aria-checked": cfg.voiceNotify,
8233
- "aria-label": "\u5F00\u5173\u8BED\u97F3\u64AD\u62A5",
8234
- title: cfg.voiceNotify ? "\u5173\u95ED\u8BED\u97F3\u64AD\u62A5" : "\u5F00\u542F\u8BED\u97F3\u64AD\u62A5",
8235
- onClick: () => patch({ voiceNotify: !cfg.voiceNotify })
8236
- }
8237
- )
8238
- ] })
8239
- ] }),
8240
- cfg.voiceNotify ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8241
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8242
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u53E3\u5F84" }),
8243
- [["brief", "\u7B80\u6D01"], ["medium", "\u9002\u4E2D"], ["detailed", "\u8BE6\u7EC6"]].map(([v, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8244
- "button",
8245
- {
8246
- type: "button",
8247
- className: "dknt-miniswitch" + (voiceTone(cfg) === v ? " on" : ""),
8248
- style: { marginRight: 6 },
8249
- title: "\u8BED\u97F3\u64AD\u62A5\u6309" + label + "\u6863\u8BF4",
8250
- onClick: () => patch({ voiceMode: v }),
8251
- children: label
8252
- },
8253
- v
8254
- )),
8255
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7B80\u6D01\uFF1A\u4E00\u53E5\u300C\u4EFB\u52A1\u5B8C\u6210 / \u4EFB\u52A1\u505C\u6B62\u4E86 / \u4EFB\u52A1\u9700\u8981\u6388\u6743 / \u4E3B\u4EFB\u52A1\uFF08\u6216\u5B50\u4EFB\u52A1\uFF09\xB7\u6807\u9898 \u5361\u4F4F\u4E86\u300D\uFF1B\u9002\u4E2D\uFF1A\u70B9\u540D\u4EFB\u52A1\uFF0C\u7ED3\u675F\u5E26\u539F\u56E0\u4E0E\u8017\u65F6\u3001\u5361\u4F4F\u5E26\u505C\u6EDE\u65F6\u957F\uFF1B\u8BE6\u7EC6\uFF1A\u7ED3\u675F\u5E26\u56DE\u5408\u7EDF\u8BA1\u4E0E\u56DE\u590D\u6458\u8981\uFF0C\u9700\u6388\u6743\u5E26\u5DE5\u5177\u540D\uFF0C\u5361\u4F4F\u5E26\u6700\u540E\u52A8\u4F5C" })
8256
- ] }),
8257
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8258
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u65F6\u523B" }),
8259
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", style: { minWidth: 0 }, children: [
8260
- ["voiceOnComplete", "\u5B8C\u6210", cfg.voiceOnComplete !== false],
8261
- ["voiceOnError", "\u505C\u6B62", cfg.voiceOnError !== false],
8262
- ["voiceOnConfirm", "\u9700\u6388\u6743", cfg.voiceOnConfirm !== false],
8263
- ["voiceOnStuck", "\u5361\u4F4F", cfg.voiceOnStuck !== false]
8264
- ].map(([key, label, on]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8265
- "button",
8266
- {
8267
- type: "button",
8268
- className: "dknt-miniswitch" + (on ? " on" : ""),
8269
- style: { marginRight: 6 },
8270
- title: key === "voiceOnStuck" ? "\u7F16\u7A0B\u9636\u6BB5 18 \u79D2\u6CA1\u6709\u52A8\u9759\u65F6\u64AD\u62A5\u4E00\u6B21\uFF08\u6062\u590D\u540E\u53EF\u518D\u62A5\uFF09" : "",
8271
- onClick: () => patch({ [key]: !on }),
8272
- children: [
8273
- label,
8274
- on ? "\xB7\u5F00" : "\xB7\u5173"
8275
- ]
8276
- },
8277
- key
8278
- )) })
8279
- ] }),
8280
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8281
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BED\u901F" }),
8282
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8283
- "input",
8284
- {
8285
- type: "range",
8286
- min: "0.5",
8287
- max: "2",
8288
- step: "0.05",
8289
- value: String(cfg.voiceRate || 1),
8290
- "aria-label": "\u64AD\u62A5\u8BED\u901F",
8291
- style: { width: 120, accentColor: "var(--dk-accent)" },
8292
- onChange: (e) => patch({ voiceRate: Number(e.target.value) || 1 })
8293
- }
8294
- ),
8295
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub", children: [
8296
- Number(cfg.voiceRate || 1).toFixed(2),
8297
- "\xD7\uFF08\u64AD\u62A5\u6BD4\u6B63\u6587\u6717\u8BFB\u7565\u5FEB\u66F4\u5229\u843D\uFF09"
8298
- ] })
8299
- ] }),
8300
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8301
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u97F3\u91CF" }),
8302
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8303
- "input",
8304
- {
8305
- type: "range",
8306
- min: "0",
8307
- max: "1",
8308
- step: "0.05",
8309
- value: String(cfg.voiceVolume == null ? 1 : cfg.voiceVolume),
8310
- "aria-label": "\u64AD\u62A5\u97F3\u91CF",
8311
- style: { width: 120, accentColor: "var(--dk-accent)" },
8312
- onChange: (e) => patch({ voiceVolume: Number(e.target.value) })
8313
- }
8314
- ),
8315
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub", children: [
8316
- Math.round((cfg.voiceVolume == null ? 1 : cfg.voiceVolume) * 100),
8317
- "%"
8924
+ ] }),
8925
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8926
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8FDE\u901A\u6D4B\u8BD5" }),
8927
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dknt-btn", disabled: testing, onClick: runDingtalkTest, children: testing ? "\u53D1\u9001\u4E2D\u2026" : "\u53D1\u9001\u6D4B\u8BD5\u6D88\u606F" }),
8928
+ testState ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub" + (testState.ok ? " dknt-ok" : " dknt-err"), children: [
8929
+ testState.ok ? "\u2713 " : "\u2717 ",
8930
+ testState.msg
8931
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7528\u5F53\u524D\u4FDD\u5B58\u7684 Webhook \u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F" })
8932
+ ] }),
8933
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-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" })
8318
8934
  ] })
8319
8935
  ] }),
8320
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8321
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u97F3\u8272" }),
8322
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8323
- "select",
8324
- {
8325
- className: "dknt-input",
8326
- style: { maxWidth: 260 },
8327
- value: cfg.voiceURI || "",
8328
- "aria-label": "\u64AD\u62A5\u97F3\u8272",
8329
- onChange: (e) => patch({ voiceURI: e.target.value }),
8330
- children: [
8331
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u81EA\u52A8\uFF08\u6309\u8BED\u8A00\u6311\uFF09" }),
8332
- (() => {
8333
- const zh = [], other = [];
8334
- for (const v of voices) {
8335
- if (!v || !v.voiceURI) continue;
8336
- if (/^zh/i.test(String(v.lang || ""))) zh.push(v);
8337
- else other.push(v);
8936
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel", children: [
8937
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-head", children: [
8938
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-title-wrap", children: [
8939
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-title", children: "\u98DE\u4E66\u63A8\u9001" }),
8940
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-channel-sub", children: "\u4EFB\u52A1\u7ED3\u675F\u4EE5\u5361\u7247\u5F62\u5F0F\u63A8\u9001\u5230\u98DE\u4E66\u7FA4\u673A\u5668\u4EBA\uFF08\u5BBF\u4E3B\u76F4\u53D1\uFF09" })
8941
+ ] }),
8942
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8943
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.feishuEnabled ? " on" : ""), children: cfg.feishuEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
8944
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8945
+ "button",
8946
+ {
8947
+ type: "button",
8948
+ className: "dock-sw" + (cfg.feishuEnabled ? " on" : ""),
8949
+ role: "switch",
8950
+ "aria-checked": cfg.feishuEnabled,
8951
+ "aria-label": "\u5F00\u5173\u98DE\u4E66\u63A8\u9001",
8952
+ disabled: source === "client",
8953
+ onClick: () => {
8954
+ if (source !== "client") patch({ feishuEnabled: !cfg.feishuEnabled });
8338
8955
  }
8339
- const groups = [];
8340
- if (zh.length) groups.push(["\u4E2D\u6587\u97F3\u8272", zh]);
8341
- if (other.length) groups.push(["\u5176\u4ED6\u97F3\u8272", other]);
8342
- return groups.map(([gname, vs]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("optgroup", { label: gname, children: vs.map((v) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: v.voiceURI, children: (v.name || v.voiceURI) + "\uFF08" + (v.lang || "?") + "\uFF09" }, v.voiceURI)) }, gname));
8343
- })()
8344
- ]
8345
- }
8346
- ),
8347
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: voices.length ? "\u97F3\u8272\u662F\u672C\u673A\u6D4F\u89C8\u5668\u7ED9\u7684\uFF0C\u6362\u8BBE\u5907\u53EF\u80FD\u8981\u91CD\u9009\uFF1B\u672C\u673A\u627E\u4E0D\u5230\u6240\u9009\u97F3\u8272\u65F6\u81EA\u52A8\u6309\u8BED\u8A00\u56DE\u843D" : "\u672C\u673A\u6682\u672A\u8BFB\u5230\u97F3\u8272\uFF08\u7CFB\u7EDF\u8BED\u97F3\u672A\u88C5/\u672A\u542F\u7528\uFF09\uFF0C\u5C06\u6309\u8BED\u8A00\u81EA\u52A8\u6311" })
8348
- ] }),
8349
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8350
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BD5\u542C" }),
8351
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8352
- "button",
8353
- {
8354
- type: "button",
8355
- className: "dknt-btn",
8356
- disabled: !voiceSupported(),
8357
- onClick: () => {
8358
- const preview = Object.assign({}, cfg, { voiceNotify: true });
8359
- speakVoice(endBroadcastText(true, { title: "\u793A\u4F8B\u4EFB\u52A1", duration: 125e3, turns: 3, steps: 9, toolCalls: 4, lastText: "\u597D\u7684\uFF0C\u4E09\u4EFD\u6587\u6863\u90FD\u5DF2\u66F4\u65B0\u5B8C\u6BD5\u3002" }, null, preview), preview);
8360
- },
8361
- children: "\u64AD\u4E00\u53E5"
8362
- }
8363
- ),
8364
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8365
- "button",
8366
- {
8367
- type: "button",
8368
- className: "dknt-btn",
8369
- disabled: !voiceSupported(),
8370
- onClick: () => {
8371
- const preview = Object.assign({}, cfg, { voiceNotify: true });
8372
- speakVoice(confirmBroadcastText({ title: "\u793A\u4F8B\u4EFB\u52A1" }, { toolName: "pwsh" }, preview), preview);
8373
- },
8374
- children: "\u9700\u6388\u6743"
8375
- }
8376
- ),
8377
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: voiceSupported() ? "\u6D4F\u89C8\u5668\u8BED\u97F3\u5408\u6210\uFF08\u4E0E\u3010\u8BED\u97F3\u6717\u8BFB\u3011\u540C\u4E00\u5957\u58F0\u97F3\uFF0C\u72EC\u7ACB\u5F00\u5173\uFF1B\u6253\u65AD\u5F0F\u2014\u2014\u64AD\u62A5\u4FE1\u65F6\u6B63\u5728\u6717\u8BFB\u7684\u6B63\u6587\u4F1A\u8BA9\u4F4D\uFF09" : "\u672C\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u8BED\u97F3\u5408\u6210\uFF08speechSynthesis \u4E0D\u53EF\u7528\uFF09" })
8378
- ] }),
8379
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8380
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BED\u8A00" }),
8381
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8382
- "select",
8383
- {
8384
- className: "dknt-input",
8385
- style: { maxWidth: 180 },
8386
- value: cfg.voiceLang || "",
8387
- "aria-label": "\u64AD\u62A5\u8BED\u8A00",
8388
- onChange: (e) => patch({ voiceLang: e.target.value }),
8389
- children: [
8390
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u81EA\u52A8\uFF08\u4E2D\u6587\u4F18\u5148\uFF09" }),
8391
- ["zh-CN", "zh-TW", "en-US", "en-GB", "ja-JP", "ko-KR"].map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: l, children: l }, l))
8392
- ]
8393
- }
8394
- ),
8395
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u672A\u6307\u5B9A\u97F3\u8272\u65F6\u6309\u8BED\u8A00\u81EA\u52A8\u6311\uFF1B\u5DF2\u9009\u97F3\u8272\u7684\u8BED\u8A00\u4F1A\u8986\u76D6\u8FD9\u91CC" })
8396
- ] })
8397
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u4E8B\u4EF6\u4E0D\u64AD\u62A5\u8BED\u97F3\uFF08\u63D0\u793A\u97F3\u3001\u7CFB\u7EDF\u901A\u77E5\u4E0D\u53D7\u5F71\u54CD\uFF09\u3002" })
8398
- ] }, "voice"),
8399
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8400
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8401
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u9489\u9489\u63A8\u9001" }),
8402
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-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" }),
8403
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8404
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.dingtalkEnabled ? " on" : ""), children: cfg.dingtalkEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
8405
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8406
- "button",
8407
- {
8408
- type: "button",
8409
- className: "dock-sw" + (cfg.dingtalkEnabled ? " on" : ""),
8410
- role: "switch",
8411
- "aria-checked": cfg.dingtalkEnabled,
8412
- "aria-label": "\u5F00\u5173\u9489\u9489\u63A8\u9001",
8413
- title: cfg.dingtalkEnabled ? "\u5173\u95ED\u9489\u9489\u63A8\u9001" : "\u5F00\u542F\u9489\u9489\u63A8\u9001",
8414
- onClick: () => patch({ dingtalkEnabled: !cfg.dingtalkEnabled })
8415
- }
8416
- )
8417
- ] })
8418
- ] }),
8419
- cfg.dingtalkEnabled ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8420
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row dknt-row-webhook", children: [
8421
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "Webhook" }),
8422
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8423
- "input",
8424
- {
8425
- type: "text",
8426
- className: "dknt-input",
8427
- spellCheck: false,
8428
- value: cfg.dingtalkWebhook || "",
8429
- placeholder: "https://oapi.dingtalk.com/robot/send?access_token=\u2026",
8430
- onChange: (e) => {
8431
- editingWebhookRef.current = true;
8432
- setCfg(Object.assign({}, cfg, { dingtalkWebhook: e.target.value }));
8433
- }
8434
- }
8435
- ),
8436
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8437
- "button",
8438
- {
8439
- type: "button",
8440
- className: "dknt-btn",
8441
- disabled: !editingWebhookRef.current,
8442
- onClick: saveWebhook,
8443
- children: editingWebhookRef.current ? "\u4FDD\u5B58" : "\u5DF2\u4FDD\u5B58"
8444
- }
8445
- )
8446
- ] }),
8447
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8448
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8FDE\u901A\u6D4B\u8BD5" }),
8449
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dknt-btn", disabled: testing, onClick: runDingtalkTest, children: testing ? "\u53D1\u9001\u4E2D\u2026" : "\u53D1\u9001\u6D4B\u8BD5\u6D88\u606F" }),
8450
- testState ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub" + (testState.ok ? " dknt-ok" : " dknt-err"), children: [
8451
- testState.ok ? "\u2713 " : "\u2717 ",
8452
- testState.msg
8453
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7528\u5F53\u524D\u4FDD\u5B58\u7684 Webhook \u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F" })
8454
- ] }),
8455
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-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" })
8456
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u7ED3\u675F\u4E0D\u63A8\u9001\u9489\u9489\u3002" })
8457
- ] }, "dingtalk"),
8458
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8459
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8460
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u98DE\u4E66\u63A8\u9001" }),
8461
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-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" }),
8462
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8463
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.feishuEnabled ? " on" : ""), children: cfg.feishuEnabled ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
8464
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8465
- "button",
8466
- {
8467
- type: "button",
8468
- className: "dock-sw" + (cfg.feishuEnabled ? " on" : ""),
8469
- role: "switch",
8470
- "aria-checked": cfg.feishuEnabled,
8471
- "aria-label": "\u5F00\u5173\u98DE\u4E66\u63A8\u9001",
8472
- title: cfg.feishuEnabled ? "\u5173\u95ED\u98DE\u4E66\u63A8\u9001" : "\u5F00\u542F\u98DE\u4E66\u63A8\u9001",
8473
- onClick: () => patch({ feishuEnabled: !cfg.feishuEnabled })
8474
- }
8475
- )
8956
+ }
8957
+ )
8958
+ ] })
8959
+ ] }),
8960
+ source === "client" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-channel-off", children: "\u672C\u673A\u914D\u7F6E\u6A21\u5F0F\u4E0D\u4FEE\u6539\u7FA4\u673A\u5668\u4EBA\uFF1B\u5207\u56DE\u670D\u52A1\u7AEF\u914D\u7F6E\u540E\u53EF\u7F16\u8F91 Webhook\u3002" }) : !cfg.feishuEnabled ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-channel-off", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u7ED3\u675F\u4E0D\u63A8\u9001\u98DE\u4E66\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-channel-body", children: [
8961
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8962
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u6D88\u606F\u53E3\u5F84" }),
8963
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModePicker, { value: cfg.pushMode || "detailed", title: "\u98DE\u4E66\u6D88\u606F", onChange: (v) => patch({ pushMode: v }) }),
8964
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7B80\u6D01\uFF1D\u4EFB\u52A1\u4E0E\u7ED3\u679C\uFF1B\u9002\u4E2D\uFF1D\u52A0\u6A21\u578B/\u8017\u65F6\uFF1B\u8BE6\u7EC6\uFF1D\u518D\u52A0\u56DE\u5408\u3001Token \u4E0E\u6458\u8981\u3002" })
8965
+ ] }),
8966
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row dknt-row-webhook", children: [
8967
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "Webhook" }),
8968
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8969
+ "input",
8970
+ {
8971
+ type: "text",
8972
+ className: "dknt-input",
8973
+ spellCheck: false,
8974
+ value: cfg.feishuWebhook || "",
8975
+ placeholder: "https://open.feishu.cn/open-apis/bot/v2/hook/\u2026",
8976
+ onChange: (e) => {
8977
+ editingFeishuRef.current = true;
8978
+ setServerDraft(Object.assign({}, cfg, { feishuWebhook: e.target.value }));
8979
+ }
8980
+ }
8981
+ ),
8982
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8983
+ "button",
8984
+ {
8985
+ type: "button",
8986
+ className: "dknt-btn",
8987
+ disabled: !editingFeishuRef.current,
8988
+ onClick: saveFeishuWebhook,
8989
+ children: editingFeishuRef.current ? "\u4FDD\u5B58" : "\u5DF2\u4FDD\u5B58"
8990
+ }
8991
+ )
8992
+ ] }),
8993
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8994
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8FDE\u901A\u6D4B\u8BD5" }),
8995
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dknt-btn", disabled: feishuTesting, onClick: runFeishuTest, children: feishuTesting ? "\u53D1\u9001\u4E2D\u2026" : "\u53D1\u9001\u6D4B\u8BD5\u6D88\u606F" }),
8996
+ feishuTestState ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub" + (feishuTestState.ok ? " dknt-ok" : " dknt-err"), children: [
8997
+ feishuTestState.ok ? "\u2713 " : "\u2717 ",
8998
+ feishuTestState.msg
8999
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7528\u5F53\u524D\u4FDD\u5B58\u7684 Webhook \u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F" })
9000
+ ] }),
9001
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-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" })
9002
+ ] })
8476
9003
  ] })
8477
- ] }),
8478
- cfg.feishuEnabled ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8479
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row dknt-row-webhook", children: [
8480
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "Webhook" }),
8481
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8482
- "input",
8483
- {
8484
- type: "text",
8485
- className: "dknt-input",
8486
- spellCheck: false,
8487
- value: cfg.feishuWebhook || "",
8488
- placeholder: "https://open.feishu.cn/open-apis/bot/v2/hook/\u2026",
8489
- onChange: (e) => {
8490
- editingFeishuRef.current = true;
8491
- setCfg(Object.assign({}, cfg, { feishuWebhook: e.target.value }));
8492
- }
8493
- }
8494
- ),
8495
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8496
- "button",
8497
- {
8498
- type: "button",
8499
- className: "dknt-btn",
8500
- disabled: !editingFeishuRef.current,
8501
- onClick: saveFeishuWebhook,
8502
- children: editingFeishuRef.current ? "\u4FDD\u5B58" : "\u5DF2\u4FDD\u5B58"
8503
- }
8504
- )
8505
- ] }),
8506
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8507
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8FDE\u901A\u6D4B\u8BD5" }),
8508
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dknt-btn", disabled: feishuTesting, onClick: runFeishuTest, children: feishuTesting ? "\u53D1\u9001\u4E2D\u2026" : "\u53D1\u9001\u6D4B\u8BD5\u6D88\u606F" }),
8509
- feishuTestState ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub" + (feishuTestState.ok ? " dknt-ok" : " dknt-err"), children: [
8510
- feishuTestState.ok ? "\u2713 " : "\u2717 ",
8511
- feishuTestState.msg
8512
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7528\u5F53\u524D\u4FDD\u5B58\u7684 Webhook \u53D1\u4E00\u6761\u6D4B\u8BD5\u6D88\u606F" })
8513
- ] }),
8514
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-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" })
8515
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u7ED3\u675F\u4E0D\u63A8\u9001\u98DE\u4E66\u3002" })
8516
- ] }, "feishu")
8517
- );
9004
+ ] }, "robots")
9005
+ );
9006
+ }
8518
9007
  }
8519
9008
  if (saveErr) rows.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note dknt-err", children: saveErr }, "err"));
8520
9009
  rows.push(
8521
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u4EFB\u52A1\u8FD0\u884C\u72B6\u6001\uFF08\u8FDB\u884C\u4E2D\u4EFB\u52A1\u3001\u7B49\u5F85\u786E\u8BA4\u4E0E\u6700\u8FD1\u5B8C\u6210\uFF09\u5DF2\u72EC\u7ACB\u6210\u5DE6\u4FA7\u300C\u8FD0\u884C\u72B6\u6001\u300D\u83DC\u5355\uFF1B\u672C\u9875\u53EA\u8D1F\u8D23\u7ED3\u675F\u4E0E\u9700\u786E\u8BA4\u65F6\u7684\u63D0\u9192\u3002" }, "hint")
9010
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u4EFB\u52A1\u8FD0\u884C\u72B6\u6001\uFF08\u8FDB\u884C\u4E2D\u4EFB\u52A1\u3001\u7B49\u4EBA\u4ECB\u5165\uFF08\u7B49\u6279\u51C6 / \u7B49\u56DE\u7B54\uFF09\u4E0E\u6700\u8FD1\u5B8C\u6210\uFF09\u5DF2\u72EC\u7ACB\u6210\u5DE6\u4FA7\u300C\u8FD0\u884C\u72B6\u6001\u300D\u83DC\u5355\uFF1B\u672C\u9875\u53EA\u8D1F\u8D23\u7ED3\u675F\u4E0E\u9700\u786E\u8BA4 / \u9700\u56DE\u7B54\u65F6\u7684\u63D0\u9192\u3002" }, "hint")
8522
9011
  );
8523
9012
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-root", children: rows });
8524
9013
  }
8525
9014
  function NotifyStat(props) {
8526
9015
  const snap = useNotify(props && props.ctx);
8527
- const cfg = snap.status && snap.status.config;
9016
+ const cfg = snap.status ? effectiveNotifyConfig(snap.status.config) : null;
8528
9017
  if (snap.error) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-err", children: "\u901A\u77E5\u72B6\u6001\u4E0D\u53EF\u7528\uFF08\u5BBF\u4E3B\u9700\u91CD\u542F\u52A0\u8F7D\u901A\u77E5\u8DEF\u7531\uFF09" });
8529
9018
  if (!cfg) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "\u7B49\u5F85\u901A\u77E5\u914D\u7F6E\u2026" });
8530
- const events = [cfg.notifyOnComplete ? "\u5B8C\u6210" : "", cfg.notifyOnError ? "\u5F02\u5E38" : "", cfg.notifyOnConfirm !== false ? "\u9700\u786E\u8BA4" : ""].filter(Boolean);
8531
- const extras = [cfg.soundNotify !== false ? "\u63D0\u793A\u97F3" : "", cfg.systemNotify ? "\u7CFB\u7EDF\u901A\u77E5" : "", cfg.voiceNotify ? "\u8BED\u97F3\u64AD\u62A5" + (cfg.voiceMode === "detailed" ? "\xB7\u8BE6" : cfg.voiceMode === "medium" ? "\xB7\u9002" : "\xB7\u7B80") : ""].filter(Boolean);
9019
+ const anyChannel = (event) => MATRIX_COLUMNS.some((column) => eventEnabled(cfg, column.id, event));
9020
+ const events = [
9021
+ anyChannel("complete") ? "\u5B8C\u6210" : "",
9022
+ anyChannel("error") ? "\u5F02\u5E38" : "",
9023
+ anyChannel("confirm") ? "\u9700\u786E\u8BA4/\u9700\u56DE\u7B54" : "",
9024
+ anyChannel("stuck") ? "\u5361\u4F4F" : ""
9025
+ ].filter(Boolean);
9026
+ const voiceMode = cfg.voiceMode === "detailed" ? "\xB7\u8BE6" : cfg.voiceMode === "medium" ? "\xB7\u9002" : "\xB7\u7B80";
9027
+ const voice = !cfg.voiceNotify ? "" : voiceClientEnabled() ? "\u8BED\u97F3\u64AD\u62A5" + voiceMode : "\u8BED\u97F3\u64AD\u62A5\xB7\u672C\u673A\u5DF2\u5173";
9028
+ const extras = [cfg.soundNotify !== false ? "\u63D0\u793A\u97F3" : "", cfg.systemNotify ? "\u7CFB\u7EDF\u901A\u77E5" : "", voice].filter(Boolean);
8532
9029
  const push = [cfg.dingtalkEnabled ? "\u9489\u9489" : "", cfg.feishuEnabled ? "\u98DE\u4E66" : ""].filter(Boolean);
8533
9030
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: (events.length ? "\u901A\u77E5\uFF1A" + events.join("/") : "\u901A\u77E5\u4E8B\u4EF6\u5168\u5173") + (extras.length ? " \xB7 " + extras.join("/") : "") + (push.length ? " \xB7 \u63A8\u9001\uFF1A" + push.join("/") : "") });
8534
9031
  }
@@ -8575,6 +9072,48 @@ var css3 = [
8575
9072
  ".dknt-row-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
8576
9073
  ".dknt-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;}",
8577
9074
  ".dknt-miniswitch.on{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
9075
+ // 配置来源与页签
9076
+ ".dknt-source{display:flex;align-items:center;gap:10px;flex-wrap:wrap;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:10px 12px;}",
9077
+ ".dknt-source-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:180px;}",
9078
+ ".dknt-source-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary);}",
9079
+ ".dknt-source-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
9080
+ ".dknt-seg{display:inline-flex;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden;flex:none;}",
9081
+ ".dknt-seg-btn{cursor:pointer;border:0;background:transparent;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;padding:5px 12px;}",
9082
+ ".dknt-seg-btn + .dknt-seg-btn{border-left:1px solid var(--dsw-alias-border-l2);}",
9083
+ ".dknt-seg-btn.on{background:var(--dk-accent-soft);color:var(--dk-accent);font-weight:600;}",
9084
+ ".dknt-tabs{display:flex;gap:4px;border-bottom:1px solid var(--dsw-alias-border-l1);padding:0 2px;}",
9085
+ ".dknt-tab{cursor:pointer;border:0;background:transparent;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:13px;padding:7px 12px;border-bottom:2px solid transparent;margin-bottom:-1px;}",
9086
+ ".dknt-tab.on{color:var(--dk-accent);border-bottom-color:var(--dk-accent);font-weight:600;}",
9087
+ // 事件 × 渠道矩阵
9088
+ ".dknt-matrix-wrap{overflow-x:auto;}",
9089
+ ".dknt-matrix{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;overflow:hidden;min-width:620px;}",
9090
+ ".dknt-matrix-row{display:grid;grid-template-columns:minmax(150px,1.4fr) repeat(6,minmax(56px,1fr));align-items:center;}",
9091
+ ".dknt-matrix-row:nth-child(even){background:color-mix(in srgb,var(--dsw-alias-bg-layer-2) 55%,transparent);}",
9092
+ ".dknt-matrix-head{background:var(--dsw-alias-bg-layer-2);border-bottom:1px solid var(--dsw-alias-border-l1);}",
9093
+ ".dknt-matrix-col{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);text-align:center;padding:7px 4px;display:flex;flex-direction:column;align-items:center;gap:1px;}",
9094
+ ".dknt-matrix-col em{font-style:normal;font-size:10px;font-weight:400;color:var(--dsw-alias-label-tertiary);}",
9095
+ ".dknt-matrix-col.on em{color:var(--dsw-alias-state-success-primary);}",
9096
+ ".dknt-matrix-event{display:flex;flex-direction:column;gap:1px;padding:8px 10px;font-size:12px;color:var(--dsw-alias-label-primary);}",
9097
+ ".dknt-matrix-event small{font-size:10px;color:var(--dsw-alias-label-tertiary);}",
9098
+ ".dknt-cell{justify-self:center;cursor:pointer;width:24px;height:24px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:transparent;font-family:inherit;font-size:12px;line-height:1;display:inline-flex;align-items:center;justify-content:center;margin:5px 0;}",
9099
+ ".dknt-cell.on{border-color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 14%,transparent);color:var(--dsw-alias-state-success-primary);}",
9100
+ ".dknt-cell-na{cursor:default;border-style:dashed;color:var(--dsw-alias-label-tertiary);}",
9101
+ ".dknt-cell.disabled{opacity:.4;cursor:not-allowed;}",
9102
+ ".dknt-matrix-legend{display:flex;gap:12px;flex-wrap:wrap;padding-top:6px;font-size:10px;color:var(--dsw-alias-label-tertiary);}",
9103
+ ".dknt-matrix-legend span{display:inline-flex;align-items:center;gap:4px;}",
9104
+ ".dknt-dot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-tertiary);display:inline-block;}",
9105
+ ".dknt-dot.on{background:var(--dsw-alias-state-success-primary);}",
9106
+ // 渠道卡片
9107
+ ".dknt-channels{display:flex;flex-direction:column;gap:10px;}",
9108
+ ".dknt-channel{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-1);overflow:hidden;}",
9109
+ ".dknt-channel-head{display:flex;align-items:center;gap:10px;padding:10px 12px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-2) 45%,transparent);border-bottom:1px solid var(--dsw-alias-border-l1);}",
9110
+ ".dknt-channel-title-wrap{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0;}",
9111
+ ".dknt-channel-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);}",
9112
+ ".dknt-channel-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);}",
9113
+ ".dknt-channel-body{display:flex;flex-direction:column;gap:8px;padding:10px 12px;}",
9114
+ ".dknt-channel-off{padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-tertiary);}",
9115
+ ".dknt-modes{display:inline-flex;gap:4px;flex:none;}",
9116
+ ".dknt-note-box{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:8px 10px;background:var(--dsw-alias-bg-layer-1);}",
8578
9117
  // 音效选择卡(名称 + 播放键;选中态描边)
8579
9118
  ".dknt-sounds{display:flex;gap:6px;flex-wrap:wrap;}",
8580
9119
  ".dknt-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);}",
@@ -8597,7 +9136,7 @@ var feature8 = {
8597
9136
  name: "\u4EFB\u52A1\u901A\u77E5",
8598
9137
  order: 140,
8599
9138
  accent: "#f59e0b",
8600
- description: "\u4EFB\u52A1\u5B8C\u6210/\u5F02\u5E38/\u9700\u786E\u8BA4\u901A\u77E5\uFF1A\u9875\u5185\u5361\u7247\u3001\u63D0\u793A\u97F3\u3001\u7CFB\u7EDF\u901A\u77E5\u3001\u9489\u9489/\u98DE\u4E66\u7FA4\u673A\u5668\u4EBA\u63A8\u9001\uFF08\u72EC\u7ACB\u5F00\u5173\uFF09",
9139
+ description: "\u4EFB\u52A1\u5B8C\u6210/\u5F02\u5E38/\u9700\u786E\u8BA4/\u9700\u56DE\u7B54/\u5361\u4F4F\u901A\u77E5\uFF1A\u670D\u52A1\u7AEF\u6216\u672C\u673A\u914D\u7F6E\u3001\u4E8B\u4EF6\xD7\u6E20\u9053\u52FE\u9009\u3001\u9875\u5185\u5361\u7247/\u63D0\u793A\u97F3/\u7CFB\u7EDF\u901A\u77E5/\u8BED\u97F3\u64AD\u62A5/\u9489\u9489\u98DE\u4E66\u63A8\u9001\uFF08\u5404\u81EA\u72EC\u7ACB\u5F00\u5173\uFF09",
8601
9140
  css: css3,
8602
9141
  View: NotifyView,
8603
9142
  HomeStat: NotifyStat,
@@ -8697,16 +9236,20 @@ function useRunState() {
8697
9236
  return snap;
8698
9237
  }
8699
9238
  function waitingOf(active) {
8700
- return (active || []).reduce((n, t) => n + (Array.isArray(t.approvals) ? t.approvals.length : 0), 0);
9239
+ return waitingCountOf(active);
8701
9240
  }
8702
9241
  function TaskCard(props) {
8703
9242
  const t = props.t;
8704
9243
  const info = endInfo2(t.endReason);
8705
- const waiting = !props.done && Array.isArray(t.approvals) && t.approvals.length > 0;
9244
+ const waiting = !props.done && taskWaiting(t);
9245
+ const approvals = taskApprovals(t);
9246
+ const questions = taskQuestions(t);
9247
+ const waitLabel = approvals.length > 0 ? "\u7B49\u5F85\u786E\u8BA4" : questions.length > 0 ? "\u7B49\u5F85\u56DE\u7B54" : "";
9248
+ const waitDetail = approvals.length > 0 ? approvals.map((a) => (a && a.toolName ? a.toolName : "\u672A\u77E5\u5DE5\u5177") + (a && a.reason ? "\uFF1A" + truncate3(a.reason, 80) : "")).join("\uFF1B") : questions.map((q) => (q && q.header ? q.header : "\u63D0\u95EE") + (q && q.question ? "\uFF1A" + truncate3(q.question, 80) : "")).join("\uFF1B");
8706
9249
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-task", children: [
8707
9250
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-task-head", children: [
8708
9251
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-task-title", title: t.title, children: t.title || "(\u65E0\u6807\u9898)" }),
8709
- props.done ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-tag " + info.cls, children: info.label }) : waiting ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-tag warn", children: "\u7B49\u5F85\u786E\u8BA4" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-tag on", children: phaseLabel2(t.phase) })
9252
+ props.done ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-tag " + info.cls, children: info.label }) : waiting ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-tag warn", children: waitLabel }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-tag on", children: phaseLabel2(t.phase) })
8710
9253
  ] }),
8711
9254
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-task-meta", children: [
8712
9255
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: (t.models && t.models.length ? t.models.join(", ") : "\u672A\u77E5") + (t.provider ? "\uFF08" + t.provider + "\uFF09" : "") }),
@@ -8715,7 +9258,7 @@ function TaskCard(props) {
8715
9258
  t.totalTokens ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u21A7" + fmtCompact3(t.inputTokens) + " \u21A5" + fmtCompact3(t.outputTokens) }) : null,
8716
9259
  props.done && t.endTime ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: fmtTime3(t.endTime) }) : null
8717
9260
  ] }),
8718
- waiting ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-task-wait", children: t.approvals.map((a, i) => (a && a.toolName ? a.toolName : "\u672A\u77E5\u5DE5\u5177") + (a && a.reason ? "\uFF1A" + truncate3(a.reason, 80) : "")).join("\uFF1B") }) : null,
9261
+ waiting && waitDetail ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-task-wait", children: waitDetail }) : null,
8719
9262
  props.done && t.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-task-err", children: truncate3(t.errorMessage, 120) }) : null
8720
9263
  ] });
8721
9264
  }
@@ -8725,6 +9268,9 @@ function RunStateView() {
8725
9268
  const active = st && st.active ? st.active : [];
8726
9269
  const recent = st && st.recent ? st.recent.slice(0, 10) : [];
8727
9270
  const waitingCount = waitingOf(active);
9271
+ const waitApprovals = (active || []).reduce((n, t) => n + taskApprovals(t).length, 0);
9272
+ const waitQuestions = (active || []).reduce((n, t) => n + taskQuestions(t).length, 0);
9273
+ const waitBannerHint = waitApprovals > 0 && waitQuestions > 0 ? waitApprovals + " \u9879\u7B49\u6279\u51C6\u3001" + waitQuestions + " \u9879\u7B49\u4F60\u56DE\u7B54" : waitApprovals > 0 ? "\u4EFB\u52A1\u505C\u5728\u9700\u8981\u4F60\u6279\u51C6\u7684\u6B65\u9AA4\u4E0A" : "\u4EFB\u52A1\u5728\u7B49\u4F60\u56DE\u7B54\u95EE\u9898";
8728
9274
  (0, import_react11.useEffect)(() => {
8729
9275
  let stopped = false;
8730
9276
  let timer = null;
@@ -8740,7 +9286,7 @@ function RunStateView() {
8740
9286
  if (timer) clearTimeout(timer);
8741
9287
  };
8742
9288
  }, []);
8743
- const sub = snap.error ? "\u72B6\u6001\u62C9\u53D6\u5931\u8D25\uFF1A" + snap.error : !st ? snap.loading ? "\u6B63\u5728\u62C9\u53D6\u4EFB\u52A1\u72B6\u6001\u2026" : "\u7B49\u5F85\u4EFB\u52A1\u72B6\u6001" : waitingCount > 0 ? waitingCount + " \u9879\u7B49\u5F85\u786E\u8BA4 \xB7 " + active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D" : 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";
9289
+ const sub = snap.error ? "\u72B6\u6001\u62C9\u53D6\u5931\u8D25\uFF1A" + snap.error : !st ? snap.loading ? "\u6B63\u5728\u62C9\u53D6\u4EFB\u52A1\u72B6\u6001\u2026" : "\u7B49\u5F85\u4EFB\u52A1\u72B6\u6001" : waitingCount > 0 ? waitingCount + " \u9879\u7B49\u4F60\u4ECB\u5165 \xB7 " + active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D" : 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";
8744
9290
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-root", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-sec", children: [
8745
9291
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-sec-head", children: [
8746
9292
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-sec-title", children: "\u8FD0\u884C\u72B6\u6001" }),
@@ -8750,7 +9296,9 @@ function RunStateView() {
8750
9296
  waitingCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-waitbanner", children: [
8751
9297
  "\u270B ",
8752
9298
  waitingCount,
8753
- " \u9879\u7B49\u5F85\u786E\u8BA4\uFF1A\u4EFB\u52A1\u505C\u5728\u9700\u8981\u4F60\u6279\u51C6\u7684\u6B65\u9AA4\u4E0A\uFF0C\u8BF7\u5728\u4F1A\u8BDD\u91CC\u5904\u7406\u540E\u7EE7\u7EED\u3002"
9299
+ " \u9879\u7B49\u4F60\u4ECB\u5165\uFF1A",
9300
+ waitBannerHint,
9301
+ "\uFF0C\u8BF7\u5728\u4F1A\u8BDD\u91CC\u5904\u7406\u540E\u7EE7\u7EED\u3002"
8754
9302
  ] }) : null,
8755
9303
  active.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-tasks", children: active.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TaskCard, { t }, t.sessionId)) }) : null,
8756
9304
  !snap.error && active.length === 0 && recent.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-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\uFF08\u52A8\u6548\u89C1\u5DE6\u4FA7\u300C\u4EFB\u52A1\u52A8\u753B\u300D\uFF0C\u63D0\u9192\u89C1\u300C\u4EFB\u52A1\u901A\u77E5\u300D\uFF09\u3002" }) : null,
@@ -8775,7 +9323,7 @@ function RunStateStat(props) {
8775
9323
  if (waiting > 0) return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "dkrs-warn", children: [
8776
9324
  "\u270B ",
8777
9325
  waiting,
8778
- " \u9879\u7B49\u5F85\u786E\u8BA4 \xB7 ",
9326
+ " \u9879\u7B49\u4F60\u4ECB\u5165 \xB7 ",
8779
9327
  active.length,
8780
9328
  " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D"
8781
9329
  ] });
@@ -8797,7 +9345,7 @@ var css4 = [
8797
9345
  ".dkrs-sec-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);flex:1;min-width:120px;}",
8798
9346
  ".dkrs-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;}",
8799
9347
  ".dkrs-refresh:hover{background:var(--dsw-alias-interactive-bg-hover);}",
8800
- // 等待确认横幅:琥珀描边,常驻在列表上方(任务卡各自也带「等待确认」标签)
9348
+ // 等人介入横幅:琥珀描边,常驻在列表上方(任务卡各自也带「等待确认」/「等待回答」标签)
8801
9349
  ".dkrs-waitbanner{border:1px solid color-mix(in srgb,var(--dk-warn) 45%,transparent);background:color-mix(in srgb,var(--dk-warn) 10%,transparent);color:var(--dk-warn);border-radius:8px;padding:6px 10px;font-size:12px;line-height:1.6;}",
8802
9350
  ".dkrs-done-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);}",
8803
9351
  // 任务列表
@@ -8820,7 +9368,7 @@ var feature9 = {
8820
9368
  name: "\u8FD0\u884C\u72B6\u6001",
8821
9369
  order: 150,
8822
9370
  accent: "#38bdf8",
8823
- description: "\u4EFB\u52A1\u8FD0\u884C\u72B6\u6001\u4E00\u89C8\uFF1A\u8FDB\u884C\u4E2D\u4EFB\u52A1\u7684\u9636\u6BB5 / \u8017\u65F6 / Token / \u7B49\u5F85\u786E\u8BA4\u4E0E\u6700\u8FD1\u5B8C\u6210\u8BB0\u5F55\uFF08\u53EA\u8BFB\uFF09",
9371
+ description: "\u4EFB\u52A1\u8FD0\u884C\u72B6\u6001\u4E00\u89C8\uFF1A\u8FDB\u884C\u4E2D\u4EFB\u52A1\u7684\u9636\u6BB5 / \u8017\u65F6 / Token / \u7B49\u4EBA\u4ECB\u5165\uFF08\u7B49\u6279\u51C6 / \u7B49\u56DE\u7B54\uFF09\u4E0E\u6700\u8FD1\u5B8C\u6210\u8BB0\u5F55\uFF08\u53EA\u8BFB\uFF09",
8824
9372
  css: css4,
8825
9373
  View: RunStateView,
8826
9374
  HomeStat: RunStateStat
@@ -14006,285 +14554,329 @@ var feature12 = {
14006
14554
  // features/mobile/view.js
14007
14555
  var import_react24 = __toESM(require("react"), 1);
14008
14556
  var import_react25 = require("react");
14009
- var MOBILE_QUERY_NARROW = "(max-width: 820px)";
14010
- var MOBILE_QUERY_COARSE = "(pointer: coarse) and (hover: none)";
14011
- var MOBILE_QUERY_CHROME = "(max-width: 700px)";
14557
+ var MOBILE_QUERY = "(max-width: 767px)";
14558
+ var COARSE_QUERY = "(pointer: coarse) and (hover: none)";
14012
14559
  function mobileActive() {
14013
14560
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
14014
14561
  try {
14015
- return window.matchMedia(MOBILE_QUERY_NARROW).matches || window.matchMedia(MOBILE_QUERY_COARSE).matches;
14562
+ return window.matchMedia(MOBILE_QUERY).matches || window.matchMedia(COARSE_QUERY).matches;
14016
14563
  } catch {
14017
14564
  return false;
14018
14565
  }
14019
14566
  }
14020
- function watchQuery(query, onChange) {
14021
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return () => {
14567
+ var MOBILE_CSS = [
14568
+ "/* \u89E6\u63A7\u4E0E\u8F93\u5165\uFF1A\u7C97\u6307\u9488\u771F\u673A\uFF08\u4E0D\u5206\u5BBD\u5EA6\uFF09 */",
14569
+ "@media (pointer: coarse) and (hover: none){",
14570
+ ' body[data-dk-mobile="1"] :is(textarea,input:not([type]),input[type="text"],input[type="search"],input[type="url"],input[type="password"],input[type="number"],input[type="email"],[contenteditable="true"]){font-size:16px !important;}',
14571
+ ' body[data-dk-mobile="1"] :is(button,[role="button"]){-webkit-tap-highlight-color:transparent;touch-action:manipulation;}',
14572
+ "}",
14573
+ "@media (max-width:767px){",
14574
+ ' body[data-dk-mobile="1"] :is(textarea,input:not([type]),input[type="text"],input[type="search"],input[type="url"],input[type="password"],input[type="number"],input[type="email"],[contenteditable="true"]){font-size:16px !important;}',
14575
+ ' body[data-dk-mobile="1"] :is(button,[role="button"]){-webkit-tap-highlight-color:transparent;touch-action:manipulation;}',
14576
+ ' body[data-dk-mobile="1"] pre{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;}',
14577
+ ' body[data-dk-mobile="1"] code{overflow-wrap:anywhere;}',
14578
+ ' body[data-dk-mobile="1"] pre code{overflow-wrap:normal;}',
14579
+ ' body[data-dk-mobile="1"] .dockchip-row{display:none;}',
14580
+ ' body[data-dk-mobile="1"] [data-sidebar-opener]{position:relative;}',
14581
+ ' body[data-dk-mobile="1"] [data-sidebar-opener]::after{content:"";position:absolute;left:50%;top:50%;width:44px;height:44px;transform:translate(-50%,-50%);}',
14582
+ ' body[data-dk-mobile="1"] [role="dialog"][class*="panel"] [class*="options"]{padding-left:max(16px,env(safe-area-inset-left,0px));padding-right:max(16px,env(safe-area-inset-right,0px));}',
14583
+ ' body[data-dk-mobile="1"] [class*="scrollBody"]{padding-bottom:env(safe-area-inset-bottom,0px) !important;}',
14584
+ " /* \u529F\u80FD\u575E\u9762\u677F\uFF08.dockm-*\uFF09\u6302\u5728 .overlayLayer(z20) \u5185\uFF0C\u800C\u624B\u673A\u62BD\u5C49 .sidebarCol \u662F z71\u2014\u2014\u9762\u677F\u867D\u662F\u5168\u5C4F\u5374\u88AB\u62BD\u5C49\u76D6\u4F4F\u3002\u628A overlayLayer \u62AC\u5230\u62BD\u5C49\u4E4B\u4E0A\uFF0C\u529F\u80FD\u575E/\u5168\u5C40\u6D6E\u5C42\u624D\u80FD\u5168\u5C4F\u76D6\u4F4F\u62BD\u5C49\u3002 */",
14585
+ ' body[data-dk-mobile="1"] [class*="overlayLayer"]{z-index:100 !important;}',
14586
+ ' body[data-dk-mobile="1"] [role="dialog"][class*="panel"][data-dsh-mobile-stack]{display:flex !important;flex-direction:column !important;width:100vw !important;max-width:100vw !important;height:100dvh !important;max-height:none !important;border-radius:0 !important;overflow:hidden !important;}',
14587
+ ' body[data-dk-mobile="1"] [role="dialog"][class*="panel"][data-dsh-mobile-stack] > [class*="header"]{order:0;flex:none;width:auto !important;height:auto !important;padding:8px 12px !important;justify-content:flex-end !important;}',
14588
+ ' body[data-dk-mobile="1"] [role="dialog"][class*="panel"][data-dsh-mobile-stack] > [class*="navTitle"]{order:1;flex:none;width:auto !important;padding:2px 16px 8px !important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}',
14589
+ ' body[data-dk-mobile="1"] [role="dialog"][class*="panel"][data-dsh-mobile-stack] > nav{order:2;flex:none;width:auto !important;height:auto !important;padding:0 8px 8px !important;overflow-x:auto;overflow-y:hidden;}',
14590
+ ' body[data-dk-mobile="1"] [role="dialog"][class*="panel"][data-dsh-mobile-stack] > nav [class*="navList"]{flex-direction:row !important;}',
14591
+ ' body[data-dk-mobile="1"] [role="dialog"][class*="panel"][data-dsh-mobile-stack] > [class*="options"]{order:3;flex:1 1 auto !important;min-height:0 !important;width:auto !important;overflow-y:auto !important;padding-bottom:max(16px,env(safe-area-inset-bottom,0px)) !important;}',
14592
+ ' body[data-dk-mobile="1"][data-dsh-mobile-legacy] [class$="frame"]{grid-template-columns:0px minmax(0,1fr) 0px !important;}',
14593
+ ' body[data-dk-mobile="1"][data-dsh-mobile-legacy] [class$="frame"] [class*="sidebarCol"]{position:fixed !important;top:0 !important;bottom:0 !important;left:0 !important;width:min(86vw,300px) !important;z-index:80 !important;box-shadow:0 12px 48px rgba(0,0,0,.45);transform:none !important;visibility:visible !important;transition:transform .22s ease !important;}',
14594
+ ' body[data-dk-mobile="1"][data-dsh-mobile-legacy] [class$="frame"][data-sidebar-collapsed] [class*="sidebarCol"]{transform:translateX(-105%) !important;visibility:hidden !important;transition:transform .22s ease, visibility 0s linear .22s !important;}',
14595
+ ' body[data-dk-mobile="1"] .dsh-mobile-scrim{position:fixed;inset:0;z-index:75;background:rgba(8,10,14,.45);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);touch-action:none;}',
14596
+ ' body[data-dk-mobile="1"] .dsh-mobile-burger{position:fixed;left:calc(4px + env(safe-area-inset-left,0px));top:calc(4px + env(safe-area-inset-top,0px));z-index:66;box-sizing:border-box;width:44px;height:44px;display:flex;align-items:center;justify-content:center;padding:0;border:0;background:transparent;color:var(--dsw-alias-label-primary,#e6eaf2);-webkit-tap-highlight-color:transparent;touch-action:manipulation;}',
14597
+ ' body[data-dk-mobile="1"] .dsh-mobile-burger svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;}',
14598
+ ' body[data-dk-mobile="1"] .dsh-mobile-burger:active{background:color-mix(in srgb,currentColor 12%,transparent);}',
14599
+ ' body[data-dk-mobile="1"][data-dsh-mobile-legacy] [class$="frame"] header:has([class*="titleRow"]){padding-left:calc(48px + env(safe-area-inset-left,0px));}',
14600
+ ' html.dsh-dock-kbd body[data-dk-mobile="1"] .dsh-mobile-burger{display:none !important;}',
14601
+ "}"
14602
+ ].join("\n");
14603
+ var STYLE_ATTR = "data-dsh-mobile-runtime";
14604
+ var BODY_ATTR = "data-dk-mobile";
14605
+ var LEGACY_ATTR = "data-dsh-mobile-legacy";
14606
+ var currentDispose = null;
14607
+ function applyRuntime() {
14608
+ if (typeof window === "undefined" || typeof document === "undefined") return function() {
14022
14609
  };
14023
- let mq = null;
14024
- try {
14025
- mq = window.matchMedia(query);
14026
- } catch {
14027
- return () => {
14028
- };
14029
- }
14030
- const update = () => onChange(mq.matches);
14031
- update();
14032
- if (typeof mq.addEventListener === "function") mq.addEventListener("change", update);
14033
- else if (typeof mq.addListener === "function") mq.addListener(update);
14034
- return () => {
14035
- if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", update);
14036
- else if (typeof mq.removeListener === "function") mq.removeListener(update);
14610
+ const doc = document;
14611
+ const body = doc.body;
14612
+ if (!body) return function() {
14037
14613
  };
14038
- }
14039
- function MobileOverlay() {
14040
- const [active, setActive] = (0, import_react25.useState)(() => mobileActive());
14041
- (0, import_react25.useEffect)(() => {
14042
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
14043
- let mqs = [];
14614
+ if (currentDispose) {
14044
14615
  try {
14045
- mqs = [window.matchMedia(MOBILE_QUERY_NARROW), window.matchMedia(MOBILE_QUERY_COARSE)];
14046
- } catch {
14047
- return void 0;
14048
- }
14049
- const update = () => setActive(mqs.some((mq) => mq.matches));
14050
- update();
14051
- for (const mq of mqs) {
14052
- if (typeof mq.addEventListener === "function") mq.addEventListener("change", update);
14053
- else if (typeof mq.addListener === "function") mq.addListener(update);
14054
- }
14055
- return () => {
14056
- for (const mq of mqs) {
14057
- if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", update);
14058
- else if (typeof mq.removeListener === "function") mq.removeListener(update);
14059
- }
14060
- };
14061
- }, []);
14062
- (0, import_react25.useEffect)(() => {
14063
- if (typeof document === "undefined") return void 0;
14064
- if (active) {
14065
- document.body.setAttribute("data-dk-mobile", "1");
14066
- try {
14067
- const meta = document.querySelector('meta[name="viewport"]');
14068
- if (meta && !/(^|,)\s*viewport-fit\s*=/.test(meta.content || "")) {
14069
- meta.setAttribute("content", (meta.content || "width=device-width, initial-scale=1") + ", viewport-fit=cover");
14070
- }
14071
- } catch {
14072
- }
14073
- } else {
14074
- document.body.removeAttribute("data-dk-mobile");
14616
+ currentDispose();
14617
+ } catch (e) {
14075
14618
  }
14076
- return () => {
14077
- document.body.removeAttribute("data-dk-mobile");
14078
- };
14079
- }, [active]);
14080
- (0, import_react25.useEffect)(() => mobileChrome(), []);
14081
- return null;
14082
- }
14083
- function mobileChrome() {
14084
- if (typeof window === "undefined" || typeof document === "undefined") return void 0;
14085
- const mq = window.matchMedia ? window.matchMedia(MOBILE_QUERY_CHROME) : null;
14086
- if (!mq) return void 0;
14087
- if (window.__dshDockMobileDrawer === "host") return void 0;
14088
- window.__dshDockMobileDrawer = "client";
14089
- const narrow = () => mq.matches;
14090
- const frameEl = () => document.querySelector('[class$="frame"]');
14091
- const sidebarCollapsed = () => {
14092
- const f = frameEl();
14093
- return !!f && f.hasAttribute("data-sidebar-collapsed");
14619
+ currentDispose = null;
14620
+ }
14621
+ body.setAttribute(BODY_ATTR, "1");
14622
+ let styleEl = doc.querySelector("style[" + STYLE_ATTR + "]");
14623
+ if (!styleEl) {
14624
+ styleEl = doc.createElement("style");
14625
+ styleEl.setAttribute(STYLE_ATTR, "");
14626
+ styleEl.textContent = MOBILE_CSS;
14627
+ doc.head.appendChild(styleEl);
14628
+ }
14629
+ const mql = window.matchMedia ? window.matchMedia(MOBILE_QUERY) : null;
14630
+ const vv = window.visualViewport || null;
14631
+ const phone = function() {
14632
+ return !!(mql && mql.matches);
14094
14633
  };
14095
- const dialogOpen = () => !!document.querySelector('[role="dialog"][class*="panel"]');
14096
- const rightOpen = () => !!document.querySelector("[data-sidebar-right-panel][data-sidebar-right-open]");
14097
- const collapse = () => {
14098
- const b = document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
14099
- if (b) b.click();
14634
+ const frame = function() {
14635
+ return doc.querySelector('[class$="frame"]');
14100
14636
  };
14101
- const expand = () => {
14102
- const b = document.querySelector('button[aria-label="\u6253\u5F00\u4FA7\u8FB9\u680F"],button[aria-label="Open sidebar"]');
14103
- if (b) b.click();
14637
+ const isCollapsed = function() {
14638
+ const f = frame();
14639
+ return !!(f && f.hasAttribute("data-sidebar-collapsed"));
14104
14640
  };
14105
- const closeDetails = () => {
14106
- const panel = document.querySelector("[data-sidebar-right-panel][data-sidebar-right-open]");
14641
+ let scrim = null;
14642
+ let burger = null;
14643
+ let observer = null;
14644
+ let timer = 0;
14645
+ function sidebarOpenToggle() {
14646
+ const b = doc.querySelector("[data-sidebar-opener]") || doc.querySelector("[data-sidebar-toggle]");
14647
+ if (b && typeof b.click === "function") b.click();
14648
+ }
14649
+ function clearStack() {
14650
+ const panels = doc.querySelectorAll('[role="dialog"][class*="panel"][data-dsh-mobile-stack]');
14651
+ for (let i = 0; i < panels.length; i++) panels[i].removeAttribute("data-dsh-mobile-stack");
14652
+ }
14653
+ function dialogStackSync() {
14654
+ const panel = doc.querySelector('[role="dialog"][class*="panel"]');
14107
14655
  if (!panel) return;
14108
- const toggle = panel.querySelector("[data-sidebar-right-toggle]");
14109
- if (toggle) toggle.click();
14110
- };
14111
- const scrim = document.createElement("div");
14112
- scrim.className = "dsh-mobile-scrim";
14113
- document.body.appendChild(scrim);
14114
- document.querySelectorAll(".dsh-mobile-tabbar").forEach((el) => el.remove());
14115
- const burger = document.createElement("button");
14116
- burger.type = "button";
14117
- burger.className = "dsh-mobile-burger";
14118
- burger.setAttribute("aria-label", "\u6253\u5F00\u4F1A\u8BDD\u5217\u8868");
14119
- burger.setAttribute("aria-expanded", "false");
14120
- burger.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7h16"/><path d="M4 12h16"/><path d="M4 17h16"/></svg><span class="dsh-mobile-burger-badge" hidden></span>';
14121
- burger.addEventListener("click", () => expand());
14122
- document.body.appendChild(burger);
14123
- const syncBurger = () => {
14124
- const expanded = !sidebarCollapsed();
14125
- burger.setAttribute("aria-expanded", expanded ? "true" : "false");
14126
- burger.classList.toggle("on", expanded);
14127
- };
14128
- const badge = burger.querySelector(".dsh-mobile-burger-badge");
14129
- let runstateGone = false;
14130
- const pollTasks = () => {
14131
- if (runstateGone || !badge || !narrow() || document.visibilityState === "hidden" || !burger.isConnected) return;
14132
- const on = stateOf("runstate").enabled !== false;
14133
- if (!on && !window.__dshDockRunstate) {
14134
- badge.hidden = true;
14656
+ let nav = null;
14657
+ let opt = null;
14658
+ const kids = panel.children;
14659
+ for (let i = 0; i < kids.length; i++) {
14660
+ const k = kids[i];
14661
+ if (!nav && k.tagName === "NAV") nav = k;
14662
+ if (!opt && k.className && String(k.className).indexOf("options") >= 0) opt = k;
14663
+ }
14664
+ if (!nav || !opt) {
14665
+ panel.removeAttribute("data-dsh-mobile-stack");
14135
14666
  return;
14136
14667
  }
14137
- fetch("dsh-dock/runstate/status", {
14138
- method: "POST",
14139
- headers: { "content-type": "application/json" },
14140
- body: "{}"
14141
- }).then(async (res) => {
14142
- if (res.status === 404 || res.status === 405) {
14143
- runstateGone = true;
14144
- badge.hidden = true;
14145
- return null;
14146
- }
14147
- const body = await res.json().catch(() => null);
14148
- if (!body) return null;
14149
- const active = body.data && body.data.active || [];
14150
- const waiting = active.reduce((n, t) => n + (Array.isArray(t.approvals) ? t.approvals.length : 0), 0);
14151
- if (waiting > 0) {
14152
- badge.textContent = waiting > 99 ? "99+" : String(waiting);
14153
- badge.className = "dsh-mobile-burger-badge wait";
14154
- badge.hidden = false;
14155
- burger.setAttribute("title", waiting + " \u4E2A\u4EFB\u52A1\u7B49\u5F85\u4F60\u786E\u8BA4");
14156
- } else if (active.length > 0) {
14157
- badge.textContent = active.length > 99 ? "99+" : String(active.length);
14158
- badge.className = "dsh-mobile-burger-badge";
14159
- badge.hidden = false;
14160
- burger.setAttribute("title", active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D");
14668
+ const a = nav.getBoundingClientRect();
14669
+ const b = opt.getBoundingClientRect();
14670
+ if (!a.width || !b.width) return;
14671
+ const sideBySide = b.left >= a.right - 8 && b.top < a.bottom - 4 && b.bottom > a.top + 4;
14672
+ if (sideBySide) panel.setAttribute("data-dsh-mobile-stack", "1");
14673
+ else panel.removeAttribute("data-dsh-mobile-stack");
14674
+ }
14675
+ function removeChrome() {
14676
+ if (scrim) {
14677
+ scrim.remove();
14678
+ scrim = null;
14679
+ }
14680
+ if (burger) {
14681
+ burger.remove();
14682
+ burger = null;
14683
+ }
14684
+ body.removeAttribute(LEGACY_ATTR);
14685
+ }
14686
+ function ensureChrome() {
14687
+ if (!scrim) {
14688
+ scrim = doc.createElement("div");
14689
+ scrim.className = "dsh-mobile-scrim";
14690
+ scrim.style.display = "none";
14691
+ scrim.addEventListener("click", function() {
14692
+ if (!isCollapsed()) sidebarOpenToggle();
14693
+ });
14694
+ body.appendChild(scrim);
14695
+ }
14696
+ if (!burger) {
14697
+ burger = doc.createElement("button");
14698
+ burger.type = "button";
14699
+ burger.className = "dsh-mobile-burger";
14700
+ burger.setAttribute("aria-label", "\u6253\u5F00\u4F1A\u8BDD\u5217\u8868");
14701
+ burger.setAttribute("aria-expanded", "false");
14702
+ burger.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7h16"/><path d="M4 12h16"/><path d="M4 17h16"/></svg>';
14703
+ burger.addEventListener("click", function() {
14704
+ sidebarOpenToggle();
14705
+ });
14706
+ body.appendChild(burger);
14707
+ }
14708
+ }
14709
+ function legacySync() {
14710
+ const f = frame();
14711
+ const legacy = !!f && phone() && !f.hasAttribute("data-sidebar-drawer");
14712
+ if (!legacy) {
14713
+ removeChrome();
14714
+ return;
14715
+ }
14716
+ body.setAttribute(LEGACY_ATTR, "1");
14717
+ ensureChrome();
14718
+ const collapsed = isCollapsed();
14719
+ if (scrim) scrim.style.display = collapsed ? "none" : "";
14720
+ if (burger) {
14721
+ burger.style.display = "";
14722
+ burger.setAttribute("aria-expanded", collapsed ? "false" : "true");
14723
+ }
14724
+ }
14725
+ function kbdSync() {
14726
+ if (!vv) return;
14727
+ const kbd = vv.height > 0 && window.innerHeight - vv.height > 120;
14728
+ const de = doc.documentElement;
14729
+ if (kbd) de.classList.add("dsh-dock-kbd");
14730
+ else de.classList.remove("dsh-dock-kbd");
14731
+ }
14732
+ let dockAutoClosed = false;
14733
+ function dockOpen() {
14734
+ return !!doc.querySelector(".dockm-dialog");
14735
+ }
14736
+ function tick() {
14737
+ try {
14738
+ kbdSync();
14739
+ if (phone()) {
14740
+ const dopen = dockOpen();
14741
+ if (dopen && !isCollapsed() && !dockAutoClosed) {
14742
+ dockAutoClosed = true;
14743
+ sidebarOpenToggle();
14744
+ }
14745
+ if (!dopen) dockAutoClosed = false;
14746
+ dialogStackSync();
14747
+ legacySync();
14161
14748
  } else {
14162
- badge.hidden = true;
14163
- burger.removeAttribute("title");
14749
+ clearStack();
14750
+ removeChrome();
14751
+ dockAutoClosed = false;
14164
14752
  }
14165
- }).catch(() => {
14753
+ } catch (e) {
14754
+ }
14755
+ }
14756
+ tick();
14757
+ if (typeof MutationObserver !== "undefined") {
14758
+ observer = new MutationObserver(function() {
14759
+ tick();
14166
14760
  });
14761
+ try {
14762
+ observer.observe(doc.documentElement, { attributes: true, attributeFilter: ["data-sidebar-collapsed", "data-sidebar-drawer"], subtree: true });
14763
+ observer.observe(body, { childList: true, subtree: true });
14764
+ } catch (e) {
14765
+ }
14766
+ }
14767
+ timer = window.setInterval(tick, 1200);
14768
+ const onResize = function() {
14769
+ tick();
14167
14770
  };
14168
- const tasksTimer = setInterval(pollTasks, 3e3);
14169
- const onVisible = () => {
14170
- if (document.visibilityState === "visible") pollTasks();
14171
- };
14172
- document.addEventListener("visibilitychange", onVisible);
14173
- pollTasks();
14174
- const vv = window.visualViewport || null;
14175
- const kbdSync = () => {
14176
- if (!vv) return;
14177
- const kbd = vv.height > 0 && window.innerHeight - vv.height > 120;
14178
- document.documentElement.classList.toggle("dsh-dock-kbd", kbd);
14179
- };
14180
- const sync = () => {
14181
- kbdSync();
14182
- document.querySelectorAll(".dsh-mobile-tabbar").forEach((el) => el.remove());
14183
- const on = narrow() && !!frameEl() && !dialogOpen();
14184
- const collapsed = sidebarCollapsed();
14185
- const right = rightOpen();
14186
- if (scrim) scrim.style.display = on && !collapsed ? "" : "none";
14187
- burger.style.display = narrow() && !!frameEl() && !panelNav.open && !right ? "" : "none";
14188
- syncBurger();
14189
- };
14190
- sync();
14191
- const observer = typeof MutationObserver !== "undefined" ? new MutationObserver(sync) : null;
14192
- if (observer) observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-sidebar-collapsed"], subtree: true });
14193
- const timer = setInterval(sync, 1500);
14194
- const onMq = () => sync();
14195
- if (mq.addEventListener) mq.addEventListener("change", onMq);
14196
- else if (mq.addListener) mq.addListener(onMq);
14197
- window.addEventListener("resize", kbdSync);
14771
+ window.addEventListener("resize", onResize);
14198
14772
  if (vv && vv.addEventListener) vv.addEventListener("resize", kbdSync);
14199
- const onClick = (e) => {
14200
- if (!narrow()) return;
14201
- const t = e.target;
14202
- if (!t || !t.closest) return;
14203
- if (t.closest(".dsh-mobile-burger")) return;
14204
- const expanded = !!document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
14205
- const col = document.querySelector('[class*="sidebarCol"]');
14206
- const inSidebar = col && col.contains(t);
14207
- if (!expanded && !inSidebar) return;
14208
- if (inSidebar) {
14209
- const row = t.closest('[role="treeitem"]');
14210
- const rowKey = row && row.getAttribute("data-row-key") || "";
14211
- const sessionRow = rowKey && rowKey.startsWith("session:") || row && !rowKey && !row.querySelector('[role="treeitem"]') && row.closest('[role="tree"]');
14212
- const fresh = t.closest('[class*="newSession"]');
14213
- if (sessionRow || fresh) {
14214
- setTimeout(() => {
14215
- collapse();
14216
- closeDetails();
14217
- }, 300);
14218
- return;
14219
- }
14220
- if (rowKey.startsWith("workspace:")) return;
14221
- setTimeout(() => {
14222
- if (document.querySelector('[role="dialog"]')) collapse();
14223
- }, 260);
14224
- return;
14773
+ if (mql && mql.addEventListener) mql.addEventListener("change", tick);
14774
+ else if (mql && mql.addListener) mql.addListener(tick);
14775
+ const dispose = function() {
14776
+ if (currentDispose === dispose) currentDispose = null;
14777
+ try {
14778
+ if (observer) observer.disconnect();
14779
+ } catch (e) {
14225
14780
  }
14226
- if (t.closest('[role="dialog"],[class*="dockm"],[class*="dgfab"],[class*="dgwin"],[class*="dgame"],[data-sidebar-right-panel]')) return;
14227
- collapse();
14228
- };
14229
- document.addEventListener("click", onClick, true);
14230
- return () => {
14231
- document.removeEventListener("click", onClick, true);
14232
- if (observer) observer.disconnect();
14233
- clearInterval(timer);
14234
- clearInterval(tasksTimer);
14235
- document.removeEventListener("visibilitychange", onVisible);
14236
- if (mq.removeEventListener) mq.removeEventListener("change", onMq);
14237
- else if (mq.removeListener) mq.removeListener(onMq);
14238
- window.removeEventListener("resize", kbdSync);
14781
+ if (timer) window.clearInterval(timer);
14782
+ window.removeEventListener("resize", onResize);
14239
14783
  if (vv && vv.removeEventListener) vv.removeEventListener("resize", kbdSync);
14240
- document.documentElement.classList.remove("dsh-dock-kbd");
14241
- if (scrim) scrim.remove();
14242
- burger.remove();
14243
- if (window.__dshDockMobileDrawer === "client") delete window.__dshDockMobileDrawer;
14784
+ if (mql && mql.removeEventListener) mql.removeEventListener("change", tick);
14785
+ else if (mql && mql.removeListener) mql.removeListener(tick);
14786
+ try {
14787
+ doc.documentElement.classList.remove("dsh-dock-kbd");
14788
+ } catch (e) {
14789
+ }
14790
+ try {
14791
+ clearStack();
14792
+ } catch (e) {
14793
+ }
14794
+ removeChrome();
14795
+ try {
14796
+ body.removeAttribute(BODY_ATTR);
14797
+ } catch (e) {
14798
+ }
14799
+ try {
14800
+ if (styleEl && styleEl.parentNode) styleEl.parentNode.removeChild(styleEl);
14801
+ } catch (e) {
14802
+ }
14244
14803
  };
14804
+ currentDispose = dispose;
14805
+ return dispose;
14245
14806
  }
14246
- function useViewportSize() {
14247
- const [size, setSize] = (0, import_react25.useState)(() => typeof window === "undefined" ? null : { w: window.innerWidth, h: window.innerHeight });
14248
- (0, import_react25.useEffect)(() => {
14249
- if (typeof window === "undefined") return void 0;
14250
- const update = () => setSize({ w: window.innerWidth, h: window.innerHeight });
14251
- window.addEventListener("resize", update);
14252
- return () => window.removeEventListener("resize", update);
14253
- }, []);
14254
- return size;
14255
- }
14256
- function useMobileState() {
14257
- const [active, setActive] = (0, import_react25.useState)(() => mobileActive());
14258
- const [chrome, setChrome] = (0, import_react25.useState)(() => typeof window === "undefined" || typeof window.matchMedia !== "function" ? false : window.matchMedia(MOBILE_QUERY_CHROME).matches);
14259
- const [owner, setOwner] = (0, import_react25.useState)(() => typeof window === "undefined" ? null : window.__dshDockMobileDrawer || null);
14260
- (0, import_react25.useEffect)(() => {
14261
- const offChrome = watchQuery(MOBILE_QUERY_CHROME, setChrome);
14807
+ function MobileOverlay() {
14808
+ const [active, setActive] = (0, import_react25.useState)(function() {
14809
+ return mobileActive();
14810
+ });
14811
+ (0, import_react25.useEffect)(function() {
14812
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
14262
14813
  let mqs = [];
14263
14814
  try {
14264
- mqs = [window.matchMedia(MOBILE_QUERY_NARROW), window.matchMedia(MOBILE_QUERY_COARSE)];
14265
- } catch {
14266
- mqs = [];
14815
+ mqs = [window.matchMedia(MOBILE_QUERY), window.matchMedia(COARSE_QUERY)];
14816
+ } catch (e) {
14817
+ return void 0;
14267
14818
  }
14268
- const compute = () => setActive(mqs.some((mq) => mq.matches));
14269
- for (const mq of mqs) {
14270
- if (typeof mq.addEventListener === "function") mq.addEventListener("change", compute);
14271
- else if (typeof mq.addListener === "function") mq.addListener(compute);
14819
+ const update = function() {
14820
+ setActive(mqs.some(function(m) {
14821
+ return m.matches;
14822
+ }));
14823
+ };
14824
+ update();
14825
+ for (let i = 0; i < mqs.length; i++) {
14826
+ const m = mqs[i];
14827
+ if (m.addEventListener) m.addEventListener("change", update);
14828
+ else if (m.addListener) m.addListener(update);
14272
14829
  }
14273
- const timer = setInterval(() => setOwner(typeof window === "undefined" ? null : window.__dshDockMobileDrawer || null), 1e3);
14274
- return () => {
14275
- offChrome();
14276
- for (const mq of mqs) {
14277
- if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", compute);
14278
- else if (typeof mq.removeListener === "function") mq.removeListener(compute);
14830
+ return function() {
14831
+ for (let i = 0; i < mqs.length; i++) {
14832
+ const m = mqs[i];
14833
+ if (m.removeEventListener) m.removeEventListener("change", update);
14834
+ else if (m.removeListener) m.removeListener(update);
14279
14835
  }
14280
- clearInterval(timer);
14281
14836
  };
14282
14837
  }, []);
14283
- return { active, chrome, owner };
14838
+ (0, import_react25.useEffect)(function() {
14839
+ if (!active) return void 0;
14840
+ return applyRuntime();
14841
+ }, [active]);
14842
+ return null;
14843
+ }
14844
+ function useViewport() {
14845
+ const [size, setSize] = (0, import_react25.useState)(function() {
14846
+ return typeof window === "undefined" ? null : { w: window.innerWidth, h: window.innerHeight };
14847
+ });
14848
+ (0, import_react25.useEffect)(function() {
14849
+ if (typeof window === "undefined") return void 0;
14850
+ const update = function() {
14851
+ setSize({ w: window.innerWidth, h: window.innerHeight });
14852
+ };
14853
+ window.addEventListener("resize", update);
14854
+ return function() {
14855
+ window.removeEventListener("resize", update);
14856
+ };
14857
+ }, []);
14858
+ return size;
14284
14859
  }
14285
14860
  function MobileView() {
14286
- const { active, chrome, owner } = useMobileState();
14287
- const size = useViewportSize();
14861
+ const size = useViewport();
14862
+ const [active, setActive] = (0, import_react25.useState)(function() {
14863
+ return mobileActive();
14864
+ });
14865
+ const [drawer, setDrawer] = (0, import_react25.useState)(false);
14866
+ (0, import_react25.useEffect)(function() {
14867
+ if (typeof window === "undefined") return void 0;
14868
+ const tick = function() {
14869
+ setActive(mobileActive());
14870
+ const f = document.querySelector('[class$="frame"]');
14871
+ setDrawer(!!(f && f.hasAttribute("data-sidebar-drawer")));
14872
+ };
14873
+ tick();
14874
+ const t = setInterval(tick, 1e3);
14875
+ return function() {
14876
+ clearInterval(t);
14877
+ };
14878
+ }, []);
14879
+ const mode = !active ? "\u672A\u547D\u4E2D" : window.matchMedia && window.matchMedia(MOBILE_QUERY).matches ? drawer ? "\u62BD\u5C49\u6A21\u5F0F\uFF08\u539F\u751F\uFF09" : "\u65E7\u7248\u515C\u5E95\uFF08\u6D6E\u5C42\u62BD\u5C49\uFF09" : "\u4EC5\u89E6\u63A7\u4F18\u5316";
14288
14880
  return import_react24.default.createElement(
14289
14881
  "div",
14290
14882
  { className: "dkmob-root" },
@@ -14293,163 +14885,45 @@ function MobileView() {
14293
14885
  { className: "dkmob-row" },
14294
14886
  import_react24.default.createElement("span", { className: "dkmob-label" }, "\u624B\u673A\u6A21\u5F0F"),
14295
14887
  import_react24.default.createElement("span", { className: "dkmob-state" + (active ? " on" : "") }, active ? "\u5DF2\u547D\u4E2D" : "\u672A\u547D\u4E2D"),
14296
- import_react24.default.createElement(
14297
- "span",
14298
- { className: "dkmob-dim" },
14299
- size ? size.w + "\xD7" + size.h + "px" : "",
14300
- "\uFF08\u2264820px \u5BBD\uFF0C\u6216\u4E3B\u6307\u9488\u4E3A\u89E6\u5C4F\u65E0\u60AC\u505C\u65F6\u547D\u4E2D\uFF1B\u684C\u9762\u628A\u7A97\u53E3\u62D6\u7A84\u4E5F\u4F1A\u547D\u4E2D\uFF0C\u65B9\u4FBF\u8C03\u8BD5\uFF09"
14301
- )
14888
+ import_react24.default.createElement("span", { className: "dkmob-dim" }, size ? size.w + "\xD7" + size.h + "px" : "")
14302
14889
  ),
14303
14890
  import_react24.default.createElement(
14304
14891
  "div",
14305
14892
  { className: "dkmob-row" },
14306
- import_react24.default.createElement("span", { className: "dkmob-label" }, "\u624B\u673A\u7AEF chrome"),
14307
- import_react24.default.createElement("span", { className: "dkmob-state" + (chrome ? " on" : "") }, chrome ? "\u2264700px\uFF0C\u751F\u6548\u4E2D" : "\u672A\u547D\u4E2D"),
14308
- import_react24.default.createElement(
14309
- "span",
14310
- { className: "dkmob-dim" },
14311
- "\u5DE6\u4E0A\u89D2\u6C49\u5821\u83DC\u5355\uFF08\u5C55\u5F00\u5DE6\u4FA7\u4F1A\u8BDD\u62BD\u5C49\uFF09+ \u4FA7\u680F\u62BD\u5C49\u906E\u7F69 + \u8F6F\u952E\u76D8\u8BA9\u4F4D\uFF1B\u5E95\u90E8 Tab \u680F\u5DF2\u6309\u7528\u6237\u8981\u6C42\u79FB\u9664\uFF0C\u63D2\u4EF6/\u8BBE\u7F6E\u7B49\u5165\u53E3\u5728\u62BD\u5C49\u91CC\u3002",
14312
- owner === "host" ? "\u5F53\u524D\u7531\u5BBF\u4E3B\u6CE8\u5165\u7248\u9A71\u52A8\uFF08\u91CD\u542F dsh web \u540E\u751F\u6548\u7684\u90A3\u5957\uFF09\u3002" : owner === "client" ? "\u5F53\u524D\u7531\u5BA2\u6237\u7AEF\u81EA\u5EFA\u7248\u9A71\u52A8\uFF08\u5237\u65B0\u5373\u751F\u6548\uFF09\u3002" : ""
14313
- )
14893
+ import_react24.default.createElement("span", { className: "dkmob-label" }, "\u5F53\u524D\u5F62\u6001"),
14894
+ import_react24.default.createElement("span", { className: "dkmob-state" + (active ? " on" : "") }, mode)
14314
14895
  ),
14315
14896
  import_react24.default.createElement(
14316
14897
  "div",
14317
14898
  { className: "dkmob-note" },
14318
- "\u751F\u6548\u4E2D\u7684\u4F18\u5316\uFF1A\u8F93\u5165\u7C7B\u63A7\u4EF6\u5B57\u53F7\u62C9\u5230 16px\uFF08\u907F\u514D iOS \u805A\u7126\u7F29\u653E\u6574\u9875\uFF09\xB7 \u7EAF\u56FE\u6807\u6309\u94AE\u9762\u79EF\u515C\u5E95 \u226536px \xB7 ",
14319
- "\u53BB\u6389\u70B9\u6309\u9AD8\u4EAE\u4E0E\u53CC\u51FB\u7F29\u653E\u5224\u5B9A \xB7 \u4EE3\u7801\u5757\u6A2A\u5411\u6EDA\u52A8\u3001\u884C\u5185\u4EE3\u7801\u81EA\u52A8\u6362\u884C \xB7 \u6EDA\u52A8\u4F53 touch-action:pan-y + iOS \u60EF\u6027\u6EDA\u52A8 \xB7 ",
14320
- "\u8BBE\u7F6E\u5F39\u5C42\u5185\u5BB9\u5217 min-height:0\uFF08\u5426\u5219\u7A84\u5C4F\u5F39\u5C42\u88AB\u5185\u5BB9\u6491\u9AD8\u540E\u6574\u7247\u6ED1\u4E0D\u52A8\uFF09\xB7 viewport meta \u8865 viewport-fit=cover",
14321
- "\uFF08standalone \u5168\u5C4F\u65F6\u7ED9\u5706\u89D2/\u5218\u6D77\u7559\u5B89\u5168\u533A\uFF09\u3002\u505C\u7528\u672C\u529F\u80FD\u5373\u5168\u90E8\u8FD8\u539F\u3002"
14899
+ "\u751F\u6548\u4E2D\u7684\u4F18\u5316\uFF1A\u8F93\u5165\u7C7B\u63A7\u4EF6\u5B57\u53F7 16px\uFF08\u9632 iOS \u805A\u7126\u6574\u9875\u7F29\u653E\uFF09\xB7 \u539F\u751F\u4FA7\u680F\u5F00\u5173\u70ED\u533A\u6269\u5230 44\xD744 \xB7 ",
14900
+ "\u53BB\u70B9\u6309\u9AD8\u4EAE\u4E0E\u53CC\u51FB\u7F29\u653E\u5224\u5B9A \xB7 \u4EE3\u7801\u5757\u6A2A\u5411\u6EDA\u52A8 / \u884C\u5185\u4EE3\u7801\u6362\u884C \xB7 \u4F1A\u8BDD\u8F93\u5165\u884C\u7684\u4F59\u989D/\u7528\u91CF chip \u6536\u8D77 \xB7 ",
14901
+ "\u8BBE\u7F6E\u5F39\u5C42\u5185\u5BB9\u5B89\u5168\u533A\u5185\u8FB9\u8DDD\u3002\u65E7\u7248 dsh\uFF08<768 \u4ECD\u662F\u4E24\u680F\u5F39\u5C42\u6216\u9759\u6001\u56FE\u6807\u8F68\u9053\uFF09\u4F1A\u81EA\u52A8\u515C\u5E95\u4E3A\u5355\u5217 / \u6D6E\u5C42\u62BD\u5C49\u3002",
14902
+ "\u5173\u95ED\u672C\u529F\u80FD\u5373\u5168\u90E8\u8FD8\u539F\u2014\u2014\u8FD0\u884C\u65F6\u6837\u5F0F\u3001body \u5C5E\u6027\u3001\u906E\u7F69/\u6309\u94AE\u4E0E\u6240\u6709\u76D1\u542C\u5668\u4E00\u5E76\u79FB\u9664\uFF0C\u9875\u9762\u4E0D\u6B8B\u7559\u4EFB\u4F55\u6CE8\u5165\u3002"
14322
14903
  )
14323
14904
  );
14324
14905
  }
14325
14906
  function MobileStat() {
14326
- const { active, chrome } = useMobileState();
14327
- if (!active) return import_react24.default.createElement("span", null, "\u5F53\u524D\u89C6\u53E3\u672A\u547D\u4E2D\u624B\u673A\u5F62\u6001\uFF0C\u6837\u5F0F\u672A\u6CE8\u5165");
14328
- return import_react24.default.createElement("span", null, "\u624B\u673A\u6A21\u5F0F\u751F\u6548\u4E2D \xB7 " + (chrome ? "\u5DE6\u4E0A\u89D2\u6C49\u5821\u83DC\u5355\u5DF2\u63A5\u7BA1\u4F1A\u8BDD\u5165\u53E3" : "chrome \u5E26\u5BBD\u672A\u547D\u4E2D\uFF08\u2264700px \u624D\u542F\u7528\uFF09"));
14907
+ const active = mobileActive();
14908
+ if (!active) return import_react24.default.createElement("span", null, "\u5F53\u524D\u89C6\u53E3\u672A\u547D\u4E2D\u624B\u673A\u5F62\u6001\uFF0C\u672A\u542F\u7528\u4EFB\u4F55\u4F18\u5316");
14909
+ return import_react24.default.createElement("span", null, "\u624B\u673A\u6A21\u5F0F\u751F\u6548\u4E2D\uFF0816px \u8F93\u5165 / \u89E6\u63A7\u70ED\u533A / \u4EE3\u7801\u6EDA\u52A8 / \u5F39\u5C42\u515C\u5E95\uFF09");
14329
14910
  }
14330
14911
  var css6 = [
14331
- // 输入类控件 16px:防 iOS 聚焦自动放大(<16px 的输入框聚焦时 Safari 强制缩放页面)
14332
- 'body[data-dk-mobile="1"] :is(textarea, input:not([type]), input[type="text"], input[type="search"], input[type="url"], input[type="password"], input[type="number"], input[type="email"], [contenteditable="true"]){font-size:16px !important;}',
14333
- // 触控基础:去点按高亮、消双击缩放判定
14334
- 'body[data-dk-mobile="1"] :is(button, [role="button"]){-webkit-tap-highlight-color:transparent;touch-action:manipulation;}',
14335
- // 纯图标按钮面积兜底:实测窄屏下一批 28×28 的工具钮很难点中;36px 是不引起行高剧变的上限。
14336
- // 只收「唯一子元素是 svg」的按钮,避免撑坏带文字的行内控件;排除本模块 chrome 按钮。
14337
- 'body[data-dk-mobile="1"] button:has(> svg:only-child):not(.dsh-mobile-burger){min-width:36px;min-height:36px;}',
14338
- // 代码块横向滚动、行内代码换行:窄屏不撑破版面
14339
- 'body[data-dk-mobile="1"] pre{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;}',
14340
- 'body[data-dk-mobile="1"] code{overflow-wrap:anywhere;}',
14341
- 'body[data-dk-mobile="1"] pre code{overflow-wrap:normal;}',
14342
- // 滚动兜底:所有纵向滚动体可纵向平移 + iOS 惯性滚动(祖先合成层/触控声明不再吃掉触摸滚动)。
14343
- 'body[data-dk-mobile="1"] :is([class*="scrollBody"], [class*="sidebarCol"] [class*="list"], [role="dialog"] [class*="options"], [class*="dockm-content"]){-webkit-overflow-scrolling:touch;overscroll-behavior-y:contain;touch-action:pan-y;}',
14344
- // iOS 横竖屏切换时的字号自动膨胀关掉(:has 挂到 html 上;dsh 自身样式已依赖 :has,基线足够)
14345
- 'html:has(body[data-dk-mobile="1"]){-webkit-text-size-adjust:100%;text-size-adjust:100%;}',
14346
- // 功能页自身
14347
14912
  ".dkmob-root{display:flex;flex-direction:column;gap:10px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.6;}",
14348
14913
  ".dkmob-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
14349
14914
  ".dkmob-label{font-weight:600;flex:none;}",
14350
14915
  ".dkmob-state{flex:none;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 10px;font-size:11px;}",
14351
14916
  ".dkmob-state.on{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary);}",
14352
14917
  ".dkmob-dim{color:var(--dsw-alias-label-secondary);font-size:12px;}",
14353
- ".dkmob-note{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.7;border-top:1px solid var(--dsw-alias-border-l1);padding-top:10px;}",
14354
- // 手机端 chrome:左上角汉堡菜单 + 抽屉遮罩(窄屏 ≤700px;与宿主半部同款)
14355
- "@media (max-width:700px){",
14356
- ".dsh-mobile-scrim{position:fixed;inset:0;z-index:75;background:rgba(8,10,14,.45);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);touch-action:none}",
14357
- // 左上角汉堡菜单(三条横线):44×44 触控面积,避让刘海/圆角安全区;z 66 高于正文、
14358
- // 低于遮罩 75 / 抽屉 80——抽屉展开时被自然盖住。
14359
- // ⚠️ 视觉上刻意「不贴合卡片」:页面左上角本来就是空的,原生同类控件(右上的侧栏开关)
14360
- // 是**裸图标**——无底色、无边框、无阴影。早期版本做成白底圆角卡片 + 阴影 + 模糊,
14361
- // 悬浮在白底页面上像一块贴上去的异物(用户实测反馈「没有贴合边缘,很突兀」)。
14362
- // 现在与原生同款:透明底、无边框无阴影,只留图标;点按才给极轻的底色反馈。
14363
- // 视觉重量靠图标本身撑住(22px、1.9px 描边、主文字色),不靠容器。
14364
- ".dsh-mobile-burger{position:fixed;left:env(safe-area-inset-left,0px);top:env(safe-area-inset-top,0px);z-index:66;box-sizing:border-box;width:44px;height:44px;display:flex;align-items:center;justify-content:center;padding:0;border:0;border-radius:0;background:transparent;color:var(--dsw-alias-label-primary,#e6eaf2);cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:manipulation;transition:color .15s var(--ds-ease-in-out,ease)}",
14365
- ".dsh-mobile-burger svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round}",
14366
- // 展开态:图标换成强调色(与原生「已激活」的语义一致),不引入额外容器。
14367
- ".dsh-mobile-burger.on{color:var(--dk-accent,#4d9fff)}",
14368
- // 点按反馈走图标本身(用 :active 的底色透出,范围就是 44×44 触控区)。
14369
- ".dsh-mobile-burger:active{background:color-mix(in srgb,currentColor 12%,transparent)}",
14370
- // 待确认任务角标:锚在按钮右上角的小圆点/数字。刻意做成「贴边小圆点」而不是
14371
- // 底部 Tab 栏那种带容器的页签角标——汉堡是裸图标,角标再带容器就又突兀了。
14372
- // 等待确认(要人介入)= 红点 + 脉冲;进行中 = 蓝色数字(弱一级,不抢注意力)。
14373
- ".dsh-mobile-burger-badge{position:absolute;top:4px;right:4px;box-sizing:border-box;min-width:8px;height:8px;padding:0;border-radius:999px;background:#4d9fff;font:700 9px/8px inherit;font-variant-numeric:tabular-nums;text-align:center;color:#fff;pointer-events:none;box-shadow:0 0 0 2px var(--dsw-alias-bg-layer-1,#12151b)}",
14374
- ".dsh-mobile-burger-badge[hidden]{display:none}",
14375
- ".dsh-mobile-burger-badge:not([hidden]){min-width:16px;height:16px;line-height:16px;padding:0 4px}",
14376
- ".dsh-mobile-burger-badge.wait{background:#ef4444;animation:dsh-burger-badge-pulse 1.2s ease-in-out infinite}",
14377
- "@keyframes dsh-burger-badge-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.18)}}",
14378
- "@media (prefers-reduced-motion:reduce){.dsh-mobile-burger-badge.wait{animation:none}}",
14379
- // ⚠️ 给标题让出汉堡宽度(用户实测:标题被汉堡压住——截图里「更新所有仓库代码」的首字
14380
- // 直接叠在三条横线上)。汉堡是 fixed 定位(贴安全区、44×44),**不占布局**,而原生标题
14381
- // 从头部的 padding-left:20px 起排——真实实例 390×844 逐字实测:会话标题首字 x=28、
14382
- // 汉堡右缘 44 → **重叠 16px**;插件页/自动化任务页的页头(自身 padding-left:0,靠外层
14383
- // 容器给 24px)首字 x=24 → 重叠 20px。
14384
- // 改法照原生排版习惯走:**给容器补内边距**,而不是给汉堡加底色/加宽(那是把问题搬到视觉上)。
14385
- // · 会话页头 header:has([class*="titleRow"])(唯一含 titleRow 的 header):左内边距
14386
- // 20px → 44px,正好等于汉堡宽度;标题自带 8px 内边距 → 首字落在 x=52,与汉堡留 8px。
14387
- // · 插件页/自动化任务页头 [class$="_pageHead"] / [class$="_pageHeading"]
14388
- // (DSH 0.2.0-rc.2 实测:plugin-manager 的 ZVcBiW_pageHead、schedule 的
14389
- // CxUija_pageHeading):左内边距 0 → 28px → 首字 x=52,同样留 8px。
14390
- // 这两条页头是 flex + gap:16px(标题块 | 工具栏),补内边距会压缩内容宽度——实测
14391
- // 430/390/360/320px 下「添加插件」按钮与描述文案会被挤到换行(按钮从单行变两行)。
14392
- // 故同时把 gap 收到 4px 补回 12px:四个宽度实测行数零回归、无横向溢出。
14393
- // 用 `[class$=…]`(语义后缀)而非 `[class*=…]`:DSH 类名是「哈希前缀 + 语义后缀」,
14394
- // 后缀稳定、前缀随版本变;`$=` 也避开 `pageHeadActions` 这类同前缀的无关元素。
14395
- // 挂 body[data-dk-mobile="1"]:本模块 css 字段会被无条件并入全局样式,停用本功能即摘掉
14396
- // body 属性 → 规则空转、原生排版还原(与文件头「开关协议」一致)。
14397
- 'body[data-dk-mobile="1"] header:has([class*="titleRow"]){padding-left:calc(44px + env(safe-area-inset-left,0px))}',
14398
- 'body[data-dk-mobile="1"] [class$="_pageHead"],body[data-dk-mobile="1"] [class$="_pageHeading"]{padding-left:calc(28px + env(safe-area-inset-left,0px));gap:4px}',
14399
- // ⚠️ 「设置页滑不动」的关键兜底(客户端无条件携带 = 刷新即生效,不必等宿主重启):
14400
- // 窄屏把设置弹层改成纵向堆叠后,内容列若是默认 min-height:auto 就会被内容撑高
14401
- // (无头 390×844 实测列高 1216px 塞在 844px 视口里)、再被 .panel 的 overflow:hidden
14402
- // 裁掉——列内滚动容器([class*=options])因此 scrollHeight==clientHeight,手指怎么滑
14403
- // 都不动。补 min-height:0 后 scrollTop 0 → 425。宿主半部 MOBILE_LAYOUT_CSS 同款;
14404
- // 两处都写是因为宿主注入要重启 dsh web 才更新,而客户端样式刷新即生效,覆盖窗口期。
14405
- '[role="dialog"][class*="panel"]>[class*="content"]{min-height:0!important}',
14406
- // 输入区吸附到视口底部 + 滚动体留白(与宿主半部同款)。
14407
- // ⚠️ 底部留白只保留 iPhone home indicator 的安全区,不再额外留白。沿革:原 72px 是
14408
- // 「底部 Tab 栏高度 + 安全区」;Tab 栏移除后先收到 24px,但实测(真实实例 390×844
14409
- // 像素扫描)输入卡片下方仍有 **51px** 空白带,其中 24px 是这里的滚动体内边距、
14410
- // 6px 是下面 composerSeat 的内边距——两者都是 Tab 栏时代的遗留,在没有底栏的页面上
14411
- // 纯属浪费。收窄到「只有安全区」后卡片下沿更贴近视口底,这 30px 直接变成会话区
14412
- // 可显示的正文(滚动体内边距在 flex 容器里会把 composerSeat 连同消息区一起下移/增高)。
14413
- // dsh 自带的 ~21px 底部间距(卡片 margin)保留,视觉上仍有呼吸感,不会贴死屏幕边缘。
14414
- // ⚠️ 绝不能给滚动体加 justify-content:flex-end/center 贴底:内容会被挤到滚动体
14415
- // 起点之外,Chrome 不把起点方向溢出算进 scrollHeight(手机视口实测
14416
- // scrollHeight==clientHeight、maxScroll==0),会话记录彻底滚不动、首条消息永远看不到。
14417
- // 宿主半部旧版注入里还留着那条 flex-end(要重启 dsh web 才消失),这里用更高优先级
14418
- // 的选择器显式复位:刷新页面即修好,不必等重启。贴底只能用输入区自己的 margin-top:auto。
14419
- '[class*="scrollBody"][data-conversation-scroll]{justify-content:flex-start !important;padding-bottom:env(safe-area-inset-bottom,0px) !important}',
14420
- 'html:not(.dsh-dock-kbd) [class*="scrollBody"]{padding-bottom:env(safe-area-inset-bottom,0px) !important}',
14421
- 'html.dsh-dock-kbd [class*="scrollBody"]{padding-bottom:env(safe-area-inset-bottom,0px) !important}',
14422
- '[class*="scrollBody"]>[class*="composerSeat"]{margin-top:auto;padding-bottom:0}',
14423
- // 输入区工具行上的 dsh-dock chip(用量/余额):窄屏下 28cqw 的宽度上限把它们挤成
14424
- // 「…」「余..」(手机实测),既读不出数值又白占输入行空间。手机端整组收起,数值在
14425
- // 功能坞(抽屉里进)看;桌面端不动。
14426
- ".dockchip-row{display:none}",
14427
- '[class*="sidebarCol"]:has([class*="collapsed"]){visibility:hidden}',
14428
- // ⚠️ 列级 visibility:hidden 在 dsh 0.2.0 上挡不住:工作区浏览器给自己的
14429
- // headerActions/sectionLabel 显式声明 visibility:visible(展开/收拢动画用),visibility
14430
- // 可被后代覆盖,轨道按钮会从隐藏列里「透」出来(实测手机截图左缘游离按钮)。
14431
- // display:none 不可被后代翻转——但只能打在**轨道根节点**上(类名同时含 root 与
14432
- // collapsed 两个语义后缀),绝不能打在列上:frame 是「侧栏 0px + 中列 1fr + 右轨 0px」
14433
- // 的网格,列 display:none 会从网格流里摘掉,中列被自动放置顶进 0px 轨(实测整页空屏)。
14434
- // 弹层打开时豁免(设置弹层挂在列内部,display:none 会连坐成空气弹层),此时列退回
14435
- // visibility 机制(由下一条 [role=dialog] 强制可见),窄屏弹层全屏铺满盖住透出的轨道。
14436
- '[class*="sidebarCol"]:has([class*="collapsed"]):not(:has([role="dialog"])) [class*="root"][class*="collapsed"]{display:none !important}',
14437
- // 设置/插件管理弹层挂在侧栏列内部:上面隐藏整列会把它连坐隐藏(空气弹层)。
14438
- // visibility 可被后代覆盖,弹层关闭态整体卸载,所以只在真正打开时命中。
14439
- '[class*="sidebarCol"]:has([class*="collapsed"]) [role="dialog"]{visibility:visible}',
14440
- "html.dsh-dock-kbd .dsh-mobile-burger{display:none !important}",
14441
- // 功能坞面板在手机端抬到原生弹层之上:从抽屉进的官方插件管理页等原生弹层 z 序高于
14442
- // 面板默认的 200,功能坞开在下面会被盖住。抽屉展开时从侧栏 rail 点功能坞图标进入。
14443
- '[class*="dockm-backdrop"]{z-index:2000 !important}',
14444
- "}"
14918
+ ".dkmob-note{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.7;border-top:1px solid var(--dsw-alias-border-l1);padding-top:10px;}"
14445
14919
  ].join("\n");
14446
14920
  var feature13 = {
14447
14921
  id: "mobile",
14448
14922
  name: "\u624B\u673A\u9002\u914D",
14449
14923
  order: 170,
14450
14924
  accent: "#34d399",
14451
- description: "\u624B\u673A/\u7A84\u5C4F\u6392\u7248\u4E0E\u89E6\u63A7\u515C\u5E95\uFF1A\u5DE6\u4E0A\u89D2\u6C49\u5821\u83DC\u5355 + \u4FA7\u680F\u62BD\u5C49\u300116px \u8F93\u5165\u9632 iOS \u7F29\u653E\u3001\u56FE\u6807\u6309\u94AE\u89E6\u63A7\u9762\u79EF\u3001\u4EE3\u7801\u5757\u6EDA\u52A8\u3001\u6EDA\u52A8\u515C\u5E95",
14452
- defaultEnabled: true,
14925
+ description: "\u624B\u673A/\u7A84\u5C4F\u4F53\u9A8C\u4F18\u5316\uFF1A16px \u8F93\u5165\u9632\u7F29\u653E\u3001\u89E6\u63A7\u70ED\u533A\u3001\u4EE3\u7801\u5757\u6EDA\u52A8\u3001\u4F1A\u8BDD chip \u6536\u8D77\u3001\u8BBE\u7F6E\u5F39\u5C42\u5355\u5217\u4E0E\u65E7\u7248\u62BD\u5C49\u515C\u5E95\uFF1B\u5173\u95ED\u540E\u96F6\u6B8B\u7559",
14926
+ defaultEnabled: false,
14453
14927
  css: css6,
14454
14928
  Overlay: MobileOverlay,
14455
14929
  View: MobileView,
@@ -14457,7 +14931,7 @@ var feature13 = {
14457
14931
  };
14458
14932
 
14459
14933
  // src/client.jsx
14460
- var DOCK_VERSION = "0.19.0";
14934
+ var DOCK_VERSION = "0.21.0";
14461
14935
  var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10, feature11, feature12, feature13];
14462
14936
  var PLANNED_FEATURES = [];
14463
14937
  var PLANNED_NOTES = {};
@@ -14572,6 +15046,12 @@ var SHELL_CSS = [
14572
15046
  ".dockm-name{display:flex;align-items:center;gap:8px;font-weight:600;font-size:15px;}",
14573
15047
  ".dockm-desc{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.6;}",
14574
15048
  ".dockm-view{display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--dsw-alias-border-l1);padding-top:10px;}",
15049
+ ".dockm-page{box-sizing:border-box;height:100%;overflow:auto;padding:20px 24px 32px;}",
15050
+ ".dockm-page-head{display:flex;align-items:flex-start;gap:10px;margin-bottom:16px;}",
15051
+ ".dockm-page-icon{flex:none;display:flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);}",
15052
+ ".dockm-page-titles{min-width:0;}",
15053
+ ".dockm-page-title{font-size:17px;font-weight:600;color:var(--dsw-alias-label-primary);line-height:1.3;}",
15054
+ ".dockm-page-sub{font-size:12px;color:var(--dsw-alias-label-tertiary);margin-top:2px;}",
14575
15055
  ".dockm-note{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.6;border-top:1px solid var(--dsw-alias-border-l1);padding-top:10px;}",
14576
15056
  ".dockm-err{color:var(--dsw-alias-state-error-primary);}",
14577
15057
  ".dockm-foot{margin-top:auto;display:flex;align-items:center;gap:8px;color:var(--dsw-alias-label-tertiary);font-size:11px;border-top:1px solid var(--dsw-alias-border-l1);padding-top:10px;flex-wrap:wrap;}",
@@ -14603,7 +15083,11 @@ var SHELL_CSS = [
14603
15083
  ".dockm-foot-swlabel.on{color:var(--dsw-alias-state-success-primary);}",
14604
15084
  // 窄屏:功能坞是一级工作台而不是被压扁的桌面弹窗。全屏承接安全区,导航改横向,
14605
15085
  // 禁用桌面拖拽/缩放,所有导航和关闭动作保持至少 44px 的可点击面积。
14606
- "@media (max-width:680px){.dockm-backdrop{align-items:stretch;justify-content:stretch;background:var(--dsw-alias-bg-layer-2);backdrop-filter:none}.dockm-dialog,.dockm-dialog.dockm-max{position:fixed!important;left:0!important;top:0!important;right:auto!important;bottom:auto!important;width:100dvw!important;height:100dvh!important;min-height:100dvh;border:0;border-radius:0;box-shadow:none}.dockm-dialog.dockm-min .dockm-body{display:flex}.dockm-head{min-height:60px;box-sizing:border-box;padding:calc(env(safe-area-inset-top) + 8px) 12px 8px;cursor:default;touch-action:manipulation}.dockm-sub,.dockm-win,.dockm-resize{display:none}.dockm-title{font-size:16px}.dockm-close{width:44px;height:44px;font-size:17px}.dockm-body{flex-direction:column;min-height:0}.dockm-nav{box-sizing:border-box;width:auto;max-width:100%;min-height:56px;flex-direction:row;gap:6px;padding:6px 10px;overflow-x:auto;overflow-y:hidden;border-right:0;border-bottom:1px solid var(--dsw-alias-border-l1);scrollbar-width:none;overscroll-behavior-x:contain}.dockm-nav::-webkit-scrollbar{display:none}.dockm-nav-item{flex:none;min-height:44px;padding:0 12px;font-size:13px;touch-action:manipulation}.dockm-nav-item .dockm-badge{display:none}.dockm-content{padding:16px max(16px,env(safe-area-inset-right)) calc(20px + env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left));gap:14px;overscroll-behavior:contain}.dockm-content-head{gap:5px}.dockm-name{font-size:16px}.dockm-desc{font-size:13px;line-height:1.55}.dockm-foot{padding-top:12px;font-size:11px}.dockm-foot-sw{width:100%;margin-left:0;justify-content:space-between}.dock-sw{width:44px;height:26px}.dock-sw::after{top:3px;left:3px;width:18px;height:18px}.dock-sw.on::after{transform:translateX(18px)}.dockh-grid{grid-template-columns:1fr;gap:10px}.dockh-card{padding:12px}.dockh-desc{font-size:13px}.dockh-go{font-size:12px}}",
15086
+ "@media (max-width:680px){.dockm-backdrop{align-items:stretch;justify-content:stretch;background:var(--dsw-alias-bg-layer-2);backdrop-filter:none}.dockm-dialog,.dockm-dialog.dockm-max{position:fixed!important;left:0!important;top:0!important;right:auto!important;bottom:auto!important;width:100dvw!important;height:100dvh!important;min-height:100dvh;border:0;border-radius:0;box-shadow:none}.dockm-dialog.dockm-min .dockm-body{display:flex}.dockm-head{min-height:60px;box-sizing:border-box;padding:calc(env(safe-area-inset-top) + 8px) 12px 8px;cursor:default;touch-action:manipulation}.dockm-sub,.dockm-win,.dockm-resize{display:none}.dockm-title{font-size:16px}.dockm-close{width:44px;height:44px;font-size:17px}.dockm-body{flex-direction:column;min-height:0}.dockm-nav{box-sizing:border-box;width:auto;max-width:100%;min-height:56px;flex-direction:row;gap:6px;padding:6px 10px;overflow-x:auto;overflow-y:hidden;border-right:0;border-bottom:1px solid var(--dsw-alias-border-l1);scrollbar-width:none;overscroll-behavior-x:contain}.dockm-nav::-webkit-scrollbar{display:none}.dockm-nav-item{flex:none;min-height:44px;padding:0 12px;font-size:13px;touch-action:manipulation}.dockm-nav-item .dockm-badge{display:none}.dockm-content{padding:16px max(16px,env(safe-area-inset-right)) calc(20px + env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left));gap:14px;overscroll-behavior:contain}.dockm-content-head{gap:5px}.dockm-name{font-size:16px}.dockm-desc{font-size:13px;line-height:1.55}.dockm-foot{padding-top:12px;font-size:11px}.dockm-foot-sw{width:100%;margin-left:0;justify-content:space-between}.dock-sw{width:44px;height:26px}.dock-sw::after{top:3px;left:3px;width:18px;height:18px}.dock-sw.on::after{transform:translateX(18px)}.dockh-grid{grid-template-columns:minmax(0,1fr);gap:10px;min-width:0}.dockh-card{padding:12px;box-sizing:border-box;min-width:0}.dockh-desc{font-size:13px}.dockh-go{font-size:12px}}",
15087
+ /* 手机端:功能坞弹层挂在 .overlayLayer(z20) 内,会被 z71 的侧栏抽屉盖住(只剩右侧一条)。\n 把 overlayLayer 在窄屏抬到抽屉之上,面板才能全屏覆盖——且不依赖【手机适配】模块是否启用。 */
15088
+ '@media (max-width:767px){[class*="overlayLayer"]{z-index:100 !important}}',
15089
+ /* 手机:输入卡里的「轮/步/token/缓存」状态条移到输入框上方,压成一行不溢出;空会话时把输入卡贴底 */
15090
+ '@media (max-width:767px){[class*="scrollBody"]>[class*="composerSeat"]{margin-top:auto!important;padding-bottom:0!important}[class*="composerSeat"] [class*="_dock"]{order:-1!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important;padding:0 2px 6px!important;gap:6px!important;font-size:10px!important;overflow:hidden!important}[class*="composerSeat"] [class*="_dock"]>*{min-width:0}}',
14607
15091
  "@media (prefers-reduced-motion:reduce){.dockm-backdrop,.dockm-dialog{animation:none}.dockm-nav-item,.dockm-close,.dockm-win,.dock-sw{transition:none}}",
14608
15092
  ".dockh-desc{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5;}",
14609
15093
  ".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;}",
@@ -14629,7 +15113,9 @@ var SHELL_CSS = [
14629
15113
  ".dockchip > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}",
14630
15114
  ".dockchip:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
14631
15115
  ".dockchip .dockchip-dot{width:6px;height:6px;border-radius:50%;flex:none;}",
14632
- ".dockchip.err{color:var(--dsw-alias-state-error-primary);}"
15116
+ ".dockchip.err{color:var(--dsw-alias-state-error-primary);}",
15117
+ /* 手机:输入区工具行很窄,给 chips 稍多宽度,并隐藏费用等次要后缀(.dockchip-x),避免被截成「⛁ 2…/余…」 */
15118
+ "@media (max-width:767px){.dockchip-row{max-width:min(216px,40cqw)}.dockchip-x{display:none}.dockchip{font-size:10px!important;padding:1px 2px!important;gap:3px!important}.dockchip .dockchip-dot{width:4px;height:4px}.dockchip-ic{display:none}.dockchip-pre{display:none}}"
14633
15119
  ].join("\n");
14634
15120
  var dockCssTag = null;
14635
15121
  var initialCssSchedule = null;
@@ -14685,19 +15171,6 @@ function DockIcon(props) {
14685
15171
  import_react26.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
14686
15172
  );
14687
15173
  }
14688
- function DockEntry(props) {
14689
- const wide = !!props.wide;
14690
- const [open, setOpen] = import_react26.default.useState(panelNav.open);
14691
- import_react26.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
14692
- return import_react26.default.createElement("button", {
14693
- type: "button",
14694
- className: "docke2-btn" + (open ? " docke2-on" : "") + (wide ? "" : " docke2-rail"),
14695
- title: "\u529F\u80FD\u575E",
14696
- "aria-label": "\u529F\u80FD\u575E",
14697
- "aria-expanded": open,
14698
- onClick: () => setPanelOpen(!open)
14699
- }, import_react26.default.createElement(DockIcon, { size: wide ? 16 : 18 }), wide ? import_react26.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
14700
- }
14701
15174
  function DockModal() {
14702
15175
  const [nav, setNav] = import_react26.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
14703
15176
  import_react26.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
@@ -15052,6 +15525,24 @@ function DockPanel(props) {
15052
15525
  })
15053
15526
  );
15054
15527
  }
15528
+ function DockPage() {
15529
+ return import_react26.default.createElement(
15530
+ "div",
15531
+ { className: "dockm-page" },
15532
+ import_react26.default.createElement(
15533
+ "div",
15534
+ { className: "dockm-page-head" },
15535
+ import_react26.default.createElement("span", { className: "dockm-page-icon" }, import_react26.default.createElement(DockIcon, { size: 20 })),
15536
+ import_react26.default.createElement(
15537
+ "div",
15538
+ { className: "dockm-page-titles" },
15539
+ import_react26.default.createElement("div", { className: "dockm-page-title" }, "\u529F\u80FD\u575E"),
15540
+ import_react26.default.createElement("div", { className: "dockm-page-sub" }, "\u6240\u6709\u5C0F\u529F\u80FD\u96C6\u4E2D\u5728\u8FD9\u91CC\u7BA1\u7406\u3002\u4FA7\u680F\u56FE\u6807\u53EF\u5728\u300C\u66F4\u591A\u300D\u83DC\u5355\u91CC Pin \u5230\u9876\u90E8\uFF0C\u6216\u53D6\u6D88\u56FA\u5B9A\u6536\u8FDB\u66F4\u591A\u3002")
15541
+ )
15542
+ ),
15543
+ import_react26.default.createElement("div", { className: "dockm-page-body" }, import_react26.default.createElement(DockPanel, { params: null }))
15544
+ );
15545
+ }
15055
15546
  function DockChips(props) {
15056
15547
  const [, force] = import_react26.default.useReducer((n) => n + 1, 0);
15057
15548
  import_react26.default.useEffect(() => subscribeFeatureState(() => force()), []);
@@ -15111,9 +15602,13 @@ function apply(ctx) {
15111
15602
  initFeatureState(BUILTIN_FEATURES.concat(PLANNED_FEATURES));
15112
15603
  const slots = ctx.get("slots");
15113
15604
  if (slots === void 0) return;
15114
- slots.inject("sidebar.footer.action", () => slots.register(
15115
- { name: "sidebar.footer.action", id: "dsh-dock", order: 1, label: "\u529F\u80FD\u575E" },
15116
- (props) => import_react26.default.createElement(DockEntry, props)
15605
+ slots.inject("sidebar.panellist", () => slots.register(
15606
+ { name: "sidebar.panellist", id: "dsh-dock", order: 30, label: "\u529F\u80FD\u575E" },
15607
+ (props) => import_react26.default.createElement(DockIcon, { size: props && props.size || 18 })
15608
+ ));
15609
+ slots.inject("main", () => slots.register(
15610
+ { name: "main", key: "dsh-dock", label: "\u529F\u80FD\u575E" },
15611
+ () => import_react26.default.createElement(DockPage, null)
15117
15612
  ));
15118
15613
  slots.inject("shell.overlay", () => slots.register(
15119
15614
  { name: "shell.overlay", id: "dsh-dock-panel", order: 21, label: "\u529F\u80FD\u575E\u9762\u677F" },