Terminals
A terminal panel — a Svelte SPA on xterm.js.
Package: @devframes/plugin-terminals

Interactive and read-only sessions in the browser
What it does
- Read-only output — via devframe's streaming channels.
- Interactive shells — PTY-backed terminal sessions you can type into, including full-screen TUI programs.
- Presets — named commands launchable in one click.
Interactive shells use zigpty's prebuilt native bindings (Linux/macOS/Windows, x64/arm64), falling back to pipe-based emulation where they can't load.
Standalone
pnpx @devframes/plugin-terminalsMount into a Vite host
// vite.config.ts
import { terminalsVite } from '@devframes/plugin-terminals/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
terminalsVite(),
],
})Programmatic
createTerminalsDevframe(options) returns a definition; declare presets to seed the launcher:
import { createTerminalsDevframe } from '@devframes/plugin-terminals'
export default createTerminalsDevframe({
presets: [
{ id: 'dev', title: 'pnpm dev', command: 'pnpm', args: ['dev'] },
],
})Hub aggregation
Mounted into a hub, the devframe spawns on its own channel (devframes:plugin:terminals:output) and mirrors every session into ctx.terminals (the hub's registry, on devframe:terminals); foreign hub sessions render read-only.
ctx.terminals is the source of truth; the devframe, the sole PTY provider, duck-types a minimal register / update / events shape to run without @devframes/hub.
startChildProcess() sessions carry a getResult() accessor (tinyexec's Result: awaitable { stdout, stderr, exitCode }, plus live getters and kill()).
Focusing a session
Via the hub's cross-iframe dock activation, an activation with a sessionId selects that session:
// e.g. right after ctx.terminals.startChildProcess(..., { id: sessionId, ... })
await rpc.call('hub:docks:activate', {
dockId: 'devframes_plugin_terminals',
params: { sessionId },
})Focus is one-shot; an unknown id waits for the session.
Deep linking
Standalone, the panel keeps the selected session in the URL hash (#id=<sessionId>), so a copied link reopens it (deep-linking guide).
RPC
Namespaced devframes:plugin:terminals:*:
| Function | Type | Purpose |
|---|---|---|
list | query (snapshot) | Sessions (status, mode, command). |
presets | query (snapshot) | Declared launcher presets. |
spawn | action | Start from a preset id or command+mode. |
write | action | Input to an interactive session. |
resize | action | Resize the PTY (columns × rows). |
restart | action | Restart, keeping scrollback. |
rename | action | Rename a session. |
terminate | action | End the process; keep the session. |
remove | action | Kill and discard. |
clear-exited | action | Discard stopped sessions. |
Status and mutations mirror into shared state, keeping panels in sync.