Fix Tab key incorrectly tree-nesting non-list blocks
Details
The global Tab KeyDown handler in NotesView was catching Tab presses in
definition lists, tables, and other non-RTE blocks and calling
IndentBlock(), which removes the block from its position and appends it
as a child of the previous sibling — appearing as a "merge" with the
block above.
This was wrong for all non-list block types:
- RTE blocks (paragraph, heading, etc.) already handle Tab internally
via IndentRequested, adjusting visual IndentLevel — so the global
handler was unreachable for those.
- Non-RTE blocks (definition list, table, image, code) don't support
Tab indentation, but the global handler was tree-nesting them.
Remove the global Tab handler entirely. Each editor handles Tab
appropriately on its own.
Update DetailedDescriptions with expanded AI intent listings
Details
All 12 plugins now list their complete AI intent inventory in the
DetailedDescription field, which is RAG-indexed for Duncan's intent
classification pipeline.
Updated from single-line format to multi-line bullet format matching
the Habits gold-standard pattern. Each intent line includes the intent
ID, action description, and slot signature with required (*) markers.
Intent count by plugin:
Calendar: 4, Notes: 4, Contacts: 5, Email: 5, Tasks: 4 (unchanged),
Finance: 10 (unchanged), Journal: 3, Habits: 6, Snippets: 4, RSS: 4,
WebClips: 3, Files: 3, Canvas: 2 (new), Data: 2 (new)
Total: ~59 intents across 14 plugins (up from 25).
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.
Add IIntentProvider to Canvas and Data plugins
Details
Canvas: 2 new intents (create_whiteboard, delete_whiteboard)
- create_whiteboard: create new blank whiteboard
- delete_whiteboard: delete by ID or title search
- Changed CanvasPlugin from sealed class to sealed partial class
Data: 2 new intents (run_query, import_csv)
- run_query: execute saved SQL query by name, returns result preview
- import_csv: create empty dataset placeholder for import
- Changed DataPlugin from sealed class to sealed partial class
These two plugins previously had zero AI intent support. Both now follow
the standard partial class IIntentProvider pattern with entity resolution
helpers.
Expand AI intents for Snippets, RSS, WebClips, and Files plugins
Details
Snippets: +3 intents (search_snippets, delete_snippet, create_collection)
— 4 total
- search_snippets: search by title/content with language/collection filter
- delete_snippet: trash snippet by ID or title search
- create_collection: create snippet collection with description/color
RSS: +3 intents (remove_feed, mark_all_read, search_articles) — 4 total
- remove_feed: unsubscribe + delete articles by ID or name search
- mark_all_read: mark all articles read (optionally per-feed)
- search_articles: search by title/summary with feed/starred filter
WebClips: +2 intents (search_clips, update_clip_status) — 3 total
- search_clips: search by title/URL/content with status filter
- update_clip_status: set status (unread/reading/read/archived)
Files: +2 intents (search_files, delete_file) — 3 total
- search_files: search by file name with folder filter
- delete_file: soft-delete (trash) by ID or name search
Uses `with` expressions for init-only record properties (RssArticle.Read,
WebClip.StatusRaw). Reuses existing service search methods where available.
Get notified about new releases