UNPKG

automagik-genie

Version:

Self-evolving AI agent orchestration framework with Model Context Protocol support

217 lines (216 loc) 7.25 kB
#!/usr/bin/env node "use strict"; /** * Migrate agent frontmatter from old schema to new schema * * Old schema: * genie: * executor: CLAUDE_CODE * executorVariant: DEFAULT * model: sonnet * dangerously_skip_permissions: false * * New schema: * genie: * executor: CLAUDE_CODE * variant: DEFAULT * background: true * forge: * model: claude-sonnet-4-5-20250929 * dangerously_skip_permissions: false */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.migrateDirectory = migrateDirectory; exports.migrateFile = migrateFile; exports.extractFrontMatter = extractFrontMatter; exports.migrateFrontmatter = migrateFrontmatter; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const yaml_1 = require("yaml"); // Fields that should move from genie.* to forge.* const FORGE_FIELDS = [ 'model', 'dangerously_skip_permissions', 'sandbox', 'dangerously_allow_all', 'model_reasoning_effort', 'model_reasoning_summary', 'model_reasoning_summary_format', 'profile', 'base_instructions', 'include_plan_tool', 'include_apply_patch_tool', 'claude_code_router', 'plan', 'approvals', 'base_command_override', 'additional_params', 'ask_for_approval', 'oss', 'force', 'yolo', 'allow_all_tools', 'allow_tool', 'deny_tool', 'add_dir', 'disable_mcp_server', 'agent' ]; // Fields that stay in genie.* const GENIE_FIELDS = [ 'executor', 'variant', // Will be renamed from executorVariant 'background' ]; function extractFrontMatter(content) { const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/); if (!match) { return null; } return { frontmatter: match[1], body: match[2] }; } function migrateFrontmatter(frontmatter) { const migrated = { ...frontmatter }; const movedFields = []; // Initialize forge object if genie has executor fields if (migrated.genie) { migrated.forge = migrated.forge || {}; // Rename executorVariant to variant if (migrated.genie.executorVariant !== undefined) { migrated.genie.variant = migrated.genie.executorVariant; delete migrated.genie.executorVariant; movedFields.push('executorVariant → variant'); } // Move executor-specific fields to forge namespace for (const field of FORGE_FIELDS) { if (migrated.genie[field] !== undefined) { migrated.forge[field] = migrated.genie[field]; delete migrated.genie[field]; movedFields.push(`genie.${field} → forge.${field}`); } } // Clean up empty genie object if (Object.keys(migrated.genie).length === 0) { delete migrated.genie; } // Clean up empty forge object if (Object.keys(migrated.forge).length === 0) { delete migrated.forge; } } return { migrated, movedFields }; } async function migrateFile(filePath) { const content = fs_1.default.readFileSync(filePath, 'utf-8'); const parsed = extractFrontMatter(content); if (!parsed) { throw new Error('No frontmatter found'); } const frontmatter = (0, yaml_1.parse)(parsed.frontmatter); const { migrated, movedFields } = migrateFrontmatter(frontmatter); // Only write if changes were made if (movedFields.length === 0) { return []; } // Reconstruct file with migrated frontmatter const newFrontmatter = (0, yaml_1.stringify)(migrated, { lineWidth: 0, // Don't wrap lines defaultStringType: 'PLAIN' }); const newContent = `---\n${newFrontmatter}---\n${parsed.body}`; fs_1.default.writeFileSync(filePath, newContent, 'utf-8'); return movedFields; } function findMarkdownFiles(dir, skipDirs = []) { const files = []; const entries = fs_1.default.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path_1.default.join(dir, entry.name); if (entry.isDirectory()) { // Skip certain directories if (skipDirs.includes(entry.name)) { continue; } // Recursively search subdirectories files.push(...findMarkdownFiles(fullPath, skipDirs)); } else if (entry.isFile() && entry.name.endsWith('.md')) { files.push(fullPath); } } return files; } async function migrateDirectory(dir) { const stats = { totalFiles: 0, migratedFiles: 0, skippedFiles: 0, errors: [], changes: [] }; // Find all .md files recursively, skipping certain directories const skipDirs = ['node_modules', 'dist', '.git', 'spells', 'workflows', 'reports', 'wishes']; const files = findMarkdownFiles(dir, skipDirs); stats.totalFiles = files.length; for (const file of files) { try { const movedFields = await migrateFile(file); if (movedFields.length > 0) { stats.migratedFiles++; stats.changes.push({ file: path_1.default.relative(dir, file), movedFields }); console.log(`✓ Migrated: ${path_1.default.relative(dir, file)} (${movedFields.length} changes)`); } else { stats.skippedFiles++; } } catch (error) { stats.errors.push(`${path_1.default.relative(dir, file)}: ${error.message}`); console.warn(`⚠ Skipped: ${path_1.default.relative(dir, file)} - ${error.message}`); } } return stats; } async function main() { const args = process.argv.slice(2); const targetDir = args[0] || '.genie'; if (!fs_1.default.existsSync(targetDir)) { console.error(`❌ Directory not found: ${targetDir}`); process.exit(1); } console.log(`🔄 Migrating frontmatter in: ${targetDir}\n`); const stats = await migrateDirectory(targetDir); console.log('\n📊 Migration Summary:'); console.log(` Total files scanned: ${stats.totalFiles}`); console.log(` Files migrated: ${stats.migratedFiles}`); console.log(` Files skipped (no changes): ${stats.skippedFiles}`); console.log(` Errors: ${stats.errors.length}`); if (stats.errors.length > 0) { console.log('\n⚠️ Errors:'); stats.errors.forEach(err => console.log(` - ${err}`)); } if (stats.changes.length > 0) { console.log('\n📝 Changes made:'); stats.changes.forEach(change => { console.log(` ${change.file}:`); change.movedFields.forEach(field => console.log(` - ${field}`)); }); } console.log('\n✅ Migration complete!'); } // Run if executed directly if (require.main === module) { main().catch(error => { console.error('❌ Migration failed:', error); process.exit(1); }); }