DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

seeseeczl /

seeseeczl/dsh-sym

Verified

给 DeepSeek Harness 接的共生体(dsh-sym):实时会话花费(人民币,按厂商/模型与峰谷时段折算)、每轮费用、账户余额、峰谷时段标记,以及把任一回复作为上下文引用的 @ 按钮。名字取自 symbiote —— 附着在宿主上、持续长出能力,功能不限于计费。

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@75a81e71

dsh-sym

给 DeepSeek Harness 的界面读数层。 实时花费、账户余额、峰谷时段、引用回复 —— 四件事直接叠在 DSH 原生界面上, 不新增面板,不打断工作流。

为什么叫 dsh-sym:sym 取自 symbiote(共生体) —— 就是毒液(Venom)的本体。 共生体的行为是附着在宿主身上、与宿主共生、把宿主的能力放大;这个名字记录的正是这个插件 和 DSH 的关系,也刻意不限定功能范围 —— 它会长出什么,不由名字预先决定。

输入框状态栏末尾的两个人民币费用读数

图标 功能 出现位置
💵 会话花费 输入框状态栏末尾,两个人民币金额
👛 账户余额 侧边栏左下角,账户名右边
🕐 峰谷时段 品牌行 deepseek HARNESS 后面
@ 引用回复 每条已完成回复的动作行

四处互相独立:某一处读不到数据时它自己安静退场,不影响其余三处,也不影响 DSH 本身。


目录

  • 功能
  • 安装
  • 计价规则
  • 工作原理
  • 配置
  • 开发
  • 已知限制
  • 许可

功能

1. 会话花费

输入框下方状态栏的最后,多出两个人民币金额:

⏱ 8 轮 355 步 · 255 tok/s   🗄 125M tok · 缓存命中 99.8%   💵 ¥18.03 · ¥0.466   🔲 333M   ◐ 61%
                                                          └ 本会话总计  └ 刻度选中那次任务  └ DSH 进程内存
  • 💵 本会话总计 —— 这个会话从第一条消息到现在,所有轮次累计花了多少。
  • 💬 本次任务 —— 你在聊天右侧那条轮次导航刻度上选中的那一格,对应的这一轮花了多少。 在刻度上点选或滚动,这个数字跟着变;只有一轮时不重复显示。
  • 金额旁边不写「第几轮」 —— 是哪一轮由你在刻度上的位置决定;鼠标悬停时才告诉你。
  • 悬停任一金额展开完整账单:厂商、模型、峰时/谷时、单价,以及 cache hit / cache miss / output 三个桶各自的 token 数与算式,可逐笔核对。
  • 字号与行高和同一行的其他统计信息完全一致(继承 DSH 的 --dsh-content-font-size-secondary)。

计价覆盖 1046 个模型、42 家厂商,不只是 DeepSeek —— 详见计价规则。

2. 账户余额

侧边栏左下角,你的账户名右边同一行:

[头像] 陈志龙                    [钱包] ¥123.45
  • 走的是 ctx.remote.account,和「设置 → 账户」那张卡同一个官方接口、同一份凭据。
  • 只读 DeepSeek 账户余额;不涉及其他厂商,也不做多账户。
  • 挂载时读一次,之后每 60 秒刷新;点击立即刷新;读不到时改成每 5 分钟才重试。
  • 悬停显示充值余额、赠送余额和上次更新时间。
  • 优先显示 CNY 钱包,只有美元钱包时显示 $。

位置是怎么落上去的:DSH 在侧边栏底部留的插件扩展位默认是竖排在账户行上方, 而账户行本身是「替换型」插槽,接管它会丢掉官方的账户菜单(反馈、退出登录)。 所以本插件用一条 CSS 把底部那一行从竖排改成横排,余额就落到了账户行右侧。 这条规则用 :has() 严格门控 —— 只有余额格真的渲染出来时才生效; 没登录、读不到余额、收起窄栏或卸载插件时,官方布局一个像素都不变。

3. 峰谷时段

品牌行后面跟着一个琥珀色的峰时标记

品牌行后面跟着一个状态标记,一眼就能看出现在贵还是便宜:

  • 峰时 —— 琥珀色描边,DeepSeek 按标准价计费
  • 谷时 —— 灰色,DeepSeek 按半价计费

悬停显示规则原文。

刷新时机:定时器直接算到下一个边界,一天只在固定时刻触发 5 次 (北京时间 09:00、12:00、14:00、18:00、00:00),在边界后约半秒翻转。

这是单次定时器,不是轮询 —— 一天 5 次,比任何固定间隔轮询都省, 而且边界一到就变。窗口重新获得焦点、或从后台切回时还会立即重新对时: 浏览器会节流后台标签页的定时器,只靠定时器的话,从睡眠唤醒后标记可能还是旧的。

实现方式:品牌行是官方元素,没有加法插槽。本插件用 CSS 给它的 ::after 接了个标签,内容从根上的 CSS 变量 --dsh-peak-label 读,颜色由 data-dsh-peak 决定。 没有替换任何官方组件;卸载后属性、变量和样式一起消失。

4. 文件链接右键菜单

回复里的文件链接(写成 [短名](/绝对/路径) 的 Markdown 链接)除点击打开外, 右键会弹出一个菜单:

  • 复制路径 —— 把磁盘上的绝对路径放进剪贴板
  • 在访达中显示 —— 走官方的 session.openWorkspacePath 的 reveal 动作

只在文件链接上接管右键,其他位置的系统菜单原样保留。菜单样式沿用官方 弹出层的变量(--dsw-specific-menu / --dsw-elevation-prominent)。

顺带一条使用约定:给模型看的路径写成反引号(只读),给人点的写成 Markdown 链接。裸写路径虽然 DSH 也会自动转成链接,但显示出来是一长串 URL,比链接难看。

5. 引用回复

输入框里出现一个短标记,模型读到的是完整原文

每条已完成的回复,动作行里多一个 @(在 👍👎 之后)。点一下,输入框里只出现一个短标记:

@引用#9806056fac67 

你接着写新任务、发送即可 —— 模型读到的是那条回复的完整原文,不是这个标记。

怎么做到的:标记里只有消息 id 的前 12 位,替换发生在发送时、宿主侧:

  1. 宿主半边一直听着 session/event,把每条已完成的回复按 message id 记进一张有界索引 (只留最近 400 条);
  2. 消息进入模型请求之前,宿主的 agent/pre-step 钩子扫描即将发送的消息,找到 @引用#xxxxxxxxxxxx,从索引取出原文,替换成 Markdown 引用块(每行前缀 >);
  3. 索引里找不到的标记原样保留 —— 不报错,也不丢内容。

思路和 DSH 自己注入会话快照(dsh-session-reference)的方式一致。整个链路都在本地,不联网。

几个边界:

  • 只取正文:text 内容块按顺序拼接;推理内容和工具调用不含在内 —— 引用的是结论,不是过程(否则一次带界面操作的回复会拖进去几万字的快照)。
  • 只对之后的发送生效:标记在发送那一刻展开,历史消息不受影响。
  • 不动会话结构:不分支、不新建会话,只是把那段原文带进这一次请求。
  • 索引在内存里:App 重启后索引随会话被读取重新填充;引用一条很久以前、已被淘汰的回复时, 标记会原样保留。
  • 插入成功按钮短暂显示 ✓;输入框不可用(拿不到插入点)显示 !,把光标放进输入框再点一次。

为什么不用 DSH 原生的 @ 引用:DSH 的引用语法 @[label](dsh-session:<id>) 是会话级的, 最小粒度就是整个会话,没有「引用某一条消息」。所以要精确引用「中途那一次回复」, 只能用一个自定义标记,再由宿主在发送时展开。


安装

这是一个 DSH 组合包(bundle):装进来之后,profile 会把它自带的 cordis.patch.yml 合并进自己的 cordis 配置树,无需手工改配置。

方式一:让 DSH 装(推荐)

# 从 GitHub 装(推荐)
dsh plugin --profile desktop add github:seeseeczl/dsh-sym

# 从 Release 附件里的 tarball
dsh plugin --profile desktop add /绝对路径/dsh-sym-1.1.0.tgz

# 从本地目录
dsh plugin --profile desktop add /绝对路径/dsh-sym

本包没有发布到 npm:它是零依赖、无构建步骤的纯 JavaScript,从 git 或 tarball 安装与从 npm 安装没有区别。npm 上确实有一个叫 dsh-hud 的同类包(另一个作者的项目), 与本项目无关。

也可以在 GUI 里走「设置 → 插件 → 安装」。

方式二:手工挂进 patch

不装进 node_modules,直接让 profile 的 cordis.patch.yml 指向本地文件:

- id: sym-cost
  name: 'file:///绝对路径/dsh-sym/lib/host-v7.js'

再在同一个文件末尾确保它是启用的:

- id: sym-cost
  disabled: false

卸载

停用即可(GUI 里关掉,或在 patch 里写 disabled: true),然后删掉包。 本插件不会修改 profile 里任何其它条目。


计价规则

DeepSeek 官方价(人民币 / 每百万 token)

模型 cache hit cache miss output
deepseek-flash 0.04 2 8
deepseek-v4-flash 0.04 2 8
deepseek-v4-flash-vision-exp 0.04 2 8
deepseek-v4-pro 0.30 9 27

谷时(空闲时段)价格 = 表中数字 × 0.5。

峰谷时段

以北京时间为准:

  • 峰时:周一至周五 09:00–12:00 与 14:00–18:00,法定节假日除外
  • 谷时:其余全部时间(含周末、法定节假日全天、以及上面两个区间之外的工作时段)

节假日表在 lib/prices.json 的 holidays 字段里,格式 YYYY-MM-DD,按年维护。

其他厂商的模型

DSH 内置了一份 pi-ai 价目目录(42 家厂商、1046 个模型,美元计价,含 cacheRead/cacheWrite)。 当会话用的不是 DeepSeek 模型时,本插件按下面的顺序找价格:

  1. DeepSeek 官方价(上面的表)—— 命中就用它,人民币直接计价,不经过汇率;
  2. pi-ai 目录 —— 按「厂商 + 模型」精确匹配;匹配不到时退化为按模型名匹配(多个厂商拥有同名 模型时取最短厂商名,保证结果稳定);
  3. lib/prices.json 的 models 覆盖 —— 你手工写的价目,优先级最高,改完存盘即生效。

命中 2 或 3 时,美元价按 usdToCny 折算成人民币。

认不出的模型不会被计费,只会在悬停账单里标出来(unpriced)—— 宁可少算,也不瞎算。

自定义价格

编辑 lib/prices.json:

{
  "usdToCny": 7,
  "holidays": ["2026-01-01", "..."],
  "models": {
    "some-model": { "input": 1.5, "output": 6, "cacheRead": 0.15, "cacheWrite": 2 }
  }
}
  • usdToCny —— 美元折算汇率
  • holidays —— 法定节假日(峰谷判断用)
  • models —— 覆盖价目;键是模型名,值是美元 / 每百万 token
  • 文件里的 _readme 字段带着中文字段说明,不用另查文档
  • 改完存盘立即生效,不用重启(宿主每次投影都会检查文件修改时间)

工作原理

本插件由两个半边组成,各自跑在不同的进程里:

┌─ 宿主(Electron 主进程,Cordis 插件树) ─────────────────────┐
│  lib/host-v7.js                                              │
│   • sessionProjections 注册 sessionCost —— 会话事件的纯折叠   │
│   • 折叠 request/header、assistant/message、llm/retry-started │
│   • 只存 token 数(按峰/谷、按轮次、按模型分桶),不存金额     │
│   • 价目:DeepSeek → pi-ai 目录 → prices.json 覆盖            │
│   • 监听 session/event 维护 messageId → 正文索引              │
│   • 监听 agent/pre-step 展开引用短标记                        │
└──────────────────────────────────────────────────────────────┘
                            ↓ 投影(纯 JSON)
┌─ 浏览器(渲染进程,客户端插件) ─────────────────────────────┐
│  lib/client.js                                               │
│   • conversation.composer.dock   → 两个费用金额              │
│   • sidebar.footer.action        → DeepSeek 余额             │
│   • conversation.chat.assistant-actions → @ 引用按钮          │
│   • 根上的 CSS 变量 + data 属性  → 品牌行的峰谷标记           │
└──────────────────────────────────────────────────────────────┘

为什么金额在客户端算、token 在宿主算:宿主只折叠 token 数(可序列化、可 checkpoint、 跨重启一致),价格表可能被 prices.json 随时改。客户端每次渲染时用当前价目重新折算, 所以改价格不需要重算历史、也不需要重启。

投影是纯折叠:sessionCost 对每个已提交的会话事件做一次 apply,不产生副作用。 会话恢复时从事件重放,结果一致;stateVersion 变化时注册表会拒绝旧 checkpoint 并重建。


配置

本插件没有需要配置的开关:装好即用,读数按需出现。

唯一的配置文件是 lib/prices.json(见上)。

宿主半边改动(lib/host-v7.js)需要重启 App;客户端半边(lib/client.js)和 lib/prices.json 都是热生效的。


开发

目录

lib/host-v7.js     宿主半边:投影折叠 + 价目来源 + 引用展开
lib/client.js      客户端半边:四处显示 + 峰谷标记
lib/prices.json    价目覆盖 / 汇率 / 节假日
cordis.patch.yml   组合包补丁(让 profile 一次性装好)
test/              仓库内回归(npm test,31 个断言,零依赖)
scripts/           开发脚本(宿主换名助手 reload-host.mjs)

两个半边都是零依赖的纯 JavaScript(ESM),没有构建步骤,改完直接生效。

热重载

改动 生效方式
lib/client.js 客户端插件热更新,页面自动重载该模块
lib/prices.json 立即生效(宿主按 mtime 检测)
lib/host-v7.js 需要重启 App,或用「停用 → 换文件名 → 启用」绕开模块缓存

宿主半边改动之所以麻烦,是因为 DSH 的宿主热重载只监听配置与补丁文件,不监听插件代码。 换一个新的文件名(host-v7.js → host-v7.js)能拿到一个全新的模块实例,但必须等旧实例 完成 dispose,否则新旧注册会撞在一起。换名与同步引用已脚本化:

node scripts/reload-host.mjs --dry-run   # 先看会改哪些文件与行
node scripts/reload-host.mjs --apply     # 真改;停用/启用与重启仍由人完成

测试

仓库内有回归,入口是 npm test(等价于 node --test,不要写成 node --test test/, Node 24 会把目录当模块解析而失败):

文件 覆盖
test/host.test.mjs 峰时边界、周末/节假日、引用展开与未知 id、索引淘汰、价目常量、内存读数、失败路径
test/client.test.mjs describeScope 账单文本(峰谷拆分、两项省钱、未收录模型、flat 厂商)、插槽注册幂等、降级日志
test/contracts.test.mjs 跨端契约常量两端一致,且客户端写出的引用标记宿主能展开

回归只覆盖纯函数:渲染、插槽注册的实际效果、热更新仍要人工验证。开发时的其余做法:

  • 客户端组件:test/helpers/load-client.mjs 用最小的 React hooks 替身物化模块工厂 (不引入 jsdom);要断言真实渲染仍需 CDP 驱动一个 headless 页面点击真实按钮
  • 端到端:curl 取页面里 plugins/??dsh-sym/client.js 的 bundle,确认各项注册都在
  • 降级排查:控制台搜 [dsh-sym],每个来源只记一条,能看到是哪个可选能力缺席了

已知限制

  • 余额需要桌面版已登录 DeepSeek 账号。未登录、账号态读不到时会整行不显示(不会显示 0 或占位符)。
  • 引用索引是内存里的,App 重启后重新填充;引用一条已被淘汰的旧回复时标记原样保留。
  • 峰谷判断按北京时间,用内置节假日表;表过期时节假日会被当成工作日(记得按年更新 holidays)。
  • 认不出的模型不计费,只在悬停账单里标出。
  • 没有「把会话移动到别的工作区」这个功能。它曾有一份用真实数据副本验证过的实现, 但 DSH 在构建期就固定了客户端可用的 Remote 命名空间,插件无法新增 「界面点一下 → 宿主做一件事」的通道,所以它永远点不到。代码已于 2026-09-30 移入 docs/01-architecture/adr-003-session-move-not-wired.md 作为设计记录, 不是已交付能力(ADR-003)。
  • 账户余额那一行的布局用了 CSS :has(),需要 Chromium 105+(DSH 自带的远高于此)。
  • 侧边栏收起成 56px 窄栏时,余额不显示(空间不够,官方布局也保持原样)。

许可

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 75a81e7178a5

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout