diff --git a/.changeset/agent-transports-mcp-scaffold.md b/.changeset/agent-transports-mcp-scaffold.md deleted file mode 100644 index eac8241..0000000 --- a/.changeset/agent-transports-mcp-scaffold.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -feat(mcp): `codemap mcp` — Model Context Protocol server (agent-transports v1) - -Adds the `codemap mcp` top-level command — boots an MCP server over -stdio so agent hosts (Claude Code, Cursor, Codex, generic MCP clients) -call codemap as JSON-RPC tools instead of shelling out per query. -Eliminates the bash round-trip on every agent invocation. - -Surface (one tool per CLI verb plus `query_batch`, all snake_case): - -- `query`, `query_batch`, `query_recipe`, `audit`, `save_baseline`, - `list_baselines`, `drop_baseline`, `context`, `validate` -- Resources: `codemap://recipes`, `codemap://recipes/{id}`, - `codemap://schema`, `codemap://skill` (lazy-cached) - -`query_batch` is MCP-only — N statements in one round-trip with -batch-wide-defaults + per-statement-overrides (items are -`string | {sql, summary?, changed_since?, group_by?}`). Per-statement -errors are isolated. `save_baseline` ships as one polymorphic tool -(`{name, sql? | recipe?}` with runtime exclusivity check) mirroring -the CLI's single `--save-baseline=` verb. - -Output shape is verbatim from each tool's CLI counterpart's `--json` -envelope (no re-mapping). Bootstrap once at server boot; tool -handlers reuse existing engine entry-points (`executeQuery`, -`runAudit`, etc.) — no duplicate business logic. - -New dep: `@modelcontextprotocol/sdk`. - -HTTP API (`codemap serve`) stays in roadmap backlog; design points -(tool taxonomy + output shape) are reserved in `docs/architecture.md -§ MCP wiring` so HTTP inherits them when a concrete consumer asks. diff --git a/.changeset/codemap-audit-base.md b/.changeset/codemap-audit-base.md deleted file mode 100644 index df7c8f9..0000000 --- a/.changeset/codemap-audit-base.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`codemap audit --base ` — ad-hoc structural-drift audit against any git committish (`origin/main`, `HEAD~5`, ``, tag, …). Closes the highest-frequency post-watch agent loop: "what changed structurally between this branch and `origin/main`?". Replaces today's 3-step `--baseline` dance (switch branches, reindex, save baselines, switch back) with one verb. - -**Three transports, one engine:** - -- **CLI:** `codemap audit --base [---baseline ] [--summary] [--json] [--no-index]` -- **MCP tool:** `audit` with new `base?: string` arg -- **HTTP:** `POST /tool/audit` (auto-wired via the existing dispatcher) - -All three dispatch the same pure `runAuditFromRef` engine in `application/audit-engine.ts`. - -**How it works:** - -1. `git rev-parse --verify "^{commit}"` resolves `` to a sha (clean error on non-git or unresolvable ref). -2. Cache lookup at `/.codemap/audit-cache//.codemap.db`. Hit → sub-100ms; miss → continue. -3. **Atomic populate** — `git worktree add` to a per-pid temp dir + `runCodemapIndex({mode: "full"})` against the worktree's `.codemap.db` + POSIX `rename` claims the final `/` slot. Concurrent CI matrix runs against the same sha race-safely without lock files (loser's rename fails with EEXIST → falls through to cache hit). -4. Run each delta's canonical SQL on the cached DB vs the live DB; `diffRows` (existing helper) computes `{added, removed}`. -5. Compose `AuditEnvelope` with per-delta `base.source: "ref"` (new value) + `base.ref` (user-supplied string) + `base.sha` (resolved). - -**Decisions worth knowing:** - -- **`AuditBase` is now a discriminated union** — existing `{source: "baseline", name, sha, indexed_at}` rows untouched; new `{source: "ref", ref, sha, indexed_at}` arm. Consumers narrowing on `base.source` keep compiling. -- **Mutually exclusive with `--baseline `.** Parser + handler both guard. Per-delta `---baseline` overrides compose orthogonally with both, so `--base origin/main --files-baseline pre-refactor-files` is valid (mixed sources). -- **Eviction:** hardcoded LRU 5 entries / 500 MiB; `git worktree remove --force` + `rm -rf` for each victim. Orphan `.tmp.*` dirs older than 10 min get swept on the next cycle. No config knobs in v1; defer to v1.x+ if real consumers ask. -- **Hard error on non-git projects.** No graceful fallback — there's no meaningful "ref" without git. The other audit modes (`--baseline`, `---baseline`) still work without git. -- **Env hygiene.** All git spawns in `audit-worktree.ts` strip inherited `GIT_*` env vars so a containing git operation (e.g. running codemap from a husky hook) doesn't route worktree calls at the wrong index. - -**Auto-`.gitignore`:** `codemap agents init` now adds `.codemap/audit-cache/` alongside `.codemap.*` so cached worktrees never get committed. `.codemap/recipes/` stays git-tracked. - -Plan: PR #51 (merged). Implementation: PR #52. diff --git a/.changeset/codemap-audit-v1.md b/.changeset/codemap-audit-v1.md deleted file mode 100644 index b06f94d..0000000 --- a/.changeset/codemap-audit-v1.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -`codemap audit` (B.5 v1) — structural-drift command emitting `{head, deltas}` where each `deltas[]` carries `{base, added, removed}`. Three v1 deltas: `files`, `dependencies`, `deprecated`. Two snapshot-source shapes — `--baseline ` (auto-resolves `-files` / `-dependencies` / `-deprecated` in `query_baselines`) and `---baseline ` (explicit per-delta override; composes with `--baseline`). Reuses B.6 baselines; no schema bump. `--summary` collapses to per-delta counts; `--no-index` skips the auto-incremental-index prelude. v1 ships no `verdict` / threshold config — consumers compose `--json` + `jq` for CI exit codes (v1.x slice). `--base ` (worktree+reindex snapshot) defers to v1.x. diff --git a/.changeset/codemap-dir-consolidation.md b/.changeset/codemap-dir-consolidation.md deleted file mode 100644 index 6bd989e..0000000 --- a/.changeset/codemap-dir-consolidation.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`.codemap/` directory consolidation + self-healing files. Every codemap-managed path lives under a single configurable state directory (default `.codemap/`, override via `--state-dir ` or `CODEMAP_STATE_DIR`). Cleans up the dual-pattern surface (`/.codemap.db` + `/.codemap//`) that's been growing with every cache PR; collapses the user `.gitignore` patching surface to zero. - -**New layout:** - -``` -/ -└── .codemap/ ← override via --state-dir / CODEMAP_STATE_DIR - ├── .gitignore ← codemap-managed (self-healing); tracked - ├── config.{ts,js,json} ← was /codemap.config.*; tracked - ├── recipes/ ← user-authored SQL; tracked (existing) - ├── index.db ← was .codemap.db - ├── index.db-shm ← was .codemap.db-shm - ├── index.db-wal ← was .codemap.db-wal - └── audit-cache/ ← was .codemap/audit-cache/ (existing) -``` - -**Self-healing files (D11):** `/.gitignore` and `/config.json` are owned by idempotent `ensure*` reconcilers (`src/application/state-dir.ts`, `src/application/state-config.ts`) that run on every codemap boot — read → validate → reconcile → write only on drift. **The setup logic IS the migration**: future codemap versions add new generated artifacts to `STATE_GITIGNORE_BODY` (or extend the Zod schema), and every consumer's project repairs itself on the next `codemap` invocation. No more per-feature `.gitignore` patching in `agents-init.ts`. - -**Pre-v1 — no migration shim:** - -- `/.codemap.db` → `/index.db` (rename basename) -- `/codemap.config.{ts,json}` → `/config.{ts,js,json}` (move file) -- Existing dev clones: `rm .codemap.db .codemap.db-shm .codemap.db-wal` once and re-index; move `codemap.config.*` into `.codemap/` (or set `--config ` to keep using the legacy location explicitly). - -**New flags + env:** - -- `--state-dir ` — override the state directory (resolves relative to project root). -- `CODEMAP_STATE_DIR` — same, env-var form. - -**Internal refactor:** new `src/cli/bootstrap-codemap.ts` extracts the `loadUserConfig + resolveCodemapConfig + initCodemap + configureResolver` dance from 9 cmd-\* files into one helper that also runs the self-healing reconcilers. Adding a new self-healing file is now a one-line addition there. - -Inspired by flowbite-react's `.flowbite-react/.gitignore` + `setup-*` pattern; expressed in codemap's own conventions (`ensure*` reconcilers, Zod schema as `z.infer` source of truth, pure `{before, after, written}` return shapes for testability). - -Plan: PR #53 (merged). Implementation: PR #54. diff --git a/.changeset/codemap-impact.md b/.changeset/codemap-impact.md deleted file mode 100644 index 7b3c59d..0000000 --- a/.changeset/codemap-impact.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`codemap impact ` — symbol/file blast-radius walker. Replaces hand-composed `WITH RECURSIVE` queries that agents struggle to write reliably with a single verb that walks the calls / dependencies / imports graphs (callers, callees, dependents, dependencies). Depth- and limit-bounded, cycle-detected. - -**Three transports, one engine:** - -- **CLI:** `codemap impact [--direction up|down|both] [--depth N] [--via dependencies|calls|imports|all] [--limit N] [--summary] [--json]` -- **MCP tool:** `impact` (registered alongside `show` / `snippet`) -- **HTTP:** `POST /tool/impact` - -All three dispatch the same pure `findImpact` engine in `application/impact-engine.ts` per the post-PR #41 layering — adding tools never duplicates business logic. - -**Decisions worth knowing:** - -- **Target auto-resolution.** Contains `/` or matches `files.path` → file target; otherwise symbol (case-sensitive, exact). Symbol targets walk `calls`; file targets walk `dependencies` + `imports` (`resolved_path` only). Mismatched explicit `--via` choices land in `skipped_backends` (no error — agent sees why their selection yielded fewer rows than expected). -- **Cycle detection.** SQLite has no native cycle predicate; we materialise a comma-bounded path string per row and `instr` it to break re-entry. Bounded depth + `--limit` (default 500) keep cyclic graphs cheap regardless. `--depth 0` walks unbounded but stays cycle-detected and limit-capped. -- **Termination classification.** `summary.terminated_by`: `limit` > `depth` > `exhausted`. CI gates can branch on it. -- **`--summary` shape.** Trims the `matches` array but preserves `summary.nodes` — the `jq '.summary.nodes'` consumption pattern still works. -- **No SARIF / annotations.** Impact rows are graph traversals, not findings — wrong shape for those formats. - -**Engine sketch:** one `WITH RECURSIVE` query per (direction, backend) combo, JS-side merge + dedup by `(direction, kind, name?, file_path)` keeping the shallowest depth, then `summary.by_kind` + `terminated_by` classification. - -Plan: PR #49 (merged). Implementation: PR #50. diff --git a/.changeset/codemap-serve.md b/.changeset/codemap-serve.md deleted file mode 100644 index 91ec011..0000000 --- a/.changeset/codemap-serve.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`codemap serve` — HTTP server exposing the same tool taxonomy as `codemap mcp` over `POST /tool/{name}`. For non-MCP consumers (CI scripts, simple `curl`, IDE plugins that don't speak MCP). - -Default bind `127.0.0.1:7878` (loopback only — refuse `0.0.0.0` unless explicitly opted in via `--host 0.0.0.0`). Optional `--token ` requires `Authorization: Bearer ` on every request; `GET /health` is auth-exempt so liveness probes work without leaking the token. Bare `node:http` (no Express / Fastify dep) — runs on Bun + Node. - -**Routes:** - -- `POST /tool/{name}` — every MCP tool (query, query_recipe, query_batch, audit, context, validate, show, snippet, save_baseline, list_baselines, drop_baseline). Body `{}`; response = same `codemap query --json` envelope (NOT MCP's `{content: [...]}` wrapper). `format: "sarif"` payloads ship as `application/sarif+json`; `format: "annotations"` as `text/plain`. -- `GET /resources/{encoded-uri}` — mirror of MCP resources (`codemap://recipes`, `codemap://recipes/{id}`, `codemap://schema`, `codemap://skill`). -- `GET /health` — liveness (auth-exempt); `GET /tools` / `GET /resources` — catalogs. -- Errors: `{"error": "..."}` with HTTP status 400 / 401 / 404 / 500. -- Every response carries `X-Codemap-Version: ` so consumers can pin / detect upgrades. - -**Internals:** Tool bodies (`application/tool-handlers.ts`) and resource fetchers (`application/resource-handlers.ts`) are pure transport-agnostic — same handlers `codemap mcp` dispatches. No engine duplication; `mcp-server.ts` and `http-server.ts` both wrap the same `ToolResult` discriminated union. - -**Security:** CSRF + DNS-rebinding guard rejects requests with `Sec-Fetch-Site: cross-site` / `same-site` (modern-browser CSRF), any `Origin` header that isn't `null` (older-browser CSRF), and `Host` header mismatch on loopback bind (DNS rebinding) — runs on every request including auth-exempt `/health`. Defends against a malicious local webpage `fetch`-ing the API while the developer is browsing. Non-browser clients (curl, MCP hosts, CI scripts) don't send those headers and pass through. SIGINT / SIGTERM → graceful drain. 1 MiB request-body cap (DoS protection). SQLite reader concurrency handles parallel requests; `PRAGMA query_only = 1` set per connection. diff --git a/.changeset/codemap-watch.md b/.changeset/codemap-watch.md deleted file mode 100644 index d2e8551..0000000 --- a/.changeset/codemap-watch.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`codemap watch` — long-running process that re-indexes changed files in real time so every CLI / MCP / HTTP query reads live data without a per-query reindex prelude. Eliminates the single biggest source of agent-side friction: "is the index stale right now?" - -**Three shapes:** - -- **Standalone**: `codemap watch [--debounce 250] [--quiet]` — foreground process; logs `reindex N file(s) in Mms` per batch unless `--quiet`. SIGINT / SIGTERM drains pending edits. -- **MCP killer combo**: `codemap mcp --watch [--debounce ]` — boots stdio MCP server + watcher in one process. Long Cursor / Claude Code sessions never hit a stale index; agents stop having to remember to reindex between edit + query. -- **HTTP killer combo**: `codemap serve --watch [--debounce ]` — same shape for non-MCP consumers (CI scripts, IDE plugins, simple `curl`). - -**Audit prelude optimization:** when watch is active, `mcp audit`'s default incremental-index prelude becomes a no-op (the watcher already keeps the index fresh — saves the per-request reindex cost). Explicit `no_index: false` still forces the prelude. - -**Env shortcut:** `CODEMAP_WATCH=1` (or `"true"`) implies `--watch` for `mcp` / `serve` — useful for IDE / CI launches that can't easily edit the spawn command. - -**Backend:** [chokidar v5](https://github.com/paulmillr/chokidar) (selected via 6-watcher audit in PR #46). Pure JS — runs identically on Bun + Node, no per-runtime branching, no native compile matrix on top of `bun:sqlite` / `better-sqlite3`. Cross-platform (macOS / Linux / Windows / WSL). Atomic-write + chunked-write detection out of the box. 1 dep (`readdirp`), 82 KB. - -**Filtering:** Only paths the indexer cares about trigger a reindex (TS / TSX / JS / JSX / CSS + project-local recipes under `/.codemap/recipes/`). `node_modules` / `.git` / `dist` / configured `excludeDirNames` are skipped. diff --git a/.changeset/coverage-ingestion.md b/.changeset/coverage-ingestion.md deleted file mode 100644 index 860cb71..0000000 --- a/.changeset/coverage-ingestion.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`codemap ingest-coverage ` — static coverage ingestion. Reads Istanbul JSON (`coverage-final.json`) or LCOV (`lcov.info`) into a new `coverage` table joinable to `symbols`, so structural queries can compose coverage filters in pure SQL — no runtime tracer, no paid coverage stack. - -**Both formats land in v1** (Istanbul + LCOV) so every test runner is a first-class consumer on day one — `vitest --coverage`, `jest --coverage`, `c8`, `nyc` (Istanbul JSON), and `bun test --coverage` (LCOV) all work without waiting on a follow-up release. - -**Bundled recipes (auto-discovered, no opt-in needed):** - -- `untested-and-dead` — exported functions with no callers AND zero coverage; the killer recipe combining structural and runtime evidence axes. -- `files-by-coverage` — files ranked ascending by statement coverage. -- `worst-covered-exports` — top-20 worst-covered exported functions. - -Each recipe ships a frontmatter `actions` block so agents see per-row follow-up hints in `--json` output. - -**Schema:** - -- New `coverage` table with natural-key PK `(file_path, name, line_start)` — intentionally not a FK to `symbols.id` so coverage rows survive the `symbols` drop-recreate cycle on every `--full` reindex. -- `idx_coverage_file_name` covers the typical join shape and the `GROUP BY file_path` scan used by the `files-by-coverage` recipe. -- Three new `meta` keys (`coverage_last_ingested_at` / `_path` / `_format`) record ingest freshness. -- `SCHEMA_VERSION` 5 → 6 — auto-rebuilds on next `codemap` run; the new table is empty until first `ingest-coverage` invocation. Subsequent bumps preserve coverage data via the `dropAll()` exclusion. - -**CLI:** - -```bash -codemap ingest-coverage coverage/coverage-final.json # Istanbul (auto-detected) -codemap ingest-coverage coverage/lcov.info # LCOV (auto-detected) -codemap ingest-coverage coverage --json # directory probe (errors if both files present) - -codemap query --json --recipe untested-and-dead # the killer query -``` - -No `--source` flag — format is auto-detected from extension. No MCP / HTTP transport in v1 — coverage exposes as a SQL column, composable with every existing recipe and ad-hoc query through the existing `query` / `query_recipe` tools (no parallel surface). - -Plan: PR #56 (merged). Implementation: this PR. diff --git a/.changeset/cyclomatic-complexity.md b/.changeset/cyclomatic-complexity.md deleted file mode 100644 index 5b63b9f..0000000 --- a/.changeset/cyclomatic-complexity.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -feat(complexity): cyclomatic complexity column on `symbols` + bundled recipe (research note § 1.4 ship-pick (c)) - -Adds per-function cyclomatic complexity computed during AST walking. Schema bump `SCHEMA_VERSION` 7 → 8 — first reindex after upgrade triggers a full rebuild via the existing version-mismatch path. - -**What lands:** - -- New `complexity REAL` column on `symbols`. Computed via McCabe formula (`1 + decision points`) for function-shaped symbols (top-level `function` declarations + arrow-function consts). `NULL` for non-functions (interfaces, types, enums, plain consts) and class methods (v1 limitation; documented in the recipe `.md`). -- Decision points counted: `if`, `while`, `do…while`, `for`, `for…in`, `for…of`, `case X:` arms (not `default:` fall-through), `&&` / `||` / `??` short-circuit operators, `?:` ternary, `catch` clauses. -- New bundled recipe `high-complexity-untested` — function-shaped symbols with complexity ≥ 10 AND measured coverage < 50%. Combines structural + runtime evidence axes; surfaces refactor-priority candidates that single-axis recipes (`untested-and-dead`, `worst-covered-exports`) miss because they're "called but undertested." - -**Implementation:** - -- Parser visitor (`src/parser.ts`) maintains a `complexityStack` keyed by symbol index. On function entry, pushes counter at 1 + symbol index. Branching-node visitors increment the top counter. On function exit, pops and writes complexity into the symbol row already pushed during entry. -- Nested function declarations get their own stack entries — inner branches don't count toward the outer function. (Standard McCabe — each function counted independently.) - -**Pre-v1 patch** per `.agents/lessons.md` "changesets bump policy": schema-bumping changes are minor in semver but pre-v1 we default to patch unless the bump forces a `.codemap.db` rebuild. This one does (column added; auto-detected by `createSchema()` mismatch path) — every consumer's first run after upgrade re-indexes from scratch. - -Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` codemap rule + skill mention the `complexity` column, the new recipe, and the cyclomatic-complexity definition. - -**Out of scope:** - -- **Class method complexity** — `MethodDefinition` visitor currently doesn't push to the complexity stack. Documented in `high-complexity-untested.md` v1 limitation; refactor opportunity for class-heavy projects. -- **Per-class / per-file rollups** — `complexity` is per-symbol; project-local recipes can `SUM` / `AVG` it as needed. diff --git a/.changeset/fts5-mermaid.md b/.changeset/fts5-mermaid.md deleted file mode 100644 index d7a24b2..0000000 --- a/.changeset/fts5-mermaid.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -feat(fts5+mermaid): opt-in FTS5 virtual table + Mermaid output formatter - -Implements the FTS5+Mermaid plan ([`docs/plans/fts5-mermaid.md`](https://github.com/stainless-code/codemap/blob/main/docs/plans/fts5-mermaid.md)) — two non-goal flips in one PR. - -**FTS5 (opt-in, default OFF):** - -- New `source_fts` virtual table — `(file_path UNINDEXED, content)` columns, `tokenize='porter unicode61'`. Always created; populated only when toggle is on. -- Toggle via `codemap.config.ts` `fts5: true` OR `--with-fts` CLI flag at index time. CLI overrides config (logs stderr line on override). -- Indexer tees file content into `source_fts` in same transaction as `files` row insert (atomic). Worker → main serialization cost is zero on default-OFF path. -- Toggle-change auto-detect via `meta.fts5_enabled` — flipping `fts5: false → true` auto-upgrades incremental → full rebuild so `source_fts` is consistently populated. -- DB-size telemetry on first FTS5 populate: `[fts5] source_fts populated: files / KB`. -- Bundled demo recipe `text-in-deprecated-functions` — `@deprecated` functions in files containing `TODO`/`FIXME`/`HACK` markers AND coverage `<50%`. Demonstrates FTS5 ⨯ `symbols` ⨯ `coverage` JOIN composability that ripgrep can't match. - -**Mermaid output formatter:** - -- New `--format mermaid` output mode. Renders `{from, to, label?, kind?}` row-shape as `flowchart LR`. -- **Bounded-input contract** (50-edge ceiling, `MERMAID_MAX_EDGES`): unbounded inputs reject with a scope-suggestion error naming the recipe + count + scoping knobs (`LIMIT` / `--via` / `WHERE`). Auto-truncation deliberately out of scope (would be a verdict masquerading as an output mode). -- Available across CLI, MCP `query` / `query_recipe` tools, HTTP `POST /tool/query` (text/plain content type). - -Schema bump: `SCHEMA_VERSION` 6 → 7. First reindex after upgrade triggers a full rebuild via the existing version-mismatch path; existing `.codemap/index.db` is preserved (only schema-managed tables get dropped + recreated). - -**Pre-v1 patch** per `.agents/lessons.md` "changesets bump policy" — additive feature, default-OFF for FTS5, behaviour-preserving for existing users (`--with-fts` is opt-in; Mermaid is a new output mode). - -Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` mention `--with-fts`, `--format mermaid`, the new bundled recipe, and the bounded-input contract. diff --git a/.changeset/lift-cli-to-application.md b/.changeset/lift-cli-to-application.md deleted file mode 100644 index 10e41a4..0000000 --- a/.changeset/lift-cli-to-application.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -Internal refactor — lift `cli/*` envelope builders + path helpers into `application/*` engines so `application/mcp-server.ts` no longer reaches sideways into `cli/`. Affected modules: `audit-engine` (added `resolveAuditBaselines`), new `context-engine` (`buildContextEnvelope`, `classifyIntent`, `ContextEnvelope`), new `validate-engine` (`computeValidateRows`, `toProjectRelative`), `show-engine` (added `buildShowResult`, `buildSnippetResult`, `ShowResult`, `SnippetResult`, `SnippetMatch`), `query-recipes` moved from `cli/` to `application/`. CLI verbs stay shells (parse / help / run / render). No behavior change, no public API change — `cli/cmd-*` and `application/*` are internal modules; the published surface (`api.ts`, the `codemap` binary, the MCP server) is untouched. diff --git a/.changeset/mcp-resources-files-symbols.md b/.changeset/mcp-resources-files-symbols.md deleted file mode 100644 index c577d50..0000000 --- a/.changeset/mcp-resources-files-symbols.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -feat(mcp): add `codemap://files/{path}` + `codemap://symbols/{name}` resources (research note § 1.8) - -Two new MCP / HTTP resources for direct agent reads — saves the recipe-compose round-trip when the agent just wants "everything about this file" or "where is this symbol?". - -- **`codemap://files/{path}`** — per-file roll-up. Returns `{path, language, line_count, symbols, imports, exports, coverage}`. `imports.specifiers` parsed inline (callers don't have to JSON.parse). `coverage` is `{measured_symbols, avg_coverage_pct, per_symbol}` when coverage was ingested, else `null`. URI-encode the path. -- **`codemap://symbols/{name}`** — symbol lookup by exact name. Returns `{matches, disambiguation?}` envelope (same shape as the `show` verb per PR #39). Optional `?in=` query parameter mirrors `show --in ` (directory prefix or exact file). - -Both reuse existing infrastructure (no schema bump): `codemap://files/` queries the existing tables; `codemap://symbols/` reuses `findSymbolsByName` + `buildShowResult` from `application/show-engine.ts`. - -**Caching policy:** catalog-style resources (`recipes`, `schema`, `skill`) lazy-cache as before. Data-shaped resources (`files/`, `symbols/`) read live every call — no caching, since the index can change between requests under `--watch`. - -Both available over MCP `read_resource` and HTTP `GET /resources/{encoded-uri}` via the existing dispatcher (no new transport plumbing). - -Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` codemap rule + skill mention the new resource templates + caching policy. diff --git a/.changeset/mcp-serve-help-parity.md b/.changeset/mcp-serve-help-parity.md deleted file mode 100644 index dab6f41..0000000 --- a/.changeset/mcp-serve-help-parity.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -docs(cli): `mcp --help` and `serve --help` now list every shipped tool + resource - -Stale help text in `src/cli/cmd-mcp.ts` and `src/cli/cmd-serve.ts` listed the original v1 tool / resource taxonomy. Updated to match what's registered today (verified against `src/application/mcp-server.ts`): - -- **`mcp --help` Tools section** now includes `show`, `snippet`, `impact` (was missing all three). -- **`mcp --help` Resources section** now distinguishes lazy-cached catalog resources (`recipes`, `recipes/{id}`, `schema`, `skill`) from live read-per-call resources (`files/{path}`, `symbols/{name}`) — was listing only the original four. -- **`serve --help` Routes section** now includes `POST /tool/impact` (was missing) and lists every mirrored MCP resource explicitly under `GET /resources/{encoded-uri}` (was a `...` ellipsis). - -No behavior change — purely a documentation accuracy fix. Bundled agent rule + skill (`templates/agents/` and `.agents/`) already enumerate the six resources correctly. diff --git a/.changeset/mcp-serve-watch-default-on.md b/.changeset/mcp-serve-watch-default-on.md deleted file mode 100644 index d68986c..0000000 --- a/.changeset/mcp-serve-watch-default-on.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -feat(mcp/serve): default-ON watcher for `codemap mcp` and `codemap serve` - -Stale-index friction is empirically the most-frequent agent UX issue under `codemap mcp` (driving the watch-mode planning in PR #46) and the most-frequent CI/IDE-plugin friction under `codemap serve`. Both modes are inherently long-running, so the chokidar co-process pays for itself immediately. Decision originally resolved 2026-05 (research note `§ 6 Q1`); this PR ships it. - -**New defaults.** - -- `codemap mcp` — watcher boots automatically; tools always read a live index. -- `codemap serve` — same. -- One-shot CLI defaults preserved: `codemap query` / `codemap show` / `codemap snippet` / etc. still spawn no watcher. - -**Opt out.** - -- `--no-watch` flag (new) — explicit opt-out for ephemeral-index workflows, fire-and-forget CI scripts, etc. -- `CODEMAP_WATCH=0` / `CODEMAP_WATCH="false"` — env-shortcut mirroring `--no-watch` for IDE / CI launches that can't easily edit the spawn command. - -**Backwards-compat preserved.** - -- `--watch` flag still parses and is honored (no-op since it matches the new default; kept so existing scripts and launch commands don't break). -- `CODEMAP_WATCH=1` / `CODEMAP_WATCH="true"` still parses (redundant after the flip, kept for backwards-compat). -- `--no-watch` wins over `--watch` when both passed (last-write semantics). - -**Tradeoffs accepted.** - -- Slightly slower mcp/serve startup (~chokidar boot cost, validated tiny on Bun + Node by PR #46's 6-watcher audit). -- Spawns a second process — visible to users running `htop` / `Activity Monitor`. Worth it for the live-index correctness gain. - -**Tests:** 12 new tests across `cmd-mcp.test.ts` and `cmd-serve.test.ts` cover default-ON behavior, `--no-watch` opt-out, env opt-out (`CODEMAP_WATCH=0` / `"false"`), env opt-in still honored (`CODEMAP_WATCH=1`), and `--no-watch` wins over `--watch`. - -**Lockstep updates:** `templates/agents/rules/codemap.md`, `templates/agents/skills/codemap/SKILL.md`, `.agents/rules/codemap.md`, `.agents/skills/codemap/SKILL.md`, and `README.md` all updated to reflect the new defaults + opt-out shape per `docs/README.md` Rule 10. diff --git a/.changeset/query-baselines.md b/.changeset/query-baselines.md deleted file mode 100644 index 3802a07..0000000 --- a/.changeset/query-baselines.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`codemap query --save-baseline` / `--baseline` — snapshot a query result set and diff against it later. Stored in the new `query_baselines` table inside `.codemap.db` (no parallel JSON files). `--baselines` lists saved snapshots, `--drop-baseline ` deletes one. Diff identity is per-row `JSON.stringify` equality; `--summary` collapses to `{added: N, removed: N}`. Recipe `actions` attach to the `added` rows when running under `--baseline`. Baselines survive `--full` and SCHEMA rebuilds. `SCHEMA_VERSION` bumps from 4 to 5. diff --git a/.changeset/recipes-content-registry.md b/.changeset/recipes-content-registry.md deleted file mode 100644 index 3df4ba0..0000000 --- a/.changeset/recipes-content-registry.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -feat(recipes): recipes-as-content registry — bundled .md siblings + project-local recipes - -Two complementary capabilities: - -1. **Bundled recipes get richer descriptions.** Every bundled recipe in - `templates/recipes/` is now a `.sql` file paired with an optional - `.md` description body (replaces the inline TypeScript map in - `src/cli/query-recipes.ts`). Per-row `actions` templates live in YAML - frontmatter on the `.md` instead of code. Same surface for end users - (`--recipe ` / `--recipes-json` / `codemap://recipes`); single - storage shape across bundled + project recipes. - -2. **Project-local recipes** — drop `.{sql,md}` files into - `/.codemap/recipes/` to ship team-internal SQL as first- - class recipes. Auto-discovered via `--recipe `, surfaced in - `--recipes-json` and the `codemap://recipes` MCP resource alongside - bundled. Project recipes win on id collision; the catalog entry - carries `shadows: true` on overrides so agents reading the catalog - at session start see when a recipe behaves differently from the - documented bundled version (per-execution response shape stays - unchanged — uniformity contract preserved). - -Catalog entries (`--recipes-json` output, `codemap://recipes` -payload) gain three additive fields: `body` (full Markdown body), -`source` (`"bundled" | "project"`), and `shadows?` (true on -project entries that override a bundled id). Existing consumers -that destructure `{id, description, sql, actions?}` keep working. - -Validation: load-time lexical scan rejects DML / DDL keywords -(`INSERT` / `UPDATE` / `DELETE` / `DROP` / `CREATE` / `ALTER` / -`ATTACH` / `DETACH` / `REPLACE` / `TRUNCATE` / `VACUUM` / `PRAGMA`) -in recipe SQL with recipe-aware error messages — defence in depth -alongside the runtime `PRAGMA query_only=1` backstop in -`query-engine.ts` shipped in the previous release. - -Implementation: pure transport-agnostic loader in -`src/application/recipes-loader.ts`; thin shim in -`src/cli/query-recipes.ts` preserves backwards-compat exports -(`QUERY_RECIPES`, `getQueryRecipeSql`, etc.). Hand-rolled YAML -frontmatter parser scoped to the `actions` shape (no `js-yaml` -dependency). - -`.codemap.db` is gitignored as before; `.codemap/recipes/` is NOT -(verified via `git check-ignore`) — recipes are git-tracked source -code authored for human review. diff --git a/.changeset/recipes-from-research-note.md b/.changeset/recipes-from-research-note.md deleted file mode 100644 index 7dc264b..0000000 --- a/.changeset/recipes-from-research-note.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -feat(recipes): ship two new bundled recipes from research note § 1 - -- **`components-touching-deprecated`** (research note § 1.1) — UNION of two paths surfacing components that touch `@deprecated` symbols: hook path (`components.hooks_used` JSON overlap) + call path (`calls.caller_name = component`, `callee_name` is `@deprecated`). Hook-only variants ship false negatives — recipe spells out the explicit UNION. Action template `review-deprecation-impact`. -- **`refactor-risk-ranking`** (research note § 1.4) — per-file ranking by `(fan_in + 1) × (100 - avg_coverage_pct)`. Three correctness fixes vs the naïve formula: orphans (`fan_in = 0`) score on coverage alone via `+1`; NULL `coverage_pct` treated as 0% via `COALESCE` (otherwise the row drops from `ORDER BY`); files with no exports excluded (no public-API surface to refactor externally). Output is per-file (not per-symbol) — empirical test showed per-symbol ranking ties on file-level fan_in. Per-symbol via `calls` is a documented tuning axis for project-local override. Action template `review-refactor-impact`. - -Both recipes use only existing substrate (`components`, `calls`, `symbols`, `dependencies`, `coverage`, `files`) — no schema bump. Bundled recipe content follows the existing recipe-as-content registry pattern (PR #37); project-local overrides live at `/.codemap/recipes/.{sql,md}`. - -Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` (ships to npm via `codemap agents init`) and `.agents/` (this clone's mirror) gain trigger-pattern entries, quick-reference rows, and recipe-id list updates. diff --git a/.changeset/sarif-formatter.md b/.changeset/sarif-formatter.md deleted file mode 100644 index 89aa791..0000000 --- a/.changeset/sarif-formatter.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -`codemap query --format ` — pipe any recipe row-set into GitHub Code Scanning (SARIF 2.1.0) or surface findings inline on PRs (GH Actions `::notice file=…,line=…::msg`). Pure output-formatter additions on top of the existing JSON pipeline; no schema impact. - -Auto-detects file-path columns (`file_path` / `path` / `to_path` / `from_path` priority) and `line_start` (+ optional `line_end`) for SARIF region. Aggregate recipes without locations (`index-summary`, `markers-by-kind`) emit `results: []` + a stderr warning. Rule id is `codemap.` for `--recipe`, `codemap.adhoc` for ad-hoc SQL. Default `result.level` is `"note"`; per-recipe overrides via `.md` frontmatter (`sarifLevel`, `sarifMessage`, `sarifRuleId`) deferred to v1.x. - -`--format` overrides `--json` when both passed; `--json` stays as the alias for `--format json`. Incompatible with `--summary` / `--group-by` / baseline (different output shapes — sarif/annotations only support flat row lists). - -MCP `query` and `query_recipe` tools accept the same `format: "sarif" | "annotations"` argument; `query_batch` deferred to v1.x. diff --git a/.changeset/targeted-read-cli.md b/.changeset/targeted-read-cli.md deleted file mode 100644 index 3a990e0..0000000 --- a/.changeset/targeted-read-cli.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -"@stainless-code/codemap": minor ---- - -feat(show + snippet): targeted-read CLI verbs + MCP tools - -Two sibling verbs that close the "agent wants to read this thing" loop -without composing SQL: - -- **`codemap show `** — returns metadata - (`file_path:line_start-line_end` + `signature` + `kind`) for the - symbol(s) matching the exact name (case-sensitive). -- **`codemap snippet `** — same lookup; each match also carries - `source` (file lines from disk), `stale` (true when content_hash - drifted since indexing), `missing` (true when file is gone). - -Both share the same flag set (`--kind ` filter, `--in ` file -scope — directory prefix or exact file, normalized via the existing -`toProjectRelative` helper for cross-platform consistency). - -Output is the agent-friendly `{matches, disambiguation?}` envelope on -both CLI `--json` and MCP responses (uniformity contract per the MCP -plan). Single match → `{matches: [{...}]}`; multi-match adds -`disambiguation: {n, by_kind, files, hint}` — structured aids so the -agent narrows without scanning every row. Forward-extensible (future -`nearest_to_cursor` / `most_recently_modified` / `caller_count` fields -land as additive keys). - -MCP tools `show` and `snippet` register parallel to the CLI verbs and -auto-inherit the same envelope shape. - -Stale-file behavior on snippet: `source` is always returned when the -file exists; `stale: true` is metadata the agent reads. No refusal, -no auto-reindex side-effects — read tool stays read-only. - -Architecturally: pure transport-agnostic engine in -`src/application/show-engine.ts` (mirrors the cmd-_ ↔ _-engine seam -from PRs #33 / #35 / #37); thin CLI verbs in `src/cli/cmd-show.ts` - -- `src/cli/cmd-snippet.ts`. Reuses `findSymbolsByName`, `hashContent` - (from `src/hash.ts`), `toProjectRelative` (now exported from - `cmd-validate.ts`), and `files.content_hash` — same primitives the - existing `validate` command already uses for stale detection. No - schema change. - -Test coverage: 19 engine tests (lookup variants, line slicing, stale -detection, missing files), 13 cmd-show parser/envelope tests, 11 -cmd-snippet parser/envelope/stale tests, 8 in-process MCP integration -tests via `@modelcontextprotocol/sdk`'s `InMemoryTransport`. diff --git a/.changeset/unimported-exports-recipe.md b/.changeset/unimported-exports-recipe.md deleted file mode 100644 index ce2d6a0..0000000 --- a/.changeset/unimported-exports-recipe.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@stainless-code/codemap": patch ---- - -feat(recipes): ship `unimported-exports` recipe (research note § 1.2) - -Surfaces exports that have no detectable import. Useful as a starting candidate list for "what's unused?" — explicitly **NOT** a "safe to delete" list. - -V1 limitations documented in the recipe `.md`: - -1. **Re-export chains not followed** — false positives if A re-exports `bar` from B and consumers import `bar` from A. Tracked under research note § 1.2; future recipe with recursive CTE walking `re_export_source` will close the gap. -2. **Unresolved imports ignored** — when `imports.resolved_path IS NULL` (codemap's resolver couldn't resolve a `tsconfig.json` path alias or external package), those rows don't count toward "used" matching. -3. **Default exports skipped** — common framework entry points (Next.js `page.tsx`, Storybook stories, `vite.config.ts`) skipped to reduce noise. Override in project-local recipe if you want to include them. - -Action template `review-for-deletion` (auto_fixable: false) — agents flag for manual verification before deletion. - -Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` codemap rule + skill gain trigger-pattern row, quick-reference row, and recipe-id list update. diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b98c4..9e7a877 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,400 @@ # @stainless-code/codemap +## 0.5.0 + +### Minor Changes + +- [#35](https://github.com/stainless-code/codemap/pull/35) [`119db38`](https://github.com/stainless-code/codemap/commit/119db38670ab007a6367556d844e3c1103dc450e) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(mcp): `codemap mcp` — Model Context Protocol server (agent-transports v1) + + Adds the `codemap mcp` top-level command — boots an MCP server over + stdio so agent hosts (Claude Code, Cursor, Codex, generic MCP clients) + call codemap as JSON-RPC tools instead of shelling out per query. + Eliminates the bash round-trip on every agent invocation. + + Surface (one tool per CLI verb plus `query_batch`, all snake_case): + - `query`, `query_batch`, `query_recipe`, `audit`, `save_baseline`, + `list_baselines`, `drop_baseline`, `context`, `validate` + - Resources: `codemap://recipes`, `codemap://recipes/{id}`, + `codemap://schema`, `codemap://skill` (lazy-cached) + + `query_batch` is MCP-only — N statements in one round-trip with + batch-wide-defaults + per-statement-overrides (items are + `string | {sql, summary?, changed_since?, group_by?}`). Per-statement + errors are isolated. `save_baseline` ships as one polymorphic tool + (`{name, sql? | recipe?}` with runtime exclusivity check) mirroring + the CLI's single `--save-baseline=` verb. + + Output shape is verbatim from each tool's CLI counterpart's `--json` + envelope (no re-mapping). Bootstrap once at server boot; tool + handlers reuse existing engine entry-points (`executeQuery`, + `runAudit`, etc.) — no duplicate business logic. + + New dep: `@modelcontextprotocol/sdk`. + + HTTP API (`codemap serve`) stays in roadmap backlog; design points + (tool taxonomy + output shape) are reserved in `docs/architecture.md +§ MCP wiring` so HTTP inherits them when a concrete consumer asks. + +- [#52](https://github.com/stainless-code/codemap/pull/52) [`fe5a355`](https://github.com/stainless-code/codemap/commit/fe5a3551bb9abd91021a8a0e021cbcd42c44234f) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap audit --base ` — ad-hoc structural-drift audit against any git committish (`origin/main`, `HEAD~5`, ``, tag, …). Closes the highest-frequency post-watch agent loop: "what changed structurally between this branch and `origin/main`?". Replaces today's 3-step `--baseline` dance (switch branches, reindex, save baselines, switch back) with one verb. + + **Three transports, one engine:** + - **CLI:** `codemap audit --base [---baseline ] [--summary] [--json] [--no-index]` + - **MCP tool:** `audit` with new `base?: string` arg + - **HTTP:** `POST /tool/audit` (auto-wired via the existing dispatcher) + + All three dispatch the same pure `runAuditFromRef` engine in `application/audit-engine.ts`. + + **How it works:** + 1. `git rev-parse --verify "^{commit}"` resolves `` to a sha (clean error on non-git or unresolvable ref). + 2. Cache lookup at `/.codemap/audit-cache//.codemap.db`. Hit → sub-100ms; miss → continue. + 3. **Atomic populate** — `git worktree add` to a per-pid temp dir + `runCodemapIndex({mode: "full"})` against the worktree's `.codemap.db` + POSIX `rename` claims the final `/` slot. Concurrent CI matrix runs against the same sha race-safely without lock files (loser's rename fails with EEXIST → falls through to cache hit). + 4. Run each delta's canonical SQL on the cached DB vs the live DB; `diffRows` (existing helper) computes `{added, removed}`. + 5. Compose `AuditEnvelope` with per-delta `base.source: "ref"` (new value) + `base.ref` (user-supplied string) + `base.sha` (resolved). + + **Decisions worth knowing:** + - **`AuditBase` is now a discriminated union** — existing `{source: "baseline", name, sha, indexed_at}` rows untouched; new `{source: "ref", ref, sha, indexed_at}` arm. Consumers narrowing on `base.source` keep compiling. + - **Mutually exclusive with `--baseline `.** Parser + handler both guard. Per-delta `---baseline` overrides compose orthogonally with both, so `--base origin/main --files-baseline pre-refactor-files` is valid (mixed sources). + - **Eviction:** hardcoded LRU 5 entries / 500 MiB; `git worktree remove --force` + `rm -rf` for each victim. Orphan `.tmp.*` dirs older than 10 min get swept on the next cycle. No config knobs in v1; defer to v1.x+ if real consumers ask. + - **Hard error on non-git projects.** No graceful fallback — there's no meaningful "ref" without git. The other audit modes (`--baseline`, `---baseline`) still work without git. + - **Env hygiene.** All git spawns in `audit-worktree.ts` strip inherited `GIT_*` env vars so a containing git operation (e.g. running codemap from a husky hook) doesn't route worktree calls at the wrong index. + + **Auto-`.gitignore`:** `codemap agents init` now adds `.codemap/audit-cache/` alongside `.codemap.*` so cached worktrees never get committed. `.codemap/recipes/` stays git-tracked. + + Plan: PR [#51](https://github.com/stainless-code/codemap/issues/51) (merged). Implementation: PR [#52](https://github.com/stainless-code/codemap/issues/52). + +- [#54](https://github.com/stainless-code/codemap/pull/54) [`1313fc2`](https://github.com/stainless-code/codemap/commit/1313fc2bb5092b175376be4b3db529bed098cece) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `.codemap/` directory consolidation + self-healing files. Every codemap-managed path lives under a single configurable state directory (default `.codemap/`, override via `--state-dir ` or `CODEMAP_STATE_DIR`). Cleans up the dual-pattern surface (`/.codemap.db` + `/.codemap//`) that's been growing with every cache PR; collapses the user `.gitignore` patching surface to zero. + + **New layout:** + + ``` + / + └── .codemap/ ← override via --state-dir / CODEMAP_STATE_DIR + ├── .gitignore ← codemap-managed (self-healing); tracked + ├── config.{ts,js,json} ← was /codemap.config.*; tracked + ├── recipes/ ← user-authored SQL; tracked (existing) + ├── index.db ← was .codemap.db + ├── index.db-shm ← was .codemap.db-shm + ├── index.db-wal ← was .codemap.db-wal + └── audit-cache/ ← was .codemap/audit-cache/ (existing) + ``` + + **Self-healing files (D11):** `/.gitignore` and `/config.json` are owned by idempotent `ensure*` reconcilers (`src/application/state-dir.ts`, `src/application/state-config.ts`) that run on every codemap boot — read → validate → reconcile → write only on drift. **The setup logic IS the migration**: future codemap versions add new generated artifacts to `STATE_GITIGNORE_BODY` (or extend the Zod schema), and every consumer's project repairs itself on the next `codemap` invocation. No more per-feature `.gitignore` patching in `agents-init.ts`. + + **Pre-v1 — no migration shim:** + - `/.codemap.db` → `/index.db` (rename basename) + - `/codemap.config.{ts,json}` → `/config.{ts,js,json}` (move file) + - Existing dev clones: `rm .codemap.db .codemap.db-shm .codemap.db-wal` once and re-index; move `codemap.config.*` into `.codemap/` (or set `--config ` to keep using the legacy location explicitly). + + **New flags + env:** + - `--state-dir ` — override the state directory (resolves relative to project root). + - `CODEMAP_STATE_DIR` — same, env-var form. + + **Internal refactor:** new `src/cli/bootstrap-codemap.ts` extracts the `loadUserConfig + resolveCodemapConfig + initCodemap + configureResolver` dance from 9 cmd-\* files into one helper that also runs the self-healing reconcilers. Adding a new self-healing file is now a one-line addition there. + + Inspired by flowbite-react's `.flowbite-react/.gitignore` + `setup-*` pattern; expressed in codemap's own conventions (`ensure*` reconcilers, Zod schema as `z.infer` source of truth, pure `{before, after, written}` return shapes for testability). + + Plan: PR [#53](https://github.com/stainless-code/codemap/issues/53) (merged). Implementation: PR [#54](https://github.com/stainless-code/codemap/issues/54). + +- [#50](https://github.com/stainless-code/codemap/pull/50) [`90092ae`](https://github.com/stainless-code/codemap/commit/90092ae51fc8d88e825cdd931bc3fb4bd9c9f047) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap impact ` — symbol/file blast-radius walker. Replaces hand-composed `WITH RECURSIVE` queries that agents struggle to write reliably with a single verb that walks the calls / dependencies / imports graphs (callers, callees, dependents, dependencies). Depth- and limit-bounded, cycle-detected. + + **Three transports, one engine:** + - **CLI:** `codemap impact [--direction up|down|both] [--depth N] [--via dependencies|calls|imports|all] [--limit N] [--summary] [--json]` + - **MCP tool:** `impact` (registered alongside `show` / `snippet`) + - **HTTP:** `POST /tool/impact` + + All three dispatch the same pure `findImpact` engine in `application/impact-engine.ts` per the post-PR [#41](https://github.com/stainless-code/codemap/issues/41) layering — adding tools never duplicates business logic. + + **Decisions worth knowing:** + - **Target auto-resolution.** Contains `/` or matches `files.path` → file target; otherwise symbol (case-sensitive, exact). Symbol targets walk `calls`; file targets walk `dependencies` + `imports` (`resolved_path` only). Mismatched explicit `--via` choices land in `skipped_backends` (no error — agent sees why their selection yielded fewer rows than expected). + - **Cycle detection.** SQLite has no native cycle predicate; we materialise a comma-bounded path string per row and `instr` it to break re-entry. Bounded depth + `--limit` (default 500) keep cyclic graphs cheap regardless. `--depth 0` walks unbounded but stays cycle-detected and limit-capped. + - **Termination classification.** `summary.terminated_by`: `limit` > `depth` > `exhausted`. CI gates can branch on it. + - **`--summary` shape.** Trims the `matches` array but preserves `summary.nodes` — the `jq '.summary.nodes'` consumption pattern still works. + - **No SARIF / annotations.** Impact rows are graph traversals, not findings — wrong shape for those formats. + + **Engine sketch:** one `WITH RECURSIVE` query per (direction, backend) combo, JS-side merge + dedup by `(direction, kind, name?, file_path)` keeping the shallowest depth, then `summary.by_kind` + `terminated_by` classification. + + Plan: PR [#49](https://github.com/stainless-code/codemap/issues/49) (merged). Implementation: PR [#50](https://github.com/stainless-code/codemap/issues/50). + +- [#44](https://github.com/stainless-code/codemap/pull/44) [`4ec51d8`](https://github.com/stainless-code/codemap/commit/4ec51d857955e2a055471decf70cfd953e36a056) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap serve` — HTTP server exposing the same tool taxonomy as `codemap mcp` over `POST /tool/{name}`. For non-MCP consumers (CI scripts, simple `curl`, IDE plugins that don't speak MCP). + + Default bind `127.0.0.1:7878` (loopback only — refuse `0.0.0.0` unless explicitly opted in via `--host 0.0.0.0`). Optional `--token ` requires `Authorization: Bearer ` on every request; `GET /health` is auth-exempt so liveness probes work without leaking the token. Bare `node:http` (no Express / Fastify dep) — runs on Bun + Node. + + **Routes:** + - `POST /tool/{name}` — every MCP tool (query, query_recipe, query_batch, audit, context, validate, show, snippet, save_baseline, list_baselines, drop_baseline). Body `{}`; response = same `codemap query --json` envelope (NOT MCP's `{content: [...]}` wrapper). `format: "sarif"` payloads ship as `application/sarif+json`; `format: "annotations"` as `text/plain`. + - `GET /resources/{encoded-uri}` — mirror of MCP resources (`codemap://recipes`, `codemap://recipes/{id}`, `codemap://schema`, `codemap://skill`). + - `GET /health` — liveness (auth-exempt); `GET /tools` / `GET /resources` — catalogs. + - Errors: `{"error": "..."}` with HTTP status 400 / 401 / 404 / 500. + - Every response carries `X-Codemap-Version: ` so consumers can pin / detect upgrades. + + **Internals:** Tool bodies (`application/tool-handlers.ts`) and resource fetchers (`application/resource-handlers.ts`) are pure transport-agnostic — same handlers `codemap mcp` dispatches. No engine duplication; `mcp-server.ts` and `http-server.ts` both wrap the same `ToolResult` discriminated union. + + **Security:** CSRF + DNS-rebinding guard rejects requests with `Sec-Fetch-Site: cross-site` / `same-site` (modern-browser CSRF), any `Origin` header that isn't `null` (older-browser CSRF), and `Host` header mismatch on loopback bind (DNS rebinding) — runs on every request including auth-exempt `/health`. Defends against a malicious local webpage `fetch`-ing the API while the developer is browsing. Non-browser clients (curl, MCP hosts, CI scripts) don't send those headers and pass through. SIGINT / SIGTERM → graceful drain. 1 MiB request-body cap (DoS protection). SQLite reader concurrency handles parallel requests; `PRAGMA query_only = 1` set per connection. + +- [#47](https://github.com/stainless-code/codemap/pull/47) [`5ef9ce4`](https://github.com/stainless-code/codemap/commit/5ef9ce4b398f60aa0e446dee5f8cc73e0978ae42) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap watch` — long-running process that re-indexes changed files in real time so every CLI / MCP / HTTP query reads live data without a per-query reindex prelude. Eliminates the single biggest source of agent-side friction: "is the index stale right now?" + + **Three shapes:** + - **Standalone**: `codemap watch [--debounce 250] [--quiet]` — foreground process; logs `reindex N file(s) in Mms` per batch unless `--quiet`. SIGINT / SIGTERM drains pending edits. + - **MCP killer combo**: `codemap mcp --watch [--debounce ]` — boots stdio MCP server + watcher in one process. Long Cursor / Claude Code sessions never hit a stale index; agents stop having to remember to reindex between edit + query. + - **HTTP killer combo**: `codemap serve --watch [--debounce ]` — same shape for non-MCP consumers (CI scripts, IDE plugins, simple `curl`). + + **Audit prelude optimization:** when watch is active, `mcp audit`'s default incremental-index prelude becomes a no-op (the watcher already keeps the index fresh — saves the per-request reindex cost). Explicit `no_index: false` still forces the prelude. + + **Env shortcut:** `CODEMAP_WATCH=1` (or `"true"`) implies `--watch` for `mcp` / `serve` — useful for IDE / CI launches that can't easily edit the spawn command. + + **Backend:** [chokidar v5](https://github.com/paulmillr/chokidar) (selected via 6-watcher audit in PR [#46](https://github.com/stainless-code/codemap/issues/46)). Pure JS — runs identically on Bun + Node, no per-runtime branching, no native compile matrix on top of `bun:sqlite` / `better-sqlite3`. Cross-platform (macOS / Linux / Windows / WSL). Atomic-write + chunked-write detection out of the box. 1 dep (`readdirp`), 82 KB. + + **Filtering:** Only paths the indexer cares about trigger a reindex (TS / TSX / JS / JSX / CSS + project-local recipes under `/.codemap/recipes/`). `node_modules` / `.git` / `dist` / configured `excludeDirNames` are skipped. + +- [#57](https://github.com/stainless-code/codemap/pull/57) [`b5679a6`](https://github.com/stainless-code/codemap/commit/b5679a67de7b145c6b5937651d72f76bc6b1664c) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap ingest-coverage ` — static coverage ingestion. Reads Istanbul JSON (`coverage-final.json`) or LCOV (`lcov.info`) into a new `coverage` table joinable to `symbols`, so structural queries can compose coverage filters in pure SQL — no runtime tracer, no paid coverage stack. + + **Both formats land in v1** (Istanbul + LCOV) so every test runner is a first-class consumer on day one — `vitest --coverage`, `jest --coverage`, `c8`, `nyc` (Istanbul JSON), and `bun test --coverage` (LCOV) all work without waiting on a follow-up release. + + **Bundled recipes (auto-discovered, no opt-in needed):** + - `untested-and-dead` — exported functions with no callers AND zero coverage; the killer recipe combining structural and runtime evidence axes. + - `files-by-coverage` — files ranked ascending by statement coverage. + - `worst-covered-exports` — top-20 worst-covered exported functions. + + Each recipe ships a frontmatter `actions` block so agents see per-row follow-up hints in `--json` output. + + **Schema:** + - New `coverage` table with natural-key PK `(file_path, name, line_start)` — intentionally not a FK to `symbols.id` so coverage rows survive the `symbols` drop-recreate cycle on every `--full` reindex. + - `idx_coverage_file_name` covers the typical join shape and the `GROUP BY file_path` scan used by the `files-by-coverage` recipe. + - Three new `meta` keys (`coverage_last_ingested_at` / `_path` / `_format`) record ingest freshness. + - `SCHEMA_VERSION` 5 → 6 — auto-rebuilds on next `codemap` run; the new table is empty until first `ingest-coverage` invocation. Subsequent bumps preserve coverage data via the `dropAll()` exclusion. + + **CLI:** + + ```bash + codemap ingest-coverage coverage/coverage-final.json # Istanbul (auto-detected) + codemap ingest-coverage coverage/lcov.info # LCOV (auto-detected) + codemap ingest-coverage coverage --json # directory probe (errors if both files present) + + codemap query --json --recipe untested-and-dead # the killer query + ``` + + No `--source` flag — format is auto-detected from extension. No MCP / HTTP transport in v1 — coverage exposes as a SQL column, composable with every existing recipe and ad-hoc query through the existing `query` / `query_recipe` tools (no parallel surface). + + Plan: PR [#56](https://github.com/stainless-code/codemap/issues/56) (merged). Implementation: this PR. + +- [`31479a5`](https://github.com/stainless-code/codemap/commit/31479a5154c1001f0a2371ff16287126cbe4c9bc) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(mcp/serve): default-ON watcher for `codemap mcp` and `codemap serve` + + Stale-index friction is empirically the most-frequent agent UX issue under `codemap mcp` (driving the watch-mode planning in PR [#46](https://github.com/stainless-code/codemap/issues/46)) and the most-frequent CI/IDE-plugin friction under `codemap serve`. Both modes are inherently long-running, so the chokidar co-process pays for itself immediately. Decision originally resolved 2026-05 (research note `§ 6 Q1`); this PR ships it. + + **New defaults.** + - `codemap mcp` — watcher boots automatically; tools always read a live index. + - `codemap serve` — same. + - One-shot CLI defaults preserved: `codemap query` / `codemap show` / `codemap snippet` / etc. still spawn no watcher. + + **Opt out.** + - `--no-watch` flag (new) — explicit opt-out for ephemeral-index workflows, fire-and-forget CI scripts, etc. + - `CODEMAP_WATCH=0` / `CODEMAP_WATCH="false"` — env-shortcut mirroring `--no-watch` for IDE / CI launches that can't easily edit the spawn command. + + **Backwards-compat preserved.** + - `--watch` flag still parses and is honored (no-op since it matches the new default; kept so existing scripts and launch commands don't break). + - `CODEMAP_WATCH=1` / `CODEMAP_WATCH="true"` still parses (redundant after the flip, kept for backwards-compat). + - `--no-watch` wins over `--watch` when both passed (last-write semantics). + + **Tradeoffs accepted.** + - Slightly slower mcp/serve startup (~chokidar boot cost, validated tiny on Bun + Node by PR [#46](https://github.com/stainless-code/codemap/issues/46)'s 6-watcher audit). + - Spawns a second process — visible to users running `htop` / `Activity Monitor`. Worth it for the live-index correctness gain. + + **Tests:** 12 new tests across `cmd-mcp.test.ts` and `cmd-serve.test.ts` cover default-ON behavior, `--no-watch` opt-out, env opt-out (`CODEMAP_WATCH=0` / `"false"`), env opt-in still honored (`CODEMAP_WATCH=1`), and `--no-watch` wins over `--watch`. + + **Lockstep updates:** `templates/agents/rules/codemap.md`, `templates/agents/skills/codemap/SKILL.md`, `.agents/rules/codemap.md`, `.agents/skills/codemap/SKILL.md`, and `README.md` all updated to reflect the new defaults + opt-out shape per `docs/README.md` Rule 10. + +- [#30](https://github.com/stainless-code/codemap/pull/30) [`a309d52`](https://github.com/stainless-code/codemap/commit/a309d52d2527084348578d6c1278d7a7fc245108) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap query --save-baseline` / `--baseline` — snapshot a query result set and diff against it later. Stored in the new `query_baselines` table inside `.codemap.db` (no parallel JSON files). `--baselines` lists saved snapshots, `--drop-baseline ` deletes one. Diff identity is per-row `JSON.stringify` equality; `--summary` collapses to `{added: N, removed: N}`. Recipe `actions` attach to the `added` rows when running under `--baseline`. Baselines survive `--full` and SCHEMA rebuilds. `SCHEMA_VERSION` bumps from 4 to 5. + +- [#37](https://github.com/stainless-code/codemap/pull/37) [`5110b1a`](https://github.com/stainless-code/codemap/commit/5110b1a595bb4b971710d0367d56770c82c91651) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(recipes): recipes-as-content registry — bundled .md siblings + project-local recipes + + Two complementary capabilities: + 1. **Bundled recipes get richer descriptions.** Every bundled recipe in + `templates/recipes/` is now a `.sql` file paired with an optional + `.md` description body (replaces the inline TypeScript map in + `src/cli/query-recipes.ts`). Per-row `actions` templates live in YAML + frontmatter on the `.md` instead of code. Same surface for end users + (`--recipe ` / `--recipes-json` / `codemap://recipes`); single + storage shape across bundled + project recipes. + + 2. **Project-local recipes** — drop `.{sql,md}` files into + `/.codemap/recipes/` to ship team-internal SQL as first- + class recipes. Auto-discovered via `--recipe `, surfaced in + `--recipes-json` and the `codemap://recipes` MCP resource alongside + bundled. Project recipes win on id collision; the catalog entry + carries `shadows: true` on overrides so agents reading the catalog + at session start see when a recipe behaves differently from the + documented bundled version (per-execution response shape stays + unchanged — uniformity contract preserved). + + Catalog entries (`--recipes-json` output, `codemap://recipes` + payload) gain three additive fields: `body` (full Markdown body), + `source` (`"bundled" | "project"`), and `shadows?` (true on + project entries that override a bundled id). Existing consumers + that destructure `{id, description, sql, actions?}` keep working. + + Validation: load-time lexical scan rejects DML / DDL keywords + (`INSERT` / `UPDATE` / `DELETE` / `DROP` / `CREATE` / `ALTER` / + `ATTACH` / `DETACH` / `REPLACE` / `TRUNCATE` / `VACUUM` / `PRAGMA`) + in recipe SQL with recipe-aware error messages — defence in depth + alongside the runtime `PRAGMA query_only=1` backstop in + `query-engine.ts` shipped in the previous release. + + Implementation: pure transport-agnostic loader in + `src/application/recipes-loader.ts`; thin shim in + `src/cli/query-recipes.ts` preserves backwards-compat exports + (`QUERY_RECIPES`, `getQueryRecipeSql`, etc.). Hand-rolled YAML + frontmatter parser scoped to the `actions` shape (no `js-yaml` + dependency). + + `.codemap.db` is gitignored as before; `.codemap/recipes/` is NOT + (verified via `git check-ignore`) — recipes are git-tracked source + code authored for human review. + +- [#43](https://github.com/stainless-code/codemap/pull/43) [`4061ac3`](https://github.com/stainless-code/codemap/commit/4061ac36ee1b4ae7b5cba94188adc824c5b5d8bd) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap query --format ` — pipe any recipe row-set into GitHub Code Scanning (SARIF 2.1.0) or surface findings inline on PRs (GH Actions `::notice file=…,line=…::msg`). Pure output-formatter additions on top of the existing JSON pipeline; no schema impact. + + Auto-detects file-path columns (`file_path` / `path` / `to_path` / `from_path` priority) and `line_start` (+ optional `line_end`) for SARIF region. Aggregate recipes without locations (`index-summary`, `markers-by-kind`) emit `results: []` + a stderr warning. Rule id is `codemap.` for `--recipe`, `codemap.adhoc` for ad-hoc SQL. Default `result.level` is `"note"`; per-recipe overrides via `.md` frontmatter (`sarifLevel`, `sarifMessage`, `sarifRuleId`) deferred to v1.x. + + `--format` overrides `--json` when both passed; `--json` stays as the alias for `--format json`. Incompatible with `--summary` / `--group-by` / baseline (different output shapes — sarif/annotations only support flat row lists). + + MCP `query` and `query_recipe` tools accept the same `format: "sarif" | "annotations"` argument; `query_batch` deferred to v1.x. + +- [#39](https://github.com/stainless-code/codemap/pull/39) [`7460b46`](https://github.com/stainless-code/codemap/commit/7460b4652181a5bfec5b826b523d143699d7b8d0) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(show + snippet): targeted-read CLI verbs + MCP tools + + Two sibling verbs that close the "agent wants to read this thing" loop + without composing SQL: + - **`codemap show `** — returns metadata + (`file_path:line_start-line_end` + `signature` + `kind`) for the + symbol(s) matching the exact name (case-sensitive). + - **`codemap snippet `** — same lookup; each match also carries + `source` (file lines from disk), `stale` (true when content_hash + drifted since indexing), `missing` (true when file is gone). + + Both share the same flag set (`--kind ` filter, `--in ` file + scope — directory prefix or exact file, normalized via the existing + `toProjectRelative` helper for cross-platform consistency). + + Output is the agent-friendly `{matches, disambiguation?}` envelope on + both CLI `--json` and MCP responses (uniformity contract per the MCP + plan). Single match → `{matches: [{...}]}`; multi-match adds + `disambiguation: {n, by_kind, files, hint}` — structured aids so the + agent narrows without scanning every row. Forward-extensible (future + `nearest_to_cursor` / `most_recently_modified` / `caller_count` fields + land as additive keys). + + MCP tools `show` and `snippet` register parallel to the CLI verbs and + auto-inherit the same envelope shape. + + Stale-file behavior on snippet: `source` is always returned when the + file exists; `stale: true` is metadata the agent reads. No refusal, + no auto-reindex side-effects — read tool stays read-only. + + Architecturally: pure transport-agnostic engine in + `src/application/show-engine.ts` (mirrors the cmd-_ ↔ _-engine seam + from PRs [#33](https://github.com/stainless-code/codemap/issues/33) / [#35](https://github.com/stainless-code/codemap/issues/35) / [#37](https://github.com/stainless-code/codemap/issues/37)); thin CLI verbs in `src/cli/cmd-show.ts` + - `src/cli/cmd-snippet.ts`. Reuses `findSymbolsByName`, `hashContent` + (from `src/hash.ts`), `toProjectRelative` (now exported from + `cmd-validate.ts`), and `files.content_hash` — same primitives the + existing `validate` command already uses for stale detection. No + schema change. + + Test coverage: 19 engine tests (lookup variants, line slicing, stale + detection, missing files), 13 cmd-show parser/envelope tests, 11 + cmd-snippet parser/envelope/stale tests, 8 in-process MCP integration + tests via `@modelcontextprotocol/sdk`'s `InMemoryTransport`. + +### Patch Changes + +- [#33](https://github.com/stainless-code/codemap/pull/33) [`114303f`](https://github.com/stainless-code/codemap/commit/114303fcbc9f61a033174c1ffaa94e3bc4003014) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - `codemap audit` (B.5 v1) — structural-drift command emitting `{head, deltas}` where each `deltas[]` carries `{base, added, removed}`. Three v1 deltas: `files`, `dependencies`, `deprecated`. Two snapshot-source shapes — `--baseline ` (auto-resolves `-files` / `-dependencies` / `-deprecated` in `query_baselines`) and `---baseline ` (explicit per-delta override; composes with `--baseline`). Reuses B.6 baselines; no schema bump. `--summary` collapses to per-delta counts; `--no-index` skips the auto-incremental-index prelude. v1 ships no `verdict` / threshold config — consumers compose `--json` + `jq` for CI exit codes (v1.x slice). `--base ` (worktree+reindex snapshot) defers to v1.x. + +- [#70](https://github.com/stainless-code/codemap/pull/70) [`db2f27a`](https://github.com/stainless-code/codemap/commit/db2f27a69747b73c244d19583d1e54476b9a8bc8) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(complexity): cyclomatic complexity column on `symbols` + bundled recipe (research note § 1.4 ship-pick (c)) + + Adds per-function cyclomatic complexity computed during AST walking. Schema bump `SCHEMA_VERSION` 7 → 8 — first reindex after upgrade triggers a full rebuild via the existing version-mismatch path. + + **What lands:** + - New `complexity REAL` column on `symbols`. Computed via McCabe formula (`1 + decision points`) for function-shaped symbols (top-level `function` declarations + arrow-function consts). `NULL` for non-functions (interfaces, types, enums, plain consts) and class methods (v1 limitation; documented in the recipe `.md`). + - Decision points counted: `if`, `while`, `do…while`, `for`, `for…in`, `for…of`, `case X:` arms (not `default:` fall-through), `&&` / `||` / `??` short-circuit operators, `?:` ternary, `catch` clauses. + - New bundled recipe `high-complexity-untested` — function-shaped symbols with complexity ≥ 10 AND measured coverage < 50%. Combines structural + runtime evidence axes; surfaces refactor-priority candidates that single-axis recipes (`untested-and-dead`, `worst-covered-exports`) miss because they're "called but undertested." + + **Implementation:** + - Parser visitor (`src/parser.ts`) maintains a `complexityStack` keyed by symbol index. On function entry, pushes counter at 1 + symbol index. Branching-node visitors increment the top counter. On function exit, pops and writes complexity into the symbol row already pushed during entry. + - Nested function declarations get their own stack entries — inner branches don't count toward the outer function. (Standard McCabe — each function counted independently.) + + **Pre-v1 patch** per `.agents/lessons.md` "changesets bump policy": schema-bumping changes are minor in semver but pre-v1 we default to patch unless the bump forces a `.codemap.db` rebuild. This one does (column added; auto-detected by `createSchema()` mismatch path) — every consumer's first run after upgrade re-indexes from scratch. + + Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` codemap rule + skill mention the `complexity` column, the new recipe, and the cyclomatic-complexity definition. + + **Out of scope:** + - **Class method complexity** — `MethodDefinition` visitor currently doesn't push to the complexity stack. Documented in `high-complexity-untested.md` v1 limitation; refactor opportunity for class-heavy projects. + - **Per-class / per-file rollups** — `complexity` is per-symbol; project-local recipes can `SUM` / `AVG` it as needed. + +- [#69](https://github.com/stainless-code/codemap/pull/69) [`560390b`](https://github.com/stainless-code/codemap/commit/560390b0b8dc13bc8c6ba70f0b230e73619696d6) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(fts5+mermaid): opt-in FTS5 virtual table + Mermaid output formatter + + Implements the FTS5+Mermaid plan ([`docs/plans/fts5-mermaid.md`](https://github.com/stainless-code/codemap/blob/main/docs/plans/fts5-mermaid.md)) — two non-goal flips in one PR. + + **FTS5 (opt-in, default OFF):** + - New `source_fts` virtual table — `(file_path UNINDEXED, content)` columns, `tokenize='porter unicode61'`. Always created; populated only when toggle is on. + - Toggle via `codemap.config.ts` `fts5: true` OR `--with-fts` CLI flag at index time. CLI overrides config (logs stderr line on override). + - Indexer tees file content into `source_fts` in same transaction as `files` row insert (atomic). Worker → main serialization cost is zero on default-OFF path. + - Toggle-change auto-detect via `meta.fts5_enabled` — flipping `fts5: false → true` auto-upgrades incremental → full rebuild so `source_fts` is consistently populated. + - DB-size telemetry on first FTS5 populate: `[fts5] source_fts populated: files / KB`. + - Bundled demo recipe `text-in-deprecated-functions` — `@deprecated` functions in files containing `TODO`/`FIXME`/`HACK` markers AND coverage `<50%`. Demonstrates FTS5 ⨯ `symbols` ⨯ `coverage` JOIN composability that ripgrep can't match. + + **Mermaid output formatter:** + - New `--format mermaid` output mode. Renders `{from, to, label?, kind?}` row-shape as `flowchart LR`. + - **Bounded-input contract** (50-edge ceiling, `MERMAID_MAX_EDGES`): unbounded inputs reject with a scope-suggestion error naming the recipe + count + scoping knobs (`LIMIT` / `--via` / `WHERE`). Auto-truncation deliberately out of scope (would be a verdict masquerading as an output mode). + - Available across CLI, MCP `query` / `query_recipe` tools, HTTP `POST /tool/query` (text/plain content type). + + Schema bump: `SCHEMA_VERSION` 6 → 7. First reindex after upgrade triggers a full rebuild via the existing version-mismatch path; existing `.codemap/index.db` is preserved (only schema-managed tables get dropped + recreated). + + **Pre-v1 patch** per `.agents/lessons.md` "changesets bump policy" — additive feature, default-OFF for FTS5, behaviour-preserving for existing users (`--with-fts` is opt-in; Mermaid is a new output mode). + + Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` mention `--with-fts`, `--format mermaid`, the new bundled recipe, and the bounded-input contract. + +- [#41](https://github.com/stainless-code/codemap/pull/41) [`0134944`](https://github.com/stainless-code/codemap/commit/0134944c2df9bbed00e4d40ce6ac3c135a983eb8) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - Internal refactor — lift `cli/*` envelope builders + path helpers into `application/*` engines so `application/mcp-server.ts` no longer reaches sideways into `cli/`. Affected modules: `audit-engine` (added `resolveAuditBaselines`), new `context-engine` (`buildContextEnvelope`, `classifyIntent`, `ContextEnvelope`), new `validate-engine` (`computeValidateRows`, `toProjectRelative`), `show-engine` (added `buildShowResult`, `buildSnippetResult`, `ShowResult`, `SnippetResult`, `SnippetMatch`), `query-recipes` moved from `cli/` to `application/`. CLI verbs stay shells (parse / help / run / render). No behavior change, no public API change — `cli/cmd-*` and `application/*` are internal modules; the published surface (`api.ts`, the `codemap` binary, the MCP server) is untouched. + +- [#67](https://github.com/stainless-code/codemap/pull/67) [`3e03db7`](https://github.com/stainless-code/codemap/commit/3e03db7a62584b4e676261dbdbfc7fb497c2c50a) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(mcp): add `codemap://files/{path}` + `codemap://symbols/{name}` resources (research note § 1.8) + + Two new MCP / HTTP resources for direct agent reads — saves the recipe-compose round-trip when the agent just wants "everything about this file" or "where is this symbol?". + - **`codemap://files/{path}`** — per-file roll-up. Returns `{path, language, line_count, symbols, imports, exports, coverage}`. `imports.specifiers` parsed inline (callers don't have to JSON.parse). `coverage` is `{measured_symbols, avg_coverage_pct, per_symbol}` when coverage was ingested, else `null`. URI-encode the path. + - **`codemap://symbols/{name}`** — symbol lookup by exact name. Returns `{matches, disambiguation?}` envelope (same shape as the `show` verb per PR [#39](https://github.com/stainless-code/codemap/issues/39)). Optional `?in=` query parameter mirrors `show --in ` (directory prefix or exact file). + + Both reuse existing infrastructure (no schema bump): `codemap://files/` queries the existing tables; `codemap://symbols/` reuses `findSymbolsByName` + `buildShowResult` from `application/show-engine.ts`. + + **Caching policy:** catalog-style resources (`recipes`, `schema`, `skill`) lazy-cache as before. Data-shaped resources (`files/`, `symbols/`) read live every call — no caching, since the index can change between requests under `--watch`. + + Both available over MCP `read_resource` and HTTP `GET /resources/{encoded-uri}` via the existing dispatcher (no new transport plumbing). + + Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` codemap rule + skill mention the new resource templates + caching policy. + +- [`8da7f3d`](https://github.com/stainless-code/codemap/commit/8da7f3df36460ae366f1ad5d0a22cea1e66d0559) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - docs(cli): `mcp --help` and `serve --help` now list every shipped tool + resource + + Stale help text in `src/cli/cmd-mcp.ts` and `src/cli/cmd-serve.ts` listed the original v1 tool / resource taxonomy. Updated to match what's registered today (verified against `src/application/mcp-server.ts`): + - **`mcp --help` Tools section** now includes `show`, `snippet`, `impact` (was missing all three). + - **`mcp --help` Resources section** now distinguishes lazy-cached catalog resources (`recipes`, `recipes/{id}`, `schema`, `skill`) from live read-per-call resources (`files/{path}`, `symbols/{name}`) — was listing only the original four. + - **`serve --help` Routes section** now includes `POST /tool/impact` (was missing) and lists every mirrored MCP resource explicitly under `GET /resources/{encoded-uri}` (was a `...` ellipsis). + + No behavior change — purely a documentation accuracy fix. Bundled agent rule + skill (`templates/agents/` and `.agents/`) already enumerate the six resources correctly. + +- [#65](https://github.com/stainless-code/codemap/pull/65) [`1b7a5c7`](https://github.com/stainless-code/codemap/commit/1b7a5c73fbabfc1cb5827e9090e32728d9d469bf) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(recipes): ship two new bundled recipes from research note § 1 + - **`components-touching-deprecated`** (research note § 1.1) — UNION of two paths surfacing components that touch `@deprecated` symbols: hook path (`components.hooks_used` JSON overlap) + call path (`calls.caller_name = component`, `callee_name` is `@deprecated`). Hook-only variants ship false negatives — recipe spells out the explicit UNION. Action template `review-deprecation-impact`. + - **`refactor-risk-ranking`** (research note § 1.4) — per-file ranking by `(fan_in + 1) × (100 - avg_coverage_pct)`. Three correctness fixes vs the naïve formula: orphans (`fan_in = 0`) score on coverage alone via `+1`; NULL `coverage_pct` treated as 0% via `COALESCE` (otherwise the row drops from `ORDER BY`); files with no exports excluded (no public-API surface to refactor externally). Output is per-file (not per-symbol) — empirical test showed per-symbol ranking ties on file-level fan_in. Per-symbol via `calls` is a documented tuning axis for project-local override. Action template `review-refactor-impact`. + + Both recipes use only existing substrate (`components`, `calls`, `symbols`, `dependencies`, `coverage`, `files`) — no schema bump. Bundled recipe content follows the existing recipe-as-content registry pattern (PR [#37](https://github.com/stainless-code/codemap/issues/37)); project-local overrides live at `/.codemap/recipes/.{sql,md}`. + + Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` (ships to npm via `codemap agents init`) and `.agents/` (this clone's mirror) gain trigger-pattern entries, quick-reference rows, and recipe-id list updates. + +- [#66](https://github.com/stainless-code/codemap/pull/66) [`f121d84`](https://github.com/stainless-code/codemap/commit/f121d845cd2108608c5829c44144fee5b1095bac) Thanks [@SutuSebastian](https://github.com/SutuSebastian)! - feat(recipes): ship `unimported-exports` recipe (research note § 1.2) + + Surfaces exports that have no detectable import. Useful as a starting candidate list for "what's unused?" — explicitly **NOT** a "safe to delete" list. + + V1 limitations documented in the recipe `.md`: + 1. **Re-export chains not followed** — false positives if A re-exports `bar` from B and consumers import `bar` from A. Tracked under research note § 1.2; future recipe with recursive CTE walking `re_export_source` will close the gap. + 2. **Unresolved imports ignored** — when `imports.resolved_path IS NULL` (codemap's resolver couldn't resolve a `tsconfig.json` path alias or external package), those rows don't count toward "used" matching. + 3. **Default exports skipped** — common framework entry points (Next.js `page.tsx`, Storybook stories, `vite.config.ts`) skipped to reduce noise. Override in project-local recipe if you want to include them. + + Action template `review-for-deletion` (auto_fixable: false) — agents flag for manual verification before deletion. + + Agent rule + skill lockstep updated per `docs/README.md` Rule 10 — both `templates/agents/` and `.agents/` codemap rule + skill gain trigger-pattern row, quick-reference row, and recipe-id list update. + ## 0.4.0 ### Minor Changes diff --git a/package.json b/package.json index 4d22a75..1a81c29 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stainless-code/codemap", - "version": "0.4.0", + "version": "0.5.0", "description": "Query your codebase — structural SQLite index for AI agents", "keywords": [ "agents",