| 139 | * Provides the primary interface for interacting with the code knowledge graph. |
| 140 | */ |
| 141 | export class CodeGraph { |
| 142 | private db: DatabaseConnection; |
| 143 | private queries: QueryBuilder; |
| 144 | private projectRoot: string; |
| 145 | // Assigned via wireLayers() from the constructor (and again on reopen) — the |
| 146 | // `!` tells TS these are definitely set even though the assignment is one |
| 147 | // method call away from the constructor body. |
| 148 | private orchestrator!: ExtractionOrchestrator; |
| 149 | private resolver!: ReferenceResolver; |
| 150 | private graphManager!: GraphQueryManager; |
| 151 | private traverser!: GraphTraverser; |
| 152 | private contextBuilder!: ContextBuilder; |
| 153 | |
| 154 | // Mutex for preventing concurrent indexing operations (in-process) |
| 155 | private indexMutex = new Mutex(); |
| 156 | |
| 157 | // File lock for preventing concurrent writes across processes (CLI, MCP, git hooks) |
| 158 | private fileLock: FileLock; |
| 159 | |
| 160 | // File watcher for auto-sync on file changes |
| 161 | private watcher: FileWatcher | null = null; |
| 162 | |
| 163 | private constructor( |
| 164 | db: DatabaseConnection, |
| 165 | queries: QueryBuilder, |
| 166 | projectRoot: string |
| 167 | ) { |
| 168 | this.db = db; |
| 169 | this.queries = queries; |
| 170 | this.projectRoot = projectRoot; |
| 171 | this.fileLock = new FileLock( |
| 172 | path.join(getCodeGraphDir(projectRoot), 'codegraph.lock') |
| 173 | ); |
| 174 | this.wireLayers(); |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * (Re)build the query/extraction/graph layers over the current `this.queries` |
| 179 | * (which wraps `this.db`). Factored out of the constructor so `reopenIfReplaced` |
| 180 | * can rebuild them against a fresh connection without duplicating the wiring. |
| 181 | * The path-based `fileLock` is independent of the DB handle, so it stays put. |
| 182 | */ |
| 183 | private wireLayers(): void { |
| 184 | // Down-weight the project name as a query term in search ranking — it names |
| 185 | // the whole repo, not a symbol, so it has no discriminative value (#720). |
| 186 | try { |
| 187 | this.queries.setProjectNameTokens(deriveProjectNameTokens(this.projectRoot)); |
| 188 | } catch { |
| 189 | // Best-effort: ranking still works without it. |
| 190 | } |
| 191 | // Down-weight the peripheral trees the project named in `codegraph.json` |
| 192 | // `deprioritize` — indexed and findable, but never outranking real code |
| 193 | // (#982). Ranking-only, so a bad pattern costs relevance, never recall. |
| 194 | // |
| 195 | // Read LAZILY, not once here: `wireLayers` runs from the constructor and |
| 196 | // from `reopenIfReplaced`, so a matcher built here would freeze at whatever |
| 197 | // the config said when the project opened. The MCP server caches one |
| 198 | // CodeGraph per root for its whole lifetime, so editing `codegraph.json` |
nothing calls this directly
no outgoing calls
no test coverage detected