(options: EmbeddingTrackerOptions)
| 65 | } |
| 66 | |
| 67 | export function startEmbeddingTracker(options: EmbeddingTrackerOptions): () => void { |
| 68 | const pendingFiles = new Set<string>(); |
| 69 | const debounceMs = clampDebounceMs(options.debounceMs); |
| 70 | const maxFilesPerTick = clampFilesPerTick(options.maxFilesPerTick); |
| 71 | |
| 72 | let watcher: FSWatcher | null = null; |
| 73 | let timer: NodeJS.Timeout | null = null; |
| 74 | let isProcessing = false; |
| 75 | let closed = false; |
| 76 | |
| 77 | const schedule = (delay: number = debounceMs): void => { |
| 78 | if (timer) clearTimeout(timer); |
| 79 | timer = setTimeout(() => { |
| 80 | void flushPending(); |
| 81 | }, delay); |
| 82 | timer.unref(); |
| 83 | }; |
| 84 | |
| 85 | const flushPending = async (): Promise<void> => { |
| 86 | if (closed || isProcessing) return; |
| 87 | if (pendingFiles.size === 0) return; |
| 88 | |
| 89 | isProcessing = true; |
| 90 | const batch = Array.from(pendingFiles).slice(0, maxFilesPerTick); |
| 91 | for (const file of batch) pendingFiles.delete(file); |
| 92 | |
| 93 | try { |
| 94 | const [fileEmbeds, identifierEmbeds] = await Promise.all([ |
| 95 | refreshFileSearchEmbeddings({ rootDir: options.rootDir, relativePaths: batch }), |
| 96 | refreshIdentifierEmbeddings({ rootDir: options.rootDir, relativePaths: batch }), |
| 97 | ]); |
| 98 | if (fileEmbeds > 0 || identifierEmbeds > 0) { |
| 99 | console.error( |
| 100 | `Embedding tracker refreshed ${batch.length} file(s) | file-vectors=${fileEmbeds}, identifier-vectors=${identifierEmbeds}`, |
| 101 | ); |
| 102 | } |
| 103 | } catch (error) { |
| 104 | console.error("Embedding tracker refresh failed:", error); |
| 105 | } finally { |
| 106 | isProcessing = false; |
| 107 | if (pendingFiles.size > 0) schedule(100); |
| 108 | } |
| 109 | }; |
| 110 | |
| 111 | try { |
| 112 | watcher = watch(options.rootDir, { recursive: true }, (_eventType, fileName) => { |
| 113 | if (closed || !fileName) return; |
| 114 | const relativePath = normalizeRelativePath(String(fileName)); |
| 115 | if (!shouldTrack(relativePath)) return; |
| 116 | if (pendingFiles.size >= MAX_PENDING_FILES) return; |
| 117 | pendingFiles.add(relativePath); |
| 118 | schedule(); |
| 119 | }); |
| 120 | } catch (error) { |
| 121 | console.error("Embedding tracker disabled: file watching is unavailable.", error); |
| 122 | return () => { }; |
| 123 | } |
| 124 |
nothing calls this directly
no test coverage detected