-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: extend deeplink actions for Raycast extension support #1543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: extend deeplink actions for Raycast extension support #1543
Conversation
|
Ready for review @richiemcilroy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
15 files reviewed, 4 comments
| export default async function Command() { | ||
| await executeCapAction(createGetStatusAction(), { | ||
| feedbackMessage: "Checking recording status...", | ||
| feedbackType: "hud", | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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..."