@jxgame2020/dsh-token-quota 0.1.15 → 0.1.16

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
@@ -170,7 +170,7 @@ window.__ModuleLoader__.load({
170
170
  }
171
171
  //#endregion
172
172
  //#region \0dsh-css:/Users/jxgame/Desktop/works/deepseek-harness-package/dsh-token-quota/packages/token-quota/src/client/TokenQuotaPanel.module.css.mjs
173
- 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_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_rowName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;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_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}.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}.NPLLIq_copyBtn:hover{background:var(--dsw-alias-bg-layer-3,#00000014)}.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_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;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:280px;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_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_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;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}";
173
+ 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_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_rowName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;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_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_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;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:280px;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_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_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;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}";
174
174
  const tagId = "@jxgame2020/dsh-token-quota/TokenQuotaPanel.module.css";
175
175
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
176
176
  const tag = document.createElement("style");
@@ -180,88 +180,90 @@ window.__ModuleLoader__.load({
180
180
  document.head.appendChild(tag);
181
181
  }
182
182
  var TokenQuotaPanel_module_css_default = {
183
- "fullNotice": "NPLLIq_fullNotice",
184
- "upgradeBanner": "NPLLIq_upgradeBanner",
185
- "logHeader": "NPLLIq_logHeader",
186
- "title": "NPLLIq_title",
187
- "rowHeader": "NPLLIq_rowHeader",
188
- "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
189
- "settingsBtn": "NPLLIq_settingsBtn",
190
- "version": "NPLLIq_version",
191
- "headerText": "NPLLIq_headerText",
192
- "gearBtn": "NPLLIq_gearBtn",
193
- "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
194
- "monitorList": "NPLLIq_monitorList",
195
- "switch": "NPLLIq_switch",
196
- "upgradeBannerText": "NPLLIq_upgradeBannerText",
197
- "checkBtn": "NPLLIq_checkBtn",
198
- "monitorName": "NPLLIq_monitorName",
199
- "copyBtn": "NPLLIq_copyBtn",
200
- "logDayCol": "NPLLIq_logDayCol",
183
+ "logSearch": "NPLLIq_logSearch",
201
184
  "logPager": "NPLLIq_logPager",
202
- "resetSelect": "NPLLIq_resetSelect",
185
+ "versionNew": "NPLLIq_versionNew",
186
+ "upgradeBannerText": "NPLLIq_upgradeBannerText",
187
+ "rowMeta": "NPLLIq_rowMeta",
188
+ "upgradeBanner": "NPLLIq_upgradeBanner",
189
+ "upgradeCommand": "NPLLIq_upgradeCommand",
190
+ "dialogTitle": "NPLLIq_dialogTitle",
191
+ "upgradeHint": "NPLLIq_upgradeHint",
192
+ "dialogHeader": "NPLLIq_dialogHeader",
193
+ "save": "NPLLIq_save",
194
+ "fillOver": "NPLLIq_fillOver",
195
+ "body": "NPLLIq_body",
196
+ "dialogActions": "NPLLIq_dialogActions",
197
+ "logClearBtn": "NPLLIq_logClearBtn",
198
+ "row": "NPLLIq_row",
199
+ "input": "NPLLIq_input",
203
200
  "logPagerInfo": "NPLLIq_logPagerInfo",
201
+ "logClearDialog": "NPLLIq_logClearDialog",
204
202
  "logClearDate": "NPLLIq_logClearDate",
205
- "logPagerBtn": "NPLLIq_logPagerBtn",
206
- "fillWarn": "NPLLIq_fillWarn",
207
- "rowMeta": "NPLLIq_rowMeta",
203
+ "dialog": "NPLLIq_dialog",
204
+ "logHeader": "NPLLIq_logHeader",
205
+ "collapse": "NPLLIq_collapse",
206
+ "selectBtn": "NPLLIq_selectBtn",
208
207
  "subtitle": "NPLLIq_subtitle",
208
+ "copyBtn": "NPLLIq_copyBtn",
209
+ "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
210
+ "fullNotice": "NPLLIq_fullNotice",
209
211
  "dialogBody": "NPLLIq_dialogBody",
210
- "fillIdle": "NPLLIq_fillIdle",
211
- "selectBtn": "NPLLIq_selectBtn",
212
- "controls": "NPLLIq_controls",
213
- "resetRow": "NPLLIq_resetRow",
214
- "upgradeCommands": "NPLLIq_upgradeCommands",
215
- "versionNew": "NPLLIq_versionNew",
216
- "body": "NPLLIq_body",
217
- "row": "NPLLIq_row",
218
- "upgradeHint": "NPLLIq_upgradeHint",
212
+ "header": "NPLLIq_header",
219
213
  "monitorHint": "NPLLIq_monitorHint",
214
+ "logPagerPages": "NPLLIq_logPagerPages",
215
+ "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
216
+ "version": "NPLLIq_version",
217
+ "rowHeader": "NPLLIq_rowHeader",
218
+ "controls": "NPLLIq_controls",
219
+ "monitorRow": "NPLLIq_monitorRow",
220
+ "tab": "NPLLIq_tab",
221
+ "logDayCol": "NPLLIq_logDayCol",
222
+ "logScroll": "NPLLIq_logScroll",
223
+ "radioRow": "NPLLIq_radioRow",
224
+ "fillWarn": "NPLLIq_fillWarn",
225
+ "resetSelect": "NPLLIq_resetSelect",
226
+ "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
220
227
  "logPagerControls": "NPLLIq_logPagerControls",
221
- "logClearDialog": "NPLLIq_logClearDialog",
222
- "currentBadge": "NPLLIq_currentBadge",
228
+ "monitorList": "NPLLIq_monitorList",
229
+ "logTable": "NPLLIq_logTable",
223
230
  "dialogSection": "NPLLIq_dialogSection",
224
- "bar": "NPLLIq_bar",
225
- "panelDim": "NPLLIq_panelDim",
226
- "headerActions": "NPLLIq_headerActions",
227
- "upgradeClose": "NPLLIq_upgradeClose",
228
- "header": "NPLLIq_header",
229
- "dialogLabel": "NPLLIq_dialogLabel",
230
- "upgradeCommand": "NPLLIq_upgradeCommand",
231
- "noticeError": "NPLLIq_noticeError",
232
- "notice": "NPLLIq_notice",
233
231
  "dialogBtn": "NPLLIq_dialogBtn",
234
- "logToolbar": "NPLLIq_logToolbar",
235
- "tab": "NPLLIq_tab",
236
- "tabIcon": "NPLLIq_tabIcon",
237
- "panel": "NPLLIq_panel",
238
- "collapse": "NPLLIq_collapse",
239
- "dialogTitle": "NPLLIq_dialogTitle",
240
- "logTable": "NPLLIq_logTable",
241
- "fillOver": "NPLLIq_fillOver",
242
- "dialog": "NPLLIq_dialog",
243
- "radioRow": "NPLLIq_radioRow",
244
- "dialogHeader": "NPLLIq_dialogHeader",
245
- "logClearBtn": "NPLLIq_logClearBtn",
246
- "logModelCol": "NPLLIq_logModelCol",
247
- "panelDimStrong": "NPLLIq_panelDimStrong",
248
- "logPagerPages": "NPLLIq_logPagerPages",
249
- "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
250
- "dialogOverlay": "NPLLIq_dialogOverlay",
251
- "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
252
- "dialogClose": "NPLLIq_dialogClose",
232
+ "title": "NPLLIq_title",
253
233
  "checkErrorHint": "NPLLIq_checkErrorHint",
234
+ "resetRow": "NPLLIq_resetRow",
235
+ "notice": "NPLLIq_notice",
236
+ "logPagerBtn": "NPLLIq_logPagerBtn",
237
+ "headerActions": "NPLLIq_headerActions",
238
+ "upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
239
+ "checkBtn": "NPLLIq_checkBtn",
240
+ "panelDim": "NPLLIq_panelDim",
241
+ "panelDimStrong": "NPLLIq_panelDimStrong",
242
+ "noticeError": "NPLLIq_noticeError",
243
+ "monitorName": "NPLLIq_monitorName",
244
+ "switch": "NPLLIq_switch",
245
+ "settingsBtn": "NPLLIq_settingsBtn",
254
246
  "rowName": "NPLLIq_rowName",
255
247
  "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
256
- "logSearch": "NPLLIq_logSearch",
257
- "dialogActions": "NPLLIq_dialogActions",
258
- "monitorRow": "NPLLIq_monitorRow",
259
- "save": "NPLLIq_save",
248
+ "dialogClose": "NPLLIq_dialogClose",
260
249
  "logUsedCol": "NPLLIq_logUsedCol",
261
- "logDialog": "NPLLIq_logDialog",
262
- "logScroll": "NPLLIq_logScroll",
250
+ "dialogOverlay": "NPLLIq_dialogOverlay",
251
+ "gearBtn": "NPLLIq_gearBtn",
252
+ "fillIdle": "NPLLIq_fillIdle",
253
+ "tabIcon": "NPLLIq_tabIcon",
254
+ "upgradeClose": "NPLLIq_upgradeClose",
255
+ "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
256
+ "currentBadge": "NPLLIq_currentBadge",
257
+ "logToolbar": "NPLLIq_logToolbar",
258
+ "bar": "NPLLIq_bar",
259
+ "dialogLabel": "NPLLIq_dialogLabel",
260
+ "panel": "NPLLIq_panel",
261
+ "headerText": "NPLLIq_headerText",
262
+ "upgradeCommands": "NPLLIq_upgradeCommands",
263
+ "copyBtnDone": "NPLLIq_copyBtnDone",
264
+ "logModelCol": "NPLLIq_logModelCol",
263
265
  "tabLabel": "NPLLIq_tabLabel",
264
- "input": "NPLLIq_input"
266
+ "logDialog": "NPLLIq_logDialog"
265
267
  };
266
268
  //#endregion
267
269
  //#region lib/types/client/TokenQuotaPanel.js
@@ -354,6 +356,11 @@ window.__ModuleLoader__.load({
354
356
  const [editingKey, setEditingKey] = (0, react.useState)(null);
355
357
  const [hovered, setHovered] = (0, react.useState)(false);
356
358
  const [inputActive, setInputActive] = (0, react.useState)(false);
359
+ const [copiedCmd, setCopiedCmd] = (0, react.useState)(null);
360
+ const copyTimerRef = (0, react.useRef)(null);
361
+ const [upgradeFlash, setUpgradeFlash] = (0, react.useState)(false);
362
+ const flashTimerRef = (0, react.useRef)(null);
363
+ const prevUpgradeRef = (0, react.useRef)(null);
357
364
  const [panelPos, setPanelPos] = (0, react.useState)(loadPanelPos);
358
365
  const [settingsPos, setSettingsPos] = (0, react.useState)(null);
359
366
  const [logPos, setLogPos] = (0, react.useState)(null);
@@ -405,6 +412,26 @@ window.__ModuleLoader__.load({
405
412
  window.removeEventListener("focusin", onFocusIn);
406
413
  };
407
414
  }, []);
415
+ (0, react.useEffect)(() => {
416
+ const latest = upgrade?.latestVersion ?? null;
417
+ if (latest !== null && prevUpgradeRef.current !== latest) {
418
+ setCollapsed(false);
419
+ setUpgradeFlash(true);
420
+ if (flashTimerRef.current !== null) clearTimeout(flashTimerRef.current);
421
+ flashTimerRef.current = window.setTimeout(() => {
422
+ setUpgradeFlash(false);
423
+ flashTimerRef.current = null;
424
+ }, 2500);
425
+ }
426
+ prevUpgradeRef.current = latest;
427
+ return () => {};
428
+ }, [upgrade]);
429
+ (0, react.useEffect)(() => {
430
+ return () => {
431
+ if (flashTimerRef.current !== null) clearTimeout(flashTimerRef.current);
432
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
433
+ };
434
+ }, []);
408
435
  const rows = (0, react.useMemo)(() => mergeModelRows(groups, snapshot, current), [
409
436
  groups,
410
437
  snapshot,
@@ -448,6 +475,16 @@ window.__ModuleLoader__.load({
448
475
  document.body.removeChild(el);
449
476
  }
450
477
  };
478
+ /** Copy an upgrade command and show per-button success feedback. */
479
+ const copyUpgradeCommand = (cmd) => {
480
+ copyToClipboard(cmd);
481
+ setCopiedCmd(cmd);
482
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
483
+ copyTimerRef.current = window.setTimeout(() => {
484
+ setCopiedCmd(null);
485
+ copyTimerRef.current = null;
486
+ }, 1600);
487
+ };
451
488
  (0, react.useEffect)(() => {
452
489
  if (!logOpen) return;
453
490
  let cancelled = false;
@@ -498,7 +535,7 @@ window.__ModuleLoader__.load({
498
535
  setLimit(row.key, parsed);
499
536
  };
500
537
  const visibleRows = rows.filter((row) => isMonitoredKey(row.key) || row.current);
501
- const panelDimClass = hovered ? "" : inputActive ? TokenQuotaPanel_module_css_default.panelDimStrong : TokenQuotaPanel_module_css_default.panelDim;
538
+ const panelDimClass = hovered || upgradeFlash ? "" : inputActive ? TokenQuotaPanel_module_css_default.panelDimStrong : TokenQuotaPanel_module_css_default.panelDim;
502
539
  return (0, react_jsx_runtime.jsxs)("div", {
503
540
  ref: panelRef,
504
541
  className: `${TokenQuotaPanel_module_css_default.panel}${panelDimClass !== "" ? ` ${panelDimClass}` : ""}`,
@@ -528,13 +565,13 @@ window.__ModuleLoader__.load({
528
565
  title: t("upgradeAvailableHint"),
529
566
  children: [
530
567
  "v",
531
- "0.1.15",
568
+ "0.1.16",
532
569
  " → v",
533
570
  upgrade.latestVersion
534
571
  ]
535
572
  }) : (0, react_jsx_runtime.jsxs)("span", {
536
573
  className: TokenQuotaPanel_module_css_default.version,
537
- children: ["v", "0.1.15"]
574
+ children: ["v", "0.1.16"]
538
575
  })]
539
576
  }), (0, react_jsx_runtime.jsx)("div", {
540
577
  className: TokenQuotaPanel_module_css_default.subtitle,
@@ -588,7 +625,7 @@ window.__ModuleLoader__.load({
588
625
  children: fullNotice
589
626
  }),
590
627
  upgrade !== null && !upgradeDismissed && (0, react_jsx_runtime.jsxs)("div", {
591
- className: TokenQuotaPanel_module_css_default.upgradeBanner,
628
+ className: `${TokenQuotaPanel_module_css_default.upgradeBanner}${upgradeFlash ? ` ${TokenQuotaPanel_module_css_default.upgradeBannerFlash}` : ""}`,
592
629
  role: "alert",
593
630
  children: [
594
631
  (0, react_jsx_runtime.jsx)("div", {
@@ -604,11 +641,11 @@ window.__ModuleLoader__.load({
604
641
  children: cmd
605
642
  }), (0, react_jsx_runtime.jsx)("button", {
606
643
  type: "button",
607
- className: TokenQuotaPanel_module_css_default.copyBtn,
644
+ className: `${TokenQuotaPanel_module_css_default.copyBtn}${copiedCmd === cmd ? ` ${TokenQuotaPanel_module_css_default.copyBtnDone}` : ""}`,
608
645
  onClick: () => {
609
- copyToClipboard(cmd);
646
+ copyUpgradeCommand(cmd);
610
647
  },
611
- children: t("copy")
648
+ children: copiedCmd === cmd ? t("copied") : t("copy")
612
649
  })]
613
650
  }, cmd))
614
651
  }),
@@ -1134,6 +1171,7 @@ window.__ModuleLoader__.load({
1134
1171
  upgradeAvailableHint: "有新版本可用",
1135
1172
  upgradeAvailable: "发现新版本 v{version},请在终端执行以下命令升级:",
1136
1173
  copy: "复制",
1174
+ copied: "已复制 ✓",
1137
1175
  upgradeHint: "升级后请重启 dsh web 并刷新浏览器页面",
1138
1176
  checkUpdatesLabel: "自动检查更新",
1139
1177
  checkUpdatesNow: "立即检查",
@@ -1198,6 +1236,7 @@ window.__ModuleLoader__.load({
1198
1236
  upgradeAvailableHint: "A new version is available",
1199
1237
  upgradeAvailable: "A new version v{version} is available. Run one of the following commands in your terminal to upgrade:",
1200
1238
  copy: "Copy",
1239
+ copied: "Copied ✓",
1201
1240
  upgradeHint: "After upgrading, restart dsh web and refresh the browser",
1202
1241
  checkUpdatesLabel: "Check for updates automatically",
1203
1242
  checkUpdatesNow: "Check now",
@@ -1426,7 +1465,8 @@ window.__ModuleLoader__.load({
1426
1465
  bound?.setUpgrade(snapshot.upgrade ?? null);
1427
1466
  bound?.setUpgradeError(snapshot.upgradeError ?? null);
1428
1467
  actOnFull(snapshot);
1429
- if (snapshot.upgrade === null) bound?.setLastCheckResult(snapshot.upgradeError !== null ? "error" : "up-to-date");
1468
+ if (snapshot.upgrade !== null) bound?.setDialogOpen(false);
1469
+ else bound?.setLastCheckResult(snapshot.upgradeError !== null ? "error" : "up-to-date");
1430
1470
  }
1431
1471
  bound?.setCheckingUpdates(false);
1432
1472
  setTimeout(() => {
package/lib/index.js CHANGED
@@ -406,7 +406,7 @@ var TokenQuotaService = class TokenQuotaService extends Service {
406
406
  return this.upgradeCheck;
407
407
  }
408
408
  async doRefreshUpgrade() {
409
- const current = "0.1.15";
409
+ const current = "0.1.16";
410
410
  let latest;
411
411
  try {
412
412
  const response = await fetch(REGISTRY_LATEST_URL, {
@@ -95,6 +95,15 @@ export function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored,
95
95
  // so the chat content behind it stays readable; hovering restores it.
96
96
  const [hovered, setHovered] = useState(false);
97
97
  const [inputActive, setInputActive] = useState(false);
98
+ // Copy-button feedback: which command was just copied (label flips to
99
+ // 「已复制」for a moment so the click is perceivable).
100
+ const [copiedCmd, setCopiedCmd] = useState(null);
101
+ const copyTimerRef = useRef(null);
102
+ // Flash state for the upgrade banner: armed when a NEW latest version shows
103
+ // up (either from a manual check or a periodic poll).
104
+ const [upgradeFlash, setUpgradeFlash] = useState(false);
105
+ const flashTimerRef = useRef(null);
106
+ const prevUpgradeRef = useRef(null);
98
107
  // Draggable placements: the panel persists across reloads; the dialogs
99
108
  // start centered (null) and remember where they were dragged to.
100
109
  const [panelPos, setPanelPos] = useState(loadPanelPos);
@@ -154,6 +163,34 @@ export function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored,
154
163
  window.addEventListener('focusin', onFocusIn);
155
164
  return () => { window.removeEventListener('focusin', onFocusIn); };
156
165
  }, []);
166
+ // When a NEW latest version appears (manual check or periodic poll):
167
+ // expand the panel (it may be collapsed), force it opaque, and flash the
168
+ // upgrade banner a few times so the discovery is unmissable.
169
+ useEffect(() => {
170
+ const latest = upgrade?.latestVersion ?? null;
171
+ if (latest !== null && prevUpgradeRef.current !== latest) {
172
+ setCollapsed(false);
173
+ setUpgradeFlash(true);
174
+ if (flashTimerRef.current !== null)
175
+ clearTimeout(flashTimerRef.current);
176
+ flashTimerRef.current = window.setTimeout(() => {
177
+ setUpgradeFlash(false);
178
+ flashTimerRef.current = null;
179
+ }, 2500);
180
+ }
181
+ prevUpgradeRef.current = latest;
182
+ return () => {
183
+ // Keep the timer across re-renders; cleared only on unmount.
184
+ };
185
+ }, [upgrade]);
186
+ useEffect(() => {
187
+ return () => {
188
+ if (flashTimerRef.current !== null)
189
+ clearTimeout(flashTimerRef.current);
190
+ if (copyTimerRef.current !== null)
191
+ clearTimeout(copyTimerRef.current);
192
+ };
193
+ }, []);
157
194
  const rows = useMemo(() => mergeModelRows(groups, snapshot, current), [groups, snapshot, current]);
158
195
  // All directory models, flattened for the monitoring picker.
159
196
  const allModels = useMemo(() => groups.flatMap(group => group.models.map((model) => ({
@@ -197,6 +234,17 @@ export function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored,
197
234
  document.body.removeChild(el);
198
235
  }
199
236
  };
237
+ /** Copy an upgrade command and show per-button success feedback. */
238
+ const copyUpgradeCommand = (cmd) => {
239
+ void copyToClipboard(cmd);
240
+ setCopiedCmd(cmd);
241
+ if (copyTimerRef.current !== null)
242
+ clearTimeout(copyTimerRef.current);
243
+ copyTimerRef.current = window.setTimeout(() => {
244
+ setCopiedCmd(null);
245
+ copyTimerRef.current = null;
246
+ }, 1600);
247
+ };
200
248
  // Fetch the usage log whenever the log dialog opens. Kept ABOVE the
201
249
  // collapsed early-return: every hook must run on every render, otherwise
202
250
  // React unmounts the component the moment the panel collapses (the old
@@ -239,10 +287,13 @@ export function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored,
239
287
  const visibleRows = rows.filter(row => isMonitoredKey(row.key) || row.current);
240
288
  // The panel dims when the pointer is away; dimming is stronger while the
241
289
  // user is typing in an input elsewhere so the text behind stays readable.
242
- const panelDimClass = hovered ? '' : inputActive ? css.panelDimStrong : css.panelDim;
290
+ // While the upgrade banner flashes, the panel is forced opaque.
291
+ const panelDimClass = hovered || upgradeFlash
292
+ ? ''
293
+ : inputActive ? css.panelDimStrong : css.panelDim;
243
294
  return (_jsxs("div", { ref: panelRef, className: `${css.panel}${panelDimClass !== '' ? ` ${panelDimClass}` : ''}`, style: panelPos !== null ? { left: panelPos.x, top: panelPos.y, right: 'auto' } : undefined, onPointerEnter: () => { setHovered(true); }, onPointerLeave: () => { setHovered(false); }, children: [_jsxs("div", { className: css.header, onPointerDown: (event) => { beginDrag(event, panelRef.current, applyPanelPos); }, children: [_jsxs("div", { className: css.headerText, children: [_jsxs("div", { className: css.title, children: [t('title'), __TOKEN_QUOTA_VERSION__ !== undefined && __TOKEN_QUOTA_VERSION__ !== '' && (upgrade !== null
244
295
  ? (_jsxs("span", { className: `${css.version} ${css.versionNew}`, title: t('upgradeAvailableHint'), children: ["v", __TOKEN_QUOTA_VERSION__, " \u2192 v", upgrade.latestVersion] }))
245
- : (_jsxs("span", { className: css.version, children: ["v", __TOKEN_QUOTA_VERSION__] })))] }), _jsx("div", { className: css.subtitle, children: t('subtitle') })] }), _jsxs("div", { className: css.headerActions, onPointerDown: (event) => { event.stopPropagation(); }, children: [_jsx("button", { type: "button", className: css.settingsBtn, onClick: () => { actions.setLogOpen(true); }, children: t('logs') }), _jsx("button", { type: "button", className: css.settingsBtn, onClick: openSettings, children: t('settings') }), _jsx("button", { type: "button", className: css.collapse, onClick: () => { setCollapsed(true); }, children: t('collapse') })] })] }), _jsxs("div", { className: css.body, children: [loading && _jsx("div", { className: css.notice, children: t('loading') }), error !== null && _jsx("div", { className: css.noticeError, children: error }), fullNotice !== null && (_jsx("div", { className: css.fullNotice, role: "alert", children: fullNotice })), upgrade !== null && !upgradeDismissed && (_jsxs("div", { className: css.upgradeBanner, role: "alert", children: [_jsx("div", { className: css.upgradeBannerText, children: t('upgradeAvailable').replace('{version}', upgrade.latestVersion) }), _jsx("div", { className: css.upgradeCommands, children: upgrade.commands.map(cmd => (_jsxs("div", { className: css.upgradeCommandRow, children: [_jsx("code", { className: css.upgradeCommand, children: cmd }), _jsx("button", { type: "button", className: css.copyBtn, onClick: () => { void copyToClipboard(cmd); }, children: t('copy') })] }, cmd))) }), _jsx("div", { className: css.upgradeHint, children: t('upgradeHint') }), _jsx("button", { type: "button", className: css.upgradeClose, onClick: () => { actions.setUpgradeDismissed(true); }, "aria-label": t('close'), children: "\u00D7" })] })), !loading && error === null && visibleRows.length === 0 && (_jsx("div", { className: css.notice, children: monitored !== null && monitored.length === 0 ? t('noMonitored') : t('waiting') })), visibleRows.map((row) => {
296
+ : (_jsxs("span", { className: css.version, children: ["v", __TOKEN_QUOTA_VERSION__] })))] }), _jsx("div", { className: css.subtitle, children: t('subtitle') })] }), _jsxs("div", { className: css.headerActions, onPointerDown: (event) => { event.stopPropagation(); }, children: [_jsx("button", { type: "button", className: css.settingsBtn, onClick: () => { actions.setLogOpen(true); }, children: t('logs') }), _jsx("button", { type: "button", className: css.settingsBtn, onClick: openSettings, children: t('settings') }), _jsx("button", { type: "button", className: css.collapse, onClick: () => { setCollapsed(true); }, children: t('collapse') })] })] }), _jsxs("div", { className: css.body, children: [loading && _jsx("div", { className: css.notice, children: t('loading') }), error !== null && _jsx("div", { className: css.noticeError, children: error }), fullNotice !== null && (_jsx("div", { className: css.fullNotice, role: "alert", children: fullNotice })), upgrade !== null && !upgradeDismissed && (_jsxs("div", { className: `${css.upgradeBanner}${upgradeFlash ? ` ${css.upgradeBannerFlash}` : ''}`, role: "alert", children: [_jsx("div", { className: css.upgradeBannerText, children: t('upgradeAvailable').replace('{version}', upgrade.latestVersion) }), _jsx("div", { className: css.upgradeCommands, children: upgrade.commands.map(cmd => (_jsxs("div", { className: css.upgradeCommandRow, children: [_jsx("code", { className: css.upgradeCommand, children: cmd }), _jsx("button", { type: "button", className: `${css.copyBtn}${copiedCmd === cmd ? ` ${css.copyBtnDone}` : ''}`, onClick: () => { copyUpgradeCommand(cmd); }, children: copiedCmd === cmd ? t('copied') : t('copy') })] }, cmd))) }), _jsx("div", { className: css.upgradeHint, children: t('upgradeHint') }), _jsx("button", { type: "button", className: css.upgradeClose, onClick: () => { actions.setUpgradeDismissed(true); }, "aria-label": t('close'), children: "\u00D7" })] })), !loading && error === null && visibleRows.length === 0 && (_jsx("div", { className: css.notice, children: monitored !== null && monitored.length === 0 ? t('noMonitored') : t('waiting') })), visibleRows.map((row) => {
246
297
  const state = barStateOf(row);
247
298
  const pct = row.limit > 0 ? Math.min(100, Math.round((row.used / row.limit) * 100)) : 0;
248
299
  const barClass = state === 'over'
@@ -254,7 +254,12 @@ export function apply(ctx) {
254
254
  bound?.setUpgrade(snapshot.upgrade ?? null);
255
255
  bound?.setUpgradeError(snapshot.upgradeError ?? null);
256
256
  actOnFull(snapshot);
257
- if (snapshot.upgrade === null) {
257
+ if (snapshot.upgrade !== null) {
258
+ // A new version was found: close the settings dialog so the
259
+ // flashing upgrade banner in the panel is immediately visible.
260
+ bound?.setDialogOpen(false);
261
+ }
262
+ else {
258
263
  // No newer version known: distinguish "checked OK, up to date"
259
264
  // from "check failed" via the host-provided error message.
260
265
  bound?.setLastCheckResult(snapshot.upgradeError !== null ? 'error' : 'up-to-date');
@@ -61,6 +61,7 @@ export declare const zh: {
61
61
  upgradeAvailableHint: string;
62
62
  upgradeAvailable: string;
63
63
  copy: string;
64
+ copied: string;
64
65
  upgradeHint: string;
65
66
  checkUpdatesLabel: string;
66
67
  checkUpdatesNow: string;
@@ -127,6 +128,7 @@ export declare const en: {
127
128
  upgradeAvailableHint: string;
128
129
  upgradeAvailable: string;
129
130
  copy: string;
131
+ copied: string;
130
132
  upgradeHint: string;
131
133
  checkUpdatesLabel: string;
132
134
  checkUpdatesNow: string;
@@ -61,6 +61,7 @@ export const zh = {
61
61
  upgradeAvailableHint: '有新版本可用',
62
62
  upgradeAvailable: '发现新版本 v{version},请在终端执行以下命令升级:',
63
63
  copy: '复制',
64
+ copied: '已复制 ✓',
64
65
  upgradeHint: '升级后请重启 dsh web 并刷新浏览器页面',
65
66
  checkUpdatesLabel: '自动检查更新',
66
67
  checkUpdatesNow: '立即检查',
@@ -125,6 +126,7 @@ export const en = {
125
126
  upgradeAvailableHint: 'A new version is available',
126
127
  upgradeAvailable: 'A new version v{version} is available. Run one of the following commands in your terminal to upgrade:',
127
128
  copy: 'Copy',
129
+ copied: 'Copied ✓',
128
130
  upgradeHint: 'After upgrading, restart dsh web and refresh the browser',
129
131
  checkUpdatesLabel: 'Check for updates automatically',
130
132
  checkUpdatesNow: 'Check now',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jxgame2020/dsh-token-quota",
3
3
  "description": "Daily per-model token quota accounting, enforcement, and a floating quota panel for the DeepSeek Harness — a fully self-contained plugin (no core-Harness wiring, no generated RPC contract)",
4
- "version": "0.1.15",
4
+ "version": "0.1.16",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },