[CmdletBinding()] param( [string]$ApiBaseUrl = "https://tb.kusoft.xyz", [string]$RepoRoot = "", [string]$CredentialPath = "", [string]$WorkerName = $env:COMPUTERNAME, [int]$PollSeconds = 10, [int]$RestartDelaySeconds = 10 ) $ErrorActionPreference = "Stop" if (-not $RepoRoot) { $RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path } if (-not $CredentialPath) { $CredentialPath = Join-Path $env:LOCALAPPDATA "TradeBot\training-agent.token" } $agent = Join-Path $RepoRoot "tools\windows_training_agent.py" if (-not (Test-Path -LiteralPath $agent)) { throw "Windows training agent not found: $agent" } if (-not (Test-Path -LiteralPath $CredentialPath)) { throw "Encrypted training credential not found: $CredentialPath" } function Resolve-Python { $venvPython = Join-Path $RepoRoot ".venv\Scripts\python.exe" if (Test-Path -LiteralPath $venvPython) { return $venvPython } $userPython = Join-Path $env:LOCALAPPDATA "Programs\TradeBotPython312\python.exe" if (Test-Path -LiteralPath $userPython) { return $userPython } foreach ($candidate in @("python.exe", "python")) { $command = Get-Command $candidate -ErrorAction SilentlyContinue if ($command) { return $command.Source } } throw "Python was not found. Create .venv or install Python 3.12." } $createdNew = $false $mutex = [System.Threading.Mutex]::new($false, "Local\TradeBotWindowsTrainingAgent", [ref]$createdNew) if (-not $createdNew) { $mutex.Dispose() exit 0 } $encryptedToken = (Get-Content -LiteralPath $CredentialPath -Raw -Encoding UTF8).Trim() $secureToken = $encryptedToken | ConvertTo-SecureString $tokenPointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureToken) try { $env:TRADEBOT_API_AUTH = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($tokenPointer) $python = Resolve-Python $workerId = "${WorkerName}:$RepoRoot" $arguments = @( "-u", $agent, "--repo-root", $RepoRoot, "--api-base-url", $ApiBaseUrl, "--worker-id", $workerId, "--worker-name", $WorkerName, "--poll-seconds", [Math]::Max(5, $PollSeconds).ToString() ) while ($true) { & $python @arguments Start-Sleep -Seconds ([Math]::Max(5, $RestartDelaySeconds)) } } finally { $env:TRADEBOT_API_AUTH = $null [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($tokenPointer) $mutex.ReleaseMutex() $mutex.Dispose() }