1- import {
2- serializeCloseResult ,
3- serializeDeployResult ,
4- serializeDevice ,
5- serializeInstallFromSourceResult ,
6- serializeOpenResult ,
7- serializeSessionListEntry ,
8- serializeSnapshotResult ,
9- } from '../../client-shared.ts' ;
10- import type {
11- AgentDeviceClient ,
12- AgentDeviceDevice ,
13- AgentDeviceSession ,
14- AppCloseResult ,
15- AppDeployResult ,
16- AppInstallFromSourceResult ,
17- AppOpenResult ,
18- CaptureSnapshotResult ,
19- CommandRequestResult ,
20- SessionCloseResult ,
21- } from '../../client.ts' ;
1+ import type { AgentDeviceClient , CommandRequestResult } from '../../client.ts' ;
222import { announceReplayTestRun } from '../../cli-test.ts' ;
23- import { runSemanticCliCommand } from '../../commands/semantic-cli.ts' ;
243import {
4+ runSemanticCliCommand ,
5+ runSemanticCliCommandWithOutput ,
6+ } from '../../commands/semantic-cli.ts' ;
7+ import {
8+ listSemanticCliOutputCommandNames ,
259 listSemanticCommandNames ,
2610 type SemanticCliCommand ,
2711} from '../../commands/semantic-command-surface.ts' ;
28- import { assertResolvedAppsFilter } from '../../commands/app-inventory -contract.ts' ;
12+ import type { SemanticCliOutput } from '../../commands/semantic -contract.ts' ;
2913import type { CliFlags } from '../../utils/command-schema.ts' ;
30- import { AppError } from '../../utils/errors.ts' ;
31- import { formatSnapshotText } from '../../utils/output.ts' ;
3214import { writeCommandCliOutput } from './output.ts' ;
33- import { writeCommandMessage , writeCommandOutput } from './shared.ts' ;
15+ import { writeCommandOutput } from './shared.ts' ;
3416import type { PublicCommandName } from '../../command-catalog.ts' ;
3517import type { ClientCommandHandler } from './router-types.ts' ;
3618
@@ -40,101 +22,12 @@ type GenericClientCommandRunner = (params: {
4022 flags : CliFlags ;
4123} ) => Promise < CommandRequestResult > ;
4224
43- const formattedSemanticCommandHandlers = {
44- devices : createFormattedSemanticHandler ( 'devices' , {
45- write : ( { flags, result } ) => {
46- const devices = result as unknown as AgentDeviceDevice [ ] ;
47- const data = { devices : devices . map ( serializeDevice ) } ;
48- writeCommandOutput ( flags , data , ( ) => devices . map ( formatDeviceLine ) . join ( '\n' ) ) ;
49- } ,
50- } ) ,
51- apps : createFormattedSemanticHandler ( 'apps' , {
52- write : ( { flags, result } ) => {
53- const appsFilter = assertResolvedAppsFilter ( flags . appsFilter ) ;
54- const apps = result as unknown as string [ ] ;
55- const data = { apps } ;
56- writeCommandOutput ( flags , data , ( ) => {
57- if ( ! flags . json ) {
58- process . stderr . write (
59- appsFilter === 'all'
60- ? 'Showing all apps, including system apps.\n'
61- : 'Showing user-installed apps. Use --all to include system apps.\n' ,
62- ) ;
63- }
64- if ( apps . length > 0 ) return apps . join ( '\n' ) ;
65- return appsFilter === 'all' ? 'No apps found.' : 'No user-installed apps found.' ;
66- } ) ;
67- } ,
68- } ) ,
69- session : createFormattedSemanticHandler ( 'session' , {
70- beforeRun : ( { positionals } ) => {
71- const subcommand = positionals [ 0 ] ?? 'list' ;
72- if ( subcommand !== 'list' ) {
73- throw new AppError ( 'INVALID_ARGS' , 'session only supports list' ) ;
74- }
75- } ,
76- write : ( { flags, result } ) => {
77- const sessions = ( result as { sessions : AgentDeviceSession [ ] } ) . sessions ;
78- const data = { sessions : sessions . map ( serializeSessionListEntry ) } ;
79- writeCommandOutput ( flags , data , ( ) => JSON . stringify ( data , null , 2 ) ) ;
80- } ,
81- } ) ,
82- open : createFormattedSemanticHandler ( 'open' , {
83- write : ( { flags, result } ) => {
84- writeCommandMessage ( flags , serializeOpenResult ( result as AppOpenResult ) ) ;
85- } ,
86- } ) ,
87- close : createFormattedSemanticHandler ( 'close' , {
88- write : ( { flags, result } ) => {
89- writeCommandMessage (
90- flags ,
91- serializeCloseResult ( result as AppCloseResult | SessionCloseResult ) ,
92- ) ;
93- } ,
94- } ) ,
95- install : createFormattedSemanticHandler ( 'install' , {
96- write : ( { flags, result } ) => {
97- writeCommandMessage ( flags , serializeDeployResult ( result as AppDeployResult ) ) ;
98- } ,
99- } ) ,
100- reinstall : createFormattedSemanticHandler ( 'reinstall' , {
101- write : ( { flags, result } ) => {
102- writeCommandMessage ( flags , serializeDeployResult ( result as AppDeployResult ) ) ;
103- } ,
104- } ) ,
105- 'install-from-source' : createFormattedSemanticHandler ( 'install-from-source' , {
106- write : ( { flags, result } ) => {
107- writeCommandMessage (
108- flags ,
109- serializeInstallFromSourceResult ( result as AppInstallFromSourceResult ) ,
110- ) ;
111- } ,
112- } ) ,
113- snapshot : createFormattedSemanticHandler ( 'snapshot' , {
114- positionals : ( ) => [ ] ,
115- write : ( { flags, result } ) => {
116- const data = serializeSnapshotResult ( result as CaptureSnapshotResult ) ;
117- // Programmatic SDK callers can see `unchanged`; CLI --json hides it for schema compatibility.
118- const outputData = flags . json ? withoutUnchanged ( data ) : data ;
119- writeCommandOutput ( flags , outputData , ( ) =>
120- formatSnapshotText ( outputData , {
121- raw : flags . snapshotRaw ,
122- flatten : flags . snapshotInteractiveOnly ,
123- } ) ,
124- ) ;
125- } ,
126- } ) ,
127- metro : createFormattedSemanticHandler ( 'metro' , {
128- write : ( { positionals, flags, result } ) => {
129- const action = ( positionals [ 0 ] ?? '' ) . toLowerCase ( ) ;
130- writeCommandOutput ( flags , result , ( ) =>
131- action === 'reload'
132- ? `Reloaded React Native apps via ${ ( result as { reloadUrl ?: unknown } ) . reloadUrl } `
133- : JSON . stringify ( result , null , 2 ) ,
134- ) ;
135- } ,
136- } ) ,
137- } satisfies Partial < Record < SemanticCliCommand , ClientCommandHandler > > ;
25+ const formattedSemanticCommandHandlers = Object . fromEntries (
26+ listSemanticCliOutputCommandNames ( ) . map ( ( command ) => [
27+ command ,
28+ createFormattedSemanticHandler ( command ) ,
29+ ] ) ,
30+ ) as Partial < Record < SemanticCliCommand , ClientCommandHandler > > ;
13831
13932export const dedicatedSemanticCommandHandlers = formattedSemanticCommandHandlers ;
14033
@@ -188,42 +81,31 @@ function createGenericClientCommandHandler(
18881 } ;
18982}
19083
191- function createFormattedSemanticHandler (
192- command : SemanticCliCommand ,
193- options : {
194- positionals ?: ( positionals : string [ ] ) => string [ ] ;
195- beforeRun ?: ( params : { positionals : string [ ] ; flags : CliFlags } ) => void ;
196- write : ( params : {
197- positionals : string [ ] ;
198- flags : CliFlags ;
199- result : Awaited < ReturnType < typeof runSemanticCliCommand > > ;
200- } ) => void ;
201- } ,
202- ) : ClientCommandHandler {
84+ function createFormattedSemanticHandler ( command : SemanticCliCommand ) : ClientCommandHandler {
20385 return async ( { positionals, flags, client } ) => {
204- options . beforeRun ?.( { positionals, flags } ) ;
205- const semanticPositionals = options . positionals ?.( positionals ) ?? positionals ;
206- const result = await runSemanticCliCommand ( {
86+ const { cliOutput } = await runSemanticCliCommandWithOutput ( {
20787 client,
20888 command,
209- positionals : semanticPositionals ,
89+ positionals,
21090 flags,
21191 } ) ;
212- options . write ( { positionals, flags, result } ) ;
92+ if ( ! cliOutput ) {
93+ throw new Error ( `Missing CLI output formatter for semantic command: ${ command } ` ) ;
94+ }
95+ writeSemanticCliOutput ( flags , cliOutput ) ;
21396 return true ;
21497 } ;
21598}
21699
217- function formatDeviceLine ( device : AgentDeviceDevice ) : string {
218- const kind = device . kind ? ` ${ device . kind } ` : '' ;
219- const target = device . target ? ` target=${ device . target } ` : '' ;
220- const booted = typeof device . booted === 'boolean' ? ` booted=${ device . booted } ` : '' ;
221- return `${ device . name } (${ device . platform } ${ kind } ${ target } )${ booted } ` ;
222- }
223-
224- function withoutUnchanged ( data : Record < string , unknown > ) : Record < string , unknown > {
225- const { unchanged : _unchanged , ...outputData } = data ;
226- return outputData ;
100+ function writeSemanticCliOutput ( flags : CliFlags , output : SemanticCliOutput ) : void {
101+ if ( ! flags . json && output . stderr ) {
102+ process . stderr . write ( output . stderr ) ;
103+ }
104+ writeCommandOutput (
105+ flags ,
106+ flags . json ? ( output . jsonData ?? output . data ) : output . data ,
107+ ( ) => output . text ,
108+ ) ;
227109}
228110
229111function isGenericSemanticCliCommand ( command : SemanticCliCommand ) : boolean {
0 commit comments