From 8c646e71767c968917f34848db69741fe2ed137e Mon Sep 17 00:00:00 2001 From: Andy Dixon Date: Sun, 11 Oct 2026 17:52:35 +0100 Subject: [PATCH] docs: rewrite for Nexus Terminal --- .github/copilot-instructions.md | 151 +++++----- README.md | 81 +++--- docs/overview.md | 343 ++++++++++------------ docs/quick-start.md | 55 ++-- docs/user-manual.md | 488 +++++++++++++++++++++----------- 5 files changed, 613 insertions(+), 505 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0a8e9d7..e6bfdb7 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,109 +1,86 @@ -# Copilot Instructions — Alchementary Link +# Copilot Instructions — Nexus Terminal + +Nexus Terminal is a native desktop client (SSH, Telnet, RAW TCP, Serial, VNC, IRC, GitHub, local shell) written in Rust with an eframe/egui UI. All the code lives in the Cargo workspace under `rust/`. ## Build & Test ```bash -make deps # go mod download + npm install -make build # production build → build/bin/alchementary-link.app -make dev # wails dev with hot reload -make test # go test ./... -v -count=1 -make lint # golangci-lint run ./... +cd rust +cargo run --release # the app (binary `nexus-terminal`) +cargo test --workspace # unit and integration tests +cargo clippy --workspace --all-targets -- -D warnings # must be clean +cargo fmt --all --check # must be clean -# Single package test -go test ./internal/storage/ -v -count=1 -run TestProfileCRUD +# Single test +cargo test -p nexus-core --lib storage:: +cargo test -p nexus-core --test ssh_integration ``` -The frontend has no separate build step — `npm run build` (called by Wails) copies xterm vendor libs from `node_modules` into `frontend/src/js/lib/` and `frontend/src/css/lib/`. All frontend assets are embedded at compile time via `frontend/embed.go`. +CI (`.github/workflows/ci.yml`) runs `cargo test --locked`, `cargo fmt --check` and `cargo clippy --all-targets -D warnings` on Linux, macOS and Windows. The toolchain is pinned in `rust/rust-toolchain.toml`. Platform prerequisites and release packaging are in `docs/build-and-release.md`. ## Architecture -Wails v2 desktop app: Go backend + HTML/CSS/JS frontend rendered in a native webview (WKWebView on macOS). +The project is engine-first: a UI-free core crate, and the egui app is one client of it. -**Go backend** (`internal/`): -- `app/` — lifecycle bootstrap: opens SQLite, inits secret stores, wires everything together -- `api/` — single `Service` struct bound to Wails; every public method is callable from JS as `window.go.api.Service.MethodName()` -- `sessions/` — manages concurrent protocol sessions; owns SSH/Telnet/RAW/GitHub client lifecycles; handles auto-reconnect, login scripts, broadcast -- `storage/` — SQLite repository (WAL mode) with embedded sequential migrations in `storage/migrations/` -- `secrets/` — two-tier credential storage: OS keychain (preferred) → AES-256-GCM encrypted file vault (fallback) -- `models/` — shared domain types and defaults; protocol configs are JSON-encoded in the DB -- `sshclient/` — SSH client with agent, TOTP/2FA, and SOCKS5/HTTP proxy support -- `telnetclient/`, `rawclient/`, `githubclient/` — protocol implementations -- `sftpclient/` — SFTP file operations (browse, upload, download, rename, delete) -- `sshconfig/` — OpenSSH `~/.ssh/config` parser and importer -- `recording/` — asciicast v2 session recording and playback -- `exportimport/` — encrypted profile bundles (.link format) -- `updater/` — GitHub Releases update checker -- `knownhosts/` — SSH host key management -- `validation/` — profile and protocol validation -- `audit/` — timestamped audit logging +``` +rust/ +├── core/ nexus-core: storage, secrets, models, protocol clients, session Manager, Service. No egui. +│ ├── migrations/ numbered SQL migrations, embedded with include_str! +│ └── tests/ sessions.rs, ssh_integration.rs, fixtures/ +└── app/ nexus: the egui shell (binary `nexus-terminal`) +``` -**Frontend** (`frontend/`): -- Plain HTML/CSS/JS — no framework, no bundler, no ES modules -- `index.html` is the app shell; loads CSS then JS in strict order -- `src/js/` — 18 modules, each IIFE-wrapped, exporting to `window.AlchementaryLink` -- `src/css/` — modular stylesheets; `tokens.css` defines all design tokens -- Vendor libs (xterm.js, addons) live in `src/js/lib/` and `src/css/lib/` — auto-copied, gitignored +**Core (`rust/core/src/`):** +- `service.rs` — `Service`, the app-facing API: profiles, connect/reconnect, credentials, known hosts, preferences, snippets, import/export, SSH keys, SFTP, updates. File dialogs live in the UI; methods here take paths. +- `sessions.rs` — `Manager`: concurrent sessions, auto-reconnect with backoff, login scripts, broadcast writes, recording hooks, secret resolution (saved / session-only / ask every time), host-key checks. It reports through one `Event` enum (`Data`, `State`, `Closed`, `RawData`, `Irc`, `Github*`, `Forward*`, `Recording*`, `SftpProgress`, `SecretPrompt`, `HostKeyVerify`, `Vnc*`). +- `clients/` — one module per protocol (`ssh`, `sftp`, `telnet`, `raw`, `serial`, `local`, `irc`, `github`, `vnc`). Read the conventions at the top of `clients/mod.rs` before touching one: `connect()` blocks its (worker) thread and returns once usable; the client then owns its reader thread(s) and reports through `Callbacks` (data, fatal error, close exactly once); `write`/`resize`/`close` are callable from any thread and `close` is idempotent. russh-based clients use the shared tokio runtime from `clients::rt()`; the rest use plain threads. +- `storage.rs` (SQLite via rusqlite, WAL), `secrets.rs` (keychain + vault), `config.rs` (data directories and Alchementary Link migration), `models.rs`, `validation.rs`, `exportimport.rs`, `recording.rs` (asciicast v2), `sshconfig.rs`, `updater.rs`, `ircformat.rs`, `terminalenv.rs`, `keyfiles.rs`. -**Go ↔ JS communication:** -- **Synchronous:** Frontend calls `window.go.api.Service.*()` (returns Promise) -- **Asynchronous:** Backend pushes events via `wailsRuntime.EventsEmit()`; frontend listens with `window.runtime.EventsOn()` -- **Bidirectional events** for secret prompts and host key verification: backend emits a request event with a `requestID`, frontend shows a modal, then emits a response event with the same ID. The Go side blocks on a channel keyed by that ID. +**App (`rust/app/src/`):** +- `main.rs` parses flags, opens the `Service` and starts eframe. `app.rs` owns `App`: it installs an event sink that forwards `Event`s over a channel and calls `request_repaint`, drains them each frame (`on_event`), handles `Request`s, the keyboard shortcuts (`shortcuts()`), and lays out the frame. +- `state.rs` — `Shared` (service handle, cached profiles and preferences, tabs, panes, toasts) and the `Request` queue features use to ask the main window to act. +- `views.rs` — `View::{Terminal, Raw, Irc, Github, Vnc}`, one per pane. +- `terminal.rs` (`TermView`: alacritty_terminal drawn with egui's painter), `tabs.rs` (tab strip, workspace, find bar, overlays), `splits.rs` (split tree), `sidebar.rs`, `chrome.rs` (title bar, status bar, command palette `Cmd` enum, prompts, dialogs, toasts). +- Feature windows: `profile_editor.rs`, `quick_connect.rs`, `settings.rs` (including the Help topics), `ssh_keys.rs`, `transfer.rs` (import/export), `sftp.rs`, `forwards.rs`, `snippets.rs`, `triggers.rs`, `recordings.rs`. +- Protocol views: `raw_view.rs`, `irc_view.rs`, `github_view.rs`, `vnc_view.rs`. -Key events: `session:data`, `session:state`, `session:closed`, `session:raw:data`, `session:github:repos`, `session:secret:prompt`/`session:secret:response`, `session:hostkey:verify`/`session:hostkey:response`. - -## WKWebView Constraints (Critical) - -The macOS webview silently blocks or breaks several standard web APIs. These constraints affect every frontend change: - -1. **No `window.confirm()`, `window.prompt()`, `window.alert()`** — they either return false/null silently or do nothing. All user prompts must use the custom modal system (DOM-based backdrop + modal with `is-visible` class toggling). - -2. **No ES modules** — `