Skip to content

Commit df80f90

Browse files
authored
feat: show all CLI commands in TUI with / toggle (#635)
* feat: add cliOnly flag to CommandMeta for TUI command visibility * feat: add CLI-only examples and toggle hint text to copy.ts * feat: add Ctrl+L toggle for CLI-only commands in HelpScreen * feat: route CLI-only commands to CliOnlyScreen with usage examples * feat: change CLI-only toggle from Ctrl+L to / key * fix: remove update and package from HIDDEN_FROM_TUI These commands have TUI screens and should be visible. The test expected them to be present but the implementation still filtered them out, causing CI failure.
1 parent 5e0f584 commit df80f90

8 files changed

Lines changed: 356 additions & 99 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,6 @@ bun.lock
6161

6262
.agentreview
6363
ProtocolTesting/
64+
65+
# Git worktrees
66+
.worktrees/

src/cli/tui/App.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { getWorkingDirectory } from '../../lib';
22
import { createProgram } from '../cli';
33
import { LayoutProvider } from './context';
4+
import { CLI_ONLY_EXAMPLES } from './copy';
45
import { MissingProjectMessage, WrongDirectoryMessage, getProjectRootMismatch, projectExists } from './guards';
56
import { AddFlow } from './screens/add/AddFlow';
7+
import { CliOnlyScreen } from './screens/cli-only';
68
import { CreateScreen } from './screens/create';
79
import { DeployScreen } from './screens/deploy/DeployScreen';
810
import { DevScreen } from './screens/dev/DevScreen';
@@ -42,7 +44,8 @@ type Route =
4244
| { name: 'fetch-access' }
4345
| { name: 'validate' }
4446
| { name: 'package' }
45-
| { name: 'update' };
47+
| { name: 'update' }
48+
| { name: 'cli-only'; commandId: string };
4649

4750
// Commands that don't require being at the project root
4851
const PROJECT_ROOT_EXEMPT_COMMANDS = new Set(['create', 'update']);
@@ -74,6 +77,13 @@ function AppContent() {
7477
return;
7578
}
7679

80+
// CLI-only commands → show usage info screen
81+
const cliOnlyExamples = CLI_ONLY_EXAMPLES[id];
82+
if (cliOnlyExamples) {
83+
setRoute({ name: 'cli-only', commandId: id });
84+
return;
85+
}
86+
7787
if (id === 'dev') {
7888
setRoute({ name: 'dev' });
7989
} else if (id === 'deploy') {
@@ -247,7 +257,20 @@ function AppContent() {
247257
return <UpdateScreen isInteractive={true} onExit={() => setRoute({ name: 'help' })} />;
248258
}
249259

250-
// All visible commands are handled above; this is unreachable.
260+
if (route.name === 'cli-only') {
261+
const info = CLI_ONLY_EXAMPLES[route.commandId];
262+
if (info) {
263+
return (
264+
<CliOnlyScreen
265+
title={route.commandId}
266+
description={info.description}
267+
examples={info.examples}
268+
onExit={() => setRoute({ name: 'help' })}
269+
/>
270+
);
271+
}
272+
}
273+
251274
return null;
252275
}
253276

src/cli/tui/copy.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
export const HINTS = {
1111
HOME: 'Type to search, Tab commands, Esc quit',
1212
COMMANDS: 'Type to filter, ↑↓ navigate, Enter select, Esc back',
13+
COMMANDS_SHOW_ALL: 'Type to filter · ↑↓ Enter select · / show all · Esc back',
14+
COMMANDS_HIDE_CLI: 'Type to filter · ↑↓ Enter select · / hide cli · Esc back',
1315
} as const;
1416

1517
/**
@@ -48,3 +50,35 @@ export const COMMAND_DESCRIPTIONS = {
4850
update: 'Check for and install CLI updates',
4951
validate: 'Validate agentcore/ config files.',
5052
} as const;
53+
54+
/**
55+
* CLI-only command examples and usage information.
56+
* These commands must run in the terminal, not in the TUI.
57+
*/
58+
export const CLI_ONLY_EXAMPLES: Record<string, { description: string; examples: string[] }> = {
59+
logs: {
60+
description: 'Stream or search agent runtime logs. This command runs in the terminal.',
61+
examples: [
62+
'agentcore logs',
63+
'agentcore logs --since 30m --level error',
64+
'agentcore logs --agent MyAgent --query "timeout"',
65+
'agentcore logs evals --since 1h',
66+
],
67+
},
68+
traces: {
69+
description: 'View and download agent traces. This command runs in the terminal.',
70+
examples: [
71+
'agentcore traces list',
72+
'agentcore traces list --since 1h --limit 10',
73+
'agentcore traces get <traceId>',
74+
],
75+
},
76+
pause: {
77+
description: 'Pause a deployed online eval config. This command runs in the terminal.',
78+
examples: ['agentcore pause online-eval <name>', 'agentcore pause online-eval --arn <arn>'],
79+
},
80+
resume: {
81+
description: 'Resume a paused online eval config. This command runs in the terminal.',
82+
examples: ['agentcore resume online-eval <name>', 'agentcore resume online-eval --arn <arn>'],
83+
},
84+
};

src/cli/tui/hooks/useTextInput.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface UseTextInputOptions {
3131
onDownArrow?: () => void;
3232
/** Whether input is active (default: true) */
3333
isActive?: boolean;
34+
/** Characters to ignore (not added to input) */
35+
excludeChars?: string[];
3436
}
3537

3638
export interface UseTextInputResult {
@@ -63,6 +65,7 @@ export function useTextInput({
6365
onUpArrow,
6466
onDownArrow,
6567
isActive = true,
68+
excludeChars,
6669
}: UseTextInputOptions = {}): UseTextInputResult {
6770
const [state, setState] = useState({ text: initialValue, cursor: initialValue.length });
6871

@@ -196,6 +199,8 @@ export function useTextInput({
196199

197200
// Regular character input
198201
if (input && !key.ctrl && !key.meta) {
202+
// Skip excluded characters
203+
if (excludeChars?.includes(input)) return;
199204
// Filter out control characters (DEL, backspace, carriage return)
200205
// eslint-disable-next-line no-control-regex
201206
const filtered = input.replace(/[\x7f\x08\r]/g, '');

0 commit comments

Comments
 (0)