Chuyển đến nội dung chính

dsh-plugin-token-report

Đã xác minh

dsh-plugin-token-report · v0.9.0 · MIT · Giao diện web

DSH 插件:无人值守地把 token 用量实时上报到部门服务端,另提供 token_usage 工具、ctx.tokenReport 服务与界面用量面板。

Cài đặt

dsh plugin add dsh-plugin-token-report

Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.

Mã nguồn

Thẻ

Tác giả

Readme

dsh-plugin-token-report

在 DeepSeek Harness(DSH) 里直接查看本机 token 用量:输入框上方一条用量条,点开就是趋势图、 模型排行与自定义日期范围;要往部门看板汇总时,再填「服务端地址 + appKey」开始上报。

不填就不发:未署名 / 未配 appKey 时,插件只读本机日志 —— 不采集上报事件,也不上报。

  • 📊 界面用量面板 —— 输入框上方的用量条(0.3.0 起是默认位置)或会话标题栏右上角的胶囊,共用同一个详情面板
  • 🧮 只展示真值 —— 计费总量 = 未缓存输入 + 输出 + 缓存读 + 缓存写;cacheRead 不是 input 的一部分
  • 💰 费用(估算) —— 按本机单价快照现算;未计价的用量写「未计价」而不是 ¥0.00,金额绝不跨币种相加
  • 🔗 多套 DSH 并集 —— 命令行版与 DSH Desktop 的会话日志一起统计;互为镜像的会话按 event_id 去重,只算一次
  • 🔌 本机客户端全覆盖 —— DSH / Codex / Claude Code / Trae(国际版与国内版)/ WorkBuddy 缺省就一起统计、也一起上报;装了哪个就有哪个,不用配置
  • 📤 实时上报 + 历史补报 —— 异步批量、磁盘 outbox、断网续传;服务端按事件 ID 去重,重复投递无害
  • 🤖 Agent 可查询 —— token_usage / token_usage_diagnostics 工具,以及供其它插件调用的 ctx.tokenReport 服务
  • 🔒 不采集对话内容 —— 只取 token 数值、模型名、工作目录与轮次等统计字段

快速开始

dsh plugin --profile web add dsh-plugin-token-report@latest
  1. 重启 —— dsh --profile web --no-open,用终端打印的完整地址打开浏览器
  2. 看用量 —— 选择工作区,输入框上方出现用量条。想汇总到部门看板,点面板右上角齿轮「配置」填服务端地址 + appKey,保存即生效,不必重启

不需要改任何 profile 配置:0.9.0 起本插件不再注册 sessionTelemetry 服务(那个名字由官方 OTel 后端占用),改为订阅宿主会话事件流 —— 因此与官方 session-telemetry-otel 可以同时开着,各记各的。桌面端(DSH Desktop)的安装见「在 DSH Desktop(桌面端)上安装」。

环境要求

项 要求
DSH 宿主 0.1.7-rc.2 或更高、0.3.0 之前(本插件已在 0.1.7-rc.2 与 0.2.0-rc.2 上实测启动)
宿主模块 与宿主同代(@deepseek-ai/cordis ~4.0.4)。插件只吃宿主的会话事件流(@deepseek-ai/dsh-session)—— 0.9.0 起不再依赖 @deepseek-ai/dsh-session-telemetry
Node.js ≥ 22.15.0
profile 需要 web profile(界面面板与 /api 数据通道在那里;headless profile 下只有上报与工具)

上面那个版本窗口是兼容窗口,不是精确版本:宿主启动时逐个 peer 判定,任一不满足就跳过整个 bundle —— 现象是「面板不见了 + 一条也不上报」,启动日志只有一行 skipping profile bundle …, 不是报错。排查看下方「升级与常见问题」的排查表。

实际使用截图

以下截图来自 2026-09-25 本机运行的 DSH Web 与真实会话日志,仅截取插件区域。数值是该机器当时的用量,不是模拟数据,也不代表性能基准。

用量概览与模型明细

点击输入框上方 TOKEN 用量 条里的「详情」,即可查看计费总量、未缓存输入、输出、缓存读、缓存命中率、调用数和会话数。趋势支持切换 Token 总量、调用数与命中率,明细支持模型、服务商、项目和会话分组,点击行可展开,超过 10 行可翻页。

真实 DSH 插件用量概览

自定义日期范围

除了今天、昨天、本周、最近 7 天、本月、近 30 天和今年,还可以通过双月日历选择开始与结束日期。开始与结束日期既可以点日历选,也可以直接敲进输入框(2026-09-21、2026/9/21、2026年9月21日 都认,失焦后统一成 2026-09-21);格式不对、日期不存在或开始晚于结束时,标题右侧会说明原因,「应用范围」只在区间可用时才可点。范围按本地时区计算,包含起止两天,点击「应用范围」后更新统计;生效期间按钮上直接显示所选区间(如 09-12 – 10-06)。

真实 DSH 插件日期选择

安装最新稳定版

前置要求(宿主版本窗口、Node 版本)见上方「环境要求」。安装本身只有一条命令:

dsh plugin --profile web add dsh-plugin-token-report@latest

dsh plugin add 会自动在 ~/.dsh/profiles/web/package.json 的 dsh.profile.bundles 中登记发布包。检查它只出现一次,且没有 0.9.0 之前的旧仓内源码包名 @ai-token-report/dsh-plugin(那个名字现在只用于清理历史装机);不要再手动 insert 插件。正常列表例如:

{
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        "dsh-plugin-token-report"
      ]
    }
  }
}

不需要额外改 cordis.patch.yml:0.9.0 起本插件不注册 sessionTelemetry 服务,所以官方 session-telemetry-otel 可以继续开着 —— 它只在你主动提交反馈时上传,本插件只看 token 数值与模型名。

⚠️ 0.8.x 及更早是互斥的:那一版把自己注册成第二个 telemetry 后端(cordis 同名服务只能注册一个),所以必须在同一个 cordis.patch.yml 里合并 - id: session-telemetry-otel 与 disabled: true,否则 DSH 启动会失败并只报一行 service "sessionTelemetry" has been registered at <OpenTelemetrySessionBackend>。 升级到 0.9.0 之后那一行可以删掉(留着也无害 —— 只是官方后端不再工作)。

随后重启 DSH,用终端打印的完整地址打开浏览器:

dsh --profile web --no-open

选择工作区后,输入框上方会出现用量条(0.3.0 起这是默认位置)。想让面板改到会话标题栏右上角、或两个位置都要,见下方「调整面板位置」。安装后无需单独启动本地统计网页。

dsh plugin 内部调用宿主自己的包管理器。上面的安装命令用于 DSH profile;本仓开发、构建与发布使用 Bun。

在 DSH Desktop(桌面端)上安装

桌面端与命令行版走的是同一条装配路,只是 home 与 profile 换成了 Desktop 自己那套; 但桌面端的图形入口装不了本插件,所以下面给的是命令行步骤。

同一套步骤的交付版在仓库的 docs/桌面端安装交付清单.md(逐条命令 + 核对 + 回滚, 文件不在 npm 包里,所以这里只写路径);本节是它的说明版。

为什么不能用桌面端的插件界面装

入口 能不能装 原因
侧边栏「插件」(社区插件市场 dshmarket) ❌ 市场只允许安装 awesome-dsh-plugin 精选列表内的来源,其它一律拒绝(其 README 明写)。实测该目录 plugins.json(约 5 MB)里 token-report 0 命中
上游「插件」管理页(@deepseek-ai/dsh-plugin-manager) ⚠️ 未实测 它接受 npm 包名 / 本地路径 / tarball / git,但在 Desktop 上包操作归 Desktop shell 所有,会走下面的 generation 管线

想让同事在界面里一键装,唯一途径是把包 PR 进 awesome-dsh-plugin 精选列表。

桌面端与命令行版的四个差别

命令行版 DSH Desktop
DSH home ~/.dsh(或 $DSH_HOME) %APPDATA%\dsh-desktop\harness(macOS:~/Library/Application Support/dsh-desktop/harness)
profile 任意 只有 web —— Desktop 只暴露这一个,别的名字直接抛错
宿主 你自己装的 dsh Desktop 自带一整套 harness,在 <安装目录>\resources\app.asar.unpacked\node_modules\ 下(本机实测 @deepseek-ai/dsh = 0.1.7-rc.2、@deepseek-ai/cordis = 4.0.4、随包 Node v24.9.0)
包操作 你调 dsh plugin … Desktop 启动时会做 profile maintenance:把非市场来源的插件迁成不可变 generation(.generations/live/<...>,一次 rename 上线),并写 dsh.desktop.generationProjection 与 pnpm.overrides;迁移失败会写 profiles/web/.generations-deferred.json 并冻结该迁移

其余一律相同:数据目录仍是 ~/.ai-token-report,与命令行版共用(身份 / appKey 填一次两边都生效,见上方「多套 DSH 并存」);会话日志按本机全部 DSH 的并集统计。

步骤

① 退出 DSH Desktop(要写 profile 与 node_modules)。

② 打开一个 PowerShell,把 home、宿主入口与 Desktop 自己的 pnpm 都指过去:

# 安装目录按实际替换(本机在 D:\Program Files\DSH Desktop)
$desktopRoot = "D:\Program Files\DSH Desktop"
$desktopDsh  = "$desktopRoot\resources\app.asar.unpacked\node_modules\@deepseek-ai\dsh\lib\bin.js"

$env:DSH_HOME = "$env:APPDATA\dsh-desktop\harness"
$env:PATH     = "$env:DSH_HOME\.desktop-bin;$env:PATH"   # ★ 用 Desktop 的 pnpm,别用系统里那个

PATH 这一行不是可有可无:Desktop 的 pnpm.cmd 会在 pnpm 跑动期间临时排除 generation 投影, 换成另一个 pnpm 就绕开了这层保护。

③ 装包(两种 spec 二选一):

# npm 稳定版
node $desktopDsh plugin --profile web add dsh-plugin-token-report@latest

# 本地 tarball:未发布的版本 / 离线分发。
#   ★ 路径用正斜杠,反斜杠会报 ERR_UNSUPPORTED_ESM_URL_SCHEME;下面的版本号按实际 tarball 替换。
node $desktopDsh plugin --profile web add file:D:/path/to/dsh-plugin-token-report-0.9.0.tgz

add 会自动在 profiles/web/package.json 的 dsh.profile.bundles 里登记包名;不要再手动 insert。

④ 官方 OTel 不需要再禁用(0.9.0 起):本插件不注册 sessionTelemetry 服务,两边可以同时开着。0.8.x 才需要在这一步往 profiles/web/cordis.patch.yml 里写 - id: session-telemetry-otel + disabled: true;升级后那两行可以删掉。

⑤ 核对(只读,不起服务):

node $desktopDsh plugin --profile web list              # 本机实测:[email protected]
node $desktopDsh --profile web --dump-config | Select-String token-report

⑥ 重启 DSH Desktop。 面板出现即装好(默认输入框上方;位置在面板「配置」里改,保存即生效)。

装好之后

  • 启动日志会打印 UI 用量面板数据通道已挂载 → GET /api/tokenReport.stats(面板位置:…)。

  • 桌面端看不到宿主的终端输出(它写进 %APPDATA%\dsh-desktop\logs\harness.log),本次启动的完整地址(含 ?token=) 就在那行 dsh web: http://127.0.0.1:<端口>/?token=… 里。想确认界面数据通道真的在跑,就用它取一次配置路由 (/api 前面有 Host/Origin 栅栏,所以要带 Origin 与上一步拿到的 cookie):

    $url = "http://127.0.0.1:<端口>/?token=<启动日志里那串>"
    $jar = "$env:TEMP\dsh-cookies.txt"
    curl.exe -s -o NUL -c $jar $url
    curl.exe -s -b $jar -H "Origin: http://127.0.0.1:<端口>" "http://127.0.0.1:<端口>/api/tokenReport.config"
    # 本机实测:200 + {"position":"dock"}
    
  • 首次使用、填服务端与 appKey、看「上报调试」,都与命令行版一致,见「第一次使用」与「开启团队上报」。

三个坑

  1. 🚨 版本窗口:当前 peerDependencies 是 >=0.1.7-rc.2 <0.3.0-0,放宽后的窗口从 0.7.0 起就在 npm 上(0.6.0 及更早那一版钉的是精确 0.1.7-rc.2)。宿主启动时由 dsh-app-boot 的 evaluatePluginCompatibility 逐个 peer 做 semver.satisfies(runtime, range, { includePrerelease: true }),任一不满足就跳过整个 bundle —— 日志只有一行 skipping profile bundle …,表现是「面板不见了 + 一条也不上报」,不是报错。所以:
    • Desktop 自带的 0.1.7-rc.2(以及 0.2.x)都在窗口内,装 @latest 即可,不需要为了拿放宽窗口去手工打 tarball(tarball 只在「装未发布版本」时才用得上)。
    • 反过来,Desktop 升到 0.3.0 及以后会被跳过。那时要么等插件放宽并复验,要么用宿主自己的 allow-version … --accept-risk 强制放行(自担风险,不等于已验证)。
  2. 不要把仓内源码目录装进 Desktop:发布包是构建产物(index.js / client.js),而仓内目录要先 bun run --filter dsh-plugin-token-report build、且依赖写的是 workspace:*(指向两个从未发布的私有包)。宿主跑在 Node 上、也不会替你构建,所以桌面端只用发布包或 tarball。
  3. 升级 / 卸载走同一条路,不要只手改 package.json:一旦 Desktop 的 generation 迁移成功,插件会被搬进不可变的 .generations/live/<...>,那时只有重新 add 才换得了版本(plugin remove 会走 Desktop 的 generation 下线流程)。

第一次使用

  1. 打开「详情」,选择需要查看的周期。首次建立索引可能需要十几秒,后续只增量读取变化的日志。
  2. 切换趋势指标或明细分组查看用量来源。图表下方「查看图表数据」提供精确值。
  3. 手动点击刷新即可读取最新数据;页面每 3 秒问一次「有没有新数」(没有就零成本), 有新采集时按宿主缓存节奏(最多 30 秒)自动更新;切回前台标签页会立刻取一次。

仅查看本机统计不需要署名。未署名时,插件不采集上报事件,也不上报。 页面读取的是 DSH 已有的本机会话日志。

多套 DSH 并存(DSH Desktop / 命令行 / 第三方客户端)

一台机器上同时装着多套 DSH 时(命令行版 ~/.dsh、DSH Desktop 的 %APPDATA%\dsh-desktop\harness……), 插件缺省把它们的会话日志一起统计。发现是结构驱动的 —— 候选目录里只有真的有 sessions 子目录 的才算一个根 —— 所以面板上的数字是多套 DSH 的并集,接入新的第三方客户端不需要改配置。

两套 DSH 的会话经常互为镜像(同一份日志被两边各记一份)。镜像按 event_id = <sessionId>:<seq> 去重、 只算一次,所以「并集小于各自相加」是正确结果,不是漏扫。启动日志与 token_usage_diagnostics 会逐一列出这次实际读到的根 —— 「我的数据到底读了哪几处」不会只给一个数字。

署名、连接配置与本地索引库都在同一个「数据目录」里,缺省 ~/.ai-token-report/,它与会话日志根无关, 所以多套 DSH 缺省就共用同一份身份与配置,Desktop 里不会再出现「尚未署名」,不需要任何配置:

<数据目录>/identity.json            ← 署名(token 就是 appKey)
<数据目录>/plugin-connection.json   ← 面板里填的服务端地址 / appKey / 间隔 / 位置 / 会话日志根
<数据目录>/usage.sqlite             ← 本地增量索引库(日志的派生物,可删可重建)
<数据目录>/outbox/                  ← 磁盘 outbox(崩溃不丢数据)

只有两种情况才需要动配置:想钉住统计范围(只看其中几处)用 dshHomes —— 面板里就能改(齿轮「配置」→「会话日志根」,保存即生效),也可以用部署配置 dshHomes 或环境变量 DSH_TOKEN_REPORT_DSH_HOMES 统一钉死; 想让某套 DSH 单独用一份身份 / 库用 dataDir(对应环境变量 DSH_TOKEN_REPORT_DATA_DIR, 只能在部署配置 / 环境变量里给 —— 换掉它等于连身份 / 库 / outbox 一起换,会让人「突然变成另一个人」)。

🚨 不要用日志根去达到「分开身份」的目的:dshHome / dshHomes 换掉的是日志来源, 那会让面板少算另一套 DSH 的会话,而实时上报照常工作 —— 这个错误不会以「完全没数据」的形式暴露。

别的 AI 客户端也算(缺省就是全算)

面板、token_usage 工具与上报都覆盖本机全部已注册来源:DSH、Codex、Claude Code、 Trae(国际版 trae / 国内版 trae-cn,两个发行版算两个来源)、WorkBuddy。 没有开关要打开 —— 本机装了哪个客户端,它的用量就进面板、也会进部门看板; 没装的那些自然不会出现(诊断里会逐项报出解析到的根)。

代价必须知情:第一次取数与第一轮历史补报要冷扫这些日志(本机实测 Codex 就有 1,500 个文件 / 2.8 GB,十几秒到几分钟),之后按文件字节数增量,只解析变化过的文件。 嫌慢就把那个客户端的日志目录挪走,或者用它自己的环境开关关掉 (例如 DSH_TOKEN_REPORT_CODEX=0)—— ⚠️ 这一项刻意不在面板里: 「我不想统计 Codex」是一件部署策略级的事,不该和「我的服务端地址」放在同一个表单里。

为什么不再做成「白名单」:少统计一个来源没有任何下游信号 —— 面板数字看着完全正常, 而它与「我在那台客户端上本来就没用量」长得一模一样。采集范围不是性能偏好,是一句会被读成结论的口径。

调整面板位置

面板默认出现在输入框上方。想让它出现在会话标题栏右上角、或两个位置都要, 有两种办法 —— 面板内改(推荐,立刻生效),或在 profile 里改部署配置。

办法一(0.6.0 起):面板右上角齿轮「配置」→ 面板位置 → 验证并保存。 保存后面板就地换地方,不必刷新页面、更不必重启 DSH:

取值 效果
输入框上方(用量条) 只显示输入框上方的用量条(默认)
会话标题栏右上角(胶囊) 只显示标题栏右上角的胶囊;点开就是同一个详情面板
两处都显示 两处都显示 —— 与 0.2.0 的外观一致

这一项与下面「部署配置」写的是同一个东西,只是存在本机 (<数据目录>/plugin-connection.json,缺省即 ~/.ai-token-report/,见上方「多套 DSH 并存」),并且优先于部署配置。

办法二:在 profile 的 cordis.patch.yml 里给插件加一段 ui —— 适合「IT 统一规定全公司都用某个位置」:

- id: token-report
  config:
    ui:
      position: dock      # dock(默认,输入框上方) | header(右上角) | both(两处都要)

改完刷新页面即可生效。三种取值共用同一个详情面板,数字口径完全一致。 也可以不改 YAML,用环境变量 DSH_TOKEN_REPORT_UI_POSITION 临时覆盖。

写错的值不会让面板消失:只认上面三个值,其它一律回退 dock,并在 DSH 启动日志里告警。 面板内那一栏同样只提供这三个值,选不出非法值。

开启团队上报

在详情面板右上角点击齿轮「配置」,五个字段:

字段 说明
服务端地址 部门平台根地址(例如 https://portal.example.com,或本机自建的 http://127.0.0.1:8787)。上报地址由它推导(<地址>/api/v1/token-usage),不需要自己拼路径
appKey 管理员在平台「appKey 管理」页签发的那一串。已配置时留空 = 只改下面各项偏好,不会重新校验、也不重写身份文件
上报间隔 5 秒 / 10 秒(默认)/ 30 秒 / 1 分钟 / 5 分钟。这个数字直接决定部门服务端的请求密度,所以只给档位
面板位置 见上一节;保存后就地换地方
会话日志根 每行一个 DSH home;留空 = 自动发现。见上方「多套 DSH 并存」

点击「验证并保存」后,插件用这个 appKey 向对应服务端的 /api/v1/identity/verify 校验身份, 姓名与分组以服务端返回值为准(面板不再询问姓名 —— 它由 appKey 在服务端绑定的人决定)。

★ 保存后立即生效,不需要重启 DSH。 保存成功后页面会如实回报当前状态 (「已保存并开始上报 → 地址」或「上报仍未启用:原因」),并当场开始补报本机全部历史用量。 已保存的 appKey 不回显。

看「到底上报了什么」(上报调试)

配置页第二个页签 「上报调试」 是排查「部门看板上没有我的数」的地方。 它每 3 秒刷新一次,把下面这些一次说清:

  • 在不在上报:状态 + 地址;没在跑时给原因(未署名 / 未配 appKey / 部署关闭了上报)。
  • 发了多少:已采集、已投递(含重复与拒收)、内存队列、磁盘待投递(批数 / 条数 / 字节)、 请求数与失败数、最近成功时间。
  • 最近上报:每次真实请求的请求体原文(点开可展开)+ 服务端回执 (接收 / 重复 / 拒收)与 HTTP 状态。请求体过大时只显示开头,并明确标注「已截断」。
  • 历史补报进度:扫描文件数 / 服务端确认数 / 上次错误。
  • 两个按钮:「立即上报一次」(真发)与「预览下一批内容」(只显示,不发送、不消耗队列)。

🚨 页面里看不到 appKey。 调试数据由宿主半的 GET /api/tokenReport.reports 提供, 而宿主只保留请求体、不保留请求头 —— appKey 走 Authorization: Bearer,天然不在这里。 不要为了「方便排查」把请求头加进去:那会把一个调试页变成凭证泄漏面。

身份与连接保存在数据目录下(缺省 ~/.ai-token-report/;DSH Desktop 与命令行版缺省就共用同一份、不需要任何配置,见上方「多套 DSH 并存」)。插件与本地 Web 共用身份文件。部署侧固定了身份时,页面会提示配置由管理员管理。

启用上报后,插件会在后台扫描上面那些会话日志根(缺省是本机全部 DSH home)以及本机全部已注册来源(Codex / Claude Code / Trae / WorkBuddy)下的全部历史会话,分批补报用量,直到服务器全部确认收到;不需要逐个打开旧会话。实时新用量同时上报,服务端按事件 ID 去重。断网或退出后,下次启动会继续;更换服务端地址或 appKey 后,会向新连接重新全量补报。

历史补报只发送 token 数值、模型和会话归属等统计字段,不发送对话正文。token_usage_diagnostics 会显示历史扫描进度、服务器确认数、重试错误和最近完成时间。对照本地与部门看板时,请选择相同时间范围并筛选 appKey 对应人员。

DSH 升级会保留旧格式日志作为备份;同一会话存在多个规范格式版本时,统计与补报都只读取最高版本,与 DSH 自身一致,避免事件重编号后重复计费。历史补报不会自动删除服务器上的旧数据;已由旧版本重复上报的记录需先对账、备份,再单独修复。

让 Agent 查询

可以在 DSH 会话里要求:

调用 token_usage,查看我今天的 token 用量,按模型分组。
调用 token_usage,查看最近 7 天的用量,按天显示趋势。
调用 token_usage_diagnostics,检查上报是否成功、是否有待发送数据。

工具注册需要宿主提供对应能力并启用 features.tools。查询工具只读本机日志,本身不产生上报。

功能说明

能力 使用方式
界面统计 用量条与标题栏入口(挂哪几个由 ui.position 决定,默认只挂输入框上方),共用详情面板
时间分析 预设周期、双月日历、自定义范围、趋势切换
明细分析 模型 / 服务商 / 项目 / 会话分组,展开与分页
费用(估算) 面板顶部一行「费用(估算)」+ 明细表每行的金额列;token_usage 工具也给出同样一段。金额是本机按 pricing.json 快照(没有就退回内置种子价)现算的估算,与部门看板可能不同 —— 所以那行口径说明(单价来源 / 未计价比例 / 「估算 ≠ 财务账单」)永远与金额一起出现
多套 DSH 并集 缺省统计本机全部 DSH 的会话日志(互为镜像的会话按 event_id 去重,只算一次)
多客户端来源 本机全部已注册来源(Codex / Claude Code / Trae / WorkBuddy)缺省就一起统计、也一起上报;装了哪个就有哪个。要收窄只能用各来源自己的环境开关(如 DSH_TOKEN_REPORT_CODEX=0)
本地增量查询 SQLite 增量索引;库不可用时自动回退日志扫描并提示
上报连接 面板内填服务端地址 + appKey,验证后立即生效(无需重启)
上报偏好 面板内选上报间隔、面板位置与会话日志根;只改偏好时不必重填 appKey,保存后即时生效
实时上报 异步批量发送、磁盘 outbox、失败保留、重启重放
历史补报 独立后台线程扫描全部历史,服务器确认后保存进度,失败持续重试
上报调试 配置页「上报调试」页签:状态与原因、计数、最近请求体原文与回执、补报进度、立即上报 / 不发送预览
Agent 与插件集成 token_usage、token_usage_diagnostics、ctx.tokenReport

token 数永远只展示真值;金额(估算)在面板与 token_usage 里也会出现, 但未计价的用量写「未计价」而不是 ¥0.00(「没配上价」与「没花钱」是两件事), 金额一律由宿主算好、格式化好再透传给界面 —— 浏览器半不做任何换算。 趋势图刻意没有金额曲线:多币种绝不跨币种相加,那条判定规则的唯一实现留在部门看板。 只采集用量相关字段(包含模型名、工作目录、轮次等),不采集对话内容。上报失败不会阻塞 DSH 的会话循环;服务端按事件 ID 去重。

采集了什么,不采集什么

内容
采集 计费级的四类 token 数(未缓存输入 / 输出 / 缓存读 / 缓存写)、模型名、供应商、工作目录(项目)、会话与轮次标识、事件时间、来源客户端
不采集 对话正文、提示词、模型回复、附件与文件内容 —— 内容开关恒为关,一个字节都不读
不署名就不采 没有身份文件、没有 appKey,或部署侧关掉上报(features.reporting: false)时,不注册上报后端、一个字节都不发,只在启动日志里提示一次「去哪里填」
为什么不做 unknown 兜底 那等于未授权的数据采集。宁可一条不报,也不替使用者做这个决定

上报走 Authorization: Bearer <appKey>,地址由使用者自己填(缺省指向本机自建的 http://127.0.0.1:8787/api/v1/token-usage)。插件不向任何其它地址发送数据。 面板的「上报调试」页签能看到每一次真实请求的请求体原文与回执 —— 采集范围不必只看承诺,可以自己核。

升级与常见问题

从旧版升级时,重新运行上方带 @latest 的安装命令即可安装最新稳定版。若曾源码直挂或手动 insert,先执行下方离线修复,再重启 DSH。

从 0.5.0(或更早)升到 0.6.0 时,数据目录换了位置,需要手动搬一次家 —— 见下方「0.6.0 数据目录位置变更」。 0.5.0 的下一个公开版本就是 0.6.0,中间没有需要单独安装的版本。

各版本都变了什么

版本 使用者能感知的变动
0.9.0 ★ 不再与官方 OTel 后端互斥:插件不再注册 sessionTelemetry 服务(改订阅宿主会话事件流),装了它不必再停用 session-telemetry-otel;cordis.patch.yml 里那两行可以删掉。包名与发布名统一为 dsh-plugin-token-report(旧仓内名 @ai-token-report/dsh-plugin 仍会被修复工具清理)。peer 去掉 @deepseek-ai/dsh-session-telemetry
0.8.0 ★ 统计与上报范围都改成「本机全部已注册来源」(Codex / Claude Code / Trae / WorkBuddy 缺省就一起算、也一起报);面板里可改「会话日志根」(保存即生效);README 补齐 DSH Desktop 的安装步骤。旧的 extraSources 配置项已废弃(写了会在启动日志里告警)
0.7.0 peerDependencies 从精确 0.1.7-rc.2 放宽成兼容窗口 >=0.1.7-rc.2 <0.3.0-0 —— 宿主小版本升级不必再等插件跟进
0.6.0 ★ 数据目录搬到 ~/.ai-token-report(升级要手动搬一次家,见下一节);面板里可改面板位置;保存即生效,不必重启;面板开始展示费用(估算)
0.4.0 随包提供离线修复工具 repair-profile.mjs(清理 duplicate loader entry id;开发期写作 0.3.1,npm 上没有这个版本)
0.3.0 面板默认位置改成输入框上方的用量条(ui.position: dock)—— 要保留 0.2.0 的外观就配 both

🚨 0.6.0 数据目录位置变更:升级必须搬一次家

这是升级到 0.6.0 唯一需要动手的地方。 数据目录(署名 / 连接配置 / 本地索引库 / outbox / 补报水位) 的缺省位置从 <DSH home>/token-report(通常是 ~/.dsh/token-report)改为 ~/.ai-token-report, 旧目录不会被自动迁移,也不会报错:

现象 原因
面板回到「尚未署名」、要求重新填 appKey 署名与连接配置还留在旧目录里
面板数字变了(历史少了一块) 新目录里没有索引库;日志仍在,重扫即可恢复
磁盘 outbox 里没发完的批留在了旧目录 待投递数据不会自己搬过来

先把该 profile 的 DSH 停掉,再搬(只做移动,不删除任何东西):

# Windows PowerShell —— 换过 DSH_HOME 的话,按实际路径替换 $old
$old = "$env:USERPROFILE\.dsh\token-report"
$new = "$env:USERPROFILE\.ai-token-report"
New-Item -ItemType Directory -Force $new | Out-Null
Get-ChildItem -Force $old | Move-Item -Destination $new -Force
# macOS / Linux
old=~/.dsh/token-report; new=~/.ai-token-report
mkdir -p "$new" && mv "$old"/* "$new"/

若新目录里已经有同名条目(例如升级后已经跑过一次 DSH、新的空 outbox/ 已建), Move-Item -Force 对已存在的目录仍会报错 —— 那种情况先把新目录里的空 outbox 删掉, 或者只搬 identity.json、plugin-connection.json、state.json、backfill 这几项 (usage.sqlite 可留可删,它是日志的派生物)。

搬完核对:新目录里应当能看到 identity.json 与 plugin-connection.json;重启 DSH 后面板不再要求重新署名。 想确认生效位置,打开「配置」→「上报调试」——诊断文本会同时打印会话日志根与数据目录。 CLI(ai-token-report)与本插件共用同一个数据目录,所以搬一次两边都恢复。

0.3.0 启动报 duplicate loader entry id: token-report

插件树里重复挂载了相同 ID,Loader 在插件代码执行前就会失败。仅升级 JS 文件不能清理旧 profile。离线修复工具从 0.4.0 起随包提供(开发期写作 0.3.1,但 npm 上并没有这个版本 —— 别去装它);先停止该 profile 的 DSH,再在 Windows PowerShell 运行:

node "$env:USERPROFILE/.dsh/profiles/web/node_modules/dsh-plugin-token-report/repair-profile.mjs" --profile web
node "$env:USERPROFILE/.dsh/profiles/web/node_modules/dsh-plugin-token-report/repair-profile.mjs" --profile web --apply

设置过 DSH_HOME 时,把上面的 USERPROFILE/.dsh 路径替换成实际 DSH_HOME。第一条只检查,需修复时退出码为 1;第二条先备份,再修改。工具去掉重复 bundle 和旧源码包依赖,把插件 insert 转成 ID 配置覆盖;保留其它插件、原配置与 !!js 表达式。YAML 注释在原文备份中保留。

终端会打印备份目录(<dataDir>/plugin-backups/repair-*,缺省 ~/.ai-token-report/plugin-backups/repair-*)。遇到配置冲突、其它插件占用 ID,或全局 $DSH_HOME/cordis.patch.yml 仍重复插入时拒绝写入,需人工合并。不要删除整个 profile、身份文件、数据库或 outbox。修复后重新运行 dsh web。

尚未升级时,也可单独复制仓库构建出的 repair-profile.mjs 到故障电脑,用同样参数运行,无需启动 DSH。

0.2.0 → 0.3.0 的行为变更(唯一一处):用量面板的默认位置改成 ui.position: dock —— 默认只出现输入框上方那条用量条, 会话标题栏右侧的胶囊不再默认出现。要保留 0.2.0 的外观(两处都有), 在插件 config 里加 ui: { position: both }。 位置配错(写了别的值)不会让面板消失:一律回退 dock 并在启动日志里告警。

现象 处理
启动报 service "sessionTelemetry" has been registered at <…> 只可能出自 0.8.x 及更早的版本(它要独占那个服务名,与官方 OTel 互斥)
面板不见了,且一条也不上报(启动日志只有 skipping profile bundle …) 宿主版本落在兼容窗口之外 —— 见上方「环境要求」。这一行不是报错,是整个 bundle 被跳过了
没有用量入口 确认安装在 web profile、bundle 数组包含发布包名,并已重启;features.ui 不能关闭
桌面端(DSH Desktop)装不上 / 界面里搜不到 桌面端的社区市场只收 awesome-dsh-plugin 精选列表内的来源,本插件不在其中 —— 按上方「在 DSH Desktop(桌面端)上安装」走命令行
401 / 未通过宿主鉴权 使用本次 DSH 启动时打印的完整地址重新打开
首次统计较慢 等待首次索引完成;如显示降级,检查 SQLite 权限与宿主 Node 版本
团队看板没有数据 先看配置页「上报调试」页签:它会直接说「未上报及原因」并列出最近请求与回执;再用 token_usage_diagnostics 看补报进度
改完配置没生效 0.6.0 起保存即生效(页面会回报状态)。若显示「需重启 DSH」,说明宿主没提供热生效入口(旧版本宿主),重启即可
升级后面板要求重新署名 / 数字少了一块 数据目录换了位置,旧目录要搬一次家 —— 见上方「0.6.0 数据目录位置变更」

源码、开发文档与构建方式见 GitHub 仓库 (0.9.0 起仓内包名与 npm 发布名是同一个:dsh-plugin-token-report —— 插件市场的 npm 映射就是按仓内 package.json 的 name 去找包的)。

单文件离线版(截图以 Base64 内嵌):README.offline.md。