@askalf/dario 4.8.103 → 4.8.105
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/analytics.d.ts +17 -7
- package/dist/analytics.js +16 -23
- package/dist/tui/tabs/analytics.d.ts +6 -0
- package/dist/tui/tabs/analytics.js +27 -8
- package/package.json +1 -1
package/dist/analytics.d.ts
CHANGED
|
@@ -118,7 +118,18 @@ export declare class Analytics extends EventEmitter {
|
|
|
118
118
|
private computeStats;
|
|
119
119
|
private perAccountStats;
|
|
120
120
|
private perModelStats;
|
|
121
|
-
|
|
121
|
+
/**
|
|
122
|
+
* The most recent rate-limit snapshot in the window — current 5h / 7d
|
|
123
|
+
* utilization (0–1) as of the last request. The Analytics tab's rate-limit
|
|
124
|
+
* gauge reads this; an empty window reads 0/0. Mirrors `perAccountStats`'
|
|
125
|
+
* `last.util*` "current" semantics.
|
|
126
|
+
*
|
|
127
|
+
* Replaces the old per-5-min-bucket `utilizationTrend` array: the TUI gauge
|
|
128
|
+
* (the only consumer of `summary.utilization`) reads `.lastUtil5h` /
|
|
129
|
+
* `.lastUtil7d`, which on the array shape were `undefined` → rendered NaN%.
|
|
130
|
+
* See #600.
|
|
131
|
+
*/
|
|
132
|
+
private currentUtilization;
|
|
122
133
|
private predict;
|
|
123
134
|
}
|
|
124
135
|
interface PerAccountStat {
|
|
@@ -164,12 +175,11 @@ export interface AnalyticsSummary {
|
|
|
164
175
|
};
|
|
165
176
|
perAccount: Record<string, PerAccountStat>;
|
|
166
177
|
perModel: Record<string, PerModelStat>;
|
|
167
|
-
utilization
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}>;
|
|
178
|
+
/** Current 5h / 7d rate-limit utilization (0–1) as of the last request. */
|
|
179
|
+
utilization: {
|
|
180
|
+
lastUtil5h: number;
|
|
181
|
+
lastUtil7d: number;
|
|
182
|
+
};
|
|
173
183
|
predictions: {
|
|
174
184
|
estimatedExhaustionMinutes: number | null;
|
|
175
185
|
tokenBurnRate: number;
|
package/dist/analytics.js
CHANGED
|
@@ -175,7 +175,7 @@ export class Analytics extends EventEmitter {
|
|
|
175
175
|
},
|
|
176
176
|
perAccount: this.perAccountStats(recent),
|
|
177
177
|
perModel: this.perModelStats(recent),
|
|
178
|
-
utilization: this.
|
|
178
|
+
utilization: this.currentUtilization(recent),
|
|
179
179
|
predictions: this.predict(recent),
|
|
180
180
|
};
|
|
181
181
|
}
|
|
@@ -267,29 +267,22 @@ export class Analytics extends EventEmitter {
|
|
|
267
267
|
}
|
|
268
268
|
return result;
|
|
269
269
|
}
|
|
270
|
-
|
|
270
|
+
/**
|
|
271
|
+
* The most recent rate-limit snapshot in the window — current 5h / 7d
|
|
272
|
+
* utilization (0–1) as of the last request. The Analytics tab's rate-limit
|
|
273
|
+
* gauge reads this; an empty window reads 0/0. Mirrors `perAccountStats`'
|
|
274
|
+
* `last.util*` "current" semantics.
|
|
275
|
+
*
|
|
276
|
+
* Replaces the old per-5-min-bucket `utilizationTrend` array: the TUI gauge
|
|
277
|
+
* (the only consumer of `summary.utilization`) reads `.lastUtil5h` /
|
|
278
|
+
* `.lastUtil7d`, which on the array shape were `undefined` → rendered NaN%.
|
|
279
|
+
* See #600.
|
|
280
|
+
*/
|
|
281
|
+
currentUtilization(records) {
|
|
271
282
|
if (records.length === 0)
|
|
272
|
-
return
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
for (const r of records) {
|
|
276
|
-
const key = Math.floor(r.timestamp / bucketMs) * bucketMs;
|
|
277
|
-
const existing = buckets.get(key);
|
|
278
|
-
if (existing) {
|
|
279
|
-
existing.push(r);
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
buckets.set(key, [r]);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return [...buckets.entries()]
|
|
286
|
-
.sort(([a], [b]) => a - b)
|
|
287
|
-
.map(([ts, recs]) => ({
|
|
288
|
-
timestamp: ts,
|
|
289
|
-
avgUtil5h: Math.round(recs.reduce((s, r) => s + r.util5h, 0) / recs.length * 100) / 100,
|
|
290
|
-
avgUtil7d: Math.round(recs.reduce((s, r) => s + r.util7d, 0) / recs.length * 100) / 100,
|
|
291
|
-
requests: recs.length,
|
|
292
|
-
}));
|
|
283
|
+
return { lastUtil5h: 0, lastUtil7d: 0 };
|
|
284
|
+
const last = records[records.length - 1];
|
|
285
|
+
return { lastUtil5h: last.util5h, lastUtil7d: last.util7d };
|
|
293
286
|
}
|
|
294
287
|
predict(records) {
|
|
295
288
|
if (records.length < 3) {
|
|
@@ -37,6 +37,12 @@ interface SummaryShape {
|
|
|
37
37
|
lastUtil5h: number;
|
|
38
38
|
lastUtil7d: number;
|
|
39
39
|
};
|
|
40
|
+
perAccount: Record<string, {
|
|
41
|
+
requests: number;
|
|
42
|
+
currentUtil5h: number;
|
|
43
|
+
currentUtil7d: number;
|
|
44
|
+
lastClaim: string;
|
|
45
|
+
}>;
|
|
40
46
|
}
|
|
41
47
|
export interface AnalyticsState {
|
|
42
48
|
summary: SummaryShape | null;
|
|
@@ -78,7 +78,7 @@ export const AnalyticsTab = {
|
|
|
78
78
|
lines.push(' ' + renderKvRow('Tokens out', formatNumber(s.window.totalOutputTokens), w - 4));
|
|
79
79
|
lines.push(' ' + renderKvRow('Thinking tokens', formatNumber(s.window.totalThinkingTokens), w - 4));
|
|
80
80
|
lines.push(' ' + renderKvRow('Avg latency', `${Math.round(s.window.avgLatencyMs)}ms`, w - 4));
|
|
81
|
-
lines.push(' ' + renderKvRow('Subscription %', `${
|
|
81
|
+
lines.push(' ' + renderKvRow('Subscription %', `${s.window.subscriptionPercent.toFixed(0)}%`, w - 4));
|
|
82
82
|
// ── Per-model bars ─────────────────────────────────────────
|
|
83
83
|
const models = Object.entries(s.perModel).sort((a, b) => b[1].requests - a[1].requests);
|
|
84
84
|
if (models.length > 0) {
|
|
@@ -94,14 +94,33 @@ export const AnalyticsTab = {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
// ── Rate-limit ────────────────────────────────────────────
|
|
97
|
+
// Each account hits its OWN 5h/7d windows, so with >1 account an
|
|
98
|
+
// aggregate gauge is misleading (#600) — show one row per account, the
|
|
99
|
+
// bar tracking the binding constraint (max of 5h/7d = closest to a limit).
|
|
97
100
|
lines.push('');
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
const accts = s.perAccount ? Object.entries(s.perAccount) : [];
|
|
102
|
+
if (accts.length > 1) {
|
|
103
|
+
lines.push(' ' + brand('Rate-limit') + dim(' (per account)'));
|
|
104
|
+
const acctBarWidth = Math.max(8, Math.min(20, w - 48));
|
|
105
|
+
for (const [alias, a] of accts.sort((x, y) => y[1].requests - x[1].requests)) {
|
|
106
|
+
const u5 = a.currentUtil5h ?? 0;
|
|
107
|
+
const u7 = a.currentUtil7d ?? 0;
|
|
108
|
+
const peak = Math.max(u5, u7);
|
|
109
|
+
lines.push(' ' + pad(alias, 14) +
|
|
110
|
+
fg(peak >= 0.9 ? 'red' : 'cyan', progressBar(peak, acctBarWidth)) +
|
|
111
|
+
' ' + dim(`5h ${(u5 * 100).toFixed(0)}%`.padEnd(8)) +
|
|
112
|
+
dim(`7d ${(u7 * 100).toFixed(0)}%`));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
lines.push(' ' + brand('Rate-limit'));
|
|
117
|
+
lines.push(' ' + pad('5h', 6) +
|
|
118
|
+
fg('cyan', progressBar(s.utilization.lastUtil5h, barWidth)) +
|
|
119
|
+
' ' + dim(`${(s.utilization.lastUtil5h * 100).toFixed(0)}%`));
|
|
120
|
+
lines.push(' ' + pad('7d', 6) +
|
|
121
|
+
fg('cyan', progressBar(s.utilization.lastUtil7d, barWidth)) +
|
|
122
|
+
' ' + dim(`${(s.utilization.lastUtil7d * 100).toFixed(0)}%`));
|
|
123
|
+
}
|
|
105
124
|
// Overage bucket (v4.1, dario#288). Count of requests that landed in
|
|
106
125
|
// the overage bucket within the rolling window. Empty bar in normal
|
|
107
126
|
// operation; non-zero count renders in red. Hard zero IS the success
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.105",
|
|
4
4
|
"description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|