claude-token-saver 2.8.4 → 2.8.6

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.en.md CHANGED
@@ -13,18 +13,21 @@ A CLI to **diagnose and save tokens on Claude Code**. Cache hit rate, TTL countd
13
13
  ## Install
14
14
 
15
15
  ```bash
16
- # 1. (existing users) remove the old package
16
+ # (existing users) remove the old package
17
17
  npm uninstall -g claude-cache-monitor
18
18
 
19
- # 2. install
19
+ # install — the postinstall hook auto-registers the Skill and statusline
20
20
  npm i -g claude-token-saver
21
-
22
- # 3. wire into Claude Code (Skill + statusline guidance)
23
- claude-token-saver install
24
21
  ```
25
22
 
26
23
  Or run once with no install: `npx claude-token-saver`.
27
24
 
25
+ If postinstall was skipped (e.g. `--ignore-scripts`, sudo, or sandboxed installs), register manually:
26
+
27
+ ```bash
28
+ claude-token-saver install
29
+ ```
30
+
28
31
  ## What you see after install
29
32
 
30
33
  **(A) One-shot report** — `claude-token-saver`:
@@ -67,7 +70,7 @@ Risk chips lead when something's wrong: `🚨 5H 94%`, `⚠ 1M ON`, `⚠ Cache m
67
70
  | `claude-token-saver` | Last 30 days diagnostic report |
68
71
  | `claude-token-saver --days 7` | Change window |
69
72
  | `claude-token-saver --statusline --icon` | One-line statusline output |
70
- | `claude-token-saver install` | Register Claude Code Skill (auto-activates on chip wording) |
73
+ | `claude-token-saver install` | Manually register the Claude Code Skill (fallback when postinstall is skipped) |
71
74
  | `claude-token-saver history` | Last 7 days of chip transitions (1M ON, Cache miss, cap, …) |
72
75
  | `claude-token-saver handoff` | Back current work up to `HANDOFF-YYYY-MM-DD-HHMM.md` before a cap blocks you |
73
76
  | `claude-token-saver --install-hook` | Auto-log cache stats on every tool call |
@@ -143,6 +146,10 @@ Node.js ≥ 18 · macOS / Windows / Linux / WSL · zero dependencies.
143
146
  - [HN discussion](https://news.ycombinator.com/item?id=47736476) — 168 points, 142 comments
144
147
  - [HNPulse KR](https://www.youtube.com/@HNPulseKR) — Korean HN tech deep-dives
145
148
 
149
+ ## Known environment quirks
150
+
151
+ **IntelliJ Claude Code plugin** — the statusline widget fuses prior and current frames at the character level when emoji are in the output, producing artifacts like `Cache expires 59:548`. v2.8.5+ detects `TERMINAL_EMULATOR=JetBrains-JediTerm` and falls back to text mode automatically (`--icon` is also ignored under IntelliJ). Other terminals (iTerm, Terminal, WSL, etc.) are unaffected.
152
+
146
153
  ## License
147
154
 
148
155
  MIT
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # claude-token-saver
4
4
 
5
- > v2.0에서 `claude-cache-monitor` → `claude-token-saver`로 이름이 바뀌었습니다. 기존 사용자는 [마이그레이션](#마이그레이션-claude-cache-monitor에서) 참고.
5
+ > v2.0에서 `claude-cache-monitor` → `claude-token-saver`로 이름이 바뀌었습니다. 기존 사용자는 아래 [마이그레이션](#마이그레이션-claude-cache-monitor에서) 항목을 참고하세요.
6
6
 
7
7
  Claude Code의 **토큰 사용량을 진단·절약**하는 CLI. 캐시 히트율, TTL 카운트다운, 1M 컨텍스트 감지, 5h/7d 한도 경고를 statusline 한 줄로 보여줍니다.
8
8
 
@@ -13,18 +13,21 @@ Claude Code의 **토큰 사용량을 진단·절약**하는 CLI. 캐시 히트
13
13
  ## 설치
14
14
 
15
15
  ```bash
16
- # 1. (기존 사용자) 구 패키지 제거
16
+ # (기존 사용자) 구 패키지 제거
17
17
  npm uninstall -g claude-cache-monitor
18
18
 
19
- # 2. 설치
19
+ # 설치 — postinstall 훅이 Skill과 statusline을 자동 등록합니다
20
20
  npm i -g claude-token-saver
21
-
22
- # 3. Claude Code 통합 (Skill + statusline 안내)
23
- claude-token-saver install
24
21
  ```
25
22
 
26
23
  설치 없이 한 번만 실행하려면 `npx claude-token-saver`.
27
24
 
25
+ `--ignore-scripts`나 sudo 등으로 postinstall이 실행되지 않은 환경에서는 다음 명령으로 수동 등록할 수 있습니다.
26
+
27
+ ```bash
28
+ claude-token-saver install
29
+ ```
30
+
28
31
  ## 설치 후 보이는 것
29
32
 
30
33
  **(A) 단발 리포트** — `claude-token-saver` 실행 시:
@@ -44,7 +47,7 @@ TTL Breakdown / Cost Impact / Daily Trend ...
44
47
  🧠 97.5% · ⏳ 1h 42:15 · 💰 $4.8K · 🤖 Opus 4.7 · ✦ 5H 47% · 📅 7D 9%
45
48
  ```
46
49
 
47
- 위험 상황에서는 칩이 앞으로 튀어나옵니다 — `🚨 5H 94%`, `⚠ 1M ON`, `⚠ Cache miss`, `⚠ 5m TTL` 등.
50
+ 위험 상황에서는 경고 칩이 앞에 표시됩니다 — `🚨 5H 94%`, `⚠ 1M ON`, `⚠ Cache miss`, `⚠ 5m TTL` 등.
48
51
 
49
52
  ## statusline 등록
50
53
 
@@ -58,7 +61,7 @@ TTL Breakdown / Cost Impact / Daily Trend ...
58
61
  }
59
62
  ```
60
63
 
61
- `refreshInterval: 5`는 TTL 카운트다운이 idle 상태에서도 5초마다 갱신되게 합니다 (1초도 가능하지만 상시 I/O 부담을 피하려고 5초를 기본값으로 권장). Windows(PowerShell) `examples/statusline-command.ps1` 참고.
64
+ `refreshInterval: 5`는 idle 상태에서도 TTL 카운트다운을 5초마다 갱신합니다 (1초도 가능하지만 상시 I/O 부담을 줄이기 위해 5초를 기본값으로 권장합니다). Windows(PowerShell) 환경은 `examples/statusline-command.ps1`을 참고하세요.
62
65
 
63
66
  ## 주요 명령
64
67
 
@@ -66,22 +69,22 @@ TTL Breakdown / Cost Impact / Daily Trend ...
66
69
  |---|---|
67
70
  | `claude-token-saver` | 최근 30일 진단 리포트 |
68
71
  | `claude-token-saver --days 7` | 기간 변경 |
69
- | `claude-token-saver --statusline --icon` | statusline용 한 줄 |
70
- | `claude-token-saver install` | Claude Code Skill 자동 등록 ( 단어 언급 시 자동 활성) |
72
+ | `claude-token-saver --statusline --icon` | statusline용 한 줄 출력 |
73
+ | `claude-token-saver install` | Claude Code Skill 수동 등록 (postinstall이 막힌 환경 대비) |
71
74
  | `claude-token-saver history` | 최근 7일간 칩 전이 로그 (1M ON, Cache miss, cap 등) |
72
75
  | `claude-token-saver handoff` | 현재 작업을 `HANDOFF-YYYY-MM-DD-HHMM.md`로 백업 (cap 임박 시) |
73
76
  | `claude-token-saver --install-hook` | 매 도구 호출마다 캐시 통계 자동 로깅 |
74
77
 
75
78
  전체 옵션은 `--help` 또는 [영문 README](./README.en.md#options).
76
79
 
77
- ## 진단되는 급증 원인
80
+ ## 토큰 급증 원인 코드
78
81
 
79
82
  | 코드 | 의미 |
80
83
  |---|---|
81
84
  | `LARGE_INPUT_PER_REQUEST` | 단일 요청 250k+ → 1M 컨텍스트 의심 |
82
- | `LOW_HIT_RATE` | 캐시 히트율 < 50% |
83
- | `BUCKET_5M_DOMINANT` | 캐시 쓰기의 70%+가 5분 버킷 (Pro 플랜 또는 Max 다운그레이드) |
84
- | `HIGH_OUTPUT_RATIO` | 출력/입력 > 0.15 (출력은 입력의 5배 가격) |
85
+ | `LOW_HIT_RATE` | 캐시 히트율 50% 미만 |
86
+ | `BUCKET_5M_DOMINANT` | 캐시 쓰기의 70% 이상이 5분 버킷에 집중 (Pro 플랜 또는 Max 다운그레이드) |
87
+ | `HIGH_OUTPUT_RATIO` | 출력/입력 비율 0.15 초과 (출력 단가가 입력의 5배) |
85
88
  | `FREQUENT_CACHE_REBUILD` | 캐시 재작성이 읽기보다 많음 |
86
89
 
87
90
  각 코드마다 OS별 해결 명령(`~/.zshrc` / `setx`)이 함께 출력됩니다.
@@ -93,16 +96,20 @@ npm uninstall -g claude-cache-monitor
93
96
  npm i -g claude-token-saver
94
97
  ```
95
98
 
96
- `~/.claude/settings.json`의 `statusLine.command`를 `claude-cache-monitor …` → `claude-token-saver …`로 교체하세요. v2.0 이전의 `claude-cache-monitor` 바이너리 별칭은 npm 충돌(EEXIST) 때문에 제거됐습니다.
99
+ `~/.claude/settings.json`의 `statusLine.command`를 `claude-cache-monitor …` → `claude-token-saver …`로 교체하세요. v2.0 잠시 제공됐던 `claude-cache-monitor` 바이너리 별칭은 글로벌 설치 시 npm 충돌(EEXIST) 일으켜 이후 버전에서 제거됐습니다.
97
100
 
98
101
  ## 동작 원리
99
102
 
100
- Claude Code는 모든 API 응답을 `~/.claude/projects/<dir>/<session>.jsonl`에 기록합니다. 이 도구는 `cache_read_input_tokens`, `cache_creation.ephemeral_5m/1h_input_tokens` 등을 `requestId`로 중복 제거 일·세션 단위로 집계합니다.
103
+ Claude Code는 모든 API 응답을 `~/.claude/projects/<dir>/<session>.jsonl`에 기록합니다. 이 도구는 `cache_read_input_tokens`, `cache_creation.ephemeral_5m/1h_input_tokens` 같은 필드를 `requestId` 기준으로 중복 제거한 일·세션 단위로 집계합니다.
101
104
 
102
105
  ## 환경
103
106
 
104
107
  Node.js ≥ 18 · macOS / Linux / Windows / WSL · 의존성 0.
105
108
 
109
+ ## 알려진 환경 이슈
110
+
111
+ **IntelliJ Claude Code plugin** — statusline 위젯이 이전 프레임과 새 프레임을 글자 단위로 잘못 합쳐 `Cache expires 59:548` 같은 잔재 문자열이 보이는 버그가 있습니다 (이모지가 포함된 출력에서만 재현). v2.8.5+는 `TERMINAL_EMULATOR=JetBrains-JediTerm`을 감지하면 자동으로 text 모드로 폴백해 이모지 없이 출력합니다 (`--icon` 플래그도 IntelliJ에서는 무시됩니다). 다른 터미널(iTerm, Terminal, WSL 등)에는 영향 없습니다.
112
+
106
113
  ## 라이선스
107
114
 
108
115
  MIT
package/bin/cli.js CHANGED
@@ -700,10 +700,21 @@ async function main() {
700
700
  const { statuslineDefaults } = await import('../src/config.js');
701
701
  const cfg = statuslineDefaults();
702
702
 
703
+ // IntelliJ's Claude Code plugin renders the statusline through a custom
704
+ // widget that fuses prior frames with the new one when emoji are present,
705
+ // producing garbage like "59:548" that no ANSI escape can clean up
706
+ // (verified: emitting the same output directly into JediTerm renders
707
+ // cleanly, so the bug is in the plugin's render path, not the terminal).
708
+ // Force text mode unconditionally inside IntelliJ — even past an explicit
709
+ // `--icon` flag, since wrappers commonly hardcode `--icon` and the user
710
+ // can't easily edit them; icon mode is just broken there.
711
+ const isIntelliJ = process.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';
703
712
  // CLI flags take precedence; otherwise fall back to persisted config.
704
- const isIcon = hasFlag('--icon')
705
- ? true
706
- : (hasFlag('--no-icon') || hasFlag('--text') ? false : cfg.icon);
713
+ const isIcon = isIntelliJ
714
+ ? false
715
+ : (hasFlag('--icon')
716
+ ? true
717
+ : (hasFlag('--no-icon') || hasFlag('--text') ? false : cfg.icon));
707
718
  const isVerbose = hasFlag('--verbose')
708
719
  ? true
709
720
  : (hasFlag('--no-verbose') || hasFlag('--compact') ? false : cfg.verbose);
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "claude-token-saver",
3
- "version": "2.8.4",
3
+ "version": "2.8.6",
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": {
7
7
  "claude-token-saver": "bin/cli.js"
8
8
  },
9
+ "scripts": {
10
+ "postinstall": "node bin/cli.js install || true"
11
+ },
9
12
  "files": [
10
13
  "bin/",
11
14
  "src/",
@@ -103,7 +103,7 @@ function formatTimer(remainingSec) {
103
103
  // Defensive: non-finite/NaN inputs (e.g. clock skew, stringified Date) used
104
104
  // to slip through and render as "NaN:NaN" or stretched seconds. Treat any
105
105
  // weird input as expired rather than rendering garbage in the statusline.
106
- if (!Number.isFinite(remainingSec) || remainingSec <= 0) return padTimer('EXPIRED');
106
+ if (!Number.isFinite(remainingSec) || remainingSec <= 0) return 'EXPIRED';
107
107
  const totalSec = Math.max(0, Math.floor(remainingSec));
108
108
  const h = Math.floor(totalSec / 3600);
109
109
  const mRaw = Math.floor((totalSec % 3600) / 60);
@@ -112,22 +112,8 @@ function formatTimer(remainingSec) {
112
112
  // truncation) can never produce m:sss like "4:547".
113
113
  const m = Math.min(59, Math.max(0, mRaw));
114
114
  const s = Math.min(59, Math.max(0, sRaw));
115
- if (h > 0) return padTimer(`${h}:${String(m).padStart(2, '0')}`);
116
- return padTimer(`${m}:${String(s).padStart(2, '0')}`);
117
- }
118
-
119
- // Pad timer text to a fixed width so transitions never shrink the visible
120
- // length. Otherwise `42:38` (5 chars) → `1:00` (4 chars) on activity reset
121
- // leaves the trailing `8` on screen → fused garbage like `1:008`. Some
122
- // terminals (JetBrains JediTerm, certain Claude Code render paths) don't
123
- // fully clear the statusline region between frames, so column-stable output
124
- // is the only reliable defense — `\x1b[K` and trailing-space padding only
125
- // help if the cursor lands at the right spot to begin with.
126
- // "EXPIRED" → "EXPIRED" (7 — already widest, used as the target width)
127
- // "59:59" → " 59:59 " no — left-pad only so the digits stay right-aligned
128
- const TIMER_WIDTH = 7;
129
- function padTimer(s) {
130
- return s.padStart(TIMER_WIDTH, ' ');
115
+ if (h > 0) return `${h}:${String(m).padStart(2, '0')}`;
116
+ return `${m}:${String(s).padStart(2, '0')}`;
131
117
  }
132
118
 
133
119
  /**
@@ -409,19 +395,8 @@ export function formatReport(data, { color = true, verbose = false, timer = true
409
395
  if (want('saved')) segs.push(saveSeg);
410
396
  if (want('period')) segs.push(periodSeg);
411
397
  // Trailing erase-to-end-of-line so any leftover characters from a previous
412
- // (longer) statusline render don't bleed into ours. Some terminals + the
413
- // Claude Code statusline integration don't fully clear the line on rewrite,
414
- // which surfaced as "Cache expires 4:574" or "Cache expires 43550" — old
415
- // digits from a prior frame leaking past the new shorter timer text.
416
- // \x1b[K is the standard "erase from cursor to EOL" CSI; safe on any
417
- // ANSI-compatible terminal and a no-op when stdout isn't a TTY.
418
- // Defensive overwrite — terminals that miscount emoji width (JetBrains JediTerm
419
- // is the known case, but others surface periodically) leave the cursor at the
420
- // wrong column, which makes trailing `\x1b[K` erase the wrong region and
421
- // leftover bytes from the previous frame fuse with the new one ("4:54" + "8"
422
- // → "4:548"). Appending a run of spaces overwrites those leftover bytes
423
- // positionally without any clear-then-redraw step (so no flicker), and is
424
- // invisible on terminals that already redraw cleanly. `\x1b[K` still mops up
425
- // anything beyond the padding.
426
- return segs.join(' · ') + ' '.repeat(40) + '\x1b[K';
398
+ // (longer) statusline render don't bleed into ours. \x1b[K is the standard
399
+ // "erase from cursor to EOL" CSI; safe on any ANSI-compatible terminal and
400
+ // a no-op when stdout isn't a TTY.
401
+ return segs.join(' · ') + '\x1b[K';
427
402
  }