@@ -3,6 +3,7 @@ import type {
33 CleanupOutcome ,
44 DurableDescriptorCodec ,
55 ManagedProcessIdentity ,
6+ OwnedProcessRecordScope ,
67 RuntimeOwnerRef ,
78 ScreenRecordingRuntimeHost ,
89 ScreenRecordingStartInput ,
@@ -11,7 +12,10 @@ import { SCREEN_RECORDING_RESOURCE_KIND } from '@agent-device/contracts/screen-r
1112import { createDurableResourceEnvelope , encodeDurableDescriptor } from '@agent-device/capture-kit' ;
1213
1314export type AppleScreenRecordingOperationHost = Readonly < {
14- screenRecording : Pick < ScreenRecordingRuntimeHost , 'apple' | 'finalize' | 'outputs' > ;
15+ screenRecording : Pick <
16+ ScreenRecordingRuntimeHost ,
17+ 'apple' | 'finalize' | 'outputs' | 'ownedProcesses'
18+ > ;
1519} > ;
1620
1721export type AppleRecordingDescriptor =
@@ -83,40 +87,55 @@ export async function cleanupAppleRecording(
8387 host : AppleScreenRecordingOperationHost ,
8488 device : DeviceInfo ,
8589 body : Parameters < AppleRecordingDescriptorCodec [ 'decode' ] > [ 0 ] ,
90+ sessionId ?: string ,
8691) : Promise < CleanupOutcome > {
8792 const decoded = descriptorCodec . decode ( body ) ;
8893 if ( decoded . status !== 'decoded' || ! descriptorMatchesAppleDevice ( device , decoded . descriptor ) ) {
8994 return { status : 'cleanup-pending' , reason : 'manual-recovery-required' } ;
9095 }
9196 if ( decoded . descriptor . backend === 'simctl' ) {
92- return await cleanupSimulator ( host , decoded . descriptor . processes ) ;
97+ return await cleanupSimulator ( host , decoded . descriptor . processes , sessionId ) ;
9398 }
9499 return await cleanupRunner ( host , device , decoded . descriptor ) ;
95100}
96101
97102async function cleanupSimulator (
98103 host : AppleScreenRecordingOperationHost ,
99104 processes : readonly ManagedProcessIdentity [ ] ,
105+ sessionId ?: string ,
100106) : Promise < CleanupOutcome > {
101107 const ownership = await Promise . all (
102108 processes . map ( async ( marker ) => await host . screenRecording . apple . inspectProcess ( marker ) ) ,
103109 ) ;
104110 if ( ownership . includes ( 'ownership-lost' ) ) {
105111 return { status : 'cleanup-pending' , reason : 'ownership-fence-lost' } ;
106112 }
107- if ( ownership . every ( ( value ) => value === 'missing' ) ) return { status : 'already-missing' } ;
113+ if ( ownership . every ( ( value ) => value === 'missing' ) ) {
114+ if ( sessionId !== undefined ) {
115+ host . screenRecording . ownedProcesses . clear ( sessionScope ( sessionId ) ) ;
116+ }
117+ return { status : 'already-missing' } ;
118+ }
108119 const outcomes = await Promise . all (
109120 processes . flatMap ( ( marker , index ) =>
110121 ownership [ index ] === 'owned-alive'
111122 ? [ host . screenRecording . apple . terminateProcess ( marker ) ]
112123 : [ ] ,
113124 ) ,
114125 ) ;
115- return outcomes . includes ( 'ownership-lost' )
116- ? { status : 'cleanup-pending' , reason : 'ownership-fence-lost' }
117- : outcomes . every ( ( outcome ) => outcome === 'already-missing' )
118- ? { status : 'already-missing' }
119- : { status : 'cleaned' } ;
126+ if ( outcomes . includes ( 'ownership-lost' ) ) {
127+ return { status : 'cleanup-pending' , reason : 'ownership-fence-lost' } ;
128+ }
129+ if ( sessionId !== undefined ) {
130+ host . screenRecording . ownedProcesses . clear ( sessionScope ( sessionId ) ) ;
131+ }
132+ return outcomes . every ( ( outcome ) => outcome === 'already-missing' )
133+ ? { status : 'already-missing' }
134+ : { status : 'cleaned' } ;
135+ }
136+
137+ function sessionScope ( sessionId : string ) : OwnedProcessRecordScope {
138+ return { kind : 'session' , sessionId } ;
120139}
121140
122141async function cleanupRunner (
0 commit comments