# Instalador del comando tododeia. Cómo se usa: https://www.tododeia.com/instalar # # irm https://www.tododeia.com/install.ps1 | iex # tododeia instalar # # Para instalar algo de una vez: $env:TODODEIA_INSTALAR=""; irm https://www.tododeia.com/install.ps1 | iex # # Qué hace: baja el comando de www.tododeia.com, comprueba su huella sha256, lo deja en # %LOCALAPPDATA%\Programs\tododeia\tododeia.exe y agrega esa carpeta a tu PATH de usuario. # No pide permisos de administrador ni toca nada más. /instalar.ps1 es el mismo archivo. & { $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' # la barra de Invoke-WebRequest hace lentísima la descarga # Morir corta todo; el catch de abajo enseña solo el mensaje, sin la traza roja de PowerShell. function Morir($texto) { throw [Exception]::new("tododeia: $texto") } # En una consola abierta a mano no se lanza (cerraría la ventana con -File); en scripts y CI sí, para que fallen. $sinPantalla = @([Environment]::GetCommandLineArgs() | Where-Object { $_ -match '^-(noni|noninteractive)' }).Count -gt 0 $interactivo = [Environment]::UserInteractive -and $Host.Name -eq 'ConsoleHost' -and -not $sinPantalla -and -not $env:CI function SinBarra($ruta) { "$ruta".TrimEnd('\') } try { # Solo https:// o http://127.0.0.1: (pruebas), igual que el comando. $sitio = 'https://www.tododeia.com' if ($env:TODODEIA_SITIO) { $sitio = $env:TODODEIA_SITIO.TrimEnd('/') if ($sitio -notmatch '^(https://[A-Za-z0-9.-]+(:[0-9]+)?|http://127\.0\.0\.1:[0-9]+)$') { Morir 'TODODEIA_SITIO solo acepta https:// o http://127.0.0.1:' } } # Sistema: Windows de 64 bits, x64 o ARM64. if (-not [Environment]::Is64BitOperatingSystem) { Morir 'Tu Windows es de 32 bits y el comando solo existe para 64 bits.' } $arq = $env:PROCESSOR_ARCHITECTURE if ($env:PROCESSOR_ARCHITEW6432) { $arq = $env:PROCESSOR_ARCHITEW6432 } $target = 'windows-amd64' if ($arq -eq 'ARM64') { $target = 'windows-arm64' } [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 $ua = "tododeia-instalar ($target)" # La versión publicada y la huella de este sistema. try { $info = Invoke-RestMethod -Uri "$sitio/api/cli/version" -UserAgent $ua -UseBasicParsing } catch { Morir "No pude conectarme con $sitio ($($_.Exception.Message)). Revisa tu internet e intenta otra vez." } $esperada = "$($info.sha256.$target)".ToLower() if ($esperada -notmatch '^[0-9a-f]{64}$') { Morir "No hay versión del comando para $target todavía." } $carpeta = Join-Path $env:LOCALAPPDATA 'Programs\tododeia' $exe = Join-Path $carpeta 'tododeia.exe' New-Item -ItemType Directory -Force -Path $carpeta | Out-Null # El temporal vive junto al destino: el cambio final es un rename en el mismo disco. $tmp = Join-Path $carpeta (".tododeia-" + [Guid]::NewGuid().ToString('N') + '.exe') try { Write-Host "Bajando tododeia $($info.version) para $target..." try { Invoke-WebRequest -Uri "$sitio/api/cli/binario/$target" -OutFile $tmp -UserAgent $ua -UseBasicParsing } catch { Morir "La descarga falló ($($_.Exception.Message)). Intenta otra vez en un momento." } $huella = (Get-FileHash -Path $tmp -Algorithm SHA256).Hash.ToLower() if ($huella -ne $esperada) { Morir 'El archivo no coincide con el publicado (sha256 distinto). No instalé nada.' } # Si ya había uno (quizá corriendo), se aparta: Windows deja renombrar un .exe en uso, no pisarlo. if (Test-Path $exe) { if (Test-Path "$exe.old") { Remove-Item "$exe.old" -Force -ErrorAction SilentlyContinue if (Test-Path "$exe.old") { # Un .old que sigue abierto: se aparta con otro nombre y se limpia la próxima vez. Move-Item -Force "$exe.old" ("$exe.old-" + [Guid]::NewGuid().ToString('N')) -ErrorAction SilentlyContinue } } Get-ChildItem -Path $carpeta -Filter 'tododeia.exe.old-*' -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue try { Move-Item -Force $exe "$exe.old" } catch { Morir "No pude apartar el comando anterior ($($_.Exception.Message)). Cierra las terminales que lo estén usando e intenta otra vez." } } try { Move-Item -Force $tmp $exe } catch { Morir "No pude dejar el comando en $exe ($($_.Exception.Message))." } } finally { Remove-Item $tmp -Force -ErrorAction SilentlyContinue } # PATH de usuario: se agrega la carpeta una sola vez. Se lee SIN expandir (%USERPROFILE% y compañía se quedan # como están) y se escribe como REG_EXPAND_SZ, para no romper las entradas que usan variables. $llave = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment', $true) if (-not $llave) { $llave = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey('Environment') } try { $pathUsuario = $llave.GetValue('Path', '', [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) $partes = @() if ($pathUsuario) { $partes = @($pathUsuario.Split(';') | Where-Object { $_ }) } $yaEsta = @($partes | Where-Object { (SinBarra $_) -ieq (SinBarra $carpeta) }).Count -gt 0 if (-not $yaEsta) { $llave.SetValue('Path', (($partes + $carpeta) -join ';'), [Microsoft.Win32.RegistryValueKind]::ExpandString) # Avisa a Windows (WM_SETTINGCHANGE) para que las terminales nuevas vean el cambio. [Environment]::SetEnvironmentVariable('TODODEIA_AVISO_PATH', '1', 'User') [Environment]::SetEnvironmentVariable('TODODEIA_AVISO_PATH', $null, 'User') Write-Host "Agregué $carpeta a tu PATH. En terminales nuevas ya funciona tododeia." } } finally { $llave.Close() } $enSesion = @($env:Path.Split(';') | Where-Object { (SinBarra $_) -ieq (SinBarra $carpeta) }).Count -gt 0 if (-not $enSesion) { $env:Path = "$env:Path;$carpeta" } # ¿Hay otro tododeia.exe antes en el PATH? Ese ganaría. $primero = Get-Command tododeia -All -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1 if ($primero -and ($primero.Source -ne $exe)) { Write-Warning "Hay otro tododeia antes en tu PATH ($($primero.Source)) y ese es el que va a correr. Quítalo o pon $carpeta antes." } # Comprueba que corre antes de decir que quedó. & $exe --version | Out-Null if ($LASTEXITCODE -ne 0) { Morir "El comando quedó en $exe pero no arranca (código $LASTEXITCODE)." } Write-Host "Listo: quedó en $exe" -ForegroundColor Green if ($env:TODODEIA_INSTALAR) { $slugs = $env:TODODEIA_INSTALAR.Split(@(' ', ','), [StringSplitOptions]::RemoveEmptyEntries) & $exe instalar @slugs $codigo = $LASTEXITCODE if ($codigo -ne 0) { $global:LASTEXITCODE = $codigo if (-not $interactivo) { throw "tododeia instalar terminó con código $codigo" } } return } # Deja la skill tododeia para que Claude Code y Codex sepan usar el comando. & $exe preparar | Out-Null if ($LASTEXITCODE -ne 0) { Write-Warning 'No pude dejar la skill tododeia para Claude Code y Codex; se escribe sola la próxima vez que uses el comando.' } Write-Host '' Write-Host 'Para empezar:' Write-Host ' tododeia buscar (lo que hay en la Bóveda)' Write-Host ' tododeia instalar (skills: para todo; herramientas y agentes: en la carpeta donde estés)' $global:LASTEXITCODE = 0 } catch { Write-Host $_.Exception.Message -ForegroundColor Red if (-not $global:LASTEXITCODE) { $global:LASTEXITCODE = 1 } if (-not $interactivo) { throw } } finally { Remove-Item Env:TODODEIA_INSTALAR -ErrorAction SilentlyContinue } }