claude-token-saver 2.10.0 → 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 +55 -5
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
|
@@ -125,15 +125,17 @@ export function harnessInit({ root = findProjectRoot(), force = false } = {}) {
|
|
|
125
125
|
writeFileSync(cmPath, next);
|
|
126
126
|
result.wrote.push(cmPath + ' (block updated in place)');
|
|
127
127
|
} else {
|
|
128
|
-
// Backup, then
|
|
129
|
-
//
|
|
130
|
-
// is
|
|
128
|
+
// Backup as safety net, then APPEND the harness block to existing
|
|
129
|
+
// content (do not clobber). Users keep all their prior CLAUDE.md content;
|
|
130
|
+
// the harness block is added at the end and managed in-place on re-runs
|
|
131
|
+
// via the BEGIN/END markers.
|
|
131
132
|
const stamp = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15); // YYYYMMDDTHHMMSS
|
|
132
133
|
const bak = `${cmPath}.bak-${stamp}`;
|
|
133
134
|
writeFileSync(bak, existing);
|
|
134
|
-
|
|
135
|
+
const sep = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
136
|
+
writeFileSync(cmPath, existing + sep + block);
|
|
135
137
|
result.backedUp.push(bak);
|
|
136
|
-
result.wrote.push(cmPath);
|
|
138
|
+
result.wrote.push(cmPath + ' (harness block appended)');
|
|
137
139
|
}
|
|
138
140
|
} else {
|
|
139
141
|
writeFileSync(cmPath, block);
|
|
@@ -152,6 +154,54 @@ export function harnessInit({ root = findProjectRoot(), force = false } = {}) {
|
|
|
152
154
|
return result;
|
|
153
155
|
}
|
|
154
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
|
+
|
|
155
205
|
/**
|
|
156
206
|
* harness promote — append a one-line rule to .claude/ratchet.md.
|
|
157
207
|
* Creates the file from the initial template if missing.
|