Skip to content

Commit ffe6a7d

Browse files
committed
feat: add logging and CLI filter options to status command
1 parent 1ca738a commit ffe6a7d

File tree

2 files changed

+190
-69
lines changed

2 files changed

+190
-69
lines changed

src/cli/commands/status/action.ts

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
} from '../../../schema';
99
import { getAgentRuntimeStatus } from '../../aws';
1010
import { getErrorMessage } from '../../errors';
11+
import { ExecLogger } from '../../logging';
1112
import type { ResourceDeploymentState } from './constants';
1213

1314
export type { ResourceDeploymentState };
@@ -28,6 +29,7 @@ export interface ProjectStatusResult {
2829
targetRegion?: string;
2930
resources: ResourceStatusEntry[];
3031
error?: string;
32+
logPath?: string;
3133
}
3234

3335
export interface StatusContext {
@@ -43,6 +45,7 @@ export interface RuntimeLookupResult {
4345
runtimeId?: string;
4446
runtimeStatus?: string;
4547
error?: string;
48+
logPath?: string;
4649
}
4750

4851
/**
@@ -156,100 +159,164 @@ export async function handleProjectStatus(
156159
context: StatusContext,
157160
options: { targetName?: string } = {}
158161
): Promise<ProjectStatusResult> {
162+
const logger = new ExecLogger({ command: 'status' });
159163
const { project, deployedState, awsTargets, mcpSpec } = context;
160164

165+
logger.startStep('Resolve target');
161166
const deployedTargetNames = Object.keys(deployedState.targets);
162167
const targetNames = deployedTargetNames.length > 0 ? deployedTargetNames : awsTargets.map(t => t.name);
163-
164168
const selectedTargetName = options.targetName ?? targetNames[0];
165169

170+
logger.log(`Project: ${project.name}`);
171+
logger.log(`Available targets: ${targetNames.length > 0 ? targetNames.join(', ') : '(none)'}`);
172+
logger.log(`Selected target: ${selectedTargetName ?? '(none)'}`);
173+
166174
if (options.targetName && !targetNames.includes(options.targetName)) {
175+
const error =
176+
targetNames.length > 0
177+
? `Target '${options.targetName}' not found. Available: ${targetNames.join(', ')}`
178+
: `Target '${options.targetName}' not found. No targets configured.`;
179+
logger.endStep('error', error);
180+
logger.finalize(false);
167181
return {
168182
success: false,
169183
projectName: project.name,
170184
targetName: options.targetName,
171185
resources: [],
172-
error:
173-
targetNames.length > 0
174-
? `Target '${options.targetName}' not found. Available: ${targetNames.join(', ')}`
175-
: `Target '${options.targetName}' not found. No targets configured.`,
186+
error,
187+
logPath: logger.getRelativeLogPath(),
176188
};
177189
}
190+
logger.endStep('success');
178191

192+
logger.startStep('Compute resource statuses');
179193
const targetConfig = selectedTargetName ? awsTargets.find(t => t.name === selectedTargetName) : undefined;
180194
const targetResources = selectedTargetName ? deployedState.targets[selectedTargetName]?.resources : undefined;
181195

182196
const resources = computeResourceStatuses(project, targetResources, mcpSpec);
183197

198+
const deployed = resources.filter(r => r.deploymentState === 'deployed').length;
199+
const localOnly = resources.filter(r => r.deploymentState === 'local-only').length;
200+
const pendingRemoval = resources.filter(r => r.deploymentState === 'pending-removal').length;
201+
logger.log(
202+
`Resources: ${resources.length} total (${deployed} deployed, ${localOnly} local-only, ${pendingRemoval} pending-removal)`
203+
);
204+
for (const entry of resources) {
205+
logger.log(
206+
` ${entry.resourceType}/${entry.name}: ${entry.deploymentState}${entry.identifier ? ` [${entry.identifier}]` : ''}`
207+
);
208+
}
209+
logger.endStep('success');
210+
184211
// Enrich deployed agents with live runtime status (parallel, entries replaced by index)
185212
if (targetConfig) {
186213
const agentStates = targetResources?.agents ?? {};
187-
188-
await Promise.all(
189-
resources.map(async (entry, i) => {
190-
if (entry.resourceType !== 'agent' || entry.deploymentState !== 'deployed') return;
191-
192-
const agentState = agentStates[entry.name];
193-
if (!agentState) return;
194-
195-
try {
196-
const runtimeStatus = await getAgentRuntimeStatus({
197-
region: targetConfig.region,
198-
runtimeId: agentState.runtimeId,
199-
});
200-
resources[i] = { ...entry, detail: runtimeStatus.status };
201-
} catch (error) {
202-
resources[i] = { ...entry, error: getErrorMessage(error) };
203-
}
204-
})
214+
const deployedAgents = resources.filter(
215+
(e, _i) => e.resourceType === 'agent' && e.deploymentState === 'deployed' && agentStates[e.name]
205216
);
217+
218+
if (deployedAgents.length > 0) {
219+
logger.startStep(
220+
`Fetch runtime status (${deployedAgents.length} agent${deployedAgents.length !== 1 ? 's' : ''})`
221+
);
222+
223+
await Promise.all(
224+
resources.map(async (entry, i) => {
225+
if (entry.resourceType !== 'agent' || entry.deploymentState !== 'deployed') return;
226+
227+
const agentState = agentStates[entry.name];
228+
if (!agentState) return;
229+
230+
try {
231+
const runtimeStatus = await getAgentRuntimeStatus({
232+
region: targetConfig.region,
233+
runtimeId: agentState.runtimeId,
234+
});
235+
resources[i] = { ...entry, detail: runtimeStatus.status };
236+
logger.log(` ${entry.name}: ${runtimeStatus.status} (${agentState.runtimeId})`);
237+
} catch (error) {
238+
const errorMsg = getErrorMessage(error);
239+
resources[i] = { ...entry, error: errorMsg };
240+
logger.log(` ${entry.name}: ERROR - ${errorMsg}`, 'error');
241+
}
242+
})
243+
);
244+
245+
const hasErrors = resources.some(r => r.error);
246+
logger.endStep(hasErrors ? 'error' : 'success');
247+
}
206248
}
207249

250+
logger.finalize(true);
208251
return {
209252
success: true,
210253
projectName: project.name,
211254
targetName: selectedTargetName ?? '',
212255
targetRegion: targetConfig?.region,
213256
resources,
257+
logPath: logger.getRelativeLogPath(),
214258
};
215259
}
216260

217261
export async function handleRuntimeLookup(
218262
context: StatusContext,
219263
options: { agentRuntimeId: string; targetName?: string }
220264
): Promise<RuntimeLookupResult> {
265+
const logger = new ExecLogger({ command: 'status' });
221266
const { awsTargets } = context;
222267

268+
logger.startStep('Resolve target');
223269
const targetNames = awsTargets.map(target => target.name);
224270
if (targetNames.length === 0) {
225-
return { success: false, error: 'No deployment targets found. Run `agentcore create` first.' };
271+
const error = 'No deployment targets found. Run `agentcore create` first.';
272+
logger.endStep('error', error);
273+
logger.finalize(false);
274+
return { success: false, error, logPath: logger.getRelativeLogPath() };
226275
}
227276

228277
const selectedTargetName = options.targetName ?? targetNames[0]!;
229278

230279
if (options.targetName && !targetNames.includes(options.targetName)) {
231-
return { success: false, error: `Target '${options.targetName}' not found. Available: ${targetNames.join(', ')}` };
280+
const error = `Target '${options.targetName}' not found. Available: ${targetNames.join(', ')}`;
281+
logger.endStep('error', error);
282+
logger.finalize(false);
283+
return { success: false, error, logPath: logger.getRelativeLogPath() };
232284
}
233285

234286
const targetConfig = awsTargets.find(target => target.name === selectedTargetName);
235287

236288
if (!targetConfig) {
237-
return { success: false, error: `Target config '${selectedTargetName}' not found in aws-targets` };
289+
const error = `Target config '${selectedTargetName}' not found in aws-targets`;
290+
logger.endStep('error', error);
291+
logger.finalize(false);
292+
return { success: false, error, logPath: logger.getRelativeLogPath() };
238293
}
239294

295+
logger.log(`Target: ${selectedTargetName} (${targetConfig.region})`);
296+
logger.endStep('success');
297+
298+
logger.startStep(`Lookup runtime ${options.agentRuntimeId}`);
240299
try {
241300
const runtimeStatus = await getAgentRuntimeStatus({
242301
region: targetConfig.region,
243302
runtimeId: options.agentRuntimeId,
244303
});
245304

305+
logger.log(`Runtime: ${runtimeStatus.runtimeId}${runtimeStatus.status}`);
306+
logger.endStep('success');
307+
logger.finalize(true);
308+
246309
return {
247310
success: true,
248311
targetName: selectedTargetName,
249312
runtimeId: runtimeStatus.runtimeId,
250313
runtimeStatus: runtimeStatus.status,
314+
logPath: logger.getRelativeLogPath(),
251315
};
252316
} catch (error) {
253-
return { success: false, error: getErrorMessage(error) };
317+
const errorMsg = getErrorMessage(error);
318+
logger.endStep('error', errorMsg);
319+
logger.finalize(false);
320+
return { success: false, error: errorMsg, logPath: logger.getRelativeLogPath() };
254321
}
255322
}

0 commit comments

Comments
 (0)