scai
Version:
> **A local-first AI CLI for understanding, querying, and iterating on large codebases.** > **100% local • No token costs • No cloud • No prompt injection • Private by design**
62 lines (61 loc) • 2.73 kB
JavaScript
// File: src/modules/structuralPreloadStep.ts
import { buildInDepthContext } from "../utils/buildContextualPrompt.js";
import { logInputOutput } from "../utils/promptLogHelper.js";
/**
* Structural preload:
* - Calls buildInDepthContext for candidate files.
* - Extracts structural facts only.
* - Populates analysis.fileAnalysis[path].structural.
* - Does NOT reason or assign relevance.
*/
export const structuralPreloadStep = {
name: "structuralPreload",
description: "Preloads structural KG and code metadata into fileAnalysis without performing reasoning.",
groups: ["analysis"],
run: async (input) => {
const query = input.query ?? "";
const context = input.context;
if (!context?.analysis) {
throw new Error("[structuralPreload] context.analysis is required.");
}
// ---- Ensure fileAnalysis exists (type-safe) ----
if (!context.analysis.fileAnalysis) {
context.analysis.fileAnalysis = {};
}
const fileAnalysis = context.analysis.fileAnalysis;
// ---- Candidate files ----
const candidatePaths = [
...(context.initContext?.relatedFiles ?? []),
];
const uniquePaths = Array.from(new Set(candidatePaths));
if (!uniquePaths.length) {
console.warn("[structuralPreload] No candidate files to preload.");
return { query, data: {} };
}
// ---- Only preload missing structural data ----
const pathsNeedingStructure = uniquePaths.filter((p) => !fileAnalysis[p]?.structural);
if (!pathsNeedingStructure.length)
return { query, data: {} };
// ---- Get structural data (path → structural object) ----
const structuralMap = await buildInDepthContext({
filenames: pathsNeedingStructure,
relatedFiles: context.initContext?.relatedFiles ?? [],
query,
});
// ---- Merge into fileAnalysis ----
for (const [path, structural] of Object.entries(structuralMap)) {
fileAnalysis[path] ?? (fileAnalysis[path] = { semanticAnalyzed: false });
fileAnalysis[path].structural = structural;
}
// ---- Minimal structured log ----
const logSummary = Object.entries(fileAnalysis).map(([path, analysis]) => ({
file: path,
hasStructural: !!analysis.structural,
functions: analysis.structural?.functions?.length ?? 0,
classes: analysis.structural?.classes?.length ?? 0,
imports: analysis.structural?.imports?.length ?? 0,
}));
logInputOutput("structuralPreload", "output", logSummary);
return { query, data: {} };
},
};