@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.
Files changed (2) hide show
  1. package/index.ts +35 -7
  2. 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 usage = theme.fg("thinkingHigh", "Usage:") + " " + 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`) + theme.fg("dim", " · (Today)");
1200
- const model = theme.fg("dim", footerModelLabel(ctx));
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
- const refreshFooter = (ctx: Pick<ExtensionCommandContext, "hasUI" | "ui" | "model" | "thinkingLevel">) => {
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) => { snapshotPrompt(ctx); refreshFooter(ctx); });
1225
- 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
+ });
1226
1254
  pi.on("model_select", (_event, ctx) => { refreshFooter(ctx); });
1227
1255
  pi.registerCommand("usage", {
1228
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.6",
3
+ "version": "0.1.8",
4
4
  "description": "Local token and cost dashboard for pi sessions",
5
5
  "keywords": [
6
6
  "pi-package",