@@ -23,14 +23,14 @@ export class E2BSandboxRunner implements SandboxRunner {
2323 }
2424 }
2525
26- async run ( job : SandboxRunRecord ) : Promise < RunnerOutput > {
26+ async run ( job : SandboxRunRecord , appendLog ?: ( chunk : string ) => void ) : Promise < RunnerOutput > {
2727 if ( job . payload . operation === "plan" ) {
28- return this . runPlan ( job ) ;
28+ return this . runPlan ( job , appendLog ) ;
2929 }
30- return this . runApply ( job ) ;
30+ return this . runApply ( job , appendLog ) ;
3131 }
3232
33- private async runPlan ( job : SandboxRunRecord ) : Promise < RunnerOutput > {
33+ private async runPlan ( job : SandboxRunRecord , appendLog ?: ( chunk : string ) => void ) : Promise < RunnerOutput > {
3434 const requestedVersion = job . payload . terraformVersion || "1.5.7" ;
3535 const requestedEngine = job . payload . engine || "terraform" ;
3636 const { sandbox, needsInstall } = await this . createSandbox ( requestedVersion , requestedEngine ) ;
@@ -42,28 +42,32 @@ export class E2BSandboxRunner implements SandboxRunner {
4242
4343 const workDir = await this . setupWorkspace ( sandbox , job ) ;
4444 const logs : string [ ] = [ ] ;
45+ const streamLog = ( chunk : string ) => {
46+ if ( ! chunk ) return ;
47+ appendLog ?.( chunk ) ;
48+ } ;
4549
4650 // Run terraform init
4751 await this . runTerraformCommand (
4852 sandbox ,
4953 workDir ,
5054 [ "init" , "-input=false" , "-no-color" ] ,
5155 logs ,
56+ streamLog ,
5257 ) ;
5358
5459 // Run terraform plan
5560 const planArgs = [ "plan" , "-input=false" , "-no-color" , "-out=tfplan.binary" ] ;
5661 if ( job . payload . isDestroy ) {
5762 planArgs . splice ( 1 , 0 , "-destroy" ) ;
5863 }
59- await this . runTerraformCommand ( sandbox , workDir , planArgs , logs ) ;
64+ await this . runTerraformCommand ( sandbox , workDir , planArgs , logs , streamLog ) ;
6065
6166 // Get plan JSON
6267 const showResult = await this . runTerraformCommand (
6368 sandbox ,
6469 workDir ,
6570 [ "show" , "-json" , "tfplan.binary" ] ,
66- logs ,
6771 ) ;
6872
6973 const planJSON = showResult . stdout ;
@@ -76,31 +80,36 @@ export class E2BSandboxRunner implements SandboxRunner {
7680 planJSON : Buffer . from ( planJSON , "utf8" ) . toString ( "base64" ) ,
7781 } ;
7882
79- return { logs : logs . join ( "\n " ) , result } ;
83+ return { logs : logs . join ( "" ) , result } ;
8084 } finally {
8185 await sandbox . kill ( ) ;
8286 }
8387 }
8488
85- private async runApply ( job : SandboxRunRecord ) : Promise < RunnerOutput > {
89+ private async runApply ( job : SandboxRunRecord , appendLog ?: ( chunk : string ) => void ) : Promise < RunnerOutput > {
8690 const requestedVersion = job . payload . terraformVersion || "1.5.7" ;
87- const requestedEngine = job . payload . engine || "terraform" ;
88- const { sandbox, needsInstall } = await this . createSandbox ( requestedVersion , requestedEngine ) ;
89- try {
90- // Install IaC tool if using fallback template
91- if ( needsInstall ) {
92- await this . installIacTool ( sandbox , requestedEngine , requestedVersion ) ;
93- }
94-
95- const workDir = await this . setupWorkspace ( sandbox , job ) ;
96- const logs : string [ ] = [ ] ;
91+ const requestedEngine = job . payload . engine || "terraform" ;
92+ const { sandbox, needsInstall } = await this . createSandbox ( requestedVersion , requestedEngine ) ;
93+ try {
94+ // Install IaC tool if using fallback template
95+ if ( needsInstall ) {
96+ await this . installIacTool ( sandbox , requestedEngine , requestedVersion ) ;
97+ }
98+
99+ const workDir = await this . setupWorkspace ( sandbox , job ) ;
100+ const logs : string [ ] = [ ] ;
101+ const streamLog = ( chunk : string ) => {
102+ if ( ! chunk ) return ;
103+ appendLog ?.( chunk ) ;
104+ } ;
97105
98106 // Run terraform init
99107 await this . runTerraformCommand (
100108 sandbox ,
101109 workDir ,
102110 [ "init" , "-input=false" , "-no-color" ] ,
103111 logs ,
112+ streamLog ,
104113 ) ;
105114
106115 // Run terraform apply/destroy
@@ -110,6 +119,7 @@ export class E2BSandboxRunner implements SandboxRunner {
110119 workDir ,
111120 [ applyCommand , "-auto-approve" , "-input=false" , "-no-color" ] ,
112121 logs ,
122+ streamLog ,
113123 ) ;
114124
115125 // Read the state file
@@ -119,7 +129,7 @@ export class E2BSandboxRunner implements SandboxRunner {
119129 state : Buffer . from ( stateContent , "utf8" ) . toString ( "base64" ) ,
120130 } ;
121131
122- return { logs : logs . join ( "\n " ) , result } ;
132+ return { logs : logs . join ( "" ) , result } ;
123133 } finally {
124134 await sandbox . kill ( ) ;
125135 }
@@ -262,28 +272,41 @@ export class E2BSandboxRunner implements SandboxRunner {
262272 cwd : string ,
263273 args : string [ ] ,
264274 logBuffer ?: string [ ] ,
275+ appendLog ?: ( chunk : string ) => void ,
265276 ) : Promise < { stdout : string ; stderr : string } > {
266277 const engine = ( sandbox as any ) . _requestedEngine || "terraform" ;
267278 const binaryName = engine === "tofu" ? "tofu" : "terraform" ;
268279 const cmdStr = `${ binaryName } ${ args . join ( " " ) } ` ;
269280 logger . info ( { cmd : cmdStr , cwd, engine } , "running IaC command in E2B sandbox" ) ;
270281
282+ let sawStream = false ;
283+ const pipeChunk = ( chunk : string | undefined ) => {
284+ if ( ! chunk ) return ;
285+ sawStream = true ;
286+ if ( logBuffer ) {
287+ logBuffer . push ( chunk ) ;
288+ }
289+ appendLog ?.( chunk ) ;
290+ } ;
291+
271292 const result = await sandbox . commands . run ( cmdStr , {
272293 cwd,
273294 envs : {
274295 TF_IN_AUTOMATION : "1" ,
275296 } ,
297+ onStdout : pipeChunk ,
298+ onStderr : pipeChunk ,
276299 } ) ;
277300
278301 const stdout = result . stdout ;
279302 const stderr = result . stderr ;
280303 const exitCode = result . exitCode ;
281304
305+ // Push any remaining buffered output for completeness in final log
282306 const mergedLogs = `${ stdout } \n${ stderr } ` . trim ( ) ;
283- if ( logBuffer && mergedLogs . length > 0 ) {
284- logBuffer . push ( mergedLogs ) ;
307+ if ( ! sawStream && mergedLogs . length > 0 ) {
308+ pipeChunk ( mergedLogs + "\n" ) ;
285309 }
286-
287310 if ( exitCode !== 0 ) {
288311 throw new Error (
289312 `${ binaryName } ${ args [ 0 ] } exited with code ${ exitCode } \n${ mergedLogs } ` ,
@@ -330,4 +353,3 @@ export class E2BSandboxRunner implements SandboxRunner {
330353 }
331354 }
332355}
333-
0 commit comments