Skip to content

Releases: stainless-code/codemap

v0.8.0

21 May 18:28
f25f8a6

Choose a tag to compare

Minor Changes

  • #107 f24f8b6 Thanks @SutuSebastian! - Substrate tiers 1–6 remainder (excludes C.9 / files.is_entry). Schema bump SCHEMA_VERSION 27 → 34 — first run after upgrade auto-rebuilds .codemap/index.db via the existing version-mismatch path.

    Tier 1 — call + import precision

    • calls.{args_count,is_method_call,is_constructor_call,is_optional_chain}; constructor vs call dedup key fix
    • symbols.{return_type,is_async,is_generator}
    • Side-effect import_specifiers rows (kind='side-effect') + import_id FK to imports

    Tier 2 — bindings

    • bindings.resolution_kind='re-exported' when resolution walks a re-export chain

    Tier 3 — JSX

    • New tables jsx_elements / jsx_attributes; extractor with per-file parent linking post-pass

    Tier 5 — behavioral

    • New tables async_calls, try_catch, decorators, jsdoc_tags; context stack for in_loop / in_try

    Tier 6 — module graph (no entry points)

    • dynamic_imports table + extractor
    • Post-pass files.is_barrel and parse-time files.has_side_effects

    Recipes + goldens: find-call-sites (extended), find-async-functions, find-dynamic-imports, find-barrel-files, find-side-effect-files, find-re-exported-bindings, find-side-effect-imports, find-jsx-usages, find-await-in-loop, find-swallowed-errors, find-decorator-usage, find-throws-jsdoc, plus golden coverage for fan-out-sample / fan-out-sample-json and substrate regression tests.

    Read-only CLI hardening: printQueryResult (ad-hoc codemap query "<SQL>") now sets PRAGMA query_only = 1, closing the last gap vs queryRows / executeQuery (#107).

    Out of scope: C.9 plugin layer (files.is_entry, reachability-from-entry); tiers 7–13.

    Migration: No in-place DDL — rebuild on schema mismatch preserves user-data tables (coverage, query_baselines, recipe_recency). Re-run codemap --full (or any index) after upgrade.

Patch Changes

  • #118 665c19a Thanks @SutuSebastian! - Reject apply targets that are symlinks so phase-2 rename cannot replace a link with a regular file.

  • #117 5ee5f2e Thanks @SutuSebastian! - Fail benchmark reindex runs when the spawned indexer exits non-zero instead of recording misleading timings.

  • #109 02a628f Thanks @SutuSebastian! - Validate codemap index --files operands before indexing starts.

  • #110 7767a97 Thanks @SutuSebastian! - Validate VERSION output in detect-pm before writing GitHub Actions outputs.

  • #112 ec31949 Thanks @SutuSebastian! - Harden apply and diff-json path containment against traversal outside the project root.

  • #123 54ad25a Thanks @SutuSebastian! - Fix high-severity bugs (describe.each parent stack, git porcelain -z paths, CLI symlink entry, pr-comment TTY stdin), medium bugs (changed-since -z paths, perf baseline RUNS guard, qualified typeof, decorator args_text, for-of binding refs, HTTP body drain, benchmark regex validation, jsx INSERT RETURNING id, sqlite stmt cache on close), and low bugs (CLI parse guards, incremental delete transaction, apply summary.files, extension case, pnpm # paths, coverage db.transaction, impact walk delimiter, worker errors, pointer dedup, benchmark readAll visibility).

  • #114 ae54ce0 Thanks @SutuSebastian! - Fix diff preview deletions, config empty-array overrides, resolver path containment, impact call-site selection, and FTS cleanup on file delete.

  • #122 4e191ba Thanks @SutuSebastian! - Run full check (not build-only) in prepublishOnly so npm publish cannot skip tests or typecheck.

  • #113 126066d Thanks @SutuSebastian! - Reject opaque Origin: null in codemap serve CSRF checks.

  • #120 17dcbd1 Thanks @SutuSebastian! - Reject unexpected arguments on codemap skill and codemap rule instead of silently printing bundled content.

  • #119 cf0532b Thanks @SutuSebastian! - Print symbol signature in codemap snippet terminal output, matching codemap show and the documented contract.

  • #116 a444c40 Thanks @SutuSebastian! - Fix V8 coverage ingest so innermost-wins applies across all FunctionCoverage entries in a script, not per-function iteration order.

  • #115 eb18750 Thanks @SutuSebastian! - Fix watcher priming race, parse-worker stat errors, incremental rename cleanup, and several indexer extractor gaps (scopes, references, tests.each, process.env, CSS imports).

  • #121 f5d013c Thanks @SutuSebastian! - Reject malformed CODEMAP_PARSE_WORKERS values (e.g. 2abc, 1.5) instead of silently truncating with parseInt.

v0.7.5

18 May 07:38
9239159

Choose a tag to compare

Patch Changes

  • #96 cc8daed Thanks @SutuSebastian! - Performance: full-rebuild wall down ~21% on small trees and ~18% on a real-world ~2k-file external corpus. Headline contributor: collectFiles switched to a single tinyglobby call with ignore patterns (collect_ms -93%, file set bit-identical via followSymbolicLinks: false). Bindings/cycles/re-exports phase now keeps the bulk-INSERT PRAGMA-OFF window open through full rebuild (bindings_ms -33% on the 2k corpus). Plus query_batch single connection, incremental double-read kill, shared countLines helper, stmtCache placeholder memo, SQLite busy_timeout, adapter Map lookup, byte-order sort, FTS5 batched delete, and getAllFileHashes hoist.

    Instrumentation: IndexPerformanceReport now surfaces bindings_ms, module_cycles_ms, re_export_chains_ms (previously rolled into total_ms with no breakdown). Set CODEMAP_PERFORMANCE_JSON=<path> to dump the report as JSON post-run (no new CLI flag added).

    Knobs: CODEMAP_PARSE_WORKERS=N (clamped [1, 32]) overrides the default max(2, min(cpus, 6)) worker count. bun run check:perf-baseline + a non-blocking CI job (📈 Perf baseline (self-index)) guard against per-phase regressions vs fixtures/benchmark/perf-baseline.json; CODEMAP_PERF_RUNS / CODEMAP_PERF_REGRESSION_PCT / CODEMAP_PERF_NOISE_FLOOR_MS tune the checker.

    Behavior change (correctness hardening): queryRows (the implementation behind Codemap.query(), codemap apply recipe SQL execution, bun run test:golden, and the cmd-query print/grouped paths) now sets PRAGMA query_only = 1 to mirror executeQuery's read-only enforcement. DML / DDL slipping through these paths now errors at SQLite instead of mutating the database. All these call sites are contractually read-only; this turns a contract into an enforceable boundary. Existing tests pass unchanged. Anyone who relied on undocumented mutation through Codemap.query("DELETE FROM ...") would now get an error — but that was always API abuse.

    Full design context: docs/plans/perf-triangulation-rollout.md (synthesis + execution rollout of 5 independent perf/architecture audits authored 2026-05-17).

v0.7.4

16 May 07:42
d299ddf

Choose a tag to compare

Patch Changes

  • #93 d92b917 Thanks @SutuSebastian! - Fix: project recipes (<root>/.codemap/recipes/<id>.sql) are now visible via the CLI.

    parseQueryRest validates --recipe <id> / --recipes-json / --print-sql <id> BEFORE runQueryCmd calls bootstrapCodemap, so the recipe registry hit getProjectRoot() pre-init, the throw was silently caught, and the loader fell back to bundled-only. The MCP and HTTP transports always bootstrap before reaching the loader, so project recipes worked there throughout — only the CLI path was affected.

    Fix is surgical:

    • New setQueryRecipesProjectRoot(root) API in application/query-recipes.ts — caller-supplied root takes precedence over the runtime config (which isn't initialised yet during argv parse).
    • cli/main.ts calls it once right after parseBootstrapArgs returns root, so every subsequent verb (parser-side and post-bootstrap) sees the same value.

    Single source of truth: the override is the same root bootstrapCodemap resolves to — no parallel walk-up heuristic, no new env var, no second resolution path. The registry cache invalidates when the override changes.

    Adds regression tests (query-recipes.pre-bootstrap.test.ts) exercising the override-only path (no initCodemap) plus a dogfood project recipe (.codemap/recipes/src-deprecated.sql) that scopes the bundled deprecated-symbols audit to src/ only — useful for codemap's own deprecation lifecycle, and a permanent regression case against this bug recurring.

    Consumers with project recipes authored on 0.6.x–0.7.2 didn't need to wait — recipes worked via MCP / HTTP throughout. After upgrading, the CLI auto-picks them up.

v0.7.3

15 May 18:45
d0f450a

Choose a tag to compare

Patch Changes

  • #91 82bca4b Thanks @SutuSebastian! - Slim the auto-generated <state-dir>/.gitignore header for consumer clarity:

    • Drop the internal function-name reference (ensureStateGitignore) — consumers can't look it up.
    • Drop the "Rule 9 analogue" / "bump alongside any new cache" line — it was guidance for codemap contributors, leaking into every consumer's checkout.
    • Reframe "blacklist" / parenthetical mention of tracked files in plainer language.

    Existing two-line header (# codemap-managed — edits will be overwritten by ensureStateGitignore. / # Blacklist of generated artifacts...) becomes:

    # Managed by codemap — overwritten on next run.
    # Generated artifacts only; user-authored config (config.*, recipes/) stays tracked.
    

    One-time rewrite on consumer side. The reconciler matches the canonical body via exact string comparison, so every consumer's next codemap run rewrites <state-dir>/.gitignore to the new shape (no entries change — only the comment lines). Harmless; the blacklist entries (index.db, index.db-shm, index.db-wal, audit-cache/) are unchanged.

v0.7.2

15 May 18:12
c67f112

Choose a tag to compare

Patch Changes

  • #89 6e53458 Thanks @SutuSebastian! - codemap audit --base <ref> now materialises the sha-keyed cache via git archive | tar -x instead of git worktree add. The cache entry at .codemap/audit-cache/<sha>/ is a plain extracted tree with no .git pointer file and no registered git worktree, so:

    • git clean -xdf sweeps it without needing -ff (which used to also nuke unrelated nested repos).
    • Plain rm -rf works — no more dangling registrations under <repo>/.git/worktrees/ that needed git worktree prune.

    All other invariants preserved: cache path layout, hit detection (<sha>/.codemap/index.db exists), atomic populate (per-pid temp + POSIX rename), LRU eviction (5 entries / 500 MiB), error code names (worktree-add-failed etc. kept for API stability — external consumers discriminate on code, not the underlying primitive).

    Also: the cache reindex now stamps meta.last_indexed_commit with the resolved sha directly instead of shelling out to git rev-parse HEAD inside the cache dir — silences a fatal: not a git repository stderr line that older revisions leaked.

    Migration — existing consumers with .codemap/audit-cache/<sha>/ worktrees from earlier versions can run git worktree prune once after upgrade to clear dangling registrations. The registrations are inert when the path is gone, so skipping the prune is harmless.

v0.7.1

15 May 17:12
de1ad28

Choose a tag to compare

Patch Changes

  • 904e4a5 Thanks @SutuSebastian! - Two skill / docs clarifications that ship in the live-served skill (codemap skill / codemap://skill / GET /resources/<encoded-skill-uri>):

    • parent_name vs scope_local_id (#86). parent_name is the nearest named enclosing scope — it walks past anonymous arrows / IIFEs / callbacks, so parent_name IS NULL matches both true module-scope symbols and symbols inside top-level anonymous IIFEs. For a strict "module-scope only" filter use scope_local_id = 0. docs/architecture.md symbols.parent_name column doc + 40-query-patterns.md mutability example updated accordingly.

    • imports.source vs imports.resolved_path (#87). The single most common cause of empty imports result sets on alias-using codebases (TS paths, Webpack / Vite aliases, Node subpath imports #internal/…, monorepo workspaces) is picking the wrong column. The skill now explicitly teaches: filter source for "via alias / package name", filter resolved_path for "via on-disk path", and WHERE resolved_path IS NULL for "external packages only".

    No schema change, no CLI / API change. Patch bump; existing .codemap/index.db unaffected.

v0.7.0

15 May 16:37
67b843a

Choose a tag to compare

Minor Changes

  • #84 e003218 Thanks @SutuSebastian! - symbols.kind distinguishes const / let / var instead of collapsing all three into 'const'. Schema bump SCHEMA_VERSION 26 → 27 — first run after upgrade auto-rebuilds .codemap/index.db via the existing version-mismatch path; consumer queries see the new values immediately.

    What changes:

    • let x = 1 now emits kind = 'let' + signature = 'let x'.
    • var y = 2 now emits kind = 'var' + signature = 'var y'.
    • const z = 3 unchanged (kind = 'const' + signature = 'const z').
    • Destructuring patterns inherit the declaration keyword: let { a, b } = obj → both a and b are kind = 'let'.
    • for (let x of arr) { ... } body bindings inherit the keyword (kind = 'let').
    • Arrow / function init still wins over the keyword: const handler = () => 1 and let handler = () => 1 both emit kind = 'function'.

    Breaking — but pre-v1 the breakage IS the fix. Any query that filtered WHERE kind = 'const' to mean "all variable bindings" was silently over-matching every let and var. Post-upgrade the filter is precise; queries that wanted the over-match should widen to WHERE kind IN ('const', 'let', 'var'). Affected paths in this PR: the 40-query-patterns.md const-values example (now demonstrates the precise filter + adds two new patterns that depend on it — "lets that should be const" and "consts that get illegally written"), and find-write-sites.md prose where the recipe's documented JOIN trick now works as described.

    Mutability filters that finally work:

    -- bindings declared `let` but never reassigned — candidates to tighten to `const`
    SELECT s.name, s.file_path, s.line_start FROM symbols s
    WHERE s.kind = 'let'
      AND NOT EXISTS (
        SELECT 1 FROM "references" r
        WHERE r.name = s.name
          AND r.file_path = s.file_path
          AND r.is_write = 1
          AND r.line_start > s.line_start
      );
    
    -- `const`s that get reassigned anyway (TypeScript usually catches it; queryable here for completeness)
    SELECT s.name, s.file_path, s.line_start FROM symbols s
    JOIN "references" r ON r.name = s.name AND r.file_path = s.file_path
    WHERE s.kind = 'const' AND r.is_write = 1 AND r.line_start > s.line_start;

    find-symbol-by-kind recipe params updated to enumerate the new values explicitly.

    file_metrics keyword counts populate toolet_count / const_count / var_count were previously hardcoded to 0 (// let/const/var distinction not yet tracked per the in-source TODO). They now reflect the actual per-file counts. docs/architecture.md § file_metrics drops the "Reserved (parser-keyword variant TBD)" notes.

v0.6.1

15 May 15:02
a8c50b5

Choose a tag to compare

Patch Changes

  • #82 8e8aae0 Thanks @SutuSebastian! - Fix resolveBundledRecipesDir() path resolution — the 40 bundled recipes were unreachable at runtime in 0.6.0's published artifact. The resolver had one extra .. segment relative to where the bundler emits the dist chunk; bunx codemap query --recipes-json returned [] and bunx codemap query --recipe <id> rejected every bundled id with unknown recipe.

    The fix derives the bundled-recipes path off resolveAgentsTemplateDir() (same pattern used by resolveAgentContentDir()) so a single resolver handles both source-mode (bun src/index.ts) and dist-mode (node dist/index.mjs) without environment-specific branching — every chunk lands flat in dist/ regardless of the source file's nested depth.

    Discovered by a downstream consumer immediately after bun install @stainless-code/codemap@0.6.0. Regression guard: new src/application/query-recipes.dist.test.ts asserts existsSync(resolveBundledRecipesDir()) + catalog populates; CI gains a node dist/index.mjs query --recipes-json smoke step that exits non-zero on an empty catalog.

v0.6.0

15 May 13:50
cb74b58

Choose a tag to compare

Minor Changes

  • #80 7c3ba71 Thanks @SutuSebastian! - codemap skill / codemap rule — live-served agent content. Consumer-disk .agents/skills/codemap/SKILL.md and .agents/rules/codemap.md are now thin pointer files (~16-22 lines); the full content is served live by the installed binary, so bun update @stainless-code/codemap automatically refreshes what agents see without re-running agents init.

    Three transports, one engine:

    • CLI: codemap skill / codemap rule
    • MCP: resources codemap://skill / codemap://rule
    • HTTP: GET /resources/{encoded-uri} against codemap serve

    All three resolve through the same assembleAgentContent(kind) function. MCP and HTTP share a lazy per-process cache.

    Section assembler with *.gen.md renderers: templates/agent-content/<kind>/*.md files concatenate in lexical name order. Files ending in .gen.md route through RENDERERS in src/application/agent-content.ts — today, 20-recipes.gen.md regenerates the recipe catalog from listQueryRecipeCatalog() on every fetch, and 30-schema.gen.md regenerates table DDL from createTables(). Adding a recipe under templates/recipes/ or a column in src/db.ts now surfaces in the served skill automatically with zero template edits.

    Pointer protocol + staleness detection: every consumer-disk pointer carries <!-- codemap-pointer-version: N -->. On startup, codemap scans the consumer's .agents/{skills/codemap/SKILL,rules/codemap}.md; if the stamp is < EXPECTED_POINTER_VERSION (or absent on a fat legacy file > 50 lines), a one-line stderr nag prints with the fix command (codemap agents init --force). Warning is stderr-only so codemap skill > file.md stays clean.

    Rule trimmed to priming surface: the always-on rule shrank from 248 → 102 lines (~70% token reduction per turn) — STOP banner + trigger patterns table + top-11 quick reference queries + pointer to the skill for full reference. CLI command table / MCP narrative / audit + apply detail moved into the skill where they belong (on-demand, not every-turn).

    Migration: existing consumers re-run codemap agents init --force to swap their fat .agents/ files for the new pointer templates (the staleness nag prompts them on first invocation).

  • #78 84f9b97 Thanks @SutuSebastian! - codemap apply <recipe-id> — substrate-shaped fix executor over the existing --format diff-json row contract. The recipe SQL describes the transformation ({file_path, line_start, before_pattern, after_pattern} rows); codemap is the executor. Floor "No fix engine" preserved — codemap doesn't synthesise edits, it only executes the hunks the recipe row described.

    Three transports, one engine:

    • CLI: codemap apply <recipe-id> [--params k=v[,k=v]] [--dry-run] [--yes] [--json]
    • MCP tool: apply (registered alongside impact / show / snippet)
    • HTTP: POST /tool/apply

    All three dispatch the same pure applyDiffPayload engine in application/apply-engine.ts.

    Decisions worth knowing (Q1–Q10 locked in docs/plans/codemap-apply.md, lifted into docs/architecture.md § Apply wiring on this PR):

    • Apply-by-default, --dry-run opts into preview. Verb-name semantics + git apply / terraform apply precedent.
    • Per-recipe-run all-or-nothing (Q2 (c)). Phase 1 validates every row first; any conflict aborts phase 2 entirely before any file is touched. Cross-file invariants matter — rename-preview produces a definition row + N import rows, and partial application leaves the project syntactically broken.
    • Scan-and-collect conflicts (Q3 (b)). Phase 1 walks every row and collects all conflicts in one pass — better remediation UX than fail-fast.
    • TTY prompt + --yes gate (Q6 (a)). Interactive contexts (TTY) get a Proceed? [y/N] prompt with default-N; non-interactive contexts (CI / agents / MCP / HTTP) require --yes (or yes: true) explicitly. --dry-run + --yes mutually exclusive.
    • Substring match per row, single-line (Q8 (a)). Mirrors buildDiffJson's contract verbatim — actual.includes(before_pattern) + actual.replace(before, after) with $-pre-escape per String.prototype.replace's GetSubstitution rule. Exemplar: templates/recipes/rename-preview.sql emits before_pattern = old_name (the bare identifier). When before_pattern appears more than once on the line (e.g. const foo = foo();), only the leftmost is replaced — same shape --format diff previews; recipe authors normalise their SQL if they need a different occurrence.
    • Path-containment guard. Every file_path is rejected with a path escapes project root conflict if it's absolute or if path.resolve(projectRoot, file_path) lands outside the project root. Defends the CLI + MCP + HTTP write paths against malicious or malformed recipe rows.
    • Overlap detection. Two rows targeting the same (file_path, line_start) are rejected with a duplicate edit on same line conflict during phase 1. Without it, the second row's substring assertion would fail mid-phase-2 (after earlier files in alphabetical order had already been renamed) — that would leave the project in a partial-write state and violate Q2 (c).
    • Atomic per-file writes via temp + rename. Sibling <file>.codemap-apply-<rand>.tmp then renameSync — POSIX-atomic so concurrent readers see either pre-rename or post-rename content, never a torn write.
    • Q7 idempotency (conflict-only path). Re-running on already-applied code reports line content drifted with actual_at_line showing the post-rename content; user re-runs codemap to refresh the index → next run produces 0 rows → vacuous clean apply.
    • Single envelope shape across modes (Q5). {mode, applied, files, conflicts, summary} — same shape for dry-run and apply; consumers pattern-match on mode + applied.
    • No SARIF / annotations. Apply is a write action, not a findings list.

    Boundary discipline (Q10): only cli/cmd-apply.ts + application/tool-handlers.ts may import the apply engine — re-runnable kit at docs/architecture.md § Boundary verification — apply write path.

    Plan: PR #77 (merged). Implementation: this PR.

  • #79 ec91bdf Thanks @SutuSebastian! - codemap-richer-index — substrate extraction across 12 tiers. Schema bump (SCHEMA_VERSION 10 → 26) — first run after upgrade rebuilds .codemap/index.db from source.

    10 new substrate tables: import_specifiers, scopes, references, bindings, function_params, file_metrics, re_export_chains, module_cycles, runtime_markers, test_suites.

    Column additions: symbols.{name_column_start, name_column_end, scope_local_id, body_line_count, param_count, nesting_depth} · calls.{line_start, column_start, column_end} · exports.{is_re_export, line_start, line_end, column_start, column_end} · markers.{column_start, column_end}.

    12 new recipes: find-references · find-symbol-references · find-write-sites · find-by-param-type · large-functions · deeply-nested-functions · circular-imports · barrel-chains · find-leftover-console · env-var-audit · find-skipped-tests · tests-by-file.

    Architecture: modular extractor pattern (R.17) splits parser.ts into per-tier extractors under src/extractors/ with a shared ExtractContext. Targeted reindex stays sub-100ms; full reindex includes bindings resolution + Tarjan SCC + re-export chain materialisation.

    Reference precision: references table emits every identifier USE with column-precise positions; kind='member' rows distinguish non-computed property access from bindings. Native JSX tags + JSXAttribute names + long-hand object-literal keys are suppressed. TSQualifiedName (e.g. React.ReactNode) splits into namespace head (kind='type') + member tail (kind='member'). Bindings resolver (full-rebuild only) walks same-file scope → imports → globals → unresolved with deduped TypeScript / DOM / Node / ES global sets. Re-export chains followed up to 10 hops with cycle detection.

    Dependency bumps: oxc-parser 0.127 → 0.130 · zod 4.3 → 4.4 (dedupe override added so the MCP SDK keeps a single $ZodType identity) · tsdown 0.21 → 0.22 (declared unrun as devDep to unblock CI build under Node's tsdown binstub).

    Docs sync: docs/architecture.md § Schema reflects every new table + column; docs/glossary.md gains 10 new entries; docs/golden-queries.md + fixtures/golden/ regenerated. Templates (templates/agents/) updated with the new schema overview + trigger patterns.

v0.5.0

14 May 14:44
bfc0b8a

Choose a tag to compare

Minor Changes

  • #35 119db38 Thanks @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=<name> 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.

  • #74 7889fed Thanks @SutuSebastian! - codemap audit --format <text|json|sarif> — emit a SARIF 2.1.0 doc directly from the audit envelope, no JSON→SARIF transform step needed. One rule per delta key (codemap.audit.files-added, codemap.audit.dependencies-added, codemap.audit.deprecated-added); one result per added row; severity = warning (audit deltas are more actionable than per-recipe note). Locations auto-detected via the same file_path / path / to_path / from_path priority list that query --format sarif uses; line ranges (line_start / line_end) populate the SARIF region. Pure output-formatter addition on top of the existing audit envelope; no schema impact.

    --json stays as the shortcut for --format json (backward-compatible). --json + --format <other> rejected as a contradiction. --summary is a no-op with --format sarif (SARIF results are per-row, not counts) and surfaces a stderr warning.

    removed rows are intentionally excluded from SARIF output — SARIF surfaces findings to act on, not cleanups. Location-only rows (e.g. files-added has only path) get a "new files: src/foo.ts" message instead of the generic "(no message)" fallback.

    This is the first half of Slice 1 from the GitHub Marketplace Action plan — independently useful for any CI consumer running codemap audit who wants Code Scanning surface without a translation layer; required for the upcoming Marketplace Action's headline default command.

  • #72 2c3045d Thanks @SutuSebastian! - feat(boundaries): config-driven architecture-boundary rules + boundary-violations recipe

    Adds the smallest substrate for first-class architecture boundary checks. Schema bump 8 → 9.

    Configure

    import { defineConfig } from "@stainless-code/codemap";
    
    export default defineConfig({
      boundaries: [
        {
          name: "ui-cant-touch-server",
          from_glob: "src/ui/**",
          to_glob: "src/server/**",
        },
      ],
    });

    action defaults to "deny" (the only shape v1 surfaces); "allow" reserves the slot for future whitelist semantics.

    Substrate

    • New config field boundaries: BoundaryRule[] on the Zod user-config schema (src/config.ts); validated at config-load time.
    • New table boundary_rules(name PK, from_glob, to_glob, action CHECK IN ('deny','allow')) (STRICT, WITHOUT ROWID) — fully derived from config, dropped on --full / SCHEMA_VERSION rebuilds and re-filled by the next index pass.
    • New helper reconcileBoundaryRules(db, rules) in src/db.ts; called from runCodemapIndex after createSchema so the table tracks config exactly.
    • New runtime accessor getBoundaryRules().

    Recipe

    templates/recipes/boundary-violations.{sql,md} joins dependencies × boundary_rules via SQLite GLOB and surfaces violating import edges as locatable rows. --format sarif and --format annotations light up automatically (the recipe aliases dependencies.from_path to file_path). Use as a CI gate:

    codemap query --recipe boundary-violations --format sarif > findings.sarif

    Lockstep

    • docs/architecture.md § Schema gains a boundary_rules subsection.
    • docs/glossary.md adds boundaries / boundary_rules / boundary-violations entry.
    • docs/roadmap.md § Backlog removes the now-shipped item per Rule 2.
    • templates/agents/rules/codemap.md, .agents/rules/codemap.md, templates/agents/skills/codemap/SKILL.md, .agents/skills/codemap/SKILL.md, and README.md all document the new shape.

    Tests

    src/application/boundary-rules.test.ts covers schema creation, idempotent reconciliation, CHECK constraint, and the recipe SQL against a synthetic dependency graph. src/config.test.ts covers Zod validation including default-action filling and unknown-action rejection.

  • #52 fe5a355 Thanks @SutuSebastian! - codemap audit --base <ref> — ad-hoc structural-drift audit against any git committish (origin/main, HEAD~5, <sha>, 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 <ref> [--<delta>-baseline <name>] [--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 "<ref>^{commit}" resolves <ref> to a sha (clean error on non-git or unresolvable ref).
    2. Cache lookup at <projectRoot>/.codemap/audit-cache/<sha>/.codemap.db. Hit → sub-100ms; miss → continue.
    3. Atomic populategit worktree add to a per-pid temp dir + runCodemapIndex({mode: "full"}) against the worktree's .codemap.db + POSIX rename claims the final <sha>/ 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 <prefix>. Parser + handler both guard. Per-delta --<key>-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, --<delta>-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.

  • #54 1313fc2 Thanks @SutuSebastian! - .codemap/ directory consolidation + self-healing files. Every codemap-managed path lives under a single config...

Read more