Live token/cost band above the prompt, with /warm-cache keep-alive counter.

Live token/cost band above the prompt, with /warm-cache keep-alive counter.
claude plugin marketplace add kenhuangus/claude-code-mods-pack
claude plugin install usage-meter@kenhuang-modshooks/usage-meter.mjs 59 lines1const SNAP = { plugin: "usage-meter", key: "snapshot" };
2const WARM = { plugin: "usage-meter", key: "warmPings" };
3function short(n) {
4 if (n >= 1_000_000) return `${+(n / 1_000_000).toFixed(1)}M`;
5 if (n >= 1_000) return `${+(n / 1_000).toFixed(1)}k`;
6 return String(n);
7}
8async function readUsage($) {
9 const usage = await $.session.usage();
10 const context = usage?.context;
11 if (!context?.window) return null;
12 const tokens = context.tokens ?? 0;
13 const percent = context.percent ?? Math.round((tokens / context.window) * 100);
14 const costUsd = typeof usage?.cost?.totalUsd === "number" ? usage.cost.totalUsd : undefined;
15 return { tokens, window: context.window, percent, costUsd };
16}
17export function register(on) {
18 on("session.start", async ($, e, next) => {
19 const r = await next(e);
20 await $.state.set(WARM, 0);
21 const snap = await readUsage($);
22 if (snap) await $.state.set(SNAP, snap);
23 await $.command.register({ name: "warm-cache", description: "Record a prompt-cache keep-warm ping" });
24 return r;
25 });
26 on("turn.complete", async ($, e, next) => {
27 const r = await next(e);
28 if (!e.agentId) {
29 const snap = await readUsage($);
30 if (snap) await $.state.set(SNAP, snap);
31 }
32 return r;
33 });
34 on("command.run", { command: "warm-cache" }, async ($) => {
35 const { value: n = 0 } = await $.state.get(WARM);
36 const nextN = n + 1;
37 await $.state.set(WARM, nextN);
38 const snap = (await readUsage($)) || { tokens: 0, window: 200000, percent: 0 };
39 await $.state.set(SNAP, snap);
40 return { text: `Cache keep-warm ping #${nextN} recorded.` };
41 });
42 on("ui.render", { component: "AbovePrompt" }, async ($, e, next) => {
43 if (e.props?.hasSurvey) return next(e);
44 const { value: snap } = await $.state.get(SNAP);
45 const { value: warm = 0 } = await $.state.get(WARM);
46 if (!snap) return next(e);
47 const { Box, Text } = $.ui.resolve(e);
48 const cost = typeof snap.costUsd === "number" ? ` $${snap.costUsd.toFixed(3)}` : "";
49 return Box({
50 flexDirection: "row",
51 paddingX: 1,
52 children: [
53 Text({ color: snap.percent >= 85 ? "red" : snap.percent >= 60 ? "yellow" : "green", bold: true, children: `USAGE ${snap.percent}%` }),
54 Text({ dimColor: true, children: ` ${short(snap.tokens)} / ${short(snap.window)}${cost} warm:${warm}` }),
55 ],
56 });
57 });
58}
59types/index.d.ts 9 lines1declare module "claude-code" {
2 interface PluginState {
3 "usage-meter": {
4 snapshot: { tokens: number; window: number; percent: number; costUsd?: number };
5 warmPings: number;
6 };
7 }
8}
9