windowsweep 1.3.1 → 1.4.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.
@@ -3,7 +3,7 @@
3
3
  This is the contract an automated caller can rely on: what windowsweep promises, what it refuses, what it
4
4
  prints, and what it returns. It is written for an agent or a script rather than a person. For what the tool
5
5
  *is*, read the [README](https://github.com/aoneahsan/windowsweep#readme); for what each section touches, read
6
- [Sections 0-25](https://github.com/aoneahsan/windowsweep/blob/main/docs/sections.md).
6
+ [Sections 0-29](https://github.com/aoneahsan/windowsweep/blob/main/docs/sections.md).
7
7
 
8
8
  **windowsweep deletes files.** Every command below that is not marked read-only can remove data. There is no
9
9
  undo for caches. Treat a real run as an irreversible operation and preview it first.
@@ -22,17 +22,17 @@ summary**, and every human-readable line goes to stderr. `--json` also implies `
22
22
 
23
23
  ## What `--yes` covers, and what it never covers
24
24
 
25
- `--yes` auto-confirms **regenerable caches only**: sections 0-3, 5-10, 21, and 12-13 when the console is
25
+ `--yes` auto-confirms **regenerable caches and superseded releases only**: sections 0-3, 5-10, 21, 28, and 12-13 when the console is
26
26
  already elevated.
27
27
 
28
28
  | Never covered by `--yes` | Behaviour |
29
29
  |---|---|
30
- | Sections 17, 18, 19, 23 | The selection prompt appears even with `--yes` and defaults to none. With no console attached nothing is selected, and each asks a final question `--yes` does not answer. Only `--select` / `--select-file` supply a choice (see below) |
31
- | Sections 11, 15, 16, 20 | Deep. Refused in batch mode unless `--i-understand-deep` is also passed |
30
+ | Sections 17, 18, 19, 23, 26, 27 | The selection prompt appears even with `--yes` and defaults to none. With no console attached nothing is selected, and each asks a final question `--yes` does not answer. Only `--select` / `--select-file` supply a choice (see below) |
31
+ | Sections 11, 15, 16, 20, 29 | Deep. Refused in batch mode unless `--i-understand-deep` is also passed |
32
32
  | `--uninstall-data` | Always asks; `--yes` does not answer it |
33
33
  | `--purge-all` | From a console it asks for a typed `purge` once per run. In a batch run `--yes` is the confirmation |
34
34
 
35
- In batch mode (`--all`, `--only`, `--profile`) sections 17, 18, 19 and 23 are refused outright and reported as
35
+ In batch mode (`--all`, `--only`, `--profile`) sections 17, 18, 19, 23, 26 and 27 are refused outright and reported as
36
36
  `refused`, unless a `--select` or `--select-file` choice was supplied. They need a person choosing items -
37
37
  in advance is fine, absent is not.
38
38
 
@@ -133,7 +133,7 @@ answered by a script, so `--elevate` does not belong in an unattended context.
133
133
  - - **Protected paths are refused regardless of flags**: every drive root, fifteen declared roots (Windows, System32, SysWOW64, both Program Files folders, ProgramData, `C:\Users` with Default and Public, the profile root, and the AppData Roaming, Local and LocalLow folders), 66 protected subtrees, 50 path patterns and 13 file names. Two paths are declared exceptions - `%LOCALAPPDATA%\Android\Sdk\.temp` and `.downloadIntermediates` - and there are no others. No flag bypasses any of it.
134
134
  - **Junctions and symlinks are removed as links, never followed.**
135
135
  - **`--dry-run` and `--scan` write nothing** but the log and the report.
136
- - **Section numbers are a public contract.** 0-25 today; a section may be retired as a no-op, and a number is
136
+ - **Section numbers are a public contract.** 0-29 in the 1.4.0 source; a section may be retired as a no-op, and a number is
137
137
  never reused. Read `--list --json` rather than hard-coding the set.
138
138
  - **Zero runtime dependencies.** The package is PowerShell plus a Node launcher that uses only built-in
139
139
  modules.
@@ -144,7 +144,7 @@ answered by a script, so `--elevate` does not belong in an unattended context.
144
144
  local package and the command fails. Run it from anywhere else.
145
145
  - Do not schedule `npx windowsweep` as a task action. The npx cache is evicted and the task breaks; install
146
146
  globally and use `--install-task`, which refuses under npx for this reason.
147
- - Do not pipe `y` into the tool to force a personal section. Sections 17, 18, 19 and 23 are interactive by
147
+ - Do not pipe `y` into the tool to force a personal section. Sections 17, 18, 19, 23, 26 and 27 are interactive by
148
148
  design and a piped answer selects nothing - pass `--select` or `--select-file` instead, which is the
149
149
  supported way and names exactly what goes.
150
150
  - Do not treat a green `--dry-run` as proof that a real run frees the same amount: an app that is open at run
@@ -152,7 +152,7 @@ answered by a script, so `--elevate` does not belong in an unattended context.
152
152
 
153
153
  ## Driving the interactive sections (1.1.0+)
154
154
 
155
- Sections 17, 18, 19 and 23 refuse to run unattended, because they delete things a person should choose. Two
155
+ Sections 17, 18, 19, 23, 26 and 27 refuse to run unattended, because they delete things a person should choose. Two
156
156
  flags supply that choice in advance, and either one lifts the refusal:
157
157
 
158
158
  ```powershell
package/CHANGELOG.md CHANGED
@@ -9,6 +9,97 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ### Added
13
+
14
+ - **Section 26 - uninstall the programs you pick.** It lists the installed programs - never Windows parts,
15
+ runtimes, drivers, hardware software, build kits or patches - and removes the ones you select with their own
16
+ uninstaller, one at a time, silently where the uninstaller has a silent form (MSI, Inno Setup, NSIS, Chromium
17
+ family, WiX bundles, winget, Docker Desktop, Qt, Adobe Creative Cloud, rustup) and in the vendor's own window
18
+ otherwise. A program installed for all users needs an elevated run. After a real uninstall it offers the
19
+ folders the program left for the Recycle Bin. `--yes` never selects here; `--select` or `--select-file` does.
20
+ - **Section 27 - folders uninstalled programs left behind.** It lists the top-level folders in Program Files,
21
+ both Common Files and ProgramData that no installed program, service, driver, PATH or environment entry, Run
22
+ entry, shortcut, scheduled task or running process still uses and that have been idle `--days`, and moves the
23
+ ones you pick to the Recycle Bin. A folder inside a protected location is shown, never removed, and an
24
+ unreadable registry offers nothing. Registered COM servers and type libraries count as use too (shared Office
25
+ and ADO components live in Common Files and are registered only that way), and shared Microsoft folders,
26
+ install caches and hardware-driver folders are never offered. It also lists environment entries that name
27
+ something that no longer exists (report only). Administrator; it joins the elevated walkthrough.
28
+ - **`--json` candidates can carry a `label`.** Section 26's program candidates use the program's uninstall
29
+ registry key as their `path` and its name as `label`; the folders it offers after an uninstall carry
30
+ `leftover: <program>`.
31
+ - **Section 4 also clears what emulators leave behind.** It looks in every folder the emulator may keep AVDs in
32
+ (`ANDROID_AVD_HOME`, `ANDROID_EMULATOR_HOME`, `ANDROID_SDK_HOME`, `ANDROID_PREFS_ROOT`), moves pointer `.ini` files
33
+ whose AVD is gone to the Recycle Bin, and removes system images no remaining AVD uses - and the emulator once no
34
+ AVD is left - with the SDK's own `sdkmanager`. An AVD whose settings name no image keeps every image, and a folder
35
+ an interrupted SDK install left is named for you to remove.
36
+ - **`--browser-profile-roots "P1;P2"` (config `browserProfileRoots`) for section 7.** Folders holding test or
37
+ automation browser profiles: section 7 clears the cache folders of each Chromium profile found in them, and skips
38
+ a profile a running browser holds. Only those cache folders are opened up; the profiles stay protected.
39
+ - **`--temp-roots "P1;P2"` (config `tempRoots`) for section 10.** Folders you use as scratch space: each entry
40
+ nothing wrote for `--temp-days` goes whole, unless a running program's command line names it.
41
+ - **Section 24 shows when each program last ran.** In an elevated run it reads Windows Prefetch and adds a RAN
42
+ column; "none" means no run is on record. File names many programs ship (`uninstall.exe`, `update.exe`,
43
+ `setup.exe`, crash handlers) never count, because Prefetch records a run by file name only.
44
+ - **Section 19 is now a data scanner: large or old personal files.** It lists files in Downloads, and in folders
45
+ you add with `--personal-roots "P1;P2"` (config `personalRoots`), that are large (`--large-file-mb` or more, at
46
+ any age) or old (untouched for `--days`, at any size) - each file once, with its reason, age and the timestamps
47
+ that age came from. A folder is refused as a root when it is a drive root, your profile folder, inside Windows,
48
+ Program Files, ProgramData or AppData, a link, or protected. Removal stays yours: exact files only, never by
49
+ `--yes`, the Recycle Bin by default - and a file that changed after the list was made, or is now reached through a
50
+ link, is refused. File names and paths stay on your machine. `--json` candidates for section 19 add `reason`
51
+ (`large`/`old`/`both`), `age_basis` (`write` or `write+access`), `modified`, `root` and `selectable` (with
52
+ `skip_reason` and `index` 0 for a file that cannot be picked); the summary adds `personal_roots`.
53
+ - **Section 28 - superseded tool releases and old downloaded updates.** Tools that update themselves often keep
54
+ every old release. This removes the superseded ones and keeps the release in use, any newer one and the newest
55
+ older one; a release a running program uses is skipped. It covers Codex standalone releases, Electron updaters
56
+ named without "@" (installers and pending updates idle 7+ days), Ollama's downloaded update and - in developer
57
+ mode, with `--scan-roots` - Node versions no project asks for, removed with nvm itself. It joins `--all` and the
58
+ `dev` and `deep` profiles.
59
+ - **Section 29 - Chrome's on-device AI model.** Chrome downloads a model of several GB and fetches it again if the
60
+ folder is deleted. This sets the `GenAILocalFoundationalModelSettings` policy that stops the download; Chrome
61
+ then removes the model on its next start, and the folder goes at once when Chrome is closed. Chrome shows
62
+ "Managed by your organization" while the policy is set; the section prints the one-line undo. It is a deep,
63
+ administrator section that no batch or profile runs.
64
+
65
+ ### Changed
66
+
67
+ - **Idle age uses write time where last-access is live.** When nearly every file written a week or more ago
68
+ was also "read" in the last day - an indexer, a backup, an antivirus or a disk scanner reading everything -
69
+ last-access says nothing, and the idle gate used to keep every file. Each root is now sampled once; where
70
+ last-access is live, idle age uses write and creation time, the log says so, and `--json` lists those volumes
71
+ in `access_live_volumes`. Everywhere else the rule is unchanged. The sample walks on until it holds enough old
72
+ files, so a folder of mostly new files - a busy temp folder - is judged on its own and the answer no longer
73
+ depends on which section ran first.
74
+ - **More folders are protected roots.** Both Common Files folders and `ProgramData\Microsoft` can never be
75
+ removed as a whole, whatever an installer registered as its own folder.
76
+
77
+ ### Fixed
78
+
79
+ - **`--exclude-path` now also holds inside the tool's own exceptions.** An exception (the Android SDK temp
80
+ folders, and from this release the superseded Codex releases) used to let a path through even when you had
81
+ excluded it.
82
+ - **Section 23 no longer offers folders that still belong to something.** It offered the desktop app's own
83
+ data folder, a Store app's data, an installed program known by its initials, and a tool running from its
84
+ own folder. A reverse-DNS folder name (`com.vendor.app`) is now matched segment by segment, a shared vendor
85
+ stem counts as a claim, a program of three or more words also claims its initials, and the folders in a
86
+ running program's command-line paths count as claimed. The desktop app's install and data folders are
87
+ protected outright.
88
+ - **`--json` is one line again on every run.** Section 12's Delivery Optimization step printed two lines to
89
+ stdout ahead of the JSON document. Its words now go to the log, and the runner discards anything a section
90
+ leaves on its output stream.
91
+
92
+ ## [1.3.2] - 2026-09-28
93
+
94
+ No change to what is cleaned, how it is decided, or what is refused: the engine is 1.3.1's, file for file.
95
+ The version moves so the desktop app and the engine it bundles keep one number, and `desktop-v1.3.2` fixes
96
+ the app's Google sign-in.
97
+
98
+ ### Changed
99
+
100
+ - **The version is 1.3.2, the desktop app's number.** The app bundles this engine and the two keep one number;
101
+ the app's 1.3.2 fixes its Google sign-in. No section, target, flag or protection changed.
102
+
12
103
  ## [1.3.1] - 2026-09-25
13
104
 
14
105
  No change to what is cleaned, how it is decided, or what is refused. This release names the team as the
package/README.md CHANGED
@@ -4,12 +4,11 @@
4
4
 
5
5
  <h1>windowsweep</h1>
6
6
 
7
- <p><strong>Developer-aware Windows cleanup CLI: dry-run first, personal folders refused, zero install via npx.</strong></p>
7
+ <p><strong>Windows cleanup CLI: dry-run first, personal files chosen row by row, zero install via npx.</strong></p>
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/windowsweep.svg)](https://www.npmjs.com/package/windowsweep)
10
10
  [![downloads](https://img.shields.io/npm/dm/windowsweep.svg)](https://www.npmjs.com/package/windowsweep)
11
11
  [![license](https://img.shields.io/npm/l/windowsweep.svg)](https://github.com/aoneahsan/windowsweep/blob/main/LICENSE)
12
- [![ci](https://github.com/aoneahsan/windowsweep/actions/workflows/ci.yml/badge.svg)](https://github.com/aoneahsan/windowsweep/actions/workflows/ci.yml)
13
12
  [![node](https://img.shields.io/node/v/windowsweep.svg)](https://nodejs.org)
14
13
  [![platform](https://img.shields.io/badge/platform-Windows%2010%20%7C%2011-0078d4?logo=windows&logoColor=white)](https://github.com/aoneahsan/windowsweep#platform-support)
15
14
 
@@ -36,14 +35,14 @@ It is the Windows member of a family with [linux-cleanup](https://github.com/aon
36
35
 
37
36
  | | |
38
37
  |---|---|
39
- | **Version** | `1.3.1` |
38
+ | **Version** | `1.4.0` |
40
39
  | **License** | MIT |
41
40
  | **Node** | `>=14` (launcher only) |
42
41
  | **Runtime** | Windows PowerShell 5.1 (built in) or PowerShell 7 |
43
42
  | **Platforms** | Windows 10 (1809+) and Windows 11 |
44
- | **Install size** | ~120 kB packed · ~401 kB unpacked · 46 files · no dependencies |
43
+ | **Install size** | ~167 kB packed · ~560 kB unpacked · 53 files · no dependencies |
45
44
  | **Undo** | Recycle Bin for personal files; none for caches (they regenerate) |
46
- | **Status** | Stable · 1.3.1, released 2026-09-25 |
45
+ | **Status** | Stable · 1.4.0, released 2026-11-03 |
47
46
 
48
47
  <a id="table-of-contents"></a>
49
48
  ## 🧭 Table of Contents&nbsp;[#](#table-of-contents)
@@ -88,7 +87,7 @@ the lot again, and your afternoon is gone. `windowsweep` takes the narrower path
88
87
  |---|---|---|---|
89
88
  | **Knows developer caches** | yarn, npm, pnpm, Gradle, Cypress, Playwright, AVDs, Docker, editors | no | some |
90
89
  | **Default action** | prune files idle 100+ days; keep the newest version of every tool | fixed categories | wipe the whole cache |
91
- | **Personal folders** | hard refusal, no flag bypasses it | out of scope | usually configurable |
90
+ | **Personal folders** | Downloads and folders you add are scanned for large or old files; only chosen files go to the Recycle Bin | out of scope | usually configurable |
92
91
  | **Junctions and symlinks** | never followed | n/a | varies |
93
92
  | **Dry-run** | every section, exact estimate | no | sometimes |
94
93
  | **Unattended use** | `--all --yes`, Scheduled Task | Storage Sense | GUI-first |
@@ -117,7 +116,7 @@ reclaims disk space, nothing else.
117
116
  - check [6] walks every directory and file target and fails if one resolves inside a protected path.
118
117
  - **A dry-run that writes nothing** - `--dry-run` short-circuits every deletion and every destructive command
119
118
  and reports an exact estimate. `--scan` and `--list-targets` are read-only.
120
- - **Personal files go to the Recycle Bin** - partial downloads and large stale files are listed, you pick, and
119
+ - **Personal files go to the Recycle Bin** - partial downloads and large or old files are listed, you pick, and
121
120
  Windows keeps the undo.
122
121
  - **Batch policy** - `--all` runs the safe batch only; deep sections need `--i-understand-deep`; personal
123
122
  sections never run unattended.
@@ -126,7 +125,7 @@ reclaims disk space, nothing else.
126
125
  - **Running-app guard** - an open browser, editor or app keeps its caches; the tool tells you which to close.
127
126
  - **Session reports** - schema-versioned JSON, exportable to Markdown or a self-contained HTML page, plus
128
127
  `--json` for scripts.
129
- - **Self-test** - 156 checks prove the guards on your machine with a real junction, a 445-character path and
128
+ - **Self-test** - 223 checks prove the guards on your machine with a real junction, a path longer than 260 characters and
130
129
  a dry-run fixture before you trust it.
131
130
  - **Offline by design** - the command-line tool makes zero network calls: no telemetry, no update check.
132
131
  Self-test check [9] fails the build on an HTTP or socket call in the source. Crash bundles stay on disk.
@@ -138,7 +137,7 @@ reclaims disk space, nothing else.
138
137
  |---|---|---|
139
138
  | Windows 11 | ✅ | Same engine and PowerShell hosts; a real run on Windows 11 is on the verification list ([project status](https://github.com/aoneahsan/windowsweep/blob/main/docs/features/windowsweep-completion/00-tracker.json)) |
140
139
  | Windows 10 (1809 and later) | ✅ | The primary development target; every real run so far |
141
- | Windows Server 2019+ | ⚠️ | Uses nothing newer than 1809; CI runs the self-test and a dry-run on Windows Server (`windows-latest`) on every push to `main` and every pull request, but no real cleanup has been run on Server |
140
+ | Windows Server 2019+ | ⚠️ | Uses nothing newer than 1809; no real cleanup has been verified on Server |
142
141
  | Linux | ❌ | `os: ["win32"]` makes npm refuse to install; use [linux-cleanup](https://github.com/aoneahsan/linux-cleanup) |
143
142
  | macOS | ❌ | Use [macleanup](https://github.com/aoneahsan/macleanup) |
144
143
 
@@ -202,6 +201,8 @@ section with `a` run / `s` skip / `q` quit and a running total.
202
201
 
203
202
  ### The sections
204
203
 
204
+ This table describes version 1.4.0.
205
+
205
206
  **Tier** says what happens to the data: *report* deletes nothing, *rebuilds* comes back on its own, *slow*
206
207
  comes back but costs minutes, *Recycle Bin* is recoverable until you empty it (`--list` shows this tier as
207
208
  `recycle`), *permanent* is not, *config* changes a setting.
@@ -227,19 +228,23 @@ comes back but costs minutes, *Recycle Bin* is recoverable until you empty it (`
227
228
  | 16 | Clear Windows Event Logs | **permanent** | yes | deep |
228
229
  | 17 | Stale project build artefacts (`node_modules`, `dist`, `.next`, `target`, ...) | rebuilds | - | interactive, developer-gated |
229
230
  | 18 | Partial / orphan downloads | Recycle Bin | - | interactive |
230
- | 19 | Large stale personal files in Downloads | Recycle Bin | - | interactive |
231
+ | 19 | Large or old personal files in Downloads and folders you add | Recycle Bin | - | interactive |
231
232
  | 20 | Docker Desktop / WSL disk-image compaction | config | yes | deep, developer-gated |
232
233
  | 21 | Disk usage report | report | - | safe |
233
234
  | 22 | Global packages audit (npm, pnpm, yarn, bun, deno) - never uninstalls | report | - | safe · audit only |
234
235
  | 23 | Orphaned application data under AppData | Recycle Bin | - | interactive |
235
236
  | 24 | Installed programs not modified for N+ days - never uninstalls | report | - | safe · audit only |
236
237
  | 25 | Startup items audit - never changes them | report | - | safe · audit only |
238
+ | 26 | Uninstall programs you pick | **permanent** | per program | interactive |
239
+ | 27 | Leftover program folders | Recycle Bin | yes | interactive |
240
+ | 28 | Superseded tool releases | rebuilds | - | safe |
241
+ | 29 | Chrome on-device AI model policy | config | yes | deep |
237
242
 
238
243
  *Safe* sections run in `--all`; *opt-in* ones run when named in `--only` or a profile; *deep* ones also need
239
244
  `--i-understand-deep`; *interactive* ones never run unattended unless you pass a selection. The three
240
245
  *audit only* sections are read-only and safe, but stay out of `--all` so a cleanup run is a cleanup run -
241
246
  `--profile audit` is where they live. Every section is documented in
242
- [Sections 0-25](https://windowsweep-docs.aoneahsan.com/sections).
247
+ [Sections 0-29](https://windowsweep-docs.aoneahsan.com/sections).
243
248
 
244
249
  ### Reclaim interactively
245
250
 
@@ -308,17 +313,20 @@ windowsweep [mode] [options]
308
313
  |---|---|---|
309
314
  | `--dry-run` | off | Delete nothing; show what would go and how much it frees |
310
315
  | `-y`, `--yes` | off | Auto-confirm regenerable caches. Never personal files |
311
- | `--i-understand-deep` | off | Allow sections 11, 15, 16, 20 unattended (with `--yes`) |
316
+ | `--i-understand-deep` | off | Allow sections 11, 15, 16, 20, 29 unattended (with `--yes`) |
312
317
  | `--elevate` | off | Relaunch elevated through a UAC prompt |
313
318
  | `-d N`, `--days N` | `100` | Idle window: a file goes when its newest timestamp is N+ days old |
314
319
  | `--temp-days N` | `3` | Idle window for temp folders |
315
320
  | `--purge-all` | off | 🔥 Clear cache targets completely instead of pruning idle files |
316
321
  | `--developer`, `--not-developer`, `--forget-developer` | saved answer | Override or re-ask the developer question |
317
322
  | `--scan-roots "P1;P2"` | auto | Section 17 project roots |
323
+ | `--personal-roots "P1;P2"` | Downloads only | Extra section 19 folders; explicit empty keeps Downloads only |
324
+ | `--browser-profile-roots "P1;P2"` | none | Cache leaves inside declared automation browser profiles |
325
+ | `--temp-roots "P1;P2"` | none | Idle scratch-folder entries |
318
326
  | `--exclude-path P` | - | A tree to leave alone, in **every** section (repeatable) |
319
327
  | `--hiberfil off\|reduced\|keep` | ask | What section 15 does |
320
- | `--permanent` | off | Sections 18, 19 and 23 delete instead of using the Recycle Bin |
321
- | `--select L`, `--select-file P` | off | Answer an interactive section's selection in advance, by index or by path - the one way sections 17/18/19/23 run unattended |
328
+ | `--permanent` | off | Sections 18 and 23 delete instead of using the Recycle Bin; section 19 always recycles selected personal files |
329
+ | `--select L`, `--select-file P` | off | Answer an interactive section's selection in advance; section 19 requires exact paths in `--select-file` |
322
330
  | `--notify` | off | A Windows notification when the run ends |
323
331
  | `--json`, `--quiet`, `--no-color`, `--ascii`, `--no-report`, `--cleanup-logs` | off | Output and record controls |
324
332
 
@@ -396,9 +404,8 @@ More: [Troubleshooting](https://windowsweep-docs.aoneahsan.com/troubleshooting).
396
404
  Bin instead.
397
405
  - **Windows only.** Linux and macOS are blocked at install and at launch.
398
406
  - **It cannot promise a number.** `--scan` measures your disk; the README will not guess.
399
- - **The idle gate is conservative.** Windows keeps last-access times off on most volumes, so the tool reads the
400
- newest of write, access and creation time - a file can only look fresher than it is, never older. Some old
401
- caches survive the default window; `--days` and `--purge-all` exist for that.
407
+ - **The idle gate checks each volume.** Where last-access is live it uses write and creation time; elsewhere
408
+ it uses the newest of write, access and creation. `--days` and `--purge-all` change how much is offered.
402
409
  - **Admin sections need an elevated console** and a UAC click; a Scheduled Task runs the safe batch only.
403
410
  - **Disk Cleanup (section 13) cannot preview sizes.** Its dry-run names the handlers it would run and nothing more.
404
411
  - **No automated test suite beyond `--self-test`.** Correctness rests on the self-test's fixtures, dry-runs and
@@ -439,7 +446,7 @@ More: [FAQ](https://windowsweep-docs.aoneahsan.com/faq).
439
446
  | [Quick start](https://windowsweep-docs.aoneahsan.com/quick-start) | running your first cleanup |
440
447
  | [Safety model](https://windowsweep-docs.aoneahsan.com/safety-model) | you want every guarantee spelled out before deleting anything |
441
448
  | [Developer mode](https://windowsweep-docs.aoneahsan.com/developer-mode) | you want to know what the first question changes |
442
- | [Sections 0-25](https://windowsweep-docs.aoneahsan.com/sections) | you want to know precisely what one section touches |
449
+ | [Sections 0-29](https://windowsweep-docs.aoneahsan.com/sections) | you want to know precisely what one section touches |
443
450
  | [CLI reference](https://windowsweep-docs.aoneahsan.com/cli-reference) | you need an exact flag, exit code or variable |
444
451
  | [Admin sections and elevation](https://windowsweep-docs.aoneahsan.com/admin-and-elevation) | before running the system profile or touching the hibernation file |
445
452
  | [Reports and logs](https://windowsweep-docs.aoneahsan.com/reports-and-logs) | parsing the JSON or finding a log |
@@ -451,18 +458,8 @@ More: [FAQ](https://windowsweep-docs.aoneahsan.com/faq).
451
458
  <a id="changelog"></a>
452
459
  ## 🔄 Changelog&nbsp;[#](#changelog)
453
460
 
454
- Latest release: **`1.3.1`** - nothing about what is cleaned, how it is decided or what is refused changed.
455
- The tool names the windowsweep team as its maker instead of one person, and the web address it prints is the
456
- product's own site.
457
-
458
- Before it, **`1.3.0`** - the documentation address the tool carries became the documentation site, two files
459
- that had grown past the project's own 500-line ceiling were split (the deletion chokepoint stayed exactly where
460
- it was), and the at-a-glance rows inside the published package were corrected.
461
-
462
- Before that, **`1.2.0`** - `--exclude-path` honoured in every section at the deletion chokepoint (it
463
- protected one section out of twenty-six, and never a folder's children), a dry-run that counts exactly what a
464
- real run removes, `newest_write_utc` on every scanned target, `protected` in `--list --json`, `excluded[]` in
465
- the summary, and the console and report strings in one voice.
461
+ Latest release: **`1.4.0`** - scan Downloads and folders you add for large or old files, then choose individual
462
+ files for the Recycle Bin. The new uninstall and leftover-folder sections also require explicit selection.
466
463
  Full history: [CHANGELOG.md](https://github.com/aoneahsan/windowsweep/blob/main/CHANGELOG.md).
467
464
 
468
465
  <a id="contributing"></a>
package/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.1
1
+ 1.4.0
package/lib/actions.ps1 CHANGED
@@ -106,6 +106,19 @@ function Test-KnownCacheLeaf {
106
106
  return ($known -contains [IO.Path]::GetFileName($Path))
107
107
  }
108
108
 
109
+ function Add-CacheLeafExceptions {
110
+ <# .SYNOPSIS D79 (1.4.0): lift the protected lists (lib/safety.ps1) for EXACTLY these folders, each of which must
111
+ carry a declared cache folder's name - never a profile, an app root or a protected root. Returns the count. #>
112
+ param([string[]] $Paths)
113
+ $pr = $Script:WS_PROTECT; $n = 0
114
+ foreach ($x in @($Paths)) {
115
+ $f = Get-FullPath $x
116
+ if (-not $f -or $pr.Exact.Contains($f) -or -not (Test-KnownCacheLeaf $f) -or $pr.Exceptions -contains $f) { continue }
117
+ $pr.Exceptions = @($pr.Exceptions) + $f; $pr.ExceptionPrefixes = @($pr.ExceptionPrefixes) + ($f + '\'); $n++
118
+ }
119
+ return $n
120
+ }
121
+
109
122
  function Invoke-TargetList {
110
123
  <# .SYNOPSIS Run every target with its mode under the dry-run, developer, purge and running-app policies. Returns bytes freed/estimated. #>
111
124
  param([pscustomobject[]] $Targets)
package/lib/config.ps1 CHANGED
@@ -10,6 +10,9 @@ function Get-DefaultConfig {
10
10
  largeFileMb = 100
11
11
  scanRoots = @()
12
12
  excludePaths = @()
13
+ browserProfileRoots = @()
14
+ tempRoots = @()
15
+ personalRoots = @()
13
16
  welcomed = $false
14
17
  }
15
18
  }
@@ -28,6 +31,7 @@ function Import-Config {
28
31
  }
29
32
  if ($null -eq $cfg.scanRoots) { $cfg.scanRoots = @() }
30
33
  if ($null -eq $cfg.excludePaths) { $cfg.excludePaths = @() }
34
+ foreach ($k in 'browserProfileRoots', 'tempRoots', 'personalRoots') { if ($null -eq $cfg[$k]) { $cfg[$k] = @() } }
31
35
  } catch {
32
36
  Write-Warn "config file unreadable, using defaults: $path ($($_.Exception.Message))"
33
37
  }
package/lib/constants.ps1 CHANGED
@@ -4,10 +4,10 @@
4
4
  # Single source of truth for the version is package.json: the Node launcher exports it as
5
5
  # WINDOWSWEEP_VERSION. A direct checkout falls back to this literal; the version:check script
6
6
  # asserts the two never drift.
7
- $Script:WS_VERSION_FALLBACK = '1.3.1'
7
+ $Script:WS_VERSION_FALLBACK = '1.4.0'
8
8
 
9
9
  $Script:WS_NAME = 'windowsweep'
10
- $Script:WS_TAGLINE = 'Developer-aware Windows cleanup CLI: dry-run first, personal folders refused, zero install via npx.'
10
+ $Script:WS_TAGLINE = 'Windows cleanup CLI: dry-run first, personal files chosen row by row, zero install via npx.'
11
11
  # The maker is the team, never one person. WS_AUTHOR lands mid-line ("by the windowsweep team");
12
12
  # WS_TEAM is the form a label shows standing alone ("Author: The windowsweep team").
13
13
  $Script:WS_AUTHOR = 'the windowsweep team'
@@ -63,31 +63,35 @@ $Script:WS_SECTIONS = @(
63
63
  @{ Id = 16; Key = 'eventlogs'; Title = 'Clear Windows Event Logs - PERMANENT'; Tier = 'permanent'; Admin = $true; Batch = 'deep'; Dev = $false; Fn = 'Invoke-Section16' }
64
64
  @{ Id = 17; Key = 'projects'; Title = 'Stale project build artefacts (node_modules, dist, .next, target, ...)'; Tier = 'rebuilds'; Admin = $false; Batch = 'interactive'; Dev = $true; Fn = 'Invoke-Section17' }
65
65
  @{ Id = 18; Key = 'partials'; Title = 'Partial / orphan downloads -> Recycle Bin'; Tier = 'recycle'; Admin = $false; Batch = 'interactive'; Dev = $false; Fn = 'Invoke-Section18' }
66
- @{ Id = 19; Key = 'large'; Title = 'Large stale personal files (Downloads) -> Recycle Bin'; Tier = 'recycle'; Admin = $false; Batch = 'interactive'; Dev = $false; Fn = 'Invoke-Section19' }
66
+ @{ Id = 19; Key = 'large'; Title = 'Large or old personal files (Downloads and folders you add) -> Recycle Bin'; Tier = 'recycle'; Admin = $false; Batch = 'interactive'; Dev = $false; Fn = 'Invoke-Section19' }
67
67
  @{ Id = 20; Key = 'vhdx'; Title = 'Docker Desktop / WSL disk image compaction (stops Docker + WSL)'; Tier = 'config'; Admin = $true; Batch = 'deep'; Dev = $true; Fn = 'Invoke-Section20' }
68
68
  @{ Id = 21; Key = 'diskusage'; Title = 'Disk usage report (largest entries, drives, disk images)'; Tier = 'report'; Admin = $false; Batch = 'safe'; Dev = $false; Fn = 'Invoke-Section21' }
69
69
  @{ Id = 22; Key = 'globals'; Title = 'Globally installed packages audit (npm, pnpm, yarn, bun, deno) - report only'; Tier = 'report'; Admin = $false; Batch = 'safe'; Dev = $false; Fn = 'Invoke-Section22' }
70
70
  @{ Id = 23; Key = 'orphaned'; Title = 'Orphaned application data under AppData -> Recycle Bin'; Tier = 'recycle'; Admin = $false; Batch = 'interactive'; Dev = $false; Fn = 'Invoke-Section23' }
71
71
  @{ Id = 24; Key = 'programs'; Title = 'Installed programs not modified for N+ days - report only'; Tier = 'report'; Admin = $false; Batch = 'safe'; Dev = $false; Fn = 'Invoke-Section24' }
72
72
  @{ Id = 25; Key = 'startup'; Title = 'Startup items audit (Run keys, Startup folders, logon tasks) - report only'; Tier = 'report'; Admin = $false; Batch = 'safe'; Dev = $false; Fn = 'Invoke-Section25' }
73
+ @{ Id = 26; Key = 'uninstall'; Title = 'Uninstall programs you pick, each with its own uninstaller, then the folders they left -> Recycle Bin'; Tier = 'permanent'; Admin = $false; Batch = 'interactive'; Dev = $false; Fn = 'Invoke-Section26' }
74
+ @{ Id = 27; Key = 'leftovers'; Title = 'Folders uninstalled programs left in Program Files, Common Files and ProgramData -> Recycle Bin'; Tier = 'recycle'; Admin = $true; Batch = 'interactive'; Dev = $false; Fn = 'Invoke-Section27' }
75
+ @{ Id = 28; Key = 'releases'; Title = 'Superseded tool releases and old downloaded updates (Codex, Electron updaters, Ollama, unrequested Node) - current kept'; Tier = 'rebuilds'; Admin = $false; Batch = 'safe'; Dev = $false; Fn = 'Invoke-Section28' }
76
+ @{ Id = 29; Key = 'browserai'; Title = 'Chrome on-device AI model - set the policy that removes it (Chrome shows "Managed by your organization")'; Tier = 'config'; Admin = $true; Batch = 'deep'; Dev = $false; Fn = 'Invoke-Section29' }
73
77
  )
74
78
 
75
79
  # The safe batch run by --all. Admin sections 12 and 13 join it only when already elevated.
76
- $Script:WS_SAFE_BATCH = @(0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 21)
80
+ $Script:WS_SAFE_BATCH = @(0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 21, 28)
77
81
  $Script:WS_SAFE_BATCH_ADMIN = @(12, 13)
78
82
 
79
83
  $Script:WS_PROFILES = @{
80
- 'dev' = @(1, 2, 3, 4, 5, 6, 17)
84
+ 'dev' = @(1, 2, 3, 4, 5, 6, 17, 28)
81
85
  'minimal' = @(7, 8, 9, 10)
82
86
  'cache-only' = @(1, 2, 3, 6, 7, 8, 9)
83
87
  'system' = @(12, 13, 14)
84
- 'deep' = @(0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 21)
88
+ 'deep' = @(0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 21, 28)
85
89
  'audit' = @(0, 21, 22, 24, 25)
86
90
  }
87
91
 
88
92
  # Walkthrough order (interactive default mode). Admin sections are inserted when elevated.
89
- $Script:WS_WALKTHROUGH = @(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, 18, 19, 23)
90
- $Script:WS_WALKTHROUGH_ADMIN = @(12, 13, 14)
93
+ $Script:WS_WALKTHROUGH = @(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 28, 11, 17, 18, 19, 23)
94
+ $Script:WS_WALKTHROUGH_ADMIN = @(12, 13, 14, 27)
91
95
 
92
96
  function Get-Section {
93
97
  <# .SYNOPSIS Returns the catalogue entry for a section id, or $null. #>
package/lib/external.ps1 CHANGED
@@ -70,15 +70,28 @@ function Test-CanElevate {
70
70
  function Invoke-Elevated {
71
71
  <# .SYNOPSIS Relaunch this run elevated (UAC prompt) and wait for it. Returns the child's exit code. #>
72
72
  $ws = $Script:WS
73
+ $summaryPath = $null
74
+ if ($ws.JsonMode) {
75
+ $token = [guid]::NewGuid().ToString('N')
76
+ $summaryPath = Join-Path $ws.ReportsDir ("elevated-summary-$token.json")
77
+ }
73
78
  $childArgs = @('-NoProfile', '-NoLogo', '-ExecutionPolicy', 'Bypass', '-File', ('"' + $ws.ScriptPath + '"'))
74
79
  foreach ($a in $ws.RawArgs) {
75
80
  if ($a -eq '--elevate') { continue }
76
81
  if ($a -match '[\s"]') { $childArgs += ('"' + ($a -replace '"', '\"') + '"') } else { $childArgs += $a }
77
82
  }
78
83
  $childArgs += '--elevated-child'
84
+ if ($summaryPath) { $childArgs += @('--elevated-summary-token', $token) }
79
85
  Write-Info 'Requesting elevation (a UAC prompt appears). The elevated run opens in a new window and writes its own log.'
80
86
  try {
81
87
  $proc = Start-Process -FilePath 'powershell.exe' -ArgumentList $childArgs -Verb RunAs -Wait -PassThru
88
+ if ($summaryPath -and (Test-Path -LiteralPath $summaryPath)) {
89
+ try {
90
+ $json = [IO.File]::ReadAllText($summaryPath).Trim()
91
+ $null = $json | ConvertFrom-Json -ErrorAction Stop
92
+ [Console]::Out.WriteLine($json)
93
+ } finally { Remove-Item -LiteralPath $summaryPath -Force -ErrorAction SilentlyContinue }
94
+ }
82
95
  return $proc.ExitCode
83
96
  } catch {
84
97
  Write-Err "elevation refused or failed: $($_.Exception.Message)"