1+ import { deriveCapabilityMatrix } from './command-descriptor/derive.ts' ;
2+ import { commandDescriptors } from './command-descriptor/registry.ts' ;
13import type { DeviceInfo } from '../utils/device.ts' ;
24
35type KindMatrix = {
@@ -17,29 +19,6 @@ export type CommandCapability = {
1719 unsupportedHint ?: ( device : DeviceInfo ) => string | undefined ;
1820} ;
1921
20- const isNotMacOs = ( device : DeviceInfo ) : boolean => device . platform !== 'macos' ;
21- const isMacOsOrAppleSimulator = ( device : DeviceInfo ) : boolean =>
22- device . platform === 'macos' || device . kind === 'simulator' ;
23- const isIosMobileSimulator = ( device : DeviceInfo ) : boolean =>
24- device . platform === 'ios' && device . kind === 'simulator' && device . target !== 'tv' ;
25-
26- // Two-finger gesture synthesis (RunnerSynthesizedGesture) is iOS-simulator-only (plus Android).
27- // When such a gesture is rejected at admission, explain where it IS available so an agent can
28- // redirect instead of getting a bare "not supported on this device".
29- const synthesisGestureUnsupportedHint = ( device : DeviceInfo ) : string | undefined => {
30- if ( device . platform === 'macos' )
31- return 'macOS automation has no multi-touch input — this gesture is supported on Android and the iOS simulator only.' ;
32- if ( device . platform === 'ios' && device . target === 'tv' )
33- return 'tvOS has no touch input — this gesture is supported on Android and the iOS simulator only.' ;
34- if ( device . platform === 'ios' && device . kind === 'device' )
35- return 'Two-finger gesture synthesis is iOS-simulator only — not available on physical iOS devices.' ;
36- return undefined ;
37- } ;
38-
39- // Linux desktop supports these commands via xdotool/ydotool + AT-SPI2.
40- // Linux device kind is always 'device' (local desktop).
41- const LINUX_DEVICE : KindMatrix = { device : true } ;
42- const LINUX_NONE : KindMatrix = { } ;
4322const WEB_DEVICE : KindMatrix = { device : true } ;
4423const WEB_RUNTIME_COMMANDS = [ 'open' , 'close' ] as const ;
4524const WEB_RECORDING_COMMANDS = [ 'record' ] as const ;
@@ -61,220 +40,13 @@ const WEB_SUPPORTED_COMMANDS = new Set<string>([
6140 ...WEB_INTERACTION_COMMANDS ,
6241 ...WEB_SETTING_COMMANDS ,
6342] ) ;
64- const ALL_DEVICE_COMMAND_CAPABILITY = {
65- apple : { simulator : true , device : true } ,
66- android : { emulator : true , device : true , unknown : true } ,
67- linux : LINUX_DEVICE ,
68- } as const satisfies CommandCapability ;
69- const APP_RUNTIME_CAPABILITY = ALL_DEVICE_COMMAND_CAPABILITY ;
70- const APP_INVENTORY_CAPABILITY = {
71- apple : { simulator : true , device : true } ,
72- android : { emulator : true , device : true , unknown : true } ,
73- linux : LINUX_NONE ,
74- } as const satisfies CommandCapability ;
75- const APP_INSTALL_CAPABILITY = {
76- apple : { simulator : true , device : true } ,
77- android : { emulator : true , device : true , unknown : true } ,
78- linux : LINUX_NONE ,
79- supports : isNotMacOs ,
80- } as const satisfies CommandCapability ;
81-
82- export const BASE_COMMAND_CAPABILITY_MATRIX : Record < string , CommandCapability > = {
83- // Apple simulator-only.
84- alert : {
85- // macOS desktop targets report kind=device, so this stays enabled here and the
86- // supports() guard excludes iOS physical devices.
87- apple : { simulator : true , device : true } ,
88- android : { emulator : true , device : true , unknown : true } ,
89- linux : LINUX_NONE ,
90- supports : ( device ) => device . platform === 'android' || isMacOsOrAppleSimulator ( device ) ,
91- } ,
92- pinch : {
93- apple : { simulator : true , device : true } ,
94- android : { emulator : true , device : true , unknown : true } ,
95- linux : LINUX_NONE ,
96- // iOS-simulator-only (plus Android): pinch is driven by the two-finger XCTest synthesis
97- // path (RunnerSynthesizedGesture), which is iOS-only. macOS has no multi-touch synthesis, so
98- // it is excluded and fails fast at admission rather than round-tripping to an unsupported
99- // runner. Matches rotate-gesture / transform-gesture.
100- supports : ( device ) => device . platform === 'android' || isIosMobileSimulator ( device ) ,
101- unsupportedHint : synthesisGestureUnsupportedHint ,
102- } ,
103- 'rotate-gesture' : {
104- apple : { simulator : true , device : true } ,
105- android : { emulator : true , device : true , unknown : true } ,
106- linux : LINUX_NONE ,
107- supports : ( device ) => device . platform === 'android' || isIosMobileSimulator ( device ) ,
108- unsupportedHint : synthesisGestureUnsupportedHint ,
109- } ,
110- 'transform-gesture' : {
111- apple : { simulator : true , device : true } ,
112- android : { emulator : true , device : true , unknown : true } ,
113- linux : LINUX_NONE ,
114- supports : ( device ) => device . platform === 'android' || isIosMobileSimulator ( device ) ,
115- unsupportedHint : synthesisGestureUnsupportedHint ,
116- } ,
117- 'app-switcher' : {
118- apple : { simulator : true , device : true } ,
119- android : { emulator : true , device : true , unknown : true } ,
120- linux : LINUX_NONE ,
121- supports : isNotMacOs ,
122- } ,
123- open : APP_RUNTIME_CAPABILITY ,
124- close : APP_RUNTIME_CAPABILITY ,
125- reinstall : APP_INSTALL_CAPABILITY ,
126- install : APP_INSTALL_CAPABILITY ,
127- 'install-from-source' : APP_INSTALL_CAPABILITY ,
128- apps : APP_INVENTORY_CAPABILITY ,
129- back : {
130- apple : { simulator : true , device : true } ,
131- android : { emulator : true , device : true , unknown : true } ,
132- linux : LINUX_DEVICE ,
133- } ,
134- boot : {
135- apple : { simulator : true , device : true } ,
136- android : { emulator : true , device : true , unknown : true } ,
137- linux : LINUX_NONE ,
138- supports : isNotMacOs ,
139- } ,
140- shutdown : {
141- apple : { simulator : true } ,
142- android : { emulator : true } ,
143- linux : LINUX_NONE ,
144- } ,
145- click : {
146- apple : { simulator : true , device : true } ,
147- android : { emulator : true , device : true , unknown : true } ,
148- linux : LINUX_DEVICE ,
149- } ,
150- clipboard : {
151- apple : { simulator : true , device : true } ,
152- android : { emulator : true , device : true , unknown : true } ,
153- linux : LINUX_DEVICE ,
154- supports : ( device ) =>
155- device . platform === 'android' ||
156- device . platform === 'linux' ||
157- device . platform === 'macos' ||
158- device . kind === 'simulator' ,
159- } ,
160- keyboard : {
161- // iOS only supports keyboard dismiss/enter; status/get remains Android-only.
162- apple : { simulator : true , device : true } ,
163- android : { emulator : true , device : true , unknown : true } ,
164- linux : LINUX_NONE ,
165- supports : ( device ) =>
166- device . platform === 'android' || ( device . platform === 'ios' && device . target !== 'tv' ) ,
167- } ,
168- fill : {
169- apple : { simulator : true , device : true } ,
170- android : { emulator : true , device : true , unknown : true } ,
171- linux : LINUX_DEVICE ,
172- } ,
173- fling : {
174- apple : { simulator : true , device : true } ,
175- android : { emulator : true , device : true , unknown : true } ,
176- linux : LINUX_NONE ,
177- } ,
178- snapshot : ALL_DEVICE_COMMAND_CAPABILITY ,
179- diff : ALL_DEVICE_COMMAND_CAPABILITY ,
180- screenshot : ALL_DEVICE_COMMAND_CAPABILITY ,
181- wait : ALL_DEVICE_COMMAND_CAPABILITY ,
182- get : ALL_DEVICE_COMMAND_CAPABILITY ,
183- find : ALL_DEVICE_COMMAND_CAPABILITY ,
184- is : ALL_DEVICE_COMMAND_CAPABILITY ,
185- focus : {
186- apple : { simulator : true , device : true } ,
187- android : { emulator : true , device : true , unknown : true } ,
188- linux : LINUX_DEVICE ,
189- } ,
190- home : {
191- apple : { simulator : true , device : true } ,
192- android : { emulator : true , device : true , unknown : true } ,
193- linux : LINUX_DEVICE ,
194- supports : isNotMacOs ,
195- } ,
196- logs : {
197- apple : { simulator : true , device : true } ,
198- android : { emulator : true , device : true , unknown : true } ,
199- linux : LINUX_NONE ,
200- } ,
201- network : {
202- apple : { simulator : true , device : true } ,
203- android : { emulator : true , device : true , unknown : true } ,
204- linux : LINUX_NONE ,
205- } ,
206- longpress : {
207- apple : { simulator : true , device : true } ,
208- android : { emulator : true , device : true , unknown : true } ,
209- linux : LINUX_DEVICE ,
210- } ,
211- perf : {
212- apple : { simulator : true , device : true } ,
213- android : { emulator : true , device : true , unknown : true } ,
214- linux : LINUX_NONE ,
215- } ,
216- pan : {
217- apple : { simulator : true , device : true } ,
218- android : { emulator : true , device : true , unknown : true } ,
219- linux : LINUX_DEVICE ,
220- } ,
221- press : {
222- apple : { simulator : true , device : true } ,
223- android : { emulator : true , device : true , unknown : true } ,
224- linux : LINUX_DEVICE ,
225- } ,
226- push : {
227- apple : { simulator : true } ,
228- android : { emulator : true , device : true , unknown : true } ,
229- linux : LINUX_NONE ,
230- supports : isNotMacOs ,
231- } ,
232- record : {
233- apple : { simulator : true , device : true } ,
234- android : { emulator : true , device : true , unknown : true } ,
235- linux : LINUX_NONE ,
236- } ,
237- 'react-native' : {
238- apple : { simulator : true , device : true } ,
239- android : { emulator : true , device : true , unknown : true } ,
240- linux : LINUX_NONE ,
241- } ,
242- rotate : {
243- apple : { simulator : true , device : true } ,
244- android : { emulator : true , device : true , unknown : true } ,
245- linux : LINUX_NONE ,
246- supports : ( device ) =>
247- device . platform === 'android' || ( device . platform === 'ios' && device . target !== 'tv' ) ,
248- } ,
249- scroll : {
250- apple : { simulator : true , device : true } ,
251- android : { emulator : true , device : true , unknown : true } ,
252- linux : LINUX_DEVICE ,
253- } ,
254- swipe : {
255- apple : { simulator : true , device : true } ,
256- android : { emulator : true , device : true , unknown : true } ,
257- linux : LINUX_DEVICE ,
258- } ,
259- settings : {
260- apple : { simulator : true , device : true } ,
261- android : { emulator : true , device : true , unknown : true } ,
262- linux : LINUX_NONE ,
263- supports : ( device ) =>
264- device . platform === 'android' || device . platform === 'macos' || device . kind === 'simulator' ,
265- } ,
266- viewport : {
267- apple : { simulator : true , device : true } ,
268- android : { emulator : true , device : true , unknown : true } ,
269- linux : LINUX_NONE ,
270- } ,
271- 'trigger-app-event' : {
272- apple : { simulator : true , device : true } ,
273- android : { emulator : true , device : true , unknown : true } ,
274- linux : LINUX_NONE ,
275- } ,
276- type : ALL_DEVICE_COMMAND_CAPABILITY ,
277- } ;
43+ // Built from the additive command-descriptor registry (ADR-0008, Phase 1 step 3).
44+ // The hand-authored literal was deleted after #906 proved deriveCapabilityMatrix is
45+ // byte-equal to it (platform/kind buckets plus the supports/unsupportedHint closures,
46+ // across the sample-device matrix). The registry only type-imports CommandCapability
47+ // from here, so this value-level dependency does not form a runtime cycle.
48+ export const BASE_COMMAND_CAPABILITY_MATRIX : Record < string , CommandCapability > =
49+ deriveCapabilityMatrix ( commandDescriptors ) ;
27850
27951const COMMAND_CAPABILITY_MATRIX = addWebCommandCapabilities ( BASE_COMMAND_CAPABILITY_MATRIX ) ;
28052
0 commit comments