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**
134 lines (133 loc) • 4.2 kB
JavaScript
// File: src/modules/cleanupModule.ts
import chalk from "chalk";
/** --- Helper: detect top/bottom fluff/noise --- */
function isTopOrBottomNoise(line) {
const trimmed = line.trim();
if (!trimmed)
return true;
if (/^```(?:\w+)?$/.test(trimmed))
return true;
if (/^<!--.*-->$/.test(trimmed))
return true;
const lower = trimmed.toLowerCase();
return [
/^i\s/i,
/^here/iu,
/^this/iu,
/^the following/iu,
/^below/iu,
/^in this/iu,
/^we have/iu,
/the code above/iu,
/ensures that/iu,
/it handles/iu,
/used to/iu,
/note that/iu,
/example/iu,
/summary/iu,
/added comments/iu,
].some((pattern) => pattern.test(lower));
}
/** --- Extract first JSON object or array slice --- */
function extractJsonSlice(text) {
const objStart = text.indexOf("{");
const objEnd = text.lastIndexOf("}");
if (objStart !== -1 && objEnd > objStart)
return text.slice(objStart, objEnd + 1);
const arrStart = text.indexOf("[");
const arrEnd = text.lastIndexOf("]");
if (arrStart !== -1 && arrEnd > arrStart)
return text.slice(arrStart, arrEnd + 1);
return null;
}
/** --- Escape raw newlines inside JSON string literals --- */
function escapeNewlinesInJsonStrings(input) {
let output = "";
let inString = false;
let escaped = false;
for (let i = 0; i < input.length; i++) {
const ch = input[i];
if (escaped) {
escaped = false;
output += ch;
continue;
}
if (ch === "\\") {
escaped = true;
output += ch;
continue;
}
if (ch === '"') {
inString = !inString;
output += ch;
continue;
}
if (inString && ch === "\n") {
output += "\\n";
continue;
}
output += ch;
}
return output;
}
/** --- Try parsing JSON with multiple fallbacks --- */
function parseJsonWithFallback(content) {
try {
return JSON.parse(content);
}
catch { }
const slice = extractJsonSlice(content);
if (slice) {
try {
return JSON.parse(slice);
}
catch { }
}
// Fallback: escape raw newlines inside string literals (markdown/text in JSON)
try {
const escaped = escapeNewlinesInJsonStrings(content);
return JSON.parse(escaped);
}
catch { }
return null;
}
/** --- Module --- */
export const cleanupModule = {
name: "cleanup",
description: "Cleans up AI output, removes noise, and extracts valid JSON if possible.",
groups: ["transform"],
async run(input) {
// --- Normalize input ---
let content = typeof input.content === "string"
? input.content
: JSON.stringify(input.content ?? "");
content = content.replace(/\r\n/g, "\n");
// --- Trim top/bottom noise ---
let lines = content.split("\n");
while (lines.length && isTopOrBottomNoise(lines[0]))
lines.shift();
while (lines.length && isTopOrBottomNoise(lines[lines.length - 1]))
lines.pop();
content = lines.join("\n").trim();
// --- Remove fences, HTML comments, thinking tags ---
content = content
.replace(/```(?:json)?/gi, "")
.replace(/```/g, "")
.replace(/<!--.*?-->/gs, "")
.replace(/<think>[\s\S]*?<\/think>/gi, "")
.trim();
// --- Attempt parsing ---
let parsed = null;
if (content.includes("{") || content.includes("[")) {
parsed = parseJsonWithFallback(content);
}
if (parsed !== null) {
return { query: input.query, content, data: parsed };
}
// --- Fallback: return raw cleaned text ---
// Use console.debug instead of warn so logs are quieter
process.stdout.write("\r\x1b[K");
console.debug(chalk.yellow(` - [cleanupModule] Could not parse JSON, returning raw content.`));
return { query: input.query, content, data: content };
},
};