vecfinder

Document searching tool based on embedding vectors
git clone git://git.finwo.net/app/vecfinder
Log | Files | Refs

commit ed89e611e73ac0b342bb3485c0a6c26791a1486b
parent 5d1bf412d6266ccb37a618e30b7f3a0f7cc3bfa5
Author: finwo <finwo@pm.me>
Date:   Tue, 24 Mar 2026 14:13:16 +0100

Wait for both consumers and walkers to be done in --query mode

Diffstat:
Mvecfinder.js | 73+++++++++++++++++++++++++++++++++++++------------------------------------
1 file changed, 37 insertions(+), 36 deletions(-)

diff --git a/vecfinder.js b/vecfinder.js @@ -256,10 +256,22 @@ async function walkDir(dirPath) { async function indexDirectory(store, dirPath) { const files = await walkDir(dirPath); const queue = []; + let totalFiles = 0; + let completedFiles = 0; + + for (const filePath of files) { + const stats = await fs.stat(filePath).catch(() => null); + if (!stats || stats.size > 1024 * 1024) continue; + const text = await isTextFile(filePath); + if (!text) continue; + queue.push(filePath); + totalFiles++; + } function consumer() { - if (queue.length === 0) return; - if (store.consumersActive >= config.parallelism) return; + if (queue.length === 0 && store.consumersActive === 0) return; + + if (store.consumersActive >= config.parallelism || queue.length === 0) return; store.consumersActive++; const filePath = queue.shift(); @@ -280,20 +292,29 @@ async function indexDirectory(store, dirPath) { } } catch {} + completedFiles++; store.consumersActive--; store.emit('documentAdded'); - setImmediate(consumer); + if (queue.length > 0 || store.consumersActive > 0) { + setImmediate(consumer); + } })(); } - for (const filePath of files) { - const stats = await fs.stat(filePath).catch(() => null); - if (!stats || stats.size > 1024 * 1024) continue; - const text = await isTextFile(filePath); - if (!text) continue; - queue.push(filePath); + for (let i = 0; i < Math.min(config.parallelism, totalFiles); i++) { setImmediate(consumer); } + + return new Promise(resolve => { + const checkComplete = () => { + if (completedFiles >= totalFiles && store.consumersActive === 0 && queue.length === 0) { + store.removeListener('documentAdded', checkComplete); + resolve(); + } + }; + store.on('documentAdded', checkComplete); + checkComplete(); + }); } // UI @@ -623,19 +644,6 @@ class UI { } } -function waitForIndexing(store) { - return new Promise(resolve => { - const check = () => { - if (store.consumersActive === 0 && store.documents.size > 0) { - store.removeListener('documentAdded', check); - resolve(); - } - }; - store.on('documentAdded', check); - check(); - }); -} - function printUsage() { stdout.write(`Usage: vecfinder [options] vecfinder --query <text> [-k N] @@ -675,21 +683,14 @@ async function main() { process.exit(1); } - indexDirectory(store, process.cwd()); - - try { - await waitForIndexing(store); - const raw = await fetchEmbedding(queryText); - store.queryVec = normalize(raw); - const results = store.getResults().slice(0, k); - for (const r of results) { - stdout.write(r.id + '\n'); - } - process.exit(0); - } catch (err) { - stderr.write(`Error: ${err.message}\n`); - process.exit(1); + await indexDirectory(store, process.cwd()); + const raw = await fetchEmbedding(queryText); + store.queryVec = normalize(raw); + const results = store.getResults().slice(0, k); + for (const r of results) { + stdout.write(r.id + '\n'); } + process.exit(0); } const useBatFlag = args.includes('--no-bat') ? false : null;