claude-token-saver 2.14.1 → 2.14.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/bin/cli.js CHANGED
@@ -24,7 +24,7 @@
24
24
 
25
25
  import { readFileSync } from 'node:fs';
26
26
  import { fileURLToPath } from 'node:url';
27
- import { dirname, join } from 'node:path';
27
+ import { dirname, isAbsolute, join } from 'node:path';
28
28
 
29
29
  /**
30
30
  * Read the JSON blob Claude Code feeds the statusline command on stdin.
@@ -804,12 +804,16 @@ async function main() {
804
804
  process.stderr.write('Scanning session files...\n');
805
805
  }
806
806
 
807
- // Exclude the current Claude Code session when computing lastActivity
808
- // otherwise the agent's own tool calls reset the countdown every few seconds.
807
+ // The current Claude Code session is only excluded from the lastActivity
808
+ // timer (so the agent's own tool calls don't reset the countdown). It MUST
809
+ // still feed ttlBreakdown — otherwise when the user's only recent traffic
810
+ // lives in the current session, the bucket signal collapses to empty and
811
+ // the statusline falsely flips to the 5m default. (See issue: Max users
812
+ // seeing "Cache expires 5:00" on idle even though their plan is 1h.)
809
813
  const excludeSessionPath =
810
814
  getArg('--exclude-session') || process.env.CACHE_MONITOR_EXCLUDE_SESSION || undefined;
811
815
 
812
- const sessions = await parseAllSessions({ days, projectFilter, excludeSessionPath });
816
+ const sessions = await parseAllSessions({ days, projectFilter });
813
817
 
814
818
  if (sessions.length === 0) {
815
819
  // Statusline must always emit a single line (no multi-line help spam every 300ms)
@@ -913,10 +917,16 @@ async function main() {
913
917
  }
914
918
 
915
919
  // Last API activity feeds the statusline TTL countdown.
916
- // For every session that wasn't excluded, take the full endTime (any API call
917
- // keeps the prefix cache warm — it doesn't matter whether it's user- or
918
- // agent-driven because the cache is shared across sessions by prefix content).
920
+ // For every session OTHER than the excluded (current) one, take the full
921
+ // endTime (any API call keeps the prefix cache warm — it doesn't matter
922
+ // whether it's user- or agent-driven because the cache is shared across
923
+ // sessions by prefix content). The current session is filtered here rather
924
+ // than at the parser, so its writes still inform ttlBreakdown above.
925
+ const excludeAbs = excludeSessionPath
926
+ ? (isAbsolute(excludeSessionPath) ? excludeSessionPath : join(process.cwd(), excludeSessionPath))
927
+ : null;
919
928
  const otherLastActivity = sessions
929
+ .filter((s) => !excludeAbs || s.filePath !== excludeAbs)
920
930
  .map((s) => (s.endTime ? s.endTime.getTime() : 0))
921
931
  .reduce((a, b) => Math.max(a, b), 0);
922
932
  // For the excluded (current) session, only the user's prompts count — the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-token-saver",
3
- "version": "2.14.1",
3
+ "version": "2.14.2",
4
4
  "description": "Save tokens on Claude Code — spike diagnosis, 1M-context detection, TTL countdown, statusline. (formerly claude-cache-monitor)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -158,9 +158,14 @@ export function formatReport(data, { color = true, verbose = false, timer = true
158
158
 
159
159
  // TTL dominance → color signal (1h = good, 5m = warning).
160
160
  // The subscription plan fixes this, so the bucket rarely changes — it's the countdown that matters.
161
- const is1h = ttl.pct1h >= 0.5;
162
- const bucketLabel = is1h ? '1h' : '5m';
163
- const bucketColor = is1h ? GREEN : YELLOW;
161
+ // When ttl.total === 0 (no cache writes observed in the window), we cannot
162
+ // infer the bucket. Default to 1h-sized countdown rather than 5m so Max
163
+ // users on idle don't see a misleading "Cache expires 5:00". The bucket
164
+ // label is shown as "?" so the uncertainty is visible.
165
+ const hasTtlData = ttl.total > 0;
166
+ const is1h = hasTtlData ? ttl.pct1h >= 0.5 : true;
167
+ const bucketLabel = hasTtlData ? (is1h ? '1h' : '5m') : '?';
168
+ const bucketColor = hasTtlData ? (is1h ? GREEN : YELLOW) : GRAY;
164
169
  const ttlSeconds = is1h ? 3600 : 300;
165
170
 
166
171
  const savings = cost?.savings ?? 0;