@po.dev/pi-usage-dashboard 0.1.7 → 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.
Files changed (2) hide show
  1. package/index.ts +27 -5
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -1192,7 +1192,7 @@ 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" | "getContextUsage">, 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[] {
@@ -1202,7 +1202,10 @@ function setUsageFooter(ctx: Pick<ExtensionCommandContext, "ui" | "model" | "thi
1202
1202
  const contextStatus = context
1203
1203
  ? " · " + theme.fg("warning", `${context.percent?.toFixed(1) ?? "?"}%`) + theme.fg("dim", "/") + theme.fg("success", `${left} left`) + " " + theme.fg("accent", "(auto)")
1204
1204
  : "";
1205
- const usage = theme.fg("thinkingHigh", "Usage:") + " " + 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;
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;
1206
1209
  const model = theme.fg("accent", footerModelLabel(ctx));
1207
1210
  const gap = width - visibleWidth(usage) - visibleWidth(model);
1208
1211
  return [gap >= 2 ? usage + " ".repeat(gap) + model : truncateToWidth(usage, width)];
@@ -1211,6 +1214,8 @@ function setUsageFooter(ctx: Pick<ExtensionCommandContext, "ui" | "model" | "thi
1211
1214
  }
1212
1215
 
1213
1216
  export default function (pi: ExtensionAPI) {
1217
+ let sessionTotals: TotalStats = { sessions: 0, messages: 0, cost: 0, tokens: { total: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } };
1218
+
1214
1219
  const refreshFooter = (ctx: Pick<ExtensionCommandContext, "hasUI" | "ui" | "model" | "thinkingLevel" | "getContextUsage">) => {
1215
1220
  if (!ctx.hasUI) return;
1216
1221
  void collectUsageData().then((data) => {
@@ -1221,14 +1226,31 @@ export default function (pi: ExtensionAPI) {
1221
1226
  totals.messages += stats.messages; totals.cost += stats.cost;
1222
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;
1223
1228
  }
1224
- setUsageFooter(ctx, totals);
1229
+ setUsageFooter(ctx, totals, sessionTotals);
1225
1230
  });
1226
1231
  };
1227
1232
  const snapshotPrompt = (ctx: { sessionManager: { getSessionId(): string }; getSystemPrompt(): string }) => {
1228
1233
  try { savePromptSnapshot(ctx.sessionManager.getSessionId(), ctx.getSystemPrompt()); } catch { /* usage must never block Pi */ }
1229
1234
  };
1230
- pi.on("session_start", (_event, ctx) => { snapshotPrompt(ctx); refreshFooter(ctx); });
1231
- pi.on("message_end", (_event, ctx) => { snapshotPrompt(ctx); refreshFooter(ctx); });
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
+ });
1232
1254
  pi.on("model_select", (_event, ctx) => { refreshFooter(ctx); });
1233
1255
  pi.registerCommand("usage", {
1234
1256
  description: "Show usage statistics dashboard",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@po.dev/pi-usage-dashboard",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Local token and cost dashboard for pi sessions",
5
5
  "keywords": [
6
6
  "pi-package",