dep-up-surgeon 2.2.2 → 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.
Files changed (45) hide show
  1. package/README.md +122 -12
  2. package/dist/cli/overrideFlow.d.ts +50 -0
  3. package/dist/cli/overrideFlow.d.ts.map +1 -1
  4. package/dist/cli/overrideFlow.js +112 -69
  5. package/dist/cli/overrideFlow.js.map +1 -1
  6. package/dist/cli/summary.d.ts.map +1 -1
  7. package/dist/cli/summary.js +17 -4
  8. package/dist/cli/summary.js.map +1 -1
  9. package/dist/cli/undo.d.ts +105 -0
  10. package/dist/cli/undo.d.ts.map +1 -0
  11. package/dist/cli/undo.js +410 -0
  12. package/dist/cli/undo.js.map +1 -0
  13. package/dist/cli/undoCommand.d.ts +2 -0
  14. package/dist/cli/undoCommand.d.ts.map +1 -0
  15. package/dist/cli/undoCommand.js +101 -0
  16. package/dist/cli/undoCommand.js.map +1 -0
  17. package/dist/cli.js +56 -14
  18. package/dist/cli.js.map +1 -1
  19. package/dist/config/loadConfig.d.ts +64 -0
  20. package/dist/config/loadConfig.d.ts.map +1 -1
  21. package/dist/config/loadConfig.js +200 -1
  22. package/dist/config/loadConfig.js.map +1 -1
  23. package/dist/core/audit.d.ts +18 -0
  24. package/dist/core/audit.d.ts.map +1 -1
  25. package/dist/core/audit.js +29 -0
  26. package/dist/core/audit.js.map +1 -1
  27. package/dist/core/peerResolver.d.ts +64 -0
  28. package/dist/core/peerResolver.d.ts.map +1 -1
  29. package/dist/core/peerResolver.js +225 -2
  30. package/dist/core/peerResolver.js.map +1 -1
  31. package/dist/core/peerResolverAdHoc.d.ts +42 -0
  32. package/dist/core/peerResolverAdHoc.d.ts.map +1 -0
  33. package/dist/core/peerResolverAdHoc.js +226 -0
  34. package/dist/core/peerResolverAdHoc.js.map +1 -0
  35. package/dist/core/upgrader.d.ts +12 -1
  36. package/dist/core/upgrader.d.ts.map +1 -1
  37. package/dist/core/upgrader.js +171 -7
  38. package/dist/core/upgrader.js.map +1 -1
  39. package/dist/types.d.ts +24 -4
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/utils/overrides.d.ts +81 -7
  42. package/dist/utils/overrides.d.ts.map +1 -1
  43. package/dist/utils/overrides.js +344 -30
  44. package/dist/utils/overrides.js.map +1 -1
  45. package/package.json +3 -3
package/README.md CHANGED
@@ -79,8 +79,9 @@ dep-up-surgeon [options]
79
79
  | `--security-only` | Run `npm audit` (or `pnpm`/`yarn` equivalent) first, then upgrade **only** the packages with open advisories. Every successful bump carries the advisory severity + ID into its commit subject (`[security:high]`) and into the summary's **Security fixes** table. Pairs well with `--git-commit-mode per-success` to produce one PR per CVE. See **Security-first mode** below. |
80
80
  | `--min-severity <level>` | Minimum advisory severity to consider under `--security-only`: `low` (default), `moderate`, `high`, or `critical`. Lower-severity advisories are filtered out before the upgrade plan is built. |
81
81
  | `--blast-radius` / `--no-blast-radius` | Scan project source files to list which files actually `import`/`require` each upgraded package, and surface the list in `--json` + `--summary`. **Default ON** when `--summary` is active. See **Blast radius** below. |
82
- | `--resolve-peers` / `--no-resolve-peers` | When a linked-group bump (e.g. `react` + `react-dom` + `@types/react`) fails with a peer-dependency conflict, compute the intersection of peer ranges across the registry packument and retry with a satisfiable version tuple (members may land below `latest`). **Default ON**. See **Peer-range intersection resolver** below. |
82
+ | `--resolve-peers` / `--no-resolve-peers` | When a linked-group bump (e.g. `react` + `react-dom` + `@types/react`) **or a single-package bump** fails with a peer-dependency conflict, compute the intersection of peer ranges across the registry packument and retry with a satisfiable version tuple (members may land below `latest`). Linked graphs with 10+ members automatically use a SAT-style AC-3 solver; single-package failures synthesize an **ad-hoc group** from direct-dep blockers named in the install output. **Default ON**. See **Peer-range intersection resolver** below. |
83
83
  | `--apply-overrides` | After the main upgrade loop, fix **transitive** CVEs that no direct bump could reach by writing a package-manager override (`overrides` for npm, `pnpm.overrides` for pnpm, `resolutions` for yarn) pinning each vulnerable transitive to its audit-recommended safe version. Runs install + validator after each pin and rolls back automatically when the validator fails. Requires `--security-only`. See **Transitive overrides** below. |
84
+ | `--override <spec...>` | Apply one or more **manual** override pins independent of the audit. Repeatable and also accepts comma-separated values. Syntax: `<chain>@<range>`, where `<chain>` is a bare name (`lodash`), a pnpm-style chain (`some-dep>foo`, any depth), or a yarn-style chain (`parent/child`). Scoped names (`@scope/pkg`) are preserved as single chain segments. Written to the manager-native nested form (npm object, pnpm `>`-keys, yarn `/`-keys) and run through the same install + validator + rollback loop as `--apply-overrides`. Works standalone — `--security-only` is not required. See **Transitive overrides** below. |
84
85
  | `--override-force` | Used with `--apply-overrides`. Overwrite an **existing** override entry whose value conflicts with the audit-recommended version. By default we refuse to clobber user-managed pins and record `conflict` in the report. |
85
86
  | `--fix-lockfile` | After the main upgrade loop, run the package manager's native dedupe command (`npm dedupe` / `pnpm dedupe` / `yarn dedupe`) to collapse redundant transitive copies **without touching `package.json`**, and flag transitives more than a minor or a full major behind registry `latest`. Lockfile is backed up before dedupe and restored if dedupe OR the post-dedupe validator fails. Yarn classic (v1) has no dedupe subcommand — recorded as `skipped: "unsupported"`. See **Lockfile fix** below. |
86
87
  | `--open-pr` | After `--git-commit --git-branch` pushes the branch, open a GitHub PR with the `--summary` markdown as the body (falls back to a deterministic minimal body). Uses the `gh` CLI (must be installed + authenticated); never fatal — a missing binary, auth failure, or push rejection is recorded as `pullRequest.error` in the JSON report without aborting the run. See **Auto-opening a PR** below. |
@@ -235,6 +236,8 @@ npx dep-up-surgeon --workspaces --security-only --min-severity high \
235
236
  --git-branch "deps/security-$(date +%Y-%m-%d)"
236
237
  ```
237
238
 
239
+ The whole path is covered by `test/unit/security-only.test.mjs` — a hermetic regression harness that drives `runAudit` with a canned `npm audit --json` blob, asserts `--min-severity` filters at every tier, and exercises the full `runUpgradeFlow` → install → validator → **rollback** cycle without touching the registry (via the `UpgradeFlowOptions.installer` injection point).
240
+
238
241
  ### Policy engine (policy-as-code)
239
242
 
240
243
  Drop a `.dep-up-surgeon.policy.yaml` (or `.json`) in the repo root to encode upgrade rules that survive across runs and humans. Loaded automatically on startup; violations are reported per-package and the engine skips the offending bumps instead of failing.
@@ -296,16 +299,21 @@ Linked-group bumps (e.g. `react` + `react-dom` + `@types/react`, or the Jest / T
296
299
  2. If the install fails with a **peer** conflict, the resolver fetches each linked package's full registry packument (cached — one call per package per run) and reads every published version's `peerDependencies` block.
297
300
  3. Each member gets a candidate domain: every version between `currentRange`'s `minVersion` and the originally-requested target, sorted newest-first, minus deprecated / pre-release versions.
298
301
  4. A **newest-first backtracking search** enumerates version tuples (variable = one package, domain = its candidate versions). For each partial assignment, every peer constraint that has become knowable is checked; peers on packages inside the linked group are checked against the chosen version, peers on packages OUTSIDE the group are checked against that package's range in the current `package.json` (via `semver.minVersion`).
299
- 5. The **first** complete tuple to satisfy every constraint is also the least-downgrade one. The engine rewrites the batch's target versions and retries the install + validator. On success, every affected row is tagged with `resolvedPeer = { originalTarget, reason, tuplesExplored }`.
300
- 6. If the resolver can't find a satisfiable tuple, or the retried install still fails, the batch falls back to the pre-resolver behavior (rollback + `kind: 'peer'` failure row).
302
+ 5. For **large linked graphs (≥ 10 members)** where the 400-tuple backtracking budget can be burned before the solver escapes the first variable's domain — the resolver automatically switches to a **SAT-style path** (arc-consistency + least-constraining-value DFS). It pre-prunes every member-version that can't be satisfied against external peers, runs up to 128 AC-3 rounds across every ordered member pair until the pruned domains reach a fixed point, then does an **MRV-ordered** (smallest domain first) newest-first DFS on whatever survived. For monorepo link groups up to ~50 members × ~30 recent versions this finishes in milliseconds where plain DFS would return `undefined`. When the SAT path fails the dispatcher falls back to the plain backtracker automatically.
303
+ 6. The **first** complete tuple to satisfy every constraint is also the least-downgrade one. The engine rewrites the batch's target versions and retries the install + validator. On success, every affected row is tagged with `resolvedPeer = { originalTarget, reason, tuplesExplored }` `reason` carries a `[backtracking]` or `[sat]` method tag so reviewers can tell which solver path produced the tuple.
304
+ 7. If the resolver can't find a satisfiable tuple, or the retried install still fails, the batch falls back to the pre-resolver behavior (rollback + `kind: 'peer'` failure row).
305
+
306
+ **Ad-hoc resolver for non-linked bumps.** Single-package upgrades that fail with a peer conflict used to be rolled back unconditionally — the resolver was linked-groups-only. Now we synthesize an **ad-hoc group** from the parsed install output: the primary + every blocker named in the peer-conflict lines that's **already a direct dep** of the workspace (peers on unknown transitives stay out of scope). The same resolver (and the same SAT fallback) runs on that synthesized group. On success the engine writes a small batch: the primary at whatever version the resolver picked, plus any blocker the resolver wants moved within its **current pinned range** (the ad-hoc path is allowed to downgrade the primary, never to silently bump a blocker past its pin).
301
307
 
302
308
  Guard rails that keep it safe:
303
309
 
304
- - **Bounded search** — capped at 400 tuples explored per batch. Past that the resolver gives up silently instead of hanging the run on pathological inputs.
310
+ - **Bounded search** — capped at 400 tuples explored per batch (small graphs) or `400 × members` tuples for the SAT path's DFS phase. Past that the resolver gives up silently instead of hanging the run on pathological inputs.
305
311
  - **Optional peers** (`peerDependenciesMeta[name].optional === true`) are ignored. An unsatisfied optional peer isn't a hard conflict.
306
312
  - **Deprecated versions** never appear in the domain. We'd rather fail to find a solution than auto-suggest a known-bad version.
313
+ - **Ad-hoc group size cap** — default 6 members (primary + up to 5 direct-dep blockers). Prevents registry fetch storms on pathological peer graphs.
314
+ - **Ad-hoc never adds dependencies** — a peer on a transitive that isn't already a direct dep is ignored rather than introduced.
307
315
  - **`--force` bypasses the resolver** — the user has explicitly opted into barreling through peer conflicts.
308
- - **`--no-resolve-peers`** keeps the old behavior when you WANT peer failures to surface so a human resolves them instead of the tool silently nudging versions off latest.
316
+ - **`--no-resolve-peers`** keeps the old behavior when you WANT peer failures to surface so a human resolves them instead of the tool silently nudging versions off latest. Applies to both the linked-group and ad-hoc paths.
309
317
 
310
318
  Where it shows up:
311
319
 
@@ -314,7 +322,7 @@ Where it shows up:
314
322
  - **Commit subjects**: `[peer-resolved]` tag sits between `[breaking]` and `[security:<sev>]` (stable order). The body gets a `Peer-range resolutions (kept linked group satisfiable):` footer listing each pinned member.
315
323
  - **`--json`**: `upgraded[].resolvedPeer = { originalTarget, reason, tuplesExplored }` plus `upgraded[].requestedLatest` still reflects the pre-resolver target so downstream tools can diff them.
316
324
 
317
- ### Transitive overrides (`--apply-overrides`)
325
+ ### Transitive overrides (`--apply-overrides` / `--override`)
318
326
 
319
327
  `--security-only` by itself can only fix vulnerabilities reachable from a direct dependency. For CVEs that live in transitives (very common — `lodash@4.17.20` buried six levels deep under a toolchain package), pair `--security-only` with `--apply-overrides` and the tool will write a package-manager override to pin the vulnerable transitive to its safe version.
320
328
 
@@ -323,19 +331,117 @@ Where it shows up:
323
331
  - **Rollback on failure**: after each override, the tool runs a full install and then the validator. If either fails, the override is removed, install re-runs to restore the starting state, and the next advisory is still attempted. A failed override never strands the workspace — `report.overrides.attempts[].rolledBack === true` appears in the JSON and the summary.
324
332
  - **Conflict protection**: when the user already has a manual override with a value that **conflicts** with the audit recommendation, we refuse to clobber by default (`reason: "conflicts with target ..."`). Pass `--override-force` to overwrite explicitly.
325
333
  - **Where it shows up**:
326
- - **`--summary`**: dedicated `Overrides applied` table with `Package / Pinned to / Severity / Advisory`.
327
- - **`--json`**: `overrides.field` + `overrides.attempts[]` with the full decision trail (`ok`, `skipped`, `reason`, `previous`, `applied`, `installLog`, `rolledBack`).
334
+ - **`--summary`**: dedicated `Overrides applied` table with `Package / Pinned to / Source / Severity / Advisory`. Parent-scoped pins render as `a › b › c` so the chain is visible at a glance.
335
+ - **`--json`**: `overrides.field` + `overrides.attempts[]` with the full decision trail (`ok`, `skipped`, `reason`, `previous`, `applied`, `installLog`, `rolledBack`, `chain`, `source`). Parent-scoped pins carry `chain: ["parent", "child"]`; `source` distinguishes `"advisory"` from `"manual"`.
336
+
337
+ #### Parent-scoped pins (`--override`)
338
+
339
+ `--apply-overrides` only writes the **flat** `name → version` form — every occurrence of the package gets pinned. When you need to pin a transitive **only when it appears under a specific parent** (e.g. you want `foo@1.2.3` under `some-dep` while the rest of the tree uses `foo@2.x`), use `--override` to write a **parent-scoped** selector. Works standalone — no `--security-only` required.
340
+
341
+ Syntax: `<chain>@<range>`. The chain supports three forms, all normalized internally:
342
+
343
+ - **Flat**: `--override lodash@4.17.21` → same shape as a classic flat override.
344
+ - **pnpm-style**: `--override "some-dep>foo@1.2.3"` — pin `foo` only when nested under `some-dep`. Chains of any depth (`a>b>c>d@1.0.0`) are supported.
345
+ - **yarn-style**: `--override "parent/child@1.2.3"` — `/` separator; `@scope/pkg` stays intact as a single chain segment.
346
+
347
+ Each selector is written to the **manager's native nested encoding**:
348
+
349
+ | Manager | Shape written |
350
+ | --- | --- |
351
+ | npm | `{ "overrides": { "some-dep": { "foo": "1.2.3" } } }` — nested object; an existing flat pin for the parent is preserved via npm's `"."` self-selector. |
352
+ | pnpm | `{ "pnpm": { "overrides": { "some-dep>foo": "1.2.3" } } }` — pnpm's `>`-chain keys, deep chains supported. |
353
+ | yarn | `{ "resolutions": { "some-dep/foo": "1.2.3" } }` — `/`-chain keys. |
354
+
355
+ Every pin runs through the same install + validator + rollback loop as advisory-driven pins. A failed manual pin is rolled back (only that specific slot) and the rest of the run continues; a flat pin and a parent-scoped pin with the same leaf name coexist as separate entries.
328
356
 
329
357
  ```bash
330
- # Weekly security sweep: direct bumps first, then transitive overrides, then a draft PR.
358
+ # Pin `lodash@4.17.21` ONLY when it's a transitive of `some-dep`, and pin `axios@1.6.0`
359
+ # globally. Both live in the same run; one failing never touches the other.
360
+ npx dep-up-surgeon \
361
+ --override "some-dep>lodash@4.17.21" \
362
+ --override "axios@1.6.0" \
363
+ --validate "npm test"
364
+ ```
365
+
366
+ ```bash
367
+ # Weekly security sweep: direct bumps first, then transitive overrides (audit-driven +
368
+ # one manual pin), then a draft PR.
331
369
  npx dep-up-surgeon --workspaces \
332
370
  --security-only --min-severity high \
333
371
  --apply-overrides \
372
+ --override "@babel/core>@babel/traverse@7.23.2" \
334
373
  --git-commit --git-commit-mode per-success --git-branch "deps/security-$(date +%Y-%m-%d)" \
335
374
  --summary md \
336
375
  --open-pr --open-pr-draft
337
376
  ```
338
377
 
378
+ #### Override policy file (`.dep-up-surgeonrc` `overrides`)
379
+
380
+ Re-typing `--override "parent>child@1.2.3"` on every CI run gets old fast. Commit the pins to `.dep-up-surgeonrc` instead and they'll apply on every run the same way `ignore` does — merging with any CLI `--override` flags on the same invocation (**CLI wins on chain conflict**). The committed form supports a `reason` string that flows straight into the report + summary so reviewers can see **why** each transitive is pinned (CVE ID, vendor guidance, upstream PR link) without grepping commit history.
381
+
382
+ Two input shapes are accepted:
383
+
384
+ ```jsonc
385
+ {
386
+ "overrides": [
387
+ // Structured: explicit chain + range. `chain: "lodash"` is shorthand for the flat case.
388
+ { "chain": ["some-dep", "foo"], "range": "1.2.3", "reason": "CVE-2025-1234" },
389
+
390
+ // Selector form: same syntax as the `--override` CLI flag.
391
+ { "selector": "@babel/core>@babel/traverse@7.23.2", "reason": "upstream PR #16012 pending" },
392
+ { "selector": "lodash@4.17.21" }
393
+ ]
394
+ }
395
+ ```
396
+
397
+ Behavior:
398
+
399
+ - **Merge + dedupe**: entries are merged with CLI `--override` selectors by exact chain. A CLI pin for the same chain **replaces** the rc entry (including the `reason`), so one-off ad-hoc overrides always win over committed policy.
400
+ - **Malformed CLI selectors are warnings**, not fatal: a typo in one `--override` flag won't prevent committed rc pins from applying. rc entries with a bad shape produce per-entry warnings in `.dep-up-surgeonrc.warnings` and the run continues.
401
+ - **Same lifecycle as `--override`**: every pin goes through the install + validator + rollback loop. Failures are per-pin — one bad pin never strands the rest.
402
+ - **`reason` surfaces in the report**: the `Overrides applied` table in `--summary` adds a `Reason` column whenever at least one attempt carries one; `--json` ships `overrides.attempts[].policyReason` verbatim for bots.
403
+
404
+ ```bash
405
+ # Run the committed overrides policy. No CLI flags needed; `overrides: [...]` in
406
+ # `.dep-up-surgeonrc` is enough to trigger the flow.
407
+ npx dep-up-surgeon --summary md
408
+
409
+ # Add a one-off pin on top of the committed set for this run only:
410
+ npx dep-up-surgeon --override "lodash@4.17.21" --summary md
411
+ ```
412
+
413
+ ### Disaster recovery (`dep-up-surgeon undo`)
414
+
415
+ Every run writes `.dep-up-surgeon.last-run.json` — a structured record of what the tool did (previous ranges, `to` values, every override attempt with `applied`/`previous`, workspace targets). `dep-up-surgeon undo` replays that record **in reverse**:
416
+
417
+ 1. For every successful upgrade row, write the recorded `from` back to `package.json` (in whatever section currently holds the dep, across the root and every workspace target).
418
+ 2. For every successful override attempt, drop the pin we added — or, when the attempt recorded a `previous` value (the run replaced an existing pin), restore that previous value.
419
+ 3. Run `<manager> install` once per edited target so the lockfile re-converges to the reverted `package.json`.
420
+ 4. Run the validator so you see green/red before you commit the revert.
421
+
422
+ Drift protection:
423
+
424
+ - If the current `package.json` value for a dep **doesn't match** the `to` the run landed on (another run, or a human edit, moved it), the row is **skipped** with `reason: 'drifted'`. Undo never rewrites state we don't recognize.
425
+ - When the recorded run was `--dry-run`, undo is a **no-op**.
426
+ - Missing / unparseable run report → the command exits with status 2 and a clear error message.
427
+
428
+ ```bash
429
+ # Replay the newest recorded run in this directory.
430
+ npx dep-up-surgeon undo
431
+
432
+ # Compute the reverse plan WITHOUT touching the disk. Use for review/CI dry-runs.
433
+ npx dep-up-surgeon undo --dry-run
434
+
435
+ # Replay a specific run file (e.g. from a CI artifact).
436
+ npx dep-up-surgeon undo --file ./ci-logs/2026-04-18-upgrade.last-run.json
437
+
438
+ # Skip the validator — handy when the project has no test script but you still want the
439
+ # dep ranges rolled back.
440
+ npx dep-up-surgeon undo --no-validate
441
+ ```
442
+
443
+ Exit codes: `0` = reverse pass succeeded (or was a no-op); `1` = install or validator failed during the reverse pass (the JSON report still explains which rows moved); `2` = the run report was missing / invalid. Pair with `--json` for CI pipelines — the full `UndoResult` is emitted on stdout.
444
+
339
445
  ### Lockfile fix (`--fix-lockfile`)
340
446
 
341
447
  `--fix-lockfile` improves the **lockfile's** dependency graph without touching `package.json`. It's the counterpart to `--apply-overrides`: where overrides fix vulnerable transitives, `--fix-lockfile` collapses redundant ones and surfaces the stale-but-not-vulnerable tail that a direct upgrade loop can never reach.
@@ -508,7 +614,11 @@ Create `.dep-up-surgeonrc` in the project root:
508
614
  "packages": ["package-a", "package-b"]
509
615
  }
510
616
  ],
511
- "validate": "tsc -p tsconfig.json --noEmit"
617
+ "validate": "tsc -p tsconfig.json --noEmit",
618
+ "overrides": [
619
+ { "chain": ["some-dep", "foo"], "range": "1.2.3", "reason": "CVE-2025-1234" },
620
+ { "selector": "lodash@4.17.21", "reason": "awaiting upstream PR #42" }
621
+ ]
512
622
  }
513
623
  ```
514
624
 
@@ -518,6 +628,8 @@ Ignored packages are never upgraded. The CLI `--ignore` list is merged with this
518
628
 
519
629
  **`validate`** overrides the validator command. Accepts either a shell string (`"tsc --noEmit"`) or an object: `{ "command": "pnpm -r build" }` or `{ "skip": true }`. CLI flags (`--validate`, `--no-validate`) always win over this file.
520
630
 
631
+ **`overrides`** defines persistent parent-scoped / flat override pins applied on every run. Merges with CLI `--override` flags (CLI wins on exact-chain conflict). Each entry's `reason` flows into `report.overrides.attempts[].policyReason` and the summary's `Reason` column. See [Override policy file](#override-policy-file-dep-up-surgeonrc-overrides) for the full schema.
632
+
521
633
  ## JSON report (`--json`)
522
634
 
523
635
  Stdout is a single JSON object including:
@@ -605,8 +717,6 @@ The compiled entry is `dist/cli.js` (see `"bin"` in `package.json`).
605
717
  ## Future work (tracked in code)
606
718
 
607
719
  - GitLab / Bitbucket auto-PR providers (today `--open-pr` is GitHub-only via `gh`)
608
- - Nested / parent-scoped override rules beyond the flat `name → version` form (`overrides: { "foo": { ">=2 <3": "3.0.0" } }` in npm, deep pnpm selectors)
609
- - Resolver sharpening: SAT-backed peer-range intersection for very large linked graphs (10+ members) where the current 400-tuple backtracking budget gives up; peer-range intersection across **non-linked** packages too (today the resolver only intervenes on linked-group failures)
610
720
  - Renovate-style scheduling helpers (cron / day-of-week filters, grouping rules)
611
721
  - True parallel installs in monorepos that don't share a root lockfile (e.g. nohoist setups), going beyond today's parallel scan + serial install model
612
722
  - AI-assisted failure explanation: feed `install.lastLines` + `validation.lastLines` to an LLM and attach a one-sentence "why this broke" note to failed records
@@ -1,5 +1,6 @@
1
1
  import type { SecurityAdvisory } from '../core/audit.js';
2
2
  import type { PackageManager } from '../core/workspaces.js';
3
+ import { runInstall } from '../utils/npm.js';
3
4
  import { type OverrideField } from '../utils/overrides.js';
4
5
  export interface OverrideAttemptRecord {
5
6
  name: string;
@@ -11,6 +12,25 @@ export interface OverrideAttemptRecord {
11
12
  applied?: string;
12
13
  /** The previous pin, if any. */
13
14
  previous?: string;
15
+ /**
16
+ * Full parent chain for parent-scoped pins, outermost → leaf. Omitted for flat pins
17
+ * (equivalent to `chain: [name]`). Included in the report so consumers know which exact
18
+ * slot in the overrides block was touched.
19
+ */
20
+ chain?: string[];
21
+ /**
22
+ * How this attempt was triggered. `advisory` = fed in by `--security-only` audit; `manual`
23
+ * = user-supplied via `--override` CLI flag or `.dep-up-surgeonrc` `overrides` policy.
24
+ * Consumers can render the two lists separately (e.g. manual overrides don't map to a CVE).
25
+ */
26
+ source: 'advisory' | 'manual';
27
+ /**
28
+ * Human-readable reason the manual pin exists (e.g. `"CVE-2025-1234"`, `"awaiting upstream
29
+ * PR #123"`). Populated only for pins sourced from the rc policy; CLI-only pins have no
30
+ * reason attached. Rendered verbatim in the JSON report and the markdown summary so
31
+ * reviewers see the "why" next to the "what" without grepping commit messages.
32
+ */
33
+ policyReason?: string;
14
34
  /** Field we touched (`overrides` / `pnpm.overrides` / `resolutions`). */
15
35
  field: OverrideField;
16
36
  /** True when the write, install, AND validator all succeeded. */
@@ -24,6 +44,25 @@ export interface OverrideAttemptRecord {
24
44
  /** True when a rollback was performed. */
25
45
  rolledBack?: boolean;
26
46
  }
47
+ /**
48
+ * User-supplied override pin (from `--override` CLI flag or similar). Unlike advisory-driven
49
+ * pins, these carry an arbitrary parent chain and no CVE metadata. They run through the same
50
+ * write + install + validator + rollback cycle so a manual pin can't wreck the workspace.
51
+ */
52
+ export interface ManualOverrideSpec {
53
+ /** Parent chain + leaf, outermost → leaf (`[name]` for flat pins). */
54
+ chain: string[];
55
+ /** Version / range to pin. */
56
+ range: string;
57
+ /** Original user-supplied selector string, for error messages and the report. */
58
+ source?: string;
59
+ /**
60
+ * Optional human-readable reason for the pin. When provided, it's threaded into the
61
+ * attempt record's `policyReason` so the JSON report + summary can render it alongside
62
+ * the pinned package. Used by rc-sourced overrides to surface CVE IDs / vendor guidance.
63
+ */
64
+ reason?: string;
65
+ }
27
66
  export interface OverrideFlowOptions {
28
67
  /** Workspace root. Every override write and `runInstall` happens here. */
29
68
  cwd: string;
@@ -49,6 +88,17 @@ export interface OverrideFlowOptions {
49
88
  dryRun?: boolean;
50
89
  /** True when the CLI is in `--json` mode: suppress human-readable progress log lines. */
51
90
  json?: boolean;
91
+ /**
92
+ * User-supplied parent-scoped or flat pins (via `--override` CLI flag). These run AFTER
93
+ * the advisory-driven pins in the same loop so they share the install + validator +
94
+ * rollback machinery. A failure here never touches advisory results.
95
+ */
96
+ manualOverrides?: ManualOverrideSpec[];
97
+ /**
98
+ * Optional install runner override. Kept as an injection point so tests can exercise the
99
+ * write + rollback cycle without actually shelling out.
100
+ */
101
+ installer?: typeof runInstall;
52
102
  }
53
103
  export interface OverrideFlowResult {
54
104
  /** Every advisory we considered, including skips. */
@@ -1 +1 @@
1
- {"version":3,"file":"overrideFlow.d.ts","sourceRoot":"","sources":["../../src/cli/overrideFlow.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;IACnD,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,KAAK,EAAE,aAAa,CAAC;IACrB,iEAAiE;IACjE,EAAE,EAAE,OAAO,CAAC;IACZ,yFAAyF;IACzF,OAAO,EAAE,OAAO,CAAC;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,OAAO,EAAE,cAAc,CAAC;IACxB,gFAAgF;IAChF,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,mFAAmF;IACnF,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,2FAA2F;IAC3F,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,gGAAgG;IAChG,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoH5F;AAkCD;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAkBrF"}
1
+ {"version":3,"file":"overrideFlow.d.ts","sourceRoot":"","sources":["../../src/cli/overrideFlow.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAsB,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;IACnD,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,MAAM,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC9B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,KAAK,EAAE,aAAa,CAAC;IACrB,iEAAiE;IACjE,EAAE,EAAE,OAAO,CAAC;IACZ,yFAAyF;IACzF,OAAO,EAAE,OAAO,CAAC;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,OAAO,EAAE,cAAc,CAAC;IACxB,gFAAgF;IAChF,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,mFAAmF;IACnF,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,2FAA2F;IAC3F,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,gGAAgG;IAChG,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0FAA0F;IAC1F,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,eAAe,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACvC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAuF5F;AAsHD;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAkBrF"}
@@ -41,10 +41,11 @@ export async function runOverrideFlow(opts) {
41
41
  // the main upgrade loop. These are the pure-transitive CVEs that overrides exist to fix.
42
42
  const targets = opts.advisories.filter((a) => !opts.directDepNames.has(a.name) &&
43
43
  !opts.upgradedNames.has(a.name));
44
- if (targets.length === 0) {
44
+ const hasManual = (opts.manualOverrides?.length ?? 0) > 0;
45
+ if (targets.length === 0 && !hasManual) {
45
46
  return { attempts };
46
47
  }
47
- if (!opts.json) {
48
+ if (targets.length > 0 && !opts.json) {
48
49
  log.info(`--apply-overrides: ${targets.length} transitive advisor${targets.length === 1 ? 'y' : 'ies'} to pin (${targets.map((t) => t.name).slice(0, 5).join(', ')}${targets.length > 5 ? ', ...' : ''})`);
49
50
  }
50
51
  for (const adv of targets) {
@@ -55,6 +56,7 @@ export async function runOverrideFlow(opts) {
55
56
  field,
56
57
  ok: false,
57
58
  skipped: false,
59
+ source: 'advisory',
58
60
  };
59
61
  if (adv.url)
60
62
  rec.url = adv.url;
@@ -67,90 +69,131 @@ export async function runOverrideFlow(opts) {
67
69
  attempts.push(rec);
68
70
  continue;
69
71
  }
70
- if (opts.dryRun) {
71
- rec.skipped = true;
72
- rec.reason = 'dry-run';
73
- rec.applied = target;
74
- attempts.push(rec);
75
- continue;
76
- }
77
- // 1. Write the pin (or skip when already safe).
78
- const applied = await applyOverrideToFile({
79
- packageJsonPath: pkgJson,
80
- manager: opts.manager,
81
- entry: { name: adv.name, range: target },
82
- ...(opts.overwriteConflicts ? { overwriteConflicts: true } : {}),
83
- });
84
- if (!applied.ok) {
85
- rec.skipped = true;
86
- rec.reason = applied.reason;
87
- if (applied.previous)
88
- rec.previous = applied.previous;
89
- attempts.push(rec);
90
- continue;
72
+ await processPin(rec, { name: adv.name, range: target }, opts, pkgJson, `--apply-overrides`);
73
+ attempts.push(rec);
74
+ }
75
+ // Manual --override pins: processed AFTER advisories so any audit-driven pin that clears a
76
+ // path is visible first. Manual pins share the same install + validator + rollback loop.
77
+ if (opts.manualOverrides && opts.manualOverrides.length > 0) {
78
+ if (!opts.json) {
79
+ log.info(`--override: ${opts.manualOverrides.length} manual pin${opts.manualOverrides.length === 1 ? '' : 's'} to apply`);
91
80
  }
92
- if (!applied.written) {
93
- // No-op (already satisfies). Record as skip but mark ok: true so the summary doesn't
94
- // mistake it for a failure.
95
- rec.skipped = true;
96
- rec.ok = true;
97
- rec.reason = applied.reason ?? 'already satisfies target';
98
- if (applied.applied)
99
- rec.applied = applied.applied;
100
- if (applied.previous)
101
- rec.previous = applied.previous;
81
+ for (const spec of opts.manualOverrides) {
82
+ if (spec.chain.length === 0)
83
+ continue;
84
+ const name = spec.chain[spec.chain.length - 1];
85
+ const parentChain = spec.chain.slice(0, -1);
86
+ const rec = {
87
+ name,
88
+ severity: 'low',
89
+ ids: [],
90
+ field,
91
+ ok: false,
92
+ skipped: false,
93
+ source: 'manual',
94
+ };
95
+ if (spec.chain.length > 1)
96
+ rec.chain = [...spec.chain];
97
+ if (spec.source)
98
+ rec.title = spec.source;
99
+ if (spec.reason)
100
+ rec.policyReason = spec.reason;
101
+ const entry = { name, range: spec.range };
102
+ if (parentChain.length > 0)
103
+ entry.parentChain = parentChain;
104
+ await processPin(rec, entry, opts, pkgJson, `--override`);
102
105
  attempts.push(rec);
103
- continue;
104
106
  }
105
- rec.applied = applied.applied ?? target;
107
+ }
108
+ return { attempts };
109
+ }
110
+ /**
111
+ * Shared write + install + validate + rollback cycle used for BOTH advisory pins and
112
+ * manual pins. Mutates `rec` in place: callers push it into `attempts` regardless of
113
+ * outcome. Returns nothing — every outcome is captured on `rec`.
114
+ */
115
+ async function processPin(rec, entry, opts, pkgJson, logTag) {
116
+ const label = entry.parentChain && entry.parentChain.length > 0
117
+ ? `${[...entry.parentChain, entry.name].join('>')}`
118
+ : entry.name;
119
+ if (opts.dryRun) {
120
+ rec.skipped = true;
121
+ rec.reason = 'dry-run';
122
+ rec.applied = entry.range;
123
+ return;
124
+ }
125
+ const applied = await applyOverrideToFile({
126
+ packageJsonPath: pkgJson,
127
+ manager: opts.manager,
128
+ entry,
129
+ ...(opts.overwriteConflicts ? { overwriteConflicts: true } : {}),
130
+ });
131
+ if (!applied.ok) {
132
+ rec.skipped = true;
133
+ rec.reason = applied.reason;
106
134
  if (applied.previous)
107
135
  rec.previous = applied.previous;
108
- // 2. Install with the new pin.
109
- if (!opts.json) {
110
- log.info(`--apply-overrides: pinning ${adv.name} → ${target} and running ${opts.manager} install`);
111
- }
112
- const install = await runInstall(opts.cwd, opts.manager, {});
113
- if (!install.ok) {
114
- rec.installLog = tailOutput(install);
115
- const rb = await rollback(pkgJson, opts, adv.name);
116
- rec.rolledBack = rb.rolledBack;
117
- rec.reason = `install failed after override (exit ${install.exitCode})`;
118
- attempts.push(rec);
119
- continue;
120
- }
121
- // 3. Validator (when provided).
122
- if (opts.runValidator) {
123
- const v = await opts.runValidator();
124
- if (!v.ok) {
125
- rec.installLog = v.message;
126
- const rb = await rollback(pkgJson, opts, adv.name);
127
- rec.rolledBack = rb.rolledBack;
128
- rec.reason = `validator failed after override: ${v.message ?? 'non-zero exit'}`;
129
- attempts.push(rec);
130
- continue;
131
- }
132
- }
136
+ return;
137
+ }
138
+ if (!applied.written) {
139
+ rec.skipped = true;
133
140
  rec.ok = true;
134
- attempts.push(rec);
135
- if (!opts.json) {
136
- log.success(`--apply-overrides: pinned ${adv.name}@${target} (severity: ${adv.severity})`);
141
+ rec.reason = applied.reason ?? 'already satisfies target';
142
+ if (applied.applied)
143
+ rec.applied = applied.applied;
144
+ if (applied.previous)
145
+ rec.previous = applied.previous;
146
+ return;
147
+ }
148
+ rec.applied = applied.applied ?? entry.range;
149
+ if (applied.previous)
150
+ rec.previous = applied.previous;
151
+ if (!opts.json) {
152
+ log.info(`${logTag}: pinning ${label} → ${entry.range} and running ${opts.manager} install`);
153
+ }
154
+ const installer = opts.installer ?? runInstall;
155
+ const install = await installer(opts.cwd, opts.manager, {});
156
+ if (!install.ok) {
157
+ rec.installLog = tailOutput(install);
158
+ const rb = await rollback(pkgJson, opts, entry);
159
+ rec.rolledBack = rb.rolledBack;
160
+ rec.reason = `install failed after override (exit ${install.exitCode})`;
161
+ return;
162
+ }
163
+ if (opts.runValidator) {
164
+ const v = await opts.runValidator();
165
+ if (!v.ok) {
166
+ if (v.message)
167
+ rec.installLog = v.message;
168
+ const rb = await rollback(pkgJson, opts, entry);
169
+ rec.rolledBack = rb.rolledBack;
170
+ rec.reason = `validator failed after override: ${v.message ?? 'non-zero exit'}`;
171
+ return;
137
172
  }
138
173
  }
139
- return { attempts };
174
+ rec.ok = true;
175
+ if (!opts.json) {
176
+ log.success(`${logTag}: pinned ${label}@${entry.range}`);
177
+ }
140
178
  }
141
179
  /**
142
180
  * Remove the override we just added and re-run install so the workspace ends up in the same
143
- * state the user had at the start of the attempt. Install failures during rollback are logged
181
+ * state the user had at the start of the attempt. The entry's parent chain (if any) is
182
+ * threaded through to `removeOverrideFromFile` so we delete the EXACT slot we wrote and
183
+ * never touch an adjacent flat pin or sibling. Install failures during rollback are logged
144
184
  * but don't crash the flow — the next override attempt will run whatever state we're in.
145
185
  */
146
- async function rollback(pkgJson, opts, name) {
147
- const removed = await removeOverrideFromFile(pkgJson, opts.manager, name);
186
+ async function rollback(pkgJson, opts, entry) {
187
+ const chain = [...(entry.parentChain ?? []), entry.name];
188
+ const label = chain.join('>');
189
+ const removed = await removeOverrideFromFile(pkgJson, opts.manager, { chain });
148
190
  if (!removed.ok || !removed.removed) {
149
191
  return { rolledBack: false, reinstallOk: false };
150
192
  }
151
- const reinstall = await runInstall(opts.cwd, opts.manager, {});
193
+ const installer = opts.installer ?? runInstall;
194
+ const reinstall = await installer(opts.cwd, opts.manager, {});
152
195
  if (!reinstall.ok && !opts.json) {
153
- log.warn(`rollback: re-install after removing override for ${name} exited ${reinstall.exitCode}; workspace may need manual cleanup.`);
196
+ log.warn(`rollback: re-install after removing override for ${label} exited ${reinstall.exitCode}; workspace may need manual cleanup.`);
154
197
  }
155
198
  return { rolledBack: true, reinstallOk: reinstall.ok };
156
199
  }
@@ -1 +1 @@
1
- {"version":3,"file":"overrideFlow.js","sourceRoot":"","sources":["../../src/cli/overrideFlow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"overrideFlow.js","sourceRoot":"","sources":["../../src/cli/overrideFlow.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../src/cli/summary.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgDpD,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,aAAa,CAAC;IACtB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAID;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CActG;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB7B;AAoBD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CA8S/F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAwN3F"}
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../src/cli/summary.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgDpD,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,aAAa,CAAC;IACtB,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAID;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CActG;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB7B;AAoBD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CA4T/F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAwN3F"}
@@ -303,18 +303,31 @@ export function renderSummaryMarkdown(structured, toolVersion) {
303
303
  lines.push(`_wrote to \`${structured.overrides.field}\` — ${ok.length} pinned, ${noOp.length} already safe, ${failed.length} failed._`);
304
304
  lines.push('');
305
305
  if (ok.length > 0) {
306
- lines.push(`| Package | Pinned to | Severity | Advisory |`);
307
- lines.push(`| --- | --- | --- | --- |`);
306
+ // Show the `Reason` column only when at least one pin carries a policy reason — keeps
307
+ // the table narrow for the common advisory-only case.
308
+ const hasReason = ok.some((a) => typeof a.policyReason === 'string' && a.policyReason);
309
+ const header = hasReason
310
+ ? `| Package | Pinned to | Source | Severity | Advisory | Reason |`
311
+ : `| Package | Pinned to | Source | Severity | Advisory |`;
312
+ const sep = hasReason
313
+ ? `| --- | --- | --- | --- | --- | --- |`
314
+ : `| --- | --- | --- | --- | --- |`;
315
+ lines.push(header);
316
+ lines.push(sep);
308
317
  for (const a of ok) {
309
318
  const advCell = a.url && a.ids[0] ? `[${a.ids[0]}](${a.url})` : a.ids[0] ?? '';
310
- lines.push(`| \`${a.name}\` | \`${a.applied ?? '?'}\` | ${a.severity} | ${advCell} |`);
319
+ const label = a.chain && a.chain.length > 1 ? a.chain.join(' ') : a.name;
320
+ const sourceLabel = a.source === 'manual' ? '`--override`' : 'advisory';
321
+ const base = `| \`${label}\` | \`${a.applied ?? '?'}\` | ${sourceLabel} | ${a.severity} | ${advCell} |`;
322
+ lines.push(hasReason ? `${base} ${a.policyReason ?? ''} |` : base);
311
323
  }
312
324
  lines.push('');
313
325
  }
314
326
  if (failed.length > 0) {
315
327
  lines.push(`**Failed overrides** (rolled back):`);
316
328
  for (const a of failed) {
317
- lines.push(`- \`${a.name}\` ${a.reason ?? 'unknown'}`);
329
+ const label = a.chain && a.chain.length > 1 ? a.chain.join(' ') : a.name;
330
+ lines.push(`- \`${label}\` — ${a.reason ?? 'unknown'}`);
318
331
  }
319
332
  lines.push('');
320
333
  }