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/commands/harness.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subcommand: harness β manage the project's CLAUDE.md harness rules.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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:
|
|
53
|
-
console.log(' or:
|
|
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:
|
|
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:
|
|
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:
|
|
142
|
-
console.error(' or:
|
|
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:
|
|
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('
|
|
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
|
-
? 'λ£° λͺ©λ‘/μ κ±°:
|
|
265
|
-
: 'List / remove:
|
|
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νμ μλ λ£°μ μΈμ λ :
|
|
349
|
-
: '\nDrop any rule you do not want:
|
|
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:
|
|
369
|
-
console.log('Archive in bulk:
|
|
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:
|
|
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:
|
|
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
|
}
|
package/src/commands/install.js
CHANGED
|
@@ -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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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 \`
|
|
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
|
-
? '
|
|
91
|
-
: ' Replace it with the
|
|
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μ μ μ§νμ΅λλ€. κ΅μ²΄νλ €λ©΄ `
|
|
98
|
-
: 'kept your statusline β replace later with `
|
|
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: 건λλ°μμ΅λλ€ β λμ€μ `
|
|
182
|
-
: ' harness: skipped β set it up later with `
|
|
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
|
-
? ' λλλ¦¬λ €λ©΄:
|
|
198
|
-
: ' to undo:
|
|
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: μλ μ€μ μ 건λλ°μμ΅λλ€ β `
|
|
210
|
-
: ' harness: auto-setup skipped β run `
|
|
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: μΌ°μ΅λλ€ β λͺ¨λ νλ‘μ νΈμ μΈμ
μμ μ μ£Όμ
λ©λλ€. λλ €λ©΄ `
|
|
268
|
-
: ' korean: enabled β injected at session start in every project. Turn off with `
|
|
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: κΊΌ λμμ΅λλ€ β λμ€μ `
|
|
272
|
-
: ' korean: left off β enable later with `
|
|
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 μΈμ
μμ ν κ±΄μ© λ±λ‘ν μ§ λ¬Όμ΄λ΄
λλ€. μ§κΈ λ³΄λ €λ©΄:
|
|
340
|
-
: ' the next Claude Code session asks about them one at a time. See them now:
|
|
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/
|
|
356
|
-
: 'Bug reports & feature requests: https://github.com/rootstudioyaml/
|
|
355
|
+
? 'λ²κ·Έ μ 보·기λ₯ μ μ: https://github.com/rootstudioyaml/sprag/issues'
|
|
356
|
+
: 'Bug reports & feature requests: https://github.com/rootstudioyaml/sprag/issues');
|
|
357
357
|
return;
|
|
358
358
|
}
|
package/src/commands/korean.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subcommand: korean β Korean writing guidance for every session.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
-
*
|
|
22
|
-
*
|
|
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:
|
|
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:
|
|
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())} (λ°κΎΈλ €λ©΄
|
|
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
|
-
? ' λλ €λ©΄:
|
|
209
|
-
: ' μΌλ €λ©΄:
|
|
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:
|
|
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:
|
|
218
|
-
: ' Turn on with:
|
|
217
|
+
? ' Turn off with: sprag korean off'
|
|
218
|
+
: ' Turn on with: sprag korean on');
|
|
219
219
|
}
|
|
220
220
|
}
|
package/src/commands/last.js
CHANGED
|
@@ -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
|
-
*
|
|
7
|
-
*
|
|
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('
|
|
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
|
-
? '(μ§λ¨ μ½λ μμ β ν λ·°λ₯Ό μ΄μ΄λ³΄μΈμ: `
|
|
125
|
-
: '(No diagnostic code attached β open the table view: `
|
|
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.
|
package/src/commands/mode.js
CHANGED
|
@@ -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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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:
|
|
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:
|
|
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μ κ±°:
|
|
185
|
-
: '\nRemove with:
|
|
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:
|
|
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:
|
|
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
|
-
`[
|
|
304
|
+
`[sprag update] μ λ²μ μ΄ λμ μμ΅λλ€: v${u.current} β ${u.latest}.`,
|
|
305
305
|
'μ¬μ©μμκ² μ§κΈ μ
κ·Έλ μ΄λν μ§ λ¬Όμ΄λ³΄κ³ , μΉλνλ©΄ μλ λͺ
λ Ήμ μ€ννμμμ€. λ¬»μ§ μκ³ μ€μΉνμ§λ λ§μμμ€.',
|
|
306
|
-
'
|
|
307
|
-
'
|
|
306
|
+
' sprag upgrade # μ
κ·Έλ μ΄λ μ€ν',
|
|
307
|
+
' sprag update-check --dismiss # μ¬μ©μκ° μμΉ μμΌλ©΄ (λ€μ λ²μ μ΄ λμ¬ λκΉμ§ λ€μ λ¬»μ§ μμ΅λλ€)',
|
|
308
308
|
].join('\n')
|
|
309
309
|
: [
|
|
310
|
-
`[
|
|
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
|
-
'
|
|
313
|
-
'
|
|
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(`[
|
|
335
|
+
lines.push(`[sprag route-scan] μ΅κ·Ό ${cache.days}μΌ μΈμ
μμ λΉμΌ λͺ¨λΈ(opus/fable)μ΄ λ°λ³΅ μ²λ¦¬ν΄ μ¨, λ μΌ λͺ¨λΈλ‘ λ겨λ λλ μμ
μ΄ κ°μ§λμμ΅λλ€.`);
|
|
336
336
|
lines.push('(R<N>μ ν보 λ²νΈ, T2/T1μ λμ΄λ λ±κΈμ
λλ€ β μ¬μ©μμκ² μ λ¬ν λλ μ½λκ° μλλΌ μλ νμ΄μ΄ μ€λͺ
μΌλ‘ λΈλ¦¬ννμΈμ)');
|
|
337
337
|
} else {
|
|
338
|
-
lines.push(`[
|
|
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('
|
|
360
|
-
lines.push('
|
|
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('
|
|
364
|
-
lines.push('
|
|
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
|
-
? '[
|
|
370
|
-
: '[
|
|
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
|
-
? ' μ κ±°:
|
|
387
|
-
: ' remove with:
|
|
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
|
-
? 'μ λ΄μ©μ μ¬μ©μμ 첫 λ©μμ§ μ£Όμ μ 무κ΄νλλΌλ(λ¨μ μΈμ¬μ¬λ) 첫 μλ΅ λ§λ―Έμ `β» [
|
|
391
|
-
: 'Summarize the above at the end of your first response under a `β» [
|
|
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('
|
|
450
|
-
console.log('
|
|
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;
|
package/src/commands/seed.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subcommand: seed β register the bundled starter rules, one answer at a time.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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λ₯Ό μ§μ νμμμ€ (λͺ©λ‘:
|
|
40
|
-
: 'Pass an id (list them with `
|
|
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
|
-
? 'λ±λ‘:
|
|
103
|
-
: 'register:
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
-
*
|
|
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
|
-
? `μμ§ νμΈλ κΈ°λ‘μ΄ μμ΅λλ€. μ§κΈ νμΈνλ €λ©΄:
|
|
75
|
-
: `No check has completed yet. Run:
|
|
74
|
+
? `μμ§ νμΈλ κΈ°λ‘μ΄ μμ΅λλ€. μ§κΈ νμΈνλ €λ©΄: sprag update-check --refresh (κΈ°λ‘ νμΌ: ${updateStatePath()})`
|
|
75
|
+
: `No check has completed yet. Run: sprag update-check --refresh (state: ${updateStatePath()})`);
|
|
76
76
|
}
|
|
77
77
|
}
|