This commit is contained in:
@@ -1,79 +1,51 @@
|
|||||||
|
import * as path from 'path';
|
||||||
import { Command } from 'commander';
|
import { Command } from 'commander';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import {
|
import inquirer from 'inquirer';
|
||||||
getWorkspacePath,
|
import ora from 'ora';
|
||||||
loadWorkspaceConfig,
|
import { getWorkspacePath, loadWorkspaceConfig, sanitizeAgentName, readPackageJson } from '../utils/file-utils';
|
||||||
sanitizeAgentName,
|
import { mergeToMain, createGit, hasUncommittedChanges as gitHasUncommittedChanges } from '../utils/git-utils';
|
||||||
hasUncommittedChanges
|
import { GitAgentSyncError, WorkspaceNotFoundError, MergeConflictError } from '../utils/errors';
|
||||||
} from '../utils/file-utils';
|
import { MergeOptions } from '../types';
|
||||||
import {
|
|
||||||
createGit,
|
|
||||||
mergeToMain,
|
|
||||||
hasUncommittedChanges as gitHasUncommittedChanges
|
|
||||||
} from '../utils/git-utils';
|
|
||||||
import { GitAgentSyncError, WorkspaceNotFoundError, MergeFailedError } from '../utils/errors';
|
|
||||||
|
|
||||||
export function createMergeCommand(): Command {
|
export function createMergeCommand(): Command {
|
||||||
const cmd = new Command('merge')
|
const cmd = new Command('merge').description('Safely merge agent changes back to main branch').argument('<agent-name>', 'Name of the agent workspace to merge').option('--force', 'Force merge even with conflicts').option('--dry-run', 'Preview merge without making changes').option('--message <msg>', 'Custom merge commit message').action(async (agentName, options: MergeOptions) => {
|
||||||
.description('Safely merge agent changes back to main branch')
|
try {
|
||||||
.argument('<agent-name>', 'Name of the agent workspace to merge')
|
const currentPath = process.cwd();
|
||||||
.option('--force', 'Force merge even with uncommitted changes')
|
const sanitizedName = sanitizeAgentName(agentName);
|
||||||
.option('--dry-run', 'Show what would happen without making changes')
|
const workspacePath = getWorkspacePath(currentPath, sanitizedName);
|
||||||
.option('-m, --message <message>', 'Custom commit message')
|
const config = await loadWorkspaceConfig(workspacePath);
|
||||||
.action(async (agentName, options) => {
|
if (!config) throw new WorkspaceNotFoundError(sanitizedName);
|
||||||
try {
|
const spinner = ora('Preparing for merge...').start();
|
||||||
const currentPath = process.cwd();
|
const uncommitted = await gitHasUncommittedChanges(workspacePath);
|
||||||
const sanitizedName = sanitizeAgentName(agentName);
|
if (uncommitted) {
|
||||||
const workspacePath = getWorkspacePath(currentPath, sanitizedName);
|
spinner.stop();
|
||||||
|
console.log(chalk.yellow('\n⚠️ Workspace has uncommitted changes.'));
|
||||||
const config = await loadWorkspaceConfig(workspacePath);
|
|
||||||
if (!config) {
|
|
||||||
throw new WorkspaceNotFoundError(sanitizedName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.force && await hasUncommittedChanges(workspacePath)) {
|
|
||||||
throw new GitAgentSyncError('Workspace has uncommitted changes. Commit or stash them first, or use --force.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const workspaceGit = createGit(workspacePath);
|
|
||||||
|
|
||||||
console.log(chalk.cyan(`\n🔀 Merging ${sanitizedName} into ${config.mainBranch}...`));
|
|
||||||
|
|
||||||
const result = await mergeToMain(
|
|
||||||
currentPath,
|
|
||||||
workspacePath,
|
|
||||||
sanitizedName,
|
|
||||||
config.mainBranch,
|
|
||||||
options.message,
|
|
||||||
options.dryRun
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
if (options.dryRun) {
|
|
||||||
console.log(chalk.yellow(`\n⚠ [DRY RUN] ${result.message}`));
|
|
||||||
} else {
|
|
||||||
console.log(chalk.green('\n✓ Merge completed successfully!'));
|
|
||||||
console.log(` Message: ${result.message}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (result.conflicts && result.conflicts.length > 0) {
|
|
||||||
console.log(chalk.red('\n❌ Merge conflicts detected!'));
|
|
||||||
console.log(chalk.cyan('\nConflicting files:'));
|
|
||||||
for (const conflict of result.conflicts) {
|
|
||||||
console.log(` ${chalk.red(conflict.file)}`);
|
|
||||||
}
|
|
||||||
console.log(chalk.cyan('\n💡 Resolve conflicts manually and commit before trying again.'));
|
|
||||||
} else {
|
|
||||||
throw new MergeFailedError(sanitizedName, result.error || 'Unknown error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
const gitError = error instanceof GitAgentSyncError ? error : new GitAgentSyncError(String(error));
|
|
||||||
console.error(chalk.red(`\n❌ Error: ${gitError.message}`));
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
});
|
const mainBranch = config.mainBranch;
|
||||||
|
spinner.text = 'Merging changes...';
|
||||||
|
const mergeResult = await mergeToMain(currentPath, workspacePath, sanitizedName, mainBranch, options.message, options.dryRun);
|
||||||
|
if (options.dryRun) {
|
||||||
|
spinner.stop();
|
||||||
|
console.log(chalk.cyan('\n🔍 Dry Run Result:'));
|
||||||
|
console.log(` ${mergeResult.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!mergeResult.success && mergeResult.conflicts) {
|
||||||
|
spinner.fail(chalk.red('Merge conflicts detected!'));
|
||||||
|
throw new MergeConflictError(mergeResult.conflicts.map(c => c.file));
|
||||||
|
}
|
||||||
|
spinner.succeed(chalk.green('Merge completed successfully!'));
|
||||||
|
console.log(chalk.cyan('\n📦 Merge Summary'));
|
||||||
|
console.log(` Agent: ${chalk.white(sanitizedName)}`);
|
||||||
|
console.log(` From Branch: ${chalk.white(config.branch)}`);
|
||||||
|
console.log(` To Branch: ${chalk.white(mainBranch)}`);
|
||||||
|
if (mergeResult.commitSha) console.log(` Commit: ${chalk.white(mergeResult.commitSha.substring(0, 7))}`);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof MergeConflictError) console.error(chalk.red(`\n❌ ${error.message}`));
|
||||||
|
else { const gitError = error instanceof GitAgentSyncError ? error : new GitAgentSyncError(String(error)); console.error(chalk.red(`\n❌ Error: ${gitError.message}`)); }
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user