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