quotacap 0.0.4 → 0.0.5
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/parse.js +37 -12
- package/dist/src/adapters/parse.js +37 -12
- package/dist/src/version.js +1 -1
- package/dist/tests/adapters/manual.test.js +13 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/adapters/parse.js
CHANGED
|
@@ -21,22 +21,14 @@ function tryParseWithYear(raw, year) {
|
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
// Last "resets" match wins: claude output lists the session reset first and
|
|
26
|
-
// the weekly (period) reset last; manual pastes carry a single line.
|
|
27
|
-
const matches = [...text.matchAll(/resets\s+([^\n(]+?)\s*(?:\(|$)/gm)];
|
|
28
|
-
if (!matches.length)
|
|
29
|
-
return null;
|
|
30
|
-
const trimmed = matches[matches.length - 1][1].trim();
|
|
31
|
-
if (!trimmed)
|
|
32
|
-
return null;
|
|
24
|
+
function parseAbsoluteReset(raw, now) {
|
|
33
25
|
const yearStr = formatInTimeZone(now, BRISBANE_TZ, "yyyy");
|
|
34
26
|
const year = parseInt(yearStr, 10);
|
|
35
|
-
let utc = tryParseWithYear(
|
|
27
|
+
let utc = tryParseWithYear(raw, year);
|
|
36
28
|
if (!utc)
|
|
37
29
|
return null;
|
|
38
30
|
if (utc.getTime() < now.getTime()) {
|
|
39
|
-
const utcNext = tryParseWithYear(
|
|
31
|
+
const utcNext = tryParseWithYear(raw, year + 1);
|
|
40
32
|
if (utcNext) {
|
|
41
33
|
const diff = utcNext.getTime() - now.getTime();
|
|
42
34
|
if (diff >= 0 && diff < 8 * 86400000) {
|
|
@@ -52,5 +44,38 @@ export function parseResetText(text, now) {
|
|
|
52
44
|
if (utc.getTime() < now.getTime())
|
|
53
45
|
return null;
|
|
54
46
|
}
|
|
55
|
-
return
|
|
47
|
+
return utc;
|
|
48
|
+
}
|
|
49
|
+
function parseRelativeDuration(raw, now) {
|
|
50
|
+
const m = raw.match(/^in\s+(.+)$/);
|
|
51
|
+
if (!m)
|
|
52
|
+
return null;
|
|
53
|
+
const inner = m[1].trim();
|
|
54
|
+
const d = inner.match(/(\d+)d/)?.[1];
|
|
55
|
+
const h = inner.match(/(\d+)h/)?.[1];
|
|
56
|
+
const min = inner.match(/(\d+)m/)?.[1];
|
|
57
|
+
if (!d && !h && !min)
|
|
58
|
+
return null;
|
|
59
|
+
const ms = (parseInt(d ?? "0", 10) * 86400 + parseInt(h ?? "0", 10) * 3600 + parseInt(min ?? "0", 10) * 60) * 1000;
|
|
60
|
+
return new Date(now.getTime() + ms);
|
|
61
|
+
}
|
|
62
|
+
export function parseResetText(text, now) {
|
|
63
|
+
// Farthest future reset wins. Claude output lists the session reset before
|
|
64
|
+
// the weekly one; kimi lists the weekly window before its 5h rolling one —
|
|
65
|
+
// the period reset is always the farthest, so one rule serves both.
|
|
66
|
+
const matches = [...text.matchAll(/resets\s+([^\n(]+?)\s*(?:\(|$)/gm)];
|
|
67
|
+
let best = null;
|
|
68
|
+
for (const m of matches) {
|
|
69
|
+
const raw = m[1].trim();
|
|
70
|
+
if (!raw)
|
|
71
|
+
continue;
|
|
72
|
+
const candidates = [parseAbsoluteReset(raw, now), parseRelativeDuration(raw, now)];
|
|
73
|
+
for (const c of candidates) {
|
|
74
|
+
if (c && (!best || c.getTime() > best.getTime()))
|
|
75
|
+
best = c;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!best)
|
|
79
|
+
return null;
|
|
80
|
+
return formatInTimeZone(best, BRISBANE_TZ, "yyyy-MM-dd'T'HH:mm:ssXXX");
|
|
56
81
|
}
|
|
@@ -21,22 +21,14 @@ function tryParseWithYear(raw, year) {
|
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
// Last "resets" match wins: claude output lists the session reset first and
|
|
26
|
-
// the weekly (period) reset last; manual pastes carry a single line.
|
|
27
|
-
const matches = [...text.matchAll(/resets\s+([^\n(]+?)\s*(?:\(|$)/gm)];
|
|
28
|
-
if (!matches.length)
|
|
29
|
-
return null;
|
|
30
|
-
const trimmed = matches[matches.length - 1][1].trim();
|
|
31
|
-
if (!trimmed)
|
|
32
|
-
return null;
|
|
24
|
+
function parseAbsoluteReset(raw, now) {
|
|
33
25
|
const yearStr = formatInTimeZone(now, BRISBANE_TZ, "yyyy");
|
|
34
26
|
const year = parseInt(yearStr, 10);
|
|
35
|
-
let utc = tryParseWithYear(
|
|
27
|
+
let utc = tryParseWithYear(raw, year);
|
|
36
28
|
if (!utc)
|
|
37
29
|
return null;
|
|
38
30
|
if (utc.getTime() < now.getTime()) {
|
|
39
|
-
const utcNext = tryParseWithYear(
|
|
31
|
+
const utcNext = tryParseWithYear(raw, year + 1);
|
|
40
32
|
if (utcNext) {
|
|
41
33
|
const diff = utcNext.getTime() - now.getTime();
|
|
42
34
|
if (diff >= 0 && diff < 8 * 86400000) {
|
|
@@ -52,5 +44,38 @@ export function parseResetText(text, now) {
|
|
|
52
44
|
if (utc.getTime() < now.getTime())
|
|
53
45
|
return null;
|
|
54
46
|
}
|
|
55
|
-
return
|
|
47
|
+
return utc;
|
|
48
|
+
}
|
|
49
|
+
function parseRelativeDuration(raw, now) {
|
|
50
|
+
const m = raw.match(/^in\s+(.+)$/);
|
|
51
|
+
if (!m)
|
|
52
|
+
return null;
|
|
53
|
+
const inner = m[1].trim();
|
|
54
|
+
const d = inner.match(/(\d+)d/)?.[1];
|
|
55
|
+
const h = inner.match(/(\d+)h/)?.[1];
|
|
56
|
+
const min = inner.match(/(\d+)m/)?.[1];
|
|
57
|
+
if (!d && !h && !min)
|
|
58
|
+
return null;
|
|
59
|
+
const ms = (parseInt(d ?? "0", 10) * 86400 + parseInt(h ?? "0", 10) * 3600 + parseInt(min ?? "0", 10) * 60) * 1000;
|
|
60
|
+
return new Date(now.getTime() + ms);
|
|
61
|
+
}
|
|
62
|
+
export function parseResetText(text, now) {
|
|
63
|
+
// Farthest future reset wins. Claude output lists the session reset before
|
|
64
|
+
// the weekly one; kimi lists the weekly window before its 5h rolling one —
|
|
65
|
+
// the period reset is always the farthest, so one rule serves both.
|
|
66
|
+
const matches = [...text.matchAll(/resets\s+([^\n(]+?)\s*(?:\(|$)/gm)];
|
|
67
|
+
let best = null;
|
|
68
|
+
for (const m of matches) {
|
|
69
|
+
const raw = m[1].trim();
|
|
70
|
+
if (!raw)
|
|
71
|
+
continue;
|
|
72
|
+
const candidates = [parseAbsoluteReset(raw, now), parseRelativeDuration(raw, now)];
|
|
73
|
+
for (const c of candidates) {
|
|
74
|
+
if (c && (!best || c.getTime() > best.getTime()))
|
|
75
|
+
best = c;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!best)
|
|
79
|
+
return null;
|
|
80
|
+
return formatInTimeZone(best, BRISBANE_TZ, "yyyy-MM-dd'T'HH:mm:ssXXX");
|
|
56
81
|
}
|
package/dist/src/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.5";
|
|
@@ -12,4 +12,17 @@ describe("manual", () => {
|
|
|
12
12
|
const q = parseManualUsage("kimi", `Current week: 22% used · resets Aug 29 at 11am`, now);
|
|
13
13
|
expect(q.resetsAt).toMatch(/^2026-08-29/);
|
|
14
14
|
});
|
|
15
|
+
it("parses kimi's real dashboard format (relative duration, weekly window)", () => {
|
|
16
|
+
const now = new Date("2026-08-28T22:00:00Z");
|
|
17
|
+
const text = [
|
|
18
|
+
"Usage",
|
|
19
|
+
"Session usage: No active session.",
|
|
20
|
+
"Weekly limit ███░░░░░░░░░░░░░░░░░ 16% used resets in 3d 1h 24m",
|
|
21
|
+
"5h limit ░░░░░░░░░░░░░░░░░░░░ 0% used resets in 3h 24m",
|
|
22
|
+
].join("\n");
|
|
23
|
+
const q = parseManualUsage("kimi", text, now);
|
|
24
|
+
expect(q.usedPct).toBe(16);
|
|
25
|
+
const expected = now.getTime() + ((3 * 24 + 1) * 3600 + 24 * 60) * 1000;
|
|
26
|
+
expect(new Date(q.resetsAt).getTime()).toBe(expected);
|
|
27
|
+
});
|
|
15
28
|
});
|
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.5";
|