From 10c60ce44ad3c00686a0607308c28c38ace42efc Mon Sep 17 00:00:00 2001 From: mcjjin <8590489+mcjjin@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:56:49 +0000 Subject: [PATCH 1/4] docs: update contributors --- contributors.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributors.svg b/contributors.svg index 5370a1222..eba9cc29a 100644 --- a/contributors.svg +++ b/contributors.svg @@ -13,7 +13,7 @@ - + From 822c761d9183fcd9e26a3e6ff863ad551ce77a12 Mon Sep 17 00:00:00 2001 From: kobefeng Date: Mon, 6 Apr 2026 22:43:28 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix(computer-use):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=A3=80=E6=9F=A5=E5=92=8C=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E8=8E=B7=E5=8F=96=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 macOS 平台下权限检查的 JXA 回退逻辑,确保在没有原生模块时仍能正确检测权限 改进应用列表获取方式,使用 mdls 获取真实的 bundleId 而非生成伪 ID --- .../computer-use-swift/src/backends/darwin.ts | 44 ++++++++++------- src/utils/computerUse/escHotkey.ts | 6 +-- src/utils/computerUse/hostAdapter.ts | 47 ++++++++++++++++++- 3 files changed, 74 insertions(+), 23 deletions(-) diff --git a/packages/@ant/computer-use-swift/src/backends/darwin.ts b/packages/@ant/computer-use-swift/src/backends/darwin.ts index 620f162a9..6e3c24933 100644 --- a/packages/@ant/computer-use-swift/src/backends/darwin.ts +++ b/packages/@ant/computer-use-swift/src/backends/darwin.ts @@ -159,25 +159,33 @@ export const apps: AppsAPI = { async listInstalled() { try { - const result = await osascript(` - tell application "System Events" - set appList to "" - repeat with appFile in (every file of folder "Applications" of startup disk whose name ends with ".app") - set appPath to POSIX path of (appFile as alias) - set appName to name of appFile - set appList to appList & appPath & "|" & appName & "\\n" - end repeat - return appList - end tell - `) - return result.split('\n').filter(Boolean).map(line => { - const [path, name] = line.split('|', 2) - const displayName = (name ?? '').replace(/\.app$/, '') - return { - bundleId: `com.app.${displayName.toLowerCase().replace(/\s+/g, '-')}`, - displayName, - path: path ?? '', + // Use mdls to enumerate apps and get real bundle identifiers. + // The previous AppleScript approach generated fake bundle IDs + // (com.app.display-name) which prevented request_access from matching + // apps by their real bundle ID (e.g. com.google.Chrome). + const dirs = ['/Applications', '~/Applications', '/System/Applications'] + const allApps: InstalledApp[] = [] + for (const dir of dirs) { + const expanded = dir.startsWith('~') ? join(process.env.HOME ?? '~', dir.slice(1)) : dir + const proc = Bun.spawn( + ['bash', '-c', `for f in "${expanded}"/*.app; do [ -d "$f" ] || continue; bid=$(mdls -name kMDItemCFBundleIdentifier "$f" 2>/dev/null | sed 's/.*= "//;s/"//'); name=$(basename "$f" .app); echo "$f|$name|$bid"; done`], + { stdout: 'pipe', stderr: 'pipe' }, + ) + const text = await new Response(proc.stdout).text() + await proc.exited + for (const line of text.split('\n').filter(Boolean)) { + const [path, displayName, bundleId] = line.split('|', 3) + if (path && displayName && bundleId && bundleId !== '(null)') { + allApps.push({ bundleId, displayName, path }) + } } + } + // Deduplicate by bundleId (prefer /Applications over ~/Applications) + const seen = new Set() + return allApps.filter(app => { + if (seen.has(app.bundleId)) return false + seen.add(app.bundleId) + return true }) } catch { return [] diff --git a/src/utils/computerUse/escHotkey.ts b/src/utils/computerUse/escHotkey.ts index 24ba17cc4..f58bdff0f 100644 --- a/src/utils/computerUse/escHotkey.ts +++ b/src/utils/computerUse/escHotkey.ts @@ -26,7 +26,7 @@ export function registerEscHotkey(onEscape: () => void): boolean { if (process.platform !== 'darwin') return false if (registered) return true const cu = requireComputerUseSwift() - if (!(cu as any).hotkey.registerEscape(onEscape)) { + if (!(cu as any).hotkey?.registerEscape(onEscape)) { // CGEvent.tapCreate failed — typically missing Accessibility permission. // CU still works, just without ESC abort. Mirrors Cowork's escAbort.ts:81. logForDebugging('[cu-esc] registerEscape returned false', { level: 'warn' }) @@ -41,7 +41,7 @@ export function registerEscHotkey(onEscape: () => void): boolean { export function unregisterEscHotkey(): void { if (!registered) return try { - (requireComputerUseSwift() as any).hotkey.unregister() + (requireComputerUseSwift() as any).hotkey?.unregister() } finally { releasePump() registered = false @@ -51,5 +51,5 @@ export function unregisterEscHotkey(): void { export function notifyExpectedEscape(): void { if (!registered) return - (requireComputerUseSwift() as any).hotkey.notifyExpectedEscape() + (requireComputerUseSwift() as any).hotkey?.notifyExpectedEscape() } diff --git a/src/utils/computerUse/hostAdapter.ts b/src/utils/computerUse/hostAdapter.ts index acefbaa3d..ae99d0b18 100644 --- a/src/utils/computerUse/hostAdapter.ts +++ b/src/utils/computerUse/hostAdapter.ts @@ -27,6 +27,38 @@ class DebugLogger implements Logger { } } +// --------------------------------------------------------------------------- +// JXA-based TCC permission probes (fallback when native .node module absent) +// --------------------------------------------------------------------------- + +/** Probe accessibility by asking System Events for a process list. */ +function checkAccessibilityJXA(): boolean { + try { + const result = Bun.spawnSync({ + cmd: ['osascript', '-e', 'tell application "System Events" to get name of every process whose background only is false'], + stdout: 'pipe', + stderr: 'pipe', + }) + return result.exitCode === 0 + } catch { + return false + } +} + +/** Probe screen recording by attempting a 1x1 screencapture. */ +function checkScreenRecordingJXA(): boolean { + try { + const result = Bun.spawnSync({ + cmd: ['screencapture', '-x', '-R', '0,0,1,1', '/dev/null'], + stdout: 'pipe', + stderr: 'pipe', + }) + return result.exitCode === 0 + } catch { + return false + } +} + let cached: ComputerUseHostAdapter | undefined /** @@ -47,8 +79,19 @@ export function getComputerUseHostAdapter(): ComputerUseHostAdapter { ensureOsPermissions: async () => { if (process.platform !== 'darwin') return { granted: true } const cu = requireComputerUseSwift() - const accessibility = (cu as any).tcc.checkAccessibility() - const screenRecording = (cu as any).tcc.checkScreenRecording() + const tcc = (cu as any).tcc + // Native Swift .node module provides tcc.checkAccessibility/checkScreenRecording. + // When absent (decompiled/reverse-engineered build), fall back to JXA probes. + if (tcc) { + const accessibility = tcc.checkAccessibility() + const screenRecording = tcc.checkScreenRecording() + return accessibility && screenRecording + ? { granted: true } + : { granted: false, accessibility, screenRecording } + } + // JXA fallback: try to query System Events (accessibility) and screencapture (screen recording). + const accessibility = checkAccessibilityJXA() + const screenRecording = checkScreenRecordingJXA() return accessibility && screenRecording ? { granted: true } : { granted: false, accessibility, screenRecording } From 3b16eba3c2332ab840bc2bc9c5eab32fa5296473 Mon Sep 17 00:00:00 2001 From: mcjjin <8590489+mcjjin@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:44:54 +0000 Subject: [PATCH 3/4] docs: update contributors --- contributors.svg | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/contributors.svg b/contributors.svg index eba9cc29a..da7b7feca 100644 --- a/contributors.svg +++ b/contributors.svg @@ -20,15 +20,17 @@ + + - + - + - + - + - + \ No newline at end of file From 8a153b6ec3374dd38249109d5f3ae024919c5ec5 Mon Sep 17 00:00:00 2001 From: mcjjin <8590489+mcjjin@users.noreply.github.com> Date: Tue, 7 Apr 2026 02:35:28 +0000 Subject: [PATCH 4/4] docs: update contributors --- contributors.svg | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/contributors.svg b/contributors.svg index da7b7feca..76dd6eacb 100644 --- a/contributors.svg +++ b/contributors.svg @@ -10,18 +10,18 @@ - - + + + + - + - + - - - +