Skip to content

Commit 2cca02e

Browse files
committed
docs(scan): document --prune/--sync/--dry-run + un-deprecate gc
CLI_CONTRACT.md: * Scan flag table: replace --no-prune row with three new rows — --prune, --sync, -d/--dry-run. Add a paragraph explaining each plus the canonical bot-mode invocation. * JSON output shape: drop the --no-prune-emits-{skipped:true} note. Clarify that `gc` is omitted ENTIRELY when --prune/--sync isn't set. Document --dry-run behavior including the explicit `apply.dryRun: true` marker for bots. * New "scan — --sync (bot mode)" section with the canonical `scan --json --sync --yes | jq '{applied, pruned, bytes_freed}'` recipe. * New "scan — --dry-run" section explaining that --dry-run is a no-op without one of the mutating flags. * Restore the `repair` section's normal heading (drop the "*(deprecated since v3.0)*" suffix and the deprecation paragraph). Note that the `gc` visible_alias is now contract-guarded. * Semver-policy table: drop the GC-default row, add explicit rows for "flipping --prune to opt-out" and "demoting `gc` from visible_alias" — both MAJOR. README.md: * Restore the `### repair` / `gc` section that was removed during the deprecation iteration. Wording clarifies that `repair`/`gc` is the right answer for cleanup-without-apply and points users at `scan --sync` for the combined workflow. * `### scan` section: replace --no-prune row with --prune, --sync, --dry-run, --yes. Bot-mode example becomes `scan --json --sync --yes` (the user's "one or two flags" target). Add a `scan --json --sync --yes --dry-run` example. * `## Scripting & CI/CD`: lead with the new `--sync` recipe piped through jq into `peter-evans/create-pull-request`. Keep the old `scan --json --ecosystems npm` read-only example as the second use case. Assisted-by: Claude Code:claude-opus-4-7
1 parent a900519 commit 2cca02e

2 files changed

Lines changed: 97 additions & 24 deletions

File tree

README.md

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ socket-patch get CVE-2024-12345 --json -y
137137

138138
### `scan`
139139

140-
Scan installed packages for available security patches. Since v3.0 `scan` is the single command bots need: it discovers patches, optionally applies them, and garbage-collects orphan blob files plus manifest entries for uninstalled packages.
140+
Scan installed packages for available security patches. Since v3.0 `scan --sync` is the single command bots need for full auto-update: it discovers patches, applies them, and garbage-collects orphan blob files plus manifest entries for uninstalled packages — all in one invocation.
141141

142142
**Usage:**
143143
```bash
@@ -148,7 +148,9 @@ socket-patch scan [options]
148148
| Flag | Description |
149149
|------|-------------|
150150
| `--apply` | Download and apply selected patches in JSON mode (non-interactive). Without it, `scan --json` is read-only. |
151-
| `--no-prune` | Disable garbage collection. By default `scan` removes manifest entries for uninstalled packages and orphan blob/diff/package-archive files. |
151+
| `--prune` | Garbage-collect after the scan: remove manifest entries for uninstalled packages and orphan blob/diff/package-archive files. Off by default. |
152+
| `--sync` | Sugar for `--apply --prune`. The canonical bot-mode flag. |
153+
| `-d, --dry-run` | Preview what `--apply`/`--prune`/`--sync` would do without mutating disk. |
152154
| `--org <slug>` | Organization slug |
153155
| `--json` | Output results as JSON |
154156
| `-y, --yes` | Skip confirmation prompts |
@@ -166,14 +168,20 @@ socket-patch scan [options]
166168
# Scan local project (interactive prompt to apply)
167169
socket-patch scan
168170

169-
# Scan with JSON output (read-only: discover + updates + GC preview)
171+
# Scan with JSON output (discover + updates, no mutation)
170172
socket-patch scan --json
171173

172174
# Bot mode: discover, apply, prune, sweep — all in one
173-
socket-patch scan --json --apply --yes
175+
socket-patch scan --json --sync --yes
174176

175-
# Apply without pruning (preserve manifest entries for uninstalled packages)
176-
socket-patch scan --apply --yes --no-prune
177+
# Apply without pruning manifest entries (default)
178+
socket-patch scan --apply --yes
179+
180+
# Apply + prune explicitly (equivalent to --sync)
181+
socket-patch scan --json --apply --prune --yes
182+
183+
# Preview a full sync without mutating disk
184+
socket-patch scan --json --sync --yes --dry-run
177185

178186
# Scan only npm packages
179187
socket-patch scan --ecosystems npm
@@ -347,6 +355,45 @@ socket-patch remove "pkg:npm/lodash@4.17.20" --skip-rollback
347355
socket-patch remove "pkg:npm/lodash@4.17.20" --json
348356
```
349357

358+
### `repair`
359+
360+
Download missing blobs and clean up unused blobs.
361+
362+
Alias: `gc`
363+
364+
`repair` cleans up the `.socket/` directory without running a scan — useful when you've manually adjusted the manifest, recovered from a partial-failure state, or just want to free space. For the combined workflow (discover + apply + GC in one pass), use `scan --sync --json --yes` instead.
365+
366+
**Usage:**
367+
```bash
368+
socket-patch repair [options]
369+
```
370+
371+
**Options:**
372+
| Flag | Description |
373+
|------|-------------|
374+
| `-d, --dry-run` | Show what would be done without doing it |
375+
| `--offline` | Skip network operations (cleanup only) |
376+
| `--download-only` | Only download missing blobs, do not clean up |
377+
| `--json` | Output results as JSON |
378+
| `-m, --manifest-path <path>` | Path to manifest (default: `.socket/manifest.json`) |
379+
| `--cwd <dir>` | Working directory (default: `.`) |
380+
| `--download-mode <mode>` | `file` (default), `diff`, or `package` |
381+
382+
**Examples:**
383+
```bash
384+
# Full repair (download missing + clean up unused)
385+
socket-patch repair
386+
387+
# Cleanup only, no downloads
388+
socket-patch repair --offline
389+
390+
# Download missing blobs only
391+
socket-patch repair --download-only
392+
393+
# JSON output for scripting
394+
socket-patch repair --json
395+
```
396+
350397
### `setup`
351398

352399
Configure `package.json` postinstall scripts to automatically apply patches after `npm install`.
@@ -384,10 +431,18 @@ socket-patch setup --json -y
384431
All commands support `--json` for machine-readable output. JSON responses always include a `"status"` field for easy error detection:
385432

386433
```bash
387-
# Check for available patches in CI
434+
# Check for available patches in CI (read-only)
388435
result=$(socket-patch scan --json --ecosystems npm)
389436
patches=$(echo "$result" | jq '.totalPatches')
390437

438+
# Auto-update bot mode: discover, apply, prune, sweep in one pass
439+
socket-patch scan --json --sync --yes | jq '{
440+
applied: [.apply.patches[] | select(.action == "added" or .action == "updated") | .purl],
441+
pruned: .gc.prunedManifestEntries,
442+
bytes_freed: .gc.bytesFreed
443+
}'
444+
# Pipe this into peter-evans/create-pull-request to open a PR with the changes.
445+
391446
# Apply patches and check result
392447
socket-patch apply --json | jq '.status'
393448
# "success", "partial_failure", "no_manifest", or "error"

crates/socket-patch-cli/CLI_CONTRACT.md

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,17 @@ The hidden alias `--no-apply` on `--save-only` is **part of the contract** — i
8484
| `--ecosystems` || (none) | CSV → `Vec<String>` |
8585
| `--download-mode` || **`diff`** | string |
8686
| `--apply` || `false` | bool |
87-
| `--no-prune` || `false` | bool |
87+
| `--prune` || `false` | bool |
88+
| `--sync` || `false` | bool |
89+
| `--dry-run` | `-d` | `false` | bool |
90+
91+
`--apply` opts JSON callers into the full discover → select → apply pipeline. Without it, `scan --json` stays read-only (discovery + `updates` array only). No effect outside `--json` mode — the non-JSON path always prompts the user interactively. Designed for unattended workflows (cron jobs, bots that open PRs).
8892

89-
`--apply` opts JSON callers into the full discover → select → apply pipeline. Without it, `scan --json` stays read-only (discovery + `updates` array + `gc` preview only). No effect outside `--json` mode — the non-JSON path always prompts the user interactively. Designed for unattended workflows (cron jobs, bots that open PRs).
93+
`--prune` opts into garbage collection. When set, `scan` removes manifest entries for packages no longer present in the crawl, then deletes orphan blob, diff, and package-archive files from `.socket/`. Off by default (v3.0) so a temporary uninstall doesn't silently destroy manifest state. Pair with `--apply` (or use `--sync`) for the auto-update workflow.
9094

91-
`--no-prune` disables garbage collection. By default (since v3.0) `scan` removes manifest entries for packages no longer present in the crawl and deletes orphan blob, diff, and package-archive files from `.socket/`. Pass `--no-prune` to leave the manifest and `.socket/` directory untouched.
95+
`--sync` is sugar for `--apply --prune` — the canonical single-flag bot invocation. `scan --json --sync --yes` discovers, applies, and reconciles state in one pass.
96+
97+
`--dry-run` (`-d`) previews what `--apply` / `--prune` / `--sync` would do without mutating disk. In JSON mode, `apply.patches[*]` is populated with would-be actions (computed via `decide_patch_action` against the current manifest) and `gc.prunable*` / `gc.orphan*` fields report counts via the cleanup helpers' built-in dry-run mode. No effect without at least one of `--apply`, `--prune`, or `--sync`.
9298

9399
### `list`
94100

@@ -121,9 +127,9 @@ Required positional `identifier`. Flags:
121127
| `--yes` | `-y` | `false` | bool |
122128
| `--json` || `false` | bool |
123129

124-
### `repair` *(deprecated since v3.0)*
130+
### `repair`
125131

126-
`scan` now performs garbage collection by default (manifest pruning + orphan file cleanup); prefer `scan` or `scan --no-prune`. `repair` and its `gc` alias remain available for direct invocation but no longer appear in `socket-patch --help`. The subcommand itself is hidden via `clap`'s `hide = true`, and `gc` is demoted from `visible_alias` to `alias`. **Removing `repair` entirely or unhiding it requires a MAJOR bump.**
132+
`repair` (alias `gc`) is a first-class command for cleaning up the `.socket/` directory without running a scan. For the combined discover-and-apply workflow with GC, use `scan --sync --json --yes`; for cleanup alone, use `repair` (or `gc`) directly. The `gc` visible alias is part of the contract — removing or demoting it is a MAJOR bump.
127133

128134
| Long | Short | Default | Type |
129135
|---|---|---|---|
@@ -241,24 +247,17 @@ When `--json` is set, commands print a single JSON object to stdout. The schemas
241247
],
242248
"updates": [
243249
{ "purl": "pkg:npm/foo@1.0", "oldUuid": "<previous>", "newUuid": "<newest>" }
244-
],
245-
"gc": {
246-
"prunableManifestEntries": ["pkg:npm/uninstalled@1.0"],
247-
"orphanBlobs": 3,
248-
"orphanDiffArchives": 1,
249-
"orphanPackageArchives": 0,
250-
"bytesReclaimable": 8421
251-
}
250+
]
252251
}
253252
```
254253

255254
The `updates` array lists PURLs where the newest available patch UUID differs from the one currently recorded in `.socket/manifest.json`. Bots use this to drive "what would change" summaries without mutating anything.
256255

257-
The `gc` sub-object in read-only mode is a *preview*: it reports what `scan --apply` *would* prune and clean up, without touching disk. When `scan` runs with no crawl results (e.g., empty project, `node_modules` missing), GC is intentionally skipped and `gc` is emitted as `{ "skipped": true }` to prevent destroying a manifest the user may still want.
256+
**The `gc` sub-object is omitted entirely when `--prune` (or `--sync`) is not set.** GC information is opt-in — `scan --json` alone is purely about patch discovery and update detection.
258257

259258
### `scan``--apply` mode
260259

261-
When invoked as `scan --json --apply`, the discovery object above is augmented with a top-level `apply` sub-object reporting per-patch outcomes from the download + manifest write, and the `gc` sub-object switches from preview to actual results:
260+
When invoked as `scan --json --apply`, the discovery object above is augmented with a top-level `apply` sub-object reporting per-patch outcomes from the download + manifest write. The `gc` sub-object is added only when `--prune` (or `--sync`, which implies it) is also set:
262261

263262
```json
264263
{
@@ -290,7 +289,25 @@ When invoked as `scan --json --apply`, the discovery object above is augmented w
290289
}
291290
```
292291

293-
With `--no-prune`, the `gc` sub-object is emitted as `{ "skipped": true }` in both read-only and `--apply` modes. GC field names differ between preview (`prunable*`/`orphan*`/`bytesReclaimable`) and apply (`pruned*`/`removed*`/`bytesFreed`) modes — bots should check `gc.prunedManifestEntries` vs `gc.prunableManifestEntries` accordingly.
292+
Without `--prune` or `--sync`, the `gc` field is **omitted entirely** from the output. When `--prune` is set without `--dry-run`, `gc` uses the apply-mode field names (`prunedManifestEntries`, `removedBlobs`, `removedDiffArchives`, `removedPackageArchives`, `bytesFreed`). With `--dry-run`, it uses preview-mode field names (`prunableManifestEntries`, `orphanBlobs`, `orphanDiffArchives`, `orphanPackageArchives`, `bytesReclaimable`) and nothing is mutated. Bots should branch on which field set is present, not assume a single shape.
293+
294+
### `scan``--sync` (bot mode)
295+
296+
`scan --json --sync --yes` is sugar for `scan --json --apply --prune --yes` — the canonical single-command auto-update workflow. Output is the full discovery + `apply` + `gc` shape above. Pipe it into PR-creation tooling:
297+
298+
```bash
299+
socket-patch scan --json --sync --yes | jq '{
300+
applied: [.apply.patches[] | select(.action == "added" or .action == "updated") | .purl],
301+
pruned: .gc.prunedManifestEntries,
302+
bytes_freed: .gc.bytesFreed
303+
}'
304+
```
305+
306+
Exit `0` on success, `1` if any `apply.patches[*].action == "failed"` (top-level `status` becomes `"partial_failure"`).
307+
308+
### `scan``--dry-run`
309+
310+
When combined with `--apply`, `--prune`, or `--sync`, `--dry-run` (`-d`) populates `apply.patches[*]` and `gc.prunable*` / `gc.orphan*` fields with the *would-be* actions without touching disk. The `apply` sub-object in dry-run mode includes a `"dryRun": true` field for bots that need an explicit signal. Without one of the mutating flags, `--dry-run` is a no-op (discovery is already non-mutating).
294311

295312
Per-patch `action` vocabulary is stable:
296313

@@ -327,7 +344,8 @@ Versioning lives in **`Cargo.toml`** at the workspace root (`version = "..."`) a
327344
| Rename a JSON output key or change a `status` string | **MAJOR** |
328345
| Remove a JSON output key | **MAJOR** |
329346
| Rename or remove a per-patch `action` value (`added`/`updated`/`skipped`/`failed`) | **MAJOR** |
330-
| Change `scan`'s default behavior (e.g. pruning, GC, apply) | **MAJOR** — done once in v3.0; future flips also MAJOR. |
347+
| Change `scan`'s default behavior (e.g. flipping `--prune` to opt-out, or making `--apply` default) | **MAJOR** |
348+
| Demote `repair`'s `gc` from `visible_alias` to hidden, or remove the `repair` subcommand | **MAJOR** |
331349
| Drop the bare-UUID fallback | **MAJOR** |
332350
| Add a *required* new flag | **MAJOR** |
333351
| Add a new subcommand | **MINOR** |

0 commit comments

Comments
 (0)