@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
|
@@ -15,10 +15,10 @@ const POPOVER_DEFAULT_HEIGHT_LOGICAL: f64 = 520.0;
|
|
|
15
15
|
//
|
|
16
16
|
// Clips-owned recording chrome (toolbar / countdown / finalizing /
|
|
17
17
|
// recording-pill) gets `NSWindow.sharingType = NSWindowSharingNone` so it does
|
|
18
|
-
// not leak into the recorded video. The main popover
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
18
|
+
// not leak into the recorded video. The main popover follows the same user
|
|
19
|
+
// preference: private by default, shareable only when "Show Clips in screen
|
|
20
|
+
// captures" is enabled. Reopening it during a recording must not silently
|
|
21
|
+
// override that choice.
|
|
22
22
|
// Recording-time exclusion has two effects on macOS: screen pickers don't list
|
|
23
23
|
// excluded windows, and full-screen captures omit them from the compositor
|
|
24
24
|
// output. This is the same mechanism Loom, 1Password, and CleanShot use to keep
|
|
@@ -183,12 +183,9 @@ pub fn set_capture_included(_window: &WebviewWindow) {
|
|
|
183
183
|
/// immediately on anything currently on screen. Called from
|
|
184
184
|
/// `set_feature_config` when the toggle flips.
|
|
185
185
|
///
|
|
186
|
-
/// The popover
|
|
187
|
-
///
|
|
188
|
-
/// parked
|
|
189
|
-
/// the toggle, so the next `show_popover` / `park_popover_offscreen` call
|
|
190
|
-
/// picks up the new setting. Rewriting it here would clobber the parked
|
|
191
|
-
/// state mid-recording.
|
|
186
|
+
/// The popover follows the same preference as ordinary Clips chrome. Applying
|
|
187
|
+
/// it here makes the toggle take effect immediately whether the popover is
|
|
188
|
+
/// visible or parked as the 2x2 recording controller.
|
|
192
189
|
///
|
|
193
190
|
/// Region-guide overlays are private recorder aids, not Clips chrome demos, so
|
|
194
191
|
/// they stay excluded even when the debug toggle makes the rest visible.
|
|
@@ -198,9 +195,6 @@ pub fn reapply_capture_exclusion_to_overlays(app: &tauri::AppHandle) {
|
|
|
198
195
|
let visible = crate::config::show_in_screen_capture(app);
|
|
199
196
|
let windows = app.webview_windows();
|
|
200
197
|
for (label, window) in &windows {
|
|
201
|
-
if label.as_str() == "popover" {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
198
|
// The meeting reminder is a notification, not Clips recording
|
|
205
199
|
// chrome — keep it visible in captures regardless of the debug
|
|
206
200
|
// toggle so it never gets re-excluded on a config change.
|
|
@@ -16,6 +16,36 @@
|
|
|
16
16
|
//!
|
|
17
17
|
use tauri::AppHandle;
|
|
18
18
|
|
|
19
|
+
/// One timestamped segment produced by bounded, offline-file transcription.
|
|
20
|
+
/// Timestamps are relative to the supplied audio, never to wall-clock time.
|
|
21
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
22
|
+
pub(crate) struct OfflineTranscriptSegment {
|
|
23
|
+
pub start_ms: i64,
|
|
24
|
+
pub end_ms: i64,
|
|
25
|
+
pub text: String,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Transcribe already-decoded 16 kHz mono samples with the process-wide
|
|
29
|
+
/// Whisper context. This is the reusable file-transcription entry point: the
|
|
30
|
+
/// caller owns container decoding and the samples are never persisted here.
|
|
31
|
+
///
|
|
32
|
+
/// Blocking work -- call from a dedicated worker thread, not the async runtime.
|
|
33
|
+
pub(crate) fn transcribe_offline_file_samples(
|
|
34
|
+
app: &AppHandle,
|
|
35
|
+
samples: &[f32],
|
|
36
|
+
language: Option<&str>,
|
|
37
|
+
) -> Result<Vec<OfflineTranscriptSegment>, String> {
|
|
38
|
+
#[cfg(target_os = "macos")]
|
|
39
|
+
{
|
|
40
|
+
macos::transcribe_offline_file_samples(app, samples, language)
|
|
41
|
+
}
|
|
42
|
+
#[cfg(not(target_os = "macos"))]
|
|
43
|
+
{
|
|
44
|
+
let _ = (app, samples, language);
|
|
45
|
+
Err("local Whisper file transcription is supported on macOS only".to_owned())
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
19
49
|
#[tauri::command]
|
|
20
50
|
pub async fn whisper_transcription_start(
|
|
21
51
|
app: AppHandle,
|
|
@@ -112,6 +142,9 @@ mod macos {
|
|
|
112
142
|
use tauri::{AppHandle, Emitter};
|
|
113
143
|
use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters};
|
|
114
144
|
|
|
145
|
+
use crate::capture_audio_bus::{
|
|
146
|
+
try_subscribe, AudioSources, AudioSubscription, SubscriptionAttempt,
|
|
147
|
+
};
|
|
115
148
|
use crate::native_speech::macos::{
|
|
116
149
|
start_raw_mic_capture, MicVoiceProcessingMode, RawMicCapture,
|
|
117
150
|
};
|
|
@@ -121,6 +154,8 @@ mod macos {
|
|
|
121
154
|
};
|
|
122
155
|
use crate::whisper_model::{ensure_model, model_file};
|
|
123
156
|
|
|
157
|
+
const MEETING_AUDIO_OWNER: &str = "meeting-whisper";
|
|
158
|
+
|
|
124
159
|
/// One transcript segment with real timestamps from whisper, already
|
|
125
160
|
/// offset onto the meeting timeline (ms since capture start).
|
|
126
161
|
#[derive(Serialize, Clone)]
|
|
@@ -185,6 +220,31 @@ mod macos {
|
|
|
185
220
|
Ok(())
|
|
186
221
|
}
|
|
187
222
|
|
|
223
|
+
pub(super) fn transcribe_offline_file_samples(
|
|
224
|
+
app: &AppHandle,
|
|
225
|
+
samples: &[f32],
|
|
226
|
+
language: Option<&str>,
|
|
227
|
+
) -> Result<Vec<super::OfflineTranscriptSegment>, String> {
|
|
228
|
+
const CHUNK_SAMPLES: usize = 25 * 16_000;
|
|
229
|
+
|
|
230
|
+
let ctx = context(app)?;
|
|
231
|
+
let mut state = ctx
|
|
232
|
+
.create_state()
|
|
233
|
+
.map_err(|e| format!("whisper state init failed: {e}"))?;
|
|
234
|
+
let mut segments = Vec::new();
|
|
235
|
+
for (chunk_index, chunk) in samples.chunks(CHUNK_SAMPLES).enumerate() {
|
|
236
|
+
let chunk_offset_ms = chunk_index as i64 * 25_000;
|
|
237
|
+
segments.extend(infer(&mut state, chunk, language).into_iter().map(
|
|
238
|
+
|(start_ms, end_ms, text)| super::OfflineTranscriptSegment {
|
|
239
|
+
start_ms: chunk_offset_ms.saturating_add(start_ms),
|
|
240
|
+
end_ms: chunk_offset_ms.saturating_add(end_ms),
|
|
241
|
+
text,
|
|
242
|
+
},
|
|
243
|
+
));
|
|
244
|
+
}
|
|
245
|
+
Ok(segments)
|
|
246
|
+
}
|
|
247
|
+
|
|
188
248
|
// ---- resampling -------------------------------------------------------
|
|
189
249
|
|
|
190
250
|
/// One linearly-interpolated 16 kHz output sample at output index `i`,
|
|
@@ -383,6 +443,12 @@ mod macos {
|
|
|
383
443
|
/// deliberately deferred to the worker so we never allocate/compute on
|
|
384
444
|
/// the realtime audio thread.
|
|
385
445
|
fn push(&self, frames: &[f32]) {
|
|
446
|
+
// A bus publish may already have cloned this callback when the
|
|
447
|
+
// subscription is dropped. Refuse that final in-flight delivery
|
|
448
|
+
// once teardown has signalled the worker to stop.
|
|
449
|
+
if !self.running.load(Ordering::SeqCst) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
386
452
|
if let Ok(mut buf) = self.buf.lock() {
|
|
387
453
|
buf.extend_from_slice(frames);
|
|
388
454
|
}
|
|
@@ -826,18 +892,31 @@ mod macos {
|
|
|
826
892
|
}
|
|
827
893
|
|
|
828
894
|
struct Session {
|
|
895
|
+
app: AppHandle,
|
|
829
896
|
// macOS 15+ meetings use a combined SCK capture, so there is no
|
|
830
897
|
// competing AVAudioEngine / VoiceProcessingIO mic input to stop.
|
|
831
898
|
mic_cap: Option<RawMicCapture>,
|
|
832
899
|
// System capture is optional — skipped when the user turns system
|
|
833
900
|
// audio off, so neither the recording nor the transcript include it.
|
|
834
901
|
sys_cap: Option<RawSckAudioCapture>,
|
|
902
|
+
// When Rewind already owns the requested SCK audio sources, meeting
|
|
903
|
+
// Whisper receives fan-out PCM through this subscription and opens no
|
|
904
|
+
// physical mic/system recorder of its own.
|
|
905
|
+
_shared_audio: Option<AudioSubscription>,
|
|
906
|
+
temporary_audio: Option<crate::screen_memory::TemporaryAudioLease>,
|
|
835
907
|
mic: Arc<WhisperStream>,
|
|
836
908
|
sys: Option<Arc<WhisperStream>>,
|
|
837
909
|
/// Who started this session — see `SessionOwner`.
|
|
838
910
|
owner: SessionOwner,
|
|
839
911
|
}
|
|
840
912
|
|
|
913
|
+
impl Drop for Session {
|
|
914
|
+
fn drop(&mut self) {
|
|
915
|
+
drop(self._shared_audio.take());
|
|
916
|
+
release_temporary_audio(&self.app, self.temporary_audio.take());
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
841
920
|
// SAFETY: the capture handles hold refcounted ObjC objects (already
|
|
842
921
|
// `Send`); the streams are `Arc` over `Send + Sync` interiors. We only move
|
|
843
922
|
// the session through the `Mutex`, never alias across threads.
|
|
@@ -936,10 +1015,80 @@ mod macos {
|
|
|
936
1015
|
as Arc<dyn Fn(&[f32]) + Send + Sync>
|
|
937
1016
|
});
|
|
938
1017
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1018
|
+
// If Rewind is running visuals-only, upgrade that one physical
|
|
1019
|
+
// producer before touching the bus. Off/paused Rewind returns no lease
|
|
1020
|
+
// and preserves the legacy meeting capture path.
|
|
1021
|
+
let temporary_audio = if owner == SessionOwner::Meeting {
|
|
1022
|
+
match crate::screen_memory::acquire_temporary_audio_consumer(
|
|
1023
|
+
&app,
|
|
1024
|
+
MEETING_AUDIO_OWNER,
|
|
1025
|
+
crate::capture_graph::CaptureConsumer::Meeting,
|
|
1026
|
+
true,
|
|
1027
|
+
capture_system,
|
|
1028
|
+
) {
|
|
1029
|
+
Ok(lease) => lease,
|
|
1030
|
+
Err(error) => {
|
|
1031
|
+
mic_stream.stop();
|
|
1032
|
+
if let Some(sys_stream) = &sys_stream {
|
|
1033
|
+
sys_stream.stop();
|
|
1034
|
+
}
|
|
1035
|
+
return Err(error);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
} else {
|
|
1039
|
+
None
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
// Make the shared-vs-physical choice atomically inside the bus. If a
|
|
1043
|
+
// Rewind producer exists but lacks a requested source, `try_subscribe`
|
|
1044
|
+
// returns a typed error and we fail closed: no combined SCK fallback,
|
|
1045
|
+
// RawMicCapture, or raw system capture is opened.
|
|
1046
|
+
let shared_audio = if owner == SessionOwner::Meeting {
|
|
1047
|
+
let mic_for_shared = mic_stream.clone();
|
|
1048
|
+
let shared_mic = Arc::new(move |samples: &[f32], sample_rate: f64| {
|
|
1049
|
+
mic_for_shared.set_src_rate(sample_rate);
|
|
1050
|
+
mic_for_shared.push(samples);
|
|
1051
|
+
});
|
|
1052
|
+
let shared_system = sys_stream.as_ref().map(|stream| {
|
|
1053
|
+
let stream = stream.clone();
|
|
1054
|
+
Arc::new(move |samples: &[f32], sample_rate: f64| {
|
|
1055
|
+
stream.set_src_rate(sample_rate);
|
|
1056
|
+
stream.push(samples);
|
|
1057
|
+
}) as crate::capture_audio_bus::AudioCallback
|
|
1058
|
+
});
|
|
1059
|
+
match try_subscribe(
|
|
1060
|
+
AudioSources::new(true, capture_system),
|
|
1061
|
+
Some(shared_mic),
|
|
1062
|
+
shared_system,
|
|
1063
|
+
) {
|
|
1064
|
+
Ok(SubscriptionAttempt::Subscribed(subscription)) => Some(subscription),
|
|
1065
|
+
Ok(SubscriptionAttempt::NoProducer) => {
|
|
1066
|
+
if temporary_audio.is_some() {
|
|
1067
|
+
release_temporary_audio(&app, temporary_audio);
|
|
1068
|
+
mic_stream.stop();
|
|
1069
|
+
if let Some(sys_stream) = &sys_stream {
|
|
1070
|
+
sys_stream.stop();
|
|
1071
|
+
}
|
|
1072
|
+
return Err("shared-audio-producer-unavailable-after-upgrade".into());
|
|
1073
|
+
}
|
|
1074
|
+
None
|
|
1075
|
+
}
|
|
1076
|
+
Err(error) => {
|
|
1077
|
+
release_temporary_audio(&app, temporary_audio);
|
|
1078
|
+
mic_stream.stop();
|
|
1079
|
+
if let Some(sys_stream) = &sys_stream {
|
|
1080
|
+
sys_stream.stop();
|
|
1081
|
+
}
|
|
1082
|
+
return Err(error.to_string());
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
} else {
|
|
1086
|
+
None
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
let combined_cap = if shared_audio.is_none()
|
|
1090
|
+
&& should_use_combined_sck_capture(owner, supports_sck_microphone_capture())
|
|
1091
|
+
{
|
|
943
1092
|
match start_raw_meeting_capture(
|
|
944
1093
|
app.clone(),
|
|
945
1094
|
mic_device_id.clone(),
|
|
@@ -963,7 +1112,10 @@ mod macos {
|
|
|
963
1112
|
None
|
|
964
1113
|
};
|
|
965
1114
|
|
|
966
|
-
let (mic_cap, sys_cap) = if
|
|
1115
|
+
let (mic_cap, sys_cap) = if shared_audio.is_some() {
|
|
1116
|
+
eprintln!("[whisper] using shared Rewind microphone/system PCM producer");
|
|
1117
|
+
(None, None)
|
|
1118
|
+
} else if let Some(combined_cap) = combined_cap {
|
|
967
1119
|
// Both SCK outputs are configured at 48 kHz.
|
|
968
1120
|
mic_stream.set_src_rate(48000.0);
|
|
969
1121
|
(None, Some(combined_cap))
|
|
@@ -1004,10 +1156,30 @@ mod macos {
|
|
|
1004
1156
|
(Some(mic_cap), sys_cap)
|
|
1005
1157
|
};
|
|
1006
1158
|
|
|
1007
|
-
let mut slot = session_slot().lock()
|
|
1159
|
+
let mut slot = match session_slot().lock() {
|
|
1160
|
+
Ok(slot) => slot,
|
|
1161
|
+
Err(error) => {
|
|
1162
|
+
drop(shared_audio);
|
|
1163
|
+
release_temporary_audio(&app, temporary_audio);
|
|
1164
|
+
mic_stream.stop();
|
|
1165
|
+
if let Some(sys_stream) = &sys_stream {
|
|
1166
|
+
sys_stream.stop();
|
|
1167
|
+
}
|
|
1168
|
+
if let Some(mic_cap) = mic_cap {
|
|
1169
|
+
mic_cap.stop();
|
|
1170
|
+
}
|
|
1171
|
+
if let Some(sys_cap) = sys_cap {
|
|
1172
|
+
sys_cap.stop();
|
|
1173
|
+
}
|
|
1174
|
+
return Err(error.to_string());
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1008
1177
|
*slot = Some(Session {
|
|
1178
|
+
app: app.clone(),
|
|
1009
1179
|
mic_cap,
|
|
1010
1180
|
sys_cap,
|
|
1181
|
+
_shared_audio: shared_audio,
|
|
1182
|
+
temporary_audio,
|
|
1011
1183
|
mic: mic_stream,
|
|
1012
1184
|
sys: sys_stream,
|
|
1013
1185
|
owner,
|
|
@@ -1039,12 +1211,23 @@ mod macos {
|
|
|
1039
1211
|
eprintln!("[whisper] transcription timeline reset");
|
|
1040
1212
|
}
|
|
1041
1213
|
|
|
1042
|
-
|
|
1214
|
+
fn release_temporary_audio(
|
|
1215
|
+
app: &AppHandle,
|
|
1216
|
+
lease: Option<crate::screen_memory::TemporaryAudioLease>,
|
|
1217
|
+
) {
|
|
1218
|
+
if let Some(lease) = lease {
|
|
1219
|
+
if let Err(error) = crate::screen_memory::release_temporary_audio_consumer(app, lease) {
|
|
1220
|
+
eprintln!("[whisper] Rewind audio lease release failed: {error}");
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
pub fn stop(app: &AppHandle) {
|
|
1043
1226
|
let session = match session_slot().lock() {
|
|
1044
1227
|
Ok(mut slot) => slot.take(),
|
|
1045
|
-
Err(
|
|
1228
|
+
Err(poisoned) => poisoned.into_inner().take(),
|
|
1046
1229
|
};
|
|
1047
|
-
let Some(session) = session else {
|
|
1230
|
+
let Some(mut session) = session else {
|
|
1048
1231
|
return;
|
|
1049
1232
|
};
|
|
1050
1233
|
// Signal workers to stop. They flush a final transcript after the loop.
|
|
@@ -1053,12 +1236,16 @@ mod macos {
|
|
|
1053
1236
|
sys.stop();
|
|
1054
1237
|
}
|
|
1055
1238
|
// Stop captures so no more samples arrive while workers flush.
|
|
1056
|
-
if let Some(mic_cap) = session.mic_cap {
|
|
1239
|
+
if let Some(mic_cap) = session.mic_cap.take() {
|
|
1057
1240
|
mic_cap.stop();
|
|
1058
1241
|
}
|
|
1059
|
-
if let Some(sys_cap) = session.sys_cap {
|
|
1242
|
+
if let Some(sys_cap) = session.sys_cap.take() {
|
|
1060
1243
|
sys_cap.stop();
|
|
1061
1244
|
}
|
|
1245
|
+
// Unsubscribe before a last-consumer release rotates the Rewind
|
|
1246
|
+
// producer back to its persisted visuals-only mode.
|
|
1247
|
+
drop(session._shared_audio.take());
|
|
1248
|
+
release_temporary_audio(app, session.temporary_audio.take());
|
|
1062
1249
|
// Wait up to 4 s for both workers to finish their final flush so
|
|
1063
1250
|
// trailing speech is not lost when the frontend unregisters listeners.
|
|
1064
1251
|
let deadline = Instant::now() + Duration::from_secs(4);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://schema.tauri.app/config/2",
|
|
3
|
+
"productName": "Clips Alpha",
|
|
4
|
+
"identifier": "com.clips.tray.alpha",
|
|
5
|
+
"bundle": {
|
|
6
|
+
"createUpdaterArtifacts": false,
|
|
7
|
+
"targets": ["app"],
|
|
8
|
+
"macOS": {
|
|
9
|
+
"minimumSystemVersion": "26.0"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"plugins": {
|
|
13
|
+
"updater": {
|
|
14
|
+
"active": false
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -33,7 +33,7 @@ export interface HttpMcpEntry {
|
|
|
33
33
|
/** Build the HTTP MCP server entry for a deployed agent-native app. */
|
|
34
34
|
export declare function buildHttpMcpEntry(mcpUrl: string, token?: string, headers?: Record<string, string>): HttpMcpEntry;
|
|
35
35
|
export declare function buildHttpMcpEntryForClient(client: ClientId, mcpUrl: string, token?: string, headers?: Record<string, string>): Record<string, unknown>;
|
|
36
|
-
export declare function buildLocalMcpEntryForClient(client: ClientId, args: string[], env?: Record<string, string
|
|
36
|
+
export declare function buildLocalMcpEntryForClient(client: ClientId, args: string[], env?: Record<string, string>, command?: string): Record<string, unknown>;
|
|
37
37
|
/**
|
|
38
38
|
* Cowork consumes MCP exactly like Claude Code (same JSON server-entry
|
|
39
39
|
* shape). Resolved lazily so `os.homedir()` reflects the current `$HOME`.
|
|
@@ -78,7 +78,7 @@ export declare function hasJsonMcpEntry(file: string, name: string): boolean;
|
|
|
78
78
|
export declare function hasJsonMcpEntryForClient(client: ClientId, file: string, name: string): boolean;
|
|
79
79
|
/** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */
|
|
80
80
|
export declare function buildCodexHttpBlock(name: string, mcpUrl: string, token?: string, headers?: Record<string, string>): string;
|
|
81
|
-
export declare function buildCodexLocalBlock(name: string, args: string[], env?: Record<string, string
|
|
81
|
+
export declare function buildCodexLocalBlock(name: string, args: string[], env?: Record<string, string>, command?: string): string;
|
|
82
82
|
/**
|
|
83
83
|
* Replace (or append) the entire `[mcp_servers.<name>]` footprint in a TOML
|
|
84
84
|
* file without disturbing other content. The footprint is the server's own
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AASH,MAAM,MAAM,QAAQ,GAChB,aAAa,GACb,iBAAiB,GACjB,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,gBAAgB,CAAC;AAErB,eAAO,MAAM,OAAO,EAAE,QAAQ,EAQ7B,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,YAAY,CAUd;AAYD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,QAAQ,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BzB;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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"}
|
|
@@ -81,12 +81,12 @@ export function buildHttpMcpEntryForClient(client, mcpUrl, token, headers) {
|
|
|
81
81
|
}
|
|
82
82
|
return buildHttpMcpEntry(mcpUrl, token, headers);
|
|
83
83
|
}
|
|
84
|
-
export function buildLocalMcpEntryForClient(client, args, env) {
|
|
84
|
+
export function buildLocalMcpEntryForClient(client, args, env, command = "agent-native") {
|
|
85
85
|
const cleanEnv = env ? Object.fromEntries(Object.entries(env)) : {};
|
|
86
86
|
if (client === "opencode") {
|
|
87
87
|
return {
|
|
88
88
|
type: "local",
|
|
89
|
-
command: [
|
|
89
|
+
command: [command, ...args],
|
|
90
90
|
enabled: true,
|
|
91
91
|
...(Object.keys(cleanEnv).length ? { environment: cleanEnv } : {}),
|
|
92
92
|
};
|
|
@@ -94,13 +94,13 @@ export function buildLocalMcpEntryForClient(client, args, env) {
|
|
|
94
94
|
if (client === "github-copilot") {
|
|
95
95
|
return {
|
|
96
96
|
type: "stdio",
|
|
97
|
-
command
|
|
97
|
+
command,
|
|
98
98
|
args,
|
|
99
99
|
...(Object.keys(cleanEnv).length ? { env: cleanEnv } : {}),
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
return {
|
|
103
|
-
command
|
|
103
|
+
command,
|
|
104
104
|
args,
|
|
105
105
|
...(Object.keys(cleanEnv).length ? { env: cleanEnv } : {}),
|
|
106
106
|
};
|
|
@@ -454,9 +454,9 @@ export function buildCodexHttpBlock(name, mcpUrl, token, headers) {
|
|
|
454
454
|
}
|
|
455
455
|
return lines.join("\n") + "\n";
|
|
456
456
|
}
|
|
457
|
-
export function buildCodexLocalBlock(name, args, env) {
|
|
457
|
+
export function buildCodexLocalBlock(name, args, env, command = "agent-native") {
|
|
458
458
|
const lines = [codexMcpHeader(name)];
|
|
459
|
-
lines.push(`command =
|
|
459
|
+
lines.push(`command = ${tomlQuote(command)}`);
|
|
460
460
|
lines.push(`args = [${args.map(tomlQuote).join(", ")}]`);
|
|
461
461
|
const cleanEnv = env ? Object.fromEntries(Object.entries(env)) : {};
|
|
462
462
|
if (Object.keys(cleanEnv).length) {
|