feat(ui): ralpi-style chat progress and pipeline-overview footer

phases.ts becomes a live chat widget (spinner + tool-call tree) and the
check-runner posts per-agent tool-call summaries and an expandable
completion tree through a custom message renderer; footer.ts adds the
static pipeline-overview status strip for single checks and /pygienium-all.
This commit is contained in:
2026-08-09 16:45:29 -04:00
parent d0e8ad5571
commit 5f8a5cbe5f
10 changed files with 1165 additions and 55 deletions

View File

@@ -355,4 +355,28 @@ describe("/pygienium-all orchestrator (task 12)", () => {
expect(joined).toContain("Beta");
expect(joined).toContain("all [");
});
it("renders only the unified widget in UI mode (no per-check spinner)", async () => {
registerCheck(fakeCheck("alpha"));
registerCheck(fakeCheck("beta"));
const calls: Array<[string, string[] | undefined]> = [];
const ui = {
setWidget: (key: string, content: string[] | undefined) => {
calls.push([key, content]);
},
} as never; // stub ExtensionUIContext (tests have no pi type imports)
await runAllChecks({ cwd, ui, hasUI: true });
const keys = new Set(calls.map(([k]) => k));
// The unified strip drives the widget area…
expect(keys.has("pygienium-all-progress")).toBe(true);
// …and per-check strips never claim it, so no second spinner can
// flicker/swap against the unified one.
expect(keys.has("pygienium-progress")).toBe(false);
// The widget is cleared when the run completes.
const last = calls[calls.length - 1]!;
expect(last[0]).toBe("pygienium-all-progress");
expect(last[1]).toBeUndefined();
});
});