@graphpilot-oss/graphpilot 0.0.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/.editorconfig +15 -0
- package/.github/CODEOWNERS +22 -0
- package/.github/FUNDING.yml +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- package/.github/dependabot.yml +15 -0
- package/.github/workflows/ci.yml +62 -0
- package/.github/workflows/release.yml +50 -0
- package/.prettierignore +19 -0
- package/.prettierrc.json +20 -0
- package/CHANGELOG.md +138 -0
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +111 -0
- package/LICENSE +201 -0
- package/README.md +132 -0
- package/SECURITY.md +44 -0
- package/assets/logo.png +0 -0
- package/assets/logo.svg +1 -0
- package/bench/README.md +544 -0
- package/bench/results/agent-tier-2026-05-22.md +28 -0
- package/bench/results/agent-tier-summary.md +44 -0
- package/bench/results/baseline-tier-2026-05-22.md +23 -0
- package/bench/results/baseline.json +810 -0
- package/bench/results/baseline.md +28 -0
- package/bench/run-agent-tier-automated.ts +234 -0
- package/bench/run-agent-tier.md +125 -0
- package/bench/run-baseline-tier.ts +200 -0
- package/bench/run.ts +210 -0
- package/bench/runner-baseline.ts +177 -0
- package/bench/runner-graphpilot.ts +131 -0
- package/bench/score-agent-tier.ts +191 -0
- package/bench/score.ts +59 -0
- package/bench/tasks.ts +236 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +162 -0
- package/dist/cli.js.map +1 -0
- package/dist/edges.d.ts +57 -0
- package/dist/edges.js +170 -0
- package/dist/edges.js.map +1 -0
- package/dist/git.d.ts +95 -0
- package/dist/git.js +247 -0
- package/dist/git.js.map +1 -0
- package/dist/graph-schema.d.ts +36 -0
- package/dist/graph-schema.js +208 -0
- package/dist/graph-schema.js.map +1 -0
- package/dist/impact.d.ts +99 -0
- package/dist/impact.js +123 -0
- package/dist/impact.js.map +1 -0
- package/dist/indexer.d.ts +28 -0
- package/dist/indexer.js +111 -0
- package/dist/indexer.js.map +1 -0
- package/dist/interactions.d.ts +46 -0
- package/dist/interactions.js +0 -0
- package/dist/interactions.js.map +1 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.js +567 -0
- package/dist/mcp.js.map +1 -0
- package/dist/parser.d.ts +24 -0
- package/dist/parser.js +128 -0
- package/dist/parser.js.map +1 -0
- package/dist/provenance.d.ts +74 -0
- package/dist/provenance.js +95 -0
- package/dist/provenance.js.map +1 -0
- package/dist/query.d.ts +68 -0
- package/dist/query.js +127 -0
- package/dist/query.js.map +1 -0
- package/dist/redact.d.ts +30 -0
- package/dist/redact.js +117 -0
- package/dist/redact.js.map +1 -0
- package/dist/storage.d.ts +42 -0
- package/dist/storage.js +85 -0
- package/dist/storage.js.map +1 -0
- package/dist/symbols.d.ts +20 -0
- package/dist/symbols.js +140 -0
- package/dist/symbols.js.map +1 -0
- package/dist/validation.d.ts +9 -0
- package/dist/validation.js +65 -0
- package/dist/validation.js.map +1 -0
- package/dist/validators.d.ts +55 -0
- package/dist/validators.js +205 -0
- package/dist/validators.js.map +1 -0
- package/dist/watcher.d.ts +86 -0
- package/dist/watcher.js +310 -0
- package/dist/watcher.js.map +1 -0
- package/docs/architecture.md +311 -0
- package/docs/limitations.md +156 -0
- package/docs/mcp-setup.md +231 -0
- package/docs/quickstart.md +202 -0
- package/eslint.config.js +148 -0
- package/lefthook.yml +81 -0
- package/package.json +56 -0
- package/pnpm-workspace.yaml +6 -0
- package/scripts/smoke-stdio.mjs +97 -0
- package/src/cli.ts +171 -0
- package/src/edges.ts +202 -0
- package/src/git.ts +255 -0
- package/src/graph-schema.ts +229 -0
- package/src/impact.ts +218 -0
- package/src/indexer.ts +152 -0
- package/src/interactions.ts +0 -0
- package/src/mcp.ts +652 -0
- package/src/parser.ts +138 -0
- package/src/provenance.ts +115 -0
- package/src/query.ts +148 -0
- package/src/redact.ts +122 -0
- package/src/storage.ts +115 -0
- package/src/symbols.ts +173 -0
- package/src/validation.ts +69 -0
- package/src/validators.ts +253 -0
- package/src/watcher.ts +383 -0
- package/tests/edges.test.ts +175 -0
- package/tests/fixtures/sample.ts +32 -0
- package/tests/git.test.ts +303 -0
- package/tests/graph-schema.test.ts +321 -0
- package/tests/impact.test.ts +454 -0
- package/tests/interactions.test.ts +180 -0
- package/tests/lint-policy.test.ts +106 -0
- package/tests/mcp-stdio.test.ts +171 -0
- package/tests/mcp.test.ts +335 -0
- package/tests/parser.test.ts +31 -0
- package/tests/provenance.test.ts +132 -0
- package/tests/query.test.ts +160 -0
- package/tests/redact.test.ts +167 -0
- package/tests/security.test.ts +144 -0
- package/tests/symbols.test.ts +78 -0
- package/tests/validators.test.ts +193 -0
- package/tests/watcher.test.ts +250 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch mode (A2) — keep the on-disk graph fresh as the user edits.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm per file event:
|
|
5
|
+
* 1. Remove all symbols + raw calls that came from this file
|
|
6
|
+
* 2. Re-parse the file, extract its symbols + raw calls
|
|
7
|
+
* 3. Re-resolve all raw calls against the full symbol table
|
|
8
|
+
* (cheap: under 50ms for a 2k-symbol repo)
|
|
9
|
+
* 4. Atomic save via storage.saveGraph (.tmp + rename)
|
|
10
|
+
*
|
|
11
|
+
* No schema change: rawCalls are reconstructed from existing edges on
|
|
12
|
+
* startup (every CallEdge carries fromId/toName/file/line/column, which
|
|
13
|
+
* is exactly the RawCall shape).
|
|
14
|
+
*
|
|
15
|
+
* Diagnostic lines go to stderr — never stdout — so stdin/stdout stays
|
|
16
|
+
* clean for any agent that's also reading the graph over MCP.
|
|
17
|
+
*/
|
|
18
|
+
import { type Graph } from './storage.js';
|
|
19
|
+
/** Per-event delta the watcher reports back to the caller (and to stderr). */
|
|
20
|
+
export interface UpdateResult {
|
|
21
|
+
file: string;
|
|
22
|
+
kind: 'add' | 'change' | 'delete';
|
|
23
|
+
symbolsBefore: number;
|
|
24
|
+
symbolsAfter: number;
|
|
25
|
+
edgesBefore: number;
|
|
26
|
+
edgesAfter: number;
|
|
27
|
+
durationMs: number;
|
|
28
|
+
}
|
|
29
|
+
export interface WatcherOptions {
|
|
30
|
+
/** Debounce window for editor "save in 3 syscalls" patterns. Default 100 ms. */
|
|
31
|
+
awaitStabilityMs?: number;
|
|
32
|
+
/** Logger for human-readable progress lines. Default: process.stderr. */
|
|
33
|
+
log?: (line: string) => void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Stateful watcher. Owns the in-memory Graph + raw calls and reconciles
|
|
37
|
+
* the on-disk graph.json on every event.
|
|
38
|
+
*
|
|
39
|
+
* Methods come in two flavours:
|
|
40
|
+
* - lifecycle: start / stop, drive chokidar
|
|
41
|
+
* - applyUpdate / applyDeletion: synchronous-style helpers that tests
|
|
42
|
+
* can call directly, bypassing chokidar (which is racy in tests)
|
|
43
|
+
*/
|
|
44
|
+
export declare class GraphWatcher {
|
|
45
|
+
readonly absRoot: string;
|
|
46
|
+
private graph;
|
|
47
|
+
private rawCalls;
|
|
48
|
+
private watcher;
|
|
49
|
+
private readonly log;
|
|
50
|
+
private readonly awaitStabilityMs;
|
|
51
|
+
/**
|
|
52
|
+
* Serializes the update queue so chokidar bursts (multiple `change`
|
|
53
|
+
* events in 200ms) don't race each other into a torn graph.
|
|
54
|
+
*/
|
|
55
|
+
private chain;
|
|
56
|
+
constructor(rawRoot: string, opts?: WatcherOptions);
|
|
57
|
+
/** Build a one-shot full index if no graph exists, then start the watcher. */
|
|
58
|
+
start(): Promise<void>;
|
|
59
|
+
stop(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Process a single file update. Public so tests can drive it directly
|
|
62
|
+
* without spawning chokidar.
|
|
63
|
+
*/
|
|
64
|
+
applyUpdate(absFilePath: string, kind?: 'add' | 'change'): Promise<UpdateResult | null>;
|
|
65
|
+
/** Drop everything that came from a deleted file. */
|
|
66
|
+
applyDeletion(absFilePath: string): Promise<UpdateResult | null>;
|
|
67
|
+
/** Force a full re-index from scratch. Used on startup if no graph exists. */
|
|
68
|
+
fullReindex(): Promise<void>;
|
|
69
|
+
/** Read-only accessor, mainly for tests + diagnostics. */
|
|
70
|
+
get currentGraph(): Graph;
|
|
71
|
+
/**
|
|
72
|
+
* Chain updates so chokidar's burst events don't run in parallel. Errors
|
|
73
|
+
* are logged but never abort the chain — the next event still runs.
|
|
74
|
+
*/
|
|
75
|
+
private enqueue;
|
|
76
|
+
private handleEvent;
|
|
77
|
+
private handleDeletion;
|
|
78
|
+
/**
|
|
79
|
+
* Apply a new (symbols, rawCalls) state: re-resolve edges, update the
|
|
80
|
+
* graph object, save atomically.
|
|
81
|
+
*/
|
|
82
|
+
private commitState;
|
|
83
|
+
private finalize;
|
|
84
|
+
private deriveRawCalls;
|
|
85
|
+
private deltaStr;
|
|
86
|
+
}
|
package/dist/watcher.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch mode (A2) — keep the on-disk graph fresh as the user edits.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm per file event:
|
|
5
|
+
* 1. Remove all symbols + raw calls that came from this file
|
|
6
|
+
* 2. Re-parse the file, extract its symbols + raw calls
|
|
7
|
+
* 3. Re-resolve all raw calls against the full symbol table
|
|
8
|
+
* (cheap: under 50ms for a 2k-symbol repo)
|
|
9
|
+
* 4. Atomic save via storage.saveGraph (.tmp + rename)
|
|
10
|
+
*
|
|
11
|
+
* No schema change: rawCalls are reconstructed from existing edges on
|
|
12
|
+
* startup (every CallEdge carries fromId/toName/file/line/column, which
|
|
13
|
+
* is exactly the RawCall shape).
|
|
14
|
+
*
|
|
15
|
+
* Diagnostic lines go to stderr — never stdout — so stdin/stdout stays
|
|
16
|
+
* clean for any agent that's also reading the graph over MCP.
|
|
17
|
+
*/
|
|
18
|
+
import chokidar from 'chokidar';
|
|
19
|
+
import { realpathSync } from 'node:fs';
|
|
20
|
+
import { resolve, relative } from 'node:path';
|
|
21
|
+
import { parseFile } from './parser.js';
|
|
22
|
+
import { extractSymbols } from './symbols.js';
|
|
23
|
+
import { extractRawCalls, resolveCallEdges } from './edges.js';
|
|
24
|
+
import { saveGraph, loadGraph, repoIdFor } from './storage.js';
|
|
25
|
+
import { readGitInfo } from './git.js';
|
|
26
|
+
import { indexDirectory } from './indexer.js';
|
|
27
|
+
import { validateRootPath, MAX_FILES_PER_INDEX } from './validation.js';
|
|
28
|
+
const DEFAULT_IGNORE = [
|
|
29
|
+
/(^|[/\\])\.git([/\\]|$)/,
|
|
30
|
+
/(^|[/\\])node_modules([/\\]|$)/,
|
|
31
|
+
/(^|[/\\])dist([/\\]|$)/,
|
|
32
|
+
/(^|[/\\])build([/\\]|$)/,
|
|
33
|
+
/(^|[/\\])coverage([/\\]|$)/,
|
|
34
|
+
/(^|[/\\])\.next([/\\]|$)/,
|
|
35
|
+
/(^|[/\\])\.nuxt([/\\]|$)/,
|
|
36
|
+
/(^|[/\\])\.cache([/\\]|$)/,
|
|
37
|
+
/(^|[/\\])out([/\\]|$)/,
|
|
38
|
+
/\.d\.ts$/,
|
|
39
|
+
];
|
|
40
|
+
const WATCHED_EXT = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
|
|
41
|
+
function isWatchableFile(absPath) {
|
|
42
|
+
const dot = absPath.lastIndexOf('.');
|
|
43
|
+
if (dot === -1)
|
|
44
|
+
return false;
|
|
45
|
+
return WATCHED_EXT.has(absPath.slice(dot).toLowerCase());
|
|
46
|
+
}
|
|
47
|
+
function defaultLogger(line) {
|
|
48
|
+
process.stderr.write(`[graphpilot:watch] ${line}\n`);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Stateful watcher. Owns the in-memory Graph + raw calls and reconciles
|
|
52
|
+
* the on-disk graph.json on every event.
|
|
53
|
+
*
|
|
54
|
+
* Methods come in two flavours:
|
|
55
|
+
* - lifecycle: start / stop, drive chokidar
|
|
56
|
+
* - applyUpdate / applyDeletion: synchronous-style helpers that tests
|
|
57
|
+
* can call directly, bypassing chokidar (which is racy in tests)
|
|
58
|
+
*/
|
|
59
|
+
export class GraphWatcher {
|
|
60
|
+
absRoot;
|
|
61
|
+
graph;
|
|
62
|
+
rawCalls;
|
|
63
|
+
watcher = null;
|
|
64
|
+
log;
|
|
65
|
+
awaitStabilityMs;
|
|
66
|
+
/**
|
|
67
|
+
* Serializes the update queue so chokidar bursts (multiple `change`
|
|
68
|
+
* events in 200ms) don't race each other into a torn graph.
|
|
69
|
+
*/
|
|
70
|
+
chain = Promise.resolve();
|
|
71
|
+
constructor(rawRoot, opts = {}) {
|
|
72
|
+
this.absRoot = resolve(rawRoot);
|
|
73
|
+
this.log = opts.log ?? defaultLogger;
|
|
74
|
+
this.awaitStabilityMs = opts.awaitStabilityMs ?? 100;
|
|
75
|
+
const refusal = validateRootPath(this.absRoot);
|
|
76
|
+
if (refusal)
|
|
77
|
+
throw new Error(refusal);
|
|
78
|
+
// Defence-in-depth realpath check (T2): make sure the user-given path
|
|
79
|
+
// resolves to a real directory. We do NOT overwrite this.absRoot with
|
|
80
|
+
// the canonical form — that would break the path → repoId hash and
|
|
81
|
+
// cause the watcher to read+write a different graph.json than `index`.
|
|
82
|
+
realpathSync(this.absRoot);
|
|
83
|
+
const loaded = loadGraph(this.absRoot);
|
|
84
|
+
if (loaded) {
|
|
85
|
+
this.graph = loaded;
|
|
86
|
+
this.rawCalls = this.deriveRawCalls(loaded.edges);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// No existing index — caller is expected to `start()`, which will
|
|
90
|
+
// build one. We initialize empty here so applyUpdate is safe to call
|
|
91
|
+
// pre-start in tests.
|
|
92
|
+
this.graph = {
|
|
93
|
+
version: 1,
|
|
94
|
+
repoId: repoIdFor(this.absRoot),
|
|
95
|
+
rootPath: this.absRoot,
|
|
96
|
+
indexedAt: new Date().toISOString(),
|
|
97
|
+
filesIndexed: 0,
|
|
98
|
+
symbolCount: 0,
|
|
99
|
+
edgeCount: 0,
|
|
100
|
+
symbols: [],
|
|
101
|
+
edges: [],
|
|
102
|
+
};
|
|
103
|
+
this.rawCalls = [];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Build a one-shot full index if no graph exists, then start the watcher. */
|
|
107
|
+
async start() {
|
|
108
|
+
if (this.graph.symbols.length === 0) {
|
|
109
|
+
this.log(`No existing index. Running full index of ${this.absRoot} ...`);
|
|
110
|
+
await this.fullReindex();
|
|
111
|
+
}
|
|
112
|
+
this.log(`Watching ${this.absRoot} ` +
|
|
113
|
+
`(${this.graph.symbols.length} symbols, ${this.graph.edges.length} calls, ` +
|
|
114
|
+
`${this.graph.filesIndexed} files). Edit a file to see updates.`);
|
|
115
|
+
this.watcher = chokidar.watch(this.absRoot, {
|
|
116
|
+
ignored: DEFAULT_IGNORE,
|
|
117
|
+
ignoreInitial: true, // we already have a graph
|
|
118
|
+
persistent: true,
|
|
119
|
+
followSymlinks: false,
|
|
120
|
+
awaitWriteFinish: {
|
|
121
|
+
stabilityThreshold: this.awaitStabilityMs,
|
|
122
|
+
pollInterval: 50,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
this.watcher.on('add', (abs) => this.enqueue(() => this.handleEvent(abs, 'add')));
|
|
126
|
+
this.watcher.on('change', (abs) => this.enqueue(() => this.handleEvent(abs, 'change')));
|
|
127
|
+
this.watcher.on('unlink', (abs) => this.enqueue(() => this.handleDeletion(abs)));
|
|
128
|
+
this.watcher.on('error', (err) => this.log(`watcher error: ${String(err)}`));
|
|
129
|
+
}
|
|
130
|
+
async stop() {
|
|
131
|
+
if (this.watcher) {
|
|
132
|
+
await this.watcher.close();
|
|
133
|
+
this.watcher = null;
|
|
134
|
+
}
|
|
135
|
+
await this.chain;
|
|
136
|
+
this.log('Stopped.');
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Process a single file update. Public so tests can drive it directly
|
|
140
|
+
* without spawning chokidar.
|
|
141
|
+
*/
|
|
142
|
+
async applyUpdate(absFilePath, kind = 'change') {
|
|
143
|
+
if (!isWatchableFile(absFilePath))
|
|
144
|
+
return null;
|
|
145
|
+
if (!absFilePath.startsWith(this.absRoot))
|
|
146
|
+
return null;
|
|
147
|
+
const start = Date.now();
|
|
148
|
+
const rel = relative(this.absRoot, absFilePath);
|
|
149
|
+
const symbolsBefore = this.graph.symbols.length;
|
|
150
|
+
const edgesBefore = this.graph.edges.length;
|
|
151
|
+
// 1. Remove existing symbols + raw calls from this file
|
|
152
|
+
const keptSymbols = this.graph.symbols.filter((s) => s.file !== rel);
|
|
153
|
+
const keptRawCalls = this.rawCalls.filter((c) => c.file !== rel);
|
|
154
|
+
// 2. Parse the new content + extract
|
|
155
|
+
const parsed = parseFile(absFilePath);
|
|
156
|
+
if (!parsed) {
|
|
157
|
+
// Could not parse (too large, unknown ext, gone, etc.) — treat as a
|
|
158
|
+
// deletion of that file's contribution. Keeps the index honest.
|
|
159
|
+
this.commitState(keptSymbols, keptRawCalls);
|
|
160
|
+
const result = this.finalize(rel, kind, symbolsBefore, edgesBefore, start);
|
|
161
|
+
this.log(`${rel} unparseable; dropped ${symbolsBefore - keptSymbols.length} symbols (${result.durationMs}ms).`);
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
const fileSymbols = extractSymbols(parsed);
|
|
165
|
+
const fileCalls = extractRawCalls(parsed, fileSymbols);
|
|
166
|
+
// 3. Normalize paths + rewrite ids to relative form (same as indexer.ts)
|
|
167
|
+
const idRewrites = new Map();
|
|
168
|
+
for (const s of fileSymbols) {
|
|
169
|
+
const oldId = s.id;
|
|
170
|
+
s.file = rel;
|
|
171
|
+
s.id = oldId.replace(absFilePath, rel);
|
|
172
|
+
idRewrites.set(oldId, s.id);
|
|
173
|
+
}
|
|
174
|
+
for (const c of fileCalls) {
|
|
175
|
+
c.file = rel;
|
|
176
|
+
c.fromId = idRewrites.get(c.fromId) ?? c.fromId;
|
|
177
|
+
}
|
|
178
|
+
const newSymbols = [...keptSymbols, ...fileSymbols];
|
|
179
|
+
const newRawCalls = [...keptRawCalls, ...fileCalls];
|
|
180
|
+
// 4. Re-resolve every edge against the new symbol table. Cheap.
|
|
181
|
+
this.commitState(newSymbols, newRawCalls);
|
|
182
|
+
const result = this.finalize(rel, kind, symbolsBefore, edgesBefore, start);
|
|
183
|
+
this.log(`${rel}: ${this.deltaStr(symbolsBefore, result.symbolsAfter)} symbols, ` +
|
|
184
|
+
`${this.deltaStr(edgesBefore, result.edgesAfter)} calls (${result.durationMs}ms).`);
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
/** Drop everything that came from a deleted file. */
|
|
188
|
+
async applyDeletion(absFilePath) {
|
|
189
|
+
if (!absFilePath.startsWith(this.absRoot))
|
|
190
|
+
return null;
|
|
191
|
+
const start = Date.now();
|
|
192
|
+
const rel = relative(this.absRoot, absFilePath);
|
|
193
|
+
const symbolsBefore = this.graph.symbols.length;
|
|
194
|
+
const edgesBefore = this.graph.edges.length;
|
|
195
|
+
const keptSymbols = this.graph.symbols.filter((s) => s.file !== rel);
|
|
196
|
+
const keptRawCalls = this.rawCalls.filter((c) => c.file !== rel);
|
|
197
|
+
// No change? File wasn't in the index, ignore.
|
|
198
|
+
if (keptSymbols.length === this.graph.symbols.length &&
|
|
199
|
+
keptRawCalls.length === this.rawCalls.length) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
this.commitState(keptSymbols, keptRawCalls);
|
|
203
|
+
const result = this.finalize(rel, 'delete', symbolsBefore, edgesBefore, start);
|
|
204
|
+
this.log(`${rel} deleted: ${this.deltaStr(symbolsBefore, result.symbolsAfter)} symbols, ` +
|
|
205
|
+
`${this.deltaStr(edgesBefore, result.edgesAfter)} calls (${result.durationMs}ms).`);
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
/** Force a full re-index from scratch. Used on startup if no graph exists. */
|
|
209
|
+
async fullReindex() {
|
|
210
|
+
const result = await indexDirectory(this.absRoot);
|
|
211
|
+
if (result.symbols.length > MAX_FILES_PER_INDEX) {
|
|
212
|
+
throw new Error('Refusing to watch: index would exceed MAX_FILES_PER_INDEX.');
|
|
213
|
+
}
|
|
214
|
+
this.graph = {
|
|
215
|
+
version: 1,
|
|
216
|
+
repoId: repoIdFor(this.absRoot),
|
|
217
|
+
rootPath: this.absRoot,
|
|
218
|
+
indexedAt: new Date().toISOString(),
|
|
219
|
+
filesIndexed: result.filesIndexed,
|
|
220
|
+
symbolCount: result.symbols.length,
|
|
221
|
+
edgeCount: result.edges.length,
|
|
222
|
+
symbols: result.symbols,
|
|
223
|
+
edges: result.edges,
|
|
224
|
+
indexedSha: result.git.sha,
|
|
225
|
+
indexedBranch: result.git.branch,
|
|
226
|
+
};
|
|
227
|
+
this.rawCalls = this.deriveRawCalls(result.edges);
|
|
228
|
+
saveGraph(this.graph);
|
|
229
|
+
}
|
|
230
|
+
/** Read-only accessor, mainly for tests + diagnostics. */
|
|
231
|
+
get currentGraph() {
|
|
232
|
+
return this.graph;
|
|
233
|
+
}
|
|
234
|
+
// -------------------------------------------------------------------------
|
|
235
|
+
// internals
|
|
236
|
+
// -------------------------------------------------------------------------
|
|
237
|
+
/**
|
|
238
|
+
* Chain updates so chokidar's burst events don't run in parallel. Errors
|
|
239
|
+
* are logged but never abort the chain — the next event still runs.
|
|
240
|
+
*/
|
|
241
|
+
enqueue(work) {
|
|
242
|
+
this.chain = this.chain.then(() => work().catch((err) => {
|
|
243
|
+
this.log(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
244
|
+
}), () => undefined);
|
|
245
|
+
}
|
|
246
|
+
async handleEvent(abs, kind) {
|
|
247
|
+
if (!isWatchableFile(abs))
|
|
248
|
+
return;
|
|
249
|
+
await this.applyUpdate(abs, kind);
|
|
250
|
+
}
|
|
251
|
+
async handleDeletion(abs) {
|
|
252
|
+
await this.applyDeletion(abs);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Apply a new (symbols, rawCalls) state: re-resolve edges, update the
|
|
256
|
+
* graph object, save atomically.
|
|
257
|
+
*/
|
|
258
|
+
commitState(symbols, rawCalls) {
|
|
259
|
+
const edges = resolveCallEdges(rawCalls, symbols);
|
|
260
|
+
// Recompute filesIndexed from surviving symbols' files.
|
|
261
|
+
const files = new Set();
|
|
262
|
+
for (const s of symbols)
|
|
263
|
+
files.add(s.file);
|
|
264
|
+
// Re-read git info on every commit — branch / sha can change between
|
|
265
|
+
// edits (e.g. user did `git checkout` mid-session) and we want the
|
|
266
|
+
// graph stamped with the *current* state. Cheap: a few fs reads.
|
|
267
|
+
const git = readGitInfo(this.absRoot);
|
|
268
|
+
this.graph = {
|
|
269
|
+
...this.graph,
|
|
270
|
+
indexedAt: new Date().toISOString(),
|
|
271
|
+
filesIndexed: files.size,
|
|
272
|
+
symbolCount: symbols.length,
|
|
273
|
+
edgeCount: edges.length,
|
|
274
|
+
symbols,
|
|
275
|
+
edges,
|
|
276
|
+
indexedSha: git.sha,
|
|
277
|
+
indexedBranch: git.branch,
|
|
278
|
+
};
|
|
279
|
+
this.rawCalls = rawCalls;
|
|
280
|
+
saveGraph(this.graph);
|
|
281
|
+
}
|
|
282
|
+
finalize(file, kind, symbolsBefore, edgesBefore, start) {
|
|
283
|
+
return {
|
|
284
|
+
file,
|
|
285
|
+
kind,
|
|
286
|
+
symbolsBefore,
|
|
287
|
+
symbolsAfter: this.graph.symbols.length,
|
|
288
|
+
edgesBefore,
|
|
289
|
+
edgesAfter: this.graph.edges.length,
|
|
290
|
+
durationMs: Date.now() - start,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
deriveRawCalls(edges) {
|
|
294
|
+
return edges.map((e) => ({
|
|
295
|
+
fromId: e.fromId,
|
|
296
|
+
toName: e.toName,
|
|
297
|
+
file: e.file,
|
|
298
|
+
line: e.line,
|
|
299
|
+
column: e.column,
|
|
300
|
+
}));
|
|
301
|
+
}
|
|
302
|
+
deltaStr(before, after) {
|
|
303
|
+
const delta = after - before;
|
|
304
|
+
if (delta === 0)
|
|
305
|
+
return `${after} (=)`;
|
|
306
|
+
const sign = delta > 0 ? '+' : '';
|
|
307
|
+
return `${after} (${sign}${delta})`;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"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"}
|