@@ -8,6 +8,8 @@ import { RootCommand } from '../src/t.js';
88const noop = ( ) => { } ;
99
1010const isTabDebug = Boolean ( process . env . TAB_DEBUG ) ;
11+ const isPowerShellEnv =
12+ process . platform === 'win32' && Boolean ( process . env . PSModulePath ) ;
1113
1214function tabDebugLog ( ...args : unknown [ ] ) {
1315 if ( isTabDebug ) {
@@ -38,6 +40,11 @@ function runCompletionCommand(
3840 const args = [ ...leadingArgs , 'complete' , '--' , ...safeCompletionArgs ] ;
3941 tabDebugLog ( 'spawn completion:' , command , args ) ;
4042
43+ // PowerShell: prefer invoking via powershell.exe so .ps1 shims are resolved.
44+ if ( isPowerShellEnv && path . extname ( command ) === '' ) {
45+ return runCompletionViaPowerShell ( command , args ) ;
46+ }
47+
4148 const result = spawnSync ( command , args , completionSpawnOptions ) ;
4249
4350 tabDebugLog ( 'spawn result:' , {
@@ -46,46 +53,13 @@ function runCompletionCommand(
4653 stdout : result . stdout ,
4754 } ) ;
4855
49- // Windows: npm may only produce a .ps1 shim; spawnSync won't resolve .ps1 via PATHEXT.
50- // Fallback: invoke through powershell so .ps1 shims (e.g. nuxt.ps1) are discoverable.
56+ // If the direct spawn fails on Windows, retry via PowerShell as a safety net.
5157 if (
5258 getErrnoCode ( result . error ) === 'ENOENT' &&
53- process . platform === 'win32' &&
59+ isPowerShellEnv &&
5460 path . extname ( command ) === ''
5561 ) {
56- const psArgs = args . map ( powerShellQuote ) ;
57- const psCommand = `& ${ command } ${ psArgs . join ( ' ' ) } ` . trimEnd ( ) ;
58-
59- tabDebugLog ( 'powershell fallback:' , psCommand ) ;
60-
61- const psResult = spawnSync (
62- 'powershell.exe' ,
63- [
64- '-NoLogo' ,
65- '-NoProfile' ,
66- '-ExecutionPolicy' ,
67- 'Bypass' ,
68- '-Command' ,
69- psCommand ,
70- ] ,
71- completionSpawnOptions
72- ) ;
73-
74- tabDebugLog ( 'powershell fallback result:' , {
75- status : psResult . status ,
76- error : psResult . error ?. message ,
77- stdout : psResult . stdout ,
78- } ) ;
79-
80- if ( psResult . error ) {
81- throw psResult . error ;
82- }
83- if ( typeof psResult . status === 'number' && psResult . status !== 0 ) {
84- throw new Error (
85- `Completion command "${ command } " (PowerShell fallback) exited with code ${ psResult . status } `
86- ) ;
87- }
88- return ( psResult . stdout ?? '' ) . trim ( ) ;
62+ return runCompletionViaPowerShell ( command , args ) ;
8963 }
9064
9165 if ( result . error ) {
@@ -106,6 +80,42 @@ function powerShellQuote(value: string): string {
10680 return `'${ value . replace ( / ' / g, "''" ) } '` ;
10781}
10882
83+ function runCompletionViaPowerShell ( command : string , args : string [ ] ) : string {
84+ const psArgs = args . map ( powerShellQuote ) ;
85+ const psCommand = `& ${ command } ${ psArgs . join ( ' ' ) } ` . trimEnd ( ) ;
86+
87+ tabDebugLog ( 'powershell exec:' , psCommand ) ;
88+
89+ const psResult = spawnSync (
90+ 'powershell.exe' ,
91+ [
92+ '-NoLogo' ,
93+ '-NoProfile' ,
94+ '-ExecutionPolicy' ,
95+ 'Bypass' ,
96+ '-Command' ,
97+ psCommand ,
98+ ] ,
99+ completionSpawnOptions
100+ ) ;
101+
102+ tabDebugLog ( 'powershell exec result:' , {
103+ status : psResult . status ,
104+ error : psResult . error ?. message ,
105+ stdout : psResult . stdout ,
106+ } ) ;
107+
108+ if ( psResult . error ) {
109+ throw psResult . error ;
110+ }
111+ if ( typeof psResult . status === 'number' && psResult . status !== 0 ) {
112+ throw new Error (
113+ `Completion command "${ command } " (PowerShell) exited with code ${ psResult . status } `
114+ ) ;
115+ }
116+ return ( psResult . stdout ?? '' ) . trim ( ) ;
117+ }
118+
109119function getErrnoCode ( error : unknown ) : string | undefined {
110120 if ( error && typeof error === 'object' && 'code' in error ) {
111121 const candidate = ( error as { code ?: unknown } ) . code ;
0 commit comments