quotacap 0.0.27 → 0.0.28
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/dist/adapters/grok.js +62 -19
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/adapters/grok.js
CHANGED
|
@@ -35,35 +35,73 @@ function parseGrokReset(raw, now) {
|
|
|
35
35
|
}
|
|
36
36
|
return dt.toISOString();
|
|
37
37
|
}
|
|
38
|
+
function validPct(v) {
|
|
39
|
+
return Number.isFinite(v) && v >= 0 && v <= 100;
|
|
40
|
+
}
|
|
38
41
|
export function parseGrokTui(text, now = new Date()) {
|
|
39
42
|
const cleaned = stripAnsi(text);
|
|
40
|
-
|
|
43
|
+
// The TUI writes "Weekly lim", repositions the cursor, then writes
|
|
44
|
+
// "t (Tier)", so after ANSI stripping the header reads "Weekly limt".
|
|
45
|
+
// The [i!l] class stays optional to keep tolerating past glitch variants.
|
|
46
|
+
const headerRe = /Weekly\s+lim[i!l]?t\s*\(([^)]+)\)/gi;
|
|
41
47
|
let plan = "unknown";
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
let lastHeaderIdx = -1;
|
|
49
|
+
for (const m of cleaned.matchAll(headerRe)) {
|
|
50
|
+
if (m.index === undefined)
|
|
51
|
+
continue;
|
|
52
|
+
plan = m[1].trim();
|
|
53
|
+
lastHeaderIdx = m.index;
|
|
44
54
|
}
|
|
45
|
-
|
|
55
|
+
if (lastHeaderIdx < 0) {
|
|
46
56
|
const tier = cleaned.match(/\b(SuperGrok|Grok\s+Pro|Grok\s+Enterprise|Grok\s+Basic)\b/i);
|
|
47
57
|
if (tier)
|
|
48
58
|
plan = tier[1].trim();
|
|
49
59
|
}
|
|
50
|
-
const pctRe = /Weekly lim[i!l]t[^\n%]*?(\d+)%/i;
|
|
51
|
-
const mPct = cleaned.match(pctRe);
|
|
52
60
|
let usedPct = null;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
// 1. Dialog header: first percent in a bounded window after the LAST
|
|
62
|
+
// header (later renders supersede earlier ones). The bar percent sits on
|
|
63
|
+
// the line below the header, so this must span newlines.
|
|
64
|
+
if (lastHeaderIdx >= 0) {
|
|
65
|
+
const after = cleaned.slice(lastHeaderIdx, lastHeaderIdx + 1200);
|
|
66
|
+
const m = after.match(/(\d{1,3})%/);
|
|
67
|
+
if (m) {
|
|
68
|
+
const v = parseInt(m[1], 10);
|
|
69
|
+
if (validPct(v))
|
|
70
|
+
usedPct = v;
|
|
71
|
+
}
|
|
57
72
|
}
|
|
73
|
+
// 2. Legacy same-line form ("Weekly limit (Tier) 26%"), excluding the
|
|
74
|
+
// startup status line "Weekly limit left: N%", which reports REMAINING
|
|
75
|
+
// quota with inverted semantics. Last valid match wins.
|
|
58
76
|
if (usedPct === null) {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
77
|
+
const lineRe = /Weekly\s+lim[i!l]?t[^\n%]*?(\d{1,3})%/gi;
|
|
78
|
+
for (const m of cleaned.matchAll(lineRe)) {
|
|
79
|
+
if (/left/i.test(m[0]))
|
|
80
|
+
continue;
|
|
81
|
+
const v = parseInt(m[1], 10);
|
|
82
|
+
if (validPct(v))
|
|
64
83
|
usedPct = v;
|
|
65
84
|
}
|
|
66
85
|
}
|
|
86
|
+
// 3. Bare progress-bar percent. Last valid match wins.
|
|
87
|
+
if (usedPct === null) {
|
|
88
|
+
const barRe = /[█░▓▒]+\s*(\d{1,3})%/g;
|
|
89
|
+
for (const m of cleaned.matchAll(barRe)) {
|
|
90
|
+
const v = parseInt(m[1], 10);
|
|
91
|
+
if (validPct(v))
|
|
92
|
+
usedPct = v;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 4. Status-line remaining figure ("Weekly limit left: N%") converted to
|
|
96
|
+
// used. Last valid match wins.
|
|
97
|
+
if (usedPct === null) {
|
|
98
|
+
const leftRe = /Weekly\s+lim[i!l]?t\s+left\s*:?\s*(\d{1,3})%/gi;
|
|
99
|
+
for (const m of cleaned.matchAll(leftRe)) {
|
|
100
|
+
const v = parseInt(m[1], 10);
|
|
101
|
+
if (validPct(v))
|
|
102
|
+
usedPct = 100 - v;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
67
105
|
if (usedPct === null)
|
|
68
106
|
throw new Error("grok: weekly percent not found in TUI output");
|
|
69
107
|
let creditsUsd;
|
|
@@ -73,11 +111,13 @@ export function parseGrokTui(text, now = new Date()) {
|
|
|
73
111
|
if (Number.isFinite(v) && v >= 0)
|
|
74
112
|
creditsUsd = v;
|
|
75
113
|
}
|
|
76
|
-
const
|
|
114
|
+
const resetRe = /Resets:\s*([A-Za-z]+\s+\d+,\s*\d+:\d+)/gi;
|
|
115
|
+
let resetsRaw = null;
|
|
116
|
+
for (const m of cleaned.matchAll(resetRe))
|
|
117
|
+
resetsRaw = m[1].trim();
|
|
77
118
|
let resetsAt = null;
|
|
78
119
|
let estimated = false;
|
|
79
|
-
if (
|
|
80
|
-
const resetsRaw = mReset[1].trim();
|
|
120
|
+
if (resetsRaw) {
|
|
81
121
|
resetsAt = parseGrokReset(resetsRaw, now);
|
|
82
122
|
if (!resetsAt)
|
|
83
123
|
throw new Error(`grok: bad resets timestamp "${resetsRaw}"`);
|
|
@@ -115,7 +155,10 @@ export const grokAdapter = {
|
|
|
115
155
|
rows: 50,
|
|
116
156
|
settleDelayMs: 5000,
|
|
117
157
|
input: "/usage\r",
|
|
118
|
-
|
|
158
|
+
// Wait for the usage dialog (tier header or Resets line), not the
|
|
159
|
+
// startup status line "Weekly limit left: N%", which matches /Weekly lim/
|
|
160
|
+
// and would complete before the dialog renders.
|
|
161
|
+
completionRegex: /Weekly\s+lim[i!l]?t\s*\(|Resets:|Credits:/i,
|
|
119
162
|
timeoutMs: 14000,
|
|
120
163
|
maxBytes: 256 * 1024,
|
|
121
164
|
signal: adapterSignal("grok"),
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// generated by scripts/build-embed.mjs — do not edit
|
|
2
|
-
export const VERSION = "0.0.
|
|
2
|
+
export const VERSION = "0.0.28";
|