- Add import for BlockedTriageModal in unified-shell.tsx
- Add blockedTriageOpen state and handlers
- Pass onOpenBlockedTriage prop to TopBar
- Render BlockedTriageModal at end of UnifiedShell
- Add onOpenBlockedTriage prop to TopBarProps interface
- Update blocked items button onClick to use onOpenBlockedTriage
- 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
TelemetryStrip now fetches from the same /api/activity endpoint and
subscribes to the same /api/events SSE stream as ActivityPanel. The
minimized dots use getEventTone() colors matching the full feed exactly
(created=green, closed=amber, reopened=blue, etc.) instead of derived
task status counts.
Co-Authored-By: Oz <oz-agent@warp.dev>
- Remove duplicate Signal (telemetry) button from DAG nodes
- Add minimize (ChevronLeft) button to Epic Command Feed view, not just global feed
- TelemetryStrip now shows 8 most recently updated tasks as status-colored dots
instead of static status counts — reflects live activity like the full feed does
- Each dot is colored by task status (blocked=red, active=amber, ready=green)
with hover tooltip showing task id, title, and status
Co-Authored-By: Oz <oz-agent@warp.dev>
- Removed broken LaunchSwarmDialog (formula-based) from TopBar/LeftPanel
- All Rocket buttons (TopBar, LeftPanel, DAG nodes, social cards) now open
AssignmentPanel (archetype-based) which actually works
- Every Rocket clears taskId first so assignMode && !taskId condition passes
- Conversation button priority: taskId always shows conversation, not assign panel
- Added TelemetryStrip: minimized right sidebar with status dots when non-telemetry
panel (conversation/assignment) is active
- Live feed has minimize button → restores last taskId or assignMode
- DAG nodes: Signal icon → restores telemetry feed
- Social button on DAG nodes: single router.push to avoid race (setView + setTaskId)
- Fixed social card message button: opens right panel with drawer:closed (no popup)
Co-Authored-By: Oz <oz-agent@warp.dev>
- 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>
- src/lib/read-issues-dolt.ts: readIssuesViaDolt() queries issues+labels (GROUP_CONCAT)
and dependencies in 2 SQL queries; normalizes Date cols to ISO strings; returns null
on unreachable so caller can fall back gracefully
- src/lib/read-issues.ts: readIssuesFromDisk() tries Dolt first (always), falls back to
issues.jsonl with console.warn; removes dead readIssuesViaBd/normalizeBdIssue/
normalizeDependencies code now that the CLI path is superseded
- AGENTS.md: documents new Dolt read path + SSE watcher trigger; removes stale
manual issues.jsonl re-export instructions (no longer needed)
Verified: bd writes update last-touched → chokidar fires → syncActivity → Dolt query
→ snapshot diff → SSE push. 146/146 tests pass, lint clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- src/lib/dolt-client.ts: getDoltConnection(projectRoot) returns cached mysql2 Pool
- Reads host/port/database from .beads/metadata.json (no hardcoded values)
- DoltConnectionError typed error for missing metadata or unreachable server
- Tests connectivity on first connection; caches pool per resolved projectRoot
- connectionLimit: 5 for Next.js server-side concurrency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 0:
- UnifiedShell: pass blockedOnly to SocialPage; wire TopBar with live counts
- thread-drawer: show real issue.status instead of hardcoded "In Progress"
- social-page: fix onJumpToActivity to open right panel (not dead ?view=activity)
Phase 1:
- contextual-right-panel: add taskId branch (ThreadDrawer embedded) and swarmId
branch (MissionInspector via SwarmIdBranch inner component); ActivityPanel
remains the no-selection fallback
All 207 tests pass; no new typecheck errors.
Closes beadboard-r1i (Phase 1: Contextual Right Panel)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Aurora: Real northern lights colors (teal/violet on deep blue-black)
- Midnight: Deep ocean blues with violet and cyan
- Forest: Rich forest greens with golden sunlight
- Dusk: Warm sunset oranges and corals
- Contrast: Pure black with neon accents
- Light: Clean professional light mode (NEW)
All themes have:
- Consistent status colors (green/amber/red)
- Distinct surface layers for visual hierarchy
- Theme-appropriate accent glows
- Improved contrast and accessibility
- Replace hardcoded blue radial gradient with theme variable
- Update graph-view to use new token system
- Ensure status colors (red/green/amber) remain consistent across all themes
- DAG background now changes with theme while maintaining card visibility
- Create ThemeToggle component with dropdown menu
- Shows all 5 themes with descriptions
- Persists choice to localStorage
- Updates data-theme attribute instantly
- Add palette icon to top bar
- aurora: Warm charcoal with cyan accents (fixed/improved)
- midnight: Cool blue-purple with violet accents
- forest: Earthy green-brown with lime accents
- dusk: Warm purple-brown with orange/pink accents
- contrast: Pure black with neon accents (high contrast)
All themes use the same 12-category token system for consistency.
Switch themes by changing data-theme attribute on html element.
Resolved conflicts:
- .gitignore: kept both bd.sock.startlock and .beadboard/ entries
- package.json: kept feature branch test script (explicit enumeration)
- API routes: kept dynamic export + isValidProjectRoot from main
- globals.css: kept HEAD slideInFromRight animation
- use-beads-subscription.ts: kept HEAD onopen handler
- realtime.ts: kept main console.log in emit()
- snapshot-differ.ts: kept main type-aware dependency diff
Blue colors preserved from feature branch.
- Add Epic Template section when an epic is selected
- Show template name, description, and team roster
- Template picker applies template to epic via metadata
- Add Remove Template functionality
- getTemplateId helper reads from metadata.templateId
- Task Assignment section only shows for non-epic tasks
- Collapsible sections for Needs Agent, Pre-assigned, Squad Roster
- Add metadata field to UpdateMutationPayload
- Add asOptionalMetadata validation function
- Pass --metadata flag to bd update command
- Enables storing custom data like templateId on issues
- ArchetypePicker: Full-screen modal with backdrop blur, 2-column grid,
Select/Edit/Create actions, 800px width for readability
- TemplatePicker: Same pattern with team size indicator and built-in badge
- Both pickers support backdrop click-to-close and keyboard navigation
- Add templateId: string | null to BeadIssue (links epics to templates)
- Add icon field to AgentArchetype for emoji/icon display
- Add color and icon fields to SwarmTemplate for visual customization
## Design Decision
Per bd (bead) system design, a task should have only ONE agent archetype
assigned at a time. This provides clear ownership and simpler mental model.
## What Changed
When assigning a new archetype:
1. Remove any existing agent: labels first (DELETE API)
2. Then add the new agent: label (POST API)
3. Optimistic UI updates to match
## Why This Makes Sense
- Clear ownership: 'Who's working on this?'
- Simpler coordination between tasks
- Matches how bd/agent orchestration is intended to work
- Reassigning is still possible (just click a different archetype)
## UI Behavior
- If task has 'coder' assigned, clicking 'architect' will:
1. Remove 'coder' label
2. Add 'architect' label
- Dropdown shows 'Assigned' badge on current archetype
- X button still available to unassign completely
## Test Coverage
Added graph-node-single-archetype.test.tsx with 5 tests:
- Removes existing labels before adding new
- Calls DELETE before POST
- Only allows one archetype per task
- Preserves non-agent labels
- Returns early if same archetype clicked
## The Bug
User reported: 'An archetype can only exist on one task at a time - when
I try to make the next task have the same arch, it deleted the one I
added prior.'
## Root Cause
The SSE subscription (useBeadsSubscription) refreshes data from the server
whenever ANY change happens. When user assigns an archetype:
1. User clicks assign -> optimistic update adds label locally
2. SSE fires (from previous operation or heartbeat) -> fetches fresh data
3. useEffect syncs localLabels with data.labels (which doesn't have the
new label yet)
4. Label disappears from UI
5. Eventually API completes and another SSE refresh brings it back
This race condition causes labels to flicker or disappear entirely.
## The Fix
Track pending optimistic labels in a useRef Set, and merge them with
incoming server data during sync:
1. pendingOptimisticLabels = useRef<Set<string>>(new Set())
2. When optimistically adding: add to pending set
3. useEffect merge: combine server labels + pending labels
4. After API completes: remove from pending set
This ensures optimistic labels survive SSE refreshes.
## Test Coverage
Added graph-node-labels-optimistic.test.tsx with 10 tests:
- Uses useRef for tracking
- Tracks in a Set
- Preserves labels during sync
- Adds/removes from pending set
- Handles multiple concurrent operations
- Per-node state isolation
## Verification
- typecheck: pass
- lint: pass (0 errors)
- test: all pass
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.
## Context
This commit adds the supporting infrastructure that makes the assign
feature work end-to-end.
## Components Added/Modified
### SmartDag
- Main view component for graph-based task management
- Integrates TaskCardGrid and WorkflowGraph
- Has 'Assign' mode toggle button
- Passes archetypes and assignMode to WorkflowGraph
- Manages filter state (hideClosed, sortReadyFirst, etc.)
### useGraphAnalysis Hook
- Extracted graph analysis logic for reuse
- Returns: actionableNodeIds, cycleNodeIdSet, blockerTooltipMap, etc.
- Used by both SmartDag and AssignmentPanel
- Ensures consistent 'actionable' definition across components
### UnifiedShell
- Added assignMode state
- Added selectedAssignIssue state
- Renders AssignmentPanel when in graph view + assign mode
- Wires up onAssignModeChange and onSelectedIssueChange callbacks
## Design Philosophy
- Shared hook means single source of truth for 'actionable'
- Clean separation between view (SmartDag) and sidebar (AssignmentPanel)
- URL state preserved for navigation
## Test Coverage
- SmartDag tests: 12 tests covering buttons, callbacks, imports
- useGraphAnalysis tests: 6 tests covering cycle detection, blockers
- UnifiedShell tests: 9 tests covering state and rendering
## The Feature Request
User wanted an enhanced sidebar panel showing:
- Tasks needing agents (ready but unassigned)
- Pre-assigned tasks waiting to start
- Active workers on current epic
## Design Collaboration
We discussed what each section should show:
1. **Needs Agent**: Actionable tasks (no blockers) without agent: label
2. **Pre-assigned**: Tasks with agent: label, not yet in_progress
3. **Squad Roster**: in_progress tasks with assignee
## Technical Implementation
- Uses useGraphAnalysis hook for actionableNodeIds
- Helper functions: hasAgentLabel(), getAgentLabels(), extractArchetypeIdFromLabel()
- Quick assign dropdown on each 'Needs Agent' item
- Archetype badges shown on 'Pre-assigned' items
## UI/UX Decisions
- Each section has count badge in header
- Max-height with scroll for each section
- Consistent styling with existing panel patterns
- Uses CSS variables for theming
## Test Coverage
- Added assignment-panel-sections.test.tsx with 5 TDD tests
- Tests verify: useGraphAnalysis import, section headers, filtering logic
## Beads: beadboard-b7t (closed)