Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
55 changes: 28 additions & 27 deletions .agents/rules/codemap.md

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions .agents/skills/codemap/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Replace placeholders (`'...'`) with your module path, file glob, or symbol name.
- **`--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`.**
- **`--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.
- **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`**.
- **Boundary violations (config-driven)** — declare `boundaries: [{name, from_glob, to_glob, action?}]` in `.codemap/config.ts` and run `bun src/index.ts query --recipe boundary-violations [--format sarif]`. The `action` field defaults to `"deny"` (the only shape v1 surfaces); rules are reconciled into the `boundary_rules` table on every index pass and joined against `dependencies` via SQLite `GLOB`. See [`docs/architecture.md` § `boundary_rules`](../../../docs/architecture.md#boundary_rules--architecture-boundary-rules-config-derived-strict-without-rowid).
- **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.

**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:
Expand Down Expand Up @@ -510,9 +511,9 @@ bun src/index.ts query --json "SELECT key, value FROM meta"

## Troubleshooting

| Problem | Solution |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Stale results after rebase | Run **`bun src/index.ts --full`** (or **`codemap --full`** when exercising the packaged CLI) |
| Missing file in results | Check exclude / include globs in **`codemap.config.ts`**, **`codemap.config.json`**, or defaults in **`src/index.ts`** |
| `resolved_path` is NULL | Import is an external package (not in project) |
| Resolver errors | Verify `tsconfig.json` paths (or **`tsconfigPath`** in config) when resolving aliases |
| Problem | Solution |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Stale results after rebase | Run **`bun src/index.ts --full`** (or **`codemap --full`** when exercising the packaged CLI) |
| Missing file in results | Check exclude / include globs in **`.codemap/config.ts`**, **`.codemap/config.json`**, or defaults in **`src/index.ts`** |
| `resolved_path` is NULL | Import is an external package (not in project) |
| Resolver errors | Verify `tsconfig.json` paths (or **`tsconfigPath`** in config) when resolving aliases |
51 changes: 51 additions & 0 deletions .changeset/boundary-violations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
"@stainless-code/codemap": minor
---

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**

```ts
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:

```bash
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.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ codemap query --json --recipe fan-out-sample
# Parametrised recipes validate params from <id>.md frontmatter before SQL binding.
codemap query --json --recipe find-symbol-by-kind --params kind=function,name_pattern=%Query%
codemap query --recipe rename-preview --params old=usePermissions,new=useAccess,kind=function --format diff
# Architecture-boundary rules (declare in .codemap/config.ts):
# boundaries: [{ name: "ui-cant-touch-server", from_glob: "src/ui/**", to_glob: "src/server/**" }]
# Default action is "deny"; the table is reconciled from config on every index pass.
codemap query --recipe boundary-violations --format sarif > boundary-findings.sarif
# Counts only (skip the rows) — pairs well with --recipe for dashboards / agent context windows
codemap query --json --summary -r deprecated-symbols
# PR-scoped: filter result rows to those touching files changed since <ref>
Expand Down Expand Up @@ -128,7 +132,7 @@ codemap query --format mermaid 'SELECT from_path AS "from", to_path AS "to" FROM
codemap query --format diff 'SELECT "README.md" AS file_path, 1 AS line_start, "# Codemap" AS before_pattern, "# Codemap Preview" AS after_pattern'
codemap query --format diff-json 'SELECT "README.md" AS file_path, 1 AS line_start, "# Codemap" AS before_pattern, "# Codemap Preview" AS after_pattern' | jq '.summary'
# --with-fts — opt-in FTS5 virtual table populated at index time. Default OFF (preserves
# .codemap/index.db size); CLI flag wins over codemap.config.ts `fts5` field. Toggle change
# .codemap/index.db size); CLI flag wins over .codemap/config.ts `fts5` field. Toggle change
# auto-detects and forces a full rebuild so `source_fts` stays consistent.
codemap --with-fts --full
codemap query --recipe text-in-deprecated-functions # demonstrates FTS5 ⨯ symbols ⨯ coverage JOIN
Expand Down
9 changes: 8 additions & 1 deletion codemap.config.example.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"include": ["src/**/*.{ts,tsx,js,jsx}", "src/**/*.css", "**/*.{md,json}"],
"excludeDirNames": ["node_modules", ".git", "dist", "build", ".output"]
"excludeDirNames": ["node_modules", ".git", "dist", "build", ".output"],
"boundaries": [
{
"name": "ui-cant-touch-server",
"from_glob": "src/ui/*",
"to_glob": "src/server/*"
}
]
}
Loading
Loading