Commit graph

8 commits

Author SHA1 Message Date
Viktor Barzin
394a771b67 [beadboard] Add Dispatch-to-Agent button and prompt template
## Context

We want a one-click path from the right-panel task detail into the
claude-agent-service runner, without the user copy-pasting the bead id
into a CLI or another tab. The runner expects a self-contained prompt
that restates the bead id, title, description, acceptance criteria, and
the guard rails the agent must operate under (no push, no file edits,
no terraform/kubectl/helm). The prompt template lives in `src/lib/` so
it can be tested and reused from the server-side dispatch route.

The right-panel button needs to:
- Only appear when the bead is actionable (`open` or `in_progress`).
- Disable itself while the claude-agent-service is already busy (the
  service has a global `asyncio.Lock` — parallel dispatches 409).
- Disable itself when the bead lacks acceptance criteria. An agent that
  doesn't know what "done" looks like burns budget and closes nothing.
- Surface the resulting `job_id` or any 409/error back to the user.

The project has no toast library (no `sonner`, no `react-hot-toast`), so
we render status inline under the button rather than pulling in a new
dependency for this single surface.

## This change

- `src/lib/dispatch-prompt.ts` exports `buildDispatchPrompt(bead)` which
  produces the exact prompt the agent runner expects. Bead id, priority
  (`P<n>`), issue type, description, and acceptance criteria are
  interpolated; `<job_id>` stays a literal placeholder because the agent
  only learns its own id at runtime (env var).
- `src/components/shared/dispatch-button.tsx` is a focused client
  component with three responsibilities:
    1. Poll `GET /api/agent-status` every 5 s while the panel is open
       (plus an initial fetch on mount), mirror `busy` into local state.
    2. On click, `POST /api/agent-dispatch` with `{taskId}`; branch on
       200 / 409 / other.
    3. Render an inline status line under the button (`text-xs`, tone
       driven by `ok | info | error`) — no toast dep required.
  The poll interval self-clears on unmount so closing the panel stops
  network traffic.
- `src/components/shared/thread-drawer.tsx` renders `<DispatchButton>`
  alongside the existing "Edit task" button in the summary section,
  wrapped in a `flex-wrap` so the two controls reflow on narrow panes.
- Registers two new tests in `package.json`'s enumerated test script.

## What is NOT in this change

- The `/api/agent-dispatch` and `/api/agent-status` routes themselves —
  those land in the next commit. The button calls them but the server
  side is intentionally a separate step so each commit can be reviewed
  in isolation.
- No real toast system is introduced; inline status is sufficient.
- No change to how task state transitions on dispatch. The agent itself
  is expected to run `bd update --claim` / `bd close` via the prompt's
  operating rules.

## Test Plan

### Automated

```
$ node --import tsx --test tests/lib/dispatch-prompt.test.ts \
    tests/components/shared/dispatch-button.test.tsx
# tests 7 pass 7 fail 0
```

Covers:
- Bead id appears in opening paragraph and in both `bd note` / `bd close`
  commands.
- Priority rendered as `P<n>`, issue type echoed.
- Description and acceptance criteria quoted verbatim when present.
- `(no description)` / `(no acceptance criteria)` fallbacks when null.
- Guard rails block present (no terraform/kubectl/helm, workspace bd
  path, `bd update … --status blocked` fallback).
- DispatchButton module loads and exports both named and default.

`npm run typecheck` shows only the pre-existing `OrchestratorChatMessage`
type gap in `left-panel.tsx` that reproduces on untouched `main`.

### Manual Verification

1. `npm install`
2. `npm run dev`
3. Open `http://localhost:3000/?task=<some-open-bead-id>`
4. Expected: "Dispatch to Agent" button next to "Edit task" in the
   right-panel summary section.
5. Button disabled on beads with `status in {closed, blocked, deferred}`
   (they don't render the button at all).
6. Button disabled on beads missing acceptance criteria, with tooltip
   "Task is missing acceptance criteria — cannot dispatch.".
7. Click: UI flips to "Dispatching…"; once the next commit is merged,
   the agent-dispatch route will surface a `job_id` (today it returns
   404 which renders as "Dispatch failed (HTTP 404)").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:04:34 +00:00
Viktor Barzin
845e90d7c0 [beadboard] Add quality filters for acceptance criteria and description length
## Context

The left-panel task list surfaces every bead regardless of whether the task
has been specified thoroughly enough for an agent to pick it up. Tasks with
empty `acceptance_criteria` or very short descriptions are low-signal noise
that muddles the navigation spine — especially now that we plan to dispatch
tasks to Claude agents (which need concrete instructions to succeed).

Epics are deliberately exempt: their role is grouping, not execution, so
requiring acceptance criteria / long descriptions on epics would hide the
entire backbone of the navigation.

## This change

- Plumbs `acceptance_criteria` end-to-end: adds the optional field on
  `BeadIssue`, and reads it both from `.beads/issues.jsonl` (parser) and
  Dolt SQL (`read-issues-dolt.ts` row shape + normalizer).
- Extends `LeftPanelFilters` with `hideNoAcceptance` and
  `hideShortDescription` (both default `true`) in the source-of-truth
  `hooks/use-url-state.ts` and in the re-exported shadow type on
  `components/shared/left-panel.tsx`.
- Updates `isTaskMatch` in both `left-panel.tsx` and `left-panel-new.tsx`
  to skip non-epic tasks lacking acceptance criteria or with a description
  shorter than `SHORT_DESCRIPTION_MIN_LENGTH` (200 chars). Epics bypass
  both filters via the `issue_type === 'epic'` guard.
- Exposes `isTaskMatch` from `left-panel.tsx` so the filter tests can
  assert behavior directly (previously only `shouldHideEpicEntry` was
  exported).
- Adds two checkboxes under the existing "Hide Closed" button in both
  left-panel variants (legacy `left-panel.tsx` and the one unified-shell
  currently wires up — `left-panel-new.tsx`).
- Seeds both new filter flags as `true` in the `UnifiedShell` default
  state so fresh sessions see the high-signal view without toggling.

## What is NOT in this change

- No mutation of `bd` / CLI behavior. Filters are purely UI-level.
- No localStorage persistence for the two new flags — existing
  `hideClosed` is also React-only, so parity is preserved. If/when we
  persist any of these, all three move together.
- No change to the `metadata.acceptance` path used by `kanban.ts`'s
  `hasQualitySignal` — that's a separate signal with its own callers.

## Test Plan

### Automated

Tests run from `/home/wizard/code/beadboard`:

```
$ node --import tsx --test tests/components/shared/left-panel-filtering.test.ts
# tests 15
# pass 15
# fail 0
# duration_ms 604
```

All 15 filter cases pass: 6 pre-existing `shouldHideEpicEntry` cases plus
9 new `isTaskMatch` cases covering acceptance-criteria-empty hides,
acceptance-criteria-disabled shows, epic exemption, 199/200-char
description boundary, null description, and short-description flag
disabled.

Related suites still green:

```
$ node --import tsx --test tests/components/shared/left-panel.test.tsx \
    tests/components/shared/unified-shell-hide-closed-contract.test.ts
# tests 7 pass 7 fail 0
```

Pre-existing failures in `tests/hooks/url-state-integration.test.ts`
(`view=activity` cases) and one pre-existing typecheck error in
`left-panel.tsx` thread prop are unrelated — both reproduce on `main`
before this change.

### Manual Verification

1. `npm install`
2. `npm run dev`
3. Open `http://localhost:3000` with bd project loaded.
4. Expected: two new checkboxes appear under "Hide Closed" in the left
   sidebar — "Hide tasks without acceptance criteria" and
   "Hide tasks with short description (<200 chars)". Both checked by
   default.
5. Toggle each off. Expected: additional beads appear in epic expansions
   (tasks that were previously hidden because they lack quality signal).
6. Confirm epics remain visible regardless of the checkbox state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:00:51 +00:00
ZenchantLive
b5db7a7753 checkpoint: pre-split branch cleanup 2026-03-03 16:43:42 -08:00
zenchantlive
fbfe393f6d chore: checkpoint related UI improvements and supporting components
Various supporting changes made during the assign archetypes feature development:

- Added contextual-right-panel.tsx and swarm-command-feed.tsx
- Updated activity-panel.tsx with new features
- UI improvements to left-panel, mobile-nav
- Test updates for url-state-integration, mobile-nav, top-bar
- Package.json updates for dependencies
- Global CSS refinements

These changes support the main assign archetypes feature but are
not directly part of its core functionality.
2026-02-24 16:25:45 -08:00
zenchantlive
c74a4098e7 refactor: BaseCard hard style shadow, SocialCard blocking lists, AgentAvatar ZFC states 2026-02-16 22:41:56 -08:00
zenchantlive
4efc461c1e feat(ui): add view components for Social, Swarm, and Graph (bb-ui2.11, .16, .20)
STORY:
With the shell layout complete, we needed the actual content for each view.
Three agents worked in parallel on the card components that would populate
the Social and Swarm views, plus integrating the existing graph into the shell.

COLLABORATION:
Agent bb-98c (social-card-builder) created SocialCard:
- Task ID with teal styling
- UNLOCKS section (green) showing what this task unblocks
- BLOCKS section (amber) showing what's blocking this task
- Agent avatars with liveness glow
- View-jump icons for quick navigation

Agent bb-nuy (swarm-card-builder) created SwarmCard:
- Agent roster with liveness indicators
- Progress bar (ASCII block format: ████████░░░░)
- Attention items with warning styling
- View-jump icons

Agent bb-54x (graph-integrator) integrated WorkflowGraph:
- Created GraphView wrapper with Flow/Overview tabs
- Wired into UnifiedShell when view=graph
- Connected taskId to selectedId for URL sync
- Connected graphTab to URL state

DELIVERABLES:
- src/components/social/social-card.tsx: Task card for activity feed
- src/components/swarm/swarm-card.tsx: Swarm health card
- src/components/graph/graph-view.tsx: Graph wrapper with tabs
- src/components/shared/mobile-nav.tsx: Bottom tab bar
- Tests for all components

VERIFICATION:
- npm run typecheck: PASS
- npm run lint: PASS
- npm run test: PASS

CLOSES: bb-ui2.11, bb-ui2.16, bb-ui2.20
2026-02-15 23:21:20 -08:00
zenchantlive
ce8fdd0d4c feat(ui): complete shell layout components (bb-ui2.6, .7, .8, .9, .27)
STORY:
Phase 1 of the Unified UX epic required a complete 3-panel shell layout
with responsive behavior across mobile, tablet, and desktop breakpoints.
The existing page structure was fragmented - we needed a cohesive shell.

COLLABORATION:
Three agents (bb-5am, bb-dwz, bb-3dv) worked in parallel on:
- TopBar: View tabs (Social/Graph/Swarm) with active states, filter input
- LeftPanel: Channel tree navigation with epic filtering, responsive collapse
- RightPanel: Detail strip with sidebar (desktop) / drawer (tablet/mobile) modes

We encountered a hydration mismatch error on mobile/tablet because
useResponsive was returning different values on server vs client.
Fixed by defaulting to desktop on server and only updating after mount.

Mobile navigation (bb-ui2.27) added:
- Hamburger menu for left panel access on mobile/tablet
- Bottom tab bar for thumb-friendly view switching

DELIVERABLES:
- src/components/shared/top-bar.tsx: TopBar with view tabs + hamburger
- src/components/shared/left-panel.tsx: Epic tree with expand/collapse
- src/components/shared/right-panel.tsx: Responsive sidebar/drawer
- src/components/shared/unified-shell.tsx: Main 3-panel grid layout
- src/components/shared/mobile-nav.tsx: Bottom tab bar for mobile
- src/hooks/use-responsive.ts: Breakpoint detection (mobile/tablet/desktop)
- Tests for all components

VERIFICATION:
- npm run typecheck: PASS
- npm run lint: PASS
- npm run test: PASS

CLOSES: bb-ui2.6, bb-ui2.7, bb-ui2.8, bb-ui2.9, bb-ui2.27
2026-02-15 23:19:52 -08:00
zenchantlive
0d73d2afaf feat(sessions): complete bb-buff.3.2 - Critical Visual Signals
STORY:
The Sessions Hub needed clear visual distinction between healthy
agents and those in trouble. Users couldn't quickly identify stuck
or dead agents in the control center view.

COLLABORATION:
We added 'stuck' and 'dead' states to the AgentSessionState type,
created deriveSessionState() with Zero-Failure-Check priority,
and implemented restrained visual treatments:
- stuck: pulsing red border (ring-2 ring-red-500 animate-pulse)
- dead: strong ghosting (opacity-40 grayscale)
- evicted: milder ghosting (opacity-60 grayscale-[0.5])

Session cards now display STUCK/OFFLINE badges with aria-labels
for accessibility.

DELIVERABLES:
- AgentSessionState extended with stuck/dead states
- deriveSessionState() derives from ZFC state priority
- Visual treatments for stuck/dead/evicted
- Accessible badges with aria-label

TESTS:
- tests/lib/agent-sessions-state.test.ts: 6/6 PASS
- tests/components/shared/status-utils-visual.test.ts: 4/4 PASS
- tests/components/sessions/session-feed-card-state.test.tsx: 4/4 PASS

CLOSES: bb-buff.3.2
BLOCKS: bb-buff.3.3
2026-02-15 21:15:28 -08:00