Skip to content

feat(ui): interactive-agent surfacing — History section + workspace card 'PA active' chip#51

Merged
fstamatelopoulos merged 3 commits into
mainfrom
iteration-7/history-interactive-section
May 19, 2026
Merged

feat(ui): interactive-agent surfacing — History section + workspace card 'PA active' chip#51
fstamatelopoulos merged 3 commits into
mainfrom
iteration-7/history-interactive-section

Conversation

@fstamatelopoulos
Copy link
Copy Markdown
Owner

@fstamatelopoulos fstamatelopoulos commented May 19, 2026

Summary

Two complementary UI improvements for surfacing interactive agents (PA today, HA when it grows history), bundled because they address the same underlying gap: F.22 (v0.24.0) tracks loop / review / document / reflect activity but not PA — PA runs outside the cfcf server entirely and isn't in the active-processes registry. This PR closes that gap on two surfaces.

Part 1 — History tab: separate section for interactive agents

Dogfood feedback from the gmbot run: PA sessions can stay alive for hours or days. In a single chronological History list, an active long-running PA row gets pushed deep as iteration events accumulate above it.

Fix: partition the History tab into two sections.

  • Interactive agents (top) — every PA + HA event (today only pa-session), newest-first within the section. Active sessions naturally appear at the top because they're the newest. Header: Interactive agents (N).
  • Loop history (bottom) — iteration / review / document / reflection / loop-stopped events, newest-first. Unchanged from today, just gets a Loop history (N) header when the interactive section is present.

Critical UX rule: every event has ONE permanent home. A PA row stays in the Interactive section regardless of status — no disappearing on completion. Status badge differentiates running/completed/failed within the section. (This was the load-bearing correction in design review: "active-only" would have hidden terminated history.)

When there are zero interactive events, no top section + no header on the bottom — looks exactly like today.

Part 2 — Workspace card + Status tab: "PA active" chip

Same problem on a different surface: F.22's active-agent chip on the workspace card / Status tab doesn't cover PA. This adds a parallel chip — "● PA active" — alongside the F.22 chip.

Liveness check: per-call process.kill(launcherPid, 0) against the PID recorded on the most-recent pa-session event with status === \"running\". Same primitive F.28's boot-reconcile uses, but called on every /api/workspaces poll instead of only at server boot.

Side benefit: PA sessions that terminate uncleanly (shell killed, terminal closed) get the chip cleared in real time — no more waiting for the next server boot's reconcile pass.

Why a separate chip, not a new activeAgent enum value: F.22's activeAgent is mutually exclusive. PA can run concurrently with the loop / standalone runs. Two chips can coexist; different accent color makes them visually separable.

Test plan

  • bun run test — 1071 tests pass (+22 new across both parts)
  • bun run typecheck — clean
  • Part 1 — 10 new tests in history-partition.test.ts: partition splits correctly; both arrays newest-first; active PA stays at top regardless of startedAt; terminated events stay in their section (status does NOT change partition); handles all loop event types; empty input; partition is total; does not mutate input
  • Part 2 — 12 new tests in pa-liveness.test.ts: null cases (missing history, no pa-session, no running event, no launcherPid, dead PID); positive case (live PID); ordering (newest-running wins); falls through stale newer to surface older live; batch shape; empty input; isPidAlive primitive
  • Manual smoke (post-merge): on a workspace with PA history + loop history, verify two History-tab sections with correct counts; an active PA appears at top of section A; dashboard card shows ● PA active chip alongside any loop chip; Status tab header shows PA active tag; chip clears immediately when PA terminates

Versioning

Target: v0.24.5 patch. Pure UX improvement, no behaviour / API contract change beyond the additive paSession field on /api/workspaces. Same shape as v0.24.4.

Files

Part 1:

  • packages/web/src/utils/history-partition.ts (new) + .test.ts
  • packages/web/src/components/WorkspaceHistory.tsx

Part 2:

  • packages/core/src/product-architect/pa-liveness.ts (new) + .test.ts
  • packages/core/src/product-architect/index.ts (export)
  • packages/server/src/app.ts (/api/workspaces enrichment)
  • packages/web/src/types.ts (mirror)
  • packages/web/src/components/WorkspaceCard.tsx (chip)
  • packages/web/src/pages/WorkspaceDetail.tsx (header tag)

Multiple-PA edge case

If a user accidentally runs multiple PAs against the same workspace, all of them appear in History section A. The chip surfaces the newest live one. No warning today — deferred until real users hit it.

🤖 Generated with Claude Code

fstamatelopoulos and others added 2 commits May 18, 2026 17:42
Dogfood feedback from gmbot: PA sessions can stay alive for hours
or days. In a single chronological History list, an active
long-running PA's row gets pushed deep as iteration events
accumulate above it. Scanning for "is PA still running?" forced
scrolling.

Fix: partition the History tab into two sections — "Interactive
agents" (PA + HA events, today only pa-session) at the top, and
the existing "Loop history" below. Both sorted newest-first
within their section.

Critical UX rule: every event has ONE permanent home. A PA's row
stays in the Interactive section regardless of status — no
disappearing on completion, no relocating to chronological slot
in the Loop section. Status badge handles running-vs-completed
within the section. The "active-only" framing would have hidden
terminated history; partition by event-type only preserves it.

When there are zero interactive events, no top section + no
header — the table looks exactly like today. The new structure
only appears when it's needed.

Complements F.22 (v0.24.0): F.22's chip surfaces loop-spawned
active agents on the dashboard card + Status tab; this PR
surfaces interactive agents in the History tab. Together they
close the "what's running RIGHT NOW" question for both classes.

Implementation: new pure helper
`partitionInteractiveEvents(events)` in
packages/web/src/utils/history-partition.ts (returns
{interactive, loop}). WorkspaceHistory.tsx renders two
<section> blocks with count-bearing headers when interactive
events exist.

INTERACTIVE_EVENT_TYPES is a Set — when HA grows a history-event
type, add it; no other changes needed.

Test coverage: 10 new tests covering partition correctness,
sorting, status-independence, empty input, totality, immutability
of input. All 1059 tests pass. Typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Natural extension of the History tab partition (same PR): F.22's
active-agent chip on the workspace card shows loop / review /
document / reflect activity but doesn't surface PA. PA runs
outside the cfcf server (interactive cfcf spec) and is tracked
separately. This adds a parallel chip — "● PA active" — that
appears alongside the F.22 chip when a PA session is alive.

Why separate chip vs new activeAgent enum value: F.22's
activeAgent is mutually exclusive. PA can run concurrently with
loop / standalone runs. Two chips can coexist; different accent
color makes them visually separable.

Liveness check: per-call process.kill(launcherPid, 0) against
the PID in the most-recent pa-session event with status=running.
Same primitive F.28's boot-reconcile uses, just called on every
/api/workspaces poll. Side benefit: PA sessions that terminate
uncleanly (shell killed) get the chip cleared in real time
instead of waiting for next server boot.

Status tab chip: matching "PA active" tag in the workspace detail
header, derived from history (same trust level as the History tab).

Pre-v0.24 events without launcherPid are skipped — no precise
verification possible, stale chip worse than no chip.
Boot-reconcile's mtime fallback handles them at next boot.

Implementation:
- packages/core/src/product-architect/pa-liveness.ts (new):
  getPaSessionLiveness, getPaSessionsForWorkspaces, isPidAlive
- packages/server/src/app.ts: /api/workspaces enriched with
  paSession in parallel with activeAgent
- packages/web/src/types.ts: mirror paSession field
- packages/web/src/components/WorkspaceCard.tsx: PA active chip
- packages/web/src/pages/WorkspaceDetail.tsx: PA active header tag

Test coverage: 12 new tests covering null cases (missing history,
no pa-session, no running event, no launcherPid, dead PID),
positive case (live PID), ordering (newest-running wins), fall
through stale to older live, batch shape, empty input, primitive
correctness. All 1071 tests pass. Typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fstamatelopoulos fstamatelopoulos changed the title feat(history): separate section for interactive agents (PA/HA) feat(ui): interactive-agent surfacing — History section + workspace card 'PA active' chip May 19, 2026
… visually distinct

Dogfood feedback after PR #51 first pass:
- "Interactive agents" → "Interactive sessions" (more accurate;
  each PA invocation IS a session, and the row content shows
  sessions, not agents-as-entities)
- Sections previously looked visually similar; user wanted them
  optically distinct + collapsible

Changes (display-only, no logic):
- <section>+<h3> → <details open>+<summary>: native HTML
  collapsible (no React state). Disclosure triangle affordance,
  click-to-collapse, default open. Browser handles persistence
  across rerenders.
- Each section gets a 3px left-border accent: interactive section
  uses var(--color-accent) (purple-ish), loop section uses
  var(--color-border) (subtle gray). Distinct at a glance.
- Summary has a light background tint + radius to read as a
  header-like band rather than plain text.
- Extracted LoopHistoryTable subcomponent so the loop section
  can render either inside a <details> (paired with interactive)
  or as a plain bare table (when no interactive events exist).
  The no-interactive-events case looks EXACTLY like today.

No test changes — pure presentation tweaks. Existing partition
tests still pass (10/10).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fstamatelopoulos fstamatelopoulos merged commit 1e93fc1 into main May 19, 2026
3 checks passed
fstamatelopoulos added a commit that referenced this pull request May 19, 2026
…polish

Bumps version 0.24.4 -> 0.24.5 and consolidates [Unreleased] into a
[0.24.5] release entry. Shipped via PR #51 + PR #52.

Net-new since v0.24.4:
- PR #51: History tab partition (Interactive sessions + Loop
  history sections) + workspace card "PA active" chip + Status
  tab tag; server-side PA PID liveness check
- PR #52: ready/iterating status semantics (cfcf review flips
  terminal status to idle) + 4 dashboard polish items (history
  active counts, in-page iteration max, card timer, card layout)

Test coverage: 1079 tests pass (+22 new). Typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@fstamatelopoulos fstamatelopoulos deleted the iteration-7/history-interactive-section branch May 19, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant