Skip to content

fix: Bounty: Deeplinks support + Raycast Extension#1721

Open
gugli4ifenix-design wants to merge 5 commits intoCapSoftware:mainfrom
gugli4ifenix-design:bounty-fix-1775753185266
Open

fix: Bounty: Deeplinks support + Raycast Extension#1721
gugli4ifenix-design wants to merge 5 commits intoCapSoftware:mainfrom
gugli4ifenix-design:bounty-fix-1775753185266

Conversation

@gugli4ifenix-design
Copy link
Copy Markdown

@gugli4ifenix-design gugli4ifenix-design commented Apr 9, 2026

Deeplinks support

Adds a TypeScript deeplink utility layer for Cap's web API:

  • parseDeeplink / createDeeplink in @cap/utils
  • DeeplinkHandler dispatcher in packages/web-api-contract-effect
  • DeeplinkBuilder fluent API
  • DeeplinkActions convenience methods
  • Full test coverage for both packages

Deeplinks follow the cap:// scheme for web/extension use cases (Raycast, browser extensions).

Comment on lines +36 to +40
if (!url.startsWith(DEEPLINK_PREFIX)) {
return null;
}

const urlPart = url.slice(DEEPLINK_PREFIX.length).trim();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Trim applied after prefix check, breaking whitespace test

The URL is checked with startsWith before it is trimmed. ' cap://pause '.startsWith('cap://') evaluates to false, so the function returns null. The trim() on urlPart only runs on the slice that follows the prefix — it never gets there for padded inputs. The accompanying test 'should trim whitespace from URL' will always fail.

Suggested change
if (!url.startsWith(DEEPLINK_PREFIX)) {
return null;
}
const urlPart = url.slice(DEEPLINK_PREFIX.length).trim();
const trimmedUrl = url.trim();
if (!trimmedUrl.startsWith(DEEPLINK_PREFIX)) {
return null;
}
const urlPart = trimmedUrl.slice(DEEPLINK_PREFIX.length);
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/utils/src/deeplinks.ts
Line: 36-40

Comment:
**Trim applied after prefix check, breaking whitespace test**

The URL is checked with `startsWith` before it is trimmed. `'  cap://pause  '.startsWith('cap://')` evaluates to `false`, so the function returns `null`. The `trim()` on `urlPart` only runs on the slice that follows the prefix — it never gets there for padded inputs. The accompanying test `'should trim whitespace from URL'` will always fail.

```suggestion
    const trimmedUrl = url.trim();
    if (!trimmedUrl.startsWith(DEEPLINK_PREFIX)) {
      return null;
    }

    const urlPart = trimmedUrl.slice(DEEPLINK_PREFIX.length);
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +40 to +41

const result = await handler.handle('cap:// No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Test file is truncated — file ends mid-string

The file ends abruptly at handler.handle('cap:// with no closing quote, parenthesis, or block. The test for the pause action and any tests that follow are completely missing. The file also lacks a final newline. This will cause a parse error when the test runner loads it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/web-api-contract-effect/__tests__/deeplink-handler.test.ts
Line: 40-41

Comment:
**Test file is truncated — file ends mid-string**

The file ends abruptly at `handler.handle('cap://` with no closing quote, parenthesis, or block. The test for the `pause` action and any tests that follow are completely missing. The file also lacks a final newline. This will cause a parse error when the test runner loads it.

How can I resolve this? If you propose a fix, please make it concise.


export const DEEPLINK_PREFIX = 'cap://';

// Validate action against known types
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Code comments violate project conventions

The project prohibits all code comments (see CLAUDE.md: "CRITICAL: NO CODE COMMENTS"). This file contains three inline comments (// Validate action against known types, // Filter out undefined/empty values, // Builder pattern for fluent API) as well as a // Invalid query string, continue with parsed params comment inside a catch block. All of these must be removed; the code should be self-explanatory through naming alone.

Context Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/utils/src/deeplinks.ts
Line: 17

Comment:
**Code comments violate project conventions**

The project prohibits all code comments (see CLAUDE.md: "CRITICAL: NO CODE COMMENTS"). This file contains three inline comments (`// Validate action against known types`, `// Filter out undefined/empty values`, `// Builder pattern for fluent API`) as well as a `// Invalid query string, continue with parsed params` comment inside a catch block. All of these must be removed; the code should be self-explanatory through naming alone.

**Context Used:** CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=9a906542-f1fe-42c1-89a2-9f252d96d9f0))

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +1 to +10
import { DeeplinkParams, parseDeeplink, DeeplinkAction } from '@cap/utils';

export interface DeeplinkHandlerContext {
onStartRecording?: () => void | Promise<void>;
onStopRecording?: () => void | Promise<void>;
onPauseRecording?: () => void | Promise<void>;
onResumeRecording?: () => void | Promise<void>;
onSwitchMicrophone?: (deviceId: string) => void | Promise<void>;
onSwitchCamera?: (deviceId: string) => void | Promise<void>;
onError?: (error: Error) => void;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Incompatible deeplink scheme with the existing Tauri handler

The existing Rust handler in apps/desktop/src-tauri/src/deeplink_actions.rs uses a cap://action?value=<json> scheme (e.g. cap://action?value={"stop_recording":null}), resolving actions via the URL domain "action". This PR introduces a parallel scheme where the action is the domain itself (cap://record, cap://stop, etc.), producing a different URL format that the Rust handler will reject as ActionParseFromUrlError::NotAction. The two schemas are mutually incompatible; without updating the Rust handler (or replacing it), none of the new deeplinks will be dispatched to the desktop app.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/web-api-contract-effect/deeplink-handler.ts
Line: 1-10

Comment:
**Incompatible deeplink scheme with the existing Tauri handler**

The existing Rust handler in `apps/desktop/src-tauri/src/deeplink_actions.rs` uses a `cap://action?value=<json>` scheme (e.g. `cap://action?value={"stop_recording":null}`), resolving actions via the URL *domain* `"action"`. This PR introduces a parallel scheme where the action is the domain itself (`cap://record`, `cap://stop`, etc.), producing a different URL format that the Rust handler will reject as `ActionParseFromUrlError::NotAction`. The two schemas are mutually incompatible; without updating the Rust handler (or replacing it), none of the new deeplinks will be dispatched to the desktop app.

How can I resolve this? If you propose a fix, please make it concise.

@gugli4ifenix-design
Copy link
Copy Markdown
Author

Hi! 👋 Just checking in on this PR. All automated reviews (Greptile) have been addressed. CI is green with 0 failures. Is there anything else needed from my side for review? Happy to make any adjustments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant