File size: 3,070 Bytes
adcc1b7
07d8f3f
f6c942e
07d8f3f
 
 
f6c942e
 
07d8f3f
 
f6c942e
 
07d8f3f
f6c942e
07d8f3f
adcc1b7
f6c942e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { parseTrace, compareBranch, parseExchange, toExchange, attachFindings, downloadJson } from "./replay-core.js";
const $ = selector => document.querySelector(selector);
let trace = null; let importedFindings = [];
function esc(value) { return String(value ?? "").replace(/[&<>'"]/g, c => ({"&":"&amp;","<":"&lt;",">":"&gt;","'":"&#39;",'"':"&quot;"}[c])); }
function renderEvents(events, target) { target.innerHTML = events.map(event => `<article class="event"><span class="seq">${event.sequence ?? "路"}</span><strong>${esc(event.event_type)}</strong><span>${esc(event.actor)}</span><p>${esc(event.output_summary || event.input_summary || "")}</p></article>`).join("") || "<p class=muted>No events.</p>"; }
function renderTrace() {
  $("#meta").textContent = `${trace.trace_id}${trace.source_type || trace.source?.format || "trace"}${(trace.original_trajectory || trace.events).length} events`;
  if (trace.original_trajectory) { renderEvents(trace.original_trajectory, $("#original-events")); const select = $("#branch"); select.innerHTML = trace.branches.map(branch => `<option value="${esc(branch.branch_id)}">${esc(branch.branch_id)}</option>`).join(""); }
  renderComparison();
}
function renderComparison() { if (!trace || !trace.branches?.length) return; const comparison = compareBranch(trace, $("#branch").value); renderEvents(comparison.alternate, $("#alternate-events")); $("#classification").textContent = comparison.classification; $("#outcomes").textContent = `Original: ${JSON.stringify(comparison.originalOutcome)} 路 Alternate: ${JSON.stringify(comparison.alternateOutcome)}`; $("#findings").innerHTML = importedFindings.map(f => `<div class="finding"><strong>${esc(f.category || f.rule_id || "finding")}</strong> ${esc(f.severity || "")} 路 evidence: ${esc((f.evidence_refs || []).join(", "))}</div>`).join(""); }
async function loadText(text) { try { const parsed = JSON.parse(text.trim().split("\n").find(Boolean)); trace = parsed.schema_version === "solstice-agent-trace-exchange/v1" ? parsed : parseTrace(parsed); renderTrace(); $("#error").textContent = ""; } catch (error) { $("#error").textContent = error.message; } }
$("#file").addEventListener("change", event => event.target.files[0]?.text().then(loadText));
$("#findings-file").addEventListener("change", event => event.target.files[0]?.text().then(text => { try { importedFindings = JSON.parse(text).findings || JSON.parse(text); if (trace?.schema_version === "solstice-agent-trace-exchange/v1") trace = attachFindings(trace, importedFindings); renderTrace(); } catch (error) { $("#error").textContent = error.message; } }));
$("#branch").addEventListener("change", renderComparison);
$("#download").addEventListener("click", () => { if (trace) downloadJson(trace.schema_version === "solstice-agent-trace-exchange/v1" ? trace : toExchange(trace), `${trace.trace_id || "trace"}-exchange.json`); });
fetch("data/traces.jsonl").then(response => response.text()).then(text => loadText(text)).catch(() => { $("#error").textContent = "Load a local trace JSON file to begin."; });