// — specialist trail. Reactive list of pipeline steps. // // API: // .pushStep(step) — append a {step, ok, elapsed_s, result, err} record // .clear() — reset // .meta = "1.4s" — text shown in the header // .stepLabels = {...} — { stepName: [label, hint] } map (set once at boot) // // Light DOM (no shadow) so the existing `#steps li.ok / .err / .running` // CSS in agent.html keeps applying without rewrites. import { html, css, LitElement } from "https://esm.sh/lit@3"; const escapeHtml = (s) => String(s ?? "").replace(/&/g, "&").replace(//g, ">"); export class Trace extends LitElement { static properties = { steps: { type: Array, state: true }, meta: { type: String, reflect: true }, stepLabels: { type: Object }, }; createRenderRoot() { return this; } constructor() { super(); this.steps = []; this.meta = ""; this.stepLabels = {}; } pushStep(step) { this.steps = [...this.steps, step]; } clear() { this.steps = []; this.meta = ""; } _renderStep(step) { const [label, hint] = this.stepLabels[step.step] || [step.step, ""]; const ok = step.ok === true; const fail = step.ok === false; const cls = ok ? "ok" : fail ? "err" : "running"; const mark = ok ? "✓" : fail ? "✗" : "○"; const time = step.elapsed_s != null ? `${step.elapsed_s}s` : ""; const result = step.result ? `
${escapeHtml(JSON.stringify(step.result))}
` : ""; const err = step.err ? `
${escapeHtml(step.err)}
` : ""; // Inner HTML is hand-built so the existing list CSS targets the same // structure as the legacy renderer; we keep .innerHTML rather than // Lit's html`` for byte-for-byte parity here. const li = document.createElement("li"); li.className = cls; li.innerHTML = ` ${mark}
${escapeHtml(label)}
${escapeHtml(hint)}
${time} ${result} ${err} `; return li; } render() { // Render the
    as innerHTML on update so we don't fight Lit's // template diffing for raw HTML lists. queueMicrotask(() => { const ol = this.querySelector("ol#steps-list"); if (!ol) return; ol.innerHTML = ""; for (const s of this.steps) ol.appendChild(this._renderStep(s)); }); // Inline reset so the legacy `#steps { list-style: none; ... }` rules // (which now target the host element, not the
      ) keep applying. return html`
        `; } } customElements.define("r-trace", Trace);