| 1906 | * Other projects are opened on-demand and cached for performance. |
| 1907 | */ |
| 1908 | export class ToolHandler { |
| 1909 | // Cache of opened CodeGraph instances for cross-project queries, keyed by the |
| 1910 | // CANONICAL (realpath) index root. Map insertion order doubles as LRU order: |
| 1911 | // a hit re-inserts, and `MAX_CACHED_PROJECTS` bounds the size (#1835). |
| 1912 | private projectCache: Map<string, CodeGraph> = new Map(); |
| 1913 | // When each cached root was last handed to a call, and the one timer that |
| 1914 | // releases the oldest once it has been idle long enough (#2087). |
| 1915 | private projectUsedAt: Map<string, number> = new Map(); |
| 1916 | private idleReleaseTimer: NodeJS.Timeout | null = null; |
| 1917 | // Engine hook that watches + catches up an explicit project (null for the |
| 1918 | // CLI and worker-thread handlers, which never own a watcher). |
| 1919 | private projectLifecycle: ProjectLifecycle | null = null; |
| 1920 | // Every concurrent call shares its project's pending catch-up promise. |
| 1921 | private projectGates: Map<CodeGraph, Promise<void>> = new Map(); |
| 1922 | private activeCalls = 0; |
| 1923 | private closing = false; |
| 1924 | private pendingCloses = 0; |
| 1925 | private closeWaiters: Array<() => void> = []; |
| 1926 | // The directory the server last searched for a default project. Surfaced in |
| 1927 | // the "not initialized" error so users can see why detection missed. |
| 1928 | private defaultProjectHint: string | null = null; |
| 1929 | // Indexed sub-projects the engine's bounded down-scan saw below the search |
| 1930 | // base when no default project resolved (#1607). Listed in the "not |
| 1931 | // initialized" error so the fact is reachable through the protocol, not just |
| 1932 | // the host's stderr capture. Engine-maintained (initial resolve + throttled |
| 1933 | // retry) — tool calls themselves never scan. |
| 1934 | private knownSubprojects: string[] = []; |
| 1935 | private knownSubprojectsBase: string | null = null; |
| 1936 | // Why the default project failed to open, when that is worth telling the |
| 1937 | // agent instead of "no project loaded" — today only the Windows/WSL |
| 1938 | // shared-index error (#995). Engine-maintained; cleared by a successful open. |
| 1939 | private defaultOpenFailure: WslSharedIndexError | null = null; |
| 1940 | // Per-start-path cache of the git worktree/index mismatch (issue #155). The |
| 1941 | // mismatch is a fixed property of (where the request came from → which |
| 1942 | // .codegraph/ it resolves to), so the up-to-two `git rev-parse` spawns run |
| 1943 | // once and every later tool call reuses the result — never shelling out to |
| 1944 | // git on the hot path. `undefined` = not computed yet; `null` = no mismatch. |
| 1945 | private worktreeMismatchCache: Map<string, WorktreeIndexMismatch | null> = new Map(); |
| 1946 | // Per-(projectPath, index root) cache of the different git repository the |
| 1947 | // path sits in below that root, if any (#2110) — the git half of |
| 1948 | // `uncoveredNestedRepo`, memoized like the mismatch above. |
| 1949 | private nestedRepoCache: Map<string, NestedRepository | null> = new Map(); |
| 1950 | // Gate that the MCP engine pokes after `cg.open()` so the first tool call |
| 1951 | // blocks on the post-open filesystem reconcile (catch-up sync). Without |
| 1952 | // this, a tool call that races past `catchUpSync()` serves rows for files |
| 1953 | // that were deleted (or edited) while no MCP server was running — and the |
| 1954 | // per-file staleness banner can't help, because `getPendingFiles()` is |
| 1955 | // populated by the watcher, not by catch-up. The wait is time-boxed |
| 1956 | // (see {@link resolveCatchUpGateTimeoutMs}) so a minutes-long reconcile on a |
| 1957 | // huge repo can't hang a call (#905); cleared when the reconcile settles. |
| 1958 | private catchUpGate: Promise<void> | null = null; |
| 1959 | // Engine hook fired when `freshen` reopened a replaced database (#1902), so |
| 1960 | // the engine can reconcile the new file with a catch-up sync. |
| 1961 | private onDatabaseReopened: ((cg: CodeGraph) => void) | null = null; |
| 1962 | // Optional worker-thread pool for off-loop read-tool dispatch. When ready + |
| 1963 | // healthy, heavy reads leave the main loop free for the MCP transport. |
| 1964 | private queryPool: QueryPool | null = null; |
| 1965 |
nothing calls this directly
no outgoing calls
no test coverage detected