(params: {
req: DaemonRequest;
sessionName: string;
logPath: string;
sessionStore: SessionStore;
leaseRegistry: LeaseRegistry;
leaseLifecycleProvider?: LeaseLifecycleProvider;
})
| 58 | } |
| 59 | |
| 60 | export async function handleCloseCommand(params: { |
| 61 | req: DaemonRequest; |
| 62 | sessionName: string; |
| 63 | logPath: string; |
| 64 | sessionStore: SessionStore; |
| 65 | leaseRegistry: LeaseRegistry; |
| 66 | leaseLifecycleProvider?: LeaseLifecycleProvider; |
| 67 | }): Promise<DaemonResponse> { |
| 68 | const { req, sessionName, logPath, sessionStore, leaseRegistry, leaseLifecycleProvider } = params; |
| 69 | const session = sessionStore.get(sessionName); |
| 70 | if (!session) { |
| 71 | return await closeWithoutSession(req, logPath); |
| 72 | } |
| 73 | let providerData: Record<string, unknown> | undefined; |
| 74 | try { |
| 75 | await stopSessionAppLog(session); |
| 76 | await stopSessionAudioProbe(session, 'session-close'); |
| 77 | await stopSessionApplePerfCapture(session); |
| 78 | await stopSessionAndroidNativePerfCapture(session); |
| 79 | await stopSessionAndroidSnapshotHelper(session); |
| 80 | if (shouldDispatchPlatformClose(req, session)) { |
| 81 | if (shouldStopAppleRunnerBeforeTargetedClose(session)) { |
| 82 | await stopAppleRunnerForClose(session); |
| 83 | } |
| 84 | await dispatchCommand(session.device, 'close', req.positionals ?? [], req.flags?.out, { |
| 85 | ...contextFromFlags(logPath, req.flags, session.appBundleId, session.trace?.outPath), |
| 86 | }); |
| 87 | await settleIosSimulator(session.device, IOS_SIMULATOR_POST_CLOSE_SETTLE_MS); |
| 88 | } |
| 89 | if ( |
| 90 | isApplePlatform(session.device.platform) && |
| 91 | !shouldRetainAppleRunnerAfterClose(req, session) |
| 92 | ) { |
| 93 | // The targeted close path stops before dispatch to avoid runner/app races. |
| 94 | // Stop again here for idempotent cleanup, and keep cleanup-sensitive closes explicit. |
| 95 | await stopAppleRunnerForClose(session); |
| 96 | } else if (isApplePlatform(session.device.platform)) { |
| 97 | emitDiagnostic({ |
| 98 | level: 'debug', |
| 99 | phase: 'ios_runner_retained_after_close', |
| 100 | data: { |
| 101 | session: session.name, |
| 102 | deviceId: session.device.id, |
| 103 | }, |
| 104 | }); |
| 105 | // A retained runner holds the device's runner lease against every other |
| 106 | // daemon; bound that with an idle stop unless something reuses it first. |
| 107 | scheduleIosRunnerIdleStop(session.device.id); |
| 108 | } |
| 109 | const runtime = sessionStore.getRuntimeHints(sessionName); |
| 110 | if (hasRuntimeTransportHints(runtime) && session.appBundleId) { |
| 111 | await clearRuntimeHintsFromApp({ |
| 112 | device: session.device, |
| 113 | appId: session.appBundleId, |
| 114 | }).catch(() => {}); |
| 115 | } |
| 116 | recordSessionAction(sessionStore, session, req, 'close', { |
| 117 | session: session.name, |
no test coverage detected