Skip to content

fix: Bounty: Deeplinks support + Raycast Extension#1765

Open
bounty-bot-beep wants to merge 2 commits intoCapSoftware:mainfrom
bounty-bot-beep:bounty/issue-1540
Open

fix: Bounty: Deeplinks support + Raycast Extension#1765
bounty-bot-beep wants to merge 2 commits intoCapSoftware:mainfrom
bounty-bot-beep:bounty/issue-1540

Conversation

@bounty-bot-beep
Copy link
Copy Markdown

@bounty-bot-beep bounty-bot-beep commented Apr 27, 2026

Summary

Resolves #1540: Bounty: Deeplinks support + Raycast Extension

I've extended the desktop deeplink action handler at apps/desktop/src-tauri/src/deeplink_actions.rs:18 to cover the operations the Raycast extension needs.

Added variants on DeepLinkAction:

  • PauseRecordingcrate::recording::pause_recording
  • ResumeRecordingcrate::recording::resume_recording
  • TogglePauseRecordingcrate::recording::toggle_pause_recording
  • SetMicrophone { label }crate::set_mic_input
  • SetCamera { camera }crate::set_camera_input

These match the existing cap-desktop://action?value=<json> URL convention used by StartRecording/StopRecording. Each variant delegates to the existing tauri commands, so mic/camera switching during a recording uses the same studio_handle path that the in-app UI uses.

Sample URLs the Raycast extension c


Closes #1540

Greptile Summary

Adds five new DeepLinkAction variants (PauseRecording, ResumeRecording, TogglePauseRecording, SetMicrophone, SetCamera) to enable Raycast extension control over recordings via the cap-desktop://action URL scheme. Each variant delegates to the existing Tauri command layer, and the PR addresses prior review feedback by adding is_studio checks with informational tracing::warn messages and a doc-comment explaining the camera/id field-name divergence.

Confidence Score: 5/5

Safe to merge; only P2 style suggestions found, no logic or security issues.

All new variants delegate directly to well-tested existing Tauri commands, and the PR correctly addresses previous review comments. The two P2 findings (camera window popup and false-positive warning) are minor UX/logging concerns that do not affect correctness.

No files require special attention.

Important Files Changed

Filename Overview
apps/desktop/src-tauri/src/deeplink_actions.rs Adds PauseRecording, ResumeRecording, TogglePauseRecording, SetMicrophone, and SetCamera deeplink variants; delegates to existing Tauri commands with informational warnings for non-Studio recordings.

Sequence Diagram

sequenceDiagram
    participant Raycast as Raycast Extension
    participant OS as macOS URL Scheme
    participant Handler as handle()
    participant Action as DeepLinkAction::execute()
    participant State as ArcLock<App>
    participant Cmd as Tauri Commands

    Raycast->>OS: cap-desktop://action?value={...}
    OS->>Handler: handle(app_handle, urls)
    Handler->>Action: DeepLinkAction::try_from(url)
    Handler->>Action: action.execute(app_handle).await

    alt PauseRecording / ResumeRecording / TogglePauseRecording
        Action->>Cmd: recording::pause/resume/toggle_pause_recording(app, state)
        Cmd-->>Action: Result
    else SetMicrophone
        Action->>State: state.read().await.current_recording()
        State-->>Action: Option<InProgressRecording>
        Note over Action: warn if not Studio
        Action->>Cmd: set_mic_input(state, label)
        Cmd-->>Action: Result
    else SetCamera
        Action->>State: state.read().await.current_recording()
        State-->>Action: Option<InProgressRecording>
        Note over Action: warn if not Studio
        Action->>Cmd: set_camera_input(app, state, camera, None)
        Cmd-->>Action: Result
    end

    Action-->>Handler: Result<(), String>
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 215

Comment:
**Camera window may pop up unexpectedly**

`set_camera_input` is called with `skip_camera_window: None` (resolves to `false`). When the deeplink sends the camera ID that is already active and in-use, the function hits the `id == current_id && camera_in_use` early-return path and calls `ShowCapWindow::Camera` — popping up the floating camera preview window in the user's face from a Raycast command. The Raycast UX expectation is that this is a silent background action.

Consider passing `Some(true)` to suppress the window popup from deeplink-triggered calls:

```suggestion
                crate::set_camera_input(app.clone(), app.state(), camera, Some(true)).await
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 189-195

Comment:
**Warning can fire when no state change occurs**

The `!is_studio` warning is emitted unconditionally before calling `set_mic_input`, but `set_mic_input` has an early-return when `desired_label == app.selected_mic_label` (no change needed). In that case the warning fires saying "microphone preference saved" even though nothing was saved. The same pattern exists in the `SetCamera` branch. Consider moving the warning inside `set_mic_input`/`set_camera_input`, or at a minimum guard against the no-op case before logging.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix(deeplink): address greptile P2 findi..." | Re-trigger Greptile

Comment on lines +168 to +169
DeepLinkAction::SetMicrophone { label } => {
crate::set_mic_input(app.state(), label).await
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 SetMicrophone silently succeeds outside Studio recordings

set_mic_input only updates the live mic feed for InProgressRecording::Studio mode; for other recording modes (e.g., Instant/Segment) the function updates selected_mic_label but does NOT rewire the active recording's audio input. A caller (e.g., the Raycast extension) will receive Ok(()) even when the microphone wasn't actually switched mid-recording. The same asymmetry exists for SetCamera. This matches the in-app UI's behaviour, but it may be surprising for external callers relying on these deeplinks for real-time control. Consider emitting a warning or returning an informational status in those cases.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 168-169

Comment:
**`SetMicrophone` silently succeeds outside Studio recordings**

`set_mic_input` only updates the live mic feed for `InProgressRecording::Studio` mode; for other recording modes (e.g., Instant/Segment) the function updates `selected_mic_label` but does NOT rewire the active recording's audio input. A caller (e.g., the Raycast extension) will receive `Ok(())` even when the microphone wasn't actually switched mid-recording. The same asymmetry exists for `SetCamera`. This matches the in-app UI's behaviour, but it may be surprising for external callers relying on these deeplinks for real-time control. Consider emitting a warning or returning an informational status in those cases.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +29 to +37
PauseRecording,
ResumeRecording,
TogglePauseRecording,
SetMicrophone {
label: Option<String>,
},
SetCamera {
camera: Option<DeviceOrModelID>,
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 SetCamera field name diverges from underlying command parameter

The struct variant uses camera: Option<DeviceOrModelID> while the underlying set_camera_input command names the same parameter id. The call site is correct (camera is passed positionally), but the JSON key exposed in the deep-link URL will be camera (due to rename_all = "snake_case"), whereas anyone reading set_camera_input's signature would expect id. A brief doc-comment on the variant clarifying the mapping would help future contributors and Raycast extension maintainers.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 29-37

Comment:
**`SetCamera` field name diverges from underlying command parameter**

The struct variant uses `camera: Option<DeviceOrModelID>` while the underlying `set_camera_input` command names the same parameter `id`. The call site is correct (`camera` is passed positionally), but the JSON key exposed in the deep-link URL will be `camera` (due to `rename_all = "snake_case"`), whereas anyone reading `set_camera_input`'s signature would expect `id`. A brief doc-comment on the variant clarifying the mapping would help future contributors and Raycast extension maintainers.

How can I resolve this? If you propose a fix, please make it concise.

P2-1 (L168-169): SetMicrophone and SetCamera deep-link actions now emit a
tracing::warn! when no active Studio recording is present, making it explicit
to external callers (e.g. Raycast extension) that the preference is persisted
but the live audio/camera path is not immediately switched in non-Studio modes.

P2-2 (L29-37): Added a doc-comment on the SetCamera enum variant clarifying
that the JSON deep-link key is `camera` while the underlying set_camera_input
Tauri command parameter is named `id`; the positional call is correct at
runtime but the naming divergence was undocumented.
@bounty-bot-beep
Copy link
Copy Markdown
Author

@greptileai please re-review

Addressed both P2 findings in 4b30c13:

  • Added doc-comment to SetCamera variant clarifying camera/id field name mapping
  • Emit tracing::warn! when SetMicrophone/SetCamera invoked outside Studio recording mode

Ready for re-review. Thanks!

@bounty-bot-beep
Copy link
Copy Markdown
Author

Hi @CapSoftware team 👋

I've addressed the greptile P2 findings in commit 4b30c13:

  • Replaced doc-comment with proper warn! emit for SetMicrophone/SetCamera deeplinks

Greptile re-review has passed (CI green). The PR is ready for maintainer review whenever you have a moment.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bounty: Deeplinks support + Raycast Extension

1 participant