@@ -743,11 +743,15 @@ function runInLinuxPortableVm(options) {
743743 toolArgs,
744744 noSyncBack,
745745 skipProjectSync,
746- authMode
746+ authMode,
747+ settings
747748 } = options ;
748749
750+ // On non-Windows hosts, linux-portable mode uses portable host-native execution
751+ // with isolated auth state instead of a VM. This provides portability without
752+ // requiring Docker/Podman.
749753 if ( process . platform !== 'win32' ) {
750- fail ( 'linux-portable mode is currently implemented for Windows hosts only.' ) ;
754+ return runPortableHostNative ( options ) ;
751755 }
752756
753757 loadJsonSafe ( vmManifestPath , 'vm manifest' ) ;
@@ -845,6 +849,47 @@ function runInLinuxPortableVm(options) {
845849 process . exitCode = typeof runResult . status === 'number' ? runResult . status : 1 ;
846850}
847851
852+ /**
853+ * Run tool in portable host-native mode (non-Windows hosts).
854+ * Uses isolated auth state in state/auth/<tool>/host/ but runs the tool
855+ * directly on the host without a VM. This provides portability on Linux/macOS
856+ * where a VM isn't needed for Linux tools.
857+ */
858+ function runPortableHostNative ( options ) {
859+ const {
860+ tool,
861+ adapter,
862+ projectPath,
863+ mergedEnv,
864+ toolArgs,
865+ authMode,
866+ settings
867+ } = options ;
868+
869+ // Resolve the runner
870+ const runner = resolveRunner ( adapter , mergedEnv ) ;
871+ if ( ! runner ) {
872+ fail ( `No executable found for tool '${ tool } '. Set ${ adapter . command_env } or install one of: ${ adapter . candidate_commands . join ( ', ' ) } ` ) ;
873+ }
874+
875+ // Apply portable auth environment (isolates auth state to state/auth/<tool>/host/)
876+ const env = applyPortableHostAuthEnv ( tool , { ...mergedEnv } , settings ) ;
877+
878+ console . log ( `[portable-native] Running ${ tool } with isolated auth state...` ) ;
879+
880+ const result = cp . spawnSync ( runner , toolArgs , {
881+ cwd : projectPath ,
882+ stdio : 'inherit' ,
883+ env
884+ } ) ;
885+
886+ if ( result . error ) {
887+ fail ( `Failed to launch '${ runner } ': ${ result . error . message } ` ) ;
888+ }
889+
890+ process . exitCode = typeof result . status === 'number' ? result . status : 1 ;
891+ }
892+
848893function startWindowsVm ( ) {
849894 const startScript = path . join ( repoRoot , 'scripts' , 'runtime' , 'windows' , 'start-vm.cmd' ) ;
850895 if ( ! fs . existsSync ( startScript ) ) {
0 commit comments