claude-token-saver 2.5.0 → 2.7.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 +7 -6
- package/bin/cli.js +21 -28
- package/package.json +1 -1
- package/src/advice.js +156 -14
- package/src/caps-cache.js +1 -1
- package/src/installer.js +18 -44
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
**Why I built this.** I'm on the Max plan. On Opus 4.6 I never hit the *current-session* cap. After Opus 4.7 rolled out, I started hitting it on the same workflow — repeatedly. The official token statistics didn't match what I was actually feeling, and Claude Code's UI doesn't show prompt-cache health. This tool is what let me see *why*: low cache hit rate, 5m TTL writes that should have been 1h, 1M context auto-promoted in the background.
|
|
13
13
|
|
|
14
14
|
v2.1 (2026-04) adds the workflow that follows the diagnosis:
|
|
15
|
-
- **`claude-token-saver install`** — one command writes a Claude Code Skill
|
|
15
|
+
- **`claude-token-saver install`** — one command writes a Claude Code Skill that auto-activates when you mention "cache hit rate" / "1M context" / "5H cap" — no slash command needed.
|
|
16
16
|
- **`claude-token-saver history`** — every warning chip transition is auto-logged to a daily Markdown file, so you can answer "when did this start" without grepping logs.
|
|
17
17
|
- **Cross-platform paths** — Windows (`%APPDATA%`), macOS (`~/Library/Application Support`), Linux (`~/.config` / XDG) all handled.
|
|
18
18
|
|
|
@@ -208,11 +208,12 @@ One command wires up everything else this README mentions:
|
|
|
208
208
|
claude-token-saver install
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
-
This writes
|
|
212
|
-
- `~/.claude/skills/claude-token-saver/SKILL.md` — auto-activates whenever you mention chip wording ("⚠ 1M ON", "cache miss", etc.) or ask
|
|
213
|
-
- `~/.claude/commands/token-monitor.md` — adds a `/token-monitor` slash command that runs `claude-token-saver history` + a fresh report and summarizes both for you.
|
|
211
|
+
This writes one file under your Claude user dir:
|
|
212
|
+
- `~/.claude/skills/claude-token-saver/SKILL.md` — auto-activates whenever you mention chip wording ("⚠ 1M ON", "cache miss", "5H cap", etc.) or ask for a token report. Claude Code will then read `claude-token-saver last`, drill into history if needed, and explain the warning.
|
|
214
213
|
|
|
215
|
-
|
|
214
|
+
If you previously installed v2.5.x or earlier, `install` also removes the now-redundant legacy `~/.claude/commands/token-monitor.md` slash command — its workflow is fully absorbed into the skill (same behavior, triggered by intent rather than typing `/token-monitor`).
|
|
215
|
+
|
|
216
|
+
Re-run with `--force` to overwrite the skill file.
|
|
216
217
|
|
|
217
218
|
## Warning history (`history`) — new in v2.1
|
|
218
219
|
|
|
@@ -286,7 +287,7 @@ That writes `./HANDOFF-YYYY-MM-DD-HHMM.md` in the current directory with:
|
|
|
286
287
|
Read the most recent HANDOFF-*.md in this directory and continue the work.
|
|
287
288
|
```
|
|
288
289
|
|
|
289
|
-
The handoff write is also recorded in history (`📝 handoff written: …`), so
|
|
290
|
+
The handoff write is also recorded in history (`📝 handoff written: …`), so `claude-token-saver history` and the auto-skill show both the cap-warn and the backup event next to each other.
|
|
290
291
|
|
|
291
292
|
## Hook Setup
|
|
292
293
|
|
package/bin/cli.js
CHANGED
|
@@ -201,9 +201,9 @@ function findLatestWarning(historyEntries, chipToCodes) {
|
|
|
201
201
|
|
|
202
202
|
async function main() {
|
|
203
203
|
// Subcommand: last — print the most recent warning + how to handle it.
|
|
204
|
-
// Designed for the
|
|
205
|
-
//
|
|
206
|
-
//
|
|
204
|
+
// Designed for the auto-trigger skill so the user immediately sees
|
|
205
|
+
// "what just fired and how to fix it" without having to read the whole
|
|
206
|
+
// history file.
|
|
207
207
|
// claude-token-saver last # search last 1 day
|
|
208
208
|
// claude-token-saver last --days 7 # widen the lookback
|
|
209
209
|
if (args[0] === 'last') {
|
|
@@ -329,38 +329,31 @@ async function main() {
|
|
|
329
329
|
return;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
-
// Subcommand: install — write the Claude Code
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
//
|
|
336
|
-
// claude-token-saver install
|
|
337
|
-
// claude-token-saver install --
|
|
338
|
-
// claude-token-saver install --force # overwrite existing files
|
|
332
|
+
// Subcommand: install — write the Claude Code auto-trigger skill so the
|
|
333
|
+
// user can just mention chip wording and Claude responds. v2.6.0 dropped
|
|
334
|
+
// the redundant /token-monitor slash command in favor of the skill alone;
|
|
335
|
+
// a legacy command file is removed automatically. Cross-platform.
|
|
336
|
+
// claude-token-saver install # install/update the skill
|
|
337
|
+
// claude-token-saver install --force # overwrite existing skill file
|
|
339
338
|
if (args[0] === 'install') {
|
|
340
|
-
const {
|
|
339
|
+
const { installAll } = await import('../src/installer.js');
|
|
341
340
|
const force = hasFlag('--force');
|
|
342
|
-
const onlySkill = hasFlag('--skill');
|
|
343
|
-
const onlyCommand = hasFlag('--command');
|
|
344
341
|
const print = (kind, r) => {
|
|
345
342
|
const verb = r.action === 'exists' ? 'already exists' : r.action;
|
|
346
343
|
console.log(` ${kind}: ${r.path} (${verb})`);
|
|
347
344
|
};
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
print('
|
|
352
|
-
|
|
353
|
-
const r = installAll({ force });
|
|
354
|
-
print('skill', r.skill);
|
|
355
|
-
print('command', r.command);
|
|
345
|
+
const r = installAll({ force });
|
|
346
|
+
print('skill', r.skill);
|
|
347
|
+
if (r.legacy.action === 'removed') {
|
|
348
|
+
print('legacy /token-monitor', r.legacy);
|
|
349
|
+
console.log(' (consolidated into the skill — same workflow, triggered by intent)');
|
|
356
350
|
}
|
|
357
351
|
console.log('');
|
|
358
|
-
console.log('Open Claude Code in any directory and
|
|
359
|
-
console.log(' /
|
|
360
|
-
console.log('Or just mention "cache hit rate" / "1M context" — the skill auto-activates.');
|
|
352
|
+
console.log('Open Claude Code in any directory and just mention:');
|
|
353
|
+
console.log(' "cache hit rate" / "1M context" / "5H cap" — the skill auto-activates.');
|
|
361
354
|
if (!force) {
|
|
362
355
|
console.log('');
|
|
363
|
-
console.log('Tip: re-run with --force to overwrite existing
|
|
356
|
+
console.log('Tip: re-run with --force to overwrite the existing skill file.');
|
|
364
357
|
}
|
|
365
358
|
return;
|
|
366
359
|
}
|
|
@@ -562,8 +555,8 @@ async function main() {
|
|
|
562
555
|
// refresh. Pull rate_limits + model out of it so we can surface cap-warn
|
|
563
556
|
// (>=90%) chips, always-on usage segments, the model chip, record cap
|
|
564
557
|
// transitions, and seed the table view's warning box. The table path falls
|
|
565
|
-
// back to the most-recent cached snapshot so the
|
|
566
|
-
//
|
|
558
|
+
// back to the most-recent cached snapshot so the table view (which
|
|
559
|
+
// doesn't pipe stdin) still has the data.
|
|
567
560
|
const stdinJson = readStdinJson();
|
|
568
561
|
let caps = extractCaps(stdinJson);
|
|
569
562
|
let model = extractModel(stdinJson);
|
|
@@ -616,7 +609,7 @@ async function main() {
|
|
|
616
609
|
}
|
|
617
610
|
}
|
|
618
611
|
// Persist transitions to ~/.config/claude-token-saver/history/YYYY-MM-DD.md
|
|
619
|
-
// so
|
|
612
|
+
// so `claude-token-saver history` and the auto-skill can replay them.
|
|
620
613
|
try {
|
|
621
614
|
const { recordChip, recordCapTransition } = await import('../src/history.js');
|
|
622
615
|
recordChip(spikeChip, { detail: chipDetail });
|
package/package.json
CHANGED
package/src/advice.js
CHANGED
|
@@ -59,6 +59,48 @@ export const ISSUE_MESSAGES = {
|
|
|
59
59
|
commands: [`Press ${toggleShortcut()} to toggle on/off instantly`],
|
|
60
60
|
commandsKo: [`${toggleShortcut()} 누르면 즉시 on/off 토글`],
|
|
61
61
|
},
|
|
62
|
+
{
|
|
63
|
+
label: 'Cap extended-thinking budget (⚠ check /effort first)',
|
|
64
|
+
labelKo: '확장 사고(thinking) 예산 제한 (⚠ /effort 먼저 확인)',
|
|
65
|
+
commands: [
|
|
66
|
+
'⚠ Run `/effort` to check current level — `xhigh` is the #1 cap killer',
|
|
67
|
+
'/effort medium — Anthropic-official default (use this for normal coding)',
|
|
68
|
+
'/effort low — for simple edits, labeling, boilerplate',
|
|
69
|
+
'/effort xhigh — ONLY for complex architecture / multi-file refactor planning, then revert',
|
|
70
|
+
'export MAX_THINKING_TOKENS=8000 # global hard cap (overrides /effort)',
|
|
71
|
+
],
|
|
72
|
+
commandsKo: [
|
|
73
|
+
'⚠ `/effort`로 현재 단계 확인 — `xhigh`가 캡 소진의 1순위 원인',
|
|
74
|
+
'/effort medium — Anthropic 공식 기본값 (일반 코딩은 이걸로)',
|
|
75
|
+
'/effort low — 단순 편집·라벨링·보일러플레이트',
|
|
76
|
+
'/effort xhigh — 복잡한 아키텍처·다파일 리팩터 계획 한정, 끝나면 즉시 복귀',
|
|
77
|
+
'export MAX_THINKING_TOKENS=8000 # 전역 하드 캡 (/effort 위에 우선 적용)',
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
label: 'Plan mode preemptively (Shift+Tab)',
|
|
82
|
+
labelKo: 'Plan 모드 선제 사용 (Shift+Tab)',
|
|
83
|
+
commands: [
|
|
84
|
+
'Plan mode forces a written plan before any edits — prevents wrong-direction rework',
|
|
85
|
+
'Rework after a misread spec costs more tokens than 1 extra plan turn',
|
|
86
|
+
],
|
|
87
|
+
commandsKo: [
|
|
88
|
+
'Plan 모드는 편집 전에 계획을 쓰게 강제 — 잘못된 방향 재작업 방지',
|
|
89
|
+
'스펙 오독 후 재작업이 plan 1턴 추가보다 훨씬 비쌈',
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
label: 'Compact or clear when context grows',
|
|
94
|
+
labelKo: '컨텍스트가 커지면 /compact 또는 /clear',
|
|
95
|
+
commands: [
|
|
96
|
+
'/compact — summarize the session history in place',
|
|
97
|
+
'/clear — drop history entirely at a clean task boundary',
|
|
98
|
+
],
|
|
99
|
+
commandsKo: [
|
|
100
|
+
'/compact — 세션 히스토리를 그 자리에서 요약',
|
|
101
|
+
'/clear — 작업 분기점에서 히스토리를 통째로 비우기',
|
|
102
|
+
],
|
|
103
|
+
},
|
|
62
104
|
{
|
|
63
105
|
label: '⚠ Known bug #31640',
|
|
64
106
|
labelKo: '⚠ 알려진 버그 #31640',
|
|
@@ -86,14 +128,26 @@ export const ISSUE_MESSAGES = {
|
|
|
86
128
|
{
|
|
87
129
|
label: 'Avoid opening fresh sessions too often',
|
|
88
130
|
labelKo: '새 세션을 너무 자주 열지 말기',
|
|
89
|
-
commands: [
|
|
90
|
-
|
|
131
|
+
commands: [
|
|
132
|
+
'Continue the same task in the same session (context switching = cache miss)',
|
|
133
|
+
'Resume with `claude --continue` instead of starting fresh — preserves the prefix cache',
|
|
134
|
+
],
|
|
135
|
+
commandsKo: [
|
|
136
|
+
'같은 작업은 같은 세션에서 계속 (컨텍스트 전환 = 캐시 미스)',
|
|
137
|
+
'새로 시작 대신 `claude --continue`로 재개 — prefix 캐시 보존',
|
|
138
|
+
],
|
|
91
139
|
},
|
|
92
140
|
{
|
|
93
141
|
label: 'Stabilize the prompt prefix',
|
|
94
142
|
labelKo: '프롬프트 prefix 안정화',
|
|
95
|
-
commands: [
|
|
96
|
-
|
|
143
|
+
commands: [
|
|
144
|
+
'System prompts / tool definitions that change per request invalidate the cache every time',
|
|
145
|
+
'Trim CLAUDE.md — every line ships on every turn; keep only durable rules',
|
|
146
|
+
],
|
|
147
|
+
commandsKo: [
|
|
148
|
+
'요청마다 바뀌는 시스템 프롬프트 / 도구 정의는 매번 캐시를 무효화',
|
|
149
|
+
'CLAUDE.md 다이어트 — 모든 줄이 매 턴 실림; 영속적인 규칙만 유지',
|
|
150
|
+
],
|
|
97
151
|
},
|
|
98
152
|
],
|
|
99
153
|
},
|
|
@@ -142,6 +196,36 @@ export const ISSUE_MESSAGES = {
|
|
|
142
196
|
'긴 문서/README 생성 요청은 스크립트로 옮겨 출력 축소',
|
|
143
197
|
],
|
|
144
198
|
},
|
|
199
|
+
{
|
|
200
|
+
label: 'Cap extended-thinking budget (⚠ check /effort)',
|
|
201
|
+
labelKo: '확장 사고(thinking) 예산 제한 (⚠ /effort 확인)',
|
|
202
|
+
commands: [
|
|
203
|
+
'⚠ Check `/effort` — `xhigh` burns thinking tokens that count as output',
|
|
204
|
+
'/effort medium — Anthropic-official default; switch back from xhigh',
|
|
205
|
+
'export MAX_THINKING_TOKENS=8000 # global hard cap',
|
|
206
|
+
],
|
|
207
|
+
commandsKo: [
|
|
208
|
+
'⚠ `/effort` 확인 — `xhigh`는 thinking 토큰을 다량 소비 (출력으로 집계)',
|
|
209
|
+
'/effort medium — Anthropic 공식 기본값; xhigh에서 복귀',
|
|
210
|
+
'export MAX_THINKING_TOKENS=8000 # 전역 하드 캡',
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
label: 'Model matching strategy (80/15/5 rule)',
|
|
215
|
+
labelKo: '모델 매칭 전략 (80/15/5 비율)',
|
|
216
|
+
commands: [
|
|
217
|
+
'Sonnet 80% — daily coding, edits, refactors',
|
|
218
|
+
'Opus 15% — complex design, multi-file refactor planning, deep debugging',
|
|
219
|
+
'Haiku 5% — boilerplate, labeling, summaries, subagent work',
|
|
220
|
+
'Switch with `/model sonnet` / `/model opus` / `/model haiku`',
|
|
221
|
+
],
|
|
222
|
+
commandsKo: [
|
|
223
|
+
'Sonnet 80% — 일상 코딩, 편집, 리팩터링',
|
|
224
|
+
'Opus 15% — 복잡한 설계, 다파일 리팩터 계획, 깊은 디버깅',
|
|
225
|
+
'Haiku 5% — 보일러플레이트, 라벨링, 요약, 서브에이전트 작업',
|
|
226
|
+
'`/model sonnet` / `/model opus` / `/model haiku`로 전환',
|
|
227
|
+
],
|
|
228
|
+
},
|
|
145
229
|
],
|
|
146
230
|
},
|
|
147
231
|
HIGH_REQUEST_COUNT: {
|
|
@@ -165,6 +249,40 @@ export const ISSUE_MESSAGES = {
|
|
|
165
249
|
commands: ['Check that the agent is not repeating the same test/search in a loop'],
|
|
166
250
|
commandsKo: ['에이전트가 동일한 테스트/검색을 루프로 반복하고 있지 않은지 확인'],
|
|
167
251
|
},
|
|
252
|
+
{
|
|
253
|
+
label: 'Delegate large searches to a subagent (Sonnet by default)',
|
|
254
|
+
labelKo: '대형 검색은 서브에이전트로 위임 (Sonnet 기본)',
|
|
255
|
+
commands: [
|
|
256
|
+
'Use the Task tool with the Explore subagent for repo-wide searches',
|
|
257
|
+
'Pin custom subagents to Sonnet/Haiku in their frontmatter: `model: sonnet`',
|
|
258
|
+
'The subagent runs in its own context — main session keeps a clean prefix',
|
|
259
|
+
],
|
|
260
|
+
commandsKo: [
|
|
261
|
+
'레포 전반 검색은 Task 도구의 Explore 서브에이전트로 위임',
|
|
262
|
+
'커스텀 서브에이전트는 frontmatter에 `model: sonnet` 명시 (Opus 자동 상속 방지)',
|
|
263
|
+
'서브에이전트는 자체 컨텍스트에서 실행 — 메인 세션 prefix가 깨끗하게 유지됨',
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
label: 'Migrate MCP servers → Skills / CLI',
|
|
268
|
+
labelKo: 'MCP 서버 → Skills / CLI 전환',
|
|
269
|
+
commands: [
|
|
270
|
+
'30 MCP tools ≈ 3,600 tokens loaded every turn — measured by mcp2cli (HN 146pts)',
|
|
271
|
+
'Replacing rarely-used MCPs with Skills (loaded on demand) or shell CLI cuts ~96%',
|
|
272
|
+
'Audit `.mcp.json` and disable everything not used weekly',
|
|
273
|
+
],
|
|
274
|
+
commandsKo: [
|
|
275
|
+
'MCP 도구 30개 ≈ 매 턴 3,600 토큰 상시 로드 (mcp2cli 측정, HN 146pts)',
|
|
276
|
+
'드물게 쓰는 MCP를 Skills(필요 시 로드) 또는 셸 CLI로 대체하면 ~96% 절감',
|
|
277
|
+
'`.mcp.json` 점검해 주간에 안 쓰는 건 모두 비활성화',
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
label: 'Trim hooks that inject context',
|
|
282
|
+
labelKo: '컨텍스트 주입 훅 정리',
|
|
283
|
+
commands: ['Disable noisy PreToolUse/PostToolUse hooks unless they earn their tokens'],
|
|
284
|
+
commandsKo: ['값을 못 하는 PreToolUse/PostToolUse 훅은 비활성화'],
|
|
285
|
+
},
|
|
168
286
|
],
|
|
169
287
|
},
|
|
170
288
|
FREQUENT_CACHE_REBUILD: {
|
|
@@ -182,6 +300,30 @@ export const ISSUE_MESSAGES = {
|
|
|
182
300
|
commands: ['Continue one task in one Claude Code session'],
|
|
183
301
|
commandsKo: ['하나의 작업은 하나의 Claude Code 세션에서 계속'],
|
|
184
302
|
},
|
|
303
|
+
{
|
|
304
|
+
label: 'Use /compact at task boundaries',
|
|
305
|
+
labelKo: '작업 분기점에서 /compact 사용',
|
|
306
|
+
commands: [
|
|
307
|
+
'/compact summarizes prior turns in place — keeps the session alive without re-reading everything',
|
|
308
|
+
'Better than starting a fresh session, which forces a full prefix rebuild',
|
|
309
|
+
],
|
|
310
|
+
commandsKo: [
|
|
311
|
+
'/compact는 이전 턴을 그 자리에서 요약 — 전체 재읽기 없이 세션 유지',
|
|
312
|
+
'새 세션을 여는 것보다 나음 (새 세션은 prefix 전체 재구축 강제)',
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
label: 'Avoid re-reading large files',
|
|
317
|
+
labelKo: '큰 파일 반복 Read 피하기',
|
|
318
|
+
commands: [
|
|
319
|
+
'Prefer `git diff` to see what changed instead of re-reading the whole file',
|
|
320
|
+
'Edit returns success silently — no need to Read after editing',
|
|
321
|
+
],
|
|
322
|
+
commandsKo: [
|
|
323
|
+
'파일 전체 다시 읽기 대신 `git diff`로 변경분만 확인',
|
|
324
|
+
'Edit는 성공 시 조용히 끝남 — 편집 후 Read 다시 할 필요 없음',
|
|
325
|
+
],
|
|
326
|
+
},
|
|
185
327
|
],
|
|
186
328
|
},
|
|
187
329
|
};
|
|
@@ -197,28 +339,28 @@ export const ISSUE_MESSAGES = {
|
|
|
197
339
|
*/
|
|
198
340
|
export const ISSUE_TIPS = {
|
|
199
341
|
LARGE_INPUT_PER_REQUEST: {
|
|
200
|
-
en: '
|
|
201
|
-
ko: '
|
|
342
|
+
en: 'Check `/effort` — `xhigh` is the #1 cap killer; switch to `/effort medium` (or `low`); disable 1M context; `/compact` when context grows',
|
|
343
|
+
ko: '`/effort` 확인 — `xhigh`가 캡 소진 1순위 원인, `medium`(또는 `low`)으로 복귀; 1M 컨텍스트 끄기; 컨텍스트 커지면 `/compact`',
|
|
202
344
|
},
|
|
203
345
|
LOW_HIT_RATE: {
|
|
204
|
-
en: 'Continue
|
|
205
|
-
ko: '
|
|
346
|
+
en: 'Continue with `claude --continue`; keep CLAUDE.md trim — every line ships every turn',
|
|
347
|
+
ko: '`claude --continue`로 재개; CLAUDE.md 다이어트 — 모든 줄이 매 턴 실림',
|
|
206
348
|
},
|
|
207
349
|
BUCKET_5M_DOMINANT: {
|
|
208
350
|
en: 'Send any prompt within 5min to keep cache warm; Max plan unlocks 1h TTL',
|
|
209
351
|
ko: '5분 이내 한 번 더 보내 캐시 유지; Max 플랜은 1시간 TTL 제공',
|
|
210
352
|
},
|
|
211
353
|
HIGH_OUTPUT_RATIO: {
|
|
212
|
-
en: '
|
|
213
|
-
ko: '
|
|
354
|
+
en: 'Check `/effort` (`xhigh` inflates output); prefer Edit over full rewrites; model matching: Sonnet 80% / Opus 15% / Haiku 5%',
|
|
355
|
+
ko: '`/effort` 확인 (`xhigh`는 출력 폭증); Edit 도구 우선 (전체 재작성 피하기); 모델 매칭: Sonnet 80% / Opus 15% / Haiku 5%',
|
|
214
356
|
},
|
|
215
357
|
HIGH_REQUEST_COUNT: {
|
|
216
|
-
en: 'Bundle
|
|
217
|
-
ko: '
|
|
358
|
+
en: 'Bundle calls into one message; delegate to subagents (`model: sonnet`); migrate MCP→Skills/CLI (30 tools = ~3,600 tokens/turn)',
|
|
359
|
+
ko: '호출은 한 메시지에 묶기; 서브에이전트(`model: sonnet`)로 위임; MCP→Skills/CLI 전환 (30 tools ≈ 매 턴 3,600 토큰)',
|
|
218
360
|
},
|
|
219
361
|
FREQUENT_CACHE_REBUILD: {
|
|
220
|
-
en: 'Continue one task in one session
|
|
221
|
-
ko: '한 작업은 한
|
|
362
|
+
en: 'Continue one task in one session; use `/compact` at boundaries; avoid re-reading large files (use `git diff`)',
|
|
363
|
+
ko: '한 작업은 한 세션에서; 분기점에선 `/compact`; 큰 파일 재읽기 대신 `git diff`',
|
|
222
364
|
},
|
|
223
365
|
};
|
|
224
366
|
|
package/src/caps-cache.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Statusline snapshot cache — the rate-limit numbers and model name only flow
|
|
3
3
|
* through stdin from Claude Code's statusline contract, but we want the table
|
|
4
|
-
* view (
|
|
4
|
+
* view (`claude-token-saver --days N`) to surface the same data. So
|
|
5
5
|
* whenever the statusline path sees them it writes them here, and the table
|
|
6
6
|
* path reads them back if its own stdin was empty.
|
|
7
7
|
*
|
package/src/installer.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Installs the Claude Code integration
|
|
2
|
+
* Installs the Claude Code integration asset:
|
|
3
3
|
* - Skill: ~/.claude/skills/claude-token-saver/SKILL.md
|
|
4
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* v2.6.0 consolidates `/token-monitor` into the skill (was redundant with the
|
|
6
|
+
* auto-trigger). On install we actively remove a legacy
|
|
7
|
+
* ~/.claude/commands/token-monitor.md if present so users don't see two
|
|
8
|
+
* overlapping entry points.
|
|
5
9
|
*
|
|
6
10
|
* All paths are resolved with node:path so Windows backslashes and POSIX
|
|
7
11
|
* forward-slashes are both handled. Directories are created with
|
|
@@ -9,7 +13,7 @@
|
|
|
9
13
|
* exist on every platform.
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
|
-
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
16
|
+
import { writeFileSync, mkdirSync, existsSync, unlinkSync } from 'node:fs';
|
|
13
17
|
import { join } from 'node:path';
|
|
14
18
|
import { claudeUserDir } from './paths.js';
|
|
15
19
|
|
|
@@ -36,6 +40,9 @@ countdown, savings, and (when relevant) a leading warning chip.
|
|
|
36
40
|
\`claude-token-saver handoff\`).
|
|
37
41
|
- The user wants to see the token-usage history file or asks for a summary
|
|
38
42
|
of recent warnings.
|
|
43
|
+
- The user asks for a quick token report or "current state" check (the
|
|
44
|
+
skill replaces the legacy \`/token-monitor\` slash command — same workflow,
|
|
45
|
+
triggered by intent rather than a typed slash).
|
|
39
46
|
|
|
40
47
|
## What to do
|
|
41
48
|
|
|
@@ -97,41 +104,6 @@ History files live under the OS-appropriate user-data dir:
|
|
|
97
104
|
Each day's file is plain Markdown — safe to open in any editor.
|
|
98
105
|
`;
|
|
99
106
|
|
|
100
|
-
const COMMAND_BODY = `---
|
|
101
|
-
description: Show recent claude-token-saver warning history and a fresh report.
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
You are responding to the \`/token-monitor\` slash command. The user wants a
|
|
105
|
-
quick read of their Claude Code token usage and any active warnings — most
|
|
106
|
-
importantly: **what just happened, and how do I handle it?**
|
|
107
|
-
|
|
108
|
-
Steps:
|
|
109
|
-
|
|
110
|
-
1. **Lead with the most recent warning.** Run \`claude-token-saver last\`
|
|
111
|
-
first and surface its output verbatim (or lightly summarized) at the top
|
|
112
|
-
of your reply. This returns the latest warning event (chip + detail +
|
|
113
|
-
timestamp) followed by the full advice block. If \`last\` says no recent
|
|
114
|
-
warnings, mention that and skip ahead — you can stop here unless the user
|
|
115
|
-
asked for more.
|
|
116
|
-
2. Run \`claude-token-saver history --days 7\` and capture the output. Use it
|
|
117
|
-
only to add context — e.g. "this is the 3rd cache miss today" — not to
|
|
118
|
-
re-print the whole file. Each entry is bilingual and includes a \`💡\`
|
|
119
|
-
action tip inline.
|
|
120
|
-
3. Run \`claude-token-saver --days 1\` and capture the output for any extra
|
|
121
|
-
color you want to add: TTL breakdown, cost impact, daily trend, or active
|
|
122
|
-
spikes. Skip if step 1 already covered what the user needs.
|
|
123
|
-
4. Summarize for the user:
|
|
124
|
-
- **What just fired** — the chip + the time + a sentence on what caused it
|
|
125
|
-
(from \`last\`).
|
|
126
|
-
- **What to do** — the action tip from \`last\`. For cap-warn (\`🚨 5H/7D NN%\`),
|
|
127
|
-
surface \`claude-token-saver handoff\` prominently so they can back up
|
|
128
|
-
state before the cap blocks them.
|
|
129
|
-
- **Today's pattern** (optional) — when warnings cluster in time, mention it.
|
|
130
|
-
|
|
131
|
-
Keep the summary to ~10 lines. The user can re-run the underlying commands
|
|
132
|
-
themselves for the full output.
|
|
133
|
-
`;
|
|
134
|
-
|
|
135
107
|
function writeIfNeeded(file, body, force) {
|
|
136
108
|
const existed = existsSync(file);
|
|
137
109
|
if (existed && !force) return { path: file, action: 'exists' };
|
|
@@ -146,16 +118,18 @@ export function installSkill({ force = false } = {}) {
|
|
|
146
118
|
return writeIfNeeded(file, SKILL_BODY, force);
|
|
147
119
|
}
|
|
148
120
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
121
|
+
// Removes the legacy /token-monitor slash command from prior versions.
|
|
122
|
+
// v2.6.0 consolidated it into the skill — the file would otherwise linger.
|
|
123
|
+
export function removeLegacyCommand() {
|
|
124
|
+
const file = join(claudeUserDir(), 'commands', 'token-monitor.md');
|
|
125
|
+
if (!existsSync(file)) return { path: file, action: 'absent' };
|
|
126
|
+
unlinkSync(file);
|
|
127
|
+
return { path: file, action: 'removed' };
|
|
154
128
|
}
|
|
155
129
|
|
|
156
130
|
export function installAll({ force = false } = {}) {
|
|
157
131
|
return {
|
|
158
132
|
skill: installSkill({ force }),
|
|
159
|
-
|
|
133
|
+
legacy: removeLegacyCommand(),
|
|
160
134
|
};
|
|
161
135
|
}
|