feat: add integrated terminal with xterm.js and shell sessions

This commit is contained in:
plenarius
2026-04-20 19:32:02 -04:00
parent b36391b520
commit 64908098cd
7 changed files with 242 additions and 10 deletions
@@ -0,0 +1,52 @@
import { spawn, ChildProcess } from "child_process";
import { WebSocket } from "ws";
interface TerminalSession {
id: string;
process: ChildProcess;
ws: WebSocket | null;
}
const sessions = new Map<string, TerminalSession>();
export function createTerminalSession(id: string): TerminalSession {
const proc = spawn("/bin/bash", ["-l"], {
env: { ...process.env, TERM: "xterm-256color" },
cwd: process.env.WORKSPACE_PATH || "/workspace",
});
const session: TerminalSession = { id, process: proc, ws: null };
sessions.set(id, session);
proc.on("exit", () => sessions.delete(id));
return session;
}
export function attachWebSocket(sessionId: string, ws: WebSocket): boolean {
const session = sessions.get(sessionId);
if (!session) return false;
session.ws = ws;
session.process.stdout?.on("data", (data: Buffer) => {
if (ws.readyState === WebSocket.OPEN) ws.send(data.toString());
});
session.process.stderr?.on("data", (data: Buffer) => {
if (ws.readyState === WebSocket.OPEN) ws.send(data.toString());
});
ws.on("message", (data) => {
session.process.stdin?.write(data.toString());
});
ws.on("close", () => {
session.ws = null;
});
return true;
}
export function destroySession(id: string): void {
const session = sessions.get(id);
if (session) {
session.process.kill();
sessions.delete(id);
}
}
export function listSessions(): string[] {
return Array.from(sessions.keys());
}