@@ -112,6 +112,12 @@ pub struct PoolRunArgs {
112112 #[ arg( long, short = 'e' ) ]
113113 pub env : Vec < String > ,
114114
115+ /// On a --deferred daemon: run via exec instead of as the box's main —
116+ /// faster (the VM survives and is returned to use), output via the exec
117+ /// stream rather than the json-file logs.
118+ #[ arg( long) ]
119+ pub exec : bool ,
120+
115121 /// Command and arguments to run in a fresh warm sandbox
116122 #[ arg( last = true , required = true ) ]
117123 pub cmd : Vec < String > ,
@@ -162,6 +168,10 @@ struct RunRequest {
162168 /// Extra KEY=VALUE environment entries.
163169 #[ serde( default ) ]
164170 env : Vec < String > ,
171+ /// Force exec mode for this request (valid on a --deferred daemon, whose
172+ /// IDLE VMs still serve exec; a keepalive daemon is always exec).
173+ #[ serde( default ) ]
174+ exec : bool ,
165175 cmd : Vec < String > ,
166176}
167177
@@ -519,9 +529,11 @@ async fn handle_conn(
519529 Ok ( mut vm) => {
520530 // Deferred-main: run the command as the box's real MAIN
521531 // (full box semantics — exit code + json-file console logs).
522- // Otherwise exec it in the keepalive VM (output via the
523- // exec stream). Both honor user/workdir/env from the request.
524- let result = if registry. deferred {
532+ // Otherwise exec it (output via the exec stream); `exec:
533+ // true` forces exec mode per request on a deferred daemon
534+ // (its IDLE VMs serve exec just as well). Both honor
535+ // user/workdir/env from the request.
536+ let result = if registry. deferred && !run. exec {
525537 vm. run_deferred_main (
526538 & deferred_spec_json ( & run) ,
527539 std:: time:: Duration :: from_secs ( 60 ) ,
@@ -592,6 +604,7 @@ async fn execute_run(args: PoolRunArgs) -> Result<(), Box<dyn std::error::Error>
592604 user : args. user ,
593605 workdir : args. workdir ,
594606 env : args. env ,
607+ exec : args. exec ,
595608 cmd : args. cmd ,
596609 } ) ) ?,
597610 )
@@ -797,6 +810,7 @@ mod tests {
797810 user : Some ( "1000" . into ( ) ) ,
798811 workdir : Some ( "/work" . into ( ) ) ,
799812 env : vec ! [ "FOO=bar" . into( ) , "not-a-pair" . into( ) ] ,
813+ exec : false ,
800814 cmd : vec ! [ "sh" . into( ) , "-c" . into( ) , "echo hi" . into( ) ] ,
801815 } ;
802816 let json = deferred_spec_json ( & req) ;
@@ -817,6 +831,7 @@ mod tests {
817831 user : None ,
818832 workdir : None ,
819833 env : vec ! [ ] ,
834+ exec : false ,
820835 cmd : vec ! [ ] ,
821836 } ;
822837 let v2: serde_json:: Value = serde_json:: from_slice ( & deferred_spec_json ( & req2) ) . unwrap ( ) ;
@@ -863,6 +878,7 @@ mod tests {
863878 user : Some ( "1000" . into ( ) ) ,
864879 workdir : Some ( "/tmp" . into ( ) ) ,
865880 env : vec ! [ "FOO=bar" . into( ) ] ,
881+ exec : false ,
866882 cmd : vec ! [ "echo" . into( ) , "hi" . into( ) ] ,
867883 } ;
868884 let bytes = serde_json:: to_vec ( & req) . unwrap ( ) ;
@@ -957,6 +973,7 @@ mod tests {
957973 user : None ,
958974 workdir : None ,
959975 env : vec ! [ ] ,
976+ exec : false ,
960977 cmd : vec ! [ "echo" . into( ) , "hi" . into( ) ] ,
961978 } ) )
962979 . unwrap ( ) ;
@@ -992,6 +1009,7 @@ mod tests {
9921009 user : None ,
9931010 workdir : None ,
9941011 env : vec ! [ ] ,
1012+ exec : false ,
9951013 cmd : vec ! [ "echo" . into( ) , "hi there" . into( ) ] ,
9961014 } )
9971015 . unwrap ( ) ;
@@ -1034,6 +1052,7 @@ mod tests {
10341052 user : None ,
10351053 workdir : None ,
10361054 env : vec ! [ ] ,
1055+ exec : false ,
10371056 cmd : vec ! [ "ls" . into( ) , "-la" . into( ) ] ,
10381057 } ;
10391058 write_frame ( & mut client, & serde_json:: to_vec ( & req) . unwrap ( ) )
0 commit comments