7. La CLI
Un punto de entrada de 30 líneas que prueba el core de IA sin ninguna UI.
src/cli.ts es el punto de entrada más chico que tiene LocalLens.
Lee dos valores de argv, instancia LocalLensApp, corre un
round-trip, limpia.
El archivo completo
import type { Brain } from "./domain.ts";
import { LocalLensApp } from "./locallens.ts";
const [folderPath, ...questionParts] = Bun.argv.slice(2);
const question = questionParts.join(" ").trim();
if (!folderPath || !question) {
console.log('Usage: bun run cli <folder-path> "question about the folder"');
process.exit(1);
}
const app = new LocalLensApp();
let brain: Brain | undefined;
try {
brain = await app.createBrainFromFolder({
name: folderPath.split(/[\\/]/).filter(Boolean).at(-1) ?? "cli-brain",
folderPath,
});
const result = await app.askBrain(brain.id, question);
console.log(`\n${result.answer}\n`);
if (result.citations.length > 0) {
console.log("Sources:");
for (const citation of result.citations) {
console.log(`- ${citation.relativePath}#${citation.chunkIndex}`);
}
}
} finally {
if (brain) await app.deleteBrain(brain.id).catch(() => undefined);
await app.close();
}El patrón del cerebro temporal
La CLI es una herramienta one-shot. Crea un cerebro, lo usa y lo
borra antes de salir. Por eso la limpieza vive en finally:
} finally {
if (brain) await app.deleteBrain(brain.id).catch(() => undefined);
await app.close();
}Dos razones:
- Sin deriva en el store JSON. Correr la CLI cien veces no deja
cien entradas en
.locallens/store.json. - Sin workspaces remanentes. El workspace de QVAC cierra y se borra junto con el cerebro, así que el uso de disco se mantiene acotado.
.catch(() => undefined) en deleteBrain es intencional. Si el
paso de creación del cerebro mismo falló, close() todavía necesita
correr. Tragar el error de limpieza mantiene el throw original en
su camino hacia arriba.
Naming del cerebro
name: folderPath.split(/[\\/]/).filter(Boolean).at(-1) ?? "cli-brain",La CLI deriva el nombre del cerebro del último segmento de la ruta
de la carpeta. examples/sample-brain se vuelve "sample-brain".
El fallback ?? "cli-brain" cubre rutas como /. Solo lo
suficiente para hacer la entrada JSON legible mientras el cerebro
existe brevemente.
Formato de salida
La CLI imprime la respuesta y un bloque Sources:. Sin renderizado
de Markdown, sin display de streaming, sin barra de progreso. Eso
es deliberado — la CLI es la prueba más simple de que el pipeline
funciona. Las interacciones más lindas viven en la app del
navegador.
LocalLens uses QWEN3_1_7B_INST_Q4 because it offers a strong balance of answer
quality and local resource use [1]. A 600M fallback is wired in for slimmer
machines [2].
Sources:
- locallens.md#0
- qvac-notes.md#1Exit codes
1— argumento(s) faltante(s). Se imprime la línea de uso.- Distinto de cero en cualquier error arrojado desde
LocalLensApp. Bun propaga el throw por default.
Los AppErrors del workflow afloran como stack traces comunes acá.
Sin response HTTP que formatear, así que el campo de status no se
usa.
Cuándo agregarías flags
La CLI es intencionalmente solo argv. Si quieres flags con nombre
(--top-k, --model, --keep), mantenlos en este archivo. No
los empujes a LocalLensApp. El workflow se queda igual; la CLI
solo aprende más maneras de invocarlo.
Lo que sigue: el servidor Bun, la contraparte más duradera.