claude-token-saver 2.10.1 → 2.10.2
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/bin/cli.js +14 -2
- package/package.json +1 -1
- package/src/harness.js +48 -0
package/bin/cli.js
CHANGED
|
@@ -446,12 +446,13 @@ async function main() {
|
|
|
446
446
|
|
|
447
447
|
// Subcommand: harness — manage the project's CLAUDE.md harness rules.
|
|
448
448
|
// claude-token-saver harness init # write CLAUDE.md (5 sections) + ratchet.md
|
|
449
|
+
// claude-token-saver harness uninit # remove harness block from CLAUDE.md (backup kept)
|
|
449
450
|
// claude-token-saver harness check # show 🅷 N/5 + which sections are missing
|
|
450
451
|
// claude-token-saver harness promote "<rule>" # append a rule to ratchet.md
|
|
451
452
|
// claude-token-saver harness off | on # toggle the statusline 🅷 segment
|
|
452
453
|
if (args[0] === 'harness') {
|
|
453
454
|
const sub = args[1];
|
|
454
|
-
const { harnessInit, harnessStatus, harnessPromote, findProjectRoot } =
|
|
455
|
+
const { harnessInit, harnessUninit, harnessStatus, harnessPromote, findProjectRoot } =
|
|
455
456
|
await import('../src/harness.js');
|
|
456
457
|
const { HARNESS_SECTIONS } = await import('../src/harness-templates.js');
|
|
457
458
|
const { loadConfig, saveConfig } = await import('../src/config.js');
|
|
@@ -557,6 +558,17 @@ async function main() {
|
|
|
557
558
|
return;
|
|
558
559
|
}
|
|
559
560
|
|
|
561
|
+
if (sub === 'uninit' || sub === 'remove') {
|
|
562
|
+
const purgeRatchet = args.includes('--purge-ratchet');
|
|
563
|
+
const r = harnessUninit({ purgeRatchet });
|
|
564
|
+
console.log(`Project root: ${r.root}`);
|
|
565
|
+
r.removed.forEach((f) => console.log(` removed: ${f}`));
|
|
566
|
+
r.backedUp.forEach((f) => console.log(` backup: ${f}`));
|
|
567
|
+
r.skipped.forEach((f) => console.log(` skip: ${f}`));
|
|
568
|
+
if (r.removed.length === 0) console.log('Nothing to remove.');
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
560
572
|
if (sub === 'off' || sub === 'on') {
|
|
561
573
|
const cfg = loadConfig();
|
|
562
574
|
cfg.harness = cfg.harness || {};
|
|
@@ -567,7 +579,7 @@ async function main() {
|
|
|
567
579
|
}
|
|
568
580
|
|
|
569
581
|
console.error(`Unknown harness subcommand: ${sub}`);
|
|
570
|
-
console.error('Usage: claude-token-saver harness [check|init|promote "<rule>"|off|on]');
|
|
582
|
+
console.error('Usage: claude-token-saver harness [check|init|uninit [--purge-ratchet]|promote "<rule>"|off|on]');
|
|
571
583
|
process.exit(1);
|
|
572
584
|
}
|
|
573
585
|
|
package/package.json
CHANGED
package/src/harness.js
CHANGED
|
@@ -154,6 +154,54 @@ export function harnessInit({ root = findProjectRoot(), force = false } = {}) {
|
|
|
154
154
|
return result;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/**
|
|
158
|
+
* harness uninit — remove the harness block from CLAUDE.md (preserves the
|
|
159
|
+
* user's other content). A safety backup is written first. ratchet.md is
|
|
160
|
+
* left intact (user-grown rules) unless `purgeRatchet` is true.
|
|
161
|
+
*
|
|
162
|
+
* Returns { removed: [], backedUp: [], skipped: [] }.
|
|
163
|
+
*/
|
|
164
|
+
export function harnessUninit({ root = findProjectRoot(), purgeRatchet = false } = {}) {
|
|
165
|
+
const cmPath = claudeMdPath(root);
|
|
166
|
+
const rmPath = ratchetMdPath(root);
|
|
167
|
+
const result = { removed: [], backedUp: [], skipped: [], root };
|
|
168
|
+
|
|
169
|
+
if (existsSync(cmPath)) {
|
|
170
|
+
const existing = readFileSync(cmPath, 'utf8');
|
|
171
|
+
if (existing.includes(HARNESS_BLOCK_BEGIN)) {
|
|
172
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15);
|
|
173
|
+
const bak = `${cmPath}.bak-${stamp}`;
|
|
174
|
+
writeFileSync(bak, existing);
|
|
175
|
+
const re = new RegExp(
|
|
176
|
+
`\\n*${escapeRe(HARNESS_BLOCK_BEGIN)}[\\s\\S]*?${escapeRe(HARNESS_BLOCK_END)}\\n?`,
|
|
177
|
+
'm',
|
|
178
|
+
);
|
|
179
|
+
const next = existing.replace(re, '').replace(/\n{3,}$/, '\n\n');
|
|
180
|
+
writeFileSync(cmPath, next);
|
|
181
|
+
result.backedUp.push(bak);
|
|
182
|
+
result.removed.push(cmPath + ' (harness block removed)');
|
|
183
|
+
} else {
|
|
184
|
+
result.skipped.push(cmPath + ' (no harness block found)');
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
result.skipped.push(cmPath + ' (does not exist)');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (purgeRatchet && existsSync(rmPath)) {
|
|
191
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15);
|
|
192
|
+
const bak = `${rmPath}.bak-${stamp}`;
|
|
193
|
+
writeFileSync(bak, readFileSync(rmPath, 'utf8'));
|
|
194
|
+
result.backedUp.push(bak);
|
|
195
|
+
// Replace with empty initial template rather than delete (preserves dir).
|
|
196
|
+
writeFileSync(rmPath, harnessRatchetMdInitial());
|
|
197
|
+
result.removed.push(rmPath + ' (reset to initial)');
|
|
198
|
+
} else if (existsSync(rmPath)) {
|
|
199
|
+
result.skipped.push(rmPath + ' (kept; pass --purge-ratchet to reset)');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
|
|
157
205
|
/**
|
|
158
206
|
* harness promote — append a one-line rule to .claude/ratchet.md.
|
|
159
207
|
* Creates the file from the initial template if missing.
|