Skip to content

Commit dcd4476

Browse files
Fix slash command filtering to include commands with empty commandText
Remove commandText requirement from getSlashCommands filter to properly include commands like help, undo, and redo that have empty commandText but are still valid slash commands. Also updates terminology from "subagent" to "trace" throughout the codebase for consistency. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
1 parent eb7eb40 commit dcd4476

File tree

4 files changed

+136
-106
lines changed

4 files changed

+136
-106
lines changed

npm-app/src/cli-handlers/subagent-list.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
let isInSubagentListBuffer = false
1515
let originalKeyHandlers: ((str: string, key: any) => void)[] = []
1616
// Make selectedIndex persistent across menu transitions
17-
// This maintains selection when navigating between subagent list and individual views
17+
// This maintains selection when navigating between trace list and individual views
1818
let persistentSelectedIndex = -1 // -1 means not initialized
1919
let scrollOffset = 0
2020
let allContentLines: string[] = []
@@ -34,30 +34,31 @@ export function isInSubagentListMode(): boolean {
3434

3535
export function enterSubagentListBuffer(rl: any, onExit: () => void) {
3636
if (isInSubagentListBuffer) {
37-
console.log(yellow('Already in subagent list mode!'))
37+
console.log(yellow('Already in trace list mode!'))
3838
return
3939
}
4040

41-
// Get subagents in chronological order
41+
// Get traces in chronological order
4242
subagentList = getSubagentsChronological(50) // Get more for the list
4343

4444
if (subagentList.length === 0) {
45-
console.log(yellow('No subagents found from previous runs.'))
45+
console.log(yellow('No traces found from previous runs.'))
4646
console.log(
4747
gray(
48-
'Subagents will appear here after you use spawn_agents in a conversation.',
48+
'Traces will appear here after you use spawn_agents in a conversation.',
4949
),
5050
)
51+
onExit() // Return control to user
5152
return
5253
}
5354

5455
// Initialize selectedIndex: reset to last item when entering from main screen,
55-
// or use persistent value if returning from individual subagent view
56+
// or use persistent value if returning from individual trace view
5657
if (
5758
persistentSelectedIndex === -1 ||
5859
persistentSelectedIndex >= subagentList.length
5960
) {
60-
// First time or invalid index - select the most recent subagent (last in chronological list)
61+
// First time or invalid index - select the most recent trace (last in chronological list)
6162
persistentSelectedIndex = Math.max(0, subagentList.length - 1)
6263
}
6364
// Use the persistent selected index
@@ -129,8 +130,8 @@ function centerSelectedItem() {
129130

130131
// Define header lines as a separate function
131132
const getHeaderLines = (terminalWidth: number) => [
132-
bold(cyan('🤖 ')) + bold(magenta('Subagent History')),
133-
gray(`${pluralize(subagentList.length, 'subagent run')} `),
133+
bold(cyan('🤖 ')) + bold(magenta('Trace History')),
134+
gray(`${pluralize(subagentList.length, 'trace run')} `),
134135
'',
135136
gray('─'.repeat(terminalWidth)),
136137
'',
@@ -143,9 +144,9 @@ function buildAllContentLines() {
143144
const selectedIndex = persistentSelectedIndex
144145

145146
if (subagentList.length === 0) {
146-
lines.push(yellow('No subagents found.'))
147+
lines.push(yellow('No traces found.'))
147148
} else {
148-
// Build all content lines for all subagents
149+
// Build all content lines for all traces
149150
for (let i = 0; i < subagentList.length; i++) {
150151
subagentLinePositions.push(lines.length) // Store the starting line number
151152
const agent = subagentList[i]
@@ -357,7 +358,7 @@ function setupSubagentListKeyHandler(rl: any, onExit: () => void) {
357358
return
358359
}
359360

360-
// Handle Enter - select current subagent
361+
// Handle Enter - select current trace
361362
if (key && key.name === 'return') {
362363
if (
363364
subagentList.length > 0 &&
@@ -366,7 +367,7 @@ function setupSubagentListKeyHandler(rl: any, onExit: () => void) {
366367
const selectedAgent = subagentList[persistentSelectedIndex]
367368
exitSubagentListBuffer(rl)
368369

369-
// Enter the individual subagent buffer
370+
// Enter the individual trace buffer
370371
enterSubagentBuffer(rl, selectedAgent.agentId, onExit)
371372
}
372373
return
@@ -446,7 +447,7 @@ export function resetSubagentSelectionToLast() {
446447
persistentSelectedIndex = -1 // This will trigger reset to last item on next entry
447448
}
448449

449-
// Cleanup function to ensure we exit subagent list buffer on process termination
450+
// Cleanup function to ensure we exit trace list buffer on process termination
450451
export function cleanupSubagentListBuffer() {
451452
if (isInSubagentListBuffer) {
452453
process.stdout.write(SHOW_CURSOR)

npm-app/src/cli-handlers/subagent.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ export function isInSubagentBufferMode(): boolean {
4848
}
4949

5050
/**
51-
* Display a formatted list of subagents with enhanced styling
51+
* Display a formatted list of traces with enhanced styling
5252
*/
5353
export function displaySubagentList(agents: SubagentData[]) {
54-
console.log(bold(cyan('🤖 Available Subagents')))
55-
console.log(gray(`Found ${pluralize(agents.length, 'subagent')}`))
54+
console.log(bold(cyan('🤖 Available Traces')))
55+
console.log(gray(`Found ${pluralize(agents.length, 'trace')}`))
5656
console.log()
5757
if (agents.length === 0) {
5858
console.log(gray(' (none)'))
@@ -81,10 +81,10 @@ export function enterSubagentBuffer(
8181
return
8282
}
8383

84-
// Validate agent ID exists
84+
// Validate trace ID exists
8585
const agentData = getSubagentData(agentId)
8686
if (!agentData) {
87-
console.log(yellow(`No subagent found with ID: ${agentId}`))
87+
console.log(yellow(`No trace found with ID: ${agentId}`))
8888
const recentSubagents = getRecentSubagents(5)
8989
displaySubagentList(recentSubagents)
9090
return

npm-app/src/cli.ts

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,17 @@ export class CLI {
397397
const slashCommands = getSlashCommands()
398398
const currentInput = line.substring(1) // Text after '/'
399399

400-
const matches = slashCommands
401-
.map((cmd) => cmd.baseCommand) // Get base command strings
402-
.filter((cmdName) => cmdName && cmdName.startsWith(currentInput))
403-
.map((cmdName) => `/${cmdName}`) // Add back the slash for display
400+
// Get all command names (base commands + aliases) that match the input
401+
const allCommandNames = slashCommands.flatMap((cmd) => [
402+
cmd.baseCommand,
403+
...(cmd.aliases || []),
404+
])
405+
const matches = allCommandNames
406+
.filter(
407+
(cmdName): cmdName is string =>
408+
!!cmdName && cmdName.startsWith(currentInput),
409+
)
410+
.map((cmdName) => `/${cmdName}`)
404411

405412
if (matches.length > 0) {
406413
return [matches, line] // Return all matches and the full line typed so far
@@ -704,7 +711,23 @@ export class CLI {
704711
* @param command The command to check (without leading slash)
705712
*/
706713
private isKnownSlashCommand(command: string): boolean {
707-
return getSlashCommands().some((cmd) => cmd.baseCommand === command)
714+
return getSlashCommands().some(
715+
(cmd) => cmd.baseCommand === command || cmd.aliases?.includes(command),
716+
)
717+
}
718+
719+
/**
720+
* Checks if input matches a command (base command or any of its aliases)
721+
* @param input The input to check
722+
* @param baseCommand The base command to look for
723+
*/
724+
private isCommandOrAlias(input: string, baseCommand: string): boolean {
725+
const commandInfo = interactiveCommandDetails.find(
726+
(cmd) => cmd.baseCommand === baseCommand,
727+
)
728+
return (
729+
input === baseCommand || (commandInfo?.aliases?.includes(input) ?? false)
730+
)
708731
}
709732

710733
/**
@@ -741,15 +764,14 @@ export class CLI {
741764
const message = costModeMatch[2]?.trim() || ''
742765
const hasSlash = userInput.startsWith('/')
743766

744-
// Check if this command requires a slash for local processing
745767
const commandInfo = interactiveCommandDetails.find(
746768
(cmd) => cmd.baseCommand === mode,
747769
)
748770
const requiresSlash = commandInfo?.requireSlash ?? false
749771

750772
// If command requires slash but no slash provided, forward to backend
751773
if (requiresSlash && !hasSlash) {
752-
return userInput // Forward to backend
774+
return userInput
753775
}
754776

755777
// Track the cost mode command usage
@@ -789,16 +811,14 @@ export class CLI {
789811

790812
if (!message) {
791813
this.freshPrompt()
792-
return null // Fully handled, no message to forward
814+
return null
793815
}
794816

795-
// Return the message part to be processed as user input
796817
return message
797818
}
798819

799-
// Handle empty slash command
800820
if (userInput === '/') {
801-
return userInput // Let it be processed as a prompt
821+
return userInput
802822
}
803823

804824
// Track slash command usage if it starts with '/'
@@ -819,17 +839,17 @@ export class CLI {
819839
})
820840
}
821841

822-
if (cleanInput === 'help' || cleanInput === 'h') {
842+
if (this.isCommandOrAlias(cleanInput, 'help')) {
823843
displayMenu()
824844
this.freshPrompt()
825845
return null
826846
}
827-
if (cleanInput === 'login' || cleanInput === 'signin') {
847+
if (this.isCommandOrAlias(cleanInput, 'login')) {
828848
await Client.getInstance().login()
829849
checkpointManager.clearCheckpoints()
830850
return null
831851
}
832-
if (cleanInput === 'logout' || cleanInput === 'signout') {
852+
if (this.isCommandOrAlias(cleanInput, 'logout')) {
833853
await Client.getInstance().logout()
834854
this.freshPrompt()
835855
return null
@@ -854,11 +874,11 @@ export class CLI {
854874
return null
855875
}
856876

857-
if (cleanInput === 'usage' || cleanInput === 'credits') {
877+
if (this.isCommandOrAlias(cleanInput, 'usage')) {
858878
await Client.getInstance().getUsage()
859879
return null
860880
}
861-
if (cleanInput === 'quit' || cleanInput === 'exit' || cleanInput === 'q') {
881+
if (this.isCommandOrAlias(cleanInput, 'exit')) {
862882
await this.handleExit()
863883
return null
864884
}
@@ -886,74 +906,74 @@ export class CLI {
886906
this.freshPrompt()
887907
return null
888908
}
889-
if (['diff', 'doff', 'dif', 'iff', 'd'].includes(cleanInput)) {
909+
if (this.isCommandOrAlias(cleanInput, 'diff')) {
890910
handleDiff()
891911
this.freshPrompt()
892912
return null
893913
}
894-
if (
895-
cleanInput === 'uuddlrlrba' ||
896-
cleanInput === 'konami' ||
897-
cleanInput === 'codebuffy'
898-
) {
914+
if (this.isCommandOrAlias(cleanInput, 'konami')) {
899915
showEasterEgg(this.freshPrompt.bind(this))
900916
return null
901917
}
902918

903-
// Handle subagent command
904-
if (cleanInput.startsWith('subagent ')) {
905-
const agentId = cleanInput.substring('subagent '.length).trim()
919+
// Handle trace command (with alternate words support)
920+
const [commandBase] = cleanInput.split(' ')
921+
if (this.isCommandOrAlias(commandBase, 'trace')) {
922+
const spaceIndex = cleanInput.indexOf(' ')
923+
if (spaceIndex > 0) {
924+
// Handle trace with ID
925+
const agentId = cleanInput.substring(spaceIndex + 1).trim()
926+
927+
if (!agentId) {
928+
console.log(
929+
yellow(
930+
`Please provide a trace ID. Usage: ${commandBase} <trace-id>`,
931+
),
932+
)
933+
const recentSubagents = getRecentSubagents(10)
934+
displaySubagentList(recentSubagents)
935+
if (recentSubagents.length === 0) {
936+
// Give control back to user when no subagents exist
937+
this.freshPrompt()
938+
} else {
939+
// Pre-fill the prompt with the command for easy completion
940+
this.freshPrompt(`/${commandBase} `)
941+
}
942+
return null
943+
}
906944

907-
if (!agentId) {
908-
console.log(
909-
yellow('Please provide a subagent ID. Usage: subagent <agent-id>'),
910-
)
911-
const recentSubagents = getRecentSubagents(10)
912-
displaySubagentList(recentSubagents)
913-
if (recentSubagents.length === 0) {
914-
// Give control back to user when no subagents exist
945+
if (isInSubagentBufferMode()) {
946+
console.log(
947+
yellow('Already in trace buffer mode! Press ESC to exit.'),
948+
)
915949
this.freshPrompt()
916-
} else {
917-
// Pre-fill the prompt with '/subagent ' for easy completion
918-
this.freshPrompt('/subagent ')
950+
return null
919951
}
920-
return null
921-
}
922952

923-
if (isInSubagentBufferMode()) {
924-
console.log(
925-
yellow('Already in subagent buffer mode! Press ESC to exit.'),
926-
)
927-
this.freshPrompt()
953+
enterSubagentBuffer(this.rl, agentId, () => {
954+
// Callback when exiting subagent buffer
955+
console.log(green('\nExited trace buffer mode!'))
956+
this.freshPrompt()
957+
})
928958
return null
929-
}
930-
931-
enterSubagentBuffer(this.rl, agentId, () => {
932-
// Callback when exiting subagent buffer
933-
console.log(green('\nExited subagent buffer mode!'))
934-
this.freshPrompt()
935-
})
936-
return null
937-
}
959+
} else {
960+
// Handle bare trace command - show trace list
961+
if (isInSubagentListMode()) {
962+
console.log(yellow('Already in trace list mode! Press ESC to exit.'))
963+
this.freshPrompt()
964+
return null
965+
}
938966

939-
// Handle bare 'subagent' command (without space) - show subagent list
940-
if (cleanInput === 'subagent') {
941-
if (isInSubagentListMode()) {
942-
console.log(yellow('Already in subagent list mode! Press ESC to exit.'))
943-
this.freshPrompt()
967+
// Reset selection to last item when entering from main screen
968+
resetSubagentSelectionToLast()
969+
enterSubagentListBuffer(this.rl, () => {
970+
this.freshPrompt()
971+
})
944972
return null
945973
}
946-
947-
// Reset selection to last item when entering from main screen
948-
resetSubagentSelectionToLast()
949-
enterSubagentListBuffer(this.rl, () => {
950-
this.freshPrompt()
951-
})
952-
return null
953974
}
954975

955-
// Handle 'agents' command - show agent management interface
956-
if (cleanInput === 'agents') {
976+
if (this.isCommandOrAlias(cleanInput, 'agents')) {
957977
if (isInAgentsMode()) {
958978
console.log(yellow('Already in agents mode! Press ESC to exit.'))
959979
this.freshPrompt()

0 commit comments

Comments
 (0)