diff --git a/packages/mcp/test/auto-screenshot.test.ts b/packages/mcp/test/auto-screenshot.test.ts index 8f4c6111..8c16fca5 100644 --- a/packages/mcp/test/auto-screenshot.test.ts +++ b/packages/mcp/test/auto-screenshot.test.ts @@ -83,7 +83,7 @@ describe("shouldAutoScreenshot", () => { }); it("returns false for excluded tools", () => { - expect(shouldAutoScreenshot("list-simulators")).toBe(false); + expect(shouldAutoScreenshot("list-devices")).toBe(false); expect(shouldAutoScreenshot("boot-simulator")).toBe(false); expect(shouldAutoScreenshot("simulator-server")).toBe(false); expect(shouldAutoScreenshot("activate-sso")).toBe(false); diff --git a/packages/skills/skills/argent-ios-profiler/SKILL.md b/packages/skills/skills/argent-ios-profiler/SKILL.md index 0678ab9f..a4724ce6 100644 --- a/packages/skills/skills/argent-ios-profiler/SKILL.md +++ b/packages/skills/skills/argent-ios-profiler/SKILL.md @@ -35,13 +35,20 @@ After presenting findings, ask the user whether to investigate further, implemen **Complete all steps in order — do not break mid-flow.** -### Step 0: Ensure the target app is running +### Step 0: Choose device and ensure the target app is running -The `ios-profiler-start` tool **auto-detects** the running app on the simulator. +**Simulator vs physical device:** Call `list-devices` to find a target device. + +- **Prefer simulators** for fast iteration, CI, and most development workflows. +- **Use a physical device** (`include_physical_devices: true`) when the user explicitly asks for device profiling, or when you need accurate real-world data: CPU/GPU timings, thermal throttling, real memory behavior, or hardware-dependent features (camera, GPS, NFC, push notifications). + +> Physical devices do **not** support automated interaction (taps, swipes, screenshots, describe) — only profiling and debugging tools work. The user must navigate the device by hand. + +The `ios-profiler-start` tool **auto-detects** the running app on the simulator or device. You do not need to derive `app_process` manually — just make sure the app is launched. -1. If the app is already running on the simulator, skip to Step 1 (do not pass `app_process`). -2. If the app is not running, use `launch-app` with the correct bundle ID first. +1. If the app is already running, skip to Step 1 (do not pass `app_process`). +2. If the app is not running on a simulator, use `launch-app` with the correct bundle ID first. On a physical device, ask the user to launch the app. 3. Only pass `app_process` explicitly if the tool reports multiple running user apps and you need to disambiguate. > **Note**: If multiple build flavors are installed (dev, staging, prod), the tool will detect whichever one is currently running. If both are running, it will ask you to specify. diff --git a/packages/skills/skills/argent-react-native-app-workflow/SKILL.md b/packages/skills/skills/argent-react-native-app-workflow/SKILL.md index aa61f1d3..179c4203 100644 --- a/packages/skills/skills/argent-react-native-app-workflow/SKILL.md +++ b/packages/skills/skills/argent-react-native-app-workflow/SKILL.md @@ -135,7 +135,7 @@ Once you discover the correct build/run workflow for a project, **save it to pro | Action | Tool / Command | | -------------------------- | -------------------------------------------------- | -| List devices | `list-simulators` tool | +| List devices | `list-devices` tool | | Boot a simulator | `boot-simulator` tool (pass UDID) | | Launch an app | `launch-app` tool (pass UDID + bundle ID) | | Restart an app | `restart-app` tool (pass UDID + bundle ID) | @@ -210,7 +210,7 @@ If the user's intent is ambiguous (run existing tests, write new tests, or find | Start Metro | `npx react-native start` | | Start Metro (reset cache) | `npx react-native start --reset-cache` | | Run iOS app | `npx react-native run-ios` | -| List simulators | `list-simulators` tool | +| List devices | `list-devices` tool | | Boot simulator | `boot-simulator` tool | | Take screenshot | `screenshot` tool | | Describe screen (a11y tree) | `describe` tool for normal app screens and in-app modals; use `screenshot` only when permission/system overlays are not exposed reliably | diff --git a/packages/skills/skills/argent-simulator-interact/SKILL.md b/packages/skills/skills/argent-simulator-interact/SKILL.md index c11a0bf3..dada58b7 100644 --- a/packages/skills/skills/argent-simulator-interact/SKILL.md +++ b/packages/skills/skills/argent-simulator-interact/SKILL.md @@ -7,7 +7,9 @@ description: Interact with an iOS simulator using argent MCP tools. Use when tap If you delegate simulator tasks to sub-agents, make sure they have MCP permissions. -Use `list-simulators` to find available simulators. **Pick the first result** if specific not specified by user — booted iPhones are listed first. If none are booted, use `boot-simulator` first. +Use `list-devices` to find available simulators. **Pick the first result** if specific not specified by user — booted iPhones are listed first. If none are booted, use `boot-simulator` first. + +> **Physical devices** do not support interaction tools (taps, swipes, screenshots, describe). For physical device workflows, use profiling and debugging tools only — see `argent-ios-profiler` skill. **Load tool schemas before first use.** Gesture tools (`gesture-tap`, `gesture-swipe`, `gesture-pinch`, `gesture-rotate`, `gesture-custom`) may be deferred — their parameter schemas are not loaded until fetched. Always use ToolSearch to load the schemas of all gesture tools you plan to use **before** calling any of them. If you skip this step, parameters may be coerced to strings instead of numbers, causing validation errors. diff --git a/packages/skills/skills/argent-simulator-setup/SKILL.md b/packages/skills/skills/argent-simulator-setup/SKILL.md index e4fdafa6..d1b3b75c 100644 --- a/packages/skills/skills/argent-simulator-setup/SKILL.md +++ b/packages/skills/skills/argent-simulator-setup/SKILL.md @@ -8,7 +8,7 @@ description: Set up and connect to an iOS simulator using argent MCP tools. Use If you delegate simulator tasks to sub-agents, make sure they have MCP permissions. 1. **Find a booted simulator** - Use `list-simulators`. Pick the first result — booted iPhones are listed first. + Use `list-devices`. Pick the first result — booted iPhones are listed first. If none are booted, use `boot-simulator` with the desired UDID. 2. **Verify connection** diff --git a/packages/tool-server/src/blueprints/js-runtime-debugger.ts b/packages/tool-server/src/blueprints/js-runtime-debugger.ts index 27a4596f..c60ce6bb 100644 --- a/packages/tool-server/src/blueprints/js-runtime-debugger.ts +++ b/packages/tool-server/src/blueprints/js-runtime-debugger.ts @@ -153,7 +153,9 @@ export const jsRuntimeDebuggerBlueprint: ServiceBlueprint(); - for (const line of launchctlOutput.split("\n")) { - const match = line.match(/UIKitApplication:([^\[]+)/); - if (match) { - runningBundleIds.add(match[1]); - } - } - - if (runningBundleIds.size === 0) { - throw new Error( - "No running apps detected on the simulator. Launch the app first using `launch-app`, then retry." - ); - } - - // 2. Get installed app metadata - const listAppsOutput = execSync(`xcrun simctl listapps ${udid} | plutil -convert json -o - -`, { - encoding: "utf-8", - }); - - const installedApps: Record = JSON.parse(listAppsOutput); - - // 3. Cross-reference: running user apps - const runningUserApps: AppInfo[] = []; - for (const [, appInfo] of Object.entries(installedApps)) { - if (appInfo.ApplicationType === "User" && runningBundleIds.has(appInfo.CFBundleIdentifier)) { - runningUserApps.push(appInfo); - } - } - - if (runningUserApps.length === 0) { - throw new Error( - "No running user apps detected on the simulator (only system apps are running). Launch the app first using `launch-app`, then retry." - ); - } - - if (runningUserApps.length > 1) { - const appList = runningUserApps - .map( - (a) => - ` - ${a.CFBundleExecutable} (${a.CFBundleIdentifier}${a.CFBundleDisplayName ? `, "${a.CFBundleDisplayName}"` : ""})` - ) - .join("\n"); - throw new Error( - `Multiple user apps are running on the simulator:\n${appList}\nSpecify \`app_process\` with the CFBundleExecutable of the app you want to profile.` - ); - } - - return runningUserApps[0].CFBundleExecutable; -} - export const iosInstrumentsStartTool: ToolDefinition< z.infer, { status: "recording"; pid: number; traceFile: string } @@ -110,7 +52,14 @@ Fails if no app is running on the simulator or xctrace cannot attach to the proc } const templatePath = params.template_path ?? DEFAULT_TEMPLATE_PATH; - const appProcess = params.app_process ?? detectRunningApp(params.device_id); + + let appProcess = params.app_process; + if (!appProcess) { + const isSimulator = await checkIsSimulator(params.device_id); + appProcess = isSimulator + ? detectRunningAppOnSimulator(params.device_id) + : await detectRunningAppOnDevice(params.device_id); + } const debugDir = await getDebugDir(); const timestamp = new Date() diff --git a/packages/tool-server/src/tools/simulator/list-devices.ts b/packages/tool-server/src/tools/simulator/list-devices.ts new file mode 100644 index 00000000..a7b763b4 --- /dev/null +++ b/packages/tool-server/src/tools/simulator/list-devices.ts @@ -0,0 +1,104 @@ +import { execFile } from "node:child_process"; +import { promisify } from "node:util"; +import { z } from "zod"; +import type { ToolDefinition } from "@argent/registry"; +import { listPhysicalDevices } from "../../utils/ios-device"; + +const execFileAsync = promisify(execFile); + +interface SimctlDevice { + udid: string; + name: string; + state: string; + deviceTypeIdentifier: string; + isAvailable: boolean; +} + +interface SimctlOutput { + devices: Record; +} + +const zodSchema = z.object({ + include_physical_devices: z + .boolean() + .optional() + .default(false) + .describe( + "Also scan for physical iOS devices connected via USB or Wi-Fi. Slower (~5s), requires Xcode 15+." + ), +}); + +export const listDevicesTool: ToolDefinition = { + id: "list-devices", + description: [ + "List available iOS devices (simulators and optionally physical devices). Use when you need a UDID or want to see which simulators are Booted vs Shutdown.", + "By default returns only simulators (fast) — each with udid, name, state, runtime, and isAvailable. Set `include_physical_devices: true` to also scan for physical devices connected via USB or Wi-Fi (slower, requires Xcode 15+); physical-device entries additionally include model, osVersion, and connectionType.", + "", + "WHEN TO INCLUDE PHYSICAL DEVICES:", + "- User explicitly asks to run/test on a real device", + "- Task requires device-only hardware: camera, GPS, NFC, Bluetooth, push notifications", + "- Profiling real-world performance (thermal throttling, actual CPU/GPU)", + "- Testing on a specific OS version not available in simulators", + "", + "IMPORTANT LIMITATION: Physical devices do NOT support automated interaction (taps, swipes, screenshots, describe, etc.) — the user must navigate the device by hand. Only profiling and debugging tools work on physical devices.", + "", + "PREFER SIMULATORS for: fast iteration, CI, UI testing, automated interaction, and most development workflows.", + "", + "Fails if Xcode command-line tools are not installed.", + ].join("\n"), + zodSchema, + services: () => ({}), + async execute(_services, params) { + const { include_physical_devices } = params as unknown as z.infer; + + // Always list simulators + const { stdout } = await execFileAsync("xcrun", ["simctl", "list", "devices", "--json"]); + const data: SimctlOutput = JSON.parse(stdout); + + const devices: Record[] = []; + + for (const [runtimeId, runtimeDevices] of Object.entries(data.devices)) { + if (!runtimeId.includes("iOS")) continue; + for (const device of runtimeDevices) { + if (!device.isAvailable) continue; + devices.push({ + type: "simulator", + udid: device.udid, + name: device.name, + state: device.state, + runtime: runtimeId, + isAvailable: device.isAvailable, + }); + } + } + + // Sort simulators: booted first, iPhones before iPads + devices.sort((a, b) => { + const aBooted = a.state === "Booted" ? 0 : 1; + const bBooted = b.state === "Booted" ? 0 : 1; + if (aBooted !== bBooted) return aBooted - bBooted; + const aIpad = (a.name as string).includes("iPad") ? 1 : 0; + const bIpad = (b.name as string).includes("iPad") ? 1 : 0; + return aIpad - bIpad; + }); + + // Optionally scan for physical devices + let physicalDevicesError: string | undefined; + if (include_physical_devices) { + const { devices: physicalDevices, error } = await listPhysicalDevices(); + physicalDevicesError = error; + for (const pd of physicalDevices) { + devices.push({ + type: "physical_device", + udid: pd.udid, + name: pd.name, + model: pd.model, + osVersion: pd.osVersion, + connectionType: pd.connectionType, + }); + } + } + + return physicalDevicesError ? { devices, physicalDevicesError } : { devices }; + }, +}; diff --git a/packages/tool-server/src/tools/simulator/list-simulators.ts b/packages/tool-server/src/tools/simulator/list-simulators.ts deleted file mode 100644 index 90e5f3a5..00000000 --- a/packages/tool-server/src/tools/simulator/list-simulators.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { execFile } from "node:child_process"; -import { promisify } from "node:util"; -import { z } from "zod"; -import type { ToolDefinition } from "@argent/registry"; - -const execFileAsync = promisify(execFile); - -interface SimctlDevice { - udid: string; - name: string; - state: string; - deviceTypeIdentifier: string; - isAvailable: boolean; -} - -interface SimctlOutput { - devices: Record; -} - -const zodSchema = z.object({}); - -export const listSimulatorsTool: ToolDefinition = { - id: "list-simulators", - description: - "List all available iOS simulators with their current state. Use when you need a UDID or want to see which simulators are Booted vs Shutdown. Returns an array of simulators with udid, name, state, runtime, and isAvailable. Fails if Xcode command-line tools are not installed.", - zodSchema, - services: () => ({}), - async execute(_services, _params, _options) { - const { stdout } = await execFileAsync("xcrun", ["simctl", "list", "devices", "--json"]); - const data: SimctlOutput = JSON.parse(stdout); - const simulators: { - udid: string; - name: string; - state: string; - runtime: string; - isAvailable: boolean; - }[] = []; - - for (const [runtimeId, devices] of Object.entries(data.devices)) { - if (!runtimeId.includes("iOS")) continue; - for (const device of devices) { - if (!device.isAvailable) continue; - simulators.push({ - udid: device.udid, - name: device.name, - state: device.state, - runtime: runtimeId, - isAvailable: device.isAvailable, - }); - } - } - - simulators.sort((a, b) => { - const aBooted = a.state === "Booted" ? 0 : 1; - const bBooted = b.state === "Booted" ? 0 : 1; - if (aBooted !== bBooted) return aBooted - bBooted; - const aIpad = a.name.includes("iPad") ? 1 : 0; - const bIpad = b.name.includes("iPad") ? 1 : 0; - return aIpad - bIpad; - }); - - return { simulators }; - }, -}; diff --git a/packages/tool-server/src/utils/ios-device.ts b/packages/tool-server/src/utils/ios-device.ts new file mode 100644 index 00000000..17c9cef1 --- /dev/null +++ b/packages/tool-server/src/utils/ios-device.ts @@ -0,0 +1,317 @@ +import { execFile, execSync } from "node:child_process"; +import { promisify } from "node:util"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import * as crypto from "node:crypto"; + +const execFileAsync = promisify(execFile); + +interface SimctlDevice { + udid: string; + state: string; + isAvailable: boolean; +} + +interface SimctlOutput { + devices: Record; +} + +const simulatorCache = new Map(); + +/** + * Determine whether a UDID belongs to a simulator or a physical device. + * Checks `xcrun simctl list devices --json` — if the UDID is found, it's a simulator. + */ +export async function checkIsSimulator(udid: string): Promise { + const cached = simulatorCache.get(udid); + if (cached !== undefined) return cached; + + const { stdout } = await execFileAsync("xcrun", ["simctl", "list", "devices", "--json"]); + const data: SimctlOutput = JSON.parse(stdout); + + const allUdids = new Set(); + for (const devices of Object.values(data.devices)) { + for (const device of devices) { + allUdids.add(device.udid); + } + } + + const result = allUdids.has(udid); + simulatorCache.set(udid, result); + return result; +} + +interface SimctlAppInfo { + CFBundleExecutable: string; + CFBundleIdentifier: string; + CFBundleDisplayName?: string; + ApplicationType: string; +} + +/** + * Detect the currently running user app on a simulator. + * Cross-references `launchctl list` with `simctl listapps` to find the running app. + * Returns the CFBundleExecutable for use with `xctrace --attach`. + */ +export function detectRunningAppOnSimulator(udid: string): string { + const launchctlOutput = execSync(`xcrun simctl spawn ${udid} launchctl list`, { + encoding: "utf-8", + }); + + const runningBundleIds = new Set(); + for (const line of launchctlOutput.split("\n")) { + const match = line.match(/UIKitApplication:([^\[]+)/); + if (match) { + runningBundleIds.add(match[1]); + } + } + + if (runningBundleIds.size === 0) { + throw new Error( + "No running apps detected on the simulator. Launch the app first using `launch-app`, then retry." + ); + } + + const listAppsOutput = execSync(`xcrun simctl listapps ${udid} | plutil -convert json -o - -`, { + encoding: "utf-8", + }); + + const installedApps: Record = JSON.parse(listAppsOutput); + + const runningUserApps: SimctlAppInfo[] = []; + for (const [, appInfo] of Object.entries(installedApps)) { + if (appInfo.ApplicationType === "User" && runningBundleIds.has(appInfo.CFBundleIdentifier)) { + runningUserApps.push(appInfo); + } + } + + if (runningUserApps.length === 0) { + throw new Error( + "No running user apps detected on the simulator (only system apps are running). Launch the app first using `launch-app`, then retry." + ); + } + + if (runningUserApps.length > 1) { + const appList = runningUserApps + .map( + (a) => + ` - ${a.CFBundleExecutable} (${a.CFBundleIdentifier}${a.CFBundleDisplayName ? `, "${a.CFBundleDisplayName}"` : ""})` + ) + .join("\n"); + throw new Error( + `Multiple user apps are running on the simulator:\n${appList}\nSpecify \`app_process\` with the CFBundleExecutable of the app you want to profile.` + ); + } + + return runningUserApps[0].CFBundleExecutable; +} + +interface DevicectlApp { + bundleIdentifier: string; + name: string; + url: string; + builtByDeveloper: boolean; + removable: boolean; +} + +interface DevicectlProcess { + processIdentifier: number; + executable: string; +} + +interface DevicectlAppsResult { + result: { apps: DevicectlApp[] }; +} + +interface DevicectlProcessesResult { + result: { runningProcesses: DevicectlProcess[] }; +} + +function tmpJsonPath(): string { + return path.join(os.tmpdir(), `argent-devicectl-${crypto.randomUUID()}.json`); +} + +async function readDevicectlJson(tmpFile: string): Promise { + const raw = await fs.promises.readFile(tmpFile, "utf-8"); + return JSON.parse(raw) as T; +} + +/** + * Detect the currently running user app on a physical device using `devicectl`. + * Cross-references installed developer apps with running processes. + * Returns the CFBundleExecutable (process name) for use with `xctrace --attach`. + */ +export async function detectRunningAppOnDevice(udid: string): Promise { + const tmpApps = tmpJsonPath(); + const tmpProcs = tmpJsonPath(); + + try { + // 1. Get installed developer apps + try { + await execFileAsync( + "xcrun", + ["devicectl", "device", "info", "apps", "--device", udid, "--json-output", tmpApps], + { timeout: 15_000 } + ); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + if (msg.includes("ENOENT") || msg.includes("not found")) { + throw new Error( + "Physical device profiling requires Xcode 15+ (devicectl not found). Update Xcode or use a simulator." + ); + } + throw new Error( + `Could not query apps on device. Ensure it is unlocked, connected via USB, and trusted. (${msg})` + ); + } + + const appsData = await readDevicectlJson(tmpApps); + const developerApps = appsData.result.apps.filter((a) => a.builtByDeveloper); + + if (developerApps.length === 0) { + throw new Error( + "No developer apps installed on the device. Install and launch your app first, then retry." + ); + } + + // 2. Get running processes + try { + await execFileAsync( + "xcrun", + ["devicectl", "device", "info", "processes", "--device", udid, "--json-output", tmpProcs], + { timeout: 15_000 } + ); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + throw new Error( + `Could not query running processes on device. Ensure it is unlocked and connected. (${msg})` + ); + } + + const procsData = await readDevicectlJson(tmpProcs); + const processes = procsData.result.runningProcesses; + + // 3. Cross-reference: find running developer apps + const runningApps: { + name: string; + bundleIdentifier: string; + executable: string; + }[] = []; + + for (const app of developerApps) { + // App url: "file:///private/var/containers/Bundle/Application//.app/" + // Process executable: "file:///private/var/containers/Bundle/Application//.app/" + const appUrl = app.url.endsWith("/") ? app.url : `${app.url}/`; + const matchingProc = processes.find( + (p) => p.executable.startsWith(appUrl) && !p.executable.includes(".appex/") + ); + if (matchingProc) { + // Extract executable name: last path component of the process URL + const executableName = matchingProc.executable + .replace(/^file:\/\//, "") + .split("/") + .pop()!; + runningApps.push({ + name: app.name, + bundleIdentifier: app.bundleIdentifier, + executable: executableName, + }); + } + } + + if (runningApps.length === 0) { + throw new Error( + "No running developer apps detected on the device. Launch your app first, then retry." + ); + } + + if (runningApps.length > 1) { + const appList = runningApps + .map((a) => ` - ${a.executable} (${a.bundleIdentifier}, "${a.name}")`) + .join("\n"); + throw new Error( + `Multiple developer apps are running on the device:\n${appList}\nSpecify \`app_process\` with the executable name of the app you want to profile.` + ); + } + + return runningApps[0].executable; + } finally { + await fs.promises.unlink(tmpApps).catch(() => {}); + await fs.promises.unlink(tmpProcs).catch(() => {}); + } +} + +interface DevicectlListDevice { + identifier: string; + hardwareProperties: { + udid: string; + platform: string; + marketingName?: string; + productType?: string; + }; + deviceProperties: { + name: string; + osVersionNumber: string; + bootState?: string; + }; + connectionProperties: { + transportType: string; + pairingState: string; + }; +} + +interface DevicectlListResult { + result: { devices: DevicectlListDevice[] }; +} + +export interface PhysicalDevice { + udid: string; + name: string; + model: string; + osVersion: string; + connectionType: string; +} + +export interface ListPhysicalDevicesResult { + devices: PhysicalDevice[]; + error?: string; +} + +/** + * List physical iOS devices connected to the host via `devicectl`. + * Returns `{ devices: [] }` on success with no devices, or `{ devices: [], error }` + * when devicectl itself fails (e.g. Xcode < 15, device locked/untrusted) so the + * caller can surface the reason instead of silently reporting "no devices". + */ +export async function listPhysicalDevices(): Promise { + const tmpFile = tmpJsonPath(); + try { + await execFileAsync("xcrun", ["devicectl", "list", "devices", "--json-output", tmpFile], { + timeout: 15_000, + }); + + const data = await readDevicectlJson(tmpFile); + + const devices = data.result.devices + .filter((d) => d.hardwareProperties.platform === "iOS") + .map((d) => ({ + udid: d.hardwareProperties.udid, + name: d.deviceProperties.name, + model: d.hardwareProperties.marketingName ?? d.hardwareProperties.productType ?? "Unknown", + osVersion: d.deviceProperties.osVersionNumber, + connectionType: d.connectionProperties.transportType, + })); + + return { devices }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + const hint = + msg.includes("ENOENT") || msg.includes("not found") + ? "devicectl not found — physical device listing requires Xcode 15+." + : `devicectl failed: ${msg}. Ensure the device is unlocked, connected, and trusted.`; + return { devices: [], error: hint }; + } finally { + await fs.promises.unlink(tmpFile).catch(() => {}); + } +} diff --git a/packages/tool-server/src/utils/setup-registry.ts b/packages/tool-server/src/utils/setup-registry.ts index 739457dd..410a8961 100644 --- a/packages/tool-server/src/utils/setup-registry.ts +++ b/packages/tool-server/src/utils/setup-registry.ts @@ -12,7 +12,7 @@ import { nativeUserInteractableViewAtPointTool } from "../tools/native-devtools/ import { jsRuntimeDebuggerBlueprint } from "../blueprints/js-runtime-debugger"; import { networkInspectorBlueprint } from "../blueprints/network-inspector"; import { reactProfilerSessionBlueprint } from "../blueprints/react-profiler-session"; -import { listSimulatorsTool } from "../tools/simulator/list-simulators"; +import { listDevicesTool } from "../tools/simulator/list-devices"; import { createBootSimulatorTool } from "../tools/simulator/boot-simulator"; import { launchAppTool } from "../tools/simulator/launch-app"; import { restartAppTool } from "../tools/simulator/restart-app"; @@ -78,7 +78,7 @@ export function createRegistry(): Registry { registry.registerBlueprint(nativeDevtoolsBlueprint); registry.registerBlueprint(axServiceBlueprint); - registry.registerTool(listSimulatorsTool); + registry.registerTool(listDevicesTool); registry.registerTool(createBootSimulatorTool(registry)); registry.registerTool(launchAppTool); registry.registerTool(restartAppTool);