@lannguyensi/harness 0.15.0 → 0.17.0

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +63 -1
  3. package/dist/cli/doctor/format.js +24 -0
  4. package/dist/cli/doctor/format.js.map +1 -1
  5. package/dist/cli/doctor/index.d.ts +7 -0
  6. package/dist/cli/doctor/index.js +10 -0
  7. package/dist/cli/doctor/index.js.map +1 -1
  8. package/dist/cli/doctor/rogue-ledger.d.ts +25 -0
  9. package/dist/cli/doctor/rogue-ledger.js +106 -0
  10. package/dist/cli/doctor/rogue-ledger.js.map +1 -0
  11. package/dist/cli/doctor/types.d.ts +10 -1
  12. package/dist/cli/doctor/types.js.map +1 -1
  13. package/dist/cli/index.js +210 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/init/composer.js +42 -0
  16. package/dist/cli/init/composer.js.map +1 -1
  17. package/dist/cli/init/templates.d.ts +1 -1
  18. package/dist/cli/init/templates.js +42 -0
  19. package/dist/cli/init/templates.js.map +1 -1
  20. package/dist/cli/pack/hook-branch-protection.d.ts +30 -0
  21. package/dist/cli/pack/hook-branch-protection.js +279 -0
  22. package/dist/cli/pack/hook-branch-protection.js.map +1 -0
  23. package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +1 -1
  24. package/dist/cli/pack/hook-codex-pre-tool-use.js +27 -2
  25. package/dist/cli/pack/hook-codex-pre-tool-use.js.map +1 -1
  26. package/dist/cli/pack/hook-pre-tool-use.js +52 -10
  27. package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
  28. package/dist/cli/pack/understanding-report-schema-hint.d.ts +13 -0
  29. package/dist/cli/pack/understanding-report-schema-hint.js +54 -0
  30. package/dist/cli/pack/understanding-report-schema-hint.js.map +1 -0
  31. package/dist/cli/session-start/branch-check.d.ts +44 -0
  32. package/dist/cli/session-start/branch-check.js +165 -0
  33. package/dist/cli/session-start/branch-check.js.map +1 -0
  34. package/dist/cli/uninstall/index.d.ts +68 -0
  35. package/dist/cli/uninstall/index.js +586 -0
  36. package/dist/cli/uninstall/index.js.map +1 -0
  37. package/dist/cli/uninstall/snapshot.d.ts +40 -0
  38. package/dist/cli/uninstall/snapshot.js +34 -0
  39. package/dist/cli/uninstall/snapshot.js.map +1 -0
  40. package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +47 -0
  41. package/dist/policy-packs/builtin/branch-protection-runtime.js +92 -0
  42. package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -0
  43. package/dist/policy-packs/builtin/branch-protection.d.ts +9 -0
  44. package/dist/policy-packs/builtin/branch-protection.js +146 -0
  45. package/dist/policy-packs/builtin/branch-protection.js.map +1 -0
  46. package/dist/policy-packs/registry.d.ts +1 -1
  47. package/dist/policy-packs/registry.js +10 -3
  48. package/dist/policy-packs/registry.js.map +1 -1
  49. package/dist/runtime/agent-facing.d.ts +9 -0
  50. package/dist/runtime/agent-facing.js +47 -0
  51. package/dist/runtime/agent-facing.js.map +1 -0
  52. package/dist/runtime/index.d.ts +1 -0
  53. package/dist/runtime/index.js +1 -0
  54. package/dist/runtime/index.js.map +1 -1
  55. package/dist/runtime/intercept.js +20 -2
  56. package/dist/runtime/intercept.js.map +1 -1
  57. package/dist/schema/index.d.ts +63 -0
  58. package/dist/schema/policies.d.ts +90 -0
  59. package/dist/schema/policies.js +29 -0
  60. package/dist/schema/policies.js.map +1 -1
  61. package/package.json +2 -1
@@ -0,0 +1,586 @@
1
+ // `harness uninstall` — clean teardown of a harness installation.
2
+ //
3
+ // Inventories what harness planted in `~/.claude/` (manifest, lock,
4
+ // generated tree, hook groups in settings.json, mcpServers entries it
5
+ // owns, and any settings.json.pre-harness-<TS> backups left by the
6
+ // operator's manual rollback recipe) and, with `--apply`, removes them.
7
+ //
8
+ // Reversibility (mirrors `gate disable`):
9
+ // - Pre-mutation `settings.json` is backed up to
10
+ // `settings.json.bak.uninstall.<ISO>`.
11
+ // - A snapshot of removed hook groups + mcpServers entries lands at
12
+ // `harness.uninstall.<ISO>.json` next to settings.json.
13
+ // - Settings.json is mutated atomically AFTER backup + snapshot are
14
+ // written, so a crash mid-write leaves the operator with both an
15
+ // intact settings.json and a complete record of what was about to be
16
+ // removed.
17
+ //
18
+ // `--restore-from <path>` is the escape hatch when the operator has a
19
+ // `settings.json.pre-harness-<TS>` backup from when they first installed
20
+ // harness: instead of selective key removal, atomically copy that
21
+ // backup over the live file. Still writes the standard `.bak.uninstall.*`
22
+ // + snapshot so the restore is itself reversible.
23
+ //
24
+ // Out of scope (v1):
25
+ // - Foreign hook groups (anything whose commands don't start with the
26
+ // harness binary) are left alone — uninstall is conservative.
27
+ // - Project-local `~/.claude.json` is read-only (we surface a warning
28
+ // when `mcpServers.grounding-mcp` is registered there since the user
29
+ // will want to clean it up too, but we don't touch it).
30
+ // - `npm uninstall -g @lannguyensi/harness` is the operator's call —
31
+ // uninstall prints a hint but doesn't shell out.
32
+ //
33
+ // Ownership heuristics:
34
+ // - Hook group: every inner hook's `command` must begin with
35
+ // `harness ` or be `npx @lannguyensi/harness ...`. Mixed groups (some
36
+ // harness, some foreign) are left in place with a warning so we
37
+ // never split an operator-authored group on a guess.
38
+ // - MCP server: union of the manifest's `tools.mcp[].name` (when the
39
+ // manifest is readable) and the canonical default `grounding-mcp`.
40
+ // This makes uninstall correct on manifests that renamed the server
41
+ // while still cleaning the default install path when the manifest is
42
+ // gone or unreadable.
43
+ import * as fs from "node:fs";
44
+ import * as os from "node:os";
45
+ import * as path from "node:path";
46
+ import { parse as parseYaml } from "yaml";
47
+ import { atomicWriteFile } from "../../io/atomic-write.js";
48
+ import { GENERATED_DIRNAME } from "../../io/generated-dir.js";
49
+ import { backupPath, sha256Hex, SNAPSHOT_VERSION, snapshotPath, } from "./snapshot.js";
50
+ const MANIFEST_BASENAME = "harness.yaml";
51
+ const LOCK_BASENAME = "harness.lock";
52
+ const SETTINGS_BASENAME = "settings.json";
53
+ const PRE_HARNESS_BACKUP_PREFIX = "settings.json.pre-harness-";
54
+ /**
55
+ * MCP servers harness wires by default across its bundled templates
56
+ * (see `src/cli/init/templates.ts` + `src/cli/init/composer.ts`). Used
57
+ * as the fallback ownership set when the manifest has been deleted
58
+ * out-of-band and we can't enumerate `tools.mcp[].name`. Widening this
59
+ * list catches the same entries the templates planted; narrowing it
60
+ * would leave them stranded after manifest-less uninstall.
61
+ */
62
+ const DEFAULT_OWNED_MCP_SERVERS = [
63
+ "agent-tasks",
64
+ "codebase-oracle",
65
+ "grounding-mcp",
66
+ ];
67
+ /**
68
+ * Prefixes a hook command must start with for the group to count as
69
+ * harness-owned. The bundled templates only ever emit `harness ...`
70
+ * plain commands (resolved via PATH); operators who hand-wired hooks
71
+ * with an absolute path to `dist/cli/main.js` or a non-PATH binary
72
+ * will NOT be matched here and must clean those groups themselves.
73
+ */
74
+ const HARNESS_COMMAND_PREFIXES = ["harness ", "npx @lannguyensi/harness "];
75
+ export class UninstallError extends Error {
76
+ constructor(message) {
77
+ super(message);
78
+ this.name = "UninstallError";
79
+ }
80
+ }
81
+ function resolveHomeDir(opts) {
82
+ return opts.homeDir ?? path.join(os.homedir(), ".claude");
83
+ }
84
+ function resolveSettingsPath(opts, homeDir) {
85
+ if (typeof opts.settingsPath === "string" && opts.settingsPath.length > 0) {
86
+ return opts.settingsPath;
87
+ }
88
+ return path.join(homeDir, SETTINGS_BASENAME);
89
+ }
90
+ /**
91
+ * Read + parse settings.json. Refuses to operate on malformed shapes
92
+ * (precedent: `gate/disable.ts`) so a broken file is surfaced rather
93
+ * than silently overwritten with "something cleaner". Returns null when
94
+ * the file simply doesn't exist (nothing to clean up; not an error).
95
+ */
96
+ function readSettings(settingsPath) {
97
+ let raw;
98
+ try {
99
+ raw = fs.readFileSync(settingsPath, "utf8");
100
+ }
101
+ catch (err) {
102
+ if (err.code === "ENOENT")
103
+ return null;
104
+ throw new UninstallError(`cannot read ${settingsPath}: ${err.message}`);
105
+ }
106
+ let parsed;
107
+ try {
108
+ parsed = JSON.parse(raw);
109
+ }
110
+ catch (err) {
111
+ throw new UninstallError(`${settingsPath} is not valid JSON (${err.message}); refusing to operate. ` +
112
+ `Fix the file by hand or restore from a backup before re-running.`);
113
+ }
114
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
115
+ throw new UninstallError(`${settingsPath} is not a JSON object; refusing to operate.`);
116
+ }
117
+ const obj = parsed;
118
+ let hooks = null;
119
+ const rawHooks = obj["hooks"];
120
+ if (rawHooks !== undefined) {
121
+ if (rawHooks === null || typeof rawHooks !== "object" || Array.isArray(rawHooks)) {
122
+ throw new UninstallError(`${settingsPath} \`hooks\` field is not an object; refusing to operate.`);
123
+ }
124
+ const out = {};
125
+ for (const [event, groups] of Object.entries(rawHooks)) {
126
+ if (!Array.isArray(groups)) {
127
+ throw new UninstallError(`${settingsPath} \`hooks.${event}\` is not an array; refusing to operate.`);
128
+ }
129
+ out[event] = groups;
130
+ }
131
+ hooks = out;
132
+ }
133
+ let mcpServers = null;
134
+ const rawMcp = obj["mcpServers"];
135
+ if (rawMcp !== undefined) {
136
+ if (rawMcp === null || typeof rawMcp !== "object" || Array.isArray(rawMcp)) {
137
+ throw new UninstallError(`${settingsPath} \`mcpServers\` field is not an object; refusing to operate.`);
138
+ }
139
+ mcpServers = rawMcp;
140
+ }
141
+ return { raw, obj, hooks, mcpServers };
142
+ }
143
+ function isHarnessOwnedCommand(command) {
144
+ const trimmed = command.trim();
145
+ return HARNESS_COMMAND_PREFIXES.some((p) => trimmed.startsWith(p));
146
+ }
147
+ /**
148
+ * A hook group is harness-owned iff every inner hook's command is a
149
+ * harness invocation. Mixed groups are left in place with a warning —
150
+ * splitting a group on a guess risks corrupting an operator-authored
151
+ * composite hook.
152
+ */
153
+ function classifyHookGroup(group) {
154
+ if (group === null || typeof group !== "object" || Array.isArray(group))
155
+ return "malformed";
156
+ const inner = group["hooks"];
157
+ if (!Array.isArray(inner) || inner.length === 0)
158
+ return "foreign";
159
+ let ownedCount = 0;
160
+ let foreignCount = 0;
161
+ for (const h of inner) {
162
+ if (h === null || typeof h !== "object" || Array.isArray(h))
163
+ return "malformed";
164
+ const cmd = h["command"];
165
+ if (typeof cmd !== "string")
166
+ return "malformed";
167
+ if (isHarnessOwnedCommand(cmd))
168
+ ownedCount++;
169
+ else
170
+ foreignCount++;
171
+ }
172
+ if (ownedCount > 0 && foreignCount === 0)
173
+ return "owned";
174
+ if (ownedCount === 0)
175
+ return "foreign";
176
+ return "mixed";
177
+ }
178
+ function groupMatcher(group) {
179
+ if (group === null || typeof group !== "object" || Array.isArray(group))
180
+ return null;
181
+ const m = group["matcher"];
182
+ return typeof m === "string" ? m : null;
183
+ }
184
+ function summarizeGroup(group) {
185
+ if (group === null || typeof group !== "object" || Array.isArray(group))
186
+ return "<malformed>";
187
+ const inner = Array.isArray(group["hooks"])
188
+ ? group["hooks"]
189
+ : [];
190
+ const cmds = [];
191
+ for (const h of inner) {
192
+ if (h !== null && typeof h === "object" && !Array.isArray(h)) {
193
+ const cmd = h["command"];
194
+ if (typeof cmd === "string")
195
+ cmds.push(cmd);
196
+ }
197
+ }
198
+ if (cmds.length === 0)
199
+ return "<no commands>";
200
+ return cmds.map((c) => (c.length > 80 ? `${c.slice(0, 77)}...` : c)).join("; ");
201
+ }
202
+ /**
203
+ * Best-effort read of the manifest's `tools.mcp[].name` list. The
204
+ * manifest may be absent (user deleted it), malformed, or just missing
205
+ * the mcp section — all return an empty list. We never throw from this:
206
+ * uninstall's job is to clean up, and a broken manifest is not a reason
207
+ * to refuse to remove the entries we already know about.
208
+ */
209
+ function manifestMcpNames(manifestPath) {
210
+ if (manifestPath === null)
211
+ return [];
212
+ let raw;
213
+ try {
214
+ raw = fs.readFileSync(manifestPath, "utf8");
215
+ }
216
+ catch {
217
+ return [];
218
+ }
219
+ let parsed;
220
+ try {
221
+ parsed = parseYaml(raw);
222
+ }
223
+ catch {
224
+ return [];
225
+ }
226
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
227
+ return [];
228
+ const tools = parsed["tools"];
229
+ if (tools === null || typeof tools !== "object" || Array.isArray(tools))
230
+ return [];
231
+ const mcp = tools["mcp"];
232
+ if (!Array.isArray(mcp))
233
+ return [];
234
+ const names = [];
235
+ for (const entry of mcp) {
236
+ if (entry !== null && typeof entry === "object" && !Array.isArray(entry)) {
237
+ const name = entry["name"];
238
+ if (typeof name === "string" && name.length > 0)
239
+ names.push(name);
240
+ }
241
+ }
242
+ return names;
243
+ }
244
+ function listPreHarnessBackups(settingsDir) {
245
+ let names;
246
+ try {
247
+ names = fs.readdirSync(settingsDir);
248
+ }
249
+ catch {
250
+ return [];
251
+ }
252
+ const out = [];
253
+ for (const n of names) {
254
+ if (n.startsWith(PRE_HARNESS_BACKUP_PREFIX)) {
255
+ out.push(path.join(settingsDir, n));
256
+ }
257
+ }
258
+ return out.sort();
259
+ }
260
+ /**
261
+ * Collect harness-owned hook group refs, plus warnings for mixed groups
262
+ * (groups we won't touch but whose presence the operator should know
263
+ * about so they can split them by hand if desired).
264
+ */
265
+ function collectOwnedHookGroups(hooks, warnings) {
266
+ if (hooks === null)
267
+ return [];
268
+ const out = [];
269
+ for (const event of Object.keys(hooks).sort()) {
270
+ const groups = hooks[event] ?? [];
271
+ groups.forEach((group, index) => {
272
+ const verdict = classifyHookGroup(group);
273
+ if (verdict === "owned") {
274
+ out.push({
275
+ event,
276
+ index,
277
+ matcher: groupMatcher(group),
278
+ description: summarizeGroup(group),
279
+ });
280
+ return;
281
+ }
282
+ if (verdict === "mixed") {
283
+ warnings.push(`hooks.${event}[${index}] is a mixed group (harness + foreign commands); leaving in place. ` +
284
+ `Split it manually if you want the harness commands removed.`);
285
+ }
286
+ });
287
+ }
288
+ return out;
289
+ }
290
+ function ownedMcpServerNames(mcp, manifestPath) {
291
+ if (mcp === null)
292
+ return [];
293
+ const owned = new Set(DEFAULT_OWNED_MCP_SERVERS);
294
+ for (const n of manifestMcpNames(manifestPath))
295
+ owned.add(n);
296
+ const present = [];
297
+ for (const name of Object.keys(mcp).sort()) {
298
+ if (owned.has(name))
299
+ present.push(name);
300
+ }
301
+ return present;
302
+ }
303
+ function existsOrNull(p) {
304
+ try {
305
+ fs.accessSync(p);
306
+ return p;
307
+ }
308
+ catch {
309
+ return null;
310
+ }
311
+ }
312
+ function probeProjectLocalClaudeJson(warnings, homeDir) {
313
+ // The user's `~/.claude.json` (note: NOT under `~/.claude/`) is where
314
+ // Claude Code records project-level config — including mcpServers
315
+ // registered with `claude mcp add`. Harness never writes there, but
316
+ // if the user followed an earlier walkthrough that wired
317
+ // `grounding-mcp` project-level, it sits silently after uninstall and
318
+ // keeps the binary on the spawn list. We surface a hint but never
319
+ // touch the file: it's user-owned territory.
320
+ const projectLocal = path.join(path.dirname(homeDir), ".claude.json");
321
+ let raw;
322
+ try {
323
+ raw = fs.readFileSync(projectLocal, "utf8");
324
+ }
325
+ catch {
326
+ return;
327
+ }
328
+ let parsed;
329
+ try {
330
+ parsed = JSON.parse(raw);
331
+ }
332
+ catch {
333
+ return;
334
+ }
335
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
336
+ return;
337
+ const stack = [parsed];
338
+ while (stack.length > 0) {
339
+ const node = stack.pop();
340
+ if (node === null || typeof node !== "object" || Array.isArray(node))
341
+ continue;
342
+ const obj = node;
343
+ const mcp = obj["mcpServers"];
344
+ if (mcp !== null && typeof mcp === "object" && !Array.isArray(mcp)) {
345
+ for (const name of Object.keys(mcp)) {
346
+ if (DEFAULT_OWNED_MCP_SERVERS.includes(name) ||
347
+ name === "agent-grounding") {
348
+ warnings.push(`~/.claude.json registers mcpServers.${name} project-level; uninstall does not touch ` +
349
+ `that file. Run \`claude mcp remove ${name}\` to clean it up if you no longer need ` +
350
+ `the binary on the spawn list.`);
351
+ }
352
+ }
353
+ }
354
+ for (const v of Object.values(obj)) {
355
+ if (v !== null && typeof v === "object")
356
+ stack.push(v);
357
+ }
358
+ }
359
+ }
360
+ function buildInventory(opts) {
361
+ const homeDir = resolveHomeDir(opts);
362
+ const settingsPath = resolveSettingsPath(opts, homeDir);
363
+ const manifestPath = existsOrNull(path.join(homeDir, MANIFEST_BASENAME));
364
+ const lockPath = existsOrNull(path.join(homeDir, LOCK_BASENAME));
365
+ const generatedDir = existsOrNull(path.join(homeDir, GENERATED_DIRNAME));
366
+ const parsed = readSettings(settingsPath);
367
+ const warnings = [];
368
+ const hookGroups = collectOwnedHookGroups(parsed?.hooks ?? null, warnings);
369
+ const mcpServers = ownedMcpServerNames(parsed?.mcpServers ?? null, manifestPath);
370
+ const preHarnessBackups = listPreHarnessBackups(path.dirname(settingsPath));
371
+ probeProjectLocalClaudeJson(warnings, homeDir);
372
+ return {
373
+ inventory: {
374
+ homeDir,
375
+ settingsPath,
376
+ manifestPath,
377
+ lockPath,
378
+ generatedDir,
379
+ hookGroups,
380
+ mcpServers,
381
+ preHarnessBackups,
382
+ warnings,
383
+ },
384
+ parsed,
385
+ };
386
+ }
387
+ function removeFilesystemArtefacts(inventory) {
388
+ const removed = [];
389
+ for (const p of [inventory.manifestPath, inventory.lockPath]) {
390
+ if (p === null)
391
+ continue;
392
+ try {
393
+ fs.unlinkSync(p);
394
+ removed.push(p);
395
+ }
396
+ catch (err) {
397
+ throw new UninstallError(`failed to remove ${p}: ${err.message}`);
398
+ }
399
+ }
400
+ if (inventory.generatedDir !== null) {
401
+ try {
402
+ fs.rmSync(inventory.generatedDir, { recursive: true, force: true });
403
+ removed.push(inventory.generatedDir);
404
+ }
405
+ catch (err) {
406
+ throw new UninstallError(`failed to remove ${inventory.generatedDir}: ${err.message}`);
407
+ }
408
+ }
409
+ return removed;
410
+ }
411
+ function writeSettingsWithRemovals(parsed, inventory, now) {
412
+ const removedHookGroups = [];
413
+ const keptHooks = {};
414
+ const ownedRefs = new Set(inventory.hookGroups.map((g) => `${g.event}${g.index}`));
415
+ if (parsed.hooks !== null) {
416
+ for (const event of Object.keys(parsed.hooks).sort()) {
417
+ const groups = parsed.hooks[event] ?? [];
418
+ const kept = [];
419
+ groups.forEach((group, index) => {
420
+ if (ownedRefs.has(`${event}${index}`)) {
421
+ removedHookGroups.push({ event, index, group });
422
+ }
423
+ else {
424
+ kept.push(group);
425
+ }
426
+ });
427
+ if (kept.length > 0)
428
+ keptHooks[event] = kept;
429
+ }
430
+ }
431
+ const removedMcpServers = [];
432
+ const keptMcpServers = {};
433
+ if (parsed.mcpServers !== null) {
434
+ const ownedMcp = new Set(inventory.mcpServers);
435
+ for (const name of Object.keys(parsed.mcpServers)) {
436
+ if (ownedMcp.has(name)) {
437
+ removedMcpServers.push({ name, spec: parsed.mcpServers[name] });
438
+ }
439
+ else {
440
+ keptMcpServers[name] = parsed.mcpServers[name];
441
+ }
442
+ }
443
+ }
444
+ const beforeSha = sha256Hex(parsed.raw);
445
+ const backup = backupPath(inventory.settingsPath, now);
446
+ const snapPath = snapshotPath(inventory.settingsPath, now);
447
+ // Backup BEFORE we touch the live file. A failure here aborts cleanly.
448
+ atomicWriteFile(backup, parsed.raw);
449
+ const newObj = { ...parsed.obj };
450
+ if (Object.keys(keptHooks).length === 0) {
451
+ delete newObj["hooks"];
452
+ }
453
+ else {
454
+ newObj["hooks"] = keptHooks;
455
+ }
456
+ if (Object.keys(keptMcpServers).length === 0) {
457
+ delete newObj["mcpServers"];
458
+ }
459
+ else {
460
+ newObj["mcpServers"] = keptMcpServers;
461
+ }
462
+ const newSettings = `${JSON.stringify(newObj, null, 2)}\n`;
463
+ const afterSha = sha256Hex(newSettings);
464
+ const snapshot = {
465
+ version: SNAPSHOT_VERSION,
466
+ createdAt: now.toISOString(),
467
+ settingsPath: inventory.settingsPath,
468
+ settingsBackupPath: backup,
469
+ settingsBeforeSha256: beforeSha,
470
+ settingsAfterSha256: afterSha,
471
+ removedHookGroups,
472
+ removedMcpServers,
473
+ };
474
+ // Snapshot lands BEFORE the live rewrite (same ordering rationale as
475
+ // `gate disable`: snapshot is the reversibility insurance).
476
+ atomicWriteFile(snapPath, `${JSON.stringify(snapshot, null, 2)}\n`);
477
+ atomicWriteFile(inventory.settingsPath, newSettings);
478
+ return { backupPath: backup, snapshotPath: snapPath, removedHookGroups, removedMcpServers };
479
+ }
480
+ function writeRestoreSnapshot(parsed, inventory, restoreSource, restoredContent, now) {
481
+ const beforeSha = sha256Hex(parsed.raw);
482
+ const afterSha = sha256Hex(restoredContent);
483
+ const backup = backupPath(inventory.settingsPath, now);
484
+ const snapPath = snapshotPath(inventory.settingsPath, now);
485
+ atomicWriteFile(backup, parsed.raw);
486
+ // Inventory the would-be removals so the snapshot still records what
487
+ // was overwritten, even though the restore is wholesale.
488
+ const removedHookGroups = [];
489
+ if (parsed.hooks !== null) {
490
+ for (const event of Object.keys(parsed.hooks).sort()) {
491
+ const groups = parsed.hooks[event] ?? [];
492
+ groups.forEach((group, index) => {
493
+ if (classifyHookGroup(group) === "owned") {
494
+ removedHookGroups.push({ event, index, group });
495
+ }
496
+ });
497
+ }
498
+ }
499
+ const removedMcpServers = [];
500
+ if (parsed.mcpServers !== null) {
501
+ const ownedMcp = new Set(inventory.mcpServers);
502
+ for (const name of Object.keys(parsed.mcpServers).sort()) {
503
+ if (ownedMcp.has(name)) {
504
+ removedMcpServers.push({ name, spec: parsed.mcpServers[name] });
505
+ }
506
+ }
507
+ }
508
+ const snapshot = {
509
+ version: SNAPSHOT_VERSION,
510
+ createdAt: now.toISOString(),
511
+ settingsPath: inventory.settingsPath,
512
+ settingsBackupPath: backup,
513
+ settingsBeforeSha256: beforeSha,
514
+ settingsAfterSha256: afterSha,
515
+ removedHookGroups,
516
+ removedMcpServers,
517
+ restoredFrom: restoreSource,
518
+ };
519
+ atomicWriteFile(snapPath, `${JSON.stringify(snapshot, null, 2)}\n`);
520
+ atomicWriteFile(inventory.settingsPath, restoredContent);
521
+ return { backupPath: backup, snapshotPath: snapPath };
522
+ }
523
+ export function uninstall(opts = {}) {
524
+ const { inventory, parsed } = buildInventory(opts);
525
+ const apply = opts.apply === true || typeof opts.restoreFrom === "string";
526
+ if (!apply) {
527
+ return { mode: "list", inventory };
528
+ }
529
+ const now = opts.now ?? new Date();
530
+ if (typeof opts.restoreFrom === "string" && opts.restoreFrom.length > 0) {
531
+ let restored;
532
+ try {
533
+ restored = fs.readFileSync(opts.restoreFrom, "utf8");
534
+ }
535
+ catch (err) {
536
+ throw new UninstallError(`cannot read restore source ${opts.restoreFrom}: ${err.message}`);
537
+ }
538
+ // Validate restore source: must be a JSON object. Avoids silently
539
+ // overwriting settings.json with a corrupt file the operator picked
540
+ // off disk.
541
+ try {
542
+ const parsedRestore = JSON.parse(restored);
543
+ if (parsedRestore === null ||
544
+ typeof parsedRestore !== "object" ||
545
+ Array.isArray(parsedRestore)) {
546
+ throw new UninstallError(`restore source ${opts.restoreFrom} is not a JSON object; refusing.`);
547
+ }
548
+ }
549
+ catch (err) {
550
+ if (err instanceof UninstallError)
551
+ throw err;
552
+ throw new UninstallError(`restore source ${opts.restoreFrom} is not valid JSON (${err.message}); refusing.`);
553
+ }
554
+ if (parsed === null) {
555
+ throw new UninstallError(`${inventory.settingsPath} does not exist; nothing to restore over. ` +
556
+ `Copy ${opts.restoreFrom} into place by hand if that's what you want.`);
557
+ }
558
+ const { backupPath: bp, snapshotPath: sp } = writeRestoreSnapshot(parsed, inventory, opts.restoreFrom, restored, now);
559
+ const removedFiles = removeFilesystemArtefacts(inventory);
560
+ return {
561
+ mode: "restore",
562
+ inventory,
563
+ restoredFrom: opts.restoreFrom,
564
+ backupPath: bp,
565
+ snapshotPath: sp,
566
+ removedFiles,
567
+ };
568
+ }
569
+ const needsSettingsRewrite = inventory.hookGroups.length > 0 || inventory.mcpServers.length > 0;
570
+ let backup = null;
571
+ let snap = null;
572
+ if (parsed !== null && needsSettingsRewrite) {
573
+ const written = writeSettingsWithRemovals(parsed, inventory, now);
574
+ backup = written.backupPath;
575
+ snap = written.snapshotPath;
576
+ }
577
+ const removedFiles = removeFilesystemArtefacts(inventory);
578
+ return {
579
+ mode: "apply",
580
+ inventory,
581
+ backupPath: backup,
582
+ snapshotPath: snap,
583
+ removedFiles,
584
+ };
585
+ }
586
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/uninstall/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ export declare const SNAPSHOT_BASENAME_PREFIX = "harness.uninstall.";
2
+ export declare const SNAPSHOT_BASENAME_SUFFIX = ".json";
3
+ export declare const BACKUP_INFIX = ".bak.uninstall.";
4
+ export declare const SNAPSHOT_VERSION: 1;
5
+ export interface RemovedHookGroup {
6
+ /** Hook event the group lived under, e.g. "PreToolUse". */
7
+ event: string;
8
+ /** Position inside `hooks[event][]` at the time of removal. */
9
+ index: number;
10
+ /** Literal JSON value of the removed group; preserved verbatim. */
11
+ group: unknown;
12
+ }
13
+ export interface RemovedMcpServer {
14
+ /** Server name (the `mcpServers` map key). */
15
+ name: string;
16
+ /** Literal JSON value of the removed server spec; preserved verbatim. */
17
+ spec: unknown;
18
+ }
19
+ export interface UninstallSnapshot {
20
+ version: typeof SNAPSHOT_VERSION;
21
+ /** ISO-8601 UTC timestamp of the uninstall call. */
22
+ createdAt: string;
23
+ /** Absolute path to the settings.json that was mutated. */
24
+ settingsPath: string;
25
+ /** Absolute path the pre-mutation copy was written to. */
26
+ settingsBackupPath: string;
27
+ /** SHA-256 of settings.json content BEFORE the removal. */
28
+ settingsBeforeSha256: string;
29
+ /** SHA-256 of settings.json content AFTER the removal. */
30
+ settingsAfterSha256: string;
31
+ /** Removed hook groups, sorted by event then ascending index. */
32
+ removedHookGroups: RemovedHookGroup[];
33
+ /** Removed mcpServers entries, sorted by name. */
34
+ removedMcpServers: RemovedMcpServer[];
35
+ }
36
+ export declare function sha256Hex(input: string | Buffer): string;
37
+ /** Build the snapshot file path for `settingsPath` at `now`. */
38
+ export declare function snapshotPath(settingsPath: string, now: Date): string;
39
+ /** Build the settings-backup file path for `settingsPath` at `now`. */
40
+ export declare function backupPath(settingsPath: string, now: Date): string;