dsh-tokenlens 1.2.1 → 1.2.2
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/CHANGELOG.md +7 -0
- package/PROTOCOL.md +3 -2
- package/README.en.md +5 -3
- package/README.md +7 -5
- package/client.js +15 -9
- package/index.js +10 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [Semantic Versioning](https://semver.org/):修复 = PATCH,新功能 = MINOR,不兼容变更 = MAJOR。发布时同步更新 `package.json` 的 `version`、`index.js` 的 `PLUGIN_VERSION` 与本文件(`node scripts/bump-version.mjs <version> "<note>"`);已发布的条目保持原样。
|
|
4
4
|
|
|
5
|
+
## 1.2.2 — 2026-11-01
|
|
6
|
+
|
|
7
|
+
- fix(workspaces): 修复「工作区悬浮卡片不显示 Token 明细」——Host 在裁剪本地路径时把 `path` 字段误删成空串,客户端只剩标题精确匹配;默认工作区等「界面标题 ≠ 统计标签」的场景因此匹配不到统计(影响 v1.2.1 及更早版本)
|
|
8
|
+
- fix(workspaces): 悬浮卡片匹配增强——标题匹配改为大小写不敏感;Host 只下发文件夹名 basename(不含完整路径);旧 Host 未下发 `path` 时用文件夹名与标签兜底
|
|
9
|
+
- docs: README 增加「用 `link:` 安装的插件不要从插件市场重复安装/升级」的排错说明(Windows 下 pnpm 会遇到 EPERM)
|
|
10
|
+
- 测试:256 个自动化用例(新增工作区 wire basename 回归;客户端匹配逻辑断言)
|
|
11
|
+
|
|
5
12
|
## 1.2.1 — 2026-10-31
|
|
6
13
|
|
|
7
14
|
- feat(settings): 图表模式「明细」环形图的窗口选择(今日 / 最近7天 / 最近X天(或最近30天)/ 总计)持久化到插件设置:点击 pill 立即保存,重开弹窗、切换供应商或重启 DSH 后仍保留上次选择;当前供应商没有该窗口时自动回落到总计
|
package/PROTOCOL.md
CHANGED
|
@@ -135,8 +135,9 @@ counts toward the `opencode-go` provider selected in DSH.
|
|
|
135
135
|
v3 additionally carries the rolling **最近 7 天** window (`last7Days`), the
|
|
136
136
|
provider effective-date fallback (`effectiveDay`, `effectiveDays`,
|
|
137
137
|
`sinceEffective`), per-workspace totals (`workspaces[]`: `workspaceId`, `label`,
|
|
138
|
-
`total`, `messages`, `today`/`last7Days`/`last30Days
|
|
139
|
-
|
|
138
|
+
`total`, `messages`, `today`/`last7Days`/`last30Days`, and `path` — only the
|
|
139
|
+
folder basename, used by the client to match a sidebar hover card; the full
|
|
140
|
+
`cwd` is Host-only and never sent on the wire), the rolling 5-hour local window
|
|
140
141
|
(`fiveHours`, DSH-only because external harnesses are day-granular), and the
|
|
141
142
|
bounded `daily[]` series used by the chart view. Absolute local paths are
|
|
142
143
|
stripped from the wire; free-form error messages have path substrings replaced
|
package/README.en.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
> One glance at your usage: plan capacity for the selected provider plus local token statistics across harnesses, right below the DSH composer.
|
|
11
11
|
|
|
12
|
-
**dsh-TokenLens** is a usage plugin for DSH (DeepSeek Harness), version v1.2.
|
|
12
|
+
**dsh-TokenLens** is a usage plugin for DSH (DeepSeek Harness), version v1.2.2. It keeps two kinds of numbers separate:
|
|
13
13
|
|
|
14
14
|
- **Plan capacity** — the provider's authoritative server-side values (percentage windows, used / cap, balance or remaining credit);
|
|
15
15
|
- **Local token stats** — tokens consumed on this machine across every connected harness, for the selected provider or for all providers combined.
|
|
@@ -66,7 +66,7 @@ dsh plugin --profile <profile> add dsh-tokenlens
|
|
|
66
66
|
Then make sure `dsh.profile.bundles` in `$DSH_HOME/profiles/<profile>/package.json` contains `"dsh-tokenlens"`:
|
|
67
67
|
|
|
68
68
|
```jsonc
|
|
69
|
-
{ "dependencies": { "dsh-tokenlens": "^1.2.
|
|
69
|
+
{ "dependencies": { "dsh-tokenlens": "^1.2.2" },
|
|
70
70
|
"dsh": { "profile": { "bundles": ["…", "dsh-tokenlens"] } } }
|
|
71
71
|
```
|
|
72
72
|
|
|
@@ -82,6 +82,8 @@ GitHub installs track the latest commit on the default branch (not a tag); updat
|
|
|
82
82
|
|
|
83
83
|
**Option C — from source.** `dsh plugin --profile <profile> add "link:<path-to-dsh-tokenlens>"`.
|
|
84
84
|
|
|
85
|
+
> ⚠️ **Do not mix a link install with a market install**: clicking install/upgrade from the market on a `link:` profile fails on Windows (pnpm cannot rename a package over a directory junction — `EPERM ... rename`). To switch, uninstall the link first (quit DSH, remove `profiles/<profile>/node_modules/dsh-tokenlens` with `cmd /c rmdir` — never `Remove-Item -Recurse` — and delete the `"dsh-tokenlens": "link:..."` dependency line), then install from the market.
|
|
86
|
+
|
|
85
87
|
**Option D — from the DSH plugin market.** This repository maintains a DSH plugin market index ([`market/index.json`](market/index.json)); add it once and the plugin shows up in the **Discover** tab with a one-click install:
|
|
86
88
|
|
|
87
89
|
1. DSH → **Plugins** → **More** next to *Experimental plugins* → enable **Custom plugin market**;
|
|
@@ -134,7 +136,7 @@ Host bridge route: `/api/tokenlens`; agent tool: `tokenlens_usage`.
|
|
|
134
136
|
|
|
135
137
|
## Development
|
|
136
138
|
|
|
137
|
-
Node.js ≥ 24, zero runtime dependencies: `node --test` runs the
|
|
139
|
+
Node.js ≥ 24, zero runtime dependencies: `node --test` runs the 256 tests.
|
|
138
140
|
|
|
139
141
|
Release: `node scripts/bump-version.mjs <version> "<note>"` updates `package.json`, `PLUGIN_VERSION` and `CHANGELOG.md`; see [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md).
|
|
140
142
|
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
> **一眼看清你的用量**:在 DSH 输入框下方显示当前供应商的套餐容量,并汇总本机跨 Harness 的 Token 消耗。
|
|
11
11
|
|
|
12
|
-
**dsh-TokenLens(词元透镜)** 是 DSH(DeepSeek Harness)的用量插件(v1.2.
|
|
12
|
+
**dsh-TokenLens(词元透镜)** 是 DSH(DeepSeek Harness)的用量插件(v1.2.2,公开版本)。它把两类数字**按不同口径**分开呈现:
|
|
13
13
|
|
|
14
14
|
- **套餐容量**(供应商服务端权威值):百分比窗口、`已用 / 上限`、账户余额或剩余额度;
|
|
15
15
|
- **本机 Token 统计**(本机记录):当前供应商在本机所有已接入 Harness 上的合计用量,也可切到「全部 Harness」看总账。
|
|
@@ -106,7 +106,7 @@ dsh plugin --profile <profile> add dsh-tokenlens
|
|
|
106
106
|
```jsonc
|
|
107
107
|
{
|
|
108
108
|
"dependencies": {
|
|
109
|
-
"dsh-tokenlens": "^1.2.
|
|
109
|
+
"dsh-tokenlens": "^1.2.2"
|
|
110
110
|
},
|
|
111
111
|
"dsh": {
|
|
112
112
|
"profile": {
|
|
@@ -156,6 +156,8 @@ dsh plugin --profile <profile> add "link:<path-to-dsh-tokenlens>"
|
|
|
156
156
|
|
|
157
157
|
本地开发时,Host 端(`index.js` / `lib/`)改动需要重启或重新加载 profile 才能生效;浏览器端 `client.js` 的改动可能被客户端热替换。
|
|
158
158
|
|
|
159
|
+
> ⚠️ **不要混用 link 安装与市场安装**:用 `link:` 装好的 profile 里再从市场点「安装/升级」会失败(Windows 下 pnpm 无法用 npm 包覆盖目录链接,报 `EPERM ... rename`)。需要切换时,先卸载 link(退出 DSH 后删除 `profiles/<profile>/node_modules/dsh-tokenlens` 这个链接——junction 请用 `cmd /c rmdir`,不要用 `Remove-Item -Recurse` 以免误删源码——并从 profile 的 `package.json` 删掉 `"dsh-tokenlens": "link:..."` 这一行),再从市场安装。
|
|
160
|
+
|
|
159
161
|
### 方式 D:从 DSH 插件市场安装
|
|
160
162
|
|
|
161
163
|
本仓库维护了一份 DSH 插件市场索引([`market/index.json`](market/index.json)),在 DSH 里添加一次索引源,就能在「发现」页搜索、查看并一键安装:
|
|
@@ -382,14 +384,14 @@ Host 半注册 `tokenlens_usage`,参数 `action`(默认 `snapshot`)与可
|
|
|
382
384
|
- Harness 卸载后其数据目录消失即判定为未安装,默认从弹窗隐藏(可用 `stats.showUninstalled: true` 显示「未安装」行);数据目录仍在磁盘时按历史记录继续计入。
|
|
383
385
|
- ZCode 数据库通常很大且持续写入:插件只做聚合查询并缓存结果,数据库被锁时会短暂显示不可用。
|
|
384
386
|
- 供应商映射是启发式的(alias → 同 id → vendor-namespaced 模型唯一匹配);语义模糊的 provider 会留在未映射列表,可用 `providerAliases` 指定。
|
|
385
|
-
- 工作区 Token
|
|
387
|
+
- 工作区 Token 徽标/悬浮卡片为实验特性,依赖 DSH 侧栏的 DOM 结构;悬浮卡片按工作区标题(大小写不敏感)或文件夹名匹配,DSH 界面变化时可能自动降级为不显示(v1.2.2 修复了 Host 未下发文件夹名、导致标题与统计标签不一致时悬浮卡片不显示 Token 明细的问题)。
|
|
386
388
|
- 多个 composer 同时挂载时,详情对话框只归属发起点击的会话。
|
|
387
389
|
|
|
388
390
|
**商标声明**:OpenCode、Command Code、DeepSeek、ZCode、WorkBuddy、CodeBuddy、Qoder 等名称与商标归各自权利人所有。本插件为独立第三方项目,与上述公司无关联,也未获得其背书。
|
|
389
391
|
|
|
390
392
|
## 验证
|
|
391
393
|
|
|
392
|
-
- `node --test`:**
|
|
394
|
+
- `node --test`:**256 个自动化用例**,覆盖 Host 数据层、供应商适配器、统计折叠、各 harness 读取、插件集成与浏览器端渲染 / 交互。
|
|
393
395
|
- 在真实环境中验证过 **5 个 harness** 的数据源;本机统计与独立的 SQLite 查询、独立的日志解析逐项对账(差额为 0),跨 harness 合并与供应商映射算术自洽。
|
|
394
396
|
- 供应商接口按各官方文档与参考客户端行为验证;未配置凭据时 chip 静默隐藏,接口异常时按可重试错误降级。
|
|
395
397
|
|
|
@@ -400,7 +402,7 @@ Host 半注册 `tokenlens_usage`,参数 `action`(默认 `snapshot`)与可
|
|
|
400
402
|
```powershell
|
|
401
403
|
git clone https://github.com/daigahou/dsh-tokenlens.git
|
|
402
404
|
cd dsh-tokenlens
|
|
403
|
-
node --test #
|
|
405
|
+
node --test # 256 个用例
|
|
404
406
|
```
|
|
405
407
|
|
|
406
408
|
本地联调安装方式见[方式 C](#方式-c本地开发从源码-link)。
|
package/client.js
CHANGED
|
@@ -6769,15 +6769,18 @@ window.__ModuleLoader__.load({
|
|
|
6769
6769
|
}
|
|
6770
6770
|
|
|
6771
6771
|
/**
|
|
6772
|
-
* Match one hover card to its stats.workspaces entry:
|
|
6773
|
-
* first, then a UNIQUE path suffix (entry path endsWith the card
|
|
6774
|
-
* the card path endsWith the entry basename
|
|
6772
|
+
* Match one hover card to its stats.workspaces entry (v1.2.2): case-insensitive
|
|
6773
|
+
* exact label first, then a UNIQUE path suffix (entry path endsWith the card
|
|
6774
|
+
* path, the card path endsWith the entry basename, or the folder-name suffix
|
|
6775
|
+
* equals the entry label for Hosts whose wire path is empty). Ambiguous → null.
|
|
6775
6776
|
*/
|
|
6776
6777
|
function workspaceHoverEntryOf(stats, title, pathText) {
|
|
6777
6778
|
if (stats === null || typeof stats !== 'object' || !Array.isArray(stats.workspaces)) return null
|
|
6778
|
-
const wantedTitle = typeof title === 'string' ? title.trim() : ''
|
|
6779
|
+
const wantedTitle = typeof title === 'string' ? title.trim().toLowerCase() : ''
|
|
6779
6780
|
if (wantedTitle !== '') {
|
|
6780
|
-
const byLabel = stats.workspaces.filter(
|
|
6781
|
+
const byLabel = stats.workspaces.filter(
|
|
6782
|
+
(entry) => stringOrEmpty(entry?.label).trim().toLowerCase() === wantedTitle,
|
|
6783
|
+
)
|
|
6781
6784
|
if (byLabel.length === 1) return byLabel[0]
|
|
6782
6785
|
}
|
|
6783
6786
|
const cardPath = typeof pathText === 'string' ? pathText.trim().toLowerCase() : ''
|
|
@@ -6785,10 +6788,13 @@ window.__ModuleLoader__.load({
|
|
|
6785
6788
|
if (suffix === '') return null
|
|
6786
6789
|
const byPath = stats.workspaces.filter((entry) => {
|
|
6787
6790
|
const entryPath = stringOrEmpty(entry?.path).trim().toLowerCase()
|
|
6788
|
-
|
|
6789
|
-
if (
|
|
6790
|
-
|
|
6791
|
-
|
|
6791
|
+
const entryLabel = stringOrEmpty(entry?.label).trim().toLowerCase()
|
|
6792
|
+
if (entryPath !== '') {
|
|
6793
|
+
if (workspacePathSuffixOf(entryPath).toLowerCase() === suffix) return true
|
|
6794
|
+
if (cardPath !== '' && (entryPath.endsWith(cardPath) || cardPath.endsWith(entryPath))) return true
|
|
6795
|
+
}
|
|
6796
|
+
// Old Hosts sent no path; the label often carries the folder name.
|
|
6797
|
+
return entryPath === '' && entryLabel !== '' && entryLabel === suffix
|
|
6792
6798
|
})
|
|
6793
6799
|
return byPath.length === 1 ? byPath[0] : null
|
|
6794
6800
|
}
|
package/index.js
CHANGED
|
@@ -72,7 +72,7 @@ export const inject = []
|
|
|
72
72
|
export const PLUGIN_NAME = 'dsh-tokenlens'
|
|
73
73
|
|
|
74
74
|
/** Plugin version; mirrors package.json (kept here so diagnostics need no fs read). */
|
|
75
|
-
export const PLUGIN_VERSION = '1.2.
|
|
75
|
+
export const PLUGIN_VERSION = '1.2.2'
|
|
76
76
|
|
|
77
77
|
/** Documented defaults; every field of the raw row config is optional. */
|
|
78
78
|
const DEFAULTS = {
|
|
@@ -1291,12 +1291,16 @@ export function apply(ctx, rawConfig) {
|
|
|
1291
1291
|
}
|
|
1292
1292
|
}
|
|
1293
1293
|
if (Array.isArray(out.workspaces)) {
|
|
1294
|
-
|
|
1294
|
+
// Only the basename crosses the wire: the client matches a workspace hover
|
|
1295
|
+
// card by its folder name (the full cwd stays Host-only). v1.2.2 fixes a
|
|
1296
|
+
// double-map bug that always emptied this field, which made hover cards
|
|
1297
|
+
// without an exact title match show no token stats.
|
|
1298
|
+
out.workspaces = out.workspaces.map(({ cwd, path, ...row }) => {
|
|
1299
|
+
const full = typeof path === 'string' && path !== '' ? path : typeof cwd === 'string' ? cwd : ''
|
|
1300
|
+
const parts = full.split(/[\\/]+/).filter((part) => part !== '')
|
|
1301
|
+
return { ...row, path: parts.length === 0 ? '' : parts[parts.length - 1] }
|
|
1302
|
+
})
|
|
1295
1303
|
}
|
|
1296
|
-
out.workspaces = out.workspaces.map((row) => ({
|
|
1297
|
-
...row,
|
|
1298
|
-
path: String(row.path ?? row.cwd ?? '').split(/[\\/]/).filter(Boolean).pop() ?? '',
|
|
1299
|
-
}))
|
|
1300
1304
|
return scrubMessagePaths(out)
|
|
1301
1305
|
}
|
|
1302
1306
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-tokenlens",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "dsh-TokenLens (词元透镜) — provider-aware plan capacity plus local token statistics (today/7d/30d/all-time, by harness/provider/model/workspace) for DSH.",
|
|
6
6
|
"license": "MIT",
|