diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md deleted file mode 100644 index 8f7f8d7..0000000 --- a/.claude/CLAUDE.md +++ /dev/null @@ -1,110 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Commands - -```bash -# Development -source ~/.nvm/nvm.sh && npm start # Start Electron app with hot-reload - -# Build & Package -source ~/.nvm/nvm.sh && npm run make # Build distributable packages -source ~/.nvm/nvm.sh && npm run package # Package without making installers - -# Lint -source ~/.nvm/nvm.sh && npm run lint # ESLint over .ts/.tsx files - -# Database migrations (Drizzle) -source ~/.nvm/nvm.sh && npx drizzle-kit generate # Generate migration from schema changes -source ~/.nvm/nvm.sh && npx drizzle-kit push # Push schema directly (dev only) -``` - -There is no test suite currently. - -## Architecture Overview - -Adiuva is a local-first Electron desktop app. The three Electron processes communicate via a custom tRPC↔IPC bridge (the public `electron-trpc` package is incompatible with tRPC v11, so a custom implementation is used). - -### Process Boundaries - -``` -Renderer (React) ──ipcLink──► Preload (contextBridge) ──IPC──► Main (tRPC router + SQLite) -``` - -1. **Main process** (`src/main/`) — Node.js, owns the database and all business logic - - `index.ts` — Window creation, app lifecycle - - `ipc.ts` — Custom handler that bridges `ipcMain` to tRPC procedures - - `router/index.ts` — All tRPC routers (clients, projects, tasks, checkpoints, notes, settings, ai) - - `db/index.ts` — Drizzle + better-sqlite3, WAL mode, singleton `getDb()` - - `db/schema.ts` — All table definitions (clients, projects, tasks, checkpoints, notes) - - `store.ts` — electron-store for persistent UI settings (e.g., `sidebarCollapsed`) - -2. **Preload** (`src/preload/trpc.ts`) — Exposes `window.electronTRPC` with `sendMessage()` / `onMessage()` - -3. **Renderer** (`src/renderer/`) — React 19, never accesses Node APIs directly - - `lib/ipcLink.ts` — Custom TRPCLink that routes calls through `window.electronTRPC` - - `lib/trpc.ts` — `createTRPCReact()` typed client - - `index.tsx` — QueryClient + tRPC + Router providers - - All data access is through `trpc.*.*useQuery()` / `trpc.*.*.useMutation()` - -### Routing - -File-based routing via TanStack Router. Add a file to `src/renderer/routes/` and the route tree (`src/renderer/routeTree.gen.ts`) is auto-regenerated by the Vite plugin on next `npm start`. Routes: -- `__root.tsx` — Root layout wrapping everything in `AppShell` -- `index.tsx`, `tasks.tsx`, `timeline.tsx`, `projects.tsx` - -### Database - -Schema lives in `src/main/db/schema.ts`. Migrations are in `src/main/db/migrations/`. The DB is created in Electron's `userData` directory as `adiuva.db`. On startup, `initDb()` runs non-destructive migrations (CREATE TABLE IF NOT EXISTS). - -To add a new table or column: edit `schema.ts`, run `drizzle-kit generate`, then `drizzle-kit push` (dev) or commit the migration file. - -### Adding a New Feature (end-to-end pattern) - -1. **Schema** — Add table/columns to `src/main/db/schema.ts` -2. **Router** — Add a tRPC sub-router in `src/main/router/index.ts`, merge it into `appRouter` -3. **Types** — `AppRouter` is exported from `src/main/router/index.ts` and imported in `src/renderer/lib/trpc.ts` — types flow automatically -4. **UI** — Create components under `src/renderer/components//`, use `trpc.*.*useQuery()` for data - -### AI Subsystem (`src/main/ai/`) - -LangGraph-based agentic system with pluggable LLM providers (OpenAI, Anthropic, GitHub Copilot). - -**Orchestrator** (`orchestrator.ts`): Classifies user intent → routes to one of three specialist agents: -- **Project agent** — project-scoped Q&A with tools: `read_project_notes`, `add_task`, `get_summary`, `suggest_checkpoints`, `suggest_tasks` -- **Knowledge agent** — cross-project semantic search via `vector_search_all` -- **General agent** — workspace-wide `add_task` - -Tool-calling strategy differs by provider: OpenAI/Anthropic use LangChain `bindTools()` + ToolMessage loop (max 5 iterations); Copilot uses SDK-native tools (loop handled internally). - -**Streaming**: Orchestrator calls `sendStreamChunk(sender, token, done)` over IPC channel `'ai:stream'`. Renderer subscribes via `window.electronAI.onStreamChunk()` in `AIChatPanel.tsx`. `` blocks are filtered before sending to renderer. - -**Provider factory** (`llm.ts`): `gpt-4o-mini` (OpenAI), `claude-sonnet-4-20250514` (Anthropic), or ChatCopilot wrapper — all with `temperature: 0.3` and streaming enabled. - -**Token storage** (`token.ts`) — three-tier fallback: -1. keytar (OS keychain) — preferred, encrypted per-user -2. electron-store + `safeStorage` — encrypted at rest -3. Plain electron-store — WSL fallback - -Keytar service name is `'adiuva'`. Once keytar fails, `keytarFailed` flag skips it for the session. - -**AI approval pattern**: Tasks and checkpoints have `isAiSuggested` (bool) and `isApproved` (bool) columns. AI-suggested items appear in the UI pending user approval before being treated as real records. - -### Vector Embeddings (`src/main/db/vectordb.ts`) - -LanceDB stored in `{userData}/vectors/`. Table schema: `{ id, projectId, content, vector }`. Vectors are 1536-dimensional (`text-embedding-3-small`). Embeddings use a priority chain: Copilot CLI token → OpenAI token. - -- Note create/update fires `upsertNoteEmbedding()` (fire-and-forget, errors swallowed) -- `migrateNotesIfNeeded()` backfills existing notes on first startup -- `searchNotes(query, limit=5)` is called by the Knowledge agent tool - -### Key Config Notes - -- Vite configs use `.mts` extension (not `.ts`) to avoid ESM/CJS conflicts with electron-forge's externalize-deps plugin -- `@/*` path alias resolves to `src/renderer/*` (TypeScript + Vite + shadcn/ui all share this alias) -- shadcn/ui style: **new-york**, base color: **neutral** -- Icons: **lucide-react** throughout — do not introduce other icon libraries -- Tailwind 4 (not 3) — use CSS variable theming via `globals.css`, not `tailwind.config.js` -- Notes use Milkdown (`@milkdown/crepe`) as the markdown editor (`src/renderer/components/notes/MilkdownEditor.tsx`) -- Routes: `index`, `tasks`, `timeline`, `projects`, `notes.$noteId` (note ID is a URL param) \ No newline at end of file diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index b3ec810..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "enabledMcpjsonServers": [ - "shadcn" - ], - "enableAllProjectMcpServers": true -} diff --git a/.gitignore b/.gitignore index 128616c..c17f069 100644 --- a/.gitignore +++ b/.gitignore @@ -92,5 +92,5 @@ typings/ out/ # local config files -.claude/ .vscode/ +.claude/ diff --git a/.vscode/mcp.json b/.vscode/mcp.json deleted file mode 100644 index 6716ff9..0000000 --- a/.vscode/mcp.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "servers": { - "shadcn": { - "command": "npx", - "args": [ - "shadcn@latest", - "mcp" - ] - } - } -}