Files
Conor Luddy 5dd6a84593 fix(xcode27): keep xcrun working under the shim, auto-retire stale companions
Two follow-ups to #100, both found while investigating #101.

1. The shim's DEVELOPER_DIR broke every xcrun call in the same process.
   `common/__init__` sets DEVELOPER_DIR process-wide, and xcrun walks up from
   it looking for an enclosing .app bundle - a shim root named
   `xcode27-idb-shim` has none, so xcrun refused it outright:

     xcrun: error: unable to find Xcode installation from active developer
     path ".../xcode27-idb-shim/Contents/Developer"

   That broke all 22 scripts that shell out to `xcrun simctl` (screenshots,
   boot, io) on any Xcode 27 machine. Renaming the shim root to
   `Xcode27Shim.app` satisfies xcrun; idb is indifferent to the name. The
   pre-.app root is removed on next run.

2. A companion started before the shim stays broken for its whole lifetime -
   it inherits DEVELOPER_DIR once, at launch, and `idb connect` reuses the
   live process rather than replacing it. Scripts now retire any companion
   whose DEVELOPER_DIR is not the shim's.

   Killing the process alone is not enough: idb's registry at /tmp/idb/state
   still names the dead pid and its socket, so the next call dials a dead
   socket ("Connection refused") instead of spawning a replacement. Retired
   companions are evicted from the registry and their sockets unlinked, which
   removes the manual `pkill -f idb_companion` + `rm -f *.sock` dance from
   the #101 repro.

Verified on Xcode 27 / iOS 27.0 / iPhone 17 Pro: shim rebuilds from scratch,
xcrun and idb both work through it, a deliberately stale companion is retired
and recovered from transparently, and navigator.py taps land on screen.

Refs #100, #101
2026-09-12 07:49:07 +01:00
..