P6: placeholder icon, README, packaged build verified

- assets/icon.png (generated by scripts/make-icon.py) + icon.iconset
  (scripts/gen-iconset.sh); electrobun compiles it to AppIcon.icns
- branding.icon points at the iconset
- README: features, stack, dev/build, rebranding, plaintext-password warning,
  shortcuts, v1 scope
- verified: full production build (ng build + electrobun build) produces a
  launchable BunSCP.app that boots standalone from views://app

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jokin
2026-07-11 14:19:16 +02:00
co-authored by Claude Fable 5
parent 0d0e4cfde4
commit 76b9b621a2
15 changed files with 253 additions and 1 deletions
+130
View File
@@ -0,0 +1,130 @@
# 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.
- 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.
(On Macs, function keys may need `fn` — every action also has a toolbar button.)
## Not in v1
Drag-and-drop, file preview/edit, transfer resume, symlink following
(symlinks are listed but skipped by transfers), OS keychain, Windows/Linux
packaging (the code is portable; only macOS packaging is wired up).