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(t.text)}
`; if (t.role === "auth") return `
${t.phase === "connected" ? "๐Ÿ”“" : "๐Ÿ”"} ${esc(t.text)}
`; if (t.role === "assistant") return `
${esc(t.text)}
`; if (t.role === "tool") return `
๐Ÿ”ง ${esc(t.call.name)} ${t.ok ? "โœ“" : "โœ—"} โ†’ ${esc(String(t.text).slice(0, 100))}
${esc(JSON.stringify({ args: t.call.args, result: t.result }, null, 2))}
`; if (t.role === "assert") return `
${t.ok ? "โœ…" : "โŒ"} expect(${esc(JSON.stringify(t.actual))}).${t.kind}(${esc(JSON.stringify(t.expected))})
`; if (t.role === "error") return `
๐Ÿ’ฅ ${esc(t.text)}
`; return ""; }; return `${esc(run.task)}

MCP run ยท ${run.ok ? "PASSED" : "FAILED"}

${run.turns.map(bubble).join("\n")}

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)); }