feat(plugin-terminals): terminals plugin with readonly + interactive PTY modes#37
Draft
antfubot wants to merge 8 commits into
Draft
feat(plugin-terminals): terminals plugin with readonly + interactive PTY modes#37antfubot wants to merge 8 commits into
antfubot wants to merge 8 commits into
Conversation
…ive PTY modes Introduce @devframes/plugin-terminals, a portable hub-native terminal panel built on the core devframe RPC + streaming surface (no hard hub dependency). It runs standalone via the CLI, mounts into a Vite host, and docks inside a hub. Two interaction modes: - readonly: a piped child process whose merged output is streamed to viewers; input is rejected. Ideal for dev servers / logs. - interactive: a real PTY (node-pty prebuilt) that accepts keystrokes and resize, so full-screen TUIs (vim, htop, Claude Code) render correctly. Falls back to a piped child process with a diagnostic when no PTY backend is present. Output streams over a per-session channel (one stream kept open for the session's life so restart reuses the same id), session metadata syncs via shared state, and spawning is allow-list gated (presets + opt-in arbitrary commands). Ships node + client + cli + vite entries plus a self-contained xterm SPA, structured DP_TERMINALS diagnostics, and an e2e test suite covering streaming, stdin, TTY detection, and SIGWINCH.
✅ Deploy Preview for devfra ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
…ith rename - Follow the system color mode and react to changes at runtime: the UI chrome (CSS variables) and every xterm instance switch between dark and a GitHub-light palette without reload, driven by prefers-color-scheme. - Tab labels show the live foreground process of the controlling TTY (e.g. bash → vim → bash), polled from node-pty for PTY sessions. - Custom renaming: double-click a tab to edit inline; backed by a new `devframes-plugin-terminals:rename` RPC. Display precedence is customTitle > processName > base title. Adds processName/customTitle to the session descriptor, a getProcessName hook on the PTY backend, an unref'd poll timer (cleared on exit/restart/ remove/dispose), and tests for process-name tracking and renaming.
…etadata, per-package typecheck) Merge upstream/main and reconcile the plugin with its newer baseline: - resolve to nostics ^1.1.4 via the catalog and regenerate the lockfile (fixes the broken merged lockfile that failed frozen CI installs). - supply the now-required DevframeDefinition metadata (version, packageName, homepage, description) from package.json. - add a `typecheck` script and switch tsconfig to explicit include/exclude (drop composite) so `turbo run typecheck` passes for the package. - refresh tsnapi snapshots for the nostics v1 diagnostics handle shape.
- Gate the PTY-semantics tests (stdin echo, SIGWINCH resize, foreground process name) to POSIX; Windows keeps the isTTY interactive coverage. These rely on behaviours conpty doesn't provide (no SIGWINCH; `.process` returns the TERM name). - Ignore the Windows `xterm-256color` TERM-name fallback so it never surfaces as a session label. - Dispose the terminal manager on test server close so spawned PTY/piped child processes don't leak across runs.
…, + tab - Mirror the active terminal into the URL hash (`#id=<sessionId>`) and react to external hash changes (links, back/forward, manual edits). - Spawn and select a fresh interactive session on every page load. - Move the "new terminal" affordance to a compact "+" pinned at the end of the tab strip. Avoids refocusing the active terminal on background shared-state updates by only fitting/focusing when the selection actually changes.
The prebuilt PTY binary isn't published for every Node ABI on every OS (e.g. Node 26 on Windows 404s and the source-build fallback crashes), which failed `pnpm install`. node-pty is already lazily imported with a piped-child fallback, so move it to optionalDependencies — a missing prebuild is now non-fatal. Gate the PTY tests on actual backend availability: the real-TTY check runs wherever a PTY exists (incl. Windows conpty), while the POSIX-only semantics (SIGWINCH, foreground process name, stdin echo) stay POSIX-gated.
…d of spawning A reload was always starting a new shell: the sessions shared state resolves with its empty initial value and backfills the server's sessions asynchronously, so the autostart check always saw an empty list. Decide autostart from the authoritative `list` RPC and seed the initial render from it, so a refresh restores the persisted sessions (reselecting the URL-hashed one) and only spawns a shell when none exist.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
@devframes/plugin-terminals— the built-in terminals plugin (#2 in the plugin planning index) — as a newplugins/*workspace. It's a portable, hub-native terminal panel built on the core devframe RPC + streaming surface (no hard hub dependency): it runs standalone via the CLI, mounts into a Vite host, and docks inside a hub.Modes
writeis rejected (DP_TERMINALS_0003). Ideal for dev servers / logs.@homebridge/node-pty-prebuilt-multiarch, prebuilt so there's no native compile step) that accepts keystrokes and resize. Degrades to a piped child process with a diagnostic when no PTY backend is available.TUI support (e.g. Claude Code)
Interactive sessions are backed by a genuine pseudo-terminal, verified end-to-end:
process.stdout.isTTY === true),What's included (
plugins/terminals/)TerminalManager(PTY + pipe backends; one stream per session kept open for the session's life sorestartreuses the same id),setupTerminals(ctx), allow-list spawn model (presets+ opt-inallowArbitraryCommands, default-deny), structuredDP_TERMINALS_*diagnostics.defineRpcFunction, namespaceddevframes-plugin-terminals:*):list,presets,spawn,write,resize,terminate,restart,remove, withdeclare module 'devframe'augmentation for server functions + shared-state keys.mountTerminals()xterm.js renderer (CSS inlined, self-contained) — input wired for interactive, disabled for readonly, fit/resize handling. Reusable by the SPA and as a hubcustom-renderentry..(createTerminalsDevframefactory + default export),/cli,/vite, plusbin.mjs. Mount path followsresolveBasePath(/standalone,/__id/hosted).Repo wiring
pnpm-workspace.yaml(plugins/*glob + catalogs for node-pty & xterm + allow-build),turbo.json,alias.ts/tsconfig.base.json,vitest.config.ts.Verification
pnpm lint && pnpm test && pnpm buildall green (379 tests, 38 files). Plugin suite covers readonly streaming + exit, readonly write rejection, interactive PTY stdin, TTY detection, SIGWINCH resize, restart id reuse, list/remove, presets, and arbitrary-command rejection — over a real HTTP + WebSocket harness. tsnapi API snapshots added for every entry.This PR was created with the help of an agent.