--- phase: 23-brainstormer-flow plan: 02 type: execute wave: 1 depends_on: ["23-00"] files_modified: - ui/src/components/ChatSpecCard.tsx - ui/src/components/ChatHandoffIndicator.tsx - ui/src/components/ChatTaskCreatedBadge.tsx - ui/src/components/ChatStatusUpdateBadge.tsx - ui/src/hooks/useBrainstormerDefault.ts autonomous: true requirements: - AGENT-01 - AGENT-02 - AGENT-05 - AGENT-06 - AGENT-07 must_haves: truths: - "ChatSpecCard renders spec sections and action buttons" - "ChatSpecCard edit mode allows editing all four fields" - "ChatHandoffIndicator renders as separator with flanking hr elements" - "ChatTaskCreatedBadge shows loading state and resolved state" - "ChatStatusUpdateBadge shows completion icon and task reference" - "useBrainstormerDefault returns general role agent ID" artifacts: - path: "ui/src/components/ChatSpecCard.tsx" provides: "Spec card with What/Why/Constraints/Success fields and action buttons" exports: ["ChatSpecCard"] - path: "ui/src/components/ChatHandoffIndicator.tsx" provides: "Separator-style handoff indicator" exports: ["ChatHandoffIndicator"] - path: "ui/src/components/ChatTaskCreatedBadge.tsx" provides: "Task created inline badge" exports: ["ChatTaskCreatedBadge"] - path: "ui/src/components/ChatStatusUpdateBadge.tsx" provides: "Status update inline badge" exports: ["ChatStatusUpdateBadge"] - path: "ui/src/hooks/useBrainstormerDefault.ts" provides: "Hook returning general agent ID for auto-selection" exports: ["useBrainstormerDefault"] key_links: - from: "ui/src/hooks/useBrainstormerDefault.ts" to: "ui/src/api/agents.ts" via: "useQuery with agents queryKey" pattern: 'queryKey.*agents' --- Build all five new UI components and the useBrainstormerDefault hook for Phase 23. Purpose: These components render the four structured message types (spec_card, handoff, task_created, status_update) and provide the brainstormer default agent selection. Plan 03 wires them into ChatMessage dispatch. Output: 4 new components + 1 new hook, all independently testable. @.claude/get-shit-done/workflows/execute-plan.md @.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/23-brainstormer-flow/23-RESEARCH.md @.planning/phases/23-brainstormer-flow/23-UI-SPEC.md @.planning/phases/23-brainstormer-flow/23-00-SUMMARY.md From ui/src/components/ChatMessage.tsx: ```typescript interface ChatMessageProps { id?: string; role: "user" | "assistant" | "system"; content: string; agentName?: string | null; agentIcon?: string | null; agentRole?: AgentRole | null; timestamp?: string; isStreaming?: boolean; isAnyStreaming?: boolean; onEdit?: (messageId: string, newContent: string) => void; onRetry?: (messageId: string) => void; } ``` From ui/src/api/chat.ts: ```typescript export const chatApi = { editMessage(conversationId: string, messageId: string, content: string) { ... }, // Will need: handoffSpec(conversationId, spec, targetRole) — added in Plan 03 }; ``` From ui/src/api/issues.ts: ```typescript export const issuesApi = { create: (companyId: string, data: Record) => api.post(`/companies/${companyId}/issues`, data), }; ``` Existing shadcn components available: button, card, textarea (all installed). Lucide icons needed: CheckCircle2, Brain (from lucide-react ^0.574.0, already installed). From agent-role-colors.ts: general role maps to text-slate-600 dark:text-slate-400. Task 1: ChatSpecCard and ChatHandoffIndicator components - ui/src/components/ChatMessage.tsx - ui/src/components/ChatMessageIdentityBar.tsx - .planning/phases/23-brainstormer-flow/23-UI-SPEC.md (Spec Card Layout section and Handoff Indicator section) ui/src/components/ChatSpecCard.tsx, ui/src/components/ChatHandoffIndicator.tsx 1. Create `ui/src/components/ChatSpecCard.tsx`: Props interface: ```typescript interface ChatSpecCardProps { content: string; // JSON string of SpecContent messageId?: string; conversationId?: string; onHandoff?: (spec: SpecContent) => void; } interface SpecContent { what: string; why: string; constraints: string; success: string; } ``` Implementation: - Parse `content` via `JSON.parse` in a try/catch. On failure, render: `
Could not render spec.
` - Container: `role="region" aria-label="Specification"` with `className="motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-2 rounded-lg border border-border bg-card p-4 max-w-[480px]"` - Four sections, each with: - Label: `

What

` (and Why, Constraints, Success) - Content: `

{spec.what}

` - Sections wrapped in `
` - Action row: `
` - "Send to PM" button: `variant="default" size="sm"` — calls `onHandoff?.(spec)`, disables during submission with `aria-disabled="true"` and `aria-busy="true"` on container - "Edit" button: `variant="outline" size="sm"` — toggles local `isEditing` state - "Save as Draft" button: `variant="ghost" size="sm"` — sets local `isDraft` state, adds "[Draft]" badge - Edit mode (when `isEditing === true`): - Each field becomes a `