mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 00:03:08 +00:00
Move notification status helper to Contents/MacOS
On macOS 26, UNUserNotificationCenter aborts when executables are run from Contents/Resources because bundleProxyForCurrentProcess returns nil. Moving the orca-notification-status helper to Contents/MacOS next to the main Electron executable ensures proper bundle resolution and avoids immediate crashes.
This commit is contained in:
@@ -159,7 +159,7 @@ module.exports = {
|
||||
if (context.electronPlatformName === 'darwin') {
|
||||
await signMacComputerUseHelper(join(resourcesDir, 'Orca Computer Use.app'), context.packager)
|
||||
await signMacNotificationStatusHelper(
|
||||
join(resourcesDir, 'orca-notification-status'),
|
||||
join(resourcesDir, '..', 'MacOS', 'orca-notification-status'),
|
||||
context.packager
|
||||
)
|
||||
}
|
||||
@@ -251,11 +251,16 @@ module.exports = {
|
||||
from: 'native/computer-use-macos/.build/release/Orca Computer Use.app',
|
||||
to: 'Orca Computer Use.app'
|
||||
},
|
||||
featureWallResources
|
||||
],
|
||||
// Why: the notification-status helper must execute from Contents/MacOS —
|
||||
// on macOS 26 UNUserNotificationCenter aborts (bundleProxyForCurrentProcess
|
||||
// is nil) for executables launched out of Contents/Resources (#7929).
|
||||
extraFiles: [
|
||||
{
|
||||
from: 'native/notification-status-macos/.build/release/orca-notification-status',
|
||||
to: 'orca-notification-status'
|
||||
},
|
||||
featureWallResources
|
||||
to: 'MacOS/orca-notification-status'
|
||||
}
|
||||
],
|
||||
target: [
|
||||
{
|
||||
|
||||
@@ -63,6 +63,22 @@ describe('electron-builder config', () => {
|
||||
)
|
||||
})
|
||||
|
||||
// Why: on macOS 26 UNUserNotificationCenter aborts for executables launched
|
||||
// from Contents/Resources, so the helper must ship in Contents/MacOS (#7929).
|
||||
it('ships the mac notification-status helper in Contents/MacOS, not Resources', () => {
|
||||
expect(electronBuilderConfig.mac.extraFiles).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
from: 'native/notification-status-macos/.build/release/orca-notification-status',
|
||||
to: 'MacOS/orca-notification-status'
|
||||
})
|
||||
])
|
||||
)
|
||||
expect(electronBuilderConfig.mac.extraResources).not.toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ to: 'orca-notification-status' })])
|
||||
)
|
||||
})
|
||||
|
||||
it('unpacks the compiled CommonJS boundary with CLI runtime files', () => {
|
||||
expect(electronBuilderConfig.asarUnpack).toEqual(
|
||||
expect.arrayContaining(['out/package.json', 'out/cli/**', 'out/shared/**'])
|
||||
|
||||
@@ -12,10 +12,11 @@ let cachedHelperPath: string | null | undefined
|
||||
/**
|
||||
* Resolves the bundled notification-status helper binary.
|
||||
*
|
||||
* Why: the helper must live inside the app bundle — NSBundle resolves the
|
||||
* process's bundle by walking up from the executable path, and macOS keys
|
||||
* notification records to that identity. Both dev copies and packaged builds
|
||||
* place it next to the Electron executable in Contents/MacOS.
|
||||
* Why: the helper must live in Contents/MacOS next to the Electron executable
|
||||
* — NSBundle resolves the process's bundle by walking up from the executable
|
||||
* path, macOS keys notification records to that identity, and macOS 26 aborts
|
||||
* UNUserNotificationCenter for executables run from Contents/Resources
|
||||
* (#7929). Dev copies and packaged builds (extraFiles) both place it there.
|
||||
*/
|
||||
function resolveHelperPath(): string | null {
|
||||
if (cachedHelperPath !== undefined) {
|
||||
@@ -25,14 +26,8 @@ function resolveHelperPath(): string | null {
|
||||
cachedHelperPath = null
|
||||
return cachedHelperPath
|
||||
}
|
||||
// Dev copies place the helper next to the Electron executable; packaged
|
||||
// builds ship it via extraResources. Both are inside the .app, which is
|
||||
// what NSBundle resolution requires.
|
||||
const candidates = [
|
||||
join(dirname(process.execPath), HELPER_EXECUTABLE),
|
||||
...(process.resourcesPath ? [join(process.resourcesPath, HELPER_EXECUTABLE)] : [])
|
||||
]
|
||||
cachedHelperPath = candidates.find((candidate) => existsSync(candidate)) ?? null
|
||||
const candidate = join(dirname(process.execPath), HELPER_EXECUTABLE)
|
||||
cachedHelperPath = existsSync(candidate) ? candidate : null
|
||||
return cachedHelperPath
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user