claude-token-saver 3.2.2 โ 3.3.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.en.md +26 -1
- package/README.md +26 -1
- package/bin/cli.js +29 -9
- package/package.json +1 -1
- package/src/harness.js +9 -0
- package/src/model-rules.js +26 -2
package/README.en.md
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
# claude-token-saver
|
|
9
9
|
|
|
10
|
-
**Diagnose
|
|
10
|
+
**Diagnose Claude Code token usage from a single statusline โ and route the easy work your expensive model keeps repeating down to cheaper models.** Zero dependencies, one-line install.
|
|
11
|
+
|
|
12
|
+
Since v3.x this is more than after-the-fact monitoring: it's a **model-fitting routing layer**. Session logs are classified into tiers (T0/T1/T2), recurring patterns get promoted to "haiku/sonnet is enough for this" delegation rules, and your main model auto-delegates them from the next session ([route-scan](#-route-scan--this-recurring-task-could-run-on-a-cheaper-tier)).
|
|
11
13
|
|
|
12
14
|
```bash
|
|
13
15
|
npm i -g claude-token-saver # postinstall auto-registers the statusline + Skill
|
|
@@ -19,6 +21,7 @@ npm i -g claude-token-saver # postinstall auto-registers the statusline + Skil
|
|
|
19
21
|
|
|
20
22
|
| | |
|
|
21
23
|
|---|---|
|
|
24
|
+
| ๐ **Model-fitting delegation** | Classifies the easy work your expensive model (opus/fable) keeps repeating into tiers (T0/T1/T2) โ promotes haiku/sonnet delegation rules, auto-applied from the next session |
|
|
22
25
|
| ๐ธ **โ18.6% measured cost** | Cost per user message $2.35 โ $1.91 after adopting harness+ratchet (author's logs, [details](#real-world-impact--beforeafter-report)) |
|
|
23
26
|
| ๐จ **No surprise rate limits** | Instant warning when the 5H/7D window hits 90% + `handoff` to back up your work |
|
|
24
27
|
| ๐ง **Cache waste detection** | Hit rate, TTL countdown, 1M-context detection โ token spikes diagnosed with issue codes |
|
|
@@ -148,6 +151,21 @@ Analyzes your session history at the **episode (user request) level**, classifie
|
|
|
148
151
|
|
|
149
152
|
Signals: call count, output tokens, **mutating tool calls (Edit/Write/Bash)**, **tool errors**, and request text. Output thresholds are auto-calibrated from your own 14-day distribution (fixed constants drift with workload).
|
|
150
153
|
|
|
154
|
+
<details>
|
|
155
|
+
<summary>Why this design โ research evidence (deep-research, 21 cross-verified sources + 553 locally measured episodes)</summary>
|
|
156
|
+
|
|
157
|
+
A survey of existing LLM-routing research and systems shaped each axis of the design:
|
|
158
|
+
|
|
159
|
+
- **Conservative demotion โ "only send down what's clearly easy" โ is the unexplored direction.** In RouterArena (2025), every academic and commercial router fell far short of the oracle (90.9%; best entrant 66.9), and the failure mode was consistently **over-routing to expensive models**. Per the routing-collapse work, the oracle needs the top model for under 20% of queries โ while 73% of the author's episodes were still on the top tier. The headroom is large.
|
|
160
|
+
- **Difficulty is defined by outcome, not text guessing.** RouterArena labels difficulty as "how many of 42 models actually got it right". Our logs already contain outcomes: tool errors, mutating tool calls, episode length. Local measurement confirms it โ error incidence splits the tiers sharply (T2 candidates 2% / T1 8% / T0 36%).
|
|
161
|
+
- **Thresholds calibrate to the user's own distribution.** RouteLLM's stated limitation is that fixed thresholds drift as the query distribution shifts โ so output-token thresholds are recomputed from your last 14 days' p25/p75 (clamped).
|
|
162
|
+
- **An escalation path makes demotion mistakes cheap.** The FrugalGPT cascade lesson ("start cheap, escalate on failure"). In Claude Code this falls out naturally: when a subagent gets stuck, the main model takes over โ and promoted rules spell out that guard.
|
|
163
|
+
- **Subagent `model:` is Anthropic's official cost-control mechanism.** The docs recommend routing to cheaper models like Haiku for cost control โ yet Claude Code itself does no automatic model routing; even trivial turns resend the full context on the session model. That gap is exactly what route-scan fills.
|
|
164
|
+
- **Learned classifiers (BERT/embeddings) deliberately excluded.** Even the best is 24 points off the oracle, we have no preference-pair training data, and it would break the zero-dependency principle. Regex categories + outcome signals are the current position.
|
|
165
|
+
|
|
166
|
+
Sources (RouteLLM, FrugalGPT, RouterArena, routing-survey arxiv links), the full local-measurement table, and the complete tier criteria: [docs/TIER_CRITERIA.md](./docs/TIER_CRITERIA.md).
|
|
167
|
+
</details>
|
|
168
|
+
|
|
151
169
|
```bash
|
|
152
170
|
claude-token-saver route-scan # scan (24h cache) + tiered candidates
|
|
153
171
|
claude-token-saver harness promote R1 --project # promote candidate R1 to a model-fitting rule
|
|
@@ -251,6 +269,13 @@ Also update `statusLine.command` in `~/.claude/settings.json` to `claude-token-s
|
|
|
251
269
|
|
|
252
270
|
## Release notes
|
|
253
271
|
|
|
272
|
+
### v3.3.0 (2026-07-13)
|
|
273
|
+
- **Delegation visibility & briefing** โ the whole model-fitting loop is now surfaced to the user:
|
|
274
|
+
- The SessionStart hook injects, per candidate, **the exact rule text that would be written to ratchet-model.md** โ you see precisely what you're approving.
|
|
275
|
+
- Rules flipped to review (delegated-category error rate over 20%) are announced on **both** the statusline (`๐
ทโ rule-health R<N>` chip โ implementing the item from the design doc; precedence: session-quality warnings > rule-health > route? candidates) and the session-start briefing.
|
|
276
|
+
- The ratchet-model.md header now instructs the model to prefix each delegation with `๐ [claude-token-saver] model-fitting: "<category>" โ <agent>` โ making it visible which tool is saving your tokens.
|
|
277
|
+
- README updated to the 3.x identity (model-fitting delegation in the top pitch, collapsible research-evidence section under route-scan); fixed a stale comment in model-rules.js.
|
|
278
|
+
|
|
254
279
|
### v3.2.2 (2026-07-13)
|
|
255
280
|
- **No re-proposing registered rules** โ (tier|category|project) combinations that already have a model-fitting rule are excluded from scan candidates (a global rule covers every project). Fixes rules registered outside the promote flow (e.g. migrations) resurfacing as candidates.
|
|
256
281
|
|
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
# claude-token-saver
|
|
9
9
|
|
|
10
|
-
**Claude Code ํ ํฐ ์ฌ์ฉ๋์ statusline ํ ์ค๋ก
|
|
10
|
+
**Claude Code ํ ํฐ ์ฌ์ฉ๋์ statusline ํ ์ค๋ก ์ง๋จํ๊ณ , ์์ ๋ชจ๋ธ์ด ๋ฐ๋ณต ์ฒ๋ฆฌํ๋ easy ์์
์ ๋ ์ผ ๋ชจ๋ธ๋ก ๋ด๋ ค๋ณด๋ด๋ CLI.** ์์กด์ฑ 0, ์ค์น ํ ์ค์ด๋ฉด ๋.
|
|
11
|
+
|
|
12
|
+
v3.x๋ถํฐ๋ ์ฌํ ๋ชจ๋ํฐ๋ง์ ๋์ด **๋ชจ๋ธ ํผํ
๋ผ์ฐํ
๊ณ์ธต**์
๋๋ค: ์ธ์
๋ก๊ทธ๋ฅผ ํฐ์ด(T0/T1/T2)๋ก ๋ถ๋ฅํด "์ด ๋ฐ๋ณต ์์
์ haiku/sonnet์ด๋ฉด ์ถฉ๋ถํ๋ค"๋ฅผ ๋ฃฐ๋ก ์น๊ฒฉํ๊ณ , ๋ค์ ์ธ์
๋ถํฐ ๋ฉ์ธ ๋ชจ๋ธ์ด ์๋ ์์ํฉ๋๋ค ([route-scan](#-route-scan--์ด-๋ฐ๋ณต-์์
-๋-์ผ-ํฐ์ด๋ก-๋ด๋ ค๋-๋ฉ๋๋ค)).
|
|
11
13
|
|
|
12
14
|
```bash
|
|
13
15
|
npm i -g claude-token-saver # postinstall์ด statusline + Skill ์๋ ๋ฑ๋ก
|
|
@@ -19,6 +21,7 @@ npm i -g claude-token-saver # postinstall์ด statusline + Skill ์๋ ๋ฑ๋ก
|
|
|
19
21
|
|
|
20
22
|
| | |
|
|
21
23
|
|---|---|
|
|
24
|
+
| ๐ **๋ชจ๋ธ ํผํ
์์** | ์์ ๋ชจ๋ธ(opus/fable)์ด ๋ฐ๋ณต ์ฒ๋ฆฌํด ์จ easy ์์
์ ํฐ์ด(T0/T1/T2)๋ก ๋ถ๋ฅ โ haiku/sonnet ์์ ๋ฃฐ๋ก ์น๊ฒฉ, ๋ค์ ์ธ์
๋ถํฐ ์๋ ์ ์ฉ |
|
|
22
25
|
| ๐ธ **๋น์ฉ ์ค์ธก โ18.6%** | harness+ratchet ๋์
์ ํ, ์ฌ์ฉ์ ๋ฉ์์ง๋น ๋น์ฉ $2.35 โ $1.91 (์ ์ ๋ก๊ทธ, [์์ธ](#์ค์ -ํจ๊ณผ--๋์
-์ ํ-๋ฆฌํฌํธ)) |
|
|
23
26
|
| ๐จ **ํ๋ ์ด๊ณผ ์๋ฐฉ** | 5H/7D rate-limit ์๋ 90% ๋๋ฌ ์ ์ฆ์ ๊ฒฝ๊ณ + `handoff`๋ก ์์
๋ฐฑ์
|
|
|
24
27
|
| ๐ง **์บ์ ๋ญ๋น ๊ฐ์ง** | ํํธ์จยทTTL ์นด์ดํธ๋ค์ดยท1M ์ปจํ
์คํธ ์๋ ๊ฐ์ง โ ํ ํฐ ๊ธ์ฆ ์์ธ์ ์ฝ๋๋ก ์ง๋จ |
|
|
@@ -129,6 +132,21 @@ ratchet์ ๊ฐ์น๋ **ํ ๋ฐฉํฅ ๋์ **์ ์์ต๋๋ค. ๋ฃฐ์ ๊ฐ๋ณ๊ฒ ์ง
|
|
|
129
132
|
|
|
130
133
|
ํ์ ์ ํธ๋ ํธ์ถ ์ยท์ถ๋ ฅ ํ ํฐยท**๋ณ๊ฒฝ์ฑ ๋๊ตฌ ์(Edit/Write/Bash)**ยท**๋๊ตฌ ์๋ฌ ์**ยท์์ฒญ ํ
์คํธ์ด๊ณ , ์ถ๋ ฅ ์๊ณ๊ฐ์ ์ฌ์ฉ์ ์์ ์ ์ต๊ทผ 14์ผ ๋ถํฌ์์ ์๋ ๋ณด์ ๋ฉ๋๋ค (๊ณ ์ ์์๋ ์ํฌ๋ก๋๊ฐ ๋ฐ๋๋ฉด ์ด๊ธ๋๊ธฐ ๋๋ฌธ).
|
|
131
134
|
|
|
135
|
+
<details>
|
|
136
|
+
<summary>์ ์ด ์ค๊ณ์ธ๊ฐ โ ๋ฆฌ์์น ๊ทผ๊ฑฐ (deep-research ์์ค 21๊ฐ ๊ต์ฐจ๊ฒ์ฆ + ๋ก์ปฌ ์ค์ธก 553 ์ํผ์๋)</summary>
|
|
137
|
+
|
|
138
|
+
๊ธฐ์กด LLM ๋ผ์ฐํ
์ฐ๊ตฌยท์์คํ
์ ์กฐ์ฌํ ๊ฒฐ๊ณผ๊ฐ ์ค๊ณ์ ๊ฐ ์ถ์ ๊ฒฐ์ ํ์ต๋๋ค:
|
|
139
|
+
|
|
140
|
+
- **"์ฌ์ด ๊ฒ๋ง ํ์คํ ๋ด๋ฆฌ๋" ๋ณด์์ ๊ฐ๋ฑ์ด ๋ฏธ๊ฐ์ฒ ์ง๋** โ RouterArena(2025) ํ๊ฐ์์ ํ์ ยท์์ฉ ๋ผ์ฐํฐ ์ ๋ถ ์ค๋ผํด(90.9%)์ ํฌ๊ฒ ๋ชป ๋ฏธ์ณค๊ณ (1์ 66.9), ์คํจ ๋ฐฉํฅ์ ์ผ๊ด๋๊ฒ **๋น์ผ ๋ชจ๋ธ๋ก์ ๊ณผ์ ๋ผ์ฐํ
**์ด์์ต๋๋ค. ์ค๋ผํด ๊ธฐ์ค ์ต์์ ๋ชจ๋ธ์ด ์ ๋ง ํ์ํ ์ฟผ๋ฆฌ๋ 20% ๋ฏธ๋ง์ธ๋ฐ(routing collapse ์ฐ๊ตฌ), ์ ์ ๋ก๊ทธ์์ 73%๊ฐ ์ต์์ ํฐ์ด์ ๋จ์ ์์์ต๋๋ค โ ํค๋๋ฃธ์ด ํฝ๋๋ค.
|
|
141
|
+
- **๋์ด๋๋ ํ
์คํธ ์ถ์ ์ด ์๋๋ผ ๊ฒฐ๊ณผ(outcome)๋ก ์ ์** โ RouterArena๋ ๋์ด๋๋ฅผ "42๊ฐ ๋ชจ๋ธ ์ค ๋ช ๊ฐ๊ฐ ์ค์ ๋ก ๋งํ๋"๋ก ๋ผ๋ฒจ๋งํ์ต๋๋ค. ์ฐ๋ฆฌ ๋ก๊ทธ์๋ ๊ฒฐ๊ณผ๊ฐ ์ด๋ฏธ ์์ต๋๋ค: ๋๊ตฌ ์๋ฌยท๋ณ๊ฒฝ์ฑ ๋๊ตฌ ์ยท์ํผ์๋ ๊ธธ์ด. ๋ก์ปฌ ์ค์ธก์์๋ ์๋ฌ ๊ฒฝํ๋ฅ ์ด ํฐ์ด๋ฅผ ๊ฐํ๊ฒ ๊ฐ๋์ต๋๋ค (T2 ํ๋ณด 2% / T1 8% / T0 36%).
|
|
142
|
+
- **์๊ณ๊ฐ์ ์ฌ์ฉ์ ๋ถํฌ์์ ๋ณด์ ** โ RouteLLM์ ๊ณต์ ํ๊ณ๊ฐ "๊ณ ์ ์๊ณ๊ฐ์ ์ฟผ๋ฆฌ ๋ถํฌ๊ฐ ๋ฐ๋๋ฉด ์ด๊ธ๋๋ค"์
๋๋ค. ๊ทธ๋์ ์ถ๋ ฅ ํ ํฐ ์๊ณ๊ฐ์ ์ต๊ทผ 14์ผ p25/p75์์ ์ฌ๊ณ์ฐํฉ๋๋ค(ํด๋จํ ํฌํจ).
|
|
143
|
+
- **์คํจ ์ ์น๊ธ ๊ฒฝ๋ก๊ฐ ๊ฐ๋ฑ ์คํ ๋น์ฉ์ ๋ฎ์ถค** โ FrugalGPT ์บ์ค์ผ์ด๋("์ผ ๋ชจ๋ธ๋ถํฐ, ์ ๋๋ฉด ์๋ก")์ ๊ตํ. Claude Code์์ ์๋ธ์์ด์ ํธ๊ฐ ๋งํ๋ฉด ๋ฉ์ธ ๋ชจ๋ธ์ด ์ด์ด๋ฐ๋ ํํ๋ก ์์ฐ ๊ตฌํ๋๊ณ , ์น๊ฒฉ ๋ฃฐ ํ
์คํธ์๋ ์ด ๊ฐ๋๊ฐ ๋ช
์๋ฉ๋๋ค.
|
|
144
|
+
- **์๋ธ์์ด์ ํธ `model:`์ Anthropic ๊ณต์ ๋น์ฉ ํต์ ๋ฉ์ปค๋์ฆ** โ ๊ณต์ ๋ฌธ์๊ฐ "Haiku ๋ฑ ์ผ ๋ชจ๋ธ๋ก ๋ผ์ฐํ
ํด ๋น์ฉ ํต์ "๋ฅผ ๊ถ์ฅํ์ง๋ง, Claude Code ๋ณธ์ฒด๋ ์๋ ๋ชจ๋ธ ๋ผ์ฐํ
์ ํ์ง ์์ต๋๋ค. ์ฌ์ํ ํด๋ ์ธ์
๋ชจ๋ธ์ด ์ ์ฒด ์ปจํ
์คํธ๋ฅผ ์ฌ์ ์กํ๋ฉฐ ์ฒ๋ฆฌํ๋ ์ด ๊ณต๋ฐฑ์ด route-scan์ด ๋ฉ์ฐ๋ ์๋ฆฌ์
๋๋ค.
|
|
145
|
+
- **ํ์ตํ ๋ถ๋ฅ๊ธฐ(BERT/์๋ฒ ๋ฉ)๋ ์๋์ ์ผ๋ก ๋ฐฐ์ ** โ ์ต๊ณ ์ฑ๋ฅ๋ ์ค๋ผํด๊ณผ 24์ ์ฐจ์ด์ธ ๋ฐ๋ค ํ์ต ๋ฐ์ดํฐ๊ฐ ์๊ณ zero-dep ์์น์ ์ด๊ธ๋ฉ๋๋ค. ์ ๊ท์ ์นดํ
๊ณ ๋ฆฌ + outcome ์ ํธ ์กฐํฉ์ด ํ์ฌ ์์น.
|
|
146
|
+
|
|
147
|
+
์ถ์ฒ(RouteLLMยทFrugalGPTยทRouterArenaยท๋ผ์ฐํ
์๋ฒ ์ด arxiv ๋งํฌ)์ ๋ก์ปฌ ์ค์ธก ์์ธ ํ
์ด๋ธ, ํฐ์ด ๊ธฐ์ค ์ ๋ฌธ์ [docs/TIER_CRITERIA.md](./docs/TIER_CRITERIA.md) ์ฐธ๊ณ .
|
|
148
|
+
</details>
|
|
149
|
+
|
|
132
150
|
```bash
|
|
133
151
|
claude-token-saver route-scan # ์ค์บ (24h ์บ์) + ํฐ์ด๋ณ ํ๋ณด ์ถ๋ ฅ
|
|
134
152
|
claude-token-saver harness promote R1 --project # ํ๋ณด R1์ ๋ชจ๋ธ ํผํ
๋ฃฐ๋ก ๋ฑ๋ก
|
|
@@ -208,6 +226,13 @@ npm uninstall -g claude-cache-monitor && npm i -g claude-token-saver
|
|
|
208
226
|
|
|
209
227
|
## ๋ฆด๋ฆฌ์ค ๋
ธํธ
|
|
210
228
|
|
|
229
|
+
### v3.3.0 (2026-07-13)
|
|
230
|
+
- **์์ ๊ฐ์ํยท๋ธ๋ฆฌํ ๊ฐํ** โ ๋ชจ๋ธ ํผํ
์ ์ ๊ณผ์ ์ด ์ฌ์ฉ์์๊ฒ ๋ณด์ด๋๋ก:
|
|
231
|
+
- SessionStart ํ
์ด ํ๋ณด๋ง๋ค **๋ฑ๋ก ์ ratchet-model.md์ ๊ธฐ๋ก๋ ๋ฃฐ ์๋ฌธ**์ ํจ๊ป ์ฃผ์
โ ๋ฌด์์ด ๋ฑ๋ก๋ ์ง ์ ํํ ๋ณด๊ณ ์น์ธ.
|
|
232
|
+
- ์๋ฌ์จ ๊ธฐ์ค(20%) ์ด๊ณผ๋ก review ์ํ๊ฐ ๋ ๋ฃฐ์ **statusline `๐
ทโ rule-health R<N>` ์นฉ** + ์ธ์
์์ ๋ธ๋ฆฌํ ์์ชฝ์ผ๋ก ํต์ง (์ค๊ณ ๋ฌธ์์ ์๋ ๋ฏธ๊ตฌํ ํญ๋ชฉ ๊ตฌํ. ์ฐ์ ์์: ์ธ์
ํ์ง ๊ฒฝ๊ณ > rule-health > route? ํ๋ณด).
|
|
233
|
+
- ratchet-model.md ํค๋์ ์์ ์คํ ์ `๐ [claude-token-saver] ๋ชจ๋ธ ํผํ
: "<์ ํ>" โ <agent> ์์` ํ ์ค์ ๋จผ์ ํ์ํ๋ผ๋ ์ง์ ์ถ๊ฐ โ ์ด๋ค ๋๊ตฌ๊ฐ ํ ํฐ์ ์๋ผ๋์ง ๊ฐ์ํ.
|
|
234
|
+
- README์ 3.x ์ ์ฒด์ฑ ๋ฐ์ (์๋จ ์์ฝ์ ๋ชจ๋ธ ํผํ
์์ ์ถ๊ฐ, route-scan ์น์
์ ๋ฆฌ์์น ๊ทผ๊ฑฐ ์ ์ด์), model-rules.js ์ฃผ์-๊ตฌํ ๋ถ์ผ์น ์์ .
|
|
235
|
+
|
|
211
236
|
### v3.2.2 (2026-07-13)
|
|
212
237
|
- **๋ฑ๋ก ๋ฃฐ ์ฌ์ ์ ์ฐจ๋จ** โ ์ด๋ฏธ ๋ชจ๋ธ ํผํ
๋ฃฐ์ด ์๋ (ํฐ์ด|์นดํ
๊ณ ๋ฆฌ|ํ๋ก์ ํธ) ์กฐํฉ์ ์ค์บ ํ๋ณด์์ ์๋ ์ ์ธ (๊ธ๋ก๋ฒ ๋ฃฐ์ ์ ํ๋ก์ ํธ ์ปค๋ฒ). promote๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๋ฑ๋ก๋ ๋ฃฐ(๋ง์ด๊ทธ๋ ์ด์
๋ฑ)์ด ํ๋ณด๋ก ๋์ด์๋๋ ๋ฌธ์ ์์ .
|
|
213
238
|
|
package/bin/cli.js
CHANGED
|
@@ -558,17 +558,37 @@ async function main() {
|
|
|
558
558
|
} catch { /* refresh is best-effort; stale cache still usable below */ }
|
|
559
559
|
}
|
|
560
560
|
const open = rs.openCandidates(cache);
|
|
561
|
-
|
|
561
|
+
// Registered rules whose delegated-category error rate crossed the
|
|
562
|
+
// health threshold since promotion โ the user approved these, so a
|
|
563
|
+
// status change must be briefed, not just written into the md file.
|
|
564
|
+
let reviewRules = [];
|
|
565
|
+
try {
|
|
566
|
+
const mr = await import('../src/model-rules.js');
|
|
567
|
+
reviewRules = mr.loadModelRules().rules
|
|
568
|
+
.map((r, i) => ({ ...r, n: i + 1 }))
|
|
569
|
+
.filter((r) => r.status === 'review');
|
|
570
|
+
} catch { /* registry unreadable โ candidate briefing still goes out */ }
|
|
571
|
+
if (open.length === 0 && reviewRules.length === 0) return; // silent โ nothing to inject
|
|
562
572
|
const lines = [];
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
573
|
+
if (open.length > 0) {
|
|
574
|
+
lines.push(`[claude-token-saver route-scan] ์ต๊ทผ ${cache.days}์ผ ์ธ์
์์ ์์ ๋ชจ๋ธ(opus/fable)์ด ์ฒ๋ฆฌํ ์์ ๊ฐ๋ฅ ๋ฐ๋ณต ์์
์ด ๊ฐ์ง๋์์ต๋๋ค:`);
|
|
575
|
+
for (const c of open) {
|
|
576
|
+
const tierNote = c.tier === 'T1' ? 'sonnet ์์(์ค๊ฐ ๋๋)' : `${c.agent} ์์(๊ฒฝ๋)`;
|
|
577
|
+
lines.push(` R${c.id} [${c.tier || 'T2'}] (ร${c.count}, ${c.project}): ${c.label} โ ${tierNote} ๊ถ์ฅ (scope ์ ์: ${c.suggestedScope})`);
|
|
578
|
+
lines.push(` ์์: "${c.example}"`);
|
|
579
|
+
lines.push(` ๋ฑ๋ก ์ ratchet-model.md์ ๊ธฐ๋ก๋ ๋ฃฐ: "${c.rule}"`);
|
|
580
|
+
}
|
|
581
|
+
lines.push('๋ฑ๋กํ๋ฉด ๋ค์ ์ธ์
๋ถํฐ ์๋ ์์๋ฉ๋๋ค. ์ฌ์ฉ์์๊ฒ ๋ฑ๋ก ์ฌ๋ถ๋ฅผ ๋ฌผ์ ๋ ์ ๋ฃฐ ์๋ฌธ์ ๊ทธ๋๋ก ๋ณด์ฌ์ฃผ๊ณ , scope๊น์ง ํ์ธํ ๋ค ์คํํ์ธ์:');
|
|
582
|
+
lines.push(' claude-token-saver harness promote R<N> --project|--global # scope๋ ๋ฐ๋์ ์ฌ์ฉ์์๊ฒ ํ์ธ');
|
|
583
|
+
lines.push(' claude-token-saver route-scan dismiss <N> # ์ฌ์ฉ์๊ฐ ์์น ์์ผ๋ฉด');
|
|
584
|
+
}
|
|
585
|
+
if (reviewRules.length > 0) {
|
|
586
|
+
lines.push(`[claude-token-saver rule-health] ๋ฑ๋ก๋ ๋ชจ๋ธ ํผํ
๋ฃฐ ์ค ์์ ๋์ ์ ํ์ ์๋ฌ์จ์ด ๊ธฐ์ค(20%)์ ๋์ ๋ฃฐ์ด ์์ต๋๋ค โ ์ฌ์ฉ์์๊ฒ ๋ธ๋ฆฌํํ๊ณ ์กฐ๊ฑด ์ขํ๊ธฐ/์ ๊ฑฐ๋ฅผ ์์ํ์ธ์:`);
|
|
587
|
+
for (const r of reviewRules) {
|
|
588
|
+
lines.push(` #${r.n} [${r.tier}|${r.scope}] ์๋ฌ์จ ${Math.round((r.errRate || 0) * 100)}%: ${r.rule}`);
|
|
589
|
+
}
|
|
590
|
+
lines.push(' ์ ๊ฑฐ: claude-token-saver route-scan rules rm <N>');
|
|
568
591
|
}
|
|
569
|
-
lines.push('์ด ํจํด์ ๋ซ์ณ ๋ฃฐ๋ก ๋ฑ๋กํ๋ฉด ๋ค์ ์ธ์
๋ถํฐ ์๋ ์์๋ฉ๋๋ค. ์ ์ ํ ์์ ์ ์ฌ์ฉ์์๊ฒ ๋ฑ๋ก ์ฌ๋ถ์ scope๋ฅผ ๋ฌผ์ด๋ณธ ๋ค ์คํํ์ธ์:');
|
|
570
|
-
lines.push(' claude-token-saver harness promote R<N> --project|--global # scope๋ ๋ฐ๋์ ์ฌ์ฉ์์๊ฒ ํ์ธ');
|
|
571
|
-
lines.push(' claude-token-saver route-scan dismiss <N> # ์ฌ์ฉ์๊ฐ ์์น ์์ผ๋ฉด');
|
|
572
592
|
console.log(lines.join('\n'));
|
|
573
593
|
return;
|
|
574
594
|
}
|
package/package.json
CHANGED
package/src/harness.js
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
appendRatchetRule,
|
|
21
21
|
} from './harness-templates.js';
|
|
22
22
|
import { routeWarningForStatusline } from './route-scan.js';
|
|
23
|
+
import { ruleHealthWarningForStatusline } from './model-rules.js';
|
|
23
24
|
|
|
24
25
|
const require = createRequire(import.meta.url);
|
|
25
26
|
function readHarnessState() {
|
|
@@ -419,6 +420,14 @@ export function harnessStatusForStatusline(cfg, { root } = {}) {
|
|
|
419
420
|
else if (state.pevSkip) warning = 'PEV-skip';
|
|
420
421
|
}
|
|
421
422
|
}
|
|
423
|
+
// Below session-quality warnings: a promoted delegation rule whose
|
|
424
|
+
// category started failing (`rule-health R<N>`) โ the user approved that
|
|
425
|
+
// rule, so its degradation outranks a mere new-candidate nudge.
|
|
426
|
+
if (!warning) {
|
|
427
|
+
try {
|
|
428
|
+
warning = ruleHealthWarningForStatusline(projectRoot);
|
|
429
|
+
} catch { /* registry unreadable โ stay silent */ }
|
|
430
|
+
}
|
|
422
431
|
// Lowest precedence: route-scan delegation candidate (`route? R<N>`).
|
|
423
432
|
// Session-quality warnings above always win โ routing is an optimization
|
|
424
433
|
// nudge, not a correctness signal. Cheap: one small cached-JSON read.
|
package/src/model-rules.js
CHANGED
|
@@ -97,6 +97,10 @@ export function renderModelRatchet(rules) {
|
|
|
97
97
|
'๋ก๊ทธ ๊ธฐ๋ฐ ํฐ์ด ์์ ๋ฃฐ. ์ด ํ์ผ์ route-scan์ด ๋งค ์ค์บ๋ง๋ค ํต์งธ๋ก ์ฌ์์ฑํ๋ฏ๋ก',
|
|
98
98
|
'์ง์ ์์ ํ์ง ๋ง์ธ์ โ ๋ชฉ๋ก/์ ๊ฑฐ: `claude-token-saver route-scan rules [rm <N>]`.',
|
|
99
99
|
'',
|
|
100
|
+
'์๋ ๋ฃฐ์ ๋ฐ๋ผ ์์์ ์คํํ ๋๋ ์ฌ์ฉ์์๊ฒ ๋ค์ ํ ์ค์ ๋จผ์ ํ์ํ ๊ฒ',
|
|
101
|
+
'(์ด๋ค ๋๊ตฌ๊ฐ ํ ํฐ์ ์๋ผ๊ณ ์๋์ง ๊ฐ์ํ):',
|
|
102
|
+
'`๐ [claude-token-saver] ๋ชจ๋ธ ํผํ
: "<์ ํ>" โ <agent> ์์`',
|
|
103
|
+
'',
|
|
100
104
|
'## Rules',
|
|
101
105
|
'',
|
|
102
106
|
];
|
|
@@ -110,6 +114,23 @@ export function renderModelRatchet(rules) {
|
|
|
110
114
|
return lines.join('\n') + '\n';
|
|
111
115
|
}
|
|
112
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Statusline helper (docs/TIER_CRITERIA.md ยงrule-health) โ cheapest possible
|
|
119
|
+
* check, one small JSON read. Returns `rule-health R<N>` for the first
|
|
120
|
+
* review-flagged rule relevant to this project (its own root, or global
|
|
121
|
+
* scope), else null. N is the 1-based registry index, matching the numbering
|
|
122
|
+
* of `route-scan rules [rm <N>]` so the fix command is one lookup away.
|
|
123
|
+
*/
|
|
124
|
+
export function ruleHealthWarningForStatusline(projectRoot) {
|
|
125
|
+
const { rules } = loadModelRules();
|
|
126
|
+
for (let i = 0; i < rules.length; i++) {
|
|
127
|
+
const r = rules[i];
|
|
128
|
+
if (r.status !== 'review') continue;
|
|
129
|
+
if (r.scope === 'global' || r.targetRoot === projectRoot) return `rule-health R${i + 1}`;
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
113
134
|
export function modelRatchetPathFor(scope, targetRoot) {
|
|
114
135
|
return scope === 'global'
|
|
115
136
|
? join(homedir(), '.claude', 'ratchet-model.md')
|
|
@@ -150,8 +171,11 @@ export function syncAllFiles({ previousPaths = [] } = {}) {
|
|
|
150
171
|
* for each registered rule, recompute recurrence count and the error rate
|
|
151
172
|
* of episodes in its (tier-eligible) category โ the rule-health signal.
|
|
152
173
|
*
|
|
153
|
-
* `episodeStats`: Map "category|project"
|
|
154
|
-
*
|
|
174
|
+
* `episodeStats`: Map "category|project" (plus a "category|*" wildcard key
|
|
175
|
+
* that global-scope rules fall back to) โ { count, errCount, epCount }.
|
|
176
|
+
* errCount/epCount measure the scan window's shape-eligible episodes โ ones
|
|
177
|
+
* an expensive model handled directly that still look T1/T2 by shape (tier
|
|
178
|
+
* judged with the error signal zeroed; see route-scan's rule-health pass).
|
|
155
179
|
*/
|
|
156
180
|
export function refreshModelRules(episodeStats, { now } = {}) {
|
|
157
181
|
const data = loadModelRules();
|