Skip to content

Commit 597f227

Browse files
authored
Add detailed output for CLI create command (#139)
* Add detailed output for CLI create command - Show progress steps with [done] status - Display created project structure summary - Print success message and next steps (cd, agentcore) - Matches TUI output for consistent user experience * Use progress callbacks for real-time CLI output - Add onProgress callback to createProject and createProjectWithAgent - Show real progress as each step completes (not fake progress after the fact) - Follow same pattern as deploy command for consistency
1 parent 5372379 commit 597f227

2 files changed

Lines changed: 74 additions & 6 deletions

File tree

src/cli/commands/create/action.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,18 @@ function createDefaultMcpDefs(): AgentCoreCliMcpDefs {
4040
return { tools: {} };
4141
}
4242

43+
export type ProgressCallback = (step: string, status: 'start' | 'done' | 'error') => void;
44+
4345
export interface CreateProjectOptions {
4446
name: string;
4547
cwd: string;
4648
skipGit?: boolean;
4749
skipDependencyCheck?: boolean;
50+
onProgress?: ProgressCallback;
4851
}
4952

5053
export async function createProject(options: CreateProjectOptions): Promise<CreateResult> {
51-
const { name, cwd, skipGit, skipDependencyCheck } = options;
54+
const { name, cwd, skipGit, skipDependencyCheck, onProgress } = options;
5255
const projectRoot = join(cwd, name);
5356
const configBaseDir = join(projectRoot, CONFIG_DIR);
5457

@@ -66,10 +69,13 @@ export async function createProject(options: CreateProjectOptions): Promise<Crea
6669

6770
try {
6871
// Create project directory
72+
onProgress?.(`Create ${name}/ project directory`, 'start');
6973
// eslint-disable-next-line security/detect-non-literal-fs-filename
7074
await mkdir(projectRoot, { recursive: true });
75+
onProgress?.(`Create ${name}/ project directory`, 'done');
7176

7277
// Initialize config directory
78+
onProgress?.('Prepare agentcore/ directory', 'start');
7379
const configIO = new ConfigIO({ baseDir: configBaseDir });
7480
await configIO.initializeBaseDir();
7581

@@ -87,13 +93,17 @@ export async function createProject(options: CreateProjectOptions): Promise<Crea
8793
// Create CDK project
8894
const cdkRenderer = new CDKRenderer();
8995
await cdkRenderer.render({ projectRoot });
96+
onProgress?.('Prepare agentcore/ directory', 'done');
9097

9198
// Initialize git (unless skipped)
9299
if (!skipGit) {
100+
onProgress?.('Initialize git repository', 'start');
93101
const gitResult = await initGitRepo(projectRoot);
94102
if (gitResult.status === 'error') {
103+
onProgress?.('Initialize git repository', 'error');
95104
return { success: false, error: gitResult.message, warnings: depWarnings };
96105
}
106+
onProgress?.('Initialize git repository', 'done');
97107
}
98108

99109
return {
@@ -118,10 +128,12 @@ export interface CreateWithAgentOptions {
118128
memory: MemoryOption;
119129
skipGit?: boolean;
120130
skipPythonSetup?: boolean;
131+
onProgress?: ProgressCallback;
121132
}
122133

123134
export async function createProjectWithAgent(options: CreateWithAgentOptions): Promise<CreateResult> {
124-
const { name, cwd, language, framework, modelProvider, apiKey, memory, skipGit, skipPythonSetup } = options;
135+
const { name, cwd, language, framework, modelProvider, apiKey, memory, skipGit, skipPythonSetup, onProgress } =
136+
options;
125137
const projectRoot = join(cwd, name);
126138
const configBaseDir = join(projectRoot, CONFIG_DIR);
127139

@@ -135,7 +147,7 @@ export async function createProjectWithAgent(options: CreateWithAgentOptions): P
135147
}
136148

137149
// First create the base project (skip dependency check since we already did it)
138-
const projectResult = await createProject({ name, cwd, skipGit, skipDependencyCheck: true });
150+
const projectResult = await createProject({ name, cwd, skipGit, skipDependencyCheck: true, onProgress });
139151
if (!projectResult.success) {
140152
// Merge warnings from both checks
141153
const allWarnings = [...depWarnings, ...(projectResult.warnings ?? [])];
@@ -145,6 +157,7 @@ export async function createProjectWithAgent(options: CreateWithAgentOptions): P
145157
try {
146158
// Build GenerateConfig for agent creation
147159
// Note: In this context, agent name = project name since we're creating a project with a single agent
160+
onProgress?.('Add agent to project', 'start');
148161
const agentName = name;
149162
const generateConfig = {
150163
projectName: agentName,
@@ -168,11 +181,14 @@ export async function createProjectWithAgent(options: CreateWithAgentOptions): P
168181
const envVarName = computeDefaultCredentialEnvVarName(credentialName);
169182
await setEnvVar(envVarName, apiKey, configBaseDir);
170183
}
184+
onProgress?.('Add agent to project', 'done');
171185

172186
// Set up Python environment if needed (unless skipped)
173187
if (language === 'Python' && !skipPythonSetup) {
188+
onProgress?.('Set up Python environment', 'start');
174189
const agentDir = join(projectRoot, APP_DIR, name);
175190
await setupPythonProject({ projectDir: agentDir });
191+
onProgress?.('Set up Python environment', 'done');
176192
}
177193

178194
return {

src/cli/commands/create/command.tsx

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,53 @@ import type { ModelProvider, SDKFramework, TargetLanguage } from '../../../schem
33
import { getErrorMessage } from '../../errors';
44
import { COMMAND_DESCRIPTIONS } from '../../tui/copy';
55
import { CreateScreen } from '../../tui/screens/create';
6-
import { createProject, createProjectWithAgent, getDryRunInfo } from './action';
6+
import { createProject, createProjectWithAgent, getDryRunInfo, type ProgressCallback } from './action';
77
import type { CreateOptions } from './types';
88
import { validateCreateOptions } from './validate';
99
import type { Command } from '@commander-js/extra-typings';
1010
import { Text, render } from 'ink';
1111

12+
/** Render CreateScreen for interactive TUI mode */
1213
function handleCreateTUI(): void {
1314
const cwd = getWorkingDirectory();
1415
const { unmount } = render(<CreateScreen cwd={cwd} isInteractive={false} onExit={() => unmount()} />);
1516
}
1617

18+
/** Print completion summary after successful create */
19+
function printCreateSummary(
20+
projectName: string,
21+
agentName: string | undefined,
22+
language: string | undefined,
23+
framework: string | undefined
24+
): void {
25+
const green = '\x1b[32m';
26+
const cyan = '\x1b[36m';
27+
const dim = '\x1b[2m';
28+
const reset = '\x1b[0m';
29+
30+
console.log('');
31+
32+
// Created summary
33+
console.log(`${dim}Created:${reset}`);
34+
console.log(` ${projectName}/`);
35+
if (agentName) {
36+
const frameworkLabel = framework ?? 'agent';
37+
console.log(` app/${agentName}/ ${dim}${language} agent (${frameworkLabel})${reset}`);
38+
}
39+
console.log(` agentcore/ ${dim}Config and CDK project${reset}`);
40+
console.log('');
41+
42+
// Success and next steps
43+
console.log(`${green}Project created successfully!${reset}`);
44+
console.log('');
45+
console.log('To continue, navigate to your new project:');
46+
console.log('');
47+
console.log(` ${cyan}cd ${projectName}${reset}`);
48+
console.log(` ${cyan}agentcore${reset}`);
49+
console.log('');
50+
}
51+
52+
/** Handle CLI mode with progress output */
1753
async function handleCreateCLI(options: CreateOptions): Promise<void> {
1854
const validation = validateCreateOptions(options);
1955
if (!validation.valid) {
@@ -41,11 +77,26 @@ async function handleCreateCLI(options: CreateOptions): Promise<void> {
4177
process.exit(0);
4278
}
4379

80+
const green = '\x1b[32m';
81+
const reset = '\x1b[0m';
82+
83+
// Progress callback for real-time output
84+
const onProgress: ProgressCallback | undefined = options.json
85+
? undefined
86+
: (step, status) => {
87+
if (status === 'done') {
88+
console.log(`${green}[done]${reset} ${step}`);
89+
} else if (status === 'error') {
90+
console.log(`\x1b[31m[error]${reset} ${step}`);
91+
}
92+
// 'start' is silent - we only show when done
93+
};
94+
4495
// Commander.js --no-agent sets agent=false, not noAgent=true
4596
const skipAgent = options.agent === false;
4697

4798
const result = skipAgent
48-
? await createProject({ name: options.name!, cwd, skipGit: options.skipGit })
99+
? await createProject({ name: options.name!, cwd, skipGit: options.skipGit, onProgress })
49100
: await createProjectWithAgent({
50101
name: options.name!,
51102
cwd,
@@ -56,12 +107,13 @@ async function handleCreateCLI(options: CreateOptions): Promise<void> {
56107
memory: options.memory as 'none' | 'shortTerm' | 'longAndShortTerm',
57108
skipGit: options.skipGit,
58109
skipPythonSetup: options.skipPythonSetup,
110+
onProgress,
59111
});
60112

61113
if (options.json) {
62114
console.log(JSON.stringify(result));
63115
} else if (result.success) {
64-
console.log(`Created project at ${result.projectPath}`);
116+
printCreateSummary(options.name!, result.agentName, options.language, options.framework);
65117
} else {
66118
console.error(result.error);
67119
}

0 commit comments

Comments
 (0)