Files
miniSCP/README.md
T
JokinandClaude Fable 5 e4f7ca86f7 Edit file: built-in editor + external editor with watch & auto-upload
- Built-in editor (default): large modal with monospace textarea, Cmd+S save,
  dirty guard; reads/writes through the provider streams so it works on local
  and remote files identically (2MB cap with a friendly error)
- External editor: remote files download to appDataDir/edits/<id>, open via
  macOS `open -a`, the temp DIR is watched (survives atomic rename-saves) and
  every save enqueues a normal upload job (progress/errors in the transfer
  list); watchers + temp dirs are cleaned when the session disconnects
- Editor setting: Built-in | Custom with a NATIVE app picker (electrobun
  openFileDialog, /Applications, .app filter) and reset-to-default
- Leftover temp files from a crash prompt for cleanup at boot
- F4, toolbar button (mynaFileText), and File > Edit File (Cmd+E) menu entry
- README: feature notes + Portability notes (open/start/xdg-open seam
  documented in code and README per user request)

Verified headless against the box: sftp read/write roundtrip incl. UTF-8,
size cap, watch->save->auto-upload->remote-updated, session cleanup, orphan
listing and clearing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 20:28:54 +02:00

174 lines
7.4 KiB
Markdown
Raw 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.
# BunSCP
A cross-platform, dual-panel SFTP/local file manager — a small WinSCP-style
commander built on **Bun**, **Electrobun**, and **Angular**.
Each of the two panels independently shows either the local filesystem or a
remote server over SSH/SFTP, so you can move files **local↔remote**,
**remote↔remote**, or **local↔local** through one symmetric engine.
> **Name & icon are placeholders.** See [Rebranding](#rebranding) — it's a
> one-file change.
## Features
- Dual-panel commander UI; either panel can be Local or any saved connection.
- **Session tabs**: each tab is an independent left/right workspace; remote
sessions stay connected and transfers keep running in background tabs.
- Per-panel action toolbar with a direction-explicit copy button, plus a
VSCode-style status bar showing live transfer progress (click to expand the
transfer queue with per-file speed and ETA).
- **Overwrite confirmation** on name collisions, with a source-vs-destination
comparison (size, modified date, which is newer) and batch replace-all /
skip-all.
- **Settings** (gear, top-right): light / dark / system theme and speed units
(MB/s or Mbps), persisted across restarts.
- On macOS the tab bar is fused with the window titlebar; other platforms keep
a standard titlebar.
- **Edit files** (F4 / toolbar / File menu): a built-in editor works on local
and remote files directly; or pick an external app (Options → Editor →
Custom → Choose…). External edits of remote files download to a temp folder,
are watched, and every save auto-uploads (visible in the transfer list) until
the session disconnects. Leftover temp files from a crash are offered for
cleanup at the next start.
- Browse, sort (name/size/modified, folders first), keyboard navigation.
- Create folder / file, rename, delete (recursive), change permissions (chmod).
- Upload, download, and remote→remote copy — files **and** whole folders —
with a transfer queue, per-job progress, and cancel.
- Connection manager: saved connections organised into folders, password or
private-key auth (with passphrase).
## Stack
| Layer | Choice |
| ---------- | ------------------------------------------------------------- |
| Runtime | Bun (main process, all SSH/SFTP + file IO) |
| Desktop | Electrobun 1.18 (native webview, typed RPC bridge) |
| Frontend | Angular 22 (standalone, signals, zoneless) in `ui/` |
| Styling | Tailwind CSS v4, shadcn-style tokens (no component library) |
| Icons | @ng-icons/mynaui |
| SSH/SFTP | `ssh2` (pure-JS under Bun) |
The repo is a Bun workspace: the Electrobun app at the root, the Angular app in
`ui/`. Shared types and the RPC contract live in `src/shared/` and are imported
by both sides.
```
src/shared/ types.ts, rpc.ts (wire contract), branding.ts
src/bun/ Electrobun main process
fs/ FileSystemProvider + LocalProvider + SftpProvider + registry
transfers/ engine.ts (queue/stream copy) + walk.ts (recursive helpers)
store/ connections.json persistence
ui/src/app/ Angular components + signal services
```
## Prerequisites
- [Bun](https://bun.sh) ≥ 1.3 (`bun --version`).
- macOS: **Xcode Command Line Tools** (for the app build).
- No Node install required — a preload shim (`scripts/node-version-shim.ts`)
satisfies the Angular CLI's Node version check while running under Bun.
## Setup
```bash
bun install # installs root + ui workspace deps
```
## Develop
```bash
bun run dev
```
This starts the Angular dev server (hot reload for UI code) and launches the
Electrobun app pointed at it. Edits under `ui/` reload instantly; edits to the
Bun main process (`src/bun/**`, RPC schema) trigger an app relaunch.
## Build a packaged app
```bash
bun run build # ng build (ui/dist) + electrobun build -> build/*/BunSCP*.app
```
The Angular bundle is copied into the app under `views://app`. The macOS icon is
compiled from `assets/icon.iconset` into `AppIcon.icns` automatically.
For a distributable (optimized, with auto-update channel) build, use
`bunx electrobun build --env=stable` (see the
[Electrobun docs](https://framework.blackboard.sh/electrobun/) for signing,
notarization, and release hosting).
## Rebranding
Everything user-facing reads from **[`src/shared/branding.ts`](src/shared/branding.ts)**:
```ts
export const BRANDING = {
appName: "BunSCP", // window title, bundle name, app-data folder
identifier: "es.teknes.bunscp",
version: "0.1.0",
icon: "assets/icon.iconset",
} as const;
```
To change the icon: replace `assets/icon.png` (1024×1024) and run
`./scripts/gen-iconset.sh` (regenerates the `.iconset` with `sips`), or point
`icon` at your own `.iconset`. `scripts/make-icon.py` regenerates the current
placeholder.
> Renaming `appName` changes the app-data directory, so existing saved
> connections won't be found under the new name — copy `connections.json` across
> if you need them.
## Where connections are stored
Saved connections live in a plain JSON file in the OS app-data directory
(macOS: `~/Library/Application Support/BunSCP/connections.json`), written with
`0600` permissions.
> ⚠️ **Passwords are stored in plaintext** in this file (a deliberate v1
> simplicity choice). Anyone who can read the file can read the passwords. If
> that isn't acceptable for your use, use key-based auth or don't save the
> password (connect ad-hoc). OS-keychain storage is a natural future addition.
## Keyboard shortcuts
`Tab` switch panel · `↑`/`↓`/`PgUp`/`PgDn`/`Home`/`End` move cursor ·
`Space` select · `Enter` open folder · `Backspace` parent ·
`Ctrl/Cmd+A` select all · `F5` copy to other panel · `F2` rename ·
`F7` new folder · `F8`/`Delete` delete · `Cmd/Ctrl+T` new tab ·
`Cmd/Ctrl+W` close tab · `Ctrl+Tab` next tab.
(On Macs, function keys may need `fn` — every action also has a toolbar button.)
## Portability notes
The codebase is platform-neutral except for two seams, both macOS-only today:
- **External editor launch** (`launchEditor` in [src/bun/edits.ts](src/bun/edits.ts)):
uses macOS `open [-a app] file`. A Windows port should use
`cmd /c start "" [app] file`; Linux `xdg-open file` (or invoke the configured
editor binary directly). The `.app` picker in the `pickEditorApp` handler
needs the equivalent executable picker per platform.
- **Application menu** ([src/bun/menu.ts](src/bun/menu.ts)): electrobun menus
are macOS-only; the in-app UI covers every menu action.
## Known issues
- **Rare native crash under load.** A long-running session (multiple remote
connections, extended uptime) can hit a Bun panic — a segfault inside Bun
1.3.13's FFI thread-safe callbacks executing Electrobun's native→worker
bridge (`FFI_Callback_threadsafe_call` → `web_worker.spin` in the decoded
crash report). This is an upstream Bun × Electrobun bug, not app code; a
restart recovers cleanly and in-flight work isn't corrupted. Expected to
resolve when Electrobun bumps its pinned Bun (currently 1.3.13; 1.3.14+
available). Bun's own crash reporter link is printed to the console on panic.
## Not in v1
Drag-and-drop, file preview/edit, transfer resume, symlink following
(symlinks are listed but skipped by transfers), OS keychain, tab persistence
across restarts, Windows/Linux packaging (the code is portable; only macOS
packaging is wired up).