Skip to content
puremixaiPublic

About

PureTerm is an SSH/SFTP client built with Cordis, ssh2, and xterm.js

Topics

Resources

Stars

102 stars

Watchers

0 watching

Forks

Repository files navigation

PureTerm

中文版本

PureTerm is an SSH/SFTP client built with Cordis, ssh2, and xterm.js. It provides two local entry points: an Electron Desktop app and a standalone local Web app. SSH connections are always initiated by the user’s computer; the Web server binds only to the local loopback interface and provides no public service, accounts, or user isolation.

The project is released under the MIT License.

The current source version is 0.1.0-alpha.2, maintained in VERSION.txt and described in the development guide.

Both entry points reuse the Host, protocol, shared Web Host assembly, and Cordis Client. Desktop starts an independent Node-mode Web Host child process from Electron. Its pureterm-app://app/ window sends SSH/SFTP, host, and Keychain traffic over a loopback WebSocket; standalone Web runs the same assembly in an ordinary Node process without starting Electron.

Getting started

You need Node.js 24 or newer and npm. Desktop also needs a working desktop environment. Install all dependencies from the repository root with the single lockfile:

npm ci

# Use the local Web app in a browser; open the tokenized URL printed in the console
npm run start:web

# Or start the Electron Desktop client
npm run start:desktop

The start commands build the required shared modules and application. Web uses a random loopback port by default; press Ctrl+C to stop it. Desktop stores data in ~/.ssh-cordis/ by default, while standalone Web uses ~/.ssh-cordis/web/; each location stores host records and trusted SSH host keys for its own entry point.

Choose how to connect

Client How to open it Host and credential policy
Desktop window npm run start:desktop Electron starts a Web Host child; credentials and Keychain keys can use system-encrypted storage, with native private-key selection
Browser attached to Desktop Start Desktop, then open its tokenized URL from the startup log Shares Desktop's Web Host, saved hosts, encrypted credentials, and native private-key selection; each client owns its SSH sessions
Standalone Web npm run start:web, then open the printed URL An independent Node Web Host with separate data; credentials and Keychain keys remain in the current client session and must be supplied again after a refresh

Desktop's attached browser entry is enabled by default. Set SSH_CORDIS_NO_WEB_CARRIER=1 to disable it; the Desktop window and its internal Web Host continue to work. This setting does not disable the standalone Web command. Keep independent Desktop and Web processes on separate data directories. See the Desktop guide and local Web guide.

Working with connections

  • Hosts is a permanent management tab. A single click selects a saved host without changing pages; use its Edit action to open the editor. Use its Connect action or double-click the host to open a new terminal tab. Each connection gets a separate tab, including repeated connections to the same host.
  • Tabs keep independent input, output, scrollback, connection state, and SFTP directories. Switching tabs or returning to Hosts leaves other connections running. Each tab also remembers which tool it had open and how far its split was dragged; no tab inherits another's.
  • Closing a tab is the only way to end a session, and it releases only that session. A dropped connection keeps its tab and its scrollback and offers Reconnect above the terminal, retrying in the same tab; failed connections open a diagnostic page with logs, retry, and host editing. A tab closed during its handshake releases the connection if the handshake later succeeds.
  • Create hosts through New Host and use Connect on its row or card; use Ctrl+Tab / Ctrl+Shift+Tab to switch tabs and Ctrl/Cmd+W to close the current terminal tab. Ctrl/Cmd+E opens Files, Ctrl/Cmd+` focuses the terminal, Ctrl/Cmd+K focuses host search, and Escape dismisses the host editor. Tab buttons also support arrow keys, Home, and End. Desktop and browser clients resolve the same bindings, and a shortcut is taken only when its modifiers match exactly: an IME composition or an open dialog owns the keyboard, Alt/AltGr passes through to the input method and the remote, and holding a key does not repeat a destructive close. Browsers may reserve some shortcuts; the visible controls remain available.
  • Each session can report the remote host's resources. The terminal page carries its own right-hand tool rail, holding Files and Monitor. Both open in one shared panel beside the terminal, separated from it by a draggable grip that also answers the arrow keys; clicking the active tool collapses the panel and clicking the other replaces its content, so at most one panel is open. The panel starts closed. Opening the monitor begins collection and stacks CPU, memory, load, the root filesystem's usage, the network rate and the host's uptime as sections, with pause, retry and close controls in its header. Closing the panel, pausing it, hiding the page, switching tabs, or losing the connection all stop collection — a closed session costs the remote nothing. Above 820px the panel takes width from the terminal; at or below 820px it stacks under it, and the rail stays on the right either way. The status bar's cipher and host-key cells are filled from the SSH handshake rather than from this panel, so they stay filled even when it is closed.

Open sessions and retry credentials live only in the current client; they are not restored after a reload. SFTP currently supports directory navigation, upload/download (up to 4 MiB per file), folder creation, and deletion with confirmation. Serial connections, port forwarding, SSH certificate authentication, Windows Hello, FIDO2, and snippet management are not implemented and are not shown as working controls.

Resource monitoring probes Linux only, with one command every five seconds. CPU and network are rates, so they read — until a second probe supplies a baseline; disk is the root filesystem, not every mount; and a counter the remote does not expose is left empty with its reason on hover instead of being shown as zero. A remote that is not Linux, or a Host without the monitoring plugin, is reported as unsupported rather than as a failure. The figures are whatever the remote's own /proc reports and are not verified against the machine by this application.

The interface is bilingual. A switch in the top bar, beside the theme and row-density toggles, moves every screen between English and Chinese and remembers the choice; English is the default. It sets the document language too, and in the Desktop app the application menu and the native dialogs follow it. Developer log lines and the standalone Web command's own output stay English, because they have no switch to reach them.

The libraries adapt to the space available beside their editors. Narrow screens keep search, connection actions, theme, density and language controls available; the navigation moves to a horizontal row and editors scroll within the remaining workspace. A search with no matching hosts offers Clear search. The interface respects the system setting to reduce motion.

Working with Keychain

  • Open Keychain → New key, enter a label, then paste, choose, or drag in a private-key file (OpenSSH, PEM, or supported PPK; up to 256 KiB). Enter the passphrase for an encrypted key and save. The SSH parser validates the key and derives its type, public key, and SHA-256 fingerprint; an optional supplied public key must match.
  • Single-click a card to select it; use Edit to rename or replace the key. Stored private material and passphrases are never returned to the editor. Leave the private-key field empty when renaming. Search by label, type, or fingerprint, switch card/list views, and copy the saved public key.
  • In a host's Private key authentication settings, select the saved Keychain entry, save the host, then connect in its own terminal tab. The Host resolves the key ID internally. Direct private-key file selection remains available.
  • Desktop stores a dedicated atomic, system-encrypted keychain.json vault with no plaintext private material; unavailable encryption fails the save. Web keeps imported keys and host-key associations only in that client's Host memory and clears them on disconnect/reload. A key used by a saved host cannot be deleted until that host's authentication is changed or the host is removed. Deletion requires confirmation and cannot be undone.

Architecture and upstream reference

The September 23 Desktop migration used deepseek-harness's Desktop implementation at 00102833 as its adaptation baseline; the reference checkout was updated on September 30 to 639ed015 (dsh-v0.2.0-rc.2). PureTerm adapts the shared Web Host and Electron shell pattern to its SSH/SFTP client. The dated architecture comparison records what is shared, adapted, or absent.

  • @pureterm/transport/web-host assembles the Cordis Host, dispatcher, and loopback HTTP/WebSocket carrier for both entry points.
  • Electron serves the shared UI at pureterm-app://app/ while its Node-mode child starts. The minimal window.puretermDesktop bridge provides the WebSocket address after Host readiness and accepts the renderer's readiness and language reports. SSH/SFTP, hosts, and Keychain operations use WebSocket.
  • Electron main owns the window, system encryption, native key picker, and child lifecycle. It injects the Desktop authentication token into the owned window's WebSocket request without exposing that token to the page. Private parent/child RPC carries platform capabilities and startup/shutdown coordination.

Desktop keeps one writer per bound profile: a launch that points at a data directory already bound to another profile stops instead of opening the same store. Quitting with active or uncertain SSH work asks first and cancels cleanly if the user declines, leaving the window and its sessions untouched; an update is installed only after the Host acknowledges a clean, signal-free exit, so a forced termination never counts as a successful install. A Host failure writes one bounded, allowlisted report under diagnostics/host/ and offers an explicit restart or quit — a restart does not restore SSH sessions. Desktop and browser clients share one shortcut definition, so a key is taken at most once and never while an input method or a dialog owns the keyboard.

For internal integrations, the old window.sshAPI and SSH business IPC have been removed. Existing SSH data directories remain unchanged. See the architecture guide for process boundaries and lifecycle, and the changelog for migration details.

Verification

# Clean build, type/dependency-boundary checks, Node and local protocol tests
npm run verify

# Desktop boot / custom-scheme WebSocket / attached Web and a real-browser check of standalone Node Web
npm run verify:electron

Tests use the repository’s local SSH/SFTP fixtures and temporary data directories. The second command requires a desktop environment; an Electron startup limitation is a failed check, not a pass. Besides the real Desktop and standalone Web flows, it runs single-profile ownership, cancellable quit protection, and Host-failure recovery against real launches, and measures the built stylesheet’s terminal tool rail — its width, ancestry, panel switching, splitter axis and scrolling — at six viewports in both themes and both languages.

Repository entry points

Path Contents
apps/desktop/ Electron shell, Node-mode Web Host child entry, platform adapters, startup diagnostics, and tests
apps/web/ Standalone local Node Web entry point and tests
packages/host/ Cordis Host, SSH/SFTP, host storage, and credential interfaces
packages/protocol/ Transport protocol and shared data structures
packages/i18n/ Message catalog and t() for both entry points; the only place user-facing copy lives
packages/transport/ Shared Web Host assembly, request dispatch, and HTTP/WebSocket carrier
packages/ui/ Shared terminal, terminal-local tool rail, file panel, and browser transport for both entry points
VERSION.txt Source version baseline for all workspaces and release tags
docs/architecture.md Current architecture, lifecycle, and data boundaries
docs/DEVELOPMENT.md Local development, verification, and contribution workflow
LAYOUT-PROPOSAL.md Current directory and shared-module decisions

The repository uses npm workspaces. Shared packages are referenced through public exports, and the root package-lock.json is the only installation lockfile. Versions and user-visible changes are recorded in CHANGELOG.md; npm run release:check validates version alignment and release entries in CI. npm run dist:desktop -- --win --x64 creates a Windows installer; CI also builds macOS/Linux artifacts. Packaged builds check GitHub Releases for updates and install them only after the user confirms a restart. Signing, publishing, and local acceptance are documented in the release guide.

English is the default for repository documentation. Chinese translations are maintained as paired *_zh.md files, including README_zh.md.

Old review documents, the original proposal, and screenshot research material have been removed. The architecture describes current behavior; dated plans under docs/superpowers/ preserve historical decisions.

About

PureTerm is an SSH/SFTP client built with Cordis, ssh2, and xterm.js

Topics

Resources

Stars

102 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages