Commander Mode

June 17, 2026 · View on GitHub

Pick-up notes for the Commander Mode feature. Read this first, then the full plan in commander_mode.md.

Last updated: 2026-06-16


TL;DR

  • Branch: commander-mode (off upcoming-mister). git checkout commander-mode.
  • What it is: a full-page, Midnight-Commander-style two-pane file explorer overlay. Full design in commander_mode.md; tracked in OPEN-WORK.md §6.1.
  • Where it's at: a working two-pane file manager (M2-lite + M3 + host panes + the M6 batch + M1 widget extraction + M4 File Info window + Phase 3 .adz/.hdz gzip containers + two rounds of hands-on-test fixes). Each pane opens a disk image / container (pick a partition) or a host folder, with a sortable multi-select listing and .. (double-click) / folder (double-click) nav. Image panes stage delete + copy-in + rename + New Folder (Apply/Discard, virtual overlay, unsaved guards + a per-pane Close); host panes write immediately. The middle column has icon buttons (painted floppy glyphs) for copy in all four combos, with a "Keep original dates" toggle (Amiga + HFS). Right-click also offers Export to hard drive, Calculate checksums, Rename (all 26 editable FS), and File Info / Details. Double-clicking a file (or right-click → File Info) opens a floating window with metadata + text/hex preview + an editable subset (HFS type/creator + dates, ProDOS type, ext permissions) staged onto the pane queue, with staged changes reflected and changed rows marked (blue + * ). .adz/.hdz open as gzip containers (peeled to read, re-gzipped on edit). The per-pane tree was removed (R4 will reuse the browse view's tree). Round-4 added a rolling session log (top-bar Log window), a read-only "Open Backup folder" pane (browse / copy files out of a native rusty-backup folder), and the per-filesystem editable-metadata matrix doc.
  • Branch state: commander-mode, tree clean, ~17 unpushed commits past the CI-green nav fix 45a108c (M1/M4/R1 → round-3 A1/A2/A4 → round-4 log / backup-open / metadata-matrix). Only 45a108c is on the remote / has run CI.
  • Verify on hardware (untested in the dev sandbox): the macOS device elevation fix (os/macos.rs open_device_for_inspect, commit ff36fa3) — open a real /dev/diskN in Inspect, confirm the authopen admin prompt + read.
  • Round-3 punch-list:
    • Center Delete button (eee8070) — "active pane" via focused on PaneResponse/RowActions + CommanderMode::active; pane.delete_selection().
    • .sit → Archives redirect (3dc0895) — InspectTab signals pending_open_archive; the app calls ArchivesTab::open_path + switches tabs.
    • Right pane cutoff (02926d5) — reserve separator/spacing width in CommanderMode::show's pane_w.
    • Rolling "applied operations" log for the Commander session — a timestamped session_log: Vec<String> on CommanderMode (capped at 200, rolling) with a top-bar Log (N) toggle opening a "Session log" window (Copy-all / Clear, sticks to bottom). Records: a pane's staged queue applied (CommanderPane::poll_apply success), host copies / exports (CommanderMode::poll_host_copy), and the immediate host writes (delete / rename / new folder). Panes surface completions via a new PaneResponse::log_events: Vec<String>, which CommanderMode timestamps via record_log.
    • Refine icon proportions (commander/mod.rs draw_copy_icon/draw_floppy/ draw_delete_icon) once seen in the app. Blocked: needs the running GUI — pixel-level visual polish, can't be judged headless.
    • Phase 2 — "Open Backup…" in a pane — a pane's source picker now offers show_backup_folder: true; SourceEvent::BackupFolder calls CommanderPane::load_backup_source, which parses the folder via backup_loader::load_backup_metadata (partition dropdown from the backup's partitions, backup_meta stored on the pane). open_partition branches to the new shared commander_source::session_for_backup_partition(folder, meta, index), which mirrors Inspect's per-compression open into a BrowseSession (raw none via source_path; zstd via a streaming ZstdStreamCache). Backup panes are read-only (a raw backup's source_path open_editable would write the partition file in place and desync metadata.json's checksum; zstd has no in-place editable session) — Apply/Discard/Edits, New Folder, Delete, Rename, copy-INTO, and the File Info metadata editors are all gated off; browse + copy-OUT (Copy-to-other / Export / Checksums / read-only File Info) remain. 4 model tests. Still deferred: CHD / WOZ backups and Clonezilla images (need the block-cache/scan machinery) — those surface a clean "not supported from a pane yet (use Inspect)" error.
    • Phase 2 — device parity: thread &[DiskDevice] (gui/mod.rs self.devices) into CommanderMode::showpane.showsource_bar; show_devices: true; handle SourceEvent::Device via an elevated open + probe + preopen BrowseSession. Untestable in sandbox; gated on the hardware verify above.
    • R4 — replace the removed Commander tree with the browse view's tree (§3.3). Blocked: large GUI refactor (lifts two working surfaces onto one shared tree model) that needs the running GUI to validate both still render — doable headless as compile+test only, but regression-prone without eyes on it.
    • Per-filesystem editable-metadata matrix — documented in editable_metadata_matrix.md: which optional EditableFilesystem setter each of the 26 editable FS implements vs. returns Unsupported (rename is universal; type/creator + dates + finder-info + rsrc-fork + bless + volume-name on HFS, a subset on HFS+/MFS, ProDOS type/access, ext permissions, PFS3 sym/hardlinks), plus the Commander File Info current-vs-available editor backlog.
    • HDZ "no files found" — likely RDB parsing of the inner .hdf after the gzip peel (commander_source::probe_partitions). Blocked: needs a real .hdz fixture — no RDB builder exists in-tree (only partition/rdb.rs's parser), and a synthetic disk likely wouldn't reproduce the real-world RDB layout (RDSK block, block size, geometry) that triggers the bug.
    • M7 Find/Search; M5 Compare; broad metadata-setter backlog (§10.2).

Deferred / blocked — what's actionable vs. what's waiting

Everything in the round-3/round-4 punch-list that can be built and verified without the running GUI or hardware is done. The four remaining items are each blocked on a resource the dev sandbox doesn't have:

ItemBlockerHow to unblock
Phase 2 device parity (#)Hardware — needs a real /dev/diskN + the unverified macOS elevation pathDo the hardware verify below first; then thread &[DiskDevice]pane.showsource_bar (show_devices: true) + handle SourceEvent::Device.
Refine icon proportionsRunning GUI — pixel polishRun the app, eyeball the middle-column copy/delete/floppy glyphs, tweak draw_* offsets.
R4 tree dedupRunning GUI — large refactor across two surfacesLift browse_view's tree onto a shared model; validate both Commander and browse_view trees render.
HDZ "no files"Fixture — needs a real .hdzObtain a real Amiga .hdz (gzip-wrapped RDB .hdf); reproduce, then fix RDB detection in probe_partitions.

The device-parity item is gated behind the macOS device-elevation hardware verify (commit ff36fa3): until that's confirmed on real hardware, building the Commander device path would only add untestable code on top of an unverified elevation path. Verify the elevation first, then build device parity.

Source-resolution unification (Inspect ⇄ Commander ⇄ CLI ⇄ TUI)

Triggered by two bugs (Commander couldn't open a Clonezilla backup; it auto- opened an APM Apple_Driver_IOKit driver partition and errored), both symptoms of source-resolution logic trapped in the Inspect view. The full plan — phases, stragglers, the .GHO note, the CLI stance, and acceptance criteria — lives in source_resolution_unification.md.

Status in brief: Phase 1 (gates → fs/, 3a4c208), Phase 2 (shared backup resolver, 60548a2), Phase 3 (cache-scan runner, 3e5fc5a), the CHD-backup fix (c1a7c2a), and the CONTRIBUTING layering rule (e188812) are done — both reported bugs are fixed. Phase 4 (Inspect adopting the resolver — the GUI unification) plus stragglers A–D (image probing, session building, the Clonezilla cache decision tree, single-file-chd convergence) remain; all need the running GUI to validate. See the plan doc.

Hands-on test checklist (round-4 — run in cargo run)

The round-4 work is browse/copy/log only (no destructive writes to backups), so it's safe to exercise against real images and backup folders:

  1. Session log: open Commander → top-bar shows Log (0). Apply a staged edit on an image pane, copy files to a host folder, delete/rename in a host pane → each bumps the count; open Log and confirm timestamped lines, newest at bottom; Copy all / Clear work.
  2. Open a backup folder: in a pane's source dropdown pick Open Backup folder…, choose a native rusty-backup folder (a zstd one and a none/ raw one). Confirm the partition dropdown lists the backed-up partitions and the volume browses (files visible).
  3. Backup pane is read-only: confirm no Apply/Discard/Edits buttons, no New Folder, and the row right-click menu shows only Copy/Export/Checksums/File Info (no Delete/Rename); File Info shows metadata + preview but no editor rows.
  4. Copy out of a backup: select files in the backup pane → Copy to other pane (onto a writable image → stages; onto a host pane → immediate) and Export to hard drive…; both should land real bytes; the export bumps the session log.
  5. Unsupported backups: open a CHD or Clonezilla backup folder → expect a clean "not supported from a pane yet (use Inspect)" message, not a crash or a bogus-MBR error.
  6. Hardware (the long-standing gate): in Inspect, open a real /dev/diskN and confirm the authopen admin prompt appears and the device reads (validates os/macos.rs open_device_for_inspect, commit ff36fa3). This is the prerequisite for Commander device parity.

Commits on this branch

660a81c  docs: per-filesystem editable-metadata matrix (round-4)
cfc76a1  commander: open a native backup folder in a pane, read-only (round-4)
4983990  commander: rolling "applied operations" session log (round-4)
c16022c  docs: handoff — mark round-3 A1/A2/A4 done, refresh punch-list + commits
02926d5  commander: stop the right pane clipping off-edge (round-3 A4)
3dc0895  inspect: route a picked Mac archive to the Archives tab (round-3 A2)
eee8070  commander: functional center Delete via active-pane tracking (round-3 A1)
0b58bde  docs: refresh Commander Mode plan + handoff to current state
522af44  commander: pictured icon buttons in the middle column
6eccbb8  commander: New Folder in both panes
2fba0bd  commander: round-2 UI fixes (collision, drop tree, dbl-click .., meta marker)
ff36fa3  os/macos: prompt for elevation on any device-open failure (read-only)
c1fb387  commander: "Keep original dates" on image-to-image copy
b55bc46  fs/affs: read files that span extension (T_LIST) blocks
07bd014  commander: Phase 3 — .adz/.hdz as editable gzip containers
7353247  commander/inspect: make the Mac-archives picker filter opt-in
2f8dfb1  commander: Phase 5 — metadata-edit UX (staged values, blue tint, edits list, dates)
2e41a11  commander: M1 widget extraction + M4 File Info window + R1 source picker + round-1
45a108c  commander: fix navigate_to path split on Windows host panes (CI-green; pushed)
--- earlier ---
<H2>     commander: host copy combos + host delete (H2)
8d4773e  commander: host-folder panes (browse) — PaneSource::Host (H1)
05664a4  commander: unsaved-changes guards on close / source switch (M3c)
fea01aa  commander: cross-pane copy via the middle column (M3b)
f72c69a  commander: per-pane staged delete + Apply/Discard (M3a)
627e989  commander: read-only two-pane browser over DirListing (M2-lite)
e7c3711  commander: add handoff/resume doc
c055273  commander: wire entry-point shell (overlay + tab-bar button)
57eb650  commander-mode: plan doc + runnable layout mock (no engine yet)

(Run git log --oneline upcoming-mister..commander-mode to see just this work; the H2 commit lands with this doc update.)

What's landed (done)

Round-4 (this session):

  • Rolling session logCommanderMode::session_log (rolling, capped 200) + a top-bar Log (N) window (Copy-all / Clear, sticks to bottom). Panes report completed data-changing ops via PaneResponse::log_events, drained per frame and timestamped by record_log. Sources: staged-queue applies (poll_apply), host copies / exports (poll_host_copy), immediate host delete / rename / new-folder.
  • Phase 2 "Open Backup folder" (read-only) — a pane can open a native rusty-backup folder. commander_source::session_for_backup_partition(folder, meta, idx) (new, 4 model tests) mirrors Inspect's per-compression open into a BrowseSession (raw none via source_path; zstd via a streaming ZstdStreamCache). Pane stores backup_meta; open_partition branches on it. Backup panes are read-only (a raw backup's open_editable would rewrite the partition file in place and desync metadata.json's checksum) — Apply/Discard/ Edits, New Folder, Delete, Rename, copy-INTO, and the File Info editors are gated off; browse + copy-OUT remain. CHD/WOZ/Clonezilla report a clean "use Inspect" error.
  • Per-FS editable-metadata matrixdocs/editable_metadata_matrix.md: audited all 26 editable filesystems for which optional EditableFilesystem setter each implements vs. Unsupported.

Earlier:

  • Plan docdocs/commander_mode.md (14 sections: locked decisions, architecture, reuse/refactor strategy, copy/staging semantics, drag-to-load, editable-metadata inventory §10, export/archiving crate inventory §9b, interaction model §9a, milestones M0–M5).
  • Runnable layout mockexamples/commander_mock.rs (throwaway, fake data). Demonstrates: two panes + middle column, multi-select (Ctrl/Cmd + Shift), sortable columns, editable @N path, copy icon + animated arrow, right-click context menu (copy/delete/undelete/info/export), delete-as-toggle + undelete, New Folder, per-pane Apply/Discard/Close, drag-to-load, File Info window + hex.
  • Entry-point shell (view layer)src/gui/commander/{mod,pane}.rs, launched from a "Commander Mode" button in the tab bar (src/gui/mod.rs). Opens a full-page overlay (Option<CommanderMode> on RustyBackupApp) that takes over the frame.
  • DirListing modelsrc/model/dir_listing.rs. Pure, unit-tested model: owns the open Box<dyn Filesystem>, a navigation stack of (dir, sorted children) frames, the active SortColumn/direction, and the name-keyed multi-selection + anchor. Methods: load_root, enter/up/reload, resort, current_rows, click/ctrl_click/shift_click/clear_selection. Folders-first stable sort; shared type_tag(&FileEntry) helper (also the sort key for the Type column). 10 tests (sort, parent-row, ctrl/shift selection, real-filesystem enter/up).
  • commander_source modelsrc/model/commander_source.rs. probe_partitions(path) peels any container (same way BrowseSession::open does) and returns the Vec<PartitionInfo>; session_for(path, &PartitionInfo) builds the pane's BrowseSession (offset via byte_offset(), FAT type-byte inference for superfloppies). Round-trip test on a real superfloppy.
  • CommanderPane bindingsrc/gui/commander/pane.rs. Source bar (Open + partition dropdown + Apply/Discard + volume/free readout), path line, async open via BrowseSession::spawn_open (spinner, polled each frame), and the listing grid (sortable headers, multi-select with Ctrl/Cmd + Shift, .. / double-click navigation) lifted from the mock.
  • commander_ops modelsrc/model/commander_ops.rs. apply_edits() opens the pane's source read-write, replays the EditQueue via apply_edit, syncs, and commits; spawn_apply() threads it behind an ApplyStatus. stage_copy() extracts selected entries (data + resource fork + HFS type/creator) to a temp dir and returns the AddFile/CreateDirectory edits to recreate them on the destination (directories recurse). 3 unit tests (apply delete+add, copy subtree).
  • M3a staged delete + Apply/Discard — right-click a row for Delete / Undelete / Remove-from-staging on the selection; Apply (threaded) writes and re-opens the source; Discard clears. Virtual overlay merges pending deletes (dimmed + strikethrough, - ) and pending adds (green, + ) in build_display_rows. EditQueue::remove_pending_delete added (with test).
  • M3b cross-pane copy — middle Copy L->R / R->L (and a per-row "Copy to other pane") stage an image→image copy onto the other pane's queue via stage_copy; CommanderMode owns a lazy temp TempDir and the copy direction; CommanderPane::show returns a PaneResponse { status, copy_to_other }.
  • M3c unsaved guard — Close with staged edits opens a Discard&Close / Cancel modal; switching a pane's source/partition with a non-empty queue opens a per-pane Discard&switch / Cancel confirm.
  • H1 host panes (browse)DirListing gains a ListingSource (None / Image(fs) / Host); a host pane lists via std::fs (size + chrono-formatted mtime), load_host_root opens a folder, up() re-roots a host pane above its loaded root, is_host() exposes the kind. Pane gets an "Open Folder..." button; partition dropdown / Apply / free-space are image-only. Host-listing + nav unit-tested.
  • H2 host copy combos + deletecommander_ops adds stage_host_to_image (host→image, real paths, no temp) and spawn_host_copy for the immediate image→host / host→host writes (threaded, HostCopyStatus); CommanderMode:: copy dispatches on (src_host, dest_host) across all four combos and polls pending_host_copy, re-listing the destination on completion. Host panes get a right-click immediate Delete behind a confirm. 3 new copy unit tests.
  • M6.1 Export to hard drive — a right-click "Export to hard drive..." action on any data row (image or host pane) pick_folders a destination and runs the existing spawn_host_copy (ImageToHost for an image source, HostToHost for a host source). Pure reuse: PaneResponse gains export_to_host, CommanderMode:: export builds the job, and pending_host_copy's destination side is now Option<Side> (None = export, so poll_host_copy skips the re-list). Excluded on not-yet-applied staged-add rows (no real data yet).
  • M6.3 Rename — new engine method EditableFilesystem::rename(parent, entry, new_name) (default Unsupported), now implemented in place for every editable filesystem (26): FAT, exFAT, NTFS, ext, UFS, EFS, HFS, HFS+, MFS, ProDOS, Apple DOS 3.3, CBM, Atari DOS, RS-DOS, DragonDOS, Acorn DFS/ADFS, OS-9, QDOS, Human68k, CP/M, AFFS, PFS3, SFS, XFS, Alto BFS. Each keeps the entry's identity (start cluster / inode / CNID / objectnode) and data; only the parent listing's name changes. Strategies vary by on-disk shape: fixed-field in-place overwrite (CBM/Atari/ProDOS/OS-9/RS-DOS/DragonDOS/DFS/ADFS/Human68k/MFS…), remove+add for variable-length dirents (exFAT/ext/UFS/EFS/PFS3/SFS), B-tree re-key + thread fix (HFS in-place Str31, HFS+ rebuilt variable thread), NTFS dual-write (index I30rekey+childI30 re-key + child `FILE_NAMEgrown/shrunk in place, sequence number preserved), AFFS hash-chain relink, XFS add-then-remove with matchedis_dirso the parent nlink ±1 cancels, BFS full-volume rebuild (DV entry + leader). Case-only renames allowed, real collisions rejected; 36 unit tests (incl. XFS fsck-clean, HFS+/NTFS persistence + grow/shrink). Model:StagedEdit::Rename+apply_editarm +EditQueue::{pending_rename_for, remove_pending_rename}. View: right-click "Rename..." (single entry) opens a name dialog validating via Filesystem::validate_name; image panes stage it (overlay shows old -> new, right-click "Cancel rename"), host panes rename immediately via std::fs::rename(existence-checked). Staging a delete drops any staged rename on the same entry. Rename is offered on any loaded pane (like Delete): browse-only filesystems (e.g. btrfs) surfaceUnsupportedat Apply rather than being pre-gated, so there is no per-typesupports_renametable to drift. **Follow-up:** a possiblerb-cli` rename verb reusing the trait method.
  • M6.2 Calculate Checksums — new model::checksum (added the sha1 crate): ChecksumHasher (a std::io::Write sink feeding crc32fast + md-5 + sha1 + sha2), hash_reader(reader, progress) -> ChecksumSet { crc32, md5, sha1, sha256 } with hex accessors, and spawn(ChecksumJob) threading a whole selection behind a ChecksumStatus (re-opens an image source on the worker, same as host copy; directories skipped). 4 unit tests (empty + "abc" known vectors, monotonic progress, writer==reader). View: right-click "Calculate checksums..." opens CommanderMode::checksums — an egui::Window with a per-file 4-row grid (monospace value + Copy button) and a live spinner/progress bar while hashing.
  • M6.4 Per-pane Tree view — a "Tree" toggle on each pane's source bar splits the pane into a lazy folder tree (left, navigation) + the flat grid (right, the working set). "Tree navigates, grid is the working set" — clicking a tree folder calls DirListing::navigate_to(path) to set the grid's cwd, so the existing selection / copy / delete / rename / checksum model is untouched. New on DirListing: root_entry(), list_dir(dir) (public lister, off-stack), navigate_to(path) (rebuilds the stack from root). The tree state (tree_cache: HashMap<path, child-dirs> + tree_expanded) lives on the pane and is dropped on every source/partition switch + host re-list; nodes lazily list child directories on first expansion (the browse_view CollapsingState pattern), side-keyed id_salt per node. 1 model test (navigate_to jump + up + back). NOTE: this is the contained version — it does not do the §3.3 R4 refactor (lifting browse_view onto the shared tree); browse_view still has its own directory_cache/expanded_paths. R4 dedup is a follow-up.

How to run it

# The runnable layout mock (fake data, no disk I/O):
cargo run --example commander_mock --features mock_gui

# The real app — click "Commander Mode" in the tab bar:
cargo run        # default features include `gui`

# The checks the pre-commit hook enforces (must be clean):
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo test --lib

Next step

The live, ordered punch-list is the round-3/round-4 list in the TL;DR above; everything buildable+verifiable headless is done. The four still-open items are each blocked on a resource the dev sandbox lacks — see the "Deferred / blocked" table above for each blocker and its unblock path. The single highest- leverage move is the macOS device-elevation hardware verify (ff36fa3): it clears the gate on Phase 2 device parity and is the only item a non-GUI session can't even start. Build each remaining item model-first (engine → model → thin view), unit-testing the model piece before the view.

Still-open backlog beyond the round-3 list (lower priority): the browsable-partition gate (lift is_browsable_type out of inspect_tab.rs); drag-to-load (§6, OS drop signals already wired in gui/mod.rs); archive Export (§9b — zip/tgz/sit); resource-fork sidecars on host copies; Apply-and-close in the unsaved guard (needs CommanderMode::temp alive until both applies finish); a possible rb-cli rename verb; M7 find/search (§15.5 — model::find::search recursive wildcard walk + a results grid mode).

Reuse map (do NOT reinvent these)

NeedReuse
open / list / open_editable / commit a sourcemodel::browse_session::BrowseSession
probe partitions + build a pane sessionmodel::commander_source::{probe_partitions, session_for} (new)
cwd / sorted rows / sort / multi-selection / navmodel::dir_listing::DirListing (new)
apply a queue / stage a copy / immediate host copymodel::commander_ops::{apply_edits, spawn_apply, stage_copy, stage_host_to_image, spawn_host_copy} (new)
staged copy/delete + applymodel::edit_queue::{EditQueue, StagedEdit, apply_edit}
picker extensionsmodel::file_types::DISK_IMAGE_EXTS
size / date formattingpartition::format_size, FileEntry::size_string() / .modified
metadata + hex detail, type/creator editor rowsextract from gui::browse_view (M1)
(devices, log) arg bundlegui::context::TabContext

Gotchas (learned during this work)

  • Patched eframe. This crate's eframe::App requires fn ui(&mut self, &mut egui::Ui, ..) (not stock update()), and panels are egui::Panel::top("id").show_inside(ui, ..) / CentralPanel::default() .show_inside(ui, ..). Follow src/gui/mod.rs and src/gui/commander/mod.rs.
  • id_salt per pane. Two near-identical panes render in one Ui tree, so every stateful widget (ScrollArea, ComboBox, CollapsingState, Grid) MUST take a side-keyed id_salt or egui raises an "ID clash" and one pane ghosts the other.
  • No Unicode glyphs in UI text (CONTRIBUTING hard rule) — ASCII only: .., <DIR>, ->, ^/v, A H S R. The animated copy arrow is painted (not a glyph). egui-time animation needs ui.ctx().request_repaint().
  • Layering (CONTRIBUTING). gui/ is a thin view — no orchestration, no background spawns (use a model runner / BrowseSession::spawn_open), no heavy state. State + queues live in model/.
  • mock_gui feature. The mock is gated behind mock_gui = ["dep:eframe", "dep:egui"] (no rfd) so the default cargo build --examples doesn't pull the gtk3 rfd tree. Run it with --features mock_gui.
  • macOS trackpad right-click / multi-select use egui's cross-platform Modifiers::command (= Cmd on macOS, Ctrl elsewhere) — already in the mock.

How to resume a session

Point a fresh session at this file:

"Resume Commander Mode. Read docs/commander_mode_handoff.md, then docs/commander_mode.md §15. We're on branch commander-mode. Browsing (image

  • host panes), all four copy combos, delete, and the unsaved guards are done. Build the M6 batch model-first per CONTRIBUTING.md (reusing DirListing / commander_ops / EditQueue): Export to hard drive (§15.3), Calculate Checksums (§15.2, add the sha1 crate), Rename (§15.1, needs an EditableFilesystem::rename trait method), then the per-pane Tree view (§15.4). Build with cargo run and click 'Commander Mode'."

Open questions still to settle are in commander_mode.md §14 (checksum set, rename scope, tree-view model, resource-fork sidecars on host copies, archive formats, function-key bar, persisting pane state).