Private/Logic/Eigenverft.Manifested.Sandbox.Runtime.NpmCli.Shared.ps1
|
<#
Eigenverft.Manifested.Sandbox.Runtime.NpmCli.Shared #> function ConvertTo-ManifestedNpmCliVersion { [CmdletBinding()] param( [string]$VersionText ) if ([string]::IsNullOrWhiteSpace($VersionText)) { return $null } $match = [regex]::Match($VersionText, 'v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.\-]+)?)') if (-not $match.Success) { return $null } return $match.Groups[1].Value } function ConvertTo-ManifestedNpmCliVersionObject { [CmdletBinding()] param( [string]$VersionText ) $normalizedVersion = ConvertTo-ManifestedNpmCliVersion -VersionText $VersionText if ([string]::IsNullOrWhiteSpace($normalizedVersion)) { return $null } $match = [regex]::Match($normalizedVersion, '(\d+\.\d+\.\d+)') if (-not $match.Success) { return $null } return [version]$match.Groups[1].Value } function Get-ManifestedNpmCliRuntimeDefinition { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateSet('Codex', 'OpenCode', 'Gemini', 'Qwen')] [string]$Name ) switch ($Name) { 'Codex' { return [pscustomobject]@{ Name = 'CodexRuntime' RuntimeFamily = 'NpmCli' RuntimePack = 'NpmCli' SnapshotName = 'CodexRuntime' SnapshotPathProperty = 'RuntimeHome' StateFunctionName = 'Get-CodexRuntimeState' InitializeCommandName = 'Initialize-CodexRuntime' DisplayName = 'Codex' DependencyCommandNames = @('Initialize-VCRuntime', 'Initialize-NodeRuntime') DirectInstallDependencies = @( [pscustomobject]@{ CommandName = 'Initialize-VCRuntime' } ) ToolsRootPropertyName = 'CodexToolsRoot' CacheRootPropertyName = 'CodexCacheRoot' InstallFunctionName = 'Install-CodexRuntime' RepairFunctionName = 'Repair-CodexRuntime' RuntimeTestFunctionName = 'Test-CodexRuntime' PackageJsonPropertyName = 'PackageJsonPath' ExecutablePropertyName = 'CodexCmd' ExecutableFileName = 'codex.cmd' CandidateLeafNames = @('codex.cmd', 'codex') DiscoveryCommandNames = @('codex.cmd', 'codex') CommandEnvironmentNames = @('codex', 'codex.cmd') PackageId = '@openai/codex@latest' PackageJsonRelativePath = 'node_modules\@openai\codex\package.json' StagePrefix = 'codex' NodeDependency = [pscustomobject]@{ Required = $true MinimumVersion = $null } BlockedReason = 'Only Windows hosts are supported by this Codex runtime bootstrap.' } } 'OpenCode' { return [pscustomobject]@{ Name = 'OpenCodeRuntime' RuntimeFamily = 'NpmCli' RuntimePack = 'NpmCli' SnapshotName = 'OpenCodeRuntime' SnapshotPathProperty = 'RuntimeHome' StateFunctionName = 'Get-OpenCodeRuntimeState' InitializeCommandName = 'Initialize-OpenCodeRuntime' DisplayName = 'OpenCode' DependencyCommandNames = @('Initialize-NodeRuntime') DirectInstallDependencies = @() ToolsRootPropertyName = 'OpenCodeToolsRoot' CacheRootPropertyName = 'OpenCodeCacheRoot' InstallFunctionName = 'Install-OpenCodeRuntime' RepairFunctionName = 'Repair-OpenCodeRuntime' RuntimeTestFunctionName = 'Test-OpenCodeRuntime' PackageJsonPropertyName = 'PackageJsonPath' ExecutablePropertyName = 'OpenCodeCmd' ExecutableFileName = 'opencode.cmd' CandidateLeafNames = @('opencode.cmd', 'opencode') DiscoveryCommandNames = @('opencode.cmd', 'opencode') CommandEnvironmentNames = @('opencode', 'opencode.cmd') PackageId = 'opencode-ai@latest' PackageJsonRelativePath = 'node_modules\opencode-ai\package.json' StagePrefix = 'opencode' NodeDependency = [pscustomobject]@{ Required = $true MinimumVersion = $null } BlockedReason = 'Only Windows hosts are supported by this OpenCode runtime bootstrap.' } } 'Gemini' { return [pscustomobject]@{ Name = 'GeminiRuntime' RuntimeFamily = 'NpmCli' RuntimePack = 'NpmCli' SnapshotName = 'GeminiRuntime' SnapshotPathProperty = 'RuntimeHome' StateFunctionName = 'Get-GeminiRuntimeState' InitializeCommandName = 'Initialize-GeminiRuntime' DisplayName = 'Gemini' DependencyCommandNames = @('Initialize-NodeRuntime') DirectInstallDependencies = @() ToolsRootPropertyName = 'GeminiToolsRoot' CacheRootPropertyName = 'GeminiCacheRoot' InstallFunctionName = 'Install-GeminiRuntime' RepairFunctionName = 'Repair-GeminiRuntime' RuntimeTestFunctionName = 'Test-GeminiRuntime' PackageJsonPropertyName = 'PackageJsonPath' ExecutablePropertyName = 'GeminiCmd' ExecutableFileName = 'gemini.cmd' CandidateLeafNames = @('gemini.cmd', 'gemini') DiscoveryCommandNames = @('gemini.cmd', 'gemini') CommandEnvironmentNames = @('gemini', 'gemini.cmd') PackageId = '@google/gemini-cli@latest' PackageJsonRelativePath = 'node_modules\@google\gemini-cli\package.json' StagePrefix = 'gemini' NodeDependency = [pscustomobject]@{ Required = $true MinimumVersion = [version]'20.0.0' } BlockedReason = 'Only Windows hosts are supported by this Gemini runtime bootstrap.' } } 'Qwen' { return [pscustomobject]@{ Name = 'QwenRuntime' RuntimeFamily = 'NpmCli' RuntimePack = 'NpmCli' SnapshotName = 'QwenRuntime' SnapshotPathProperty = 'RuntimeHome' StateFunctionName = 'Get-QwenRuntimeState' InitializeCommandName = 'Initialize-QwenRuntime' DisplayName = 'Qwen' DependencyCommandNames = @('Initialize-NodeRuntime') DirectInstallDependencies = @() ToolsRootPropertyName = 'QwenToolsRoot' CacheRootPropertyName = 'QwenCacheRoot' InstallFunctionName = 'Install-QwenRuntime' RepairFunctionName = 'Repair-QwenRuntime' RuntimeTestFunctionName = 'Test-QwenRuntime' PackageJsonPropertyName = 'PackageJsonPath' ExecutablePropertyName = 'QwenCmd' ExecutableFileName = 'qwen.cmd' CandidateLeafNames = @('qwen.cmd', 'qwen') DiscoveryCommandNames = @('qwen.cmd', 'qwen') CommandEnvironmentNames = @('qwen', 'qwen.cmd') PackageId = '@qwen-code/qwen-code@latest' PackageJsonRelativePath = 'node_modules\@qwen-code\qwen-code\package.json' StagePrefix = 'qwen' NodeDependency = [pscustomobject]@{ Required = $true MinimumVersion = [version]'20.0.0' } BlockedReason = 'Only Windows hosts are supported by this Qwen runtime bootstrap.' } } } } function Get-ManifestedCodexNpmCliRuntimeDefinition { [CmdletBinding()] param() return (Get-ManifestedNpmCliRuntimeDefinition -Name 'Codex') } function Get-ManifestedOpenCodeNpmCliRuntimeDefinition { [CmdletBinding()] param() return (Get-ManifestedNpmCliRuntimeDefinition -Name 'OpenCode') } function Get-ManifestedGeminiNpmCliRuntimeDefinition { [CmdletBinding()] param() return (Get-ManifestedNpmCliRuntimeDefinition -Name 'Gemini') } function Get-ManifestedQwenNpmCliRuntimeDefinition { [CmdletBinding()] param() return (Get-ManifestedNpmCliRuntimeDefinition -Name 'Qwen') } function New-ManifestedNpmCliCommandEnvironmentResolver { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string[]]$CommandNames, [Parameter(Mandatory = $true)] [string]$ExecutableFileName ) $resolvedCommandNames = @($CommandNames) $resolvedExecutableFileName = $ExecutableFileName return { param([pscustomobject]$RuntimeState) $runtimeHome = if ($RuntimeState -and $RuntimeState.PSObject.Properties['RuntimeHome']) { $RuntimeState.RuntimeHome } else { $null } $executablePath = if ($RuntimeState -and $RuntimeState.PSObject.Properties['ExecutablePath']) { $RuntimeState.ExecutablePath } else { $null } $desiredCommandDirectory = $null $expectedCommandPaths = [ordered]@{} if (-not [string]::IsNullOrWhiteSpace($runtimeHome)) { $desiredCommandDirectory = $runtimeHome } elseif (-not [string]::IsNullOrWhiteSpace($executablePath)) { $desiredCommandDirectory = Split-Path -Parent $executablePath } $commandPath = $null if (-not [string]::IsNullOrWhiteSpace($executablePath)) { $commandPath = (Get-ManifestedFullPath -Path $executablePath) } elseif (-not [string]::IsNullOrWhiteSpace($runtimeHome)) { $commandPath = (Get-ManifestedFullPath -Path (Join-Path $runtimeHome $resolvedExecutableFileName)) } if (-not [string]::IsNullOrWhiteSpace($commandPath)) { foreach ($commandName in @($resolvedCommandNames)) { $expectedCommandPaths[$commandName] = $commandPath } } [pscustomobject]@{ DesiredCommandDirectory = $desiredCommandDirectory ExpectedCommandPaths = $expectedCommandPaths } } } function New-ManifestedNpmCliRuntimeRegistryDescriptor { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition ) return [pscustomobject]@{ Name = $Definition.Name RuntimeFamily = $Definition.RuntimeFamily RuntimePack = $Definition.RuntimePack SnapshotName = $Definition.SnapshotName SnapshotPathProperty = $Definition.SnapshotPathProperty StateFunctionName = $Definition.StateFunctionName InitializeCommandName = $Definition.InitializeCommandName DisplayName = $Definition.DisplayName DependencyCommandNames = @($Definition.DependencyCommandNames) DirectInstallDependencies = @($Definition.DirectInstallDependencies) ToolsRootPropertyName = $Definition.ToolsRootPropertyName InstallFunctionName = $Definition.InstallFunctionName RepairFunctionName = $Definition.RepairFunctionName RuntimeTestFunctionName = $Definition.RuntimeTestFunctionName PackageJsonPropertyName = $Definition.PackageJsonPropertyName NodeDependency = $Definition.NodeDependency ResolveCommandEnvironment = (New-ManifestedNpmCliCommandEnvironmentResolver -CommandNames $Definition.CommandEnvironmentNames -ExecutableFileName $Definition.ExecutableFileName) } } function Get-ManifestedNpmCliRuntimePackageJsonPath { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [Parameter(Mandatory = $true)] [string]$RuntimeHome ) return (Join-Path $RuntimeHome $Definition.PackageJsonRelativePath) } function Get-ManifestedNpmCliRuntimePackageVersion { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [Parameter(Mandatory = $true)] [string]$PackageJsonPath ) if (-not (Test-Path -LiteralPath $PackageJsonPath)) { return $null } try { $packageDocument = Get-Content -LiteralPath $PackageJsonPath -Raw -ErrorAction Stop | ConvertFrom-Json return (ConvertTo-ManifestedNpmCliVersion -VersionText ([string]$packageDocument.version)) } catch { return $null } } function Test-ManifestedNpmCliRuntime { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [Parameter(Mandatory = $true)] [string]$RuntimeHome ) $executablePath = Join-Path $RuntimeHome $Definition.ExecutableFileName $packageJsonPath = Get-ManifestedNpmCliRuntimePackageJsonPath -Definition $Definition -RuntimeHome $RuntimeHome $packageVersion = $null $reportedVersion = $null if (-not (Test-Path -LiteralPath $RuntimeHome)) { $status = 'Missing' } elseif (-not (Test-Path -LiteralPath $executablePath) -or -not (Test-Path -LiteralPath $packageJsonPath)) { $status = 'NeedsRepair' } else { $packageVersion = Get-ManifestedNpmCliRuntimePackageVersion -Definition $Definition -PackageJsonPath $packageJsonPath try { $reportedVersion = (& $executablePath --version 2>$null | Select-Object -First 1) if ($reportedVersion) { $reportedVersion = (ConvertTo-ManifestedNpmCliVersion -VersionText $reportedVersion.ToString().Trim()) } } catch { $reportedVersion = $null } if ([string]::IsNullOrWhiteSpace($packageVersion) -or [string]::IsNullOrWhiteSpace($reportedVersion)) { $status = 'NeedsRepair' } elseif ($packageVersion -ne $reportedVersion) { $status = 'NeedsRepair' } else { $status = 'Ready' } } $result = [ordered]@{ Status = $status IsReady = ($status -eq 'Ready') RuntimeHome = $RuntimeHome } $result[$Definition.ExecutablePropertyName] = $executablePath $result['PackageJsonPath'] = $packageJsonPath $result['PackageVersion'] = $packageVersion $result['ReportedVersion'] = $reportedVersion return [pscustomobject]$result } function Get-InstalledManifestedNpmCliRuntime { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $layout = Get-ManifestedLayout -LocalRoot $LocalRoot $toolsRoot = $layout.($Definition.ToolsRootPropertyName) $entries = @() if (Test-Path -LiteralPath $toolsRoot) { $runtimeRoots = Get-ChildItem -LiteralPath $toolsRoot -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike ('_stage_{0}_*' -f $Definition.StagePrefix) } | Sort-Object -Descending -Property @{ Expression = { ConvertTo-ManifestedNpmCliVersionObject -VersionText $_.Name } }, Name foreach ($runtimeRoot in $runtimeRoots) { $validation = Test-ManifestedNpmCliRuntime -Definition $Definition -RuntimeHome $runtimeRoot.FullName $expectedVersion = ConvertTo-ManifestedNpmCliVersion -VersionText $runtimeRoot.Name $runtimeVersion = if ($validation.PackageVersion) { $validation.PackageVersion } else { $expectedVersion } $versionMatches = (-not $expectedVersion) -or (-not $validation.PackageVersion) -or ($expectedVersion -eq $validation.PackageVersion) $entry = [ordered]@{ Version = $runtimeVersion RuntimeHome = $runtimeRoot.FullName } $entry[$Definition.ExecutablePropertyName] = $validation.($Definition.ExecutablePropertyName) $entry['PackageJsonPath'] = $validation.PackageJsonPath $entry['Validation'] = $validation $entry['VersionMatches'] = $versionMatches $entry['IsReady'] = ($validation.IsReady -and $versionMatches) $entry['Source'] = 'Managed' $entries += [pscustomobject]$entry } } [pscustomobject]@{ Current = ($entries | Where-Object { $_.IsReady } | Select-Object -First 1) Valid = @($entries | Where-Object { $_.IsReady }) Invalid = @($entries | Where-Object { -not $_.IsReady }) } } function Get-ManifestedNpmCliRuntimeFromCandidatePath { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [string]$CandidatePath ) $resolvedCandidatePath = Get-ManifestedFullPath -Path $CandidatePath if ([string]::IsNullOrWhiteSpace($resolvedCandidatePath) -or -not (Test-Path -LiteralPath $resolvedCandidatePath)) { return $null } $leafName = Split-Path -Leaf $resolvedCandidatePath $isSupportedLeaf = $false foreach ($candidateLeafName in @($Definition.CandidateLeafNames)) { if ($leafName -ieq $candidateLeafName) { $isSupportedLeaf = $true break } } if (-not $isSupportedLeaf) { return $null } $runtimeHome = Split-Path -Parent $resolvedCandidatePath $validation = Test-ManifestedNpmCliRuntime -Definition $Definition -RuntimeHome $runtimeHome if (-not $validation.IsReady) { return $null } $result = [ordered]@{ Version = $validation.PackageVersion RuntimeHome = $runtimeHome } $result[$Definition.ExecutablePropertyName] = $validation.($Definition.ExecutablePropertyName) $result['PackageJsonPath'] = $validation.PackageJsonPath $result['Validation'] = $validation $result['IsReady'] = $true $result['Source'] = 'External' $result['Discovery'] = 'Path' return [pscustomobject]$result } function Get-SystemManifestedNpmCliRuntime { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $layout = Get-ManifestedLayout -LocalRoot $LocalRoot $toolsRoot = $layout.($Definition.ToolsRootPropertyName) $candidatePaths = New-Object System.Collections.Generic.List[string] foreach ($commandName in @($Definition.DiscoveryCommandNames)) { $candidatePath = Get-ManifestedApplicationPath -CommandName $commandName -ExcludedRoots @($toolsRoot) if (-not [string]::IsNullOrWhiteSpace($candidatePath)) { $candidatePaths.Add($candidatePath) | Out-Null } } foreach ($candidatePath in @($candidatePaths | Select-Object -Unique)) { $runtime = Get-ManifestedNpmCliRuntimeFromCandidatePath -Definition $Definition -CandidatePath $candidatePath if ($runtime) { return $runtime } } return $null } function Get-ManifestedNpmCliRuntimeState { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) { return [pscustomobject]@{ Status = 'Blocked' LocalRoot = $LocalRoot Layout = $null CurrentVersion = $null RuntimeHome = $null RuntimeSource = $null ExecutablePath = $null Runtime = $null InvalidRuntimeHomes = @() PartialPaths = @() BlockedReason = $Definition.BlockedReason PackageJsonPath = $null } } $layout = Get-ManifestedLayout -LocalRoot $LocalRoot $toolsRoot = $layout.($Definition.ToolsRootPropertyName) $partialPaths = @( Get-ManifestedStageDirectories -Prefix $Definition.StagePrefix -Mode TemporaryShort -LegacyRootPaths @($toolsRoot) | Select-Object -ExpandProperty FullName ) $installed = Get-InstalledManifestedNpmCliRuntime -Definition $Definition -LocalRoot $layout.LocalRoot $managedRuntime = $installed.Current $externalRuntime = $null if (-not $managedRuntime) { $externalRuntime = Get-SystemManifestedNpmCliRuntime -Definition $Definition -LocalRoot $layout.LocalRoot } $currentRuntime = if ($managedRuntime) { $managedRuntime } else { $externalRuntime } $runtimeSource = if ($managedRuntime) { 'Managed' } elseif ($externalRuntime) { 'External' } else { $null } $invalidRuntimeHomes = @($installed.Invalid | Select-Object -ExpandProperty RuntimeHome) if ($invalidRuntimeHomes.Count -gt 0) { $status = 'NeedsRepair' } elseif ($partialPaths.Count -gt 0) { $status = 'Partial' } elseif ($currentRuntime) { $status = 'Ready' } else { $status = 'Missing' } [pscustomobject]@{ Status = $status LocalRoot = $layout.LocalRoot Layout = $layout CurrentVersion = if ($currentRuntime) { $currentRuntime.Version } else { $null } RuntimeHome = if ($currentRuntime) { $currentRuntime.RuntimeHome } else { $null } RuntimeSource = $runtimeSource ExecutablePath = if ($currentRuntime) { $currentRuntime.($Definition.ExecutablePropertyName) } else { $null } Runtime = if ($currentRuntime) { $currentRuntime.Validation } else { $null } InvalidRuntimeHomes = $invalidRuntimeHomes PartialPaths = $partialPaths BlockedReason = $null PackageJsonPath = if ($currentRuntime) { $currentRuntime.PackageJsonPath } else { $null } } } function Repair-ManifestedNpmCliRuntime { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [pscustomobject]$State, [string[]]$CorruptRuntimeHomes = @(), [string]$LocalRoot = (Get-ManifestedLocalRoot) ) if (-not $State) { $State = Get-ManifestedNpmCliRuntimeState -Definition $Definition -LocalRoot $LocalRoot } $pathsToRemove = New-Object System.Collections.Generic.List[string] foreach ($path in @($State.PartialPaths)) { if (-not [string]::IsNullOrWhiteSpace($path)) { $pathsToRemove.Add($path) | Out-Null } } foreach ($path in @($State.InvalidRuntimeHomes)) { if (-not [string]::IsNullOrWhiteSpace($path)) { $pathsToRemove.Add($path) | Out-Null } } foreach ($path in @($CorruptRuntimeHomes)) { if (-not [string]::IsNullOrWhiteSpace($path)) { $pathsToRemove.Add($path) | Out-Null } } $removedPaths = New-Object System.Collections.Generic.List[string] foreach ($path in @($pathsToRemove | Select-Object -Unique)) { if (Remove-ManifestedPath -Path $path) { $removedPaths.Add($path) | Out-Null } } [pscustomobject]@{ Action = if ($removedPaths.Count -gt 0) { 'Repaired' } else { 'Skipped' } RemovedPaths = @($removedPaths) LocalRoot = $State.LocalRoot Layout = $State.Layout } } function Install-ManifestedNpmCliRuntime { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Definition, [Parameter(Mandatory = $true)] [string]$NpmCmd, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $layout = Get-ManifestedLayout -LocalRoot $LocalRoot $cacheRoot = $layout.($Definition.CacheRootPropertyName) $toolsRoot = $layout.($Definition.ToolsRootPropertyName) New-ManifestedDirectory -Path $cacheRoot | Out-Null New-ManifestedDirectory -Path $toolsRoot | Out-Null $stagePath = New-ManifestedStageDirectory -Prefix $Definition.StagePrefix -Mode TemporaryShort $npmConfiguration = Get-ManifestedManagedNpmCommandArguments -NpmCmd $NpmCmd -LocalRoot $LocalRoot $npmArguments = @('install', '-g', '--prefix', $stagePath, '--cache', $cacheRoot) $npmArguments += @($npmConfiguration.CommandArguments) $npmArguments += $Definition.PackageId Write-Host ('Installing {0} CLI into managed sandbox tools...' -f $Definition.DisplayName) & $NpmCmd @npmArguments if ($LASTEXITCODE -ne 0) { throw ("npm install for {0} exited with code {1}." -f $Definition.DisplayName, $LASTEXITCODE) } $stageValidation = Test-ManifestedNpmCliRuntime -Definition $Definition -RuntimeHome $stagePath if (-not $stageValidation.IsReady) { throw ("{0} runtime validation failed after staged install at {1}." -f $Definition.DisplayName, $stagePath) } $version = if ($stageValidation.PackageVersion) { $stageValidation.PackageVersion } else { ConvertTo-ManifestedNpmCliVersion -VersionText $stageValidation.ReportedVersion } if ([string]::IsNullOrWhiteSpace($version)) { throw ("Could not determine the installed {0} version from {1}." -f $Definition.DisplayName, $stageValidation.PackageJsonPath) } $runtimeHome = Join-Path $toolsRoot $version if (Test-Path -LiteralPath $runtimeHome) { Remove-ManifestedPath -Path $runtimeHome | Out-Null } Move-Item -LiteralPath $stagePath -Destination $runtimeHome -Force $validation = Test-ManifestedNpmCliRuntime -Definition $Definition -RuntimeHome $runtimeHome if (-not $validation.IsReady) { throw ("{0} runtime validation failed after install at {1}." -f $Definition.DisplayName, $runtimeHome) } $result = [ordered]@{ Action = 'Installed' Version = $validation.PackageVersion RuntimeHome = $runtimeHome } $result[$Definition.ExecutablePropertyName] = $validation.($Definition.ExecutablePropertyName) $result['PackageJsonPath'] = $validation.PackageJsonPath $result['Source'] = 'Managed' $result['CacheRoot'] = $cacheRoot $result['NpmCmd'] = $NpmCmd return [pscustomobject]$result } |