Skip to content

Commit cd4a96f

Browse files
elirantutiaclaude
andcommitted
fix windows-only status line test failure by forcing utf-8 python stdin
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 194d558 commit cd4a96f

1 file changed

Lines changed: 21 additions & 12 deletions

File tree

‎src/main/hook-status.test.ts‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,21 @@ describe('hook-status', () => {
9191
// used by the Windows branch is exercised on every platform's CI run.
9292
const body = () => buildStatusLinePython(STATUS_DIR);
9393

94+
// Feeds the script to python3 on stdin. PYTHONIOENCODING is required:
95+
// Node writes `input` as UTF-8, but on Windows sys.stdin defaults to the
96+
// locale codepage, so a non-ascii path comes back mojibake'd (\u00fc ->
97+
// \u00c3\u00bc). Production is unaffected — the body is written to a .py file,
98+
// and Python reads source files as UTF-8 regardless of locale.
99+
const runPython = (code: string, input: string) => {
100+
const { spawnSync } = require('child_process') as typeof import('child_process');
101+
const opts = { input, env: { ...process.env, PYTHONIOENCODING: 'utf-8' } };
102+
return spawnSync('python3', ['-c', code], opts);
103+
};
104+
const hasPython = () => {
105+
const { spawnSync } = require('child_process') as typeof import('child_process');
106+
return !spawnSync('python3', ['-c', 'pass']).error;
107+
};
108+
94109
it('extracts cost, context_window, session_id and session_name', () => {
95110
const script = body();
96111
for (const field of ['cost', 'context_window', 'session_id', 'session_name']) {
@@ -121,13 +136,12 @@ describe('hook-status', () => {
121136
const literal = script.split('\n').find((l) => l.startsWith('status_dir='))!;
122137
expect(literal).toBe(`status_dir=${JSON.stringify(dir)}`);
123138

124-
const { spawnSync } = require('child_process') as typeof import('child_process');
125-
if (spawnSync('python3', ['-c', 'pass']).error) return; // no python3 here
139+
if (!hasPython()) return; // no python3 here
126140

127-
const result = spawnSync('python3', [
128-
'-c',
141+
const result = runPython(
129142
`import sys,json;ns={};exec(sys.stdin.read(),ns);print(json.dumps(ns["status_dir"]))`,
130-
], { input: literal });
143+
literal,
144+
);
131145
expect(result.status).toBe(0);
132146
expect(JSON.parse(result.stdout.toString())).toBe(dir);
133147
});
@@ -144,14 +158,9 @@ describe('hook-status', () => {
144158
// A syntax error here is silent in production: it kills cost, context,
145159
// sessionid and name at once, with the traceback going only to
146160
// statusline.log. Nothing else in this suite would catch it.
147-
const { spawnSync } = require('child_process') as typeof import('child_process');
148-
const probe = spawnSync('python3', ['-c', 'pass']);
149-
if (probe.error) return; // no python3 on this runner
161+
if (!hasPython()) return; // no python3 on this runner
150162

151-
const result = spawnSync('python3', [
152-
'-c',
153-
'import sys;compile(sys.stdin.read(),"statusline","exec")',
154-
], { input: body() });
163+
const result = runPython('import sys;compile(sys.stdin.read(),"statusline","exec")', body());
155164

156165
expect(result.stderr.toString()).toBe('');
157166
expect(result.status).toBe(0);

0 commit comments

Comments
 (0)