dsh-dock 0.9.6 → 0.9.8

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.
Files changed (35) hide show
  1. package/LICENSE +18 -18
  2. package/README.md +325 -325
  3. package/client.js +42 -8
  4. package/cordis.patch.yml +2 -2
  5. package/features/animation/host.js +660 -660
  6. package/features/animation/view.jsx +2247 -2247
  7. package/features/balance/host.js +494 -494
  8. package/features/balance/view.js +351 -351
  9. package/features/games/games/breakout.jsx +227 -227
  10. package/features/games/games/gomoku.jsx +244 -244
  11. package/features/games/games/racer.jsx +169 -169
  12. package/features/games/games/shared.jsx +118 -118
  13. package/features/games/games/snake.jsx +144 -144
  14. package/features/games/games/sokoban.jsx +180 -180
  15. package/features/games/games/tank.jsx +128 -128
  16. package/features/games/games/tetris.jsx +308 -308
  17. package/features/games/games/xiangqi.jsx +277 -277
  18. package/features/games/tank-core.js +152 -152
  19. package/features/games/view.jsx +639 -639
  20. package/features/games/xiangqi-core.js +299 -299
  21. package/features/heartbeat/view.js +35 -35
  22. package/features/mobile-relay/gateway.js +472 -472
  23. package/features/mobile-relay/host.js +570 -569
  24. package/features/mobile-relay/view.jsx +300 -300
  25. package/features/modelconfig/host.js +403 -403
  26. package/features/modelconfig/view.js +490 -490
  27. package/features/theme/view.js +61 -61
  28. package/features/tokenlog/host.js +690 -678
  29. package/features/tokenlog/view.jsx +561 -561
  30. package/features/visionproxy/host.js +315 -315
  31. package/index.js +175 -118
  32. package/package.json +59 -59
  33. package/src/client.jsx +668 -668
  34. package/src/host-core.js +98 -95
  35. package/src/shared.js +167 -130
package/index.js CHANGED
@@ -1,118 +1,175 @@
1
- // dsh-dock · Host 半部(Node 侧入口)· v0.9.0 模块化架构
2
- //
3
- // 功能坞 = hub + 一个个独立功能模块(像 dsh 本身由小包组成):
4
- // - 每个功能是一个 features/<id>/ 目录:host.js(宿主半部)+ view.js(x)(客户端视图),
5
- // 可整体拎出单独打包发布(scripts/extract-feature.mjs 生成独立包骨架);
6
- // - 独立发布的功能包装回本插件后,经 client 半部的 dockBridge 注册进面板菜单;
7
- // - 本文件只做组装:import 各模块的 feature 描述符,统一生命周期(开关/错误隔离/卸载清理),
8
- // 不含任何具体功能逻辑。
9
- //
10
- // 功能清单(宿主半部;客户端菜单次序由 view 模块的 order 字段决定):
11
- // - models 模型设置(v0.3.0):模型目录读 + 官方配置写
12
- // - visionproxy 图片理解代理(v0.3.1):纯文本模型收图自动走视觉模型识别
13
- // - balance 模型余额(v0.2.0):各 Provider 账户余额/配额
14
- // - tokenlog 用量记录(v0.4.0):LLM 调用记账与统计(移植自 @wycto/dsh-token-usage)
15
- // - animation 任务动画(v0.5.0):会话任务追踪 + 动效/通知配置持久化(参照 @wycto/dsh-task-pulse)
16
- // - mobile-relay 手机接力(未发布):扫码反向代理接力 + 局域网电脑直连(0.0.0.0)
17
- import { DOCK_NS, DockConfig } from './src/host-core.js'
18
- import { feature as fModels } from './features/modelconfig/host.js'
19
- import { feature as fVisionProxy } from './features/visionproxy/host.js'
20
- import { feature as fBalance } from './features/balance/host.js'
21
- import { feature as fTokenlog } from './features/tokenlog/host.js'
22
- import { feature as fAnimation } from './features/animation/host.js'
23
- import { feature as fMobileRelay } from './features/mobile-relay/host.js'
24
-
25
- export const name = 'dsh-dock'
26
-
27
- // 硬依赖 webServer(路由注册)+ llm(图片理解代理包装)+ settings(自有命名空间读写)。
28
- export const inject = ['webServer', 'llm', 'settings']
29
-
30
- /** 测试钩子:清空识别缓存(冒烟在用例间隔离;实现在 visionproxy 模块)。 */
31
- export { __clearDescribeCache } from './features/visionproxy/host.js'
32
-
33
- // 宿主进程健壮性护栏:Node 对已半脱离 HTTP 管理的 socket 上到达的传输层重置
34
- // 没有兜底监听——手机锁屏/切后台、页面跳转中断请求等日常 RST 会以未捕获异常
35
- // 打崩整个 dsh web(实测:Error: read ECONNRESET, Emitted 'error' on Socket)。
36
- // 这里只吞 ECONNRESET/EPIPE 这类纯传输层错误(连接本身已死,吞掉等价于 nginx
37
- // 对客户端断连的处理),其余未捕获异常照常抛出。
38
- if (typeof process !== 'undefined' && typeof process.on === 'function' && !process.listenerCount('uncaughtException')) {
39
- process.on('uncaughtException', (err) => {
40
- const code = err && err.code
41
- if (code === 'ECONNRESET' || code === 'EPIPE') {
42
- console.error('[dsh-dock] swallowed transport error:', code, (err && err.message) || err)
43
- return
44
- }
45
- throw err
46
- })
47
- }
48
-
49
- export function apply(ctx) {
50
- // ---- 功能注册表(Host 侧):每个条目来自对应功能模块的 feature 描述符 ----
51
- // defaultEnabled:与 Client 半部保持一致。已接入的功能默认打开,
52
- // 规划中的功能缺省 false,等实现后移除 roadmap 并打开。
53
- const FEATURES = [
54
- fModels,
55
- fVisionProxy,
56
- fBalance,
57
- fTokenlog,
58
- fAnimation,
59
- fMobileRelay,
60
- ]
61
-
62
- const state = new Map()
63
- for (const f of FEATURES) state.set(f.id, { enabled: false, dispose: null, error: null })
64
-
65
- // 自有 settings 命名空间(dsh-dock):图片理解代理等插件配置的持久化;
66
- // 读取走 settings.get(内存 resolved 值,写入经 settings.mutate,均热生效)
67
- ctx.inject(['settings'], (sctx) => {
68
- sctx.settings.register(DOCK_NS, DockConfig, {})
69
- })
70
-
71
- // 每个功能的 Host 半部安装函数:setup 返回 disposer,关闭功能时调用。
72
- function setEnabled(id, enabled) {
73
- const st = state.get(id)
74
- if (!st || st.enabled === enabled) return
75
- st.enabled = enabled
76
- st.error = null
77
- if (enabled) {
78
- const f = FEATURES.find((x) => x.id === id)
79
- if (f && typeof f.setup === 'function') {
80
- try {
81
- st.dispose = f.setup(ctx) || null
82
- } catch (err) {
83
- st.error = String((err && err.message) || err)
84
- console.error('[dsh-dock] feature setup failed:', id, err)
85
- }
86
- }
87
- } else if (st.dispose) {
88
- try {
89
- st.dispose()
90
- } catch (err) {
91
- console.error('[dsh-dock] feature dispose failed:', id, err)
92
- }
93
- st.dispose = null
94
- }
95
- }
96
-
97
- // 默认启用已实现的功能(与 Client 半部 defaultEnabled 对齐)。
98
- // Client 侧功能开关已 localStorage 持久化(v0.5.0);Host↔Client 的开关双向同步仍未打通,
99
- // 在此之前 Host 侧开关以本处 defaultEnabled 为准(面板停用某功能只影响浏览器侧 UI)。
100
- for (const f of FEATURES) {
101
- if (f.defaultEnabled) setEnabled(f.id, true)
102
- }
103
-
104
- console.log('[dsh-dock] host half loaded; features registered:', FEATURES.map((f) => f.id).join(', '))
105
-
106
- // 插件卸载/更新时兜底清理仍在运行的功能
107
- ctx.effect(() => () => {
108
- for (const st of state.values()) {
109
- if (st.dispose) {
110
- try {
111
- st.dispose()
112
- } catch (err) {
113
- /* ignore */
114
- }
115
- }
116
- }
117
- })
118
- }
1
+ // dsh-dock · Host 半部(Node 侧入口)· v0.9.0 模块化架构
2
+ //
3
+ // 功能坞 = hub + 一个个独立功能模块(像 dsh 本身由小包组成):
4
+ // - 每个功能是一个 features/<id>/ 目录:host.js(宿主半部)+ view.js(x)(客户端视图),
5
+ // 可整体拎出单独打包发布(scripts/extract-feature.mjs 生成独立包骨架);
6
+ // - 独立发布的功能包装回本插件后,经 client 半部的 dockBridge 注册进面板菜单;
7
+ // - 本文件只做组装:import 各模块的 feature 描述符,统一生命周期(开关/错误隔离/卸载清理),
8
+ // 不含任何具体功能逻辑。
9
+ //
10
+ // 功能清单(宿主半部;客户端菜单次序由 view 模块的 order 字段决定):
11
+ // - models 模型设置(v0.3.0):模型目录读 + 官方配置写
12
+ // - visionproxy 图片理解代理(v0.3.1):纯文本模型收图自动走视觉模型识别
13
+ // - balance 模型余额(v0.2.0):各 Provider 账户余额/配额
14
+ // - tokenlog 用量记录(v0.4.0):LLM 调用记账与统计(移植自 @wycto/dsh-token-usage)
15
+ // - animation 任务动画(v0.5.0):会话任务追踪 + 动效/通知配置持久化(参照 @wycto/dsh-task-pulse)
16
+ // - mobile-relay 手机接力(未发布):扫码反向代理接力 + 局域网电脑直连(0.0.0.0)
17
+ import { DOCK_NS, DockConfig, sendJson, readBody } from './src/host-core.js'
18
+ import { feature as fModels } from './features/modelconfig/host.js'
19
+ import { feature as fVisionProxy } from './features/visionproxy/host.js'
20
+ import { feature as fBalance } from './features/balance/host.js'
21
+ import { feature as fTokenlog } from './features/tokenlog/host.js'
22
+ import { feature as fAnimation } from './features/animation/host.js'
23
+ import { feature as fMobileRelay } from './features/mobile-relay/host.js'
24
+
25
+ export const name = 'dsh-dock'
26
+
27
+ // 硬依赖 webServer(路由注册)+ llm(图片理解代理包装)+ settings(自有命名空间读写)。
28
+ export const inject = ['webServer', 'llm', 'settings']
29
+
30
+ /** 测试钩子:清空识别缓存(冒烟在用例间隔离;实现在 visionproxy 模块)。 */
31
+ export { __clearDescribeCache } from './features/visionproxy/host.js'
32
+
33
+ // 宿主进程健壮性护栏:Node 对已半脱离 HTTP 管理的 socket 上到达的传输层重置
34
+ // 没有兜底监听——手机锁屏/切后台、页面跳转中断请求等日常 RST 会以未捕获异常
35
+ // 打崩整个 dsh web(实测:Error: read ECONNRESET, Emitted 'error' on Socket)。
36
+ // 这里只吞 ECONNRESET/EPIPE 这类纯传输层错误(连接本身已死,吞掉等价于 nginx
37
+ // 对客户端断连的处理),其余未捕获异常照常抛出。
38
+ if (typeof process !== 'undefined' && typeof process.on === 'function' && !process.listenerCount('uncaughtException')) {
39
+ process.on('uncaughtException', (err) => {
40
+ const code = err && err.code
41
+ if (code === 'ECONNRESET' || code === 'EPIPE') {
42
+ console.error('[dsh-dock] swallowed transport error:', code, (err && err.message) || err)
43
+ return
44
+ }
45
+ throw err
46
+ })
47
+ }
48
+
49
+ export function apply(ctx) {
50
+ // ---- 功能注册表(Host 侧):每个条目来自对应功能模块的 feature 描述符 ----
51
+ // defaultEnabled:与 Client 半部保持一致。已接入的功能默认打开,
52
+ // 规划中的功能缺省 false,等实现后移除 roadmap 并打开。
53
+ const FEATURES = [
54
+ fModels,
55
+ fVisionProxy,
56
+ fBalance,
57
+ fTokenlog,
58
+ fAnimation,
59
+ fMobileRelay,
60
+ ]
61
+
62
+ const state = new Map()
63
+ for (const f of FEATURES) state.set(f.id, { enabled: false, dispose: null, error: null })
64
+
65
+ /** 读宿主侧功能开关表(settings 持久化;settings 未挂载时回退 defaultEnabled)。 */
66
+ function persistedFeatureMap() {
67
+ try {
68
+ const settings = ctx.get('settings')
69
+ const v = settings && typeof settings.get === 'function' ? settings.get(DOCK_NS) : null
70
+ if (v && typeof v === 'object' && v.features && typeof v.features === 'object') return v.features
71
+ } catch {
72
+ // settings 未挂载
73
+ }
74
+ return null
75
+ }
76
+
77
+ // 每个功能的 Host 半部安装函数:setup 返回 disposer,关闭功能时调用。
78
+ function setEnabled(id, enabled) {
79
+ const st = state.get(id)
80
+ if (!st || st.enabled === enabled) return
81
+ st.enabled = enabled
82
+ st.error = null
83
+ if (enabled) {
84
+ const f = FEATURES.find((x) => x.id === id)
85
+ if (f && typeof f.setup === 'function') {
86
+ try {
87
+ st.dispose = f.setup(ctx) || null
88
+ } catch (err) {
89
+ st.error = String((err && err.message) || err)
90
+ console.error('[dsh-dock] feature setup failed:', id, err)
91
+ }
92
+ }
93
+ } else if (st.dispose) {
94
+ try {
95
+ st.dispose()
96
+ } catch (err) {
97
+ console.error('[dsh-dock] feature dispose failed:', id, err)
98
+ }
99
+ st.dispose = null
100
+ }
101
+ }
102
+
103
+ // 自有 settings 命名空间(dsh-dock):功能开关与各功能配置的持久化;
104
+ // 读取走 settings.get(内存 resolved 值,写入经 settings.mutate,均热生效)。
105
+ // 宿主侧初始开关也在这里应用:settings 命名空间注册完成后才能读到持久化开关表
106
+ // (apply() 同步执行时注册尚未生效,读到的永远是空值)。
107
+ let initialTogglesApplied = false
108
+ ctx.inject(['settings'], (sctx) => {
109
+ sctx.settings.register(DOCK_NS, DockConfig, {})
110
+ if (initialTogglesApplied) return
111
+ initialTogglesApplied = true
112
+ const persisted = persistedFeatureMap()
113
+ for (const f of FEATURES) {
114
+ const saved = persisted ? persisted[f.id] : undefined
115
+ setEnabled(f.id, typeof saved === 'boolean' ? saved : !!f.defaultEnabled)
116
+ }
117
+ })
118
+
119
+ // 功能开关管理路由(无条件注册):GET 查询各功能宿主侧状态;POST 同步开关——
120
+ // 浏览器面板 toggle 经此写入 settings(跨浏览器/重启保持)并即时 setup/dispose 宿主半部。
121
+ {
122
+ const webServer = ctx.get('webServer')
123
+ if (webServer) {
124
+ webServer.register({
125
+ kind: 'exact',
126
+ path: '/dsh-dock/features',
127
+ handler: async (req, res) => {
128
+ try {
129
+ if (req.method === 'POST') {
130
+ const body = await readBody(req)
131
+ const id = body && typeof body.id === 'string' ? body.id : ''
132
+ const enabled = !!(body && body.enabled)
133
+ if (!state.has(id)) return sendJson(res, 404, { ok: false, error: { message: `未知功能:${id}` } })
134
+ setEnabled(id, enabled)
135
+ const settings = ctx.get('settings')
136
+ if (settings && typeof settings.mutate === 'function') {
137
+ const features = Object.assign({}, persistedFeatureMap() || {}, { [id]: enabled })
138
+ await settings.mutate(DOCK_NS, [{ op: 'set', path: ['features'], value: features }])
139
+ }
140
+ }
141
+ const persisted = persistedFeatureMap() || {}
142
+ sendJson(res, 200, {
143
+ ok: true,
144
+ data: {
145
+ features: Array.from(state.entries()).map(([id, st]) => ({
146
+ id,
147
+ enabled: st.enabled,
148
+ error: st.error,
149
+ })),
150
+ persisted,
151
+ },
152
+ })
153
+ } catch (e) {
154
+ sendJson(res, 500, { ok: false, error: { message: e instanceof Error ? e.message : String(e) } })
155
+ }
156
+ },
157
+ })
158
+ }
159
+ }
160
+
161
+ console.log('[dsh-dock] host half loaded; features registered:', FEATURES.map((f) => f.id).join(', '))
162
+
163
+ // 插件卸载/更新时兜底清理仍在运行的功能
164
+ ctx.effect(() => () => {
165
+ for (const st of state.values()) {
166
+ if (st.dispose) {
167
+ try {
168
+ st.dispose()
169
+ } catch (err) {
170
+ /* ignore */
171
+ }
172
+ }
173
+ }
174
+ })
175
+ }
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "dsh-dock",
3
- "version": "0.9.6",
4
- "description": "DeepSeek Harness 功能坞插件(dsh-dock):模块化功能中枢——每个功能一个 features/ 模块(可单独提取成包发布,又可经 dockBridge 装回面板)。含用量记录(LLM 调用记账/费用统计)、模型设置、图片理解代理、模型余额、任务动画(19 种运行动画 + 桌面伙伴 3D 场景、完成/需确认通知与提示音、钉钉/飞书推送,开关独立、配置持久化);侧栏入口 + 可拖拽弹窗(最大化/最小化/缩放)。",
5
- "type": "module",
6
- "main": "index.js",
7
- "files": [
8
- "index.js",
9
- "client.js",
10
- "src/",
11
- "features/",
12
- "cordis.patch.yml",
13
- "screenshots"
14
- ],
15
- "exports": {
16
- ".": "./index.js",
17
- "./client": "./client.js",
18
- "./package.json": "./package.json"
19
- },
20
- "dsh": {
21
- "bundle": {
22
- "patch": "./cordis.patch.yml"
23
- },
24
- "client": {
25
- "platform": "web"
26
- }
27
- },
28
- "keywords": [
29
- "dsh",
30
- "deepseek-harness",
31
- "cordis",
32
- "plugin",
33
- "dock",
34
- "function-dock",
35
- "功能坞",
36
- "panel",
37
- "hub",
38
- "web",
39
- "dashboard"
40
- ],
41
- "author": "wycto",
42
- "license": "MIT",
43
- "repository": {
44
- "type": "git",
45
- "url": "git+https://github.com/wycto/dsh-dock.git"
46
- },
47
- "homepage": "https://github.com/wycto/dsh-dock",
48
- "publishConfig": {
49
- "access": "public"
50
- },
51
- "dependencies": {
52
- "js-yaml": "^4.1.0",
53
- "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6",
54
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
55
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
56
- "@deepseek-ai/schemastery": "^3.18.1",
57
- "qrcode": "^1.5.4"
58
- }
59
- }
1
+ {
2
+ "name": "dsh-dock",
3
+ "version": "0.9.8",
4
+ "description": "DeepSeek Harness 功能坞插件(dsh-dock):模块化功能中枢——每个功能一个 features/ 模块(可单独提取成包发布,又可经 dockBridge 装回面板)。含用量记录(LLM 调用记账/费用统计)、模型设置、图片理解代理、模型余额、任务动画(19 种运行动画 + 桌面伙伴 3D 场景、完成/需确认通知与提示音、钉钉/飞书推送,开关独立、配置持久化);侧栏入口 + 可拖拽弹窗(最大化/最小化/缩放)。",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "files": [
8
+ "index.js",
9
+ "client.js",
10
+ "src/",
11
+ "features/",
12
+ "cordis.patch.yml",
13
+ "screenshots"
14
+ ],
15
+ "exports": {
16
+ ".": "./index.js",
17
+ "./client": "./client.js",
18
+ "./package.json": "./package.json"
19
+ },
20
+ "dsh": {
21
+ "bundle": {
22
+ "patch": "./cordis.patch.yml"
23
+ },
24
+ "client": {
25
+ "platform": "web"
26
+ }
27
+ },
28
+ "keywords": [
29
+ "dsh",
30
+ "deepseek-harness",
31
+ "cordis",
32
+ "plugin",
33
+ "dock",
34
+ "function-dock",
35
+ "功能坞",
36
+ "panel",
37
+ "hub",
38
+ "web",
39
+ "dashboard"
40
+ ],
41
+ "author": "wycto",
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/wycto/dsh-dock.git"
46
+ },
47
+ "homepage": "https://github.com/wycto/dsh-dock",
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "dependencies": {
52
+ "js-yaml": "^4.1.0",
53
+ "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6",
54
+ "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
55
+ "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
56
+ "@deepseek-ai/schemastery": "^3.18.1",
57
+ "qrcode": "^1.5.4"
58
+ }
59
+ }