@colbymchenry/codegraph-darwin-arm64 0.9.4 → 0.9.6
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.js +12 -0
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/db/queries.d.ts +1 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +31 -3
- package/lib/dist/db/queries.js.map +1 -1
- package/lib/dist/extraction/grammars.d.ts +1 -1
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +29 -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/c-cpp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.js +45 -0
- package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
- package/lib/dist/extraction/languages/csharp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/csharp.js +2 -1
- package/lib/dist/extraction/languages/csharp.js.map +1 -1
- package/lib/dist/extraction/languages/go.d.ts.map +1 -1
- package/lib/dist/extraction/languages/go.js +12 -0
- package/lib/dist/extraction/languages/go.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/mybatis-extractor.d.ts +48 -0
- package/lib/dist/extraction/mybatis-extractor.d.ts.map +1 -0
- package/lib/dist/extraction/mybatis-extractor.js +198 -0
- package/lib/dist/extraction/mybatis-extractor.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 +33 -0
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +351 -14
- package/lib/dist/extraction/tree-sitter.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 +53 -1
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/index.d.ts +1 -1
- package/lib/dist/installer/index.js +3 -3
- package/lib/dist/installer/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 +1 -1
- package/lib/dist/installer/targets/antigravity.d.ts +57 -0
- package/lib/dist/installer/targets/antigravity.d.ts.map +1 -0
- package/lib/dist/installer/targets/antigravity.js +307 -0
- package/lib/dist/installer/targets/antigravity.js.map +1 -0
- package/lib/dist/installer/targets/gemini.d.ts +26 -0
- package/lib/dist/installer/targets/gemini.d.ts.map +1 -0
- package/lib/dist/installer/targets/gemini.js +165 -0
- package/lib/dist/installer/targets/gemini.js.map +1 -0
- package/lib/dist/installer/targets/hermes.d.ts.map +1 -1
- package/lib/dist/installer/targets/hermes.js +57 -3
- package/lib/dist/installer/targets/hermes.js.map +1 -1
- package/lib/dist/installer/targets/kiro.d.ts +27 -0
- package/lib/dist/installer/targets/kiro.d.ts.map +1 -0
- package/lib/dist/installer/targets/kiro.js +196 -0
- package/lib/dist/installer/targets/kiro.js.map +1 -0
- package/lib/dist/installer/targets/registry.d.ts.map +1 -1
- package/lib/dist/installer/targets/registry.js +6 -0
- package/lib/dist/installer/targets/registry.js.map +1 -1
- package/lib/dist/installer/targets/types.d.ts +1 -1
- package/lib/dist/installer/targets/types.d.ts.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 +64 -53
- package/lib/dist/mcp/index.d.ts.map +1 -1
- package/lib/dist/mcp/index.js +307 -387
- 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 +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 +49 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +253 -17
- 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 +3 -2
- package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.js +351 -3
- package/lib/dist/resolution/callback-synthesizer.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/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/index.d.ts +4 -0
- package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/index.js +21 -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 +270 -1
- package/lib/dist/resolution/frameworks/java.js.map +1 -1
- package/lib/dist/resolution/frameworks/nestjs.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/nestjs.js +324 -0
- package/lib/dist/resolution/frameworks/nestjs.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/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/go-module.d.ts +26 -0
- package/lib/dist/resolution/go-module.d.ts.map +1 -0
- package/lib/dist/resolution/go-module.js +78 -0
- package/lib/dist/resolution/go-module.js.map +1 -0
- package/lib/dist/resolution/import-resolver.d.ts +18 -0
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +538 -4
- package/lib/dist/resolution/import-resolver.js.map +1 -1
- package/lib/dist/resolution/index.d.ts +10 -0
- package/lib/dist/resolution/index.d.ts.map +1 -1
- package/lib/dist/resolution/index.js +102 -0
- package/lib/dist/resolution/index.js.map +1 -1
- package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
- package/lib/dist/resolution/name-matcher.js +212 -0
- package/lib/dist/resolution/name-matcher.js.map +1 -1
- 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 +29 -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 +8 -1
- package/lib/dist/sync/index.js.map +1 -1
- package/lib/dist/sync/watcher.d.ts +119 -7
- package/lib/dist/sync/watcher.d.ts.map +1 -1
- package/lib/dist/sync/watcher.js +243 -37
- 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 +3 -0
- package/lib/dist/types.js.map +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/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,29 +47,82 @@ 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
|
-
exports.FileWatcher = void 0;
|
|
46
|
-
const
|
|
54
|
+
exports.FileWatcher = exports.LockUnavailableError = void 0;
|
|
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");
|
|
50
60
|
const watch_policy_1 = require("./watch-policy");
|
|
61
|
+
/**
|
|
62
|
+
* Thrown by a `syncFn` to signal that the underlying sync couldn't acquire
|
|
63
|
+
* the cross-process write lock (#449). The watcher treats this as "no
|
|
64
|
+
* progress" — preserves `pendingFiles`, skips `onSyncComplete`, and the
|
|
65
|
+
* `finally` block reschedules. Quiet (debug-only) because a long-running
|
|
66
|
+
* external indexer can hit this every debounce cycle.
|
|
67
|
+
*/
|
|
68
|
+
class LockUnavailableError extends Error {
|
|
69
|
+
constructor(message = 'CodeGraph file lock unavailable; another process is writing') {
|
|
70
|
+
super(message);
|
|
71
|
+
this.name = 'LockUnavailableError';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.LockUnavailableError = LockUnavailableError;
|
|
51
75
|
/**
|
|
52
76
|
* FileWatcher monitors a project directory for changes and triggers
|
|
53
77
|
* debounced sync operations via a provided callback.
|
|
54
78
|
*
|
|
55
79
|
* Design goals:
|
|
56
|
-
* - Minimal resource usage (
|
|
80
|
+
* - Minimal resource usage (chokidar filters excluded directories before
|
|
81
|
+
* registering an inotify watch — see module docs / #276)
|
|
57
82
|
* - Debounced to avoid thrashing on rapid saves
|
|
58
83
|
* - Filters to supported source files by extension
|
|
59
|
-
* - Ignores .codegraph/
|
|
84
|
+
* - Ignores .codegraph/ and .git/ regardless of .gitignore
|
|
85
|
+
* - Tracks per-file pending state so MCP tools can flag stale results
|
|
86
|
+
* without blocking on a sync (issue #403)
|
|
60
87
|
*/
|
|
61
88
|
class FileWatcher {
|
|
62
89
|
watcher = null;
|
|
63
90
|
debounceTimer = null;
|
|
64
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Files seen by the watcher since the last successful sync — populated on
|
|
93
|
+
* every chokidar event, cleared at the start of a sync, and re-populated by
|
|
94
|
+
* events that arrive mid-sync (or restored on sync failure). Keyed by the
|
|
95
|
+
* same project-relative POSIX path the rest of the codebase uses, so a
|
|
96
|
+
* caller can intersect tool-response file paths against this map cheaply.
|
|
97
|
+
*/
|
|
98
|
+
pendingFiles = new Map();
|
|
99
|
+
/**
|
|
100
|
+
* Wall-clock ms at which the in-flight sync began. Combined with
|
|
101
|
+
* {@link pendingFiles}'s `lastSeenMs`, this distinguishes "still in the
|
|
102
|
+
* debounce window" (lastSeen > syncStarted, sync hasn't started yet for
|
|
103
|
+
* this edit) from "currently being indexed" (lastSeen <= syncStarted).
|
|
104
|
+
*/
|
|
105
|
+
syncStartedMs = 0;
|
|
65
106
|
syncing = false;
|
|
66
107
|
stopped = false;
|
|
108
|
+
/**
|
|
109
|
+
* False until chokidar fires its `ready` event. Gates `pendingFiles`
|
|
110
|
+
* insertion so the initial crawl's `add` events (one per pre-existing
|
|
111
|
+
* source file) don't pollute the per-file staleness signal. The events
|
|
112
|
+
* still flow into `scheduleSync()` to preserve the previous "initial
|
|
113
|
+
* scan triggers a reconciling sync" behavior.
|
|
114
|
+
*/
|
|
115
|
+
chokidarReady = false;
|
|
116
|
+
/**
|
|
117
|
+
* Callbacks that resolve when chokidar fires `ready`. Used by tests (and
|
|
118
|
+
* any production caller that cares about a clean baseline) to deterministically
|
|
119
|
+
* gate on the end of the initial scan instead of guessing at a sleep duration.
|
|
120
|
+
*/
|
|
121
|
+
readyWaiters = [];
|
|
122
|
+
// The shared ignore matcher (built-in defaults + project .gitignore), built
|
|
123
|
+
// once at start(). Same source of truth the indexer uses, so watcher scope
|
|
124
|
+
// can never diverge from index scope.
|
|
125
|
+
ignoreMatcher = null;
|
|
67
126
|
projectRoot;
|
|
68
127
|
debounceMs;
|
|
69
128
|
syncFn;
|
|
@@ -84,49 +143,108 @@ class FileWatcher {
|
|
|
84
143
|
if (this.watcher)
|
|
85
144
|
return true; // Already watching
|
|
86
145
|
this.stopped = false;
|
|
87
|
-
// Some environments make
|
|
88
|
-
// /mnt/ drives, where
|
|
89
|
-
// handshakes (issue #199). Skip watching
|
|
90
|
-
// manual `codegraph sync` or
|
|
146
|
+
// Some environments make filesystem watching unusable — most notably
|
|
147
|
+
// WSL2 /mnt/ drives, where the underlying fs.watch calls block long
|
|
148
|
+
// enough to break MCP startup handshakes (issue #199). Skip watching
|
|
149
|
+
// there; callers fall back to manual `codegraph sync` or git sync hooks.
|
|
91
150
|
const disabledReason = (0, watch_policy_1.watchDisabledReason)(this.projectRoot);
|
|
92
151
|
if (disabledReason) {
|
|
93
152
|
(0, errors_1.logDebug)('File watcher disabled', { reason: disabledReason, projectRoot: this.projectRoot });
|
|
94
153
|
return false;
|
|
95
154
|
}
|
|
155
|
+
// Reuse the indexer's ignore set so the watcher and indexer agree on scope.
|
|
156
|
+
// chokidar only registers an inotify watch on directories that pass this
|
|
157
|
+
// filter — that's the #276 fix.
|
|
158
|
+
this.ignoreMatcher = (0, extraction_1.buildDefaultIgnore)(this.projectRoot);
|
|
96
159
|
try {
|
|
97
|
-
this.watcher =
|
|
98
|
-
|
|
160
|
+
this.watcher = chokidar_1.default.watch(this.projectRoot, {
|
|
161
|
+
// chokidar calls this for every path it encounters and only watches
|
|
162
|
+
// those that pass — so excluded trees (node_modules/, dist/, .git/, …)
|
|
163
|
+
// never get an inotify watch in the first place.
|
|
164
|
+
ignored: (testPath, stats) => this.shouldIgnore(testPath, stats),
|
|
165
|
+
});
|
|
166
|
+
// Chokidar emits `add` for every pre-existing source file during its
|
|
167
|
+
// initial scan. Those events should still trigger the post-startup
|
|
168
|
+
// reconciling sync (preserving prior behavior), but they must NOT land
|
|
169
|
+
// in pendingFiles — otherwise every file in the project shows up as
|
|
170
|
+
// "edited but not indexed" on startup, which is the opposite of the
|
|
171
|
+
// signal #403 is supposed to provide. Flip the flag on chokidar's
|
|
172
|
+
// `ready` event; from then on, real edits populate pendingFiles.
|
|
173
|
+
//
|
|
174
|
+
// We also clear `pendingFiles` here as defense-in-depth: chokidar can
|
|
175
|
+
// emit late initial-scan `add` events via setImmediate AFTER the
|
|
176
|
+
// `ready` callback runs (observed under test-parallelism load).
|
|
177
|
+
// Clearing once at ready guarantees a clean baseline; real subsequent
|
|
178
|
+
// edits repopulate the set normally.
|
|
179
|
+
this.watcher.on('ready', () => {
|
|
180
|
+
this.chokidarReady = true;
|
|
181
|
+
this.pendingFiles.clear();
|
|
182
|
+
for (const cb of this.readyWaiters)
|
|
183
|
+
cb();
|
|
184
|
+
this.readyWaiters.length = 0;
|
|
185
|
+
});
|
|
186
|
+
// chokidar emits 'all' for every event type; we only sync source files.
|
|
187
|
+
this.watcher.on('all', (_event, filePath) => {
|
|
188
|
+
if (this.stopped)
|
|
99
189
|
return;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
//
|
|
103
|
-
if (normalized
|
|
104
|
-
normalized.startsWith('.codegraph/') ||
|
|
105
|
-
normalized.startsWith('.codegraph\\')) {
|
|
190
|
+
const normalized = (0, utils_1.normalizePath)(path.relative(this.projectRoot, filePath));
|
|
191
|
+
// Defense in depth: `ignored` should already keep these out, but events
|
|
192
|
+
// can still arrive during setup or via symlink traversal.
|
|
193
|
+
if (this.isAlwaysIgnored(normalized))
|
|
106
194
|
return;
|
|
107
|
-
|
|
108
|
-
// Only sync changes to files we can actually parse.
|
|
109
|
-
if (!(0, extraction_1.isSourceFile)(normalized)) {
|
|
195
|
+
if (!(0, extraction_1.isSourceFile)(normalized))
|
|
110
196
|
return;
|
|
111
|
-
}
|
|
112
197
|
(0, errors_1.logDebug)('File change detected', { file: normalized });
|
|
113
|
-
|
|
198
|
+
// Only track events from after chokidar's initial scan as pending
|
|
199
|
+
// edits — pre-existing files on disk are already represented by
|
|
200
|
+
// (or about to be reconciled by) the index, not a user edit.
|
|
201
|
+
if (this.chokidarReady) {
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
const existing = this.pendingFiles.get(normalized);
|
|
204
|
+
this.pendingFiles.set(normalized, {
|
|
205
|
+
firstSeenMs: existing?.firstSeenMs ?? now,
|
|
206
|
+
lastSeenMs: now,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
114
209
|
this.scheduleSync();
|
|
115
210
|
});
|
|
116
|
-
// Handle watcher errors gracefully
|
|
211
|
+
// Handle watcher errors gracefully — don't crash, the user can restart.
|
|
117
212
|
this.watcher.on('error', (err) => {
|
|
118
213
|
(0, errors_1.logWarn)('File watcher error', { error: String(err) });
|
|
119
|
-
// Don't crash — watcher may recover or user can restart
|
|
120
214
|
});
|
|
121
215
|
(0, errors_1.logDebug)('File watcher started', { projectRoot: this.projectRoot, debounceMs: this.debounceMs });
|
|
122
216
|
return true;
|
|
123
217
|
}
|
|
124
218
|
catch (err) {
|
|
125
|
-
//
|
|
126
|
-
(0, errors_1.logWarn)('Could not start file watcher
|
|
219
|
+
// Watcher setup failed (e.g., permission denied, missing directory).
|
|
220
|
+
(0, errors_1.logWarn)('Could not start file watcher', { error: String(err) });
|
|
127
221
|
return false;
|
|
128
222
|
}
|
|
129
223
|
}
|
|
224
|
+
/** Our own dirs are always ignored, regardless of .gitignore. */
|
|
225
|
+
isAlwaysIgnored(rel) {
|
|
226
|
+
return (rel === '.codegraph' || rel.startsWith('.codegraph/') ||
|
|
227
|
+
rel === '.git' || rel.startsWith('.git/'));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* chokidar `ignored` predicate — true for any path that should NOT be watched.
|
|
231
|
+
* Uses chokidar's provided `stats` to decide directory-vs-file so a dir-only
|
|
232
|
+
* rule like `build/` matches, without an extra `statSync` per path.
|
|
233
|
+
*/
|
|
234
|
+
shouldIgnore(testPath, stats) {
|
|
235
|
+
const rel = (0, utils_1.normalizePath)(path.relative(this.projectRoot, testPath));
|
|
236
|
+
if (!rel || rel === '.' || rel.startsWith('..'))
|
|
237
|
+
return false; // root / outside
|
|
238
|
+
if (this.isAlwaysIgnored(rel))
|
|
239
|
+
return true;
|
|
240
|
+
if (!this.ignoreMatcher)
|
|
241
|
+
return false;
|
|
242
|
+
if (stats) {
|
|
243
|
+
return this.ignoreMatcher.ignores(stats.isDirectory() ? rel + '/' : rel);
|
|
244
|
+
}
|
|
245
|
+
// Stats unknown: test both forms so a directory match isn't missed.
|
|
246
|
+
return this.ignoreMatcher.ignores(rel) || this.ignoreMatcher.ignores(rel + '/');
|
|
247
|
+
}
|
|
130
248
|
/**
|
|
131
249
|
* Stop watching for file changes.
|
|
132
250
|
*/
|
|
@@ -140,7 +258,9 @@ class FileWatcher {
|
|
|
140
258
|
this.watcher.close();
|
|
141
259
|
this.watcher = null;
|
|
142
260
|
}
|
|
143
|
-
this.
|
|
261
|
+
this.pendingFiles.clear();
|
|
262
|
+
this.chokidarReady = false;
|
|
263
|
+
this.ignoreMatcher = null;
|
|
144
264
|
(0, errors_1.logDebug)('File watcher stopped');
|
|
145
265
|
}
|
|
146
266
|
/**
|
|
@@ -149,6 +269,31 @@ class FileWatcher {
|
|
|
149
269
|
isActive() {
|
|
150
270
|
return this.watcher !== null && !this.stopped;
|
|
151
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Resolves once chokidar has fired its `ready` event (or immediately if
|
|
274
|
+
* it has already done so). Useful for tests that need a deterministic
|
|
275
|
+
* boundary before asserting on `pendingFiles` — guessing a sleep duration
|
|
276
|
+
* is flaky under load because chokidar can take longer than expected to
|
|
277
|
+
* finish its initial crawl on slow filesystems / parallel test runs.
|
|
278
|
+
*
|
|
279
|
+
* Production callers don't need this: `pendingFiles` is read continuously,
|
|
280
|
+
* the staleness banner is always correct (empty or populated), and the
|
|
281
|
+
* initial-scan window is a small one-time startup cost.
|
|
282
|
+
*/
|
|
283
|
+
waitUntilReady(timeoutMs = 10000) {
|
|
284
|
+
if (this.chokidarReady)
|
|
285
|
+
return Promise.resolve();
|
|
286
|
+
return new Promise((resolve, reject) => {
|
|
287
|
+
const t = setTimeout(() => {
|
|
288
|
+
const idx = this.readyWaiters.indexOf(handler);
|
|
289
|
+
if (idx >= 0)
|
|
290
|
+
this.readyWaiters.splice(idx, 1);
|
|
291
|
+
reject(new Error(`FileWatcher.waitUntilReady timed out after ${timeoutMs}ms`));
|
|
292
|
+
}, timeoutMs);
|
|
293
|
+
const handler = () => { clearTimeout(t); resolve(); };
|
|
294
|
+
this.readyWaiters.push(handler);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
152
297
|
/**
|
|
153
298
|
* Schedule a debounced sync.
|
|
154
299
|
*/
|
|
@@ -163,30 +308,91 @@ class FileWatcher {
|
|
|
163
308
|
}
|
|
164
309
|
/**
|
|
165
310
|
* Flush pending changes by running sync.
|
|
311
|
+
*
|
|
312
|
+
* pendingFiles is NOT cleared at the start of sync — entries are removed
|
|
313
|
+
* only after sync commits successfully, and only for entries whose
|
|
314
|
+
* lastSeenMs <= syncStartedMs. That way, a query that arrives mid-sync
|
|
315
|
+
* still sees the affected files marked stale (the DB hasn't been updated
|
|
316
|
+
* yet), and an event that lands mid-sync persists into the follow-up.
|
|
317
|
+
*
|
|
318
|
+
* On sync failure pendingFiles is left untouched — every edit is still
|
|
319
|
+
* unindexed, and the rescheduled sync will absorb the same set next time.
|
|
166
320
|
*/
|
|
167
321
|
async flush() {
|
|
168
322
|
// If already syncing, the post-sync check will re-trigger
|
|
169
323
|
if (this.syncing || this.stopped)
|
|
170
324
|
return;
|
|
171
|
-
this.
|
|
325
|
+
this.syncStartedMs = Date.now();
|
|
172
326
|
this.syncing = true;
|
|
173
327
|
try {
|
|
174
328
|
const result = await this.syncFn();
|
|
329
|
+
// Remove entries whose most recent event predates this sync — those
|
|
330
|
+
// edits are now in the DB. Entries with lastSeenMs > syncStartedMs
|
|
331
|
+
// arrived mid-sync; whether the in-flight sync captured them depends
|
|
332
|
+
// on when sync read that file, so we keep them as pending and let
|
|
333
|
+
// the follow-up sync handle them. We prefer false positives ("shown
|
|
334
|
+
// stale, actually fresh" → at worst one extra Read) over false
|
|
335
|
+
// negatives ("shown fresh, actually stale" → misleads the agent).
|
|
336
|
+
for (const [filePath, info] of this.pendingFiles) {
|
|
337
|
+
if (info.lastSeenMs <= this.syncStartedMs) {
|
|
338
|
+
this.pendingFiles.delete(filePath);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
175
341
|
this.onSyncComplete?.(result);
|
|
176
342
|
}
|
|
177
343
|
catch (err) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
344
|
+
if (err instanceof LockUnavailableError) {
|
|
345
|
+
// Lock-failure no-op (another writer holds the lock). pendingFiles
|
|
346
|
+
// stays intact and the `finally` block reschedules. Debug-only —
|
|
347
|
+
// a long external index would otherwise spam stderr every cycle.
|
|
348
|
+
(0, errors_1.logDebug)('Watch sync skipped: file lock unavailable', {
|
|
349
|
+
pendingFiles: this.pendingFiles.size,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
354
|
+
(0, errors_1.logWarn)('Watch sync failed', { error: error.message });
|
|
355
|
+
this.onSyncError?.(error);
|
|
356
|
+
}
|
|
357
|
+
// Failure: leave pendingFiles untouched. Every edit it tracks is
|
|
358
|
+
// still unindexed; the rescheduled sync sees the same set.
|
|
181
359
|
}
|
|
182
360
|
finally {
|
|
183
361
|
this.syncing = false;
|
|
184
|
-
// If
|
|
185
|
-
|
|
362
|
+
// If pending files remain (mid-sync events, or this sync failed),
|
|
363
|
+
// schedule another pass.
|
|
364
|
+
if (this.pendingFiles.size > 0 && !this.stopped) {
|
|
186
365
|
this.scheduleSync();
|
|
187
366
|
}
|
|
188
367
|
}
|
|
189
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* Snapshot of files seen by the watcher since the last successful sync.
|
|
371
|
+
*
|
|
372
|
+
* Used by MCP tool responses to mark stale results without blocking on a
|
|
373
|
+
* sync: a tool that returns a hit in `src/foo.ts` while `src/foo.ts` is in
|
|
374
|
+
* this list tells the agent "Read this file directly, the index lags."
|
|
375
|
+
*
|
|
376
|
+
* `indexing` is true when a sync is currently in flight whose start time is
|
|
377
|
+
* AFTER this file's most recent event — i.e. that sync will absorb the
|
|
378
|
+
* edit. False means the file is still inside the debounce window and no
|
|
379
|
+
* sync has started yet (a follow-up call a few hundred ms later may show
|
|
380
|
+
* `indexing: true` or the file may have left the list entirely).
|
|
381
|
+
*
|
|
382
|
+
* Cheap: O(pendingFiles.size), no I/O, no locks.
|
|
383
|
+
*/
|
|
384
|
+
getPendingFiles() {
|
|
385
|
+
const result = [];
|
|
386
|
+
for (const [filePath, info] of this.pendingFiles) {
|
|
387
|
+
result.push({
|
|
388
|
+
path: filePath,
|
|
389
|
+
firstSeenMs: info.firstSeenMs,
|
|
390
|
+
lastSeenMs: info.lastSeenMs,
|
|
391
|
+
indexing: this.syncing && this.syncStartedMs >= info.lastSeenMs,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
190
396
|
}
|
|
191
397
|
exports.FileWatcher = FileWatcher;
|
|
192
398
|
//# 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;AAwBrD;;;;;;GAMG;AACH,MAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAO,GAAG,6DAA6D;QACjF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AALD,oDAKC;AAsBD;;;;;;;;;;;;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,IAAI,GAAG,YAAY,oBAAoB,EAAE,CAAC;gBACxC,mEAAmE;gBACnE,iEAAiE;gBACjE,iEAAiE;gBACjE,IAAA,iBAAQ,EAAC,2CAA2C,EAAE;oBACpD,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;iBACrC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAClE,IAAA,gBAAO,EAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvD,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;YACD,iEAAiE;YACjE,2DAA2D;QAC7D,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;AAtUD,kCAsUC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Worktree Awareness
|
|
3
|
+
*
|
|
4
|
+
* A CodeGraph index lives in a `.codegraph/` directory and is resolved by
|
|
5
|
+
* walking up parent directories to the nearest one (see
|
|
6
|
+
* `findNearestCodeGraphRoot`). That walk is unaware of git worktrees: when a
|
|
7
|
+
* worktree is created *inside* the main checkout (e.g. some tools place them
|
|
8
|
+
* under `.gitignore`d paths like `.claude/worktrees/<name>/`), a command run
|
|
9
|
+
* from the worktree walks up and silently resolves the MAIN checkout's index.
|
|
10
|
+
*
|
|
11
|
+
* Every query then returns results from the main tree's code — usually a
|
|
12
|
+
* different branch — rather than the worktree the user is actually editing.
|
|
13
|
+
* Symbols added or changed only in the worktree are invisible. This module
|
|
14
|
+
* detects that "borrowed index" situation so callers can warn about it.
|
|
15
|
+
*
|
|
16
|
+
* Detection is best-effort: when git is unavailable or the path isn't a repo,
|
|
17
|
+
* it reports "no mismatch" and callers carry on unchanged.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Absolute, symlink-resolved toplevel of the git working tree that `dir`
|
|
21
|
+
* belongs to, or null when `dir` isn't inside a git repo (or git is missing).
|
|
22
|
+
*
|
|
23
|
+
* `git rev-parse --show-toplevel` returns the per-worktree root: the main
|
|
24
|
+
* checkout and each linked worktree report their own distinct directory, which
|
|
25
|
+
* is exactly the distinction this module relies on.
|
|
26
|
+
*/
|
|
27
|
+
export declare function gitWorktreeRoot(dir: string): string | null;
|
|
28
|
+
export interface WorktreeIndexMismatch {
|
|
29
|
+
/** The git working tree the command was run from. */
|
|
30
|
+
worktreeRoot: string;
|
|
31
|
+
/** The (different) working tree whose `.codegraph` index is being used. */
|
|
32
|
+
indexRoot: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Detect when `startPath` lives in one git working tree but the resolved
|
|
36
|
+
* CodeGraph index (`indexRoot`) belongs to a *different* working tree.
|
|
37
|
+
*
|
|
38
|
+
* Returns null — meaning "nothing to warn about" — when:
|
|
39
|
+
* - `startPath` isn't in a git repo (or git is unavailable),
|
|
40
|
+
* - the index already lives in `startPath`'s own working tree, or
|
|
41
|
+
* - `indexRoot` isn't itself a working-tree root (an unrelated parent dir
|
|
42
|
+
* that merely happens to contain a `.codegraph/`), which keeps non-git
|
|
43
|
+
* and monorepo-subdir layouts from producing false warnings.
|
|
44
|
+
*/
|
|
45
|
+
export declare function detectWorktreeIndexMismatch(startPath: string, indexRoot: string): WorktreeIndexMismatch | null;
|
|
46
|
+
/** One-line-per-fact warning describing a detected mismatch. */
|
|
47
|
+
export declare function worktreeMismatchWarning(m: WorktreeIndexMismatch): string;
|
|
48
|
+
/**
|
|
49
|
+
* Compact, single-line variant for prefixing a tool's result. Read tools
|
|
50
|
+
* return their answer inline, so the heads-up has to ride on the same payload
|
|
51
|
+
* the agent is already reading — a multi-line block would bury the result.
|
|
52
|
+
*/
|
|
53
|
+
export declare function worktreeMismatchNotice(m: WorktreeIndexMismatch): string;
|
|
54
|
+
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/sync/worktree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW1D;AAED,MAAM,WAAW,qBAAqB;IACpC,qDAAqD;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,qBAAqB,GAAG,IAAI,CAa9B;AAED,gEAAgE;AAChE,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,qBAAqB,GAAG,MAAM,CASxE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAOvE"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Git Worktree Awareness
|
|
4
|
+
*
|
|
5
|
+
* A CodeGraph index lives in a `.codegraph/` directory and is resolved by
|
|
6
|
+
* walking up parent directories to the nearest one (see
|
|
7
|
+
* `findNearestCodeGraphRoot`). That walk is unaware of git worktrees: when a
|
|
8
|
+
* worktree is created *inside* the main checkout (e.g. some tools place them
|
|
9
|
+
* under `.gitignore`d paths like `.claude/worktrees/<name>/`), a command run
|
|
10
|
+
* from the worktree walks up and silently resolves the MAIN checkout's index.
|
|
11
|
+
*
|
|
12
|
+
* Every query then returns results from the main tree's code — usually a
|
|
13
|
+
* different branch — rather than the worktree the user is actually editing.
|
|
14
|
+
* Symbols added or changed only in the worktree are invisible. This module
|
|
15
|
+
* detects that "borrowed index" situation so callers can warn about it.
|
|
16
|
+
*
|
|
17
|
+
* Detection is best-effort: when git is unavailable or the path isn't a repo,
|
|
18
|
+
* it reports "no mismatch" and callers carry on unchanged.
|
|
19
|
+
*/
|
|
20
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
23
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
24
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
25
|
+
}
|
|
26
|
+
Object.defineProperty(o, k2, desc);
|
|
27
|
+
}) : (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
o[k2] = m[k];
|
|
30
|
+
}));
|
|
31
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
32
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
33
|
+
}) : function(o, v) {
|
|
34
|
+
o["default"] = v;
|
|
35
|
+
});
|
|
36
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
37
|
+
var ownKeys = function(o) {
|
|
38
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
39
|
+
var ar = [];
|
|
40
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
41
|
+
return ar;
|
|
42
|
+
};
|
|
43
|
+
return ownKeys(o);
|
|
44
|
+
};
|
|
45
|
+
return function (mod) {
|
|
46
|
+
if (mod && mod.__esModule) return mod;
|
|
47
|
+
var result = {};
|
|
48
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
49
|
+
__setModuleDefault(result, mod);
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
})();
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.gitWorktreeRoot = gitWorktreeRoot;
|
|
55
|
+
exports.detectWorktreeIndexMismatch = detectWorktreeIndexMismatch;
|
|
56
|
+
exports.worktreeMismatchWarning = worktreeMismatchWarning;
|
|
57
|
+
exports.worktreeMismatchNotice = worktreeMismatchNotice;
|
|
58
|
+
const fs = __importStar(require("fs"));
|
|
59
|
+
const path = __importStar(require("path"));
|
|
60
|
+
const child_process_1 = require("child_process");
|
|
61
|
+
/**
|
|
62
|
+
* Absolute, symlink-resolved toplevel of the git working tree that `dir`
|
|
63
|
+
* belongs to, or null when `dir` isn't inside a git repo (or git is missing).
|
|
64
|
+
*
|
|
65
|
+
* `git rev-parse --show-toplevel` returns the per-worktree root: the main
|
|
66
|
+
* checkout and each linked worktree report their own distinct directory, which
|
|
67
|
+
* is exactly the distinction this module relies on.
|
|
68
|
+
*/
|
|
69
|
+
function gitWorktreeRoot(dir) {
|
|
70
|
+
try {
|
|
71
|
+
const out = (0, child_process_1.execFileSync)('git', ['rev-parse', '--show-toplevel'], {
|
|
72
|
+
cwd: dir,
|
|
73
|
+
encoding: 'utf8',
|
|
74
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
75
|
+
}).trim();
|
|
76
|
+
return out ? realpath(out) : null;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Detect when `startPath` lives in one git working tree but the resolved
|
|
84
|
+
* CodeGraph index (`indexRoot`) belongs to a *different* working tree.
|
|
85
|
+
*
|
|
86
|
+
* Returns null — meaning "nothing to warn about" — when:
|
|
87
|
+
* - `startPath` isn't in a git repo (or git is unavailable),
|
|
88
|
+
* - the index already lives in `startPath`'s own working tree, or
|
|
89
|
+
* - `indexRoot` isn't itself a working-tree root (an unrelated parent dir
|
|
90
|
+
* that merely happens to contain a `.codegraph/`), which keeps non-git
|
|
91
|
+
* and monorepo-subdir layouts from producing false warnings.
|
|
92
|
+
*/
|
|
93
|
+
function detectWorktreeIndexMismatch(startPath, indexRoot) {
|
|
94
|
+
const worktreeRoot = gitWorktreeRoot(startPath);
|
|
95
|
+
if (!worktreeRoot)
|
|
96
|
+
return null;
|
|
97
|
+
const resolvedIndexRoot = realpath(indexRoot);
|
|
98
|
+
if (worktreeRoot === resolvedIndexRoot)
|
|
99
|
+
return null;
|
|
100
|
+
// Only flag it when the index root is itself a real working-tree root. This
|
|
101
|
+
// distinguishes "borrowed another worktree's index" from "index sits in a
|
|
102
|
+
// plain ancestor directory", and avoids warning outside git entirely.
|
|
103
|
+
if (gitWorktreeRoot(resolvedIndexRoot) !== resolvedIndexRoot)
|
|
104
|
+
return null;
|
|
105
|
+
return { worktreeRoot, indexRoot: resolvedIndexRoot };
|
|
106
|
+
}
|
|
107
|
+
/** One-line-per-fact warning describing a detected mismatch. */
|
|
108
|
+
function worktreeMismatchWarning(m) {
|
|
109
|
+
return (`This CodeGraph index belongs to a different git working tree.\n` +
|
|
110
|
+
` Running in: ${m.worktreeRoot}\n` +
|
|
111
|
+
` Index from: ${m.indexRoot}\n` +
|
|
112
|
+
`Results reflect that tree's code (often a different branch), not this worktree — ` +
|
|
113
|
+
`symbols changed only here are missing. Run "codegraph init -i" in this worktree ` +
|
|
114
|
+
`for a worktree-local index.`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Compact, single-line variant for prefixing a tool's result. Read tools
|
|
118
|
+
* return their answer inline, so the heads-up has to ride on the same payload
|
|
119
|
+
* the agent is already reading — a multi-line block would bury the result.
|
|
120
|
+
*/
|
|
121
|
+
function worktreeMismatchNotice(m) {
|
|
122
|
+
return (`⚠ CodeGraph results below come from a different git worktree (${m.indexRoot}), ` +
|
|
123
|
+
`not where you're working (${m.worktreeRoot}) — they may reflect another branch, ` +
|
|
124
|
+
`and symbols changed only here are missing. Run "codegraph init -i" here for a ` +
|
|
125
|
+
`worktree-local index.`);
|
|
126
|
+
}
|
|
127
|
+
/** Resolve symlinks where possible so tmp/realpath quirks don't break equality. */
|
|
128
|
+
function realpath(p) {
|
|
129
|
+
try {
|
|
130
|
+
return fs.realpathSync(path.resolve(p));
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return path.resolve(p);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/sync/worktree.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcH,0CAWC;AAoBD,kEAgBC;AAGD,0DASC;AAOD,wDAOC;AArFD,uCAAyB;AACzB,2CAA6B;AAC7B,iDAA6C;AAE7C;;;;;;;GAOG;AACH,SAAgB,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE;YAChE,GAAG,EAAE,GAAG;YACR,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AASD;;;;;;;;;;GAUG;AACH,SAAgB,2BAA2B,CACzC,SAAiB,EACjB,SAAiB;IAEjB,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAChD,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAE/B,MAAM,iBAAiB,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,YAAY,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAEpD,4EAA4E;IAC5E,0EAA0E;IAC1E,sEAAsE;IACtE,IAAI,eAAe,CAAC,iBAAiB,CAAC,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAE1E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;AACxD,CAAC;AAED,gEAAgE;AAChE,SAAgB,uBAAuB,CAAC,CAAwB;IAC9D,OAAO,CACL,iEAAiE;QACjE,iBAAiB,CAAC,CAAC,YAAY,IAAI;QACnC,iBAAiB,CAAC,CAAC,SAAS,IAAI;QAChC,mFAAmF;QACnF,kFAAkF;QAClF,6BAA6B,CAC9B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CAAC,CAAwB;IAC7D,OAAO,CACL,iEAAiE,CAAC,CAAC,SAAS,KAAK;QACjF,6BAA6B,CAAC,CAAC,YAAY,uCAAuC;QAClF,gFAAgF;QAChF,uBAAuB,CACxB,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,SAAS,QAAQ,CAAC,CAAS;IACzB,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;AACH,CAAC"}
|
package/lib/dist/types.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type EdgeKind = 'contains' | 'calls' | 'imports' | 'exports' | 'extends'
|
|
|
20
20
|
* Supported programming languages. See NODE_KINDS for why this is a
|
|
21
21
|
* runtime-iterable const array.
|
|
22
22
|
*/
|
|
23
|
-
export declare const LANGUAGES: readonly ["typescript", "javascript", "tsx", "jsx", "python", "go", "rust", "java", "c", "cpp", "csharp", "php", "ruby", "swift", "kotlin", "dart", "svelte", "vue", "liquid", "pascal", "scala", "lua", "luau", "yaml", "twig", "unknown"];
|
|
23
|
+
export declare const LANGUAGES: readonly ["typescript", "javascript", "tsx", "jsx", "python", "go", "rust", "java", "c", "cpp", "csharp", "php", "ruby", "swift", "kotlin", "dart", "svelte", "vue", "liquid", "pascal", "scala", "lua", "luau", "objc", "yaml", "twig", "xml", "properties", "unknown"];
|
|
24
24
|
export type Language = (typeof LANGUAGES)[number];
|
|
25
25
|
/**
|
|
26
26
|
* A node in the knowledge graph representing a code symbol
|