#requires -Version 5.1 param([string]$Token = '') $ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $Token = "" $SynthloRoot = Join-Path $env:LOCALAPPDATA 'Synthlo' $NodeDir = Join-Path $SynthloRoot 'node' $BinDir = Join-Path $SynthloRoot 'tools' $env:PATH = "$BinDir;$NodeDir;$env:PATH" function Test-SynthloNode { if (-not (Get-Command node.exe -ErrorAction SilentlyContinue)) { return $false } try { $version = (& node.exe --version).Trim().TrimStart('v') return $LASTEXITCODE -eq 0 -and ([version]$version -ge [version]'22.19.0') } catch { return $false } } Write-Host 'Checking your Synthlo connection...' $null = Invoke-RestMethod 'http://192.168.100.242:8000/v1/models' -TimeoutSec 30 if (-not (Test-SynthloNode) -or -not (Get-Command npm.cmd -ErrorAction SilentlyContinue)) { $archName = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE } $arch = switch ($archName) { 'AMD64' { 'x64' }; 'ARM64' { 'arm64' }; default { throw 'Install Node.js 22.19+ and npm for this CPU, then rerun.' } } $tmp = Join-Path ([IO.Path]::GetTempPath()) ('synthlo-node-' + [guid]::NewGuid()) New-Item -ItemType Directory -Force $tmp | Out-Null try { $base = 'https://nodejs.org/dist/latest-v22.x' $checksums = (Invoke-WebRequest -UseBasicParsing "$base/SHASUMS256.txt" -TimeoutSec 120).Content $entry = $checksums -split "`n" | Where-Object { $_.Trim() -match "^[a-f0-9]{64}\s+node-v22\.\d+\.\d+-win-$arch\.zip$" } | Select-Object -First 1 if (-not $entry) { throw 'No compatible Node.js download found.' } $parts = $entry.Trim() -split '\s+' $zip = Join-Path $tmp $parts[1] Write-Host "Installing a private Node.js runtime in $NodeDir..." Invoke-WebRequest -UseBasicParsing "$base/$($parts[1])" -OutFile $zip -TimeoutSec 600 if ((Get-FileHash $zip -Algorithm SHA256).Hash.ToLower() -ne $parts[0]) { throw 'Node.js checksum mismatch.' } Expand-Archive $zip $tmp -Force New-Item -ItemType Directory -Force $NodeDir | Out-Null Copy-Item (Join-Path (Join-Path $tmp ($parts[1] -replace '\.zip$', '')) '*') $NodeDir -Recurse -Force } finally { Remove-Item $tmp -Recurse -Force -ErrorAction SilentlyContinue } if (-not (Test-SynthloNode)) { throw 'Node.js installation failed.' } } Write-Host 'Installing Pi and OpenCode for your user...' & npm.cmd install --global --prefix $BinDir --ignore-scripts '@earendil-works/pi-coding-agent' if ($LASTEXITCODE -ne 0) { throw 'Pi installation failed.' } & npm.cmd install --global --prefix $BinDir opencode-ai if ($LASTEXITCODE -ne 0) { throw 'OpenCode installation failed.' } $runtime = Split-Path (Get-Command node.exe).Source $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') $entries = @($BinDir, $runtime) + @($userPath -split ';' | Where-Object { $_ -and $_ -ne $BinDir -and $_ -ne $runtime }) [Environment]::SetEnvironmentVariable('Path', ($entries -join ';'), 'User') if (-not (Get-Command bash.exe -ErrorAction SilentlyContinue) -and -not (Test-Path "$env:ProgramFiles\Git\bin\bash.exe")) { Write-Warning 'Pi needs Bash for shell commands. Install Git for Windows, or use the Linux setup inside WSL.' } if (-not (Test-SynthloNode)) { throw 'Node.js 22.19+ is required. Use the full setup command first.' } $env:SYNTHLO_TOKEN = $Token $env:SYNTHLO_CONFIG = '' $writerPath = Join-Path ([IO.Path]::GetTempPath()) ('synthlo-config-' + [guid]::NewGuid() + '.cjs') try { $writer = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('KGFzeW5jICgpID0+IHsKLy8gU2hhcmVkIGJ5IFVuaXggYW5kIFdpbmRvd3MgaW5zdGFsbGVycy4gVmFsaWRhdGUgZXZlcnkgaW5wdXQgYmVmb3JlIHdyaXRpbmcgZmlsZXMuCmNvbnN0IGZzID0gcmVxdWlyZSgnZnMnKTsKY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKTsKY29uc3Qgb3MgPSByZXF1aXJlKCdvcycpOwpjb25zdCBjcnlwdG8gPSByZXF1aXJlKCdjcnlwdG8nKTsKY29uc3QgdG9rZW4gPSBwcm9jZXNzLmVudi5TWU5USExPX1RPS0VOOwoKLy8gVGhpcyBTeW50aGxvIGluc3RhbGxhdGlvbiB1c2VzIG11bHRpbW9kYWwgbW9kZWxzLiBFeHBsaWNpdCBiYWNrZW5kIG1ldGFkYXRhCi8vIGFuZCBvcGVyYXRvciBvdmVycmlkZXMgdGFrZSBwcmVjZWRlbmNlIG92ZXIgdGhhdCB3b3Jrc3BhY2UgZGVmYXVsdC4KY29uc3QgbW9kZWxJbnB1dCA9IGZ1bmN0aW9uIG1vZGVsSW5wdXQobW9kZWwpIHsKICAgIGNvbnN0IGlucHV0ID0gbW9kZWwubW9kYWxpdGllcz8uaW5wdXQgfHwgbW9kZWwuaW5wdXQ7CiAgICBpZiAoQXJyYXkuaXNBcnJheShpbnB1dCkgJiYgaW5wdXQubGVuZ3RoKSByZXR1cm4gWyd0ZXh0JywgLi4uKGlucHV0LmluY2x1ZGVzKCdpbWFnZScpID8gWydpbWFnZSddIDogW10pXTsKICAgIGlmICh0eXBlb2YgbW9kZWwuc3VwcG9ydHNfdmlzaW9uID09PSAnYm9vbGVhbicpIHJldHVybiBtb2RlbC5zdXBwb3J0c192aXNpb24gPyBbJ3RleHQnLCdpbWFnZSddIDogWyd0ZXh0J107CiAgICBpZiAoQXJyYXkuaXNBcnJheShtb2RlbC5jYXBhYmlsaXRpZXMpICYmIG1vZGVsLmNhcGFiaWxpdGllcy5pbmNsdWRlcygndGV4dC1vbmx5JykpIHJldHVybiBbJ3RleHQnXTsKICAgIHJldHVybiBbJ3RleHQnLCdpbWFnZSddOwp9OwoKLy8gQ2F0YWxvZyBtZW1iZXJzaGlwIGlzIG5vdCBwcm9vZiB0aGF0IGEgbW9kZWwgaXMgbG9hZGVkIGludG8gbWVtb3J5Lgpjb25zdCBkaXNjb3Zlck1vZGVscyA9IGFzeW5jIGZ1bmN0aW9uIGRpc2NvdmVyTW9kZWxzKGJhc2VVUkwsIGhlYWRlcnMgPSB7fSkgewogICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChiYXNlVVJMICsgJy9tb2RlbHMnLCB7IGhlYWRlcnMsIHNpZ25hbDogQWJvcnRTaWduYWwudGltZW91dCgxMDAwMCkgfSk7CiAgICBpZiAoIXJlc3BvbnNlLm9rKSB0aHJvdyBuZXcgRXJyb3IoYE1vZGVsIGNhdGFsb2cgcmV0dXJuZWQgSFRUUCAke3Jlc3BvbnNlLnN0YXR1c31gKTsKICAgIGNvbnN0IGNhdGFsb2cgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7CiAgICBpZiAoIUFycmF5LmlzQXJyYXkoY2F0YWxvZy5kYXRhKSB8fCBjYXRhbG9nLmRhdGEuc29tZShtID0+ICFtIHx8IHR5cGVvZiBtLmlkICE9PSAnc3RyaW5nJyB8fCAhbS5pZCkpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB1cHN0cmVhbSBtb2RlbCBjYXRhbG9nJyk7CiAgICBpZiAoY2F0YWxvZy5kYXRhLmV2ZXJ5KG0gPT4gdHlwZW9mIG0uY3VycmVudGx5X2xvYWRlZCA9PT0gJ2Jvb2xlYW4nKSkgcmV0dXJuIGNhdGFsb2cuZGF0YTsKICAgIGNvbnN0IHN0YXR1c1Jlc3BvbnNlID0gYXdhaXQgZmV0Y2goYmFzZVVSTCArICcvc3RhdHVzJywgeyBoZWFkZXJzLCBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoMTAwMDApIH0pOwogICAgaWYgKCFzdGF0dXNSZXNwb25zZS5vaykgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgdmVyaWZ5IGxvYWRlZCBtb2RlbHM6IHN0YXR1cyBIVFRQICR7c3RhdHVzUmVzcG9uc2Uuc3RhdHVzfWApOwogICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgc3RhdHVzUmVzcG9uc2UuanNvbigpOwogICAgY29uc3QgcnVudGltZSA9IHN0YXR1cy5tb2RlbF9tYW5hZ2VyPy5tb2RlbHM7CiAgICBpZiAoIUFycmF5LmlzQXJyYXkocnVudGltZSkpIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHZlcmlmeSBsb2FkZWQgbW9kZWxzOiBpbnZhbGlkIHJ1bnRpbWUgc3RhdHVzJyk7CiAgICByZXR1cm4gY2F0YWxvZy5kYXRhLm1hcChtb2RlbCA9PiB7CiAgICAgICAgY29uc3Qgc3RhdGUgPSBydW50aW1lLmZpbmQobSA9PiBtLmlkID09PSBtb2RlbC5pZCk7CiAgICAgICAgaWYgKCFzdGF0ZSB8fCB0eXBlb2Ygc3RhdGUubG9hZGVkICE9PSAnYm9vbGVhbicpIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHZlcmlmeSBsb2FkZWQgc3RhdGUgZm9yICcgKyBtb2RlbC5pZCk7CiAgICAgICAgcmV0dXJuIHsgLi4ubW9kZWwsIGNhcGFiaWxpdGllczogbW9kZWwuY2FwYWJpbGl0aWVzID8/IHN0YXRlLmNhcGFiaWxpdGllcywgbW9kYWxpdGllczogbW9kZWwubW9kYWxpdGllcyA/PyBzdGF0ZS5tb2RhbGl0aWVzLCBpbnB1dDogbW9kZWwuaW5wdXQgPz8gc3RhdGUuaW5wdXQsIHN1cHBvcnRzX3Zpc2lvbjogbW9kZWwuc3VwcG9ydHNfdmlzaW9uID8/IHN0YXRlLnN1cHBvcnRzX3Zpc2lvbiwgY3VycmVudGx5X2xvYWRlZDogc3RhdGUubG9hZGVkIH07CiAgICB9KTsKfTsKCi8vIEJ1aWxkIGZyZXNoIExBTiBjb25maWd1cmF0aW9ucyBvbiB0aGUgdGFyZ2V0IG1hY2hpbmUsIHdpdGhvdXQgY3JlZGVudGlhbHMuCmNvbnN0IGRpc2NvdmVyTG9jYWwgPSBhc3luYyBmdW5jdGlvbiBsb2NhbENvbmZpZyhiYXNlVVJMKSB7CiAgICBjb25zdCBjYXRhbG9nID0gYXdhaXQgZGlzY292ZXJNb2RlbHMoYmFzZVVSTCk7CiAgICBjb25zdCBtb2RlbHMgPSBjYXRhbG9nLmZpbHRlcihtID0+IG0uY3VycmVudGx5X2xvYWRlZCA9PT0gdHJ1ZSk7CiAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWxzIGFyZSBsb2FkZWQgb24gdGhlIGxvY2FsIEFJIHNlcnZlci4gTG9hZCBhIG1vZGVsIGFuZCByZXJ1bi4nKTsKICAgIGNvbnN0IGlkcyA9IG5ldyBTZXQoKTsKICAgIGNvbnN0IHBpTW9kZWxzID0gbW9kZWxzLmZpbHRlcihtID0+ICFpZHMuaGFzKG0uaWQpICYmIGlkcy5hZGQobS5pZCkpLm1hcChtID0+IHsKICAgICAgICBjb25zdCBjdHggPSBOdW1iZXIobS5tYXhfY29udGV4dF9sZW5ndGgpID4gMCA/IE51bWJlcihtLm1heF9jb250ZXh0X2xlbmd0aCkgOiAxMjgwMDA7CiAgICAgICAgY29uc3QgY2FwcyA9IEFycmF5LmlzQXJyYXkobS5jYXBhYmlsaXRpZXMpID8gbS5jYXBhYmlsaXRpZXMgOiBbXTsKICAgICAgICByZXR1cm4geyBpZDogbS5pZCwgbmFtZTogbS5pZC5zcGxpdCgnLycpLnBvcCgpLCByZWFzb25pbmc6IGNhcHMuaW5jbHVkZXMoJ3JlYXNvbmluZycpLCBpbnB1dDogbW9kZWxJbnB1dChtKSwgY29udGV4dFdpbmRvdzogY3R4LCBtYXhUb2tlbnM6IE1hdGgubWluKDMyNzY4LCBNYXRoLmZsb29yKGN0eCAvIDQpKSB9OwogICAgfSk7CiAgICBjb25zdCBvcGVuTW9kZWxzID0gT2JqZWN0LmZyb21FbnRyaWVzKHBpTW9kZWxzLm1hcCgobSwgaSkgPT4gWydtb2RlbC0nICsgKGkgKyAxKSwgeyBpZDogbS5pZCwgbmFtZTogbS5uYW1lLCBhdHRhY2htZW50OiBtLmlucHV0LmluY2x1ZGVzKCdpbWFnZScpLCBtb2RhbGl0aWVzOiB7IGlucHV0OiBtLmlucHV0LCBvdXRwdXQ6IFsndGV4dCddIH0sIGxpbWl0OiB7IGNvbnRleHQ6IG0uY29udGV4dFdpbmRvdywgb3V0cHV0OiBtLm1heFRva2VucyB9IH1dKSk7CiAgICAvLyBQaSByZXF1aXJlcyBhIG5vbmVtcHR5IGFwaUtleSB2YWx1ZSBldmVuIGZvciBzZXJ2ZXJzIHdpdGhvdXQgYXV0aGVudGljYXRpb24uCiAgICAvLyAibG9jYWwiIGlzIGEgcHVibGljIHBsYWNlaG9sZGVyLCBuZXZlciBhIFN5bnRobG8gb3IgYmFja2VuZCBjcmVkZW50aWFsLgogICAgcmV0dXJuIHsKICAgICAgICBvcGVuY29kZTogeyAnJHNjaGVtYSc6ICdodHRwczovL29wZW5jb2RlLmFpL2NvbmZpZy5qc29uJywgbW9kZWw6ICdsb2NhbC1zeW50aG8vbW9kZWwtMScsIHByb3ZpZGVyOiB7ICdsb2NhbC1zeW50aG8nOiB7IG5wbTogJ0BhaS1zZGsvb3BlbmFpLWNvbXBhdGlibGUnLCBuYW1lOiAnTG9jYWwgbmV0d29yayBBSScsIG9wdGlvbnM6IHsgYmFzZVVSTCwgdGltZW91dDogMTUwMDAwMCB9LCBtb2RlbHM6IG9wZW5Nb2RlbHMgfSB9IH0sCiAgICAgICAgcGk6IHsgcHJvdmlkZXJzOiB7ICdsb2NhbC1zeW50aG8nOiB7IGJhc2VVcmw6IGJhc2VVUkwsIGFwaTogJ29wZW5haS1jb21wbGV0aW9ucycsIGFwaUtleTogJ2xvY2FsJywgY29tcGF0OiB7IHN1cHBvcnRzRGV2ZWxvcGVyUm9sZTogZmFsc2UsIHN1cHBvcnRzUmVhc29uaW5nRWZmb3J0OiBmYWxzZSwgc3VwcG9ydHNVc2FnZUluU3RyZWFtaW5nOiBmYWxzZSwgbWF4VG9rZW5zRmllbGQ6ICdtYXhfdG9rZW5zJyB9LCBtb2RlbHM6IHBpTW9kZWxzIH0gfSB9LAogICAgICAgIHBpU2V0dGluZ3M6IHsgZGVmYXVsdFByb3ZpZGVyOiAnbG9jYWwtc3ludGhvJywgZGVmYXVsdE1vZGVsOiBwaU1vZGVsc1swXS5pZCB9CiAgICB9Owp9OwoKY29uc3QgZ2VuZXJhdGVkID0gYXdhaXQgZGlzY292ZXJMb2NhbCgiaHR0cDovLzE5Mi4xNjguMTAwLjI0Mjo4MDAwL3YxIik7CmdlbmVyYXRlZC5yZXBsYWNlQWxsID0gZmFsc2U7CmNvbnN0IHJlcGxhY2VBbGwgPSBnZW5lcmF0ZWQucmVwbGFjZUFsbCA9PT0gdHJ1ZTsKY29uc3QgcHJvdmlkZXJJZCA9IGdlbmVyYXRlZC5waVNldHRpbmdzLmRlZmF1bHRQcm92aWRlcjsKY29uc3Qgb2JqZWN0ID0gdiA9PiB2ICE9PSBudWxsICYmIHR5cGVvZiB2ID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheSh2KTsKY29uc3QgdXNlckhvbWUgPSBwcm9jZXNzLmVudi5TWU5USExPX0hPTUUgfHwgb3MuaG9tZWRpcigpOwpjb25zdCBvcGVuRGlyID0gcGF0aC5qb2luKHByb2Nlc3MuZW52LlhER19DT05GSUdfSE9NRSB8fCBwYXRoLmpvaW4odXNlckhvbWUsICcuY29uZmlnJyksICdvcGVuY29kZScpOwpjb25zdCBwaURpciA9IHByb2Nlc3MuZW52LlBJX0NPRElOR19BR0VOVF9ESVIgfHwgcGF0aC5qb2luKHVzZXJIb21lLCAnLnBpJywgJ2FnZW50Jyk7CmNvbnN0IHRhcmdldHMgPSBbcGF0aC5qb2luKG9wZW5EaXIsICdvcGVuY29kZS5qc29uJyksIHBhdGguam9pbihwaURpciwgJ21vZGVscy5qc29uJyksIHBhdGguam9pbihwaURpciwgJ3NldHRpbmdzLmpzb24nKV07CmNvbnN0IGpzb25jID0gcGF0aC5qb2luKG9wZW5EaXIsICdvcGVuY29kZS5qc29uYycpOwppZiAoZnMuZXhpc3RzU3luYyhqc29uYykgJiYgIXJlcGxhY2VBbGwpIHsKICAgIHRocm93IG5ldyBFcnJvcignT3BlbkNvZGUgdXNlcyBvcGVuY29kZS5qc29uYyBoZXJlLiBNZXJnZSB0aGUgU3ludGhsbyBwcm92aWRlciBmcm9tIHRoZSBkYXNoYm9hcmQgY29uZmlnIHByZXZpZXcgaW50byB0aGF0IGZpbGUgYmVmb3JlIHVzaW5nIHRoaXMgdXBkYXRlci4gTm8gY29uZmlnIGZpbGVzIHdlcmUgY2hhbmdlZC4nKTsKfQpmdW5jdGlvbiByZWFkKGZpbGUpIHsKICAgIGlmICghZnMuZXhpc3RzU3luYyhmaWxlKSkgcmV0dXJuIHt9OwogICAgaWYgKGZzLmxzdGF0U3luYyhmaWxlKS5pc1N5bWJvbGljTGluaygpKSB0aHJvdyBuZXcgRXJyb3IoYFJlZnVzaW5nIHRvIHJlcGxhY2UgYSBzeW1saW5rOiAke2ZpbGV9YCk7CiAgICBpZiAocmVwbGFjZUFsbCkgcmV0dXJuIHt9OwogICAgdHJ5IHsKICAgICAgICBjb25zdCBkYXRhID0gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKS5yZXBsYWNlKC9eXHVGRUZGLywgJycpKTsKICAgICAgICBpZiAoIW9iamVjdChkYXRhKSkgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RlZCBhIEpTT04gb2JqZWN0Jyk7CiAgICAgICAgcmV0dXJuIGRhdGE7CiAgICB9IGNhdGNoIChlcnJvcikgeyB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBtZXJnZSAke2ZpbGV9OiAke2Vycm9yLm1lc3NhZ2V9LiBGaXggaXQgYW5kIHJlcnVuOyBubyBjb25maWcgZmlsZXMgd2VyZSBjaGFuZ2VkLmApOyB9Cn0KY29uc3QgW29wZW4sIHBpLCBzZXR0aW5nc10gPSB0YXJnZXRzLm1hcChyZWFkKTsKZm9yIChjb25zdCBbdmFsdWUsIGxhYmVsXSBvZiBbW29wZW4ucHJvdmlkZXIsICdPcGVuQ29kZSBwcm92aWRlciddLCBbcGkucHJvdmlkZXJzLCAnUGkgcHJvdmlkZXJzJ11dKSB7CiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCAmJiAhb2JqZWN0KHZhbHVlKSkgdGhyb3cgbmV3IEVycm9yKGAke2xhYmVsfSBtdXN0IGJlIGFuIG9iamVjdC4gTm8gY29uZmlnIGZpbGVzIHdlcmUgY2hhbmdlZC5gKTsKfQpjb25zdCBvcGVuUHJvdmlkZXIgPSBnZW5lcmF0ZWQub3BlbmNvZGUucHJvdmlkZXJbcHJvdmlkZXJJZF07CmNvbnN0IHBpUHJvdmlkZXIgPSBnZW5lcmF0ZWQucGkucHJvdmlkZXJzW3Byb3ZpZGVySWRdOwoKCi8vIFJlbW92ZSBvdXIgbmFtZWQgcHJvdmlkZXJzIGFuZCBhbGlhc2VzIHBvaW50aW5nIGF0IHRoaXMgQUkgc2VydmljZSBvbmx5LgpmdW5jdGlvbiBtYW5hZ2VkKGlkLCBwcm92aWRlcikgewogICAgaWYgKFsnc3ludGhsbycsICdsb2NhbC1zeW50aG8nLCAnbG9jYWwtc3ludGhsbyddLmluY2x1ZGVzKGlkKSkgcmV0dXJuIHRydWU7CiAgICBjb25zdCBhZGRyZXNzID0gcHJvdmlkZXI/Lm9wdGlvbnM/LmJhc2VVUkwgfHwgcHJvdmlkZXI/LmJhc2VVcmwgfHwgcHJvdmlkZXI/LmJhc2VVUkw7CiAgICB0cnkgewogICAgICAgIGNvbnN0IHVybCA9IG5ldyBVUkwoYWRkcmVzcyk7CiAgICAgICAgcmV0dXJuIFsnc3ludGhsby5jb20nLCAnd3d3LnN5bnRobG8uY29tJ10uaW5jbHVkZXModXJsLmhvc3RuYW1lKSB8fCAodXJsLmhvc3RuYW1lID09PSAnMTkyLjE2OC4xMDAuMjQyJyAmJiB1cmwucG9ydCA9PT0gJzgwMDAnKTsKICAgIH0gY2F0Y2ggeyByZXR1cm4gZmFsc2U7IH0KfQpjb25zdCByZW1vdmVkT3BlbiA9IE9iamVjdC5rZXlzKG9wZW4ucHJvdmlkZXIgfHwge30pLmZpbHRlcihpZCA9PiBtYW5hZ2VkKGlkLCBvcGVuLnByb3ZpZGVyW2lkXSkpOwpjb25zdCByZW1vdmVkUGkgPSBPYmplY3Qua2V5cyhwaS5wcm92aWRlcnMgfHwge30pLmZpbHRlcihpZCA9PiBtYW5hZ2VkKGlkLCBwaS5wcm92aWRlcnNbaWRdKSk7CmNvbnN0IGtlZXAgPSAocHJvdmlkZXJzLCByZW1vdmVkKSA9PiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMocHJvdmlkZXJzIHx8IHt9KS5maWx0ZXIoKFtpZF0pID0+ICFyZW1vdmVkLmluY2x1ZGVzKGlkKSkpOwpjb25zdCBjbGVhbk9wZW4gPSB7IC4uLm9wZW4gfTsKaWYgKHR5cGVvZiBjbGVhbk9wZW4uc21hbGxfbW9kZWwgPT09ICdzdHJpbmcnICYmIHJlbW92ZWRPcGVuLnNvbWUoaWQgPT4gY2xlYW5PcGVuLnNtYWxsX21vZGVsLnN0YXJ0c1dpdGgoaWQgKyAnLycpKSkgZGVsZXRlIGNsZWFuT3Blbi5zbWFsbF9tb2RlbDsKZm9yIChjb25zdCBmaWVsZCBvZiBbJ2VuYWJsZWRfcHJvdmlkZXJzJywgJ2Rpc2FibGVkX3Byb3ZpZGVycyddKSB7CiAgICBpZiAoQXJyYXkuaXNBcnJheShjbGVhbk9wZW5bZmllbGRdKSkgewogICAgICAgIGNsZWFuT3BlbltmaWVsZF0gPSBjbGVhbk9wZW5bZmllbGRdLmZpbHRlcihpZCA9PiAhcmVtb3ZlZE9wZW4uaW5jbHVkZXMoaWQpKTsKICAgICAgICBpZiAoZmllbGQgPT09ICdlbmFibGVkX3Byb3ZpZGVycycgJiYgIWNsZWFuT3BlbltmaWVsZF0uaW5jbHVkZXMocHJvdmlkZXJJZCkpIGNsZWFuT3BlbltmaWVsZF0ucHVzaChwcm92aWRlcklkKTsKICAgIH0KfQpjb25zdCBjbGVhblNldHRpbmdzID0geyAuLi5zZXR0aW5ncyB9OwppZiAoQXJyYXkuaXNBcnJheShjbGVhblNldHRpbmdzLmVuYWJsZWRNb2RlbHMpKSBjbGVhblNldHRpbmdzLmVuYWJsZWRNb2RlbHMgPSBjbGVhblNldHRpbmdzLmVuYWJsZWRNb2RlbHMuZmlsdGVyKGlkID0+IHR5cGVvZiBpZCAhPT0gJ3N0cmluZycgfHwgIXJlbW92ZWRQaS5zb21lKHAgPT4gaWQuc3RhcnRzV2l0aChwICsgJy8nKSkpOwpjb25zdCBuZXh0ID0gWwogICAgeyAuLi5jbGVhbk9wZW4sICckc2NoZW1hJzogZ2VuZXJhdGVkLm9wZW5jb2RlLiRzY2hlbWEsIG1vZGVsOiBnZW5lcmF0ZWQub3BlbmNvZGUubW9kZWwsIHByb3ZpZGVyOiB7IC4uLmtlZXAob3Blbi5wcm92aWRlciwgcmVtb3ZlZE9wZW4pLCBbcHJvdmlkZXJJZF06IG9wZW5Qcm92aWRlciB9IH0sCiAgICB7IC4uLnBpLCBwcm92aWRlcnM6IHsgLi4ua2VlcChwaS5wcm92aWRlcnMsIHJlbW92ZWRQaSksIFtwcm92aWRlcklkXTogcGlQcm92aWRlciB9IH0sCiAgICB7IC4uLmNsZWFuU2V0dGluZ3MsIC4uLmdlbmVyYXRlZC5waVNldHRpbmdzIH0KXTsKLy8gSW4gcmVzZXQgbW9kZSwgYmFjayB1cCBKU09OQyB0b28sIHRoZW4gcmVtb3ZlIGl0IHNvIGl0IGNhbm5vdCBvdmVycmlkZSBKU09OLgppZiAocmVwbGFjZUFsbCAmJiBmcy5leGlzdHNTeW5jKGpzb25jKSAmJiBmcy5sc3RhdFN5bmMoanNvbmMpLmlzU3ltYm9saWNMaW5rKCkpIHRocm93IG5ldyBFcnJvcignUmVmdXNpbmcgdG8gcmVwbGFjZSBhIHN5bWxpbms6ICcgKyBqc29uYyk7CmNvbnN0IHN1ZmZpeCA9IERhdGUubm93KCkgKyAnLScgKyBjcnlwdG8ucmFuZG9tQnl0ZXMoNCkudG9TdHJpbmcoJ2hleCcpOwovLyBGaW5pc2ggYWxsIGJhY2t1cHMgYmVmb3JlIHJlcGxhY2luZyBhbnkgY29uZmlndXJhdGlvbi4KZm9yIChjb25zdCBmaWxlIG9mIFsuLi50YXJnZXRzLCAuLi4ocmVwbGFjZUFsbCA/IFtqc29uY10gOiBbXSldKSB7CiAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZmlsZSkpIGNvbnRpbnVlOwogICAgY29uc3QgYmFja3VwID0gZmlsZSArICcuc3ludGhsby1iYWNrdXAtJyArIHN1ZmZpeDsKICAgIGZzLmNvcHlGaWxlU3luYyhmaWxlLCBiYWNrdXAsIGZzLmNvbnN0YW50cy5DT1BZRklMRV9FWENMKTsKICAgIGZzLmNobW9kU3luYyhiYWNrdXAsIDBvNjAwKTsKICAgIGNvbnNvbGUubG9nKCdCYWNrdXA6ICcgKyBiYWNrdXApOwp9CmZvciAobGV0IGkgPSAwOyBpIDwgdGFyZ2V0cy5sZW5ndGg7IGkrKykgewogICAgY29uc3QgZmlsZSA9IHRhcmdldHNbaV07CiAgICBmcy5ta2RpclN5bmMocGF0aC5kaXJuYW1lKGZpbGUpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgbW9kZTogMG83MDAgfSk7CiAgICBjb25zdCB0bXAgPSBmaWxlICsgJy5zeW50aGxvLScgKyBzdWZmaXg7CiAgICB0cnkgewogICAgICAgIGZzLndyaXRlRmlsZVN5bmModG1wLCBKU09OLnN0cmluZ2lmeShuZXh0W2ldLCBudWxsLCAyKSArICdcbicsIHsgbW9kZTogMG82MDAsIGZsYWc6ICd3eCcgfSk7CiAgICAgICAgZnMucmVuYW1lU3luYyh0bXAsIGZpbGUpOwogICAgfSBmaW5hbGx5IHsgaWYgKGZzLmV4aXN0c1N5bmModG1wKSkgZnMudW5saW5rU3luYyh0bXApOyB9CiAgICBjb25zb2xlLmxvZygnQ29uZmlndXJlZDogJyArIGZpbGUpOwp9CmlmIChyZXBsYWNlQWxsICYmIGZzLmV4aXN0c1N5bmMoanNvbmMpKSBmcy51bmxpbmtTeW5jKGpzb25jKTsKY29uc29sZS5sb2coJ1JlYWR5LiBPcGVuIGEgbmV3IHRlcm1pbmFsIGluIHlvdXIgcHJvamVjdCwgdGhlbiBydW4gcGkgb3Igb3BlbmNvZGUuJyk7Cgp9KSgpLmNhdGNoKGVycm9yID0+IHsgY29uc29sZS5lcnJvcihlcnJvci5tZXNzYWdlKTsgcHJvY2Vzcy5leGl0Q29kZSA9IDE7IH0pOw==')) [IO.File]::WriteAllText($writerPath, $writer, (New-Object Text.UTF8Encoding($false))) & node.exe $writerPath if ($LASTEXITCODE -ne 0) { throw 'Synthlo configuration failed. See the error above.' } } finally { Remove-Item $writerPath -ErrorAction SilentlyContinue Remove-Item Env:SYNTHLO_TOKEN -ErrorAction SilentlyContinue Remove-Item Env:SYNTHLO_CONFIG -ErrorAction SilentlyContinue }