From 42feb4b9a3fe2bd465df90345714bb098e901371 Mon Sep 17 00:00:00 2001 From: mackaman29-6008 Date: Mon, 2 Feb 2026 08:46:33 +0000 Subject: [PATCH 1/4] feat(deeplink): add pause/resume/toggle/camera/mic actions for Raycast integration Adds new deeplink actions to support Raycast extension (#1540): - PauseRecording: Pause current recording - ResumeRecording: Resume paused recording - TogglePauseRecording: Toggle pause state - SetCamera: Switch camera input - SetMicrophone: Switch microphone input These actions enable full Raycast integration for controlling Cap without bringing up the main window. --- .../desktop/src-tauri/src/deeplink_actions.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/apps/desktop/src-tauri/src/deeplink_actions.rs b/apps/desktop/src-tauri/src/deeplink_actions.rs index fce75b4a84..35c73e91f1 100644 --- a/apps/desktop/src-tauri/src/deeplink_actions.rs +++ b/apps/desktop/src-tauri/src/deeplink_actions.rs @@ -32,6 +32,16 @@ pub enum DeepLinkAction { OpenSettings { page: Option, }, + // New actions for Raycast integration (#1540) + PauseRecording, + ResumeRecording, + TogglePauseRecording, + SetCamera { + device_id: Option, + }, + SetMicrophone { + label: Option, + }, } pub fn handle(app_handle: &AppHandle, urls: Vec) { @@ -152,6 +162,23 @@ impl DeepLinkAction { DeepLinkAction::OpenSettings { page } => { crate::show_window(app.clone(), ShowCapWindow::Settings { page }).await } + DeepLinkAction::PauseRecording => { + crate::recording::pause_recording(app.clone(), app.state()).await + } + DeepLinkAction::ResumeRecording => { + crate::recording::resume_recording(app.clone(), app.state()).await + } + DeepLinkAction::TogglePauseRecording => { + crate::recording::toggle_pause_recording(app.clone(), app.state()).await + } + DeepLinkAction::SetCamera { device_id } => { + let state = app.state::>(); + crate::set_camera_input(app.clone(), state.clone(), device_id, None).await + } + DeepLinkAction::SetMicrophone { label } => { + let state = app.state::>(); + crate::set_mic_input(state.clone(), label).await + } } } } From 45153969cbf8c2c2e157634aa48c083caa2af29f Mon Sep 17 00:00:00 2001 From: mackaman29-6008 Date: Mon, 2 Feb 2026 08:46:51 +0000 Subject: [PATCH 2/4] feat(raycast): add Raycast extension for Cap control Implements Raycast extension for issue #1540: - Start/Stop/Pause/Resume recording commands - Toggle pause functionality - Uses cap-desktop:// deeplink protocol - No-view commands for quick actions Installation: Can be submitted to Raycast Store after testing. --- extensions/raycast/README.md | 59 ++++++++++++++++++++ extensions/raycast/package.json | 61 +++++++++++++++++++++ extensions/raycast/src/pause-recording.tsx | 13 +++++ extensions/raycast/src/resume-recording.tsx | 13 +++++ extensions/raycast/src/start-recording.tsx | 33 +++++++++++ extensions/raycast/src/stop-recording.tsx | 13 +++++ extensions/raycast/src/toggle-pause.tsx | 13 +++++ 7 files changed, 205 insertions(+) create mode 100644 extensions/raycast/README.md create mode 100644 extensions/raycast/package.json create mode 100644 extensions/raycast/src/pause-recording.tsx create mode 100644 extensions/raycast/src/resume-recording.tsx create mode 100644 extensions/raycast/src/start-recording.tsx create mode 100644 extensions/raycast/src/stop-recording.tsx create mode 100644 extensions/raycast/src/toggle-pause.tsx diff --git a/extensions/raycast/README.md b/extensions/raycast/README.md new file mode 100644 index 0000000000..7be07e3315 --- /dev/null +++ b/extensions/raycast/README.md @@ -0,0 +1,59 @@ +# Cap Raycast Extension + +Control Cap screen recorder directly from Raycast. + +## Features + +- **Start Recording** - Begin a new screen recording +- **Stop Recording** - End the current recording +- **Pause Recording** - Pause the current recording +- **Resume Recording** - Resume a paused recording +- **Toggle Pause** - Toggle between paused/recording states + +## Installation + +1. Install the Cap desktop app from [cap.so](https://cap.so) +2. Open Raycast +3. Search for "Cap" in the Raycast Store +4. Install the extension + +## Development + +```bash +cd extensions/raycast +npm install +npm run dev +``` + +## How it Works + +This extension uses Cap's deeplink protocol (`cap-desktop://`) to communicate with the desktop app. Each command sends a specific deeplink action: + +| Command | Deeplink Action | +|---------|-----------------| +| Start Recording | `start_recording` | +| Stop Recording | `stop_recording` | +| Pause Recording | `pause_recording` | +| Resume Recording | `resume_recording` | +| Toggle Pause | `toggle_pause_recording` | + +## Deeplink Format + +``` +cap-desktop://action?value={"action_name": {...params}} +``` + +Example: +``` +cap-desktop://action?value={"pause_recording":null} +``` + +## Requirements + +- macOS 11.0 or later +- Cap desktop app installed +- Raycast installed + +## License + +MIT diff --git a/extensions/raycast/package.json b/extensions/raycast/package.json new file mode 100644 index 0000000000..74ee7b207c --- /dev/null +++ b/extensions/raycast/package.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://www.raycast.com/schemas/extension.json", + "name": "cap", + "title": "Cap", + "description": "Control Cap screen recorder with Raycast", + "icon": "cap-icon.png", + "author": "cap-software", + "categories": ["Productivity", "Media"], + "license": "MIT", + "commands": [ + { + "name": "start-recording", + "title": "Start Recording", + "description": "Start a screen recording with Cap", + "mode": "no-view" + }, + { + "name": "stop-recording", + "title": "Stop Recording", + "description": "Stop the current recording", + "mode": "no-view" + }, + { + "name": "pause-recording", + "title": "Pause Recording", + "description": "Pause the current recording", + "mode": "no-view" + }, + { + "name": "resume-recording", + "title": "Resume Recording", + "description": "Resume a paused recording", + "mode": "no-view" + }, + { + "name": "toggle-pause", + "title": "Toggle Pause", + "description": "Toggle pause/resume on current recording", + "mode": "no-view" + } + ], + "dependencies": { + "@raycast/api": "^1.83.0" + }, + "devDependencies": { + "@raycast/eslint-config": "^1.0.11", + "@types/node": "20.8.10", + "@types/react": "18.3.3", + "eslint": "^8.57.0", + "prettier": "^3.3.3", + "typescript": "^5.4.5" + }, + "scripts": { + "build": "ray build --skip-types -e dist -o dist", + "dev": "ray develop", + "fix-lint": "ray lint --fix", + "lint": "ray lint", + "prepublishOnly": "echo \"\\n\\nIt seems like you are trying to publish the Raycast extension to npm.\\n\\nIf you did intend to publish it to npm, remove the \\`prepublishOnly\\` script and rerun \\`npm publish\\` again.\\nIf you wanted to publish it to the Raycast Store instead, use \\`npm run publish\\` instead.\\n\\n\" && exit 1", + "publish": "npx @raycast/api@latest publish" + } +} diff --git a/extensions/raycast/src/pause-recording.tsx b/extensions/raycast/src/pause-recording.tsx new file mode 100644 index 0000000000..7a1182799b --- /dev/null +++ b/extensions/raycast/src/pause-recording.tsx @@ -0,0 +1,13 @@ +import { open, showHUD } from "@raycast/api"; + +export default async function Command() { + const action = { pause_recording: null }; + const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; + + try { + await open(deeplink); + await showHUD("⏸️ Recording paused"); + } catch (error) { + await showHUD("❌ Failed to pause recording"); + } +} diff --git a/extensions/raycast/src/resume-recording.tsx b/extensions/raycast/src/resume-recording.tsx new file mode 100644 index 0000000000..bfba0349a6 --- /dev/null +++ b/extensions/raycast/src/resume-recording.tsx @@ -0,0 +1,13 @@ +import { open, showHUD } from "@raycast/api"; + +export default async function Command() { + const action = { resume_recording: null }; + const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; + + try { + await open(deeplink); + await showHUD("▶️ Recording resumed"); + } catch (error) { + await showHUD("❌ Failed to resume recording"); + } +} diff --git a/extensions/raycast/src/start-recording.tsx b/extensions/raycast/src/start-recording.tsx new file mode 100644 index 0000000000..02ad9576d2 --- /dev/null +++ b/extensions/raycast/src/start-recording.tsx @@ -0,0 +1,33 @@ +import { open, showHUD, getApplications } from "@raycast/api"; + +export default async function Command() { + const apps = await getApplications(); + const capInstalled = apps.some( + (app) => app.bundleId === "so.cap.desktop" || app.bundleId === "so.cap.desktop.dev" + ); + + if (!capInstalled) { + await showHUD("❌ Cap is not installed"); + return; + } + + // Start recording with default settings + const action = { + start_recording: { + capture_mode: { screen: "Built-in Display" }, + camera: null, + mic_label: null, + capture_system_audio: false, + mode: "studio" + } + }; + + const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; + + try { + await open(deeplink); + await showHUD("🎬 Recording started"); + } catch (error) { + await showHUD("❌ Failed to start recording"); + } +} diff --git a/extensions/raycast/src/stop-recording.tsx b/extensions/raycast/src/stop-recording.tsx new file mode 100644 index 0000000000..a94ea60c77 --- /dev/null +++ b/extensions/raycast/src/stop-recording.tsx @@ -0,0 +1,13 @@ +import { open, showHUD } from "@raycast/api"; + +export default async function Command() { + const action = { stop_recording: null }; + const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; + + try { + await open(deeplink); + await showHUD("⏹️ Recording stopped"); + } catch (error) { + await showHUD("❌ Failed to stop recording"); + } +} diff --git a/extensions/raycast/src/toggle-pause.tsx b/extensions/raycast/src/toggle-pause.tsx new file mode 100644 index 0000000000..a16854bbde --- /dev/null +++ b/extensions/raycast/src/toggle-pause.tsx @@ -0,0 +1,13 @@ +import { open, showHUD } from "@raycast/api"; + +export default async function Command() { + const action = { toggle_pause_recording: null }; + const deeplink = `cap-desktop://action?value=${encodeURIComponent(JSON.stringify(action))}`; + + try { + await open(deeplink); + await showHUD("⏯️ Recording pause toggled"); + } catch (error) { + await showHUD("❌ Failed to toggle pause"); + } +} From a1ec408f76371a34939e5f0e41f59e2cca8037d5 Mon Sep 17 00:00:00 2001 From: mackaman29-6008 Date: Mon, 2 Feb 2026 08:53:17 +0000 Subject: [PATCH 3/4] fix: address review feedback - Add icon file (assets/cap-icon.png) - Update icon path in package.json - Remove hardcoded display name from start-recording - Remove code comment per repo policy --- apps/desktop/src-tauri/src/deeplink_actions.rs | 1 - extensions/raycast/assets/cap-icon.png | Bin 0 -> 187 bytes extensions/raycast/package.json | 2 +- extensions/raycast/src/start-recording.tsx | 15 +++++---------- 4 files changed, 6 insertions(+), 12 deletions(-) create mode 100644 extensions/raycast/assets/cap-icon.png diff --git a/apps/desktop/src-tauri/src/deeplink_actions.rs b/apps/desktop/src-tauri/src/deeplink_actions.rs index 35c73e91f1..449c250ef6 100644 --- a/apps/desktop/src-tauri/src/deeplink_actions.rs +++ b/apps/desktop/src-tauri/src/deeplink_actions.rs @@ -32,7 +32,6 @@ pub enum DeepLinkAction { OpenSettings { page: Option, }, - // New actions for Raycast integration (#1540) PauseRecording, ResumeRecording, TogglePauseRecording, diff --git a/extensions/raycast/assets/cap-icon.png b/extensions/raycast/assets/cap-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f19a2414165608c66d42fcb4ae46697bf9e9128d GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ7Ec$)kO=p;(+v3<3^-i>&z`Yk zm)5(!?r!%BM};ed!ym=Q+%Yj!;pNp0NHXz}`TaxWo;HKQ?~k=_ Date: Tue, 3 Feb 2026 02:33:05 +0000 Subject: [PATCH 4/4] chore: remove code comments per repo guidelines Addresses Greptile review feedback - removes comments from start-recording.tsx per CLAUDE.md and AGENTS.md no-comments policy. --- extensions/raycast/src/start-recording.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/raycast/src/start-recording.tsx b/extensions/raycast/src/start-recording.tsx index f2864b0bcd..bfd7971dcb 100644 --- a/extensions/raycast/src/start-recording.tsx +++ b/extensions/raycast/src/start-recording.tsx @@ -11,8 +11,6 @@ export default async function Command() { return; } - // Start recording - Cap will use the default/last used display - // Note: For display selection, users should configure in Cap preferences const action = { open_settings: { page: "recording" } };