(
projectRoot: string,
opts: { ttlMs?: number; maxFiles?: number; signal?: AbortSignal } = {},
)
| 36 | * every turn. Returns null if the graph can't be built. |
| 37 | */ |
| 38 | export async function getSymbolGraph( |
| 39 | projectRoot: string, |
| 40 | opts: { ttlMs?: number; maxFiles?: number; signal?: AbortSignal } = {}, |
| 41 | ): Promise<ImportGraph | null> { |
| 42 | const ttl = opts.ttlMs ?? DEFAULT_TTL_MS; |
| 43 | const cached = _cache.get(projectRoot); |
| 44 | if (cached && Date.now() - cached.builtAt < ttl) { |
| 45 | return cached.graph; |
| 46 | } |
| 47 | try { |
| 48 | const { walkSource } = await import('./retrieval.js'); |
| 49 | const files = await walkSource(projectRoot, opts.maxFiles ?? 2000); |
| 50 | const graph = await buildImportGraph( |
| 51 | projectRoot, |
| 52 | files.map(f => ({ rel: f.rel, content: f.content })), |
| 53 | ); |
| 54 | _cache.set(projectRoot, { graph, builtAt: Date.now() }); |
| 55 | logger.debug('Symbol graph built', { files: graph.files.size }); |
| 56 | return graph; |
| 57 | } catch (e: any) { |
| 58 | logger.debug('Symbol graph build failed', { err: e?.message }); |
| 59 | return null; |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | /** Invalidate the cached graph for a project (e.g. after a big refactor). */ |
| 64 | export function invalidateSymbolGraph(projectRoot: string): void { |
no test coverage detected