@aroman22/codegraph-vba 1.17.0 β†’ 1.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  # CodeGraph (VBA & Access Fork)
4
4
 
5
- ## πŸŽ‰ 1.5 Released β€” VBA conditional-compilation is now correct + TempVars/RecordSource/RowSource indexed
5
+ ## v1.17.1 Released β€” Bounded Access Behavior Evidence and Layout-Aware Handler Lookup
6
6
 
7
7
  Already installed? Run `codegraph-vba upgrade` to update in place.
8
8
 
9
- Follow [@getcodegraph](https://x.com/getcodegraph) on X for updates.
9
+ Follow the upstream project at [@getcodegraph](https://x.com/getcodegraph) on X for upstream updates.
10
10
 
11
11
  ### Supercharge Claude Code, Cursor, Codex, OpenCode, Hermes Agent, Gemini, Antigravity, and Kiro with Semantic Code Intelligence
12
12
 
@@ -18,7 +18,9 @@ Follow [@getcodegraph](https://x.com/getcodegraph) on X for updates.
18
18
  > This repository is a fork of the official [CodeGraph](https://github.com/colbymchenry/codegraph).
19
19
  > It is renamed to **`codegraph-vba`** to avoid name collisions and features custom parser support for **VBA (Visual Basic for Applications)** and **MS Access** applications.
20
20
 
21
- ### [Official Documentation & Website β†’](https://colbymchenry.github.io/codegraph/)
21
+ ### [Upstream Documentation & Website β†’](https://colbymchenry.github.io/codegraph/)
22
+
23
+ > These pages describe upstream CodeGraph. Features added there after the integrated v1.4.1 base are not automatically available in this fork.
22
24
 
23
25
  [![Windows](https://img.shields.io/badge/Windows-supported-blue.svg)](#supported-platforms)
24
26
  [![macOS](https://img.shields.io/badge/macOS-supported-blue.svg)](#supported-platforms)
@@ -35,11 +37,11 @@ Follow [@getcodegraph](https://x.com/getcodegraph) on X for updates.
35
37
 
36
38
  <br>
37
39
 
38
- **The CodeGraph platform is coming** β€” for every PR, know exactly what to test, what could break, which flows are affected, and whether business logic is compromised.
40
+ **The upstream CodeGraph platform is coming** β€” for every PR, know exactly what to test, what could break, which flows are affected, and whether business logic is compromised.
39
41
 
40
42
  <a href="https://getcodegraph.com"><img alt="Join the waitlist for early beta access" src="https://raw.githubusercontent.com/colbymchenry/codegraph/main/assets/waitlist.svg?v=2" height="52"></a>
41
43
 
42
- <sub>Get <b>early beta access</b> to the hosted product Β· <a href="https://getcodegraph.com">getcodegraph.com</a></sub>
44
+ <sub>Get <b>early beta access</b> to the upstream hosted product Β· <a href="https://getcodegraph.com">getcodegraph.com</a></sub>
43
45
 
44
46
  </div>
45
47
 
@@ -47,7 +49,11 @@ Follow [@getcodegraph](https://x.com/getcodegraph) on X for updates.
47
49
 
48
50
  ## This is a fork β€” VBA / Access + Dysflow
49
51
 
50
- This repository is a fork of [`colbymchenry/codegraph`](https://github.com/colbymchenry/codegraph), maintained at [`ardelperal/codegraph-vba`](https://github.com/ardelperal/codegraph-vba). It is **identical to the upstream for every language except VBA / Access** β€” the fork adds nothing new to TypeScript, Python, Go, Rust, Java, etc., and is kept rebased against `colbymchenry/codegraph:main` so it stays current with upstream fixes and benchmarks.
52
+ This repository is maintained at [`ardelperal/codegraph-vba`](https://github.com/ardelperal/codegraph-vba). It extends CodeGraph with VBA / Access analysis and fork-specific integration changes; it is not guaranteed identical to current upstream for other languages.
53
+
54
+ The integrated upstream base is **v1.4.1**, commit [`ecc8b30`](https://github.com/colbymchenry/codegraph/commit/ecc8b307ac2f8a7d06bff02ee513c4ea2380b2f8), merged through [`910c7bb`](https://github.com/ardelperal/codegraph-vba/commit/910c7bb09fcc1e681e86803f93fffdb758086a22). Upstream v1.6.0 is not integrated. Fork and upstream versions are independent.
55
+
56
+ See [fork capabilities and lineage](docs/fork-capabilities.md) for the delivered VBA, Access data/UI, error-analysis, and behavior-evidence scope.
51
57
 
52
58
  **Why fork?** To add VBA / Access language support that does not exist upstream, so agents can navigate Microsoft Access projects managed by Dysflow the same way they navigate TypeScript or Python today. See the [VBA / Access + Dysflow integration](#vba--access--dysflow-integration) section below for the feature spec, the pattern table, and the hard invariants.
53
59
 
@@ -70,7 +76,7 @@ pnpm run build # produces dist/bin/codegraph.js
70
76
  # The binary is now at dist/bin/codegraph.js β€” point your agent's MCP at this path
71
77
  ```
72
78
 
73
- **If you do not need VBA / Access support**, install the upstream package instead β€” it is otherwise identical and gets released more frequently:
79
+ **If you do not need VBA / Access support**, consider the upstream package instead. It follows its own release line; check its documentation rather than assuming feature parity:
74
80
 
75
81
  ```bash
76
82
  npm i -g @colbymchenry/codegraph
@@ -1,36 +1,33 @@
1
1
  /**
2
2
  * Dysflow-export framework resolver (issue #154).
3
3
  *
4
- * The 3 Dysflow-specific extractors ÔÇâ form/report SaveAsText UI, test
5
- * manifests, and test sequences ÔÇâ used to be hard-coded into
6
- * `extractFromSource` as a `detectedLanguage === 'vba' && <isFoo> (filePath)`
7
- * ladder. They are now lifted into this `FrameworkResolver`-shaped module
8
- * so they can be:
9
- * 1. Reached through the standard framework registry (the same path every
10
- * other framework ÔÇâ Express, React, Spring ÔÇâ flows through).
11
- * 2. Opted out at the project level via `codegraph.json`'s
12
- * `vba.dysflowExport: false` ÔÇâ useful for projects that carry legacy
13
- * `.form.txt`/`.report.txt` files (or test manifests from a different
14
- * system) and want them tracked as just a `file` node instead of
15
- * being expanded into the graph.
4
+ * Marks a project as "this is a Dysflow export" so `dysflow-export` shows up
5
+ * in the detected-framework list alongside Express, React, Spring and the
6
+ * rest. Detection is path-shape based: at least one `.form.txt` /
7
+ * `.report.txt` / `tests.*.json` / `sequences/*.json` in the tree, and no
8
+ * `vba.dysflowExport: false` opt-out in `codegraph.json`.
16
9
  *
17
- * Architecture: the underlying `VbaFormExtractor` / `VbaTestManifestExtractor`
18
- * / `VbaTestSequenceExtractor` classes are the single source of truth for
19
- * the per-file extraction logic. This module:
20
- * - decides WHICH sub-extractor applies to a file (path shape);
21
- * - delegates the actual `extract()` to that sub-extractor;
22
- * - exposes the `FrameworkResolver` shape (`detect` / `extract` /
23
- * `resolve` / `claimsReference`) so the rest of the codebase can treat
24
- * "Dysflow export" as a regular framework on top of the base VBA
25
- * language.
10
+ * PER-FILE EXTRACTION DOES NOT LIVE HERE (issue #314). The three Dysflow
11
+ * sub-extractors β€” `VbaFormExtractor`, `VbaTestManifestExtractor` and
12
+ * `VbaTestSequenceExtractor` β€” are dispatched by the VBA branch of
13
+ * `extractFromSource` in `../tree-sitter.ts`, gated on the `dysflowExport`
14
+ * flag that `loadDysflowExportConfig()` reads from the project config. That
15
+ * ladder is the ONLY dispatch site, and it runs on every path into
16
+ * extraction, including the ones that pass no `frameworkNames` at all
17
+ * (single-file re-index, library callers, the extraction unit tests).
26
18
  *
27
- * Behavior contract: with `dysflowExport: true` (the default), the emitted
28
- * nodes/edges/references are byte-identical to the pre-refactor paths in
29
- * `tree-sitter.ts`. With `dysflowExport: false`, the framework's `detect()`
30
- * returns `false` so it's never in the per-project detected list ÔÇâ meaning
31
- * its `extract()` is never called and the form/report/manifest/sequence
32
- * files fall through to a `file`-only node via the language-specific
33
- * dispatch in `tree-sitter.ts`.
19
+ * This module deliberately exposes no `extract()`. It used to carry one that
20
+ * re-ran the same three sub-extractors, which meant every Dysflow artifact in
21
+ * a real project was parsed twice per index β€” once by the `tree-sitter.ts`
22
+ * ladder and once by the framework loop at the end of `extractFromSource` β€”
23
+ * and every manifest/sequence entry landed twice in `unresolved_refs`. Adding
24
+ * an `extract()` back here re-introduces that duplication; extend the
25
+ * `tree-sitter.ts` ladder instead.
26
+ *
27
+ * Opt-out contract: `vba.dysflowExport: false` turns BOTH halves off. This
28
+ * resolver's `detect()` returns `false` so the project is not classified as a
29
+ * Dysflow export, and the same config flag makes the `tree-sitter.ts` ladder
30
+ * emit a `file`-only node for the form/report/manifest/sequence shapes.
34
31
  */
35
32
  import { FrameworkResolver } from '../../resolution/types';
36
33
  export declare const dysflowExportResolver: FrameworkResolver;
@@ -53,6 +53,33 @@ export interface SyncResult {
53
53
  * Calculate SHA256 hash of file contents
54
54
  */
55
55
  export declare function hashContent(content: string): string;
56
+ /**
57
+ * Issue #53: read extraction source with encoding-robust decode for VBA-family
58
+ * files (BOM strip + CP1252 fallback), byte-identical to the plain UTF-8 read
59
+ * for every other language. The same read must feed extraction, storage, and
60
+ * change-detection hashing so a BOM-carrying or CP1252 VBA file doesn't hash
61
+ * differently at detect-time than what was stored (perpetual "modified").
62
+ */
63
+ /**
64
+ * Files that must be decoded with Access encoding rules (BOM strip + CP1252
65
+ * fallback) rather than as plain UTF-8.
66
+ *
67
+ * Two predicates because the family is matched two ways. `isVbaFamilyFile`
68
+ * owns the extensions (`.bas`, `.cls`, `.form.txt`, `.sql`, …). The Access
69
+ * structure export is `ERD/*.md`, so it is matched by PATH SHAPE β€” `.md`
70
+ * alone must never route every markdown file in a repo through the CP1252
71
+ * fallback β€” and that shape is owned by `grammars.ts` (issue #322).
72
+ *
73
+ * Combining them here rather than inside `isVbaFamilyFile` keeps
74
+ * `vba-source.ts` a leaf module: this is the only place that needs both.
75
+ *
76
+ * Without the ERD half, an export naming a table with accents decoded to
77
+ * replacement characters while the `.sql` and `.bas` referencing that same
78
+ * table decoded it correctly, so the ERD declaration never joined the
79
+ * placeholder those scanners emit and the table's field list hung off an
80
+ * orphan node.
81
+ */
82
+ export declare function usesAccessEncoding(filePath: string): boolean;
56
83
  /**
57
84
  * An `ignore` matcher seeded with the built-in defaults, merged with the project's
58
85
  * root .gitignore so a negation there (e.g. `!vendor/`) overrides a default. Shared
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Decoding helpers for the JSON artifacts Dysflow writes beside a VBA export
3
+ * (`tests(.<slice>)*.json` test manifests, `sequences/*.json` test sequences).
4
+ *
5
+ * These are the only indexed files that are parsed as JSON rather than scanned
6
+ * as text, and they are deliberately NOT part of `isVbaFamilyFile` β€” JSON is
7
+ * UTF-8 by specification, so the CP1252 fallback in `readVbaSource` would turn
8
+ * a mis-encoded manifest into silently wrong data instead of a loud parse
9
+ * error. What they do share with the rest of the VBA family is the byte-order
10
+ * mark.
11
+ */
12
+ /**
13
+ * Strip a leading UTF-8 BOM from already-decoded JSON text.
14
+ *
15
+ * A `.json` is read with a plain `fs.readFile(path, 'utf-8')`, and Node keeps
16
+ * the BOM as a leading `\uFEFF` rather than consuming it. `JSON.parse` rejects
17
+ * that character outright, so a BOM-carrying manifest used to contribute
18
+ * nothing to the graph but a `warning`-severity parse error β€” every `Test_*`
19
+ * link it declared silently vanished (issue #316). On Windows this is the
20
+ * common case, not an exotic one: PowerShell 5.1 writes the BOM by default for
21
+ * `-Encoding UTF8` in both `Set-Content` and `Out-File`.
22
+ *
23
+ * Only a BOM at position 0 is removed; a `\uFEFF` anywhere else is data and is
24
+ * left for `JSON.parse` to judge.
25
+ */
26
+ export declare function stripJsonBom(text: string): string;
27
+ //# sourceMappingURL=json-source.d.ts.map
@@ -55,7 +55,8 @@ export interface BehaviorEvidenceRequest {
55
55
  layout?: string;
56
56
  /** Call-path depth budget. Default 5, clamped to 1..20. */
57
57
  maxCallDepth?: number;
58
- /** Maximum evidence entries. Default 50, clamped to 1..500. */
58
+ /** Maximum evidence entries. Default 50, clamped to 1..500.
59
+ * Traversal also visits at most (maxResults + 1) * maxCallDepth path steps. */
59
60
  maxResults?: number;
60
61
  }
61
62
  export interface BehaviorEvidenceTarget {
@@ -127,7 +128,7 @@ export interface BehaviorEvidenceResult {
127
128
  truncated: {
128
129
  /** A path hit `maxCallDepth` and was cut short. */
129
130
  callDepth: boolean;
130
- /** Entries were dropped at `maxResults`. */
131
+ /** Entries were dropped, or the traversal work budget left paths unexplored. */
131
132
  results: boolean;
132
133
  /** A path re-entered a procedure already on it. */
133
134
  cycle: boolean;
@@ -17,7 +17,7 @@
17
17
  * tools (node/search/callers/…) stay defined and are re-enablable via
18
18
  * CODEGRAPH_MCP_TOOLS, but they are NOT listed to agents, so don't name them.
19
19
  */
20
- export declare const SERVER_INSTRUCTIONS = "# Codegraph \u2014 code intelligence over an indexed knowledge graph\n\nCodegraph is a SQLite knowledge graph of every symbol, edge, and file in\nthe workspace \u2014 pre-computed structure you would otherwise re-derive by\nreading files (cached intelligence: thousands of parse/trace decisions you\ndon't pay to re-reason each run). Reads are sub-millisecond; the index lags\nwrites by ~1s through the file watcher. Reach for it BEFORE *and* while\nwriting or editing code \u2014 not just for questions: one call returns the\nverbatim source PLUS who calls it and what it affects, so you edit with the\nblast radius in view. More accurate context, in far fewer tokens and\nround-trips than reading files yourself.\n\n## One tool: codegraph_explore \u2014 use it instead of reading files\n\nThere is a single tool, `codegraph_explore`, and it is Read-equivalent. It\ntakes either a natural-language question or a bag of symbol/file names and\nreturns the **verbatim, line-numbered source** of the relevant symbols\ngrouped by file \u2014 the same `<n>\\t<line>` shape `Read` gives you, safe to\n`Edit` from \u2014 PLUS the call path among them (including dynamic-dispatch hops\nlike callbacks, React re-render, and JSX children that grep can't follow) and\na blast-radius summary of what depends on them.\n\nWhether you're answering \"how does X work\" or implementing a change (fixing a\nbug, adding a feature), call `codegraph_explore` before you Read. ONE call\nusually answers the whole question. Codegraph IS the pre-built search index \u2014\nso running your own grep + read loop, or delegating the lookup to a separate\nfile-reading sub-task/agent, repeats work codegraph already did and costs more\nfor the same answer. A direct codegraph answer is typically one to a few\ncalls; a grep/read exploration is dozens.\n\n## How to query\n\n- **Almost any question \u2014 \"how does X work\", architecture, a bug, \"what/where is X\", or surveying an area** \u2192 `codegraph_explore` with a natural-language question or the relevant names. ONE capped call returns the verbatim source grouped by file; most often the ONLY call you need.\n- **\"How does X reach/become Y? / the flow / the path from X to Y\"** \u2192 `codegraph_explore`, naming the symbols that span the flow (e.g. `mutateElement renderScene`) \u2014 it surfaces the call path among them, riding dynamic-dispatch hops, and returns their source.\n- **Reading or editing a file/symbol you can name** \u2192 put its name or file path in the `codegraph_explore` query \u2014 it returns that current line-numbered source (safe to `Edit` from) with the call path and blast radius attached, so you don't Read it separately. For an overloaded name it returns every matching definition's body in one call.\n- **Need more?** Call `codegraph_explore` again with more specific names \u2014 treat the source it returns as already Read.\n\n## Anti-patterns\n\n- **Trust codegraph's results \u2014 don't re-verify them with grep.** They come from a full AST parse; re-checking with grep is slower, less accurate, and wastes context.\n- **Don't grep or Read first** to find or understand indexed code \u2014 ONE `codegraph_explore` returns the relevant symbols' source together in a single round-trip. Reach for raw `Read`/`Grep` only to confirm a specific detail codegraph didn't cover, or for what codegraph doesn't index (configs, docs).\n- **Don't reconstruct a flow by hand** \u2014 name the endpoints in one `codegraph_explore` and it surfaces the path between them, dynamic-dispatch hops included.\n- **After editing, check the staleness banner.** When a tool response starts with \"\u26A0\uFE0F Some files referenced below were edited since the last index sync\u2026\", the listed files are pending re-index \u2014 Read those specific files for accurate content. Every file NOT in that banner is fresh, so still trust codegraph. A different, rarer banner \u2014 \"\u26A0\uFE0F CodeGraph auto-sync is DISABLED\u2026\" \u2014 means live watching stopped entirely (the whole index is frozen, not just a few files); until it's resolved, Read files directly to confirm anything that may have changed.\n\n## Limitations\n\n- If a tool reports a project isn't indexed (no `.codegraph/`), stop calling codegraph tools for that project for the rest of the session and use your built-in tools there instead. Indexing is the user's decision \u2014 mention they can run `codegraph init` if it comes up, but don't run it yourself.\n- Index lags file writes by ~1 second.\n- Cross-file resolution is best-effort name matching; ambiguous calls may return multiple candidates.\n- No live correctness validation \u2014 that's still the TypeScript compiler / test suite / linter's job. Codegraph supplements those with structural context they don't have.\n\n## Supported Languages\n\nThe indexer recognizes a fixed set of languages; if you ask about symbols in a\nfile with an unsupported extension, codegraph will report the project isn't\nindexed for that file and you should fall back to Read/Grep. The fork-specific\naddition beyond upstream codegraph is **VBA / Access** (Dysflow export\nformat):\n\n- **VBA / Access** - Dysflow exports Access/VBA source as `.bas`/`.cls`/\n `.form.txt`/`.report.txt`. Codegraph extracts `.bas`/`.cls` as `module`/\n `class`/`function` nodes with `calls`/`implements`/`references` edges\n (procedural-level; regex-based, not full AST). Cross-module calls, qualified\n `Dim As`, `WithEvents`, and SQL table references inside string literals\n emit synthesized edges tagged `metadata.synthesizedBy` (`vba-name-resolution`,\n `vba-withevents`, `vba-sql-table`). A `.form.txt` / `.report.txt` emits a\n `form-layout` / `report-layout` container, one\n `form-instance-control` per named control, a `property` node per control\n type, and a placeholder node per table/query it binds - but **no\n procedures**: no `function`/`sub` node, and no class node for the form's\n own code, comes from a layout file. The canonical code lives in the sibling\n `.cls`, parsed by the same extractor on that file.\n- **Access event wiring has ONE direction: handler -> control/layout.** The\n `event-handler` edge is stored from the handler procedure to the\n `form-instance-control` it is named for (`btnSave_Click` -> `btnSave`), or\n to the sibling layout node for a form/report lifecycle event\n (`Form_Load` -> `Form_Orders`, carrying `metadata.scope: 'form'`). An\n `=Expression()` event property resolves to the same direction, tagged\n `vba-expression-handler`. There is no reverse edge: to answer \"what runs on\n this control\", follow the edge BACKWARDS from the control. Scope every\n control lookup by its layout - the same control name usually exists on\n several forms, and a layout owns its controls through `contains`.\n- **A VBA call is not always a `calls` edge.** `Call Foo` and `Foo 1, 2` are\n `calls`; a bare `Foo` on its own line could also be a `Const` read, so it\n stays an ambiguous identifier and resolves to a `references` edge onto the\n procedure. That bare form is the dominant call style in Access code-behind,\n so a trace that follows only `calls` stops at the handler.\n- **Codegraph indexes the exported source tree, not the live `.accdb`.** It is\n static evidence: it never proves a handler ran, and it says nothing about\n whether the binary matches the export (Dysflow owns that round-trip). A\n missing edge is missing evidence, not proof of no runtime effect.\n Dysflow test manifests (`tests.*.json`) link each registered `Test_*`\n procedure to its manifest with a `references` edge tagged\n `vba-test-manifest` carrying the test name + tags, so `getCallers` of a\n production symbol reaches its covering test atoms with the manifest and tags\n to run.\n Pass `projectPath` to a codegraph index that includes VBA files.\n- **VBA unresolved refs carry syntactic shape** (v1.7+). `unresolved_refs.reference_kind` is no longer the literal string `\"references\"` \u2014 it reports what the syntactic shape actually was. Values: `call` (paren-form or statement-form call site), `qualified-call` (`obj.Foo(...)` with runtime receiver), `property-get` / `property-set` (`Me.Name`, `obj.Prop = value`), `bang-get` / `bang-set` (`Me!SubCtl`, `obj!Field = value`), `unqualified-ident` (bare identifier like `HayErrorEnRiesgo` in an `If` condition), `member-with` (`.Member` inside a `With` block), `dao-query` (`DoCmd.OpenQuery \"X\"` argument). The legacy value `references` is retained on any path the round did not reclassify, so older SQL filters that key on it keep working. To find real missing callees, filter `WHERE reference_kind IN ('call','qualified-call','unqualified-ident','member-with','bang-get')` \u2014 that set has <10% false positives (DAO-field accesses, form-property reads, and bang refs no longer pollute the bucket).\n- **Post-extraction stub resolver** (v1.7+). Edges with `metadata.synthesizedBy='vba-name-resolution'` start life pointing at a synthetic function node; the resolver at `src/resolution/index.ts:resolveVbaCallStubs` (invoked from `indexAll` and `sync`) walks them and repoints each `target` to the real `nodes.id` when one exists. Runtime-object calls (`DAO.*`, `fso.*`, `ListBox.*`, `Collection.*`, `err.*`, `VBA.*`, `Application.*`, `Screen.*`, `DoCmd.*`, `CurrentDb.*`, `Forms`, `Reports`, `Debug`, `Modules`, `References`, `CommandBars`, `SysCmd`, `CreateObject`, `GetObject`, `Fields`) are explicitly declined \u2014 they remain `stub:true` because they can never link to user code. Shadow user classes (e.g. a user class actually named `DAO` with an `Execute` method) are preserved and linked normally. Every stub edge carries `metadata.repointDecision` with one of `reponted-to-real` (linked to a real `nodes.id`), `declined-runtime` (runtime object \u2014 never user code, filter OUT), `declined-ambiguous` (multiple real candidates \u2014 investigate), or `declined-not-found` (genuinely missing callee \u2014 this is the actionable signal). Consumers detecting \"missing callees\" MUST filter on `repointDecision='declined-not-found'`, NOT on the raw `stub=true` count \u2014 the raw count is dominated by runtime-object noise. See `docs/vba-stub-repoint-decision.md` for the full contract.\n";
20
+ export declare const SERVER_INSTRUCTIONS = "# Codegraph \u2014 code intelligence over an indexed knowledge graph\n\nCodegraph is a SQLite knowledge graph of every symbol, edge, and file in\nthe workspace \u2014 pre-computed structure you would otherwise re-derive by\nreading files (cached intelligence: thousands of parse/trace decisions you\ndon't pay to re-reason each run). Reads are sub-millisecond; the index lags\nwrites by ~1s through the file watcher. Reach for it BEFORE *and* while\nwriting or editing code \u2014 not just for questions: one call returns the\nverbatim source PLUS who calls it and what it affects, so you edit with the\nblast radius in view. More accurate context, in far fewer tokens and\nround-trips than reading files yourself.\n\n## One tool: codegraph_explore \u2014 use it instead of reading files\n\nThere is a single tool, `codegraph_explore`, and it is Read-equivalent. It\ntakes either a natural-language question or a bag of symbol/file names and\nreturns the **verbatim, line-numbered source** of the relevant symbols\ngrouped by file \u2014 the same `<n>\\t<line>` shape `Read` gives you, safe to\n`Edit` from \u2014 PLUS the call path among them (including dynamic-dispatch hops\nlike callbacks, React re-render, and JSX children that grep can't follow) and\na blast-radius summary of what depends on them.\n\nWhether you're answering \"how does X work\" or implementing a change (fixing a\nbug, adding a feature), call `codegraph_explore` before you Read. ONE call\nusually answers the whole question. Codegraph IS the pre-built search index \u2014\nso running your own grep + read loop, or delegating the lookup to a separate\nfile-reading sub-task/agent, repeats work codegraph already did and costs more\nfor the same answer. A direct codegraph answer is typically one to a few\ncalls; a grep/read exploration is dozens.\n\n## How to query\n\n- **Almost any question \u2014 \"how does X work\", architecture, a bug, \"what/where is X\", or surveying an area** \u2192 `codegraph_explore` with a natural-language question or the relevant names. ONE capped call returns the verbatim source grouped by file; most often the ONLY call you need.\n- **\"How does X reach/become Y? / the flow / the path from X to Y\"** \u2192 `codegraph_explore`, naming the symbols that span the flow (e.g. `mutateElement renderScene`) \u2014 it surfaces the call path among them, riding dynamic-dispatch hops, and returns their source.\n- **Reading or editing a file/symbol you can name** \u2192 put its name or file path in the `codegraph_explore` query \u2014 it returns that current line-numbered source (safe to `Edit` from) with the call path and blast radius attached, so you don't Read it separately. For an overloaded name it returns every matching definition's body in one call.\n- **Need more?** Call `codegraph_explore` again with more specific names \u2014 treat the source it returns as already Read.\n\n## Anti-patterns\n\n- **Trust codegraph's results \u2014 don't re-verify them with grep.** They come from a full AST parse; re-checking with grep is slower, less accurate, and wastes context.\n- **Don't grep or Read first** to find or understand indexed code \u2014 ONE `codegraph_explore` returns the relevant symbols' source together in a single round-trip. Reach for raw `Read`/`Grep` only to confirm a specific detail codegraph didn't cover, or for what codegraph doesn't index (configs, docs).\n- **Don't reconstruct a flow by hand** \u2014 name the endpoints in one `codegraph_explore` and it surfaces the path between them, dynamic-dispatch hops included.\n- **After editing, check the staleness banner.** When a tool response starts with \"\u26A0\uFE0F Some files referenced below were edited since the last index sync\u2026\", the listed files are pending re-index \u2014 Read those specific files for accurate content. Every file NOT in that banner is fresh, so still trust codegraph. A different, rarer banner \u2014 \"\u26A0\uFE0F CodeGraph auto-sync is DISABLED\u2026\" \u2014 means live watching stopped entirely (the whole index is frozen, not just a few files); until it's resolved, Read files directly to confirm anything that may have changed.\n\n## Limitations\n\n- If a tool reports a project isn't indexed (no `.codegraph/`), stop calling codegraph tools for that project for the rest of the session and use your built-in tools there instead. Indexing is the user's decision \u2014 mention they can run `codegraph init` if it comes up, but don't run it yourself.\n- Index lags file writes by ~1 second.\n- Cross-file resolution is best-effort name matching; ambiguous calls may return multiple candidates.\n- No live correctness validation \u2014 that's still the TypeScript compiler / test suite / linter's job. Codegraph supplements those with structural context they don't have.\n\n## Supported Languages\n\nThe indexer recognizes a fixed set of languages; if you ask about symbols in a\nfile with an unsupported extension, codegraph will report the project isn't\nindexed for that file and you should fall back to Read/Grep. The fork-specific\naddition beyond upstream codegraph is **VBA / Access** (Dysflow export\nformat):\n\n- **VBA / Access** - Dysflow exports Access/VBA source as `.bas`/`.cls`/\n `.form.txt`/`.report.txt`. Codegraph extracts `.bas`/`.cls` as `module`/\n `class`/`function` nodes with `calls`/`implements`/`references` edges\n (procedural-level; regex-based, not full AST). Cross-module calls, qualified\n `Dim As`, `WithEvents`, and SQL table references inside string literals\n emit synthesized edges tagged `metadata.synthesizedBy` (`vba-name-resolution`,\n `vba-withevents`, `vba-sql-table`). A `.form.txt` / `.report.txt` emits a\n `form-layout` / `report-layout` container, one\n `form-instance-control` per named control, a `property` node per control\n type, and a placeholder node per table/query it binds - but **no\n procedures**: no `function`/`sub` node, and no class node for the form's\n own code, comes from a layout file. The canonical code lives in the sibling\n `.cls`, parsed by the same extractor on that file.\n- **Access event wiring has ONE direction: handler -> control/layout.** The\n `event-handler` edge is stored from the handler procedure to the\n `form-instance-control` it is named for (`btnSave_Click` -> `btnSave`), or\n to the sibling layout node for a form/report lifecycle event\n (`Form_Load` -> `Form_Orders`, carrying `metadata.scope: 'form'`). An\n `=Expression()` event property resolves to the same direction, tagged\n `vba-expression-handler`. There is no reverse edge: to answer \"what runs on\n this control\", follow the edge BACKWARDS from the control. Scope every\n control lookup by its layout - the same control name usually exists on\n several forms, and a layout owns its controls through `contains`.\n- **A VBA call is not always a `calls` edge.** `Call Foo` and `Foo 1, 2` are\n `calls`; a bare `Foo` on its own line could also be a `Const` read, so it\n stays an ambiguous identifier and resolves to a `references` edge onto the\n procedure. That bare form is the dominant call style in Access code-behind,\n so a trace that follows only `calls` stops at the handler.\n- **Codegraph indexes the exported source tree, not the live `.accdb`.** It is\n static evidence: it never proves a handler ran, and it says nothing about\n whether the binary matches the export (Dysflow owns that round-trip). A\n missing edge is missing evidence, not proof of no runtime effect.\n Dysflow test manifests (`tests.*.json`) link each registered `Test_*`\n procedure to its manifest with a `references` edge tagged\n `vba-test-manifest` carrying the test name + tags, so `getCallers` of a\n production symbol reaches its covering test atoms with the manifest and tags\n to run.\n Pass `projectPath` to a codegraph index that includes VBA files.\n- **Saved Access queries are first-class nodes \u2014 do not grep the `.sql`.** A\n Dysflow-exported `queries/<Name>.sql` whose directory also carries a\n `queries.json` manifest becomes a `query` node (language `sql`, named after\n the file) with a `references` edge to every table its `FROM` / `JOIN` /\n `INTO` / `UPDATE` names, tagged `sql-query-table`; a table that resolves to\n another backend file is tagged `vba-external-backend` instead. A `.sql` with\n no sibling `queries.json` is deliberately NOT indexed, so an ordinary SQL\n migration in a non-Access repo stays out of the graph.\n- **Dysflow test sequences sit beside the manifests.** A `sequences/*.json`\n emits a `file` node and one `references` edge per `procedures[]` entry to\n that `Test_*` procedure, tagged `vba-test-sequence` and carrying\n `runnerPolicy`, `sequenceFile` and `procedureIndex`. So `getCallers` of a\n test atom reaches both the manifest that registers it (`vba-test-manifest`)\n and the sequence that orders it, with the runner policy to honour.\n- **Table structure comes from the Access ERD export.** An `ERD/*.md` produced\n by the Access structure generator emits one `class` node per table (tagged\n `access-erd-table`), one `type_member` per field joined by `contains`, and a\n `references` edge from a linked table to the backend it really lives in\n (tagged `vba-linked-table`). This is the cheapest answer to \"what columns\n does this table have\" and to \"which backend owns it\" \u2014 ask codegraph before\n reading the export. The extractor requires the generated header, so a\n hand-written diagram in an `ERD/` folder contributes nothing.\n- **VBA unresolved refs carry syntactic shape** (v1.7+). `unresolved_refs.reference_kind` is no longer the literal string `\"references\"` \u2014 it reports what the syntactic shape actually was. Values: `call` (paren-form or statement-form call site), `qualified-call` (`obj.Foo(...)` with runtime receiver), `property-get` / `property-set` (`Me.Name`, `obj.Prop = value`), `bang-get` / `bang-set` (`Me!SubCtl`, `obj!Field = value`), `unqualified-ident` (bare identifier like `HayErrorEnRiesgo` in an `If` condition), `member-with` (`.Member` inside a `With` block), `dao-query` (`DoCmd.OpenQuery \"X\"` argument). The legacy value `references` is retained on any path the round did not reclassify, so older SQL filters that key on it keep working. To find real missing callees, filter `WHERE reference_kind IN ('call','qualified-call','unqualified-ident','member-with','bang-get')` \u2014 that set has <10% false positives (DAO-field accesses, form-property reads, and bang refs no longer pollute the bucket).\n- **Post-extraction stub resolver** (v1.7+). Edges with `metadata.synthesizedBy='vba-name-resolution'` start life pointing at a synthetic function node; the resolver at `src/resolution/index.ts:resolveVbaCallStubs` (invoked from `indexAll` and `sync`) walks them and repoints each `target` to the real `nodes.id` when one exists. Runtime-object calls (`DAO.*`, `fso.*`, `ListBox.*`, `Collection.*`, `err.*`, `VBA.*`, `Application.*`, `Screen.*`, `DoCmd.*`, `CurrentDb.*`, `Forms`, `Reports`, `Debug`, `Modules`, `References`, `CommandBars`, `SysCmd`, `CreateObject`, `GetObject`, `Fields`) are explicitly declined \u2014 they remain `stub:true` because they can never link to user code. Shadow user classes (e.g. a user class actually named `DAO` with an `Execute` method) are preserved and linked normally. Every stub edge carries `metadata.repointDecision` with one of `reponted-to-real` (linked to a real `nodes.id`), `declined-runtime` (runtime object \u2014 never user code, filter OUT), `declined-ambiguous` (multiple real candidates \u2014 investigate), or `declined-not-found` (genuinely missing callee \u2014 this is the actionable signal). Consumers detecting \"missing callees\" MUST filter on `repointDecision='declined-not-found'`, NOT on the raw `stub=true` count \u2014 the raw count is dominated by runtime-object noise. See `docs/vba-stub-repoint-decision.md` for the full contract.\n";
21
21
  /**
22
22
  * Instructions variant sent when the server's own root has NO codegraph index.
23
23
  *
@@ -237,6 +237,20 @@ export declare class FileWatcher {
237
237
  * as they are during a full index.
238
238
  */
239
239
  private isDysflowQuerySql;
240
+ /**
241
+ * True when `rel` is a Dysflow saved-query manifest (`queries.json`).
242
+ *
243
+ * The manifest is not itself indexable, but it is the gate that decides
244
+ * whether the `.sql` files beside it are Access saved queries at all β€” both
245
+ * here and in the indexer's directory discovery. Without this check a
246
+ * manifest write schedules nothing (#318): a first export that writes its
247
+ * `.sql` files before the manifest leaves every query out of the graph,
248
+ * because those `.sql` events were dropped for having no manifest yet and
249
+ * the manifest that would have made them indexable is not a source file.
250
+ * Treating the manifest as a change closes the race from both directions β€”
251
+ * the sync it schedules picks up every `.sql` in that directory.
252
+ */
253
+ private isDysflowQueriesManifest;
240
254
  /**
241
255
  * Shared change handler for both watch strategies. `rel` is a
242
256
  * project-relative POSIX path. Applies the ignore + source-file filters and,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aroman22/codegraph-vba",
3
- "version": "1.17.0",
3
+ "version": "1.17.2",
4
4
  "description": "Local-first code intelligence for AI agents (MCP). Self-contained β€” bundles its own runtime.",
5
5
  "bin": {
6
6
  "codegraph-vba": "npm-shim.js"
@@ -15,12 +15,12 @@
15
15
  "./package.json": "./package.json"
16
16
  },
17
17
  "optionalDependencies": {
18
- "@aroman22/codegraph-vba-darwin-arm64": "1.17.0",
19
- "@aroman22/codegraph-vba-darwin-x64": "1.17.0",
20
- "@aroman22/codegraph-vba-linux-arm64": "1.17.0",
21
- "@aroman22/codegraph-vba-linux-x64": "1.17.0",
22
- "@aroman22/codegraph-vba-win32-arm64": "1.17.0",
23
- "@aroman22/codegraph-vba-win32-x64": "1.17.0"
18
+ "@aroman22/codegraph-vba-darwin-arm64": "1.17.2",
19
+ "@aroman22/codegraph-vba-darwin-x64": "1.17.2",
20
+ "@aroman22/codegraph-vba-linux-arm64": "1.17.2",
21
+ "@aroman22/codegraph-vba-linux-x64": "1.17.2",
22
+ "@aroman22/codegraph-vba-win32-arm64": "1.17.2",
23
+ "@aroman22/codegraph-vba-win32-x64": "1.17.2"
24
24
  },
25
25
  "files": [
26
26
  "npm-shim.js",