feat: extend deeplink actions for Raycast extension support#1543
feat: extend deeplink actions for Raycast extension support#1543onyedikachi-david wants to merge 1 commit intoCapSoftware:mainfrom
Conversation
|
Ready for review @richiemcilroy |
| export default async function Command() { | ||
| await executeCapAction(createGetStatusAction(), { | ||
| feedbackMessage: "Checking recording status...", | ||
| feedbackType: "hud", | ||
| }); |
There was a problem hiding this comment.
logic: GetStatus action prints response to stdout but Raycast extension doesn't capture it. The status is sent via deeplink but never displayed to the user.
| export default async function Command() { | |
| await executeCapAction(createGetStatusAction(), { | |
| feedbackMessage: "Checking recording status...", | |
| feedbackType: "hud", | |
| }); | |
| import { showHUD } from "@raycast/api"; | |
| import { executeCapAction, createGetStatusAction, RecordingStatus } from "./utils"; | |
| export default async function Command() { | |
| const status = await getRecordingStatus(); | |
| if (status) { | |
| const message = status.is_recording | |
| ? `Recording (${status.recording_mode})${status.is_paused ? ' - Paused' : ''}` | |
| : 'Not recording'; | |
| await showHUD(message); | |
| } | |
| } | |
| async function getRecordingStatus(): Promise<RecordingStatus | null> { | |
| return null; | |
| } |
How should the Raycast extension receive the JSON response that's printed to stdout via CAP_DEEPLINK_RESPONSE:?
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/raycast/src/recording-status.tsx
Line: 3:7
Comment:
**logic:** `GetStatus` action prints response to stdout but Raycast extension doesn't capture it. The status is sent via deeplink but never displayed to the user.
```suggestion
import { showHUD } from "@raycast/api";
import { executeCapAction, createGetStatusAction, RecordingStatus } from "./utils";
export default async function Command() {
const status = await getRecordingStatus();
if (status) {
const message = status.is_recording
? `Recording (${status.recording_mode})${status.is_paused ? ' - Paused' : ''}`
: 'Not recording';
await showHUD(message);
}
}
async function getRecordingStatus(): Promise<RecordingStatus | null> {
return null;
}
```
How should the Raycast extension receive the JSON response that's printed to stdout via `CAP_DEEPLINK_RESPONSE:`?
How can I resolve this? If you propose a fix, please make it concise.| DeepLinkAction::ListDevices => { | ||
| let devices = get_available_devices(); | ||
| let json = serde_json::to_string(&devices).map_err(|e| e.to_string())?; | ||
| println!("CAP_DEEPLINK_RESPONSE:{}", json); | ||
| Ok(()) |
There was a problem hiding this comment.
logic: ListDevices and GetStatus actions print JSON to stdout, but there's no mechanism in the Raycast extension to capture this output. The deeplink protocol is fire-and-forget via URL scheme, so the extension cannot receive the response. Should these actions use IPC commands instead of deeplinks, or is there a planned mechanism for capturing stdout from the deeplink handler?
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 238:242
Comment:
**logic:** `ListDevices` and `GetStatus` actions print JSON to stdout, but there's no mechanism in the Raycast extension to capture this output. The deeplink protocol is fire-and-forget via URL scheme, so the extension cannot receive the response. Should these actions use IPC commands instead of deeplinks, or is there a planned mechanism for capturing stdout from the deeplink handler?
How can I resolve this? If you propose a fix, please make it concise.| <Form.Dropdown.Item value="instant" title="Instant" icon={Icon.Video} /> | ||
| <Form.Dropdown.Item value="studio" title="Studio" icon={Icon.Camera} /> | ||
| </Form.Dropdown> | ||
| <Form.Description text="Tip: Run 'List Devices' command in Cap to see available screen and window names." /> |
There was a problem hiding this comment.
logic: References non-existent "List Devices" command. The package.json doesn't define a list-devices command, only the deeplink action exists.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/raycast/src/start-recording.tsx
Line: 53:53
Comment:
**logic:** References non-existent "List Devices" command. The `package.json` doesn't define a `list-devices` command, only the deeplink action exists.
How can I resolve this? If you propose a fix, please make it concise.| value={targetName} | ||
| onChange={setTargetName} | ||
| /> | ||
| <Form.Description text="Tip: Run 'List Devices' command in Cap to see available screen and window names." /> |
There was a problem hiding this comment.
logic: References non-existent "List Devices" command. The package.json doesn't define a list-devices command.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/raycast/src/take-screenshot.tsx
Line: 47:47
Comment:
**logic:** References non-existent "List Devices" command. The `package.json` doesn't define a `list-devices` command.
How can I resolve this? If you propose a fix, please make it concise.| @@ -0,0 +1,96 @@ | |||
| { | |||
| "$schema": "https://www.raycast.com/schemas/extension.json", | |||
| "name": "cap", | |||
There was a problem hiding this comment.
Since pnpm-workspace.yaml includes extensions/*, this package ends up in the pnpm workspace. The repo root already has a package named cap, so this duplicate name will likely break workspace resolution.
| "name": "cap", | |
| "name": "cap-raycast", |
| let state = app.state::<ArcLock<App>>(); | ||
| let app_state = state.read().await; | ||
| let status = if let Some(recording) = app_state.current_recording() { | ||
| let is_paused = recording.is_paused().await.unwrap_or(false); |
There was a problem hiding this comment.
unwrap_or(false) will silently hide failures from is_paused() and report an incorrect status. It might be better to surface the error through the deeplink response.
| let is_paused = recording.is_paused().await.unwrap_or(false); | |
| let is_paused = recording.is_paused().await.map_err(|e| e.to_string())?; |
| DeepLinkAction::ListDevices => { | ||
| let devices = get_available_devices(); | ||
| let json = serde_json::to_string(&devices).map_err(|e| e.to_string())?; | ||
| println!("CAP_DEEPLINK_RESPONSE:{}", json); |
There was a problem hiding this comment.
list_devices/get_status currently print the JSON response to stdout. When invoked via a URL scheme there usually isn’t a stdout consumer, so these responses may never be observable from Raycast. If you need Raycast to read the response, consider a transport it can actually access (clipboard, file, notification, or callback URL).
| }) | ||
| .collect(); | ||
|
|
||
| let microphones: Vec<String> = MicrophoneFeed::list().keys().cloned().collect(); |
There was a problem hiding this comment.
Microphone list ordering can be nondeterministic (map key iteration). Sorting makes the output stable.
| let microphones: Vec<String> = MicrophoneFeed::list().keys().cloned().collect(); | |
| let mut microphones: Vec<String> = MicrophoneFeed::list().keys().cloned().collect(); | |
| microphones.sort(); |
/claim #1540
Fixes #1540
I am still trying to record a demo, currently unable to do that due to the error below when i run this command:
pnpm tauri:build --debug; is there a specific node version that the repo recommends, only this commands fails, commands likepnpm dev:desktopworks fine.Error:
@cap/web-domain:build: import { styleText } from "node:util"; @cap/web-domain:build: ^^^^^^^^^ @cap/web-domain:build: SyntaxError: The requested module 'node:util' does not provide an export named 'styleText' @cap/web-domain:build: at ModuleJob._instantiate (node:internal/modules/esm/module_job:122:21) @cap/web-domain:build: at async ModuleJob.run (node:internal/modules/esm/module_job:188:5) @cap/web-domain:build: @cap/web-domain:build: Node.js v20.2.0 @cap/env:build: ELIFECYCLE Command failed with exit code 1. @cap/web-domain:build: ELIFECYCLE Command failed with exit code 1. @cap/env:build: ERROR: command finished with error: command (/Users/onyedikachi/Documents/codes/Cap/packages/env) /Users/onyedikachi/.nvm/versions/node/v20.2.0/bin/pnpm run build exited (1) @cap/web-domain:build: ERROR: command finished with error: command (/Users/onyedikachi/Documents/codes/Cap/packages/web-domain) /Users/onyedikachi/.nvm/versions/node/v20.2.0/bin/pnpm run build exited (1) @cap/env#build: command (/Users/onyedikachi/Documents/codes/Cap/packages/env) /Users/onyedikachi/.nvm/versions/node/v20.2.0/bin/pnpm run build exited (1) @cap/web-domain#build: command (/Users/onyedikachi/Documents/codes/Cap/packages/web-domain) /Users/onyedikachi/.nvm/versions/node/v20.2.0/bin/pnpm run build exited (1) Tasks: 0 successful, 2 total Cached: 0 cached, 2 total Time: 1.834s Failed: @cap/env#build, @cap/web-domain#build ERROR run failed: command exited (1) beforeBuildCommand `pnpm turbo build --filter @cap/desktop` failed with exit code 1 Error [tauri_cli_node] beforeBuildCommand `pnpm turbo build --filter @cap/desktop` failed with exit code 1 ELIFECYCLE Command failed with exit code 1. ELIFECYCLE Command failed with exit code 1.Greptile Summary
Extends Cap's deeplink API with 8 new actions for recording control and adds a functional Raycast extension for controlling Cap from Raycast.
Major Changes:
pause_recording,resume_recording,toggle_pause_recording,restart_recording,take_screenshot,set_microphone,set_camera,list_devices,get_statusresolve_capture_target()helperextensions/raycast/with 8 commandsextensions/*to pnpm workspace configurationIssues Found:
GetStatusandListDevicesactions print JSON responses to stdout viaCAP_DEEPLINK_RESPONSE:prefix, but the Raycast extension has no mechanism to capture this output since deeplinks are fire-and-forget URL scheme callsrecording-statuscommand triggers the action but cannot display the actual status datapackage.json)Confidence Score: 3/5
GetStatusandListDevicesactions are incomplete as their responses cannot be received by the Raycast extension through the current deeplink architectureapps/desktop/src-tauri/src/deeplink_actions.rs(stdout response mechanism) andextensions/raycast/src/recording-status.tsx(incomplete implementation)Important Files Changed
Sequence Diagram
sequenceDiagram participant R as Raycast Extension participant OS as macOS URL Handler participant C as Cap Desktop App participant DR as Deeplink Router participant RA as Recording Actions Note over R,RA: Start Recording Flow R->>R: User fills form (screen/window, mode) R->>R: Create JSON action payload R->>OS: Open cap-desktop://action?value=<encoded-json> OS->>C: Route deeplink URL C->>DR: handle(url) DR->>DR: Parse URL & deserialize action DR->>RA: execute(StartRecording) RA->>RA: set_camera_input() RA->>RA: set_mic_input() RA->>RA: resolve_capture_target() RA->>RA: start_recording() R->>R: Show HUD "Starting recording..." Note over R,RA: Control Recording Flow R->>OS: Open cap-desktop://action?value={"pause_recording":{}} OS->>C: Route deeplink C->>DR: handle(url) DR->>RA: execute(PauseRecording) RA->>RA: pause_recording() R->>R: Show HUD "Pausing recording..." Note over R,RA: Query Status Flow (Current Issue) R->>OS: Open cap-desktop://action?value={"get_status":{}} OS->>C: Route deeplink C->>DR: handle(url) DR->>RA: execute(GetStatus) RA->>RA: Read app state RA->>RA: println!("CAP_DEEPLINK_RESPONSE:{json}") Note over R,RA: Response printed to stdout but not captured by Raycast R->>R: Show HUD (no actual status data) Note over R,RA: Screenshot Flow R->>R: User selects screen/window R->>OS: Open cap-desktop://action?value={"take_screenshot":{...}} OS->>C: Route deeplink C->>DR: handle(url) DR->>RA: execute(TakeScreenshot) RA->>RA: resolve_capture_target() RA->>RA: take_screenshot() R->>R: Show HUD "Taking screenshot..."