Ship Paseo-equivalent provider snapshot, AgentComposerBar, ACP dispatch rewrite with streaming/persist, permission prompts, and agent commands. Follow-up: pane-scoped chat resolution, CoderMessageList tool timeline, WS user-delta replace, and inference orphan tool_call stripping. Archive openspec v2-2; update CHANGELOG and CURRENT. Co-authored-by: Cursor <cursoragent@cursor.com>
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import { Readable, Writable } from 'node:stream';
|
|
import type { ChildProcess } from 'node:child_process';
|
|
import { ndJsonStream } from '@agentclientprotocol/sdk';
|
|
|
|
export function nodeReadableToWeb(nodeStream: NodeJS.ReadableStream): ReadableStream<Uint8Array> {
|
|
return new ReadableStream<Uint8Array>({
|
|
start(controller) {
|
|
nodeStream.on('data', (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)));
|
|
nodeStream.on('end', () => controller.close());
|
|
nodeStream.on('error', (err) => controller.error(err));
|
|
},
|
|
cancel() {
|
|
if ('destroy' in nodeStream && typeof (nodeStream as Readable).destroy === 'function') {
|
|
(nodeStream as Readable).destroy();
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
export function nodeWritableToWeb(nodeStream: NodeJS.WritableStream): WritableStream<Uint8Array> {
|
|
return new WritableStream<Uint8Array>({
|
|
write(chunk) {
|
|
return new Promise<void>((resolve, reject) => {
|
|
const ok = (nodeStream as Writable).write(chunk, (err) => {
|
|
if (err) reject(err);
|
|
});
|
|
if (ok) resolve();
|
|
else (nodeStream as Writable).once('drain', resolve);
|
|
});
|
|
},
|
|
close() {
|
|
return new Promise<void>((resolve) => {
|
|
(nodeStream as Writable).end(resolve);
|
|
});
|
|
},
|
|
abort() {
|
|
(nodeStream as Writable).destroy();
|
|
},
|
|
});
|
|
}
|
|
|
|
export function createAcpNdJsonStream(child: ChildProcess) {
|
|
return ndJsonStream(nodeWritableToWeb(child.stdin!), nodeReadableToWeb(child.stdout!));
|
|
}
|