@aroman22/codegraph-vba 1.16.0 → 1.17.1
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 +131 -3
- package/dist/db/queries.d.ts +11 -0
- package/dist/graph/behavior-evidence.d.ts +163 -0
- package/dist/index.d.ts +22 -0
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/utils/backtrace-helpers.d.ts +14 -2
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -382,7 +382,10 @@ The two are **sibling tools**: Dysflow owns the Access binary round-trip (sync,
|
|
|
382
382
|
|
|
383
383
|
| Pattern | `.bas` / `.cls` side | `.form.txt` / `.report.txt` side | How |
|
|
384
384
|
|---|---|---|---|
|
|
385
|
-
| **Form code ↔ UI binding** | `.cls` class node (canonical form code) |
|
|
385
|
+
| **Form code ↔ UI binding** | `.cls` class node (canonical form code) | `form-layout` / `report-layout` node + one `form-instance-control` per named control (and a `property` node per control *type*) | `UnresolvedReference` with `synthesizedBy: 'vba-form-binding'`; resolver wires the layout → sibling `.cls` class at index time |
|
|
386
|
+
| **Control event handler** (`btnSave_Click`) | `.cls` handler procedure | `form-instance-control` node for `btnSave` | `event-handler` edge stored **handler → control**. To go the other way — from a control to what runs on it — follow that edge *backwards* |
|
|
387
|
+
| **Form / report lifecycle event** (`Form_Load`, `Report_Open`) | `.cls` handler procedure | `form-layout` / `report-layout` node | `event-handler` edge **handler → layout**, carrying `metadata.scope: 'form'` so it is distinguishable from a control handler |
|
|
388
|
+
| **Expression-wired event** (`OnClick ="=AuditNow()"`) | `.bas`/`.cls` procedure named in the expression | `form-instance-control` / layout node carrying the property | Resolves to the **same** `event-handler` direction (handler → control), tagged `synthesizedBy: 'vba-expression-handler'`. A bare macro name or `[Event Procedure]` emits nothing rather than inventing a procedure |
|
|
386
389
|
| **`Implements IFoo`** | `.cls` declares `Implements IFoo` | — | Emits an `implements` edge from the class to `IFoo` |
|
|
387
390
|
| **`Dim x As Foo.Bar`** | `.bas`/`.cls` qualified type reference | — | `references` edge to `Foo` with `synthesizedBy: 'vba-name-resolution'`; silent when unresolvable |
|
|
388
391
|
| **`WithEvents m_X As Form_Foo`** | `.cls` listener declaration | — | `references` edge to `Form_Foo` with `synthesizedBy: 'vba-withevents'` — closes the event-driven form flow |
|
|
@@ -396,7 +399,11 @@ The two are **sibling tools**: Dysflow owns the Access binary round-trip (sync,
|
|
|
396
399
|
|
|
397
400
|
**Hard invariants** enforced by the extractor and verified by tests:
|
|
398
401
|
|
|
399
|
-
- **`.cls` is the canonical source for form code.** `.form.txt`
|
|
402
|
+
- **`.cls` is the canonical source for form code.** `.form.txt` / `.report.txt` emit **zero procedures** — no `function` / `sub` node, and no class node for the form's own code, ever comes from a layout file. What they do emit is the `form-layout` / `report-layout` container, one `form-instance-control` per named control, a `property` node per control *type*, and a synthetic placeholder node for each table or query the layout binds through `RecordSource` / `RowSource` / `ControlSource`. Dysflow overwrites the layout file's embedded code on the next import, so emitting procedures from there would be both wrong and ephemeral.
|
|
403
|
+
- **An event binding is stored in one direction: handler → control/layout.** There is no reverse edge and no bidirectional edge. Reaching a handler from its control means following the `event-handler` edge backwards; that is what `traverseGraph` and `getBehaviorEvidence` do for you.
|
|
404
|
+
- **A control belongs to the layout that `contains` it**, not to whatever file its name appears in. The same control name (`btnSave`) routinely exists on several forms, so any lookup by name must be scoped by layout — an unscoped name is ambiguous, not a match.
|
|
405
|
+
- **A call is not always a `calls` edge.** VBA's statement-form Sub call (`SaveRecord` alone on a line) could also be a `Const` read, so the extractor keeps it as an ambiguous identifier and it resolves to a `references` edge onto the procedure. Consumers that follow only `calls` lose the dominant call style in Access code-behind.
|
|
406
|
+
- **CodeGraph indexes the exported source tree, not the live `.accdb`.** Everything here is static evidence: it does not prove a handler ran, and it says nothing about whether the binary matches the export — Dysflow owns that round-trip. Edges tagged `provenance: 'heuristic'` are inferred from naming and string contents; absence of an edge is missing evidence, never proof of no runtime effect.
|
|
400
407
|
- **Option-only files stay silent.** A `.bas` containing only `Option ...` directives emits zero symbol nodes; a `.bas` with only `Enum`, `Const`, `Event`, `Type`, or `Declare` declarations DOES emit its module node because those declarations are real graph symbols.
|
|
401
408
|
|
|
402
409
|
**VBA / Access node kinds added by the fork:**
|
|
@@ -414,6 +421,125 @@ The two are **sibling tools**: Dysflow owns the Access binary round-trip (sync,
|
|
|
414
421
|
|
|
415
422
|
**Scope:** Dysflow-managed projects only (Dysflow's `.form.txt` / `.report.txt` SaveAsText format). Legacy `.frm` / `.dsr` Access binary formats are not in scope.
|
|
416
423
|
|
|
424
|
+
### Semantic acceptance
|
|
425
|
+
|
|
426
|
+
Extraction tests prove the graph holds what it should; this proves the
|
|
427
|
+
**answers** are right — which expected paths and entities are missing, and
|
|
428
|
+
which unrelated ones get reported. Node and edge counts detect neither.
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
npm run acceptance:vba
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
It builds a fresh, isolated index over a throwaway copy of
|
|
435
|
+
`__tests__/fixtures/vba-consumer-semantics/`, asks the public consumer surfaces
|
|
436
|
+
the questions in `__tests__/fixtures/vba-consumer-semantics-ground-truth.json`
|
|
437
|
+
— expected answers read off the source by hand, each with its source location,
|
|
438
|
+
each carrying what must be present **and** what must not — compares them, and
|
|
439
|
+
exits non-zero on the first missing or unexpected identity. It also runs on the
|
|
440
|
+
normal test and CI path; no separate workflow hosts it.
|
|
441
|
+
|
|
442
|
+
To evaluate an authorized copy of your own export with the same criteria and
|
|
443
|
+
harness, write a ground-truth file in the same shape and point the run at both:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
VBA_ACCEPTANCE_CORPUS=/path/to/export-copy VBA_ACCEPTANCE_GROUND_TRUTH=/path/to/ground-truth.json npm run acceptance:vba
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
The run is local: it reads only the directory you name, copies it to a
|
|
450
|
+
temporary directory it deletes afterwards, never touches an `.accdb`, never
|
|
451
|
+
discovers projects on your machine, and keeps your paths out of the report it
|
|
452
|
+
prints. Keep a ground-truth file derived from private data beside the export
|
|
453
|
+
copy — don't commit it. Passing the checked-in corpus is not certification of
|
|
454
|
+
arbitrary projects, and says nothing about live Access execution.
|
|
455
|
+
|
|
456
|
+
### Worked example: from a control to the tables it touches
|
|
457
|
+
|
|
458
|
+
Runnable against any indexed Dysflow export. It is also executed as a test —
|
|
459
|
+
`documented Access traversal example matches indexed fixture` in
|
|
460
|
+
`__tests__/vba-documented-example.test.ts` — against the checked-in
|
|
461
|
+
`__tests__/fixtures/vba-consumer-semantics/` corpus, so these values are
|
|
462
|
+
asserted, not illustrative.
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
import CodeGraph from 'codegraph-vba';
|
|
466
|
+
|
|
467
|
+
const cg = await CodeGraph.open('/path/to/dysflow-export');
|
|
468
|
+
|
|
469
|
+
// 1. Resolve the control WITH its layout. `btnSave` exists on several forms,
|
|
470
|
+
// so the layout file is what makes the answer unambiguous. A bare name is
|
|
471
|
+
// ambiguous, not a match.
|
|
472
|
+
const btnSave = cg
|
|
473
|
+
.searchNodes('btnSave', { kinds: ['form-instance-control'], languages: ['vba'] })
|
|
474
|
+
.map(({ node }) => node)
|
|
475
|
+
.find((node) => node.filePath.endsWith('Form_Orders.form.txt'))!;
|
|
476
|
+
|
|
477
|
+
// 2. The binding is stored handler -> control, so the handler is found by
|
|
478
|
+
// following it BACKWARDS.
|
|
479
|
+
const binding = cg
|
|
480
|
+
.getIncomingEdges(btnSave.id)
|
|
481
|
+
.filter((edge) => edge.kind === 'event-handler');
|
|
482
|
+
// binding[0].metadata.eventName === 'Click'
|
|
483
|
+
// binding[0].source === the btnSave_Click node's id
|
|
484
|
+
|
|
485
|
+
// 3. What runs, and what it reaches. One read, already scoped by step 1.
|
|
486
|
+
const behavior = cg.getBehaviorEvidence({ nodeId: btnSave.id });
|
|
487
|
+
// behavior.evidence[0].handler === 'btnSave_Click'
|
|
488
|
+
// behavior.evidence[0].callPath === ['btnSave_Click', 'SaveOrderTotals']
|
|
489
|
+
// behavior.evidence[0].tables === ['tblOrderLines', 'tblProducts']
|
|
490
|
+
|
|
491
|
+
// 4. The tables are reached THROUGH the saved query — the context says which,
|
|
492
|
+
// instead of leaving you to match names yourself.
|
|
493
|
+
behavior.context.data.find((d) => d.name === 'tblOrderLines')!.throughQuery;
|
|
494
|
+
// 'qryOrderTotals'
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Same control name on a different form, same call, different answer:
|
|
498
|
+
`{ name: 'btnSave', layout: 'Form_Invoices' }` returns
|
|
499
|
+
`['btnSave_Click', 'SaveInvoiceTotals']` — and `{ name: 'btnSave' }` with no
|
|
500
|
+
layout returns no evidence at all, listing both candidates in
|
|
501
|
+
`context.ambiguous`.
|
|
502
|
+
|
|
503
|
+
### Behavior evidence for one control
|
|
504
|
+
|
|
505
|
+
`getBehaviorEvidence` answers "what does this control actually do?" in one
|
|
506
|
+
read, for a consumer that wants data rather than prose: the event binding, the
|
|
507
|
+
call paths under it, and the tables and effects those procedures reach.
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
const evidence = cg.getBehaviorEvidence({ name: 'btnSave', layout: 'Form_Orders' });
|
|
511
|
+
|
|
512
|
+
evidence.evidence;
|
|
513
|
+
// [{ handler: 'btnSave_Click',
|
|
514
|
+
// callPath: ['btnSave_Click', 'SaveOrderTotals'],
|
|
515
|
+
// tables: ['tblOrderLines', 'tblProducts'],
|
|
516
|
+
// effects: ['data-access:qryOrderTotals', 'data-access:tblOrderLines', 'data-access:tblProducts'] }]
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
- **Identify the target by `nodeId`** whenever you have one. A `name` needs a
|
|
520
|
+
`layout` as soon as it is not unique — the same control name usually exists on
|
|
521
|
+
several forms, and an ambiguous name is **refused** with the candidates listed
|
|
522
|
+
in `context.ambiguous`, never narrowed to an arbitrary match.
|
|
523
|
+
- **`callPath` is one root-to-leaf path**, handler first. Distinct branches are
|
|
524
|
+
separate entries, never concatenated into a sequence the runtime would not
|
|
525
|
+
take; a path that re-enters a procedure ends there.
|
|
526
|
+
- **`effects` uses a closed vocabulary**: `read:<name>`, `write:<name>`,
|
|
527
|
+
`data-access:<name>` (direction unknown — neither a read nor a write),
|
|
528
|
+
`opens-form:<Name>`, `opens-report:<Name>`, `raises-event:<Name>`.
|
|
529
|
+
- **`context` carries everything that is not the payload**: node identities and
|
|
530
|
+
source locations, how each handler is wired (`control`, `form` lifecycle,
|
|
531
|
+
`expression`), what could not be resolved, and whether a depth or result
|
|
532
|
+
budget cut the answer short (`maxCallDepth` defaults to 5, `maxResults` to 50).
|
|
533
|
+
- **It is static evidence from exported source.** An empty `tables` or `effects`
|
|
534
|
+
list means the index holds no such fact — **not** that the code has no runtime
|
|
535
|
+
effect. It also says nothing about whether the `.accdb` binary matches the
|
|
536
|
+
export.
|
|
537
|
+
|
|
538
|
+
The same assembler is available over MCP as `codegraph_behavior_evidence`
|
|
539
|
+
(unlisted by default like the other narrow tools — enable it with
|
|
540
|
+
`CODEGRAPH_MCP_TOOLS=explore,behavior_evidence`), returning the identical
|
|
541
|
+
payload as JSON.
|
|
542
|
+
|
|
417
543
|
---
|
|
418
544
|
|
|
419
545
|
## Quick Start
|
|
@@ -616,7 +742,7 @@ When running as an MCP server, CodeGraph exposes a **single tool** — `codegrap
|
|
|
616
742
|
|------|---------|
|
|
617
743
|
| `codegraph_explore` | Answer almost any question in one call — "how does X work", a flow ("how does X reach Y"), or surveying an area — returning the relevant symbols' verbatim source grouped by file, plus the call paths between them and a blast-radius summary. Surfaces dynamic-dispatch hops (callbacks, React re-render, interface→impl) grep can't follow. Name a file or symbol in the query to read its current line-numbered source, the same shape the Read tool gives you. |
|
|
618
744
|
|
|
619
|
-
The other tools (`codegraph_node`, `codegraph_search`, `codegraph_callers`, `codegraph_callees`, `codegraph_impact`, `codegraph_files`, `codegraph_status`) 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`).
|
|
745
|
+
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`).
|
|
620
746
|
|
|
621
747
|
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.
|
|
622
748
|
|
|
@@ -644,6 +770,8 @@ const results = cg.searchNodes('UserService');
|
|
|
644
770
|
const callers = cg.getCallers(results[0].node.id);
|
|
645
771
|
const context = await cg.buildContext('fix login bug', { maxNodes: 20, includeCode: true, format: 'markdown' });
|
|
646
772
|
const impact = cg.getImpactRadius(results[0].node.id, 2);
|
|
773
|
+
// Access/VBA only — see "Behavior evidence for one control" above:
|
|
774
|
+
const behavior = cg.getBehaviorEvidence({ name: 'btnSave', layout: 'Form_Orders' });
|
|
647
775
|
|
|
648
776
|
cg.watch(); // auto-sync on file changes
|
|
649
777
|
cg.unwatch(); // stop watching
|
package/dist/db/queries.d.ts
CHANGED
|
@@ -507,6 +507,17 @@ export declare class QueryBuilder {
|
|
|
507
507
|
* Get unresolved references by name (for resolution)
|
|
508
508
|
*/
|
|
509
509
|
getUnresolvedByName(name: string): UnresolvedReference[];
|
|
510
|
+
/**
|
|
511
|
+
* Get the unresolved references recorded for one file, ordered by position.
|
|
512
|
+
*
|
|
513
|
+
* Scoped read for consumers that report what could NOT be answered about a
|
|
514
|
+
* specific procedure (issue #299): loading every row to filter in memory
|
|
515
|
+
* would scale with the whole project instead of the file being explained.
|
|
516
|
+
* Both pending and failed rows are returned — for this purpose "the
|
|
517
|
+
* resolver never matched it" and "the resolver has not tried yet" are the
|
|
518
|
+
* same honest answer: the index cannot say.
|
|
519
|
+
*/
|
|
520
|
+
getUnresolvedReferencesForFile(filePath: string): UnresolvedReference[];
|
|
510
521
|
/**
|
|
511
522
|
* Get all unresolved references
|
|
512
523
|
*/
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { QueryBuilder } from '../db/queries';
|
|
2
|
+
/**
|
|
3
|
+
* The consumer compatibility payload.
|
|
4
|
+
*
|
|
5
|
+
* Field types are fixed by the consumer that reads them (Dysflow's
|
|
6
|
+
* `CodeGraphBehaviorEvidence`) and must not be widened here.
|
|
7
|
+
*/
|
|
8
|
+
export interface CodeGraphBehaviorEvidence {
|
|
9
|
+
/** Name of the procedure the event is bound to. */
|
|
10
|
+
handler: string;
|
|
11
|
+
/**
|
|
12
|
+
* One root-to-leaf execution path, handler first, callees in the order the
|
|
13
|
+
* graph stores them (by node id, so the output is stable across runs).
|
|
14
|
+
* Distinct branches are separate entries — they are never concatenated into
|
|
15
|
+
* a single sequence the runtime would not take. A path that re-enters a
|
|
16
|
+
* procedure already on it ends there, repeating that name once.
|
|
17
|
+
*/
|
|
18
|
+
callPath: string[];
|
|
19
|
+
/** Tables reached along this path, directly or through a saved query. */
|
|
20
|
+
tables?: string[];
|
|
21
|
+
/** See {@link BEHAVIOR_EFFECT_VOCABULARY}. */
|
|
22
|
+
effects?: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The closed vocabulary of `effects` strings. Anything outside this list is a
|
|
26
|
+
* bug, not a new fact.
|
|
27
|
+
*
|
|
28
|
+
* - `read:<name>` / `write:<name>` — a data reference the extractor typed.
|
|
29
|
+
* - `data-access:<name>` — a data reference whose direction is unknown.
|
|
30
|
+
* NOT a read and NOT a write; it means the index cannot say.
|
|
31
|
+
* - `opens-form:<Name>` / `opens-report:<Name>` — an Access object opened.
|
|
32
|
+
* - `raises-event:<Name>` — an event raised from the path.
|
|
33
|
+
*/
|
|
34
|
+
export declare const BEHAVIOR_EFFECT_VOCABULARY: readonly ["read:<name>", "write:<name>", "data-access:<name>", "opens-form:<Name>", "opens-report:<Name>", "raises-event:<Name>"];
|
|
35
|
+
/** How a handler is bound to the thing it answers for. */
|
|
36
|
+
export type BehaviorBindingScope =
|
|
37
|
+
/** `<Control>_<Event>` code-behind on a control. */
|
|
38
|
+
'control'
|
|
39
|
+
/** The form's or report's own lifecycle event. */
|
|
40
|
+
| 'form'
|
|
41
|
+
/** An `=Expression()` property on the control or layout. */
|
|
42
|
+
| 'expression'
|
|
43
|
+
/** The request named a procedure directly; no binding was involved. */
|
|
44
|
+
| 'direct';
|
|
45
|
+
export interface BehaviorEvidenceRequest {
|
|
46
|
+
/** Stable node id. The unambiguous form — always prefer it. */
|
|
47
|
+
nodeId?: string;
|
|
48
|
+
/** Control, handler or layout name. Requires `layout` when not unique. */
|
|
49
|
+
name?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Layout context for `name`: a form/report name or its layout file name.
|
|
52
|
+
* Without it an ambiguous name is REFUSED, never silently narrowed to the
|
|
53
|
+
* first match.
|
|
54
|
+
*/
|
|
55
|
+
layout?: string;
|
|
56
|
+
/** Call-path depth budget. Default 5, clamped to 1..20. */
|
|
57
|
+
maxCallDepth?: number;
|
|
58
|
+
/** Maximum evidence entries. Default 50, clamped to 1..500.
|
|
59
|
+
* Traversal also visits at most (maxResults + 1) * maxCallDepth path steps. */
|
|
60
|
+
maxResults?: number;
|
|
61
|
+
}
|
|
62
|
+
export interface BehaviorEvidenceTarget {
|
|
63
|
+
id: string;
|
|
64
|
+
name: string;
|
|
65
|
+
kind: string;
|
|
66
|
+
filePath: string;
|
|
67
|
+
/** Owning form/report, from the layout's `contains` edge. */
|
|
68
|
+
layout: string | null;
|
|
69
|
+
}
|
|
70
|
+
export interface BehaviorHandlerContext {
|
|
71
|
+
handler: string;
|
|
72
|
+
handlerId: string;
|
|
73
|
+
/** Access event name (`Click`, `Load`, …), or null when not bound. */
|
|
74
|
+
event: string | null;
|
|
75
|
+
scope: BehaviorBindingScope;
|
|
76
|
+
provenance: string;
|
|
77
|
+
/** `file:line` of the wiring site. */
|
|
78
|
+
location: string;
|
|
79
|
+
/** `metadata.synthesizedBy` of the binding edge, when present. */
|
|
80
|
+
wiredBy: string | null;
|
|
81
|
+
}
|
|
82
|
+
export interface BehaviorDataEvidence {
|
|
83
|
+
/** Procedure the reference was attributed to. */
|
|
84
|
+
procedure: string;
|
|
85
|
+
name: string;
|
|
86
|
+
/** Node kind of the referenced object (`class`, `table`, `query`, …). */
|
|
87
|
+
targetKind: string;
|
|
88
|
+
access: 'read' | 'write' | 'unknown';
|
|
89
|
+
/** `metadata.synthesizedBy` of the reference edge. */
|
|
90
|
+
via: string | null;
|
|
91
|
+
/** Set when the table was reached through a saved query. */
|
|
92
|
+
throughQuery?: string;
|
|
93
|
+
/**
|
|
94
|
+
* `edge-source` — the reference edge starts at the procedure itself.
|
|
95
|
+
* `source-line` — it starts at the module node and was attributed to this
|
|
96
|
+
* procedure because the edge's line falls inside its range.
|
|
97
|
+
*/
|
|
98
|
+
attributedBy: 'edge-source' | 'source-line';
|
|
99
|
+
location: string;
|
|
100
|
+
}
|
|
101
|
+
export interface BehaviorAmbiguity {
|
|
102
|
+
name: string;
|
|
103
|
+
matches: Array<{
|
|
104
|
+
id: string;
|
|
105
|
+
kind: string;
|
|
106
|
+
filePath: string;
|
|
107
|
+
layout: string | null;
|
|
108
|
+
}>;
|
|
109
|
+
}
|
|
110
|
+
export interface BehaviorUnresolvedReference {
|
|
111
|
+
/** Procedure the unresolved reference sits in, when it could be attributed. */
|
|
112
|
+
procedure: string | null;
|
|
113
|
+
referenceName: string;
|
|
114
|
+
referenceKind: string;
|
|
115
|
+
location: string;
|
|
116
|
+
}
|
|
117
|
+
export interface BehaviorEvidenceResult {
|
|
118
|
+
/** What the request resolved to, or null when it resolved to nothing. */
|
|
119
|
+
target: BehaviorEvidenceTarget | null;
|
|
120
|
+
/** The consumer compatibility payload. */
|
|
121
|
+
evidence: CodeGraphBehaviorEvidence[];
|
|
122
|
+
context: {
|
|
123
|
+
handlers: BehaviorHandlerContext[];
|
|
124
|
+
data: BehaviorDataEvidence[];
|
|
125
|
+
unresolved: BehaviorUnresolvedReference[];
|
|
126
|
+
/** Populated only when a name matched more than one node. */
|
|
127
|
+
ambiguous: BehaviorAmbiguity[];
|
|
128
|
+
truncated: {
|
|
129
|
+
/** A path hit `maxCallDepth` and was cut short. */
|
|
130
|
+
callDepth: boolean;
|
|
131
|
+
/** Entries were dropped, or the traversal work budget left paths unexplored. */
|
|
132
|
+
results: boolean;
|
|
133
|
+
/** A path re-entered a procedure already on it. */
|
|
134
|
+
cycle: boolean;
|
|
135
|
+
};
|
|
136
|
+
/** See {@link BEHAVIOR_EVIDENCE_NOTES}. */
|
|
137
|
+
notes: string[];
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The closed vocabulary of `context.notes`.
|
|
142
|
+
*
|
|
143
|
+
* - `MISSING_TARGET_SELECTOR` — neither `nodeId` nor `name` was given.
|
|
144
|
+
* - `TARGET_NOT_FOUND` — nothing in the index matches. A lookup miss, not
|
|
145
|
+
* proof the control has no behavior.
|
|
146
|
+
* - `AMBIGUOUS_TARGET` — the name matches several nodes; see
|
|
147
|
+
* `context.ambiguous`. No evidence is returned, and nothing is guessed.
|
|
148
|
+
* - `NO_HANDLER_BOUND` — the target exists but no handler is wired to it in
|
|
149
|
+
* the index. Access macros and `[Event Procedure]` entries with no
|
|
150
|
+
* code-behind land here.
|
|
151
|
+
* - `STATIC_SOURCE_EVIDENCE` — always present. The answer comes from indexed
|
|
152
|
+
* exported source: it does not prove the code ran, and it says nothing
|
|
153
|
+
* about whether the `.accdb` binary matches the export.
|
|
154
|
+
*/
|
|
155
|
+
export declare const BEHAVIOR_EVIDENCE_NOTES: readonly ["MISSING_TARGET_SELECTOR", "TARGET_NOT_FOUND", "AMBIGUOUS_TARGET", "NO_HANDLER_BOUND", "STATIC_SOURCE_EVIDENCE"];
|
|
156
|
+
/**
|
|
157
|
+
* Assembles behavior evidence for one control, layout or handler.
|
|
158
|
+
*
|
|
159
|
+
* Pure read path over {@link QueryBuilder}: no new SQL, no second traversal
|
|
160
|
+
* implementation, no writes.
|
|
161
|
+
*/
|
|
162
|
+
export declare function buildBehaviorEvidence(queries: QueryBuilder, request: BehaviorEvidenceRequest): BehaviorEvidenceResult;
|
|
163
|
+
//# sourceMappingURL=behavior-evidence.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* knowledge graph from any codebase.
|
|
6
6
|
*/
|
|
7
7
|
import { Node, Edge, FileRecord, ExtractionResult, Subgraph, TraversalOptions, SearchOptions, SearchResult, SegmentMatch, Context, GraphStats, TaskInput, TaskContext, BuildContextOptions, FindRelevantContextOptions } from './types';
|
|
8
|
+
import { BehaviorEvidenceRequest, BehaviorEvidenceResult } from './graph/behavior-evidence';
|
|
8
9
|
import { IndexProgress, IndexResult, SyncResult } from './extraction';
|
|
9
10
|
import { ResolutionResult } from './resolution';
|
|
10
11
|
import { WatchOptions, PendingFile } from './sync';
|
|
@@ -16,6 +17,7 @@ export { IndexProgress, IndexResult, SyncResult } from './extraction';
|
|
|
16
17
|
export { detectLanguage, isLanguageSupported, isGrammarLoaded, getSupportedLanguages, initGrammars, loadGrammarsForLanguages, loadAllGrammars } from './extraction';
|
|
17
18
|
export { ResolutionResult } from './resolution';
|
|
18
19
|
export { CodeGraphError, FileError, ParseError, DatabaseError, SearchError, VectorError, ConfigError, Logger, setLogger, getLogger, silentLogger, defaultLogger, } from './errors';
|
|
20
|
+
export { buildBehaviorEvidence, BEHAVIOR_EFFECT_VOCABULARY, BEHAVIOR_EVIDENCE_NOTES, CodeGraphBehaviorEvidence, BehaviorEvidenceRequest, BehaviorEvidenceResult, BehaviorEvidenceTarget, BehaviorHandlerContext, BehaviorDataEvidence, BehaviorAmbiguity, BehaviorUnresolvedReference, BehaviorBindingScope, } from './graph/behavior-evidence';
|
|
19
21
|
export { Mutex, FileLock, processInBatches, debounce, throttle, MemoryMonitor } from './utils';
|
|
20
22
|
export { FileWatcher, WatchOptions, PendingFile, LockUnavailableError } from './sync';
|
|
21
23
|
export { MCPServer } from './mcp';
|
|
@@ -527,6 +529,26 @@ export declare class CodeGraph {
|
|
|
527
529
|
* @returns Subgraph containing potentially impacted nodes
|
|
528
530
|
*/
|
|
529
531
|
getImpactRadius(nodeId: string, maxDepth?: number): Subgraph;
|
|
532
|
+
/**
|
|
533
|
+
* Assemble bounded behavior evidence for an Access control, layout or
|
|
534
|
+
* handler (issue #299).
|
|
535
|
+
*
|
|
536
|
+
* Read-only: it joins facts that are already indexed — the event binding,
|
|
537
|
+
* the call paths under it, and the tables/effects those procedures reach —
|
|
538
|
+
* into one typed payload, so a consumer does not re-implement the graph
|
|
539
|
+
* semantics for itself. It never parses source, opens Access, or writes to
|
|
540
|
+
* the index.
|
|
541
|
+
*
|
|
542
|
+
* Identify the target by `nodeId` whenever you have one. A `name` needs a
|
|
543
|
+
* `layout` as soon as it is not unique: an ambiguous name is REFUSED with
|
|
544
|
+
* the candidates listed, never narrowed to an arbitrary first match.
|
|
545
|
+
*
|
|
546
|
+
* The answer is static evidence from exported source. An empty `tables` or
|
|
547
|
+
* `effects` list means the index holds no such fact — not that the code has
|
|
548
|
+
* no runtime effect. See {@link BehaviorEvidenceResult.context} for what
|
|
549
|
+
* could not be answered.
|
|
550
|
+
*/
|
|
551
|
+
getBehaviorEvidence(request: BehaviorEvidenceRequest): BehaviorEvidenceResult;
|
|
530
552
|
/**
|
|
531
553
|
* Find the shortest path between two nodes
|
|
532
554
|
*
|
|
@@ -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`). `.form.txt` and `.report.txt` are\n extracted as a `module` plus one `property` per Access control - **no**\n `function`/`sub`/`class` nodes come from form files; the canonical code\n lives in the sibling `.cls`, parsed by the same extractor on that file.\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- **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
|
*
|
package/dist/mcp/tools.d.ts
CHANGED
|
@@ -382,6 +382,18 @@ export declare class ToolHandler {
|
|
|
382
382
|
* NotIndexed/PathRefusal, which {@link executeReadTool} classifies.
|
|
383
383
|
*/
|
|
384
384
|
private dispatchTool;
|
|
385
|
+
/**
|
|
386
|
+
* Access/VBA behavior evidence (issue #299) — a thin adapter over
|
|
387
|
+
* {@link CodeGraph.getBehaviorEvidence}. The assembly lives in
|
|
388
|
+
* `src/graph/behavior-evidence.ts`; this only validates argument shapes and
|
|
389
|
+
* serializes the typed result, so the MCP surface and a library consumer
|
|
390
|
+
* can never drift into two different answers.
|
|
391
|
+
*
|
|
392
|
+
* A request with no selector is NOT an error: the payload comes back with
|
|
393
|
+
* `MISSING_TARGET_SELECTOR` in `context.notes`, the same success-shaped
|
|
394
|
+
* guidance every other recoverable condition uses here.
|
|
395
|
+
*/
|
|
396
|
+
private handleBehaviorEvidence;
|
|
385
397
|
/** Run the CLI-only query command and preserve its JSON stdout verbatim. */
|
|
386
398
|
private handleQuery;
|
|
387
399
|
/**
|
|
@@ -28,8 +28,20 @@ export interface TraversalResult {
|
|
|
28
28
|
warnings: string[];
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Traverses VBA
|
|
32
|
-
*
|
|
31
|
+
* Traverses the VBA execution graph from a node id, following the semantics
|
|
32
|
+
* the production extractor actually stores.
|
|
33
|
+
*
|
|
34
|
+
* Two directions are involved, which is the whole point of this helper:
|
|
35
|
+
*
|
|
36
|
+
* - An `event-handler` edge is stored HANDLER -> UI object (both for the
|
|
37
|
+
* `<Control>_<Event>` code-behind convention and for `=Expression()`
|
|
38
|
+
* wiring, which the resolver repoints the same way). So reaching a
|
|
39
|
+
* handler from its control or layout means following that edge BACKWARDS.
|
|
40
|
+
* - A `calls` edge is stored CALLER -> CALLEE, so the rest of the path is
|
|
41
|
+
* followed forwards.
|
|
42
|
+
*
|
|
43
|
+
* Starting from a handler still works: it simply has no incoming
|
|
44
|
+
* `event-handler` edge to expand, and its callees are found the usual way.
|
|
33
45
|
*/
|
|
34
46
|
export declare function traverseGraph(db: SqliteDatabase, startNodeId: string, maxDepth?: number): TraversalResult;
|
|
35
47
|
//# sourceMappingURL=backtrace-helpers.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aroman22/codegraph-vba",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.1",
|
|
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.
|
|
19
|
-
"@aroman22/codegraph-vba-darwin-x64": "1.
|
|
20
|
-
"@aroman22/codegraph-vba-linux-arm64": "1.
|
|
21
|
-
"@aroman22/codegraph-vba-linux-x64": "1.
|
|
22
|
-
"@aroman22/codegraph-vba-win32-arm64": "1.
|
|
23
|
-
"@aroman22/codegraph-vba-win32-x64": "1.
|
|
18
|
+
"@aroman22/codegraph-vba-darwin-arm64": "1.17.1",
|
|
19
|
+
"@aroman22/codegraph-vba-darwin-x64": "1.17.1",
|
|
20
|
+
"@aroman22/codegraph-vba-linux-arm64": "1.17.1",
|
|
21
|
+
"@aroman22/codegraph-vba-linux-x64": "1.17.1",
|
|
22
|
+
"@aroman22/codegraph-vba-win32-arm64": "1.17.1",
|
|
23
|
+
"@aroman22/codegraph-vba-win32-x64": "1.17.1"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"npm-shim.js",
|