From e75c4370fd7ba2aab3f71962eb425d59122e8ced Mon Sep 17 00:00:00 2001 From: Meleki Date: Sun, 26 Apr 2026 16:12:24 +0200 Subject: [PATCH] =?UTF-8?q?fix(encoding):=20UTF-8=20prozess-global=20+=201?= =?UTF-8?q?6-KB-StreamReader=20f=C3=BCr=20CLI-Output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zwei zusätzliche Härtungen gegen intermittierende �-Replacement-Chars (Umlaute, Em-Dash) im CLI-Output unter Windows: - Program.cs: Auf Windows Console.OutputEncoding/InputEncoding = UTF-8 setzen. Wirkt prozess-global via Win32 SetConsoleOutputCP/SetConsoleCP und wird von direkt gestarteten Child-Prozessen geerbt – ergänzt den bestehenden chcp-65001-cmd-Wrapper. In try/catch, falls als Windows- Dienst ohne Console gestartet. - ClaudeCliService.cs: stdout-Lesen mit eigenem StreamReader (16-KB- Buffer, explizit UTF-8 ohne BOM-Detection) statt Default-Reader (1 KB). Verhindert, dass bei gefragmentierten Pipe-Reads Multi-Byte-UTF-8- Sequenzen über Buffer-Grenzen aufgesplittet werden und der Decoder den State verliert. Co-Authored-By: Claude Opus 4.7 (1M context) --- Program.cs | 15 +++++++++++++++ Services/ClaudeCliService.cs | 11 ++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Program.cs b/Program.cs index 556a54e..51c9ec9 100644 --- a/Program.cs +++ b/Program.cs @@ -3,6 +3,7 @@ using System.IO; using System.Net; using System.Net.Http; using System.Runtime.InteropServices; +using System.Text; using Gott.Endpoints; using Gott.Middleware; using Gott.Services; @@ -13,6 +14,20 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; +// Auf Windows: Console-Codepage des Server-Prozesses auf UTF-8 erzwingen. +// Wirkt prozess-global (Win32 SetConsoleOutputCP/SetConsoleCP) und wird von +// direkt gestarteten Child-Prozessen geerbt – damit Tools/Sub-Prozesse, die +// die Console-Codepage abfragen, UTF-8 als Output-Encoding nutzen. +if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) +{ + try + { + Console.OutputEncoding = Encoding.UTF8; + Console.InputEncoding = Encoding.UTF8; + } + catch { /* In Service-Kontexten ohne Console kann das werfen – ignorieren. */ } +} + var builder = WebApplication.CreateBuilder(args); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) diff --git a/Services/ClaudeCliService.cs b/Services/ClaudeCliService.cs index 8df2771..f374d4a 100644 --- a/Services/ClaudeCliService.cs +++ b/Services/ClaudeCliService.cs @@ -337,7 +337,16 @@ public class ClaudeCliService await process.StandardInput.FlushAsync(); process.StandardInput.Close(); - using var reader = process.StandardOutput; + // Eigener StreamReader mit großem Buffer + explizit UTF-8 ohne BOM-Detection. + // Default-Reader (process.StandardOutput) nutzt nur 1 KB Buffer, was bei + // gefragmentierten Pipe-Reads zu zerschnittenen Multi-Byte-UTF-8-Sequenzen + // und damit zu �-Replacement-Chars für Umlaute/Em-Dashes führen kann. + using var reader = new StreamReader( + process.StandardOutput.BaseStream, + new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), + detectEncodingFromByteOrderMarks: false, + bufferSize: 16384, + leaveOpen: false); string line; while ((line = await reader.ReadLineAsync(cancellationToken)) != null) {