UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

166 lines (144 loc) 4.54 kB
/** * Doctor Fix Handler * * Maps check names to fix functions. Supports --fix and --dry-run modes. * All fix operations are idempotent. * * @module aios-core/doctor/fix-handler * @story INS-4.1 */ const path = require('path'); const fs = require('fs'); const { EXPECTED_RULES } = require('./checks/rules-files'); const { EXPECTED_AGENTS } = require('./checks/agent-memory'); /** * Apply fixes for WARN/FAIL results * * @param {Array} results - Check results * @param {Object} context - Doctor context * @returns {Array} Fix results */ async function applyFixes(results, context) { const { projectRoot, frameworkRoot, options } = context; const { dryRun = false } = options; const fixResults = []; for (const result of results) { if (result.status !== 'WARN' && result.status !== 'FAIL') { continue; } const fixer = FIX_MAP[result.check]; if (!fixer) { fixResults.push({ check: result.check, applied: false, message: 'No auto-fix available', }); continue; } try { if (dryRun) { const description = fixer.describe(result, { projectRoot, frameworkRoot }); fixResults.push({ check: result.check, applied: false, message: `[DRY RUN] Would: ${description}`, }); } else { const fixMessage = await fixer.apply(result, { projectRoot, frameworkRoot }); fixResults.push({ check: result.check, applied: true, message: fixMessage, }); } } catch (error) { fixResults.push({ check: result.check, applied: false, message: `Fix failed: ${error.message}`, }); } } return fixResults; } const FIX_MAP = { 'rules-files': { describe(result, { projectRoot, frameworkRoot }) { const rulesSource = path.join(frameworkRoot, '.claude', 'rules'); const rulesTarget = path.join(projectRoot, '.claude', 'rules'); return `Copy missing rules from ${rulesSource} to ${rulesTarget}`; }, async apply(result, { projectRoot, frameworkRoot }) { const rulesSource = path.join(frameworkRoot, '.claude', 'rules'); const rulesTarget = path.join(projectRoot, '.claude', 'rules'); if (!fs.existsSync(rulesTarget)) { fs.mkdirSync(rulesTarget, { recursive: true }); } let copied = 0; for (const file of EXPECTED_RULES) { const targetFile = path.join(rulesTarget, file); const sourceFile = path.join(rulesSource, file); if (!fs.existsSync(targetFile) && fs.existsSync(sourceFile)) { fs.copyFileSync(sourceFile, targetFile); copied++; } } return `Copied ${copied} missing rules files`; }, }, 'agent-memory': { describe() { return 'Create missing MEMORY.md stubs for agents'; }, async apply(result, { projectRoot }) { const agentsDir = path.join(projectRoot, '.aios-core', 'development', 'agents'); let created = 0; for (const agent of EXPECTED_AGENTS) { const memoryPath = path.join(agentsDir, agent, 'MEMORY.md'); const agentDir = path.join(agentsDir, agent); if (!fs.existsSync(memoryPath)) { if (!fs.existsSync(agentDir)) { fs.mkdirSync(agentDir, { recursive: true }); } fs.writeFileSync(memoryPath, `# ${agent} Agent Memory\n\n_Created by aios doctor --fix_\n`); created++; } } return `Created ${created} MEMORY.md stubs`; }, }, 'claude-md': { describe() { return 'Regenerate CLAUDE.md with missing sections'; }, async apply() { return 'CLAUDE.md regeneration requires npx aios-core install --force'; }, }, 'settings-json': { describe() { return 'Regenerate settings.json with boundary deny rules'; }, async apply(result, { frameworkRoot }) { const generatorPath = path.join( frameworkRoot, 'packages', 'installer', 'src', 'generators', 'generate-settings-json', ); try { const generator = require(generatorPath); if (typeof generator.generateSettingsJson === 'function') { await generator.generateSettingsJson(); return 'settings.json regenerated'; } } catch { // Generator not available } return 'settings.json regeneration requires npx aios-core install --force'; }, }, }; module.exports = { applyFixes };