nomnomtokens 0.5.0 → 0.6.0

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/README.md CHANGED
@@ -61,15 +61,18 @@ live updates.
61
61
  The hook doubles as a real status line:
62
62
 
63
63
  ```
64
- (^u^) $4.20 ctx 37% 7d 81% ·4d3h 5h 73% ·1h47m 138 lines
64
+ Limits: 7d 81% 4d3h | 5h 73% 1h47m | ctx. 37% | Opus 4.6
65
65
  ```
66
66
 
67
- The countdown after each window is the time left until it resets: the
68
- percentage tells you whether to slow down, the countdown tells you what slowing
69
- down would cost. It is omitted when Claude Code sends no `resets_at`. The
70
- weekly window is shown first when it is the tighter of the two. If Claude's
71
- week is nearly full and a recent Codex snapshot in the store still has
72
- headroom, a `codex 7d N%` suffix is appended.
67
+ The labels `7d`, `5h`, and `ctx`, and the session model name, are cyan; the
68
+ figures stay the default colour. The model is Claude's `display_name` for
69
+ whatever is selected in this session. The countdown after each percentage is
70
+ the time left until that
71
+ window resets. It is omitted when there is no `resets_at`. If this render's
72
+ payload has no `rate_limits` yet — typical before the first request of a
73
+ session — the last stored snapshot is shown instead, as long as that window
74
+ has not reset. If Claude's week is nearly full and a recent Codex snapshot
75
+ in the store still has headroom, a `codex: N%` segment is appended.
73
76
 
74
77
  ## Commands
75
78
 
package/dist/index.js CHANGED
@@ -5303,13 +5303,6 @@ function forecastLimit(snapshots, now = Date.now()) {
5303
5303
  samples: current.length
5304
5304
  };
5305
5305
  }
5306
- function moodFor(usedPct) {
5307
- if (usedPct < 5) return "hungry";
5308
- if (usedPct < 50) return "content";
5309
- if (usedPct < 80) return "full";
5310
- if (usedPct < 100) return "stuffed";
5311
- return "overstuffed";
5312
- }
5313
5306
 
5314
5307
  // packages/core/src/export-format.ts
5315
5308
  var CSV_HEADERS = [
@@ -8443,45 +8436,43 @@ async function serve(opts = {}) {
8443
8436
  }
8444
8437
 
8445
8438
  // packages/cli/src/statusline-render.ts
8446
- var MOOD_FACE = {
8447
- hungry: "(\u30FB_\u30FB)",
8448
- content: "(^_^)",
8449
- full: "(\uFF3E\uFF55\uFF3E)",
8450
- stuffed: "(>_<)",
8451
- overstuffed: "(x_x)"
8452
- };
8453
8439
  var CLAUDE_WEEKLY_HINT = 80;
8454
8440
  var CODEX_HEADROOM = 50;
8441
+ var ESC2 = "\x1B";
8442
+ function paintLabel(label) {
8443
+ if (process.env.NO_COLOR !== void 0) return label;
8444
+ return `${ESC2}[36m${label}${ESC2}[0m`;
8445
+ }
8455
8446
  function limitSegment(label, usedPct, resetsAtSeconds, now) {
8456
8447
  const resetsAt = typeof resetsAtSeconds === "number" && Number.isFinite(resetsAtSeconds) ? resetsAtSeconds * 1e3 : null;
8457
8448
  const left = untilReset(resetsAt, now);
8458
- return `${label} ${Math.round(usedPct)}%${left ? ` \xB7${left}` : ""}`;
8449
+ const head = `${paintLabel(label)} ${Math.round(usedPct)}%`;
8450
+ return left ? `${head} ${left}` : head;
8451
+ }
8452
+ function resolveWindow(livePct, liveResetsAtSeconds, cached, now) {
8453
+ if (livePct !== null) {
8454
+ return { pct: livePct, resetsAtSeconds: liveResetsAtSeconds };
8455
+ }
8456
+ if (cached && cached.resetsAt !== null && cached.resetsAt > now) {
8457
+ return { pct: cached.usedPct, resetsAtSeconds: cached.resetsAt / 1e3 };
8458
+ }
8459
+ return { pct: null };
8459
8460
  }
8460
8461
  function buildStatuslineParts(view) {
8461
8462
  const now = view.now;
8462
8463
  const five = view.fiveHour;
8463
8464
  const seven = view.sevenDay;
8464
- const moodPct = Math.max(five ?? 0, seven ?? 0);
8465
- const parts = [];
8466
- parts.push(MOOD_FACE[moodFor(moodPct)] ?? "(^_^)");
8467
- if (view.cost !== null) parts.push(usd(view.cost));
8468
- if (view.ctx !== null) parts.push(`ctx ${Math.round(view.ctx)}%`);
8469
- const fiveSeg = five !== null ? limitSegment("5h", five, view.fiveHourResetsAt, now) : null;
8470
- const sevenSeg = seven !== null ? limitSegment("7d", seven, view.sevenDayResetsAt, now) : null;
8471
- const weeklyFirst = seven !== null && (five === null || seven >= five);
8472
- if (weeklyFirst) {
8473
- if (sevenSeg) parts.push(sevenSeg);
8474
- if (fiveSeg) parts.push(fiveSeg);
8475
- } else {
8476
- if (fiveSeg) parts.push(fiveSeg);
8477
- if (sevenSeg) parts.push(sevenSeg);
8478
- }
8479
- if (view.lines > 0) parts.push(`${compactNumber(view.lines)} lines`);
8465
+ const segments = [];
8466
+ if (seven !== null) segments.push(limitSegment("7d", seven, view.sevenDayResetsAt, now));
8467
+ if (five !== null) segments.push(limitSegment("5h", five, view.fiveHourResetsAt, now));
8468
+ if (view.ctx !== null) segments.push(`${paintLabel("ctx")}. ${Math.round(view.ctx)}%`);
8469
+ const model = view.model?.trim();
8470
+ if (model) segments.push(paintLabel(model));
8480
8471
  const codex = view.codexSevenDay;
8481
8472
  if (seven !== null && seven >= CLAUDE_WEEKLY_HINT && typeof codex === "number" && Number.isFinite(codex) && codex <= CODEX_HEADROOM) {
8482
- parts.push(`codex 7d ${Math.round(codex)}%`);
8473
+ segments.push(`${paintLabel("codex")}: ${Math.round(codex)}%`);
8483
8474
  }
8484
- return parts;
8475
+ return segments.length === 0 ? "Limits:" : `Limits: ${segments.join(" | ")}`;
8485
8476
  }
8486
8477
 
8487
8478
  // packages/cli/src/commands/statusline.ts
@@ -8491,18 +8482,24 @@ async function readStdin() {
8491
8482
  for await (const chunk of process.stdin) chunks.push(chunk);
8492
8483
  return Buffer.concat(chunks).toString("utf8");
8493
8484
  }
8494
- function readCodexWeekly(db) {
8485
+ function readStoredLimits(db, now = Date.now()) {
8486
+ const empty = { codexSevenDay: null, claudeFive: null, claudeSeven: null };
8495
8487
  try {
8496
8488
  const { sqlite } = openDb(db);
8497
- const q = new Queries(sqlite);
8498
- const latest = q.latestLimits();
8489
+ const latest = new Queries(sqlite).latestLimits();
8499
8490
  sqlite.close();
8500
- const row = latest.find((l) => l.provider === "codex" && l.window === "7d");
8501
- if (!row) return null;
8502
- if (Date.now() - row.ts > CODEX_FRESH_MS) return null;
8503
- return row.usedPct;
8491
+ const claude = (window) => {
8492
+ const row = latest.find((l) => l.provider === "claude-code" && l.window === window);
8493
+ return row ? { usedPct: row.usedPct, resetsAt: row.resetsAt } : null;
8494
+ };
8495
+ const codex = latest.find((l) => l.provider === "codex" && l.window === "7d");
8496
+ return {
8497
+ codexSevenDay: codex && now - codex.ts <= CODEX_FRESH_MS ? codex.usedPct : null,
8498
+ claudeFive: claude("5h"),
8499
+ claudeSeven: claude("7d")
8500
+ };
8504
8501
  } catch {
8505
- return null;
8502
+ return empty;
8506
8503
  }
8507
8504
  }
8508
8505
  async function statusline(opts = {}) {
@@ -8514,23 +8511,33 @@ async function statusline(opts = {}) {
8514
8511
  return;
8515
8512
  }
8516
8513
  const limits2 = payload.rate_limits;
8517
- const fiveHour = limits2?.five_hour?.used_percentage ?? null;
8518
- const sevenDay = limits2?.seven_day?.used_percentage ?? null;
8519
- const cost = payload.cost?.total_cost_usd ?? null;
8514
+ const now = Date.now();
8515
+ const stored = readStoredLimits(opts.db, now);
8516
+ const five = resolveWindow(
8517
+ limits2?.five_hour?.used_percentage ?? null,
8518
+ limits2?.five_hour?.resets_at,
8519
+ stored.claudeFive,
8520
+ now
8521
+ );
8522
+ const seven = resolveWindow(
8523
+ limits2?.seven_day?.used_percentage ?? null,
8524
+ limits2?.seven_day?.resets_at,
8525
+ stored.claudeSeven,
8526
+ now
8527
+ );
8520
8528
  const ctx = payload.context_window?.used_percentage ?? null;
8521
- const lines = (payload.cost?.total_lines_added ?? 0) + (payload.cost?.total_lines_removed ?? 0);
8522
- const codexSevenDay = readCodexWeekly(opts.db);
8523
- const parts = buildStatuslineParts({
8524
- fiveHour,
8525
- sevenDay,
8526
- fiveHourResetsAt: limits2?.five_hour?.resets_at,
8527
- sevenDayResetsAt: limits2?.seven_day?.resets_at,
8528
- cost,
8529
+ const model = payload.model?.display_name?.trim() || payload.model?.id?.trim() || null;
8530
+ const line = buildStatuslineParts({
8531
+ fiveHour: five.pct,
8532
+ sevenDay: seven.pct,
8533
+ fiveHourResetsAt: five.resetsAtSeconds,
8534
+ sevenDayResetsAt: seven.resetsAtSeconds,
8529
8535
  ctx,
8530
- lines,
8531
- codexSevenDay
8536
+ model,
8537
+ codexSevenDay: stored.codexSevenDay,
8538
+ now
8532
8539
  });
8533
- process.stdout.write(`${parts.join(" ")}
8540
+ process.stdout.write(`${line}
8534
8541
  `);
8535
8542
  if (opts.dryRun) return;
8536
8543
  try {