sudo commands through ephemeral terminal

This commit is contained in:
2026-02-19 21:43:37 +00:00
parent 04c79a09f0
commit 7c0b11c5a5
6 changed files with 240 additions and 46 deletions
+44 -34
View File
@@ -3,9 +3,16 @@ import { existsSync } from 'node:fs';
import { cp, mkdir } from 'node:fs/promises';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { execFile } from 'node:child_process';
import { WebSocketServer } from 'ws';
import * as pty from 'node-pty';
const run = (cmd, args, opts = {}) =>
new Promise((resolve) => {
const proc = execFile(cmd, args, { stdio: 'ignore', ...opts }, () => resolve());
proc.on('error', () => resolve());
});
const __dirname = dirname(fileURLToPath(import.meta.url));
const isDocker = existsSync('/opt/terminal-templates/.zshrc');
@@ -60,25 +67,14 @@ const ensureUserFiles = async (homeDir) => {
if (ohMyZshSource && existsSync(ohMyZshSource)) {
await cp(ohMyZshSource, ohMyZshPath, { recursive: true });
} else {
const proc = Bun.spawn({
cmd: ['git', 'clone', '--depth=1', 'https://github.com/ohmyzsh/ohmyzsh.git', ohMyZshPath],
stdout: 'ignore',
stderr: 'ignore',
});
await proc.exited;
await run('git', ['clone', '--depth=1', 'https://github.com/ohmyzsh/ohmyzsh.git', ohMyZshPath]);
}
}
if (!isDocker) {
const starshipBin = join(homeDir, '.local', 'bin', 'starship');
if (!existsSync(starshipBin)) {
const installProc = Bun.spawn({
cmd: ['sh', '-c', 'curl -sS https://starship.rs/install.sh | sh -s -- -y -b "$HOME/.local/bin"'],
env: { ...process.env, HOME: homeDir },
stdout: 'ignore',
stderr: 'ignore',
});
await installProc.exited;
await run('sh', ['-c', 'curl -sS https://starship.rs/install.sh | sh -s -- -y -b "$HOME/.local/bin"'], { env: { ...process.env, HOME: homeDir } });
}
}
};
@@ -149,15 +145,36 @@ wss.on('connection', (ws) => {
const cwd = msg.cwd ?? process.cwd();
const homeDir = msg.homeDir ?? process.cwd();
const userLabel = msg.userLabel ?? 'officer';
const prompt = `${userLabel} in %~ %# `;
const bashPrompt = `${userLabel} \\w \\$ `;
const cols = msg.cols ?? 80;
const rows = msg.rows ?? 24;
const isHost = !!msg.host;
try {
await ensureUserFiles(homeDir);
} catch {
// ignore
let ptyEnv;
if (isHost) {
ptyEnv = { ...process.env, TERM: 'xterm-256color' };
} else {
const prompt = `${userLabel} in %~ %# `;
const bashPrompt = `${userLabel} \\w \\$ `;
try {
await ensureUserFiles(homeDir);
} catch {
// ignore
}
ptyEnv = {
...process.env,
HOME: homeDir,
ZDOTDIR: homeDir,
ZSH: `${homeDir}/.oh-my-zsh`,
SHELL: shell.command,
USER: userLabel,
LOGNAME: userLabel,
OFFICER_TERMINAL_USER: userLabel,
PROMPT: prompt,
PS1: bashPrompt,
TERM: 'xterm-256color',
};
}
let term;
@@ -167,19 +184,7 @@ wss.on('connection', (ws) => {
cols,
rows,
cwd,
env: {
...process.env,
HOME: homeDir,
ZDOTDIR: homeDir,
ZSH: `${homeDir}/.oh-my-zsh`,
SHELL: shell.command,
USER: userLabel,
LOGNAME: userLabel,
OFFICER_TERMINAL_USER: userLabel,
PROMPT: prompt,
PS1: bashPrompt,
TERM: 'xterm-256color',
},
env: ptyEnv,
});
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to start terminal';
@@ -205,7 +210,8 @@ wss.on('connection', (ws) => {
}
});
term.onExit(() => {
term.onExit(({ exitCode, signal }) => {
console.log(`[sidecar] session ${sessionId} exited code=${exitCode} signal=${signal}`);
if (session.ws) {
sendJson(session.ws, { type: 'exit' });
}
@@ -228,7 +234,11 @@ wss.on('connection', (ws) => {
if (msg.cols > 0 && msg.rows > 0) {
session.cols = msg.cols;
session.rows = msg.rows;
session.term.resize(msg.cols, msg.rows);
try {
session.term.resize(msg.cols, msg.rows);
} catch {
// PTY may have already exited
}
}
break;
case 'cwd':