dsh-subusage 0.10.9 → 0.10.10

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
@@ -6,7 +6,7 @@
6
6
 
7
7
  > **English.** dsh-subusage shows subscription quota and balance for the AI providers you already use, as a pill next to the model selector in DeepSeek Harness. Provider switches and credentials live in one settings page, and other plugins or agents can read the same snapshot through a read-only quota API.
8
8
 
9
- [![npm version](https://img.shields.io/badge/npm-0.10.9-blue)](https://www.npmjs.com/package/dsh-subusage)
9
+ [![npm version](https://img.shields.io/badge/npm-0.10.10-blue)](https://www.npmjs.com/package/dsh-subusage)
10
10
  [![license](https://img.shields.io/badge/license-MIT-green)](#license--security--许可与安全)
11
11
  [![DSH](https://img.shields.io/badge/DSH-%3E%3D0.2.0--rc.1%20%3C0.3.0--0-informational)](#compatibility--兼容性)
12
12
 
package/lib/client.js CHANGED
@@ -389,13 +389,16 @@ window.__ModuleLoader__.load({
389
389
  }
390
390
  return worst;
391
391
  }
392
+ function remainingPercent(percent) {
393
+ return Math.round(Math.max(0, 100 - (Number(percent) || 0)) * 10) / 10;
394
+ }
392
395
  /** 药丸文案:永远答「还能用多少」(余),限额/连坐直说。多窗带窗口短名。 */
393
396
  function pillText(w, multi, t) {
394
397
  // 短标签走 locale(中文「周 / 月 / 日」,英文 1w / 1m / 1d),不让人猜 W 是哪个窗口。
395
398
  const short = multi ? `${t(KIND_SHORT[w.kind] ?? "srolling")} ` : "";
396
399
  if (w.status === "rate-limited" && !w.cascade) return `${short}${t("pillLimited")}`;
397
400
  if (w.status === "rate-limited") return `${short}${t("pillBlocked")}`;
398
- return `${short}${t("pillRemaining").replace("{p}", String(Math.round(Math.max(0, 100 - w.percent) * 10) / 10))}`;
401
+ return `${short}${t("pillRemaining").replace("{p}", String(remainingPercent(w.percent)))}`;
399
402
  }
400
403
  /** extras 标签:plan / account / balance 三类,未知类型回退为余额。 */
401
404
  function extraLabel(x, t) {
@@ -917,14 +920,23 @@ window.__ModuleLoader__.load({
917
920
  );
918
921
  }
919
922
 
923
+ function RemainingBar({ value, color, label }) {
924
+ const pct = Math.max(0, Math.min(100, Number(value) || 0));
925
+ return h("div", {
926
+ role: "progressbar",
927
+ "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": pct, "aria-label": label,
928
+ style: { width: "100%", height: 10, marginTop: 8, borderRadius: 6, background: "rgba(148,163,184,.22)", overflow: "hidden" }
929
+ }, h("div", { style: { width: `${pct}%`, height: "100%", borderRadius: 6, background: color, boxShadow: pct ? "inset 0 1px 0 rgba(255,255,255,.2)" : "none" } }));
930
+ }
920
931
  /**
921
- * 单窗口行(药丸弹层与设置页共用):徽标 + 已用% 主数字 + 进度条 + 明细行。
932
+ * 单窗口行(药丸弹层与设置页共用):徽标 + 余量% 主数字 + 进度条(满格=100% 剩余,随已用扣减)+ 明细行。
922
933
  * 明细分两行:用量/适用范围一行,重置时间一行。挤在一行时「重置于 …(还有 …)」
923
934
  * 会在窄弹层里被从中间折断,读起来像属性和数值分了家。
924
935
  */
925
936
  function UsageWindowRow({ w, t, getLocale, uncertain = false }) {
926
937
  const tier = uncertain && w.status !== "rate-limited" ? { icon: "?", badge: "badgeUnknown", color: "#b7791f", rank: 2 } : usageTier(w);
927
938
  const blocked = w.status === "rate-limited";
939
+ const left = blocked ? 0 : remainingPercent(w.percent);
928
940
  const usageLine = [
929
941
  w.detail && typeof w.detail.used === "number" && typeof w.detail.limit === "number" && w.detail.limit > 0
930
942
  ? t("detailUsed").replace("{used}", fmtTokens(w.detail.used)).replace("{limit}", fmtTokens(w.detail.limit)).replace("{unit}", w.detail.unit || "")
@@ -955,12 +967,9 @@ window.__ModuleLoader__.load({
955
967
  }, `${tier.icon} ${t(tier.badge)}`),
956
968
  h("span", { style: { flex: 1 } }),
957
969
  h("strong", { style: { fontSize: 13, color: numColor(w), whiteSpace: "nowrap" } },
958
- blocked ? t(tier.num) : t("numUsed").replace("{p}", String(w.percent)))
970
+ blocked ? t(tier.num) : t("pillRemaining").replace("{p}", String(remainingPercent(w.percent))))
959
971
  ),
960
- h("progress", {
961
- max: 100, value: Math.min(100, w.percent),
962
- style: { width: "100%", height: 6, marginTop: 6, accentColor: tier.color }
963
- }),
972
+ RemainingBar({ value: left, color: tier.color, label: blocked ? t(tier.num) : t("pillRemaining").replace("{p}", String(remainingPercent(w.percent))) }),
964
973
  usageLine || resetParts
965
974
  ? h("div", { style: { fontSize: 11, opacity: 0.7, marginTop: 4 } },
966
975
  usageLine ? h("div", { style: { overflowWrap: "anywhere" } }, usageLine) : null,
package/lib/index.js CHANGED
@@ -411,7 +411,7 @@ function volcFailure(action, error) {
411
411
  }
412
412
  async function fetchJson(fetcher, url, headers, lifetimeSignal, init = {}) {
413
413
  let response;
414
- try { response = await fetcher(url, { method: init.method ?? "GET", ...(init.body !== undefined ? { body: init.body } : {}), headers: { accept: "application/json", "user-agent": "dsh-subusage/0.10.9", ...headers }, signal: lifetimeSignal ? AbortSignal.any([AbortSignal.timeout(10000), lifetimeSignal]) : AbortSignal.timeout(10000), redirect: "manual" }); }
414
+ try { response = await fetcher(url, { method: init.method ?? "GET", ...(init.body !== undefined ? { body: init.body } : {}), headers: { accept: "application/json", "user-agent": "dsh-subusage/0.10.10", ...headers }, signal: lifetimeSignal ? AbortSignal.any([AbortSignal.timeout(10000), lifetimeSignal]) : AbortSignal.timeout(10000), redirect: "manual" }); }
415
415
  catch { throw failure("subusage/network", "网络请求失败或超时", true); }
416
416
  if (response.status >= 300 && response.status < 400 || response.status === 401 || response.status === 403) throw failure("subusage/auth", "登录或凭据已失效");
417
417
  if (!response.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-subusage",
3
- "version": "0.10.9",
3
+ "version": "0.10.10",
4
4
  "displayName": "订阅用量显示",
5
5
  "description": "显示 DeepSeek 官方余额、火山方舟(arkcli 官方 CLI 路由:Agent / Coding Plan 个人版与企业版席位,设置页合并为一组)、Z.ai(中国与国际)、Kimi、MiMo、OpenCode Go、Command Code、SuperGrok、Codex(ChatGPT 订阅,默认关闭)、MiniMax(中国)、Synthetic、NanoGPT、SiliconFlow、OpenRouter、Novita、Hyperbolic、DeepInfra、Chutes、Ollama Cloud、Vercel AI Gateway、ZenMux、LiteLLM 的订阅余量与余额;共享刷新与凭据管理,默认关闭 17 家。",
6
6
  "keywords": [