Skip to content

Releases: CaseReed/wincleaner

WinCleaner v0.10.1

Choose a tag to compare

@github-actions github-actions released this 12 Sep 22:52

Fixed

  • Force-closing a browser now only touches that browser, in this session.
    The second pass, the one that catches whatever outlived the main process,
    used to terminate any pid from the list that was still a live process —
    and Windows hands pid numbers straight back out, with three seconds of
    waiting for it to happen. It now re-lists the browser by name and keeps the
    intersection, so a number that came back as something else is left alone.
    The list of processes is narrowed to the current logon session as well: the
    same account can be signed in twice, on the console and over RDP, and the
    other session's browser has windows nobody here can see. And Firefox is
    finally read correctly — its children are marked -contentproc, not
    --type=, so every firefox.exe used to pass for a main process and be
    terminated one by one.
  • The command line refuses an ambiguous line instead of measuring the wrong
    thing.
    --rules a,a measured that rule twice and counted its files twice
    in the totals; a repeated id is now kept once. A second --rules silently
    replaced the first: it is a usage error, exit 2. And the arguments are read
    as args_os, so a line carrying bytes that are not valid text is refused
    with the usage rather than panicking — in a windowed binary, that panic had
    no console to print to.
  • The release notes no longer imply the portable executable is signed.
    Only the installers go through SignPath; the note the workflow writes once
    they are signed now says so, and the README and docs/releasing.md say it
    too.
  • The quit confirmation is announced, and the focus goes somewhere. The
    confirmation next to a background browser is a live region now, so its
    sentence is read out as it appears. Once the quit goes through, the banner
    and the button that raised it disappear together and the focus used to fall
    to the top of the page: it lands on Analyze instead, and back on the Quit
    button when the browser refused to die.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.10.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 22:02

Added

  • A portable build. Drop a file named portable.txt next to
    wincleaner.exe and the application stops writing to %APPDATA%: the
    exclusions list and the Recycle Bin measurement move to
    <exe dir>\WinCleaner\, so a copy on a USB stick leaves nothing behind on
    the machine it is run from. The content of the marker is never read — it is
    a marker, not a configuration file, and a user creating it by hand cannot
    get it wrong. One resolver decides for both stores, so a store added later
    cannot quietly stay in the roaming profile, and a sandbox still keeps
    precedence over both layouts. Settings → About says "Portable" when the mode
    is active, which is the only way to tell the two apart from inside the
    window: no path crosses the IPC boundary here either. Theme, language and
    the automatic-update consent stay in WebView2's own storage and do not
    move. Releases now carry WinCleaner_<version>_x64-portable.exe next to the
    MSI and the NSIS installer; WebView2 is still required, and it ships with
    Windows 11.

  • A read-only command line. wincleaner --analyze measures every rule and
    prints a table; --json prints one stable object instead, for a script or a
    support ticket, and --rules id,id narrows the run. It opens no window: the
    arguments are answered before Tauri starts, and the release binary attaches
    the calling terminal's console to print at all. The measurement is the
    application's own — same catalogue, same detected Winapp2 entries, same
    stored exclusions with the same fail-closed rule, same concurrent scan — so a
    figure printed here is the figure the window would show. There is no
    --clean and there never will be: the confirmation before a deletion is an
    invariant, and an unattended flag would be the way around it. No option
    takes a path either — --rules accepts rule ids and refuses anything the
    catalogue does not know. Exit codes are 0 for a run, 1 for a scan error and
    2 for a bad argument, which is what a script actually branches on.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.9.2

Choose a tag to compare

@github-actions github-actions released this 12 Sep 20:22

Added

  • Quitting a browser that only runs in the background. Chrome and Edge
    keep a handful of processes alive after the last window is closed, and one
    extension is enough to hold them there for the rest of the session: on the
    machine this was written for, nine chrome.exe processes with no window
    between them, and a Clean that reported the cache files "in use" every time.
    The banner that already told those two cases apart now does something about
    the second one: a Quit {browser} button next to the warning, a
    confirmation that says what it costs — the browser is force-closed, and it
    may offer to restore its session next time — and a count of the processes
    stopped. Chrome has no external "quit" command, so the new quit_browser
    terminates its main process (the one with no --type= on its command line)
    and gives the children three seconds to follow it out before terminating
    whatever is left. It takes an executable name and matches it against the
    three browsers the detection already knows, never a path, and it re-checks
    at the moment of the click that no window has appeared since the banner was
    painted — a browser you can see is one you close yourself. The banner also
    names the permanent fix now: the "Continue running background apps" setting
    in the browser itself.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.9.1

Choose a tag to compare

@github-actions github-actions released this 12 Sep 19:39

Fixed

  • The Recycle Bin was the whole Analyze. Measured on a loaded profile,
    SHQueryRecycleBinW took 243 s cold for 110,553 items and 19 GB, while
    every other rule of the same run finished in seconds: the Analyze simply
    waited on that one call. The last measurement is now remembered in
    %APPDATA%\WinCleaner\recycle-bin.toml, keyed on a cheap fingerprint of the
    bin — the LastWriteTime of <drive>\$Recycle.Bin\<your SID> on each fixed
    drive, plus the drive list. Windows restamps that directory whenever
    anything is filed into the bin or taken out of it, so emptying the bin, or
    dropping one more file into it, invalidates the cache on its own; the drive
    list covers the one case timestamps alone would miss, a bin on a disk
    plugged in between two runs. A rule answered from the cache says so on its
    row. Unlike the exclusions store this one deliberately fails open: a
    missing, unreadable or corrupt file is ignored and rewritten, because the
    worst a lost cache can cost is one slow Analyze — nothing is ever deleted on
    the strength of a cached figure.

  • The progress bar named the wrong rule. scan-progress carried only the
    rule that had just finished, so while the Recycle Bin took its four
    minutes the hero read "84 / 85 · AMD" — a rule that was long done. The event
    now also carries the rules still in flight, and the counter says
    "Analyzing 84 / 85 · still measuring: Recycle Bin" while any of them is,
    falling back to the finished rule on the last event.

  • Excluding a folder hid only the row that was clicked. The stored pattern
    is %VAR%\folder\**, so the whole folder is out of the rule — but its
    siblings stayed on screen, each still offering an Exclude button for a file
    already excluded. Every listed path under that folder now goes at once
    (matched case-insensitively, as everywhere else a Windows path is compared),
    and the file count drops by the number of rows actually hidden. The byte
    total is still left as measured, with the same "Analyze again to refresh the
    figures" note: a scan result carries no per-file size, and inventing one
    would be worse than admitting the figure is stale.

  • The cleanup report quoted raw shell errors. A locked file read
    Error during a `trash` operation: Unknown { description: "Some operations were aborted" }, and a file the system refuses read "(os error 1920)".
    Every skipped item now also carries a stable code — in-use,
    access-denied, not-found, other, derived once in Rust from the
    sharing- and lock-violation classes, os errors 5, 32, 33 and 1920, and the
    shell's own "aborted" — which the window turns into its own sentence ("File
    in use or locked"). The raw message stays one hover away, and stays verbatim
    in the JSON report, where a script or a bug report needs it.

  • The deletion-mode help always described Auto. The footer rendered
    mode.autoHelp whatever was selected, so picking Permanent still read
    "recycle bin for the rest". It now shows the help for the mode in the
    picker, in both languages: the Recycle Bin keeps everything recoverable, and
    Permanent recovers nothing.

  • Switching screens threw the analysis away. The scan results, the last
    cleanup report and the ticked boxes lived inside the Cleanup panel, which
    the screen switch unmounts: a glance at Space or Settings cost a full
    re-Analyze — minutes, on the profile that needs it most. They now live in
    App, so they survive the trip. Entering or leaving the sandbox still
    clears them, because the catalogue and the profile both change with it.

  • The Space screen showed "0 B" before measuring anything. Nothing had
    been measured, and a zero is a figure. It now shows the em dash the Cleanup
    hero already shows in the same situation.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.9.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 18:58

Added

  • A Space screen: where your own files sit, without a delete button. A
    fourth entry in the sidebar measures the six known folders of your profile —
    Downloads, Desktop, Documents, Pictures, Videos and Music, resolved through
    SHGetKnownFolderPath so a folder redirected into OneDrive is the one that
    gets measured — and shows the total, a bar per folder, the 100 largest files
    and the 20 largest folders, each with Reveal in Explorer. The walk goes
    through the same two guards as Analyze: a known folder that resolves outside
    the profile, or that is a reparse point, is refused and named instead of
    followed, and a junction below one is never crossed. Nothing on this screen
    deletes anything and the back end offers it no way to: this is your own
    data, and the gesture that removes a file stays with you, in Explorer. The
    reveal takes the row's index, never its path, exactly as clean and
    add_exclusion do. Unavailable while a sandbox is active, because the
    folders it measures are the real ones.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.8.1

Choose a tag to compare

@github-actions github-actions released this 12 Sep 12:46

Fixed

  • Three spots in the French interface still read in English. The
    copyable cleanup report's per-rule lines now go through ruleLabel, so a
    French report says "Fichiers temporaires" instead of "Temporary files" (the
    JSON report is unaffected: its label stays English and language-neutral,
    as documented). The Exclusions section in Settings now loads the rule
    catalogue alongside the exclusion list and shows each entry's French label
    when the interface is French, falling back to the back end's own label for
    an id no longer in the catalogue, and formats the "Added on" date for the
    locale instead of printing the raw YYYY-MM-DD string (parsed as a local
    date, so the day never shifts). The rule row's sr-only file count is now a
    proper .one/.other pair, so a screen reader hears "1 fichier" rather
    than "1 fichiers".

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.8.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 12:10

Added

  • A file or a folder can be kept out of a rule for good, picked from the
    paths that rule actually found.
    "Show the paths" gains two actions on every
    line — Exclude this file, Exclude its folder — and Settings gains an
    Exclusions section listing what was kept out, with the rule it belongs to,
    the date, and a way to drop it again. The back end never receives a path: the
    command takes an index into the last analysis of that rule, the same reason
    scan and clean take only rule ids, and the same reason there is no
    free-form glob editor. What gets stored is a pattern written with the rule
    variables — %TEMP%\a\b.log for a file, %TEMP%\a\** for a folder — so the
    file carries no account name and survives a profile that moves; a path under
    none of the four allowed variables is refused. The list lives in
    %APPDATA%\WinCleaner\exclusions.toml, written through a temporary file and
    a rename so an interrupted write cannot leave a half-file behind, and under
    the sandbox root instead while a sandbox is active, so the sandbox stays
    isolated. The patterns are merged into the rule's own exclude list before
    the scan and again before the clean, and go through the validation any
    rules.toml exclude goes through — a stored pattern that is not a valid glob
    is refused exactly like a bad rule. Because clean re-walks each rule rather
    than trusting the paths the window is holding, a file excluded after the last
    Analyze is already spared by the clean that follows. A store that exists but
    cannot be read or parsed fails the scan and the clean outright rather than
    proceeding as though nothing were excluded.

  • The ten native rules now have French labels. rules.toml gains optional
    label_fr, description_fr and category_fr fields (Rule/RuleSummary
    in Rust, src/lib/rule-i18n.ts::ruleLabel/ruleDescription/ruleCategory
    on the front end, falling back to the English field when the French one is
    absent). A native rule is grouped, searched and announced under its French
    name when the interface is French — search still matches the English name
    too — including the "Analyze 3 / 85 · …" progress line, which now looks the
    label up by rule id from the loaded summaries instead of the (deliberately
    unlocalised) event Rust emits. Winapp2 (community) rules stay English, as
    documented in Settings.

  • The last cleanup report can be copied to the clipboard. "Copy report"
    puts a readable summary on the clipboard — app version, date, deletion mode,
    a total line of what Clean actually freed, the skipped paths if any, and
    per rule how many files and bytes the last Analyze measured for it plus
    its skipped count — in the current interface language. CleanReport only
    ever returns aggregate totals, never a per-rule breakdown, so the per-rule
    figures are explicitly labelled as measured rather than freed: a rule with
    a skipped file frees less than it measured, and the report says so instead
    of implying otherwise. "Copy as JSON" puts the same data on the clipboard as
    a stable, language-neutral object (version, generated_at, mode, a
    note spelling out the same distinction, rules[] with files_measured/
    bytes_measured, totals with the real files_deleted/bytes_freed, and
    skipped[]). Both reuse the clipboard mechanism already behind "Copy link"
    in Settings (navigator.clipboard.writeText, a success or failure toast)
    and build off a pure, unit-tested src/lib/report.ts. No file is written.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.7.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 10:31

Added

  • Added a native rule for per-user Windows Error Reporting reports.
    windows.wer-reports clears %LOCALAPPDATA%\Microsoft\Windows\WER\ReportQueue
    and ReportArchive — the crash reports Windows queues and archives for this
    user, regenerated on the next crash and not user data. The machine-wide
    %ProgramData%\Microsoft\Windows\WER\* store is out of scope: no allowed
    variable resolves there. risk = medium, default_checked = false, same
    category and voice as windows.crash-dumps.

  • The interface speaks English and French. Every string the application
    writes itself now goes through a small typed dictionary (src/i18n/en.ts,
    src/i18n/fr.ts, keys typed from the English one, so a missing translation
    fails tsc): labels, buttons, toasts, the confirmation, the progress lines,
    the sandbox banner and every accessibility string. Settings gains a Language
    selector — System, English, Français — that follows navigator.language
    until it is touched, applies without a reload, is remembered in
    localStorage beside the theme and the update-check consent, and sets
    document.documentElement.lang. Sizes and counters are formatted for the
    locale (1.5 KB / 1,5 Ko). What stays English whatever the setting: the
    rule labels and descriptions, which come from rules.toml and from Winapp2,
    the "What's new" body extracted from CHANGELOG.md, the release notes
    GitHub returns, and this changelog.

Changed

  • Analyze scans its rules concurrently instead of one after another.
    commands::scan_rules_with used to walk the 84 rules of a full catalogue in
    a straight loop, so the wall time was their sum — dominated by a couple of
    slow ones (the Winapp2 catch-all, and the Recycle Bin's own OS call). It now
    runs them on a small worker pool (std::thread::scope, sized to
    available_parallelism capped at 8), each rule scanned by the exact same
    scan::scan_rule/scan_rule_with_api function as before. scan_bench
    (cargo run --release --example scan_bench in src-tauri), on this machine:
    26s cold / 17s warm before, 11.2s cold / 7.3s warm after — the warm run now
    lands almost exactly on the slowest single rule (7.3s total against a 7.3s
    Recycle Bin query) instead of their sum. The scan-progress event still
    fires once per rule with a running byte total, but the order it arrives in
    now follows completion rather than catalogue order; the result list handed
    back to the front end is unaffected, since it is reassembled by index after
    every rule finishes.

  • Measured the Recycle Bin batching gain: about 2.6x. The new opt-in
    benchmark (cargo run --release --example trash_bench in src-tauri)
    creates its own fixture files and times both strategies on this machine: one
    trash::delete per file ran at 77-80 files/s, matching the ~75 files/s seen
    on the real 77,000-file run that motivated the batching change; batches of
    500 through trash::delete_all ran at about 205 files/s, a 2.5x-2.7x
    speed-up depending on fixture size (2,000 and 5,000 files tested).

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.6.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 23:08

Fixed

  • The browser warning now tells the truth about background processes. Closing every
    Chrome window is not enough when "Continue running background apps" is on; the
    banner used to say the browser was open. It now names the browser, counts its
    processes, distinguishes a visible window from background-only processes, and
    is refreshed every time Analyze is clicked. Closes #5.

Added

  • The Clean has a progress bar of its own. Cleaning used to be a disabled
    button reading "Cleaning…" for as long as the work took — thirteen minutes on
    a measured run. clean now emits clean-progress as each rule closes and
    every 500 files inside a rule, and the hero draws the same determinate bar as
    Analyze: "Cleaning 3 / 9 · Temporary files", with the freed bytes and the
    file count ticking up in the big-number position. The live region follows the
    rules, not the files, so a rule deleting 59,000 of them is not read out a
    hundred times over.

Changed

  • Recycle Bin mode is far faster: files go to the bin 500 at a time. Each
    trash::delete is one IFileOperation, and its fixed cost — COM plumbing,
    the shell's own progress reporting, one undo record — is what dominates a bin
    full of small files: a real run measured about 75 files/s, so 59,000 files
    took thirteen minutes. One trash::delete_all per batch of 500 divides that
    by the batch. The deletable_path guard still runs per file, immediately
    before the file joins its batch, and a batch the shell refuses is retried one
    file at a time so skipped still names exactly what is still on disk.
    Permanent mode is unchanged: one remove_file per file.

  • Keyboard and screen-reader pass over the whole interface. The sidebar is
    a named Main landmark with a roving tabindex — the arrow keys, Home and
    End move between the three screens, and it costs one Tab press to get past
    instead of three; the theme toggle states which theme is on, not only what
    the next press does. On Cleanup, each category header names the rows it
    folds, each "Show the paths" names its rule and opens a named region, and the
    confirmation takes the focus when it appears, cancels on Escape and hands
    the focus back to the Clean button. The scan announces itself every ten rules
    and on completion — not on every rule, which would be hundreds of
    interruptions — and the cleanup report, the sandbox verdict and the sandbox
    banner announce themselves too. The reclaim gauge states its total and its
    three largest rules in words. The startup table is named and every row toggle
    reports its outcome. Nothing moved on screen: no layout, no wording, no test
    id changed.

  • Two measured contrast failures fixed. The focus ring on the controls that
    carry no border — sidebar entries, category headers, paths triggers, the
    search field, the mode selector — was drawn at half opacity (1.66:1 against
    the card in the light theme) and is now solid (4.87:1). The Clean and Confirm
    buttons wrote --destructive on a wash of itself: 4.11:1 light, 3.75:1 dark,
    2.87:1 hovered, all under the 4.5:1 body text asks for. A new
    --destructive-foreground token takes the worst case to 4.71:1 with the
    fills untouched. Everything else measured clean, --muted-foreground
    included (5.11:1 to 6.42:1 on every surface, both themes), and
    src/theme-contrast.test.ts recomputes all of it from the stylesheet so the
    next nudge to a colour fails in CI.

  • prefers-reduced-motion is now honoured app-wide, the shadcn transitions
    and the loading spinners included, by one rule in the base layer rather than
    a class to remember on each element.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md

WinCleaner v0.5.1

Choose a tag to compare

@github-actions github-actions released this 11 Sep 21:03

Fixed

  • Two Winapp2 entries deleted application content, not cache. [Vortex *]
    swept %LocalAppData%\Vortex-Updater, where Vortex stages the executables of
    its own pending update, and [Discord *] deleted the Squirrel .nupkg
    packages the installed tree is unpacked from and the next delta is computed
    against. The converter now carries an explicit app-content deny-list
    (winapp2.rs::APP_CONTENT_DENY): a denied directory prefix sinks the whole
    FileKey, a denied file spec removes that spec. Refused keys are counted by
    app_content_keys and an entry left with no FileKey by
    dropped_app_content; on the embedded file this refuses 3 keys and drops no
    entry — both applications keep their real cache keys. Closes #2.
  • Sandbox folders are no longer left behind in %TEMP%. Leaving the
    sandbox was the only thing that removed its directory, so a crash, a kill or
    a window closed with a sandbox still open left
    %TEMP%\wincleaner-sandbox-… and its few hundred files there for good.
    WinCleaner now sweeps those leftovers at every start — only ever a directory
    whose owning process is gone, never one a running WinCleaner is using — and
    Settings → Sandbox shows a line naming how many are left and how much they
    take, with a Remove button, so no restart is needed. Closing the window with
    a sandbox active also attempts the removal on the way out, within a short
    budget so the window never hangs on it. The sweep unlinks junctions before
    removing a tree, exactly as leaving the sandbox does, and never counts nor
    follows what is on the other side. Closes #3.

Installers are unsigned until SignPath signing is configured in the repository secrets — see docs/code-signing.md.
Full changelog: https://github.com/CaseReed/wincleaner/blob/main/CHANGELOG.md