Files
miniSCP/docs/platform-notes.md
jgamboaandClaude 8f8f230711 Remap any shortcut in Settings → Keyboard; the macOS menu bar follows
A Keyboard section in the Settings window edits the shared keymap: rows
by group with a search field, a chip per key (x removes), + to record,
reset per row and Reset all. Recording takes the keydown before every
other key in the window (Cmd+W records instead of closing), refuses
reserved combos without preventDefault (Cmd+Q still quits), requires a
chord or F-key for editor commands, and offers Replace when another
command in an overlapping scope owns the key. Rows flag conflicts and
plain character keys that would stop starting a type-to-filter query.
Fixed keys are listed read-only, in the platform's spelling.

Remaps are ordinary settings (only rows that differ from the defaults),
so every window, the menu hints and the tooltips follow live — and the
macOS menu bar: its accelerators are built from the keymap (only the
combos Electrobun's parser expresses faithfully) and rebuilt on a remap.
A main-window menu action fired from the editor or Settings window
brings the main window forward first.

Also: the "Enter / double-click on a file" setting under File list (do
nothing / open local files in their default app), arrow keys in the
Settings sidebar with focus on open and a hand-walked Tab, translations
for all seven languages (the spec now checks every language labels every
command), and a README shortcut table generated from the keymap.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-05 14:57:27 +02:00

193 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Platform notes — macOS / Windows / Linux behavior matrix
macOS (Apple Silicon) is the primary target; Windows 11+ x64 and Linux x64 are
**beta** targets (win-arm64 and linux-arm64 deferred). **Intel Macs were
dropped** with the move to Electrobun 2.x, which publishes no macOS x64 core.
Every platform seam carries a `PORTABILITY:` comment at the branch site.
## Seam inventory (where platform branches live)
| Concern | File | mac | win | linux |
|---|---|---|---|---|
| Window chrome | `src/bun/windows.ts chromeOptions` | hiddenInset + traffic-light offset, UI drag header | native titlebar, compact header | same as win |
| Scrollbars | `ui/src/styles.css` (`::-webkit-scrollbar`) | custom square, always visible (styling them turns off overlay scrollbars) | custom square | custom square |
| External editor launch | `src/bun/edits.ts launchEditor` | `open [-a app]` | `cmd /c start "" [app] file` | app directly / `xdg-open` |
| Editor app picker | `rpc-handlers.ts pickEditorApp` | /Applications, `.app` | %ProgramFiles%, `.exe` | home, any |
| Owner/group names | `fs/local.ts resolveId` | `id -nu` + `dscacheutil` | undefined → "—" | `id -nu` + `getent` |
| Drive roots | `fs/local.ts listLocalDrives` | empty | `fsutil fsinfo drives` | empty |
| chmod/Permissions | context-menu.service.ts, file-panel, file-actions | full | hidden for LOCAL panels (only flips read-only); SFTP unaffected | full |
| Shell wording | `ui context-menu.service.ts` | Reveal in Finder / Move to Trash | Show in Explorer / Move to Recycle Bin | Show in File Manager |
| Shortcut labels | `src/shared/keymap.ts formatCombo` (+ `keys.names.*`) | ⌘⇧⌥⌃ glyphs: ⇧⌘N | Ctrl+Shift+N, localized key names (Strg+Entf) | as Windows |
| Command modifier | `keymap.ts` `Mod` | ⌘ only (⌃ stays Cocoa's text keys) | Ctrl | Ctrl |
| Key equivalents | `shortcuts.service.ts claim` | page first, unclaimed → app menu | page only (no app menu) | page only |
| Tab focus | `core/focus-cycle.ts cycleFocus` | WKWebView skips buttons/checkboxes without Keyboard navigation → walked by hand | native order (same walk) | native order (same walk) |
| Reload keys | `platform.ts blockReloadKeys` | — | WebView2 reloads on F5 / Ctrl+R → swallowed when unclaimed | — |
| Tray | `src/bun/tray.ts` | 22 pt template PNG | 16 px colored PNG | colored (needs AppIndicator, see below) |
| App menu | `src/bun/menu.ts` | full menu incl. About; accelerators follow the keymap (remaps included), ⌘Q fixed | none (early return) — Settings opens from the tab-bar gear (Ctrl+,), About from its About section | none (unsupported upstream) |
| connections.json protection | `store/connections.ts` | chmod 0600 | `icacls` current-user ACL (0600 is meaningless) | 0600 |
| App data dir | `store/paths.ts` | ~/Library/Application Support | %APPDATA% | $XDG_CONFIG_HOME/.config |
| ssh-agent | `fs/sftp.ts` | $SSH_AUTH_SOCK | `\\.\pipe\openssh-ssh-agent` fallback | $SSH_AUTH_SOCK |
| Paths in UI | `ui format.ts joinPath/isRootPath` | "/" | separator detected from the dir string; drive-root regex | "/" |
The **context menu is HTML on every platform** (`ui/src/app/skins/shadlike/context-menu.ts` +
`context-menu.service.ts`), not a native electrobun menu — see the Linux section
below for why. Only the three shell actions it can't do itself (reveal, open with
the default app, copy path) cross to bun, via the `shellItemAction` RPC.
Remote (SFTP) paths are ALWAYS POSIX regardless of host or server OS
(`path.posix` throughout `fs/sftp.ts`).
## Memory footprint (expected, not a bug)
Investigated 2026-07 — packaged build. Roughly **~200 MB macOS / ~300 MB
Windows** (Linux sits near macOS: WebKitGTK, like WKWebView, is lighter than
Chromium), which is normal for a Bun + system-WebView app (30 MB is native /
no-web-engine territory; Tauri-class apps run ~80–200 MB, Electron 150–400 MB).
Not reducible to tens of MB without dropping the web UI.
- macOS splits across several "miniSCP" processes: the **Bun main** (~120 MB:
backend + the bundled electrobun runtime + live SSH sessions — the largest and
least reducible piece), the **`views://app`** WKWebView content process (~60 MB,
the Angular UI), and the standard WebKit **Networking** / **Graphics and
Media** helpers. All are one app; WebKit just names them per-role.
- Windows is higher because **WebView2 is Chromium** (multi-process: browser +
GPU + renderer + utility + crashpad), vs macOS's lighter WKWebKit.
- Measure against a **packaged** build — `bun run dev` inflates the WebContent
heap (ng-serve, unminified, sourcemaps, live-reload) and is not representative.
- Verified non-issues: transfers stream (no whole-file buffering), icons
tree-shaken to ~33 glyphs, zoneless Angular, 364 KB prod bundle.
- Only real growth levers if this ever matters: the file list is **not
virtualized** (a directory with tens of thousands of entries retains a DOM row
each), and each open tab keeps both panels' full `entries` arrays; terminal
transfers are retained until cleared. None affect normal use.
## Linux runtime dependencies (REQUIRED — the app will not start without them)
electrobun's `libNativeWrapper.so` links AppIndicator *hard* for the tray, so a
missing library is a hard boot failure (`ERR_DLOPEN_FAILED` out of `bun:ffi`
`dlopen`), not a degraded tray. The transitive deps (`libdbusmenu-glib`,
`libdbusmenu-gtk3`, `libayatana-indicator3`, `libayatana-ido3`) come in as
package dependencies:
| Distro | Install |
|---|---|
| Arch / CachyOS | `sudo pacman -S libayatana-appindicator` |
| Debian / Ubuntu | `sudo apt install libayatana-appindicator3-1` |
| Fedora | `sudo dnf install libayatana-appindicator-gtk3` |
GTK/WebKit itself comes from the distro too — electrobun uses the system webview
(`bundleCEF: false`), so `webkit2gtk` must be present.
Diagnosing a boot failure:
```sh
ldd build/dev-linux-x64/*/bin/libNativeWrapper.so | grep 'not found'
```
`libasar.so => not found` in that output is **expected and harmless** — it ships
in the same `bin/` folder and resolves at load time; only an unresolved
`libayatana-appindicator3.so.1` is fatal. (Hard link and path verified on
1.18.1 — re-check both on the first 2.x Linux build.)
**Tray visibility** is a separate matter from linking: GNOME 3.26+ hides the
legacy tray, so the icon needs the
[AppIndicator extension](https://extensions.gnome.org/extension/615/appindicator-support/).
KDE Plasma, XFCE, MATE and Cinnamon show it out of the box. The app runs fine
either way — the tray is a convenience, and every action it offers exists in-app.
## Linux known issues (upstream electrobun)
- **No native menus of any kind.** Application menus and `showContextMenu` are
both no-ops (electrobun's `.hutch/devkit/api/sdks/main/proc/linux.md`, still in
2.0.2; the app logs
"Application menus are not supported on Linux" at boot). The app menubar was
already macOS-only, and the panel context menus are now HTML on every platform,
so nothing is missing at the UI level — but do not add a feature that depends
on a native menu.
- **NVIDIA renders black without the DMABUF workaround.** WebKitGTK can't
allocate GBM buffers on the proprietary driver, so the window paints nothing
while the log looks perfectly healthy. The dev launches
(`scripts/linux-gpu.ts`) set `WEBKIT_DISABLE_DMABUF_RENDERER=1` when
`/proc/driver/nvidia` exists; an installed build (the official Setup
installer) does not — launch it with that variable set (e.g. in the desktop
entry's `Exec`). The app can't do it itself (Bun's `process.env` writes don't
reach child processes); see [gotchas.md](gotchas.md#linux).
- **Benign startup noise**: a deprecation warning pointing at
`libayatana-appindicator-glib`. Not fatal.
- **Unsigned; Electrobun's own installer**: the release artifact is
`linux-x64-miniSCP-Setup.tar.gz` — a self-extracting `installer` + README
(2.x does the desktop-entry packaging and ships an uninstaller); no AppImage
or `.deb`. Layout unverified until the first 2.x Linux build.
## First-Linux-boot smoke test
1. Install the AppIndicator package for your distro (table above), then
`bun run start`. The window opens **and actually renders the UI** (a black
window on NVIDIA means the DMABUF workaround didn't apply — check for
`Failed to create GBM buffer` in the log), and the tray icon appears (or
doesn't, on bare GNOME — that's the extension caveat, not a failure).
2. Right-click a file row: menu appears at the pointer, Send to Other Panel is
first, Permissions is present, Escape / click-outside / arrow keys + Enter all
work, and a right-click near the bottom-right flips the menu instead of
overflowing.
3. Right-click empty panel space (New Folder / New File / Refresh / Show in File
Manager) and a column header (checkmarks toggle columns live).
4. Copy Path puts the path on the clipboard; Show in File Manager opens the
distro's file manager; Open (local file) launches the default app via
`xdg-open`.
5. local↔remote transfers both directions; external editor round-trip
(temp download → save → auto-upload) with the inotify watcher.
6. Move to Trash lands the item in the desktop's trash; connections.json is 0600.
7. `bun scripts/release.ts --target linux-x64` produces
`release/linux-x64/miniSCP-Build<N>-linux-x64-Setup.tar.gz`; unpack it
elsewhere, run its `installer`, then launch the installed app (on NVIDIA with
`WEBKIT_DISABLE_DMABUF_RENDERER=1`).
## Windows known issues (upstream electrobun, documented not fixed)
- **HiDPI blur** — WebView2 renders at 1x on scaled displays
(blackboardsh/electrobun#324, seen on 1.18.1). Most user-visible defect; 2.x
lists per-monitor DPI setup among its Windows fixes — re-check on the first
2.x Windows build.
- **Notifications** are legacy balloon style (`Shell_NotifyIcon`), not
Windows toasts.
- **Unsigned binaries** — Setup.exe and the portable exe both trigger
SmartScreen / Mark-of-the-Web on first run. No Authenticode support (2.x:
"Windows release signing is not currently part of Hutch's packaging
pipeline"; a signtool post-hook is an option later). Installer unpacks to
`%LOCALAPPDATA%`, desktop shortcut only; 2.x installer builds add an
uninstaller (`%LOCALAPPDATA%\<identifier>\<install-root>\uninstall.exe`).
- `hiddenInset` degrades to `hidden` on Windows — irrelevant here because
non-mac windows use the native titlebar.
- `findInPage` is a `window.find()` shim on WebView2 — irrelevant here, the
editor find is custom.
## First-Windows-boot smoke test
Code paths written blind (no Windows box was available); verify in order:
1. Build: `bun scripts/release.ts --target win-x64` on the Windows machine —
Hutch, the core and the pinned Bun download into `~/.hutch` on first run;
Setup.zip AND the portable zip appear under `release/win-x64/` (the portable
step warns instead of failing if the assembled-app folder layout differs —
fix the `appDir` path in release.ts if so). A v1 0.1.78 install must pick up
the published 2.x build through its updater (the bridge release).
2. App boots, tray icon renders colored, window has a native titlebar.
3. Drives dropdown in each panel lists `C:\` (+ others); navigating to a
drive root hides the `'..'` row; the path bar shows consistent `\` paths.
4. local↔remote transfers both directions; self-copy guard still blocks
same-path copies.
5. External editor: default app opens via `cmd /c start`; the Choose… picker
starts in Program Files and accepts an .exe; remote temp-edit → save →
auto-upload works (directory watcher on NTFS).
6. Context menus: Send to Other Panel is the first row item; Show in Explorer,
Move to Recycle Bin (item restorable from the bin), Copy Path; Permissions
ABSENT on local rows, present on remote.
7. Ctrl+T/W/F/S and Ctrl+digit tab jumps; tooltips read "Ctrl+…".
8. connections.json ACL: `icacls connections.json` shows only the current
user after saving a connection.
9. Editor/manager/Settings windows open, modal bounce works, Ctrl+, opens
Settings and About shows from its About section.
10. Known-issue check: HiDPI blur on a scaled display (seen on 1.18.1 — 2.x's
per-monitor DPI setup may have fixed it).