mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 09:57:48 +00:00
fix(emulator): make iPhone Duo fold work in release builds and show serve-sim's real error (#41051)
* fix(emulator): let iPhone Duo fold in release builds Release signing gave serve-sim's in-simulator helpers the hardened runtime, which drops the DYLD_ROOT_PATH that simctl spawn hands them, so the Duo HID and accessibility helpers aborted at launch. Sign just those two with only allow-dyld-environment-variables. serve-sim's uncaught errors print its minified source, which contains the "No serve-sim server running" text, so every crash was reported as no active emulator. Report the thrown error line instead. Fixes #40509 * fix(emulator): keep multi-line serve-sim error messages * refactor(emulator): simplify serve-sim failure message parsing
This commit is contained in:
@@ -1,8 +1,21 @@
|
||||
import { createRequire } from 'node:module'
|
||||
|
||||
// serve-sim launches these with `simctl spawn`, whose DYLD_ROOT_PATH the hardened runtime drops (#40509).
|
||||
const IOS_SIMULATOR_HELPER_PATHS = [
|
||||
'/node_modules/serve-sim/dist/simduo/serve-sim-duo-hid',
|
||||
'/node_modules/serve-sim/dist/simax/serve-sim-ax-settings'
|
||||
]
|
||||
const IOS_SIMULATOR_HELPER_ENTITLEMENTS = ['com.apple.security.cs.allow-dyld-environment-variables']
|
||||
|
||||
export function signMacApp(options, { sign, retry }) {
|
||||
const optionsForFile = (filePath, context) => {
|
||||
const fileOptions = options.optionsForFile?.(filePath, context)
|
||||
return IOS_SIMULATOR_HELPER_PATHS.some((helperPath) => filePath.endsWith(helperPath))
|
||||
? { ...fileOptions, entitlements: IOS_SIMULATOR_HELPER_ENTITLEMENTS }
|
||||
: fileOptions
|
||||
}
|
||||
// A custom signer bypasses electron-builder's retry wrapper.
|
||||
return retry(() => sign({ ...options, batchCodesignCalls: true }), {
|
||||
return retry(() => sign({ ...options, optionsForFile, batchCodesignCalls: true }), {
|
||||
retries: 3,
|
||||
interval: 5000,
|
||||
backoff: 5000
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { expect, it, vi } from 'vitest'
|
||||
|
||||
const { runProcessMock } = vi.hoisted(() => ({ runProcessMock: vi.fn() }))
|
||||
|
||||
vi.mock('@orca/process-host', () => ({ runProcess: runProcessMock }))
|
||||
|
||||
import { execServeSimCommand } from './serve-sim-execution'
|
||||
|
||||
// Shape of serve-sim 0.1.47's real `fold 180 -d <udid> -q` crash: the minified source line holds
|
||||
// the "No serve-sim server running" text of every other command (#40509).
|
||||
const UNCAUGHT_FOLD_FAILURE = `file:///Users/me/Library/Application Support/orca/serve-sim-runtime/1.4.255/node_modules/serve-sim/dist/serve-sim.js:161
|
||||
Shutting down...\`);async function GG($,Q){let Z=s(Q);if(!Z)console.error("No serve-sim server running. Run \`serve-sim\` first."),process.exit(1);let J=await C5(Z.wsUrl)}
|
||||
|
||||
|
||||
Error: Simulator rejected the fold. An iPhone Duo with guest HID support is required.
|
||||
at J.onmessage (file:///Users/me/Library/Application Support/orca/serve-sim-runtime/1.4.255/node_modules/serve-sim/dist/serve-sim.js:161:6107)
|
||||
at callListener (/Users/me/node_modules/ws/lib/event-target.js:290:14)
|
||||
|
||||
Node.js v24.22.1
|
||||
`
|
||||
|
||||
it('reports the thrown serve-sim error instead of no active emulator', async () => {
|
||||
runProcessMock.mockResolvedValueOnce({
|
||||
code: 1,
|
||||
signal: null,
|
||||
stdout: '',
|
||||
stderr: UNCAUGHT_FOLD_FAILURE,
|
||||
timedOut: false
|
||||
})
|
||||
await expect(
|
||||
execServeSimCommand({ command: 'serve-sim', baseArgs: [], usesElectronAsNode: false }, [
|
||||
'fold',
|
||||
'180'
|
||||
])
|
||||
).rejects.toMatchObject({
|
||||
code: 'emulator_error',
|
||||
message: 'Error: Simulator rejected the fold. An iPhone Duo with guest HID support is required.'
|
||||
})
|
||||
})
|
||||
@@ -171,6 +171,12 @@ export function stripEmulatorTargetArgs(args: string[]): string[] {
|
||||
return stripped
|
||||
}
|
||||
|
||||
function serveSimFailureMessage(output: string): string {
|
||||
// Uncaught throws print serve-sim's minified source (every CLI message) first; keep the thrown error.
|
||||
const thrown = /^\w*Error: [\s\S]*?(?=^\s+at |^Node\.js v)/m.exec(output)
|
||||
return thrown?.[0].trim() || output.trim() || 'serve-sim command failed'
|
||||
}
|
||||
|
||||
export async function execServeSimCommand(
|
||||
executable: ServeSimExecutable,
|
||||
args: string[],
|
||||
@@ -198,9 +204,9 @@ export async function execServeSimCommand(
|
||||
)
|
||||
}
|
||||
if (result.code !== 0 || result.timedOut) {
|
||||
const message = result.stdout || result.stderr || 'serve-sim command failed'
|
||||
const message = serveSimFailureMessage(result.stdout || result.stderr)
|
||||
// Why: serve-sim also says "not running" for a missing camera helper; that needs its own message.
|
||||
if (/no serve-sim server/i.test(message)) {
|
||||
if (/^no serve-sim server/im.test(message)) {
|
||||
throw new EmulatorError(
|
||||
'emulator_no_active',
|
||||
'No active emulator for this worktree — use orca emulator devices/attach or open the pane'
|
||||
|
||||
Reference in New Issue
Block a user