apps/raycast extension with commands for start/stop/pause/resume/toggle and mic/camera switchingcap-desktop://action?value=... payload format for compatibilitypnpm --dir apps/raycast run typecheckcargo test -p cap-desktop deeplink_actions -- --nocapture (blocked in this environment: cargo not installed)/claim #1540
This PR adds pause/resume/toggle deeplink actions to the Cap desktop app and introduces a new Raycast extension (apps/raycast) that exposes seven commands (start/stop/pause/resume/toggle recording, switch mic, switch camera) by serializing DeepLinkAction payloads and dispatching them via macOS’s open URL scheme.
Key changes:
deeplink_actions.rs: Adds PauseRecording, ResumeRecording, TogglePauseRecording, SetMicrophone, and SetCamera enum variants with correct delegation to existing recording.rs functions.apps/raycast/: New workspace package with a utils.ts dispatcher (execFile("open", [...])) and one source file per command.pnpm-lock.yaml: Adds @raycast/api and related dev dependencies for the new workspace; also reflects minor transitive dependency bumps.Issues found:
start-recording.tsx: The form fires two sequential open deeplinks — start_recording (with camera: null) then set_camera. Because open returns before Cap processes the URL, these can be handled by Cap out of order. If set_camera is processed first, the subsequent StartRecording handler’s call to set_camera_input(..., None, None) silently overwrites the camera selection back to null.isRequired on targetName: An empty target name passes form validation but causes a silent Rust-side error when the lookup fails.start_recording + set_camera dispatch pattern can silently overwrite the user’s camera selection back to null if processing order is inverted, and (2) missing isRequired validation on the targetName field allowing empty form submission with silent Rust-side failures. The race condition specifically poses a data-loss risk in the most complex command.sequenceDiagram
participant User
participant Raycast
participant macOS as macOS open
participant Cap as Cap Desktop (Tauri)
participant Recording as recording.rs
User->>Raycast: Invoke command (e.g. Pause Recording)
Raycast->>macOS: open cap-desktop://action?value={"pause_recording":null}
macOS-->>Raycast: returns immediately
Raycast->>Raycast: showToast("Sent to Cap")
macOS->>Cap: deliver deeplink URL
Cap->>Cap: DeepLinkAction::try_from(url) → PauseRecording
Cap->>Recording: pause_recording(app, state)
Note over Raycast,Cap: start-recording race condition
User->>Raycast: Submit start form (with cameraLabel)
Raycast->>macOS: open cap-desktop://action?value={"start_recording":{...,"camera":null}}
macOS-->>Raycast: returns immediately
Raycast->>macOS: open cap-desktop://action?value={"set_camera":{"camera_label":"..."}}
macOS-->>Raycast: returns immediately
macOS->>Cap: deliver start_recording (camera=null)
macOS->>Cap: deliver set_camera (may arrive before OR after start_recording)
Cap->>Recording: set_camera_input(..., None) ← may overwrite set_camera result
Last reviewed commit: 525d651
Greptile also left 2 inline comments on this PR.
(2/5) Greptile learns from your feedback when you react with thumbs up/down!
Luna Ops
@lustsazeus-lab
Cap
@CapSoftware
Abhishek Verma
@w3Abhishek