11import type { ReplayScriptSourceBundle } from '@agent-device/contracts/replay' ;
22import type { MaestroSourceReader } from '@agent-device/maestro' ;
33import type { DaemonRequest } from '../../daemon/types.ts' ;
4- import { buildReplayScriptSourceBundle } from '../../replay/script-source-bundle.ts' ;
4+ import {
5+ loadReplayScriptSourceBundle ,
6+ readAdScriptSourceBundle ,
7+ } from '../../replay/script-source-bundle.ts' ;
58import { discoverReplaySourcePaths } from '../../replay/source-discovery.ts' ;
69
710/**
8- * Builds a replay script source bundle from a file on disk the way a real
9- * caller does (#1802) — through the client's own builder, so a test never
10- * hand-rolls a bundle shape the CLI would not actually send.
11+ * A native `.ad` script's bundle, built from a file on disk through the client's own reader
12+ * (#1802) so a test never hand-rolls a shape the CLI would not actually send. Synchronous
13+ * because an `.ad` script has no include grammar and needs no engine; use
14+ * `maestroScriptSourceBundleFor` for a flow.
1115 */
12- export function replayScriptSourceBundleFor (
16+ export function replayScriptSourceBundleFor ( filePath : string ) : ReplayScriptSourceBundle {
17+ return readAdScriptSourceBundle ( { inputPath : filePath , cwd : process . cwd ( ) } ) ;
18+ }
19+
20+ /** A Maestro flow's bundle — async because the engine that walks its includes loads on demand. */
21+ export async function maestroScriptSourceBundleFor (
1322 filePath : string ,
14- options : { replayBackend ?: string } = { } ,
15- ) : ReplayScriptSourceBundle {
16- return buildReplayScriptSourceBundle ( {
23+ ) : Promise < ReplayScriptSourceBundle > {
24+ return await loadReplayScriptSourceBundle ( {
1725 inputPath : filePath ,
1826 cwd : process . cwd ( ) ,
19- replayBackend : options . replayBackend ,
27+ replayBackend : 'maestro' ,
2028 } ) ;
2129}
2230
@@ -35,36 +43,44 @@ export const noMaestroIncludeSources: MaestroSourceReader = (resolvedPath) => {
3543 * Test harnesses that stand in for "a request as it arrives at the daemon" call this so their
3644 * cases keep expressing what they are about; a request that already carries its own sources (or
3745 * deliberately carries none, to pin the daemon's refusal) is returned untouched.
46+ *
47+ * Collection that cannot succeed — a case driving `replay` at a path that deliberately does not
48+ * exist — leaves the request alone rather than throwing: the real client raises that failure at
49+ * the CLI boundary (pinned in `cli-client-commands.test.ts`), and a daemon-level harness must
50+ * still deliver the request so the daemon's own response is what the case observes.
3851 */
39- export function withClientReplayScriptSources ( req : DaemonRequest ) : DaemonRequest {
52+ export async function withClientReplayScriptSources ( req : DaemonRequest ) : Promise < DaemonRequest > {
4053 if ( req . command !== 'replay' && req . command !== 'test' ) return req ;
4154 const inputs = req . positionals ?? [ ] ;
42- if ( inputs . length === 0 ) return req ;
55+ const entryPath = inputs [ 0 ] ;
56+ if ( entryPath === undefined ) return req ;
4357 const cwd = req . meta ?. cwd ?? process . cwd ( ) ;
4458 const replayBackend = req . flags ?. replayBackend ;
45- const entryPath = inputs [ 0 ] ;
46- if ( req . command === 'replay' ) {
47- if ( req . flags ?. replayScriptSource || entryPath === undefined ) return req ;
48- return {
49- ...req ,
50- flags : {
51- ...( req . flags ?? { } ) ,
52- replayScriptSource : buildReplayScriptSourceBundle ( {
59+ try {
60+ if ( req . command === 'replay' ) {
61+ if ( req . flags ?. replayScriptSource ) return req ;
62+ return withFlags ( req , {
63+ replayScriptSource : await loadReplayScriptSourceBundle ( {
5364 inputPath : entryPath ,
5465 cwd,
5566 replayBackend,
5667 } ) ,
57- } ,
58- } ;
59- }
60- if ( req . flags ?. replayScriptSources ) return req ;
61- return {
62- ...req ,
63- flags : {
64- ...( req . flags ?? { } ) ,
65- replayScriptSources : discoverReplaySourcePaths ( { inputs, cwd, replayBackend } ) . map (
66- ( inputPath ) => buildReplayScriptSourceBundle ( { inputPath, cwd, replayBackend } ) ,
68+ } ) ;
69+ }
70+ if ( req . flags ?. replayScriptSources ) return req ;
71+ return withFlags ( req , {
72+ replayScriptSources : await Promise . all (
73+ discoverReplaySourcePaths ( { inputs, cwd, replayBackend } ) . map (
74+ async ( inputPath ) =>
75+ await loadReplayScriptSourceBundle ( { inputPath, cwd, replayBackend } ) ,
76+ ) ,
6777 ) ,
68- } ,
69- } ;
78+ } ) ;
79+ } catch {
80+ return req ;
81+ }
82+ }
83+
84+ function withFlags ( req : DaemonRequest , flags : Partial < DaemonRequest [ 'flags' ] > ) : DaemonRequest {
85+ return { ...req , flags : { ...( req . flags ?? { } ) , ...flags } } ;
7086}
0 commit comments