claude-code-runrate 0.2.1 → 0.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-runrate",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Claude Code run-rate — subscription burn-rate & economy for your Claude Code sessions.",
5
5
  "license": "MIT",
6
6
  "author": "Bing Ho <reps-attic-riot@duck.com>",
@@ -59,7 +59,17 @@ function tok(/** @type {number|null} */ n) {
59
59
  function fmtMins(/** @type {number|null} */ m) {
60
60
  if (m == null || !isFinite(m)) return '?';
61
61
  m = Math.max(0, Math.round(m));
62
- if (m >= 1440) { const d = Math.floor(m / 1440), hh = Math.floor((m % 1440) / 60); return hh ? `${d}d${hh}h` : `${d}d`; }
62
+ if (m >= 1440) {
63
+ const d = Math.floor(m / 1440), hh = Math.floor((m % 1440) / 60);
64
+ // A 100+ day horizon is a near-zero-burn artifact (100−used%)/rate with a
65
+ // tiny rate). Its hours are noise, and a wide value like "1000d5h" would
66
+ // overflow the sidebar's fixed 7-col time column and shove the meter bar out
67
+ // of vertical line with the sibling row (the 5h/weekly bars must align). Cap
68
+ // it so the string never exceeds 6 visible columns — compact and honest.
69
+ if (d >= 1000) return '>999d';
70
+ if (d >= 100) return `${d}d`;
71
+ return hh ? `${d}d${hh}h` : `${d}d`;
72
+ }
63
73
  const h = Math.floor(m / 60), r = m % 60;
64
74
  if (h >= 1) return r ? `${h}h${String(r).padStart(2, '0')}m` : `${h}h`;
65
75
  return `${m}m`;
package/src/sidecar.js CHANGED
@@ -12,6 +12,7 @@ const { normalizeStatus } = require('./normalize');
12
12
  const { renderEconomy } = require('./render/economy');
13
13
  const { renderFeed } = require('./render/feed');
14
14
  const { clampVisible } = require('./render/shared');
15
+ const { liveness } = require('./liveness');
15
16
  const { currentTranscriptPath, readNewLines, parseEvents } = require('./transcripts');
16
17
 
17
18
  const STATE_DIR = process.env.CCR_STATE_DIR || path.join(os.homedir(), '.ccr');
@@ -102,6 +103,16 @@ function composeFrame(stateDir, opts = {}) {
102
103
  if (feedStr) out += '\n\n' + feedStr;
103
104
  }
104
105
  } catch { /* feed is optional */ }
106
+ // Staleness annotation (never a wipe): Claude Code does not emit the status line
107
+ // during a single long operation, so the snapshot legitimately ages. Surface a
108
+ // quiet "updated Nm ago" so a stale panel reads as stale rather than broken —
109
+ // otherwise a long agent run (or a CC statusLine that stopped firing) looks like
110
+ // the sidecar just froze. See src/liveness.js + features/liveness.feature.
111
+ try {
112
+ const ageMs = now - fs.statSync(snapshot).mtimeMs;
113
+ const mark = liveness({ exited: false, ageMs }).marker;
114
+ if (mark) out += (out.endsWith('\n') ? '' : '\n') + ' ' + dim('· ' + mark);
115
+ } catch { /* snapshot mtime unknown → no marker */ }
105
116
  return clamp(out.endsWith('\n') ? out : out + '\n');
106
117
  }
107
118