Fix Duncan not initializing on app load due to vault timing
Details
The AI provider's IsConfigured check uses a synchronous vault read with
a 2-second timeout (GetApiKeySync). During DI resolution this runs before
EnsureStandardVaults has unlocked the ai-vault, so it times out and
returns false. Since IsEnabled is a plain computed property with no
re-notification, Duncan stays dead for the entire session.
Fix:
- AiService.RecheckAvailability() — called from the deferred background
services block after the vault is guaranteed unlocked. Re-evaluates the
provider's IsConfigured state.
- AiService.AvailabilityChanged event — fires when availability transitions.
- AiSuggestionTrayViewModel subscribes to AvailabilityChanged and re-raises
PropertyChanged for IsEnabled, which flips the UI visibility binding.
Load .env file at startup for local development
Details
Adds a LoadDotEnv() helper that walks up from the executable directory
to find the nearest .env file and sets any missing environment variables.
This ensures PRIVSTACK_GITHUB_CLIENT_ID and other secrets are available
during local dev without requiring manual export or launchSettings.json.
Existing env vars are never overwritten.
Fix PushAllEntities firing on every app launch
Details
StartSyncForWorkspace unconditionally called PushAllEntities, which
re-uploads every entity in the store as a FullSnapshot to S3. Since
AutoStartSyncAsync calls StartSyncForWorkspace on every app launch,
this caused a full re-upload of all entities (seed data, categories,
accounts, metadata — everything) on every restart, regardless of
whether anything actually changed.
Added a pushAllEntities parameter (default false) so only first-time
setup paths (enable cloud sync, acknowledge recovery kit, after cloud
clean/purge) trigger the full push. Auto-start and manual resume use
the incremental path via SyncOutboundService.PushEvent instead.
Let Ctrl+Tab bubble through RTE for block-level indent
Details
The RTE's Tab handler now checks for Ctrl/Cmd modifier first and skips
handling, allowing the event to bubble up to the parent view for
block-level indent/outdent. Plain Tab and Shift+Tab behavior unchanged.
Fix code block language pill not responding to clicks
Details
Switch the language pill click handler from PointerReleased to
PointerPressed. When the AvaloniaEdit TextEditor has focus, it captures
the pointer on press, preventing PointerReleased from reaching the
pill overlay. PointerPressed always fires on the element under the
cursor regardless of capture state.
Get notified about new releases