You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(recipes): parametrised recipes and rename preview (#71)
* feat(recipes): parametrised recipe infra + find-symbol-by-kind
Ships Slice 1 from the parametrised-recipes plan: recipe frontmatter can now
declare typed params, CLI/MCP/HTTP validate those params before SQL binding,
and query execution binds values through SQLite placeholders instead of string
interpolation.
Highlights:
- Add `params:` block-list frontmatter support alongside existing `actions:`.
Param types are `string | number | boolean`; omitted optional params bind
NULL internally so positional placeholders stay stable.
- Add strict param validation with clear `{error}` envelopes for missing,
unknown, and malformed params. CLI supports comma-separated and repeated
`--params`; duplicate keys use last-write semantics.
- Thread bind values through query execution, grouped results, baselines,
formatted outputs, MCP `query_recipe`, HTTP `query_recipe`, and golden-query
scenarios.
- Add bundled exemplar recipe `find-symbol-by-kind` and expose params metadata
in `--recipes-json` / recipe catalog entries.
- Update README, architecture docs, bundled agent rule + skill, and dev-side
mirrors per Rule 10.
- Add focused tests for param parsing, metadata loading, execution binding,
MCP/HTTP handler path, CLI parsing, and golden-query coverage.
Verification: bun run check (782 tests + golden scenarios) passes.
* feat(recipes): diff formatters + rename-preview recipe
Completes Slices 2 and 3 from the parametrised-recipes plan in the same PR:
- Add `--format diff` (plain unified diff) and `--format diff-json` (structured
hunks) for rows shaped as `{file_path, line_start, before_pattern,
after_pattern}`.
- Diff formatters read source files at format time and surface stale/missing
files instead of silently emitting partial output.
- Wire diff / diff-json through CLI, MCP, and HTTP formatted-output paths.
- Add conservative `rename-preview` bundled recipe using the new params + diff
infrastructure. V1 covers symbol definition lines and direct named import
specifiers; docs clearly call out call-site / re-export / string/comment
caveats until those source locations are indexed.
- Add golden scenario for rename-preview and docs / agent lockstep updates.
- Delete the completed plan file and remove its docs-index entry per Rule 3.
Verification: bun run check (786 tests + golden scenarios) passes.
* fix(recipes): address PR #71 fact-checked review comments
Verified each CodeRabbit thread against the code, applied real bugs and
substantive nits, kept changes minimal.
- scripts/query-golden.ts: reject params on raw-SQL scenarios so misconfigured
fixtures fail fast instead of silently running unbound SQL.
- output-formatters: add JSDoc to all new diff exports; treat \`after_pattern\`
as a literal so identifiers with \`$\` (e.g. \`$inject\`, \`$$factory\`) round-
trip through the diff; replace stale-vs-missing substring inference with an
explicit kind argument and preserve every per-file warning instead of
overwriting the last one.
- recipe-params: add JSDoc on every public symbol; accept numeric 1/0 for
boolean params so the MCP / HTTP path (where Zod permits z.number()) stops
rejecting legitimate inputs.
- recipes-loader: JSDoc on the new \`RecipeParamType\` / \`RecipeParam\` types;
refresh the \`extractFrontmatterAndBody\` JSDoc so it documents the new
\`params\` field.
- templates/recipes/rename-preview.sql: stop applying the \`in_file\` prefix to
\`target_symbols\` so import-only previews surface even when the symbol's
defining file is outside the scoped path; tighten the \`.md\` docstring to
describe the output-side filter explicitly.
New regression tests: \`$\`-escape, path-substring stale/missing classification,
multi-warning preservation, numeric boolean coercion.
* fix(recipes): address PR #71 round-2 fact-checked review feedback
Verified each CodeRabbit nit against the code, applied the substantive ones.
- cli/cmd-query: introduce a `structuredErrors` flag (true for any non-text
format) so bootstrap / param / `--changed-since` errors emit the same
`{"error":"..."}` envelope `printFormattedQuery` already uses, instead of
plain stderr only when `--format json`.
- application/query-engine: stop importing `RecipeParamValue`. Define a
local `QueryBindValue` union at the DB boundary so the engine layer no
longer depends on the recipe layer; recipe coercion stays in
`application/recipe-params.ts` and produces values assignable to it.
- application/index-engine: switch `printQueryResult` / `queryRows` bind
signatures to `QueryBindValue` for the same decoupling reason.
- application/query-recipes: doc the new `params` surface on
`QueryRecipeCatalogEntry` and `getQueryRecipeParams` so `--recipes-json`
and MCP catalog consumers are self-describing.
- application/recipes-loader: extract a shared `scanFrontmatterBlock` helper
so `parseActionsFromFrontmatter` and `parseParamsFromFrontmatter` no
longer duplicate the scanning skeleton.
- scripts/query-golden/schema: add a Zod refine that rejects raw-SQL
scenarios declaring `params` at parse time (matches the runtime check in
`query-golden.ts`).
- README: add a runnable `--format diff-json` example next to `--format diff`.
No behaviour change beyond the structured-errors flip and the schema-level
fail-fast on misconfigured fixtures.
@@ -35,14 +37,20 @@ A local database (default **`.codemap/index.db`**) indexes structure: symbols, i
35
37
| Coverage ingest | — |`bun src/index.ts ingest-coverage <path> [--json]` — Istanbul (`coverage-final.json`) or LCOV (`lcov.info`); format auto-detected. Joinable to `symbols` for "untested AND dead" queries. |
**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.
43
+
**Recipe metadata:** 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. Parametrised recipes declare `params` in `.md` frontmatter; pass values with `--params key=value[,key=value]` (repeatable; last value wins). Inspect both via **`--recipes-json`**. Ad-hoc SQL never carries actions or params.
41
44
42
45
**Project-local recipes:** drop `<id>.sql` (and optional `<id>.md` for description + actions) into **`<projectRoot>/.codemap/recipes/`** — auto-discovered, runs via `--recipe <id>` like bundled. Project recipes win on id collision; check `--recipes-json` for **`shadows: true`** entries to know when a project recipe overrides the documented bundled version. `<id>.md` supports YAML frontmatter for the per-row action template — block-list shape only (the loader's hand-rolled parser doesn't accept inline-flow `[{...}]`):
Copy file name to clipboardExpand all lines: .agents/skills/codemap/SKILL.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -45,7 +45,7 @@ Replace placeholders (`'...'`) with your module path, file glob, or symbol name.
45
45
-**`--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 multiset equality (canonical `JSON.stringify` keyed frequency map; duplicates preserved). Pair with `--summary` for `{baseline:{...}, current_row_count, added: N, removed: N}`. **Mutually exclusive with `--group-by`.**
46
46
-**`--baselines`** lists saved baselines (no `rows_json` payload); **`--drop-baseline <name>`** deletes one. Both reject every other flag — they're list-only / drop-only operations.
47
47
-**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`**.
48
-
- **Project-local recipes** — drop **`<id>.sql`** (and optional **`<id>.md`** for description body + actions) into **`<state-dir>/recipes/`** (default `<projectRoot>/.codemap/recipes/`) to make team-internal SQL a first-class CLI verb. `--recipes-json` and the `codemap://recipes` MCP resource list project recipes alongside bundled ones with **`source: "bundled" | "project"`** discriminating them. Project recipes win on id collision; entries that override a bundled id carry **`shadows: true`** so agents reading the catalog at session start know when a recipe behaves differently from the documented bundled version. `<id>.md` supports YAML frontmatter for the per-row action template — **block-list shape only** (loader's hand-rolled parser; no inline-flow `[{...}]`): `---\nactions:\n - type: my-verb\n auto_fixable: false\n description: "..."\n---`. Validation: SQL is rejected at load time if it starts with DML/DDL (DELETE/DROP/UPDATE/etc.); the runtime `PRAGMA query_only=1` is the parser-proof backstop. `.codemap/index.db` is gitignored; **`.codemap/recipes/` is NOT** — recipes are git-tracked source code authored for human review.
48
+
- **Project-local recipes** — drop **`<id>.sql`** (and optional **`<id>.md`** for description body, params, and actions) into **`<state-dir>/recipes/`** (default `<projectRoot>/.codemap/recipes/`) to make team-internal SQL a first-class CLI verb. `--recipes-json` and the `codemap://recipes` MCP resource list project recipes alongside bundled ones with **`source: "bundled" | "project"`** discriminating them. Project recipes win on id collision; entries that override a bundled id carry **`shadows: true`** so agents reading the catalog at session start know when a recipe behaves differently from the documented bundled version. `<id>.md` supports YAML frontmatter for `params:` and per-row `actions:` — **block-list shape only** (loader's hand-rolled parser; no inline-flow `[{...}]`). Param types: `string | number | boolean`; pass values with `--params key=value[,key=value]` (repeatable; last value wins). Example: `bun src/index.ts query --json --recipe find-symbol-by-kind --params kind=function,name_pattern=%Query%`. Validation: SQL is rejected at load time if it starts with DML/DDL (DELETE/DROP/UPDATE/etc.); params validate before SQL binding; runtime `PRAGMA query_only=1` is the parser-proof backstop. `.codemap/index.db` is gitignored; **`.codemap/recipes/` is NOT** — recipes are git-tracked source code authored for human review.
49
49
50
50
**Audit (`bun src/index.ts audit`)** — separate top-level command for structural-drift verdicts. Composes B.6 baselines into a per-delta `{head, deltas}` envelope; v1 ships `files` / `dependencies` / `deprecated`. Two snapshot-source shapes:
51
51
@@ -62,9 +62,9 @@ Each emitted delta carries its own `base` metadata so mixed-baseline audits are
62
62
63
63
**Tools (snake_case keys — Codemap convention matching MCP spec examples + reference servers; spec is convention-agnostic. CLI stays kebab; translation lives at the MCP-arg layer.):**
64
64
65
-
-**`query`** — one SQL statement. Args: `{sql, summary?, changed_since?, group_by?, format?}`. Same envelope as `codemap query --json`. Pass `format: "sarif"` or `"annotations"` to receive a formatted text payload (SARIF 2.1.0 doc / `::notice` lines); ad-hoc SQL gets `rule.id = codemap.adhoc`. Format is incompatible with `summary` / `group_by` (parser rejects with a structured `{error}`).
65
+
-**`query`** — one SQL statement. Args: `{sql, summary?, changed_since?, group_by?, format?}`. Same envelope as `codemap query --json`. Pass `format: "sarif" | "annotations" | "mermaid" | "diff" | "diff-json"` to receive a formatted payload; ad-hoc SQL gets `rule.id = codemap.adhoc` for SARIF. `diff` expects rows shaped as `{file_path, line_start, before_pattern, after_pattern}` and emits read-only unified diff text; `diff-json` emits structured hunks. Format is incompatible with `summary` / `group_by` (parser rejects with a structured `{error}`).
66
66
-**`query_batch`** — MCP-only, no CLI counterpart. Args: `{statements: (string | {sql, summary?, changed_since?, group_by?})[], summary?, changed_since?, group_by?}`. Items are bare SQL strings (inherit batch-wide flag defaults) or objects (override on a per-key basis). Output is N-element array; per-element shape mirrors single-`query`'s output for that statement's effective flag set. Per-statement errors are isolated — failed statements return `{error}` in their slot; siblings still execute. SQL-only (no `recipe` polymorphism in items). `format` deferred to v1.x — annotation/sarif on a heterogeneous batch is awkward; call `query` per recipe instead.
67
-
-**`query_recipe`** — `{recipe, summary?, changed_since?, group_by?, format?}`. Resolves the recipe id to SQL + per-row actions, then executes like `query`. Unknown recipe id returns a structured `{error}` pointing at the `codemap://recipes` resource. With `format: "sarif"`, `rule.id = codemap.<recipe>`, `rule.shortDescription` = recipe description, `rule.fullDescription` = the recipe's `<id>.md` body.
67
+
-**`query_recipe`** — `{recipe, params?, summary?, changed_since?, group_by?, format?}`. Resolves the recipe id to SQL + params + per-row actions, then executes like `query`. `params` is a nested object, e.g. `{recipe: "find-symbol-by-kind", params: {kind: "function", name_pattern: "%Query%"}}`; values validate against the recipe's `.md` frontmatter before SQL binding. Unknown recipe id returns a structured `{error}` pointing at the `codemap://recipes` resource. With `format: "sarif"`, `rule.id = codemap.<recipe>`, `rule.shortDescription` = recipe description, `rule.fullDescription` = the recipe's `<id>.md` body. `format: "diff" | "diff-json"` is read-only preview output; codemap never writes files. Example: `bun src/index.ts query --recipe rename-preview --params old=usePermissions,new=useAccess,kind=function --format diff`.
68
68
-**`audit`** — `{base?, baseline_prefix?, baselines?: {files?, dependencies?, deprecated?}, summary?, no_index?}`. Composes per-delta snapshots into the `{head, deltas}` envelope. Two **primary** sources are mutually exclusive: `base: <ref>` (git committish — worktree+reindex against any committish; sha-keyed cache under `.codemap/audit-cache/`; sub-100ms second run; requires git, errors cleanly on non-git projects) OR `baseline_prefix: "<prefix>"` (auto-resolve `<prefix>-{files,dependencies,deprecated}` from `query_baselines`). Plus optional **per-delta overrides** via `baselines: {<key>: <name>}` that compose with either primary source. Per-delta `base.source` is `"ref"` (with `base.ref` + `base.sha`) or `"baseline"` (with `base.name` + `base.sha`). Auto-runs incremental index unless `no_index: true`; watch-active sessions skip the prelude automatically.
69
69
-**`save_baseline`** — polymorphic `{name, sql? | recipe?}` with runtime exclusivity check (mirrors the CLI's single `--save-baseline=<name>` verb). Pass exactly one of `sql` or `recipe`.
70
70
-**`list_baselines`** — no args; returns the array `codemap query --baselines --json` would print.
-**`--format diff-json`** emits `{files, warnings, summary}` for agents that need structured hunks.
19
+
- Source files are read at format time. If a file is missing or the indexed line no longer contains `before_pattern`, the formatter marks it `missing` / `stale` in `diff-json` and emits `# WARNING:` comments at the top of plain diff output.
20
+
- Same formatter support is exposed through MCP / HTTP `format: "diff" | "diff-json"` on `query` and `query_recipe`.
21
+
22
+
This is read-only preview infrastructure — codemap never writes files.
feat(recipes): parametrised recipe support + `find-symbol-by-kind`
6
+
7
+
Recipes may now declare `params` in sibling `<id>.md` frontmatter and consume values through positional `?` placeholders in SQL. Values validate before SQL binding and support `string`, `number`, and `boolean` types.
The v1 recipe emits rows shaped for `--format diff` / `diff-json` and covers:
16
+
17
+
- symbol definition lines from `symbols`
18
+
- direct named import specifier lines from `imports.specifiers` when `imports.resolved_path` points at the target symbol file
19
+
20
+
It intentionally does **not** cover call sites, re-export alias chains, string literals, comments, dynamic dispatch, or template-literal property access yet. Those require more precise source-location substrate (for calls / exports) or non-structural search. The recipe `.md` documents the caveats clearly and repeats the key product-floor rule: codemap never writes files; this is a preview for review / `git apply --check`.
21
+
22
+
Parameters:
23
+
24
+
-`old` (required string)
25
+
-`new` (required string)
26
+
-`kind` (optional string)
27
+
-`in_file` (optional string path prefix)
28
+
-`include_tests` (optional boolean, default true)
29
+
-`include_re_exports` (optional boolean, default true; reserved until export locations are indexed)
0 commit comments