@duke-dsh-plugins/dsh-token-stats 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.
Files changed (2) hide show
  1. package/client.js +77 -23
  2. package/package.json +1 -1
package/client.js CHANGED
@@ -72,7 +72,7 @@ window.__ModuleLoader__.load({
72
72
  .ts-legend-val{color:var(--dsw-alias-label-secondary);white-space:nowrap}
73
73
  .ts-heat{stroke:var(--dsw-alias-border-l1);stroke-width:0.5}
74
74
  .ts-quota{position:relative;display:inline-flex}
75
- .ts-quota-pop{position:absolute;bottom:calc(100% + 8px);right:0;width:230px;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;box-shadow:var(--dsw-elevation-soft,0 6px 24px rgba(0,0,0,0.18));padding:10px 12px;display:flex;flex-direction:column;gap:6px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);z-index:60;pointer-events:none;animation:ts-pop-in .12s ease-out}
75
+ .ts-quota-pop{position:absolute;bottom:calc(100% + 8px);right:0;min-width:230px;max-width:340px;width:max-content;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;box-shadow:var(--dsw-elevation-soft,0 6px 24px rgba(0,0,0,0.18));padding:10px 12px;display:flex;flex-direction:column;gap:6px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);z-index:60;pointer-events:none;animation:ts-pop-in .12s ease-out}
76
76
  .ts-quota-pop-head{display:flex;align-items:center;justify-content:space-between;gap:12px;font-weight:600;font-size:12px}
77
77
  .ts-quota-pop-sub{color:var(--dsw-alias-label-secondary);font-size:11px}
78
78
  .ts-quota-pop-row{display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--dsw-alias-label-secondary)}
@@ -754,6 +754,15 @@ window.__ModuleLoader__.load({
754
754
  ];
755
755
  }
756
756
 
757
+ /** 悬浮窗标题行(QuotaHoverCard 与加载态共用)。 */
758
+ function quotaPopHead(label) {
759
+ return React.createElement(
760
+ "div", { className: "ts-quota-pop-head" },
761
+ React.createElement("span", null, label),
762
+ React.createElement("span", { className: "ts-quota-pop-sub" }, "套餐余额"),
763
+ );
764
+ }
765
+
757
766
  /** 自定义悬停面板 (替代原生 title): 结构化展示余额/窗口用量 + 进度条. */
758
767
  function QuotaHoverCard(props) {
759
768
  const label = quotaProviderLabel(props.provider);
@@ -761,10 +770,12 @@ window.__ModuleLoader__.load({
761
770
  if (props.ok && props.display) {
762
771
  const d = props.display;
763
772
  if (typeof d.balanceText === "string" && d.balanceText) {
764
- // mimo 的 balanceText 可能是「本地用量」也可能是官方「剩余 X%」。
773
+ // mimo 的 balanceText 可能是「本地用量」(今日/7d 自带说明)也可能是官方「剩余 X%」。
765
774
  const cap =
766
775
  props.provider === "mimo"
767
- ? (typeof d.weeklyPct === "number" ? "官方剩余用量" : "本地用量(近 7 天 / 今日)")
776
+ ? (typeof d.weeklyPct === "number" || typeof d.fiveHrPct === "number"
777
+ ? "官方剩余用量"
778
+ : "本地用量")
768
779
  : "账户余额" + (d.currency ? " (" + d.currency + ")" : "");
769
780
  rows.push(
770
781
  React.createElement(
@@ -774,15 +785,29 @@ window.__ModuleLoader__.load({
774
785
  ),
775
786
  );
776
787
  }
777
- // mimo 官方读数只有一个 Token Plan 窗口(/api/v1/user/usage 的
778
- // percent 是「剩余」,host 已换算成已用 %);本地用量模式没有窗口。
779
- const windows =
780
- props.provider === "mimo"
781
- ? [["Token Plan", d.weeklyPct, d.weeklyResetsIn]]
782
- : [
783
- ["5h 窗口", d.fiveHrPct, d.fiveHrResetsIn],
784
- ["7d 窗口", d.weeklyPct, d.weeklyResetsIn],
785
- ];
788
+ // mimo 窗口行:新端点 /api/v1/user/usage(percent=剩余,host 换算成已用%)
789
+ // 把单一窗口放在 weeklyPct;旧端点 tokenPlan/usage 回退路径把套餐已用放在
790
+ // fiveHrPct(套餐与月度同额度时 weeklyPct 被去重为 null)。两个都认,缺一
791
+ // 不跳过——v1.7.0 只读 weeklyPct,导致旧端点形状下悬浮窗只剩标题(无进度条
792
+ // 无重置时间,设置页却有)。两者都在且数值不同时显示两行(套餐 + 本月)。
793
+ let windows;
794
+ if (props.provider === "mimo") {
795
+ windows = [];
796
+ if (typeof d.fiveHrPct === "number") {
797
+ windows.push(["Token Plan", d.fiveHrPct, d.fiveHrResetsIn]);
798
+ }
799
+ if (typeof d.weeklyPct === "number") {
800
+ const dup = windows.length > 0 && Math.abs(d.weeklyPct - d.fiveHrPct) < 0.5;
801
+ if (!dup) {
802
+ windows.push([windows.length > 0 ? "本月" : "Token Plan", d.weeklyPct, d.weeklyResetsIn]);
803
+ }
804
+ }
805
+ } else {
806
+ windows = [
807
+ ["5h 窗口", d.fiveHrPct, d.fiveHrResetsIn],
808
+ ["7d 窗口", d.weeklyPct, d.weeklyResetsIn],
809
+ ];
810
+ }
786
811
  for (const w of windows) {
787
812
  if (typeof w[1] !== "number") continue;
788
813
  rows.push(
@@ -800,18 +825,19 @@ window.__ModuleLoader__.load({
800
825
  ),
801
826
  );
802
827
  }
828
+ if (rows.length === 0) {
829
+ // 兜底:display 在但没有任何可渲染字段时也给一行,悬浮窗不能只剩标题。
830
+ rows.push(
831
+ React.createElement(
832
+ "div", { key: "empty", className: "ts-quota-pop-row" },
833
+ React.createElement("span", null, "暂无配额数据"),
834
+ ),
835
+ );
836
+ }
803
837
  } else {
804
838
  rows.push(React.createElement("div", { key: "err", className: "ts-quota-pop-err" }, props.message || "获取失败"));
805
839
  }
806
- return React.createElement(
807
- "div", { className: "ts-quota-pop" },
808
- React.createElement(
809
- "div", { className: "ts-quota-pop-head" },
810
- React.createElement("span", null, label),
811
- React.createElement("span", { className: "ts-quota-pop-sub" }, "套餐余额"),
812
- ),
813
- ...rows,
814
- );
840
+ return React.createElement("div", { className: "ts-quota-pop" }, quotaPopHead(label), ...rows);
815
841
  }
816
842
 
817
843
  function QuotaReadout(props) {
@@ -920,11 +946,22 @@ window.__ModuleLoader__.load({
920
946
  : null;
921
947
 
922
948
  if (!state.loaded) {
949
+ // 加载态也渲染悬浮窗(此前只有一行 ···,悬停时面板完全不出)。
923
950
  return React.createElement(
924
951
  "div",
925
952
  Object.assign({ className: "ts-quota", style: containerStyle }, hoverProps),
926
953
  React.createElement("span", { style: { fontWeight: 500 } }, label),
927
954
  React.createElement("span", { style: { opacity: 0.6, fontSize: 10 } }, "···"),
955
+ hover
956
+ ? React.createElement(
957
+ "div", { className: "ts-quota-pop" },
958
+ quotaPopHead(label),
959
+ React.createElement(
960
+ "div", { className: "ts-quota-pop-row" },
961
+ React.createElement("span", null, "加载中…"),
962
+ ),
963
+ )
964
+ : null,
928
965
  );
929
966
  }
930
967
 
@@ -981,8 +1018,24 @@ window.__ModuleLoader__.load({
981
1018
  // mimo 复用 balanceText 承载两种读数:本地用量(无窗口百分比)或
982
1019
  // 官方「剩余 X%」(有 weeklyPct),所以标题不能写死「账户余额」。
983
1020
  const head = p === "mimo"
984
- ? (typeof d.weeklyPct === "number" ? "Token Plan" : "本地用量")
1021
+ ? ((typeof d.weeklyPct === "number" || typeof d.fiveHrPct === "number") ? "Token Plan" : "本地用量")
985
1022
  : "账户余额" + (d.currency ? " · " + d.currency : "");
1023
+ // 官方读数(新端点)把单一窗口放在 weeklyPct:数值下面补进度条 + 重置时间,
1024
+ // 与其它 provider 的窗口卡片及悬浮窗对齐。
1025
+ const planWindow = p === "mimo" && typeof d.weeklyPct === "number"
1026
+ ? React.createElement(
1027
+ "div", { style: { display: "flex", flexDirection: "column", gap: 4 } },
1028
+ React.createElement(
1029
+ "div", { className: "ts-quota-pop-row" },
1030
+ React.createElement("span", null, "Token Plan已用"),
1031
+ React.createElement("b", null, d.weeklyPct + "%" + (d.weeklyResetsIn ? " · " + d.weeklyResetsIn : "")),
1032
+ ),
1033
+ React.createElement(
1034
+ "div", { className: "ts-quota-card-bar" },
1035
+ React.createElement("i", { style: { width: Math.max(0, Math.min(100, d.weeklyPct)) + "%" } }),
1036
+ ),
1037
+ )
1038
+ : null;
986
1039
  return React.createElement(
987
1040
  "div", { className: "ts-card ts-quota-card" },
988
1041
  React.createElement(
@@ -991,12 +1044,13 @@ window.__ModuleLoader__.load({
991
1044
  React.createElement("span", { className: "ts-quota-card-status" }, head),
992
1045
  ),
993
1046
  React.createElement("div", { className: "ts-quota-card-value" }, d.balanceText),
1047
+ planWindow,
994
1048
  );
995
1049
  }
996
1050
  const windows =
997
1051
  p === "mimo"
998
1052
  ? [
999
- ["套餐已用", d.fiveHrPct, d.fiveHrResetsIn],
1053
+ ["套餐", d.fiveHrPct, d.fiveHrResetsIn],
1000
1054
  ["本月总额度", d.weeklyPct, d.weeklyResetsIn],
1001
1055
  ]
1002
1056
  : [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duke-dsh-plugins/dsh-token-stats",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "Token usage statistics for DeepSeek Harness (7/30-day per-model charts + yearly heatmap) plus an inline coding-plan balance/quota readout in the composer (minimax/deepseek/kimi/openrouter/zhipu/mimo; mimo falls back to local usage since MiMo exposes no API-key quota API).",
5
5
  "repository": {
6
6
  "type": "git",