Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .agents/sessions/harness-ui-overhaul-2026-08/PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# PLAN — Harness UI Overhaul (Full Sweep)

Slug: `harness-ui-overhaul-2026-08`
Snapshot: `399c28986835a71e7ee7b45b6dcaf9bf2b9f8ef85181a443bdcfaeebbe6a137c`
Source: SPEC.md (this session), prior harness inventory (399c… snapshot, 22 subsystems)
Current workspace: `feat/task-memory-evidence-pipeline`, clean worktree.

## Milestones

### M0 — Session bootstrap (done)
- SPEC.md landed. This PLAN.md + STATUS.md land this turn. Gate clears on session artifacts only (no src/ changes this turn).

### M1 — Primitive + Completion summary (P1, vertical slice 1)
Goal: one visual language — no more `✅ 3 files edited | ❌ Hooks: 1 failed` pipe-joined text line.

- [ ] M1-T1 Extract `cli/src/components/renderers/harness-box.tsx` (`HarnessBox`, `HarnessSection`, `HarnessRow`): `borderStyle: single` + `BORDER_CHARS` + `paddingLeft/Right 1 + gap`, theme token prop (`secondary` default, `success/error/warning` for status). Adopt in `PlanBox` + `GateStateBox` (no visual regression).
- [ ] M1-T2 Extend `cli/src/types/chat.ts`: `CompletionSummaryContentBlock { type:'completion-summary', summary: CompletionSummary }` + guard `isCompletionSummaryBlock`. Extend `ContentBlock` union.
- [ ] M1-T3 New renderer `cli/src/components/renderers/completion-summary-box.tsx`: sections Files / Hooks / Review / Tests / Auxiliary / Errors, icon+color mapping (`STATUS_ICON` style: `✓ ✗ ⚠` or reuse emoji but themed), bordered via `HarnessBox`. Empty → null (honor `computeCompletionSummary` null).
- [ ] M1-T4 Wire `cli/src/utils/sdk-event-handlers.ts:handleFinish`: emit typed block instead of `type:'text'` with `formatCompletionSummary(summary)`. Keep `formatCompletionSummary` export for logs/tests.
- [ ] M1-T5 Route in `cli/src/components/blocks/single-block.tsx` (`case 'completion-summary'` → `CompletionSummaryBox`), thread `availableWidth`/`markdownPalette`/`onInsertCommand` as needed (no new props needed, but keep parity with plan/gate).
- [ ] M1-T6 Tests: extend `cli/src/utils/__tests__/completion-summary.test.ts` (data unchanged), add `cli/src/components/__tests__/completion-summary-box.test.tsx` (dark/light, null/empty, mixed verdict), `cli/src/utils/__tests__/sdk-event-handlers.test.ts` for handleFinish block type.
- Validate: `bun --cwd cli run typecheck`, `bun --cwd cli test` (targeted), `tmux-cli` smoke: stream → completion box renders.

### M2 — Memory interactive box (P1, vertical slice 2)
- [ ] M2-T1 Extend `chat.ts`: `MemoryContentBlock { type:'memory', status:'empty'|'status'|'prune-result', revision?, updatedAt?, goal?, counts?, evidence:{live,stale,total}, stalePaths?, hint?, pruneOutcome? }` or reuse raw `TaskMemoryV1` + reconciled evidence; decide in slice kickoff (prefer minimal view-model to keep renderer pure).
- [ ] M2-T2 New renderer `cli/src/components/renderers/memory-box.tsx`: header `revision · age` (`formatAge`), goal preview 120 chars with expand, counts grid, evidence badge (`fresh/stale` colored), collapsible `Stale paths (5)` via `CollapseButton`/`Button`, empty state copy ("written after your first successful run"), error banner for prune failure reasons.
- [ ] M2-T3 Refactor `cli/src/commands/memory-command.ts`: `handleMemoryCommand` returns `{ blocks: ContentBlock[] }` or typed message payload instead of `string`; keep `string` fallback export for `handleMemoryCommand` tests via wrapper. Preserve `WorkspaceJournalService.create → collectWorkspaceMoves` move-rebinding for both status & prune.
- [ ] M2-T4 Wire `cli/src/commands/command-registry.ts` memory handler: `getSystemMessage(string)` → typed memory block insertion (mirror `appendLocalMessage` but block-aware; add `appendLocalBlocks` helper if needed, keep `appendLocalMessage` for other commands until M3).
- [ ] M2-T5 Interactions: `Button` "Prune stale evidence" → `onInsertCommand('/memory prune')`, hover `borderColor theme.foreground`, `DASHED_BORDER` not used (harness = solid).
- [ ] M2-T6 Tests: update `cli/src/commands/__tests__/memory-command.test.ts` (block shape), add `memory-box.test.tsx`, add move-aware prune integration test (rename fixture → stale rebounds, not deleted).
- Validate: `bun --cwd cli test` memory + command-registry, tmux `/memory` → box, `/memory prune` flow.

### M3 — Sweep remaining plain-text reports (P2)
Each command gets minimal typed block + box, reusing `HarnessBox`.

- [ ] M3-T1 `context` (`cli/src/commands/context.ts`): `context` block + `ContextBox` (ledger breakdown, trigger/target budgets).
- [ ] M3-T2 `info` (`cli/src/commands/info.ts`): `info` block + `InfoBox`.
- [ ] M3-T3 `doctor` (`formatOpenbuffProviderStatus` + diagnostics): `doctor` block + `DoctorBox` (split provider status vs diagnostics sections).
- [ ] M3-T4 `index` (`cli/src/commands/index-command.ts`): `index-status` block + `IndexStatusBox`.
- [ ] M3-T5 `plan-status` + `plans` (`formatPlanStatusReport`/`formatPlanListReport`): `plan-status-list` block + `PlanStatusBox` (preserve `STATUS_BADGE` `[active]/[paused]/…`, `progress done/total`, `currentTask`).
- [ ] M3-T6 `help` audit: if it bypasses box system, migrate; otherwise mark out-of-scope with reason in STATUS matrix.
- [ ] M3-T7 Registry wiring: replace `getSystemMessage(string)` calls for each with block helper; keep `appendLocalMessage(string)` deprecated path until all migrated, then remove or keep shim for skills.
- Validate: per-command tests + one combined `command-registry` sweep test; tmux checklist `/context /info /doctor /index /plan-status /plans`.

### M4 — Hardening + docs
- [ ] M4-T1 OpenTUI safety audit: every box wraps markdown/`span` in `<text>`, no `{' '}` whitespace, `minWidth:0` on flex cols, resize 1→2 col not collapsing. Add to `cli/knowledge.md` "HarnessBox" note.
- [ ] M4-T2 Theme parity: `dark` + `light` via `useTheme()`; `messageTextAttributes` preserved.
- [ ] M4-T3 Update `docs/architecture.md` (CLI TUI section) pending-gate box inventory.
- [ ] M4-T4 `LESSONS.md` capture: string→typed-block migration pattern for future harness surfaces.

## Dependencies
M1 primitive extraction before M1-T3/M2-T2/M3 boxes. M1-T2 (chat types) before any box. M2-T3 (memory command contract) before registry wiring. M3 can parallelize T1-T5 after harness-box lands.

## Risks
- `CompletionSummaryBox` icon drift from `formatCompletionSummary` emoji → mitigate: keep string formatter for logs, box uses theme tokens (not emoji parsing).
- `handleFinish` text→block change breaks `sdk-event-handlers.test.ts` snapshots → update snapshots, keep null-path.
- `memory-command` string→blocks breaks existing tests expecting `string` → keep backward-compat wrapper or update test to assert block shape.
- Move-rebinding regression (rename → stale → prune deletes) → explicit test with `WorkspaceJournalService` mock moves.
- OpenTUI reconciler fragility (`<text>` nesting) → reuse `PlanBox`/`GateStateBox` patterns verbatim.

## Validation gates
- `bun --cwd cli run typecheck`
- `bun --cwd cli test` (or `bun test cli/src/utils/__tests__/completion-summary.test.ts cli/src/utils/__tests__/sdk-event-handlers.test.ts cli/src/commands/__tests__/memory-command.test.ts`)
- `tmux-cli` (via `tmux-cli` agent): streaming → completion box, `/memory`, `/memory prune` (move-aware), `/context /info /doctor /index /plan-status /plans` sweep.
- No new `common/` contract beyond `chat.ts` ContentBlock extension; no `sdk/` provider change.

## Out of scope
- `read-edit` / `shell-policy` surfaces (separate sessions).
- `common/src/templates` agent examples.

## Resume pointer
Next concrete step after gate: `M1-T1 + M1-T2` (harness-box + chat types) — single editor slice, no validation bypass.
62 changes: 62 additions & 0 deletions .agents/sessions/harness-ui-overhaul-2026-08/SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# SPEC — Harness UI Overhaul (Full Sweep)

## Goal
Unify the Openbuff harness into one visual language. Every system surface that currently emits a plain `string → getSystemMessage → <text>` must land on the same bordered, themed, OpenTUI-safe renderer system that `PlanBox` / `GateStateBox` / `AgentBranchWrapper` already use. No more split between premium interactive chrome and `console.log`-style dumps for memory or session summaries.

## Non-goals
- No redesign of already-mature surfaces (`PlanBox`, `GateStateBox`, `AgentBranchWrapper`/`AgentBlockGrid`/`ImplementorRow`/`DiffViewer`, `StatusBar`) beyond extracting a shared primitive they adopt.
- No new backend or provider APIs; no agent-runtime prompt contract change (`task_completed` stays empty).
- No global theming overhaul; reuse existing `ChatTheme` + `BORDER_CHARS` tokens.
- No migration of log/debug artifacts outside `cli/src`.

## Requirements

### R1 — Completion summary becomes a first-class box (P1)
- Data source stays `computeCompletionSummary(blocks)` (`cli/src/utils/completion-summary.ts`).
- New typed block `type: 'completion-summary'` + renderer `CompletionSummaryBox` replaces the `formatCompletionSummary()` → `type:'text'` injection in `cli/src/utils/sdk-event-handlers.ts:handleFinish`.
- Sections: Files (edited/failed/unconfirmed/rolled_back/rollback_incomplete), Hooks (passed/failed/skipped), Review verdict (`BLOCKING/NON_BLOCKING/LOOKS_GOOD/…` → `error/warning/success`), Tests, Auxiliary, Errors. Status → border color + icon mapping mirrors `GateStateBox` (success/warning/error).
- `formatCompletionSummary()` retained for logs/fallback; renderer is the TUI source of truth.

### R2 — Memory becomes interactive and on-system (P1)
- Data source stays `sdk/task-memory-store` + `reconcileTaskMemoryEvidence`/`pruneStale…` via `WorkspaceJournalService`.
- New typed block `type: 'memory'` + `MemoryBox` replaces `string` return from `cli/src/commands/memory-command.ts` (`handleMemoryCommand` → `runStatus`/`runPrune`).
- Layout: header `revision · age` (via `formatAge`), goal preview (120 chars, expand affordance if truncated), counts grid (Decisions · Requirements · Edits / Validations · Blockers · Next actions), evidence `fresh/stale` with colored badge, collapsible `Stale paths (5)` list, empty/no-record state that explains when memory is written.
- Prune affordance: clickable `Button` wired to `onInsertCommand('/memory prune')` (same pattern as `PlanBox` command pills), hover border `theme.secondary → theme.foreground`. Prune failure reasons surfaced verbatim (invalid-record / concurrent-write / write-failed) with no phrasing as "nothing to prune".
- Workspace-move rebinding contract preserved: both status and prune pass `WorkspaceMoveRecord[]` from `WorkspaceJournalService.create`.

### R3 — Sweep remaining plain-text reports (P2)
Convert every `getSystemMessage(string)` report in `cli/src/commands/command-registry.ts` and helpers to typed blocks/boxes sharing the same primitive:
- `/context` (`cli/src/commands/context.ts` — ledger breakdown)
- `/info` (`cli/src/commands/info.ts`)
- `/doctor` (`formatOpenbuffProviderStatus` + agent diagnostics)
- `/index` (`cli/src/commands/index-command.ts`)
- `/plan-status` + `/plans` (`formatPlanStatusReport`/`formatPlanListReport` — retain `STATUS_BADGE`/`progress done/total` + `currentTask` semantics)
- `/help` if it still bypasses the box system; otherwise leave its existing structured screen.
Each gets a minimal typed block (e.g. `context`, `info`, `doctor`, `index-status`, `plan-status-list`) and a `*Box` renderer. No one-off inline styles.

### R4 — Shared harness chrome primitive (P2, extracted alongside R1/R2)
- Extract `HarnessBox` (and `HarnessSection`/`HarnessRow` helpers) that codifies the common pattern: `borderStyle:'single' + BORDER_CHARS + theme token + paddingLeft/right 1 + gap`. Adopted by `PlanBox`, `GateStateBox`, `CompletionSummaryBox`, `MemoryBox`, and the sweep boxes. One change propagates.
- Tokens: `DASHED_BORDER_CHARS` / `IMPLEMENTOR_BORDER_CHARS` remain reserved for ghost/implementor contexts; harness uses rounded `BORDER_CHARS`.

### R5 — Wiring and single-point injection
- `sdk-event-handlers.ts:handleFinish` and `command-registry.ts` (`appendLocalMessage` path) are the only UI injection seams. Change is additive (new block types) not string-format surgery.

## Acceptance criteria
- AC1: A completed run with edits+hooks+review renders a bordered `CompletionSummaryBox` (not a `| -joined` text line); empty runs produce no box (`computeCompletionSummary` null path unchanged).
- AC2: `/memory` (no record) shows the two-line "not yet written" empty state inside a box; `/memory` with record shows revision/age/goal/counts/evidence + stale-list affordance; `/memory prune` with stale entries shows the button and correctly rebinds renamed-file evidence (move-aware).
- AC3: `/context` `/info` `/doctor` `/index` `/plan-status` `/plans` each render as bordered boxes with themed headings (no raw `lines.join('\n')` text blocks).
- AC4: `SingleBlock` routes all new block types; `chat.ts`→`MessageBlock`→`BlocksRenderer` threading of `onInsertCommand`/`markdownPalette`/`availableWidth` matches `PlanBox` precedent.
- AC5: OpenTUI-safe: every markdown / `<span>` / `<strong>` fragment is wrapped in `<text>`; no `{' '}` JSX whitespace; no box-inside-text violations; resize (1→2 column) does not collapse `minWidth`.
- AC6: Theme-correct in `dark` and `light` (`useTheme()` tokens, border `success/error/warning/secondary` mapping, `TextAttributes.DIM/BOLD` where appropriate).
- AC7: Backward-compatible: `formatCompletionSummary` and `formatAge`/`pluralizeEntries` remain exported for logs/tests; block types extend the `ContentBlock` union, never retype existing `text`/`tool`/`agent` fields.
- AC8: Tests: `completion-summary.test.ts` (data), new `completion-summary-box.test.tsx`/`memory-box.test.tsx` (render), `command-registry` integration for move-aware prune, plus one `tmux-cli` smoke for streaming→completion and `/memory` flow.

## Relevant systems
- `cli/src/types/chat.ts` — `ContentBlock` union, `GateStateStatus`, `PlanArtifactMetadata`.
- `cli/src/types/theme-system.ts` + `cli/src/utils/ui-constants.ts` + `cli/src/hooks/use-theme.tsx` — `ChatTheme`, `BORDER_CHARS`.
- `cli/src/utils/completion-summary.ts` + `cli/src/utils/sdk-event-handlers.ts` (finish seam) + `cli/src/utils/message-block-helpers.ts`.
- `cli/src/commands/memory-command.ts` + `sdk/src/services/task-memory-store.ts` + `common/src/types/task-memory.ts`.
- `cli/src/commands/command-registry.ts` + `cli/src/commands/context.ts`/`info.ts`/`index-command.ts`/`plan-artifacts.ts`.
- `cli/src/components/renderers/{plan-box,gate-state-box}.tsx` + `cli/src/components/blocks/single-block.tsx` + `cli/src/components/message-block.tsx` + `cli/src/utils/markdown-renderer.tsx`.
- `cli/knowledge.md` — autoCollapse, toggle, suggestion-menu, streaming markdown constraints.
- Validation: `cli` Vitest/Bun + `tmux-cli` / `scripts/tmux/tmux-cli.sh`.
49 changes: 49 additions & 0 deletions .agents/sessions/harness-ui-overhaul-2026-08/STATUS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# STATUS — Harness UI Overhaul (Full Sweep)

Slug: `harness-ui-overhaul-2026-08`
Snapshot: `399c28986835a71e7ee7b45b6dcaf9bf2b9f8ef85181a443bdcfaeebbe6a137c`
Branch: `feat/task-memory-evidence-pipeline` (clean)

## Current state
- **Phase:** Plan complete — SPEC.md + PLAN.md landed and under gate review. Ready for `M1` execution.
- **Mode:** PLAN (no `cli/src` edits this turn; gate is artifacts-only)

## Milestone tracker
- M0 Session bootstrap — done ✅ (SPEC.md, PLAN.md)
- M1 Primitive + Completion summary (P1) — pending
- M1-T1 `harness-box.tsx` + adopt in PlanBox/GateStateBox
- M1-T2 `chat.ts` `completion-summary` block + guard
- M1-T3 `completion-summary-box.tsx`
- M1-T4 `sdk-event-handlers.ts:handleFinish` wired
- M1-T5 `single-block.tsx` routing
- M1-T6 tests + tmux smoke
- M2 Memory interactive box (P1) — pending
- M3 Sweep remaining reports (P2) — pending
- M4 Hardening + docs — pending

## Coverage matrix (plan scope)
| Domain | Shard / File | Covered |
|--------|--------------|---------|
| cli TUI renderers | `cli/src/components/renderers/*` | yes — SPEC R4, M1 |
| cli chat types | `cli/src/types/chat.ts` | yes — R1/R2, M1-T2/M2-T1 |
| cli completion summary | `cli/src/utils/completion-summary.ts` | yes — R1, M1 |
| cli sdk-event-handlers (finish seam) | `cli/src/utils/sdk-event-handlers.ts` | yes — R5, M1-T4 |
| cli memory command | `cli/src/commands/memory-command.ts` | yes — R2, M2 |
| cli command registry + helpers | `cli/src/commands/command-registry.ts` + `context.ts`/`info.ts`/`index-command.ts`/`plan-artifacts.ts` | yes — R3, M3 |
| cli blocks routing | `cli/src/components/blocks/single-block.tsx` | yes — M1-T5/M2 |
| sdk task memory store | `sdk/src/services/task-memory-store.ts` | yes — R2 (data source) |
| common task-memory types | `common/src/types/task-memory.ts` | yes — R2 |
| theme/tokens | `cli/src/types/theme-system.ts` + `ui-constants.ts` + `hooks/use-theme.tsx` | yes — R4 |

Domains explicitly out-of-scope for this plan: `sdk/provider`, `agent-runtime` prompts, `packages/indexer`, `common/templates`.

## Validation gates (next)
- `bun --cwd cli run typecheck`
- `bun --cwd cli test` (completion-summary, sdk-event-handlers, memory-command, command-registry)
- `tmux-cli` smoke: streaming→completion box, `/memory` + `/memory prune` (move-aware), `/context /info /doctor /index /plan-status /plans`

## Resume instructions
1. Read `SPEC.md` + `PLAN.md` in this session dir.
2. Start at `M1-T1 + M1-T2` (harness-box + chat types) — single editor slice.
3. Keep `formatCompletionSummary`/`formatAge` exported for logs/tests (AC7).
4. Preserve move-rebinding: `WorkspaceJournalService.create → collectWorkspaceMoves` in memory status & prune.
Loading
Loading