dsh-dock 0.12.0 → 0.14.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
@@ -12,7 +12,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
12
12
  var __getProtoOf = Object.getPrototypeOf;
13
13
  var __hasOwnProp = Object.prototype.hasOwnProperty;
14
14
  var __commonJS = (cb, mod) => function __require() {
15
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
+ try {
16
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
17
+ } catch (e) {
18
+ throw mod = 0, e;
19
+ }
16
20
  };
17
21
  var __export = (target, all) => {
18
22
  for (var name in all)
@@ -36,18 +40,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
40
  ));
37
41
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
42
 
39
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/can-promise.js
43
+ // node_modules/qrcode/lib/can-promise.js
40
44
  var require_can_promise = __commonJS({
41
- ".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) {
42
46
  module2.exports = function() {
43
47
  return typeof Promise === "function" && Promise.prototype && Promise.prototype.then;
44
48
  };
45
49
  }
46
50
  });
47
51
 
48
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js
52
+ // node_modules/qrcode/lib/core/utils.js
49
53
  var require_utils = __commonJS({
50
- ".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) {
51
55
  var toSJISFunction;
52
56
  var CODEWORDS_COUNT = [
53
57
  0,
@@ -124,9 +128,9 @@ var require_utils = __commonJS({
124
128
  }
125
129
  });
126
130
 
127
- // .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
128
132
  var require_error_correction_level = __commonJS({
129
- ".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) {
130
134
  exports.L = { bit: 1 };
131
135
  exports.M = { bit: 0 };
132
136
  exports.Q = { bit: 3 };
@@ -169,9 +173,9 @@ var require_error_correction_level = __commonJS({
169
173
  }
170
174
  });
171
175
 
172
- // .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
173
177
  var require_bit_buffer = __commonJS({
174
- ".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) {
175
179
  function BitBuffer() {
176
180
  this.buffer = [];
177
181
  this.length = 0;
@@ -204,9 +208,9 @@ var require_bit_buffer = __commonJS({
204
208
  }
205
209
  });
206
210
 
207
- // .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
208
212
  var require_bit_matrix = __commonJS({
209
- ".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) {
210
214
  function BitMatrix(size) {
211
215
  if (!size || size < 1) {
212
216
  throw new Error("BitMatrix size must be defined and greater than 0");
@@ -233,9 +237,9 @@ var require_bit_matrix = __commonJS({
233
237
  }
234
238
  });
235
239
 
236
- // .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
237
241
  var require_alignment_pattern = __commonJS({
238
- ".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) {
239
243
  var getSymbolSize = require_utils().getSymbolSize;
240
244
  exports.getRowColCoords = function getRowColCoords(version) {
241
245
  if (version === 1) return [];
@@ -268,9 +272,9 @@ var require_alignment_pattern = __commonJS({
268
272
  }
269
273
  });
270
274
 
271
- // .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
272
276
  var require_finder_pattern = __commonJS({
273
- ".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) {
274
278
  var getSymbolSize = require_utils().getSymbolSize;
275
279
  var FINDER_PATTERN_SIZE = 7;
276
280
  exports.getPositions = function getPositions(version) {
@@ -287,9 +291,9 @@ var require_finder_pattern = __commonJS({
287
291
  }
288
292
  });
289
293
 
290
- // .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
291
295
  var require_mask_pattern = __commonJS({
292
- ".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) {
293
297
  exports.Patterns = {
294
298
  PATTERN000: 0,
295
299
  PATTERN001: 1,
@@ -429,9 +433,9 @@ var require_mask_pattern = __commonJS({
429
433
  }
430
434
  });
431
435
 
432
- // .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
433
437
  var require_error_correction_code = __commonJS({
434
- ".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) {
435
439
  var ECLevel = require_error_correction_level();
436
440
  var EC_BLOCKS_TABLE = [
437
441
  // L M Q H
@@ -790,9 +794,9 @@ var require_error_correction_code = __commonJS({
790
794
  }
791
795
  });
792
796
 
793
- // .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
794
798
  var require_galois_field = __commonJS({
795
- ".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) {
796
800
  var EXP_TABLE = new Uint8Array(512);
797
801
  var LOG_TABLE = new Uint8Array(256);
798
802
  (function initTables() {
@@ -823,9 +827,9 @@ var require_galois_field = __commonJS({
823
827
  }
824
828
  });
825
829
 
826
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/polynomial.js
830
+ // node_modules/qrcode/lib/core/polynomial.js
827
831
  var require_polynomial = __commonJS({
828
- ".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) {
829
833
  var GF = require_galois_field();
830
834
  exports.mul = function mul(p1, p2) {
831
835
  const coeff = new Uint8Array(p1.length + p2.length - 1);
@@ -859,9 +863,9 @@ var require_polynomial = __commonJS({
859
863
  }
860
864
  });
861
865
 
862
- // .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
863
867
  var require_reed_solomon_encoder = __commonJS({
864
- ".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) {
865
869
  var Polynomial = require_polynomial();
866
870
  function ReedSolomonEncoder(degree) {
867
871
  this.genPoly = void 0;
@@ -891,18 +895,18 @@ var require_reed_solomon_encoder = __commonJS({
891
895
  }
892
896
  });
893
897
 
894
- // .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
895
899
  var require_version_check = __commonJS({
896
- ".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) {
897
901
  exports.isValid = function isValid(version) {
898
902
  return !isNaN(version) && version >= 1 && version <= 40;
899
903
  };
900
904
  }
901
905
  });
902
906
 
903
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/regex.js
907
+ // node_modules/qrcode/lib/core/regex.js
904
908
  var require_regex = __commonJS({
905
- ".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) {
906
910
  var numeric = "[0-9]+";
907
911
  var alphanumeric = "[A-Z $%*+\\-./:]+";
908
912
  var kanji = "(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";
@@ -928,9 +932,9 @@ var require_regex = __commonJS({
928
932
  }
929
933
  });
930
934
 
931
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mode.js
935
+ // node_modules/qrcode/lib/core/mode.js
932
936
  var require_mode = __commonJS({
933
- ".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) {
934
938
  var VersionCheck = require_version_check();
935
939
  var Regex = require_regex();
936
940
  exports.NUMERIC = {
@@ -1009,9 +1013,9 @@ var require_mode = __commonJS({
1009
1013
  }
1010
1014
  });
1011
1015
 
1012
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version.js
1016
+ // node_modules/qrcode/lib/core/version.js
1013
1017
  var require_version = __commonJS({
1014
- ".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) {
1015
1019
  var Utils = require_utils();
1016
1020
  var ECCode = require_error_correction_code();
1017
1021
  var ECLevel = require_error_correction_level();
@@ -1104,9 +1108,9 @@ var require_version = __commonJS({
1104
1108
  }
1105
1109
  });
1106
1110
 
1107
- // .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
1108
1112
  var require_format_info = __commonJS({
1109
- ".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) {
1110
1114
  var Utils = require_utils();
1111
1115
  var G15 = 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0;
1112
1116
  var G15_MASK = 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1;
@@ -1122,9 +1126,9 @@ var require_format_info = __commonJS({
1122
1126
  }
1123
1127
  });
1124
1128
 
1125
- // .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
1126
1130
  var require_numeric_data = __commonJS({
1127
- ".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) {
1128
1132
  var Mode = require_mode();
1129
1133
  function NumericData(data) {
1130
1134
  this.mode = Mode.NUMERIC;
@@ -1157,9 +1161,9 @@ var require_numeric_data = __commonJS({
1157
1161
  }
1158
1162
  });
1159
1163
 
1160
- // .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
1161
1165
  var require_alphanumeric_data = __commonJS({
1162
- ".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) {
1163
1167
  var Mode = require_mode();
1164
1168
  var ALPHA_NUM_CHARS = [
1165
1169
  "0",
@@ -1236,9 +1240,9 @@ var require_alphanumeric_data = __commonJS({
1236
1240
  }
1237
1241
  });
1238
1242
 
1239
- // .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
1240
1244
  var require_byte_data = __commonJS({
1241
- ".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) {
1242
1246
  var Mode = require_mode();
1243
1247
  function ByteData(data) {
1244
1248
  this.mode = Mode.BYTE;
@@ -1266,9 +1270,9 @@ var require_byte_data = __commonJS({
1266
1270
  }
1267
1271
  });
1268
1272
 
1269
- // .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
1270
1274
  var require_kanji_data = __commonJS({
1271
- ".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) {
1272
1276
  var Mode = require_mode();
1273
1277
  var Utils = require_utils();
1274
1278
  function KanjiData(data) {
@@ -1305,9 +1309,9 @@ var require_kanji_data = __commonJS({
1305
1309
  }
1306
1310
  });
1307
1311
 
1308
- // .devdeps/node_modules/.pnpm/dijkstrajs@1.0.3/node_modules/dijkstrajs/dijkstra.js
1312
+ // node_modules/dijkstrajs/dijkstra.js
1309
1313
  var require_dijkstra = __commonJS({
1310
- ".devdeps/node_modules/.pnpm/dijkstrajs@1.0.3/node_modules/dijkstrajs/dijkstra.js"(exports, module2) {
1314
+ "node_modules/dijkstrajs/dijkstra.js"(exports, module2) {
1311
1315
  "use strict";
1312
1316
  var dijkstra = {
1313
1317
  single_source_shortest_paths: function(graph, s, d) {
@@ -1406,9 +1410,9 @@ var require_dijkstra = __commonJS({
1406
1410
  }
1407
1411
  });
1408
1412
 
1409
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/segments.js
1413
+ // node_modules/qrcode/lib/core/segments.js
1410
1414
  var require_segments = __commonJS({
1411
- ".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) {
1412
1416
  var Mode = require_mode();
1413
1417
  var NumericData = require_numeric_data();
1414
1418
  var AlphanumericData = require_alphanumeric_data();
@@ -1592,9 +1596,9 @@ var require_segments = __commonJS({
1592
1596
  }
1593
1597
  });
1594
1598
 
1595
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/qrcode.js
1599
+ // node_modules/qrcode/lib/core/qrcode.js
1596
1600
  var require_qrcode = __commonJS({
1597
- ".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) {
1598
1602
  var Utils = require_utils();
1599
1603
  var ECLevel = require_error_correction_level();
1600
1604
  var BitBuffer = require_bit_buffer();
@@ -1853,9 +1857,9 @@ var require_qrcode = __commonJS({
1853
1857
  }
1854
1858
  });
1855
1859
 
1856
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js
1860
+ // node_modules/qrcode/lib/renderer/utils.js
1857
1861
  var require_utils2 = __commonJS({
1858
- ".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) {
1859
1863
  function hex2rgba(hex) {
1860
1864
  if (typeof hex === "number") {
1861
1865
  hex = hex.toString();
@@ -1933,9 +1937,9 @@ var require_utils2 = __commonJS({
1933
1937
  }
1934
1938
  });
1935
1939
 
1936
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/canvas.js
1940
+ // node_modules/qrcode/lib/renderer/canvas.js
1937
1941
  var require_canvas = __commonJS({
1938
- ".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) {
1939
1943
  var Utils = require_utils2();
1940
1944
  function clearCanvas(ctx, canvas, size) {
1941
1945
  ctx.clearRect(0, 0, canvas.width, canvas.height);
@@ -1986,9 +1990,9 @@ var require_canvas = __commonJS({
1986
1990
  }
1987
1991
  });
1988
1992
 
1989
- // .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
1990
1994
  var require_svg_tag = __commonJS({
1991
- ".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) {
1992
1996
  var Utils = require_utils2();
1993
1997
  function getColorAttrib(color, attrib) {
1994
1998
  const alpha = color.a / 255;
@@ -2044,9 +2048,9 @@ var require_svg_tag = __commonJS({
2044
2048
  }
2045
2049
  });
2046
2050
 
2047
- // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/browser.js
2051
+ // node_modules/qrcode/lib/browser.js
2048
2052
  var require_browser = __commonJS({
2049
- ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/browser.js"(exports) {
2053
+ "node_modules/qrcode/lib/browser.js"(exports) {
2050
2054
  var canPromise = require_can_promise();
2051
2055
  var QRCode2 = require_qrcode();
2052
2056
  var CanvasRenderer = require_canvas();
@@ -2122,7 +2126,7 @@ __export(client_exports, {
2122
2126
  inject: () => inject
2123
2127
  });
2124
2128
  module.exports = __toCommonJS(client_exports);
2125
- var import_react22 = __toESM(require("react"), 1);
2129
+ var import_react24 = __toESM(require("react"), 1);
2126
2130
 
2127
2131
  // src/shared.js
2128
2132
  var import_react = __toESM(require("react"), 1);
@@ -2183,7 +2187,7 @@ function initFeatureState(defs) {
2183
2187
  }
2184
2188
  function syncFeatureStateFromHost(defs) {
2185
2189
  if (typeof fetch !== "function") return;
2186
- fetch("/dsh-dock/features").then(async (res) => {
2190
+ fetch("dsh-dock/features").then(async (res) => {
2187
2191
  if (!res.ok) return;
2188
2192
  const data = await res.json().catch(() => null);
2189
2193
  const persisted = data && data.ok && data.data && data.data.persisted;
@@ -2210,7 +2214,7 @@ function syncFeatureStateFromHost(defs) {
2210
2214
  }
2211
2215
  function pushFeatureEnabledToHost(id, enabled) {
2212
2216
  if (typeof fetch !== "function") return;
2213
- fetch("/dsh-dock/features", {
2217
+ fetch("dsh-dock/features", {
2214
2218
  method: "POST",
2215
2219
  headers: { "content-type": "application/json" },
2216
2220
  body: JSON.stringify({ id, enabled })
@@ -2296,7 +2300,7 @@ function subscribePanel(fn) {
2296
2300
  var import_react2 = __toESM(require("react"), 1);
2297
2301
  var import_jsx_runtime = require("react/jsx-runtime");
2298
2302
  function rpcCall(method, args) {
2299
- return fetch("/dsh-dock/tokenlog/" + method, {
2303
+ return fetch("dsh-dock/tokenlog/" + method, {
2300
2304
  method: "POST",
2301
2305
  headers: { "content-type": "application/json" },
2302
2306
  body: JSON.stringify(args === void 0 ? {} : args)
@@ -3727,7 +3731,7 @@ var modelsStore = {
3727
3731
  load() {
3728
3732
  if (this.snap.loading) return;
3729
3733
  this.set({ loading: true, error: null });
3730
- fetch("/dsh-dock/models", { cache: "no-store", signal: AbortSignal.timeout(2e4) }).then((res) => res.ok ? res.json() : Promise.reject(new Error("\u6A21\u578B\u76EE\u5F55\u63A5\u53E3 HTTP " + res.status))).then((data) => this.set({ data, loading: false, error: null })).catch((e) => this.set({ loading: false, error: e && e.message || String(e) }));
3734
+ fetch("dsh-dock/models", { cache: "no-store", signal: AbortSignal.timeout(2e4) }).then((res) => res.ok ? res.json() : Promise.reject(new Error("\u6A21\u578B\u76EE\u5F55\u63A5\u53E3 HTTP " + res.status))).then((data) => this.set({ data, loading: false, error: null })).catch((e) => this.set({ loading: false, error: e && e.message || String(e) }));
3731
3735
  }
3732
3736
  };
3733
3737
  function useModels() {
@@ -3744,35 +3748,190 @@ var DKM_TAGS = [["video", "\u89C6\u9891"], ["audio", "\u97F3\u9891"], ["document
3744
3748
  var DKM_PI_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
3745
3749
  var DKM_DS_LEVELS = ["off", "low", "high", "max"];
3746
3750
  var DKM_EFFORT_NAMES = { off: "\u5173\u95ED", minimal: "\u6781\u4F4E", low: "\u4F4E", medium: "\u4E2D", high: "\u9AD8", xhigh: "\u8D85\u9AD8", max: "\u6700\u9AD8" };
3751
+ var DKM_APIS = [
3752
+ ["openai-completions", "OpenAI \u517C\u5BB9\uFF08chat/completions\uFF09"],
3753
+ ["openai-responses", "OpenAI Responses"],
3754
+ ["anthropic-messages", "Anthropic Messages"]
3755
+ ];
3756
+ var DKM_ROUTE_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
3757
+ function dkmEnvFromRoute(route) {
3758
+ const s = String(route || "").toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
3759
+ if (!s) return "";
3760
+ return (/^[0-9]/.test(s) ? "KEY_" + s : s) + "_API_KEY";
3761
+ }
3762
+ var DKM_ALL_INPUT = DKM_MODALITIES.map((x) => x[0]);
3763
+ var DKM_ALL_TAGS = DKM_TAGS.map((x) => x[0]);
3764
+ function dkmToggleIn(list, v) {
3765
+ return list.indexOf(v) >= 0 ? list.filter((x) => x !== v) : list.concat([v]);
3766
+ }
3767
+ function dkmAllInputs(on) {
3768
+ return { input: on ? DKM_ALL_INPUT.slice() : [], tags: on ? DKM_ALL_TAGS.slice() : [] };
3769
+ }
3770
+ function dkmAllLevels(on) {
3771
+ const lv = {};
3772
+ for (const k of DKM_PI_LEVELS) lv[k] = !!on;
3773
+ return { effortsMode: "custom", effortLevels: lv };
3774
+ }
3775
+ function draftFromModel(m) {
3776
+ const levels = {};
3777
+ if (m.efforts === "custom" && m.effortMap && typeof m.effortMap === "object") {
3778
+ for (const lv of DKM_PI_LEVELS) levels[lv] = m.effortMap[lv] !== void 0;
3779
+ }
3780
+ return {
3781
+ id: m.id || "",
3782
+ name: m.name || "",
3783
+ contextWindow: m.contextWindow != null ? String(m.contextWindow) : "",
3784
+ maxTokens: m.maxTokens != null ? String(m.maxTokens) : "",
3785
+ input: m.input && m.input.length ? m.input.slice() : ["text"],
3786
+ tags: (m.tags || []).slice(),
3787
+ effortsMode: m.efforts === "custom" ? "custom" : m.efforts === "off" ? "off" : "inherit",
3788
+ effortLevels: levels,
3789
+ raw: m.raw && typeof m.raw === "object" ? m.raw : null
3790
+ };
3791
+ }
3792
+ function emptyModelDraft() {
3793
+ return { id: "", name: "", contextWindow: "", maxTokens: "", input: ["text"], tags: [], effortsMode: "inherit", effortLevels: {}, raw: null };
3794
+ }
3795
+ function emptyProviderForm() {
3796
+ return {
3797
+ route: "",
3798
+ displayName: "",
3799
+ api: "openai-completions",
3800
+ baseURL: "",
3801
+ apiKeyEnv: "",
3802
+ apiKey: "",
3803
+ defaultInput: ["text"],
3804
+ models: [],
3805
+ extra: {}
3806
+ };
3807
+ }
3808
+ function providerFormFromProvider(p) {
3809
+ const raw = p.rawProfile && typeof p.rawProfile === "object" && !Array.isArray(p.rawProfile) ? p.rawProfile : {};
3810
+ const extra = Object.assign({}, raw);
3811
+ delete extra.displayName;
3812
+ delete extra.api;
3813
+ delete extra.baseURL;
3814
+ delete extra.apiKeyEnv;
3815
+ delete extra.defaultInput;
3816
+ delete extra.models;
3817
+ const models = draftFromProvider(p).models;
3818
+ return {
3819
+ route: p.route || p.id || "",
3820
+ displayName: typeof raw.displayName === "string" ? raw.displayName : p.displayName || "",
3821
+ api: typeof raw.api === "string" && raw.api ? raw.api : p.api || "openai-completions",
3822
+ baseURL: typeof raw.baseURL === "string" ? raw.baseURL : p.baseURL || "",
3823
+ apiKeyEnv: typeof raw.apiKeyEnv === "string" ? raw.apiKeyEnv : p.apiKeyEnv || "",
3824
+ apiKey: "",
3825
+ defaultInput: Array.isArray(raw.defaultInput) && raw.defaultInput.length ? raw.defaultInput.slice() : Array.isArray(p.defaultInput) && p.defaultInput.length ? p.defaultInput.slice() : ["text"],
3826
+ models: models.length ? models : [emptyModelDraft()],
3827
+ extra
3828
+ };
3829
+ }
3747
3830
  function draftFromProvider(p) {
3748
3831
  return {
3749
3832
  id: p.id,
3750
3833
  kind: p.kind,
3751
3834
  thinking: p.thinking === "disabled" ? "disabled" : "enabled",
3752
3835
  defaultEffort: DKM_DS_LEVELS.indexOf(p.defaultEffort) >= 0 ? p.defaultEffort : "high",
3753
- models: (p.models || []).map((m) => {
3754
- const levels = {};
3755
- if (m.efforts === "custom" && m.effortMap && typeof m.effortMap === "object") {
3756
- for (const lv of DKM_PI_LEVELS) levels[lv] = m.effortMap[lv] !== void 0;
3757
- }
3758
- return {
3759
- id: m.id || "",
3760
- name: m.name || "",
3761
- contextWindow: m.contextWindow != null ? String(m.contextWindow) : "",
3762
- maxTokens: m.maxTokens != null ? String(m.maxTokens) : "",
3763
- input: m.input && m.input.length ? m.input.slice() : ["text"],
3764
- tags: (m.tags || []).slice(),
3765
- effortsMode: m.efforts === "custom" ? "custom" : m.efforts === "off" ? "off" : "inherit",
3766
- effortLevels: levels,
3767
- raw: m.raw && typeof m.raw === "object" ? m.raw : null
3768
- };
3769
- })
3836
+ models: (p.models || []).map(draftFromModel)
3770
3837
  };
3771
3838
  }
3772
- function ModelsView() {
3839
+ function ModelRow(props) {
3840
+ const m = props.m, i = props.i, kind = props.kind, onPatch = props.onPatch, onDel = props.onDel;
3841
+ return import_react3.default.createElement(
3842
+ "div",
3843
+ { key: i, className: "dkm-model" },
3844
+ import_react3.default.createElement(
3845
+ "div",
3846
+ { className: "dkm-model-head" },
3847
+ import_react3.default.createElement("span", { className: "dkm-model-idx" }, "#" + (i + 1)),
3848
+ import_react3.default.createElement("button", { type: "button", className: "dkm-del", onClick: () => onDel(i) }, "\u5220\u9664")
3849
+ ),
3850
+ import_react3.default.createElement(
3851
+ "div",
3852
+ { className: "dkm-grid" },
3853
+ import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u6A21\u578B id\uFF08\u5FC5\u586B\uFF0C\u5982 deepseek-v4-pro\uFF09", value: m.id, onChange: (e) => onPatch(i, { id: e.target.value }) }),
3854
+ import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u663E\u793A\u540D\u79F0\uFF08\u53EF\u9009\uFF09", value: m.name, onChange: (e) => onPatch(i, { name: e.target.value }) }),
3855
+ import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u4E0A\u4E0B\u6587\u7A97\u53E3", inputMode: "numeric", value: m.contextWindow, onChange: (e) => onPatch(i, { contextWindow: e.target.value }) }),
3856
+ import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u6700\u5927\u8F93\u51FA", inputMode: "numeric", value: m.maxTokens, onChange: (e) => onPatch(i, { maxTokens: e.target.value }) })
3857
+ ),
3858
+ import_react3.default.createElement(
3859
+ "div",
3860
+ { className: "dkm-checks" },
3861
+ import_react3.default.createElement("span", { className: "dkm-label" }, "\u8F93\u5165\u7C7B\u578B\uFF1A"),
3862
+ DKM_MODALITIES.map(([v, label]) => import_react3.default.createElement(
3863
+ "label",
3864
+ {
3865
+ key: v,
3866
+ className: "dkm-check",
3867
+ title: v === "image" ? "\u7531\u4F60\u58F0\u660E\u8BE5\u7AEF\u70B9\u652F\u6301\u56FE\u7247\uFF1A\u4FDD\u5B58\u540E\u539F\u56FE\u76F4\u53D1\uFF0C\u5E76\u53EF\u4F5C\u4E3A\u89C6\u89C9\u6A21\u578B\u5019\u9009\u3002\u7CFB\u7EDF\u4E0D\u4F1A\u66FF\u4F60\u731C\u6D4B\uFF1B\u7AEF\u70B9\u5B9E\u9645\u4E0D\u652F\u6301\u65F6\u53D6\u6D88\u52FE\u9009\u5373\u53EF\u6062\u590D\u8D70\u56FE\u7247\u7406\u89E3\u4EE3\u7406" : null
3868
+ },
3869
+ import_react3.default.createElement("input", {
3870
+ type: "checkbox",
3871
+ checked: m.input.indexOf(v) >= 0,
3872
+ onChange: () => {
3873
+ const next = dkmToggleIn(m.input, v);
3874
+ onPatch(i, { input: next.length > 0 ? next : ["text"] });
3875
+ }
3876
+ }),
3877
+ label
3878
+ )),
3879
+ import_react3.default.createElement("span", { className: "dkm-label dkm-tag", title: "\u6807\u6CE8\u4EC5\u5728\u672C\u9762\u677F\u5C55\u793A\u4E0E\u6301\u4E45\u5316\uFF0C\u4E0D\u53C2\u4E0E\u8BF7\u6C42\u8DEF\u7531\uFF08\u5B98\u65B9 schema \u53EA\u63A5\u53D7\u6587\u672C/\u56FE\u7247\uFF09" }, "\u6807\u6CE8\uFF1A"),
3880
+ DKM_TAGS.map(([v, label]) => import_react3.default.createElement(
3881
+ "label",
3882
+ { key: v, className: "dkm-check dkm-tag" },
3883
+ import_react3.default.createElement("input", { type: "checkbox", checked: m.tags.indexOf(v) >= 0, onChange: () => onPatch(i, { tags: dkmToggleIn(m.tags, v) }) }),
3884
+ label
3885
+ )),
3886
+ import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u52FE\u9009\u5168\u90E8\u8F93\u5165\u7C7B\u578B\u4E0E\u6807\u6CE8", onClick: () => onPatch(i, dkmAllInputs(true)) }, "\u5168\u9009"),
3887
+ import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u53D6\u6D88\u5168\u90E8\u52FE\u9009\uFF08\u8F93\u5165\u7559\u7A7A = \u7EE7\u627F\u76EE\u5F55\u9ED8\u8BA4\uFF09", onClick: () => onPatch(i, dkmAllInputs(false)) }, "\u53D6\u6D88\u5168\u9009")
3888
+ ),
3889
+ import_react3.default.createElement(
3890
+ "div",
3891
+ { className: "dkm-efforts" },
3892
+ import_react3.default.createElement("span", { className: "dkm-label" }, "\u601D\u8003\u5F3A\u5EA6\uFF1A"),
3893
+ kind === "deepseek" ? import_react3.default.createElement("span", { className: "dkm-sub" }, "\u968F Provider \u8BBE\u7F6E\uFF08Off/Low/High/Max\uFF0C\u5168\u6A21\u578B\u5171\u4EAB\uFF09") : import_react3.default.createElement(
3894
+ "span",
3895
+ null,
3896
+ import_react3.default.createElement(
3897
+ "select",
3898
+ {
3899
+ className: "dkm-select",
3900
+ value: m.effortsMode,
3901
+ onChange: (e) => onPatch(i, {
3902
+ effortsMode: e.target.value,
3903
+ effortLevels: e.target.value === "custom" && m.effortsMode !== "custom" ? { off: true, low: true, high: true } : m.effortLevels
3904
+ })
3905
+ },
3906
+ import_react3.default.createElement("option", { value: "inherit" }, "\u8DDF\u968F\u76EE\u5F55\u9ED8\u8BA4"),
3907
+ import_react3.default.createElement("option", { value: "off" }, "\u4E0D\u652F\u6301\u601D\u8003"),
3908
+ import_react3.default.createElement("option", { value: "custom" }, "\u81EA\u5B9A\u4E49\u6863\u4F4D")
3909
+ ),
3910
+ m.effortsMode === "custom" ? DKM_PI_LEVELS.map((lv) => import_react3.default.createElement(
3911
+ "label",
3912
+ { key: lv, className: "dkm-check" },
3913
+ import_react3.default.createElement("input", {
3914
+ type: "checkbox",
3915
+ checked: !!m.effortLevels[lv],
3916
+ onChange: () => {
3917
+ const nl = Object.assign({}, m.effortLevels);
3918
+ nl[lv] = !nl[lv];
3919
+ onPatch(i, { effortLevels: nl });
3920
+ }
3921
+ }),
3922
+ DKM_EFFORT_NAMES[lv] || lv
3923
+ )) : null,
3924
+ import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u52FE\u9009\u5168\u90E8\u5F3A\u5EA6\u6863\uFF08\u5207\u4E3A\u81EA\u5B9A\u4E49\uFF09", onClick: () => onPatch(i, dkmAllLevels(true)) }, "\u5168\u9009"),
3925
+ import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u53D6\u6D88\u5168\u90E8\u5F3A\u5EA6\u6863", onClick: () => onPatch(i, dkmAllLevels(false)) }, "\u53D6\u6D88\u5168\u9009")
3926
+ )
3927
+ )
3928
+ );
3929
+ }
3930
+ function ModelsView(props) {
3773
3931
  const snap = useModels();
3774
3932
  const data = snap.data;
3775
3933
  const providers = data && Array.isArray(data.providers) ? data.providers : [];
3934
+ const params = props && props.params;
3776
3935
  const [selId, setSelId] = import_react3.default.useState(null);
3777
3936
  const [draft, setDraft] = import_react3.default.useState(null);
3778
3937
  const [builtKey, setBuiltKey] = import_react3.default.useState(null);
@@ -3785,6 +3944,8 @@ function ModelsView() {
3785
3944
  const [vpSaving, setVpSaving] = import_react3.default.useState(false);
3786
3945
  const [vpMsg, setVpMsg] = import_react3.default.useState(null);
3787
3946
  const [vpDirectExpanded, setVpDirectExpanded] = import_react3.default.useState(false);
3947
+ const [page, setPage] = import_react3.default.useState("settings");
3948
+ const [pageOpenCreate, setPageOpenCreate] = import_react3.default.useState(false);
3788
3949
  import_react3.default.useEffect(() => {
3789
3950
  modelsStore.load();
3790
3951
  }, []);
@@ -3809,7 +3970,7 @@ function ModelsView() {
3809
3970
  const saveVp = () => {
3810
3971
  if (!vpDraft || vpSaving) return;
3811
3972
  setVpSaving(true);
3812
- fetch("/dsh-dock/models", {
3973
+ fetch("dsh-dock/models", {
3813
3974
  method: "POST",
3814
3975
  headers: { "content-type": "application/json" },
3815
3976
  body: JSON.stringify({ visionProxy: vpDraft, revisions: data && data.revisions || {} }),
@@ -3847,6 +4008,13 @@ function ModelsView() {
3847
4008
  setSelId(id);
3848
4009
  setMsg(null);
3849
4010
  };
4011
+ import_react3.default.useEffect(() => {
4012
+ if (params && params.page === "providers") setPage("providers");
4013
+ if (params && params.openProviderForm) {
4014
+ setPage("providers");
4015
+ setPageOpenCreate(true);
4016
+ }
4017
+ }, []);
3850
4018
  const save = () => {
3851
4019
  if (!draft || !cur || !dirty || saving) return;
3852
4020
  const models = draft.models.map((m) => ({
@@ -3866,7 +4034,7 @@ function ModelsView() {
3866
4034
  payload.defaultEffort = draft.defaultEffort;
3867
4035
  }
3868
4036
  setSaving(true);
3869
- fetch("/dsh-dock/models", {
4037
+ fetch("dsh-dock/models", {
3870
4038
  method: "POST",
3871
4039
  headers: { "content-type": "application/json" },
3872
4040
  body: JSON.stringify(payload),
@@ -3880,98 +4048,28 @@ function ModelsView() {
3880
4048
  }
3881
4049
  }).catch((e) => setMsg({ ok: false, text: e && e.message || String(e) })).then(() => setSaving(false));
3882
4050
  };
3883
- const modelRow = (m, i) => import_react3.default.createElement(
3884
- "div",
3885
- { key: i, className: "dkm-model" },
3886
- import_react3.default.createElement(
3887
- "div",
3888
- { className: "dkm-model-head" },
3889
- import_react3.default.createElement("span", { className: "dkm-model-idx" }, "#" + (i + 1)),
3890
- import_react3.default.createElement("button", {
3891
- type: "button",
3892
- className: "dkm-del",
3893
- onClick: () => patchDraft({ models: draft.models.filter((_, j) => j !== i) })
3894
- }, "\u5220\u9664")
3895
- ),
3896
- import_react3.default.createElement(
3897
- "div",
3898
- { className: "dkm-grid" },
3899
- import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u6A21\u578B id\uFF08\u5FC5\u586B\uFF0C\u5982 deepseek-v4-pro\uFF09", value: m.id, onChange: (e) => patchModel(i, { id: e.target.value }) }),
3900
- import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u663E\u793A\u540D\u79F0\uFF08\u53EF\u9009\uFF09", value: m.name, onChange: (e) => patchModel(i, { name: e.target.value }) }),
3901
- import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u4E0A\u4E0B\u6587\u7A97\u53E3", inputMode: "numeric", value: m.contextWindow, onChange: (e) => patchModel(i, { contextWindow: e.target.value }) }),
3902
- import_react3.default.createElement("input", { className: "dkm-input", placeholder: "\u6700\u5927\u8F93\u51FA", inputMode: "numeric", value: m.maxTokens, onChange: (e) => patchModel(i, { maxTokens: e.target.value }) })
3903
- ),
3904
- import_react3.default.createElement(
3905
- "div",
3906
- { className: "dkm-checks" },
3907
- import_react3.default.createElement("span", { className: "dkm-label" }, "\u8F93\u5165\u7C7B\u578B\uFF1A"),
3908
- DKM_MODALITIES.map(([v, label]) => import_react3.default.createElement(
3909
- "label",
3910
- {
3911
- key: v,
3912
- className: "dkm-check",
3913
- title: v === "image" ? "\u7531\u4F60\u58F0\u660E\u8BE5\u7AEF\u70B9\u652F\u6301\u56FE\u7247\uFF1A\u4FDD\u5B58\u540E\u539F\u56FE\u76F4\u53D1\uFF0C\u5E76\u53EF\u4F5C\u4E3A\u89C6\u89C9\u6A21\u578B\u5019\u9009\u3002\u7CFB\u7EDF\u4E0D\u4F1A\u66FF\u4F60\u731C\u6D4B\uFF1B\u7AEF\u70B9\u5B9E\u9645\u4E0D\u652F\u6301\u65F6\u53D6\u6D88\u52FE\u9009\u5373\u53EF\u6062\u590D\u8D70\u56FE\u7247\u7406\u89E3\u4EE3\u7406" : null
3914
- },
3915
- import_react3.default.createElement("input", {
3916
- type: "checkbox",
3917
- checked: m.input.indexOf(v) >= 0,
3918
- onChange: () => {
3919
- const next = toggleIn(m.input, v);
3920
- patchModel(i, { input: next.length > 0 ? next : ["text"] });
3921
- }
3922
- }),
3923
- label
3924
- )),
3925
- import_react3.default.createElement("span", { className: "dkm-label dkm-tag", title: "\u6807\u6CE8\u4EC5\u5728\u672C\u9762\u677F\u5C55\u793A\u4E0E\u6301\u4E45\u5316\uFF0C\u4E0D\u53C2\u4E0E\u8BF7\u6C42\u8DEF\u7531\uFF08\u5B98\u65B9 schema \u53EA\u63A5\u53D7\u6587\u672C/\u56FE\u7247\uFF09" }, "\u6807\u6CE8\uFF1A"),
3926
- DKM_TAGS.map(([v, label]) => import_react3.default.createElement(
3927
- "label",
3928
- { key: v, className: "dkm-check dkm-tag" },
3929
- import_react3.default.createElement("input", { type: "checkbox", checked: m.tags.indexOf(v) >= 0, onChange: () => patchModel(i, { tags: toggleIn(m.tags, v) }) }),
3930
- label
3931
- )),
3932
- import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u52FE\u9009\u5168\u90E8\u8F93\u5165\u7C7B\u578B\u4E0E\u6807\u6CE8", onClick: () => patchModel(i, allInputs(true)) }, "\u5168\u9009"),
3933
- import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u53D6\u6D88\u5168\u90E8\u52FE\u9009\uFF08\u8F93\u5165\u7559\u7A7A = \u7EE7\u627F\u76EE\u5F55\u9ED8\u8BA4\uFF09", onClick: () => patchModel(i, allInputs(false)) }, "\u53D6\u6D88\u5168\u9009")
3934
- ),
3935
- import_react3.default.createElement(
3936
- "div",
3937
- { className: "dkm-efforts" },
3938
- import_react3.default.createElement("span", { className: "dkm-label" }, "\u601D\u8003\u5F3A\u5EA6\uFF1A"),
3939
- cur.kind === "deepseek" ? import_react3.default.createElement("span", { className: "dkm-sub" }, "\u968F Provider \u8BBE\u7F6E\uFF08Off/Low/High/Max\uFF0C\u5168\u6A21\u578B\u5171\u4EAB\uFF09") : import_react3.default.createElement(
3940
- "span",
3941
- null,
3942
- import_react3.default.createElement(
3943
- "select",
3944
- {
3945
- className: "dkm-select",
3946
- value: m.effortsMode,
3947
- onChange: (e) => patchModel(i, {
3948
- effortsMode: e.target.value,
3949
- effortLevels: e.target.value === "custom" && m.effortsMode !== "custom" ? { off: true, low: true, high: true } : m.effortLevels
3950
- })
3951
- },
3952
- import_react3.default.createElement("option", { value: "inherit" }, "\u8DDF\u968F\u76EE\u5F55\u9ED8\u8BA4"),
3953
- import_react3.default.createElement("option", { value: "off" }, "\u4E0D\u652F\u6301\u601D\u8003"),
3954
- import_react3.default.createElement("option", { value: "custom" }, "\u81EA\u5B9A\u4E49\u6863\u4F4D")
3955
- ),
3956
- m.effortsMode === "custom" ? DKM_PI_LEVELS.map((lv) => import_react3.default.createElement(
3957
- "label",
3958
- { key: lv, className: "dkm-check" },
3959
- import_react3.default.createElement("input", {
3960
- type: "checkbox",
3961
- checked: !!m.effortLevels[lv],
3962
- onChange: () => {
3963
- const nl = Object.assign({}, m.effortLevels);
3964
- nl[lv] = !nl[lv];
3965
- patchModel(i, { effortLevels: nl });
3966
- }
3967
- }),
3968
- DKM_EFFORT_NAMES[lv] || lv
3969
- )) : null,
3970
- import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u52FE\u9009\u5168\u90E8\u5F3A\u5EA6\u6863\uFF08\u5207\u4E3A\u81EA\u5B9A\u4E49\uFF09", onClick: () => patchModel(i, allLevels(true)) }, "\u5168\u9009"),
3971
- import_react3.default.createElement("button", { type: "button", className: "dkm-mini", title: "\u4E00\u952E\u53D6\u6D88\u5168\u90E8\u5F3A\u5EA6\u6863", onClick: () => patchModel(i, allLevels(false)) }, "\u53D6\u6D88\u5168\u9009")
3972
- )
3973
- )
3974
- );
4051
+ const modelRow = (m, i) => ModelRow({
4052
+ m,
4053
+ i,
4054
+ kind: cur.kind,
4055
+ onPatch: (j, patch) => patchModel(j, patch),
4056
+ onDel: (j) => patchDraft({ models: draft.models.filter((_, k) => k !== j) })
4057
+ });
4058
+ if (page === "providers") {
4059
+ return import_react3.default.createElement(ProvidersPage, {
4060
+ data,
4061
+ providers,
4062
+ loading: snap.loading,
4063
+ error: snap.error,
4064
+ openCreate: pageOpenCreate,
4065
+ onCreateHandled: () => setPageOpenCreate(false),
4066
+ // 返回主页时顺手重读目录:子页面里增删改过的 Provider 立即反映到模型编辑器
4067
+ onBack: () => {
4068
+ setPage("settings");
4069
+ refreshModels();
4070
+ }
4071
+ });
4072
+ }
3975
4073
  const body = [];
3976
4074
  if (data) {
3977
4075
  body.push(import_react3.default.createElement(
@@ -4111,6 +4209,44 @@ function ModelsView() {
4111
4209
  )
4112
4210
  ));
4113
4211
  }
4212
+ if (data) {
4213
+ const custom = providers.filter((p) => p.kind === "pi-ai");
4214
+ const missingKey = custom.filter((p) => p.apiKeyEnv && !p.apiKeyConfigured).length;
4215
+ body.push(import_react3.default.createElement(
4216
+ "div",
4217
+ { key: "pf-entry", className: "dkp-card" },
4218
+ import_react3.default.createElement(
4219
+ "div",
4220
+ { className: "dkp-rowhead" },
4221
+ import_react3.default.createElement(
4222
+ "span",
4223
+ { className: "dkp-identity" },
4224
+ import_react3.default.createElement("span", { className: "dkp-name" }, "\u6A21\u578B\u63D0\u4F9B\u5546"),
4225
+ import_react3.default.createElement("span", { className: "dkp-tag" }, custom.length + " \u4E2A\u81EA\u5B9A\u4E49\u8DEF\u7531"),
4226
+ custom.length > 0 ? import_react3.default.createElement("span", {
4227
+ className: "dkp-dot " + (missingKey > 0 ? "warn" : "ok"),
4228
+ role: "img",
4229
+ title: missingKey > 0 ? "\u6709 " + missingKey + " \u4E2A Provider \u672A\u914D\u7F6E\u5BC6\u94A5" : "\u5BC6\u94A5\u5747\u5DF2\u914D\u7F6E",
4230
+ "aria-label": missingKey > 0 ? "\u6709 Provider \u672A\u914D\u7F6E\u5BC6\u94A5" : "\u5BC6\u94A5\u5747\u5DF2\u914D\u7F6E"
4231
+ }) : null
4232
+ ),
4233
+ import_react3.default.createElement(
4234
+ "span",
4235
+ { className: "dkp-actions" },
4236
+ import_react3.default.createElement("button", {
4237
+ type: "button",
4238
+ className: "dkp-btn ghost sm",
4239
+ onClick: () => setPage("providers")
4240
+ }, "\u7BA1\u7406")
4241
+ )
4242
+ ),
4243
+ import_react3.default.createElement(
4244
+ "p",
4245
+ { className: "dkp-hint" },
4246
+ "\u65B0\u589E / \u7F16\u8F91 / \u5220\u9664\u81EA\u5B9A\u4E49\u6A21\u578B Provider\uFF08OpenAI \u517C\u5BB9\u3001Anthropic \u7B49\uFF09\uFF0C\u5199\u5165\u5B98\u65B9\u914D\u7F6E\u5E76\u70ED\u751F\u6548\uFF1BAPI Key \u5B58\u672C\u673A\u51ED\u636E\u5E93\uFF08\u6587\u4EF6\u4EC5 root \u53EF\u8BFB\uFF09\u3002"
4247
+ )
4248
+ ));
4249
+ }
4114
4250
  if (data && providers.length === 0) {
4115
4251
  body.push(import_react3.default.createElement("div", { key: "empty", className: "dkm-note" }, "\u6CA1\u6709\u53EF\u7F16\u8F91\u7684\u6A21\u578B Provider\uFF08Host \u4FA7\u5C1A\u672A\u914D\u7F6E\uFF09"));
4116
4252
  }
@@ -4187,6 +4323,532 @@ function ModelsView() {
4187
4323
  }
4188
4324
  return import_react3.default.createElement("div", { className: "dkm-list" }, body);
4189
4325
  }
4326
+ function ProviderModelRow(props) {
4327
+ const m = props.m;
4328
+ const i = props.i;
4329
+ const check = (v, list, kind) => import_react3.default.createElement(
4330
+ "label",
4331
+ { key: v[0], className: "dkp-check" },
4332
+ import_react3.default.createElement("input", {
4333
+ type: "checkbox",
4334
+ checked: list.indexOf(v[0]) >= 0,
4335
+ onChange: () => {
4336
+ const next = dkmToggleIn(list, v[0]);
4337
+ props.onPatch(i, kind === "input" ? { input: next.length > 0 ? next : ["text"] } : { tags: next });
4338
+ }
4339
+ }),
4340
+ v[1]
4341
+ );
4342
+ return import_react3.default.createElement(
4343
+ "div",
4344
+ { className: "dkp-model-entry" },
4345
+ import_react3.default.createElement(
4346
+ "div",
4347
+ { className: "dkp-model-row" },
4348
+ import_react3.default.createElement("input", { className: "dkp-input", placeholder: "\u6A21\u578B id\uFF08\u5FC5\u586B\uFF09", value: m.id, onChange: (e) => props.onPatch(i, { id: e.target.value }) }),
4349
+ import_react3.default.createElement("input", { className: "dkp-input", placeholder: "\u663E\u793A\u540D\u79F0\uFF08\u53EF\u9009\uFF09", value: m.name, onChange: (e) => props.onPatch(i, { name: e.target.value }) }),
4350
+ import_react3.default.createElement("input", { className: "dkp-input", placeholder: "\u4E0A\u4E0B\u6587\u7A97\u53E3", inputMode: "numeric", value: m.contextWindow, onChange: (e) => props.onPatch(i, { contextWindow: e.target.value }) }),
4351
+ import_react3.default.createElement("input", { className: "dkp-input", placeholder: "\u6700\u5927\u8F93\u51FA", inputMode: "numeric", value: m.maxTokens, onChange: (e) => props.onPatch(i, { maxTokens: e.target.value }) }),
4352
+ import_react3.default.createElement("button", { type: "button", className: "dkp-iconbtn danger", title: "\u5220\u9664\u8BE5\u6A21\u578B", "aria-label": "\u5220\u9664\u6A21\u578B", onClick: () => props.onDel(i) }, "\u2715")
4353
+ ),
4354
+ import_react3.default.createElement(
4355
+ "div",
4356
+ { className: "dkp-model-opts" },
4357
+ import_react3.default.createElement(
4358
+ "div",
4359
+ { className: "dkp-checks" },
4360
+ import_react3.default.createElement("span", { className: "dkp-flabel" }, "\u8F93\u5165\u7C7B\u578B\uFF1A"),
4361
+ DKM_MODALITIES.map((v) => check(v, m.input, "input")),
4362
+ import_react3.default.createElement("span", { className: "dkp-flabel dkp-dim", title: "\u6807\u6CE8\u4EC5\u5728\u672C\u9762\u677F\u5C55\u793A\u4E0E\u6301\u4E45\u5316\uFF0C\u4E0D\u53C2\u4E0E\u8BF7\u6C42\u8DEF\u7531\uFF08\u5B98\u65B9 schema \u53EA\u63A5\u53D7\u6587\u672C/\u56FE\u7247\uFF09" }, "\u6807\u6CE8\uFF1A"),
4363
+ DKM_TAGS.map((v) => check(v, m.tags, "tags")),
4364
+ import_react3.default.createElement("button", { type: "button", className: "dkp-mini", title: "\u4E00\u952E\u52FE\u9009\u5168\u90E8\u8F93\u5165\u7C7B\u578B\u4E0E\u6807\u6CE8", onClick: () => props.onPatch(i, dkmAllInputs(true)) }, "\u5168\u9009"),
4365
+ import_react3.default.createElement("button", { type: "button", className: "dkp-mini", title: "\u4E00\u952E\u53D6\u6D88\u5168\u90E8\u52FE\u9009", onClick: () => props.onPatch(i, dkmAllInputs(false)) }, "\u53D6\u6D88\u5168\u9009")
4366
+ ),
4367
+ import_react3.default.createElement(
4368
+ "div",
4369
+ { className: "dkp-checks" },
4370
+ import_react3.default.createElement("span", { className: "dkp-flabel" }, "\u601D\u8003\u5F3A\u5EA6\uFF1A"),
4371
+ import_react3.default.createElement(
4372
+ "select",
4373
+ {
4374
+ className: "dkp-input dkp-select dkp-select-sm",
4375
+ value: m.effortsMode,
4376
+ onChange: (e) => props.onPatch(i, {
4377
+ effortsMode: e.target.value,
4378
+ effortLevels: e.target.value === "custom" && m.effortsMode !== "custom" ? { off: true, low: true, high: true } : m.effortLevels
4379
+ })
4380
+ },
4381
+ import_react3.default.createElement("option", { value: "inherit" }, "\u8DDF\u968F\u76EE\u5F55\u9ED8\u8BA4"),
4382
+ import_react3.default.createElement("option", { value: "off" }, "\u4E0D\u652F\u6301\u601D\u8003"),
4383
+ import_react3.default.createElement("option", { value: "custom" }, "\u81EA\u5B9A\u4E49\u6863\u4F4D")
4384
+ ),
4385
+ m.effortsMode === "custom" ? DKM_PI_LEVELS.map((lv) => import_react3.default.createElement(
4386
+ "label",
4387
+ { key: lv, className: "dkp-check" },
4388
+ import_react3.default.createElement("input", {
4389
+ type: "checkbox",
4390
+ checked: !!m.effortLevels[lv],
4391
+ onChange: () => {
4392
+ const nl = Object.assign({}, m.effortLevels);
4393
+ nl[lv] = !nl[lv];
4394
+ props.onPatch(i, { effortLevels: nl });
4395
+ }
4396
+ }),
4397
+ DKM_EFFORT_NAMES[lv] || lv
4398
+ )) : null,
4399
+ import_react3.default.createElement("button", { type: "button", className: "dkp-mini", title: "\u4E00\u952E\u52FE\u9009\u5168\u90E8\u5F3A\u5EA6\u6863\uFF08\u5207\u4E3A\u81EA\u5B9A\u4E49\uFF09", onClick: () => props.onPatch(i, dkmAllLevels(true)) }, "\u5168\u9009"),
4400
+ import_react3.default.createElement("button", { type: "button", className: "dkp-mini", title: "\u4E00\u952E\u53D6\u6D88\u5168\u90E8\u5F3A\u5EA6\u6863", onClick: () => props.onPatch(i, dkmAllLevels(false)) }, "\u53D6\u6D88\u5168\u9009")
4401
+ )
4402
+ )
4403
+ );
4404
+ }
4405
+ function ProvidersPage(props) {
4406
+ const data = props.data;
4407
+ const providers = props.providers || [];
4408
+ const piProviders = providers.filter((p) => p.kind === "pi-ai");
4409
+ const [pfMode, setPfMode] = import_react3.default.useState(null);
4410
+ const [pfDraft, setPfDraft] = import_react3.default.useState(null);
4411
+ const [pfDirty, setPfDirty] = import_react3.default.useState(false);
4412
+ const [pfSaving, setPfSaving] = import_react3.default.useState(false);
4413
+ const [pfMsg, setPfMsg] = import_react3.default.useState(null);
4414
+ const [pfDelArm, setPfDelArm] = import_react3.default.useState(null);
4415
+ const [pfFetching, setPfFetching] = import_react3.default.useState(false);
4416
+ const [pfFetchedList, setPfFetchedList] = import_react3.default.useState(null);
4417
+ const openPfCreate = () => {
4418
+ setPfMode("create");
4419
+ setPfDraft(emptyProviderForm());
4420
+ setPfDirty(false);
4421
+ setPfMsg(null);
4422
+ setPfDelArm(null);
4423
+ setPfFetchedList(null);
4424
+ };
4425
+ const openPfEdit = (p) => {
4426
+ setPfMode("edit");
4427
+ setPfDraft(providerFormFromProvider(p));
4428
+ setPfDirty(false);
4429
+ setPfMsg(null);
4430
+ setPfDelArm(null);
4431
+ setPfFetchedList(null);
4432
+ };
4433
+ const closePf = () => {
4434
+ setPfMode(null);
4435
+ setPfDraft(null);
4436
+ setPfDirty(false);
4437
+ setPfMsg(null);
4438
+ setPfDelArm(null);
4439
+ setPfFetchedList(null);
4440
+ };
4441
+ const patchPf = (patch) => {
4442
+ setPfDraft(Object.assign({}, pfDraft, patch));
4443
+ setPfDirty(true);
4444
+ setPfMsg(null);
4445
+ };
4446
+ const patchPfModel = (i, patch) => {
4447
+ const models = pfDraft.models.slice();
4448
+ models[i] = Object.assign({}, models[i], patch);
4449
+ patchPf({ models });
4450
+ };
4451
+ const delPfModel = (i) => patchPf({ models: pfDraft.models.filter((_, j) => j !== i) });
4452
+ const addPfModel = () => patchPf({ models: pfDraft.models.concat([emptyModelDraft()]) });
4453
+ const togglePfModel = (id, name, on) => {
4454
+ const base = pfDraft.models.filter((m) => String(m.id || "").trim());
4455
+ if (on) {
4456
+ if (base.some((m) => String(m.id).trim() === id)) return;
4457
+ base.push(Object.assign(emptyModelDraft(), { id, name: name || "", input: pfDraft.defaultInput.slice() }));
4458
+ } else {
4459
+ const i = base.findIndex((m) => String(m.id).trim() === id);
4460
+ if (i >= 0) base.splice(i, 1);
4461
+ }
4462
+ patchPf({ models: base });
4463
+ };
4464
+ const setAllPfModels = (on) => {
4465
+ const base = [];
4466
+ if (on && pfFetchedList) {
4467
+ for (const mm of pfFetchedList) {
4468
+ const id = String(mm && mm.id || "").trim();
4469
+ if (!id) continue;
4470
+ base.push(Object.assign(emptyModelDraft(), { id, name: mm && mm.name || "", input: pfDraft.defaultInput.slice() }));
4471
+ }
4472
+ }
4473
+ patchPf({ models: base });
4474
+ };
4475
+ const pfSelectedCount = () => pfDraft ? pfDraft.models.filter((m) => String(m.id || "").trim()).length : 0;
4476
+ const pfModelsPayload = () => pfDraft.models.map((m) => ({
4477
+ id: String(m.id || "").trim(),
4478
+ name: String(m.name || "").trim(),
4479
+ contextWindow: m.contextWindow === "" || m.contextWindow == null ? void 0 : Number(m.contextWindow),
4480
+ maxTokens: m.maxTokens === "" || m.maxTokens == null ? void 0 : Number(m.maxTokens),
4481
+ input: m.input,
4482
+ tags: m.tags,
4483
+ effortsMode: m.effortsMode,
4484
+ effortLevels: m.effortLevels,
4485
+ raw: m.raw
4486
+ }));
4487
+ const fetchPfModels = () => {
4488
+ if (!pfDraft || pfFetching) return;
4489
+ setPfFetching(true);
4490
+ setPfMsg(null);
4491
+ fetch("dsh-dock/models", {
4492
+ method: "POST",
4493
+ headers: { "content-type": "application/json" },
4494
+ body: JSON.stringify({
4495
+ action: "listModels",
4496
+ baseURL: pfDraft.baseURL,
4497
+ api: pfDraft.api,
4498
+ apiKeyEnv: pfDraft.apiKeyEnv,
4499
+ apiKey: pfDraft.apiKey
4500
+ }),
4501
+ signal: AbortSignal.timeout(3e4)
4502
+ }).then((res) => res.json().then((b) => ({ status: res.status, body: b })).catch(() => ({ status: res.status, body: {} }))).then((r) => {
4503
+ if (r.status === 200 && r.body && r.body.ok) {
4504
+ setPfFetchedList(Array.isArray(r.body.models) ? r.body.models : []);
4505
+ } else {
4506
+ setPfMsg({ ok: false, text: r.body && r.body.error || "HTTP " + r.status });
4507
+ }
4508
+ }).catch((e) => setPfMsg({ ok: false, text: e && e.message || String(e) })).then(() => setPfFetching(false));
4509
+ };
4510
+ const savePf = () => {
4511
+ if (!pfDraft || pfSaving) return;
4512
+ const route = pfDraft.route.trim();
4513
+ const baseURL = pfDraft.baseURL.trim();
4514
+ const apiKey = pfDraft.apiKey.trim();
4515
+ let apiKeyEnv = pfDraft.apiKeyEnv.trim();
4516
+ if (apiKey && !apiKeyEnv) {
4517
+ apiKeyEnv = dkmEnvFromRoute(route);
4518
+ setPfDraft(Object.assign({}, pfDraft, { apiKeyEnv }));
4519
+ }
4520
+ const models = pfModelsPayload();
4521
+ if (!route) {
4522
+ setPfMsg({ ok: false, text: "\u8DEF\u7531 key \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u5982 modelscope\uFF09" });
4523
+ return;
4524
+ }
4525
+ if (!DKM_ROUTE_KEY_RE.test(route)) {
4526
+ setPfMsg({ ok: false, text: "\u8DEF\u7531 key \u975E\u6CD5\uFF1A\u53EA\u80FD\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u4E0E . _ -\uFF0C\u4E14\u4EE5\u5B57\u6BCD/\u6570\u5B57\u5F00\u5934" });
4527
+ return;
4528
+ }
4529
+ if (!/^https?:\/\//i.test(baseURL)) {
4530
+ setPfMsg({ ok: false, text: "baseURL \u987B\u4EE5 http:// \u6216 https:// \u5F00\u5934" });
4531
+ return;
4532
+ }
4533
+ const ids = models.map((m) => m.id);
4534
+ if (ids.length === 0 || ids.some((x) => !x)) {
4535
+ setPfMsg({ ok: false, text: "\u6BCF\u4E2A\u6A21\u578B\u90FD\u8981\u6709 id\uFF08\u53EF\u70B9\u300C\u83B7\u53D6\u6A21\u578B\u5217\u8868\u300D\u81EA\u52A8\u62C9\u53D6\uFF09" });
4536
+ return;
4537
+ }
4538
+ if (new Set(ids).size !== ids.length) {
4539
+ setPfMsg({ ok: false, text: "\u6A21\u578B id \u6709\u91CD\u590D" });
4540
+ return;
4541
+ }
4542
+ const profile = Object.assign({}, pfDraft.extra || {});
4543
+ const dn = pfDraft.displayName.trim();
4544
+ if (dn) profile.displayName = dn;
4545
+ else delete profile.displayName;
4546
+ profile.api = pfDraft.api;
4547
+ profile.baseURL = baseURL;
4548
+ if (apiKeyEnv) profile.apiKeyEnv = apiKeyEnv;
4549
+ else delete profile.apiKeyEnv;
4550
+ profile.defaultInput = pfDraft.defaultInput;
4551
+ profile.models = models;
4552
+ const payload = {
4553
+ action: pfMode === "create" ? "create" : "update",
4554
+ route,
4555
+ profile,
4556
+ revisions: data && data.revisions || {}
4557
+ };
4558
+ if (apiKey) payload.apiKey = apiKey;
4559
+ setPfSaving(true);
4560
+ setPfMsg(null);
4561
+ fetch("dsh-dock/models", {
4562
+ method: "POST",
4563
+ headers: { "content-type": "application/json" },
4564
+ body: JSON.stringify(payload),
4565
+ signal: AbortSignal.timeout(3e4)
4566
+ }).then((res) => res.json().then((b) => ({ status: res.status, body: b })).catch(() => ({ status: res.status, body: {} }))).then((r) => {
4567
+ if (r.status === 200 && r.body && r.body.ok) {
4568
+ setPfMsg({ ok: true, text: "Provider\u300C" + route + "\u300D\u5DF2" + (pfMode === "create" ? "\u65B0\u589E" : "\u66F4\u65B0") + "\uFF1B\u4F1A\u8BDD\u6A21\u578B\u9009\u62E9\u5668\u5373\u65F6\u53EF\u9009" });
4569
+ setPfMode(null);
4570
+ setPfDraft(null);
4571
+ setPfDirty(false);
4572
+ modelsStore.load();
4573
+ } else {
4574
+ setPfMsg({ ok: false, text: r.body && r.body.error || "HTTP " + r.status });
4575
+ }
4576
+ }).catch((e) => setPfMsg({ ok: false, text: e && e.message || String(e) })).then(() => setPfSaving(false));
4577
+ };
4578
+ const deletePf = (p) => {
4579
+ const route = p.route || p.id;
4580
+ if (pfDelArm !== route) {
4581
+ setPfDelArm(route);
4582
+ setPfMsg(null);
4583
+ return;
4584
+ }
4585
+ setPfDelArm(null);
4586
+ setPfSaving(true);
4587
+ setPfMsg(null);
4588
+ fetch("dsh-dock/models", {
4589
+ method: "POST",
4590
+ headers: { "content-type": "application/json" },
4591
+ body: JSON.stringify({ action: "delete", route, revisions: data && data.revisions || {} }),
4592
+ signal: AbortSignal.timeout(2e4)
4593
+ }).then((res) => res.json().then((b) => ({ status: res.status, body: b })).catch(() => ({ status: res.status, body: {} }))).then((r) => {
4594
+ if (r.status === 200 && r.body && r.body.ok) {
4595
+ setPfMsg({ ok: true, text: "Provider\u300C" + route + "\u300D\u5DF2\u5220\u9664" });
4596
+ if (pfMode === "edit" && pfDraft && pfDraft.route === route) {
4597
+ setPfMode(null);
4598
+ setPfDraft(null);
4599
+ }
4600
+ modelsStore.load();
4601
+ } else {
4602
+ setPfMsg({ ok: false, text: r.body && r.body.error || "HTTP " + r.status });
4603
+ }
4604
+ }).catch((e) => setPfMsg({ ok: false, text: e && e.message || String(e) })).then(() => setPfSaving(false));
4605
+ };
4606
+ const openedRef = import_react3.default.useRef(false);
4607
+ import_react3.default.useEffect(() => {
4608
+ if (props.openCreate && !openedRef.current) {
4609
+ openedRef.current = true;
4610
+ openPfCreate();
4611
+ if (typeof props.onCreateHandled === "function") props.onCreateHandled();
4612
+ }
4613
+ }, []);
4614
+ const input = (p) => import_react3.default.createElement("input", Object.assign({ className: "dkp-input" }, p));
4615
+ const field = (label, node, hint) => import_react3.default.createElement(
4616
+ "div",
4617
+ { className: "dkp-field", key: label },
4618
+ import_react3.default.createElement("label", { className: "dkp-flabel" }, label),
4619
+ node,
4620
+ hint ? import_react3.default.createElement("p", { className: "dkp-hint" }, hint) : null
4621
+ );
4622
+ const editor = !pfDraft ? null : import_react3.default.createElement(
4623
+ "div",
4624
+ { className: "dkp-editor" },
4625
+ import_react3.default.createElement(
4626
+ "div",
4627
+ { className: "dkp-editor-head" },
4628
+ import_react3.default.createElement("span", { className: "dkp-editor-title" }, pfMode === "create" ? "\u65B0\u589E Provider" : "\u7F16\u8F91 Provider"),
4629
+ pfMode === "edit" ? import_react3.default.createElement("span", { className: "dkp-editor-route" }, pfDraft.route) : null
4630
+ ),
4631
+ field("\u8DEF\u7531 key", input({
4632
+ value: pfDraft.route,
4633
+ disabled: pfMode === "edit",
4634
+ placeholder: "acme-gateway",
4635
+ onChange: (e) => patchPf({ route: e.target.value })
4636
+ }), pfMode === "edit" ? "\u8DEF\u7531 key \u662F\u914D\u7F6E\u952E\uFF0C\u4FDD\u5B58\u540E\u4E0D\u5EFA\u8BAE\u4FEE\u6539\u3002" : "\u552F\u4E00\u6807\u8BC6\uFF1A\u53EA\u80FD\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u4E0E . _ -\uFF0C\u4E14\u4EE5\u5B57\u6BCD/\u6570\u5B57\u5F00\u5934\u3002"),
4637
+ field("\u663E\u793A\u540D\u79F0", input({
4638
+ value: pfDraft.displayName,
4639
+ placeholder: pfDraft.route || "\u5982 \u9B54\u642D ModelScope",
4640
+ onChange: (e) => patchPf({ displayName: e.target.value })
4641
+ })),
4642
+ field("baseURL", input({
4643
+ value: pfDraft.baseURL,
4644
+ placeholder: pfDraft.api === "anthropic-messages" ? "https://gateway.example" : "https://gateway.example/v1",
4645
+ onChange: (e) => patchPf({ baseURL: e.target.value })
4646
+ }), "OpenAI \u517C\u5BB9\u7AEF\u70B9\u901A\u5E38\u4EE5 /v1 \u7ED3\u5C3E\uFF1BAnthropic Messages \u7531 SDK \u81EA\u884C\u8FFD\u52A0 /v1/messages\u3002"),
4647
+ field("API \u534F\u8BAE", import_react3.default.createElement(
4648
+ "select",
4649
+ {
4650
+ className: "dkp-input dkp-select",
4651
+ value: pfDraft.api,
4652
+ onChange: (e) => patchPf({ api: e.target.value })
4653
+ },
4654
+ DKM_APIS.map(([v, label]) => import_react3.default.createElement("option", { key: v, value: v }, label))
4655
+ )),
4656
+ field("API Key", import_react3.default.createElement("input", {
4657
+ className: "dkp-input",
4658
+ type: "password",
4659
+ autoComplete: "new-password",
4660
+ placeholder: pfMode === "edit" ? "\u7559\u7A7A = \u4E0D\u6539\u52A8\u5DF2\u5B58\u5BC6\u94A5" : "sk-\u2026\uFF08\u4EC5\u672C\u6B21\u5199\u5165\u672C\u673A\u51ED\u636E\u5E93\uFF0C\u4E0D\u56DE\u663E\uFF09",
4661
+ value: pfDraft.apiKey,
4662
+ onChange: (e) => patchPf({ apiKey: e.target.value })
4663
+ })),
4664
+ import_react3.default.createElement(
4665
+ "details",
4666
+ { className: "dkp-customized" },
4667
+ import_react3.default.createElement("summary", { className: "dkp-summary" }, "\u81EA\u5B9A\u4E49\u8BBE\u7F6E"),
4668
+ import_react3.default.createElement(
4669
+ "div",
4670
+ { className: "dkp-custombody" },
4671
+ field("apiKeyEnv", input({
4672
+ value: pfDraft.apiKeyEnv,
4673
+ placeholder: "\u7559\u7A7A = \u6309\u8DEF\u7531 key \u81EA\u52A8\u751F\u6210\uFF08" + (dkmEnvFromRoute(pfDraft.route) || "ROUTE_API_KEY") + "\uFF09",
4674
+ onChange: (e) => patchPf({ apiKeyEnv: e.target.value })
4675
+ }), "\u51ED\u636E\u5E93\u6761\u76EE\u540D\uFF1B\u7559\u7A7A\u65F6\u6309\u8DEF\u7531 key \u63A8\u5BFC\uFF0C\u4E00\u822C\u65E0\u9700\u586B\u5199\u3002"),
4676
+ import_react3.default.createElement(
4677
+ "div",
4678
+ { className: "dkp-field" },
4679
+ import_react3.default.createElement("span", { className: "dkp-flabel" }, "\u9ED8\u8BA4\u8F93\u5165\u7C7B\u578B"),
4680
+ import_react3.default.createElement(
4681
+ "div",
4682
+ { className: "dkp-checks" },
4683
+ DKM_MODALITIES.map(([v, label]) => import_react3.default.createElement(
4684
+ "label",
4685
+ { key: v, className: "dkp-check" },
4686
+ import_react3.default.createElement("input", {
4687
+ type: "checkbox",
4688
+ checked: pfDraft.defaultInput.indexOf(v) >= 0,
4689
+ onChange: () => {
4690
+ const next = dkmToggleIn(pfDraft.defaultInput, v);
4691
+ patchPf({ defaultInput: next.length > 0 ? next : ["text"] });
4692
+ }
4693
+ }),
4694
+ label
4695
+ )),
4696
+ import_react3.default.createElement("span", { className: "dkp-hint" }, "\u6A21\u578B\u672A\u5355\u72EC\u58F0\u660E\u8F93\u5165\u7C7B\u578B\u65F6\u7EE7\u627F\u8FD9\u91CC\u3002")
4697
+ )
4698
+ )
4699
+ )
4700
+ ),
4701
+ import_react3.default.createElement(
4702
+ "section",
4703
+ { className: "dkp-catalog", "aria-label": "\u6A21\u578B" },
4704
+ import_react3.default.createElement(
4705
+ "div",
4706
+ { className: "dkp-catalog-head" },
4707
+ import_react3.default.createElement(
4708
+ "div",
4709
+ { className: "dkp-catalog-titlewrap" },
4710
+ import_react3.default.createElement("span", { className: "dkp-catalog-title" }, "\u6A21\u578B"),
4711
+ import_react3.default.createElement(
4712
+ "span",
4713
+ { className: "dkp-catalog-meta" },
4714
+ "\u5DF2\u9009 " + pfSelectedCount() + " \u4E2A" + (pfFetchedList ? " / \u4E0A\u6E38\u5171 " + pfFetchedList.length + " \u4E2A" : "")
4715
+ )
4716
+ ),
4717
+ import_react3.default.createElement(
4718
+ "div",
4719
+ { className: "dkp-actions" },
4720
+ import_react3.default.createElement("button", {
4721
+ type: "button",
4722
+ className: "dkp-btn ghost sm",
4723
+ disabled: pfFetching || !pfDraft.baseURL,
4724
+ title: "\u8C03\u7528 baseURL/models \u62C9\u53D6\u8BE5\u7AEF\u70B9\u53EF\u7528\u6A21\u578B\uFF0C\u52FE\u9009\u540E\u52A0\u5165\u4E0B\u65B9\u5217\u8868",
4725
+ onClick: fetchPfModels
4726
+ }, pfFetching ? "\u62C9\u53D6\u4E2D\u2026" : "\u83B7\u53D6\u6A21\u578B\u5217\u8868"),
4727
+ pfFetchedList && pfFetchedList.length > 0 ? import_react3.default.createElement("button", { type: "button", className: "dkp-btn ghost sm", title: "\u52FE\u9009\u4E0A\u6E38\u8FD4\u56DE\u7684\u5168\u90E8\u6A21\u578B", onClick: () => setAllPfModels(true) }, "\u5168\u9009") : null,
4728
+ pfFetchedList && pfFetchedList.length > 0 ? import_react3.default.createElement("button", { type: "button", className: "dkp-btn ghost sm", title: "\u6E05\u7A7A\u5DF2\u52FE\u9009\u7684\u6A21\u578B", onClick: () => setAllPfModels(false) }, "\u6E05\u7A7A") : null
4729
+ )
4730
+ ),
4731
+ pfFetchedList ? import_react3.default.createElement(
4732
+ "div",
4733
+ { className: "dkp-picker" },
4734
+ pfFetchedList.length === 0 ? import_react3.default.createElement("div", { className: "dkp-hint" }, "\u4E0A\u6E38\u6CA1\u6709\u8FD4\u56DE\u4EFB\u4F55\u6A21\u578B") : pfFetchedList.map((mm) => {
4735
+ const id = String(mm && mm.id || "").trim();
4736
+ if (!id) return null;
4737
+ const checked = pfDraft.models.some((m) => String(m.id || "").trim() === id);
4738
+ return import_react3.default.createElement(
4739
+ "label",
4740
+ { key: id },
4741
+ import_react3.default.createElement("input", {
4742
+ type: "checkbox",
4743
+ checked,
4744
+ onChange: () => togglePfModel(id, mm && mm.name || "", !checked)
4745
+ }),
4746
+ import_react3.default.createElement("span", { className: "dkp-picker-id" }, id),
4747
+ mm && mm.name ? import_react3.default.createElement("span", { className: "dkp-picker-name" }, mm.name) : null
4748
+ );
4749
+ })
4750
+ ) : null,
4751
+ pfDraft.models.length === 0 ? import_react3.default.createElement("div", { className: "dkp-empty" }, "\u8FD8\u6CA1\u6709\u6A21\u578B\u2014\u2014\u70B9\u300C\u83B7\u53D6\u6A21\u578B\u5217\u8868\u300D\u52FE\u9009\u4E0A\u6E38\u6A21\u578B\uFF0C\u6216\u300C\u6DFB\u52A0\u6A21\u578B\u300D\u624B\u52A8\u586B\u5199\u3002") : import_react3.default.createElement(
4752
+ "div",
4753
+ { className: "dkp-model-list" },
4754
+ pfDraft.models.map((m, i) => import_react3.default.createElement(ProviderModelRow, { key: i, m, i, onPatch: patchPfModel, onDel: delPfModel }))
4755
+ ),
4756
+ import_react3.default.createElement("button", { type: "button", className: "dkp-addmodel", onClick: addPfModel }, "\uFF0B \u6DFB\u52A0\u6A21\u578B")
4757
+ ),
4758
+ pfMsg && !pfMsg.ok ? import_react3.default.createElement("p", { className: "dkp-error" }, pfMsg.text) : null,
4759
+ import_react3.default.createElement(
4760
+ "div",
4761
+ { className: "dkp-editor-actions" },
4762
+ import_react3.default.createElement("span", { className: "dkp-hint" }, pfDirty ? "\u6709\u672A\u4FDD\u5B58\u7684\u4FEE\u6539" : ""),
4763
+ import_react3.default.createElement("button", { type: "button", className: "dkp-btn ghost", onClick: closePf }, "\u53D6\u6D88"),
4764
+ import_react3.default.createElement(
4765
+ "button",
4766
+ { type: "button", className: "dkp-btn primary", disabled: pfSaving, onClick: savePf },
4767
+ pfSaving ? "\u4FDD\u5B58\u4E2D\u2026" : pfMode === "create" ? "\u65B0\u589E Provider" : "\u4FDD\u5B58\u4FEE\u6539"
4768
+ )
4769
+ )
4770
+ );
4771
+ const body = [
4772
+ import_react3.default.createElement("button", { key: "back", type: "button", className: "dkp-back", onClick: props.onBack }, "\u2190 \u6A21\u578B\u8BBE\u7F6E"),
4773
+ import_react3.default.createElement("h2", { key: "title", className: "dkp-title" }, "\u6A21\u578B\u63D0\u4F9B\u5546"),
4774
+ import_react3.default.createElement(
4775
+ "p",
4776
+ { key: "intro", className: "dkp-intro" },
4777
+ "\u65B0\u589E / \u7F16\u8F91 / \u5220\u9664\u81EA\u5B9A\u4E49\u6A21\u578B Provider\uFF08OpenAI \u517C\u5BB9\u3001Anthropic \u7B49\uFF09\uFF0C\u5199\u5165\u5B98\u65B9\u914D\u7F6E\u5E76\u70ED\u751F\u6548\uFF1BAPI Key \u5B58\u672C\u673A\u51ED\u636E\u5E93\uFF08\u6587\u4EF6\u4EC5 root \u53EF\u8BFB\uFF09\u3002\u5185\u7F6E DeepSeek \u5B98\u65B9 Provider \u5728\u672C\u9875\u53EA\u8BFB\uFF0C\u5176\u6A21\u578B\u76EE\u5F55\u8BF7\u56DE\u300C\u6A21\u578B\u8BBE\u7F6E\u300D\u7F16\u8F91\u3002"
4778
+ )
4779
+ ];
4780
+ if (props.error) {
4781
+ body.push(import_react3.default.createElement("p", { key: "err", className: "dkp-error" }, "\u6A21\u578B\u76EE\u5F55\u62C9\u53D6\u5931\u8D25\uFF1A" + props.error));
4782
+ }
4783
+ if (pfMsg && !pfDraft) {
4784
+ body.push(import_react3.default.createElement("p", { key: "msg", className: "dkp-msg " + (pfMsg.ok ? "ok" : "err"), role: "status" }, pfMsg.text));
4785
+ }
4786
+ if (!data) {
4787
+ body.push(import_react3.default.createElement("p", { key: "loading", className: "dkp-hint" }, props.loading ? "\u6B63\u5728\u62C9\u53D6\u6A21\u578B\u76EE\u5F55\u2026" : "\u7B49\u5F85\u62C9\u53D6\u6A21\u578B\u76EE\u5F55"));
4788
+ } else if (piProviders.length === 0) {
4789
+ body.push(import_react3.default.createElement("div", { key: "empty", className: "dkp-empty" }, "\u8FD8\u6CA1\u6709\u81EA\u5B9A\u4E49 Provider\u2014\u2014\u70B9\u4E0B\u65B9\u300C\u65B0\u589E Provider\u300D\u6DFB\u52A0\u3002"));
4790
+ } else {
4791
+ body.push(import_react3.default.createElement(
4792
+ "ul",
4793
+ { key: "rows", className: "dkp-rows" },
4794
+ piProviders.map((p) => {
4795
+ const route = p.route || p.id;
4796
+ const editing = pfMode === "edit" && !!pfDraft && pfDraft.route === route;
4797
+ const keyMissing = !!(p.apiKeyEnv && !p.apiKeyConfigured);
4798
+ return import_react3.default.createElement(
4799
+ "li",
4800
+ { key: p.id, className: "dkp-card" },
4801
+ import_react3.default.createElement(
4802
+ "div",
4803
+ { className: "dkp-rowhead" },
4804
+ import_react3.default.createElement(
4805
+ "span",
4806
+ { className: "dkp-identity" },
4807
+ import_react3.default.createElement("span", { className: "dkp-name" }, p.displayName || route),
4808
+ import_react3.default.createElement("span", { className: "dkp-tag" }, route),
4809
+ import_react3.default.createElement("span", { className: "dkp-tag" }, (p.models ? p.models.length : 0) + " \u6A21\u578B"),
4810
+ import_react3.default.createElement("span", {
4811
+ className: "dkp-dot " + (keyMissing ? "missing" : "ok"),
4812
+ role: "img",
4813
+ title: p.apiKeyEnv ? p.apiKeyConfigured ? p.apiKeyEnv + " \u5DF2\u914D\u7F6E" : p.apiKeyEnv + " \u672A\u914D\u7F6E" : "\u672A\u8BBE apiKeyEnv",
4814
+ "aria-label": p.apiKeyEnv ? p.apiKeyConfigured ? "\u5BC6\u94A5\u5DF2\u914D\u7F6E" : "\u5BC6\u94A5\u672A\u914D\u7F6E" : "\u672A\u8BBE apiKeyEnv"
4815
+ }),
4816
+ p.apiKeyEnv ? import_react3.default.createElement(
4817
+ "span",
4818
+ { className: "dkp-tag" + (keyMissing ? " warn" : " ok") },
4819
+ p.apiKeyConfigured ? p.apiKeyEnv + " \u5DF2\u914D\u7F6E" : p.apiKeyEnv + " \u672A\u914D\u7F6E"
4820
+ ) : null
4821
+ ),
4822
+ import_react3.default.createElement(
4823
+ "span",
4824
+ { className: "dkp-actions" },
4825
+ import_react3.default.createElement("button", {
4826
+ type: "button",
4827
+ className: "dkp-btn ghost sm",
4828
+ "aria-expanded": editing,
4829
+ onClick: () => editing ? closePf() : openPfEdit(p)
4830
+ }, editing ? "\u6536\u8D77" : "\u7F16\u8F91"),
4831
+ import_react3.default.createElement("button", {
4832
+ type: "button",
4833
+ className: "dkp-btn danger sm" + (pfDelArm === route ? " arm" : ""),
4834
+ title: pfDelArm === route ? "\u518D\u70B9\u4E00\u6B21\u786E\u8BA4\u5220\u9664" : "\u5220\u9664\u8BE5 Provider",
4835
+ onClick: () => deletePf(p)
4836
+ }, pfDelArm === route ? "\u786E\u8BA4\u5220\u9664\uFF1F" : "\u5220\u9664")
4837
+ )
4838
+ ),
4839
+ import_react3.default.createElement("div", { className: "dkp-sub" }, [p.api, p.baseURL].filter(Boolean).join(" \xB7 ")),
4840
+ editing ? editor : null
4841
+ );
4842
+ })
4843
+ ));
4844
+ }
4845
+ body.push(import_react3.default.createElement(
4846
+ "div",
4847
+ { key: "add", className: "dkp-addblock" },
4848
+ pfMode === "create" && pfDraft ? import_react3.default.createElement("div", { className: "dkp-card dkp-addcard" }, editor) : import_react3.default.createElement("button", { type: "button", className: "dkp-addbtn", onClick: openPfCreate }, "\uFF0B \u65B0\u589E Provider")
4849
+ ));
4850
+ return import_react3.default.createElement("div", { className: "dkp-page" }, body);
4851
+ }
4190
4852
  function ModelsStat() {
4191
4853
  const snap = useModels();
4192
4854
  const data = snap.data;
@@ -4201,7 +4863,7 @@ var feature2 = {
4201
4863
  name: "\u6A21\u578B\u8BBE\u7F6E",
4202
4864
  order: 100,
4203
4865
  accent: "#22d3ee",
4204
- description: "\u7F16\u8F91\u5404 Provider \u6A21\u578B\u76EE\u5F55\uFF1A\u8F93\u5165\u7C7B\u578B\uFF08\u6587\u672C/\u56FE\u7247 + \u6807\u6CE8\uFF09\u4E0E\u601D\u8003\u5F3A\u5EA6\u6863\u4F4D\uFF1B\u5199\u56DE\u5B98\u65B9\u914D\u7F6E\u70ED\u751F\u6548\uFF0C\u4F1A\u8BDD\u6A21\u578B\u9009\u62E9\u5668\u5373\u65F6\u53EF\u9009",
4866
+ description: "\u7F16\u8F91\u5404 Provider \u6A21\u578B\u76EE\u5F55\uFF08\u8F93\u5165\u7C7B\u578B/\u601D\u8003\u5F3A\u5EA6\u6863\u4F4D\uFF09\uFF1B\u81EA\u5B9A\u4E49 Provider \u7684\u589E\u5220\u6539\u5728\u300C\u6A21\u578B\u63D0\u4F9B\u5546\u300D\u5B50\u9875\u9762\uFF0C\u5199\u56DE\u5B98\u65B9\u914D\u7F6E\u70ED\u751F\u6548\uFF0C\u4F1A\u8BDD\u6A21\u578B\u9009\u62E9\u5668\u5373\u65F6\u53EF\u9009",
4205
4867
  css: [
4206
4868
  ".dkm-note{color:var(--dsw-alias-label-secondary);font-size:12px;}",
4207
4869
  ".dkm-warn{color:var(--dk-warn);}",
@@ -4246,7 +4908,99 @@ var feature2 = {
4246
4908
  ".dkm-mini{cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-family:inherit;font-size:11px;flex:none;}",
4247
4909
  ".dkm-mini:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary);}",
4248
4910
  ".dkm-toolbar{display:flex;align-items:center;gap:6px;flex-wrap:wrap;border-top:1px dashed var(--dsw-alias-border-l1);padding-top:8px;}",
4249
- ".dkm-toolbar-label{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none;}"
4911
+ ".dkm-toolbar-label{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none;}",
4912
+ // ---- 模型提供商子页面(dkp- 前缀):对齐官方「模型」设置页的排版与尺寸 ----
4913
+ // 官方用量参考:section 限宽 720、行卡片 .5px 描边 + radius-xl + 12/14 内距、
4914
+ // 输入高 32、按钮高 36(行内小按钮 28)、新增按钮 44 虚线、编辑器 bg-module-platform。
4915
+ ".dkp-page{width:100%;max-width:720px;display:flex;flex-direction:column;gap:12px;color:var(--dsw-alias-label-primary);}",
4916
+ ".dkp-back{box-sizing:border-box;align-self:flex-start;cursor:pointer;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);border-radius:var(--dsw-radius-sm,6px);padding:4px 8px;margin-left:-8px;font-family:inherit;font-size:12px;line-height:18px;}",
4917
+ ".dkp-back:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
4918
+ ".dkp-title{margin:0;font-size:16px;font-weight:500;line-height:24px;}",
4919
+ ".dkp-intro{margin:0;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px;}",
4920
+ ".dkp-rows{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:8px;}",
4921
+ ".dkp-card{box-sizing:border-box;margin:0;border:.5px solid var(--dsw-alias-settings-card-stroke,var(--dsw-alias-border-l2));background:var(--dsw-alias-settings-card-fill,var(--dsw-alias-bg-layer-1));border-radius:var(--dsw-radius-xl,12px);padding:12px 14px;display:flex;flex-direction:column;gap:10px;}",
4922
+ ".dkp-rowhead{display:flex;align-items:center;gap:10px;flex-wrap:wrap;}",
4923
+ ".dkp-identity{display:inline-flex;align-items:center;gap:6px;min-width:0;flex-wrap:wrap;}",
4924
+ ".dkp-name{font-size:14px;font-weight:500;line-height:22px;}",
4925
+ ".dkp-tag{flex:none;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-xs,4px);color:var(--dsw-alias-label-secondary);padding:1px 6px;font-size:11px;line-height:16px;}",
4926
+ ".dkp-tag.ok{color:var(--dsw-alias-state-success-primary);border-color:currentColor;}",
4927
+ ".dkp-tag.warn{color:var(--dk-warn);border-color:currentColor;}",
4928
+ ".dkp-dot{box-sizing:border-box;flex:none;width:8px;height:8px;border-radius:50%;display:inline-block;}",
4929
+ ".dkp-dot.ok{background:var(--dsw-alias-state-success-primary);}",
4930
+ ".dkp-dot.missing{background:var(--dsw-alias-state-error-primary);}",
4931
+ ".dkp-dot.warn{background:var(--dk-warn);}",
4932
+ ".dkp-sub{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
4933
+ ".dkp-hint{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;}",
4934
+ ".dkp-dim{color:var(--dsw-alias-label-tertiary);}",
4935
+ ".dkp-error{margin:0;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px;}",
4936
+ ".dkp-msg{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;}",
4937
+ ".dkp-msg.ok{color:var(--dsw-alias-state-success-primary);}",
4938
+ ".dkp-msg.err{color:var(--dsw-alias-state-error-primary);}",
4939
+ ".dkp-actions{flex:none;margin-left:auto;display:inline-flex;align-items:center;gap:4px;}",
4940
+ ".dkp-btn{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:4px;height:36px;padding:0 14px;border:none;border-radius:var(--dsw-radius-md,8px);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;cursor:pointer;}",
4941
+ ".dkp-btn.ghost{border:.5px solid var(--dsw-alias-border-l3);}",
4942
+ ".dkp-btn.ghost:hover{background:var(--dsw-alias-interactive-bg-hover);}",
4943
+ ".dkp-btn.primary{background:var(--dsw-alias-button-primary-fill,var(--dk-accent));color:var(--dsw-alias-label-primary-foreground,#fff);}",
4944
+ ".dkp-btn.primary:hover{background:var(--dsw-alias-button-primary-hover,var(--dk-accent));}",
4945
+ ".dkp-btn.danger{color:var(--dsw-alias-state-error-primary);}",
4946
+ ".dkp-btn.danger:hover{background:var(--dsw-alias-interactive-bg-hover-danger,rgba(220,38,38,.1));}",
4947
+ ".dkp-btn.arm{color:var(--dsw-alias-state-error-primary);border-color:currentColor;}",
4948
+ ".dkp-btn.sm{height:28px;padding:0 10px;border-radius:var(--dsw-radius-sm,6px);font-size:12px;line-height:18px;}",
4949
+ ".dkp-btn[disabled]{opacity:.4;cursor:default;}",
4950
+ ".dkp-editor{border-radius:var(--dsw-radius-lg,10px);background:var(--dsw-alias-bg-module-platform,var(--dsw-alias-bg-layer-1));padding:14px 16px;display:flex;flex-direction:column;gap:14px;}",
4951
+ ".dkp-editor-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;}",
4952
+ ".dkp-editor-title{font-size:14px;font-weight:500;line-height:22px;}",
4953
+ ".dkp-editor-route{color:var(--dsw-alias-label-tertiary);font-family:var(--ds-font-family-code,ui-monospace,monospace);font-size:12px;line-height:18px;}",
4954
+ ".dkp-field{display:flex;flex-direction:column;gap:6px;min-width:0;}",
4955
+ ".dkp-flabel{display:inline-flex;align-items:center;gap:10px;color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;}",
4956
+ ".dkp-input{box-sizing:border-box;width:100%;height:32px;padding:0 10px;border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-l2));border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;}",
4957
+ ".dkp-input:focus{border-color:var(--dsw-alias-state-business-primary,var(--dk-accent));outline:none;}",
4958
+ ".dkp-input::placeholder{color:var(--dsw-alias-label-dimmed,var(--dsw-alias-label-tertiary));}",
4959
+ ".dkp-input:disabled{opacity:.6;cursor:default;}",
4960
+ "select.dkp-input{appearance:auto;cursor:pointer;max-width:240px;}",
4961
+ ".dkp-select-sm{height:28px;max-width:160px;font-size:12px;line-height:18px;}",
4962
+ ".dkp-checks{display:flex;align-items:center;gap:16px;flex-wrap:wrap;min-height:32px;}",
4963
+ ".dkp-check{display:inline-flex;align-items:center;gap:6px;cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;}",
4964
+ ".dkp-check input{accent-color:var(--dk-accent);margin:0;}",
4965
+ ".dkp-mini{cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-tertiary);padding:1px 8px;font-family:inherit;font-size:11px;line-height:16px;flex:none;}",
4966
+ ".dkp-mini:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary);}",
4967
+ ".dkp-customized{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:10px;}",
4968
+ ".dkp-summary{display:flex;align-items:center;gap:6px;width:fit-content;margin-left:-4px;padding:2px 4px;border-radius:var(--dsw-radius-sm,6px);list-style:none;cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;}",
4969
+ ".dkp-summary::-webkit-details-marker{display:none;}",
4970
+ '.dkp-summary::before{content:"";width:5px;height:5px;border-right:1.5px solid;border-bottom:1.5px solid;transform:rotate(-45deg);transition:transform .12s;}',
4971
+ ".dkp-customized[open]>.dkp-summary::before{transform:rotate(45deg);}",
4972
+ ".dkp-summary:hover{color:var(--dsw-alias-label-primary);}",
4973
+ ".dkp-custombody{display:flex;flex-direction:column;gap:12px;padding-top:12px;}",
4974
+ ".dkp-catalog{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px;display:flex;flex-direction:column;gap:10px;}",
4975
+ ".dkp-catalog-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;}",
4976
+ ".dkp-catalog-titlewrap{display:flex;flex-direction:column;gap:2px;}",
4977
+ ".dkp-catalog-title{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;}",
4978
+ ".dkp-catalog-meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;}",
4979
+ ".dkp-model-list{display:flex;flex-direction:column;gap:8px;}",
4980
+ ".dkp-model-entry{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-l2));border-radius:var(--dsw-radius-lg,10px);padding:6px;display:flex;flex-direction:column;gap:6px;}",
4981
+ ".dkp-model-row{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) minmax(0,.7fr) minmax(0,.7fr) auto;gap:6px;align-items:center;}",
4982
+ ".dkp-model-row .dkp-input{height:30px;padding:0 8px;font-size:13px;}",
4983
+ ".dkp-model-opts{display:flex;flex-direction:column;gap:4px;padding:2px 2px 0;}",
4984
+ ".dkp-iconbtn{box-sizing:border-box;width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:none;border-radius:var(--dsw-radius-sm,6px);background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:12px;line-height:1;}",
4985
+ ".dkp-iconbtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}",
4986
+ ".dkp-iconbtn.danger:hover{background:var(--dsw-alias-interactive-bg-hover-danger,rgba(220,38,38,.1));color:var(--dsw-alias-state-error-primary);}",
4987
+ ".dkp-addmodel{box-sizing:border-box;align-self:flex-start;display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 10px;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm,6px);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px;cursor:pointer;}",
4988
+ ".dkp-addmodel:hover{background:var(--dsw-alias-interactive-bg-hover);}",
4989
+ ".dkp-picker{max-height:320px;overflow-y:auto;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md,8px);padding:4px 6px;display:flex;flex-direction:column;gap:2px;}",
4990
+ ".dkp-picker label{display:flex;align-items:center;gap:8px;min-width:0;cursor:pointer;padding:6px 8px;border-radius:var(--dsw-radius-md,8px);}",
4991
+ ".dkp-picker label:hover{background:var(--dsw-alias-interactive-bg-hover);}",
4992
+ ".dkp-picker input{accent-color:var(--dk-accent);margin:0;flex:none;}",
4993
+ ".dkp-picker-id{flex:none;font-family:var(--ds-font-family-code,ui-monospace,monospace);font-size:13px;line-height:20px;}",
4994
+ ".dkp-picker-name{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
4995
+ ".dkp-empty{border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg,10px);padding:12px;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;}",
4996
+ ".dkp-addblock{display:flex;align-items:stretch;}",
4997
+ ".dkp-addbtn{box-sizing:border-box;flex:1 1 auto;min-width:180px;height:44px;display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-lg,10px);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;cursor:pointer;}",
4998
+ ".dkp-addbtn:hover{background:var(--dsw-alias-interactive-bg-hover);}",
4999
+ ".dkp-addcard{flex:1 1 auto;padding:14px 16px;}",
5000
+ ".dkp-addcard .dkp-editor{background:transparent;padding:0;}",
5001
+ ".dkp-editor-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap;border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px;}",
5002
+ ".dkp-editor-actions .dkp-hint{margin-right:auto;}",
5003
+ "@media (max-width:680px){.dkp-page{max-width:none;gap:14px}.dkp-intro{font-size:13px;line-height:20px}.dkp-model-row{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.dkp-model-row .dkp-iconbtn{justify-self:end}.dkp-editor{padding:12px}.dkp-addcard{padding:12px 14px}.dkp-btn{height:40px}.dkp-btn.sm{height:34px}.dkp-addbtn{height:48px}}"
4250
5004
  ].join("\n"),
4251
5005
  View: ModelsView,
4252
5006
  HomeStat: ModelsStat
@@ -4398,7 +5152,7 @@ var balanceStore = {
4398
5152
  load() {
4399
5153
  if (this.snap.loading) return;
4400
5154
  this.set({ loading: true });
4401
- fetch("/dsh-dock/balance", { signal: AbortSignal.timeout(2e4) }).then((res) => res.ok ? res.json() : Promise.reject(new Error("\u4F59\u989D\u63A5\u53E3 HTTP " + res.status))).then((data) => this.set({ data, loading: false, error: null })).catch((e) => this.set({ loading: false, error: e && e.message || String(e) }));
5155
+ fetch("dsh-dock/balance", { signal: AbortSignal.timeout(2e4) }).then((res) => res.ok ? res.json() : Promise.reject(new Error("\u4F59\u989D\u63A5\u53E3 HTTP " + res.status))).then((data) => this.set({ data, loading: false, error: null })).catch((e) => this.set({ loading: false, error: e && e.message || String(e) }));
4402
5156
  }
4403
5157
  };
4404
5158
  function useBalance(ctx) {
@@ -4721,7 +5475,7 @@ var feature5 = {
4721
5475
  var import_react8 = require("react");
4722
5476
  var import_jsx_runtime2 = require("react/jsx-runtime");
4723
5477
  function rpcCall2(method, args) {
4724
- return fetch("/dsh-dock/animation/" + method, {
5478
+ return fetch("dsh-dock/animation/" + method, {
4725
5479
  method: "POST",
4726
5480
  headers: { "content-type": "application/json" },
4727
5481
  body: JSON.stringify(args === void 0 ? {} : args)
@@ -6398,7 +7152,7 @@ var feature6 = {
6398
7152
  var import_react9 = require("react");
6399
7153
  var import_jsx_runtime3 = require("react/jsx-runtime");
6400
7154
  function rpcCall3(method, args) {
6401
- return fetch("/dsh-dock/notify/" + method, {
7155
+ return fetch("dsh-dock/notify/" + method, {
6402
7156
  method: "POST",
6403
7157
  headers: { "content-type": "application/json" },
6404
7158
  body: JSON.stringify(args === void 0 ? {} : args)
@@ -7162,7 +7916,7 @@ var feature7 = {
7162
7916
  var import_react10 = require("react");
7163
7917
  var import_jsx_runtime4 = require("react/jsx-runtime");
7164
7918
  function rpcCall4(method, args) {
7165
- return fetch("/dsh-dock/runstate/" + method, {
7919
+ return fetch("dsh-dock/runstate/" + method, {
7166
7920
  method: "POST",
7167
7921
  headers: { "content-type": "application/json" },
7168
7922
  body: JSON.stringify(args === void 0 ? {} : args)
@@ -10145,7 +10899,7 @@ function initialDash() {
10145
10899
  }
10146
10900
  function useTaskPulse() {
10147
10901
  const [status, setStatus] = (0, import_react20.useState)({ loading: true, active: [], error: false });
10148
- const refresh = (0, import_react20.useCallback)(() => fetch("/dsh-dock/animation/status", {
10902
+ const refresh = (0, import_react20.useCallback)(() => fetch("dsh-dock/animation/status", {
10149
10903
  method: "POST",
10150
10904
  headers: { "content-type": "application/json" },
10151
10905
  body: "{}"
@@ -10918,7 +11672,7 @@ var import_react21 = require("react");
10918
11672
  var import_qrcode = __toESM(require_browser(), 1);
10919
11673
  var import_jsx_runtime14 = require("react/jsx-runtime");
10920
11674
  function rpc(method, payload) {
10921
- return fetch("/dsh-dock/mobile-relay/" + method, {
11675
+ return fetch("dsh-dock/mobile-relay/" + method, {
10922
11676
  method: "POST",
10923
11677
  headers: { "content-type": "application/json" },
10924
11678
  body: JSON.stringify(payload || {})
@@ -11177,6 +11931,11 @@ function RemoteCard() {
11177
11931
  busy === "stop" ? "\u6B63\u5728\u5173\u95ED\u2026" : "\u5173\u95ED\u8FDC\u7A0B\u8BBF\u95EE"
11178
11932
  ] })
11179
11933
  ] }),
11934
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("small", { children: [
11935
+ "\u5DF2\u767B\u5F55\u8BBE\u5907\uFF1A",
11936
+ typeof lan.devices === "number" ? lan.devices : 0,
11937
+ " \u53F0\uFF08\u6539\u5BC6\u6216\u5173\u95ED\u5165\u53E3\u5373\u5168\u90E8\u4E0B\u7EBF\uFF09"
11938
+ ] }),
11180
11939
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("small", { children: "\u4E3B\u5B9E\u4F8B\u4FDD\u6301\u4EC5\u672C\u673A\uFF08\u7ED3\u6784\u4E0A\u4E0D\u5B58\u5728\u514D\u767B\u5F55\u76F4\u8FDE\uFF09\uFF1B\u8D26\u53F7\u5BC6\u7801\u53EA\u53D1\u7ED9\u81EA\u5DF1\u3002\u82E5\u5F00\u542F\u524D\u5DF2\u6709\u65E7\u670D\u52A1\u5668\u6A21\u5F0F\uFF080.0.0.0\uFF09\u914D\u7F6E\uFF0C\u4F1A\u4E00\u5E76\u79FB\u9664\u5E76\u63D0\u793A\u91CD\u542F\u3002" })
11181
11940
  ] })
11182
11941
  ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "dmr-primary", onClick: enable, disabled: busy === "start", children: busy === "start" ? "\u6B63\u5728\u5F00\u542F\u2026" : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
@@ -11212,180 +11971,19 @@ function RemoteCard() {
11212
11971
  function MobileRelayView() {
11213
11972
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(RemoteCard, {});
11214
11973
  }
11215
- function MobileRelayOverlay() {
11216
- (0, import_react21.useEffect)(() => {
11217
- if (typeof window === "undefined" || typeof document === "undefined") return void 0;
11218
- const hostPresent = !!(window.__dshDockMobileDrawer && document.querySelector(".dsh-mobile-drawer-btn"));
11219
- const mq = window.matchMedia ? window.matchMedia("(max-width:700px)") : null;
11220
- if (!mq) return void 0;
11221
- if (!hostPresent) window.__dshDockMobileDrawer = "client";
11222
- const narrow = () => mq.matches;
11223
- const frameEl = () => document.querySelector('[class$="frame"]');
11224
- const sidebarCollapsed = () => {
11225
- const f = frameEl();
11226
- return !!f && f.hasAttribute("data-sidebar-collapsed");
11227
- };
11228
- const dialogOpen = () => !!document.querySelector('[role="dialog"][class*="panel"]');
11229
- const collapse = () => {
11230
- const b = document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
11231
- if (b) b.click();
11232
- };
11233
- const expand = () => {
11234
- const b = document.querySelector('button[aria-label="\u6253\u5F00\u4FA7\u8FB9\u680F"],button[aria-label="Open sidebar"]');
11235
- if (b) b.click();
11236
- };
11237
- const closeDetails = () => {
11238
- const d = document.querySelector('[class*="detailsCol"]');
11239
- if (!d || !d.getBoundingClientRect().width) return;
11240
- const c = d.querySelector('button[aria-label="\u5173\u95ED\u8BE6\u60C5"]');
11241
- if (c) c.click();
11242
- };
11243
- let fab = null;
11244
- let scrim = null;
11245
- if (!hostPresent) {
11246
- fab = document.createElement("button");
11247
- fab.type = "button";
11248
- fab.className = "dsh-mobile-drawer-btn";
11249
- fab.setAttribute("aria-label", "\u6253\u5F00\u4F1A\u8BDD\u5217\u8868");
11250
- fab.innerHTML = '<svg viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h10"/></svg>';
11251
- fab.addEventListener("click", expand);
11252
- scrim = document.createElement("div");
11253
- scrim.className = "dsh-mobile-scrim";
11254
- document.body.appendChild(fab);
11255
- document.body.appendChild(scrim);
11256
- }
11257
- const tabbar = document.createElement("nav");
11258
- tabbar.className = "dsh-mobile-tabbar";
11259
- tabbar.setAttribute("aria-label", "\u5E95\u90E8\u5BFC\u822A");
11260
- const tabDefs = [
11261
- {
11262
- id: "sessions",
11263
- label: "\u4F1A\u8BDD",
11264
- icon: '<svg viewBox="0 0 24 24"><path d="M21 12a8 8 0 0 1-8 8H5l-2 2V12a8 8 0 0 1 8-8h2a8 8 0 0 1 8 8z"/></svg>',
11265
- act: () => expand()
11266
- },
11267
- {
11268
- id: "dock",
11269
- label: "\u529F\u80FD\u575E",
11270
- icon: '<svg viewBox="0 0 24 24"><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></svg>',
11271
- act: () => {
11272
- if (panelNav.open) setPanelOpen(false);
11273
- else openPanel("home");
11274
- }
11275
- },
11276
- {
11277
- id: "settings",
11278
- label: "\u8BBE\u7F6E",
11279
- icon: '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3.2"/><path d="M19.4 15a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06A1.7 1.7 0 0 0 15 19.4a1.7 1.7 0 0 0-1 1.55V21a2 2 0 1 1-4 0v-.09A1.7 1.7 0 0 0 9 19.4a1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-1.55-1H3a2 2 0 1 1 0-4h.09A1.7 1.7 0 0 0 4.6 9a1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.7 1.7 0 0 0 9 4.6a1.7 1.7 0 0 0 1-1.55V3a2 2 0 1 1 4 0v.09a1.7 1.7 0 0 0 1 1.51 1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.7 1.7 0 0 0 19.4 9c.23.6.86 1 1.51 1H21a2 2 0 1 1 0 4h-.09a1.7 1.7 0 0 0-1.51 1z"/></svg>',
11280
- act: () => {
11281
- const b = [...document.querySelectorAll("button")].find((x) => (x.getAttribute("aria-label") || "") === "\u8BBE\u7F6E" || (x.textContent || "").trim() === "\u8BBE\u7F6E");
11282
- if (b) b.click();
11283
- }
11284
- }
11285
- ];
11286
- const tabButtons = tabDefs.map((def) => {
11287
- const b = document.createElement("button");
11288
- b.type = "button";
11289
- b.className = "dsh-mobile-tab";
11290
- b.dataset.tab = def.id;
11291
- b.innerHTML = def.icon + "<span>" + def.label + "</span>";
11292
- b.addEventListener("click", () => def.act());
11293
- tabbar.appendChild(b);
11294
- return b;
11295
- });
11296
- document.body.appendChild(tabbar);
11297
- const syncTabs = () => {
11298
- const expanded = !sidebarCollapsed();
11299
- const settingsOpen = dialogOpen();
11300
- for (const b of tabButtons) {
11301
- const id = b.dataset.tab;
11302
- const on = id === "sessions" && expanded || id === "dock" && panelNav.open || id === "settings" && settingsOpen;
11303
- b.classList.toggle("on", on);
11304
- }
11305
- };
11306
- const unsubPanel = subscribePanel(syncTabs);
11307
- const place = () => {
11308
- if (!fab) return;
11309
- const vh = window.innerHeight;
11310
- let top = null;
11311
- const g = document.querySelector(".dgfab");
11312
- if (g && !g.classList.contains("dgfab-hide") && g.getBoundingClientRect) {
11313
- const r = g.getBoundingClientRect();
11314
- if (r && r.height > 0 && r.top > 0) {
11315
- top = r.top - fab.offsetHeight - 8;
11316
- if (top < 64) top = r.bottom + 8;
11317
- if (top + fab.offsetHeight > vh - 16) top = null;
11318
- }
11319
- }
11320
- if (top == null) top = Math.round(vh * 0.38);
11321
- fab.style.top = top + "px";
11322
- };
11323
- const sync = () => {
11324
- const on = narrow() && !!frameEl() && !dialogOpen();
11325
- const collapsed = sidebarCollapsed();
11326
- if (fab) {
11327
- const showFab = on && collapsed && !panelNav.open;
11328
- fab.style.display = showFab ? "" : "none";
11329
- if (showFab) place();
11330
- }
11331
- if (scrim) scrim.style.display = on && !collapsed ? "" : "none";
11332
- tabbar.style.display = narrow() && !!frameEl() && !panelNav.open ? "" : "none";
11333
- syncTabs();
11334
- };
11335
- sync();
11336
- const observer = typeof MutationObserver !== "undefined" ? new MutationObserver(sync) : null;
11337
- if (observer) observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-sidebar-collapsed"], subtree: true });
11338
- const timer = setInterval(sync, 1500);
11339
- const onMq = () => sync();
11340
- if (mq.addEventListener) mq.addEventListener("change", onMq);
11341
- else if (mq.addListener) mq.addListener(onMq);
11342
- window.addEventListener("resize", place);
11343
- const onClick = (e) => {
11344
- if (!narrow()) return;
11345
- const t = e.target;
11346
- if (!t || !t.closest) return;
11347
- if (t.closest(".dsh-mobile-drawer-btn") || t.closest(".dsh-mobile-tabbar")) return;
11348
- const expanded = !!document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
11349
- const col = document.querySelector('[class*="sidebarCol"]');
11350
- const inSidebar = col && col.contains(t);
11351
- if (!expanded && !inSidebar) return;
11352
- if (inSidebar) {
11353
- const row = t.closest('[role="treeitem"]');
11354
- const leaf = row && !row.querySelector('[role="treeitem"]') && row.closest('[role="tree"]');
11355
- const fresh = t.closest('[class*="newSession"]');
11356
- if (leaf || fresh) setTimeout(() => {
11357
- collapse();
11358
- closeDetails();
11359
- }, 300);
11360
- return;
11361
- }
11362
- if (t.closest('[role="dialog"],[class*="dockm"],[class*="dgfab"],[class*="dgwin"],[class*="dgame"],[class*="detailsCol"]')) return;
11363
- collapse();
11364
- };
11365
- if (!hostPresent) document.addEventListener("click", onClick, true);
11366
- return () => {
11367
- if (!hostPresent) document.removeEventListener("click", onClick, true);
11368
- if (observer) observer.disconnect();
11369
- clearInterval(timer);
11370
- unsubPanel();
11371
- if (mq.removeEventListener) mq.removeEventListener("change", onMq);
11372
- else if (mq.removeListener) mq.removeListener(onMq);
11373
- window.removeEventListener("resize", place);
11374
- if (fab) fab.remove();
11375
- if (scrim) scrim.remove();
11376
- tabbar.remove();
11377
- if (window.__dshDockMobileDrawer === "client") delete window.__dshDockMobileDrawer;
11378
- };
11379
- }, []);
11380
- return null;
11381
- }
11382
11974
  function MobileRelayHomeStat() {
11383
11975
  const [summary, setSummary] = (0, import_react21.useState)("\u672A\u5F00\u542F\uFF0C\u5F00\u542F\u540E\u53EF\u8FDC\u7A0B\u767B\u5F55");
11384
11976
  (0, import_react21.useEffect)(() => {
11385
- rpc("lan").then((data) => {
11386
- setSummary(data.gatewayActive ? "\u5165\u53E3\u8FD0\u884C\u4E2D \xB7 \u7AEF\u53E3 " + data.gatewayPort : data.accountSet ? "\u8D26\u53F7\u5DF2\u8BBE\u7F6E\uFF0C\u5165\u53E3\u672A\u5F00\u542F" : "\u672A\u5F00\u542F\uFF0C\u5F00\u542F\u540E\u53EF\u8FDC\u7A0B\u767B\u5F55");
11387
- }).catch(() => {
11388
- });
11977
+ const refresh = () => {
11978
+ rpc("lan").then((data) => {
11979
+ const devices = typeof data.devices === "number" && data.devices > 0 ? " \xB7 " + data.devices + " \u53F0\u8BBE\u5907\u5728\u7EBF" : "";
11980
+ setSummary(data.gatewayActive ? "\u5165\u53E3\u8FD0\u884C\u4E2D \xB7 \u7AEF\u53E3 " + data.gatewayPort + devices : data.accountSet ? "\u8D26\u53F7\u5DF2\u8BBE\u7F6E\uFF0C\u5165\u53E3\u672A\u5F00\u542F" : "\u672A\u5F00\u542F\uFF0C\u5F00\u542F\u540E\u53EF\u8FDC\u7A0B\u767B\u5F55");
11981
+ }).catch(() => {
11982
+ });
11983
+ };
11984
+ refresh();
11985
+ const timer = setInterval(refresh, 1e4);
11986
+ return () => clearInterval(timer);
11389
11987
  }, []);
11390
11988
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: summary });
11391
11989
  }
@@ -11398,35 +11996,474 @@ var feature10 = {
11398
11996
  defaultEnabled: false,
11399
11997
  css: `
11400
11998
  .dmr{--dmr-accent:var(--dk-accent,#2f6fed);--dmr-accent-soft:color-mix(in srgb,var(--dmr-accent) 13%,transparent);display:flex;flex-direction:column;gap:16px;max-width:720px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5}.dmr h3,.dmr h4,.dmr p{margin:0}.dmr h3{font-size:17px;line-height:1.25;letter-spacing:-.01em}.dmr h4{font-size:13px}.dmr-hero,.dmr-status-head{display:flex;align-items:flex-start;gap:12px}.dmr-hero>div,.dmr-status-head>div{min-width:0;display:flex;flex-direction:column;gap:4px}.dmr-hero p,.dmr-status-head p,.dmr-field small,.dmr-share small,.dmr-overview-card small,.dmr-task small,.dmr-note p{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55}.dmr-hero-icon{width:42px;height:42px;display:inline-flex;align-items:center;justify-content:center;flex:none;border-radius:14px;background:var(--dmr-accent-soft);color:var(--dmr-accent);border:1px solid color-mix(in srgb,var(--dmr-accent) 35%,var(--dsw-alias-border-l1))}.dmr-steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:0;padding:0;list-style:none}.dmr-steps li{display:flex;gap:9px;padding:11px;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px}.dmr-steps li>span{width:21px;height:21px;display:inline-flex;align-items:center;justify-content:center;flex:none;border-radius:50%;font-size:11px;font-weight:700;color:var(--dmr-accent);background:var(--dmr-accent-soft)}.dmr-steps div{display:flex;flex-direction:column;gap:3px;min-width:0}.dmr-steps strong{font-size:12px}.dmr-steps small{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.45}.dmr-field{display:flex;flex-direction:column;gap:6px;font-weight:600}.dmr-field input,.dmr-field select,.dmr-note textarea{box-sizing:border-box;width:100%;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:10px;padding:10px 12px;min-height:44px;font:inherit;outline:none;transition:border-color .18s ease,box-shadow .18s ease}.dmr-field input:focus,.dmr-field select:focus,.dmr-note textarea:focus{border-color:var(--dmr-accent);box-shadow:0 0 0 3px var(--dmr-accent-soft)}.dmr-field small{font-weight:400}.dmr-network-grid{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(150px,.6fr);gap:12px}.dmr-security{padding:12px 13px;border:1px solid color-mix(in srgb,var(--dk-warn) 48%,var(--dsw-alias-border-l1));border-radius:12px;background:color-mix(in srgb,var(--dk-warn) 9%,transparent)}.dmr-security strong{display:block;margin-bottom:4px;color:var(--dk-warn);font-size:12px}.dmr-security p{font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.55}.dmr-primary,.dmr-secondary,.dmr-text-button,.dmr-icon-button{font:inherit;touch-action:manipulation;cursor:pointer;transition:transform .15s ease,background .18s ease,border-color .18s ease,opacity .18s ease}.dmr-primary,.dmr-secondary{min-height:44px;display:inline-flex;align-items:center;justify-content:center;gap:8px;border-radius:10px;padding:9px 13px;font-weight:600}.dmr-primary{align-self:flex-start;border:1px solid var(--dmr-accent);background:var(--dmr-accent);color:#fff}.dmr-primary:hover{filter:brightness(1.05)}.dmr-secondary{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.dmr-secondary:hover{border-color:var(--dmr-accent);background:var(--dmr-accent-soft)}.dmr-primary:active,.dmr-secondary:active,.dmr-icon-button:active{transform:scale(.98)}.dmr-primary:disabled,.dmr-secondary:disabled,.dmr-text-button:disabled,.dmr-icon-button:disabled{cursor:not-allowed;opacity:.5}.dmr-message{display:flex;align-items:flex-start;gap:7px;padding:10px 12px;border-radius:10px;font-size:12px}.dmr-message.success{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 10%,transparent)}.dmr-message.error{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}.dmr-status-head{justify-content:space-between}.dmr-eyebrow{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;color:var(--dmr-accent)}.dmr-eyebrow i{width:7px;height:7px;border-radius:50%;background:currentColor;box-shadow:0 0 0 4px var(--dmr-accent-soft)}.dmr-icon-button{display:inline-flex;align-items:center;justify-content:center;flex:none;width:44px;height:44px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:transparent;color:var(--dsw-alias-label-secondary)}.dmr-icon-button:hover{color:var(--dsw-alias-state-error-primary);border-color:currentColor}.dmr-share{display:flex;flex-direction:column;gap:9px;padding:13px;border:1px solid color-mix(in srgb,var(--dmr-accent) 32%,var(--dsw-alias-border-l1));border-radius:13px;background:var(--dmr-accent-soft)}.dmr-share-layout{display:grid;grid-template-columns:196px minmax(0,1fr);gap:16px;align-items:center}.dmr-qr-card{box-sizing:border-box;display:flex;flex-direction:column;align-items:center;gap:5px;padding:10px;border-radius:12px;background:#fff;color:#111827;text-align:center}.dmr-qr-card img{display:block;width:176px;height:176px;max-width:100%;object-fit:contain}.dmr-qr-card strong{font-size:12px}.dmr-qr-card small{color:#4b5563;font-size:10px}.dmr-qr-loading{display:grid;place-items:center;width:176px;height:176px;color:#64748b;font-size:12px}.dmr-share-detail{min-width:0;display:flex;flex-direction:column;gap:10px}.dmr-share-detail>div:first-child{display:flex;flex-direction:column;gap:4px}.dmr-link{padding:10px 11px;border-radius:8px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace;word-break:break-all;color:var(--dsw-alias-label-secondary)}.dmr-share-actions{display:flex;gap:8px;flex-wrap:wrap}.dmr-share-actions .dmr-primary{align-self:auto}.dmr-overview{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.dmr-overview-card{display:flex;flex-direction:column;gap:3px;padding:12px;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-1)}.dmr-overview-card>span{font-size:11px;color:var(--dsw-alias-label-tertiary)}.dmr-overview-card strong{font-size:16px;letter-spacing:-.01em}.dmr-section{display:flex;flex-direction:column;gap:9px}.dmr-section-head{display:flex;align-items:center;justify-content:space-between;gap:10px}.dmr-section-head small{font-size:11px;color:var(--dsw-alias-label-tertiary)}.dmr-text-button{border:0;background:transparent;color:var(--dmr-accent);padding:8px;min-height:36px;font-weight:600}.dmr-task-list{display:flex;flex-direction:column;gap:8px}.dmr-task{display:flex;align-items:flex-start;gap:9px;padding:10px 11px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-1)}.dmr-task>div{display:flex;min-width:0;flex:1;flex-direction:column;gap:2px}.dmr-task strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dmr-phase{flex:none;border-radius:999px;padding:3px 8px;font-size:11px;background:var(--dmr-accent-soft);color:var(--dmr-accent)}.dmr-phase.write{color:var(--dsw-alias-state-success-primary)}.dmr-phase.code{color:var(--dk-warn)}.dmr-phase.search{color:#0d9488}.dmr-empty{padding:18px 12px;text-align:center;border:1px dashed var(--dsw-alias-border-l2);border-radius:10px;color:var(--dsw-alias-label-secondary);font-size:12px}.dmr-note{display:flex;flex-direction:column;gap:9px;padding-top:2px}.dmr-note blockquote{margin:0;padding:10px 12px;border-left:3px solid var(--dmr-accent);border-radius:0 9px 9px 0;background:var(--dmr-accent-soft);white-space:pre-wrap;font-size:12px}.dmr-note textarea{min-height:88px;resize:vertical;line-height:1.5}.dmr-note .dmr-secondary{align-self:flex-start}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (max-width:680px){.dmr{gap:14px;font-size:14px}.dmr h3{font-size:18px}.dmr-steps{grid-template-columns:1fr;gap:8px}.dmr-steps li{padding:10px}.dmr-steps small,.dmr-hero p,.dmr-status-head p,.dmr-field small,.dmr-share small,.dmr-overview-card small,.dmr-task small,.dmr-note p{font-size:12px}.dmr-network-grid{grid-template-columns:1fr;gap:10px}.dmr-field input,.dmr-field select{font-size:16px}.dmr-primary,.dmr-secondary{width:100%;font-size:14px}.dmr-share-layout{grid-template-columns:1fr;gap:12px}.dmr-qr-card{width:min(240px,100%);margin:0 auto}.dmr-qr-card img,.dmr-qr-loading{width:210px;height:210px}.dmr-share-actions{flex-direction:column}.dmr-share-actions .dmr-primary{width:100%}.dmr-overview{gap:8px}.dmr-overview-card{padding:11px}.dmr-status-head{gap:8px}.dmr-link{font-size:11px}.dmr-note textarea{font-size:16px;min-height:104px}.dmr-note .dmr-secondary{align-self:stretch}.dmr-compact .dmr-hero-icon{width:40px;height:40px;border-radius:13px}}@media (prefers-reduced-motion:reduce){.dmr-primary,.dmr-secondary,.dmr-text-button,.dmr-icon-button,.dmr-field input,.dmr-field select,.dmr-note textarea{transition:none}}.dmr-lan{flex:none;margin-top:6px;padding-top:16px;border-top:1px solid var(--dsw-alias-border-l1)}.dmr-lan-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.dmr-lan-title{min-width:0;display:flex;flex-direction:column;gap:4px}.dmr-lan-title p{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55}.dmr-lan-badge{flex:none;display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:5px 10px;font-size:11px;font-weight:700;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary)}.dmr-lan-badge.on{border-color:color-mix(in srgb,var(--dmr-accent) 45%,transparent);background:var(--dmr-accent-soft);color:var(--dmr-accent)}.dmr-lan-active,.dmr-lan-idle{display:flex;flex-direction:column;gap:12px}.dmr-lan-active .dmr-share-detail small strong{color:var(--dsw-alias-state-error-primary)}.dmr-danger{border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 45%,var(--dsw-alias-border-l2));color:var(--dsw-alias-state-error-primary)}.dmr-danger:hover{border-color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
11401
- /* \u62BD\u5C49\u628A\u624B\uFF1A\u8D34\u5DE6\u8FB9\u7F18\uFF08\u540C\u8DA3\u5473\u6E38\u620F\u6D6E\u6807\u7684\u8FB9\u7F18\u5438\u9644\u8BED\u8A00\uFF09\uFF0Ctop \u7531 place() \u52A8\u6001\u8BBE\u5B9A\uFF1B
11402
- * z \u5E8F 70 < \u906E\u7F69 75 < \u4FA7\u680F 80 < overlayLayer 90\uFF0C\u9762\u677F/\u5F39\u7A97\u6253\u5F00\u65F6\u81EA\u7136\u88AB\u76D6\u3002 */
11403
- @media (max-width:700px){.dsh-mobile-drawer-btn{position:fixed;left:0;top:38vh;z-index:70;box-sizing:border-box;width:30px;height:48px;padding:0;display:flex;align-items:center;justify-content:center;border:1px solid var(--dsw-alias-border-l1,rgba(127,139,161,.35));border-left:none;border-radius:0 12px 12px 0;background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,#1c2230) 88%,transparent);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:var(--dsw-alias-label-primary,#e6eaf2);box-shadow:4px 0 18px rgba(0,0,0,.28);cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent}.dsh-mobile-drawer-btn:active{transform:scale(.94)}.dsh-mobile-drawer-btn svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.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}
11404
- /* ---- \u4EFF ZCode \u624B\u673A\u7AEF\uFF1A\u5E95\u90E8 Tab \u680F + \u8F93\u5165\u533A\u5438\u9644\u5E95\u90E8 ---- */
11405
- .dsh-mobile-tabbar{position:fixed;left:0;right:0;bottom:0;z-index:65;display:flex;align-items:stretch;justify-content:space-around;padding:6px 8px calc(8px + env(safe-area-inset-bottom,0px));background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,#1c2230) 92%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-top:1px solid var(--dsw-alias-border-l1,rgba(127,139,161,.25));touch-action:manipulation}
11406
- .dsh-mobile-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;min-height:48px;padding:4px 0;border:0;background:transparent;color:var(--dsw-alias-label-tertiary,#8b95ab);font:600 11px/1.2 inherit;cursor:pointer;-webkit-tap-highlight-color:transparent;border-radius:10px}
11407
- .dsh-mobile-tab svg{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
11408
- .dsh-mobile-tab.on{color:var(--dsw-alias-label-primary,#e6eaf2)}
11409
- .dsh-mobile-tab.on svg{color:var(--dk-accent,#4d9fff)}
11410
- .dsh-mobile-tab:active{transform:scale(.94)}
11411
- /* \u8F93\u5165\u533A\u5438\u9644\u5230 Tab \u680F\u4E0A\u65B9\uFF1A\u5BBF\u4E3B\u628A\u6B22\u8FCE\u5185\u5BB9 justify-content:center \u5782\u76F4\u5C45\u4E2D\uFF0C
11412
- * \u624B\u673A\u89C6\u53E3\u4E0B\u8F93\u5165\u5361\u7247\u60AC\u5728\u4E2D\u90E8\u3001\u4E0B\u65B9\u7559\u51FA\u5927\u7247\u7A7A\u767D\u3002\u6539\u4E3A flex-end \u8D34\u5E95\uFF0C\u5E76\u7ED9
11413
- * \u6EDA\u52A8\u4F53\u7559\u51FA Tab \u680F\u9AD8\u5EA6\u7684\u5185\u8FB9\u8DDD\uFF0C\u907F\u514D\u5185\u5BB9\u88AB Tab \u680F\u906E\u6321\u3002 */
11414
- [class*="scrollBody"]{justify-content:flex-end !important;padding-bottom:calc(72px + env(safe-area-inset-bottom,0px)) !important}
11415
- [class*="scrollBody"]>[class*="composerSeat"]{padding-bottom:6px}
11416
- /* \u6536\u8D77\u7684\u4FA7\u680F\u8F68\u9053\uFF08collapsed rail\uFF09\u5728\u7A84\u5C4F\u53EA\u5269 1px \u5360\u4F4D\uFF0C\u4F46\u8F68\u9053\u91CC\u7684\u6309\u94AE
11417
- * \u4ECD\u4F1A\u6EA2\u51FA\u8D34\u5728\u5DE6\u8FB9\u7F18\uFF08\u529F\u80FD\u575E/\u8FDB\u5316/\u8BBE\u7F6E\u4E09\u679A\u9732\u51FA\u534A\u8FB9\u7684\u5706\u94AE\uFF09\u3002\u9690\u85CF\u6574\u5217\uFF0C
11418
- * \u8FD9\u4E9B\u5165\u53E3\u5DF2\u7531\u5E95\u90E8 Tab \u680F\u63A5\u7BA1\uFF1B\u5C55\u5F00\u62BD\u5C49\uFF08z 80\uFF09\u4E0D\u53D7\u5F71\u54CD\u3002 */
11419
- [class*="sidebarCol"]:has([class*="collapsed"]){visibility:hidden}
11420
- /* \u62BD\u5C49\u628A\u624B\u4ECE\u5C4F\u5E55\u4E2D\u90E8\u632A\u5230 Tab \u680F\u4E0A\u65B9\u4E00\u70B9\uFF0C\u514D\u5F97\u5B64\u96F6\u96F6\u60AC\u5728\u534A\u7A7A */
11421
- .dsh-mobile-drawer-btn{top:auto !important;bottom:calc(96px + env(safe-area-inset-bottom,0px))}}`,
11999
+ `,
11422
12000
  View: MobileRelayView,
11423
- HomeStat: MobileRelayHomeStat,
11424
- Overlay: MobileRelayOverlay
12001
+ HomeStat: MobileRelayHomeStat
12002
+ };
12003
+
12004
+ // features/mobile/view.js
12005
+ var import_react22 = __toESM(require("react"), 1);
12006
+ var import_react23 = require("react");
12007
+ var MOBILE_QUERY_NARROW = "(max-width: 820px)";
12008
+ var MOBILE_QUERY_COARSE = "(pointer: coarse) and (hover: none)";
12009
+ var MOBILE_QUERY_CHROME = "(max-width: 700px)";
12010
+ function mobileActive() {
12011
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
12012
+ try {
12013
+ return window.matchMedia(MOBILE_QUERY_NARROW).matches || window.matchMedia(MOBILE_QUERY_COARSE).matches;
12014
+ } catch {
12015
+ return false;
12016
+ }
12017
+ }
12018
+ function watchQuery(query, onChange) {
12019
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return () => {
12020
+ };
12021
+ let mq = null;
12022
+ try {
12023
+ mq = window.matchMedia(query);
12024
+ } catch {
12025
+ return () => {
12026
+ };
12027
+ }
12028
+ const update = () => onChange(mq.matches);
12029
+ update();
12030
+ if (typeof mq.addEventListener === "function") mq.addEventListener("change", update);
12031
+ else if (typeof mq.addListener === "function") mq.addListener(update);
12032
+ return () => {
12033
+ if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", update);
12034
+ else if (typeof mq.removeListener === "function") mq.removeListener(update);
12035
+ };
12036
+ }
12037
+ function MobileOverlay() {
12038
+ const [active, setActive] = (0, import_react23.useState)(() => mobileActive());
12039
+ (0, import_react23.useEffect)(() => {
12040
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return void 0;
12041
+ let mqs = [];
12042
+ try {
12043
+ mqs = [window.matchMedia(MOBILE_QUERY_NARROW), window.matchMedia(MOBILE_QUERY_COARSE)];
12044
+ } catch {
12045
+ return void 0;
12046
+ }
12047
+ const update = () => setActive(mqs.some((mq) => mq.matches));
12048
+ update();
12049
+ for (const mq of mqs) {
12050
+ if (typeof mq.addEventListener === "function") mq.addEventListener("change", update);
12051
+ else if (typeof mq.addListener === "function") mq.addListener(update);
12052
+ }
12053
+ return () => {
12054
+ for (const mq of mqs) {
12055
+ if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", update);
12056
+ else if (typeof mq.removeListener === "function") mq.removeListener(update);
12057
+ }
12058
+ };
12059
+ }, []);
12060
+ (0, import_react23.useEffect)(() => {
12061
+ if (typeof document === "undefined") return void 0;
12062
+ if (active) {
12063
+ document.body.setAttribute("data-dk-mobile", "1");
12064
+ try {
12065
+ const meta = document.querySelector('meta[name="viewport"]');
12066
+ if (meta && !/(^|,)\s*viewport-fit\s*=/.test(meta.content || "")) {
12067
+ meta.setAttribute("content", (meta.content || "width=device-width, initial-scale=1") + ", viewport-fit=cover");
12068
+ }
12069
+ } catch {
12070
+ }
12071
+ } else {
12072
+ document.body.removeAttribute("data-dk-mobile");
12073
+ }
12074
+ return () => {
12075
+ document.body.removeAttribute("data-dk-mobile");
12076
+ };
12077
+ }, [active]);
12078
+ (0, import_react23.useEffect)(() => mobileChrome(), []);
12079
+ return null;
12080
+ }
12081
+ function mobileChrome() {
12082
+ if (typeof window === "undefined" || typeof document === "undefined") return void 0;
12083
+ const mq = window.matchMedia ? window.matchMedia(MOBILE_QUERY_CHROME) : null;
12084
+ if (!mq) return void 0;
12085
+ if (window.__dshDockMobileDrawer === "host") return void 0;
12086
+ window.__dshDockMobileDrawer = "client";
12087
+ const narrow = () => mq.matches;
12088
+ const frameEl = () => document.querySelector('[class$="frame"]');
12089
+ const sidebarCollapsed = () => {
12090
+ const f = frameEl();
12091
+ return !!f && f.hasAttribute("data-sidebar-collapsed");
12092
+ };
12093
+ const dialogOpen = () => !!document.querySelector('[role="dialog"][class*="panel"]');
12094
+ const rightOpen = () => !!document.querySelector("[data-sidebar-right-panel][data-sidebar-right-open]");
12095
+ const collapse = () => {
12096
+ const b = document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
12097
+ if (b) b.click();
12098
+ };
12099
+ const expand = () => {
12100
+ const b = document.querySelector('button[aria-label="\u6253\u5F00\u4FA7\u8FB9\u680F"],button[aria-label="Open sidebar"]');
12101
+ if (b) b.click();
12102
+ };
12103
+ const closeDetails = () => {
12104
+ const panel = document.querySelector("[data-sidebar-right-panel][data-sidebar-right-open]");
12105
+ if (!panel) return;
12106
+ const toggle = panel.querySelector("[data-sidebar-right-toggle]");
12107
+ if (toggle) toggle.click();
12108
+ };
12109
+ const scrim = document.createElement("div");
12110
+ scrim.className = "dsh-mobile-scrim";
12111
+ document.body.appendChild(scrim);
12112
+ document.querySelectorAll(".dsh-mobile-tabbar").forEach((el) => el.remove());
12113
+ const tabbar = document.createElement("nav");
12114
+ tabbar.className = "dsh-mobile-tabbar";
12115
+ tabbar.setAttribute("aria-label", "\u5E95\u90E8\u5BFC\u822A");
12116
+ let tasksActive = 0;
12117
+ let tasksWaiting = 0;
12118
+ const tabDefs = [
12119
+ {
12120
+ id: "sessions",
12121
+ label: "\u4F1A\u8BDD",
12122
+ icon: '<svg viewBox="0 0 24 24"><path d="M21 12a8 8 0 0 1-8 8H5l-2 2V12a8 8 0 0 1 8-8h2a8 8 0 0 1 8 8z"/></svg>',
12123
+ act: () => expand()
12124
+ },
12125
+ {
12126
+ id: "dock",
12127
+ label: "\u63D2\u4EF6",
12128
+ icon: '<svg viewBox="0 0 24 24"><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></svg>',
12129
+ act: () => {
12130
+ openPanel(tasksActive > 0 || tasksWaiting > 0 ? "runstate" : "home");
12131
+ }
12132
+ },
12133
+ {
12134
+ id: "settings",
12135
+ label: "\u8BBE\u7F6E",
12136
+ icon: '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3.2"/><path d="M19.4 15a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06A1.7 1.7 0 0 0 15 19.4a1.7 1.7 0 0 0-1 1.55V21a2 2 0 1 1-4 0v-.09A1.7 1.7 0 0 0 9 19.4a1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.7 1.7 0 0 0 4.6 15a1.7 1.7 0 0 0-1.55-1H3a2 2 0 1 1 0-4h.09A1.7 1.7 0 0 0 4.6 9a1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.7 1.7 0 0 0 9 4.6a1.7 1.7 0 0 0 1-1.55V3a2 2 0 1 1 4 0v.09a1.7 1.7 0 0 0 1 1.51 1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.7 1.7 0 0 0 19.4 9c.23.6.86 1 1.51 1H21a2 2 0 1 1 0 4h-.09a1.7 1.7 0 0 0-1.51 1z"/></svg>',
12137
+ act: () => {
12138
+ const b = [...document.querySelectorAll("button")].find((x) => {
12139
+ const a = x.getAttribute("aria-label") || "";
12140
+ return a === "\u8BBE\u7F6E" || a === "Settings" || (x.textContent || "").trim() === "\u8BBE\u7F6E";
12141
+ });
12142
+ if (b) b.click();
12143
+ }
12144
+ }
12145
+ ];
12146
+ let tasksBadge = null;
12147
+ const tabButtons = tabDefs.map((def) => {
12148
+ const b = document.createElement("button");
12149
+ b.type = "button";
12150
+ b.className = "dsh-mobile-tab";
12151
+ b.dataset.tab = def.id;
12152
+ b.innerHTML = def.icon + "<span>" + def.label + "</span>";
12153
+ b.addEventListener("click", () => def.act());
12154
+ if (def.id === "dock") {
12155
+ tasksBadge = document.createElement("span");
12156
+ tasksBadge.className = "dsh-mobile-tab-badge";
12157
+ tasksBadge.style.display = "none";
12158
+ b.appendChild(tasksBadge);
12159
+ }
12160
+ tabbar.appendChild(b);
12161
+ return b;
12162
+ });
12163
+ document.body.appendChild(tabbar);
12164
+ const syncTabs = () => {
12165
+ const expanded = !sidebarCollapsed();
12166
+ const settingsOpen = dialogOpen();
12167
+ for (const b of tabButtons) {
12168
+ const id = b.dataset.tab;
12169
+ const on = id === "sessions" && expanded || id === "dock" && panelNav.open || id === "settings" && settingsOpen;
12170
+ b.classList.toggle("on", on);
12171
+ }
12172
+ };
12173
+ const unsubPanel = subscribePanel(syncTabs);
12174
+ let runstateGone = false;
12175
+ const pollTasks = () => {
12176
+ if (runstateGone || !tasksBadge || !narrow() || document.visibilityState === "hidden" || !tabbar.isConnected) return;
12177
+ fetch("dsh-dock/runstate/status", {
12178
+ method: "POST",
12179
+ headers: { "content-type": "application/json" },
12180
+ body: "{}"
12181
+ }).then(async (res) => {
12182
+ if (res.status === 404 || res.status === 405) {
12183
+ runstateGone = true;
12184
+ tasksActive = 0;
12185
+ tasksWaiting = 0;
12186
+ tasksBadge.style.display = "none";
12187
+ return null;
12188
+ }
12189
+ const body = await res.json().catch(() => null);
12190
+ if (!body) return null;
12191
+ const active = body.data && body.data.active || [];
12192
+ const waiting = active.filter((t) => t.approvals && t.approvals.length).length;
12193
+ tasksActive = active.length;
12194
+ tasksWaiting = waiting;
12195
+ if (waiting > 0) {
12196
+ tasksBadge.textContent = String(waiting);
12197
+ tasksBadge.className = "dsh-mobile-tab-badge wait";
12198
+ tasksBadge.style.display = "";
12199
+ } else if (active.length > 0) {
12200
+ tasksBadge.textContent = String(active.length);
12201
+ tasksBadge.className = "dsh-mobile-tab-badge";
12202
+ tasksBadge.style.display = "";
12203
+ } else {
12204
+ tasksBadge.style.display = "none";
12205
+ }
12206
+ }).catch(() => {
12207
+ });
12208
+ };
12209
+ const tasksTimer = setInterval(pollTasks, 3e3);
12210
+ const vv = window.visualViewport || null;
12211
+ const kbdSync = () => {
12212
+ if (!vv) return;
12213
+ const kbd = vv.height > 0 && window.innerHeight - vv.height > 120;
12214
+ document.documentElement.classList.toggle("dsh-dock-kbd", kbd);
12215
+ };
12216
+ const sync = () => {
12217
+ kbdSync();
12218
+ document.querySelectorAll(".dsh-mobile-tabbar").forEach((el) => {
12219
+ if (el !== tabbar) el.remove();
12220
+ });
12221
+ const on = narrow() && !!frameEl() && !dialogOpen();
12222
+ const collapsed = sidebarCollapsed();
12223
+ const right = rightOpen();
12224
+ if (scrim) scrim.style.display = on && !collapsed ? "" : "none";
12225
+ tabbar.style.display = narrow() && !!frameEl() && !panelNav.open && !right ? "" : "none";
12226
+ syncTabs();
12227
+ };
12228
+ sync();
12229
+ pollTasks();
12230
+ const observer = typeof MutationObserver !== "undefined" ? new MutationObserver(sync) : null;
12231
+ if (observer) observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-sidebar-collapsed"], subtree: true });
12232
+ const timer = setInterval(sync, 1500);
12233
+ const onMq = () => sync();
12234
+ if (mq.addEventListener) mq.addEventListener("change", onMq);
12235
+ else if (mq.addListener) mq.addListener(onMq);
12236
+ window.addEventListener("resize", kbdSync);
12237
+ if (vv && vv.addEventListener) vv.addEventListener("resize", kbdSync);
12238
+ const onVisible = () => {
12239
+ if (document.visibilityState === "visible") pollTasks();
12240
+ };
12241
+ document.addEventListener("visibilitychange", onVisible);
12242
+ const onClick = (e) => {
12243
+ if (!narrow()) return;
12244
+ const t = e.target;
12245
+ if (!t || !t.closest) return;
12246
+ if (t.closest(".dsh-mobile-tabbar")) return;
12247
+ const expanded = !!document.querySelector('button[aria-label="\u6536\u8D77\u4FA7\u8FB9\u680F"],button[aria-label="Collapse sidebar"]');
12248
+ const col = document.querySelector('[class*="sidebarCol"]');
12249
+ const inSidebar = col && col.contains(t);
12250
+ if (!expanded && !inSidebar) return;
12251
+ if (inSidebar) {
12252
+ const row = t.closest('[role="treeitem"]');
12253
+ const rowKey = row && row.getAttribute("data-row-key") || "";
12254
+ const sessionRow = rowKey && rowKey.startsWith("session:") || row && !rowKey && !row.querySelector('[role="treeitem"]') && row.closest('[role="tree"]');
12255
+ const fresh = t.closest('[class*="newSession"]');
12256
+ if (sessionRow || fresh) {
12257
+ setTimeout(() => {
12258
+ collapse();
12259
+ closeDetails();
12260
+ }, 300);
12261
+ return;
12262
+ }
12263
+ if (rowKey.startsWith("workspace:")) return;
12264
+ setTimeout(() => {
12265
+ if (document.querySelector('[role="dialog"]')) collapse();
12266
+ }, 260);
12267
+ return;
12268
+ }
12269
+ if (t.closest('[role="dialog"],[class*="dockm"],[class*="dgfab"],[class*="dgwin"],[class*="dgame"],[data-sidebar-right-panel]')) return;
12270
+ collapse();
12271
+ };
12272
+ document.addEventListener("click", onClick, true);
12273
+ return () => {
12274
+ document.removeEventListener("click", onClick, true);
12275
+ if (observer) observer.disconnect();
12276
+ clearInterval(timer);
12277
+ clearInterval(tasksTimer);
12278
+ unsubPanel();
12279
+ if (mq.removeEventListener) mq.removeEventListener("change", onMq);
12280
+ else if (mq.removeListener) mq.removeListener(onMq);
12281
+ window.removeEventListener("resize", kbdSync);
12282
+ if (vv && vv.removeEventListener) vv.removeEventListener("resize", kbdSync);
12283
+ document.removeEventListener("visibilitychange", onVisible);
12284
+ document.documentElement.classList.remove("dsh-dock-kbd");
12285
+ if (scrim) scrim.remove();
12286
+ tabbar.remove();
12287
+ if (window.__dshDockMobileDrawer === "client") delete window.__dshDockMobileDrawer;
12288
+ };
12289
+ }
12290
+ function useViewportSize() {
12291
+ const [size, setSize] = (0, import_react23.useState)(() => typeof window === "undefined" ? null : { w: window.innerWidth, h: window.innerHeight });
12292
+ (0, import_react23.useEffect)(() => {
12293
+ if (typeof window === "undefined") return void 0;
12294
+ const update = () => setSize({ w: window.innerWidth, h: window.innerHeight });
12295
+ window.addEventListener("resize", update);
12296
+ return () => window.removeEventListener("resize", update);
12297
+ }, []);
12298
+ return size;
12299
+ }
12300
+ function useMobileState() {
12301
+ const [active, setActive] = (0, import_react23.useState)(() => mobileActive());
12302
+ const [chrome, setChrome] = (0, import_react23.useState)(() => typeof window === "undefined" || typeof window.matchMedia !== "function" ? false : window.matchMedia(MOBILE_QUERY_CHROME).matches);
12303
+ const [owner, setOwner] = (0, import_react23.useState)(() => typeof window === "undefined" ? null : window.__dshDockMobileDrawer || null);
12304
+ (0, import_react23.useEffect)(() => {
12305
+ const offChrome = watchQuery(MOBILE_QUERY_CHROME, setChrome);
12306
+ let mqs = [];
12307
+ try {
12308
+ mqs = [window.matchMedia(MOBILE_QUERY_NARROW), window.matchMedia(MOBILE_QUERY_COARSE)];
12309
+ } catch {
12310
+ mqs = [];
12311
+ }
12312
+ const compute = () => setActive(mqs.some((mq) => mq.matches));
12313
+ for (const mq of mqs) {
12314
+ if (typeof mq.addEventListener === "function") mq.addEventListener("change", compute);
12315
+ else if (typeof mq.addListener === "function") mq.addListener(compute);
12316
+ }
12317
+ const timer = setInterval(() => setOwner(typeof window === "undefined" ? null : window.__dshDockMobileDrawer || null), 1e3);
12318
+ return () => {
12319
+ offChrome();
12320
+ for (const mq of mqs) {
12321
+ if (typeof mq.removeEventListener === "function") mq.removeEventListener("change", compute);
12322
+ else if (typeof mq.removeListener === "function") mq.removeListener(compute);
12323
+ }
12324
+ clearInterval(timer);
12325
+ };
12326
+ }, []);
12327
+ return { active, chrome, owner };
12328
+ }
12329
+ function MobileView() {
12330
+ const { active, chrome, owner } = useMobileState();
12331
+ const size = useViewportSize();
12332
+ return import_react22.default.createElement(
12333
+ "div",
12334
+ { className: "dkmob-root" },
12335
+ import_react22.default.createElement(
12336
+ "div",
12337
+ { className: "dkmob-row" },
12338
+ import_react22.default.createElement("span", { className: "dkmob-label" }, "\u624B\u673A\u6A21\u5F0F"),
12339
+ import_react22.default.createElement("span", { className: "dkmob-state" + (active ? " on" : "") }, active ? "\u5DF2\u547D\u4E2D" : "\u672A\u547D\u4E2D"),
12340
+ import_react22.default.createElement(
12341
+ "span",
12342
+ { className: "dkmob-dim" },
12343
+ size ? size.w + "\xD7" + size.h + "px" : "",
12344
+ "\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"
12345
+ )
12346
+ ),
12347
+ import_react22.default.createElement(
12348
+ "div",
12349
+ { className: "dkmob-row" },
12350
+ import_react22.default.createElement("span", { className: "dkmob-label" }, "\u624B\u673A\u7AEF chrome"),
12351
+ import_react22.default.createElement("span", { className: "dkmob-state" + (chrome ? " on" : "") }, chrome ? "\u2264700px\uFF0C\u751F\u6548\u4E2D" : "\u672A\u547D\u4E2D"),
12352
+ import_react22.default.createElement(
12353
+ "span",
12354
+ { className: "dkmob-dim" },
12355
+ "\u5E95\u90E8 Tab \u680F\uFF08\u4F1A\u8BDD / \u63D2\u4EF6 / \u8BBE\u7F6E\uFF09+ \u4FA7\u680F\u62BD\u5C49\u906E\u7F69 + \u8F6F\u952E\u76D8\u8BA9\u4F4D\uFF1B\u4F1A\u8BDD\u5165\u53E3\u5728\u5E95\u90E8\u300C\u4F1A\u8BDD\u300D\u9875\u7B7E\uFF0C\u4E0D\u8BBE\u5DE6\u7F18\u6D6E\u52A8\u6309\u94AE\u3002",
12356
+ 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" : ""
12357
+ )
12358
+ ),
12359
+ import_react22.default.createElement(
12360
+ "div",
12361
+ { className: "dkmob-note" },
12362
+ "\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 ",
12363
+ "\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 ",
12364
+ "\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",
12365
+ "\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"
12366
+ )
12367
+ );
12368
+ }
12369
+ function MobileStat() {
12370
+ const { active, chrome } = useMobileState();
12371
+ if (!active) return import_react22.default.createElement("span", null, "\u5F53\u524D\u89C6\u53E3\u672A\u547D\u4E2D\u624B\u673A\u5F62\u6001\uFF0C\u6837\u5F0F\u672A\u6CE8\u5165");
12372
+ return import_react22.default.createElement("span", null, "\u624B\u673A\u6A21\u5F0F\u751F\u6548\u4E2D \xB7 " + (chrome ? "\u5E95\u90E8 Tab \u680F\u5DF2\u63A5\u7BA1\u4F1A\u8BDD\u5165\u53E3" : "chrome \u5E26\u5BBD\u672A\u547D\u4E2D\uFF08\u2264700px \u624D\u542F\u7528\uFF09"));
12373
+ }
12374
+ var css6 = [
12375
+ // 输入类控件 16px:防 iOS 聚焦自动放大(<16px 的输入框聚焦时 Safari 强制缩放页面)
12376
+ '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;}',
12377
+ // 触控基础:去点按高亮、消双击缩放判定
12378
+ 'body[data-dk-mobile="1"] :is(button, [role="button"]){-webkit-tap-highlight-color:transparent;touch-action:manipulation;}',
12379
+ // 纯图标按钮面积兜底:实测窄屏下一批 28×28 的工具钮很难点中;36px 是不引起行高剧变的上限。
12380
+ // 只收「唯一子元素是 svg」的按钮,避免撑坏带文字的行内控件;排除本模块 chrome 按钮。
12381
+ 'body[data-dk-mobile="1"] button:has(> svg:only-child):not(.dsh-mobile-tab){min-width:36px;min-height:36px;}',
12382
+ // 代码块横向滚动、行内代码换行:窄屏不撑破版面
12383
+ 'body[data-dk-mobile="1"] pre{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;}',
12384
+ 'body[data-dk-mobile="1"] code{overflow-wrap:anywhere;}',
12385
+ 'body[data-dk-mobile="1"] pre code{overflow-wrap:normal;}',
12386
+ // 滚动兜底:所有纵向滚动体可纵向平移 + iOS 惯性滚动(祖先合成层/触控声明不再吃掉触摸滚动)。
12387
+ '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;}',
12388
+ // iOS 横竖屏切换时的字号自动膨胀关掉(:has 挂到 html 上;dsh 自身样式已依赖 :has,基线足够)
12389
+ 'html:has(body[data-dk-mobile="1"]){-webkit-text-size-adjust:100%;text-size-adjust:100%;}',
12390
+ // 功能页自身
12391
+ ".dkmob-root{display:flex;flex-direction:column;gap:10px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.6;}",
12392
+ ".dkmob-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
12393
+ ".dkmob-label{font-weight:600;flex:none;}",
12394
+ ".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;}",
12395
+ ".dkmob-state.on{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary);}",
12396
+ ".dkmob-dim{color:var(--dsw-alias-label-secondary);font-size:12px;}",
12397
+ ".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;}",
12398
+ // 手机端 chrome:底部 Tab 栏 + 抽屉遮罩(窄屏 ≤700px;与宿主半部同款)
12399
+ "@media (max-width:700px){",
12400
+ ".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}",
12401
+ ".dsh-mobile-tabbar{position:fixed;left:0;right:0;bottom:0;z-index:65;display:flex;align-items:stretch;justify-content:space-around;padding:6px 8px calc(8px + env(safe-area-inset-bottom,0px));background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,#1c2230) 92%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-top:1px solid var(--dsw-alias-border-l1,rgba(127,139,161,.25));touch-action:manipulation}",
12402
+ ".dsh-mobile-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;min-height:48px;padding:4px 0;border:0;background:transparent;color:var(--dsw-alias-label-tertiary,#8b95ab);font:600 11px/1.2 inherit;cursor:pointer;-webkit-tap-highlight-color:transparent;border-radius:10px;position:relative}",
12403
+ ".dsh-mobile-tab svg{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}",
12404
+ ".dsh-mobile-tab.on{color:var(--dsw-alias-label-primary,#e6eaf2)}",
12405
+ ".dsh-mobile-tab.on svg{color:var(--dk-accent,#4d9fff)}",
12406
+ ".dsh-mobile-tab:active{transform:scale(.94)}",
12407
+ ".dsh-mobile-tab-badge{position:absolute;top:0;right:calc(50% - 26px);box-sizing:border-box;min-width:16px;height:16px;padding:0 4px;border-radius:9px;display:flex;align-items:center;justify-content:center;background:#4d9fff;color:#fff;font-size:10px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums;box-shadow:0 2px 8px rgba(0,0,0,.35);pointer-events:none}",
12408
+ ".dsh-mobile-tab-badge.wait{background:#ef4444;animation:dsh-badge-pulse 1.2s ease-in-out infinite}",
12409
+ "@keyframes dsh-badge-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.18)}}",
12410
+ "@media (prefers-reduced-motion:reduce){.dsh-mobile-tab-badge.wait{animation:none}}",
12411
+ // ⚠️ 「设置页滑不动」的关键兜底(客户端无条件携带 = 刷新即生效,不必等宿主重启):
12412
+ // 窄屏把设置弹层改成纵向堆叠后,内容列若是默认 min-height:auto 就会被内容撑高
12413
+ // (无头 390×844 实测列高 1216px 塞在 844px 视口里)、再被 .panel 的 overflow:hidden
12414
+ // 裁掉——列内滚动容器([class*=options])因此 scrollHeight==clientHeight,手指怎么滑
12415
+ // 都不动。补 min-height:0 后 scrollTop 0 → 425。宿主半部 MOBILE_LAYOUT_CSS 同款;
12416
+ // 两处都写是因为宿主注入要重启 dsh web 才更新,而客户端样式刷新即生效,覆盖窗口期。
12417
+ '[role="dialog"][class*="panel"]>[class*="content"]{min-height:0!important}',
12418
+ // 输入区吸附到 Tab 栏上方 + 滚动体留白(与宿主半部同款)。
12419
+ // ⚠️ 绝不能给滚动体加 justify-content:flex-end/center 贴底:内容会被挤到滚动体
12420
+ // 起点之外,Chrome 不把起点方向溢出算进 scrollHeight(手机视口实测
12421
+ // scrollHeight==clientHeight、maxScroll==0),会话记录彻底滚不动、首条消息永远看不到。
12422
+ // 宿主半部旧版注入里还留着那条 flex-end(要重启 dsh web 才消失),这里用更高优先级
12423
+ // 的选择器显式复位:刷新页面即修好,不必等重启。
12424
+ '[class*="scrollBody"][data-conversation-scroll]{justify-content:flex-start !important;padding-bottom:calc(72px + env(safe-area-inset-bottom,0px)) !important}',
12425
+ 'html:not(.dsh-dock-kbd) [class*="scrollBody"]{padding-bottom:calc(72px + env(safe-area-inset-bottom,0px)) !important}',
12426
+ 'html.dsh-dock-kbd [class*="scrollBody"]{padding-bottom:12px !important}',
12427
+ '[class*="scrollBody"]>[class*="composerSeat"]{margin-top:auto;padding-bottom:6px}',
12428
+ // 输入区工具行上的 dsh-dock chip(用量/余额):窄屏下 28cqw 的宽度上限把它们挤成
12429
+ // 「…」「余..」(手机实测),既读不出数值又白占输入行空间。手机端整组收起,数值在
12430
+ // 底部「插件」里看(用量/余额页信息更全);桌面端不动。
12431
+ ".dockchip-row{display:none}",
12432
+ '[class*="sidebarCol"]:has([class*="collapsed"]){visibility:hidden}',
12433
+ // ⚠️ 列级 visibility:hidden 在 dsh 0.2.0 上挡不住:工作区浏览器给自己的
12434
+ // headerActions/sectionLabel 显式声明 visibility:visible(展开/收拢动画用),visibility
12435
+ // 可被后代覆盖,轨道按钮会从隐藏列里「透」出来(实测手机截图左缘游离按钮)。
12436
+ // display:none 不可被后代翻转——但只能打在**轨道根节点**上(类名同时含 root 与
12437
+ // collapsed 两个语义后缀),绝不能打在列上:frame 是「侧栏 0px + 中列 1fr + 右轨 0px」
12438
+ // 的网格,列 display:none 会从网格流里摘掉,中列被自动放置顶进 0px 轨(实测整页空屏)。
12439
+ // 弹层打开时豁免(设置弹层挂在列内部,display:none 会连坐成空气弹层),此时列退回
12440
+ // visibility 机制(由下一条 [role=dialog] 强制可见),窄屏弹层全屏铺满盖住透出的轨道。
12441
+ '[class*="sidebarCol"]:has([class*="collapsed"]):not(:has([role="dialog"])) [class*="root"][class*="collapsed"]{display:none !important}',
12442
+ // 设置/插件管理弹层挂在侧栏列内部:上面隐藏整列会把它连坐隐藏(空气弹层)。
12443
+ // visibility 可被后代覆盖,弹层关闭态整体卸载,所以只在真正打开时命中。
12444
+ '[class*="sidebarCol"]:has([class*="collapsed"]) [role="dialog"]{visibility:visible}',
12445
+ "html.dsh-dock-kbd .dsh-mobile-tabbar{display:none !important}",
12446
+ // 功能坞面板在手机端抬到原生弹层之上:从侧栏进的官方插件管理页等原生弹层 z 序高于
12447
+ // 面板默认的 200,功能坞开在下面会被盖住——「插件」页签点了像没反应/露出原页面。
12448
+ '[class*="dockm-backdrop"]{z-index:2000 !important}',
12449
+ "}"
12450
+ ].join("\n");
12451
+ var feature11 = {
12452
+ id: "mobile",
12453
+ name: "\u624B\u673A\u9002\u914D",
12454
+ order: 170,
12455
+ accent: "#34d399",
12456
+ description: "\u624B\u673A/\u7A84\u5C4F\u6392\u7248\u4E0E\u89E6\u63A7\u515C\u5E95\uFF1A\u5E95\u90E8 Tab \u680F + \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",
12457
+ defaultEnabled: true,
12458
+ css: css6,
12459
+ Overlay: MobileOverlay,
12460
+ View: MobileView,
12461
+ HomeStat: MobileStat
11425
12462
  };
11426
12463
 
11427
12464
  // src/client.jsx
11428
- var DOCK_VERSION = "0.12.0";
11429
- var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10];
12465
+ var DOCK_VERSION = "0.14.0";
12466
+ var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10, feature11];
11430
12467
  var PLANNED_FEATURES = [];
11431
12468
  var PLANNED_NOTES = {};
11432
12469
  var externalDefs = [];
@@ -11633,8 +12670,8 @@ function ensureCss() {
11633
12670
  }
11634
12671
  }
11635
12672
  function useExternalVersion() {
11636
- const [, bump] = import_react22.default.useReducer((n) => n + 1, 0);
11637
- import_react22.default.useEffect(() => {
12673
+ const [, bump] = import_react24.default.useReducer((n) => n + 1, 0);
12674
+ import_react24.default.useEffect(() => {
11638
12675
  externalListeners.add(bump);
11639
12676
  return () => {
11640
12677
  externalListeners.delete(bump);
@@ -11644,44 +12681,44 @@ function useExternalVersion() {
11644
12681
  var lastGeom = { x: null, y: null, w: null, h: null };
11645
12682
  function DockIcon(props) {
11646
12683
  const size = props && props.size || 16;
11647
- return import_react22.default.createElement(
12684
+ return import_react24.default.createElement(
11648
12685
  "svg",
11649
12686
  { width: size, height: size, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.3, "aria-hidden": true },
11650
- import_react22.default.createElement("rect", { x: 2.5, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
11651
- import_react22.default.createElement("rect", { x: 9, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
11652
- import_react22.default.createElement("rect", { x: 2.5, y: 9, width: 4.4, height: 4.4, rx: 1.2 }),
11653
- import_react22.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
12687
+ import_react24.default.createElement("rect", { x: 2.5, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
12688
+ import_react24.default.createElement("rect", { x: 9, y: 2.5, width: 4.4, height: 4.4, rx: 1.2 }),
12689
+ import_react24.default.createElement("rect", { x: 2.5, y: 9, width: 4.4, height: 4.4, rx: 1.2 }),
12690
+ import_react24.default.createElement("rect", { x: 9, y: 9, width: 4.4, height: 4.4, rx: 1.2 })
11654
12691
  );
11655
12692
  }
11656
12693
  function DockEntry(props) {
11657
12694
  const wide = !!props.wide;
11658
- const [open, setOpen] = import_react22.default.useState(panelNav.open);
11659
- import_react22.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
11660
- return import_react22.default.createElement("button", {
12695
+ const [open, setOpen] = import_react24.default.useState(panelNav.open);
12696
+ import_react24.default.useEffect(() => subscribePanel(() => setOpen(panelNav.open)), []);
12697
+ return import_react24.default.createElement("button", {
11661
12698
  type: "button",
11662
12699
  className: "docke2-btn" + (open ? " docke2-on" : "") + (wide ? "" : " docke2-rail"),
11663
12700
  title: "\u529F\u80FD\u575E",
11664
12701
  "aria-label": "\u529F\u80FD\u575E",
11665
12702
  "aria-expanded": open,
11666
12703
  onClick: () => setPanelOpen(!open)
11667
- }, import_react22.default.createElement(DockIcon, { size: wide ? 16 : 18 }), wide ? import_react22.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
12704
+ }, import_react24.default.createElement(DockIcon, { size: wide ? 16 : 18 }), wide ? import_react24.default.createElement("span", { className: "docke2-label" }, "\u529F\u80FD\u575E") : null);
11668
12705
  }
11669
12706
  function DockModal() {
11670
- const [nav, setNav] = import_react22.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
11671
- import_react22.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
12707
+ const [nav, setNav] = import_react24.default.useState({ open: panelNav.open, active: panelNav.active, params: panelNav.params });
12708
+ import_react24.default.useEffect(() => subscribePanel(() => setNav({ open: panelNav.open, active: panelNav.active, params: panelNav.params })), []);
11672
12709
  const open = nav.open || typeof document === "undefined";
11673
12710
  const active = nav.active;
11674
12711
  const setActive = navigatePanel;
11675
12712
  const navParams = nav.params;
11676
- const [, force] = import_react22.default.useReducer((n) => n + 1, 0);
12713
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
11677
12714
  useExternalVersion();
11678
- const [win, setWin] = import_react22.default.useState(() => ({ mode: "normal", x: null, y: null, w: null, h: null }));
11679
- const dlgRef = import_react22.default.useRef(null);
11680
- const contentRef = import_react22.default.useRef(null);
11681
- import_react22.default.useEffect(() => {
12715
+ const [win, setWin] = import_react24.default.useState(() => ({ mode: "normal", x: null, y: null, w: null, h: null }));
12716
+ const dlgRef = import_react24.default.useRef(null);
12717
+ const contentRef = import_react24.default.useRef(null);
12718
+ import_react24.default.useEffect(() => {
11682
12719
  if (lastGeom.w) setWin({ mode: "normal", x: lastGeom.x, y: lastGeom.y, w: lastGeom.w, h: lastGeom.h });
11683
12720
  }, []);
11684
- import_react22.default.useEffect(() => {
12721
+ import_react24.default.useEffect(() => {
11685
12722
  if (open && contentRef.current) contentRef.current.scrollTop = 0;
11686
12723
  }, [active, open]);
11687
12724
  function beginDrag(e, type) {
@@ -11719,13 +12756,13 @@ function DockModal() {
11719
12756
  const mod = isHome ? null : MODULES.find((m) => m.id === active) || MODULES[0];
11720
12757
  const st = mod ? stateOf(mod.id) : null;
11721
12758
  const View = mod ? mod.View : null;
11722
- const viewNode = mod && View ? import_react22.default.createElement(
12759
+ const viewNode = mod && View ? import_react24.default.createElement(
11723
12760
  "div",
11724
12761
  { className: "dockm-view" },
11725
- import_react22.default.createElement(
12762
+ import_react24.default.createElement(
11726
12763
  FeatureBoundary,
11727
12764
  { key: mod.id, label: mod.name },
11728
- import_react22.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
12765
+ import_react24.default.createElement(View, { ctx: ctxRef.current, feature: mod, params: navParams })
11729
12766
  )
11730
12767
  ) : null;
11731
12768
  const enabledCount = MODULES.filter((m) => {
@@ -11739,10 +12776,10 @@ function DockModal() {
11739
12776
  width: win.w != null ? win.w : void 0,
11740
12777
  height: win.mode === "min" ? "auto" : win.h != null ? win.h : void 0
11741
12778
  } : null;
11742
- return import_react22.default.createElement(
12779
+ return import_react24.default.createElement(
11743
12780
  "div",
11744
12781
  { className: "dockm-backdrop", onClick: () => setPanelOpen(false) },
11745
- import_react22.default.createElement(
12782
+ import_react24.default.createElement(
11746
12783
  "div",
11747
12784
  {
11748
12785
  className: "dockm-dialog" + (win.mode === "max" ? " dockm-max" : "") + (win.mode === "min" ? " dockm-min" : ""),
@@ -11750,41 +12787,41 @@ function DockModal() {
11750
12787
  ref: dlgRef,
11751
12788
  onClick: (e) => e.stopPropagation()
11752
12789
  },
11753
- import_react22.default.createElement(
12790
+ import_react24.default.createElement(
11754
12791
  "div",
11755
12792
  {
11756
12793
  className: "dockm-head",
11757
12794
  onPointerDown: (e) => beginDrag(e, "move"),
11758
12795
  onDoubleClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
11759
12796
  },
11760
- import_react22.default.createElement(DockIcon, null),
11761
- import_react22.default.createElement("span", { className: "dockm-title" }, "\u529F\u80FD\u575E"),
11762
- import_react22.default.createElement("span", { className: "dockm-sub" }, "dsh-dock \xB7 \u4E5F\u53EF\u5728 \u8BBE\u7F6E \u2192 \u529F\u80FD\u575E \u6253\u5F00\u7BA1\u7406\u9875"),
11763
- import_react22.default.createElement(
12797
+ import_react24.default.createElement(DockIcon, null),
12798
+ import_react24.default.createElement("span", { className: "dockm-title" }, "\u529F\u80FD\u575E"),
12799
+ 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"),
12800
+ import_react24.default.createElement(
11764
12801
  "span",
11765
12802
  { className: "dockm-ctrls" },
11766
- import_react22.default.createElement("button", {
12803
+ import_react24.default.createElement("button", {
11767
12804
  type: "button",
11768
12805
  className: "dockm-win",
11769
12806
  title: win.mode === "min" ? "\u8FD8\u539F" : "\u6700\u5C0F\u5316",
11770
12807
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "min" ? "normal" : "min" }))
11771
12808
  }, "\u2581"),
11772
- import_react22.default.createElement("button", {
12809
+ import_react24.default.createElement("button", {
11773
12810
  type: "button",
11774
12811
  className: "dockm-win",
11775
12812
  title: win.mode === "max" ? "\u8FD8\u539F" : "\u6700\u5927\u5316",
11776
12813
  onClick: () => setWin((s) => Object.assign({}, s, { mode: s.mode === "max" ? "normal" : "max" }))
11777
12814
  }, win.mode === "max" ? "\u2750" : "\u25A2"),
11778
- import_react22.default.createElement("button", { type: "button", className: "dockm-close", "aria-label": "\u5173\u95ED", title: "\u5173\u95ED", onClick: () => setPanelOpen(false) }, "\u2715")
12815
+ import_react24.default.createElement("button", { type: "button", className: "dockm-close", "aria-label": "\u5173\u95ED", title: "\u5173\u95ED", onClick: () => setPanelOpen(false) }, "\u2715")
11779
12816
  )
11780
12817
  ),
11781
- import_react22.default.createElement(
12818
+ import_react24.default.createElement(
11782
12819
  "div",
11783
12820
  { className: "dockm-body" },
11784
- import_react22.default.createElement(
12821
+ import_react24.default.createElement(
11785
12822
  "nav",
11786
12823
  { className: "dockm-nav", "aria-label": "\u529F\u80FD\u6A21\u5757" },
11787
- import_react22.default.createElement(
12824
+ import_react24.default.createElement(
11788
12825
  "button",
11789
12826
  {
11790
12827
  type: "button",
@@ -11792,10 +12829,10 @@ function DockModal() {
11792
12829
  className: "dockm-nav-item" + (isHome ? " on" : ""),
11793
12830
  onClick: () => setActive("home")
11794
12831
  },
11795
- import_react22.default.createElement("span", { className: "dockm-navhome" }, import_react22.default.createElement(DockIcon, null)),
11796
- import_react22.default.createElement("span", null, "\u9996\u9875")
12832
+ import_react24.default.createElement("span", { className: "dockm-navhome" }, import_react24.default.createElement(DockIcon, null)),
12833
+ import_react24.default.createElement("span", null, "\u9996\u9875")
11797
12834
  ),
11798
- MODULES.map((m) => import_react22.default.createElement(
12835
+ MODULES.map((m) => import_react24.default.createElement(
11799
12836
  "button",
11800
12837
  {
11801
12838
  type: "button",
@@ -11803,42 +12840,42 @@ function DockModal() {
11803
12840
  className: "dockm-nav-item" + (m.id === active ? " on" : ""),
11804
12841
  onClick: () => setActive(m.id)
11805
12842
  },
11806
- import_react22.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
11807
- import_react22.default.createElement("span", null, m.name),
11808
- m.planned ? import_react22.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
11809
- m.external ? import_react22.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8") : null
12843
+ import_react24.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
12844
+ import_react24.default.createElement("span", null, m.name),
12845
+ m.planned ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
12846
+ m.external ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8") : null
11810
12847
  ))
11811
12848
  ),
11812
- import_react22.default.createElement(
12849
+ import_react24.default.createElement(
11813
12850
  "div",
11814
12851
  { className: "dockm-content", ref: contentRef },
11815
- import_react22.default.createElement(
12852
+ import_react24.default.createElement(
11816
12853
  "div",
11817
12854
  { className: "dockm-content-head" },
11818
- import_react22.default.createElement(
12855
+ import_react24.default.createElement(
11819
12856
  "div",
11820
12857
  { className: "dockm-name" },
11821
- isHome ? import_react22.default.createElement("span", { className: "dockm-navhome" }, import_react22.default.createElement(DockIcon, null)) : import_react22.default.createElement("span", { className: "dockm-dot", style: { background: mod.accent } }),
12858
+ 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 } }),
11822
12859
  isHome ? "\u9996\u9875" : mod.name,
11823
- !isHome && mod.planned ? import_react22.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
11824
- !isHome && mod.external ? import_react22.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8\u5305" + (mod.package ? " \xB7 " + mod.package : "")) : null
12860
+ !isHome && mod.planned ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u89C4\u5212\u4E2D") : null,
12861
+ !isHome && mod.external ? import_react24.default.createElement("span", { className: "dockm-badge" }, "\u5916\u90E8\u5305" + (mod.package ? " \xB7 " + mod.package : "")) : null
11825
12862
  ),
11826
- import_react22.default.createElement(
12863
+ import_react24.default.createElement(
11827
12864
  "div",
11828
12865
  { className: "dockm-desc" },
11829
12866
  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
11830
12867
  )
11831
12868
  ),
11832
- isHome ? import_react22.default.createElement("div", { className: "dockm-view" }, import_react22.default.createElement(HomeView, { ctx: ctxRef.current, onOpen: setActive, onToggle: force })) : mod.planned ? import_react22.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_react22.default.createElement("div", { className: "dockm-note dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : import_react22.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"),
11833
- import_react22.default.createElement(
12869
+ 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"),
12870
+ import_react24.default.createElement(
11834
12871
  "div",
11835
12872
  { className: "dockm-foot" },
11836
- import_react22.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"),
11837
- !isHome && mod && !mod.planned && st ? import_react22.default.createElement(
12873
+ 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"),
12874
+ !isHome && mod && !mod.planned && st ? import_react24.default.createElement(
11838
12875
  "span",
11839
12876
  { className: "dockm-foot-sw" },
11840
- import_react22.default.createElement("span", { className: "dockm-foot-swlabel" + (st.enabled ? " on" : "") }, st.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
11841
- import_react22.default.createElement("button", {
12877
+ import_react24.default.createElement("span", { className: "dockm-foot-swlabel" + (st.enabled ? " on" : "") }, st.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528"),
12878
+ import_react24.default.createElement("button", {
11842
12879
  type: "button",
11843
12880
  className: "dock-sw" + (st.enabled ? " on" : ""),
11844
12881
  role: "switch",
@@ -11851,11 +12888,11 @@ function DockModal() {
11851
12888
  }
11852
12889
  })
11853
12890
  ) : null,
11854
- !isHome && mod && typeof mod.Chip === "function" ? import_react22.default.createElement(
12891
+ !isHome && mod && typeof mod.Chip === "function" ? import_react24.default.createElement(
11855
12892
  "span",
11856
12893
  { className: "dockm-foot-sw" },
11857
- import_react22.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(mod.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
11858
- import_react22.default.createElement("button", {
12894
+ import_react24.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(mod.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
12895
+ import_react24.default.createElement("button", {
11859
12896
  type: "button",
11860
12897
  className: "dock-sw" + (chipShown(mod.id) ? " on" : ""),
11861
12898
  role: "switch",
@@ -11871,30 +12908,30 @@ function DockModal() {
11871
12908
  )
11872
12909
  )
11873
12910
  ),
11874
- win.mode === "normal" ? import_react22.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
12911
+ win.mode === "normal" ? import_react24.default.createElement("div", { className: "dockm-resize", onPointerDown: (e) => beginDrag(e, "size") }) : null
11875
12912
  )
11876
12913
  );
11877
12914
  }
11878
12915
  function HomeView(props) {
11879
12916
  const ctx = props && props.ctx;
11880
- const [, force] = import_react22.default.useReducer((n) => n + 1, 0);
12917
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
11881
12918
  useExternalVersion();
11882
12919
  const open = (id) => {
11883
12920
  if (props && typeof props.onOpen === "function") props.onOpen(id);
11884
12921
  };
11885
- return import_react22.default.createElement(
12922
+ return import_react24.default.createElement(
11886
12923
  "div",
11887
12924
  { className: "dockh-grid" },
11888
12925
  allModules().map((m) => {
11889
12926
  const st = stateOf(m.id);
11890
12927
  const enabled = !!(st && st.enabled);
11891
12928
  const Stat = m.HomeStat;
11892
- const statNode = m.planned ? import_react22.default.createElement("span", null, PLANNED_NOTES[m.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : enabled && Stat ? import_react22.default.createElement(
12929
+ 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(
11893
12930
  FeatureBoundary,
11894
12931
  { key: m.id, label: m.name },
11895
- import_react22.default.createElement(Stat, { ctx })
11896
- ) : import_react22.default.createElement("span", null, "\u5DF2\u505C\u7528\uFF0C\u542F\u7528\u540E\u5728\u6B64\u5C55\u793A\u8FD0\u884C\u6982\u8981");
11897
- return import_react22.default.createElement(
12932
+ import_react24.default.createElement(Stat, { ctx })
12933
+ ) : import_react24.default.createElement("span", null, "\u5DF2\u505C\u7528\uFF0C\u542F\u7528\u540E\u5728\u6B64\u5C55\u793A\u8FD0\u884C\u6982\u8981");
12934
+ return import_react24.default.createElement(
11898
12935
  "div",
11899
12936
  {
11900
12937
  key: m.id,
@@ -11909,21 +12946,21 @@ function HomeView(props) {
11909
12946
  }
11910
12947
  }
11911
12948
  },
11912
- import_react22.default.createElement(
12949
+ import_react24.default.createElement(
11913
12950
  "div",
11914
12951
  { className: "dockh-head" },
11915
- import_react22.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
11916
- import_react22.default.createElement("span", { className: "dockh-name" }, m.name),
11917
- m.external ? import_react22.default.createElement("span", { className: "dockh-badge", title: m.package || void 0 }, "\u5916\u90E8") : null,
12952
+ import_react24.default.createElement("span", { className: "dockm-dot", style: { background: m.accent } }),
12953
+ import_react24.default.createElement("span", { className: "dockh-name" }, m.name),
12954
+ m.external ? import_react24.default.createElement("span", { className: "dockh-badge", title: m.package || void 0 }, "\u5916\u90E8") : null,
11918
12955
  // 状态标识:圆点 + 文字(纯展示,与开关视觉区分)
11919
- import_react22.default.createElement(
12956
+ import_react24.default.createElement(
11920
12957
  "span",
11921
12958
  { className: "dockh-status" + (m.planned ? " plan" : enabled ? "" : " off") },
11922
- import_react22.default.createElement("span", { className: "dockh-sdot" }),
11923
- import_react22.default.createElement("span", null, m.planned ? "\u89C4\u5212\u4E2D" : enabled ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u505C\u7528")
12959
+ import_react24.default.createElement("span", { className: "dockh-sdot" }),
12960
+ import_react24.default.createElement("span", null, m.planned ? "\u89C4\u5212\u4E2D" : enabled ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u505C\u7528")
11924
12961
  ),
11925
12962
  // 启停开关(规划中的功能不显示)
11926
- m.planned ? null : import_react22.default.createElement("button", {
12963
+ m.planned ? null : import_react24.default.createElement("button", {
11927
12964
  type: "button",
11928
12965
  className: "dock-sw" + (enabled ? " on" : ""),
11929
12966
  role: "switch",
@@ -11938,12 +12975,12 @@ function HomeView(props) {
11938
12975
  }
11939
12976
  })
11940
12977
  ),
11941
- import_react22.default.createElement("div", { className: "dockh-desc" }, m.description),
11942
- import_react22.default.createElement("div", { className: "dockh-stat" }, statNode),
11943
- import_react22.default.createElement(
12978
+ import_react24.default.createElement("div", { className: "dockh-desc" }, m.description),
12979
+ import_react24.default.createElement("div", { className: "dockh-stat" }, statNode),
12980
+ import_react24.default.createElement(
11944
12981
  "div",
11945
12982
  { className: "dockh-foot" },
11946
- import_react22.default.createElement("span", { className: "dockh-go" }, "\u67E5\u770B\u8BE6\u60C5 \u2192")
12983
+ import_react24.default.createElement("span", { className: "dockh-go" }, "\u67E5\u770B\u8BE6\u60C5 \u2192")
11947
12984
  )
11948
12985
  );
11949
12986
  })
@@ -11951,16 +12988,16 @@ function HomeView(props) {
11951
12988
  }
11952
12989
  function DockPanel(props) {
11953
12990
  const ctx = ctxRef.current;
11954
- const [, force] = import_react22.default.useReducer((n) => n + 1, 0);
12991
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
11955
12992
  useExternalVersion();
11956
12993
  const toggle = (id) => {
11957
12994
  toggleFeature(id);
11958
12995
  force();
11959
12996
  };
11960
- return import_react22.default.createElement(
12997
+ return import_react24.default.createElement(
11961
12998
  "div",
11962
12999
  { className: "dock-root" },
11963
- import_react22.default.createElement(
13000
+ import_react24.default.createElement(
11964
13001
  "div",
11965
13002
  { className: "dock-intro" },
11966
13003
  "\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",
@@ -11969,25 +13006,25 @@ function DockPanel(props) {
11969
13006
  allModules().map((f) => {
11970
13007
  const st = stateOf(f.id);
11971
13008
  const View = f.View;
11972
- const viewNode = !f.planned && st.enabled && View ? import_react22.default.createElement(
13009
+ const viewNode = !f.planned && st.enabled && View ? import_react24.default.createElement(
11973
13010
  "div",
11974
13011
  { className: "dock-body" },
11975
- import_react22.default.createElement(
13012
+ import_react24.default.createElement(
11976
13013
  FeatureBoundary,
11977
13014
  { key: f.id, label: f.name },
11978
- import_react22.default.createElement(View, { ctx, feature: f, params: props && props.params })
13015
+ import_react24.default.createElement(View, { ctx, feature: f, params: props && props.params })
11979
13016
  )
11980
13017
  ) : null;
11981
- return import_react22.default.createElement(
13018
+ return import_react24.default.createElement(
11982
13019
  "div",
11983
13020
  { className: "dock-card", key: f.id },
11984
- import_react22.default.createElement(
13021
+ import_react24.default.createElement(
11985
13022
  "div",
11986
13023
  { className: "dock-card-head" },
11987
- import_react22.default.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
11988
- import_react22.default.createElement("span", { className: "dock-name" }, f.name),
11989
- import_react22.default.createElement("span", { className: "dock-desc" }, f.description + (f.external ? "\uFF08\u6765\u81EA\u5916\u90E8\u5305" + (f.package ? " " + f.package : "") + "\uFF09" : "")),
11990
- f.planned ? import_react22.default.createElement("span", { className: "dock-badge" }, "\u89C4\u5212\u4E2D") : import_react22.default.createElement("button", {
13024
+ import_react24.default.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
13025
+ import_react24.default.createElement("span", { className: "dock-name" }, f.name),
13026
+ import_react24.default.createElement("span", { className: "dock-desc" }, f.description + (f.external ? "\uFF08\u6765\u81EA\u5916\u90E8\u5305" + (f.package ? " " + f.package : "") + "\uFF09" : "")),
13027
+ f.planned ? import_react24.default.createElement("span", { className: "dock-badge" }, "\u89C4\u5212\u4E2D") : import_react24.default.createElement("button", {
11991
13028
  type: "button",
11992
13029
  className: "dock-sw" + (st.enabled ? " on" : ""),
11993
13030
  role: "switch",
@@ -11996,11 +13033,11 @@ function DockPanel(props) {
11996
13033
  title: st.enabled ? "\u505C\u7528\u300C" + f.name + "\u300D" : "\u542F\u7528\u300C" + f.name + "\u300D",
11997
13034
  onClick: () => toggle(f.id)
11998
13035
  }),
11999
- !f.planned && typeof f.Chip === "function" ? import_react22.default.createElement(
13036
+ !f.planned && typeof f.Chip === "function" ? import_react24.default.createElement(
12000
13037
  "span",
12001
13038
  { className: "dockm-foot-sw" },
12002
- import_react22.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(f.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
12003
- import_react22.default.createElement("button", {
13039
+ import_react24.default.createElement("span", { className: "dockm-foot-swlabel" + (chipShown(f.id) ? " on" : "") }, "\u4F1A\u8BDD\u9875\u5C0F\u63A7\u4EF6"),
13040
+ import_react24.default.createElement("button", {
12004
13041
  type: "button",
12005
13042
  className: "dock-sw" + (chipShown(f.id) ? " on" : ""),
12006
13043
  role: "switch",
@@ -12014,22 +13051,22 @@ function DockPanel(props) {
12014
13051
  })
12015
13052
  ) : null
12016
13053
  ),
12017
- f.planned ? import_react22.default.createElement("div", { className: "dock-body" }, PLANNED_NOTES[f.id] || "\u5F85\u63A5\u5165\uFF1A\u89C1 README \u8DEF\u7EBF\u56FE") : st.error ? import_react22.default.createElement("div", { className: "dock-body dockm-err" }, "\u529F\u80FD\u51FA\u9519\uFF1A" + st.error) : null,
13054
+ 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,
12018
13055
  viewNode
12019
13056
  );
12020
13057
  })
12021
13058
  );
12022
13059
  }
12023
13060
  function DockChips(props) {
12024
- const [, force] = import_react22.default.useReducer((n) => n + 1, 0);
12025
- import_react22.default.useEffect(() => subscribeFeatureState(() => force()), []);
13061
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
13062
+ import_react24.default.useEffect(() => subscribeFeatureState(() => force()), []);
12026
13063
  const items = [];
12027
13064
  for (const f of allModules()) {
12028
13065
  if (f.planned || !stateOf(f.id).enabled || !chipShown(f.id) || typeof f.Chip !== "function") continue;
12029
- items.push(import_react22.default.createElement(
13066
+ items.push(import_react24.default.createElement(
12030
13067
  FeatureBoundary,
12031
13068
  { key: f.id, label: f.name },
12032
- import_react22.default.createElement(f.Chip, {
13069
+ import_react24.default.createElement(f.Chip, {
12033
13070
  ctx: props.ctx,
12034
13071
  feature: f,
12035
13072
  session: props.session,
@@ -12039,23 +13076,23 @@ function DockChips(props) {
12039
13076
  ));
12040
13077
  }
12041
13078
  if (items.length === 0) return null;
12042
- return import_react22.default.createElement("div", { className: "dockchip-row" }, items);
13079
+ return import_react24.default.createElement("div", { className: "dockchip-row" }, items);
12043
13080
  }
12044
13081
  function FeatureOverlays() {
12045
- const [, force] = import_react22.default.useReducer((n) => n + 1, 0);
13082
+ const [, force] = import_react24.default.useReducer((n) => n + 1, 0);
12046
13083
  useExternalVersion();
12047
- import_react22.default.useEffect(() => subscribeFeatureState(() => force()), []);
13084
+ import_react24.default.useEffect(() => subscribeFeatureState(() => force()), []);
12048
13085
  const items = [];
12049
13086
  for (const f of allModules()) {
12050
13087
  if (f.planned || !stateOf(f.id).enabled || typeof f.Overlay !== "function") continue;
12051
- items.push(import_react22.default.createElement(
13088
+ items.push(import_react24.default.createElement(
12052
13089
  FeatureBoundary,
12053
13090
  { key: f.id, label: f.name },
12054
- import_react22.default.createElement(f.Overlay, { ctx: ctxRef.current, feature: f })
13091
+ import_react24.default.createElement(f.Overlay, { ctx: ctxRef.current, feature: f })
12055
13092
  ));
12056
13093
  }
12057
13094
  if (items.length === 0) return null;
12058
- return import_react22.default.createElement(import_react22.default.Fragment, null, items);
13095
+ return import_react24.default.createElement(import_react24.default.Fragment, null, items);
12059
13096
  }
12060
13097
  var ctxRef = { current: null };
12061
13098
  function apply(ctx) {
@@ -12066,23 +13103,23 @@ function apply(ctx) {
12066
13103
  if (slots === void 0) return;
12067
13104
  slots.inject("sidebar.footer.action", () => slots.register(
12068
13105
  { name: "sidebar.footer.action", id: "dsh-dock", order: 1, label: "\u529F\u80FD\u575E" },
12069
- (props) => import_react22.default.createElement(DockEntry, props)
13106
+ (props) => import_react24.default.createElement(DockEntry, props)
12070
13107
  ));
12071
13108
  slots.inject("shell.overlay", () => slots.register(
12072
13109
  { name: "shell.overlay", id: "dsh-dock-panel", order: 21, label: "\u529F\u80FD\u575E\u9762\u677F" },
12073
- () => import_react22.default.createElement(DockModal, null)
13110
+ () => import_react24.default.createElement(DockModal, null)
12074
13111
  ));
12075
13112
  slots.inject("shell.overlay", () => slots.register(
12076
13113
  { name: "shell.overlay", id: "dsh-dock-feature-overlays", order: 22, label: "\u529F\u80FD\u575E\u5168\u5C40\u6D6E\u5C42" },
12077
- () => import_react22.default.createElement(FeatureOverlays, null)
13114
+ () => import_react24.default.createElement(FeatureOverlays, null)
12078
13115
  ));
12079
13116
  slots.inject("settings.section", () => slots.register(
12080
13117
  { name: "settings.section", id: "dsh-dock", order: 90, label: "\u529F\u80FD\u575E" },
12081
- (props) => import_react22.default.createElement(DockPanel, props)
13118
+ (props) => import_react24.default.createElement(DockPanel, props)
12082
13119
  ));
12083
13120
  slots.inject("conversation.input.left", () => slots.register(
12084
13121
  { name: "conversation.input.left", id: "dsh-dock-chips", order: 10, label: "\u529F\u80FD\u575E" },
12085
- (zone) => import_react22.default.createElement(DockChips, Object.assign({}, zone, { ctx: ctxRef.current }))
13122
+ (zone) => import_react24.default.createElement(DockChips, Object.assign({}, zone, { ctx: ctxRef.current }))
12086
13123
  ));
12087
13124
  }
12088
13125
  var inject = ["timer"];