7. CLI
30 行のエントリポイントで、UI なしに AI のコアが動くことを示す。
src/cli.ts は LocalLens で最も小さなエントリポイントです。argv の値を
2 つ読み、LocalLensApp をインスタンス化し、1 往復走らせて、片付けます。
ファイル全体
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();
}一時 brain のパターン
CLI はワンショットのツールです。brain を作り、使い、終了前に削除します。
だからクリーンアップが finally にあります。
} finally {
if (brain) await app.deleteBrain(brain.id).catch(() => undefined);
await app.close();
}理由は 2 つあります。
- JSON ストアにゴミが溜まらない。 CLI を 100 回叩いても、
.locallens/store.jsonに 100 件のエントリが残ったりしません。 - 使い残しのワークスペースが残らない。 QVAC ワークスペースは brain と 一緒に閉じて削除されるので、ディスク使用量が一定範囲に収まります。
deleteBrain に付いている .catch(() => undefined) は意図的です。brain
作成ステップ自体が失敗した場合でも、close() は実行する必要があります。
クリーンアップ側のエラーを飲み込むことで、元の throw を上に伝えられます。
brain の命名
name: folderPath.split(/[\\/]/).filter(Boolean).at(-1) ?? "cli-brain",CLI はフォルダパスの最後のセグメントから brain 名を作ります。
examples/sample-brain は "sample-brain" になります。?? "cli-brain"
のフォールバックは / のようなパスをカバーします。brain が短命のあいだ
JSON エントリを読みやすくするのにちょうど良い情報量です。
出力フォーマット
CLI は回答と Sources: ブロックを表示します。Markdown レンダリングも、
ストリーミング表示も、プログレスバーもありません。これは意図的です。
CLI はパイプラインが動くことを示す最小の証拠であり、リッチな操作は
ブラウザアプリの担当です。
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#1終了コード
1— 引数の不足。usage 行が表示されます。LocalLensAppから throw されたエラーは非ゼロで終了。Bun が デフォルトで throw を伝播します。
ワークフローから上がってきた AppError は、ここでは普通の stack trace
として表面化します。フォーマットすべき HTTP レスポンスがないので、
status フィールドは使われません。
フラグを追加したくなったら
CLI は意図的に argv のみです。名前付きフラグ(--top-k、--model、
--keep)を追加したくなった場合は、このファイル内で済ませてください。
LocalLensApp には押し付けないこと。ワークフローは変わらず、CLI が
それを呼び出す方法だけが増えます。
次は Bun サーバー、長命版のエントリ ポイントです。