/** * Preview Seed Script * * Populates the database with demo data for preview deployments. * Run with: CW_DB_PATH=/workspace/.cw/cw.db node /app/apps/server/dist/preview-seed.js * * Prints the project ID to stdout so the calling shell script * can derive the clone path. */ import { createDatabase, ensureSchema } from './db/index.js'; import { createRepositories } from './container.js'; const dbPath = process.env.CW_DB_PATH; if (!dbPath) { console.error('CW_DB_PATH environment variable is required'); process.exit(1); } const db = createDatabase(dbPath); ensureSchema(db); const repos = createRepositories(db); // ─── Project ─── const project = await repos.projectRepository.create({ name: 'demo-app', url: 'file:///workspace/demo-repo.git', defaultBranch: 'main', }); // ─── Initiative ─── const initiative = await repos.initiativeRepository.create({ name: 'Task Manager Redesign', status: 'active', branch: 'cw/task-manager-redesign', executionMode: 'review_per_phase', }); await repos.projectRepository.setInitiativeProjects(initiative.id, [project.id]); // ─── Phases ─── const phase1 = await repos.phaseRepository.create({ initiativeId: initiative.id, name: 'Backend API', status: 'completed', }); const phase2 = await repos.phaseRepository.create({ initiativeId: initiative.id, name: 'UI Overhaul', status: 'pending_review', }); const phase3 = await repos.phaseRepository.create({ initiativeId: initiative.id, name: 'Testing & Polish', status: 'in_progress', }); // ─── Tasks ─── // Phase 1: Backend API (all completed) const task1a = await repos.taskRepository.create({ phaseId: phase1.id, initiativeId: initiative.id, name: 'Research REST vs GraphQL patterns', category: 'research', status: 'completed', description: 'Evaluate REST and GraphQL approaches for the task management API. Consider developer experience, caching, and real-time requirements.', order: 0, summary: 'Recommended REST with WebSocket subscriptions for real-time. GraphQL adds complexity without clear benefit for this domain.', }); const task1b = await repos.taskRepository.create({ phaseId: phase1.id, initiativeId: initiative.id, name: 'Implement task CRUD endpoints', category: 'execute', status: 'completed', description: 'Build the core CRUD API for tasks with proper validation and error handling.', order: 1, summary: 'Implemented GET/POST/PUT/DELETE /api/tasks with Zod validation, proper HTTP status codes, and pagination support.', }); const task1c = await repos.taskRepository.create({ phaseId: phase1.id, initiativeId: initiative.id, name: 'Add input validation middleware', category: 'execute', status: 'completed', description: 'Create reusable validation middleware using Zod schemas for all API endpoints.', order: 2, summary: 'Added validateBody() and validateQuery() middleware with typed error responses.', }); // Phase 2: UI Overhaul (all completed) const task2a = await repos.taskRepository.create({ phaseId: phase2.id, initiativeId: initiative.id, name: 'Design component hierarchy', category: 'plan', status: 'completed', description: 'Plan the component architecture for the redesigned UI, focusing on reusability and maintainability.', order: 0, summary: 'Designed 3-level hierarchy: Layout (Header, Sidebar) → Views (TaskList, TaskDetail) → Primitives (StatusBadge, PriorityTag).', }); const task2b = await repos.taskRepository.create({ phaseId: phase2.id, initiativeId: initiative.id, name: 'Implement responsive header', category: 'execute', status: 'completed', description: 'Build the responsive header component with search functionality and notification bell.', order: 1, summary: 'Created Header.tsx with search input, notification dropdown (3 mock items), and user avatar. Fully responsive with mobile hamburger menu.', }); const task2c = await repos.taskRepository.create({ phaseId: phase2.id, initiativeId: initiative.id, name: 'Refactor task list with filters', category: 'execute', status: 'completed', description: 'Rewrite the task list component with status icons, priority badges, and filter controls.', order: 2, summary: 'Refactored TaskList.tsx with table layout, status icons, priority badges, assignee avatars, and due dates. Added TaskFilters.tsx with status/priority filter buttons.', }); // Phase 3: Testing & Polish (mixed statuses) const task3a = await repos.taskRepository.create({ phaseId: phase3.id, initiativeId: initiative.id, name: 'Plan test strategy', category: 'plan', status: 'completed', description: 'Define the testing strategy: unit tests, integration tests, and E2E test coverage targets.', order: 0, summary: 'Defined 3-tier strategy: Vitest unit tests (80% coverage), API integration tests with supertest, and Playwright E2E for critical flows.', }); const task3b = await repos.taskRepository.create({ phaseId: phase3.id, initiativeId: initiative.id, name: 'Write integration tests', category: 'execute', status: 'in_progress', description: 'Write integration tests for all API endpoints using supertest.', order: 1, }); const task3c = await repos.taskRepository.create({ phaseId: phase3.id, initiativeId: initiative.id, name: 'Add error handling', category: 'execute', status: 'pending', description: 'Add global error boundary, API error toasts, and retry logic for failed requests.', order: 2, }); // ─── Agents ─── const agent1 = await repos.agentRepository.create({ name: 'keen-falcon', worktreeId: 'worktrees/keen-falcon', taskId: task1b.id, initiativeId: initiative.id, status: 'stopped', mode: 'execute', provider: 'claude', }); const agent2 = await repos.agentRepository.create({ name: 'swift-otter', worktreeId: 'worktrees/swift-otter', taskId: task2c.id, initiativeId: initiative.id, status: 'stopped', mode: 'execute', provider: 'claude', }); const agent3 = await repos.agentRepository.create({ name: 'bright-heron', worktreeId: 'worktrees/bright-heron', taskId: task3b.id, initiativeId: initiative.id, status: 'running', mode: 'execute', provider: 'claude', }); // ─── Agent Log Chunks ─── // Agent 1: keen-falcon (completed backend work) await repos.logChunkRepository.insertChunk({ agentId: agent1.id, agentName: 'keen-falcon', sessionNumber: 1, content: [ JSON.stringify({ type: 'system', session_id: 'session-kf-001' }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "I'll start by reading the existing API structure to understand the current patterns." }, { type: 'tool_use', id: 'toolu_kf1', name: 'Read', input: { file_path: '/app/src/lib/api.ts' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: "const API_URL = '/api';\n\nexport async function fetchTasks(filter: string) {\n const res = await fetch(`${API_URL}/tasks?filter=${filter}`);\n return res.json();\n}" }] }, tool_use_result: { stdout: "const API_URL = '/api';\n\nexport async function fetchTasks(filter: string) {\n const res = await fetch(`${API_URL}/tasks?filter=${filter}`);\n return res.json();\n}" }, }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "Now I'll implement the task CRUD endpoints with proper validation. I'll create a structured API client with error handling." }, { type: 'tool_use', id: 'toolu_kf2', name: 'Write', input: { file_path: '/app/src/server/routes/tasks.ts', content: '// CRUD endpoints implementation...' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'File written successfully' }] }, tool_use_result: { stdout: 'File written successfully' }, }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "Let me also add the Zod validation schemas and middleware." }, { type: 'tool_use', id: 'toolu_kf3', name: 'Write', input: { file_path: '/app/src/server/middleware/validate.ts', content: '// Validation middleware...' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'File written successfully' }] }, tool_use_result: { stdout: 'File written successfully' }, }), JSON.stringify({ type: 'result', is_error: false, total_cost_usd: 0.0847, duration_ms: 32000 }), ].join('\n'), }); // Agent 2: swift-otter (completed UI overhaul) await repos.logChunkRepository.insertChunk({ agentId: agent2.id, agentName: 'swift-otter', sessionNumber: 1, content: [ JSON.stringify({ type: 'system', session_id: 'session-so-001' }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "I'll start by reading the current TaskList component to understand what needs to be refactored." }, { type: 'tool_use', id: 'toolu_so1', name: 'Read', input: { file_path: '/app/src/components/TaskList.tsx' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: "import { useTasks } from '../hooks/useTasks';\n\nexport function TaskList({ filter }) {\n const { tasks, loading } = useTasks(filter);\n if (loading) return
Loading...
;\n return (\n \n );\n}", }], }, tool_use_result: { stdout: "import { useTasks } from '../hooks/useTasks';\n..." }, }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "The current TaskList is very basic — just a plain unordered list with no visual hierarchy. I'll refactor it into a proper table with status icons, priority badges, assignee avatars, and a loading skeleton." }, { type: 'tool_use', id: 'toolu_so2', name: 'Edit', input: { file_path: '/app/src/components/TaskList.tsx', old_string: "import { useTasks } from '../hooks/useTasks';", new_string: "import { useTasks } from '../hooks/useTasks';\n\ninterface Task {\n id: string;\n title: string;\n status: 'active' | 'completed' | 'blocked';\n priority: 'high' | 'medium' | 'low';\n assignee?: string;\n}", }, }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'File edited successfully' }] }, tool_use_result: { stdout: 'File edited successfully' }, }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "Now I'll create the TaskFilters component for status and priority filtering." }, { type: 'tool_use', id: 'toolu_so3', name: 'Write', input: { file_path: '/app/src/components/TaskFilters.tsx', content: '// TaskFilters component...' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'File written successfully' }] }, tool_use_result: { stdout: 'File written successfully' }, }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "Finally, let me refactor the API client to be type-safe with proper error handling." }, { type: 'tool_use', id: 'toolu_so4', name: 'Edit', input: { file_path: '/app/src/lib/api.ts', old_string: "const API_URL = '/api';", new_string: 'class ApiClient {\n private baseUrl: string;\n constructor(baseUrl = \'/api\') { this.baseUrl = baseUrl; }' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'File edited successfully' }] }, tool_use_result: { stdout: 'File edited successfully' }, }), JSON.stringify({ type: 'result', is_error: false, total_cost_usd: 0.1234, duration_ms: 45000 }), ].join('\n'), }); // Agent 3: bright-heron (in-progress, no result line) await repos.logChunkRepository.insertChunk({ agentId: agent3.id, agentName: 'bright-heron', sessionNumber: 1, content: [ JSON.stringify({ type: 'system', session_id: 'session-bh-001' }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "I'll start writing integration tests for the task CRUD endpoints. Let me first check the existing test setup." }, { type: 'tool_use', id: 'toolu_bh1', name: 'Bash', input: { command: 'ls src/test/', description: 'Check existing test files' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'setup.ts\nfixtures/' }] }, tool_use_result: { stdout: 'setup.ts\nfixtures/' }, }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "Good, there's a test setup file and fixtures directory. Let me read the setup to understand the test configuration." }, { type: 'tool_use', id: 'toolu_bh2', name: 'Read', input: { file_path: '/app/src/test/setup.ts' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: "import { beforeAll, afterAll } from 'vitest';\nimport { createTestServer } from './fixtures/server';\n\nlet server;\nbeforeAll(async () => { server = await createTestServer(); });\nafterAll(() => server?.close());" }] }, tool_use_result: { stdout: "import { beforeAll, afterAll } from 'vitest';\n..." }, }), JSON.stringify({ type: 'assistant', message: { content: [ { type: 'text', text: "Now I'll write the integration tests for the tasks API. Starting with the CRUD operations..." }, { type: 'tool_use', id: 'toolu_bh3', name: 'Write', input: { file_path: '/app/src/test/tasks.test.ts', content: '// Integration tests...' } }, ], }, }), JSON.stringify({ type: 'user', message: { content: [{ type: 'tool_result', content: 'File written successfully' }] }, tool_use_result: { stdout: 'File written successfully' }, }), ].join('\n'), }); // ─── Root Page ─── const pageContent = { type: 'doc', content: [ { type: 'heading', attrs: { level: 1 }, content: [{ type: 'text', text: 'Task Manager Redesign' }], }, { type: 'paragraph', content: [ { type: 'text', text: 'A comprehensive redesign of the task management application, focusing on improved user experience, type safety, and modern UI patterns.', }, ], }, { type: 'heading', attrs: { level: 2 }, content: [{ type: 'text', text: 'Goals' }], }, { type: 'bulletList', content: [ { type: 'listItem', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Responsive layout with mobile-first design' }] }], }, { type: 'listItem', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Type-safe API client with proper error handling' }] }], }, { type: 'listItem', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Status icons and priority badges for visual clarity' }] }], }, { type: 'listItem', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Comprehensive test coverage (unit, integration, E2E)' }] }], }, ], }, { type: 'heading', attrs: { level: 2 }, content: [{ type: 'text', text: 'Progress' }], }, { type: 'paragraph', content: [ { type: 'text', text: 'Backend API is complete with full CRUD endpoints and validation middleware. The UI overhaul phase is in review — header, task list, and filters have been refactored. Testing phase is actively in progress with integration tests being written.', }, ], }, ], }; await repos.pageRepository.create({ initiativeId: initiative.id, title: 'Task Manager Redesign', content: JSON.stringify(pageContent), sortOrder: 0, }); // ─── Review Comments (on Phase 2) ─── await repos.reviewCommentRepository.create({ phaseId: phase2.id, filePath: 'src/components/TaskList.tsx', lineNumber: 12, lineType: 'added', body: 'Should we memoize the STATUS_ICONS and PRIORITY_COLORS objects since they are static? Moving them outside the component is good, but wrapping the component in React.memo might help with re-renders.', author: 'you', }); await repos.reviewCommentRepository.create({ phaseId: phase2.id, filePath: 'src/components/Header.tsx', lineNumber: 8, lineType: 'added', body: 'The notifications are hardcoded. For the demo this is fine, but we should add a TODO to wire this up to a real notification system.', author: 'you', }); await repos.reviewCommentRepository.create({ phaseId: phase2.id, filePath: 'src/lib/api.ts', lineNumber: 25, lineType: 'added', body: 'Nice error handling pattern. Could we also add request timeout support? Long-running requests should fail gracefully.', author: 'you', }); // Print project ID for the shell script process.stdout.write(project.id);