feat(desktop): add deeplink control actions#1804
Conversation
| async fn refresh_raycast_device_cache(app: &AppHandle) -> Result<(), String> { | ||
| let displays = cap_recording::screen_capture::list_displays() | ||
| .into_iter() | ||
| .map(|(display, _)| display.name) | ||
| .collect(); | ||
| let windows = cap_recording::screen_capture::list_windows() | ||
| .into_iter() | ||
| .map(|(window, _)| window.name) | ||
| .collect(); | ||
| let microphones = MicrophoneFeed::list().keys().cloned().collect(); | ||
| let cameras = cap_camera::list_cameras() | ||
| .map(|camera| RaycastCamera { | ||
| name: camera.display_name().to_string(), | ||
| camera: DeviceOrModelID::from_info(&camera), | ||
| }) | ||
| .collect(); | ||
| let cache = RaycastDeviceCache { |
There was a problem hiding this comment.
Blocking OS APIs on async task thread
list_displays(), list_windows(), MicrophoneFeed::list(), and cap_camera::list_cameras() are all synchronous, potentially slow OS API calls executed directly on a Tokio async task thread. Camera and audio enumeration in particular can stall the entire Tauri runtime while they run. Since this action is designed to be called frequently from Raycast, the risk of stalls is higher than it is for StartRecording. Consider wrapping the enumeration block in tokio::task::spawn_blocking(|| { ... }).await to keep the runtime free.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 224-240
Comment:
**Blocking OS APIs on async task thread**
`list_displays()`, `list_windows()`, `MicrophoneFeed::list()`, and `cap_camera::list_cameras()` are all synchronous, potentially slow OS API calls executed directly on a Tokio async task thread. Camera and audio enumeration in particular can stall the entire Tauri runtime while they run. Since this action is designed to be called frequently from Raycast, the risk of stalls is higher than it is for `StartRecording`. Consider wrapping the enumeration block in `tokio::task::spawn_blocking(|| { ... }).await` to keep the runtime free.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Addressed in 7f1c1bc: the synchronous display/window/microphone/camera enumeration now runs inside tokio::task::spawn_blocking, then the device cache write happens asynchronously after the blocking result returns.
| DeepLinkAction::TakeScreenshot { capture_mode } => { | ||
| let capture_target = capture_target_from_mode(capture_mode)?; | ||
| crate::recording::take_screenshot(app.clone(), capture_target) | ||
| .await | ||
| .map(|_| ()) | ||
| } |
There was a problem hiding this comment.
TakeScreenshot silently drops the output path
take_screenshot returns Result<PathBuf, String> and this arm discards the PathBuf with .map(|_| ()). That's fine for the deeplink contract, but there's no signal back to the Raycast caller whether the capture succeeded or where the file landed. Worth confirming whether Raycast needs the resulting path or whether fire-and-forget is intentional here. Is fire-and-forget acceptable for TakeScreenshot from Raycast, or does the extension need the output path?
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 186-191
Comment:
**`TakeScreenshot` silently drops the output path**
`take_screenshot` returns `Result<PathBuf, String>` and this arm discards the `PathBuf` with `.map(|_| ())`. That's fine for the deeplink contract, but there's no signal back to the Raycast caller whether the capture succeeded or where the file landed. Worth confirming whether Raycast needs the resulting path or whether fire-and-forget is intentional here. Is fire-and-forget acceptable for TakeScreenshot from Raycast, or does the extension need the output path?
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Addressed in 7f1c1bc: TakeScreenshot now records the returned screenshot path to raycast-last-screenshot.json in the desktop app data directory, using the same JSON writer pattern as the Raycast device cache.
|
Addressed the Greptile P2 feedback in 7f1c1bc:
Verification after the update:
I retried |
/claim #1540
This is a focused desktop-side quality pass for the Cap deeplink/Raycast surface.
What changed:
cap-desktop://action?...routing so action deeplinks reach the JSON payload parser instead of being rejected as invalidcap-desktop://signinWhy this is useful:
Validation:
cargo fmt --all -- --checkpassesgit diff --checkpassescargo test -p cap-desktop deeplink_actions --lib --no-run, but this Windows environment resolveslink.exetouutils.coreutilsinstead of the MSVC linker, so Rust dependency build scripts fail before compiling project codeDemo note:
Greptile Summary
This PR fixes a long-standing routing bug where
cap-desktop://action?...deeplinks were silently rejected becauseurl.domain()returnsNonefor custom URL schemes — onlyurl.host_str()correctly returns\"action\". It also adds eight new recording-control actions (pause, resume, toggle-pause, restart, screenshot, microphone selection, camera selection, and Raycast device-cache refresh) that delegate directly into existing Cap desktop commands.TryFrom<&Url>now useshost_str()instead ofdomain(), making theactionhost correctly routable for all non-special URL schemes.recording.rscommands verbatim;SetMicrophone/SetCameracorrectly passOptionto support deselection;TakeScreenshotextracts the sharedcapture_target_from_modehelper fromStartRecording.refresh_raycast_device_cacheenumerates displays, windows, microphones, and cameras and writes a JSON file asynchronously to the app data directory for Raycast to read.Confidence Score: 4/5
The routing fix is correct and well-tested; the new actions delegate cleanly into existing, proven commands with no data-loss or correctness risk.
The url.domain() → url.host_str() fix is verified by the new parser tests. New actions reuse existing code paths without introducing new state. The device-cache refresh runs several synchronous OS APIs directly on a Tokio task thread; on a machine with slow camera or audio subsystems this could momentarily stall the runtime, but it is not a data-loss or correctness issue.
The refresh_raycast_device_cache function in deeplink_actions.rs deserves a second look for the blocking enumeration calls.
Important Files Changed
Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "Add desktop deeplink control actions" | Re-trigger Greptile