Skip to main content

Changelog

Every improvement, automatically tracked from our commit history.

Subscribe via Atom feed
← Prev Page 16 of 117 Next →
February 28, 2026
patch Desktop ShellServices

Fix client mode startup: license check and error handling

Details

In client mode, ShowMainWindow crashed at LicenseExpirationService because

PrivStackService.GetLicenseStatus() requires the native runtime to be

initialized — which it isn't in client mode. The exception was silently

swallowed by the fire-and-forget task, leaving the app with no visible

window.

  • Add license_status field to /api/v1/status endpoint response
  • Parse and store server license status during TryEnterClientMode()
  • Add CheckLicenseStatusFromServer() to LicenseExpirationService for

applying license status from a remote server string

  • Use server-provided license status in client mode ShowMainWindow
  • Add ContinueWith error handler on fire-and-forget EnterClientModeAsync

to log failures instead of silently swallowing them

patch Desktop ShellServerServices

Route entity type registration through SDK transport layer

Details

RegisterEntityType was called directly via NativeLib P/Invoke in both

PluginRegistry (Desktop) and HeadlessPluginRegistry (Server), bypassing

the ISdkTransport abstraction. In client mode, the native runtime isn't

initialized, causing all entity schema registrations to fail with error

code -4.

  • Add RegisterEntityType to ISdkTransport interface
  • Implement in FfiSdkTransport (delegates to NativeLib)
  • Implement in HttpSdkTransport (POSTs to /api/v1/sdk/register-entity-type)
  • Add public RegisterEntityType method on SdkHost
  • Add /sdk/register-entity-type endpoint to LocalApiServer
  • Update PluginRegistry to route through SdkHost instead of NativeLib
  • Update HeadlessPluginRegistry with same fix, remove unused NativeLib import
patch Desktop ShellServices

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.

patch Desktop Shell

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)
patch Server

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)

← Prev Page 16 of 117 Next →

Get notified about new releases