diff --git a/src/cli/tui/copy.ts b/src/cli/tui/copy.ts
index e7e567bb..2aef3c42 100644
--- a/src/cli/tui/copy.ts
+++ b/src/cli/tui/copy.ts
@@ -45,7 +45,7 @@ export const COMMAND_DESCRIPTIONS = {
fetch: 'Fetch access info for deployed resources.',
pause: 'Pause an online eval config. Supports --arn for configs outside the project.',
resume: 'Resume a paused online eval config. Supports --arn for configs outside the project.',
- run: 'Run on-demand evaluation. Supports --agent-arn for agents outside the project.',
+ run: 'Run on-demand evaluation.',
import: 'Import a runtime, memory, or starter toolkit into this project. [experimental]',
telemetry: 'Manage anonymous usage analytics preferences.',
update: 'Check for and install CLI updates',
diff --git a/src/cli/tui/screens/create/CreateScreen.tsx b/src/cli/tui/screens/create/CreateScreen.tsx
index 5b56a0ac..801dfc8d 100644
--- a/src/cli/tui/screens/create/CreateScreen.tsx
+++ b/src/cli/tui/screens/create/CreateScreen.tsx
@@ -237,75 +237,12 @@ export function CreateScreen({ cwd, isInteractive, onExit, onNavigate }: CreateS
isActive: flow.phase === 'create-prompt',
});
- // Checking phase: brief loading state
+ // Checking phase: instant async check — render nothing to avoid a flash before the real UI
if (flow.phase === 'checking') {
- return (
-
- Checking for existing project...
-
- );
- }
-
- // Existing project error phase
- if (flow.phase === 'existing-project-error') {
- return (
-
-
- A project already exists at this location.
- {flow.existingProjectPath && Found: {flow.existingProjectPath}}
-
-
- Use add agent to create a new agent in the existing project.
-
-
-
-
- );
+ return null;
}
- // Input phase: ask for project name
- if (flow.phase === 'input') {
- return (
-
-
- Create a new AgentCore project
- This will create a directory with your project name.
-
- validateFolderNotExists(name, cwd)}
- onSubmit={name => {
- flow.setProjectName(name);
- flow.confirmProjectName();
- }}
- onCancel={handleExit}
- />
-
- );
- }
-
- // Create prompt phase
- if (flow.phase === 'create-prompt') {
- return (
-
-
-
- Project: {flow.projectName}
-
-
-
- Would you like to add an agent now?
-
-
-
-
-
- );
- }
-
- // Create wizard phase - use AddAgentScreen for consistent experience
+ // Create wizard phase - use AddAgentScreen (separate component, no header conflict)
if (flow.phase === 'create-wizard') {
return (
to prevent duplicate header flashes
+ // when Ink transitions between different mounts.
+ const phase = flow.phase;
+ const showProjectHeader = phase !== 'input' && phase !== 'existing-project-error';
+ const headerContent = showProjectHeader ? (
Project: {flow.projectName}
- );
-
- const helpText = flow.hasError || allSuccess ? HELP_TEXT.EXIT : undefined;
+ ) : undefined;
+
+ const helpText =
+ phase === 'existing-project-error'
+ ? 'Press Esc to exit'
+ : phase === 'input'
+ ? HELP_TEXT.TEXT_INPUT
+ : phase === 'create-prompt'
+ ? HELP_TEXT.NAVIGATE_SELECT
+ : flow.hasError || allSuccess
+ ? HELP_TEXT.EXIT
+ : undefined;
return (
-
+ {phase === 'existing-project-error' && (
+
+ A project already exists at this location.
+ {flow.existingProjectPath && Found: {flow.existingProjectPath}}
+
+
+ Use add agent to create a new agent in the existing project.
+
+
+
+ )}
+
+ {phase === 'input' && (
+ <>
+
+ Create a new AgentCore project
+ This will create a directory with your project name.
+
+ validateFolderNotExists(name, cwd)}
+ onSubmit={name => {
+ flow.setProjectName(name);
+ flow.confirmProjectName();
+ }}
+ onCancel={handleExit}
+ />
+ >
+ )}
+
+ {phase === 'create-prompt' && (
+ <>
+
+
+ Project: {flow.projectName}
+
+
+
+ Would you like to add an agent now?
+
+
+
+
+ >
+ )}
+
+ {phase === 'running' && }
+
{allSuccess && flow.outputDir && (
+
{isInteractive ? (
@@ -352,8 +351,10 @@ export function CreateScreen({ cwd, isInteractive, onExit, onNavigate }: CreateS
)}
)}
+
{flow.hasError && (
+
Project creation failed.
{flow.logFilePath && (
diff --git a/src/cli/tui/screens/deploy/DeployScreen.tsx b/src/cli/tui/screens/deploy/DeployScreen.tsx
index 0954f00a..6e99e0cf 100644
--- a/src/cli/tui/screens/deploy/DeployScreen.tsx
+++ b/src/cli/tui/screens/deploy/DeployScreen.tsx
@@ -228,13 +228,13 @@ export function DeployScreen({
);
}
- // AWS target configuration phase (skip when preSynthesized - we already have context)
- if (!skipPreflight && !awsConfig.isConfigured) {
- return (
-
-
-
- );
+ const showAwsConfig = !skipPreflight && !awsConfig.isConfigured;
+
+ // Brief transitional phases — render nothing to avoid a header flash before the real UI
+ const awsTransitional =
+ awsConfig.phase === 'checking' || awsConfig.phase === 'detecting' || awsConfig.phase === 'saving';
+ if (showAwsConfig && awsTransitional) {
+ return null;
}
// Credentials prompt phase
@@ -304,7 +304,11 @@ export function DeployScreen({
]
.filter(Boolean)
.join(' · ');
- const helpText = context && isInteractive ? `${toggleHints} · ${baseHelpText}` : baseHelpText;
+ const helpText = showAwsConfig
+ ? (getAwsConfigHelpText(awsConfig.phase) ?? HELP_TEXT.EXIT)
+ : context && isInteractive
+ ? `${toggleHints} · ${baseHelpText}`
+ : baseHelpText;
const screenTitle = diffMode ? 'AgentCore Diff' : 'AgentCore Deploy';
@@ -316,94 +320,105 @@ export function DeployScreen({
const diffMaxHeight = Math.max(6, terminalRows - chromeLines);
return (
-
-
-
- {/* Toggleable ResourceGraph view */}
- {showResourceGraph && context && (
-
-
-
- )}
-
- {/* Show deploy status when deploying or complete */}
- {showDeployStatus && (
-
-
-
- )}
-
- {/* Show diff output (diff mode: always; normal mode: Ctrl+D toggle) */}
- {(diffMode === true || showDiff) && isDiffLoading && (
-
- Loading diff...
-
- )}
- {(diffMode === true || showDiff) && diffSummaries.length > 0 && (
-
-
-
- )}
-
- {allSuccess && deployOutput && !diffMode && (
-
- {deployOutput}
-
- )}
-
- {allSuccess && diffMode && (
-
- Diff complete
-
- )}
-
- {allSuccess && deployNotes.length > 0 && (
-
- {deployNotes.map((note, i) => (
-
- Note: {note}
-
- ))}
-
- )}
-
- {allSuccess && targetStatuses.length > 0 && (
-
- Gateway Targets:
- {targetStatuses.map(t => (
-
- {' '}
- {t.name}: {formatTargetStatus(t.status)}
-
- ))}
-
- )}
-
- {logFilePath && (
-
-
-
- )}
-
- {allSuccess && !diffMode && (
- 0)}
- isInteractive={isInteractive}
- onSelect={step => {
- if (step.command === 'invoke') {
- setShowInvoke(true);
- } else if (onNavigate) {
- onNavigate(step.command);
- }
- }}
- onBack={onExit}
- isActive={allSuccess && !showInvoke}
- />
+
+ {showAwsConfig ? (
+
+ ) : (
+ <>
+
+
+ {/* Toggleable ResourceGraph view */}
+ {showResourceGraph && context && (
+
+
+
+ )}
+
+ {/* Show deploy status when deploying or complete */}
+ {showDeployStatus && (
+
+
+
+ )}
+
+ {/* Show diff output (diff mode: always; normal mode: Ctrl+D toggle) */}
+ {(diffMode === true || showDiff) && isDiffLoading && (
+
+ Loading diff...
+
+ )}
+ {(diffMode === true || showDiff) && diffSummaries.length > 0 && (
+
+
+
+ )}
+
+ {allSuccess && deployOutput && !diffMode && (
+
+ {deployOutput}
+
+ )}
+
+ {allSuccess && diffMode && (
+
+ Diff complete
+
+ )}
+
+ {allSuccess && deployNotes.length > 0 && (
+
+ {deployNotes.map((note, i) => (
+
+ Note: {note}
+
+ ))}
+
+ )}
+
+ {allSuccess && targetStatuses.length > 0 && (
+
+ Gateway Targets:
+ {targetStatuses.map(t => (
+
+ {' '}
+ {t.name}: {formatTargetStatus(t.status)}
+
+ ))}
+
+ )}
+
+ {logFilePath && (
+
+
+
+ )}
+
+ {allSuccess && !diffMode && (
+ 0)}
+ isInteractive={isInteractive}
+ onSelect={step => {
+ if (step.command === 'invoke') {
+ setShowInvoke(true);
+ } else if (onNavigate) {
+ onNavigate(step.command);
+ }
+ }}
+ onBack={onExit}
+ isActive={allSuccess && !showInvoke}
+ />
+ )}
+ >
)}
);
diff --git a/src/cli/tui/screens/home/CommandListScreen.tsx b/src/cli/tui/screens/home/CommandListScreen.tsx
index f2d2f149..ad2f22c7 100644
--- a/src/cli/tui/screens/home/CommandListScreen.tsx
+++ b/src/cli/tui/screens/home/CommandListScreen.tsx
@@ -1,10 +1,8 @@
import { buildLogo, useLayout } from '../../context';
import type { CommandMeta } from '../../utils/commands';
-import { Box, Text, useApp } from 'ink';
+import { Box, Text, useApp, useStdout } from 'ink';
import React, { useEffect } from 'react';
-const MAX_DESC_WIDTH = 50;
-
function truncateDescription(desc: string, maxLen: number): string {
if (desc.length <= maxLen) return desc;
return desc.slice(0, maxLen - 1) + '…';
@@ -21,6 +19,9 @@ interface CommandListScreenProps {
export function CommandListScreen({ commands }: CommandListScreenProps) {
const { exit } = useApp();
const { contentWidth } = useLayout();
+ const { stdout } = useStdout();
+ const terminalWidth = stdout?.columns ?? 80;
+ const maxDescWidth = Math.max(20, terminalWidth - 18);
const logo = buildLogo(contentWidth);
// Exit after render
@@ -44,7 +45,7 @@ export function CommandListScreen({ commands }: CommandListScreenProps) {
Commands:
{visibleCommands.map(cmd => {
- const desc = truncateDescription(cmd.description, MAX_DESC_WIDTH);
+ const desc = truncateDescription(cmd.description, maxDescWidth);
const padding = ' '.repeat(Math.max(1, 14 - cmd.title.length));
return (
diff --git a/src/cli/tui/screens/home/HelpScreen.tsx b/src/cli/tui/screens/home/HelpScreen.tsx
index 84746f2d..485c263c 100644
--- a/src/cli/tui/screens/home/HelpScreen.tsx
+++ b/src/cli/tui/screens/home/HelpScreen.tsx
@@ -3,11 +3,9 @@ import { useLayout } from '../../context';
import { HINTS } from '../../copy';
import { useTextInput } from '../../hooks';
import type { CommandMeta } from '../../utils/commands';
-import { Box, Text, useInput } from 'ink';
+import { Box, Text, useInput, useStdout } from 'ink';
import React, { useEffect, useMemo, useRef, useState } from 'react';
-const MAX_DESC_WIDTH = 50;
-
function truncateDescription(desc: string, maxLen: number): string {
if (desc.length <= maxLen) return desc;
return desc.slice(0, maxLen - 1) + '…';
@@ -29,8 +27,18 @@ interface HelpDisplayProps {
notice?: React.ReactNode;
}
-function CommandRow({ item, selected, maxLabelLen }: { item: DisplayItem; selected: boolean; maxLabelLen: number }) {
- const desc = truncateDescription(item.command.description, MAX_DESC_WIDTH);
+function CommandRow({
+ item,
+ selected,
+ maxLabelLen,
+ maxDescWidth,
+}: {
+ item: DisplayItem;
+ selected: boolean;
+ maxLabelLen: number;
+ maxDescWidth: number;
+}) {
+ const desc = truncateDescription(item.command.description, maxDescWidth);
const labelLen = item.matchedSubcommand
? item.command.title.length + 3 + item.matchedSubcommand.length
: item.command.title.length;
@@ -77,10 +85,13 @@ function HelpDisplay({
notice,
}: HelpDisplayProps) {
const { contentWidth } = useLayout();
+ const { stdout } = useStdout();
+ const terminalWidth = stdout?.columns ?? 80;
const bottomDivider = '─'.repeat(contentWidth);
const allItems = [...interactiveItems, ...cliOnlyItems];
const maxLabelLen = getMaxLabelLen(allItems);
+ const maxDescWidth = Math.max(20, terminalWidth - maxLabelLen - 8);
const hasCliOnly = cliOnlyItems.length > 0;
const showCliSection = hasCliOnly && (showCliOnly || !!query);
@@ -114,6 +125,7 @@ function HelpDisplay({
item={item}
selected={idx === clampedIndex}
maxLabelLen={maxLabelLen}
+ maxDescWidth={maxDescWidth}
/>
))}
@@ -128,6 +140,7 @@ function HelpDisplay({
item={item}
selected={interactiveCount + idx === clampedIndex}
maxLabelLen={maxLabelLen}
+ maxDescWidth={maxDescWidth}
/>
))}
>