@kidli1412/dsh-token-heatmap 0.1.3 → 0.1.4
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 +2 -1
- package/lib/client.js +6 -3
- package/lib/index.js +42 -4
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -61,9 +61,10 @@ dsh plugin --profile web remove @kidli1412/dsh-token-heatmap
|
|
|
61
61
|
|
|
62
62
|
## 兼容性 / Compatibility
|
|
63
63
|
|
|
64
|
-
- **DSH**:manifest 通过 `dsh.compatibility.dshReleases` 将官方最新三个版本 `0.1.2-alpha.4`、`0.1.2-alpha.5`、`0.1.2-rc.1` 逐项声明为 `compatible`(DSH STORE
|
|
64
|
+
- **DSH**:manifest 通过 `dsh.compatibility.dshReleases` 将官方最新三个版本 `0.1.2-alpha.4`、`0.1.2-alpha.5`、`0.1.2-rc.1` 逐项声明为 `compatible`(DSH STORE 的精确逐版本兼容证据;仅范围声明不会恢复上架)。插件使用的客户端注入(`dsh-api-remotes` / `dsh-client-connection` / `dsh-client-locale` / `dsh-client-ui-conversation` / `dsh-client-ui-settings`)与 Host 服务(`settings` namespace、`webServer` 精确路由)在这条版本线上保持稳定。
|
|
65
65
|
- **Node**:`^22.19.0 || >=24.0.0`(与 DSH 一致)。
|
|
66
66
|
- **依赖**:`@deepseek-ai/dsh-settings` 自 0.1.3 起提升为 `^0.1.2-rc.1`、`@deepseek-ai/schemastery` 提升为 `^3.18.2`,与 DSH 0.1.2 版本线对齐。npm 的 prerelease 解析规则下 `^0.1.0-rc.7` 不会解析到 `0.1.2-rc.1`(只会装 `0.1.0-rc.8`),因此较低的范围会拉到与新版 DSH 不同 train 的 settings 副本。
|
|
67
|
+
- **0.1.4(DSH 0.1.2 适配)**:rc.1 起 live session 不再携带 `.events` 数组(改用 `session.seq` + `session.eventAt(seq)`,与官方 `dsh-token-meter` 相同),新会话判断从 `composerPhase === "blank"` 改为布尔 `session.blank`;`sessionPersistence` 在 rc.1 不再提供会话枚举(list/listSnapshots 已移除),持久化历史的增量刷新降级为保留已有缓存、只累计 live 会话。客户端注入模块列表同步为新架构模块(见上)。
|
|
67
68
|
|
|
68
69
|
## License
|
|
69
70
|
|
package/lib/client.js
CHANGED
|
@@ -542,10 +542,13 @@ window.__ModuleLoader__.load({
|
|
|
542
542
|
// config fetch — the loopback endpoint remains as a back-compat API.
|
|
543
543
|
const config = react.useSyncExternalStore(configStore.subscribe, configStore.getSnapshot);
|
|
544
544
|
|
|
545
|
-
// New-session hero only
|
|
546
|
-
// the
|
|
545
|
+
// New-session hero only. DSH 0.1.2+ (rc.1) exposes the state as
|
|
546
|
+
// the boolean `session.blank` (the `composerPhase` string is
|
|
547
|
+
// gone); older harnesses keep `composerPhase === "blank"`.
|
|
548
|
+
// Conversed sessions hide the card.
|
|
547
549
|
if (session === void 0 || session === null || input === void 0 || input === null) return null;
|
|
548
|
-
|
|
550
|
+
const heroBlank = typeof session.blank === "boolean" ? session.blank === true : session.composerPhase === "blank";
|
|
551
|
+
if (!heroBlank) return null;
|
|
549
552
|
// Master switch from the settings card (设置 → 插件 → 插件配置).
|
|
550
553
|
if (config.enabled === false) return null;
|
|
551
554
|
|
package/lib/index.js
CHANGED
|
@@ -389,6 +389,31 @@ async function handleConfig(ctx, req, res) {
|
|
|
389
389
|
}
|
|
390
390
|
//#endregion
|
|
391
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Enumerate a live session's events from an offset, across session shapes.
|
|
394
|
+
*
|
|
395
|
+
* Pre-0.1.2 sessions kept the whole log on the object as `.events`; DSH
|
|
396
|
+
* 0.1.2+ (rc.1) live sessions expose no `.events` array — the count is
|
|
397
|
+
* `session.seq` and each event is read via `session.eventAt(seq)` (0-based,
|
|
398
|
+
* the same reads @deepseek-ai/dsh-token-meter uses).
|
|
399
|
+
* @returns `{ count, events }` — `count` the session's total event count,
|
|
400
|
+
* `events` the events from `from` onward.
|
|
401
|
+
*/
|
|
402
|
+
function liveSessionEvents(session, from) {
|
|
403
|
+
if (Array.isArray(session.events)) {
|
|
404
|
+
return { count: session.events.length, events: session.events.slice(from) };
|
|
405
|
+
}
|
|
406
|
+
if (typeof session.seq !== "number" || typeof session.eventAt !== "function") {
|
|
407
|
+
return { count: 0, events: [] };
|
|
408
|
+
}
|
|
409
|
+
const events = [];
|
|
410
|
+
for (let seq = from; seq < session.seq; seq += 1) {
|
|
411
|
+
const event = session.eventAt(seq);
|
|
412
|
+
if (event !== void 0) events.push(event);
|
|
413
|
+
}
|
|
414
|
+
return { count: session.seq, events };
|
|
415
|
+
}
|
|
416
|
+
|
|
392
417
|
/**
|
|
393
418
|
* Collect per-day usage across live and persisted sessions, incrementally.
|
|
394
419
|
*
|
|
@@ -400,6 +425,9 @@ async function handleConfig(ctx, req, res) {
|
|
|
400
425
|
* the log was truncated/rewritten, so the session is refolded from scratch.
|
|
401
426
|
* Sessions that vanished are dropped, and a session switching between
|
|
402
427
|
* live/persisted is refolded from scratch to stay exact.
|
|
428
|
+
* On DSH 0.1.2+ (rc.1) sessionPersistence no longer exposes a session
|
|
429
|
+
* enumeration (list/listSnapshots are gone), so persisted-only history is
|
|
430
|
+
* kept in the cache untouched instead of being refreshed or dropped.
|
|
403
431
|
*/
|
|
404
432
|
export async function collectUsage(ctx) {
|
|
405
433
|
return withLock(async () => {
|
|
@@ -417,9 +445,9 @@ export async function collectUsage(ctx) {
|
|
|
417
445
|
state.currentModel = null;
|
|
418
446
|
state.consumed = 0;
|
|
419
447
|
}
|
|
420
|
-
const count = session.
|
|
448
|
+
const { count, events } = liveSessionEvents(session, state.consumed ?? 0);
|
|
421
449
|
if ((state.consumed ?? 0) < count) {
|
|
422
|
-
applyUsageDelta(state,
|
|
450
|
+
applyUsageDelta(state, events);
|
|
423
451
|
state.consumed = count;
|
|
424
452
|
}
|
|
425
453
|
state.kind = "live";
|
|
@@ -428,7 +456,10 @@ export async function collectUsage(ctx) {
|
|
|
428
456
|
}
|
|
429
457
|
const persistence = ctx.get("sessionPersistence");
|
|
430
458
|
const persistedIds = new Set();
|
|
431
|
-
|
|
459
|
+
const canEnumeratePersisted = persistence !== void 0 && (
|
|
460
|
+
typeof persistence.list === "function" || typeof persistence.listSnapshots === "function"
|
|
461
|
+
);
|
|
462
|
+
if (canEnumeratePersisted) {
|
|
432
463
|
// Prefer the backend's opaque per-log revisions (no file I/O in the
|
|
433
464
|
// plugin, works for any backend that exposes listSnapshots).
|
|
434
465
|
let snapshots = null;
|
|
@@ -482,9 +513,16 @@ export async function collectUsage(ctx) {
|
|
|
482
513
|
}
|
|
483
514
|
cache.sessions[meta.id] = state;
|
|
484
515
|
}
|
|
516
|
+
} else if (persistence !== void 0) {
|
|
517
|
+
// DSH 0.1.2+ (rc.1): sessionPersistence exposes no session
|
|
518
|
+
// enumeration (list/listSnapshots are gone). Previously folded
|
|
519
|
+
// persisted days stay in the cache untouched — they are neither
|
|
520
|
+
// refreshed (no enumeration to walk) nor dropped (they still
|
|
521
|
+
// describe real past days).
|
|
522
|
+
ctx.logger.warn("token-heatmap: sessionPersistence exposes no list()/listSnapshots() enumeration on this DSH; persisted-only history will not refresh");
|
|
485
523
|
}
|
|
486
524
|
for (const id of Object.keys(cache.sessions)) {
|
|
487
|
-
if (!attached.has(id) && !persistedIds.has(id)) delete cache.sessions[id];
|
|
525
|
+
if (!attached.has(id) && !persistedIds.has(id) && canEnumeratePersisted) delete cache.sessions[id];
|
|
488
526
|
}
|
|
489
527
|
const byDay = new Map();
|
|
490
528
|
for (const state of Object.values(cache.sessions)) mergeInto(byDay, state.days);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kidli1412/dsh-token-heatmap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "DSH web plugin: GitHub-style daily token-usage heatmap on the new-session screen with a selectable calendar-year view, green/blue color schemes and a display switch (设置 → 插件 → 插件配置), plus today / this-month / all-time totals.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
"client": {
|
|
28
28
|
"platform": "web",
|
|
29
29
|
"inject": [
|
|
30
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
31
|
+
"@deepseek-ai/dsh-client-connection",
|
|
30
32
|
"@deepseek-ai/dsh-client-locale",
|
|
31
|
-
"@deepseek-ai/dsh-client-
|
|
32
|
-
"@deepseek-ai/dsh-client-ui-
|
|
33
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
33
35
|
]
|
|
34
36
|
},
|
|
35
37
|
"compatibility": {
|
|
@@ -42,7 +44,7 @@
|
|
|
42
44
|
},
|
|
43
45
|
"scripts": {
|
|
44
46
|
"check": "node --check lib/usage.js && node --check lib/config.js && node --check lib/index.js && node --check lib/client.js",
|
|
45
|
-
"test": "node scripts/smoke.mjs && node scripts/settings-smoke.mjs",
|
|
47
|
+
"test": "node scripts/smoke.mjs && node scripts/settings-smoke.mjs && node scripts/rc1-session-smoke.mjs",
|
|
46
48
|
"prepublishOnly": "npm run check && npm test"
|
|
47
49
|
},
|
|
48
50
|
"license": "MIT",
|