# Changelog

All notable changes to AiDex will be documented in this file.

## [2.1.2] - 2026-06-02

Feature + stability release. Adds the live **Debug Dashboard** and closes the WebSocket memory leak the v2.1.0/2.1.1 fixes had missed.

### Added

- **Debug Dashboard (Panel API)** — a live, fixed-slot dashboard alongside the scrolling log stream. External programs `POST /panel` with `{ id, type, value, group? }`; sending the same `id` again **overwrites the value in place** instead of scrolling away. Built for high-frequency / repeated values (audio levels, buffer fill, FPS, sensors).
  - Four widget types: **label**, **progress** (with warn/crit threshold colouring), **gauge** (radial tachometer in the MSI Afterburner / ASUS GPU Tweak style, or a pulsing status LED for string values), and **plot** (real-time line graph in the HWiNFO style with grid + min/max/avg).
  - Endpoints `POST /panel`, `POST /panels` (batch), `POST /panel/clear`. The server keeps the last state per `id`, so a freshly-connected or reloaded viewer gets the full dashboard snapshot immediately; cards with no update for ~3 s grey out as "stale". **Clear** is a full reset — a source reappears only if it re-sends widgets with their `type`.
  - New Viewer **Debug** tab (Tokyo-Night cockpit look). Plots are redrawn on a single `requestAnimationFrame` tick so audio-rate updates stay smooth. All panel broadcasts use the WS backpressure guard.
  - New files: `src/loghub/panel-types.ts`, `src/loghub/panel-store.ts`.
- **Showcase demo** (`scripts/demo-dashboard.mjs`) — an endless animation of all widget types (audio waveform, GPU gauges drifting through their zones, a signal generator cycling sine → sawtooth → triangle → square, latency spikes). A **▷ Demo** button on the Debug tab copies the run command to the clipboard. Launcher: `scripts/demo-dashboard.ps1`.

### Fixed

- **WebSocket backpressure leak in `broadcastTreeUpdate`** (`src/viewer/server.ts`): the v2.1.0 fix added a `bufferedAmount` guard to `broadcastLogEntry` and `broadcastTaskUpdate`, but `broadcastTreeUpdate` still called `client.send()` with no guard. On actively-changing projects (chokidar fires continuously while files churn) it broadcast full code + all trees (~0.5 MB/frame); a slow viewer client let ws's internal send-queue grow without bound → **50+ GB committed**. This was the dominant leak the v2.1.0 fix missed. The same guard (drop + `wsDropCounts` + rate-limited stderr) is now applied to `broadcastTreeUpdate` and `broadcastFocusTab`. Proof: `scripts/test-tree-backpressure.mjs` — unguarded 2559 MB buffered, guarded 1 MB.
- **Dashboard layout flicker**: latency spikes / growing numbers made plot-stats wrap and value rows widen, changing card height and reflowing every card below. Plot-stats are now fixed-height `nowrap` cells, value rows are `nowrap`, and the grid uses a stable `grid-auto-rows` baseline.
- **Plot-stats overlap**: a `cur` value with its unit (e.g. `-19.71 dB`) ran into the next stat. Stats are now key+value cells with a fixed gap; long values clip with an ellipsis instead of colliding.

### Tests

- `scripts/test-panel-store.mjs` (25 checks: validation, all widget types, plot ring + array frames + NaN filter + caps, snapshot, clear) and `scripts/test-panel-http.mjs` (8 checks: endpoints + error handling) cover the new panel layer. Backpressure proofs: `scripts/test-backpressure.mjs`, `scripts/test-tree-backpressure.mjs`.

## [2.1.1] - 2026-05-31

Bugfix release. C and C++ functions were silently dropped from the index — `aidex_signature` and `aidex_signatures` returned types but **zero methods** for every C/C++ file.

### Fixed

- **C/C++ function names were never extracted** (`src/parser/extractor.ts`): The generic method extractor only looked for a direct `identifier` child of a `function_definition` node. But the tree-sitter-c/c++ grammar never places the name there — it nests it under a declarator chain: `function_definition → (pointer_declarator)* → function_declarator → identifier`. As a result `name` stayed `null` and every function was discarded, so C/C++ files showed types but no methods at all.

  **Fix**: A new `findCFunctionName()` helper walks the `declarator` field chain (through any number of `pointer_declarator` / `reference_declarator` wrappers) down to the `function_declarator` and reads the real name. Applied only on the `c` / `cpp` path — other languages are untouched.

  Verified: `loghub_client.c` went from **0 → 11** functions extracted (including pointer-return functions like `uint8_t *slot_at(...)`); regression-tested against C#, TypeScript and C++ with no change to their output.

  **Action required**: Already-indexed C/C++ projects keep the old (empty) result in their DB because the file hash is unchanged and won't auto-reindex. Force a re-index with `aidex_init` (or remove + update the affected files) to pick up the now-extracted functions.

## [2.1.0] - 2026-05-19

Stability release. Two independent root causes that crashed the embedding pipeline in production — one silently killing the entire MCP server process, the other silently generating impossible memory allocations — are now both permanently prevented.

### Fixed

- **ONNX OOM killed the entire MCP server process**: Projects with large generated files (Blazor WASM bundles, large C++ translation units, minified JS) caused the ONNX runtime to request allocations of 67–93 GB of RAM. Because the ONNX model ran inside the MCP server process, the resulting `std::bad_alloc` killed the server — disconnecting Claude from every tool and requiring a manual `/mcp` reconnect. Root cause: the embedding model ran directly in the MCP server's Node.js heap with no crash isolation.

  **Fix — Worker process isolation** (`src/commands/init.ts` + `src/embeddings/embed-worker.ts`): `aidex_init({ embeddings: true })` now spawns a dedicated child process via `spawn(process.execPath, [workerPath], { stdio: ['pipe','pipe','pipe'] })` for each embedding run. The worker reads the project path from stdin as JSON, runs the full pipeline, and writes the result to stdout. When ONNX OOMs, only the worker dies — the MCP server survives and reports a Warning in the `aidex_init` result instead of crashing. A 10-minute timeout kills runaway workers automatically.

  Verified: projects that previously killed the server (`YouTubeVoiceOver`, `CiscoWebExTranslator/cpp`, `UcHome`) now complete with a Warning rather than disconnecting Claude.

- **ONNX OOM on large source files**: Even with worker isolation, files larger than ~50 KB reliably triggered the ONNX `Non-zero status code returned while running Add node` error inside the worker, causing the worker to exit with code 3228369023 (Windows `STATUS_ACCESS_VIOLATION`). Root cause: the jina-code model's attention layers allocate O(n²) memory relative to token count — a 63 KB file with deeply nested methods produces a sequence too long for the model's fixed-size buffers.

  **Fix — 25 KB file size limit** (`src/embeddings/pipeline.ts`): Methods, types, and doc-sections from files larger than 25 KB are silently skipped during embedding. File sizes are resolved once per file via `statSync` and cached for the run. The limit applies in `collectCodeWrites()`, `collectDocsWrites()`, and `updateFile()` — covering both full re-index and incremental update paths. Files below the limit are embedded normally; files above it are excluded without error or warning.

  Verified: `TwSudoku` (Blazor WASM JS bundles >1 MB + 14 C# files), `YouTubeVoiceOver` (63 KB `TranscriptProcessor.cs`), and `UcHome` (ESP32 SDK managed components) all complete cleanly. A 6-worker parallel stress test across all 252 registered projects completed in 33 minutes with 0 crashes and 0 errors.

### Added

- **`src/embeddings/embed-worker.ts`**: Standalone embedding worker entry point. Reads `{ projectPath, force? }` from stdin, calls `createRealModule().enable()` + `.indexProject()`, writes `{ ok, embedded, skipped, removed, durationMs }` (or `{ ok: false, error }`) to stdout, then exits. Has no IPC channel — crash isolation relies entirely on process separation.

### Changed

- **`aidex_init` with `embeddings: true`** no longer runs the embedding model in-process. The spawn-based worker adds ~100 ms overhead per project but eliminates the possibility of an ONNX crash affecting the MCP server.

## [2.0.1] - 2026-05-05

Bug-fix release. Two issues that surfaced when running `aidex_init({ embeddings: true })` in real-world workflows with mixed-age project DBs and concurrent calls.

### Fixed
- **Embedder crashed on legacy project DBs with "no such column"**: Projects whose `index.db` predated the v1.19a / v1.15 / archive-summary migrations crashed `aidex_init({ embeddings: true })` with `SqliteError: no such column: m.body_text` (or `tasks.summary` / `note_history.summary`). The embedder opens each project's `index.db` read-only, so the writeable `migrateLegacySchema()` path in `db/database.ts` never ran on those DBs — and the `SELECT`s in `embeddings/store.ts` referenced the missing columns directly. `openProjectIndexDb()` now opens the DB writeable briefly to apply the same idempotent ALTER TABLEs, then reopens read-only. Belt-and-suspenders: `readMethods` / `readMethodsForFile` / `readAllTasks` / `readNoteHistory` now check `PRAGMA table_info` and substitute `NULL` for missing columns, so even a locked / read-only DB no longer crashes — it just produces embeddings without the optional context fields. `migrateLegacySchema` itself was missing the `note_history.summary` ALTER and got it added.
- **Concurrent `indexProject` calls loaded N copies of the embedding model**: When several `aidex_init` (or `indexProject`) calls fired before the embedder was warm — a typical user pattern after global enable — every caller raced past the `this.embedder == null` check in `RealEmbeddings.getEmbedder()` and started its own `createEmbedder()`. Each load pulled the ~7 GB ONNX model into RAM. 14 parallel calls reproducibly produced ~98 GB RSS. Fix: the in-flight load is now cached as a `Promise<Embedder>`, so concurrent callers `await` the same load and the model is loaded exactly once. Verified with a 14-parallel stress harness: peak RSS during the run dropped from 12 GB to 92 MB; end-of-run RSS dropped from 98 GB to 12 GB.

### Added
- **Regression tests for the above** (`tests/embedder-fixes.test.js`): 12 jest tests covering legacy-schema migration on each affected table, defensive read paths when columns are missing, idempotency of `openProjectIndexDb`, and the Promise-cache mechanism that prevents the N-way embedder load.

## [2.0.0] - 2026-05-04

**Major release** — AiDex grew a brain. Semantic search across code, docs, and workspace items via locally-run embeddings (jina-code, 768d). Optional LLM layer for multilingual queries and reranking. New Settings tab in the Viewer. Schema migrated to v1.2 (additive — existing indexes keep working).

19 commits, ~8400 lines. Restore points: tag `v1.18.0-pre-bugsweep` (clean v1.18.0 working tree) and `v2.0-pre-cleanup` (mid-branch checkpoint).

### Added
- **Method body storage** (v1.19a, prerequisite for embeddings): `aidex_init` accepts `store_bodies` (or `embeddings`) flag. When enabled, full method bodies are stored in `methods.body_text` for snippet display and re-embedding. Bodies >8000 chars are truncated to head + tail. Setting persists in `metadata` so `aidex_update` continues to store bodies on incremental updates. Schema migrated to v1.1 (additive, backward compatible).
- **Embeddings module skeleton** (v1.19b): New encapsulated module `src/embeddings/` with stable public API (`getEmbeddings()`), lazy loading, and additive schema migration on `~/.aidex/global.db`. Adds the `embeddings` table and `embedding_model_id` / `embedding_dim` / `embedding_version` / `last_full_embed_at` / `files_changed_since` columns to `projects`. Model registry includes `jina-code` (default), `nomic-text`, `bge-small`. Heavy dependencies (`@xenova/transformers`, `sqlite-vec`) are declared as `optionalDependencies` and only loaded when `enable()` is called — AiDex still installs and runs without them.
- **Code embeddings** (v1.19c): `aidex_init({ embeddings: true })` and `getEmbeddings().indexProject()` produce semantic vectors for every method and type via three-tier chunking (signature + doc-comment + weighted identifier bag with string literals). Vectors live in a `vec0` virtual table per dimension (`vec_embeddings_<dim>`); metadata in the `embeddings` table joins them by rowid. Hash-based skip-on-no-change avoids redundant model calls on re-runs (~500ms for a fully cached re-index). Default model `jina-embeddings-v2-base-code` is downloaded into `~/.aidex/models` on first use. Indexing AiDex itself (402 methods + 132 types) takes ~30s on CPU, ~600ms on subsequent runs.
- **Workspace embeddings** (v1.20): Tasks, task logs, the active session note, and all archived note-history entries are embedded alongside code. `commands/task.ts` and `commands/note.ts` fire fire-and-forget `onTaskChanged` / `onNoteChanged` hooks that re-embed only the affected items. Deleted tasks and stale anchors are pruned automatically (`pruneEmbeddingsByType`). Combined index for AiDex now covers 402 methods + 132 types + 144 workspace items (35 tasks, 85 task-logs, 1 active note, 23 history entries). Semantic queries like "release process for npm publishing" return the right tasks; "visualization of progress in the browser" pinpoints the `startProgress` / `getProgressHTML` / `stopProgress` methods in `src/viewer/progress.ts`.
- **Docs embeddings** (v1.21): All Markdown / MDX files surfaced by `project_files.type='doc'` (README, CHANGELOG, CLAUDE.md, docs/**, plan/release notes, etc.) are split at heading boundaries and embedded as `doc-section`s. The chunker keeps code fences intact, sub-splits oversize sections with overlap, and prepends the document title for context — so a single retrieval is "Auth: token rotation", not just "token rotation". Stale sections and removed files are pruned via `pruneDocSectionsExcept`. AiDex's own index grew to 984 embeddings (534 code + 144 workspace + 306 doc-sections from 10 files). Hybrid retrieval works as designed: a query like "how to write logs from external programs" returns the README's `## Log Hub` section first, then the `log` method in `src/commands/log.ts`.
- **`aidex_search` MCP tool** (v1.22): New tool for semantic / exact / hybrid retrieval across embedded code, docs, and workspace items. Three modes: `semantic` (pure vec0 KNN against the query embedding), `exact` (identifier match — same as `aidex_query`), and `hybrid` (default — fuses both via Reciprocal Rank Fusion with k=60). Filters: `scope` (current project / all enabled / linked), `project_filter` (glob over project paths), `source_kinds` (code / docs / workspace), `source_types` (method, type, doc-section, task, task-log, note, note-history), and `k`. Output is a ranked list with file:line, snippet (≤180 chars), distance, and project name when scope is global. The module auto-loads on first search call — no explicit `enable()` needed for read-only use.
- **Viewer Search tab** (v1.24): Interactive embedding search inside the project Viewer. New "Search" tab in the detail panel with a debounced text input (350 ms), mode selector (Hybrid / Semantic / Exact), source-kind checkboxes (Code / Docs / Workspace), and a `k` slider (5–50). Results stream in via WebSocket (`searchEmbeddings` → `searchResults` with a `requestId` to discard stale responses). Hits render as clickable cards with a kind/type badge, distance score, file:line, and snippet — clicking a code/docs hit opens the file in the Overview tab; workspace hits switch to the Tasks tab. State survives tab switches and the panel rebuilds itself if other tabs overwrite the shared `#detail` container.
- **Code chunk display split**: The chunker now produces two separate texts — `embeddingText` (still uses weighted token repetition for the model) and `displayText` (compact `Identifiers: files (8), Filter (7), path (7), …` form for the DB and viewer). Search results stop showing the noisy "files files files files files" pattern. The `migrateDisplayText()` helper rewrites `source_text` for all existing code embeddings without re-running the model — ~130 ms for AiDex's 534 vectors.

- **Embeddings lifecycle** (v1.23): Embeddings now track and refresh themselves automatically as code, docs, and workspace items change. `aidex_update` and `aidex_remove` fire fire-and-forget hooks that re-embed the affected file (or drop it). The pipeline uses content-hash skip-on-no-change so a no-op edit costs nothing. Anchors that disappear (renamed methods, deleted sections) are pruned. `aidex_session` reports an embeddings status block (`fresh` / `drifting` / `stale`) with a human-readable hint — "55 files changed since last full embed, consider re-indexing". Model migration: `migrate({ fromModel, toModel, apply })` re-embeds every project pinned to the source model after a transactional wipe; dry-run mode reports affected counts without touching anything. The lazy-loaded module stub now auto-promotes itself to the real implementation on hooks for projects that have embeddings enabled — previously the hook silently no-op'd in fresh processes until something explicitly called `enable()`.
- **Settings tab + `aidex_settings` tool**: A single Settings tab in the viewer is now the home for all user-facing configuration — embeddings on/off and model choice, LLM provider / endpoint / API key / model, and the `llm_send_code` privacy switch. Live status probes show what's already active (e.g. "OpenAI / gpt-4o-mini from env"). A "Test connection" button verifies the LLM round-trip with latency. API keys persist to `~/.aidex/llm.json` (chmod 600). The new MCP tool `aidex_settings({ path, open: true })` opens the viewer and jumps straight to the Settings tab — so the user can say "open my AiDex settings" and the AI just calls it. First session after install/upgrade prepends a one-time welcome banner to `aidex_session` ("🎉 AiDex X.Y — new features available, open Settings to enable") that stops once the user opens Settings.
- **LLM layer** (v1.25): Optional intelligence layer over `aidex_search`. When an Anthropic / OpenAI / OpenRouter API key is configured, or a local Ollama is running, AiDex can: translate non-English queries into English (so "wie speichere ich Logs lokal" finds the right code), expand vague queries into 2-4 concrete subqueries (RRF-merged), and rerank top-N retrieval candidates. New `llm` parameter on `aidex_search` (`auto` / `off` / `translate` / `rerank` / `expand+rerank`). Per-project privacy switch `llm_send_code` (default **off**): when off, only the user's literal query and metadata (paths, names, anchors) are sent to the LLM — never source bodies, doc sections, or notes. New `aidex_init` parameters: `llm_endpoint`, `llm_model`, `llm_send_code`. Credentials discovered in this order: project config → env vars → `aidex_global_guideline` keys → `~/.aidex/llm.json` → local Ollama probe. If nothing is found, AiDex stays in pure-embeddings mode. Encapsulated in `src/llm/` with a stable `getLlm()` proxy and a strict `safety.ts` chokepoint that defensively asserts no body content leaks when `sendCode=false`.
- **HuggingFace backend**: Sixth LLM provider option, alongside Anthropic / OpenAI / OpenRouter / Ollama / Custom. Targets the OpenAI-compatible Router endpoint (`https://router.huggingface.co/v1`); auto-detected from `HF_TOKEN` (HuggingFace standard) or `HUGGINGFACE_API_KEY` env vars. Suggested model dropdown includes `Llama-3.1-8B-Instruct`, `Llama-3.3-70B-Instruct`, `Qwen2.5-Coder-32B-Instruct`, `Qwen2.5-72B-Instruct`, `Mistral-7B-Instruct-v0.3`, and `DeepSeek-V3` — but free typing works for any HF model. 503 cold-start responses surface as an explicit error with the model-loading hint. Endpoint URLs containing `huggingface.co` are recognised by `inferBackend` so per-project overrides and `~/.aidex/llm.json` entries route correctly.

### Fixed
- **`aidex_search`: semantic results no longer depend on `k`**: With small `k` (e.g. `k=5`) the KNN candidate pool was only `k * 3 = 15` vectors, while a `k=10` call pulled `30`. sqlite-vec's KNN is not strictly stable across `k` variations, so the user-facing top-5 was sometimes a *different* set than the top-5 of a `k=10` call — occasionally returning "No matches" while `k=10` returned plausible hits for the same query. Pinned the underlying KNN candidate pool to a floor of 60 (`SEMANTIC_FETCH_FLOOR`); the JS slice still trims to the user's requested `k`. Result: `aidex_search k=5` is now a proper subset of `k=10` for the same query.
- **Viewer: task description rendering**: Task descriptions in the viewer's Tasks tab were piped through `escapeHtml()` and rendered as a single wall-of-text — Markdown headings, lists, tables, and code fences collapsed into one unreadable line. Added a small inline Markdown renderer (no dependencies) that handles H1-H6, fenced + inline code, bold/italic/strikethrough, ordered/unordered lists, blockquotes, GFM tables, horizontal rules, and links. Anyone who writes multi-paragraph task descriptions sees them properly formatted now.
- **Viewer: Settings tab auto-switch via `aidex_settings({ open: true })`**: The auto-switch never fired because `readPendingFocusTab` and `writePendingFocusTab` in `src/viewer/server.ts` used `require('better-sqlite3')` inside a pure-ESM module (`"type": "module"`). Node threw `ReferenceError: require is not defined`, the surrounding silent `try/catch` returned `null`, and the metadata round-trip via `~/.aidex/global.db` was a no-op. Replaced with the existing top-level `import Database from 'better-sqlite3'` and a `getGlobalDbPath()` helper using `process.env.USERPROFILE`. The same anti-pattern in `writeLlmConfigFile` was fixed alongside.

## [1.18.0] - 2026-04-25

### Added
- **HCL/Terraform support** ([#9](https://github.com/CSCSoftware/AiDex/pull/9)): Indexes `.tf`, `.tfvars`, and `.hcl` files — now 12 supported languages
  - Blocks (`resource`, `module`, `variable`, `output`, `data`, `locals`, `provider`, ...) → types with dotted names (e.g. `resource.aws_instance.web`)
  - Function calls → methods
  - Attributes → properties
  - Block labels (incl. keyword-like names: `default`, `root`, `type`, `data`) indexed as searchable items
  - Terraform projects auto-discovered via `*.tf` and `.terraform.lock.hcl` markers in `global_init`
  - `.terraform/` excluded from indexing
  - Uses `@tree-sitter-grammars/tree-sitter-hcl` grammar

### Changed
- **tree-sitter upgrade** ([#8](https://github.com/CSCSoftware/AiDex/pull/8)): Bumped `tree-sitter` from 0.21 to 0.25 and all 10 grammar packages to latest — enables newer grammars requiring tree-sitter ^0.25.0
- **Parser refactor**: Centralized grammar mapping in `GRAMMAR_MAP` — adding a new language is now a one-line change
- **File watcher**: Viewer's live re-indexing watcher now uses `parser.isSupported()` instead of a hardcoded extension regex — automatically tracks every supported language

### Notes
- **Node.js 22+ recommended**: tree-sitter 0.25 requires native compilation; Node 24 not yet compatible. `.node-version` pins to 22.
- **`tree-sitter-c-sharp` pinned to ^0.23.1**: 0.23.5+ switched to ESM-only with top-level await, breaking CJS imports.

## [1.17.1] - 2026-04-20

### Changed
- **Node.js 18+ enforcement**: Server now exits immediately with an OS-specific install hint when run on Node <18, instead of crashing later on native modules
- **Prerequisites section**: Added to README with install commands for macOS (brew/nvm), Linux (nvm), and Windows
- **.nvmrc**: Added so `nvm use` picks the correct version automatically

## [1.17.0] - 2026-04-07

### Added
- **Task Scheduler**: Tasks can now have due dates (`due`), repeat intervals (`interval`), actions (`task_action`), and auto-execute flag (`auto_go`)
  - **Due dates**: Relative (`"3d"`, `"1w"`) or ISO date (`"2026-04-10"`)
  - **Recurring tasks**: Automatically advance due date by interval after each trigger
  - **One-shot tasks**: Due date cleared after trigger
  - **Cross-project**: Overdue tasks reported at every `aidex_session` call — even from other projects
  - **Global mirror**: `scheduled_tasks` table in `~/.aidex/global.db` for fast cross-project lookups
  - **Auto-migration**: Existing databases get new columns automatically
- **Test suite**: First tests for AiDex — 26 tests covering scheduler logic, task CRUD, global sync

## [1.16.3] - 2026-03-26

### Fixed
- **Monorepo support**: Removed `**/packages/**` from `DEFAULT_EXCLUDE` — was incorrectly blocking indexing of JS/TS monorepo workspaces (pnpm, npm workspaces, etc.) ([#4](https://github.com/CSCSoftware/AiDex/issues/4))

## [1.16.2] - 2026-03-20

### Changed
- **Auto-setup instructions overhaul**: Complete rewrite of the CLAUDE.md/GEMINI.md block installed by `aidex setup`
  - Added **Log Hub** section with full usage guide (init, query, HTTP API, Viewer integration)
  - Added missing query parameters: `modified_before`, `file_filter`, `type_filter`
  - Added `show_progress` for `global_init`
  - Added task `summary` field documentation
  - Added note `summary` field documentation
  - Updated tool count from 28 → 30
  - Updated Viewer description to include Logs tab
  - Added "Debug my app" to Question → Right Tool table
- **README**: Added `aidex_log` to Available Tools table, updated tool counts to 30
- **Projekt-CLAUDE.md**: Updated tool count to 30

## [1.16.1] - 2026-03-20

### Added
- **Log Hub consume pattern**: New `consume` parameter on `aidex_log` query — returned entries are removed from the buffer, ideal for polling without duplicates
- **Viewer: Clear Logs button**: "Clear" button in the Logs tab to reset the log display
- **Viewer: WebSocket auto-reconnect**: Viewer automatically reconnects when WebSocket connection drops (2s retry)
- **LogHub Developer Guide**: Added comprehensive integration guide to project CLAUDE.md with code examples for C#, Python, JavaScript, C/C++, PowerShell

### Fixed
- **Log entry `data: null` display**: Entries with `data: null` no longer show "null" text in Viewer and MCP output

## [1.16.0] - 2026-03-20

### Added
- **Log Hub** (`aidex_log`): Universal logging system — any program (C#, Python, Node, etc.) sends logs via HTTP POST to AiDex, queryable by the LLM via MCP tool. Zero-cost when not used — no server, no buffer, no resources until `init` is called.
  - **HTTP Server** on port 3335 (configurable): `POST /log` (single), `POST /logs` (batch), `GET /health`
  - **Ring Buffer**: In-memory circular buffer (default 10,000 entries), oldest entries overwritten
  - **Query**: Filter by `since`, `level`, `source`, `contains`, `limit` — newest first
  - **Write**: LLM can inject entries (source: "claude")
  - **Persistence**: Optional SQLite storage with 7-day auto-cleanup
  - **Viewer integration**: New "Logs" tab with WebSocket live-stream, level/source/text filters, auto-scroll

## [1.15.0] - 2026-03-17

### Added
- **Task summaries**: Tasks now support a `summary` field — a one-sentence table-of-contents entry (~150 chars) that the AI writes on create/update. `aidex_tasks` shows summaries inline so you can scan the backlog without reading full details.
- **Note history summaries**: Archived notes now get an optional `summary` field. When a note is overwritten or cleared, a summary can be provided for the archive. `aidex_note` with `history: true` shows summaries (with fallback to truncated preview for older notes). Search also matches summaries.
- **Auto-migration**: Existing databases are automatically upgraded with `ALTER TABLE ADD COLUMN summary` — no manual migration needed.
- **Viewer integration**: Task summaries shown in italic between title and description in the browser viewer.

## [1.14.0] - 2026-03-10

### Added
- **`aidex_global_guideline`**: New tool (#28) — persistent key-value store in `~/.aidex/global.db` for AI guidelines and coding conventions. Store named instructions like "review" → review checklist, "release-prep" → release steps. Actions: `set`, `get`, `list`, `delete`. Works without prior `global_init`.
- **Viewer file size limit**: `getFileContent()` now refuses files larger than 1 MB — prevents browser from freezing on large binary or generated files

### Fixed
- **Command injection in Linux screenshot tools**: All `execSync` calls with shell string interpolation replaced with `execFileSync` using argument arrays — window titles, file paths and IDs are no longer injectable via shell
- **Global query cache grows unbounded**: Cache entries are now evicted on write when they exceed the 5-minute TTL — prevents memory leak in long-running sessions
- **Viewer race condition on file change**: `pendingChanges` set is now snapshotted and cleared before processing — new events arriving during async re-indexing are no longer silently dropped
- **Viewer buildTree() N+1 queries**: Correlated subqueries for `methods` and `types` counts replaced with `LEFT JOIN` — single query instead of one subquery per file
- **WebSocket unknown message type**: Viewer now sends an error response for unrecognized message types instead of silently ignoring them
- **Viewer taskId not validated**: `updateTaskStatus` now checks `Number.isInteger(taskId)` before processing
- **Viewer mode not whitelisted**: `getTree` message mode is now constrained to `'code' | 'all'` — arbitrary values no longer passed through
- **`getProjects()` SQL injection via tag/namePattern**: `escapeLikeTerm()` now applied to both filter parameters in `global-database.ts`
- **Silent fails in viewer and global DB**: `catch {}` blocks now log errors via `console.error`
- **Git status refresh on every file event**: Added 5-second minimum interval between git status refreshes — reduces git subprocess spam during rapid file saves
- **Global query cache not invalidated after init/update**: `aidex_init` and `aidex_update` now call `invalidateGlobalCache()` so global searches immediately see fresh data

### Refactored
- **`screenshot/shared.ts`**: New module with centralized `hasTool()` and `runPowerShell()` — both use `execFileSync` (no shell). Imported by `platform-win32.ts`, `platform-linux.ts`, and `post-process.ts` — eliminates duplicate implementations
- **`normalizePath()`**: Private duplicates in `global-database.ts` and `git-status.ts` removed — both now import from `commands/shared.ts`
- **`escapeLikeTerm()`**: Exported from `commands/shared.ts` and used consistently across all LIKE queries
- **macOS sips output parsing**: Replaced shell pipe (`| tail -1 | awk`) with regex on direct `sips` output

## [1.13.0] - 2026-03-09

### Added
- **Screenshot optimization**: New `scale` (0.1-1.0) and `colors` (2/4/16/256) parameters for `aidex_screenshot`
  - Reduces file size up to 95% (e.g., 108 KB → 5 KB with `scale: 0.5, colors: 2`)
  - Black & white mode (`colors: 2`) ideal for text-only screenshots — saves thousands of tokens
  - Cross-platform post-processing: Windows (System.Drawing), macOS (sips + ImageMagick), Linux (ImageMagick)
  - Size reporting: shows original → optimized size and percentage saved
- **LLM auto-optimization strategy**: Tool description guides AI assistants to start with aggressive settings, retry if unreadable, and remember working settings per app during the session

## [1.12.1] - 2026-03-07

### Added
- **Update notifications**: `aidex_session` now shows "What's New" when AiDex was updated since the last session
  - Compares installed version with `last_seen_version` stored in project DB
  - Shows highlights + changelog link, only once per version update

## [1.12.0] - 2026-03-07

### Added
- **Auto-setup on install**: `npm install -g aidex-mcp` now automatically registers AiDex with all detected AI clients and installs AI instructions (`CLAUDE.md`, `GEMINI.md`)
  - Opt-out via `AIDEX_NO_SETUP=1` or `CI` environment variable
  - Graceful fallback: shows manual hint if auto-setup fails
- **Comprehensive AI instructions**: The CLAUDE.md block installed by `aidex setup` now covers all 27 tools
  - Decision tree: "Do I want to search code? → .aidex/ exists? → STOP, use AiDex"
  - Explicit ❌/✅ examples (never Grep when .aidex exists)
  - Search modes explained (exact/contains/starts_with)
  - Session notes, task backlog, global search, screenshots — all with examples
- **Duplicate detection**: `aidex setup` skips CLAUDE.md/GEMINI.md if manual AiDex instructions already exist (avoids double entries)

### Changed
- **Refactored commands**: Extracted shared utilities into `shared.ts` and `global-shared.ts`
  - `validateIndex()`, `noIndexError()`, `withDatabase()`, `withProjectDb()` — ~200 lines of boilerplate eliminated across 10 command files
  - `withGlobalDb()`, `EMPTY_TOTALS` — 4 global commands refactored
- **README**: Expanded "Make your AI use it" section with full best-practice instruction block

### Fixed
- **DB transactions**: `clearFileData()` and `bulkInsert*()` now wrapped in transactions
- **N+1 query**: Batch `getOccurrencesByItems()` replaces per-item queries
- **Stats query**: `getStats()` reduced from 7 queries to 1
- **SQL injection**: `global-signatures.ts` — `t.kind = '${kind}'` → parameterized query
- **Session**: Eliminated duplicate `getMetadata` calls
- **Tasks**: Added null-check for `tableInfo` result

## [1.11.0] - 2026-03-07

### Added
- **Global Search**: Search across ALL indexed projects at once — 5 new tools
  - `aidex_global_init` — Scan directory tree, register indexed projects in `~/.aidex/global.db`, detect unindexed projects by project markers (`.csproj`, `package.json`, `Cargo.toml`, etc.)
  - `aidex_global_status` — List all registered projects with stats, sortable by name/size/recent
  - `aidex_global_query` — Cross-project term search (exact/contains/starts_with) with in-memory session caching (5-min TTL)
  - `aidex_global_signatures` — Search methods/types by name across all projects, filterable by kind
  - `aidex_global_refresh` — Update stats and remove stale projects
  - Uses SQLite `ATTACH DATABASE` for zero-copy queries — each project DB remains the single source of truth
  - `exclude` parameter on `global_init` to skip external repos (e.g., `["llama.cpp"]`)
  - Auto-updates global registry after `aidex_init` / `aidex_update`
- **Bulk Indexing**: `global_init` can auto-index all unindexed projects in one call
  - `index_unindexed: true` — Auto-index projects with ≤500 code files
  - Large projects (>500 files) are listed separately for user decision
  - File count estimation uses code-only extensions (matches what `init()` actually processes)
- **Progress UI**: Browser-based progress display for bulk indexing
  - `show_progress: true` — Opens `http://localhost:3334` with live progress bar
  - Server-Sent Events (SSE) for real-time updates
  - Shows per-project status (indexing/done/error), progress bar, scrolling log
  - Dark theme, auto-closes after completion
- **Project deduplication**: Parent projects that contain sub-projects are automatically removed
  - e.g., `AudioGrabber/` is skipped when `AudioGrabber/AudioGrabber/` and `AudioGrabber/AudioGrabber2/` exist
  - Existing duplicates in global DB are cleaned up on next `global_init` run
  - Reduced test index from 215 to 167 projects (48 parent-duplicates removed)
- **Extended excludes**: Better handling of embedded runtimes and external code
  - `init.ts`: Added `**/site-packages/**`, `**/Lib/**`, `**/fdk-aac/**` to DEFAULT_EXCLUDE
  - `global-init.ts`: Added Python venvs, embedded Python runtimes (Python310-313), `.cargo`, `packages`, `fdk-aac` to DEFAULT_EXCLUDED_DIRS

## [1.10.1] - 2026-03-07

### Fixed
- **npm package**: Exclude token files and `futureWork.md` from published package
- **gitignore negation patterns**: Filter out `!` negation patterns in `.gitignore` to prevent excluding all files
  - Negation patterns (e.g., `!.vscode/settings.json`) were passed to minimatch, which interpreted `!` as "NOT this pattern" — matching ALL files
  - This caused the entire index to be purged after initialization in projects with negation patterns (common in monorepos)

## [1.10.0] - 2026-02-17

### Added
- **Note History**: Archived notes are now searchable across sessions
  - Old notes are automatically archived when overwritten or cleared
  - `history: true` parameter to browse archived notes (newest first)
  - `search: "term"` parameter to search note history (case-insensitive)
  - `limit` parameter to control how many history entries are returned (default: 20)

## [1.9.1] - 2026-02-10

### Added
- **Rect Screenshot Mode**: New `mode: "rect"` for coordinate-based screen capture
  - Specify exact `x`, `y`, `width`, `height` in pixels
  - Useful with accessibility bounds (e.g., from WinfoMCP `get_element_details`)

### Fixed
- **Region screenshot flicker on Windows**: Fixed visual flicker during interactive region selection

## [1.9.0] - 2026-02-06

### Added
- **Cross-Platform Screenshots**: New `aidex_screenshot` tool for capturing screenshots directly from AI assistants
  - 4 capture modes: `fullscreen`, `active_window`, `window` (by title), `region` (interactive selection)
  - Cross-platform: Windows (PowerShell + .NET), macOS (screencapture), Linux (maim/scrot)
  - Multi-monitor support (select monitor by index)
  - Delay parameter (wait N seconds before capture)
  - Default: Saves to temp directory with fixed filename (overwrites for quick iteration)
  - Custom filename and save path supported
  - Returns file path so AI can immediately `Read` the image
  - No project index required - standalone utility
- **Window Listing**: New `aidex_windows` tool to list all open windows
  - Shows title, PID, and process name
  - Optional substring filter (case-insensitive)
  - Helper for `aidex_screenshot` mode="window"

### Technical
- New directory module: `src/commands/screenshot/` with platform-specific implementations
- Windows: PowerShell scripts written to temp .ps1 files (avoids quoting issues with inline C#)
- macOS: Uses native `screencapture` command (interactive selection built-in)
- Linux: Uses `maim` (preferred) with `scrot` fallback; `xdotool`/`wmctrl` for window operations
- Synchronous delay via `Atomics.wait` (Node >= 18)

## [1.8.1] - 2026-02-02

### Added
- **Cancelled status** for tasks: `backlog → active → done | cancelled`
  - Cancelled tasks preserved as documentation (not deleted)
  - Viewer: collapsible ❌ Cancelled section with strikethrough styling

### Fixed
- **`aidex_update` now respects exclude patterns**: Files in `build/`, `node_modules/`, `.gitignore` patterns are rejected
  - Previously the viewer's file watcher could re-index excluded files via `aidex_update`

### Technical
- Auto-migration: existing `tasks` table CHECK constraint updated to include `cancelled`
- Exported `DEFAULT_EXCLUDE` and `readGitignore` from `init.ts` for reuse

## [1.8.0] - 2026-02-02

### Added
- **Task Backlog**: Built-in project task management persisted in AiDex database
  - `aidex_task` - Create, read, update, delete tasks with priority, tags, and descriptions
  - `aidex_tasks` - List and filter tasks by status, priority, or tag
  - **Auto-logging**: Status changes and task creation are automatically recorded in task history
  - **Manual log entries**: Add notes to any task with the `log` action
  - Priorities: high (🔴), medium (🟡), low (⚪)
  - Statuses: backlog → active → done
  - Sort order support for custom ordering within same priority
- **Viewer Tasks Tab**: Interactive task management in the browser viewer
  - Priority-colored task list grouped by status
  - Done toggle directly from the viewer
  - Tag display

### Technical
- New database tables: `tasks` and `task_log` with auto-migration
- Tasks survive between sessions (persisted in SQLite)

## [1.7.0] - 2026-02-01

### Added
- **Gemini CLI support**: `aidex setup` now detects and registers AiDex with Gemini CLI (`~/.gemini/settings.json`)
- **VS Code Copilot support**: `aidex setup` now detects and registers AiDex with VS Code (`mcp.json` with `"servers"` key and `"type": "stdio"`)

### Changed
- JSON client config is now flexible: supports custom server key (`serversKey`) and extra fields (`extraFields`) per client
- Updated README with Gemini CLI and VS Code Copilot config examples

## [1.6.1] - 2026-02-01

### Fixed
- **MCP Server version**: Now reads version dynamically from package.json (was hardcoded to 1.3.0)
- **`aidex setup` for local installs**: Detects if `aidex` is globally available; falls back to `node /full/path/index.js` when not installed globally

## [1.6.0] - 2026-02-01

### Added
- **Auto CLAUDE.md instructions**: `aidex setup` now installs AI instructions in `~/.claude/CLAUDE.md`
  - Tells Claude to auto-run `aidex_init` when no `.aidex/` exists
  - Provides tool usage guide (prefer AiDex over Grep/Glob)
  - `aidex unsetup` cleanly removes the instructions block
- **Idempotent setup**: Re-running `aidex setup` updates existing config without errors

## [1.5.2] - 2026-02-01

### Fixed
- **`aidex setup` for Claude Code**: Uses `claude mcp add --scope user` instead of editing settings.json directly
- Claude Desktop, Cursor, Windsurf still use JSON config editing

## [1.5.1] - 2026-01-31

### Fixed
- **`aidex setup`**: Now creates config file if client directory exists but config is missing (e.g. fresh Claude Code install)

## [1.5.0] - 2026-01-31

### Added
- **`aidex setup`**: Auto-register AiDex as MCP server in all detected AI clients
  - Supports: Claude Code, Claude Desktop, Cursor, Windsurf
  - Cross-platform: Windows, macOS, Linux
- **`aidex unsetup`**: Remove AiDex registration from all clients
- **Postinstall hint**: Shows `Run "aidex setup"` after npm install

## [1.4.2] - 2026-01-31

### Added
- **npm package**: Published as `aidex-mcp` on npm (`npm install -g aidex-mcp`)
- **Dual CLI commands**: Both `aidex` and `aidex-mcp` work as command names
- **npm-publish.bat**: Script for easy npm publishing

### Changed
- README updated with npm install instructions

## [1.4.1] - 2026-01-31

### Fixed
- **Git Status for Subfolder Projects**: Viewer now correctly shows git status for projects that are subdirectories of a git repo (e.g., a library inside a monorepo)
  - `isGitRepo()` now uses `simpleGit().checkIsRepo()` instead of checking for `.git` directory — traverses parent dirs
  - New `toProjectRelative()` helper maps git-root-relative paths to project-relative paths
  - Files outside the project subfolder are properly filtered out

## [1.4.0] - 2026-01-31

### Breaking Changes
- **Renamed from CodeGraph to AiDex**: Package name, MCP server name, and all internal references updated
  - MCP prefix changes from `mcp__codegraph__` to `mcp__aidex__` (requires config update)
  - Index directory changed from `.codegraph/` to `.aidex/`
  - Batch scripts renamed: `codegraph-scan.bat` → `aidex-scan.bat`, `codegraph-init-all.bat` → `aidex-init-all.bat`
  - Old `.codegraph/` directories can be safely deleted

### Added
- **Automatic Cleanup**: `aidex_init` now removes files that became excluded (e.g., build outputs)
  - Reports `filesRemoved` count in result
  - Uses minimatch for proper glob pattern matching
- **Git Status in Viewer**: File tree now shows git status with cat icons
  - 🟢 Pushed (committed and up-to-date)
  - 🟡 Modified (uncommitted changes)
  - 🔵 Staged (added to index)
  - ⚪ Untracked (new files)
- **aidex-init-all.bat**: New batch script to recursively index all git projects in a directory tree

### Changed
- Added minimatch dependency for exclude pattern handling
- Updated all documentation (README, CLAUDE.md, MCP-API-REFERENCE) with correct MCP prefix info

## [1.3.0] - 2026-01-27

### Added
- **Interactive Viewer**: New `aidex_viewer` tool opens a browser-based project explorer
  - Interactive file tree (click to expand directories)
  - Click files to view signatures (types, methods)
  - Tabs: Code files / All files, Overview / Source code
  - **Live reload** with chokidar file watcher
  - WebSocket for real-time updates
  - Syntax highlighting with highlight.js
  - Runs on `http://localhost:3333`
- **Recent Files Filter**: New `modified_since` parameter for `aidex_files`
  - Find files changed in current session: `modified_since: "30m"`
  - Supports relative time (`2h`, `1d`, `1w`) and ISO dates

### Changed
- Viewer auto-reindexes changed files before refreshing tree

### Fixed
- Server version now correctly reports 1.3.0

## [1.2.0] - 2026-01-27

### Added
- **Session Notes**: New `aidex_note` tool to persist reminders between sessions
  - Write, append, read, and clear notes
  - Stored in SQLite database (survives restarts)
  - Use cases: handover notes, test reminders, context for next session
- **Session Tracking**: New `aidex_session` tool for automatic session management
  - Detects new sessions (>5 min since last activity)
  - Records session start/end times
  - Detects files modified externally (outside sessions)
  - Auto-reindexes changed files on session start
  - Returns session note if one exists

### Changed
- Database schema: Added `metadata` table for key-value storage (session times, notes)

## [1.1.0] - 2026-01-27

### Added
- **Time-based Filtering**: New `modified_since` and `modified_before` parameters for `aidex_query`
  - Relative time: `30m`, `2h`, `1d`, `1w`
  - ISO dates: `2026-01-27` or `2026-01-27T14:30:00`
  - Track line-level changes across updates
- **Project Structure**: New `aidex_files` tool to query all project files
  - File types: `code`, `config`, `doc`, `asset`, `test`, `other`, `dir`
  - Glob pattern filtering
  - Statistics by file type

### Changed
- `aidex_init` now indexes complete project structure (all files, not just code)
- `aidex_update` preserves modification timestamps for unchanged lines (hash-based diff)
- Path normalization to forward slashes across all commands

### Technical
- New `project_files` table in database schema
- New `line_hash` and `modified` columns in `lines` table
- Hash-based change detection for accurate timestamps

## [1.0.0] - 2026-01-27

### Added
- **11 Language Support**: C#, TypeScript, JavaScript, Rust, Python, C, C++, Java, Go, PHP, Ruby
- **Core Tools**:
  - `aidex_init` - Index a project
  - `aidex_query` - Search terms (exact/contains/starts_with)
  - `aidex_signature` - Get file signatures (methods, types)
  - `aidex_signatures` - Batch signatures with glob patterns
  - `aidex_update` - Re-index single files
  - `aidex_remove` - Remove files from index
  - `aidex_summary` - Project overview with auto-detected entry points
  - `aidex_tree` - File tree with statistics
  - `aidex_describe` - Add documentation to summary
  - `aidex_status` - Index statistics
- **Cross-Project Support**:
  - `aidex_link` - Link dependency projects
  - `aidex_unlink` - Remove linked projects
  - `aidex_links` - List all linked projects
- **Discovery**:
  - `aidex_scan` - Find all indexed projects in directory tree
  - CLI commands: `scan`, `init`
- **Technical**:
  - Tree-sitter parsing for accurate identifier extraction
  - SQLite with WAL mode for fast, reliable storage
  - Keyword filtering per language (excludes language keywords from index)
  - 1MB parser buffer for large files

### Infrastructure
- MCP Server protocol implementation
- MIT License
- Comprehensive documentation
