@@ -29,11 +29,7 @@ import type {
2929} from '@agent-device/contracts/client' ;
3030import type { AgentArtifactsResult } from '@agent-device/contracts/observability' ;
3131import type { MetroPrepareOptions } from '@agent-device/contracts/remote' ;
32- import {
33- isNonDefaultResponseLevel ,
34- type ResponseLevel ,
35- type SessionRuntimeHints ,
36- } from '@agent-device/kernel/contracts' ;
32+ import { isNonDefaultResponseLevel , type ResponseLevel } from '@agent-device/kernel/contracts' ;
3733import { AppError , throwDaemonError } from '@agent-device/kernel/errors' ;
3834import { createRequestId } from '@agent-device/host-kit/diagnostics' ;
3935import {
@@ -54,7 +50,7 @@ import {
5450 readSnapshotNodes ,
5551 resolveSessionName ,
5652} from './client/client-normalizers.ts' ;
57- import type { AgentDeviceClient , MetroPrepareResult } from './client/client-types.ts' ;
53+ import type { AgentDeviceClient } from './client/client-types.ts' ;
5854import { INTERNAL_COMMANDS } from '@agent-device/command-registry/catalog' ;
5955import { buildRequestFlags } from './commands/command-flags.ts' ;
6056import {
@@ -64,13 +60,12 @@ import {
6460import type { CommandResult } from '@agent-device/command-registry/command-result' ;
6561import { sendToDaemon } from './daemon-client/daemon-client.ts' ;
6662import { resolveDaemonPaths } from '@agent-device/daemon-contracts/daemon-resolution' ;
67- import { resolveMetroServerUrl } from './metro/metro-reload-endpoints.ts' ;
6863import { prepareMetroRuntime , reloadMetro } from './metro/client-metro.ts' ;
6964import {
70- clearMetroSessionHints ,
71- readMetroSessionHints ,
72- writeMetroSessionHints ,
73- type MetroSessionHints ,
65+ clearMetroSessionHintsQuietly ,
66+ recordPreparedMetroSession ,
67+ recordOpenedMetroSession ,
68+ readMetroSessionRuntime ,
7469} from './metro/metro-session-hints.ts' ;
7570import {
7671 asOptionalRecord ,
@@ -226,7 +221,7 @@ export function createAgentDeviceClient(
226221 } ;
227222 } finally {
228223 // Close is teardown intent: drop the dev-server binding even if the daemon call fails.
229- clearMetroSessionHintsQuietly ( config , options ) ;
224+ clearMetroSessionHintsQuietly ( metroSessionHintsScope ( config , options ) ) ;
230225 }
231226 } ,
232227 saveScript : async (
@@ -281,9 +276,8 @@ export function createAgentDeviceClient(
281276 open : async ( options : AppOpenOptions ) => {
282277 const session = resolveRequestSession ( options ) ;
283278 const data = await executeCommand < Record < string , unknown > > ( 'open' , options ) ;
284- recordMetroSessionHintsAfterOpen ( {
285- config,
286- options,
279+ recordOpenedMetroSession ( metroSessionHintsScope ( config , options ) , {
280+ explicitRuntime : options . runtime !== undefined ,
287281 runtime : mergeClientOptions ( config , options ) . runtime ,
288282 sessionReused : data . sessionReused === true ,
289283 } ) ;
@@ -367,16 +361,13 @@ export function createAgentDeviceClient(
367361 runtimeFilePath : options . runtimeFilePath ,
368362 logPath : options . logPath ,
369363 } ) ;
370- persistMetroSessionHints ( config , result ) ;
364+ recordPreparedMetroSession ( metroSessionHintsScope ( config ) , result ) ;
371365 return result ;
372366 } ,
373367 reload : async ( options = { } ) =>
374368 await reloadMetro ( {
375- metroHost : options . metroHost ,
376- metroPort : options . metroPort ,
377- bundleUrl : options . bundleUrl ,
378- runtime : resolveMetroSessionHints ( config ) ?? config . runtime ,
379- timeoutMs : options . timeoutMs ,
369+ ...options ,
370+ runtime : readMetroSessionRuntime ( metroSessionHintsScope ( config ) ) ?? config . runtime ,
380371 } ) ,
381372 } ,
382373 capture : {
@@ -597,90 +588,4 @@ function metroSessionHintsScope(
597588 } ;
598589}
599590
600- // The metro-sessions file is the session's dev-server binding; see MetroSessionHints.
601- function persistMetroSessionHints (
602- config : AgentDeviceClientConfig ,
603- result : Pick < MetroPrepareResult , 'statusUrl' | 'iosRuntime' | 'androidRuntime' > ,
604- ) : void {
605- try {
606- const deviceBaseUrls = new Set < string > ( ) ;
607- for ( const runtime of [ result . iosRuntime , result . androidRuntime ] ) {
608- try {
609- const hints = metroHintsFromRuntime ( runtime ) ;
610- if ( hints ) deviceBaseUrls . add ( hints . controlBaseUrl ) ;
611- } catch { }
612- }
613- writeMetroSessionHints ( {
614- ...metroSessionHintsScope ( config ) ,
615- hints : {
616- controlBaseUrl : new URL ( '.' , result . statusUrl ) . toString ( ) ,
617- deviceBaseUrls : [ ...deviceBaseUrls ] ,
618- } ,
619- } ) ;
620- } catch {
621- // Session-hint persistence is best-effort; reload still works with explicit flags.
622- }
623- }
624-
625- function resolveMetroSessionHints (
626- config : AgentDeviceClientConfig ,
627- ) : SessionRuntimeHints | undefined {
628- try {
629- const binding = readMetroSessionHints ( metroSessionHintsScope ( config ) ) ;
630- return binding ? { bundleUrl : binding . controlBaseUrl } : undefined ;
631- } catch {
632- return undefined ;
633- }
634- }
635-
636- function metroHintsFromRuntime (
637- runtime : SessionRuntimeHints | undefined ,
638- ) : MetroSessionHints | undefined {
639- const { metroHost, metroPort, bundleUrl } = runtime ?? { } ;
640- if ( metroHost === undefined && metroPort === undefined && bundleUrl === undefined )
641- return undefined ;
642- return { controlBaseUrl : resolveMetroServerUrl ( { runtime } ) . toString ( ) } ;
643- }
644-
645- // Hint flags rebind the session's dev server; a hintless open that created the session clears
646- // any leftover binding from a previous same-name session.
647- function recordMetroSessionHintsAfterOpen ( params : {
648- config : AgentDeviceClientConfig ;
649- options : InternalRequestOptions ;
650- runtime : SessionRuntimeHints | undefined ;
651- sessionReused : boolean ;
652- } ) : void {
653- try {
654- const scope = metroSessionHintsScope ( params . config , params . options ) ;
655- const hints = metroHintsFromRuntime ( params . runtime ) ;
656- if ( hints ) {
657- const binding =
658- params . options . runtime === undefined ? readMetroSessionHints ( scope ) : undefined ;
659- if (
660- binding &&
661- ( params . sessionReused || binding . deviceBaseUrls ?. includes ( hints . controlBaseUrl ) )
662- )
663- return ;
664- writeMetroSessionHints ( { ...scope , hints } ) ;
665- return ;
666- }
667- if ( ! params . sessionReused ) {
668- clearMetroSessionHints ( scope ) ;
669- }
670- } catch {
671- // Session-hint sync is best-effort; reload still works with explicit flags.
672- }
673- }
674-
675- function clearMetroSessionHintsQuietly (
676- config : AgentDeviceClientConfig ,
677- options : InternalRequestOptions ,
678- ) : void {
679- try {
680- clearMetroSessionHints ( metroSessionHintsScope ( config , options ) ) ;
681- } catch {
682- // Session-hint cleanup is best-effort; close must not fail on local file state.
683- }
684- }
685-
686591export type * from './client/client-types.ts' ;
0 commit comments