Skip to content

v0.9.2

Choose a tag to compare

@github-actions github-actions released this 19 Sep 12:31
· 11 commits to main since this release

Two one-time steps

This build is not signed with an Apple Developer ID and not notarized, so macOS blocks
the first launch. Allow it once:

  • macOS 15 Sequoia and later β€” double-click, dismiss the warning, then open
    System Settings β–Έ Privacy & Security and click Open Anyway. Apple removed the
    Control-click shortcut for unsigned apps in macOS 15, so right-clicking does not help.
  • macOS 13–14 β€” right-click the app β–Έ Open, then confirm.

Then answer the folder prompts once β€” macOS asks separately for Desktop, Documents and
Downloads the first time the app looks at them. Allow them and it stays quiet from then on.

Named workspaces, a keyboard that works the same in every view β€” and the packaging defect behind
"it keeps asking for folder permissions".

A workspace is a named work context now rather than a saved layout: both panels, every tab, the
marks, the filter, the tree and the window's whole arrangement switch together, and switching back
restores what you left. The panel's keyboard vocabulary, which only ever worked in the details view,
now works in Brief, Icons and Gallery as well, and those views draw what is marked. The quick search
and the quick filter lost the last of the places where the list and the count disagreed.

And the app bundle is sealed at last. It never was: codesign --verify answered "code object is
not signed at all"
, because the plugin build wrote its incremental stamps into
Contents/PlugIns/.build-stamps and codesign refuses a bundle carrying a directory it does not
recognise β€” with or without a certificate. macOS 26 kept honouring permissions granted to an unsealed
bundle; macOS 27 will not grant new ones, which is why a fresh install asked for Desktop, Documents
and Downloads over and over and forgot every answer. Measured on 27.0: 27 prompts before, three
after β€” one per folder, remembered, and nothing at all on the next launch. This is an ad-hoc seal,
not a Developer ID: the first launch still goes through System Settings.

Changed

  • Workspaces are named work contexts now, not saved layouts (F-499). A workspace β€” "clean up
    backups", "sort applicant documents" β€” remembers both panels, every tab, the active side, the view
    mode, the folder tree and the back/forward history, and switching restores the other one exactly as
    it was left. It never asks whether to save, because a workspace never ends; what the old feature
    did on every load β€” "anything you had open but did not save is not kept" β€” was the reason it was
    worth rebuilding rather than extending.

    The whole window switches, not just the folders: both panels and their tabs, the view mode, the
    folder tree, the back/forward history, which files you had marked, the quick filter, the cursor,
    and the window's arrangement β€” the side panel, the dock and which plugin view it shows, every bar,
    the panel layout and where the divider sits. Change any of those and you have changed this
    workspace, not a global setting.

    The terminal and the assistant follow too, and nothing running dies. The tabs of the workspace
    you leave are set aside with their shells alive rather than closed β€” a make or an rsync started
    in one workspace keeps running while you work in another, and is still there when you come back. The
    assistant keeps a separate conversation per workspace; an answer still arriving when you switch away
    finishes and is waiting for you. Chats from before this existed belong to no workspace and appear
    everywhere, so nothing is hidden by the upgrade.

    And a basket per workspace, for what actually happens while tidying up. Three folders deep in the
    backups you find something that belongs to an entirely different job: drag it onto that job's chip
    and it lands in its stash. You do not switch, nothing is copied or moved, the chip's counter goes
    up and you carry on. βŒ₯ copies into that workspace's folder instead and ⌘ moves; Ctrl+Cmd+A adds the
    selection to the current one; the Stash page in the side panel shows what is in it; and Copy/Move
    Stash to Other Panel does the whole basket in one operation, through the same background transfer,
    overwrite handling and undo as every other copy. Files deleted in the meantime are shown as missing
    rather than dropped, and a bulk operation offers to skip them or take them out first.

    A workspace can also be limited to a folder, which is the safety net for a tool that deletes.
    Right-click its chip, Limit to Folder, and choose whether operations outside it are allowed, asked
    about, or refused β€” "clean up backups" covering /Volumes/Backup then asks before F8 takes something
    from your Desktop. Checked before a delete, a copy, a move, a rename or a new folder reaches outside,
    and asked before the delete confirmation rather than after it. Navigating is never restricted
    (ADR-013): a file manager that refuses to show you a folder is broken, and a guard that gets in the
    way while you are only looking is one people switch off before the moment it was built for.

    And each workspace keeps a journal β€” folders visited, operations carried out, shell lines run,
    and anything the folder limit refused. Workspace β–Έ Journal… shows it newest day first, with a
    Problems filter for everything that failed or was stopped; the refusals are recorded nowhere
    else in the application. Return repeats a row under the history's rule β€” only a copy or a move goes
    with one keystroke, a shell line is filled into the command line rather than run. It is a log rather
    than a filter over the global history, because that one ranks by frequency and collapses repeats,
    and "what did I do here" needs the order and the whole of it. Deleted with its workspace, kept
    indefinitely otherwise, and switchable off in Settings β–Έ Tabs.

    And a workspace is a file you can hand over. Workspace β–Έ Export Workspace… writes a
    .pcworkspace; Import Workspace…, or a double-click in the Finder, reads one back. The storage
    format is the export format, so there is no second schema to drift apart from it, and paths inside
    your home are written shortened so the file opens in the other person's home. What travels is the
    workspace's saved starting point, with its name, colour, folder limit and stash. What deliberately
    does not: anything that could be a credential β€” a tab on a connection or a mounted plugin drive
    is removed rather than cleaned up, and counted in the report, so there is nothing about a connection
    in the file to leak β€” and the journal, which records what you did and names folders on your
    machine. An import always adds a workspace and never switches by itself; a file somebody sent should
    not move the window you are working in. Folders that are not on this Mac open at the nearest one
    that is, stash entries keep their paths and show greyed, and a folder limit set to refuse whose
    folder is missing is kept but asks instead β€” a refusal nobody can act on is worse than a question.

    Each chip carries a βœ• at its right-hand end, so putting a workspace away does not mean finding
    a context menu first. It leads into the same confirmation as everywhere else, because a workspace is
    deleted rather than closed and its stash and journal go with it; the last remaining one has no βœ• at
    all, and a chip too narrow to spare the room keeps its name instead.

    Marked files are the part worth stating plainly: come back to a workspace two days later and the
    forty files you had ticked are still ticked. Anything deleted in the meantime is quietly no longer
    in the selection rather than a phantom entry. Undo is per workspace too, but only while the app is
    running β€” an undo step carries the action that reverses it, and that cannot be written to disk.

    Switch from a strip of coloured chips across the top of the window, from the Workspace menu, or with
    Ctrl+1…Ctrl+9. Each workspace also keeps the arrangement it was set up as, so Cmd+Ctrl+S ("save the
    layout" in the old feature) now means "make this the state I reset to", and Reset to Saved State
    goes back there.

    None of it is visible until you make a second workspace: no chip strip, no menu, no shortcuts β€”
    and the whole feature can be switched off in Settings β–Έ Tabs, which also takes the two Go entries
    away. Switching it off keeps your workspaces; they come back unchanged.

    Upgrading loses nothing: workspaces saved with the old feature become chips, the session you were in
    becomes the first one, and workspaces.ini is kept as workspaces.ini.migrated. Each workspace is
    now its own workspaces/<id>.json, so one unreadable file costs only itself and a workspace can be
    handed to somebody else.

  • The arrow keys step between the quick search's matches (F-060). Typing letters in a panel jumps
    the cursor to the first name that starts with them; ↑ and ↓ now walk backwards and forwards through
    the rest of the hits, wrapping at both ends, for as long as the βŒ• re 2/3 indicator is on screen.
    Repeating the same single letter still cycles too, but that only ever worked forwards and only for a
    one-letter prefix β€” past the first hit of "re" there was nothing to press. Only the bare arrows are
    taken: Shift+Arrow still extends the selection, Alt+Down is still the history dropdown, and once the
    indicator has timed out Up and Down move one row again.

  • A filtered list cycles, and keeps its cursor while you narrow it (F-395). The quick filter hides
    what does not match, so ↑ and ↓ already walked only over hits β€” but they stopped at the ends, and
    every keystroke threw the cursor back to the first row. Now the arrows wrap (.. is part of the
    cycle: in filter mode Backspace edits the mask, so the parent row is reachable by arrow and by
    nothing else), and refining a mask leaves the cursor on the item you were aiming at for as long as
    the narrower mask keeps it. Clearing the filter keeps it too β€” you filter to find one file and press
    Esc to see it among its neighbours. Marking is deliberately left alone: Shift+Arrow and Insert still
    stop at the ends, because a mark run that wrapped would come back round and untoggle what it had
    just set.

Fixed

  • macOS kept asking for the same folder permission and never remembered the answer (#3). The app
    bundle carried no code seal: Tools/build-all-plugins.sh wrote its incremental stamps to
    $OUT_DIR/.build-stamps, which for a packaged build is the app's Contents/PlugIns, and codesign
    refuses an entire bundle over a directory no bundle format knows β€” "bundle format unrecognized,
    invalid, or unsuitable. In subcomponent: Contents/PlugIns/.build-stamps"
    . Tools/codesign-app.sh
    then returned early whenever no signing identity was configured, so no build was ever sealed and the
    first defect stayed invisible. Stamps now live outside the target, and the app is sealed ad-hoc when
    no identity is given.

    macOS 26 went on honouring permissions that had been granted earlier, so this only showed on a
    machine without them β€” a new install, or macOS 27, which refuses to store one for an unsealed
    bundle at all. Measured on 27.0 (26A428): 27 prompts, every one answered, none recorded; after the
    fix three prompts, one per folder, each recorded, and a restart asks nothing. Full Disk Access is
    not a workaround for the old build and never was.

  • The build stopped compiling under Xcode 27. Swift 6.4 will not choose between
    Data.append(Data) and Data.append(UInt8) for a bare $0 inside an array literal, where earlier
    compilers took the type from the literal. Two places, the same four lines copied once:
    Sources/PCFoundation/TextPipe.swift and Plugins/SDK/PluginDecompiler.swift.

  • The quick filter's count was one keystroke behind its text (F-395). applyFilterLive reported
    to the indicator before rebuilding the list, so πŸ” rep 7/1217 showed the new mask beside the
    previous mask's number β€” and a mask that had just narrowed to nothing still claimed the hits it no
    longer had. Counted after the rebuild now.

  • The panel's keyboard now works in Brief, Icons and Gallery too, and those views draw marks
    (F-021, F-060, F-395). IconGridView answered the arrows and Enter and dropped every other key, so
    in three of the five view modes there was no quick search, no quick filter, no Space or Insert
    marking, and Backspace did not go up a folder β€” while syncGridCursor's own comment said the
    type-ahead was meant to reach the grid. Every key the grid does not own is handed to the list that
    implements it; the arrows and Enter stay with the grid, because there they are about cells rather
    than rows. Marks are drawn in the theme's marked colour, the same colour and the same meaning as in
    the list, and they follow every change without rebuilding a cell.

    Page Up and Page Down belong to the grid too, because a page there is a screenful of cells:
    handed to the list they asked a table that is not on screen how tall it was, and its answer covered
    the whole folder β€” so one press went to the last file rather than down a screen. Measured on a
    500-file folder: 52 cells per page in Brief, 20 in Icons at that window size, the same step on
    every press and the exact inverse going up. Home and End keep going to the list, which needs no
    geometry to answer them.

  • A grid mode answered Shift+Arrow, Alt+Down and Ctrl+PageDown as if they were bare keys (F-021).
    IconGridView.keyDown switched on the key code and never looked at the modifiers, so marking a
    range, opening the history dropdown and "enter the item under the cursor" all arrived as a plain
    arrow: the cursor moved and nothing else happened. Only bare keys belong to the grid now β€” anything
    carrying a modifier goes to the panel. Measured in Icons view: Shift+Down marks notes.txt, again
    marks report-1.txt beside it, and the grid draws both.

  • A quick search that had already expired kept Backspace (F-060). The typed prefix outlives its
    indicator by design β€” the next keystroke's window check is what clears it β€” but the keys went on
    belonging to a search nobody could see: measured, 2.6 s after one letter the indicator was empty and
    Backspace still edited the invisible prefix instead of going to the parent folder, and it stayed
    that way until some other keystroke happened to clear the buffer. An expired search now owns
    nothing, which is the same rule the arrows got when they learned to step between matches.

  • The quick filter and the Brief/Icons/Gallery view disagreed about which files exist (F-021,
    F-395). Those three modes draw an icon grid that mirrors the panel's visible entries, and the
    quick filter is the one thing that changes that set without a new listing β€” so nothing rebuilt the
    grid when a mask was applied or cleared while one of them was showing. Filter in Details view,
    switch to Brief, clear the filter from the View menu, and the grid went on drawing the matches of a
    mask no longer in force, with the folder's other files simply absent. Worse than stale: the grid
    maps a click or Enter through its own index into the panel's list, so the file that opened was
    not the file under the highlight β€” measured, gridName=report-2.txt against
    tableCursor=report-1.txt. The grid is rebuilt on every filter change now, and a new griddump
    verb reports what it is drawing beside the panel's own cursor, with an agree= line, so the VM
    gate can see the two part company.

  • Ctrl+S in the middle of a quick search left the search's prefix behind. The filter took the
    keyboard while the type-ahead's buffer and its indicator stayed up for the rest of the two-second
    window β€” and since the arrows now step between a search's matches, they would have been taken from
    a list that prefix no longer describes. Entering the filter ends the search.

  • A tab's cursor position survived loading a saved workspace but not restarting the app: the session
    and the workspace format had drifted apart, and only one of them wrote it down. There is one
    serializer now, and it does (F-499).