Skip to content

feat: display configured keyboard shortcuts inside tray menubar dropdown menu (#1854) - #2091

Open
Samarth1306w wants to merge 7 commits into
CapSoftware:mainfrom
Samarth1306w:feat/display-keyboard-shortcuts-in-tray-menu-1854
Open

feat: display configured keyboard shortcuts inside tray menubar dropdown menu (#1854)#2091
Samarth1306w wants to merge 7 commits into
CapSoftware:mainfrom
Samarth1306w:feat/display-keyboard-shortcuts-in-tray-menu-1854

Conversation

@Samarth1306w

@Samarth1306w Samarth1306w commented Aug 6, 2026

Copy link
Copy Markdown

Fixes #1854

Summary

Display configured hotkeys next to menu item actions inside the desktop tray menubar dropdown menu and refresh the menu dynamically when shortcuts are modified in Settings.

  1. ****:
    • Added helper on .
    • Added helper to query active keybindings from the .
    • Wired inside so tray menu item labels/accelerators update immediately upon saving a new hotkey.
  2. ****:
    • Passed into for Record Display, Record Window, Record Area, and Take Screenshot items.

Greptile Summary

The PR adds tray-menu accelerator labels with dynamic refresh, introduces a CLI command and web endpoint for AI video metadata, adds rate limiting to selected endpoints, supports configurable OpenAI-compatible URLs, and adjusts desktop/mobile teleprompter layout behavior.

  • Displays configured recording and screenshot shortcuts in the desktop tray menu.
  • Adds cap recordings info and a corresponding video-metadata GET endpoint.
  • Adds endpoint rate limits and a contract test for rate-limit identifiers.
  • Preserves teleprompter position across selected relayouts and supports OPENAI_BASE_URL.

Confidence Score: 2/5

This PR is not safe to merge until the password-protected metadata disclosure and valid share-URL parsing failure are fixed.

The new metadata route exposes AI-derived content without enforcing the existing password gate, while the CLI rejects valid copied share URLs containing common trailing or query components; the remaining comments are non-blocking repository-quality issues.

Files Needing Attention: apps/web/app/api/video/metadata/route.ts, apps/cli/src/recordings.rs

Security Review

The new metadata endpoint bypasses the password gate for public password-protected videos, exposing titles, summaries, chapters, and generation status to unauthenticated callers. How this was verified: The added GET handler returns metadata whenever video.public is true and contains no password-cookie or shared video-policy validation.

Important Files Changed

Filename Overview
apps/desktop/src-tauri/src/hotkeys.rs Adds accelerator formatting and queues a tray refresh after hotkey changes; no blocking defect remains in the checked lock path.
apps/desktop/src-tauri/src/tray.rs Attaches configured hotkey accelerators to recording and screenshot tray items.
apps/cli/src/recordings.rs Adds remote metadata retrieval, but valid copied URLs with common suffixes are parsed into invalid video IDs.
apps/web/app/api/video/metadata/route.ts Adds metadata retrieval but bypasses password protection for public videos and introduces an unsafe any cast.
apps/web/tests/unit/rate-limit-ids.test.ts Adds a repository-wide rate-limit-ID reference check with redundant comments contrary to repository guidance.
apps/mobile/src/recording/TeleprompterOverlay.tsx Preserves normalized playback progress across subsequent text layouts; current callers prevent editing during playback.
packages/env/server.ts Adds optional validated configuration for an OpenAI-compatible base URL.
Prompt To Fix All With AI
### Issue 1
apps/web/app/api/video/metadata/route.ts:61-63
**Password gate bypassed for metadata**

When an unauthenticated caller supplies the ID of a public, password-protected video, this check grants access based only on `video.public`, exposing its AI title, summary, chapters, and generation status without the configured password. **How this was verified:** The successful GET path contains no password-cookie or shared video-policy check before returning the metadata.

### Issue 2
apps/cli/src/recordings.rs:111-119
**Share URL suffix corrupts ID**

When a copied share URL contains a trailing slash, query string, or fragment, `rsplit('/')` produces an empty or decorated video ID, causing valid URLs such as `https://cap.so/s/abc123/` or `https://cap.so/s/abc123?t=30` to fail with a 404.

### Issue 3
apps/web/app/api/video/metadata/route.ts:65
**Metadata cast discards type safety**

Casting persisted metadata to `Record<string, any>` removes type checking from every returned property, allowing incompatible values and misspelled fields to pass compilation. Use `unknown` with narrowing or an existing metadata type instead.

### Issue 4
apps/web/__tests__/unit/rate-limit-ids.test.ts:6-7
**Allowlist comments duplicate the code**

These comments only narrate the adjacent, self-describing `UNWIRED_RATE_LIMIT_IDS` declaration and add text that must be maintained without preserving a non-obvious invariant or trade-off.

```suggestion

```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "feat: display configured keyboard shortc..." | Re-trigger Greptile

Greptile also left 4 inline comments on this PR.

Context used (6)

@superagent-security

Copy link
Copy Markdown

🚨 Contributor flagged. Click here for more info: Superagent Dashboard

Comment on lines +61 to +63
return Response.json({ error: "Unauthorized" }, { status: 401 });
}

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 security Password gate bypassed for metadata

When an unauthenticated caller supplies the ID of a public, password-protected video, this check grants access based only on video.public, exposing its AI title, summary, chapters, and generation status without the configured password. How this was verified: The successful GET path contains no password-cookie or shared video-policy check before returning the metadata.

Knowledge Base Used: Web App (apps/web)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/app/api/video/metadata/route.ts
Line: 61-63

Comment:
**Password gate bypassed for metadata**

When an unauthenticated caller supplies the ID of a public, password-protected video, this check grants access based only on `video.public`, exposing its AI title, summary, chapters, and generation status without the configured password. **How this was verified:** The successful GET path contains no password-cookie or shared video-policy check before returning the metadata.

**Knowledge Base Used:** [Web App (apps/web)](https://app.greptile.com/cap/-/custom-context/knowledge-base/capsoftware/cap/-/docs/web-app.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +111 to +119
let video_id = if url_or_id.contains('/') {
url_or_id
.rsplit('/')
.next()
.unwrap_or(&url_or_id)
.to_string()
} else {
url_or_id
};

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 Share URL suffix corrupts ID

When a copied share URL contains a trailing slash, query string, or fragment, rsplit('/') produces an empty or decorated video ID, causing valid URLs such as https://cap.so/s/abc123/ or https://cap.so/s/abc123?t=30 to fail with a 404.

Knowledge Base Used: Cap CLI (apps/cli)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/cli/src/recordings.rs
Line: 111-119

Comment:
**Share URL suffix corrupts ID**

When a copied share URL contains a trailing slash, query string, or fragment, `rsplit('/')` produces an empty or decorated video ID, causing valid URLs such as `https://cap.so/s/abc123/` or `https://cap.so/s/abc123?t=30` to fail with a 404.

**Knowledge Base Used:** [Cap CLI (`apps/cli`)](https://app.greptile.com/cap/-/custom-context/knowledge-base/capsoftware/cap/-/docs/cli.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

}

const meta = (video.metadata as Record<string, any>) ?? {};

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 Metadata cast discards type safety

Casting persisted metadata to Record<string, any> removes type checking from every returned property, allowing incompatible values and misspelled fields to pass compilation. Use unknown with narrowing or an existing metadata type instead.

Context Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/app/api/video/metadata/route.ts
Line: 65

Comment:
**Metadata cast discards type safety**

Casting persisted metadata to `Record<string, any>` removes type checking from every returned property, allowing incompatible values and misspelled fields to pass compilation. Use `unknown` with narrowing or an existing metadata type instead.

**Context Used:** CLAUDE.md ([source](https://github.com/capsoftware/cap/blob/main/CLAUDE.md))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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 +6 to +7
// Rate limit IDs declared in advance for firewall rules or separate app packages
// that are intentionally not yet wired in apps/web endpoints.

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 Allowlist comments duplicate the code

These comments only narrate the adjacent, self-describing UNWIRED_RATE_LIMIT_IDS declaration and add text that must be maintained without preserving a non-obvious invariant or trade-off.

Suggested change
// Rate limit IDs declared in advance for firewall rules or separate app packages
// that are intentionally not yet wired in apps/web endpoints.

Context Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/__tests__/unit/rate-limit-ids.test.ts
Line: 6-7

Comment:
**Allowlist comments duplicate the code**

These comments only narrate the adjacent, self-describing `UNWIRED_RATE_LIMIT_IDS` declaration and add text that must be maintained without preserving a non-obvious invariant or trade-off.

```suggestion

```

**Context Used:** CLAUDE.md ([source](https://github.com/capsoftware/cap/blob/main/CLAUDE.md))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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!

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.

[Feature Request]: Display keyboard shortcuts inside the Menubar dropdown menu

2 participants