# Agent J emergency rescue on Windows (P332). Agent J on Windows runs inside WSL; this script runs the same rescue as # Linux / macOS (https://agentj.app/rescue.sh, SHA-256 pinned below) inside the WSL distro, in this same window. # # irm https://agentj.app/rescue.ps1 | iex # $env:AGENTJ_TICKET='st_…'; irm https://agentj.app/rescue.ps1 | iex read the reply to an earlier ticket # $env:AGENTJ_WSL_DISTRO='Debian'; irm https://agentj.app/rescue.ps1 | iex Agent J lives in another distro # # Read-only on the Windows side: it installs nothing, asks for no administrator rights and changes no Windows setting. # If WSL or the distro is missing it says so and stops (then Agent J was never installed on this Windows). # Works in Windows PowerShell 5.1 and PowerShell 7. $ErrorActionPreference = 'Stop' $Help = 'https://agentj.app/rescue/' $RescueShSha256 = '581788dc9907bddfbdd3859bde9b27ec63867cf94238df109fe1ada1081811d2' $Distro = if ($env:AGENTJ_WSL_DISTRO) { $env:AGENTJ_WSL_DISTRO } else { 'Ubuntu' } $env:WSL_UTF8 = '1' # wsl.exe writes UTF-16 by default; PowerShell would read it as garbage $Wsl = if ($env:AGENTJ_WSL_EXE) { $env:AGENTJ_WSL_EXE } else { 'wsl.exe' } # tests point this at a stand-in function Say([string]$Text) { Write-Host $Text } function Fail([string]$What, [string]$Next) { Write-Host '' Write-Host ('✗ ' + $What) -ForegroundColor Red Write-Host (' 怎么办 / What to do: ' + $Next) Write-Host (' 帮助 / Help: ' + $Help) throw 'Agent J rescue stopped' } # Optional inputs travel as checked plain tokens only: nothing typed here ever becomes part of a Linux command line. function Get-RescueArgs([string]$Ticket, [string]$Lang) { $a = '' if ($Lang -eq 'en') { $a += ' --en' } if ($Ticket) { $t = $Ticket.Trim() if ($t -notmatch '^st_[A-Za-z0-9_-]{22}$') { return $null } $a += ' --ticket ' + $t } return $a } if ($env:AGENTJ_RESCUE_PS1_TEST -eq 'extract') { return } # unit tests dot-source the functions above Say 'Agent J 紧急救援(Windows)/ Agent J emergency rescue (Windows)' Say '在 WSL 里检查、修好能安全修的地方、把去掉隐私的报告发给 Agent J Father。随时按 Ctrl+C 停下。' Say 'Checks Agent J inside WSL, repairs what is safe, sends a redacted report to Agent J Father. Ctrl+C stops it.' $rescueArgs = Get-RescueArgs $env:AGENTJ_TICKET $env:AGENTJ_RESCUE_LANG if ($null -eq $rescueArgs) { Fail '工单号的格式不对 / the ticket number looks wrong' '工单号是 st_ 加 22 个字符 / a ticket is st_ followed by 22 characters' } if ($Distro -notmatch '^[A-Za-z0-9._-]{1,64}$') { Fail 'AGENTJ_WSL_DISTRO 的名字不对 / AGENTJ_WSL_DISTRO is not a distro name' '只用 wsl --list 里显示的名字 / use a name exactly as wsl --list shows it' } # 1. WSL itself if (-not $env:AGENTJ_WSL_EXE -and -not (Get-Command $Wsl -ErrorAction SilentlyContinue)) { Fail '这台 Windows 没有 WSL,所以这里没有装 Agent J(Windows 上的 Agent J 只在 WSL 里运行)。/ This Windows has no WSL, so Agent J is not installed here (on Windows, Agent J runs only inside WSL).' ` '如果 Agent J 装在别的电脑上,请在那台电脑上运行;要在这台装,看 https://agentj.app/docs/install/#windows / If Agent J is on another computer, run this there; to install it here see https://agentj.app/docs/install/#windows' } $have = '' try { $have = ((& $Wsl --list --quiet 2>$null) -join "`n") -replace "`0", '' } catch { $have = '' } if ($have -notmatch "(?m)^\s*$([regex]::Escape($Distro))\s*$") { $names = (($have -split "`n") | ForEach-Object { $_.Trim() } | Where-Object { $_ }) -join ', ' if (-not $names) { $names = '无 / none' } Fail ("WSL 里没有「$Distro」,所以找不到 Agent J。已有的发行版:$names / WSL has no '$Distro', so Agent J is not there. Distros found: $names") ` ('如果 Agent J 装在别的发行版里,先运行 $env:AGENTJ_WSL_DISTRO=''名字'',再粘贴同一行 / If Agent J is in another distro, run $env:AGENTJ_WSL_DISTRO=''name'' first, then paste the same line again') } # 2. the rescue inside the distro, as its default user (the one Agent J runs as), in this window. # Windows PowerShell 5.1 drops empty arguments and does not escape embedded quotes for native programs, so the script # never travels as a quoted argument: it goes base64-encoded (only [A-Za-z0-9+/=]) and runs from a temporary file. $run = @" f=`$(mktemp) || exit 4 if command -v curl >/dev/null 2>&1; then curl --proto '=https' --tlsv1.2 -fsSL https://agentj.app/rescue.sh -o "`$f" elif command -v wget >/dev/null 2>&1; then wget -q --https-only -O "`$f" https://agentj.app/rescue.sh else echo '✗ WSL 里没有 curl 或 wget,下载不了救援脚本 / no curl or wget inside WSL'; rm -f "`$f"; exit 4; fi [ -s "`$f" ] || { echo '✗ 救援脚本下载失败:WSL 里连不上 agentj.app / could not download the rescue script: WSL cannot reach agentj.app'; rm -f "`$f"; exit 4; } got=`$(sha256sum "`$f" | cut -d' ' -f1) [ "`$got" = '$RescueShSha256' ] || { echo '✗ 救援脚本校验不对:过几分钟再试 / the rescue script failed its checksum: try again in a few minutes'; rm -f "`$f"; exit 4; } sh "`$f"$rescueArgs