@@ -19,7 +19,11 @@ import intermediateGitCommitter from '../../../common/src/templates/initial-agen
1919import advancedFileExplorer from '../../../common/src/templates/initial-agents-dir/examples/03-advanced-file-explorer' with { type : 'text' }
2020import myCustomAgent from '../../../common/src/templates/initial-agents-dir/my-custom-agent' with { type : 'text' }
2121
22- import { loadLocalAgents , getLoadedAgentNames } from '../agents/load-agents'
22+ import {
23+ loadLocalAgents ,
24+ getLoadedAgentNames ,
25+ loadedAgents ,
26+ } from '../agents/load-agents'
2327import { CLI } from '../cli'
2428import { getProjectRoot } from '../project-files'
2529import { Spinner } from '../utils/spinner'
@@ -90,35 +94,87 @@ export async function enterAgentsBuffer(rl: any, onExit: () => void) {
9094 customAgentFiles = filterCustomAgentFiles ( files )
9195 }
9296
93- // Add agents section header
94- actions . push ( {
95- id : '__agents_header__' ,
96- name :
97- bold ( cyan ( 'Custom Agents' ) ) +
98- gray ( ` • ${ customAgentFiles . length } in ${ AGENT_TEMPLATES_DIR } ` ) ,
99- description : '' ,
100- isBuiltIn : false ,
101- isSectionHeader : true ,
102- } )
103-
10497 // Build agent list starting with management actions
10598 agentList = [ ...actions ]
10699
107- // Add custom agents from .agents/templates
108- if ( customAgentFiles . length > 0 ) {
109- for ( const file of customAgentFiles ) {
110- const agentId = extractAgentIdFromFileName ( file )
111- const agentName = localAgents [ agentId ] || agentId
100+ // Collect custom agents from .agents/templates
101+ const agentEntries = customAgentFiles . map ( ( file ) => {
102+ const agentId = extractAgentIdFromFileName ( file )
103+ const filePath = path . join ( agentsDir , file )
104+ let mtime = 0
105+ try {
106+ mtime = fs . statSync ( filePath ) . mtimeMs
107+ } catch { }
108+ const def = ( loadedAgents as any ) [ agentId ]
109+ return { file, agentId, filePath, mtime, def }
110+ } )
111+
112+ const validAgents = agentEntries
113+ . filter ( ( e ) => e . def && e . def . id && e . def . model )
114+ . sort ( ( a , b ) => b . mtime - a . mtime )
115+
116+ const now = Date . now ( )
117+ const sevenDaysMs = 7 * 24 * 60 * 60 * 1000
118+ const recentAgents = validAgents . filter ( ( e ) => now - e . mtime <= sevenDaysMs )
119+ const otherAgents = validAgents . filter ( ( e ) => now - e . mtime > sevenDaysMs )
120+
121+ if ( validAgents . length > 0 ) {
122+ if ( recentAgents . length > 0 ) {
123+ agentList . push ( {
124+ id : '__recent_agents_header__' ,
125+ name : bold ( cyan ( 'Recently Updated' ) ) + gray ( ' • last 7 days' ) ,
126+ description : '' ,
127+ isBuiltIn : false ,
128+ isSectionHeader : true ,
129+ } )
130+
131+ for ( const entry of recentAgents ) {
132+ const agentName =
133+ localAgents [ entry . agentId ] || entry . def ?. displayName || entry . agentId
134+ agentList . push ( {
135+ id : entry . agentId ,
136+ name : agentName ,
137+ description : entry . def ?. description || 'Custom user-defined agent' ,
138+ isBuiltIn : false ,
139+ filePath : entry . filePath ,
140+ } )
141+ }
142+ }
143+
144+ if ( otherAgents . length > 0 ) {
112145 agentList . push ( {
113- id : agentId ,
114- name : agentName ,
115- description : 'Custom user-defined agent' ,
146+ id : '__agents_header__' ,
147+ name :
148+ bold ( cyan ( 'Custom Agents' ) ) +
149+ gray ( ` • ${ otherAgents . length } in ${ AGENT_TEMPLATES_DIR } ` ) ,
150+ description : '' ,
116151 isBuiltIn : false ,
117- filePath : path . join ( agentsDir , file ) ,
152+ isSectionHeader : true ,
118153 } )
154+
155+ for ( const entry of otherAgents ) {
156+ const agentName =
157+ localAgents [ entry . agentId ] || entry . def ?. displayName || entry . agentId
158+ agentList . push ( {
159+ id : entry . agentId ,
160+ name : agentName ,
161+ description : entry . def ?. description || 'Custom user-defined agent' ,
162+ isBuiltIn : false ,
163+ filePath : entry . filePath ,
164+ } )
165+ }
119166 }
120167 } else {
121- // If no custom agents, add a helpful message
168+ // No valid agents; show header + placeholder
169+ agentList . push ( {
170+ id : '__agents_header__' ,
171+ name :
172+ bold ( cyan ( 'Custom Agents' ) ) +
173+ gray ( ` • ${ customAgentFiles . length } in ${ AGENT_TEMPLATES_DIR } ` ) ,
174+ description : '' ,
175+ isBuiltIn : false ,
176+ isSectionHeader : true ,
177+ } )
122178 agentList . push ( {
123179 id : '__no_agents__' ,
124180 name : gray ( 'No custom agents found' ) ,
@@ -128,8 +184,6 @@ export async function enterAgentsBuffer(rl: any, onExit: () => void) {
128184 } )
129185 }
130186
131- // No need for special handling here since we now have a proper placeholder
132-
133187 // Initialize selection to first selectable item
134188 selectedIndex = 0
135189 // Find first selectable item (skip section headers, separators, placeholders)
@@ -400,7 +454,7 @@ function renderAgentsList() {
400454 }
401455
402456 // Display status line at bottom
403- const statusLine = `\n${ gray ( `Use ↑/↓/j/k to navigate, Enter to select, ESC to go back` ) } `
457+ const statusLine = `\n${ gray ( `Use ↑/↓/j/k to navigate, Enter to select, ESC or q to go back` ) } `
404458
405459 process . stdout . write ( statusLine )
406460 process . stdout . write ( HIDE_CURSOR )
@@ -416,7 +470,11 @@ function setupAgentsKeyHandler(rl: any, onExit: () => void) {
416470
417471 // Add our custom handler
418472 process . stdin . on ( 'keypress' , ( str : string , key : any ) => {
419- if ( key && key . name === 'escape' ) {
473+ // Support ESC or 'q' (no ctrl/meta) to go back
474+ if (
475+ ( key && key . name === 'escape' ) ||
476+ ( ! key ?. ctrl && ! key ?. meta && str === 'q' )
477+ ) {
420478 exitAgentsBuffer ( rl )
421479 onExit ( )
422480 return
0 commit comments