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
+19
View File
@@ -3,10 +3,13 @@ import cors from "cors";
import { createServer } from "http";
import path from "path";
import { fileURLToPath } from "url";
import { WebSocketServer } from "ws";
import { initWebSocket, getClientCount } from "./services/ws.service.js";
import workspaceRouter from "./routes/workspace.js";
import dockerRouter from "./routes/docker.js";
import editorRouter from "./routes/editor.js";
import terminalRouter from "./routes/terminal.js";
import { attachWebSocket, createTerminalSession } from "./services/terminal.service.js";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const app = express();
@@ -28,6 +31,7 @@ app.get("/api/health", (_req, res) => {
app.use("/api/workspace", workspaceRouter);
app.use("/api/docker", dockerRouter);
app.use("/api/editor", editorRouter);
app.use("/api/terminal", terminalRouter);
const frontendDist = path.resolve(__dirname, "../../frontend/dist");
app.use(express.static(frontendDist));
@@ -35,6 +39,21 @@ app.get("*path", (_req, res) => {
res.sendFile(path.join(frontendDist, "index.html"));
});
server.on("upgrade", (request, socket, head) => {
const url = new URL(request.url || "", `http://${request.headers.host}`);
const termMatch = url.pathname.match(/^\/ws\/terminal\/(.+)$/);
if (termMatch) {
const sessionId = termMatch[1];
const termWss = new WebSocketServer({ noServer: true });
termWss.handleUpgrade(request, socket, head, (ws) => {
if (!attachWebSocket(sessionId, ws)) {
createTerminalSession(sessionId);
attachWebSocket(sessionId, ws);
}
});
}
});
const PORT = parseInt(process.env.PORT || "3000", 10);
server.listen(PORT, "0.0.0.0", () => {
console.log(`Layonara Forge listening on http://0.0.0.0:${PORT}`);