feat: remove heuristics, go LLM-only with mocks + restructure

BREAKING: Heuristic fallback removed — LLM client now required

Changes:
- Remove extractFileHeuristic, extractPackageHeuristic, all helpers
- extractFileLLM / extractPackageLLM now throw LLMError when client missing
- Add hybrid binary detection: extension blacklist + content sniffing
- Increase file size limit: 50KB → 500KB (text files only)
- Restructure src/ into subdirectories:
  - src/llm/ — all LLM clients, extract, batch, cache, error
  - src/ast/ — AST extraction
  - src/cli/ — CLI entry point
- Update all imports across codebase and tests
- Add tests/mock-llm.ts helper for deterministic mock clients
- Update all tests to use mock LLM clients (no heuristics dependency)
- All 52 tests passing (including 8 real LLM integration tests)
This commit is contained in:
2026-06-10 17:34:37 +02:00
parent d948d88d0a
commit 2f198ea0d2
23 changed files with 382 additions and 507 deletions
+5 -5
View File
@@ -2,9 +2,9 @@ import { describe, it, expect } from "vitest";
import { writeFileSync, mkdtempSync, readFileSync } from "fs";
import { join } from "path";
import { tmpdir } from "os";
import { createLLMClient } from "../src/llm-client.js";
import { extractFileLLM, extractPackageLLM } from "../src/llm-extract.js";
import { processFiles } from "../src/llm-batch.js";
import { createLLMClient } from "../src/llm/llm-client.js";
import { extractFileLLM, extractPackageLLM } from "../src/llm/llm-extract.js";
import { processFiles } from "../src/llm/llm-batch.js";
// Load .env file manually (no dotenv dependency needed)
function loadEnv(): Record<string, string> {
@@ -135,7 +135,7 @@ describe.skipIf(!hasKimiKey)("LLM integration with Kimi", () => {
it("skips large files without calling LLM", async () => {
const dir = mkdtempSync(join(tmpdir(), "pi-map-llm-"));
const file = join(dir, "big.ts");
writeFileSync(file, "x".repeat(60 * 1024));
writeFileSync(file, "x".repeat(600 * 1024));
let calls = 0;
const trackingClient = createLLMClient("kimi", { model: kimiModel });
@@ -146,7 +146,7 @@ describe.skipIf(!hasKimiKey)("LLM integration with Kimi", () => {
};
const result = await extractFileLLM(file, trackingClient, dir);
expect(result.purpose).toBe("Large/generated file");
expect(result.purpose).toBe("Large file");
expect(calls).toBe(0); // Should never call LLM for large files
});
});