Files
git-agent-sync/.src/commands/destroy.ts

135 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}