66import { t } from '@thacio/auditaria-cli-core' ;
77
88import { spawn } from 'child_process' ;
9- import { StringDecoder } from 'string_decoder ' ;
9+ import { TextDecoder } from 'util ' ;
1010import {
1111 HistoryItemWithoutId ,
1212 IndividualToolCallDisplay ,
1313 ToolCallStatus ,
1414} from '../types.js' ;
1515import { useCallback } from 'react' ;
16- import { Config , GeminiClient } from '@thacio/auditaria-cli-core' ;
16+ import {
17+ Config ,
18+ GeminiClient ,
19+ getCachedEncodingForBuffer ,
20+ } from '@thacio/auditaria-cli-core' ;
1721import { type PartListUnion } from '@google/genai' ;
1822import { formatMemoryUsage } from '../utils/formatters.js' ;
1923import { isBinary } from '../utils/textUtils.js' ;
@@ -72,8 +76,8 @@ function executeShellCommand(
7276 } ) ;
7377
7478 // Use decoders to handle multi-byte characters safely (for streaming output).
75- const stdoutDecoder = new StringDecoder ( 'utf8' ) ;
76- const stderrDecoder = new StringDecoder ( 'utf8' ) ;
79+ let stdoutDecoder : TextDecoder | null = null ;
80+ let stderrDecoder : TextDecoder | null = null ;
7781
7882 let stdout = '' ;
7983 let stderr = '' ;
@@ -86,6 +90,12 @@ function executeShellCommand(
8690 let sniffedBytes = 0 ;
8791
8892 const handleOutput = ( data : Buffer , stream : 'stdout' | 'stderr' ) => {
93+ if ( ! stdoutDecoder || ! stderrDecoder ) {
94+ const encoding = getCachedEncodingForBuffer ( data ) ;
95+ stdoutDecoder = new TextDecoder ( encoding ) ;
96+ stderrDecoder = new TextDecoder ( encoding ) ;
97+ }
98+
8999 outputChunks . push ( data ) ;
90100
91101 if ( streamToUi && sniffedBytes < MAX_SNIFF_SIZE ) {
@@ -102,8 +112,8 @@ function executeShellCommand(
102112
103113 const decodedChunk =
104114 stream === 'stdout'
105- ? stdoutDecoder . write ( data )
106- : stderrDecoder . write ( data ) ;
115+ ? stdoutDecoder . decode ( data , { stream : true } )
116+ : stderrDecoder . decode ( data , { stream : true } ) ;
107117 if ( stream === 'stdout' ) {
108118 stdout += stripAnsi ( decodedChunk ) ;
109119 } else {
@@ -161,8 +171,12 @@ function executeShellCommand(
161171 abortSignal . removeEventListener ( 'abort' , abortHandler ) ;
162172
163173 // Handle any final bytes lingering in the decoders
164- stdout += stdoutDecoder . end ( ) ;
165- stderr += stderrDecoder . end ( ) ;
174+ if ( stdoutDecoder ) {
175+ stdout += stdoutDecoder . decode ( ) ;
176+ }
177+ if ( stderrDecoder ) {
178+ stderr += stderrDecoder . decode ( ) ;
179+ }
166180
167181 const finalBuffer = Buffer . concat ( outputChunks ) ;
168182
0 commit comments