Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions .agents/rules/codemap.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@ A local database (default **`.codemap.db`**) indexes structure: symbols, imports

## CLI (this repository)

| Context | Incremental index | Query |
| ------------------------------ | ------------------ | ------------------------------------------------------------------------------------------ |
| **Default** — from this clone | `bun src/index.ts` | `bun src/index.ts query --json "<SQL>"` |
| Same entry | `bun run dev` | (same as first row) |
| Query (ASCII table — optional) | — | `bun src/index.ts query "<SQL>"` |
| Recipe | — | `bun src/index.ts query --json --recipe fan-out` (see **`bun src/index.ts query --help`**) |
| Recipe catalog / SQL | — | `bun src/index.ts query --recipes-json` · `bun src/index.ts query --print-sql fan-out` |
| Counts only | — | `bun src/index.ts query --json --summary -r deprecated-symbols` |
| PR-scoped rows | — | `bun src/index.ts query --json --changed-since origin/main -r fan-out` |
| Bucket by owner / dir / pkg | — | `bun src/index.ts query --json --group-by directory -r fan-in` |

**Recipe `actions`:** with **`--json`**, recipes that define an `actions` template append it to every row (kebab-case verb + description — e.g. `fan-out` → `review-coupling`). Inspect via **`--recipes-json`**. Ad-hoc SQL never carries actions.
| Context | Incremental index | Query |
| ------------------------------ | ------------------ | --------------------------------------------------------------------------------------------------------- |
| **Default** — from this clone | `bun src/index.ts` | `bun src/index.ts query --json "<SQL>"` |
| Same entry | `bun run dev` | (same as first row) |
| Query (ASCII table — optional) | — | `bun src/index.ts query "<SQL>"` |
| Recipe | — | `bun src/index.ts query --json --recipe fan-out` (see **`bun src/index.ts query --help`**) |
| Recipe catalog / SQL | — | `bun src/index.ts query --recipes-json` · `bun src/index.ts query --print-sql fan-out` |
| Counts only | — | `bun src/index.ts query --json --summary -r deprecated-symbols` |
| PR-scoped rows | — | `bun src/index.ts query --json --changed-since origin/main -r fan-out` |
| Bucket by owner / dir / pkg | — | `bun src/index.ts query --json --group-by directory -r fan-in` |
| Save / diff a baseline | — | `bun src/index.ts query --save-baseline -r visibility-tags` then `… --json --baseline -r visibility-tags` |
| List / drop baselines | — | `bun src/index.ts query --baselines` · `bun src/index.ts query --drop-baseline <name>` |

**Recipe `actions`:** with **`--json`**, recipes that define an `actions` template append it to every row (kebab-case verb + description — e.g. `fan-out` → `review-coupling`). Under `--baseline`, actions attach to the **`added`** rows only. Inspect via **`--recipes-json`**. Ad-hoc SQL never carries actions.

**Baselines** (`query_baselines` table inside `.codemap.db`, no parallel JSON files): `--save-baseline[=<name>]` snapshots a result set; `--baseline[=<name>]` diffs the current result against it (added / removed rows; identity = `JSON.stringify(row)`). Name defaults to the `--recipe` id; ad-hoc SQL needs an explicit `=<name>`. Survives `--full` and SCHEMA bumps.

After **`bun run build`**, **`node dist/index.mjs`** matches the published **`codemap`** binary (same flags). **`bun link`** / global **`codemap`** also work when testing the packaged CLI.

Expand Down
19 changes: 18 additions & 1 deletion .agents/skills/codemap/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ Replace placeholders (`'...'`) with your module path, file glob, or symbol name.
- **`--summary`** — counts only. With **`--json`**: **`{"count": N}`**. With **`--group-by`**: **`{"group_by": "<mode>", "groups": [{key, count}]}`**.
- **`--changed-since <ref>`** — post-filter rows by **`path`** / **`file_path`** / **`from_path`** / **`to_path`** / **`resolved_path`** against **`git diff --name-only <ref>...HEAD ∪ git status --porcelain`**. Rows with no recognised path column pass through.
- **`--group-by owner|directory|package`** — partition into buckets and emit **`{"group_by", "groups": [{key, count, rows}]}`**. **`owner`** reads CODEOWNERS (last matching rule wins); **`directory`** is the first path segment; **`package`** uses **`package.json`** **`workspaces`** or **`pnpm-workspace.yaml`**.
- **Per-row recipe `actions`** — recipes that define an **`actions: [{type, auto_fixable?, description?}]`** template append it to every row in **`--json`** output (recipe-only; ad-hoc SQL never carries actions). Inspect via **`--recipes-json`**.
- **`--save-baseline[=<name>]`** — snapshot the result rows to the **`query_baselines`** table inside `.codemap.db` (no parallel JSON files; survives `--full` and SCHEMA bumps). Name defaults to the `--recipe` id; ad-hoc SQL needs an explicit `=<name>`. Re-saving with the same name overwrites in place.
- **`--baseline[=<name>]`** — diff the current result against the saved baseline. Output `{baseline:{...}, current_row_count, added: [...], removed: [...]}` (with `--json`) or a two-section terminal dump. Identity = per-row `JSON.stringify` equality. Pair with `--summary` for `{added: N, removed: N}`.
- **`--baselines`** lists saved baselines (no `rows_json` payload); **`--drop-baseline <name>`** deletes one.
- **Per-row recipe `actions`** — recipes that define an **`actions: [{type, auto_fixable?, description?}]`** template append it to every row in **`--json`** output (recipe-only; ad-hoc SQL never carries actions). Under `--baseline`, actions attach to the **`added`** rows only (the rows the agent should act on). Inspect via **`--recipes-json`**.

**Determinism:** Bundled recipes use stable secondary **`ORDER BY`** tie-breakers (and ordered inner **`LIMIT`** samples where applicable). Prefer **`--recipe`** over pasting SQL when you need the maintained ordering. **Canonical SQL** is **`src/cli/query-recipes.ts`** (`QUERY_RECIPES`).

Expand Down Expand Up @@ -212,6 +215,20 @@ LIMIT 10
| `project_root` | Absolute path to project |
| `schema_version` | Schema version number |

### `query_baselines` — Saved query result snapshots (user data)

User-facing baselines saved by `codemap query --save-baseline`, replayed by `codemap query --baseline`. **Survives `--full` and SCHEMA bumps** — intentionally absent from `dropAll()`.

| Column | Type | Description |
| ---------- | ------- | ---------------------------------------------------------------------------------------- |
| name | TEXT PK | User-supplied name; defaults to the `--recipe` id (ad-hoc SQL requires an explicit name) |
| recipe_id | TEXT | The `--recipe` id when known; NULL for ad-hoc SQL |
| sql | TEXT | The SQL that produced the snapshot |
| rows_json | TEXT | Canonical `JSON.stringify(rows)` — set-diff identity = per-row JSON-stringify equality |
| row_count | INTEGER | Cached length of `rows_json` |
| git_ref | TEXT | `git rev-parse HEAD` at save time, or NULL when not a git working tree |
| created_at | INTEGER | `Date.now()` at save time (epoch ms) |

## Query patterns

### Basic lookups
Expand Down
5 changes: 5 additions & 0 deletions .changeset/query-baselines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@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 <name>` 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.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ codemap query --json --summary --changed-since HEAD~5 "SELECT file_path FROM sym
codemap query --json --summary --group-by directory -r fan-in
codemap query --json --group-by owner -r deprecated-symbols
codemap query --json --summary --group-by package "SELECT file_path FROM symbols"
# Snapshot a result, refactor, then diff (saved inside .codemap.db, no JSON files)
codemap query --save-baseline -r visibility-tags # save under name "visibility-tags"
codemap query --json --baseline -r visibility-tags # full diff: {baseline, added, removed}
codemap query --json --summary --baseline -r visibility-tags # counts only: {added, removed}
codemap query --baselines # list saved baselines
codemap query --drop-baseline visibility-tags # delete
Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Recipes that define per-row action templates append "actions" hints (kebab-case verb +
# description) in --json output; ad-hoc SQL never carries actions. Inspect via --recipes-json.
# List bundled recipes as JSON, or print one recipe's SQL (no DB required)
Expand Down
18 changes: 16 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ A local SQLite database (`.codemap.db`) indexes the project tree and stores stru

**Commands and flags** (index, query, **`codemap agents init`**, **`--root`**, **`--config`**, environment): [../README.md § CLI](../README.md#cli) — **do not duplicate** flag lists here; this section only adds implementation notes. From this repository: **`bun run dev`** or **`bun src/index.ts`** (same flags).

**Query wiring:** **`src/cli/cmd-query.ts`** (argv, **`printQueryResult`**, `--recipe` / `-r` alias, **`--summary`**, **`--changed-since`**, **`--group-by`**), **`src/cli/query-recipes.ts`** (**`QUERY_RECIPES`** — bundled SQL only source; optional **`actions: RecipeAction[]`** per recipe), **`src/cli/main.ts`** (**`--recipes-json`** / **`--print-sql`** exit before config/DB). With **`--json`**, errors use **`{"error":"…"}`** on stdout for SQL failures, DB open, and bootstrap (same shape); **`runQueryCmd`** sets **`process.exitCode`** instead of **`process.exit`**. Friendlier "no `.codemap.db`" — `no such table: <X>` and `no such column: <X>` errors are rewritten in **`enrichQueryError`** to point at `codemap` / `codemap --full`. **`--summary`** filters output only — the SQL still executes against the index; output collapses to `{"count": N}` (with `--json`) or `count: N`. **`--changed-since <ref>`** post-filters result rows by `path` / `file_path` / `from_path` / `to_path` / `resolved_path` against `git diff --name-only <ref>...HEAD ∪ git status --porcelain` (helper: **`src/git-changed.ts`** — `getFilesChangedSince`, `filterRowsByChangedFiles`, `PATH_COLUMNS`); rows with no recognised path column pass through. **`--group-by <mode>`** (`owner` | `directory` | `package`) routes through **`runGroupedQuery`** in `cmd-query.ts` and emits `{"group_by": "<mode>", "groups": [{key, count, rows}]}` (or `[{key, count}]` with `--summary`); helpers in **`src/group-by.ts`** (`groupRowsBy`, `firstDirectory`, `loadCodeowners`, `discoverWorkspaceRoots`, `makePackageBucketizer`, `codeownersGlobToRegex`). CODEOWNERS lookup is last-match-wins (GitHub semantics); workspace discovery reads `package.json` `workspaces` and `pnpm-workspace.yaml` `packages:`. **Per-row recipe `actions`** are appended only when the user runs **`--recipe <id>`** with **`--json`** AND the recipe defines an `actions` template — programmatic `cm.query(sql)` and ad-hoc CLI SQL never carry actions. The **`components-by-hooks`** recipe ranks by hook count with a **comma-based tally** on **`hooks_used`** (no SQLite JSON1). Shipped **`templates/agents/`** documents **`codemap query --json`** as the primary agent example ([README § CLI](../README.md#cli)).
**Query wiring:** **`src/cli/cmd-query.ts`** (argv, **`printQueryResult`**, `--recipe` / `-r` alias, **`--summary`**, **`--changed-since`**, **`--group-by`**, **`--save-baseline`** / **`--baseline`** / **`--baselines`** / **`--drop-baseline`**), **`src/cli/query-recipes.ts`** (**`QUERY_RECIPES`** — bundled SQL only source; optional **`actions: RecipeAction[]`** per recipe), **`src/cli/main.ts`** (**`--recipes-json`** / **`--print-sql`** exit before config/DB). With **`--json`**, errors use **`{"error":"…"}`** on stdout for SQL failures, DB open, and bootstrap (same shape); **`runQueryCmd`** sets **`process.exitCode`** instead of **`process.exit`**. Friendlier "no `.codemap.db`" — `no such table: <X>` and `no such column: <X>` errors are rewritten in **`enrichQueryError`** to point at `codemap` / `codemap --full`. **`--summary`** filters output only — the SQL still executes against the index; output collapses to `{"count": N}` (with `--json`) or `count: N`. **`--changed-since <ref>`** post-filters result rows by `path` / `file_path` / `from_path` / `to_path` / `resolved_path` against `git diff --name-only <ref>...HEAD ∪ git status --porcelain` (helper: **`src/git-changed.ts`** — `getFilesChangedSince`, `filterRowsByChangedFiles`, `PATH_COLUMNS`); rows with no recognised path column pass through. **`--group-by <mode>`** (`owner` | `directory` | `package`) routes through **`runGroupedQuery`** in `cmd-query.ts` and emits `{"group_by": "<mode>", "groups": [{key, count, rows}]}` (or `[{key, count}]` with `--summary`); helpers in **`src/group-by.ts`** (`groupRowsBy`, `firstDirectory`, `loadCodeowners`, `discoverWorkspaceRoots`, `makePackageBucketizer`, `codeownersGlobToRegex`). CODEOWNERS lookup is last-match-wins (GitHub semantics); workspace discovery reads `package.json` `workspaces` and `pnpm-workspace.yaml` `packages:`. **`--save-baseline[=<name>]`** snapshots the result to the **`query_baselines`** table inside `.codemap.db` (no parallel JSON files; survives `--full` / SCHEMA bumps because the table is intentionally absent from `dropAll()`); name defaults to `--recipe` id, ad-hoc SQL needs an explicit name. **`--baseline[=<name>]`** replays the SQL, fetches the saved row set, and emits `{baseline:{...}, current_row_count, added: [...], removed: [...]}` (or `{added: N, removed: N}` with `--summary`); identity is per-row `JSON.stringify` equality, no fuzzy "changed" category in v1. **`--baselines`** (read-only list) and **`--drop-baseline <name>`** complete the surface; helpers in **`src/db.ts`** (`upsertQueryBaseline`, `getQueryBaseline`, `listQueryBaselines`, `deleteQueryBaseline`). **Per-row recipe `actions`** are appended only when the user runs **`--recipe <id>`** with **`--json`** AND the recipe defines an `actions` template — programmatic `cm.query(sql)` and ad-hoc CLI SQL never carry actions; under `--baseline`, actions attach to `added` rows only (the rows the agent should act on). The **`components-by-hooks`** recipe ranks by hook count with a **comma-based tally** on **`hooks_used`** (no SQLite JSON1). Shipped **`templates/agents/`** documents **`codemap query --json`** as the primary agent example ([README § CLI](../README.md#cli)).
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

**Validate wiring:** **`src/cli/cmd-validate.ts`** — **`computeValidateRows`** is a pure function over `(db, projectRoot, paths)` returning `{path, status}` rows where `status ∈ stale | missing | unindexed`. CLI wraps it with read-once-and-print + exits **1** on any drift (git-status semantics). Path normalization: **`toProjectRelative`** converts CLI input to POSIX-style relative keys matching the `files.path` storage format (Windows backslash → forward slash); same convention as `lint-staged.config.js`.

Expand Down Expand Up @@ -161,7 +161,7 @@ Optional **`codemap.config.ts`** (default export: object or async factory) or **

**Fresh database:** the default CLI **`codemap`** (incremental) calls **`createSchema()`** in **`runCodemapIndex`** before **`getChangedFiles()`**, so the **`meta`** table exists before **`getMeta(..., "last_indexed_commit")`** runs on an empty **`.codemap.db`**.

Current schema version: **4** — see [Schema Versioning](#schema-versioning) for details.
Current schema version: **5** — see [Schema Versioning](#schema-versioning) for details.

All tables use `STRICT` mode. Tables marked with `WITHOUT ROWID` store data directly in the primary key B-tree. PRAGMAs and index design: [SQLite Performance Configuration](#sqlite-performance-configuration).

Expand Down Expand Up @@ -308,6 +308,20 @@ Edges are deduped per (caller_scope, callee) per file: if `foo` calls `bar` thre
| key | TEXT PK | e.g. `schema_version`, `last_indexed_commit`, `indexed_at` |
| value | TEXT | Stored value |

### `query_baselines` — Saved query result snapshots (user data) (`STRICT`)

User-facing baselines saved by `codemap query --save-baseline`, replayed by `codemap query --baseline` for diffs (added / removed rows). Lives next to the index tables so the entire codemap state stays in one SQLite file — no parallel JSON snapshot files. **Intentionally absent from `dropAll()`** so `--full` and `SCHEMA_VERSION` rebuilds preserve baselines (only index tables get dropped).

| Column | Type | Description |
| ---------- | ------- | ----------------------------------------------------------------------------------------- |
| name | TEXT PK | User-supplied name; defaults to the `--recipe` id (ad-hoc SQL must pass an explicit name) |
| recipe_id | TEXT | The `--recipe` id when known; NULL for ad-hoc SQL |
| sql | TEXT | The SQL that produced the snapshot (replayable; useful when re-running on a new branch) |
| rows_json | TEXT | Canonical `JSON.stringify(rows)`. Diff identity is per-row JSON-stringify equality |
| row_count | INTEGER | Cached length of `rows_json` for fast `--baselines` listing |
| git_ref | TEXT | `git rev-parse HEAD` at save time, or NULL when not a git working tree |
| created_at | INTEGER | `Date.now()` at save time (epoch ms) |

### Indexes

All tables have covering indexes tuned for AI agent query patterns. See [Covering indexes](#covering-indexes) and [Partial indexes](#partial-indexes) for the full list.
Expand Down
Loading
Loading