import { readFileSync, writeFileSync } from "node:fs"; const C = { dim: "\x1b[2m", grn: "\x1b[32m", red: "\x1b[31m", cyn: "\x1b[36m", yel: "\x1b[33m", b: "\x1b[1m", r: "\x1b[0m" }; const icon = { user: "๐ง", assistant: "๐ค", tool: "๐ง", assert: " ", error: "๐ฅ" }; export function renderTerminal(run) { const L = []; L.push(`${C.b}${run.ok ? C.grn + "โ" : C.red + "โ"} ${run.task}${C.r} ${C.dim}(${run.durationMs}ms, brain=${run.brain})${C.r}`); for (const t of run.turns) { if (t.role === "user") L.push(`\n${icon.user} ${C.b}${t.text}${C.r}`); else if (t.role === "assistant") L.push(`${icon.assistant} ${C.dim}${t.text}${C.r}`); else if (t.role === "auth") L.push(`${t.phase === "connected" ? "๐" : "๐"} ${C.yel}${t.text}${C.r}`); else if (t.role === "tool") L.push(`${icon.tool} ${C.cyn}${t.call.name}${C.r}(${C.dim}${JSON.stringify(t.call.args)}${C.r}) ${t.ok ? C.grn + "โ" : C.red + "โ"}${C.r} ${C.dim}โ ${String(t.text).slice(0, 80)}${C.r}`); else if (t.role === "assert") L.push(`${t.ok ? C.grn + " โ " : C.red + " โ"} expect(${JSON.stringify(t.actual)}).${t.kind}(${JSON.stringify(t.expected)})${C.r}`); else if (t.role === "error") L.push(`${icon.error} ${C.red}${t.text}${C.r}`); } return L.join("\n"); } export function renderHtml(run) { const esc = (s) => String(s).replace(/[&<>]/g, (c) => ({ "&": "&", "<": "<", ">": ">" }[c])); const bubble = (t) => { if (t.role === "user") return `
${esc(JSON.stringify({ args: t.call.args, result: t.result }, null, 2))}brain=${run.brain} ยท ${run.durationMs}ms ยท ${esc(run.meta?.server ?? "")}
`; } if (process.argv[1]?.endsWith("render.mjs")) { const file = process.argv[2]; const run = JSON.parse(readFileSync(file, "utf8")); const htmlArg = process.argv.indexOf("--html"); if (htmlArg > -1) { const out = process.argv[htmlArg + 1]; writeFileSync(out, renderHtml(run)); console.log("wrote", out); } else console.log(renderTerminal(run)); } import { dirname, join as _join } from "node:path"; import { fileURLToPath } from "node:url"; export function renderPlayer(run) { const tpl = readFileSync(_join(dirname(fileURLToPath(import.meta.url)), "player.template.html"), "utf8"); return tpl.replace("__RUN__", JSON.stringify(run)); }