@po.dev/pi-usage-dashboard 0.1.6 → 0.1.8
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/index.ts +35 -7
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -1192,12 +1192,21 @@ function footerModelLabel(ctx: Pick<ExtensionCommandContext, "model" | "thinking
|
|
|
1192
1192
|
return model.reasoning && ctx.thinkingLevel ? `${label} • ${ctx.thinkingLevel}` : label;
|
|
1193
1193
|
}
|
|
1194
1194
|
|
|
1195
|
-
function setUsageFooter(ctx: Pick<ExtensionCommandContext, "ui" | "model" | "thinkingLevel">, totals: TotalStats): void {
|
|
1195
|
+
function setUsageFooter(ctx: Pick<ExtensionCommandContext, "ui" | "model" | "thinkingLevel" | "getContextUsage">, totals: TotalStats, sessionTotals: TotalStats | null): void {
|
|
1196
1196
|
ctx.ui.setFooter((_tui, theme) => ({
|
|
1197
1197
|
invalidate() {},
|
|
1198
1198
|
render(width: number): string[] {
|
|
1199
|
-
const
|
|
1200
|
-
const
|
|
1199
|
+
const context = ctx.getContextUsage();
|
|
1200
|
+
const compactAt = context ? context.contextWindow - 16_384 : 0;
|
|
1201
|
+
const left = context?.tokens === null ? "?" : context ? formatTokens(Math.max(0, compactAt - context.tokens)) : "?";
|
|
1202
|
+
const contextStatus = context
|
|
1203
|
+
? " · " + theme.fg("warning", `${context.percent?.toFixed(1) ?? "?"}%`) + theme.fg("dim", "/") + theme.fg("success", `${left} left`) + " " + theme.fg("accent", "(auto)")
|
|
1204
|
+
: "";
|
|
1205
|
+
const sessionPart = sessionTotals
|
|
1206
|
+
? theme.fg("success", "(Session)") + " · " + theme.fg("accent", formatCost(sessionTotals.cost)) + " · " + theme.fg("text", `${formatTokens(sessionTotals.tokens.total)} tokens`) + " · " + theme.fg("success", `↑${formatTokens(sessionTotals.tokens.input + sessionTotals.tokens.cacheWrite)}`) + " · " + theme.fg("warning", `↓${formatTokens(sessionTotals.tokens.output)}`) + " "
|
|
1207
|
+
: "";
|
|
1208
|
+
const usage = theme.fg("thinkingHigh", "Usage:") + " " + sessionPart + theme.fg("accent", "(Today)") + " · " + theme.fg("accent", formatCost(totals.cost)) + " · " + theme.fg("text", `${formatTokens(totals.tokens.total)} tokens`) + " · " + theme.fg("success", `↑${formatTokens(totals.tokens.input + totals.tokens.cacheWrite)}`) + " · " + theme.fg("warning", `↓${formatTokens(totals.tokens.output)}`) + " · " + theme.fg("thinkingHigh", `${formatTokens(totals.tokens.cacheRead + totals.tokens.cacheWrite)} cache`) + contextStatus;
|
|
1209
|
+
const model = theme.fg("accent", footerModelLabel(ctx));
|
|
1201
1210
|
const gap = width - visibleWidth(usage) - visibleWidth(model);
|
|
1202
1211
|
return [gap >= 2 ? usage + " ".repeat(gap) + model : truncateToWidth(usage, width)];
|
|
1203
1212
|
},
|
|
@@ -1205,7 +1214,9 @@ function setUsageFooter(ctx: Pick<ExtensionCommandContext, "ui" | "model" | "thi
|
|
|
1205
1214
|
}
|
|
1206
1215
|
|
|
1207
1216
|
export default function (pi: ExtensionAPI) {
|
|
1208
|
-
|
|
1217
|
+
let sessionTotals: TotalStats = { sessions: 0, messages: 0, cost: 0, tokens: { total: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } };
|
|
1218
|
+
|
|
1219
|
+
const refreshFooter = (ctx: Pick<ExtensionCommandContext, "hasUI" | "ui" | "model" | "thinkingLevel" | "getContextUsage">) => {
|
|
1209
1220
|
if (!ctx.hasUI) return;
|
|
1210
1221
|
void collectUsageData().then((data) => {
|
|
1211
1222
|
if (!data) return;
|
|
@@ -1215,14 +1226,31 @@ export default function (pi: ExtensionAPI) {
|
|
|
1215
1226
|
totals.messages += stats.messages; totals.cost += stats.cost;
|
|
1216
1227
|
totals.tokens.total += stats.tokens.total; totals.tokens.input += stats.tokens.input; totals.tokens.output += stats.tokens.output; totals.tokens.cacheRead += stats.tokens.cacheRead; totals.tokens.cacheWrite += stats.tokens.cacheWrite;
|
|
1217
1228
|
}
|
|
1218
|
-
setUsageFooter(ctx, totals);
|
|
1229
|
+
setUsageFooter(ctx, totals, sessionTotals);
|
|
1219
1230
|
});
|
|
1220
1231
|
};
|
|
1221
1232
|
const snapshotPrompt = (ctx: { sessionManager: { getSessionId(): string }; getSystemPrompt(): string }) => {
|
|
1222
1233
|
try { savePromptSnapshot(ctx.sessionManager.getSessionId(), ctx.getSystemPrompt()); } catch { /* usage must never block Pi */ }
|
|
1223
1234
|
};
|
|
1224
|
-
pi.on("session_start", (_event, ctx) => {
|
|
1225
|
-
|
|
1235
|
+
pi.on("session_start", (_event, ctx) => {
|
|
1236
|
+
sessionTotals = { sessions: 0, messages: 0, cost: 0, tokens: { total: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } };
|
|
1237
|
+
snapshotPrompt(ctx);
|
|
1238
|
+
refreshFooter(ctx);
|
|
1239
|
+
});
|
|
1240
|
+
pi.on("message_end", (event, ctx) => {
|
|
1241
|
+
if (event.message.role === "assistant") {
|
|
1242
|
+
const u = event.message.usage;
|
|
1243
|
+
sessionTotals.messages++;
|
|
1244
|
+
sessionTotals.cost += u.cost.total;
|
|
1245
|
+
sessionTotals.tokens.total += u.totalTokens;
|
|
1246
|
+
sessionTotals.tokens.input += u.input;
|
|
1247
|
+
sessionTotals.tokens.output += u.output;
|
|
1248
|
+
sessionTotals.tokens.cacheRead += u.cacheRead;
|
|
1249
|
+
sessionTotals.tokens.cacheWrite += u.cacheWrite;
|
|
1250
|
+
}
|
|
1251
|
+
snapshotPrompt(ctx);
|
|
1252
|
+
refreshFooter(ctx);
|
|
1253
|
+
});
|
|
1226
1254
|
pi.on("model_select", (_event, ctx) => { refreshFooter(ctx); });
|
|
1227
1255
|
pi.registerCommand("usage", {
|
|
1228
1256
|
description: "Show usage statistics dashboard",
|