@jxgame2020/dsh-token-quota 0.1.35 → 0.1.36

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/lib/client.js CHANGED
@@ -7,6 +7,14 @@ window.__ModuleLoader__.load({
7
7
  let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
9
  let react = require("react");
10
+ //#region lib/types/types.js
11
+ /**
12
+ * Provider route keys the host knows how to query for account balance. A
13
+ * directory provider outside this list renders as "not integrated for query"
14
+ * in the balance window.
15
+ */
16
+ const TOKEN_QUOTA_BALANCE_PROVIDERS = ["deepseek"];
17
+ //#endregion
10
18
  //#region lib/types/client/store.js
11
19
  /**
12
20
  * Token-quota panel store: the shared, remount-surviving view state. The
@@ -40,6 +48,9 @@ window.__ModuleLoader__.load({
40
48
  order: [],
41
49
  notes: [],
42
50
  notesLoaded: false,
51
+ balances: [],
52
+ balanceEnabled: true,
53
+ balancePollMinutes: 5,
43
54
  musicEnabled: false,
44
55
  musicVolume: .5,
45
56
  musicStyle: "pentatonic",
@@ -92,6 +103,13 @@ window.__ModuleLoader__.load({
92
103
  d.notes = notes;
93
104
  d.notesLoaded = true;
94
105
  },
106
+ setBalances: (d, balances) => {
107
+ d.balances = balances;
108
+ },
109
+ setBalanceSettings: (d, enabled, pollMinutes) => {
110
+ d.balanceEnabled = enabled;
111
+ d.balancePollMinutes = pollMinutes;
112
+ },
95
113
  setMusicEnabled: (d, enabled) => {
96
114
  d.musicEnabled = enabled;
97
115
  },
@@ -105,7 +123,7 @@ window.__ModuleLoader__.load({
105
123
  d.musicOnlyCurrentSession = only;
106
124
  },
107
125
  setUpgrade: (d, upgrade) => {
108
- const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.35" ? upgrade : null;
126
+ const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.36" ? upgrade : null;
109
127
  if (d.upgrade === null || d.upgrade.latestVersion !== normalized?.latestVersion) d.upgradeDismissed = false;
110
128
  d.upgrade = normalized;
111
129
  },
@@ -225,7 +243,7 @@ window.__ModuleLoader__.load({
225
243
  }
226
244
  //#endregion
227
245
  //#region \0dsh-css:/Users/jxgame/Desktop/works/deepseek-harness-package/dsh-token-quota/packages/token-quota/src/client/TokenQuotaPanel.module.css.mjs
228
- const css = ".NPLLIq_panel{box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);pointer-events:auto;z-index:40;opacity:1;border-radius:12px;flex-direction:column;width:320px;max-height:min(72vh,560px);transition:opacity .18s;display:flex;position:fixed;top:56px;right:12px;overflow:hidden;box-shadow:0 8px 28px #0000002e}.NPLLIq_panelDim{opacity:.55}.NPLLIq_panelDimStrong{opacity:.3}.NPLLIq_header{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:flex-start;gap:8px;padding:10px 12px;display:flex}.NPLLIq_header:active{cursor:grabbing}.NPLLIq_headerText{flex-direction:column;gap:2px;min-width:0;display:flex}.NPLLIq_title{color:var(--dsw-alias-label-primary);align-items:baseline;gap:6px;font-size:13px;font-weight:600;display:flex}.NPLLIq_version{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:10px;font-weight:500}.NPLLIq_versionNew{color:var(--dsw-alias-status-warning-foreground,#b56900);background:var(--dsw-alias-status-warning-background,#fff6d7);cursor:default;border-radius:4px;padding:1px 6px}.NPLLIq_subtitle{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_notesBar{flex-wrap:wrap;align-items:center;gap:4px;margin-top:4px;display:flex}.NPLLIq_noteChip{width:20px;height:20px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:5px;flex:none;justify-content:center;align-items:center;padding:0;font-size:11px;line-height:1;transition:color .12s,border-color .12s;display:inline-flex}.NPLLIq_noteChip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.NPLLIq_noteChipOpen{color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteNew{width:22px;height:20px;color:var(--dsw-alias-label-secondary);border:1px dashed var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:5px;flex:none;justify-content:center;align-items:center;padding:0;transition:color .12s,border-color .12s;display:inline-flex;position:relative}.NPLLIq_noteNew:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteNew:disabled{opacity:.4;cursor:not-allowed}.NPLLIq_noteNewPlus{color:inherit;font-size:10px;font-weight:700;line-height:1;position:absolute;bottom:-2px;right:-1px}.NPLLIq_noteWin{z-index:60;pointer-events:auto;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;display:flex;position:fixed;overflow:hidden;box-shadow:0 8px 24px #00000038}.NPLLIq_noteWinCollapsed{height:auto!important}.NPLLIq_noteWinBar{background:var(--dsw-alias-bg-layer-1);border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;flex:none;align-items:center;gap:4px;padding:4px 6px;display:flex}.NPLLIq_noteWinBar:active{cursor:grabbing}.NPLLIq_noteWinGripBar{color:var(--dsw-alias-label-secondary);opacity:.7;flex:none;font-size:10px}.NPLLIq_noteWinTitleText{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;padding:1px 2px;font-size:11px;font-weight:600;overflow:hidden}.NPLLIq_noteWinTitle{min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border:1px solid #0000;border-radius:4px;outline:none;flex:1;padding:1px 2px;font-size:11px;font-weight:600}.NPLLIq_noteWinTitle:hover{border-color:var(--dsw-alias-border-l1)}.NPLLIq_noteWinTitle:focus{background:var(--dsw-alias-bg-overlay);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteWinBtn{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:1;display:inline-flex}.NPLLIq_noteWinBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.NPLLIq_noteWinText{box-sizing:border-box;width:100%;min-height:0;color:var(--dsw-alias-label-primary);resize:none;background:0 0;border:none;outline:none;flex:1;padding:6px 8px;font-family:inherit;font-size:11px;line-height:1.5}.NPLLIq_noteWinResize{cursor:nwse-resize;background:linear-gradient(135deg, transparent 0 45%, var(--dsw-alias-border-l2) 45% 55%, transparent 55% 70%, var(--dsw-alias-border-l2) 70% 80%, transparent 80%);width:14px;height:14px;position:absolute;bottom:0;right:0}.NPLLIq_noteMenuBackdrop{z-index:100;pointer-events:auto;position:fixed;inset:0}.NPLLIq_noteMenu{z-index:101;pointer-events:auto;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;min-width:96px;padding:4px;display:flex;position:fixed;box-shadow:0 8px 24px #0000003d}.NPLLIq_noteMenuItem{text-align:left;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:5px;padding:5px 8px;font-size:11px}.NPLLIq_noteMenuItem:hover{background:var(--dsw-alias-bg-layer-2)}.NPLLIq_collapse{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_collapse:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_body{padding:4px 0;overflow-y:auto}.NPLLIq_row{border-bottom:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:6px;padding:8px 12px;display:flex}.NPLLIq_rowHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.NPLLIq_rowDrag{cursor:grab;color:var(--dsw-alias-label-secondary);user-select:none;border-radius:4px;flex:none;margin-right:2px;padding:2px 3px;font-size:11px;line-height:1}.NPLLIq_rowDrag:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_rowDrag:active{cursor:grabbing}.NPLLIq_rowDragging{opacity:.45}.NPLLIq_rowDropTarget{box-shadow:inset 0 2px 0 var(--dsw-alias-brand-primary)}.NPLLIq_rowName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;align-items:center;gap:6px;font-size:12px;font-weight:500;display:inline-flex;overflow:hidden}.NPLLIq_currentBadge{color:var(--dsw-alias-state-success-primary);border:1px solid var(--dsw-alias-state-success-primary);border-radius:8px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_rowMeta{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.NPLLIq_bar{background:var(--dsw-alias-bg-layer-1);border-radius:3px;height:6px;overflow:hidden}.NPLLIq_fillIdle{background:var(--dsw-alias-brand-primary);height:100%;transition:width .2s}.NPLLIq_fillWarn{background:var(--dsw-alias-state-warn-primary);height:100%;transition:width .2s}.NPLLIq_fillOver{background:var(--dsw-alias-state-error-primary);height:100%;transition:width .2s}.NPLLIq_controls{align-items:center;gap:6px;display:flex}.NPLLIq_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);min-width:0;color:var(--dsw-alias-label-primary);border-radius:6px;flex:1;padding:4px 8px;font-size:11px}.NPLLIq_input::placeholder{color:var(--dsw-alias-label-secondary)}.NPLLIq_save,.NPLLIq_switch{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px;font-size:11px}.NPLLIq_save:hover,.NPLLIq_switch:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}.NPLLIq_switch:disabled{opacity:.5;cursor:default}.NPLLIq_notice,.NPLLIq_noticeError{color:var(--dsw-alias-label-secondary);padding:10px 12px;font-size:12px}.NPLLIq_noticeError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_tab{background:var(--dsw-alias-brand-primary);border:1px solid var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay);pointer-events:auto;cursor:pointer;z-index:90;border-radius:10px;align-items:center;gap:6px;padding:9px 14px;font-size:12px;font-weight:600;display:inline-flex;position:fixed;top:56px;right:12px;box-shadow:0 6px 20px #00000040}.NPLLIq_tab:hover{filter:brightness(1.08)}.NPLLIq_tabIcon{font-size:12px;line-height:1}.NPLLIq_tabLabel{white-space:nowrap}.NPLLIq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.NPLLIq_settingsBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_settingsBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_settingsBtnActive{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-2,#0000000f);box-shadow:inset 0 0 0 1px var(--dsw-alias-brand-primary);font-weight:700}.NPLLIq_selectBtn{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border-radius:6px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_selectBtn:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_gearBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;margin-left:6px;padding:0 2px;font-size:12px;line-height:1}.NPLLIq_gearBtn:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_fullNotice{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;margin:6px 12px;padding:8px 10px;font-size:12px}.NPLLIq_upgradeBanner{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-divider-1,#0000001a);border-radius:8px;margin:6px 12px;padding:10px 30px 10px 10px;font-size:12px;position:relative}@keyframes NPLLIq_upgradeBannerFlash{0%,to{border-color:var(--dsw-alias-divider-1,#0000001a);box-shadow:0 0 #f0a02000}50%{border-color:var(--dsw-alias-status-warning-foreground,#b56900);box-shadow:0 0 0 5px #f0a02073}}.NPLLIq_upgradeBannerFlash{border-color:var(--dsw-alias-status-warning-foreground,#b56900);animation:.6s ease-in-out 4 NPLLIq_upgradeBannerFlash}.NPLLIq_upgradeBannerText{margin-bottom:6px;font-weight:600}.NPLLIq_upgradeCommands{flex-direction:column;gap:4px;display:flex}.NPLLIq_upgradeCommandRow{align-items:center;gap:6px;display:flex}.NPLLIq_upgradeCommand{background:var(--dsw-alias-bg-layer-2,#0000000a);white-space:nowrap;border-radius:4px;flex:1;min-width:0;padding:4px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;overflow-x:auto}.NPLLIq_copyBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;flex:none;padding:3px 8px;font-size:11px;transition:transform 80ms,background .12s,color .12s}.NPLLIq_copyBtn:hover{background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_copyBtn:active{transform:scale(.92)}.NPLLIq_copyBtnDone{background:var(--dsw-alias-status-success-background,#14963c1f);border-color:var(--dsw-alias-status-success-foreground,#0a7d32);color:var(--dsw-alias-status-success-foreground,#0a7d32);font-weight:600}.NPLLIq_upgradeHint{color:var(--dsw-alias-label-secondary);margin-top:6px;font-size:11px}.NPLLIq_upgradeClose{width:20px;height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;font-size:16px;line-height:1;position:absolute;top:4px;right:6px}.NPLLIq_upgradeClose:hover{background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary)}.NPLLIq_checkUpdatesRow{justify-content:space-between;align-items:center;gap:12px;display:flex}.NPLLIq_checkUpdatesLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.NPLLIq_checkUpdatesLabel input{margin:0}.NPLLIq_checkUpdatesLabel input[type=range]{min-width:90px;accent-color:var(--dsw-alias-brand-primary);flex:1}.NPLLIq_checkUpdatesLabel select{background:var(--dsw-alias-bg-layer-2,#0000000a);min-width:90px;color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-divider-1,#00000026);border-radius:4px;flex:1;padding:2px 4px;font-size:12px}.NPLLIq_checkBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-align:center;border-radius:4px;flex:none;min-width:72px;padding:4px 10px;font-size:12px}.NPLLIq_checkBtn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_checkBtn:disabled{opacity:.6;cursor:default}.NPLLIq_checkErrorHint{color:var(--dsw-alias-state-error-primary,#c00);background:var(--dsw-alias-state-error-background,#ff00000f);border:1px solid var(--dsw-alias-state-error-border,#b4000040);word-break:break-all;border-radius:6px;margin-top:8px;padding:6px 8px;font-size:11px;line-height:1.4}.NPLLIq_dialog{z-index:100;pointer-events:auto;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;gap:12px;width:430px;max-width:94vw;max-height:80vh;padding:14px;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%);box-shadow:0 8px 28px #00000040}.NPLLIq_dialogTabs{border-bottom:1px solid var(--dsw-alias-divider-1,#00000014);gap:2px;margin:-6px -14px 0;padding:0 14px;display:flex}.NPLLIq_dialogTab{appearance:none;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:6px 12px 8px;font-size:12px}.NPLLIq_dialogTab:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_dialogTabActive{color:var(--dsw-alias-brand-primary);border-bottom-color:var(--dsw-alias-brand-primary);font-weight:600}.NPLLIq_settingsDialog{height:min(560px,80vh)}.NPLLIq_dialogTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.NPLLIq_dialogSection{flex-direction:column;gap:6px;display:flex}.NPLLIq_dialogLabel{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500}.NPLLIq_monitorHint{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_dialogHint{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:11px;line-height:1.4}.NPLLIq_monitorList{flex-direction:column;gap:2px;max-height:180px;display:flex;overflow-y:auto}.NPLLIq_monitorRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:2px 4px;font-size:12px;display:flex}.NPLLIq_monitorRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_monitorName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.NPLLIq_radioRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:3px 4px;font-size:12px;display:flex}.NPLLIq_radioRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_dialogActions{justify-content:flex-end;gap:6px;display:flex}.NPLLIq_dialogBtn,.NPLLIq_dialogBtnPrimary{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:6px;padding:4px 12px;font-size:11px}.NPLLIq_dialogBtn{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.NPLLIq_dialogBtnPrimary{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay)}.NPLLIq_dialogHeader{z-index:2;background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:center;gap:8px;margin:-14px -14px 0;padding:14px 14px 8px;display:flex;position:sticky;top:-14px}.NPLLIq_dialogHeader:active{cursor:grabbing}.NPLLIq_dialogClose{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;font-size:18px;line-height:1;display:flex}.NPLLIq_dialogClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_resetRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.NPLLIq_resetSelect{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:6px;padding:3px 6px;font-size:12px}.NPLLIq_logTable{border-collapse:collapse;width:100%;font-size:11px}.NPLLIq_logTable th{text-align:left;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);padding:4px 6px;font-weight:500}.NPLLIq_logTable td{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);font-variant-numeric:tabular-nums;padding:4px 6px}.NPLLIq_logDayCol{white-space:nowrap;color:var(--dsw-alias-label-secondary)}.NPLLIq_logModelCol{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.NPLLIq_logUsedCol{text-align:right}.NPLLIq_logDialog{gap:0;width:380px;max-height:min(72vh,480px);padding:0}.NPLLIq_logHeader{background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 8px;display:flex}.NPLLIq_logHeader:active{cursor:grabbing}.NPLLIq_logScroll{flex:1;min-height:0;padding:0 14px 14px;overflow:auto}.NPLLIq_logToolbar{flex:1;align-items:center;gap:6px;display:flex}.NPLLIq_logSearch{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);min-width:0;color:var(--dsw-alias-label-primary);border-radius:4px;flex:1;padding:3px 6px;font-size:11px}.NPLLIq_logSearch:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}.NPLLIq_logClearBtn{border:1px solid var(--dsw-alias-state-error-border,#b400004d);color:var(--dsw-alias-state-error-primary,#c00);cursor:pointer;white-space:nowrap;background:0 0;border-radius:4px;flex:none;padding:3px 8px;font-size:11px}.NPLLIq_logClearBtn:hover{background:var(--dsw-alias-state-error-background,#ff00000f)}.NPLLIq_logPager{border-top:1px solid var(--dsw-alias-divider-1,#00000014);background:var(--dsw-alias-bg-overlay);color:var(--dsw-alias-label-secondary);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 14px;font-size:11px;display:flex}.NPLLIq_logPagerInfo{white-space:nowrap}.NPLLIq_logPagerControls{align-items:center;gap:4px;display:flex}.NPLLIq_logPagerBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:24px;height:24px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;font-size:13px;line-height:1}.NPLLIq_logPagerBtn:disabled{opacity:.4;cursor:default}.NPLLIq_logPagerPages{text-align:center;min-width:50px;color:var(--dsw-alias-label-secondary)}.NPLLIq_logPageSizeSelect{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;padding:2px 4px;font-size:11px}.NPLLIq_dialogOverlay{z-index:100001;pointer-events:auto;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.NPLLIq_logClearDialog{gap:0;width:320px;padding:16px}.NPLLIq_dialogBody{color:var(--dsw-alias-label-secondary);margin:6px 0 10px;font-size:12px;line-height:1.5}.NPLLIq_logClearDate{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:100%;color:var(--dsw-alias-label-primary);border-radius:6px;margin-bottom:12px;padding:6px 8px;font-size:13px}.NPLLIq_logClearDate:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}";
246
+ const css = ".NPLLIq_panel{box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);pointer-events:auto;z-index:40;opacity:1;border-radius:12px;flex-direction:column;width:320px;max-height:min(72vh,560px);transition:opacity .18s;display:flex;position:fixed;top:56px;right:12px;overflow:hidden;box-shadow:0 8px 28px #0000002e}.NPLLIq_panelDim{opacity:.55}.NPLLIq_panelDimStrong{opacity:.3}.NPLLIq_header{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:flex-start;gap:8px;padding:10px 12px;display:flex}.NPLLIq_header:active{cursor:grabbing}.NPLLIq_headerText{flex-direction:column;gap:2px;min-width:0;display:flex}.NPLLIq_title{color:var(--dsw-alias-label-primary);align-items:baseline;gap:6px;font-size:13px;font-weight:600;display:flex}.NPLLIq_version{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:10px;font-weight:500}.NPLLIq_versionNew{color:var(--dsw-alias-status-warning-foreground,#b56900);background:var(--dsw-alias-status-warning-background,#fff6d7);cursor:default;border-radius:4px;padding:1px 6px}.NPLLIq_subtitle{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_notesBar{flex-wrap:wrap;align-items:center;gap:4px;margin-top:4px;display:flex}.NPLLIq_noteChip{width:20px;height:20px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:5px;flex:none;justify-content:center;align-items:center;padding:0;font-size:11px;line-height:1;transition:color .12s,border-color .12s;display:inline-flex}.NPLLIq_noteChip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.NPLLIq_noteChipOpen{color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteNew{width:22px;height:20px;color:var(--dsw-alias-label-secondary);border:1px dashed var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:5px;flex:none;justify-content:center;align-items:center;padding:0;transition:color .12s,border-color .12s;display:inline-flex;position:relative}.NPLLIq_noteNew:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteNew:disabled{opacity:.4;cursor:not-allowed}.NPLLIq_noteNewPlus{color:inherit;font-size:10px;font-weight:700;line-height:1;position:absolute;bottom:-2px;right:-1px}.NPLLIq_noteWin{z-index:60;pointer-events:auto;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;display:flex;position:fixed;overflow:hidden;box-shadow:0 8px 24px #00000038}.NPLLIq_noteWinCollapsed{height:auto!important}.NPLLIq_noteWinBar{background:var(--dsw-alias-bg-layer-1);border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;flex:none;align-items:center;gap:4px;padding:4px 6px;display:flex}.NPLLIq_noteWinBar:active{cursor:grabbing}.NPLLIq_noteWinGripBar{color:var(--dsw-alias-label-secondary);opacity:.7;flex:none;font-size:10px}.NPLLIq_noteWinTitleText{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;padding:1px 2px;font-size:11px;font-weight:600;overflow:hidden}.NPLLIq_noteWinTitle{min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border:1px solid #0000;border-radius:4px;outline:none;flex:1;padding:1px 2px;font-size:11px;font-weight:600}.NPLLIq_noteWinTitle:hover{border-color:var(--dsw-alias-border-l1)}.NPLLIq_noteWinTitle:focus{background:var(--dsw-alias-bg-overlay);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteWinBtn{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:1;display:inline-flex}.NPLLIq_noteWinBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.NPLLIq_noteWinText{box-sizing:border-box;width:100%;min-height:0;color:var(--dsw-alias-label-primary);resize:none;background:0 0;border:none;outline:none;flex:1;padding:6px 8px;font-family:inherit;font-size:11px;line-height:1.5}.NPLLIq_noteWinResize{cursor:nwse-resize;background:linear-gradient(135deg, transparent 0 45%, var(--dsw-alias-border-l2) 45% 55%, transparent 55% 70%, var(--dsw-alias-border-l2) 70% 80%, transparent 80%);width:14px;height:14px;position:absolute;bottom:0;right:0}.NPLLIq_noteMenuBackdrop{z-index:100;pointer-events:auto;position:fixed;inset:0}.NPLLIq_noteMenu{z-index:101;pointer-events:auto;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;min-width:96px;padding:4px;display:flex;position:fixed;box-shadow:0 8px 24px #0000003d}.NPLLIq_noteMenuItem{text-align:left;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:5px;padding:5px 8px;font-size:11px}.NPLLIq_noteMenuItem:hover{background:var(--dsw-alias-bg-layer-2)}.NPLLIq_collapse{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_collapse:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_body{padding:4px 0;overflow-y:auto}.NPLLIq_row{border-bottom:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:6px;padding:8px 12px;display:flex}.NPLLIq_rowHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.NPLLIq_rowDrag{cursor:grab;color:var(--dsw-alias-label-secondary);user-select:none;border-radius:4px;flex:none;margin-right:2px;padding:2px 3px;font-size:11px;line-height:1}.NPLLIq_rowDrag:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_rowDrag:active{cursor:grabbing}.NPLLIq_rowDragging{opacity:.45}.NPLLIq_rowDropTarget{box-shadow:inset 0 2px 0 var(--dsw-alias-brand-primary)}.NPLLIq_rowName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;align-items:center;gap:6px;font-size:12px;font-weight:500;display:inline-flex;overflow:hidden}.NPLLIq_currentBadge{color:var(--dsw-alias-state-success-primary);border:1px solid var(--dsw-alias-state-success-primary);border-radius:8px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_rowMeta{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.NPLLIq_bar{background:var(--dsw-alias-bg-layer-1);border-radius:3px;height:6px;overflow:hidden}.NPLLIq_fillIdle{background:var(--dsw-alias-brand-primary);height:100%;transition:width .2s}.NPLLIq_fillWarn{background:var(--dsw-alias-state-warn-primary);height:100%;transition:width .2s}.NPLLIq_fillOver{background:var(--dsw-alias-state-error-primary);height:100%;transition:width .2s}.NPLLIq_controls{align-items:center;gap:6px;display:flex}.NPLLIq_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);min-width:0;color:var(--dsw-alias-label-primary);border-radius:6px;flex:1;padding:4px 8px;font-size:11px}.NPLLIq_input::placeholder{color:var(--dsw-alias-label-secondary)}.NPLLIq_save,.NPLLIq_switch{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px;font-size:11px}.NPLLIq_save:hover,.NPLLIq_switch:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}.NPLLIq_switch:disabled{opacity:.5;cursor:default}.NPLLIq_balanceToggle{margin-left:auto}.NPLLIq_balanceToggleOpen{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_balanceWin{z-index:1199;background:var(--dsw-alias-bg-layer-2);width:280px;color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);pointer-events:auto;border-radius:12px;flex-direction:column;display:flex;position:fixed;overflow:hidden;box-shadow:0 8px 24px #00000029}.NPLLIq_balanceWinHeader{border-bottom:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-3);user-select:none;align-items:center;gap:6px;padding:6px 8px 6px 12px;display:flex}.NPLLIq_balanceWinTitle{flex:1;font-size:12px;font-weight:600;line-height:1}.NPLLIq_balanceWinBody{font-variant-numeric:tabular-nums;padding:6px 10px 10px;font-size:11px}.NPLLIq_balanceRowHeader{border-bottom:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);grid-template-columns:1fr auto 20px;align-items:center;gap:6px;padding:3px 2px;font-weight:600;display:grid}.NPLLIq_balanceSortBtn{all:unset;cursor:pointer;color:inherit;border-radius:4px;padding:1px 2px;font-size:10px;font-weight:600}.NPLLIq_balanceSortBtn:hover{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_balanceRefreshAll{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:1;display:inline-flex}.NPLLIq_balanceRefreshAll:hover:not(:disabled){color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_balanceRefreshAll:disabled{opacity:.4;cursor:not-allowed}.NPLLIq_balanceRow{grid-template-columns:1fr auto 20px;align-items:center;gap:6px;padding:3px 2px;display:grid}.NPLLIq_balanceRow+.NPLLIq_balanceRow{border-top:1px dashed var(--dsw-alias-border-l1)}.NPLLIq_balanceRowName{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-weight:500;overflow:hidden}.NPLLIq_balanceRowValue{text-align:right;font-weight:600}.NPLLIq_balanceRowRefresh{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:1;display:inline-flex}.NPLLIq_balanceRowRefresh:hover:not(:disabled){color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_balanceRowRefresh:disabled{opacity:.4;cursor:not-allowed}.NPLLIq_balanceValueOk{color:var(--dsw-alias-label-primary)}.NPLLIq_balanceValueLow{color:var(--dsw-alias-state-warn-primary)}.NPLLIq_balanceValueError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_balanceStateHint{color:var(--dsw-alias-label-secondary);font-style:italic;font-weight:500}.NPLLIq_balanceStateError{color:var(--dsw-alias-state-error-primary);font-weight:500}.NPLLIq_balanceLastLine{border-top:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);margin-top:6px;padding-top:5px;font-size:10px}.NPLLIq_balanceBar{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:center;gap:6px;padding:5px 12px;font-size:11px;display:flex}.NPLLIq_balanceBarText{text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:6px;min-width:0;font-weight:600;display:inline-flex;overflow:hidden}.NPLLIq_balanceBarBadge{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-1);border-radius:4px;flex:none;padding:0 4px;font-size:10px;font-weight:600}.NPLLIq_balanceBarDim{color:var(--dsw-alias-label-secondary);font-weight:500}.NPLLIq_balanceBarLow{color:var(--dsw-alias-state-warn-primary)}.NPLLIq_balanceBarError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_balanceBarRefresh{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:1;display:inline-flex}.NPLLIq_balanceBarRefresh:hover:not(:disabled){color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_balanceBarRefresh:disabled{opacity:.4;cursor:not-allowed}.NPLLIq_notice,.NPLLIq_noticeError{color:var(--dsw-alias-label-secondary);padding:10px 12px;font-size:12px}.NPLLIq_noticeError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_tab{background:var(--dsw-alias-brand-primary);border:1px solid var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay);pointer-events:auto;cursor:pointer;z-index:90;border-radius:10px;align-items:center;gap:6px;padding:9px 14px;font-size:12px;font-weight:600;display:inline-flex;position:fixed;top:56px;right:12px;box-shadow:0 6px 20px #00000040}.NPLLIq_tab:hover{filter:brightness(1.08)}.NPLLIq_tabIcon{font-size:12px;line-height:1}.NPLLIq_tabLabel{white-space:nowrap}.NPLLIq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.NPLLIq_settingsBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_settingsBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_settingsBtnActive{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-2,#0000000f);box-shadow:inset 0 0 0 1px var(--dsw-alias-brand-primary);font-weight:700}.NPLLIq_selectBtn{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border-radius:6px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_selectBtn:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_gearBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;margin-left:6px;padding:0 2px;font-size:12px;line-height:1}.NPLLIq_gearBtn:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_fullNotice{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;margin:6px 12px;padding:8px 10px;font-size:12px}.NPLLIq_upgradeBanner{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-divider-1,#0000001a);border-radius:8px;margin:6px 12px;padding:10px 30px 10px 10px;font-size:12px;position:relative}@keyframes NPLLIq_upgradeBannerFlash{0%,to{border-color:var(--dsw-alias-divider-1,#0000001a);box-shadow:0 0 #f0a02000}50%{border-color:var(--dsw-alias-status-warning-foreground,#b56900);box-shadow:0 0 0 5px #f0a02073}}.NPLLIq_upgradeBannerFlash{border-color:var(--dsw-alias-status-warning-foreground,#b56900);animation:.6s ease-in-out 4 NPLLIq_upgradeBannerFlash}.NPLLIq_upgradeBannerText{margin-bottom:6px;font-weight:600}.NPLLIq_upgradeCommands{flex-direction:column;gap:4px;display:flex}.NPLLIq_upgradeCommandRow{align-items:center;gap:6px;display:flex}.NPLLIq_upgradeCommand{background:var(--dsw-alias-bg-layer-2,#0000000a);white-space:nowrap;border-radius:4px;flex:1;min-width:0;padding:4px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;overflow-x:auto}.NPLLIq_copyBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;flex:none;padding:3px 8px;font-size:11px;transition:transform 80ms,background .12s,color .12s}.NPLLIq_copyBtn:hover{background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_copyBtn:active{transform:scale(.92)}.NPLLIq_copyBtnDone{background:var(--dsw-alias-status-success-background,#14963c1f);border-color:var(--dsw-alias-status-success-foreground,#0a7d32);color:var(--dsw-alias-status-success-foreground,#0a7d32);font-weight:600}.NPLLIq_upgradeHint{color:var(--dsw-alias-label-secondary);margin-top:6px;font-size:11px}.NPLLIq_upgradeClose{width:20px;height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;font-size:16px;line-height:1;position:absolute;top:4px;right:6px}.NPLLIq_upgradeClose:hover{background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary)}.NPLLIq_checkUpdatesRow{justify-content:space-between;align-items:center;gap:12px;display:flex}.NPLLIq_checkUpdatesLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.NPLLIq_checkUpdatesLabel input{margin:0}.NPLLIq_checkUpdatesLabel input[type=range]{min-width:90px;accent-color:var(--dsw-alias-brand-primary);flex:1}.NPLLIq_checkUpdatesLabel select{background:var(--dsw-alias-bg-layer-2,#0000000a);min-width:90px;color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-divider-1,#00000026);border-radius:4px;flex:1;padding:2px 4px;font-size:12px}.NPLLIq_checkBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-align:center;border-radius:4px;flex:none;min-width:72px;padding:4px 10px;font-size:12px}.NPLLIq_checkBtn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_checkBtn:disabled{opacity:.6;cursor:default}.NPLLIq_checkErrorHint{color:var(--dsw-alias-state-error-primary,#c00);background:var(--dsw-alias-state-error-background,#ff00000f);border:1px solid var(--dsw-alias-state-error-border,#b4000040);word-break:break-all;border-radius:6px;margin-top:8px;padding:6px 8px;font-size:11px;line-height:1.4}.NPLLIq_dialog{z-index:100;pointer-events:auto;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;gap:12px;width:430px;max-width:94vw;max-height:80vh;padding:14px;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%);box-shadow:0 8px 28px #00000040}.NPLLIq_dialogTabs{border-bottom:1px solid var(--dsw-alias-divider-1,#00000014);gap:2px;margin:-6px -14px 0;padding:0 14px;display:flex}.NPLLIq_dialogTab{appearance:none;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:6px 12px 8px;font-size:12px}.NPLLIq_dialogTab:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_dialogTabActive{color:var(--dsw-alias-brand-primary);border-bottom-color:var(--dsw-alias-brand-primary);font-weight:600}.NPLLIq_settingsDialog{height:min(560px,80vh)}.NPLLIq_dialogTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.NPLLIq_dialogSection{flex-direction:column;gap:6px;display:flex}.NPLLIq_dialogLabel{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500}.NPLLIq_monitorHint{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_dialogHint{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:11px;line-height:1.4}.NPLLIq_monitorList{flex-direction:column;gap:2px;max-height:180px;display:flex;overflow-y:auto}.NPLLIq_monitorRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:2px 4px;font-size:12px;display:flex}.NPLLIq_monitorRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_monitorName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.NPLLIq_radioRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:3px 4px;font-size:12px;display:flex}.NPLLIq_radioRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_dialogActions{justify-content:flex-end;gap:6px;display:flex}.NPLLIq_dialogBtn,.NPLLIq_dialogBtnPrimary{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:6px;padding:4px 12px;font-size:11px}.NPLLIq_dialogBtn{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.NPLLIq_dialogBtnPrimary{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay)}.NPLLIq_dialogHeader{z-index:2;background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:center;gap:8px;margin:-14px -14px 0;padding:14px 14px 8px;display:flex;position:sticky;top:-14px}.NPLLIq_dialogHeader:active{cursor:grabbing}.NPLLIq_dialogClose{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;font-size:18px;line-height:1;display:flex}.NPLLIq_dialogClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_resetRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.NPLLIq_resetSelect{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:6px;padding:3px 6px;font-size:12px}.NPLLIq_logTable{border-collapse:collapse;width:100%;font-size:11px}.NPLLIq_logTable th{text-align:left;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);padding:4px 6px;font-weight:500}.NPLLIq_logTable td{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);font-variant-numeric:tabular-nums;padding:4px 6px}.NPLLIq_logDayCol{white-space:nowrap;color:var(--dsw-alias-label-secondary)}.NPLLIq_logModelCol{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.NPLLIq_logUsedCol{text-align:right}.NPLLIq_logDialog{gap:0;width:380px;max-height:min(72vh,480px);padding:0}.NPLLIq_logHeader{background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 8px;display:flex}.NPLLIq_logHeader:active{cursor:grabbing}.NPLLIq_logScroll{flex:1;min-height:0;padding:0 14px 14px;overflow:auto}.NPLLIq_logToolbar{flex:1;align-items:center;gap:6px;display:flex}.NPLLIq_logSearch{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);min-width:0;color:var(--dsw-alias-label-primary);border-radius:4px;flex:1;padding:3px 6px;font-size:11px}.NPLLIq_logSearch:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}.NPLLIq_logClearBtn{border:1px solid var(--dsw-alias-state-error-border,#b400004d);color:var(--dsw-alias-state-error-primary,#c00);cursor:pointer;white-space:nowrap;background:0 0;border-radius:4px;flex:none;padding:3px 8px;font-size:11px}.NPLLIq_logClearBtn:hover{background:var(--dsw-alias-state-error-background,#ff00000f)}.NPLLIq_logPager{border-top:1px solid var(--dsw-alias-divider-1,#00000014);background:var(--dsw-alias-bg-overlay);color:var(--dsw-alias-label-secondary);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 14px;font-size:11px;display:flex}.NPLLIq_logPagerInfo{white-space:nowrap}.NPLLIq_logPagerControls{align-items:center;gap:4px;display:flex}.NPLLIq_logPagerBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:24px;height:24px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;font-size:13px;line-height:1}.NPLLIq_logPagerBtn:disabled{opacity:.4;cursor:default}.NPLLIq_logPagerPages{text-align:center;min-width:50px;color:var(--dsw-alias-label-secondary)}.NPLLIq_logPageSizeSelect{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;padding:2px 4px;font-size:11px}.NPLLIq_dialogOverlay{z-index:100001;pointer-events:auto;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.NPLLIq_logClearDialog{gap:0;width:320px;padding:16px}.NPLLIq_dialogBody{color:var(--dsw-alias-label-secondary);margin:6px 0 10px;font-size:12px;line-height:1.5}.NPLLIq_logClearDate{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:100%;color:var(--dsw-alias-label-primary);border-radius:6px;margin-bottom:12px;padding:6px 8px;font-size:13px}.NPLLIq_logClearDate:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}";
229
247
  const tagId = "@jxgame2020/dsh-token-quota/TokenQuotaPanel.module.css";
230
248
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
231
249
  const tag = document.createElement("style");
@@ -235,116 +253,142 @@ window.__ModuleLoader__.load({
235
253
  document.head.appendChild(tag);
236
254
  }
237
255
  var TokenQuotaPanel_module_css_default = {
238
- "logPager": "NPLLIq_logPager",
239
- "noteWinTitleText": "NPLLIq_noteWinTitleText",
256
+ "noteMenuBackdrop": "NPLLIq_noteMenuBackdrop",
257
+ "rowDrag": "NPLLIq_rowDrag",
258
+ "balanceStateHint": "NPLLIq_balanceStateHint",
240
259
  "controls": "NPLLIq_controls",
241
- "logPagerBtn": "NPLLIq_logPagerBtn",
242
- "logPagerPages": "NPLLIq_logPagerPages",
243
- "selectBtn": "NPLLIq_selectBtn",
244
- "logUsedCol": "NPLLIq_logUsedCol",
245
- "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
246
- "fillWarn": "NPLLIq_fillWarn",
247
- "dialogOverlay": "NPLLIq_dialogOverlay",
248
- "dialogBody": "NPLLIq_dialogBody",
249
- "switch": "NPLLIq_switch",
250
- "fillOver": "NPLLIq_fillOver",
251
- "upgradeClose": "NPLLIq_upgradeClose",
252
- "dialogBtn": "NPLLIq_dialogBtn",
253
- "notice": "NPLLIq_notice",
254
- "logClearDate": "NPLLIq_logClearDate",
255
- "copyBtn": "NPLLIq_copyBtn",
256
- "rowHeader": "NPLLIq_rowHeader",
257
- "logClearBtn": "NPLLIq_logClearBtn",
260
+ "balanceWinBody": "NPLLIq_balanceWinBody",
261
+ "currentBadge": "NPLLIq_currentBadge",
262
+ "save": "NPLLIq_save",
263
+ "balanceBarText": "NPLLIq_balanceBarText",
264
+ "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
265
+ "logModelCol": "NPLLIq_logModelCol",
266
+ "logDialog": "NPLLIq_logDialog",
267
+ "noteWin": "NPLLIq_noteWin",
268
+ "noteMenu": "NPLLIq_noteMenu",
269
+ "copyBtnDone": "NPLLIq_copyBtnDone",
270
+ "input": "NPLLIq_input",
271
+ "upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
272
+ "balanceBarDim": "NPLLIq_balanceBarDim",
273
+ "panelDim": "NPLLIq_panelDim",
274
+ "dialogTitle": "NPLLIq_dialogTitle",
275
+ "noteNew": "NPLLIq_noteNew",
276
+ "balanceBarError": "NPLLIq_balanceBarError",
258
277
  "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
259
- "upgradeCommands": "NPLLIq_upgradeCommands",
278
+ "logSearch": "NPLLIq_logSearch",
279
+ "upgradeBanner": "NPLLIq_upgradeBanner",
280
+ "balanceStateError": "NPLLIq_balanceStateError",
281
+ "logTable": "NPLLIq_logTable",
282
+ "upgradeBannerText": "NPLLIq_upgradeBannerText",
283
+ "logPagerInfo": "NPLLIq_logPagerInfo",
284
+ "resetSelect": "NPLLIq_resetSelect",
260
285
  "monitorHint": "NPLLIq_monitorHint",
261
- "noteNew": "NPLLIq_noteNew",
262
- "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
263
286
  "logClearDialog": "NPLLIq_logClearDialog",
264
- "logPagerInfo": "NPLLIq_logPagerInfo",
287
+ "fillWarn": "NPLLIq_fillWarn",
288
+ "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
289
+ "fillOver": "NPLLIq_fillOver",
290
+ "title": "NPLLIq_title",
291
+ "noteWinTitleText": "NPLLIq_noteWinTitleText",
292
+ "balanceWinHeader": "NPLLIq_balanceWinHeader",
293
+ "fullNotice": "NPLLIq_fullNotice",
294
+ "logUsedCol": "NPLLIq_logUsedCol",
295
+ "body": "NPLLIq_body",
296
+ "balanceToggle": "NPLLIq_balanceToggle",
297
+ "gearBtn": "NPLLIq_gearBtn",
298
+ "settingsBtnActive": "NPLLIq_settingsBtnActive",
299
+ "dialogHint": "NPLLIq_dialogHint",
300
+ "dialogBody": "NPLLIq_dialogBody",
301
+ "logPager": "NPLLIq_logPager",
302
+ "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
303
+ "versionNew": "NPLLIq_versionNew",
304
+ "settingsBtn": "NPLLIq_settingsBtn",
305
+ "rowHeader": "NPLLIq_rowHeader",
306
+ "noteWinText": "NPLLIq_noteWinText",
307
+ "balanceLastLine": "NPLLIq_balanceLastLine",
308
+ "dialogLabel": "NPLLIq_dialogLabel",
309
+ "noticeError": "NPLLIq_noticeError",
310
+ "bar": "NPLLIq_bar",
311
+ "balanceRowValue": "NPLLIq_balanceRowValue",
312
+ "dialogTab": "NPLLIq_dialogTab",
313
+ "balanceRowRefresh": "NPLLIq_balanceRowRefresh",
314
+ "monitorRow": "NPLLIq_monitorRow",
315
+ "balanceToggleOpen": "NPLLIq_balanceToggleOpen",
316
+ "noteWinGripBar": "NPLLIq_noteWinGripBar",
317
+ "header": "NPLLIq_header",
265
318
  "headerActions": "NPLLIq_headerActions",
319
+ "dialogClose": "NPLLIq_dialogClose",
320
+ "row": "NPLLIq_row",
321
+ "selectBtn": "NPLLIq_selectBtn",
322
+ "monitorName": "NPLLIq_monitorName",
323
+ "fillIdle": "NPLLIq_fillIdle",
324
+ "dialogHeader": "NPLLIq_dialogHeader",
325
+ "balanceBarLow": "NPLLIq_balanceBarLow",
326
+ "noteWinResize": "NPLLIq_noteWinResize",
327
+ "upgradeClose": "NPLLIq_upgradeClose",
328
+ "balanceRow": "NPLLIq_balanceRow",
329
+ "radioRow": "NPLLIq_radioRow",
330
+ "headerText": "NPLLIq_headerText",
331
+ "collapse": "NPLLIq_collapse",
332
+ "tabLabel": "NPLLIq_tabLabel",
333
+ "logClearBtn": "NPLLIq_logClearBtn",
266
334
  "rowDropTarget": "NPLLIq_rowDropTarget",
335
+ "panel": "NPLLIq_panel",
336
+ "upgradeCommands": "NPLLIq_upgradeCommands",
337
+ "switch": "NPLLIq_switch",
267
338
  "subtitle": "NPLLIq_subtitle",
268
- "tab": "NPLLIq_tab",
269
- "fillIdle": "NPLLIq_fillIdle",
270
339
  "noteWinTitle": "NPLLIq_noteWinTitle",
271
- "rowDragging": "NPLLIq_rowDragging",
272
- "currentBadge": "NPLLIq_currentBadge",
340
+ "balanceValueError": "NPLLIq_balanceValueError",
341
+ "logScroll": "NPLLIq_logScroll",
273
342
  "noteNewPlus": "NPLLIq_noteNewPlus",
274
- "panel": "NPLLIq_panel",
275
- "header": "NPLLIq_header",
276
- "panelDim": "NPLLIq_panelDim",
277
- "noteWin": "NPLLIq_noteWin",
278
- "noteWinBar": "NPLLIq_noteWinBar",
279
- "rowMeta": "NPLLIq_rowMeta",
280
- "copyBtnDone": "NPLLIq_copyBtnDone",
281
- "rowName": "NPLLIq_rowName",
282
- "settingsBtnActive": "NPLLIq_settingsBtnActive",
283
- "dialog": "NPLLIq_dialog",
343
+ "upgradeCommand": "NPLLIq_upgradeCommand",
344
+ "logPagerControls": "NPLLIq_logPagerControls",
345
+ "logClearDate": "NPLLIq_logClearDate",
346
+ "logPagerBtn": "NPLLIq_logPagerBtn",
347
+ "balanceSortBtn": "NPLLIq_balanceSortBtn",
348
+ "tabIcon": "NPLLIq_tabIcon",
349
+ "balanceWinTitle": "NPLLIq_balanceWinTitle",
350
+ "balanceRowName": "NPLLIq_balanceRowName",
284
351
  "settingsDialog": "NPLLIq_settingsDialog",
285
- "dialogLabel": "NPLLIq_dialogLabel",
286
- "noteMenu": "NPLLIq_noteMenu",
352
+ "noteMenuItem": "NPLLIq_noteMenuItem",
353
+ "rowName": "NPLLIq_rowName",
354
+ "copyBtn": "NPLLIq_copyBtn",
355
+ "dialogTabs": "NPLLIq_dialogTabs",
356
+ "logToolbar": "NPLLIq_logToolbar",
357
+ "logDayCol": "NPLLIq_logDayCol",
358
+ "balanceBarBadge": "NPLLIq_balanceBarBadge",
359
+ "rowMeta": "NPLLIq_rowMeta",
360
+ "upgradeHint": "NPLLIq_upgradeHint",
361
+ "noteWinBtn": "NPLLIq_noteWinBtn",
362
+ "balanceWin": "NPLLIq_balanceWin",
363
+ "balanceValueOk": "NPLLIq_balanceValueOk",
364
+ "notice": "NPLLIq_notice",
365
+ "dialogOverlay": "NPLLIq_dialogOverlay",
366
+ "dialogActions": "NPLLIq_dialogActions",
367
+ "balanceBar": "NPLLIq_balanceBar",
368
+ "checkErrorHint": "NPLLIq_checkErrorHint",
287
369
  "noteChipOpen": "NPLLIq_noteChipOpen",
288
- "monitorRow": "NPLLIq_monitorRow",
289
- "collapse": "NPLLIq_collapse",
290
- "monitorName": "NPLLIq_monitorName",
291
- "row": "NPLLIq_row",
292
- "dialogTitle": "NPLLIq_dialogTitle",
293
370
  "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
294
- "noteWinResize": "NPLLIq_noteWinResize",
295
- "resetSelect": "NPLLIq_resetSelect",
296
- "logTable": "NPLLIq_logTable",
297
- "settingsBtn": "NPLLIq_settingsBtn",
298
- "versionNew": "NPLLIq_versionNew",
299
- "bar": "NPLLIq_bar",
300
- "input": "NPLLIq_input",
301
- "gearBtn": "NPLLIq_gearBtn",
302
- "save": "NPLLIq_save",
303
- "upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
304
- "upgradeCommand": "NPLLIq_upgradeCommand",
305
- "rowDrag": "NPLLIq_rowDrag",
306
- "headerText": "NPLLIq_headerText",
307
- "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
308
- "checkBtn": "NPLLIq_checkBtn",
309
- "checkErrorHint": "NPLLIq_checkErrorHint",
310
- "noteWinGripBar": "NPLLIq_noteWinGripBar",
311
- "noteWinBtn": "NPLLIq_noteWinBtn",
312
- "dialogTab": "NPLLIq_dialogTab",
313
- "upgradeBanner": "NPLLIq_upgradeBanner",
314
371
  "dialogTabActive": "NPLLIq_dialogTabActive",
315
- "dialogHeader": "NPLLIq_dialogHeader",
316
- "resetRow": "NPLLIq_resetRow",
317
- "upgradeBannerText": "NPLLIq_upgradeBannerText",
318
- "logDayCol": "NPLLIq_logDayCol",
372
+ "noteChip": "NPLLIq_noteChip",
373
+ "version": "NPLLIq_version",
374
+ "dialog": "NPLLIq_dialog",
375
+ "monitorList": "NPLLIq_monitorList",
376
+ "dialogBtn": "NPLLIq_dialogBtn",
377
+ "rowDragging": "NPLLIq_rowDragging",
378
+ "balanceRowHeader": "NPLLIq_balanceRowHeader",
379
+ "balanceValueLow": "NPLLIq_balanceValueLow",
319
380
  "logHeader": "NPLLIq_logHeader",
320
- "noteMenuBackdrop": "NPLLIq_noteMenuBackdrop",
381
+ "logPagerPages": "NPLLIq_logPagerPages",
382
+ "tab": "NPLLIq_tab",
321
383
  "notesBar": "NPLLIq_notesBar",
322
- "dialogHint": "NPLLIq_dialogHint",
323
- "monitorList": "NPLLIq_monitorList",
324
- "logModelCol": "NPLLIq_logModelCol",
325
384
  "dialogSection": "NPLLIq_dialogSection",
326
- "logScroll": "NPLLIq_logScroll",
327
- "logPagerControls": "NPLLIq_logPagerControls",
385
+ "balanceRefreshAll": "NPLLIq_balanceRefreshAll",
386
+ "balanceBarRefresh": "NPLLIq_balanceBarRefresh",
387
+ "checkBtn": "NPLLIq_checkBtn",
328
388
  "panelDimStrong": "NPLLIq_panelDimStrong",
329
- "noticeError": "NPLLIq_noticeError",
330
- "title": "NPLLIq_title",
331
- "body": "NPLLIq_body",
332
- "dialogTabs": "NPLLIq_dialogTabs",
333
- "tabLabel": "NPLLIq_tabLabel",
334
- "radioRow": "NPLLIq_radioRow",
335
- "dialogActions": "NPLLIq_dialogActions",
336
- "version": "NPLLIq_version",
337
- "logDialog": "NPLLIq_logDialog",
338
- "logToolbar": "NPLLIq_logToolbar",
339
- "fullNotice": "NPLLIq_fullNotice",
340
- "upgradeHint": "NPLLIq_upgradeHint",
341
- "logSearch": "NPLLIq_logSearch",
342
- "noteChip": "NPLLIq_noteChip",
343
- "noteMenuItem": "NPLLIq_noteMenuItem",
344
- "noteWinText": "NPLLIq_noteWinText",
345
- "tabIcon": "NPLLIq_tabIcon",
346
389
  "noteWinCollapsed": "NPLLIq_noteWinCollapsed",
347
- "dialogClose": "NPLLIq_dialogClose"
390
+ "noteWinBar": "NPLLIq_noteWinBar",
391
+ "resetRow": "NPLLIq_resetRow"
348
392
  };
349
393
  //#endregion
350
394
  //#region lib/types/client/TokenQuotaPanel.js
@@ -449,6 +493,19 @@ window.__ModuleLoader__.load({
449
493
  if (trimmed === "") return "·";
450
494
  return Array.from(trimmed)[0] ?? "·";
451
495
  }
496
+ /** Currency symbol for the balance bar; a raw code is appended for unknowns. */
497
+ function currencySymbol(currency) {
498
+ if (currency === "CNY") return "¥";
499
+ if (currency === "USD") return "$";
500
+ if (currency === "EUR") return "€";
501
+ if (currency === "GBP") return "£";
502
+ return `${currency} `;
503
+ }
504
+ /** Short "Last: MM-dd HH:mm:ss" timestamp for the balance window footer. */
505
+ function formatBalanceTime(epochMs) {
506
+ const d = new Date(epochMs);
507
+ return `${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")} ${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}`;
508
+ }
452
509
  /** Default geometry of a new note; later notes cascade so they don't stack. */
453
510
  const NOTE_DEFAULT_SIZE = 220;
454
511
  const NOTE_MIN_WIDTH = 150;
@@ -469,7 +526,7 @@ window.__ModuleLoader__.load({
469
526
  * @param props - composed slot props.
470
527
  * @returns the panel element tree.
471
528
  */
472
- function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, setCheckUpdates, checkUpdatesNow, clearLogBefore, setDimWhenIdle, setModelOrder, saveNotes, setMusicEnabled, setMusicVolume, setMusicStyle, setMusicOnlyCurrentSession, useStore, actions, useSessions }) {
529
+ function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, setCheckUpdates, checkUpdatesNow, clearLogBefore, setDimWhenIdle, setModelOrder, saveNotes, setBalanceSettings, refreshBalance, setMusicEnabled, setMusicVolume, setMusicStyle, setMusicOnlyCurrentSession, useStore, actions, useSessions }) {
473
530
  const [collapsed, setCollapsed] = (0, react.useState)(false);
474
531
  const [drafts, setDrafts] = (0, react.useState)({});
475
532
  const [editingKey, setEditingKey] = (0, react.useState)(null);
@@ -486,6 +543,18 @@ window.__ModuleLoader__.load({
486
543
  const notesPending = (0, react.useRef)(null);
487
544
  const [noteMenu, setNoteMenu] = (0, react.useState)(null);
488
545
  const [activeNote, setActiveNote] = (0, react.useState)(null);
546
+ const [balanceOpen, setBalanceOpen] = (0, react.useState)(false);
547
+ const [balancePos, setBalancePos] = (0, react.useState)(null);
548
+ const [balanceSort, setBalanceSort] = (0, react.useState)(null);
549
+ const [refreshingAll, setRefreshingAll] = (0, react.useState)(false);
550
+ const [refreshingProvider, setRefreshingProvider] = (0, react.useState)(null);
551
+ /** Which model row is currently hovered (model key), for quota/balance flip. */
552
+ const [hoveredRowKey, setHoveredRowKey] = (0, react.useState)(null);
553
+ /** Flip state in rowMeta: 0 = shows quota text, 1 = shows balance text. Cycles every 3s while hovering. */
554
+ const [metaToggle, setMetaToggle] = (0, react.useState)(0);
555
+ /** Last time we auto-refreshed a stale balance on row-hover (per-provider epoch ms),
556
+ * throttles refreshes to at most one per 60s per provider. */
557
+ const lastRowStaleRefreshRef = (0, react.useRef)({});
489
558
  const [editingTitle, setEditingTitle] = (0, react.useState)(null);
490
559
  const [titleDraft, setTitleDraft] = (0, react.useState)("");
491
560
  (0, react.useEffect)(() => {
@@ -622,6 +691,9 @@ window.__ModuleLoader__.load({
622
691
  const checkUpdates = useStore((s) => s.checkUpdates);
623
692
  const dimWhenIdle = useStore((s) => s.dimWhenIdle);
624
693
  const order = useStore((s) => s.order);
694
+ const balances = useStore((s) => s.balances);
695
+ const balanceEnabled = useStore((s) => s.balanceEnabled);
696
+ const balancePollMinutes = useStore((s) => s.balancePollMinutes);
625
697
  const musicEnabled = useStore((s) => s.musicEnabled);
626
698
  const musicVolume = useStore((s) => s.musicVolume);
627
699
  const musicStyle = useStore((s) => s.musicStyle);
@@ -792,6 +864,168 @@ window.__ModuleLoader__.load({
792
864
  setLimit(row.key, parsed);
793
865
  };
794
866
  const visibleRows = rows.filter((row) => isMonitoredKey(row.key) || row.current);
867
+ const providers = (0, react.useMemo)(() => {
868
+ const seen = /* @__PURE__ */ new Set();
869
+ const list = [];
870
+ for (const group of groups) if (!seen.has(group.id)) {
871
+ seen.add(group.id);
872
+ list.push(group.id);
873
+ }
874
+ if (list.length === 0) list.push("deepseek");
875
+ return list;
876
+ }, [groups]);
877
+ const balanceByProvider = (0, react.useMemo)(() => {
878
+ const map = /* @__PURE__ */ new Map();
879
+ for (const provider of providers) {
880
+ const bal = balances.find((b) => b.provider === provider);
881
+ if (bal !== void 0) map.set(provider, bal);
882
+ else if (TOKEN_QUOTA_BALANCE_PROVIDERS.includes(provider)) map.set(provider, "loading");
883
+ else map.set(provider, "unsupported");
884
+ }
885
+ return map;
886
+ }, [providers, balances]);
887
+ const sortedProviders = (0, react.useMemo)(() => {
888
+ const toNum = (entry) => {
889
+ if (typeof entry === "string") return -1;
890
+ if (entry.status === "ok") return entry.total;
891
+ return -1;
892
+ };
893
+ const statusOrder = (entry) => {
894
+ if (entry === "loading") return 0;
895
+ if (entry === "unsupported") return 3;
896
+ if (entry.status === "ok" && entry.isAvailable && entry.total >= 5) return 0;
897
+ if (entry.status === "ok" && entry.total < 5) return 1;
898
+ if (entry.status === "unconfigured") return 3;
899
+ if (entry.status === "error") return 2;
900
+ return 0;
901
+ };
902
+ return [...providers].sort((left, right) => {
903
+ const lEntry = balanceByProvider.get(left);
904
+ const rEntry = balanceByProvider.get(right);
905
+ if (lEntry === void 0 || rEntry === void 0) return 0;
906
+ const ls = statusOrder(lEntry), rs = statusOrder(rEntry);
907
+ if (ls !== rs) return ls - rs;
908
+ if (balanceSort === null) return left.localeCompare(right);
909
+ if (balanceSort.key === "provider") return left.localeCompare(right) * balanceSort.dir;
910
+ return (toNum(lEntry) - toNum(rEntry)) * balanceSort.dir;
911
+ });
912
+ }, [
913
+ providers,
914
+ balanceByProvider,
915
+ balanceSort
916
+ ]);
917
+ /** Most recent successful fetch time (epoch ms), for the "Last: ..." line. */
918
+ const lastFetchedAt = (0, react.useMemo)(() => {
919
+ let latest = 0;
920
+ for (const bal of balances) if (bal.status === "ok") latest = Math.max(latest, bal.fetchedAt);
921
+ return latest;
922
+ }, [balances]);
923
+ /** Format a balance value for display, or a state label. */
924
+ const renderProviderCell = (provider) => {
925
+ const entry = balanceByProvider.get(provider);
926
+ if (entry === void 0) return { text: "" };
927
+ if (entry === "loading") return {
928
+ text: t("balanceLoading"),
929
+ cls: TokenQuotaPanel_module_css_default.balanceStateHint
930
+ };
931
+ if (entry === "unsupported") return {
932
+ text: t("balanceUnsupported"),
933
+ cls: TokenQuotaPanel_module_css_default.balanceStateHint
934
+ };
935
+ switch (entry.status) {
936
+ case "unconfigured": return {
937
+ text: t("balanceUnconfiguredShort"),
938
+ cls: TokenQuotaPanel_module_css_default.balanceStateHint,
939
+ title: t("balanceUnconfiguredHint")
940
+ };
941
+ case "error":
942
+ if (entry.total > 0) return entry.error !== void 0 ? {
943
+ text: `${currencySymbol(entry.currency)}${entry.total.toFixed(2)}`,
944
+ cls: TokenQuotaPanel_module_css_default.balanceValueError,
945
+ title: entry.error
946
+ } : {
947
+ text: `${currencySymbol(entry.currency)}${entry.total.toFixed(2)}`,
948
+ cls: TokenQuotaPanel_module_css_default.balanceValueError
949
+ };
950
+ return entry.error !== void 0 ? {
951
+ text: t("balanceError"),
952
+ cls: TokenQuotaPanel_module_css_default.balanceStateError,
953
+ title: entry.error
954
+ } : {
955
+ text: t("balanceError"),
956
+ cls: TokenQuotaPanel_module_css_default.balanceStateError
957
+ };
958
+ case "ok":
959
+ if (entry.isAvailable) return entry.total < 5 ? {
960
+ text: `${currencySymbol(entry.currency)}${entry.total.toFixed(2)}`,
961
+ cls: TokenQuotaPanel_module_css_default.balanceValueLow
962
+ } : {
963
+ text: `${currencySymbol(entry.currency)}${entry.total.toFixed(2)}`,
964
+ cls: TokenQuotaPanel_module_css_default.balanceValueOk
965
+ };
966
+ return {
967
+ text: `${currencySymbol(entry.currency)}${entry.total.toFixed(2)}`,
968
+ cls: TokenQuotaPanel_module_css_default.balanceValueError,
969
+ title: t("balanceUnavailable")
970
+ };
971
+ }
972
+ };
973
+ const lastLabel = lastFetchedAt > 0 ? t("balanceLastUpdated").replace("{v}", formatBalanceTime(lastFetchedAt)) : "";
974
+ /**
975
+ * Flip quota/balance every 3s while any supported row is hovered. If nothing
976
+ * is hovered (or the hovered row's provider has no balance data) we reset the
977
+ * toggle so quota shows first next time.
978
+ */
979
+ (0, react.useEffect)(() => {
980
+ if (hoveredRowKey === null) {
981
+ setMetaToggle(0);
982
+ return;
983
+ }
984
+ const [prov] = hoveredRowKey.split("/", 1);
985
+ const bal = balances.find((b) => b.provider === prov);
986
+ if (bal === void 0 || bal.status !== "ok") {
987
+ setMetaToggle(0);
988
+ return;
989
+ }
990
+ const id = window.setInterval(() => {
991
+ setMetaToggle((v) => (v + 1) % 2);
992
+ }, 3e3);
993
+ return () => {
994
+ window.clearInterval(id);
995
+ };
996
+ }, [hoveredRowKey, balances]);
997
+ /** On row hover, if the provider balance is stale (>5min since last ok fetch), kick off a single-provider refresh (throttled to 1/min). */
998
+ const triggerRowBalanceRefreshIfStale = (provider) => {
999
+ const bal = balances.find((b) => b.provider === provider);
1000
+ if (bal === void 0 || bal.status !== "ok") return;
1001
+ if (Date.now() - bal.fetchedAt < 5 * 6e4) return;
1002
+ const last = lastRowStaleRefreshRef.current[provider] ?? 0;
1003
+ if (Date.now() - last < 6e4) return;
1004
+ lastRowStaleRefreshRef.current[provider] = Date.now();
1005
+ setRefreshingProvider(provider);
1006
+ refreshBalance(provider);
1007
+ window.setTimeout(() => {
1008
+ setRefreshingProvider((prev) => prev === provider ? null : prev);
1009
+ }, 1500);
1010
+ };
1011
+ /** Quota text shown on the right of each model row (used/lot or used · unlimited). */
1012
+ const quotaText = (row) => row.limit > 0 ? `${formatTokens(row.used)} / ${formatTokens(row.limit)}` : `${formatTokens(row.used)} · ${t("unlimited")}`;
1013
+ /** Balance text shown when hovering a supported-provider row, or '' when unavailable. */
1014
+ const balanceTextForRow = (row) => {
1015
+ const bal = balances.find((b) => b.provider === row.provider);
1016
+ if (bal === void 0) return { text: "" };
1017
+ if (bal.status === "ok" && bal.isAvailable) {
1018
+ if (bal.total < 5) return {
1019
+ text: `${currencySymbol(bal.currency)}${bal.total.toFixed(2)}`,
1020
+ cls: TokenQuotaPanel_module_css_default.balanceValueLow
1021
+ };
1022
+ return {
1023
+ text: `${currencySymbol(bal.currency)}${bal.total.toFixed(2)}`,
1024
+ cls: TokenQuotaPanel_module_css_default.balanceValueOk
1025
+ };
1026
+ }
1027
+ return { text: "" };
1028
+ };
795
1029
  const panelDimClass = dimWhenIdle ? hovered || upgradeFlash ? "" : inputActive ? TokenQuotaPanel_module_css_default.panelDimStrong : TokenQuotaPanel_module_css_default.panelDim : "";
796
1030
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
797
1031
  (0, react_jsx_runtime.jsxs)("div", {
@@ -822,70 +1056,118 @@ window.__ModuleLoader__.load({
822
1056
  title: t("upgradeAvailableHint"),
823
1057
  children: [
824
1058
  "v",
825
- "0.1.35",
1059
+ "0.1.36",
826
1060
  " → v",
827
1061
  upgrade.latestVersion
828
1062
  ]
829
1063
  }) : (0, react_jsx_runtime.jsxs)("span", {
830
1064
  className: TokenQuotaPanel_module_css_default.version,
831
- children: ["v", "0.1.35"]
1065
+ children: ["v", "0.1.36"]
832
1066
  })]
833
1067
  }), (0, react_jsx_runtime.jsxs)("div", {
834
1068
  className: TokenQuotaPanel_module_css_default.notesBar,
835
1069
  onPointerDown: (event) => {
836
1070
  event.stopPropagation();
837
1071
  },
838
- children: [notes.map((note) => {
839
- const open = note.visible && !note.collapsed;
840
- return (0, react_jsx_runtime.jsx)("button", {
1072
+ children: [
1073
+ notes.map((note) => {
1074
+ const open = note.visible && !note.collapsed;
1075
+ return (0, react_jsx_runtime.jsx)("button", {
1076
+ type: "button",
1077
+ className: `${TokenQuotaPanel_module_css_default.noteChip}${open ? ` ${TokenQuotaPanel_module_css_default.noteChipOpen}` : ""}`,
1078
+ title: note.title.trim() === "" ? t("noteUntitled") : note.title,
1079
+ onClick: () => {
1080
+ patchNote(note.id, {
1081
+ visible: true,
1082
+ collapsed: false
1083
+ });
1084
+ },
1085
+ onContextMenu: (event) => {
1086
+ event.preventDefault();
1087
+ setNoteMenu({
1088
+ id: note.id,
1089
+ x: event.clientX,
1090
+ y: event.clientY
1091
+ });
1092
+ },
1093
+ children: noteInitial(note.title)
1094
+ }, note.id);
1095
+ }),
1096
+ (0, react_jsx_runtime.jsxs)("button", {
1097
+ type: "button",
1098
+ className: TokenQuotaPanel_module_css_default.noteNew,
1099
+ disabled: notes.length >= 5,
1100
+ title: notes.length >= 5 ? t("noteMaxHint") : t("noteNewHint"),
1101
+ onClick: createNote,
1102
+ children: [(0, react_jsx_runtime.jsxs)("svg", {
1103
+ viewBox: "0 0 16 16",
1104
+ width: "13",
1105
+ height: "13",
1106
+ "aria-hidden": "true",
1107
+ children: [(0, react_jsx_runtime.jsx)("path", {
1108
+ d: "M4 1.6h4.6L12.4 5.4v9H4z",
1109
+ fill: "none",
1110
+ stroke: "currentColor",
1111
+ strokeWidth: "1.2",
1112
+ strokeLinejoin: "round"
1113
+ }), (0, react_jsx_runtime.jsx)("path", {
1114
+ d: "M8.4 1.6v3.9h4",
1115
+ fill: "none",
1116
+ stroke: "currentColor",
1117
+ strokeWidth: "1.2",
1118
+ strokeLinejoin: "round"
1119
+ })]
1120
+ }), (0, react_jsx_runtime.jsx)("span", {
1121
+ className: TokenQuotaPanel_module_css_default.noteNewPlus,
1122
+ children: "+"
1123
+ })]
1124
+ }),
1125
+ balanceEnabled && (0, react_jsx_runtime.jsx)("button", {
841
1126
  type: "button",
842
- className: `${TokenQuotaPanel_module_css_default.noteChip}${open ? ` ${TokenQuotaPanel_module_css_default.noteChipOpen}` : ""}`,
843
- title: note.title.trim() === "" ? t("noteUntitled") : note.title,
1127
+ className: `${TokenQuotaPanel_module_css_default.noteNew} ${TokenQuotaPanel_module_css_default.balanceToggle}${balanceOpen ? ` ${TokenQuotaPanel_module_css_default.balanceToggleOpen}` : ""}`,
1128
+ title: t("balanceTitle"),
844
1129
  onClick: () => {
845
- patchNote(note.id, {
846
- visible: true,
847
- collapsed: false
1130
+ if (balanceOpen) {
1131
+ setBalanceOpen(false);
1132
+ return;
1133
+ }
1134
+ const winW = 280;
1135
+ const rect = panelRef.current?.getBoundingClientRect();
1136
+ if (rect !== void 0) setBalancePos({
1137
+ x: Math.max(8, rect.left - winW - 8),
1138
+ y: rect.top
848
1139
  });
849
- },
850
- onContextMenu: (event) => {
851
- event.preventDefault();
852
- setNoteMenu({
853
- id: note.id,
854
- x: event.clientX,
855
- y: event.clientY
1140
+ else setBalancePos({
1141
+ x: Math.max(8, (typeof window !== "undefined" ? window.innerWidth : 800) - 12 - 320 - winW - 8),
1142
+ y: 56
856
1143
  });
1144
+ setBalanceOpen(true);
857
1145
  },
858
- children: noteInitial(note.title)
859
- }, note.id);
860
- }), (0, react_jsx_runtime.jsxs)("button", {
861
- type: "button",
862
- className: TokenQuotaPanel_module_css_default.noteNew,
863
- disabled: notes.length >= 5,
864
- title: notes.length >= 5 ? t("noteMaxHint") : t("noteNewHint"),
865
- onClick: createNote,
866
- children: [(0, react_jsx_runtime.jsxs)("svg", {
867
- viewBox: "0 0 16 16",
868
- width: "13",
869
- height: "13",
870
- "aria-hidden": "true",
871
- children: [(0, react_jsx_runtime.jsx)("path", {
872
- d: "M4 1.6h4.6L12.4 5.4v9H4z",
873
- fill: "none",
874
- stroke: "currentColor",
875
- strokeWidth: "1.2",
876
- strokeLinejoin: "round"
877
- }), (0, react_jsx_runtime.jsx)("path", {
878
- d: "M8.4 1.6v3.9h4",
879
- fill: "none",
880
- stroke: "currentColor",
881
- strokeWidth: "1.2",
882
- strokeLinejoin: "round"
883
- })]
884
- }), (0, react_jsx_runtime.jsx)("span", {
885
- className: TokenQuotaPanel_module_css_default.noteNewPlus,
886
- children: "+"
887
- })]
888
- })]
1146
+ "aria-pressed": balanceOpen,
1147
+ children: (0, react_jsx_runtime.jsxs)("svg", {
1148
+ viewBox: "0 0 16 16",
1149
+ width: "13",
1150
+ height: "13",
1151
+ "aria-hidden": "true",
1152
+ children: [(0, react_jsx_runtime.jsx)("circle", {
1153
+ cx: "8",
1154
+ cy: "8",
1155
+ r: "6.3",
1156
+ fill: "none",
1157
+ stroke: "currentColor",
1158
+ strokeWidth: "1.3"
1159
+ }), (0, react_jsx_runtime.jsx)("text", {
1160
+ x: "8",
1161
+ y: "11",
1162
+ textAnchor: "middle",
1163
+ fontSize: "9",
1164
+ fontWeight: "700",
1165
+ fill: "currentColor",
1166
+ children: "¥"
1167
+ })]
1168
+ })
1169
+ })
1170
+ ]
889
1171
  })]
890
1172
  }), (0, react_jsx_runtime.jsxs)("div", {
891
1173
  className: TokenQuotaPanel_module_css_default.headerActions,
@@ -994,6 +1276,13 @@ window.__ModuleLoader__.load({
994
1276
  const editing = editingKey === row.key;
995
1277
  return (0, react_jsx_runtime.jsxs)("div", {
996
1278
  className: `${TokenQuotaPanel_module_css_default.row}${dragKey === row.key ? ` ${TokenQuotaPanel_module_css_default.rowDragging}` : ""}${dropKey === row.key && dragKey !== row.key ? ` ${TokenQuotaPanel_module_css_default.rowDropTarget}` : ""}`,
1279
+ onMouseEnter: () => {
1280
+ setHoveredRowKey(row.key);
1281
+ triggerRowBalanceRefreshIfStale(row.provider);
1282
+ },
1283
+ onMouseLeave: () => {
1284
+ setHoveredRowKey((prev) => prev === row.key ? null : prev);
1285
+ },
997
1286
  onDragOver: (event) => {
998
1287
  if (dragKey === null || dragKey === row.key) return;
999
1288
  event.preventDefault();
@@ -1045,7 +1334,13 @@ window.__ModuleLoader__.load({
1045
1334
  }),
1046
1335
  (0, react_jsx_runtime.jsxs)("span", {
1047
1336
  className: TokenQuotaPanel_module_css_default.rowMeta,
1048
- children: [row.limit > 0 ? `${formatTokens(row.used)} / ${formatTokens(row.limit)}` : `${formatTokens(row.used)} · ${t("unlimited")}`, (0, react_jsx_runtime.jsx)("button", {
1337
+ children: [(() => {
1338
+ const bt = balanceTextForRow(row);
1339
+ return hoveredRowKey === row.key && bt.text !== "" && metaToggle === 1 ? (0, react_jsx_runtime.jsx)("span", {
1340
+ className: bt.cls,
1341
+ children: bt.text
1342
+ }) : (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: quotaText(row) });
1343
+ })(), (0, react_jsx_runtime.jsx)("button", {
1049
1344
  type: "button",
1050
1345
  className: TokenQuotaPanel_module_css_default.gearBtn,
1051
1346
  title: t("setLimitHint"),
@@ -1361,7 +1656,7 @@ window.__ModuleLoader__.load({
1361
1656
  })
1362
1657
  ]
1363
1658
  })] }),
1364
- settingsTab === "other" && (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: (0, react_jsx_runtime.jsxs)("div", {
1659
+ settingsTab === "other" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
1365
1660
  className: TokenQuotaPanel_module_css_default.dialogSection,
1366
1661
  children: [(0, react_jsx_runtime.jsxs)("div", {
1367
1662
  className: TokenQuotaPanel_module_css_default.checkUpdatesRow,
@@ -1386,9 +1681,176 @@ window.__ModuleLoader__.load({
1386
1681
  role: "alert",
1387
1682
  children: upgradeError
1388
1683
  })]
1389
- }) })
1684
+ }), (0, react_jsx_runtime.jsxs)("div", {
1685
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1686
+ children: [
1687
+ (0, react_jsx_runtime.jsx)("div", {
1688
+ className: TokenQuotaPanel_module_css_default.dialogLabel,
1689
+ children: t("balanceSectionLabel")
1690
+ }),
1691
+ (0, react_jsx_runtime.jsxs)("label", {
1692
+ className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1693
+ children: [(0, react_jsx_runtime.jsx)("input", {
1694
+ type: "checkbox",
1695
+ checked: balanceEnabled,
1696
+ onChange: (event) => {
1697
+ setBalanceSettings(event.target.checked, balancePollMinutes);
1698
+ }
1699
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("balanceEnabledLabel") })]
1700
+ }),
1701
+ (0, react_jsx_runtime.jsx)("div", {
1702
+ className: TokenQuotaPanel_module_css_default.dialogHint,
1703
+ children: t("balanceHint").replace("{v}", String(balancePollMinutes))
1704
+ }),
1705
+ balanceEnabled && (0, react_jsx_runtime.jsxs)("label", {
1706
+ className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1707
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("balancePollLabel") }), (0, react_jsx_runtime.jsx)("select", {
1708
+ value: balancePollMinutes,
1709
+ onChange: (event) => {
1710
+ setBalanceSettings(balanceEnabled, Number(event.target.value));
1711
+ },
1712
+ children: [
1713
+ 1,
1714
+ 5,
1715
+ 15,
1716
+ 30,
1717
+ 60
1718
+ ].map((minutes) => (0, react_jsx_runtime.jsx)("option", {
1719
+ value: minutes,
1720
+ children: t("balancePollMinutes").replace("{v}", String(minutes))
1721
+ }, minutes))
1722
+ })]
1723
+ })
1724
+ ]
1725
+ })] })
1390
1726
  ]
1391
1727
  }),
1728
+ balanceOpen && balancePos !== null && (0, react_jsx_runtime.jsxs)("div", {
1729
+ className: TokenQuotaPanel_module_css_default.balanceWin,
1730
+ style: {
1731
+ left: balancePos.x,
1732
+ top: balancePos.y
1733
+ },
1734
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1735
+ className: TokenQuotaPanel_module_css_default.balanceWinHeader,
1736
+ children: [(0, react_jsx_runtime.jsx)("div", {
1737
+ className: TokenQuotaPanel_module_css_default.balanceWinTitle,
1738
+ children: t("balanceTitle")
1739
+ }), (0, react_jsx_runtime.jsx)("button", {
1740
+ type: "button",
1741
+ className: TokenQuotaPanel_module_css_default.dialogClose,
1742
+ title: t("close"),
1743
+ onClick: () => {
1744
+ setBalanceOpen(false);
1745
+ },
1746
+ children: "×"
1747
+ })]
1748
+ }), (0, react_jsx_runtime.jsxs)("div", {
1749
+ className: TokenQuotaPanel_module_css_default.balanceWinBody,
1750
+ children: [
1751
+ (0, react_jsx_runtime.jsxs)("div", {
1752
+ className: TokenQuotaPanel_module_css_default.balanceRowHeader,
1753
+ children: [
1754
+ (0, react_jsx_runtime.jsxs)("button", {
1755
+ type: "button",
1756
+ className: TokenQuotaPanel_module_css_default.balanceSortBtn,
1757
+ onClick: () => {
1758
+ setBalanceSort((prev) => {
1759
+ if (prev === null || prev.key !== "provider") return {
1760
+ key: "provider",
1761
+ dir: 1
1762
+ };
1763
+ if (prev.dir === 1) return {
1764
+ key: "provider",
1765
+ dir: -1
1766
+ };
1767
+ return null;
1768
+ });
1769
+ },
1770
+ children: [t("balanceColProvider"), balanceSort?.key === "provider" ? balanceSort.dir === 1 ? " ▲" : " ▼" : ""]
1771
+ }),
1772
+ (0, react_jsx_runtime.jsxs)("button", {
1773
+ type: "button",
1774
+ className: TokenQuotaPanel_module_css_default.balanceSortBtn,
1775
+ onClick: () => {
1776
+ setBalanceSort((prev) => {
1777
+ if (prev === null || prev.key !== "total") return {
1778
+ key: "total",
1779
+ dir: -1
1780
+ };
1781
+ if (prev.dir === -1) return {
1782
+ key: "total",
1783
+ dir: 1
1784
+ };
1785
+ return null;
1786
+ });
1787
+ },
1788
+ children: [t("balanceColBalance"), balanceSort?.key === "total" ? balanceSort.dir === 1 ? " ▲" : " ▼" : ""]
1789
+ }),
1790
+ (0, react_jsx_runtime.jsx)("button", {
1791
+ type: "button",
1792
+ className: TokenQuotaPanel_module_css_default.balanceRefreshAll,
1793
+ title: t("balanceRefreshAll"),
1794
+ disabled: refreshingAll,
1795
+ onClick: () => {
1796
+ setRefreshingAll(true);
1797
+ refreshBalance();
1798
+ window.setTimeout(() => {
1799
+ setRefreshingAll(false);
1800
+ }, 1500);
1801
+ },
1802
+ children: refreshingAll ? "…" : "↻"
1803
+ })
1804
+ ]
1805
+ }),
1806
+ (0, react_jsx_runtime.jsxs)("div", {
1807
+ className: TokenQuotaPanel_module_css_default.balanceRow,
1808
+ children: [
1809
+ (0, react_jsx_runtime.jsx)("span", { className: TokenQuotaPanel_module_css_default.balanceRowName }),
1810
+ (0, react_jsx_runtime.jsx)("span", { className: TokenQuotaPanel_module_css_default.balanceRowValue }),
1811
+ (0, react_jsx_runtime.jsx)("span", { className: TokenQuotaPanel_module_css_default.balanceRowRefresh })
1812
+ ]
1813
+ }),
1814
+ sortedProviders.map((provider) => {
1815
+ const cell = renderProviderCell(provider);
1816
+ const busy = refreshingProvider === provider || balanceByProvider.get(provider) === "loading";
1817
+ return (0, react_jsx_runtime.jsxs)("div", {
1818
+ className: TokenQuotaPanel_module_css_default.balanceRow,
1819
+ children: [
1820
+ (0, react_jsx_runtime.jsx)("span", {
1821
+ className: TokenQuotaPanel_module_css_default.balanceRowName,
1822
+ title: provider,
1823
+ children: provider
1824
+ }),
1825
+ (0, react_jsx_runtime.jsx)("span", {
1826
+ className: `${TokenQuotaPanel_module_css_default.balanceRowValue}${cell.cls !== void 0 ? ` ${cell.cls}` : ""}`,
1827
+ title: cell.title,
1828
+ children: cell.text
1829
+ }),
1830
+ (0, react_jsx_runtime.jsx)("button", {
1831
+ type: "button",
1832
+ className: TokenQuotaPanel_module_css_default.balanceRowRefresh,
1833
+ title: t("balanceRefreshOne"),
1834
+ disabled: busy || refreshingAll || cell.text === t("balanceUnsupported"),
1835
+ onClick: () => {
1836
+ setRefreshingProvider(provider);
1837
+ refreshBalance(provider);
1838
+ window.setTimeout(() => {
1839
+ setRefreshingProvider(null);
1840
+ }, 1500);
1841
+ },
1842
+ children: busy ? "…" : "↻"
1843
+ })
1844
+ ]
1845
+ }, provider);
1846
+ }),
1847
+ lastLabel !== "" && (0, react_jsx_runtime.jsx)("div", {
1848
+ className: TokenQuotaPanel_module_css_default.balanceLastLine,
1849
+ children: lastLabel
1850
+ })
1851
+ ]
1852
+ })]
1853
+ }),
1392
1854
  logOpen && (0, react_jsx_runtime.jsxs)("div", {
1393
1855
  ref: logRef,
1394
1856
  className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.logDialog}`,
@@ -2355,6 +2817,29 @@ window.__ModuleLoader__.load({
2355
2817
  settingsTabMusic: "音乐设置",
2356
2818
  settingsTabOther: "其它",
2357
2819
  reorderHint: "拖动排序",
2820
+ balanceLabel: "余额",
2821
+ balanceUnconfigured: "未配置 DeepSeek API Key",
2822
+ balanceUnconfiguredHint: "在 Models 页配置 API Key 后,这里自动显示账户余额",
2823
+ balanceError: "余额获取失败",
2824
+ balanceUnavailable: "账户不可用",
2825
+ balanceRefresh: "刷新余额",
2826
+ balanceUpdatedAt: "更新于 {v}",
2827
+ balanceGranted: "赠送 {v}",
2828
+ balanceToppedUp: "充值 {v}",
2829
+ balanceSectionLabel: "账户余额",
2830
+ balanceEnabledLabel: "显示账户余额",
2831
+ balanceHint: "每 {v} 分钟从服务商查询一次,也可在主界面点击 ↻ 手动刷新",
2832
+ balancePollLabel: "刷新间隔",
2833
+ balancePollMinutes: "{v} 分钟",
2834
+ balanceTitle: "账户余额",
2835
+ balanceColProvider: "提供方",
2836
+ balanceColBalance: "余额",
2837
+ balanceLoading: "查询中…",
2838
+ balanceUnsupported: "未接入查询",
2839
+ balanceUnconfiguredShort: "未配置 KEY",
2840
+ balanceRefreshAll: "刷新全部",
2841
+ balanceRefreshOne: "刷新单条",
2842
+ balanceLastUpdated: "Last: {v}",
2358
2843
  noteNewHint: "新建笔记(最多 5 个)",
2359
2844
  noteMaxHint: "最多 5 个笔记",
2360
2845
  noteUntitled: "未命名",
@@ -2448,6 +2933,29 @@ window.__ModuleLoader__.load({
2448
2933
  settingsTabMusic: "Music",
2449
2934
  settingsTabOther: "Other",
2450
2935
  reorderHint: "Drag to reorder",
2936
+ balanceLabel: "Balance",
2937
+ balanceUnconfigured: "No DeepSeek API key",
2938
+ balanceUnconfiguredHint: "Configure an API key on the Models page to show the account balance here",
2939
+ balanceError: "Balance fetch failed",
2940
+ balanceUnavailable: "Account unavailable",
2941
+ balanceRefresh: "Refresh balance",
2942
+ balanceUpdatedAt: "Updated {v}",
2943
+ balanceGranted: "Granted {v}",
2944
+ balanceToppedUp: "Topped up {v}",
2945
+ balanceSectionLabel: "Account balance",
2946
+ balanceEnabledLabel: "Show account balance",
2947
+ balanceHint: "Queried from the provider every {v} min; refresh manually from the panel with ↻",
2948
+ balancePollLabel: "Refresh interval",
2949
+ balancePollMinutes: "{v} min",
2950
+ balanceTitle: "Account balance",
2951
+ balanceColProvider: "Provider",
2952
+ balanceColBalance: "Balance",
2953
+ balanceLoading: "Loading…",
2954
+ balanceUnsupported: "Not available",
2955
+ balanceUnconfiguredShort: "No API key",
2956
+ balanceRefreshAll: "Refresh all",
2957
+ balanceRefreshOne: "Refresh",
2958
+ balanceLastUpdated: "Last: {v}",
2451
2959
  noteNewHint: "New note (max 5)",
2452
2960
  noteMaxHint: "At most 5 notes",
2453
2961
  noteUntitled: "Untitled",
@@ -2735,6 +3243,8 @@ window.__ModuleLoader__.load({
2735
3243
  bound?.setOrder(Array.isArray(doc?.order) ? doc.order : []);
2736
3244
  bound?.setNotes(normalizeNotes(doc?.notes));
2737
3245
  bound?.setReset(lastReset);
3246
+ const balanceRaw = doc?.balance;
3247
+ bound?.setBalanceSettings(balanceRaw?.enabled !== false, typeof balanceRaw?.pollMinutes === "number" ? Math.max(1, Math.min(120, Math.round(balanceRaw.pollMinutes))) : 5);
2738
3248
  const musicSettings = musicDefaults(doc?.music);
2739
3249
  lastOnlyCurrentSession = musicSettings.onlyCurrentSession;
2740
3250
  music.setEnabled(musicSettings.enabled);
@@ -2757,6 +3267,7 @@ window.__ModuleLoader__.load({
2757
3267
  bound?.setSnapshot(snapshot);
2758
3268
  bound?.setUpgrade(snapshot.upgrade ?? null);
2759
3269
  bound?.setUpgradeError(snapshot.upgradeError ?? null);
3270
+ bound?.setBalances(snapshot.balances ?? []);
2760
3271
  actOnFull(snapshot);
2761
3272
  });
2762
3273
  if (pullCount % 2 === 0) refreshCurrent();
@@ -2823,6 +3334,33 @@ window.__ModuleLoader__.load({
2823
3334
  const saveNotes = (notes) => {
2824
3335
  scope.set("notes", notes.slice(0, 5));
2825
3336
  };
3337
+ /** Persist the account-balance display settings. */
3338
+ const setBalanceSettings = (enabled, pollMinutes) => {
3339
+ bound?.setBalanceSettings(enabled, pollMinutes);
3340
+ scope.set("balance", {
3341
+ enabled,
3342
+ pollMinutes
3343
+ });
3344
+ };
3345
+ /**
3346
+ * Ask the Host to refresh account balances now and adopt the result.
3347
+ * With a provider key only that provider is refreshed; otherwise all of
3348
+ * them are.
3349
+ */
3350
+ const refreshBalance = (provider) => {
3351
+ const init = {
3352
+ method: "POST",
3353
+ headers: { "content-type": "application/json" }
3354
+ };
3355
+ if (provider !== void 0) init.body = JSON.stringify({ provider });
3356
+ fetch("/token-quota/refresh-balance", init).then((response) => response.ok ? response.json() : void 0, () => void 0).then((snapshot) => {
3357
+ if (snapshot === void 0) return;
3358
+ bound?.setSnapshot(snapshot);
3359
+ bound?.setUpgrade(snapshot.upgrade ?? null);
3360
+ bound?.setUpgradeError(snapshot.upgradeError ?? null);
3361
+ bound?.setBalances(snapshot.balances ?? []);
3362
+ });
3363
+ };
2826
3364
  const setMusicEnabled = (enabled) => {
2827
3365
  const doc = scope.getSnapshot().value;
2828
3366
  const current = musicDefaults(doc?.music);
@@ -2937,7 +3475,9 @@ window.__ModuleLoader__.load({
2937
3475
  setMusicStyle,
2938
3476
  setMusicOnlyCurrentSession,
2939
3477
  setModelOrder,
2940
- saveNotes
3478
+ saveNotes,
3479
+ setBalanceSettings,
3480
+ refreshBalance
2941
3481
  };
2942
3482
  };
2943
3483
  ctx.slots.inject("shell.overlay", () => ctx.slots.register({