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/README.ko.md +84 -84
- package/README.md +84 -84
- package/bin/cli.js +80 -80
- package/package.json +1 -1
- package/src/advice.js +3 -3
- package/src/brief.js +4 -4
- package/src/cohesion.js +2 -2
- package/src/commands/brief.js +7 -7
- package/src/commands/cohesion.js +6 -6
- package/src/commands/compact-window.js +9 -9
- package/src/commands/doc2md.js +6 -6
- package/src/commands/feedback.js +5 -5
- package/src/commands/harness.js +22 -22
- package/src/commands/install.js +23 -23
- package/src/commands/korean.js +14 -14
- package/src/commands/last.js +5 -5
- package/src/commands/mode.js +4 -4
- package/src/commands/route-scan.js +25 -25
- package/src/commands/seed.js +10 -10
- package/src/commands/update-check.js +6 -6
- package/src/doc2md.cjs +15 -15
- package/src/handoff.js +1 -1
- package/src/harness-templates.js +7 -7
- package/src/history.js +1 -1
- package/src/installer.js +21 -21
- package/src/korean-style.js +8 -4
- package/src/model-rules.js +6 -6
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
|
-
'
|
|
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 = '
|
|
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 파서가 없어 변환하지 못했습니다. 설치:
|
|
851
|
-
: ` ${name}: no .fig parser installed. Install it with:
|
|
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}개만 변환했습니다. 나머지는 \`
|
|
865
|
-
: ` (converted the first ${targets.length} of ${paths.length} documents; run \`
|
|
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
|
-
'변환이 일어났다는 사실은 사용자에게도 보여야 하므로, 답변 첫 줄에 변환한 문서마다 다음 형식으로 한 줄씩 출력하십시오: `📄 [
|
|
874
|
-
'경로가 주어지지 않은 문서를 열어야 할 때는 `
|
|
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: `📄 [
|
|
881
|
-
'For a document whose path was not given here, run `
|
|
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 가 이진 파일이라며 거부하면, `
|
|
896
|
+
' 문서를 열어야 하는데 Read 가 이진 파일이라며 거부하면, `sprag doc2md <경로>` 를 실행하고 그 결과로 나온 .md 를 Read 하십시오.',
|
|
897
897
|
' 사용자가 문서를 메시지에 직접 첨부했다면, 첨부는 내용 전체가 컨텍스트에 실려 토큰을 크게 씁니다. 다음부터는 첨부 대신 파일 경로를 적어 달라고 안내하십시오. 경로로 주면 변환본만 읽습니다.',
|
|
898
|
-
' 변환은 단방향입니다. 변환본 .md 를 고쳐도 원본에는 반영되지 않습니다. 문서 수정 요청을 받으면: ① 원본을 복사하고 ② 복사본을 스크립트로 수정하십시오. pptx·docx·xlsx 는 도구 venv 파이썬에 python-pptx·python-docx·openpyxl 이 준비되어 있고(`
|
|
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 `
|
|
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
|
-
+ '수정 후 복사본을 `
|
|
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
|
-
+ '수정 후 `
|
|
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 \`
|
|
73
|
+
lines.push(`Generated by \`sprag handoff\`.`);
|
|
74
74
|
lines.push('');
|
|
75
75
|
lines.push('## Context');
|
|
76
76
|
lines.push('');
|
package/src/harness-templates.js
CHANGED
|
@@ -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
|
-
이 섹션은 \`
|
|
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
|
-
\`
|
|
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
|
-
- \`
|
|
112
|
-
- \`
|
|
113
|
-
- \`
|
|
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
|
-
\`
|
|
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
|
-
\`
|
|
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
|
-
* `
|
|
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
|
|
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
|
-
#
|
|
28
|
+
# sprag — Claude Code Token Monitor
|
|
29
29
|
|
|
30
|
-
This skill helps users interpret and act on the \`
|
|
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
|
-
\`
|
|
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
|
-
\`
|
|
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
|
-
\`
|
|
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 \`
|
|
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 \`
|
|
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
|
-
\`
|
|
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
|
-
- \`
|
|
107
|
-
- \`
|
|
108
|
-
- \`
|
|
109
|
-
- \`
|
|
110
|
-
- \`
|
|
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
|
-
- \`
|
|
113
|
-
- \`
|
|
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
|
-
- \`
|
|
116
|
-
- \`
|
|
117
|
-
- \`
|
|
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
|
|
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
|
-
//
|
|
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
|
|
package/src/korean-style.js
CHANGED
|
@@ -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
|
-
* `
|
|
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
|
-
|
|
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
|
-
'[
|
|
183
|
+
'[sprag korean-style] 이 세션에서 한국어를 출력할 때는 아래 지침을 따르십시오.',
|
|
180
184
|
'이 지침은 사용자가 claude-token-saver에 설정한 것입니다.',
|
|
181
185
|
...koreanScopeLines(cfg),
|
|
182
186
|
'표기 규칙(예외 없이 적용): 도구 호출 인자에 한국어를 비롯한 비ASCII 문자열을 담을 때에는 반드시 리터럴 UTF-8로 작성하고, \\uXXXX 유니코드 이스케이프로는 절대 작성하지 마십시오. 이스케이프로 작성하면 글자가 깨진 채 파일에 기록되는 사례가 자주 발생합니다.',
|
package/src/model-rules.js
CHANGED
|
@@ -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 (
|
|
201
|
+
'# Model-Fitting Ratchet (sprag 자동 관리)',
|
|
202
202
|
'',
|
|
203
203
|
'로그 기반 티어 위임 룰. 이 파일은 route-scan이 매 스캔마다 통째로 재생성하므로',
|
|
204
|
-
'직접 수정하지 마세요 — 목록/제거: `
|
|
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
|
-
'`🔀 [
|
|
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
|
|
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
|
-
'`
|
|
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
|
-
'`🔀 [
|
|
263
|
+
'`🔀 [sprag] model fitting: "<category>" → delegated to <agent>`',
|
|
264
264
|
'',
|
|
265
265
|
'## Tier criteria (apply to every rule below)',
|
|
266
266
|
'',
|