← Back to home@qiuzhiyei

dsh-companion

DSH 伴侣 — DeepSeek Harness 的伴飞插件:桌面宠物 + Token/费用统计 + 预算告警 + 会话管理。数据全在本地。

Stars
0
Language
TypeScript
Created
Oct 21, 2026
Updated
Oct 21, 2026

Introduction

🐳 DSH 伴侣 · dsh-companion

给 DeepSeek Harness 的伴飞插件 桌宠陪伴 · 用量与费用统计 · 预算告警 · 界面增强

English · 快速开始 · 功能 · 配置 · 自制皮肤 · 开发

license npm release node ci topic

桌宠:鲸鱼娘·JK 学院风

DeepSeek Harness(dsh)是「一切皆插件」的 agent harness,但跑长任务时你通常不知道 它在忙什么、花了多少、要不要歇一会儿。DSH 伴侣把这三件事一起解决:一只跟着任务 状态变化表情的桌宠、一套看得懂的用量/费用面板、以及到点就提醒你起来走走的久坐闹钟。

全部数据留在本机(node:sqlite 或 JSON),只监听 127.0.0.1,不联网上报任何东西 (唯一的出网请求是拉 DeepSeek 官方定价页)。

统计面板历史任务
统计:KPI 环比 · 趋势图 · 费用去向历史:筛选芯片 · 分页 · 按筛选导出

功能一览

能力说明
🐳 桌宠浏览器 / 桌面悬浮窗里的一只鲸鱼娘,随 DSH 任务状态换表情:待机 → 启动 → 思考 → 卖力(流式输出/工具执行)→ 收尾 → 完成 / 出错 / 中断
👗 5 套皮肤 = 5 种人格whale(JK 学院风,默认)/ whale-ol(秘书)/ whale-police(女警)/ whale-hanfu(中华娘)/ whale-qipao(旗袍)。换装不是换张贴图——表情帧、互动反应帧、台词口吻整套都跟着换
💬 互动左键抚摸出爱心粒子 + 台词、连点 5 下有晕头彩蛋、拖着走时被拎起、落地生气;闲下来会自己张望/伸懒腰/打瞌睡,还会自己在屏幕上慢慢逛一圈,被打断立刻回原位
🖱 Ctrl + 滚轮调大小按住 Ctrl 再滚滚轮才缩放(40%–300%,每格 8%),不用开面板;平时滚动文档/网页经过她不会误改大小。和「设置 → 伴侣 → 缩放」滑杆是同一个值,改完立刻存盘
⏰ 久坐提醒坐够 N 分钟(默认 60,5–480 可调)就伸懒腰提醒,气泡里「起来走走 / 稍后 10 分钟」;人离开电脑 ≥3 分钟自动重算,读代码时 DSH 空闲也照样算坐着
📊 统计面板6 张 KPI 卡(Token / 任务数 / 成功率 / 时长 / 费用 / 缓存命中)每张带环比;Token·费用·时长三指标切换的柱状图;费用去向排行(按模型 / 按项目)
💰 费用估算拉取 DeepSeek 官方定价,高峰 / 闲时(5 折)分档计价、缓存命中单独按 1/50 价、按任务开始时刻定档;只统计 DeepSeek 账号 / API key 的任务,自建渠道 Token 照记、费用恒 0
🚨 预算告警单任务 / 每日 × Token / 费用四档上限,触顶时桌宠气泡 + 系统通知 + companion/budget-alert 事件;设置页有今日用量进度条
🗂 历史与导出服务端筛任务(模型 / 状态 / 日期 / 关键词),CSV / JSON 导出(带 BOM,Excel 友好),可按当前筛选导出
🧹 会话管理补上宿主没有的「彻底删除会话」:GUI 会话行菜单单项删除 + 面板批量删除,删除前跑安全检查(运行中会话拒删)
🖥 桌面壳(可选)装个 Electron 就得到真托盘 + 透明无边框置顶悬浮窗 + 点击穿透(宠物本体才接鼠标,周边透明区直接点到桌面)+ 位置记忆
🔔 系统通知长任务(≥60s)完成/失败、预算触顶才弹,短任务不打扰;可在设置页关掉
🧩 零依赖前端面板与悬浮页都是服务端生成的单文件 HTML(无构建、无 CDN、无外部字体),离线可用;图表是手绘 SVG

快速开始

前置:Node.js ^22.19.0 || >=24.0.0、DeepSeek Harness(目前 0.2.0-rc 线)、pnpm。

方式一:桌面版 GUI(不用敲命令)

DSH 桌面版 → 插件管理器 → 安装插件 → 源选「中国大陆镜像源」或「npm 官方源」→ 输入包名:

@qiuzhiyei/dsh-companion

→ 安装 → 在列表里把 「DSH 伴侣」 打开 启用 → 完全退出 DSH(含托盘)再重开。

方式二:命令行

# 推荐:从 npm 装(走你自己配的 registry / 国内镜像,不受 GitHub 连通性影响)
dsh plugin --profile <你的 profile> add @qiuzhiyei/dsh-companion

# 备选:直接吃 GitHub 仓库(仓库里带着编译好的 dist/)
dsh plugin --profile <你的 profile> add github:qiuzhiyei/dsh-companion

# 启动 DSH,日志里会打印伴侣地址
dsh --profile <你的 profile>

dsh plugin 只是把参数原样转发给 profile 目录里的 pnpm,所以两条分别等价于 pnpm add @qiuzhiyei/dsh-companion 和 pnpm add github:qiuzhiyei/dsh-companion。 包和仓库都带着编译好的 dist/(约 0.3 MB),装完即可用,不需要构建步骤, 也不会撞上 pnpm 10+ 那条「git 依赖不准跑构建脚本」的拦截。

为什么包名带 @qiuzhiyei/ 前缀:npm 上 dsh-companion 这个无前缀名已被另一个作者占用, 所以正式包发布在作者 scope 下(npm 页面);插件在 DSH 里的显示名与功能不受影响。

装完不等于启用:宿主只有在 profile 的 cordis.patch.yml 里看到该插件的 insert 条目才会加载它, 必须在上面的插件管理器里启用,然后完全退出(含托盘)重开 DSH。

想改源码(开发模式)就 clone 一份、用 link 方式挂进去,改完 pnpm run build + 重启即生效:

git clone https://github.com/qiuzhiyei/dsh-companion.git
cd dsh-companion && pnpm install && pnpm run build

cd .. && dsh plugin --profile <你的 profile> add ./dsh-companion

跑起来后会看到:

  • 侧边栏角标:GUI 底部一行 今日 30.98M token,点它直接在当前窗口弹出完整面板
  • 伴侣页:http://127.0.0.1:17573(悬浮窗;端口被占会自动 +1,最多试 10 个)
  • 面板页:http://127.0.0.1:17573/panel

桌宠默认是「浏览器页面模式」:桌面悬浮窗需要一个可选壳,而 npm 包不带 electron (它在 devDependencies 里,100 MB+,故意不随包发)。想让她真的浮在桌面上,看下面一节。

桌面悬浮桌宠(可选壳)

给 profile 装一份 electron(不是装到插件目录):

dsh plugin --profile <你的 profile> add -D electron

装完完全退出 DSH 再重开——插件启动时检测到 electron 就会自动拉起壳(server.shell: 'auto'), 于是得到透明、置顶、点击穿透、带托盘菜单的桌面伴侣。

⚠️ pnpm 10+ 默认不跑依赖的 install 脚本,而 electron 的二进制正是靠它下载的。如果装完 仍然是浏览器模式(日志里有一行 electron 未安装,伴侣以浏览器页面模式运行),在 profile 的 pnpm-workspace.yaml 里放行它,然后重装:

allowBuilds:
  electron: true

也可以直接复用本机已有的 electron:版本相同时,把 node_modules/electron/ 里的 dist/ 和 path.txt 拷进 profile 的 node_modules/electron/ 即可(省掉 200 MB 下载)。 国内下载慢就设 $env:ELECTRON_MIRROR = "https://npmmirror.com/mirrors/electron/"。

什么都不装也能用:浏览器打开 http://127.0.0.1:17573 就是同一只桌宠(只是没有托盘、 没有鼠标穿透、不会浮在所有窗口之上)。

不想装 DSH,先看看它长什么样

node demo.mjs        # mock 事件自动循环,数据写临时目录,Ctrl+C 干净退出
node demo.mjs fast   # 20 倍速,30 秒看完一整套状态

然后打开 http://127.0.0.1:17573。不需要 API Key,也不需要 DSH。

配置

插件配置走 cordis 的 schemastery,写在 profile 的 cordis.patch.yml 里;日常用的开关都在面板「设置」页(改一个存一个,即时生效,没有保存按钮)。

键默认说明
adapter'auto'auto 接 DSH 真实事件;mock 用内置模拟器
dataDir''数据目录;空 = $DSH_HOME/dsh-companion,无 DSH_HOME 时 ~/.dsh/dsh-companion
storage'auto'auto(SQLite 优先,失败降级 JSON)/ sqlite / json
currency'CNY'费用货币
settleMs8000任务结束后表情停留时长
logEventsfalse调试:打印宿主事件
server.enabledtrue是否启动伴侣/面板 HTTP 服务(仅回环)
server.host / server.port127.0.0.1 / 17573端口占用时自动 +1(最多 10 次)
server.shell'auto'检测到 electron 时自动拉起桌面壳
server.toasttrue预算告警尝试系统 Toast
mock.auto / mock.intervalMs / mock.speedfalse / 45000 / 1模拟任务:自动运行 / 间隔 / 时间压缩倍数

面板里能直接调的:皮肤、不透明度、缩放、显示/隐藏伴侣、纯宠物模式、点击穿透、久坐提醒、 预算上限、货币、导出、暂停统计。设置分「伴侣 / 提醒 / 计费 / 数据」四组,窄窗自动变顶部胶囊。 小技巧:把鼠标移到宠物身上,按住 Ctrl 再滚滚轮即可调大小(40%–300%,每格 8%,mac 上是 ⌘+滚轮); 它和面板「设置 → 伴侣 → 缩放」滑杆是同一个值,调完立刻存盘、面板会同步。普通滚动不缩放(避免误触)。

设置页

数据都在本地:$DSH_HOME/dsh-companion/pet.sqlite(或 pet.json)+ pricing-official.json。 删掉目录就是彻底重置。

桌面壳(可选)

宿主不向插件暴露 Electron 的托盘/窗口 API,所以桌面级体验由插件自带的可选壳进程提供 (electron/,未安装则完全跳过,浏览器模式依然可用):

  • 透明、无边框、置顶、不占任务栏的悬浮窗,加载与浏览器完全相同的页面
  • 命中区域 = 宠物本体:周边透明区智能穿透,点击直达桌面/下层窗口
  • 托盘:显示/隐藏、暂停统计、打开面板、切换皮肤、导出、伴侣回到屏幕、退出
  • 窗口位置记忆 + 启动/挪窗自动夹回屏幕(拖出屏幕也不会「消失」)
  • 生命周期跟 DSH 走:插件优雅卸载时壳即时退出;宿主被强杀时壳看门狗 ~15s 内自行退出

装法(国内网络建议先设镜像):

$env:ELECTRON_MIRROR = "https://npmmirror.com/mirrors/electron/"
pnpm add -D electron
node node_modules/electron/install.js   # pnpm 拦截构建脚本时手动跑一次

不能复用 DSH 宿主自己的 Electron 可执行文件——打包过的应用只认自己的主程序。

自制皮肤

assets/skins/my-skin/
  manifest.json
  idle.png  casting.png  waiting.png  hooked.png  reeling.png
  done.png  error.png  interrupted.png
  pat.png  angry.png  dizzy.png  drag.png    ← 反应帧,可选
{
  "name": "my-skin",
  "displayName": "我的皮肤",
  "labels": { "idle": "待机中", "done": "完成" },
  "states": { "idle": { "file": "idle.png" }, "done": { "file": "done.png" } },
  "reactions": { "pat": { "file": "pat.png" } }
}
  • 皮肤名/文件名限 [A-Za-z0-9_-](防路径穿越);缺帧按回退链降级(interrupted→error→done 等)
  • 素材支持 PNG / SVG / GIF / WebP;PNG 必须透明底,显示区 220×200(object-fit: contain 不拉伸), 源图高 400px、单帧 ≤150KB 为宜;同一套所有帧用统一裁剪框,切换才不跳位
  • 有 reactions 帧就整图替换互动表情,没有就退回纯 CSS 动画——两种皮肤都能正常工作
  • 放进去即出现在设置页皮肤下拉里,无需改代码;台词口吻想跟着换,两处即可(见 AGENTS.md)

开发

src/index.ts            插件入口(cordis:name + apply + Schema 配置)
src/client/index.ts     浏览器半边:GUI 侧边栏角标 + 面板大窗 + 会话行「删除会话」菜单项
src/adapter/            真实事件适配 / mock 模拟器
src/state-machine/      动画状态机 / 任务追踪 / 预算 / 计费
src/pricing/            DeepSeek 官方定价抓取与解析
src/storage/            SQLite(失败降级 JSON)/ 统计聚合 / 导出
src/ui/                 HTTP + SSE 服务 / 页面 / 托盘 / 皮肤注册
src/ui-enhance/         宿主界面增强(会话删除)
electron/               可选桌面壳
assets/skins/           5 套皮肤素材
tests/                  node --test,81 项
pnpm run build        # 双 tsc:node 半边 + 浏览器半边(脚本模式)
pnpm test             # 81 项,应全绿
node demo.mjs         # 离线演示
  • 改 node 半边(服务/统计/告警)→ 需要完全退出并重开 DSH
  • 改 浏览器半边(角标/面板)→ 重启后再 Ctrl+R 即可
  • 本项目是 link 安装(link:<path>):改完 pnpm run build + 重启,不用重新 add

写作约定、架构决策、踩过的坑都记在 AGENTS.md(这也是给 AI 协作者的交接书), 公共 FAQ 与开发陷阱见 docs/pitfalls.md,发版流程见 npm发布.md。

测试

81 项 node --test:状态机 / 计费(含峰谷与缓存价)/ 预算 / 存储双后端 / 导出 / mock 端到端 / 插件冒烟(真实 cordis Context 加载 → 服务 → 模拟任务 → 统计 → 导出 → 可逆卸载)/ 面板与桌宠页契约(深浅色、反应帧接线、台词-皮肤映射、久坐提醒、壳 IPC 面)/ 会话管理 / 历史筛选。

已知限制

  • 费用只对 DeepSeek 官方渠道计价:deepseek-account(账号登录)与 deepseek-official(API Key)。 走自建/第三方渠道(如百炼)的任务 Token 照记,费用恒 0——与 DSH 自己的台账口径一致。
  • 不做上下文进度条:DSH 自带 UI 的口径更准,插件侧重复做只会对不上(尤其有子代理任务时)。
  • 浏览器模式拿不到点击穿透 / 置顶 / 透明 / 系统空闲检测,需要装桌面壳。
  • 系统通知在 Windows 上依赖 Toast 与焦点辅助设置;非 Windows 退化为日志 + 气泡。
  • 桌面壳需要你自己装 Electron,插件不会偷偷 npm install 任何东西。

参与

License

MIT © 2026 QiuWenXiong