#!/bin/sh set -e echo "=== Creating demo git repository ===" BARE_REPO="/workspace/demo-repo.git" TEMP_DIR=$(mktemp -d) # Initialize bare repo git init --bare "$BARE_REPO" cd "$TEMP_DIR" git init -b main git remote add origin "$BARE_REPO" # ─── main branch: initial task manager app ─── cat > README.md << 'READMEEOF' # Task Manager A modern task management application built with React and TypeScript. ## Features - Create, update, and delete tasks - Filter by status and priority - Real-time updates - Responsive design ## Getting Started ```bash npm install npm run dev ``` READMEEOF cat > package.json << 'PKGEOF' { "name": "task-manager", "version": "1.0.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc && vite build" }, "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0" } } PKGEOF mkdir -p src/components src/hooks src/lib cat > src/app.tsx << 'APPEOF' import { useState } from 'react'; import { TaskList } from './components/TaskList'; import { Sidebar } from './components/Sidebar'; export function App() { const [filter, setFilter] = useState('all'); return (

Task Manager

); } APPEOF cat > src/components/TaskList.tsx << 'TLEOF' import { useTasks } from '../hooks/useTasks'; interface TaskListProps { filter: string; } export function TaskList({ filter }: TaskListProps) { const { tasks, loading } = useTasks(filter); if (loading) return
Loading...
; return ( ); } TLEOF cat > src/components/Sidebar.tsx << 'SBEOF' interface SidebarProps { filter: string; onFilterChange: (filter: string) => void; } export function Sidebar({ filter, onFilterChange }: SidebarProps) { const filters = ['all', 'active', 'completed']; return ( ); } SBEOF cat > src/hooks/useTasks.ts << 'HTEOF' import { useState, useEffect } from 'react'; import { fetchTasks } from '../lib/api'; export function useTasks(filter: string) { const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { fetchTasks(filter).then(data => { setTasks(data); setLoading(false); }); }, [filter]); return { tasks, loading }; } HTEOF cat > src/lib/api.ts << 'APIEOF' const API_URL = '/api'; export async function fetchTasks(filter: string) { const res = await fetch(`${API_URL}/tasks?filter=${filter}`); return res.json(); } export async function createTask(title: string) { const res = await fetch(`${API_URL}/tasks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title }), }); return res.json(); } APIEOF git add -A git commit -m "feat: initial task manager setup" git push origin main # ─── initiative branch (same as main, no extra commits) ─── git checkout -b cw/task-manager-redesign git push origin cw/task-manager-redesign # ─── phase branch: UI overhaul with 3 commits ─── git checkout -b cw/task-manager-redesign-phase-ui-overhaul # Commit 1: responsive header with search and notifications mkdir -p src/components cat > src/components/Header.tsx << 'HDREOF' import { useState } from 'react'; interface HeaderProps { onSearch: (query: string) => void; } export function Header({ onSearch }: HeaderProps) { const [query, setQuery] = useState(''); const [notifications] = useState([ { id: 1, text: 'Task "Deploy v2" completed', unread: true }, { id: 2, text: 'New comment on "API redesign"', unread: true }, { id: 3, text: 'Sprint review tomorrow', unread: false }, ]); const unreadCount = notifications.filter(n => n.unread).length; return (

TaskFlow

{ setQuery(e.target.value); onSearch(e.target.value); }} />
JD
); } HDREOF cat > src/components/TaskFilters.tsx << 'TFEOF' interface TaskFiltersProps { activeFilter: string; onFilterChange: (filter: string) => void; activePriority: string; onPriorityChange: (priority: string) => void; } export function TaskFilters({ activeFilter, onFilterChange, activePriority, onPriorityChange, }: TaskFiltersProps) { const statuses = ['all', 'active', 'completed', 'blocked']; const priorities = ['all', 'high', 'medium', 'low']; return (
{statuses.map(s => ( ))}
{priorities.map(p => ( ))}
); } TFEOF # Update app.tsx to use Header cat > src/app.tsx << 'APPEOF2' import { useState } from 'react'; import { Header } from './components/Header'; import { TaskList } from './components/TaskList'; import { TaskFilters } from './components/TaskFilters'; import { Sidebar } from './components/Sidebar'; export function App() { const [filter, setFilter] = useState('all'); const [priority, setPriority] = useState('all'); const [searchQuery, setSearchQuery] = useState(''); return (
); } APPEOF2 git add -A git commit -m "feat: add responsive header with search and notifications" # Commit 2: enhance task list with status icons and priorities cat > src/components/TaskList.tsx << 'TL2EOF' import { useTasks } from '../hooks/useTasks'; interface Task { id: string; title: string; status: 'active' | 'completed' | 'blocked'; priority: 'high' | 'medium' | 'low'; assignee?: string; dueDate?: string; } interface TaskListProps { filter: string; } const STATUS_ICONS: Record = { active: '🔵', completed: '✅', blocked: '🔴', }; const PRIORITY_COLORS: Record = { high: 'priority-high', medium: 'priority-medium', low: 'priority-low', }; export function TaskList({ filter }: TaskListProps) { const { tasks, loading } = useTasks(filter); if (loading) { return (
{[1, 2, 3].map(i => (
))}
); } if (tasks.length === 0) { return (

No tasks found

); } return (
Task Priority Assignee Due Date Status
{(tasks as Task[]).map(task => (
{STATUS_ICONS[task.status]} {task.title}
{task.priority} {task.assignee ? ( {task.assignee.slice(0, 2).toUpperCase()} ) : ( )} {task.dueDate ?? '—'} {task.status}
))}
); } TL2EOF git add -A git commit -m "refactor: enhance task list with status icons and priorities" # Commit 3: type-safe API client with error handling cat > src/lib/api.ts << 'API2EOF' interface ApiError { message: string; status: number; } interface Task { id: string; title: string; status: 'active' | 'completed' | 'blocked'; priority: 'high' | 'medium' | 'low'; assignee?: string; dueDate?: string; } interface CreateTaskInput { title: string; priority?: Task['priority']; assignee?: string; dueDate?: string; } class ApiClient { private baseUrl: string; constructor(baseUrl = '/api') { this.baseUrl = baseUrl; } private async request(path: string, options?: RequestInit): Promise { const response = await fetch(`${this.baseUrl}${path}`, { ...options, headers: { 'Content-Type': 'application/json', ...options?.headers, }, }); if (!response.ok) { const error: ApiError = { message: `Request failed: ${response.statusText}`, status: response.status, }; throw error; } return response.json(); } async getTasks(filter?: string): Promise { const params = filter && filter !== 'all' ? `?filter=${filter}` : ''; return this.request(`/tasks${params}`); } async getTask(id: string): Promise { return this.request(`/tasks/${id}`); } async createTask(input: CreateTaskInput): Promise { return this.request('/tasks', { method: 'POST', body: JSON.stringify(input), }); } async updateTask(id: string, updates: Partial): Promise { return this.request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(updates), }); } async deleteTask(id: string): Promise { await this.request(`/tasks/${id}`, { method: 'DELETE' }); } } export const api = new ApiClient(); API2EOF cat > src/hooks/useTasks.ts << 'HT2EOF' import { useState, useEffect, useCallback } from 'react'; import { api } from '../lib/api'; interface Task { id: string; title: string; status: 'active' | 'completed' | 'blocked'; priority: 'high' | 'medium' | 'low'; assignee?: string; dueDate?: string; } interface UseTasksResult { tasks: Task[]; loading: boolean; error: string | null; refresh: () => void; createTask: (title: string) => Promise; deleteTask: (id: string) => Promise; } export function useTasks(filter: string): UseTasksResult { const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const loadTasks = useCallback(async () => { try { setLoading(true); setError(null); const data = await api.getTasks(filter); setTasks(data); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load tasks'); } finally { setLoading(false); } }, [filter]); useEffect(() => { loadTasks(); }, [loadTasks]); const createTask = useCallback(async (title: string) => { await api.createTask({ title }); await loadTasks(); }, [loadTasks]); const deleteTask = useCallback(async (id: string) => { await api.deleteTask(id); await loadTasks(); }, [loadTasks]); return { tasks, loading, error, refresh: loadTasks, createTask, deleteTask }; } HT2EOF git add -A git commit -m "refactor: type-safe API client with error handling" # Push all branches git push origin cw/task-manager-redesign-phase-ui-overhaul # Clean up cd / rm -rf "$TEMP_DIR" echo "=== Demo git repository created at $BARE_REPO ===" # ─── Step 2: Run Node.js seed ─── echo "=== Running database seed ===" PROJECT_ID=$(CW_DB_PATH=/workspace/.cw/cw.db node /app/apps/server/dist/preview-seed.js) echo "=== Seed complete, project ID: $PROJECT_ID ===" # ─── Step 3: Set up local branches in the server's clone dir ─── CLONE_DIR="/workspace/repos/demo-app-${PROJECT_ID}" echo "=== Cloning demo repo to $CLONE_DIR ===" mkdir -p /workspace/repos git clone "$BARE_REPO" "$CLONE_DIR" echo "=== Setting up local branches in $CLONE_DIR ===" cd "$CLONE_DIR" git checkout -b cw/task-manager-redesign origin/cw/task-manager-redesign git checkout -b cw/task-manager-redesign-phase-ui-overhaul origin/cw/task-manager-redesign-phase-ui-overhaul git checkout main echo "=== Preview seed complete ==="