Commit graph

39 commits

Author SHA1 Message Date
Viktor Barzin
a7b4f7ba32 [beadboard] Add agent-dispatch and agent-status API routes
## Context

The Dispatch-to-Agent button in the right-panel (previous commit) calls
two endpoints that did not yet exist server-side:

- `POST /api/agent-dispatch` — resolve the bead via the same Dolt pool
  the existing `/api/beads/read` route uses, build a prompt from it, and
  forward to `claude-agent-service`'s `/execute` endpoint with a bearer
  token. This is the server-side trust boundary: the bearer token lives
  in env (never in the browser), and the bead is re-read from Dolt
  (never trusted from the client payload) so a malicious client cannot
  inject a prompt.

- `GET /api/agent-status` — proxy `claude-agent-service`'s `/health`
  endpoint (which already returns `{status, busy}`), with a 2 s in-
  memory cache so 5 s UI polls across multiple open tabs don't hammer
  the service.

The claude-agent-service serialises jobs behind an `asyncio.Lock` — a
second `/execute` while one is running returns HTTP 409 "Agent is busy".
We surface that 409 through to the browser unchanged so the UI can show
the right toast/status line without re-mapping status codes.

```
client ──► /api/agent-dispatch ──► claude-agent-service /execute
             │                        (asyncio.Lock guards)
             └─► reads bead from Dolt pool (same path as /api/beads/read)
             └─► buildDispatchPrompt(bead)
             └─► POST {prompt, agent, budget, timeout} + Bearer token

client ──► /api/agent-status (2s cache) ──► /health  ──► {busy: bool}
```

## This change

### `src/app/api/agent-dispatch/route.ts`

- `POST {taskId: string}` handler.
- Validates JSON body and non-empty taskId (→ 400).
- Early 500 if `CLAUDE_AGENT_SERVICE_URL` or `CLAUDE_AGENT_BEARER_TOKEN`
  is missing — fail fast, fail loud.
- Resolves the bead via `readIssuesFromDisk({preferBd: true})`, which
  uses the existing Dolt client (and falls back to `issues.jsonl`).
  Filtering by id after is acceptable at BeadBoard's scale (~hundreds
  of beads) and avoids introducing a new single-bead query path.
- 400 when the bead is missing, or when `acceptance_criteria?.trim()` is
  empty — defense in depth alongside the UI disable. The button should
  already hide in these cases, but a curl'd POST must still be rejected.
- Forwards to `${CLAUDE_AGENT_SERVICE_URL}/execute` with agent
  `beads-task-runner`, max_budget_usd 5, timeout_seconds 900 (matches
  the values in the task spec).
- Passes through 409 verbatim. Other upstream errors collapse to 502.

### `src/app/api/agent-status/route.ts`

- `GET` handler, module-level snapshot cache with 2 s TTL to avoid
  hammering `/health`.
- In-flight de-dup: a single pending `fetchRemoteStatus()` is shared
  across concurrent requests so we only hit the upstream once per
  window even under bursty load.
- When `CLAUDE_AGENT_SERVICE_URL` is unset, returns `{busy: false}` and
  skips the fetch entirely — this is how the dev server boots before
  the service env is configured.
- HTTP 503 from upstream is interpreted as `busy: true` (future-proofing
  in case the service swaps 409 for 503 on overload).
- Any network error degrades gracefully to `{busy: false}` — the 409
  path on `/api/agent-dispatch` is the authoritative gate.

### Test coverage

- `tests/api/agent-dispatch-route.test.ts` (3 cases): invalid JSON body,
  missing taskId, missing env returns 500.
- `tests/api/agent-status-route.test.ts` (3 cases): unset service URL
  returns `{busy: false}` without a fetch, `/health busy:true` proxies
  through, HTTP 503 maps to busy=true. Uses a `globalThis.fetch` stub
  and cache-busting query params on dynamic import so each case starts
  from a fresh module snapshot.

## What is NOT in this change

- End-to-end happy-path coverage (bead loads, fetch returns 200, route
  yields job_id) would require mocking `readIssuesFromDisk` — that's a
  bigger refactor than this commit warrants. Live integration happens
  once the pipeline is wired.
- No retry/backoff on upstream failures. 502 passes through; the client
  decides whether to retry.
- No auth on the routes themselves — they inherit the Next.js app's
  session model (same as all other `/api/*` routes today).

## Test Plan

### Automated

```
$ node --import tsx --test tests/api/agent-dispatch-route.test.ts \
    tests/api/agent-status-route.test.ts
# tests 6 pass 6 fail 0 duration_ms 1560
```

All six route cases pass. Typecheck output shows only the pre-existing
`OrchestratorChatMessage` gap in `left-panel.tsx`. Lint output is
unchanged from `main` (1 pre-existing `no-require-imports` error in
`src/lib/bb-pi-bootstrap.ts`).

### Manual Verification

1. Export env:
   ```
   export CLAUDE_AGENT_SERVICE_URL=http://claude-agent-service.claude-agent.svc.cluster.local:8080
   export CLAUDE_AGENT_BEARER_TOKEN=$(vault kv get -field=api_bearer_token secret/claude-agent-service)
   ```
2. `npm run dev`
3. `curl -s http://localhost:3000/api/agent-status` → `{"busy":false}`
   (if the service is reachable; `{"busy":true}` if a job is running).
4. `curl -X POST http://localhost:3000/api/agent-dispatch \
       -H 'content-type: application/json' \
       -d '{"taskId":"beadboard-xyz"}'`
   - 400 if bead does not exist or lacks acceptance criteria.
   - 200 `{"job_id":"..."}` on success.
   - 409 `{"error":"Agent is busy"}` when an agent is already running.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:07:21 +00:00
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
zenchantlive
d335e5bf71 fix: orchestrator button + Pi SDK session error
- Move leftSidebarMode from URL state to local useState in unified-shell,
    avoiding force-dynamic router round-trip that made the button appear broken                                           - Replace fileURLToPath(new URL(..., import.meta.url)) with process.cwd()
    in bb-pi-bootstrap.ts — import.meta.url is a webpack:// URL in Next.js,
    causing cross-realm TypeError when passed to Node.js fileURLToPath()
2026-03-24 19:02:04 -05:00
zenchantlive
1c4b5ab401 Cleanup: Runtime artifacts, hard-coded paths, PR 14 bug fixes 2026-03-05 15:57:33 -08:00
ZenchantLive
003aba3179 test(skill): add bb mail lifecycle and preflight coverage 2026-03-03 19:23:53 -08:00
ZenchantLive
e16ddcb532 test(coord): expand registry/api/reservation coverage 2026-03-03 18:48:13 -08:00
ZenchantLive
e72a99e629 feat(cli): make --help human-readable by default 2026-03-02 21:27:18 -08:00
ZenchantLive
b61f27aaf3 feat(cli): expand non-json status diagnostics output 2026-03-02 21:23:21 -08:00
ZenchantLive
34c2b7f4eb feat(cli): route runtime commands and add bd diagnostics to status 2026-03-02 21:19:12 -08:00
ZenchantLive
4a98ab2976 feat(cli): add global entrypoint with doctor/update/uninstall commands 2026-03-02 20:44:07 -08:00
ZenchantLive
7945ee8d3c feat(installer): migrate shims to runtime-managed targets 2026-03-02 20:42:35 -08:00
ZenchantLive
205f9500ec feat(launcher): add runtime-aware status metadata 2026-03-02 20:40:26 -08:00
ZenchantLive
0f33a653d3 feat(installer): add runtime manager core library 2026-03-02 20:36:09 -08:00
zenchantlive
29eefaf7ec feat: add BlockedTriageModal component with tests
- Create BlockedTriageModal component at src/components/shared/blocked-triage-modal.tsx
- Implements modal with blocked task triage functionality
- Uses deriveBlockedIds and buildBlockedByTree from kanban lib
- Each row shows blocker chain and has inline archetype picker
- Modal is scrollable and closes via Escape/close button
- Add corresponding tests at tests/components/blocked-triage-modal.test.tsx
- Register test in package.json test script
2026-03-01 21:12:46 -08:00
ZenchantLive
861ae89491 fix: wire conversation panel to DAG nodes with toggle support
- Add MessageSquare icon to GraphNodeCard; prop-thread onConversationOpen
  and selectedTaskId through WorkflowGraph node data (no useUrlState
  inside ReactFlow nodes — avoids context/timing issues)
- Fix ContextualRightPanel: check taskId before epicId so clicking the
  conversation icon always opens ThreadDrawer even when an epic filter
  is active
- setEpicId now clears task from URL so selecting an epic resets any
  open conversation thread
- handleGraphSelect toggles: second click on same node calls setTaskId(null)
  closing the right panel
- Add onSelect to WorkflowGraph flowModel deps to prevent stale callbacks
- Fix ContextualRightPanel onClose no-ops: wired to setTaskId(null) /
  setSwarmId(null) so back button works
- Right panel always visible (removed panel==='open' gate in UnifiedShell)
- SmartDag task grid: horizontal scroll, fixed-width cards, hideClosed=true
- Add <Suspense> in page.tsx for useSearchParams compatibility
- Enable dolt auto-start in .beads/config.yaml
- Add 14 static analysis tests (graph-node-conversation.test.tsx)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 13:51:46 -08:00
ZenchantLive
bb1231860e chore: update next session prompt + install mysql2 for beadboard-550
- NEXT_SESSION_PROMPT.md: full context for Dolt mysql2 integration
  including schema, current read path, normalization approach, watcher
  concern, skills to use, and files to read
- mysql2 installed (beadboard-550.1 in_progress)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 17:08:38 -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
dfaf523029 feat(swarm): implement Swarm View remake with Operations, Archetypes, and Templates
This commit includes the new SwarmWorkspace with its 3 sub-tabs, the LeftPanel mission picker, and the comprehensive Operations Command Dashboard featuring the live interactive DAG telemetry and task assignment prep flow.
2026-02-20 22:19:38 -08:00
zenchantlive
c74a4098e7 refactor: BaseCard hard style shadow, SocialCard blocking lists, AgentAvatar ZFC states 2026-02-16 22:41:56 -08:00
zenchantlive
54729c72f6 initial commit for beadboard 2026-02-16 21:45:27 -08:00
zenchantlive
f6c5398f0c fix(bb-ui2): integrate ThreadView into detail panels with sample data
- Wired ThreadView component into SocialDetail and SwarmDetail
- Added sample thread items for demo purposes
- Removed thread placeholders

Beads: bb-ui2.13 closed
2026-02-16 10:10:50 -08:00
zenchantlive
8dd2d01686 feat(bb-ui2): Social and Swarm views with detail panels integrated 2026-02-16 00:26:31 -08:00
zenchantlive
a2b0909724 fix: recover from mass file corruption incident (2026-02-15)
INCIDENT SUMMARY:
A catastrophic corruption event affected the working directory, with null
bytes (0x00) overwriting content in dozens of files including:
- package.json (corrupted)
- tailwind.config.ts (corrupted)
- All modified tracked files
- Untracked directories (components/ui/, node_modules/, .next/)

ROOT CAUSE:
Unknown - files were filled with null bytes, destroying their content.

RECOVERY PROCESS:
1. Discovered corruption when npm run dev failed with EJSONPARSE
2. Checked git diff --stat - showed many files as "binary"
3. Found dangling stash commits (0d80ad9, a1a33cf) containing our work
4. Restored tracked files from stash: git checkout a1a33cf -- .
5. Removed corrupted untracked directories (node_modules, .next, components/ui)
6. Reinstalled dependencies: npm install
7. Reinitialized shadcn/ui: npx shadcn@latest init
8. Reinstalled shadcn components: npx shadcn@latest add button card ...
9. Recreated earthy-dark tokens (bb-ui2.1) - lost in shadcn init overwrite
10. Verified all closed bb-ui2 beads still had their deliverables

DATA PRESERVED:
- All tracked source code (recovered from git stash)
- .beads/issues.jsonl (recovered from stash)
- All bead history and metadata

DATA LOST:
- Uncommitted changes to untracked files
- Earthy-dark tokens (recreated from bead spec)
- components/ui/ (regenerated from shadcn)

LESSONS LEARNED:
1. Commit work frequently - untracked changes are not protected
2. Git stash captures tracked files only
3. shadcn init overwrites globals.css - preserve tokens separately
4. Dangling commits can save the day

VERIFICATION POST-RECOVERY:
- npm run typecheck: PASS
- npm run lint: PASS
- npm run test: PASS
- All bb-ui2 closed bead deliverables present

CLOSES: bb-silver-castle (triage bead for this incident)
2026-02-15 21:19:58 -08:00
zenchantlive
4ee550c333 feat(telemetry): complete bb-buff.1.3 - Backend Liveness Refactor
STORY:
The session backend needed to aggregate agent health from a live
telemetry stream rather than static bead metadata. This refactor
makes liveness signals real-time and accurate.

COLLABORATION:
We extended the ActivityEvent model with a native 'heartbeat' kind,
updated extendActivityLease() to emit through the activity bus, and
refactored getAgentLivenessMap() to prioritize heartbeat activity
history over stale bead metadata.

DELIVERABLES:
- ActivityEvent extended with 'heartbeat' kind
- extendActivityLease() emits heartbeats through activity bus
- getAgentLivenessMap() prefers telemetry over static metadata
- Registry APIs support projectRoot injection for testing
- Tests verify preference logic via TDD

VERIFICATION:
- 93/93 tests PASSING
- Heartbeat override verified in isolated temp projects

CLOSES: bb-buff.1.3
BLOCKS: bb-buff.3.2, bb-buff.3.3, bb-buff.2.1
2026-02-15 21:14:05 -08:00
zenchantlive
c7c3a25457 docs(beads): etch project history into memory bank and finalize skill-bb
We completed the 'Deep Metadata Etch' today, transforming our Beads issues from simple trackers into a permanent narrative of our collaboration.

Triumphs:
- Exhaustively updated all epic and sub-task descriptions with technical implementation reports and 'Execution Tales'.
- Finalized the 'bb' agent CLI skill (bb.ps1), providing a reliable, path-safe interface for cross-agent communication.
- Published ADR-001 and RFC-001 to document our coordination protocols.
- Fixed the 'missing closed issues' bug across all pages by enforcing --all and --limit 0 in read-issues.ts.

Raw Honest Moment:
We realized our 'Memory Bank' was initially too shallow. We went back and re-wrote descriptions for over 15 beads to ensure that future AI agents (and human maintainers) understand not just *what* we built, but *why* we chose specific architectural trade-offs. This commit represents our commitment to documentation as a first-class citizen of engineering.
2026-02-14 00:21:25 -08:00
zenchantlive
2cfaa9b406 chore: migrate lint to eslint flat config and finalize graph card status handling 2026-02-13 12:27:09 -08:00
zenchantlive
e1f3d48f6e feat(ui): Enhance Graph and Kanban UX (bb-18e)
- feat(kanban): Add progressive disclosure to task details drawer
- feat(kanban): Fix title layout on mobile (remove flex-row constraint)
- feat(kanban): Add bead count and metadata to epics
- style(globals): Add status color tokens and refined scrollbars
- deps: Add dagre for true DAG layout in graph view
- chore: Update capture scripts
2026-02-12 23:37:27 -08:00
zenchantlive
b4cb09a6cc Merge main into master and unify realtime + project-context test matrix 2026-02-11 21:06:38 -08:00
zenchantlive
3f2ae384f5 Add realtime watcher+SSE transport with tests and lock-retry read path 2026-02-11 21:05:27 -08:00
zenchantlive
89a9941d88 Merge bb-6aj-3-scanner 2026-02-11 21:00:28 -08:00
zenchantlive
50d3833766 feat: add project scanner with full-drive mode 2026-02-11 20:41:39 -08:00
zenchantlive
c836be46cf feat: add Windows project registry API and persistence 2026-02-11 20:35:36 -08:00
zenchantlive
cc616c1543 Add optimistic writeback flow with kanban drag-drop transitions 2026-02-11 19:59:55 -08:00
zenchantlive
2c80265258 Add bd exec bridge and mutation API routes with tests 2026-02-11 19:46:02 -08:00
zenchantlive
0b127b5404 feat: add project context model 2026-02-11 19:44:47 -08:00
zenchantlive
75cc86e259 feat: harden kanban responsiveness and visual system 2026-02-11 19:01:34 -08:00
zenchantlive
ce2010fd92 feat: establish tokenized kanban design foundation 2026-02-11 18:38:51 -08:00
zenchantlive
c09420dc68 Add tracer-bullet Kanban baseline with live issues read path 2026-02-11 17:55:26 -08:00
zenchantlive
292a72f861 chore: initialize beadboard baseline 2026-02-11 17:42:51 -08:00