feat(provider-nomac): NoMac Simulator as a provider plugin

GE
3d ago
+2867-43

Adds NoMac Simulator as a provider plugin, @agent-device/nomac, beside TestMu and Limrun. NoMac Simulator gives an agent an iPhone 17 Pro or iPad Pro 11-inch (M5) Simulator on iOS 27, on Apple silicon Macs, from any machine. I work on NoMac.

What it adds

  • packages/provider-nomac: the version 2 plugin (credential NOMAC_API_KEY, optional NOMAC_BASE_URL), connect nomac, the provider runtime, the platform runtime, an interactor and a snapshot adapter, with 24 tests.
  • A lease is a phone. It starts under the lease's own request key, so a retried allocation reaches the same phone and never bills twice; it stops on close; a lease the daemon lost track of is found by its label and stopped.
  • Devices: --device iphone|ipad (or the model's name), both on iOS 27. --provider-os-version takes only 27; every other cloud profile flag is refused by name.
  • Commands: snapshot (the phone's accessibility tree through a new nomac-ios-tree producer, with the same capability facts as limrun-ios-tree), screenshot, tap, long press, fill, type, scroll, back, home, open (app or deep link), close, install (a Simulator .app, .zip or .tar.gz). Every operation a NoMac phone does not serve is an unavailable fact with its reason.
  • Docs: a NoMac page, a column in the device-clouds comparison, and the plugin in connect's optional-provider catalog.
  • Requests carry agent-device-cli/<version> as their User-Agent, as the other providers do.

Changes outside the package

  • nomac-ios-tree joins the iOS producer unions in contracts and kernel, and the keyboard-occlusion notes that list the producers without window ancestry.
  • kernel/src/snapshot.ts was at its 1,000-line cap, and adding the producer wrapped the union onto seven lines. I moved SnapshotProvenance into kernel/src/snapshot-provenance.ts (beside the existing snapshot-provenance.test.ts), imported and re-exported from snapshot.ts, so the public surface is unchanged and the file is 979 lines. Happy to do this another way if you prefer.
  • Registration, mirroring @agent-device/testmu: the layering model, examples/sdk/tsconfig.json, tsconfig.typecheck.json, and the root manifest's workspace dependency.

Validation

  • pnpm check:affected --run --head a627d02c7 at this commit (exactCommit: true): format, lint, typecheck, layering, di-seams, fallow, mcp-metadata, build, package, integration-node and macos-coverage pass. vitest-related ran 17,287 tests: 2 failed, both 5 s timeouts of the fast-check properties in packages/platform-android/src/manifest.test.ts, which this change does not touch (5.0 s each even run alone on my laptop, and they timed out on main here too).
  • The provider's 24 tests cover the lease (idempotent start, release, the lost lease found by its label), the platform runtime's facts, the interactor and the snapshot adapter, against a fake NoMac API.
  • On production, October 24, with the agent-device CLI built from this branch and the plugin installed as the store installs it: plugins list shows it compatible; connect nomac verified the key; install (phone start, upload, install) 15 to 49 s; open 6 s; snapshot -i 1.7 to 4.9 s with refs; fill the email and password, then click 'label="Sign In"', signed in.

Notes

  • fallow audit passes and lists, as warnings, the root manifest's @agent-device/nomac entry as an unused devDependency (project-references.test.ts requires every workspace package there, and nothing at the root imports the plugin, unlike TestMu's root connect test), the root's existing unused devDependencies (touched because the change edits package.json), and the two fallow-ignore lines in tmp-dir.fixtures.ts, copied from TestMu's fixture of the same name.
  • A NoMac account and API key are needed for live runs; happy to arrange a key for review.

🤖 Generated with Claude Code