chore: Push command files (part 1)
Some checks failed
/ test (push) Failing after 8s

This commit is contained in:
2026-02-03 08:39:26 +00:00
parent 8569130584
commit 4a19ad3879

View File

@@ -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('<agent-name>', '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 <msg>', '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 <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);
}
});