# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Sidekick for Max is a VS Code extension providing AI-powered inline completions, code transforms, commit messages, session monitoring, and more — using the user's existing Claude Max subscription or Anthropic API key. It also supports OpenCode and Codex CLI as inference and monitoring providers. All extension source lives in `sidekick-vscode/`. The root directory contains only documentation and assets. ## Build & Development Commands All commands run from `sidekick-vscode/`: ```bash npm run compile # Dev build with source maps (esbuild) npm run build # Production build, minified npm run watch # Watch mode for development npm test # Run all tests (Vitest) npm run test:watch # Watch mode for tests npm run lint # ESLint check npm run lint:fix # ESLint auto-fix npm run package # Create .vsix for distribution ``` Run a single test file: `npx vitest run src/services/ModelResolver.test.ts` (from `sidekick-vscode/`). Press **F5** in VS Code with `sidekick-vscode/` open to launch the Extension Development Host. ### Documentation Site The docs site uses **zensical** (not mkdocs). Config is in `mkdocs.yml` at the repo root, content in `docs/`. ```bash zensical build --strict # Build docs site (from repo root) zensical serve # Local dev server with hot reload ``` Do **not** use `mkdocs build` or `mkdocs serve` — use `zensical` instead. ## Architecture ### Build System (esbuild.js) esbuild produces four bundles: | Output | Format | Platform | |--------|--------|----------| | `out/extension.js` (from `src/extension.ts`) | CommonJS | Node.js | | `out/webview/explain.js` | IIFE | Browser | | `out/webview/error.js` | IIFE | Browser | | `out/webview/dashboard.js` | IIFE | Browser | Only `vscode` is externalized. All other dependencies (including `@anthropic-ai/claude-agent-sdk` and `@opencode-ai/sdk`) are bundled by esbuild. The `conditions: ['import']`, `banner`, and `define` settings in esbuild.js polyfill `import.meta.url` for ESM deps bundled into CJS. ### Dual Provider System Two separate provider concepts exist: 1. **Inference providers** (`InferenceProviderId` in `src/types/inferenceProvider.ts`): `claude-max | claude-api | opencode | codex` — which service generates AI completions 2. **Session providers** (`SessionProvider` in `src/types/sessionProvider.ts`): `claude-code | opencode | codex` — which CLI agent's sessions to monitor Both use auto-detection via `ProviderDetector` based on filesystem presence and most-recent mtime. ### ClaudeClient Interface All inference clients implement `ClaudeClient` from `src/types.ts`: ```typescript interface ClaudeClient { complete(prompt: string, options?: CompletionOptions): Promise; isAvailable(): Promise; dispose(): void; } ``` `AuthService` is the central entry point — lazily initializes the correct client and routes all `complete()` calls. ### Model Resolution `ModelResolver.resolveModel()` handles: `"auto"` → per-feature default tier (from `FEATURE_AUTO_TIERS`) → provider-specific model ID. Legacy names (`haiku`/`sonnet`/`opus`) map through `LEGACY_TIER_MAP`. Tiers (`fast`/`balanced`/`powerful`) map through `DEFAULT_MODEL_MAPPINGS`. Anything else passes through as a literal model ID. ### Session Monitoring Pipeline ``` CLI agent writes JSONL/DB files → SessionProvider (normalizes to ClaudeSessionEvent) → SessionMonitor (watches files, aggregates stats, emits events) → Dashboard / MindMap / KanbanBoard / TreeViews / Notifications ``` Provider implementations live in `src/services/providers/`. Each normalizes raw data into `ClaudeSessionEvent` format defined in `src/types/claudeSession.ts`. ### Request Management - **Debouncing**: Configurable delay (default 1000ms) before firing inline completion requests - **LRU cache**: `CompletionCache` — 100 entries, 30s TTL - **Cancellation**: `AbortController` linked through `CompletionOptions.signal` - **Timeouts**: `TimeoutManager` provides per-operation timeouts with context-size scaling ### Key Source Locations - **Entry point**: `src/extension.ts` — `activate()`, all command/provider registration - **Core types**: `src/types.ts` (ClaudeClient, CompletionOptions), `src/types/` (per-feature types) - **Prompt templates**: `src/utils/prompts.ts`, `src/utils/analysisPrompts.ts`, `src/utils/summaryPrompts.ts` - **Inference clients**: `src/services/AuthService.ts`, `MaxSubscriptionClient.ts`, `ApiKeyClient.ts`, `OpenCodeClient.ts`, `CodexClient.ts` (spawns CLI directly, no SDK) - **Session providers**: `src/services/providers/ClaudeCodeSessionProvider.ts`, `OpenCodeSessionProvider.ts`, `CodexSessionProvider.ts` - **Webview UI**: `src/webview/` — vanilla TS, bundled as IIFE; Chart.js for dashboard, D3.js for mind map ### Persistence Cross-session data stored in `~/.config/sidekick/`: - `historical-data.json` — token/cost/tool usage stats - `tasks/{projectSlug}.json` — kanban board carry-over - `decisions/{projectSlug}.json` — decision log ## Sidekick CLI The CLI reads from `~/.config/sidekick/` (same data as the VS Code extension). Build with `bash scripts/build-all.sh`. Source in `sidekick-shared/` (pure TS library) and `sidekick-cli/` (esbuild-bundled binary). - **npm package**: `sidekick-agent-hub` — the **binary name** is `sidekick` (defined in `sidekick-cli/package.json` `bin` field), not `sidekick-agent-hub` - **CLI discovery**: `SidekickCliService.ts` searches configured path → common paths (including nvm) → `which sidekick` - **VS Code terminal launch gotcha**: `vscode.window.createTerminal({ shellPath })` bypasses shell init (`.bashrc`/`.zshrc`), so nvm/volta `node` is not in PATH. The service injects the CLI's bin directory into the terminal `env.PATH` to fix this. ## Testing Tests use **Vitest** with co-located files (`Foo.ts` / `Foo.test.ts`). The `vscode` module must be mocked in test files using `vi.mock("vscode", ...)` since VS Code is not available in the test runner. ## Conventions - **TypeScript**: `strict: true`, target ES2022, no tsc emission (`noEmit: true` — esbuild builds) - **Linting**: ESLint 9 + typescript-eslint; `@typescript-eslint/no-explicit-any` is `warn`; unused vars prefixed with `_` are allowed - **Commits**: Conventional Commits (`feat(scope):`, `fix(scope):`, etc.) - **Branches**: `feature/`, `fix/`, `docs/`, `refactor/` prefixes - **File naming**: PascalCase for classes/services, camelCase for utilities - **Settings prefix**: All VS Code settings use `sidekick.*` ## Release Process Releases are triggered by pushing a `v*` tag to `main`. The CI workflow (`.github/workflows/release.yml`) runs four jobs: 1. **Validate Version** — verifies tag is on `main` and all three `package.json` versions match the tag 2. **Publish VS Code Extension** — lint, test, package `.vsix`, upload as artifact, publish to Open VSX 3. **Publish CLI to npm** — build shared lib, test CLI, build CLI, publish to npm (skips if version already published) 4. **Create GitHub Release** — downloads `.vsix` artifact, extracts changelog section, creates release with `.vsix` attached **Version bump checklist** (all must match the tag): - `sidekick-vscode/package.json` - `sidekick-cli/package.json` - `sidekick-shared/package.json` - `sidekick-cli/package-lock.json` and `sidekick-shared/package-lock.json` (run `npm install --package-lock-only` in each) **Changelogs to update** (four total): - `CHANGELOG.md` (root — full project) - `sidekick-vscode/CHANGELOG.md` (extension-specific) - `sidekick-cli/CHANGELOG.md` (CLI-specific) - `docs/changelog.md` (documentation site)