CI / Capabilities and shell quality (push) Successful in 12s
CI / Python tests and compilation (push) Successful in 22s
CI / CI configuration security checks (push) Successful in 4s
CI / Build and inspect generated packages (push) Successful in 13s
CI / PowerShell tests on Ubuntu (push) Successful in 1m10s
CI / Bash integration and installation guards (push) Successful in 1m38s
CI / Installed client configuration smoke tests (push) Successful in 13s
CI / Qwen retrieval integration (push) Successful in 14m24s
83 lines
6.5 KiB
PowerShell
83 lines
6.5 KiB
PowerShell
[CmdletBinding()]
|
|
param([switch]$Summary)
|
|
$ErrorActionPreference = 'Stop'
|
|
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
|
|
function Write-Host { param($Object) if (-not $Summary) { Microsoft.PowerShell.Utility\Write-Host $Object } }
|
|
. (Join-Path $root 'scripts/lib/plugins.ps1')
|
|
|
|
$script:answers = [System.Collections.Generic.Queue[string]]::new()
|
|
$script:answers.Enqueue('1')
|
|
$script:answers.Enqueue('2')
|
|
$script:answers.Enqueue('done')
|
|
function Read-Host { param($Prompt) $answers.Dequeue() }
|
|
|
|
$result = Read-PluginToggleSelection -Names @('A','B','C') -Checked @($true, $false, $true)
|
|
if ($result[0] -ne $false) { throw 'Toggling checked entry 1 must uncheck it.' }
|
|
if ($result[1] -ne $true) { throw 'Toggling unchecked entry 2 must check it.' }
|
|
if ($result[2] -ne $true) { throw 'Entry 3 was never toggled and must stay unchanged.' }
|
|
|
|
$script:answers.Enqueue('')
|
|
$confirmed = @(Read-PluginToggleSelection -Names @('A') -Checked @($true))
|
|
if ($confirmed.Count -ne 1 -or -not $confirmed[0]) { throw 'Enter must confirm without changing the selection.' }
|
|
function Test-PluginOutput {
|
|
param([string]$Mode)
|
|
Write-Output 'download progress'
|
|
Write-Output 'WARN test warning'
|
|
$global:LASTEXITCODE = if ($Mode -eq 'fail') { 7 } else { 0 }
|
|
}
|
|
$compact = @(Invoke-PluginCommand -Command Test-PluginOutput -Arguments @('success') -Summary)
|
|
if ($compact.Count -ne 1 -or $compact[0] -ne 'WARN test warning') { throw 'Plugin summary must retain warnings and suppress progress.' }
|
|
$detailed = @(Invoke-PluginCommand -Command Test-PluginOutput -Arguments @('success'))
|
|
if ($detailed.Count -ne 2 -or $detailed[0] -ne 'download progress') { throw 'Detailed output must retain progress.' }
|
|
$diagnostics = [System.Collections.Generic.List[string]]::new()
|
|
$failed = $false
|
|
$env:AI_CONFIG_VERBOSE = $null
|
|
try { Invoke-PluginCommand -Command Test-PluginOutput -Arguments @('fail') -Summary | ForEach-Object { $diagnostics.Add("$_") } }
|
|
catch { $failed = $true }
|
|
$env:AI_CONFIG_VERBOSE = $null
|
|
if (-not $failed -or $diagnostics -notcontains 'download progress' -or $diagnostics -notcontains 'WARN test warning') { throw 'Plugin failure must retain full diagnostics and fail.' }
|
|
$global:LASTEXITCODE = 0
|
|
$script:codexInventory = '{"installed":[{"pluginId":"ponytail@ponytail"},{"pluginId":"i-have-adhd@i-have-adhd"},{"pluginId":"superpowers@openai-curated-remote"},{"pluginId":"context7@context7-marketplace"},{"pluginId":"caveman@thinkhome-caveman"}],"available":[]}'
|
|
function codex { $script:observedCodexHome = $env:CODEX_HOME; $script:observedProfile = $env:USERPROFILE; $script:codexInventory }
|
|
$testHome = Join-Path ([System.IO.Path]::GetTempPath()) 'ai-config-plugin-test-home'
|
|
$previousCodexHome = [Environment]::GetEnvironmentVariable('CODEX_HOME', 'Process')
|
|
$previousProfile = [Environment]::GetEnvironmentVariable('USERPROFILE', 'Process')
|
|
$null = Get-InstalledPlugins -Client Codex -HomePath $testHome
|
|
if ($observedCodexHome -ne (Join-Path $testHome '.codex') -or $observedProfile -ne $testHome) { throw 'Plugin inspection must use the requested user home.' }
|
|
if ([Environment]::GetEnvironmentVariable('CODEX_HOME', 'Process') -ne $previousCodexHome -or [Environment]::GetEnvironmentVariable('USERPROFILE', 'Process') -ne $previousProfile) { throw 'Plugin inspection must restore the process environment.' }
|
|
$script:answers.Enqueue('done')
|
|
$selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Mode Update
|
|
if (@($selection.Selected | Where-Object { $_.codex_method -eq 'plugin' }).Count -ne 5) { throw 'All installed Codex plugins must start checked when updating.' }
|
|
$script:answers.Enqueue('4')
|
|
$script:answers.Enqueue('done')
|
|
$selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Mode Update
|
|
if (@($selection.Deselected | Where-Object { $_.name -eq 'Context7' }).Count -ne 1) { throw 'Only the explicitly unchecked installed plugin must be deselected.' }
|
|
$mcporterHome = Join-Path (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) ('.context7-test-' + [Guid]::NewGuid())
|
|
try {
|
|
$configPath = Join-Path $mcporterHome '.mcporter/mcporter.json'
|
|
New-Item (Split-Path $configPath) -ItemType Directory -Force | Out-Null
|
|
[System.IO.File]::WriteAllText($configPath, '{"mcpServers":{"context7":{"baseUrl":"https://mcp.context7.com/mcp"}}}')
|
|
$script:codexInventory = '{"installed":[],"available":[]}'
|
|
$script:answers.Enqueue('done')
|
|
$selection = Select-ConfiguredPlugins -RepositoryRoot $root -Client Codex -Mode Update -HomePath $mcporterHome
|
|
if (@($selection.Selected | Where-Object { $_.name -eq 'Context7' }).Count -ne 1) { throw 'MCPorter Context7 must start checked when updating.' }
|
|
[System.IO.File]::WriteAllText($configPath, '{"mcpServers":{"context7":{"baseUrl":"https://example.invalid/mcp"}}}')
|
|
$script:answers.Enqueue('done')
|
|
$selection = Select-ConfiguredPlugins -RepositoryRoot $root -Client Codex -Mode Update -HomePath $mcporterHome
|
|
if (@($selection.Deselected | Where-Object { $_.name -eq 'Context7' }).Count -ne 1) { throw 'A different MCPorter server must not select Context7.' }
|
|
} finally { Remove-Item -LiteralPath $mcporterHome -Recurse -Force -ErrorAction SilentlyContinue }
|
|
$script:managedArguments = @()
|
|
function python { $script:managedArguments = @($args); $global:LASTEXITCODE = 0 }
|
|
$entry = [pscustomobject]@{ name = 'Test'; codex_method = 'plugin'; codex_marketplace = '-'; codex_plugin = 'test@market' }
|
|
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -HomePath $testHome -Update -Summary -Entries @($entry)
|
|
if ($managedArguments -notcontains 'sync' -or $managedArguments -notcontains '--update' -or $managedArguments -notcontains 'Test' -or $managedArguments -notcontains $testHome) { throw 'Managed reconciliation must receive selection, home, and update mode.' }
|
|
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Entries @()
|
|
if ($managedArguments[-1] -ne '--selected') { throw 'Empty selection must reach reconciliation for managed cleanup.' }
|
|
function Get-InstalledPlugins { throw 'Empty selection must not query installed plugins.' }
|
|
function Invoke-PluginCommand { throw 'Empty selection must not run plugin commands.' }
|
|
Install-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Both -Entries @()
|
|
Uninstall-DeselectedPlugins -Client Both -Entries @()
|
|
|
|
if ($Summary) { Write-Output 'Tests: PASS | plugin selection' } else { Write-Output 'PASS plugin toggle selection: toggle and confirm' }
|
|
exit 0
|