The win7 skin is dropped. Everything else the branch built stays: Linux support and the HTML context menus, the workspace-tab menu, the continuous interface scale (rem everywhere, stepper, Ctrl/Cmd +/-/0) and the core/ service layer. The modern tree already carried all of them, and nothing outside skins/7like/ imported the win7 tree except main.ts and styles.css. Removed: the skins/7like/ tree (5.1k lines, fonts), the 7.css dependency, the skin setting and its options row + strings in all 7 locales, the frameless-window plumbing (window-control RPCs, windowState push, trackMaximizeState, the synthesized resize grip and its postinstall watchdog), the session-skin pinning in buildPreload/chromeOptions, the skin/skinfix cascade layers, and the win7-only probes and screenshot harness (the harness cannot render the modern tree: plain Firefox has no RPC bridge). chromeOptions() stays as the one shared frame decision. Fixed on the way out: - index.html's per-theme pre-paint background is restored. The branch had replaced it with a win7-only transparent rule, so modern dark windows had silently lost one of the three flash guards. - editor-windows.ts wrote its window-key separator as a literal NUL byte, which made git and grep treat the file as binary; it is `\0` now (same string at runtime). No settings migration: a stale "skin" key is carried harmlessly by the store's spread-merge and dropped on the next save. UI bundle: 616.7 kB -> 405.4 kB, back under the 500 kB budget. Docs: architecture, gotchas and platform-notes lose the win7 material but keep what stays true (construction-time preloads/frames, drag regions ignoring preventDefault, electrobun's missing resize/maximize primitives); flash-prevention, dev-URL and Bun-panic notes move back under Electrobun; stale context-menu/tab-bar links fixed; README documents the scale keys. Co-Authored-By: Claude <noreply@anthropic.com>
179 lines
10 KiB
Markdown
179 lines
10 KiB
Markdown
# Platform notes — macOS / Windows / Linux behavior matrix
|
||
|
||
macOS is the primary target; Windows 11+ x64 and Linux x64 are **beta** targets
|
||
(win-arm64 and linux-arm64 deferred). 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 |
|
||
| 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 | `ui platform.ts MOD_LABEL/ALT_LABEL` | ⌘ / ⌥ | Ctrl+ / Alt+ | Ctrl+ / Alt+ |
|
||
| 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 | none (early return) — About lives in the options popover | 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.
|
||
|
||
**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 `dist/api/bun/proc/linux.md`; 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. Every launch path sets
|
||
`WEBKIT_DISABLE_DMABUF_RENDERER=1` when `/proc/driver/nvidia` exists —
|
||
`scripts/linux-gpu.ts` for dev, the `miniSCP.sh` wrapper in the tarball for
|
||
releases. 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, unpackaged**: the release artifact is a portable tarball — no
|
||
AppImage, `.deb`, `.desktop` entry or icon installation. Unpack and run
|
||
`miniSCP.sh` (which execs `bin/launcher`).
|
||
|
||
## 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.tar.gz`; unpack it elsewhere and
|
||
run `miniSCP.sh`.
|
||
|
||
## Windows known issues (upstream electrobun, documented not fixed)
|
||
|
||
- **HiDPI blur** — WebView2 renders at 1x on scaled displays
|
||
(blackboardsh/electrobun#324, open). Most user-visible defect; wait for
|
||
upstream DPI awareness.
|
||
- **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 in
|
||
electrobun 1.18.1 (signtool post-hook or electrobun-builder are options
|
||
later). Installer unpacks to `%LOCALAPPDATA%`, desktop shortcut only — no
|
||
Start Menu entry or uninstaller.
|
||
- `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 —
|
||
core binaries download from GitHub releases 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).
|
||
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 windows open, modal bounce works, About shows from the
|
||
options popover.
|
||
10. Known-issue confirmation: HiDPI blur on a scaled display (expected until
|
||
upstream fixes it).
|