@angelyeye/dsh-cost-tracker 1.7.0 → 1.7.1
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 +26 -2
- package/README.en.md +7 -3
- package/README.md +7 -3
- package/client.js +76 -1
- package/cordis.patch.yml +7 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,15 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
本文件用中文记录 dsh-cost-tracker 的版本变更。
|
|
4
4
|
|
|
5
|
+
## v1.7.1(2026-09-14)
|
|
6
|
+
|
|
7
|
+
**修复(严重,影响所有 v1.7.0 的干净安装)**
|
|
8
|
+
- **修复客户端半端加载失败**:`client.js` 向浏览器端 `__ModuleLoader__.load()` 注册时用的 id 仍是旧裸名 `dsh-cost-tracker`,而加载器持有的图行 id 已是包名全称 `@angelyeye/dsh-cost-tracker`(v1.7.0 改包名时漏改了这一处手写字符串)。两者不等,加载器判定「bundle 已执行但没有以该 id 注册」并抛错:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
client-modules: bundle /plugins/??…@angelyeye/dsh-cost-tracker/client.js… loaded without
|
|
12
|
+
registering "@angelyeye/dsh-cost-tracker" via __ModuleLoader__.load
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
表现为 `HARNESS / Failed to load plugins`:插件的服务端部分正常(Agent 工具仍可用),但客户端整半端(设置页「花费统计」、输入框花费状态条、侧边栏峰谷条)全部不出现。
|
|
16
|
+
- **影响范围**:`npm` / 插件市场 / `github:Angelyeye/dsh-cost-tracker` / 手工 clone —— **所有**安装路径下的干净安装都会命中。图行 id 由包自己声明的 `name` 推导,与安装方式无关;v1.7.0 是此前唯一已发布版本,因此本修复针对的就是全部现存安装。
|
|
17
|
+
|
|
18
|
+
**加固(防回归)**
|
|
19
|
+
- `client.js` 末尾新增注册名护栏:以单一事实源常量表述注册 id,执行时自检「实际写入 `factories` 的 id」是否等于包名。**一致时不介入**(不会安装对 `loader.load` 的包装);不一致时在控制台直接点名根因 —— 若注册的是历史裸名,会明确说明这是 v1.7.0 的缺陷及改法,而不是只留加载器那句难以定位的报错。
|
|
20
|
+
- 新增 `test/client-registration.test.js`(11 项断言):在 `node:vm` 沙箱里按宿主的真实注册语义运行 bundle,断言注册名严格等于 `package.json` 的 `name`、允许尾部 `/client` 写法(会被宿主的 `stripClientSuffix` 去掉)、并**反向验证**注册名不一致时护栏必须报错。已接入 `npm test`。
|
|
21
|
+
|
|
22
|
+
**文档**
|
|
23
|
+
- **更正 v1.7.0 条目里的迁移指引**:原文让人用 `dsh plugin --profile web add github:Angelyeye/dsh-cost-tracker` 重装 —— 该写法在 v1.7.0 上**同样无法修复**客户端加载失败(包名不变、图行 id 不变,问题在 bundle 内部)。已装坏的用户正确出路是**升级到 1.7.1**,不需要重装。中英文 README 同步更正。
|
|
24
|
+
- 明确一条开发约定:**客户端 bundle 注册的 id 必须与 `package.json` 的 `name` 逐字一致**(允许尾部带 `/client`)。包名带 scope 时尤其容易漏。
|
|
25
|
+
|
|
26
|
+
**升级**
|
|
27
|
+
- 1.7.0 → 1.7.1 直接升级即可,**无需**先卸载;`cordis.patch.yml` 的 loader id 未变,不会产生重复注册。功能、数据格式、存储路径均无变化。
|
|
28
|
+
|
|
5
29
|
## v1.7.0(2026-09-12)
|
|
6
30
|
|
|
7
31
|
**变更(破坏性,仅影响安装方式,不影响功能与数据)**
|
|
8
32
|
- **包名由 `dsh-cost-tracker` 改为 `@angelyeye/dsh-cost-tracker`**:npm 上原名已被他人占用,而插件市场的 npm 映射要求「已发布包名 = 仓库 `package.json` 的 `name`」并且该包的 `repository` 指回本仓库。改名后市场才能建立 npm 映射(下载量、宿主兼容徽章、版本化更新)。
|
|
9
33
|
- `cordis.patch.yml` 的 bundle 补丁同步改为新包名。**注意 scoped 名在 YAML 里必须加引号**(`name: "@angelyeye/dsh-cost-tracker"`)——`@` 是 YAML 的保留起始字符,不加引号会导致整个 bundle 层解析失败。
|
|
10
34
|
- **迁移**:旧安装必须**先清掉旧的、再装新的**,不能直接叠加安装 —— 新旧两份 `cordis.patch.yml` 用的是**同一个 loader id**(`dsh-cost-tracker`),叠加会让两份同时加载,表现为重复的 HTTP 路由、Agent 工具与 UI 插槽。
|
|
11
|
-
- 市场安装的(用 `dsh plugin add` 装的):`dsh plugin --profile web remove dsh-cost-tracker`,再 `dsh plugin --profile web add
|
|
35
|
+
- 市场安装的(用 `dsh plugin add` 装的):`dsh plugin --profile web remove dsh-cost-tracker`,再 `dsh plugin --profile web add @angelyeye/dsh-cost-tracker`;
|
|
12
36
|
- 手工 clone 装的:删掉 `~/.dsh/profiles/web/cordis.patch.yml` 里 id 为 `dsh-cost-tracker` 的那段 `- insert:`,并 `rm -rf ~/.dsh/profiles/node_modules/dsh-cost-tracker`,然后重装一次。
|
|
13
|
-
-
|
|
37
|
+
- ~~按仓库安装的写法 `dsh plugin --profile web add github:Angelyeye/dsh-cost-tracker` 改名后依然可用(包名以包自己声明的为准)。~~ **【v1.7.1 更正】** 该写法在 v1.7.0 上同样无法修复客户端加载失败(包名不变、图行 id 不变,故障在 bundle 内部),且会让人误以为排障成功。已装坏的用户请直接升级到 v1.7.1。详见 README「从旧包名迁移」。
|
|
14
38
|
- README(中/英)安装章节同步更新。
|
|
15
39
|
|
|
16
40
|
**不变**
|
package/README.en.md
CHANGED
|
@@ -72,7 +72,7 @@ This plugin is listed in the curated [awesome-dsh-plugin](https://github.com/awe
|
|
|
72
72
|
dsh plugin --profile web add @angelyeye/dsh-cost-tracker
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
>
|
|
75
|
+
> You can also install straight from the repository with `dsh plugin --profile web add github:Angelyeye/dsh-cost-tracker`. It yields the same package: the name comes from the bundle's own `package.json`, so the graph row id — and therefore the client-registration requirement — is identical either way.
|
|
76
76
|
|
|
77
77
|
The marketplace installs the plugin into your profile and writes the loader config for you. It installs **the latest published version** — no manual `git clone`, no hand-editing the patch file. Restart `dsh web` and refresh the browser when prompted.
|
|
78
78
|
|
|
@@ -122,13 +122,15 @@ dsh web
|
|
|
122
122
|
|
|
123
123
|
As of v1.7.0 the package name changed from `dsh-cost-tracker` to `@angelyeye/dsh-cost-tracker` — the old name is held on npm by an unrelated package, and the marketplace's npm mapping requires the published name to equal the repository's `package.json` `name`.
|
|
124
124
|
|
|
125
|
+
> ⚠️ **The v1.7.0 migration guidance has been corrected.** v1.7.0 shipped a client-registration defect (see the v1.7.1 entry in [`CHANGELOG.md`](./CHANGELOG.md)): the client half fails to load for **every** install of v1.7.0, whichever way it was installed. Install **v1.7.1 or newer** — do not troubleshoot by reinstalling v1.7.0. Installing from the repository does not help either: the package name is the same, so the graph row id is the same, and the fault is inside the bundle.
|
|
126
|
+
|
|
125
127
|
⚠️ **Do not simply install the new version on top of the old one.** Both versions' `cordis.patch.yml` insert the **same loader id** (`dsh-cost-tracker`), so stacking them loads **both copies** — duplicated HTTP routes, agent tools and UI slots. Remove the old one first:
|
|
126
128
|
|
|
127
129
|
**Marketplace install** (installed via `dsh plugin add`):
|
|
128
130
|
|
|
129
131
|
```bash
|
|
130
132
|
dsh plugin --profile web remove dsh-cost-tracker
|
|
131
|
-
dsh plugin --profile web add
|
|
133
|
+
dsh plugin --profile web add @angelyeye/dsh-cost-tracker
|
|
132
134
|
```
|
|
133
135
|
|
|
134
136
|
**Manual clone install**:
|
|
@@ -140,7 +142,9 @@ rm -rf ~/.dsh/profiles/node_modules/dsh-cost-tracker
|
|
|
140
142
|
# 3. Reinstall once via Option A above
|
|
141
143
|
```
|
|
142
144
|
|
|
143
|
-
|
|
145
|
+
> Note: if you delete the old directory but leave that `- insert:` block in `cordis.patch.yml`, DSH fails to resolve the module name `dsh-cost-tracker` at startup and the profile will not load. Handle both together.
|
|
146
|
+
|
|
147
|
+
**No data is lost**: usage records live in `~/.dsh/storages/cost-tracker-records.json`, independent of the plugin directory, the package name and the install method.
|
|
144
148
|
|
|
145
149
|
---
|
|
146
150
|
|
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
dsh plugin --profile web add @angelyeye/dsh-cost-tracker
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
>
|
|
75
|
+
> 也可以直接按仓库安装:`dsh plugin --profile web add github:Angelyeye/dsh-cost-tracker`。装出来是同一个包——包名以包自己声明的 `package.json` 为准,所以图行 id、以及随之而来的客户端注册要求,两种装法完全一致。
|
|
76
76
|
|
|
77
77
|
市场会把插件装进当前 profile 并自动写好 loader 配置,**装的是市场上架的最新版本**,装完按提示重启 `dsh web`、刷新浏览器,无需手工 `git clone`,也不用自己改 patch 文件。
|
|
78
78
|
|
|
@@ -122,13 +122,15 @@ dsh web
|
|
|
122
122
|
|
|
123
123
|
v1.7.0 起包名由 `dsh-cost-tracker` 改为 `@angelyeye/dsh-cost-tracker` —— 因为 npm 上原名已被他人占用,而市场的 npm 映射要求「已发布的包名 = 仓库 `package.json` 的 `name`」。
|
|
124
124
|
|
|
125
|
+
> ⚠️ **v1.7.0 的迁移指引已更正**:v1.7.0 存在客户端注册名缺陷(详见 [`CHANGELOG.md`](./CHANGELOG.md) 的 v1.7.1 条目),**任何安装方式装出来的 v1.7.0 都无法加载客户端**。请直接装 **v1.7.1 或更高版本**,不要用重装 v1.7.0 的方式排障 —— 按仓库装同样不行(包名一样,图行 id 一样,问题出在 bundle 内部)。
|
|
126
|
+
|
|
125
127
|
⚠️ **不要只是"再装一次新版"**:新旧两份的 `cordis.patch.yml` 用的是**同一个 loader id**(`dsh-cost-tracker`),叠加安装会让**两份同时被加载** —— 表现为重复的 HTTP 路由、Agent 工具与 UI 插槽。必须先清掉旧的:
|
|
126
128
|
|
|
127
129
|
**市场安装的**(用 `dsh plugin add` 装的):
|
|
128
130
|
|
|
129
131
|
```bash
|
|
130
132
|
dsh plugin --profile web remove dsh-cost-tracker
|
|
131
|
-
dsh plugin --profile web add
|
|
133
|
+
dsh plugin --profile web add @angelyeye/dsh-cost-tracker
|
|
132
134
|
```
|
|
133
135
|
|
|
134
136
|
**手工 clone 装的**:
|
|
@@ -140,7 +142,9 @@ rm -rf ~/.dsh/profiles/node_modules/dsh-cost-tracker
|
|
|
140
142
|
# 3. 再按上面的「方式一」重新安装一次
|
|
141
143
|
```
|
|
142
144
|
|
|
143
|
-
|
|
145
|
+
> 提示:清理旧目录后,如果 `cordis.patch.yml` 里那段 `- insert:` 没删掉,DSH 启动时会因为找不到模块名 `dsh-cost-tracker` 而解析失败。两者要一起处理。
|
|
146
|
+
|
|
147
|
+
**数据不会丢**:用量记录在 `~/.dsh/storages/cost-tracker-records.json`,与插件目录、包名、安装方式全都无关。
|
|
144
148
|
|
|
145
149
|
---
|
|
146
150
|
|
package/client.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// 输出为浏览器 ModuleLoader bundle:exports.apply / exports.inject
|
|
8
8
|
// ============================================================
|
|
9
9
|
window.__ModuleLoader__.load({
|
|
10
|
-
id: "dsh-cost-tracker",
|
|
10
|
+
id: "@angelyeye/dsh-cost-tracker",
|
|
11
11
|
factory: (require) => {
|
|
12
12
|
var module = { exports: {} };
|
|
13
13
|
var exports = module.exports;
|
|
@@ -1253,3 +1253,78 @@ window.__ModuleLoader__.load({
|
|
|
1253
1253
|
return module.exports;
|
|
1254
1254
|
}
|
|
1255
1255
|
});
|
|
1256
|
+
|
|
1257
|
+
// ------------------------------------------------------------
|
|
1258
|
+
// 注册名护栏(防回归)
|
|
1259
|
+
//
|
|
1260
|
+
// 背景:DSH 客户端 ModuleLoader 按模块图里的 row.id 拉取 bundle,脚本执行后要求
|
|
1261
|
+
// __ModuleLoader__.load() 的 id 与之「完全一致」(允许尾部带 "/client",会被
|
|
1262
|
+
// stripClientSuffix 去掉),否则抛:
|
|
1263
|
+
// client-modules: bundle <url> loaded without registering "<id>" via __ModuleLoader__.load
|
|
1264
|
+
//
|
|
1265
|
+
// 该 id 历史上是手写字符串。v1.7.0 发布时漏了 scope 前缀(写成裸名
|
|
1266
|
+
// "dsh-cost-tracker"),导致所有从插件市场安装的用户客户端加载失败、插件无法加载。
|
|
1267
|
+
//
|
|
1268
|
+
// 下面两层都指向同一个单一事实源 _DSH_BUNDLE_ID,改动包名时只需改这一处;
|
|
1269
|
+
// 同时若宿主将来改变约定,也能在控制台给出明确指引,而不是只留一句加载器报错。
|
|
1270
|
+
// ------------------------------------------------------------
|
|
1271
|
+
(function () {
|
|
1272
|
+
/** 单一事实源:必须与 package.json 的 name 完全一致。 */
|
|
1273
|
+
var _DSH_BUNDLE_ID = "@angelyeye/dsh-cost-tracker";
|
|
1274
|
+
/** v1.7.0 发布时用过的旧裸名,仅用于给出针对性提示。 */
|
|
1275
|
+
var _DSH_LEGACY_BARE_ID = "dsh-cost-tracker";
|
|
1276
|
+
|
|
1277
|
+
var loader = (typeof window !== "undefined" && window.__ModuleLoader__) || null;
|
|
1278
|
+
if (!loader || typeof loader.load !== "function") return;
|
|
1279
|
+
|
|
1280
|
+
/** 实际写入 factories 的 id:与加载器内部 stripClientSuffix 保持一致(尾部 "/client" 会被去掉)。 */
|
|
1281
|
+
function storedIdOf(id) {
|
|
1282
|
+
return String(id).replace(/\/client$/, "");
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
function report(registeredId) {
|
|
1286
|
+
var detail = ' bundle 内注册的 id = "' + registeredId + '"(strip 后 = "' + storedIdOf(registeredId) + '")'
|
|
1287
|
+
+ "\n 包名(加载器期望的 id) = \"" + _DSH_BUNDLE_ID + "\"";
|
|
1288
|
+
if (registeredId === _DSH_LEGACY_BARE_ID) {
|
|
1289
|
+
detail += "\n 这是 v1.7.0 的历史缺陷:包改成 scoped 名后,bundle 内的 id 忘了同步加上 scope 前缀。"
|
|
1290
|
+
+ "\n 修复:把 client.js 里 __ModuleLoader__.load({ id: ... }) 改成包名全称(含 scope)。";
|
|
1291
|
+
}
|
|
1292
|
+
if (typeof console !== "undefined" && console.error) {
|
|
1293
|
+
console.error("[dsh-cost-tracker] client bundle 注册名与包名不一致,插件将无法加载。\n" + detail);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// 第 1 层:自检本次 load() 实际写进 factories 的 id。
|
|
1298
|
+
// 只在确认不一致时才动,避免覆盖别人的 loader 行为或产生误报。
|
|
1299
|
+
if (typeof loader.factories !== "undefined") {
|
|
1300
|
+
if (loader.factories.has(storedIdOf(_DSH_BUNDLE_ID))) return;
|
|
1301
|
+
report(_DSH_BUNDLE_ID);
|
|
1302
|
+
var originalLoad = loader.load;
|
|
1303
|
+
loader.load = function (registration) {
|
|
1304
|
+
var r = originalLoad.apply(this, arguments);
|
|
1305
|
+
if (registration && typeof registration.id === "string"
|
|
1306
|
+
&& storedIdOf(registration.id) !== storedIdOf(_DSH_BUNDLE_ID)) {
|
|
1307
|
+
report(registration.id);
|
|
1308
|
+
}
|
|
1309
|
+
return r;
|
|
1310
|
+
};
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// 第 2 层:loader 尚未就绪(HTML 里的 pending queue 模式)。
|
|
1315
|
+
// load() 此时只是入队,等模块系统构造时会逐条重放;这里同样不改变原行为。
|
|
1316
|
+
var queue = loader.pendingQueue;
|
|
1317
|
+
if (!Array.isArray(queue)) return;
|
|
1318
|
+
var queuedLoad = loader.load;
|
|
1319
|
+
loader.load = function (registration) {
|
|
1320
|
+
var r = queuedLoad.apply(this, arguments);
|
|
1321
|
+
if (registration && typeof registration.id === "string"
|
|
1322
|
+
&& storedIdOf(registration.id) !== storedIdOf(_DSH_BUNDLE_ID)) {
|
|
1323
|
+
report(registration.id);
|
|
1324
|
+
}
|
|
1325
|
+
return r;
|
|
1326
|
+
};
|
|
1327
|
+
if (queue.length === 0) return;
|
|
1328
|
+
if (storedIdOf(queue[queue.length - 1].id) === storedIdOf(_DSH_BUNDLE_ID)) return;
|
|
1329
|
+
report(queue[queue.length - 1].id);
|
|
1330
|
+
})();
|
package/cordis.patch.yml
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# dsh-cost-tracker bundle patch: registers the plugin when installed via
|
|
2
2
|
# `dsh plugin add @angelyeye/dsh-cost-tracker` (or from this repo directly).
|
|
3
|
+
#
|
|
4
|
+
# 注意两个 id 是两回事,不要混改:
|
|
5
|
+
# - 下面的 `id: dsh-cost-tracker` 是 loader 条目 id,用于新旧版本互斥。
|
|
6
|
+
# 它自 v1.6.0 起就没变,改了会与旧版补丁 id 不同,导致两份同时加载
|
|
7
|
+
# (重复的 HTTP 路由、Agent 工具与 UI 插槽)。
|
|
8
|
+
# - 客户端 bundle 的注册 id 必须是包名全称(见 client.js 的 __ModuleLoader__.load),
|
|
9
|
+
# 与这里的 loader id 无关。
|
|
3
10
|
- insert:
|
|
4
11
|
- id: dsh-cost-tracker
|
|
5
12
|
name: "@angelyeye/dsh-cost-tracker"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angelyeye/dsh-cost-tracker",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "DeepSeek Harness (DSH) plugin: LLM token usage & cost tracking with a settings dashboard, agent tools, HTTP API and persistent storage.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"./package.json": "./package.json"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"test": "node test/storage.test.js && node test/pricing.test.js && node test/config.test.js && node test/recompute.test.js"
|
|
22
|
+
"test": "node test/storage.test.js && node test/pricing.test.js && node test/config.test.js && node test/recompute.test.js && node test/client-registration.test.js"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"dsh-plugin",
|