Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

feat(code): prompt for microphone permission for custom completion sounds - #2136

Closed
jamesefhawkins wants to merge 13 commits into
mainfrom
posthog-code/custom-sound-mic-permission
Closed

jamesefhawkins wants to merge 13 commits into
mainfrom
posthog-code/custom-sound-mic-permission

Conversation

@jamesefhawkins

Copy link
Copy Markdown

Summary

  • Wires up the macOS plumbing so the custom completion-sound recorder can actually capture audio (previously the mic stream returned silent ~1 KB blobs because Electron never asked for permission).
  • New IMediaAccess platform port + ElectronMediaAccess adapter wrapping systemPreferences.getMediaAccessStatus / askForMediaAccess, exposed via two new os.* tRPC procedures.
  • useSoundRecorder triggers the macOS prompt up front when status is not-determined, surfaces a toast with an "Open Settings" deeplink on denial, and shows a "Recording capped at 10 seconds" toast on auto-stop.
  • Adds NSMicrophoneUsageDescription to the packaged Info.plist via extendInfo and com.apple.security.device.audio-input to the hardened-runtime entitlements file.

Note: the diff also contains the unmerged project-work commits (the basic Custom recording UI, work-mode skills, etc.) because this branch is based on project-work. The mic-permission work itself is the single commit ddf556a5 and lives in:

  • apps/code/src/main/platform-adapters/electron-media-access.ts (new)
  • packages/platform/src/media-access.ts (new)
  • apps/code/src/main/trpc/routers/os.ts
  • apps/code/src/renderer/features/settings/hooks/useSoundRecorder.ts
  • apps/code/src/main/di/{container,tokens}.ts
  • apps/code/build/entitlements.mac.plist, apps/code/forge.config.ts
  • packages/platform/{package.json,tsup.config.ts}

Test plan

  • Fresh-install scenario on macOS: pick Settings → General → Sound effect → "Custom recording" → Record → macOS shows the native mic permission prompt with our usage string → click Allow → speak → Stop → Test plays back the recording.
  • Denied scenario: at the prompt click "Don't Allow" → toast appears with "Open Settings" action that opens System Settings → Privacy & Security → Microphone.
  • Auto-stop scenario: start recording and let it run for 10 seconds without clicking Stop → recording auto-stops and "Recording capped at 10 seconds" toast appears.
  • Packaged build (`pnpm --filter code package`) launches cleanly and the app appears in Privacy & Security → Microphone after the first prompt.
  • Non-macOS smoke (Linux/Windows): `requestMicrophoneAccess` returns true without prompting; recording works via the standard Chromium getUserMedia flow.

Created with PostHog Code

cleo-pleurodon and others added 13 commits May 13, 2026 14:22
Introduces a top-level mode toggle above the nav list. Work mode is an
empty shell — placeholder for an upcoming feature set built during the
hackathon.

Generated-By: PostHog Code
Task-Id: bd0f6387-4ee8-42a4-b17d-80927d214463
Generated-By: PostHog Code
Task-Id: 770a6aff-7419-424e-a0b0-893d6a1f9b3b
Adds icon assets and BRAND_ICONS entries for Gmail, Granola, Asana,
and the Google Workspace apps (Calendar, Drive, Docs, Sheets, Slides)
so the marketplace renders them once the backend catalog includes
matching templates.

The asana.svg is the wordmark for now — a square brand mark wasn't
available from public sources and should be swapped in later.

Generated-By: PostHog Code
Task-Id: 7540ef3b-b0e0-43a2-bb62-5e1836d85765
…Google Calendar/Drive

Adds a small client-side registry of MCP templates the backend catalog
doesn't yet expose, so the marketplace renders them with their brand
icons. Connect routes through the existing custom-install endpoint
using the official remote URLs.

Drops the Google Docs/Sheets/Slides icons that were registered in the
previous commit — there's no official remote MCP server for those (only
self-hosted community alternatives), and Drive's MCP already covers
their files.

Generated-By: PostHog Code
Task-Id: af4a4d09-f33e-4053-8f4d-5740d632fcc7
Generated-By: PostHog Code
Task-Id: 770a6aff-7419-424e-a0b0-893d6a1f9b3b
Replaces the splash with a full home: hero, real PromptInput-style
chat that hands off to TaskInput, clickable sample-project cards, and
a Work-mode sidebar with placeholder sections (Projects, Automations,
Artifacts, MCP, Memory) plus the standard New task entry. Adds new
hedgehog assets and a staggered entrance animation.

Generated-By: PostHog Code
Task-Id: 14cf4155-07c2-4962-ae8e-4065d6322475
Generated-By: PostHog Code
Task-Id: 14cf4155-07c2-4962-ae8e-4065d6322475
Adds the first iteration of Work-mode Skills:
- New WorkSidebarMenu listing skills, seeded with an example skill
- WorkGenerateView with a centered prompt that creates a task and streams
  the agent authoring the skill via PostHog MCP
- WorkSkillDetailView reuses TaskLogsPanel for live streaming, with a
  static card for seeded examples
- workSkillsStore (persisted) plus workView state in navigationStore
- os.getHomeDir tRPC helper for fallback repoPath

Includes the user's in-progress sound-recorder settings changes.

Generated-By: PostHog Code
Task-Id: bd0f6387-4ee8-42a4-b17d-80927d214463
# Conflicts:
#	apps/code/src/renderer/features/work/components/WorkSidebarMenu.tsx
#	apps/code/src/renderer/features/work/components/WorkView.tsx
…unds

Adds the macOS plumbing needed for the custom completion-sound recorder
to actually capture audio:
- New IMediaAccess platform port + ElectronMediaAccess adapter wrapping
  systemPreferences.getMediaAccessStatus / askForMediaAccess
- os.getMicrophoneAccessStatus / os.requestMicrophoneAccess tRPC procs
- useSoundRecorder triggers the macOS prompt up front when status is
  not-determined and shows a toast with an "Open Settings" deeplink on
  denial, plus a "Recording capped at 10 seconds" toast on the auto-stop
- NSMicrophoneUsageDescription in forge extendInfo (packaged builds)
- com.apple.security.device.audio-input entitlement for hardened-runtime
  signed builds

Generated-By: PostHog Code
Task-Id: af45b000-f4e8-4c8b-9dd2-ad0b607ea8cf
@greptile-apps

greptile-apps Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/code/src/renderer/features/settings/hooks/useSoundRecorder.ts:120-121
`toast.error` signals an unexpected failure to users, but hitting the 10-second cap is an expected, non-error outcome of leaving a recording running. Using a neutral toast type avoids falsely alarming the user.

```suggestion
          recorderRef.current.stop();
          toast.info(`Recording capped at ${MAX_RECORDING_MS / 1000} seconds`);
```

### Issue 2 of 2
apps/code/src/renderer/features/settings/hooks/useSoundRecorder.ts:124-133
**macOS-only deeplink shown on non-macOS platforms**

The `isPermissionError` branch can be reached on any platform (e.g. if the user denies Chromium-level microphone access on Linux or Windows). When that happens, the "Open Settings" action fires `x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone`, which is meaningless outside macOS — either silently failing or opening an unrelated URL. The description text ("in System Settings") is also macOS-specific. Consider hiding the action button or swapping the URL and description to a platform-appropriate value on non-macOS.

Reviews (1): Last reviewed commit: "feat(code): prompt for microphone permis..." | Re-trigger Greptile

Comment on lines +120 to +121
recorderRef.current.stop();
toast.error(`Recording capped at ${MAX_RECORDING_MS / 1000} seconds`);

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 toast.error signals an unexpected failure to users, but hitting the 10-second cap is an expected, non-error outcome of leaving a recording running. Using a neutral toast type avoids falsely alarming the user.

Suggested change
recorderRef.current.stop();
toast.error(`Recording capped at ${MAX_RECORDING_MS / 1000} seconds`);
recorderRef.current.stop();
toast.info(`Recording capped at ${MAX_RECORDING_MS / 1000} seconds`);
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/settings/hooks/useSoundRecorder.ts
Line: 120-121

Comment:
`toast.error` signals an unexpected failure to users, but hitting the 10-second cap is an expected, non-error outcome of leaving a recording running. Using a neutral toast type avoids falsely alarming the user.

```suggestion
          recorderRef.current.stop();
          toast.info(`Recording capped at ${MAX_RECORDING_MS / 1000} seconds`);
```

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 +124 to +133
} catch (error) {
log.error("Failed to start recording", error);
cleanup();
setIsRecording(false);
const isPermissionError =
error instanceof Error &&
(error.name === "NotAllowedError" ||
error.name === "SecurityError" ||
error.message.toLowerCase().includes("permission"));
if (isPermissionError) {

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 macOS-only deeplink shown on non-macOS platforms

The isPermissionError branch can be reached on any platform (e.g. if the user denies Chromium-level microphone access on Linux or Windows). When that happens, the "Open Settings" action fires x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone, which is meaningless outside macOS — either silently failing or opening an unrelated URL. The description text ("in System Settings") is also macOS-specific. Consider hiding the action button or swapping the URL and description to a platform-appropriate value on non-macOS.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/settings/hooks/useSoundRecorder.ts
Line: 124-133

Comment:
**macOS-only deeplink shown on non-macOS platforms**

The `isPermissionError` branch can be reached on any platform (e.g. if the user denies Chromium-level microphone access on Linux or Windows). When that happens, the "Open Settings" action fires `x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone`, which is meaningless outside macOS — either silently failing or opening an unrelated URL. The description text ("in System Settings") is also macOS-specific. Consider hiding the action button or swapping the URL and description to a platform-appropriate value on non-macOS.

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

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants