dsh-dock 0.16.1 → 0.17.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/README.md CHANGED
@@ -19,7 +19,7 @@
19
19
  | **用量记录** | 记录全部 LLM API 调用:秒级时间筛选、Token/费用统计(**可配置各模型单价、持久保存并按自填单价计费**,支持多段分时价与周末/节假日谷价,内置峰谷计价 + 官网价目自动同步作兜底)、分组汇总、明细检索与 CSV 导出 |
20
20
  | **模型设置** | 编辑各 Provider 模型目录:输入类型(文本/图片 + 标注)与思考强度档位;图片能力可由你手动声明,新增 Provider 后进入页面自动重读目录,写回官方配置热生效 |
21
21
  | **模型提供商** | 管理自定义模型 Provider 本身:新增 / 编辑 / 删除(OpenAI 兼容、Anthropic Messages 等)、API Key 写入本机凭据库、拉取上游 `{baseURL}/models` 列表;排版同官方模型管理页。**独立功能,可单独停用**——停用后写配置与出站拉取的路由一并关闭 |
22
- | **模型余额** | 展示所有模型 Provider 账户余额(5 分钟自动刷新) |
22
+ | **模型余额** | 展示所有模型 Provider 账户余额(5 分钟自动刷新);内置「DeepSeek 账号」官网余额(走宿主登录态,充值/赠送分列,不是 API Key 余额接口) |
23
23
  | **任务动画** | 19 种任务运行动画(含星际远征、星云潮汐、曲速航道、量子雷达、星座网络、深海脉动、神经电路等),速度随任务活动联动,配置全部持久化 |
24
24
  | **任务通知** | 任务完成 / 异常 / 需确认通知:页内卡片、6 种提示音、浏览器系统通知、钉钉/飞书群机器人推送(宿主直发,浏览器关着也能推);与动画互相独立、各自启停 |
25
25
  | **运行状态** | 任务运行状态一览:进行中任务的阶段 / 耗时 / 回合 / 步骤 / 工具 / Token、等待确认提醒(等待的工具与说明)与最近完成记录(只读,与动画/通知共用同一份宿主侧追踪) |
@@ -170,6 +170,7 @@ dsh plugin --profile web add dsh-dock # 换回 npm 版
170
170
 
171
171
  1. 打开功能坞 → 模型余额
172
172
  2. 列表展示全部已配置 Provider 的余额/配额状态(每 5 分钟自动刷新,可手动「刷新」)
173
+ 3. 选的是 **「DeepSeek 账号」**(官网账号,未填 API Key)时,余额走宿主同一条登录态查官网站内余额:充值余额与赠送余额分列展示,美元按 7.2 估算为人民币;**未登录或登录失效**显示「需登录」并给出官网控制台链接,重新登录后自动恢复;金额与官网页一致按「分」截断(不四舍五入,避免显示比官网多一分钱)
173
174
 
174
175
  **任务动画**
175
176
 
@@ -283,7 +284,7 @@ dsh plugin --profile web add dsh-dock # 换回 npm 版
283
284
  - **任务动画/任务通知/运行状态不生效**:三者的路由都在宿主进程内(动画/通知的配置持久化也在宿主),旧宿主需重启 `dsh web` 加载(面板页会提示「宿主进程是旧版本」)。另注意通知与运行状态已各自独立成菜单项,需在功能坞里分别开启「任务通知」「运行状态」。
284
285
  - **用量记录空白**:确认 dsh 是较新版本且插件宿主已加载(查看启动日志含 `[dsh-dock] host half loaded`);旧宿主进程需重启 dsh web 加载新路由。
285
286
  - **费用不准 / 与实际账单对不上**:金额是按单价估算的,官网抓取来的刊例价不代表你的实际计费。在用量记录页点「单价设置」(独立子弹窗,可最大化/拖动/缩放),按模型填真实单价并保存(持久化到宿主配置),费用会立即按自填单价重算;每个模型还支持多段分时价(跨零点 / 半点边界 / 每天·仅工作日·仅周末节假日)+ 全局法定节假日列表。计价优先级为「自定义单价 > 官网同步价 > 内置价 > 兜底价」,明细里走兜底价的金额会标「兜底」。
286
- - **余额显示「需登录 / 无密钥」**:对应 Provider 未在 dsh 凭据中配置可查询余额的密钥,属正常状态提示。
287
+ - **余额显示「需登录 / 无密钥」**:对应 Provider 未在 dsh 凭据中配置可查询余额的密钥,属正常状态提示。「DeepSeek 账号」显示「需登录」则是设置里那条官方账号没登录(或登录已失效),去设置 → 模型里登录一次即可。
287
288
  - **切模型 / 打开历史会话卡住,报 `preset "…" failed to mount`**:这是该 **agent 预设**与 dsh 版本
288
289
  的 schema 漂移,不是本插件的问题。预设目录在 `~/.dsh/.agent-presets/<id>/`,dsh 升级后预设里的
289
290
  行可能不再合法(例如 `@deepseek-ai/dsh-persona` 在 0.1.5-rc.1 把 `config.text` 改为必填的
package/client.js CHANGED
@@ -40,18 +40,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
40
40
  ));
41
41
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
42
42
 
43
- // node_modules/qrcode/lib/can-promise.js
43
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/can-promise.js
44
44
  var require_can_promise = __commonJS({
45
- "node_modules/qrcode/lib/can-promise.js"(exports, module2) {
45
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/can-promise.js"(exports, module2) {
46
46
  module2.exports = function() {
47
47
  return typeof Promise === "function" && Promise.prototype && Promise.prototype.then;
48
48
  };
49
49
  }
50
50
  });
51
51
 
52
- // node_modules/qrcode/lib/core/utils.js
52
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js
53
53
  var require_utils = __commonJS({
54
- "node_modules/qrcode/lib/core/utils.js"(exports) {
54
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/utils.js"(exports) {
55
55
  var toSJISFunction;
56
56
  var CODEWORDS_COUNT = [
57
57
  0,
@@ -128,9 +128,9 @@ var require_utils = __commonJS({
128
128
  }
129
129
  });
130
130
 
131
- // node_modules/qrcode/lib/core/error-correction-level.js
131
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-level.js
132
132
  var require_error_correction_level = __commonJS({
133
- "node_modules/qrcode/lib/core/error-correction-level.js"(exports) {
133
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-level.js"(exports) {
134
134
  exports.L = { bit: 1 };
135
135
  exports.M = { bit: 0 };
136
136
  exports.Q = { bit: 3 };
@@ -173,9 +173,9 @@ var require_error_correction_level = __commonJS({
173
173
  }
174
174
  });
175
175
 
176
- // node_modules/qrcode/lib/core/bit-buffer.js
176
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-buffer.js
177
177
  var require_bit_buffer = __commonJS({
178
- "node_modules/qrcode/lib/core/bit-buffer.js"(exports, module2) {
178
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-buffer.js"(exports, module2) {
179
179
  function BitBuffer() {
180
180
  this.buffer = [];
181
181
  this.length = 0;
@@ -208,9 +208,9 @@ var require_bit_buffer = __commonJS({
208
208
  }
209
209
  });
210
210
 
211
- // node_modules/qrcode/lib/core/bit-matrix.js
211
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-matrix.js
212
212
  var require_bit_matrix = __commonJS({
213
- "node_modules/qrcode/lib/core/bit-matrix.js"(exports, module2) {
213
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/bit-matrix.js"(exports, module2) {
214
214
  function BitMatrix(size) {
215
215
  if (!size || size < 1) {
216
216
  throw new Error("BitMatrix size must be defined and greater than 0");
@@ -237,9 +237,9 @@ var require_bit_matrix = __commonJS({
237
237
  }
238
238
  });
239
239
 
240
- // node_modules/qrcode/lib/core/alignment-pattern.js
240
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alignment-pattern.js
241
241
  var require_alignment_pattern = __commonJS({
242
- "node_modules/qrcode/lib/core/alignment-pattern.js"(exports) {
242
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alignment-pattern.js"(exports) {
243
243
  var getSymbolSize = require_utils().getSymbolSize;
244
244
  exports.getRowColCoords = function getRowColCoords(version) {
245
245
  if (version === 1) return [];
@@ -272,9 +272,9 @@ var require_alignment_pattern = __commonJS({
272
272
  }
273
273
  });
274
274
 
275
- // node_modules/qrcode/lib/core/finder-pattern.js
275
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/finder-pattern.js
276
276
  var require_finder_pattern = __commonJS({
277
- "node_modules/qrcode/lib/core/finder-pattern.js"(exports) {
277
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/finder-pattern.js"(exports) {
278
278
  var getSymbolSize = require_utils().getSymbolSize;
279
279
  var FINDER_PATTERN_SIZE = 7;
280
280
  exports.getPositions = function getPositions(version) {
@@ -291,9 +291,9 @@ var require_finder_pattern = __commonJS({
291
291
  }
292
292
  });
293
293
 
294
- // node_modules/qrcode/lib/core/mask-pattern.js
294
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mask-pattern.js
295
295
  var require_mask_pattern = __commonJS({
296
- "node_modules/qrcode/lib/core/mask-pattern.js"(exports) {
296
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mask-pattern.js"(exports) {
297
297
  exports.Patterns = {
298
298
  PATTERN000: 0,
299
299
  PATTERN001: 1,
@@ -433,9 +433,9 @@ var require_mask_pattern = __commonJS({
433
433
  }
434
434
  });
435
435
 
436
- // node_modules/qrcode/lib/core/error-correction-code.js
436
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-code.js
437
437
  var require_error_correction_code = __commonJS({
438
- "node_modules/qrcode/lib/core/error-correction-code.js"(exports) {
438
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/error-correction-code.js"(exports) {
439
439
  var ECLevel = require_error_correction_level();
440
440
  var EC_BLOCKS_TABLE = [
441
441
  // L M Q H
@@ -794,9 +794,9 @@ var require_error_correction_code = __commonJS({
794
794
  }
795
795
  });
796
796
 
797
- // node_modules/qrcode/lib/core/galois-field.js
797
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/galois-field.js
798
798
  var require_galois_field = __commonJS({
799
- "node_modules/qrcode/lib/core/galois-field.js"(exports) {
799
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/galois-field.js"(exports) {
800
800
  var EXP_TABLE = new Uint8Array(512);
801
801
  var LOG_TABLE = new Uint8Array(256);
802
802
  (function initTables() {
@@ -827,9 +827,9 @@ var require_galois_field = __commonJS({
827
827
  }
828
828
  });
829
829
 
830
- // node_modules/qrcode/lib/core/polynomial.js
830
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/polynomial.js
831
831
  var require_polynomial = __commonJS({
832
- "node_modules/qrcode/lib/core/polynomial.js"(exports) {
832
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/polynomial.js"(exports) {
833
833
  var GF = require_galois_field();
834
834
  exports.mul = function mul(p1, p2) {
835
835
  const coeff = new Uint8Array(p1.length + p2.length - 1);
@@ -863,9 +863,9 @@ var require_polynomial = __commonJS({
863
863
  }
864
864
  });
865
865
 
866
- // node_modules/qrcode/lib/core/reed-solomon-encoder.js
866
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/reed-solomon-encoder.js
867
867
  var require_reed_solomon_encoder = __commonJS({
868
- "node_modules/qrcode/lib/core/reed-solomon-encoder.js"(exports, module2) {
868
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/reed-solomon-encoder.js"(exports, module2) {
869
869
  var Polynomial = require_polynomial();
870
870
  function ReedSolomonEncoder(degree) {
871
871
  this.genPoly = void 0;
@@ -895,18 +895,18 @@ var require_reed_solomon_encoder = __commonJS({
895
895
  }
896
896
  });
897
897
 
898
- // node_modules/qrcode/lib/core/version-check.js
898
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version-check.js
899
899
  var require_version_check = __commonJS({
900
- "node_modules/qrcode/lib/core/version-check.js"(exports) {
900
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version-check.js"(exports) {
901
901
  exports.isValid = function isValid(version) {
902
902
  return !isNaN(version) && version >= 1 && version <= 40;
903
903
  };
904
904
  }
905
905
  });
906
906
 
907
- // node_modules/qrcode/lib/core/regex.js
907
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/regex.js
908
908
  var require_regex = __commonJS({
909
- "node_modules/qrcode/lib/core/regex.js"(exports) {
909
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/regex.js"(exports) {
910
910
  var numeric = "[0-9]+";
911
911
  var alphanumeric = "[A-Z $%*+\\-./:]+";
912
912
  var kanji = "(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";
@@ -932,9 +932,9 @@ var require_regex = __commonJS({
932
932
  }
933
933
  });
934
934
 
935
- // node_modules/qrcode/lib/core/mode.js
935
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mode.js
936
936
  var require_mode = __commonJS({
937
- "node_modules/qrcode/lib/core/mode.js"(exports) {
937
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/mode.js"(exports) {
938
938
  var VersionCheck = require_version_check();
939
939
  var Regex = require_regex();
940
940
  exports.NUMERIC = {
@@ -1013,9 +1013,9 @@ var require_mode = __commonJS({
1013
1013
  }
1014
1014
  });
1015
1015
 
1016
- // node_modules/qrcode/lib/core/version.js
1016
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version.js
1017
1017
  var require_version = __commonJS({
1018
- "node_modules/qrcode/lib/core/version.js"(exports) {
1018
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/version.js"(exports) {
1019
1019
  var Utils = require_utils();
1020
1020
  var ECCode = require_error_correction_code();
1021
1021
  var ECLevel = require_error_correction_level();
@@ -1108,9 +1108,9 @@ var require_version = __commonJS({
1108
1108
  }
1109
1109
  });
1110
1110
 
1111
- // node_modules/qrcode/lib/core/format-info.js
1111
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/format-info.js
1112
1112
  var require_format_info = __commonJS({
1113
- "node_modules/qrcode/lib/core/format-info.js"(exports) {
1113
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/format-info.js"(exports) {
1114
1114
  var Utils = require_utils();
1115
1115
  var G15 = 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0;
1116
1116
  var G15_MASK = 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1;
@@ -1126,9 +1126,9 @@ var require_format_info = __commonJS({
1126
1126
  }
1127
1127
  });
1128
1128
 
1129
- // node_modules/qrcode/lib/core/numeric-data.js
1129
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/numeric-data.js
1130
1130
  var require_numeric_data = __commonJS({
1131
- "node_modules/qrcode/lib/core/numeric-data.js"(exports, module2) {
1131
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/numeric-data.js"(exports, module2) {
1132
1132
  var Mode = require_mode();
1133
1133
  function NumericData(data) {
1134
1134
  this.mode = Mode.NUMERIC;
@@ -1161,9 +1161,9 @@ var require_numeric_data = __commonJS({
1161
1161
  }
1162
1162
  });
1163
1163
 
1164
- // node_modules/qrcode/lib/core/alphanumeric-data.js
1164
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alphanumeric-data.js
1165
1165
  var require_alphanumeric_data = __commonJS({
1166
- "node_modules/qrcode/lib/core/alphanumeric-data.js"(exports, module2) {
1166
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/alphanumeric-data.js"(exports, module2) {
1167
1167
  var Mode = require_mode();
1168
1168
  var ALPHA_NUM_CHARS = [
1169
1169
  "0",
@@ -1240,9 +1240,9 @@ var require_alphanumeric_data = __commonJS({
1240
1240
  }
1241
1241
  });
1242
1242
 
1243
- // node_modules/qrcode/lib/core/byte-data.js
1243
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/byte-data.js
1244
1244
  var require_byte_data = __commonJS({
1245
- "node_modules/qrcode/lib/core/byte-data.js"(exports, module2) {
1245
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/byte-data.js"(exports, module2) {
1246
1246
  var Mode = require_mode();
1247
1247
  function ByteData(data) {
1248
1248
  this.mode = Mode.BYTE;
@@ -1270,9 +1270,9 @@ var require_byte_data = __commonJS({
1270
1270
  }
1271
1271
  });
1272
1272
 
1273
- // node_modules/qrcode/lib/core/kanji-data.js
1273
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/kanji-data.js
1274
1274
  var require_kanji_data = __commonJS({
1275
- "node_modules/qrcode/lib/core/kanji-data.js"(exports, module2) {
1275
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/kanji-data.js"(exports, module2) {
1276
1276
  var Mode = require_mode();
1277
1277
  var Utils = require_utils();
1278
1278
  function KanjiData(data) {
@@ -1309,9 +1309,9 @@ var require_kanji_data = __commonJS({
1309
1309
  }
1310
1310
  });
1311
1311
 
1312
- // node_modules/dijkstrajs/dijkstra.js
1312
+ // .devdeps/node_modules/.pnpm/dijkstrajs@1.0.3/node_modules/dijkstrajs/dijkstra.js
1313
1313
  var require_dijkstra = __commonJS({
1314
- "node_modules/dijkstrajs/dijkstra.js"(exports, module2) {
1314
+ ".devdeps/node_modules/.pnpm/dijkstrajs@1.0.3/node_modules/dijkstrajs/dijkstra.js"(exports, module2) {
1315
1315
  "use strict";
1316
1316
  var dijkstra = {
1317
1317
  single_source_shortest_paths: function(graph, s, d) {
@@ -1410,9 +1410,9 @@ var require_dijkstra = __commonJS({
1410
1410
  }
1411
1411
  });
1412
1412
 
1413
- // node_modules/qrcode/lib/core/segments.js
1413
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/segments.js
1414
1414
  var require_segments = __commonJS({
1415
- "node_modules/qrcode/lib/core/segments.js"(exports) {
1415
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/segments.js"(exports) {
1416
1416
  var Mode = require_mode();
1417
1417
  var NumericData = require_numeric_data();
1418
1418
  var AlphanumericData = require_alphanumeric_data();
@@ -1596,9 +1596,9 @@ var require_segments = __commonJS({
1596
1596
  }
1597
1597
  });
1598
1598
 
1599
- // node_modules/qrcode/lib/core/qrcode.js
1599
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/qrcode.js
1600
1600
  var require_qrcode = __commonJS({
1601
- "node_modules/qrcode/lib/core/qrcode.js"(exports) {
1601
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/core/qrcode.js"(exports) {
1602
1602
  var Utils = require_utils();
1603
1603
  var ECLevel = require_error_correction_level();
1604
1604
  var BitBuffer = require_bit_buffer();
@@ -1857,9 +1857,9 @@ var require_qrcode = __commonJS({
1857
1857
  }
1858
1858
  });
1859
1859
 
1860
- // node_modules/qrcode/lib/renderer/utils.js
1860
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js
1861
1861
  var require_utils2 = __commonJS({
1862
- "node_modules/qrcode/lib/renderer/utils.js"(exports) {
1862
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/utils.js"(exports) {
1863
1863
  function hex2rgba(hex) {
1864
1864
  if (typeof hex === "number") {
1865
1865
  hex = hex.toString();
@@ -1937,9 +1937,9 @@ var require_utils2 = __commonJS({
1937
1937
  }
1938
1938
  });
1939
1939
 
1940
- // node_modules/qrcode/lib/renderer/canvas.js
1940
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/canvas.js
1941
1941
  var require_canvas = __commonJS({
1942
- "node_modules/qrcode/lib/renderer/canvas.js"(exports) {
1942
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/canvas.js"(exports) {
1943
1943
  var Utils = require_utils2();
1944
1944
  function clearCanvas(ctx, canvas, size) {
1945
1945
  ctx.clearRect(0, 0, canvas.width, canvas.height);
@@ -1990,9 +1990,9 @@ var require_canvas = __commonJS({
1990
1990
  }
1991
1991
  });
1992
1992
 
1993
- // node_modules/qrcode/lib/renderer/svg-tag.js
1993
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg-tag.js
1994
1994
  var require_svg_tag = __commonJS({
1995
- "node_modules/qrcode/lib/renderer/svg-tag.js"(exports) {
1995
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg-tag.js"(exports) {
1996
1996
  var Utils = require_utils2();
1997
1997
  function getColorAttrib(color, attrib) {
1998
1998
  const alpha = color.a / 255;
@@ -2048,9 +2048,9 @@ var require_svg_tag = __commonJS({
2048
2048
  }
2049
2049
  });
2050
2050
 
2051
- // node_modules/qrcode/lib/browser.js
2051
+ // .devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/browser.js
2052
2052
  var require_browser = __commonJS({
2053
- "node_modules/qrcode/lib/browser.js"(exports) {
2053
+ ".devdeps/node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/browser.js"(exports) {
2054
2054
  var canPromise = require_can_promise();
2055
2055
  var QRCode2 = require_qrcode();
2056
2056
  var CanvasRenderer = require_canvas();
@@ -5114,6 +5114,7 @@ var ACCENT_PALETTE = ["#2563eb", "#0d9488", "#b45309", "#7c3aed", "#be185d", "#0
5114
5114
  var CURATED_ACCENTS = {
5115
5115
  "deepseek-official": "#2563eb",
5116
5116
  deepseek: "#2563eb",
5117
+ "deepseek-account": "#2563eb",
5117
5118
  "qwen-token-plan-cn": "#b45309",
5118
5119
  fangzhou: "#7c3aed",
5119
5120
  openai: "#15803d",
@@ -5132,6 +5133,13 @@ function accentOf(id) {
5132
5133
  return ACCENT_PALETTE[h % ACCENT_PALETTE.length];
5133
5134
  }
5134
5135
  var fmt = (v) => v == null || v === "" ? "\u2014" : String(v);
5136
+ function moneyText(v) {
5137
+ if (v == null || v === "") return fmt(v);
5138
+ const n = Number(v);
5139
+ if (!Number.isFinite(n)) return fmt(v);
5140
+ const cents = Math.trunc(Number((n * 100).toFixed(6)));
5141
+ return (cents / 100).toFixed(2);
5142
+ }
5135
5143
  function cnyBalanceInfo(info) {
5136
5144
  if (!info) return info;
5137
5145
  if (info.currency === "CNY") return Object.assign({}, info, { currency: "\u4EBA\u6C11\u5E01" });
@@ -5269,12 +5277,12 @@ function BalanceView(props) {
5269
5277
  "div",
5270
5278
  { key: idx, className: "dkb-main" },
5271
5279
  import_react8.default.createElement("span", { className: "dkb-main-label", style: { color: accent } }, i.currency),
5272
- import_react8.default.createElement("span", { className: "dkb-main-value" }, fmt(i.totalBalance)),
5280
+ import_react8.default.createElement("span", { className: "dkb-main-value" }, moneyText(i.totalBalance)),
5273
5281
  import_react8.default.createElement(
5274
5282
  "span",
5275
5283
  { className: "dkb-main-parts" },
5276
- i.grantedBalance != null ? import_react8.default.createElement("span", { className: "dkb-main-part", style: { color: C_GRANTED } }, "\u8D60\u9001 " + fmt(i.grantedBalance)) : null,
5277
- i.toppedUpBalance != null ? import_react8.default.createElement("span", { className: "dkb-main-part", style: { color: C_TOPUP } }, "\u5145\u503C " + fmt(i.toppedUpBalance)) : null
5284
+ i.grantedBalance != null ? import_react8.default.createElement("span", { className: "dkb-main-part", style: { color: C_GRANTED } }, "\u8D60\u9001 " + moneyText(i.grantedBalance)) : null,
5285
+ i.toppedUpBalance != null ? import_react8.default.createElement("span", { className: "dkb-main-part", style: { color: C_TOPUP } }, "\u5145\u503C " + moneyText(i.toppedUpBalance)) : null
5278
5286
  )
5279
5287
  );
5280
5288
  })
@@ -5399,7 +5407,7 @@ function chipBalanceText(p) {
5399
5407
  if (!info) return "\u4F59\u989D \u2026";
5400
5408
  const cur = info.currency === "CNY" || info.currency === "\u4EBA\u6C11\u5E01\uFF08\u4F30\u7B97\uFF09" ? "\xA5" : "";
5401
5409
  const v = Number(info.totalBalance);
5402
- const s = Number.isFinite(v) ? v >= 1e4 ? (v / 1e4).toFixed(2) + "\u4E07" : String(Math.round(v * 100) / 100) : fmt(info.totalBalance);
5410
+ const s = Number.isFinite(v) ? v >= 1e4 ? moneyText(v / 1e4) + "\u4E07" : moneyText(v) : fmt(info.totalBalance);
5403
5411
  return "\u4F59\u989D " + cur + s;
5404
5412
  }
5405
5413
  function BalanceChip(props) {
@@ -13886,7 +13894,7 @@ var feature13 = {
13886
13894
  };
13887
13895
 
13888
13896
  // src/client.jsx
13889
- var DOCK_VERSION = "0.16.1";
13897
+ var DOCK_VERSION = "0.17.0";
13890
13898
  var BUILTIN_FEATURES = [feature, feature2, feature3, feature4, feature5, feature6, feature7, feature8, feature9, feature10, feature11, feature12, feature13];
13891
13899
  var PLANNED_FEATURES = [];
13892
13900
  var PLANNED_NOTES = {};
@@ -3,7 +3,10 @@
3
3
  // 在回环 webServer 上注册 /dsh-dock/balance 路由:枚举所有已配置的模型 Provider,
4
4
  // 按余额策略查询各账号余额/配额,返回归一化 JSON 给浏览器半身(同源 fetch,无需 typert)。
5
5
  // 余额策略表沿用 @wycto/dsh-balance-panel@0.1.1 的实现(MIT,同作者)。
6
+ // 「DeepSeek 账号」这条官方 Provider 没有 API Key 余额接口,余额在官网站内:
7
+ // 改走宿主 deepseekAccount 服务(设置里「DeepSeek 账号 · 已登录」的同一份登录态)。
6
8
  import { credentialRef } from '@deepseek-ai/dsh-credentials'
9
+ import { APP_IDENTITY } from '@deepseek-ai/dsh-llm'
7
10
  import { sendJson, walkPath, rejectUntrustedRequest } from '../../src/host-core.js'
8
11
 
9
12
  /** deepseek-official 内置默认值(适配器默认配置的镜像,配置缺失时兜底)。 */
@@ -12,6 +15,13 @@ const DEEPSEEK_DEFAULTS = {
12
15
  baseURL: 'https://api.deepseek.com',
13
16
  }
14
17
 
18
+ /** 官方 DeepSeek 账号 Provider(llm-deepseek-account 注册的 id;余额来自官网账号,不是 API Key)。 */
19
+ const ACCOUNT_PROVIDER_ID = 'deepseek-account'
20
+ /** 账号 Provider 的中文显示名(宿主 entry 的 displayName 是英文 'DeepSeek Account')。 */
21
+ const ACCOUNT_PROVIDER_NAME = 'DeepSeek 账号'
22
+ /** 账号未登录 / 查询失败时的兜底控制台地址(正常从 getState().links 取)。 */
23
+ const ACCOUNT_FALLBACK_URL = 'https://platform.deepseek.com/usage'
24
+
15
25
  function parseDeepSeek(body) {
16
26
  const infos = body && Array.isArray(body.balance_infos) ? body.balance_infos : []
17
27
  if (infos.length === 0) return { status: 'error', message: '无法识别的余额响应' }
@@ -129,6 +139,109 @@ function parseXai(body) {
129
139
  }
130
140
  }
131
141
 
142
+ /** 官网账号余额的 client metadata:Platform 用版本/语言/时区生成请求头
143
+ * (见 dsh 的 accountClientMetadata;时区取本机,正值=东经秒)。 */
144
+ function accountClientMetadata() {
145
+ return {
146
+ version: APP_IDENTITY.version,
147
+ locale: 'zh-CN',
148
+ timezoneOffsetSeconds: -new Date().getTimezoneOffset() * 60,
149
+ }
150
+ }
151
+
152
+ /** 金额字符串化:去浮点尾巴(0.1+0.2 这类),最多保留四位小数。 */
153
+ function moneyText(value) {
154
+ const n = Number(value)
155
+ return Number.isFinite(n) ? String(Math.round(n * 1e4) / 1e4) : '0'
156
+ }
157
+
158
+ /**
159
+ * 把官网账号的钱包投影成前端统一的 currency infos:
160
+ * normal_wallets(充值钱包,AccountDetails.balance.value)→ toppedUpBalance,
161
+ * bonus_wallets(赠送钱包)→ grantedBalance,total = 两者之和。
162
+ * 有非零币种时隐藏全零币种(否则国内账号会多出一张「人民币(估算)0」的美元卡);
163
+ * 钱包全空时兜底一张 CNY 0,避免前端出现空白卡片。
164
+ */
165
+ function parseAccountWallets(detail) {
166
+ const byCurrency = new Map()
167
+ const add = (wallets, field) => {
168
+ for (const wallet of Array.isArray(wallets) ? wallets : []) {
169
+ if (!wallet || typeof wallet.currency !== 'string') continue
170
+ const amount = Number(wallet.balance)
171
+ if (!Number.isFinite(amount)) continue
172
+ const currency = wallet.currency.toUpperCase()
173
+ const slot = byCurrency.get(currency) || { currency, granted: 0, toppedUp: 0 }
174
+ slot[field] += amount
175
+ byCurrency.set(currency, slot)
176
+ }
177
+ }
178
+ add(detail.value, 'toppedUp')
179
+ add(detail.bonusWallets, 'granted')
180
+ const order = ['CNY', 'USD']
181
+ let infos = Array.from(byCurrency.values())
182
+ .sort((a, b) => order.indexOf(a.currency) - order.indexOf(b.currency))
183
+ .map((s) => ({
184
+ currency: s.currency,
185
+ totalBalance: moneyText(s.toppedUp + s.granted),
186
+ grantedBalance: moneyText(s.granted),
187
+ toppedUpBalance: moneyText(s.toppedUp),
188
+ }))
189
+ const nonzero = infos.filter((info) => Number(info.totalBalance) !== 0)
190
+ if (nonzero.length > 0) infos = nonzero
191
+ else if (infos.length === 0) {
192
+ infos = [{ currency: 'CNY', totalBalance: '0', grantedBalance: '0', toppedUpBalance: '0' }]
193
+ } else {
194
+ // 全零:只留一张兜底卡(优先 CNY),别把 0 美元的「人民币(估算)」卡也摆出来
195
+ infos = [infos.find((info) => info.currency === 'CNY') || infos[0]]
196
+ }
197
+ return { status: 'ok', kind: 'currency', available: true, infos }
198
+ }
199
+
200
+ /**
201
+ * 查询「DeepSeek 账号」的官网余额(走宿主 deepseekAccount 服务,不是 HTTP API Key)。
202
+ * 未登录 / 登录失效都归为 login-required(前端显示「需登录」并给控制台链接),
203
+ * 平台失败归为 error(绝不把失败伪装成 0 余额)。
204
+ */
205
+ async function queryOfficialAccountBalance(ctx) {
206
+ const fallbackUrl = ACCOUNT_FALLBACK_URL
207
+ let account
208
+ try {
209
+ account = ctx.get('deepseekAccount')
210
+ } catch {
211
+ account = undefined
212
+ }
213
+ if (!account || typeof account.getState !== 'function' || typeof account.getBalance !== 'function') {
214
+ return { status: 'unsupported', message: '当前宿主未挂载 DeepSeek 账号服务(需在设置里登录 DeepSeek 账号)' }
215
+ }
216
+
217
+ let state
218
+ try {
219
+ state = await account.getState()
220
+ } catch (e) {
221
+ return { status: 'error', message: '读取 DeepSeek 账号状态失败:' + (e && e.message ? e.message : String(e)) }
222
+ }
223
+ const links = state && state.links ? state.links : {}
224
+ const consoleUrl = typeof links.usageUrl === 'string' && links.usageUrl ? links.usageUrl : fallbackUrl
225
+ if (!state || state.status !== 'credential-stored') {
226
+ return { status: 'login-required', consoleUrl, message: 'DeepSeek 账号未登录,登录后可查看官网余额' }
227
+ }
228
+
229
+ let detail
230
+ try {
231
+ detail = await account.getBalance(accountClientMetadata())
232
+ } catch (e) {
233
+ return { status: 'error', message: '查询官网余额失败:' + (e && e.message ? e.message : String(e)) }
234
+ }
235
+ // null = 凭证已失效/被移除(平台返回 401 时账号服务会清掉 grant,这里按需重新登录处理)
236
+ if (detail === null) {
237
+ return { status: 'login-required', consoleUrl, message: 'DeepSeek 账号登录已失效,请重新登录' }
238
+ }
239
+ if (!detail || detail.status !== 'ready') {
240
+ return { status: 'error', message: '官网余额查询失败(平台接口返回失败)' }
241
+ }
242
+ return parseAccountWallets(detail)
243
+ }
244
+
132
245
  /** 策略表:key 为规范 provider id,aliases 为别名。 */
133
246
  const STRATEGIES = {
134
247
  deepseek: {
@@ -314,7 +427,10 @@ function collectProviders(ctx) {
314
427
 
315
428
  out.set(e.provider, {
316
429
  id: e.provider,
317
- displayName: (profile && typeof profile.displayName === 'string' && profile.displayName) || e.displayName || e.provider,
430
+ displayName: (profile && typeof profile.displayName === 'string' && profile.displayName)
431
+ || (e.provider === ACCOUNT_PROVIDER_ID ? ACCOUNT_PROVIDER_NAME : undefined)
432
+ || e.displayName
433
+ || e.provider,
318
434
  apiKeyEnv,
319
435
  baseURL,
320
436
  api,
@@ -328,7 +444,7 @@ function collectProviders(ctx) {
328
444
  const isDeepseek = sel.provider === 'deepseek-official' || sel.provider === 'deepseek'
329
445
  out.set(sel.provider, {
330
446
  id: sel.provider,
331
- displayName: sel.provider,
447
+ displayName: sel.provider === ACCOUNT_PROVIDER_ID ? ACCOUNT_PROVIDER_NAME : sel.provider,
332
448
  apiKeyEnv: isDeepseek ? DEEPSEEK_DEFAULTS.apiKeyEnv : undefined,
333
449
  baseURL: isDeepseek ? DEEPSEEK_DEFAULTS.baseURL : undefined,
334
450
  api: isDeepseek ? 'deepseek' : undefined,
@@ -405,6 +521,12 @@ async function queryProviderBalance(ctx, p) {
405
521
  }
406
522
  }
407
523
 
524
+ // 0) 官方 DeepSeek 账号:余额在官网站内,走宿主 deepseekAccount 服务(没有 API Key 余额接口)
525
+ if (String(p.id).toLowerCase() === ACCOUNT_PROVIDER_ID) {
526
+ entry.balance = await queryOfficialAccountBalance(ctx)
527
+ return entry
528
+ }
529
+
408
530
  // 1) 自定义 balance 配置优先
409
531
  const custom = p.profile && typeof p.profile.balance === 'object' && p.profile.balance !== null
410
532
  ? p.profile.balance
@@ -10,6 +10,7 @@ const ACCENT_PALETTE = ['#2563eb', '#0d9488', '#b45309', '#7c3aed', '#be185d', '
10
10
  const CURATED_ACCENTS = {
11
11
  'deepseek-official': '#2563eb',
12
12
  deepseek: '#2563eb',
13
+ 'deepseek-account': '#2563eb',
13
14
  'qwen-token-plan-cn': '#b45309',
14
15
  fangzhou: '#7c3aed',
15
16
  openai: '#15803d',
@@ -32,6 +33,16 @@ function accentOf(id) {
32
33
  return ACCENT_PALETTE[h % ACCENT_PALETTE.length];
33
34
  }
34
35
  const fmt = (v) => (v == null || v === '' ? '—' : String(v));
36
+ // 金额展示统一按「分」截断(不四舍五入)并固定两位小数,与官网 platform.deepseek.com 的口径一致:
37
+ // 账号真实余额是 77.6772,官网显示 ¥77.67,四舍五入会显示成 77.68——比官网多一分钱(实际踩到过)。
38
+ // 先 toFixed(6) 抹掉二进制浮点误差(如 0.29*100 = 28.999…)再向零截断。
39
+ function moneyText(v) {
40
+ if (v == null || v === '') return fmt(v);
41
+ const n = Number(v);
42
+ if (!Number.isFinite(n)) return fmt(v);
43
+ const cents = Math.trunc(Number((n * 100).toFixed(6)));
44
+ return (cents / 100).toFixed(2);
45
+ }
35
46
  function cnyBalanceInfo(info) {
36
47
  if (!info) return info;
37
48
  if (info.currency === 'CNY') return Object.assign({}, info, { currency: '人民币' });
@@ -147,10 +158,10 @@ function BalanceView(props) {
147
158
  const i = cnyBalanceInfo(rawInfo);
148
159
  return react.createElement("div", { key: idx, className: "dkb-main" },
149
160
  react.createElement("span", { className: "dkb-main-label", style: { color: accent } }, i.currency),
150
- react.createElement("span", { className: "dkb-main-value" }, fmt(i.totalBalance)),
161
+ react.createElement("span", { className: "dkb-main-value" }, moneyText(i.totalBalance)),
151
162
  react.createElement("span", { className: "dkb-main-parts" },
152
- i.grantedBalance != null ? react.createElement("span", { className: "dkb-main-part", style: { color: C_GRANTED } }, "赠送 " + fmt(i.grantedBalance)) : null,
153
- i.toppedUpBalance != null ? react.createElement("span", { className: "dkb-main-part", style: { color: C_TOPUP } }, "充值 " + fmt(i.toppedUpBalance)) : null));
163
+ i.grantedBalance != null ? react.createElement("span", { className: "dkb-main-part", style: { color: C_GRANTED } }, "赠送 " + moneyText(i.grantedBalance)) : null,
164
+ i.toppedUpBalance != null ? react.createElement("span", { className: "dkb-main-part", style: { color: C_TOPUP } }, "充值 " + moneyText(i.toppedUpBalance)) : null));
154
165
  }));
155
166
  } else if (b && b.status === "login-required" && b.consoleUrl) {
156
167
  balBody = react.createElement("div", { className: "dkb-main" },
@@ -265,7 +276,7 @@ function chipBalanceText(p) {
265
276
  if (!info) return "余额 …";
266
277
  const cur = info.currency === "CNY" || info.currency === "人民币(估算)" ? "¥" : "";
267
278
  const v = Number(info.totalBalance);
268
- const s = Number.isFinite(v) ? (v >= 10000 ? (v / 10000).toFixed(2) + "万" : String(Math.round(v * 100) / 100)) : fmt(info.totalBalance);
279
+ const s = Number.isFinite(v) ? (v >= 10000 ? moneyText(v / 10000) + "万" : moneyText(v)) : fmt(info.totalBalance);
269
280
  return "余额 " + cur + s;
270
281
  }
271
282
  function BalanceChip(props) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-dock",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "description": "DeepSeek Harness 功能坞插件(dsh-dock):模块化功能中枢——每个功能一个 features/ 模块(可单独提取成包发布,又可经 dockBridge 装回面板)。含用量记录(LLM 调用记账/费用统计,支持各模型自定义单价、多段分时价与周末/节假日谷价)、模型设置、图片理解代理、模型余额、任务动画(19 种运行动画 + 桌面伙伴 3D 场景)、任务通知(完成/异常/需确认通知、提示音、系统通知、钉钉/飞书推送)、运行状态(进行中任务与最近完成一览)、语音朗读(浏览器 TTS 读回复:回合下方喇叭按钮 + 自动朗读);侧栏入口 + 可拖拽弹窗(最大化/最小化/缩放)。",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -43,7 +43,7 @@
43
43
  "scripts": {
44
44
  "build:client": "node scripts/build-client.mjs",
45
45
  "test:client": "node scripts/test-client-views.mjs",
46
- "test:host": "node scripts/test-task-host.mjs && node scripts/test-tokenlog-host.mjs && node scripts/test-route-trust-host.mjs && node scripts/test-tts-host.mjs && node scripts/test-legacy-import.mjs && node scripts/test-mobile-host.mjs && node scripts/test-mobile-relay-host.mjs && node scripts/test-mobile-relay.mjs && node scripts/test-welcome-ack.mjs",
46
+ "test:host": "node scripts/test-task-host.mjs && node scripts/test-tokenlog-host.mjs && node scripts/test-balance-host.mjs && node scripts/test-route-trust-host.mjs && node scripts/test-tts-host.mjs && node scripts/test-legacy-import.mjs && node scripts/test-mobile-host.mjs && node scripts/test-mobile-relay-host.mjs && node scripts/test-mobile-relay.mjs && node scripts/test-welcome-ack.mjs",
47
47
  "dev:client": "node scripts/watch-client.mjs",
48
48
  "dev:link": "node scripts/dev-link-deps.mjs"
49
49
  },
package/src/client.jsx CHANGED
@@ -33,7 +33,7 @@ import { feature as fMobileRelay } from "../features/mobile-relay/view.jsx";
33
33
  import { feature as fMobile } from "../features/mobile/view.js";
34
34
 
35
35
  const name = "dsh-dock";
36
- const DOCK_VERSION = "0.16.1";
36
+ const DOCK_VERSION = "0.17.0";
37
37
 
38
38
  // ---- 内置功能注册表:新功能 = features/<id>/ 加模块 + 这里 import 一行 ----
39
39
  const BUILTIN_FEATURES = [fTokenlog, fModelconfig, fProviderConfig, fHeartbeat, fTheme, fBalance, fAnimation, fNotify, fRunState, fTts, fGames, fMobileRelay, fMobile];