Add stop_reason/finish_reason validation to all AI providers
Details
All cloud AI providers (Anthropic, OpenAI, Gemini, Groq, Mistral) now
check the API's stop/finish reason field to detect token-limit truncation.
Previously, truncated responses were returned as Success=true with
partial content, causing garbled output or literal "MAX_TOKENS" error
strings to leak through to the user.
Changes:
- AiResponse: add WasTruncated property for consumer-side handling
- AnthropicProvider: check stop_reason == "max_tokens"
- OpenAiProvider: check finish_reason == "length"
- OpenAiCompatibleProviderBase: check finish_reason == "length" (covers
Groq, Mistral, and any future OpenAI-compatible providers)
- GeminiProvider: check finishReason == "MAX_TOKENS", log warning
- All providers log a warning with the MaxTokens limit when truncated
Delete wiki pages from GitHub at trash time, not permanent delete
Details
The remote delete was only wired into DeletePagePermanentlyAsync
(permanent delete from trash view), but the user expects the file
to be removed from GitHub when they trash the page. Additionally,
SyncAsync restores trashed wiki pages that still exist in the repo,
so the page would reappear on next sync.
Move the GitHub delete call to both TrashPageAsync and
TrashPageFromTreeAsync — the two entry points for trashing a page.
Update confirmation dialogs for wiki pages to say "Delete from Wiki"
and mention GitHub removal. Keep the remote delete in
DeletePagePermanentlyAsync as a fallback for pages trashed before
this change.
Add BoxShadows elevation token system to SharedTokens
Details
Define a 5-tier elevation shadow system as BoxShadows resources:
ThemeShadowXs — cards at rest, subtle depth cue
ThemeShadowSm — surface cards, raised sections
ThemeShadowMd — elevated cards, hover lift, floating toolbars
ThemeShadowLg — menus, popovers, dropdowns, toasts
ThemeShadowXl — modals, dialogs, full-screen overlays
Plus two hover-state tokens (ThemeShadowXsHover, ThemeShadowSmHover)
for cards that lift on pointer-over.
Migrate all theme style classes (card, surface-card, elevated-card,
stat-card, item-card, modal, shadow-sm/md/lg, hoverable) and the
menu/context-menu templates to reference these tokens instead of
hardcoded values. Also migrate inline shadows in MainWindow,
UniversalSearchDropdown, and ToastContainer.
Previously there were 80+ hardcoded shadow values with inconsistent
opacity levels across the codebase. This establishes a single source
of truth that can be tuned in one place.
Detail panel: percentage-based sizing with persistence
Details
The list/detail split panel now defaults to 50/50 and can be resized
between 25% and 75% of the available width. The ratio is persisted via
plugin settings so it survives navigation and app restart.
- ViewModel: add DetailPanelRatio property (0.25–0.75, default 0.5),
loaded from settings on construction, saved on resize release
- AXAML: remove fixed Width/MinWidth/MaxWidth from ListDetailPanel,
add SizeChanged handler on split grid
- Code-behind: OnSplitGridSizeChanged applies the ratio whenever the
grid resizes (window resize, etc). Resize drag clamps to 25%–75%
of available width and persists the new ratio on release.
Fix context menu drop shadow clipped by popup window bounds
Details
The BoxShadow on MenuFlyoutPresenter and ContextMenu was invisible
because the Popup native window sizes exactly to its child, clipping
any shadow that extends outside the Border bounds.
Override the control templates to wrap the LayoutRoot Border in a Panel
with margin (12,6,12,22) matching the shadow extent (blur=24 offset-y=8).
This inflates the popup window, giving the shadow room to render. The
BoxShadow is now set directly on the template Border instead of via a
separate style selector.
Get notified about new releases