From 4fb31023caa5532aaf356c6032ff27732ffb1cc7 Mon Sep 17 00:00:00 2001 From: AmirSa12 Date: Tue, 16 Dec 2025 18:05:21 +0330 Subject: [PATCH 1/6] init --- bin/package-manager-completion.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bin/package-manager-completion.ts b/bin/package-manager-completion.ts index 7c12ff9..74e8af5 100644 --- a/bin/package-manager-completion.ts +++ b/bin/package-manager-completion.ts @@ -105,7 +105,17 @@ export class PackageManagerCompletion extends RootCommand { } async parse(args: string[]) { - const normalizedArgs = this.stripPackageManagerCommands(args); + const isPowerShell = process.platform === 'win32' && process.env.PSModulePath; + const dashIndex = process.argv.indexOf('--'); + + const completionArgs = + dashIndex !== -1 && (!isPowerShell || dashIndex < process.argv.length - 1) + ? process.argv.slice(dashIndex + 1) + : isPowerShell + ? process.argv.slice(process.argv.indexOf('complete') + 1) + : args; + + const normalizedArgs = this.stripPackageManagerCommands(completionArgs); if (normalizedArgs.length >= 1 && normalizedArgs[0].trim() !== '') { const potentialCliName = normalizedArgs[0]; From 6454475d6d9731c5901edf35efd7f8849e744b5d Mon Sep 17 00:00:00 2001 From: AmirSa12 Date: Wed, 17 Dec 2025 17:37:56 +0330 Subject: [PATCH 2/6] revert --- bin/package-manager-completion.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/bin/package-manager-completion.ts b/bin/package-manager-completion.ts index 74e8af5..7c12ff9 100644 --- a/bin/package-manager-completion.ts +++ b/bin/package-manager-completion.ts @@ -105,17 +105,7 @@ export class PackageManagerCompletion extends RootCommand { } async parse(args: string[]) { - const isPowerShell = process.platform === 'win32' && process.env.PSModulePath; - const dashIndex = process.argv.indexOf('--'); - - const completionArgs = - dashIndex !== -1 && (!isPowerShell || dashIndex < process.argv.length - 1) - ? process.argv.slice(dashIndex + 1) - : isPowerShell - ? process.argv.slice(process.argv.indexOf('complete') + 1) - : args; - - const normalizedArgs = this.stripPackageManagerCommands(completionArgs); + const normalizedArgs = this.stripPackageManagerCommands(args); if (normalizedArgs.length >= 1 && normalizedArgs[0].trim() !== '') { const potentialCliName = normalizedArgs[0]; From 9e323b671b53afcaa449bb7e2a44f92358175917 Mon Sep 17 00:00:00 2001 From: AmirSa12 Date: Wed, 17 Dec 2025 17:41:06 +0330 Subject: [PATCH 3/6] ps1 --- bin/package-manager-completion.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/bin/package-manager-completion.ts b/bin/package-manager-completion.ts index 7c12ff9..00b53b1 100644 --- a/bin/package-manager-completion.ts +++ b/bin/package-manager-completion.ts @@ -2,6 +2,7 @@ import { spawnSync, type SpawnSyncOptionsWithStringEncoding, } from 'child_process'; +import path from 'node:path'; import { RootCommand } from '../src/t.js'; const noop = () => {}; @@ -23,11 +24,20 @@ function runCompletionCommand( leadingArgs: string[], completionArgs: string[] ): string { - const result = spawnSync( - command, - [...leadingArgs, 'complete', '--', ...completionArgs], - completionSpawnOptions - ); + const args = [...leadingArgs, 'complete', '--', ...completionArgs]; + + // On Windows, prefer invoking the PowerShell shim (.ps1) so global installs work. + const maybePs1Command = + process.platform === 'win32' && path.extname(command) === '' + ? `${command}.ps1` + : command; + + let result = spawnSync(maybePs1Command, args, completionSpawnOptions); + + // If the .ps1 shim is not found, fall back to the original command. + if (result.error && maybePs1Command !== command) { + result = spawnSync(command, args, completionSpawnOptions); + } if (result.error) { throw result.error; From 66faa7f374897f30db6de047daaaf5c720fa5f12 Mon Sep 17 00:00:00 2001 From: AmirSa12 Date: Wed, 17 Dec 2025 17:46:02 +0330 Subject: [PATCH 4/6] ps1 --- bin/package-manager-completion.ts | 35 ++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/bin/package-manager-completion.ts b/bin/package-manager-completion.ts index 00b53b1..d7d1994 100644 --- a/bin/package-manager-completion.ts +++ b/bin/package-manager-completion.ts @@ -26,19 +26,34 @@ function runCompletionCommand( ): string { const args = [...leadingArgs, 'complete', '--', ...completionArgs]; - // On Windows, prefer invoking the PowerShell shim (.ps1) so global installs work. - const maybePs1Command = - process.platform === 'win32' && path.extname(command) === '' - ? `${command}.ps1` - : command; - - let result = spawnSync(maybePs1Command, args, completionSpawnOptions); + // On Windows, prefer invoking via powershell.exe so .ps1 shims work. + if (process.platform === 'win32' && path.extname(command) === '') { + const ps1Path = `${command}.ps1`; + const psResult = spawnSync( + 'powershell.exe', + [ + '-NoLogo', + '-NoProfile', + '-ExecutionPolicy', + 'Bypass', + '-File', + ps1Path, + ...args, + ], + completionSpawnOptions + ); - // If the .ps1 shim is not found, fall back to the original command. - if (result.error && maybePs1Command !== command) { - result = spawnSync(command, args, completionSpawnOptions); + // If that fails, fall back to invoking the command directly. + if ( + !psResult.error && + (typeof psResult.status !== 'number' || psResult.status === 0) + ) { + return (psResult.stdout ?? '').trim(); + } } + const result = spawnSync(command, args, completionSpawnOptions); + if (result.error) { throw result.error; } From db0683bb74f0b53b20eb7963665a5122a1bd033b Mon Sep 17 00:00:00 2001 From: AmirSa12 Date: Wed, 17 Dec 2025 17:51:42 +0330 Subject: [PATCH 5/6] ps1 --- bin/package-manager-completion.ts | 42 ++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/bin/package-manager-completion.ts b/bin/package-manager-completion.ts index d7d1994..efd1f62 100644 --- a/bin/package-manager-completion.ts +++ b/bin/package-manager-completion.ts @@ -26,9 +26,19 @@ function runCompletionCommand( ): string { const args = [...leadingArgs, 'complete', '--', ...completionArgs]; - // On Windows, prefer invoking via powershell.exe so .ps1 shims work. - if (process.platform === 'win32' && path.extname(command) === '') { - const ps1Path = `${command}.ps1`; + const result = spawnSync(command, args, completionSpawnOptions); + + // Windows: npm may only produce a .ps1 shim; spawnSync won't resolve .ps1 via PATHEXT. + // Fallback: invoke through PowerShell so .ps1 shims (e.g. nuxt.ps1) are discoverable. + if ( + result.error && + (result.error as { code?: string }).code === 'ENOENT' && + process.platform === 'win32' && + path.extname(command) === '' + ) { + const psArgs = args.map(powerShellQuote); + const psCommand = `& ${command} ${psArgs.join(' ')}`.trimEnd(); + const psResult = spawnSync( 'powershell.exe', [ @@ -36,24 +46,23 @@ function runCompletionCommand( '-NoProfile', '-ExecutionPolicy', 'Bypass', - '-File', - ps1Path, - ...args, + '-Command', + psCommand, ], completionSpawnOptions ); - // If that fails, fall back to invoking the command directly. - if ( - !psResult.error && - (typeof psResult.status !== 'number' || psResult.status === 0) - ) { - return (psResult.stdout ?? '').trim(); + if (psResult.error) { + throw psResult.error; + } + if (typeof psResult.status === 'number' && psResult.status !== 0) { + throw new Error( + `Completion command "${command}" (PowerShell fallback) exited with code ${psResult.status}` + ); } + return (psResult.stdout ?? '').trim(); } - const result = spawnSync(command, args, completionSpawnOptions); - if (result.error) { throw result.error; } @@ -67,6 +76,11 @@ function runCompletionCommand( return (result.stdout ?? '').trim(); } +function powerShellQuote(value: string): string { + // Use single quotes and escape embedded single quotes by doubling them. + return `'${value.replace(/'/g, "''")}'`; +} + async function checkCliHasCompletions( cliName: string, packageManager: string From 83c6481e2cc7e2eb06f4c5107d138f36fcad1d0f Mon Sep 17 00:00:00 2001 From: AmirSa12 Date: Wed, 17 Dec 2025 18:11:49 +0330 Subject: [PATCH 6/6] add todo --- bin/package-manager-completion.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/package-manager-completion.ts b/bin/package-manager-completion.ts index efd1f62..aabf72d 100644 --- a/bin/package-manager-completion.ts +++ b/bin/package-manager-completion.ts @@ -30,6 +30,8 @@ function runCompletionCommand( // Windows: npm may only produce a .ps1 shim; spawnSync won't resolve .ps1 via PATHEXT. // Fallback: invoke through PowerShell so .ps1 shims (e.g. nuxt.ps1) are discoverable. + // TODO(AMIR): This is a hack to get the completion working on Windows. + // We should find a better way to do this. as this is not a good solution. and slows down the completion. if ( result.error && (result.error as { code?: string }).code === 'ENOENT' &&