From ad64f268838ab2a29c2bad8a9d046ed3b3fb73ba Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Sat, 21 Mar 2026 16:46:26 -0400 Subject: [PATCH] docs: add spec and implementation plan for FlowPilot message bar and Script Builder Co-Authored-By: Claude Opus 4.6 (1M context) --- ...lowpilot-message-bar-and-script-builder.md | 1990 +++++++++++++++++ ...t-message-bar-and-script-builder-design.md | 339 +++ 2 files changed, 2329 insertions(+) create mode 100644 docs/superpowers/plans/2026-03-21-flowpilot-message-bar-and-script-builder.md create mode 100644 docs/superpowers/specs/2026-03-21-flowpilot-message-bar-and-script-builder-design.md diff --git a/docs/superpowers/plans/2026-03-21-flowpilot-message-bar-and-script-builder.md b/docs/superpowers/plans/2026-03-21-flowpilot-message-bar-and-script-builder.md new file mode 100644 index 00000000..891f240d --- /dev/null +++ b/docs/superpowers/plans/2026-03-21-flowpilot-message-bar-and-script-builder.md @@ -0,0 +1,1990 @@ +# FlowPilot Message Bar & AI Script Builder — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add an always-visible message bar to FlowPilot sessions, build a standalone AI Script Builder with chat-style UX and fullscreen preview modal, reorganize the Script Library with My/Team tabs, and connect FlowPilot to the Script Builder. + +**Architecture:** Five phases executed sequentially. Phase 1 is frontend-only (message bar). Phases 2-3 add the Script Builder (new model, service, endpoints, chat page, preview modal, save flow). Phase 4 reorganizes the existing Script Library. Phase 5 wires FlowPilot to the Script Builder. + +**Tech Stack:** FastAPI, SQLAlchemy 2.0 (async), Alembic, Anthropic Claude API (Sonnet), React 19, TypeScript, Zustand, Tailwind CSS, react-syntax-highlighter, Lucide React + +**Spec:** `docs/superpowers/specs/2026-03-21-flowpilot-message-bar-and-script-builder-design.md` + +--- + +## File Map + +### Phase 1 — Message Bar + +| Action | File | +| ------ | ---- | +| Create | `frontend/src/components/flowpilot/FlowPilotMessageBar.tsx` | +| Modify | `frontend/src/components/flowpilot/FlowPilotSession.tsx` | +| Modify | `frontend/src/components/flowpilot/FlowPilotStepCard.tsx` | + +### Phase 2 — Script Builder Core (Backend) + +| Action | File | +| ------ | ---- | +| Create | `backend/app/models/script_builder_session.py` | +| Modify | `backend/alembic/env.py` (import new model) | +| Create | `backend/alembic/versions/_add_script_builder_sessions.py` (migration) | +| Create | `backend/app/schemas/script_builder.py` | +| Create | `backend/app/services/script_builder_service.py` | +| Create | `backend/app/api/endpoints/script_builder.py` | +| Modify | `backend/app/api/router.py` (register new router) | +| Modify | `backend/app/core/config.py` (add `script_build` action to `ACTION_MODEL_MAP`) | +| Create | `backend/tests/test_script_builder.py` | + +### Phase 2 — Script Builder Core (Frontend) + +| Action | File | +| ------ | ---- | +| Create | `frontend/src/types/script-builder.ts` | +| Modify | `frontend/src/types/index.ts` (export new types) | +| Create | `frontend/src/api/scriptBuilder.ts` | +| Modify | `frontend/src/api/index.ts` (export new API module) | +| Create | `frontend/src/pages/ScriptBuilderPage.tsx` | +| Create | `frontend/src/components/script-builder/ScriptBuilderChat.tsx` | +| Create | `frontend/src/components/script-builder/ScriptBuilderInput.tsx` | +| Create | `frontend/src/components/script-builder/ScriptCodeBlock.tsx` | +| Modify | `frontend/src/router.tsx` (add route) | +| Modify | `frontend/src/components/layout/Sidebar.tsx` (add nav item) | +| Modify | `frontend/src/components/layout/AppLayout.tsx` (add mobile nav item) | + +### Phase 3 — Preview Modal & Save Flow + +| Action | File | +| ------ | ---- | +| Create | `frontend/src/components/script-builder/ScriptPreviewModal.tsx` | +| Create | `frontend/src/components/script-builder/SaveToLibraryDialog.tsx` | +| Modify | `frontend/src/components/script-builder/ScriptCodeBlock.tsx` (wire modal + save) | +| Modify | `frontend/src/api/scriptBuilder.ts` (add save method) | + +### Phase 4 — Library Reorganization + +| Action | File | +| ------ | ---- | +| Create | `backend/alembic/versions/_add_language_and_ai_generated_category.py` (migration) | +| Modify | `backend/app/models/script_template.py` (add `language` column) | +| Modify | `backend/app/schemas/script_template.py` (add `language` field, `SaveToLibraryRequest`) | +| Modify | `backend/app/api/endpoints/scripts.py` (add `mine` filter) | +| Modify | `frontend/src/pages/ScriptLibraryPage.tsx` (tabs + Build button) | +| Modify | `frontend/src/types/scripts.ts` (add `language` field) | + +### Phase 5 — FlowPilot Integration + +| Action | File | +| ------ | ---- | +| Modify | `backend/app/services/flowpilot_engine.py` (prompt update for script detection) | +| Modify | `frontend/src/components/flowpilot/FlowPilotStepCard.tsx` (Script Builder action button) | + +--- + +## Phase 1: Always-Visible Message Bar + +### Task 1.1: Create FlowPilotMessageBar Component + +**Files:** + +- Create: `frontend/src/components/flowpilot/FlowPilotMessageBar.tsx` + +- [ ] **Step 1: Create the message bar component** + +```tsx +// frontend/src/components/flowpilot/FlowPilotMessageBar.tsx +import { useState, useRef, useCallback } from 'react' +import { Send } from 'lucide-react' +import { cn } from '@/lib/utils' +import type { StepResponseRequest } from '@/types/ai-session' + +interface FlowPilotMessageBarProps { + onRespond: (response: StepResponseRequest) => void + disabled?: boolean + isProcessing?: boolean +} + +export function FlowPilotMessageBar({ onRespond, disabled = false, isProcessing = false }: FlowPilotMessageBarProps) { + const [message, setMessage] = useState('') + const textareaRef = useRef(null) + + const isDisabled = disabled || isProcessing + + const handleSubmit = useCallback(() => { + const trimmed = message.trim() + if (!trimmed || isDisabled) return + onRespond({ free_text_input: trimmed }) + setMessage('') + // Reset textarea height + if (textareaRef.current) { + textareaRef.current.style.height = 'auto' + } + }, [message, isDisabled, onRespond]) + + const handleKeyDown = useCallback((e: React.KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault() + handleSubmit() + } + }, [handleSubmit]) + + const handleInput = useCallback((e: React.ChangeEvent) => { + setMessage(e.target.value) + // Auto-resize textarea + const textarea = e.target + textarea.style.height = 'auto' + textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px` + }, []) + + return ( +
+
+