Skip to content

refactor(7/12): migrate device and macOS tools to event-based handlers#325

Merged
cameroncooke merged 3 commits intomainfrom
refactor/migrate-device-macos-tools
Apr 10, 2026
Merged

refactor(7/12): migrate device and macOS tools to event-based handlers#325
cameroncooke merged 3 commits intomainfrom
refactor/migrate-device-macos-tools

Conversation

@cameroncooke
Copy link
Copy Markdown
Collaborator

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-settings

macOS tools: build_macos, build_run_macos, get_mac_app_path, launch_mac_app, stop_mac_app, test_macos

Notable changes

  • test_device.ts and test_macos.ts were the most complex handlers (~250-280 lines each). They've been significantly simplified by delegating to test-preflight.ts, device-steps.ts/macos-steps.ts, and xcodebuild-pipeline.ts from PR 4. The handlers are now thin orchestrators that emit events.
  • Device and macOS build tools pass ctx.emit through to the xcodebuild pipeline for real-time progress streaming.
  • stop_app_device.ts and stop_mac_app.ts updated to emit structured events for process termination results.

Stack navigation

  • PR 1-5/12: Foundation, utilities, runtime contract
  • PR 6/12: Simulator tool migrations
  • PR 7/12 (this PR): Device + macOS tool migrations
  • PR 8/12: UI automation tool migrations
  • PR 9/12: Remaining tool migrations
  • PR 10-12/12: Boundaries, config, tests

Test plan

  • npx vitest run passes -- all device and macOS tool tests updated
  • Build tools stream progress events through the xcodebuild pipeline
  • Test tools correctly delegate to test-preflight and platform step modules

@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from daf00b3 to d9e9216 Compare April 8, 2026 21:29
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from ae0e2ac to 6eabc79 Compare April 8, 2026 21:29
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from d9e9216 to 90f6699 Compare April 9, 2026 07:49
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch 2 times, most recently from 2a18f34 to a3b5afd Compare April 9, 2026 07:59
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from 90f6699 to 6ad5269 Compare April 9, 2026 07:59
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from 6ad5269 to c6bb094 Compare April 9, 2026 08:45
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from a3b5afd to 7558ea2 Compare April 9, 2026 08:45
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from ea1dcfb to c4d9441 Compare April 9, 2026 10:39
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from 6bf61bc to 3036639 Compare April 9, 2026 10:39
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from c802970 to f5b95e6 Compare April 9, 2026 11:48
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from 106a7dc to f7bde95 Compare April 9, 2026 11:48
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from f5b95e6 to 3a2b3da Compare April 9, 2026 12:03
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from f7bde95 to c18c941 Compare April 9, 2026 12:03
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from 3a2b3da to 9f921b2 Compare April 9, 2026 14:43
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from c18c941 to 1b4e244 Compare April 9, 2026 14:43
logPrefix: `${platform} Device Build`,
};

const deviceName = resolveDeviceName(params.deviceId);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from 1b4e244 to 732814d Compare April 9, 2026 15:15
@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch 2 times, most recently from 25b8d8d to 8d84711 Compare April 9, 2026 15:40
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from 732814d to 54730dd Compare April 9, 2026 15:40
Comment on lines +342 to +345
ctx.nextStepParams = {
build_device: { scheme: 'YOUR_SCHEME', deviceId: 'UUID_FROM_ABOVE' },
install_app_device: { deviceId: 'UUID_FROM_ABOVE', appPath: 'PATH_TO_APP' },
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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' },
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8f6c4c7. Configure here.

@cameroncooke cameroncooke force-pushed the refactor/migrate-simulator-tools branch from 063044a to 7735495 Compare April 10, 2026 07:36
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from 8f6c4c7 to 28186ae Compare April 10, 2026 07:36
Copy link
Copy Markdown
Collaborator Author

cameroncooke commented Apr 10, 2026

Merge activity

  • Apr 10, 12:18 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 10, 12:25 PM UTC: Graphite rebased this pull request as part of a merge.
  • Apr 10, 12:25 PM UTC: @cameroncooke merged this pull request with Graphite.

@cameroncooke cameroncooke changed the base branch from refactor/migrate-simulator-tools to graphite-base/325 April 10, 2026 12:22
@cameroncooke cameroncooke changed the base branch from graphite-base/325 to main April 10, 2026 12:23
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
@cameroncooke cameroncooke force-pushed the refactor/migrate-device-macos-tools branch from 28186ae to 64513a8 Compare April 10, 2026 12:24
@cameroncooke cameroncooke merged commit 7317fb4 into main Apr 10, 2026
11 of 12 checks passed
@cameroncooke cameroncooke deleted the refactor/migrate-device-macos-tools branch April 10, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant