uninstall.ps1
Rama main · réplica de lectura del repositorio original.
#
# Uninstaller for the bare-metal Windows install. Everything Jun
# created lives either in this folder or as a normal app under
# Settings > Apps, so removal is:
# 1. stop the running processes (start.ps1 stop)
# 2. optionally uninstall Ollama / llama.cpp (machine-wide apps)
# 3. take Jun's local certificate authority back out of your
# Windows trust store, if start.ps1 put it there
# 4. delete this folder (webapp, PHP, TTS venv, model weights,
# chat data)
#
# git (and Python, if voice or asset recovery installed it) are
# left alone. They are general-purpose tools you may use
# elsewhere. Remove them yourself from Settings > Apps if you
# want.
#
# ./uninstall.ps1 # interactive
# ./uninstall.ps1 -Yes # no prompts
# Stops services, removes llama.cpp and Ollama if present
# (including Ollama's %USERPROFILE%\.ollama model store),
# then deletes this folder.
[CmdletBinding()]
param([switch]$Yes)
$ErrorActionPreference = 'Stop'
$root = $PSScriptRoot
# JunOS.exe opens this in its own window, which closes the moment
# the script ends. Keep the error on screen.
trap {
Write-Host ''
Write-Host "Uninstall stopped: $($_.Exception.Message)" -ForegroundColor Red
Write-Host "Whatever is left is still in $root. Close anything running from it (Task Manager: caddy, php, python, llama-server) and run uninstall.ps1 again, or delete the folder."
if (-not $Yes) { Read-Host 'Press Enter to close' | Out-Null }
exit 1
}
function Confirm-Step([string]$question) {
if ($Yes) { return $true }
return (Read-Host "$question [y/N]") -match '^(y|yes)$'
}
Write-Host "This removes Jun from: $root"
Write-Host "Chat history, settings and downloaded models in that folder will be deleted."
if (-not (Confirm-Step 'Continue?')) { Write-Host 'Aborted, nothing touched.'; exit 0 }
$start = Join-Path $root 'start.ps1'
if (Test-Path $start) {
& $start stop
}
# The model servers are the machine-wide pieces Jun really
# installed for itself (which one depends on the provider chosen
# at install time).
if (Get-Command llama-server -ErrorAction SilentlyContinue) {
if (Confirm-Step 'Uninstall llama.cpp too (machine-wide app)?') {
Get-Process 'llama-server*' -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
winget uninstall -e --id ggml.llamacpp
# Models Jun downloaded live in runtime\llama-cache (deleted
# below).
}
}
if (Get-Command ollama -ErrorAction SilentlyContinue) {
if (Confirm-Step 'Uninstall Ollama too (machine-wide app)?') {
Get-Process 'ollama*' -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
# install.ps1 runs OllamaSetup.exe directly, so the Inno
# uninstaller sits next to ollama.exe. winget is only for an
# Ollama that came from somewhere else.
$unins = Join-Path (Split-Path -Parent (Get-Command ollama).Source) 'unins000.exe'
if (Test-Path $unins) {
Start-Process $unins -ArgumentList '/VERYSILENT', '/NORESTART' -Wait
} else {
winget uninstall -e --id Ollama.Ollama
}
# Models pulled by Jun live in runtime\ollama-models (deleted
# below), but a pre-existing / self-started Ollama keeps its own
# store:
$store = Join-Path $env:USERPROFILE '.ollama'
if (Test-Path $store) {
$gb = [math]::Round((Get-ChildItem $store -Recurse -File -ErrorAction SilentlyContinue |
Measure-Object Length -Sum).Sum / 1GB, 1)
if (Confirm-Step "Also delete $store (~${gb} GB of models)?") {
Remove-Item $store -Recurse -Force
}
}
}
}
# runtime\caddy\tls\trusted holds the thumbprint start.ps1 added
# to the current user's Root store. Windows asks to confirm the
# removal.
$trustMark = Join-Path $root 'runtime\caddy\tls\trusted'
if (Test-Path -LiteralPath $trustMark) {
$thumb = (Get-Content -LiteralPath $trustMark -Raw).Trim()
if ($thumb -and (Confirm-Step "Remove Jun's local certificate authority from your trust store?")) {
$store = [Security.Cryptography.X509Certificates.X509Store]::new('Root', 'CurrentUser')
$store.Open('ReadWrite')
try {
foreach ($c in $store.Certificates.Find('FindByThumbprint', $thumb, $false)) { $store.Remove($c) }
Write-Host 'Removed the local certificate authority.'
} catch {
Write-Host "Could not remove it ($($_.Exception.Message)). Remove ""Jun OS local CA"" from certmgr.msc > Trusted Root Certification Authorities."
} finally {
$store.Close()
}
}
}
# Only shortcuts that point into this folder. Another install may
# own a "Jun OS" shortcut of its own.
$shell = New-Object -ComObject WScript.Shell
foreach ($folder in @([Environment]::GetFolderPath('Desktop'), [Environment]::GetFolderPath('Programs'))) {
if (-not $folder) { continue }
$path = Join-Path $folder 'Jun OS.lnk'
if (-not (Test-Path -LiteralPath $path)) { continue }
$lnk = $shell.CreateShortcut($path)
if ($lnk.WorkingDirectory -ieq $root -or $lnk.TargetPath.StartsWith($root, [StringComparison]::OrdinalIgnoreCase)) {
Remove-Item -LiteralPath $path -Force
Write-Host "Removed shortcut $path"
}
}
# JunOS.exe can still be running if it was opened again after the
# uninstall started. It would keep the folder from being deleted.
Get-Process JunOS -ErrorAction SilentlyContinue |
Where-Object { $_.Path -and $_.Path.StartsWith($root, [StringComparison]::OrdinalIgnoreCase) } |
Stop-Process -Force -ErrorAction SilentlyContinue
# From outside the folder, since this script lives inside it.
Set-Location $env:USERPROFILE
# Windows releases a stopped process's files a moment after it exits.
for ($try = 1; ; $try++) {
try { Remove-Item -LiteralPath $root -Recurse -Force -ErrorAction Stop; break }
catch { if ($try -ge 5) { throw } }
Start-Sleep -Seconds 2
}
Write-Host "Removed $root. Jun is uninstalled."
Write-Host 'Left in place: git and any Python installed for voice or asset recovery - remove via Settings > Apps if unwanted.'