@mzzsfy/dsh-usage-panel 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @mzzsfy/dsh-usage-panel(用量面板)
2
+
3
+ DeepSeek Harness 双端插件:在「设置 → 账号余额」手动配置多组(上限 20 个)LLM 平台账号(API 地址 + Key),定期自动查询并展示每个账号的余额、额度与历史趋势;刷新评估越过逻辑点(用量阈值穿越 / 余额阈值穿越 / 额度窗口重置)时,经 webhook、dsh-im、页内 toast 三通道推送通知。无自动发现;配置持久化在本机 `~/.dsh/dsh-usage-panel/accounts.json`,查询快照留存于同目录 `history.json`。
4
+
5
+ ## 安装
6
+
7
+ ```sh
8
+ dsh plugin --profile web add @mzzsfy/dsh-usage-panel
9
+ ```
10
+
11
+ `--profile` 必填;本包为 web 平台向,建议 web profile。
12
+
13
+ 或手动把以下条目加入 `~/.dsh/profiles/web/cordis.patch.yml` 的 `insert` 列表(勿写入 profile 根 cordis.yml——该文件每次启动会被重写,手动行会静默丢失):
14
+
15
+ ```yaml
16
+ - insert:
17
+ - id: usage-panel
18
+ name: '@mzzsfy/dsh-usage-panel'
19
+ ```
20
+
21
+ ## 支持的平台
22
+
23
+ | 类型 | 默认地址 | 查询接口 | 展示 |
24
+ | --- | --- | --- | --- |
25
+ | `deepseek` | `https://api.deepseek.com` | `GET /user/balance` | 各币种余额 + 可用性 |
26
+ | `openrouter` | `https://openrouter.ai` | `GET /api/v1/credits` | 剩余/总额/已用(USD) |
27
+ | `kimi` | `https://api.kimi.com/coding` | `GET /v1/usages` | 5小时/7天窗口进度条 |
28
+ | `zhipu` | `https://open.bigmodel.cn` | `GET /api/monitor/usage/quota/limit` | 5小时/7天进度条;兼容 v3 `CREDIT_LIMIT` |
29
+ | `minimax` | `https://api.minimaxi.com` | `GET /v1/api/openplatform/coding_plan/remains` | 5小时/7天进度条 |
30
+ | `newapi` | 需填写站点地址 | `GET {站点}/api/usage/token` | quota/500000 换算 USD |
31
+ | `custom` | 需填写完整 URL | 任意 HTTP 端点 | 按 extract 规则提取 |
32
+
33
+ 预设类型均可用「API 基础地址」覆盖默认(如中转站),Key 按平台要求以 `Authorization: Bearer <key>`(智谱为裸 key)发送。
34
+
35
+ ## 读数展示
36
+
37
+ - 额度窗口(5小时/7天)渲染为进度条,绿/橙/红三档(70%/90% 阈值);余额账户有已用/总额时同样渲染
38
+ - 鼠标悬停读数行显示明细:余/总额、已用、赠送、充值、重置时间、账户可用性
39
+ - 卡片头部:账号名 + 平台类型徽章 + 套餐档位徽章(智谱 `data.level` / Kimi membership)
40
+
41
+ ## 定期查询与趋势(v2)
42
+
43
+ - 定期查询:时间驱动调度——每账号按读数档位定档,含 5 小时窗口的账号每 10 分钟查询一次(= 短窗口快照粒度),其余账号每小时一次(= 长窗口快照粒度);上次尝试查询时刻随配置持久化,宿主重启后调度无缝衔接。定时轮询为软依赖:宿主 timer 服务不可用时仅停用自动轮询,面板显示降级提示,手动查询与全部配置能力不受影响
44
+ - 失败退避:单账号失败按指数退避(基期 = 账号档位间隔,×2 封顶 8 倍),成功即恢复;失败账号按短档节奏(10 分钟)调度重试,退避指数压制实际频率,避免一次瞬时失败造成短窗序列长时间空洞。退避与档位到点独立叠加,二者皆过才发起查询。面板打开触发的自动查询同样受退避约束,手动刷新不受限
45
+ - 历史快照:按序列分档落盘 `history.json`(5 小时滚动 → 10 分钟粒度留 7 天;7 天 / 月 / 余额 → 小时粒度留 30 天),档内去重,超期修剪,硬点数上限兜底;删除账号时其历史序列同步清理
46
+ - 趋势视图:悬浮账号卡片弹出 sparkline(自绘 SVG),短 / 长窗口独立成图,绝对值 / 差值双视角;「详情」对话框可切时间范围(长窗口 / 月 / 余额:近 7 天 / 30 天 / 全部;5 小时短窗口仅近 7 天 / 全部),含区间摘要与明细表
47
+ - 历史文件解析失败时自动备份为 `history.json.bak` 并暂停写入(防空数据覆盖);`history.json` 被移除或恢复为可解析内容后自动恢复写入,`.bak` 是损坏前的最后数据,删除前请确认不再需要。`accounts.json` 同构守卫:损坏时备份为 `accounts.json.bak` 并拒绝一切写入(防账号 Key 被空配置覆盖),恢复后解除
48
+ - 月窗口序列 `月` 由 host 侧按当月余额快照聚合产出
49
+
50
+ ## 通知(v3)
51
+
52
+ 刷新(自动轮询与手动查询)本身不是通知类型,而是评估时机:每次查询成功后评估读数,**越过逻辑点才触发一个事件**,通知关闭时评估短路零成本。
53
+
54
+ ### 通知类型与沿触发
55
+
56
+ | 类型 | 触发逻辑点 | 防抖 |
57
+ | --- | --- | --- |
58
+ | 用量阈值 | 窗口利用率上穿阈值(全局默认 90%,账号可覆盖) | 沿触发:触发一次即解除武装,窗口重置后恢复 |
59
+ | 余额阈值 | 可用余额下穿阈值(数值即启用,留空不评估;口径 remaining 优先、缺失回落 total,币种随读数) | 沿触发:充值回升到阈值上方后恢复武装 |
60
+ | 窗口重置 | 额度窗口 `resetsAt` 轮转(5小时/7天等) | 每窗口生命周期一次,内容为上一窗口峰值利用率 |
61
+
62
+ 沿触发状态与窗口峰值基线随账号持久化在 `accounts.json`,宿主重启不重发。
63
+
64
+ ### 规则模型
65
+
66
+ - 全局规则(host settings `usage-panel` 命名空间的 `notify` 键,面板与 settings.yaml 等价,热生效):
67
+
68
+ ```yaml
69
+ usage-panel:
70
+ notify:
71
+ enabled: false # 总开关,默认关闭
72
+ quotaThresholdPct: 90 # 用量窗口阈值百分比,(0,100]
73
+ balanceThreshold: null # 余额阈值,null 为不启用
74
+ resetNotice: true # 窗口重置时通知上一窗口峰值
75
+ toast: true # 页内 toast 通道
76
+ webhookUrl: '' # 凭据,留空禁用;面板只写不回显
77
+ imTargets: [] # dsh-im 投递目标 [{botId, targetId}]
78
+ ```
79
+
80
+ - 账号覆盖:账号表单「通知规则覆盖」折叠区,仅 `quotaThresholdPct` / `balanceThreshold` / `resetNotice` 三字段,**字段级合并**,留空继承全局;通道配置全局统一。
81
+
82
+ ### 通知通道
83
+
84
+ - webhook:host 直发(Slack-compatible `{text}` + 结构化字段),超时 10 秒不重试,fire-and-forget;面板「保存并测试」返回真实投递结果
85
+ - dsh-im:安装 [@xmanrui/dsh-im](https://www.npmjs.com/package/@xmanrui/dsh-im) 后自动启用,面板粘贴 Bot ID 加载其已保存投递目标目录,勾选即自动保存;支持绑定多个 bot,已绑 bot 以标签展示,点标签加载该 bot 目录,× 一键取消注册(移除该 bot 全部目标);触发逻辑与 webhook 完全一致(fire-and-forget 不重试);目标的新建与平台测试仍在 dsh-im 设置页完成,此处仅选择;「测试 IM」逐目标返回真实结果
86
+ - 页内 toast:host 内存投影(环形 20 条 / 60 秒过期,version 单调递增),浏览器半区长轮询挂起等待增量并经公共依赖 `@mzzsfy/dsh-toast` 展示(语义与 turn-notify 同构);localStorage 单元级认领锁保证多窗口只弹一次。**toast 依赖由 session-manager 插件代挂**,未安装 session-manager 时此通道静默不可用,其余通道不受影响
87
+
88
+ ### 通知接口
89
+
90
+ - `GET /api/usage-panel/notifications`:通知投影长轮询;`cursor` 缺省=首拉立即返回全量,`cursor` 等于当前版本时挂起至事件或超时,落后或超前(宿主重启版本回退)立即返回全量,客户端以响应 version 重置游标自愈;响应 `{units, version}`
91
+ - `GET|POST /api/usage-panel/notify-config`:全局通知规则;`webhookUrl` 属凭据任何响应不回传原文,仅 `webhookConfigured` 标志
92
+ - `POST /api/usage-panel/test-webhook` / `POST /api/usage-panel/test-im`:测试投递,返回真实结果
93
+ - `GET /api/usage-panel/im-targets?botId=`:列出 dsh-im 该 bot 已保存投递目标
94
+
95
+ 全部路由统一经守卫样板:POST 带同源守卫(Origin 与 Host 不符 403)与 JSON content-type 校验(text/plain 等简单请求 400),阻断跨站 drive-by 改写账号配置(含注入指向攻击者端点的账号)、通知配置或借测试通道外发;非 GET/POST 方法一律 405;已知边界同 turn-notify:同源守卫不防 DNS rebinding,该暴露面属 host webserver 全部 /api 路由的存量问题,应在 host 层统一解决。
96
+
97
+ ## custom 提取规则
98
+
99
+ `extract` 是 JSON 对象,`remaining` 必填;读数按余额(balance)形态呈现并参与余额阈值通知、余额历史序列与月窗口聚合。取值支持四种形式:
100
+
101
+ - 点路径字符串:`"data.total_available"`
102
+ - 数字常量:`42`
103
+ - 运算对象:`{"op": "add" | "subtract", "paths": ["a.b", "c"]}`、`{"op": "divide", "path": "a.b", "by": 500000}`
104
+ - 混合:`maxBudget` / `spend` 可选,`unit` 指定币种(默认 USD)
105
+
106
+ 数值提取为严格模式:空串/null/布尔/千分位字符串均视为提取失败,不会伪造成 0。
107
+
108
+ custom 端点支持自定义请求方法(GET/POST/PUT/DELETE/PATCH)、请求头(JSON)与请求体(非 GET 可选),并提供 NewApi 示例一键填入。
109
+
110
+ ## 架构与依赖
111
+
112
+ - Host 半区(`src/index.js`):Node ESM,`fetch` 直连平台 API(超时 20s),通过 `webServer` 服务暴露 `/api/usage-panel/*` 路由(accounts / query / history / settings / notifications / notify-config / test-webhook / test-im / im-targets);需要 DSH 提供 `webServer` 服务与 `settings` 服务(通知规则持久化);`timer` 服务(定期轮询)为软依赖,缺失时仅停用自动轮询
113
+ - Client 半区(`src/client.js`):DSH client-modules 自注册格式(`__ModuleLoader__.load`),注册 `settings.section` 槽位;需要 `slots` 服务与 `react` 18;`@mzzsfy/dsh-toast` 可选消费(动态 require,模块表缺失即页内通道停用,操作反馈降级 `console.warn`)
114
+ - 纯逻辑层(`src/parsers.mjs` / `src/poller.mjs` / `src/history.mjs` / `src/historyStore.mjs` / `src/notify.mjs`):无 IO 数据变换,`npm test` 覆盖解析、时间驱动调度与退避、快照留存、持久化守卫与规则合并 / 沿触发评估 / 投影认领 / 配置校验;趋势图 SVG 点位算法内联于 client.js(唯一实现)
115
+
116
+ ## 安全提示
117
+
118
+ 账号 Key 以明文保存在 `~/.dsh/dsh-usage-panel/accounts.json`,注意不要分享该文件;Key 只存在与使用于宿主进程,**任何接口响应都不回传 Key**(仅带 `hasKey` 标志,保存时空值表示保持不变)。路由访问控制由 DSH web 鉴权层统一负责。
119
+
120
+ ## 已知取舍
121
+
122
+ - spark / feebar 视图组件的前端渲染逻辑以内联方式维护,未做 host/client 双端 parity 测试,属已知技术债务(点位算法纯客户端消费,单一实现无漂移面)
123
+ - 早期版本允许无 `id` 的账号(落盘时按索引一次性补齐);当前前端保存时总携带 `id`,不再做旧数据特判
124
+ - 账号卡片渲染未做 memo 化、趋势浮层常挂载:数据规模受账号上限(20)与悬浮窗口点数(24)双重钳制,无可感知卡顿,后置观察
125
+
126
+ ## 开发安装(不经 npm 发布直接装仓库副本)
127
+
128
+ ```sh
129
+ dsh plugin --profile web add file:./packages/dsh-usage-panel
130
+ ```
131
+
132
+ `file:` 安装指向仓库工作副本,改代码后重跑该命令即同步,无需发版。
@@ -0,0 +1,8 @@
1
+ # The usage-panel bundle patch: inserts the balance panel plugin into the
2
+ # profile root as one entry. Applied by `dsh plugin add @mzzsfy/dsh-usage-panel`;
3
+ # the row id addresses this plugin's host half, whose `/api/usage-panel/*`
4
+ # routes serve the browser half rendered in the settings page.
5
+
6
+ - insert:
7
+ - id: usage-panel
8
+ name: '@mzzsfy/dsh-usage-panel'
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@mzzsfy/dsh-usage-panel",
3
+ "description": "多平台 LLM 账号余额与额度面板:支持 DeepSeek/OpenRouter/Kimi/智谱/MiniMax/NewApi 及自定义端点,自动定期查询,趋势图与历史快照,用量/余额阈值与窗口重置多通道通知",
4
+ "version": "0.4.3",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./client": "./src/client.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "dsh": {
13
+ "bundle": {
14
+ "patch": "./cordis.patch.yml"
15
+ },
16
+ "client": {
17
+ "platform": "web",
18
+ "external": [
19
+ "@mzzsfy/dsh-toast/client"
20
+ ]
21
+ }
22
+ },
23
+ "scripts": {
24
+ "test": "node --test \"test/*.test.mjs\"",
25
+ "npmPublish": "npm publish --access public --provenance=false --registry=https://registry.npmjs.org"
26
+ },
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/mzzsfy/dsh-plugin.git"
31
+ },
32
+ "engines": {
33
+ "node": ">=22"
34
+ },
35
+ "dependencies": {
36
+ "@mzzsfy/dsh-toast": "^0.1.2"
37
+ },
38
+ "peerDependencies": {
39
+ "@deepseek-ai/dsh-settings": ">=0.1.2-alpha.2",
40
+ "@deepseek-ai/schemastery": ">=3.18.0",
41
+ "react": "^18.2.0"
42
+ },
43
+ "files": [
44
+ "src",
45
+ "test",
46
+ "cordis.patch.yml",
47
+ "README.md"
48
+ ]
49
+ }