dsh-dock 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wycto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # dsh-dock
2
+
3
+ [![npm version](https://img.shields.io/npm/v/dsh-dock)](https://www.npmjs.com/package/dsh-dock)
4
+ [![license](https://img.shields.io/npm/l/dsh-dock)](LICENSE)
5
+
6
+ **DeepSeek Harness 功能中枢插件**:用一张管理面板,统一注册、开关所有小功能。
7
+
8
+ 模型余额、Token 用量记录、任务动画……这些散落的小功能,全部收进一个面板:
9
+ 每个功能是独立模块,有注册表、有开关、有错误隔离。新功能按注册表模式追加,老功能互不牵连。
10
+
11
+ > 前身:本地原型 `feature-hub`(已安装验证),本包为其正式发布的 npm 版本。
12
+ > 相关功能包:`@wycto/dsh-balance-panel`、`@wycto/dsh-token-usage`、`@wycto/dsh-task-pulse`
13
+ > (后续按路线图吸收为中枢内的功能模块,或保持独立包并注册进中枢)。
14
+
15
+ ---
16
+
17
+ ## 当前状态(v0.1.0 · 基础框架)
18
+
19
+ - ✅ 设置页新增一整页「功能中枢」面板(侧栏底部 → 设置 → 功能中枢)
20
+ - ✅ 功能注册表:`FEATURES` 一处登记,面板自动渲染
21
+ - ✅ 每功能独立开关 + 错误隔离:单个功能出错只降级自己
22
+ - ✅ 示例功能:心跳监视、主题信息(纯 Client,开箱可用)
23
+ - 🚧 示例功能的开关为浏览器内存态,刷新重置(持久化在 0.5.0)
24
+ - 🚧 三个真实功能已登记为**规划占位**,面板可见但显示"规划中"
25
+
26
+ ## 面板入口
27
+
28
+ ```
29
+ 设置(侧栏底部)→ 功能中枢
30
+ ```
31
+
32
+ ## 目录结构
33
+
34
+ ```
35
+ dsh-dock/
36
+ ├── index.js # Host 半部:功能注册表 + 每功能生命周期(setup/dispose)+ 错误隔离
37
+ ├── client.js # Client 半部:中枢面板(settings.section),浏览器 bundle,无需构建器
38
+ ├── cordis.patch.yml # 组合层:insert 一行 dsh-dock
39
+ ├── package.json # 双面程序包清单(dsh.bundle.patch + dsh.client)
40
+ └── scripts/publish.sh # 一键发布(登录检查 + 预览 + publish)
41
+ ```
42
+
43
+ ## 路线图(后面要干嘛)
44
+
45
+ | 版本 | 内容 | 动哪里 |
46
+ | --- | --- | --- |
47
+ | **0.2.0** | 接入**模型余额**:拉取所有模型 Provider 账户余额并展示 | `index.js` 的 `hostSetups.balance` 实现拉取;打通 Client↔Host 联通(typert);`client.js` 的 balance 占位改为真实视图 |
48
+ | **0.3.0** | 接入 **Token 用量记录**:记录全部 LLM API 调用,支持时间范围/维度筛选与统计 | `hostSetups.tokenlog` 监听事件记账;面板加统计视图 |
49
+ | **0.4.0** | 接入**任务动画**:任务进度动画、完成/卡住通知 | 纯 Client 功能模块;如需挂对话区,在模块内注册对应 slot(如 `conversation.composer.dock`) |
50
+ | **0.5.0** | 开关状态**持久化**、Host↔Client 双侧注册表打通 | 状态写入持久化服务;可选依赖注册(面板不在,功能照跑) |
51
+
52
+ 后续新增功能遵循同一模式:**注册表加一条 + 视图加一个**,即插即用。
53
+
54
+ ## 新增一个功能(三步)
55
+
56
+ 1. `client.js` 的 `FEATURES` 加一条 `{ id, name, description, defaultEnabled }`;
57
+ 2. `featureViews` 加同名组件(`react.createElement` 写法,可用 `ctx.get(...)` 取 Client 服务);
58
+ 3. 需要 Host 侧逻辑的,在 `index.js` 的 `hostSetups` 加一个返回 disposer 的函数。
59
+
60
+ ## 安装
61
+
62
+ 开发期(link 模式):
63
+
64
+ ```sh
65
+ dsh plugin --profile web add dsh-dock # npm 版安装
66
+ # 或本地路径:dsh plugin --profile web add /path/to/dsh-dock
67
+ ```
68
+
69
+ 查看/卸载:
70
+
71
+ ```sh
72
+ dsh web --dump-config # 查看合成层(含 dsh-dock)
73
+ dsh plugin --profile web remove dsh-dock # 卸载
74
+ ```
75
+
76
+ ### 从 feature-hub 迁移
77
+
78
+ 本包是 feature-hub 原型的正式发布版,面板与功能几乎一致:
79
+
80
+ ```sh
81
+ dsh plugin --profile web remove dsh-feature-hub
82
+ dsh plugin --profile web add dsh-dock
83
+ ```
84
+
85
+ (两个插件共存亦可,只是面板重复;建议迁移后移除旧版。)
86
+
87
+ ## 开发与发布
88
+
89
+ - **开发提交**:Gitea 仓库(`wycto/dsh-dock`)
90
+ - **发版**:GitHub 仓库(`github.com/wycto/dsh-dock`)打 tag 发 Release
91
+ - **npm 发布**(无作用域名先到先得,已占用后归本账号所有):
92
+
93
+ ```sh
94
+ cd dsh-dock
95
+ npm login # 首次:登录你的 npm 账号(wycto)
96
+ scripts/publish.sh # 预览 → 登录检查 → 发布
97
+ ```
98
+
99
+ > 若发布时报 `EPERM`(npm 缓存目录里有 root 属主文件的历史 bug):
100
+ > 修复一次 `sudo chown -R 501:20 ~/.npm`,或临时绕过
101
+ > `CACHE_DIR=/tmp/dsh-dock-npm-cache ./scripts/publish.sh`。
102
+
103
+ > 注:`package.json` 中仓库链接请在 Gitea/GitHub 建仓后按实际地址更新。
104
+
105
+ ## License
106
+
107
+ MIT
package/client.js ADDED
@@ -0,0 +1,115 @@
1
+ // dsh-dock · Client 半部(浏览器 bundle,手写 lazy-CJS 工厂格式,无需构建器)
2
+ // 面板挂载在 settings.section:设置 → 功能中枢
3
+ // 每个功能是一个模块:FEATURES 注册表 + featureViews 视图组件 + 独立开关(内存态)。
4
+ // planned: true 的功能为规划占位(见 README 路线图),接入后移除 planned 并提供视图即可。
5
+ window.__ModuleLoader__.load({
6
+ id: "dsh-dock",
7
+ factory: (require) => {
8
+ var module = { exports: {} };
9
+ var exports = module.exports;
10
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
11
+ let react = require("react");
12
+
13
+ const name = "dsh-dock";
14
+ const inject = ["timer"];
15
+
16
+ // ---- 功能注册表:新功能在这里加一条,featureViews 里加同名视图 ----
17
+ const FEATURES = [
18
+ { id: "heartbeat", name: "心跳监视", description: "示例功能:面板侧运行时长心跳(纯 Client)", defaultEnabled: true },
19
+ { id: "theme", name: "主题信息", description: "示例功能:读取当前主题快照(纯 Client)", defaultEnabled: true },
20
+ { id: "balance", name: "模型余额", description: "接入路线图 0.2.0:展示所有模型 Provider 账户余额", planned: true },
21
+ { id: "tokenlog", name: "Token 用量记录", description: "接入路线图 0.3.0:记录全部 LLM API 调用并统计", planned: true },
22
+ { id: "animation", name: "任务动画", description: "接入路线图 0.4.0:任务进度动画与通知", planned: true }
23
+ ];
24
+
25
+ const CSS = [
26
+ ".dock-root{display:flex;flex-direction:column;gap:12px;padding:4px 0;color:var(--dsw-alias-label-primary);font-size:13px;}",
27
+ ".dock-intro{color:var(--dsw-alias-label-secondary);line-height:1.6;}",
28
+ ".dock-card{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:12px 14px;display:flex;flex-direction:column;gap:8px;}",
29
+ ".dock-card-head{display:flex;align-items:center;gap:8px;}",
30
+ ".dock-dot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-secondary);flex:none;}",
31
+ ".dock-dot.on{background:var(--dsw-alias-state-success-primary);}",
32
+ ".dock-dot.err{background:var(--dsw-alias-state-error-primary);}",
33
+ ".dock-name{font-weight:600;flex:none;}",
34
+ ".dock-desc{color:var(--dsw-alias-label-secondary);flex:1;}",
35
+ ".dock-switch{flex:none;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:3px 10px;cursor:pointer;font-size:12px;}",
36
+ ".dock-switch.on{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary);}",
37
+ ".dock-badge{flex:none;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:3px 10px;font-size:12px;}",
38
+ ".dock-body{border-top:1px solid var(--dsw-alias-border-l1);padding-top:8px;color:var(--dsw-alias-label-secondary);display:flex;flex-direction:column;gap:4px;}"
39
+ ].join("\n");
40
+
41
+ function apply(ctx) {
42
+ const slots = ctx.get("slots");
43
+ if (slots === undefined) return;
44
+
45
+ // 开关状态:浏览器内存态,随页面生命周期
46
+ const state = new Map();
47
+ for (const f of FEATURES) state.set(f.id, { enabled: !!f.defaultEnabled, error: null });
48
+
49
+ // ---- 每个功能的客户端视图:key 与注册表 id 一致 ----
50
+ const featureViews = {
51
+ heartbeat: function HeartbeatView() {
52
+ const [sec, setSec] = react.useState(0);
53
+ react.useEffect(() => ctx.interval(() => setSec((s) => s + 1), 1000), []);
54
+ const m = Math.floor(sec / 60);
55
+ return react.createElement("div", null,
56
+ "面板已运行 " + (m > 0 ? m + " 分 " : "") + (sec % 60) + " 秒");
57
+ },
58
+ theme: function ThemeView() {
59
+ const theme = ctx.get("theme");
60
+ if (theme === undefined) return react.createElement("div", null, "theme 服务不可用");
61
+ let snap = null;
62
+ try { snap = theme.getTheme(); }
63
+ catch (err) { return react.createElement("div", null, "读取失败:" + String((err && err.message) || err)); }
64
+ const label = snap && typeof snap.id === "string" ? snap.id
65
+ : snap && typeof snap.name === "string" ? snap.name : "未知";
66
+ return react.createElement("div", null, "当前主题:" + label);
67
+ }
68
+ };
69
+
70
+ function DockPanel() {
71
+ const [, force] = react.useReducer((n) => n + 1, 0);
72
+ const toggle = (id) => {
73
+ const st = state.get(id);
74
+ if (!st) return;
75
+ st.enabled = !st.enabled;
76
+ force();
77
+ };
78
+ return react.createElement("div", { className: "dock-root" },
79
+ react.createElement("style", null, CSS),
80
+ react.createElement("div", { className: "dock-intro" },
81
+ "功能中枢(dsh-dock)· 所有小功能集中在这一个面板里管理。每个功能是独立模块:开关只影响自己,单个功能出错不影响其他功能。新功能按注册表模式追加(FEATURES + featureViews 各加一条)。"),
82
+ FEATURES.map((f) => {
83
+ const st = state.get(f.id);
84
+ const View = featureViews[f.id];
85
+ return react.createElement("div", { className: "dock-card", key: f.id },
86
+ react.createElement("div", { className: "dock-card-head" },
87
+ react.createElement("span", { className: "dock-dot" + (st.error ? " err" : st.enabled ? " on" : "") }),
88
+ react.createElement("span", { className: "dock-name" }, f.name),
89
+ react.createElement("span", { className: "dock-desc" }, f.description),
90
+ f.planned
91
+ ? react.createElement("span", { className: "dock-badge" }, "规划中")
92
+ : react.createElement("button", {
93
+ className: "dock-switch" + (st.enabled ? " on" : ""),
94
+ onClick: () => toggle(f.id)
95
+ }, st.enabled ? "已启用" : "已停用")),
96
+ f.planned
97
+ ? react.createElement("div", { className: "dock-body" }, "待接入:见 README 路线图")
98
+ : st.error ? react.createElement("div", { className: "dock-body dock-err" }, "功能出错:" + st.error) : null,
99
+ !f.planned && st.enabled && View
100
+ ? react.createElement("div", { className: "dock-body" }, react.createElement(View, null))
101
+ : null);
102
+ }));
103
+ }
104
+
105
+ slots.inject("settings.section", () => slots.register(
106
+ { name: "settings.section", id: "dsh-dock", order: 90, label: "功能中枢" },
107
+ () => react.createElement(DockPanel, null)));
108
+ }
109
+
110
+ exports.name = name;
111
+ exports.inject = inject;
112
+ exports.apply = apply;
113
+ return module.exports;
114
+ }
115
+ });
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: dsh-dock
3
+ name: dsh-dock
package/index.js ADDED
@@ -0,0 +1,89 @@
1
+ // dsh-dock · Host 半部(Node 侧入口)
2
+ //
3
+ // v0.1.0 基础框架:
4
+ // - 功能注册表(FEATURES):与 Client 半部注册表同构,规划中的功能已登记;
5
+ // - 每功能独立生命周期(hostSetups 返回 disposer,开关只影响自己);
6
+ // - 函数级错误隔离:单个功能 setup 抛错只标记 error,不影响其他功能。
7
+ //
8
+ // 路线图:
9
+ // - 0.2.0 接入模型余额:在 hostSetups.balance 里实现余额拉取,
10
+ // Client↔Host 联通(typert)随本版本一起打通;
11
+ // - 0.3.0 接入 Token 用量记录:hostSetups.tokenlog 监听事件记账;
12
+ // - 0.4.0 接入任务动画。
13
+ export const name = 'dsh-dock'
14
+
15
+ export function apply(ctx) {
16
+ // ---- 功能注册表(Host 侧)----
17
+ // defaultEnabled 缺省为 false:v0.1.0 只有示例功能,真实功能按路线图接入后打开。
18
+ const FEATURES = [
19
+ {
20
+ id: 'balance',
21
+ name: '模型余额',
22
+ roadmap: '0.2.0',
23
+ description: '拉取所有模型 Provider 账户余额',
24
+ },
25
+ {
26
+ id: 'tokenlog',
27
+ name: 'Token 用量记录',
28
+ roadmap: '0.3.0',
29
+ description: '记录全部 LLM API 调用并统计',
30
+ },
31
+ {
32
+ id: 'animation',
33
+ name: '任务动画',
34
+ roadmap: '0.4.0',
35
+ description: '任务进度动画与通知',
36
+ },
37
+ ]
38
+
39
+ const state = new Map()
40
+ for (const f of FEATURES) state.set(f.id, { enabled: false, dispose: null, error: null })
41
+
42
+ // 每个功能的 Host 半部安装函数:返回 disposer,关闭功能时调用。
43
+ // 接入时在此实现,例如:
44
+ // balance: () => {
45
+ // const stop = ctx.interval(pullBalance, 60_000)
46
+ // return () => stop()
47
+ // },
48
+ const hostSetups = {}
49
+
50
+ function setEnabled(id, enabled) {
51
+ const st = state.get(id)
52
+ if (!st || st.enabled === enabled) return
53
+ st.enabled = enabled
54
+ st.error = null
55
+ if (enabled) {
56
+ const setup = hostSetups[id]
57
+ if (setup) {
58
+ try {
59
+ st.dispose = setup() || null
60
+ } catch (err) {
61
+ st.error = String((err && err.message) || err)
62
+ console.error('[dsh-dock] feature setup failed:', id, err)
63
+ }
64
+ }
65
+ } else if (st.dispose) {
66
+ try {
67
+ st.dispose()
68
+ } catch (err) {
69
+ console.error('[dsh-dock] feature dispose failed:', id, err)
70
+ }
71
+ st.dispose = null
72
+ }
73
+ }
74
+
75
+ console.log('[dsh-dock] host half loaded; features registered:', FEATURES.map((f) => f.id).join(', '))
76
+
77
+ // 插件卸载/更新时兜底清理仍在运行的功能
78
+ ctx.effect(() => () => {
79
+ for (const st of state.values()) {
80
+ if (st.dispose) {
81
+ try {
82
+ st.dispose()
83
+ } catch (err) {
84
+ /* ignore */
85
+ }
86
+ }
87
+ }
88
+ })
89
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "dsh-dock",
3
+ "version": "0.1.0",
4
+ "description": "DeepSeek Harness 功能中枢插件:用一张管理面板统一注册、开关所有小功能(模型余额、Token 用量记录、任务动画等)。0.1.0 为基础框架版本,功能接入路线见 README。",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "files": [
8
+ "index.js",
9
+ "client.js",
10
+ "cordis.patch.yml"
11
+ ],
12
+ "exports": {
13
+ ".": "./index.js",
14
+ "./client": "./client.js",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "dsh": {
18
+ "bundle": { "patch": "./cordis.patch.yml" },
19
+ "client": { "platform": "web" }
20
+ },
21
+ "keywords": [
22
+ "dsh",
23
+ "deepseek-harness",
24
+ "cordis",
25
+ "plugin",
26
+ "panel",
27
+ "hub",
28
+ "feature-hub",
29
+ "web",
30
+ "dashboard"
31
+ ],
32
+ "author": "wycto",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/wycto/dsh-dock.git"
37
+ },
38
+ "homepage": "https://github.com/wycto/dsh-dock",
39
+ "publishConfig": {
40
+ "access": "public"
41
+ }
42
+ }