Repository navigation
Conversation
* Rename the app to PwrDisk, a maintained fork of disktree Only what users see changes: the binary is pwrdisk, the macOS bundle is PwrDisk.app with the identifier com.pwrdrvr.pwrdisk, and the desktop entry, icon name, window class, titles, menus, exports and release archives follow. Crate, module and type names and the disktree-scan SSH helper keep their upstream names so merging tobi/disktree stays clean. The bundle identifier has to change: releases are signed with our Developer ID, and the old one belongs to upstream. The Power Efficiency setting moves to a pwrdisk folder; a missing one falls back to disktree's, so switching keeps the choice. LICENSE keeps Tobi Lütke's notice and adds ours; the README credits disktree up front. * Name PwrDisk in the messages the rename missed The Full Disk Access notice told Mac users to grant access to disktree, an app System Settings no longer lists. The missing-scanner error, the remote helper's install hint and disktree-scan's help also named the old command.
…nts (#3) * Sign releases through the apple-signing and windows-signing environments Releases now fail rather than ship unsigned. macOS signs with the Developer ID from apple-signing, notarizes, staples and checks the app with spctl; the identity is read from the certificate. The secrets reach only the signing steps, after the tests and the build. Windows build jobs hand their unsigned executables to windows-sign, the only job with the Azure credentials, which neither checks out nor builds source. It signs both with Azure Artifact Signing, checks each signature is valid, timestamped and PwrDrvr's, and packages the zips. Both environments accept only v* tags and wait for approval. scripts/release/upload-csc-link-from-1password.sh, from PwrRoute, fills apple-signing; docs/releasing.md lists every value. * Upload the Windows signing settings from 1Password The PwrDisk counterpart of PwrRoute's upload-azure-signing-from-1password.sh (pwrdrvr/PwrRoute#127): reads the 'PwrDisk - Windows Azure Trusted Signing' item and sets the four WIN_AZURE_SIGN_* variables and three AZURE_* secrets on windows-signing. * Harden the release workflow's signing jobs - A rebuild dispatched from a branch could never pass the v*-only signing environments; the first job now requires running from the tag. - The Windows publisher check compares the certificate's name whole instead of matching a substring of its subject. - README and LICENSE for the Windows zips are fetched in bash; a PowerShell redirect re-encoded them and mangled the copyright notice. - Every action is pinned to a commit, since the signing jobs run them before their credentials arrive.
…ily's PR conventions (#11)
Like PwrRoute's. Build is a debug build of the app; Test and Lint run the xtask gate. Start runs a release build, as make run does, but through cargo so it also works on Windows, which has no make. On macOS the unbundled run still gets its Dock icon.
…pipe (#17) * feat(windows): link the window to its MCP agent over a named pipe * fix(windows): cancel pipe I/O before releasing link handles * test(windows): accept the named pipe disconnected error * fix(windows): authenticate the window pipe owner before use * fix(mcp): describe Windows window handover in agent guidance
#89) * feat(app): keep the removal list on screen and check it off as it goes Removing and Done now draw every target of the run from the first frame: a drawn checkbox that goes from grey to green (red on failure), the row dimmed until it is reached, the name over its folder with the middle of the path shortened to fit, what the scan classified it as, and its size. The list follows the item in hand until it is scrolled by hand, and Done keeps it instead of dropping it. A sidebar beside it shows progress and the reported, private and observed figures as running totals, the disk meter and what the mode means for them; on Done it shows the result, with the ledger under the list. * feat(app): follow the item in hand like the live log, and give Review the same rows The removal list keeps the item in hand in view while it is on screen. Scrolling it out of view pauses that and shows a pill at the foot of the list, "Follow the removal", which follows it again, as does scrolling back until it shows. Review's rows now read as Removing's do: the kind's colour, the name over its folder shortened from the middle on one line, and a chip saying why it is listed, with the icon where Removing puts its checkbox. * perf(app): draw only the removal rows in view, and cache what Review's marks are Removing redrew up to 1,200 rows on every 60 ms poll and every free-space sample. The list is now a uniform list that builds only the rows in view, so a run of any length scrolls end to end with no block that moves under the reader, and the item in hand is placed from the rows' one height rather than from bounds of rows that may not be drawn. The poll redraws only when a report arrived, the run ended or following changed. Review resolved every mark on the page on every frame, which indexes each directory the paths pass through; what each mark is now lives in a cache kept until the tree changes. The pill's click also clears a wheel turn the poll has not read yet, so it cannot pause following again. * fix(app): stretch each removal row across the list A uniform_list row is only as wide as its content, so the size and status lanes moved with each row's kind chip. Found in the screenshots; the follow test now checks that rows span the list.
* refactor(app): keep one record of a removal run The run's list was the third copy of each worker report, beside run_summary and run_log, and ledger::Start held a fourth copy of every target. Each item now owns its Target, the summary counts come from RunList::totals, and what went is a filter over the list in plan order. A failure reported against no listed target, which is how the worker says it could not start, still counts as failed. The worker's Done tally is kept only to log a warning if it ever disagrees with the list. * fix(app): keep unlisted failures out of the run's per-item figures A failure the worker reports against no listed target was counted in Totals::failed, which the screens subtract from the item count. Count it apart, and give the agent and the ledger both through failed_all. The cohort also reads its figures from one totals pass.
…st the size limit (#97) * fix(removal): never offer home folders for removal, and gate marks past the limit Mark for removal was a filled, highlighted button on /Users: the guards only refused it later, in Review, and another account's folder under /Users was not refused at all on macOS. - Guards: /Users and every folder directly in it are refused on macOS, as C:\Users and each profile already are on Windows (and now C:\Users itself). `removal::refusal` judges one path as `plan` does. - Inspector: a refused path shows Protected with the reason and a disabled "Can't remove"; Space marks nothing and says why. - Size limit at mark time: a mark that takes the marked total past the limit shows "Over 5% limit" with a chevron whose menu holds Mark anyway. Space refuses and points there. - Review: past the limit, the commit stays off until the person types "delete 20% of my disk" (or "trash ..."), and the worker is held to the share typed, so growth since is refused. - Settings > Safety: limit 1/5/10/25/50% or Off; over-limit confirmation Type a phrase (default), Tick a box, or No second step; read-only Always protected and Agents rows. - Agents: a mark onto a protected path or past the limit is refused; with the window's limit Off, agents keep 5%. * fix(app): make Mark anyway and Safety settings real buttons * fix(app): draw the Mark chevron at heading size * test(app): lift the size limit where a fixture outgrows a small disk * fix(app): tighten the over-limit gate after review - Clear the typed phrase and the tick once a removal starts, so the next removal past the limit asks again. - Read a saved 100% limit as Off, so agents keep the 5% default. - Measure capacity when the ticker has no reading yet, so an early mark is still judged. - Leave Home, End and the arrows to Review's phrase field while it is being edited. - Judge a new mark afresh rather than from the inspector's cached answer. - commit() plans once and asks removal_limit directly. - Skills: a window checks marks made before it was linked.
…› Agents (MCP) (#99)
* fix(removal): refuse other users' home folders on Linux /home and every directory directly in it are refused, as /Users is on macOS and the profiles folder on Windows. Where /home is a link (Fedora's atomic editions point it at /var/home) both names are refused, so a scan from either spelling is judged alike. The folders come from the layout, not /etc/passwd, which lists service homes like / and /var/lib/*, misses LDAP and SSSD accounts, and forgets a removed account's leftover files. * fix(removal): build the linked-home helper only where it is used Its test runs on Unix only, so a Windows test build saw the helper as dead code and the lint gate failed. * fix(removal): name /home in Settings and test refusal by both names Settings › Safety now lists /home among what is always protected on Linux. The profiles check moves into profile_refusal, so the linked-home test runs the refusal itself against both names of the folder.
#103) * fix(removal): hold each disk to its own confirmed share past the limit Review's over-limit gate counted every marked byte against the scanned volume and handed the worker that one percent, which Limit::check then applied to each volume separately. A mark on a disk mounted inside the scan could therefore pass at the boot disk's confirmed share without anyone confirming it for that disk. Core gains Ceilings, a base Limit with per-volume raised limits, and usage(), the grouping Limit::check already used; Limit::check delegates to Ceilings so there is one implementation. The worker takes Ceilings. Review now groups the plan by volume the same way, lists each disk past the limit with its own meter, and asks for a phrase naming every share ("delete 30% and 10% of my disks"). The worker holds each listed disk to its confirmed share and every other disk to the window's limit. Agents still get a plain Limit and can never pass it. * fix(removal): name a marked link's disk by where it sits, and reread disks on every way into Review Review's disk cache was cleared only by open_review; the agent's review request and the side panel's Review button now clear it too, so a disk remounted since the last visit is read again. disk_of took its key from the path the worker's check reads (a link's directory) but its name from the link itself, which statfs and canonicalize follow. Both now come from removal_limit::volume_entry. Also corrects the mark-time comment, which claimed counting against the scanned volume only over-counts, and lets rustfmt keep Ceilings::check_with within 80 columns.
* fix(removal): hold an agent's removal worker to the agent limit An MCP removal's preview is checked at the agent limit, which stays 5% when the window's limit is Off. agent_remove then started the run through begin_removal, which held the worker to the window's limit: 100% with Off. A selection that grew past 5% between the preview and the start of the removal was removed. agent_remove now starts the run through begin_agent_removal, which hands the worker Ceilings::from(policy.agent_limit()) and ignores Review's over-limit gate, so nothing the person confirmed raises an agent's removal. The person's path through begin_removal is unchanged. * test(app): share the agent link setup between the two link tests
…93) * feat(core): distinguish artifact detections from cleanup suggestions * fix(core): preserve ownership in narrow artifact scans * fix(app): scroll artifact guidance above pinned free space * fix(app): give artifact assessments their own hierarchy The inspector drew the status, artifact, evidence and guidance as three grey caption lines of equal weight, so Detected and Suggested for review looked alike, and the filled Mark for removal stayed the strongest element under guidance to manage a VM in its own app. Draw the assessment as one block: a status chip beside the artifact, the evidence as a sentence, and the guidance in body ink, ruled in the kind's colour. A detection that is not a suggestion leaves Mark as an outline button. Review repeats a caution chip on marked VM data. The hatch filter's chip and totals line say Suggested instead of Reclaimable, and an empty Worth a look no longer implies that its rows are disposable. The guide follows.
…indows (#106) An empty Marked or Worth a look is now its header alone, with "Space to mark" or "none" where a full section shows its count or total. Under 48 rem tall the panel is compact: the selection's four figures fold into one summary line that opens the grid again, the selection's label goes, the spacing tightens, and the idle "Connect an AI agent" line waits until an agent connects (Help still offers it). At 1200x600 with an assessment selected, Marked now starts in sight. The name, the size, the assessment and Mark never fold.
#108) * feat(app): size the legend's chips and fold empty kinds into a +N menu PR #93 grew the legend to eleven kinds plus Suggested, and the row wrapped onto a second line on narrower windows, showing kinds that hold nothing on this disk. Each chip now carries what it keeps of the whole scan, worked out once per tree off the UI thread by `filter::shares`, which judges files by the same facts as `Rule::passes`, so a chip's size is the "Showing" figure clicking it gives. The row is one line: chips with no data or under a thousandth of the scan, then the smallest when the measured labels still do not fit, go into a "+N" menu at the row's end. A chip that is set always stays on the row; setting one from the menu moves it there. * fix(app): hang the legend's +N menu at the row's right end * test(app): pin the legend's set chips across drilling down; say sizes are scan-wide * fix(app): close a stranded legend menu, wrap set chips, open the compact figures by keyboard The +N menu closes when nothing draws it, so Escape is not swallowed and it does not reopen by itself; Escape closes it only on Explore. Set chips, which never fold into the menu, wrap rather than clip on a narrow row. Chip widths are shaped once per frame, not once per pass. The compact panel's summary line is focusable and opens with Enter or Space.
* feat(app): route cache cleanup through supported owners * fix(app): refine owner cleanup previews and results * fix(core): detect active npm launchers and pip3 * fix(app): make cleanup previews explicit and refuse installing shims * fix(core): reject npm download proxies before discovery * fix(core): preserve exact owner cache paths from probes * fix(core): refuse ambiguous cache-root line endings * fix(removal): preserve owner cleanup boundaries * test(app): use native separators in cache export fixture
#109) * feat(app): decide cache cleanup per path, with deliberate Delete files Cache cleanup is now best effort and decided item by item. Check owners returns one proposal per marked path: the exact owner command (executable, version, arguments, environment, root, actual scope, effects, limitations, recoverability) or why there is none, in one problem vocabulary. A missing CLI, unsupported version or failed probe is that path's status, not the whole review's. For each path the person chooses Skip (the default), the owner's exact command, or Delete files: a separate destructive intent for exactly the selected path, with its own disclosure (owner bypassed, caches inside, unknown owners never called disposable), Trash or permanent, and its own tick in Review or its own confirmation text over MCP. Owner approval never approves deleting files, and a failed or cancelled owner command never falls back to it. Guards, the capacity limit and an in-use check apply. The worker runs each step on its own and reports every path: succeeded, failed with a reason, cancelled, skipped or not reached. MCP previews take per-path decisions and name each intent in the confirmation. * test(core): gate Unix-only cleanup test helpers owner_error and owners are only called from Unix tests, so Windows' -D warnings lint rejected them as dead code. * fix(app): name disabled owner commands with Run, and read the cleanup confirmation plainly A proposal whose owner is known but whose command did not resolve drew its disabled choice as "pip cache purge" instead of "Run pip cache purge". The confirmation listed sizes in raw bytes and the untouched paths as one bracketed list; it now uses human sizes and one path per line. * fix(app): say "1 command" in Review's cache cleanup header * fix(app): keep cleanup decisions, offer Delete files only where checkable From a review of #101 and #109: - The window's owner check expired after five minutes. The person's decisions vanished at the next redraw, and an agent's unexpired preview failed at pwrdisk_remove with "Check owners first". The worker already rechecks the executable, version, root, scope, guards, limit and in-use state before each step, so the check no longer expires. - Delete files was offered on Windows, where the in-use check is unavailable, so every such step failed as "in use". It is no longer offered there; docs and the Windows reference say so. - Review rebuilt the approved steps (cloning the whole check and planning against the mount table twice) several times per frame. They are now kept in the review and rebuilt only when a decision changes. - Two expressions were over 80 columns where rustfmt had given up; they are now a helper and a constant it formats.
* fix(core): recognize pip3.12 and uvx as running owners A running pip3.12 (as python.org and Homebrew install it) or uvx (uv's tool runner) writes the same cache as pip or uv, but the in-use check compared only pip, pip3 and uv, so cleanup could start while they ran. * test(core): property and oracle tests for cache cleanup Seeded, generated cases for the rules earlier fixes restored: the cache root is exactly what the owner printed; a cache's sign protects every path under it; probing never runs a launcher that could install; a running owner is recognized in every launcher form; approval keeps each decision and Skip means nothing happens. Each failure names its seed, and PWRDISK_SEED replays it. * test(app): check Review's cache decisions against a model of them After any sequence of decisions, Trash or permanent choices and ticks, the window's kept approval equals a fresh one, a change to what is deleted clears the consent tick, and the export lists the marks. * test(core): replayable seeds and poison-tolerant fixture locks Each Review model seed starts from the same state, so the seed named on failure replays alone; seed ranges wrap instead of overflowing; a failed test holding the execution lock no longer fails the others with a poisoned-lock error; the test-only owner_argument wrapper is gone now that tests call owner_named directly.
…ff the pointer Once a legend set filters, hovering another chip of it shows an "only" pill over the chip's right end. Clicking it makes that chip the set's one only chip and clears the rest of the set, hidden chips included, so going from Code to just Cache, or from Code, Cache and Media to one of them, is one click. A click on the chip itself still adds or cycles. `o` does the same from the keyboard. Modelled on PwrSnap's sidebar facets. GPUI puts a tooltip one pixel from the pointer's tip, so it sat under the cursor and over the next chip. Every app tooltip now goes through `widgets::with_tooltip`, which waits 700 ms instead of 400 ms and draws the surface below the cursor's height.
Contributor
Author
|
Opened here by mistake; this belongs in the fork. Sorry for the noise. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Only pill. Once a legend set (kinds, or ages) filters, hovering another chip of it shows an only pill over the chip's right end. Clicking it makes that chip the set's one only chip and clears the rest of the set, hidden ones included:
A click on the chip itself still adds or cycles, so building "Code, Cache" still works. No pill when nothing is set (a click already means only), on a chip that is already the set's one only chip, or on Suggested.
oon a focused chip does the same. The pill sits over the chip's size rather than beside it, so it never moves the chips after it out from under the pointer. Modelled on PwrSnap's sidebar facets (Library.tsx,psl__facet-only).Tooltips off the pointer. GPUI places a tooltip 1px from the pointer's tip, so it sat under the cursor and over the next chip and the pill. Every app tooltip now goes through
widgets::with_tooltip, which waits 700 ms instead of Omarchy's 400 ms and draws the surfacesize::TOOLTIP_CLEARANCE(26px, past the arrow cursor) below the pointer. Near the window's bottom GPUI flips it above the pointer, which is clear too.Mockup: Legend Only Pill and Tooltips in the PwrDisk design project.
Tests
legend::only_switches_a_set_to_one_chip_in_one_step: when the pill is offered, and that it clears only its own set.the_only_pill_switches_kinds_and_the_tooltip_stays_clear(window harness): no pill with nothing set; with Code set, hovering Cache shows the pill, the tooltip waits for the delay and its surface starts below the cursor and off the pill, and clicking the pill leaves just Cache.make ciis green locally (macOS). Not eyeballed in the running app.