dep-up-surgeon 2.2.3 → 2.2.4

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.
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Implementation of the `dep-up-surgeon undo` subcommand.
3
+ *
4
+ * Given a `.dep-up-surgeon.last-run.json` report (the one written next to every CLI run,
5
+ * unless `--no-persist-report`), this module computes a reverse pass that:
6
+ *
7
+ * 1. Reverts `package.json` dependency ranges back to the `from` values recorded for each
8
+ * successful upgrade (root + every workspace target).
9
+ * 2. Drops override pins that this run added and, when the attempt recorded a `previous`
10
+ * value, restores the previous pin (i.e. if the advisory/manual pin REPLACED an
11
+ * existing override, we don't silently delete the original).
12
+ * 3. Runs `<manager> install` so the lockfile reconverges to the reverted ranges.
13
+ * 4. Runs the validator (unless `--no-validate`) so the operator knows the project builds
14
+ * with the reverted versions before they commit the undo.
15
+ *
16
+ * Safety contract:
17
+ * - If `package.json` has drifted since the recorded run (e.g. another upgrade changed the
18
+ * range), we **skip** that row with `reason: 'drifted'`. We never rewrite a range the
19
+ * user moved out from under us.
20
+ * - If the recorded run was `dryRun`, there's nothing to undo — we return a no-op report.
21
+ * - The module does not know how to restore a lockfile snapshot; instead it asks the
22
+ * manager to reinstall from the reverted `package.json`, which is the guarantee we
23
+ * actually want. A future extension can layer on a lockfile-hash check.
24
+ *
25
+ * Everything heavy (install, validator) is injected via `opts.installer` / `opts.runValidator`
26
+ * so unit tests can exercise the reverse pass without network / process calls.
27
+ */
28
+ import path from 'node:path';
29
+ import fs from 'fs-extra';
30
+ import { readOverrides, removeOverrideFromFile, applyOverrideInMemory, } from '../utils/overrides.js';
31
+ import { runInstall } from '../utils/npm.js';
32
+ import { log } from '../utils/logger.js';
33
+ import { LAST_RUN_FILENAME, loadLastRunReport } from './lastRun.js';
34
+ const DEP_SECTIONS = [
35
+ 'dependencies',
36
+ 'devDependencies',
37
+ 'peerDependencies',
38
+ 'optionalDependencies',
39
+ ];
40
+ /**
41
+ * Run the full reverse pass. Returns a structured `UndoResult` describing what was reverted,
42
+ * what was skipped, and the outcome of the post-reverse install + validator. Never throws on
43
+ * recoverable errors — skipped / failed items are recorded on the result.
44
+ */
45
+ export async function runUndo(opts) {
46
+ const file = opts.file ? path.resolve(opts.cwd, opts.file) : path.join(opts.cwd, LAST_RUN_FILENAME);
47
+ const persisted = opts.file
48
+ ? await readPersisted(file)
49
+ : await loadLastRunReport(opts.cwd);
50
+ if (!persisted) {
51
+ throw new Error(`undo: no run report found at ${file}. Pass --file <path> to point at a specific ` +
52
+ `${LAST_RUN_FILENAME}, or re-run dep-up-surgeon so it writes one.`);
53
+ }
54
+ if (persisted.dryRun) {
55
+ if (!opts.json) {
56
+ log.info(`undo: the recorded run was a dry-run; nothing to revert.`);
57
+ }
58
+ return {
59
+ sourceFile: file,
60
+ noop: true,
61
+ reverts: [],
62
+ overrides: [],
63
+ installs: [],
64
+ };
65
+ }
66
+ const manager = opts.manager ?? persisted.project?.manager ?? 'npm';
67
+ const targets = buildTargetMap(persisted, opts.cwd);
68
+ const reverts = [];
69
+ const overrides = [];
70
+ // ---- 1. Revert dep ranges ------------------------------------------------
71
+ const editedTargets = new Set();
72
+ for (const row of persisted.upgraded ?? []) {
73
+ if (!row.success || row.skipped)
74
+ continue;
75
+ const workspace = row.workspace ?? 'root';
76
+ const target = targets.get(workspace) ?? targets.get('root');
77
+ if (!target) {
78
+ reverts.push({
79
+ name: row.name,
80
+ workspace,
81
+ ok: false,
82
+ skipped: true,
83
+ reason: 'target-missing',
84
+ detail: `no target cwd found for workspace "${workspace}"`,
85
+ });
86
+ continue;
87
+ }
88
+ if (!row.from) {
89
+ reverts.push({
90
+ name: row.name,
91
+ workspace,
92
+ ok: false,
93
+ skipped: true,
94
+ reason: 'no-from',
95
+ detail: 'upgrade row did not record a `from` value',
96
+ ...(row.to ? { to: row.to } : {}),
97
+ });
98
+ continue;
99
+ }
100
+ const revert = await revertDepRange(target.packageJson, row.name, row.from, row.to);
101
+ reverts.push({
102
+ name: row.name,
103
+ workspace,
104
+ from: row.from,
105
+ ...(row.to ? { to: row.to } : {}),
106
+ ...(revert.section ? { section: revert.section } : {}),
107
+ ok: revert.ok,
108
+ skipped: !revert.ok,
109
+ ...(revert.reason ? { reason: revert.reason } : {}),
110
+ ...(revert.detail ? { detail: revert.detail } : {}),
111
+ });
112
+ if (revert.ok && !opts.planOnly) {
113
+ await fs.writeJson(target.packageJson, revert.pkg, { spaces: 2 });
114
+ editedTargets.add(target.cwd);
115
+ }
116
+ }
117
+ // ---- 2. Drop / restore overrides ----------------------------------------
118
+ for (const att of persisted.overrides?.attempts ?? []) {
119
+ if (!att.ok || att.skipped)
120
+ continue;
121
+ const pkgJson = targets.get('root')?.packageJson ?? path.join(opts.cwd, 'package.json');
122
+ if (!(await fs.pathExists(pkgJson))) {
123
+ overrides.push({
124
+ name: att.name,
125
+ ok: false,
126
+ skipped: true,
127
+ reason: 'missing-package-json',
128
+ detail: pkgJson,
129
+ });
130
+ continue;
131
+ }
132
+ const chain = att.chain && att.chain.length > 0 ? [...att.chain] : [att.name];
133
+ let result;
134
+ if (att.previous && att.previous !== att.applied) {
135
+ // Restore the pre-existing pin rather than deleting outright. This is the case where
136
+ // --apply-overrides REPLACED an existing override (e.g. we bumped 1.2.3 → 1.3.0); undo
137
+ // should put 1.2.3 back, not leave the transitive floating.
138
+ if (opts.planOnly) {
139
+ result = {
140
+ name: att.name,
141
+ chain,
142
+ ...(att.applied ? { applied: att.applied } : {}),
143
+ previous: att.previous,
144
+ ok: true,
145
+ skipped: false,
146
+ reason: 'restored-previous',
147
+ detail: `would restore ${att.previous}`,
148
+ };
149
+ }
150
+ else {
151
+ const entry = { name: chain[chain.length - 1], range: att.previous };
152
+ if (chain.length > 1)
153
+ entry.parentChain = chain.slice(0, -1);
154
+ // Undo deliberately bypasses `applyOverrideToFile`'s "skip if existing >= target"
155
+ // semantics — a revert is allowed to move the pin backwards; that's literally the
156
+ // whole point. We call `applyOverrideInMemory` directly and write the result.
157
+ const pkg = (await fs.readJson(pkgJson));
158
+ const next = applyOverrideInMemory(pkg, manager, entry);
159
+ await fs.writeJson(pkgJson, next, { spaces: 2 });
160
+ editedTargets.add(opts.cwd);
161
+ result = {
162
+ name: att.name,
163
+ chain,
164
+ ...(att.applied ? { applied: att.applied } : {}),
165
+ previous: att.previous,
166
+ ok: true,
167
+ skipped: false,
168
+ reason: 'restored-previous',
169
+ };
170
+ }
171
+ }
172
+ else {
173
+ if (opts.planOnly) {
174
+ result = {
175
+ name: att.name,
176
+ chain,
177
+ ...(att.applied ? { applied: att.applied } : {}),
178
+ ok: true,
179
+ skipped: false,
180
+ reason: 'dropped',
181
+ detail: 'would drop',
182
+ };
183
+ }
184
+ else {
185
+ const removed = await removeOverrideFromFile(pkgJson, manager, { chain });
186
+ if (removed.removed) {
187
+ editedTargets.add(opts.cwd);
188
+ result = {
189
+ name: att.name,
190
+ chain,
191
+ ...(att.applied ? { applied: att.applied } : {}),
192
+ ok: true,
193
+ skipped: false,
194
+ reason: 'dropped',
195
+ };
196
+ }
197
+ else {
198
+ result = {
199
+ name: att.name,
200
+ chain,
201
+ ...(att.applied ? { applied: att.applied } : {}),
202
+ ok: false,
203
+ skipped: true,
204
+ reason: 'not-present',
205
+ ...(removed.reason ? { detail: removed.reason } : {}),
206
+ };
207
+ }
208
+ }
209
+ }
210
+ overrides.push(result);
211
+ }
212
+ // ---- 3. Post-reverse install --------------------------------------------
213
+ const installs = [];
214
+ if (!opts.planOnly && !opts.skipInstall && editedTargets.size > 0) {
215
+ const installer = opts.installer ?? runInstall;
216
+ for (const targetCwd of editedTargets) {
217
+ const r = await installer(targetCwd, manager, {});
218
+ const row = {
219
+ cwd: targetCwd,
220
+ ok: r.ok,
221
+ ...(r.command ? { command: r.command } : {}),
222
+ ...(typeof r.exitCode === 'number' ? { exitCode: r.exitCode } : {}),
223
+ ...(r.output ? { lastLines: tail(r.output, 40) } : {}),
224
+ };
225
+ installs.push(row);
226
+ }
227
+ }
228
+ // ---- 4. Post-reverse validator ------------------------------------------
229
+ let validation;
230
+ if (!opts.planOnly && !opts.skipValidator && installs.every((r) => r.ok)) {
231
+ if (opts.runValidator) {
232
+ validation = await opts.runValidator();
233
+ }
234
+ }
235
+ return {
236
+ sourceFile: file,
237
+ noop: false,
238
+ reverts,
239
+ overrides,
240
+ installs,
241
+ ...(validation ? { validation } : {}),
242
+ };
243
+ }
244
+ async function readPersisted(file) {
245
+ if (!(await fs.pathExists(file))) {
246
+ return undefined;
247
+ }
248
+ try {
249
+ return (await fs.readJson(file));
250
+ }
251
+ catch {
252
+ return undefined;
253
+ }
254
+ }
255
+ /**
256
+ * Map workspace label → `{ cwd, packageJson }`. Falls back to the run's `cwd` when no
257
+ * targets block was persisted (single-root run).
258
+ */
259
+ function buildTargetMap(persisted, invokedAt) {
260
+ const map = new Map();
261
+ const targets = persisted.targets ?? [];
262
+ if (targets.length === 0) {
263
+ const rootCwd = persisted.cwd ?? invokedAt;
264
+ map.set('root', {
265
+ cwd: rootCwd,
266
+ packageJson: path.join(rootCwd, 'package.json'),
267
+ });
268
+ return map;
269
+ }
270
+ for (const t of targets) {
271
+ map.set(t.label, { cwd: t.cwd, packageJson: t.packageJson });
272
+ }
273
+ if (!map.has('root')) {
274
+ const rootCwd = persisted.cwd ?? invokedAt;
275
+ map.set('root', {
276
+ cwd: rootCwd,
277
+ packageJson: path.join(rootCwd, 'package.json'),
278
+ });
279
+ }
280
+ return map;
281
+ }
282
+ /**
283
+ * Revert `name` back to `from` in whichever dep section currently holds it. Returns the
284
+ * modified `pkg` object alongside metadata about what section we touched. If the current
285
+ * range doesn't match the recorded `to`, we skip with `drifted` — the user modified the
286
+ * range out from under us and rewriting would be destructive.
287
+ *
288
+ * We do NOT assert the recorded `from` matches the version before the run; the run itself
289
+ * wrote it, so treating its `from` value as authoritative is exactly what the user wants.
290
+ */
291
+ async function revertDepRange(packageJson, name, from, to) {
292
+ if (!(await fs.pathExists(packageJson))) {
293
+ return { ok: false, reason: 'missing', detail: `${packageJson} not found` };
294
+ }
295
+ const pkg = (await fs.readJson(packageJson));
296
+ for (const section of DEP_SECTIONS) {
297
+ const sec = pkg[section];
298
+ if (!sec || typeof sec !== 'object')
299
+ continue;
300
+ const map = sec;
301
+ if (!(name in map))
302
+ continue;
303
+ const current = typeof map[name] === 'string' ? map[name] : undefined;
304
+ if (to && current !== undefined && current !== to) {
305
+ // The recorded run landed on `to` but the current file holds something else — another
306
+ // run (or a human edit) changed it. Bail out of this row; undo is about REVERSING this
307
+ // specific run, not about steamrolling later history.
308
+ return {
309
+ ok: false,
310
+ reason: 'drifted',
311
+ detail: `current \`${section}.${name}\` is "${current}" but the run recorded "${to}"; leaving as-is`,
312
+ };
313
+ }
314
+ map[name] = from;
315
+ pkg[section] = map;
316
+ return { ok: true, pkg, section };
317
+ }
318
+ return {
319
+ ok: false,
320
+ reason: 'missing',
321
+ detail: `${name} not found in any dep section of ${path.basename(packageJson)}`,
322
+ };
323
+ }
324
+ /**
325
+ * Render a human-readable summary of an `UndoResult`. Used by the CLI when `--json` is not
326
+ * set; tests render the JSON directly.
327
+ */
328
+ export function renderUndoHuman(result) {
329
+ const lines = [];
330
+ lines.push(`undo: replayed ${path.basename(result.sourceFile)}`);
331
+ if (result.noop) {
332
+ lines.push(' nothing to revert (recorded run was a dry-run)');
333
+ return lines.join('\n');
334
+ }
335
+ const reverted = result.reverts.filter((r) => r.ok);
336
+ const skipped = result.reverts.filter((r) => !r.ok);
337
+ const droppedOverrides = result.overrides.filter((r) => r.ok);
338
+ const skippedOverrides = result.overrides.filter((r) => !r.ok);
339
+ lines.push(` ${reverted.length} dep range(s) reverted, ${skipped.length} skipped`);
340
+ for (const r of reverted) {
341
+ const ws = r.workspace === 'root' ? '' : ` [${r.workspace}]`;
342
+ lines.push(` - ${r.name}${ws}: ${r.to ?? '?'} → ${r.from}`);
343
+ }
344
+ for (const r of skipped) {
345
+ const ws = r.workspace === 'root' ? '' : ` [${r.workspace}]`;
346
+ lines.push(` ~ ${r.name}${ws}: skipped (${r.reason}${r.detail ? ` — ${r.detail}` : ''})`);
347
+ }
348
+ if (result.overrides.length > 0) {
349
+ lines.push(` ${droppedOverrides.length} override(s) dropped, ${skippedOverrides.length} skipped`);
350
+ for (const o of droppedOverrides) {
351
+ const label = o.chain && o.chain.length > 1 ? o.chain.join('>') : o.name;
352
+ lines.push(` - ${label}: ${o.reason}${o.previous ? ` (${o.applied} → ${o.previous})` : ` (dropped ${o.applied ?? '?'})`}`);
353
+ }
354
+ for (const o of skippedOverrides) {
355
+ const label = o.chain && o.chain.length > 1 ? o.chain.join('>') : o.name;
356
+ lines.push(` ~ ${label}: skipped (${o.reason}${o.detail ? ` — ${o.detail}` : ''})`);
357
+ }
358
+ }
359
+ for (const inst of result.installs) {
360
+ lines.push(` install @ ${inst.cwd}: ${inst.ok ? 'ok' : `failed (exit ${inst.exitCode ?? '?'})`}`);
361
+ }
362
+ if (result.validation) {
363
+ lines.push(` validator: ${result.validation.ok ? 'ok' : 'failed'}`);
364
+ }
365
+ return lines.join('\n');
366
+ }
367
+ /** Take the last `n` lines of multi-line text, preserving order. */
368
+ function tail(text, n) {
369
+ const lines = text.split(/\r?\n/);
370
+ return lines.slice(-n).join('\n');
371
+ }
372
+ /** True when the reverse pass succeeded end-to-end (reverts, installs, validator). */
373
+ export function undoSucceeded(result) {
374
+ if (result.noop)
375
+ return true;
376
+ if (result.installs.some((i) => !i.ok))
377
+ return false;
378
+ if (result.validation && !result.validation.ok)
379
+ return false;
380
+ // Skipped revert rows are soft failures — the user knows about them — so we still return
381
+ // true so `--undo` can exit 0 when everything else is clean. The JSON report surfaces the
382
+ // per-row `skipped` so CI bots can be stricter if they care.
383
+ return true;
384
+ }
385
+ /**
386
+ * Verify a persisted run's overrides weren't already partially undone by a subsequent run.
387
+ * Exported so callers can cheaply check state before running the full reverse pass (e.g. a
388
+ * `--undo --dry-run` mode).
389
+ */
390
+ export async function checkOverridesStillPresent(persisted, manager, cwd) {
391
+ const pkgJson = path.join(cwd, 'package.json');
392
+ if (!(await fs.pathExists(pkgJson)))
393
+ return { present: 0, missing: 0 };
394
+ const pkg = (await fs.readJson(pkgJson));
395
+ const read = readOverrides(pkg, manager);
396
+ let present = 0;
397
+ let missing = 0;
398
+ for (const att of persisted.overrides?.attempts ?? []) {
399
+ if (!att.ok || att.skipped)
400
+ continue;
401
+ const chain = att.chain && att.chain.length > 0 ? att.chain : [att.name];
402
+ const hit = read.entries.find((e) => e.chain.length === chain.length && e.chain.every((seg, i) => seg === chain[i]));
403
+ if (hit)
404
+ present++;
405
+ else
406
+ missing++;
407
+ }
408
+ return { present, missing };
409
+ }
410
+ //# sourceMappingURL=undo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undo.js","sourceRoot":"","sources":["../../src/cli/undo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runUndoCommand(argv: string[], version: string): Promise<void>;
2
+ //# sourceMappingURL=undoCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undoCommand.d.ts","sourceRoot":"","sources":["../../src/cli/undoCommand.ts"],"names":[],"mappings":"AAeA,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsHnF"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Dedicated entry point for `dep-up-surgeon undo`. Like `doctor`, this subcommand has its
3
+ * own commander program because `undo` only needs a tiny subset of the main flow's options,
4
+ * and threading it as a flag would force every upgrade-time option to grow a guard.
5
+ *
6
+ * Exit-code contract:
7
+ * - reverse pass succeeded (or noop) → 0
8
+ * - persisted run file not found / can't be parsed → 2
9
+ * - install or validator failed during the reverse pass → 1
10
+ */
11
+ import path from 'node:path';
12
+ import { Command } from 'commander';
13
+ import { log } from '../utils/logger.js';
14
+ import { renderUndoHuman, runUndo, undoSucceeded } from './undo.js';
15
+ export async function runUndoCommand(argv, version) {
16
+ const cmd = new Command();
17
+ cmd
18
+ .name('dep-up-surgeon undo')
19
+ .description('Reverse the most recent `dep-up-surgeon` run using `.dep-up-surgeon.last-run.json`. ' +
20
+ 'Reverts `package.json` dep ranges to their `from` values, drops override pins this ' +
21
+ 'run added (or restores the previous pin when the run replaced an existing one), ' +
22
+ 'runs a fresh `<manager> install`, then runs the validator so you see green/red before ' +
23
+ 'you commit the revert. Skips rows whose current `package.json` value has drifted from ' +
24
+ 'the recorded `to`, so another run\'s changes are never clobbered. Pair with `--json` ' +
25
+ 'for machine-readable output in CI.')
26
+ .version(version)
27
+ .option('--file <path>', 'Use a specific run report instead of `.dep-up-surgeon.last-run.json` in cwd. Useful when ' +
28
+ 'the directory has been cleaned up or you want to replay a report from a CI artifact.')
29
+ .option('--json', 'Emit the structured `UndoResult` as JSON on stdout instead of the human format.', false)
30
+ .option('--dry-run', 'Compute the reverse plan and print it, but do not touch `package.json`, do not run install, do not run the validator.', false)
31
+ .option('--no-validate', 'Skip the post-reverse validator. Use when the project has no test/build script or when you ' +
32
+ 'only care that the dep ranges rolled back cleanly.')
33
+ .option('--validate <cmd>', 'Run this command as the post-reverse validator (same semantics as the upgrade flow\'s `--validate`).')
34
+ .option('--skip-install', 'Skip the post-reverse `<manager> install`. Only use when you plan to run install yourself ' +
35
+ '(e.g. in a follow-up CI step) — the lockfile will otherwise diverge from the reverted `package.json`.', false)
36
+ .option('--package-manager <mgr>', 'Override the manager recorded in the run report (auto / npm / pnpm / yarn).', 'auto')
37
+ .option('--cwd <path>', 'Run the undo against this directory instead of the current one.');
38
+ // Strip the `undo` dispatch token the same way `doctor` does.
39
+ const forwarded = [argv[0], argv[1], ...argv.slice(3)];
40
+ cmd.parse(forwarded);
41
+ const opts = cmd.opts();
42
+ const cwd = opts.cwd ? path.resolve(process.cwd(), opts.cwd) : process.cwd();
43
+ const skipValidator = opts.validate === false;
44
+ const validatorCommand = typeof opts.validate === 'string' ? opts.validate : undefined;
45
+ try {
46
+ // Build a validator closure that mirrors the main flow's behavior: if the user passed a
47
+ // command we shell that out; otherwise `validateProject` auto-detects test / build. This
48
+ // keeps `--validate "my-cmd"` working identically across `upgrade`, `doctor`, and `undo`.
49
+ const runValidator = async () => {
50
+ if (skipValidator)
51
+ return { ok: true };
52
+ try {
53
+ const { validateProject } = await import('../core/validator.js');
54
+ const fs = await import('fs-extra');
55
+ const pkg = await fs.default.readJson(path.join(cwd, 'package.json'));
56
+ const manager = opts.packageManager && opts.packageManager !== 'auto'
57
+ ? opts.packageManager
58
+ : 'npm';
59
+ const vr = await validateProject(cwd, pkg, {
60
+ ...(validatorCommand ? { command: validatorCommand, source: 'cli' } : {}),
61
+ manager,
62
+ });
63
+ return {
64
+ ok: vr.ok,
65
+ ...(vr.command ? { command: vr.command } : {}),
66
+ ...(vr.output ? { lastLines: vr.output } : {}),
67
+ };
68
+ }
69
+ catch {
70
+ // Validator crash != project broken for undo's purposes — report ok so we don't
71
+ // exit 1 purely because the validator harness itself errored. The reverse pass has
72
+ // already written the correct ranges; the operator can run their tests manually.
73
+ return { ok: true };
74
+ }
75
+ };
76
+ const result = await runUndo({
77
+ cwd,
78
+ ...(opts.file ? { file: opts.file } : {}),
79
+ ...(opts.packageManager && opts.packageManager !== 'auto'
80
+ ? { manager: opts.packageManager }
81
+ : {}),
82
+ ...(opts.dryRun ? { planOnly: true } : {}),
83
+ ...(opts.skipInstall ? { skipInstall: true } : {}),
84
+ ...(skipValidator ? { skipValidator: true } : {}),
85
+ ...(skipValidator ? {} : { runValidator }),
86
+ ...(opts.json ? { json: true } : {}),
87
+ });
88
+ if (opts.json) {
89
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
90
+ }
91
+ else {
92
+ process.stdout.write(renderUndoHuman(result) + '\n');
93
+ }
94
+ process.exit(undoSucceeded(result) ? 0 : 1);
95
+ }
96
+ catch (e) {
97
+ log.error(`undo failed: ${e instanceof Error ? e.message : String(e)}`);
98
+ process.exit(2);
99
+ }
100
+ }
101
+ //# sourceMappingURL=undoCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undoCommand.js","sourceRoot":"","sources":["../../src/cli/undoCommand.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import chalk from 'chalk';
5
5
  import fs from 'fs-extra';
6
6
  import { program } from 'commander';
7
7
  import prompts from 'prompts';
8
- import { appendIgnoreToRc, loadConfig, mergeIgnoreLists, resolveValidateOptions, } from './config/loadConfig.js';
8
+ import { appendIgnoreToRc, loadConfig, mergeIgnoreLists, mergeOverrideSources, resolveValidateOptions, } from './config/loadConfig.js';
9
9
  import { buildStructuredReport, printStructuredCliSummary } from './cli/report.js';
10
10
  import { computeRetryFailedIgnores, LAST_RUN_FILENAME, loadLastRunReport, persistLastRunReport, } from './cli/lastRun.js';
11
11
  import { resolveSummaryDestination, writeSummary } from './cli/summary.js';
@@ -122,6 +122,14 @@ async function main() {
122
122
  await runDoctorCommand(process.argv, version);
123
123
  return;
124
124
  }
125
+ // `undo` reads `.dep-up-surgeon.last-run.json` and reverses the last run (dep ranges +
126
+ // overrides + reinstall + validate). Same early-dispatch pattern as `doctor` so the
127
+ // subcommand doesn't inherit the upgrade flow's 70+ options.
128
+ if (process.argv[2] === 'undo') {
129
+ const { runUndoCommand } = await import('./cli/undoCommand.js');
130
+ await runUndoCommand(process.argv, version);
131
+ return;
132
+ }
125
133
  program
126
134
  .name('dep-up-surgeon')
127
135
  .description('Upgrade npm dependencies one-by-one with install + test/build validation and rollback on failure.')
@@ -197,6 +205,12 @@ async function main() {
197
205
  }
198
206
  const config = await loadConfig(cwd);
199
207
  const ignore = mergeIgnoreLists(config.ignore, opts.ignore);
208
+ for (const w of config.warnings ?? []) {
209
+ log.warn(`rc: ${w}`);
210
+ }
211
+ if ((config.overrides?.length ?? 0) > 0 && !jsonOutput) {
212
+ log.info(`rc: loaded ${config.overrides.length} override pin${config.overrides.length === 1 ? '' : 's'} from .dep-up-surgeonrc (will run through the same install + validator + rollback cycle as --apply-overrides)`);
213
+ }
200
214
  // ---- Load .dep-up-surgeon.policy.{yaml,json} ----
201
215
  const { loadPolicy } = await import('./config/policy.js');
202
216
  const policyResult = await loadPolicy(cwd);
@@ -571,32 +585,34 @@ async function main() {
571
585
  // Runs AFTER enrichments so we have the final `upgraded` list, and BEFORE the summary so
572
586
  // the summary writer + JSON consumers see `report.overrides`. `--override` works
573
587
  // standalone (no --security-only required); `--apply-overrides` still needs an audit.
574
- const hasManualOverrides = Array.isArray(opts.override) && opts.override.length > 0;
588
+ const hasCliOverrides = Array.isArray(opts.override) && opts.override.length > 0;
589
+ const hasRcOverrides = (config.overrides?.length ?? 0) > 0;
590
+ const hasManualOverrides = hasCliOverrides || hasRcOverrides;
575
591
  const wantsAdvisoryOverrides = Boolean(opts.applyOverrides);
576
592
  if ((wantsAdvisoryOverrides || hasManualOverrides) && !dryRun) {
577
- // Parse manual selectors up-front so we can warn about malformed entries even if the
578
- // audit path is skipped. A malformed selector is fatal (not just skipped) because the
579
- // user asked for something we can't represent.
580
- let manualOverrides = [];
581
- let manualError;
582
- if (hasManualOverrides) {
583
- const { parseOverrideSelector } = await import('./utils/overrides.js');
584
- for (const raw of opts.override) {
585
- const parsed = parseOverrideSelector(raw);
586
- if (!parsed || !parsed.range) {
587
- manualError = `invalid --override selector "${raw}" (expected "<chain>@<range>" where chain is a package name, "parent>child", or "parent/child")`;
588
- break;
589
- }
590
- manualOverrides.push({ chain: parsed.chain, range: parsed.range, source: raw });
591
- }
592
- }
593
- if (manualError) {
594
- log.error(manualError);
595
- process.exitCode = 1;
596
- }
597
- else if (wantsAdvisoryOverrides &&
593
+ // Merge rc-sourced + CLI selectors. The merger dedupes by chain (CLI wins on conflict),
594
+ // normalizes selector strings, and surfaces malformed CLI entries as warnings but NOT
595
+ // as a fatal error, because we still want the valid rc entries to apply even when the
596
+ // user typo'd one `--override` flag.
597
+ const merged = mergeOverrideSources(config.overrides, opts.override);
598
+ for (const w of merged.warnings) {
599
+ log.warn(w);
600
+ }
601
+ const manualOverrides = merged.entries.map((e) => {
602
+ const spec = {
603
+ chain: e.chain,
604
+ range: e.range,
605
+ };
606
+ if (e.source)
607
+ spec.source = e.source;
608
+ if (e.reason)
609
+ spec.reason = e.reason;
610
+ return spec;
611
+ });
612
+ const effectivelyHasManual = manualOverrides.length > 0;
613
+ if (wantsAdvisoryOverrides &&
598
614
  (!opts.securityOnly || !auditResult || auditResult.advisories.length === 0) &&
599
- !hasManualOverrides) {
615
+ !effectivelyHasManual) {
600
616
  if (!jsonOutput) {
601
617
  log.warn('--apply-overrides requires --security-only with at least one audit advisory; skipping.');
602
618
  }