import { ConfigIO } from '../../../lib'; import { getErrorMessage } from '../../errors'; import { COMMAND_DESCRIPTIONS } from '../../tui/copy'; import { requireProject } from '../../tui/guards'; import { RemoveAllScreen, RemoveFlow } from '../../tui/screens/remove'; import type { RemoveAllOptions, RemoveResult } from './types'; import { validateRemoveAllOptions } from './validate'; import type { Command } from '@commander-js/extra-typings'; import { Text, render } from 'ink'; import React from 'react'; async function handleRemoveAll(_options: RemoveAllOptions): Promise { try { const configIO = new ConfigIO(); // Get current project name to preserve it let projectName = 'Project'; try { const current = await configIO.readProjectSpec(); projectName = current.name; } catch { // Use default if can't read } // Reset agentcore.json (keep project name, clear all resources including gateways) await configIO.writeProjectSpec({ name: projectName, version: 1, managedBy: 'CDK' as const, runtimes: [], memories: [], credentials: [], evaluators: [], onlineEvalConfigs: [], agentCoreGateways: [], policyEngines: [], }); // Preserve aws-targets.json and deployed-state.json so that // a subsequent `agentcore deploy` can tear down existing stacks. return { success: true, message: 'All schemas reset to empty state', note: 'Your source code has not been modified. Run `agentcore deploy` to apply changes to AWS.', }; } catch (err) { return { success: false, error: getErrorMessage(err) }; } } async function handleRemoveAllCLI(options: RemoveAllOptions): Promise { validateRemoveAllOptions(options); const result = await handleRemoveAll(options); console.log(JSON.stringify(result)); process.exit(result.success ? 0 : 1); } export const registerRemove = (program: Command): Command => { const removeCommand = program.command('remove').description(COMMAND_DESCRIPTIONS.remove); // 'remove all' is a special command, not a primitive removeCommand .command('all') .description('Reset all agentcore schemas to empty state') .option('-y, --yes', 'Skip confirmation prompts [non-interactive]') .option('--dry-run', 'Show what would be reset without actually resetting [non-interactive]') .option('--json', 'Output as JSON [non-interactive]') .action(async (cliOptions: { yes?: boolean; dryRun?: boolean; json?: boolean }) => { try { // Any flag triggers non-interactive CLI mode if (cliOptions.yes || cliOptions.dryRun || cliOptions.json) { await handleRemoveAllCLI({ force: cliOptions.yes, dryRun: cliOptions.dryRun, json: cliOptions.json, }); } else { const { unmount } = render( { unmount(); process.exit(0); }} /> ); } } catch (error) { if (cliOptions.json) { console.log(JSON.stringify({ success: false, error: getErrorMessage(error) })); } else { render(Error: {getErrorMessage(error)}); } process.exit(1); } }); // Resource subcommands (agent, memory, credential, gateway, mcp-tool) are registered // via primitive.registerCommands() in cli.ts // Catch-all for TUI fallback when no subcommand is specified. // Commander matches named subcommands first, so this is safe even though // primitive subcommands are registered after this point. removeCommand .argument('[subcommand]') .action((subcommand: string | undefined, _options, cmd) => { if (subcommand) { console.error(`error: '${subcommand}' is not a valid subcommand.`); cmd.outputHelp(); process.exit(1); } requireProject(); const { clear, unmount } = render( { clear(); unmount(); }} /> ); }) .showHelpAfterError() .showSuggestionAfterError(); return removeCommand; };