//// // The shell runs on the server and processes input, returning output. import type { Message, CommandResult, CommandOutput } from "../shared/types.js" import { addInput, setStatus, addOutput, appendOutput, replaceOutput } from "./scrollback.js" import { send } from "./websocket.js" import { randomId } from "../shared/utils.js" import { addToHistory } from "./history.js" import { browserCommands, cacheCommands } from "./commands.js" export function runCommand(input: string) { if (!input.trim()) return const id = randomId() addToHistory(input) addInput(id, input) const [cmd = "", ...args] = input.split(" ") if (browserCommands[cmd]) { const result = browserCommands[cmd]() if (typeof result === "string") addOutput(id, result) setStatus(id, "ok") } else { send({ id, type: "input", data: input }) } } // message received from server export function handleMessage(msg: Message) { switch (msg.type) { case "output": handleOutput(msg); break case "commands": cacheCommands(msg.data as string[]); break case "error": console.error(msg.data); break case "stream:start": handleStreamStart(msg); break case "stream:end": handleStreamEnd(msg); break case "stream:append": handleStreamAppend(msg); break case "stream:replace": handleStreamReplace(msg); break default: console.error("unknown message type", msg) } } function handleOutput(msg: Message) { const result = msg.data as CommandResult setStatus(msg.id!, result.status) addOutput(msg.id!, result.output) } function handleStreamStart(msg: Message) { const id = msg.id! const status = document.querySelector(`[data-id="${id}"].input .status`) if (!status) return addOutput(id, msg.data as CommandOutput) status.classList.remove("yellow") status.classList.add("purple") } function handleStreamAppend(msg: Message) { appendOutput(msg.id!, msg.data as CommandOutput) } function handleStreamReplace(msg: Message) { replaceOutput(msg.id!, msg.data as CommandOutput) } function handleStreamEnd(msg: Message) { const id = msg.id! const status = document.querySelector(`[data-id="${id}"].input .status`) if (!status) return status.classList.remove("purple") status.classList.remove("green") }