Repository navigation
v0.9.0
Keyboard
- Presets for the program you come from. Four keymaps keep the keys of their programs: Norton Commander / Far (the default), Standard (Windows Explorer, VS Code, Total Commander), Neovim (Vim, vifm, oil.nvim, nvim-tree, with a
Spaceleader) and yazi. Each says what plain letters do: type into the command line (Far), jump to a file (Explorer) or act as commands (Vim, yazi). Key sequences (g g,Ctrl+w h), the leader key and Norton'sAlt+letter quick search are supported. The F1 help has a reference page per preset (generated from the presets,pairee keymap print --preset <name> --lang <code>prints it) and a "Coming from another program" guide. - Keyboard shortcuts list (
Ctrl+Kin Norton,Ctrl+K Ctrl+Sin Standard,g?in Neovim,~in yazi, Options → Keyboard shortcuts... in theF9menu, or Options → Configuration → Interface): every command of the panels, editor, viewer and dialog lists with its keys, searchable by name or by pressing a key.F2rebinds,Insadds a key,Delremoves,F8restores,Ctrl+←/→previews another preset,F9saves your preset. Changes apply at once. It replaces the which-key overlay; the command palette now shows each action's key. - New actions available in every preset: file clipboard (yank / cut / paste, paste overwriting, paste as link), recycle bin vs. permanent delete, select all, visual (range) selection, back / forward through visited folders, home and root folder, half-page moves, search in the panel with next / previous match, create a file or folder, rename the name only, copy name / folder path, focus a given panel, cycle view and sort, and Far's command-line keys (
Ctrl+Enter,Ctrl+F,Ctrl+E/Ctrl+X,Ctrl+Y) andCtrl+P/Ctrl+B. - Editor, viewer and dialog lists take their keys from the preset too, and help, screens, palette and the shortcuts list work over the editor and viewer with whatever key they have.
- Plugins declare commands with suggested keys per preset (
[[commands]]inmanifest.toml); they join the keymap, the palette and the shortcuts list, never take a key the preset uses, and can be rebound.pairee.keymap.list()/chord_for()read the keymap andpairee.emit()runs any action.
Changed (keyboard)
- Norton Commander / Far follows NC/Far again:
F7makes a folder,Shift+F6renames,Ctrl+Shift+F6is the multi-rename tool,F11opens plugins,Ctrl+\goes to the root, andAlt+letter is the quick search. Pairee's own keys moved toCtrl+Alt+letter: tabsCtrl+Alt+T/W/O, GitCtrl+Alt+G, SSHCtrl+Alt+R, folder sizesCtrl+Alt+S, disk usageCtrl+Alt+D, hotlistCtrl+Alt+B, quick filterCtrl+Alt+F; redo isAlt+Shift+Backspace. - The VSCode preset is now Standard (
vscodestill works as a name). Alt+F3opens the alternative viewer again.- The
F2user menu offers new tab (T), open in a new tab (O) and close tab (W) whileusermenu.tomldefines no commands of its own.
Migration
- Your keymap is updated automatically when the files in
keymaps/are copies Pairee wrote; a copy you edited is kept and the new version is saved next to it as<name>.toml.new. [custom_bindings]inkeybindings.tomlbecomes[overrides.all]. An override now replaces the action's keys and takes the key from the action that had it, instead of being rejected.- Plugin
[keybindings]tables keep working;[[commands]]is the new format.
Added
-
Undo and redo of file operations:
Alt+Backspace/ Files → Undo reverses the last rename, multi-rename, move, copy (only the new copies are deleted, never a file that overwrote another one), make folder, create link or send to trash (restored from the Recycle Bin / trash on Windows and Linux), andCtrl+Y/ Files → Redo repeats it. The menu shows the operation (Undo: Move (3 items)); a confirmation lists what will be reversed. Every entry is checked first (still there with the same size and date, original location free) and whatever changed is skipped and reported, never overwritten. Undo and redo run through the Transfer Engine and the rename executor. The journal keeps the last 50 operations in memory; permanent delete, wipe and SSH transfers are recorded as not undoable. -
Multi-rename tool (
Ctrl+Shift+F6in Norton, Files → Multi-Rename) for the selected items: name and extension masks with[N],[N2-5],[E],[P],[C](start, step, digits) and[Y][M][D][h][m][s]placeholders, search & replace (plain or regular expression, optional case-insensitive), case transform, and a live old → new preview that flags empty, invalid, duplicate and already-existing names. Renames are ordered so nothing is overwritten (swaps go through a temporary name) and are undone if one fails. Works on local and SSH panels. -
Commands → Synchronize folders (Total Commander "Synchronize dirs"): compares both panel folders recursively in the background (size and modification time with the configurable tolerance, optionally file contents with the transfer hash algorithm; filter mask with include/exclude globs; hidden files can be ignored), lists every difference with an action per item (copy →, copy ←, delete, skip) and totals of files and bytes, and applies the plan as Transfer Engine copy/delete jobs. Directions: left → right, right → left, both ways (newer wins) and mirror (deletes extras on the right, after an explicit confirmation).
-
Folder shortcuts can now be assigned: Commands → Folder shortcuts lists slots
Ctrl+Alt+1…Ctrl+Alt+9;Ins/Space(or the slot digit) assigns the current folder andDelclears it. Shortcuts are saved inbookmarks.tomlin the config folder. -
The directory hotlist (
Ctrl+\, also Commands → Directory hotlist) is now persistent:Ins/+adds the current folder,Del/-removes an entry. Default entries are localized. -
The Git panel has a key in every built-in keymap, as the menu already advertised.
-
Built-in keymaps now pick up newly shipped bindings even when an older copy of the keymap file exists in the config folder (user-defined chords always win).
-
Editor and viewer honor the "Tab size" settings when displaying tab characters.
-
Built-in editor: undo/redo (
Ctrl+Z/Ctrl+Y, typing runs are one step), save as (Shift+F2),Tabkey,Home/EndandCtrl+Home/Ctrl+End, horizontal scrolling for long lines, andF6in the viewer opens the file in the editor. Line endings (LF/CRLF), the final newline and the UTF-8 BOM are preserved on save. Saving asks before overwriting a file that another program changed or an existing "save as" target. Files that are not valid UTF-8 or larger than 64 MiB are refused with an explanation instead of being corrupted. -
Built-in editor: text selection with
Shift+ arrows/Home/End/PgUp/PgDn/Ctrl+Home/Ctrl+End,Ctrl+Aand mouse drag (the mouse wheel scrolls); vertical block selection withAlt+Shift+ arrows orAlt+ drag; copy/cut/paste withCtrl+C/Ctrl+X/Ctrl+V(alsoCtrl+Insert/Shift+Delete/Shift+Insert) through the system clipboard, falling back to an internal clipboard over SSH or without a display. Typing,BackspaceandDeletereplace the selection, each paste or cut is one undo step, and bracketed paste inserts every pasted line. The key bar showsShift+F2(save as) andShift+F7whileShiftis held, andF3(next match). -
Editor settings that had no effect now work and are back in Options → Configuration → Editor/Viewer: expand tabs, auto indent, show line numbers, cursor at the end, lock editing of read-only files and warn when opening read-only files.
-
Panel visibility, view mode, sort order and long-names mode from the last Save setup are the defaults of the panels when there is no session to restore.
-
Session restore (new setting Restore last session,
restore_session, on by default, Options → Configuration → Interface): on exit Pairee saves every tab of both panels (folder, archive, view, sort, filter, name, lock, entry under the cursor), the shown tab per side, the focused side, panel visibility and Quick View tosession.toml(atomic write, owner-only on Unix) and reopens them at startup. Missing folders open their nearest existing parent; SFTP tabs are saved by SSH preset name (never a password) and reconnect only when shown, falling back to the home folder with a notice; a damaged file is ignored with a logged warning and kept assession.toml.bak. -
Command-line folders:
pairee <left> [<right>]opens them in the shown tab of each panel (overriding the restored ones; a file opens its folder with the cursor on it).--cwd-file <file>writes the focused panel's folder on exit so a shell wrapper cancdthere, and--print-cwdprints it; wrapper functions for bash, zsh, fish and PowerShell are in the user guide and README. -
The "natural" sorting collation now sorts numbers inside names numerically.
-
pairee.fs.data_dir()returns the plugin's private data directory, the only location an untrusted plugin may write to. -
Support for untracked files in the Git diff viewer, allowing inspection of newly added files with full contents.
-
Home and End key navigation in the unified Git diff viewer.
-
Context-sensitive empty list notifications across all Git panel tabs (Log, Branches, Stash, and Tags).
-
Full suite of unit tests for file diffs (staged, unstaged, untracked), commit diffs, and stash diffs.
-
Clipboard paste support (
Ctrl+V) in the Git clone dialog to easily paste repository URLs and target directory names. -
Detection and notice for modified and untracked binary files in the unified Git diff viewer.
-
Guard and modal error notification preventing deletion of the currently checked-out branch in the Git panel.
-
Validation guard preventing commit amend (
Ctrl+A) on repositories without prior commits. -
Protection and modal alert preventing push and pull operations while HEAD is in detached state.
-
Mode localization (
Soft,Mixed,Hard) in Git commit reset confirmation prompts. -
Informative notice when attempting to commit with clean working copy and no amend mode.
-
Internal viewer (F3) and Quick View detect the text encoding: byte-order mark (UTF-8, UTF-16 LE/BE), UTF-16 without a mark, UTF-8, and otherwise the most likely legacy code page via
chardetng(Windows-1252/Latin-1, other Windows/ISO code pages, Shift-JIS, EUC, GBK, Big5...), decoded withencoding_rs. Text in another encoding is no longer treated as binary. The viewer shows the encoding in its new status line andF8opens a list to switch it manually. New settingsviewer_autodetect_codepageandviewer_default_codepage(Options → Configuration → Editor/Viewer). -
Plugins can declare the programs they need in
manifest.toml([permissions] commands = [...]); the Plugin Manager shows them in the plugin details. -
Folder sizes:
SpaceorF3on a folder, or Commands → Folder sizes (selected folders, or all of them), computes the size in the background and shows it in the size column and status line until the directory changes;Esccancels. Symbolic links are not followed, hard links count once on Unix, and folders that could not be read completely are marked with+. Works on SFTP panels too. -
Disk usage view (Commands → Disk usage): ncdu-like list of the current folder sorted by size with percentages and bars, cancellable scan with live progress, navigation into subfolders and back, deletion through the regular delete confirmation and rescan (
r/F5). Scan results are cached per folder. -
Archives as folders:
EnterorCtrl+PgDn(newopen_archiveaction) on a zip, tar, tar.gz/tgz or 7z file opens it in the panel; subfolders open withEnter, the title shows the path inside the archive and..(orBackspace/Ctrl+PgUp) at its root returns to the containing folder with the cursor on the archive.F5copies the selection out through the Transfer Engine with the safe extractor (no traversal, no writing through links, no overwrite, size limits). Zip archives also accept copies into them, new folders (F7) and deletions (F8), applied by rewriting the archive to a temporary file and atomically replacing it; tar and 7z archives are read-only. Unsupported actions inside an archive (and archives on SSH panels or inside other archives) show a clear message. Plain.tarfiles are now recognized, andF7on an SFTP panel now creates the folder on the server. -
Folder tabs per panel (Double Commander / Far style): a new tab (
Ctrl+Alt+Tin Norton,Ctrl+Tin Standard) opens on the current folder,Ctrl+Alt+OorCtrl+Enteropens the folder or archive under the cursor in a new tab,Ctrl+Alt+Wcloses a tab (never the last one),Alt+PgDn/Alt+PgUp(alsoAlt+Right/Alt+Leftin Norton) switch,Alt+Shift+PgUp/Alt+Shift+PgDnmove a tab andAlt+1…Alt+9jump to a tab. Each tab keeps its own folder and source (local, SFTP, archive), cursor, selection, view, sort, filter and folder sizes, and keeps loading in the background while another tab is shown. A one-line tab bar appears above a panel with more than one tab (new setting Always show tab bar,always_show_tab_bar); titles are shortened with…, a click switches tabs and a middle click closes one. Left/Right → Tabs lists every tab command, plus Rename tab and Lock tab (a locked tab stays on its folder and opens other folders in new tabs).Ctrl+TabandCtrl+Wkeep switching screens and opening the task list. -
Automatic panel refresh: the folder shown by each side's active tab is watched with native notifications (
notify, non-recursive) and reread in the background when another program changes it, keeping cursor and selection and without the "Loading…" title; Git badges are updated with the listing and computed folder sizes of changed folders are measured again. Changes are coalesced (250 ms of quiet, at most 2 s during a sustained burst such as a large copy: about 6,000 events in 3 s give 2 rereads). Network shares (SMB/NFS mapped drives, UNC and\\wsl$paths), 9p/drvfs/FUSE mounts on Linux and folders whose watch cannot be set up are polled instead (modification time + entry count). Folders abovedisable_panel_update_object_countare not refreshed automatically at all, as the setting's name says. Archive tabs are not watched; SFTP tabs are polled over their connection (stat+ listing through the panel source) when the new setting Also poll SFTP panel folders (auto_refresh_ssh, off) is on, every SFTP poll interval (auto_refresh_ssh_poll_secs, 30 s). New settings Refresh panels automatically when folders change (auto_refresh, on) and Poll interval for network folders (auto_refresh_poll_secs, 3 s) in Options → Configuration → Panel. -
SFTP panels get back what the panel source refactor had marked as unavailable: renaming in place works on the server (refusing an existing name, undoable),
F4edits a remote file through a private local copy that is uploaded on save after checking that the original did not change meanwhile (size and time; asks before overwriting), andCtrl+Ashows permissions, numeric owner and modification time and changes the mode with SFTPsetstat(chmod). The sameF4flow edits files inside zip archives. A move between two panels on the same SFTP connection (a server-side rename) is now journaled and can be undone; other SSH copies, moves and deletions stay "not undoable". -
.tar.bz2/.tbz2/.tbzand.tar.xz/.txzarchives open as folders, list in Quick View and extract natively (pure-Rustbzip2andlzma-rust2decoders, so static musl builds are unaffected). A bare.bz2/.xzfile is not treated as a folder. -
Archives inside archives open as folders (read-only): the inner archive is extracted to a private temporary file, in the background on its first listing and up to 512 MiB, then listed, viewed and previewed like any other archive;
..at its root returns to the containing archive. Copies, edits and deletions inside a nested archive are refused with a message. -
Default keys for Folder sizes and Disk usage in every built-in keymap (
Ctrl+Alt+S/Ctrl+Alt+Din Norton; a test checks it).
Improved
- Commands → Compare folders is now recursive (a folder on both sides is reported as different when anything inside differs) and runs in the background with a progress popup;
Esccancels it. - The Screens menu and the development-plugin picker now use the theme's selection colors, like the other list popups.
- Text fields in dialogs (make folder, rename, copy/move destination, compress, apply command, describe, link, filters, select group) now share one input box: the cursor can be moved with Left/Right/Home/End, Delete removes the character under it,
Ctrl+Vpastes from the clipboard, and non-ASCII text is edited by whole characters. - Panels are now read in the background: the directory listing, SFTP listing, Git status and free space no longer block the interface, the panel title shows "⟳ Loading…" while a read is in progress, and the cursor and selection are kept when the new listing arrives. Entering a directory rereads only that panel, and Git status is computed only for the listed directory instead of the whole repository.
- Git fetch, pull, push, push tags, remote branch deletion and clone now run in the background with a progress popup (objects and bytes transferred);
Esccancels the operation. The Left/Right menus no longer open the repository while drawing. - Quick view loads previews in the background after the cursor settles (no more stalls when scrolling through large files), caches recent previews per file version, and reads at most 16 MiB per file. The F3 viewer reads files page by page through a small block cache with a line index built in the background, so multi-gigabyte files open instantly with bounded memory (the status line shows the line count growing while indexing); hex mode uses the same paged reads. Viewer search (
F7,F3to repeat) runs in the background over the whole file, shows its progress and is cancelled withEsc. Quick View reads only the first 256 KiB of a text file. The viewer shows the error instead of an empty viewer when the file cannot be read. - The Git panel opens immediately and reads status, log, branches, stashes and tags in the background (the title shows "⟳ Loading…"); refreshing after an operation or with
r/F5keeps the current contents on screen until the new data arrives, outdated results are discarded, and older log pages load in the background while scrolling. Loading the panel no longer reads the repository on the UI thread. After applying a stash the success notice now opens over the panel instead of closing it. - Local Git panel operations (stage, unstage, stage/unstage all, discard, add to
.gitignore, file/commit/stash diffs, commit, stash save/apply/pop/drop/clear, branch create/rename/delete/checkout, merge, rebase, reset, cherry-pick, revert, tag create/delete, remotes) no longer touch the repository on the key handler: they run as background jobs (one genericapp::git_localjob), the panel title shows "⟳ Working…" while one runs, the panel is then re-read by the background loader, and failures that used to be silent (stage, unstage,.gitignore, diff) now open the localized error over the panel. Success and conflict notices open over the panel instead of closing it. - Quick view loads previews in the background after the cursor settles (no more stalls when scrolling through large files), caches recent previews per file version, and reads at most 16 MiB per file. The F3 viewer also loads in the background, reads at most 64 MiB (larger files are shown truncated with a notice) and shows the error instead of an empty viewer when the file cannot be read.
- Detailed, Owners and Links views no longer read file attributes on every repaint, and the free-space footer no longer queries the disk on every repaint; both are refreshed with the listing.
- Release builds now use thin LTO, a single codegen unit and stripped symbols for a smaller, faster binary.
- Untracked file badges and labels in Git panel now render in Magenta for consistent contrast and readability across dark backgrounds.
- Enhanced scroll behavior in the Git diff viewer for short files.
- Centralized all Git operation error alerts, conflict notifications, confirmation prompts, and buttons into localization catalogs with zero hardcoding.
- Internal: the "do not overwrite an invalid
config.tomluntil confirmed" lock and the startup load error now live inAppConfig(ConfigLoadState) instead of process-wide globals. - Internal: the panel source port gained an
attributescapability (Vfs::attributes/Vfs::set_attributes), and one-off background changes of a non-local source (AppState::start_vfs_task) return a follow-up command that runs on the UI thread (open the editor, show a dialog). - Internal: panels, folder sizes, the disk usage view, multi-rename and SSH copy/move/delete now go through one panel source port (
fs::vfs::Vfs, Ports & Adapters) with local and SFTP adapters and capability flags, replacing the separateDuSource,RenameBackendandRemoteFstraits and the per-feature "local or SSH" branches. Panels keep aPanelSourceinstead of an optional SSH connection. Folder links inside a tree uploaded or downloaded over SSH are created as folders but not followed. - The viewer (
F3) and Quick View read through the panel's source: entries of an archive panel and files on SFTP panels open in the viewer and preview (read into memory, up to 64 MiB; local files are still paged from disk). Images are decoded from the bytes read, so they preview inside archives too. - Internal: each panel side now holds a list of folder tabs (
app::state::tabs); a tab owns the whole panel state (location and source, listing, cursor, selection, view, sort, filters, folder sizes) and its background jobs, identified by a stableTabId, so listings and SSH connections finish in the tab that started them even after switching tabs. Tabs describe themselves as a plain, serializableTabSpec. - Internal:
bookmarks.toml,history.tomland the newsession.tomlshare one TOML state-file store (config::toml_store): tolerant reads and atomic writes (owner-only0600on Unix); the history file is no longer rewritten in place. - Commands → Compare folders reads both panels through their source, so a folder inside an archive or on an SFTP server can be compared with any other panel (content hashes are computed from the source too). Synchronize folders also works with folders inside archives (zip archives accept the copies and deletions); only SFTP panels are refused, with a clearer message.
- Internal: no function is longer than 100 lines any more (
clippy::too_many_linesis enforced in CI): long key, action and plugin-request dispatchers became per-group handlers and tables, and long renderers small render steps; duplicated code is down to 0.73% (jscpd).
Deprecated
Removed
- External editor support: Pairee edits files only with its built-in editor. F4 and every other "edit" entry point always open the internal editor. The
editor_use_externalanddefault_editorsettings are gone (oldconfig.tomlfiles that still contain them load fine), and the default file associations no longer launchnotepad/nanofor text files; untouched old default rules of that kind are removed fromassociations.tomlon load. - Settings that had no effect (file descriptions, info panel details, dialog/command-line editing, editor code pages and blocks, most viewer options, plugin manager flags,
git_auto_detect,transfer_engine_enabledand some confirmations) were removed from the configuration, the dialog and the manuals. Oldconfig.tomlfiles that still contain them load fine; the keys are dropped on the next save. Seedocs/technical/settings-audit.md.
Fixed
- Keymaps: the
Ctrl+Shift+<letter>bindings of the shipped presets (copy path, command palette, key overlay, SSH and, in VSCode, make folder, view, history, refresh, tree, quick view) were rejected by the key parser and never worked; they are now written asCtrl+<UPPERCASE>and the old spelling is accepted in user files. The VSCode keymap no longer bindsF2twice (user menu moved toAlt+U) norCtrl+Ftwice (find file isCtrl+Shift+F), swap panels isCtrl+U(it collided with SSH),Ctrl+,(settings, writtenCtrl+Comma) andCtrl+.(hidden files) now load, and the NeoVim keymap lost an unknownchange_panel_tabentry. A test loads the three presets and requires zero errors, warnings and duplicate chords. - F-key bar: the panel rows (plain,
Shift,Ctrl,Alt) are now built from the active keymap through one action → label table, soShift+F1–F3(pack, unpack, archive commands),Shift+F9(save setup),Shift+F10(context menu),Alt+F11/Alt+F12(histories) show their labels, and keys a keymap leaves unbound are blank instead of showing Norton defaults.Ctrl+Pnow also cycles to theShiftrow. - Built-in editor: block selection without
Alt+Shift+ arrows, which Windows Terminal keeps for itself:Ctrl+Btoggles block mode (the status line shows it), whereShift+ arrows and mouse drags select a vertical block;Ctrl+Alt+Shift+ arrows also select a block. - Multi-rename preview: the table has a scrollbar (drag or click) and scrolls with the mouse wheel. The mouse wheel now scrolls the list or text under the pointer (Git panel, histories, help, transfer lists, panels…) instead of always the topmost one, three rows per step; away from any scrollable view it keeps scrolling the topmost.
- Disk usage view: deleting an item on an SFTP panel left it in the list until a rescan; deleted items now leave the tree when the delete job finishes, for every source, instead of the view polling the local disk on every frame.
- Folder sizes were kept after a reread of the same folder even when a folder's contents had changed; folders whose modification time changed in the new listing are now measured again (watcher-reported changes still invalidate at once).
- Copying into a zip archive no longer silently replaces entries that already exist: the copy dialog's conflict choice (overwrite, overwrite older, skip, rename, ask with the usual conflict dialog) applies, through the same resolver as local copies. Copies into or out of archives and deletions inside them now appear in the undo journal as not undoable instead of not at all.
- Auto-refresh: a file created or deleted right after entering a folder (while its watch was still being set up) never showed up until the next change; a folder modified just before its monitor is armed is now reread once.
- Archives: copying a single item out of an archive (or a single file into a zip) with the destination
F5suggests (<folder>/<name>) created a folder with the item's name and put the item inside it (b.txt/b.txt); the suggested path is now the target itself, as for local copies. - Copy/move filter masks: an exclusion such as
!targetnow also skips folders with that name (it only applied to files, so excluded folders were still copied in full). - Folder compare: files copied to or from FAT/exFAT drives were reported as "Different" because the modification-time tolerance was 1 second; it is now 2 seconds and configurable with
compare_mtime_tolerance_secsinconfig.toml. On Windows and macOS names are matched ignoring case (README.txtandreadme.txtare the same file there), and comparing a remote (SSH) panel now shows a clear message instead of reading a local path with the same name. - Configuration dialog: editing the plugin developer folder now shows the text being typed (it kept showing the old path), and text fields there support cursor movement and paste like other dialogs.
- Search highlighting in the viewer and editor no longer misaligns (or can panic) on lines containing characters whose lowercase form is longer, such as 'İ'.
- Git panel: the "rename branch" prompt opened with no field focused (typing did nothing until the arrows were pressed); it now starts on the name field.
- Create link: typing
sorhin the link name switched between symbolic and hard link instead of inserting the letter; the link type is now toggled withTab(shown in the dialog hint). - Move (F6) with "Confirm move" turned off ignored the transfer settings (it always disabled attribute preservation, write-cache bypass and symlink handling and asked on conflicts); it now uses them exactly like Copy does.
- Removed several crash paths: Git panel sub-dialogs, copy/move filter and tree prompts no longer
unwrapthe open dialog, file panels never slice out of range while drawing, and popups are no longer cloned on every key press (the Git panel and image quick view were deep-copied per key). - Transfers: a panic in one transfer no longer cascades into crashes of the whole application through poisoned locks; the "file exists" prompt no longer polls every 100 ms (the worker is woken by the answer or by cancelling the job), and copy progress updates are coalesced so a fast copy cannot flood the interface.
- File owner names on Linux/macOS:
/etc/passwdis parsed once per session instead of being re-read for every file whose owner is unknown. - SSH: blocking SSH/SFTP calls now time out after
ssh_timeout_secsseconds (new setting inconfig.toml, default 30; 0 disables it) instead of hanging forever on a dead server. Connecting and SSH copy/move/delete jobs run on the blocking thread pool, and the panel title no longer locks the SSH session while drawing. - SSH: deleting a remote folder with nested subfolders failed because a directory was removed before its subdirectories were emptied; remote recursive delete now removes children first, and symbolic links to directories are removed as links instead of being followed.
- Compressing a folder to ZIP now keeps its subfolder structure; previously file names were glued together (e.g.
projectsubfile.txtinstead ofproject/sub/file.txt). - The "Save commands / folders / view and edit history" settings are now honored: disabled categories are no longer written to or restored from
history.toml. - Symbolic links to directories are listed and opened as directories instead of files.
- On Windows, files with the Hidden attribute are hidden unless "Show hidden files" is on.
- Delete to Recycle Bin now uses the system trash on Linux, macOS and Windows; when the trash is unavailable the item is kept and an error is shown, instead of being deleted permanently.
- "Disable panel update if object count exceeds" no longer prevents opening a large directory; it only skips automatic rereads of the same directory, and
Ctrl+Ralways rereads. - Keyboard shortcuts help: removed the duplicated
Ctrl+Lentry, repaired the selection table, documented thatCtrl+H/Ctrl+I/Ctrl+Mneed the kitty keyboard protocol (with rebinding examples), and fixed broken links to other manuals. - Fixed crashes in the built-in editor, the Git commit prompt and editor search when typing or moving the cursor over non-ASCII text (e.g.
ñ,á, emoji, combining accents); cursor movement, Backspace and Delete now operate on whole grapheme clusters via a shared text-input helper. - Fixed the terminal being left in raw mode / alternate screen with mouse capture after a crash: a panic hook now restores the terminal and logs the panic before printing it.
- Fixed an invalid
config.tomlsilently falling back to defaults and later being overwritten: the file is now backed up toconfig.toml.bak, a localized error is shown at startup, and it is not overwritten until the user confirms via Options > Save setup. - Failed writes of
config.tomlduring startup are now logged instead of ignored. - Security: Untrusted plugins now always have
pairee.fsjailed to their own directory (read) and private data directory (read/write), regardless of Secure Mode; previously they had unrestricted filesystem access unless Secure Mode was enabled. - Security: Secure Mode can no longer be disabled from Lua: the flag is captured in Rust instead of being read from the writable
pairee._secure_modeglobal (now informational only). - Security: Plugin path checks now normalize
..and resolve symlinks through the nearest existing parent, closing a Secure Mode bypass via..on non-existent paths. - Security: User menu commands expand
{f}/{p}in a single pass, so a file name such as;id;{p}can no longer break shell quoting. - Security: Registry plugin installs reject
[files]entries that escape the plugin directory, validate plugin name/author, and verify each file's SHA-256 before writing it to disk. - Security: The self-updater now requires the release
.sha256asset, only downloads fromhttps://github.com/FittyAr/Pairee/releases/download/, verifies the artifact in memory and installs from that same buffer (no shared, predictablepairee_updatetemp dir, no verify→extract race). SHA-256 now uses thesha2crate instead of a hand-rolled implementation. - Security: Secure wipe no longer follows symbolic links or junctions: wiping a link removes only the link and never overwrites its target.
- Security: The 7-Zip helper downloaded on Windows is verified against a pinned SHA-256 before use; RAR/ISO extraction via external 7z now refuses to run when the archive cannot be listed and validated first.
- Security: Archive extraction (zip, tar.gz, 7z, RAR/ISO) never overwrites existing files (they are skipped and listed in the job results), never writes through symlinks already present in the destination, and aborts archives with more than 500,000 entries or 32 GiB of uncompressed data.
- Security:
config.tomland other config files are written with0600permissions on Unix. - Security: Secure Mode's plugin command blacklist normalizes names (case, path,
.exe/.cmd/.bat… extensions, version suffixes) and now also blockswscript,cscript,mshta,rundll32,env,osascript,busybox, more shells and interpreters, and command wrappers. - Security: Plugin Lua states have a memory limit and a watchdog that aborts runaway scripts (e.g. infinite loops) instead of freezing Pairee.
- Security:
install.sh/install.ps1fail on HTTP errors (curl -fsSL), validate the release tag and verify the downloaded archive against its.sha256before extracting. - Fixed file panel views to properly honor the
git_enabledsetting when rendering Git status badges. - Fixed silent no-op when attempting to delete the active checked-out branch in the Git branches tab.
- Fixed obscure failure when attempting to toggle commit amend on an empty repository without previous commits.
- Fixed duplicate placeholder replacement in branch merge confirmation dialog which mistakenly duplicated the source branch name instead of showing the target branch.
- Fixed duplicate placeholder replacement in commit reset confirmation dialog which hid the reset mode (Soft/Mixed/Hard).
- Fixed newly initialized repositories with zero commits showing
(detached HEAD)instead of their initial branch name (e.g.masterormain). - Fixed push tags without configured remotes failing with obscure libgit2 error.
- Security: Secure Mode now uses a command allowlist for plugins instead of a name blacklist: a plugin may only run programs declared in its manifest, by name, resolved through
PATH(no explicit or relative paths, no.bat/.cmd), and shells or interpreters are refused even if declared or reached through a symlink. A renamed binary can no longer slip through. - On Windows, commands run from the command line, the user menu and apply-command now reach
cmd.exeunmodified: quotes are no longer mangled, and file names containing%VAR%,&,^,!,(,)or quotes are passed literally instead of being expanded or split. - Security: On Windows, opening a file with no association uses the system handler directly (
ShellExecuteW) instead ofcmd /c start, so the file name is never parsed by the shell. - Security: Jailed plugin file operations (
pairee.fsread, write, mkdir, remove, rename, copy, list) now run through a directory handle of the allowed root, so a folder swapped for a symlink or junction after the path check can no longer redirect them outside the jail. - Security: Updates are now signed: the self-updater requires a minisign signature (
.minisig) for the downloaded release asset in addition to the SHA-256 checksum and refuses to install if it is missing or invalid. The install scripts verify the signature whenminisignis installed.