claude-token-saver 3.6.3 โ†’ 3.6.4

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
@@ -243,6 +243,9 @@ Also update `statusLine.command` in `~/.claude/settings.json` to `claude-token-s
243
243
 
244
244
  ## Release notes
245
245
 
246
+ ### v3.6.4 (2026-07-29)
247
+ - **Fixed: false `๐Ÿ…ทโš  ratchet-unloaded`** โ€” the import check looked at a single CLAUDE.md. When the project file carried the harness block, only that file was inspected, so the common layout of block-in-project + `@` imports-in-global raised the warning even though the rules loaded fine. Claude Code loads both files, so the flags are now the union of the two, and `importSource` (`project`/`global`/`both`) says which file carries them. The warning fires only when neither file imports.
248
+
246
249
  ### v3.6.3 (2026-07-27)
247
250
  - **Fixed: approved ratchet rules never reached the session** โ€” `harness promote` appended rules to `ratchet.md`, but nothing ever read that file. Claude Code loads `CLAUDE.md` (plus whatever it imports) and the harness block carried no import line, so "approved rules apply automatically from the next session" was unimplemented. The block now imports `@.claude/ratchet.md` (project) / `@~/.claude/ratchet.md` (global). Re-running `harness init` upgrades an existing block in place.
248
251
  - **`ratchet-model.md` is imported explicitly too** โ€” delegation rules now travel the same declared path instead of relying on a host that happens to pick the file up. To keep the import from dangling, `harness init` seeds an empty file and `syncAllFiles` empties rather than deletes a target that loses its last rule.
package/README.md CHANGED
@@ -200,6 +200,9 @@ npm uninstall -g claude-cache-monitor && npm i -g claude-token-saver
200
200
 
201
201
  ## ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ
202
202
 
203
+ ### v3.6.4 (2026-07-29)
204
+ - **`๐Ÿ…ทโš  ratchet-unloaded`๊ฐ€ ์ž˜๋ชป ๋œจ๋˜ ๋ฒ„๊ทธ ์ˆ˜์ •** โ€” import ์—ฌ๋ถ€๋ฅผ CLAUDE.md ํ•œ ํŒŒ์ผ์—์„œ๋งŒ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ `CLAUDE.md`์— harness ๋ธ”๋ก์ด ์žˆ์œผ๋ฉด ๊ทธ ํŒŒ์ผ๋งŒ ๋ณด๊ณ  ํŒ์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, `@` import๊ฐ€ ๊ธ€๋กœ๋ฒŒ `~/.claude/CLAUDE.md`์— ์žˆ๋Š” ํ”ํ•œ ์กฐํ•ฉ์—์„œ๋Š” ๋ฃฐ์ด ์ •์ƒ ๋กœ๋“œ๋˜๋Š”๋ฐ๋„ ๊ฒฝ๊ณ ๊ฐ€ ๋–ด์Šต๋‹ˆ๋‹ค. Claude Code๋Š” ๋‘ ํŒŒ์ผ์„ ๋ชจ๋‘ ๋กœ๋“œํ•˜๋ฏ€๋กœ ์ด์ œ ์–‘์ชฝ์˜ import๋ฅผ ํ•ฉ์ณ์„œ ํŒ์ •ํ•˜๊ณ , ์–ด๋А ์ชฝ์ด ๋“ค๊ณ  ์žˆ๋Š”์ง€๋Š” `importSource`(`project`/`global`/`both`)๋กœ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ๋‘ ํŒŒ์ผ ๋‹ค import๊ฐ€ ์—†์„ ๋•Œ๋งŒ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค.
205
+
203
206
  ### v3.6.3 (2026-07-27)
204
207
  - **์Šน์ธํ•œ ratchet ๋ฃฐ์ด ์„ธ์…˜์— ์ „๋‹ฌ๋˜์ง€ ์•Š๋˜ ๋ฒ„๊ทธ ์ˆ˜์ •** โ€” `harness promote`๋Š” ๋ฃฐ์„ `ratchet.md`์— appendํ–ˆ์ง€๋งŒ, ๊ทธ ํŒŒ์ผ์„ ์ฝ๋Š” ์†Œ๋น„์ž๊ฐ€ ์–ด๋””์—๋„ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. Claude Code๋Š” `CLAUDE.md`(์™€ ๊ทธ๊ฒƒ์ด importํ•˜๋Š” ํŒŒ์ผ)๋งŒ ๋กœ๋“œํ•˜๋Š”๋ฐ harness ๋ธ”๋ก์— import ๋ผ์ธ์ด ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, "์Šน์ธ๋œ ๋ฃฐ์€ ๋‹ค์Œ ์„ธ์…˜๋ถ€ํ„ฐ ์ž๋™ ์ ์šฉ"์€ ์‚ฌ์‹ค์ƒ ๋ฏธ๊ตฌํ˜„ ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค. ์ด์ œ harness ๋ธ”๋ก์ด `@.claude/ratchet.md`(project) / `@~/.claude/ratchet.md`(global)๋ฅผ importํ•ฉ๋‹ˆ๋‹ค. `harness init`์„ ๋‹ค์‹œ ๋Œ๋ฆฌ๋ฉด ๊ธฐ์กด ๋ธ”๋ก๋„ ์ œ์ž๋ฆฌ์—์„œ ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค.
205
208
  - **`ratchet-model.md`๋„ ๋ช…์‹œ์ ์œผ๋กœ import** โ€” ๋ชจ๋ธ ํ”ผํŒ… ๋ฃฐ๋„ ํ˜ธ์ŠคํŠธ๊ฐ€ ์•Œ์•„์„œ ์ฝ์–ด์ฃผ๊ธธ ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š๊ณ  ๊ฐ™์€ ๊ฒฝ๋กœ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. import๊ฐ€ ๋Š๊ธฐ์ง€ ์•Š๋„๋ก `harness init`์ด ๋นˆ ํŒŒ์ผ์„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค๊ณ , ๋งˆ์ง€๋ง‰ ๋ฃฐ์ด ์‚ฌ๋ผ์ ธ๋„ `syncAllFiles`๊ฐ€ ํŒŒ์ผ์„ ์ง€์šฐ๋Š” ๋Œ€์‹  ๋น„์›๋‹ˆ๋‹ค.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-token-saver",
3
- "version": "3.6.3",
3
+ "version": "3.6.4",
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": {
package/src/harness.js CHANGED
@@ -153,15 +153,37 @@ function statusForFile(filePath) {
153
153
  * relies on a globally-installed harness report ๐Ÿ…ท 5/5 (covered by global),
154
154
  * matching reality: Claude Code loads ~/.claude/CLAUDE.md for every project.
155
155
  * The returned `source` ('project'|'global') tells callers which file was used.
156
+ *
157
+ * The `@` import flags are the union of both files, not just the source one:
158
+ * Claude Code loads ~/.claude/CLAUDE.md for every project *and* the project
159
+ * CLAUDE.md, so a project-scope block with the imports living in the global
160
+ * file still gets the ratchet rules. Checking only the source file made that
161
+ * layout report a false `ratchet-unloaded`. `importSource` says which file
162
+ * actually carries them ('project' | 'global' | 'both' | null).
156
163
  */
157
164
  export function harnessStatus(root = findProjectRoot(), { scope = 'auto' } = {}) {
158
- if (scope === 'project') return { ...statusForFile(claudeMdPath(root)), root, source: 'project' };
159
- if (scope === 'global') return { ...statusForFile(globalClaudeMdPath()), root, source: 'global' };
160
165
  const project = statusForFile(claudeMdPath(root));
161
- if (project.hasBlock) return { ...project, root, source: 'project' };
162
166
  const global = statusForFile(globalClaudeMdPath());
163
- if (global.hasBlock) return { ...global, root, source: 'global' };
164
- return { ...project, root, source: 'project' };
167
+ const pick = (s, source) => ({ ...s, ...unionImports(project, global), root, source });
168
+ if (scope === 'project') return pick(project, 'project');
169
+ if (scope === 'global') return pick(global, 'global');
170
+ if (project.hasBlock) return pick(project, 'project');
171
+ if (global.hasBlock) return pick(global, 'global');
172
+ return pick(project, 'project');
173
+ }
174
+
175
+ // Union the two files' import flags. Same file read twice (project root === ~)
176
+ // is harmless โ€” OR is idempotent.
177
+ function unionImports(project, global) {
178
+ const samePath = project.file === global.file;
179
+ const g = samePath ? { hasRatchetImport: false, hasModelRatchetImport: false } : global;
180
+ const inProject = project.hasRatchetImport || project.hasModelRatchetImport;
181
+ const inGlobal = g.hasRatchetImport || g.hasModelRatchetImport;
182
+ return {
183
+ hasRatchetImport: project.hasRatchetImport || g.hasRatchetImport,
184
+ hasModelRatchetImport: project.hasModelRatchetImport || g.hasModelRatchetImport,
185
+ importSource: inProject && inGlobal ? 'both' : inProject ? 'project' : inGlobal ? 'global' : null,
186
+ };
165
187
  }
166
188
 
167
189
  /**