Add HeadlessPluginBase and update plugin scanning for headless split
Details
Add HeadlessPluginBase to PrivStack.Sdk — an abstract IAppPlugin
implementation with no-op defaults for UI methods (CreateViewModel,
navigation, etc.). Headless plugin assemblies extend this to provide
services, capabilities, and API routes without Avalonia dependencies.
Update HeadlessPluginRegistry to prioritize .Headless.dll assemblies
(sorted first in scan order) so they load before their full Avalonia
counterparts. Plugin ID deduplication prevents double-loading.
Update run-server.sh to build .Headless plugin projects in a first
pass, then skip full plugins that have a headless variant.
Add run-server.sh dev launcher for headless server
Details
Points at test-data/ by default (same DB as build.sh --run --with-plugins).
Use --live for the system data directory, --workspace to skip the picker.
Add interactive workspace picker to headless server
Details
When starting without --workspace, the server now:
- Single workspace: auto-selects it
- Multiple workspaces: shows an interactive numbered menu
- No workspaces: offers to create one
- Non-interactive (piped stdin): uses active workspace or errors
Also lists available workspace names when --workspace doesn't match.
Fix DI deadlock in headless server plugin discovery
Details
HeadlessPluginRegistry's constructor created PluginHostFactory eagerly,
which resolved IPluginRegistry from DI — causing a circular dependency
deadlock (DI was still constructing HeadlessPluginRegistry itself).
Fix: lazy-initialize PluginHostFactory on first use via a property.
Also switch HeadlessHost to call DiscoverAndInitializeAsync() directly
instead of the sync wrapper that used .GetAwaiter().GetResult(), and
wrap GetExportedTypes() in try-catch for ReflectionTypeLoadException
to handle assemblies with unresolvable type dependencies gracefully.
Get notified about new releases