UNPKG

scai

Version:

> **AI-powered CLI for local code analysis, commit message suggestions, and natural-language queries.** 100% local, private, GDPR-friendly, made in Denmark/EU with ❤️.

110 lines (106 loc) 3.39 kB
import { getDbForRepo } from "../db/client.js"; import { generate } from "../lib/generate.js"; import { cleanupModule } from "../pipeline/modules/cleanupModule.js"; import path from "path"; export async function generateFolderCapsules() { const db = getDbForRepo(); // --- Load files (paths only) --- const files = db .prepare(`SELECT path FROM files`) .all(); // --- Group files by folder --- const folders = new Map(); for (const { path: filePath } of files) { const dir = path.dirname(filePath) || "/"; const depth = dir === "/" ? 0 : dir.split("/").length; if (!folders.has(dir)) { folders.set(dir, { path: dir, depth, files: [], }); } folders.get(dir).files.push({ name: path.basename(filePath), ext: path.extname(filePath).replace(".", "") || "unknown", }); } // --- Generate one capsule per folder --- for (const folder of folders.values()) { const byType = {}; for (const f of folder.files) { byType[f.ext] = (byType[f.ext] ?? 0) + 1; } const inputPayload = { path: folder.path, depth: folder.depth, fileCount: folder.files.length, byType, files: folder.files.map((f) => f.name), }; const input = { query: `Generate a FolderCapsule for ${folder.path}`, content: ` You are generating a structured FolderCapsule describing the architectural role of a folder. Return ONLY valid JSON matching this TypeScript interface: interface FolderCapsule { path: string; depth: number; stats: { fileCount: number; byType: Record<string, number>; }; roles: string[]; concerns: string[]; keyFiles: { path: string; reason: string }[]; dependencies: { importsFrom: string[]; usedBy: string[]; }; confidence: number; } Folder facts: ${JSON.stringify(inputPayload, null, 2)} `.trim(), }; const response = await generate(input); // --- Cleanup model output --- const cleaned = await cleanupModule.run({ query: input.query, content: response.content, }); let capsule = null; try { capsule = JSON.parse(String(cleaned.content)); } catch { console.warn(`⚠️ Failed to parse FolderCapsule for ${folder.path}`); continue; } db.prepare(` INSERT INTO folder_capsules (path, depth, capsule_json, confidence, last_generated, source_file_count) VALUES ( @path, @depth, @capsule_json, @confidence, datetime('now'), @source_file_count ) ON CONFLICT(path) DO UPDATE SET capsule_json = excluded.capsule_json, confidence = excluded.confidence, last_generated = datetime('now'), source_file_count = excluded.source_file_count `).run({ path: folder.path, depth: folder.depth, capsule_json: JSON.stringify(capsule), confidence: capsule?.confidence ?? null, source_file_count: folder.files.length, }); console.log(`📦 Folder capsule generated for ${folder.path}`); } }