refactor(7/12): migrate device and macOS tools to event-based handlers#325
refactor(7/12): migrate device and macOS tools to event-based handlers#325cameroncooke merged 3 commits intomainfrom
Conversation
daf00b3 to
d9e9216
Compare
ae0e2ac to
6eabc79
Compare
d9e9216 to
90f6699
Compare
2a18f34 to
a3b5afd
Compare
90f6699 to
6ad5269
Compare
6ad5269 to
c6bb094
Compare
a3b5afd to
7558ea2
Compare
c6bb094 to
ea1dcfb
Compare
7558ea2 to
6bf61bc
Compare
ea1dcfb to
c4d9441
Compare
6bf61bc to
3036639
Compare
c802970 to
f5b95e6
Compare
106a7dc to
f7bde95
Compare
f5b95e6 to
3a2b3da
Compare
f7bde95 to
c18c941
Compare
3a2b3da to
9f921b2
Compare
c18c941 to
1b4e244
Compare
| logPrefix: `${platform} Device Build`, | ||
| }; | ||
|
|
||
| const deviceName = resolveDeviceName(params.deviceId); |
There was a problem hiding this comment.
Bug: The use of execSync in device name resolution functions blocks the Node.js event loop, causing the application to hang for up to 10 seconds.
Severity: HIGH
Suggested Fix
Replace the synchronous execSync call in device-name-resolver.ts with an asynchronous alternative, such as exec or spawn from the child_process module. This will prevent the event loop from being blocked while waiting for the external command to complete. Ensure the asynchronous implementation properly handles stdout, stderr, and potential errors.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: src/mcp/tools/device/build_run_device.ts#L111
Potential issue: The functions `formatDeviceId` and `resolveDeviceName` use `execSync`
to run an external command (`xcrun devicectl list devices`). This is a synchronous,
blocking call that will freeze the Node.js event loop for up to its 10-second timeout.
While a 30-second cache mitigates repeated blocking, the first call to any affected
device tool, or any call after the cache expires, will cause the application to hang.
This behavior violates the project's own coding standards, which ban `execSync` in
production code due to its severe performance implications.
There was a problem hiding this comment.
Valid concern, tracked in #333. Low priority given the 10s timeout, 30s TTL cache, and the MCP server's single-request-at-a-time model.
1b4e244 to
732814d
Compare
25b8d8d to
8d84711
Compare
732814d to
54730dd
Compare
8d84711 to
a7d936d
Compare
54730dd to
30ef514
Compare
| ctx.nextStepParams = { | ||
| build_device: { scheme: 'YOUR_SCHEME', deviceId: 'UUID_FROM_ABOVE' }, | ||
| install_app_device: { deviceId: 'UUID_FROM_ABOVE', appPath: 'PATH_TO_APP' }, | ||
| }; |
There was a problem hiding this comment.
Bug: ctx.nextStepParams is set unconditionally in list_devicesLogic, suggesting follow-up actions even when no devices are found or an error occurs.
Severity: MEDIUM
Suggested Fix
Reintroduce a conditional check before setting ctx.nextStepParams. The assignment should only happen if the availableDevices array is not empty, mirroring the logic that was present before the refactoring.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: src/mcp/tools/device/list_devices.ts#L342-L345
Potential issue: In the `list_devicesLogic` function, `ctx.nextStepParams` is set
unconditionally. This occurs even when no devices are found or when an error is
encountered during the device listing process. This is a regression from the previous
implementation, where this assignment was guarded by a condition checking for the
existence of available devices. Consequently, the client will be misled into suggesting
follow-up actions like `build_device` when no devices are actually available, degrading
the user experience and potentially causing errors for automated clients.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8f6c4c7. Configure here.
| ctx.nextStepParams = { | ||
| build_device: { scheme: 'YOUR_SCHEME', deviceId: 'UUID_FROM_ABOVE' }, | ||
| install_app_device: { deviceId: 'UUID_FROM_ABOVE', appPath: 'PATH_TO_APP' }, | ||
| }; |
There was a problem hiding this comment.
Unconditional nextStepParams assignment breaks conditional behavior
Medium Severity
ctx.nextStepParams is set unconditionally after buildEvents() completes, but the old code only set nextStepParams when availableDevicesExist was true. This means next-step hints are now provided even when no devices are found or all devices are unavailable, which is misleading. The test at line 219 expects nextStepParams to be undefined, confirming the intended conditional behavior was lost during migration.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 8f6c4c7. Configure here.
063044a to
7735495
Compare
8f6c4c7 to
28186ae
Compare
Merge activity
|
Replace 7 identical local runLogic definitions with the shared import from test-helpers.ts.
…arams - Remove unused re-exports from build-settings.ts barrel - Remove unreachable "Available (WiFi)" check from isAvailableState - Add ctx.nextStepParams to list_devices for consistency with list_sims
28186ae to
64513a8
Compare



Summary
This is PR 7 of 12 in a stacked PR series that decouples the rendering pipeline from MCP transport. Depends on PR 6 (simulator migrations).
Migrates all device and macOS tool handlers to the new event-based handler contract. Same mechanical transformation pattern as PR 6 but for physical device and macOS desktop targets.
Tools migrated (31 files)
Device tools:
build_device,build_run_device,get_device_app_path,install_app_device,launch_app_device,list_devices,stop_app_device,test_device,build-settingsmacOS tools:
build_macos,build_run_macos,get_mac_app_path,launch_mac_app,stop_mac_app,test_macosNotable changes
test_device.tsandtest_macos.tswere the most complex handlers (~250-280 lines each). They've been significantly simplified by delegating totest-preflight.ts,device-steps.ts/macos-steps.ts, andxcodebuild-pipeline.tsfrom PR 4. The handlers are now thin orchestrators that emit events.ctx.emitthrough to the xcodebuild pipeline for real-time progress streaming.stop_app_device.tsandstop_mac_app.tsupdated to emit structured events for process termination results.Stack navigation
Test plan
npx vitest runpasses -- all device and macOS tool tests updated