rooflow
Version:
RooFlow installer for VS Code AI-assisted development
286 lines (242 loc) • 8.12 kB
JavaScript
const fs = require("fs");
const path = require("path");
const yaml = require("js-yaml");
// Colors for terminal output
const GREEN = "\x1b[32m";
const BLUE = "\x1b[34m";
const YELLOW = "\x1b[33m";
const RED = "\x1b[31m";
const RESET = "\x1b[0m";
/**
* Fix duplicate capabilities sections in system prompt files
* @param {string} projectRoot - Path to the project root
* @returns {boolean} - True if fixes were successful
*/
function fixDuplicateCapabilities(projectRoot) {
console.log(
"\nChecking system prompt files for duplicate capabilities sections..."
);
const systemPromptFiles = [
".roo/system-prompt-architect",
".roo/system-prompt-ask",
".roo/system-prompt-code",
".roo/system-prompt-debug",
".roo/system-prompt-test",
];
let fixesMade = false;
for (const file of systemPromptFiles) {
const filePath = path.join(projectRoot, file);
if (!fs.existsSync(filePath)) {
console.log(` ${BLUE}${file}${RESET}: File not found, skipping`);
continue;
}
// Read file content
const content = fs.readFileSync(filePath, "utf8");
// Simple check: Count how many times "capabilities:" appears at line start
const matches = content.match(/^capabilities:/gm);
if (!matches || matches.length <= 1) {
console.log(` ${BLUE}${file}${RESET}: No duplicate capabilities found`);
continue;
}
console.log(
` ${BLUE}${file}${RESET}: Found ${matches.length} capabilities sections`
);
// Split the file into YAML documents (sections)
// Each section starts with a non-indented line
const sections = splitIntoSections(content);
// Now find all capabilities sections
const capabilitiesSections = [];
const otherSections = [];
sections.forEach((section) => {
if (section.startsWith("capabilities:")) {
capabilitiesSections.push(section);
} else {
otherSections.push(section);
}
});
// If we have multiple capabilities sections, keep only the first one
if (capabilitiesSections.length > 1) {
// Actually use js-yaml to parse and validate the first capabilities section
try {
// We need to add a root element to make it a valid YAML document
const yamlStr =
"temp_root:\n" +
capabilitiesSections[0]
.split("\n")
.map((line) => " " + line)
.join("\n");
// Parse the YAML to validate it
yaml.load(yamlStr);
// If parsing succeeds, keep only the first capabilities section
const newContent = [
...otherSections.slice(
0,
otherSections.findIndex((s) => s.startsWith("mode:")) + 1
),
capabilitiesSections[0],
...otherSections.slice(
otherSections.findIndex((s) => s.startsWith("mode:")) + 1
),
].join("");
// Write the fixed content back to the file
fs.writeFileSync(filePath, newContent, "utf8");
console.log(
` ${GREEN}Fixed${RESET}: Kept first capabilities section in ${BLUE}${file}${RESET}`
);
fixesMade = true;
} catch (yamlError) {
console.error(
` ${RED}Error${RESET}: Failed to parse capabilities section in ${BLUE}${file}${RESET}: ${yamlError.message}`
);
// Try the second section if the first one failed to parse
try {
const yamlStr =
"temp_root:\n" +
capabilitiesSections[1]
.split("\n")
.map((line) => " " + line)
.join("\n");
yaml.load(yamlStr);
const newContent = [
...otherSections.slice(
0,
otherSections.findIndex((s) => s.startsWith("mode:")) + 1
),
capabilitiesSections[1],
...otherSections.slice(
otherSections.findIndex((s) => s.startsWith("mode:")) + 1
),
].join("");
fs.writeFileSync(filePath, newContent, "utf8");
console.log(
` ${GREEN}Fixed${RESET}: Used second capabilities section in ${BLUE}${file}${RESET} (first had YAML errors)`
);
fixesMade = true;
} catch (secondYamlError) {
console.error(
` ${RED}Error${RESET}: Both capabilities sections have YAML errors in ${BLUE}${file}${RESET}`
);
}
}
}
}
if (fixesMade) {
console.log(
`${GREEN}Fixed duplicate capabilities sections in system prompt files${RESET}`
);
} else {
console.log("No duplicate capabilities sections found or fixed");
}
return true;
}
/**
* Validate system prompt files using js-yaml
* @param {string} projectRoot - Path to the project root
* @returns {boolean} - True if all files are valid
*/
function validateFilesWithYaml(projectRoot) {
console.log("\nValidating system prompt files with js-yaml...");
const systemPromptFiles = [
".roo/system-prompt-architect",
".roo/system-prompt-ask",
".roo/system-prompt-code",
".roo/system-prompt-debug",
".roo/system-prompt-test",
];
let allValid = true;
for (const file of systemPromptFiles) {
const filePath = path.join(projectRoot, file);
if (!fs.existsSync(filePath)) {
console.log(` ${BLUE}${file}${RESET}: File not found, skipping`);
continue;
}
// Read file content
const content = fs.readFileSync(filePath, "utf8");
// Check for duplicate capabilities sections first
const matches = content.match(/^capabilities:/gm);
if (matches && matches.length > 1) {
console.log(
` ${YELLOW}Warning${RESET}: ${BLUE}${file}${RESET} still has ${matches.length} capabilities sections`
);
allValid = false;
continue;
}
// Split into sections
const sections = splitIntoSections(content);
// Validate each section that looks like YAML with js-yaml
let invalidSections = 0;
for (const section of sections) {
// Only try to validate sections that look like YAML
if (section.includes(":")) {
try {
// Add temp root to make it a valid YAML document
const yamlStr =
"temp_root:\n" +
section
.split("\n")
.map((line) => " " + line)
.join("\n");
yaml.load(yamlStr);
} catch (yamlError) {
invalidSections++;
console.log(
` ${YELLOW}Warning${RESET}: Invalid YAML in section starting with: ${section
.substring(0, 40)
.replace(/\n/g, "\\n")}...`
);
console.log(` Error: ${yamlError.message}`);
}
}
}
if (invalidSections > 0) {
console.log(
` ${YELLOW}Warning${RESET}: ${BLUE}${file}${RESET} has ${invalidSections} sections with YAML errors`
);
} else {
console.log(
` ${GREEN}Valid${RESET}: ${BLUE}${file}${RESET} - All YAML sections validated successfully`
);
}
}
if (allValid) {
console.log(
`${GREEN}All system prompt files validated successfully${RESET}`
);
} else {
console.log(
`${YELLOW}Warning${RESET}: Some files have issues that may need attention`
);
}
return allValid;
}
/**
* Helper function to split content into sections
* @param {string} content - File content
* @returns {string[]} - Array of sections
*/
function splitIntoSections(content) {
const sections = [];
let currentSection = "";
content.split("\n").forEach((line) => {
if (line.trim() !== "" && !line.startsWith(" ") && !line.startsWith("\t")) {
// This is the start of a new section
if (currentSection) {
sections.push(currentSection);
}
currentSection = line + "\n";
} else {
currentSection += line + "\n";
}
});
// Add the last section
if (currentSection) {
sections.push(currentSection);
}
return sections;
}
// Export the functions
module.exports = {
fixDuplicateCapabilities,
validateFilesWithYaml,
};