Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | 1x 10x 10x 10x 10x 9x 81x 11x 11x 11x 11x 11x 10x 10x 11x 10x 9x 10x 10x 10x 25x 9x 10x 28x 25x 28x 28x 28x 28x 28x 27x 27x 27x 3x 3x 3x 24x 21x 24x 3x 27x 3x 24x 1x 10x 10x 1x 9x 10x 10x 10x 10x 10x 10x 10x 1x 1x 1x | /**
* Sync V2 Command
*
* Syncs rosetta.yaml to all IDE configuration files
* This is the new YAML-first architecture implementation
*/
import chalk from 'chalk';
import path from 'path';
import { ensureDir, pathExists } from 'fs-extra';
import { writeFile } from 'fs/promises';
import { TARGETS } from '../constants.js';
import { ClaudeGenerator, CursorGenerator, WindsurfGenerator } from '../generators/index.js';
import { findRosettaYAML, parseYAMLFile } from '../parsers/yaml-parser.js';
import { TreeLogger } from '../utils.js';
const GENERATORS = {
'claude': ClaudeGenerator,
'cursor': CursorGenerator,
'windsurf': WindsurfGenerator,
// Future: 'codex': CodexGenerator,
// Future: 'copilot': CopilotGenerator,
// Future: 'kilo': KiloGenerator,
// Future: 'continue': ContinueGenerator
};
/**
* Get default YAML path (search from current directory)
* @returns {Promise<string>} Path to rosetta.yaml
*/
async function getDefaultYAMLPath() {
const yamlPath = await findRosettaYAML(process.cwd(), 5);
Iif (!yamlPath) {
throw new Error('No rosetta.yaml found in current or parent directories. Run "rosetta init" to create one.');
}
return yamlPath;
}
/**
* Get target IDEs based on selection
* @param {Array<string>|null} selectedIdes - Selected IDE labels or null for all
* @returns {Array<Object>} Target configurations
*/
function getTargets(selectedIdes = null) {
if (selectedIdes) {
// Match by generator key (claude, cursor, etc.) provided via --ides
return TARGETS.filter(t => t.generator && selectedIdes.includes(t.generator));
}
// Return all targets that have a generator defined
return TARGETS.filter(t => t.generator && GENERATORS[t.generator]);
}
/**
* Main sync function
* @param {Object} options - Sync options
*/
export async function syncYAMLCommand(options = {}) {
const { ides = null, from = null, dryRun = false, verbose = false } = options;
const logger = dryRun ? null : new TreeLogger('Sync YAML');
try {
// 1. Find and parse rosetta.yaml
const yamlPath = from || await getDefaultYAMLPath();
if (logger) {
logger.logStep(`Found rosetta.yaml at: ${yamlPath}`);
logger.logStep('Parsing rosetta.yaml...');
}
const ast = await parseYAMLFile(yamlPath);
if (logger) {
logger.logStep(`Parsed successfully: ${ast.getProjectName()} (${ast.getProjectType()})`);
}
// 2. Get target IDEs
const targets = getTargets(ides);
Iif (targets.length === 0) {
throw new Error('No supported IDE targets found. Supported IDEs: ' + Object.keys(GENERATORS).join(', '));
}
if (logger) {
logger.logStep(`Target IDEs: ${targets.map(t => t.label).join(', ')}`);
console.log('');
}
// 3. Generate IDE configurations
for (const target of targets) {
if (logger) {
console.log(chalk.blue(`Generating ${target.label} → ${target.path}`));
}
const GeneratorClass = GENERATORS[target.generator];
Iif (!GeneratorClass) {
console.log(chalk.yellow(` ⚠ No generator available for ${target.label} (${target.generator}), skipping...`));
continue;
}
try {
const generator = new GeneratorClass();
const content = generator.generate(ast);
// Write file
const targetDir = path.dirname(target.path);
await ensureDir(targetDir);
if (await pathExists(target.path)) {
Eif (!dryRun) {
await writeFile(target.path, content, 'utf8');
}
Iif (verbose) {
console.log(chalk.gray(' Updated existing file'));
}
} else {
if (!dryRun) {
await writeFile(target.path, content, 'utf8');
}
if (verbose) {
console.log(chalk.gray(' Created new file'));
}
}
if (dryRun) {
console.log(chalk.yellow(` [Dry Run] Would write to: ${target.path}`));
} else {
console.log(chalk.green(` ✓ Wrote ${target.path}`));
}
} catch (error) {
console.log(chalk.red(` ✗ Failed to generate ${target.label}: ${error.message}`));
}
}
// 4. Summary
console.log('');
if (dryRun) {
console.log(chalk.yellow('Dry run complete. No files were modified.'));
} else {
console.log(chalk.green('✓ rosetta.yaml sync complete!'));
}
console.log('');
console.log(`Source: ${yamlPath}`);
console.log(`Targets: ${targets.length} IDE configuration(s)`);
console.log('');
console.log('Next steps:');
console.log(' - rosetta translate <file> --to yaml # Convert existing configs');
console.log(' - rosetta validate-config # Validate your rosetta.yaml');
} catch (error) {
console.log(chalk.red(`Sync failed: ${error.message}`));
Iif (verbose) {
console.error(error);
}
// Throw error to allow callers (including tests) to handle
throw new Error(`Sync failed: ${error.message}`);
}
}
/**
* Validate command
* Validates a rosetta.yaml file
*/
export async function validateConfigCommand(options = {}) {
const { file = null } = options;
try {
const yamlPath = file || await getDefaultYAMLPath();
console.log(chalk.blue(`Validating: ${yamlPath}`));
const { parseYAMLContent, validateYAMLFile } = await import('../parsers/yaml-parser.js');
// Try parsing and validation together
try {
const ast = await parseYAMLFile(yamlPath);
console.log(chalk.green('✓ rosetta.yaml is valid'));
console.log(` Project: ${ast.getProjectName()}`);
console.log(` Type: ${ast.getProjectType()}`);
console.log(` Language: ${ast.getLanguage()}`);
console.log(` Conventions: ${ast.getConventions().length}`);
console.log(` Agents: ${ast.getAgents().length}`);
console.log(` Notes: ${ast.getNotes().length}`);
process.exit(0);
} catch (error) {
const validation = await validateYAMLFile(yamlPath);
if (!validation.valid) {
console.log(chalk.red('Validation failed:'));
for (const err of validation.errors) {
console.log(chalk.red(` - ${err.path}: ${err.message}`));
}
} else {
console.log(chalk.red(`Parse error: ${error.message}`));
}
process.exit(1);
}
} catch (error) {
console.log(chalk.red(`Error: ${error.message}`));
process.exit(1);
}
}
export default {
syncYAMLCommand,
validateConfigCommand
};
|