diff --git a/.cursor/rules/codegraph.mdc b/.cursor/rules/codegraph.mdc index 87daa27b..48c6948c 100644 --- a/.cursor/rules/codegraph.mdc +++ b/.cursor/rules/codegraph.mdc @@ -18,7 +18,7 @@ Reach for `codegraph_explore` before grep/find or Read for any **structural** qu - **Don't grep or Read first** to find or understand indexed code — one `codegraph_explore` returns the relevant source in a single round-trip. Reach for raw Read/Grep only to confirm a specific detail codegraph didn't cover, or for what it doesn't index (configs, docs). - **Index lag — check the staleness banner, don't guess a wait.** When a codegraph response starts with "⚠️ Some files referenced below were edited since the last index sync…", the listed files are pending re-index — Read those specific files for accurate content. Files NOT in that banner are fresh and codegraph is authoritative for them. -### If `.codegraph-vba/` doesn't exist +### If `.codegraph/` doesn't exist The MCP server returns "not initialized." Ask the user: *"I notice this project doesn't have CodeGraph-VBA initialized. Want me to run `codegraph-vba init` to build the index?"* diff --git a/.gitignore b/.gitignore index 103b125f..5f1afe5e 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ docs/business/ # CodeGraph data directories (in test projects) .codegraph/ +# Legacy data directory written by releases before #324 .codegraph-vba/ # Test-local fixture copy (issue #281). `extraction-vba-event-synth.test.ts` diff --git a/CHANGELOG.md b/CHANGELOG.md index 22104548..afae554d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Breaking Changes + +- The per-project index now lives in `.codegraph/`, the same directory upstream CodeGraph and agent tooling look for, instead of `.codegraph-vba/`. Existing projects need a fresh `codegraph-vba init`; an old `.codegraph-vba/` folder is ignored by indexing and can be deleted. (#324) ## [1.17.2] - 2026-09-12 diff --git a/CLAUDE.md b/CLAUDE.md index a971a25b..8cf32c53 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -CodeGraph-VBA is a local-first code intelligence library + CLI + MCP server. It parses any supported codebase with tree-sitter, stores symbols/edges/files in SQLite (FTS5), and exposes a knowledge graph to AI agents (Claude Code, Cursor, Codex CLI, opencode) over MCP. Per-project data lives in `.codegraph-vba/`. Extraction is deterministic — derived from AST, not LLM-summarized. +CodeGraph-VBA is a local-first code intelligence library + CLI + MCP server. It parses any supported codebase with tree-sitter, stores symbols/edges/files in SQLite (FTS5), and exposes a knowledge graph to AI agents (Claude Code, Cursor, Codex CLI, opencode) over MCP. Per-project data lives in `.codegraph/`. Extraction is deterministic — derived from AST, not LLM-summarized. Distributed as `codegraph-vba` on npm; same binary serves as installer, indexer, and MCP server. @@ -104,7 +104,7 @@ CodeGraph's only channels to influence the agent are low-salience: the MCP `init What works is meeting the agent where it already is: - **explore-flow** — `codegraph_explore` is the PRIMARY tool the agent reliably calls; its query is a precise bag of symbol names (incl. qualified `Class.method`) spanning the flow the agent is after; explore finds the call path _among those named symbols_ (riding synthesized edges) and leads its output with it. (`buildFlowFromNamedSymbols`: segment/co-naming disambiguation; ≤1 unnamed bridge so it never wanders a god-function's fan-out. Overload-aware: a PascalCase type token in the query biases an overloaded name to that type's own def — `DataRequest task` → DataRequest's `task`, not the abstract base; named-symbol files sort first.) - **Sufficiency** — make the tool's output complete enough that the agent stops. `codegraph_node` returns the full body + the caller/callee trail, and for an AMBIGUOUS name returns **every overload's body in one call** (so the agent never Reads a file to find the right overload — validated on Alamofire/gin). This is the after-explore depth tool (labeled SECONDARY). -- **Errors teach abandonment** — one or two `isError: true` responses early in a session and the agent stops calling codegraph entirely (maintainer-observed, repeatedly). `isError` is reserved for genuine "stop trying" cases: security refusals (`PathRefusalError`) and real malfunctions (which carry a retry-once note). Every expected/recoverable condition — project not indexed, symbol not found, file not in the index — returns a **SUCCESS-shaped response carrying the guidance** (`NotIndexedError` → `textResult`, see `ToolHandler.execute`'s catch). The same principle is why the tool surface is **always exposed, even at an un-indexed root** (the old empty-`tools/list` gate was removed in #964 — it broke monorepos where only sub-projects carry a `.codegraph-vba/`, and hid the tools from a session that started before `codegraph-vba init`): safety comes from the response SHAPE (success-shaped guidance, never `isError`), not from hiding tools. An un-indexed root's `initialize` sends a per-project variant (`SERVER_INSTRUCTIONS_NO_ROOT_INDEX` — "pass `projectPath` to a project that has a `.codegraph-vba/`"), not an "inactive" note; indexing is still deliberately the user's call, never the agent's. +- **Errors teach abandonment** — one or two `isError: true` responses early in a session and the agent stops calling codegraph entirely (maintainer-observed, repeatedly). `isError` is reserved for genuine "stop trying" cases: security refusals (`PathRefusalError`) and real malfunctions (which carry a retry-once note). Every expected/recoverable condition — project not indexed, symbol not found, file not in the index — returns a **SUCCESS-shaped response carrying the guidance** (`NotIndexedError` → `textResult`, see `ToolHandler.execute`'s catch). The same principle is why the tool surface is **always exposed, even at an un-indexed root** (the old empty-`tools/list` gate was removed in #964 — it broke monorepos where only sub-projects carry a `.codegraph/`, and hid the tools from a session that started before `codegraph-vba init`): safety comes from the response SHAPE (success-shaped guidance, never `isError`), not from hiding tools. An un-indexed root's `initialize` sends a per-project variant (`SERVER_INSTRUCTIONS_NO_ROOT_INDEX` — "pass `projectPath` to a project that has a `.codegraph/`"), not an "inactive" note; indexing is still deliberately the user's call, never the agent's. What fails is the inverse — folding a precise answer into a **fuzzy-input** tool: the now-removed `codegraph_context` took a description, not symbols, so it couldn't disambiguate a flow's endpoints and surfaced the _wrong feature_ (which is why it was cut). Precise output needs precise input — explore takes a symbol bag for exactly this reason. (`codegraph_trace` was likewise removed: explore-flow does its job and the agent under-picked it.) @@ -139,7 +139,7 @@ For each **language × framework**, validate on **small, medium, and large** rea 2. **Deterministic probes** (`scripts/agent-eval/probe-{node,explore}.mjs` against the built `dist/`): `codegraph_explore` with the flow's symbol names connects from→to end-to-end with no break (its Flow section shows the path); **no node explosion** (`select count(*) from nodes` stable before/after re-index); synthesized-edge **precision** spot-check (`select … where provenance='heuristic'`). 3. **Agent A/B** (`scripts/agent-eval/run-all.sh ""`): with vs without codegraph, **≥2 runs/arm** (run-to-run variance is large — never conclude from n=1). Record **duration, total tool calls, Read, Grep**. Optional forced-Read-0 sufficiency proof via the block-read hook (`scripts/agent-eval/hook-settings.json`). - **Model policy — every A/B arm runs Claude with `--model sonnet --effort high`. Always. Never Opus/Fable.** All `scripts/agent-eval/*.sh` default to this (`MODEL`/`EFFORT` env override exists — don't raise it without an explicit reason from the maintainer). Two reasons, and the second matters more than cost: (a) Sonnet doesn't burn tokens; (b) **Sonnet is the deliberate floor model** — codegraph's real users attach it to whatever agent they already run (Cursor Composer, Gemini, etc.), so we validate on a "dumber" model on purpose: a stronger model's tool-use covers up the salience/sufficiency problems a weaker one exposes. An affordance that lands on Sonnet generalizes up to every host; one that only works on Opus/Fable doesn't generalize down to the agents most users actually have. Both arms always use the same model. - - **MCP attach is a startup-latency issue, not a hard block.** On a multi-step task the agent dives into Read/grep before codegraph-vba finishes its ~2-3s startup (worse when the eval is itself run nested inside a Claude session, under CPU contention), so it runs with no codegraph. Fix: **pre-warm a persistent daemon** for the target (`CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS` high; spawn `serve --mcp --path "" [baseline-ref]` (it bakes in the pre-warm). + - **MCP attach is a startup-latency issue, not a hard block.** On a multi-step task the agent dives into Read/grep before codegraph-vba finishes its ~2-3s startup (worse when the eval is itself run nested inside a Claude session, under CPU contention), so it runs with no codegraph. Fix: **pre-warm a persistent daemon** for the target (`CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS` high; spawn `serve --mcp --path "" [baseline-ref]` (it bakes in the pre-warm). 4. **Pass bar:** a normal flow question reaches **~0 Read/Grep within the repo's explore-call budget**, runs **faster** than without-codegraph, and shows **no regression on a control repo**. Record the numbers in `docs/design/dynamic-dispatch-coverage-playbook.md` (the coverage matrix). Full playbook + per-mechanism design: `docs/design/dynamic-dispatch-coverage-playbook.md` and `docs/design/callback-edge-synthesis.md`. diff --git a/README.md b/README.md index ed29bf25..ab5c3c29 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ cd your-project codegraph-vba init ``` -`codegraph-vba init` creates the local `.codegraph-vba/` directory and builds the full graph in the same step — one command, done. +`codegraph-vba init` creates the local `.codegraph/` directory and builds the full graph in the same step — one command, done.
@@ -148,7 +148,7 @@ Changed your mind? One command removes CodeGraph from every agent it configured: codegraph-vba uninstall ``` -Reverses the installer — strips CodeGraph's MCP server config, instructions, and permissions from each configured agent. Your project indexes (`.codegraph-vba/`) are left untouched; remove those per-project with `codegraph-vba uninit`. Use `--target` to remove from specific agents, or `--yes` to run non-interactively. +Reverses the installer — strips CodeGraph's MCP server config, instructions, and permissions from each configured agent. Your project indexes (`.codegraph/`) are left untouched; remove those per-project with `codegraph-vba uninit`. Use `--target` to remove from specific agents, or `--yes` to run non-interactively. --- @@ -595,7 +595,7 @@ codegraph-vba init Builds the per-project knowledge graph index, which then auto-syncs on every file change. A single global `codegraph-vba install` works in every project you open — no need to re-run the installer per project. -That's it — your agent will use CodeGraph tools automatically when a `.codegraph-vba/` directory exists. +That's it — your agent will use CodeGraph tools automatically when a `.codegraph/` directory exists.
Manual Setup (Alternative) @@ -641,7 +641,7 @@ CodeGraph's MCP server delivers its usage guidance to your agent **automatically - **Answer structural questions directly with CodeGraph** — it *is* the pre-built index, so a grep/read loop just repeats work it already did. Treat the returned source as already read. - **Reach for `codegraph_explore` for almost anything** — "how does X work", a flow/"how does X reach Y", or surveying an area. One call returns the relevant symbols' verbatim source grouped by file, the call paths between them (dynamic-dispatch hops included), and a blast-radius summary. Name a file or symbol in the query to read its current line-numbered source. - **Trust the results — don't re-verify with grep**, and check the staleness banner after edits. -- Works **per project**: query any project that has a `.codegraph-vba/` index by passing `projectPath` — so a monorepo where only some services are indexed, or a second repo, works in one session. A path with no index returns clean guidance to use built-in tools; indexing stays your decision. +- Works **per project**: query any project that has a `.codegraph/` index by passing `projectPath` — so a monorepo where only some services are indexed, or a second repo, works in one session. A path with no index returns clean guidance to use built-in tools; indexing stays your decision. The exact text is `src/mcp/server-instructions.ts` — the single source of truth for the main agent. Because subagents and non-MCP harnesses never see the MCP guidance, the installer also writes a short marker-fenced section into the agent's instructions file pointing at the `codegraph-vba explore` CLI equivalent. @@ -674,7 +674,7 @@ The exact text is `src/mcp/server-instructions.ts` — the single source of trut 1. **Extraction** — [tree-sitter](https://tree-sitter.github.io/) parses source code into ASTs. Language-specific queries extract nodes (functions, classes, methods) and edges (calls, imports, extends, implements). -2. **Storage** — Everything goes into a local SQLite database (`.codegraph-vba/codegraph.db`) with FTS5 full-text search. +2. **Storage** — Everything goes into a local SQLite database (`.codegraph/codegraph.db`) with FTS5 full-text search. 3. **Resolution** — After extraction, references are resolved: function calls → definitions, imports → source files, class inheritance, and framework-specific patterns. @@ -750,7 +750,7 @@ When running as an MCP server, CodeGraph exposes a **single tool** — `codegrap The other tools (`codegraph_node`, `codegraph_search`, `codegraph_callers`, `codegraph_callees`, `codegraph_impact`, `codegraph_files`, `codegraph_status`, and the Access-specific `codegraph_behavior_evidence`) stay fully functional but **unlisted by default** — everything they return already arrives inline on `codegraph_explore` (its blast-radius section, the relationship map, a symbol's body as its callee list). Re-enable any of them for the MCP surface with the `CODEGRAPH_MCP_TOOLS` environment variable (e.g. `CODEGRAPH_MCP_TOOLS=explore,node,search,callers`), or use their CLI equivalents (`codegraph-vba node` / `query` / `callers` / `callees` / `impact` / `files` / `status`). -Even when the server's own root has no `.codegraph-vba/` index, the tools stay available: pass `projectPath` to query any indexed project — a sub-service in a monorepo, or a second repo — in the same session. A path that has no index returns clean guidance to use built-in tools instead, so nothing fails loudly, and indexing stays your decision. +Even when the server's own root has no `.codegraph/` index, the tools stay available: pass `projectPath` to query any indexed project — a sub-service in a monorepo, or a second repo — in the same session. A path that has no index returns clean guidance to use built-in tools instead, so nothing fails loudly, and indexing stays your decision. --- @@ -973,7 +973,7 @@ Framework routing is validated the same way, on a canonical app per framework: E **MCP hits `database is locked`** — current builds shouldn't: CodeGraph bundles its own Node runtime and uses Node's built-in `node:sqlite` in WAL mode, where concurrent reads never block on a writer. If you still see it: - **You're on an old (pre-0.9) install.** Reinstall to get the bundled runtime — `curl -fsSL https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.sh | sh` (macOS/Linux), `irm https://raw.githubusercontent.com/ardelperal/codegraph-vba/main/install.ps1 | iex` (Windows), or `npm i -g @aroman22/codegraph-vba@latest`. -- **`codegraph-vba status` shows `Journal:` other than `wal`** — WAL couldn't be enabled on this filesystem (common on network shares and WSL2 `/mnt`), so reads can block on writes. Move the project (with its `.codegraph-vba/` folder) onto a local disk. +- **`codegraph-vba status` shows `Journal:` other than `wal`** — WAL couldn't be enabled on this filesystem (common on network shares and WSL2 `/mnt`), so reads can block on writes. Move the project (with its `.codegraph/` folder) onto a local disk. **MCP server not connecting** — Your agent starts the server itself, so you don't launch it by hand. Make sure the project is initialized and indexed (`codegraph-vba status`) and that the path in your MCP config is correct. If it still won't connect, re-run `codegraph-vba install` to rewrite the config. @@ -981,7 +981,7 @@ Framework routing is validated the same way, on a canonical app per framework: E **Missing symbols** — The MCP server auto-syncs on save (wait a couple seconds). Run `codegraph-vba sync` manually if needed. Check that the file's language is supported and isn't inside a `.gitignore`d or default-excluded directory (e.g. `node_modules`, `dist`). -**Sharing one checkout between Windows and WSL** — Don't point both at the same `.codegraph-vba/`: the background-server lock and the SQLite index are tied to the OS that wrote them, and SQLite locking across the WSL2/Windows filesystem boundary is unreliable. Give each side its own index in the same tree by setting `CODEGRAPH_DIR` to a distinct name on one of them — e.g. `CODEGRAPH_DIR=.codegraph-win` on Windows, leaving WSL on the default `.codegraph-vba`. CodeGraph skips any sibling `.codegraph-*` directory when indexing and watching, so the two never trip over each other. +**Sharing one checkout between Windows and WSL** — Don't point both at the same `.codegraph/`: the background-server lock and the SQLite index are tied to the OS that wrote them, and SQLite locking across the WSL2/Windows filesystem boundary is unreliable. Give each side its own index in the same tree by setting `CODEGRAPH_DIR` to a distinct name on one of them — e.g. `CODEGRAPH_DIR=.codegraph-win` on Windows, leaving WSL on the default `.codegraph`. CodeGraph skips any sibling `.codegraph-*` directory when indexing and watching, so the two never trip over each other. ## Star History diff --git a/__tests__/daemon-release.test.ts b/__tests__/daemon-release.test.ts index 44241fde..4483711a 100644 --- a/__tests__/daemon-release.test.ts +++ b/__tests__/daemon-release.test.ts @@ -26,8 +26,8 @@ import { getStaticTools, ToolHandler } from '../src/mcp/tools'; function project(parent: string, name: string): string { const root = path.join(parent, name); - fs.mkdirSync(path.join(root, '.codegraph-vba'), { recursive: true }); - fs.writeFileSync(path.join(root, '.codegraph-vba', 'codegraph.db'), ''); + fs.mkdirSync(path.join(root, '.codegraph'), { recursive: true }); + fs.writeFileSync(path.join(root, '.codegraph', 'codegraph.db'), ''); return fs.realpathSync(root); } diff --git a/__tests__/daemon-socket-fallback.test.ts b/__tests__/daemon-socket-fallback.test.ts index 8f0df7d0..3862b4c9 100644 --- a/__tests__/daemon-socket-fallback.test.ts +++ b/__tests__/daemon-socket-fallback.test.ts @@ -74,7 +74,7 @@ describe('getDaemonSocketCandidates (#997)', () => { const root = path.join(os.tmpdir(), 'cg-cand-short'); const candidates = getDaemonSocketCandidates(root); expect(candidates).toHaveLength(2); - expect(candidates[0]).toBe(path.join(root, '.codegraph-vba', 'daemon.sock')); + expect(candidates[0]).toBe(path.join(root, '.codegraph', 'daemon.sock')); expect(candidates[1]!.startsWith(os.tmpdir())).toBe(true); expect(path.basename(candidates[1]!)).toMatch(/^codegraph-[0-9a-f]{16}\.sock$/); }); diff --git a/__tests__/daemon-watchdog.test.ts b/__tests__/daemon-watchdog.test.ts index fffa5803..ec843f08 100644 --- a/__tests__/daemon-watchdog.test.ts +++ b/__tests__/daemon-watchdog.test.ts @@ -27,15 +27,14 @@ function rec(root: string, pid: number, startedAt = Date.now()): DaemonRecord { } function fakeProject(): string { - // Make a fake .codegraph-vba/ dir (note the suffix — codegraph-vba's - // getCodeGraphDir() uses `.codegraph-vba`, NOT `.codegraph`) so + // Make a fake .codegraph/ dir so // findNearestCodeGraphRoot() and getDaemonPidPath() both resolve correctly. // isInitialized() requires BOTH the dir AND a codegraph.db file, so create // an empty placeholder db so the project looks "initialized" to the daemon // logic. const root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-watchdog-')); - fs.mkdirSync(path.join(root, '.codegraph-vba'), { recursive: true }); - fs.writeFileSync(path.join(root, '.codegraph-vba', 'codegraph.db'), ''); + fs.mkdirSync(path.join(root, '.codegraph'), { recursive: true }); + fs.writeFileSync(path.join(root, '.codegraph', 'codegraph.db'), ''); return root; } diff --git a/__tests__/dump-index-schema.test.ts b/__tests__/dump-index-schema.test.ts index 599f92ba..7dd4ea38 100644 --- a/__tests__/dump-index-schema.test.ts +++ b/__tests__/dump-index-schema.test.ts @@ -16,7 +16,7 @@ * external tools. * * The dump is tested against a FRESH temp DB created from the canonical - * `src/db/schema.sql` (NOT against the user's real `.codegraph-vba/codegraph.db`), + * `src/db/schema.sql` (NOT against the user's real `.codegraph/codegraph.db`), * so the test is hermetic — it never reads or mutates project state. */ diff --git a/__tests__/exclude-config.test.ts b/__tests__/exclude-config.test.ts index 6807eb31..e2b777b5 100644 --- a/__tests__/exclude-config.test.ts +++ b/__tests__/exclude-config.test.ts @@ -86,9 +86,9 @@ describe('exclude loader (codegraph.json)', () => { expect(loadExcludePatterns(dir)).toEqual([]); }); - it('loads and merges from local .codegraph-vba/config.json', () => { + it('loads and merges from local .codegraph/config.json', () => { // Write local config.json - const codegraphDir = path.join(dir, '.codegraph-vba'); + const codegraphDir = path.join(dir, '.codegraph'); fs.mkdirSync(codegraphDir, { recursive: true }); fs.writeFileSync( path.join(codegraphDir, 'config.json'), diff --git a/__tests__/extraction-vba-control-modeling.test.ts b/__tests__/extraction-vba-control-modeling.test.ts index fc7cfbe9..963d6dae 100644 --- a/__tests__/extraction-vba-control-modeling.test.ts +++ b/__tests__/extraction-vba-control-modeling.test.ts @@ -27,7 +27,7 @@ * - Tests are RED, no GREEN code is written here. * - No src/extraction/* files are modified. * - The CodeGraph index for hueco 5 is created under the fixture dir and - * cleaned up in afterAll so this test leaves no stale `.codegraph-vba/` + * cleaned up in afterAll so this test leaves no stale `.codegraph/` * behind in the repo. */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; @@ -258,7 +258,7 @@ describe('hueco-4: .form.txt emits kind=form-layout, NOT kind=module', () => { // ============================================================================= describe('huecos 3 & 5: VBA event-handler and Form_Load integration', () => { let cg: CodeGraph | null = null; - const codeGraphDir = path.join(FIXTURE_DIR, '.codegraph-vba'); + const codeGraphDir = path.join(FIXTURE_DIR, '.codegraph'); let initialized = false; beforeAll(async () => { diff --git a/__tests__/extraction-vba-event-synth.test.ts b/__tests__/extraction-vba-event-synth.test.ts index 82c70de3..aa881966 100644 --- a/__tests__/extraction-vba-event-synth.test.ts +++ b/__tests__/extraction-vba-event-synth.test.ts @@ -54,7 +54,7 @@ const FORM_MISMATCHED_BASENAME = 'Form_MismatchedName.cls'; let cg: CodeGraph | null = null; let initialized = false; -const codeGraphDir = path.join(FIXTURE_DIR, '.codegraph-vba'); +const codeGraphDir = path.join(FIXTURE_DIR, '.codegraph'); beforeAll(async () => { if (fs.existsSync(codeGraphDir)) { @@ -413,13 +413,13 @@ describe('issue-150 AC#5: vba-event-tracer backward compatibility', () => { // ============================================================================= // AC #6 — No new false positives on the existing FORMS-* fixture suite. // We index a COPY of the existing vba-control-modeling fixtures (kept -// under a test-local subdirectory so the .codegraph-vba database lives +// under a test-local subdirectory so the .codegraph database lives // in OUR directory, not in the shared source fixture) and verify the // count of vba-event-handler edges stays at zero. // // The copy is needed because the sibling // `__tests__/extraction-vba-control-modeling.test.ts` test owns the -// real `vba-control-modeling/.codegraph-vba` directory. When vitest +// real `vba-control-modeling/.codegraph` directory. When vitest // runs both test files in the same worker (file parallelism), both // tests try to open the same SQLite file and Windows returns EBUSY on // the second opener's unlink/cleanup. Copying the fixtures into our @@ -438,12 +438,12 @@ describe('issue-150 AC#6: no false positives on the FORMS-* (vba-control-modelin 'vba-control-modeling', ); // Test-local subdirectory. We copy the FORMS fixtures into here so - // our .codegraph-vba lives in OUR dir, not in the shared source + // our .codegraph lives in OUR dir, not in the shared source // dir. This is a subdirectory of the test workspace — kept under // the worktree but outside the existing vba-control-modeling // fixture so it doesn't conflict with sibling tests. const LOCAL_FORMS_DIR = path.join(FIXTURE_DIR, '.forms-copy'); - const LOCAL_FORMS_CODEGRAPH_DIR = path.join(LOCAL_FORMS_DIR, '.codegraph-vba'); + const LOCAL_FORMS_CODEGRAPH_DIR = path.join(LOCAL_FORMS_DIR, '.codegraph'); let formsCg: CodeGraph | null = null; let formsInit = false; @@ -452,12 +452,12 @@ describe('issue-150 AC#6: no false positives on the FORMS-* (vba-control-modelin // it. fs.cpSync with `recursive: true` is the idiomatic Node 16+ // way to deep-copy a directory; it's idempotent (we delete // LOCAL_FORMS_DIR first if it exists). We also EXCLUDE any - // `.codegraph-vba` subdirectory the source might have — that + // `.codegraph` subdirectory the source might have — that // subdirectory is owned by the sibling test // (`extraction-vba-control-modeling.test.ts`) and may still // exist on disk while that test's `afterAll` is still running in // a parallel vitest worker. Copying it in would leave a stale - // `.codegraph-vba` in our local copy and `CodeGraph.init` would + // `.codegraph` in our local copy and `CodeGraph.init` would // then refuse with "already initialized". rmWithRetry(LOCAL_FORMS_DIR, { recursive: true, force: true }); fs.cpSync(SOURCE_FORMS_DIR, LOCAL_FORMS_DIR, { diff --git a/__tests__/extraction-vba-framework-resolver.test.ts b/__tests__/extraction-vba-framework-resolver.test.ts index 8e4cfd25..66faf2ff 100644 --- a/__tests__/extraction-vba-framework-resolver.test.ts +++ b/__tests__/extraction-vba-framework-resolver.test.ts @@ -49,7 +49,7 @@ import { getCodeGraphDir } from '../src/directory'; // --------------------------------------------------------------------------- // Fixture gate: every test builds its OWN isolated temp project so config and // state never bleed. We do NOT use the `__tests__/fixtures/vba/` real-fixture -// directory ÔÇö that one carries a `.codegraph-vba/` produced by earlier tests +// directory ÔÇö that one carries a `.codegraph/` produced by earlier tests // and a strict `codegraph.json` could be left over from a previous run, // hiding a regression in our own loader. // --------------------------------------------------------------------------- @@ -92,7 +92,7 @@ afterEach(async () => { // ignore close errors } // Give Windows a beat to release the SQLite file handle ÔÇö the - // `.codegraph-vba/index.sqlite` lingers under an exclusive lock for + // `.codegraph/index.sqlite` lingers under an exclusive lock for // a few ms after `close()` returns, and `rmSync` would otherwise // hit EPERM. await new Promise((resolve) => setTimeout(resolve, 50)); diff --git a/__tests__/extraction-vba-realfixtures.test.ts b/__tests__/extraction-vba-realfixtures.test.ts index 94c0fe1c..2ac5f051 100644 --- a/__tests__/extraction-vba-realfixtures.test.ts +++ b/__tests__/extraction-vba-realfixtures.test.ts @@ -11,7 +11,7 @@ * per-scenario shape; this E2E verifies the integrated tool works end-to-end * against real fixtures — same patterns, real bytes. * - * The `.codegraph-vba/` index is created in the fixtures folder during this test + * The `.codegraph/` index is created in the fixtures folder during this test * and removed in afterAll so subsequent runs are idempotent. */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; @@ -27,10 +27,10 @@ const FORM_BASENAME = 'Form_FormNCAuditoriaMotivoEliminado'; describe('E2E - real VBA fixtures from a Dysflow-managed project', () => { let cg: CodeGraph | null = null; let initializedByTest = false; - const codeGraphDir = path.join(FIXTURES_DIR, '.codegraph-vba'); + const codeGraphDir = path.join(FIXTURES_DIR, '.codegraph'); beforeAll(async () => { - // Clean slate: remove any prior .codegraph-vba/ left by a previous run so + // Clean slate: remove any prior .codegraph/ left by a previous run so // init() doesn't refuse to re-initialize. if (fs.existsSync(codeGraphDir)) { fs.rmSync(codeGraphDir, { recursive: true, force: true }); @@ -48,7 +48,7 @@ describe('E2E - real VBA fixtures from a Dysflow-managed project', () => { // ignore close errors } } - // Clean up the .codegraph-vba/ we created so subsequent runs are clean. + // Clean up the .codegraph/ we created so subsequent runs are clean. if (initializedByTest && fs.existsSync(codeGraphDir)) { fs.rmSync(codeGraphDir, { recursive: true, force: true }); } diff --git a/__tests__/foundation.test.ts b/__tests__/foundation.test.ts index 0570d87f..6d3ae1c7 100644 --- a/__tests__/foundation.test.ts +++ b/__tests__/foundation.test.ts @@ -452,9 +452,9 @@ describe('CODEGRAPH_DIR override (#636)', () => { }); describe('codeGraphDirName()', () => { - it('defaults to .codegraph-vba when unset', () => { + it('defaults to .codegraph when unset', () => { delete process.env.CODEGRAPH_DIR; - expect(codeGraphDirName()).toBe('.codegraph-vba'); + expect(codeGraphDirName()).toBe('.codegraph'); }); it('honors a valid override', () => { @@ -465,10 +465,10 @@ describe('CODEGRAPH_DIR override (#636)', () => { // Anything that isn't a plain segment could escape the project root or // clobber it, so it's ignored in favor of the default. it.each(['foo/bar', 'a\\b', '..', '../x', '.', '/abs/path', ' ', ''])( - 'falls back to .codegraph-vba for invalid value %j', + 'falls back to .codegraph for invalid value %j', (bad) => { process.env.CODEGRAPH_DIR = bad; - expect(codeGraphDirName()).toBe('.codegraph-vba'); + expect(codeGraphDirName()).toBe('.codegraph'); } ); }); @@ -481,6 +481,11 @@ describe('CODEGRAPH_DIR override (#636)', () => { expect(isCodeGraphDataDir('.codegraph-wsl')).toBe(true); // any sibling }); + it('matches the legacy .codegraph-vba directory so it is never indexed', () => { + delete process.env.CODEGRAPH_DIR; + expect(isCodeGraphDataDir('.codegraph-vba')).toBe(true); + }); + it('does not match unrelated directories', () => { delete process.env.CODEGRAPH_DIR; for (const name of ['src', 'node_modules', '.git', 'codegraph', '.codegraphextra']) { @@ -489,12 +494,23 @@ describe('CODEGRAPH_DIR override (#636)', () => { }); }); - it('init writes the index under the overridden directory, not .codegraph-vba', () => { + it('init writes the index under .codegraph by default, not the legacy .codegraph-vba', () => { + delete process.env.CODEGRAPH_DIR; + const cg = CodeGraph.initSync(tempDir); + try { + expect(fs.existsSync(path.join(tempDir, '.codegraph', 'codegraph.db'))).toBe(true); + expect(fs.existsSync(path.join(tempDir, '.codegraph-vba'))).toBe(false); + } finally { + cg.close(); + } + }); + + it('init writes the index under the overridden directory, not .codegraph', () => { process.env.CODEGRAPH_DIR = '.codegraph-win'; const cg = CodeGraph.initSync(tempDir); try { expect(fs.existsSync(path.join(tempDir, '.codegraph-win', 'codegraph.db'))).toBe(true); - expect(fs.existsSync(path.join(tempDir, '.codegraph-vba'))).toBe(false); + expect(fs.existsSync(path.join(tempDir, '.codegraph'))).toBe(false); expect(getCodeGraphDir(tempDir)).toBe(path.join(tempDir, '.codegraph-win')); expect(CodeGraph.isInitialized(tempDir)).toBe(true); } finally { @@ -503,7 +519,7 @@ describe('CODEGRAPH_DIR override (#636)', () => { }); it('two index dirs coexist in one tree and the override side skips the sibling', async () => { - // WSL side: default `.codegraph-vba`, with a source file. + // WSL side: default `.codegraph`, with a source file. delete process.env.CODEGRAPH_DIR; fs.writeFileSync(path.join(tempDir, 'app.ts'), 'export function onlyReal() {}\n'); const wsl = await CodeGraph.init(tempDir, { index: true }); @@ -512,10 +528,10 @@ describe('CODEGRAPH_DIR override (#636)', () => { // Windows side: override dir, same tree. Plant a decoy source file INSIDE // the WSL data dir — the override-side index must not pick it up. process.env.CODEGRAPH_DIR = '.codegraph-win'; - fs.writeFileSync(path.join(tempDir, '.codegraph-vba', 'decoy.ts'), 'export function decoyLeak() {}\n'); + fs.writeFileSync(path.join(tempDir, '.codegraph', 'decoy.ts'), 'export function decoyLeak() {}\n'); const win = await CodeGraph.init(tempDir, { index: true }); try { - expect(fs.existsSync(path.join(tempDir, '.codegraph-vba', 'codegraph.db'))).toBe(true); + expect(fs.existsSync(path.join(tempDir, '.codegraph', 'codegraph.db'))).toBe(true); expect(fs.existsSync(path.join(tempDir, '.codegraph-win', 'codegraph.db'))).toBe(true); expect(win.searchNodes('onlyReal').length).toBeGreaterThan(0); expect(win.searchNodes('decoyLeak')).toEqual([]); // sibling data dir not indexed diff --git a/__tests__/mcp-tools-lifecycle.test.ts b/__tests__/mcp-tools-lifecycle.test.ts index a08e4172..128c778c 100644 --- a/__tests__/mcp-tools-lifecycle.test.ts +++ b/__tests__/mcp-tools-lifecycle.test.ts @@ -97,7 +97,7 @@ describe('MCP lifecycle tools — codegraph_init', () => { const handler = new ToolHandler(null); const success = await handler.execute('codegraph_init', { path: projectDir }); expect(success.isError).toBe(false); - expect(fs.existsSync(path.join(projectDir, '.codegraph-vba'))).toBe(true); + expect(fs.existsSync(path.join(projectDir, '.codegraph'))).toBe(true); const fileTarget = path.join(projectDir, 'not-a-directory'); fs.writeFileSync(fileTarget, 'file'); @@ -112,12 +112,12 @@ describe('MCP lifecycle tools — codegraph_init', () => { process.env.CODEGRAPH_MCP_ALLOWLIST = path.join(os.tmpdir(), 'different-root'); const denied = await handler.execute('codegraph_init', { path: projectDir }); expect(denied.isError).toBe(true); - expect(fs.existsSync(path.join(projectDir, '.codegraph-vba'))).toBe(false); + expect(fs.existsSync(path.join(projectDir, '.codegraph'))).toBe(false); process.env.CODEGRAPH_MCP_ALLOWLIST = '*'; const allowed = await handler.execute('codegraph_init', { path: projectDir }); expect(allowed.isError).toBe(false); - expect(fs.existsSync(path.join(projectDir, '.codegraph-vba'))).toBe(true); + expect(fs.existsSync(path.join(projectDir, '.codegraph'))).toBe(true); }); it('rejects a junction that escapes the canonical allowlist root', async () => { @@ -131,7 +131,7 @@ describe('MCP lifecycle tools — codegraph_init', () => { try { const result = await new ToolHandler(null).execute('codegraph_init', { path: escape }); expect(result.isError).toBe(true); - expect(fs.existsSync(path.join(outsideRoot, '.codegraph-vba'))).toBe(false); + expect(fs.existsSync(path.join(outsideRoot, '.codegraph'))).toBe(false); } finally { cleanup(outsideRoot); } @@ -148,8 +148,8 @@ describe('MCP lifecycle tools — codegraph_uninit', () => { }); afterEach(() => cleanup(projectDir)); - it('removes .codegraph-vba/ from a previously-initialized project', async () => { - expect(fs.existsSync(path.join(projectDir, '.codegraph-vba'))).toBe(true); + it('removes .codegraph/ from a previously-initialized project', async () => { + expect(fs.existsSync(path.join(projectDir, '.codegraph'))).toBe(true); process.env.CODEGRAPH_MCP_TOOLS = 'explore,uninit'; const result = await new ToolHandler(null).execute('codegraph_uninit', { @@ -160,7 +160,7 @@ describe('MCP lifecycle tools — codegraph_uninit', () => { expect(result.isError).toBeUndefined(); expect(result.content[0].text).toContain('Removed CodeGraph'); - expect(fs.existsSync(path.join(projectDir, '.codegraph-vba'))).toBe(false); + expect(fs.existsSync(path.join(projectDir, '.codegraph'))).toBe(false); const definition = tools.find((tool) => tool.name === 'codegraph_uninit'); expect(definition?.annotations).toEqual({ readOnlyHint: false, @@ -174,8 +174,8 @@ describe('MCP lifecycle tools — codegraph_uninit', () => { delete process.env.CODEGRAPH_MCP_TOOLS; }); - it('returns the CLI result when the project has no .codegraph-vba/', async () => { - fs.rmSync(path.join(projectDir, '.codegraph-vba'), { recursive: true }); + it('returns the CLI result when the project has no .codegraph/', async () => { + fs.rmSync(path.join(projectDir, '.codegraph'), { recursive: true }); process.env.CODEGRAPH_MCP_TOOLS = 'explore,uninit'; const result = await new ToolHandler(null).execute('codegraph_uninit', { @@ -520,10 +520,10 @@ describe.skip('MCP lifecycle tools — codegraph_unlock', () => { }); afterEach(() => cleanup(projectDir)); - it('removes a stale .codegraph-vba/.lock file', () => { + it('removes a stale .codegraph/.lock file', () => { const cg = CodeGraph.initSync(projectDir); cg.close(); - const lock = path.join(projectDir, '.codegraph-vba', 'codegraph.lock'); + const lock = path.join(projectDir, '.codegraph', 'codegraph.lock'); fs.writeFileSync(lock, 'stale-pid'); expect(fs.existsSync(lock)).toBe(true); fs.rmSync(lock); @@ -531,9 +531,9 @@ describe.skip('MCP lifecycle tools — codegraph_unlock', () => { // TODO(RED): MCP tool wrapper around the same operation. }); - it('refuses to unlock a project that has no .codegraph-vba/', () => { + it('refuses to unlock a project that has no .codegraph/', () => { // TODO(RED): MCP tool returns isError: true with code E_NOT_INDEXED. - expect(fs.existsSync(path.join(projectDir, '.codegraph-vba'))).toBe(false); + expect(fs.existsSync(path.join(projectDir, '.codegraph'))).toBe(false); }); }); diff --git a/__tests__/resolution.test.ts b/__tests__/resolution.test.ts index 84650b97..7ab636b5 100644 --- a/__tests__/resolution.test.ts +++ b/__tests__/resolution.test.ts @@ -2871,7 +2871,7 @@ func main() { // The `#include "utils.h"` edge should target the real // `include/utils.h` file node — not a floating `import` node // living inside main.cpp. - const db = DatabaseConnection.open(path.join(tempProject, '.codegraph-vba', 'codegraph.db')); + const db = DatabaseConnection.open(path.join(tempProject, '.codegraph', 'codegraph.db')); try { const rows = db.getDb().prepare(` select dst.kind as dstKind, dst.file_path as dstPath @@ -2988,7 +2988,7 @@ class Both : public Base, public Plain {}; // templated + plain in one cla // reporter's repro: page.php's `require_once("lib.php")` must resolve // to the real src/lib.php file node — a file→file `imports` edge, so // callers(lib.php) now includes page.php. - const db = DatabaseConnection.open(path.join(tempProject, '.codegraph-vba', 'codegraph.db')); + const db = DatabaseConnection.open(path.join(tempProject, '.codegraph', 'codegraph.db')); try { const rows = db.getDb().prepare(` select dst.kind as dstKind, dst.file_path as dstPath @@ -3030,7 +3030,7 @@ class Both : public Base, public Plain {}; // templated + plain in one cla cg = await CodeGraph.init(tempProject, { index: true }); - const db = DatabaseConnection.open(path.join(tempProject, '.codegraph-vba', 'codegraph.db')); + const db = DatabaseConnection.open(path.join(tempProject, '.codegraph', 'codegraph.db')); try { const rows = db.getDb().prepare(` select dst.kind as dstKind, dst.file_path as dstPath @@ -3077,7 +3077,7 @@ class Both : public Base, public Plain {}; // templated + plain in one cla cg = await CodeGraph.init(tempProject, { index: true }); - const db = DatabaseConnection.open(path.join(tempProject, '.codegraph-vba', 'codegraph.db')); + const db = DatabaseConnection.open(path.join(tempProject, '.codegraph', 'codegraph.db')); try { const rows = db.getDb().prepare(` select dst.kind as dstKind, dst.file_path as dstPath diff --git a/__tests__/vba-targets-config.test.ts b/__tests__/vba-targets-config.test.ts index b2b0d975..bc0d53e0 100644 --- a/__tests__/vba-targets-config.test.ts +++ b/__tests__/vba-targets-config.test.ts @@ -83,7 +83,7 @@ describe('VBA targets config loader', () => { it('merges local and root project config where root overrides local', () => { // Write local config - const localDir = path.join(dir, '.codegraph-vba'); + const localDir = path.join(dir, '.codegraph'); fs.mkdirSync(localDir, { recursive: true }); fs.writeFileSync( path.join(localDir, 'config.json'), @@ -186,7 +186,7 @@ describe('VBA targets config end-to-end integration', () => { expect(qualifiedNames1).not.toContain('MyClass.ActiveWin64Sub'); await cg1.destroy(); - fs.rmSync(path.join(dir, '.codegraph-vba'), { recursive: true, force: true }); + fs.rmSync(path.join(dir, '.codegraph'), { recursive: true, force: true }); clearProjectConfigCache(); // 2. Run with Win64: true in codegraph.json diff --git a/docs/external-integration.md b/docs/external-integration.md index fe4e34ef..7b5c3b4c 100644 --- a/docs/external-integration.md +++ b/docs/external-integration.md @@ -122,7 +122,7 @@ Shape (top-level keys; values elided): "initialized": true, "version": "1.13.0", // npm package version (string) "projectPath": "C:\\...\\my-project", - "indexPath": "C:\\...\\my-project\\.codegraph-vba", + "indexPath": "C:\\...\\my-project\\.codegraph", "lastIndexed": "2026-07-20T13:45:22.512Z", // ISO-8601, null before first index "fileCount": 643, "nodeCount": 9289, @@ -234,7 +234,7 @@ without changes for the lifetime of the v1.x line". | The set of top-level subcommands listed in `codegraph --help` | Subcommands are ADDITIVE — new commands may appear, but existing ones will not be removed without a major version bump. A removed subcommand is a breaking change. | | The `--json` flag on every read-only subcommand | Stable. The JSON top-level keys listed in §3 are stable; existing keys are never removed, only added. | | The spawn snippet in §2 (Node `child_process.spawn` + platform branch) | Stable — this is the exact pattern the maintainer team uses internally. | -| The presence of `.codegraph-vba/codegraph.db` after `codegraph init` | Stable — the directory + file name are part of the contract. | +| The presence of `.codegraph/codegraph.db` after `codegraph init` | Stable — the directory + file name are part of the contract. | | The published schema in [`docs/index-schema.md`](index-schema.md) | **Stable columns** (tagged in the doc) are stable. **Implementation-detail columns** may change between minor releases. | ### Implementation detail (NOT stable) diff --git a/docs/index-schema.md b/docs/index-schema.md index 659446af..09fa2cc5 100644 --- a/docs/index-schema.md +++ b/docs/index-schema.md @@ -1,6 +1,6 @@ # codegraph-vba index — SQL schema reference -This document is the published SQL contract for the `.codegraph-vba/codegraph.db` index. It is **auto-generated** by `scripts/dump-index-schema.ts` from the canonical schema in `src/db/schema.sql` (issue #200, Deliverable 2). +This document is the published SQL contract for the `.codegraph/codegraph.db` index. It is **auto-generated** by `scripts/dump-index-schema.ts` from the canonical schema in `src/db/schema.sql` (issue #200, Deliverable 2). Regenerate with `npm run schema:dump` after any schema change. diff --git a/docs/vba-error-handling.md b/docs/vba-error-handling.md index ca5bdead..215c6b72 100644 --- a/docs/vba-error-handling.md +++ b/docs/vba-error-handling.md @@ -2,10 +2,10 @@ CodeGraph records each VBA procedure's error policy in the procedure node's `metadata.errorPolicy` object. Run the four queries below against the generated -`.codegraph-vba/codegraph.db` SQLite database to find risky unprotected code, +`.codegraph/codegraph.db` SQLite database to find risky unprotected code, open suppression scopes, user-facing error displays, and missing handlers. -> If `CODEGRAPH_DIR` is set, use that directory instead of `.codegraph-vba`. +> If `CODEGRAPH_DIR` is set, use that directory instead of `.codegraph`. > Build or refresh the index before querying so these fields reflect the current > source. SQLite's JSON functions (`json_extract`) are required. diff --git a/scripts/dump-index-schema.ts b/scripts/dump-index-schema.ts index 77c92df0..5b469a58 100644 --- a/scripts/dump-index-schema.ts +++ b/scripts/dump-index-schema.ts @@ -1,7 +1,7 @@ /** * scripts/dump-index-schema.ts * - * Emits the live `.codegraph-vba/codegraph.db` schema as a markdown file + * Emits the live `.codegraph/codegraph.db` schema as a markdown file * (`docs/index-schema.md`). This is Deliverable 2 of issue #200. * * Why this script exists @@ -119,7 +119,7 @@ const FTS_SHADOW_PREFIX = 'nodes_fts'; /** * Open a fresh temp `node:sqlite` database, apply the canonical schema, and * return the live table/column/index metadata. Hermetic — never reads or - * mutates the user's real `.codegraph-vba/codegraph.db`. + * mutates the user's real `.codegraph/codegraph.db`. */ function readLiveSchema(): { tables: Map; @@ -290,7 +290,7 @@ function buildDoc(tables: Map, indexes: Map