From 4a19ad3879ad7f9f0682e71f959f1051d532ae91 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Tue, 3 Feb 2026 08:39:26 +0000 Subject: [PATCH] chore: Push command files (part 1) --- src/commands/merge.ts | 137 +++++++++--------------------------------- 1 file changed, 29 insertions(+), 108 deletions(-) diff --git a/src/commands/merge.ts b/src/commands/merge.ts index dfdfbd6..a7d85f5 100644 --- a/src/commands/merge.ts +++ b/src/commands/merge.ts @@ -1,32 +1,26 @@ -import * as path from 'path'; import { Command } from 'commander'; import chalk from 'chalk'; -import inquirer from 'inquirer'; -import ora from 'ora'; import { getWorkspacePath, loadWorkspaceConfig, sanitizeAgentName, - hasUncommittedChanges, - readPackageJson + hasUncommittedChanges } from '../utils/file-utils'; import { - mergeToMain, createGit, + mergeToMain, hasUncommittedChanges as gitHasUncommittedChanges } from '../utils/git-utils'; -import { GitAgentSyncError, WorkspaceNotFoundError, MergeConflictError } from '../utils/errors'; -import { ConflictInfo } from '../types/index'; -import { MergeOptions } from '../types'; +import { GitAgentSyncError, WorkspaceNotFoundError, MergeFailedError } from '../utils/errors'; export function createMergeCommand(): Command { const cmd = new Command('merge') .description('Safely merge agent changes back to main branch') .argument('', 'Name of the agent workspace to merge') - .option('--force', 'Force merge even with conflicts (use with caution)') - .option('--dry-run', 'Preview merge without making changes') - .option('--message ', 'Custom merge commit message') - .action(async (agentName, options: MergeOptions) => { + .option('--force', 'Force merge even with uncommitted changes') + .option('--dry-run', 'Show what would happen without making changes') + .option('-m, --message ', 'Custom commit message') + .action(async (agentName, options) => { try { const currentPath = process.cwd(); const sanitizedName = sanitizeAgentName(agentName); @@ -37,119 +31,46 @@ export function createMergeCommand(): Command { throw new WorkspaceNotFoundError(sanitizedName); } - const spinner = ora('Preparing for merge...').start(); - - const uncommitted = await gitHasUncommittedChanges(workspacePath); - if (uncommitted) { - spinner.stop(); - console.log(chalk.yellow('\nāš ļø Workspace has uncommitted changes.')); - const { shouldCommit } = await inquirer.prompt([ - { - type: 'confirm', - name: 'shouldCommit', - message: 'Commit changes before merging?', - default: true - } - ]); - - if (shouldCommit) { - const workspaceGit = createGit(workspacePath); - await workspaceGit.add('.'); - await workspaceGit.commit('Uncommitted changes before merge'); - } + if (!options.force && await hasUncommittedChanges(workspacePath)) { + throw new GitAgentSyncError('Workspace has uncommitted changes. Commit or stash them first, or use --force.'); } - spinner.text = 'Running pre-merge validation...'; - - const mainBranch = config.mainBranch; const workspaceGit = createGit(workspacePath); - const pkgJson = await readPackageJson(workspacePath); - let testsPassed = true; + console.log(chalk.cyan(`\nšŸ”€ Merging ${sanitizedName} into ${config.mainBranch}...`)); - if (pkgJson?.scripts?.test && !options.force) { - spinner.text = 'Running tests...'; - const { execa } = await import('execa'); - try { - await execa('npm', ['test'], { cwd: workspacePath, reject: false }); - } catch { - testsPassed = false; - } - } - - if (!testsPassed && !options.force) { - spinner.fail(chalk.red('Tests failed. Use --force to bypass.')); - process.exit(1); - } - - spinner.text = 'Merging changes...'; - const mergeResult = await mergeToMain( + const result = await mergeToMain( currentPath, workspacePath, sanitizedName, - mainBranch, + config.mainBranch, options.message, options.dryRun ); - if (options.dryRun) { - spinner.stop(); - console.log(chalk.cyan('\nšŸ” Dry Run Result:')); - console.log(chalk.gray('─'.repeat(50))); - console.log(` ${mergeResult.message}`); - console.log(chalk.gray('─'.repeat(50))); - return; - } - - if (!mergeResult.success && mergeResult.conflicts) { - spinner.fail(chalk.red('Merge conflicts detected!')); - - console.log(chalk.yellow('\nšŸ“ Conflicting files:')); - for (const conflict of mergeResult.conflicts) { - console.log(` ${chalk.red(conflict.file)}`); + 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}`); } - - const { shouldRollback } = await inquirer.prompt([ - { - type: 'confirm', - name: 'shouldRollback', - message: 'Rollback merge?', - default: true + } 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)}`); } - ]); - - if (shouldRollback) { - const { execa } = await import('execa'); - await execa('git', ['merge', '--abort'], { cwd: currentPath }); - console.log(chalk.green('\nāœ… Rollback complete. Resolve conflicts and try again.')); + console.log(chalk.cyan('\nšŸ’” Resolve conflicts manually and commit before trying again.')); + } else { + throw new MergeFailedError(sanitizedName, result.error || 'Unknown error'); } - - throw new MergeConflictError(mergeResult.conflicts.map((c: ConflictInfo) => c.file)); } - spinner.succeed(chalk.green('Merge completed successfully!')); - - console.log(chalk.cyan('\nšŸ“¦ Merge Summary')); - console.log(chalk.gray('─'.repeat(50))); - console.log(` Agent: ${chalk.white(sanitizedName)}`); - console.log(` From Branch: ${chalk.white(config.branch)}`); - console.log(` To Branch: ${chalk.white(mainBranch)}`); - console.log(` Status: ${chalk.green('āœ“ Merged')}`); - if (mergeResult.commitSha) { - console.log(` Commit: ${chalk.white(mergeResult.commitSha.substring(0, 7))}`); - } - console.log(chalk.gray('─'.repeat(50))); - - console.log(chalk.cyan('\n✨ You can now delete the workspace with:')); - console.log(` ${chalk.white(\`git-agent-sync destroy ${sanitizedName}\`)}`); - } 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}`)); - } + const gitError = error instanceof GitAgentSyncError ? error : new GitAgentSyncError(String(error)); + console.error(chalk.red(`\nāŒ Error: ${gitError.message}`)); process.exit(1); } });