maxpool 1.5.26 → 1.5.27
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/package.json +1 -1
- package/src/tui.js +56 -13
package/package.json
CHANGED
package/src/tui.js
CHANGED
|
@@ -18,11 +18,38 @@ const yellow = s => fg(33, s);
|
|
|
18
18
|
const red = s => fg(31, s);
|
|
19
19
|
const cyan = s => fg(36, s);
|
|
20
20
|
const gray = s => fg(90, s);
|
|
21
|
+
const dimUnderline = s => `${ESC}2;4m${s}${RESET}`;
|
|
21
22
|
|
|
22
23
|
const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
23
24
|
const strip = s => s.replace(ANSI_RE, '');
|
|
24
25
|
const vw = s => strip(s).length;
|
|
25
26
|
|
|
27
|
+
// ── Accounts-table columns ───────────────────────────────────
|
|
28
|
+
// Fixed column widths shared by the header row (acctHeader) AND every data row, so
|
|
29
|
+
// the header labels stay aligned with the columns they name. The Account/Type/
|
|
30
|
+
// Status/Quota start offsets (4/17/26/40) are pure functions of these widths + the
|
|
31
|
+
// 4-col row prefix, independent of the quota-bar width.
|
|
32
|
+
const NAME_W = 12; // a.name.slice(0, NAME_W).padEnd(NAME_W)
|
|
33
|
+
const TYPE_W = 8; // a.type.padEnd(TYPE_W) — fits "provider"
|
|
34
|
+
const STATUS_W = 13; // rpad(status, STATUS_W) — fits "throttled 59s"
|
|
35
|
+
const ROW_PREFIX = ' '; // ' ' + sel(1) + cur(1) + ' ' — 4 cols before the name
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Aligned column header for the accounts table. Names the three columns that carry
|
|
39
|
+
* NO inline label (Account / Type / Status) plus a group label over the two quota
|
|
40
|
+
* bars (Quota). The per-bar naming (Ses/Wk for OAuth, Tok/Req for API keys) and the
|
|
41
|
+
* load fields (Now/15m/1h) stay inline per row — they're row-type-dependent and
|
|
42
|
+
* begin at a variable offset — so the header stops after the Quota group label.
|
|
43
|
+
*/
|
|
44
|
+
function acctHeader(W) {
|
|
45
|
+
const quota = W >= 88 ? 'Quota (used% · resets-in)' : 'Quota';
|
|
46
|
+
return ROW_PREFIX
|
|
47
|
+
+ 'Account'.padEnd(NAME_W) + ' '
|
|
48
|
+
+ 'Type'.padEnd(TYPE_W) + ' '
|
|
49
|
+
+ 'Status'.padEnd(STATUS_W) + ' '
|
|
50
|
+
+ quota;
|
|
51
|
+
}
|
|
52
|
+
|
|
26
53
|
function rpad(s, w) {
|
|
27
54
|
const gap = w - vw(s);
|
|
28
55
|
return gap > 0 ? s + ' '.repeat(gap) : s;
|
|
@@ -194,7 +221,7 @@ function emptyBar(label, w = 10) {
|
|
|
194
221
|
return `${ESC}100m${' '.repeat(lp)}${text}${' '.repeat(rp)}${RESET}`;
|
|
195
222
|
}
|
|
196
223
|
|
|
197
|
-
export const __tuiTest = { formatReset, quotaLabel, bar, emptyBar, strip, loadText, countdown };
|
|
224
|
+
export const __tuiTest = { formatReset, quotaLabel, bar, emptyBar, strip, loadText, countdown, acctHeader, fitLine };
|
|
198
225
|
|
|
199
226
|
function timestamp() {
|
|
200
227
|
return new Date().toLocaleTimeString('en-US', { hour12: false });
|
|
@@ -663,12 +690,14 @@ export class TUI {
|
|
|
663
690
|
const previous = this.config.accounts[idx];
|
|
664
691
|
entry.enabled = previous.enabled;
|
|
665
692
|
this.config.accounts[idx] = entry;
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
693
|
+
// Update the AccountManager to the FRESH tokens BEFORE persisting. The
|
|
694
|
+
// saveConfig writer (index.js) derives the ON-DISK tokens from the
|
|
695
|
+
// AccountManager, not from config.accounts — so persisting first writes the
|
|
696
|
+
// STALE pre-re-auth token (typically the dead one we're re-authing away from)
|
|
697
|
+
// to disk. The account then works in memory but boots DEAD on the next restart
|
|
698
|
+
// (a just-re-authed token rejected as invalid_grant). A later refresh does NOT
|
|
699
|
+
// heal disk (persistTokenRefresh's generation guard skips a disk token that
|
|
700
|
+
// != _refreshedFrom), so disk must be made correct right here.
|
|
672
701
|
const amAcct = this.am.accounts.find(account =>
|
|
673
702
|
(entry.accountUuid && account.accountUuid === entry.accountUuid) || account.name === name
|
|
674
703
|
);
|
|
@@ -684,6 +713,17 @@ export class TUI {
|
|
|
684
713
|
amAcct.refreshDead = false;
|
|
685
714
|
if (amAcct.status === 'error') amAcct.status = 'active';
|
|
686
715
|
}
|
|
716
|
+
try {
|
|
717
|
+
await this.saveConfig(this.config);
|
|
718
|
+
} catch (error) {
|
|
719
|
+
// Persist failed (e.g. disk full). The browser re-auth genuinely SUCCEEDED,
|
|
720
|
+
// so KEEP the AccountManager on the fresh tokens — reverting it to the dead
|
|
721
|
+
// token would brick a working in-memory account. Roll back only the
|
|
722
|
+
// config.accounts mirror and surface the error; disk self-heals on the next
|
|
723
|
+
// saveConfig (the AM-derived writer re-writes the fresh token).
|
|
724
|
+
this.config.accounts[idx] = previous;
|
|
725
|
+
throw error;
|
|
726
|
+
}
|
|
687
727
|
this._addLog(`Updated account "${name}"`);
|
|
688
728
|
return { updated: true, name };
|
|
689
729
|
} else {
|
|
@@ -906,10 +946,13 @@ export class TUI {
|
|
|
906
946
|
lines.push(yellow(' No accounts configured. Press [a] to add one.'));
|
|
907
947
|
} else {
|
|
908
948
|
lines.push('');
|
|
909
|
-
//
|
|
910
|
-
//
|
|
949
|
+
// Aligned column header (dim + underline so it reads as chrome, not data). It
|
|
950
|
+
// labels the fixed columns that have no inline label; the Ses/Wk/Tok/Req and
|
|
951
|
+
// Now/15m/1h labels stay inline per row. A short glossary below expands the
|
|
952
|
+
// abbreviations the header + inline labels can't spell out.
|
|
953
|
+
lines.push(dimUnderline(acctHeader(W)));
|
|
911
954
|
if (W >= 88) {
|
|
912
|
-
lines.push(' ' + dim('Ses
|
|
955
|
+
lines.push(' ' + dim('Ses 5h · Wk 7d · Now in-flight (weight) · 15m/1h served (avg · f fails)'));
|
|
913
956
|
}
|
|
914
957
|
const showBoth = W >= 70;
|
|
915
958
|
const bw = showBoth
|
|
@@ -979,13 +1022,13 @@ export class TUI {
|
|
|
979
1022
|
const cur = isCur ? green('►') : ' ';
|
|
980
1023
|
|
|
981
1024
|
// Name (bold if selected)
|
|
982
|
-
const rawName = a.name.slice(0,
|
|
1025
|
+
const rawName = a.name.slice(0, NAME_W).padEnd(NAME_W);
|
|
983
1026
|
const name = isSel ? bold(rawName) : rawName;
|
|
984
1027
|
|
|
985
1028
|
// Type — pad to 8 so "provider" (8 chars) doesn't overflow a 7-wide column and
|
|
986
1029
|
// shift the whole provider row (incl. its quota bars) 1 char out of alignment
|
|
987
1030
|
// with the "oauth"/"apikey" rows.
|
|
988
|
-
const type = gray(a.type.padEnd(
|
|
1031
|
+
const type = gray(a.type.padEnd(TYPE_W));
|
|
989
1032
|
|
|
990
1033
|
// Status
|
|
991
1034
|
let status;
|
|
@@ -1030,7 +1073,7 @@ export class TUI {
|
|
|
1030
1073
|
default: status = a.status || 'ready';
|
|
1031
1074
|
}
|
|
1032
1075
|
// Widened from 10 to fit "throttled 59s" so the quota bars stay column-aligned.
|
|
1033
|
-
status = rpad(status,
|
|
1076
|
+
status = rpad(status, STATUS_W);
|
|
1034
1077
|
|
|
1035
1078
|
if (a.type === 'provider') {
|
|
1036
1079
|
return this._renderProviderAcct(sel, cur, name, type, status, a, bw, showBoth);
|