LocalLens
ウォークスルー

7. CLI

30 行のエントリポイントで、UI なしに AI のコアが動くことを示す。

src/cli.ts は LocalLens で最も小さなエントリポイントです。argv の値を 2 つ読み、LocalLensApp をインスタンス化し、1 往復走らせて、片付けます。

ファイル全体

src/cli.ts
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 つあります。

  1. JSON ストアにゴミが溜まらない。 CLI を 100 回叩いても、 .locallens/store.json に 100 件のエントリが残ったりしません。
  2. 使い残しのワークスペースが残らない。 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 サーバー、長命版のエントリ ポイントです。

On this page