Phase 19: Agent Inbox - 4 plans in 2 waves - 3 parallel (Wave 1), 1 sequential (Wave 2) - Ready for execution
4.6 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous
| phase | plan | type | wave | depends_on | files_modified | autonomous | ||
|---|---|---|---|---|---|---|---|---|
| 19-agent-inbox | 02 | execute | 1 |
|
true |
Purpose: These are the entry-point components for the inbox — showing a filterable, sortable list of agent messages. Following the wireframe spec from docs/wireframes/agent-inbox.md.
Output: InboxList and MessageCard components with filter/sort controls and empty state.
<execution_context>
@/.claude/get-shit-done/workflows/execute-plan.md
@/.claude/get-shit-done/templates/summary.md
</execution_context>
@docs/wireframes/agent-inbox.md @packages/web/src/components/InitiativeList.tsx @packages/web/src/components/InitiativeCard.tsx @packages/web/src/components/StatusBadge.tsx @packages/web/src/components/ui/card.tsx @packages/web/src/components/ui/badge.tsx @packages/web/src/components/ui/button.tsx
Task 1: Create MessageCard component packages/web/src/components/MessageCard.tsx Create MessageCard following the wireframe spec. Props: - `agentName: string` — agent human-readable name - `agentStatus: string` — 'waiting_for_input' | 'running' | 'stopped' | etc. - `preview: string` — message preview text (truncated) - `timestamp: string` — ISO date string for relative time display - `requiresResponse: boolean` — determines filled (●) vs empty (○) indicator - `isSelected: boolean` — highlighted state - `onClick: () => void`Display:
- Status indicator: ● (filled circle) when requiresResponse=true, ○ (empty) otherwise
- Agent name with status text in parentheses (e.g., "gastown (waiting)")
- Message preview truncated to ~80 chars with ellipsis
- Relative timestamp using simple helper (e.g., "2 min ago", "1h ago"). Write an inline
formatRelativeTime(isoDate: string): stringhelper at the top of the file — do NOT create a separate utils file. - Selected state: slightly different background via className toggle
Use shadcn Card as the base, Tailwind for styling. Match the visual density of InitiativeCard. npx tsc --noEmit -p packages/web/tsconfig.app.json MessageCard renders with indicator, name, preview, timestamp, and selected state
Task 2: Create InboxList component packages/web/src/components/InboxList.tsx Create InboxList following the wireframe spec. Props: - `agents: Array<{ id: string; name: string; status: string; taskId: string; updatedAt: string }>` — agent data - `messages: Array<{ id: string; senderId: string | null; content: string; requiresResponse: boolean; status: string; createdAt: string }>` — message data - `selectedAgentId: string | null` — currently selected agent - `onSelectAgent: (agentId: string) => void` — selection handler - `onRefresh: () => void` — refresh handlerInternal state:
filter: 'all' | 'waiting' | 'completed'— default 'all'sort: 'newest' | 'oldest'— default 'newest'
Behavior:
- Join agents with their latest message (match message.senderId to agent.id)
- Filter: 'waiting' = requiresResponse messages, 'completed' = responded/non-requiring messages, 'all' = everything
- Sort by message timestamp (newest or oldest)
- Render MessageCard for each result
- Show header with count badge: "Agent Inbox (3)" and Refresh button
- Filter and sort as simple button groups or select elements (not dropdowns — keep it simple)
- Empty state when no messages match filter: "No pending messages" with subtitle text
Follow the pattern from InitiativeList for the list layout structure. npx tsc --noEmit -p packages/web/tsconfig.app.json - InboxList renders with filter/sort controls - MessageCard instances rendered for each agent+message pair - Empty state shown when no messages - Filter and sort work correctly
Before declaring plan complete: - [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes - [ ] `npx vite build` in packages/web succeeds<success_criteria>
- MessageCard shows indicator, agent name, preview, relative time
- InboxList filters by waiting/completed/all
- InboxList sorts by newest/oldest
- Empty state renders when no messages match
- All builds pass </success_criteria>