Route ordinary CLI results through the bounded JSON writer after command registration, including managed member inspection. Remove JavaScript-specific output plumbing while preserving filters, envelopes, cancellation, and failure exits. Measure formatted UTF-16 expansion before Incur token counting and return resource_constraint above the runtime string limit, with recovery guidance. Validate output above the real V8 string limit by SHA-256 and exercise the compiled managed provider. Clean-worktree validation: npm run check; 76 focused tests passed, with 2 optional-provider skips; test discovery passed. Fixes #1371.
53 lines
1.5 KiB
TypeScript
53 lines
1.5 KiB
TypeScript
import type { Writable } from "node:stream";
|
|
|
|
import { bufferedJsonParts, jsonParts } from "../domain/jsonSerialization.js";
|
|
|
|
type JsonOutputFormat = "json" | "jsonl";
|
|
|
|
/** Write ordinary JSON without constructing a document-sized string. */
|
|
export const writeJsonOutput = async (
|
|
value: unknown,
|
|
destination: Writable,
|
|
format: JsonOutputFormat = "json",
|
|
): Promise<void> => {
|
|
for (const part of bufferedJsonParts(jsonOutputParts(value, format)))
|
|
await writePart(destination, part);
|
|
};
|
|
|
|
const writePart = (destination: Writable, part: string): Promise<void> =>
|
|
new Promise((resolve, reject) => {
|
|
const onError = (cause: unknown): void => reject(cause);
|
|
destination.once("error", onError);
|
|
try {
|
|
destination.write(part, (cause) => {
|
|
if (cause) {
|
|
// A Writable can emit its error after invoking the write callback.
|
|
setImmediate(() => destination.off("error", onError));
|
|
reject(cause);
|
|
} else {
|
|
destination.off("error", onError);
|
|
resolve();
|
|
}
|
|
});
|
|
} catch (cause: unknown) {
|
|
destination.off("error", onError);
|
|
reject(cause);
|
|
}
|
|
});
|
|
|
|
/** The exact formatted document, including its final newline. */
|
|
export function* jsonOutputParts(
|
|
value: unknown,
|
|
format: JsonOutputFormat,
|
|
): Generator<string> {
|
|
if (format === "jsonl" && Array.isArray(value)) {
|
|
for (const item of value) {
|
|
yield* jsonParts(item);
|
|
yield "\n";
|
|
}
|
|
return;
|
|
}
|
|
yield* jsonParts(value, format === "json");
|
|
yield "\n";
|
|
}
|