diff --git a/src/ai.ts b/src/ai.ts index 36340d2..73d6a33 100644 --- a/src/ai.ts +++ b/src/ai.ts @@ -31,6 +31,7 @@ import { withFacultRootScope, } from "./paths"; import { redactReconciliationText } from "./reconciliation-adapters"; +import { writeCliOutput } from "./util/cli-output"; const NEWLINE_RE = /\r?\n/; const TRAILING_NEWLINE_RE = /\n$/; @@ -3118,7 +3119,7 @@ async function loopCommand(argv: string[]) { homeDir, globalRootDir, }); - console.log( + await writeCliOutput( json ? JSON.stringify(result, null, 2) : renderActivitySet(result) ); return; @@ -3131,7 +3132,7 @@ async function loopCommand(argv: string[]) { if (!result) { throw new Error("No evolution loop report has been recorded"); } - console.log( + await writeCliOutput( json ? JSON.stringify(result, null, 2) : renderActivityFeed(result) ); return; @@ -3206,7 +3207,7 @@ async function loopCommand(argv: string[]) { }, async () => await queryActivityHistory(queryArgs) ); - console.log( + await writeCliOutput( json ? JSON.stringify(result, null, 2) : renderActivityHistory(result) ); return; diff --git a/src/util/cli-output.test.ts b/src/util/cli-output.test.ts new file mode 100644 index 0000000..09d7bb1 --- /dev/null +++ b/src/util/cli-output.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from "bun:test"; + +describe("writeCliOutput", () => { + it("flushes output larger than Bun's buffered stdout window", async () => { + const expectedBytes = 200_001; + const proc = Bun.spawn( + [ + process.execPath, + "-e", + 'import { writeCliOutput } from "./src/util/cli-output"; await writeCliOutput("x".repeat(200_000));', + ], + { + cwd: process.cwd(), + stdout: "pipe", + stderr: "pipe", + } + ); + const [exitCode, stdout, stderr] = await Promise.all([ + proc.exited, + new Response(proc.stdout).arrayBuffer(), + new Response(proc.stderr).text(), + ]); + + expect(exitCode).toBe(0); + expect(stderr).toBe(""); + expect(stdout.byteLength).toBe(expectedBytes); + }); +}); diff --git a/src/util/cli-output.ts b/src/util/cli-output.ts new file mode 100644 index 0000000..4d99bd2 --- /dev/null +++ b/src/util/cli-output.ts @@ -0,0 +1,19 @@ +const BUFFERED_STDOUT_THRESHOLD_BYTES = 64 * 1024; + +export async function writeCliOutput(output: string): Promise { + const terminated = `${output}\n`; + if (Buffer.byteLength(terminated, "utf8") < BUFFERED_STDOUT_THRESHOLD_BYTES) { + console.log(output); + return; + } + + await new Promise((resolve, reject) => { + process.stdout.write(terminated, (error) => { + if (error) { + reject(error); + return; + } + resolve(); + }); + }); +}