From c30cde242aacc7867e5e34c0f6dfa2f1e209706e Mon Sep 17 00:00:00 2001 From: Shirone Date: Tue, 27 Jan 2026 13:48:24 +0100 Subject: [PATCH] docs: map existing codebase - STACK.md - Technologies and dependencies - ARCHITECTURE.md - System design and patterns - STRUCTURE.md - Directory layout - CONVENTIONS.md - Code style and patterns - TESTING.md - Test structure - INTEGRATIONS.md - External services - CONCERNS.md - Technical debt and issues --- .planning/codebase/ARCHITECTURE.md | 234 +++++++++++++++++ .planning/codebase/CONCERNS.md | 245 ++++++++++++++++++ .planning/codebase/CONVENTIONS.md | 255 +++++++++++++++++++ .planning/codebase/INTEGRATIONS.md | 232 +++++++++++++++++ .planning/codebase/STACK.md | 230 +++++++++++++++++ .planning/codebase/STRUCTURE.md | 340 +++++++++++++++++++++++++ .planning/codebase/TESTING.md | 389 +++++++++++++++++++++++++++++ 7 files changed, 1925 insertions(+) create mode 100644 .planning/codebase/ARCHITECTURE.md create mode 100644 .planning/codebase/CONCERNS.md create mode 100644 .planning/codebase/CONVENTIONS.md create mode 100644 .planning/codebase/INTEGRATIONS.md create mode 100644 .planning/codebase/STACK.md create mode 100644 .planning/codebase/STRUCTURE.md create mode 100644 .planning/codebase/TESTING.md diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md new file mode 100644 index 00000000..9e1265e9 --- /dev/null +++ b/.planning/codebase/ARCHITECTURE.md @@ -0,0 +1,234 @@ +# Architecture + +**Analysis Date:** 2026-01-27 + +## Pattern Overview + +**Overall:** Monorepo with layered client-server architecture (Electron-first) and pluggable provider abstraction for AI models. + +**Key Characteristics:** + +- Event-driven communication via WebSocket between frontend and backend +- Multi-provider AI model abstraction layer (Claude, Cursor, Codex, Gemini, OpenCode, Copilot) +- Feature-centric workflow stored in `.automaker/` directories +- Isolated git worktree execution for each feature +- State management through Zustand stores with API persistence + +## Layers + +**Presentation Layer (UI):** + +- Purpose: React 19 Electron/web frontend with TanStack Router file-based routing +- Location: `apps/ui/src/` +- Contains: Route components, view pages, custom React hooks, Zustand stores, API client +- Depends on: @automaker/types, @automaker/utils, HTTP API backend +- Used by: Electron main process (desktop), web browser (web mode) + +**API Layer (Server):** + +- Purpose: Express 5 backend exposing RESTful and WebSocket endpoints +- Location: `apps/server/src/` +- Contains: Route handlers, business logic services, middleware, provider adapters +- Depends on: @automaker/types, @automaker/utils, @automaker/platform, Claude Agent SDK +- Used by: UI frontend via HTTP/WebSocket + +**Service Layer (Server):** + +- Purpose: Business logic and domain operations +- Location: `apps/server/src/services/` +- Contains: AgentService, FeatureLoader, AutoModeService, SettingsService, DevServerService, etc. +- Depends on: Providers, secure filesystem, feature storage +- Used by: Route handlers + +**Provider Abstraction (Server):** + +- Purpose: Unified interface for different AI model providers +- Location: `apps/server/src/providers/` +- Contains: ProviderFactory, specific provider implementations (ClaudeProvider, CursorProvider, CodexProvider, GeminiProvider, OpencodeProvider, CopilotProvider) +- Depends on: @automaker/types, provider SDKs +- Used by: AgentService + +**Shared Library Layer:** + +- Purpose: Type definitions and utilities shared across apps +- Location: `libs/` +- Contains: @automaker/types, @automaker/utils, @automaker/platform, @automaker/prompts, @automaker/model-resolver, @automaker/dependency-resolver, @automaker/git-utils, @automaker/spec-parser +- Depends on: None (types has no external deps) +- Used by: All apps and services + +## Data Flow + +**Feature Execution Flow:** + +1. User creates/updates feature via UI (`apps/ui/src/`) +2. UI sends HTTP request to backend (`POST /api/features`) +3. Server route handler invokes FeatureLoader to persist to `.automaker/features/{featureId}/` +4. When executing, AgentService loads feature, creates isolated git worktree via @automaker/git-utils +5. AgentService invokes ProviderFactory to get appropriate AI provider (Claude, Cursor, etc.) +6. Provider executes with context from CLAUDE.md files via @automaker/utils loadContextFiles() +7. Server emits events via EventEmitter throughout execution +8. Events stream to frontend via WebSocket +9. UI updates stores and renders real-time progress +10. Feature results persist back to `.automaker/features/` with generated agent-output.md + +**State Management:** + +**Frontend State (Zustand):** + +- `app-store.ts`: Global app state (projects, features, settings, boards, themes) +- `setup-store.ts`: First-time setup wizard flow +- `ideation-store.ts`: Ideation feature state +- `test-runners-store.ts`: Test runner configurations +- Settings now persist via API (`/api/settings`) rather than localStorage (see use-settings-sync.ts) + +**Backend State (Services):** + +- SettingsService: Global and project-specific settings (in-memory with file persistence) +- AgentService: Active agent sessions and conversation history +- FeatureLoader: Feature data model operations +- DevServerService: Development server logs +- EventHistoryService: Persists event logs for replay + +**Real-Time Updates (WebSocket):** + +- Server EventEmitter emits TypedEvent (type + payload) +- WebSocket handler subscribes to events and broadcasts to all clients +- Frontend listens on multiple WebSocket subscriptions and updates stores + +## Key Abstractions + +**Feature:** + +- Purpose: Represents a development task/story with rich metadata +- Location: @automaker/types → `libs/types/src/feature.ts` +- Fields: id, title, description, status, images, tasks, priority, etc. +- Stored: `.automaker/features/{featureId}/feature.json` + +**Provider:** + +- Purpose: Abstracts different AI model implementations +- Location: `apps/server/src/providers/{provider}-provider.ts` +- Interface: Common execute() method with consistent message format +- Implementations: Claude, Cursor, Codex, Gemini, OpenCode, Copilot +- Factory: ProviderFactory picks correct provider based on model ID + +**Event:** + +- Purpose: Real-time updates streamed to frontend +- Location: @automaker/types → `libs/types/src/event.ts` +- Format: { type: EventType, payload: unknown } +- Examples: agent-started, agent-step, agent-complete, feature-updated, etc. + +**AgentSession:** + +- Purpose: Represents a conversation between user and AI agent +- Location: @automaker/types → `libs/types/src/session.ts` +- Contains: Messages (user + assistant), metadata, creation timestamp +- Stored: `{DATA_DIR}/agent-sessions/{sessionId}.json` + +**Settings:** + +- Purpose: Configuration for global and per-project behavior +- Location: @automaker/types → `libs/types/src/settings.ts` +- Stored: Global in `{DATA_DIR}/settings.json`, per-project in `.automaker/settings.json` +- Service: SettingsService in `apps/server/src/services/settings-service.ts` + +## Entry Points + +**Server:** + +- Location: `apps/server/src/index.ts` +- Triggers: `npm run dev:server` or Docker startup +- Responsibilities: + - Initialize Express app with middleware + - Create shared EventEmitter for WebSocket streaming + - Bootstrap services (SettingsService, AgentService, FeatureLoader, etc.) + - Mount API routes at `/api/*` + - Create WebSocket servers for agent streaming and terminal sessions + - Load and apply user settings (log level, request logging, etc.) + +**UI (Web):** + +- Location: `apps/ui/src/main.ts` (Vite entry), `apps/ui/src/app.tsx` (React component) +- Triggers: `npm run dev:web` or `npm run build` +- Responsibilities: + - Initialize Zustand stores from API settings + - Setup React Router with TanStack Router + - Render root layout with sidebar and main content area + - Handle authentication via verifySession() + +**UI (Electron):** + +- Location: `apps/ui/src/main.ts` (Vite entry), `apps/ui/electron/main-process.ts` (Electron main process) +- Triggers: `npm run dev:electron` +- Responsibilities: + - Launch local server via node-pty + - Create native Electron window + - Bridge IPC between renderer and main process + - Provide file system access via preload.ts APIs + +## Error Handling + +**Strategy:** Layered error classification and user-friendly messaging + +**Patterns:** + +**Backend Error Handling:** + +- Errors classified via `classifyError()` from @automaker/utils +- Classification: ParseError, NetworkError, AuthenticationError, RateLimitError, etc. +- Response format: `{ success: false, error: { type, message, code }, details? }` +- Example: `apps/server/src/lib/error-handler.ts` + +**Frontend Error Handling:** + +- HTTP errors caught by api-fetch.ts with retry logic +- WebSocket disconnects trigger reconnection with exponential backoff +- Errors shown in toast notifications via `sonner` library +- Validation errors caught and displayed inline in forms + +**Agent Execution Errors:** + +- AgentService wraps provider calls in try-catch +- Aborts handled specially via `isAbortError()` check +- Rate limit errors trigger cooldown before retry +- Model-specific errors mapped to user guidance + +## Cross-Cutting Concerns + +**Logging:** + +- Framework: @automaker/utils createLogger() +- Pattern: `const logger = createLogger('ModuleName')` +- Levels: ERROR, WARN, INFO, DEBUG (configurable via settings) +- Output: stdout (dev), files (production) + +**Validation:** + +- File path validation: @automaker/platform initAllowedPaths() enforces restrictions +- Model ID validation: @automaker/model-resolver resolveModelString() +- JSON schema validation: Manual checks in route handlers (no JSON schema lib) +- Authentication: Session token validation via validateWsConnectionToken() + +**Authentication:** + +- Frontend: Session token stored in httpOnly cookie +- Backend: authMiddleware checks token on protected routes +- WebSocket: validateWsConnectionToken() for upgrade requests +- Providers: API keys stored encrypted in `{DATA_DIR}/credentials.json` + +**Internationalization:** + +- Not detected - strings are English-only + +**Performance:** + +- Code splitting: File-based routing via TanStack Router +- Lazy loading: React.lazy() in route components +- Caching: React Query for HTTP requests (query-keys.ts defines cache strategy) +- Image optimization: Automatic base64 encoding for agent context +- State hydration: Settings loaded once at startup, synced via API + +--- + +_Architecture analysis: 2026-01-27_ diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md new file mode 100644 index 00000000..bd573015 --- /dev/null +++ b/.planning/codebase/CONCERNS.md @@ -0,0 +1,245 @@ +# Codebase Concerns + +**Analysis Date:** 2026-01-27 + +## Tech Debt + +**Loose Type Safety in Error Handling:** + +- Issue: Multiple uses of `as any` type assertions bypass TypeScript safety, particularly in error context handling and provider responses +- Files: `apps/server/src/providers/claude-provider.ts` (lines 318-322), `apps/server/src/lib/error-handler.ts`, `apps/server/src/routes/settings/routes/update-global.ts` +- Impact: Errors could have unchecked properties; refactoring becomes risky without compiler assistance +- Fix approach: Replace `as any` with proper type guards and discriminated unions; create helper functions for safe property access + +**Missing Test Coverage for Critical Services:** + +- Issue: Several core services explicitly excluded from test coverage thresholds due to integration complexity +- Files: `apps/server/vitest.config.ts` (line 22), explicitly excluded: `claude-usage-service.ts`, `mcp-test-service.ts`, `cli-provider.ts`, `cursor-provider.ts` +- Impact: Usage tracking, MCP integration, and CLI detection could break undetected; regression detection is limited +- Fix approach: Create integration test fixtures for CLI providers; mock MCP SDK for mcp-test-service tests; add usage tracking unit tests with mocked API calls + +**Unused/Stub TODO Item Processing:** + +- Issue: TodoWrite tool implementation exists but is partially integrated; tool name constants scattered across codex provider +- Files: `apps/server/src/providers/codex-tool-mapping.ts`, `apps/server/src/providers/codex-provider.ts` +- Impact: Todo list updates may not synchronize properly with all providers; unclear which providers support TodoWrite +- Fix approach: Consolidate tool name constants; add provider capability flags for todo support + +**Electron Electron.ts Size and Complexity:** + +- Issue: Single 3741-line file handles all Electron IPC, native bindings, and communication +- Files: `apps/ui/src/lib/electron.ts` +- Impact: Difficult to test; hard to isolate bugs; changes require full testing of all features; potential memory overhead from monolithic file +- Fix approach: Split by responsibility (IPC, window management, file operations, debug tools); create separate bridge layers + +## Known Bugs + +**API Key Management Incomplete for Gemini:** + +- Symptoms: Gemini API key verification endpoint not implemented despite other providers having verification +- Files: `apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts` (line 122) +- Trigger: User tries to verify Gemini API key in settings +- Workaround: Key verification skipped for Gemini; settings page still accepts and stores key + +**Orphaned Features Detection Vulnerable to False Negatives:** + +- Symptoms: Features marked as orphaned when branch matching logic doesn't account for all scenarios +- Files: `apps/server/src/services/auto-mode-service.ts` (lines 5714-5773) +- Trigger: Features that were manually switched branches or rebased +- Workaround: Manual cleanup via feature deletion; branch comparison is basic name matching only + +**Terminal Themes Incomplete:** + +- Symptoms: Light theme themes (solarizedlight, github) map to same generic lightTheme; no dedicated implementations +- Files: `apps/ui/src/config/terminal-themes.ts` (lines 593-594) +- Trigger: User selects solarizedlight or github terminal theme +- Workaround: Uses generic light theme instead of specific scheme; visual appearance doesn't match expectation + +## Security Considerations + +**Process Environment Variable Exposure:** + +- Risk: Child processes inherit all parent `process.env` including sensitive credentials (API keys, tokens) +- Files: `apps/server/src/providers/cursor-provider.ts` (line 993), `apps/server/src/providers/codex-provider.ts` (line 1099) +- Current mitigation: Dotenv provides isolation at app startup; selective env passing to some providers +- Recommendations: Use explicit allowlists for env vars passed to child processes (only pass REQUIRED_KEYS); audit all spawn calls for env handling; document which providers need which credentials + +**Unvalidated Provider Tool Input:** + +- Risk: Tool input from CLI providers (Cursor, Copilot, Codex) is partially validated through Record patterns; execution context could be escaped +- Files: `apps/server/src/providers/codex-provider.ts` (lines 506-543), `apps/server/src/providers/tool-normalization.ts` +- Current mitigation: Status enums validated; tool names checked against allow-lists in some providers +- Recommendations: Implement comprehensive schema validation for all tool inputs before execution; use zod or similar for runtime validation; add security tests for injection patterns + +**API Key Storage in Settings Files:** + +- Risk: API keys stored in plaintext in `~/.automaker/settings.json` and `data/settings.json`; file permissions may not be restricted +- Files: `apps/server/src/services/settings-service.ts`, uses `atomicWriteJson` without file permission enforcement +- Current mitigation: Limited by file system permissions; Electron mode has single-user access +- Recommendations: Encrypt sensitive settings fields (apiKeys, tokens); use OS credential stores (Keychain/Credential Manager) for production; add file permission checks on startup + +## Performance Bottlenecks + +**Synchronous Feature Loading at Startup:** + +- Problem: All features loaded synchronously at project load; blocks UI with 1000+ features +- Files: `apps/server/src/services/feature-loader.ts` (line 230 Promise.all, but synchronous enumeration) +- Cause: Feature directory walk and JSON parsing is not paginated or lazy-loaded +- Improvement path: Implement lazy loading with pagination (load first 50, fetch more on scroll); add caching layer with TTL; move to background indexing; add feature count limits with warnings + +**Auto-Mode Concurrency at Max Can Exceed Rate Limits:** + +- Problem: maxConcurrency = 10 can quickly exhaust Claude API rate limits if all features execute simultaneously +- Files: `apps/server/src/services/auto-mode-service.ts` (line 2931 Promise.all for concurrent agents) +- Cause: No adaptive backoff; no API usage tracking before queuing; hint mentions reducing concurrency but doesn't enforce it +- Improvement path: Integrate with claude-usage-service to check remaining quota before starting features; implement exponential backoff on 429 errors; add per-model rate limit tracking + +**Terminal Session Memory Leak Risk:** + +- Problem: Terminal sessions accumulate in memory; expired sessions not cleaned up reliably +- Files: `apps/server/src/routes/terminal/common.ts` (line 66 cleanup runs every 5 minutes, but only for tokens) +- Cause: Cleanup interval is arbitrary; session map not bounded; no session lifespan limit +- Improvement path: Implement LRU eviction with max session count; reduce cleanup interval to 1 minute; add memory usage monitoring; auto-close idle sessions after 30 minutes + +**Large File Content Loading Without Limits:** + +- Problem: File content loaded entirely into memory; `describe-file.ts` truncates at 50KB but loads all content first +- Files: `apps/server/src/routes/context/routes/describe-file.ts` (line 128) +- Cause: Synchronous file read; no streaming; no check before reading large files +- Improvement path: Check file size before reading; stream large files; add file size warnings; implement chunked processing for analysis + +## Fragile Areas + +**Provider Factory Model Resolution:** + +- Files: `apps/server/src/providers/provider-factory.ts`, `apps/server/src/providers/simple-query-service.ts` +- Why fragile: Each provider interprets model strings differently; no central registry; model aliases resolved at multiple layers (model-resolver, provider-specific maps, CLI validation) +- Safe modification: Add integration tests for each model alias per provider; create model capability matrix; centralize model validation before dispatch +- Test coverage: No dedicated tests; relies on E2E; no isolated unit tests for model resolution + +**WebSocket Session Authentication:** + +- Files: `apps/server/src/lib/auth.ts` (line 40 setInterval), `apps/server/src/index.ts` (token validation per message) +- Why fragile: Session tokens generated and validated at multiple points; no single source of truth; expiration is not atomic +- Safe modification: Add tests for token expiration edge cases; ensure cleanup removes all references; log all auth failures +- Test coverage: Auth middleware tested, but not session lifecycle + +**Auto-Mode Feature State Machine:** + +- Files: `apps/server/src/services/auto-mode-service.ts` (lines 465-600) +- Why fragile: Multiple states (running, queued, completed, error) managed across different methods; no explicit state transition validation; error recovery is defensive (catches all, logs, continues) +- Safe modification: Create explicit state enum with valid transitions; add invariant checks; unit test state transitions with all error cases +- Test coverage: Gaps in error recovery paths; no tests for concurrent state changes + +## Scaling Limits + +**Feature Count Scalability:** + +- Current capacity: ~1000 features tested; UI performance degrades with pagination required +- Limit: 10K+ features cause >5s load times; memory usage ~100MB for metadata alone +- Scaling path: Implement feature database instead of file-per-feature; add ElasticSearch indexing for search; paginate API responses (50 per page); add feature archiving + +**Concurrent Auto-Mode Executions:** + +- Current capacity: maxConcurrency = 10 features; limited by Claude API rate limits +- Limit: Rate limit hits at ~4-5 simultaneous features with extended context (100K+ tokens) +- Scaling path: Implement token usage budgeting before feature start; queue features with estimated token cost; add provider-specific rate limit handling + +**Terminal Session Count:** + +- Current capacity: ~100 active terminal sessions per server +- Limit: Memory grows unbounded; no session count limit enforced +- Scaling path: Add max session count with least-recently-used eviction; implement session federation for distributed setup + +**Worktree Disk Usage:** + +- Current capacity: 10K worktrees (~20GB with typical repos) +- Limit: `.worktrees` directory grows without cleanup; old worktrees accumulate +- Scaling path: Add worktree TTL (delete if not used for 30 days); implement cleanup job; add quota warnings at 50/80% disk + +## Dependencies at Risk + +**node-pty Beta Version:** + +- Risk: `node-pty@1.1.0-beta41` used for terminal emulation; beta status indicates possible instability +- Impact: Terminal features could break on minor platform changes; no guarantees on bug fixes +- Migration plan: Monitor releases for stable version; pin to specific commit if needed; test extensively on target platforms (macOS, Linux, Windows) + +**@anthropic-ai/claude-agent-sdk 0.1.x:** + +- Risk: Pre-1.0 version; SDK API may change in future releases; limited version stability guarantees +- Impact: Breaking changes could require significant refactoring; feature additions in SDK may not align with Automaker roadmap +- Migration plan: Pin to specific 0.1.x version; review SDK changelogs before upgrades; maintain SDK compatibility tests; consider fallback implementation for critical paths + +**@openai/codex-sdk 0.77.x:** + +- Risk: Codex model deprecated by OpenAI; SDK may be archived or unsupported +- Impact: Codex provider could become non-functional; error messages may not be actionable +- Migration plan: Monitor OpenAI roadmap for migration path; implement fallback to Claude for Codex requests; add deprecation warning in UI + +**Express 5.2.x RC Stage:** + +- Risk: Express 5 is still in release candidate phase (as of Node 22); full stability not guaranteed +- Impact: Minor version updates could include breaking changes; middleware compatibility issues possible +- Migration plan: Maintain compatibility layer for Express 5 API; test with latest major before release; document any version-specific workarounds + +## Missing Critical Features + +**Persistent Session Storage:** + +- Problem: Agent conversation sessions stored only in-memory; restart loses all chat history +- Blocks: Long-running analysis across server restarts; session recovery not possible +- Impact: Users must re-run entire analysis if server restarts; lost productivity + +**Rate Limit Awareness:** + +- Problem: No tracking of API usage relative to rate limits before executing features +- Blocks: Predictable concurrent feature execution; users frequently hit rate limits unexpectedly +- Impact: Feature execution fails with cryptic rate limit errors; poor user experience + +**Feature Dependency Visualization:** + +- Problem: Dependency-resolver package exists but no UI to visualize or manage dependencies +- Blocks: Users cannot plan feature order; complex dependencies not visible +- Impact: Features implemented in wrong order; blocking dependencies missed + +## Test Coverage Gaps + +**CLI Provider Integration:** + +- What's not tested: Actual CLI execution paths; environment setup; error recovery from CLI crashes +- Files: `apps/server/src/providers/cli-provider.ts`, `apps/server/src/lib/cli-detection.ts` +- Risk: Changes to CLI handling could break silently; detection logic not validated on target platforms +- Priority: High - affects all CLI-based providers (Cursor, Copilot, Codex) + +**Cursor Provider Platform-Specific Paths:** + +- What's not tested: Windows/Linux Cursor installation detection; version directory parsing; APPDATA environment variable handling +- Files: `apps/server/src/providers/cursor-provider.ts` (lines 267-498) +- Risk: Platform-specific bugs not caught; Cursor detection fails on non-standard installations +- Priority: High - Cursor is primary provider; platform differences critical + +**Event Hook System State Changes:** + +- What's not tested: Concurrent hook execution; cleanup on server shutdown; webhook delivery retries +- Files: `apps/server/src/services/event-hook-service.ts` (line 248 Promise.allSettled) +- Risk: Hooks may not execute in expected order; memory not cleaned up; webhooks lost on failure +- Priority: Medium - affects automation workflows + +**Error Classification for New Providers:** + +- What's not tested: Each provider's unique error patterns mapped to ErrorType enum; new provider errors not classified +- Files: `apps/server/src/lib/error-handler.ts` (lines 58-80), each provider error mapping +- Risk: User sees generic "unknown error" instead of actionable message; categorization regresses with new providers +- Priority: Medium - impacts user experience + +**Feature State Corruption Scenarios:** + +- What's not tested: Concurrent feature updates; partial writes with power loss; JSON parsing recovery +- Files: `apps/server/src/services/feature-loader.ts`, `@automaker/utils` (atomicWriteJson) +- Risk: Feature data corrupted on concurrent access; recovery incomplete; no validation before use +- Priority: High - data loss risk + +--- + +_Concerns audit: 2026-01-27_ diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md new file mode 100644 index 00000000..e035741c --- /dev/null +++ b/.planning/codebase/CONVENTIONS.md @@ -0,0 +1,255 @@ +# Coding Conventions + +**Analysis Date:** 2026-01-27 + +## Naming Patterns + +**Files:** + +- PascalCase for class/service files: `auto-mode-service.ts`, `feature-loader.ts`, `claude-provider.ts` +- kebab-case for route/handler directories: `auto-mode/`, `features/`, `event-history/` +- kebab-case for utility files: `secure-fs.ts`, `sdk-options.ts`, `settings-helpers.ts` +- kebab-case for React components: `card.tsx`, `ansi-output.tsx`, `count-up-timer.tsx` +- kebab-case for hooks: `use-board-background-settings.ts`, `use-responsive-kanban.ts`, `use-test-logs.ts` +- kebab-case for store files: `app-store.ts`, `auth-store.ts`, `setup-store.ts` +- Organized by functionality: `routes/features/routes/list.ts`, `routes/features/routes/get.ts` + +**Functions:** + +- camelCase for all function names: `createEventEmitter()`, `getAutomakerDir()`, `executeQuery()` +- Verb-first for action functions: `buildPrompt()`, `classifyError()`, `loadContextFiles()`, `atomicWriteJson()` +- Prefix with `use` for React hooks: `useBoardBackgroundSettings()`, `useAppStore()`, `useUpdateProjectSettings()` +- Private methods prefixed with underscore: `_deleteOrphanedImages()`, `_migrateImages()` + +**Variables:** + +- camelCase for constants and variables: `featureId`, `projectPath`, `modelId`, `tempDir` +- UPPER_SNAKE_CASE for global constants/enums: `DEFAULT_MAX_CONCURRENCY`, `DEFAULT_PHASE_MODELS` +- Meaningful naming over abbreviations: `featureDirectory` not `fd`, `featureImages` not `img` +- Prefixes for computed values: `is*` for booleans: `isClaudeModel`, `isContainerized`, `isAutoLoginEnabled` + +**Types:** + +- PascalCase for interfaces and types: `Feature`, `ExecuteOptions`, `EventEmitter`, `ProviderConfig` +- Type files suffixed with `.d.ts`: `paths.d.ts`, `types.d.ts` +- Organized by domain: `src/store/types/`, `src/lib/` +- Re-export pattern from main package indexes: `export type { Feature };` + +## Code Style + +**Formatting:** + +- Tool: Prettier 3.7.4 +- Print width: 100 characters +- Tab width: 2 spaces +- Single quotes for strings +- Semicolons required +- Trailing commas: es5 (trailing in arrays/objects, not in params) +- Arrow functions always include parentheses: `(x) => x * 2` +- Line endings: LF (Unix) +- Bracket spacing: `{ key: value }` + +**Linting:** + +- Tool: ESLint (flat config in `apps/ui/eslint.config.mjs`) +- TypeScript ESLint plugin for `.ts`/`.tsx` files +- Recommended configs: `@eslint/js`, `@typescript-eslint/recommended` +- Unused variables warning with exception for parameters starting with `_` +- Type assertions are allowed with description when using `@ts-ignore` +- `@typescript-eslint/no-explicit-any` is warn-level (allow with caution) + +## Import Organization + +**Order:** + +1. Node.js standard library: `import fs from 'fs/promises'`, `import path from 'path'` +2. Third-party packages: `import { describe, it } from 'vitest'`, `import { Router } from 'express'` +3. Shared packages (monorepo): `import type { Feature } from '@automaker/types'`, `import { createLogger } from '@automaker/utils'` +4. Local relative imports: `import { FeatureLoader } from './feature-loader.js'`, `import * as secureFs from '../lib/secure-fs.js'` +5. Type imports: separated with `import type { ... } from` + +**Path Aliases:** + +- `@/` - resolves to `./src` in both UI (`apps/ui/`) and server (`apps/server/`) +- Shared packages prefixed with `@automaker/`: + - `@automaker/types` - core TypeScript definitions + - `@automaker/utils` - logging, errors, utilities + - `@automaker/prompts` - AI prompt templates + - `@automaker/platform` - path management, security, processes + - `@automaker/model-resolver` - model alias resolution + - `@automaker/dependency-resolver` - feature dependency ordering + - `@automaker/git-utils` - git operations +- Extensions: `.js` extension used in imports for ESM imports + +**Import Rules:** + +- Always import from shared packages, never from old paths +- No circular dependencies between layers +- Services import from providers and utilities +- Routes import from services +- Shared packages have strict dependency hierarchy (types → utils → platform → git-utils → server/ui) + +## Error Handling + +**Patterns:** + +- Use `try-catch` blocks for async operations: wraps feature execution, file operations, git commands +- Throw `new Error(message)` with descriptive messages: `throw new Error('already running')`, `throw new Error('Feature ${featureId} not found')` +- Classify errors with `classifyError()` from `@automaker/utils` for categorization +- Log errors with context using `createLogger()`: includes error classification +- Return error info objects: `{ valid: false, errors: [...], warnings: [...] }` +- Validation returns structured result: `{ valid, errors, warnings }` from provider `validateConfig()` + +**Error Types:** + +- Authentication errors: distinguish from validation/runtime errors +- Path validation errors: caught by middleware in Express routes +- File system errors: logged and recovery attempted with backups +- SDK/API errors: classified and wrapped with context +- Abort/cancellation errors: handled without stack traces (graceful shutdown) + +**Error Messages:** + +- Descriptive and actionable: not vague error codes +- Include context when helpful: file paths, feature IDs, model names +- User-friendly messages via `getUserFriendlyErrorMessage()` for client display + +## Logging + +**Framework:** + +- Built-in `createLogger()` from `@automaker/utils` +- Each module creates logger: `const logger = createLogger('ModuleName')` +- Logger functions: `info()`, `warn()`, `error()`, `debug()` + +**Patterns:** + +- Log operation start and completion for significant operations +- Log warnings for non-critical issues: file deletion failures, missing optional configs +- Log errors with full error object: `logger.error('operation failed', error)` +- Use module name as logger context: `createLogger('AutoMode')`, `createLogger('HttpClient')` +- Avoid logging sensitive data (API keys, passwords) +- No console.log in production code - use logger + +**What to Log:** + +- Feature execution start/completion +- Error classification and recovery attempts +- File operations (create, delete, migrate) +- API calls and responses (in debug mode) +- Async operation start/end +- Warnings for deprecated patterns + +## Comments + +**When to Comment:** + +- Complex algorithms or business logic: explain the "why" not the "what" +- Integration points: explain how modules communicate +- Workarounds: explain the constraint that made the workaround necessary +- Non-obvious performance implications +- Edge cases and their handling + +**JSDoc/TSDoc:** + +- Used for public functions and classes +- Document parameters with `@param` +- Document return types with `@returns` +- Document exceptions with `@throws` +- Used for service classes: `/**\n * Module description\n * Manages: ...\n */` +- Not required for simple getters/setters + +**Example JSDoc Pattern:** + +```typescript +/** + * Delete images that were removed from a feature + */ +private async deleteOrphanedImages( + projectPath: string, + oldPaths: Array, + newPaths: Array +): Promise { + // Implementation +} +``` + +## Function Design + +**Size:** + +- Keep functions under 100 lines when possible +- Large services split into multiple related methods +- Private helper methods extracted for complex logic + +**Parameters:** + +- Use destructuring for object parameters with multiple properties +- Document parameter types with TypeScript types +- Optional parameters marked with `?` +- Use `Record` for flexible object parameters + +**Return Values:** + +- Explicit return types required for all public functions +- Return structured objects for multiple values +- Use `Promise` for async functions +- Async generators use `AsyncGenerator` for streaming responses +- Never implicitly return `undefined` (explicit return or throw) + +## Module Design + +**Exports:** + +- Default export for class instantiation: `export default class FeatureLoader {}` +- Named exports for functions: `export function createEventEmitter() {}` +- Type exports separated: `export type { Feature };` +- Barrel files (index.ts) re-export from module + +**Barrel Files:** + +- Used in routes: `routes/features/index.ts` creates router and exports +- Used in stores: `store/index.ts` exports all store hooks +- Pattern: group related exports for easier importing + +**Service Classes:** + +- Instantiated once and dependency injected +- Public methods for API surface +- Private methods prefixed with `_` +- No static methods - prefer instances or functions +- Constructor takes dependencies: `constructor(config?: ProviderConfig)` + +**Provider Pattern:** + +- Abstract base class: `BaseProvider` with abstract methods +- Concrete implementations: `ClaudeProvider`, `CodexProvider`, `CursorProvider` +- Common interface: `executeQuery()`, `detectInstallation()`, `validateConfig()` +- Factory for instantiation: `ProviderFactory.create()` + +## TypeScript Specific + +**Strict Mode:** Always enabled globally + +- `strict: true` in all tsconfigs +- No implicit `any` - declare types explicitly +- No optional chaining on base types without narrowing + +**Type Definitions:** + +- Interface for shapes: `interface Feature { ... }` +- Type for unions/aliases: `type ModelAlias = 'haiku' | 'sonnet' | 'opus'` +- Type guards for narrowing: `if (typeof x === 'string') { ... }` +- Generic types for reusable patterns: `EventCallback` + +**React Specific (UI):** + +- Functional components only +- React 19 with hooks +- Type props interface: `interface CardProps extends React.ComponentProps<'div'> { ... }` +- Zustand stores for state management +- Custom hooks for shared logic + +--- + +_Convention analysis: 2026-01-27_ diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md new file mode 100644 index 00000000..d7cbafa9 --- /dev/null +++ b/.planning/codebase/INTEGRATIONS.md @@ -0,0 +1,232 @@ +# External Integrations + +**Analysis Date:** 2026-01-27 + +## APIs & External Services + +**AI/LLM Providers:** + +- Claude (Anthropic) + - SDK: `@anthropic-ai/claude-agent-sdk` (0.1.76) + - Auth: `ANTHROPIC_API_KEY` environment variable or stored credentials + - Features: Extended thinking, vision/images, tools, streaming + - Implementation: `apps/server/src/providers/claude-provider.ts` + - Models: Opus 4.5, Sonnet 4, Haiku 4.5, and legacy models + - Custom endpoints: `ANTHROPIC_BASE_URL` (optional) + +- GitHub Copilot + - SDK: `@github/copilot-sdk` (0.1.16) + - Auth: GitHub OAuth (via `gh` CLI) or `GITHUB_TOKEN` environment variable + - Features: Tools, streaming, runtime model discovery + - Implementation: `apps/server/src/providers/copilot-provider.ts` + - CLI detection: Searches for Copilot CLI binary + - Models: Dynamic discovery via `copilot models list` + +- OpenAI Codex/GPT-4 + - SDK: `@openai/codex-sdk` (0.77.0) + - Auth: `OPENAI_API_KEY` environment variable or stored credentials + - Features: Extended thinking, tools, sandbox execution + - Implementation: `apps/server/src/providers/codex-provider.ts` + - Execution modes: CLI (with sandbox) or SDK (direct API) + - Models: Dynamic discovery via Codex CLI or SDK + +- Google Gemini + - Implementation: `apps/server/src/providers/gemini-provider.ts` + - Features: Vision support, tools, streaming + +- OpenCode (AWS/Azure/other) + - Implementation: `apps/server/src/providers/opencode-provider.ts` + - Supports: Amazon Bedrock, Azure models, local models + - Features: Flexible provider architecture + +- Cursor Editor + - Implementation: `apps/server/src/providers/cursor-provider.ts` + - Features: Integration with Cursor IDE + +**Model Context Protocol (MCP):** + +- SDK: `@modelcontextprotocol/sdk` (1.25.2) +- Purpose: Connect AI agents to external tools and data sources +- Implementation: `apps/server/src/services/mcp-test-service.ts`, `apps/server/src/routes/mcp/` +- Configuration: Per-project in `.automaker/` directory + +## Data Storage + +**Databases:** + +- None - This codebase does NOT use traditional databases (SQL/NoSQL) +- All data stored as files in local filesystem + +**File Storage:** + +- Local filesystem only +- Locations: + - `.automaker/` - Project-specific data (features, context, settings) + - `./data/` or `DATA_DIR` env var - Global data (settings, credentials, sessions) +- Secure file operations: `@automaker/platform` exports `secureFs` for restricted file access + +**Caching:** + +- In-memory caches for: + - Model lists (Copilot, Codex runtime discovery) + - Feature metadata + - Project specifications +- No distributed/persistent caching system + +## Authentication & Identity + +**Auth Provider:** + +- Custom implementation (no third-party provider) +- Authentication methods: + 1. Claude Max Plan (OAuth via Anthropic CLI) + 2. API Key mode (ANTHROPIC_API_KEY) + 3. Custom provider profiles with API keys + 4. Token-based session authentication for WebSocket + +**Implementation:** + +- `apps/server/src/lib/auth.ts` - Auth middleware +- `apps/server/src/routes/auth/` - Auth routes +- Session tokens for WebSocket connections +- Credential storage in `./data/credentials.json` (encrypted/protected) + +## Monitoring & Observability + +**Error Tracking:** + +- None - No automatic error reporting service integrated +- Custom error classification: `@automaker/utils` exports `classifyError()` +- User-friendly error messages: `getUserFriendlyErrorMessage()` + +**Logs:** + +- Console logging with configurable levels +- Logger: `@automaker/utils` exports `createLogger()` +- Log levels: ERROR, WARN, INFO, DEBUG +- Environment: `LOG_LEVEL` env var (optional) +- Storage: Logs output to console/stdout (no persistent logging to files) + +**Usage Tracking:** + +- Claude API usage: `apps/server/src/services/claude-usage-service.ts` +- Codex API usage: `apps/server/src/services/codex-usage-service.ts` +- Tracks: Tokens, costs, rates + +## CI/CD & Deployment + +**Hosting:** + +- Local development: Node.js server + Vite dev server +- Desktop: Electron application (macOS, Windows, Linux) +- Web: Express server deployed to any Node.js host + +**CI Pipeline:** + +- GitHub Actions likely (`.github/workflows/` present in repo) +- Testing: Playwright E2E, Vitest unit tests +- Linting: ESLint +- Formatting: Prettier + +**Build Process:** + +- `npm run build:packages` - Build shared packages +- `npm run build` - Build web UI +- `npm run build:electron` - Build Electron apps (platform-specific) +- Electron Builder handles code signing and distribution + +## Environment Configuration + +**Required env vars:** + +- `ANTHROPIC_API_KEY` - For Claude provider (or provide in settings) +- `OPENAI_API_KEY` - For Codex provider (optional) +- `GITHUB_TOKEN` - For GitHub operations (optional) + +**Optional env vars:** + +- `PORT` - Server port (default 3008) +- `HOST` - Server bind address (default 0.0.0.0) +- `HOSTNAME` - Public hostname (default localhost) +- `DATA_DIR` - Data storage directory (default ./data) +- `ANTHROPIC_BASE_URL` - Custom Claude endpoint +- `ALLOWED_ROOT_DIRECTORY` - Restrict file operations to directory +- `AUTOMAKER_MOCK_AGENT` - Enable mock agent for testing +- `AUTOMAKER_AUTO_LOGIN` - Skip login prompt in dev + +**Secrets location:** + +- Runtime: Environment variables (`process.env`) +- Stored: `./data/credentials.json` (file-based) +- Retrieval: `apps/server/src/services/settings-service.ts` + +## Webhooks & Callbacks + +**Incoming:** + +- WebSocket connections for real-time agent event streaming +- GitHub webhook routes (optional): `apps/server/src/routes/github/` +- Terminal WebSocket connections: `apps/server/src/routes/terminal/` + +**Outgoing:** + +- GitHub PRs: `apps/server/src/routes/worktree/routes/create-pr.ts` +- Git operations: `@automaker/git-utils` handles commits, pushes +- Terminal output streaming via WebSocket to clients +- Event hooks: `apps/server/src/services/event-hook-service.ts` + +## Credential Management + +**API Keys Storage:** + +- File: `./data/credentials.json` +- Format: JSON with nested structure for different providers + ```json + { + "apiKeys": { + "anthropic": "sk-...", + "openai": "sk-...", + "github": "ghp_..." + } + } + ``` +- Access: `SettingsService.getCredentials()` from `apps/server/src/services/settings-service.ts` +- Security: File permissions should restrict to current user only + +**Profile/Provider Configuration:** + +- File: `./data/settings.json` (global) or `.automaker/settings.json` (per-project) +- Stores: Alternative provider profiles, model mappings, sandbox settings +- Types: `ClaudeApiProfile`, `ClaudeCompatibleProvider` from `@automaker/types` + +## Third-Party Service Integration Points + +**Git/GitHub:** + +- `@automaker/git-utils` - Git operations (worktrees, commits, diffs) +- Codex/Cursor providers can create GitHub PRs +- GitHub CLI (`gh`) detection for Copilot authentication + +**Terminal Access:** + +- `node-pty` (1.1.0-beta41) - Pseudo-terminal interface +- `TerminalService` manages terminal sessions +- WebSocket streaming to frontend + +**AI Models - Multi-Provider Abstraction:** + +- `BaseProvider` interface: `apps/server/src/providers/base-provider.ts` +- Factory pattern: `apps/server/src/providers/provider-factory.ts` +- Allows swapping providers without changing agent logic +- All providers implement: `executeQuery()`, `detectInstallation()`, `getAvailableModels()` + +**Process Spawning:** + +- `@automaker/platform` exports `spawnProcess()`, `spawnJSONLProcess()` +- Codex CLI execution: JSONL output parsing +- Copilot CLI execution: Subprocess management +- Cursor IDE interaction: Process spawning for tool execution + +--- + +_Integration audit: 2026-01-27_ diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md new file mode 100644 index 00000000..4d645865 --- /dev/null +++ b/.planning/codebase/STACK.md @@ -0,0 +1,230 @@ +# Technology Stack + +**Analysis Date:** 2026-01-27 + +## Languages + +**Primary:** + +- TypeScript 5.9.3 - Used across all packages, apps, and configuration +- JavaScript (Node.js) - Runtime execution for scripts and tooling + +**Secondary:** + +- YAML 2.7.0 - Configuration files +- CSS/Tailwind CSS 4.1.18 - Frontend styling + +## Runtime + +**Environment:** + +- Node.js 22.x (>=22.0.0 <23.0.0) - Required version, specified in `.nvmrc` + +**Package Manager:** + +- npm - Monorepo workspace management via npm workspaces +- Lockfile: `package-lock.json` (present) + +## Frameworks + +**Core - Frontend:** + +- React 19.2.3 - UI framework with hooks and concurrent features +- Vite 7.3.0 - Build tool and dev server (`apps/ui/vite.config.ts`) +- Electron 39.2.7 - Desktop application runtime (`apps/ui/package.json`) +- TanStack Router 1.141.6 - File-based routing (React) +- Zustand 5.0.9 - State management (lightweight alternative to Redux) +- TanStack Query (React Query) 5.90.17 - Server state management + +**Core - Backend:** + +- Express 5.2.1 - HTTP server framework (`apps/server/package.json`) +- WebSocket (ws) 8.18.3 - Real-time bidirectional communication +- Claude Agent SDK (@anthropic-ai/claude-agent-sdk) 0.1.76 - AI provider integration + +**Testing:** + +- Playwright 1.57.0 - End-to-end testing (`apps/ui` E2E tests) +- Vitest 4.0.16 - Unit testing framework (runs on all packages and server) +- @vitest/ui 4.0.16 - Visual test runner UI +- @vitest/coverage-v8 4.0.16 - Code coverage reporting + +**Build/Dev:** + +- electron-builder 26.0.12 - Electron app packaging and distribution +- @vitejs/plugin-react 5.1.2 - Vite React support +- vite-plugin-electron 0.29.0 - Vite plugin for Electron main process +- vite-plugin-electron-renderer 0.14.6 - Vite plugin for Electron renderer +- ESLint 9.39.2 - Code linting (`apps/ui`) +- @typescript-eslint/eslint-plugin 8.50.0 - TypeScript ESLint rules +- Prettier 3.7.4 - Code formatting (root-level config) +- Tailwind CSS 4.1.18 - Utility-first CSS framework +- @tailwindcss/vite 4.1.18 - Tailwind Vite integration + +**UI Components & Libraries:** + +- Radix UI - Unstyled accessible component library (@radix-ui packages) + - react-dropdown-menu 2.1.16 + - react-dialog 1.1.15 + - react-select 2.2.6 + - react-tooltip 1.2.8 + - react-tabs 1.1.13 + - react-collapsible 1.1.12 + - react-checkbox 1.3.3 + - react-radio-group 1.3.8 + - react-popover 1.1.15 + - react-slider 1.3.6 + - react-switch 1.2.6 + - react-scroll-area 1.2.10 + - react-label 2.1.8 +- Lucide React 0.562.0 - Icon library +- Geist 1.5.1 - Design system UI library +- Sonner 2.0.7 - Toast notifications + +**Code Editor & Terminal:** + +- @uiw/react-codemirror 4.25.4 - Code editor React component +- CodeMirror (@codemirror packages) 6.x - Editor toolkit +- xterm.js (@xterm/xterm) 5.5.0 - Terminal emulator +- @xterm/addon-fit 0.10.0 - Fit addon for terminal +- @xterm/addon-search 0.15.0 - Search addon for terminal +- @xterm/addon-web-links 0.11.0 - Web links addon +- @xterm/addon-webgl 0.18.0 - WebGL renderer for terminal + +**Diagram/Graph Visualization:** + +- @xyflow/react 12.10.0 - React flow diagram library +- dagre 0.8.5 - Graph layout algorithms + +**Markdown/Content Rendering:** + +- react-markdown 10.1.0 - Markdown parser and renderer +- remark-gfm 4.0.1 - GitHub Flavored Markdown support +- rehype-raw 7.0.0 - Raw HTML support in markdown +- rehype-sanitize 6.0.0 - HTML sanitization + +**Data Validation & Parsing:** + +- zod 3.24.1 or 4.0.0 - Schema validation and TypeScript type inference + +**Utilities:** + +- class-variance-authority 0.7.1 - CSS variant utilities +- clsx 2.1.1 - Conditional className utility +- cmdk 1.1.1 - Command menu/palette +- tailwind-merge 3.4.0 - Tailwind CSS conflict resolution +- usehooks-ts 3.1.1 - TypeScript React hooks +- @dnd-kit (drag-and-drop) 6.3.1 - Drag and drop library + +**Font Libraries:** + +- @fontsource - Web font packages (Cascadia Code, Fira Code, IBM Plex, Inconsolata, Inter, etc.) + +**Development Utilities:** + +- cross-spawn 7.0.6 - Cross-platform process spawning +- dotenv 17.2.3 - Environment variable loading +- tsx 4.21.0 - TypeScript execution for Node.js +- tree-kill 1.2.2 - Process tree killer utility +- node-pty 1.1.0-beta41 - PTY/terminal interface for Node.js + +## Key Dependencies + +**Critical - AI/Agent Integration:** + +- @anthropic-ai/claude-agent-sdk 0.1.76 - Core Claude AI provider +- @github/copilot-sdk 0.1.16 - GitHub Copilot integration +- @openai/codex-sdk 0.77.0 - OpenAI Codex/GPT-4 integration +- @modelcontextprotocol/sdk 1.25.2 - Model Context Protocol servers + +**Infrastructure - Internal Packages:** + +- @automaker/types 1.0.0 - Shared TypeScript type definitions +- @automaker/utils 1.0.0 - Logging, error handling, utilities +- @automaker/platform 1.0.0 - Path management, security, process spawning +- @automaker/prompts 1.0.0 - AI prompt templates +- @automaker/model-resolver 1.0.0 - Claude model alias resolution +- @automaker/dependency-resolver 1.0.0 - Feature dependency ordering +- @automaker/git-utils 1.0.0 - Git operations & worktree management +- @automaker/spec-parser 1.0.0 - Project specification parsing + +**Server Utilities:** + +- express 5.2.1 - Web framework +- cors 2.8.5 - CORS middleware +- morgan 1.10.1 - HTTP request logger +- cookie-parser 1.4.7 - Cookie parsing middleware +- yaml 2.7.0 - YAML parsing and generation + +**Type Definitions:** + +- @types/express 5.0.6 +- @types/node 22.19.3 +- @types/react 19.2.7 +- @types/react-dom 19.2.3 +- @types/dagre 0.7.53 +- @types/ws 8.18.1 +- @types/cookie 0.6.0 +- @types/cookie-parser 1.4.10 +- @types/cors 2.8.19 +- @types/morgan 1.9.10 + +**Optional Dependencies (Platform-specific):** + +- lightningcss (various platforms) 1.29.2 - CSS parser (alternate to PostCSS) +- dmg-license 1.0.11 - DMG license dialog for macOS + +## Configuration + +**Environment:** + +- `.env` and `.env.example` files in `apps/server/` and `apps/ui/` +- `dotenv` library loads variables from `.env` files +- Key env vars: + - `ANTHROPIC_API_KEY` - Claude API authentication + - `OPENAI_API_KEY` - OpenAI/Codex authentication + - `GITHUB_TOKEN` - GitHub API access + - `ANTHROPIC_BASE_URL` - Custom Claude endpoint (optional) + - `HOST` - Server bind address (default: 0.0.0.0) + - `HOSTNAME` - Hostname for URLs (default: localhost) + - `PORT` - Server port (default: 3008) + - `DATA_DIR` - Data storage directory (default: ./data) + - `ALLOWED_ROOT_DIRECTORY` - Restrict file operations + - `AUTOMAKER_MOCK_AGENT` - Enable mock agent for testing + - `AUTOMAKER_AUTO_LOGIN` - Skip login in dev (disabled in production) + - `VITE_HOSTNAME` - Frontend API hostname + +**Build:** + +- `apps/ui/electron-builder.config.json` or `apps/ui/package.json` build config +- Electron builder targets: + - macOS: DMG and ZIP + - Windows: NSIS installer + - Linux: AppImage, DEB, RPM +- Vite config: `apps/ui/vite.config.ts`, `apps/server/tsconfig.json` +- TypeScript config: `tsconfig.json` files in each package + +## Platform Requirements + +**Development:** + +- Node.js 22.x +- npm (included with Node.js) +- Git (for worktree operations) +- Python (optional, for some dev scripts) + +**Production:** + +- Electron desktop app: Windows, macOS, Linux +- Web browser: Modern Chromium-based browsers +- Server: Any platform supporting Node.js 22.x + +**Deployment Target:** + +- Local desktop (Electron) +- Local web server (Express + Vite) +- Remote server deployment (Docker, systemd, or other orchestration) + +--- + +_Stack analysis: 2026-01-27_ diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md new file mode 100644 index 00000000..a98e07c8 --- /dev/null +++ b/.planning/codebase/STRUCTURE.md @@ -0,0 +1,340 @@ +# Codebase Structure + +**Analysis Date:** 2026-01-27 + +## Directory Layout + +``` +automaker/ +├── apps/ # Application packages +│ ├── ui/ # React + Electron frontend (port 3007) +│ │ ├── src/ +│ │ │ ├── main.ts # Electron/Vite entry point +│ │ │ ├── app.tsx # Root React component (splash, router) +│ │ │ ├── renderer.tsx # Electron renderer entry +│ │ │ ├── routes/ # TanStack Router file-based routes +│ │ │ ├── components/ # React components (views, dialogs, UI, layout) +│ │ │ ├── store/ # Zustand state management +│ │ │ ├── hooks/ # Custom React hooks +│ │ │ ├── lib/ # Utilities (API client, electron, queries, etc.) +│ │ │ ├── electron/ # Electron main & preload process files +│ │ │ ├── config/ # UI configuration (fonts, themes, routes) +│ │ │ └── styles/ # CSS and theme files +│ │ ├── public/ # Static assets +│ │ └── tests/ # E2E Playwright tests +│ │ +│ └── server/ # Express backend (port 3008) +│ ├── src/ +│ │ ├── index.ts # Express app initialization, route mounting +│ │ ├── routes/ # REST API endpoints (30+ route folders) +│ │ ├── services/ # Business logic services +│ │ ├── providers/ # AI model provider implementations +│ │ ├── lib/ # Utilities (events, auth, helpers, etc.) +│ │ ├── middleware/ # Express middleware +│ │ └── types/ # Server-specific type definitions +│ └── tests/ # Unit tests (Vitest) +│ +├── libs/ # Shared npm packages (@automaker/*) +│ ├── types/ # @automaker/types (no dependencies) +│ │ └── src/ +│ │ ├── index.ts # Main export with all type definitions +│ │ ├── feature.ts # Feature, FeatureStatus, etc. +│ │ ├── provider.ts # Provider interfaces, model definitions +│ │ ├── settings.ts # Global and project settings types +│ │ ├── event.ts # Event types for real-time updates +│ │ ├── session.ts # AgentSession, conversation types +│ │ ├── model*.ts # Model-specific types (cursor, codex, gemini, etc.) +│ │ └── ... 20+ more type files +│ │ +│ ├── utils/ # @automaker/utils (logging, errors, images, context) +│ │ └── src/ +│ │ ├── logger.ts # createLogger() with LogLevel enum +│ │ ├── errors.ts # classifyError(), error types +│ │ ├── image-utils.ts # Image processing, base64 encoding +│ │ ├── context-loader.ts # loadContextFiles() for AI prompts +│ │ └── ... more utilities +│ │ +│ ├── platform/ # @automaker/platform (paths, security, OS) +│ │ └── src/ +│ │ ├── index.ts # Path getters (getFeatureDir, getFeaturesDir, etc.) +│ │ ├── secure-fs.ts # Secure filesystem operations +│ │ └── config/ # Claude auth detection, allowed paths +│ │ +│ ├── prompts/ # @automaker/prompts (AI prompt templates) +│ │ └── src/ +│ │ ├── index.ts # Main prompts export +│ │ └── *-prompt.ts # Prompt templates for different features +│ │ +│ ├── model-resolver/ # @automaker/model-resolver +│ │ └── src/ +│ │ └── index.ts # resolveModelString() for model aliases +│ │ +│ ├── dependency-resolver/ # @automaker/dependency-resolver +│ │ └── src/ +│ │ └── index.ts # Resolve feature dependencies +│ │ +│ ├── git-utils/ # @automaker/git-utils (git operations) +│ │ └── src/ +│ │ ├── index.ts # getGitRepositoryDiffs(), worktree management +│ │ └── ... git helpers +│ │ +│ ├── spec-parser/ # @automaker/spec-parser +│ │ └── src/ +│ │ └── ... spec parsing utilities +│ │ +│ └── tsconfig.base.json # Base TypeScript config for all packages +│ +├── .automaker/ # Project data directory (created by app) +│ ├── features/ # Feature storage +│ │ └── {featureId}/ +│ │ ├── feature.json # Feature metadata and content +│ │ ├── agent-output.md # Agent execution results +│ │ └── images/ # Feature images +│ ├── context/ # Context files (CLAUDE.md, etc.) +│ ├── settings.json # Per-project settings +│ ├── spec.md # Project specification +│ └── analysis.json # Project structure analysis +│ +├── data/ # Global data directory (default, configurable) +│ ├── settings.json # Global settings, profiles +│ ├── credentials.json # Encrypted API keys +│ ├── sessions-metadata.json # Chat session metadata +│ └── agent-sessions/ # Conversation histories +│ +├── .planning/ # Generated documentation by GSD orchestrator +│ └── codebase/ # Codebase analysis documents +│ ├── ARCHITECTURE.md # Architecture patterns and layers +│ ├── STRUCTURE.md # This file +│ ├── STACK.md # Technology stack +│ ├── INTEGRATIONS.md # External API integrations +│ ├── CONVENTIONS.md # Code style and naming +│ ├── TESTING.md # Testing patterns +│ └── CONCERNS.md # Technical debt and issues +│ +├── .github/ # GitHub Actions workflows +├── scripts/ # Build and utility scripts +├── tests/ # Test data and utilities +├── docs/ # Documentation +├── package.json # Root workspace config +├── package-lock.json # Lock file +├── CLAUDE.md # Project instructions for Claude Code +├── DEVELOPMENT_WORKFLOW.md # Development guidelines +└── README.md # Project overview +``` + +## Directory Purposes + +**apps/ui/:** + +- Purpose: React frontend for desktop (Electron) and web modes +- Build system: Vite 7 with TypeScript +- Styling: Tailwind CSS 4 +- State: Zustand 5 with API persistence +- Routing: TanStack Router with file-based structure +- Desktop: Electron 39 with preload IPC bridge + +**apps/server/:** + +- Purpose: Express backend API and service layer +- Build system: TypeScript → JavaScript +- Runtime: Node.js 18+ +- WebSocket: ws library for real-time streaming +- Process management: node-pty for terminal isolation + +**libs/types/:** + +- Purpose: Central type definitions (no dependencies, fast import) +- Used by: All other packages and apps +- Pattern: Single namespace export from index.ts +- Build: Compiled to ESM only + +**libs/utils/:** + +- Purpose: Shared utilities for logging, errors, file operations, image processing +- Used by: Server, UI, other libraries +- Notable: `createLogger()`, `classifyError()`, `loadContextFiles()`, `readImageAsBase64()` + +**libs/platform/:** + +- Purpose: OS-agnostic path management and security enforcement +- Used by: Server services for file operations +- Notable: Path normalization, allowed directory enforcement, Claude auth detection + +**libs/prompts/:** + +- Purpose: AI prompt templates injected into agent context +- Used by: AgentService when executing features +- Pattern: Function exports that return prompt strings + +## Key File Locations + +**Entry Points:** + +**Server:** + +- `apps/server/src/index.ts`: Express server initialization, route mounting, WebSocket setup + +**UI (Web):** + +- `apps/ui/src/main.ts`: Vite entry point +- `apps/ui/src/app.tsx`: Root React component + +**UI (Electron):** + +- `apps/ui/src/main.ts`: Vite entry point +- `apps/ui/src/electron/main-process.ts`: Electron main process +- `apps/ui/src/preload.ts`: Electron preload script for IPC bridge + +**Configuration:** + +- `apps/server/src/index.ts`: PORT, HOST, HOSTNAME, DATA_DIR env vars +- `apps/ui/src/config/`: Theme options, fonts, model aliases +- `libs/types/src/settings.ts`: Settings schema +- `.env.local`: Local development overrides (git-ignored) + +**Core Logic:** + +**Server:** + +- `apps/server/src/services/agent-service.ts`: AI agent execution engine (31KB) +- `apps/server/src/services/auto-mode-service.ts`: Feature batching and automation (216KB - largest) +- `apps/server/src/services/feature-loader.ts`: Feature persistence and loading +- `apps/server/src/services/settings-service.ts`: Settings management +- `apps/server/src/providers/provider-factory.ts`: AI provider selection + +**UI:** + +- `apps/ui/src/store/app-store.ts`: Global state (84KB - largest frontend file) +- `apps/ui/src/lib/http-api-client.ts`: API client with auth (92KB) +- `apps/ui/src/components/views/board-view.tsx`: Kanban board (70KB) +- `apps/ui/src/routes/__root.tsx`: Root layout with session init (32KB) + +**Testing:** + +**E2E Tests:** + +- `apps/ui/tests/`: Playwright tests organized by feature area + - `settings/`, `features/`, `projects/`, `agent/`, `utils/`, `context/` + +**Unit Tests:** + +- `libs/*/tests/`: Package-specific Vitest tests +- `apps/server/src/tests/`: Server integration tests + +**Test Config:** + +- `vitest.config.ts`: Root Vitest configuration +- `apps/ui/playwright.config.ts`: Playwright configuration + +## Naming Conventions + +**Files:** + +- **Components:** PascalCase.tsx (e.g., `board-view.tsx`, `session-manager.tsx`) +- **Services:** camelCase-service.ts (e.g., `agent-service.ts`, `settings-service.ts`) +- **Hooks:** use-kebab-case.ts (e.g., `use-auto-mode.ts`, `use-settings-sync.ts`) +- **Utilities:** camelCase.ts (e.g., `api-fetch.ts`, `log-parser.ts`) +- **Routes:** kebab-case with index.ts pattern (e.g., `routes/agent/index.ts`) +- **Tests:** _.test.ts or _.spec.ts (co-located with source) + +**Directories:** + +- **Feature domains:** kebab-case (e.g., `auto-mode/`, `event-history/`, `project-settings-view/`) +- **Type categories:** kebab-case plural (e.g., `types/`, `services/`, `providers/`, `routes/`) +- **Shared utilities:** kebab-case (e.g., `lib/`, `utils/`, `hooks/`) + +**TypeScript:** + +- **Types:** PascalCase (e.g., `Feature`, `AgentSession`, `ProviderMessage`) +- **Interfaces:** PascalCase (e.g., `EventEmitter`, `ProviderFactory`) +- **Enums:** PascalCase (e.g., `LogLevel`, `FeatureStatus`) +- **Functions:** camelCase (e.g., `createLogger()`, `classifyError()`) +- **Constants:** UPPER_SNAKE_CASE (e.g., `DEFAULT_TIMEOUT_MS`, `MAX_RETRIES`) +- **Variables:** camelCase (e.g., `featureId`, `settingsService`) + +## Where to Add New Code + +**New Feature (end-to-end):** + +- API Route: `apps/server/src/routes/{feature-name}/index.ts` +- Service Logic: `apps/server/src/services/{feature-name}-service.ts` +- UI Route: `apps/ui/src/routes/{feature-name}.tsx` (simple) or `{feature-name}/` (complex with subdir) +- Store: `apps/ui/src/store/{feature-name}-store.ts` (if complex state) +- Tests: `apps/ui/tests/{feature-name}/` or `apps/server/src/tests/` + +**New Component/Module:** + +- View Components: `apps/ui/src/components/views/{component-name}/` +- Dialog Components: `apps/ui/src/components/dialogs/{dialog-name}.tsx` +- Shared Components: `apps/ui/src/components/shared/` or `components/ui/` (shadcn) +- Layout Components: `apps/ui/src/components/layout/` + +**Utilities:** + +- New Library: Create in `libs/{package-name}/` with package.json and tsconfig.json +- Server Utilities: `apps/server/src/lib/{utility-name}.ts` +- Shared Utilities: Extend `libs/utils/src/` or create new lib if self-contained +- UI Utilities: `apps/ui/src/lib/{utility-name}.ts` + +**New Provider (AI Model):** + +- Implementation: `apps/server/src/providers/{provider-name}-provider.ts` +- Types: Add to `libs/types/src/{provider-name}-models.ts` +- Model Resolver: Update `libs/model-resolver/src/index.ts` with model alias mapping +- Settings: Update `libs/types/src/settings.ts` for provider-specific config + +## Special Directories + +**apps/ui/electron/:** + +- Purpose: Electron-specific code (main process, IPC handlers, native APIs) +- Generated: Yes (preload.ts) +- Committed: Yes + +**apps/ui/public/** + +- Purpose: Static assets (sounds, images, icons) +- Generated: No +- Committed: Yes + +**apps/ui/dist/:** + +- Purpose: Built web application +- Generated: Yes +- Committed: No (.gitignore) + +**apps/ui/dist-electron/:** + +- Purpose: Built Electron app bundle +- Generated: Yes +- Committed: No (.gitignore) + +**.automaker/features/{featureId}/:** + +- Purpose: Per-feature persistent storage +- Structure: feature.json, agent-output.md, images/ +- Generated: Yes (at runtime) +- Committed: Yes (tracked in project git) + +**data/:** + +- Purpose: Global data directory (global settings, credentials, sessions) +- Generated: Yes (created at first run) +- Committed: No (.gitignore) +- Configurable: Via DATA_DIR env var + +**node_modules/:** + +- Purpose: Installed dependencies +- Generated: Yes +- Committed: No (.gitignore) + +**dist/**, **build/:** + +- Purpose: Build artifacts +- Generated: Yes +- Committed: No (.gitignore) + +--- + +_Structure analysis: 2026-01-27_ diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md new file mode 100644 index 00000000..4d58a28f --- /dev/null +++ b/.planning/codebase/TESTING.md @@ -0,0 +1,389 @@ +# Testing Patterns + +**Analysis Date:** 2026-01-27 + +## Test Framework + +**Runner:** + +- Vitest 4.0.16 (for unit and integration tests) +- Playwright (for E2E tests) +- Config: `apps/server/vitest.config.ts`, `libs/*/vitest.config.ts`, `apps/ui/playwright.config.ts` + +**Assertion Library:** + +- Vitest built-in expect assertions +- API: `expect().toBe()`, `expect().toEqual()`, `expect().toHaveLength()`, `expect().toHaveProperty()` + +**Run Commands:** + +```bash +npm run test # E2E tests (Playwright, headless) +npm run test:headed # E2E tests with browser visible +npm run test:packages # All shared package unit tests (vitest) +npm run test:server # Server unit tests (vitest run) +npm run test:server:coverage # Server tests with coverage report +npm run test:all # All tests (packages + server) +npm run test:unit # Vitest run (all projects) +npm run test:unit:watch # Vitest watch mode +``` + +## Test File Organization + +**Location:** + +- Co-located with source: `src/module.ts` has `tests/unit/module.test.ts` +- Server tests: `apps/server/tests/` (separate directory) +- Library tests: `libs/*/tests/` (each package) +- E2E tests: `apps/ui/tests/` (Playwright) + +**Naming:** + +- Pattern: `{moduleName}.test.ts` for unit tests +- Pattern: `{moduleName}.spec.ts` for specification tests +- Glob pattern: `tests/**/*.test.ts`, `tests/**/*.spec.ts` + +**Structure:** + +``` +apps/server/ +├── tests/ +│ ├── setup.ts # Global test setup +│ ├── unit/ +│ │ ├── providers/ # Provider tests +│ │ │ ├── claude-provider.test.ts +│ │ │ ├── codex-provider.test.ts +│ │ │ └── base-provider.test.ts +│ │ └── services/ +│ └── utils/ +│ └── helpers.ts # Test utilities +└── src/ + +libs/platform/ +├── tests/ +│ ├── paths.test.ts +│ ├── security.test.ts +│ ├── subprocess.test.ts +│ └── node-finder.test.ts +└── src/ +``` + +## Test Structure + +**Suite Organization:** + +```typescript +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { FeatureLoader } from '@/services/feature-loader.js'; + +describe('feature-loader.ts', () => { + let featureLoader: FeatureLoader; + + beforeEach(() => { + vi.clearAllMocks(); + featureLoader = new FeatureLoader(); + }); + + afterEach(async () => { + // Cleanup resources + }); + + describe('methodName', () => { + it('should do specific thing', () => { + expect(result).toBe(expected); + }); + }); +}); +``` + +**Patterns:** + +- Setup pattern: `beforeEach()` initializes test instance, clears mocks +- Teardown pattern: `afterEach()` cleans up temp directories, removes created files +- Assertion pattern: one logical assertion per test (or multiple closely related) +- Test isolation: each test runs with fresh setup + +## Mocking + +**Framework:** + +- Vitest `vi` module: `vi.mock()`, `vi.mocked()`, `vi.clearAllMocks()` +- Mock patterns: module mocking, function spying, return value mocking + +**Patterns:** + +Module mocking: + +```typescript +vi.mock('@anthropic-ai/claude-agent-sdk'); +// In test: +vi.mocked(sdk.query).mockReturnValue( + (async function* () { + yield { type: 'text', text: 'Response 1' }; + })() +); +``` + +Async generator mocking (for streaming APIs): + +```typescript +const generator = provider.executeQuery({ + prompt: 'Hello', + model: 'claude-opus-4-5-20251101', + cwd: '/test', +}); +const results = await collectAsyncGenerator(generator); +``` + +Partial mocking with spies: + +```typescript +const provider = new TestProvider(); +const spy = vi.spyOn(provider, 'getName'); +spy.mockReturnValue('mocked-name'); +``` + +**What to Mock:** + +- External APIs (Claude SDK, GitHub SDK, cloud services) +- File system operations (use temp directories instead when possible) +- Network calls +- Process execution +- Time-dependent operations + +**What NOT to Mock:** + +- Core business logic (test the actual implementation) +- Type definitions +- Internal module dependencies (test integration with real services) +- Standard library functions (fs, path, etc. - use fixtures instead) + +## Fixtures and Factories + +**Test Data:** + +```typescript +// Test helper for collecting async generator results +async function collectAsyncGenerator(generator: AsyncGenerator): Promise { + const results: T[] = []; + for await (const item of generator) { + results.push(item); + } + return results; +} + +// Temporary directory fixture +beforeEach(async () => { + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test-')); + projectPath = path.join(tempDir, 'test-project'); + await fs.mkdir(projectPath, { recursive: true }); +}); + +afterEach(async () => { + try { + await fs.rm(tempDir, { recursive: true, force: true }); + } catch (error) { + // Ignore cleanup errors + } +}); +``` + +**Location:** + +- Inline in test files for simple fixtures +- `tests/utils/helpers.ts` for shared test utilities +- Factory functions for complex test objects: `createTestProvider()`, `createMockFeature()` + +## Coverage + +**Requirements (Server):** + +- Lines: 60% +- Functions: 75% +- Branches: 55% +- Statements: 60% +- Config: `apps/server/vitest.config.ts` with thresholds + +**Excluded from Coverage:** + +- Route handlers: tested via integration/E2E tests +- Type re-exports +- Middleware: tested via integration tests +- Prompt templates +- MCP integration: awaits MCP SDK integration tests +- Provider CLI integrations: awaits integration tests + +**View Coverage:** + +```bash +npm run test:server:coverage # Generate coverage report +# Opens HTML report in: apps/server/coverage/index.html +``` + +**Coverage Tools:** + +- Provider: v8 +- Reporters: text, json, html, lcov +- File inclusion: `src/**/*.ts` +- File exclusion: `src/**/*.d.ts`, specific service files in thresholds + +## Test Types + +**Unit Tests:** + +- Scope: Individual functions and methods +- Approach: Test inputs → outputs with mocked dependencies +- Location: `apps/server/tests/unit/` +- Examples: + - Provider executeQuery() with mocked SDK + - Path construction functions with assertions + - Error classification with different error types + - Config validation with various inputs + +**Integration Tests:** + +- Scope: Multiple modules working together +- Approach: Test actual service calls with real file system or temp directories +- Pattern: Setup data → call method → verify results +- Example: Feature loader reading/writing feature.json files +- Example: Auto-mode service coordinating with multiple services + +**E2E Tests:** + +- Framework: Playwright +- Scope: Full user workflows from UI +- Location: `apps/ui/tests/` +- Config: `apps/ui/playwright.config.ts` +- Setup: + - Backend server with mock agent enabled + - Frontend Vite dev server + - Sequential execution (workers: 1) to avoid auth conflicts + - Screenshots/traces on failure +- Auth: Global setup authentication in `tests/global-setup.ts` +- Fixtures: `tests/e2e-fixtures/` for test project data + +## Common Patterns + +**Async Testing:** + +```typescript +it('should execute async operation', async () => { + const result = await featureLoader.loadFeature(projectPath, featureId); + expect(result).toBeDefined(); + expect(result.id).toBe(featureId); +}); + +// For streams/generators: +const generator = provider.executeQuery({ prompt, model, cwd }); +const results = await collectAsyncGenerator(generator); +expect(results).toHaveLength(2); +``` + +**Error Testing:** + +```typescript +it('should throw error when feature not found', async () => { + await expect(featureLoader.getFeature(projectPath, 'nonexistent')).rejects.toThrow('not found'); +}); + +// Testing error classification: +const errorInfo = classifyError(new Error('ENOENT')); +expect(errorInfo.category).toBe('FileSystem'); +``` + +**Fixture Setup:** + +```typescript +it('should create feature with images', async () => { + // Setup: create temp feature directory + const featureDir = path.join(projectPath, '.automaker', 'features', featureId); + await fs.mkdir(featureDir, { recursive: true }); + + // Act: perform operation + const result = await featureLoader.updateFeature(projectPath, { + id: featureId, + imagePaths: ['/temp/image.png'], + }); + + // Assert: verify file operations + const migratedPath = path.join(featureDir, 'images', 'image.png'); + expect(fs.existsSync(migratedPath)).toBe(true); +}); +``` + +**Mock Reset Pattern:** + +```typescript +// In vitest.config.ts: +mockReset: true, // Reset all mocks before each test +restoreMocks: true, // Restore original implementations +clearMocks: true, // Clear mock call history + +// In test: +beforeEach(() => { + vi.clearAllMocks(); + delete process.env.ANTHROPIC_API_KEY; +}); +``` + +## Test Configuration + +**Vitest Config Patterns:** + +Server config (`apps/server/vitest.config.ts`): + +- Environment: node +- Globals: true (describe/it without imports) +- Setup files: `./tests/setup.ts` +- Alias resolution: resolves `@automaker/*` to source files for mocking + +Library config: + +- Simpler setup: just environment and globals +- Coverage with high thresholds (90%+ lines) + +**Global Setup:** + +```typescript +// tests/setup.ts +import { vi, beforeEach } from 'vitest'; + +process.env.NODE_ENV = 'test'; +process.env.DATA_DIR = '/tmp/test-data'; + +beforeEach(() => { + vi.clearAllMocks(); +}); +``` + +## Testing Best Practices + +**Isolation:** + +- Each test is independent (no state sharing) +- Cleanup temp files in afterEach +- Reset mocks and environment variables in beforeEach + +**Clarity:** + +- Descriptive test names: "should do X when Y condition" +- One logical assertion per test +- Clear arrange-act-assert structure + +**Speed:** + +- Mock external services +- Use in-memory temp directories +- Avoid real network calls +- Sequential E2E tests to prevent conflicts + +**Maintainability:** + +- Use beforeEach/afterEach for common setup +- Extract test helpers to `tests/utils/` +- Keep test data simple and local +- Mock consistently across tests + +--- + +_Testing analysis: 2026-01-27_