Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
397 changes: 397 additions & 0 deletions AGENT_MONITOR_PLAN.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ notes/burnlists/

`burnlist.md` is the canonical shrinking queue. `goal.md` holds the stable contract, and `completed.md` can hold optional human-readable history. Ready work moves to `inprogress` before execution and to `completed` after the active queue is empty.

An optional top-level `Default Oven: <oven-id>` line selects the first detail
view opened from both the Web dashboard and `burnlist -i`. If it is absent, or
the named Oven is unavailable, both surfaces open Checklist. The setting only
chooses the landing lens; it does not change canonical progress or prevent
switching to another compatible Oven.

An active item is completed and validated before it leaves the checklist. The agent appends a terse completion record, deletes the active item, then validates the updated Burnlist. The lifecycle folder and `burnlist.md` remain the source of truth.

One skill owns Burnlist creation, hardening, execution, and maintenance. The project owns implementation and verification.
Expand Down
2,132 changes: 1,812 additions & 320 deletions console-oven-behavior-policy.json → ...ts/oven/console-oven-behavior-policy.json

Large diffs are not rendered by default.

4,160 changes: 3,348 additions & 812 deletions console-oven-behavior.json → audits/oven/console-oven-behavior.json

Large diffs are not rendered by default.

3,156 changes: 2,065 additions & 1,091 deletions terminal-oven-parity-corpus.json → audits/oven/terminal-oven-parity-corpus.json

Large diffs are not rendered by default.

6,585 changes: 5,961 additions & 624 deletions terminal-oven-parity.json → audits/oven/terminal-oven-parity.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions bin/burnlist.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const knownSubcommands = new Set([
"install",
"uninstall",
"agent-monitor",
"differential-testing",
"streaming-diff",
"hooks",
Expand Down Expand Up @@ -161,6 +162,7 @@ Usage:
burnlist differential-testing validate-bundle <bundle/current.json>
burnlist differential-testing schema
burnlist differential-testing sdk
burnlist agent-monitor <start|stop|status|run|url> ...
burnlist streaming-diff <ensure-feed|capture|url|hook> ...
burnlist hooks [install|uninstall|status] [--agent codex,claude] [--untracked] (bare defaults to status)
burnlist oven <list|view|use|set|bind|unbind|bindings|event|create|update|adopt|upgrade|fork> ...
Expand Down Expand Up @@ -223,6 +225,8 @@ if (args[0] !== "oven" && (args.includes("--version") || args.includes("-v"))) {

if (args[0] === "oven") {
await import("../src/cli/oven-cli.mjs");
} else if (args[0] === "agent-monitor") {
await import("../src/cli/agent-monitor-cli.mjs");
} else if (args[0] === "streaming-diff") {
await import("../src/cli/streaming-diff-cli.mjs");
} else if (args[0] === "hooks") {
Expand Down
13 changes: 7 additions & 6 deletions dashboard/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useMemo, useState } from "react";
import { ListChecks } from "lucide-react";
import { AppHeader, BurnlistTable, ChecklistOvenView, CustomOvenView, DashboardError, DifferentialTestingOvenPage, EmptyState, FILTERS, Filters, LensSwitcher, ModelLabPage, NewOvenPage, OvenCatalog, OvenDefinition, OvenExplainer, PerformanceTracingOvenPage, ProjectGroup, RunBurnPage, StreamingDiff, VisualParityPage } from "@components";
import { AgentMonitor, AppHeader, BurnlistTable, ChecklistOvenView, CustomOvenView, DashboardError, DifferentialTestingOvenPage, EmptyState, FILTERS, Filters, LensSwitcher, ModelLabPage, NewOvenPage, OvenCatalog, OvenDefinition, OvenExplainer, PerformanceTracingOvenPage, ProjectGroup, RunBurnPage, StreamingDiff, VisualParityPage } from "@components";
import { useDashboardData } from "@hooks";
import { checklistOvenRepoKey, currentSection, filterFromUrl, ovenRepoKey, selectedBurnlist } from "@lib";
import { checklistOvenRepoKey, currentSection, customOvenSelection, filterFromUrl, ovenRepoKey, selectedBurnlist } from "@lib";
import type { Filter } from "@lib";
import { Button } from "@layout";

export function App() {
const section = currentSection();
const selected = useMemo(selectedBurnlist, [window.location.pathname, window.location.search]);
const repoKey = ovenRepoKey();
const customOven = section === "custom-oven" ? customOvenSelection() : null;
const [filter, setFilter] = useState(() => filterFromUrl(FILTERS));
const dashboardSection = ["landing", "burnlist", "streaming-diff"].includes(section) || (section === "custom-oven" && selected) ? "burnlists" : section;
const dashboardSection = ["landing", "burnlist", "agent-monitor", "streaming-diff"].includes(section) || (section === "custom-oven" && selected) ? "burnlists" : section;
const { projects, progress, error, loading, stale } = useDashboardData({ section: dashboardSection, selected });
const checklistRepoKey = checklistOvenRepoKey(progress, selected);
const visibleBurnlistCount = projects.reduce((total, project) => total + project.entries.filter((entry) => filter === "all" || entry.status === filter).length, 0);
Expand All @@ -26,13 +27,13 @@ export function App() {
setFilter(nextFilter);
};

const fullLayout = ["differential-testing", "model-lab", "performance-tracing", "streaming-diff", "visual-parity", "custom-oven"].includes(section) || selected;
const fullLayout = ["agent-monitor", "differential-testing", "model-lab", "performance-tracing", "streaming-diff", "visual-parity", "custom-oven"].includes(section) || selected;

return (
<div className="dashboard-app">
<AppHeader detail={progress} section={section} />
<AppHeader detail={progress} ovenId={customOven?.id} section={section} />
<main className="dashboard-main" data-layout={fullLayout ? "full" : "index"} data-section={section}>
{section === "differential-testing" ? <OvenDefinition id="differential-testing" repoKey={repoKey}>{(ir) => <DifferentialTestingOvenPage ir={ir} />}</OvenDefinition> : section === "model-lab" ? <OvenDefinition id="model-lab" repoKey={repoKey}>{(ir) => <ModelLabPage ir={ir} />}</OvenDefinition> : section === "performance-tracing" ? <OvenDefinition id="performance-tracing" repoKey={repoKey}>{(ir) => <PerformanceTracingOvenPage ir={ir} />}</OvenDefinition> : section === "streaming-diff" ? <OvenDefinition id="streaming-diff" repoKey={repoKey}>{(ir) => <StreamingDiff ir={ir} projects={projects} projectsLoading={loading} />}</OvenDefinition> : section === "visual-parity" ? <OvenDefinition id="visual-parity" repoKey={repoKey}>{(ir) => <VisualParityPage ir={ir} />}</OvenDefinition> : section === "custom-oven" ? <CustomOvenView error={error} loading={loading} progress={progress} stale={stale} /> : section === "new-oven" ? <NewOvenPage /> : section === "run-burn" ? <RunBurnPage /> : section === "ovens-catalog" ? <OvenCatalog /> : section === "oven-explainer" ? <OvenExplainer /> : selected ? (
{section === "agent-monitor" ? <OvenDefinition id="agent-monitor" repoKey={repoKey}>{(ir) => <AgentMonitor ir={ir} projects={projects} projectsLoading={loading} />}</OvenDefinition> : section === "differential-testing" ? <OvenDefinition id="differential-testing" repoKey={repoKey}>{(ir) => <DifferentialTestingOvenPage ir={ir} />}</OvenDefinition> : section === "model-lab" ? <OvenDefinition id="model-lab" repoKey={repoKey}>{(ir) => <ModelLabPage ir={ir} />}</OvenDefinition> : section === "performance-tracing" ? <OvenDefinition id="performance-tracing" repoKey={repoKey}>{(ir) => <PerformanceTracingOvenPage ir={ir} />}</OvenDefinition> : section === "streaming-diff" ? <OvenDefinition id="streaming-diff" repoKey={repoKey}>{(ir) => <StreamingDiff ir={ir} projects={projects} projectsLoading={loading} />}</OvenDefinition> : section === "visual-parity" ? <OvenDefinition id="visual-parity" repoKey={repoKey}>{(ir) => <VisualParityPage ir={ir} />}</OvenDefinition> : section === "custom-oven" ? <CustomOvenView error={error} loading={loading} progress={progress} stale={stale} /> : section === "new-oven" ? <NewOvenPage /> : section === "run-burn" ? <RunBurnPage /> : section === "ovens-catalog" ? <OvenCatalog /> : section === "oven-explainer" ? <OvenExplainer /> : selected ? (
loading && !progress ? <EmptyState title="Loading progress" detail="Reading the selected Burnlist." /> : progress ? (
<>{error && <DashboardError message={error} />}<LensSwitcher /><OvenDefinition id="checklist" repoKey={checklistRepoKey}>{(ir) => <ChecklistOvenView data={progress} ir={ir} />}</OvenDefinition></>
) : error ? <DashboardError message={error} /> : <EmptyState title="Choose a Burnlist" detail="Select an item from the list to inspect its progress." icon={ListChecks} />
Expand Down
71 changes: 71 additions & 0 deletions dashboard/src/components/AgentMonitor/AgentMonitor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useEffect, useMemo } from "react";
import { useAgentMonitorActivation, useAgentMonitorFeeds, useAgentMonitorSnapshot, type ResolvedOvenIr } from "@hooks";
import { FeedList } from "@oven";
import {
agentMonitorAutoOpenHref,
agentMonitorRepositories,
agentMonitorSelection,
agentMonitorSnapshotNotice,
ovenRepoKey,
} from "@lib";
import type { Project } from "@lib";
import { OvenRuntime } from "@/oven/runtime/OvenRuntime";
import "./agent-monitor.css";

export function AgentMonitor({
ir,
projects,
projectsLoading,
}: {
ir: ResolvedOvenIr;
projects: Project[];
projectsLoading: boolean;
}) {
const selection = agentMonitorSelection();
const repoKey = ovenRepoKey();
const aggregateSelection = !selection && repoKey
? { repoKey, worktreeKey: repoKey, session: "all" }
: null;
const repositories = useMemo(
() => repoKey ? [{ repoKey, label: repoKey }] : agentMonitorRepositories(projects),
[projects, repoKey],
);
const activation = useAgentMonitorActivation(repositories);
const feeds = useAgentMonitorFeeds(
repositories,
projectsLoading || activation.loading,
Boolean(selection || aggregateSelection),
);
const snapshot = useAgentMonitorSnapshot(selection ?? aggregateSelection, Boolean(aggregateSelection));
const notice = activation.error
? { kind: "error", text: activation.error }
: agentMonitorSnapshotNotice(snapshot);
const autoOpenHref = agentMonitorAutoOpenHref(feeds.feeds);

useEffect(() => {
if (autoOpenHref) window.location.replace(autoOpenHref);
}, [autoOpenHref]);

if (!selection && !aggregateSelection) {
return <FeedList
{...feeds}
description="Recent Codex threads for this repository, identified by exact session id."
emptyText="No recent Codex thread feeds."
loadingText="Loading recent Codex threads."
showRepository={!repoKey && repositories.length > 1}
title="Agent Monitor"
/>;
}

const current = selection ?? aggregateSelection!;
const backHref = `/r/${encodeURIComponent(current.repoKey)}/o/agent-monitor`;
return <section className="agent-monitor-selected">
<header className="agent-monitor-heading">
{selection && <a className="agent-monitor-back" href={backHref}>All recent activity</a>}
<h1>Agent Monitor</h1>
<p>{selection ? `Thread ${selection.session}` : "Latest activity across recent threads"}</p>
</header>
{notice && <p className={`agent-monitor-message${notice.kind === "error" ? " is-error" : ""}`}>{notice.text}</p>}
{snapshot.data && <OvenRuntime ir={ir} payload={snapshot.data} />}
</section>;
}
Loading
Loading