news 2026/9/30 17:49:31

以DSH小鲸鱼挂件为例学会开发DSH插件:3个文件与23条路由的完整架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
以DSH小鲸鱼挂件为例学会开发DSH插件:3个文件与23条路由的完整架构

以DSH小鲸鱼挂件为例学会开发DSH插件:3个文件与23条路由的完整架构

【免费下载链接】DeepSeek-Balance-Whale-WidgetDeepSeek Harness(DSH)一只住在 DSH 界面右下角的小鲸鱼娘,帮你盯着DeepSeek账户余额。QQ弹弹,支持拖拽吸附、左吸附翻转、数字滚动动画,随界面自动启用,建议直接喊来你的dsh安装项目地址: https://gitcode.com/gh_mirrors/de/DeepSeek-Balance-Whale-Widget

本文以 DeepSeek-Balance-Whale-Widget 项目(DSH 小鲸鱼记账挂件插件dsh-whale-widget)为例,带你拆解一个 DeepSeek Harness(DSH)Web 插件的完整架构:它只靠 3 个核心 JS 文件 + 1 个挂载声明,就实现了余额监控、小鲸鱼记账、音效泡泡等全部功能,宿主侧共注册 23 条/dsh-whale/*路由。读完这篇 DSH 插件开发指南,你就能掌握「bundle 插件包 + webServer 路由 + 页面注入脚本」这套标准架构。

1. 先认识这个插件:3 个文件撑起全部功能

DSH 小鲸鱼挂件住在 DSH Web 界面右下角:气泡里显示 DeepSeek API 余额、今日已用、每轮对话消耗,支持拖拽吸附、Q 弹按压、音效与自定义泡泡。它的全部能力来自 3 个核心文件,各司其职:

文件角色一句话说明
package.json插件身份证声明包名dsh-whale-widget与dsh.bundle.patch,DSH 据此识别它为 bundle 插件
lib/index.js宿主侧本体(约 3900 行)注册全部路由、监听会话事件、记账与余额拉取
lib/accounting.mjs记账内核(仅 252 行)定点金额运算 + 余额观测/校正账本,独立成模块方便测试
assets/whale-widget.js前端挂件本体(约 1.7 万行)原生 JS,运行在浏览器页面里,画鲸鱼、气泡、菜单

这套「宿主(Node 进程)+ 前端(浏览器)」双半区结构是 DSH 插件的通用形态:宿主负责取数、存盘、注册 HTTP 路由;前端只负责渲染与交互,两者通过路由通信。

2. 插件是如何被 DSH 加载的:2 个声明文件

包元数据:让 DSH 认出这是个插件

package.json 里最关键的是dsh.bundle.patch字段,它指向挂载声明文件;main指向宿主入口:

"main": "lib/index.js", "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }

挂载声明:一行 YAML 把自己插进配置树

cordis.patch.yml 内容只有两行有效配置:

- insert: - id: dsh-whale-widget name: dsh-whale-widget

DSH 启动时会按 bundle 层栈叠加各插件的 patch,把这个插件插入 Web profile 的配置树。装进 DSH 只需一条命令:

dsh plugin --profile web add dsh-whale-widget

⚠️ 新手常见坑:发布包里name必须写插件包名(dsh-whale-widget),不要写成name: ./xxx.mjs?v=N那种相对路径——那是本机手动复制到 profile 时的热更写法,发布给他人会因路径不存在而破坏启动。完整原因见 whale-widget-prompt.md 的「关键技术结论」一节。

3. 宿主侧完整架构:23 条路由怎么组织

打开 lib/index.js,你会发现所有路由都不是零散register的,而是统一走一个包装入口 registerRoute:它给每条路由自动套上「浏览器信任栅栏」(拦截跨站请求、写操作仅限本机回环地址),再调用ctx.webServer.register。这是插件安全设计的第一原则——统一入口,默认拒绝。

全部 23 条/dsh-whale/*路由按职责可分为 5 组(源码位置见 lib/index.js):

数据类:挂件内容的"取数口"

路由方法职责
/dsh-whale/balance.jsonGET余额 + 今日已用 + 峰谷状态,永远返回 200 JSON
/dsh-whale/last-turn.jsonGET最近一轮对话消耗(seq递增,前端据此判断"新轮次")
/dsh-whale/wait.jsonGET当前挂起的「提问/授权」事件,驱动提示音
/dsh-whale/usage-records.jsonGET小鲸鱼记账的逐日/逐条明细
/dsh-whale/balance-adjustments.jsonGET/POST余额校正(充值等非调用扣减)

配置类:用户设置的持久化回路

路由方法职责
/dsh-whale/size.jsonGET/PUT外观与开关(缩放、音量、吸附等)
/dsh-whale/usage-settings.jsonGET/PUT提醒类设置(预警、预算、每轮消耗提示内容)
/dsh-whale/api-models.jsonGET/POST/DELETE自定义 API 模型注册表(密钥走 DSH 凭据,不落配置)

媒体类:图片、音效、前端代码

路由职责
/dsh-whale/image.png鲸鱼本体图(读包内 assets/DSniang1.png)
/dsh-whale/rua.gif随机台词/撒娇动图
/dsh-whale/widget.js下发前端挂件源码(宿主按 mtime 热读取,改前端不用重启)
/dsh-whale/sound/press.mp3/sound/release.mp3按压/松开音效,按?set=duck\|fx1切换
/dsh-whale/audio.json+audio-fragment.wav音效库索引与片段试听
/dsh-whale/role-image.png自定义角色图

自定义资产类:用户上传内容的管理

路由职责
/dsh-whale/roles.json/role-pin.json/role-delete.json自定义角色列表、置顶、删除
/dsh-whale/bubble.json自定义泡泡(点击序列 + 模块库)
/dsh-whale/bubble-imgs.json/bubble-img-upload.json/bubble-img.png泡泡图库的列表、上传、读取

架构要点:生命周期与可迁移路径

  • disposer 收集模式:每个registerRoute/tapIndex的返回物都 push 进disposers数组,统一挂到ctx.effect上清理,HMR 热重载不会留下重复路由(见 lib/index.js)。
  • 可迁移路径:lib/index.js#L18-L22 用fileURLToPath(import.meta.url)推出包根目录PACKAGE_ROOT,资源一律相对包内assets/取;用户数据(账本、角色、音频)写到$DSH_HOME(默认~/.dsh),因为node_modules可能在更新时被清理。
  • 会话事件监听:宿主用ctx.on('session/event', ...)捕获每轮assistant/message的真实 usage(input/cache/output/reasoning tokens),turn/end时按峰谷定价表结算写入lastTurn——前端每秒轮询last-turn.json,看到seq变大就弹出消耗泡泡。

4. 记账内核:252 行如何避免"浮点数陷阱"

lib/accounting.mjs 是独立模块,只导出纯函数:preciseMoney/addMoney/sumMoney/observeBalance等。核心设计有两个:

  1. 定点金额:金额先放大 1 亿倍(SCALE = 100000000)转成整数运算,8 位小数记账、2 位小数显示,彻底绕开浮点误差(accounting.mjs#L4-L20)。
  2. 观测 ≠ 交易:余额下降记为消费(debit),余额上升(充值/赠金)单独记为 credit,不会冲掉已有消费;充值出现「待核对余额调整」提示,由用户在界面上显式校正。

把记账逻辑从 3900 行的宿主本体里拆出来,是新手最容易忽略、却最值钱的架构习惯:数据计算与 HTTP 处理分离,前者可独立验证,后者只做路由与校验。

5. 前端挂件:一个"寄生"在页面上的原生 JS 程序

assets/whale-widget.js 由宿主通过tapIndex注入<script defer src="/dsh-whale/widget.js">到 DSH 的 index.html(幂等注入,已存在则跳过)。它有几个值得学习的手法:

  • 幂等守卫:首行if (window.__dshWhaleWidget) return,防止热重载后重复初始化(whale-widget.js#L1-L4)。
  • 环境自检:脚本会注入 DSH 的每个index 页面(含插件市场等 SPA 视图),所以开头先检测「当前是否主聊天界面」(识别 composer 输入区),不是就干脆不碰 DOM——避免干扰 React 渲染树。
  • DOM 分层:div.dshwv-root(定位/翻转)→div.dshwv-body(按压 Q 弹缩放)→ 鲸鱼图 + SVG 气泡,三层职责清晰,动画互不干扰。
  • 浮层层级自检:项目还配了零依赖脚本 tools/z-layer-audit.mjs,node tools/z-layer-audit.mjs即可校验所有 body 级浮层是否登记进 z-index 候选表,防止「两个窗口互相盖住且谁都不报错」的静默失效——小项目也值得有这种自检工具。

6. 本地开发工作流:热重载怎么用最顺

按 whale-widget-prompt.md 总结的踩坑结论,DSH 插件联调的最快姿势:

  1. 安装:在仓库根目录(package.json所在层,不要多套子目录)执行dsh plugin --profile web add link:.,然后重启dsh web。
  2. 改前端(assets/whale-widget.js):宿主按文件 mtime 热读取,浏览器Ctrl+F5 硬刷新即生效,不用重启。
  3. 改宿主(lib/index.js/lib/accounting.mjs):必须重启dsh web。
  4. 验证路由存活:带会话在浏览器里访问/dsh-whale/balance.json应返回 200 JSON(含totalBalance);裸curl返回 401/403 是信任栅栏在工作的预期行为,不是接口坏了(详见 README.md 的「验证」一节)。
  5. 卸载:dsh plugin --profile web remove dsh-whale-widget。

7. 总结:从这个小挂件能学到的 DSH 插件架构清单

📌 把这份清单存下来,下一个插件直接套用:

  1. 标准 bundle 插件=package.json(含dsh.bundle.patch)+cordis.patch.yml挂载声明 + ESM 宿主入口,实现"随界面自动启用"。
  2. 路由统一入口:用一个registerRoute包装所有路由,安全栅栏、错误兜底一次配齐;balance.json这类高频接口永远返回 200 + JSON,绝不悬挂。
  3. disposer 生命周期:所有注册物收集进数组、挂ctx.effect清理,热重载零残留。
  4. 数据与逻辑分层:记账内核独立成纯函数模块,定点数运算,观测与校正分离。
  5. 前端自守:幂等守卫 + 环境自检,注入脚本只在它该工作的页面工作。
  6. 可迁移路径:资源相对包根目录取,用户数据落$DSH_HOME,插件升级/迁移不掉数据。

想深入完整规格(DOM 结构、视觉几何参数、12 条踩坑结论、全部路由表),直接读项目自带的「完整生成提示词」whale-widget-prompt.md——它本身就是面向二次开发的架构文档,也是"把 README 写成 AI 可复现规格"的一个优秀范例。

【免费下载链接】DeepSeek-Balance-Whale-WidgetDeepSeek Harness(DSH)一只住在 DSH 界面右下角的小鲸鱼娘,帮你盯着DeepSeek账户余额。QQ弹弹,支持拖拽吸附、左吸附翻转、数字滚动动画,随界面自动启用,建议直接喊来你的dsh安装项目地址: https://gitcode.com/gh_mirrors/de/DeepSeek-Balance-Whale-Widget

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 17:47:13

选视频云,让我多花钱的其实不是价格,是这 10 个决定

计费规则本身——那些公式和倍数&#xff0c;我到现在都还留着当工具用。我想说说比规则更值钱的东西&#xff1a;我做的那些决定。因为事后复盘我发现&#xff0c;让我们最后多花 7 万的&#xff0c;不是供应商报价贵&#xff0c;是我自己做错了几个判断。 而这些判断&#xf…

作者头像 李华
网站建设 2026/9/30 17:46:43

EPR合规红线:跨境电商卖家如何判断必须注册并避坑

有朋友问我“什么情况下必须做 EPR”&#xff1f;我的第一反应往往是&#xff1a;你既然问出这个问题&#xff0c;大概率已经踩线了。做跨境电商这几年&#xff0c;EPR&#xff08;生产者责任延伸&#xff09;已经从“后台一封提醒邮件”变成了实实在在的合规红线。我见过太多卖…

作者头像 李华
网站建设 2026/9/30 17:45:01

企业自建ATTCK知识库:从攻防演练到威胁情报的运营实战

简介&#xff1a;这份资料是面向安全运营、红蓝对抗及威胁情报人员的ATT&CK企业落地实战讲解&#xff0c;聚焦如何从零建立并长效运营内部ATT&CK框架。内容完整覆盖框架背景与设计哲学、企业级建设步骤、V9版本数据源更新及2021路线图&#xff0c;并给出威胁情报、模拟…

作者头像 李华
网站建设 2026/9/30 17:44:58

含风电的电力系统动态经济调度:随机场景与MILP建模详解

1. 从静态到动态&#xff1a;风电随机性到底难在哪接到这个题目的时候&#xff0c;我第一反应是&#xff1a;很多人把“动态经济调度”和“含风电的经济调度”当成两件事来做。实际上&#xff0c;这两个难点叠在一起&#xff0c;才是这个模型的真正核心——既要处理常规机组跨时…

作者头像 李华
网站建设 2026/9/30 17:43:50

Java 多线程总结:线程、锁、线程池与异步协作

Java 多线程总结&#xff1a;线程、锁、线程池与异步协作 从“大量数据怎样导入”和“一笔订单怎样拆成多个任务”出发&#xff0c;看懂多线程究竟在解决什么。 主体以 Java 17 的平台线程为基线&#xff1b;末尾单独说明 Java 21 虚拟线程。导入数量、批次大小、库存和线程池参…

作者头像 李华