param( [string]$Origin = 'https://agentchat.innovacors.com', [string]$InstallDir = (Join-Path $env:LOCALAPPDATA 'AgentChat') ) # Instalador de AgentChat para Windows. Uso: irm https://TU-SERVIDOR/install.ps1 | iex # El servidor sustituye https://agentchat.innovacors.com por su propia URL, asi que no hace falta pasar parametros. $previousPreference = $ErrorActionPreference $ErrorActionPreference = 'Stop' function Get-AgentChatPrioritizedPath { param([string]$InstallDir, [string]$PathValue) $normalized = $InstallDir.TrimEnd('\') $entries = @($PathValue -split ';' | Where-Object { $_ -and $_.TrimEnd('\') -ne $normalized }) return (@($InstallDir) + $entries) -join ';' } try { $server = $null if (-not [uri]::TryCreate($Origin, [System.UriKind]::Absolute, [ref]$server)) { throw 'Indica el servidor: -Origin https://dominio' } if ($server.UserInfo -or $server.Query -or $server.Fragment -or $server.AbsolutePath -ne '/') { throw 'Origin debe ser solo https://dominio, sin ruta, credenciales ni parámetros.' } if ($server.Scheme -ne 'https' -and $server.Host -notin @('localhost', '127.0.0.1')) { throw 'Se requiere HTTPS fuera de localhost.' } $base = $server.GetLeftPart([System.UriPartial]::Authority).TrimEnd('/') $platform = 'windows-amd64' $name = 'agentchat.exe' # ngrok (plan gratuito) sirve una página intermedia a agentes tipo navegador, como el de PowerShell; esta cabecera la omite y otros servidores la ignoran. $headers = @{ 'ngrok-skip-browser-warning' = '1' } $checksum = (Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "$base/client/download/$platform.sha256").Content.Trim() $expected = ($checksum -split '\s+')[0].ToLowerInvariant() if ($expected -notmatch '^[a-f0-9]{64}$') { throw 'El servidor devolvió un checksum inválido.' } $temp = Join-Path ([System.IO.Path]::GetTempPath()) ("agentchat-" + [guid]::NewGuid().ToString('N') + '.exe') try { Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "$base/client/download/$platform" -OutFile $temp $sha = [System.Security.Cryptography.SHA256]::Create() try { $actual = [System.BitConverter]::ToString($sha.ComputeHash([System.IO.File]::ReadAllBytes($temp))).Replace('-', '').ToLowerInvariant() } finally { $sha.Dispose() } if ($actual -ne $expected) { throw 'El checksum del cliente no coincide; se canceló la instalación.' } New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null $target = Join-Path $InstallDir $name $backup = $target + '.previous' if (Test-Path -LiteralPath $backup) { Remove-Item -LiteralPath $backup -Force } if (Test-Path -LiteralPath $target) { Move-Item -LiteralPath $target -Destination $backup } try { Move-Item -LiteralPath $temp -Destination $target } catch { if (Test-Path -LiteralPath $backup) { Move-Item -LiteralPath $backup -Destination $target } throw } Write-Output "AgentChat instalado/actualizado: $target" # La carpeta Go debe preceder a npm para que `agentchat` resuelva al binario Go; AGENTCHAT_NO_PATH=1 lo evita. if (-not $PSBoundParameters.ContainsKey('InstallDir') -and $env:AGENTCHAT_NO_PATH -ne '1') { $userPath = Get-AgentChatPrioritizedPath -InstallDir $InstallDir -PathValue ([Environment]::GetEnvironmentVariable('Path', 'User')) [Environment]::SetEnvironmentVariable('Path', $userPath, 'User') $env:Path = Get-AgentChatPrioritizedPath -InstallDir $InstallDir -PathValue $env:Path try { if (-not ('AgentChatEnvironmentBroadcast' -as [type])) { Add-Type -TypeDefinition 'using System; using System.Runtime.InteropServices; public static class AgentChatEnvironmentBroadcast { [DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, string lParam, uint flags, uint timeout, out IntPtr result); }' } $broadcastResult = [IntPtr]::Zero [void][AgentChatEnvironmentBroadcast]::SendMessageTimeout([IntPtr]0xffff, 0x001A, [IntPtr]::Zero, 'Environment', 0x0002, 2000, [ref]$broadcastResult) } catch { } $first = Get-Command agentchat -ErrorAction SilentlyContinue | Select-Object -First 1 if ($first -and $first.Source -ne $target) { Write-Output "Aviso: PowerShell aún resuelve otro comando 'agentchat' ($($first.Source)). Abre una terminal nueva; el PATH de Go quedó primero." } else { Write-Output "Ya puedes escribir: agentchat --version (abre una terminal nueva para usarlo)." } } else { Write-Output "Para usarlo: & '$target' --version" } Write-Output "Para actualizar, vuelve a ejecutar el instalador." } finally { if (Test-Path -LiteralPath $temp) { Remove-Item -LiteralPath $temp -Force } } } finally { $ErrorActionPreference = $previousPreference }