dsh-dock 0.17.0 → 0.19.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();
@@ -7275,6 +7275,216 @@ function previewSound(effect) {
7275
7275
  const delayed = lib.notes.err.map(([f, at, dur, wave]) => [f, at + 0.55, dur, wave]);
7276
7276
  playTone(delayed);
7277
7277
  }
7278
+ function synthOf() {
7279
+ try {
7280
+ const g = typeof globalThis !== "undefined" ? globalThis : null;
7281
+ if (g && g.speechSynthesis) return g.speechSynthesis;
7282
+ if (typeof window !== "undefined" && window.speechSynthesis) return window.speechSynthesis;
7283
+ } catch {
7284
+ }
7285
+ return null;
7286
+ }
7287
+ function utterCtor() {
7288
+ try {
7289
+ const g = typeof globalThis !== "undefined" && globalThis.SpeechSynthesisUtterance ? globalThis.SpeechSynthesisUtterance : typeof window !== "undefined" ? window.SpeechSynthesisUtterance : null;
7290
+ return g;
7291
+ } catch {
7292
+ return null;
7293
+ }
7294
+ }
7295
+ function voiceSupported() {
7296
+ return synthOf() !== null && utterCtor() !== null;
7297
+ }
7298
+ function localVoices() {
7299
+ const s = synthOf();
7300
+ if (!s) return [];
7301
+ try {
7302
+ return (typeof s.getVoices === "function" ? s.getVoices() : []) || [];
7303
+ } catch {
7304
+ return [];
7305
+ }
7306
+ }
7307
+ function pickVoice(cfg, text) {
7308
+ const voices = localVoices();
7309
+ if (voices.length === 0) return null;
7310
+ const want = String(cfg && cfg.voiceURI || "");
7311
+ if (want) {
7312
+ const hit = voices.find((v) => v && v.voiceURI === want);
7313
+ if (hit) return hit;
7314
+ }
7315
+ const lang = String(cfg && cfg.voiceLang || "");
7316
+ if (lang) {
7317
+ const base = lang.split("-")[0].toLowerCase();
7318
+ return voices.find((v) => String(v.lang || "").toLowerCase() === lang.toLowerCase()) || voices.find((v) => String(v.lang || "").toLowerCase().startsWith(base)) || null;
7319
+ }
7320
+ if (!text || /[\u4E00-\u9FFF]/.test(text)) {
7321
+ const zh = voices.find((v) => /^zh/i.test(String(v.lang || "")));
7322
+ if (zh) return zh;
7323
+ }
7324
+ return null;
7325
+ }
7326
+ function useLocalVoices() {
7327
+ const [, force] = (0, import_react10.useState)(0);
7328
+ const ref = (0, import_react10.useRef)(null);
7329
+ if (ref.current === null) ref.current = localVoices();
7330
+ (0, import_react10.useEffect)(() => {
7331
+ const s = synthOf();
7332
+ const onChange = () => {
7333
+ ref.current = localVoices();
7334
+ force((n) => n + 1);
7335
+ };
7336
+ if (s && typeof s.addEventListener === "function") {
7337
+ try {
7338
+ s.addEventListener("voiceschanged", onChange);
7339
+ } catch {
7340
+ }
7341
+ }
7342
+ if (ref.current.length === 0) onChange();
7343
+ return () => {
7344
+ if (s && typeof s.removeEventListener === "function") {
7345
+ try {
7346
+ s.removeEventListener("voiceschanged", onChange);
7347
+ } catch {
7348
+ }
7349
+ }
7350
+ };
7351
+ }, []);
7352
+ return ref.current;
7353
+ }
7354
+ var voiceEpoch = 0;
7355
+ function speakVoice(text, cfg) {
7356
+ const t = String(text || "").trim();
7357
+ if (!t) return false;
7358
+ const s = synthOf();
7359
+ const Ctor = utterCtor();
7360
+ if (!s || !Ctor) return false;
7361
+ const c = cfg || {};
7362
+ let utt = null;
7363
+ try {
7364
+ utt = new Ctor(t);
7365
+ } catch {
7366
+ return false;
7367
+ }
7368
+ if (!utt) return false;
7369
+ utt.rate = typeof c.voiceRate === "number" ? Math.min(2, Math.max(0.5, c.voiceRate)) : 1;
7370
+ utt.volume = typeof c.voiceVolume === "number" ? Math.min(1, Math.max(0, c.voiceVolume)) : 1;
7371
+ let lang = String(c.voiceLang || "");
7372
+ if (!lang && /[\u4E00-\u9FFF]/.test(t)) lang = "zh-CN";
7373
+ if (lang) utt.lang = lang;
7374
+ const voice = pickVoice(c, t);
7375
+ if (voice) {
7376
+ utt.voice = voice;
7377
+ if (voice.lang) utt.lang = voice.lang;
7378
+ }
7379
+ const epoch = ++voiceEpoch;
7380
+ try {
7381
+ s.cancel();
7382
+ } catch {
7383
+ }
7384
+ const delay = () => {
7385
+ if (epoch !== voiceEpoch) return;
7386
+ try {
7387
+ s.speak(utt);
7388
+ } catch {
7389
+ }
7390
+ };
7391
+ let waited = 0;
7392
+ const poll = () => {
7393
+ if (epoch !== voiceEpoch) return;
7394
+ let busy = false;
7395
+ try {
7396
+ busy = s.speaking === true || s.pending === true;
7397
+ } catch {
7398
+ busy = false;
7399
+ }
7400
+ if (!busy || waited >= 800) {
7401
+ delay();
7402
+ return;
7403
+ }
7404
+ waited += 20;
7405
+ setTimeout(poll, 20);
7406
+ };
7407
+ poll();
7408
+ return true;
7409
+ }
7410
+ function voiceTone(cfg) {
7411
+ const m = cfg && cfg.voiceMode;
7412
+ return m === "detailed" || m === "medium" ? m : "brief";
7413
+ }
7414
+ function cardTone(cfg) {
7415
+ const m = cfg && cfg.cardMode;
7416
+ return m === "brief" || m === "medium" ? m : "detailed";
7417
+ }
7418
+ function endReasonSpeech(reason) {
7419
+ if (reason === "error") return "\u51FA\u9519\u4E86";
7420
+ if (reason === "aborted") return "\u5DF2\u505C\u6B62";
7421
+ if (reason === "blocked") return "\u53D7\u963B\u505C\u6B62\u4E86";
7422
+ if (reason === "max-tokens") return "\u8FBE\u5230\u8F93\u51FA\u4E0A\u9650\u505C\u6B62\u4E86";
7423
+ if (reason === "interrupted") return "\u88AB\u6253\u65AD\u4E86";
7424
+ return "\u5B8C\u6210\u4E86";
7425
+ }
7426
+ function endBroadcastText(success, record, task, cfg) {
7427
+ const mode = voiceTone(cfg);
7428
+ const reason = record && record.endReason || "";
7429
+ const title = record && record.title || task && task.title || "";
7430
+ if (mode === "brief") {
7431
+ return success ? "\u4EFB\u52A1\u5B8C\u6210" : "\u4EFB\u52A1\u505C\u6B62\u4E86";
7432
+ }
7433
+ if (mode === "medium") {
7434
+ const who = title ? "\u4EFB\u52A1\u300C" + truncate2(title, 30) + "\u300D" : "\u4EFB\u52A1";
7435
+ const parts2 = [success ? who + "\u5B8C\u6210\u4E86" : who + "\u505C\u6B62\u4E86"];
7436
+ if (!success) parts2.push("\uFF0C\u539F\u56E0\uFF1A" + endReasonSpeech(reason));
7437
+ const dur2 = record && record.duration || 0;
7438
+ if (dur2 > 0) parts2.push("\uFF0C\u8017\u65F6" + fmtDur(dur2));
7439
+ parts2.push("\u3002");
7440
+ return parts2.join("");
7441
+ }
7442
+ const parts = [];
7443
+ if (title) parts.push("\u4EFB\u52A1\uFF1A" + truncate2(title, 30) + "\u3002");
7444
+ parts.push(success ? "\u5DF2\u5B8C\u6210\u3002" : "\u7ED3\u675F\uFF0C\u539F\u56E0\uFF1A" + endReasonSpeech(reason) + "\u3002");
7445
+ const dur = record && record.duration || 0;
7446
+ if (dur > 0) parts.push("\u8017\u65F6" + fmtDur(dur) + "\u3002");
7447
+ const turns = record && record.turns || task && task.turns || 0;
7448
+ const steps = record && record.steps || task && task.steps || 0;
7449
+ const tools = record && record.toolCalls || task && task.toolCalls || 0;
7450
+ if (turns || steps) parts.push("\u5171" + turns + "\u56DE\u5408" + steps + "\u6B65" + (tools ? "\u3001\u5DE5\u5177" + tools + "\u6B21" : "") + "\u3002");
7451
+ if (!success && record && record.errorMessage) parts.push("\u9519\u8BEF\uFF1A" + truncate2(String(record.errorMessage).replace(/[`*_#>\[\]()]/g, " "), 50) + "\u3002");
7452
+ if (success && record && record.lastText) {
7453
+ const plain = truncate2(String(record.lastText).replace(/[#*_`>\[\]()!]/g, "").replace(/\s+/g, " "), 40);
7454
+ if (plain) parts.push("\u56DE\u590D\u6458\u8981\uFF1A" + plain);
7455
+ }
7456
+ return parts.join("");
7457
+ }
7458
+ function confirmBroadcastText(task, approval, cfg) {
7459
+ const mode = voiceTone(cfg);
7460
+ if (mode === "brief") return "\u4EFB\u52A1\u9700\u8981\u6388\u6743";
7461
+ const tool = approval && approval.toolName || "\u5DE5\u5177";
7462
+ const scene = toolLabel(tool);
7463
+ if (mode === "medium") {
7464
+ const who = task && task.title ? "\u4EFB\u52A1\u300C" + truncate2(task.title, 30) + "\u300D" : "\u4EFB\u52A1";
7465
+ return who + "\u9700\u8981\u6388\u6743\uFF0C\u6B63\u5728\u7B49\u4F60\u6279\u51C6" + (scene || "\u5DE5\u5177 " + tool) + "\u3002";
7466
+ }
7467
+ const parts = [];
7468
+ if (task && task.title) parts.push("\u4EFB\u52A1\uFF1A" + truncate2(task.title, 30) + "\u3002");
7469
+ parts.push("\u6B63\u5728\u7B49\u5F85\u4F60\u6279\u51C6" + (scene ? "\u6267\u884C" + scene : "") + "\uFF0C\u5DE5\u5177\u662F" + tool + "\uFF0C\u8BF7\u56DE\u5230\u4F1A\u8BDD\u5904\u7406\u3002");
7470
+ return parts.join("");
7471
+ }
7472
+ function stuckBroadcastText(task, cfg) {
7473
+ const mode = voiceTone(cfg);
7474
+ const where = (task && task.isSubtask ? "\u5B50\u4EFB\u52A1" : "\u4E3B\u4EFB\u52A1") + (task && task.title ? "\u300C" + truncate2(task.title, 30) + "\u300D" : "");
7475
+ if (mode === "brief") return where + "\u5361\u4F4F\u4E86";
7476
+ if (mode === "medium") {
7477
+ return where + "\u5361\u4F4F\u4E86\uFF0C\u5DF2\u7ECF" + fmtDur(Math.max(0, cfg && cfg.stuckMs || STUCK_MS)) + "\u6CA1\u6709\u4EFB\u4F55\u52A8\u9759\u3002";
7478
+ }
7479
+ const parts = [where + "\u5361\u4F4F\u4E86\u3002"];
7480
+ parts.push("\u7F16\u7A0B\u9636\u6BB5\u5DF2\u7ECF" + fmtDur(Math.max(0, cfg && cfg.stuckMs || STUCK_MS)) + "\u6CA1\u6709\u4EFB\u4F55\u52A8\u9759\uFF0C");
7481
+ const tool = task && task.lastToolName || "";
7482
+ const scene = tool ? toolLabel(tool) : "";
7483
+ parts.push(tool ? "\u6700\u540E\u5728\u6267\u884C" + tool + (scene ? "\uFF08" + scene + "\uFF09" : "") + "\uFF0C" : "");
7484
+ parts.push("\u8BF7\u67E5\u770B\u3002");
7485
+ return parts.join("");
7486
+ }
7487
+ var STUCK_MS = 18e3;
7278
7488
  var notifyStore = {
7279
7489
  snap: { status: null, loading: false, error: null },
7280
7490
  listeners: /* @__PURE__ */ new Set(),
@@ -7314,27 +7524,56 @@ function useNotify() {
7314
7524
  function pageVisible() {
7315
7525
  return typeof document === "undefined" || document.visibilityState === "visible";
7316
7526
  }
7317
- function currentSelectedSessionTitle() {
7318
- if (typeof document === "undefined" || typeof window === "undefined") return "";
7319
- if (typeof document.querySelectorAll !== "function") return "";
7527
+ function currentSelectedSession() {
7528
+ if (typeof document === "undefined" || typeof window === "undefined") return { id: "", title: "" };
7529
+ if (typeof document.querySelectorAll !== "function") return { id: "", title: "" };
7530
+ let byTitle = null;
7320
7531
  for (const el of document.querySelectorAll('[role="treeitem"][aria-selected="true"]')) {
7321
- const r = el.getBoundingClientRect();
7322
- if (r.width > 0 && r.height > 0 && r.right <= window.innerWidth * 0.35) {
7323
- const text = (el.textContent || "").trim();
7324
- if (text) return text;
7532
+ const k = typeof el.getAttribute === "function" ? el.getAttribute("data-row-key") : null;
7533
+ if (typeof k === "string" && k.indexOf("session:") === 0) {
7534
+ return { id: k.slice(8), title: (el.textContent || "").trim() };
7535
+ }
7536
+ if (!byTitle) {
7537
+ const r = typeof el.getBoundingClientRect === "function" ? el.getBoundingClientRect() : null;
7538
+ if (r && r.width > 0 && r.height > 0 && r.right <= window.innerWidth * 0.35) {
7539
+ const text = (el.textContent || "").trim();
7540
+ if (text) byTitle = text;
7541
+ }
7325
7542
  }
7326
7543
  }
7327
- return "";
7544
+ return { id: "", title: byTitle || "" };
7328
7545
  }
7329
7546
  function titleMatches(a, b) {
7330
7547
  return !!a && !!b && (a === b || a.indexOf(b) !== -1 || b.indexOf(a) !== -1);
7331
7548
  }
7549
+ var overlayCtx = null;
7550
+ function openSessionById(sessionId) {
7551
+ if (!sessionId || !overlayCtx) return false;
7552
+ let uiw = null;
7553
+ try {
7554
+ uiw = typeof overlayCtx.get === "function" ? overlayCtx.get("uiWorkspace") : overlayCtx.uiWorkspace;
7555
+ } catch {
7556
+ return false;
7557
+ }
7558
+ if (!uiw || typeof uiw.openSession !== "function") return false;
7559
+ try {
7560
+ uiw.openSession(sessionId);
7561
+ return true;
7562
+ } catch {
7563
+ return false;
7564
+ }
7565
+ }
7332
7566
  function openSessionByTitle(title) {
7333
7567
  if (typeof document === "undefined" || typeof window === "undefined") return false;
7334
7568
  if (typeof document.querySelectorAll !== "function" || !title) return false;
7335
7569
  for (const el of document.querySelectorAll('[role="treeitem"]')) {
7336
- const r = typeof el.getBoundingClientRect === "function" ? el.getBoundingClientRect() : null;
7337
- if (!r || r.width <= 0 || r.height <= 0 || r.right > window.innerWidth * 0.35) continue;
7570
+ const k = typeof el.getAttribute === "function" ? el.getAttribute("data-row-key") : null;
7571
+ const isSessionRow = typeof k === "string" ? k.indexOf("session:") === 0 : true;
7572
+ if (!isSessionRow) continue;
7573
+ if (typeof k !== "string") {
7574
+ const r = typeof el.getBoundingClientRect === "function" ? el.getBoundingClientRect() : null;
7575
+ if (!r || r.width <= 0 || r.height <= 0 || r.right > window.innerWidth * 0.35) continue;
7576
+ }
7338
7577
  if (!titleMatches((el.textContent || "").trim(), title)) continue;
7339
7578
  const link = typeof el.querySelector === "function" ? el.querySelector("a,button") : null;
7340
7579
  const target = link || el;
@@ -7353,9 +7592,10 @@ function Toast(props) {
7353
7592
  setClosing(true);
7354
7593
  }, []);
7355
7594
  const jump = (0, import_react10.useCallback)(() => {
7356
- if (!t.sessionTitle) return;
7357
- if (openSessionByTitle(t.sessionTitle) && t.kind !== "confirm") setClosing(true);
7358
- }, [t.sessionTitle, t.kind]);
7595
+ if (!t.sessionTitle && !t.sessionId) return;
7596
+ const ok = openSessionById(t.sessionId) || (t.fallbackSessionId ? openSessionById(t.fallbackSessionId) : false) || (t.sessionTitle ? openSessionByTitle(t.sessionTitle) : false);
7597
+ if (ok && t.kind !== "confirm" && t.kind !== "stuck") setClosing(true);
7598
+ }, [t.sessionId, t.sessionTitle, t.fallbackSessionId, t.kind]);
7359
7599
  (0, import_react10.useEffect)(() => {
7360
7600
  if (t.closing && !closing) setClosing(true);
7361
7601
  }, [t.closing, closing]);
@@ -7368,13 +7608,13 @@ function Toast(props) {
7368
7608
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
7369
7609
  "div",
7370
7610
  {
7371
- className: "dknt-toast" + (t.kind === "confirm" ? " dknt-toast-confirm" : "") + (t.sessionTitle ? " clickable" : "") + (props.collapsed ? " collapsed" : "") + (closing ? " out" : ""),
7372
- onClick: t.sessionTitle ? jump : void 0,
7611
+ className: "dknt-toast" + (t.kind === "confirm" ? " dknt-toast-confirm" : "") + (t.sessionTitle || t.sessionId ? " clickable" : "") + (props.collapsed ? " collapsed" : "") + (closing ? " out" : ""),
7612
+ onClick: t.sessionTitle || t.sessionId ? jump : void 0,
7373
7613
  children: [
7374
7614
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-toast-head", children: [
7375
7615
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-toast-mark", style: { background: markColor } }),
7376
7616
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-toast-title", title: t.sessionTitle || t.title, children: [
7377
- t.kind === "confirm" ? "\u270B " : "",
7617
+ t.kind === "confirm" ? "\u270B " : t.kind === "stuck" ? "\u23F3 " : "",
7378
7618
  props.collapsed ? t.sessionTitle || t.title : t.title,
7379
7619
  !props.collapsed && t.sessionTitle && t.kind !== "confirm" ? " \xB7 " + t.sessionTitle : ""
7380
7620
  ] }),
@@ -7398,6 +7638,7 @@ function Toast(props) {
7398
7638
  );
7399
7639
  }
7400
7640
  function NotifyOverlay(props) {
7641
+ if (props && props.ctx) overlayCtx = props.ctx;
7401
7642
  const snap = useNotify();
7402
7643
  const [toasts, setToasts] = (0, import_react10.useState)([]);
7403
7644
  const [stackHover, setStackHover] = (0, import_react10.useState)(false);
@@ -7405,8 +7646,15 @@ function NotifyOverlay(props) {
7405
7646
  const remindedApprovalsRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
7406
7647
  const toastSeqRef = (0, import_react10.useRef)(0);
7407
7648
  const pushToast = (0, import_react10.useCallback)((toast) => {
7649
+ const st = notifyStore.snap.status;
7650
+ const cfg = st && st.config;
7651
+ if (cfg && cfg.notifyCards === false) return;
7408
7652
  setToasts((prev) => prev.concat([toast]).slice(-12));
7409
7653
  }, []);
7654
+ (0, import_react10.useEffect)(() => {
7655
+ const cfg = snap.status && snap.status.config;
7656
+ if (cfg && cfg.notifyCards === false) setToasts((prev) => prev.length ? [] : prev);
7657
+ }, [snap.status]);
7410
7658
  (0, import_react10.useEffect)(() => {
7411
7659
  let stopped = false;
7412
7660
  let timer = null;
@@ -7460,21 +7708,30 @@ function NotifyOverlay(props) {
7460
7708
  const fresh = approvals.filter((a) => a && !seen.has(a.id));
7461
7709
  if (fresh.length === 0) continue;
7462
7710
  for (const a of fresh) seen.add(a.id);
7711
+ if (cfg.voiceNotify === true && cfg.voiceOnConfirm !== false) {
7712
+ speakVoice(confirmBroadcastText(task, fresh[0], cfg), cfg);
7713
+ }
7463
7714
  if (cfg.notifyOnConfirm === false) continue;
7464
7715
  const toolName = fresh[0].toolName || "";
7465
7716
  const scene = toolLabel(toolName);
7717
+ const tone = cardTone(cfg);
7466
7718
  const lines = [
7467
7719
  "\u4EFB\u52A1\uFF1A" + (task.title || "(\u65E0\u6807\u9898)"),
7468
7720
  "\u5DE5\u5177\uFF1A" + (toolName || "\u672A\u77E5") + (scene ? "\uFF08" + scene + "\uFF09" : "")
7469
7721
  ];
7470
- if (fresh[0].reason) lines.push("\u8BF4\u660E\uFF1A" + truncate2(fresh[0].reason, 140));
7471
- 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");
7722
+ if (tone !== "brief" && fresh[0].reason) lines.push("\u8BF4\u660E\uFF1A" + truncate2(fresh[0].reason, 140));
7723
+ if (fresh.length > 1) {
7724
+ lines.push(tone === "brief" ? "\u5171 " + fresh.length + " \u9879\u7B49\u5F85\u786E\u8BA4" : "\u5171 " + fresh.length + " \u9879\u7B49\u5F85\u4F60\u7684\u786E\u8BA4");
7725
+ } else if (tone === "detailed") {
7726
+ lines.push("\u8BF7\u5728\u4F1A\u8BDD\u91CC\u786E\u8BA4\u540E\u7EE7\u7EED");
7727
+ }
7472
7728
  pushToast({
7473
7729
  id: ++toastSeqRef.current,
7474
7730
  kind: "confirm",
7475
7731
  title: "\u4EFB\u52A1\u9700\u8981\u786E\u8BA4",
7476
7732
  body: lines.join("\n"),
7477
7733
  // 点卡片直达该会话去处理审批(需确认卡跳转后不收起——审批没处理完它就该在)
7734
+ sessionId: task.sessionId || "",
7478
7735
  sessionTitle: task.title || "",
7479
7736
  // 卡片与这批审批项绑定:approval/decided 后宿主把它们移出 approvals,
7480
7737
  // 下面的对账 effect 据此自动收起卡片(处理完就不该再占着右上角)。
@@ -7515,13 +7772,15 @@ function NotifyOverlay(props) {
7515
7772
  (0, import_react10.useEffect)(() => {
7516
7773
  const timer = setInterval(() => {
7517
7774
  if (!pageVisible()) return;
7518
- const current = currentSelectedSessionTitle();
7519
- if (!current) return;
7775
+ const cur = currentSelectedSession();
7776
+ if (!cur.id && !cur.title) return;
7520
7777
  setToasts((prev) => {
7521
7778
  let changed = false;
7522
7779
  const next = prev.map((x) => {
7523
- if (x.kind === "confirm" || x.closing || !x.sessionTitle) return x;
7524
- if (!titleMatches(x.sessionTitle, current)) return x;
7780
+ if (x.kind === "confirm" || x.kind === "stuck" || x.closing) return x;
7781
+ if (!x.sessionTitle && !x.sessionId) return x;
7782
+ const hit = cur.id && x.sessionId && cur.id === x.sessionId || !cur.id && x.sessionTitle && titleMatches(x.sessionTitle, cur.title);
7783
+ if (!hit) return x;
7525
7784
  changed = true;
7526
7785
  return Object.assign({}, x, { closing: true });
7527
7786
  });
@@ -7530,33 +7789,115 @@ function NotifyOverlay(props) {
7530
7789
  }, 500);
7531
7790
  return () => clearInterval(timer);
7532
7791
  }, []);
7792
+ const stuckSeenRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
7793
+ (0, import_react10.useEffect)(() => {
7794
+ const st = snap.status;
7795
+ if (!st || !st.active) return;
7796
+ const cfg = st.config || {};
7797
+ const now = st.now || Date.now();
7798
+ const activeIds = new Set(st.active.map((x) => x.sessionId));
7799
+ for (const sid of Array.from(stuckSeenRef.current.keys())) {
7800
+ if (!activeIds.has(sid)) stuckSeenRef.current.delete(sid);
7801
+ }
7802
+ const parentsWaitingOnSubtask = /* @__PURE__ */ new Set();
7803
+ for (const t of st.active) {
7804
+ if (t.isSubtask && t.parentSessionId) parentsWaitingOnSubtask.add(t.parentSessionId);
7805
+ }
7806
+ for (const task of st.active) {
7807
+ const approvals = Array.isArray(task.approvals) ? task.approvals : [];
7808
+ if (approvals.length > 0) {
7809
+ stuckSeenRef.current.delete(task.sessionId);
7810
+ continue;
7811
+ }
7812
+ if (task.phase !== "code") {
7813
+ continue;
7814
+ }
7815
+ if (parentsWaitingOnSubtask.has(task.sessionId)) continue;
7816
+ const lastAct = task.lastActivityAt || task.phaseAt || 0;
7817
+ if (!lastAct || now - lastAct < STUCK_MS) continue;
7818
+ const prev = stuckSeenRef.current.get(task.sessionId);
7819
+ if (prev === lastAct) continue;
7820
+ stuckSeenRef.current.set(task.sessionId, lastAct);
7821
+ const stuckMs = now - lastAct;
7822
+ if (cfg.voiceNotify === true && cfg.voiceOnStuck !== false) {
7823
+ speakVoice(stuckBroadcastText(task, Object.assign({}, cfg, { stuckMs })), cfg);
7824
+ }
7825
+ if (cfg.notifyOnStuck === false) continue;
7826
+ const label = task.isSubtask ? "\u5B50\u4EFB\u52A1" : "\u4E3B\u4EFB\u52A1";
7827
+ const title = task.title || "(\u65E0\u6807\u9898)";
7828
+ const tool = task.lastToolName || "";
7829
+ const tone = cardTone(cfg);
7830
+ const lines = ["\u4EFB\u52A1\uFF1A" + label + "\xB7" + title];
7831
+ if (tone !== "brief") lines.push("\u5DF2\u505C\u6EDE\uFF1A" + fmtDur(stuckMs) + "\uFF08\u7F16\u7A0B\u9636\u6BB5\u65E0\u6D3B\u52A8\uFF09");
7832
+ if (tone === "detailed") {
7833
+ if (tool) lines.push("\u6700\u540E\u52A8\u4F5C\uFF1A" + tool + (toolLabel(tool) ? "\uFF08" + toolLabel(tool) + "\uFF09" : ""));
7834
+ 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");
7835
+ }
7836
+ pushToast({
7837
+ id: ++toastSeqRef.current,
7838
+ kind: "stuck",
7839
+ title: label + "\u5361\u4F4F\u4E86",
7840
+ body: lines.join("\n"),
7841
+ sessionId: task.sessionId || "",
7842
+ sessionTitle: title,
7843
+ // 子任务会话通常不在侧栏里:跳不到自己时回退到父会话(看主会话里的子代理进度)
7844
+ fallbackSessionId: task.isSubtask && task.parentSessionId ? task.parentSessionId : "",
7845
+ // 停点指纹:恢复活动(lastActivityAt 变了)即由下面的对账 effect 收起
7846
+ stuckAt: lastAct
7847
+ });
7848
+ }
7849
+ }, [snap.status]);
7850
+ (0, import_react10.useEffect)(() => {
7851
+ const st = snap.status;
7852
+ if (!st || !st.active) return;
7853
+ const byId = new Map(st.active.map((x) => [x.sessionId, x]));
7854
+ setToasts((prev) => {
7855
+ let changed = false;
7856
+ const next = prev.map((x) => {
7857
+ if (x.kind !== "stuck" || x.closing) return x;
7858
+ const task = byId.get(x.sessionId);
7859
+ const stillStalled = !!task && (task.lastActivityAt || task.phaseAt || 0) === x.stuckAt && (Array.isArray(task.approvals) ? task.approvals.length : 0) === 0;
7860
+ if (stillStalled) return x;
7861
+ changed = true;
7862
+ return Object.assign({}, x, { closing: true });
7863
+ });
7864
+ return changed ? next : prev;
7865
+ });
7866
+ }, [snap.status]);
7533
7867
  const handleTaskEnd = (task, record, cfg) => {
7534
7868
  const reason = record && record.endReason || "";
7535
7869
  const success = isSuccessReason2(reason);
7536
7870
  const info = endInfo(reason);
7537
7871
  const wanted = success ? cfg.notifyOnComplete : cfg.notifyOnError;
7872
+ if (cfg.voiceNotify === true && (success ? cfg.voiceOnComplete !== false : cfg.voiceOnError !== false)) {
7873
+ speakVoice(endBroadcastText(success, record, task, cfg), cfg);
7874
+ }
7538
7875
  if (wanted === false) return;
7539
7876
  const models = record && record.models && record.models.length ? record.models.join(", ") : task.models && task.models.length ? task.models.join(", ") : "\u672A\u77E5\u6A21\u578B";
7540
7877
  const provider = record && record.provider || task.provider || "";
7541
7878
  const startTs = record && record.startTime || task.startTime;
7542
7879
  const endTs = record && record.endTime || Date.now();
7543
- const lines = [
7544
- "\u4EFB\u52A1\uFF1A" + (record && record.title || task.title || "(\u65E0\u6807\u9898)"),
7545
- "\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""),
7546
- "\u8017\u65F6\uFF1A" + fmtDur(record && record.duration || endTs - startTs) + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09",
7547
- "\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" : ""),
7548
- "Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens)
7549
- ];
7550
- if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate2(record.lastText, 140));
7551
- if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate2(record.errorMessage, 120));
7880
+ const tone = cardTone(cfg);
7881
+ const durText = fmtDur(record && record.duration || endTs - startTs);
7882
+ const lines = ["\u4EFB\u52A1\uFF1A" + (record && record.title || task.title || "(\u65E0\u6807\u9898)")];
7883
+ if (tone !== "brief") lines.push("\u6A21\u578B\uFF1A" + models + (provider ? "\uFF08" + provider + "\uFF09" : ""));
7884
+ lines.push(tone === "brief" ? "\u8017\u65F6\uFF1A" + durText : "\u8017\u65F6\uFF1A" + durText + "\uFF08" + fmtTime2(startTs) + " \u2192 " + fmtTime2(endTs) + "\uFF09");
7885
+ if (tone === "detailed") {
7886
+ lines.push("\u56DE\u5408 " + (record && record.turns || task.turns || 0) + " \xB7 \u6B65\u9AA4 " + (record && record.steps || task.steps || 0) + (record && record.toolCalls || task.toolCalls ? " \xB7 \u5DE5\u5177 " + (record && record.toolCalls || task.toolCalls) + " \u6B21" : ""));
7887
+ lines.push("Token\uFF1A\u8F93\u5165 " + fmtNum2(record && record.inputTokens || task.inputTokens) + " / \u8F93\u51FA " + fmtNum2(record && record.outputTokens || task.outputTokens));
7888
+ if (record && record.lastText) lines.push("\u6458\u8981\uFF1A" + truncate2(record.lastText, 140));
7889
+ if (!success && record && record.errorMessage) lines.push("\u9519\u8BEF\uFF1A" + truncate2(record.errorMessage, 120));
7890
+ }
7552
7891
  const title = success ? "\u4EFB\u52A1\u5B8C\u6210" : "\u4EFB\u52A1" + info.label;
7553
7892
  pushToast({
7554
7893
  id: ++toastSeqRef.current,
7555
7894
  kind: success ? "success" : info.cls === "err" ? "error" : "warn",
7556
7895
  title,
7557
7896
  body: lines.join("\n"),
7558
- // 绑定会话标题:点卡片直达该会话;用户点进这个会话(侧栏选中)也视为
7897
+ // 绑定会话:点卡片直达该会话;用户点进这个会话(侧栏选中)也视为
7559
7898
  // 看到了结果,巡检 effect 据此自动收起卡片。没看过就一直挂着。
7899
+ // sessionId 是权威标识(跳转/对账都用它),标题只作旧宿主回退。
7900
+ sessionId: task.sessionId || "",
7560
7901
  sessionTitle: record && record.title || task.title || ""
7561
7902
  });
7562
7903
  if (cfg.soundNotify !== false) playDoneSound(success, cfg.soundEffect);
@@ -7593,6 +7934,7 @@ function NotifyOverlay(props) {
7593
7934
  }
7594
7935
  function NotifyView(props) {
7595
7936
  const snap = useNotify();
7937
+ const voices = useLocalVoices();
7596
7938
  const [cfg, setCfg] = (0, import_react10.useState)(null);
7597
7939
  const [saveErr, setSaveErr] = (0, import_react10.useState)("");
7598
7940
  const [testing, setTesting] = (0, import_react10.useState)(false);
@@ -7718,6 +8060,19 @@ function NotifyView(props) {
7718
8060
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u54EA\u4E9B\u65F6\u523B\u63D0\u9192\u4F60\uFF1B\u4E0E\u3010\u4EFB\u52A1\u52A8\u753B\u3011\u7684\u52A8\u6548\u4E92\u4E0D\u4F9D\u8D56" })
7719
8061
  ] }),
7720
8062
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8063
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8064
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u9875\u5185\u5361\u7247" }),
8065
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8066
+ "button",
8067
+ {
8068
+ type: "button",
8069
+ className: "dknt-miniswitch" + (cfg.notifyCards !== false ? " on" : ""),
8070
+ onClick: () => patch({ notifyCards: cfg.notifyCards === false }),
8071
+ children: cfg.notifyCards !== false ? "\u5F00" : "\u5173"
8072
+ }
8073
+ ),
8074
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u53F3\u4FA7\u901A\u77E5\u5361\u7247\u603B\u5F00\u5173\uFF1A\u5173\u95ED\u540E\u4E0B\u9762\u5404\u7C7B\u5361\u7247\uFF08\u5B8C\u6210 / \u5F02\u5E38 / \u9700\u786E\u8BA4 / \u5361\u4F4F\uFF09\u4E00\u5F8B\u4E0D\u5F39\uFF0C\u5DF2\u6302\u7740\u7684\u4E00\u5E76\u6536\u8D77\uFF1B\u8BED\u97F3\u64AD\u62A5\u3001\u63D0\u793A\u97F3\u3001\u7CFB\u7EDF\u901A\u77E5\u3001\u9489\u9489\u98DE\u4E66\u63A8\u9001\u4E0D\u53D7\u5F71\u54CD" })
8075
+ ] }),
7721
8076
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
7722
8077
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5B8C\u6210\u901A\u77E5" }),
7723
8078
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -7756,6 +8111,19 @@ function NotifyView(props) {
7756
8111
  }
7757
8112
  ),
7758
8113
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u5DE5\u5177\u7B49\u5F85\u4F60\u6279\u51C6\u65F6\u5F39\u5361\u7247\u5E76\u54CD\u786E\u8BA4\u97F3\uFF1B\u5BA1\u6279\u5904\u7406\u5B8C\u81EA\u52A8\u6536\u8D77\uFF0C\u6CA1\u5904\u7406\u5B8C\u5C31\u4E00\u76F4\u663E\u793A\uFF08\u70B9\u5361\u7247\u76F4\u8FBE\u4F1A\u8BDD\uFF09" })
8114
+ ] }),
8115
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8116
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u4F4F\u63D0\u9192" }),
8117
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8118
+ "button",
8119
+ {
8120
+ type: "button",
8121
+ className: "dknt-miniswitch" + (cfg.notifyOnStuck !== false ? " on" : ""),
8122
+ onClick: () => patch({ notifyOnStuck: cfg.notifyOnStuck === false }),
8123
+ children: cfg.notifyOnStuck !== false ? "\u5F00" : "\u5173"
8124
+ }
8125
+ ),
8126
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7F16\u7A0B\u9636\u6BB5 18 \u79D2\u6CA1\u6709\u52A8\u9759\u65F6\u5F39\u5361\u7247\uFF0C\u5199\u660E\u662F\u4E3B\u4EFB\u52A1\u8FD8\u662F\u5B50\u4EFB\u52A1\u3001\u505C\u6EDE\u4E86\u591A\u4E45\u3001\u6700\u540E\u5728\u6267\u884C\u4EC0\u4E48\uFF1B\u6062\u590D\u6D3B\u52A8 / \u4EFB\u52A1\u7ED3\u675F\u81EA\u52A8\u6536\u8D77\uFF0C\u540C\u4E00\u505C\u70B9\u53EA\u5F39\u4E00\u6B21\uFF08\u8BED\u97F3\u64AD\u62A5\u8D70\u300C\u8BED\u97F3\u64AD\u62A5\u300D\u533A\u7684\u5361\u4F4F\u5F00\u5173\uFF0C\u4E92\u4E0D\u5E72\u6270\uFF09" })
7759
8127
  ] })
7760
8128
  ] })
7761
8129
  ] }, "events"),
@@ -7765,9 +8133,25 @@ function NotifyView(props) {
7765
8133
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u9875\u5185\u5361\u7247\u3001\u63D0\u793A\u97F3\u3001\u6D4F\u89C8\u5668\u7CFB\u7EDF\u901A\u77E5\u53EF\u81EA\u7531\u7EC4\u5408" })
7766
8134
  ] }),
7767
8135
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8136
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8137
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u7247\u53E3\u5F84" }),
8138
+ [["brief", "\u7B80\u6D01"], ["medium", "\u9002\u4E2D"], ["detailed", "\u8BE6\u7EC6"]].map(([v, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8139
+ "button",
8140
+ {
8141
+ type: "button",
8142
+ className: "dknt-miniswitch" + (cardTone(cfg) === v ? " on" : ""),
8143
+ style: { marginRight: 6 },
8144
+ title: "\u53F3\u4FA7\u901A\u77E5\u5361\u7247\u6B63\u6587\u6309" + label + "\u6863\u663E\u793A",
8145
+ onClick: () => patch({ cardMode: v }),
8146
+ children: label
8147
+ },
8148
+ v
8149
+ )),
8150
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u53F3\u4FA7\u5361\u7247\u6B63\u6587\u5199\u591A\u5C11\uFF08\u4E0E\u5404\u7C7B\u578B\u5F00\u5173\u3001\u8BED\u97F3\u64AD\u62A5\u4E92\u4E0D\u5F71\u54CD\uFF09\uFF1A\u7B80\u6D01\uFF1D\u4EFB\u52A1\u4E0E\u8017\u65F6 / \u8C01\u5361\u4F4F\uFF1B\u9002\u4E2D\uFF1D\u52A0\u6A21\u578B\u3001\u8D77\u6B62\u65F6\u95F4\u3001\u505C\u6EDE\u65F6\u957F\uFF1B\u8BE6\u7EC6\uFF1D\u5168\u90E8\uFF08\u56DE\u5408\u6B65\u9AA4\u3001Token\u3001\u6458\u8981\u6216\u9519\u8BEF\u3001\u6700\u540E\u52A8\u4F5C\uFF09" })
8151
+ ] }),
7768
8152
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
7769
8153
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u5361\u7247\u6536\u7EB3" }),
7770
- /* @__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" })
8154
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u6240\u6709\u5361\u7247\u90FD\u4E0D\u8D85\u65F6\u81EA\u52A8\u6D88\u5931\uFF1A\u7ED3\u675F\u5361\u7247\u6CA1\u770B\u8FC7\u5C31\u4E00\u76F4\u6302\u7740\uFF08\u540E\u53F0\u8DD1\u5B8C\u7684\u5207\u56DE\u6765\u4E5F\u5728\uFF09\uFF0C\u70B9\u5361\u7247\u76F4\u8FBE\u5BF9\u5E94\u4F1A\u8BDD\uFF0C\u6216\u70B9\u8FDB\u8BE5\u4F1A\u8BDD\uFF0C\u5361\u7247\u81EA\u52A8\u6536\u8D77\uFF1B\u9700\u786E\u8BA4\u5361\u7247\u6302\u5230\u5BA1\u6279\u5904\u7406\u5B8C\uFF1B\u5361\u4F4F\u5361\u7247\u6302\u5230\u6062\u590D\u6D3B\u52A8\u30023 \u5F20\u53CA\u4EE5\u4E0A\u81EA\u52A8\u53E0\u653E\u6210\u6807\u9898\u6761\uFF0C\u9F20\u6807\u79FB\u4E0A\u53BB\u6574\u4F53\u5C55\u5F00\uFF1B\u8981\u6574\u4F53\u4E0D\u5F39\u770B\u4E0A\u9762\u300C\u9875\u5185\u5361\u7247\u300D\u603B\u5F00\u5173" })
7771
8155
  ] }),
7772
8156
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
7773
8157
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u7CFB\u7EDF\u901A\u77E5" }),
@@ -7833,6 +8217,185 @@ function NotifyView(props) {
7833
8217
  )) }) : null
7834
8218
  ] })
7835
8219
  ] }, "style"),
8220
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
8221
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
8222
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u8BED\u97F3\u64AD\u62A5" }),
8223
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-sub", children: "\u4EFB\u52A1\u5B8C\u6210 / \u505C\u6B62 / \u9700\u8981\u6388\u6743 / \u5361\u4F4F\u65F6\u7528\u6D4F\u89C8\u5668\u8BED\u97F3\uFF08TTS\uFF09\u8BF4\u4E00\u53E5\u8BDD\uFF1B\u4E0E\u63D0\u793A\u97F3\u3001\u7CFB\u7EDF\u901A\u77E5\u4E92\u4E0D\u51B2\u7A81" }),
8224
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-sec-sw", children: [
8225
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-swlabel" + (cfg.voiceNotify ? " on" : ""), children: cfg.voiceNotify ? "\u5DF2\u5F00\u542F" : "\u5DF2\u5173\u95ED" }),
8226
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8227
+ "button",
8228
+ {
8229
+ type: "button",
8230
+ className: "dock-sw" + (cfg.voiceNotify ? " on" : ""),
8231
+ role: "switch",
8232
+ "aria-checked": cfg.voiceNotify,
8233
+ "aria-label": "\u5F00\u5173\u8BED\u97F3\u64AD\u62A5",
8234
+ title: cfg.voiceNotify ? "\u5173\u95ED\u8BED\u97F3\u64AD\u62A5" : "\u5F00\u542F\u8BED\u97F3\u64AD\u62A5",
8235
+ onClick: () => patch({ voiceNotify: !cfg.voiceNotify })
8236
+ }
8237
+ )
8238
+ ] })
8239
+ ] }),
8240
+ cfg.voiceNotify ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-rows-narrow", children: [
8241
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8242
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u53E3\u5F84" }),
8243
+ [["brief", "\u7B80\u6D01"], ["medium", "\u9002\u4E2D"], ["detailed", "\u8BE6\u7EC6"]].map(([v, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8244
+ "button",
8245
+ {
8246
+ type: "button",
8247
+ className: "dknt-miniswitch" + (voiceTone(cfg) === v ? " on" : ""),
8248
+ style: { marginRight: 6 },
8249
+ title: "\u8BED\u97F3\u64AD\u62A5\u6309" + label + "\u6863\u8BF4",
8250
+ onClick: () => patch({ voiceMode: v }),
8251
+ children: label
8252
+ },
8253
+ v
8254
+ )),
8255
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u7B80\u6D01\uFF1A\u4E00\u53E5\u300C\u4EFB\u52A1\u5B8C\u6210 / \u4EFB\u52A1\u505C\u6B62\u4E86 / \u4EFB\u52A1\u9700\u8981\u6388\u6743 / \u4E3B\u4EFB\u52A1\uFF08\u6216\u5B50\u4EFB\u52A1\uFF09\xB7\u6807\u9898 \u5361\u4F4F\u4E86\u300D\uFF1B\u9002\u4E2D\uFF1A\u70B9\u540D\u4EFB\u52A1\uFF0C\u7ED3\u675F\u5E26\u539F\u56E0\u4E0E\u8017\u65F6\u3001\u5361\u4F4F\u5E26\u505C\u6EDE\u65F6\u957F\uFF1B\u8BE6\u7EC6\uFF1A\u7ED3\u675F\u5E26\u56DE\u5408\u7EDF\u8BA1\u4E0E\u56DE\u590D\u6458\u8981\uFF0C\u9700\u6388\u6743\u5E26\u5DE5\u5177\u540D\uFF0C\u5361\u4F4F\u5E26\u6700\u540E\u52A8\u4F5C" })
8256
+ ] }),
8257
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8258
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u64AD\u62A5\u65F6\u523B" }),
8259
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", style: { minWidth: 0 }, children: [
8260
+ ["voiceOnComplete", "\u5B8C\u6210", cfg.voiceOnComplete !== false],
8261
+ ["voiceOnError", "\u505C\u6B62", cfg.voiceOnError !== false],
8262
+ ["voiceOnConfirm", "\u9700\u6388\u6743", cfg.voiceOnConfirm !== false],
8263
+ ["voiceOnStuck", "\u5361\u4F4F", cfg.voiceOnStuck !== false]
8264
+ ].map(([key, label, on]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8265
+ "button",
8266
+ {
8267
+ type: "button",
8268
+ className: "dknt-miniswitch" + (on ? " on" : ""),
8269
+ style: { marginRight: 6 },
8270
+ title: key === "voiceOnStuck" ? "\u7F16\u7A0B\u9636\u6BB5 18 \u79D2\u6CA1\u6709\u52A8\u9759\u65F6\u64AD\u62A5\u4E00\u6B21\uFF08\u6062\u590D\u540E\u53EF\u518D\u62A5\uFF09" : "",
8271
+ onClick: () => patch({ [key]: !on }),
8272
+ children: [
8273
+ label,
8274
+ on ? "\xB7\u5F00" : "\xB7\u5173"
8275
+ ]
8276
+ },
8277
+ key
8278
+ )) })
8279
+ ] }),
8280
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8281
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BED\u901F" }),
8282
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8283
+ "input",
8284
+ {
8285
+ type: "range",
8286
+ min: "0.5",
8287
+ max: "2",
8288
+ step: "0.05",
8289
+ value: String(cfg.voiceRate || 1),
8290
+ "aria-label": "\u64AD\u62A5\u8BED\u901F",
8291
+ style: { width: 120, accentColor: "var(--dk-accent)" },
8292
+ onChange: (e) => patch({ voiceRate: Number(e.target.value) || 1 })
8293
+ }
8294
+ ),
8295
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub", children: [
8296
+ Number(cfg.voiceRate || 1).toFixed(2),
8297
+ "\xD7\uFF08\u64AD\u62A5\u6BD4\u6B63\u6587\u6717\u8BFB\u7565\u5FEB\u66F4\u5229\u843D\uFF09"
8298
+ ] })
8299
+ ] }),
8300
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8301
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u97F3\u91CF" }),
8302
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8303
+ "input",
8304
+ {
8305
+ type: "range",
8306
+ min: "0",
8307
+ max: "1",
8308
+ step: "0.05",
8309
+ value: String(cfg.voiceVolume == null ? 1 : cfg.voiceVolume),
8310
+ "aria-label": "\u64AD\u62A5\u97F3\u91CF",
8311
+ style: { width: 120, accentColor: "var(--dk-accent)" },
8312
+ onChange: (e) => patch({ voiceVolume: Number(e.target.value) })
8313
+ }
8314
+ ),
8315
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dknt-row-sub", children: [
8316
+ Math.round((cfg.voiceVolume == null ? 1 : cfg.voiceVolume) * 100),
8317
+ "%"
8318
+ ] })
8319
+ ] }),
8320
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8321
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u97F3\u8272" }),
8322
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8323
+ "select",
8324
+ {
8325
+ className: "dknt-input",
8326
+ style: { maxWidth: 260 },
8327
+ value: cfg.voiceURI || "",
8328
+ "aria-label": "\u64AD\u62A5\u97F3\u8272",
8329
+ onChange: (e) => patch({ voiceURI: e.target.value }),
8330
+ children: [
8331
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u81EA\u52A8\uFF08\u6309\u8BED\u8A00\u6311\uFF09" }),
8332
+ (() => {
8333
+ const zh = [], other = [];
8334
+ for (const v of voices) {
8335
+ if (!v || !v.voiceURI) continue;
8336
+ if (/^zh/i.test(String(v.lang || ""))) zh.push(v);
8337
+ else other.push(v);
8338
+ }
8339
+ const groups = [];
8340
+ if (zh.length) groups.push(["\u4E2D\u6587\u97F3\u8272", zh]);
8341
+ if (other.length) groups.push(["\u5176\u4ED6\u97F3\u8272", other]);
8342
+ return groups.map(([gname, vs]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("optgroup", { label: gname, children: vs.map((v) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: v.voiceURI, children: (v.name || v.voiceURI) + "\uFF08" + (v.lang || "?") + "\uFF09" }, v.voiceURI)) }, gname));
8343
+ })()
8344
+ ]
8345
+ }
8346
+ ),
8347
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: voices.length ? "\u97F3\u8272\u662F\u672C\u673A\u6D4F\u89C8\u5668\u7ED9\u7684\uFF0C\u6362\u8BBE\u5907\u53EF\u80FD\u8981\u91CD\u9009\uFF1B\u672C\u673A\u627E\u4E0D\u5230\u6240\u9009\u97F3\u8272\u65F6\u81EA\u52A8\u6309\u8BED\u8A00\u56DE\u843D" : "\u672C\u673A\u6682\u672A\u8BFB\u5230\u97F3\u8272\uFF08\u7CFB\u7EDF\u8BED\u97F3\u672A\u88C5/\u672A\u542F\u7528\uFF09\uFF0C\u5C06\u6309\u8BED\u8A00\u81EA\u52A8\u6311" })
8348
+ ] }),
8349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8350
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BD5\u542C" }),
8351
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8352
+ "button",
8353
+ {
8354
+ type: "button",
8355
+ className: "dknt-btn",
8356
+ disabled: !voiceSupported(),
8357
+ onClick: () => {
8358
+ const preview = Object.assign({}, cfg, { voiceNotify: true });
8359
+ speakVoice(endBroadcastText(true, { title: "\u793A\u4F8B\u4EFB\u52A1", duration: 125e3, turns: 3, steps: 9, toolCalls: 4, lastText: "\u597D\u7684\uFF0C\u4E09\u4EFD\u6587\u6863\u90FD\u5DF2\u66F4\u65B0\u5B8C\u6BD5\u3002" }, null, preview), preview);
8360
+ },
8361
+ children: "\u64AD\u4E00\u53E5"
8362
+ }
8363
+ ),
8364
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
8365
+ "button",
8366
+ {
8367
+ type: "button",
8368
+ className: "dknt-btn",
8369
+ disabled: !voiceSupported(),
8370
+ onClick: () => {
8371
+ const preview = Object.assign({}, cfg, { voiceNotify: true });
8372
+ speakVoice(confirmBroadcastText({ title: "\u793A\u4F8B\u4EFB\u52A1" }, { toolName: "pwsh" }, preview), preview);
8373
+ },
8374
+ children: "\u9700\u6388\u6743"
8375
+ }
8376
+ ),
8377
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: voiceSupported() ? "\u6D4F\u89C8\u5668\u8BED\u97F3\u5408\u6210\uFF08\u4E0E\u3010\u8BED\u97F3\u6717\u8BFB\u3011\u540C\u4E00\u5957\u58F0\u97F3\uFF0C\u72EC\u7ACB\u5F00\u5173\uFF1B\u6253\u65AD\u5F0F\u2014\u2014\u64AD\u62A5\u4FE1\u65F6\u6B63\u5728\u6717\u8BFB\u7684\u6B63\u6587\u4F1A\u8BA9\u4F4D\uFF09" : "\u672C\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u8BED\u97F3\u5408\u6210\uFF08speechSynthesis \u4E0D\u53EF\u7528\uFF09" })
8378
+ ] }),
8379
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-row", children: [
8380
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-label", children: "\u8BED\u8A00" }),
8381
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
8382
+ "select",
8383
+ {
8384
+ className: "dknt-input",
8385
+ style: { maxWidth: 180 },
8386
+ value: cfg.voiceLang || "",
8387
+ "aria-label": "\u64AD\u62A5\u8BED\u8A00",
8388
+ onChange: (e) => patch({ voiceLang: e.target.value }),
8389
+ children: [
8390
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u81EA\u52A8\uFF08\u4E2D\u6587\u4F18\u5148\uFF09" }),
8391
+ ["zh-CN", "zh-TW", "en-US", "en-GB", "ja-JP", "ko-KR"].map((l) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: l, children: l }, l))
8392
+ ]
8393
+ }
8394
+ ),
8395
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-row-sub", children: "\u672A\u6307\u5B9A\u97F3\u8272\u65F6\u6309\u8BED\u8A00\u81EA\u52A8\u6311\uFF1B\u5DF2\u9009\u97F3\u8272\u7684\u8BED\u8A00\u4F1A\u8986\u76D6\u8FD9\u91CC" })
8396
+ ] })
8397
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dknt-note", children: "\u672A\u5F00\u542F\u2014\u2014\u4EFB\u52A1\u4E8B\u4EF6\u4E0D\u64AD\u62A5\u8BED\u97F3\uFF08\u63D0\u793A\u97F3\u3001\u7CFB\u7EDF\u901A\u77E5\u4E0D\u53D7\u5F71\u54CD\uFF09\u3002" })
8398
+ ] }, "voice"),
7836
8399
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec", children: [
7837
8400
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dknt-sec-head", children: [
7838
8401
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dknt-sec-title", children: "\u9489\u9489\u63A8\u9001" }),
@@ -7965,7 +8528,7 @@ function NotifyStat(props) {
7965
8528
  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" });
7966
8529
  if (!cfg) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "\u7B49\u5F85\u901A\u77E5\u914D\u7F6E\u2026" });
7967
8530
  const events = [cfg.notifyOnComplete ? "\u5B8C\u6210" : "", cfg.notifyOnError ? "\u5F02\u5E38" : "", cfg.notifyOnConfirm !== false ? "\u9700\u786E\u8BA4" : ""].filter(Boolean);
7968
- const extras = [cfg.soundNotify !== false ? "\u63D0\u793A\u97F3" : "", cfg.systemNotify ? "\u7CFB\u7EDF\u901A\u77E5" : ""].filter(Boolean);
8531
+ const extras = [cfg.soundNotify !== false ? "\u63D0\u793A\u97F3" : "", cfg.systemNotify ? "\u7CFB\u7EDF\u901A\u77E5" : "", cfg.voiceNotify ? "\u8BED\u97F3\u64AD\u62A5" + (cfg.voiceMode === "detailed" ? "\xB7\u8BE6" : cfg.voiceMode === "medium" ? "\xB7\u9002" : "\xB7\u7B80") : ""].filter(Boolean);
7969
8532
  const push = [cfg.dingtalkEnabled ? "\u9489\u9489" : "", cfg.feishuEnabled ? "\u98DE\u4E66" : ""].filter(Boolean);
7970
8533
  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("/") : "") });
7971
8534
  }
@@ -8285,7 +8848,7 @@ function makeUtterance(text) {
8285
8848
  return null;
8286
8849
  }
8287
8850
  }
8288
- function localVoices() {
8851
+ function localVoices2() {
8289
8852
  const s = synth();
8290
8853
  if (!s) return [];
8291
8854
  try {
@@ -8545,8 +9108,8 @@ function chunkForSpeech(text, limit) {
8545
9108
  if (buf.trim()) chunks.push(buf);
8546
9109
  return chunks;
8547
9110
  }
8548
- function pickVoice(cfg) {
8549
- const voices = localVoices();
9111
+ function pickVoice2(cfg) {
9112
+ const voices = localVoices2();
8550
9113
  if (voices.length === 0) return null;
8551
9114
  const want = String(cfg && cfg.voiceURI || "");
8552
9115
  if (want) {
@@ -8648,7 +9211,7 @@ function startSession(opts) {
8648
9211
  const chunks = chunkForSpeech(text, 180);
8649
9212
  if (chunks.length === 0) return false;
8650
9213
  const epoch = ++engine.epoch;
8651
- const voice = pickVoice(cfg);
9214
+ const voice = pickVoice2(cfg);
8652
9215
  const session = { key, raw: text, chunks, index: 0, epoch, cfg, label: String(o.label || "") };
8653
9216
  engine.session = session;
8654
9217
  setEngineState({ phase: "playing", key, label: session.label });
@@ -9168,13 +9731,13 @@ function TtsView() {
9168
9731
  const eng = useEngineState();
9169
9732
  const [, force] = (0, import_react12.useState)(0);
9170
9733
  const [saved, setSaved] = (0, import_react12.useState)("");
9171
- const voices = (0, import_react12.useRef)(localVoices());
9734
+ const voices = (0, import_react12.useRef)(localVoices2());
9172
9735
  (0, import_react12.useEffect)(() => {
9173
9736
  ensureConfigLoaded();
9174
9737
  const s = synth();
9175
9738
  if (!s || typeof s.addEventListener !== "function") return;
9176
9739
  const onChange = () => {
9177
- voices.current = localVoices();
9740
+ voices.current = localVoices2();
9178
9741
  force((n) => n + 1);
9179
9742
  };
9180
9743
  try {
@@ -9191,7 +9754,7 @@ function TtsView() {
9191
9754
  }, []);
9192
9755
  (0, import_react12.useEffect)(() => {
9193
9756
  if (voices.current.length === 0) {
9194
- voices.current = localVoices();
9757
+ voices.current = localVoices2();
9195
9758
  force((n) => n + 1);
9196
9759
  }
9197
9760
  }, []);
@@ -13894,7 +14457,7 @@ var feature13 = {
13894
14457
  };
13895
14458
 
13896
14459
  // src/client.jsx
13897
- var DOCK_VERSION = "0.17.0";
14460
+ var DOCK_VERSION = "0.19.0";
13898
14461
  var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10, feature11, feature12, feature13];
13899
14462
  var PLANNED_FEATURES = [];
13900
14463
  var PLANNED_NOTES = {};