Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ffda493
Fix character encoding issues in shell command processor
boylin0 Jun 26, 2025
07e8ded
Merge branch 'main' into main
boylin0 Jun 26, 2025
923b04c
Merge branch 'main' into main
boylin0 Jun 26, 2025
3b9694f
fix: validate Windows code page before encoding conversion
boylin0 Jun 30, 2025
0cb8755
fix: improve system encoding detection with robust fallbacks
boylin0 Jun 30, 2025
55fdc7c
fix: handle unsupported Windows code pages safely
boylin0 Jun 30, 2025
2676821
perf(shellCommandProcessor): cache system encoding detection
boylin0 Jul 12, 2025
72dc235
perf(shellCommandProcessor): Fix text decoder streaming and end-of-st…
boylin0 Jul 12, 2025
bde9748
Improve shell command encoding detection and error handling
boylin0 Jul 12, 2025
5f1ef8f
Merge branch 'main' into main
boylin0 Jul 12, 2025
3e6d8a9
fix(package): remove unnecessary dependency on @google/gemini-cli
boylin0 Jul 12, 2025
a6cb358
style(shellCommandProcessor): remove unnecessary blank line in execut…
boylin0 Jul 12, 2025
41b524a
fix(package): add missing chardet dependency
boylin0 Jul 12, 2025
7588ae3
Merge branch 'main' into main
jacob314 Jul 12, 2025
6224be2
fix: improve encoding detection caching
boylin0 Jul 19, 2025
2aa1706
fix: improve Windows encoding detection error messages
boylin0 Jul 19, 2025
d25e52f
fix: missing output final bytes from TextDecoder on process exit
boylin0 Jul 19, 2025
9286142
test(shellCommandProcessor): add comprehensive test coverage
boylin0 Jul 19, 2025
dd63380
Merge branch 'fix/shell-command-processor-encoding'
boylin0 Jul 19, 2025
b871ab7
refactor(cli): integrate core encoding utilities; add reset function …
boylin0 Jul 19, 2025
c629c8f
test(core): add systemEncoding utility test suite
boylin0 Jul 19, 2025
3583693
refactor(deps): move chardet dependency into packages\core
boylin0 Jul 19, 2025
30a1f7e
style(shellCommandProcessor): format code
boylin0 Jul 19, 2025
1aa9491
fix(systemEncoding): update cachedSystemEncoding use undefined for un…
boylin0 Jul 19, 2025
b14869e
style(systemEncoding): format code
boylin0 Jul 19, 2025
b474dd5
fix(shellCommandProcessor): ensure homedir mock is defined for consis…
boylin0 Jul 19, 2025
909d170
Merge branch 'main' into main
SandyTao520 Jul 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/cli/src/ui/hooks/shellCommandProcessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ vi.mock('os', () => ({
default: {
platform: () => 'linux',
tmpdir: () => '/tmp',
homedir: () => '/home/user',
},
platform: () => 'linux',
tmpdir: () => '/tmp',
homedir: () => '/home/user',
}));
vi.mock('@google/gemini-cli-core');
vi.mock('../utils/textUtils.js', () => ({
Expand Down
30 changes: 22 additions & 8 deletions packages/cli/src/ui/hooks/shellCommandProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
*/

import { spawn } from 'child_process';
import { StringDecoder } from 'string_decoder';
import { TextDecoder } from 'util';
import {
HistoryItemWithoutId,
IndividualToolCallDisplay,
ToolCallStatus,
} from '../types.js';
import { useCallback } from 'react';
import { Config, GeminiClient } from '@google/gemini-cli-core';
import {
Config,
GeminiClient,
getCachedEncodingForBuffer,
} from '@google/gemini-cli-core';
import { type PartListUnion } from '@google/genai';
import { formatMemoryUsage } from '../utils/formatters.js';
import { isBinary } from '../utils/textUtils.js';
Expand Down Expand Up @@ -71,8 +75,8 @@ function executeShellCommand(
});

// Use decoders to handle multi-byte characters safely (for streaming output).
const stdoutDecoder = new StringDecoder('utf8');
const stderrDecoder = new StringDecoder('utf8');
let stdoutDecoder: TextDecoder | null = null;
let stderrDecoder: TextDecoder | null = null;

let stdout = '';
let stderr = '';
Expand All @@ -85,6 +89,12 @@ function executeShellCommand(
let sniffedBytes = 0;

const handleOutput = (data: Buffer, stream: 'stdout' | 'stderr') => {
if (!stdoutDecoder || !stderrDecoder) {
const encoding = getCachedEncodingForBuffer(data);
stdoutDecoder = new TextDecoder(encoding);
stderrDecoder = new TextDecoder(encoding);
}

outputChunks.push(data);

if (streamToUi && sniffedBytes < MAX_SNIFF_SIZE) {
Expand All @@ -101,8 +111,8 @@ function executeShellCommand(

const decodedChunk =
stream === 'stdout'
? stdoutDecoder.write(data)
: stderrDecoder.write(data);
? stdoutDecoder.decode(data, { stream: true })
: stderrDecoder.decode(data, { stream: true });
if (stream === 'stdout') {
stdout += stripAnsi(decodedChunk);
} else {
Expand Down Expand Up @@ -160,8 +170,12 @@ function executeShellCommand(
abortSignal.removeEventListener('abort', abortHandler);

// Handle any final bytes lingering in the decoders
Comment thread
boylin0 marked this conversation as resolved.
stdout += stdoutDecoder.end();
stderr += stderrDecoder.end();
if (stdoutDecoder) {
stdout += stdoutDecoder.decode();
}
if (stderrDecoder) {
stderr += stderrDecoder.decode();
}

const finalBuffer = Buffer.concat(outputChunks);

Expand Down
3 changes: 2 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"simple-git": "^3.28.0",
"strip-ansi": "^7.1.0",
"undici": "^7.10.0",
"ws": "^8.18.0"
"ws": "^8.18.0",
"chardet": "^2.1.0"
},
"devDependencies": {
"@types/diff": "^7.0.2",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export * from './utils/editor.js';
export * from './utils/quotaErrorDetection.js';
export * from './utils/fileUtils.js';
export * from './utils/retry.js';
export * from './utils/systemEncoding.js';

// Export services
export * from './services/fileDiscoveryService.js';
Expand Down
Loading