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

GE
9h ago
+3598-113

Adds NoMac Simulator as a provider plugin, @agent-device/nomac, beside TestMu and Revyl. NoMac Simulator gives an agent an iPhone 17 Pro, iPhone 17 Pro Max 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 (credentials NOMAC_API_KEY and optional NOMAC_API_URL), connect nomac, the provider runtime, the platform runtime, an interactor and the snapshot fetch, with 40 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. Every failed or cancelled allocation stops the phone it started, with a stop the abort cannot cancel, and a cancelled one ends with the daemon's own cancellation.
  • Devices: --device iphone|iphone-pro-max|ipad (or the model's name), all on iOS 27. --provider-os-version takes 27 or a 27.x version; every other cloud profile flag is refused by name.
  • Commands: snapshot (the phone's accessibility tree, read through capture-kit/ios-ax-tree as Limrun's and Revyl's are, under a nomac-ios-tree producer with the same capability facts), screenshot, tap, long press, fill, type, scroll, back, home, open (app or deep link, with launch arguments), close, install (a Simulator .app, .zip or .tar.gz), trigger-app-event. Every operation a NoMac phone does not serve is an unavailable fact or a refusal with its reason.
  • Docs: a NoMac page, a column in the device-clouds comparison, the site's cloud list, and the plugin in connect's optional-provider catalog and the remote CLI help.
  • Requests carry agent-device-cli/<version> as their User-Agent, as the other providers do.

Changes outside the package

  • nomac-ios-tree sits beside revyl-ios-tree at every producer site: the iOS producer unions in contracts and kernel, the capability tables, stable-capture, the keyboard-occlusion notes, the presentation lists and the layering policy.
  • kernel/src/snapshot.ts is at its 1,000-line cap on main, and the added producer wraps the union onto more 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 978 lines.
  • Registration, mirroring @agent-device/revyl: the layering model, examples/sdk/tsconfig.json, tsconfig.typecheck.json, the root manifest's workspace dependency, fallow's entry points, and a NoMac iOS column in the capability matrix (collected from the plugin's runtime against a fake NoMac API; capabilities.md regenerated).
  • CLI help: NoMac's Providers line and credential sentence. The "Plugin installation" block moves below "Device cloud interfaces": left where it was, the NoMac Providers line and the catalog's NoMac plugin line put the MCP rule on line 32 of help remote, and cli-help-first-screen.test.ts requires it in the first 30 lines.
  • scripts/check-provider-plugin.mjs reads a version 2 plugin's provider from its smoke fixture, since a version 2 manifest doesn't name it.

Validation

  • Local gates and the live transcript at the head are in the comments below. The repository's workflows don't run on this fork PR.
  • The provider's 40 tests run against a fake NoMac API: the lease (idempotent start, release, the lost lease found by its label, and every failed or cancelled allocation), the client's budgets and typed errors, the platform runtime's facts, the interactor and the snapshot fetch.

Notes

  • fallow audit passes, with warnings: small clone groups shared with Limrun, Revyl and testmu, and the two fallow-ignore lines in tmp-dir.fixtures.ts, copied from TestMu's fixture of the same name.
  • The lease bookkeeping in runtime.ts (the sessions map, allocate-once, stopping a failed allocation's phone, the label lookup and its retry, release by label, shutdown) can move onto the shared table #4102 plans, once it lands.
  • A NoMac account and API key are needed for live runs; happy to arrange a key for review.