import { defineCommand } from "citty"; import { getPodContainerName, getPodForDeployment } from "../lib/shared"; import { execClient } from "../lib/k8s"; function prepareInteractiveStdin(): (() => void) | undefined { if (!process.stdin.isTTY) return; process.stdin.setRawMode?.(true); process.stdin.resume(); return () => { process.stdin.setRawMode?.(false); process.stdin.pause(); }; } export const exec = defineCommand({ meta: { name: "exec", description: "Execute a command inside a deployment pod", }, async run({ args }) { const [deployment, ...command] = args._; if (!deployment) throw new Error("Deployment name is required"); if (command.length === 0) throw new Error("Command is required"); const pod = await getPodForDeployment(deployment); if (pod.status?.phase !== "Running") { throw new Error( `Deployment ${deployment} has no running pod to exec into (${pod.metadata?.name ?? "unknown pod"} is ${pod.status?.phase ?? "not ready"})`, ); } const namespace = pod.metadata?.namespace ?? "default"; const podName = pod.metadata?.name; if (!podName) throw new Error(`No pod name found for deployment ${deployment}`); const restoreStdin = prepareInteractiveStdin(); try { const socket = await execClient.exec( namespace, podName, getPodContainerName(pod), command, process.stdout, process.stderr, process.stdin, Boolean(process.stdin.isTTY), ); await new Promise((resolve, reject) => { socket.onclose = () => resolve(); socket.onerror = (event: { error?: unknown }) => reject(event.error ?? new Error("Exec failed")); }); } finally { restoreStdin?.(); } }, });