- Implemented Input component for user input fields. - Created Separator component for visual separation in UI. - Added Sheet component for modal-like overlays with customizable content. - Developed Sidebar component with collapsible functionality and mobile responsiveness. - Introduced Skeleton component for loading placeholders. - Implemented Tooltip component for contextual hints. - Updated global CSS variables for sidebar theming. - Added useIsMobile hook for responsive design handling. - Modified projects route to include ProjectSidebar. - Enhanced Tailwind CSS configuration for improved styling. - Updated Vite preload configuration for custom entry file naming.
464 lines
33 KiB
JSON
464 lines
33 KiB
JSON
{
|
|
"project": "Adiuva",
|
|
"branchName": "ralph/adiuva-mvp",
|
|
"description": "Adiuva MVP — Local-first desktop workspace with hierarchical project management, Fluid Curtain AI chat overlay, and multi-agent intelligence via GitHub Copilot SDK",
|
|
"userStories": [
|
|
{
|
|
"id": "US-001",
|
|
"title": "Electron + React scaffold",
|
|
"description": "As a developer, I need a working Electron app with React+TypeScript and a shared main/renderer process setup so that all other features have a platform to run on.",
|
|
"acceptanceCriteria": [
|
|
"electron-forge + Vite plugin scaffold with hot-reload in dev",
|
|
"Main process opens a BrowserWindow serving the React app",
|
|
"TypeScript strict mode enabled, tsconfig.json configured",
|
|
"package.json scripts: dev, build, preview",
|
|
"App opens without errors",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 1,
|
|
"passes": true,
|
|
"notes": "Completed in initial scaffold commit (f6cc8bb)"
|
|
},
|
|
{
|
|
"id": "US-002",
|
|
"title": "SQLite + Drizzle ORM schema and migrations",
|
|
"description": "As a developer, I need the SQLite database initialized with Drizzle ORM so that all CRUD operations use a typed, schema-driven interface.",
|
|
"acceptanceCriteria": [
|
|
"better-sqlite3 and drizzle-orm installed as main-process dependencies",
|
|
"Drizzle schema file defines all 5 tables matching the PRD exactly: clients (id, parentId, name, industry, createdAt), projects (id, clientId, name, status, aiSummary, createdAt), tasks (id, projectId, title, description, status, priority, assignee, dueDate, createdAt), checkpoints (id, projectId, title, date, isAiSuggested, isApproved, createdAt), notes (id, projectId, title, content, createdAt, updatedAt)",
|
|
"DB file created at app.getPath('userData')/adiuva.db on startup",
|
|
"Migration runs automatically on app start (drizzle-kit migrate or push); never destructive",
|
|
"All IDs are UUIDs generated via crypto.randomUUID()",
|
|
"TypeScript types inferred from schema with no manual type duplication",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 2,
|
|
"passes": true,
|
|
"notes": "Completed: better-sqlite3 + drizzle-orm, 5-table schema, non-destructive push migration via CREATE TABLE IF NOT EXISTS, WAL mode enabled"
|
|
},
|
|
{
|
|
"id": "US-003",
|
|
"title": "electron-trpc IPC bridge and appRouter scaffold",
|
|
"description": "As a developer, I need electron-trpc wired up between main and renderer processes so that all DB and AI operations are exposed as type-safe tRPC procedures callable from the renderer.",
|
|
"acceptanceCriteria": [
|
|
"electron-trpc installed; IPC bridge configured in main process and preload script",
|
|
"appRouter defined in main process with stub routers for all domains: clients, projects, tasks, checkpoints, notes, ai",
|
|
"Renderer-side trpc client created with the correct IPC link and wrapped in TRPCProvider + QueryClientProvider",
|
|
"A health.ping procedure returns 'pong' and is successfully callable from the renderer (verified via console log or React component)",
|
|
"Zod imported and used to validate at least one procedure input",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 3,
|
|
"passes": true,
|
|
"notes": "Completed: electron-trpc IPC bridge, appRouter with stub routers for all 7 domains (health, clients, projects, tasks, checkpoints, notes, ai), renderer TRPCProvider+QueryClientProvider, health.ping returns 'pong' displayed in HomePage, Zod validates all procedure inputs"
|
|
},
|
|
{
|
|
"id": "US-004",
|
|
"title": "App shell layout and sidebar navigation",
|
|
"description": "As a user, I want a persistent left sidebar so that I can navigate between all sections of the app.",
|
|
"acceptanceCriteria": [
|
|
"Sidebar renders at 240px with #fafafa background and 1px right border (#e5e5e5)",
|
|
"Nav items render with Lucide icons + labels: Home (house), Timeline (chart-gantt), Tasks (clipboard-check), Projects (folder-kanban)",
|
|
"Active route highlights nav item with #f5f5f5 accent background (no extra border)",
|
|
"Collapse button at bottom toggles sidebar to icon-only mode (64px wide); state persisted via electron-store",
|
|
"TanStack Router renders the correct view component for each nav route: /, /timeline, /tasks, /projects",
|
|
"Right-edge vertical rotated label 'keep scrolling for AI' with chevron-down icon is visible in every section as a non-interactive visual affordance",
|
|
"Geist font applied globally via @fontsource/geist",
|
|
"Global CSS variables set: bg=#ffffff, foreground=#0a0a0a, muted=#737373, border=#e5e5e5, sidebar=#fafafa, sidebar-accent=#f5f5f5, primary=#171717, primary-fg=#fafafa",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 4,
|
|
"passes": true,
|
|
"notes": "Completed: electron-store@8 sidebar collapse persistence via settings tRPC router, @fontsource/geist replacing Google Fonts CDN, right-edge 'keep scrolling for AI' label in all views, ESLint fixed with eslint-import-resolver-typescript"
|
|
},
|
|
{
|
|
"id": "US-005",
|
|
"title": "Client tRPC procedures (CRUD)",
|
|
"description": "As a developer, I need tRPC procedures for client and sub-client CRUD so that the UI can create, read, update, and delete hierarchical client records.",
|
|
"acceptanceCriteria": [
|
|
"clients.list returns all clients ordered by name",
|
|
"clients.create accepts { name: string, parentId?: string, industry?: string } and inserts with UUID and createdAt timestamp",
|
|
"clients.update accepts { id: string, name?: string, industry?: string } and updates the record",
|
|
"clients.delete accepts { id: string } and returns an error payload if the client has child clients or projects (does not delete)",
|
|
"clients.deleteWithCascade accepts { id: string } and deletes the client, all descendant clients, and their projects (nulls projectId on orphaned tasks)",
|
|
"All inputs validated with Zod schemas",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 5,
|
|
"passes": true,
|
|
"notes": "Completed: clients.list (ordered by name), clients.create (UUID + createdAt), clients.update (partial), clients.delete (guard returns error payload if children exist), clients.deleteWithCascade (BFS recursive — nulls orphaned tasks.projectId, deletes projects, then clients). All queries use .all()/.run() for drizzle better-sqlite3 sync driver."
|
|
},
|
|
{
|
|
"id": "US-006",
|
|
"title": "Project tRPC procedures (CRUD)",
|
|
"description": "As a developer, I need tRPC procedures for project CRUD so that the UI can create, read, update, and archive projects attached to clients or as standalone.",
|
|
"acceptanceCriteria": [
|
|
"projects.list accepts optional { clientId?: string, includeArchived?: boolean } and returns matching projects",
|
|
"projects.listAll returns all projects (for dropdowns) with id and name only",
|
|
"projects.get accepts { id: string } and returns the full project record",
|
|
"projects.create accepts { name: string, clientId?: string } and inserts with UUID, status='active', createdAt",
|
|
"projects.update accepts { id: string, name?: string, clientId?: string, status?: 'active'|'archived', aiSummary?: string }",
|
|
"projects.delete accepts { id: string } and deletes the project (nulls projectId on its tasks)",
|
|
"All inputs validated with Zod",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 6,
|
|
"passes": true,
|
|
"notes": "Completed: projects.list (filters by clientId + includeArchived via drizzle and()), projects.listAll (id+name only), projects.get (returns null if not found), projects.create (UUID + status='active' + createdAt), projects.update (partial set object), projects.delete (nulls tasks.projectId then deletes project)"
|
|
},
|
|
{
|
|
"id": "US-007",
|
|
"title": "Task tRPC procedures (CRUD + filtering)",
|
|
"description": "As a developer, I need tRPC procedures for task CRUD with search and filter support so that the global Tasks view can query tasks efficiently.",
|
|
"acceptanceCriteria": [
|
|
"tasks.list accepts { projectId?: string, status?: 'todo'|'in_progress'|'done', search?: string, orderBy?: 'dueDate'|'priority'|'createdAt' } and returns matching tasks",
|
|
"tasks.list joins with projects and clients tables to return breadcrumb fields: projectName, clientName, subClientName",
|
|
"tasks.create accepts { title: string, description?: string, status?: string, priority?: string, assignee?: string, dueDate?: number, projectId?: string }",
|
|
"tasks.update accepts { id: string, ...partial task fields }",
|
|
"tasks.delete accepts { id: string }",
|
|
"All inputs validated with Zod",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 7,
|
|
"passes": true,
|
|
"notes": "Completed: tasks.list (LEFT JOIN projects+clients+parentClients for breadcrumb fields, and() filters for projectId/status/search via like(), orderBy CASE for priority), tasks.create (UUID + createdAt + defaults), tasks.update (partial set), tasks.delete. alias() from drizzle-orm/sqlite-core for self-join."
|
|
},
|
|
{
|
|
"id": "US-008",
|
|
"title": "Checkpoint and Note tRPC procedures (CRUD)",
|
|
"description": "As a developer, I need tRPC procedures for checkpoints and notes so that the timeline and notes features have a typed backend.",
|
|
"acceptanceCriteria": [
|
|
"checkpoints.list accepts { projectId?: string } and returns matching checkpoints ordered by date",
|
|
"checkpoints.create accepts { projectId: string, title: string, date: number, isAiSuggested?: number, isApproved?: number }",
|
|
"checkpoints.update accepts { id: string, title?: string, date?: number, isApproved?: number }",
|
|
"checkpoints.delete accepts { id: string }",
|
|
"notes.list accepts { projectId?: string } and returns notes with id, title, createdAt, updatedAt — not content (for performance)",
|
|
"notes.get accepts { id: string } and returns the full note including content",
|
|
"notes.create accepts { title: string, content: string, projectId?: string }",
|
|
"notes.update accepts { id: string, title?: string, content?: string } and always updates updatedAt",
|
|
"notes.delete accepts { id: string }",
|
|
"All inputs validated with Zod",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 8,
|
|
"passes": true,
|
|
"notes": "Completed: checkpoints.list (ordered by date, optional projectId filter), checkpoints.create (UUID + createdAt + defaults for isAiSuggested/isApproved), checkpoints.update (partial set), checkpoints.delete. notes.list (returns id/projectId/title/createdAt/updatedAt — no content), notes.get (full record or null), notes.create (UUID + createdAt + updatedAt), notes.update (partial set, always updates updatedAt), notes.delete."
|
|
},
|
|
{
|
|
"id": "US-009",
|
|
"title": "Client CRUD UI in Projects sidebar",
|
|
"description": "As a user, I want to create, rename, and delete Clients and Sub-Clients from the Projects sidebar so that I can mirror real-world corporate structures.",
|
|
"acceptanceCriteria": [
|
|
"'New Client' button at top of Projects sidebar uses shadcn/ui Button component; creates a top-level client via clients.create tRPC mutation",
|
|
"Each client item has a context menu using shadcn/ui DropdownMenu (triggered by right-click or kebab icon) with items: Rename, New Sub-Client, Delete",
|
|
"Rename activates an inline editable field (shadcn/ui Input) replacing the label; pressing Enter or blurring saves via clients.update",
|
|
"'New Sub-Client' calls clients.create with parentId set to the selected client's id",
|
|
"Delete shows a shadcn/ui AlertDialog confirmation; if the client has children or projects, warns the user and offers cascade-delete option",
|
|
"Tree updates immediately after any mutation without full page reload",
|
|
"All interactive elements use shadcn/ui primitives: install via 'npx shadcn@latest add button input dropdown-menu alert-dialog' before implementing",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 9,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-010",
|
|
"title": "Projects sidebar tree view and project CRUD UI",
|
|
"description": "As a user, I want to see all clients, sub-clients, and projects in a collapsible tree and manage projects from the Projects section.",
|
|
"acceptanceCriteria": [
|
|
"Tree renders hierarchy: Client (folder icon, bold) → Sub-Client (folder icon) → Project (circle icon); use shadcn/ui Collapsible for expand/collapse nodes",
|
|
"Clients and sub-clients have expand/collapse chevrons that work independently",
|
|
"Search input at the top of the Projects sidebar uses shadcn/ui Input (via SidebarInput from the sidebar component); filters the tree in real-time by name",
|
|
"'+ New Project' shadcn/ui Button opens a shadcn/ui Dialog with: shadcn/ui Input for name + shadcn/ui Select (searchable) for optional client",
|
|
"Projects with no client appear under 'Internal / No Client' group",
|
|
"Project context menu uses shadcn/ui DropdownMenu with items: Edit (re-parent to different client), Archive/Unarchive, Delete",
|
|
"Archived projects hidden by default; a shadcn/ui Switch or toggle reveals them",
|
|
"Clicking a project node loads the Project Detail panel in the right pane",
|
|
"Active project highlighted in tree",
|
|
"Install shadcn/ui components via 'npx shadcn@latest add collapsible dialog select switch' before implementing",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 10,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-011",
|
|
"title": "Global Tasks view UI",
|
|
"description": "As a user, I want a global task list where I can create, filter, search, and update tasks across all projects in one place.",
|
|
"acceptanceCriteria": [
|
|
"4 stat cards using shadcn/ui Card (Card, CardHeader, CardTitle, CardContent) at top: Total Tasks, To Do, In Progress, Completed — each with a Lucide icon and count, reactively updated via tasks.list queries",
|
|
"Search uses shadcn/ui Input; filters tasks by title or description (case-insensitive, 300ms debounce)",
|
|
"Status filter uses shadcn/ui Tabs (Tabs, TabsList, TabsTrigger): All | To Do | In Progress | Completed",
|
|
"'Order by' uses shadcn/ui DropdownMenu: Due Date | Priority | Created Date",
|
|
"Task rows display: shadcn/ui Checkbox, title (bold 14px), description (muted 14px), priority chip using shadcn/ui Badge (HIGH=destructive variant, MEDIUM=secondary variant, LOW=outline variant with green), due date chip (calendar icon + 'Due Mon DD'), breadcrumb (Client > Sub-Client > Project, chevron-separated via shadcn/ui Breadcrumb if available), assignee (person icon + name)",
|
|
"Completed task rows have green-tinted background (#f0fdf4 or similar)",
|
|
"Clicking the shadcn/ui Checkbox calls tasks.update to set status='done' (or back to 'todo') immediately",
|
|
"'New Task' shadcn/ui Button opens a shadcn/ui Dialog modal: shadcn/ui Input for title (required), Textarea for description, Select for priority, Popover+Calendar for due date, Select for project (optional searchable), Input for assignee (optional)",
|
|
"Install shadcn/ui components via 'npx shadcn@latest add card tabs checkbox badge dialog textarea select popover calendar' before implementing",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 11,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-012",
|
|
"title": "GanttChart SVG component and global Timeline view",
|
|
"description": "As a user, I want to view and create timeline checkpoints on a Gantt-style view so that I have full control over project milestones.",
|
|
"acceptanceCriteria": [
|
|
"Reusable GanttChart component accepts { checkpoints: Checkpoint[], startDate: Date, endDate: Date } props",
|
|
"Component renders a custom SVG: month labels on the X axis, a horizontal baseline <line>, and <circle> dots for each checkpoint positioned by date",
|
|
"Dot fill: dark (#171717) = isApproved=1 + status todo, green (#16a34a) = done/approved, dashed outline = isApproved=0 (pending AI suggestion)",
|
|
"A vertical 'Today' marker line rendered at the current date",
|
|
"Component uses ResizeObserver for responsive SVG width",
|
|
"Clicking a checkpoint dot opens a shadcn/ui Popover with: title, formatted date, and a shadcn/ui Button (variant=destructive, size=sm) for Delete (calls checkpoints.delete)",
|
|
"Global Timeline route (/timeline) renders GanttChart with all checkpoints from all projects, color-coded or grouped by project",
|
|
"'+ Add' shadcn/ui Button opens a shadcn/ui Dialog: shadcn/ui Input for title (required), Popover+Calendar for date picker (required), Select for project dropdown (required in global view)",
|
|
"Install shadcn/ui components via 'npx shadcn@latest add popover calendar' before implementing (button, dialog, input, select already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 12,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-013",
|
|
"title": "Project Detail view — layout, breadcrumb, stat cards, AI summary",
|
|
"description": "As a user, I want a project detail panel showing breadcrumb navigation, project name, stat cards, and an AI summary card.",
|
|
"acceptanceCriteria": [
|
|
"Right panel renders when a project is selected in the Projects tree",
|
|
"Breadcrumb at top uses shadcn/ui Breadcrumb (Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbSeparator) showing Client > Sub-Client path",
|
|
"Project name renders as H1 below the breadcrumb",
|
|
"3 stat cards using shadcn/ui Card displayed horizontally: Notes (count from notes.list), Tasks Complete (done/total fraction from tasks.list), Checkpoints (approved/total fraction from checkpoints.list)",
|
|
"AI Project Summary card uses shadcn/ui Card with sparkle (sparkles) Lucide icon + placeholder text 'AI summary will appear here' when project.aiSummary is null/empty",
|
|
"When project.aiSummary is populated, the card displays the AI-generated text instead",
|
|
"Install shadcn/ui components via 'npx shadcn@latest add breadcrumb' before implementing (card already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 13,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-014",
|
|
"title": "Kanban board in Project Detail",
|
|
"description": "As a user, I want a Kanban board inside the project detail view with drag-and-drop task management between status columns.",
|
|
"acceptanceCriteria": [
|
|
"@hello-pangea/dnd installed; DragDropContext wraps 3 Droppable columns: To Do | In Progress | Completed",
|
|
"Each task card is a Draggable wrapped in a shadcn/ui Card rendering: title, description (truncated), priority as shadcn/ui Badge, due date chip, assignee string",
|
|
"Dragging a card to another column calls tasks.update({ id, status }) via tRPC and the UI updates immediately (optimistic or on success)",
|
|
"'+ Add' shadcn/ui Button (variant=ghost, size=sm) in each column header opens the shadcn/ui Dialog new-task modal with the column's status pre-selected",
|
|
"Columns show a task count in their header using shadcn/ui Badge (variant=secondary)",
|
|
"All card content uses shadcn/ui primitives: Card, Badge, Button (already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 14,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-015",
|
|
"title": "Inline project timeline and notes list in Project Detail",
|
|
"description": "As a user, I want to see the project's Gantt timeline and a list of its notes within the project detail scrollable view.",
|
|
"acceptanceCriteria": [
|
|
"Project Detail view includes a 'Project Timeline' section using the GanttChart component (from US-012) scoped to the current project's checkpoints",
|
|
"'+ Add' shadcn/ui Button (variant=outline, size=sm) in the timeline section header opens the add-checkpoint shadcn/ui Dialog with the project pre-selected",
|
|
"Notes section below Kanban shows a flat list using shadcn/ui Separator between rows: each row has note title + formatted createdAt date",
|
|
"'+ Add' shadcn/ui Button in notes header calls notes.create with a default title and navigates to /notes/:noteId",
|
|
"Clicking a note title navigates to /notes/:noteId",
|
|
"All buttons/dialogs use shadcn/ui components (already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 15,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-016",
|
|
"title": "Milkdown note editor",
|
|
"description": "As a user, I want a full-screen Markdown editor for each note so that I can write rich content without leaving the app.",
|
|
"acceptanceCriteria": [
|
|
"@milkdown/react and @milkdown/preset-commonmark installed; Milkdown editor renders at route /notes/:noteId",
|
|
"Supported Markdown: headings (H1-H6), bold, italic, inline code, code blocks, bullet lists, ordered lists, blockquotes",
|
|
"Note title editable as a shadcn/ui Input (variant borderless/ghost style) at the top of the page (separate from Milkdown content area)",
|
|
"Content auto-saves to SQLite via notes.update on Milkdown onChange event, debounced 500ms",
|
|
"Unsaved indicator shown using shadcn/ui Badge (variant=secondary, text 'Saving...') next to the title while save is pending",
|
|
"Back button uses shadcn/ui Button (variant=ghost, size=icon) with ArrowLeft Lucide icon; navigates to the previous route",
|
|
"All UI chrome uses shadcn/ui components (already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 16,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-017",
|
|
"title": "Fluid Curtain pull-down animation",
|
|
"description": "As a user, I want to pull down from the top of any view to slide the app panel off-screen and reveal the AI chat layer beneath.",
|
|
"acceptanceCriteria": [
|
|
"framer-motion useMotionValue + useSpring (stiffness: 300, damping: 30) controls a 'y' CSS transform on the main app panel wrapper",
|
|
"Trigger 1: wheel event listener at document level — when the current route's scroll position is at 0 and deltaY < 0 (overscroll up), animate panel y from 0 to viewport height",
|
|
"Trigger 2: Cmd/Ctrl+K keyboard shortcut toggles curtain open (y = viewport height) and closed (y = 0)",
|
|
"AI chat view is rendered as a fixed full-screen layer behind the sliding panel and becomes fully visible when panel slides down",
|
|
"App panel remains mounted during animation (no unmount/remount, no state loss)",
|
|
"Returning from chat: wheel event with deltaY > 0 at chat-bottom OR Cmd/Ctrl+K slides panel back to y = 0",
|
|
"Right-edge vertical 'keep scrolling for AI' label with chevron-down is visible in every section (non-interactive, visual hint only)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 17,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-018",
|
|
"title": "GitHub Copilot SDK setup and keytar token storage",
|
|
"description": "As a developer, I need the GitHub Copilot SDK initialized in the main process with secure OS keychain token storage so that AI features can authenticate.",
|
|
"acceptanceCriteria": [
|
|
"keytar installed and imported in main process only (not renderer)",
|
|
"ai.setToken tRPC mutation accepts { token: string } and stores it via keytar.setPassword('adiuva', 'copilot-token', token)",
|
|
"ai.hasToken tRPC query returns a boolean indicating whether a token is stored",
|
|
"On app start, main process reads the token from keychain and initializes the GitHub Copilot SDK client",
|
|
"Settings dialog uses shadcn/ui Dialog (DialogTrigger as a SidebarMenuButton with Settings/gear icon in the sidebar footer); dialog content uses shadcn/ui Input for token paste + shadcn/ui Button to save via ai.setToken",
|
|
"If no token is stored, AI-dependent features display a prompt using shadcn/ui Card with a shadcn/ui Button linking to the Settings dialog instead of throwing an error",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 18,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-019",
|
|
"title": "@Orchestrator agent with intent routing",
|
|
"description": "As a developer, I need an Orchestrator agent that receives user messages, reads intent, and routes to the correct specialist agent.",
|
|
"acceptanceCriteria": [
|
|
"ai.chat tRPC procedure accepts { message: string, context: { type: 'global' | 'project', projectId?: string } }",
|
|
"@Orchestrator system prompt instructs the model to use one of three routing tool calls: route_to_project (when context is a project), route_to_knowledge (for cross-project questions), or route_to_general (for everything else)",
|
|
"For project-scoped context, Orchestrator invokes @ProjectAgent logic and returns its response",
|
|
"For global context, Orchestrator answers from task/project summaries directly",
|
|
"Streaming tokens returned to renderer incrementally (use tRPC subscription or async generator pattern)",
|
|
"SDK auth errors and timeouts caught; procedure returns { error: string } for user-facing display",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 19,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-020",
|
|
"title": "Context-scoped AI chat UI",
|
|
"description": "As a user, I want the AI chat (revealed by the Fluid Curtain) to display a context header, support message input, and stream AI responses.",
|
|
"acceptanceCriteria": [
|
|
"Chat panel shows a context header using shadcn/ui Badge (variant=outline): 'Chatting about: [Project Name]' when opened from a project detail view, or 'Global workspace' when opened from other sections",
|
|
"Chat input box uses shadcn/ui Textarea: white background, border #d4d4d4, shadow-lg, min-height 109px, placeholder 'Ask me anything...'; Send uses shadcn/ui Button (black bg, Send Lucide icon + 'Send' label) anchored bottom-right",
|
|
"User messages appear as right-aligned message bubbles using shadcn/ui Card; AI responses as left-aligned Cards",
|
|
"Streaming: AI response tokens appended to the current AI bubble as they arrive from ai.chat",
|
|
"A loading spinner or pulsing indicator (shadcn/ui Skeleton) shown while waiting for first token",
|
|
"If ai.chat returns { error }, display the error message in a shadcn/ui Card with destructive border styling",
|
|
"Chat history is session-only — cleared when the curtain closes or the app restarts",
|
|
"Install shadcn/ui components via 'npx shadcn@latest add textarea' before implementing (card, badge, button, skeleton already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 20,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-021",
|
|
"title": "@ProjectAgent with project action tools",
|
|
"description": "As a user, I want the AI to answer project-specific questions and take actions like adding tasks, summarizing the project, and suggesting checkpoints.",
|
|
"acceptanceCriteria": [
|
|
"read_project_notes tool: fetches all notes for the scoped projectId from SQLite and returns combined content to the model",
|
|
"add_task tool: creates a task in the project via tasks.create and confirms with 'Task added: [title]' in the chat response",
|
|
"get_summary tool: calls the SDK to generate a 2-3 sentence summary of the project based on its notes and tasks, then calls projects.update to persist the result in project.aiSummary",
|
|
"suggest_checkpoints tool: returns a JSON array of { title: string, date: string } proposed checkpoints based on date-anchored commitments found in notes",
|
|
"@Orchestrator routes project-context messages to @ProjectAgent",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 21,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-022",
|
|
"title": "LanceDB vector store setup and note embedding pipeline",
|
|
"description": "As a developer, I need notes embedded into LanceDB so that semantic search across all project notes is possible.",
|
|
"acceptanceCriteria": [
|
|
"vectordb (LanceDB Node.js binding) installed and initialized in main process only; vector DB stored at app.getPath('userData')/vectors/",
|
|
"After notes.create or notes.update, note content is embedded via the GitHub Copilot SDK embeddings endpoint and upserted in LanceDB with metadata: { noteId, projectId, content }",
|
|
"On first app startup, a migration routine checks if the 'notes' LanceDB table exists; if not, embeds all existing SQLite notes and populates LanceDB",
|
|
"Embedding errors are caught and logged to console (console.error) but do not reject the notes.update/create promise",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 22,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-023",
|
|
"title": "@KnowledgeAgent semantic search across all projects",
|
|
"description": "As a user, I want to ask questions that retrieve semantically relevant content from all past project notes regardless of project scope.",
|
|
"acceptanceCriteria": [
|
|
"vector_search_all tool accepts a query string and performs a LanceDB similarity search returning the top-5 results",
|
|
"Each result includes: noteId, note title (joined from SQLite), projectId, project name (joined from SQLite), and matched text excerpt",
|
|
"@Orchestrator routes cross-project knowledge queries to @KnowledgeAgent",
|
|
"Chat response includes inline citations in the format: 'From: [Project Name] — [Note Title]'",
|
|
"Typecheck passes"
|
|
],
|
|
"priority": 23,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-024",
|
|
"title": "AI checkpoint suggestions UI",
|
|
"description": "As a user, I want the AI to suggest timeline checkpoints from my meeting notes, which I can approve or reject directly in the timeline.",
|
|
"acceptanceCriteria": [
|
|
"'Suggest checkpoints' shadcn/ui Button (variant=outline, sparkles Lucide icon) in the Project Detail timeline header calls ai.chat with a suggest_checkpoints intent for the current project",
|
|
"Suggested checkpoints returned by @ProjectAgent are inserted into the checkpoints table via checkpoints.create with isAiSuggested=1, isApproved=0",
|
|
"Pending suggestions appear as shadcn/ui Card components (with dashed border via className 'border-dashed') above or below the GanttChart in the Project Detail timeline section",
|
|
"'Approve' shadcn/ui Button (variant=default, size=sm) on each card calls checkpoints.update({ id, isApproved: 1 }); the checkpoint then appears as a normal dot on the Gantt",
|
|
"'Reject' shadcn/ui Button (variant=ghost, size=sm) calls checkpoints.delete({ id }) and removes the card",
|
|
"All UI uses shadcn/ui components (already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 24,
|
|
"passes": false,
|
|
"notes": ""
|
|
},
|
|
{
|
|
"id": "US-025",
|
|
"title": "Home dashboard — AI daily brief and suggestion chips",
|
|
"description": "As a user, I want the Home screen to greet me with an AI-generated daily brief and pre-populated suggestion chips for quick queries.",
|
|
"acceptanceCriteria": [
|
|
"Greeting rendered as '✦ Hello, {name}' in Geist Semibold 30px with -1px letter-spacing; name sourced from electron-store (defaults to 'there' if not set)",
|
|
"Top-right corner stat chip uses shadcn/ui Badge (variant=secondary) showing 'N Task due' where N = count of tasks with dueDate on or before end of today",
|
|
"On app open, ai.chat called with global context to generate a daily brief paragraph highlighting tasks due today/this week and recent project activity",
|
|
"Brief displayed below greeting in a shadcn/ui Card; bold key phrases rendered as <strong> (model wraps them in **markdown bold**)",
|
|
"4 suggestion chips rendered in a 4-column flex row below the chat box using shadcn/ui Button (variant=outline); each chip has a Lucide icon + short prompt text",
|
|
"Clicking a suggestion chip populates the chat input with the chip's prompt text",
|
|
"Chat box uses shadcn/ui Textarea: white bg, border #d4d4d4, shadow-lg, min-height 109px, placeholder 'Ask me anything...'; Send uses shadcn/ui Button (black bg) bottom-right",
|
|
"All UI uses shadcn/ui components (already installed)",
|
|
"Typecheck passes",
|
|
"Verify in browser using dev-browser skill"
|
|
],
|
|
"priority": 25,
|
|
"passes": false,
|
|
"notes": ""
|
|
}
|
|
]
|
|
}
|