dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 插件:常驻 API 用量监控 —— DeepSeek/SiliconFlow/OpenCode Go/火山引擎 余额与配额、会话树 token 与花费(侧边栏入口 + 浮动窗)
本插件的工作区布局(规范见 plugins/README.md)
code/运行代码 |tests/测试代码 |docs/开发文档 |reference/参考资料package.json/cordis.patch.yml/README.md/LICENSE是包契约文件,必须留在本目录根- 状态:休眠 | 运行实体:
~/.dsh/profiles/desktop/plugins/api-monitor/- 本目录是备份 + 开发文档存放处,不在这里开发:要改代码请改运行实体,验证通过后再回写到这里
一个常驻的「我还有多少钱 / 还剩多少额度」面板:侧边栏底部一个「⛽ API 用量」竖排入口, 点开是一扇 Cordis 风格的浮动窗,里面同时显示 DeepSeek 余额、GLM Coding Plan 配额、 OpenCode Go 用量、Command Code(command goat)三周期额度、火山 Coding / Agent Plan 配额, 以及当前会话树的 token 与花费。
宿主半(
lib/index.js)活在 dsh web 进程里,负责轮询各家接口 + 聚合会话用量, 并通过同源 HTTP 路由/api-monitor/*把数据交给浏览器半(lib/client.js)。
SessionListState.current,因此「当前会话 id」不再能从列表状态里直接读;客户端已改为
由主视图保留标记推导 —— byId[id].retainedBy.mainView > 0,与上游 dsh-client-ui-workspace 的
mainSessionId() 同款表达式;同时保留 s.current 作为回退,故 0.1.5-rc.1 与 0.1.6-alpha.2 双向兼容。config:」模型(export const Config + apply(ctx, config) +
settings.configure({ auto: true }, ctx.fiber) 自动设置页 + configEditor.edit 落盘到 profile patch)。
另修一处观感回归:浮窗 .am-panel 原用 --dsw-specific-menu,该 token 在 0.1.7 由不透明改为半透明
(浅 #f8f9fa94 / 深 #30313680,官方菜单另配 backdrop-filter 做毛玻璃),本插件没配模糊
→ 面板透出背后内容;已改用不透明的 --dsw-alias-bg-layer-3。hostGet 会把
null 参数丢掉,请求退化成无 root,宿主随即走全零分支(静默,无报错)。GetCodingPlanUsage)、
火山 Agent Plan(GetAFPUsage)。subagents.listDescendants() 的子代理会话一起折叠;
总量取 token-meter 的 tokenUsage 投影口径,按来源(provider/model)分桶,仅 DeepSeek 计价。assistant/message 事件自带的 time 判定高峰/空闲
(北京时间周一至周五 9:00-12:00、14:00-18:00 为高峰),高峰/空闲分别给出用量与金额。(5h cap, 周 cap) 反查套餐档位(Go / Team Pro / GOAT / Pro / Max 10× / Max 20×)。fetch / crypto.subtle)与 @deepseek-ai/schemastery;
火山签名用 crypto.subtle 手写 SigV4。cordis.patch.yml 是 bundle patch 层,内容就是一行挂载:
- insert:
- id: api-monitor
name: api-monitor
apply() 内 ctx.inject([...]) 要求
settings / credentials / subagents / sessions / sessionProjections / webServer
六者齐备,否则宿主半不激活、路由也不注册。package.json 的 dsh.bundle.patch 与 dsh.client
(platform: "web"),浏览器半从 exports["./client"] 载入。node_modules 并追加上面的 insert 行后,需要重启实例;
浏览器半与宿主半一样随实例加载(本仓库未附带安装脚本)。pollIntervalSeconds 后需再次重启:轮询定时器在 apply() 时按当时的配置值建立一次。宿主 settings.register('api-monitor', SCHEMA) 注册的 schema:
| 字段 | 类型 | 默认值 | 含义 |
|---|---|---|---|
volcesAccessKeyId | string | '' | 火山引擎 AccessKey ID(Coding 与 Agent Plan 共用) |
volcesSecretAccessKey | string(secret) | '' | 火山引擎 SecretKey |
volcesTier | string | 'auto' | 套餐档位;仅保存与回显,代码中未见用于任何请求 |
pollIntervalSeconds | number | 60 | 轮询间隔秒;apply 时读一次,实际下限 20 秒 |
warnPercent | number | 70 | 预警阈值(已用 %,剩余 ≤ 100−该值 变黄) |
dangerPercent | number | 90 | 危险阈值(已用 %,剩余 ≤ 100−该值 变红) |
balanceWarn | number | 10 | 余额低于该值(CNY)标红 |
priceTable | dict(any) | {} | 单价覆盖表;支持平铺 {in,cr,cw,out}(旧键 pi/pcr/pcw/po)或 {peak,offPeak} 两种形态 |
showCacheHitRate | boolean | true | 面板是否显示「缓存命中率」行 |
showResetTime | boolean | false | 在配置里下发;客户端代码未读取该字段 |
commandMonthlyCap | number | 0 | Command Code 月度额度上限(美元)。0 = 自动按 (5h cap, 周 cap) 反查档位;认不出档位且也为 0 时退化为 summary.totalCost 兜底 |
entryVisibility | object | 七项全 true | 各区块是否显示在侧边栏入口:deepseek / glm / opencodeGo / command / qwen / volcesCoding / volcesAgent |
浮动窗内可直接改的只有:火山 AK/SK(「key配置」)、套餐档位下拉、每个区块的「显示在入口」勾选。
priceTable / pollIntervalSeconds / commandMonthlyCap / 三个阈值 / showCacheHitRate 没有面板 UI,需直接改设置值。
宿主半
轮询并缓存 6 个数据源:state.deepseek / glm / opencode / command / volcesCoding / volcesAgent。
凭证经 credentials.resolve() 读取:DEEPSEEK_API_KEY、BIGMODEL_API_KEY 或 ZAI_API_KEY、
VISION_API_KEY、COMMANDCODE_API_KEY(兼容旧名 COMMAND_API_KEY)、VOLCES_API_KEY(仅用于标记已配置)。
command 走 GET https://api.commandcode.ai/alpha/billing/credits(Bearer),
只在档位/配置都给不出月度上限时才追加一次 /alpha/usage/summary。
会话用量:subagents.listDescendants(rootId) 收集 kind === 'child' 的子会话,
总量取 sessionProjections.snapshot(s).values.tokenUsage,
来源桶按 assistant/message 的 source.provider / source.model 归并,
并用 llm/retry-started 做替换冲销(与 token-meter 投影同口径)。快照有 8 秒缓存。
同源 HTTP 路由(webServer.register):
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api-monitor/snapshot?root=<会话ID> | 供应商状态 + 会话用量 + 生效配置;未做同源校验 |
| GET | /api-monitor/config | 生效配置摘要(含 volcesKeyConfigured) |
| POST | /api-monitor/refresh | 强制刷新官方价格 + 立刻轮询全部;校验同源 |
| POST | /api-monitor/set-volces-keys | 写入 AK/SK 并立即重查火山;校验同源 |
| POST | /api-monitor/set-tier | 写入 volcesTier;校验同源 |
| POST | /api-monitor/set-visibility | 写入 entryVisibility,只接受 7 个已知键;校验同源 |
未注册任何 model 工具、命令或事件监听;对外只有上面的 HTTP 路由与设置命名空间。
浏览器半
sidebar.footer.action 注册一个 slot:id: "api-monitor"、order: -20、label: "API 用量"。
窄侧边栏时退化为一个圆形图标按钮(wide === false 分支)。/api-monitor/snapshot(带当前会话 id),并在面板里做刷新/改配置后的重载。style[data-plugin-css="api-monitor/styles.css"]),面板宽度固定 420px、
最大高度 60vh;再点入口或点遮罩、按 Esc 关闭。api-monitor/
├── README.md # 本文件
├── package.json # name/version 0.2.6;dsh.bundle.patch 指向 cordis.patch.yml;dsh.client(web)
├── cordis.patch.yml # bundle patch 层:一行 insert 挂载 id/name = api-monitor
└── lib/
├── index.js # 宿主半:settings 命名空间 + 6 路轮询 + 会话树聚合 + /api-monitor/* 路由
└── client.js # 浏览器半(预构建产物,window.__ModuleLoader__.load 工厂):侧边栏入口 + 浮动窗
test/
├── smoke-client-current-session.mjs # 「当前会话 id」推导回归(真实 bundle + 假 React/DOM)
├── smoke-command-credits.mjs # Command Code 三周期折算 + 档位反查回归(可选打真实接口)
└── _schemastery-stub.mjs # 裸 node 跑宿主半时替换 @deepseek-ai/schemastery
package.json 的 dsh.client.inject 声明了
@deepseek-ai/dsh-client-locale、@deepseek-ai/dsh-client-runtime、
@deepseek-ai/dsh-client-ui-primitives 三项,但 lib/client.js 只 require("react");
它也没有注册 locale 字典,面板文案(「key配置」「读取套餐」「显示在入口」等)是硬编码中文。pollIntervalSeconds(下限 20 秒)。volcesTier 是死配置:可在面板下拉选择并持久化,但宿主从未把它用于请求或解析。showResetTime 无人消费:schema 与 /config、snapshot 都会带出,客户端不读。配额的重置时间
在宿主 parseQuotaRows 里读成了 reset,但未进入对外快照。qwen 区块没有对应的宿主轮询:entryVisibility.qwen 只控制侧边栏是否显示,
Qwen 数据来自会话桶(token / 调用次数),额度行在客户端写死为「接口不可查」并给一个外部控制台链接。
因此 state 里只有 6 个供应商条目,而可见性键有 7 个(command 两者都有)。/alpha/billing/credits 不回月度上限,
插件用 (5h cap, 周 cap) 对照官方档位表(COMMAND_PLANS)取月度额度;
官方若调整某档位的 cap 数字,反查会落空并回退到 summary.totalCost 兜底(该接口在部分账号恒回 0,
此时月度行显示 —,5 小时/1 周两行仍正常)。可用 commandMonthlyCap 手工钉死。$ 显示,不参与 DeepSeek 的峰谷计价。pollIntervalSeconds 只在 apply 时生效(Math.max(20, ...)),改小/改大都要重启插件;
客户端快照轮询 8 秒也是写死的。https://api-docs.deepseek.com/zh-cn/quick_start/pricing、
内置价目表(注释标注按 2026-09-11 官方定价页校准,含峰谷两档)、
OpenCode 请求使用的伪造 Chrome User-Agent、火山签名固定 open.volcengineapi.com 与 cn-beijing / ark。.hHd-Xa_root:not(.hHd-Xa_collapsed) .hHd-Xa_footerActions{...} —— 直接绑定侧边栏的哈希类名,
壳层类名一变,竖排布局就会失效(功能不崩,只影响排版)。source.provider:没有路由信息的事件只进总量、不进来源桶,
所以「各来源相加 ≤ 总览总量」是预期行为。catch 吞掉异常并写 entry.error(如「未配置」「HTTP 401」「接口错误」),
面板只显示这一句短文案,日志里没有逐次堆栈(价格抓取失败会 console.warn)。COMMAND_API_KEY,而由 DSH 模型设置
写入 .credentials.yaml 的名字是 COMMANDCODE_API_KEY(即 profile 里 providers.commandcode.apiKeyEnv)。
后果:凡是在 DSH 里配好 command goat 的用户,面板恒显示「未配置」(2026-10-10 实测复现)。
现在按 COMMANDCODE_API_KEY → COMMAND_API_KEY 的顺序解析,两个名字都能用。
该值本身就是可用凭据(实测:93 字符、u 开头,直连 /alpha/billing/credits 返回 200,
解析出 plan=GOAT / five=97.7% / weekly=94.1% / monthly=56.0%),但形状不像 sk-,
别误判成"引用";读取时走 credentials.resolve() 而不是自己解析文件。smoke-command-credits / smoke-command-render /
smoke-client-current-session 的默认目标路径写的是 ../lib/*,而插件早已是 code/*
(提交 20bc5b8 同时做了 lib/→code/ 改名并新增这三个测试,路径却仍指向 lib/,提交信息还声称
"测试内 ../lib/ 引用同步"——实际没有)。三份测试因此全部 ERR_MODULE_NOT_FOUND,
等于 52 项检查(26+15+11)长期无人执行。修好后全部通过。