[CmdletBinding()] param( [ValidateSet('Debug', 'Release', 'ReleaseFast', 'ReleaseSize')] [string]$Configuration = 'ReleaseFast', [switch]$SkipBuild, [switch]$SkipPromptGeneration ) $ErrorActionPreference = 'Stop' Set-StrictMode -Version Latest . (Join-Path $PSScriptRoot 'toolbox-commands.ps1') function Invoke-StrictNative { param( [Parameter(Mandatory = $true)] [string]$FilePath, [Parameter(Mandatory = $true)] [string[]]$ArgumentList ) & $FilePath @ArgumentList if ($LASTEXITCODE -ne 0) { throw "Command failed with exit code ${LASTEXITCODE}: $FilePath $($ArgumentList -join ' ')" } } function Get-RequiredCommandPath { param( [Parameter(Mandatory = $true)] [string]$Name ) $command = Get-Command -Name $Name -ErrorAction SilentlyContinue if ($null -eq $command) { throw "Required command not found on PATH: $Name" } return $command.Source } function Assert-Condition { param( [Parameter(Mandatory = $true)] [bool]$Condition, [Parameter(Mandatory = $true)] [string]$Message ) if (-not $Condition) { throw $Message } } function Get-ToolboxBinaryPath { param( [Parameter(Mandatory = $true)] [string]$Name ) $path = Join-Path $script:BinaryRoot "$Name.exe" if (-not (Test-Path -LiteralPath $path)) { throw "Expected toolbox binary not found: $path" } return $path } function Get-FreeTcpPort { $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) $listener.Start() try { return ([System.Net.IPEndPoint]$listener.LocalEndpoint).Port } finally { $listener.Stop() } } function Start-LoopbackHttpServer { param( [Parameter(Mandatory = $true)] [int]$Port ) $readyFile = Join-Path ([System.IO.Path]::GetTempPath()) ("mercury-loopback-ready-" + [System.Guid]::NewGuid()) $job = Start-Job -ScriptBlock { param($JobPort, $JobReadyFile) $listener = [System.Net.HttpListener]::new() $listener.Prefixes.Add("http://127.0.0.1:$JobPort/") $listener.Start() New-Item -ItemType File -Force -Path $JobReadyFile | Out-Null try { $context = $listener.GetContext() $payload = [System.Text.Encoding]::UTF8.GetBytes('{"ok":true}') $response = $context.Response $response.StatusCode = 200 $response.ContentType = 'application/json' $response.ContentLength64 = $payload.Length $response.OutputStream.Write($payload, 0, $payload.Length) $response.OutputStream.Close() } finally { Remove-Item -LiteralPath $JobReadyFile -Force -ErrorAction SilentlyContinue $listener.Stop() $listener.Close() } } -ArgumentList $Port, $readyFile Wait-Until -Description "loopback HTTP server on port $Port" -TimeoutMilliseconds 3000 -Probe { if (Test-Path -LiteralPath $readyFile) { return $true } if ($job.State -in @('Completed', 'Failed', 'Stopped')) { return $true } return $false } if (-not (Test-Path -LiteralPath $readyFile)) { Stop-JobSafe -Job $job throw "loopback HTTP server on port $Port exited before becoming ready" } return [pscustomobject]@{ Job = $job ReadyFile = $readyFile } } function Stop-JobSafe { param( [Parameter(Mandatory = $true)] [System.Management.Automation.Job]$Job ) if ($Job.State -eq 'Running') { Stop-Job -Job $Job | Out-Null } Receive-Job -Job $Job -ErrorAction SilentlyContinue | Out-Null Remove-Job -Job $Job -Force -ErrorAction SilentlyContinue | Out-Null } function Stop-LoopbackHttpServer { param( [Parameter(Mandatory = $true)] [psobject]$Server ) if ($null -ne $Server.Job) { Stop-JobSafe -Job $Server.Job } if ($Server.PSObject.Properties.Name -contains 'ReadyFile') { Remove-Item -LiteralPath $Server.ReadyFile -Force -ErrorAction SilentlyContinue } } function Wait-Until { param( [Parameter(Mandatory = $true)] [string]$Description, [Parameter(Mandatory = $true)] [scriptblock]$Probe, [int]$TimeoutMilliseconds = 3000, [int]$IntervalMilliseconds = 50 ) $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() while ($stopwatch.ElapsedMilliseconds -lt $TimeoutMilliseconds) { if (& $Probe) { return } Start-Sleep -Milliseconds $IntervalMilliseconds } throw "timed out waiting for $Description" } function Test-TcpPortListening { param( [Parameter(Mandatory = $true)] [int]$Port ) $client = [System.Net.Sockets.TcpClient]::new() try { $connect = $client.ConnectAsync([System.Net.IPAddress]::Loopback, $Port) if (-not $connect.Wait(150)) { return $false } return $client.Connected } catch { return $false } finally { $client.Dispose() } } function Test-ExclusiveFileLock { param( [Parameter(Mandatory = $true)] [string]$Path ) $stream = $null try { $stream = [System.IO.File]::Open($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) return $false } catch [System.IO.IOException] { return $true } finally { if ($null -ne $stream) { $stream.Dispose() } } } function Invoke-Check { param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [scriptblock]$Script ) try { $detail = & $Script $script:Results.Add([pscustomobject]@{ Check = $Name Status = 'PASS' Detail = [string]$detail }) } catch { $script:Results.Add([pscustomobject]@{ Check = $Name Status = 'FAIL' Detail = $_.Exception.Message }) $script:Failed = $true } } function Invoke-PwshFile { param( [Parameter(Mandatory = $true)] [string]$FilePath, [string[]]$ArgumentList = @() ) $output = & pwsh -NoProfile -ExecutionPolicy Bypass -File $FilePath @ArgumentList 2>&1 return [pscustomobject]@{ ExitCode = $LASTEXITCODE Output = (($output | ForEach-Object { [string]$_ }) -join "`n") } } function Invoke-NativeCapture { param( [Parameter(Mandatory = $true)] [string]$FilePath, [string[]]$ArgumentList = @(), [int]$TimeoutMilliseconds = 5000 ) $psi = [System.Diagnostics.ProcessStartInfo]::new() $psi.FileName = $FilePath foreach ($argument in $ArgumentList) { [void]$psi.ArgumentList.Add($argument) } $psi.UseShellExecute = $false $psi.RedirectStandardOutput = $true $psi.RedirectStandardError = $true $psi.CreateNoWindow = $true $process = [System.Diagnostics.Process]::new() $process.StartInfo = $psi [void]$process.Start() if (-not $process.WaitForExit($TimeoutMilliseconds)) { try { $process.Kill($true) } catch { $process.Kill() } throw "timed out after ${TimeoutMilliseconds}ms: $FilePath $($ArgumentList -join ' ')" } $stdout = $process.StandardOutput.ReadToEnd() $stderr = $process.StandardError.ReadToEnd() $exitCode = $process.ExitCode $process.Dispose() return [pscustomobject]@{ ExitCode = $exitCode Stdout = $stdout Stderr = $stderr Output = ($stdout + $stderr) } } function Test-ToolboxBinaryVersions { foreach ($commandName in Get-ToolboxCommandNames) { $binary = Get-ToolboxBinaryPath -Name $commandName $result = Invoke-NativeCapture -FilePath $binary -ArgumentList @('--version') Assert-Condition ($result.ExitCode -eq 0) "$commandName --version failed with exit code $($result.ExitCode): $($result.Output)" Assert-Condition ($result.Output -match [regex]::Escape($commandName)) "$commandName --version did not include command name: $($result.Output)" } } function Test-ToolboxNoArgsContracts { $stdinWaitingCommands = @( 'ison', 'isonl', 'zon', 'tonl', 'jsonlgrep', 'ctxpack', 'diagpick', 'hitsnip', 'logshape', 'recent', 'codeshape', 'snip', 'sysshape', 'toon' ) foreach ($commandName in Get-ToolboxCommandNames) { if ($commandName -in $stdinWaitingCommands) { continue } $binary = Get-ToolboxBinaryPath -Name $commandName $result = Invoke-NativeCapture -FilePath $binary Assert-Condition ($result.Output.Length -lt 20000) "$commandName no-args output was unexpectedly large" Assert-Condition ($result.Output -notmatch '(?i)panic|backtrace') "$commandName no-args output contained panic/backtrace text" } } function Test-ToolboxInvalidFlagContracts { foreach ($commandName in Get-ToolboxCommandNames) { $binary = Get-ToolboxBinaryPath -Name $commandName $result = Invoke-NativeCapture -FilePath $binary -ArgumentList @('--mercury-invalid-flag') Assert-Condition ($result.ExitCode -ne 0) "$commandName accepted an invalid flag" Assert-Condition ($result.Output.Length -gt 0) "$commandName invalid-flag diagnostic was empty" Assert-Condition ($result.Output -notmatch '(?i)panic|backtrace') "$commandName invalid-flag output contained panic/backtrace text" } } function Test-ToolboxStructuredOutputHelpContracts { foreach ($commandName in Get-ToolboxCommandNames) { $binary = Get-ToolboxBinaryPath -Name $commandName $result = Invoke-NativeCapture -FilePath $binary -ArgumentList @('--help') Assert-Condition ($result.ExitCode -eq 0) "$commandName --help failed with exit code $($result.ExitCode)" Assert-Condition ($result.Output -match '--json|--format|--toon|JSON|TOON') "$commandName --help does not mention structured output controls" } } function Test-ToolboxMalformedJsonlStdinContracts { foreach ($probe in @( @{ Name = 'cjson'; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'jsonshape'; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'toon'; Args = @('--input-format', 'jsonl') } )) { $binary = Get-ToolboxBinaryPath -Name $probe.Name $result = "'{not-json}'" | & $binary @($probe.Args) 2>&1 $exitCode = $LASTEXITCODE $text = (($result | ForEach-Object { [string]$_ }) -join "`n") Assert-Condition ($exitCode -ne 0) "$($probe.Name) accepted malformed JSONL stdin" Assert-Condition ($text.Length -gt 0) "$($probe.Name) malformed JSONL diagnostic was empty" Assert-Condition ($text -notmatch '(?i)panic|backtrace') "$($probe.Name) malformed JSONL diagnostic contained panic/backtrace text" } } function Write-TestPackageSha256Sums { param( [Parameter(Mandatory = $true)] [string]$PackageRoot, [switch]$UseWindowsSeparators ) $hashPath = Join-Path $PackageRoot 'SHA256SUMS.txt' $lines = [System.Collections.Generic.List[string]]::new() foreach ($file in (Get-ChildItem -LiteralPath $PackageRoot -Recurse -File | Sort-Object FullName)) { if ($file.FullName -eq $hashPath) { continue } $relativePath = [System.IO.Path]::GetRelativePath($PackageRoot, $file.FullName) if (-not $UseWindowsSeparators) { $relativePath = $relativePath.Replace('\', '/') } $hash = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant() $lines.Add("$hash $relativePath") } Set-Content -LiteralPath $hashPath -Value $lines -Encoding utf8NoBOM } function New-TestPortablePackage { param( [Parameter(Mandatory = $true)] [string]$PackageRoot, [switch]$UseWindowsSeparators ) $scriptsRoot = Join-Path $PackageRoot 'scripts' $binRoot = Join-Path $PackageRoot 'bin' $docsRoot = Join-Path $PackageRoot 'docs\ai' $skillRoot = Join-Path $PackageRoot 'skills\mercury-toolbox' $catalogRoot = Join-Path $skillRoot 'references' New-Item -ItemType Directory -Force -Path $scriptsRoot, $binRoot, $docsRoot, $catalogRoot | Out-Null Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'install-package-toolbox.ps1') -Destination (Join-Path $scriptsRoot 'install-package-toolbox.ps1') -Force Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'toolbox-commands.ps1') -Destination (Join-Path $scriptsRoot 'toolbox-commands.ps1') -Force foreach ($commandName in Get-ToolboxCommandNames) { Set-Content -LiteralPath (Join-Path $binRoot "$commandName.exe") -Value "fake $commandName" -Encoding utf8NoBOM } Set-Content -LiteralPath (Join-Path $docsRoot 'mercury-toolbox-ai-prompt.md') -Value 'test prompt' -Encoding utf8NoBOM Set-Content -LiteralPath (Join-Path $skillRoot 'SKILL.md') -Value 'test skill' -Encoding utf8NoBOM Set-Content -LiteralPath (Join-Path $catalogRoot 'command-catalog.md') -Value 'test catalog' -Encoding utf8NoBOM [ordered]@{ name = 'Mercury Toolbox' commands = @(Get-ToolboxCommandNames) } | ConvertTo-Json -Depth 3 | Set-Content -LiteralPath (Join-Path $PackageRoot 'mercury-toolbox-package.json') -Encoding utf8NoBOM Write-TestPackageSha256Sums -PackageRoot $PackageRoot -UseWindowsSeparators:$UseWindowsSeparators } $workspaceRoot = Split-Path -Parent $PSScriptRoot $targetProfile = Resolve-ToolboxProfileName -Configuration $Configuration $script:BinaryRoot = Join-Path $workspaceRoot (Join-Path 'target' $targetProfile) $dependencyRoot = Join-Path $script:BinaryRoot 'deps' if (Test-Path -LiteralPath $dependencyRoot -PathType Container) { $env:PATH = "$dependencyRoot$([System.IO.Path]::PathSeparator)$env:PATH" } $fixtureRoot = Join-Path $workspaceRoot 'fixtures' $cargoPath = Get-RequiredCommandPath -Name 'cargo' $batPath = Get-RequiredCommandPath -Name 'bat' $fdPath = Get-RequiredCommandPath -Name 'fd' $rgPath = Get-RequiredCommandPath -Name 'rg' $jqPath = Get-RequiredCommandPath -Name 'jq' $script:Results = [System.Collections.Generic.List[object]]::new() $script:Failed = $false Write-Host "Mercury Toolbox ecosystem check" Write-Host "workspace: $workspaceRoot" Write-Host "configuration: $Configuration" Write-Host "binary root: $script:BinaryRoot" if (-not $SkipBuild) { Invoke-ToolboxBuild -CargoPath $cargoPath -Configuration $Configuration } $jsonlgrep = Get-ToolboxBinaryPath -Name 'jsonlgrep' $jsonshape = Get-ToolboxBinaryPath -Name 'jsonshape' $cjson = Get-ToolboxBinaryPath -Name 'cjson' $recent = Get-ToolboxBinaryPath -Name 'recent' $pathshadow = Get-ToolboxBinaryPath -Name 'pathshadow' $portping = Get-ToolboxBinaryPath -Name 'portping' $portunlock = Get-ToolboxBinaryPath -Name 'portunlock' $msudo = Get-ToolboxBinaryPath -Name 'msudo' $asmtype = Get-ToolboxBinaryPath -Name 'asmtype' $asmmember = Get-ToolboxBinaryPath -Name 'asmmember' $asmref = Get-ToolboxBinaryPath -Name 'asmref' $binmeta = Get-ToolboxBinaryPath -Name 'binmeta' $fileprobe = Get-ToolboxBinaryPath -Name 'fileprobe' $outline = Get-ToolboxBinaryPath -Name 'outline' $codeshape = Get-ToolboxBinaryPath -Name 'codeshape' $snip = Get-ToolboxBinaryPath -Name 'snip' $defsnip = Get-ToolboxBinaryPath -Name 'defsnip' $chunkcat = Get-ToolboxBinaryPath -Name 'chunkcat' $hitsnip = Get-ToolboxBinaryPath -Name 'hitsnip' $diagpick = Get-ToolboxBinaryPath -Name 'diagpick' $logshape = Get-ToolboxBinaryPath -Name 'logshape' $stringscan = Get-ToolboxBinaryPath -Name 'stringscan' $toon = Get-ToolboxBinaryPath -Name 'toon' $csvshape = Get-ToolboxBinaryPath -Name 'csvshape' $sqliteshape = Get-ToolboxBinaryPath -Name 'sqliteshape' $sqlshape = Get-ToolboxBinaryPath -Name 'sqlshape' $envdiff = Get-ToolboxBinaryPath -Name 'envdiff' $proctree = Get-ToolboxBinaryPath -Name 'proctree' $sysshape = Get-ToolboxBinaryPath -Name 'sysshape' $unlock = Get-ToolboxBinaryPath -Name 'unlock' Invoke-Check -Name 'toolbox:all-binaries-report-version' -Script { Test-ToolboxBinaryVersions "verified --version output for $((Get-ToolboxCommandNames).Count) toolbox binaries" } Invoke-Check -Name 'toolbox:all-binaries-no-args-contract' -Script { Test-ToolboxNoArgsContracts "verified bounded no-args behavior for non-stdin-waiting toolbox binaries" } Invoke-Check -Name 'toolbox:all-binaries-invalid-flag-contract' -Script { Test-ToolboxInvalidFlagContracts "verified invalid-flag diagnostics for $((Get-ToolboxCommandNames).Count) toolbox binaries" } Invoke-Check -Name 'toolbox:all-binaries-structured-output-help' -Script { Test-ToolboxStructuredOutputHelpContracts "verified structured-output help surface for $((Get-ToolboxCommandNames).Count) toolbox binaries" } Invoke-Check -Name 'toolbox:malformed-jsonl-stdin-contract' -Script { Test-ToolboxMalformedJsonlStdinContracts 'verified malformed JSONL stdin fails closed for representative input-format commands' } Invoke-Check -Name 'toolbox:functional-toon-smokes' -Script { $outputs = @( (& $fileprobe (Join-Path $fixtureRoot 'reading\sample.rs') --toon), (& $jsonshape (Join-Path $fixtureRoot 'jsonshape\events.jsonl') --input-format jsonl --toon), (& $csvshape (Join-Path $fixtureRoot 'csvshape\sample.csv') --toon) ) foreach ($output in $outputs) { $text = (($output | ForEach-Object { [string]$_ }) -join "`n") Assert-Condition ($text.Trim().Length -gt 0) 'expected non-empty representative TOON smoke output' Assert-Condition ($text -notmatch '(?i)panic|backtrace') "TOON smoke output contained panic/backtrace text: $text" } 'verified representative functional TOON smokes across file, JSONL, and CSV families' } Invoke-Check -Name 'cjson:stdin-jsonl-wrapper' -Script { $wrapper = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'cjson\records.jsonl') | & $cjson --input-format jsonl --sort-keys --json | ConvertFrom-Json Assert-Condition ($wrapper.format -eq 'jsonl') "expected cjson wrapper format jsonl, got $($wrapper.format)" Assert-Condition ($wrapper.documents -eq 2) "expected 2 compacted documents, got $($wrapper.documents)" Assert-Condition ($wrapper.text -match '"event":"login","ok":true') 'expected compact wrapper text to contain a sorted login record' "wrapped $($wrapper.documents) compacted JSONL document(s) for PowerShell consumers" } Invoke-Check -Name 'jsonlgrep:stdin-json' -Script { $matchRows = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'jsonl\events.jsonl') | & $jsonlgrep 'level=error' --pick ts,msg --json | ConvertFrom-Json Assert-Condition (@($matchRows).Count -eq 2) "expected 2 error rows, got $(@($matchRows).Count)" Assert-Condition ((@($matchRows)[0].msg) -eq 'failed login') 'expected first error message to be "failed login"' "matched $(@($matchRows).Count) error rows through stdin + ConvertFrom-Json" } Invoke-Check -Name 'jsonshape:stdin-jq' -Script { $summaryJson = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'jsonshape\events.jsonl') | & $jsonshape --input-format jsonl --json $documents = [int]($summaryJson | & $jqPath '-r' '.documents') $pathCount = [int]($summaryJson | & $jqPath '-r' '.paths | length') Assert-Condition ($documents -eq 2) "expected 2 JSON documents, got $documents" Assert-Condition ($pathCount -ge 3) "expected at least 3 summarized paths, got $pathCount" "summarized $documents documents and $pathCount paths through jq" } Invoke-Check -Name 'recent:json-pipeline' -Script { $recentJson = & $recent --root $fixtureRoot --ext rs --limit 3 --json $firstPath = $recentJson | & $jqPath '-r' '.[0].path' $count = [int]($recentJson | & $jqPath '-r' 'length') Assert-Condition ($count -ge 1) "expected recent to return at least one Rust file, got $count" Assert-Condition ($firstPath.EndsWith('.rs')) "expected first recent path to end with .rs, got $firstPath" "returned $count recent Rust paths and projected the first path with jq" } Invoke-Check -Name 'pathshadow:piped-command' -Script { $pathMatches = 'cargo' | & $pathshadow --json | ConvertFrom-Json Assert-Condition (@($pathMatches).Count -ge 1) 'expected at least one cargo path match' Assert-Condition ((@($pathMatches)[0].command) -eq 'cargo') "expected first pathshadow command to be cargo" "resolved $(@($pathMatches).Count) PATH candidates for cargo from piped input" } Invoke-Check -Name 'pathshadow:summary-shell-json' -Script { $summary = & $pathshadow cargo --shell powershell --summary --json | ConvertFrom-Json $first = @($summary)[0] Assert-Condition (@($summary).Count -ge 1) 'expected at least one pathshadow summary row' Assert-Condition ($first.command -eq 'cargo') "expected cargo summary row, got $($first.command)" Assert-Condition ($first.total_matches -ge 1) "expected at least one cargo match, got $($first.total_matches)" Assert-Condition ($first.shell_mode -eq 'powershell') "expected powershell shell mode, got $($first.shell_mode)" "summarized cargo resolution with shell-aware metadata" } Invoke-Check -Name 'portping:loopback-http' -Script { $port = Get-FreeTcpPort $server = Start-LoopbackHttpServer -Port $port try { $target = "http://127.0.0.1:$port/health" $results = $target | & $portping --method GET --expect-status 200 --json | ConvertFrom-Json $probe = @($results)[0] Assert-Condition ($probe.ok) 'expected loopback HTTP probe to succeed' Assert-Condition ($probe.status_code -eq 200) "expected HTTP 200, got $($probe.status_code)" "probed $target successfully in $($probe.total_ms) ms from piped target input" } finally { Stop-LoopbackHttpServer -Server $server } } Invoke-Check -Name 'portunlock:who-and-free' -Script { $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ("portunlock-check-" + [System.Guid]::NewGuid()) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null $listener = $null try { $port = Get-FreeTcpPort $listenerScript = Join-Path $tempDir 'listen.ps1' Set-Content -LiteralPath $listenerScript -Encoding utf8NoBOM -Value @' param([int]$Port) $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, $Port) $listener.Start() try { Start-Sleep -Seconds 30 } finally { $listener.Stop() } '@ $listener = Start-Process -FilePath pwsh -ArgumentList @('-NoProfile', '-File', $listenerScript, $port) -PassThru -WindowStyle Hidden Wait-Until -Description "TCP listener on port $port" -TimeoutMilliseconds 3000 -Probe { Test-TcpPortListening -Port $port } $who = & $portunlock who --json --protocol tcp $port | ConvertFrom-Json $free = & $portunlock free --json --force --protocol tcp $port | ConvertFrom-Json $whoResult = @($who)[0] $freeResult = @($free)[0] Assert-Condition ($whoResult.port -eq $port) "expected who result for port $port, got $($whoResult.port)" Assert-Condition (@($whoResult.initial_owners).Count -ge 1) 'expected portunlock who to surface at least one owner' Assert-Condition ($freeResult.ok) 'expected portunlock free --force to succeed' Assert-Condition (@($freeResult.final_owners).Count -eq 0) 'expected portunlock free to leave no remaining owners' "identified and freed a loopback TCP owner on port $port" } finally { if ($null -ne $listener -and -not $listener.HasExited) { Stop-Process -Id $listener.Id -Force -ErrorAction SilentlyContinue } Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'msudo:status-json-stable-fields' -Script { $status = & $msudo status --json | ConvertFrom-Json $propertyNames = @($status.PSObject.Properties.Name) $stableFields = @('ok', 'host', 'supports_runas', 'is_elevated', 'session_id', 'active_session_id', 'can_current_user') $shellPresets = @($status.shells | ForEach-Object { [string]$_.preset }) Assert-Condition ($propertyNames.Count -ge 4) "expected msudo status to expose multiple stable fields, got $($propertyNames.Count)" foreach ($stableField in $stableFields) { Assert-Condition ($propertyNames -contains $stableField) "expected msudo status JSON to expose stable field $stableField" } Assert-Condition ($status.ok -is [bool]) "expected msudo status ok to be boolean, got $($status.ok.GetType().FullName)" Assert-Condition ($status.is_elevated -is [bool]) "expected msudo status is_elevated to be boolean, got $($status.is_elevated.GetType().FullName)" Assert-Condition ($status.supports_runas -is [bool]) "expected msudo status supports_runas to be boolean, got $($status.supports_runas.GetType().FullName)" Assert-Condition ($status.can_current_user -is [bool]) "expected msudo status can_current_user to be boolean, got $($status.can_current_user.GetType().FullName)" Assert-Condition (-not [string]::IsNullOrWhiteSpace([string]$status.host)) 'expected msudo status host to be a non-empty string' Assert-Condition ($shellPresets -contains 'powershell') "expected msudo status to expose the CLI shell preset name 'powershell', got: $($shellPresets -join ', ')" Assert-Condition ($shellPresets -contains 'git-bash') "expected msudo status to expose the CLI shell preset name 'git-bash', got: $($shellPresets -join ', ')" "reported stable msudo discovery fields ok=$($status.ok) host=$($status.host) supports_runas=$($status.supports_runas) is_elevated=$($status.is_elevated) session=$($status.session_id) active_session=$($status.active_session_id) without launching a privileged child process" } Invoke-Check -Name 'msudo:help-surfaces-same-console-honestly' -Script { $helpText = (& $msudo --help 2>&1 | Out-String) Assert-Condition ($LASTEXITCODE -eq 0) 'expected msudo --help to succeed' Assert-Condition ( $helpText -match '--same-console' ) "expected msudo help to expose the same-console flag, got: $helpText" Assert-Condition ( $helpText -match 'Reuse the current console' ) "expected msudo help to describe same-console foreground behavior, got: $helpText" 'reported msudo help with the explicit same-console surface' } Invoke-Check -Name 'msudo:current-user-native-cli' -Script { $tempDir = Join-Path $env:TEMP ("msudo-current-user-" + [guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null try { $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name $currentProcessPath = Join-Path $tempDir 'current-process.json' $currentUserPath = Join-Path $tempDir 'current-user.json' function New-EncodedPayload([string]$outputPath, [bool]$includeGroups) { $escapedPath = $outputPath.Replace("'", "''") $groupsExpr = if ($includeGroups) { "(whoami /groups | Out-String)" } else { '$null' } $script = @' $result = @{ user = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name session = (Get-Process -Id $PID).SessionId groups = __GROUPS__ } | ConvertTo-Json -Compress [System.IO.File]::WriteAllText('__OUTPUT_PATH__', $result) '@ $script = $script.Replace('__GROUPS__', $groupsExpr).Replace('__OUTPUT_PATH__', $escapedPath) [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($script)) } & $msudo --user current-process --wait -- powershell.exe -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $currentProcessPath -includeGroups:$false) Assert-Condition ($LASTEXITCODE -eq 0) "expected current-process launch to succeed, got exit code $LASTEXITCODE" & $msudo --user current-user --wait -- powershell.exe -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $currentUserPath -includeGroups:$false) Assert-Condition ($LASTEXITCODE -eq 0) "expected current-user launch to succeed, got exit code $LASTEXITCODE" $currentProcess = Get-Content $currentProcessPath -Raw | ConvertFrom-Json $currentUserResult = Get-Content $currentUserPath -Raw | ConvertFrom-Json Assert-Condition ($currentProcess.user -eq $currentUser) "expected current-process user $currentUser, got $($currentProcess.user)" Assert-Condition ($currentUserResult.user -eq $currentUser) "expected current-user user $currentUser, got $($currentUserResult.user)" "verified native current-process/current-user identities" } finally { Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'msudo:admin-system-ti-current-session' -Script { $tempDir = Join-Path $env:TEMP ("msudo-ecosystem-" + [guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null try { $currentSession = (Get-Process -Id $PID).SessionId $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name $adminPath = Join-Path $tempDir 'admin.json' $systemPath = Join-Path $tempDir 'system.json' $tiPath = Join-Path $tempDir 'ti.json' function New-EncodedPayload([string]$outputPath, [bool]$includeGroups) { $escapedPath = $outputPath.Replace("'", "''") $groupsExpr = if ($includeGroups) { "(whoami /groups | Out-String)" } else { '$null' } $script = @' $result = @{ user = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name session = (Get-Process -Id $PID).SessionId groups = __GROUPS__ } | ConvertTo-Json -Compress [System.IO.File]::WriteAllText('__OUTPUT_PATH__', $result) '@ $script = $script.Replace('__GROUPS__', $groupsExpr).Replace('__OUTPUT_PATH__', $escapedPath) [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($script)) } & $msudo --user admin --wait -- powershell -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $adminPath -includeGroups:$false) Assert-Condition ($LASTEXITCODE -eq 0) "expected admin msudo one-shot to succeed, got exit code $LASTEXITCODE" & $msudo --user system --dangerous --wait -- powershell -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $systemPath -includeGroups:$true) Assert-Condition ($LASTEXITCODE -eq 0) "expected system msudo one-shot to succeed, got exit code $LASTEXITCODE" & $msudo --user trustedinstaller --dangerous --wait -- powershell -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $tiPath -includeGroups:$true) Assert-Condition ($LASTEXITCODE -eq 0) "expected trustedinstaller msudo one-shot to succeed, got exit code $LASTEXITCODE" $admin = Get-Content $adminPath -Raw | ConvertFrom-Json $system = Get-Content $systemPath -Raw | ConvertFrom-Json $ti = Get-Content $tiPath -Raw | ConvertFrom-Json Assert-Condition ($admin.session -eq $currentSession) "expected admin session $currentSession, got $($admin.session)" Assert-Condition ($system.session -eq $currentSession) "expected system session $currentSession, got $($system.session)" Assert-Condition ($ti.session -eq $currentSession) "expected trustedinstaller session $currentSession, got $($ti.session)" Assert-Condition ($admin.user -eq $currentUser) "expected admin user $currentUser, got $($admin.user)" Assert-Condition ($system.user -eq 'NT AUTHORITY\SYSTEM') "expected system user NT AUTHORITY\\SYSTEM, got $($system.user)" Assert-Condition ($ti.groups -match 'NT SERVICE\\TrustedInstaller') "expected trustedinstaller token groups to include TrustedInstaller SID, got: $($ti.groups)" "verified admin/system/trustedinstaller one-shot launches in session $currentSession with SYSTEM user and TrustedInstaller service SID evidence" } finally { Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'msudo:admin-integrity-and-privileges' -Script { $tempDir = Join-Path $env:TEMP ("msudo-shape-" + [guid]::NewGuid().ToString('N')) try { New-Item -ItemType Directory -Force -Path $tempDir | Out-Null $disableAllPath = Join-Path $tempDir 'disable-all.json' $enableAllPath = Join-Path $tempDir 'enable-all.json' $escapedDisableAllPath = $disableAllPath.Replace("'", "''") $disableAllPayload = @' $result = @{ groups = (whoami /groups | Out-String) privileges = (whoami /priv | Out-String) } | ConvertTo-Json -Compress [System.IO.File]::WriteAllText('__OUTPUT_PATH__', $result) '@ $disableAllPayload = $disableAllPayload.Replace('__OUTPUT_PATH__', $escapedDisableAllPath) $disableAllEncoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($disableAllPayload)) & $msudo --user admin --wait --integrity medium --privileges disable-all -- powershell.exe -NoProfile -EncodedCommand $disableAllEncoded Assert-Condition ($LASTEXITCODE -eq 0) "expected admin integrity/privilege shaping launch to succeed, got exit code $LASTEXITCODE" Assert-Condition (Test-Path -LiteralPath $disableAllPath) "expected admin integrity/privilege shaping launch to write $disableAllPath" $disableAll = Get-Content $disableAllPath -Raw | ConvertFrom-Json Assert-Condition ($disableAll.groups -match 'S-1-16-8192') "expected shaped admin token to include medium integrity SID S-1-16-8192, got: $($disableAll.groups)" Assert-Condition ($disableAll.privileges -notmatch '(?m)(Enabled|已启用)\s*$') "expected shaped admin token privileges to be fully disabled, got: $($disableAll.privileges)" $escapedEnableAllPath = $enableAllPath.Replace("'", "''") $enableAllPayload = @' $result = @{ privileges = (whoami /priv | Out-String) } | ConvertTo-Json -Compress [System.IO.File]::WriteAllText('__OUTPUT_PATH__', $result) '@ $enableAllPayload = $enableAllPayload.Replace('__OUTPUT_PATH__', $escapedEnableAllPath) $enableAllEncoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($enableAllPayload)) & $msudo --user admin --wait --privileges enable-all -- powershell.exe -NoProfile -EncodedCommand $enableAllEncoded Assert-Condition ($LASTEXITCODE -eq 0) "expected admin enable-all privilege launch to succeed, got exit code $LASTEXITCODE" Assert-Condition (Test-Path -LiteralPath $enableAllPath) "expected admin enable-all privilege launch to write $enableAllPath" $enableAll = Get-Content $enableAllPath -Raw | ConvertFrom-Json Assert-Condition ($enableAll.privileges -match '(?m)(Enabled|已启用)\s*$') "expected enable-all privilege shaping to leave at least one enabled privilege, got: $($enableAll.privileges)" 'verified admin token shaping for medium integrity plus real enable-all and disable-all privilege modes' } finally { Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'msudo:shell-wrapped-system-and-ti' -Script { $status = & $msudo status --json | ConvertFrom-Json $availableShells = @{} foreach ($shell in @($status.shells)) { $availableShells[[string]$shell.preset] = [bool]$shell.available } $tempDir = Join-Path $env:TEMP ("msudo-shells-" + [guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null function New-EncodedPayload([string]$outputPath, [bool]$includeGroups) { $escapedPath = $outputPath.Replace("'", "''") $groupsExpr = if ($includeGroups) { "(whoami /groups | Out-String)" } else { '$null' } $script = @' $result = @{ user = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name session = (Get-Process -Id $PID).SessionId groups = __GROUPS__ } | ConvertTo-Json -Compress [System.IO.File]::WriteAllText('__OUTPUT_PATH__', $result) '@ $script = $script.Replace('__GROUPS__', $groupsExpr).Replace('__OUTPUT_PATH__', $escapedPath) [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($script)) } $systemCases = @( @{ preset = 'cmd' } @{ preset = 'powershell' } @{ preset = 'pwsh' } @{ preset = 'git-bash' } ) $verified = [System.Collections.Generic.List[string]]::new() try { foreach ($case in $systemCases) { if (-not $availableShells.ContainsKey($case.preset) -or -not $availableShells[$case.preset]) { continue } $outputPath = Join-Path $tempDir ("system-" + $case.preset + '.json') $argv = @( '--user', 'system', '--dangerous', '--wait', '--shell', $case.preset, '--', 'powershell.exe', '-NoProfile', '-EncodedCommand', (New-EncodedPayload -outputPath $outputPath -includeGroups:$true) ) $output = (& $msudo @argv 2>&1 | Out-String) $exitCode = $LASTEXITCODE Assert-Condition ($exitCode -eq 0) "expected system shell-wrapped launch via $($case.preset) to succeed, got exit code $exitCode with output: $output" Assert-Condition (Test-Path -LiteralPath $outputPath) "expected system shell-wrapped launch via $($case.preset) to write $outputPath" $result = Get-Content $outputPath -Raw | ConvertFrom-Json Assert-Condition ($result.user -eq 'NT AUTHORITY\SYSTEM') "expected system shell-wrapped launch via $($case.preset) to run as SYSTEM, got $($result.user)" [void]$verified.Add($case.preset) } Assert-Condition ($verified.Count -ge 3) "expected to verify at least 3 available system shell presets, got $($verified.Count): $($verified -join ', ')" $tiPreset = @('powershell', 'pwsh', 'cmd', 'git-bash') | Where-Object { $availableShells.ContainsKey($_) -and $availableShells[$_] } | Select-Object -First 1 Assert-Condition ($null -ne $tiPreset) 'expected at least one available shell preset to verify trustedinstaller shell wrapping' $tiPath = Join-Path $tempDir ("trustedinstaller-" + $tiPreset + '.json') $tiArgv = @( '--user', 'trustedinstaller', '--dangerous', '--wait', '--shell', $tiPreset, '--', 'powershell.exe', '-NoProfile', '-EncodedCommand', (New-EncodedPayload -outputPath $tiPath -includeGroups:$true) ) $tiOutput = (& $msudo @tiArgv 2>&1 | Out-String) $tiExitCode = $LASTEXITCODE Assert-Condition ($tiExitCode -eq 0) "expected trustedinstaller shell-wrapped launch via $tiPreset to succeed, got exit code $tiExitCode with output: $tiOutput" Assert-Condition (Test-Path -LiteralPath $tiPath) "expected trustedinstaller shell-wrapped launch via $tiPreset to write $tiPath" $tiResult = Get-Content $tiPath -Raw | ConvertFrom-Json Assert-Condition ($tiResult.user -eq 'NT AUTHORITY\SYSTEM') "expected trustedinstaller shell-wrapped launch via $tiPreset to report SYSTEM user, got $($tiResult.user)" Assert-Condition ($tiResult.groups -match 'NT SERVICE\\TrustedInstaller') "expected trustedinstaller shell-wrapped launch via $tiPreset to include TrustedInstaller group evidence, got: $($tiResult.groups)" "verified shell-wrapped system launches through $($verified -join ', ') and trustedinstaller group evidence through $tiPreset" } finally { Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'msudo:same-console-system-and-ti' -Script { $status = & $msudo status --json | ConvertFrom-Json $availableShells = @{ } foreach ($shell in @($status.shells)) { $availableShells[[string]$shell.preset] = [bool]$shell.available } $tempDir = Join-Path $env:TEMP ("msudo-same-console-" + [guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null function New-EncodedPayload([string]$outputPath, [bool]$includeGroups) { $escapedPath = $outputPath.Replace("'", "''") $groupsExpr = if ($includeGroups) { "(whoami /groups | Out-String)" } else { '$null' } $script = @' $result = @{ user = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name session = (Get-Process -Id $PID).SessionId groups = __GROUPS__ } | ConvertTo-Json -Compress [System.IO.File]::WriteAllText('__OUTPUT_PATH__', $result) '@ $script = $script.Replace('__GROUPS__', $groupsExpr).Replace('__OUTPUT_PATH__', $escapedPath) [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($script)) } try { $systemPath = Join-Path $tempDir 'system-direct.json' & $msudo --same-console --user system --dangerous -- powershell.exe -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $systemPath -includeGroups:$true) Assert-Condition ($LASTEXITCODE -eq 0) "expected same-console system launch to succeed, got exit code $LASTEXITCODE" Assert-Condition (Test-Path -LiteralPath $systemPath) "expected same-console system launch to write $systemPath" $system = Get-Content $systemPath -Raw | ConvertFrom-Json Assert-Condition ($system.user -eq 'NT AUTHORITY\SYSTEM') "expected same-console system launch to run as SYSTEM, got $($system.user)" $tiPath = Join-Path $tempDir 'trustedinstaller-direct.json' & $msudo --same-console --user trustedinstaller --dangerous -- powershell.exe -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $tiPath -includeGroups:$true) Assert-Condition ($LASTEXITCODE -eq 0) "expected same-console trustedinstaller launch to succeed, got exit code $LASTEXITCODE" Assert-Condition (Test-Path -LiteralPath $tiPath) "expected same-console trustedinstaller launch to write $tiPath" $ti = Get-Content $tiPath -Raw | ConvertFrom-Json Assert-Condition ($ti.groups -match 'NT SERVICE\\TrustedInstaller') "expected same-console trustedinstaller launch to include TrustedInstaller group evidence, got: $($ti.groups)" $sameConsolePreset = @('powershell', 'pwsh', 'cmd', 'git-bash') | Where-Object { $availableShells.ContainsKey($_) -and $availableShells[$_] } | Select-Object -First 1 Assert-Condition ($null -ne $sameConsolePreset) 'expected at least one available preset for same-console shell wrapping' $wrappedPath = Join-Path $tempDir ("system-wrapped-" + $sameConsolePreset + '.json') & $msudo --same-console --user system --dangerous --shell $sameConsolePreset -- powershell.exe -NoProfile -EncodedCommand (New-EncodedPayload -outputPath $wrappedPath -includeGroups:$true) Assert-Condition ($LASTEXITCODE -eq 0) "expected same-console system shell wrapping via $sameConsolePreset to succeed, got exit code $LASTEXITCODE" Assert-Condition (Test-Path -LiteralPath $wrappedPath) "expected same-console system shell wrapping via $sameConsolePreset to write $wrappedPath" $wrapped = Get-Content $wrappedPath -Raw | ConvertFrom-Json Assert-Condition ($wrapped.user -eq 'NT AUTHORITY\SYSTEM') "expected same-console system shell wrapping via $sameConsolePreset to run as SYSTEM, got $($wrapped.user)" "verified same-console direct SYSTEM/TI launches and shell wrapping through $sameConsolePreset" } finally { Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'msudo:privileged-pipeline-passthrough' -Script { $systemOutput = (& $msudo --same-console --user system --dangerous --wait -- cmd /d /c whoami | Out-String) $systemExit = $LASTEXITCODE Assert-Condition ($systemExit -eq 0) "expected piped same-console SYSTEM launch to exit 0, got $systemExit" Assert-Condition ($systemOutput -match 'nt authority\\system') "expected piped same-console SYSTEM stdout to include identity, got: $systemOutput" $tiOutput = (& $msudo --same-console --user trustedinstaller --dangerous --wait -- cmd /d /c whoami /groups | Out-String) $tiExit = $LASTEXITCODE Assert-Condition ($tiExit -eq 0) "expected piped same-console TrustedInstaller launch to exit 0, got $tiExit" Assert-Condition ($tiOutput -match 'NT SERVICE\\TrustedInstaller') "expected piped same-console TrustedInstaller stdout to include service SID, got: $tiOutput" $stderrOutput = (& $msudo --same-console --user system --dangerous --wait -- cmd /d /c 'echo msudo-stderr 1>&2' 2>&1 | Out-String) $stderrExit = $LASTEXITCODE Assert-Condition ($stderrExit -eq 0) "expected piped same-console SYSTEM stderr launch to exit 0, got $stderrExit" Assert-Condition ($stderrOutput -match 'msudo-stderr') "expected piped same-console SYSTEM stderr to be replayed, got: $stderrOutput" 'verified privileged stdout/stderr passthrough through non-elevated relay pipelines' } Invoke-Check -Name 'asmtype:managed-json' -Script { $types = & $asmtype (Join-Path $fixtureRoot 'managed\bin\GameAssembly.dll') --with-member-match 'StartProject|QueueVehicle' --json | ConvertFrom-Json Assert-Condition (@($types).Count -ge 2) "expected at least 2 managed types, got $(@($types).Count)" Assert-Condition ((@($types) | Where-Object full_name -eq 'Game.UI.Windows.Windows.SpaceCraftConstructionWindow').Count -ge 1) 'expected SpaceCraftConstructionWindow in asmtype output' Assert-Condition ((@($types) | Where-Object full_name -eq 'Game.UI.Windows.Windows.SpaceCraftProjectWindow').Count -ge 1) 'expected SpaceCraftProjectWindow in asmtype output' "listed $(@($types).Count) matching managed types" } Invoke-Check -Name 'asmmember:jsonl-types' -Script { $members = & $asmtype (Join-Path $fixtureRoot 'managed\bin\GameAssembly.dll') --intent unity-spacecraft-workflow --json | & $asmmember --assembly (Join-Path $fixtureRoot 'managed\bin\GameAssembly.dll') --input-format jsonl --intent unity-spacecraft-workflow --json | ConvertFrom-Json Assert-Condition ((@($members) | Where-Object kind -eq 'method' | Where-Object name -eq 'StartProject').Count -ge 1) 'expected StartProject method in asmmember output' Assert-Condition ((@($members) | Where-Object kind -eq 'method' | Where-Object name -eq 'FinishProject').Count -ge 1) 'expected FinishProject method in asmmember output' Assert-Condition ((@($members) | Where-Object kind -eq 'property' | Where-Object name -eq 'ProjectName').Count -ge 1) 'expected ProjectName property in asmmember output' "listed $(@($members).Count) managed members from JSONL type handoff" } Invoke-Check -Name 'asmref:resolved-reference' -Script { $report = & $asmref (Join-Path $fixtureRoot 'managed\bin\GameAssembly.dll') --resolve-dir (Join-Path $fixtureRoot 'managed\bin') --json | ConvertFrom-Json $fixtureSupport = @($report.references) | Where-Object name -eq 'FixtureSupport' | Select-Object -First 1 Assert-Condition ($null -ne $fixtureSupport) 'expected FixtureSupport reference in asmref output' Assert-Condition ($fixtureSupport.resolved) 'expected FixtureSupport reference to resolve' "resolved managed references for $($report.assembly.assembly_name)" } Invoke-Check -Name 'binmeta:fd-path-stream' -Script { $reports = & $fdPath '-a' '--max-depth' '1' '^jsonlgrep\.exe$' $script:BinaryRoot | & $binmeta --input-format lines --json | ConvertFrom-Json $report = @($reports)[0] Assert-Condition (@($reports).Count -eq 1) "expected one binmeta report, got $(@($reports).Count)" Assert-Condition ($report.path.EndsWith('jsonlgrep.exe')) "expected binmeta path to end with jsonlgrep.exe, got $($report.path)" "inspected $($report.path) from fd path output" } Invoke-Check -Name 'fileprobe:fd-path-stream' -Script { $reports = & $fdPath '-a' '^sample\.rs$' (Join-Path $fixtureRoot 'reading') | & $fileprobe --input-format lines --json | ConvertFrom-Json $report = @($reports)[0] Assert-Condition (@($reports).Count -eq 1) "expected one fileprobe report, got $(@($reports).Count)" Assert-Condition ($report.language_hint -eq 'rust') "expected fileprobe language hint rust, got $($report.language_hint)" "classified $($report.path) as $($report.family) with language hint $($report.language_hint)" } Invoke-Check -Name 'outline:recent-path-chain' -Script { $reports = & $recent --root $fixtureRoot --ext rs --limit 1 --json | ConvertFrom-Json | Select-Object -ExpandProperty path | & $outline --input-format lines --json | ConvertFrom-Json $report = @($reports)[0] Assert-Condition (@($reports).Count -eq 1) "expected one outline report, got $(@($reports).Count)" Assert-Condition (@($report.items).Count -ge 3) "expected outline to report at least 3 items, got $(@($report.items).Count)" "outlined $($report.path) with $(@($report.items).Count) structural items" } Invoke-Check -Name 'codeshape:polyglot-json' -Script { $report = & $codeshape (Join-Path $fixtureRoot 'polyglot\repo') --json | ConvertFrom-Json $appTs = @($report.files) | Where-Object path -like '*web\app.ts' | Select-Object -First 1 Assert-Condition (@($report.files).Count -ge 6) "expected at least 6 indexed files, got $(@($report.files).Count)" Assert-Condition ($null -ne $appTs) 'expected codeshape to include web\app.ts' Assert-Condition ((@($appTs.items) | Where-Object name -eq 'helper').Count -ge 1) 'expected codeshape to capture helper in app.ts' "indexed $(@($report.files).Count) files and surfaced AST-backed declarations" } Invoke-Check -Name 'snip:stdin-text' -Script { $snippet = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'reading\sample.rs') | & $snip --around helper --context 0 Assert-Condition (($snippet -join "`n") -match 'helper') 'expected snip output to include helper' "extracted helper-focused context from piped text" } Invoke-Check -Name 'defsnip:polyglot-json' -Script { $symbolMatches = & $defsnip helper (Join-Path $fixtureRoot 'polyglot\repo') --json | ConvertFrom-Json Assert-Condition (@($symbolMatches).Count -ge 4) "expected at least 4 helper definitions, got $(@($symbolMatches).Count)" Assert-Condition ((@($symbolMatches) | Where-Object path -like '*web\app.ts').Count -ge 1) 'expected defsnip to include the TypeScript helper' Assert-Condition ((@($symbolMatches) | Where-Object text -match 'helper').Count -ge 4) 'expected emitted definition text to contain helper bodies' "extracted $(@($symbolMatches).Count) full definition block(s) by exact symbol name" } Invoke-Check -Name 'chunkcat:recent-path-chain' -Script { $report = & $recent --root $fixtureRoot --ext rs --limit 1 --json | ConvertFrom-Json | Select-Object -ExpandProperty path | & $chunkcat --input-format lines --max-lines 8 --chunk 0 --json | ConvertFrom-Json Assert-Condition ($report.chunk_count -ge 1) "expected at least one chunk, got $($report.chunk_count)" Assert-Condition ($null -ne $report.selected_chunk) 'expected chunkcat to materialize the selected chunk' "selected chunk 0 from $($report.path) with $($report.selected_chunk.line_count) lines" } Invoke-Check -Name 'hitsnip:rg-context' -Script { $snippets = & $rgPath '-n' '-H' 'Mode::' (Join-Path $fixtureRoot 'reading\sample.rs') | & $hitsnip --context 1 --json | ConvertFrom-Json Assert-Condition (@($snippets).Count -ge 1) 'expected at least one hitsnip snippet' Assert-Condition ((@($snippets)[0].path) -like '*sample.rs') "expected hitsnip path to end with sample.rs, got $((@($snippets)[0].path))" "expanded rg hits into $(@($snippets).Count) merged snippet(s)" } Invoke-Check -Name 'diagpick:stdin-log' -Script { $diagnostics = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'diag\rust-errors.txt') | & $diagpick --with-source --json | ConvertFrom-Json $diagnostic = @($diagnostics)[0] Assert-Condition (@($diagnostics).Count -ge 1) 'expected at least one diagnostic' Assert-Condition ($diagnostic.severity -eq 'error') "expected first diagnostic severity error, got $($diagnostic.severity)" "picked $(@($diagnostics).Count) diagnostic(s) with source context" } Invoke-Check -Name 'logshape:stdin-log' -Script { $report = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'logs\repetitive.log') | & $logshape --json | ConvertFrom-Json Assert-Condition ($report.summary.group_count -ge 2) "expected at least 2 grouped patterns, got $($report.summary.group_count)" Assert-Condition ((@($report.groups)[0].count) -ge 2) "expected top log group count >= 2, got $((@($report.groups)[0].count))" "grouped repetitive logs into $($report.summary.group_count) templates" } Invoke-Check -Name 'stringscan:fd-path-stream' -Script { $reports = & $fdPath '-a' '^stringscan-sample\.bin$' (Join-Path $fixtureRoot 'binaries') | & $stringscan --input-format lines --json | ConvertFrom-Json $report = @($reports)[0] Assert-Condition (@($reports).Count -eq 1) "expected one stringscan report, got $(@($reports).Count)" Assert-Condition ((@($report.categories) -contains 'url')) 'expected stringscan categories to include url' Assert-Condition ((@($report.categories) -contains 'bepinex')) 'expected stringscan categories to include bepinex' "extracted $($report.match_count) classified strings from $($report.path)" } Invoke-Check -Name 'toon:json-wrapper-and-jsonl' -Script { $wrapper = & $toon (Join-Path $fixtureRoot 'toon\config.json') --json | ConvertFrom-Json $text = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'toon\records.jsonl') | & $toon Assert-Condition ($wrapper.format -eq 'toon') "expected toon JSON wrapper format to be toon, got $($wrapper.format)" Assert-Condition (($text -join "`n") -match 'event') 'expected TOON text converted from JSONL to include the event field' "rendered a TOON JSON wrapper and converted JSONL stdin to TOON text" } Invoke-Check -Name 'csvshape:stdin-tsv' -Script { $summary = & $batPath '--style=plain' '--paging=never' (Join-Path $fixtureRoot 'csvshape\sample.tsv') | & $csvshape --delimiter tab --json | ConvertFrom-Json Assert-Condition ($summary.delimiter -eq 'tab') "expected detected delimiter tab, got $($summary.delimiter)" Assert-Condition ($summary.column_count -eq 4) "expected 4 columns, got $($summary.column_count)" Assert-Condition ((@($summary.columns) | Where-Object name -eq 'score').Count -eq 1) 'expected score column in csvshape output' "summarized TSV schema with $($summary.column_count) columns and delimiter $($summary.delimiter)" } Invoke-Check -Name 'sqliteshape:fixture-db' -Script { $summary = & $sqliteshape (Join-Path $fixtureRoot 'sqliteshape\sample.db') --include-indexes --json | ConvertFrom-Json Assert-Condition ((@($summary.tables) | Where-Object name -eq 'users').Count -eq 1) 'expected users table in sqliteshape output' Assert-Condition ((@($summary.tables) | Where-Object name -eq 'events').Count -eq 1) 'expected events table in sqliteshape output' Assert-Condition ((@($summary.tables)[0].columns).Count -ge 2) 'expected at least two columns in first table summary' "inspected SQLite fixture with $(@($summary.tables).Count) tables" } Invoke-Check -Name 'sqlshape:sqlite-fixture-db' -Script { $summary = & $sqlshape --engine sqlite --url (Join-Path $fixtureRoot 'sqliteshape\sample.db') --json | ConvertFrom-Json Assert-Condition ($summary.engine -eq 'sqlite') "expected sqlite engine, got $($summary.engine)" Assert-Condition (@($summary.schemas | Where-Object { $_ -eq 'main' }).Count -eq 1) 'expected main schema in sqlshape output' Assert-Condition (@($summary.tables | Where-Object name -eq 'users').Count -eq 1) 'expected users table in sqlshape output' Assert-Condition (@($summary.tables | Where-Object name -eq 'events').Count -eq 1) 'expected events table in sqlshape output' "inspected normalized SQLite fixture with $(@($summary.tables).Count) tables" } Invoke-Check -Name 'envdiff:cmd-wrapper-json' -Script { $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ("envdiff-check-" + [System.Guid]::NewGuid()) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null try { $scriptPath = Join-Path $tempDir 'mutate-env.cmd' Set-Content -LiteralPath $scriptPath -Encoding ascii -Value @' @echo off set TOOLBOX_STAGE=after set TOOLBOX_REMOVE= set PATH=%PATH%;C:\MercuryToolbox\TestBin '@ $report = & $envdiff run --json --shell cmd -- $scriptPath | ConvertFrom-Json Assert-Condition ((@($report.added) | Where-Object name -eq 'TOOLBOX_STAGE').Count -eq 1) 'expected TOOLBOX_STAGE in added variables' Assert-Condition ((@($report.path_like_changes) | Where-Object name -eq 'Path' | Where-Object { @($_.added_segments) -contains 'C:\MercuryToolbox\TestBin' }).Count -eq 1) 'expected PATH segment delta in envdiff output' "captured environment mutations and PATH segment deltas from cmd wrapper" } finally { Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'proctree:run-json' -Script { $report = & $proctree run --json -- pwsh -NoProfile -Command "Start-Process -FilePath pwsh -ArgumentList '-NoProfile','-Command','Start-Sleep -Seconds 2' -WindowStyle Hidden; Start-Sleep -Milliseconds 400" | ConvertFrom-Json Assert-Condition ($report.root_pid -gt 0) "expected rooted report pid, got $($report.root_pid)" Assert-Condition (@($report.nodes).Count -ge 1) 'expected at least one process node from proctree run' Assert-Condition ((@($report.nodes) | Where-Object pid -eq $report.root_pid).Count -eq 1) 'expected proctree report to include the root node' "captured process tree with $(@($report.nodes).Count) node(s)" } Invoke-Check -Name 'sysshape:shell-json' -Script { $report = & $sysshape --json --env none --group shell | ConvertFrom-Json Assert-Condition (-not [string]::IsNullOrWhiteSpace($report.system.architecture)) 'expected sysshape to report a machine architecture' Assert-Condition (-not [string]::IsNullOrWhiteSpace($report.system.default_shell)) 'expected sysshape to report a default shell hint' Assert-Condition (@($report.tools).Count -ge 1) 'expected sysshape to detect at least one shell tool' Assert-Condition ( ((@($report.tools) | Where-Object name -eq 'pwsh').Count -ge 1) -or ((@($report.tools) | Where-Object name -eq 'powershell').Count -ge 1) ) 'expected sysshape shell inventory to include pwsh or powershell' Assert-Condition ((@($report.tools) | Where-Object probe_status -eq 'ok').Count -ge 1) 'expected sysshape shell inventory to report probe_status' "captured shell inventory with $(@($report.tools).Count) detected tool(s)" } Invoke-Check -Name 'unlock:who-and-delete' -Script { $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ("unlock-check-" + [System.Guid]::NewGuid()) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null $locker = $null try { $lockedPath = Join-Path $tempDir 'locked.txt' $lockerScript = Join-Path $tempDir 'locker.ps1' Set-Content -LiteralPath $lockedPath -Encoding utf8NoBOM -Value 'busy' Set-Content -LiteralPath $lockerScript -Encoding utf8NoBOM -Value @' $path = '__LOCKED_PATH__' $stream = [System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) try { Start-Sleep -Seconds 30 } finally { $stream.Dispose() } '@.Replace('__LOCKED_PATH__', $lockedPath.Replace("'", "''")) $locker = Start-Process -FilePath pwsh -ArgumentList @('-NoProfile', '-File', $lockerScript) -PassThru -WindowStyle Hidden Wait-Until -Description "exclusive lock on $lockedPath" -TimeoutMilliseconds 3000 -Probe { Test-ExclusiveFileLock -Path $lockedPath } $who = & $unlock who --json $lockedPath | ConvertFrom-Json $delete = & $unlock delete --json --force $lockedPath | ConvertFrom-Json $whoResult = @($who.results)[0] $deleteResult = @($delete.results)[0] Assert-Condition ($who.summary.results -eq 1) "expected single unlock who result, got $($who.summary.results)" Assert-Condition (@($whoResult.initial_blockers).Count -ge 1 -or @($whoResult.final_blockers).Count -ge 1) 'expected unlock who to surface at least one blocker' Assert-Condition ($delete.summary.results -eq 1) "expected single unlock delete result, got $($delete.summary.results)" Assert-Condition ($deleteResult.ok) 'expected unlock delete --force to succeed' Assert-Condition (-not (Test-Path -LiteralPath $lockedPath)) 'expected locked file to be deleted' "identified blockers and deleted a locked file with staged escalation" } finally { if ($null -ne $locker -and -not $locker.HasExited) { Stop-Process -Id $locker.Id -Force -ErrorAction SilentlyContinue } Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue } } Invoke-Check -Name 'toolbox:valid-jsonl-path-stream-smokes' -Script { 'covered by per-command path-stream:* JSONL path-record checks below' } function Invoke-JsonlPathRecordSmoke { param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$InputPath, [string[]]$ArgumentList = @(), [int[]]$AcceptExitCodes = @(0) ) Assert-Condition (Test-Path -LiteralPath $InputPath) "expected JSONL path-record smoke input to exist for ${Name}: $InputPath" $commandPath = Get-ToolboxBinaryPath -Name $Name $jsonl = @{ path = $InputPath } | ConvertTo-Json -Compress $output = $jsonl | & $commandPath @ArgumentList 2>&1 $exitCode = $LASTEXITCODE $text = (($output | ForEach-Object { [string]$_ }) -join "`n") Assert-Condition (@($AcceptExitCodes) -contains $exitCode) "expected ${Name} JSONL path-record exit code in $($AcceptExitCodes -join ', '), got $exitCode with output: $text" Assert-Condition (-not [string]::IsNullOrWhiteSpace($text)) "expected ${Name} JSONL path-record smoke to emit output" Assert-Condition ($text -notmatch "(?i)thread '.*' panicked|stack backtrace|RUST_BACKTRACE|panic at") "expected ${Name} JSONL path-record smoke to avoid panic/backtrace text, got: $text" "verified ${Name} JSONL path-record stdin using $InputPath" } $sampleRust = Join-Path $fixtureRoot 'reading\sample.rs' $readingRoot = Join-Path $fixtureRoot 'reading' $polyglotRoot = Join-Path $fixtureRoot 'polyglot\repo' $managedBinRoot = Join-Path $fixtureRoot 'managed\bin' $managedAssembly = Join-Path $managedBinRoot 'GameAssembly.dll' $csvSample = Join-Path $fixtureRoot 'csvshape\sample.csv' $sqliteSample = Join-Path $fixtureRoot 'sqliteshape\sample.db' $stringSample = Join-Path $fixtureRoot 'binaries\stringscan-sample.bin' $peSample = Join-Path $script:BinaryRoot 'portping.exe' $kernel32 = Join-Path $env:WINDIR 'System32\kernel32.dll' $driverRoot = Join-Path $env:WINDIR 'System32\drivers' $driverSmokeSample = @( 'ndis.sys', 'disk.sys', 'afd.sys', 'tcpip.sys', 'afunix.sys' ) | ForEach-Object { Join-Path $driverRoot $_ } | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | Select-Object -First 1 if ([string]::IsNullOrWhiteSpace($driverSmokeSample) -and (Test-Path -LiteralPath $driverRoot -PathType Container)) { $driverSmokeSample = Get-ChildItem -LiteralPath $driverRoot -Filter '*.sys' -File | Sort-Object Name | Select-Object -First 1 -ExpandProperty FullName } Assert-Condition (-not [string]::IsNullOrWhiteSpace($driverSmokeSample)) "expected at least one system driver sample under $driverRoot for path-stream smoke coverage" $pathStreamSmokes = @( @{ Name = 'asmflow'; Path = $managedAssembly; Args = @('--input-format', 'jsonl', '--json', 'find', '--match', 'StartProject') }, @{ Name = 'asmref'; Path = $managedAssembly; Args = @('--input-format', 'jsonl', '--resolve-dir', $managedBinRoot, '--json') }, @{ Name = 'asmtype'; Path = $managedAssembly; Args = @('--input-format', 'jsonl', '--match', 'SpaceCraft', '--json') }, @{ Name = 'binmeta'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'chunkcat'; Path = $sampleRust; Args = @('--input-format', 'jsonl', '--max-lines', '8', '--chunk', '0', '--json') }, @{ Name = 'codeshape'; Path = $polyglotRoot; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'csvshape'; Path = $csvSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'defsnip'; Path = $polyglotRoot; Args = @('helper', '--input-format', 'jsonl', '--json') }, @{ Name = 'mhash'; Path = $sampleRust; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'drvshape'; Path = $driverSmokeSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'fileprobe'; Path = $sampleRust; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'ioctlscan'; Path = $driverSmokeSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'llvmnm'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'llvmobjdump'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json', '--raw-output-limit', '65536') }, @{ Name = 'llvmreadobj'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'outline'; Path = $sampleRust; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'pecalls'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json', '--api', 'GetProcAddress'); AcceptExitCodes = @(0, 1) }, @{ Name = 'peexports'; Path = $kernel32; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'peimports'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'pesig'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json', '--min-confidence', 'low') }, @{ Name = 'pestrrefs'; Path = $peSample; Args = @('--input-format', 'jsonl', '--json', '--contains', 'json') }, @{ Name = 'recent'; Path = $readingRoot; Args = @('--input-format', 'jsonl', '--json', '--limit', '1') }, @{ Name = 'refs'; Path = $polyglotRoot; Args = @('helper', '--input-format', 'jsonl', '--json') }, @{ Name = 'sqliteshape'; Path = $sqliteSample; Args = @('--input-format', 'jsonl', '--include-indexes', '--json') }, @{ Name = 'stringscan'; Path = $stringSample; Args = @('--input-format', 'jsonl', '--json') }, @{ Name = 'unityasset'; Path = $readingRoot; Args = @('--input-format', 'jsonl', '--json', 'index', '--allow-empty') }, @{ Name = 'unlock'; Path = $sampleRust; Args = @('--input-format', 'jsonl', '--json', 'who') } ) foreach ($smoke in $pathStreamSmokes) { Invoke-Check -Name "path-stream:$($smoke.Name):jsonl-path-record" -Script { $acceptExitCodes = if ($smoke.ContainsKey('AcceptExitCodes')) { $smoke.AcceptExitCodes } else { @(0) } Invoke-JsonlPathRecordSmoke -Name $smoke.Name -InputPath $smoke.Path -ArgumentList $smoke.Args -AcceptExitCodes $acceptExitCodes }.GetNewClosure() } Invoke-Check -Name 'installer:temp-root-roundtrip' -Script { $installRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolbox-" + [System.Guid]::NewGuid()) $codexHome = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxCodex-" + [System.Guid]::NewGuid()) $activeBinDir = Join-Path $installRoot 'current\bin' try { & (Join-Path $PSScriptRoot 'install-toolbox.ps1') ` -Configuration $Configuration ` -InstallRoot $installRoot ` -CodexHome $codexHome ` -NoPathUpdate ` -SkipBuild if ($LASTEXITCODE -ne 0) { throw "install-toolbox.ps1 exited with $LASTEXITCODE" } foreach ($commandName in Get-ToolboxCommandNames) { $commandPath = Join-Path $activeBinDir "$commandName.exe" Assert-Condition (Test-Path -LiteralPath $commandPath) "expected installed binary not found: $commandPath" } Assert-Condition (Test-Path -LiteralPath (Join-Path $activeBinDir 'duckdb.dll')) 'expected installed DuckDB runtime' Assert-Condition ( Test-Path -LiteralPath (Join-Path $installRoot 'share\mercury-toolbox\docs\ai\mercury-toolbox-ai-prompt.md') ) 'expected installed AI prompt in share directory' Assert-Condition ( Test-Path -LiteralPath (Join-Path $installRoot 'share\mercury-toolbox\skills\mercury-toolbox\SKILL.md') ) 'expected installed shared skill copy' Assert-Condition ( Test-Path -LiteralPath (Join-Path $codexHome 'skills\mercury-toolbox\SKILL.md') ) 'expected installed Codex skill copy' Assert-Condition ( Test-Path -LiteralPath (Join-Path $codexHome 'skills\mercury-toolbox\references\command-catalog.md') ) 'expected installed Codex command catalog' & (Join-Path $PSScriptRoot 'uninstall-toolbox.ps1') -InstallRoot $installRoot -CodexHome $codexHome if ($LASTEXITCODE -ne 0) { throw "uninstall-toolbox.ps1 exited with $LASTEXITCODE" } Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $installRoot 'current'))) 'expected uninstall to remove the current install junction' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $installRoot 'versions'))) 'expected uninstall to remove staged versions' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $installRoot 'share\mercury-toolbox'))) 'expected uninstall to remove the share directory' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $codexHome 'skills\mercury-toolbox'))) 'expected uninstall to remove the Codex skill' "installed and removed $((Get-ToolboxCommandNames).Count) commands in a temp root" } finally { foreach ($path in @($installRoot, $codexHome)) { if (Test-Path -LiteralPath $path) { Remove-Item -LiteralPath $path -Recurse -Force } } } } Invoke-Check -Name 'installer:refuses-unmanaged-codex-skill' -Script { $installRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxGuard-" + [System.Guid]::NewGuid()) $codexHome = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxGuardCodex-" + [System.Guid]::NewGuid()) $skillRoot = Join-Path $codexHome 'skills\mercury-toolbox' $sentinel = Join-Path $skillRoot 'USER-SKILL.txt' try { New-Item -ItemType Directory -Force -Path $skillRoot | Out-Null Set-Content -LiteralPath $sentinel -Value 'user managed' -Encoding utf8NoBOM $result = Invoke-PwshFile -FilePath (Join-Path $PSScriptRoot 'install-toolbox.ps1') -ArgumentList @( '-Configuration', $Configuration, '-InstallRoot', $installRoot, '-CodexHome', $codexHome, '-NoPathUpdate', '-SkipBuild' ) Assert-Condition ($result.ExitCode -ne 0) 'expected workspace installer to refuse unmanaged Codex skill directory' Assert-Condition (Test-Path -LiteralPath $sentinel) 'expected unmanaged Codex skill sentinel to be preserved' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $skillRoot '.mercury-toolbox-owner.json'))) 'expected unmanaged skill to remain unmarked' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $installRoot 'current'))) 'expected direct installer to fail before activating an install' 'refused unmanaged direct-install Codex skill directory without overwriting it' } finally { foreach ($path in @($installRoot, $codexHome)) { if (Test-Path -LiteralPath $path) { Remove-Item -LiteralPath $path -Recurse -Force } } } } Invoke-Check -Name 'package:portable-roundtrip' -Script { $packageOutputRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxPkg-" + [System.Guid]::NewGuid()) $extractRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxExtract-" + [System.Guid]::NewGuid()) $installRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxPortable-" + [System.Guid]::NewGuid()) $codexHome = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxPortableCodex-" + [System.Guid]::NewGuid()) $activeBinDir = Join-Path $installRoot 'current\bin' try { if ($SkipPromptGeneration) { & (Join-Path $PSScriptRoot 'package-toolbox.ps1') ` -Configuration $Configuration ` -OutputRoot $packageOutputRoot ` -SkipBuild ` -SkipPromptGeneration } else { & (Join-Path $PSScriptRoot 'package-toolbox.ps1') ` -Configuration $Configuration ` -OutputRoot $packageOutputRoot ` -SkipBuild } if ($LASTEXITCODE -ne 0) { throw "package-toolbox.ps1 exited with $LASTEXITCODE" } $zip = @(Get-ChildItem -LiteralPath $packageOutputRoot -Filter '*.zip' -File) Assert-Condition ($zip.Count -eq 1) 'expected exactly one portable package archive' Expand-Archive -LiteralPath $zip[0].FullName -DestinationPath $extractRoot -Force $packageDirs = @(Get-ChildItem -LiteralPath $extractRoot -Directory) Assert-Condition ($packageDirs.Count -eq 1) 'expected extracted archive to contain one top-level package directory' $packageRoot = $packageDirs[0].FullName $installScript = Join-Path $packageRoot 'scripts\install-package-toolbox.ps1' $uninstallScript = Join-Path $packageRoot 'scripts\uninstall-package-toolbox.ps1' Assert-Condition (Test-Path -LiteralPath $installScript) "expected package install script at $installScript" Assert-Condition (Test-Path -LiteralPath $uninstallScript) "expected package uninstall script at $uninstallScript" Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'docs\ai\mercury-toolbox-ai-prompt.md')) 'expected packaged AI prompt' Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'skills\mercury-toolbox\SKILL.md')) 'expected packaged Codex skill' Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'skills\mercury-toolbox\references\command-catalog.md')) 'expected packaged command catalog' Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'mercury-toolbox-package.json')) 'expected package manifest' Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'SHA256SUMS.txt')) 'expected package checksums' Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'START-HERE.txt')) 'expected portable package quickstart' Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'LICENSE')) 'expected packaged license' Assert-Condition (Test-Path -LiteralPath (Join-Path $packageRoot 'bin\duckdb.dll')) 'expected packaged DuckDB runtime' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $packageRoot 'README.md'))) 'expected portable package to omit README.md' & $installScript -InstallRoot $installRoot -CodexHome $codexHome -NoPathUpdate if ($LASTEXITCODE -ne 0) { throw "install-package-toolbox.ps1 exited with $LASTEXITCODE" } foreach ($commandName in Get-ToolboxCommandNames) { $commandPath = Join-Path $activeBinDir "$commandName.exe" Assert-Condition (Test-Path -LiteralPath $commandPath) "expected packaged install binary not found: $commandPath" } Assert-Condition (Test-Path -LiteralPath (Join-Path $activeBinDir 'duckdb.dll')) 'expected packaged install DuckDB runtime' Assert-Condition ( Test-Path -LiteralPath (Join-Path $installRoot 'share\mercury-toolbox\docs\ai\mercury-toolbox-ai-prompt.md') ) 'expected installed AI prompt in portable share directory' Assert-Condition ( Test-Path -LiteralPath (Join-Path $installRoot 'share\mercury-toolbox\skills\mercury-toolbox\SKILL.md') ) 'expected installed shared skill in portable share directory' Assert-Condition ( -not (Test-Path -LiteralPath (Join-Path $installRoot 'share\mercury-toolbox\README.md')) ) 'expected portable share directory to omit README.md' Assert-Condition ( Test-Path -LiteralPath (Join-Path $codexHome 'skills\mercury-toolbox\SKILL.md') ) 'expected installed portable Codex skill' Assert-Condition ( Test-Path -LiteralPath (Join-Path $codexHome 'skills\mercury-toolbox\references\command-catalog.md') ) 'expected installed portable Codex command catalog' & $uninstallScript -InstallRoot $installRoot -CodexHome $codexHome if ($LASTEXITCODE -ne 0) { throw "uninstall-package-toolbox.ps1 exited with $LASTEXITCODE" } Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $installRoot 'current'))) 'expected portable uninstall to remove the current install junction' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $installRoot 'versions'))) 'expected portable uninstall to remove staged versions' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $installRoot 'share\mercury-toolbox'))) 'expected portable uninstall to remove the share directory' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $codexHome 'skills\mercury-toolbox'))) 'expected portable uninstall to remove the Codex skill' 'packaged, extracted, installed, and removed the portable toolbox bundle' } finally { foreach ($path in @($packageOutputRoot, $extractRoot, $installRoot, $codexHome)) { if (Test-Path -LiteralPath $path) { Remove-Item -LiteralPath $path -Recurse -Force } } } } Invoke-Check -Name 'package:refuses-traversal-package-name' -Script { $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxTraversal-" + [System.Guid]::NewGuid()) $outputRoot = Join-Path $tempRoot 'out' $escapeRoot = Join-Path $tempRoot 'escape' $sentinel = Join-Path $escapeRoot 'sentinel.txt' try { New-Item -ItemType Directory -Force -Path $outputRoot, $escapeRoot | Out-Null Set-Content -LiteralPath $sentinel -Value 'do not delete' -Encoding utf8NoBOM $result = Invoke-PwshFile -FilePath (Join-Path $PSScriptRoot 'package-toolbox.ps1') -ArgumentList @( '-Configuration', $Configuration, '-OutputRoot', $outputRoot, '-PackageName', '..\escape', '-SkipBuild', '-SkipPromptGeneration' ) Assert-Condition ($result.ExitCode -ne 0) 'expected packager to reject a package name containing a path separator' Assert-Condition (Test-Path -LiteralPath $sentinel) 'expected path outside OutputRoot to be preserved' 'rejected traversal package name without deleting outside OutputRoot' } finally { if (Test-Path -LiteralPath $tempRoot) { Remove-Item -LiteralPath $tempRoot -Recurse -Force } } } Invoke-Check -Name 'package-installer:verifies-sha256-before-install' -Script { $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxHash-" + [System.Guid]::NewGuid()) $packageRoot = Join-Path $tempRoot 'package' $installRoot = Join-Path $tempRoot 'install' $codexHome = Join-Path $tempRoot 'codex' try { New-TestPortablePackage -PackageRoot $packageRoot -UseWindowsSeparators Set-Content -LiteralPath (Join-Path $packageRoot 'docs\ai\mercury-toolbox-ai-prompt.md') -Value 'tampered prompt' -Encoding utf8NoBOM $result = Invoke-PwshFile -FilePath (Join-Path $packageRoot 'scripts\install-package-toolbox.ps1') -ArgumentList @( '-InstallRoot', $installRoot, '-CodexHome', $codexHome, '-NoPathUpdate' ) Assert-Condition ($result.ExitCode -ne 0) 'expected portable installer to reject a mismatched SHA256SUMS entry' Assert-Condition (-not (Test-Path -LiteralPath $installRoot)) 'expected hash failure before writing install root' Assert-Condition (-not (Test-Path -LiteralPath $codexHome)) 'expected hash failure before writing Codex skill root' 'rejected tampered package content before installing' } finally { if (Test-Path -LiteralPath $tempRoot) { Remove-Item -LiteralPath $tempRoot -Recurse -Force } } } Invoke-Check -Name 'package-installer:requires-listed-sha256-file' -Script { $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxHashMissing-" + [System.Guid]::NewGuid()) $packageRoot = Join-Path $tempRoot 'package' $installRoot = Join-Path $tempRoot 'install' try { New-TestPortablePackage -PackageRoot $packageRoot -UseWindowsSeparators Add-Content -LiteralPath (Join-Path $packageRoot 'SHA256SUMS.txt') -Value ('0' * 64 + ' docs\ai\missing.txt') $result = Invoke-PwshFile -FilePath (Join-Path $packageRoot 'scripts\install-package-toolbox.ps1') -ArgumentList @( '-InstallRoot', $installRoot, '-NoCodexSkillInstall', '-NoPathUpdate' ) Assert-Condition ($result.ExitCode -ne 0) 'expected portable installer to reject a missing SHA256SUMS entry' Assert-Condition (-not (Test-Path -LiteralPath $installRoot)) 'expected missing-file failure before writing install root' 'rejected package with a missing listed checksum file before installing' } finally { if (Test-Path -LiteralPath $tempRoot) { Remove-Item -LiteralPath $tempRoot -Recurse -Force } } } Invoke-Check -Name 'package-installer:refuses-unmanaged-codex-skill' -Script { $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("MercuryToolboxPackageGuard-" + [System.Guid]::NewGuid()) $packageRoot = Join-Path $tempRoot 'package' $installRoot = Join-Path $tempRoot 'install' $codexHome = Join-Path $tempRoot 'codex' $skillRoot = Join-Path $codexHome 'skills\mercury-toolbox' $sentinel = Join-Path $skillRoot 'USER-SKILL.txt' try { New-TestPortablePackage -PackageRoot $packageRoot -UseWindowsSeparators New-Item -ItemType Directory -Force -Path $skillRoot | Out-Null Set-Content -LiteralPath $sentinel -Value 'user managed' -Encoding utf8NoBOM $result = Invoke-PwshFile -FilePath (Join-Path $packageRoot 'scripts\install-package-toolbox.ps1') -ArgumentList @( '-InstallRoot', $installRoot, '-CodexHome', $codexHome, '-NoPathUpdate' ) Assert-Condition ($result.ExitCode -ne 0) 'expected portable installer to refuse unmanaged Codex skill directory' Assert-Condition (Test-Path -LiteralPath $sentinel) 'expected unmanaged portable Codex skill sentinel to be preserved' Assert-Condition (-not (Test-Path -LiteralPath (Join-Path $skillRoot '.mercury-toolbox-owner.json'))) 'expected unmanaged portable skill to remain unmarked' Assert-Condition (-not (Test-Path -LiteralPath $installRoot)) 'expected portable installer to fail before writing install root' 'refused unmanaged portable Codex skill directory without overwriting it' } finally { if (Test-Path -LiteralPath $tempRoot) { Remove-Item -LiteralPath $tempRoot -Recurse -Force } } } Write-Host '' $script:Results | Format-Table -AutoSize if ($script:Failed) { throw 'One or more ecosystem checks failed.' }