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**
75 lines (74 loc) • 2.73 kB
JavaScript
// File: src/modules/selectRelevantSourcesStep.ts
import fs from "fs";
import { logInputOutput } from "../utils/promptLogHelper.js";
/**
* Purpose:
* Mirrors previously selected files into workingFiles.
* - Does NOT promote files based on evidence.
* - Candidate files are left untouched.
* - Rationale is preserved from preFileSearchCheckStep.
*/
export const selectRelevantSourcesStep = {
name: "selectRelevantSources",
description: "Mirrors focus.selectedFiles into workingFiles without reasoning over evidence.",
groups: ["analysis"],
run: async (input) => {
const query = input.query ?? "";
const context = input.context;
if (!context?.analysis?.focus) {
throw new Error("[selectRelevantSources] context.analysis.focus is required.");
}
const selectedFiles = context.analysis.focus.selectedFiles ?? [];
const candidateFiles = context.analysis.focus.candidateFiles ?? [];
const discardedFiles = []; // no reasoning done here
// ---------------------------
// 1️⃣ Populate workingFiles from selectedFiles only
// ---------------------------
const workingFiles = [];
for (const path of selectedFiles) {
let code;
try {
code = fs.readFileSync(path, "utf-8");
}
catch {
code = undefined;
}
workingFiles.push({
path,
code,
selectionReason: "Selected by preFileSearchCheckStep",
});
}
// Deduplicate if anything preexists
const seen = new Set();
context.workingFiles = [
...(context.workingFiles ?? []),
...workingFiles.filter(f => {
if (!f.path || seen.has(f.path))
return false;
seen.add(f.path);
return true;
}),
];
// ---------------------------
// 2️⃣ Preserve focus but update rationale
// ---------------------------
context.analysis.focus = {
selectedFiles,
candidateFiles,
discardedFiles,
rationale: (context.analysis.focus.rationale ?? "") +
"\n[selectRelevantSources] Working files mirrored mechanically from previous selections.",
};
const output = {
query,
data: {
workingFiles: context.workingFiles.map(f => ({ path: f.path })),
selectedFiles,
candidateFiles
},
};
logInputOutput("selectRelevantSources", "output", output.data);
return output;
},
};