Add SDK transport abstraction for Desktop client mode
Details
Extract FFI calls from SdkHost into ISdkTransport interface with two
implementations:
- FfiSdkTransport: wraps NativeLibrary P/Invoke calls with pointer
marshalling (standalone mode, existing behavior)
- HttpSdkTransport: proxies SDK calls over HTTP to a running headless
server (client mode, new)
When Desktop detects a running headless server at startup (probes
GET /api/v1/status), it switches to client mode: swaps the transport
from FFI to HTTP, skips DuckDB initialization and the unlock screen,
and routes all plugin data operations through the server. This solves
the DuckDB single-process limitation during development — server for
API testing, Desktop for UI verification, both against the same data.
Server-side: LocalApiServer gains SDK passthrough endpoints under
/api/v1/sdk/* (execute, search, vault, blob, db maintenance) so the
HttpSdkTransport has something to call. All endpoints sit behind the
existing API key authentication.
In client mode, server-managed background services (backup, file sync,
snapshot sync, reminders, RAG indexing, API server) are skipped since
the headless server handles them. UI services, plugin discovery, and
IPC still run locally.
SdkHost.SetTransport() follows the same post-build wiring pattern as
SetSyncOutbound() and SetVaultUnlockPrompt(). Pure refactor in
standalone mode — zero behavior change when no server is detected.
Fix AXAML xmlns references after Services extraction
Details
8 AXAML files still referenced `using:PrivStack.Desktop.Models` which
is now an empty namespace — all model types moved to
`PrivStack.Services.Models` during the architecture split.
Updated xmlns declarations:
- models → PrivStack.Services.Models (8 files)
- BacklinkEntry → PrivStack.Services via new svc: prefix (InfoPanel)
Fix color picker missing selected visual feedback (BUG #60)
Details
Add SelectedColorBrushConverter (IMultiValueConverter) that compares the
swatch color with the ViewModel's SelectedColor. Use MultiBinding on the
swatch BorderBrush to show a white ring around the currently selected color.
Bump version 1.14.6 → 1.14.7.
Register entity schemas with Rust core in headless plugin registry
Details
HeadlessPluginRegistry was loading and initializing plugins but never
registering their entity schemas with the Rust core via FFI. This caused
the API to return "No schema registered for entity type: task" errors
because the Rust engine didn't know about the entity types.
Mirrors the desktop PluginRegistry behavior:
- RegisterEntitySchemas() called per-plugin BEFORE InitializeAsync()
- RegisterSystemEntitySchemas() for system types (entity_metadata,
property_definition, property_group, property_template)
- Uses NativeLib alias for PrivStack.Services.Native.NativeLibrary
(InternalsVisibleTo already grants access to privstack-server)
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.
Get notified about new releases