Files
Paweł Fornagiel 55d1567d48 feat: improve iOS profiler startup, shutdown, and exit recovery (#181)
## Summary

Refactor of the iOS profiler (`xctrace`-driven) session to make start,
stop, and unexpected-exit handling proper, without the iOS hanging
infinitely.

### Startup (`ios-profiler-start`)
- **Locale ready signal**: subscribe-before-spawn to a Darwin
notification (`com.argent.ios-profiler.started.<pid>.<ts>`) via
`notifyutil`, passed through `xctrace --notify-tracing-started`. Falls
back to the existing stdout substring match (`Starting recording` /
`Ctrl-C to stop`) if `notifyutil` fails to spawn or register within 2 s.
- **Startup timeout**: new 10 s cap on reaching the ready state — on
timeout, `SIGKILL` the child so it cannot leak.
- **Bounded `simctl` calls**: `detectRunningApp` now applies a 10 s
timeout to both `xcrun simctl spawn ... launchctl list` and `xcrun
simctl listapps`, with explicit error messages telling the user to
verify the simulator is booted.
- **Cold-start retry**: if xctrace's process resolver fails with
`"Cannot find process matching name:"` (launchd has registered the
bundle but xctrace's resolver hasn't caught up), the tool retries once
after a 1.2 s backoff — up to 2 attempts total. On exhausted retries
throws a classified error naming the cold-launch race and pointing at
`app_process` as the override. Non-cold-start failures propagate
immediately without retry.
- **Exit listener installed**: every `xctrace record` child gets a
long-lived `'exit'` handler (`handleXctraceExit`) that marks the session
as `recordingExitedUnexpectedly` and stores `lastExitInfo`.

### Shutdown (`ios-profiler-stop`)
- **SIGINT → SIGTERM → SIGKILL ladder** via
`utils/ios-profiler/lifecycle.ts::shutdownChild` (30 s grace, 5 s term,
5 s kill).
- **Returns a `warning`** when the ladder had to escalate past SIGINT,
so callers know the trace bundle may be incomplete.

### Exit recovery
- **New `recordingTimedOut` / `recordingExitedUnexpectedly` flags** on
the session API. If `ios-profiler-stop` is called after either fired,
the tool now exports whatever `.trace` bundle is on disk and returns it
with a descriptive `warning` instead of throwing "no active session".
- Covers the in-process 10-min recording cap, attached-app crashes, and
simulator daemon hiccups.

### Dispose semantics
- Registry teardown (process shutdown) skips SIGINT and goes straight to
`SIGKILL` with a 1 s reap window. The explicit `ios-profiler-stop`
contract is the only path that takes the slow finalise grace.

### Other
- `utils/ios-profiler/run-with-timeout.ts`: `execSyncWithTimeout`
wrapper with a 60 s default — guards every shelled-out `xctrace export`
/ `xctrace version`.
- New reference doc `utils/ios-profiler/IOS_PROFILER_REFERENCE.md`
covering the native foundations, capture flow, and pipeline.

## Tests
New unit tests under `packages/tool-server/test/ios-instruments/`

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 09:26:57 +02:00
..