bowenliang123/dsh-context
bowenliang123/dsh-contextDSH 上下文洞察面板:Context 仪表盘 + /context命令 + Context 浏览器,查看 Context的分类组成、内容详情、演进趋势、压缩/注入事件、统计等一站式 Context 全生命周期管理。
在 DeepSeek Harness 的 Web 输入框 dock 显示 OpenCode Go 套餐的 5 小时 / 每周 / 每月剩余额度。
在额度见底之前,先看见它。 OpenCode Go 的 5 小时滚动 / 每周 / 每月剩余额度,化作 dsh Web 输入框统计行里最安静的 一枚 pill——一眼可见,细节点开才有。
官网(自动跟随浏览器语言:语言列表含中文即显示中文,否则英文):https://colorlessboy.github.io/dsh-opencode-usage/ · DeepSeek Harness 插件:在输入框下方的 开发者小字里、内置「上下文已用」pill 之后,多显示一枚 OpenCode Go 额度 pill。

10 轮 89 步 · 42 tok/s │ 1.2M · 缓存命中 45% │ 24% │ 🔋 剩余 5h 80% │ 周 84% │ 月 42%
llm-pi-ai 里已配好的 provider,不复制 key、不新增设置页。lib/,dsh plugin add 秒装即用。dsh 的用量类插件很多,取舍差别主要在下面这几处:
| 常见同类做法 | 本插件 |
|---|---|
| 再造一个常驻悬浮卡 / 圆环 / 呼吸灯,占一块新位置 | 复用输入框已有的统计行,只多一枚 pill |
| 自带一套玻璃、渐变或霓虹皮肤 | 与内置「Token 用量」同一套面板 token 与皮肤 |
| 写死某个 key 引用名,或让你在面板里填 key / cookie | 跟随 llm-pi-ai 已配的 provider 与 apiKeyEnv,多账号 route 各自生效 |
| 显示「已用」,或给一个来路不明的孤立百分比 | 三档一律剩余量,chip / 面板 / 无障碍名称口径一致 |
| 接管 provider 路由、参与请求甚至计费 | 只读展示,不碰你的请求与账单 |
| 需要构建、构建授权或额外依赖 | 仓库自带 lib/,dsh plugin add 秒装即用 |
baseURL 指向
https://opencode.ai/zen/go... 时才显示;切到 DeepSeek 官方等其它 provider 时自动隐藏,
不会误报错误。每月 剩余 42%),不会出现一个来路不明的孤立数字。100% · 19% · 1%(5h / 周 / 月),悬停给出带窗口名的完整文案;非 Go 的 provider
不显示。它读同一份 host 结果,因此与 dock 芯片永远一致。该位置由 harness 的
conversation.input.model.provider.label slot 提供:没有这个 slot 的 DSH 只少这一行,
dock 芯片照常工作。/api/opencode-usage,API key 由 host 侧
credentials 服务按 apiKeyEnv 解析,永不进入页面。lib/ 是可直接加载的纯 JS 产物,装好即用,仓库不需要构建步骤。OpenCode Go 订阅的官方额度接口:
GET <baseURL>/usage # https://opencode.ai/zen/go/v1/usage
Authorization: Bearer <apiKeyEnv 对应的凭据>
返回 {"usage":{"rolling":{…},"weekly":{…},"monthly":{…}}},每个窗口带
status / percent(已用百分比)/ resetsAt。
dsh plugin --profile web add github:ColorlessBoy/dsh-opencode-usage
package.json 声明了 dsh.bundle,dsh plugin 会把它加进 profile 的
dsh.profile.bundles 并链接进 profile 的 node_modules。仓库自带可直接运行的 lib/,
安装过程不需要构建授权。
装好后重启 dsh web 并刷新页面。不启动也能先验证层已组合:
dsh --profile web --dump-config # 应出现 "# == dsh-opencode-usage" 层
在 $DSH_HOME/profiles/web/cordis.patch.yml 里按绝对路径挂载:
- insert:
- id: opencode-usage
name: /absolute/path/to/dsh-opencode-usage/lib/index.js
两种方式不要同时用:同一个 opencode-usage id 出现两行是组合错误。
dsh plugin --profile web remove dsh-opencode-usage
手工方式则删掉那一块。之后重启 dsh web。
dsh-opencode-usage/
├── package.json # dsh.client 声明 lib/client.js 是浏览器半边;dsh.bundle 指向 patch
├── cordis.patch.yml # bundle 层:插入 opencode-usage 这一行
├── lib/
│ ├── index.js # host 半边:/api/opencode-usage 路由 + 上游抓取 + 缓存
│ └── client.js # 浏览器半边:模块表 bundle,注册 dock chip 与模型菜单账号徽标
└── test/
├── host.test.mjs # 路由行为:URL 判定、凭据、归一化、错误码、缓存、鉴权
└── client.test.mjs # jsdom + 真实 React:chip、dock 同级排布、详情面板、菜单徽标、中英文案
架构上分两半,是因为 API key 只在 host 侧:
| 半边 | 职责 |
|---|---|
host lib/index.js | 解析 provider 的 baseURL / apiKeyEnv,带凭据请求上游,归一化为只含剩余量的 JSON,按 provider 缓存(成功 30s、失败 10s),对并发轮询合并为一次上游请求 |
browser lib/client.js | 从会话的 modelSelection 投影读当前 provider,轮询同源端点(15s),把 chip 渲染成 dock 的独立 pill;模型菜单按 provider 分组再取同一端点,渲染账号名后的余量徽标 |
dock 把自己的内容用 display: contents 摊平,所以 chip 是 dock 的 flex item;它用
flex order: 1 排在内置「上下文已用」pill 之后(忽略 DOM 先后),与内置 pill 共用
同一行的居中、间距和基线。
它用的是自己的 1px 竖线分隔符,而不是内置 pill 的 · 字形:三个分段挤在一枚标签里,
竖线加两侧留白比借来的圆点更窄。图标是插件自带的 16px 线稿电池(电量意象),不依赖
ui-primitives 的图标名。皮肤其余部分(字号、行高、--dsw-* 语义 token、面板圆角与
阴影)与内置 pill 保持一致;详情面板底色用菜单色叠加不透明 surface token,整卡不透明,
不会透出背后的内容。
两个脚本都从 DSH checkout 里解析 React / react-dom / jsdom,插件目录本身不需要
npm install:
DSH_CHECKOUT=/path/to/deepseek-harness npm test
DSH_CHECKOUT 省略时默认为本机的 DSH checkout 路径。test/host.test.mjs 只依赖 Node。
无。行为完全由已有的 DSH 配置推导:
| 事实 | 来源 |
|---|---|
| 当前选中的 provider | 会话的 modelSelection 投影(/model 弹窗写入的同一个值) |
provider 的 baseURL / apiKeyEnv | settings 服务投影的 llm-pi-ai 条目实时值:settings.describe() 的 value.providers.<route> |
| API key | credentials 服务解析 apiKeyEnv 指向的引用 |
未在 llm-pi-ai 中声明的 provider(例如 deepseek-official 由另一个适配器族提供)一律
视为「不适用」并隐藏。route 省略 baseURL、靠 pi-ai 内置目录继承端点时,投影里没有该
字段,同样按「不适用」处理。
profile patch 是 live reload 的,但 host 半边不会:lib/index.js 由 Node 的 ESM 模块
缓存持有,改完必须重启 dsh web。浏览器半边(lib/client.js)由 client HMR 的文件监视器
热重载,改完刷新页面即可。
模型菜单里的账号徽标依赖 harness 提供的 conversation.input.model.provider.label slot:
上游 DSH 还没有这个 slot 时,ctx.slots.inject 会一直等待,dock 芯片不受影响。
MIT