@aroman22/codegraph-vba 1.15.0 → 1.17.0
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/bin/daemon-release.d.ts +7 -0
- package/dist/db/queries.d.ts +41 -0
- package/dist/extraction/access-erd-extractor.d.ts +57 -0
- package/dist/extraction/extraction-version.d.ts +1 -1
- package/dist/extraction/grammars.d.ts +20 -0
- package/dist/extraction/index.d.ts +1 -0
- package/dist/extraction/parse-pool.d.ts +8 -3
- package/dist/extraction/sql-query-extractor.d.ts +16 -14
- package/dist/extraction/sql-table-scan.d.ts +184 -0
- package/dist/extraction/tree-sitter.d.ts +10 -1
- package/dist/extraction/vba/call-sweep.d.ts +2 -7
- package/dist/extraction/vba/calls.d.ts +24 -4
- package/dist/extraction/vba/constants.d.ts +7 -14
- package/dist/extraction/vba/context.d.ts +443 -7
- package/dist/extraction/vba/controls.d.ts +18 -1
- package/dist/extraction/vba/declarations.d.ts +1 -6
- package/dist/extraction/vba/dims.d.ts +11 -7
- package/dist/extraction/vba/docmd.d.ts +29 -2
- package/dist/extraction/vba/enums-consts.d.ts +7 -14
- package/dist/extraction/vba/error-channel.d.ts +57 -0
- package/dist/extraction/vba/errors.d.ts +64 -0
- package/dist/extraction/vba/filesystem-statements.d.ts +23 -0
- package/dist/extraction/vba/implements.d.ts +1 -6
- package/dist/extraction/vba/labels.d.ts +26 -0
- package/dist/extraction/vba/module-vars.d.ts +36 -0
- package/dist/extraction/vba/options.d.ts +88 -0
- package/dist/extraction/vba/parameters.d.ts +35 -0
- package/dist/extraction/vba/procedures.d.ts +1 -9
- package/dist/extraction/vba/rules.d.ts +10 -5
- package/dist/extraction/vba/runtime-objects.d.ts +59 -0
- package/dist/extraction/vba/signature.d.ts +57 -0
- package/dist/extraction/vba/sql-wrapper.d.ts +76 -3
- package/dist/extraction/vba/text-utils.d.ts +62 -2
- package/dist/extraction/vba-extractor.d.ts +18 -1
- package/dist/extraction/vba-form-extractor.d.ts +28 -14
- package/dist/extraction/vba-preprocess.d.ts +89 -3
- package/dist/extraction/vba-source.d.ts +0 -10
- package/dist/extraction/vba-test-manifest-extractor.d.ts +0 -6
- package/dist/graph/behavior-evidence.d.ts +162 -0
- package/dist/index.d.ts +22 -0
- package/dist/mcp/daemon-paths.d.ts +6 -0
- package/dist/mcp/daemon-registry.d.ts +82 -7
- package/dist/mcp/daemon-watchdog.d.ts +12 -0
- package/dist/mcp/daemon.d.ts +20 -1
- package/dist/mcp/proxy.d.ts +32 -0
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/project-config.d.ts +43 -2
- package/dist/resolution/index.d.ts +47 -2
- package/dist/resolution/name-matcher.d.ts +25 -0
- package/dist/resolution/vba-runtime-objects.d.ts +11 -11
- package/dist/types.d.ts +13 -5
- package/dist/utils/backtrace-helpers.d.ts +14 -2
- package/package.json +7 -7
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global daemon registry + stop/list control — the discovery layer behind
|
|
3
|
+
* `codegraph list` and `codegraph stop [--all]`.
|
|
4
|
+
*
|
|
5
|
+
* Every per-project daemon already writes an authoritative lockfile at
|
|
6
|
+
* `<root>/.codegraph/daemon.pid`. That's enough to stop ONE daemon you can name,
|
|
7
|
+
* but there's no central place to find them ALL — which `list` and `stop --all`
|
|
8
|
+
* need. So each daemon also drops a tiny record under `~/.codegraph/daemons/` on
|
|
9
|
+
* start and removes it on graceful shutdown.
|
|
10
|
+
*
|
|
11
|
+
* The registry is a DISCOVERY index, never a source of truth: the live pid is.
|
|
12
|
+
* A SIGKILL'd daemon can't remove its own record, so readers prune any record
|
|
13
|
+
* whose pid is dead (`isProcessAlive`). Every write/read is best-effort — a
|
|
14
|
+
* registry hiccup must never break the daemon or a command; worst case `list`
|
|
15
|
+
* momentarily misses or over-lists one, which the next liveness prune corrects.
|
|
16
|
+
*
|
|
17
|
+
* Cross-platform by construction: only files + `process.kill(pid, signal)`,
|
|
18
|
+
* which behave consistently on macOS/Linux (real signals) and Windows (mapped to
|
|
19
|
+
* TerminateProcess). Validated live on all three.
|
|
20
|
+
*/
|
|
21
|
+
import * as fs from 'fs';
|
|
1
22
|
export interface DaemonRecord {
|
|
2
23
|
/** Realpath'd project root the daemon serves. */
|
|
3
24
|
root: string;
|
|
@@ -32,16 +53,70 @@ export declare function listDaemons(opts?: {
|
|
|
32
53
|
export interface StopResult {
|
|
33
54
|
root: string;
|
|
34
55
|
pid: number | null;
|
|
35
|
-
|
|
36
|
-
|
|
56
|
+
outcome: 'released' | 'not-running' | 'no-daemon' | 'identity-mismatch' | 'unreachable' | 'termination-failed';
|
|
57
|
+
failure?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface ExpectedDaemon {
|
|
60
|
+
root: string;
|
|
61
|
+
pid: number;
|
|
62
|
+
version: string;
|
|
63
|
+
socketPath: string;
|
|
64
|
+
startedAt: number;
|
|
65
|
+
}
|
|
66
|
+
export interface DaemonReleaseDeps {
|
|
67
|
+
isAlive?: (pid: number) => boolean;
|
|
68
|
+
waitForDeath?: (pid: number, timeoutMs: number) => Promise<boolean>;
|
|
69
|
+
requestControl?: (expected: ExpectedDaemon) => Promise<'releasing' | 'identity-mismatch' | 'unreachable'>;
|
|
70
|
+
beforeArtifactDelete?: () => void;
|
|
71
|
+
leaseLinkSync?: typeof fs.linkSync;
|
|
72
|
+
afterLifecycleAcquired?: () => void;
|
|
73
|
+
afterReleaseLeasePublished?: (expected: ExpectedDaemon) => void;
|
|
74
|
+
}
|
|
75
|
+
export declare const DAEMON_RELEASE_LEASE_TTL_MS = 30000;
|
|
76
|
+
export interface DaemonLifecycleLock {
|
|
77
|
+
token: string;
|
|
78
|
+
ownerPid: number;
|
|
79
|
+
createdAt: number;
|
|
80
|
+
expiresAt: number;
|
|
81
|
+
}
|
|
82
|
+
/** Atomically acquire the shared startup/release publication arbiter. */
|
|
83
|
+
export declare function tryAcquireDaemonLifecycleLock(root: string, options?: {
|
|
84
|
+
now?: number;
|
|
85
|
+
linkSync?: typeof fs.linkSync;
|
|
86
|
+
}): DaemonLifecycleLock | null;
|
|
87
|
+
export declare function releaseDaemonLifecycleLock(root: string, lock: DaemonLifecycleLock): void;
|
|
88
|
+
export interface DaemonReleaseLease {
|
|
89
|
+
token: string;
|
|
90
|
+
ownerPid: number;
|
|
91
|
+
createdAt: number;
|
|
92
|
+
heartbeatAt: number;
|
|
93
|
+
expiresAt: number;
|
|
94
|
+
generation: Pick<ExpectedDaemon, 'pid' | 'startedAt' | 'socketPath'>;
|
|
37
95
|
}
|
|
96
|
+
/** True while intentional release exclusively owns this root's lifecycle. */
|
|
97
|
+
export declare function hasActiveDaemonReleaseLease(root: string, now?: number, hooks?: {
|
|
98
|
+
afterRecoveryRead?: () => void;
|
|
99
|
+
}): boolean;
|
|
100
|
+
/** Atomically claim release/cleanup ownership for one daemon generation. */
|
|
101
|
+
export declare function tryAcquireDaemonReleaseLease(root: string, expected: ExpectedDaemon, options?: {
|
|
102
|
+
now?: number;
|
|
103
|
+
linkSync?: typeof fs.linkSync;
|
|
104
|
+
}): DaemonReleaseLease | null;
|
|
105
|
+
/** Publish a complete renewed generation atomically under the recovery marker. */
|
|
106
|
+
export declare function refreshDaemonReleaseLease(root: string, lease: DaemonReleaseLease, now?: number): boolean;
|
|
107
|
+
/** Resolve an explicit project root to the same canonical form daemons use. */
|
|
108
|
+
export declare function canonicalDaemonRoot(root: string): string;
|
|
109
|
+
/** Stable map/set key for aliases of the same canonical root. */
|
|
110
|
+
export declare function canonicalDaemonRootKey(root: string): string;
|
|
111
|
+
/** Project-scoped, idempotent release contract shared by CLI and MCP. */
|
|
112
|
+
export declare function releaseDaemonAt(root: string, deps?: DaemonReleaseDeps): Promise<StopResult>;
|
|
38
113
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* falling back to the registry.
|
|
114
|
+
* Release the daemon serving `root` through its authenticated socket handshake,
|
|
115
|
+
* wait for confirmed process death, then sweep ownership artifacts. Never sends
|
|
116
|
+
* a signal based only on pidfile/registry liveness. `root` must be realpath'd.
|
|
43
117
|
*/
|
|
44
|
-
export declare function stopDaemonAt(root: string): Promise<StopResult>;
|
|
118
|
+
export declare function stopDaemonAt(root: string, deps?: DaemonReleaseDeps): Promise<StopResult>;
|
|
119
|
+
export declare function requestDaemonRelease(expected: ExpectedDaemon): Promise<'releasing' | 'identity-mismatch' | 'unreachable'>;
|
|
45
120
|
/** Stop every registered, live daemon. */
|
|
46
121
|
export declare function stopAllDaemons(): Promise<StopResult[]>;
|
|
47
122
|
//# sourceMappingURL=daemon-registry.d.ts.map
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* Spawned detaches (own session/process group) so closing the MCP process
|
|
17
17
|
* does not take the watchdog down with it.
|
|
18
18
|
*/
|
|
19
|
+
import { type StopResult } from './daemon-registry';
|
|
19
20
|
export interface DaemonWatchdogOptions {
|
|
20
21
|
/** Poll interval (ms). Default 30s. */
|
|
21
22
|
intervalMs?: number;
|
|
@@ -33,6 +34,10 @@ export interface DaemonWatchdogOptions {
|
|
|
33
34
|
windowsHide?: boolean;
|
|
34
35
|
stdio?: 'ignore' | ['ignore', number, number];
|
|
35
36
|
}) => boolean;
|
|
37
|
+
/** Release seam for deterministic overlap/failure tests. */
|
|
38
|
+
releaseFn?: (root: string) => Promise<StopResult>;
|
|
39
|
+
/** Async boundary before spawn; defaults to one microtask for release ordering. */
|
|
40
|
+
beforeSpawn?: () => Promise<void>;
|
|
36
41
|
}
|
|
37
42
|
/**
|
|
38
43
|
* Per-project daemon liveness watchdog. Registers roots; polls every
|
|
@@ -40,16 +45,23 @@ export interface DaemonWatchdogOptions {
|
|
|
40
45
|
*/
|
|
41
46
|
export declare class DaemonWatchdog {
|
|
42
47
|
private readonly roots;
|
|
48
|
+
private readonly releasing;
|
|
43
49
|
private interval;
|
|
44
50
|
private readonly intervalMs;
|
|
45
51
|
private readonly scriptPath;
|
|
46
52
|
private readonly nodePath;
|
|
47
53
|
private readonly spawnFn;
|
|
54
|
+
private readonly releaseFn;
|
|
55
|
+
private readonly beforeSpawn;
|
|
48
56
|
constructor(opts?: DaemonWatchdogOptions);
|
|
49
57
|
/** Watch a project root: if its daemon dies, respawn it. Idempotent. */
|
|
50
58
|
watch(root: string): void;
|
|
59
|
+
/** Begin a new lifecycle for an intentionally released root. */
|
|
60
|
+
resume(root: string): void;
|
|
51
61
|
/** Stop watching a root. Idempotent. */
|
|
52
62
|
unwatch(root: string): void;
|
|
63
|
+
/** Intentionally release one project without allowing the next tick to respawn it. */
|
|
64
|
+
release(root: string): Promise<StopResult>;
|
|
53
65
|
/** Number of roots currently being watched. */
|
|
54
66
|
size(): number;
|
|
55
67
|
/**
|
package/dist/mcp/daemon.d.ts
CHANGED
|
@@ -63,8 +63,17 @@ export interface DaemonHello {
|
|
|
63
63
|
codegraph: string;
|
|
64
64
|
pid: number;
|
|
65
65
|
socketPath: string;
|
|
66
|
+
root: string;
|
|
67
|
+
startedAt: number;
|
|
66
68
|
protocol: 1;
|
|
67
69
|
}
|
|
70
|
+
export interface DaemonReleaseControl {
|
|
71
|
+
codegraph_control: 1;
|
|
72
|
+
action: 'release';
|
|
73
|
+
root: string;
|
|
74
|
+
pid: number;
|
|
75
|
+
startedAt: number;
|
|
76
|
+
}
|
|
68
77
|
/**
|
|
69
78
|
* Optional reverse-handshake line a proxy sends right after it verifies the
|
|
70
79
|
* daemon hello, carrying its own pids so the daemon can reap the client if its
|
|
@@ -112,9 +121,16 @@ export declare class Daemon {
|
|
|
112
121
|
private stopping;
|
|
113
122
|
private socketPath;
|
|
114
123
|
private pidPath;
|
|
124
|
+
private startedAt;
|
|
125
|
+
private acquiredGeneration;
|
|
126
|
+
private listenSocket;
|
|
127
|
+
private exit;
|
|
115
128
|
constructor(projectRoot: string, opts?: {
|
|
116
129
|
idleTimeoutMs?: number;
|
|
117
130
|
maxIdleMs?: number;
|
|
131
|
+
generation?: DaemonLockInfo;
|
|
132
|
+
listenSocket?: (socketPath: string, onConnection: (socket: net.Socket) => void) => Promise<net.Server>;
|
|
133
|
+
exit?: (code: number) => void;
|
|
118
134
|
});
|
|
119
135
|
/**
|
|
120
136
|
* Bind the socket, kick off engine init, and register signal handlers. The
|
|
@@ -222,7 +238,9 @@ export type AcquireResult = {
|
|
|
222
238
|
* widened). The race's worst case is two daemons briefly; on a single external
|
|
223
239
|
* drive that's strictly better than the daemon never starting at all.
|
|
224
240
|
*/
|
|
225
|
-
export declare function tryAcquireDaemonLock(projectRoot: string
|
|
241
|
+
export declare function tryAcquireDaemonLock(projectRoot: string, options?: {
|
|
242
|
+
afterLifecycleAcquired?: () => void;
|
|
243
|
+
}): AcquireResult;
|
|
226
244
|
/**
|
|
227
245
|
* Exclusive-create the pidfile (O_CREAT|O_EXCL via the `wx` flag) and write the
|
|
228
246
|
* full record through the same fd — the hard-link-free fallback used by
|
|
@@ -285,6 +303,7 @@ export declare function peerIsDead(peers: {
|
|
|
285
303
|
pid: number | null;
|
|
286
304
|
hostPid: number | null;
|
|
287
305
|
}, isAlive: (pid: number) => boolean): boolean;
|
|
306
|
+
export declare function parseReleaseControlLine(line: string): DaemonReleaseControl | null;
|
|
288
307
|
/** Exported for test stubs that need to bound the hello-line read. */
|
|
289
308
|
export { MAX_HELLO_LINE_BYTES };
|
|
290
309
|
//# sourceMappingURL=daemon.d.ts.map
|
package/dist/mcp/proxy.d.ts
CHANGED
|
@@ -58,6 +58,35 @@ export declare function runProxy(socketPath: string, expectedVersion?: string):
|
|
|
58
58
|
* owns the socket. Used by the local-handshake proxy's background connect.
|
|
59
59
|
*/
|
|
60
60
|
export declare function connectWithHello(socketPath: string, expectedVersion?: string): Promise<net.Socket | 'version-mismatch' | null>;
|
|
61
|
+
type JsonRpc = Record<string, unknown>;
|
|
62
|
+
type ProxyWrite = (obj: JsonRpc | string) => void;
|
|
63
|
+
/** Tracks request order across the proxy's pending-before-connect and in-flight phases. */
|
|
64
|
+
export declare class ProxyRequestBarrier {
|
|
65
|
+
private readonly pending;
|
|
66
|
+
private readonly inflight;
|
|
67
|
+
private readonly drainWaiters;
|
|
68
|
+
private track;
|
|
69
|
+
private requestId;
|
|
70
|
+
private resolveDrain;
|
|
71
|
+
buffer(line: string): void;
|
|
72
|
+
forward(line: string, send: (line: string) => void): void;
|
|
73
|
+
flush(send: (line: string) => void): void;
|
|
74
|
+
settle(id: unknown): void;
|
|
75
|
+
settleLine(line: string): void;
|
|
76
|
+
inflightLines(): string[];
|
|
77
|
+
pendingCount(): number;
|
|
78
|
+
inflightCount(): number;
|
|
79
|
+
drain(): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
/** Per-proxy barrier for intentional release of the project this session owns. */
|
|
82
|
+
export declare class ProxyReleaseCoordinator {
|
|
83
|
+
private readonly drainEarlierRequests;
|
|
84
|
+
private readonly entries;
|
|
85
|
+
private readonly sessionKey;
|
|
86
|
+
constructor(sessionRoot: string, drainEarlierRequests?: () => Promise<void>);
|
|
87
|
+
getState(root?: string): 'active' | 'releasing' | 'released';
|
|
88
|
+
handle(msg: JsonRpc, enabled: boolean, releaseProject: ((root: string) => Promise<unknown>) | undefined, write: ProxyWrite): boolean;
|
|
89
|
+
}
|
|
61
90
|
/** Dependencies the local-handshake proxy needs, injected by MCPServer (which
|
|
62
91
|
* owns the daemon-spawn machinery and the engine factory). */
|
|
63
92
|
export interface LocalHandshakeDeps {
|
|
@@ -69,6 +98,8 @@ export interface LocalHandshakeDeps {
|
|
|
69
98
|
makeEngine(): MCPEngine;
|
|
70
99
|
/** Project root for the fallback engine's lazy init. */
|
|
71
100
|
root: string;
|
|
101
|
+
/** Release one root locally so the proxy can suppress watchdog respawn first. */
|
|
102
|
+
releaseProject?(root: string): Promise<unknown>;
|
|
72
103
|
}
|
|
73
104
|
/**
|
|
74
105
|
* Local-handshake proxy (the cold-start fix).
|
|
@@ -84,4 +115,5 @@ export interface LocalHandshakeDeps {
|
|
|
84
115
|
* never costs the old fall-back-to-direct robustness.
|
|
85
116
|
*/
|
|
86
117
|
export declare function runLocalHandshakeProxy(deps: LocalHandshakeDeps): Promise<void>;
|
|
118
|
+
export {};
|
|
87
119
|
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -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
|
/**
|
package/dist/project-config.d.ts
CHANGED
|
@@ -46,6 +46,39 @@ export interface ProjectConfig {
|
|
|
46
46
|
* `true`.
|
|
47
47
|
*/
|
|
48
48
|
dysflowExport?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Extra receiver names that execute SQL, so table references inside the
|
|
51
|
+
* SQL they run are still found (#244). Two entry forms are accepted:
|
|
52
|
+
*
|
|
53
|
+
* - a bare identifier fragment — `"getdb"` reaches `getdb()`,
|
|
54
|
+
* `getdbHPS()` and `getdbExpedientes()`;
|
|
55
|
+
* - an explicit `receiver.method` pair — `"cnn.Execute"`.
|
|
56
|
+
*
|
|
57
|
+
* Raw regular expressions are deliberately NOT accepted: these patterns
|
|
58
|
+
* run against every line of every VBA file, where a user-supplied regex
|
|
59
|
+
* is a catastrophic-backtracking hazard. Entries EXTEND the built-in
|
|
60
|
+
* list (`db`, `getdb`, `CurrentDb`, `DBEngine`, the DAO `QueryDef`
|
|
61
|
+
* receivers, `DoCmd.RunSQL` and the ADO pair) — they never replace it.
|
|
62
|
+
* A non-array value, or an entry that is not one of the two forms,
|
|
63
|
+
* warns and is ignored.
|
|
64
|
+
*/
|
|
65
|
+
sqlWrappers?: string[];
|
|
66
|
+
/**
|
|
67
|
+
* Issue #261 — extra module-level variable names this project uses as its
|
|
68
|
+
* error channel: the field a failing procedure writes and its caller
|
|
69
|
+
* reads, which is how an error message actually travels in an Access
|
|
70
|
+
* codebase of this shape (VBA's own mechanism unwinds one frame and is
|
|
71
|
+
* used for that, not for the message).
|
|
72
|
+
*
|
|
73
|
+
* Bare VBA identifiers only, matched as WHOLE names — `"lastFailure"`
|
|
74
|
+
* flags `lastFailure` and never `lastFailureCount`. Raw regular
|
|
75
|
+
* expressions are deliberately NOT accepted, for the same reason
|
|
76
|
+
* `sqlWrappers` refuses them: these names are tested against every
|
|
77
|
+
* identifier of every line of every VBA file. Entries EXTEND the built-in
|
|
78
|
+
* list (`m_Error`, `p_Error`, `g_Error`, `Error`) — they never replace
|
|
79
|
+
* it. A non-array value, or a non-identifier entry, warns and is ignored.
|
|
80
|
+
*/
|
|
81
|
+
errorChannel?: string[];
|
|
49
82
|
};
|
|
50
83
|
/**
|
|
51
84
|
* Gitignore-style patterns for first-party source to force INTO the index even
|
|
@@ -62,11 +95,19 @@ export interface ProjectConfig {
|
|
|
62
95
|
*/
|
|
63
96
|
include?: string[];
|
|
64
97
|
}
|
|
65
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Parsed, validated view of the `vba` block. Named (rather than repeated
|
|
100
|
+
* inline at each of its five use sites) so adding a knob — `sqlWrappers` in
|
|
101
|
+
* #244 — is one edit instead of five that can silently drift apart.
|
|
102
|
+
*/
|
|
103
|
+
export interface VbaConfig {
|
|
66
104
|
targets?: Record<string, boolean>;
|
|
67
105
|
maxRaiseFanout?: number;
|
|
68
106
|
dysflowExport?: boolean;
|
|
69
|
-
|
|
107
|
+
sqlWrappers?: string[];
|
|
108
|
+
errorChannel?: string[];
|
|
109
|
+
}
|
|
110
|
+
export declare function loadVbaConfig(rootDir: string): VbaConfig;
|
|
70
111
|
/**
|
|
71
112
|
* Load the validated `vba.dysflowExport` flag for a project, mtime-cached
|
|
72
113
|
* (issue #154). Returns `true` when the flag is absent — the default keeps
|
|
@@ -302,10 +302,55 @@ export declare class ReferenceResolver {
|
|
|
302
302
|
* (enum, class, interface, struct, type_alias). Exactly one match →
|
|
303
303
|
* repoint; zero or 2+ → decline (leave the stub as-is).
|
|
304
304
|
*
|
|
305
|
-
* Duplicate `(source, target,
|
|
306
|
-
*
|
|
305
|
+
* Duplicate `(source, target, kind)` rows after repointing are collapsed the
|
|
306
|
+
* same way `resolveVbaCallStubs` handles F1 duplicates.
|
|
307
|
+
*
|
|
308
|
+
* Issue #257: `type_of` edges are repointed alongside `references` ones.
|
|
309
|
+
* They share the stub by construction (`emitTypeOf` and `emitReference` both
|
|
310
|
+
* go through `ensureSynthTypeNode`), and the stub is DELETED at the end of
|
|
311
|
+
* each iteration — with `ON DELETE CASCADE` on both endpoint columns, an
|
|
312
|
+
* un-repointed `type_of` edge would be silently destroyed rather than
|
|
313
|
+
* resolved. The de-duplication key carries the edge kind so a module's
|
|
314
|
+
* `references` edge and its parameter's `type_of` edge onto the same type
|
|
315
|
+
* cannot collapse into each other.
|
|
307
316
|
*/
|
|
308
317
|
resolveVbaReferenceStubs(): number;
|
|
318
|
+
/**
|
|
319
|
+
* Promote Access ERD table declarations to canonical and repoint the
|
|
320
|
+
* SQL-derived placeholders onto them (#257, half B).
|
|
321
|
+
*
|
|
322
|
+
* Two extractors already synthesize a `class` placeholder for every table
|
|
323
|
+
* name they see in SQL text (`vba-sql-table` from in-code SQL,
|
|
324
|
+
* `sql-query-table` from a saved query), each keyed on the REFERENCING file.
|
|
325
|
+
* `AccessErdExtractor` emits its own table node keyed on the ERD document.
|
|
326
|
+
* Left alone, `TbAnexos` from the ERD and `TbAnexos` from a `SELECT` in a
|
|
327
|
+
* `.cls` are two unrelated nodes — the fields land on one, the references on
|
|
328
|
+
* the other, and the whole feature buys nothing.
|
|
329
|
+
*
|
|
330
|
+
* This pass is the convergence step, and it reuses the mechanism
|
|
331
|
+
* `resolveVbaCallStubs` already proved: repoint the incoming edges onto the
|
|
332
|
+
* canonical node, collapse would-be duplicates, delete the emptied
|
|
333
|
+
* placeholder, and stamp `metadata.repointDecision` on every edge it touched
|
|
334
|
+
* so the outcome is auditable (same vocabulary as `docs/vba-stub-repoint-
|
|
335
|
+
* decision.md`).
|
|
336
|
+
*
|
|
337
|
+
* Three deliberate declines:
|
|
338
|
+
* - **No ERD declares this name** → leave the placeholder exactly as it is.
|
|
339
|
+
* That is the no-ERD project, and its behavior must not change at all.
|
|
340
|
+
* - **Two ERD files declare the same name** (two backends, same table) →
|
|
341
|
+
* `declined-ambiguous`. Repoint nothing and keep both declarations; which
|
|
342
|
+
* backend a bare `SELECT` meant is not something to guess.
|
|
343
|
+
* - **The placeholder still has other edges** → keep the node. Only a
|
|
344
|
+
* placeholder whose every edge has moved is deleted.
|
|
345
|
+
*
|
|
346
|
+
* Runs BEFORE `resolveVbaReferenceStubs` so this explicit, decision-stamping
|
|
347
|
+
* pass owns the outcome rather than the generic stub resolver silently
|
|
348
|
+
* arriving at half of it. Idempotent: a repointed placeholder is gone, so a
|
|
349
|
+
* second pass finds nothing to do.
|
|
350
|
+
*
|
|
351
|
+
* @returns the number of edges repointed onto an ERD table node.
|
|
352
|
+
*/
|
|
353
|
+
resolveAccessErdTableNodes(): number;
|
|
309
354
|
/**
|
|
310
355
|
* Resolve a single VBA call-stub node to its real target, or `null` when
|
|
311
356
|
* unresolvable/ambiguous. See `resolveVbaCallStubs` for the two-step
|
|
@@ -7,6 +7,31 @@ import { Node } from '../types';
|
|
|
7
7
|
import { UnresolvedRef, ResolvedRef, ResolutionContext } from './types';
|
|
8
8
|
/** Resolve Me.<Control> only inside the extractor-declared sibling layout. */
|
|
9
9
|
export declare function matchVbaMeControl(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a module-level variable read/write to that variable's node in
|
|
12
|
+
* the SAME file (issue #251).
|
|
13
|
+
*
|
|
14
|
+
* The binding is file-scoped and never falls through to global name
|
|
15
|
+
* matching. `m_count`, `strSQL` and `blnOk` are declared privately in
|
|
16
|
+
* dozens of modules of a typical Access project; a global match would
|
|
17
|
+
* pick one of them at random and claim a coupling between two modules
|
|
18
|
+
* that never reference each other. The extractor only emits these refs
|
|
19
|
+
* for names it already registered as module-level variables of the file
|
|
20
|
+
* being scanned, so the answer, when there is one, is always in that file.
|
|
21
|
+
*/
|
|
22
|
+
export declare function matchVbaModuleVariable(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null;
|
|
23
|
+
/**
|
|
24
|
+
* Issue #253: resolve a saved-query name to the `query` node that
|
|
25
|
+
* `SqlQueryExtractor` builds from `queries/<Name>.sql`.
|
|
26
|
+
*
|
|
27
|
+
* Query-kind only, and a miss DECLINES rather than falling through to global
|
|
28
|
+
* name matching. That is the whole point of the gate: a name matching neither
|
|
29
|
+
* a query nor a table must stay a `failed` reference, because a fallback that
|
|
30
|
+
* invented a table placeholder would turn "this query does not exist" into a
|
|
31
|
+
* confident, wrong answer — and a fallback to generic name matching could bind
|
|
32
|
+
* the name to an unrelated same-named class or procedure.
|
|
33
|
+
*/
|
|
34
|
+
export declare function matchVbaQueryName(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null;
|
|
10
35
|
/** Resolve Access SourceObject embeddings only to a unique real layout node. */
|
|
11
36
|
export declare function matchVbaSourceObject(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null;
|
|
12
37
|
/** Keep a layout's sibling-code binding from resolving back to the layout. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRuntimeObject as canonicalIsRuntimeObject } from '../extraction/vba/runtime-objects';
|
|
1
2
|
/**
|
|
2
3
|
* Canonical list of VBA/Access runtime objects and singletons whose
|
|
3
4
|
* `Receiver.Member` calls are NEVER user-defined code — DAO, FileSystemObject
|
|
@@ -18,14 +19,15 @@
|
|
|
18
19
|
* only falls back to this list when no real target exists, so a shadow
|
|
19
20
|
* declaration is repointed exactly like any other real symbol (FR-2.1).
|
|
20
21
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `
|
|
27
|
-
*
|
|
28
|
-
*
|
|
22
|
+
* Issue #245 — this used to be a SECOND literal, complementary to the VBA
|
|
23
|
+
* extractor's `RUNTIME_RECEIVER_BLACKLIST`. The two drifted: the extractor
|
|
24
|
+
* list omitted `VBA`, `fso`, `Collection` and `ListBox`, so those receivers
|
|
25
|
+
* kept synthesizing stub function NODES even though the resolver already
|
|
26
|
+
* declined their edges. Both sets now derive from one literal in
|
|
27
|
+
* `src/extraction/vba/runtime-objects.ts` (a leaf module — `src/extraction`
|
|
28
|
+
* must not import from `src/resolution`, so the canonical set lives on the
|
|
29
|
+
* extraction side and is re-exported here). Every existing
|
|
30
|
+
* `from '../src/resolution/vba-runtime-objects'` import keeps working.
|
|
29
31
|
*
|
|
30
32
|
* Entries are lowercased so matching is case-insensitive against a stub's
|
|
31
33
|
* receiver.
|
|
@@ -36,9 +38,7 @@ export declare const RUNTIME_OBJECTS: ReadonlySet<string>;
|
|
|
36
38
|
* Leading/trailing brackets and surrounding whitespace are stripped
|
|
37
39
|
* defensively so a bracketed receiver (`[DAO]`) still matches.
|
|
38
40
|
*/
|
|
39
|
-
export declare
|
|
40
|
-
/** Canonical VBA and Access built-in functions that never resolve to project code. */
|
|
41
|
-
export declare const VBA_STDLIB_FUNCTIONS: ReadonlySet<string>;
|
|
41
|
+
export declare const isRuntimeObject: typeof canonicalIsRuntimeObject;
|
|
42
42
|
export declare function isVbaStdlibFunction(name: string | null | undefined): boolean;
|
|
43
43
|
/**
|
|
44
44
|
* Issue #188 — VBA intrinsic constants and DAO enum values reach
|
package/dist/types.d.ts
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
* of truth backs both the TS type and any runtime validation
|
|
11
11
|
* (e.g. the search query parser).
|
|
12
12
|
*/
|
|
13
|
-
export declare const NODE_KINDS: readonly ["file", "module", "class", "struct", "interface", "trait", "protocol", "function", "method", "property", "field", "variable", "constant", "enum", "enum_member", "event", "type", "type_member", "declare", "type_alias", "namespace", "parameter", "import", "export", "route", "component", "query", "form-layout", "form-instance-control", "report-layout"];
|
|
13
|
+
export declare const NODE_KINDS: readonly ["file", "module", "class", "struct", "interface", "trait", "protocol", "function", "method", "property", "field", "variable", "constant", "enum", "enum_member", "event", "type", "type_member", "declare", "type_alias", "namespace", "parameter", "import", "export", "route", "component", "query", "form-layout", "form-instance-control", "report-layout", "label"];
|
|
14
14
|
export type NodeKind = (typeof NODE_KINDS)[number];
|
|
15
15
|
/**
|
|
16
16
|
* Types of edges (relationships) between nodes
|
|
17
17
|
*/
|
|
18
|
-
export type EdgeKind = 'contains' | 'calls' | 'imports' | 'exports' | 'extends' | 'implements' | 'references' | 'type_of' | 'returns' | 'instantiates' | 'overrides' | 'decorates' | 'event-handler' | 'opens-form' | 'opens-report' | 'raises-event' | 'subscribes-event' | 'type-member';
|
|
18
|
+
export type EdgeKind = 'contains' | 'calls' | 'imports' | 'exports' | 'extends' | 'implements' | 'references' | 'type_of' | 'returns' | 'instantiates' | 'overrides' | 'decorates' | 'event-handler' | 'opens-form' | 'opens-report' | 'raises-event' | 'subscribes-event' | 'type-member' | 'handles-error';
|
|
19
19
|
/**
|
|
20
20
|
* Supported programming languages. See NODE_KINDS for why this is a
|
|
21
21
|
* runtime-iterable const array.
|
|
@@ -175,7 +175,11 @@ export interface ExtractionError {
|
|
|
175
175
|
* layer. The legacy `EdgeKind` literal `'references'` is preserved as
|
|
176
176
|
* `references` here via `EdgeKind` — back-compat for any push site this
|
|
177
177
|
* round does not reclassify (e.g. the Implements emitter). New literals:
|
|
178
|
-
* - `calls` paren-form `Name(...)
|
|
178
|
+
* - `calls` paren-form `Name(...)`, or a statement-form Sub call
|
|
179
|
+
* whose syntax rules out a `Const` read (issue #265):
|
|
180
|
+
* `Call Escribir` (the `Call` keyword is only valid on
|
|
181
|
+
* a procedure) and `Escribir 1, 2` (a constant takes no
|
|
182
|
+
* argument list)
|
|
179
183
|
* - `qualified-call` `Receiver.Member(...)` (qualified-paren) or
|
|
180
184
|
* `Receiver.Member args` (qualified-statement)
|
|
181
185
|
* - `property-get` `Me.Name` (dot access, read)
|
|
@@ -183,9 +187,13 @@ export interface ExtractionError {
|
|
|
183
187
|
* - `bang-get` `Me!SubCtl` (bang read) or
|
|
184
188
|
* `Forms!FormX!Ctl` / `Forms("FormX")!Ctl` (cross-form)
|
|
185
189
|
* - `bang-set` `Me!SubCtl = value` (bang assignment)
|
|
186
|
-
* - `unqualified-ident` bare identifier
|
|
190
|
+
* - `unqualified-ident` bare identifier with no `(` after it, no `Call`
|
|
191
|
+
* keyword and no argument list; default for
|
|
187
192
|
* `HayErrorEnRiesgo`-style hits — Const-read takes
|
|
188
|
-
* priority via FR-3.1 disambiguation
|
|
193
|
+
* priority via FR-3.1 disambiguation. That shape is
|
|
194
|
+
* genuinely ambiguous between a no-argument Sub call
|
|
195
|
+
* and a `Const` read, which is why it stays here while
|
|
196
|
+
* the two unambiguous statement forms are `calls`
|
|
189
197
|
* - `member-with` `.Member` inside a `With <receiver>` block
|
|
190
198
|
* - `dao-query` `DoCmd.OpenQuery "X"` argument
|
|
191
199
|
* `dao-field-get` / `dao-field-set` are deliberately deferred to round-4.
|
|
@@ -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.0",
|
|
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.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"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"npm-shim.js",
|