claude-flow
Version:
Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration
742 lines • 32.1 kB
JavaScript
/**
* V3 CLI Migrate Command
* Migration tools for V2 to V3 transition
*/
import { output } from '../output.js';
import * as fs from 'fs';
import * as path from 'path';
// Migration targets
const MIGRATION_TARGETS = [
{ value: 'config', label: 'Configuration', hint: 'Migrate configuration files' },
{ value: 'memory', label: 'Memory Data', hint: 'Migrate memory/database content' },
{ value: 'agents', label: 'Agent Configs', hint: 'Migrate agent configurations' },
{ value: 'hooks', label: 'Hooks', hint: 'Migrate hook definitions' },
{ value: 'workflows', label: 'Workflows', hint: 'Migrate workflow definitions' },
{ value: 'embeddings', label: 'Embeddings', hint: 'Migrate to ONNX with hyperbolic support' },
{ value: 'all', label: 'All', hint: 'Full migration' }
];
// Status command
const statusCommand = {
name: 'status',
description: 'Check migration status',
action: async (ctx) => {
const cwd = ctx.cwd || process.cwd();
const components = [];
// Check v2 config: claude-flow.config.json with version "2" or missing version
const v2ConfigPath = path.join(cwd, 'claude-flow.config.json');
const v3ConfigDir = path.join(cwd, '.claude-flow');
let hasV2Config = false;
let hasV3Config = false;
try {
if (fs.existsSync(v2ConfigPath)) {
const raw = fs.readFileSync(v2ConfigPath, 'utf-8');
const parsed = JSON.parse(raw);
if (parsed.version === '2' || parsed.version === 2 || !parsed.version) {
hasV2Config = true;
}
}
}
catch { /* ignore parse errors */ }
try {
hasV3Config = fs.existsSync(v3ConfigDir) && fs.statSync(v3ConfigDir).isDirectory();
}
catch { /* ignore */ }
if (hasV2Config && hasV3Config) {
components.push({ component: 'Config', status: 'v2 + v3', migrationNeeded: 'no' });
}
else if (hasV2Config) {
components.push({ component: 'Config', status: 'v2', migrationNeeded: 'yes' });
}
else if (hasV3Config) {
components.push({ component: 'Config', status: 'v3', migrationNeeded: 'no' });
}
else {
components.push({ component: 'Config', status: 'missing', migrationNeeded: 'no' });
}
// Check v2 memory: ./data/memory/*.json or memory.db
const v2MemoryDir = path.join(cwd, 'data', 'memory');
let hasV2MemoryJson = false;
let hasV2MemoryDb = false;
try {
if (fs.existsSync(v2MemoryDir)) {
const files = fs.readdirSync(v2MemoryDir);
hasV2MemoryJson = files.some(f => f.endsWith('.json'));
hasV2MemoryDb = files.includes('memory.db');
}
}
catch { /* ignore */ }
if (hasV2MemoryJson || hasV2MemoryDb) {
components.push({ component: 'Memory', status: 'v2', migrationNeeded: 'yes' });
}
else {
components.push({ component: 'Memory', status: 'missing', migrationNeeded: 'no' });
}
// Check v2 sessions: ./data/sessions/
const v2SessionsDir = path.join(cwd, 'data', 'sessions');
let hasV2Sessions = false;
try {
if (fs.existsSync(v2SessionsDir)) {
const files = fs.readdirSync(v2SessionsDir);
hasV2Sessions = files.length > 0;
}
}
catch { /* ignore */ }
if (hasV2Sessions) {
components.push({ component: 'Sessions', status: 'v2', migrationNeeded: 'yes' });
}
else {
components.push({ component: 'Sessions', status: 'missing', migrationNeeded: 'no' });
}
// Check migration state
const migrationStatePath = path.join(cwd, '.claude-flow', 'migration-state.json');
let migrationState = null;
try {
if (fs.existsSync(migrationStatePath)) {
const raw = fs.readFileSync(migrationStatePath, 'utf-8');
const parsed = JSON.parse(raw);
migrationState = parsed.status || 'unknown';
}
}
catch { /* ignore */ }
if (migrationState) {
components.push({ component: 'Migration State', status: migrationState, migrationNeeded: 'no' });
}
// Display results
if (ctx.flags.format === 'json') {
output.printJson({ components, migrationState });
return { success: true, data: { components, migrationState } };
}
output.writeln();
output.writeln(output.bold('Migration Status'));
output.writeln();
output.printTable({
columns: [
{ key: 'component', header: 'Component', width: 20 },
{ key: 'status', header: 'Status', width: 15 },
{ key: 'migrationNeeded', header: 'Migration Needed', width: 20 }
],
data: components.map(c => ({
component: c.component,
status: formatMigrationStatus(c.status),
migrationNeeded: c.migrationNeeded === 'yes' ? output.warning('yes') : output.dim('no')
})),
border: false
});
const needsMigration = components.some(c => c.migrationNeeded === 'yes');
output.writeln();
if (needsMigration) {
output.printInfo('V2 artifacts detected. Run "claude-flow migrate run" to migrate.');
}
else {
output.printSuccess('No migration needed.');
}
return { success: true, data: { components, needsMigration } };
}
};
// Run migration
const runCommand = {
name: 'run',
description: 'Run migration',
options: [
{
name: 'target',
short: 't',
description: 'Migration target',
type: 'string',
choices: MIGRATION_TARGETS.map(t => t.value)
},
{
name: 'dry-run',
description: 'Show what would be migrated without making changes',
type: 'boolean',
default: false
},
{
name: 'backup',
description: 'Create backup before migration',
type: 'boolean',
default: true
},
{
name: 'force',
short: 'f',
description: 'Force migration (overwrite existing)',
type: 'boolean',
default: false
}
],
action: async (ctx) => {
const cwd = ctx.cwd || process.cwd();
const dryRun = ctx.flags['dry-run'] === true;
const skipBackup = ctx.flags.backup === false;
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const v3Dir = path.join(cwd, '.claude-flow');
const backupDir = path.join(v3Dir, 'backup', `v2-${timestamp}`);
const migrationStatePath = path.join(v3Dir, 'migration-state.json');
const migrated = [];
const skipped = [];
output.writeln();
output.writeln(output.bold('V2 to V3 Migration'));
if (dryRun) {
output.printWarning('Dry run mode — no changes will be made.');
}
output.writeln();
// Ensure .claude-flow directory exists
if (!dryRun) {
fs.mkdirSync(v3Dir, { recursive: true });
}
// --- Backup ---
if (!skipBackup && !dryRun) {
output.writeln(output.dim('Creating backup...'));
fs.mkdirSync(backupDir, { recursive: true });
}
// --- Config migration ---
const v2ConfigPath = path.join(cwd, 'claude-flow.config.json');
try {
if (fs.existsSync(v2ConfigPath)) {
const raw = fs.readFileSync(v2ConfigPath, 'utf-8');
const parsed = JSON.parse(raw);
if (parsed.version === '2' || parsed.version === 2 || !parsed.version) {
if (dryRun) {
output.printInfo(`Would migrate config: ${v2ConfigPath}`);
}
else {
// Backup
if (!skipBackup) {
fs.copyFileSync(v2ConfigPath, path.join(backupDir, 'claude-flow.config.json'));
}
// Transform to v3 format
const v3Config = { ...parsed, version: '3' };
// Rename swarm.mode -> swarm.topology if present
if (v3Config.swarm && typeof v3Config.swarm === 'object') {
const swarm = v3Config.swarm;
if ('mode' in swarm && !('topology' in swarm)) {
swarm.topology = swarm.mode;
delete swarm.mode;
}
}
// Rename memory.type -> memory.backend if present
if (v3Config.memory && typeof v3Config.memory === 'object') {
const mem = v3Config.memory;
if ('type' in mem && !('backend' in mem)) {
mem.backend = mem.type;
delete mem.type;
}
}
const v3ConfigPath = path.join(v3Dir, 'config.json');
fs.writeFileSync(v3ConfigPath, JSON.stringify(v3Config, null, 2));
output.printSuccess(`Config migrated to ${v3ConfigPath}`);
}
migrated.push('config');
}
else {
output.printInfo('Config already at v3 — skipping.');
skipped.push('config');
}
}
else {
output.writeln(output.dim('No v2 config found — skipping config migration.'));
skipped.push('config');
}
}
catch (err) {
output.printError('Config migration failed', String(err));
skipped.push('config');
}
// --- Memory migration ---
const v2MemoryDir = path.join(cwd, 'data', 'memory');
try {
if (fs.existsSync(v2MemoryDir)) {
const files = fs.readdirSync(v2MemoryDir);
const jsonFiles = files.filter(f => f.endsWith('.json'));
const hasDb = files.includes('memory.db');
if (jsonFiles.length > 0 || hasDb) {
if (dryRun) {
output.printInfo(`Would migrate memory: ${jsonFiles.length} JSON files, ${hasDb ? '1 DB' : 'no DB'}`);
}
else {
// Backup memory files
if (!skipBackup) {
const memBackup = path.join(backupDir, 'data', 'memory');
fs.mkdirSync(memBackup, { recursive: true });
for (const f of files) {
const src = path.join(v2MemoryDir, f);
if (fs.statSync(src).isFile()) {
fs.copyFileSync(src, path.join(memBackup, f));
}
}
}
output.printSuccess(`Memory files backed up (${jsonFiles.length} JSON, ${hasDb ? '1 DB' : '0 DB'}).`);
output.printInfo('Run "claude-flow memory init --force" to import v2 memory into v3 AgentDB.');
}
migrated.push('memory');
}
else {
output.writeln(output.dim('No v2 memory files found — skipping.'));
skipped.push('memory');
}
}
else {
output.writeln(output.dim('No v2 memory directory found — skipping.'));
skipped.push('memory');
}
}
catch (err) {
output.printError('Memory migration failed', String(err));
skipped.push('memory');
}
// --- Session migration ---
const v2SessionsDir = path.join(cwd, 'data', 'sessions');
try {
if (fs.existsSync(v2SessionsDir)) {
const files = fs.readdirSync(v2SessionsDir);
if (files.length > 0) {
if (dryRun) {
output.printInfo(`Would migrate sessions: ${files.length} files from ${v2SessionsDir}`);
}
else {
const v3SessionsDir = path.join(v3Dir, 'sessions');
fs.mkdirSync(v3SessionsDir, { recursive: true });
// Backup
if (!skipBackup) {
const sessBackup = path.join(backupDir, 'data', 'sessions');
fs.mkdirSync(sessBackup, { recursive: true });
for (const f of files) {
const src = path.join(v2SessionsDir, f);
if (fs.statSync(src).isFile()) {
fs.copyFileSync(src, path.join(sessBackup, f));
}
}
}
// Copy to v3 location
for (const f of files) {
const src = path.join(v2SessionsDir, f);
if (fs.statSync(src).isFile()) {
fs.copyFileSync(src, path.join(v3SessionsDir, f));
}
}
output.printSuccess(`Sessions migrated: ${files.length} files to ${v3SessionsDir}`);
}
migrated.push('sessions');
}
else {
output.writeln(output.dim('No v2 session files found — skipping.'));
skipped.push('sessions');
}
}
else {
output.writeln(output.dim('No v2 sessions directory found — skipping.'));
skipped.push('sessions');
}
}
catch (err) {
output.printError('Session migration failed', String(err));
skipped.push('sessions');
}
// --- Save migration state ---
if (!dryRun && migrated.length > 0) {
const state = {
status: 'completed',
timestamp,
backupPath: skipBackup ? null : backupDir,
migrated,
skipped
};
fs.writeFileSync(migrationStatePath, JSON.stringify(state, null, 2));
output.writeln();
output.printSuccess(`Migration state saved to ${migrationStatePath}`);
}
// Summary
output.writeln();
if (dryRun) {
output.printInfo(`Dry run complete. ${migrated.length} component(s) would be migrated.`);
}
else if (migrated.length > 0) {
output.printSuccess(`Migration complete. ${migrated.length} component(s) migrated: ${migrated.join(', ')}`);
output.printInfo('Run "claude-flow migrate verify" to validate the migration.');
}
else {
output.printInfo('Nothing to migrate.');
}
return { success: true, data: { migrated, skipped, dryRun } };
}
};
// Verify migration
const verifyCommand = {
name: 'verify',
description: 'Verify migration integrity',
options: [
{
name: 'fix',
description: 'Automatically fix issues',
type: 'boolean',
default: false
}
],
action: async (ctx) => {
const cwd = ctx.cwd || process.cwd();
const v3Dir = path.join(cwd, '.claude-flow');
const migrationStatePath = path.join(v3Dir, 'migration-state.json');
const checks = [];
let allPassed = true;
output.writeln();
output.writeln(output.bold('Migration Verification'));
output.writeln();
// Check 1: Migration state file exists
let migrationState = null;
try {
if (fs.existsSync(migrationStatePath)) {
const raw = fs.readFileSync(migrationStatePath, 'utf-8');
migrationState = JSON.parse(raw);
checks.push({ check: 'Migration state file', result: 'passed' });
}
else {
checks.push({ check: 'Migration state file', result: 'failed' });
allPassed = false;
}
}
catch {
checks.push({ check: 'Migration state file', result: 'failed' });
allPassed = false;
}
// Check 2: V3 config exists and is valid JSON
const v3ConfigPath = path.join(v3Dir, 'config.json');
try {
if (fs.existsSync(v3ConfigPath)) {
const raw = fs.readFileSync(v3ConfigPath, 'utf-8');
JSON.parse(raw); // validate JSON
checks.push({ check: 'V3 config (valid JSON)', result: 'passed' });
}
else {
// Config might not have been migrated if there was no v2 config
const wasMigrated = migrationState &&
Array.isArray(migrationState.migrated) &&
migrationState.migrated.includes('config');
if (wasMigrated) {
checks.push({ check: 'V3 config (valid JSON)', result: 'failed' });
allPassed = false;
}
else {
checks.push({ check: 'V3 config (valid JSON)', result: 'skipped' });
}
}
}
catch {
checks.push({ check: 'V3 config (valid JSON)', result: 'failed' });
allPassed = false;
}
// Check 3: Backup exists
if (migrationState && migrationState.backupPath) {
const backupPath = migrationState.backupPath;
try {
if (fs.existsSync(backupPath) && fs.statSync(backupPath).isDirectory()) {
checks.push({ check: 'Backup directory', result: 'passed' });
}
else {
checks.push({ check: 'Backup directory', result: 'failed' });
allPassed = false;
}
}
catch {
checks.push({ check: 'Backup directory', result: 'failed' });
allPassed = false;
}
}
else if (migrationState && migrationState.backupPath === null) {
checks.push({ check: 'Backup directory', result: 'skipped (backup was disabled)' });
}
else {
checks.push({ check: 'Backup directory', result: 'failed' });
allPassed = false;
}
// Check 4: V3 sessions directory if sessions were migrated
if (migrationState &&
Array.isArray(migrationState.migrated) &&
migrationState.migrated.includes('sessions')) {
const v3Sessions = path.join(v3Dir, 'sessions');
try {
if (fs.existsSync(v3Sessions) && fs.readdirSync(v3Sessions).length > 0) {
checks.push({ check: 'V3 sessions directory', result: 'passed' });
}
else {
checks.push({ check: 'V3 sessions directory', result: 'failed' });
allPassed = false;
}
}
catch {
checks.push({ check: 'V3 sessions directory', result: 'failed' });
allPassed = false;
}
}
// Display
if (ctx.flags.format === 'json') {
output.printJson({ checks, allPassed });
return { success: allPassed, data: { checks, allPassed } };
}
output.printTable({
columns: [
{ key: 'check', header: 'Check', width: 30 },
{ key: 'result', header: 'Result', width: 35 }
],
data: checks.map(c => ({
check: c.check,
result: formatMigrationStatus(c.result)
})),
border: false
});
output.writeln();
if (allPassed) {
output.printSuccess('All verification checks passed.');
}
else {
output.printError('Some verification checks failed.');
output.printInfo('Run "claude-flow migrate run" to re-run the migration, or "migrate rollback" to restore from backup.');
}
return { success: allPassed, data: { checks, allPassed }, exitCode: allPassed ? 0 : 1 };
}
};
// Rollback migration
const rollbackCommand = {
name: 'rollback',
description: 'Rollback to previous version',
options: [
{
name: 'backup-id',
description: 'Backup ID to restore',
type: 'string'
},
{
name: 'force',
short: 'f',
description: 'Skip confirmation',
type: 'boolean',
default: false
}
],
action: async (ctx) => {
const cwd = ctx.cwd || process.cwd();
const v3Dir = path.join(cwd, '.claude-flow');
const migrationStatePath = path.join(v3Dir, 'migration-state.json');
output.writeln();
output.writeln(output.bold('Migration Rollback'));
output.writeln();
// Read migration state
let migrationState;
try {
if (!fs.existsSync(migrationStatePath)) {
output.printError('No migration state found.', 'Run "migrate run" first before attempting rollback.');
return { success: false, exitCode: 1 };
}
const raw = fs.readFileSync(migrationStatePath, 'utf-8');
migrationState = JSON.parse(raw);
}
catch (err) {
output.printError('Failed to read migration state', String(err));
return { success: false, exitCode: 1 };
}
const backupPath = migrationState.backupPath;
if (!backupPath) {
output.printError('No backup path in migration state.', 'Migration was run with --no-backup. Cannot rollback.');
return { success: false, exitCode: 1 };
}
if (!fs.existsSync(backupPath)) {
output.printError('Backup directory not found.', `Expected: ${backupPath}`);
return { success: false, exitCode: 1 };
}
const restored = [];
try {
// Restore config
const backupConfig = path.join(backupPath, 'claude-flow.config.json');
if (fs.existsSync(backupConfig)) {
const destConfig = path.join(cwd, 'claude-flow.config.json');
fs.copyFileSync(backupConfig, destConfig);
// Remove v3 config
const v3Config = path.join(v3Dir, 'config.json');
if (fs.existsSync(v3Config)) {
fs.unlinkSync(v3Config);
}
output.printSuccess('Restored: config');
restored.push('config');
}
// Restore memory
const backupMemory = path.join(backupPath, 'data', 'memory');
if (fs.existsSync(backupMemory)) {
const destMemory = path.join(cwd, 'data', 'memory');
fs.mkdirSync(destMemory, { recursive: true });
const files = fs.readdirSync(backupMemory);
for (const f of files) {
fs.copyFileSync(path.join(backupMemory, f), path.join(destMemory, f));
}
output.printSuccess(`Restored: memory (${files.length} files)`);
restored.push('memory');
}
// Restore sessions
const backupSessions = path.join(backupPath, 'data', 'sessions');
if (fs.existsSync(backupSessions)) {
const destSessions = path.join(cwd, 'data', 'sessions');
fs.mkdirSync(destSessions, { recursive: true });
const files = fs.readdirSync(backupSessions);
for (const f of files) {
fs.copyFileSync(path.join(backupSessions, f), path.join(destSessions, f));
}
// Remove v3 sessions
const v3Sessions = path.join(v3Dir, 'sessions');
if (fs.existsSync(v3Sessions)) {
const v3Files = fs.readdirSync(v3Sessions);
for (const f of v3Files) {
fs.unlinkSync(path.join(v3Sessions, f));
}
fs.rmdirSync(v3Sessions);
}
output.printSuccess(`Restored: sessions (${files.length} files)`);
restored.push('sessions');
}
// Delete migration state
fs.unlinkSync(migrationStatePath);
output.writeln();
output.printSuccess(`Rollback complete. Restored: ${restored.join(', ') || 'nothing to restore'}`);
return { success: true, data: { restored } };
}
catch (err) {
output.printError('Rollback failed', String(err));
return { success: false, exitCode: 1 };
}
}
};
// Breaking changes info
const breakingCommand = {
name: 'breaking',
description: 'Show V3 breaking changes',
action: async (ctx) => {
const changes = [
{
category: 'Configuration',
changes: [
{ change: 'Config file renamed', from: 'claude-flow.json', to: 'claude-flow.config.json' },
{ change: 'Swarm config restructured', from: 'swarm.mode', to: 'swarm.topology' },
{ change: 'Provider config format', from: 'provider: "anthropic"', to: 'providers: [...]' }
]
},
{
category: 'Memory',
changes: [
{ change: 'Backend option changed', from: 'memory: { type }', to: 'memory: { backend }' },
{ change: 'HNSW enabled by default', from: 'Manual opt-in', to: 'Auto-enabled' },
{ change: 'Storage path changed', from: '.claude-flow/memory', to: 'data/memory' }
]
},
{
category: 'CLI',
changes: [
{ change: 'Agent command renamed', from: 'spawn <type>', to: 'agent spawn -t <type>' },
{ change: 'Memory command added', from: 'N/A', to: 'memory <subcommand>' },
{ change: 'Hook command enhanced', from: 'hook <type>', to: 'hooks <subcommand>' }
]
},
{
category: 'API',
changes: [
{ change: 'Removed Deno support', from: 'Deno + Node.js', to: 'Node.js 20+ only' },
{ change: 'Event system changed', from: 'EventEmitter', to: 'Event sourcing' },
{ change: 'Coordination unified', from: 'Multiple coordinators', to: 'SwarmCoordinator' }
]
},
{
category: 'Embeddings',
changes: [
{ change: 'Provider changed', from: 'OpenAI API / TF.js', to: 'ONNX Runtime (local)' },
{ change: 'Geometry support', from: 'Euclidean only', to: 'Hyperbolic (Poincaré ball)' },
{ change: 'Cache system', from: 'Memory-only', to: 'sql.js persistent cache' },
{ change: 'Neural substrate', from: 'None', to: 'RuVector integration' }
]
}
];
if (ctx.flags.format === 'json') {
output.printJson(changes);
return { success: true, data: changes };
}
output.writeln();
output.writeln(output.bold('V3 Breaking Changes'));
output.writeln();
for (const category of changes) {
output.writeln(output.highlight(category.category));
output.printTable({
columns: [
{ key: 'change', header: 'Change', width: 25 },
{ key: 'from', header: 'V2', width: 25 },
{ key: 'to', header: 'V3', width: 25 }
],
data: category.changes,
border: false
});
output.writeln();
}
output.printInfo('Run "claude-flow migrate run" to automatically handle these changes');
return { success: true, data: changes };
}
};
// Main migrate command
export const migrateCommand = {
name: 'migrate',
description: 'V2 to V3 migration tools',
subcommands: [statusCommand, runCommand, verifyCommand, rollbackCommand, breakingCommand],
options: [],
examples: [
{ command: 'claude-flow migrate status', description: 'Check migration status' },
{ command: 'claude-flow migrate run --dry-run', description: 'Preview migration' },
{ command: 'claude-flow migrate run -t all', description: 'Run full migration' }
],
action: async (ctx) => {
output.writeln();
output.writeln(output.bold('V2 to V3 Migration Tools'));
output.writeln();
output.writeln('Usage: claude-flow migrate <subcommand> [options]');
output.writeln();
output.writeln('Subcommands:');
output.printList([
`${output.highlight('status')} - Check migration status`,
`${output.highlight('run')} - Run migration`,
`${output.highlight('verify')} - Verify migration integrity`,
`${output.highlight('rollback')} - Rollback to previous version`,
`${output.highlight('breaking')} - Show breaking changes`
]);
return { success: true };
}
};
// Helper functions
function formatMigrationStatus(status) {
if (status === 'migrated' || status === 'passed' || status === 'completed') {
return output.success(status);
}
if (status === 'pending' || status === 'partial') {
return output.warning(status);
}
if (status === 'failed') {
return output.error(status);
}
if (status === 'not-required' || status.startsWith('skipped') || status === 'v3' || status === 'missing') {
return output.dim(status);
}
if (status === 'v2') {
return output.warning(status);
}
if (status === 'v2 + v3') {
return output.success(status);
}
return status;
}
function getMigrationSteps(target) {
const allSteps = [
{ name: 'Configuration Files', description: 'Migrate config schema to V3 format', source: './claude-flow.json', dest: './claude-flow.config.json' },
{ name: 'Memory Backend', description: 'Upgrade to hybrid backend with AgentDB', source: './.claude-flow/memory', dest: './data/memory' },
{ name: 'Agent Definitions', description: 'Convert agent configs to V3 format', source: './.claude-flow/agents', dest: './v3/agents' },
{ name: 'Hook Registry', description: 'Migrate hooks to V3 hook system', source: './src/hooks', dest: './v3/hooks' },
{ name: 'Workflow Definitions', description: 'Convert workflows to event-sourced format', source: './.claude-flow/workflows', dest: './data/workflows' },
{ name: 'Embeddings System', description: 'Migrate to ONNX with hyperbolic (Poincaré ball)', source: 'OpenAI/TF.js embeddings', dest: '.claude-flow/embeddings.json' }
];
if (target === 'all')
return allSteps;
return allSteps.filter(s => s.name.toLowerCase().includes(target.toLowerCase()));
}
export default migrateCommand;
//# sourceMappingURL=migrate.js.map