@agent-native/core 0.114.6 → 0.114.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +15 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/mcp-config-writers.ts +6 -4
- package/corpus/core/src/cli/mcp.ts +124 -0
- package/corpus/core/src/cli/skills-content/help.ts +4 -3
- package/corpus/core/src/cli/skills-content/index.ts +1 -0
- package/corpus/core/src/cli/skills-content/rewind-skill.ts +52 -0
- package/corpus/core/src/cli/skills.ts +115 -13
- package/corpus/core/src/mcp/screen-memory-stdio.ts +1360 -104
- package/corpus/core/src/mcp-client/index.ts +9 -0
- package/corpus/core/src/mcp-client/screen-memory-local.ts +847 -13
- package/corpus/core/src/server/agent-chat-plugin.ts +16 -9
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +19 -7
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-portal.ts +60 -0
- package/corpus/templates/analytics/app/routes/chart.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-07-20-dashboard-requests-no-longer-stall-without-progress.md +6 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -0
- package/corpus/templates/clips/actions/apply-rewind-extension.ts +195 -0
- package/corpus/templates/clips/actions/delete-agent-recording-if-unpromoted.ts +64 -0
- package/corpus/templates/clips/actions/get-rewind-extension-request.ts +22 -0
- package/corpus/templates/clips/actions/get-screen-memory-status.ts +18 -2
- package/corpus/templates/clips/actions/list-rewind-extension-requests.ts +52 -0
- package/corpus/templates/clips/actions/make-recording-private-for-rewind.ts +55 -0
- package/corpus/templates/clips/actions/query-screen-memory-context.ts +4 -4
- package/corpus/templates/clips/actions/request-rewind-extension.ts +81 -0
- package/corpus/templates/clips/actions/update-rewind-extension-request.ts +47 -0
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +25 -0
- package/corpus/templates/clips/app/components/editor/editor-toolbar.tsx +36 -0
- package/corpus/templates/clips/app/components/editor/rewind-extension-dialog.tsx +338 -0
- package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +1 -16
- package/corpus/templates/clips/app/components/editor/timeline.tsx +26 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +18 -0
- package/corpus/templates/clips/app/lib/ffmpeg-export.ts +19 -12
- package/corpus/templates/clips/app/lib/rewind-visibility.ts +31 -0
- package/corpus/templates/clips/app/lib/timestamp-mapping.ts +7 -0
- package/corpus/templates/clips/app/lib/upload-file-client.ts +17 -0
- package/corpus/templates/clips/changelog/2026-07-14-rewind-keeps-recent-screen-context-local-and-turns-it-into-clips.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-active-clips-keep-rewind-stable-and-settings-clear.md +12 -0
- package/corpus/templates/clips/changelog/2026-07-17-clicking-the-clips-icon-during-a-recording-now-opens-the-app.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-default-mic-now-uses-the-mac-default-and-transcription-shares-one-capture.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-full-screen-clips-finalize-even-when-screencapturekit-stop-hangs.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-normal-full-screen-clips-no-longer-stop-immediately-after-th.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-can-hand-one-bounded-private-clip-to-your-agent.md +12 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-home-can-copy-a-local-agent-prompt.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-now-has-a-calm-home-status-focused-first-run-consent-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-settings-are-smaller-clearer-and-agent-first.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-the-full-clips-interface-stays-available-while-recording.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-18-rewind-organizes-recent-work-into-local-searchable-chapters.md +8 -0
- package/corpus/templates/clips/changelog/2026-07-18-searchable-rewind-chapters.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-19-rewind-backed-recordings-now-start-immediately-after-the-cou.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-rewind-can-set-up-your-local-agent-once-so-future-requests-w.md +6 -0
- package/corpus/templates/clips/desktop/package.json +1 -0
- package/corpus/templates/clips/desktop/scripts/sign-macos-local.ts +12 -1
- package/corpus/templates/clips/desktop/src/app.tsx +2498 -239
- package/corpus/templates/clips/desktop/src/components/ReadinessPanel.tsx +21 -1
- package/corpus/templates/clips/desktop/src/components/Switch.tsx +3 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +156 -24
- package/corpus/templates/clips/desktop/src/lib/native-recording-warm.ts +6 -7
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +1763 -1160
- package/corpus/templates/clips/desktop/src/lib/rewind-agent-prompt.ts +9 -0
- package/corpus/templates/clips/desktop/src/lib/rewind-recording-start.ts +20 -0
- package/corpus/templates/clips/desktop/src/main.tsx +3 -0
- package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +14 -14
- package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +4 -4
- package/corpus/templates/clips/desktop/src/overlays/preparing.tsx +13 -0
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +27 -2
- package/corpus/templates/clips/desktop/src/shared/config.ts +16 -0
- package/corpus/templates/clips/desktop/src/styles.css +956 -134
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +5 -0
- package/corpus/templates/clips/desktop/src-tauri/build.rs +69 -1
- package/corpus/templates/clips/desktop/src-tauri/src/accessibility.rs +386 -12
- package/corpus/templates/clips/desktop/src-tauri/src/capture_audio_bus.rs +382 -0
- package/corpus/templates/clips/desktop/src-tauri/src/capture_graph.rs +777 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +249 -22
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +148 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +58 -4
- package/corpus/templates/clips/desktop/src-tauri/src/logfile.rs +13 -1
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +1505 -51
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +124 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1006 -95
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_capture_suspension.rs +165 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_chapters.rs +2434 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +1650 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_egress.rs +643 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_local_ask.rs +803 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_meeting_history.rs +595 -0
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory.rs +2900 -91
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory_ocr.rs +360 -0
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory_transcript.rs +408 -0
- package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +114 -33
- package/corpus/templates/clips/desktop/src-tauri/src/state.rs +2 -2
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +13 -3
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +4 -1
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +7 -13
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +198 -11
- package/corpus/templates/clips/desktop/src-tauri/tauri.alpha.conf.json +17 -0
- package/corpus/toolkit/CHANGELOG.md +6 -0
- package/corpus/toolkit/package.json +1 -1
- package/dist/cli/mcp-config-writers.d.ts +2 -2
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +6 -6
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/mcp.d.ts +14 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +79 -0
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/skills-content/help.d.ts +1 -1
- package/dist/cli/skills-content/help.d.ts.map +1 -1
- package/dist/cli/skills-content/help.js +4 -3
- package/dist/cli/skills-content/help.js.map +1 -1
- package/dist/cli/skills-content/index.d.ts +1 -0
- package/dist/cli/skills-content/index.d.ts.map +1 -1
- package/dist/cli/skills-content/index.js +1 -0
- package/dist/cli/skills-content/index.js.map +1 -1
- package/dist/cli/skills-content/rewind-skill.d.ts +2 -0
- package/dist/cli/skills-content/rewind-skill.d.ts.map +1 -0
- package/dist/cli/skills-content/rewind-skill.js +53 -0
- package/dist/cli/skills-content/rewind-skill.js.map +1 -0
- package/dist/cli/skills.d.ts +6 -0
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +90 -14
- package/dist/cli/skills.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +365 -0
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
- package/dist/mcp/screen-memory-stdio.js +1014 -91
- package/dist/mcp/screen-memory-stdio.js.map +1 -1
- package/dist/mcp-client/index.d.ts +1 -1
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +1 -1
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/screen-memory-local.d.ts +90 -0
- package/dist/mcp-client/screen-memory-local.d.ts.map +1 -1
- package/dist/mcp-client/screen-memory-local.js +590 -12
- package/dist/mcp-client/screen-memory-local.js.map +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-chat-plugin.d.ts +5 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +10 -9
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/mcp-config-writers.ts +6 -4
- package/src/cli/mcp.ts +124 -0
- package/src/cli/skills-content/help.ts +4 -3
- package/src/cli/skills-content/index.ts +1 -0
- package/src/cli/skills-content/rewind-skill.ts +52 -0
- package/src/cli/skills.ts +115 -13
- package/src/mcp/screen-memory-stdio.ts +1360 -104
- package/src/mcp-client/index.ts +9 -0
- package/src/mcp-client/screen-memory-local.ts +847 -13
- package/src/server/agent-chat-plugin.ts +16 -9
|
@@ -157,6 +157,26 @@ export function ReadinessPanel({
|
|
|
157
157
|
}
|
|
158
158
|
}, []);
|
|
159
159
|
|
|
160
|
+
const requestOrOpenPermission = useCallback(
|
|
161
|
+
async (pane: MacosPrivacyPane) => {
|
|
162
|
+
if (mac && pane === "screen") {
|
|
163
|
+
try {
|
|
164
|
+
const granted = await invoke<boolean>(
|
|
165
|
+
"system_audio_request_permission",
|
|
166
|
+
);
|
|
167
|
+
await checkStatuses();
|
|
168
|
+
if (granted) return;
|
|
169
|
+
} catch {
|
|
170
|
+
// Fall through to the dedicated privacy pane. The request API may
|
|
171
|
+
// be unavailable on an older macOS build or the user may already
|
|
172
|
+
// have denied the prompt once.
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
onOpenPermission(pane);
|
|
176
|
+
},
|
|
177
|
+
[checkStatuses, mac, onOpenPermission],
|
|
178
|
+
);
|
|
179
|
+
|
|
160
180
|
useEffect(() => {
|
|
161
181
|
if (open && !statuses && mac) checkStatuses();
|
|
162
182
|
}, [open, statuses, mac, checkStatuses]);
|
|
@@ -219,7 +239,7 @@ export function ReadinessPanel({
|
|
|
219
239
|
<button
|
|
220
240
|
type="button"
|
|
221
241
|
className="readiness-open-button"
|
|
222
|
-
onClick={() =>
|
|
242
|
+
onClick={() => void requestOrOpenPermission(item.pane)}
|
|
223
243
|
>
|
|
224
244
|
Open
|
|
225
245
|
</button>
|
|
@@ -2,10 +2,12 @@ export function Switch({
|
|
|
2
2
|
on,
|
|
3
3
|
onChange,
|
|
4
4
|
label,
|
|
5
|
+
disabled = false,
|
|
5
6
|
}: {
|
|
6
7
|
on: boolean;
|
|
7
8
|
onChange: (v: boolean) => void;
|
|
8
9
|
label: string;
|
|
10
|
+
disabled?: boolean;
|
|
9
11
|
}) {
|
|
10
12
|
return (
|
|
11
13
|
<button
|
|
@@ -14,6 +16,7 @@ export function Switch({
|
|
|
14
16
|
role="switch"
|
|
15
17
|
aria-checked={on}
|
|
16
18
|
aria-label={label}
|
|
19
|
+
disabled={disabled}
|
|
17
20
|
onClick={() => onChange(!on)}
|
|
18
21
|
>
|
|
19
22
|
<span className="switch-thumb" aria-hidden />
|
|
@@ -23,6 +23,8 @@ export interface MeetingTranscriptionPayload {
|
|
|
23
23
|
meetingId: string;
|
|
24
24
|
joinUrl?: string | null;
|
|
25
25
|
reason?: "user" | "calendar-auto" | string;
|
|
26
|
+
scheduledStart?: string | null;
|
|
27
|
+
includeFromMeetingStart?: boolean;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
interface MeetingTranscriptionSession {
|
|
@@ -35,6 +37,9 @@ interface MeetingTranscriptionSession {
|
|
|
35
37
|
stopping: boolean;
|
|
36
38
|
paused: boolean;
|
|
37
39
|
engine: TranscriptionEngine;
|
|
40
|
+
/** Offset local live-engine timestamps onto the scheduled meeting timeline. */
|
|
41
|
+
liveTimelineOffsetMs: number;
|
|
42
|
+
historyInFlight: Promise<void> | null;
|
|
38
43
|
// Single-flight flush bookkeeping (M3): `flushInFlight` is the promise of
|
|
39
44
|
// the currently-running save-browser-transcript call (or null). `flushSeq`
|
|
40
45
|
// is bumped every time flushTranscript is invoked; `dirtySeq` records the
|
|
@@ -175,6 +180,9 @@ export function useMeetingTranscription({
|
|
|
175
180
|
}
|
|
176
181
|
});
|
|
177
182
|
await invoke("silence_detector_stop").catch(() => {});
|
|
183
|
+
if (reason !== "app-quit") {
|
|
184
|
+
await session.historyInFlight?.catch(() => {});
|
|
185
|
+
}
|
|
178
186
|
// Final flush waits for any in-flight flush first (flushTranscript's
|
|
179
187
|
// single-flight coalescing) then sends the definitive snapshot.
|
|
180
188
|
await flushTranscript().catch((err) => {
|
|
@@ -257,7 +265,29 @@ export function useMeetingTranscription({
|
|
|
257
265
|
await stopTranscription("replaced");
|
|
258
266
|
}
|
|
259
267
|
|
|
268
|
+
let historyPreparedRef: {
|
|
269
|
+
current: {
|
|
270
|
+
token: string;
|
|
271
|
+
scheduledStart: string;
|
|
272
|
+
capturedUntil: string;
|
|
273
|
+
} | null;
|
|
274
|
+
} = { current: null };
|
|
260
275
|
try {
|
|
276
|
+
if (payload.includeFromMeetingStart) {
|
|
277
|
+
if (payload.reason !== "user" || !payload.scheduledStart) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
"Include from meeting start is only available when you manually start a scheduled meeting.",
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
historyPreparedRef.current = await invoke<{
|
|
283
|
+
token: string;
|
|
284
|
+
scheduledStart: string;
|
|
285
|
+
capturedUntil: string;
|
|
286
|
+
}>("rewind_meeting_history_prepare", {
|
|
287
|
+
scheduledStart: payload.scheduledStart,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
261
291
|
const result = await callClipsAction<{
|
|
262
292
|
meetingId?: string;
|
|
263
293
|
scheduledEnd?: string | null;
|
|
@@ -286,19 +316,13 @@ export function useMeetingTranscription({
|
|
|
286
316
|
stopping: false,
|
|
287
317
|
paused: false,
|
|
288
318
|
engine: "whisper",
|
|
319
|
+
liveTimelineOffsetMs: 0,
|
|
320
|
+
historyInFlight: null,
|
|
289
321
|
flushInFlight: null,
|
|
290
322
|
flushSeq: 0,
|
|
291
323
|
dirtySeq: 0,
|
|
292
324
|
};
|
|
293
325
|
sessionRef.current = session;
|
|
294
|
-
await invoke("set_recording_state", { active: true }).catch(() => {});
|
|
295
|
-
await invoke("set_meeting_active", {
|
|
296
|
-
active: true,
|
|
297
|
-
meetingId: resolvedMeetingId,
|
|
298
|
-
}).catch(() => {});
|
|
299
|
-
emit("meetings:transcription-started", {
|
|
300
|
-
meetingId: resolvedMeetingId,
|
|
301
|
-
}).catch(() => {});
|
|
302
326
|
|
|
303
327
|
const scheduleFlush = () => {
|
|
304
328
|
if (session.flushTimer) window.clearTimeout(session.flushTimer);
|
|
@@ -325,7 +349,23 @@ export function useMeetingTranscription({
|
|
|
325
349
|
addUnlisten(
|
|
326
350
|
onFinalTranscript((event) => {
|
|
327
351
|
if (sessionRef.current !== session) return;
|
|
328
|
-
|
|
352
|
+
const timelineEvent = session.liveTimelineOffsetMs
|
|
353
|
+
? {
|
|
354
|
+
...event,
|
|
355
|
+
segments: event.segments.map((segment) => ({
|
|
356
|
+
...segment,
|
|
357
|
+
startMs: segment.startMs + session.liveTimelineOffsetMs,
|
|
358
|
+
endMs: segment.endMs + session.liveTimelineOffsetMs,
|
|
359
|
+
})),
|
|
360
|
+
}
|
|
361
|
+
: event;
|
|
362
|
+
if (
|
|
363
|
+
appendFinalTranscript(
|
|
364
|
+
timelineEvent,
|
|
365
|
+
session.lines,
|
|
366
|
+
session.segments,
|
|
367
|
+
)
|
|
368
|
+
) {
|
|
329
369
|
scheduleFlush();
|
|
330
370
|
}
|
|
331
371
|
}),
|
|
@@ -471,24 +511,15 @@ export function useMeetingTranscription({
|
|
|
471
511
|
}),
|
|
472
512
|
);
|
|
473
513
|
|
|
474
|
-
//
|
|
475
|
-
//
|
|
514
|
+
// Prepare the pill payload before live audio starts, but don't show a
|
|
515
|
+
// recording indicator or publish an active meeting until the engine
|
|
516
|
+
// has actually acquired its audio source. This keeps "Recording"
|
|
517
|
+
// truthful when model/capture startup fails.
|
|
476
518
|
pendingPillInitRef.current = {
|
|
477
519
|
meetingId: resolvedMeetingId,
|
|
478
520
|
initialNotes: "",
|
|
479
521
|
};
|
|
480
522
|
|
|
481
|
-
await invoke("recording_pill_show", {
|
|
482
|
-
meetingId: resolvedMeetingId,
|
|
483
|
-
mode: "meeting",
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
// Immediate emit covers the reused-window case (pill already mounted).
|
|
487
|
-
emit("clips:pill-context", {
|
|
488
|
-
meetingId: resolvedMeetingId,
|
|
489
|
-
mode: "meeting",
|
|
490
|
-
}).catch(() => {});
|
|
491
|
-
|
|
492
523
|
callClipsAction<{
|
|
493
524
|
meeting?: { userNotesMd?: string };
|
|
494
525
|
transcript?: { segmentsJson?: string | null } | null;
|
|
@@ -503,6 +534,11 @@ export function useMeetingTranscription({
|
|
|
503
534
|
pendingPillInitRef.current = {
|
|
504
535
|
meetingId: resolvedMeetingId,
|
|
505
536
|
initialNotes,
|
|
537
|
+
preloadedLines: session.segments.map((segment) => ({
|
|
538
|
+
text: segment.text,
|
|
539
|
+
source: segment.source,
|
|
540
|
+
startMs: segment.startMs,
|
|
541
|
+
})),
|
|
506
542
|
};
|
|
507
543
|
emit("clips:meeting-notes-init", {
|
|
508
544
|
meetingId: resolvedMeetingId,
|
|
@@ -534,9 +570,9 @@ export function useMeetingTranscription({
|
|
|
534
570
|
...preloadedSegments,
|
|
535
571
|
...session.segments,
|
|
536
572
|
];
|
|
537
|
-
const preloadedLines =
|
|
573
|
+
const preloadedLines = session.segments.map((s) => ({
|
|
538
574
|
text: s.text,
|
|
539
|
-
source:
|
|
575
|
+
source: s.source,
|
|
540
576
|
startMs: s.startMs,
|
|
541
577
|
}));
|
|
542
578
|
// Store in ref so clips:pill-ready can re-emit if the
|
|
@@ -560,6 +596,15 @@ export function useMeetingTranscription({
|
|
|
560
596
|
})
|
|
561
597
|
.catch(() => {});
|
|
562
598
|
|
|
599
|
+
// The local index may need a moment after the fragment fence. Anchor
|
|
600
|
+
// the live engine where it actually begins, not at the earlier click,
|
|
601
|
+
// so every stored segment remains on one honest meeting timeline.
|
|
602
|
+
if (payload.includeFromMeetingStart && payload.scheduledStart) {
|
|
603
|
+
session.liveTimelineOffsetMs = Math.max(
|
|
604
|
+
0,
|
|
605
|
+
Date.now() - Date.parse(payload.scheduledStart),
|
|
606
|
+
);
|
|
607
|
+
}
|
|
563
608
|
session.engine = await startTranscriptionEngine({
|
|
564
609
|
mic: { deviceId: selectedMicId, label: selectedMicLabel },
|
|
565
610
|
// macOS 15+ uses ScreenCaptureKit's independent microphone output.
|
|
@@ -568,6 +613,81 @@ export function useMeetingTranscription({
|
|
|
568
613
|
voiceProcessing: false,
|
|
569
614
|
});
|
|
570
615
|
|
|
616
|
+
await invoke("set_recording_state", { active: true }).catch(() => {});
|
|
617
|
+
await invoke("set_meeting_active", {
|
|
618
|
+
active: true,
|
|
619
|
+
meetingId: resolvedMeetingId,
|
|
620
|
+
}).catch(() => {});
|
|
621
|
+
await invoke("recording_pill_show", {
|
|
622
|
+
meetingId: resolvedMeetingId,
|
|
623
|
+
mode: "meeting",
|
|
624
|
+
});
|
|
625
|
+
// Immediate emit covers the reused-window case (pill already mounted).
|
|
626
|
+
emit("clips:pill-context", {
|
|
627
|
+
meetingId: resolvedMeetingId,
|
|
628
|
+
mode: "meeting",
|
|
629
|
+
}).catch(() => {});
|
|
630
|
+
emit("meetings:transcription-started", {
|
|
631
|
+
meetingId: resolvedMeetingId,
|
|
632
|
+
}).catch(() => {});
|
|
633
|
+
|
|
634
|
+
// Indexing the fenced local fragment can take tens of seconds. It runs
|
|
635
|
+
// after live capture is active, then prepends its bounded rows into the
|
|
636
|
+
// same canonical session. A local-index failure is visible but never
|
|
637
|
+
// tears down notes that are already recording.
|
|
638
|
+
if (historyPreparedRef.current) {
|
|
639
|
+
const prepared = historyPreparedRef.current;
|
|
640
|
+
const historyPromise = invoke<{
|
|
641
|
+
segments: SourcedTranscriptSegment[];
|
|
642
|
+
}>("rewind_meeting_history_collect", { token: prepared.token })
|
|
643
|
+
.then((history) => {
|
|
644
|
+
if (sessionRef.current !== session) return;
|
|
645
|
+
const historyLines = history.segments.map(
|
|
646
|
+
(segment) => `${speakerFor(segment.source)}: ${segment.text}`,
|
|
647
|
+
);
|
|
648
|
+
session.lines = [...historyLines, ...session.lines];
|
|
649
|
+
session.segments = [...history.segments, ...session.segments];
|
|
650
|
+
const preloadedLines = session.segments.map((segment) => ({
|
|
651
|
+
text: segment.text,
|
|
652
|
+
source: segment.source,
|
|
653
|
+
startMs: segment.startMs,
|
|
654
|
+
}));
|
|
655
|
+
if (pendingPillInitRef.current?.meetingId === resolvedMeetingId) {
|
|
656
|
+
pendingPillInitRef.current = {
|
|
657
|
+
...pendingPillInitRef.current,
|
|
658
|
+
preloadedLines,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
emit("clips:transcript-preload", {
|
|
662
|
+
lines: preloadedLines,
|
|
663
|
+
}).catch(() => {});
|
|
664
|
+
flushTranscript().catch((err) => {
|
|
665
|
+
console.warn(
|
|
666
|
+
"[clips-popover] earlier meeting transcript save failed:",
|
|
667
|
+
err,
|
|
668
|
+
);
|
|
669
|
+
});
|
|
670
|
+
})
|
|
671
|
+
.catch((error) => {
|
|
672
|
+
const message =
|
|
673
|
+
typeof error === "string"
|
|
674
|
+
? error
|
|
675
|
+
: error instanceof Error
|
|
676
|
+
? error.message
|
|
677
|
+
: "Earlier local meeting audio could not be included.";
|
|
678
|
+
emit("meetings:history-error", {
|
|
679
|
+
meetingId: resolvedMeetingId,
|
|
680
|
+
error: message,
|
|
681
|
+
}).catch(() => {});
|
|
682
|
+
})
|
|
683
|
+
.finally(() => {
|
|
684
|
+
if (session.historyInFlight === historyPromise) {
|
|
685
|
+
session.historyInFlight = null;
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
session.historyInFlight = historyPromise;
|
|
689
|
+
}
|
|
690
|
+
|
|
571
691
|
await invoke("silence_detector_start", {
|
|
572
692
|
config: silenceDetectorConfig,
|
|
573
693
|
}).catch(() => {});
|
|
@@ -580,7 +700,19 @@ export function useMeetingTranscription({
|
|
|
580
700
|
|
|
581
701
|
emit("meetings:hide-notification", { meetingId }).catch(() => {});
|
|
582
702
|
} catch (err) {
|
|
703
|
+
if (historyPreparedRef.current) {
|
|
704
|
+
invoke("rewind_meeting_history_cancel", {
|
|
705
|
+
token: historyPreparedRef.current.token,
|
|
706
|
+
}).catch(() => {});
|
|
707
|
+
}
|
|
708
|
+
const failedSession = sessionRef.current;
|
|
583
709
|
sessionRef.current = null;
|
|
710
|
+
if (failedSession?.meetingId) {
|
|
711
|
+
await callClipsAction("stop-meeting-recording", {
|
|
712
|
+
meetingId: failedSession.meetingId,
|
|
713
|
+
}).catch(() => {});
|
|
714
|
+
}
|
|
715
|
+
pendingPillInitRef.current = null;
|
|
584
716
|
await invoke("recording_pill_hide").catch(() => {});
|
|
585
717
|
await invoke("set_recording_state", { active: false }).catch(() => {});
|
|
586
718
|
await invoke("set_meeting_active", { active: false }).catch(() => {});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Hosted native start sequencing:
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Hosted native start sequencing: create the recording, warm its one physical
|
|
3
|
+
* SCK capture (which registers the shared audio producer), then attach Whisper
|
|
4
|
+
* as a PCM subscriber. The countdown still hides this work, while the ordering
|
|
5
|
+
* prevents a second microphone capture from muting both consumers.
|
|
5
6
|
*/
|
|
6
7
|
export function planNativeFullscreenWarmOverlap<
|
|
7
8
|
TRecording extends { id: string },
|
|
@@ -10,12 +11,10 @@ export function planNativeFullscreenWarmOverlap<
|
|
|
10
11
|
startTranscription: () => Promise<unknown>;
|
|
11
12
|
warmMic: (recordingId: string) => Promise<unknown>;
|
|
12
13
|
}): Promise<TRecording> {
|
|
13
|
-
const transcriptionPromise = input.startTranscription();
|
|
14
14
|
return (async () => {
|
|
15
15
|
const created = await input.createRecording();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
await Promise.all([transcriptionPromise, input.warmMic(created.id)]);
|
|
16
|
+
await input.warmMic(created.id);
|
|
17
|
+
await input.startTranscription();
|
|
19
18
|
return created;
|
|
20
19
|
})();
|
|
21
20
|
}
|