fix(terminal): terminal mic access (#1018)

* release: 1.3.8-rc.3 [rc-slot:2026-04-21-15]

* release: 1.3.8-rc.4 [rc-slot:2026-04-22-15]

* release: 1.3.8-rc.5 [rc-slot:2026-04-23-15]

* fix(mac): enable microphone permission popup for embedded terminal [Fixes 1009]

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Jingyue Wu 2026-04-24 15:36:05 -04:00 committed by GitHub
parent 517ce93d38
commit 9ca6314692
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 3 deletions

View File

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>

View File

@ -1,4 +1,4 @@
import { app, BrowserWindow, nativeImage, nativeTheme } from 'electron'
import { app, BrowserWindow, nativeImage, nativeTheme, systemPreferences } from 'electron'
import { electronApp, is } from '@electron-toolkit/utils'
import devIcon from '../../resources/icon-dev.png?asset'
import { Store, initDataPath } from './persistence'
@ -54,6 +54,26 @@ let rateLimits: RateLimitService | null = null
let runtimeRpc: OrcaRuntimeRpcServer | null = null
let starNag: StarNagService | null = null
function triggerStartupMicrophoneRegistration(): void {
if (process.platform !== 'darwin') {
return
}
try {
const status = systemPreferences.getMediaAccessStatus('microphone')
if (status !== 'not-determined') {
return
}
// Why: terminal child processes (sox/ffmpeg/voice CLIs) cannot reliably
// surface the TCC dialog themselves. Prompt once from the app process after
// the window is visible so mic capture in embedded terminals can work.
void systemPreferences.askForMediaAccess('microphone').catch((error: unknown) => {
console.error('[permissions] Failed to request microphone access:', error)
})
} catch (error) {
console.error('[permissions] Failed to check microphone access status:', error)
}
}
installUncaughtPipeErrorGuard()
// Why: propagate the Orca app version into `process.env` so PTY-env
// construction in both main (local-pty-provider) and the forked daemon
@ -242,6 +262,7 @@ app.whenReady().then(async () => {
// window, making it impossible for the user to click "Allow".
win.once('show', () => {
triggerStartupNotificationRegistration(store!)
triggerStartupMicrophoneRegistration()
})
app.on('activate', () => {

View File

@ -155,6 +155,7 @@ export function useDiffCommentDecorator({
})
disposablesRef.current = [onMouseMove, onMouseLeave, onScroll]
const zones = zonesRef.current
return () => {
for (const d of disposablesRef.current) {
@ -169,10 +170,10 @@ export function useDiffCommentDecorator({
// stale zone ids from a dead editor. The diff effect below deliberately
// has no cleanup so comment-only changes don't cause a full zone
// rebuild; this cleanup is the single place we reset zone tracking.
for (const entry of zonesRef.current.values()) {
for (const entry of zones.values()) {
entry.root.unmount()
}
zonesRef.current.clear()
zones.clear()
}
}, [editor])