Commit Graph
183 Commits
Author SHA1 Message Date
iamdoubz e0112ec8c4 style(mcp): rustfmt 2026-07-07 00:29:48 -05:00
iamdoubz 45e34284e9 fix(mcp): use HttpServerHandle.local_addr instead of a second lookup (T10.4)
Fixes a dead_code warning (clippy -D warnings would fail on it) --
server.rs was calling listener.local_addr() itself before handing the
listener to http_transport::serve(), leaving the handle's own
local_addr field unread.
2026-07-07 00:27:56 -05:00
iamdoubz 0ecc72f18f feat(mcp): wire mcp_status/set_mcp_enabled/set_mcp_scope/mcp_access_log (T10.4)
Replaces the four not_implemented() stubs. mcp_status/set_mcp_enabled
reach the process-wide RmcpServer singleton (behind `#[cfg(feature =
"mcp")]`, with a not_implemented fallback for builds without it);
set_mcp_scope/mcp_access_log are plain settings/Store I/O and work in
every build regardless of the `mcp` cargo feature. The token is only
ever returned once, right when set_mcp_enabled mints it -- it is never
re-readable afterwards, same as any other freshly-issued secret.
2026-07-07 00:26:11 -05:00
iamdoubz f99845ef1b feat(mcp): run_mcp_stdio() serves one session over process stdio (T10.4, FR-MCP-6)
Builds its own tokio runtime (there is no Tauri app in this mode) and
tracing goes to stderr, not stdout -- stdout is the MCP JSON-RPC channel.
Connects to the same wa.db as the GUI instance via SqliteStore::connect,
builds a WaMcpHandler with no AppHandle (None), and runs it to
completion via mcp::stdio_transport::serve_once. A build without the
`mcp` feature prints an error and exits(1) instead of silently opening
the GUI.
2026-07-07 00:24:47 -05:00
iamdoubz f85b78c9eb fix(mcp): add tokio-util for CancellationToken (T10.4)
http_transport.rs needs tokio_util::sync::CancellationToken directly;
rmcp pulls tokio-util transitively but that doesn't make it `use`-able
from our own crate without a direct Cargo.toml entry.
2026-07-07 00:24:32 -05:00
iamdoubz 949bade137 feat(mcp): --mcp-stdio launches the headless stdio adapter (T10.4, FR-MCP-6)
Checked before whispassist_lib::run() builds the Tauri app -- the flag
routes straight to run_mcp_stdio() (next commit) and returns instead of
opening a window.
2026-07-07 00:23:47 -05:00
iamdoubz eb2aa2a0d6 fix(mcp): pass the GUI's AppHandle as Some(..) to the handler (T10.4)
Follows the previous commit's WaMcpHandler::new signature change.
2026-07-07 00:23:27 -05:00
iamdoubz 49cc1e6cd3 fix(mcp): WaMcpHandler's AppHandle is optional (T10.4)
The --mcp-stdio child process (main.rs, next commits) has no running
Tauri app/window to emit "mcp://access" events to -- only the GUI
instance's HTTP transport does. The mcp_access_log DB row is still
written unconditionally either way (FR-MCP-5); only the live event is
skipped when there's no AppHandle.
2026-07-07 00:23:20 -05:00
iamdoubz bd9b5ba3cc feat(mcp): RmcpServer wires token+transport+handler together (T10.4)
start() mints/stores a fresh token, then either binds the loopback HTTP
listener (bind_loopback + http_transport::serve) or, for stdio, just
records "enabled" and hands back the whishassist.exe --mcp-stdio command
line the agent's client config should spawn -- there is nothing to run
in-process for stdio (see mcp::stdio_transport). stop() tears down the
HTTP listener if any and deletes the stored token. instance() is a
process-wide singleton (OnceLock) so separate Tauri command invocations
(set_mcp_enabled/mcp_status/set_mcp_scope) share the same running state.
2026-07-07 00:22:35 -05:00
iamdoubz 58d565907b feat(mcp): McpToolDescriptor is Copy (T10.4)
Needed so RmcpServer::tools() can hand back TOOL_DESCRIPTORS without a
manual field-by-field clone (next commit).
2026-07-07 00:21:58 -05:00
iamdoubz 5f690f4b74 feat(mcp): stdio transport adapter (T10.4, FR-MCP-6)
serve_once() runs one MCP session over the current process's stdin/
stdout to completion -- the entry point main.rs's --mcp-stdio flag calls
into (next commit). No bearer-token check here: spawning this process
at all requires the same local-user privilege as any other command, so
process-spawn capability is the trust boundary for stdio, not a header.
2026-07-07 00:21:16 -05:00
iamdoubz 851e89720d feat(mcp): auth token in the OS credential store, not settings/DB (T10.4, FR-MCP-1)
Mirrors sync::credentials: mint_and_store() generates a fresh 32-byte
random token per set_mcp_enabled call and writes it via `keyring`
(Windows Credential Manager); the token is never persisted to
settings.json/wa.db/logs. verify() is a constant-time compare so token
checking doesn't leak timing information about a partial match
(NFR-SEC-5).
2026-07-07 00:20:39 -05:00
iamdoubz 9eed88e5bd feat(mcp): loopback bind + bearer-token gate for Streamable HTTP (T10.4, FR-MCP-1/6)
bind_loopback() refuses to bind anything that doesn't resolve to a
loopback address -- unit tested directly (non-loopback IP, unparseable
host, and a real 127.0.0.1:0 bind). serve() runs a hyper HTTP/1 accept
loop in front of rmcp's StreamableHttpService (a bare tower_service, not
an axum app); every request needs `Authorization: Bearer <token>`
(constant-time compared via mcp::token::verify) before it ever reaches
the MCP service -- an unauthenticated request never reaches rmcp at all.
2026-07-07 00:20:14 -05:00
iamdoubz c48c67760d build(mcp): pull in the HTTP/stdio transport features (T10.4)
rmcp gains transport-streamable-http-server + transport-io (the actual
serving code -- the base "server" feature only got tool routing) plus
client + transport-streamable-http-client-reqwest, used solely by this
crate's own in-process MCP-client tests (WA never opens an outbound MCP
connection at runtime, so this is not new egress, FR-MCP-7). hyper/
hyper-util/http-body-util/http/bytes/tower-service are the low-level glue
to run HTTP/1 over a loopback TcpListener in front of rmcp's
StreamableHttpService (a bare tower_service::Service, not an axum app).
All are already in Cargo.lock transitively via reqwest/tauri -- no new
crates, just promoted to direct deps under the existing `mcp` feature.
2026-07-07 00:19:15 -05:00
iamdoubz 14868d4e5c feat(mcp): ServerHandler implementing the four MCP tools (T10.5)
WaMcpHandler wires list_recent_meetings/get_transcript/get_action_items/
get_feature_brief to Store, re-checking ExposeScope + the recordings
gate independently in every handler (FR-MCP-3) and logging every read
via record_mcp_access + an "mcp://access" event (FR-MCP-5) before scope
is even evaluated, so the audit trail is "what was asked for", not just
"what was returned". get_feature_brief calls through the existing
commands::get_feature_brief stub per the M1/M2 integration contract --
it always errors right now since M1's brief storage isn't implemented
in this worktree yet; the `selected`-scope exposed-flag check is left
as a marked TODO for when M1 lands.
2026-07-07 00:17:56 -05:00
iamdoubz fc93f8e14f feat(mcp): scope-control logic, unit tested (T10.7, FR-MCP-3)
Pure functions (no DB, no cargo feature gate) so scope control is
testable without a running server: meetings_visible/brief_visible/
recording_gate_ok/meeting_allowed. Documents the conservative choice for
`selected` scope on meetings/transcript/action-items -- there's no
per-meeting selection flag in the schema yet (only feature_briefs.exposed
does), so `selected` behaves like `none` there until a real "pick which
meetings" mechanism exists, rather than silently behaving like `all`.
2026-07-07 00:14:50 -05:00
iamdoubz c73245f293 feat(mcp): trait/config plumbing for the real server (T10.4)
ExposeScope/McpTransport gain as_str/parse (privacy-safe fallback: an
unparsed scope becomes None, not All/Selected) so commands.rs can read
them out of Settings' string fields. Declares the mcp submodules
(scope always compiled; handler/http_transport/server/stdio_transport/
token behind the `mcp` cargo feature) and removes the todo!() RmcpServer
stub -- its real implementation moves to mcp::server in the next commits.
2026-07-07 00:14:32 -05:00
iamdoubz e0668e48df feat(mcp): Store methods for action items + access log (T10.4/10.5)
Adds list_action_items (backs the get_action_items MCP tool -- distinct
from list_pending_reminders, which is reminder-scoped across all
meetings) and record_mcp_access/list_mcp_access_log (FR-MCP-5 audit
trail) to the Store trait + SqliteStore, reusing the mcp_access_log
table from migrations/0003_ai_mcp.sql.
2026-07-07 00:13:11 -05:00
iamdoubz 999084ab3f feat(mcp): default_settings() covers the new MCP fields (T10.4)
Keeps default_settings() exhaustive now that Settings grew mcp_* fields.
2026-07-07 00:10:37 -05:00
iamdoubz c88c04233c feat(mcp): add MCP settings fields to Settings (T10.4)
Adds mcp_enabled/mcp_transport/mcp_port/mcp_expose/mcp_expose_recordings
to Settings, all defaulting to off/none so an upgrading settings.json
gets a fully-local default (FR-MCP-1). The auth token itself never lives
here -- OS credential store only (see mcp::token, next commit).
2026-07-07 00:10:17 -05:00
iamdoubz 233c6fa8cd chore(release): bump version to 0.2.0 + refresh README 2026-07-06 19:14:51 -05:00
iamdoubz 2a0379ce43 build: bundle vulkan-1.dll so the single Vulkan installer runs on non-GPU machines 2026-07-06 19:06:07 -05:00
iamdoubz 91677476cc build: stage redistributable vulkan-1.dll for the merged installer 2026-07-06 19:06:06 -05:00
iamdoubz 76a4f8ce08 build: lockfile after dropping protocol-asset 2026-07-06 18:40:18 -05:00
iamdoubz 90ba14cc2d build: drop tauri protocol-asset feature (no longer used) 2026-07-06 18:40:15 -05:00
iamdoubz 7106dc1584 feat(recording): CSP media-src for waaudio://; drop asset protocol 2026-07-06 18:40:14 -05:00
iamdoubz 84b9087de7 feat(recording): register waaudio:// protocol + sweep plaintext temp files 2026-07-06 18:40:13 -05:00
iamdoubz 1634820523 feat(recording): stream + decrypt recordings in memory via waaudio:// (FR-REC-5) 2026-07-06 18:40:12 -05:00
iamdoubz 49893d5874 feat(audio): wire MicBridge so recordings include the user's voice 2026-07-06 18:25:57 -05:00
iamdoubz a14ca871e1 fix(audio): mix mic into the recording at native rate via MicBridge (FR-CAP-7) 2026-07-06 18:25:56 -05:00
iamdoubz ea79fb656d docs(commands): correct playback requirement id to FR-REC-5 2026-07-06 17:56:16 -05:00
iamdoubz a7eba7fd82 build: lockfile for tauri protocol-asset (http-range) 2026-07-06 17:55:13 -05:00
iamdoubz 010941e620 feat: enable asset protocol + media-src CSP for recording playback 2026-07-06 17:52:00 -05:00
iamdoubz 90580da0af build: enable tauri protocol-asset feature for recording playback 2026-07-06 17:51:59 -05:00
iamdoubz e715c09ce0 feat: register cancel_recording + recording_playback_path commands 2026-07-06 17:51:58 -05:00
iamdoubz da25ccaec6 feat: cancel_recording, recording_playback_path, live sync progress 2026-07-06 17:51:57 -05:00
iamdoubz e7f628ad7a feat(sync): stream upload bodies with live byte progress (FR-SYNC-11) 2026-07-06 17:51:55 -05:00
iamdoubz 25d0232256 feat(vault): add is_sealed() helper 2026-07-06 17:51:54 -05:00
iamdoubz 34b4f4ae09 feat(audio): write recordings as 16-bit PCM to halve .wav size (FR-CAP-8) 2026-07-06 17:51:53 -05:00
iamdoubz 4cdeb8f475 test(audio): real-hardware microphone open/stop smoke test (FR-CAP-7) 2026-07-06 16:29:56 -05:00
iamdoubz 97b5f67049 feat(audio): wire mic capture + mixer into recording lifecycle (FR-CAP-7) 2026-07-06 16:26:17 -05:00
iamdoubz 55ddaad544 feat(audio): track mic capture handle; register list_input_devices (FR-CAP-7) 2026-07-06 16:26:16 -05:00
iamdoubz 75f7d19ade feat(audio): add microphone_enabled + audio_input_device settings (FR-CAP-7) 2026-07-06 16:26:14 -05:00
iamdoubz 2fb5fd6f30 feat(audio): microphone capture + stream mixer (FR-CAP-7) 2026-07-06 16:26:13 -05:00
iamdoubz 5b281531fb feat(audio): register list_audio_devices with the Tauri invoke handler 2026-07-06 16:00:50 -05:00
iamdoubz 2759a0e49a feat(audio): add list_audio_devices command; wire device into start_recording
list_audio_devices runs the (blocking, COM-based) enumeration off the
async runtime via spawn_blocking, same pattern as import_pst_core.
start_recording now passes settings.audio_output_device through to
WasapiCapture::start instead of always capturing the default device.
2026-07-06 16:00:49 -05:00
iamdoubz 8e3e22c0e5 feat(audio): add audio_output_device to Settings
Device::get_id() string; None = system default (unchanged behavior).
#[serde(default)] so an existing settings.json without this key still
deserializes.
2026-07-06 16:00:47 -05:00
iamdoubz bb1d1730f8 feat(audio): device-selectable WASAPI loopback capture
AudioCapture::start now takes an optional device id (Device::get_id())
instead of always resolving the system default render device.
open_capture_session/find_render_device resolve the configured device,
falling back to the system default if it's no longer present (same
degrade-gracefully spirit as the existing mid-recording reconnect,
which now retries the *same* selection rather than switching to
whatever's currently default).

Adds list_render_devices() (new AudioDeviceInfo) for the Settings
picker — enumeration was already fully supported by the wasapi crate,
just unused until now.
2026-07-06 16:00:46 -05:00
iamdoubz ba1b577734 feat(llm): register generate_tags with the Tauri invoke handler 2026-07-06 15:38:01 -05:00
iamdoubz fb406d62da feat(llm): add generate_tags command
Reuses build_prompt's transcript+metadata assembly (same as
generate_summary) and the same recording-in-progress guard.
2026-07-06 15:38:00 -05:00