TypeScript SDK splits valid JSON events on U+2028 in Node 24
What issue are you seeing?
On Node 24, @openai/codex-sdk can fail while consuming thread.runStreamed() when a valid Codex JSON event contains a literal U+2028 or U+2029 character inside a string. The SDK's CodexExec.run() uses node:readline to frame the CLI's LF-delimited JSON output. Node 24 also treats U+2028 and U+2029 as line separators, so one valid JSON record is split into invalid fragments before the SDK calls JSON.parse.
This was observed with Node 24.9.0 and @openai/codex-sdk 0.140.0. Current main still uses readline.createInterface() in sdk/typescript/src/exec.ts, and the same minimal reproduction fails on Node 24.14.0.
What steps can reproduce the bug?
Run this with Node 24:
import readline from "node:readline";
import { Readable } from "node:stream";
const record = JSON.stringify({ text: "before\u2028middle\u2029after" });
const lines = [];
for await (const line of readline.createInterface({
input: Readable.from([`${record}\n`]),
crlfDelay: Infinity,
})) {
lines.push(line);
}
console.log(lines.length);
console.log(lines.map((line) => {
try {
JSON.parse(line);
return true;
} catch {
return false;
}
}));
Node 24.9.0 prints:
3
[ false, false, false ]
The unsplit record parses successfully. U+2028/U+2029 are legal within JSON strings, while NDJSON records are delimited by LF (optionally preceded by CR), so human-text readline semantics are not suitable for this protocol.
What is the expected behavior?
The TypeScript SDK should split Codex CLI output only on LF, strip a preceding CR for CRLF, preserve literal U+2028/U+2029 inside records, and emit a final unterminated record at EOF.
Additional information
A focused patch and Node 24 regression test are ready on wrizvi/codex:codex/sdk-lf-only-jsonl-framing. The decoder uses the stream's UTF-8 StringDecoder through setEncoding("utf8"), so multibyte characters remain intact across chunk boundaries. The compact test also covers CRLF and a final record without a trailing LF.
Validation completed on the patch:
- focused
exec.test.ts: 8/8 on Node 20.20.2, Node 24.9.0, and Node 24.14.0 - TypeScript SDK Prettier and ESLint
- TypeScript SDK build
git diff --check
The full SDK integration suite additionally requires a locally built Codex CLI binary; that is left to repository CI.