Files
everything-claude-code/scripts/install-apply.js

138 lines
4.6 KiB
JavaScript

#!/usr/bin/env node
/**
* Refactored ECC installer runtime.
*
* Keeps the legacy language-based install entrypoint intact while moving
* target-specific mutation logic into testable Node code.
*/
const {
SUPPORTED_INSTALL_TARGETS,
listAvailableLanguages,
} = require('./lib/install-executor');
const {
LEGACY_INSTALL_TARGETS,
normalizeInstallRequest,
parseInstallArgs,
} = require('./lib/install/request');
const { loadInstallConfig } = require('./lib/install/config');
const { applyInstallPlan } = require('./lib/install/apply');
const { createInstallPlanFromRequest } = require('./lib/install/runtime');
function showHelp(exitCode = 0) {
const languages = listAvailableLanguages();
console.log(`
Usage: install.sh [--target <${LEGACY_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] <language> [<language> ...]
install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --profile <name> [--with <component>]... [--without <component>]...
install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --modules <id,id,...> [--with <component>]... [--without <component>]...
install.sh [--dry-run] [--json] --config <path>
Targets:
claude (default) - Install rules to ~/.claude/rules/
cursor - Install rules, hooks, and bundled Cursor configs to ./.cursor/
antigravity - Install rules, workflows, skills, and agents to ./.agent/
Options:
--profile <name> Resolve and install a manifest profile
--modules <ids> Resolve and install explicit module IDs
--with <component> Include a user-facing install component
--without <component>
Exclude a user-facing install component
--config <path> Load install intent from ecc-install.json
--dry-run Show the install plan without copying files
--json Emit machine-readable plan/result JSON
--help Show this help text
Available languages:
${languages.map(language => ` - ${language}`).join('\n')}
`);
process.exit(exitCode);
}
function printHumanPlan(plan, dryRun) {
console.log(`${dryRun ? 'Dry-run install plan' : 'Applying install plan'}:\n`);
console.log(`Mode: ${plan.mode}`);
console.log(`Target: ${plan.target}`);
console.log(`Adapter: ${plan.adapter.id}`);
console.log(`Install root: ${plan.installRoot}`);
console.log(`Install-state: ${plan.installStatePath}`);
if (plan.mode === 'legacy') {
console.log(`Languages: ${plan.languages.join(', ')}`);
} else {
console.log(`Profile: ${plan.profileId || '(custom modules)'}`);
console.log(`Included components: ${plan.includedComponentIds.join(', ') || '(none)'}`);
console.log(`Excluded components: ${plan.excludedComponentIds.join(', ') || '(none)'}`);
console.log(`Requested modules: ${plan.requestedModuleIds.join(', ') || '(none)'}`);
console.log(`Selected modules: ${plan.selectedModuleIds.join(', ') || '(none)'}`);
if (plan.skippedModuleIds.length > 0) {
console.log(`Skipped modules: ${plan.skippedModuleIds.join(', ')}`);
}
if (plan.excludedModuleIds.length > 0) {
console.log(`Excluded modules: ${plan.excludedModuleIds.join(', ')}`);
}
}
console.log(`Operations: ${plan.operations.length}`);
if (plan.warnings.length > 0) {
console.log('\nWarnings:');
for (const warning of plan.warnings) {
console.log(`- ${warning}`);
}
}
console.log('\nPlanned file operations:');
for (const operation of plan.operations) {
console.log(`- ${operation.sourceRelativePath} -> ${operation.destinationPath}`);
}
if (!dryRun) {
console.log(`\nDone. Install-state written to ${plan.installStatePath}`);
}
}
function main() {
try {
const options = parseInstallArgs(process.argv);
if (options.help) {
showHelp(0);
}
const config = options.configPath
? loadInstallConfig(options.configPath, { cwd: process.cwd() })
: null;
const request = normalizeInstallRequest({
...options,
config,
});
const plan = createInstallPlanFromRequest(request, {
projectRoot: process.cwd(),
homeDir: process.env.HOME,
claudeRulesDir: process.env.CLAUDE_RULES_DIR || null,
});
if (options.dryRun) {
if (options.json) {
console.log(JSON.stringify({ dryRun: true, plan }, null, 2));
} else {
printHumanPlan(plan, true);
}
return;
}
const result = applyInstallPlan(plan);
if (options.json) {
console.log(JSON.stringify({ dryRun: false, result }, null, 2));
} else {
printHumanPlan(result, false);
}
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
}
main();