dsh-dock 0.13.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.
@@ -10,12 +10,12 @@
10
10
  // features/runstate/,本模块只管通知(页内卡片 / 提示音 / 系统通知 / 钉钉飞书群机器人推送)。
11
11
  // 模块启停 = 功能坞里的开关(独立菜单项),本页不再有第二个总开关。
12
12
  //
13
- // Host 通信:fetch('/dsh-dock/notify/<method>')(见 features/notify/host.js)。
13
+ // Host 通信:fetch('dsh-dock/notify/<method>')(见 features/notify/host.js)。
14
14
  import { useState, useEffect, useRef, useCallback } from "react";
15
15
 
16
16
  // ---------- Host RPC 桥接 ----------
17
17
  function rpcCall(method, args) {
18
- return fetch("/dsh-dock/notify/" + method, {
18
+ return fetch("dsh-dock/notify/" + method, {
19
19
  method: "POST",
20
20
  headers: { "content-type": "application/json" },
21
21
  body: JSON.stringify(args === undefined ? {} : args),
@@ -8,12 +8,12 @@
8
8
  // 共用同一份实例),本模块不写任何配置——动效在 features/animation/、结束与确认提醒在
9
9
  // features/notify/。没有全局浮层,因此只在面板打开时轮询,关闭面板即零开销。
10
10
  //
11
- // Host 通信:fetch('/dsh-dock/runstate/status')(见 features/runstate/host.js)。
11
+ // Host 通信:fetch('dsh-dock/runstate/status')(见 features/runstate/host.js)。
12
12
  import { useState, useEffect } from "react";
13
13
 
14
14
  // ---------- Host RPC 桥接 ----------
15
15
  function rpcCall(method, args) {
16
- return fetch("/dsh-dock/runstate/" + method, {
16
+ return fetch("dsh-dock/runstate/" + method, {
17
17
  method: "POST",
18
18
  headers: { "content-type": "application/json" },
19
19
  body: JSON.stringify(args === undefined ? {} : args),
@@ -8,13 +8,13 @@
8
8
  // - 挂载即扫描历史+按暂存条件查询;挂载期间每 5s 静默自动刷新
9
9
  // - 查询等待动画:点「查询」后按钮转圈扫光 + 数据区顶部「记账小队清点」banner(轮换俏皮文案,
10
10
  // 等久了换语气),旧数据压暗禁点;结果到位时闪一次「✓ 数据已更新」并让 KPI 卡回弹
11
- // Host 通信:fetch('/dsh-dock/tokenlog/<method>')(见 features/tokenlog/host.js)。
11
+ // Host 通信:fetch('dsh-dock/tokenlog/<method>')(见 features/tokenlog/host.js)。
12
12
  import react, { useState, useEffect, useCallback, useMemo, useRef } from "react";
13
13
  import { openPanel } from "../../src/shared.js";
14
14
 
15
15
  // ---------- Host RPC 桥接 ----------
16
16
  function rpcCall(method, args) {
17
- return fetch("/dsh-dock/tokenlog/" + method, {
17
+ return fetch("dsh-dock/tokenlog/" + method, {
18
18
  method: "POST",
19
19
  headers: { "content-type": "application/json" },
20
20
  body: JSON.stringify(args === undefined ? {} : args),
package/index.js CHANGED
@@ -15,8 +15,10 @@
15
15
  // - animation 任务动画(v0.5.0):会话任务追踪 + 动效配置持久化(参照 @wycto/dsh-task-pulse)
16
16
  // - notify 任务通知:完成/异常/需确认通知 + 提示音/系统通知/钉钉飞书推送(从任务动画拆出)
17
17
  // - runstate 运行状态:进行中任务与最近完成一览(从任务动画拆出;只读,无配置段)
18
- // - mobile-relay 手机接力(未发布):扫码反向代理接力 + 局域网电脑直连(0.0.0.0)
18
+ // - mobile 手机适配:窄屏排版/Tab 栏/抽屉/遮罩/键盘(宿主经 tapIndex 注入 index.html)
19
+ // - mobile-relay 远程访问:账号密码登录的远程入口(网关 + 账号 + 浏览模式目录选择器)
19
20
  import { DockConfig, sendJson, readBody, migrateNotifyConfig, migrateModelsFeatureId, migrateImportedFeatures, migrateImportedSections, bindDockConfig, readDockRoot, mutateDockSection } from './src/host-core.js'
21
+ import { injectWelcomeAck } from './src/welcome-ack.js'
20
22
  import { feature as fModels } from './features/modelconfig/host.js'
21
23
  import { feature as fVisionProxy } from './features/visionproxy/host.js'
22
24
  import { feature as fBalance } from './features/balance/host.js'
@@ -25,6 +27,7 @@ import { feature as fAnimation } from './features/animation/host.js'
25
27
  import { feature as fNotify } from './features/notify/host.js'
26
28
  import { feature as fRunState } from './features/runstate/host.js'
27
29
  import { feature as fMobileRelay } from './features/mobile-relay/host.js'
30
+ import { feature as fMobile } from './features/mobile/host.js'
28
31
 
29
32
  export const name = 'dsh-dock'
30
33
 
@@ -66,6 +69,7 @@ export function apply(ctx, config) {
66
69
  fNotify,
67
70
  fRunState,
68
71
  fMobileRelay,
72
+ fMobile,
69
73
  ]
70
74
 
71
75
  // 绑定 Config 镜像(替代已移除的 settings.get);volatile 字段热更时重绑。
@@ -170,6 +174,16 @@ export function apply(ctx, config) {
170
174
  })
171
175
  })
172
176
 
177
+ // 插件级兼容注入(不随功能开关启停):远程(非回环)浏览器的「预览版说明」自动确认。
178
+ // 根因与归属见 src/welcome-ack.js 文件头——关掉远程访问、主实例直接绑 0.0.0.0 的
179
+ // 直连形态同样每次重弹,所以不能挂在【远程访问】名下;回环地址脚本自我短路。
180
+ {
181
+ const webServer = ctx.get('webServer')
182
+ if (webServer && typeof webServer.tapIndex === 'function') {
183
+ ctx.effect(() => webServer.tapIndex(injectWelcomeAck), 'dsh-dock: welcome-ack index tap')
184
+ }
185
+ }
186
+
173
187
  // 功能开关管理路由(无条件注册):GET 查询各功能宿主侧状态;POST 同步开关——
174
188
  // 浏览器面板 toggle 经此写入 settings(跨浏览器/重启保持)并即时 setup/dispose 宿主半部。
175
189
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-dock",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "DeepSeek Harness 功能坞插件(dsh-dock):模块化功能中枢——每个功能一个 features/ 模块(可单独提取成包发布,又可经 dockBridge 装回面板)。含用量记录(LLM 调用记账/费用统计,支持各模型自定义单价、多段分时价与周末/节假日谷价)、模型设置、图片理解代理、模型余额、任务动画(19 种运行动画 + 桌面伙伴 3D 场景)、任务通知(完成/异常/需确认通知、提示音、系统通知、钉钉/飞书推送)、运行状态(进行中任务与最近完成一览);侧栏入口 + 可拖拽弹窗(最大化/最小化/缩放)。",
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-legacy-import.mjs && node scripts/test-mobile-relay-host.mjs && node scripts/test-mobile-relay.mjs",
46
+ "test:host": "node scripts/test-task-host.mjs && node scripts/test-tokenlog-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
  },
@@ -64,5 +64,11 @@
64
64
  "@deepseek-ai/dsh-llm": "*",
65
65
  "@deepseek-ai/dsh-settings": "*",
66
66
  "@deepseek-ai/schemastery": "*"
67
+ },
68
+ "allowScripts": {
69
+ "file:../esbuild@0.28.1/node_modules/esbuild": true,
70
+ "file:../../esbuild@0.28.1/node_modules/esbuild": true,
71
+ "file:../../esbuild@0.25.12/node_modules/esbuild": true,
72
+ "file:../../esbuild@0.21.5/node_modules/esbuild": true
67
73
  }
68
- }
74
+ }
Binary file
package/src/client.jsx CHANGED
@@ -31,7 +31,7 @@ import { feature as fMobileRelay } from "../features/mobile-relay/view.jsx";
31
31
  import { feature as fMobile } from "../features/mobile/view.js";
32
32
 
33
33
  const name = "dsh-dock";
34
- const DOCK_VERSION = "0.13.0";
34
+ const DOCK_VERSION = "0.14.0";
35
35
 
36
36
  // ---- 内置功能注册表:新功能 = features/<id>/ 加模块 + 这里 import 一行 ----
37
37
  const BUILTIN_FEATURES = [fTokenlog, fModelconfig, fHeartbeat, fTheme, fBalance, fAnimation, fNotify, fRunState, fGames, fMobileRelay, fMobile];
package/src/shared.js CHANGED
@@ -68,11 +68,14 @@ export function initFeatureState(defs) {
68
68
  syncFeatureStateFromHost(defs);
69
69
  }
70
70
 
71
- /** 从宿主 /dsh-dock/features 拉取持久化开关,覆盖尚未本地表态的功能默认值。
71
+ /** 从宿主 dsh-dock/features 拉取持久化开关,覆盖尚未本地表态的功能默认值。
72
+ * 路由一律用文档相对路径(不带前导斜杠):DSH 的 index.html 带 <base href="./">,
73
+ * 子路径反代(如 /ui/)下自动解析为 /ui/dsh-dock/...,根挂载下即 dsh-dock/...。
74
+ * 写死前导斜杠会绕过反代挂载前缀,请求被 302 打回应用入口,宿主接口整片失败。
72
75
  * 拉取失败(宿主旧版本无此路由)静默降级——沿用本地默认。 */
73
76
  function syncFeatureStateFromHost(defs) {
74
77
  if (typeof fetch !== "function") return;
75
- fetch("/dsh-dock/features").then(async (res) => {
78
+ fetch("dsh-dock/features").then(async (res) => {
76
79
  if (!res.ok) return;
77
80
  const data = await res.json().catch(() => null);
78
81
  const persisted = data && data.ok && data.data && data.data.persisted;
@@ -108,7 +111,7 @@ function syncFeatureStateFromHost(defs) {
108
111
  * 开关永远 404 而这里毫无声息,排查了两个版本才发现。) */
109
112
  function pushFeatureEnabledToHost(id, enabled) {
110
113
  if (typeof fetch !== "function") return;
111
- fetch("/dsh-dock/features", {
114
+ fetch("dsh-dock/features", {
112
115
  method: "POST",
113
116
  headers: { "content-type": "application/json" },
114
117
  body: JSON.stringify({ id, enabled }),
@@ -0,0 +1,69 @@
1
+ // dsh-dock · 插件级兼容注入:远程(非回环)浏览器的「预览版说明」自动确认
2
+ //
3
+ // 根因(dsh 0.2.0 ui-settings-models/src/client/welcome-store.ts,文件头注释原文):
4
+ // 回环浏览器的确认走宿主持久化,一次确认永久生效;**远程(非回环)浏览器的设置 scope
5
+ // 是 memory 模式,确认只存页面进程内存,刷新即丢**——所以从局域网/组网 IP 打开时
6
+ // 「预览版说明」每次刷新都重弹,profile patch 里钉 welcomeNoticeVersion 也救不了
7
+ // (memory 分支根本不读持久值)。
8
+ //
9
+ // 归属:这是「非回环浏览器」这一访问形态的兼容问题,与任何一个功能模块的职责都不重合——
10
+ // 【远程访问】只保留远程入口本身(用户要求),而关掉远程访问、主实例经 patch 层绑 0.0.0.0
11
+ // 的直连形态(公司部署)同样会每次重弹。所以挂在插件级(index.js 注册 tapIndex),
12
+ // 不随任何功能开关启停;回环地址自我短路,让 dsh 原生的一次性持久确认自然工作。
13
+ //
14
+ // 与【远程访问】网关的关系:网关代理的页面由网关对连接 bundle 做回环自判改写,
15
+ // 确认可持久化、弹窗首次确认后不再出现,本脚本找不到弹窗即零副作用;直连形态下
16
+ // 本脚本每次页面加载最多替用户点一次「继续」。dsh 未来若让远程确认可持久化,
17
+ // 弹窗不再出现,本脚本自动空转,无需随版本跟进。
18
+ //
19
+ // 注入点在 <head> 之后,body 尚未解析:观察器一律推迟到 DOMContentLoaded 再挂。
20
+ const WELCOME_ACK_JS = [
21
+ ';(function(){',
22
+ 'if (window.__dshDockWelcomeAck) return;',
23
+ 'window.__dshDockWelcomeAck = "host";',
24
+ 'var host = (window.location && window.location.hostname) || "";',
25
+ 'if (host === "127.0.0.1" || host === "localhost" || host === "::1" || host.slice(-10) === ".localhost") return;',
26
+ 'if (typeof MutationObserver === "undefined") return;',
27
+ 'var done = false;',
28
+ 'var observer = null;',
29
+ 'function tryDismiss() {',
30
+ ' if (done || !document.body) return;',
31
+ ' var dialogs = document.querySelectorAll(\'[role="dialog"]\');',
32
+ ' for (var i = 0; i < dialogs.length; i++) {',
33
+ ' if (!/预览版说明|Preview Notice/.test(dialogs[i].textContent || "")) continue;',
34
+ ' var buttons = dialogs[i].querySelectorAll("button");',
35
+ ' for (var j = 0; j < buttons.length; j++) {',
36
+ ' var label = (buttons[j].textContent || "").replace(/^\\s+|\\s+$/g, "");',
37
+ ' if (label === "继续" || label === "Continue") {',
38
+ ' done = true;',
39
+ ' buttons[j].click();',
40
+ ' if (observer) observer.disconnect();',
41
+ ' return;',
42
+ ' }',
43
+ ' }',
44
+ ' break;',
45
+ ' }',
46
+ '}',
47
+ 'function start() {',
48
+ ' observer = new MutationObserver(tryDismiss);',
49
+ ' observer.observe(document.body, { childList: true, subtree: true });',
50
+ ' tryDismiss();',
51
+ // 兜底停止:说明若 60 秒内没出现(未来版本改版/被官方移除),观察器自动退场
52
+ ' setTimeout(function () { if (observer) observer.disconnect(); }, 60000);',
53
+ '}',
54
+ 'if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start);',
55
+ 'else start();',
56
+ '})();',
57
+ ].join('\n')
58
+ const WELCOME_ACK_MARKER = 'data-dsh-dock-welcome-ack'
59
+ export { WELCOME_ACK_MARKER }
60
+
61
+ /** 把「预览版说明」自动确认脚本内联注入 index.html 的 <head> 之后(幂等)。 */
62
+ export function injectWelcomeAck(html) {
63
+ if (html.includes(WELCOME_ACK_MARKER)) return html
64
+ const match = /<head(?:\s[^>]*)?>/i.exec(html)
65
+ const script = `<script ${WELCOME_ACK_MARKER}>${WELCOME_ACK_JS}</script>`
66
+ if (!match) return script + html
67
+ const at = match.index + match[0].length
68
+ return html.slice(0, at) + script + html.slice(at)
69
+ }