dsh-dock 0.1.0 → 0.4.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 CHANGED
@@ -2,20 +2,17 @@ MIT License
2
2
 
3
3
  Copyright (c) 2026 wycto
4
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:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
11
10
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
14
13
 
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.
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,61 +1,192 @@
1
- # dsh-dock
1
+ # dsh-dock · 功能坞
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/dsh-dock)](https://www.npmjs.com/package/dsh-dock)
4
4
  [![license](https://img.shields.io/npm/l/dsh-dock)](LICENSE)
5
5
 
6
- **DeepSeek Harness 功能中枢插件**:用一张管理面板,统一注册、开关所有小功能。
6
+ **DeepSeek Harness 功能坞插件(dsh-dock)**:用一张管理面板,统一注册、开关所有小功能。
7
7
 
8
- 模型余额、Token 用量记录、任务动画……这些散落的小功能,全部收进一个面板:
9
- 每个功能是独立模块,有注册表、有开关、有错误隔离。新功能按注册表模式追加,老功能互不牵连。
8
+ 模型余额、用量记录、任务动画……这些散落的小功能,全部收进一个「功能坞」:
9
+ 每个功能是独立模块,有注册表、有开关、有错误隔离。新功能按模块追加,老功能互不牵连。
10
10
 
11
+ > **v0.4.0 起为模块化架构**:功能坞 = hub + 一个个独立功能模块(像 dsh 本身由小包组成)。
12
+ > 每个功能是一个 `features/<id>/` 目录(宿主半部 + 客户端视图),**可整体拎出单独打包发布**
13
+ > (`scripts/extract-feature.mjs` 生成独立包骨架);独立发布的功能包装回后,经
14
+ > **dockBridge** 注册进功能坞菜单——「单独成包」与「完美集成」两全。
15
+ >
11
16
  > 前身:本地原型 `feature-hub`(已安装验证),本包为其正式发布的 npm 版本。
12
17
  > 相关功能包:`@wycto/dsh-balance-panel`、`@wycto/dsh-token-usage`、`@wycto/dsh-task-pulse`
13
- > (后续按路线图吸收为中枢内的功能模块,或保持独立包并注册进中枢)。
18
+ > (余额功能已于 0.2.0 吸收为中枢内模块;用量记录已于 0.4.0 以模块化方式重吸收)。
19
+ > 开发背景与决策见 [docs/session-notes.md](docs/session-notes.md)。
14
20
 
15
21
  ---
16
22
 
17
- ## 当前状态(v0.1.0 · 基础框架)
18
-
19
- - ✅ 设置页新增一整页「功能中枢」面板(侧栏底部 → 设置 → 功能中枢)
20
- - ✅ 功能注册表:`FEATURES` 一处登记,面板自动渲染
21
- - ✅ 每功能独立开关 + 错误隔离:单个功能出错只降级自己
23
+ ## 当前状态(v0.4.0 · 模块化架构 + 用量记录已接入)
24
+
25
+ - ✅ **模块化架构(0.4.0)**:功能代码从两个大文件拆进 `features/<id>/` 模块目录;
26
+ 宿主半部 `index.js` 与客户端外壳 `src/client.jsx` 只做组装,不含功能逻辑;
27
+ 每个模块可单独提取成包(见下文「提取一个功能成独立包」)
28
+ - ✅ **用量记录(0.4.0)**:记录全部 LLM API 调用并统计——
29
+ - 秒级时间范围 + 会话/提供商/模型(联动)/状态/推理强度筛选,条件本地暂存(下次打开恢复);
30
+ - 9 张 KPI 卡(调用次数 / 总 Token / 输入 / 缓存命中 / 命中率 / 输出 / 金额($) / 金额(¥) / 累计耗时);
31
+ - 分组统计(无/provider/model/status/effort 维度切换);
32
+ - 明细表 15 列可排序、100 行/页上下双分页、会话 ID 点击即筛选、行详情弹窗、CSV 导出;
33
+ - 定价引擎:内置 DeepSeek 峰谷价目 + 官网价目每日自动抓取 + `dsh-dock-tokenlog` 命名空间覆盖;
34
+ - 首页总揽「今日调用/Token/花费」卡片;面板打开期间每 5 秒自动刷新
35
+ - ✅ 设置页「功能坞」面板(侧栏底部 → 设置 → 功能坞)
36
+ - ✅ **侧栏入口按钮**:侧栏底部动作区右端「功能坞」按钮,弹出**功能面板**(居中模态:左导航 = 首页总揽 + 各功能模块按 order 排序,右内容区)
37
+ - ✅ **弹层窗口化**:默认大窗(1080×700 自适应),最大化/最小化/还原、标题栏拖动、右下角缩放;几何页内记忆
38
+ - ✅ **模型设置(0.3.0,集成官方链路)**:编辑各 Provider 模型目录(输入类型 + 思考强度档位),`settings.mutate` 写回官方配置热生效
39
+ - ✅ **模型余额(0.2.0)**:枚举全部已配置 Provider,内置策略表查询余额/配额/控制台链接,5 分钟自动刷新
40
+ - ✅ 每功能独立开关 + 错误隔离:单个功能出错只降级自己(外部包视图另有错误边界保护)
22
41
  - ✅ 示例功能:心跳监视、主题信息(纯 Client,开箱可用)
23
- - 🚧 示例功能的开关为浏览器内存态,刷新重置(持久化在 0.5.0)
24
- - 🚧 三个真实功能已登记为**规划占位**,面板可见但显示"规划中"
42
+ - ✅ **会话区随身小控件(0.4.0)**:启用后在会话输入区工具行(模型选择器左侧)显示——
43
+ - **模型余额**:当前选中 Provider 的账户余额(随余额刷新更新),点击打开功能坞并高亮该 Provider 行;
44
+ - **用量记录**:当前会话总 Token 与估算花费(10s 静默刷新),点击打开功能坞并按该会话筛选;
45
+ - 每个功能可单独设置「会话页显示/隐藏」(面板页脚与设置页均有开关,localStorage 持久化)
46
+ - 🚧 功能开关为浏览器内存态,刷新重置(持久化在 0.6.0)
47
+ - 🚧 任务动画已登记为规划占位(0.5.0)
25
48
 
26
- ## 面板入口
49
+ ### 模块化架构(0.4.0)
27
50
 
28
51
  ```
29
- 设置(侧栏底部)→ 功能中枢
52
+ dsh-dock/
53
+ ├── index.js # 宿主半部入口(纯 ESM,零构建):import 各模块组装注册表与生命周期
54
+ ├── client.js # 客户端 bundle(构建产物,提交仓库;源码见 src/ + features/)
55
+ ├── src/
56
+ │ ├── client.jsx # 客户端外壳:入口按钮/弹层/设置页/首页总揽/slots 注册/外部功能桥
57
+ │ ├── shared.js # 共享工具(外部视图错误边界等)
58
+ │ └── host-core.js # 宿主共享内核(DOCK_NS 命名空间、sendJson/readBody/walkPath)
59
+ ├── features/ # ★ 一个目录 = 一个功能模块(整体可拎出单独打包)
60
+ │ ├── balance/ # host.js + view.js
61
+ │ ├── modelconfig/ # host.js + view.js(含图片理解代理配置面板)
62
+ │ ├── visionproxy/ # host.js(纯宿主功能,UI 在 modelconfig 页内)
63
+ │ ├── tokenlog/ # host.js + view.jsx(用量记录)
64
+ │ ├── heartbeat/ # view.js(纯客户端功能)
65
+ │ └── theme/ # view.js(纯客户端功能)
66
+ ├── scripts/
67
+ │ ├── build-client.mjs # esbuild bundle → client.js(改视图后需重跑)
68
+ │ ├── extract-feature.mjs # 功能提取脚手架:features/<id> → 独立包目录
69
+ │ └── publish.sh # 一键发布
70
+ └── docs/session-notes.md # 会话总结与决策记录
30
71
  ```
31
72
 
32
- ## 目录结构
73
+ **模块契约**:
74
+
75
+ - 宿主模块 `features/<id>/host.js` 导出 `feature = { id, name, description, defaultEnabled, setup(ctx) → disposer }`;
76
+ - 视图模块 `features/<id>/view.js(x)` 导出 `feature = { id, name, order, accent, description, css, View, HomeStat? }`;
77
+ `order` 决定菜单次序(首页固定第一;modelconfig=100 → 第二菜单,tokenlog=110 第三);
78
+ 视图收到 `{ ctx, feature, params }` props(`params` 来自导航总线:chips 点击可带入
79
+ `{ provider }` 高亮余额行、`{ sessionId }` 按会话筛选用量);
80
+ 可选 `Chip` 组件(`{ ctx, session, sessionId, input, feature }` props):启用且「会话页显示」
81
+ 时渲染在会话输入区工具行左端(`conversation.input.left`,模型选择器左侧),点击通常经
82
+ `openPanel(id, params)` 打开功能坞定位到对应功能页;
83
+ 每模块自带 `css`(类名前缀隔离:dkb-/dkm-/dtok- …),外壳统一注入;
84
+ - 客户端外壳 `src/client.jsx`:import 模块 → 组装导航/首页/设置页;导出
85
+ `apply` / `inject` / **`dockBridge`**(外部功能回装通道)。
86
+
87
+ **为什么客户端引入了构建**(v0.4.0 决策,宿主半部仍是零构建纯 ESM):
88
+ 功能模块用真实源码文件 + JSX 组织,esbuild 打成单文件 `client.js`
89
+ (`react`/`react/jsx-runtime` 由运行时 seed,外部化;与 `@wycto/dsh-token-usage`
90
+ 已在线上验证的构建模式同款)。改客户端代码后跑 `node scripts/build-client.mjs`。
91
+
92
+ ## 面板入口
33
93
 
34
94
  ```
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)
95
+ ① 快捷入口:侧栏底部「功能坞」按钮(与设置按钮同底对齐)→ 弹出功能面板(首页总揽 + 模块导航 + 内容区,窗口可最大化/最小化/拖动/缩放)
96
+ ② 完整面板:设置(侧栏底部)→ 功能坞
41
97
  ```
42
98
 
43
- ## 路线图(后面要干嘛)
99
+ 入口按钮与功能弹层挂载在 shell 的 `sidebar.footer.action` / `shell.overlay` 座位;
100
+ 弹层与完整面板共用各功能的模块级共享快照
101
+ (余额 `/dsh-dock/balance`、模型目录 `/dsh-dock/models`、用量 `/dsh-dock/tokenlog/*`,首页总揽概要与各视图同源)。
44
102
 
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 双侧注册表打通 | 状态写入持久化服务;可选依赖注册(面板不在,功能照跑) |
103
+ ### 用量记录(0.4.0)
104
+
105
+ - **数据源**:DSH 会话日志(`sessionQuery` 服务)。宿主实时监听 `session/event` 增量记账,
106
+ 启动时全量扫描历史(`sessionId:seq` 幂等去重,实时与扫描重叠不双计);
107
+ 记录含五类 token 桶、状态/错误码(`turn/end` 两遍式回填)、耗时(step/start → assistant/message)。
108
+ - **定价与金额(估算)**:内置 DeepSeek-V4 峰谷刊例(高峰每日 9:00–14:00 双倍)等;
109
+ 每 24h 自动抓取官网价目页(失败静默回退内置);汇率与价目可在 settings.yaml 覆盖:
110
+
111
+ ```yaml
112
+ dsh-dock-tokenlog:
113
+ usdCnyRate: 7.2
114
+ pricingUrl: 'https://api-docs.deepseek.com/zh-cn/quick_start/pricing'
115
+ pricingFetchIntervalHours: 24
116
+ pricing:
117
+ deepseek-v4-flash: { input: 1.5, output: 4.5, cacheRead: 0.05, cacheWrite: 0 }
118
+ ```
119
+
120
+ 改价即时生效(查询/导出时按当前价目重算历史)。
121
+ - **RPC**:`POST /dsh-dock/tokenlog/query|export|scan`(同源 webServer 路由)。
122
+ - 已知口径:金额为估算;失败调用(无 `assistant/message`)不产生 token 行,状态反映回合结局。
123
+
124
+ ### 模型余额支持情况(0.2.0)
125
+
126
+ 内置余额策略表覆盖:**DeepSeek**(官方余额接口)、**StepFun**、**Kimi Coding**(配额)、**OpenRouter**、**MiniMax**、**xAI/grok**;
127
+ 按 provider id(含别名)或 baseURL 家族自动匹配;`qwen-token-plan-*`(阿里云百炼)等无 API 余额接口的 Provider 显示"需登录"并提供控制台跳转链接;
128
+ 其余未知 Provider 显示"不支持"。自定义余额接口可在 Provider profile 里配 `balance.endpoint` 覆盖(沿用 `dsh-balance-panel` 约定)。
129
+
130
+ 密钥全程留在 Host 进程内:只按 `apiKeyEnv` 解析凭证使用,不出 Host、不下发到浏览器。
131
+ 数据经回环 webServer 路由同源下发(Client `fetch` 拉取,不依赖 typert RPC,详见 [docs/session-notes.md](docs/session-notes.md))。
132
+
133
+ ### 模型设置怎么生效(0.3.0)
51
134
 
52
- 后续新增功能遵循同一模式:**注册表加一条 + 视图加一个**,即插即用。
135
+ 面板保存 → Host 经 `settings.mutate` 写入官方配置(`llm-pi-ai.providers.<route>.models[].reasoningEfforts/input/dockTags`
136
+ 或 `llm-deepseek.models[]/thinking/reasoningEffort`)→ 适配器热加载(无需重启)→
137
+ **会话窗口的模型选择器重新打开后,每个模型即可选择配置的强度档**(官方链路按 `model.reasoning.efforts` 展示)。
138
+ 输入类型中仅文本/图片为官方真实模态(请求路由生效);视频/音频/文档为面板标注(持久化但不参与路由)。
53
139
 
54
- ## 新增一个功能(三步)
140
+ > **思考兼容兜底(0.3.0 修复)**:不在 pi-ai 内置目录里的模型(如部分第三方路由模型)启用思考后,
141
+ > 适配器默认会把 system 改写成 `developer` 角色,百炼等 OpenAI 兼容端点直接 400。面板在启用思考档时
142
+ > 自动写入 `compat.supportsDeveloperRole: false`;qwen/百炼家族再补 `thinkingFormat: qwen`,与官方目录内模型一致。
143
+ > 保存时原条目上的未知字段(含用户自配 compat)原样保留,不会被面板清掉。
144
+
145
+ ### 图片理解代理(0.3.1)
146
+
147
+ 纯文本模型也能"看图":在 设置 → 功能坞 → 模型设置 顶部(或弹层同页)启用**图片理解代理**并点选一个
148
+ **视觉模型**(候选 = 模型目录中支持图片输入的全部模型,跨 Provider)后:
149
+
150
+ - 发给**纯文本模型**的消息带图片时,自动先调用所选视觉模型识别,识别文本以 `[图片内容(由视觉模型 … 识别):…]` 注入请求;
151
+ - **多模态模型不受影响**,按官方链路原样自识别;
152
+ - 识别失败自动降级(注入说明文本,不影响主请求);同一张图 10 分钟识别缓存;
153
+ - 配置存插件自有 `dsh-dock` 命名空间,保存即热生效。
154
+
155
+ ## 新增一个功能(两步)
156
+
157
+ 1. 建 `features/<id>/`:
158
+ - `view.js(x)` 导出 `feature = { id, name, order, accent, description, css, View, HomeStat? }`
159
+ (纯客户端功能到这就够了);
160
+ - 需要宿主逻辑的加 `host.js` 导出 `feature = { id, name, description, defaultEnabled, setup(ctx) → disposer }`;
161
+ 2. 在 `src/client.jsx` 的 `BUILTIN_FEATURES` import 一行;宿主功能再在 `index.js` 的 `FEATURES` import 一行;
162
+ 改完跑 `node scripts/build-client.mjs`。
163
+
164
+ 需要从 Host 拿数据的功能:在模块 `setup(ctx)` 里用 `ctx.get('webServer').register`
165
+ 注册同源路由(纯 JSON),视图 `fetch('/dsh-dock/<id>')` 拉取——密钥只进 Host,
166
+ 绝不下发浏览器。详见 [docs/session-notes.md](docs/session-notes.md) 8.3。
167
+
168
+ ## 提取一个功能成独立包
169
+
170
+ ```sh
171
+ node scripts/extract-feature.mjs tokenlog --out ../dsh-dock-tokenlog
172
+ ```
173
+
174
+ 生成独立包骨架(镜像本仓库布局,模块内相对导入不变):宿主入口、独立客户端入口
175
+ (**双形态**:装了 dsh-dock → `ctx.modules.import('dsh-dock')` 成功 → `dockBridge.register`
176
+ 注册进功能坞菜单;没装 → 自己的侧栏入口 + 全屏面板)、构建脚本、`cordis.patch.yml`、`package.json`。
177
+ 发布前裁剪依赖 → 构建 → 实测两种形态(含与功能坞共存时的菜单合并,独立入口应隐藏)。
178
+
179
+ ## 路线图(后面要干嘛)
180
+
181
+ | 版本 | 内容 | 状态 |
182
+ | --- | --- | --- |
183
+ | **0.2.0** | 接入**模型余额**:策略表查询各 Provider 余额/配额;侧栏入口 + 功能弹层 | ✅ 已接入 |
184
+ | **0.3.0** | 接入**模型设置**:官方目录链路集成,写回热生效;弹层窗口化 | ✅ 已接入 |
185
+ | **0.4.0** | **模块化架构**(features/ 模块目录 + 客户端构建 + dockBridge 回装通道)+ 接入**用量记录** + **会话区随身小控件**(余额/用量 chips,模型选择器左侧,可单独开关) | ✅ 已接入(本版) |
186
+ | **0.5.0** | 接入**任务动画**:任务进度动画、完成/卡住通知 | 纯 Client 功能模块;如需挂对话区,在模块内注册对应 slot(如 `conversation.composer.dock`) |
187
+ | **0.6.0** | 开关状态**持久化**、Host↔Client 双侧注册表打通 | 状态写入持久化服务;Host 侧开关与 Client 面板同步;外部功能包的可选依赖注册(面板不在,功能照跑) |
55
188
 
56
- 1. `client.js` 的 `FEATURES` 加一条 `{ id, name, description, defaultEnabled }`;
57
- 2. `featureViews` 加同名组件(`react.createElement` 写法,可用 `ctx.get(...)` 取 Client 服务);
58
- 3. 需要 Host 侧逻辑的,在 `index.js` 的 `hostSetups` 加一个返回 disposer 的函数。
189
+ 后续新增功能遵循同一模式:**模块目录 + 注册表一行 import**,即插即用。
59
190
 
60
191
  ## 安装
61
192
 
@@ -86,8 +217,9 @@ dsh plugin --profile web add dsh-dock
86
217
 
87
218
  ## 开发与发布
88
219
 
89
- - **开发提交**:Gitea 仓库(`wycto/dsh-dock`)
90
- - **发版**:GitHub 仓库(`github.com/wycto/dsh-dock`)打 tag 发 Release
220
+ - **开发提交**:Gitea 开发仓库(本仓库)
221
+ `ssh://git@172.18.99.124:9022/wycto/dsh-dock.git`
222
+ - **发版**:GitHub 仓库(`github.com/wycto/dsh-dock`,待建)打 tag 发 Release
91
223
  - **npm 发布**(无作用域名先到先得,已占用后归本账号所有):
92
224
 
93
225
  ```sh
@@ -100,8 +232,9 @@ scripts/publish.sh # 预览 → 登录检查 → 发布
100
232
  > 修复一次 `sudo chown -R 501:20 ~/.npm`,或临时绕过
101
233
  > `CACHE_DIR=/tmp/dsh-dock-npm-cache ./scripts/publish.sh`。
102
234
 
103
- > 注:`package.json` 中仓库链接请在 Gitea/GitHub 建仓后按实际地址更新。
235
+ > 注:`package.json` 中 repository 指向 GitHub(发版仓库),Gitea 建好后
236
+ > 建议把两个地址都确认一遍。
104
237
 
105
238
  ## License
106
239
 
107
- MIT
240
+ MIT