Commit Graph
60 Commits
Author SHA1 Message Date
iamdoubz 575118ceba feat(sync): begin_oauth_link command; pump/test dispatch via build_sync_target (T9.9/9.10) 2026-07-03 07:54:29 -05:00
iamdoubz 27541dd171 feat(sync): OneDrive (Graph) provider + kind-based target dispatch + token resolution (T9.10) 2026-07-03 07:54:29 -05:00
iamdoubz e8363042ce feat(sync): OAuth 2.0 PKCE core — auth URL, token exchange/refresh, loopback capture (T9.9) 2026-07-03 07:54:29 -05:00
iamdoubz daa9b72e62 feat(sync): resume pending sync jobs on startup (T9.5) 2026-07-02 21:56:58 -05:00
iamdoubz 2969008d8b feat(sync): upload queue pump w/ backoff, sync_meeting/status/retry, finalize hook, sync://job events (T9.5) 2026-07-02 21:56:58 -05:00
iamdoubz 87161553ee feat(sync): durable sync_jobs queue in storage (upsert/claim/update, skip-if-unchanged) (T9.5) 2026-07-02 21:56:57 -05:00
iamdoubz e6911a6bff feat(sync): target management + test-connection commands; wire allowlist (T9.3/9.8) 2026-07-02 20:17:03 -05:00
iamdoubz 10af546d7f feat(sync): real WebDavTarget (PROPFIND/MKCOL/PUT/HEAD) + keyring creds + TLS enforcement (T9.2/9.4/9.6/9.7) 2026-07-02 20:17:02 -05:00
iamdoubz bb7f704e16 feat(sync): sync_targets CRUD in the storage layer (T9.1) 2026-07-02 20:17:02 -05:00
iamdoubz 9c0b0c1d02 mod file 2026-07-02 19:57:59 -05:00
iamdoubz 2b435f3629 feat(hardware): register NPU package command + background model fetch (T3.4) 2026-07-02 17:16:44 -05:00
iamdoubz 69ed6256db feat(transcription): dispatch NPU backend + NPU package download command (T3.4) 2026-07-02 17:16:43 -05:00
iamdoubz 92752698c5 refactor(transcription): let streaming worker take &dyn Transcriber (T3.4) 2026-07-02 17:16:43 -05:00
iamdoubz a9335f487d feat(transcription): expose onnx model_dir for the dispatcher (T3.4) 2026-07-02 17:16:43 -05:00
iamdoubz f58c0f2d6c feat(transcription): wire OnnxNpuTranscriber behind npu feature (T3.4) 2026-07-02 16:14:16 -05:00
iamdoubz f8731adae3 feat(transcription): OnnxNpuTranscriber — NPU encoder + CPU greedy decode (T3.4) 2026-07-02 16:14:15 -05:00
iamdoubz 8fe6b5ceb1 feat(transcription): Whisper ONNX model catalog + downloader (T3.4) 2026-07-02 16:14:15 -05:00
iamdoubz e875c5de9a feat(transcription): Whisper log-mel front-end for NPU path (T3.4) 2026-07-02 16:14:15 -05:00
iamdoubz b97e5ebe85 feat(hardware): detect Intel NPU via ComputeAccelerator class (T3.4, FR-HW-1) 2026-07-02 15:55:00 -05:00
iamdoubz d5f7b1ac95 feat(hardware): on-demand NPU runtime paths + readiness probe (T3.4) 2026-07-02 15:54:54 -05:00
iamdoubz 8530a22899 fix(transcription): reduce whisper.cpp encoder cost per streaming window
whisper.cpp's encoder always runs over a full, padded 30s mel window
(1500 encoder positions) unless audio_ctx is explicitly reduced. The
~4s live-transcription streaming windows were never setting it, so
every window paid the full 30s-equivalent encode cost on one serial
worker thread -- the actual cause of the reported 30-65s lag between
speaking and a segment appearing, not "CPU is just slow".

Scales audio_ctx proportionally to the window's real sample count
instead (audio_ctx_for_window), floored and capped to whisper.cpp's
own valid range. Verified with a controlled A/B against the real
base.en-q5_1 model: ~30% faster even under heavy concurrent CPU
contention on this machine, which is masking most of the improvement
--the fix targets the encoder's O(n^2)-ish attention cost specifically
(1500 -> ~201 positions for a 4s window), so the gain on an otherwise-
idle machine should be substantially larger.
2026-07-02 15:02:02 -05:00
iamdoubz 8a28854250 feat(reminders): schedule/cancel from confirm_action_items (T8.6, FR-CAL-5) 2026-07-02 11:59:15 -05:00
iamdoubz 7f97328a2d feat(reminders): persist reminder_set; save_action_items returns saved rows (T8.6, FR-CAL-5)
reminder_set was accepted on the model but hard-coded to 0 on insert
and never included in the UPDATE. save_action_items's return type
changes from () to Vec<ActionItem> so the caller (which needs the row
id to key reminder scheduling) doesn't need a second round-trip for
newly-inserted items. Also adds list_pending_reminders for startup
reconciliation.
2026-07-02 11:59:09 -05:00
iamdoubz 994ace4b3f feat(reminders): initialize reminder_set: false on drafted action items (T8.6) 2026-07-02 11:59:02 -05:00
iamdoubz 47706cc0f3 feat(reminders): add ActionItem.reminder_set field (T8.6, FR-CAL-5) 2026-07-02 11:58:56 -05:00
iamdoubz 26ad920182 feat(reminders): register module; init + startup reconcile (T8.6, FR-CAL-5)
Reschedules anything Windows' own toast schedule lost track of
(uninstall/reinstall, a changed AppUserModelID) — safe to run every
startup since schedule() is idempotent (cancels any existing entry for
the same action item id first).
2026-07-02 11:58:50 -05:00
iamdoubz f6e0de5486 feat(reminders): schedule/cancel via Windows scheduled toast notifications (T8.6, FR-CAL-5)
Chosen over an app-side polling timer specifically to honor NFR-RES-1
("no polling timers running when not recording") — Windows itself
delivers the toast at due_at, and a scheduled toast is cleared by the
OS after it fires, so there's no "already fired" bookkeeping needed in
this app either. Windows-only, matching hardware::dxgi's pattern: the
real WinRT implementation lives in a #[cfg(windows)] submodule behind
plain top-level functions.

Verified against the live Windows toast API (not just compiled): a
throwaway example scheduled a reminder, confirmed
GetScheduledToastNotifications() reported it back with the correct id,
then confirmed cancel() removed it.
2026-07-02 11:58:44 -05:00
iamdoubz 10f0e31903 feat(export): register bulk_export_meetings command (T8.5, FR-STORE-4) 2026-07-02 11:35:31 -05:00
iamdoubz 5a5afa51e4 feat(export): add bulk_export_meetings (T8.5, FR-STORE-4)
Extracts export_meeting_to as a shared helper (was duplicated inline
in export_meeting) so single and bulk export share identical
fetch+render logic. bulk_export_stem sanitizes+suffixes filenames with
an id prefix — meeting titles are very often duplicates ("Untitled
meeting") and would otherwise silently overwrite each other in a
batch. A meeting that fails to export is skipped rather than aborting
the whole run; also fixes export_meeting's doc comment, stale since
T8.4 added pdf/docx.
2026-07-02 11:35:24 -05:00
iamdoubz 9a2177dd62 feat(templates): register list_note_templates command (T8.1, FR-NOTE-5) 2026-07-02 11:25:53 -05:00
iamdoubz 2f56891d40 feat(templates): apply templates at all 4 notes-render call sites (T8.1, FR-NOTE-5)
Adds StartRecordingArgs.template_id + list_note_templates command;
renames built_in_template to summary_prompt_bias to disambiguate it
from the new NoteTemplate concept (same meeting-type identifiers,
different purpose). Also fixes refresh_notes_and_notify (the
rename/merge-speaker refresh path) to route through
Store::update_notes instead of a raw std::fs::write — it was bypassing
T8.2's FTS reindexing, a gap missed there because this call site uses
meeting_dir(meeting_id) without the & that my earlier grep matched on.
2026-07-02 11:25:48 -05:00
iamdoubz 6b5b359438 feat(templates): persist template_id; finalize_meeting returns it (T8.1, FR-NOTE-5)
NewMeeting/Meeting gain template_id; finalize_meeting now returns it
(fetched via one cheap scalar SELECT) so callers that only have
segments/speakers in memory (not a fetched Meeting) can resolve the
template without a separate round-trip.
2026-07-02 11:25:41 -05:00
iamdoubz f63076ad06 feat(templates): NoteTemplate catalog + apply in to_markdown (T8.1, FR-NOTE-5)
4 built-in templates (Standup, 1:1, Sales Call, Retro), keyed by the
same meeting-type ids commands::summary_prompt_bias already uses for
LLM-prompt biasing — one identifier space shared by both, but two
independent lookups (structuring notes.md vs. biasing a summary
prompt). Section headers are prepended as an empty scaffold above the
auto-rendered speaker dialogue.
2026-07-02 11:25:34 -05:00
iamdoubz 06bdf6d469 feat(export): wire pdf/docx formats into export_meeting (T8.4, FR-NOTE-4) 2026-07-02 11:02:52 -05:00
iamdoubz 0425f64cfe feat(export): DOCX renderer via docx-rs (T8.4, FR-NOTE-4)
Bullet items get a literal "• " prefix rather than a real Word
numbered-list definition — this is read-only generated content, not
something the user continues typing into, so numbering-continuity
machinery isn't worth the extra API surface.
2026-07-02 11:02:46 -05:00
iamdoubz ec7ae5c01f feat(export): PDF renderer via printpdf + built-in Helvetica (T8.4, FR-NOTE-4)
Character-count word wrap (printpdf's builtin fonts expose no glyph
metrics) and per-boldness-run line groups (a bold speaker-name prefix
gets its own line above the dialogue) — simple choices that keep the
renderer self-contained with no bundled font asset.
2026-07-02 11:02:41 -05:00
iamdoubz f6a5b9583a feat(export): parse notes Markdown into a block model for PDF/Word (T8.4, FR-NOTE-4)
Fills in the ExportFormat::Pdf/Docx arms that previously errored
"lands in Phase 8". markdown_to_blocks() covers headings, paragraphs,
bullet/task lists, and bold runs — everything MarkdownNotes::to_markdown
and the notes editor's toolbar actually produce, not general Markdown.
Shared by both new renderer submodules (pdf, docx).
2026-07-02 11:02:35 -05:00
iamdoubz e6e209e1c4 feat(tags): register set_tags/list_tags commands (T8.3, FR-SEARCH-2) 2026-07-02 10:38:36 -05:00
iamdoubz d1ca2f63dd feat(tags): add set_tags/list_tags commands; extend list_meetings (T8.3, FR-SEARCH-2) 2026-07-02 10:38:31 -05:00
iamdoubz fc6a2fa0aa feat(tags): wire tags + list filters (T8.3, FR-SEARCH-2)
tags/meeting_tags existed since migration 0001, completely unused.
Adds upsert_tag/tags_for_meeting (mirroring upsert_participant's
find-or-create pattern) and real set_tags/list_tags implementations.

Extends list_meetings with tag/participant/date filters via a new
MeetingFilter struct, replacing the old query-only signature — the
participant filter matches either a speaker mapped to that participant
or an attendee of the meeting's linked calendar event, since neither
signal alone covers "who was in this meeting." Tags are populated on
Meeting/MeetingListItem/SearchHit via a per-row lookup (N+1, but
meeting counts are small enough that this is simpler than GROUP_CONCAT
string-splitting).
2026-07-02 10:38:26 -05:00
iamdoubz c2d282e5ba feat(tags): add tags fields to MeetingListItem/SearchHit (T8.3, FR-SEARCH-2) 2026-07-02 10:38:19 -05:00
iamdoubz c9c049ce2a feat(search): register the search command (T8.2, FR-SEARCH-1) 2026-07-02 10:07:40 -05:00
iamdoubz d928dfd51d feat(search): add search command; route notes.md writes through the store (T8.2, FR-SEARCH-1)
The initial notes.md render after finalize/resume/recovery bypassed
the Store abstraction entirely (raw std::fs::write) — routing it
through update_notes means that first render also gets FTS-indexed and
bumps updated_at, instead of only later manual edits doing either.
2026-07-02 10:07:29 -05:00
iamdoubz 68379f8f56 feat(search): wire meeting_fts population + real search (T8.2, FR-SEARCH-1)
meeting_fts existed since migration 0001 but nothing ever wrote to it.
Adds reindex_fts (called from finalize_meeting/update_notes so the
index can't drift from what's on disk), a one-time startup backfill
for meetings finalized before this feature existed, delete_meeting
cleanup (meeting_fts is a virtual table with no FK/CASCADE support),
and a real Store::search() replacing the hardcoded stub. Query input
is phrase-quoted per token so stray FTS5 operators in free-text search
input can't throw a MATCH syntax error.
2026-07-02 10:07:20 -05:00
iamdoubz b5aa1714ad feat(search): add SearchHit type (T8.2, FR-SEARCH-1)
Same fields as MeetingListItem plus a highlighted snippet of what matched.
2026-07-02 10:07:03 -05:00
iamdoubz fc9c1d9fc2 feat(audio): forward capture-event sink to recording://level/device (T7.3)
start_recording now creates the EventSink alongside the existing frame
channel and forwards Level/DeviceChanged onto a small fire-and-forget
thread that emits "recording://level" and "recording://device".
2026-07-01 21:09:34 -05:00
iamdoubz 098331d6f5 feat(audio): compute level meter + device-change recovery (T7.3, FR-CAP-5/6)
Adds AudioLevel (rms/peak per chunk, throttled to ~20Hz) and
CaptureEvent::DeviceChanged emitted through a new EventSink alongside
the existing FrameSink. On a capture read failure, reopens against
whatever is now the default render device and continues the same WAV
file if the new format is compatible; otherwise fails loudly rather
than silently corrupting the recording.
2026-07-01 21:09:28 -05:00
iamdoubz 70c8c61af5 feat(privacy): implement privacy_self_check command (T7.6, FR-SEC-2)
Reports LLM endpoint/local-only status and enabled sync targets so the
UI can prove local-only handling, per the shape fixed in
docs/04-api-contracts.md. Sync targets stay empty until Phase 9 lands
SyncManager; list_sync_targets' not_implemented error is swallowed
rather than failing the whole self-check.
2026-07-01 17:01:40 -05:00
iamdoubz 826d87c7fa Persist calendar events/attendees with dedup; link meetings to events (T6.2/T6.3/T6.6) 2026-07-01 15:07:40 -05:00
iamdoubz cd170c2907 Add CalendarEvent, AttendeeInfo, ImportedEvent types for calendar import (T6.1) 2026-07-01 15:07:36 -05:00