Conversation
- Fix icon and reorganize action panel sections - Prepare for publishing: README, changelog, clean up tracked files - Prepare for Raycast Store publishing - Fix Open/Edit in Contacts to use AppleScript - Add favorite contacts feature (⌘⇧S) - Add Edit in Contacts action (⌘⇧O) - Add detail pane profile picture and organization name - Fix flicker: batch contacts and frequency into single render - Fix selection: load frequency before showing cached contacts - Revert detail pane to Metadata.Label with colored icons - Revert list accessories to icons, add colored tags in detail pane - Show primary label tags as accessories instead of count icons - Group non-alpha contacts under # like standard phonebooks - Group contacts by first letter in phonebook-style sections - Fix frequently contacted: use Action with push() instead of Action.Push - Add frequently contacted sorting with persistent tracking - Add colored icons to ContactActions sections - Revert Swift to original thumbnails, simplify detail panel to metadata-only - Generate initials avatars for contacts without photos - Use standard markdown image for circular contact photo in detail panel - Circular contact photo in detail panel with name beside it - Show circular contact photo in detail panel metadata - Re-add contact photo to detail panel as small 80px image - Remove oversized photo from detail panel, keep metadata only - Fix detail panel image: encode spaces in file:// path - Add detail side panel with contact info (⌘D toggle) - Add empty search state and contact row accessories - Add email addresses to FaceTime Video section - Add Open in Contacts action (⌘O) - Group copy actions into separate ActionPanel section - Align shortcuts with Raycast built-in Contacts and add copy actions - Fix reserved shortcut: ⌘P → ⌘⇧P for Call action - Pre-compile Swift contact fetcher for faster startup - Cache contacts for instant loading on repeat opens - Add keyboard shortcuts for quick actions on main contact list - Working state: contacts, photos, search ranking, contact argument feature
|
Congratulations on your new Raycast extension! 🚀 We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days. Once the PR is approved and merged, the extension will be available on our Store. |
Greptile SummaryThis PR adds a new Quick Contact Actions extension that lets users search their macOS contacts and launch FaceTime, calls, messages, and emails directly from Raycast. It uses a bundled Swift binary (compiled via a Key issues to address before merging:
Confidence Score: 3/5Not safe to merge — the AppleScript injection in the Swift binary is a definite code injection path that should be fixed before shipping. The AppleScript injection via unescaped newlines is a verified P1 security defect. While exploitation requires a crafted contact in the user's own address book, the vulnerability is real and reproducible. The two P2 findings are not blockers on their own. assets/get-contacts.swift (AppleScript injection), src/quick-contact-actions.tsx (silent errors and detail computation) Important Files Changed
Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/quick-contact-actions/assets/get-contacts.swift
Line: 71-72
Comment:
**AppleScript injection via unescaped newlines in contact name**
The Swift code escapes double quotes in the contact name before embedding it in the AppleScript string, but does not escape newline characters (`\n`). A contact whose `givenName` or `familyName` contains a literal newline (which `CNContactStore` does not prohibit) would break out of the AppleScript string and allow arbitrary AppleScript injection.
At minimum, newlines should also be stripped or escaped:
```swift
let escaped = name
.replacingOccurrences(of: "\\", with: "\\\\")
.replacingOccurrences(of: "\"", with: "\\\"")
.replacingOccurrences(of: "\n", with: " ")
.replacingOccurrences(of: "\r", with: " ")
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/quick-contact-actions/src/quick-contact-actions.tsx
Line: 479-484
Comment:
**Silent errors on Open/Edit in Contacts actions**
The `execFile` callback is `() => {}` for both "Open in Contacts" and "Edit in Contacts", silently discarding any errors. Users receive zero feedback if the action fails. Consider showing a `Toast` on error. The same applies to the "Edit in Contacts" action on line 492.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/quick-contact-actions/src/quick-contact-actions.tsx
Line: 386-417
Comment:
**Detail panel content computed on every render for all contacts**
The `detail` prop — including the IIFE that generates SVG data URIs — is evaluated unconditionally on every render for every list item, regardless of whether `showDetail` is `true`. Guard the prop behind the `showDetail` flag so the computation is skipped when the panel is hidden.
How can I resolve this? If you propose a fix, please make it concise.Reviews (2): Last reviewed commit: "Update screenshots and apply reviewer ch..." | Re-trigger Greptile |
| <Action.Open | ||
| title="Start FaceTime Video" | ||
| icon={Icon.Video} | ||
| target={`facetime://${p.value.replace(/\s/g, "")}`} |
There was a problem hiding this comment.
Inconsistent phone number normalization in FaceTime URLs
The facetime:// URL only strips whitespace (.replace(/\s/g, "")), which leaves parentheses, dashes, and other formatting characters in the URL. A number like (555) 123-4567 becomes facetime://(555)123-4567, which is an invalid URL and will silently fail to launch FaceTime.
The tel: action on line 136 correctly uses .replace(/[^+\d]/g, "") to strip all non-digit/non-plus characters. The same regex should be applied here and in the facetime-audio:// URLs.
Affected lines: 65, 102, 117, 436, 444.
| target={`facetime://${p.value.replace(/\s/g, "")}`} | |
| target={`facetime://${p.value.replace(/[^+\d]/g, "")}`} |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/quick-contact-actions/src/quick-contact-actions.tsx
Line: 65
Comment:
**Inconsistent phone number normalization in FaceTime URLs**
The `facetime://` URL only strips whitespace (`.replace(/\s/g, "")`), which leaves parentheses, dashes, and other formatting characters in the URL. A number like `(555) 123-4567` becomes `facetime://(555)123-4567`, which is an invalid URL and will silently fail to launch FaceTime.
The `tel:` action on line 136 correctly uses `.replace(/[^+\d]/g, "")` to strip all non-digit/non-plus characters. The same regex should be applied here and in the `facetime-audio://` URLs.
Affected lines: `65`, `102`, `117`, `436`, `444`.
```suggestion
target={`facetime://${p.value.replace(/[^+\d]/g, "")}`}
```
How can I resolve this? If you propose a fix, please make it concise.| "commands": [ | ||
| { | ||
| "name": "quick-contact-actions", | ||
| "title": "Quick Contact Actions", | ||
| "description": "Search contacts and launch calls, messages, and emails instantly.", | ||
| "mode": "view", | ||
| "arguments": [ | ||
| { | ||
| "name": "contact", | ||
| "placeholder": "Contact name", | ||
| "required": false, | ||
| "type": "text" | ||
| } | ||
| ] | ||
| } |
There was a problem hiding this comment.
Missing
metadata/ folder with store screenshots
The extension defines a view-mode command but no metadata/ folder with Raycast-styled screenshots has been included. This folder is required before an extension can be published to the Raycast Store.
Please add a metadata/ directory containing at least one screenshot of the extension in use (PNG, 2880×1800px recommended). See the Raycast docs on screenshots for formatting requirements.
Rule Used: What: Extensions with view-type commands must incl... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/quick-contact-actions/package.json
Line: 18-32
Comment:
**Missing `metadata/` folder with store screenshots**
The extension defines a `view`-mode command but no `metadata/` folder with Raycast-styled screenshots has been included. This folder is required before an extension can be published to the Raycast Store.
Please add a `metadata/` directory containing at least one screenshot of the extension in use (PNG, 2880×1800px recommended). See the [Raycast docs on screenshots](https://developers.raycast.com/basics/prepare-an-extension-for-store#screenshots) for formatting requirements.
**Rule Used:** What: Extensions with view-type commands must incl... ([source](https://app.greptile.com/review/custom-context?memory=87059ac1-c601-487f-9f1c-bce8a3cb6209))
How can I resolve this? If you propose a fix, please make it concise.| await LocalStorage.setItem(FREQ_KEY, JSON.stringify(freq)); | ||
| } | ||
|
|
||
| export default function Command(props: { arguments: { contact?: string } }) { |
There was a problem hiding this comment.
Manually typed Arguments interface
The Arguments type for command props should not be defined manually — it is auto-generated in raycast-env.d.ts when the extension runs. Use LaunchProps with the generated type instead:
| export default function Command(props: { arguments: { contact?: string } }) { | |
| export default function Command(props: LaunchProps<{ arguments: Arguments.QuickContactActions }>) { |
You'll also need to add LaunchProps to the @raycast/api import at the top of the file.
Rule Used: What: Don't manually define Preferences for `get... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/quick-contact-actions/src/quick-contact-actions.tsx
Line: 269
Comment:
**Manually typed Arguments interface**
The `Arguments` type for command props should not be defined manually — it is auto-generated in `raycast-env.d.ts` when the extension runs. Use `LaunchProps` with the generated type instead:
```suggestion
export default function Command(props: LaunchProps<{ arguments: Arguments.QuickContactActions }>) {
```
You'll also need to add `LaunchProps` to the `@raycast/api` import at the top of the file.
**Rule Used:** What: Don't manually define `Preferences` for `get... ([source](https://app.greptile.com/review/custom-context?memory=d93fc9fb-a45d-4479-a6a4-b1b4af98ebc8))
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| do { |
There was a problem hiding this comment.
AppleScript injection via unescaped newlines in contact name
The Swift code escapes double quotes in the contact name before embedding it in the AppleScript string, but does not escape newline characters (\n). A contact whose givenName or familyName contains a literal newline (which CNContactStore does not prohibit) would break out of the AppleScript string and allow arbitrary AppleScript injection.
At minimum, newlines should also be stripped or escaped:
let escaped = name
.replacingOccurrences(of: "\\", with: "\\\\")
.replacingOccurrences(of: "\"", with: "\\\"")
.replacingOccurrences(of: "\n", with: " ")
.replacingOccurrences(of: "\r", with: " ")Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/quick-contact-actions/assets/get-contacts.swift
Line: 71-72
Comment:
**AppleScript injection via unescaped newlines in contact name**
The Swift code escapes double quotes in the contact name before embedding it in the AppleScript string, but does not escape newline characters (`\n`). A contact whose `givenName` or `familyName` contains a literal newline (which `CNContactStore` does not prohibit) would break out of the AppleScript string and allow arbitrary AppleScript injection.
At minimum, newlines should also be stripped or escaped:
```swift
let escaped = name
.replacingOccurrences(of: "\\", with: "\\\\")
.replacingOccurrences(of: "\"", with: "\\\"")
.replacingOccurrences(of: "\n", with: " ")
.replacingOccurrences(of: "\r", with: " ")
```
How can I resolve this? If you propose a fix, please make it concise.
Description
Search your macOS contacts and launch calls, messages, and emails instantly from
Raycast.
Features
or email
qca johnto auto-navigate if there's a uniquematch
Keyboard Shortcuts
Permissions
on first use.
Contacts.app via System Events). macOS will prompt when first used.
Screencast
Checklist
npm run buildand tested this distribution build in Raycastassetsfolder are used by the extension itselfREADMEare placed outside of themetadatafolder