npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-token-panorama

v1.0.4

Published

Token panorama for DSH: totals, cache hit rate, peak/off-peak cost, calendar heatmap, session tree, workspaces, CSV/JSON export, plus context clear/compact actions, prompt optimization, and auto answers for ask_user_question batches.

Readme

Token Panorama for DSH(用量概览 · 中文说明)

一个 DeepSeek Harness 功能插件,看清全部会话的 token 去向:一个面板汇总累计总量、日历热力图、趋势曲线、 模型分布、逐会话用量明细,以及 CSV / JSON 导出。另带三组工具:上下文清理 / 压缩按钮、提示词优化按钮, 以及在你不在场时代答 ask_user_question 的问答功能。

数据全部来自平台自带的会话持久化服务,不解析日志文件,也不依赖任何第三方库。

功能

  • 累计统计:总 token 消耗,输入 / 输出 / 缓存读取 / 缓存写入各多少,调用了多少次。
  • 缓存命中率:缓存读取占输入侧 token 的比例,命中和未命中的绝对量都列出来。
  • 成本折算:按 DeepSeek 分时段价格(高峰 / 空闲)估算花费,峰谷金额分开列。
  • 日历热力图:GitHub 风格的周列视图,也可以切成每月一个小日历。
  • 趋势曲线:按日 / 周 / 月 / 年聚合,悬停时间点看具体数值。
  • 模型分布:按用量排序展示各模型的 token 与调用次数。点某个模型后,下方统计(热力图、趋势、 成本、峰谷、会话列表)只算它一个,再点一次取消。
  • 工作区分布:按会话头记录的工作目录分组,一眼看出哪个项目最耗 token。
  • 会话用量明细:默认只列主会话,点箭头展开名下的子代理,卡片高度不会跟着子代理数膨胀。 表头可排序,归档会话带标记、能用复选框隐藏;时间范围变化后,每个会话只统计落在范围内的部分。
  • 分页:每页 40 组会话,量再大也不会一次渲染全部行。
  • 统一时间范围:顶部过滤器控制全局(全部 / 今天 / 近 24 小时 / 本周 / 近 7 天 / 本月 / 近 30 天), 下方每张卡片(热力图、趋势、成本、峰谷、模型、会话、工作区)都按同一段范围重算, 也可以自选 起始 / 结束 日期。
  • 小时粒度:范围缩到「今天」或「近 24 小时」,趋势图横轴自动切成小时,没活动的小时补零画出来, 折线不会把两段活动连成一段。
  • 数据导出:按天明细导出 CSV / JSON,也可以单独导出会话级 CSV(含工作区、父会话、成本列)。
  • 增量刷新:按会话的 revision 判断要不要重读,刷新时只解码真正变化的会话。
  • 节假日自动更新:任意年份运行时联网拉取并缓存,跨年不用等新版本。
  • 上下文操作:输入框下方 dock 里的「清空上下文」(橙)和「压缩上下文」(绿),也提供 /clear-context、/compact-context 与 /compact 命令。压缩可以在会话运行中用:先定好截断点 再让模型写摘要,压缩期间新产生的对话原样保留、接在摘要之后,检查点复用平台自带的 「上下文已压缩」标记展示条数与 token。/compact 的一次压缩会把命令行与标记折叠成一张合并卡片, 跟平台自带压缩一致。清空替换整个表层,因此要求会话空闲。
  • 提示词优化:常驻输入框工具栏的「优化提示词」按钮,把草稿交给可配置的优化模型改写,结果粘贴 回输入框,附件不动。可以让请求附带当前会话的上下文摘录,改写贴合正在进行的任务,指代「这个函数」 的提示词能改写成指名道姓的版本。指令、模型路由和上下文开关在「提示词优化」设置页配置。 模型直接返回提示词正文,不带代码块也不带块外建议,因此填入输入框的内容就是最终要发送的内容; 若你自己改写了指令并要求围栏,插件只会剥掉包住整段回答的那一层,块外文字会一并留下。
  • 问答功能:代替你回答 ask_user_question 的提问,让你不在时运行不会卡住。默认关闭;权限审批、 凭据密钥、不可逆操作、付费与发布类提问永不代答。指令、模型路由与等待上限在「问答功能」设置页配置。
  • 中英双语:跟随平台语言设置。

环境要求

  • DSH >= 0.2.1-rc.3(在 dsh.engines.dsh 中声明)。
  • 使用 Web UI 的 profile;插件注册到 sidebar.panellist 与 main 两个插槽。

安装

在「插件」页面安装,或通过 plugin manager 指向本包目录(含 package.json 的文件夹):

plugin_manager install_bundle target="<本目录的绝对路径>"

安装后侧边栏出现 Token 统计 入口,点击即可打开主面板。

卸载:在「插件」页面卸载 dsh-token-panorama 即可。

npm 包与下载量口径

本插件同时发布到公共 npm registry,包名 dsh-token-panorama。目录站(awesome-dsh-plugin)与 应用内市场可据此按包名安装并显示下载量;未发布到 npm 时才回退到 GitHub Release 的 tgz 附件。

  • 发布新版本:npm publish --access public。npm 要求开启两步验证,或使用勾选了 Bypass 2FA 的 granular access token。
  • 目录站会读取仓库 package.json 的 name,在 registry 上确认同名包,并要求该 npm 包的 repository 字段回指本 GitHub 仓库。这层映射自动从 registry 抓取,条目里无需、也不允许 手写 npm: 字段。
  • 市场显示的「下载量」是 npm 近 30 天(UTC 滚动窗口)下载数,来自 api.npmjs.org/downloads/point,由目录站每天夜间探测刷新。它不是「查看量 / 浏览量」: 目录与市场都不提供任何访问量字段。GitHub Release 附件的下载次数是另一套独立计数, 不会进入这个字段。
  • 每次修改都会迭代 package.json 的 version,并发布新版本,使 registry 的 latest 与目录里的 version 保持一致。

使用

  1. 在侧边栏点击 Token 统计。
  2. 用两个日期输入框或快捷按钮调整时间范围。
  3. 热力图可在 周 / 月 之间切换;趋势图可在 日 / 周 / 月 / 年 之间切换。
  4. 鼠标悬停趋势图任一数据点,查看该时间点的精确数值。
  5. 会话用量 表格默认只列主会话;点行首 ▶ 展开该会话,展开后能看到它名下所有子代理会话。 点表头(会话 / 消耗 / 调用 / 创建时间)切换排序,取消勾选 显示已归档 可只看仍在使用的会话 (该勾选状态会记住,下次打开沿用上次的选择),导出会话 CSV 落盘当前表格。
  6. 会话较多时用卡片底部的 上一页 / 下一页 翻页,每页 40 组。
  7. 点击 刷新 重新扫描,或点击 导出 保存按天明细的 CSV / JSON。
  8. 点击 常规设置 打开设置窗口,修改时区、货币、峰谷时段、节假日与价目表,保存后立即重新计价。

面板打开时会自动刷新。首次扫描后只解码发生变化的会话,历史数据量很大时也能很快加载。

计费配置

插件的全部计费参数都在 profile 的配置里,在面板右上角点「常规设置」就能打开设置窗口在线修改, 保存后立即重新计价,不用重启 DSH。

设置窗口按结构编辑配置,不是按字段名逐条渲染:模型价格是一张表、峰谷是可复用的方案、 节假日是勾选清单,这几样通用的键值编辑器都表达不了。窗口分七个标签页:

| 标签页 | 内容 | | --- | --- | | 模型与价格 | 每个模型一行,未命中输入 / 命中缓存输入 / 缓存写入 / 输出四个独立价格框,峰谷开关与方案下拉,最后一列固定是删除 | | 峰谷方案 | 可复用的时段方案:名称、自动模式、若干「起止」窗口、空闲价比例 | | 节假日 | 系统预封装的日历,勾选即生效 | | 上下文 | 压缩指令、压缩模型路由、上下文占用、自动压缩与分段压缩开关 | | 提示词优化 | 优化指令、模型路由,以及请求是否附带当前会话的上下文摘录 | | 问答功能 | 代答指令、代答模型路由、等待上限,以及总开关 | | 通用 | 计费时区与货币单位 |

窗口底部还有导出配置和导入配置。导出的 JSON 只含计费设置,不含任何会话数据,可以直接分享给别人; 导入只填表,确认无误后点保存才写进 profile。

模型列表默认只列日志里实际出现过的模型(按用量降序),打开窗口就能给正在花钱的模型定价, 不用先知道模型叫什么。还没定价的模型显示「未配置」和「添加价格」按钮,点一下就建行。

每个模型独立定价。价目表里没有的模型走 defaultPrice,面板会在成本卡下面注明 「某模型无定价,按默认价计算」,不会闷头按 0 算。

价格拆成四项填,因为供应商对同一段输入的处理并不等价:

| 列 | 含义 | 不单独计费时 | | --- | --- | --- | | 未命中输入 | 首次送入、没命中前缀缓存的部分 | 填官方标价 | | 命中缓存输入 | 命中前缀缓存、按折扣价读取的部分 | 填 0 表示不收取 | | 缓存写入 | 把输入写入缓存的部分 | 填 0 表示不收取 | | 输出 | 模型生成的内容 | 填官方标价 |

缓存这两项必须分开:写入是存进缓存,读取是从缓存取,单价通常差十倍以上。合成一列的话,正在预热 缓存的会话会算得偏便宜,稳定复用缓存的反而偏贵。缓存写入也不算进命中率的分母,它是写入,不是读取。

峰谷是独立配置,一个方案可以给多个模型复用:模型行的开关打开后选方案名就行。开关关着的模型 全天按标价(高峰价)计费,归入「高峰时段」,它实际付的就是这个价。方案改名时引用它的模型跟着 改;删掉方案会留下悬空引用,这时该模型仍按高峰价计费,行内提示「方案已删除,请重新选择」, 可以重选。

空闲价按比例算。方案里的「空闲价比例」是标价的百分比,默认 0.5 就是半价,所以价格表只维护一份, 改比例会把高峰和空闲两个时段一起重新计价。

自动模式

「自动模式」决定一段时段的生效日期,参考闹钟响铃规则:

| 模式 | 含义 | | --- | --- | | 每天 | 不限星期与节假日 | | 法定工作日(智能跳过节假日) | 周一至周五,且不在已勾选的节假日里 | | 法定节假日(智能跳过工作日) | 只在已勾选的节假日生效 | | 周一至周五 | 只看星期,不管节假日 | | 自定义 | 七个星期勾选框自由组合 |

时段窗口

每个方案可以有多条「起始 – 结束」窗口,24 小时制。多条窗口不是摆设:DeepSeek 的高峰是两个 不连续的区间(09:00-12:00 与 14:00-18:00),午休走空闲价。写成一条 09:00-18:00 的话,午休 那段会被算成高峰,高峰 token 从约 4.0 亿虚增到约 4.5 亿。

end 小于 start 时按跨零点处理,22:00-02:00 不需要拆成两条。

节假日

节假日日期在运行时联网拉取,缓存在 profile 下,跨年不用等新版本。 只补没有数据的年份:已发布的年份不再变,还没发布的年份(比如下一年)每天重试一次。 三个免密数据源按顺序尝试,全挂了就保留已有缓存。

插件内置了 2026 年的日期当种子,第一次运行、还没发出网络请求之前计价就是对的。 设置里显示已加载的年数,也有一个强制重新拉取的刷新按钮。默认勾选法定节假日那一组。

内置清单只是种子数据,不是权威来源:某一年一旦拉取成功,以网络副本为准。

上下文操作

输入框下方的 dock 里有两个按钮,和上下文用量环在同一行:左边橙色清空上下文,右边绿色压缩上下文。 它们同时也是斜杠命令 /clear-context 与 /compact-context,不用鼠标也能触发。

两者的差别在替换范围。清空取整个表层,因此要求会话空闲:改写期间追加的步骤会跟着它依赖的 历史一起被丢掉。压缩只取调用摘要之前就选定的一段,终点落在最后一个不切断 tool-call/result 配对的位置,所以会话运行中也能用,压缩期间写入的内容会原样重放在检查点之后。两种情况下 会话和日志都原样保留,事件还在磁盘上,只是表层不再显示被替换的部分,上下文窗口也就腾出来了。

  • 清空:写入一行占位说明。它不是摘要,下一条消息之前的内容都不再保留。
  • 压缩:直接调用模型写出摘要,再用它替换那段历史。默认沿用会话的 provider 与模型, 可在「上下文」标签页覆盖。这段历史按原样的消息重放给模型(同样的系统提示词、同样的 工具定义,指令放在最后),provider 的前缀缓存能覆盖整段历史,这次调用按缓存命中计价, 不用把历史重发一遍。全程不派子代理,没有子会话也没有属于自己的工具,不会顺手改动任何东西。

两者完成后,对话里会出现一条命令卡片,按钮下方不再给一份重复的提示。两个按钮的反馈文本和 统计口径不一样:清空报告替换前后的条数与 token,压缩还会多报写入摘要的字符数。它们走平台 原生的 command/run / command/done 事件,卡片可见、可展开,但不进会话表层,不会污染模型上下文。

压缩用的提示词在设置窗口的「上下文」标签页里可编辑,同一页还能指定压缩模型的 provider 与模型,留空即沿用会话的。默认提示词是一份中文的「工作状态存档」指令,要求写清目标、 决策及理由、被否决的方案、原样路径与签名、报错原文、精确数值和未完成事项,按八个章节组织, 并明确禁止提及压缩本身。

内置的三段默认提示词(压缩、优化、问答)共用同一套结构:# 角色定义、## 核心能力、 ## 核心红线、## 工作流程、## 交付格式。它们分属「上下文」「提示词优化」「问答功能」三个标签页, 但共用同一套骨架,改其中一段时其余两段照着对齐即可。默认值存放在 lib/contextops.js 的 DEFAULT_COMPACT_PROMPT / DEFAULT_OPTIMIZER_PROMPT 与 lib/ask.js 的 DEFAULT_ASK_PROMPT,test/prompts.test.mjs 会把这三条性质(同一套五标题结构、 自身只用半角标点、各自的专属条款)钉死,避免以后改写时漂移。

三者都遵守两条与调用点直接相关的约定:

  • 优化指令不要求代码块。改写结果会被原样填入输入框,而接收端只会剥掉包住整段回答的首尾围栏; 若提示词要求「代码块 + 块外建议」,那些建议文字会一并进入待发送的草稿。
  • 压缩指令里的标点规则只约束模型自己写的叙述。被逐字复现的原文(引号内内容、用户原话、 报错信息、代码、配置值)保持其原始标点,不得替换——这与「逐字保真」是同一件事。 分段压缩时,输入如带「第 N/M 段」或「合并」说明,一律以分段说明为准。

同一页还有三块与「窗口还剩多少」有关的内容:

  • 上下文占用:显示当前会话按「系统提示词 + 工具定义 + 对话消息」三项算出的真实总占用, 以及所选模型的输入上下文上限、占用比例与三项分项。
  • 自动压缩开关与触发阈值(默认 75%):决定本插件在每一步开始前自动压缩的时机。 同一会话两次压缩之间至少间隔一分钟,避免刚压完仍超阈值时每一步都再付一次摘要。 触发挂在与平台引擎同一个 agent/pre-step 事件上,但由本插件执行,不写任何平台配置。 某个 profile 完全可能禁用平台引擎(dsh-compaction-basic 可以被整行关掉,preset 内嵌 的行本来也改不到),那样开关存进去了也没人生效。判定用的是上面那三项 真实总和,不是平台面板顶部按 provider usage 锚定的那个数字,后者在长会话里可以显示 112K,而同一份请求实际带着 2.3M。
  • 超出上限时分段压缩:决定历史大于摘要模型窗口时怎么办。关闭时丢弃最早的部分,只把 最近能装下的记录交给模型,并用显式标记写明丢了多少条。开启时按上限切成多段,并行各写 一份摘要,再由最后一次请求整合成一份替换整段历史,不丢历史,也不会有哪次请求越过窗口。 长对话压缩时模型无响应或返回空,原因就在这里。
  • 压缩前会先量一次体积。历史若已超过摘要模型窗口的 2/3 且没开分段,就退回到「头尾摘录」: 开头保留目标与约束,结尾保留正在进行的事,中间以显式标记省略。被压缩的那一段伸进正在 运行的轮次也没关系,交给模型的就是这些消息本身,摘要正好覆盖检查点要替换的内容。
  • 摘要被输出上限截断时是重试,不是接受。截断的检查点会用一份说到一半就停的摘要替换真实历史,所以 第一次尝试沿用会话当前发出的输出预算,之后每次重试把预算翻倍,上限是 64000 tokens(平台自己为压缩 预留的输出量),历史、提示词与模型都不动。只有 max-tokens 会重试;适配器报错在第一次就抛出,不 为同一个错误付两次钱。所有档位都被截断时放弃这次压缩并点名截断原因,不会有半份摘要替换历史。
  • 压缩锁在调用摘要之前就打开,不是之后。第二次请求会直接答「已有压缩在进行中」, 不会为同一份摘要付两次钱,平台自己的引擎也会让路。

对已经清空过的会话再清一次是空操作,按成功返回:拿一个占位换另一个同样的占位不算错误。

问答功能

模型需要人做决定时会调用 ask_user_question 并停下等待。本插件可以代你回答这批问题,让运行不会因为 你不在而卡住。它默认关闭:开关关着时插件对每一批问题都原样放行,提问照旧弹到你面前。

机制用的是平台自己的:提问经由 user-questions/request 上的 cordis waterfall 发出,任何监听者都可以 作答,谁先返回一批答案就由谁生效。插件以 prepend 注册这一个监听者,因此会排在人机卡片之前被询问 (排在它后面的话卡片先弹出来,代答永远没有机会)。作答是一次直接的 llm.stream 调用,只带问题与指令, 不传工具:模型除了文本什么也做不了。

除了一次确定的回答,其他所有结果都会把问题交回链上:开关关着、问题落在禁区、没有可路由的模型、答案解析 不出来、选项不是问题里给过的、调用失败、等待超时。问题随后照常到你手上,所以这里出问题最坏是多看一次 卡片,不会让问题消失。

无论如何都不会代答的:权限与审批、计划评审(任何带 intent 的批次)、凭据与密钥、API Key 与验证码、 删除与一切不可逆操作、付费与购买、发布与部署。检查是对问题正文和每个选项做关键词匹配,刻意宁滥勿缺: 误判的代价是多看一张卡片,漏判的代价是模型替你做了一个绝不该由它做的决定。

设置窗口的问答功能标签页里有开关、代答模型读到的指令、它的 provider 与模型(留空沿用会话的),以及 等待上限。上限按秒计,与 ask_user_question 同一口径:-1 表示不限时,其余必须是 1 到 2147483 的整数。 这个范围来自平台本身,工具会拒绝的值这里也存不进去。

答案在你看得到的地方有标注:模型给出的答案末尾带着是哪个模型答的(由 <provider>/<model> 代答),写在 答案正文里,因为问题服务只搬运 {id, selected, custom} 三项,其余字段会被丢掉。这次调用的花费记在工具账 本的 ask-answer 名下,并在用量概览里以「代答 N」显示,与压缩、优化并列。

答案也不会写进会话记录:问答卡片显示答了什么,下一轮的内容是模型自己的产物,因此代答做过的决定不会以 「你说过」的形式混进之后的摘要。

校验

所有值在保存前由平台 schema 与插件自身各校验一次:非法时区、非法 HH:MM、负数价格、 不在 0–1 的开区间内的空闲价比例、未知的自动模式都会被拒绝,并指出是哪一项不合法。

升级

1.0 的配置结构(peakWindows 单表、hitPeak/missPeak/outPeak 六字段价格、日期数组 形式的节假日)会在读取时自动迁移:高峰价成为新的标价,启用了空闲价的模型自动挂到 standard 方案上,日期数组折回对应的日历键。迁移是只读的,磁盘上的旧配置不被改写, 直到你在窗口里点保存。

窗口内所有文案都在 client.js 的 ZH / EN 字典里,两种语言各 285 个键,键集完全一致。

保存走平台的 configEditor 服务:先做 schema 校验,再把整份配置写进 profile 的 cordis.patch.yml 并触发热重载。插件在保存前也会自己校验一遍,把错误定位到具体字段, 而不是抛一个 Loader 级的失败。若当前 profile 没有该服务或对应条目,窗口会退化为只读并说明原因。

说明:DeepSeek 的高峰规则字面是「周一至周五」,所以调休补班(周末上班)的日子仍按空闲价计算, 面板不会把补班日算成高峰。价格单位是「每百万 tokens」,与官方公告一致。

数据统计口径

  • 数据源:Host 的 sessionPersistence 服务列出全部会话及其不透明版本号 revision。版本号未变的会话直接 跳过;其余会话先只走一遍日志的 Zstandard 帧表(不解压),只解码上次扫描之后新增的帧——语料没变时 一个字节都不解压,需要重读时也只解码日志尾部而不是整段历史。
  • 计数:每条带 data.usage 的 assistant/message 事件计为一次调用。总量优先取 usage.totalTokens, 缺失时回退为 inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens。
  • 范围:当前 profile 下的全部会话,包含子代理会话(header.origin === 'subagent')与已归档会话; 页脚分别统计主会话、子代理和归档数量。
  • 会话标题:从每个会话自己的 session/title 事件中取最后一条,不依赖可变的元数据。
  • 归档标记:读 workspaceRegistry.archivedSessionIds;该服务缺失时按「无归档」处理,不影响其他统计。
  • 工作区:取会话头事件(type: "session")里的 cwd;没有 cwd 的会话归到「(无工作区)」。
  • 父子关系:取会话头里的 parentSession。父会话不在本次统计内时,该子代理按顶层条目展示。
  • 时间桶:按事件时间戳所处的本地日历日归类;计费额外按小时划分,小时桶用配置时区换算。
  • 缓存:折叠结果写入 ~/.dsh/storages/dsh-token-panorama/usage-cache.json(CACHE_VERSION = 5), 通过临时文件 + 重命名原子写入。每条记录同时保存已折叠到的字节偏移与最大序号,下一轮可直接续读。
  • 投影种子:Host 挂载 sessionProjections 时,本插件注册自己的折叠单元(tokenPanoramaUsage), 由 Host 在事件提交时持续维护。投影行已经追平日志末尾的会话完全不读日志,直接采用该行。只有在状态版本、 时区、水位线和日志身份全部吻合时才采信;任何一项不吻合就退回读日志,所以种子只会省事,不会改变结果。 没有该服务时行为与原先一致。读不出来的日志按 revision 记住十分钟,不再每轮重复解码。
  • 准确性:总量严格等于底层 usage 记录之和,面板不做任何估算;会话行跟随所选时间范围, 各会话在该范围内的用量之和与热力图对应日期完全一致;成本按小时计价后汇入日、模型与会话三个维度, 三者的求和恒等于总量。

HTTP 接口

Host 在 /token-stats/api 注册前缀路由。请求必须通过平台的 Host / Origin 校验 (ctx.connection.requestRejection),且为 POST + JSON 体。

| 方法 | 请求体 | 说明 | | ------------ | ------------------- | ----------------------------------------------- | | summary | {} | 返回当前快照,仅重新扫描发生变化的会话。 | | summary | {"refresh": true} | 不信任本插件的折叠结果并重建,仍会采用能通过校验的 Host 投影行。 | | refresh | {} | 等价于强制刷新。 | | config | {} | 返回当前配置、字段描述与可编辑状态;models 附 Host 实时模型目录(含各自上下文上限)。 | | saveConfig | {"value": {...}} | 校验并保存配置,返回保存后的配置与字段描述。自动压缩由本插件执行,不写任何平台配置,因此没有「是否同步成功」这一项。 | | holidays | {} | 强制重新拉取节假日数据,返回是否变化与按年目录。| | clearContext | {"sessionId": "..."} | 把该会话的整个表层换成一条占位说明。 | | compactContext | {"sessionId": "..."} | 直接调用模型压缩该会话,并用摘要替换表层。 | | contextPressure | {"sessionId": "..."} | 量一次该会话:总 token、系统提示词/工具定义/对话消息三项分项、路由模型的上下文上限与占用比例。 |

响应结构:

{
  "ok": true,
  "value": {
    "generatedAt": 1793511000000,
    "lastScanAt": 1793510999000,
    "scan": null,
    "sessions": { "total": 0, "subagent": 0, "main": 0, "archived": 0 },
    "totals": {
      "input": 0,
      "output": 0,
      "cacheRead": 0,
      "cacheWrite": 0,
      "total": 0,
      "calls": 0
    },
    "days": [["2026-11-01", 0, 0, 0, 0, 0, 0, 0]],
    "models": [["deepseek-v4.1-flash", 0, 0, 0]],
    "cache": { "hits": 0, "misses": 0, "hitRate": 0 },
    "billing": {
      "currency": "CNY",
      "timeZone": "Asia/Shanghai",
      "cost": 0,
      "peakCost": 0,
      "offPeakCost": 0,
      "peakTokens": 0,
      "offPeakTokens": 0,
      "peakCalls": 0,
      "offPeakCalls": 0,
      "hitRate": 0,
      "hits": 0,
      "misses": 0,
      "priced": ["deepseek-v4.1-flash"],
      "unpriced": []
    },
    "sessionRows": [],
    "firstDay": "2026-10-30",
    "lastDay": "2026-11-01"
  }
}

days 每行是 [日期, 输入, 输出, 缓存读取, 缓存写入, 合计, 调用次数, 成本]; models 每行是 [模型名, 输入, 输出, 缓存读取, 缓存写入, 合计, 调用次数, 成本]; sessionRows 每行是 [会话 id, 标题, 创建时间, 是否子代理(0/1), 是否已归档(0/1), 合计, 调用次数, 父会话 id, 按天明细, 成本, 工作区, 按小时明细, 用过的模型名],其中按天明细为 [日期, 输入, 输出, 缓存读取, 缓存写入, 合计, 调用次数, 成本],按小时明细为 [小时, 模型名, 输入, 输出, 缓存读取, 缓存写入, 合计, 调用次数, 成本, 是否高峰(0/1)]。 归档状态取自 workspaceRegistry.archivedSessionIds,归档会话的日志保留在磁盘上, 因此照常出现在 sessionPersistence.list() 中。

按小时明细是会话级的最小事实单元,整张表的每个数字都能从它推出,前端按范围、按模型筛选会话时 不必回 Host 再问一次。高峰标志随行下发:只有 Host 知道峰谷时段与节假日日历,前端自行推算就得 复制同一套规则,两套规则迟早会漂移。

三个额外的按模型字段供前端做「只看某个模型」的联动,避免二次请求:

  • modelDays:[模型名, [按天明细…]],用于按时间范围重算该模型的每日曲线与热力图。
  • modelHours:[模型名, [按小时明细…]],范围缩到一天以内时用它画小时曲线。
  • modelBilling:[模型名, {cost, peakCost, offPeakCost, peakTokens, offPeakTokens, peakCalls, offPeakCalls, hits, misses}],用于重算该模型的成本、峰谷与命中率。

各类行统一为 14 列(带 key 的 days / hours / models 行为 15 列): [输入, 输出, 缓存读取, 缓存写入, 合计, 调用次数, 成本, 高峰输入, 高峰输出, 高峰读取, 高峰写入, 高峰合计, 高峰调用次数, 高峰成本]。高峰块与全量块同宽同序,所以任何一张卡只要求出 当前范围的行就能同时得到成本与峰谷占比,两者不会描述不同的时间切片。

三者的求和都与全局 totals、billing 完全一致。

包结构

package.json        manifest:exports、dsh.bundle.patch、dsh.client、engines
cordis.patch.yml    把本插件插入 profile patch
index.js            Host 半入口:Config 校验、HTTP 路由、插件生命周期
lib/time.js         时区换算、小时分桶、数值归一
lib/scan.js         把会话事件折叠成「小时 × 模型」档位
lib/schema.js       Config schema、默认价目表、字段描述
lib/billing.js      峰谷判定、计价、旧配置迁移
lib/holidays.js     节假日联网拉取、按年缓存、内置种子
lib/contextops.js   清空 / 压缩上下文的表面替换事务、真实三项测量、分段与整合、压缩与优化默认指令
lib/ask.js          问答代答:禁区筛查、答案校验、调用代答模型、默认代答指令
lib/store.js        增量缓存、帧级扫描与快照(逐日 / 逐模型聚合)
lib/frames.js       遍历日志的 Zstandard 帧表,只解码新增部分
lib/projection.js   交给 Host 持续维护的 tokenPanoramaUsage 投影单元
lib/http.js         请求体读取与 JSON 响应
client.js           Client 半:面板、热力图、趋势图、折叠会话树、工作区、导出
locale/en.json      插件元数据(英文)
locale/zh.json      插件元数据(中文)
icon.svg            插件图标(亦可通过 "./icon" 导出)
icon-prompt-optimize.svg  「优化提示词」按钮图标(同款图形内联在 client.js)

界面文案位于 client.js 的 ZH / EN 字典,通过 ctx.locale.register 注册;locale/*.json 只承载「插件」页面显示的标题与描述。

schemastery 由运行时从 profile 目录解析(见 schemaLibrary()),不写进 package.json 的 dependencies:本插件以 link: 方式安装,包自身的依赖不会被安装,声明了反而会导致加载失败。

说明与限制

  • 热力图、趋势与计费按配置的 timeZone 归类(默认 Asia/Shanghai,与 DeepSeek 的计费口径一致)。
  • 历史很长时热力图按周生成列,超出宽度横向滚动,而不是压缩到看不清。
  • 用量严格按记录的模型归类;早于用量记录功能的会话不贡献数据。
  • 价目表里没有的模型按 defaultPrice 计价,并在「预估成本」卡片上点名提示,不会静默套价。
  • 调休补班日(周末上班)按规则字面仍计空闲价;如需按补班计高峰,把峰谷方案改成「自定义」并勾上对应星期即可。
  • 本插件只读取会话持久化与归档列表,注册一条 HTTP 前缀路由,并提供一个 Config schema。
  • 上下文操作会改写会话表层(compaction/* 与一次表面替换),因此需要 commands、tokenMeter、 agents、llm 四个平台服务;平台缺其中任何一个时,这两个按钮与命令在该 profile 里不可用, 统计功能不受影响。日志里被替换的历史事件不会被删除。
  • 压缩必须先跑完摘要才能改写,因此一次压缩的耗时取决于会话长度与所选模型; 期间不会占住会话,可以继续对话,改写会在会话空闲时进行。