@colbymchenry/codegraph-darwin-arm64 0.9.3 → 0.9.5
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/lib/dist/bin/codegraph.d.ts +3 -0
- package/lib/dist/bin/codegraph.d.ts.map +1 -1
- package/lib/dist/bin/codegraph.js +250 -0
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/context/index.d.ts +13 -0
- package/lib/dist/context/index.d.ts.map +1 -1
- package/lib/dist/context/index.js +120 -1
- package/lib/dist/context/index.js.map +1 -1
- package/lib/dist/db/index.d.ts +18 -0
- package/lib/dist/db/index.d.ts.map +1 -1
- package/lib/dist/db/index.js +31 -0
- package/lib/dist/db/index.js.map +1 -1
- package/lib/dist/db/queries.d.ts +16 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +80 -27
- package/lib/dist/db/queries.js.map +1 -1
- package/lib/dist/extraction/grammars.d.ts +6 -0
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +31 -1
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +15 -2
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js +170 -78
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/languages/index.d.ts.map +1 -1
- package/lib/dist/extraction/languages/index.js +2 -0
- package/lib/dist/extraction/languages/index.js.map +1 -1
- package/lib/dist/extraction/languages/objc.d.ts +3 -0
- package/lib/dist/extraction/languages/objc.d.ts.map +1 -0
- package/lib/dist/extraction/languages/objc.js +133 -0
- package/lib/dist/extraction/languages/objc.js.map +1 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts +4 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +155 -9
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/extraction/wasm-runtime-flags.d.ts +12 -0
- package/lib/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/lib/dist/extraction/wasm-runtime-flags.js +14 -2
- package/lib/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/lib/dist/graph/traversal.d.ts.map +1 -1
- package/lib/dist/graph/traversal.js +71 -36
- package/lib/dist/graph/traversal.js.map +1 -1
- package/lib/dist/index.d.ts +21 -2
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +42 -0
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/instructions-template.d.ts +2 -2
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +3 -2
- package/lib/dist/installer/instructions-template.js.map +1 -1
- package/lib/dist/mcp/daemon-paths.d.ts +46 -0
- package/lib/dist/mcp/daemon-paths.d.ts.map +1 -0
- package/lib/dist/mcp/daemon-paths.js +125 -0
- package/lib/dist/mcp/daemon-paths.js.map +1 -0
- package/lib/dist/mcp/daemon.d.ts +161 -0
- package/lib/dist/mcp/daemon.d.ts.map +1 -0
- package/lib/dist/mcp/daemon.js +403 -0
- package/lib/dist/mcp/daemon.js.map +1 -0
- package/lib/dist/mcp/engine.d.ts +100 -0
- package/lib/dist/mcp/engine.d.ts.map +1 -0
- package/lib/dist/mcp/engine.js +291 -0
- package/lib/dist/mcp/engine.js.map +1 -0
- package/lib/dist/mcp/index.d.ts +67 -52
- package/lib/dist/mcp/index.d.ts.map +1 -1
- package/lib/dist/mcp/index.js +347 -330
- package/lib/dist/mcp/index.js.map +1 -1
- package/lib/dist/mcp/proxy.d.ts +46 -0
- package/lib/dist/mcp/proxy.d.ts.map +1 -0
- package/lib/dist/mcp/proxy.js +276 -0
- package/lib/dist/mcp/proxy.js.map +1 -0
- package/lib/dist/mcp/server-instructions.d.ts +1 -1
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +3 -1
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/session.d.ts +67 -0
- package/lib/dist/mcp/session.d.ts.map +1 -0
- package/lib/dist/mcp/session.js +276 -0
- package/lib/dist/mcp/session.js.map +1 -0
- package/lib/dist/mcp/tools.d.ts +130 -2
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +902 -37
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/mcp/transport.d.ts +111 -29
- package/lib/dist/mcp/transport.d.ts.map +1 -1
- package/lib/dist/mcp/transport.js +181 -71
- package/lib/dist/mcp/transport.js.map +1 -1
- package/lib/dist/mcp/version.d.ts +19 -0
- package/lib/dist/mcp/version.d.ts.map +1 -0
- package/lib/dist/mcp/version.js +71 -0
- package/lib/dist/mcp/version.js.map +1 -0
- package/lib/dist/resolution/callback-synthesizer.d.ts +10 -0
- package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -0
- package/lib/dist/resolution/callback-synthesizer.js +847 -0
- package/lib/dist/resolution/callback-synthesizer.js.map +1 -0
- package/lib/dist/resolution/frameworks/csharp.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/csharp.js +36 -8
- package/lib/dist/resolution/frameworks/csharp.js.map +1 -1
- package/lib/dist/resolution/frameworks/drupal.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/drupal.js +44 -12
- package/lib/dist/resolution/frameworks/drupal.js.map +1 -1
- package/lib/dist/resolution/frameworks/expo-modules.d.ts +3 -0
- package/lib/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/expo-modules.js +143 -0
- package/lib/dist/resolution/frameworks/expo-modules.js.map +1 -0
- package/lib/dist/resolution/frameworks/express.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/express.js +102 -19
- package/lib/dist/resolution/frameworks/express.js.map +1 -1
- package/lib/dist/resolution/frameworks/fabric.d.ts +3 -0
- package/lib/dist/resolution/frameworks/fabric.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/fabric.js +354 -0
- package/lib/dist/resolution/frameworks/fabric.js.map +1 -0
- package/lib/dist/resolution/frameworks/go.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/go.js +6 -3
- package/lib/dist/resolution/frameworks/go.js.map +1 -1
- package/lib/dist/resolution/frameworks/index.d.ts +5 -0
- package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/index.js +25 -1
- package/lib/dist/resolution/frameworks/index.js.map +1 -1
- package/lib/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/java.js +70 -12
- package/lib/dist/resolution/frameworks/java.js.map +1 -1
- package/lib/dist/resolution/frameworks/laravel.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/laravel.js +17 -8
- package/lib/dist/resolution/frameworks/laravel.js.map +1 -1
- package/lib/dist/resolution/frameworks/play.d.ts +19 -0
- package/lib/dist/resolution/frameworks/play.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/play.js +111 -0
- package/lib/dist/resolution/frameworks/play.js.map +1 -0
- package/lib/dist/resolution/frameworks/python.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/python.js +134 -16
- package/lib/dist/resolution/frameworks/python.js.map +1 -1
- package/lib/dist/resolution/frameworks/react-native.d.ts +3 -0
- package/lib/dist/resolution/frameworks/react-native.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/react-native.js +360 -0
- package/lib/dist/resolution/frameworks/react-native.js.map +1 -0
- package/lib/dist/resolution/frameworks/react.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/react.js +96 -3
- package/lib/dist/resolution/frameworks/react.js.map +1 -1
- package/lib/dist/resolution/frameworks/ruby.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/ruby.js +106 -2
- package/lib/dist/resolution/frameworks/ruby.js.map +1 -1
- package/lib/dist/resolution/frameworks/rust.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/rust.js +102 -5
- package/lib/dist/resolution/frameworks/rust.js.map +1 -1
- package/lib/dist/resolution/frameworks/swift-objc.d.ts +37 -0
- package/lib/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/swift-objc.js +252 -0
- package/lib/dist/resolution/frameworks/swift-objc.js.map +1 -0
- package/lib/dist/resolution/frameworks/swift.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/swift.js +30 -6
- package/lib/dist/resolution/frameworks/swift.js.map +1 -1
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +1 -0
- package/lib/dist/resolution/import-resolver.js.map +1 -1
- package/lib/dist/resolution/index.d.ts.map +1 -1
- package/lib/dist/resolution/index.js +61 -9
- package/lib/dist/resolution/index.js.map +1 -1
- package/lib/dist/resolution/lru-cache.d.ts +24 -0
- package/lib/dist/resolution/lru-cache.d.ts.map +1 -0
- package/lib/dist/resolution/lru-cache.js +62 -0
- package/lib/dist/resolution/lru-cache.js.map +1 -0
- package/lib/dist/resolution/swift-objc-bridge.d.ts +134 -0
- package/lib/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
- package/lib/dist/resolution/swift-objc-bridge.js +256 -0
- package/lib/dist/resolution/swift-objc-bridge.js.map +1 -0
- package/lib/dist/resolution/types.d.ts +8 -0
- package/lib/dist/resolution/types.d.ts.map +1 -1
- package/lib/dist/sync/index.d.ts +3 -1
- package/lib/dist/sync/index.d.ts.map +1 -1
- package/lib/dist/sync/index.js +7 -1
- package/lib/dist/sync/index.js.map +1 -1
- package/lib/dist/sync/watcher.d.ts +109 -7
- package/lib/dist/sync/watcher.d.ts.map +1 -1
- package/lib/dist/sync/watcher.js +215 -33
- package/lib/dist/sync/watcher.js.map +1 -1
- package/lib/dist/sync/worktree.d.ts +54 -0
- package/lib/dist/sync/worktree.d.ts.map +1 -0
- package/lib/dist/sync/worktree.js +136 -0
- package/lib/dist/sync/worktree.js.map +1 -0
- package/lib/dist/types.d.ts +1 -1
- package/lib/dist/types.d.ts.map +1 -1
- package/lib/dist/types.js +1 -0
- package/lib/dist/types.js.map +1 -1
- package/lib/dist/utils.js +1 -1
- package/lib/node_modules/.package-lock.json +29 -1
- package/lib/node_modules/chokidar/LICENSE +21 -0
- package/lib/node_modules/chokidar/README.md +305 -0
- package/lib/node_modules/chokidar/esm/handler.d.ts +90 -0
- package/lib/node_modules/chokidar/esm/handler.js +629 -0
- package/lib/node_modules/chokidar/esm/index.d.ts +215 -0
- package/lib/node_modules/chokidar/esm/index.js +798 -0
- package/lib/node_modules/chokidar/esm/package.json +1 -0
- package/lib/node_modules/chokidar/handler.d.ts +90 -0
- package/lib/node_modules/chokidar/handler.js +635 -0
- package/lib/node_modules/chokidar/index.d.ts +215 -0
- package/lib/node_modules/chokidar/index.js +804 -0
- package/lib/node_modules/chokidar/package.json +69 -0
- package/lib/node_modules/readdirp/LICENSE +21 -0
- package/lib/node_modules/readdirp/README.md +120 -0
- package/lib/node_modules/readdirp/esm/index.d.ts +108 -0
- package/lib/node_modules/readdirp/esm/index.js +257 -0
- package/lib/node_modules/readdirp/esm/package.json +1 -0
- package/lib/node_modules/readdirp/index.d.ts +108 -0
- package/lib/node_modules/readdirp/index.js +263 -0
- package/lib/node_modules/readdirp/package.json +70 -0
- package/lib/package.json +2 -1
- package/package.json +1 -1
package/lib/dist/sync/index.d.ts
CHANGED
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
* - FileWatcher: Debounced fs.watch that auto-triggers sync on file changes
|
|
9
9
|
* - Watch policy: decides when the watcher must be disabled (e.g. WSL2 /mnt)
|
|
10
10
|
* - Git sync hooks: opt-in commit/merge/checkout hooks when watching is off
|
|
11
|
+
* - Git worktree awareness: detect when a query borrows another tree's index
|
|
11
12
|
* - Content hashing for change detection (in extraction module)
|
|
12
13
|
* - Incremental reindexing (in extraction module)
|
|
13
14
|
*/
|
|
14
|
-
export { FileWatcher, WatchOptions } from './watcher';
|
|
15
|
+
export { FileWatcher, WatchOptions, PendingFile } from './watcher';
|
|
15
16
|
export { watchDisabledReason, detectWsl } from './watch-policy';
|
|
16
17
|
export { installGitSyncHook, removeGitSyncHook, isSyncHookInstalled, isGitRepo, DEFAULT_SYNC_HOOKS, type GitHookName, type GitHookResult, } from './git-hooks';
|
|
18
|
+
export { gitWorktreeRoot, detectWorktreeIndexMismatch, worktreeMismatchWarning, worktreeMismatchNotice, type WorktreeIndexMismatch, } from './worktree';
|
|
17
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,uBAAuB,EACvB,sBAAsB,EACtB,KAAK,qBAAqB,GAC3B,MAAM,YAAY,CAAC"}
|
package/lib/dist/sync/index.js
CHANGED
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* - FileWatcher: Debounced fs.watch that auto-triggers sync on file changes
|
|
10
10
|
* - Watch policy: decides when the watcher must be disabled (e.g. WSL2 /mnt)
|
|
11
11
|
* - Git sync hooks: opt-in commit/merge/checkout hooks when watching is off
|
|
12
|
+
* - Git worktree awareness: detect when a query borrows another tree's index
|
|
12
13
|
* - Content hashing for change detection (in extraction module)
|
|
13
14
|
* - Incremental reindexing (in extraction module)
|
|
14
15
|
*/
|
|
15
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.DEFAULT_SYNC_HOOKS = exports.isGitRepo = exports.isSyncHookInstalled = exports.removeGitSyncHook = exports.installGitSyncHook = exports.detectWsl = exports.watchDisabledReason = exports.FileWatcher = void 0;
|
|
17
|
+
exports.worktreeMismatchNotice = exports.worktreeMismatchWarning = exports.detectWorktreeIndexMismatch = exports.gitWorktreeRoot = exports.DEFAULT_SYNC_HOOKS = exports.isGitRepo = exports.isSyncHookInstalled = exports.removeGitSyncHook = exports.installGitSyncHook = exports.detectWsl = exports.watchDisabledReason = exports.FileWatcher = void 0;
|
|
17
18
|
var watcher_1 = require("./watcher");
|
|
18
19
|
Object.defineProperty(exports, "FileWatcher", { enumerable: true, get: function () { return watcher_1.FileWatcher; } });
|
|
19
20
|
var watch_policy_1 = require("./watch-policy");
|
|
@@ -25,4 +26,9 @@ Object.defineProperty(exports, "removeGitSyncHook", { enumerable: true, get: fun
|
|
|
25
26
|
Object.defineProperty(exports, "isSyncHookInstalled", { enumerable: true, get: function () { return git_hooks_1.isSyncHookInstalled; } });
|
|
26
27
|
Object.defineProperty(exports, "isGitRepo", { enumerable: true, get: function () { return git_hooks_1.isGitRepo; } });
|
|
27
28
|
Object.defineProperty(exports, "DEFAULT_SYNC_HOOKS", { enumerable: true, get: function () { return git_hooks_1.DEFAULT_SYNC_HOOKS; } });
|
|
29
|
+
var worktree_1 = require("./worktree");
|
|
30
|
+
Object.defineProperty(exports, "gitWorktreeRoot", { enumerable: true, get: function () { return worktree_1.gitWorktreeRoot; } });
|
|
31
|
+
Object.defineProperty(exports, "detectWorktreeIndexMismatch", { enumerable: true, get: function () { return worktree_1.detectWorktreeIndexMismatch; } });
|
|
32
|
+
Object.defineProperty(exports, "worktreeMismatchWarning", { enumerable: true, get: function () { return worktree_1.worktreeMismatchWarning; } });
|
|
33
|
+
Object.defineProperty(exports, "worktreeMismatchNotice", { enumerable: true, get: function () { return worktree_1.worktreeMismatchNotice; } });
|
|
28
34
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAEH,qCAAmE;AAA1D,sGAAA,WAAW,OAAA;AACpB,+CAAgE;AAAvD,mHAAA,mBAAmB,OAAA;AAAE,yGAAA,SAAS,OAAA;AACvC,yCAQqB;AAPnB,+GAAA,kBAAkB,OAAA;AAClB,8GAAA,iBAAiB,OAAA;AACjB,gHAAA,mBAAmB,OAAA;AACnB,sGAAA,SAAS,OAAA;AACT,+GAAA,kBAAkB,OAAA;AAIpB,uCAMoB;AALlB,2GAAA,eAAe,OAAA;AACf,uHAAA,2BAA2B,OAAA;AAC3B,mHAAA,uBAAuB,OAAA;AACvB,kHAAA,sBAAsB,OAAA"}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File Watcher
|
|
3
3
|
*
|
|
4
|
-
* Watches the project directory for file changes and triggers
|
|
5
|
-
*
|
|
4
|
+
* Watches the project directory for file changes and triggers debounced sync
|
|
5
|
+
* operations to keep the code graph up-to-date.
|
|
6
6
|
*
|
|
7
|
-
* Uses
|
|
8
|
-
*
|
|
7
|
+
* Uses chokidar, whose `ignored` callback filters directories BEFORE they are
|
|
8
|
+
* watched — so we never register inotify watches on excluded trees like
|
|
9
|
+
* node_modules/, dist/, .git/ (fixes #276: recursive fs.watch exhausted the
|
|
10
|
+
* kernel watch budget on large repos). The ignore decision reuses the indexer's
|
|
11
|
+
* `buildDefaultIgnore` (built-in default-ignore dirs + the project's .gitignore)
|
|
12
|
+
* so the watcher watches exactly the set the indexer indexes — in particular,
|
|
13
|
+
* node_modules/build/cache dirs are excluded even when the repo has no
|
|
14
|
+
* .gitignore (#407), which a .gitignore-only filter would miss.
|
|
9
15
|
*/
|
|
10
16
|
/**
|
|
11
17
|
* Options for the file watcher
|
|
@@ -29,22 +35,73 @@ export interface WatchOptions {
|
|
|
29
35
|
*/
|
|
30
36
|
onSyncError?: (error: Error) => void;
|
|
31
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Per-file pending entry — tracks a source file the watcher saw an event for
|
|
40
|
+
* but hasn't yet synced into the index. Exposed via {@link FileWatcher.getPendingFiles}
|
|
41
|
+
* so MCP tool responses can mark stale results without forcing a wait.
|
|
42
|
+
*/
|
|
43
|
+
export interface PendingFile {
|
|
44
|
+
/** Project-relative POSIX path (e.g. "src/foo.ts"). */
|
|
45
|
+
path: string;
|
|
46
|
+
/** Wall-clock ms at the first event we saw for this path since the last sync. */
|
|
47
|
+
firstSeenMs: number;
|
|
48
|
+
/** Wall-clock ms at the most recent event we saw for this path. */
|
|
49
|
+
lastSeenMs: number;
|
|
50
|
+
/**
|
|
51
|
+
* True when a sync is currently in flight that began AFTER this file's most
|
|
52
|
+
* recent event — i.e. the next successful sync will pick it up. False when
|
|
53
|
+
* the file is still in the debounce window (no sync running yet).
|
|
54
|
+
*/
|
|
55
|
+
indexing: boolean;
|
|
56
|
+
}
|
|
32
57
|
/**
|
|
33
58
|
* FileWatcher monitors a project directory for changes and triggers
|
|
34
59
|
* debounced sync operations via a provided callback.
|
|
35
60
|
*
|
|
36
61
|
* Design goals:
|
|
37
|
-
* - Minimal resource usage (
|
|
62
|
+
* - Minimal resource usage (chokidar filters excluded directories before
|
|
63
|
+
* registering an inotify watch — see module docs / #276)
|
|
38
64
|
* - Debounced to avoid thrashing on rapid saves
|
|
39
65
|
* - Filters to supported source files by extension
|
|
40
|
-
* - Ignores .codegraph/
|
|
66
|
+
* - Ignores .codegraph/ and .git/ regardless of .gitignore
|
|
67
|
+
* - Tracks per-file pending state so MCP tools can flag stale results
|
|
68
|
+
* without blocking on a sync (issue #403)
|
|
41
69
|
*/
|
|
42
70
|
export declare class FileWatcher {
|
|
43
71
|
private watcher;
|
|
44
72
|
private debounceTimer;
|
|
45
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Files seen by the watcher since the last successful sync — populated on
|
|
75
|
+
* every chokidar event, cleared at the start of a sync, and re-populated by
|
|
76
|
+
* events that arrive mid-sync (or restored on sync failure). Keyed by the
|
|
77
|
+
* same project-relative POSIX path the rest of the codebase uses, so a
|
|
78
|
+
* caller can intersect tool-response file paths against this map cheaply.
|
|
79
|
+
*/
|
|
80
|
+
private pendingFiles;
|
|
81
|
+
/**
|
|
82
|
+
* Wall-clock ms at which the in-flight sync began. Combined with
|
|
83
|
+
* {@link pendingFiles}'s `lastSeenMs`, this distinguishes "still in the
|
|
84
|
+
* debounce window" (lastSeen > syncStarted, sync hasn't started yet for
|
|
85
|
+
* this edit) from "currently being indexed" (lastSeen <= syncStarted).
|
|
86
|
+
*/
|
|
87
|
+
private syncStartedMs;
|
|
46
88
|
private syncing;
|
|
47
89
|
private stopped;
|
|
90
|
+
/**
|
|
91
|
+
* False until chokidar fires its `ready` event. Gates `pendingFiles`
|
|
92
|
+
* insertion so the initial crawl's `add` events (one per pre-existing
|
|
93
|
+
* source file) don't pollute the per-file staleness signal. The events
|
|
94
|
+
* still flow into `scheduleSync()` to preserve the previous "initial
|
|
95
|
+
* scan triggers a reconciling sync" behavior.
|
|
96
|
+
*/
|
|
97
|
+
private chokidarReady;
|
|
98
|
+
/**
|
|
99
|
+
* Callbacks that resolve when chokidar fires `ready`. Used by tests (and
|
|
100
|
+
* any production caller that cares about a clean baseline) to deterministically
|
|
101
|
+
* gate on the end of the initial scan instead of guessing at a sleep duration.
|
|
102
|
+
*/
|
|
103
|
+
private readyWaiters;
|
|
104
|
+
private ignoreMatcher;
|
|
48
105
|
private readonly projectRoot;
|
|
49
106
|
private readonly debounceMs;
|
|
50
107
|
private readonly syncFn;
|
|
@@ -59,6 +116,14 @@ export declare class FileWatcher {
|
|
|
59
116
|
* Returns true if watching started successfully, false otherwise.
|
|
60
117
|
*/
|
|
61
118
|
start(): boolean;
|
|
119
|
+
/** Our own dirs are always ignored, regardless of .gitignore. */
|
|
120
|
+
private isAlwaysIgnored;
|
|
121
|
+
/**
|
|
122
|
+
* chokidar `ignored` predicate — true for any path that should NOT be watched.
|
|
123
|
+
* Uses chokidar's provided `stats` to decide directory-vs-file so a dir-only
|
|
124
|
+
* rule like `build/` matches, without an extra `statSync` per path.
|
|
125
|
+
*/
|
|
126
|
+
private shouldIgnore;
|
|
62
127
|
/**
|
|
63
128
|
* Stop watching for file changes.
|
|
64
129
|
*/
|
|
@@ -67,13 +132,50 @@ export declare class FileWatcher {
|
|
|
67
132
|
* Whether the watcher is currently active.
|
|
68
133
|
*/
|
|
69
134
|
isActive(): boolean;
|
|
135
|
+
/**
|
|
136
|
+
* Resolves once chokidar has fired its `ready` event (or immediately if
|
|
137
|
+
* it has already done so). Useful for tests that need a deterministic
|
|
138
|
+
* boundary before asserting on `pendingFiles` — guessing a sleep duration
|
|
139
|
+
* is flaky under load because chokidar can take longer than expected to
|
|
140
|
+
* finish its initial crawl on slow filesystems / parallel test runs.
|
|
141
|
+
*
|
|
142
|
+
* Production callers don't need this: `pendingFiles` is read continuously,
|
|
143
|
+
* the staleness banner is always correct (empty or populated), and the
|
|
144
|
+
* initial-scan window is a small one-time startup cost.
|
|
145
|
+
*/
|
|
146
|
+
waitUntilReady(timeoutMs?: number): Promise<void>;
|
|
70
147
|
/**
|
|
71
148
|
* Schedule a debounced sync.
|
|
72
149
|
*/
|
|
73
150
|
private scheduleSync;
|
|
74
151
|
/**
|
|
75
152
|
* Flush pending changes by running sync.
|
|
153
|
+
*
|
|
154
|
+
* pendingFiles is NOT cleared at the start of sync — entries are removed
|
|
155
|
+
* only after sync commits successfully, and only for entries whose
|
|
156
|
+
* lastSeenMs <= syncStartedMs. That way, a query that arrives mid-sync
|
|
157
|
+
* still sees the affected files marked stale (the DB hasn't been updated
|
|
158
|
+
* yet), and an event that lands mid-sync persists into the follow-up.
|
|
159
|
+
*
|
|
160
|
+
* On sync failure pendingFiles is left untouched — every edit is still
|
|
161
|
+
* unindexed, and the rescheduled sync will absorb the same set next time.
|
|
76
162
|
*/
|
|
77
163
|
private flush;
|
|
164
|
+
/**
|
|
165
|
+
* Snapshot of files seen by the watcher since the last successful sync.
|
|
166
|
+
*
|
|
167
|
+
* Used by MCP tool responses to mark stale results without blocking on a
|
|
168
|
+
* sync: a tool that returns a hit in `src/foo.ts` while `src/foo.ts` is in
|
|
169
|
+
* this list tells the agent "Read this file directly, the index lags."
|
|
170
|
+
*
|
|
171
|
+
* `indexing` is true when a sync is currently in flight whose start time is
|
|
172
|
+
* AFTER this file's most recent event — i.e. that sync will absorb the
|
|
173
|
+
* edit. False means the file is still inside the debounce window and no
|
|
174
|
+
* sync has started yet (a follow-up call a few hundred ms later may show
|
|
175
|
+
* `indexing: true` or the file may have left the list entirely).
|
|
176
|
+
*
|
|
177
|
+
* Cheap: O(pendingFiles.size), no I/O, no locks.
|
|
178
|
+
*/
|
|
179
|
+
getPendingFiles(): PendingFile[];
|
|
78
180
|
}
|
|
79
181
|
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAEhF;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,aAAa,CAA8C;IACnE;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAkE;IACtF;;;;;OAKG;IACH,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB;;;;;;OAMG;IACH,OAAO,CAAC,aAAa,CAAS;IAC9B;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAAyB;IAI7C,OAAO,CAAC,aAAa,CAAuB;IAE5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8D;IACrF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAiC;IACjE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAA8B;gBAGzD,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,EACnE,OAAO,GAAE,YAAiB;IAS5B;;;OAGG;IACH,KAAK,IAAI,OAAO;IAuFhB,iEAAiE;IACjE,OAAO,CAAC,eAAe;IAOvB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACH,IAAI,IAAI,IAAI;IAmBZ;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,SAAS,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAahD;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;;;;;;;;OAWG;YACW,KAAK;IAuCnB;;;;;;;;;;;;;;OAcG;IACH,eAAe,IAAI,WAAW,EAAE;CAYjC"}
|
package/lib/dist/sync/watcher.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* File Watcher
|
|
4
4
|
*
|
|
5
|
-
* Watches the project directory for file changes and triggers
|
|
6
|
-
*
|
|
5
|
+
* Watches the project directory for file changes and triggers debounced sync
|
|
6
|
+
* operations to keep the code graph up-to-date.
|
|
7
7
|
*
|
|
8
|
-
* Uses
|
|
9
|
-
*
|
|
8
|
+
* Uses chokidar, whose `ignored` callback filters directories BEFORE they are
|
|
9
|
+
* watched — so we never register inotify watches on excluded trees like
|
|
10
|
+
* node_modules/, dist/, .git/ (fixes #276: recursive fs.watch exhausted the
|
|
11
|
+
* kernel watch budget on large repos). The ignore decision reuses the indexer's
|
|
12
|
+
* `buildDefaultIgnore` (built-in default-ignore dirs + the project's .gitignore)
|
|
13
|
+
* so the watcher watches exactly the set the indexer indexes — in particular,
|
|
14
|
+
* node_modules/build/cache dirs are excluded even when the repo has no
|
|
15
|
+
* .gitignore (#407), which a .gitignore-only filter would miss.
|
|
10
16
|
*/
|
|
11
17
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
18
|
if (k2 === undefined) k2 = k;
|
|
@@ -41,9 +47,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
47
|
return result;
|
|
42
48
|
};
|
|
43
49
|
})();
|
|
50
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
51
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
52
|
+
};
|
|
44
53
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
54
|
exports.FileWatcher = void 0;
|
|
46
|
-
const
|
|
55
|
+
const path = __importStar(require("path"));
|
|
56
|
+
const chokidar_1 = __importDefault(require("chokidar"));
|
|
47
57
|
const extraction_1 = require("../extraction");
|
|
48
58
|
const errors_1 = require("../errors");
|
|
49
59
|
const utils_1 = require("../utils");
|
|
@@ -53,17 +63,52 @@ const watch_policy_1 = require("./watch-policy");
|
|
|
53
63
|
* debounced sync operations via a provided callback.
|
|
54
64
|
*
|
|
55
65
|
* Design goals:
|
|
56
|
-
* - Minimal resource usage (
|
|
66
|
+
* - Minimal resource usage (chokidar filters excluded directories before
|
|
67
|
+
* registering an inotify watch — see module docs / #276)
|
|
57
68
|
* - Debounced to avoid thrashing on rapid saves
|
|
58
69
|
* - Filters to supported source files by extension
|
|
59
|
-
* - Ignores .codegraph/
|
|
70
|
+
* - Ignores .codegraph/ and .git/ regardless of .gitignore
|
|
71
|
+
* - Tracks per-file pending state so MCP tools can flag stale results
|
|
72
|
+
* without blocking on a sync (issue #403)
|
|
60
73
|
*/
|
|
61
74
|
class FileWatcher {
|
|
62
75
|
watcher = null;
|
|
63
76
|
debounceTimer = null;
|
|
64
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Files seen by the watcher since the last successful sync — populated on
|
|
79
|
+
* every chokidar event, cleared at the start of a sync, and re-populated by
|
|
80
|
+
* events that arrive mid-sync (or restored on sync failure). Keyed by the
|
|
81
|
+
* same project-relative POSIX path the rest of the codebase uses, so a
|
|
82
|
+
* caller can intersect tool-response file paths against this map cheaply.
|
|
83
|
+
*/
|
|
84
|
+
pendingFiles = new Map();
|
|
85
|
+
/**
|
|
86
|
+
* Wall-clock ms at which the in-flight sync began. Combined with
|
|
87
|
+
* {@link pendingFiles}'s `lastSeenMs`, this distinguishes "still in the
|
|
88
|
+
* debounce window" (lastSeen > syncStarted, sync hasn't started yet for
|
|
89
|
+
* this edit) from "currently being indexed" (lastSeen <= syncStarted).
|
|
90
|
+
*/
|
|
91
|
+
syncStartedMs = 0;
|
|
65
92
|
syncing = false;
|
|
66
93
|
stopped = false;
|
|
94
|
+
/**
|
|
95
|
+
* False until chokidar fires its `ready` event. Gates `pendingFiles`
|
|
96
|
+
* insertion so the initial crawl's `add` events (one per pre-existing
|
|
97
|
+
* source file) don't pollute the per-file staleness signal. The events
|
|
98
|
+
* still flow into `scheduleSync()` to preserve the previous "initial
|
|
99
|
+
* scan triggers a reconciling sync" behavior.
|
|
100
|
+
*/
|
|
101
|
+
chokidarReady = false;
|
|
102
|
+
/**
|
|
103
|
+
* Callbacks that resolve when chokidar fires `ready`. Used by tests (and
|
|
104
|
+
* any production caller that cares about a clean baseline) to deterministically
|
|
105
|
+
* gate on the end of the initial scan instead of guessing at a sleep duration.
|
|
106
|
+
*/
|
|
107
|
+
readyWaiters = [];
|
|
108
|
+
// The shared ignore matcher (built-in defaults + project .gitignore), built
|
|
109
|
+
// once at start(). Same source of truth the indexer uses, so watcher scope
|
|
110
|
+
// can never diverge from index scope.
|
|
111
|
+
ignoreMatcher = null;
|
|
67
112
|
projectRoot;
|
|
68
113
|
debounceMs;
|
|
69
114
|
syncFn;
|
|
@@ -84,49 +129,108 @@ class FileWatcher {
|
|
|
84
129
|
if (this.watcher)
|
|
85
130
|
return true; // Already watching
|
|
86
131
|
this.stopped = false;
|
|
87
|
-
// Some environments make
|
|
88
|
-
// /mnt/ drives, where
|
|
89
|
-
// handshakes (issue #199). Skip watching
|
|
90
|
-
// manual `codegraph sync` or
|
|
132
|
+
// Some environments make filesystem watching unusable — most notably
|
|
133
|
+
// WSL2 /mnt/ drives, where the underlying fs.watch calls block long
|
|
134
|
+
// enough to break MCP startup handshakes (issue #199). Skip watching
|
|
135
|
+
// there; callers fall back to manual `codegraph sync` or git sync hooks.
|
|
91
136
|
const disabledReason = (0, watch_policy_1.watchDisabledReason)(this.projectRoot);
|
|
92
137
|
if (disabledReason) {
|
|
93
138
|
(0, errors_1.logDebug)('File watcher disabled', { reason: disabledReason, projectRoot: this.projectRoot });
|
|
94
139
|
return false;
|
|
95
140
|
}
|
|
141
|
+
// Reuse the indexer's ignore set so the watcher and indexer agree on scope.
|
|
142
|
+
// chokidar only registers an inotify watch on directories that pass this
|
|
143
|
+
// filter — that's the #276 fix.
|
|
144
|
+
this.ignoreMatcher = (0, extraction_1.buildDefaultIgnore)(this.projectRoot);
|
|
96
145
|
try {
|
|
97
|
-
this.watcher =
|
|
98
|
-
|
|
146
|
+
this.watcher = chokidar_1.default.watch(this.projectRoot, {
|
|
147
|
+
// chokidar calls this for every path it encounters and only watches
|
|
148
|
+
// those that pass — so excluded trees (node_modules/, dist/, .git/, …)
|
|
149
|
+
// never get an inotify watch in the first place.
|
|
150
|
+
ignored: (testPath, stats) => this.shouldIgnore(testPath, stats),
|
|
151
|
+
});
|
|
152
|
+
// Chokidar emits `add` for every pre-existing source file during its
|
|
153
|
+
// initial scan. Those events should still trigger the post-startup
|
|
154
|
+
// reconciling sync (preserving prior behavior), but they must NOT land
|
|
155
|
+
// in pendingFiles — otherwise every file in the project shows up as
|
|
156
|
+
// "edited but not indexed" on startup, which is the opposite of the
|
|
157
|
+
// signal #403 is supposed to provide. Flip the flag on chokidar's
|
|
158
|
+
// `ready` event; from then on, real edits populate pendingFiles.
|
|
159
|
+
//
|
|
160
|
+
// We also clear `pendingFiles` here as defense-in-depth: chokidar can
|
|
161
|
+
// emit late initial-scan `add` events via setImmediate AFTER the
|
|
162
|
+
// `ready` callback runs (observed under test-parallelism load).
|
|
163
|
+
// Clearing once at ready guarantees a clean baseline; real subsequent
|
|
164
|
+
// edits repopulate the set normally.
|
|
165
|
+
this.watcher.on('ready', () => {
|
|
166
|
+
this.chokidarReady = true;
|
|
167
|
+
this.pendingFiles.clear();
|
|
168
|
+
for (const cb of this.readyWaiters)
|
|
169
|
+
cb();
|
|
170
|
+
this.readyWaiters.length = 0;
|
|
171
|
+
});
|
|
172
|
+
// chokidar emits 'all' for every event type; we only sync source files.
|
|
173
|
+
this.watcher.on('all', (_event, filePath) => {
|
|
174
|
+
if (this.stopped)
|
|
99
175
|
return;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
//
|
|
103
|
-
if (normalized
|
|
104
|
-
normalized.startsWith('.codegraph/') ||
|
|
105
|
-
normalized.startsWith('.codegraph\\')) {
|
|
176
|
+
const normalized = (0, utils_1.normalizePath)(path.relative(this.projectRoot, filePath));
|
|
177
|
+
// Defense in depth: `ignored` should already keep these out, but events
|
|
178
|
+
// can still arrive during setup or via symlink traversal.
|
|
179
|
+
if (this.isAlwaysIgnored(normalized))
|
|
106
180
|
return;
|
|
107
|
-
|
|
108
|
-
// Only sync changes to files we can actually parse.
|
|
109
|
-
if (!(0, extraction_1.isSourceFile)(normalized)) {
|
|
181
|
+
if (!(0, extraction_1.isSourceFile)(normalized))
|
|
110
182
|
return;
|
|
111
|
-
}
|
|
112
183
|
(0, errors_1.logDebug)('File change detected', { file: normalized });
|
|
113
|
-
|
|
184
|
+
// Only track events from after chokidar's initial scan as pending
|
|
185
|
+
// edits — pre-existing files on disk are already represented by
|
|
186
|
+
// (or about to be reconciled by) the index, not a user edit.
|
|
187
|
+
if (this.chokidarReady) {
|
|
188
|
+
const now = Date.now();
|
|
189
|
+
const existing = this.pendingFiles.get(normalized);
|
|
190
|
+
this.pendingFiles.set(normalized, {
|
|
191
|
+
firstSeenMs: existing?.firstSeenMs ?? now,
|
|
192
|
+
lastSeenMs: now,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
114
195
|
this.scheduleSync();
|
|
115
196
|
});
|
|
116
|
-
// Handle watcher errors gracefully
|
|
197
|
+
// Handle watcher errors gracefully — don't crash, the user can restart.
|
|
117
198
|
this.watcher.on('error', (err) => {
|
|
118
199
|
(0, errors_1.logWarn)('File watcher error', { error: String(err) });
|
|
119
|
-
// Don't crash — watcher may recover or user can restart
|
|
120
200
|
});
|
|
121
201
|
(0, errors_1.logDebug)('File watcher started', { projectRoot: this.projectRoot, debounceMs: this.debounceMs });
|
|
122
202
|
return true;
|
|
123
203
|
}
|
|
124
204
|
catch (err) {
|
|
125
|
-
//
|
|
126
|
-
(0, errors_1.logWarn)('Could not start file watcher
|
|
205
|
+
// Watcher setup failed (e.g., permission denied, missing directory).
|
|
206
|
+
(0, errors_1.logWarn)('Could not start file watcher', { error: String(err) });
|
|
127
207
|
return false;
|
|
128
208
|
}
|
|
129
209
|
}
|
|
210
|
+
/** Our own dirs are always ignored, regardless of .gitignore. */
|
|
211
|
+
isAlwaysIgnored(rel) {
|
|
212
|
+
return (rel === '.codegraph' || rel.startsWith('.codegraph/') ||
|
|
213
|
+
rel === '.git' || rel.startsWith('.git/'));
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* chokidar `ignored` predicate — true for any path that should NOT be watched.
|
|
217
|
+
* Uses chokidar's provided `stats` to decide directory-vs-file so a dir-only
|
|
218
|
+
* rule like `build/` matches, without an extra `statSync` per path.
|
|
219
|
+
*/
|
|
220
|
+
shouldIgnore(testPath, stats) {
|
|
221
|
+
const rel = (0, utils_1.normalizePath)(path.relative(this.projectRoot, testPath));
|
|
222
|
+
if (!rel || rel === '.' || rel.startsWith('..'))
|
|
223
|
+
return false; // root / outside
|
|
224
|
+
if (this.isAlwaysIgnored(rel))
|
|
225
|
+
return true;
|
|
226
|
+
if (!this.ignoreMatcher)
|
|
227
|
+
return false;
|
|
228
|
+
if (stats) {
|
|
229
|
+
return this.ignoreMatcher.ignores(stats.isDirectory() ? rel + '/' : rel);
|
|
230
|
+
}
|
|
231
|
+
// Stats unknown: test both forms so a directory match isn't missed.
|
|
232
|
+
return this.ignoreMatcher.ignores(rel) || this.ignoreMatcher.ignores(rel + '/');
|
|
233
|
+
}
|
|
130
234
|
/**
|
|
131
235
|
* Stop watching for file changes.
|
|
132
236
|
*/
|
|
@@ -140,7 +244,9 @@ class FileWatcher {
|
|
|
140
244
|
this.watcher.close();
|
|
141
245
|
this.watcher = null;
|
|
142
246
|
}
|
|
143
|
-
this.
|
|
247
|
+
this.pendingFiles.clear();
|
|
248
|
+
this.chokidarReady = false;
|
|
249
|
+
this.ignoreMatcher = null;
|
|
144
250
|
(0, errors_1.logDebug)('File watcher stopped');
|
|
145
251
|
}
|
|
146
252
|
/**
|
|
@@ -149,6 +255,31 @@ class FileWatcher {
|
|
|
149
255
|
isActive() {
|
|
150
256
|
return this.watcher !== null && !this.stopped;
|
|
151
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* Resolves once chokidar has fired its `ready` event (or immediately if
|
|
260
|
+
* it has already done so). Useful for tests that need a deterministic
|
|
261
|
+
* boundary before asserting on `pendingFiles` — guessing a sleep duration
|
|
262
|
+
* is flaky under load because chokidar can take longer than expected to
|
|
263
|
+
* finish its initial crawl on slow filesystems / parallel test runs.
|
|
264
|
+
*
|
|
265
|
+
* Production callers don't need this: `pendingFiles` is read continuously,
|
|
266
|
+
* the staleness banner is always correct (empty or populated), and the
|
|
267
|
+
* initial-scan window is a small one-time startup cost.
|
|
268
|
+
*/
|
|
269
|
+
waitUntilReady(timeoutMs = 10000) {
|
|
270
|
+
if (this.chokidarReady)
|
|
271
|
+
return Promise.resolve();
|
|
272
|
+
return new Promise((resolve, reject) => {
|
|
273
|
+
const t = setTimeout(() => {
|
|
274
|
+
const idx = this.readyWaiters.indexOf(handler);
|
|
275
|
+
if (idx >= 0)
|
|
276
|
+
this.readyWaiters.splice(idx, 1);
|
|
277
|
+
reject(new Error(`FileWatcher.waitUntilReady timed out after ${timeoutMs}ms`));
|
|
278
|
+
}, timeoutMs);
|
|
279
|
+
const handler = () => { clearTimeout(t); resolve(); };
|
|
280
|
+
this.readyWaiters.push(handler);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
152
283
|
/**
|
|
153
284
|
* Schedule a debounced sync.
|
|
154
285
|
*/
|
|
@@ -163,30 +294,81 @@ class FileWatcher {
|
|
|
163
294
|
}
|
|
164
295
|
/**
|
|
165
296
|
* Flush pending changes by running sync.
|
|
297
|
+
*
|
|
298
|
+
* pendingFiles is NOT cleared at the start of sync — entries are removed
|
|
299
|
+
* only after sync commits successfully, and only for entries whose
|
|
300
|
+
* lastSeenMs <= syncStartedMs. That way, a query that arrives mid-sync
|
|
301
|
+
* still sees the affected files marked stale (the DB hasn't been updated
|
|
302
|
+
* yet), and an event that lands mid-sync persists into the follow-up.
|
|
303
|
+
*
|
|
304
|
+
* On sync failure pendingFiles is left untouched — every edit is still
|
|
305
|
+
* unindexed, and the rescheduled sync will absorb the same set next time.
|
|
166
306
|
*/
|
|
167
307
|
async flush() {
|
|
168
308
|
// If already syncing, the post-sync check will re-trigger
|
|
169
309
|
if (this.syncing || this.stopped)
|
|
170
310
|
return;
|
|
171
|
-
this.
|
|
311
|
+
this.syncStartedMs = Date.now();
|
|
172
312
|
this.syncing = true;
|
|
173
313
|
try {
|
|
174
314
|
const result = await this.syncFn();
|
|
315
|
+
// Remove entries whose most recent event predates this sync — those
|
|
316
|
+
// edits are now in the DB. Entries with lastSeenMs > syncStartedMs
|
|
317
|
+
// arrived mid-sync; whether the in-flight sync captured them depends
|
|
318
|
+
// on when sync read that file, so we keep them as pending and let
|
|
319
|
+
// the follow-up sync handle them. We prefer false positives ("shown
|
|
320
|
+
// stale, actually fresh" → at worst one extra Read) over false
|
|
321
|
+
// negatives ("shown fresh, actually stale" → misleads the agent).
|
|
322
|
+
for (const [filePath, info] of this.pendingFiles) {
|
|
323
|
+
if (info.lastSeenMs <= this.syncStartedMs) {
|
|
324
|
+
this.pendingFiles.delete(filePath);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
175
327
|
this.onSyncComplete?.(result);
|
|
176
328
|
}
|
|
177
329
|
catch (err) {
|
|
178
330
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
179
331
|
(0, errors_1.logWarn)('Watch sync failed', { error: error.message });
|
|
332
|
+
// Failure: leave pendingFiles untouched. Every edit it tracks is
|
|
333
|
+
// still unindexed; the rescheduled sync sees the same set.
|
|
180
334
|
this.onSyncError?.(error);
|
|
181
335
|
}
|
|
182
336
|
finally {
|
|
183
337
|
this.syncing = false;
|
|
184
|
-
// If
|
|
185
|
-
|
|
338
|
+
// If pending files remain (mid-sync events, or this sync failed),
|
|
339
|
+
// schedule another pass.
|
|
340
|
+
if (this.pendingFiles.size > 0 && !this.stopped) {
|
|
186
341
|
this.scheduleSync();
|
|
187
342
|
}
|
|
188
343
|
}
|
|
189
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Snapshot of files seen by the watcher since the last successful sync.
|
|
347
|
+
*
|
|
348
|
+
* Used by MCP tool responses to mark stale results without blocking on a
|
|
349
|
+
* sync: a tool that returns a hit in `src/foo.ts` while `src/foo.ts` is in
|
|
350
|
+
* this list tells the agent "Read this file directly, the index lags."
|
|
351
|
+
*
|
|
352
|
+
* `indexing` is true when a sync is currently in flight whose start time is
|
|
353
|
+
* AFTER this file's most recent event — i.e. that sync will absorb the
|
|
354
|
+
* edit. False means the file is still inside the debounce window and no
|
|
355
|
+
* sync has started yet (a follow-up call a few hundred ms later may show
|
|
356
|
+
* `indexing: true` or the file may have left the list entirely).
|
|
357
|
+
*
|
|
358
|
+
* Cheap: O(pendingFiles.size), no I/O, no locks.
|
|
359
|
+
*/
|
|
360
|
+
getPendingFiles() {
|
|
361
|
+
const result = [];
|
|
362
|
+
for (const [filePath, info] of this.pendingFiles) {
|
|
363
|
+
result.push({
|
|
364
|
+
path: filePath,
|
|
365
|
+
firstSeenMs: info.firstSeenMs,
|
|
366
|
+
lastSeenMs: info.lastSeenMs,
|
|
367
|
+
indexing: this.syncing && this.syncStartedMs >= info.lastSeenMs,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
190
372
|
}
|
|
191
373
|
exports.FileWatcher = FileWatcher;
|
|
192
374
|
//# sourceMappingURL=watcher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,2CAA6B;AAE7B,wDAA+C;AAE/C,8CAAiE;AACjE,sCAA8C;AAC9C,oCAAyC;AACzC,iDAAqD;AA4CrD;;;;;;;;;;;;GAYG;AACH,MAAa,WAAW;IACd,OAAO,GAAqB,IAAI,CAAC;IACjC,aAAa,GAAyC,IAAI,CAAC;IACnE;;;;;;OAMG;IACK,YAAY,GAAG,IAAI,GAAG,EAAuD,CAAC;IACtF;;;;;OAKG;IACK,aAAa,GAAG,CAAC,CAAC;IAClB,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAG,KAAK,CAAC;IACxB;;;;;;OAMG;IACK,aAAa,GAAG,KAAK,CAAC;IAC9B;;;;OAIG;IACK,YAAY,GAAsB,EAAE,CAAC;IAC7C,4EAA4E;IAC5E,2EAA2E;IAC3E,sCAAsC;IAC9B,aAAa,GAAkB,IAAI,CAAC;IAE3B,WAAW,CAAS;IACpB,UAAU,CAAS;IACnB,MAAM,CAA8D;IACpE,cAAc,CAAkC;IAChD,WAAW,CAA+B;IAE3D,YACE,WAAmB,EACnB,MAAmE,EACnE,UAAwB,EAAE;QAE1B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;QAC7C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,CAAC,mBAAmB;QAClD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QAErB,qEAAqE;QACrE,oEAAoE;QACpE,qEAAqE;QACrE,yEAAyE;QACzE,MAAM,cAAc,GAAG,IAAA,kCAAmB,EAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7D,IAAI,cAAc,EAAE,CAAC;YACnB,IAAA,iBAAQ,EAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YAC7F,OAAO,KAAK,CAAC;QACf,CAAC;QAED,4EAA4E;QAC5E,yEAAyE;QACzE,gCAAgC;QAChC,IAAI,CAAC,aAAa,GAAG,IAAA,+BAAkB,EAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,GAAG,kBAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE;gBAC9C,oEAAoE;gBACpE,uEAAuE;gBACvE,iDAAiD;gBACjD,OAAO,EAAE,CAAC,QAAgB,EAAE,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC;aACjF,CAAC,CAAC;YAEH,qEAAqE;YACrE,mEAAmE;YACnE,uEAAuE;YACvE,oEAAoE;YACpE,oEAAoE;YACpE,kEAAkE;YAClE,iEAAiE;YACjE,EAAE;YACF,sEAAsE;YACtE,iEAAiE;YACjE,gEAAgE;YAChE,sEAAsE;YACtE,qCAAqC;YACrC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC5B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;gBAC1B,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;gBAC1B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,YAAY;oBAAE,EAAE,EAAE,CAAC;gBACzC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;YAEH,wEAAwE;YACxE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAc,EAAE,QAAgB,EAAE,EAAE;gBAC1D,IAAI,IAAI,CAAC,OAAO;oBAAE,OAAO;gBAEzB,MAAM,UAAU,GAAG,IAAA,qBAAa,EAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;gBAE5E,wEAAwE;gBACxE,0DAA0D;gBAC1D,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC;oBAAE,OAAO;gBAC7C,IAAI,CAAC,IAAA,yBAAY,EAAC,UAAU,CAAC;oBAAE,OAAO;gBAEtC,IAAA,iBAAQ,EAAC,sBAAsB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;gBACvD,kEAAkE;gBAClE,gEAAgE;gBAChE,6DAA6D;gBAC7D,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;oBACnD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE;wBAChC,WAAW,EAAE,QAAQ,EAAE,WAAW,IAAI,GAAG;wBACzC,UAAU,EAAE,GAAG;qBAChB,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,CAAC,CAAC,CAAC;YAEH,wEAAwE;YACxE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAY,EAAE,EAAE;gBACxC,IAAA,gBAAO,EAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;YAEH,IAAA,iBAAQ,EAAC,sBAAsB,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;YACjG,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,qEAAqE;YACrE,IAAA,gBAAO,EAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,iEAAiE;IACzD,eAAe,CAAC,GAAW;QACjC,OAAO,CACL,GAAG,KAAK,YAAY,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC;YACrD,GAAG,KAAK,MAAM,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAC1C,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACK,YAAY,CAAC,QAAgB,EAAE,KAAa;QAClD,MAAM,GAAG,GAAG,IAAA,qBAAa,EAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,iBAAiB;QAChF,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO,KAAK,CAAC;QACtC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,oEAAoE;QACpE,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IAClF,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC5B,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC3B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAA,iBAAQ,EAAC,sBAAsB,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAChD,CAAC;IAED;;;;;;;;;;OAUG;IACH,cAAc,CAAC,SAAS,GAAG,KAAK;QAC9B,IAAI,IAAI,CAAC,aAAa;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE;gBACxB,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC/C,IAAI,GAAG,IAAI,CAAC;oBAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC/C,MAAM,CAAC,IAAI,KAAK,CAAC,8CAA8C,SAAS,IAAI,CAAC,CAAC,CAAC;YACjF,CAAC,EAAE,SAAS,CAAC,CAAC;YACd,MAAM,OAAO,GAAG,GAAG,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YACtD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,YAAY;QAClB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACtB,CAAC;IAED;;;;;;;;;;;OAWG;IACK,KAAK,CAAC,KAAK;QACjB,0DAA0D;QAC1D,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YACnC,oEAAoE;YACpE,mEAAmE;YACnE,qEAAqE;YACrE,kEAAkE;YAClE,oEAAoE;YACpE,+DAA+D;YAC/D,kEAAkE;YAClE,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACjD,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC1C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;YACD,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,IAAA,gBAAO,EAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACvD,iEAAiE;YACjE,2DAA2D;YAC3D,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YAErB,kEAAkE;YAClE,yBAAyB;YACzB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChD,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,eAAe;QACb,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACjD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,QAAQ,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU;aAChE,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA7TD,kCA6TC"}
|