Two coupled changes addressing the issue's underlying ask — "how does the
agent know when the index lags" — without resorting to a static wait.
Per-file staleness banner
-------------------------
FileWatcher now tracks per-path `pendingFiles` (path, firstSeenMs,
lastSeenMs, indexing) — events since the last successful sync, cleared
only after a sync whose `syncStartedMs >= lastSeenMs` commits. Chokidar
initial-scan events are gated behind a `ready` flag (with `waitUntilReady()`
exposed so tests can deterministically wait through it) so a fresh startup
doesn't falsely flag every existing file as pending.
ToolHandler now wraps every code-returning response (search, context,
callers, callees, impact, trace, explore, node, files) with
`withStalenessNotice`: intersects "files referenced in the response" with
`getPendingFiles()` and emits a hybrid signal —
* banner at the top for files referenced AND pending (with edit age +
indexing/pending-sync state, telling the agent to Read those specific
files directly; the rest of the response stays fresh and codegraph
stays authoritative for it),
* compact footer for pending files elsewhere in the project not
referenced above (capped at 5).
Cost is one boolean check + N substring matches when pending; zero
allocation when idle. `codegraph_status` surfaces the same data as a
first-class `### Pending sync:` section so the agent can ask "is the index
caught up?" in one call.
Cross-project quirk: when an agent passes `projectPath` matching the
default session's project, the staleness wrapper switches from the cached
cross-project CodeGraph (no watcher) to the default one (with watcher) so
the signal still fires. Same fix applied to `handleStatus`.
CODEGRAPH_WATCH_DEBOUNCE_MS
---------------------------
MCP `serve --mcp` now reads `CODEGRAPH_WATCH_DEBOUNCE_MS` and forwards it
to `cg.watch({ debounceMs })`. Clamped to [100ms, 60s]; out-of-range or
non-numeric values fall back to the FileWatcher default (2000ms). Active
value is logged to stderr on watcher startup so it's discoverable. The
docs in `server-instructions.ts`, `installer/instructions-template.ts`,
and `.cursor/rules/codegraph.mdc` no longer claim "~500ms"; they now
describe the banner mechanism instead — since per-file staleness replaces
the "wait N ms" guidance entirely, the docs become accurate at any
debounce value.
Validation
----------
* 847 unit/integration tests pass (added 15 new ones — pending-file
tracking, banner/footer routing, status section, env-var parsing).
* Direct MCP probe through a real `codegraph serve --mcp` process: edit a
file, query within the debounce window, banner fires naming the
edited file with edit-age.
* Real Claude TUI session via `scripts/agent-eval/itrun.sh` with
`CODEGRAPH_WATCH_DEBOUNCE_MS=10000`: agent edits `math.ts`, calls
`codegraph_explore`, reads the banner, **and discloses it unprompted in
its final reply**: "note: symbol index is mid-sync for the new `divide`,
but the source it returned is verbatim from disk."
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
34 lines
1.0 KiB
TypeScript
34 lines
1.0 KiB
TypeScript
/**
|
|
* Sync Module
|
|
*
|
|
* Provides synchronization functionality for keeping the code graph
|
|
* up-to-date with file system changes.
|
|
*
|
|
* Components:
|
|
* - FileWatcher: Debounced fs.watch that auto-triggers sync on file changes
|
|
* - Watch policy: decides when the watcher must be disabled (e.g. WSL2 /mnt)
|
|
* - Git sync hooks: opt-in commit/merge/checkout hooks when watching is off
|
|
* - Git worktree awareness: detect when a query borrows another tree's index
|
|
* - Content hashing for change detection (in extraction module)
|
|
* - Incremental reindexing (in extraction module)
|
|
*/
|
|
|
|
export { FileWatcher, WatchOptions, PendingFile } from './watcher';
|
|
export { watchDisabledReason, detectWsl } from './watch-policy';
|
|
export {
|
|
installGitSyncHook,
|
|
removeGitSyncHook,
|
|
isSyncHookInstalled,
|
|
isGitRepo,
|
|
DEFAULT_SYNC_HOOKS,
|
|
type GitHookName,
|
|
type GitHookResult,
|
|
} from './git-hooks';
|
|
export {
|
|
gitWorktreeRoot,
|
|
detectWorktreeIndexMismatch,
|
|
worktreeMismatchWarning,
|
|
worktreeMismatchNotice,
|
|
type WorktreeIndexMismatch,
|
|
} from './worktree';
|