Add CLI commands (create, list, status, merge, destroy, diff)

This commit is contained in:
2026-02-03 07:57:02 +00:00
parent c539992209
commit 65a861433d

134
.src/commands/destroy.ts Normal file
View File

@@ -0,0 +1,134 @@
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,
exportChangesAsPatch,
getAllWorkspaces
} from '../utils/file-utils';
import {
createGit,
createWorktree,
removeWorktree,
deleteBranch,
hasUncommittedChanges as gitHasUncommittedChanges,
stashChanges
} from '../utils/git-utils';
import { GitAgentSyncError, WorkspaceNotFoundError } from '../utils/errors';
export function createDestroyCommand(): Command {
const cmd = new Command('destroy')
.alias('rm')
.description('Safely remove an agent workspace')
.argument('<agent-name>', 'Name of the agent workspace to destroy')
.option('--force', 'Skip confirmation and remove without preservation')
.option('--preserve', 'Preserve uncommitted changes as a patch file')
.option('--output <path>', 'Path for patch file (if --preserve is used)')
.action(async (agentName, options) => {
try {
const currentPath = process.cwd();
const sanitizedName = sanitizeAgentName(agentName);
const workspacePath = getWorkspacePath(currentPath, sanitizedName);
const config = await loadWorkspaceConfig(workspacePath);
if (!config) {
throw new WorkspaceNotFoundError(sanitizedName);
}
const uncommitted = await gitHasUncommittedChanges(workspacePath);
const spinner = ora('Checking workspace status...').start();
if (uncommitted && !options.force) {
if (!options.preserve) {
spinner.stop();
const { shouldPreserve } = await inquirer.prompt([
{
type: 'confirm',
name: 'shouldPreserve',
message: `Workspace has uncommitted changes. Preserve them as a patch file?`,
default: true
}
]);
if (shouldPreserve) {
options.preserve = true;
}
}
}
spinner.text = 'Preparing to destroy workspace...';
spinner.stop();
if (!options.force) {
console.log(chalk.cyan('\n🗑 Workspace Destruction Summary'));
console.log(chalk.gray('─'.repeat(50)));
console.log(` Agent: ${chalk.white(sanitizedName)}`);
console.log(` Branch: ${chalk.white(config.branch)}`);
console.log(` Path: ${chalk.white(workspacePath)}`);
console.log(` Created: ${chalk.white(new Date(config.createdAt).toLocaleString())}`);
console.log(` Uncommitted changes: ${uncommitted ? chalk.yellow('Yes') : chalk.green('No')}`);
console.log(chalk.gray('─'.repeat(50)));
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: `Are you sure you want to destroy workspace '${sanitizedName}'?`,
default: false
}
]);
if (!confirm) {
console.log(chalk.yellow('\n⏸ Destruction cancelled.'));
return;
}
}
const destroySpinner = ora('Destroying workspace...').start();
if (uncommitted && options.preserve) {
const patchPath = options.output || path.join(currentPath, `${sanitizedName}-changes.patch`);
await exportChangesAsPatch(workspacePath, patchPath);
destroySpinner.text = `Changes exported to ${patchPath}`;
}
await removeWorktree(currentPath, workspacePath, config.branch);
await deleteBranch(createGit(currentPath), config.branch, true);
const fs = await import('fs-extra');
const configPath = path.join(workspacePath, '.agent-workspace.json');
const envPath = path.join(workspacePath, '.env');
await fs.remove(configPath);
await fs.remove(envPath);
const workspaceRoot = path.dirname(workspacePath);
if (await fs.pathExists(workspaceRoot)) {
const remaining = await fs.readdir(workspaceRoot);
if (remaining.length === 0) {
await fs.remove(workspaceRoot);
}
}
destroySpinner.succeed(chalk.green('Workspace destroyed successfully!'));
if (uncommitted && options.preserve) {
console.log(chalk.yellow(`\n📦 Changes preserved at: ${options.output || `${sanitizedName}-changes.patch`}`));
}
console.log(chalk.cyan('\n✨ Done'));
} catch (error) {
const gitError = error instanceof GitAgentSyncError ? error : new GitAgentSyncError(String(error));
console.error(chalk.red(`\n❌ Error: ${gitError.message}`));
process.exit(1);
}
});
return cmd;
}