@latentminds/pi-quotas 0.1.0
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/LICENSE +21 -0
- package/README.md +94 -0
- package/package.json +44 -0
- package/src/config.ts +216 -0
- package/src/extensions/command-quotas/command.ts +122 -0
- package/src/extensions/command-quotas/components/quotas-display.ts +209 -0
- package/src/extensions/command-quotas/index.ts +1 -0
- package/src/extensions/command-quotas/provider-commands.test.ts +34 -0
- package/src/extensions/command-quotas/provider-commands.ts +32 -0
- package/src/extensions/core/index.ts +95 -0
- package/src/extensions/quota-warnings/index.ts +128 -0
- package/src/extensions/usage-status/format-status.test.ts +104 -0
- package/src/extensions/usage-status/format-status.ts +80 -0
- package/src/extensions/usage-status/index.ts +163 -0
- package/src/index.ts +4 -0
- package/src/lib/quotas.ts +96 -0
- package/src/providers/fetch.test.ts +137 -0
- package/src/providers/fetch.ts +245 -0
- package/src/providers/parse.test.ts +256 -0
- package/src/providers/providers.ts +245 -0
- package/src/types/quotas.ts +31 -0
- package/src/utils/quotas-severity.test.ts +111 -0
- package/src/utils/quotas-severity.ts +151 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { QuotaWindow } from "../types/quotas.js";
|
|
2
|
+
export type { QuotaWindow } from "../types/quotas.js";
|
|
3
|
+
|
|
4
|
+
export type RiskSeverity = "none" | "warning" | "high" | "critical";
|
|
5
|
+
|
|
6
|
+
export interface WindowProjection {
|
|
7
|
+
pacePercent: number | null;
|
|
8
|
+
progress: number | null;
|
|
9
|
+
projectedPercent: number;
|
|
10
|
+
usedPercent: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface RiskAssessment extends WindowProjection {
|
|
14
|
+
usedFloorPercent: number | null;
|
|
15
|
+
warnProjectedPercent: number | null;
|
|
16
|
+
highProjectedPercent: number | null;
|
|
17
|
+
criticalProjectedPercent: number | null;
|
|
18
|
+
severity: RiskSeverity;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const MIN_PACE_PERCENT = 5;
|
|
22
|
+
const THRESHOLDS = {
|
|
23
|
+
usedFloor: { start: 33, end: 8 },
|
|
24
|
+
warnProjected: { start: 260, end: 120 },
|
|
25
|
+
highProjected: { start: 320, end: 145 },
|
|
26
|
+
criticalProjected: { start: 400, end: 170 },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function interpolate(start: number, end: number, progress: number): number {
|
|
30
|
+
const clampedProgress = Math.max(0, Math.min(1, progress));
|
|
31
|
+
return start + (end - start) * clampedProgress;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function safePercent(used: number, limit: number): number {
|
|
35
|
+
if (!Number.isFinite(used) || !Number.isFinite(limit) || limit <= 0) return 0;
|
|
36
|
+
return Math.max(0, Math.min(100, (used / limit) * 100));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getPacePercent(window: QuotaWindow): number | null {
|
|
40
|
+
const totalMs = window.windowSeconds * 1000;
|
|
41
|
+
if (totalMs <= 0) return null;
|
|
42
|
+
const remainingMs = window.resetsAt.getTime() - Date.now();
|
|
43
|
+
const elapsedMs = totalMs - remainingMs;
|
|
44
|
+
return Math.max(0, Math.min(100, (elapsedMs / totalMs) * 100));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getProjectedPercent(
|
|
48
|
+
usedPercent: number,
|
|
49
|
+
pacePercent: number | null,
|
|
50
|
+
): number {
|
|
51
|
+
if (pacePercent === null) return usedPercent;
|
|
52
|
+
const effectivePace = Math.max(MIN_PACE_PERCENT, pacePercent);
|
|
53
|
+
return Math.max(0, (usedPercent / effectivePace) * 100);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function assessWindow(window: QuotaWindow): RiskAssessment {
|
|
57
|
+
const rawPace = window.showPace ? getPacePercent(window) : null;
|
|
58
|
+
const pacePercent =
|
|
59
|
+
rawPace !== null ? rawPace * (window.paceScale ?? 1) : null;
|
|
60
|
+
const projectedPercent = getProjectedPercent(window.usedPercent, pacePercent);
|
|
61
|
+
|
|
62
|
+
let progress: number | null = null;
|
|
63
|
+
if (pacePercent !== null) progress = pacePercent / 100;
|
|
64
|
+
|
|
65
|
+
const base: WindowProjection = {
|
|
66
|
+
pacePercent,
|
|
67
|
+
progress,
|
|
68
|
+
projectedPercent,
|
|
69
|
+
usedPercent: window.usedPercent,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (progress === null) {
|
|
73
|
+
let severity: RiskSeverity = "none";
|
|
74
|
+
if (window.limited || projectedPercent >= 100) severity = "critical";
|
|
75
|
+
else if (projectedPercent >= 90) severity = "high";
|
|
76
|
+
else if (projectedPercent >= 80) severity = "warning";
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
...base,
|
|
80
|
+
usedFloorPercent: null,
|
|
81
|
+
warnProjectedPercent: 80,
|
|
82
|
+
highProjectedPercent: 90,
|
|
83
|
+
criticalProjectedPercent: 100,
|
|
84
|
+
severity,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const usedFloorPercent = interpolate(
|
|
89
|
+
THRESHOLDS.usedFloor.start,
|
|
90
|
+
THRESHOLDS.usedFloor.end,
|
|
91
|
+
progress,
|
|
92
|
+
);
|
|
93
|
+
const warnProjectedPercent = interpolate(
|
|
94
|
+
THRESHOLDS.warnProjected.start,
|
|
95
|
+
THRESHOLDS.warnProjected.end,
|
|
96
|
+
progress,
|
|
97
|
+
);
|
|
98
|
+
const highProjectedPercent = interpolate(
|
|
99
|
+
THRESHOLDS.highProjected.start,
|
|
100
|
+
THRESHOLDS.highProjected.end,
|
|
101
|
+
progress,
|
|
102
|
+
);
|
|
103
|
+
const criticalProjectedPercent = interpolate(
|
|
104
|
+
THRESHOLDS.criticalProjected.start,
|
|
105
|
+
THRESHOLDS.criticalProjected.end,
|
|
106
|
+
progress,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
let severity: RiskSeverity = "none";
|
|
110
|
+
if (window.limited) {
|
|
111
|
+
severity = "critical";
|
|
112
|
+
} else if (window.usedPercent >= usedFloorPercent) {
|
|
113
|
+
if (projectedPercent >= criticalProjectedPercent) severity = "critical";
|
|
114
|
+
else if (projectedPercent >= highProjectedPercent) severity = "high";
|
|
115
|
+
else if (projectedPercent >= warnProjectedPercent) severity = "warning";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...base,
|
|
120
|
+
usedFloorPercent,
|
|
121
|
+
warnProjectedPercent,
|
|
122
|
+
highProjectedPercent,
|
|
123
|
+
criticalProjectedPercent,
|
|
124
|
+
severity,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function formatTimeRemaining(date: Date): string {
|
|
129
|
+
const ms = date.getTime() - Date.now();
|
|
130
|
+
if (ms <= 0) return "now";
|
|
131
|
+
const totalMins = Math.ceil(ms / (1000 * 60));
|
|
132
|
+
const hours = Math.floor(totalMins / 60);
|
|
133
|
+
const mins = totalMins % 60;
|
|
134
|
+
if (hours >= 1) return mins > 0 ? `${hours}h${mins}m` : `${hours}h`;
|
|
135
|
+
const totalSecs = Math.ceil(ms / 1000);
|
|
136
|
+
return totalMins >= 1 ? `${totalMins}m` : `${totalSecs}s`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function getSeverityColor(
|
|
140
|
+
severity: RiskSeverity,
|
|
141
|
+
): "success" | "warning" | "error" {
|
|
142
|
+
switch (severity) {
|
|
143
|
+
case "critical":
|
|
144
|
+
case "high":
|
|
145
|
+
return "error";
|
|
146
|
+
case "warning":
|
|
147
|
+
return "warning";
|
|
148
|
+
default:
|
|
149
|
+
return "success";
|
|
150
|
+
}
|
|
151
|
+
}
|