nose-pluto/app/src/js/shell.ts
2025-09-26 21:12:48 -07:00

87 lines
2.4 KiB
TypeScript

////
// 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")
}