@@ -21,6 +21,7 @@ import { buildUnifiedDiffForStatus } from './utils/diff'
2121import { countTokens } from './utils/tokenizer'
2222// Globally shared token counts
2323import { TokenCountsProvider , useTokenCountsContext } from './context/TokenCountsContext'
24+ import { isBinaryPath } from './utils/binary'
2425import { logError } from './utils/logger'
2526import { debounce } from './utils/debounce'
2627
@@ -580,6 +581,11 @@ function App() {
580581
581582 async function previewFile ( path : string , status : FileDiffStatus ) : Promise < void > {
582583 if ( ! gitClient ) return
584+ // Hard guard: no previews for binary files (prevents heavy reads)
585+ if ( isBinaryPath ( path ) ) {
586+ setNotif ( 'Binary file preview is not supported.' )
587+ return
588+ }
583589 try {
584590 const toFetchBase = status !== 'add'
585591 const toFetchCompare = status !== 'remove'
@@ -589,6 +595,13 @@ function App() {
589595 toFetchCompare && compareBranch ? gitClient . readFile ( compareBranch , path ) : Promise . resolve ( undefined ) ,
590596 ] )
591597
598+ // If worker reports binary, bail out as well
599+ const baseBin = ( baseRes as any ) ?. binary
600+ const compareBin = ( compareRes as any ) ?. binary
601+ if ( baseBin || compareBin ) {
602+ setNotif ( 'Binary file preview is not supported.' )
603+ return
604+ }
592605 setPreviewPath ( path )
593606 setPreviewStatus ( status )
594607 setPreviewData ( {
@@ -654,19 +667,27 @@ function App() {
654667 // File sections
655668 const fileSections : string [ ] = [ ]
656669 const includeBinaryNow = ( includeBinaryCheckboxRef . current ?. checked ?? includeBinaryAsPathsRef . current )
657- const pathsToProcess = includeBinaryNow ? selected : selected . filter ( ( p ) => ! isLikelyBinaryPath ( p ) )
670+ const pathsToProcess = includeBinaryNow ? selected : selected . filter ( ( p ) => ! isBinaryPath ( p ) )
658671 const fileReadPromises = pathsToProcess . map ( ( path ) => {
659672 const status = statusByPath . get ( path ) ?? 'unchanged'
660673 const needBase = status !== 'add'
661674 const needCompare = status !== 'remove'
675+ // Avoid heavy reads for binary paths — we only emit a header line
676+ if ( isBinaryPath ( path ) ) {
677+ return Promise . resolve ( {
678+ path, status,
679+ baseRes : { binary : true , text : null } ,
680+ compareRes : { binary : true , text : null } ,
681+ } )
682+ }
662683 return Promise . all ( [
663684 needBase ? gitClient . readFile ( baseBranch , path ) : Promise . resolve ( undefined ) ,
664685 needCompare ? gitClient . readFile ( compareBranch , path ) : Promise . resolve ( undefined ) ,
665686 ] ) . then ( ( [ baseRes , compareRes ] ) => ( { path, status, baseRes, compareRes } ) )
666687 } )
667688 const fileContents = await Promise . all ( fileReadPromises )
668689 for ( const { path, status, baseRes, compareRes } of fileContents ) {
669- const isBinary = ( baseRes as { binary ?: boolean } | undefined ) ?. binary || ( compareRes as { binary ?: boolean } | undefined ) ?. binary || isLikelyBinaryPath ( path )
690+ const isBinary = ( baseRes as { binary ?: boolean } | undefined ) ?. binary || ( compareRes as { binary ?: boolean } | undefined ) ?. binary || isBinaryPath ( path )
670691 const header = `## FILE: ${ path } (${ status . toUpperCase ( ) } )\n\n`
671692 if ( isBinary ) {
672693 // When we filtered out likely-binary paths earlier and still hit binary here (e.g. unknown ext),
@@ -741,17 +762,7 @@ function App() {
741762 if ( lower . endsWith ( '.html' ) || lower . endsWith ( '.htm' ) ) return 'html'
742763 return ''
743764 }
744- function isLikelyBinaryPath ( p : string ) : boolean {
745- const lower = p . toLowerCase ( )
746- const binaryExts = [
747- '.png' , '.jpg' , '.jpeg' , '.gif' , '.bmp' , '.webp' , '.ico' ,
748- '.pdf' , '.zip' , '.rar' , '.7z' , '.tar' , '.gz' , '.tgz' ,
749- '.mp3' , '.wav' , '.flac' , '.mp4' , '.mov' , '.avi' , '.mkv' , '.webm' ,
750- '.exe' , '.dll' , '.bin' , '.dmg' , '.pkg' , '.iso' ,
751- '.woff' , '.woff2' , '.ttf' , '.otf'
752- ]
753- return binaryExts . some ( ( ext ) => lower . endsWith ( ext ) )
754- }
765+ // binary detection now centralized in utils/binary.ts (isBinaryPath)
755766
756767 // Small helper: use context to feed TokenUsage without prop-drilling
757768 function TokenUsageWithContext ( {
@@ -847,6 +858,7 @@ function App() {
847858 selectedPaths = { selectedPaths }
848859 statusByPath = { statusByPath }
849860 diffContextLines = { diffContextLines }
861+ includeBinaryPaths = { includeBinaryAsPaths }
850862 >
851863 < div className = { `app-container${ ! projectLoaded ? ' landing-full' : '' } ` } id = "gc-app" >
852864 < header className = "header" >
@@ -1135,7 +1147,7 @@ function App() {
11351147 const curr = Array . from ( selectedPathsRef . current )
11361148 const removed : string [ ] = [ ]
11371149 for ( const p of curr ) {
1138- if ( isLikelyBinaryPath ( p ) ) {
1150+ if ( isBinaryPath ( p ) ) {
11391151 removed . push ( p )
11401152 toggleSelect ( p )
11411153 }
0 commit comments