dsh-dock 0.18.0 → 0.20.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
@@ -40,18 +40,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
40
40
  ));
41
41
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
42
42
 
43
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/can-promise.js
43
+ // node_modules/qrcode/lib/can-promise.js
44
44
  var require_can_promise = __commonJS({
45
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/can-promise.js"(exports, module2) {
45
+ "node_modules/qrcode/lib/can-promise.js"(exports, module2) {
46
46
  module2.exports = function() {
47
47
  return typeof Promise === "function" && Promise.prototype && Promise.prototype.then;
48
48
  };
49
49
  }
50
50
  });
51
51
 
52
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js
52
+ // node_modules/qrcode/lib/core/utils.js
53
53
  var require_utils = __commonJS({
54
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js"(exports) {
54
+ "node_modules/qrcode/lib/core/utils.js"(exports) {
55
55
  var toSJISFunction;
56
56
  var CODEWORDS_COUNT = [
57
57
  0,
@@ -128,9 +128,9 @@ var require_utils = __commonJS({
128
128
  }
129
129
  });
130
130
 
131
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-level.js
131
+ // node_modules/qrcode/lib/core/error-correction-level.js
132
132
  var require_error_correction_level = __commonJS({
133
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-level.js"(exports) {
133
+ "node_modules/qrcode/lib/core/error-correction-level.js"(exports) {
134
134
  exports.L = { bit: 1 };
135
135
  exports.M = { bit: 0 };
136
136
  exports.Q = { bit: 3 };
@@ -173,9 +173,9 @@ var require_error_correction_level = __commonJS({
173
173
  }
174
174
  });
175
175
 
176
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-buffer.js
176
+ // node_modules/qrcode/lib/core/bit-buffer.js
177
177
  var require_bit_buffer = __commonJS({
178
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-buffer.js"(exports, module2) {
178
+ "node_modules/qrcode/lib/core/bit-buffer.js"(exports, module2) {
179
179
  function BitBuffer() {
180
180
  this.buffer = [];
181
181
  this.length = 0;
@@ -208,9 +208,9 @@ var require_bit_buffer = __commonJS({
208
208
  }
209
209
  });
210
210
 
211
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-matrix.js
211
+ // node_modules/qrcode/lib/core/bit-matrix.js
212
212
  var require_bit_matrix = __commonJS({
213
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-matrix.js"(exports, module2) {
213
+ "node_modules/qrcode/lib/core/bit-matrix.js"(exports, module2) {
214
214
  function BitMatrix(size) {
215
215
  if (!size || size < 1) {
216
216
  throw new Error("BitMatrix size must be defined and greater than 0");
@@ -237,9 +237,9 @@ var require_bit_matrix = __commonJS({
237
237
  }
238
238
  });
239
239
 
240
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alignment-pattern.js
240
+ // node_modules/qrcode/lib/core/alignment-pattern.js
241
241
  var require_alignment_pattern = __commonJS({
242
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alignment-pattern.js"(exports) {
242
+ "node_modules/qrcode/lib/core/alignment-pattern.js"(exports) {
243
243
  var getSymbolSize = require_utils().getSymbolSize;
244
244
  exports.getRowColCoords = function getRowColCoords(version) {
245
245
  if (version === 1) return [];
@@ -272,9 +272,9 @@ var require_alignment_pattern = __commonJS({
272
272
  }
273
273
  });
274
274
 
275
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/finder-pattern.js
275
+ // node_modules/qrcode/lib/core/finder-pattern.js
276
276
  var require_finder_pattern = __commonJS({
277
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/finder-pattern.js"(exports) {
277
+ "node_modules/qrcode/lib/core/finder-pattern.js"(exports) {
278
278
  var getSymbolSize = require_utils().getSymbolSize;
279
279
  var FINDER_PATTERN_SIZE = 7;
280
280
  exports.getPositions = function getPositions(version) {
@@ -291,9 +291,9 @@ var require_finder_pattern = __commonJS({
291
291
  }
292
292
  });
293
293
 
294
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mask-pattern.js
294
+ // node_modules/qrcode/lib/core/mask-pattern.js
295
295
  var require_mask_pattern = __commonJS({
296
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mask-pattern.js"(exports) {
296
+ "node_modules/qrcode/lib/core/mask-pattern.js"(exports) {
297
297
  exports.Patterns = {
298
298
  PATTERN000: 0,
299
299
  PATTERN001: 1,
@@ -433,9 +433,9 @@ var require_mask_pattern = __commonJS({
433
433
  }
434
434
  });
435
435
 
436
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-code.js
436
+ // node_modules/qrcode/lib/core/error-correction-code.js
437
437
  var require_error_correction_code = __commonJS({
438
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-code.js"(exports) {
438
+ "node_modules/qrcode/lib/core/error-correction-code.js"(exports) {
439
439
  var ECLevel = require_error_correction_level();
440
440
  var EC_BLOCKS_TABLE = [
441
441
  // L M Q H
@@ -794,9 +794,9 @@ var require_error_correction_code = __commonJS({
794
794
  }
795
795
  });
796
796
 
797
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/galois-field.js
797
+ // node_modules/qrcode/lib/core/galois-field.js
798
798
  var require_galois_field = __commonJS({
799
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/galois-field.js"(exports) {
799
+ "node_modules/qrcode/lib/core/galois-field.js"(exports) {
800
800
  var EXP_TABLE = new Uint8Array(512);
801
801
  var LOG_TABLE = new Uint8Array(256);
802
802
  (function initTables() {
@@ -827,9 +827,9 @@ var require_galois_field = __commonJS({
827
827
  }
828
828
  });
829
829
 
830
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/polynomial.js
830
+ // node_modules/qrcode/lib/core/polynomial.js
831
831
  var require_polynomial = __commonJS({
832
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/polynomial.js"(exports) {
832
+ "node_modules/qrcode/lib/core/polynomial.js"(exports) {
833
833
  var GF = require_galois_field();
834
834
  exports.mul = function mul(p1, p2) {
835
835
  const coeff = new Uint8Array(p1.length + p2.length - 1);
@@ -863,9 +863,9 @@ var require_polynomial = __commonJS({
863
863
  }
864
864
  });
865
865
 
866
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/reed-solomon-encoder.js
866
+ // node_modules/qrcode/lib/core/reed-solomon-encoder.js
867
867
  var require_reed_solomon_encoder = __commonJS({
868
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/reed-solomon-encoder.js"(exports, module2) {
868
+ "node_modules/qrcode/lib/core/reed-solomon-encoder.js"(exports, module2) {
869
869
  var Polynomial = require_polynomial();
870
870
  function ReedSolomonEncoder(degree) {
871
871
  this.genPoly = void 0;
@@ -895,18 +895,18 @@ var require_reed_solomon_encoder = __commonJS({
895
895
  }
896
896
  });
897
897
 
898
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version-check.js
898
+ // node_modules/qrcode/lib/core/version-check.js
899
899
  var require_version_check = __commonJS({
900
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version-check.js"(exports) {
900
+ "node_modules/qrcode/lib/core/version-check.js"(exports) {
901
901
  exports.isValid = function isValid(version) {
902
902
  return !isNaN(version) && version >= 1 && version <= 40;
903
903
  };
904
904
  }
905
905
  });
906
906
 
907
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/regex.js
907
+ // node_modules/qrcode/lib/core/regex.js
908
908
  var require_regex = __commonJS({
909
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/regex.js"(exports) {
909
+ "node_modules/qrcode/lib/core/regex.js"(exports) {
910
910
  var numeric = "[0-9]+";
911
911
  var alphanumeric = "[A-Z $%*+\\-./:]+";
912
912
  var kanji = "(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";
@@ -932,9 +932,9 @@ var require_regex = __commonJS({
932
932
  }
933
933
  });
934
934
 
935
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mode.js
935
+ // node_modules/qrcode/lib/core/mode.js
936
936
  var require_mode = __commonJS({
937
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mode.js"(exports) {
937
+ "node_modules/qrcode/lib/core/mode.js"(exports) {
938
938
  var VersionCheck = require_version_check();
939
939
  var Regex = require_regex();
940
940
  exports.NUMERIC = {
@@ -1013,9 +1013,9 @@ var require_mode = __commonJS({
1013
1013
  }
1014
1014
  });
1015
1015
 
1016
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version.js
1016
+ // node_modules/qrcode/lib/core/version.js
1017
1017
  var require_version = __commonJS({
1018
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version.js"(exports) {
1018
+ "node_modules/qrcode/lib/core/version.js"(exports) {
1019
1019
  var Utils = require_utils();
1020
1020
  var ECCode = require_error_correction_code();
1021
1021
  var ECLevel = require_error_correction_level();
@@ -1108,9 +1108,9 @@ var require_version = __commonJS({
1108
1108
  }
1109
1109
  });
1110
1110
 
1111
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/format-info.js
1111
+ // node_modules/qrcode/lib/core/format-info.js
1112
1112
  var require_format_info = __commonJS({
1113
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/format-info.js"(exports) {
1113
+ "node_modules/qrcode/lib/core/format-info.js"(exports) {
1114
1114
  var Utils = require_utils();
1115
1115
  var G15 = 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0;
1116
1116
  var G15_MASK = 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1;
@@ -1126,9 +1126,9 @@ var require_format_info = __commonJS({
1126
1126
  }
1127
1127
  });
1128
1128
 
1129
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/numeric-data.js
1129
+ // node_modules/qrcode/lib/core/numeric-data.js
1130
1130
  var require_numeric_data = __commonJS({
1131
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/numeric-data.js"(exports, module2) {
1131
+ "node_modules/qrcode/lib/core/numeric-data.js"(exports, module2) {
1132
1132
  var Mode = require_mode();
1133
1133
  function NumericData(data) {
1134
1134
  this.mode = Mode.NUMERIC;
@@ -1161,9 +1161,9 @@ var require_numeric_data = __commonJS({
1161
1161
  }
1162
1162
  });
1163
1163
 
1164
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alphanumeric-data.js
1164
+ // node_modules/qrcode/lib/core/alphanumeric-data.js
1165
1165
  var require_alphanumeric_data = __commonJS({
1166
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alphanumeric-data.js"(exports, module2) {
1166
+ "node_modules/qrcode/lib/core/alphanumeric-data.js"(exports, module2) {
1167
1167
  var Mode = require_mode();
1168
1168
  var ALPHA_NUM_CHARS = [
1169
1169
  "0",
@@ -1240,9 +1240,9 @@ var require_alphanumeric_data = __commonJS({
1240
1240
  }
1241
1241
  });
1242
1242
 
1243
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/byte-data.js
1243
+ // node_modules/qrcode/lib/core/byte-data.js
1244
1244
  var require_byte_data = __commonJS({
1245
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/byte-data.js"(exports, module2) {
1245
+ "node_modules/qrcode/lib/core/byte-data.js"(exports, module2) {
1246
1246
  var Mode = require_mode();
1247
1247
  function ByteData(data) {
1248
1248
  this.mode = Mode.BYTE;
@@ -1270,9 +1270,9 @@ var require_byte_data = __commonJS({
1270
1270
  }
1271
1271
  });
1272
1272
 
1273
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/kanji-data.js
1273
+ // node_modules/qrcode/lib/core/kanji-data.js
1274
1274
  var require_kanji_data = __commonJS({
1275
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/kanji-data.js"(exports, module2) {
1275
+ "node_modules/qrcode/lib/core/kanji-data.js"(exports, module2) {
1276
1276
  var Mode = require_mode();
1277
1277
  var Utils = require_utils();
1278
1278
  function KanjiData(data) {
@@ -1309,9 +1309,9 @@ var require_kanji_data = __commonJS({
1309
1309
  }
1310
1310
  });
1311
1311
 
1312
- // .devdeps/node_modules/.pnpm/dijkstrajs@1.0.3/node_modules/dijkstrajs/dijkstra.js
1312
+ // node_modules/dijkstrajs/dijkstra.js
1313
1313
  var require_dijkstra = __commonJS({
1314
- ".devdeps/node_modules/.pnpm/dijkstrajs@1.0.3/node_modules/dijkstrajs/dijkstra.js"(exports, module2) {
1314
+ "node_modules/dijkstrajs/dijkstra.js"(exports, module2) {
1315
1315
  "use strict";
1316
1316
  var dijkstra = {
1317
1317
  single_source_shortest_paths: function(graph, s, d) {
@@ -1410,9 +1410,9 @@ var require_dijkstra = __commonJS({
1410
1410
  }
1411
1411
  });
1412
1412
 
1413
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/segments.js
1413
+ // node_modules/qrcode/lib/core/segments.js
1414
1414
  var require_segments = __commonJS({
1415
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/segments.js"(exports) {
1415
+ "node_modules/qrcode/lib/core/segments.js"(exports) {
1416
1416
  var Mode = require_mode();
1417
1417
  var NumericData = require_numeric_data();
1418
1418
  var AlphanumericData = require_alphanumeric_data();
@@ -1596,9 +1596,9 @@ var require_segments = __commonJS({
1596
1596
  }
1597
1597
  });
1598
1598
 
1599
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/qrcode.js
1599
+ // node_modules/qrcode/lib/core/qrcode.js
1600
1600
  var require_qrcode = __commonJS({
1601
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/qrcode.js"(exports) {
1601
+ "node_modules/qrcode/lib/core/qrcode.js"(exports) {
1602
1602
  var Utils = require_utils();
1603
1603
  var ECLevel = require_error_correction_level();
1604
1604
  var BitBuffer = require_bit_buffer();
@@ -1857,9 +1857,9 @@ var require_qrcode = __commonJS({
1857
1857
  }
1858
1858
  });
1859
1859
 
1860
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js
1860
+ // node_modules/qrcode/lib/renderer/utils.js
1861
1861
  var require_utils2 = __commonJS({
1862
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js"(exports) {
1862
+ "node_modules/qrcode/lib/renderer/utils.js"(exports) {
1863
1863
  function hex2rgba(hex) {
1864
1864
  if (typeof hex === "number") {
1865
1865
  hex = hex.toString();
@@ -1937,9 +1937,9 @@ var require_utils2 = __commonJS({
1937
1937
  }
1938
1938
  });
1939
1939
 
1940
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/canvas.js
1940
+ // node_modules/qrcode/lib/renderer/canvas.js
1941
1941
  var require_canvas = __commonJS({
1942
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/canvas.js"(exports) {
1942
+ "node_modules/qrcode/lib/renderer/canvas.js"(exports) {
1943
1943
  var Utils = require_utils2();
1944
1944
  function clearCanvas(ctx, canvas, size) {
1945
1945
  ctx.clearRect(0, 0, canvas.width, canvas.height);
@@ -1990,9 +1990,9 @@ var require_canvas = __commonJS({
1990
1990
  }
1991
1991
  });
1992
1992
 
1993
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg-tag.js
1993
+ // node_modules/qrcode/lib/renderer/svg-tag.js
1994
1994
  var require_svg_tag = __commonJS({
1995
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg-tag.js"(exports) {
1995
+ "node_modules/qrcode/lib/renderer/svg-tag.js"(exports) {
1996
1996
  var Utils = require_utils2();
1997
1997
  function getColorAttrib(color, attrib) {
1998
1998
  const alpha = color.a / 255;
@@ -2048,9 +2048,9 @@ var require_svg_tag = __commonJS({
2048
2048
  }
2049
2049
  });
2050
2050
 
2051
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/browser.js
2051
+ // node_modules/qrcode/lib/browser.js
2052
2052
  var require_browser = __commonJS({
2053
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/browser.js"(exports) {
2053
+ "node_modules/qrcode/lib/browser.js"(exports) {
2054
2054
  var canPromise = require_can_promise();
2055
2055
  var QRCode2 = require_qrcode();
2056
2056
  var CanvasRenderer = require_canvas();
@@ -2126,7 +2126,7 @@ __export(client_exports, {
2126
2126
  inject: () => inject
2127
2127
  });
2128
2128
  module.exports = __toCommonJS(client_exports);
2129
- var import_react26 = __toESM(require("react"), 1);
2129
+ var import_react24 = __toESM(require("react"), 1);
2130
2130
 
2131
2131
  // src/shared.js
2132
2132
  var import_react = __toESM(require("react"), 1);
@@ -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);
@@ -6200,13 +6245,15 @@ function MissionDeparture(props) {
6200
6245
  }
6201
6246
  function ProgrammingStuck(props) {
6202
6247
  const waiting = !!props.waiting;
6248
+ const task = props.task;
6249
+ const label = !waiting ? "\u7F16\u7A0B\u7B49\u5F85\u4E2D" : taskApprovals(task).length > 0 ? "\u7B49\u5F85\u786E\u8BA4" : "\u7B49\u5F85\u56DE\u7B54";
6203
6250
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dkan-space-stuck" + (waiting ? " waiting" : ""), "aria-hidden": "true", children: [
6204
6251
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FreighterHull, { units: 3, empty: true }),
6205
6252
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-stuck-code", children: [
6206
6253
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", {}),
6207
6254
  `{ }`
6208
6255
  ] }),
6209
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: waiting ? "\u7B49\u5F85\u786E\u8BA4" : "\u7F16\u7A0B\u7B49\u5F85\u4E2D" }),
6256
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: label }),
6210
6257
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("small", { children: truncate(props.task && props.task.title || "\u5DE5\u5177\u6682\u65E0\u65B0\u54CD\u5E94", 28) })
6211
6258
  ] });
6212
6259
  }
@@ -6359,7 +6406,8 @@ function AnimationOverlay(props) {
6359
6406
  const animOn = !!(cfg && cfg.animationEnabled && active.length > 0);
6360
6407
  const mode = cfg && cfg.effectMode ? cfg.effectMode : "flow";
6361
6408
  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;
6409
+ const waitingTask = active.find((x) => taskWaiting(x)) || null;
6410
+ const waitWord = waitingTask && taskApprovals(waitingTask).length === 0 ? "\u7B49\u5F85\u56DE\u7B54" : "\u7B49\u5F85\u786E\u8BA4";
6363
6411
  const sessionTitleRef = (0, import_react9.useRef)({ at: 0, title: "" });
6364
6412
  const currentTitle = (0, import_react9.useMemo)(() => {
6365
6413
  const c = sessionTitleRef.current;
@@ -6370,7 +6418,7 @@ function AnimationOverlay(props) {
6370
6418
  return c.title;
6371
6419
  }, [snap.status]);
6372
6420
  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;
6421
+ const waitingTaskOnScreen = onScreenTasks.find((x) => taskWaiting(x)) || null;
6374
6422
  useTicker(ctx, animOn);
6375
6423
  const now = Date.now();
6376
6424
  const elapsed = active.length > 0 ? fmtClock(now - Math.min(...active.map((x) => x.startTime || now))) : "";
@@ -6404,7 +6452,7 @@ function AnimationOverlay(props) {
6404
6452
  const spaceModeOn = !!(cfg && cfg.animationEnabled && mode === "space" && !panelOpen);
6405
6453
  const spaceDocks = useSpaceDocks(spaceModeOn);
6406
6454
  const spaceGalaxies = spaceModeOn && spaceDocks ? spaceGalaxyLayout() : null;
6407
- const stuckTask = onScreenTasks.find((task) => task.phase === "code" && now - (task.lastActivityAt || task.phaseAt || now) >= 18e3) || null;
6455
+ const stuckTask = onScreenTasks.find((task) => task.phase === "code" && taskStalled(task, now, 18e3)) || null;
6408
6456
  const robotScaleFromConfig = Math.max(0.85, Math.min(2.2, Number(cfg && cfg.robotScale) || 1.35));
6409
6457
  const speedStyle = { "--dkan-speed": Number(speed).toFixed(2) };
6410
6458
  const saveRobotScale = (0, import_react9.useCallback)((robotScale) => {
@@ -6519,7 +6567,7 @@ function AnimationOverlay(props) {
6519
6567
  ambientOn && mode === "flow" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-line", style: speedStyle, "aria-hidden": "true" }) : null,
6520
6568
  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
6569
  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,
6570
+ spaceModeOn && stuckTask ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ProgrammingStuck, { task: stuckTask, waiting: taskWaiting(stuckTask) }) : null,
6523
6571
  !panelOpen ? departures.map((departure) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MissionDeparture, { departure }, departure.id)) : null,
6524
6572
  ambientOn && mode === "orbit" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-orbit", style: speedStyle, "aria-hidden": "true" }) : null,
6525
6573
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BurstLayer, { bursts }),
@@ -6530,7 +6578,7 @@ function AnimationOverlay(props) {
6530
6578
  role: "button",
6531
6579
  tabIndex: 0,
6532
6580
  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",
6581
+ 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
6582
  onPointerDown: onBotPointerDown,
6535
6583
  onPointerMove: onBotPointerMove,
6536
6584
  onPointerUp: onBotPointerUp,
@@ -6549,7 +6597,7 @@ function AnimationOverlay(props) {
6549
6597
  " \u4E2A\u4EFB\u52A1",
6550
6598
  elapsed ? " \xB7 " + elapsed : "",
6551
6599
  " \xB7 ",
6552
- waitingTask ? "\u7B49\u5F85\u786E\u8BA4" : phaseLabel(phase)
6600
+ waitingTask ? waitWord : phaseLabel(phase)
6553
6601
  ] }),
6554
6602
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
6555
6603
  "button",
@@ -6581,7 +6629,7 @@ function AnimationOverlay(props) {
6581
6629
  type: "button",
6582
6630
  className: "dkan-badge" + (mode === "breathe" ? " dkan-badge-breathe" : ""),
6583
6631
  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",
6632
+ 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
6633
  onClick: () => openPanel("animation"),
6586
6634
  children: [
6587
6635
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dkan-dotwrap", children: [
@@ -6594,7 +6642,7 @@ function AnimationOverlay(props) {
6594
6642
  " \u4E2A\u4EFB\u52A1",
6595
6643
  elapsed ? " \xB7 " + elapsed : "",
6596
6644
  " \xB7 ",
6597
- waitingTask ? "\u7B49\u5F85\u786E\u8BA4" : phaseLabel(phase)
6645
+ waitingTask ? waitWord : phaseLabel(phase)
6598
6646
  ] })
6599
6647
  ]
6600
6648
  }
@@ -6776,7 +6824,7 @@ function AnimationView(props) {
6776
6824
  }
6777
6825
  if (saveErr) rows.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-note dkan-err", children: saveErr }, "err"));
6778
6826
  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")
6827
+ /* @__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
6828
  );
6781
6829
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dkan-root", children: rows });
6782
6830
  }
@@ -7295,6 +7343,50 @@ function utterCtor() {
7295
7343
  function voiceSupported() {
7296
7344
  return synthOf() !== null && utterCtor() !== null;
7297
7345
  }
7346
+ var VOICE_CLIENT_KEY = "dsh-dock/notify/voice-client/v1";
7347
+ function voiceClientEnabled() {
7348
+ try {
7349
+ if (typeof localStorage === "undefined") return true;
7350
+ return localStorage.getItem(VOICE_CLIENT_KEY) !== "0";
7351
+ } catch {
7352
+ return true;
7353
+ }
7354
+ }
7355
+ function setVoiceClientEnabled(on) {
7356
+ try {
7357
+ if (typeof localStorage !== "undefined") localStorage.setItem(VOICE_CLIENT_KEY, on ? "1" : "0");
7358
+ } catch {
7359
+ }
7360
+ }
7361
+ function voiceAllowed(cfg) {
7362
+ return !!cfg && cfg.voiceNotify === true && voiceClientEnabled();
7363
+ }
7364
+ function useVoiceClientEnabled() {
7365
+ const [on, setOn] = (0, import_react10.useState)(() => voiceClientEnabled());
7366
+ (0, import_react10.useEffect)(() => {
7367
+ const sync = () => setOn(voiceClientEnabled());
7368
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") return void 0;
7369
+ window.addEventListener("storage", sync);
7370
+ return () => {
7371
+ if (typeof window.removeEventListener === "function") window.removeEventListener("storage", sync);
7372
+ };
7373
+ }, []);
7374
+ const set = (0, import_react10.useCallback)((next) => {
7375
+ const v = next !== false;
7376
+ setVoiceClientEnabled(v);
7377
+ setOn(v);
7378
+ if (!v) {
7379
+ const s = synthOf();
7380
+ if (s) {
7381
+ try {
7382
+ s.cancel();
7383
+ } catch {
7384
+ }
7385
+ }
7386
+ }
7387
+ }, []);
7388
+ return [on, set];
7389
+ }
7298
7390
  function localVoices() {
7299
7391
  const s = synthOf();
7300
7392
  if (!s) return [];
@@ -7407,6 +7499,14 @@ function speakVoice(text, cfg) {
7407
7499
  poll();
7408
7500
  return true;
7409
7501
  }
7502
+ function voiceTone(cfg) {
7503
+ const m = cfg && cfg.voiceMode;
7504
+ return m === "detailed" || m === "medium" ? m : "brief";
7505
+ }
7506
+ function cardTone(cfg) {
7507
+ const m = cfg && cfg.cardMode;
7508
+ return m === "brief" || m === "medium" ? m : "detailed";
7509
+ }
7410
7510
  function endReasonSpeech(reason) {
7411
7511
  if (reason === "error") return "\u51FA\u9519\u4E86";
7412
7512
  if (reason === "aborted") return "\u5DF2\u505C\u6B62";
@@ -7416,12 +7516,21 @@ function endReasonSpeech(reason) {
7416
7516
  return "\u5B8C\u6210\u4E86";
7417
7517
  }
7418
7518
  function endBroadcastText(success, record, task, cfg) {
7419
- const mode = cfg && cfg.voiceMode === "detailed" ? "detailed" : "brief";
7519
+ const mode = voiceTone(cfg);
7420
7520
  const reason = record && record.endReason || "";
7421
7521
  const title = record && record.title || task && task.title || "";
7422
7522
  if (mode === "brief") {
7423
7523
  return success ? "\u4EFB\u52A1\u5B8C\u6210" : "\u4EFB\u52A1\u505C\u6B62\u4E86";
7424
7524
  }
7525
+ if (mode === "medium") {
7526
+ const who = title ? "\u4EFB\u52A1\u300C" + truncate2(title, 30) + "\u300D" : "\u4EFB\u52A1";
7527
+ const parts2 = [success ? who + "\u5B8C\u6210\u4E86" : who + "\u505C\u6B62\u4E86"];
7528
+ if (!success) parts2.push("\uFF0C\u539F\u56E0\uFF1A" + endReasonSpeech(reason));
7529
+ const dur2 = record && record.duration || 0;
7530
+ if (dur2 > 0) parts2.push("\uFF0C\u8017\u65F6" + fmtDur(dur2));
7531
+ parts2.push("\u3002");
7532
+ return parts2.join("");
7533
+ }
7425
7534
  const parts = [];
7426
7535
  if (title) parts.push("\u4EFB\u52A1\uFF1A" + truncate2(title, 30) + "\u3002");
7427
7536
  parts.push(success ? "\u5DF2\u5B8C\u6210\u3002" : "\u7ED3\u675F\uFF0C\u539F\u56E0\uFF1A" + endReasonSpeech(reason) + "\u3002");
@@ -7439,24 +7548,58 @@ function endBroadcastText(success, record, task, cfg) {
7439
7548
  return parts.join("");
7440
7549
  }
7441
7550
  function confirmBroadcastText(task, approval, cfg) {
7442
- const mode = cfg && cfg.voiceMode === "detailed" ? "detailed" : "brief";
7551
+ const mode = voiceTone(cfg);
7443
7552
  if (mode === "brief") return "\u4EFB\u52A1\u9700\u8981\u6388\u6743";
7444
7553
  const tool = approval && approval.toolName || "\u5DE5\u5177";
7445
7554
  const scene = toolLabel(tool);
7555
+ if (mode === "medium") {
7556
+ const who = task && task.title ? "\u4EFB\u52A1\u300C" + truncate2(task.title, 30) + "\u300D" : "\u4EFB\u52A1";
7557
+ return who + "\u9700\u8981\u6388\u6743\uFF0C\u6B63\u5728\u7B49\u4F60\u6279\u51C6" + (scene || "\u5DE5\u5177 " + tool) + "\u3002";
7558
+ }
7446
7559
  const parts = [];
7447
7560
  if (task && task.title) parts.push("\u4EFB\u52A1\uFF1A" + truncate2(task.title, 30) + "\u3002");
7448
7561
  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");
7449
7562
  return parts.join("");
7450
7563
  }
7451
- function stuckBroadcastText(task, cfg) {
7452
- const mode = cfg && cfg.voiceMode === "detailed" ? "detailed" : "brief";
7453
- if (mode === "brief") return "\u4EFB\u52A1\u5361\u4F4F\u4E86";
7564
+ function questionBroadcastText(task, question, cfg) {
7565
+ const mode = voiceTone(cfg);
7566
+ if (mode === "brief") return "\u4EFB\u52A1\u9700\u8981\u4F60\u56DE\u7B54";
7567
+ const who = task && task.title ? "\u4EFB\u52A1\u300C" + truncate2(task.title, 30) + "\u300D" : "\u4EFB\u52A1";
7568
+ const head = question && question.header || "";
7569
+ const body = question && question.question || "";
7570
+ const what = body ? truncate2(body.replace(/[#*_`>\[\]()!]/g, ""), 40) : "";
7571
+ if (mode === "medium") {
7572
+ const tail = what ? "\uFF1A" + what : head ? "\uFF1A" + head : "";
7573
+ return who + "\u5728\u7B49\u4F60\u56DE\u7B54" + tail + "\u3002";
7574
+ }
7454
7575
  const parts = [];
7455
7576
  if (task && task.title) parts.push("\u4EFB\u52A1\uFF1A" + truncate2(task.title, 30) + "\u3002");
7456
- parts.push("\u7F16\u7A0B\u9636\u6BB5\u5DF2\u7ECF" + fmtDur(Math.max(0, cfg && cfg.stuckMs || STUCK_MS)) + "\u6CA1\u6709\u4EFB\u4F55\u52A8\u9759\uFF0C\u53EF\u80FD\u5361\u4F4F\u4E86\uFF0C\u8BF7\u67E5\u770B\u3002");
7577
+ parts.push(what ? "\u6B63\u5728\u7B49\u4F60\u56DE\u7B54\u95EE\u9898\uFF1A" + what + "\u3002" : "\u6B63\u5728\u7B49\u4F60\u56DE\u7B54\u95EE\u9898\u3002");
7578
+ const count = question && question.count || 0;
7579
+ if (count > 1) parts.push("\u5171 " + count + " \u4E2A\u95EE\u9898\u3002");
7580
+ parts.push("\u8BF7\u56DE\u5230\u4F1A\u8BDD\u9009\u62E9\u7B54\u6848\u3002");
7581
+ return parts.join("");
7582
+ }
7583
+ function stuckBroadcastText(task, cfg) {
7584
+ const mode = voiceTone(cfg);
7585
+ const where = (task && task.isSubtask ? "\u5B50\u4EFB\u52A1" : "\u4E3B\u4EFB\u52A1") + (task && task.title ? "\u300C" + truncate2(task.title, 30) + "\u300D" : "");
7586
+ if (mode === "brief") return where + "\u5361\u4F4F\u4E86";
7587
+ if (mode === "medium") {
7588
+ return where + "\u5361\u4F4F\u4E86\uFF0C\u5DF2\u7ECF" + fmtDur(Math.max(0, cfg && cfg.stuckMs || STUCK_MS)) + "\u6CA1\u6709\u4EFB\u4F55\u52A8\u9759\u3002";
7589
+ }
7590
+ const parts = [where + "\u5361\u4F4F\u4E86\u3002"];
7591
+ parts.push("\u7F16\u7A0B\u9636\u6BB5\u5DF2\u7ECF" + fmtDur(Math.max(0, cfg && cfg.stuckMs || STUCK_MS)) + "\u6CA1\u6709\u4EFB\u4F55\u52A8\u9759\uFF0C");
7592
+ const tool = task && task.lastToolName || "";
7593
+ const scene = tool ? toolLabel(tool) : "";
7594
+ parts.push(tool ? "\u6700\u540E\u5728\u6267\u884C" + tool + (scene ? "\uFF08" + scene + "\uFF09" : "") + "\uFF0C" : "");
7595
+ parts.push("\u8BF7\u67E5\u770B\u3002");
7457
7596
  return parts.join("");
7458
7597
  }
7459
7598
  var STUCK_MS = 18e3;
7599
+ function stuckMsOf(cfg) {
7600
+ const v = cfg && Number(cfg.stuckMs);
7601
+ return Number.isFinite(v) && v > 0 ? v : STUCK_MS;
7602
+ }
7460
7603
  var notifyStore = {
7461
7604
  snap: { status: null, loading: false, error: null },
7462
7605
  listeners: /* @__PURE__ */ new Set(),
@@ -7565,9 +7708,9 @@ function Toast(props) {
7565
7708
  }, []);
7566
7709
  const jump = (0, import_react10.useCallback)(() => {
7567
7710
  if (!t.sessionTitle && !t.sessionId) return;
7568
- const ok = openSessionById(t.sessionId) || (t.sessionTitle ? openSessionByTitle(t.sessionTitle) : false);
7569
- if (ok && t.kind !== "confirm") setClosing(true);
7570
- }, [t.sessionId, t.sessionTitle, t.kind]);
7711
+ const ok = openSessionById(t.sessionId) || (t.fallbackSessionId ? openSessionById(t.fallbackSessionId) : false) || (t.sessionTitle ? openSessionByTitle(t.sessionTitle) : false);
7712
+ if (ok && t.kind !== "confirm" && t.kind !== "stuck") setClosing(true);
7713
+ }, [t.sessionId, t.sessionTitle, t.fallbackSessionId, t.kind]);
7571
7714
  (0, import_react10.useEffect)(() => {
7572
7715
  if (t.closing && !closing) setClosing(true);
7573
7716
  }, [t.closing, closing]);
@@ -7586,7 +7729,7 @@ function Toast(props) {
7586
7729
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-toast-head", children: [
7587
7730
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-toast-mark", style: { background: markColor } }),
7588
7731
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-toast-title", title: t.sessionTitle || t.title, children: [
7589
- t.kind === "confirm" ? "\u270B " : "",
7732
+ t.kind === "confirm" ? "\u270B " : t.kind === "stuck" ? "\u23F3 " : "",
7590
7733
  props.collapsed ? t.sessionTitle || t.title : t.title,
7591
7734
  !props.collapsed && t.sessionTitle && t.kind !== "confirm" ? " \xB7 " + t.sessionTitle : ""
7592
7735
  ] }),
@@ -7616,10 +7759,18 @@ function NotifyOverlay(props) {
7616
7759
  const [stackHover, setStackHover] = (0, import_react10.useState)(false);
7617
7760
  const prevActiveRef = (0, import_react10.useRef)(null);
7618
7761
  const remindedApprovalsRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
7762
+ const remindedQuestionsRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
7619
7763
  const toastSeqRef = (0, import_react10.useRef)(0);
7620
7764
  const pushToast = (0, import_react10.useCallback)((toast) => {
7765
+ const st = notifyStore.snap.status;
7766
+ const cfg = st && st.config;
7767
+ if (cfg && cfg.notifyCards === false) return;
7621
7768
  setToasts((prev) => prev.concat([toast]).slice(-12));
7622
7769
  }, []);
7770
+ (0, import_react10.useEffect)(() => {
7771
+ const cfg = snap.status && snap.status.config;
7772
+ if (cfg && cfg.notifyCards === false) setToasts((prev) => prev.length ? [] : prev);
7773
+ }, [snap.status]);
7623
7774
  (0, import_react10.useEffect)(() => {
7624
7775
  let stopped = false;
7625
7776
  let timer = null;
@@ -7663,7 +7814,7 @@ function NotifyOverlay(props) {
7663
7814
  if (!activeIds.has(sid)) remindedApprovalsRef.current.delete(sid);
7664
7815
  }
7665
7816
  for (const task of st.active) {
7666
- const approvals = Array.isArray(task.approvals) ? task.approvals : [];
7817
+ const approvals = taskApprovals(task);
7667
7818
  if (approvals.length === 0) continue;
7668
7819
  let seen = remindedApprovalsRef.current.get(task.sessionId);
7669
7820
  if (!seen) {
@@ -7673,18 +7824,23 @@ function NotifyOverlay(props) {
7673
7824
  const fresh = approvals.filter((a) => a && !seen.has(a.id));
7674
7825
  if (fresh.length === 0) continue;
7675
7826
  for (const a of fresh) seen.add(a.id);
7676
- if (cfg.voiceNotify === true && cfg.voiceOnConfirm !== false) {
7827
+ if (voiceAllowed(cfg) && cfg.voiceOnConfirm !== false) {
7677
7828
  speakVoice(confirmBroadcastText(task, fresh[0], cfg), cfg);
7678
7829
  }
7679
7830
  if (cfg.notifyOnConfirm === false) continue;
7680
7831
  const toolName = fresh[0].toolName || "";
7681
7832
  const scene = toolLabel(toolName);
7833
+ const tone = cardTone(cfg);
7682
7834
  const lines = [
7683
7835
  "\u4EFB\u52A1\uFF1A" + (task.title || "(\u65E0\u6807\u9898)"),
7684
7836
  "\u5DE5\u5177\uFF1A" + (toolName || "\u672A\u77E5") + (scene ? "\uFF08" + scene + "\uFF09" : "")
7685
7837
  ];
7686
- if (fresh[0].reason) lines.push("\u8BF4\u660E\uFF1A" + truncate2(fresh[0].reason, 140));
7687
- lines.push(fresh.length > 1 ? "\u5171 " + fresh.length + " \u9879\u7B49\u5F85\u4F60\u7684\u786E\u8BA4" : "\u8BF7\u5728\u4F1A\u8BDD\u91CC\u786E\u8BA4\u540E\u7EE7\u7EED");
7838
+ if (tone !== "brief" && fresh[0].reason) lines.push("\u8BF4\u660E\uFF1A" + truncate2(fresh[0].reason, 140));
7839
+ if (fresh.length > 1) {
7840
+ lines.push(tone === "brief" ? "\u5171 " + fresh.length + " \u9879\u7B49\u5F85\u786E\u8BA4" : "\u5171 " + fresh.length + " \u9879\u7B49\u5F85\u4F60\u7684\u786E\u8BA4");
7841
+ } else if (tone === "detailed") {
7842
+ lines.push("\u8BF7\u5728\u4F1A\u8BDD\u91CC\u786E\u8BA4\u540E\u7EE7\u7EED");
7843
+ }
7688
7844
  pushToast({
7689
7845
  id: ++toastSeqRef.current,
7690
7846
  kind: "confirm",
@@ -7709,19 +7865,74 @@ function NotifyOverlay(props) {
7709
7865
  }
7710
7866
  }
7711
7867
  }, [snap.status]);
7868
+ (0, import_react10.useEffect)(() => {
7869
+ const st = snap.status;
7870
+ if (!st || !st.active) return;
7871
+ const cfg = st.config || {};
7872
+ const activeIds = new Set(st.active.map((x) => x.sessionId));
7873
+ for (const [sid, seen] of remindedQuestionsRef.current) {
7874
+ if (!activeIds.has(sid)) remindedQuestionsRef.current.delete(sid);
7875
+ }
7876
+ for (const task of st.active) {
7877
+ const questions = taskQuestions(task);
7878
+ if (questions.length === 0) continue;
7879
+ let seen = remindedQuestionsRef.current.get(task.sessionId);
7880
+ if (!seen) {
7881
+ seen = /* @__PURE__ */ new Set();
7882
+ remindedQuestionsRef.current.set(task.sessionId, seen);
7883
+ }
7884
+ const fresh = questions.filter((q) => q && q.id && !seen.has(q.id));
7885
+ if (fresh.length === 0) continue;
7886
+ for (const q of fresh) seen.add(q.id);
7887
+ if (voiceAllowed(cfg) && cfg.voiceOnConfirm !== false) {
7888
+ speakVoice(questionBroadcastText(task, fresh[0], cfg), cfg);
7889
+ }
7890
+ if (cfg.notifyOnConfirm === false) continue;
7891
+ const tone = cardTone(cfg);
7892
+ const head = fresh[0].header || "";
7893
+ const body = fresh[0].question || "";
7894
+ const lines = ["\u4EFB\u52A1\uFF1A" + (task.title || "(\u65E0\u6807\u9898)")];
7895
+ if (body) lines.push((head ? head + "\uFF1A" : "\u95EE\u9898\uFF1A") + truncate2(body, 140));
7896
+ else if (head) lines.push("\u95EE\u9898\uFF1A" + head);
7897
+ const count = fresh[0].count || 0;
7898
+ if (count > 1) lines.push(tone === "brief" ? "\u5171 " + count + " \u4E2A\u95EE\u9898" : "\u5171 " + count + " \u4E2A\u95EE\u9898\u7B49\u4F60\u9009\u62E9");
7899
+ if (tone === "detailed") lines.push("\u8BF7\u5728\u4F1A\u8BDD\u91CC\u9009\u597D\u7B54\u6848\u540E\u7EE7\u7EED");
7900
+ pushToast({
7901
+ id: ++toastSeqRef.current,
7902
+ kind: "confirm",
7903
+ title: "\u4EFB\u52A1\u9700\u8981\u4F60\u56DE\u7B54",
7904
+ body: lines.join("\n"),
7905
+ // 点卡片直达该会话去选答案(与需确认卡同哲学:问题没答完卡片就该在)
7906
+ sessionId: task.sessionId || "",
7907
+ sessionTitle: task.title || "",
7908
+ // 与这批提问绑定:回答落地后宿主把它们移出 questions,下面的对账 effect 据此收起
7909
+ questionKeys: fresh.map((q) => task.sessionId + "|" + q.id)
7910
+ });
7911
+ if (cfg.soundNotify !== false) playAskSound(cfg.soundEffect);
7912
+ if (cfg.systemNotify && typeof document !== "undefined" && document.hidden && typeof Notification !== "undefined" && Notification.permission === "granted") {
7913
+ try {
7914
+ new Notification("dsh \u4EFB\u52A1\u9700\u8981\u4F60\u56DE\u7B54", {
7915
+ body: (task.title || "(\u65E0\u6807\u9898)") + " \xB7 " + (head || "\u6709\u4E00\u95EE\u5728\u7B49\u4F60\u9009\u62E9"),
7916
+ tag: "dsh-dock-question-" + task.sessionId
7917
+ });
7918
+ } catch {
7919
+ }
7920
+ }
7921
+ }
7922
+ }, [snap.status]);
7712
7923
  (0, import_react10.useEffect)(() => {
7713
7924
  const st = snap.status;
7714
7925
  if (!st || !st.active) return;
7715
7926
  const live = /* @__PURE__ */ new Set();
7716
7927
  for (const task of st.active) {
7717
- const approvals = Array.isArray(task.approvals) ? task.approvals : [];
7718
- for (const a of approvals) if (a && a.id) live.add(task.sessionId + "|" + a.id);
7928
+ for (const a of taskApprovals(task)) if (a && a.id) live.add(task.sessionId + "|" + a.id);
7929
+ for (const q of taskQuestions(task)) if (q && q.id) live.add(task.sessionId + "|" + q.id);
7719
7930
  }
7720
7931
  setToasts((prev) => {
7721
7932
  let changed = false;
7722
7933
  const next = prev.map((x) => {
7723
7934
  if (x.kind !== "confirm" || x.closing) return x;
7724
- const keys = Array.isArray(x.approvalKeys) ? x.approvalKeys : [];
7935
+ const keys = [].concat(Array.isArray(x.approvalKeys) ? x.approvalKeys : []).concat(Array.isArray(x.questionKeys) ? x.questionKeys : []);
7725
7936
  if (keys.length === 0 || keys.some((k) => live.has(k))) return x;
7726
7937
  changed = true;
7727
7938
  return Object.assign({}, x, { closing: true });
@@ -7737,7 +7948,7 @@ function NotifyOverlay(props) {
7737
7948
  setToasts((prev) => {
7738
7949
  let changed = false;
7739
7950
  const next = prev.map((x) => {
7740
- if (x.kind === "confirm" || x.closing) return x;
7951
+ if (x.kind === "confirm" || x.kind === "stuck" || x.closing) return x;
7741
7952
  if (!x.sessionTitle && !x.sessionId) return x;
7742
7953
  const hit = cur.id && x.sessionId && cur.id === x.sessionId || !cur.id && x.sessionTitle && titleMatches(x.sessionTitle, cur.title);
7743
7954
  if (!hit) return x;
@@ -7759,30 +7970,76 @@ function NotifyOverlay(props) {
7759
7970
  for (const sid of Array.from(stuckSeenRef.current.keys())) {
7760
7971
  if (!activeIds.has(sid)) stuckSeenRef.current.delete(sid);
7761
7972
  }
7762
- if (cfg.voiceNotify !== true || cfg.voiceOnStuck === false) return;
7973
+ const parentsWaitingOnSubtask = /* @__PURE__ */ new Set();
7974
+ for (const t of st.active) {
7975
+ if (t.isSubtask && t.parentSessionId) parentsWaitingOnSubtask.add(t.parentSessionId);
7976
+ }
7763
7977
  for (const task of st.active) {
7764
- const approvals = Array.isArray(task.approvals) ? task.approvals : [];
7765
- if (approvals.length > 0) {
7978
+ if (taskWaiting(task)) {
7766
7979
  stuckSeenRef.current.delete(task.sessionId);
7767
7980
  continue;
7768
7981
  }
7769
7982
  if (task.phase !== "code") {
7770
7983
  continue;
7771
7984
  }
7772
- const lastAct = task.lastActivityAt || task.phaseAt || 0;
7773
- if (!lastAct || now - lastAct < STUCK_MS) continue;
7985
+ if (parentsWaitingOnSubtask.has(task.sessionId)) continue;
7986
+ const lastAct = taskActivityAt(task);
7987
+ const stuckMs = taskStalled(task, now, stuckMsOf(cfg));
7988
+ if (!stuckMs) continue;
7774
7989
  const prev = stuckSeenRef.current.get(task.sessionId);
7775
7990
  if (prev === lastAct) continue;
7776
7991
  stuckSeenRef.current.set(task.sessionId, lastAct);
7777
- speakVoice(stuckBroadcastText(task, Object.assign({}, cfg, { stuckMs: now - lastAct })), cfg);
7992
+ if (voiceAllowed(cfg) && cfg.voiceOnStuck !== false) {
7993
+ speakVoice(stuckBroadcastText(task, Object.assign({}, cfg, { stuckMs })), cfg);
7994
+ }
7995
+ if (cfg.notifyOnStuck === false) continue;
7996
+ const label = task.isSubtask ? "\u5B50\u4EFB\u52A1" : "\u4E3B\u4EFB\u52A1";
7997
+ const title = task.title || "(\u65E0\u6807\u9898)";
7998
+ const tool = task.lastToolName || "";
7999
+ const tone = cardTone(cfg);
8000
+ const lines = ["\u4EFB\u52A1\uFF1A" + label + "\xB7" + title];
8001
+ if (tone !== "brief") lines.push("\u5DF2\u505C\u6EDE\uFF1A" + fmtDur(stuckMs) + "\uFF08\u7F16\u7A0B\u9636\u6BB5\u65E0\u6D3B\u52A8\uFF09");
8002
+ if (tone === "detailed") {
8003
+ if (tool) lines.push("\u6700\u540E\u52A8\u4F5C\uFF1A" + tool + (toolLabel(tool) ? "\uFF08" + toolLabel(tool) + "\uFF09" : ""));
8004
+ lines.push("\u6062\u590D\u6D3B\u52A8\u6216\u4EFB\u52A1\u7ED3\u675F\u540E\u81EA\u52A8\u6536\u8D77\uFF1B\u70B9\u51FB\u5361\u7247\u76F4\u8FBE\u4F1A\u8BDD");
8005
+ }
8006
+ pushToast({
8007
+ id: ++toastSeqRef.current,
8008
+ kind: "stuck",
8009
+ title: label + "\u5361\u4F4F\u4E86",
8010
+ body: lines.join("\n"),
8011
+ sessionId: task.sessionId || "",
8012
+ sessionTitle: title,
8013
+ // 子任务会话通常不在侧栏里:跳不到自己时回退到父会话(看主会话里的子代理进度)
8014
+ fallbackSessionId: task.isSubtask && task.parentSessionId ? task.parentSessionId : "",
8015
+ // 停点指纹:恢复活动(lastActivityAt 变了)即由下面的对账 effect 收起
8016
+ stuckAt: lastAct
8017
+ });
7778
8018
  }
7779
8019
  }, [snap.status]);
8020
+ (0, import_react10.useEffect)(() => {
8021
+ const st = snap.status;
8022
+ if (!st || !st.active) return;
8023
+ const byId = new Map(st.active.map((x) => [x.sessionId, x]));
8024
+ setToasts((prev) => {
8025
+ let changed = false;
8026
+ const next = prev.map((x) => {
8027
+ if (x.kind !== "stuck" || x.closing) return x;
8028
+ const task = byId.get(x.sessionId);
8029
+ const stillStalled = !!task && taskActivityAt(task) === x.stuckAt && !taskWaiting(task);
8030
+ if (stillStalled) return x;
8031
+ changed = true;
8032
+ return Object.assign({}, x, { closing: true });
8033
+ });
8034
+ return changed ? next : prev;
8035
+ });
8036
+ }, [snap.status]);
7780
8037
  const handleTaskEnd = (task, record, cfg) => {
7781
8038
  const reason = record && record.endReason || "";
7782
8039
  const success = isSuccessReason2(reason);
7783
8040
  const info = endInfo(reason);
7784
8041
  const wanted = success ? cfg.notifyOnComplete : cfg.notifyOnError;
7785
- if (cfg.voiceNotify === true && (success ? cfg.voiceOnComplete !== false : cfg.voiceOnError !== false)) {
8042
+ if (voiceAllowed(cfg) && (success ? cfg.voiceOnComplete !== false : cfg.voiceOnError !== false)) {
7786
8043
  speakVoice(endBroadcastText(success, record, task, cfg), cfg);
7787
8044
  }
7788
8045
  if (wanted === false) return;
@@ -7790,15 +8047,17 @@ function NotifyOverlay(props) {
7790
8047
  const provider = record && record.provider || task.provider || "";
7791
8048
  const startTs = record && record.startTime || task.startTime;
7792
8049
  const endTs = record && record.endTime || Date.now();
7793
- const lines = [
7794
- "\u4EFB\u52A1\uFF1A" + (record && record.title || task.title || "(\u65E0\u6807\u9898)"),
7795
- "\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""),
7796
- "\u8017\u65F6\uFF1A" + fmtDur(record && record.duration || endTs - startTs) + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09",
7797
- "\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" : ""),
7798
- "Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens)
7799
- ];
7800
- if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate2(record.lastText, 140));
7801
- if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate2(record.errorMessage, 120));
8050
+ const tone = cardTone(cfg);
8051
+ const durText = fmtDur(record && record.duration || endTs - startTs);
8052
+ const lines = ["\u4EFB\u52A1\uFF1A" + (record && record.title || task.title || "(\u65E0\u6807\u9898)")];
8053
+ if (tone !== "brief") lines.push("\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""));
8054
+ lines.push(tone === "brief" ? "\u8017\u65F6\uFF1A" + durText : "\u8017\u65F6\uFF1A" + durText + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09");
8055
+ if (tone === "detailed") {
8056
+ 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" : ""));
8057
+ lines.push("Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens));
8058
+ if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate2(record.lastText, 140));
8059
+ if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate2(record.errorMessage, 120));
8060
+ }
7802
8061
  const title = success ? "\u4EFB\u52A1\u5B8C\u6210" : "\u4EFB\u52A1" + info.label;
7803
8062
  pushToast({
7804
8063
  id: ++toastSeqRef.current,
@@ -7846,6 +8105,7 @@ function NotifyOverlay(props) {
7846
8105
  function NotifyView(props) {
7847
8106
  const snap = useNotify();
7848
8107
  const voices = useLocalVoices();
8108
+ const [voiceClientOn, setVoiceClientOn] = useVoiceClientEnabled();
7849
8109
  const [cfg, setCfg] = (0, import_react10.useState)(null);
7850
8110
  const [saveErr, setSaveErr] = (0, import_react10.useState)("");
7851
8111
  const [testing, setTesting] = (0, import_react10.useState)(false);
@@ -7971,6 +8231,19 @@ function NotifyView(props) {
7971
8231
  /* @__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" })
7972
8232
  ] }),
7973
8233
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8234
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8235
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u9875\u5185\u5361\u7247" }),
8236
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8237
+ "button",
8238
+ {
8239
+ type: "button",
8240
+ className: "dknt-miniswitch" + (cfg.notifyCards !== false ? " on" : ""),
8241
+ onClick: () => patch({ notifyCards: cfg.notifyCards === false }),
8242
+ children: cfg.notifyCards !== false ? "\u5F00" : "\u5173"
8243
+ }
8244
+ ),
8245
+ /* @__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" })
8246
+ ] }),
7974
8247
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
7975
8248
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5B8C\u6210\u901A\u77E5" }),
7976
8249
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -8008,7 +8281,20 @@ function NotifyView(props) {
8008
8281
  children: cfg.notifyOnConfirm !== false ? "\u5F00" : "\u5173"
8009
8282
  }
8010
8283
  ),
8011
- /* @__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" })
8284
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u5DE5\u5177\u7B49\u4F60\u6279\u51C6\u3001\u6216\u4F1A\u8BDD\u63D0\u95EE\u7B49\u4F60\u9009\u7B54\u6848\u65F6\u5F39\u5361\u7247\u5E76\u54CD\u786E\u8BA4\u97F3\uFF1B\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\u3002\u8FD9\u4E24\u79CD\u300C\u505C\u5728\u539F\u5730\u7B49\u4EBA\u300D\u90FD\u4E0D\u7B97\u5361\u4F4F" })
8285
+ ] }),
8286
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8287
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u4F4F\u63D0\u9192" }),
8288
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8289
+ "button",
8290
+ {
8291
+ type: "button",
8292
+ className: "dknt-miniswitch" + (cfg.notifyOnStuck !== false ? " on" : ""),
8293
+ onClick: () => patch({ notifyOnStuck: cfg.notifyOnStuck === false }),
8294
+ children: cfg.notifyOnStuck !== false ? "\u5F00" : "\u5173"
8295
+ }
8296
+ ),
8297
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7F16\u7A0B\u9636\u6BB5\u957F\u65F6\u95F4\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\u3002\u7B49\u6279\u51C6\u3001\u7B49\u56DE\u7B54\u3001\u547D\u4EE4\u8FD8\u5728\u8DD1\u3001\u6B63\u5728\u538B\u7F29\u4E0A\u4E0B\u6587\u7684\u4F1A\u8BDD\u90FD\u4E0D\u7B97\u5361\u4F4F\uFF08\u90A3\u4E9B\u90FD\u662F\u5728\u5E72\u6D3B\uFF0C\u522B\u91CD\u590D\u8F70\u70B8\uFF09\uFF08\u8BED\u97F3\u64AD\u62A5\u8D70\u300C\u8BED\u97F3\u64AD\u62A5\u300D\u533A\u7684\u5361\u4F4F\u5F00\u5173\uFF0C\u4E92\u4E0D\u5E72\u6270\uFF09" })
8012
8298
  ] })
8013
8299
  ] })
8014
8300
  ] }, "events"),
@@ -8018,9 +8304,25 @@ function NotifyView(props) {
8018
8304
  /* @__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" })
8019
8305
  ] }),
8020
8306
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8307
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8308
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u7247\u53E3\u5F84" }),
8309
+ [["brief", "\u7B80\u6D01"], ["medium", "\u9002\u4E2D"], ["detailed", "\u8BE6\u7EC6"]].map(([v, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8310
+ "button",
8311
+ {
8312
+ type: "button",
8313
+ className: "dknt-miniswitch" + (cardTone(cfg) === v ? " on" : ""),
8314
+ style: { marginRight: 6 },
8315
+ title: "\u53F3\u4FA7\u901A\u77E5\u5361\u7247\u6B63\u6587\u6309" + label + "\u6863\u663E\u793A",
8316
+ onClick: () => patch({ cardMode: v }),
8317
+ children: label
8318
+ },
8319
+ v
8320
+ )),
8321
+ /* @__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" })
8322
+ ] }),
8021
8323
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8022
8324
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u7247\u6536\u7EB3" }),
8023
- /* @__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\u30023 \u5F20\u53CA\u4EE5\u4E0A\u81EA\u52A8\u53E0\u653E\u6210\u6807\u9898\u6761\uFF0C\u9F20\u6807\u79FB\u4E0A\u53BB\u6574\u4F53\u5C55\u5F00" })
8325
+ /* @__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" })
8024
8326
  ] }),
8025
8327
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8026
8328
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u7CFB\u7EDF\u901A\u77E5" }),
@@ -8089,9 +8391,9 @@ function NotifyView(props) {
8089
8391
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8090
8392
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8091
8393
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u8BED\u97F3\u64AD\u62A5" }),
8092
- /* @__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" }),
8394
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u4EFB\u52A1\u5B8C\u6210 / \u505C\u6B62 / \u9700\u8981\u6388\u6743 / \u9700\u56DE\u7B54 / \u5361\u4F4F\u65F6\u7528\u6D4F\u89C8\u5668\u8BED\u97F3\uFF08TTS\uFF09\u8BF4\u4E00\u53E5\u8BDD\uFF1B\u670D\u52A1\u7AEF\u603B\u5F00\u5173\uFF08\u8DE8\u6D4F\u89C8\u5668\uFF09\u4E0E\u672C\u673A\u5F00\u5173\uFF08\u5F53\u524D\u6D4F\u89C8\u5668\uFF09\u90FD\u5F00\u542F\u624D\u64AD\u62A5" }),
8093
8395
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8094
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.voiceNotify ? " on" : ""), children: cfg.voiceNotify ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
8396
+ /* @__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" }),
8095
8397
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8096
8398
  "button",
8097
8399
  {
@@ -8099,42 +8401,53 @@ function NotifyView(props) {
8099
8401
  className: "dock-sw" + (cfg.voiceNotify ? " on" : ""),
8100
8402
  role: "switch",
8101
8403
  "aria-checked": cfg.voiceNotify,
8102
- "aria-label": "\u5F00\u5173\u8BED\u97F3\u64AD\u62A5",
8103
- title: cfg.voiceNotify ? "\u5173\u95ED\u8BED\u97F3\u64AD\u62A5" : "\u5F00\u542F\u8BED\u97F3\u64AD\u62A5",
8404
+ "aria-label": "\u5F00\u5173\u8BED\u97F3\u64AD\u62A5\uFF08\u670D\u52A1\u7AEF\u603B\u5F00\u5173\uFF09",
8405
+ title: 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",
8104
8406
  onClick: () => patch({ voiceNotify: !cfg.voiceNotify })
8105
8407
  }
8106
8408
  )
8107
8409
  ] })
8108
8410
  ] }),
8411
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8412
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u672C\u673A\u64AD\u62A5" }),
8413
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8414
+ "button",
8415
+ {
8416
+ type: "button",
8417
+ className: "dknt-miniswitch" + (voiceClientOn ? " on" : ""),
8418
+ role: "switch",
8419
+ "aria-checked": voiceClientOn,
8420
+ "aria-label": "\u5F00\u5173\u672C\u673A\u8BED\u97F3\u64AD\u62A5",
8421
+ title: voiceClientOn ? "\u5173\u95ED\u672C\u673A\u8BED\u97F3\u64AD\u62A5" : "\u5F00\u542F\u672C\u673A\u8BED\u97F3\u64AD\u62A5",
8422
+ onClick: () => setVoiceClientOn(!voiceClientOn),
8423
+ children: voiceClientOn ? "\u5F00" : "\u5173"
8424
+ }
8425
+ ),
8426
+ /* @__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" })
8427
+ ] }),
8109
8428
  cfg.voiceNotify ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8110
8429
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8111
8430
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u53E3\u5F84" }),
8112
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8113
- "button",
8114
- {
8115
- type: "button",
8116
- className: "dknt-miniswitch" + (cfg.voiceMode !== "detailed" ? " on" : ""),
8117
- onClick: () => patch({ voiceMode: "brief" }),
8118
- children: "\u7B80\u6D01"
8119
- }
8120
- ),
8121
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8431
+ [["brief", "\u7B80\u6D01"], ["medium", "\u9002\u4E2D"], ["detailed", "\u8BE6\u7EC6"]].map(([v, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8122
8432
  "button",
8123
8433
  {
8124
8434
  type: "button",
8125
- className: "dknt-miniswitch" + (cfg.voiceMode === "detailed" ? " on" : ""),
8126
- onClick: () => patch({ voiceMode: "detailed" }),
8127
- children: "\u8BE6\u7EC6"
8128
- }
8129
- ),
8130
- /* @__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 / \u4EFB\u52A1\u5361\u4F4F\u4E86\u300D\uFF1B\u8BE6\u7EC6\uFF1A\u5E26\u4E0A\u4EFB\u52A1\u6807\u9898\u3001\u8017\u65F6\u3001\u56DE\u5408\u7EDF\u8BA1\u4E0E\u539F\u56E0" })
8435
+ className: "dknt-miniswitch" + (voiceTone(cfg) === v ? " on" : ""),
8436
+ style: { marginRight: 6 },
8437
+ title: "\u8BED\u97F3\u64AD\u62A5\u6309" + label + "\u6863\u8BF4",
8438
+ onClick: () => patch({ voiceMode: v }),
8439
+ children: label
8440
+ },
8441
+ v
8442
+ )),
8443
+ /* @__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" })
8131
8444
  ] }),
8132
8445
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8133
8446
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u65F6\u523B" }),
8134
8447
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", style: { minWidth: 0 }, children: [
8135
8448
  ["voiceOnComplete", "\u5B8C\u6210", cfg.voiceOnComplete !== false],
8136
8449
  ["voiceOnError", "\u505C\u6B62", cfg.voiceOnError !== false],
8137
- ["voiceOnConfirm", "\u9700\u6388\u6743", cfg.voiceOnConfirm !== false],
8450
+ ["voiceOnConfirm", "\u9700\u6388\u6743/\u9700\u56DE\u7B54", cfg.voiceOnConfirm !== false],
8138
8451
  ["voiceOnStuck", "\u5361\u4F4F", cfg.voiceOnStuck !== false]
8139
8452
  ].map(([key, label, on]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8140
8453
  "button",
@@ -8142,7 +8455,7 @@ function NotifyView(props) {
8142
8455
  type: "button",
8143
8456
  className: "dknt-miniswitch" + (on ? " on" : ""),
8144
8457
  style: { marginRight: 6 },
8145
- 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" : "",
8458
+ title: key === "voiceOnStuck" ? "\u7F16\u7A0B\u9636\u6BB5\u957F\u65F6\u95F4\u6CA1\u6709\u52A8\u9759\u65F6\u64AD\u62A5\u4E00\u6B21\uFF08\u6062\u590D\u540E\u53EF\u518D\u62A5\uFF1B\u547D\u4EE4\u5728\u8DD1 / \u6B63\u5728\u538B\u7F29\u4E0A\u4E0B\u6587\u4E0D\u7B97\uFF09" : "",
8146
8459
  onClick: () => patch({ [key]: !on }),
8147
8460
  children: [
8148
8461
  label,
@@ -8269,7 +8582,7 @@ function NotifyView(props) {
8269
8582
  ),
8270
8583
  /* @__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" })
8271
8584
  ] })
8272
- ] }) : /* @__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" })
8585
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u670D\u52A1\u7AEF\u603B\u5F00\u5173\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\uFF1B\u4E0A\u9762\u7684\u300C\u672C\u673A\u64AD\u62A5\u300D\u53EA\u51B3\u5B9A\u672C\u6D4F\u89C8\u5668\u662F\u5426\u51FA\u58F0\u3002" })
8273
8586
  ] }, "voice"),
8274
8587
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8275
8588
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
@@ -8393,7 +8706,7 @@ function NotifyView(props) {
8393
8706
  }
8394
8707
  if (saveErr) rows.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note dknt-err", children: saveErr }, "err"));
8395
8708
  rows.push(
8396
- /* @__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")
8709
+ /* @__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")
8397
8710
  );
8398
8711
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-root", children: rows });
8399
8712
  }
@@ -8402,8 +8715,10 @@ function NotifyStat(props) {
8402
8715
  const cfg = snap.status && snap.status.config;
8403
8716
  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" });
8404
8717
  if (!cfg) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "\u7B49\u5F85\u901A\u77E5\u914D\u7F6E\u2026" });
8405
- const events = [cfg.notifyOnComplete ? "\u5B8C\u6210" : "", cfg.notifyOnError ? "\u5F02\u5E38" : "", cfg.notifyOnConfirm !== false ? "\u9700\u786E\u8BA4" : ""].filter(Boolean);
8406
- 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" : "\xB7\u7B80") : ""].filter(Boolean);
8718
+ const events = [cfg.notifyOnComplete ? "\u5B8C\u6210" : "", cfg.notifyOnError ? "\u5F02\u5E38" : "", cfg.notifyOnConfirm !== false ? "\u9700\u786E\u8BA4/\u9700\u56DE\u7B54" : ""].filter(Boolean);
8719
+ const voiceMode = cfg.voiceMode === "detailed" ? "\xB7\u8BE6" : cfg.voiceMode === "medium" ? "\xB7\u9002" : "\xB7\u7B80";
8720
+ const voice = !cfg.voiceNotify ? "" : voiceClientEnabled() ? "\u8BED\u97F3\u64AD\u62A5" + voiceMode : "\u8BED\u97F3\u64AD\u62A5\xB7\u672C\u673A\u5DF2\u5173";
8721
+ const extras = [cfg.soundNotify !== false ? "\u63D0\u793A\u97F3" : "", cfg.systemNotify ? "\u7CFB\u7EDF\u901A\u77E5" : "", voice].filter(Boolean);
8407
8722
  const push = [cfg.dingtalkEnabled ? "\u9489\u9489" : "", cfg.feishuEnabled ? "\u98DE\u4E66" : ""].filter(Boolean);
8408
8723
  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("/") : "") });
8409
8724
  }
@@ -8572,16 +8887,20 @@ function useRunState() {
8572
8887
  return snap;
8573
8888
  }
8574
8889
  function waitingOf(active) {
8575
- return (active || []).reduce((n, t) => n + (Array.isArray(t.approvals) ? t.approvals.length : 0), 0);
8890
+ return waitingCountOf(active);
8576
8891
  }
8577
8892
  function TaskCard(props) {
8578
8893
  const t = props.t;
8579
8894
  const info = endInfo2(t.endReason);
8580
- const waiting = !props.done && Array.isArray(t.approvals) && t.approvals.length > 0;
8895
+ const waiting = !props.done && taskWaiting(t);
8896
+ const approvals = taskApprovals(t);
8897
+ const questions = taskQuestions(t);
8898
+ const waitLabel = approvals.length > 0 ? "\u7B49\u5F85\u786E\u8BA4" : questions.length > 0 ? "\u7B49\u5F85\u56DE\u7B54" : "";
8899
+ 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");
8581
8900
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-task", children: [
8582
8901
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-task-head", children: [
8583
8902
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-task-title", title: t.title, children: t.title || "(\u65E0\u6807\u9898)" }),
8584
- 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) })
8903
+ 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) })
8585
8904
  ] }),
8586
8905
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-task-meta", children: [
8587
8906
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: (t.models && t.models.length ? t.models.join(", ") : "\u672A\u77E5") + (t.provider ? "\uFF08" + t.provider + "\uFF09" : "") }),
@@ -8590,7 +8909,7 @@ function TaskCard(props) {
8590
8909
  t.totalTokens ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u21A7" + fmtCompact3(t.inputTokens) + " \u21A5" + fmtCompact3(t.outputTokens) }) : null,
8591
8910
  props.done && t.endTime ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: fmtTime3(t.endTime) }) : null
8592
8911
  ] }),
8593
- 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,
8912
+ waiting && waitDetail ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-task-wait", children: waitDetail }) : null,
8594
8913
  props.done && t.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-task-err", children: truncate3(t.errorMessage, 120) }) : null
8595
8914
  ] });
8596
8915
  }
@@ -8600,6 +8919,9 @@ function RunStateView() {
8600
8919
  const active = st && st.active ? st.active : [];
8601
8920
  const recent = st && st.recent ? st.recent.slice(0, 10) : [];
8602
8921
  const waitingCount = waitingOf(active);
8922
+ const waitApprovals = (active || []).reduce((n, t) => n + taskApprovals(t).length, 0);
8923
+ const waitQuestions = (active || []).reduce((n, t) => n + taskQuestions(t).length, 0);
8924
+ 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";
8603
8925
  (0, import_react11.useEffect)(() => {
8604
8926
  let stopped = false;
8605
8927
  let timer = null;
@@ -8615,7 +8937,7 @@ function RunStateView() {
8615
8937
  if (timer) clearTimeout(timer);
8616
8938
  };
8617
8939
  }, []);
8618
- 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";
8940
+ 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";
8619
8941
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dkrs-root", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-sec", children: [
8620
8942
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-sec-head", children: [
8621
8943
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dkrs-sec-title", children: "\u8FD0\u884C\u72B6\u6001" }),
@@ -8625,7 +8947,9 @@ function RunStateView() {
8625
8947
  waitingCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dkrs-waitbanner", children: [
8626
8948
  "\u270B ",
8627
8949
  waitingCount,
8628
- " \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"
8950
+ " \u9879\u7B49\u4F60\u4ECB\u5165\uFF1A",
8951
+ waitBannerHint,
8952
+ "\uFF0C\u8BF7\u5728\u4F1A\u8BDD\u91CC\u5904\u7406\u540E\u7EE7\u7EED\u3002"
8629
8953
  ] }) : null,
8630
8954
  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,
8631
8955
  !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,
@@ -8650,7 +8974,7 @@ function RunStateStat(props) {
8650
8974
  if (waiting > 0) return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "dkrs-warn", children: [
8651
8975
  "\u270B ",
8652
8976
  waiting,
8653
- " \u9879\u7B49\u5F85\u786E\u8BA4 \xB7 ",
8977
+ " \u9879\u7B49\u4F60\u4ECB\u5165 \xB7 ",
8654
8978
  active.length,
8655
8979
  " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D"
8656
8980
  ] });
@@ -8672,7 +8996,7 @@ var css4 = [
8672
8996
  ".dkrs-sec-sub{font-size:11px;color:var(--dsw-alias-label-tertiary);flex:1;min-width:120px;}",
8673
8997
  ".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;}",
8674
8998
  ".dkrs-refresh:hover{background:var(--dsw-alias-interactive-bg-hover);}",
8675
- // 等待确认横幅:琥珀描边,常驻在列表上方(任务卡各自也带「等待确认」标签)
8999
+ // 等人介入横幅:琥珀描边,常驻在列表上方(任务卡各自也带「等待确认」/「等待回答」标签)
8676
9000
  ".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;}",
8677
9001
  ".dkrs-done-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);}",
8678
9002
  // 任务列表
@@ -8695,7 +9019,7 @@ var feature9 = {
8695
9019
  name: "\u8FD0\u884C\u72B6\u6001",
8696
9020
  order: 150,
8697
9021
  accent: "#38bdf8",
8698
- 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",
9022
+ 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",
8699
9023
  css: css4,
8700
9024
  View: RunStateView,
8701
9025
  HomeStat: RunStateStat
@@ -13878,462 +14202,9 @@ var feature12 = {
13878
14202
  HomeStat: MobileRelayHomeStat
13879
14203
  };
13880
14204
 
13881
- // features/mobile/view.js
13882
- var import_react24 = __toESM(require("react"), 1);
13883
- var import_react25 = require("react");
13884
- var MOBILE_QUERY_NARROW = "(max-width: 820px)";
13885
- var MOBILE_QUERY_COARSE = "(pointer: coarse) and (hover: none)";
13886
- var MOBILE_QUERY_CHROME = "(max-width: 700px)";
13887
- function mobileActive() {
13888
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
13889
- try {
13890
- return window.matchMedia(MOBILE_QUERY_NARROW).matches || window.matchMedia(MOBILE_QUERY_COARSE).matches;
13891
- } catch {
13892
- return false;
13893
- }
13894
- }
13895
- function watchQuery(query, onChange) {
13896
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return () => {
13897
- };
13898
- let mq = null;
13899
- try {
13900
- mq = window.matchMedia(query);
13901
- } catch {
13902
- return () => {
13903
- };
13904
- }
13905
- const update = () => onChange(mq.matches);
13906
- update();
13907
- if (typeof mq.addEventListener === "function") mq.addEventListener("change", update);
13908
- else if (typeof mq.addListener === "function") mq.addListener(update);
13909
- return () => {
13910
- if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", update);
13911
- else if (typeof mq.removeListener === "function") mq.removeListener(update);
13912
- };
13913
- }
13914
- function MobileOverlay() {
13915
- const [active, setActive] = (0, import_react25.useState)(() => mobileActive());
13916
- (0, import_react25.useEffect)(() => {
13917
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
13918
- let mqs = [];
13919
- try {
13920
- mqs = [window.matchMedia(MOBILE_QUERY_NARROW), window.matchMedia(MOBILE_QUERY_COARSE)];
13921
- } catch {
13922
- return void 0;
13923
- }
13924
- const update = () => setActive(mqs.some((mq) => mq.matches));
13925
- update();
13926
- for (const mq of mqs) {
13927
- if (typeof mq.addEventListener === "function") mq.addEventListener("change", update);
13928
- else if (typeof mq.addListener === "function") mq.addListener(update);
13929
- }
13930
- return () => {
13931
- for (const mq of mqs) {
13932
- if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", update);
13933
- else if (typeof mq.removeListener === "function") mq.removeListener(update);
13934
- }
13935
- };
13936
- }, []);
13937
- (0, import_react25.useEffect)(() => {
13938
- if (typeof document === "undefined") return void 0;
13939
- if (active) {
13940
- document.body.setAttribute("data-dk-mobile", "1");
13941
- try {
13942
- const meta = document.querySelector('meta[name="viewport"]');
13943
- if (meta && !/(^|,)\s*viewport-fit\s*=/.test(meta.content || "")) {
13944
- meta.setAttribute("content", (meta.content || "width=device-width, initial-scale=1") + ", viewport-fit=cover");
13945
- }
13946
- } catch {
13947
- }
13948
- } else {
13949
- document.body.removeAttribute("data-dk-mobile");
13950
- }
13951
- return () => {
13952
- document.body.removeAttribute("data-dk-mobile");
13953
- };
13954
- }, [active]);
13955
- (0, import_react25.useEffect)(() => mobileChrome(), []);
13956
- return null;
13957
- }
13958
- function mobileChrome() {
13959
- if (typeof window === "undefined" || typeof document === "undefined") return void 0;
13960
- const mq = window.matchMedia ? window.matchMedia(MOBILE_QUERY_CHROME) : null;
13961
- if (!mq) return void 0;
13962
- if (window.__dshDockMobileDrawer === "host") return void 0;
13963
- window.__dshDockMobileDrawer = "client";
13964
- const narrow = () => mq.matches;
13965
- const frameEl = () => document.querySelector('[class$="frame"]');
13966
- const sidebarCollapsed = () => {
13967
- const f = frameEl();
13968
- return !!f && f.hasAttribute("data-sidebar-collapsed");
13969
- };
13970
- const dialogOpen = () => !!document.querySelector('[role="dialog"][class*="panel"]');
13971
- const rightOpen = () => !!document.querySelector("[data-sidebar-right-panel][data-sidebar-right-open]");
13972
- const collapse = () => {
13973
- const b = document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
13974
- if (b) b.click();
13975
- };
13976
- const expand = () => {
13977
- const b = document.querySelector('button[aria-label="\u6253\u5F00\u4FA7\u8FB9\u680F"],button[aria-label="Open sidebar"]');
13978
- if (b) b.click();
13979
- };
13980
- const closeDetails = () => {
13981
- const panel = document.querySelector("[data-sidebar-right-panel][data-sidebar-right-open]");
13982
- if (!panel) return;
13983
- const toggle = panel.querySelector("[data-sidebar-right-toggle]");
13984
- if (toggle) toggle.click();
13985
- };
13986
- const scrim = document.createElement("div");
13987
- scrim.className = "dsh-mobile-scrim";
13988
- document.body.appendChild(scrim);
13989
- document.querySelectorAll(".dsh-mobile-tabbar").forEach((el) => el.remove());
13990
- const burger = document.createElement("button");
13991
- burger.type = "button";
13992
- burger.className = "dsh-mobile-burger";
13993
- burger.setAttribute("aria-label", "\u6253\u5F00\u4F1A\u8BDD\u5217\u8868");
13994
- burger.setAttribute("aria-expanded", "false");
13995
- 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>';
13996
- burger.addEventListener("click", () => expand());
13997
- document.body.appendChild(burger);
13998
- const syncBurger = () => {
13999
- const expanded = !sidebarCollapsed();
14000
- burger.setAttribute("aria-expanded", expanded ? "true" : "false");
14001
- burger.classList.toggle("on", expanded);
14002
- };
14003
- const badge = burger.querySelector(".dsh-mobile-burger-badge");
14004
- let runstateGone = false;
14005
- const pollTasks = () => {
14006
- if (runstateGone || !badge || !narrow() || document.visibilityState === "hidden" || !burger.isConnected) return;
14007
- const on = stateOf("runstate").enabled !== false;
14008
- if (!on && !window.__dshDockRunstate) {
14009
- badge.hidden = true;
14010
- return;
14011
- }
14012
- fetch("dsh-dock/runstate/status", {
14013
- method: "POST",
14014
- headers: { "content-type": "application/json" },
14015
- body: "{}"
14016
- }).then(async (res) => {
14017
- if (res.status === 404 || res.status === 405) {
14018
- runstateGone = true;
14019
- badge.hidden = true;
14020
- return null;
14021
- }
14022
- const body = await res.json().catch(() => null);
14023
- if (!body) return null;
14024
- const active = body.data && body.data.active || [];
14025
- const waiting = active.reduce((n, t) => n + (Array.isArray(t.approvals) ? t.approvals.length : 0), 0);
14026
- if (waiting > 0) {
14027
- badge.textContent = waiting > 99 ? "99+" : String(waiting);
14028
- badge.className = "dsh-mobile-burger-badge wait";
14029
- badge.hidden = false;
14030
- burger.setAttribute("title", waiting + " \u4E2A\u4EFB\u52A1\u7B49\u5F85\u4F60\u786E\u8BA4");
14031
- } else if (active.length > 0) {
14032
- badge.textContent = active.length > 99 ? "99+" : String(active.length);
14033
- badge.className = "dsh-mobile-burger-badge";
14034
- badge.hidden = false;
14035
- burger.setAttribute("title", active.length + " \u4E2A\u4EFB\u52A1\u8FDB\u884C\u4E2D");
14036
- } else {
14037
- badge.hidden = true;
14038
- burger.removeAttribute("title");
14039
- }
14040
- }).catch(() => {
14041
- });
14042
- };
14043
- const tasksTimer = setInterval(pollTasks, 3e3);
14044
- const onVisible = () => {
14045
- if (document.visibilityState === "visible") pollTasks();
14046
- };
14047
- document.addEventListener("visibilitychange", onVisible);
14048
- pollTasks();
14049
- const vv = window.visualViewport || null;
14050
- const kbdSync = () => {
14051
- if (!vv) return;
14052
- const kbd = vv.height > 0 && window.innerHeight - vv.height > 120;
14053
- document.documentElement.classList.toggle("dsh-dock-kbd", kbd);
14054
- };
14055
- const sync = () => {
14056
- kbdSync();
14057
- document.querySelectorAll(".dsh-mobile-tabbar").forEach((el) => el.remove());
14058
- const on = narrow() && !!frameEl() && !dialogOpen();
14059
- const collapsed = sidebarCollapsed();
14060
- const right = rightOpen();
14061
- if (scrim) scrim.style.display = on && !collapsed ? "" : "none";
14062
- burger.style.display = narrow() && !!frameEl() && !panelNav.open && !right ? "" : "none";
14063
- syncBurger();
14064
- };
14065
- sync();
14066
- const observer = typeof MutationObserver !== "undefined" ? new MutationObserver(sync) : null;
14067
- if (observer) observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-sidebar-collapsed"], subtree: true });
14068
- const timer = setInterval(sync, 1500);
14069
- const onMq = () => sync();
14070
- if (mq.addEventListener) mq.addEventListener("change", onMq);
14071
- else if (mq.addListener) mq.addListener(onMq);
14072
- window.addEventListener("resize", kbdSync);
14073
- if (vv && vv.addEventListener) vv.addEventListener("resize", kbdSync);
14074
- const onClick = (e) => {
14075
- if (!narrow()) return;
14076
- const t = e.target;
14077
- if (!t || !t.closest) return;
14078
- if (t.closest(".dsh-mobile-burger")) return;
14079
- const expanded = !!document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
14080
- const col = document.querySelector('[class*="sidebarCol"]');
14081
- const inSidebar = col && col.contains(t);
14082
- if (!expanded && !inSidebar) return;
14083
- if (inSidebar) {
14084
- const row = t.closest('[role="treeitem"]');
14085
- const rowKey = row && row.getAttribute("data-row-key") || "";
14086
- const sessionRow = rowKey && rowKey.startsWith("session:") || row && !rowKey && !row.querySelector('[role="treeitem"]') && row.closest('[role="tree"]');
14087
- const fresh = t.closest('[class*="newSession"]');
14088
- if (sessionRow || fresh) {
14089
- setTimeout(() => {
14090
- collapse();
14091
- closeDetails();
14092
- }, 300);
14093
- return;
14094
- }
14095
- if (rowKey.startsWith("workspace:")) return;
14096
- setTimeout(() => {
14097
- if (document.querySelector('[role="dialog"]')) collapse();
14098
- }, 260);
14099
- return;
14100
- }
14101
- if (t.closest('[role="dialog"],[class*="dockm"],[class*="dgfab"],[class*="dgwin"],[class*="dgame"],[data-sidebar-right-panel]')) return;
14102
- collapse();
14103
- };
14104
- document.addEventListener("click", onClick, true);
14105
- return () => {
14106
- document.removeEventListener("click", onClick, true);
14107
- if (observer) observer.disconnect();
14108
- clearInterval(timer);
14109
- clearInterval(tasksTimer);
14110
- document.removeEventListener("visibilitychange", onVisible);
14111
- if (mq.removeEventListener) mq.removeEventListener("change", onMq);
14112
- else if (mq.removeListener) mq.removeListener(onMq);
14113
- window.removeEventListener("resize", kbdSync);
14114
- if (vv && vv.removeEventListener) vv.removeEventListener("resize", kbdSync);
14115
- document.documentElement.classList.remove("dsh-dock-kbd");
14116
- if (scrim) scrim.remove();
14117
- burger.remove();
14118
- if (window.__dshDockMobileDrawer === "client") delete window.__dshDockMobileDrawer;
14119
- };
14120
- }
14121
- function useViewportSize() {
14122
- const [size, setSize] = (0, import_react25.useState)(() => typeof window === "undefined" ? null : { w: window.innerWidth, h: window.innerHeight });
14123
- (0, import_react25.useEffect)(() => {
14124
- if (typeof window === "undefined") return void 0;
14125
- const update = () => setSize({ w: window.innerWidth, h: window.innerHeight });
14126
- window.addEventListener("resize", update);
14127
- return () => window.removeEventListener("resize", update);
14128
- }, []);
14129
- return size;
14130
- }
14131
- function useMobileState() {
14132
- const [active, setActive] = (0, import_react25.useState)(() => mobileActive());
14133
- const [chrome, setChrome] = (0, import_react25.useState)(() => typeof window === "undefined" || typeof window.matchMedia !== "function" ? false : window.matchMedia(MOBILE_QUERY_CHROME).matches);
14134
- const [owner, setOwner] = (0, import_react25.useState)(() => typeof window === "undefined" ? null : window.__dshDockMobileDrawer || null);
14135
- (0, import_react25.useEffect)(() => {
14136
- const offChrome = watchQuery(MOBILE_QUERY_CHROME, setChrome);
14137
- let mqs = [];
14138
- try {
14139
- mqs = [window.matchMedia(MOBILE_QUERY_NARROW), window.matchMedia(MOBILE_QUERY_COARSE)];
14140
- } catch {
14141
- mqs = [];
14142
- }
14143
- const compute = () => setActive(mqs.some((mq) => mq.matches));
14144
- for (const mq of mqs) {
14145
- if (typeof mq.addEventListener === "function") mq.addEventListener("change", compute);
14146
- else if (typeof mq.addListener === "function") mq.addListener(compute);
14147
- }
14148
- const timer = setInterval(() => setOwner(typeof window === "undefined" ? null : window.__dshDockMobileDrawer || null), 1e3);
14149
- return () => {
14150
- offChrome();
14151
- for (const mq of mqs) {
14152
- if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", compute);
14153
- else if (typeof mq.removeListener === "function") mq.removeListener(compute);
14154
- }
14155
- clearInterval(timer);
14156
- };
14157
- }, []);
14158
- return { active, chrome, owner };
14159
- }
14160
- function MobileView() {
14161
- const { active, chrome, owner } = useMobileState();
14162
- const size = useViewportSize();
14163
- return import_react24.default.createElement(
14164
- "div",
14165
- { className: "dkmob-root" },
14166
- import_react24.default.createElement(
14167
- "div",
14168
- { className: "dkmob-row" },
14169
- import_react24.default.createElement("span", { className: "dkmob-label" }, "\u624B\u673A\u6A21\u5F0F"),
14170
- import_react24.default.createElement("span", { className: "dkmob-state" + (active ? " on" : "") }, active ? "\u5DF2\u547D\u4E2D" : "\u672A\u547D\u4E2D"),
14171
- import_react24.default.createElement(
14172
- "span",
14173
- { className: "dkmob-dim" },
14174
- size ? size.w + "\xD7" + size.h + "px" : "",
14175
- "\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"
14176
- )
14177
- ),
14178
- import_react24.default.createElement(
14179
- "div",
14180
- { className: "dkmob-row" },
14181
- import_react24.default.createElement("span", { className: "dkmob-label" }, "\u624B\u673A\u7AEF chrome"),
14182
- import_react24.default.createElement("span", { className: "dkmob-state" + (chrome ? " on" : "") }, chrome ? "\u2264700px\uFF0C\u751F\u6548\u4E2D" : "\u672A\u547D\u4E2D"),
14183
- import_react24.default.createElement(
14184
- "span",
14185
- { className: "dkmob-dim" },
14186
- "\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",
14187
- 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" : ""
14188
- )
14189
- ),
14190
- import_react24.default.createElement(
14191
- "div",
14192
- { className: "dkmob-note" },
14193
- "\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 ",
14194
- "\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 ",
14195
- "\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",
14196
- "\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"
14197
- )
14198
- );
14199
- }
14200
- function MobileStat() {
14201
- const { active, chrome } = useMobileState();
14202
- 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");
14203
- 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"));
14204
- }
14205
- var css6 = [
14206
- // 输入类控件 16px:防 iOS 聚焦自动放大(<16px 的输入框聚焦时 Safari 强制缩放页面)
14207
- '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;}',
14208
- // 触控基础:去点按高亮、消双击缩放判定
14209
- 'body[data-dk-mobile="1"] :is(button, [role="button"]){-webkit-tap-highlight-color:transparent;touch-action:manipulation;}',
14210
- // 纯图标按钮面积兜底:实测窄屏下一批 28×28 的工具钮很难点中;36px 是不引起行高剧变的上限。
14211
- // 只收「唯一子元素是 svg」的按钮,避免撑坏带文字的行内控件;排除本模块 chrome 按钮。
14212
- 'body[data-dk-mobile="1"] button:has(> svg:only-child):not(.dsh-mobile-burger){min-width:36px;min-height:36px;}',
14213
- // 代码块横向滚动、行内代码换行:窄屏不撑破版面
14214
- 'body[data-dk-mobile="1"] pre{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;}',
14215
- 'body[data-dk-mobile="1"] code{overflow-wrap:anywhere;}',
14216
- 'body[data-dk-mobile="1"] pre code{overflow-wrap:normal;}',
14217
- // 滚动兜底:所有纵向滚动体可纵向平移 + iOS 惯性滚动(祖先合成层/触控声明不再吃掉触摸滚动)。
14218
- '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;}',
14219
- // iOS 横竖屏切换时的字号自动膨胀关掉(:has 挂到 html 上;dsh 自身样式已依赖 :has,基线足够)
14220
- 'html:has(body[data-dk-mobile="1"]){-webkit-text-size-adjust:100%;text-size-adjust:100%;}',
14221
- // 功能页自身
14222
- ".dkmob-root{display:flex;flex-direction:column;gap:10px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.6;}",
14223
- ".dkmob-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
14224
- ".dkmob-label{font-weight:600;flex:none;}",
14225
- ".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;}",
14226
- ".dkmob-state.on{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary);}",
14227
- ".dkmob-dim{color:var(--dsw-alias-label-secondary);font-size:12px;}",
14228
- ".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;}",
14229
- // 手机端 chrome:左上角汉堡菜单 + 抽屉遮罩(窄屏 ≤700px;与宿主半部同款)
14230
- "@media (max-width:700px){",
14231
- ".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}",
14232
- // 左上角汉堡菜单(三条横线):44×44 触控面积,避让刘海/圆角安全区;z 66 高于正文、
14233
- // 低于遮罩 75 / 抽屉 80——抽屉展开时被自然盖住。
14234
- // ⚠️ 视觉上刻意「不贴合卡片」:页面左上角本来就是空的,原生同类控件(右上的侧栏开关)
14235
- // 是**裸图标**——无底色、无边框、无阴影。早期版本做成白底圆角卡片 + 阴影 + 模糊,
14236
- // 悬浮在白底页面上像一块贴上去的异物(用户实测反馈「没有贴合边缘,很突兀」)。
14237
- // 现在与原生同款:透明底、无边框无阴影,只留图标;点按才给极轻的底色反馈。
14238
- // 视觉重量靠图标本身撑住(22px、1.9px 描边、主文字色),不靠容器。
14239
- ".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)}",
14240
- ".dsh-mobile-burger svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round}",
14241
- // 展开态:图标换成强调色(与原生「已激活」的语义一致),不引入额外容器。
14242
- ".dsh-mobile-burger.on{color:var(--dk-accent,#4d9fff)}",
14243
- // 点按反馈走图标本身(用 :active 的底色透出,范围就是 44×44 触控区)。
14244
- ".dsh-mobile-burger:active{background:color-mix(in srgb,currentColor 12%,transparent)}",
14245
- // 待确认任务角标:锚在按钮右上角的小圆点/数字。刻意做成「贴边小圆点」而不是
14246
- // 底部 Tab 栏那种带容器的页签角标——汉堡是裸图标,角标再带容器就又突兀了。
14247
- // 等待确认(要人介入)= 红点 + 脉冲;进行中 = 蓝色数字(弱一级,不抢注意力)。
14248
- ".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)}",
14249
- ".dsh-mobile-burger-badge[hidden]{display:none}",
14250
- ".dsh-mobile-burger-badge:not([hidden]){min-width:16px;height:16px;line-height:16px;padding:0 4px}",
14251
- ".dsh-mobile-burger-badge.wait{background:#ef4444;animation:dsh-burger-badge-pulse 1.2s ease-in-out infinite}",
14252
- "@keyframes dsh-burger-badge-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.18)}}",
14253
- "@media (prefers-reduced-motion:reduce){.dsh-mobile-burger-badge.wait{animation:none}}",
14254
- // ⚠️ 给标题让出汉堡宽度(用户实测:标题被汉堡压住——截图里「更新所有仓库代码」的首字
14255
- // 直接叠在三条横线上)。汉堡是 fixed 定位(贴安全区、44×44),**不占布局**,而原生标题
14256
- // 从头部的 padding-left:20px 起排——真实实例 390×844 逐字实测:会话标题首字 x=28、
14257
- // 汉堡右缘 44 → **重叠 16px**;插件页/自动化任务页的页头(自身 padding-left:0,靠外层
14258
- // 容器给 24px)首字 x=24 → 重叠 20px。
14259
- // 改法照原生排版习惯走:**给容器补内边距**,而不是给汉堡加底色/加宽(那是把问题搬到视觉上)。
14260
- // · 会话页头 header:has([class*="titleRow"])(唯一含 titleRow 的 header):左内边距
14261
- // 20px → 44px,正好等于汉堡宽度;标题自带 8px 内边距 → 首字落在 x=52,与汉堡留 8px。
14262
- // · 插件页/自动化任务页头 [class$="_pageHead"] / [class$="_pageHeading"]
14263
- // (DSH 0.2.0-rc.2 实测:plugin-manager 的 ZVcBiW_pageHead、schedule 的
14264
- // CxUija_pageHeading):左内边距 0 → 28px → 首字 x=52,同样留 8px。
14265
- // 这两条页头是 flex + gap:16px(标题块 | 工具栏),补内边距会压缩内容宽度——实测
14266
- // 430/390/360/320px 下「添加插件」按钮与描述文案会被挤到换行(按钮从单行变两行)。
14267
- // 故同时把 gap 收到 4px 补回 12px:四个宽度实测行数零回归、无横向溢出。
14268
- // 用 `[class$=…]`(语义后缀)而非 `[class*=…]`:DSH 类名是「哈希前缀 + 语义后缀」,
14269
- // 后缀稳定、前缀随版本变;`$=` 也避开 `pageHeadActions` 这类同前缀的无关元素。
14270
- // 挂 body[data-dk-mobile="1"]:本模块 css 字段会被无条件并入全局样式,停用本功能即摘掉
14271
- // body 属性 → 规则空转、原生排版还原(与文件头「开关协议」一致)。
14272
- 'body[data-dk-mobile="1"] header:has([class*="titleRow"]){padding-left:calc(44px + env(safe-area-inset-left,0px))}',
14273
- '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}',
14274
- // ⚠️ 「设置页滑不动」的关键兜底(客户端无条件携带 = 刷新即生效,不必等宿主重启):
14275
- // 窄屏把设置弹层改成纵向堆叠后,内容列若是默认 min-height:auto 就会被内容撑高
14276
- // (无头 390×844 实测列高 1216px 塞在 844px 视口里)、再被 .panel 的 overflow:hidden
14277
- // 裁掉——列内滚动容器([class*=options])因此 scrollHeight==clientHeight,手指怎么滑
14278
- // 都不动。补 min-height:0 后 scrollTop 0 → 425。宿主半部 MOBILE_LAYOUT_CSS 同款;
14279
- // 两处都写是因为宿主注入要重启 dsh web 才更新,而客户端样式刷新即生效,覆盖窗口期。
14280
- '[role="dialog"][class*="panel"]>[class*="content"]{min-height:0!important}',
14281
- // 输入区吸附到视口底部 + 滚动体留白(与宿主半部同款)。
14282
- // ⚠️ 底部留白只保留 iPhone home indicator 的安全区,不再额外留白。沿革:原 72px 是
14283
- // 「底部 Tab 栏高度 + 安全区」;Tab 栏移除后先收到 24px,但实测(真实实例 390×844
14284
- // 像素扫描)输入卡片下方仍有 **51px** 空白带,其中 24px 是这里的滚动体内边距、
14285
- // 6px 是下面 composerSeat 的内边距——两者都是 Tab 栏时代的遗留,在没有底栏的页面上
14286
- // 纯属浪费。收窄到「只有安全区」后卡片下沿更贴近视口底,这 30px 直接变成会话区
14287
- // 可显示的正文(滚动体内边距在 flex 容器里会把 composerSeat 连同消息区一起下移/增高)。
14288
- // dsh 自带的 ~21px 底部间距(卡片 margin)保留,视觉上仍有呼吸感,不会贴死屏幕边缘。
14289
- // ⚠️ 绝不能给滚动体加 justify-content:flex-end/center 贴底:内容会被挤到滚动体
14290
- // 起点之外,Chrome 不把起点方向溢出算进 scrollHeight(手机视口实测
14291
- // scrollHeight==clientHeight、maxScroll==0),会话记录彻底滚不动、首条消息永远看不到。
14292
- // 宿主半部旧版注入里还留着那条 flex-end(要重启 dsh web 才消失),这里用更高优先级
14293
- // 的选择器显式复位:刷新页面即修好,不必等重启。贴底只能用输入区自己的 margin-top:auto。
14294
- '[class*="scrollBody"][data-conversation-scroll]{justify-content:flex-start !important;padding-bottom:env(safe-area-inset-bottom,0px) !important}',
14295
- 'html:not(.dsh-dock-kbd) [class*="scrollBody"]{padding-bottom:env(safe-area-inset-bottom,0px) !important}',
14296
- 'html.dsh-dock-kbd [class*="scrollBody"]{padding-bottom:env(safe-area-inset-bottom,0px) !important}',
14297
- '[class*="scrollBody"]>[class*="composerSeat"]{margin-top:auto;padding-bottom:0}',
14298
- // 输入区工具行上的 dsh-dock chip(用量/余额):窄屏下 28cqw 的宽度上限把它们挤成
14299
- // 「…」「余..」(手机实测),既读不出数值又白占输入行空间。手机端整组收起,数值在
14300
- // 功能坞(抽屉里进)看;桌面端不动。
14301
- ".dockchip-row{display:none}",
14302
- '[class*="sidebarCol"]:has([class*="collapsed"]){visibility:hidden}',
14303
- // ⚠️ 列级 visibility:hidden 在 dsh 0.2.0 上挡不住:工作区浏览器给自己的
14304
- // headerActions/sectionLabel 显式声明 visibility:visible(展开/收拢动画用),visibility
14305
- // 可被后代覆盖,轨道按钮会从隐藏列里「透」出来(实测手机截图左缘游离按钮)。
14306
- // display:none 不可被后代翻转——但只能打在**轨道根节点**上(类名同时含 root 与
14307
- // collapsed 两个语义后缀),绝不能打在列上:frame 是「侧栏 0px + 中列 1fr + 右轨 0px」
14308
- // 的网格,列 display:none 会从网格流里摘掉,中列被自动放置顶进 0px 轨(实测整页空屏)。
14309
- // 弹层打开时豁免(设置弹层挂在列内部,display:none 会连坐成空气弹层),此时列退回
14310
- // visibility 机制(由下一条 [role=dialog] 强制可见),窄屏弹层全屏铺满盖住透出的轨道。
14311
- '[class*="sidebarCol"]:has([class*="collapsed"]):not(:has([role="dialog"])) [class*="root"][class*="collapsed"]{display:none !important}',
14312
- // 设置/插件管理弹层挂在侧栏列内部:上面隐藏整列会把它连坐隐藏(空气弹层)。
14313
- // visibility 可被后代覆盖,弹层关闭态整体卸载,所以只在真正打开时命中。
14314
- '[class*="sidebarCol"]:has([class*="collapsed"]) [role="dialog"]{visibility:visible}',
14315
- "html.dsh-dock-kbd .dsh-mobile-burger{display:none !important}",
14316
- // 功能坞面板在手机端抬到原生弹层之上:从抽屉进的官方插件管理页等原生弹层 z 序高于
14317
- // 面板默认的 200,功能坞开在下面会被盖住。抽屉展开时从侧栏 rail 点功能坞图标进入。
14318
- '[class*="dockm-backdrop"]{z-index:2000 !important}',
14319
- "}"
14320
- ].join("\n");
14321
- var feature13 = {
14322
- id: "mobile",
14323
- name: "\u624B\u673A\u9002\u914D",
14324
- order: 170,
14325
- accent: "#34d399",
14326
- 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",
14327
- defaultEnabled: true,
14328
- css: css6,
14329
- Overlay: MobileOverlay,
14330
- View: MobileView,
14331
- HomeStat: MobileStat
14332
- };
14333
-
14334
14205
  // src/client.jsx
14335
- var DOCK_VERSION = "0.18.0";
14336
- var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10, feature11, feature12, feature13];
14206
+ var DOCK_VERSION = "0.20.0";
14207
+ var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10, feature11, feature12];
14337
14208
  var PLANNED_FEATURES = [];
14338
14209
  var PLANNED_NOTES = {};
14339
14210
  var externalDefs = [];
@@ -14540,8 +14411,8 @@ function ensureCss() {
14540
14411
  }
14541
14412
  }
14542
14413
  function useExternalVersion() {
14543
- const [, bump] = import_react26.default.useReducer((n) => n + 1, 0);
14544
- import_react26.default.useEffect(() => {
14414
+ const [, bump] = import_react24.default.useReducer((n) => n + 1, 0);
14415
+ import_react24.default.useEffect(() => {
14545
14416
  externalListeners.add(bump);
14546
14417
  return () => {
14547
14418
  externalListeners.delete(bump);
@@ -14551,44 +14422,44 @@ function useExternalVersion() {
14551
14422
  var lastGeom = { x: null, y: null, w: null, h: null };
14552
14423
  function DockIcon(props) {
14553
14424
  const size = props && props.size || 16;
14554
- return import_react26.default.createElement(
14425
+ return import_react24.default.createElement(
14555
14426
  "svg",
14556
14427
  { width: size, height: size, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.3, "aria-hidden": true },
14557
- import_react26.default.createElement("rect", { x: 2.5, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
14558
- import_react26.default.createElement("rect", { x: 9, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
14559
- import_react26.default.createElement("rect", { x: 2.5, y: 9, width: 4.4, height: 4.4, rx: 1.2 }),
14560
- import_react26.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
14428
+ import_react24.default.createElement("rect", { x: 2.5, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
14429
+ import_react24.default.createElement("rect", { x: 9, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
14430
+ import_react24.default.createElement("rect", { x: 2.5, y: 9, width: 4.4, height: 4.4, rx: 1.2 }),
14431
+ import_react24.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
14561
14432
  );
14562
14433
  }
14563
14434
  function DockEntry(props) {
14564
14435
  const wide = !!props.wide;
14565
- const [open, setOpen] = import_react26.default.useState(panelNav.open);
14566
- import_react26.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
14567
- return import_react26.default.createElement("button", {
14436
+ const [open, setOpen] = import_react24.default.useState(panelNav.open);
14437
+ import_react24.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
14438
+ return import_react24.default.createElement("button", {
14568
14439
  type: "button",
14569
14440
  className: "docke2-btn" + (open ? " docke2-on" : "") + (wide ? "" : " docke2-rail"),
14570
14441
  title: "\u529F\u80FD\u575E",
14571
14442
  "aria-label": "\u529F\u80FD\u575E",
14572
14443
  "aria-expanded": open,
14573
14444
  onClick: () => setPanelOpen(!open)
14574
- }, import_react26.default.createElement(DockIcon, { size: wide ? 16 : 18 }), wide ? import_react26.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
14445
+ }, import_react24.default.createElement(DockIcon, { size: wide ? 16 : 18 }), wide ? import_react24.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
14575
14446
  }
14576
14447
  function DockModal() {
14577
- const [nav, setNav] = import_react26.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
14578
- import_react26.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
14448
+ const [nav, setNav] = import_react24.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
14449
+ import_react24.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
14579
14450
  const open = nav.open || typeof document === "undefined";
14580
14451
  const active = nav.active;
14581
14452
  const setActive = navigatePanel;
14582
14453
  const navParams = nav.params;
14583
- const [, force] = import_react26.default.useReducer((n) => n + 1, 0);
14454
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
14584
14455
  useExternalVersion();
14585
- const [win, setWin] = import_react26.default.useState(() => ({ mode: "normal", x: null, y: null, w: null, h: null }));
14586
- const dlgRef = import_react26.default.useRef(null);
14587
- const contentRef = import_react26.default.useRef(null);
14588
- import_react26.default.useEffect(() => {
14456
+ const [win, setWin] = import_react24.default.useState(() => ({ mode: "normal", x: null, y: null, w: null, h: null }));
14457
+ const dlgRef = import_react24.default.useRef(null);
14458
+ const contentRef = import_react24.default.useRef(null);
14459
+ import_react24.default.useEffect(() => {
14589
14460
  if (lastGeom.w) setWin({ mode: "normal", x: lastGeom.x, y: lastGeom.y, w: lastGeom.w, h: lastGeom.h });
14590
14461
  }, []);
14591
- import_react26.default.useEffect(() => {
14462
+ import_react24.default.useEffect(() => {
14592
14463
  if (open && contentRef.current) contentRef.current.scrollTop = 0;
14593
14464
  }, [active, open]);
14594
14465
  function beginDrag(e, type) {
@@ -14626,13 +14497,13 @@ function DockModal() {
14626
14497
  const mod = isHome ? null : MODULES.find((m) => m.id === active) || MODULES[0];
14627
14498
  const st = mod ? stateOf(mod.id) : null;
14628
14499
  const View = mod ? mod.View : null;
14629
- const viewNode = mod && View ? import_react26.default.createElement(
14500
+ const viewNode = mod && View ? import_react24.default.createElement(
14630
14501
  "div",
14631
14502
  { className: "dockm-view" },
14632
- import_react26.default.createElement(
14503
+ import_react24.default.createElement(
14633
14504
  FeatureBoundary,
14634
14505
  { key: mod.id, label: mod.name },
14635
- import_react26.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
14506
+ import_react24.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
14636
14507
  )
14637
14508
  ) : null;
14638
14509
  const enabledCount = MODULES.filter((m) => {
@@ -14646,10 +14517,10 @@ function DockModal() {
14646
14517
  width: win.w != null ? win.w : void 0,
14647
14518
  height: win.mode === "min" ? "auto" : win.h != null ? win.h : void 0
14648
14519
  } : null;
14649
- return import_react26.default.createElement(
14520
+ return import_react24.default.createElement(
14650
14521
  "div",
14651
14522
  { className: "dockm-backdrop", onClick: () => setPanelOpen(false) },
14652
- import_react26.default.createElement(
14523
+ import_react24.default.createElement(
14653
14524
  "div",
14654
14525
  {
14655
14526
  className: "dockm-dialog" + (win.mode === "max" ? " dockm-max" : "") + (win.mode === "min" ? " dockm-min" : ""),
@@ -14657,41 +14528,41 @@ function DockModal() {
14657
14528
  ref: dlgRef,
14658
14529
  onClick: (e) => e.stopPropagation()
14659
14530
  },
14660
- import_react26.default.createElement(
14531
+ import_react24.default.createElement(
14661
14532
  "div",
14662
14533
  {
14663
14534
  className: "dockm-head",
14664
14535
  onPointerDown: (e) => beginDrag(e, "move"),
14665
14536
  onDoubleClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
14666
14537
  },
14667
- import_react26.default.createElement(DockIcon, null),
14668
- import_react26.default.createElement("span", { className: "dockm-title" }, "\u529F\u80FD\u575E"),
14669
- import_react26.default.createElement("span", { className: "dockm-sub" }, "dsh-dock \xB7 \u4E5F\u53EF\u5728 \u8BBE\u7F6E \u2192 \u529F\u80FD\u575E \u6253\u5F00\u7BA1\u7406\u9875"),
14670
- import_react26.default.createElement(
14538
+ import_react24.default.createElement(DockIcon, null),
14539
+ import_react24.default.createElement("span", { className: "dockm-title" }, "\u529F\u80FD\u575E"),
14540
+ import_react24.default.createElement("span", { className: "dockm-sub" }, "dsh-dock \xB7 \u4E5F\u53EF\u5728 \u8BBE\u7F6E \u2192 \u529F\u80FD\u575E \u6253\u5F00\u7BA1\u7406\u9875"),
14541
+ import_react24.default.createElement(
14671
14542
  "span",
14672
14543
  { className: "dockm-ctrls" },
14673
- import_react26.default.createElement("button", {
14544
+ import_react24.default.createElement("button", {
14674
14545
  type: "button",
14675
14546
  className: "dockm-win",
14676
14547
  title: win.mode === "min" ? "\u8FD8\u539F" : "\u6700\u5C0F\u5316",
14677
14548
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "min" ? "normal" : "min" }))
14678
14549
  }, "\u2581"),
14679
- import_react26.default.createElement("button", {
14550
+ import_react24.default.createElement("button", {
14680
14551
  type: "button",
14681
14552
  className: "dockm-win",
14682
14553
  title: win.mode === "max" ? "\u8FD8\u539F" : "\u6700\u5927\u5316",
14683
14554
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
14684
14555
  }, win.mode === "max" ? "\u2750" : "\u25A2"),
14685
- import_react26.default.createElement("button", { type: "button", className: "dockm-close", "aria-label": "\u5173\u95ED", title: "\u5173\u95ED", onClick: () => setPanelOpen(false) }, "\u2715")
14556
+ import_react24.default.createElement("button", { type: "button", className: "dockm-close", "aria-label": "\u5173\u95ED", title: "\u5173\u95ED", onClick: () => setPanelOpen(false) }, "\u2715")
14686
14557
  )
14687
14558
  ),
14688
- import_react26.default.createElement(
14559
+ import_react24.default.createElement(
14689
14560
  "div",
14690
14561
  { className: "dockm-body" },
14691
- import_react26.default.createElement(
14562
+ import_react24.default.createElement(
14692
14563
  "nav",
14693
14564
  { className: "dockm-nav", "aria-label": "\u529F\u80FD\u6A21\u5757" },
14694
- import_react26.default.createElement(
14565
+ import_react24.default.createElement(
14695
14566
  "button",
14696
14567
  {
14697
14568
  type: "button",
@@ -14699,10 +14570,10 @@ function DockModal() {
14699
14570
  className: "dockm-nav-item" + (isHome ? " on" : ""),
14700
14571
  onClick: () => setActive("home")
14701
14572
  },
14702
- import_react26.default.createElement("span", { className: "dockm-navhome" }, import_react26.default.createElement(DockIcon, null)),
14703
- import_react26.default.createElement("span", null, "\u9996\u9875")
14573
+ import_react24.default.createElement("span", { className: "dockm-navhome" }, import_react24.default.createElement(DockIcon, null)),
14574
+ import_react24.default.createElement("span", null, "\u9996\u9875")
14704
14575
  ),
14705
- MODULES.map((m) => import_react26.default.createElement(
14576
+ MODULES.map((m) => import_react24.default.createElement(
14706
14577
  "button",
14707
14578
  {
14708
14579
  type: "button",
@@ -14710,42 +14581,42 @@ function DockModal() {
14710
14581
  className: "dockm-nav-item" + (m.id === active ? " on" : ""),
14711
14582
  onClick: () => setActive(m.id)
14712
14583
  },
14713
- import_react26.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
14714
- import_react26.default.createElement("span", null, m.name),
14715
- m.planned ? import_react26.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
14716
- m.external ? import_react26.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8") : null
14584
+ import_react24.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
14585
+ import_react24.default.createElement("span", null, m.name),
14586
+ m.planned ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
14587
+ m.external ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8") : null
14717
14588
  ))
14718
14589
  ),
14719
- import_react26.default.createElement(
14590
+ import_react24.default.createElement(
14720
14591
  "div",
14721
14592
  { className: "dockm-content", ref: contentRef },
14722
- import_react26.default.createElement(
14593
+ import_react24.default.createElement(
14723
14594
  "div",
14724
14595
  { className: "dockm-content-head" },
14725
- import_react26.default.createElement(
14596
+ import_react24.default.createElement(
14726
14597
  "div",
14727
14598
  { className: "dockm-name" },
14728
- isHome ? import_react26.default.createElement("span", { className: "dockm-navhome" }, import_react26.default.createElement(DockIcon, null)) : import_react26.default.createElement("span", { className: "dockm-dot", style: { background: mod.accent } }),
14599
+ isHome ? import_react24.default.createElement("span", { className: "dockm-navhome" }, import_react24.default.createElement(DockIcon, null)) : import_react24.default.createElement("span", { className: "dockm-dot", style: { background: mod.accent } }),
14729
14600
  isHome ? "\u9996\u9875" : mod.name,
14730
- !isHome && mod.planned ? import_react26.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
14731
- !isHome && mod.external ? import_react26.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8\u5305" + (mod.package ? " \xB7 " + mod.package : "")) : null
14601
+ !isHome && mod.planned ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
14602
+ !isHome && mod.external ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8\u5305" + (mod.package ? " \xB7 " + mod.package : "")) : null
14732
14603
  ),
14733
- import_react26.default.createElement(
14604
+ import_react24.default.createElement(
14734
14605
  "div",
14735
14606
  { className: "dockm-desc" },
14736
14607
  isHome ? "\u6240\u6709\u5B50\u529F\u80FD\u603B\u63FD\uFF1A\u8FD0\u884C\u72B6\u6001\u3001\u6982\u8981\u4E0E\u5FEB\u6377\u5F00\u5173\uFF0C\u70B9\u51FB\u5361\u7247\u8FDB\u5165\u5BF9\u5E94\u529F\u80FD\u9875\u3002" : mod.description
14737
14608
  )
14738
14609
  ),
14739
- isHome ? import_react26.default.createElement("div", { className: "dockm-view" }, import_react26.default.createElement(HomeView, { ctx: ctxRef.current, onOpen: setActive, onToggle: force })) : mod.planned ? import_react26.default.createElement("div", { className: "dockm-note" }, PLANNED_NOTES[mod.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st && st.enabled && viewNode ? viewNode : st && st.error ? import_react26.default.createElement("div", { className: "dockm-note dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : import_react26.default.createElement("div", { className: "dockm-note" }, "\u8BE5\u529F\u80FD\u5F53\u524D\u4E3A\u505C\u7528\u72B6\u6001\uFF08\u5F00\u5173\u5DF2\u6301\u4E45\u5316\uFF0C\u91CD\u542F\u540E\u4FDD\u6301\uFF09"),
14740
- import_react26.default.createElement(
14610
+ isHome ? import_react24.default.createElement("div", { className: "dockm-view" }, import_react24.default.createElement(HomeView, { ctx: ctxRef.current, onOpen: setActive, onToggle: force })) : mod.planned ? import_react24.default.createElement("div", { className: "dockm-note" }, PLANNED_NOTES[mod.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st && st.enabled && viewNode ? viewNode : st && st.error ? import_react24.default.createElement("div", { className: "dockm-note dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : import_react24.default.createElement("div", { className: "dockm-note" }, "\u8BE5\u529F\u80FD\u5F53\u524D\u4E3A\u505C\u7528\u72B6\u6001\uFF08\u5F00\u5173\u5DF2\u6301\u4E45\u5316\uFF0C\u91CD\u542F\u540E\u4FDD\u6301\uFF09"),
14611
+ import_react24.default.createElement(
14741
14612
  "div",
14742
14613
  { className: "dockm-foot" },
14743
- import_react26.default.createElement("span", null, isHome ? "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u5171 " + MODULES.length + " \u4E2A\u529F\u80FD\u6A21\u5757\uFF0C" + enabledCount + " \u4E2A\u5DF2\u542F\u7528" : "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u65B0\u529F\u80FD\u6309\u8DEF\u7EBF\u56FE\u8FFD\u52A0"),
14744
- !isHome && mod && !mod.planned && st ? import_react26.default.createElement(
14614
+ import_react24.default.createElement("span", null, isHome ? "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u5171 " + MODULES.length + " \u4E2A\u529F\u80FD\u6A21\u5757\uFF0C" + enabledCount + " \u4E2A\u5DF2\u542F\u7528" : "\u529F\u80FD\u575E v" + DOCK_VERSION + " \xB7 \u65B0\u529F\u80FD\u6309\u8DEF\u7EBF\u56FE\u8FFD\u52A0"),
14615
+ !isHome && mod && !mod.planned && st ? import_react24.default.createElement(
14745
14616
  "span",
14746
14617
  { className: "dockm-foot-sw" },
14747
- import_react26.default.createElement("span", { className: "dockm-foot-swlabel" + (st.enabled ? " on" : "") }, st.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
14748
- import_react26.default.createElement("button", {
14618
+ import_react24.default.createElement("span", { className: "dockm-foot-swlabel" + (st.enabled ? " on" : "") }, st.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
14619
+ import_react24.default.createElement("button", {
14749
14620
  type: "button",
14750
14621
  className: "dock-sw" + (st.enabled ? " on" : ""),
14751
14622
  role: "switch",
@@ -14758,11 +14629,11 @@ function DockModal() {
14758
14629
  }
14759
14630
  })
14760
14631
  ) : null,
14761
- !isHome && mod && typeof mod.Chip === "function" ? import_react26.default.createElement(
14632
+ !isHome && mod && typeof mod.Chip === "function" ? import_react24.default.createElement(
14762
14633
  "span",
14763
14634
  { className: "dockm-foot-sw" },
14764
- import_react26.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(mod.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
14765
- import_react26.default.createElement("button", {
14635
+ import_react24.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(mod.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
14636
+ import_react24.default.createElement("button", {
14766
14637
  type: "button",
14767
14638
  className: "dock-sw" + (chipShown(mod.id) ? " on" : ""),
14768
14639
  role: "switch",
@@ -14778,30 +14649,30 @@ function DockModal() {
14778
14649
  )
14779
14650
  )
14780
14651
  ),
14781
- win.mode === "normal" ? import_react26.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
14652
+ win.mode === "normal" ? import_react24.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
14782
14653
  )
14783
14654
  );
14784
14655
  }
14785
14656
  function HomeView(props) {
14786
14657
  const ctx = props && props.ctx;
14787
- const [, force] = import_react26.default.useReducer((n) => n + 1, 0);
14658
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
14788
14659
  useExternalVersion();
14789
14660
  const open = (id) => {
14790
14661
  if (props && typeof props.onOpen === "function") props.onOpen(id);
14791
14662
  };
14792
- return import_react26.default.createElement(
14663
+ return import_react24.default.createElement(
14793
14664
  "div",
14794
14665
  { className: "dockh-grid" },
14795
14666
  allModules().map((m) => {
14796
14667
  const st = stateOf(m.id);
14797
14668
  const enabled = !!(st && st.enabled);
14798
14669
  const Stat = m.HomeStat;
14799
- const statNode = m.planned ? import_react26.default.createElement("span", null, PLANNED_NOTES[m.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : enabled && Stat ? import_react26.default.createElement(
14670
+ const statNode = m.planned ? import_react24.default.createElement("span", null, PLANNED_NOTES[m.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : enabled && Stat ? import_react24.default.createElement(
14800
14671
  FeatureBoundary,
14801
14672
  { key: m.id, label: m.name },
14802
- import_react26.default.createElement(Stat, { ctx })
14803
- ) : import_react26.default.createElement("span", null, "\u5DF2\u505C\u7528\uFF0C\u542F\u7528\u540E\u5728\u6B64\u5C55\u793A\u8FD0\u884C\u6982\u8981");
14804
- return import_react26.default.createElement(
14673
+ import_react24.default.createElement(Stat, { ctx })
14674
+ ) : import_react24.default.createElement("span", null, "\u5DF2\u505C\u7528\uFF0C\u542F\u7528\u540E\u5728\u6B64\u5C55\u793A\u8FD0\u884C\u6982\u8981");
14675
+ return import_react24.default.createElement(
14805
14676
  "div",
14806
14677
  {
14807
14678
  key: m.id,
@@ -14816,21 +14687,21 @@ function HomeView(props) {
14816
14687
  }
14817
14688
  }
14818
14689
  },
14819
- import_react26.default.createElement(
14690
+ import_react24.default.createElement(
14820
14691
  "div",
14821
14692
  { className: "dockh-head" },
14822
- import_react26.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
14823
- import_react26.default.createElement("span", { className: "dockh-name" }, m.name),
14824
- m.external ? import_react26.default.createElement("span", { className: "dockh-badge", title: m.package || void 0 }, "\u5916\u90E8") : null,
14693
+ import_react24.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
14694
+ import_react24.default.createElement("span", { className: "dockh-name" }, m.name),
14695
+ m.external ? import_react24.default.createElement("span", { className: "dockh-badge", title: m.package || void 0 }, "\u5916\u90E8") : null,
14825
14696
  // 状态标识:圆点 + 文字(纯展示,与开关视觉区分)
14826
- import_react26.default.createElement(
14697
+ import_react24.default.createElement(
14827
14698
  "span",
14828
14699
  { className: "dockh-status" + (m.planned ? " plan" : enabled ? "" : " off") },
14829
- import_react26.default.createElement("span", { className: "dockh-sdot" }),
14830
- import_react26.default.createElement("span", null, m.planned ? "\u89C4\u5212\u4E2D" : enabled ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u505C\u7528")
14700
+ import_react24.default.createElement("span", { className: "dockh-sdot" }),
14701
+ import_react24.default.createElement("span", null, m.planned ? "\u89C4\u5212\u4E2D" : enabled ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u505C\u7528")
14831
14702
  ),
14832
14703
  // 启停开关(规划中的功能不显示)
14833
- m.planned ? null : import_react26.default.createElement("button", {
14704
+ m.planned ? null : import_react24.default.createElement("button", {
14834
14705
  type: "button",
14835
14706
  className: "dock-sw" + (enabled ? " on" : ""),
14836
14707
  role: "switch",
@@ -14845,12 +14716,12 @@ function HomeView(props) {
14845
14716
  }
14846
14717
  })
14847
14718
  ),
14848
- import_react26.default.createElement("div", { className: "dockh-desc" }, m.description),
14849
- import_react26.default.createElement("div", { className: "dockh-stat" }, statNode),
14850
- import_react26.default.createElement(
14719
+ import_react24.default.createElement("div", { className: "dockh-desc" }, m.description),
14720
+ import_react24.default.createElement("div", { className: "dockh-stat" }, statNode),
14721
+ import_react24.default.createElement(
14851
14722
  "div",
14852
14723
  { className: "dockh-foot" },
14853
- import_react26.default.createElement("span", { className: "dockh-go" }, "\u67E5\u770B\u8BE6\u60C5 \u2192")
14724
+ import_react24.default.createElement("span", { className: "dockh-go" }, "\u67E5\u770B\u8BE6\u60C5 \u2192")
14854
14725
  )
14855
14726
  );
14856
14727
  })
@@ -14858,16 +14729,16 @@ function HomeView(props) {
14858
14729
  }
14859
14730
  function DockPanel(props) {
14860
14731
  const ctx = ctxRef.current;
14861
- const [, force] = import_react26.default.useReducer((n) => n + 1, 0);
14732
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
14862
14733
  useExternalVersion();
14863
14734
  const toggle = (id) => {
14864
14735
  toggleFeature(id);
14865
14736
  force();
14866
14737
  };
14867
- return import_react26.default.createElement(
14738
+ return import_react24.default.createElement(
14868
14739
  "div",
14869
14740
  { className: "dock-root" },
14870
- import_react26.default.createElement(
14741
+ import_react24.default.createElement(
14871
14742
  "div",
14872
14743
  { className: "dock-intro" },
14873
14744
  "\u529F\u80FD\u575E\uFF08dsh-dock\uFF09\xB7 \u6240\u6709\u5C0F\u529F\u80FD\u96C6\u4E2D\u5728\u8FD9\u4E00\u4E2A\u9762\u677F\u91CC\u7BA1\u7406\u3002v0.4.0 \u8D77\u6BCF\u4E2A\u529F\u80FD\u662F\u72EC\u7ACB\u6A21\u5757\uFF08features/<id>/\uFF09\uFF0C",
@@ -14876,25 +14747,25 @@ function DockPanel(props) {
14876
14747
  allModules().map((f) => {
14877
14748
  const st = stateOf(f.id);
14878
14749
  const View = f.View;
14879
- const viewNode = !f.planned && st.enabled && View ? import_react26.default.createElement(
14750
+ const viewNode = !f.planned && st.enabled && View ? import_react24.default.createElement(
14880
14751
  "div",
14881
14752
  { className: "dock-body" },
14882
- import_react26.default.createElement(
14753
+ import_react24.default.createElement(
14883
14754
  FeatureBoundary,
14884
14755
  { key: f.id, label: f.name },
14885
- import_react26.default.createElement(View, { ctx, feature: f, params: props && props.params })
14756
+ import_react24.default.createElement(View, { ctx, feature: f, params: props && props.params })
14886
14757
  )
14887
14758
  ) : null;
14888
- return import_react26.default.createElement(
14759
+ return import_react24.default.createElement(
14889
14760
  "div",
14890
14761
  { className: "dock-card", key: f.id },
14891
- import_react26.default.createElement(
14762
+ import_react24.default.createElement(
14892
14763
  "div",
14893
14764
  { className: "dock-card-head" },
14894
- import_react26.default.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
14895
- import_react26.default.createElement("span", { className: "dock-name" }, f.name),
14896
- import_react26.default.createElement("span", { className: "dock-desc" }, f.description + (f.external ? "\uFF08\u6765\u81EA\u5916\u90E8\u5305" + (f.package ? " " + f.package : "") + "\uFF09" : "")),
14897
- f.planned ? import_react26.default.createElement("span", { className: "dock-badge" }, "\u89C4\u5212\u4E2D") : import_react26.default.createElement("button", {
14765
+ import_react24.default.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
14766
+ import_react24.default.createElement("span", { className: "dock-name" }, f.name),
14767
+ import_react24.default.createElement("span", { className: "dock-desc" }, f.description + (f.external ? "\uFF08\u6765\u81EA\u5916\u90E8\u5305" + (f.package ? " " + f.package : "") + "\uFF09" : "")),
14768
+ f.planned ? import_react24.default.createElement("span", { className: "dock-badge" }, "\u89C4\u5212\u4E2D") : import_react24.default.createElement("button", {
14898
14769
  type: "button",
14899
14770
  className: "dock-sw" + (st.enabled ? " on" : ""),
14900
14771
  role: "switch",
@@ -14903,11 +14774,11 @@ function DockPanel(props) {
14903
14774
  title: st.enabled ? "\u505C\u7528\u300C" + f.name + "\u300D" : "\u542F\u7528\u300C" + f.name + "\u300D",
14904
14775
  onClick: () => toggle(f.id)
14905
14776
  }),
14906
- !f.planned && typeof f.Chip === "function" ? import_react26.default.createElement(
14777
+ !f.planned && typeof f.Chip === "function" ? import_react24.default.createElement(
14907
14778
  "span",
14908
14779
  { className: "dockm-foot-sw" },
14909
- import_react26.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(f.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
14910
- import_react26.default.createElement("button", {
14780
+ import_react24.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(f.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
14781
+ import_react24.default.createElement("button", {
14911
14782
  type: "button",
14912
14783
  className: "dock-sw" + (chipShown(f.id) ? " on" : ""),
14913
14784
  role: "switch",
@@ -14921,22 +14792,22 @@ function DockPanel(props) {
14921
14792
  })
14922
14793
  ) : null
14923
14794
  ),
14924
- f.planned ? import_react26.default.createElement("div", { className: "dock-body" }, PLANNED_NOTES[f.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st.error ? import_react26.default.createElement("div", { className: "dock-body dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : null,
14795
+ f.planned ? import_react24.default.createElement("div", { className: "dock-body" }, PLANNED_NOTES[f.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st.error ? import_react24.default.createElement("div", { className: "dock-body dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : null,
14925
14796
  viewNode
14926
14797
  );
14927
14798
  })
14928
14799
  );
14929
14800
  }
14930
14801
  function DockChips(props) {
14931
- const [, force] = import_react26.default.useReducer((n) => n + 1, 0);
14932
- import_react26.default.useEffect(() => subscribeFeatureState(() => force()), []);
14802
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
14803
+ import_react24.default.useEffect(() => subscribeFeatureState(() => force()), []);
14933
14804
  const items = [];
14934
14805
  for (const f of allModules()) {
14935
14806
  if (f.planned || !stateOf(f.id).enabled || !chipShown(f.id) || typeof f.Chip !== "function") continue;
14936
- items.push(import_react26.default.createElement(
14807
+ items.push(import_react24.default.createElement(
14937
14808
  FeatureBoundary,
14938
14809
  { key: f.id, label: f.name },
14939
- import_react26.default.createElement(f.Chip, {
14810
+ import_react24.default.createElement(f.Chip, {
14940
14811
  ctx: props.ctx,
14941
14812
  feature: f,
14942
14813
  session: props.session,
@@ -14946,38 +14817,38 @@ function DockChips(props) {
14946
14817
  ));
14947
14818
  }
14948
14819
  if (items.length === 0) return null;
14949
- return import_react26.default.createElement("div", { className: "dockchip-row" }, items);
14820
+ return import_react24.default.createElement("div", { className: "dockchip-row" }, items);
14950
14821
  }
14951
14822
  function FeatureOverlays() {
14952
- const [, force] = import_react26.default.useReducer((n) => n + 1, 0);
14823
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
14953
14824
  useExternalVersion();
14954
- import_react26.default.useEffect(() => subscribeFeatureState(() => force()), []);
14825
+ import_react24.default.useEffect(() => subscribeFeatureState(() => force()), []);
14955
14826
  const items = [];
14956
14827
  for (const f of allModules()) {
14957
14828
  if (f.planned || !stateOf(f.id).enabled || typeof f.Overlay !== "function") continue;
14958
- items.push(import_react26.default.createElement(
14829
+ items.push(import_react24.default.createElement(
14959
14830
  FeatureBoundary,
14960
14831
  { key: f.id, label: f.name },
14961
- import_react26.default.createElement(f.Overlay, { ctx: ctxRef.current, feature: f })
14832
+ import_react24.default.createElement(f.Overlay, { ctx: ctxRef.current, feature: f })
14962
14833
  ));
14963
14834
  }
14964
14835
  if (items.length === 0) return null;
14965
- return import_react26.default.createElement(import_react26.default.Fragment, null, items);
14836
+ return import_react24.default.createElement(import_react24.default.Fragment, null, items);
14966
14837
  }
14967
14838
  function FeatureTurnTail(props) {
14968
- const [, force] = import_react26.default.useReducer((n) => n + 1, 0);
14969
- import_react26.default.useEffect(() => subscribeFeatureState(() => force()), []);
14839
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
14840
+ import_react24.default.useEffect(() => subscribeFeatureState(() => force()), []);
14970
14841
  const items = [];
14971
14842
  for (const f of allModules()) {
14972
14843
  if (f.planned || !stateOf(f.id).enabled || typeof f.TurnTail !== "function") continue;
14973
- items.push(import_react26.default.createElement(
14844
+ items.push(import_react24.default.createElement(
14974
14845
  FeatureBoundary,
14975
14846
  { key: f.id, label: f.name },
14976
- import_react26.default.createElement(f.TurnTail, Object.assign({}, props, { ctx: ctxRef.current, feature: f }))
14847
+ import_react24.default.createElement(f.TurnTail, Object.assign({}, props, { ctx: ctxRef.current, feature: f }))
14977
14848
  ));
14978
14849
  }
14979
14850
  if (items.length === 0) return null;
14980
- return import_react26.default.createElement(import_react26.default.Fragment, null, items);
14851
+ return import_react24.default.createElement(import_react24.default.Fragment, null, items);
14981
14852
  }
14982
14853
  var ctxRef = { current: null };
14983
14854
  function apply(ctx) {
@@ -14988,27 +14859,27 @@ function apply(ctx) {
14988
14859
  if (slots === void 0) return;
14989
14860
  slots.inject("sidebar.footer.action", () => slots.register(
14990
14861
  { name: "sidebar.footer.action", id: "dsh-dock", order: 1, label: "\u529F\u80FD\u575E" },
14991
- (props) => import_react26.default.createElement(DockEntry, props)
14862
+ (props) => import_react24.default.createElement(DockEntry, props)
14992
14863
  ));
14993
14864
  slots.inject("shell.overlay", () => slots.register(
14994
14865
  { name: "shell.overlay", id: "dsh-dock-panel", order: 21, label: "\u529F\u80FD\u575E\u9762\u677F" },
14995
- () => import_react26.default.createElement(DockModal, null)
14866
+ () => import_react24.default.createElement(DockModal, null)
14996
14867
  ));
14997
14868
  slots.inject("shell.overlay", () => slots.register(
14998
14869
  { name: "shell.overlay", id: "dsh-dock-feature-overlays", order: 22, label: "\u529F\u80FD\u575E\u5168\u5C40\u6D6E\u5C42" },
14999
- () => import_react26.default.createElement(FeatureOverlays, null)
14870
+ () => import_react24.default.createElement(FeatureOverlays, null)
15000
14871
  ));
15001
14872
  slots.inject("settings.section", () => slots.register(
15002
14873
  { name: "settings.section", id: "dsh-dock", order: 90, label: "\u529F\u80FD\u575E" },
15003
- (props) => import_react26.default.createElement(DockPanel, props)
14874
+ (props) => import_react24.default.createElement(DockPanel, props)
15004
14875
  ));
15005
14876
  slots.inject("conversation.input.left", () => slots.register(
15006
14877
  { name: "conversation.input.left", id: "dsh-dock-chips", order: 10, label: "\u529F\u80FD\u575E" },
15007
- (zone) => import_react26.default.createElement(DockChips, Object.assign({}, zone, { ctx: ctxRef.current }))
14878
+ (zone) => import_react24.default.createElement(DockChips, Object.assign({}, zone, { ctx: ctxRef.current }))
15008
14879
  ));
15009
14880
  slots.inject("conversation.chat.turnTail", () => slots.register(
15010
14881
  { name: "conversation.chat.turnTail", id: "dsh-dock-turn-tail", order: 40, label: "\u529F\u80FD\u575E" },
15011
- (owner) => import_react26.default.createElement(FeatureTurnTail, owner)
14882
+ (owner) => import_react24.default.createElement(FeatureTurnTail, owner)
15012
14883
  ));
15013
14884
  }
15014
14885
  var inject = ["timer"];