Commit Graph

141 Commits

Author SHA1 Message Date
bvandeusen c9f2134ad4 feat(journal): conversational LLM-generated daily prep (replaces card)
The structured prep card was data-rich but voiceless. Replaced with an
LLM-generated conversational opener — same shape the briefing's compilation
slot had — that renders as a normal assistant chat bubble at the top of
the day's conversation.

Backend (services/journal_prep.py):
- Renamed generate_daily_prep -> gather_daily_sections (still pure data
  fetching, no LLM); kept the old name as a backwards-compat alias.
- New _generate_prep_prose: hands the gathered sections to generate_completion
  with a warm-conversational system prompt; returns prose. Falls back to a
  plain greeting if the LLM call fails or no model is configured.
- ensure_daily_prep_message now persists the prep as role='assistant' with
  the prose as content. Structured sections stay on msg_metadata for
  provenance. Auto-upgrades legacy system-role preps in place on next call.

Frontend:
- Drop the <article class="daily-prep"> structured block from JournalView.
  The prep is now just the first chat bubble — picks up the existing
  Illuminated Transcript styling automatically.
- Drop dayMessages / prepMessage / prepSections / asArray helpers — no
  longer needed.
- ChatMessage hideMessage filter: comment refined to clarify it only
  catches LEGACY system-role prep rows. Current preps are assistant-role
  and render normally.

Net effect: open /journal -> first thing you see is a warm assistant bubble
that talks about your day -> input bar below to reply.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 15:42:30 -04:00
bvandeusen cacfcac86a fix(journal): restore weather + events panels; hide daily-prep system msg in chat
The journal UI was over-stripped earlier — weather panel, current-conditions
poll, and the upcoming-events sidebar were all dropped. Restored those (calls
the new /api/journal/weather, /api/journal/weather/current,
/api/journal/weather/refresh, /api/journal/weather/geocode endpoints).

Also: the daily-prep system message was rendering as flat text inside
ChatPanel because there's no .role-system bubble styling. Added a hideMessage
guard in ChatMessage so daily-prep system messages don't render in the chat
stream — they're already shown above as a structured prep card.

News / RSS reactions / article-discuss are intentionally NOT in the journal
(scoped out per user direction). The broader RSS infrastructure cleanup is
a separate, larger task.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 12:22:51 -04:00
bvandeusen 873e70c7ea feat(journal): add JournalView UI with /journal route + nav link
Restores a working browser surface for the journal feature, which was
left UI-less when Stage F of the original plan was deferred. JournalView
is a fresh write (not a rename of BriefingView) — drops the briefing-
specific weather panel, news cards, RSS reactions, article-discuss
button, and setup wizard, since none of those have journal-backend
equivalents.

What it does:
- Fetches /api/journal/today on mount; shows today's daily-prep card
  (rendered from msg_metadata.kind === 'daily_prep' sections)
- Day picker via /api/journal/days lets you switch to past days
- Refresh-prep button hits /api/journal/trigger-prep
- Center is the existing ChatPanel pinned to today's journal conversation
  (so the chat input + SSE + tool-call cards inherit unchanged)
- Right sidebar keeps the upcoming-events list (uses the generic
  /api/events endpoint, not a briefing-specific one)

Also:
- Replace the dead Briefing API client functions with Journal equivalents
  (getJournalConfig, saveJournalConfig, getJournalToday, getJournalDay,
  getJournalDays, triggerJournalPrep, list/update/deleteJournalMoment).
- Remove NewsView.vue — it was orphaned (no route, no nav) and depended
  on the deleted /api/briefing/* endpoints. If a standalone news surface
  is wanted later it'll need to be rebuilt against new endpoints.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 11:54:06 -04:00
bvandeusen 7602bf2293 feat(briefing): hard-cut tear-down
Backend:
- Delete briefing services (pipeline, scheduler, conversations, profile, tools)
- Delete routes/briefing.py + remove blueprint registration
- Move _get_temp_unit into services/weather.get_temp_unit (reads top-level temp_unit setting)
- Rename briefing_preferences.py → rss_filtering.py (functions are RSS-specific)
- Strip briefing scheduler hooks from app.py
- Strip briefing scheduler call from routes/settings.py
- Update test imports (test_rss_service, test_tz_helpers)

Frontend:
- Delete BriefingView, BriefingSetupWizard, BriefingToolStatusRow
- Strip /briefing route + nav links (AppHeader, KnowledgeView)
- Strip Settings → Briefing tab + state + functions + imports
- Strip briefing-intermediate handling from ChatMessage
- Hide /news route + nav links (NewsView depended on briefing endpoints; orphaned in tree)
- Drop unused useSettingsStore from AppHeader

The Android BriefingScreen lives in a separate repo and is not touched here.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 22:33:37 -04:00
bvandeusen f422d4158c style(workspace-notes): larger, more spacious note title
Title input bumps to 1.4rem with Fraunces serif (matches the
design language's heading treatment) and gains 0.9/1.1rem padding
on the title row for breathing room.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 14:52:58 -04:00
bvandeusen 70ec060b7a style(workspace-notes): move active-note indicator to right edge
Anchors it to the editor side rather than the tasks-panel side.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 14:43:59 -04:00
bvandeusen 3b41a45757 style(workspace-notes): drop border between toolbar and body
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 14:35:45 -04:00
bvandeusen 19e1ca505d style(workspace-notes): unify editor chrome, distinguish rail
- Drop border-bottom lines between header / title / tags / toolbar
  so they read as one continuous input surface.
- Add a single border-top above the editor body so the body's
  existing boundary stays clear.
- Notes rail gets --color-bg-card so it no longer visually merges
  with the tasks panel (both previously shared --color-surface).
  Dropped the rail's border-right since the tint now carries the
  division from the editor pane.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 13:30:17 -04:00
bvandeusen f75c40b417 refactor(workspace): match KnowledgeView mini-chat dock style
- Widget is now a bottom-anchored dock spanning the content width
  (max-width 1200px, rounded top corners, bg-secondary, upward shadow)
  instead of a floating corner box.
- Drop the closed state and ✕ button — widget is always present,
  matching KnowledgeView's pattern. Collapsed = input-only dock,
  expanded = full ChatPanel above the input.
- Grid ratio 1fr:2fr → 0.85fr:2.15fr so tasks get a touch less room
  and notes a touch more.
- Workspace note-rail (the notes picker column inside the editor)
  widens from 155px to 200px so note titles breathe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 12:53:02 -04:00
bvandeusen 649c0f124b feat(workspace): history dropdown on project chat widget
Clicking the ▾ button reveals conversations where
rag_project_id === projectId, most-recent first. Selecting one
repoints the widget (and the workspace_conv_{pid} storage key) to
that conversation without deleting the previously active one.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:10:54 -04:00
bvandeusen 6026c24450 refactor(workspace): two-column grid; widget drives tool-call refresh
WorkspaceView now renders tasks (1fr) on the left and notes (2fr) on
the right with the floating WorkspaceChatWidget layered on top. The
widget owns the SSE streamingToolCalls watcher and emits note-changed
and task-changed events; the view listens and reloads the affected
panel refs.

Dropped from the view:
- ChatPanel mount, empty-state quick chips, and Chat header toggle
- The conversation lifecycle + SSE watcher (moved into the widget)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:09:50 -04:00
bvandeusen ae5c61a179 feat(workspace): floating project chat widget
Modeled on KnowledgeView's mini-chat. Three states (closed handle,
collapsed input-only, expanded full panel). Takes over the project
conversation lifecycle from WorkspaceView (resume-or-create on mount,
delete-if-empty-and-new on unmount) and adds a restart action. Reuses
ChatPanel for expanded view and ChatInputBar for collapsed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:08:25 -04:00
bvandeusen ddab0db781 feat(weather): add hourly precipitation summaries and peak timing to weather card
Fetch hourly precipitation probabilities from Open-Meteo alongside daily
forecasts. Generate human-readable precip summaries ("Rain likely 2–5 PM",
"Rain likely all day") for today and each forecast day. Display today's
summary as a styled callout and show peak precipitation hour in forecast rows.
Also fix briefing pipeline to parse all weather location rows (not just first).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 16:05:26 -04:00
bvandeusen 3ac32dc3bc feat: add rss_enabled user setting to toggle RSS functionality
RSS is now off by default. When disabled:
- Scheduler skips RSS feed sync during compilation slot
- Briefing pipeline skips RSS item gathering
- RSS LLM tools (get_rss_items, add_rss_feed) are hidden
- API routes return empty results for feeds/news
- Frontend hides News nav link, RSS Feeds and News Preferences in settings
- Briefing view hides news sidebar section

Toggle in Settings > Briefing > RSS / News.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 13:58:50 -04:00
bvandeusen 6cf880506d fix(voice): allow WASM compilation in CSP for Silero VAD
Add 'wasm-unsafe-eval' to script-src and blob: to worker-src in
Content-Security-Policy header. Required by onnxruntime-web to compile
the Silero VAD ONNX model. Also surface VAD init errors as a toast
instead of silent console log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 20:10:29 -04:00
bvandeusen c07a0f0f7e fix(chat): remove input bar border across all chat views
Remove border-top from .input-wrapper in ChatPanel directly instead
of overriding per-view. Applies to chat, workspace, and briefing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 19:25:48 -04:00
bvandeusen 776e5edb68 fix(briefing): responsive sidebar, remove dividers, scale forecast icons
Switch sidebar from fixed px to proportional 35% so it resizes with
the viewport. Remove border between chat and input bar and between
weather and news. Use container query units for weather/forecast icons
so they scale with column width.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 19:10:49 -04:00
bvandeusen f12d29563a fix(briefing): 2-column layout with table-based weather forecast
Collapse briefing from 3-column to 2-column grid (chat + sidebar).
Weather moves to top of news column, forecast uses an HTML table so
rows align cleanly. Drop verbose condition text from forecast days
(emoji already conveys it). Switch CI node_modules cache to npm
download cache to avoid tar size error from onnxruntime-web.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 18:10:46 -04:00
bvandeusen 0a8a755909 feat(voice): replace silence detector with Silero VAD in ChatInputBar
Swaps useSilenceDetector for useVad. Adds no-speech guard: when the
user manually stops recording without VAD ever detecting speech, show
a toast and skip the Whisper round-trip instead of sending pure noise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 17:45:21 -04:00
bvandeusen 369cf0a7c9 fix(chat): default context sidebar to hidden
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 23:29:14 -04:00
bvandeusen 3f2813d16f feat(chat): Phase D empty-state + overlay context sidebar
Empty-state rethink: replace "Start a conversation." with a richer
landing showing recent conversations (top 5 as resume links) and a
voice-mode entry button. Gated to full variant only; widget/briefing
keep the simple message.

Context sidebar: switch from grid column (4-col layout) to absolute
overlay on the right gutter (3-col layout). The reading column is now
always symmetrically centered regardless of whether the sidebar is
visible — eliminates the leftward shift that occurred when context
notes appeared.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 22:35:39 -04:00
bvandeusen 5e281c534a fix(chat): add bottom padding to messages container to clear input bar
Streaming bubble (Generating response…) was flush against the input
wrapper top border. Give the scroll column 0.75rem of breathing room
so the assistant bubble sits visibly separate from the input.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 19:29:14 -04:00
bvandeusen 9082281225 feat(chat): Phase C — collapsible context sidebar with header toggle
Context sidebar sections (Auto-included / Suggested / In Context) are
now collapsible with chevrons, and collapsed state persists per
conversation via localStorage. A new Context (N) button in the chat
header toggles the whole sidebar — open by default on wide screens
(>=1200px), closed by default below. Visual differentiation: auto-
included notes get a muted background with an AUTO pill, in-context
notes get an active-chip style with a primary-colored left border,
and each section header shows its item count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 19:12:11 -04:00
bvandeusen 4228e9a384 feat(chat): move scope chip to header, consolidate voice controls into input bar
Phase B of chat view refinement. Bumps chat reading column to 1200px,
lifts the RAG scope chip out of the footer and into the ChatView header
(next to the title), and collapses the listen toggle / volume slider /
stop-playback buttons into a single speaker popover on the input bar.
Listen mode + TTS are now available in briefing and workspace chats too,
since the controls live on the shared ChatInputBar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 09:44:16 -04:00
bvandeusen ad4fe3d783 feat(chat): center chat reading column and full-height context sidebar
Replaces the full-variant flex layout with a single CSS grid owning the
messages column, input bar, and context sidebar. Messages and input bar
share a centered ~820px reading track (--chat-reading-width token) so
the mic button can't get pushed off-screen on wide monitors, and the
context sidebar spans grid-row 1/-1 so it runs the full height from the
chat header down to the bottom edge instead of stopping above the input
bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 07:11:08 -04:00
bvandeusen 36fb71699b feat(voice): dynamic silence threshold + filled red mic halo
The web silence detector previously ran RMS over getByteFrequencyData
bytes (which are already dB-scaled) and re-log'd the result, producing
numbers that didn't line up with real dBFS. Combined with a static
-40 dB threshold that sat right on top of room ambient, silence
detection rarely fired and the user had to click stop manually.

- Rewrite useSilenceDetector to use getFloatTimeDomainData for honest
  linear RMS → dBFS.
- Silence threshold is now dynamic: track session peak dBFS and treat
  "silent" as 15 dB below peak. Auto-calibrates per mic/room.
- Grace period (1500 ms) at start so the user can begin speaking
  before checks arm; static -45 dB fallback until peak clears -25 dB
  so dead-silent sessions don't spin forever.
- Silence duration bumped 1500 → 2000 ms for breathing room.

Visual: detached red radial-gradient disc sits behind the mic in a
wrapper; the button no longer scales, so the white mic icon stays
legible on top while the halo grows from 1x to ~2.6x with live
amplitude. Much more obvious "you are live" signal than the prior
subtle box-shadow pulse.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 00:26:52 -04:00
bvandeusen 730dbfaf7b feat(voice): pulse mic button with live amplitude
The mic button now scales and glows proportional to the silence
detector's RMS amplitude instead of sitting static. Gives obvious
feedback that audio is actually being picked up — silence still
breathes via a 0.1 floor, loud input caps at ~1.18x scale so it
doesn't punch through the input bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 22:46:37 -04:00
bvandeusen 87fcaa6a0d fix(chat): gate qwen3 thinking on message content instead of always-on
The frontend hardcoded think=true on every chat send (ChatPanel full +
widget variants, KnowledgeView minichat), which defeated the _should_think
gate on the backend and made qwen3:14b spend 5-20s on chain-of-thought
reasoning for every turn — even "hi". This was the root cause of the
warm-path TTFT variance tracked in followup_ttft_variance.md: the logged
ttft_ms was really prefill + full thinking phase, bouncing with the depth
of the model's reasoning, not with cache or eviction.

All three frontend callers now pass think=false and let _should_think be
authoritative. The classifier is now a real content-based gate: explicit
think_requested=True still forces on as an override (briefing discuss
actions, future UI toggles, MCP callers), otherwise messages <80 chars
without reasoning keywords skip thinking, messages >=400 chars or
containing keywords like why/explain/analyze/debug/review/etc. get it.

Generation timing now separately records think_requested, the final
think decision, first_token_ms (first any chunk), and thinking_ms
(duration of the thinking phase). ttft_ms keeps its existing semantic
(first content token) so existing log analysis still works. The timing
log line surfaces all four fields so the old "just a big ttft number"
ambiguity is gone.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 00:53:47 -04:00
bvandeusen 77339d5c58 refactor(tools): consolidate LLM tools from 42 to 38
Merge create_task into create_note (set status='todo' for tasks, omit
for notes), merge delete_task into delete_note, consolidate entity
tools (create/update_person → save_person, create/update_place →
save_place), rename get_note → read_note with clearer descriptions,
move calculate out of rag.py into utility.py, and extract shared
duplicate detection into check_duplicate() helper.

Updates all downstream references in generation_task.py, quick_capture.py,
ToolCallCard.vue, and WorkspaceView.vue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 13:38:45 -04:00
bvandeusen 593d737e26 feat(briefing): UI polish for agentic briefing messages
Three visual improvements for the briefing conversation:

1. Intermediate tool-call messages (empty content, briefing_intermediate:
   true) now render as a compact dashed status row with per-tool pills
   showing result counts, instead of an empty assistant bubble followed
   by a stack of ToolCallCards. Click to expand the full cards.

2. Slot badge on non-intermediate briefing messages — "Full Briefing"
   for compilation, "Morning/Midday/Afternoon Update" for slot
   injections. Slot updates get a softer bubble treatment (transparent
   background, muted border, smaller text) so the compilation stays
   visually dominant.

3. Slot separator now triggers on briefing_slot metadata (not the
   compilation-only rss_item_ids), and uses a look-behind so it only
   fires when there's a prior slot message — no separator above the
   first briefing of the day.

New component: BriefingToolStatusRow.vue handles the intermediate
pill row and delegates to ToolCallCard when expanded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 22:10:31 -04:00
bvandeusen 126bad7d99 fix(header): darken nav text in light mode — use text-secondary for inactive, primary-solid for active 2026-04-08 23:43:25 -04:00
bvandeusen f9c6802939 feat(calendar): linked start/end times, 1h default duration, smart rounding, past event hint 2026-04-08 13:47:15 -04:00
bvandeusen 317d8f25d0 feat(editor): skip toolbar in tab order; auto-focus title; type-dependent placeholders
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 13:25:07 -04:00
bvandeusen 16d9af8b96 fix(theme): increase dark mode contrast for borders, glows, and card edges; DRY color values into CSS variables 2026-04-08 12:22:03 -04:00
bvandeusen 2ac894b5d1 refactor(theme): DRY hardcoded violet values into CSS custom properties
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:19:38 -04:00
bvandeusen 7e81e50e3e feat(theme): sweep indigo to violet across all remaining views and components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:12:46 -04:00
bvandeusen f30e90ef8d feat: narrator empty states, scroll fades, glow buttons, violet color sweep 2026-04-08 11:17:06 -04:00
bvandeusen f953a36b86 feat(header): pill nav bar, brand shortening, status pulse, header gradient 2026-04-08 11:11:35 -04:00
bvandeusen 4bc7f9eaac feat(theme): shift palette from indigo to deep violet + muted gold
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 11:09:23 -04:00
bvandeusen a684d84edf feat: deprecate /notes and /tasks routes; redirect to Knowledge view 2026-04-08 10:35:21 -04:00
bvandeusen 56b687c9f4 fix(voice): show mic button on HTTP; graceful error for non-secure contexts 2026-04-07 20:06:57 -04:00
bvandeusen 7f37cee49f refactor(voice): integrate click-to-toggle mic into ChatInputBar; remove VoiceOverlay 2026-04-07 13:17:25 -04:00
bvandeusen d290bebad2 feat(stt): pass conversation context as Whisper initial_prompt to reduce mishearings 2026-04-07 08:48:27 -04:00
bvandeusen 853dc810ff feat: click-to-toggle silence detection and amplitude bars in VoiceOverlay 2026-04-06 20:01:44 -04:00
bvandeusen b9d0716b01 feat: add News link to main navigation header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 17:49:22 -04:00
bvandeusen 9af8ab8f70 fix(briefing): use briefing context for follow-ups; add slot separator
- build_context: when conversation_type is 'briefing', inject a system
  prompt instruction telling the model to answer from conversation history
  and article context instead of searching the web
- Consolidate briefing conversation type detection to one DB query (was
  being checked twice — once for the system prompt addition, once for
  article context injection)
- ChatPanel: render a visual 'New Briefing Update' separator line before
  2nd+ briefing slot messages (identified by metadata.rss_item_ids)
- types/chat.ts: add metadata field to Message interface

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 06:15:18 -04:00
bvandeusen 358534efbf fix(events): audit pass — 7 correctness fixes across the events system
Backend:
- tools.py: apply UTC normalization to update_event datetime fields
  (matched create_event which already did this)
- events.py service: allow end_dt/recurrence/project_id to be cleared
  via update_event by permitting None for nullable fields
- events.py service: find_events_by_query now returns upcoming events
  first, falling back to past — prevents AI tools from mutating stale
  past events when a future match exists
- events.py service: list_events now uses overlap logic (start <= to
  AND end >= from) so multi-day events spanning the query boundary
  are included; previously only start_dt was checked

Frontend:
- ToolCallCard: fire fable:calendar-changed on created/updated/deleted
  so CalendarView refetches without requiring a manual page refresh
- KnowledgeView: replace raw apiGet('/api/events') with listEvents()
  client function; also fix today bar which was reading .events off a
  flat array (always empty) — now correctly receives EventEntry[]
- HomeView: use full ISO strings for event date range instead of naive
  UTC-midnight strings; deduplicate inline date math via _dateRange()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 12:02:10 -04:00
bvandeusen 7677ab4028 fix(calendar): use date-only strings for all-day events to prevent timezone shift
UTC midnight passed to FullCalendar's timeZone:'local' was being
converted to local time, shifting all-day events back by 1+ days for
users in UTC-X zones. The edit form had the same bug via new Date().

Fix: pass YYYY-MM-DD slices (UTC date) for all-day events in both
toFcEvent and EventSlideOver resetForm, bypassing timezone conversion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:01:51 -04:00
bvandeusen eda9c5ce43 feat: migrate KnowledgeView mini-chat to ChatPanel + enable note picker everywhere
- KnowledgeView: replace custom mini-chat (voice, PTT, manual scroll, message
  rendering) with ChatPanel variant="full"; gains RAG scope chip, TTS listen
  mode, volume control, and note picker automatically (-218 lines)
- ChatInputBar: remove briefingMode guard on note picker so attach/search works
  in briefing, workspace, widget, and knowledge chat surfaces

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 20:16:36 -04:00
bvandeusen d624d38412 fix: KnowledgeView infinite scroll root + calendar event refresh
- KnowledgeView: IntersectionObserver was watching the viewport instead
  of the card-grid scroll container, causing infinite scroll to stop
  loading after only ~29 items. Pass card-grid element as `root`.
- CalendarView: listen for 'fable:calendar-changed' custom event and
  call refetchEvents() so tool-created events appear without navigation.
- ChatPanel: dispatch 'fable:calendar-changed' when create_event,
  update_event, or delete_event tool calls succeed.
- tools.py: normalize naive datetimes to UTC before storing events so
  timezone comparisons in list_events queries are always consistent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 19:28:33 -04:00