@@ -298,7 +298,7 @@ Object.assign(CodemanApp.prototype, {
298298 // Find the highest existing w-number for THIS case to avoid duplicates
299299 let startNumber = 1 ;
300300 for ( const [ , session ] of this . sessions ) {
301- const match = session . name && session . name . match ( / ^ w ( \d + ) - ( . + ) $ / ) ;
301+ const match = session . name && session . name . match ( / ^ w ( \d + ) - ( [ a - z A - Z 0 - 9 _ - ] + ) / ) ;
302302 if ( match && match [ 2 ] === caseName ) {
303303 const num = parseInt ( match [ 1 ] ) ;
304304 if ( num >= startNumber ) {
@@ -432,7 +432,7 @@ Object.assign(CodemanApp.prototype, {
432432 // Find the highest existing s-number for THIS case to avoid duplicates
433433 let startNumber = 1 ;
434434 for ( const [ , session ] of this . sessions ) {
435- const match = session . name && session . name . match ( / ^ s ( \d + ) - ( . + ) $ / ) ;
435+ const match = session . name && session . name . match ( / ^ s ( \d + ) - ( [ a - z A - Z 0 - 9 _ - ] + ) / ) ;
436436 if ( match && match [ 2 ] === caseName ) {
437437 const num = parseInt ( match [ 1 ] ) ;
438438 if ( num >= startNumber ) {
@@ -596,8 +596,20 @@ Object.assign(CodemanApp.prototype, {
596596 document . getElementById ( 'modalImageWatcherEnabled' ) . checked = session . imageWatcherEnabled ?? true ;
597597 document . getElementById ( 'modalFlickerFilterEnabled' ) . checked = session . flickerFilterEnabled ?? false ;
598598
599- // Populate session name input
600- document . getElementById ( 'modalSessionName' ) . value = session . name || '' ;
599+ // Populate session name input with prefix/suffix split
600+ const _modalParsed = parseSessionPrefix ( session . name ) ;
601+ const _prefixEl = document . getElementById ( 'modalSessionPrefix' ) ;
602+ if ( _modalParsed ) {
603+ _prefixEl . textContent = _modalParsed . prefix + ': ' ;
604+ _prefixEl . style . display = '' ;
605+ document . getElementById ( 'modalSessionName' ) . value = _modalParsed . suffix ;
606+ document . getElementById ( 'modalSessionName' ) . placeholder = 'Add description...' ;
607+ } else {
608+ _prefixEl . style . display = 'none' ;
609+ _prefixEl . textContent = '' ;
610+ document . getElementById ( 'modalSessionName' ) . value = session . name || '' ;
611+ document . getElementById ( 'modalSessionName' ) . placeholder = 'Auto (directory name)' ;
612+ }
601613
602614 // Initialize color picker with current session color
603615 const currentColor = session . color || 'default' ;
@@ -644,7 +656,15 @@ Object.assign(CodemanApp.prototype, {
644656
645657 async saveSessionName ( ) {
646658 if ( ! this . editingSessionId ) return ;
647- const name = document . getElementById ( 'modalSessionName' ) . value . trim ( ) ;
659+ const session = this . sessions . get ( this . editingSessionId ) ;
660+ const parsed = session ? parseSessionPrefix ( session . name ) : null ;
661+ const inputVal = document . getElementById ( 'modalSessionName' ) . value . trim ( ) ;
662+ let name ;
663+ if ( parsed ) {
664+ name = parsed . prefix + ( inputVal ? ': ' + inputVal : '' ) ;
665+ } else {
666+ name = inputVal ;
667+ }
648668 try {
649669 await this . _apiPut ( `/api/sessions/${ this . editingSessionId } /name` , { name } ) ;
650670 } catch ( err ) {
@@ -864,29 +884,46 @@ Object.assign(CodemanApp.prototype, {
864884 if ( ! tabName ) return ;
865885
866886 const currentName = this . getSessionName ( session ) ;
887+ const parsed = parseSessionPrefix ( session . name ) ;
888+ const originalContent = tabName . textContent ;
889+ tabName . textContent = '' ;
890+ tabName . innerHTML = '' ;
891+
892+ // If prefix detected, show it as non-editable label
893+ if ( parsed ) {
894+ const prefixLabel = document . createElement ( 'span' ) ;
895+ prefixLabel . textContent = parsed . prefix + ': ' ;
896+ prefixLabel . style . cssText = 'color: var(--text-muted); font-size: 0.75rem; white-space: nowrap;' ;
897+ tabName . appendChild ( prefixLabel ) ;
898+ }
899+
867900 const input = document . createElement ( 'input' ) ;
868901 input . type = 'text' ;
869- input . value = session . name || '' ;
870- input . placeholder = currentName ;
902+ input . value = parsed ? parsed . suffix : ( session . name || '' ) ;
903+ input . placeholder = parsed ? 'Add description...' : currentName ;
871904 input . className = 'tab-rename-input' ;
872905 input . style . cssText = 'width: 80px; font-size: 0.75rem; padding: 2px 4px; background: var(--bg-input); border: 1px solid var(--accent); border-radius: 3px; color: var(--text); outline: none;' ;
873906
874- const originalContent = tabName . textContent ;
875- tabName . textContent = '' ;
876907 tabName . appendChild ( input ) ;
877908 input . focus ( ) ;
878909 input . select ( ) ;
879910
880911 const finishRename = async ( ) => {
881- const newName = input . value . trim ( ) ;
882- tabName . textContent = newName || originalContent ;
912+ const suffix = input . value . trim ( ) ;
913+ let fullName ;
914+ if ( parsed ) {
915+ fullName = parsed . prefix + ( suffix ? ': ' + suffix : '' ) ;
916+ } else {
917+ fullName = suffix ;
918+ }
919+ tabName . textContent = fullName || originalContent ;
883920
884- if ( newName && newName !== session . name ) {
921+ if ( fullName !== session . name ) {
885922 try {
886923 await fetch ( `/api/sessions/${ sessionId } /name` , {
887924 method : 'PUT' ,
888925 headers : { 'Content-Type' : 'application/json' } ,
889- body : JSON . stringify ( { name : newName } )
926+ body : JSON . stringify ( { name : fullName } )
890927 } ) ;
891928 } catch ( err ) {
892929 tabName . textContent = originalContent ;
0 commit comments