fix(launch): reliable Windows launcher; feat(ui): compact sidebar, Vite toggle, chat Think toggle
Ported from the private repo via bin/publish.sh, plus a manual catch-up on files that had drifted out of sync before today: - launch_nexus.ps1: health-check based restart decisions instead of a bare port-listen check (a wedged leftover process squatting a port used to look "already running" and block the real service from starting), a script-path quoting fix for Start-Process, hidden console via a wscript.exe wrapper (bin/launch_nexus_hidden.vbs), and a taskbar/window icon for the native app window. - Sidebar: slim icon+text nav rows instead of bulky bordered buttons, tighter spacing throughout. - Settings: full-width layout, a Vite dev-server Start/Stop toggle (synapse/frontend_manager.py + /frontend/* endpoints), and the Linux-only Icon Branding section now gated on the new /status `platform` field instead of always rendering. - Chatbot: a Think toggle next to the model picker, so extended thinking can be flipped without leaving the chat page. - management/ncp.py: faster start/stop polling (0.25s steps instead of 1s), Vite no longer blocks `ncp start` on Linux and is skipped outright on Windows. Note: the private repo also has a Mail (IMAP/SMTP) feature; it's intentionally not included here, so the Mail-only pieces of main.py, App.jsx, and requirements-windows.txt were left out of this port.
This commit is contained in:
+31
-14
@@ -202,6 +202,14 @@ def check(svc: Service) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
# Poll granularity for both waiters below. 1s steps used to mean every
|
||||
# start/stop paid up to a full second of dead latency per service on top of
|
||||
# however long the process actually took - three services in sequence could
|
||||
# lose several seconds to nothing but sleep(). 0.25s still amounts to one
|
||||
# cheap local HTTP HEAD every quarter second, not a busy-loop.
|
||||
_POLL_STEP = 0.25
|
||||
|
||||
|
||||
def wait_for_port(svc: Service, timeout: int = 30) -> bool:
|
||||
if http_ok(svc.url):
|
||||
# "READY", not "already running": `ncp start` launches memory and backend
|
||||
@@ -210,8 +218,8 @@ def wait_for_port(svc: Service, timeout: int = 30) -> bool:
|
||||
# this same command started two seconds ago reads like a stale process.
|
||||
print(f" {svc.label} READY (:{svc.port})")
|
||||
return True
|
||||
for _ in range(timeout):
|
||||
time.sleep(1)
|
||||
for _ in range(int(timeout / _POLL_STEP)):
|
||||
time.sleep(_POLL_STEP)
|
||||
if http_ok(svc.url):
|
||||
print(f"{svc.label} STARTED")
|
||||
return True
|
||||
@@ -220,10 +228,10 @@ def wait_for_port(svc: Service, timeout: int = 30) -> bool:
|
||||
|
||||
|
||||
def wait_for_port_close(port: int, timeout: int = 15) -> bool:
|
||||
for _ in range(timeout):
|
||||
for _ in range(int(timeout / _POLL_STEP)):
|
||||
if not http_ok(f"http://localhost:{port}/"):
|
||||
return True
|
||||
time.sleep(1)
|
||||
time.sleep(_POLL_STEP)
|
||||
return False
|
||||
|
||||
|
||||
@@ -353,24 +361,33 @@ def cmd_start(target) -> None:
|
||||
elif target in ("--ai", "-a"):
|
||||
start_ollama()
|
||||
elif target in (None, "", "all"):
|
||||
# Bring the UI up first, then warm Ollama in the background — the model
|
||||
# loads concurrently and into the first chat instead of blocking boot.
|
||||
# Bring the UI up first, then kick off Ollama and (on Linux) Vite in the
|
||||
# background without waiting on either — neither gates the app being
|
||||
# usable. The backend already serves the built interface/web/dist at
|
||||
# :8000 on both platforms (single-process design), and that's the URL
|
||||
# nexus-app.sh/ncp web actually opens; nothing points a user at :5173.
|
||||
# Vite only exists for whoever is hot-reload-editing the frontend, and
|
||||
# they'll open :5173 themselves once it's ready - polling for it here
|
||||
# just delayed "boot done" for a benefit nobody in the critical path
|
||||
# gets. Skipped outright on Windows, where it's not part of the normal
|
||||
# workflow at all and is the slow part of `ncp stop` to boot (npm's
|
||||
# cmd.exe -> node -> esbuild tree doesn't die from a plain terminate()
|
||||
# and falls through to the ~30s force-kill path). Still available on
|
||||
# demand via `ncp start --frontend`.
|
||||
t0 = time.perf_counter()
|
||||
launch(SERVICES["memory"])
|
||||
launch(SERVICES["backend"])
|
||||
wait_for_port(SERVICES["memory"])
|
||||
wait_for_port(SERVICES["backend"])
|
||||
t_services = time.perf_counter()
|
||||
launch(SERVICES["frontend"])
|
||||
wait_for_port(SERVICES["frontend"])
|
||||
t_frontend = time.perf_counter()
|
||||
start_ollama(background=True)
|
||||
t_ollama = time.perf_counter()
|
||||
if not WINDOWS:
|
||||
launch(SERVICES["frontend"])
|
||||
t_bg = time.perf_counter()
|
||||
print("\nBoot timing:")
|
||||
print(f" services (memory+backend) : {t_services - t0:5.1f}s")
|
||||
print(f" frontend (UI ready) : {t_frontend - t_services:5.1f}s")
|
||||
print(f" ollama kickoff (bg warm) : {t_ollama - t_frontend:5.1f}s")
|
||||
print(f" total to interactive : {t_ollama - t0:5.1f}s")
|
||||
print(f" services (memory+backend) : {t_services - t0:5.1f}s")
|
||||
print(f" ollama + frontend (bg kickoff) : {t_bg - t_services:5.1f}s")
|
||||
print(f" total to interactive : {t_bg - t0:5.1f}s")
|
||||
else:
|
||||
show_help()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user