fix: UTF-8-Encoding für Claude CLI auf Windows erzwingen
Auf Windows kam es sporadisch zu Replacement-Chars (�) für Umlaute und Em-Dash, weil claude.exe Output mit CP1252/CP850 schreiben konnte. Lösung: CLI über cmd.exe wrappen und Codepage 65001 (UTF-8) erzwingen, zusätzlich LANG/LC_ALL/PYTHONIOENCODING auf UTF-8 setzen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
b47ca33259
commit
32aad7feef
1 file changed
+79
-1
@@ -39,7 +39,6 @@ public class ClaudeCliService
|
|||||||
{
|
{
|
||||||
var psi = new ProcessStartInfo
|
var psi = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = _cliPath,
|
|
||||||
RedirectStandardInput = redirectInput,
|
RedirectStandardInput = redirectInput,
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
@@ -49,12 +48,91 @@ public class ClaudeCliService
|
|||||||
StandardErrorEncoding = Encoding.UTF8
|
StandardErrorEncoding = Encoding.UTF8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
// Auf Windows: über cmd.exe wrappen und Codepage 65001 (UTF-8) erzwingen.
|
||||||
|
// Sonst kann der Child-Prozess (claude.exe) Output mit CP1252/CP850 schreiben,
|
||||||
|
// was beim UTF-8-Decode zu Replacement-Chars (�) für Umlaute / Em-Dash führt.
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append("/S /C \"chcp 65001 >nul && ");
|
||||||
|
sb.Append(QuoteArgForCmd(_cliPath));
|
||||||
|
foreach (var a in args)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(QuoteArgForCmd(a));
|
||||||
|
}
|
||||||
|
sb.Append('"');
|
||||||
|
|
||||||
|
psi.FileName = Environment.GetEnvironmentVariable("ComSpec") ?? "cmd.exe";
|
||||||
|
psi.Arguments = sb.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psi.FileName = _cliPath;
|
||||||
foreach (var arg in args)
|
foreach (var arg in args)
|
||||||
psi.ArgumentList.Add(arg);
|
psi.ArgumentList.Add(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTF-8-Locale für den Child setzen (Node.js / diverse Tools respektieren das).
|
||||||
|
// Schadet auf Windows nicht, hilft auf manchen Linux-Setups (z.B. systemd-Diensten ohne LANG).
|
||||||
|
psi.Environment["LANG"] = "en_US.UTF-8";
|
||||||
|
psi.Environment["LC_ALL"] = "en_US.UTF-8";
|
||||||
|
psi.Environment["PYTHONIOENCODING"] = "utf-8";
|
||||||
|
|
||||||
return psi;
|
return psi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Quotet ein Argument im Stil von Microsoft CRT (CommandLineToArgvW),
|
||||||
|
/// passend für die Verwendung innerhalb von cmd.exe /C "...".
|
||||||
|
/// </summary>
|
||||||
|
private static string QuoteArgForCmd(string arg)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(arg))
|
||||||
|
return "\"\"";
|
||||||
|
|
||||||
|
bool needsQuoting = false;
|
||||||
|
foreach (var c in arg)
|
||||||
|
{
|
||||||
|
if (c == ' ' || c == '\t' || c == '"' || c == '\n' || c == '\v')
|
||||||
|
{
|
||||||
|
needsQuoting = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needsQuoting)
|
||||||
|
return arg;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append('"');
|
||||||
|
int backslashes = 0;
|
||||||
|
foreach (var c in arg)
|
||||||
|
{
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
backslashes++;
|
||||||
|
}
|
||||||
|
else if (c == '"')
|
||||||
|
{
|
||||||
|
// 2n+1 Backslashes vor einem Anführungszeichen
|
||||||
|
sb.Append('\\', backslashes * 2 + 1);
|
||||||
|
sb.Append('"');
|
||||||
|
backslashes = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append('\\', backslashes);
|
||||||
|
sb.Append(c);
|
||||||
|
backslashes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2n Backslashes am Ende (vor dem schließenden ")
|
||||||
|
sb.Append('\\', backslashes * 2);
|
||||||
|
sb.Append('"');
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
private static string FindCliPath()
|
private static string FindCliPath()
|
||||||
{
|
{
|
||||||
// 1. Expliziter Pfad über Umgebungsvariable (höchste Priorität)
|
// 1. Expliziter Pfad über Umgebungsvariable (höchste Priorität)
|
||||||
|
|||||||
Reference in new issue
Block a user