visualizar-rate-limit 0.1.0 → 0.1.2
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/README.md +2 -2
- package/banner_visualizar.png +0 -0
- package/example.png +0 -0
- package/package.json +4 -2
- package/src/fetch-usage.mjs +42 -19
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# visualizar-r-l
|
|
2
2
|
|
|
3
|
-
(banner_visualizar.png)
|
|
3
|
+

|
|
4
4
|
|
|
5
5
|
Una CLI liviana para ver los rate limits de Codex sin salir de la terminal. Si eres de los que revisan su uso con `tmux`, `weechat` o cualquier terminal de la vieja escuela, este mini panel te da dos barras limpias y un `watch` para mantener el pulso del consumo.
|
|
6
6
|
|
|
7
7
|
## Qué se ve
|
|
8
8
|
|
|
9
|
-
(example.png)
|
|
9
|
+

|
|
10
10
|
|
|
11
11
|
1. **Dos ventanas**: carga de 5h y semanal con porcentajes coloreados (verde/amarillo/rojo según urgencia).
|
|
12
12
|
2. **Reset automático**: el parser extrae etiquetas como `Reset:` y muestra cuándo se renueva cada cuota.
|
|
Binary file
|
package/example.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "visualizar-rate-limit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "TUI para ver el rate limit de Codex desde chatgpt.com/codex/settings/usage",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"src",
|
|
12
12
|
"scripts",
|
|
13
13
|
"README.md",
|
|
14
|
-
"LICENSE"
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"banner_visualizar.png",
|
|
16
|
+
"example.png"
|
|
15
17
|
],
|
|
16
18
|
"scripts": {
|
|
17
19
|
"postinstall": "chmod +x ./bin/visualizar-r-l ./src/fetch-usage.mjs ./scripts/install.sh",
|
package/src/fetch-usage.mjs
CHANGED
|
@@ -98,8 +98,8 @@ function fallbackWindows(text) {
|
|
|
98
98
|
|
|
99
99
|
function colorize(percent, value) {
|
|
100
100
|
if (!process.stdout.isTTY) return value;
|
|
101
|
-
if (percent
|
|
102
|
-
if (percent
|
|
101
|
+
if (percent < 20) return `\x1b[31m${value}\x1b[0m`;
|
|
102
|
+
if (percent <= 50) return `\x1b[33m${value}\x1b[0m`;
|
|
103
103
|
return `\x1b[32m${value}\x1b[0m`;
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -153,6 +153,44 @@ function render(text) {
|
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
async function readPagePayload(page) {
|
|
157
|
+
return page.evaluate(() => ({
|
|
158
|
+
href: location.href,
|
|
159
|
+
title: document.title,
|
|
160
|
+
text: document.body?.innerText || '',
|
|
161
|
+
html: document.documentElement?.outerHTML || '',
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function looksUsablePayload(payload) {
|
|
166
|
+
const text = stripHtml(payload.text || payload.html);
|
|
167
|
+
if (!text) return false;
|
|
168
|
+
if (/just a moment|enable javascript and cookies to continue/i.test(text)) return false;
|
|
169
|
+
return /codex|usage|limit|rate|chatgpt/i.test(text);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function ensureUsagePage(page) {
|
|
173
|
+
const currentUrl = page.url();
|
|
174
|
+
|
|
175
|
+
if (currentUrl === url) {
|
|
176
|
+
const payload = await readPagePayload(page);
|
|
177
|
+
if (looksUsablePayload(payload)) {
|
|
178
|
+
logDebug('Reutilizando pestaña existente ya cargada');
|
|
179
|
+
return payload;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
logDebug(`Abriendo ${url}`);
|
|
184
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 });
|
|
185
|
+
logDebug('DOM content loaded');
|
|
186
|
+
await page.waitForFunction(() => document.body && document.body.innerText.length > 50, { timeout: 5000 }).catch(() => {});
|
|
187
|
+
logDebug('Paso waitForFunction');
|
|
188
|
+
await page.waitForNetworkIdle({ idleTime: 350, timeout: 2500 }).catch(() => {});
|
|
189
|
+
logDebug('Paso waitForNetworkIdle');
|
|
190
|
+
|
|
191
|
+
return readPagePayload(page);
|
|
192
|
+
}
|
|
193
|
+
|
|
156
194
|
let browser;
|
|
157
195
|
let hardTimeout;
|
|
158
196
|
|
|
@@ -160,7 +198,7 @@ try {
|
|
|
160
198
|
hardTimeout = setTimeout(() => {
|
|
161
199
|
console.error('Timeout duro alcanzado mientras intentaba extraer la página.');
|
|
162
200
|
process.exit(124);
|
|
163
|
-
},
|
|
201
|
+
}, 15000);
|
|
164
202
|
|
|
165
203
|
logDebug(`Conectando a Chrome visible en 127.0.0.1:${debugPort}`);
|
|
166
204
|
browser = await puppeteer.connect({
|
|
@@ -181,22 +219,7 @@ try {
|
|
|
181
219
|
page.on('framenavigated', (frame) => {
|
|
182
220
|
if (frame === page.mainFrame()) logDebug(`navegacion: ${frame.url()}`);
|
|
183
221
|
});
|
|
184
|
-
|
|
185
|
-
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
|
186
|
-
logDebug('DOM content loaded');
|
|
187
|
-
await page.waitForFunction(() => document.body && document.body.innerText.length > 50, { timeout: 30000 }).catch(() => {});
|
|
188
|
-
logDebug('Paso waitForFunction');
|
|
189
|
-
await page.waitForNetworkIdle({ idleTime: 1200, timeout: 15000 }).catch(() => {});
|
|
190
|
-
logDebug('Paso waitForNetworkIdle');
|
|
191
|
-
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
192
|
-
logDebug('Pausa final completada');
|
|
193
|
-
|
|
194
|
-
const payload = await page.evaluate(() => ({
|
|
195
|
-
href: location.href,
|
|
196
|
-
title: document.title,
|
|
197
|
-
text: document.body?.innerText || '',
|
|
198
|
-
html: document.documentElement?.outerHTML || '',
|
|
199
|
-
}));
|
|
222
|
+
const payload = await ensureUsagePage(page);
|
|
200
223
|
|
|
201
224
|
const text = stripHtml(payload.text || payload.html);
|
|
202
225
|
logDebug(`Título detectado: ${payload.title}`);
|