@@ -8,6 +8,7 @@ type Props = {
88 onSelect : ( sessionId : string ) => void ;
99 onCancel : ( ) => void ;
1010 onDelete ?: ( sessionId : string ) => void ;
11+ onRename ?: ( sessionId : string , newName : string ) => void ;
1112} ;
1213
1314/**
@@ -38,10 +39,13 @@ export function filterSessions(sessions: SessionEntry[], query: string): Session
3839 } ) ;
3940}
4041
41- export function SessionList ( { sessions, onSelect, onCancel, onDelete } : Props ) : React . ReactElement {
42+ export function SessionList ( { sessions, onSelect, onCancel, onDelete, onRename } : Props ) : React . ReactElement {
4243 const [ index , setIndex ] = useState ( 0 ) ;
4344 const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
4445 const [ confirmDeleteSessionId , setConfirmDeleteSessionId ] = useState < string | null > ( null ) ;
46+ const [ renameSessionId , setRenameSessionId ] = useState < string | null > ( null ) ;
47+ const [ renameValue , setRenameValue ] = useState ( "" ) ;
48+ const [ renameCursor , setRenameCursor ] = useState ( 0 ) ;
4549 const { columns, rows } = useWindowSize ( ) ;
4650
4751 // Filter sessions by search query
@@ -83,6 +87,65 @@ export function SessionList({ sessions, onSelect, onCancel, onDelete }: Props):
8387 const selectedSession = filteredSessions [ safeIndex ] ;
8488
8589 useInput ( ( input , key ) => {
90+ // If in rename mode, handle rename editing
91+ if ( renameSessionId ) {
92+ if ( key . return ) {
93+ if ( renameValue . trim ( ) ) {
94+ onRename ?.( renameSessionId , renameValue . trim ( ) ) ;
95+ }
96+ setRenameSessionId ( null ) ;
97+ setRenameValue ( "" ) ;
98+ setRenameCursor ( 0 ) ;
99+ return ;
100+ }
101+ if ( key . escape ) {
102+ setRenameSessionId ( null ) ;
103+ setRenameValue ( "" ) ;
104+ setRenameCursor ( 0 ) ;
105+ return ;
106+ }
107+ if ( key . leftArrow ) {
108+ setRenameCursor ( ( c ) => Math . max ( 0 , c - 1 ) ) ;
109+ return ;
110+ }
111+ if ( key . rightArrow ) {
112+ setRenameCursor ( ( c ) => Math . min ( renameValue . length , c + 1 ) ) ;
113+ return ;
114+ }
115+ if ( key . home ) {
116+ setRenameCursor ( 0 ) ;
117+ return ;
118+ }
119+ if ( key . end ) {
120+ setRenameCursor ( renameValue . length ) ;
121+ return ;
122+ }
123+ if ( key . delete ) {
124+ if ( renameCursor < renameValue . length ) {
125+ setRenameValue ( ( prev ) => prev . slice ( 0 , renameCursor ) + prev . slice ( renameCursor + 1 ) ) ;
126+ // cursor stays at same position (next char shifts left)
127+ }
128+ return ;
129+ }
130+ if ( key . backspace ) {
131+ if ( renameCursor > 0 ) {
132+ setRenameValue ( ( prev ) => prev . slice ( 0 , renameCursor - 1 ) + prev . slice ( renameCursor ) ) ;
133+ setRenameCursor ( ( c ) => c - 1 ) ;
134+ }
135+ return ;
136+ }
137+ // Printable character: insert at cursor position
138+ if ( input && input . length > 0 && ! key . meta && ! key . ctrl && ! key . tab ) {
139+ if ( key . upArrow || key . downArrow ) {
140+ return ;
141+ }
142+ setRenameValue ( ( prev ) => prev . slice ( 0 , renameCursor ) + input + prev . slice ( renameCursor ) ) ;
143+ setRenameCursor ( ( c ) => c + input . length ) ;
144+ return ;
145+ }
146+ return ;
147+ }
148+
86149 // If in delete confirmation mode, handle confirm/cancel
87150 if ( confirmDeleteSessionId ) {
88151 if ( key . return ) {
@@ -114,6 +177,17 @@ export function SessionList({ sessions, onSelect, onCancel, onDelete }: Props):
114177 return ;
115178 }
116179
180+ // Ctrl+R: start rename on selected session
181+ if ( key . ctrl && ( input === "r" || input === "R" ) ) {
182+ if ( selectedSession && onRename ) {
183+ const name = selectedSession . summary || "" ;
184+ setRenameSessionId ( selectedSession . id ) ;
185+ setRenameValue ( name ) ;
186+ setRenameCursor ( name . length ) ;
187+ return ;
188+ }
189+ }
190+
117191 // Delete key: remove search character, or start delete confirmation
118192 if ( key . delete || key . backspace ) {
119193 if ( searchQuery ) {
@@ -237,19 +311,28 @@ export function SessionList({ sessions, onSelect, onCancel, onDelete }: Props):
237311 const actualIndex = scrollOffset + i ;
238312 const isSelected = actualIndex === safeIndex ;
239313 const isConfirming = confirmDeleteSessionId === session . id ;
314+ const isRenaming = renameSessionId === session . id ;
240315 return (
241316 < Box key = { session . id } height = { 2 } marginBottom = { 1 } >
242317 < Box >
243318 < Text color = "#229ac3" > { isSelected ? "> " : " " } </ Text >
244319 </ Box >
245320 < Box flexDirection = "column" flexGrow = { 1 } >
246321 < Box width = { "100%" } >
247- < Text { ...( isSelected ? { bold : true } : { } ) } color = { isSelected ? "#229ac3" : undefined } >
248- { formatSessionTitle ( session . summary || "Untitled" ) }
249- </ Text >
322+ { isRenaming ? (
323+ < Text color = "yellow" >
324+ Rename: { renameValue . slice ( 0 , renameCursor ) }
325+ < Text bold > |</ Text >
326+ { renameValue . slice ( renameCursor ) }
327+ </ Text >
328+ ) : (
329+ < Text { ...( isSelected ? { bold : true } : { } ) } color = { isSelected ? "#229ac3" : undefined } >
330+ { formatSessionTitle ( session . summary || "Untitled" ) }
331+ </ Text >
332+ ) }
250333 { isConfirming ? (
251334 < Text color = "yellow" > [Delete? Enter=yes, Esc=no]</ Text >
252- ) : (
335+ ) : isRenaming ? null : (
253336 < Text dimColor > ({ formatSessionStatus ( session . status ) } )</ Text >
254337 ) }
255338 </ Box >
@@ -272,7 +355,19 @@ export function SessionList({ sessions, onSelect, onCancel, onDelete }: Props):
272355 </ Box >
273356 { /* Footer */ }
274357 < Box flexDirection = "column" >
275- { confirmDeleteSessionId ? (
358+ { renameSessionId ? (
359+ < Box >
360+ < Text color = "yellow" > Input new session name, </ Text >
361+ < Text bold color = "green" >
362+ Enter
363+ </ Text >
364+ < Text dimColor > to save · </ Text >
365+ < Text bold color = "red" >
366+ Esc
367+ </ Text >
368+ < Text dimColor > to cancel</ Text >
369+ </ Box >
370+ ) : confirmDeleteSessionId ? (
276371 < Box >
277372 < Text color = "yellow" > Delete this session? </ Text >
278373 < Text bold color = "green" >
@@ -292,7 +387,7 @@ export function SessionList({ sessions, onSelect, onCancel, onDelete }: Props):
292387 ) : (
293388 < Box >
294389 < Text dimColor >
295- Type to search · ↑/↓ navigate · PgUp/PgDn page · Enter select · Esc cancel · Del delete
390+ Type to search · ↑/↓ navigate · PgUp/PgDn page · Enter select · Esc cancel · Del delete · Ctrl+r rename
296391 </ Text >
297392 </ Box >
298393 ) }
0 commit comments