Fix Unknown subsystem entries and scroll cutoff at bottom
Details
Two issues:
1. "Unknown" group with 5 entries: Plugin SDK calls via TrackedSdkProxy
triggered GetOrCreateState() before DashboardPlugin.CreateViewModelCore
registered the plugin subsystems. The fallback created entries with
DisplayName="Unknown", Category="Unknown".
Fix: GetOrCreateState now infers display name and category from the
subsystem ID pattern. "plugin.privstack.notes" → DisplayName="Notes",
Category="Plugin". Non-plugin IDs get Category="Other" with the raw
ID as name. Register() now uses AddOrUpdate so explicit registration
from DashboardPlugin overwrites auto-created entries with the
authoritative PluginMetadata.Name.
2. Bottom scroll cutoff: Increased ScrollViewer bottom padding from 80
to 120 to clear the macOS dock + app status bar.
Add Auto-Check for Updates toggle in Settings > About
Details
The AutoCheckForUpdates setting existed in AppSettings and was wired in
the ViewModel but had no UI toggle — users couldn't disable it. Added a
ToggleSwitch in the About section (same card pattern as Notifications).
Track plugin SDK activity, fix status dots, guard reminders on setting
Details
Three issues with Subsystems tab accuracy:
1. Status dots: Green only showed for active tasks (task count > 0), so
subsystems with tracked memory but no running task (Crypto/Vault,
Auto-Update, Reminders) showed gray. Now green if tasks > 0 OR
native bytes > 0 OR managed alloc bytes > 0.
2. Plugin activity invisible: Plugins make all data calls through
Host.Sdk.SendAsync, but the shared SdkHost had no subsystem tracking.
Added TrackedSdkProxy that wraps IPrivStackSdk per-plugin — each
PluginHost now gets a scoped proxy tagged with "plugin.<id>". SDK
calls (SendAsync, CountAsync, SearchAsync) enter a subsystem scope,
so navigating to a plugin and loading data shows tracked memory.
3. Reminders allocating with notifications off: The scheduler started
its timer and initial poll unconditionally — PollAsync checked
NotificationsEnabled but already allocated before returning early.
Now guards in Start() itself: if notifications disabled, don't
create the timer or fire the initial poll at all.
Group Subsystems tab by category with section headers
Details
The flat list of ~30 subsystem rows was unmanageable and lacked visual
structure. Now grouped by category (Core, AI, Services, UI, Runtime,
Plugin) with each group showing a bold header, item count + active
summary, per-group column headers, and compact item rows.
- New SubsystemGroupViewModel holds category name, summary, and items
- RefreshSubsystemMetrics builds grouped collections instead of flat list
- XAML uses nested ItemsControl: outer for groups, inner for items
- Dropped the redundant Category column from each row (header shows it)
- Tighter row padding (6,8) and smaller font sizes for compact layout
- Inactive dots at 40% opacity for visual hierarchy
- Bottom padding (24,24,24,80) already handles the lower bar overlap
Use explicit BridgeEnabled setting for IPC server guard
Details
The previous guard checked BridgeAuthToken, but that token gets
auto-generated by NativeMessagingRegistrar.EnsureAuthToken() whenever
the bridge binary exists on disk — which it always does in dev builds.
So the check was always true.
Added BridgeEnabled (bool, default false) to AppSettings. The IPC server
now only starts when ApiEnabled || BridgeEnabled. The native messaging
registrar accepts an enableBridge flag to flip the setting when the user
explicitly installs the browser extension.
Get notified about new releases