Auto-refresh Dashboard stats every 5 seconds while visible
Details
Add a DispatcherTimer that refreshes memory usage (WorkingSet64,
GC heap), data storage totals (DuckDB file sizes), and detailed
storage breakdown every 5 seconds while the Dashboard tab is active.
The timer starts on OnNavigatedToAsync and stops on OnNavigatedFrom,
so it only polls while the Dashboard is actually visible. Uses the
existing SystemMetricsService for memory and GetDataMetricsAsync for
storage — both are lightweight local-only operations.
Bump Dashboard plugin version 1.3.0 → 1.4.0.
Unload AI models from memory when AI is disabled
Details
When the user toggles AI off in settings, the ONNX embedding model
(InferenceSession + tokenizer) and local LLM weights (LLamaWeights +
LLamaContext) were staying resident in memory because nothing called
Dispose or released the native resources. This caused ~1.7GB+ of
memory to persist even after AI was disabled.
Changes:
- Add EmbeddingService.UnloadAsync() — disposes the ONNX session and
tokenizer without permanently disposing the service, so it can be
re-initialized later via InitializeAsync()
- Add LocalLlamaProvider.UnloadModelAsync() — same pattern for the
LLama weights and context
- Add IEmbeddingService.UnloadAsync() to the interface contract
(+ HeadlessEmbeddingService no-op stub)
- Wire OnAiEnabledChanged(false) to call UnloadAiModelsAsync() which
releases both models and nudges GC to reclaim native buffers
- Add RagIndexService + EmbeddingService disposal to
MainWindowViewModel.Cleanup() for clean app shutdown
Fix Dashboard blocked by slow API health check (5-min timeout)
Details
Root cause: RefreshAsync populated AllPlugins AFTER awaiting
IsOnlineAsync(), which used PluginInstallService's 5-minute timeout
HttpClient for a simple health check. When privstack.io was slow or
unreachable, the entire dashboard sat on "Loading..." for minutes
with nothing rendered.
Fix: Split RefreshAsync into three phases:
1. PopulateLocalPlugins() — instant, no network. Builds AllPlugins
from filesystem manifests + IPluginRegistry.Plugins (the actually
loaded plugins). Sets IsLoading=false immediately so plugins render.
2. LoadSystemMetricsAsync() — local metrics (disk sizes, memory).
3. TryFetchRemoteRegistryAsync() — non-blocking enrichment with
server data. If it fails, local plugins are already displayed.
Also added a 5-second CancellationToken timeout to IsOnlineAsync()
so the health check doesn't inherit the 5-minute download timeout.
Fix Dashboard showing no plugins when registry is offline
Details
The previous fix handled the API timeout gracefully but the dashboard
still showed 0 plugins because GetInstalledVersions() only scans
~/.privstack/plugins and bundled plugin directories for manifest.json
files. In dev mode (project references) and when plugins are loaded
from non-standard paths, no manifests exist in those directories.
Added a fallback that populates AllPlugins from IPluginRegistry.Plugins
— the actually loaded/running plugins — for any plugin not already
covered by the server registry or filesystem manifests. This ensures
the dashboard always shows all active plugins with their metadata
regardless of how they were loaded.
Get notified about new releases