@tmustier/pi-usage-extension 0.6.0 → 0.6.1
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/CHANGELOG.md +5 -0
- package/README.md +3 -2
- package/graph.ts +29 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.1] - 2026-07-17
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Graph lines are clipped to each series' active range (first to last bucket with usage). Applies to every grouping — provider, model, thinking level, `other`, and Total — so a model that starts late (e.g. reasoning tokens, only recorded since pi 0.80.3) or gets retired no longer draws a flat zero/flat cumulative tail across the whole period.
|
|
7
|
+
|
|
3
8
|
## [0.6.0] - 2026-07-17
|
|
4
9
|
|
|
5
10
|
### Added
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A Pi extension that displays aggregated usage statistics across all sessions.
|
|
|
7
7
|
## Compatibility
|
|
8
8
|
|
|
9
9
|
- **Pi version:** 0.42.4+
|
|
10
|
-
- **Last updated:** 2026-07-17 (0.6.
|
|
10
|
+
- **Last updated:** 2026-07-17 (0.6.1)
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -76,8 +76,9 @@ The **Graphs** view plots usage over time for the active period as a braille lin
|
|
|
76
76
|
- **Cumulative vs per-bucket** (`c` to toggle): running total across the period (default), or the raw per-bucket rate.
|
|
77
77
|
- **Filtering**: move the legend cursor with `↑`/`↓` and toggle series visibility with `Enter`/`Space` (`a` shows all again). The y-axis rescales to the visible series — hide the big lines to zoom into the small ones.
|
|
78
78
|
- **Buckets**: hourly for Today / This Week / Last Week, daily for Last 30 Days / All Time.
|
|
79
|
+
- **Line clipping**: every series (provider, model, thinking level, `other`, Total) is drawn only between its first and last bucket with usage, so late-starting or retired series don't drag a flat zero/flat tail across the whole period.
|
|
79
80
|
|
|
80
|
-
Thinking levels are replayed from `thinking_level_change` entries in each session file; messages before the first recorded change appear as `unknown`. Reasoning token counts come from `usage.reasoning` where providers report them.
|
|
81
|
+
Thinking levels are replayed from `thinking_level_change` entries in each session file; messages before the first recorded change appear as `unknown`. Reasoning token counts come from `usage.reasoning` where providers report them; pi only records this field since **pi 0.80.3 (30 June 2026)**, so earlier sessions show zero reasoning tokens even though thinking models were in use.
|
|
81
82
|
|
|
82
83
|
The insights currently shown:
|
|
83
84
|
|
package/graph.ts
CHANGED
|
@@ -60,6 +60,10 @@ export interface GraphSeries {
|
|
|
60
60
|
/** Period total for this series (not affected by cumulative). */
|
|
61
61
|
total: number;
|
|
62
62
|
hidden: boolean;
|
|
63
|
+
/** First bucket index with activity, or -1 when the series is empty. */
|
|
64
|
+
firstIdx: number;
|
|
65
|
+
/** Last bucket index with activity, or -1 when the series is empty. */
|
|
66
|
+
lastIdx: number;
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
export interface GraphModel {
|
|
@@ -183,21 +187,40 @@ export function buildGraphModel(
|
|
|
183
187
|
const hidden = options.hidden ?? new Set<string>();
|
|
184
188
|
const series: GraphSeries[] = [];
|
|
185
189
|
|
|
190
|
+
// Active range per series (computed on raw per-bucket values, before any
|
|
191
|
+
// cumulative transform): lines are later drawn only between the first and
|
|
192
|
+
// last bucket with usage, so late-starting or retired series do not drag a
|
|
193
|
+
// flat zero/flat tail across the whole period.
|
|
194
|
+
const activeRange = (points: number[]): { firstIdx: number; lastIdx: number } => {
|
|
195
|
+
let firstIdx = -1;
|
|
196
|
+
let lastIdx = -1;
|
|
197
|
+
for (let i = 0; i < points.length; i++) {
|
|
198
|
+
if (points[i] !== 0) {
|
|
199
|
+
if (firstIdx === -1) firstIdx = i;
|
|
200
|
+
lastIdx = i;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return { firstIdx, lastIdx };
|
|
204
|
+
};
|
|
205
|
+
|
|
186
206
|
series.push({
|
|
187
207
|
key: TOTAL_SERIES_KEY,
|
|
188
208
|
label: "Total",
|
|
189
209
|
points: totalPoints.slice(),
|
|
190
210
|
total: totalSum,
|
|
191
211
|
hidden: hidden.has(TOTAL_SERIES_KEY),
|
|
212
|
+
...activeRange(totalPoints),
|
|
192
213
|
});
|
|
193
214
|
|
|
194
215
|
for (const [groupKey, total] of kept) {
|
|
216
|
+
const points = groupValues.get(groupKey)!;
|
|
195
217
|
series.push({
|
|
196
218
|
key: groupKey,
|
|
197
219
|
label: groupKey,
|
|
198
|
-
points
|
|
220
|
+
points,
|
|
199
221
|
total,
|
|
200
222
|
hidden: hidden.has(groupKey),
|
|
223
|
+
...activeRange(points),
|
|
201
224
|
});
|
|
202
225
|
}
|
|
203
226
|
|
|
@@ -215,6 +238,7 @@ export function buildGraphModel(
|
|
|
215
238
|
points,
|
|
216
239
|
total,
|
|
217
240
|
hidden: hidden.has(OTHER_SERIES_KEY),
|
|
241
|
+
...activeRange(points),
|
|
218
242
|
});
|
|
219
243
|
}
|
|
220
244
|
|
|
@@ -295,10 +319,11 @@ export function renderChart(model: GraphModel, options: ChartRenderOptions): str
|
|
|
295
319
|
const yMax = model.yMax > 0 ? model.yMax : 1;
|
|
296
320
|
const bucketCount = model.bucketStarts.length;
|
|
297
321
|
|
|
298
|
-
const plot = (seriesIndex: number, points: number[]) => {
|
|
322
|
+
const plot = (seriesIndex: number, points: number[], firstIdx: number, lastIdx: number) => {
|
|
323
|
+
if (firstIdx < 0) return;
|
|
299
324
|
let prevX = -1;
|
|
300
325
|
let prevY = -1;
|
|
301
|
-
for (let i =
|
|
326
|
+
for (let i = firstIdx; i <= lastIdx; i++) {
|
|
302
327
|
const x = bucketCount === 1 ? dotW - 1 : Math.round((i / (bucketCount - 1)) * (dotW - 1));
|
|
303
328
|
const y = Math.round((1 - (points[i]! / yMax)) * (dotH - 1));
|
|
304
329
|
if (prevX >= 0) {
|
|
@@ -335,7 +360,7 @@ export function renderChart(model: GraphModel, options: ChartRenderOptions): str
|
|
|
335
360
|
entry.s.key === TOTAL_SERIES_KEY ? Number.POSITIVE_INFINITY : entry.s.key === OTHER_SERIES_KEY ? -1 : entry.s.total;
|
|
336
361
|
return rank(a) - rank(b);
|
|
337
362
|
});
|
|
338
|
-
for (const { s, i } of drawOrder) plot(i, s.points);
|
|
363
|
+
for (const { s, i } of drawOrder) plot(i, s.points, s.firstIdx, s.lastIdx);
|
|
339
364
|
|
|
340
365
|
// Compose text rows.
|
|
341
366
|
const lines: string[] = [];
|