feat: initial commit

This commit is contained in:
Jeffrey Wu
2026-09-07 09:57:33 +08:00
commit f39f6ac881
66 changed files with 9859 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
import { useEffect, useRef, useState } from "react";
import { useHarnessState } from "../assistant/HarnessContext";
import type { HarnessEvent } from "@agent-studio/shared";
type Filter = "all" | "run" | "skill" | "tool" | "approval" | "model";
export function TimelinePanel() {
const { events } = useHarnessState(); const [filter, setFilter] = useState<Filter>("all"); const viewport = useRef<HTMLDivElement>(null); const atBottom = useRef(true);
const visible = events.filter((event) => filter === "all" || event.type.startsWith(`${filter}.`) || (filter === "tool" && event.type.startsWith("attachment.")));
useEffect(() => { if (atBottom.current) viewport.current?.scrollTo({ top: viewport.current.scrollHeight }); }, [visible.length]);
return <aside className="side-panel timeline-panel" aria-label="Event Timeline"><div className="panel-heading"><span className="eyebrow">HARNESS FACTS</span><h2>Event Timeline</h2><p>Pi Skill Session sequence </p></div><div className="filters" role="group" aria-label="事件筛选">{(["all", "run", "skill", "tool", "approval", "model"] as Filter[]).map((item) => <button key={item} className={filter === item ? "selected" : ""} onClick={() => setFilter(item)}>{item}</button>)}</div><div className="timeline" ref={viewport} onScroll={(event) => { const node = event.currentTarget; atBottom.current = node.scrollHeight - node.scrollTop - node.clientHeight < 48; }}>{visible.length === 0 && <div className="panel-state"> Harness </div>}{visible.map((event) => <EventRow key={event.eventId} event={event}/>)}</div></aside>;
}
function EventRow({ event }: { event: HarnessEvent }) { const [open, setOpen] = useState(false); return <article className={`event-row ${event.type.startsWith("approval.") ? "risk" : ""}`}><button onClick={() => setOpen(!open)} aria-expanded={open}><span className="sequence">#{event.sequence}</span><span><strong>{event.type}</strong><small>{new Date(event.timestamp).toLocaleTimeString()}</small></span></button>{open && <pre>{JSON.stringify(event.payload, null, 2)}</pre>}</article>; }