@@ -162,6 +162,59 @@ interface ShellProfile {
162162 args ?: string [ ] ;
163163}
164164
165+ /**
166+ * Safely format duration from start and end timestamps
167+ * Handles undefined/null values gracefully for robust Tauri integration
168+ * @param startTime - Start timestamp (ms)
169+ * @param endTime - End timestamp (ms)
170+ * @returns Formatted duration string or null if times are invalid
171+ */
172+ function formatCommandDuration ( startTime : number | undefined , endTime : number | undefined ) : string | null {
173+ if ( startTime === undefined || endTime === undefined ) return null ;
174+ if ( startTime <= 0 || endTime <= 0 ) return null ;
175+
176+ const duration = endTime - startTime ;
177+ if ( duration < 0 ) return null ;
178+
179+ if ( duration < 1000 ) {
180+ return `${ duration } ms` ;
181+ } else if ( duration < 60000 ) {
182+ return `${ ( duration / 1000 ) . toFixed ( 1 ) } s` ;
183+ } else {
184+ const minutes = Math . floor ( duration / 60000 ) ;
185+ const seconds = ( ( duration % 60000 ) / 1000 ) . toFixed ( 0 ) ;
186+ return `${ minutes } m ${ seconds } s` ;
187+ }
188+ }
189+
190+ /**
191+ * Check if a terminal instance is in a valid state for writing
192+ * Provides defensive checks to prevent crashes when terminal is closing
193+ * @param terminal - XTerm terminal instance
194+ * @param terminalId - Terminal ID for debug logging
195+ * @returns true if terminal is valid for writing
196+ */
197+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
198+ function isTerminalWritable ( terminal : XTerm | null | undefined , terminalId : string ) : boolean {
199+ try {
200+ if ( ! terminal ) {
201+ console . debug ( `[Terminal] Terminal ${ terminalId } is null` ) ;
202+ return false ;
203+ }
204+ if ( ! terminal . element ) {
205+ console . debug ( `[Terminal] Terminal ${ terminalId } element is null` ) ;
206+ return false ;
207+ }
208+ if ( terminal . element . classList . contains ( 'disposed' ) ) {
209+ console . debug ( `[Terminal] Terminal ${ terminalId } has disposed class` ) ;
210+ return false ;
211+ }
212+ return true ;
213+ } catch {
214+ return false ;
215+ }
216+ }
217+
165218// Get shell type from shell path/name
166219function getShellType ( shell : string ) : ShellType {
167220 const shellLower = shell . toLowerCase ( ) ;
@@ -1388,6 +1441,7 @@ export function TerminalPanel() {
13881441
13891442 /**
13901443 * Format tooltip text for command marker
1444+ * Uses formatCommandDuration helper for safe duration handling with undefined metadata
13911445 */
13921446 const formatCommandTooltip = ( marker : CommandMarker ) : string => {
13931447 const lines : string [ ] = [ ] ;
@@ -1402,17 +1456,10 @@ export function TerminalPanel() {
14021456 lines . push ( `Exit Code: ${ marker . exitCode } ` ) ;
14031457 }
14041458
1405- if ( marker . startTime && marker . endTime ) {
1406- const duration = marker . endTime - marker . startTime ;
1407- if ( duration < 1000 ) {
1408- lines . push ( `Duration: ${ duration } ms` ) ;
1409- } else if ( duration < 60000 ) {
1410- lines . push ( `Duration: ${ ( duration / 1000 ) . toFixed ( 1 ) } s` ) ;
1411- } else {
1412- const minutes = Math . floor ( duration / 60000 ) ;
1413- const seconds = ( ( duration % 60000 ) / 1000 ) . toFixed ( 0 ) ;
1414- lines . push ( `Duration: ${ minutes } m ${ seconds } s` ) ;
1415- }
1459+ // Use helper function for safe duration formatting (handles undefined metadata from Tauri)
1460+ const durationStr = formatCommandDuration ( marker . startTime , marker . endTime ) ;
1461+ if ( durationStr ) {
1462+ lines . push ( `Duration: ${ durationStr } ` ) ;
14161463 } else if ( marker . startTime && marker . status === 'running' ) {
14171464 lines . push ( 'Running...' ) ;
14181465 }
@@ -1513,12 +1560,8 @@ export function TerminalPanel() {
15131560
15141561 // Announce command completion to screen reader
15151562 if ( ts . screenReaderAnnounce ) {
1516- const duration = marker . endTime - ( marker . startTime || marker . endTime ) ;
1517- const durationStr = duration < 1000
1518- ? `${ duration } ms`
1519- : duration < 60000
1520- ? `${ ( duration / 1000 ) . toFixed ( 1 ) } s`
1521- : `${ Math . floor ( duration / 60000 ) } m ${ ( ( duration % 60000 ) / 1000 ) . toFixed ( 0 ) } s` ;
1563+ // Use helper for safe duration formatting (handles undefined metadata from Tauri)
1564+ const durationStr = formatCommandDuration ( marker . startTime , marker . endTime ) ?? "unknown time" ;
15221565 const commandName = marker . command ? `"${ marker . command } "` : "Command" ;
15231566 const statusMsg = marker . status === 'success'
15241567 ? `${ commandName } completed successfully in ${ durationStr } `
0 commit comments