@@ -101,22 +101,30 @@ fn is_potential_package_binary(tool: &str) -> bool {
101101/// Environment variable used for shim tool detection via shell wrapper scripts.
102102const SHIM_TOOL_ENV_VAR : & str = env_vars:: VP_SHIM_TOOL ;
103103
104+ /// Legacy environment variable name, kept for backward compatibility with
105+ /// older trampoline binaries that still set `VITE_PLUS_SHIM_TOOL`.
106+ const LEGACY_SHIM_TOOL_ENV_VAR : & str = "VITE_PLUS_SHIM_TOOL" ;
107+
104108/// Detect the shim tool from environment and argv.
105109///
106110/// Detection priority:
107111/// 1. Check `VP_SHIM_TOOL` env var (set by trampoline exe on Windows)
108- /// 2. If argv[0] is "vp" or "vp.exe", this is a direct CLI invocation - NOT shim mode
109- /// 3. Fall back to argv[0] detection (primary method on Unix with symlinks)
112+ /// 2. Fall back to `VITE_PLUS_SHIM_TOOL` for older trampoline compatibility
113+ /// 3. If argv[0] is "vp" or "vp.exe", this is a direct CLI invocation - NOT shim mode
114+ /// 4. Fall back to argv[0] detection (primary method on Unix with symlinks)
110115///
111- /// IMPORTANT: This function clears `VP_SHIM_TOOL` after reading it to
112- /// prevent the env var from leaking to child processes.
116+ /// IMPORTANT: This function clears both env vars after reading to
117+ /// prevent them from leaking to child processes.
113118pub fn detect_shim_tool ( argv0 : & str ) -> Option < String > {
114- // Always clear the env var to prevent it from leaking to child processes.
115- // We read it first, then clear it immediately.
119+ // Always clear both env vars to prevent them from leaking to child processes.
120+ // We read them first, then clear immediately.
116121 // SAFETY: We're at program startup before any threads are spawned.
117- let env_tool = std:: env:: var ( SHIM_TOOL_ENV_VAR ) . ok ( ) ;
122+ let env_tool = std:: env:: var ( SHIM_TOOL_ENV_VAR )
123+ . ok ( )
124+ . or_else ( || std:: env:: var ( LEGACY_SHIM_TOOL_ENV_VAR ) . ok ( ) ) ;
118125 unsafe {
119126 std:: env:: remove_var ( SHIM_TOOL_ENV_VAR ) ;
127+ std:: env:: remove_var ( LEGACY_SHIM_TOOL_ENV_VAR ) ;
120128 }
121129
122130 // Check VP_SHIM_TOOL env var first (set by trampoline exe on Windows).
@@ -147,6 +155,8 @@ pub fn detect_shim_tool(argv0: &str) -> Option<String> {
147155
148156#[ cfg( test) ]
149157mod tests {
158+ use serial_test:: serial;
159+
150160 use super :: * ;
151161
152162 #[ test]
@@ -205,6 +215,37 @@ mod tests {
205215 }
206216
207217 #[ test]
218+ #[ serial]
219+ fn test_detect_shim_tool_from_env_var ( ) {
220+ // SAFETY: We're in a test at startup, no other threads
221+ unsafe {
222+ std:: env:: set_var ( SHIM_TOOL_ENV_VAR , "node" ) ;
223+ std:: env:: remove_var ( LEGACY_SHIM_TOOL_ENV_VAR ) ;
224+ }
225+ let result = detect_shim_tool ( "vp" ) ;
226+ assert_eq ! ( result, Some ( "node" . to_string( ) ) ) ;
227+ // Env var should be cleared after detection
228+ assert ! ( std:: env:: var( SHIM_TOOL_ENV_VAR ) . is_err( ) ) ;
229+ }
230+
231+ #[ test]
232+ #[ serial]
233+ fn test_detect_shim_tool_from_legacy_env_var ( ) {
234+ // When only VITE_PLUS_SHIM_TOOL is set (older trampoline), it should
235+ // fall back to reading the legacy env var.
236+ // SAFETY: We're in a test at startup, no other threads
237+ unsafe {
238+ std:: env:: remove_var ( SHIM_TOOL_ENV_VAR ) ;
239+ std:: env:: set_var ( LEGACY_SHIM_TOOL_ENV_VAR , "npm" ) ;
240+ }
241+ let result = detect_shim_tool ( "vp" ) ;
242+ assert_eq ! ( result, Some ( "npm" . to_string( ) ) ) ;
243+ // Both env vars should be cleared after detection
244+ assert ! ( std:: env:: var( LEGACY_SHIM_TOOL_ENV_VAR ) . is_err( ) ) ;
245+ }
246+
247+ #[ test]
248+ #[ serial]
208249 fn test_detect_shim_tool_vpx ( ) {
209250 // vpx should be detected via the argv0 check, before the env var check
210251 // and before is_shim_tool (which would incorrectly match it as a package binary)
0 commit comments