sprag-cli 3.41.0 → 3.42.1

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/src/doc2md.cjs CHANGED
@@ -158,7 +158,7 @@ function banner(sourcePath, saving) {
158
158
  const src = fs.statSync(sourcePath);
159
159
  const lines = [
160
160
  '<!--',
161
- 'claude-token-saver doc2md 가 변환한 파일입니다. 직접 편집하지 마십시오.',
161
+ 'sprag doc2md 가 변환한 파일입니다. 직접 편집하지 마십시오.',
162
162
  `원본: ${path.resolve(sourcePath)} (${humanBytes(src.size)})`,
163
163
  `변환: ${new Date().toISOString()} · Markdown ${humanBytes(Buffer.byteLength(saving.markdown, 'utf8'))} · 약 ${saving.tokens.toLocaleString('en-US')} 토큰`,
164
164
  ];
@@ -642,7 +642,7 @@ function markNoticeShown() {
642
642
  } catch { /* an unwritable state dir just means the notice repeats */ }
643
643
  }
644
644
 
645
- const INSTALL_HINT = 'claude-token-saver doc2md install-converter';
645
+ const INSTALL_HINT = 'sprag doc2md install-converter';
646
646
 
647
647
  /**
648
648
  * Decide what to tell Claude Code about one PreToolUse(Read) payload.
@@ -847,8 +847,8 @@ function contextForPrompt(payload, opts = {}) {
847
847
  : ` ${name}: the converter needs Python 3.10+, and none is on PATH (macOS ships 3.9). Tell the user to install a newer Python, e.g. \`brew install python\`.`);
848
848
  } else if (result.reason === 'no-figparser') {
849
849
  lines.push(lang === 'ko'
850
- ? ` ${name}: .fig 파서가 없어 변환하지 못했습니다. 설치: claude-token-saver doc2md install-converter`
851
- : ` ${name}: no .fig parser installed. Install it with: claude-token-saver doc2md install-converter`);
850
+ ? ` ${name}: .fig 파서가 없어 변환하지 못했습니다. 설치: sprag doc2md install-converter`
851
+ : ` ${name}: no .fig parser installed. Install it with: sprag doc2md install-converter`);
852
852
  } else if (result.reason === 'sensitive') {
853
853
  lines.push(lang === 'ko'
854
854
  ? ` ${name}: 파일명이 민감 문서 패턴에 걸려 변환하지 않았습니다.`
@@ -861,8 +861,8 @@ function contextForPrompt(payload, opts = {}) {
861
861
  }
862
862
  if (paths.length > targets.length) {
863
863
  lines.push(lang === 'ko'
864
- ? ` (문서 ${paths.length}개 가운데 앞 ${targets.length}개만 변환했습니다. 나머지는 \`claude-token-saver doc2md <경로>\` 로 변환하십시오.)`
865
- : ` (converted the first ${targets.length} of ${paths.length} documents; run \`claude-token-saver doc2md <path>\` for the rest.)`);
864
+ ? ` (문서 ${paths.length}개 가운데 앞 ${targets.length}개만 변환했습니다. 나머지는 \`sprag doc2md <경로>\` 로 변환하십시오.)`
865
+ : ` (converted the first ${targets.length} of ${paths.length} documents; run \`sprag doc2md <path>\` for the rest.)`);
866
866
  }
867
867
 
868
868
  return lang === 'ko'
@@ -870,15 +870,15 @@ function contextForPrompt(payload, opts = {}) {
870
870
  '[doc2md] 이 프롬프트에 문서 경로가 있어 Markdown 으로 변환해 두었습니다.',
871
871
  ...lines,
872
872
  '원본 대신 위 변환본을 Read 하십시오. pptx·xlsx·docx 는 Read 도구가 이진 파일이라며 거부하므로 원본을 직접 열 수 없습니다.',
873
- '변환이 일어났다는 사실은 사용자에게도 보여야 하므로, 답변 첫 줄에 변환한 문서마다 다음 형식으로 한 줄씩 출력하십시오: `📄 [claude-token-saver] doc2md: <파일명> (<원본 크기> → <Markdown 크기>, 약 <토큰> 토큰)`. 절감액이 함께 안내됐다면 그 금액도 같은 줄 끝에 덧붙이십시오.',
874
- '경로가 주어지지 않은 문서를 열어야 할 때는 `claude-token-saver doc2md <경로>` 를 실행해 변환본 경로를 얻으십시오.',
873
+ '변환이 일어났다는 사실은 사용자에게도 보여야 하므로, 답변 첫 줄에 변환한 문서마다 다음 형식으로 한 줄씩 출력하십시오: `📄 [sprag] doc2md: <파일명> (<원본 크기> → <Markdown 크기>, 약 <토큰> 토큰)`. 절감액이 함께 안내됐다면 그 금액도 같은 줄 끝에 덧붙이십시오.',
874
+ '경로가 주어지지 않은 문서를 열어야 할 때는 `sprag doc2md <경로>` 를 실행해 변환본 경로를 얻으십시오.',
875
875
  ].join('\n')
876
876
  : [
877
877
  '[doc2md] This prompt names document paths, which have been converted to Markdown:',
878
878
  ...lines,
879
879
  'Read the conversions above rather than the originals: Read refuses pptx/xlsx/docx as binary files, so the originals cannot be opened directly.',
880
- 'The user cannot see that any of this happened, so open your reply with one line per converted document: `📄 [claude-token-saver] doc2md: <name> (<source size> → <markdown size>, ~<tokens> tokens)`, adding the saving above if one was reported.',
881
- 'For a document whose path was not given here, run `claude-token-saver doc2md <path>` to get its conversion.',
880
+ 'The user cannot see that any of this happened, so open your reply with one line per converted document: `📄 [sprag] doc2md: <name> (<source size> → <markdown size>, ~<tokens> tokens)`, adding the saving above if one was reported.',
881
+ 'For a document whose path was not given here, run `sprag doc2md <path>` to get its conversion.',
882
882
  ].join('\n');
883
883
  }
884
884
 
@@ -893,14 +893,14 @@ function sessionNote(lang = 'en') {
893
893
  if (lang === 'ko') {
894
894
  return [
895
895
  '[doc2md] 문서(pptx·xlsx·pdf·docx)를 다룰 때의 규칙입니다.',
896
- ' 문서를 열어야 하는데 Read 가 이진 파일이라며 거부하면, `claude-token-saver doc2md <경로>` 를 실행하고 그 결과로 나온 .md 를 Read 하십시오.',
896
+ ' 문서를 열어야 하는데 Read 가 이진 파일이라며 거부하면, `sprag doc2md <경로>` 를 실행하고 그 결과로 나온 .md 를 Read 하십시오.',
897
897
  ' 사용자가 문서를 메시지에 직접 첨부했다면, 첨부는 내용 전체가 컨텍스트에 실려 토큰을 크게 씁니다. 다음부터는 첨부 대신 파일 경로를 적어 달라고 안내하십시오. 경로로 주면 변환본만 읽습니다.',
898
- ' 변환은 단방향입니다. 변환본 .md 를 고쳐도 원본에는 반영되지 않습니다. 문서 수정 요청을 받으면: ① 원본을 복사하고 ② 복사본을 스크립트로 수정하십시오. pptx·docx·xlsx 는 도구 venv 파이썬에 python-pptx·python-docx·openpyxl 이 준비되어 있고(`claude-token-saver doc2md` 상태 출력에 경로가 나옵니다), .fig 는 openfig-core 로 편집·재인코드합니다. ③ 수정한 복사본을 doc2md 로 재변환해 변경이 들어갔는지 검증하십시오. 차트·이미지 같은 시각 요소는 변환본에 안 잡히므로 텍스트 검증만으로 완료를 단정하지 마십시오.',
898
+ ' 변환은 단방향입니다. 변환본 .md 를 고쳐도 원본에는 반영되지 않습니다. 문서 수정 요청을 받으면: ① 원본을 복사하고 ② 복사본을 스크립트로 수정하십시오. pptx·docx·xlsx 는 도구 venv 파이썬에 python-pptx·python-docx·openpyxl 이 준비되어 있고(`sprag doc2md` 상태 출력에 경로가 나옵니다), .fig 는 openfig-core 로 편집·재인코드합니다. ③ 수정한 복사본을 doc2md 로 재변환해 변경이 들어갔는지 검증하십시오. 차트·이미지 같은 시각 요소는 변환본에 안 잡히므로 텍스트 검증만으로 완료를 단정하지 마십시오.',
899
899
  ].join('\n');
900
900
  }
901
901
  return [
902
902
  '[doc2md] Handling documents (pptx/xlsx/pdf/docx):',
903
- ' If Read refuses a document as a binary file, run `claude-token-saver doc2md <path>` and Read the .md it prints.',
903
+ ' If Read refuses a document as a binary file, run `sprag doc2md <path>` and Read the .md it prints.',
904
904
  ' If the user attached a document to their message, its full contents were billed into the context. Tell them that naming the file path instead is far cheaper, since only the converted Markdown gets read.',
905
905
  ' Conversions are one-way: editing the cached .md changes nothing in the source. When asked to modify a document: ① copy the original, ② edit the COPY with a script — the managed venv python has python-pptx/python-docx/openpyxl, and .fig edits go through openfig-core — then ③ re-convert the copy with doc2md to verify the change landed. Charts and images do not appear in conversions, so text verification alone does not prove visual edits.',
906
906
  ].join('\n');
@@ -939,7 +939,7 @@ function decideForWrite(context) {
939
939
  + ' 문서 수정이 목적이라면: 원본을 복사한 뒤(cp) 복사본을 스크립트로 수정하십시오. '
940
940
  + `pptx·docx·xlsx 는 ${managedPython()} 에 python-pptx·python-docx·openpyxl 이 설치되어 있고, `
941
941
  + '.fig 는 doc2md-fig 의 openfig-core 로 편집·재인코드할 수 있습니다. '
942
- + '수정 후 복사본을 `claude-token-saver doc2md <복사본>` 으로 재변환해 의도한 변경이 들어갔는지 확인하십시오. 원본은 절대 직접 수정하지 마십시오.',
942
+ + '수정 후 복사본을 `sprag doc2md <복사본>` 으로 재변환해 의도한 변경이 들어갔는지 확인하십시오. 원본은 절대 직접 수정하지 마십시오.',
943
943
  };
944
944
  }
945
945
 
@@ -949,7 +949,7 @@ function decideForWrite(context) {
949
949
  reason: `[doc2md] ${path.basename(abs)} 는 이진 문서입니다. Edit/Write 는 텍스트를 쓰므로 이 파일을 파괴합니다. `
950
950
  + '수정하려면 원본을 복사한 뒤(cp) 복사본을 스크립트로 고치십시오. '
951
951
  + `pptx·docx·xlsx 는 ${managedPython()} 의 python-pptx·python-docx·openpyxl, .fig 는 openfig-core 를 쓰고, `
952
- + '수정 후 `claude-token-saver doc2md <복사본>` 재변환으로 결과를 검증하십시오.',
952
+ + '수정 후 `sprag doc2md <복사본>` 재변환으로 결과를 검증하십시오.',
953
953
  };
954
954
  }
955
955
  return null;
package/src/handoff.js CHANGED
@@ -70,7 +70,7 @@ function renderTemplate({ now, cwd, git, caps }) {
70
70
  const lines = [];
71
71
  lines.push(`# Handoff — ${ymd(now)} ${pad(now.getHours())}:${pad(now.getMinutes())}`);
72
72
  lines.push('');
73
- lines.push(`Generated by \`claude-token-saver handoff\`.`);
73
+ lines.push(`Generated by \`sprag handoff\`.`);
74
74
  lines.push('');
75
75
  lines.push('## Context');
76
76
  lines.push('');
@@ -51,7 +51,7 @@ export function harnessClaudeMdBlock(scope = 'project') {
51
51
  return `${HARNESS_BLOCK_BEGIN}
52
52
  ## 🅷 Harness Rules (claude-token-saver)
53
53
 
54
- 이 섹션은 \`claude-token-saver harness init\`이 생성합니다. 5가지 원칙 모두를
54
+ 이 섹션은 \`sprag harness init\`이 생성합니다. 5가지 원칙 모두를
55
55
  지키면 statusline에 \`🅷 5/5\`로 표시되고, 빠진 게 있으면 \`🅷 3/5\` 식으로
56
56
  경고합니다. 수정해도 무방하지만, 섹션 헤더(### 1. ~ ### 5.)는 검출용이므로
57
57
  지우지 마세요.
@@ -60,7 +60,7 @@ ${HARNESS_SECTIONS[0].heading}
60
60
  - 같은 에러·오해·반복 작업이 한 번 더 발생하면 즉시 \`.claude/ratchet.md\`에
61
61
  "조건 → 행동" 한 줄로 룰 추가.
62
62
  - claude-token-saver가 후보를 감지하면 statusline에 \`🅷⚠ ratchet?\`로 알림.
63
- \`claude-token-saver harness promote "<rule>" --project|--global\`로 승인.
63
+ \`sprag harness promote "<rule>" --project|--global\`로 승인.
64
64
  - **scope는 항상 사용자에게 먼저 물어볼 것** — 프로젝트 한정이면 \`--project\`,
65
65
  도구·환경 일반 룰이면 \`--global\`(\`~/.claude/ratchet.md\`). Bash 환경은
66
66
  non-TTY라 CLI의 readline 프롬프트가 안 뜨므로, 호출자(LLM)가 직접 묻고
@@ -108,9 +108,9 @@ ${HARNESS_SECTIONS[4].heading}
108
108
  ---
109
109
 
110
110
  📌 운영:
111
- - \`claude-token-saver harness check\` — 현재 셋업 점수
112
- - \`claude-token-saver harness promote "<룰>" --project|--global\` — ratchet에 룰 추가 (scope는 사용자에게 먼저 물어볼 것)
113
- - \`claude-token-saver harness off\` — statusline 표시 끄기
111
+ - \`sprag harness check\` — 현재 셋업 점수
112
+ - \`sprag harness promote "<룰>" --project|--global\` — ratchet에 룰 추가 (scope는 사용자에게 먼저 물어볼 것)
113
+ - \`sprag harness off\` — statusline 표시 끄기
114
114
 
115
115
  ---
116
116
 
@@ -127,13 +127,13 @@ export function harnessRatchetMdInitial() {
127
127
 
128
128
  같은 실수가 두 번 발생하면 여기에 한 줄 추가됩니다. 형식: "YYYY-MM-DD: <조건> → <행동>".
129
129
 
130
- \`claude-token-saver harness promote "<rule>"\`로 룰을 추가하면 자동으로
130
+ \`sprag harness promote "<rule>"\`로 룰을 추가하면 자동으로
131
131
  이 파일에 append 됩니다.
132
132
 
133
133
  이 파일은 CLAUDE.md의 \`@\` import로 매 세션 로드됩니다 — 즉 여기 있는 모든 줄이
134
134
  매 요청마다 토큰을 씁니다. 날짜 뒤에 \`[태그]\`를 붙여두면 나중에 묶어서 정리할 수
135
135
  있습니다: \`- 2026-05-08: [video,tts] ...\` →
136
- \`claude-token-saver harness prune --tag video\` (삭제 아니라 ratchet-archive.md로 이동).
136
+ \`sprag harness prune --tag video\` (삭제 아니라 ratchet-archive.md로 이동).
137
137
 
138
138
  ## Rules
139
139
 
package/src/history.js CHANGED
@@ -306,7 +306,7 @@ export function recordCapTransition(window) {
306
306
 
307
307
  /**
308
308
  * Record a handoff write — invoked by the `handoff` subcommand so
309
- * `claude-token-saver history` shows when work was backed up to a HANDOFF file.
309
+ * `sprag history` shows when work was backed up to a HANDOFF file.
310
310
  *
311
311
  * @param {string} filePath
312
312
  * @returns {boolean}
package/src/installer.js CHANGED
@@ -22,19 +22,19 @@ const STATUSLINE_REFRESH_INTERVAL = 5;
22
22
 
23
23
  const SKILL_BODY = `---
24
24
  name: claude-token-saver
25
- description: Use when the user mentions Claude Code token usage, prompt cache hit rate, TTL/expiry, the 1M context window, cache misses, output spikes, rate-limit caps (5h/7d), or anything in the statusline produced by claude-token-saver (chips like "🚨 5H 94%", "🚨 7D 92%", "⚠ Ctx 500k+", "⚠ Input spike", "⚠ Cache miss", "⚠ 5m TTL", "⚠ Rebuild churn", "⚠ Output heavy", "⚠ Call surge", "⏳ Cache expires", "💰 Cache saved", "🧠 Cache hit"). Also use when they ask to view token-usage history, want to understand a warning they just saw, or want to back up work before a session cap with \`claude-token-saver handoff\`.
25
+ description: Use when the user mentions Claude Code token usage, prompt cache hit rate, TTL/expiry, the 1M context window, cache misses, output spikes, rate-limit caps (5h/7d), or anything in the statusline produced by sprag (chips like "🚨 5H 94%", "🚨 7D 92%", "⚠ Ctx 500k+", "⚠ Input spike", "⚠ Cache miss", "⚠ 5m TTL", "⚠ Rebuild churn", "⚠ Output heavy", "⚠ Call surge", "⏳ Cache expires", "💰 Cache saved", "🧠 Cache hit"). Also use when they ask to view token-usage history, want to understand a warning they just saw, or want to back up work before a session cap with \`sprag handoff\`.
26
26
  ---
27
27
 
28
- # claude-token-saver — Claude Code Token Monitor
28
+ # sprag — Claude Code Token Monitor
29
29
 
30
- This skill helps users interpret and act on the \`claude-token-saver\` statusline
30
+ This skill helps users interpret and act on the \`sprag\` statusline
31
31
  in Claude Code. The statusline updates every ~1s and shows cache health, TTL
32
32
  countdown, savings, and (when relevant) a leading warning chip.
33
33
 
34
34
  ## Response language
35
35
 
36
36
  Respond in the user's configured output language. Run
37
- \`claude-token-saver mode\` once at the start of the session and read the
37
+ \`sprag mode\` once at the start of the session and read the
38
38
  \`Output language\` field — if it shows \`language: ko\`, write **all of your
39
39
  prose to the user in Korean** (summary, "All clear" status lines, headings,
40
40
  recommendations). If it shows \`language: en\` (the default), write in
@@ -52,7 +52,7 @@ honor that for the rest of the turn without changing the saved setting.
52
52
  "when did this start happening", or similar.
53
53
  - The user is approaching a rate-limit cap and wants to back up the current
54
54
  work so a fresh session can continue (point them at
55
- \`claude-token-saver handoff\`).
55
+ \`sprag handoff\`).
56
56
  - The user wants to see the token-usage history file or asks for a summary
57
57
  of recent warnings.
58
58
  - The user asks for a quick token report or "current state" check (the
@@ -62,16 +62,16 @@ honor that for the rest of the turn without changing the saved setting.
62
62
  ## What to do
63
63
 
64
64
  1. **Lead with the most recent warning + how to handle it.** Run
65
- \`claude-token-saver last\` first. It returns the most recent warning event
65
+ \`sprag last\` first. It returns the most recent warning event
66
66
  (chip + detail + timestamp) plus the full advice block for it. Surface that
67
67
  to the user before anything else — this is what they came for.
68
68
  2. **Identify the chip.** If the user pasted a statusline (instead of relying
69
69
  on \`last\`), pull out the leading \`⚠ ...\` chip. That maps to a specific
70
70
  issue category.
71
- 3. **Show recent history.** Run \`claude-token-saver history\` (default last 7
71
+ 3. **Show recent history.** Run \`sprag history\` (default last 7
72
72
  days) to see the chronology of warning transitions. Each entry is timestamped,
73
73
  bilingual (English line + 한국어), and includes a \`💡\` action tip inline.
74
- 4. **Drill down on the live state.** Run \`claude-token-saver --days 1\` (or
74
+ 4. **Drill down on the live state.** Run \`sprag --days 1\` (or
75
75
  another window) to render the full table view, which lists per-session
76
76
  spikes and recommended actions.
77
77
  5. **Explain the warning** in plain language. Use the chip → cause table:
@@ -94,7 +94,7 @@ honor that for the rest of the turn without changing the saved setting.
94
94
  that is expected, not a failure of this tool.
95
95
 
96
96
  6. **Suggest the next action.** For \`🚨 5H/7D\` chips, recommend running
97
- \`claude-token-saver handoff\` to back up the current work to a
97
+ \`sprag handoff\` to back up the current work to a
98
98
  \`HANDOFF-*.md\` file before the cap hits, then continue in a fresh
99
99
  session. For \`⚠ Ctx 500k+\`, recommend \`/compact\` or \`/clear\` and
100
100
  checking what is pinned into context. For
@@ -103,18 +103,18 @@ honor that for the rest of the turn without changing the saved setting.
103
103
 
104
104
  ## Useful commands
105
105
 
106
- - \`claude-token-saver last\` — most recent warning + full advice (start here).
107
- - \`claude-token-saver last --days 7\` — widen the lookback window.
108
- - \`claude-token-saver\` — full table report (default last 1 day).
109
- - \`claude-token-saver --days 7\` — wider window.
110
- - \`claude-token-saver history\` — recent warning transitions per day, with
106
+ - \`sprag last\` — most recent warning + full advice (start here).
107
+ - \`sprag last --days 7\` — widen the lookback window.
108
+ - \`sprag\` — full table report (default last 1 day).
109
+ - \`sprag --days 7\` — wider window.
110
+ - \`sprag history\` — recent warning transitions per day, with
111
111
  inline \`💡\` action tips.
112
- - \`claude-token-saver history --days 30\` — longer history.
113
- - \`claude-token-saver handoff\` — write a HANDOFF-*.md template in cwd
112
+ - \`sprag history --days 30\` — longer history.
113
+ - \`sprag handoff\` — write a HANDOFF-*.md template in cwd
114
114
  capturing git status + cap snapshot, so a fresh session can resume cleanly.
115
- - \`claude-token-saver mode\` — show statusline preferences.
116
- - \`claude-token-saver mode icon verbose 1d\` — change preferences.
117
- - \`claude-token-saver feedback "<message>"\` — file a bug report or feature
115
+ - \`sprag mode\` — show statusline preferences.
116
+ - \`sprag mode icon verbose 1d\` — change preferences.
117
+ - \`sprag feedback "<message>"\` — file a bug report or feature
118
118
  request for this tool right from the session (tries the gh CLI, then an
119
119
  anonymous no-login submission, then saves locally with a prefilled GitHub
120
120
  issue URL; \`--anonymous\` skips the gh path).
@@ -163,7 +163,7 @@ export function removeLegacyCommand() {
163
163
 
164
164
  // Registers/repairs the Claude Code statusLine entry in ~/.claude/settings.json.
165
165
  // - No statusLine yet: insert ours with refreshInterval:STATUSLINE_REFRESH_INTERVAL.
166
- // - statusLine already points at claude-token-saver: ensure that refreshInterval
166
+ // - statusLine already points at sprag: ensure that refreshInterval
167
167
  // (this is the bit that makes the TTL countdown tick every second while idle).
168
168
  // - statusLine points at a different command: leave it alone unless --force.
169
169
  export function installStatusline({ force = false } = {}) {
@@ -219,7 +219,7 @@ export function installStatusline({ force = false } = {}) {
219
219
 
220
220
  // Registers the SessionStart hook that surfaces route-scan delegation
221
221
  // candidates as session context (startup + /clear). Idempotent: skips when a
222
- // claude-token-saver route-scan hook is already present; never touches other
222
+ // sprag route-scan hook is already present; never touches other
223
223
  // hooks the user configured.
224
224
  const ROUTE_SCAN_HOOK_COMMAND = 'claude-token-saver route-scan --hook';
225
225
 
@@ -15,7 +15,7 @@
15
15
  * Cost: the text is ~1.3k tokens, injected once per session (not per turn) and
16
16
  * covered by the prompt cache from the second request on. A token-saving tool
17
17
  * has no business spending that silently, so the feature is opt-in via
18
- * `claude-token-saver korean on`.
18
+ * `sprag korean on`.
19
19
  *
20
20
  * The guidance itself is vendored from fluent-korean
21
21
  * (https://github.com/snflkd/fluent-korean), Copyright (c) 2026 snflkd, MIT
@@ -67,9 +67,13 @@ export function koreanStyleDecided(cfg = loadConfig()) {
67
67
  * locale variables, then (macOS only, where those are routinely unset) the
68
68
  * system locale.
69
69
  */
70
- export function koreanLocaleDetected({ env = process.env, platform = process.platform } = {}) {
70
+ export function koreanLocaleDetected({ env = process.env, platform = process.platform, cfg } = {}) {
71
71
  try {
72
- if (loadConfig().language === 'ko') return true;
72
+ // The saved language answer only applies to the live process environment.
73
+ // A caller that injects a synthetic `env` (tests, simulations) is asking
74
+ // about that environment, not about this machine's recorded choice.
75
+ const c = cfg !== undefined ? cfg : (env === process.env ? loadConfig() : null);
76
+ if (c && c.language === 'ko') return true;
73
77
  } catch { /* unreadable config falls through to the env checks */ }
74
78
  const posix = [env.LC_ALL, env.LC_MESSAGES, env.LANG, env.LANGUAGE].filter(
75
79
  (v) => typeof v === 'string' && v.trim() && v !== 'C' && v !== 'POSIX',
@@ -176,7 +180,7 @@ export function koreanStyleInjection({ cfg = loadConfig() } = {}) {
176
180
  const text = koreanStyleText();
177
181
  if (!text) return null;
178
182
  return [
179
- '[claude-token-saver korean-style] 이 세션에서 한국어를 출력할 때는 아래 지침을 따르십시오.',
183
+ '[sprag korean-style] 이 세션에서 한국어를 출력할 때는 아래 지침을 따르십시오.',
180
184
  '이 지침은 사용자가 claude-token-saver에 설정한 것입니다.',
181
185
  ...koreanScopeLines(cfg),
182
186
  '표기 규칙(예외 없이 적용): 도구 호출 인자에 한국어를 비롯한 비ASCII 문자열을 담을 때에는 반드시 리터럴 UTF-8로 작성하고, \\uXXXX 유니코드 이스케이프로는 절대 작성하지 마십시오. 이스케이프로 작성하면 글자가 깨진 채 파일에 기록되는 사례가 자주 발생합니다.',
@@ -198,10 +198,10 @@ export function removeModelRule(index1) {
198
198
  export function renderModelRatchet(rules, lang = userLanguage()) {
199
199
  const ko = lang === 'ko';
200
200
  const lines = ko ? [
201
- '# Model-Fitting Ratchet (claude-token-saver 자동 관리)',
201
+ '# Model-Fitting Ratchet (sprag 자동 관리)',
202
202
  '',
203
203
  '로그 기반 티어 위임 룰. 이 파일은 route-scan이 매 스캔마다 통째로 재생성하므로',
204
- '직접 수정하지 마세요 — 목록/제거: `claude-token-saver route-scan rules [rm <N>]`.',
204
+ '직접 수정하지 마세요 — 목록/제거: `sprag route-scan rules [rm <N>]`.',
205
205
  '',
206
206
  '**사용자는 아래 룰에 해당하는 서브에이전트 위임을 이미 승인했습니다.**',
207
207
  '룰에 들어맞는 요청이면 되묻지 말고 바로 위임하십시오. "사용자가 명시적으로',
@@ -212,7 +212,7 @@ export function renderModelRatchet(rules, lang = userLanguage()) {
212
212
  '',
213
213
  '위임을 실행할 때는 사용자에게 다음 한 줄을 먼저 표시할 것',
214
214
  '(어떤 도구가 토큰을 아끼고 있는지 가시화):',
215
- '`🔀 [claude-token-saver] 모델 피팅: "<유형>" → <agent> 위임`',
215
+ '`🔀 [sprag] 모델 피팅: "<유형>" → <agent> 위임`',
216
216
  '',
217
217
  '## 티어 판별 기준 (모든 룰에 공통 적용)',
218
218
  '',
@@ -245,11 +245,11 @@ export function renderModelRatchet(rules, lang = userLanguage()) {
245
245
  '## Rules',
246
246
  '',
247
247
  ] : [
248
- '# Model-Fitting Ratchet (managed by claude-token-saver)',
248
+ '# Model-Fitting Ratchet (managed by sprag)',
249
249
  '',
250
250
  'Log-derived tier delegation rules. route-scan regenerates this file in full',
251
251
  'on every scan — do not edit it by hand. List / remove with:',
252
- '`claude-token-saver route-scan rules [rm <N>]`.',
252
+ '`sprag route-scan rules [rm <N>]`.',
253
253
  '',
254
254
  '**The user has already approved the subagent delegations described below.**',
255
255
  'When a request matches a rule, delegate right away instead of asking. If a',
@@ -260,7 +260,7 @@ export function renderModelRatchet(rules, lang = userLanguage()) {
260
260
  '',
261
261
  'When delegating under a rule below, show the user this line first so it is',
262
262
  'visible which tool is saving tokens:',
263
- '`🔀 [claude-token-saver] model fitting: "<category>" → delegated to <agent>`',
263
+ '`🔀 [sprag] model fitting: "<category>" → delegated to <agent>`',
264
264
  '',
265
265
  '## Tier criteria (apply to every rule below)',
266
266
  '',