From 98eb2ae80201168f3eed56a29e2d72818952c485 Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Thu, 26 Mar 2026 23:20:37 -0600 Subject: [PATCH] =?UTF-8?q?fix:=20revert=20jsonl.ts=20to=20inline=20implem?= =?UTF-8?q?entation=20=E2=80=94=20@gsd-build/rpc-client=20not=20available?= =?UTF-8?q?=20at=20source-level=20test=20time=20in=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The re-export from @gsd-build/rpc-client fails in CI because tests run against TypeScript source (--experimental-strip-types) before any build step. The npm dependency resolves to node_modules/ which requires dist/ to exist. Reverting to the original inline implementation eliminates the cross-package dependency for source-level imports. --- package-lock.json | 1 - packages/pi-coding-agent/package.json | 1 - .../pi-coding-agent/src/modes/rpc/jsonl.ts | 65 ++++++++++++++++++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4514327de..9a9a89a5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9221,7 +9221,6 @@ "name": "@gsd/pi-coding-agent", "version": "2.52.0", "dependencies": { - "@gsd-build/rpc-client": "^2.52.0", "@mariozechner/jiti": "^2.6.2", "@silvia-odwyer/photon-node": "^0.3.4", "chalk": "^5.5.0", diff --git a/packages/pi-coding-agent/package.json b/packages/pi-coding-agent/package.json index 9252a6196..7d3cb624e 100644 --- a/packages/pi-coding-agent/package.json +++ b/packages/pi-coding-agent/package.json @@ -20,7 +20,6 @@ "copy-assets": "node scripts/copy-assets.cjs" }, "dependencies": { - "@gsd-build/rpc-client": "^2.52.0", "@mariozechner/jiti": "^2.6.2", "@silvia-odwyer/photon-node": "^0.3.4", "chalk": "^5.5.0", diff --git a/packages/pi-coding-agent/src/modes/rpc/jsonl.ts b/packages/pi-coding-agent/src/modes/rpc/jsonl.ts index 5ef2e2473..5392defef 100644 --- a/packages/pi-coding-agent/src/modes/rpc/jsonl.ts +++ b/packages/pi-coding-agent/src/modes/rpc/jsonl.ts @@ -1 +1,64 @@ -export { serializeJsonLine, attachJsonlLineReader } from '@gsd-build/rpc-client'; +import type { Readable } from "node:stream"; +import { StringDecoder } from "node:string_decoder"; + +/** + * Serialize a single strict JSONL record. + * + * Framing is LF-only. Payload strings may contain other Unicode separators such as + * U+2028 and U+2029. Clients must split records on `\n` only. + */ +export function serializeJsonLine(value: unknown): string { + return `${JSON.stringify(value)}\n`; +} + +/** + * Attach an LF-only JSONL reader to a stream. + * + * This intentionally does not use Node readline. Readline splits on additional + * Unicode separators that are valid inside JSON strings and therefore does not + * implement strict JSONL framing. + */ +export function attachJsonlLineReader(stream: Readable, onLine: (line: string) => void): () => void { + const decoder = new StringDecoder("utf8"); + let buffer = ""; + + const emitLine = (line: string) => { + onLine(line.endsWith("\r") ? line.slice(0, -1) : line); + }; + + const onData = (chunk: string | Buffer) => { + buffer += typeof chunk === "string" ? chunk : decoder.write(chunk); + + while (true) { + const newlineIndex = buffer.indexOf("\n"); + if (newlineIndex === -1) { + return; + } + + emitLine(buffer.slice(0, newlineIndex)); + buffer = buffer.slice(newlineIndex + 1); + } + }; + + const onEnd = () => { + buffer += decoder.end(); + if (buffer.length > 0) { + emitLine(buffer); + buffer = ""; + } + }; + + const onError = (_err: Error) => { + // Stream errors are non-fatal for JSONL reading + }; + + stream.on("data", onData); + stream.on("end", onEnd); + stream.on("error", onError); + + return () => { + stream.off("data", onData); + stream.off("end", onEnd); + stream.off("error", onError); + }; +}