feat(meeting): opt-in process-list reminder when a meeting app starts

Default off. When on, the layout polls detect_meeting_processes every 15s
with the user's app-name patterns. On a fresh match (edge-triggered — no
re-toast until the app goes away and comes back) we fire a reminder toast
that tells the user which meeting app appeared and their global hotkey. We
never start recording on this signal; the ideology rule says the user
decides. The signal is a single channel: process list match only — no mic
activity heuristic, no calendar.

Backend adds kon_core::process_watch::{list_running_process_names,
match_meeting_patterns} over sysinfo, exposed to the frontend as the
detect_meeting_processes Tauri command.

Settings ships two new fields — meetingAutoCapture (bool) and
meetingAutoCaptureApps (string[]) — with a comma-separated input in the
Output section. Default app list is ["zoom", "teams"], user-editable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-21 07:54:55 +01:00
parent 63e00c15b1
commit ba0d59f563
9 changed files with 164 additions and 0 deletions

View File

@@ -1518,6 +1518,28 @@
label="Auto-paste into focused window"
description={pasteBackendsDescription}
/>
<Toggle
bind:checked={settings.meetingAutoCapture}
label="Remind me when a meeting starts"
description="Toasts when a matching app appears in the process list. You still hit the hotkey — Kon never records on its own."
/>
{#if settings.meetingAutoCapture}
<div class="ml-[50px] mt-2 mb-1 animate-fade-in">
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider mb-1.5">Apps to watch (comma-separated)</p>
<input
type="text"
class="w-full bg-bg-input border border-border-subtle rounded-lg px-3 py-1.5 text-[12px] text-text"
value={settings.meetingAutoCaptureApps.join(", ")}
oninput={(event) => {
const raw = event.currentTarget.value;
settings.meetingAutoCaptureApps = raw
.split(",")
.map((entry) => entry.trim().toLowerCase())
.filter((entry) => entry.length > 0);
}}
/>
</div>
{/if}
<Toggle bind:checked={settings.includeTimestamps} label="Include timestamps in exports" />
<Toggle
bind:checked={settings.saveAudio}

View File

@@ -47,6 +47,8 @@ const defaults: SettingsState = {
britishEnglish: true,
autoCopy: true,
autoPaste: false,
meetingAutoCapture: false,
meetingAutoCaptureApps: ["zoom", "teams"],
includeTimestamps: true,
theme: "Dark",
fontSize: 14,

View File

@@ -37,6 +37,8 @@ export interface SettingsState {
britishEnglish: boolean;
autoCopy: boolean;
autoPaste: boolean;
meetingAutoCapture: boolean;
meetingAutoCaptureApps: string[];
includeTimestamps: boolean;
theme: "Dark" | "Light" | "System";
fontSize: number;