dsh-cost-meter 1.7.8 → 1.7.9
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.en.md +7 -7
- package/README.md +7 -7
- package/lib/custom-balance.js +5 -2
- package/lib/net.js +39 -0
- package/lib/store.js +9 -30
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Per-conversation cost · daily totals · OpenCode Go subscription quota display · budget with usage percentage · official account balance · custom provider balance · balance progress bar · history · peak/off-peak pricing hours display (peak hours UTC 01:00–04:00, 06:00–10:00; from Aug 23, 2026 weekends are billed at off-peak prices all day, shown as “Weekend — all off-peak”) · pre-switch popup & system-notification alerts for peak/off-peak changes (position / lead time / alert type configurable) · one-click price sync from the official docs · Codex-style token usage heat grid · multi-vendor model pricing (built-in 90+ model price catalog with auto-matching) · mainstream Coding Plan quota queries & display (Anthropic / Z.ai / MiniMax / Kimi / OpenRouter / SiliconFlow / CommandCode / SCNet) plan/API dual-track billing (subscription quota vs pay-as-you-go money separated, per-1% & full-window token/equivalent-cost estimates with daily/weekly/monthly curves) · · quota strip above the input box (budget / Go / coding-plan usage in one row, toggleable)
|
|
8
8
|
|
|
9
|
-
[](https://github.com/Han-1413141/dsh-cost-meter)
|
|
10
10
|
[](https://www.npmjs.com/package/dsh-cost-meter)
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
@@ -87,11 +87,11 @@ For NewApi `GET /api/usage/token` (response `{ "code": 200, "data": { "total_gra
|
|
|
87
87
|
- Unlimited-quota tokens (`unlimited_quota: true`) have no `total_available`, so `remaining` cannot be extracted and the query reports “remaining is missing or not numeric” — use a limited-quota token or a middle-layer endpoint that converts the units;
|
|
88
88
|
- Entry point: Settings → Cost (Quota tab) → “Custom provider balance” → expand config; or write `config.customBalance` in `storages/cost-meter/ledger.json`.
|
|
89
89
|
|
|
90
|
-
### Credentials & security (v1.7.
|
|
90
|
+
### Credentials & security (v1.7.9)
|
|
91
91
|
|
|
92
92
|
- **Variable naming**: `{{VAR_NAME}}` follows the `<ROUTE>_API_KEY` convention — `<ROUTE>` is the Provider ID from the DSH Models page (Settings → Models), uppercased with non-alphanumeric characters replaced by underscores, e.g. `openai`→`{{OPENAI_API_KEY}}`, `anthropic`→`{{ANTHROPIC_API_KEY}}`, `abc23-d`→`{{ABC23_D_API_KEY}}`. Sharing a name with the Models page means the balance query and model calls **share the same key** (both resolve from the DSH credential store). This note is also shown above the “Headers (JSON)” input in Settings.
|
|
93
93
|
- **Credential input fields**: after expanding an entry, the “Credential input” section renders one write-only field per `{{VAR}}` placeholder found in the headers — the key goes straight into the DSH credential store (never written to disk, never echoed back, never stored in `ledger.json`); no need to hand-edit environment variables or credential files.
|
|
94
|
-
- **Automatic plaintext migration**: older versions let a literal `Bearer sk-…` in the headers leak into `ledger.json` in plaintext. Since v1.7.
|
|
94
|
+
- **Automatic plaintext migration**: older versions let a literal `Bearer sk-…` in the headers leak into `ledger.json` in plaintext. Since v1.7.9 the plugin imports such keys into the DSH credential store at startup and replaces the header value with a `{{CUSTOM_BALANCE_KEY_…}}` placeholder (derived from the entry's host + header name, stable across restarts) — nothing breaks. From now on `ledger.json` and the config shipped to the browser **never contain plaintext keys**: suspected secret headers (Authorization / X-Api-Key / Bearer / sk- prefixes / long opaque strings) are blanked, while placeholders and ordinary headers pass through.
|
|
95
95
|
- **Credential allowlist `allowedHosts`**: when headers carry credentials (placeholders or plaintext), the outbound host must be on this list or the request is refused — protection against leaked keys when importing someone else's config. Without a list, requests proceed with a one-time logged warning. The entry panel provides an “Allowed hosts” input (comma-separated).
|
|
96
96
|
|
|
97
97
|
## CLIProxyAPI Gateway Quotas and WorkBuddy Credits (Issue #87)
|
|
@@ -252,22 +252,22 @@ Real captures from an actual DSH sidebar of the period strip and collapsed verti
|
|
|
252
252
|
dsh plugin --profile web add dsh-cost-meter
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
-
**PowerShell one-click script** (copy the whole line, paste, press Enter; pnpm is provisioned automatically, git is auto-detected — no clone needed; the install chain is **pinned to the release tag `v1.7.
|
|
255
|
+
**PowerShell one-click script** (copy the whole line, paste, press Enter; pnpm is provisioned automatically, git is auto-detected — no clone needed; the install chain is **pinned to the release tag `v1.7.9`** — review the script before running):
|
|
256
256
|
|
|
257
257
|
```powershell
|
|
258
|
-
irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.
|
|
258
|
+
irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.9/install.ps1 | iex
|
|
259
259
|
```
|
|
260
260
|
|
|
261
261
|
**Or a plain command line** (the machine must already have pnpm and git; also pinned to the tag):
|
|
262
262
|
|
|
263
263
|
```sh
|
|
264
|
-
dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.
|
|
264
|
+
dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.9
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
Without git, use the GitHub tag archive:
|
|
268
268
|
|
|
269
269
|
```sh
|
|
270
|
-
dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.
|
|
270
|
+
dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.9.tar.gz
|
|
271
271
|
```
|
|
272
272
|
|
|
273
273
|
After installing, **restart** `dsh web` (plugin rows, the Typert manifest and the client bundle are all scanned at startup):
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
本会话费用 · 当日费用 · OpenCode Go 订阅额度显示 · 预算与已用百分比 · 官方账户余额 · 自定义 Provider 余额查询(可配任意 HTTP 端点) · 余额三段进度条 · 历史记录 · 峰谷计价时段显示(UTC 01:00–04:00、06:00–10:00 为峰时段;2026-08-23 起周末全天按谷价,显示「周末时段——全谷价」) · 峰/谷切换前弹窗与系统通知提醒(位置/提前量/提醒类型可配) · 官方价格一键同步 · 类 Codex Token 用量热图 · 多厂商多模型价格计费(内置 90+ 模型价格目录与自动匹配) · 主流 Coding Plan 额度查询与显示(Anthropic / Z.ai / MiniMax / Kimi / OpenRouter / SiliconFlow / CommandCode / SCNet / 火山方舟 九家,含 Volcano Ark AK/SK 签名) · Plan/API 双轨计费(订阅额度与按量金额分离统计,每 1% 额度与满窗的 token/等值金额估算及日/周/月曲线) · 输入框上方额度横条(预算/Go/Coding Plan 用量一条横排显示,可开关)
|
|
8
8
|
|
|
9
|
-
[](https://github.com/Han-1413141/dsh-cost-meter)
|
|
10
10
|
[](https://www.npmjs.com/package/dsh-cost-meter)
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
@@ -88,11 +88,11 @@
|
|
|
88
88
|
- 无限额度 token(`unlimited_quota: true`)没有 `total_available`,无法提取 `remaining`,查询会报「remaining is missing or not numeric」——请改用有限额度 token,或在中间层端点换算;
|
|
89
89
|
- 配置入口:设置 → 费用(额度标签)→「自定义 Provider 余额」展开配置;或直接改 `storages/cost-meter/ledger.json` 的 `config.customBalance`。
|
|
90
90
|
|
|
91
|
-
### 凭据与安全(v1.7.
|
|
91
|
+
### 凭据与安全(v1.7.9)
|
|
92
92
|
|
|
93
93
|
- **变量名命名规则**:`{{VAR_NAME}}` 的参考格式为 `<ROUTE>_API_KEY`——`<ROUTE>` 对应 DSH 模型配置页(设置 → 模型)里的 Provider ID,把 ID 大写、非字母数字字符替换为下划线,例如 `openai`→`{{OPENAI_API_KEY}}`、`anthropic`→`{{ANTHROPIC_API_KEY}}`、`abc23-d`→`{{ABC23_D_API_KEY}}`。与模型页共用同一变量名,自定义余额查询与模型调用即**共用同一把密钥**(都从 DSH 凭据库解析)。该说明也展示在设置页「请求头 (JSON)」输入框上方。
|
|
94
94
|
- **凭据输入框**:展开条目配置后,「凭据输入」区会为请求头里出现的每个 `{{VAR}}` 占位符显示一行 write-only 输入框,密钥直接存入 DSH 凭据库(不落盘、不回显、不经 `ledger.json`),无需再手改环境变量或凭据文件。
|
|
95
|
-
- **明文密钥自动迁移**:旧版本把 `Bearer sk-…` 明文写在请求头里时会明文落盘;v1.7.
|
|
95
|
+
- **明文密钥自动迁移**:旧版本把 `Bearer sk-…` 明文写在请求头里时会明文落盘;v1.7.9 起插件在启动时自动把这类明文导入 DSH 凭据库,并把头值替换为 `{{CUSTOM_BALANCE_KEY_…}}` 占位符(名称由条目 host + 头名派生,跨重启稳定),功能不受影响。此后 `ledger.json` 与下发给浏览器的配置**永不包含明文密钥**——疑似密钥头(Authorization / X-Api-Key / Bearer / sk- 前缀 / 长不透明串)一律置空,占位符与普通头照常保留。
|
|
96
96
|
- **凭据白名单 `allowedHosts`**:请求头携带密钥(占位符或明文)时,出站主机必须命中该白名单,否则直接拒绝——用于防止「导入他人配置」导致密钥外带。未配置白名单时放行并在日志警告一次。设置页条目面板内有「凭据白名单主机」输入框(逗号分隔)。
|
|
97
97
|
|
|
98
98
|
## CLIProxyAPI 网关额度与 WorkBuddy 积分 (Issue #87)
|
|
@@ -254,22 +254,22 @@
|
|
|
254
254
|
dsh plugin --profile web add dsh-cost-meter
|
|
255
255
|
```
|
|
256
256
|
|
|
257
|
-
**PowerShell 一键脚本**(复制整行粘贴回车;自动补齐 pnpm、自动探测 git,无需克隆仓库;安装链**固定到发布 tag `v1.7.
|
|
257
|
+
**PowerShell 一键脚本**(复制整行粘贴回车;自动补齐 pnpm、自动探测 git,无需克隆仓库;安装链**固定到发布 tag `v1.7.9`**,建议先下载审阅再运行):
|
|
258
258
|
|
|
259
259
|
```powershell
|
|
260
|
-
irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.
|
|
260
|
+
irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.9/install.ps1 | iex
|
|
261
261
|
```
|
|
262
262
|
|
|
263
263
|
**或直接命令行**(机器上需已有 pnpm 与 git;同样固定到 tag):
|
|
264
264
|
|
|
265
265
|
```sh
|
|
266
|
-
dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.
|
|
266
|
+
dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.9
|
|
267
267
|
```
|
|
268
268
|
|
|
269
269
|
没有 git 时可用 GitHub tag 打包直链:
|
|
270
270
|
|
|
271
271
|
```sh
|
|
272
|
-
dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.
|
|
272
|
+
dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.9.tar.gz
|
|
273
273
|
```
|
|
274
274
|
|
|
275
275
|
安装后**重启** `dsh web`(插件行、Typert 清单与客户端 bundle 均在启动时扫描):
|
package/lib/custom-balance.js
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
* 与 coding-plans.js 固定端点 adapter 互补:共用 index.js 侧的 refresh/cache 模式。
|
|
4
4
|
*/
|
|
5
5
|
import { credentialRef } from '@deepseek-ai/dsh-credentials'
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
// 密钥头判定自 net.js 直接导入(v1.7.9):此前从 store.js 导入会在
|
|
7
|
+
// coding-plans → custom-balance → store → plan-billing → coding-plans 的
|
|
8
|
+
// ESM 环上再加一条边,DSH Desktop 的加载顺序下爆发 TDZ。net.js 是零本地
|
|
9
|
+
// 依赖底层,从它导入即断环。
|
|
10
|
+
import { fetchWithRetry, looksLikeSecretHeaderValue } from './net.js'
|
|
8
11
|
|
|
9
12
|
export const CUSTOM_BALANCE_ADAPTER_ID = 'custom'
|
|
10
13
|
|
package/lib/net.js
CHANGED
|
@@ -68,3 +68,42 @@ export async function fetchWithRetry(url, init = {}, { attempts = 4, backoffMs =
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
// ── 请求头密钥判定(v1.7.9 自 store.js 迁入) ─────────────────────────────
|
|
73
|
+
//
|
|
74
|
+
// 本模块是插件的零本地依赖底层(store / custom-balance / coding-plans / gateway
|
|
75
|
+
// 都只依赖 net),这里存放共享判定可避免「coding-plans → custom-balance →
|
|
76
|
+
// store → plan-billing → coding-plans」的 ESM 环(v1.7.6 引入环边 custom-balance
|
|
77
|
+
// → store;v1.7.8 在 DSH Desktop 的加载顺序下爆发 TDZ:
|
|
78
|
+
// Cannot access 'CODING_PLAN_PROVIDER_IDS' before initialization)。
|
|
79
|
+
// 函数语义与迁移前逐位一致,仅搬家破环。
|
|
80
|
+
|
|
81
|
+
/** {{VAR}} 占位符形态(与 custom-balance.js resolveTemplateString 同一文法)。 */
|
|
82
|
+
const HEADER_PLACEHOLDER_RE = /\{\{\s*[A-Za-z_][A-Za-z0-9_]*\s*\}\}/
|
|
83
|
+
|
|
84
|
+
/** 敏感头名:这类头下的非占位符值一律按密钥处理(自定义余额场景里它们就是凭据)。 */
|
|
85
|
+
const SENSITIVE_HEADER_NAME_RE = /authorization|api[-_]?key|apikey|token|secret|cookie|session|credential|private[-_]?key/i
|
|
86
|
+
|
|
87
|
+
/** 典型密钥值形状:sk- 系 / Google AIza / GitHub ghp_ / Slack xoxb- / JWT eyJ 头。 */
|
|
88
|
+
const KNOWN_KEY_VALUE_RE = /^(sk-[A-Za-z0-9_-]|rk-[A-Za-z0-9_-]|gsk_[A-Za-z0-9]|AIza[0-9A-Za-z_-]{10,}|gh[pousr]_[A-Za-z0-9]{20,}|xox[bap]-|eyJ[A-Za-z0-9_-]{10,})/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 判定一个请求头的值是否疑似明文密钥(issue #86)。
|
|
92
|
+
* 两级判定:敏感头名(authorization / api-key / token 等)的非占位符值一律视为密钥;
|
|
93
|
+
* 其余头名只在值具备典型密钥形状(Bearer 前缀 / 已知 key 前缀 / ≥32 位混合字母数字的
|
|
94
|
+
* 不透明长串)时判密钥——Content-Type、Accept 等普通值不会误判(误判会让该头无法落盘)。
|
|
95
|
+
* @param {unknown} name - 头名。
|
|
96
|
+
* @param {unknown} value - 头值。
|
|
97
|
+
* @returns {boolean}
|
|
98
|
+
*/
|
|
99
|
+
export function looksLikeSecretHeaderValue(name, value) {
|
|
100
|
+
if (typeof value !== 'string' || value.length === 0) return false
|
|
101
|
+
// 占位符是安全引用(值本身是变量名,不是密钥),任何路径都原样保留。
|
|
102
|
+
if (HEADER_PLACEHOLDER_RE.test(value)) return false
|
|
103
|
+
if (SENSITIVE_HEADER_NAME_RE.test(String(name ?? ''))) return true
|
|
104
|
+
const trimmed = value.trim()
|
|
105
|
+
if (/^(bearer|basic|token)\s+\S/i.test(trimmed)) return true
|
|
106
|
+
if (KNOWN_KEY_VALUE_RE.test(trimmed)) return true
|
|
107
|
+
if (trimmed.length >= 32 && /^[A-Za-z0-9_-]+$/.test(trimmed) && /[A-Za-z]/.test(trimmed) && /[0-9]/.test(trimmed)) return true
|
|
108
|
+
return false
|
|
109
|
+
}
|
package/lib/store.js
CHANGED
|
@@ -1706,36 +1706,15 @@ export function writeSecret(cfg, target, value) {
|
|
|
1706
1706
|
// 疑似明文密钥的值在落盘/下发/补丁三条路径一律置空;运行期由启动迁移把明文导入
|
|
1707
1707
|
// DSH 凭据库并替换为 {{CUSTOM_BALANCE_KEY_xxx}} 占位符(见 index.js
|
|
1708
1708
|
// migrateCustomBalanceHeaderSecrets),普通头不受影响。
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
/**
|
|
1720
|
-
* 判定一个请求头的值是否疑似明文密钥(issue #86)。
|
|
1721
|
-
* 两级判定:敏感头名(authorization / api-key / token 等)的非占位符值一律视为密钥;
|
|
1722
|
-
* 其余头名只在值具备典型密钥形状(Bearer 前缀 / 已知 key 前缀 / ≥32 位混合字母数字的
|
|
1723
|
-
* 不透明长串)时判密钥——Content-Type、Accept 等普通值不会误判(误判会让该头无法落盘)。
|
|
1724
|
-
* @param {unknown} name - 头名。
|
|
1725
|
-
* @param {unknown} value - 头值。
|
|
1726
|
-
* @returns {boolean}
|
|
1727
|
-
*/
|
|
1728
|
-
export function looksLikeSecretHeaderValue(name, value) {
|
|
1729
|
-
if (typeof value !== 'string' || value.length === 0) return false
|
|
1730
|
-
// 占位符是安全引用(值本身是变量名,不是密钥),任何路径都原样保留。
|
|
1731
|
-
if (HEADER_PLACEHOLDER_RE.test(value)) return false
|
|
1732
|
-
if (SENSITIVE_HEADER_NAME_RE.test(String(name ?? ''))) return true
|
|
1733
|
-
const trimmed = value.trim()
|
|
1734
|
-
if (/^(bearer|basic|token)\s+\S/i.test(trimmed)) return true
|
|
1735
|
-
if (KNOWN_KEY_VALUE_RE.test(trimmed)) return true
|
|
1736
|
-
if (trimmed.length >= 32 && /^[A-Za-z0-9_-]+$/.test(trimmed) && /[A-Za-z]/.test(trimmed) && /[0-9]/.test(trimmed)) return true
|
|
1737
|
-
return false
|
|
1738
|
-
}
|
|
1709
|
+
//
|
|
1710
|
+
// 判定函数 looksLikeSecretHeaderValue 自 v1.7.9 起移居 net.js(零本地依赖层):
|
|
1711
|
+
// v1.7.6 把它放本模块时引入了 custom-balance → store 的环边,连同既有的
|
|
1712
|
+
// store → plan-billing → coding-plans → custom-balance 构成 ESM 环,在 DSH
|
|
1713
|
+
// Desktop 的加载顺序下爆发 TDZ(Cannot access 'CODING_PLAN_PROVIDER_IDS'
|
|
1714
|
+
// before initialization,v1.7.8 用户实测)。本模块自身使用(脱敏三条路径)与
|
|
1715
|
+
// 既有「from store.js 导入」的消费方(测试/客户端)经下方 re-export 保持兼容。
|
|
1716
|
+
import { looksLikeSecretHeaderValue } from './net.js'
|
|
1717
|
+
export { looksLikeSecretHeaderValue }
|
|
1739
1718
|
|
|
1740
1719
|
/**
|
|
1741
1720
|
* 脱敏一条自定义余额条目的请求头:疑似明文密钥的值置空,占位符与普通头原样保留。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-cost-meter",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"description": "DeepSeek Harness 会话费用统计插件:本会话成本、当日费用、历史记录与官方价格同步,支持多厂商多模型价格计费(内置 90+ 模型价格目录与自动匹配)、主流 Coding Plan 订阅额度查询与显示(9 家,含 SCNet Token Plan 本地 Credits 计量与火山方舟 Volcano Ark Coding Plan AK/SK 签名查询)、自定义 Provider 余额查询(可配任意 HTTP 端点)与余额进度条、峰谷计价时段显示与切换前弹窗/系统通知提醒(位置/提前量/类型可配),界面中英双语。Session cost tracking plugin for DeepSeek Harness: per-conversation cost, daily totals, history and official price sync, with multi-vendor model pricing (built-in 90+ model catalog with auto-matching), Coding Plan quota queries & display for 9 vendors (incl. local credits metering for the SCNet Token Plan and Volcano Ark Coding Plan via AK/SK signature), plan/API dual-track billing with per-1% & full-window Token Plan usage estimates, custom provider balance lookup (configurable HTTP endpoint) and balance progress bar, plus peak/off-peak pricing display with pre-switch popup & system-notification alerts (position / lead time / type configurable), in a bilingual (Chinese/English) UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|