trial-session-package-acceptance.ps1 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. param(
  2. [string]$TrainingDir = 'D:\qiwei-training',
  3. [string]$CredentialEnv = 'E:\workspace\QIWEI-skill\.env.local',
  4. [int]$Port = 4434
  5. )
  6. $ErrorActionPreference = 'Stop'
  7. function Read-EnvValue([string]$path, [string]$key) {
  8. $line = Get-Content -LiteralPath $path | Where-Object { $_ -match "^$([regex]::Escape($key))\s*=" } | Select-Object -Last 1
  9. if (-not $line) { return '' }
  10. return ($line -replace "^$([regex]::Escape($key))\s*=\s*", '').Trim().Trim('"').Trim("'")
  11. }
  12. function Wait-Http([string]$url, [int]$seconds = 30) {
  13. $deadline = (Get-Date).AddSeconds($seconds)
  14. do {
  15. try { return Invoke-RestMethod -Uri $url -TimeoutSec 5 }
  16. catch { Start-Sleep -Milliseconds 750 }
  17. } while ((Get-Date) -lt $deadline)
  18. throw "Timed out waiting for $url"
  19. }
  20. $token = Read-EnvValue $CredentialEnv 'QIWEI_AUTH_TOKEN'
  21. if (-not $token.StartsWith('r:')) { throw 'The acceptance credential must be an r: session credential' }
  22. $root = Join-Path $env:TEMP ("qiwei-trial-" + [guid]::NewGuid().ToString('N'))
  23. $exe = Join-Path $root 'qiwei-workbench.exe'
  24. $dashboard = $null
  25. New-Item -ItemType Directory -Path $root | Out-Null
  26. try {
  27. Copy-Item (Join-Path $TrainingDir 'qiwei-workbench.exe') $exe
  28. Copy-Item (Join-Path $TrainingDir 'qiwei.runtime.config.mjs') (Join-Path $root 'qiwei.runtime.config.mjs')
  29. New-Item -ItemType Directory -Path (Join-Path $root 'web') | Out-Null
  30. Copy-Item (Join-Path $TrainingDir 'web\*') (Join-Path $root 'web')
  31. New-Item -ItemType Directory -Path (Join-Path $root 'knowledge') | Out-Null
  32. Copy-Item (Join-Path $TrainingDir 'knowledge\*') (Join-Path $root 'knowledge') -Recurse
  33. $envText = @(
  34. 'QIWEI_API_BASE=https://server.fmode.cn/api/qiwei'
  35. "QIWEI_AUTH_TOKEN=$token"
  36. 'QIWEI_UID='
  37. 'QIWEI_GUID='
  38. 'QIWEI_AUTO_REPLY_ALLOWED_SENDERS='
  39. ) -join [Environment]::NewLine
  40. [IO.File]::WriteAllText((Join-Path $root '.env.local'), $envText + [Environment]::NewLine, [Text.UTF8Encoding]::new($false))
  41. $dashboard = Start-Process -FilePath $exe -ArgumentList '--no-open','--port',"$Port" -WorkingDirectory $root -PassThru -WindowStyle Hidden -Environment @{
  42. QIWEI_AUTH_TOKEN = 'stale-startup-credential'
  43. }
  44. $status = Wait-Http "http://127.0.0.1:$Port/api/status"
  45. Start-Sleep -Seconds 12
  46. $agent = Invoke-RestMethod -Uri "http://127.0.0.1:$Port/api/agent/status" -TimeoutSec 10
  47. $runtimePath = Join-Path $root 'outputs\runtime\qiwei-runtime.json'
  48. $runtime = Get-Content -LiteralPath $runtimePath -Raw | ConvertFrom-Json
  49. if (-not $status.summary.authConfigured) { throw 'Session credential was not recognized' }
  50. if (-not $status.summary.subscribed) { throw 'Trial entitlement was not recognized' }
  51. if ($status.data.subscription.summary.trialActive -ne $true) { throw 'Entitlement was not classified as trial' }
  52. if ($status.data.subscription.summary.source -ne 'trial') { throw 'Trial source was not preserved' }
  53. if ([int]$status.data.subscription.summary.seats -ne 1) { throw 'Unexpected trial seat count' }
  54. [ordered]@{
  55. credentialKind = 'session'
  56. authConfigured = [bool]$status.summary.authConfigured
  57. subscribed = [bool]$status.summary.subscribed
  58. trialActive = [bool]$status.data.subscription.summary.trialActive
  59. source = $status.data.subscription.summary.source
  60. seats = $status.data.subscription.summary.seats
  61. usedSeats = $status.data.subscription.summary.usedSeats
  62. boundAccounts = 0
  63. accountOnline = [bool]$agent.data.account.online
  64. listenerRunning = [bool]$agent.data.listener.running
  65. runtimeStatus = $runtime.status
  66. runtimeComponentStatus = $runtime.components.personalPolling.status
  67. runtimeError = $runtime.components.personalPolling.lastError
  68. reviewMode = $agent.data.globalMode
  69. allowedSenderCount = $agent.data.config.allowedSenderCount
  70. } | ConvertTo-Json -Depth 8
  71. } finally {
  72. if (Test-Path $exe) {
  73. try { & $exe runtime stop *> $null } catch {}
  74. }
  75. Get-CimInstance Win32_Process |
  76. Where-Object { $_.ExecutablePath -eq $exe } |
  77. ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
  78. if ($dashboard -and -not $dashboard.HasExited) { Stop-Process -Id $dashboard.Id -Force -ErrorAction SilentlyContinue }
  79. Start-Sleep -Milliseconds 500
  80. $resolvedRoot = [IO.Path]::GetFullPath($root)
  81. $resolvedTemp = [IO.Path]::GetFullPath($env:TEMP)
  82. if ($resolvedRoot.StartsWith($resolvedTemp, [StringComparison]::OrdinalIgnoreCase) -and (Test-Path $resolvedRoot)) {
  83. Remove-Item -LiteralPath $resolvedRoot -Recurse -Force
  84. }
  85. }