Skip to content

Commit a5d7071

Browse files
authored
Merge pull request #162 from Lykhoyda/fix/gh-105-repair-action-kill-fast-runner
fix(gh-105): kill fast-runner before simctl launch in cdp_repair_action — closes the live focus race
2 parents 164ddde + d677f10 commit a5d7071

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

scripts/cdp-bridge/dist/tools/repair-action.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { repairBudgetAvailable } from '../domain/reusable-action.js';
1616
import { snapshotEnvelopeFailed } from './device-batch.js';
1717
import { resolveBundleId } from '../project-config.js';
1818
import { isAgentDeviceRunnerSentinel } from './runner-leak-recovery.js';
19+
import { stopFastRunner } from '../fast-runner-session.js';
1920
const execFile = promisify(execFileCb);
2021
/**
2122
* GH #105 / B153: bring the target app to foreground BEFORE taking the
@@ -24,12 +25,31 @@ const execFile = promisify(execFileCb);
2425
* no testIDs of its own. That yields the misleading "snapshot returned 0
2526
* testIDs" failure on a perfectly healthy app.
2627
*
28+
* **Live-smoke-test discovery (GH #105 follow-up):** `simctl launch` alone
29+
* loses the focus race when the agent-device fast-runner (spawned by the
30+
* prior `maestro_run`) is still alive — `XCUIApplication.activate()` inside
31+
* the runner re-foregrounds the runner before the snapshot lands. The fix
32+
* is to `stopFastRunner()` FIRST so there's nothing competing for focus,
33+
* THEN `simctl launch` the test-app. The next `runAgentDevice(snapshot)`
34+
* will lazily re-spawn the fast-runner, which is fine because by then
35+
* agent-device knows which bundle to attach to (it inherits the foreground
36+
* app's XCUIApplication).
37+
*
2738
* Best-effort: silent failure means we still fall through to the snapshot,
2839
* which can still detect the runner-leak sentinel and surface a useful
2940
* error. iOS uses `simctl launch booted <bundleId>`; Android uses `am start`
3041
* via adb.
3142
*/
3243
async function bringTargetAppToForeground(platform, bundleId) {
44+
// Kill the fast-runner FIRST so it can't re-grab focus the moment we
45+
// simctl-launch the test-app. Equivalent step exists in cdp_restart
46+
// hardReset (PR #161); this is its single-tool counterpart inside the
47+
// repair path so users don't have to call cdp_restart manually after
48+
// a SELECTOR_NOT_FOUND.
49+
try {
50+
stopFastRunner();
51+
}
52+
catch { /* best-effort — fast-runner may already be dead */ }
3353
try {
3454
if (platform === 'android') {
3555
await execFile('adb', ['shell', 'monkey', '-p', bundleId, '-c', 'android.intent.category.LAUNCHER', '1'], { timeout: 5000, encoding: 'utf8' });

scripts/cdp-bridge/src/tools/repair-action.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { repairBudgetAvailable } from '../domain/reusable-action.js';
2727
import { snapshotEnvelopeFailed } from './device-batch.js';
2828
import { resolveBundleId } from '../project-config.js';
2929
import { isAgentDeviceRunnerSentinel, type RunnerLeakNode } from './runner-leak-recovery.js';
30+
import { stopFastRunner } from '../fast-runner-session.js';
3031

3132
const execFile = promisify(execFileCb);
3233

@@ -37,6 +38,16 @@ const execFile = promisify(execFileCb);
3738
* no testIDs of its own. That yields the misleading "snapshot returned 0
3839
* testIDs" failure on a perfectly healthy app.
3940
*
41+
* **Live-smoke-test discovery (GH #105 follow-up):** `simctl launch` alone
42+
* loses the focus race when the agent-device fast-runner (spawned by the
43+
* prior `maestro_run`) is still alive — `XCUIApplication.activate()` inside
44+
* the runner re-foregrounds the runner before the snapshot lands. The fix
45+
* is to `stopFastRunner()` FIRST so there's nothing competing for focus,
46+
* THEN `simctl launch` the test-app. The next `runAgentDevice(snapshot)`
47+
* will lazily re-spawn the fast-runner, which is fine because by then
48+
* agent-device knows which bundle to attach to (it inherits the foreground
49+
* app's XCUIApplication).
50+
*
4051
* Best-effort: silent failure means we still fall through to the snapshot,
4152
* which can still detect the runner-leak sentinel and surface a useful
4253
* error. iOS uses `simctl launch booted <bundleId>`; Android uses `am start`
@@ -46,6 +57,14 @@ async function bringTargetAppToForeground(
4657
platform: string,
4758
bundleId: string,
4859
): Promise<void> {
60+
// Kill the fast-runner FIRST so it can't re-grab focus the moment we
61+
// simctl-launch the test-app. Equivalent step exists in cdp_restart
62+
// hardReset (PR #161); this is its single-tool counterpart inside the
63+
// repair path so users don't have to call cdp_restart manually after
64+
// a SELECTOR_NOT_FOUND.
65+
try {
66+
stopFastRunner();
67+
} catch { /* best-effort — fast-runner may already be dead */ }
4968
try {
5069
if (platform === 'android') {
5170
await execFile(

0 commit comments

Comments
 (0)