//// // runs commands and such. import type { CommandResult, CommandOutput } from "./shared/types" import type { State } from "./state" import { join } from "path" import { NOSE_SYS_BIN, NOSE_BIN } from "./config" import { isFile } from "./utils" import { ALS } from "./state" const sessions: Map = new Map() export async function runCommand(session: string, id: string, input: string): Promise { const [cmd = "", ...args] = input.split(" ") if (!commandExists(cmd)) { return { status: "error", output: `${cmd} not found` } } let status: "ok" | "error" = "ok" let output: CommandOutput = "" const state = getState(session, id) try { [status, output] = await ALS.run(state, async () => await exec(cmd, args)) } catch (err) { status = "error" output = errorMessage(err) } return { status, output } } async function exec(cmd: string, args: string[]): Promise<["ok" | "error", CommandOutput]> { const module = await import(commandPath(cmd) + "?t+" + Date.now()) if (!module || !module.default) return ["error", `${cmd} has no default export`] return processExecOutput(await module.default(...args)) } function processExecOutput(output: string | any): ["ok" | "error", CommandOutput] { if (typeof output === "string") { return ["ok", output] } else if (typeof output === "object") { if (output.error) { return ["error", output.error] } else { return ["ok", output] } } else { return ["ok", String(output)] } } function getState(session: string, id: string): State { let state = sessions.get(session) if (!state) { state = { session, project: "" } sessions.set(session, state) } state.id = id return state } function commandPath(cmd: string): string | undefined { const sysPath = join(NOSE_SYS_BIN, cmd + ".ts") const usrPath = join(NOSE_BIN, cmd + ".ts") return (isFile(sysPath) && sysPath) || (isFile(usrPath) && usrPath) || undefined } function commandExists(cmd: string): boolean { return commandPath(cmd) !== undefined } function errorMessage(error: Error | any): string { if (!(error instanceof Error)) return String(error) let msg = `${error.name}: ${error.message}` if (error.stack) msg += `\n${error.stack}` return msg }