DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Month Tokens — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
M

dsh-month-tokens

Month Tokens

侧边栏计数器,用于统计一个日历月内提供商报告的令牌使用量:此 DSH home 加上 opencode,仅使用本地数据,并在每月 1 日 00:00 重置。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:greyhackintoch-dev/dsh-month-tokens#082b4ff03372c7b50d316b44847fecea66b0ffa4
README兼容性版本

兼容性与来源证明

Month Tokens 以 dsh-month-tokens 发布,当前版本为 0.5.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/9/24

版本

0.5.0stable
2026/9/24

相关插件

正在加载相关插件…

最新版
0.5.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 1
周下载
0
最近提交
2026/9/24
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 models-usage 分类下经过校验的插件。

Usage@linxin666/dsh-usage用于 dsh Web GUI 的使用统计插件:检测各提供商的余额和编程套餐配额,并实时记录令牌使用情况;侧边栏 Settings 行上方显示紧凑的价格概览卡片Whale Widgetdsh-whale-widgetDSH Web 界面右下角的 DeepSeek 余额小鲸鱼挂件:余额/今日已用/峰谷定价、自定义泡泡点击序列(文本/余额/今日/峰谷/图片/随机语句与并列加权选择)、逐行样式与字体、悬浮快捷编辑、音效与每轮消耗、自定义角色/动图/音效、吸附与翻转自定义Commandcode Provider@mars-sea/dsh-commandcode-provider适用于 Command Code 的非官方 DeepSeek Harness LLM 提供商插件,移植自 pi-commandcode-provider(MIT)。注册“commandcode”提供商路由,并在 Models 页面添加卡片和实时模型目录。Plugin Subscriptionsdsh-plugin-subscriptions将 ChatGPT (Codex)、Claude、Grok (X Premium)、GitHub Copilot 和 Google Antigravity 订阅用作 DeepSeek Harness LLM 提供商,并通过网页设置页面使用 OAuth 登录

README

dsh-month-tokens

A DeepSeek Harness plugin that puts one calendar month of token usage in the sidebar, directly above Settings. It counts this DSH home and opencode, reads only local data, and resets at 00:00 on the 1st.

┌──────────────────────────────┐
│  ▮▮  本月消耗Token    3.61亿  │   ← this plugin
│  ⚙   Settings                 │
└──────────────────────────────┘

Click the row for the breakdown.

Install

dsh plugin --profile web add github:greyhackintoch-dev/dsh-month-tokens

No build step, so there is no allowBuilds approval to answer. Restart dsh web afterwards.

Install through the agent instead

Prefer not to touch a terminal? Paste this into any DSH session:

Install the dsh-month-tokens plugin by running:

dsh plugin --profile web add github:greyhackintoch-dev/dsh-month-tokens

Then confirm dsh-month-tokens appears in ~/.dsh/profiles/web/package.json
under dsh.profile.bundles, and remind me to restart dsh web for it to take
effect.

The command writes outside the agent's workspace sandbox, so expect a single approval prompt. dsh plugin reconciles the package into dsh.profile.bundles by itself — the bundle declares dsh.bundle, so its cordis.patch.yml is applied with no further configuration.

Requires a browser-shell DSH (web profile)

The browser half runs in a page with a real origin. Two consequences:

The official DSH Desktop app is not supported. dsh plugin refuses its reserved profile outright:

$ dsh plugin --profile desktop add github:greyhackintoch-dev/dsh-month-tokens
error: profile "desktop" is managed exclusively by the Electron application

Installing it there by other means would not help either. The browser half streams over a plain HTTP route (GET /token-ledger/stream), while the Electron shell loads the frontend from file:// and carries every bit of DSH's own client I/O through window.__DSH_TRANSPORT__ instead. Under file:// a relative URL has no host to resolve against — the shell's own code detects this, since location.origin is the string "null" — and nothing exposes the loopback port to the renderer, so there is no absolute URL to fall back to.

Third-party desktop wrappers that embed the standard web profile do work. If the client is a BrowserWindow pointed at the local web GUI, it is an ordinary browser context, and the command above is all that is needed.

What makes it different

Most usage plugins show you a number. This one also tells you how much of the month it could not attribute, and refuses to invent the difference.

DSH ships no projection that buckets usage by day — every shipped unit is either cumulative (tokenUsage) or a snapshot of the present (contextPressure, contextBreakdown, sessionStats). A cumulative per-session figure cannot be reconstructed into "how much of this happened after the 1st". So each session is decided by the first rule that applies, and the rule used is reported:

RuleConditionResultAccuracy
ledgeran optional per-day ledger covers the monthsum the days with this month's prefixexact
borncreated at or after the 1stits whole totalexact
idlecreated earlier, last user prompt before the 1st0exact
splitcreated earlier and prompted this month0, and counted in unattributedunknown

A long-running session that spans the boundary lands in split, and that is exactly the case where a naive counter silently reports too little. When any session lands there, local.exact is false, local.unattributed says how many, and the panel says so in the warning colour.

To resolve the remaining cases exactly, add a per-day activity projection. The community dsh-context plugin contributes one named contextActivity; when it is mounted, the ledger rule takes over automatically and no session is left ambiguous. Measured on a real 79-session home it covered 78 sessions exactly, the exception being a session checkpointed before that plugin existed. This plugin has no dependency on it — it is an optional upgrade, and everything works without it.

What it counts

SourceWhere it comes fromLatency
This DSH homeper-session tokenUsage projectionslive — pushed on every settled turn
opencodeits own SQLite database, read-onlya poll, up to ~1 minute behind

Both are local. The plugin makes no HTTP request of any kind: opencode's calls never pass through DSH, so reading its database is the only way to see them.

opencode

opencode writes one row per assistant message into ~/.local/share/opencode/opencode.db, whose data JSON carries tokens: { input, output, reasoning, cache: { read, write }, total }. The columns line up with this ledger's vocabulary almost exactly:

Ledger bucketopencode field
uncachedInputTokenstokens.input — uncached; cache reads are separate
cacheReadTokenstokens.cache.read
cacheWriteTokenstokens.cache.write
outputTokenstokens.output + tokens.reasoning

reasoning is the one translation: opencode reports it apart from output, while DSH folds it in, so the two are summed to keep the rows comparable.

Rows are filtered by providerID (deepseek by default) and by time_created >= 本月 1 日. The database is opened read-only and closed on every poll — it is a third-party schema under active WAL writes, so holding a handle buys nothing and risks a stale snapshot.

Requirements: Node 22.5+ for node:sqlite. On an older runtime the plugin still runs; it reports that opencode cannot be read instead of quietly counting zero.

Three limits worth knowing:

  1. Not real-time. opencode records usage when a message completes, so the best available cadence is a 60-second poll. The DSH number is genuinely live.
  2. Private schema. message.data is an opencode implementation detail that any release can change. A schema that still queries but yields no token fields is reported as drift, never as a smaller month.
  3. Provider, not key. providerID: 'deepseek' names the provider, not the credential. Same key in both tools → correct. Swap in a different DeepSeek key in opencode and the two are silently merged.

Override the location or the provider list in the plugin's entry:

- insert:
    - id: token-ledger
      name: 'dsh-month-tokens'
      config:
        opencodeDbPath: /custom/path/opencode.db
        opencodeProviders: [deepseek]

DSH_TOKEN_LEDGER_OPENCODE_DB overrides the path when no config is given.

Routes

RouteBody
GET /token-ledger/streamSSE; one ledger event per movement, plus : keep-alive every 25s
GET /token-ledger/summarythe same payload as one JSON document
{
  "revision": 6,
  "period":  { "kind": "month", "key": "2026-09", "start": 1788192000000, "end": 1790294400000 },
  "month":   361262338,
  "totals":  { "uncachedInputTokens": 3944544, "outputTokens": 2456933, "cacheReadTokens": 269710720, "cacheWriteTokens": 0 },
  "local":   { "total": 346169232, "month": 346169232, "monthSource": "mixed", "exact": true, "unattributed": 0 },
  "tools": {
    "opencode": { "state": "ok", "messages": 98, "fetchedAt": 1790231906819,
      "totals": { "uncachedInputTokens": 1700628, "outputTokens": 77406, "cacheReadTokens": 13315072, "cacheWriteTokens": 0 } }
  },
  "sessions": { "counted": 79, "live": 2, "skippedSeeded": 0, "scannedAt": 1790229233573 }
}

month is the headline. totals is the all-time DSH bucket breakdown, shown in the panel under a 本机历史累计(仅 DSH) caption. monthSource is ledger, born, idle, mixed, or none; tools.opencode.state is loading, ok, absent, drift, unavailable, or error.

curl -s http://127.0.0.1:3080/token-ledger/summary | python3 -m json.tool

Why the period needs no stored counter

The window is derived from the clock on every read:

start = 本月 1 日 00:00(本地时间)
end   = 明天 00:00

There is no accumulated total and no reset job, so a process that slept through midnight on the 1st still reports the new month the moment it next looks, and no reset can be missed. A timer also fires at the boundary so an open panel turns over immediately rather than waiting for the next turn or rescan.

Development

npm test        # node test/host.test.mjs && node test/client.test.mjs

The suite is dependency-free, offline, and hermetic: it points the plugin at a path that cannot exist, so it can never read your real opencode database.

To mount a working copy instead of the installed package, insert it by absolute path — dsh converts absolute paths inside insert rows to file URLs, and the client-module scanner walks up from the entry file to the nearest package.json:

- insert:
    - id: token-ledger
      name: /absolute/path/to/dsh-month-tokens/lib/index.js

Use either the bundle or the path insert, never both — the token-ledger id would collide and the duplicate route registration would fail loudly.

Restart dsh web after editing the host half. Profiles with patchReload: live recompose on a patch edit, but the host module is a plain ESM import and stays in the module cache. The browser half is read from disk, so a page refresh is enough for it.

How it is put together

  • lib/index.js — the host half. Folds DSH's projections, reads opencode, and serves the two routes. No dependencies beyond Node builtins.
  • client/client.js — the browser half, hand-bundled for the DSH client module loader (window.__ModuleLoader__.load({ id, factory })). It requires only the platform seed words react and react-dom, registers one entry into the sidebar.footer.action list slot, opens one EventSource, and renders whole values the host computed. No domain folding happens in the browser.

Counts render in Chinese myriad units — 999, 2.95万, 2.77亿 — with the exact integer on hover.

Cost

  • Cold scan on boot and every 60s: one sessionPersistence.list() (a directory walk plus a stat per session) and one in-memory cachedSnapshot per cold session. No session log is ever read.
  • One read-only COUNT/SUM over opencode's message table per minute.
  • An idle rescan does not republish, so a quiet ledger never re-renders an open panel. fetchedAt is deliberately excluded from the change comparison — including it would bump the revision once a minute forever.

Security

The two routes answer without the dsh web launch-token exchange, because the webserver's named-route table is not behind that guard. That is acceptable here: the webserver binds to 127.0.0.1 by default, the payload is aggregate counts rather than session content, and no access-control-allow-origin header is sent, so a cross-origin page cannot read the body. If you deliberately expose the GUI with networkExposure: 0.0.0.0, these two routes become reachable by anyone who can reach the port.

The plugin reads exactly two things off disk: DSH's own session projections, and opencode's message table. It never reads opencode's auth.json, never opens that database for writing, and never puts a credential or a message body into a payload or a log line — only counts.

License

MIT