fix(install-windows): pull models last, so Ctrl+C can't abort the install
Ctrl+C in PS 5.1 kills the whole script, and the multi-GB model pull sat in the middle -- skipping the download also skipped the ncp PATH registration and the desktop shortcut. Moves the pull after them. Also drops the pipe that buffered ollama's progress bar (a running download looked like a hang) and replaces a try/catch that native commands never trigger with $LASTEXITCODE checks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+68
-60
@@ -106,64 +106,6 @@ if (-not (Test-Path (Join-Path $RepoRoot "interface\web\dist\index.html"))) {
|
|||||||
}
|
}
|
||||||
Write-OK "Web UI built (interface\web\dist)"
|
Write-OK "Web UI built (interface\web\dist)"
|
||||||
|
|
||||||
# -- Pull models (best-effort) -------------------------------------------------
|
|
||||||
# Which models ship is decided in ONE place - DEFAULT_CHAT_MODEL and
|
|
||||||
# DEFAULT_MEMORY_MODEL in synapse\nexus_config.py (rationale documented there).
|
|
||||||
# Read them instead of hardcoding, so the installer can never pull one model
|
|
||||||
# while the backend defaults to another.
|
|
||||||
Push-Location $RepoRoot
|
|
||||||
$ChatModel = (& $VenvPy -c "from synapse.nexus_config import DEFAULT_CHAT_MODEL as m; print(m)")
|
|
||||||
$MemModel = (& $VenvPy -c "from synapse.nexus_config import DEFAULT_MEMORY_MODEL as m; print(m)")
|
|
||||||
Pop-Location
|
|
||||||
if ($LASTEXITCODE -ne 0 -or -not $ChatModel -or -not $MemModel) {
|
|
||||||
Write-Fail "Could not read the default models from synapse\nexus_config.py - the venv install is broken"
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Step "Pulling models ($ChatModel for chat, $MemModel for memory)"
|
|
||||||
Write-Host " Downloads a few GB; press Ctrl+C to skip and pull them later from the Models tab." -ForegroundColor DarkGray
|
|
||||||
try {
|
|
||||||
ollama pull $ChatModel | Out-Host
|
|
||||||
Write-OK "$ChatModel ready (default chat model)"
|
|
||||||
} catch {
|
|
||||||
Write-Warn "$ChatModel pull skipped/failed - pull it from the Models tab later."
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
ollama pull $MemModel | Out-Host
|
|
||||||
Write-OK "$MemModel ready (memory curator)"
|
|
||||||
} catch {
|
|
||||||
Write-Warn "$MemModel pull skipped/failed - the memory service will fall back to the chat model."
|
|
||||||
}
|
|
||||||
|
|
||||||
# Pin it as the default chat model. Runs from the repo root so the synapse
|
|
||||||
# package imports; only writes the 'model' setting in the shared DB.
|
|
||||||
Write-Step "Setting $ChatModel as the default model"
|
|
||||||
Push-Location $RepoRoot
|
|
||||||
& $VenvPy -c "from synapse.memory.store import store; from synapse.nexus_config import DEFAULT_CHAT_MODEL; store.update_settings({'model': DEFAULT_CHAT_MODEL})"
|
|
||||||
$seedOk = ($LASTEXITCODE -eq 0)
|
|
||||||
Pop-Location
|
|
||||||
if ($seedOk) { Write-OK "Default model set to $ChatModel" }
|
|
||||||
else { Write-Warn "Could not persist default model - pick it at the top of the chat instead." }
|
|
||||||
|
|
||||||
# -- Make Ollama manual-start (NexusOS owns the lifecycle) ----------------------
|
|
||||||
Write-Step "Setting Ollama to manual start"
|
|
||||||
# The Ollama desktop app autostarts a server at every login, and the elevated
|
|
||||||
# 'ollama pull' above leaves an elevated server the user-level app cannot stop -
|
|
||||||
# which makes the Start/Stop AI button get stuck. Remove the login autostart and
|
|
||||||
# stop the running server so NexusOS controls Ollama via its Start AI button.
|
|
||||||
try {
|
|
||||||
$ollamaAutostart = Join-Path ([Environment]::GetFolderPath("Startup")) "Ollama.lnk"
|
|
||||||
if (Test-Path $ollamaAutostart) {
|
|
||||||
Remove-Item $ollamaAutostart -Force
|
|
||||||
Write-OK "Removed Ollama login autostart"
|
|
||||||
}
|
|
||||||
foreach ($img in @("ollama app.exe", "ollama.exe")) {
|
|
||||||
taskkill /F /T /IM $img 2>$null | Out-Null
|
|
||||||
}
|
|
||||||
Write-OK "Ollama set to manual start"
|
|
||||||
} catch {
|
|
||||||
Write-Warn "Could not adjust Ollama autostart - you can still Start/Stop AI from the app."
|
|
||||||
}
|
|
||||||
|
|
||||||
# -- ncp command ---------------------------------------------------------------
|
# -- ncp command ---------------------------------------------------------------
|
||||||
# management\ncp.cmd goes on the machine PATH rather than a `function ncp` in the
|
# management\ncp.cmd goes on the machine PATH rather than a `function ncp` in the
|
||||||
# PowerShell profile. Three reasons the profile route kept biting:
|
# PowerShell profile. Three reasons the profile route kept biting:
|
||||||
@@ -220,6 +162,72 @@ try {
|
|||||||
Write-Warn "Could not create desktop shortcut - launch with: powershell -File launch_nexus.ps1"
|
Write-Warn "Could not create desktop shortcut - launch with: powershell -File launch_nexus.ps1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -- Pull models (best-effort, LAST on purpose) --------------------------------
|
||||||
|
# This is the only multi-GB step, and the only one a user is invited to Ctrl+C.
|
||||||
|
# Ctrl+C in PowerShell 5.1 terminates the whole SCRIPT, not just the running
|
||||||
|
# native command - so with this block in the middle, skipping the download also
|
||||||
|
# skipped the PATH registration and the desktop shortcut, and left an install
|
||||||
|
# that looked finished but had no working `ncp`. Everything that makes NexusOS
|
||||||
|
# usable now runs before we get here; abort at this point and you lose only the
|
||||||
|
# models, which the Models tab can pull later.
|
||||||
|
#
|
||||||
|
# Which models ship is decided in ONE place - DEFAULT_CHAT_MODEL and
|
||||||
|
# DEFAULT_MEMORY_MODEL in synapse\nexus_config.py (rationale documented there).
|
||||||
|
# Read them instead of hardcoding, so the installer can never pull one model
|
||||||
|
# while the backend defaults to another.
|
||||||
|
Push-Location $RepoRoot
|
||||||
|
$ChatModel = (& $VenvPy -c "from synapse.nexus_config import DEFAULT_CHAT_MODEL as m; print(m)")
|
||||||
|
$MemModel = (& $VenvPy -c "from synapse.nexus_config import DEFAULT_MEMORY_MODEL as m; print(m)")
|
||||||
|
Pop-Location
|
||||||
|
if ($LASTEXITCODE -ne 0 -or -not $ChatModel -or -not $MemModel) {
|
||||||
|
Write-Fail "Could not read the default models from synapse\nexus_config.py - the venv install is broken"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step "Pulling models ($ChatModel for chat, $MemModel for memory)"
|
||||||
|
Write-Host " Downloads a few GB; press Ctrl+C to skip and pull them later from the Models tab." -ForegroundColor DarkGray
|
||||||
|
# No pipe: 'ollama pull' draws a progress bar with cursor control, and piping it
|
||||||
|
# (to Out-Host or anything else) buffers the redraws - the download then shows no
|
||||||
|
# output for minutes and reads as a hang. Let it own the console.
|
||||||
|
# No try/catch either: a native command that exits non-zero does not throw, so
|
||||||
|
# the catch never fired and a failed pull was reported as success.
|
||||||
|
ollama pull $ChatModel
|
||||||
|
if ($LASTEXITCODE -eq 0) { Write-OK "$ChatModel ready (default chat model)" }
|
||||||
|
else { Write-Warn "$ChatModel pull skipped/failed - pull it from the Models tab later." }
|
||||||
|
|
||||||
|
ollama pull $MemModel
|
||||||
|
if ($LASTEXITCODE -eq 0) { Write-OK "$MemModel ready (memory curator)" }
|
||||||
|
else { Write-Warn "$MemModel pull skipped/failed - the memory service will fall back to the chat model." }
|
||||||
|
|
||||||
|
# Pin it as the default chat model. Runs from the repo root so the synapse
|
||||||
|
# package imports; only writes the 'model' setting in the shared DB.
|
||||||
|
Write-Step "Setting $ChatModel as the default model"
|
||||||
|
Push-Location $RepoRoot
|
||||||
|
& $VenvPy -c "from synapse.memory.store import store; from synapse.nexus_config import DEFAULT_CHAT_MODEL; store.update_settings({'model': DEFAULT_CHAT_MODEL})"
|
||||||
|
$seedOk = ($LASTEXITCODE -eq 0)
|
||||||
|
Pop-Location
|
||||||
|
if ($seedOk) { Write-OK "Default model set to $ChatModel" }
|
||||||
|
else { Write-Warn "Could not persist default model - pick it at the top of the chat instead." }
|
||||||
|
|
||||||
|
# -- Make Ollama manual-start (NexusOS owns the lifecycle) ----------------------
|
||||||
|
Write-Step "Setting Ollama to manual start"
|
||||||
|
# The Ollama desktop app autostarts a server at every login, and the elevated
|
||||||
|
# 'ollama pull' above leaves an elevated server the user-level app cannot stop -
|
||||||
|
# which makes the Start/Stop AI button get stuck. Remove the login autostart and
|
||||||
|
# stop the running server so NexusOS controls Ollama via its Start AI button.
|
||||||
|
try {
|
||||||
|
$ollamaAutostart = Join-Path ([Environment]::GetFolderPath("Startup")) "Ollama.lnk"
|
||||||
|
if (Test-Path $ollamaAutostart) {
|
||||||
|
Remove-Item $ollamaAutostart -Force
|
||||||
|
Write-OK "Removed Ollama login autostart"
|
||||||
|
}
|
||||||
|
foreach ($img in @("ollama app.exe", "ollama.exe")) {
|
||||||
|
taskkill /F /T /IM $img 2>$null | Out-Null
|
||||||
|
}
|
||||||
|
Write-OK "Ollama set to manual start"
|
||||||
|
} catch {
|
||||||
|
Write-Warn "Could not adjust Ollama autostart - you can still Start/Stop AI from the app."
|
||||||
|
}
|
||||||
|
|
||||||
# -- Done ----------------------------------------------------------------------
|
# -- Done ----------------------------------------------------------------------
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host " ==========================================================" -ForegroundColor Green
|
Write-Host " ==========================================================" -ForegroundColor Green
|
||||||
@@ -231,8 +239,8 @@ Write-Host ""
|
|||||||
Write-Host " The app opens at http://localhost:8000" -ForegroundColor White
|
Write-Host " The app opens at http://localhost:8000" -ForegroundColor White
|
||||||
Write-Host " The AI starts OFF - click 'Start AI' in the sidebar to turn it on." -ForegroundColor White
|
Write-Host " The AI starts OFF - click 'Start AI' in the sidebar to turn it on." -ForegroundColor White
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host " Terminal: open a NEW PowerShell window, then run ncp help" -ForegroundColor White
|
Write-Host " Terminal: open a NEW terminal (PowerShell or cmd), then run ncp help" -ForegroundColor White
|
||||||
Write-Host " (the profile that defines ncp is only read at startup)" -ForegroundColor DarkGray
|
Write-Host " (PATH is read at process start, so open windows lack it)" -ForegroundColor DarkGray
|
||||||
Write-Host " ==========================================================" -ForegroundColor Green
|
Write-Host " ==========================================================" -ForegroundColor Green
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Read-Host "Press Enter to close"
|
Read-Host "Press Enter to close"
|
||||||
|
|||||||
@@ -86,6 +86,16 @@ def test_ncp_is_registered_on_path_not_in_a_shell_profile():
|
|||||||
assert "setx" not in code.lower()
|
assert "setx" not in code.lower()
|
||||||
assert 'SetEnvironmentVariable("Path"' in code
|
assert 'SetEnvironmentVariable("Path"' in code
|
||||||
|
|
||||||
|
# The model pull is the only multi-GB step and the only one the script
|
||||||
|
# invites a Ctrl+C on -- which in PS 5.1 kills the whole script. Anything
|
||||||
|
# after it is lost, so it has to come last. It used to sit in the middle,
|
||||||
|
# and skipping the download silently skipped the ncp registration too.
|
||||||
|
assert ps1.index("ollama pull") > ps1.index("Registering the ncp command"), \
|
||||||
|
"model pull must come after ncp registration - a Ctrl+C there aborts the installer"
|
||||||
|
assert ps1.index("ollama pull") > ps1.index("Creating desktop shortcut"), \
|
||||||
|
"model pull must come after the desktop shortcut"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_first_playbook_is_the_system_prompt(tmp_path, monkeypatch):
|
def test_first_playbook_is_the_system_prompt(tmp_path, monkeypatch):
|
||||||
store = PlaybookFileStore(tmp_path)
|
store = PlaybookFileStore(tmp_path)
|
||||||
|
|||||||
Reference in New Issue
Block a user