@@ -451,12 +451,35 @@ export class CopilotSessionStorage extends BaseSessionStorage {
451451 }
452452 }
453453
454+ /** Check if a remote-fs error indicates a benign not-found/permission case vs an unexpected SSH failure. */
455+ private isExpectedRemoteError ( error ?: string ) : boolean {
456+ if ( ! error ) return false ;
457+ const lower = error . toLowerCase ( ) ;
458+ return (
459+ lower . includes ( 'not found' ) ||
460+ lower . includes ( 'not accessible' ) ||
461+ lower . includes ( 'no such file' ) ||
462+ lower . includes ( 'permission denied' ) ||
463+ lower . includes ( 'does not exist' )
464+ ) ;
465+ }
466+
454467 /** List all session directory names from the session state directory. */
455468 private async listSessionIds ( sshConfig ?: SshRemoteConfig ) : Promise < string [ ] > {
456469 const sessionStateDir = this . getSessionStateDir ( sshConfig ) ;
457470 if ( sshConfig ) {
458471 const result = await readDirRemote ( sessionStateDir , sshConfig ) ;
459472 if ( ! result . success || ! result . data ) {
473+ if ( ! this . isExpectedRemoteError ( result . error ) ) {
474+ logger . warn (
475+ `Unexpected SSH failure listing Copilot sessions: ${ result . error } ` ,
476+ LOG_CONTEXT
477+ ) ;
478+ captureException ( new Error ( result . error || 'readDirRemote failed' ) , {
479+ operation : 'copilotStorage:listSessionIds:remote' ,
480+ sessionStateDir,
481+ } ) ;
482+ }
460483 return [ ] ;
461484 }
462485 return result . data . filter ( ( entry ) => entry . isDirectory ) . map ( ( entry ) => entry . name ) ;
@@ -590,21 +613,37 @@ export class CopilotSessionStorage extends BaseSessionStorage {
590613 }
591614 }
592615
593- /** Read a file from a remote host via SSH. Returns null on failure . */
616+ /** Read a file from a remote host via SSH. Returns null on not-found; reports unexpected failures to Sentry . */
594617 private async readRemoteFile (
595618 filePath : string ,
596619 sshConfig : SshRemoteConfig
597620 ) : Promise < string | null > {
598621 const result = await readFileRemote ( filePath , sshConfig ) ;
599- return result . success && result . data ? result . data : null ;
622+ if ( result . success && result . data ) return result . data ;
623+ if ( ! this . isExpectedRemoteError ( result . error ) ) {
624+ logger . warn ( `Unexpected SSH failure reading ${ filePath } : ${ result . error } ` , LOG_CONTEXT ) ;
625+ captureException ( new Error ( result . error || 'readFileRemote failed' ) , {
626+ operation : 'copilotStorage:readRemoteFile' ,
627+ filePath,
628+ } ) ;
629+ }
630+ return null ;
600631 }
601632
602- /** Calculate the total size of a session directory on a remote host. */
633+ /** Calculate the total size of a session directory on a remote host. Returns 0 on not-found; reports unexpected failures. */
603634 private async getRemoteDirectorySize (
604635 sessionDir : string ,
605636 sshConfig : SshRemoteConfig
606637 ) : Promise < number > {
607638 const result = await directorySizeRemote ( sessionDir , sshConfig ) ;
608- return result . success && result . data ? result . data : 0 ;
639+ if ( result . success && result . data ) return result . data ;
640+ if ( ! this . isExpectedRemoteError ( result . error ) ) {
641+ logger . warn ( `Unexpected SSH failure sizing ${ sessionDir } : ${ result . error } ` , LOG_CONTEXT ) ;
642+ captureException ( new Error ( result . error || 'directorySizeRemote failed' ) , {
643+ operation : 'copilotStorage:getRemoteDirectorySize' ,
644+ sessionDir,
645+ } ) ;
646+ }
647+ return 0 ;
609648 }
610649}
0 commit comments