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.
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Subcommand: harness β€” manage the project's CLAUDE.md harness rules.
3
- * claude-token-saver harness init # write CLAUDE.md (5 sections) + ratchet.md
4
- * claude-token-saver harness uninit # remove harness block from CLAUDE.md (backup kept)
5
- * claude-token-saver harness check # show πŸ…· N/5 + which sections are missing
6
- * claude-token-saver harness promote "<rule>" # append a rule to ratchet.md
7
- * claude-token-saver harness pull [--global|--project] # register the package's curated preset rules (default global)
8
- * claude-token-saver harness off | on # toggle the statusline πŸ…· segment
3
+ * sprag harness init # write CLAUDE.md (5 sections) + ratchet.md
4
+ * sprag harness uninit # remove harness block from CLAUDE.md (backup kept)
5
+ * sprag harness check # show πŸ…· N/5 + which sections are missing
6
+ * sprag harness promote "<rule>" # append a rule to ratchet.md
7
+ * sprag harness pull [--global|--project] # register the package's curated preset rules (default global)
8
+ * sprag harness off | on # toggle the statusline πŸ…· segment
9
9
  */
10
10
 
11
11
  import { debug } from '../debug.js';
@@ -49,8 +49,8 @@ export async function run({ args, hasFlag }) {
49
49
  const sec = HARNESS_SECTIONS.find((x) => x.id === id);
50
50
  console.log(` - ${id}: ${sec ? sec.heading.replace(/^#+\s*/, '') : ''}`);
51
51
  }
52
- console.log('\nRun: claude-token-saver harness init (this project)');
53
- console.log(' or: claude-token-saver harness init --global (all projects, ~/.claude/CLAUDE.md)');
52
+ console.log('\nRun: sprag harness init (this project)');
53
+ console.log(' or: sprag harness init --global (all projects, ~/.claude/CLAUDE.md)');
54
54
  } else {
55
55
  console.log('All 5 harness sections present. βœ…');
56
56
  }
@@ -60,7 +60,7 @@ export async function run({ args, hasFlag }) {
60
60
  const dead = [!s.hasRatchetImport && 'ratchet.md', !s.hasModelRatchetImport && 'ratchet-model.md'].filter(Boolean).join(' + ');
61
61
  console.log(`\n⚠ ${dead} is NOT loaded into sessions β€” the harness block has no \`@\` import line for it.`);
62
62
  console.log(' Those rules are being written to a file nothing reads.');
63
- console.log(` Fix: claude-token-saver harness init${s.source === 'global' ? ' --global' : ''} (updates the block in place)`);
63
+ console.log(` Fix: sprag harness init${s.source === 'global' ? ' --global' : ''} (updates the block in place)`);
64
64
  }
65
65
  // Imported ratchets are charged on every request, so their size matters.
66
66
  // Static `@` imports cannot be filtered at load time β€” the only lever is
@@ -71,7 +71,7 @@ export async function run({ args, hasFlag }) {
71
71
  const line = `ratchet.md [${sc}]: ${size.count} rules, ~${size.tokens} tok/request`;
72
72
  if (size.overBudget) {
73
73
  console.log(`\n⚠ ${line} β€” over the ~${RATCHET_TOKEN_BUDGET} token budget.`);
74
- console.log(` Trim: claude-token-saver harness prune${sc === 'global' ? ' --global' : ''} --older-than 6 --dry-run`);
74
+ console.log(` Trim: sprag harness prune${sc === 'global' ? ' --global' : ''} --older-than 6 --dry-run`);
75
75
  console.log(' (project-specific rules belong in --project scope, not global.)');
76
76
  } else {
77
77
  console.log(`${line}`);
@@ -138,8 +138,8 @@ export async function run({ args, hasFlag }) {
138
138
  }
139
139
  const raw = promoteArgs.filter((_, i) => !scopeFlags.has(i)).join(' ').trim();
140
140
  if (!raw) {
141
- console.error('Usage: claude-token-saver harness promote [--global|--project] <N> # from statusline πŸ…·βš  ratchet? #N');
142
- console.error(' or: claude-token-saver harness promote [--global|--project] "<rule text>"');
141
+ console.error('Usage: sprag harness promote [--global|--project] <N> # from statusline πŸ…·βš  ratchet? #N');
142
+ console.error(' or: sprag harness promote [--global|--project] "<rule text>"');
143
143
  process.exit(1);
144
144
  }
145
145
  let rule = raw;
@@ -173,7 +173,7 @@ export async function run({ args, hasFlag }) {
173
173
  const rs = await import('../route-scan.js');
174
174
  const cand = (rs.openCandidates(rs.readRouteScan()) || []).find((c) => c.id === n);
175
175
  if (!cand) {
176
- console.error(`No open route candidate R${n}. Run: claude-token-saver route-scan`);
176
+ console.error(`No open route candidate R${n}. Run: sprag route-scan`);
177
177
  process.exit(1);
178
178
  }
179
179
  rule = lang === 'ko' ? cand.rule : (cand.ruleEn || cand.rule);
@@ -229,7 +229,7 @@ export async function run({ args, hasFlag }) {
229
229
  console.error(`Route candidate R${routeCandidateId} was detected in another project (${routeCandidate.project}),`);
230
230
  console.error('but this cached scan predates project-path tracking.');
231
231
  console.error('Re-scan to capture it, then promote again:');
232
- console.error(' claude-token-saver route-scan --refresh');
232
+ console.error(' sprag route-scan --refresh');
233
233
  process.exit(1);
234
234
  }
235
235
  }
@@ -261,8 +261,8 @@ export async function run({ args, hasFlag }) {
261
261
  ? `(route candidate R${routeCandidateId} resolved β€” λ‹€μŒ μ„Έμ…˜λΆ€ν„° μžλ™ μœ„μž„, 이후 μŠ€μΊ”λ§ˆλ‹€ 둜그 기반 κ°±μ‹ λ©λ‹ˆλ‹€)`
262
262
  : `(route candidate R${routeCandidateId} resolved β€” delegation applies from the next session, refreshed from logs on every rescan)`);
263
263
  console.log(lang === 'ko'
264
- ? 'λ£° λͺ©λ‘/제거: claude-token-saver route-scan rules [rm <N>]'
265
- : 'List / remove: claude-token-saver route-scan rules [rm <N>]');
264
+ ? 'λ£° λͺ©λ‘/제거: sprag route-scan rules [rm <N>]'
265
+ : 'List / remove: sprag route-scan rules [rm <N>]');
266
266
  // Event-triggered refresh: establish the new rule's stat baseline
267
267
  // right away instead of waiting for the next data-gated rescan.
268
268
  try {
@@ -345,8 +345,8 @@ export async function run({ args, hasFlag }) {
345
345
  }
346
346
  if (r.skippedRules && r.added.length) console.log(` (${r.skippedRules} already present β€” skipped)`);
347
347
  console.log(lang === 'ko'
348
- ? '\nν•„μš” μ—†λŠ” 룰은 μ–Έμ œλ“ : claude-token-saver harness list / rm <N>'
349
- : '\nDrop any rule you do not want: claude-token-saver harness list / rm <N>');
348
+ ? '\nν•„μš” μ—†λŠ” 룰은 μ–Έμ œλ“ : sprag harness list / rm <N>'
349
+ : '\nDrop any rule you do not want: sprag harness list / rm <N>');
350
350
  return;
351
351
  }
352
352
 
@@ -365,8 +365,8 @@ export async function run({ args, hasFlag }) {
365
365
  };
366
366
  if (wantProject) print('project');
367
367
  if (wantGlobal) print('global');
368
- console.log('Remove with: claude-token-saver harness rm [--global|--project] <N>');
369
- console.log('Archive in bulk: claude-token-saver harness prune [--global] [--tag <t>] [--older-than <months>] [--dry-run]');
368
+ console.log('Remove with: sprag harness rm [--global|--project] <N>');
369
+ console.log('Archive in bulk: sprag harness prune [--global] [--tag <t>] [--older-than <months>] [--dry-run]');
370
370
  return;
371
371
  }
372
372
 
@@ -406,7 +406,7 @@ export async function run({ args, hasFlag }) {
406
406
  const rmArgs = args.slice(2).filter((a) => a !== '--global' && a !== '--project');
407
407
  const raw = (rmArgs[0] || '').trim();
408
408
  if (!/^\d+$/.test(raw)) {
409
- console.error('Usage: claude-token-saver harness rm [--global|--project] <N> # N from `harness list`');
409
+ console.error('Usage: sprag harness rm [--global|--project] <N> # N from `harness list`');
410
410
  process.exit(1);
411
411
  }
412
412
  const n = parseInt(raw, 10);
@@ -454,6 +454,6 @@ export async function run({ args, hasFlag }) {
454
454
  }
455
455
 
456
456
  console.error(`Unknown harness subcommand: ${sub}`);
457
- console.error('Usage: claude-token-saver harness [check|init|uninit [--purge-ratchet]|promote "<rule>"|pull [--global|--project]|list|rm <N>|prune [--tag <t>] [--older-than <months>] [--dry-run]|off|on]');
457
+ console.error('Usage: sprag harness [check|init|uninit [--purge-ratchet]|promote "<rule>"|pull [--global|--project]|list|rm <N>|prune [--tag <t>] [--older-than <months>] [--dry-run]|off|on]');
458
458
  process.exit(1);
459
459
  }
@@ -3,10 +3,10 @@
3
3
  * user can just mention chip wording and Claude responds. v2.6.0 dropped
4
4
  * the redundant /token-monitor slash command in favor of the skill alone;
5
5
  * a legacy command file is removed automatically. Cross-platform.
6
- * claude-token-saver install # install/update the skill
7
- * claude-token-saver install --force # overwrite existing skill file
8
- * claude-token-saver install --yes # take the defaults instead of asking
9
- * claude-token-saver install --no-input # same as --yes; also implied by CTS_NO_INPUT=1
6
+ * sprag install # install/update the skill
7
+ * sprag install --force # overwrite existing skill file
8
+ * sprag install --yes # take the defaults instead of asking
9
+ * sprag install --no-input # same as --yes; also implied by CTS_NO_INPUT=1
10
10
  */
11
11
 
12
12
  import { debug } from '../debug.js';
@@ -49,7 +49,7 @@ export async function run({ hasFlag }) {
49
49
  chosen = ko ? 'ko' : 'en';
50
50
  }
51
51
  setUserLanguage(chosen);
52
- console.log(` language: set to ${chosen === 'ko' ? 'ν•œκ΅­μ–΄' : 'English'} β€” change it any time with \`claude-token-saver mode lang=${chosen === 'ko' ? 'en' : 'ko'}\``);
52
+ console.log(` language: set to ${chosen === 'ko' ? 'ν•œκ΅­μ–΄' : 'English'} β€” change it any time with \`sprag mode lang=${chosen === 'ko' ? 'en' : 'ko'}\``);
53
53
  } else if (process.env.CTS_LANG) {
54
54
  // Escape hatch for scripted installs, which cannot answer a prompt but
55
55
  // do know which language the machine's user reads.
@@ -87,15 +87,15 @@ export async function run({ hasFlag }) {
87
87
  ? ' κ΅μ²΄ν•˜λ©΄ ν† ν°Β·μΊμ‹œΒ·μƒν•œ κ²½κ³ κ°€ statusline에 ν‘œμ‹œλ©λ‹ˆλ‹€. κΈ°μ‘΄ 섀정은 μ‚¬λΌμ§‘λ‹ˆλ‹€.'
88
88
  : ' replacing it shows token/cache/cap warnings in the statusline; the current one is removed.');
89
89
  const replace = await confirm(lang === 'ko'
90
- ? ' claude-token-saver statusline으둜 κ΅μ²΄ν• κΉŒμš”?'
91
- : ' Replace it with the claude-token-saver statusline?', { defaultValue: false });
90
+ ? ' sprag statusline으둜 κ΅μ²΄ν• κΉŒμš”?'
91
+ : ' Replace it with the sprag statusline?', { defaultValue: false });
92
92
  if (replace) {
93
93
  const { installStatusline } = await import('../installer.js');
94
94
  s = installStatusline({ force: true });
95
95
  } else {
96
96
  s = { ...s, reason: lang === 'ko'
97
- ? 'κΈ°μ‘΄ statusline을 μœ μ§€ν–ˆμŠ΅λ‹ˆλ‹€. κ΅μ²΄ν•˜λ €λ©΄ `claude-token-saver install --force`'
98
- : 'kept your statusline β€” replace later with `claude-token-saver install --force`' };
97
+ ? 'κΈ°μ‘΄ statusline을 μœ μ§€ν–ˆμŠ΅λ‹ˆλ‹€. κ΅μ²΄ν•˜λ €λ©΄ `sprag install --force`'
98
+ : 'kept your statusline β€” replace later with `sprag install --force`' };
99
99
  }
100
100
  }
101
101
  const verb = s.action === 'exists' ? 'already configured (refreshInterval=5)'
@@ -178,8 +178,8 @@ export async function run({ hasFlag }) {
178
178
  }
179
179
  if (!proceed) {
180
180
  console.log(lang === 'ko'
181
- ? ' harness: κ±΄λ„ˆλ›°μ—ˆμŠ΅λ‹ˆλ‹€ β€” λ‚˜μ€‘μ— `claude-token-saver harness init --global` 둜 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.'
182
- : ' harness: skipped β€” set it up later with `claude-token-saver harness init --global`.');
181
+ ? ' harness: κ±΄λ„ˆλ›°μ—ˆμŠ΅λ‹ˆλ‹€ β€” λ‚˜μ€‘μ— `sprag harness init --global` 둜 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.'
182
+ : ' harness: skipped β€” set it up later with `sprag harness init --global`.');
183
183
  throw new SkipStep();
184
184
  }
185
185
  const h = harnessInit({ scope: 'global' });
@@ -194,8 +194,8 @@ export async function run({ hasFlag }) {
194
194
  ? ' harness: 5원칙을 ~/.claude/CLAUDE.md 에 μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€ β€” statusline에 πŸ…· 5/5 κ°€ ν‘œμ‹œλ©λ‹ˆλ‹€.'
195
195
  : ' harness: 5 principles installed in ~/.claude/CLAUDE.md β€” the statusline now shows πŸ…· 5/5.');
196
196
  console.log(lang === 'ko'
197
- ? ' 되돌리렀면: claude-token-saver harness uninit --global'
198
- : ' to undo: claude-token-saver harness uninit --global');
197
+ ? ' 되돌리렀면: sprag harness uninit --global'
198
+ : ' to undo: sprag harness uninit --global');
199
199
  }
200
200
  } catch (e) {
201
201
  // A declined prompt already printed its own line; only real failures fall
@@ -206,8 +206,8 @@ export async function run({ hasFlag }) {
206
206
  // in place, and `harness init` remains available as a manual step.
207
207
  debug('install:harness-init', e);
208
208
  console.log(lang === 'ko'
209
- ? ' harness: μžλ™ 섀정을 κ±΄λ„ˆλ›°μ—ˆμŠ΅λ‹ˆλ‹€ β€” `claude-token-saver harness init --global` 둜 직접 μ„€μ •ν•˜μ„Έμš”.'
210
- : ' harness: auto-setup skipped β€” run `claude-token-saver harness init --global` yourself.');
209
+ ? ' harness: μžλ™ 섀정을 κ±΄λ„ˆλ›°μ—ˆμŠ΅λ‹ˆλ‹€ β€” `sprag harness init --global` 둜 직접 μ„€μ •ν•˜μ„Έμš”.'
210
+ : ' harness: auto-setup skipped β€” run `sprag harness init --global` yourself.');
211
211
  }
212
212
  }
213
213
 
@@ -264,12 +264,12 @@ export async function run({ hasFlag }) {
264
264
  if (interactive || enable) ks.setKoreanStyleEnabled(enable);
265
265
  if (enable) {
266
266
  console.log(lang === 'ko'
267
- ? ' korean: μΌ°μŠ΅λ‹ˆλ‹€ β€” λͺ¨λ“  ν”„λ‘œμ νŠΈμ˜ μ„Έμ…˜ μ‹œμž‘ μ‹œ μ£Όμž…λ©λ‹ˆλ‹€. 끄렀면 `claude-token-saver korean off`.'
268
- : ' korean: enabled β€” injected at session start in every project. Turn off with `claude-token-saver korean off`.');
267
+ ? ' korean: μΌ°μŠ΅λ‹ˆλ‹€ β€” λͺ¨λ“  ν”„λ‘œμ νŠΈμ˜ μ„Έμ…˜ μ‹œμž‘ μ‹œ μ£Όμž…λ©λ‹ˆλ‹€. 끄렀면 `sprag korean off`.'
268
+ : ' korean: enabled β€” injected at session start in every project. Turn off with `sprag korean off`.');
269
269
  } else {
270
270
  console.log(lang === 'ko'
271
- ? ' korean: κΊΌ λ‘μ—ˆμŠ΅λ‹ˆλ‹€ β€” λ‚˜μ€‘μ— `claude-token-saver korean on` 으둜 μΌ€ 수 μžˆμŠ΅λ‹ˆλ‹€.'
272
- : ' korean: left off β€” enable later with `claude-token-saver korean on`.');
271
+ ? ' korean: κΊΌ λ‘μ—ˆμŠ΅λ‹ˆλ‹€ β€” λ‚˜μ€‘μ— `sprag korean on` 으둜 μΌ€ 수 μžˆμŠ΅λ‹ˆλ‹€.'
272
+ : ' korean: left off β€” enable later with `sprag korean on`.');
273
273
  }
274
274
  }
275
275
  } catch (e) {
@@ -336,8 +336,8 @@ export async function run({ hasFlag }) {
336
336
  ? ` seed: μΆ”μ²œ λ£° ${pending.length}건이 λŒ€κΈ° μ€‘μž…λ‹ˆλ‹€ (λͺ¨λΈ ν”ΌνŒ… + λž«μ³‡ 프리셋).`
337
337
  : ` seed: ${pending.length} recommended rule(s) are waiting (model-fitting + ratchet presets).`);
338
338
  console.log(lang === 'ko'
339
- ? ' λ‹€μŒ Claude Code μ„Έμ…˜μ—μ„œ ν•œ 건씩 등둝할지 λ¬Όμ–΄λ΄…λ‹ˆλ‹€. μ§€κΈˆ 보렀면: claude-token-saver seed'
340
- : ' the next Claude Code session asks about them one at a time. See them now: claude-token-saver seed');
339
+ ? ' λ‹€μŒ Claude Code μ„Έμ…˜μ—μ„œ ν•œ 건씩 등둝할지 λ¬Όμ–΄λ΄…λ‹ˆλ‹€. μ§€κΈˆ 보렀면: sprag seed'
340
+ : ' the next Claude Code session asks about them one at a time. See them now: sprag seed');
341
341
  }
342
342
  } catch (e) {
343
343
  debug('install:seed-offer', e); // optional feature; never fail install
@@ -352,7 +352,7 @@ export async function run({ hasFlag }) {
352
352
  }
353
353
  console.log('');
354
354
  console.log(lang === 'ko'
355
- ? '버그 제보·기λŠ₯ μ œμ•ˆ: https://github.com/rootstudioyaml/claude-token-saver/issues'
356
- : 'Bug reports & feature requests: https://github.com/rootstudioyaml/claude-token-saver/issues');
355
+ ? '버그 제보·기λŠ₯ μ œμ•ˆ: https://github.com/rootstudioyaml/sprag/issues'
356
+ : 'Bug reports & feature requests: https://github.com/rootstudioyaml/sprag/issues');
357
357
  return;
358
358
  }
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Subcommand: korean β€” Korean writing guidance for every session.
3
- * claude-token-saver korean on # inject at session start, all projects
4
- * claude-token-saver korean off # stop injecting
5
- * claude-token-saver korean status # current state, cost, and provenance
6
- * claude-token-saver korean show # print the guidance itself
3
+ * sprag korean on # inject at session start, all projects
4
+ * sprag korean off # stop injecting
5
+ * sprag korean status # current state, cost, and provenance
6
+ * sprag korean show # print the guidance itself
7
7
  *
8
8
  * Why this exists rather than pointing users at Claude Code's output styles:
9
9
  * an output style is one global slot, so turning it on takes the slot away
@@ -18,8 +18,8 @@
18
18
  * reads the finished file. `korean on` therefore also installs a PostToolUse
19
19
  * hook that runs the machine-checkable clauses over the prose the model just
20
20
  * wrote:
21
- * claude-token-saver korean lint block|warn|off # how findings are handled
22
- * claude-token-saver korean lint <file...> # check files on disk
21
+ * sprag korean lint block|warn|off # how findings are handled
22
+ * sprag korean lint <file...> # check files on disk
23
23
  */
24
24
 
25
25
  // Enforcement is only useful if it is on by default β€” a check the user has to
@@ -108,7 +108,7 @@ export async function run({ args, hasFlag }) {
108
108
  return;
109
109
  }
110
110
  if (!['all', 'prose'].includes(next)) {
111
- console.error('Usage: claude-token-saver korean lint scope [all|prose]');
111
+ console.error('Usage: sprag korean lint scope [all|prose]');
112
112
  process.exit(1);
113
113
  }
114
114
  cfg.koreanStyle = cfg.koreanStyle || {};
@@ -135,7 +135,7 @@ export async function run({ args, hasFlag }) {
135
135
  return;
136
136
  }
137
137
  if (!['block', 'warn', 'off'].includes(mode)) {
138
- console.error('Usage: claude-token-saver korean lint [block|warn|off] | korean lint <file...>');
138
+ console.error('Usage: sprag korean lint [block|warn|off] | korean lint <file...>');
139
139
  process.exit(1);
140
140
  }
141
141
  cfg.koreanStyle = cfg.koreanStyle || {};
@@ -201,20 +201,20 @@ export async function run({ args, hasFlag }) {
201
201
  if (lang === 'ko') {
202
202
  console.log(`ν•œκ΅­μ–΄ 문체 μ§€μΉ¨: ${on ? '켜짐' : '꺼짐'}`);
203
203
  console.log(` λΉ„μš©: μ„Έμ…˜λ‹Ή μ•½ ${tokens} 토큰 (μ„Έμ…˜ μ‹œμž‘ 1회 μ£Όμž…)`);
204
- console.log(` μ“°κΈ° μ‹œμ  검사: ${koreanLintMode(loadConfig())}, λ²”μœ„ ${koreanLintScope(loadConfig())} (λ°”κΎΈλ €λ©΄ claude-token-saver korean lint block|warn|off, korean lint scope all|prose)`);
204
+ console.log(` μ“°κΈ° μ‹œμ  검사: ${koreanLintMode(loadConfig())}, λ²”μœ„ ${koreanLintScope(loadConfig())} (λ°”κΎΈλ €λ©΄ sprag korean lint block|warn|off, korean lint scope all|prose)`);
205
205
  console.log(` 좜처: ${ks.KOREAN_STYLE_SOURCE}`);
206
206
  console.log(` λΌμ΄μ„ μŠ€ μ „λ¬Έ: ${ks.KOREAN_STYLE_LICENSE_PATH}`);
207
207
  console.log(on
208
- ? ' 끄렀면: claude-token-saver korean off'
209
- : ' 켜렀면: claude-token-saver korean on');
208
+ ? ' 끄렀면: sprag korean off'
209
+ : ' 켜렀면: sprag korean on');
210
210
  } else {
211
211
  console.log(`Korean writing guidance: ${on ? 'on' : 'off'}`);
212
212
  console.log(` Cost: ~${tokens} tokens per session (injected once at session start)`);
213
- console.log(` Write-time check: ${koreanLintMode(loadConfig())}, scope ${koreanLintScope(loadConfig())} (change with: claude-token-saver korean lint block|warn|off, korean lint scope all|prose)`);
213
+ console.log(` Write-time check: ${koreanLintMode(loadConfig())}, scope ${koreanLintScope(loadConfig())} (change with: sprag korean lint block|warn|off, korean lint scope all|prose)`);
214
214
  console.log(` Source: ${ks.KOREAN_STYLE_SOURCE}`);
215
215
  console.log(` License text: ${ks.KOREAN_STYLE_LICENSE_PATH}`);
216
216
  console.log(on
217
- ? ' Turn off with: claude-token-saver korean off'
218
- : ' Turn on with: claude-token-saver korean on');
217
+ ? ' Turn off with: sprag korean off'
218
+ : ' Turn on with: sprag korean on');
219
219
  }
220
220
  }
@@ -3,8 +3,8 @@
3
3
  * Designed for the auto-trigger skill so the user immediately sees
4
4
  * "what just fired and how to fix it" without having to read the whole
5
5
  * history file.
6
- * claude-token-saver last # search last 1 day
7
- * claude-token-saver last --days 7 # widen the lookback
6
+ * sprag last # search last 1 day
7
+ * sprag last --days 7 # widen the lookback
8
8
  */
9
9
 
10
10
 
@@ -113,7 +113,7 @@ export async function run({ numArg }) {
113
113
  console.log('πŸ’‘ ' + (lang === 'ko' ? CAP_TIPS.ko : CAP_TIPS.en));
114
114
  console.log('');
115
115
  console.log(lang === 'ko' ? 'μ‹€ν–‰:' : 'Run:');
116
- console.log(' claude-token-saver handoff');
116
+ console.log(' sprag handoff');
117
117
  return;
118
118
  }
119
119
  // Chip warning path: render full ISSUE_MESSAGES advice for each code,
@@ -121,8 +121,8 @@ export async function run({ numArg }) {
121
121
  // the history.md format).
122
122
  if (latest.codes.length === 0) {
123
123
  console.log(lang === 'ko'
124
- ? '(진단 μ½”λ“œ μ—†μŒ β€” ν‘œ λ·°λ₯Ό μ—΄μ–΄λ³΄μ„Έμš”: `claude-token-saver --days 1`)'
125
- : '(No diagnostic code attached β€” open the table view: `claude-token-saver --days 1`)');
124
+ ? '(진단 μ½”λ“œ μ—†μŒ β€” ν‘œ λ·°λ₯Ό μ—΄μ–΄λ³΄μ„Έμš”: `sprag --days 1`)'
125
+ : '(No diagnostic code attached β€” open the table view: `sprag --days 1`)');
126
126
  return;
127
127
  }
128
128
  // Pick a single language per field; fall back to EN when KO is missing.
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Subcommand: mode β€” persist statusline preferences so future runs pick
3
3
  * them up without flags or wrapper edits.
4
- * claude-token-saver mode # show current config
5
- * claude-token-saver mode icon verbose # set icon + verbose
6
- * claude-token-saver mode reset # clear back to defaults
4
+ * sprag mode # show current config
5
+ * sprag mode icon verbose # set icon + verbose
6
+ * sprag mode reset # clear back to defaults
7
7
  */
8
8
 
9
9
 
@@ -28,7 +28,7 @@ export async function run({ args }) {
28
28
  console.log(`Stored config file (${configPath()}):`);
29
29
  console.log(` ${Object.keys(raw).length === 0 ? '(none β€” using defaults)' : JSON.stringify(raw)}`);
30
30
  console.log('');
31
- console.log('Change with: claude-token-saver mode <keywords...>');
31
+ console.log('Change with: sprag mode <keywords...>');
32
32
  console.log(`Keywords: ${VALID_KEYWORDS.join(', ')}`);
33
33
  return;
34
34
  }
@@ -111,7 +111,7 @@ export async function run({ args, hasFlag, numArg }) {
111
111
  const n = parseInt(args[3], 10);
112
112
  const removed = Number.isFinite(n) ? mr.removeModelRule(n) : null;
113
113
  if (!removed) {
114
- console.error('Usage: claude-token-saver route-scan rules rm <N> # N from `route-scan rules`');
114
+ console.error('Usage: sprag route-scan rules rm <N> # N from `route-scan rules`');
115
115
  process.exit(1);
116
116
  }
117
117
  // A target whose last rule was removed gets its (tool-owned) file deleted.
@@ -181,20 +181,20 @@ export async function run({ args, hasFlag, numArg }) {
181
181
  + '\n Map it under modelAliases in profile-map.json, then run route-scan --refresh.');
182
182
  }
183
183
  console.log(lang === 'ko'
184
- ? '\n제거: claude-token-saver route-scan rules rm <N>'
185
- : '\nRemove with: claude-token-saver route-scan rules rm <N>');
184
+ ? '\n제거: sprag route-scan rules rm <N>'
185
+ : '\nRemove with: sprag route-scan rules rm <N>');
186
186
  return;
187
187
  }
188
188
 
189
189
  if (args[1] === 'dismiss') {
190
190
  const n = parseInt(args[2], 10);
191
191
  if (!Number.isFinite(n)) {
192
- console.error('Usage: claude-token-saver route-scan dismiss <N> # N from `route? R<N>`');
192
+ console.error('Usage: sprag route-scan dismiss <N> # N from `route? R<N>`');
193
193
  process.exit(1);
194
194
  }
195
195
  const cand = rs.resolveCandidate(n);
196
196
  if (!cand) {
197
- console.error(`No route candidate R${n}. Run: claude-token-saver route-scan`);
197
+ console.error(`No route candidate R${n}. Run: sprag route-scan`);
198
198
  process.exit(1);
199
199
  }
200
200
  console.log(lang === 'ko'
@@ -301,16 +301,16 @@ export async function run({ args, hasFlag, numArg }) {
301
301
  if (u && u.available && !u.dismissed) {
302
302
  updateBlock = lang === 'ko'
303
303
  ? [
304
- `[claude-token-saver update] μƒˆ 버전이 λ‚˜μ™€ μžˆμŠ΅λ‹ˆλ‹€: v${u.current} β†’ ${u.latest}.`,
304
+ `[sprag update] μƒˆ 버전이 λ‚˜μ™€ μžˆμŠ΅λ‹ˆλ‹€: v${u.current} β†’ ${u.latest}.`,
305
305
  'μ‚¬μš©μžμ—κ²Œ μ§€κΈˆ μ—…κ·Έλ ˆμ΄λ“œν• μ§€ 물어보고, μŠΉλ‚™ν•˜λ©΄ μ•„λž˜ λͺ…령을 μ‹€ν–‰ν•˜μ‹­μ‹œμ˜€. 묻지 μ•Šκ³  μ„€μΉ˜ν•˜μ§€λŠ” λ§ˆμ‹­μ‹œμ˜€.',
306
- ' claude-token-saver upgrade # μ—…κ·Έλ ˆμ΄λ“œ μ‹€ν–‰',
307
- ' claude-token-saver update-check --dismiss # μ‚¬μš©μžκ°€ μ›μΉ˜ μ•ŠμœΌλ©΄ (λ‹€μŒ 버전이 λ‚˜μ˜¬ λ•ŒκΉŒμ§€ λ‹€μ‹œ 묻지 μ•ŠμŠ΅λ‹ˆλ‹€)',
306
+ ' sprag upgrade # μ—…κ·Έλ ˆμ΄λ“œ μ‹€ν–‰',
307
+ ' sprag update-check --dismiss # μ‚¬μš©μžκ°€ μ›μΉ˜ μ•ŠμœΌλ©΄ (λ‹€μŒ 버전이 λ‚˜μ˜¬ λ•ŒκΉŒμ§€ λ‹€μ‹œ 묻지 μ•ŠμŠ΅λ‹ˆλ‹€)',
308
308
  ].join('\n')
309
309
  : [
310
- `[claude-token-saver update] A newer version is available: v${u.current} β†’ ${u.latest}.`,
310
+ `[sprag update] A newer version is available: v${u.current} β†’ ${u.latest}.`,
311
311
  'Ask the user whether to upgrade now, and run the command below only if they agree. Do not install without asking.',
312
- ' claude-token-saver upgrade # perform the upgrade',
313
- ' claude-token-saver update-check --dismiss # if they decline (stays quiet until a newer release)',
312
+ ' sprag upgrade # perform the upgrade',
313
+ ' sprag update-check --dismiss # if they decline (stays quiet until a newer release)',
314
314
  ].join('\n');
315
315
  }
316
316
  } catch (e) { debug('route-scan:update-check', e); /* the offer is optional */ }
@@ -332,10 +332,10 @@ export async function run({ args, hasFlag, numArg }) {
332
332
  const lines = [];
333
333
  if (open.length > 0) {
334
334
  if (lang === 'ko') {
335
- lines.push(`[claude-token-saver route-scan] 졜근 ${cache.days}일 μ„Έμ…˜μ—μ„œ λΉ„μ‹Ό λͺ¨λΈ(opus/fable)이 반볡 μ²˜λ¦¬ν•΄ 온, 더 μ‹Ό λͺ¨λΈλ‘œ λ„˜κ²¨λ„ λ˜λŠ” μž‘μ—…μ΄ κ°μ§€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.`);
335
+ lines.push(`[sprag route-scan] 졜근 ${cache.days}일 μ„Έμ…˜μ—μ„œ λΉ„μ‹Ό λͺ¨λΈ(opus/fable)이 반볡 μ²˜λ¦¬ν•΄ 온, 더 μ‹Ό λͺ¨λΈλ‘œ λ„˜κ²¨λ„ λ˜λŠ” μž‘μ—…μ΄ κ°μ§€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.`);
336
336
  lines.push('(R<N>은 후보 번호, T2/T1은 λ‚œμ΄λ„ λ“±κΈ‰μž…λ‹ˆλ‹€ β€” μ‚¬μš©μžμ—κ²Œ 전달할 λ•ŒλŠ” μ½”λ“œκ°€ μ•„λ‹ˆλΌ μ•„λž˜ ν’€μ–΄μ“΄ μ„€λͺ…μœΌλ‘œ λΈŒλ¦¬ν•‘ν•˜μ„Έμš”)');
337
337
  } else {
338
- lines.push(`[claude-token-saver route-scan] Over the last ${cache.days} days, expensive models (opus/fable) repeatedly handled work that a cheaper model could take.`);
338
+ lines.push(`[sprag route-scan] Over the last ${cache.days} days, expensive models (opus/fable) repeatedly handled work that a cheaper model could take.`);
339
339
  lines.push('(R<N> is the candidate id, T2/T1 the difficulty tier β€” brief the user with the spelled-out wording below, not the codes.)');
340
340
  }
341
341
  for (const c of open) {
@@ -356,18 +356,18 @@ export async function run({ args, hasFlag, numArg }) {
356
356
  }
357
357
  if (lang === 'ko') {
358
358
  lines.push('λ“±λ‘ν•˜λ©΄ λ‹€μŒ μ„Έμ…˜λΆ€ν„° μžλ™ μœ„μž„λ©λ‹ˆλ‹€. μ‚¬μš©μžμ—κ²Œ 등둝 μ—¬λΆ€λ₯Ό 물을 λ•Œ μœ„ λ£° 원문을 κ·ΈλŒ€λ‘œ 보여주고, 적용 λ²”μœ„κΉŒμ§€ ν™•μΈν•œ λ’€ μ‹€ν–‰ν•˜μ„Έμš”:');
359
- lines.push(' claude-token-saver harness promote R<N> --project|--global # 적용 λ²”μœ„λŠ” λ°˜λ“œμ‹œ μ‚¬μš©μžμ—κ²Œ 확인');
360
- lines.push(' claude-token-saver route-scan dismiss <N> # μ‚¬μš©μžκ°€ μ›μΉ˜ μ•ŠμœΌλ©΄');
359
+ lines.push(' sprag harness promote R<N> --project|--global # 적용 λ²”μœ„λŠ” λ°˜λ“œμ‹œ μ‚¬μš©μžμ—κ²Œ 확인');
360
+ lines.push(' sprag route-scan dismiss <N> # μ‚¬μš©μžκ°€ μ›μΉ˜ μ•ŠμœΌλ©΄');
361
361
  } else {
362
362
  lines.push('Once registered, delegation happens automatically from the next session. Show the user the rule text verbatim, confirm the scope with them, then run:');
363
- lines.push(' claude-token-saver harness promote R<N> --project|--global # ALWAYS confirm the scope with the user first');
364
- lines.push(' claude-token-saver route-scan dismiss <N> # if they do not want it');
363
+ lines.push(' sprag harness promote R<N> --project|--global # ALWAYS confirm the scope with the user first');
364
+ lines.push(' sprag route-scan dismiss <N> # if they do not want it');
365
365
  }
366
366
  }
367
367
  if (reviewRules.length > 0) {
368
368
  lines.push(lang === 'ko'
369
- ? '[claude-token-saver rule-health] μ‚¬μš©μžκ°€ μŠΉμΈν•œ μœ„μž„ λ£° 쀑, μœ„μž„ λŒ€μƒ μœ ν˜•μ˜ 졜근 μ—λŸ¬μœ¨μ΄ κΈ°μ€€(20%)을 λ„˜μ–΄ μž¬κ²€ν† κ°€ ν•„μš”ν•œ 룰이 μžˆμŠ΅λ‹ˆλ‹€ β€” μ‚¬μš©μžμ—κ²Œ λΈŒλ¦¬ν•‘ν•˜κ³  쑰건 쒁히기/제거λ₯Ό μƒμ˜ν•˜μ„Έμš”:'
370
- : '[claude-token-saver rule-health] Some user-approved delegation rules now exceed the 20% error-rate threshold for their delegated category β€” brief the user and discuss narrowing or removing them:');
369
+ ? '[sprag rule-health] μ‚¬μš©μžκ°€ μŠΉμΈν•œ μœ„μž„ λ£° 쀑, μœ„μž„ λŒ€μƒ μœ ν˜•μ˜ 졜근 μ—λŸ¬μœ¨μ΄ κΈ°μ€€(20%)을 λ„˜μ–΄ μž¬κ²€ν† κ°€ ν•„μš”ν•œ 룰이 μžˆμŠ΅λ‹ˆλ‹€ β€” μ‚¬μš©μžμ—κ²Œ λΈŒλ¦¬ν•‘ν•˜κ³  쑰건 쒁히기/제거λ₯Ό μƒμ˜ν•˜μ„Έμš”:'
370
+ : '[sprag rule-health] Some user-approved delegation rules now exceed the 20% error-rate threshold for their delegated category β€” brief the user and discuss narrowing or removing them:');
371
371
  for (const r of reviewRules) {
372
372
  // Say WHICH signal tripped: a measured delegation failure rate is a
373
373
  // much stronger claim than the shape-based proxy, and the user's
@@ -383,12 +383,12 @@ export async function run({ args, hasFlag, numArg }) {
383
383
  lines.push(` "${r.rule}"`);
384
384
  }
385
385
  lines.push(lang === 'ko'
386
- ? ' 제거: claude-token-saver route-scan rules rm <N>'
387
- : ' remove with: claude-token-saver route-scan rules rm <N>');
386
+ ? ' 제거: sprag route-scan rules rm <N>'
387
+ : ' remove with: sprag route-scan rules rm <N>');
388
388
  }
389
389
  lines.push(lang === 'ko'
390
- ? 'μœ„ λ‚΄μš©μ€ μ‚¬μš©μžμ˜ 첫 λ©”μ‹œμ§€ μ£Όμ œμ™€ λ¬΄κ΄€ν•˜λ”λΌλ„(λ‹¨μˆœ 인사여도) 첫 응닡 말미에 `β€» [claude-token-saver]` 라벨을 달아 μš”μ•½ λΈŒλ¦¬ν•‘ν•˜μ„Έμš” β€” μ‚¬μš©μžκ°€ λ¬Όμ–΄λ³Ό λ•ŒκΉŒμ§€ 기닀리지 말 것.'
391
- : 'Summarize the above at the end of your first response under a `β€» [claude-token-saver]` label, even if the user\'s first message is unrelated (a bare greeting counts) β€” do not wait to be asked.');
390
+ ? 'μœ„ λ‚΄μš©μ€ μ‚¬μš©μžμ˜ 첫 λ©”μ‹œμ§€ μ£Όμ œμ™€ λ¬΄κ΄€ν•˜λ”λΌλ„(λ‹¨μˆœ 인사여도) 첫 응닡 말미에 `β€» [sprag]` 라벨을 달아 μš”μ•½ λΈŒλ¦¬ν•‘ν•˜μ„Έμš” β€” μ‚¬μš©μžκ°€ λ¬Όμ–΄λ³Ό λ•ŒκΉŒμ§€ 기닀리지 말 것.'
391
+ : 'Summarize the above at the end of your first response under a `β€» [sprag]` label, even if the user\'s first message is unrelated (a bare greeting counts) β€” do not wait to be asked.');
392
392
  // Style first, briefing second: the briefing is Korean prose too, so the
393
393
  // guidance has to be in context before the model reads it.
394
394
  if (koreanBlock) console.log(koreanBlock + '\n');
@@ -446,8 +446,8 @@ export async function run({ args, hasFlag, numArg }) {
446
446
  }
447
447
  console.log('');
448
448
  console.log(lang === 'ko' ? '등둝 / λ¬΄μ‹œ:' : 'Promote / dismiss:');
449
- console.log(' claude-token-saver harness promote R<N> --project|--global');
450
- console.log(' claude-token-saver route-scan dismiss <N>');
449
+ console.log(' sprag harness promote R<N> --project|--global');
450
+ console.log(' sprag route-scan dismiss <N>');
451
451
  // 졜초 1회만 β€” 맀번 찍으면 도ꡬ가 κ΄‘κ³ νŒμ΄ λœλ‹€ (CTS_NO_NOTE=1 둜 끔)
452
452
  (await import('../first-run-note.js')).printOnce('route-scan', lang);
453
453
  return;
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Subcommand: seed β€” register the bundled starter rules, one answer at a time.
3
3
  *
4
- * claude-token-saver seed # what is still pending
5
- * claude-token-saver seed accept <id> --global # register one rule
6
- * claude-token-saver seed accept <id> --project # ... into this project only
7
- * claude-token-saver seed accept all --global # when the user says "all of them"
8
- * claude-token-saver seed skip <id> | skip all # never offer it again
9
- * claude-token-saver seed reset # make every preset pending again
4
+ * sprag seed # what is still pending
5
+ * sprag seed accept <id> --global # register one rule
6
+ * sprag seed accept <id> --project # ... into this project only
7
+ * sprag seed accept all --global # when the user says "all of them"
8
+ * sprag seed skip <id> | skip all # never offer it again
9
+ * sprag seed reset # make every preset pending again
10
10
  *
11
11
  * Scope is explicit on purpose, exactly as `harness promote` requires it: the
12
12
  * hook environment is non-TTY, so the model has to ask the user and pass the
@@ -36,8 +36,8 @@ export async function run({ args, hasFlag }) {
36
36
  const ids = args.slice(2).filter((a) => !a.startsWith('-'));
37
37
  if (ids.length === 0) {
38
38
  console.error(ko
39
- ? 'idλ₯Ό μ§€μ •ν•˜μ‹­μ‹œμ˜€ (λͺ©λ‘: claude-token-saver seed). μ „μ²΄λŠ” `all`.'
40
- : 'Pass an id (list them with `claude-token-saver seed`), or `all`.');
39
+ ? 'idλ₯Ό μ§€μ •ν•˜μ‹­μ‹œμ˜€ (λͺ©λ‘: sprag seed). μ „μ²΄λŠ” `all`.'
40
+ : 'Pass an id (list them with `sprag seed`), or `all`.');
41
41
  process.exit(1);
42
42
  }
43
43
  const pending = seed.pendingSeeds({ lang, root });
@@ -99,7 +99,7 @@ export async function run({ args, hasFlag }) {
99
99
  if (pending.length > 0) {
100
100
  console.log('');
101
101
  console.log(ko
102
- ? '등둝: claude-token-saver seed accept <id> --global|--project Β· 거절: seed skip <id>'
103
- : 'register: claude-token-saver seed accept <id> --global|--project Β· decline: seed skip <id>');
102
+ ? '등둝: sprag seed accept <id> --global|--project Β· 거절: seed skip <id>'
103
+ : 'register: sprag seed accept <id> --global|--project Β· decline: seed skip <id>');
104
104
  }
105
105
  }
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Subcommand: update-check β€” everything around "is a newer version out".
3
3
  *
4
- * claude-token-saver update-check # print the cached answer
5
- * claude-token-saver update-check --refresh # ask the registry now
6
- * claude-token-saver update-check --refresh --quiet
4
+ * sprag update-check # print the cached answer
5
+ * sprag update-check --refresh # ask the registry now
6
+ * sprag update-check --refresh --quiet
7
7
  * # what the detached background child runs
8
- * claude-token-saver update-check --dismiss # stop offering this version at session start
8
+ * sprag update-check --dismiss # stop offering this version at session start
9
9
  *
10
10
  * The statusline never calls the --refresh path directly; it spawns this
11
11
  * command detached so the render itself stays offline and instant.
@@ -71,7 +71,7 @@ export async function run({ hasFlag, version }) {
71
71
  : `Up to date (v${version}).`);
72
72
  if (!s.latest) {
73
73
  console.log(lang === 'ko'
74
- ? `아직 ν™•μΈλœ 기둝이 μ—†μŠ΅λ‹ˆλ‹€. μ§€κΈˆ ν™•μΈν•˜λ €λ©΄: claude-token-saver update-check --refresh (기둝 파일: ${updateStatePath()})`
75
- : `No check has completed yet. Run: claude-token-saver update-check --refresh (state: ${updateStatePath()})`);
74
+ ? `아직 ν™•μΈλœ 기둝이 μ—†μŠ΅λ‹ˆλ‹€. μ§€κΈˆ ν™•μΈν•˜λ €λ©΄: sprag update-check --refresh (기둝 파일: ${updateStatePath()})`
75
+ : `No check has completed yet. Run: sprag update-check --refresh (state: ${updateStatePath()})`);
76
76
  }
77
77
  }