Skip to content

Commit cc0c71d

Browse files
feat: add live output monitoring to ActionRunner
- Add onLiveOutput callback parameter to constructor - Implement monitorLiveOutput method to stream command output - Integrate monitoring into runShellAction method - Stream accumulates and emits output in real-time
1 parent 02ab5dd commit cc0c71d

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

app/lib/runtime/action-runner.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export class ActionRunner {
8383
onSupabaseAlert?: (alert: SupabaseAlert) => void;
8484
onDeployAlert?: (alert: DeployAlert) => void;
8585
onTestResult?: TestResultCallback;
86+
onLiveOutput?: (output: string, actionId: string) => void;
8687
buildOutput?: { path: string; exitCode: number; output: string };
8788

8889
constructor(
@@ -92,13 +93,15 @@ export class ActionRunner {
9293
onSupabaseAlert?: (alert: SupabaseAlert) => void,
9394
onDeployAlert?: (alert: DeployAlert) => void,
9495
onTestResult?: TestResultCallback,
96+
onLiveOutput?: (output: string, actionId: string) => void,
9597
) {
9698
this.#webcontainer = webcontainerPromise;
9799
this.#shellTerminal = getShellTerminal;
98100
this.onAlert = onAlert;
99101
this.onSupabaseAlert = onSupabaseAlert;
100102
this.onDeployAlert = onDeployAlert;
101103
this.onTestResult = onTestResult;
104+
this.onLiveOutput = onLiveOutput;
102105
}
103106

104107
addAction(data: ActionCallbackData) {
@@ -272,6 +275,10 @@ export class ActionRunner {
272275
unreachable('Shell terminal not found');
273276
}
274277

278+
if (this.onLiveOutput && shell.liveActionStream) {
279+
this.#monitorLiveOutput(shell.liveActionStream, action.content);
280+
}
281+
275282
const resp = await shell.executeCommand(this.runnerId.get(), action.content, () => {
276283
logger.debug(`[${action.type}]:Aborting Action\n\n`, action);
277284
action.abort();
@@ -298,6 +305,28 @@ export class ActionRunner {
298305
}
299306
}
300307

308+
async #monitorLiveOutput(stream: ReadableStreamDefaultReader<string>, command: string) {
309+
let buffer = '';
310+
311+
try {
312+
while (true) {
313+
const { value, done } = await stream.read();
314+
315+
if (done) {
316+
break;
317+
}
318+
319+
buffer += value || '';
320+
321+
if (this.onLiveOutput) {
322+
this.onLiveOutput(buffer, command);
323+
}
324+
}
325+
} catch (error) {
326+
logger.error('Live output monitoring error:', error);
327+
}
328+
}
329+
301330
async #runStartAction(action: ActionState) {
302331
if (action.type !== 'start') {
303332
unreachable('Expected shell action');

0 commit comments

Comments
 (0)