@mgcrea/mcp-ios-simulator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-C1TH-p-c.js","names":["IosError","IosError","IosError","IosError","IosError"],"sources":["../src/build-info.ts","../src/client/errors.ts","../src/client/display.ts","../src/client/shape.ts","../src/client/simctl.ts","../src/client/simulator.ts","../src/tools/util.ts","../src/tools/apps.ts","../src/tools/diagnostics.ts","../src/tools/environment.ts","../src/tools/lifecycle.ts","../src/tools/runner.ts","../src/tools/index.ts","../src/server.ts","../src/config.ts"],"sourcesContent":["// Build-time / runtime identity for the running server. `name`/`version` are\n// read from package.json at startup (always accurate); `gitCommit` /\n// `gitCommitDate` are injected by tsdown's `define` substitution at build time\n// and fall back to \"unknown\" when running from source (e.g. vitest).\n\nimport { readFileSync } from \"node:fs\";\n\n// oxlint-disable no-underscore-dangle -- bundler-injected build-time constants.\ndeclare const __GIT_COMMIT__: string;\ndeclare const __GIT_COMMIT_DATE__: string;\n\ntype PackageJson = { name: string; version: string };\n\nconst readPackageJson = (): PackageJson => {\n try {\n const pkgUrl = new URL(\"../package.json\", import.meta.url);\n return JSON.parse(readFileSync(pkgUrl, \"utf8\")) as PackageJson;\n } catch {\n return { name: \"@mgcrea/mcp-ios-device\", version: \"0.0.0\" };\n }\n};\n\nconst pkg = readPackageJson();\n\nexport type BuildInfo = {\n name: string;\n version: string;\n gitCommit: string;\n gitCommitDate: string;\n};\n\nexport const BUILD_INFO: BuildInfo = {\n name: pkg.name,\n version: pkg.version,\n gitCommit: typeof __GIT_COMMIT__ === \"string\" ? __GIT_COMMIT__ : \"unknown\",\n gitCommitDate: typeof __GIT_COMMIT_DATE__ === \"string\" ? __GIT_COMMIT_DATE__ : \"unknown\",\n};\n","import { IosError } from \"@mgcrea/mcp-ios-core\";\n\nexport {\n CommandError,\n CommandTimeoutError,\n IosError,\n ToolchainError,\n WdaError,\n WdaUnavailableError,\n} from \"@mgcrea/mcp-ios-core\";\n\n/** Raising the budget, or noticing the simulator died mid-call. */\nexport const TIMEOUT_REMEDY =\n \"Raise IOS_SIMULATOR_TIMEOUT_MS if this is a slow operation (a boot or a large `install` \" +\n \"genuinely takes tens of seconds), or check the simulator is still booted.\";\n\nexport const TOOLCHAIN_REMEDY =\n \"Install Xcode and run `xcode-select --install`, or point IOS_SIMULATOR_XCRUN_PATH at a \" +\n \"different xcrun.\";\n\n/**\n * How to get the runner up. Much shorter than the device server's equivalent,\n * and that is the headline difference between the two: a simulator runner needs\n * no Apple team, no signing, no trust prompt and no tunnel.\n */\nexport const START_RUNNER_REMEDY =\n \"Build and start the runner with `scripts/wda.sh setup` then `scripts/wda.sh run` (or \" +\n \"`npx -p @mgcrea/mcp-ios-simulator ios-simulator-wda run` from an npm install) and leave it \" +\n \"open — the HTTP server is the XCTest process, so it stops when that command does. It needs no \" +\n \"Apple Developer team: a simulator build is not signed.\";\n\n/** What to do when WebDriverAgent does not answer at all. */\nexport const WDA_UNAVAILABLE_REMEDY =\n `${START_RUNNER_REMEDY} Everything except ios_simulator_ui_tree and the input tools works ` +\n \"without it — screenshots go through simctl. If something else already forwards the port, set \" +\n \"IOS_SIMULATOR_WDA_URL.\";\n\n/** No simulator matched, or several did and none was named. */\nexport class SimulatorNotFoundError extends IosError {\n override readonly name = \"SimulatorNotFoundError\";\n\n constructor(message: string, remedy: string) {\n super(message, { remedy });\n }\n}\n\n/**\n * The simulator exists but is shut down.\n *\n * Its own error class because the fix is a single specific call and nothing\n * else: almost every simctl subcommand fails this way, `listapps` included, so\n * \"it is shut down\" would otherwise be buried in a CoreSimulator envelope that\n * reads like a lookup bug.\n */\nexport class SimulatorNotBootedError extends IosError {\n override readonly name = \"SimulatorNotBootedError\";\n\n constructor(name: string, udid: string) {\n super(`${name} is shut down.`, {\n remedy:\n `Boot it with ios_simulator_power {\"simulator\":\"${udid}\",\"state\":\"booted\"} — this server ` +\n \"never boots a simulator implicitly, because a cold boot takes tens of seconds and puts a \" +\n \"window on the user's screen.\",\n });\n }\n}\n\n/**\n * The simulator's runtime is not installed, so CoreSimulator cannot service it.\n *\n * Worth its own class because the failure it prevents is not an error message\n * at all: `simctl io` against one of these aborts with an uncaught\n * NSInternalInconsistencyException and a thirty-line stack trace.\n */\nexport class RuntimeUnavailableError extends IosError {\n override readonly name = \"RuntimeUnavailableError\";\n\n constructor(name: string, reason: string | undefined) {\n super(`${name} is unavailable${reason ? `: ${reason}` : \".\"}`, {\n remedy:\n \"The iOS runtime this simulator was created against is not installed. Install it in \" +\n \"Xcode > Settings > Components, or clear the orphans with `xcrun simctl delete unavailable`.\",\n });\n }\n}\n\n/** Thrown when a write path is reached while IOS_SIMULATOR_ALLOW_WRITES is off. */\nexport class WritesDisabledError extends IosError {\n override readonly name = \"WritesDisabledError\";\n\n constructor(what: string) {\n super(\n `${what} changes the simulator, but writes are disabled. ` +\n \"Unset IOS_SIMULATOR_ALLOW_WRITES (it defaults to on) to enable them again.\",\n );\n }\n}\n\n/** A shut-down simulator captures nothing, and that is the usual cause here. */\nexport const EMPTY_SCREENSHOT_REMEDY =\n \"The simulator produced an empty capture. Check it is actually booted with \" +\n \"ios_simulator_diagnostics, and that its runtime is installed.\";\n","import { join } from \"node:path\";\n\nimport type { DisplayInfo, ExecImpl } from \"@mgcrea/mcp-ios-core\";\n\nimport { IosError } from \"#/client/errors\";\nimport type { RawDeviceType } from \"#/client/simctl\";\n\n/**\n * Screen geometry for a simulator, which has no `devicectl device info displays`.\n *\n * Three sources were measured, and the split between them is the interesting\n * part:\n *\n * - **`profile.plist`, per device type.** `mainScreenWidth`, `mainScreenHeight`\n * and `mainScreenScale`, agreeing exactly with both `io enumerate` and the\n * captured PNG. A pure file read: no simctl call, nothing to boot, and no\n * crash surface on an unavailable simulator. This is where `pointScale`\n * comes from.\n * - **The captured PNG's own header.** This is where *pixels* come from\n * whenever there is a capture, because `simctl io … screenConfig geometry`\n * can resize a booted simulator's screen at runtime and the profile would\n * then be silently wrong — putting every tap coordinate in the wrong space\n * with nothing looking wrong.\n * - **`io enumerate`**, which also reports it, but is a text parse of a\n * 150-line dump and aborts on an unavailable device. Not used.\n */\nexport const profilePlistPath = (bundlePath: string): string =>\n join(bundlePath, \"Contents\", \"Resources\", \"profile.plist\");\n\nexport type ScreenProfile = {\n mainScreenWidth?: number;\n mainScreenHeight?: number;\n mainScreenScale?: number;\n};\n\nexport const readScreenProfile = async (\n deviceType: RawDeviceType,\n opts: { plutilPath: string; exec: ExecImpl; timeoutMs: number },\n): Promise<ScreenProfile> => {\n if (!deviceType.bundlePath) return {};\n const { stdout } = await opts.exec(\n opts.plutilPath,\n [\"-convert\", \"json\", \"-o\", \"-\", profilePlistPath(deviceType.bundlePath)],\n opts.timeoutMs,\n );\n try {\n return JSON.parse(stdout) as ScreenProfile;\n } catch {\n return {};\n }\n};\n\n/**\n * Width and height straight out of a PNG's IHDR.\n *\n * Cheaper than shelling to `sips` for the one number that must not be stale,\n * and the bytes are already in hand: the signature is fixed, `IHDR` is always\n * the first chunk, and the two dimensions are big-endian at offsets 16 and 20.\n */\nexport const pngDimensions = (png: Buffer): { width: number; height: number } | undefined => {\n const SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n if (png.length < 24 || !png.subarray(0, 8).equals(SIGNATURE)) return undefined;\n if (png.subarray(12, 16).toString(\"ascii\") !== \"IHDR\") return undefined;\n return { width: png.readUInt32BE(16), height: png.readUInt32BE(20) };\n};\n\n/**\n * Assemble a `DisplayInfo`.\n *\n * `orientation` is derived by comparing the capture's own aspect against the\n * profile's portrait dimensions, and is `\"unknown\"` when there is no capture to\n * compare — never guessed as `\"portrait\"`, because the whole point of the field\n * is telling a caller whether the screen they are about to read is rotated.\n *\n * `backlightState` is left undefined: a simulator has no backlight, and\n * `io enumerate`'s `Power state` is about the framebuffer port rather than the\n * screen, so mapping it would be a lie.\n */\nexport const toDisplayInfo = (\n profile: ScreenProfile,\n capture?: { width: number; height: number },\n): DisplayInfo => {\n const scale = profile.mainScreenScale ?? 1;\n const pixelWidth = capture?.width ?? profile.mainScreenWidth;\n const pixelHeight = capture?.height ?? profile.mainScreenHeight;\n\n if (!pixelWidth || !pixelHeight) {\n throw new IosError(\"Could not determine the simulator's screen geometry.\", {\n remedy:\n \"The device type's profile.plist could not be read and no screenshot was available. \" +\n \"Run ios_simulator_diagnostics — an unavailable runtime is the usual cause.\",\n });\n }\n\n const landscape =\n profile.mainScreenWidth !== undefined && profile.mainScreenHeight !== undefined\n ? pixelWidth > pixelHeight && profile.mainScreenWidth < profile.mainScreenHeight\n : pixelWidth > pixelHeight;\n\n return {\n pixelWidth,\n pixelHeight,\n pointWidth: Math.round(pixelWidth / scale),\n pointHeight: Math.round(pixelHeight / scale),\n pointScale: scale,\n orientation: capture ? (landscape ? \"landscape\" : \"portrait\") : \"unknown\",\n };\n};\n","// The context-window layer.\n//\n// `simctl listapps` spends ~38 KB on the 31 apps a stock simulator carries, 25\n// of which are Apple's own, and most of every entry is group-container UUIDs no\n// caller acts on. `list devices` is smaller but still reports five keys per\n// simulator that only matter to CoreSimulator.\n//\n// So: lists return the few fields the other tools consume, and nothing else.\n\nimport type { RawDeviceType, RawRuntime, RawSim, RawSimApp } from \"#/client/simctl\";\n\nexport type SimulatorSummary = {\n /**\n * The UDID. Called `id` because that is the name the shared `ScreenHost`\n * contract uses — a physical device has two identifiers and a simulator has\n * one, so there is nothing here to disambiguate. Rendered back as `udid` by\n * `toListRow`, which is the word anyone reading the output will know it by.\n */\n id: string;\n name: string;\n /** `Booted` or `Shutdown`, verbatim from CoreSimulator. */\n state: string;\n runtime: string;\n deviceType: string | undefined;\n deviceTypeIdentifier: string | undefined;\n /**\n * False when the runtime is missing. Kept rather than filtered: \"why can't I\n * use that one\" has to be answerable from the list, and an unavailable\n * simulator is the one input that makes `simctl io` abort rather than fail.\n */\n available: boolean;\n unavailableReason?: string;\n lastBootedAt?: string;\n};\n\n/**\n * Flatten the runtime-keyed map `list devices` returns.\n *\n * The key is a runtime *identifier* and identifiers are not unique — a machine\n * carrying both iOS 26.4 and 26.4.1 has two entries under\n * `com.apple.CoreSimulator.SimRuntime.iOS-26-4`. So the key is never used as a\n * primary key: it is joined against `list runtimes` for a display name, 0..n\n * matches tolerated, and carried through verbatim besides.\n */\nexport const summarizeDevices = (\n devices: Record<string, RawSim[]>,\n runtimes: RawRuntime[],\n deviceTypes: RawDeviceType[],\n): SimulatorSummary[] => {\n const runtimeName = new Map(\n runtimes.map((r) => [r.identifier, r.name ?? r.version ?? r.identifier]),\n );\n const typeName = new Map(deviceTypes.map((t) => [t.identifier, t.name]));\n\n return Object.entries(devices).flatMap(([runtimeId, sims]) =>\n (sims ?? []).map((sim) => ({\n id: sim.udid,\n name: sim.name,\n state: sim.state,\n runtime: runtimeName.get(runtimeId) ?? runtimeId.split(\".\").pop() ?? runtimeId,\n deviceType: sim.deviceTypeIdentifier ? typeName.get(sim.deviceTypeIdentifier) : undefined,\n deviceTypeIdentifier: sim.deviceTypeIdentifier,\n available: sim.isAvailable !== false,\n ...(sim.availabilityError ? { unavailableReason: sim.availabilityError } : {}),\n ...(sim.lastBootedAt ? { lastBootedAt: sim.lastBootedAt } : {}),\n })),\n );\n};\n\nexport type SimAppSummary = {\n bundleId: string;\n name: string | undefined;\n version: string | undefined;\n build: string | undefined;\n type: string | undefined;\n /**\n * Host filesystem paths, and the reason there is no `pull_container` tool: a\n * simulator's containers are already on this machine, so reading an app's\n * SwiftData store is an ordinary file read rather than a copy off a device.\n */\n bundlePath: string | undefined;\n dataContainer: string | undefined;\n};\n\n/** `file:///Users/…/Foo.app/` → `/Users/…/Foo.app`, which is what a person can use. */\nconst toPath = (url: string | undefined): string | undefined => {\n if (!url) return undefined;\n if (!url.startsWith(\"file://\")) return url;\n try {\n return decodeURIComponent(new URL(url).pathname).replace(/\\/$/, \"\");\n } catch {\n return url;\n }\n};\n\nexport const summarizeApps = (\n apps: Record<string, RawSimApp>,\n opts: { includeAll?: boolean } = {},\n): SimAppSummary[] =>\n Object.values(apps)\n .filter((app) => opts.includeAll === true || app.ApplicationType === \"User\")\n .map((app) => ({\n bundleId: app.CFBundleIdentifier ?? \"\",\n name: app.CFBundleDisplayName ?? app.CFBundleName,\n version: app.CFBundleShortVersionString,\n build: app.CFBundleVersion,\n type: app.ApplicationType,\n bundlePath: toPath(app.Bundle ?? app.Path),\n dataContainer: toPath(app.DataContainer),\n }))\n .filter((app) => app.bundleId !== \"\")\n .toSorted((a, b) => a.bundleId.localeCompare(b.bundleId));\n\n/** The public shape of one row of `ios_simulator_list`. */\nexport const toListRow = (sim: SimulatorSummary): Record<string, unknown> => ({\n udid: sim.id,\n name: sim.name,\n state: sim.state,\n runtime: sim.runtime,\n ...(sim.deviceType ? { deviceType: sim.deviceType } : {}),\n ...(sim.available ? {} : { available: false }),\n ...(sim.unavailableReason ? { unavailableReason: sim.unavailableReason } : {}),\n});\n","import { mkdtemp, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n assertNoShellMetachars,\n createExec,\n type ExecImpl,\n type Logger,\n} from \"@mgcrea/mcp-ios-core\";\n\nimport { IosError, TIMEOUT_REMEDY, TOOLCHAIN_REMEDY } from \"#/client/errors\";\n\n/**\n * `xcrun simctl` — Apple's own simulator tool, and the half of this server that\n * needs nothing installed and nothing signed.\n *\n * It covers strictly more here than `devicectl` does on a physical device: app\n * lifecycle, but also the screen itself (`io screenshot`), the appearance, the\n * status bar, permissions, location and push. Only the accessibility tree and\n * synthetic touches need WebDriverAgent.\n *\n * Three output shapes, and knowing which is which explains the whole class:\n *\n * - `list` takes `-j` and writes clean JSON to **stdout**. It is the only\n * subcommand that does; `listapps --json` does not exist.\n * - `listapps` writes an old-style NeXTSTEP plist. `plutil` converts it, but\n * `ExecImpl` has no stdin, so it goes through a temp file and two processes.\n * - everything else answers in prose, including `(null)` and `unknown`, which\n * are passed through rather than normalised — see the readers below.\n */\nexport type SimctlOptions = {\n xcrunPath: string;\n plutilPath: string;\n timeoutMs: number;\n exec?: ExecImpl | undefined;\n logger?: Logger | undefined;\n};\n\nexport type RawSim = {\n udid: string;\n name: string;\n state: string;\n isAvailable?: boolean;\n availabilityError?: string;\n deviceTypeIdentifier?: string;\n lastBootedAt?: string;\n};\n\nexport type RawRuntime = {\n identifier: string;\n name?: string;\n version?: string;\n isAvailable?: boolean;\n};\n\nexport type RawDeviceType = {\n identifier: string;\n name?: string;\n bundlePath?: string;\n modelIdentifier?: string;\n};\n\n/** One app as `listapps` reports it, once plutil has turned it into JSON. */\nexport type RawSimApp = {\n CFBundleIdentifier?: string;\n CFBundleDisplayName?: string;\n CFBundleName?: string;\n CFBundleShortVersionString?: string;\n CFBundleVersion?: string;\n ApplicationType?: string;\n Bundle?: string;\n Path?: string;\n DataContainer?: string;\n};\n\n/**\n * The two exit codes simctl actually uses, and what they mean.\n *\n * `148` is a device it could not even parse as an identifier. `149` is\n * everything else, wrapped in an envelope whose first line is machine-readable\n * and whose second line is the only part worth showing a person.\n */\nconst INVALID_DEVICE = 148;\n\n/**\n * Pull the human sentence out of a CoreSimulator error envelope.\n *\n * An error was encountered processing the command (domain=…, code=405):\n * Unable to lookup in current state: Shutdown\n *\n * Without this the message a caller sees is the first line, which names a\n * numeric code and says nothing about what to do.\n */\nexport const parseSimctlError = (\n stderr: string,\n): { domain?: string; code?: number; message: string } => {\n const envelope = /\\(domain=([^,]+),\\s*code=(\\d+)\\)\\s*:?\\s*\\n?([\\s\\S]*)/.exec(stderr);\n if (envelope) {\n return {\n domain: envelope[1]?.trim(),\n code: Number(envelope[2]),\n message: (envelope[3] ?? \"\").trim().split(\"\\n\")[0]?.trim() ?? stderr.trim(),\n };\n }\n return { message: stderr.trim().split(\"\\n\")[0]?.trim() ?? stderr.trim() };\n};\n\n/**\n * simctl reports its interesting failures in prose, and each has a different\n * fix. Every string here describes something only a simulator has.\n */\nconst remedyFor = (stderr: string): string | undefined => {\n const { message } = parseSimctlError(stderr);\n const text = `${stderr} ${message}`.toLowerCase();\n if (text.includes(\"invalid device\")) {\n return \"That is not a UDID or a name simctl knows. Run ios_simulator_list to see what exists.\";\n }\n if (text.includes(\"unable to lookup in current state: shutdown\")) {\n return 'The simulator is shut down. Boot it with ios_simulator_power {\"state\":\"booted\"}.';\n }\n if (text.includes(\"current state: booted\")) {\n return \"The simulator is already booted, which for most operations means there is nothing to do.\";\n }\n if (text.includes(\"no such file or directory\")) {\n return (\n \"Check the path exists and is a `.app` **bundle directory** built for the simulator — an \" +\n \"`.ipa` or a device build will not install, and reports exactly this.\"\n );\n }\n if (text.includes(\"failed to initialize io ports\")) {\n return (\n \"The simulator's runtime is not installed, so CoreSimulator cannot service it. Install the \" +\n \"runtime, or clear the orphans with `xcrun simctl delete unavailable`.\"\n );\n }\n return undefined;\n};\n\n/**\n * The one argument that must never reach simctl.\n *\n * `erase`, `delete` and `shutdown` all accept the literal string `all`, and\n * `simctl erase all` wipes every simulator on the machine. A device hint that\n * happens to be the word \"all\" is the single worst thing this server could\n * forward, so it is refused here as well as in the resolver — the resolver is\n * where it should be caught, and this is where it cannot be missed.\n */\nexport const assertNotBulkTarget = (udid: string): void => {\n if (udid === \"all\" || udid === \"unavailable\" || udid === \"booted\") {\n throw new IosError(`Refusing to pass \"${udid}\" to simctl as a device.`, {\n remedy:\n \"simctl reads these as *every* matching simulator, so `erase all` would wipe the machine. \" +\n \"Resolve to one concrete UDID with ios_simulator_list first.\",\n });\n }\n};\n\nexport class Simctl {\n private readonly opts: SimctlOptions;\n private readonly exec: ExecImpl;\n /** Device types change only when Xcode is updated; re-reading is pure cost. */\n private deviceTypes: RawDeviceType[] | undefined;\n\n constructor(opts: SimctlOptions) {\n this.opts = opts;\n this.exec =\n opts.exec ?? createExec({ timeout: TIMEOUT_REMEDY, toolchain: TOOLCHAIN_REMEDY, remedyFor });\n }\n\n /** Raw stdout, for the subcommands that answer in prose. */\n private async run(args: string[]): Promise<string> {\n this.opts.logger?.debug?.(\"simctl\", ...args);\n const { stdout } = await this.exec(\n this.opts.xcrunPath,\n [\"simctl\", ...args],\n this.opts.timeoutMs,\n );\n return stdout;\n }\n\n /**\n * `list` and only `list`. `-e` stops `/` being escaped as `\\/`, which matters\n * only for fixture readability but costs nothing.\n */\n private async runJson<T>(args: string[]): Promise<T> {\n const stdout = await this.run([...args, \"-j\", \"-e\"]);\n try {\n return JSON.parse(stdout) as T;\n } catch {\n throw new IosError(`simctl ${args.join(\" \")} did not return JSON.`, {\n details: stdout.slice(0, 400),\n });\n }\n }\n\n /**\n * A NeXTSTEP plist, via `plutil` and a temp file.\n *\n * The obvious `simctl listapps … | plutil -convert json -o - -` is not\n * expressible: `ExecImpl` takes argv and no stdin, deliberately, because that\n * is what keeps every caller value data rather than shell syntax. So simctl's\n * stdout is written out and handed to plutil by path. A fresh directory per\n * call rather than a shared one, so two concurrent tools cannot read each\n * other's answer with nothing looking wrong.\n */\n private async runPlist<T>(args: string[]): Promise<T> {\n const stdout = await this.run(args);\n const dir = await mkdtemp(join(tmpdir(), \"simctl-\"));\n const path = join(dir, \"out.plist\");\n try {\n await writeFile(path, stdout);\n const { stdout: json } = await this.exec(\n this.opts.plutilPath,\n [\"-convert\", \"json\", \"-o\", \"-\", path],\n this.opts.timeoutMs,\n );\n return JSON.parse(json) as T;\n } catch (err) {\n if (err instanceof IosError) throw err;\n throw new IosError(`Could not read simctl ${args[0]} output as a property list.`, {\n details: stdout.slice(0, 400),\n });\n } finally {\n await rm(dir, { recursive: true, force: true });\n }\n }\n\n // ------------------------------------------------------------------ list --\n\n async listDevices(): Promise<Record<string, RawSim[]>> {\n const result = await this.runJson<{ devices?: Record<string, RawSim[]> }>([\"list\", \"devices\"]);\n return result.devices ?? {};\n }\n\n async listRuntimes(): Promise<RawRuntime[]> {\n return (await this.runJson<{ runtimes?: RawRuntime[] }>([\"list\", \"runtimes\"])).runtimes ?? [];\n }\n\n async listDeviceTypes(): Promise<RawDeviceType[]> {\n this.deviceTypes ??=\n (await this.runJson<{ devicetypes?: RawDeviceType[] }>([\"list\", \"devicetypes\"]))\n .devicetypes ?? [];\n return this.deviceTypes;\n }\n\n // ------------------------------------------------------------- lifecycle --\n\n async boot(udid: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"boot\", udid]);\n }\n\n async shutdown(udid: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"shutdown\", udid]);\n }\n\n async erase(udid: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"erase\", udid]);\n }\n\n /** Attach the Simulator UI to whatever is booted. A `boot` alone is headless. */\n async openApp(openPath: string): Promise<void> {\n await this.exec(openPath, [\"-a\", \"Simulator\"], this.opts.timeoutMs);\n }\n\n // ------------------------------------------------------------------ apps --\n\n async listApps(udid: string): Promise<Record<string, RawSimApp>> {\n assertNotBulkTarget(udid);\n return this.runPlist<Record<string, RawSimApp>>([\"listapps\", udid]);\n }\n\n async install(udid: string, appPath: string): Promise<void> {\n assertNotBulkTarget(udid);\n assertNoShellMetachars(\"path\", appPath);\n await this.run([\"install\", udid, appPath]);\n }\n\n /**\n * Launch, optionally replacing a running copy.\n *\n * Environment variables do not go on the command line: simctl reads them from\n * its **own** environment under a `SIMCTL_CHILD_` prefix. `ExecImpl` pins a\n * minimal environment on purpose, so a caller wanting them has to say so, and\n * this is where that would be threaded through.\n */\n async launch(\n udid: string,\n bundleId: string,\n opts: { args?: string[]; terminateExisting?: boolean; stdout?: string; stderr?: string } = {},\n ): Promise<string> {\n assertNotBulkTarget(udid);\n const flags = [\n ...(opts.terminateExisting ? [\"--terminate-running-process\"] : []),\n ...(opts.stdout ? [`--stdout=${opts.stdout}`] : []),\n ...(opts.stderr ? [`--stderr=${opts.stderr}`] : []),\n ];\n return this.run([\"launch\", ...flags, udid, bundleId, ...(opts.args ?? [])]);\n }\n\n async terminate(udid: string, bundleId: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"terminate\", udid, bundleId]);\n }\n\n async openUrl(udid: string, url: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"openurl\", udid, url]);\n }\n\n // ---------------------------------------------------------------- screen --\n\n /**\n * A PNG of the screen, base64, with no WebDriverAgent involved.\n *\n * The documented `-` for stdout **does not work**: measured on Xcode 26.6, it\n * writes a file literally named `-` into the current working directory and\n * leaves stdout empty, exit code 0. So this passes a real path, like the\n * device lane's `--json-output` does, and for the same reason uses a fresh\n * directory per call.\n *\n * A successful capture also writes a `Note: No display specified…` line to\n * stderr, so non-empty stderr is not a failure here.\n */\n async screenshotPng(udid: string): Promise<string> {\n assertNotBulkTarget(udid);\n const dir = await mkdtemp(join(tmpdir(), \"simshot-\"));\n const path = join(dir, \"shot.png\");\n try {\n await this.run([\"io\", udid, \"screenshot\", \"--type=png\", path]);\n return (await readFile(path)).toString(\"base64\");\n } finally {\n await rm(dir, { recursive: true, force: true });\n }\n }\n\n // ----------------------------------------------------------- environment --\n\n /**\n * Read a `simctl ui` option.\n *\n * `unknown` and `unsupported` are passed through rather than normalised: they\n * mean genuinely different things — the runtime is too old, versus it failed\n * to read — and collapsing them throws away a distinction a caller can act on.\n */\n async uiGet(udid: string, option: string): Promise<string> {\n assertNotBulkTarget(udid);\n return (await this.run([\"ui\", udid, option])).trim();\n }\n\n async uiSet(udid: string, option: string, value: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"ui\", udid, option, value]);\n }\n\n async statusBarOverride(udid: string, flags: string[]): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"status_bar\", udid, \"override\", ...flags]);\n }\n\n async statusBarClear(udid: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"status_bar\", udid, \"clear\"]);\n }\n\n async statusBarList(udid: string): Promise<string> {\n assertNotBulkTarget(udid);\n return (await this.run([\"status_bar\", udid, \"list\"])).trim();\n }\n\n async locationSet(udid: string, latitude: number, longitude: number): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"location\", udid, \"set\", `${latitude},${longitude}`]);\n }\n\n async locationClear(udid: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"location\", udid, \"clear\"]);\n }\n\n /** `grant` and `revoke` need a bundle id; `reset` does not. */\n async privacy(udid: string, action: string, service: string, bundleId?: string): Promise<void> {\n assertNotBulkTarget(udid);\n await this.run([\"privacy\", udid, action, service, ...(bundleId ? [bundleId] : [])]);\n }\n\n /**\n * A simulated remote push. The payload goes through a temp file rather than\n * stdin, for the same argv-only reason as the plist lane.\n */\n async push(udid: string, bundleId: string, payload: unknown): Promise<void> {\n assertNotBulkTarget(udid);\n const dir = await mkdtemp(join(tmpdir(), \"simpush-\"));\n const path = join(dir, \"payload.json\");\n try {\n await writeFile(path, JSON.stringify(payload));\n await this.run([\"push\", udid, bundleId, path]);\n } finally {\n await rm(dir, { recursive: true, force: true });\n }\n }\n}\n\nexport { INVALID_DEVICE };\n","import {\n createExec,\n WdaClient,\n type DisplayInfo,\n type ExecImpl,\n type Logger,\n type ScreenHost,\n} from \"@mgcrea/mcp-ios-core\";\n\nimport { pngDimensions, readScreenProfile, toDisplayInfo } from \"#/client/display\";\nimport {\n RuntimeUnavailableError,\n SimulatorNotBootedError,\n SimulatorNotFoundError,\n START_RUNNER_REMEDY,\n TIMEOUT_REMEDY,\n TOOLCHAIN_REMEDY,\n WDA_UNAVAILABLE_REMEDY,\n} from \"#/client/errors\";\nimport { summarizeDevices, type SimulatorSummary } from \"#/client/shape\";\nimport { Simctl } from \"#/client/simctl\";\n\n/** What to say when WebDriverAgent fails, on a simulator. */\nconst SIMULATOR_WDA_REMEDIES = {\n unavailable: WDA_UNAVAILABLE_REMEDY,\n notAuthorized:\n \"WebDriverAgent is running but is refusing to drive the UI. On a simulator there is no \" +\n `Enable UI Automation toggle to blame, so this is nearly always a stale runner. ${START_RUNNER_REMEDY}`,\n noForegroundApp:\n \"WebDriverAgent can see no foreground application on a session it has just created. Launch \" +\n \"the app with ios_simulator_launch, or restart the runner with ios_simulator_restart_wda.\",\n noSuchElement:\n \"Call ios_simulator_ui_tree to see what is actually on screen — the element may not have \" +\n \"appeared yet.\",\n};\n\nexport type SimulatorClientOptions = {\n xcrunPath: string;\n sipsPath: string;\n plutilPath: string;\n openPath: string;\n execTimeoutMs: number;\n wdaTimeoutMs: number;\n wdaPort: number;\n wdaUrl?: string | undefined;\n defaultSimulatorId?: string | undefined;\n exec?: ExecImpl | undefined;\n fetch?: typeof fetch | undefined;\n logger?: Logger | undefined;\n};\n\nexport class SimulatorClient implements ScreenHost<SimulatorSummary> {\n readonly simctl: Simctl;\n readonly exec: ExecImpl;\n readonly sipsPath: string;\n readonly plutilPath: string;\n readonly openPath: string;\n readonly execTimeoutMs: number;\n private readonly opts: SimulatorClientOptions;\n private readonly wdaClients = new Map<string, WdaClient>();\n /** `simctl list` is ~80ms and most tools want it twice; 2s collapses that. */\n private cache: { at: number; simulators: SimulatorSummary[] } | undefined;\n private profiles = new Map<string, Awaited<ReturnType<typeof readScreenProfile>>>();\n\n constructor(opts: SimulatorClientOptions) {\n this.opts = opts;\n this.exec = opts.exec ?? createExec({ timeout: TIMEOUT_REMEDY, toolchain: TOOLCHAIN_REMEDY });\n this.sipsPath = opts.sipsPath;\n this.plutilPath = opts.plutilPath;\n this.openPath = opts.openPath;\n this.execTimeoutMs = opts.execTimeoutMs;\n this.simctl = new Simctl({\n xcrunPath: opts.xcrunPath,\n plutilPath: opts.plutilPath,\n timeoutMs: opts.execTimeoutMs,\n ...(opts.exec ? { exec: opts.exec } : {}),\n ...(opts.logger ? { logger: opts.logger } : {}),\n });\n }\n\n async listSimulators(opts: { fresh?: boolean } = {}): Promise<SimulatorSummary[]> {\n const cached = this.cache;\n if (!opts.fresh && cached && Date.now() - cached.at < 2000) return cached.simulators;\n const [devices, runtimes, deviceTypes] = await Promise.all([\n this.simctl.listDevices(),\n this.simctl.listRuntimes(),\n this.simctl.listDeviceTypes(),\n ]);\n const simulators = summarizeDevices(devices, runtimes, deviceTypes);\n this.cache = { at: Date.now(), simulators };\n return simulators;\n }\n\n /**\n * Resolve a hint to exactly one simulator, or refuse.\n *\n * The device server's rule — never guess between two — transfers, but\n * \"connected\" has to become the right predicate. A typical machine carries\n * dozens of simulators, most of them shut down and some of them unavailable,\n * so the population is mostly non-candidates.\n *\n * Three things happen here that cannot happen further down:\n *\n * - `all` and `unavailable` are refused outright. `simctl erase all` wipes\n * every simulator on the machine, and a hint is a string from a model.\n * - `booted` is resolved *here* rather than passed through. simctl's own\n * documentation says that with several booted it \"will choose one of\n * them\", and a coin flip that drives the wrong screen most of the time is\n * exactly what the refuse-to-guess rule exists to prevent.\n * - availability is checked before the target is returned, because `simctl\n * io` against an unavailable simulator aborts with an uncaught\n * NSInternalInconsistencyException rather than failing.\n *\n * State is deliberately *not* checked: `ios_simulator_list` and\n * `ios_simulator_diagnostics` are useful against a shut-down simulator, so\n * requiring booted is each tool's decision, via `requireBooted`.\n */\n async resolveTarget(hint?: string): Promise<SimulatorSummary> {\n const wanted = hint ?? this.opts.defaultSimulatorId;\n const simulators = await this.listSimulators();\n\n if (wanted === \"all\" || wanted === \"unavailable\") {\n throw new SimulatorNotFoundError(\n `\"${wanted}\" is not a simulator, it is how simctl says *every* simulator.`,\n \"Name one by UDID or by name. `simctl erase all` would wipe the machine, so this server \" +\n \"refuses to forward it.\",\n );\n }\n\n const usable = simulators.filter((sim) => sim.available);\n if (wanted !== undefined && wanted !== \"booted\") {\n const byUdid = simulators.filter((sim) => sim.id.toLowerCase() === wanted.toLowerCase());\n // A name is ambiguous far more often than a UDID: the same device name\n // exists once per runtime, and the orphans of an uninstalled runtime keep\n // theirs. Prefer the ones that can actually be used, so \"iPhone 17 Pro\"\n // resolves to the real one rather than erroring against a dead 26.3 twin.\n const named = simulators.filter((sim) => sim.name === wanted);\n const byName = named.some((sim) => sim.available)\n ? named.filter((sim) => sim.available)\n : named;\n const matches = byUdid.length > 0 ? byUdid : byName;\n if (matches.length === 0) {\n throw new SimulatorNotFoundError(\n `No simulator matches \"${wanted}\".`,\n simulators.length === 0\n ? \"simctl knows about no simulators at all. Install a runtime in Xcode > Settings > Components.\"\n : `Run ios_simulator_list to see them. ${usable.length} of ${simulators.length} are available.`,\n );\n }\n if (matches.length > 1) {\n throw new SimulatorNotFoundError(\n `${matches.length} simulators are named \"${wanted}\".`,\n `Pass a UDID instead: ${matches.map((sim) => `${sim.name} = ${sim.id}`).join(\", \")}.`,\n );\n }\n return this.assertAvailable(matches[0] as SimulatorSummary);\n }\n\n const booted = usable.filter((sim) => sim.state === \"Booted\");\n if (booted.length === 1) return this.assertAvailable(booted[0] as SimulatorSummary);\n if (booted.length === 0) {\n const candidates = usable\n .slice(0, 6)\n .map((sim) => `${sim.name} = ${sim.id}`)\n .join(\", \");\n throw new SimulatorNotFoundError(\n \"No simulator is booted.\",\n usable.length === 0\n ? \"No simulator on this machine has an installed runtime. Install one in Xcode > Settings > Components.\"\n : `Boot one with ios_simulator_power, e.g. ${candidates}.`,\n );\n }\n throw new SimulatorNotFoundError(\n `${booted.length} simulators are booted, so there is no obvious default.`,\n `Pass \\`simulator\\` (or set IOS_SIMULATOR_ID) to one of: ${booted\n .map((sim) => `${sim.name} = ${sim.id}`)\n .join(\", \")}.`,\n );\n }\n\n private assertAvailable(sim: SimulatorSummary): SimulatorSummary {\n if (!sim.available) throw new RuntimeUnavailableError(sim.name, sim.unavailableReason);\n return sim;\n }\n\n /** Every tool that needs a running simulator calls this; the resolver does not. */\n requireBooted(sim: SimulatorSummary): SimulatorSummary {\n if (sim.state !== \"Booted\") throw new SimulatorNotBootedError(sim.name, sim.id);\n return sim;\n }\n\n /**\n * Geometry. Cached per device *type* rather than per simulator, since that is\n * what the profile describes and it changes only when Xcode does.\n */\n async display(target: SimulatorSummary, capturePng?: string): Promise<DisplayInfo> {\n const id = target.deviceTypeIdentifier;\n let profile = id ? this.profiles.get(id) : undefined;\n if (!profile) {\n const deviceType = (await this.simctl.listDeviceTypes()).find((t) => t.identifier === id);\n profile = deviceType\n ? await readScreenProfile(deviceType, {\n plutilPath: this.plutilPath,\n exec: this.exec,\n timeoutMs: this.execTimeoutMs,\n })\n : {};\n if (id) this.profiles.set(id, profile);\n }\n const capture = capturePng ? pngDimensions(Buffer.from(capturePng, \"base64\")) : undefined;\n return toDisplayInfo(profile, capture);\n }\n\n /** The capture lane that needs no runner — the whole reason this server is cheap to start. */\n async screenshotPng(target: SimulatorSummary): Promise<string> {\n this.requireBooted(target);\n return this.simctl.screenshotPng(target.id);\n }\n\n /**\n * Where WebDriverAgent is.\n *\n * Unlike the device lane there is no tunnel address to derive: a simulator\n * shares the host's network stack, so the runner's port *is* a host loopback\n * port. That is also the trap — several booted simulators contend for the\n * same one, and WebDriverAgent scans 8100-8199 when `USE_PORT` is unset, so a\n * second runner comes up healthy on 8101 and a server pointed at 8100 drives\n * the first simulator while reporting success. `ios_simulator_diagnostics`\n * reports which simulator actually owns the port.\n */\n wdaUrl(): string {\n return this.opts.wdaUrl ?? `http://127.0.0.1:${this.opts.wdaPort}`;\n }\n\n get wdaPort(): number {\n return this.opts.wdaPort;\n }\n\n wda(_target: SimulatorSummary): WdaClient {\n const url = this.wdaUrl();\n const existing = this.wdaClients.get(url);\n if (existing) return existing;\n const client = new WdaClient({\n baseUrl: async () => url,\n timeoutMs: this.opts.wdaTimeoutMs,\n remedies: SIMULATOR_WDA_REMEDIES,\n ...(this.opts.fetch ? { fetch: this.opts.fetch } : {}),\n ...(this.opts.logger ? { logger: this.opts.logger } : {}),\n });\n this.wdaClients.set(url, client);\n return client;\n }\n}\n","import { createArgs, type ScreenNaming } from \"@mgcrea/mcp-ios-core\";\n\nexport {\n compact,\n fail,\n ok,\n okImage,\n okText,\n toFailure,\n wrap,\n wrapResult,\n} from \"@mgcrea/mcp-ios-core\";\nexport type { ImageContent, TextContent, ToolResult } from \"@mgcrea/mcp-ios-core\";\n\n/**\n * How the shared tools name themselves and each other in this server.\n *\n * `copy.target` is written out rather than derived: a simulator is picked by\n * UDID, by name, or by being the only booted one, and none of those is what the\n * device server's version of this sentence says. `names.listTargets` is\n * overridden for the same reason — `ios_simulator_list_devices` would be a\n * mouthful for a tool that lists simulators.\n */\nexport const SIMULATOR_NAMING: ScreenNaming = {\n prefix: \"ios_simulator\",\n title: \"iOS Simulator\",\n noun: \"simulator\",\n envPrefix: \"IOS_SIMULATOR\",\n names: { listTargets: \"ios_simulator_list\" },\n copy: {\n target:\n \"Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly \" +\n \"one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. \" +\n \"Unlike simctl's own `booted`, this never picks arbitrarily between two.\",\n },\n};\n\nconst args = createArgs(SIMULATOR_NAMING);\n\nexport const { bundleIdArg, confirmArg, detailArg, screenshotArg, settleArg, xArg, yArg } = args;\n\n/**\n * The schema field is `device` in every tool here, shared and local alike.\n *\n * It looks odd next to a server called \"simulator\" and it is still the right\n * name: `simctl`'s own interface calls a simulator a device — `simctl list\n * devices`, and `<device>` in the usage line of every subcommand — so this is\n * Apple's word for the thing, and the `ios_simulator_` prefix already says\n * which kind. Mixing `simulator` here with the shared tools' `device` would be\n * worse than either alone.\n */\nexport const deviceArg = args.targetArg;\n","import type { McpServer } from \"@modelcontextprotocol/server\";\nimport { z } from \"zod\";\n\nimport { IosError } from \"#/client/errors\";\nimport { summarizeApps } from \"#/client/shape\";\nimport type { SimulatorClient } from \"#/client/simulator\";\nimport { bundleIdArg, deviceArg, wrap } from \"#/tools/util\";\n\nexport const registerListAppsTool = (server: McpServer, client: SimulatorClient): void => {\n server.registerTool(\n \"ios_simulator_list_apps\",\n {\n title: \"iOS Simulator: List Apps\",\n description:\n \"List the apps installed on a simulator, with the bundle id every other tool takes. \" +\n \"Defaults to your own apps: a stock simulator carries about thirty, and twenty-five of \" +\n \"them are Apple's. Each entry also carries `dataContainer` — an ordinary path on this \" +\n \"Mac, so an app's database or logs can be read directly with no copy step.\",\n inputSchema: z.object({\n device: deviceArg,\n include_all: z\n .boolean()\n .default(false)\n .describe(\"Include Apple's built-in apps as well. Off by default; the list is long.\"),\n }),\n annotations: { readOnlyHint: true },\n },\n async ({ device, include_all }) =>\n wrap(async () => {\n const target = client.requireBooted(await client.resolveTarget(device));\n const apps = await client.simctl.listApps(target.id);\n return { apps: summarizeApps(apps, { includeAll: include_all }) };\n }),\n );\n};\n\nexport const registerAppTools = (\n server: McpServer,\n client: SimulatorClient,\n launchArgs: string[],\n outputDir: string,\n): void => {\n server.registerTool(\n \"ios_simulator_install\",\n {\n title: \"iOS Simulator: Install\",\n description:\n \"Install a build. The path must be a `.app` **bundle directory** built for the simulator \" +\n '— not an `.ipa`, and not a device build, both of which fail with a bare \"No such file or ' +\n 'directory\" that reads like a typo. Installing over an existing copy replaces it and ' +\n \"keeps its data.\",\n inputSchema: z.object({\n device: deviceArg,\n path: z\n .string()\n .describe(\n \"Absolute path to the .app bundle, e.g. \" +\n \"~/Library/Developer/Xcode/DerivedData/…/Build/Products/Debug-iphonesimulator/Foo.app\",\n ),\n }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n },\n async ({ device, path }) =>\n wrap(async () => {\n if (!path.startsWith(\"/\")) {\n throw new IosError(`path must be absolute, got \"${path}\".`, {\n remedy: \"Pass the full path to the .app bundle.\",\n });\n }\n const target = client.requireBooted(await client.resolveTarget(device));\n await client.simctl.install(target.id, path);\n return { installed: path, udid: target.id };\n }),\n );\n\n server.registerTool(\n \"ios_simulator_launch\",\n {\n title: \"iOS Simulator: Launch\",\n description:\n \"Launch an installed app. Pass `arguments` to put it into a fixture or demo mode — that \" +\n \"is what IOS_SIMULATOR_LAUNCH_ARGS sets as the default for every launch that does not \" +\n \"override it. Standard output and error are captured to files under the output directory, \" +\n \"so an app that dies on launch leaves something readable behind.\",\n inputSchema: z.object({\n device: deviceArg,\n bundle_id: bundleIdArg,\n arguments: z\n .array(z.string())\n .optional()\n .describe(\n 'Launch arguments, e.g. [\"-DemoMode\", \"YES\"]. Overrides IOS_SIMULATOR_LAUNCH_ARGS ' +\n \"rather than adding to it.\",\n ),\n terminate_first: z\n .boolean()\n .default(true)\n .describe(\n \"Replace a running copy rather than attaching to it. On by default so a launch means \" +\n \"a fresh process and a predictable first screen.\",\n ),\n }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },\n },\n async ({ device, bundle_id, arguments: args, terminate_first }) =>\n wrap(async () => {\n const target = client.requireBooted(await client.resolveTarget(device));\n const effective = args ?? launchArgs;\n const stdout = `${outputDir}/${bundle_id}.out.log`;\n const stderr = `${outputDir}/${bundle_id}.err.log`;\n const output = await client.simctl.launch(target.id, bundle_id, {\n args: effective,\n terminateExisting: terminate_first,\n stdout,\n stderr,\n });\n const pid = /:\\s*(\\d+)\\s*$/.exec(output.trim())?.[1];\n return {\n launched: bundle_id,\n ...(pid ? { pid: Number(pid) } : {}),\n ...(effective.length > 0 ? { arguments: effective } : {}),\n ...(args === undefined && launchArgs.length > 0\n ? { argumentsFrom: \"IOS_SIMULATOR_LAUNCH_ARGS\" }\n : {}),\n logs: { stdout, stderr },\n };\n }),\n );\n\n server.registerTool(\n \"ios_simulator_terminate\",\n {\n title: \"iOS Simulator: Terminate\",\n description:\n \"Kill a running app. The app is not uninstalled and its data is untouched — this is how \" +\n \"you get back to a cold start without erasing anything.\",\n inputSchema: z.object({ device: deviceArg, bundle_id: bundleIdArg }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n },\n async ({ device, bundle_id }) =>\n wrap(async () => {\n const target = client.requireBooted(await client.resolveTarget(device));\n await client.simctl.terminate(target.id, bundle_id);\n return { terminated: bundle_id };\n }),\n );\n\n server.registerTool(\n \"ios_simulator_open_url\",\n {\n title: \"iOS Simulator: Open URL\",\n description:\n \"Open a URL on the simulator, which is how you exercise a deep link or a universal link \" +\n \"without finding a way to tap one. An `https://` link opens in Safari unless the app \" +\n \"claims it; a custom scheme goes straight to whichever app registered it.\",\n inputSchema: z.object({\n device: deviceArg,\n url: z.url().describe('e.g. \"myapp://garden/42\" or \"https://example.com/garden/42\".'),\n }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },\n },\n async ({ device, url }) =>\n wrap(async () => {\n const target = client.requireBooted(await client.resolveTarget(device));\n await client.simctl.openUrl(target.id, url);\n return { opened: url };\n }),\n );\n};\n","import type { DisplayInfo } from \"@mgcrea/mcp-ios-core\";\nimport type { McpServer } from \"@modelcontextprotocol/server\";\nimport { z } from \"zod\";\n\nimport { START_RUNNER_REMEDY } from \"#/client/errors\";\nimport { toListRow, type SimulatorSummary } from \"#/client/shape\";\nimport type { SimulatorClient } from \"#/client/simulator\";\nimport type { ToolContext } from \"#/tools/index\";\nimport { deviceArg, wrap } from \"#/tools/util\";\n\nexport type Diagnosis = {\n ok: boolean;\n writes: \"enabled\" | \"disabled\";\n /**\n * The booted ones only, plus the target. A typical machine carries thirty-odd\n * simulators and listing them all here spent more of the context window than\n * the whole rest of the report — and none of them is what a diagnosis is\n * about. `counts` carries the shape of the rest; ios_simulator_list is there\n * for the full picture.\n */\n simulators: Record<string, unknown>[];\n counts: { total: number; booted: number; unavailable: number };\n target?: { udid: string; name: string; state: string; runtime: string };\n display?: DisplayInfo;\n wda: {\n url: string;\n port: number;\n reachable: boolean;\n /** Which simulator actually owns the port — the failure unique to this server. */\n boundTo?: string;\n state?: unknown;\n error?: string;\n };\n problems: string[];\n nextSteps: string[];\n};\n\n/**\n * Which simulator owns the WebDriverAgent port.\n *\n * This check has no device-server equivalent and it is the most valuable one\n * here. A simulator shares the host's network stack, so a runner's port is a\n * *host* port, and WebDriverAgent scans 8100-8199 when `USE_PORT` is unset. Two\n * booted simulators therefore give you a second runner answering healthily on\n * 8101 while a server pointed at 8100 drives the first one and reports success\n * on every call.\n *\n * Every process inside a simulator carries `SIMULATOR_UDID` in its environment,\n * and `ps -Eww` prints it, so the port's real owner is knowable rather than\n * assumed.\n */\nconst portOwner = async (client: SimulatorClient, port: number): Promise<string | undefined> => {\n try {\n const { stdout: pids } = await client.exec(\n \"/usr/sbin/lsof\",\n [\"-nP\", `-iTCP:${port}`, \"-sTCP:LISTEN\", \"-t\"],\n 5000,\n );\n const pid = pids.trim().split(\"\\n\")[0];\n if (!pid) return undefined;\n const { stdout: env } = await client.exec(\"/bin/ps\", [\"-Eww\", \"-p\", pid], 5000);\n return /SIMULATOR_UDID=([0-9A-Fa-f-]{36})/.exec(env)?.[1];\n } catch {\n // lsof is not always installed and needs no permissions we can assume.\n // Not knowing the owner is a missing field, not a failure.\n return undefined;\n }\n};\n\n/**\n * The whole point of this tool is that **it never throws**. Every other tool\n * fails when nothing is booted, the runtime is missing or the runner is not up,\n * and each of those looks much like the others from the outside. This one\n * collects all of it as data and names which half is missing.\n */\nexport const diagnose = async (\n client: SimulatorClient,\n ctx: ToolContext,\n deviceHint?: string,\n): Promise<Diagnosis> => {\n const problems: string[] = [];\n const nextSteps: string[] = [];\n const writes = ctx.allowWrites ? \"enabled\" : \"disabled\";\n\n let simulators: SimulatorSummary[] = [];\n try {\n simulators = await client.listSimulators({ fresh: true });\n } catch (err) {\n problems.push(`Could not list simulators: ${err instanceof Error ? err.message : String(err)}`);\n nextSteps.push(\n \"Install Xcode and its command line tools, then run `xcrun simctl list devices`.\",\n );\n return {\n ok: false,\n writes,\n simulators: [],\n counts: { total: 0, booted: 0, unavailable: 0 },\n wda: { url: client.wdaUrl(), port: client.wdaPort, reachable: false },\n problems,\n nextSteps,\n };\n }\n\n const booted = simulators.filter((sim) => sim.state === \"Booted\");\n const unavailable = simulators.filter((sim) => !sim.available);\n const counts = {\n total: simulators.length,\n booted: booted.length,\n unavailable: unavailable.length,\n };\n\n if (simulators.length === 0) {\n problems.push(\"simctl knows about no simulators at all.\");\n nextSteps.push(\"Install a runtime: Xcode > Settings > Components.\");\n } else if (booted.length === 0) {\n problems.push(\"No simulator is booted.\");\n nextSteps.push(\n 'Boot one with ios_simulator_power {\"state\":\"booted\"} — this server never boots implicitly.',\n );\n }\n\n let target: SimulatorSummary | undefined;\n try {\n target = await client.resolveTarget(deviceHint);\n } catch (err) {\n if (booted.length > 0) {\n problems.push(err instanceof Error ? err.message : String(err));\n const remedy = (err as { remedy?: string }).remedy;\n if (remedy) nextSteps.push(remedy);\n }\n }\n\n let display: DisplayInfo | undefined;\n if (target) {\n try {\n display = await client.display(target);\n } catch {\n // Geometry comes from the device type's profile.plist, so failing here\n // means the profile could not be read — worth a missing field, not a\n // failed report.\n }\n }\n\n // WebDriverAgent. `reachable` and usable coincide on a simulator: there is no\n // Enable UI Automation toggle, so the device server's separate `authorized`\n // probe would be pure latency. What replaces it is `boundTo`.\n const url = client.wdaUrl();\n const wda: Diagnosis[\"wda\"] = { url, port: client.wdaPort, reachable: false };\n try {\n wda.state = await client.wda(target ?? ({ id: \"\", name: \"\" } as SimulatorSummary)).status();\n wda.reachable = true;\n } catch (err) {\n wda.error = err instanceof Error ? err.message : String(err);\n problems.push(\"WebDriverAgent is not answering, so the UI tree and the input tools will fail.\");\n nextSteps.push(\n `${START_RUNNER_REMEDY} Everything else — including screenshots — works without it.`,\n );\n }\n\n if (wda.reachable) {\n const owner = await portOwner(client, client.wdaPort);\n if (owner) wda.boundTo = owner;\n if (owner && target && owner.toLowerCase() !== target.id.toLowerCase()) {\n const other = simulators.find((sim) => sim.id.toLowerCase() === owner.toLowerCase());\n problems.push(\n `Port ${client.wdaPort} is owned by ${other?.name ?? owner}, not ${target.name}. ` +\n \"Every tap and every UI tree read would go to the wrong screen.\",\n );\n nextSteps.push(\n \"WebDriverAgent scans 8100-8199 when USE_PORT is unset, so a second simulator's runner \" +\n \"takes the next free port and nothing looks wrong. Give this one its own port with \" +\n \"IOS_SIMULATOR_WDA_PORT and start its runner with a matching USE_PORT.\",\n );\n }\n }\n\n if (unavailable.length > 0) {\n nextSteps.push(\n `${unavailable.length} simulators have no installed runtime and cannot be used at all. ` +\n \"`xcrun simctl delete unavailable` clears them.\",\n );\n }\n\n return {\n ok: problems.length === 0,\n writes,\n simulators: [...booted, ...(target && target.state !== \"Booted\" ? [target] : [])].map(\n toListRow,\n ),\n counts,\n ...(target\n ? {\n target: {\n udid: target.id,\n name: target.name,\n state: target.state,\n runtime: target.runtime,\n },\n }\n : {}),\n ...(display ? { display } : {}),\n wda,\n problems,\n nextSteps,\n };\n};\n\nexport const registerDiagnosticsTools = (\n server: McpServer,\n client: SimulatorClient,\n ctx: ToolContext,\n): void => {\n server.registerTool(\n \"ios_simulator_diagnostics\",\n {\n title: \"iOS Simulator: Diagnostics\",\n description:\n \"Report both lanes separately and never fail: which simulators exist and which are \" +\n \"usable, which one this server would drive, its screen geometry, and whether \" +\n \"WebDriverAgent is answering — including *which* simulator owns its port, which is the \" +\n \"one way to catch a second runner quietly taking your taps. Start here when anything \" +\n \"else misbehaves.\",\n inputSchema: z.object({ device: deviceArg }),\n annotations: { readOnlyHint: true },\n },\n async ({ device }) => wrap(async () => diagnose(client, ctx, device)),\n );\n\n server.registerResource(\n \"diagnostics\",\n \"ios-simulator://diagnostics\",\n {\n title: \"iOS Simulator diagnostics\",\n description: \"The same report as ios_simulator_diagnostics, as a resource.\",\n mimeType: \"application/json\",\n },\n async (uri) => ({\n contents: [\n {\n uri: uri.href,\n mimeType: \"application/json\",\n text: JSON.stringify(await diagnose(client, ctx)),\n },\n ],\n }),\n );\n};\n","import type { McpServer } from \"@modelcontextprotocol/server\";\nimport { z } from \"zod\";\n\nimport { IosError } from \"#/client/errors\";\nimport type { SimulatorClient } from \"#/client/simulator\";\nimport { bundleIdArg, deviceArg, wrap } from \"#/tools/util\";\n\n/** simctl's own list, verbatim — a value it does not accept is not worth guessing at. */\nconst PRIVACY_SERVICES = [\n \"all\",\n \"calendar\",\n \"contacts-limited\",\n \"contacts\",\n \"location\",\n \"location-always\",\n \"photos-add\",\n \"photos\",\n \"media-library\",\n \"microphone\",\n \"motion\",\n \"reminders\",\n \"siri\",\n] as const;\n\n/** APNs refuses anything larger, and it is worth saying so before the round trip. */\nconst MAX_PUSH_BYTES = 4096;\n\nexport const registerEnvironmentTools = (server: McpServer, client: SimulatorClient): void => {\n server.registerTool(\n \"ios_simulator_set_environment\",\n {\n title: \"iOS Simulator: Set Environment\",\n description:\n \"Stage the simulator before a screenshot or a test: dark mode, Dynamic Type size, \" +\n \"increased contrast, a frozen status bar, a simulated location, and app permissions. \" +\n \"None of this is possible on a physical device, and it is most of the reason to prefer a \" +\n \"simulator for UI work. Every field is optional; those given are applied in order and the \" +\n \"result reports the state afterwards. A status bar override survives a reboot, so clear \" +\n \"it when you are done or it quietly pollutes later screenshots.\",\n inputSchema: z.object({\n device: deviceArg,\n appearance: z.enum([\"light\", \"dark\"]).optional().describe(\"Interface style.\"),\n content_size: z\n .enum([\n \"extra-small\",\n \"small\",\n \"medium\",\n \"large\",\n \"extra-large\",\n \"extra-extra-large\",\n \"extra-extra-extra-large\",\n \"accessibility-medium\",\n \"accessibility-large\",\n \"accessibility-extra-large\",\n \"accessibility-extra-extra-large\",\n \"accessibility-extra-extra-extra-large\",\n ])\n .optional()\n .describe(\"Dynamic Type size. The accessibility- sizes are where layouts break.\"),\n increase_contrast: z.boolean().optional().describe(\"Increase Contrast accessibility mode.\"),\n status_bar: z\n .object({\n time: z\n .string()\n .optional()\n .describe('Fixed clock, e.g. \"9:41\" — what App Store screenshots use.'),\n wifi_bars: z.number().int().min(0).max(3).optional(),\n cellular_bars: z.number().int().min(0).max(4).optional(),\n operator_name: z.string().optional().describe('Carrier name; \"\" hides it.'),\n battery_level: z.number().int().min(0).max(100).optional(),\n battery_state: z.enum([\"charging\", \"charged\", \"discharging\"]).optional(),\n })\n .optional()\n .describe(\"Freeze the status bar. Overrides persist until cleared.\"),\n clear_status_bar: z\n .boolean()\n .default(false)\n .describe(\"Drop every status bar override, restoring the real one.\"),\n location: z\n .object({ latitude: z.number(), longitude: z.number() })\n .optional()\n .describe(\"Teleport the device, for location-gated screens.\"),\n clear_location: z.boolean().default(false).describe(\"Stop simulating a location.\"),\n permission: z\n .object({\n action: z\n .enum([\"grant\", \"revoke\", \"reset\"])\n .describe(\n \"`grant` and `revoke` answer the prompt without showing it; `reset` makes it \" +\n \"appear again on next use.\",\n ),\n service: z.enum(PRIVACY_SERVICES),\n bundle_id: bundleIdArg\n .optional()\n .describe(\"Required for grant and revoke; optional for reset.\"),\n })\n .optional()\n .describe(\n \"Set an app permission directly. This is how you reach the denied branch of a \" +\n \"permission check, which is otherwise a prompt nobody can tap.\",\n ),\n }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n },\n async ({\n device,\n appearance,\n content_size,\n increase_contrast,\n status_bar,\n clear_status_bar,\n location,\n clear_location,\n permission,\n }) =>\n wrap(async () => {\n const target = client.requireBooted(await client.resolveTarget(device));\n const applied: string[] = [];\n\n if (appearance) {\n await client.simctl.uiSet(target.id, \"appearance\", appearance);\n applied.push(`appearance=${appearance}`);\n }\n if (content_size) {\n await client.simctl.uiSet(target.id, \"content_size\", content_size);\n applied.push(`content_size=${content_size}`);\n }\n if (increase_contrast !== undefined) {\n await client.simctl.uiSet(\n target.id,\n \"increase_contrast\",\n increase_contrast ? \"enabled\" : \"disabled\",\n );\n applied.push(`increase_contrast=${increase_contrast}`);\n }\n if (clear_status_bar) {\n await client.simctl.statusBarClear(target.id);\n applied.push(\"status_bar cleared\");\n }\n if (status_bar) {\n const flags = [\n ...(status_bar.time ? [\"--time\", status_bar.time] : []),\n ...(status_bar.wifi_bars !== undefined\n ? [\"--wifiMode\", \"active\", \"--wifiBars\", String(status_bar.wifi_bars)]\n : []),\n ...(status_bar.cellular_bars !== undefined\n ? [\"--cellularMode\", \"active\", \"--cellularBars\", String(status_bar.cellular_bars)]\n : []),\n ...(status_bar.operator_name !== undefined\n ? [\"--operatorName\", status_bar.operator_name]\n : []),\n ...(status_bar.battery_level !== undefined\n ? [\"--batteryLevel\", String(status_bar.battery_level)]\n : []),\n ...(status_bar.battery_state ? [\"--batteryState\", status_bar.battery_state] : []),\n ];\n if (flags.length === 0) {\n throw new IosError(\"`status_bar` was given with no fields to override.\", {\n remedy: \"Set at least one field, or use `clear_status_bar` to drop the overrides.\",\n });\n }\n await client.simctl.statusBarOverride(target.id, flags);\n applied.push(\"status_bar overridden\");\n }\n if (clear_location) {\n await client.simctl.locationClear(target.id);\n applied.push(\"location cleared\");\n }\n if (location) {\n await client.simctl.locationSet(target.id, location.latitude, location.longitude);\n applied.push(`location=${location.latitude},${location.longitude}`);\n }\n if (permission) {\n if (permission.action !== \"reset\" && !permission.bundle_id) {\n throw new IosError(`\\`${permission.action}\\` needs a bundle_id.`, {\n remedy: \"Pass the app's bundle id, or use `reset`, which does not need one.\",\n });\n }\n await client.simctl.privacy(\n target.id,\n permission.action,\n permission.service,\n permission.bundle_id,\n );\n applied.push(`permission ${permission.action} ${permission.service}`);\n }\n\n if (applied.length === 0) {\n throw new IosError(\"Nothing to do — no field was given.\", {\n remedy:\n \"Set at least one of appearance, content_size, status_bar, location, permission.\",\n });\n }\n\n // Read back rather than echo the request: `simctl ui` answers `unknown`\n // or `unsupported` on a runtime too old for a setting, and reporting the\n // value we asked for would hide that.\n return {\n applied,\n state: {\n appearance: await client.simctl.uiGet(target.id, \"appearance\"),\n contentSize: await client.simctl.uiGet(target.id, \"content_size\"),\n statusBar: await client.simctl.statusBarList(target.id),\n },\n };\n }),\n );\n\n server.registerTool(\n \"ios_simulator_push\",\n {\n title: \"iOS Simulator: Push\",\n description:\n \"Deliver a push notification, with no APNs certificate and no server. The payload is a \" +\n \"normal remote-notification body and must contain an `aps` key. Only remote pushes are \" +\n \"simulated — not VoIP, complications or file-provider. The app must be installed; it does \" +\n \"not have to be running.\",\n inputSchema: z.object({\n device: deviceArg,\n bundle_id: bundleIdArg,\n payload: z\n .record(z.string(), z.unknown())\n .describe(\n 'The APNs payload, e.g. {\"aps\":{\"alert\":{\"title\":\"Watering due\",\"body\":\"Monstera\"},' +\n '\"sound\":\"default\",\"badge\":1}}. Max 4096 bytes.',\n ),\n }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },\n },\n async ({ device, bundle_id, payload }) =>\n wrap(async () => {\n if (!(\"aps\" in payload)) {\n throw new IosError(\"A push payload must have a top-level `aps` key.\", {\n remedy: 'Wrap the notification, e.g. {\"aps\":{\"alert\":\"Hello\"}}.',\n });\n }\n const bytes = Buffer.byteLength(JSON.stringify(payload));\n if (bytes > MAX_PUSH_BYTES) {\n throw new IosError(`The payload is ${bytes} bytes; APNs allows ${MAX_PUSH_BYTES}.`, {\n remedy: \"Shorten it — this is refused here rather than by simctl, but the cap is real.\",\n });\n }\n const target = client.requireBooted(await client.resolveTarget(device));\n await client.simctl.push(target.id, bundle_id, payload);\n return { pushed: bundle_id, bytes };\n }),\n );\n};\n","import type { McpServer } from \"@modelcontextprotocol/server\";\nimport { z } from \"zod\";\n\nimport { toListRow } from \"#/client/shape\";\nimport type { SimulatorClient } from \"#/client/simulator\";\nimport { confirmArg, deviceArg, wrap } from \"#/tools/util\";\n\n/** Booting is slow and visible; this is how long `power` waits to see it land. */\nconst BOOT_POLL_MS = 500;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport const registerListTool = (server: McpServer, client: SimulatorClient): void => {\n server.registerTool(\n \"ios_simulator_list\",\n {\n title: \"iOS Simulator: List\",\n description:\n \"List the simulators on this machine, with the UDID every other tool takes. Returns all \" +\n \"of them by default — booted and shut down, available and not — because \\\"why can't I use \" +\n 'that one\" has to be answerable from this list: a simulator whose runtime is missing shows ' +\n \"`available: false` with the reason.\",\n inputSchema: z.object({\n booted_only: z\n .boolean()\n .default(false)\n .describe(\"Only simulators that are currently running.\"),\n name_contains: z\n .string()\n .optional()\n .describe('Case-insensitive substring filter on the name, e.g. \"iPhone 17\".'),\n }),\n annotations: { readOnlyHint: true },\n },\n async ({ booted_only, name_contains }) =>\n wrap(async () => {\n const all = await client.listSimulators({ fresh: true });\n const needle = name_contains?.toLowerCase();\n const matched = all.filter(\n (sim) =>\n (!booted_only || sim.state === \"Booted\") &&\n (needle === undefined || sim.name.toLowerCase().includes(needle)),\n );\n const unavailable = all.filter((sim) => !sim.available).length;\n return {\n simulators: matched.map(toListRow),\n booted: all.filter((sim) => sim.state === \"Booted\").length,\n total: all.length,\n ...(unavailable > 0\n ? {\n unavailable,\n note:\n `${unavailable} simulators have no installed runtime and cannot be used. ` +\n \"`xcrun simctl delete unavailable` clears them.\",\n }\n : {}),\n };\n }),\n );\n};\n\nexport const registerLifecycleTools = (server: McpServer, client: SimulatorClient): void => {\n server.registerTool(\n \"ios_simulator_power\",\n {\n title: \"iOS Simulator: Power\",\n description:\n \"Boot or shut down a simulator. Booting is the one thing this server will not do for you \" +\n \"implicitly — a cold boot takes tens of seconds and puts a window on the user's screen, \" +\n \"and it changes which simulator an unqualified call resolves to afterwards. Both \" +\n \"directions are idempotent: booting a booted simulator succeeds.\",\n inputSchema: z.object({\n device: deviceArg,\n state: z\n .enum([\"booted\", \"shutdown\"])\n .describe(\"The state to put it in. `booted` also waits for it to actually get there.\"),\n open_window: z\n .boolean()\n .default(true)\n .describe(\n \"Bring up the Simulator app so the screen is visible. A `boot` on its own is headless, \" +\n \"which is fine for an agent and confusing for a person watching.\",\n ),\n wait_ms: z\n .number()\n .int()\n .min(0)\n .max(300_000)\n .default(60_000)\n .describe(\"How long to wait for a boot to complete before reporting what it saw.\"),\n }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n },\n async ({ device, state, open_window, wait_ms }) =>\n wrap(async () => {\n const target = await client.resolveTarget(device);\n if (state === \"shutdown\") {\n if (target.state !== \"Booted\") {\n return { udid: target.id, name: target.name, state: \"Shutdown\", alreadyThere: true };\n }\n await client.simctl.shutdown(target.id);\n return { udid: target.id, name: target.name, state: \"Shutdown\" };\n }\n\n const already = target.state === \"Booted\";\n if (!already) await client.simctl.boot(target.id);\n if (open_window) await client.simctl.openApp(client.openPath);\n\n // Poll rather than trust the exit code: `simctl boot` returns as soon as\n // CoreSimulator has accepted the request, well before the device is\n // usable, and every tool after this one would fail on a half-booted one.\n const deadline = Date.now() + wait_ms;\n let observed = target.state;\n while (Date.now() < deadline) {\n const now = (await client.listSimulators({ fresh: true })).find(\n (sim) => sim.id === target.id,\n );\n observed = now?.state ?? observed;\n if (observed === \"Booted\") break;\n await sleep(BOOT_POLL_MS);\n }\n return {\n udid: target.id,\n name: target.name,\n state: observed,\n ...(already ? { alreadyThere: true } : {}),\n ...(observed === \"Booted\"\n ? {}\n : { warning: `Still ${observed} after ${wait_ms}ms. Raise wait_ms, or check Xcode.` }),\n };\n }),\n );\n\n server.registerTool(\n \"ios_simulator_erase\",\n {\n title: \"iOS Simulator: Erase\",\n description:\n \"Wipe a simulator back to a factory state: installed apps, their data, the keychain and \" +\n \"every granted permission. The only irreversible tool here, and the reason it is the only \" +\n \"one behind `confirm`. Use it to test a genuine first launch. A booted simulator is shut \" +\n \"down first and booted again afterwards, because simctl refuses to erase a running one.\",\n inputSchema: z.object({\n device: deviceArg,\n confirm: confirmArg,\n }),\n annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false },\n },\n async ({ device }) =>\n wrap(async () => {\n const target = await client.resolveTarget(device);\n const wasBooted = target.state === \"Booted\";\n if (wasBooted) await client.simctl.shutdown(target.id);\n await client.simctl.erase(target.id);\n if (wasBooted) await client.simctl.boot(target.id);\n return {\n udid: target.id,\n name: target.name,\n erased: true,\n rebooted: wasBooted,\n };\n }),\n );\n};\n","import { spawn } from \"node:child_process\";\nimport { mkdir, open } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { McpServer } from \"@modelcontextprotocol/server\";\nimport { z } from \"zod\";\n\nimport { IosError, START_RUNNER_REMEDY } from \"#/client/errors\";\nimport type { SimulatorClient } from \"#/client/simulator\";\nimport { deviceArg, wrap } from \"#/tools/util\";\n\n/** Injected in tests so no xcodebuild is ever started by the suite. */\nexport type SpawnRunner = (\n command: string,\n args: string[],\n opts: { env: Record<string, string>; logPath: string },\n) => Promise<number | undefined>;\n\nconst defaultSpawnRunner: SpawnRunner = async (command, args, { env, logPath }) => {\n await mkdir(dirname(logPath), { recursive: true });\n const log = await open(logPath, \"a\");\n const child = spawn(command, args, {\n // Detached, because the XCTest session *is* the HTTP server: it has to\n // outlive this MCP server, or the runner dies with the conversation.\n detached: true,\n stdio: [\"ignore\", log.fd, log.fd],\n env: { ...process.env, ...env },\n });\n child.unref();\n await log.close();\n return child.pid;\n};\n\nconst scriptPath = (): string => {\n // Beside the built module in dist/, or beside src/ in a checkout.\n const here = dirname(fileURLToPath(import.meta.url));\n for (const candidate of [\n join(here, \"..\", \"scripts\", \"wda.sh\"),\n join(here, \"..\", \"..\", \"scripts\", \"wda.sh\"),\n ]) {\n return candidate;\n }\n throw new IosError(\"Could not find `scripts/wda.sh` beside this module.\");\n};\n\nexport const registerRunnerTools = (\n server: McpServer,\n client: SimulatorClient,\n outputDir: string,\n spawnRunner: SpawnRunner = defaultSpawnRunner,\n): void => {\n server.registerTool(\n \"ios_simulator_restart_wda\",\n {\n title: \"iOS Simulator: Restart WebDriverAgent\",\n description:\n \"Start the WebDriverAgent runner, or restart it after it has died. Only the UI tree and \" +\n \"the input tools need it — screenshots and everything simctl does keep working without \" +\n \"it. The runner is started detached so it outlives this conversation, and its output goes \" +\n \"to a log file rather than to you. It does not wait: give it fifteen seconds or so, then \" +\n \"check ios_simulator_diagnostics.\",\n inputSchema: z.object({\n device: deviceArg,\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe(\n \"Port to bind, passed to the runner as USE_PORT. Defaults to IOS_SIMULATOR_WDA_PORT. \" +\n \"Two simulators need two ports: they share this Mac's loopback, and a runner with \" +\n \"no USE_PORT scans 8100-8199 and silently takes the next free one.\",\n ),\n }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },\n },\n async ({ device, port }) =>\n wrap(async () => {\n const target = client.requireBooted(await client.resolveTarget(device));\n const usePort = port ?? client.wdaPort;\n const logPath = join(outputDir, \"wda.log\");\n const pid = await spawnRunner(\"/bin/bash\", [scriptPath(), \"run\"], {\n env: {\n IOS_SIMULATOR_ID: target.id,\n IOS_SIMULATOR_WDA_PORT: String(usePort),\n USE_PORT: String(usePort),\n },\n logPath,\n });\n if (pid === undefined) {\n throw new IosError(\"Could not start the runner — the process had no pid.\", {\n remedy: START_RUNNER_REMEDY,\n });\n }\n return {\n started: true,\n pid,\n port: usePort,\n udid: target.id,\n logPath,\n note: \"Give it ~15s, then check ios_simulator_diagnostics for `wda.reachable`.\",\n };\n }),\n );\n};\n","import { registerInputTools, registerScreenTools } from \"@mgcrea/mcp-ios-core\";\nimport type { McpServer } from \"@modelcontextprotocol/server\";\n\nimport { EMPTY_SCREENSHOT_REMEDY } from \"#/client/errors\";\nimport type { SimulatorClient } from \"#/client/simulator\";\nimport type { Config } from \"#/config\";\nimport { registerAppTools, registerListAppsTool } from \"#/tools/apps\";\nimport { registerDiagnosticsTools } from \"#/tools/diagnostics\";\nimport { registerEnvironmentTools } from \"#/tools/environment\";\nimport { registerLifecycleTools, registerListTool } from \"#/tools/lifecycle\";\nimport { registerRunnerTools, type SpawnRunner } from \"#/tools/runner\";\nimport { SIMULATOR_NAMING } from \"#/tools/util\";\n\nexport type ToolContext = {\n config: Config;\n /** On by default here — see IOS_SIMULATOR_ALLOW_WRITES. */\n allowWrites: boolean;\n};\n\n/**\n * All capability decisions in one place, so \"why can't I call that\" is answered\n * by one file.\n *\n * The split is observe versus drive, exactly as in the device server. What\n * differs is the **default**: writes are on. The convention that keeps the rest\n * of the fleet read-only exists because a mutating tool acts on someone's real\n * account or someone's real phone, and a simulator is neither — it holds no\n * person's data and `ios_simulator_erase` puts it back to factory in seconds.\n * Turning writes off with IOS_SIMULATOR_ALLOW_WRITES=0 restores the device\n * server's posture, and then the driving tools are *absent* rather than\n * refused, because a refusal still lets a model try, retry and reason about a\n * way around it.\n *\n * The observe half is unusually capable here: `screenshot` goes through simctl,\n * so seeing the screen needs no WebDriverAgent and no setup of any kind. Only\n * `ui_tree` does, and that is a runtime fact reported by\n * ios_simulator_diagnostics rather than a registration decision — the runner\n * can start and stop while this server is connected.\n */\nexport const registerTools = (\n server: McpServer,\n client: SimulatorClient,\n ctx: ToolContext,\n spawnRunner?: SpawnRunner,\n): void => {\n const shared = {\n host: client,\n naming: SIMULATOR_NAMING,\n maxTreeBytes: ctx.config.maxTreeBytes,\n capHint: \"raise IOS_SIMULATOR_MAX_TREE_BYTES\",\n // `home` is the gesture and works; a simulator has no volume rocker worth\n // pressing, and offering one that does nothing is worse than offering none.\n buttons: [\"home\"] as [string, ...string[]],\n emptyScreenshotRemedy: EMPTY_SCREENSHOT_REMEDY,\n // Geometry here is a local plist read reported on every screenshot, not a\n // slow round trip worth its own tool as it is on a device.\n includeDisplayInfo: false,\n };\n\n registerDiagnosticsTools(server, client, ctx);\n registerListTool(server, client);\n registerListAppsTool(server, client);\n registerScreenTools(server, shared);\n\n if (!ctx.allowWrites) return;\n\n registerInputTools(server, shared);\n registerLifecycleTools(server, client);\n registerAppTools(server, client, ctx.config.launchArgs, ctx.config.outputDir);\n registerEnvironmentTools(server, client);\n registerRunnerTools(server, client, ctx.config.outputDir, spawnRunner);\n};\n","import type { ExecImpl, Logger } from \"@mgcrea/mcp-ios-core\";\nimport { McpServer } from \"@modelcontextprotocol/server\";\n\nimport { BUILD_INFO } from \"#/build-info\";\nimport { SimulatorClient } from \"#/client/simulator\";\nimport type { Config } from \"#/config\";\nimport { registerTools } from \"#/tools/index\";\nimport type { SpawnRunner } from \"#/tools/runner\";\n\nexport const SERVER_NAME = BUILD_INFO.name;\nexport const SERVER_VERSION = BUILD_INFO.version;\n\nexport type CreateServerOptions = {\n config: Config;\n /** Override the process boundary (tests): `xcrun`, `plutil` and `sips` never run. */\n exec?: ExecImpl;\n /** Override HTTP to WebDriverAgent (tests). */\n fetch?: typeof fetch;\n /** Override starting the runner (tests): no process is spawned. */\n spawnRunner?: SpawnRunner;\n logger?: Logger;\n};\n\nexport type CreatedServer = {\n server: McpServer;\n client: SimulatorClient;\n};\n\n/**\n * A pure factory. The injectable seams — `exec`, `fetch` and `spawnRunner` —\n * are the whole reason the test suite can drive real tools through the real SDK\n * with no simulator, no Xcode, no WebDriverAgent and no process left running.\n * Nothing below `config.ts` reads `process.env`.\n */\nexport const createServer = (opts: CreateServerOptions): CreatedServer => {\n const { config } = opts;\n const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });\n\n const client = new SimulatorClient({\n xcrunPath: config.xcrunPath,\n sipsPath: config.sipsPath,\n plutilPath: config.plutilPath,\n openPath: config.openPath,\n execTimeoutMs: config.execTimeoutMs,\n wdaTimeoutMs: config.wdaTimeoutMs,\n wdaPort: config.wdaPort,\n ...(config.wdaUrl ? { wdaUrl: config.wdaUrl } : {}),\n ...(config.simulatorId ? { defaultSimulatorId: config.simulatorId } : {}),\n ...(opts.exec ? { exec: opts.exec } : {}),\n ...(opts.fetch ? { fetch: opts.fetch } : {}),\n ...(opts.logger ? { logger: opts.logger } : {}),\n });\n\n registerTools(server, client, { config, allowWrites: config.allowWrites }, opts.spawnRunner);\n\n return { server, client };\n};\n","import { readFileSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\n/**\n * There are no credentials here, and unlike the device server there is barely\n * any setup either. Two lanes reach a simulator and both are local:\n *\n * * `xcrun simctl` — Apple's own tool. It covers app lifecycle, the device's\n * whole staged environment, and the screen itself: `simctl io screenshot`\n * needs no runner at all.\n * * WebDriverAgent — an HTTP server inside the simulator, on the *host's*\n * loopback since a simulator shares the host network stack. Only the\n * accessibility tree and synthetic touches go through it.\n */\nconst ConfigSchema = z\n .object({\n /**\n * UDID, name, or the literal `booted`. Left unset, a single booted\n * simulator is used and two or more is an error that names them, rather\n * than the coin flip simctl's own `booted` performs.\n */\n simulatorId: z.string().min(1).optional(),\n wdaUrl: z.url().optional(),\n /**\n * Must match the runner's `USE_PORT`. One port per simulator: they all bind\n * the same host loopback, so two runners on 8100 is a silent wrong-target\n * bug rather than a collision.\n */\n wdaPort: z.number().int().min(1).max(65535).default(8100),\n wdaTimeoutMs: z.number().int().min(1000).max(600_000).default(30_000),\n /** A cold boot or a large `install` genuinely takes tens of seconds. */\n execTimeoutMs: z.number().int().min(1000).max(1_800_000).default(120_000),\n /**\n * **On by default**, which is the one place this server deliberately breaks\n * the fleet convention. What makes the device server read-only is that a\n * phone belongs to a real person; a simulator is disposable and holds\n * nobody's data. `ios_simulator_erase` still requires an explicit `confirm`\n * because it is the only irreversible tool here.\n */\n allowWrites: z.boolean().default(true),\n /** Applied by `launch` when the call passes no `arguments` of its own. */\n launchArgs: z.array(z.string()).default([]),\n /** Saved screenshots, launch logs and the runner log. */\n outputDir: z.string().min(1).default(join(tmpdir(), \"mcp-ios-simulator\")),\n maxTreeBytes: z.number().int().min(1000).max(500_000).default(24_000),\n xcrunPath: z.string().min(1).default(\"/usr/bin/xcrun\"),\n sipsPath: z.string().min(1).default(\"/usr/bin/sips\"),\n /** The `listapps` plist lane, and the device-type profile read. */\n plutilPath: z.string().min(1).default(\"/usr/bin/plutil\"),\n /** `simctl boot` is headless; this is what attaches a window. */\n openPath: z.string().min(1).default(\"/usr/bin/open\"),\n })\n .strict()\n .superRefine((_cfg, _ctx) => {\n // Deliberately NOT an error when there is no simulator and no Xcode. An MCP\n // server that exits on startup shows up in the client as a bare\n // \"MCP error -32000: Connection closed\" with stderr swallowed, so the one\n // message that would have explained the problem never reaches anyone.\n // ios_simulator_diagnostics reports all of it as data instead.\n });\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\nconst trimmed = (value: string | undefined): string | undefined => {\n const t = value?.trim();\n return t ? t : undefined;\n};\n\nconst parseBool = (value: string | undefined): boolean | undefined => {\n const t = trimmed(value);\n if (t === undefined) return undefined;\n return [\"1\", \"true\", \"yes\", \"on\"].includes(t.toLowerCase());\n};\n\nconst parseIntOpt = (value: string | undefined): number | undefined => {\n const t = trimmed(value);\n if (t === undefined) return undefined;\n const n = Number(t);\n return Number.isInteger(n) ? n : undefined;\n};\n\n/** Whitespace-separated, so `IOS_SIMULATOR_LAUNCH_ARGS=\"-DemoMode -NoCloud\"` works. */\nconst parseArgs = (value: string | undefined): string[] | undefined => {\n const t = trimmed(value);\n return t === undefined ? undefined : t.split(/\\s+/);\n};\n\nexport const defaultConfigPath = (env: NodeJS.ProcessEnv = process.env): string =>\n trimmed(env.IOS_SIMULATOR_CONFIG) ??\n join(homedir(), \".config\", \"ios-simulator-mcp\", \"config.json\");\n\n/**\n * `.strict()` on purpose: a typo'd `wdaPort` spelled `wda_port` must be an\n * error. Silently ignoring an unknown key looks exactly like \"that setting had\n * no effect\", which is the worst possible way to learn where your config came\n * from.\n */\nconst readConfigFile = (path: string): Partial<Config> => {\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return {};\n }\n return ConfigSchema.partial().strict().parse(JSON.parse(raw)) as Partial<Config>;\n};\n\n/**\n * Environment first, config file second, **per field** — not whole-source.\n * A one-off `IOS_SIMULATOR_ALLOW_WRITES=0` has to beat a file that says `true`,\n * while a file that sets `simulatorId` keeps working when the environment says\n * nothing about it. Merging field by field is the only rule that gives both.\n */\nexport const loadConfig = (\n env: NodeJS.ProcessEnv = process.env,\n configPath: string = defaultConfigPath(env),\n): Config => {\n const file = readConfigFile(configPath);\n const pick = <K extends keyof Config>(\n fromEnv: Config[K] | undefined,\n key: K,\n ): Config[K] | undefined => fromEnv ?? file[key];\n\n return ConfigSchema.parse({\n simulatorId: pick(trimmed(env.IOS_SIMULATOR_ID), \"simulatorId\"),\n wdaUrl: pick(trimmed(env.IOS_SIMULATOR_WDA_URL), \"wdaUrl\"),\n wdaPort: pick(parseIntOpt(env.IOS_SIMULATOR_WDA_PORT), \"wdaPort\"),\n wdaTimeoutMs: pick(parseIntOpt(env.IOS_SIMULATOR_WDA_TIMEOUT_MS), \"wdaTimeoutMs\"),\n execTimeoutMs: pick(parseIntOpt(env.IOS_SIMULATOR_TIMEOUT_MS), \"execTimeoutMs\"),\n allowWrites: pick(parseBool(env.IOS_SIMULATOR_ALLOW_WRITES), \"allowWrites\"),\n launchArgs: pick(parseArgs(env.IOS_SIMULATOR_LAUNCH_ARGS), \"launchArgs\"),\n outputDir: pick(trimmed(env.IOS_SIMULATOR_OUTPUT_DIR), \"outputDir\"),\n maxTreeBytes: pick(parseIntOpt(env.IOS_SIMULATOR_MAX_TREE_BYTES), \"maxTreeBytes\"),\n xcrunPath: pick(trimmed(env.IOS_SIMULATOR_XCRUN_PATH), \"xcrunPath\"),\n sipsPath: pick(trimmed(env.IOS_SIMULATOR_SIPS_PATH), \"sipsPath\"),\n plutilPath: pick(trimmed(env.IOS_SIMULATOR_PLUTIL_PATH), \"plutilPath\"),\n openPath: pick(trimmed(env.IOS_SIMULATOR_OPEN_PATH), \"openPath\"),\n });\n};\n"],"mappings":"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"}