dsh-usage-spend 0.2.0 → 0.2.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/README.md CHANGED
@@ -2,16 +2,14 @@
2
2
 
3
3
  Shows the session's token usage and an **estimated spend** under the DSH composer, priced at DeepSeek's **peak and off-peak rates**, and appends the amount to the built-in per-turn usage action. Currency and exchange rate are configured on the **Plugins** page.
4
4
 
5
- One package is both the bundle (it declares the `usage-cost` row) and the feature itself, so installing it gives you a card on the Plugins page.
6
-
7
5
  ## What you get
8
6
 
9
- - **Composer usage pill**: `85.3M tok · ≈¥3.09 · cache hit 99.4%`, replacing the built-in `usage` row; a `峰` / `谷` badge after the amount says which window it was priced in.
7
+ - **Composer usage pill**: `85.3M tok · ≈¥3.09 · cache hit 99.4%`, replacing the built-in `usage` row.
10
8
  - **Click the card**: the header shows the exact token count and amount, followed by buckets for cache hits, uncached input, cache reads, cache writes, output and the billing window.
11
9
  - **Per-turn action**: the built-in `用量 85.3M tok` becomes `85.3M tok · ≈¥3.09`, priced at that turn's end time.
12
10
  - **Peak pricing**: Beijing time weekdays 09:00–12:00 and 14:00–18:00 cost double; everything else, weekends and public holidays included, is off-peak.
13
11
  - **Plugins page settings**: currency (CNY / USD / both), exchange rate, and whether to show the sidebar balance, with a read-only price table below the form.
14
- - **Sidebar balance**: `余额 ¥12.34` at the bottom of the sidebar, refreshed every 60 seconds or on click; the grant is in the tooltip; collapsed the sidebar shows a compact amount. Can be turned off.
12
+ - **Sidebar balance**: `余额 ¥12.34` at the bottom of the sidebar, refreshed every 60 seconds or on click; the grant is in the tooltip; collapsed the sidebar shows a compact amount. A `峰` / `谷` badge after the amount names the billing window, and the tooltip spells it out. Can be turned off.
15
13
 
16
14
  ## Install
17
15
 
@@ -63,7 +61,7 @@ How the numbers are produced:
63
61
  - Cache writes bill at the cache-miss input price, matching DeepSeek
64
62
  - **Per-turn amounts use that turn's end time**, so they are exact
65
63
  - **The session total uses the window in effect now**: the whole-log token projection carries no time dimension, so a session cannot be replayed turn by turn. Reopening an old session prices the total at the window you open it in while the per-turn amounts stay put
66
- - The `峰` / `谷` badge on the pill shows which window the total used
64
+ - The `峰` / `谷` badge at the end of the sidebar balance line names the window in effect. It is hidden when the sidebar is collapsed or the balance chip is turned off; the card's billing-window row still shows it
67
65
  - CNY is the base currency; USD is converted with the configured rate and only affects that column
68
66
  - Discounts, granted credit, Search/Fetch fees and the platform's actual bill are **not** included. This is an estimate only.
69
67
 
package/README.zh.md CHANGED
@@ -2,16 +2,14 @@
2
2
 
3
3
  在 DSH 的输入框下方显示本次会话的 token 用量与**估算花费**,按 DeepSeek 官方的**峰谷价**计价,并把金额补到内置的每轮用量按钮上。币种和汇率在 **插件** 页配置。
4
4
 
5
- 一个包同时是 bundle(声明 `usage-cost` 这一行)和功能本体,装上即出现插件页卡片。
6
-
7
5
  ## 功能
8
6
 
9
- - **底部用量 pill**:`85.3M tok · ≈¥3.09 · 缓存命中 99.4%`,替换内置的 `usage` 行;金额后面带 `峰` / `谷` 小标签,标明这一笔按哪档价格算。
7
+ - **底部用量 pill**:`85.3M tok · ≈¥3.09 · 缓存命中 99.4%`,替换内置的 `usage` 行。
10
8
  - **点击卡片**:标题行显示精确 token 数与金额,下面是缓存命中、未缓存输入、缓存读取、缓存写入、输出、计费时段。
11
9
  - **每轮按钮**:把内置的 `用量 85.3M tok` 改成 `85.3M tok · ≈¥3.09`,金额按该轮结束时间判断峰谷。
12
10
  - **峰谷计价**:北京时间工作日 9:00–12:00、14:00–18:00 为高峰(价目 ×2),其余时段含周末与法定节假日为空闲。
13
11
  - **插件页配置**:`币种`(人民币 / 美元 / 同时显示)、`汇率(1 USD = ? CNY)`、是否显示左侧栏余额,并在表单下方以只读表格展示当前单价表。
14
- - **左侧栏余额**:在侧栏底部显示 `余额 ¥12.34`,每 60 秒或点击时刷新;赠金放在 tooltip 里;折叠栏显示紧凑金额。可关闭。
12
+ - **左侧栏余额**:在侧栏底部显示 `余额 ¥12.34`,每 60 秒或点击时刷新;赠金放在 tooltip 里;折叠栏显示紧凑金额。金额后面带 `峰` / `谷` 小标签,标明当前的计费时段,悬停 tooltip 里有完整说明。可关闭。
15
13
 
16
14
  ## 安装
17
15
 
@@ -63,7 +61,7 @@ dsh plugin --profile <profile> add dsh-usage-spend
63
61
  - 缓存写入按缓存未命中的输入价计费,与官方一致
64
62
  - **单轮金额按该轮结束时间**判断峰谷,是精确的
65
63
  - **会话总额按当前时段**估算:整份 token 统计没有时间维度,无法回溯每一轮分别落在哪个时段。所以隔天回看老会话时,总额按你打开它时的时段算,而每轮按钮上的金额不变
66
- - 底部 pill 上的 `峰` / `谷` 小标签就是当前用的哪档
64
+ - 左侧栏余额那行末尾的 `峰` / `谷` 小标签就是当前用的哪档;侧栏收起、或关掉余额显示时看不到它,卡片里的「计费时段」仍然在
67
65
  - 币种默认人民币;选美元时按配置的汇率把人民币换算过去,汇率只影响美元那一栏
68
66
  - **不包含**折扣、赠送额度、Search/Fetch 费用或平台实际账单,只用于估算
69
67
 
package/lib/client.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * dsh-usage-cost — browser half.
2
+ * dsh-usage-spend — browser half.
3
3
  *
4
4
  * Contributes:
5
5
  * - `conversation.composer.dock` id `usage` at priority -1, replacing the
@@ -17,7 +17,7 @@
17
17
  * an optional localStorage override. No network request is made for pricing.
18
18
  */
19
19
  window.__ModuleLoader__.load({
20
- id: "dsh-usage-cost",
20
+ id: "dsh-usage-spend",
21
21
  factory: (require) => {
22
22
  var module = { exports: {} };
23
23
  var exports = module.exports;
@@ -27,8 +27,8 @@ window.__ModuleLoader__.load({
27
27
  const primitives = require("@deepseek-ai/dsh-client-ui-primitives");
28
28
  const h = React.createElement;
29
29
 
30
- const NS = "dsh-usage-cost";
31
- const STYLE_ID = "dsh-usage-cost/styles";
30
+ const NS = "dsh-usage-spend";
31
+ const STYLE_ID = "dsh-usage-spend/styles";
32
32
  const ENTRY_ID = "usage-cost";
33
33
  const CONFIG_KEY = "dsh-usage-spend#usage-cost";
34
34
  const CURRENCY_KEY = "dsh.cost.currency";
@@ -40,8 +40,8 @@ window.__ModuleLoader__.load({
40
40
  const zh = {
41
41
  "pill.tokens": "{count} tok",
42
42
  "pill.cacheHit": "缓存命中 {percent}%",
43
- "pill.peak": "峰",
44
- "pill.offPeak": "谷",
43
+ "window.peak": "峰",
44
+ "window.offPeak": "谷",
45
45
  "dialog.title": "Token 用量",
46
46
  "dialog.cacheHit": "缓存命中",
47
47
  "dialog.input": "未缓存输入",
@@ -65,6 +65,8 @@ window.__ModuleLoader__.load({
65
65
  "config.showBalance": "显示左侧栏余额",
66
66
  "config.showBalanceHint": "关闭后不显示余额 chip,也不会请求账号余额。",
67
67
  "balance.label": "余额",
68
+ "balance.windowPeak": "当前按高峰价估算(表价 ×2)",
69
+ "balance.windowOffPeak": "当前按空闲价估算",
68
70
  "balance.loading": "读取中…",
69
71
  "balance.unavailable": "暂不可用",
70
72
  "balance.signedOut": "未登录",
@@ -83,8 +85,8 @@ window.__ModuleLoader__.load({
83
85
  const en = {
84
86
  "pill.tokens": "{count} tok",
85
87
  "pill.cacheHit": "cache hit {percent}%",
86
- "pill.peak": "peak",
87
- "pill.offPeak": "off-peak",
88
+ "window.peak": "peak",
89
+ "window.offPeak": "off-peak",
88
90
  "dialog.title": "Token usage",
89
91
  "dialog.cacheHit": "Cache hit",
90
92
  "dialog.input": "Uncached input",
@@ -108,6 +110,8 @@ window.__ModuleLoader__.load({
108
110
  "config.showBalance": "Show the sidebar balance",
109
111
  "config.showBalanceHint": "When off, the balance chip is hidden and no balance request is made.",
110
112
  "balance.label": "Balance",
113
+ "balance.windowPeak": "Estimated at peak rates (twice the card)",
114
+ "balance.windowOffPeak": "Estimated at off-peak rates",
111
115
  "balance.loading": "Loading…",
112
116
  "balance.unavailable": "Unavailable",
113
117
  "balance.signedOut": "Not signed in",
@@ -135,7 +139,8 @@ window.__ModuleLoader__.load({
135
139
  ".dshuc_label{text-overflow:ellipsis;min-width:0;overflow:hidden}",
136
140
  ".dshuc_sep{color:var(--dsw-alias-separator-primary);margin:0 6px}",
137
141
  ".dshuc_money{color:var(--dsw-alias-label-secondary)}",
138
- ".dshuc_window{color:var(--dsw-alias-label-tertiary);border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xs,4px);padding:0 3px;margin-left:4px;font-size:10px;line-height:14px}",
142
+ ".dshuc_window{flex:none;color:var(--dsw-alias-label-tertiary);border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xs,4px);padding:0 3px;font-size:10px;line-height:14px}",
143
+ ".dshuc_balance[data-wide=false] .dshuc_window{display:none}",
139
144
  ".dshuc_panel{z-index:1100;box-sizing:border-box;width:max-content;min-width:min(300px,calc(100vw - 24px),var(--dsh-anchored-max-width,100vw));max-width:min(440px,calc(100vw - 24px),var(--dsh-anchored-max-width,100vw));border-radius:var(--dsw-radius-lg);background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;max-height:var(--dsh-anchored-max-height,none);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border:0;padding:16px;font-size:12px;line-height:18px;position:fixed;overflow:hidden auto}",
140
145
  ".dshuc_title{color:var(--dsw-alias-label-primary);justify-content:space-between;gap:16px;margin-bottom:8px;font-weight:500;display:flex}",
141
146
  ".dshuc_titleRule{border-top:.5px solid var(--dsw-alias-border-l2);margin-bottom:10px}",
@@ -178,7 +183,7 @@ window.__ModuleLoader__.load({
178
183
  if (typeof document === "undefined") return;
179
184
  if (document.querySelector('style[data-plugin-css="' + STYLE_ID + '"]') !== null) return;
180
185
  const tag = document.createElement("style");
181
- tag.dataset.plugin = "dsh-usage-cost";
186
+ tag.dataset.plugin = "dsh-usage-spend";
182
187
  tag.dataset.pluginCss = STYLE_ID;
183
188
  tag.textContent = CSS;
184
189
  document.head.appendChild(tag);
@@ -342,7 +347,7 @@ window.__ModuleLoader__.load({
342
347
  if (forms === undefined || typeof forms.get !== "function") return;
343
348
  const detach = configStore.attach(forms.get(ENTRY_ID));
344
349
  if (typeof scope.effect === "function") {
345
- scope.effect(() => detach, "dsh-usage-cost: config form");
350
+ scope.effect(() => detach, "dsh-usage-spend: config form");
346
351
  }
347
352
  });
348
353
  } catch {
@@ -687,6 +692,7 @@ window.__ModuleLoader__.load({
687
692
 
688
693
  function BalanceChip({ wide, balance, t }) {
689
694
  const config = useConfig();
695
+ const peak = isPeak(Date.now());
690
696
  const state = React.useSyncExternalStore(balance.subscribe, balance.getSnapshot, balance.getSnapshot);
691
697
  if (!config.showBalance) return null;
692
698
  const wallets = state.wallets ?? [];
@@ -707,11 +713,13 @@ window.__ModuleLoader__.load({
707
713
  } else {
708
714
  value = "…";
709
715
  }
716
+ const windowText = t(peak ? "balance.windowPeak" : "balance.windowOffPeak");
710
717
  const tooltip =
711
718
  state.status === "ready"
712
719
  ? [
713
720
  t("balance.tooltip", { wallets: wallets.length > 0 ? walletListText(wallets) : formatMoney(0, "CNY") }),
714
721
  bonusWallets.length > 0 ? t("balance.bonus", { wallets: walletListText(bonusWallets) }) : null,
722
+ windowText,
715
723
  t("balance.refresh"),
716
724
  ]
717
725
  .filter((part) => part !== null)
@@ -740,6 +748,7 @@ window.__ModuleLoader__.load({
740
748
  h("span", { className: "dshuc_balanceGlyph", "aria-hidden": true }, symbol),
741
749
  h("span", { className: "dshuc_balanceLabel" }, t("balance.label")),
742
750
  h("span", { className: "dshuc_balanceValue" }, value),
751
+ wide ? h("span", { className: "dshuc_window" }, t(peak ? "window.peak" : "window.offPeak")) : null,
743
752
  ),
744
753
  },
745
754
  );
@@ -787,9 +796,9 @@ window.__ModuleLoader__.load({
787
796
  };
788
797
  const access = scope.remoteAccess;
789
798
  if (access !== undefined && typeof access.whenAccess === "function") {
790
- scope.effect(() => access.whenAccess("account/watch", register), "dsh-usage-cost: balance");
799
+ scope.effect(() => access.whenAccess("account/watch", register), "dsh-usage-spend: balance");
791
800
  } else {
792
- scope.effect(() => register(), "dsh-usage-cost: balance");
801
+ scope.effect(() => register(), "dsh-usage-spend: balance");
793
802
  }
794
803
  });
795
804
  } catch {
@@ -891,15 +900,7 @@ window.__ModuleLoader__.load({
891
900
  const cacheHit = cacheHitPercent(usage);
892
901
  const money = moneyText(cny, config.currency, config.usdToCny);
893
902
  const titleMoney = moneyText(cny, config.currency, config.usdToCny, true);
894
- const moneyNode =
895
- money === null
896
- ? null
897
- : h(
898
- "span",
899
- { className: "dshuc_money" },
900
- money,
901
- h("span", { className: "dshuc_window" }, t(peak ? "pill.peak" : "pill.offPeak")),
902
- );
903
+ const moneyNode = money === null ? null : h("span", { className: "dshuc_money" }, money);
903
904
  const cacheHitText = cacheHit === null ? null : t("pill.cacheHit", { percent: cacheHit });
904
905
 
905
906
  const segments = [t("pill.tokens", { count: formatTokens(total) })];
@@ -1281,7 +1282,7 @@ window.__ModuleLoader__.load({
1281
1282
  ru: en,
1282
1283
  pt: en,
1283
1284
  }),
1284
- "dsh-usage-cost: dictionaries",
1285
+ "dsh-usage-spend: dictionaries",
1285
1286
  );
1286
1287
  injectStyles();
1287
1288
  attachConfig(ctx);
@@ -1321,7 +1322,7 @@ window.__ModuleLoader__.load({
1321
1322
  );
1322
1323
  }
1323
1324
 
1324
- exports.name = "dsh-usage-cost";
1325
+ exports.name = "dsh-usage-spend";
1325
1326
  exports.inject = ["slots", "locale"];
1326
1327
  exports.apply = apply;
1327
1328
  /** Test-only internals (loaded through the stub module factory). */
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Host loader entry for dsh-usage-cost.
2
+ * Host loader entry for dsh-usage-spend.
3
3
  *
4
4
  * The feature is browser-only: the usage projection, the composer dock and the
5
5
  * turn-footer amount all live in the client runtime, and pricing is a local
@@ -15,6 +15,6 @@ export const Config = z.object({
15
15
  showBalance: z.boolean().default(true).volatile(),
16
16
  });
17
17
 
18
- export const name = "dsh-usage-cost";
18
+ export const name = "dsh-usage-spend";
19
19
 
20
20
  export function apply() {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-usage-spend",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Session token usage and estimated spend for DSH, priced with DeepSeek peak and off-peak rates: a composer usage pill, the amount appended to the built-in per-turn usage action, and a settings form for currency and exchange rate.",
5
5
  "type": "module",
6
6
  "license": "MIT",