Local Files
Terminality includes a Rust-native local file manager as a first-class Pane type. The WebView never touches the filesystem directly.
Safety by Design
File operations are descriptor-relative and generation-scoped:
- Every path must be absolute, normalized, and within a registered root capability.
- Directory components are opened with no-follow semantics — a swapped symlink cannot redirect traversal.
- Mutating actions accept only
(generation, index)references from the current listing — never caller-supplied paths. - Batches are non-empty, duplicate-free, and bounded to 100 entries.
Identity Verification
Each cached entry carries a native sidecar: Unix (device, inode) or Windows (volume, file index). The core re-verifies through the retained parent capability three times: before confirmation, after confirmation, and immediately before each side effect.
A same-name, same-kind replacement fails stale instead of inheriting consent.
Features
- Navigation: breadcrumb, parent, home. Platform roots (
/on Unix, logical volumes on Windows). - Large directories: paged rendering with hard entry limit.
- Multi-selection: generation-scoped, survives directory navigation within the same generation.
- Create / Rename: single filename component, atomic no-replace rename primitive — concurrent destination cannot be silently overwritten.
- Trash-only delete: macOS Trash, Windows Recycle Bin (with undo record), or Ubuntu trash portal /
gio trash.- Bounded, expiring, single-use prepare token freezes selections.
- Native platform adapter forces localized confirmation before the first side effect.
- No permanent-delete fallback. No automatic retry after indeterminate result.
- Native reveal: open in platform file manager.
What React Receives
The filesystem plugin is intentionally not granted to the WebView. React receives:
- Display/navigation paths for breadcrumbs and directory rendering.
- Bounded metadata snapshots (name, kind, size, modified).
- Typed commands:
navigateTo,goToParent,goToHome,activate,create,rename,trash,reveal.
Non-UTF-8 names are skipped and counted — never lossily converted into operable paths. Native errors cross as a small stable vocabulary; raw filesystem diagnostics are never logged or returned.
Architecture
React FilePane Component
→ FileServiceViewModel (binding)
→ FileService (Rust)
→ openat2 / CreateFile2 (platform adapter)PaneId remains stable. Replacing the Pane's content rotates PaneContentId, which invalidates its child ViewModel and owned directory snapshots — stale async results cannot publish into a new Pane generation.