@lyk308/dsh-token-dashboard 0.1.0 → 0.1.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/README.md CHANGED
@@ -2,28 +2,34 @@
2
2
 
3
3
  [![awesome · DSH plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
4
4
 
5
- A DeepSeek Harness plugin that puts your **real-time account balance** and **token usage** on one dashboard. Local-first: reads your DSH session logs and the DeepSeek `/user/balance` API. No cloud account beyond your existing DeepSeek key.
5
+ A DeepSeek Harness plugin that puts your **real-time account balance** and **token usage** — including **cost estimation** — on one dashboard. Local-first: reads your DSH session logs and the DeepSeek `/user/balance` API. No cloud account beyond your existing DeepSeek key.
6
+
7
+ ## Screenshots
8
+
9
+ ![Dashboard](https://raw.githubusercontent.com/lyk308/dsh-token-dashboard/main/docs/screenshot.png)
10
+
11
+ ![Token usage & trend](https://raw.githubusercontent.com/lyk308/dsh-token-dashboard/main/docs/screenshot2.png)
6
12
 
7
13
  ## Features
8
14
 
9
15
  - 💰 **Account balance** — live balance from the DeepSeek official `/user/balance` API (CNY/USD aware), with force-refresh.
10
16
  - 📊 **Token usage** — Today / This month / All-time cards, plus request count, cache hit rate, and session count.
17
+ - 💵 **Cost estimation** — accurate DeepSeek pricing (peak/off-peak aware), per-model cost, and Today / This month / All-time spend.
11
18
  - 📈 **Usage distribution** — toggle between **by model** and **by workspace**, with a proportional share bar (top 8 + "other" aggregate). Percentages match the bar exactly.
19
+ - 📉 **Daily trend** — an SVG line chart of daily cost or tokens (30/90/180-day switch).
12
20
  - 🗓 **Activity heatmap** — 30 / 90 / 180 day switch, green-shade intensity maps token usage.
13
- - 🤖 **Model breakdown** — a table of Req / Input / Cache / Output per model.
21
+ - 🤖 **Model breakdown** — a table of Req / Input / Cache / Output / Cost per model.
14
22
 
15
23
  ## Installation
16
24
 
17
25
  This is a standard DSH bundle plugin, so install it with the official CLI:
18
26
 
19
27
  ```bash
20
- dsh plugin --profile web add <path-or-git-url-to-this-repo>
21
- ```
28
+ # From GitHub
29
+ dsh plugin --profile web add github:lyk308/dsh-token-dashboard
22
30
 
23
- If published to npm, you can also install by name:
24
-
25
- ```bash
26
- dsh plugin --profile web add dsh-token-dashboard
31
+ # From npm
32
+ dsh plugin --profile web add @lyk308/dsh-token-dashboard
27
33
  ```
28
34
 
29
35
  After installing, **refresh the web UI**. The dashboard appears under **Settings → 用量看板** (Usage Dashboard).
@@ -34,19 +40,22 @@ After installing, **refresh the web UI**. The dashboard appears under **Settings
34
40
 
35
41
  1. Open **Settings → 用量看板**.
36
42
  2. Refresh the server to load the latest data at any time.
37
- 3. Switch between **by model / by workspace** and the **30 / 90 / 180-day** heatmap ranges.
43
+ 3. Switch between **by model / by workspace**, the **30 / 90 / 180-day** heatmap ranges, and the **cost / token** trend metric.
38
44
 
39
45
  ## Configuration
40
46
 
41
47
  The plugin mostly works with no configuration. The host half resolves sensible defaults in `lib/index.js`:
48
+
42
49
  - `sessionsRoot` — defaults to `$DSH_HOME/sessions`.
43
50
  - `balanceCacheMs` — balance cache TTL (default 300000 ms = 5 min).
44
51
  - `sweepIntervalMs` — stats refresh interval (default 60000 ms).
45
52
 
53
+ > Cost estimation uses DeepSeek's official V4 pricing (CNY per 1,000,000 tokens) with peak/off-peak billing: peak = Mon–Fri 09:00–12:00 & 14:00–18:00. Prices are defined in `MODEL_PRICES` in `lib/index.js` and can be edited as DeepSeek changes them.
54
+
46
55
  ## Development
47
56
 
48
- - `lib/index.js` — host half: session scanning (multi-frame zstd), token aggregation, balance proxy.
49
- - `lib/client.js` — client half: the settings.section UI.
57
+ - `lib/index.js` — host half: session scanning (multi-frame zstd), token aggregation, cost estimation, balance proxy.
58
+ - `lib/client.js` — client half: the settings.section UI, trend chart, and cost display.
50
59
 
51
60
  Edit `lib/client.js` → refresh the page to see changes. Edit `lib/index.js` → restart the DSH web profile.
52
61
 
package/README.zh.md CHANGED
@@ -2,28 +2,34 @@
2
2
 
3
3
  [![awesome · DSH plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
4
4
 
5
- 一个 DeepSeek Harness 插件,把**实时账户余额**和 **Token 使用量**整合在一个看板上。本地优先:读取你的 DSH 会话日志 + DeepSeek 官方 `/user/balance` 接口,无需额外云端账号(沿用你已有的 DeepSeek key)。
5
+ 一个 DeepSeek Harness 插件,把**实时账户余额**、**Token 使用量**和**成本估算**整合在一个看板上。本地优先:读取你的 DSH 会话日志 + DeepSeek 官方 `/user/balance` 接口,无需额外云端账号(沿用你已有的 DeepSeek key)。
6
+
7
+ ## 效果预览
8
+
9
+ ![用量看板](https://raw.githubusercontent.com/lyk308/dsh-token-dashboard/main/docs/screenshot.png)
10
+
11
+ ![Token 用量与趋势](https://raw.githubusercontent.com/lyk308/dsh-token-dashboard/main/docs/screenshot2.png)
6
12
 
7
13
  ## 功能
8
14
 
9
15
  - 💰 **账户余额** — 通过 DeepSeek 官方 `/user/balance` 接口实时获取(自动识别 CNY/USD),支持强制刷新。
10
16
  - 📊 **Token 使用量** — 今日 / 本月 / 总计三卡,加请求数、缓存命中率、会话数。
17
+ - 💵 **成本估算** — 精确的 DeepSeek 定价(区分峰谷时段),按模型成本,以及 今日/本月/总计 花费。
11
18
  - 📈 **用量分布** — 在**按模型**和**按工作区**之间切换,带比例占比条(前 8 项 + 「其他」聚合),百分比与占比条完全一致。
19
+ - 📉 **每日趋势** — SVG 折线图展示每日成本或 Token(30 / 90 / 180 天切换)。
12
20
  - 🗓 **活跃度热力图** — 30 / 90 / 180 天切换,绿色深浅映射 Token 用量。
13
- - 🤖 **按模型明细** — 每个模型的 Req / Input / Cache / Output 表格。
21
+ - 🤖 **按模型明细** — 每个模型的 Req / Input / Cache / Output / Cost 表格。
14
22
 
15
23
  ## 安装
16
24
 
17
25
  这是一个标准 DSH bundle 插件,用官方 CLI 安装:
18
26
 
19
27
  ```bash
20
- dsh plugin --profile web add <此仓库的路径或 git 地址>
21
- ```
28
+ # GitHub 安装
29
+ dsh plugin --profile web add github:lyk308/dsh-token-dashboard
22
30
 
23
- 如果发布到 npm,也可按包名安装:
24
-
25
- ```bash
26
- dsh plugin --profile web add dsh-token-dashboard
31
+ # npm 安装
32
+ dsh plugin --profile web add @lyk308/dsh-token-dashboard
27
33
  ```
28
34
 
29
35
  安装后**刷新网页**即可。看板位于 **设置 → 用量看板**。
@@ -34,19 +40,22 @@ dsh plugin --profile web add dsh-token-dashboard
34
40
 
35
41
  1. 打开 **设置 → 用量看板**。
36
42
  2. 随时刷新服务器加载最新数据。
37
- 3. 切换 **按模型 / 按工作区**,以及 **30 / 90 / 180 天**热力图范围。
43
+ 3. 切换 **按模型 / 按工作区**、**30 / 90 / 180 天**热力图范围,以及 **成本 / Token** 趋势指标。
38
44
 
39
45
  ## 配置
40
46
 
41
47
  插件基本无需配置即可使用,host 半在 `lib/index.js` 里解析合理默认值:
48
+
42
49
  - `sessionsRoot` — 默认为 `$DSH_HOME/sessions`。
43
50
  - `balanceCacheMs` — 余额缓存时长(默认 300000 毫秒 = 5 分钟)。
44
51
  - `sweepIntervalMs` — 统计刷新间隔(默认 60000 毫秒)。
45
52
 
53
+ > 成本估算使用 DeepSeek 官方 V4 定价(元/百万 tokens),按峰谷计费:高峰 = 周一至周五 09:00-12:00、14:00-18:00。价格定义在 `lib/index.js` 的 `MODEL_PRICES`,可随 DeepSeek 调价而修改。
54
+
46
55
  ## 开发
47
56
 
48
- - `lib/index.js` — host 半:会话扫描(多帧 zstd)、Token 聚合、余额代理。
49
- - `lib/client.js` — client 半:settings.section 界面。
57
+ - `lib/index.js` — host 半:会话扫描(多帧 zstd)、Token 聚合、成本估算、余额代理。
58
+ - `lib/client.js` — client 半:settings.section 界面、趋势图、成本显示。
50
59
 
51
60
  改 `lib/client.js` → 刷新页面即可看到变化。改 `lib/index.js` → 重启 DSH web profile。
52
61
 
Binary file
Binary file
package/lib/client.js CHANGED
@@ -94,6 +94,7 @@ window.__ModuleLoader__.load({
94
94
  const [balanceLoading, setBalanceLoading] = useState(true);
95
95
  const [groupBy, setGroupBy] = useState("model"); // "model" | "workspace"
96
96
  const [range, setRange] = useState(90); // 30 | 90 | 180 days
97
+ const [metric, setMetric] = useState("cost"); // "cost" | "token"
97
98
 
98
99
  const loadStats = useCallback(async () => {
99
100
  try {
@@ -162,14 +163,18 @@ window.__ModuleLoader__.load({
162
163
  // both reflect "share of all usage".
163
164
  const groupSum = groupEntries.reduce((s, g) => s + (Number(g.total) || 0), 0);
164
165
 
165
- // heatmap: build days from byDay within range
166
+ // heatmap: build days from byDay within range. byDay entries are either
167
+ // {total, cost, ...} objects (new) or a bare number (legacy), so normalize.
166
168
  const byDay = stats.byDay || {};
167
169
  const todayD = new Date();
168
170
  const cells = [];
169
171
  for (let i = range - 1; i >= 0; i--) {
170
172
  const d = new Date(todayD); d.setDate(d.getDate() - i);
171
173
  const key = d.toISOString().slice(0, 10);
172
- cells.push({ key, val: Number(byDay[key]) || 0 });
174
+ const rec = byDay[key];
175
+ const total = (rec && typeof rec === "object") ? Number(rec.total) || 0 : Number(rec) || 0;
176
+ const cost = (rec && typeof rec === "object") ? Number(rec.cost) || 0 : 0;
177
+ cells.push({ key, val: total, cost });
173
178
  }
174
179
  const heatMax = Math.max(1, ...cells.map((c) => c.val));
175
180
  // group cells into weeks for the grid (7 per week)
@@ -234,18 +239,43 @@ window.__ModuleLoader__.load({
234
239
  jsx("div", { style: { width: "14px", height: "14px", borderRadius: "2px", background: heatColor(c.val, heatMax) }, title: c.key + ": " + fmt(c.val) }, c.key)
235
240
  ) });
236
241
 
242
+ // --- trend chart: a lightweight SVG polyline of daily metric over `range`.
243
+ // metric = "cost" or "token". Uses only inline SVG — no chart lib.
244
+ const trendValues = cells.map((c) => (metric === "cost" ? c.cost : c.val));
245
+ const tMax = Math.max(1, ...trendValues);
246
+ const TW = 320, TH = 80, PAD = 6;
247
+ let trendSvg;
248
+ if (trendValues.length <= 1) {
249
+ trendSvg = jsx("div", { style: { color: "var(--dsw-alias-label-secondary)", fontSize: "12px", padding: "8px 0" }, children: "数据不足" });
250
+ } else {
251
+ const step = TW / (trendValues.length - 1);
252
+ const pts = trendValues.map((v, i) => {
253
+ const x = PAD + i * step;
254
+ const y = TH - PAD - (v / tMax) * (TH - 2 * PAD);
255
+ return x.toFixed(1) + "," + y.toFixed(1);
256
+ }).join(" ");
257
+ const lastPt = pts.split(" ")[pts.split(" ").length - 1];
258
+ const lastV = trendValues[trendValues.length - 1];
259
+ trendSvg = jsxs("svg", { width: "100%", viewBox: "0 0 " + TW + " " + TH, style: { display: "block", maxHeight: "90px", width: "100%" }, children: [
260
+ jsx("polyline", { points: pts, fill: "none", stroke: "var(--dsw-alias-label-primary)", strokeWidth: "2", strokeLinejoin: "round", strokeLinecap: "round" }),
261
+ jsx("circle", { cx: lastPt.split(",")[0], cy: lastPt.split(",")[1], r: "3", fill: "var(--dsw-alias-label-primary)" }),
262
+ jsx("text", { x: "10", y: "12", fill: "var(--dsw-alias-label-tertiary)", fontSize: "10", children: (metric === "cost" ? ("¥" + fmtMoney(lastV)) : fmt(lastV)) })
263
+ ] });
264
+ }
265
+
237
266
  const modelTable = jsxs("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: "13px" }, children: [
238
267
  jsxs("thead", { children: [jsxs("tr", { children: [
239
268
  jsx("th", { style: thStyle, children: "模型" }), jsx("th", { style: thR, children: "Req" }),
240
269
  jsx("th", { style: thR, children: "Input" }), jsx("th", { style: thR, children: "Cache" }),
241
- jsx("th", { style: thR, children: "Output" })
270
+ jsx("th", { style: thR, children: "Output" }), jsx("th", { style: thR, children: "Cost" })
242
271
  ] })] }),
243
272
  jsxs("tbody", { children: modelRows.map((r) => jsxs("tr", { style: { borderTop: "1px solid var(--dsw-alias-border-l1)" }, children: [
244
273
  jsx("td", { style: tdStyle, children: r.key }),
245
274
  jsx("td", { style: tdR, children: r.req }),
246
275
  jsx("td", { style: tdR, children: fmt(r.input) }),
247
276
  jsx("td", { style: tdR, children: fmt(r.cacheRead) }),
248
- jsx("td", { style: tdR, children: fmt(r.output) })
277
+ jsx("td", { style: tdR, children: fmt(r.output) }),
278
+ jsx("td", { style: { ...tdR, color: "var(--dsw-alias-label-primary)", fontWeight: 600 }, children: "¥" + fmtMoney(r.cost || 0) })
249
279
  ] }, r.key)) })
250
280
  ] });
251
281
 
@@ -263,6 +293,15 @@ window.__ModuleLoader__.load({
263
293
  jsx("div", { style: SEC_TITLE, children: "📊 Token 使用量" }),
264
294
  statBar,
265
295
  jsxs("div", { style: { ...ROW, marginTop: "10px" }, children: [
296
+ jsx("span", { children: "今日花费" }), jsx("span", { ...MONO, children: "¥" + fmtMoney(stats.todayCost) })
297
+ ] }),
298
+ jsxs("div", { style: ROW, children: [
299
+ jsx("span", { children: "本月花费" }), jsx("span", { ...MONO, children: "¥" + fmtMoney(stats.thisMonthCost) })
300
+ ] }),
301
+ jsxs("div", { style: ROW, children: [
302
+ jsx("span", { children: "总花费" }), jsx("span", { ...MONO, children: "¥" + fmtMoney(stats.cost) })
303
+ ] }),
304
+ jsxs("div", { style: { ...ROW, marginTop: "6px", borderTop: "1px solid var(--dsw-alias-border-l1)", paddingTop: "6px" }, children: [
266
305
  jsx("span", { children: "请求数" }), jsx("span", { ...MONO, children: fmt(req) })
267
306
  ] }),
268
307
  jsxs("div", { style: ROW, children: [
@@ -291,6 +330,15 @@ window.__ModuleLoader__.load({
291
330
  heatGrid
292
331
  ] }),
293
332
 
333
+ // Trend chart
334
+ jsxs("div", { style: CARD, children: [
335
+ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "10px" }, children: [
336
+ jsx("div", { style: SEC_TITLE, children: "📉 趋势" }),
337
+ jsx(Seg, { options: [{ label: "成本", value: "cost" }, { label: "Token", value: "token" }], value: metric, onChange: setMetric })
338
+ ] }),
339
+ trendSvg
340
+ ] }),
341
+
294
342
  // Models table
295
343
  jsxs("div", { style: CARD, children: [
296
344
  jsx("div", { style: SEC_TITLE, children: "🤖 按模型" }),
package/lib/index.js CHANGED
@@ -21,6 +21,51 @@ import { once } from "node:events";
21
21
 
22
22
  const ZSTD_MAGIC = 0xfd2fb528; // bytes 28 b5 2f fd (little-endian)
23
23
 
24
+ // ---- DeepSeek V4 pricing (CNY per 1,000,000 tokens) ----
25
+ // Source: https://api-docs.deepseek.com/zh-cn/quick_start/pricing
26
+ // Prices are peak/off-peak. Off-peak = half of peak. Peak = Mon–Fri 09:00–12:00, 14:00–18:00.
27
+ // deepseek-v4-flash and deepseek-v4-flash-vision-exp share the same price.
28
+ const MODEL_PRICES = {
29
+ "deepseek-v4-flash": { cacheHit: [0.05, 0.10], cacheMiss: [1.5, 3.0], output: [4.5, 9.0] },
30
+ "deepseek-v4-flash-vision-exp": { cacheHit: [0.05, 0.10], cacheMiss: [1.5, 3.0], output: [4.5, 9.0] },
31
+ "deepseek-v4-pro": { cacheHit: [0.15, 0.30], cacheMiss: [4.5, 9.0], output: [13.5, 27.0] }
32
+ };
33
+ // Fallback for any model not in the table (use flash's price).
34
+ const FALLBACK_PRICE = MODEL_PRICES["deepseek-v4-flash"];
35
+
36
+ /**
37
+ * Whether the given timestamp falls in DeepSeek's peak period.
38
+ * Peak = Mon–Fri 09:00–12:00 and 14:00–18:00 (Beijing time / local device time).
39
+ * @param {number|null} timeMs - epoch milliseconds of the event.
40
+ * @returns {boolean}
41
+ */
42
+ function isPeakTime(timeMs) {
43
+ if (!timeMs) return false;
44
+ const d = new Date(timeMs);
45
+ const dow = d.getDay(); // 0=Sun .. 6=Sat
46
+ if (dow === 0 || dow === 6) return false; // weekends are off-peak
47
+ const mins = d.getHours() * 60 + d.getMinutes();
48
+ // 09:00-12:00 => 540-720 ; 14:00-18:00 => 840-1080
49
+ return (mins >= 540 && mins < 720) || (mins >= 840 && mins < 1080);
50
+ }
51
+
52
+ /**
53
+ * Compute the CNY cost of one usage event given its token breakdown + timestamp.
54
+ * @param {{input:number, output:number, cacheRead:number}} t
55
+ * @param {number|null} timeMs
56
+ * @param {string} model
57
+ * @returns {number}
58
+ */
59
+ function costOf(t, timeMs, model) {
60
+ const p = MODEL_PRICES[model] || FALLBACK_PRICE;
61
+ const peak = isPeakTime(timeMs) ? 1 : 0;
62
+ // cacheRead is charged at the cache-hit input price; reasoning tokens are billed
63
+ // as output per DeepSeek's model—fold reasoning into output for cost.
64
+ const inputCost = (t.cacheRead * p.cacheHit[peak] + (t.input) * p.cacheMiss[peak]) / 1e6;
65
+ const outputCost = ((t.output + t.reasoning || 0) * p.output[peak]) / 1e6;
66
+ return inputCost + outputCost;
67
+ }
68
+
24
69
  /**
25
70
  * Split a zstd buffer into its constituent frames. DSH writes multi-frame zstd
26
71
  * (one frame per chunk). We walk frame headers to find each frame boundary by
@@ -95,7 +140,7 @@ function zstdDecompressToText(buf) {
95
140
  }
96
141
 
97
142
  /** Normalize a token-usage event into our source-neutral shape. */
98
- function usagesFromEvent(obj, acc, currentModel) {
143
+ function usagesFromEvent(obj, acc, currentModel, timeMs) {
99
144
  if (!obj || typeof obj !== "object") return;
100
145
  const data = obj.data;
101
146
  if (!data) return;
@@ -122,13 +167,14 @@ function usagesFromEvent(obj, acc, currentModel) {
122
167
  const model = chunk.model || data.model || obj.model || currentModel || "unknown";
123
168
  if (model) {
124
169
  let m = acc.byModel[model];
125
- if (m === undefined) { m = acc.byModel[model] = { req: 0, input: 0, output: 0, cacheRead: 0, reasoning: 0, total: 0 }; }
170
+ if (m === undefined) { m = acc.byModel[model] = { req: 0, input: 0, output: 0, cacheRead: 0, reasoning: 0, total: 0, cost: 0 }; }
126
171
  m.req += 1;
127
172
  m.input += input;
128
173
  m.output += output;
129
174
  m.cacheRead += cacheRead;
130
175
  m.reasoning += reasoning;
131
176
  m.total += sum;
177
+ m.cost += costOf({ input, output, cacheRead, reasoning }, timeMs, model);
132
178
  }
133
179
  }
134
180
 
@@ -156,7 +202,7 @@ function findSessionLogs(root) {
156
202
  /** Aggregate token stats across all session logs under `root`. */
157
203
  function aggregateTokens(root) {
158
204
  const acc = {
159
- total: 0, input: 0, output: 0, cacheRead: 0, reasoning: 0,
205
+ total: 0, input: 0, output: 0, cacheRead: 0, reasoning: 0, cost: 0,
160
206
  events: 0, req: 0, cacheHits: 0, sessions: 0, files: 0,
161
207
  byModel: {}, byDay: {}, byWorkspace: {}
162
208
  };
@@ -204,22 +250,32 @@ function aggregateTokens(root) {
204
250
  const sum = inTok + outTok + cTok + rTok;
205
251
  const t = o.time ?? o.createdAt;
206
252
  const day = t ? new Date(t).toISOString().slice(0, 10) : null;
253
+ // cost of this single event (peak/off-peak aware, model-aware)
254
+ const cost = costOf({ input: inTok, output: outTok, cacheRead: cTok, reasoning: rTok }, t, currentModel || "unknown");
255
+ acc.cost += cost;
207
256
  if (day !== null) {
208
- acc.byDay[day] = (acc.byDay[day] || 0) + sum;
209
- if (day === todayKey) acc.today = (acc.today || 0) + sum;
210
- if (day.slice(0, 7) === monthKey) acc.thisMonth = (acc.thisMonth || 0) + sum;
257
+ let d = acc.byDay[day];
258
+ if (d === undefined) { d = acc.byDay[day] = { total: 0, input: 0, output: 0, cacheRead: 0, cost: 0 }; }
259
+ d.total += sum;
260
+ d.input += inTok;
261
+ d.output += outTok;
262
+ d.cacheRead += cTok;
263
+ d.cost += cost;
264
+ if (day === todayKey) { acc.today = (acc.today || 0) + sum; acc.todayCost = (acc.todayCost || 0) + cost; }
265
+ if (day.slice(0, 7) === monthKey) { acc.thisMonth = (acc.thisMonth || 0) + sum; acc.thisMonthCost = (acc.thisMonthCost || 0) + cost; }
211
266
  }
212
267
  // per-workspace broken-down counters
213
268
  let w = acc.byWorkspace[ws];
214
- if (w === undefined) { w = acc.byWorkspace[ws] = { req: 0, input: 0, output: 0, cacheRead: 0, reasoning: 0, total: 0 }; }
269
+ if (w === undefined) { w = acc.byWorkspace[ws] = { req: 0, input: 0, output: 0, cacheRead: 0, reasoning: 0, total: 0, cost: 0 }; }
215
270
  w.req += 1;
216
271
  w.input += inTok;
217
272
  w.output += outTok;
218
273
  w.cacheRead += cTok;
219
274
  w.reasoning += rTok;
220
275
  w.total += sum;
276
+ w.cost += cost;
221
277
  }
222
- usagesFromEvent(o, acc, currentModel);
278
+ usagesFromEvent(o, acc, currentModel, o.time ?? o.createdAt);
223
279
  }
224
280
  }
225
281
  return acc;
package/package.json CHANGED
@@ -1,49 +1,45 @@
1
- {
2
- "name": "@lyk308/dsh-token-dashboard",
3
- "version": "0.1.0",
4
- "description": "DeepSeek Harness 实时看板:账户余额 + Token 使用量(按模型/工作区/缓存命中),本地读取会话日志 + DeepSeek /user/balance。",
5
- "type": "module",
6
- "main": "lib/index.js",
7
- "exports": {
8
- ".": "./lib/index.js",
9
- "./client": "./lib/client.js",
10
- "./package.json": "./package.json"
11
- },
12
- "dsh": {
13
- "bundle": {
14
- "patch": "./cordis.patch.yml"
15
- },
16
- "client": {
17
- "inject": [
18
- "@deepseek-ai/dsh-client-runtime",
19
- "@deepseek-ai/dsh-client-locale",
20
- "@deepseek-ai/dsh-client-ui-slots",
21
- "@deepseek-ai/dsh-client-ui-primitives"
22
- ],
23
- "platform": "web"
24
- }
25
- },
26
- "files": [
27
- "lib/index.js",
28
- "lib/client.js",
29
- "cordis.patch.yml",
30
- "README.md",
31
- "README.zh.md",
32
- "LICENSE"
33
- ],
34
- "keywords": [
35
- "deepseek-harness",
36
- "dsh",
37
- "plugin",
38
- "token",
39
- "balance",
40
- "usage",
41
- "dashboard"
42
- ],
43
- "license": "MIT",
44
- "repository": {
45
- "type": "git",
46
- "url": "https://github.com/lyk308/dsh-token-dashboard.git"
47
- },
48
- "homepage": "https://github.com/lyk308/dsh-token-dashboard"
49
- }
1
+ {
2
+ "name": "@lyk308/dsh-token-dashboard",
3
+ "version": "0.1.2",
4
+ "description": "DeepSeek Harness 实时看板:账户余额 + Token 使用量(按模型/工作区/缓存命中),本地读取会话日志 + DeepSeek /user/balance。",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "exports": {
8
+ ".": "./lib/index.js",
9
+ "./client": "./lib/client.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "dsh": {
13
+ "bundle": {
14
+ "patch": "./cordis.patch.yml"
15
+ },
16
+ "client": {
17
+ "inject": [
18
+ "@deepseek-ai/dsh-client-runtime",
19
+ "@deepseek-ai/dsh-client-locale",
20
+ "@deepseek-ai/dsh-client-ui-slots",
21
+ "@deepseek-ai/dsh-client-ui-primitives"
22
+ ],
23
+ "platform": "web"
24
+ }
25
+ },
26
+ "files": [
27
+ "lib/index.js",
28
+ "lib/client.js",
29
+ "cordis.patch.yml",
30
+ "README.md",
31
+ "README.zh.md",
32
+ "LICENSE",
33
+ "docs"
34
+ ],
35
+ "keywords": [
36
+ "deepseek-harness",
37
+ "dsh",
38
+ "plugin",
39
+ "token",
40
+ "balance",
41
+ "usage",
42
+ "dashboard"
43
+ ],
44
+ "license": "MIT"
45
+ }