#!/usr/bin/env bun const defaultFrontendPort = 18081; const sshInputChunkBytes = 32 * 1024; function jsonHelp() { return { ok: true, tool: "tran", purpose: "AgentRun runner UniDesk SSH passthrough over frontend /ws/ssh", requiredEnv: ["UNIDESK_SSH_CLIENT_TOKEN", "UNIDESK_MAIN_SERVER_IP or UNIDESK_FRONTEND_URL"], supported: [ "tran ", "tran argv ", "tran script -- ''", "tran :/absolute/workspace script -- ''", "tran :/absolute/workspace apply-patch < patch.diff", "tran :k3s kubectl ", "tran :k3s script -- ''", "tran :k3s::[:container] argv ", "tran :k3s::[:container] script -- ''", "tran :k3s::[:container] apply-patch < patch.diff", ], unsupported: ["upload", "download", "Windows win/ps/cmd routes"], valuesPrinted: false, }; } function writeJson(value, stream = process.stdout) { stream.write(`${JSON.stringify(value)}\n`); } function fail(failureKind, message, details = {}, exitCode = 2) { writeJson({ ok: false, failureKind, message, ...details, valuesPrinted: false }, process.stderr); process.exit(exitCode); } function shellQuote(value) { return `'${String(value).replace(/'/g, `'"'"'`)}'`; } function shellArgv(args) { if (args.length === 0) return ""; return args.map(shellQuote).join(" "); } function baseUrlFromEnv(env) { const explicit = (env.UNIDESK_FRONTEND_URL || env.UNIDESK_MAIN_SERVER_URL || "").trim(); if (explicit) return explicit.replace(/\/+$/g, ""); const host = (env.UNIDESK_MAIN_SERVER_IP || env.UNIDESK_MAIN_SERVER_HOST || env.CODE_QUEUE_DEV_CONTAINER_MASTER_HOST || "").trim(); if (!host) return null; if (host.startsWith("http://") || host.startsWith("https://")) return host.replace(/\/+$/g, ""); if (/:[0-9]+$/u.test(host)) return `http://${host}`; const port = Number(env.UNIDESK_FRONTEND_PORT || env.UNIDESK_MAIN_SERVER_PORT || defaultFrontendPort); return `http://${host}:${Number.isInteger(port) && port > 0 ? port : defaultFrontendPort}`; } function websocketUrl(baseUrl) { const url = new URL("/ws/ssh", baseUrl); url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; return url.toString(); } function parseRoute(raw) { const parts = String(raw).split(":"); const providerId = parts.shift() || ""; if (!providerId) fail("schema-invalid", "tran route requires a provider id", { route: raw }); if (parts.length === 0) return { providerId, plane: "host", workspace: null, namespace: null, resource: null, container: null, raw }; if (parts[0] === "win") fail("unsupported-operation", "AgentRun tran does not support Windows routes yet", { route: raw }); if (parts[0] === "k3s") { return { providerId, plane: "k3s", workspace: null, namespace: parts[1] || null, resource: parts[2] || null, container: parts[3] || null, raw, }; } const workspace = parts.join(":"); if (!workspace.startsWith("/")) fail("schema-invalid", "host workspace routes must be absolute paths", { route: raw }); return { providerId, plane: "host", workspace, namespace: null, resource: null, container: null, raw }; } async function readStdinText() { const chunks = []; for await (const chunk of Bun.stdin.stream()) chunks.push(Buffer.from(chunk)); return Buffer.concat(chunks).toString("utf8"); } async function readApplyPatchHelperSource() { const helperPath = new URL("./apply_patch", import.meta.url); try { const text = await Bun.file(helperPath).text(); if (!text.startsWith("#!")) fail("infra-failed", "adjacent apply_patch helper is not executable script shaped", { helper: "tools/apply_patch" }); return text; } catch (error) { fail("infra-failed", "adjacent apply_patch helper is required for runner-side tran apply-patch", { helper: "tools/apply_patch", error: error instanceof Error ? error.message : String(error) }); } } function applyPatchToolArgs(args) { const supported = new Set(["--allow-loose", "--help", "-h"]); for (const arg of args) { if (!supported.has(arg)) fail("schema-invalid", `unsupported apply-patch option: ${arg}`, { supported: [...supported].sort() }); } return args; } function base64Text(value) { return Buffer.from(value, "utf8").toString("base64").replace(/.{1,76}/g, "$&\n").trimEnd(); } async function applyPatchRemoteScript(args) { const toolArgs = applyPatchToolArgs(args); const [helperSource, patchText] = await Promise.all([readApplyPatchHelperSource(), readStdinText()]); if (patchText.trim().length === 0) fail("schema-invalid", "apply-patch requires patch text on stdin"); const helperMarker = "__AGENTRUN_TRAN_APPLY_PATCH_HELPER__"; const patchMarker = "__AGENTRUN_TRAN_APPLY_PATCH_BODY__"; const toolArgText = toolArgs.length > 0 ? ` ${shellArgv(toolArgs)}` : ""; return [ "set -eu", "helper=$(mktemp \"${TMPDIR:-/tmp}/agentrun-apply-patch.XXXXXX\") || exit 1", "patch_file=$(mktemp \"${TMPDIR:-/tmp}/agentrun-apply-patch-body.XXXXXX\") || exit 1", "cleanup() { rm -f \"$helper\" \"$patch_file\"; }", "trap cleanup EXIT HUP INT TERM", "decode_b64() { base64 -d; }", `decode_b64 > \"$helper\" <<'${helperMarker}'`, base64Text(helperSource), helperMarker, `decode_b64 > \"$patch_file\" <<'${patchMarker}'`, base64Text(patchText), patchMarker, "chmod 700 \"$helper\"", `\"$helper\"${toolArgText} < \"$patch_file\"`, ].join("\n"); } async function scriptCommand(args) { if (args[0] === "--") { const rest = args.slice(1); if (rest.length === 0) return await readStdinText(); if (rest.length === 1) return rest[0]; return shellArgv(rest); } if (args.length === 0) return await readStdinText(); return shellArgv(args); } async function hostCommand(route, args) { if (args.length === 0) return { command: null, cwd: route.workspace, tty: true }; const op = args[0]; if (op === "apply-patch") return { command: await applyPatchRemoteScript(args.slice(1)), cwd: route.workspace, tty: false }; if (op === "upload" || op === "download") { fail("unsupported-operation", `AgentRun tran does not support ${op}; use host/source controlled tools outside the runner for that operation`, { operation: op }); } if (op === "script" || op === "shell") return { command: await scriptCommand(args.slice(1)), cwd: route.workspace, tty: false }; if (op === "argv") return { command: shellArgv(args.slice(1)), cwd: route.workspace, tty: false }; return { command: shellArgv(args), cwd: route.workspace, tty: false }; } function k3sExecPrefix(route) { const base = ["env", "KUBECONFIG=/etc/rancher/k3s/k3s.yaml", "kubectl", "exec"]; if (route.namespace) base.push("-n", route.namespace); if (!route.resource) fail("schema-invalid", "k3s workload routes require namespace and resource", { route: route.raw }); base.push(route.resource); if (route.container) base.push("-c", route.container); base.push("--"); return base; } async function k3sCommand(route, args) { const op = args[0] || "kubectl"; if (op === "upload" || op === "download") { fail("unsupported-operation", `AgentRun tran does not support ${op}; use host/source controlled tools outside the runner for that operation`, { operation: op }); } if (!route.resource) { if (op === "apply-patch") fail("schema-invalid", "k3s apply-patch requires namespace and workload route", { route: route.raw }); if (op === "kubectl") return { command: shellArgv(["env", "KUBECONFIG=/etc/rancher/k3s/k3s.yaml", "kubectl", ...args.slice(1)]), cwd: null, tty: false }; if (op === "script" || op === "shell") { const script = await scriptCommand(args.slice(1)); return { command: `export KUBECONFIG=/etc/rancher/k3s/k3s.yaml; ${script}`, cwd: null, tty: false }; } if (op === "argv") return { command: shellArgv(["env", "KUBECONFIG=/etc/rancher/k3s/k3s.yaml", ...args.slice(1)]), cwd: null, tty: false }; return { command: shellArgv(["env", "KUBECONFIG=/etc/rancher/k3s/k3s.yaml", ...args]), cwd: null, tty: false }; } if (op === "apply-patch") { const script = await applyPatchRemoteScript(args.slice(1)); return { command: shellArgv([...k3sExecPrefix(route), "sh", "-lc", script]), cwd: null, tty: false }; } if (op === "script" || op === "shell") { const script = await scriptCommand(args.slice(1)); return { command: shellArgv([...k3sExecPrefix(route), "sh", "-lc", script]), cwd: null, tty: false }; } if (op === "argv") return { command: shellArgv([...k3sExecPrefix(route), ...args.slice(1)]), cwd: null, tty: false }; return { command: shellArgv([...k3sExecPrefix(route), ...args]), cwd: null, tty: false }; } async function buildOpenPayload(argv) { if (argv.length === 0) fail("schema-invalid", "tran requires a route", { help: jsonHelp() }); const route = parseRoute(argv[0]); const parsed = route.plane === "k3s" ? await k3sCommand(route, argv.slice(1)) : await hostCommand(route, argv.slice(1)); return { providerId: route.providerId, command: parsed.command || undefined, cwd: parsed.cwd || undefined, tty: parsed.tty === true, cols: Number(process.stdout.columns) > 0 ? Number(process.stdout.columns) : 100, rows: Number(process.stdout.rows) > 0 ? Number(process.stdout.rows) : 30, openTimeoutMs: Math.max(15000, Math.min(Number(process.env.UNIDESK_SSH_OPEN_TIMEOUT_MS || 60000), 60000)), runtimeTimeoutMs: Math.max(1000, Math.min(Number(process.env.UNIDESK_SSH_RUNTIME_TIMEOUT_MS || process.env.UNIDESK_TRAN_RUNTIME_TIMEOUT_MS || 60000), 60000)), stdinEotOnEnd: true, route: route.raw, }; } async function main() { const argv = process.argv.slice(2); if (argv[0] === "--help" || argv[0] === "help" || argv[0] === "-h") { writeJson(jsonHelp()); return; } const token = (process.env.UNIDESK_SSH_CLIENT_TOKEN || "").trim(); if (!token) fail("secret-unavailable", "UNIDESK_SSH_CLIENT_TOKEN is required for runner-side tran"); const baseUrl = baseUrlFromEnv(process.env); if (!baseUrl) fail("schema-invalid", "UNIDESK_MAIN_SERVER_IP, UNIDESK_MAIN_SERVER_HOST, or UNIDESK_FRONTEND_URL is required for runner-side tran"); const open = await buildOpenPayload(argv); await runWebSocket(open, websocketUrl(baseUrl), token); } async function runWebSocket(open, url, token) { const ws = new WebSocket(url, { headers: { authorization: `Bearer ${token}` } }); let exitCode = 255; let canSend = false; let sessionReady = false; let settled = false; const pending = []; const pendingInput = []; const send = (value) => { const text = JSON.stringify(value); if (!canSend || ws.readyState !== WebSocket.OPEN) pending.push(text); else ws.send(text); }; const sendInput = (value) => { const text = JSON.stringify(value); if (!sessionReady || ws.readyState !== WebSocket.OPEN) pendingInput.push(text); else ws.send(text); }; const flush = () => { while (pending.length > 0 && ws.readyState === WebSocket.OPEN) ws.send(pending.shift()); }; const flushInput = () => { if (!sessionReady || ws.readyState !== WebSocket.OPEN) return; while (pendingInput.length > 0) ws.send(pendingInput.shift()); }; const finish = (code) => { if (settled) return; settled = true; clearTimeout(openTimer); clearTimeout(runtimeTimer); process.exit(code); }; const openTimer = setTimeout(() => { if (sessionReady || settled) return; process.stderr.write("unidesk runner tran timed out waiting for provider session\n"); exitCode = 255; try { ws.close(); } catch {} }, open.openTimeoutMs); const runtimeTimer = setTimeout(() => { if (settled) return; process.stderr.write(`UNIDESK_TRAN_TIMEOUT_HINT ${JSON.stringify({ code: "tran-runtime-timeout", level: "warning", route: open.route, timeoutMs: open.runtimeTimeoutMs, message: "tran exceeded the runtime limit; use short query plus poll semantics" })}\n`); exitCode = 124; try { ws.close(); } catch {} finish(124); }, open.runtimeTimeoutMs); ws.addEventListener("open", () => { canSend = true; send({ type: "ssh.open", providerId: open.providerId, command: open.command, cwd: open.cwd, tty: open.tty, cols: open.cols, rows: open.rows }); flush(); }); ws.addEventListener("message", (event) => { let message; const text = typeof event.data === "string" ? event.data : Buffer.from(event.data).toString("utf8"); try { message = JSON.parse(text); } catch { process.stderr.write(`${text}\n`); return; } if (message.type === "ssh.dispatched") return; if (message.type === "ssh.opened") { sessionReady = true; clearTimeout(openTimer); sendInput({ type: "ssh.input", data: Buffer.from([4]).toString("base64"), encoding: "base64" }); sendInput({ type: "ssh.eof" }); flushInput(); return; } if (message.type === "ssh.data") { const chunk = Buffer.from(String(message.data || ""), message.encoding === "base64" ? "base64" : "utf8"); if (message.stream === "stderr") process.stderr.write(chunk); else process.stdout.write(chunk); return; } if (message.type === "ssh.error") { process.stderr.write(`${String(message.message || "ssh bridge error")}\n`); exitCode = 255; try { ws.close(); } catch {} return; } if (message.type === "ssh.exit") { exitCode = Number.isInteger(message.exitCode) ? Number(message.exitCode) : 255; try { ws.close(); } catch {} } }); ws.addEventListener("close", () => finish(exitCode)); ws.addEventListener("error", () => { process.stderr.write("unidesk runner tran websocket error\n"); finish(255); }); } await main();