feat: Add Raycast extension for controlling Cap recordings#1554
feat: Add Raycast extension for controlling Cap recordings#15541234-ad wants to merge 13 commits intoCapSoftware:mainfrom
Conversation
| "name": "cap", | ||
| "title": "Cap", | ||
| "description": "Control Cap screen recording from Raycast", | ||
| "icon": "cap-icon.png", |
There was a problem hiding this comment.
Icon file cap-icon.png is referenced here but isn’t included in this PR; Raycast will fail to load the extension icon unless it exists. Consider adding it or switching to a built-in icon.
| mic_label: string; | ||
| } | ||
|
|
||
| export type DeepLinkAction = |
There was a problem hiding this comment.
Unit enum variants in the Rust DeepLinkAction deserialize from a JSON string (e.g. "stop_recording"), not an object like { stop_recording: {} }. JSON.stringify() will do the right thing if you pass a string here.
| export type DeepLinkAction = | |
| export type DeepLinkAction = | |
| | { start_recording: StartRecordingOptions } | |
| | "stop_recording" | |
| | "pause_recording" | |
| | "resume_recording" | |
| | "toggle_pause_recording" | |
| | { switch_camera: SwitchCameraOptions } | |
| | { switch_microphone: SwitchMicrophoneOptions }; |
| title: "Stopping recording...", | ||
| }); | ||
|
|
||
| await executeCapAction({ stop_recording: {} }); |
There was a problem hiding this comment.
With the enum serialization, this should be a JSON string action.
| await executeCapAction({ stop_recording: {} }); | |
| await executeCapAction("stop_recording"); |
| title: "Pausing recording...", | ||
| }); | ||
|
|
||
| await executeCapAction({ pause_recording: {} }); |
There was a problem hiding this comment.
With the enum serialization, this should be a JSON string action.
| await executeCapAction({ pause_recording: {} }); | |
| await executeCapAction("pause_recording"); |
| title: "Resuming recording...", | ||
| }); | ||
|
|
||
| await executeCapAction({ resume_recording: {} }); |
There was a problem hiding this comment.
With the enum serialization, this should be a JSON string action.
| await executeCapAction({ resume_recording: {} }); | |
| await executeCapAction("resume_recording"); |
| title: "Toggling pause...", | ||
| }); | ||
|
|
||
| await executeCapAction({ toggle_pause_recording: {} }); |
There was a problem hiding this comment.
With the enum serialization, this should be a JSON string action.
| await executeCapAction({ toggle_pause_recording: {} }); | |
| await executeCapAction("toggle_pause_recording"); |
| title: "Starting recording...", | ||
| }); | ||
|
|
||
| // For simplicity, using default screen/window |
There was a problem hiding this comment.
Minor: this repo avoids code comments; you can drop these without losing clarity.
| // For simplicity, using default screen/window | |
| const capture_mode = |
| // In a real implementation, you'd want to list available screens/windows | ||
| const capture_mode = | ||
| captureType === "screen" | ||
| ? { screen: "Default Screen" } |
There was a problem hiding this comment.
capture_mode uses a display/window name and the backend matches it exactly. Default Screen / Default Window won’t exist, so this command will consistently fail unless you wire it up to real screen/window names (or adjust the deep link/backend to accept a default/ID).
|
|
||
| await executeCapAction({ | ||
| switch_camera: { | ||
| camera: cameraId, |
There was a problem hiding this comment.
The backend expects DeviceOrModelID for camera (serde enum like { "DeviceID": "..." } or { "ModelID": "vid:pid" }), so a raw string here won’t deserialize. Probably want to update the payload/type accordingly (even if you still keep placeholder IDs for now).
Description
This PR adds a Raycast extension that allows users to control Cap screen recordings directly from Raycast using the existing deep link protocol.
Changes
Backend Updates (
apps/desktop/src-tauri/src/deeplink_actions.rs)DeepLinkActionenum to include recording control actions:StopRecording- Stop the current recordingPauseRecording- Pause the current recordingResumeRecording- Resume a paused recordingTogglePauseRecording- Toggle between pause/resume statesSwitchCamera- Switch to a different cameraSwitchMicrophone- Switch to a different microphonecap://actiondeep link protocolRaycast Extension (
extensions/raycast/)Created a complete Raycast extension with the following commands:
Start Recording (
start-recording.tsx)Stop Recording (
stop-recording.tsx)Pause Recording (
pause-recording.tsx)Resume Recording (
resume-recording.tsx)Toggle Pause (
toggle-pause.tsx)Switch Camera (
switch-camera.tsx)Switch Microphone (
switch-microphone.tsx)Supporting Files
utils.ts- TypeScript types and deep link execution helperpackage.json- Extension metadata and dependenciestsconfig.json- TypeScript configurationREADME.md- Documentation for installation and usageTechnical Details
cap://actiondeep link protocolTesting
The extension can be tested by:
cd extensions/raycast && npm installnpm run devBenefits
Future Enhancements
Related Issues
Closes #[issue-number] (if applicable)
Note: This extension requires Cap desktop application to be installed and running. It's designed for macOS users who use Raycast as their launcher.
Greptile Overview
Greptile Summary
Adds a Raycast extension for controlling Cap recordings via the existing
cap://actiondeep link protocol, enabling keyboard-driven recording control without opening the Cap UI.Major changes:
DeepLinkActionenum in Rust backend with 6 new recording control actions (pause, resume, toggle pause, camera/mic switching)pause_recording,resume_recording,set_camera_input,set_mic_input)Issues found:
cap-icon.pngfile will cause extension installation to failConfidence Score: 2/5
extensions/raycast/package.json(missing icon),extensions/raycast/src/start-recording.tsx,extensions/raycast/src/switch-camera.tsx, andextensions/raycast/src/switch-microphone.tsx(hardcoded placeholders)Important Files Changed
cap-icon.pngSequence Diagram
sequenceDiagram participant User participant Raycast participant Extension participant DeepLink participant CapApp participant Recording User->>Raycast: Trigger command Raycast->>Extension: Execute command Extension->>Extension: Build action JSON Extension->>DeepLink: Open cap://action?value={encoded_json} DeepLink->>CapApp: Parse deep link URL CapApp->>CapApp: Deserialize action enum alt Start Recording CapApp->>CapApp: Set camera/mic inputs CapApp->>CapApp: Resolve screen/window name CapApp->>Recording: start_recording() else Stop/Pause/Resume CapApp->>Recording: stop/pause/resume_recording() else Switch Camera/Mic CapApp->>CapApp: set_camera_input/set_mic_input() end CapApp-->>User: Action executed(2/5) Greptile learns from your feedback when you react with thumbs up/down!