estela 0.1.39 → 0.1.40
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 +53 -0
- package/dist/cli-quota.test.d.ts +2 -0
- package/dist/cli-quota.test.d.ts.map +1 -0
- package/dist/cli-quota.test.js +216 -0
- package/dist/cli-quota.test.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +138 -0
- package/dist/cli.js.map +1 -1
- package/dist/db/store.d.ts +10 -1
- package/dist/db/store.d.ts.map +1 -1
- package/dist/db/store.js +29 -0
- package/dist/db/store.js.map +1 -1
- package/dist/demo.d.ts.map +1 -1
- package/dist/demo.js +53 -0
- package/dist/demo.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +29 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/metrics/quota.d.ts +186 -0
- package/dist/metrics/quota.d.ts.map +1 -0
- package/dist/metrics/quota.js +245 -0
- package/dist/metrics/quota.js.map +1 -0
- package/dist/metrics/quota.test.d.ts +2 -0
- package/dist/metrics/quota.test.d.ts.map +1 -0
- package/dist/metrics/quota.test.js +262 -0
- package/dist/metrics/quota.test.js.map +1 -0
- package/dist/quota.d.ts +18 -0
- package/dist/quota.d.ts.map +1 -0
- package/dist/quota.js +85 -0
- package/dist/quota.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -0
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +37 -0
- package/dist/server.test.js.map +1 -1
- package/package.json +1 -1
- package/web/app.css +36 -0
- package/web/app.js +61 -1
- package/web/i18n.js +28 -0
- package/web/index.html +4 -1
package/web/app.js
CHANGED
|
@@ -428,7 +428,14 @@ function haceCuanto(days) {
|
|
|
428
428
|
|
|
429
429
|
async function loadSummary() {
|
|
430
430
|
const { from, to } = periodRange(state.period === "all" ? "quarter" : state.period);
|
|
431
|
-
|
|
431
|
+
// La cuota es siempre de esta semana, sea cual sea el periodo elegido: si
|
|
432
|
+
// fallara, el resumen se pinta igual y la tarjeta simplemente no sale.
|
|
433
|
+
const [summary, quota] = await Promise.all([
|
|
434
|
+
api(`/api/summary?from=${from}&to=${to}`),
|
|
435
|
+
api("/api/quota").catch(() => null),
|
|
436
|
+
]);
|
|
437
|
+
state.summary = summary;
|
|
438
|
+
state.quota = quota;
|
|
432
439
|
renderSummary();
|
|
433
440
|
}
|
|
434
441
|
|
|
@@ -473,6 +480,8 @@ function renderSummary() {
|
|
|
473
480
|
parts.push(`<div class="plist">${s.projects.map(renderProjectRow).join("")}</div>`);
|
|
474
481
|
}
|
|
475
482
|
|
|
483
|
+
parts.push(renderQuota(state.quota));
|
|
484
|
+
|
|
476
485
|
if (s.activity.length) {
|
|
477
486
|
parts.push(`<h2 class="block-title">${tr("summary.activity")}</h2>`);
|
|
478
487
|
parts.push(`<div class="feed">${s.activity.map(renderActivity).join("")}</div>`);
|
|
@@ -510,6 +519,57 @@ function renderSummary() {
|
|
|
510
519
|
});
|
|
511
520
|
}
|
|
512
521
|
|
|
522
|
+
/* ¿Qué proyecto se come tu cuota? El mismo reparto de la semana que da
|
|
523
|
+
`estela quota`, por agente y nunca mezclados: Claude Code gasta la cuota de
|
|
524
|
+
Anthropic y Codex la de OpenAI. Solo consumo real: ni "te queda" ni
|
|
525
|
+
"se acaba", porque esos límites no se publican. */
|
|
526
|
+
function renderQuota(q) {
|
|
527
|
+
if (!q || (!q.agents.length && !q.excluded.length)) return "";
|
|
528
|
+
const AGENT = { "claude-code": "Claude Code", codex: "Codex" };
|
|
529
|
+
const out = [];
|
|
530
|
+
|
|
531
|
+
for (const a of q.agents) {
|
|
532
|
+
out.push(`<h2 class="block-title">${tr("quota.title", { agent: AGENT[a.agent] || a.agent })}</h2>`);
|
|
533
|
+
out.push(`<div class="plist">${a.week.projects.map(quotaRow).join("")}</div>`);
|
|
534
|
+
out.push(`<p class="quota-note">${esc(quotaComparison(a.comparison))}</p>`);
|
|
535
|
+
}
|
|
536
|
+
if (q.excluded.length) out.push(`<p class="quota-note">${tr("quota.copilot")}</p>`);
|
|
537
|
+
if (q.agents.length) out.push(`<p class="quota-note">${tr("quota.estimate")}</p>`);
|
|
538
|
+
return out.join("");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function quotaRow(p) {
|
|
542
|
+
const name = p.projectName ?? (p.folder ? tr("quota.folder", { folder: p.folder }) : tr("quota.noFolder"));
|
|
543
|
+
const pct = Math.round(p.share * 100);
|
|
544
|
+
return `
|
|
545
|
+
<div class="prow">
|
|
546
|
+
<div class="prow-text">
|
|
547
|
+
<div class="prow-name">${esc(name)}</div>
|
|
548
|
+
<div class="prow-meta">${tr("quota.breakdown", {
|
|
549
|
+
input: fmtTokens(p.input), output: fmtTokens(p.output),
|
|
550
|
+
read: fmtTokens(p.cacheRead), write: fmtTokens(p.cacheWrite) })}</div>
|
|
551
|
+
<div class="quota-bar"><i style="width:${pct}%"></i></div>
|
|
552
|
+
</div>
|
|
553
|
+
<div class="prow-figs">
|
|
554
|
+
<div class="prow-hours">${fmtTokens(p.total)}</div>
|
|
555
|
+
<div class="prow-amount">${tr("quota.share", { n: pct })}</div>
|
|
556
|
+
</div>
|
|
557
|
+
</div>`;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function quotaComparison(c) {
|
|
561
|
+
if (c.status !== "ok") return tr("quota.noHistory", { weeks: c.weeks, have: c.completeWeeks });
|
|
562
|
+
if (c.ratio === null) return tr("quota.noPastUsage", { current: fmtTokens(c.current), weeks: c.weeks });
|
|
563
|
+
const diff = Math.round((c.ratio - 1) * 100);
|
|
564
|
+
const how = diff > 0 ? tr("quota.more", { n: diff }) : diff < 0 ? tr("quota.less", { n: -diff }) : tr("quota.same");
|
|
565
|
+
return tr("quota.vsHistory", { current: fmtTokens(c.current), average: fmtTokens(c.average), weeks: c.weeks, how });
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** Tokens con el formato corto del idioma: "22,7 M" o "22.7M". */
|
|
569
|
+
function fmtTokens(n) {
|
|
570
|
+
return new Intl.NumberFormat(localeTag(), { notation: "compact", maximumFractionDigits: 1 }).format(n);
|
|
571
|
+
}
|
|
572
|
+
|
|
513
573
|
function kpi(value, label, extra = "") {
|
|
514
574
|
return `<div class="kpi ${extra}">
|
|
515
575
|
<div class="kpi-value">${esc(value)}</div>
|
package/web/i18n.js
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"refresh.searching": "Buscando…",
|
|
41
41
|
"refresh.failed": "No se pudo actualizar",
|
|
42
42
|
"upgrade.btn": "Actualizar a Pro o Teams",
|
|
43
|
+
"upgrade.btnShort": "Pro o Teams",
|
|
43
44
|
"upgrade.cycle": "Ciclo de facturación",
|
|
44
45
|
"upgrade.monthly": "Mensual",
|
|
45
46
|
"upgrade.yearly": "Anual",
|
|
@@ -140,6 +141,19 @@
|
|
|
140
141
|
"summary.approveAll": "Hay <b>{n}</b> bloques de trabajo <b>tuyo</b> sin revisar en este periodo. Al configurar un proyecto entra de golpe todo su histórico. Pulsa el aviso de cada proyecto para ir a ellos.",
|
|
141
142
|
"summary.approveAll.btn": "Aprobar el periodo",
|
|
142
143
|
"summary.activity": "Actividad reciente",
|
|
144
|
+
"quota.title": "Cuota de {agent} esta semana",
|
|
145
|
+
"quota.breakdown": "entrada {input} · salida {output} · lect. caché {read} · escr. caché {write}",
|
|
146
|
+
"quota.share": "{n} % de la semana",
|
|
147
|
+
"quota.folder": "sin proyecto · {folder}",
|
|
148
|
+
"quota.noFolder": "sin carpeta",
|
|
149
|
+
"quota.vsHistory": "Frente a tu historial: {current} esta semana, y una media de {average} en el mismo tramo de las {weeks} semanas anteriores: {how}.",
|
|
150
|
+
"quota.noPastUsage": "Frente a tu historial: {current} esta semana; en el mismo tramo de las {weeks} semanas anteriores no hubo consumo.",
|
|
151
|
+
"quota.noHistory": "Sin historial suficiente para comparar: hacen falta {weeks} semanas completas y hay {have}.",
|
|
152
|
+
"quota.more": "un {n} % más",
|
|
153
|
+
"quota.less": "un {n} % menos",
|
|
154
|
+
"quota.same": "lo mismo",
|
|
155
|
+
"quota.copilot": "Copilot no guarda tokens fiables y queda fuera de este cálculo.",
|
|
156
|
+
"quota.estimate": "Solo consumo real, calculado en tu máquina: los límites de cada plan no se publican, y lo que uses en claude.ai u otro equipo también cuenta y Estela no lo ve. El detalle de la ventana de 5 h, con <code>estela quota</code>.",
|
|
143
157
|
"summary.nothingLeft": "Ya no queda nada por revisar ahí",
|
|
144
158
|
"summary.pendingHere": "{blocks} por revisar aquí · {more}",
|
|
145
159
|
"summary.moreDays": { one: "1 día más con pendientes", other: "{n} días más con pendientes" },
|
|
@@ -323,6 +337,7 @@
|
|
|
323
337
|
"refresh.searching": "Looking…",
|
|
324
338
|
"refresh.failed": "Couldn't refresh",
|
|
325
339
|
"upgrade.btn": "Upgrade to Pro or Teams",
|
|
340
|
+
"upgrade.btnShort": "Pro or Teams",
|
|
326
341
|
"upgrade.cycle": "Billing cycle",
|
|
327
342
|
"upgrade.monthly": "Monthly",
|
|
328
343
|
"upgrade.yearly": "Yearly",
|
|
@@ -423,6 +438,19 @@
|
|
|
423
438
|
"summary.approveAll": "There are <b>{n}</b> blocks of <b>your</b> work unreviewed in this period. Setting up a project brings in its whole history at once. Click each project's notice to go to them.",
|
|
424
439
|
"summary.approveAll.btn": "Approve the period",
|
|
425
440
|
"summary.activity": "Recent activity",
|
|
441
|
+
"quota.title": "{agent} quota this week",
|
|
442
|
+
"quota.breakdown": "input {input} · output {output} · cache read {read} · cache write {write}",
|
|
443
|
+
"quota.share": "{n}% of the week",
|
|
444
|
+
"quota.folder": "no project · {folder}",
|
|
445
|
+
"quota.noFolder": "no folder",
|
|
446
|
+
"quota.vsHistory": "Against your history: {current} this week, and an average of {average} over the same stretch of the previous {weeks} weeks: {how}.",
|
|
447
|
+
"quota.noPastUsage": "Against your history: {current} this week; over the same stretch of the previous {weeks} weeks there was no usage.",
|
|
448
|
+
"quota.noHistory": "Not enough history to compare: it takes {weeks} complete weeks and there are {have}.",
|
|
449
|
+
"quota.more": "{n}% more",
|
|
450
|
+
"quota.less": "{n}% less",
|
|
451
|
+
"quota.same": "about the same",
|
|
452
|
+
"quota.copilot": "Copilot doesn't record reliable tokens and is left out of this calculation.",
|
|
453
|
+
"quota.estimate": "Real usage only, calculated on your machine: each plan's limits aren't published, and anything you use on claude.ai or another machine also counts and Estela can't see it. For the 5-hour window, run <code>estela quota</code>.",
|
|
426
454
|
"summary.nothingLeft": "Nothing left to review there",
|
|
427
455
|
"summary.pendingHere": "{blocks} to review here · {more}",
|
|
428
456
|
"summary.moreDays": { one: "1 more day with pending blocks", other: "{n} more days with pending blocks" },
|
package/web/index.html
CHANGED
|
@@ -30,7 +30,10 @@
|
|
|
30
30
|
data-i18n="sync.now" data-i18n-title="sync.now.title"
|
|
31
31
|
title="Sube tus horas a la nube y baja lo de tus otras máquinas">Sincronizar</button>
|
|
32
32
|
<div class="upgrade-wrap" id="upgrade-wrap" hidden>
|
|
33
|
-
<button type="button" class="btn-main btn-upgrade" id="upgrade-btn"
|
|
33
|
+
<button type="button" class="btn-main btn-upgrade" id="upgrade-btn"
|
|
34
|
+
data-i18n-aria-label="upgrade.btn" aria-label="Actualizar a Pro o Teams"><span class="up-long"
|
|
35
|
+
data-i18n="upgrade.btn">Actualizar a Pro o Teams</span><span class="up-short"
|
|
36
|
+
data-i18n="upgrade.btnShort">Pro o Teams</span></button>
|
|
34
37
|
<div class="upgrade-menu" id="upgrade-menu" hidden>
|
|
35
38
|
<div class="upgrade-ciclo" role="group" aria-label="Ciclo de facturación" data-i18n-aria-label="upgrade.cycle">
|
|
36
39
|
<button type="button" data-ciclo="monthly" class="is-on" data-i18n="upgrade.monthly">Mensual</button>
|