@houwert/conductor 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.InprocClient = void 0;
7
+ exports.getInprocPort = getInprocPort;
8
+ /**
9
+ * Client + port allocation for the injected in-process control library
10
+ * (`packages/ios-inproc`). This is a second inspection plane that runs *inside*
11
+ * the target app — distinct from the external XCUITest driver in `ios.ts`.
12
+ *
13
+ * The dylib is injected at launch (see IOSDriver.launchApp `inject` option). The
14
+ * CLI allocates a loopback port per device, hands it to the app via
15
+ * SIMCTL_CHILD_CONDUCTOR_INPROC_PORT, and connects here. Simulator apps share
16
+ * the host loopback, so 127.0.0.1:<port> reaches the in-process server — the same
17
+ * mechanism the XCUITest driver uses on :1075.
18
+ */
19
+ const http_1 = __importDefault(require("http"));
20
+ const fs_1 = __importDefault(require("fs"));
21
+ const os_1 = __importDefault(require("os"));
22
+ const path_1 = __importDefault(require("path"));
23
+ const INPROC_BASE_PORT = 6075;
24
+ const PORT_FILE = path_1.default.join(os_1.default.homedir(), '.conductor', 'inproc-ports.json');
25
+ function readState() {
26
+ try {
27
+ return JSON.parse(fs_1.default.readFileSync(PORT_FILE, 'utf-8'));
28
+ }
29
+ catch {
30
+ return { assignments: {}, nextPort: INPROC_BASE_PORT };
31
+ }
32
+ }
33
+ /**
34
+ * Deterministic in-process control port for a device. Stable across calls so
35
+ * the launcher and any later `native-*` command agree without a discovery file.
36
+ */
37
+ function getInprocPort(deviceId) {
38
+ const state = readState();
39
+ const existing = state.assignments[deviceId];
40
+ if (existing !== undefined)
41
+ return existing;
42
+ const port = state.nextPort;
43
+ state.assignments[deviceId] = port;
44
+ state.nextPort = port + 1;
45
+ fs_1.default.mkdirSync(path_1.default.dirname(PORT_FILE), { recursive: true });
46
+ fs_1.default.writeFileSync(PORT_FILE, JSON.stringify(state, null, 2));
47
+ return port;
48
+ }
49
+ /** HTTP/JSON client for the in-process control server. */
50
+ class InprocClient {
51
+ constructor(port, host = '127.0.0.1') {
52
+ this.port = port;
53
+ this.host = host;
54
+ }
55
+ get(reqPath, timeoutMs = 5000) {
56
+ return new Promise((resolve, reject) => {
57
+ const req = http_1.default.request({ hostname: this.host, port: this.port, path: reqPath, method: 'GET' }, (res) => {
58
+ const chunks = [];
59
+ res.on('data', (c) => chunks.push(c));
60
+ res.on('end', () => {
61
+ try {
62
+ resolve(JSON.parse(Buffer.concat(chunks).toString('utf-8')));
63
+ }
64
+ catch (err) {
65
+ reject(err);
66
+ }
67
+ });
68
+ res.on('error', reject);
69
+ });
70
+ req.setTimeout(timeoutMs, () => req.destroy(new Error('in-proc request timed out')));
71
+ req.on('error', reject);
72
+ req.end();
73
+ });
74
+ }
75
+ ping(timeoutMs = 5000) {
76
+ return this.get('/ping', timeoutMs);
77
+ }
78
+ /** Full native view hierarchy with colors, fonts, text, and layer visuals. */
79
+ inspect(timeoutMs = 15000) {
80
+ return this.get('/inspect', timeoutMs);
81
+ }
82
+ /** Navigation / view-controller hierarchy (stacks, tabs, presented, titles). */
83
+ nav(timeoutMs = 15000) {
84
+ return this.get('/nav', timeoutMs);
85
+ }
86
+ /** Full property detail for one view (by id from inspect). */
87
+ view(id, timeoutMs = 8000) {
88
+ return this.get(`/view?id=${encodeURIComponent(id)}`, timeoutMs);
89
+ }
90
+ /** Live-set a whitelisted property on a view (alpha, backgroundColor, text, frame, …). */
91
+ set(id, key, value, timeoutMs = 8000) {
92
+ const q = `id=${encodeURIComponent(id)}&key=${encodeURIComponent(key)}&value=${encodeURIComponent(value)}`;
93
+ return this.get(`/set?${q}`, timeoutMs);
94
+ }
95
+ /** React Native Fabric props: typed ViewProps + the raw JS prop bag. */
96
+ props(id, timeoutMs = 8000) {
97
+ return this.get(`/props?id=${encodeURIComponent(id)}`, timeoutMs);
98
+ }
99
+ /** Auto Layout constraints affecting a view + ambiguity flag. */
100
+ constraints(id, timeoutMs = 8000) {
101
+ return this.get(`/constraints?id=${encodeURIComponent(id)}`, timeoutMs);
102
+ }
103
+ /** Topmost view at a window point, plus its ancestor chain. */
104
+ hittest(x, y, timeoutMs = 8000) {
105
+ return this.get(`/hittest?x=${x}&y=${y}`, timeoutMs);
106
+ }
107
+ /** Flash a highlight overlay over a view on the device. */
108
+ highlight(id, timeoutMs = 8000) {
109
+ return this.get(`/highlight?id=${encodeURIComponent(id)}`, timeoutMs);
110
+ }
111
+ /** Search views by class-name substring and/or text substring. */
112
+ find(q, timeoutMs = 10000) {
113
+ const parts = [];
114
+ if (q.className)
115
+ parts.push(`class=${encodeURIComponent(q.className)}`);
116
+ if (q.text)
117
+ parts.push(`text=${encodeURIComponent(q.text)}`);
118
+ return this.get(`/find?${parts.join('&')}`, timeoutMs);
119
+ }
120
+ /** PNG of the whole key window. */
121
+ screenshot(timeoutMs = 20000) {
122
+ return this.getBuffer('/screenshot', timeoutMs);
123
+ }
124
+ /**
125
+ * PNG of a single view in isolation — the texture for a 3D exploded-layer
126
+ * viewer. Default (`includeSubviews=false`) captures only this view's own
127
+ * content, so each node is a distinct transparent layer plane.
128
+ */
129
+ snapshot(id, includeSubviews = false, timeoutMs = 15000) {
130
+ const q = `id=${encodeURIComponent(id)}&subviews=${includeSubviews ? 'true' : 'false'}`;
131
+ return this.getBuffer(`/snapshot?${q}`, timeoutMs);
132
+ }
133
+ /**
134
+ * PNG crop of a window-absolute rect (use a node's `absFrame` from inspect).
135
+ * Composites whatever is drawn there — works for UIImageView, RN Fabric, etc.
136
+ */
137
+ image(frame, timeoutMs = 15000) {
138
+ return this.getBuffer(`/image?frame=${frame.x},${frame.y},${frame.w},${frame.h}`, timeoutMs);
139
+ }
140
+ /** Raw GET to any endpoint, parsed as JSON. */
141
+ rawJson(reqPath, timeoutMs = 15000) {
142
+ const path = reqPath.startsWith('/') ? reqPath : `/${reqPath}`;
143
+ return this.get(path, timeoutMs);
144
+ }
145
+ /** Raw GET to any endpoint — returns the content-type and bytes (json or image). */
146
+ rawRequest(reqPath, timeoutMs = 20000) {
147
+ const path = reqPath.startsWith('/') ? reqPath : `/${reqPath}`;
148
+ return new Promise((resolve, reject) => {
149
+ const req = http_1.default.request({ hostname: this.host, port: this.port, path, method: 'GET' }, (res) => {
150
+ const chunks = [];
151
+ res.on('data', (c) => chunks.push(c));
152
+ res.on('end', () => resolve({ contentType: res.headers['content-type'] ?? '', body: Buffer.concat(chunks) }));
153
+ res.on('error', reject);
154
+ });
155
+ req.setTimeout(timeoutMs, () => req.destroy(new Error('in-proc request timed out')));
156
+ req.on('error', reject);
157
+ req.end();
158
+ });
159
+ }
160
+ getBuffer(reqPath, timeoutMs) {
161
+ return new Promise((resolve, reject) => {
162
+ const req = http_1.default.request({ hostname: this.host, port: this.port, path: reqPath, method: 'GET' }, (res) => {
163
+ const chunks = [];
164
+ res.on('data', (c) => chunks.push(c));
165
+ res.on('end', () => {
166
+ const buf = Buffer.concat(chunks);
167
+ const type = res.headers['content-type'] ?? '';
168
+ if (!type.startsWith('image/')) {
169
+ reject(new Error(`expected an image, got: ${buf.toString('utf-8').slice(0, 200)}`));
170
+ return;
171
+ }
172
+ resolve(buf);
173
+ });
174
+ res.on('error', reject);
175
+ });
176
+ req.setTimeout(timeoutMs, () => req.destroy(new Error('in-proc image request timed out')));
177
+ req.on('error', reject);
178
+ req.end();
179
+ });
180
+ }
181
+ /** True once the in-process server answers a ping (poll after an injected launch). */
182
+ async waitUntilReady(timeoutMs = 10000) {
183
+ const deadline = Date.now() + timeoutMs;
184
+ while (Date.now() < deadline) {
185
+ try {
186
+ const res = await this.ping(1500);
187
+ if (res.status === 'ok')
188
+ return true;
189
+ }
190
+ catch {
191
+ /* not up yet */
192
+ }
193
+ await new Promise((r) => setTimeout(r, 300));
194
+ }
195
+ return false;
196
+ }
197
+ }
198
+ exports.InprocClient = InprocClient;
@@ -89,14 +89,35 @@ class IOSDriver {
89
89
  invalidateHierarchyCache() {
90
90
  this.hierarchyCache = null;
91
91
  }
92
- simctl(args) {
92
+ simctl(args, childEnv) {
93
93
  const _id = this.requireDeviceId();
94
94
  return new Promise((resolve, reject) => {
95
- const proc = (0, child_process_1.spawn)('xcrun', ['simctl', ...args], { stdio: 'ignore' });
95
+ const proc = (0, child_process_1.spawn)('xcrun', ['simctl', ...args], {
96
+ stdio: 'ignore',
97
+ env: childEnv ? this.launchEnv(childEnv) : undefined,
98
+ });
96
99
  proc.on('close', (code) => code === 0 ? resolve() : reject(new Error(`xcrun simctl ${args[0]} failed (exit ${code})`)));
97
100
  proc.on('error', reject);
98
101
  });
99
102
  }
103
+ /**
104
+ * Build the env for a `simctl launch` that must forward vars into the target
105
+ * app. `simctl` copies `SIMCTL_CHILD_*` vars into the app's real environment at
106
+ * exec() — the only path dyld honours for restricted vars like
107
+ * DYLD_INSERT_LIBRARIES. Inherited SIMCTL_CHILD_* are stripped first so stale
108
+ * values (from a parent shell) can't override ours and silently break injection.
109
+ */
110
+ launchEnv(childEnv) {
111
+ const env = { ...process.env };
112
+ for (const key of Object.keys(env)) {
113
+ if (key.startsWith('SIMCTL_CHILD_'))
114
+ delete env[key];
115
+ }
116
+ for (const [key, value] of Object.entries(childEnv)) {
117
+ env[`SIMCTL_CHILD_${key}`] = value;
118
+ }
119
+ return env;
120
+ }
100
121
  simctlCapture(args) {
101
122
  this.requireDeviceId();
102
123
  return new Promise((resolve, reject) => {
@@ -167,15 +188,25 @@ class IOSDriver {
167
188
  });
168
189
  this.invalidateHierarchyCache();
169
190
  }
170
- async launchApp(bundleId, args) {
171
- if (args && Object.keys(args).length > 0) {
191
+ async launchApp(bundleId, args, inject) {
192
+ const argPairs = [];
193
+ for (const [key, value] of Object.entries(args ?? {})) {
194
+ argPairs.push(`-${key}`, value);
195
+ }
196
+ if (inject) {
197
+ // Injection requires simctl launch with SIMCTL_CHILD_ env — the XCTest
198
+ // /launchApp path only activates and can't set environment.
199
+ const deviceId = this.requireDeviceId();
200
+ await this.simctl(['terminate', deviceId, bundleId]).catch(() => { });
201
+ await this.simctl(['launch', '--terminate-running-process', deviceId, bundleId, ...argPairs], {
202
+ DYLD_INSERT_LIBRARIES: inject.dylibPath,
203
+ CONDUCTOR_INPROC_PORT: String(inject.inprocPort),
204
+ });
205
+ }
206
+ else if (argPairs.length > 0) {
172
207
  const deviceId = this.requireDeviceId();
173
208
  // xctest /launchApp doesn't support launch args — use simctl
174
209
  await this.simctl(['terminate', deviceId, bundleId]).catch(() => { });
175
- const argPairs = [];
176
- for (const [key, value] of Object.entries(args)) {
177
- argPairs.push(`-${key}`, value);
178
- }
179
210
  await this.simctl(['launch', '--terminate-running-process', deviceId, bundleId, ...argPairs]);
180
211
  }
181
212
  else {
@@ -16,6 +16,8 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.makeComponentTreeScript = makeComponentTreeScript;
19
+ exports.makeOverridePropsScript = makeOverridePropsScript;
20
+ exports.makeRnPropsScript = makeRnPropsScript;
19
21
  exports.makeInspectElementScript = makeInspectElementScript;
20
22
  /** RN internals + navigation/safe-area wrappers we always strip from the tree. */
21
23
  const SKIP_NAMES = [
@@ -289,6 +291,178 @@ function makeComponentTreeScript(requestId) {
289
291
  }
290
292
  })();`;
291
293
  }
294
+ /**
295
+ * Shared JS: locate a host fiber by its native reactTag, across every registered
296
+ * renderer and both RN architectures (Paper `_nativeTag`/`canonical.nativeTag`,
297
+ * Fabric bridgeless `__nativeTag` on the state node / public instance). Defines
298
+ * `findByTag(hook, TAG)` returning `{ fiber, renderer }` or null.
299
+ */
300
+ const FIBER_BY_TAG_HELPERS = `
301
+ function nativeTagOf(f) {
302
+ if (typeof f.type !== 'string' || !f.stateNode) return null;
303
+ var sn = f.stateNode;
304
+ if (typeof sn._nativeTag === 'number') return sn._nativeTag;
305
+ if (typeof sn.__nativeTag === 'number') return sn.__nativeTag;
306
+ if (sn.canonical) {
307
+ if (typeof sn.canonical.nativeTag === 'number') return sn.canonical.nativeTag;
308
+ var pi = sn.canonical.publicInstance;
309
+ if (pi && typeof pi.__nativeTag === 'number') return pi.__nativeTag;
310
+ }
311
+ if (sn.node && typeof sn.node.__nativeTag === 'number') return sn.node.__nativeTag;
312
+ return null;
313
+ }
314
+ function findHostByTag(root, TAG) {
315
+ var stack = [root.current || root], seen = 0;
316
+ while (stack.length && seen < 40000) {
317
+ var f = stack.pop(); seen++;
318
+ if (!f) continue;
319
+ if (nativeTagOf(f) === TAG) return f;
320
+ if (f.sibling) stack.push(f.sibling);
321
+ if (f.child) stack.push(f.child);
322
+ }
323
+ return null;
324
+ }
325
+ function findByTag(hook, TAG) {
326
+ var entries = [];
327
+ hook.renderers.forEach(function(r, id) { entries.push([id, r]); });
328
+ for (var i = 0; i < entries.length; i++) {
329
+ var id = entries[i][0], r = entries[i][1], roots = null;
330
+ try { roots = hook.getFiberRoots(id); } catch (e) {}
331
+ if (!roots) continue;
332
+ var arr = Array.from(roots);
333
+ for (var j = 0; j < arr.length; j++) {
334
+ var hf = findHostByTag(arr[j], TAG);
335
+ if (hf) return { fiber: hf, renderer: r };
336
+ }
337
+ }
338
+ return null;
339
+ }`;
340
+ /**
341
+ * Live-edit props via React DevTools' `overrideProps(fiber, path, value)` — the
342
+ * same call the DevTools "edit prop" UI makes. Maps `reactTag` → host fiber, then
343
+ * picks the fiber that owns the top-level path key (for `children`, prefers the
344
+ * composite `<Text>` ancestor, so the visible string changes). Returns a JSON
345
+ * string: `{status:'ok',applied:true}` or `{status:'error',message}`.
346
+ */
347
+ function makeOverridePropsScript(reactTag, path, valueJson) {
348
+ return `(function() {
349
+ try {
350
+ var hook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
351
+ if (!hook || !hook.renderers || !hook.getFiberRoots) {
352
+ return JSON.stringify({ status: 'error', message: 'No React DevTools hook — not a dev/debug build?' });
353
+ }
354
+ var TAG = ${JSON.stringify(reactTag)};
355
+ var PATH = ${JSON.stringify(path)};
356
+ var VALUE = ${valueJson};
357
+ ${FIBER_BY_TAG_HELPERS}
358
+ var hit = findByTag(hook, TAG);
359
+ if (!hit) return JSON.stringify({ status: 'error', message: 'no fiber for reactTag ' + TAG });
360
+ var renderer = hit.renderer;
361
+ if (!renderer || typeof renderer.overrideProps !== 'function') {
362
+ return JSON.stringify({ status: 'error', message: 'renderer has no overrideProps — is this a dev build?' });
363
+ }
364
+ // Pick the fiber that owns the top path key. For 'children' prefer the
365
+ // nearest fiber whose children is a string (the renderable <Text>/RCTText),
366
+ // so overriding actually swaps the visible glyphs.
367
+ var key = PATH[0];
368
+ var cur = hit.fiber, hops = 0, fallback = null;
369
+ while (cur && hops < 10) {
370
+ var p = cur.memoizedProps;
371
+ if (p && typeof p === 'object' && Object.prototype.hasOwnProperty.call(p, key)) {
372
+ if (fallback === null) fallback = cur;
373
+ if (key !== 'children') { fallback = cur; break; }
374
+ if (typeof p.children === 'string') { fallback = cur; break; }
375
+ }
376
+ cur = cur.return; hops++;
377
+ }
378
+ var target = fallback || hit.fiber;
379
+ // RN styles are often arrays (StyleSheet composition). overrideProps' setIn
380
+ // can't create missing intermediates, and a key set on the array object is
381
+ // ignored by flattening — so for a 'style.<key>' path we flatten the current
382
+ // style to a plain object (what RN does anyway), apply the override, and set
383
+ // the whole 'style'. Works whether style started as an object or an array.
384
+ if (PATH[0] === 'style' && PATH.length >= 2) {
385
+ function flattenStyle(s) {
386
+ var acc = {};
387
+ (function merge(x) {
388
+ if (!x) return;
389
+ if (Array.isArray(x)) { for (var i = 0; i < x.length; i++) merge(x[i]); return; }
390
+ if (typeof x === 'object') { for (var k in x) if (Object.prototype.hasOwnProperty.call(x, k)) acc[k] = x[k]; }
391
+ })(s);
392
+ return acc;
393
+ }
394
+ var flat = flattenStyle(target.memoizedProps && target.memoizedProps.style);
395
+ var keys = PATH.slice(1), o = flat;
396
+ for (var i = 0; i < keys.length - 1; i++) {
397
+ if (typeof o[keys[i]] !== 'object' || o[keys[i]] === null) o[keys[i]] = {};
398
+ o = o[keys[i]];
399
+ }
400
+ o[keys[keys.length - 1]] = VALUE;
401
+ renderer.overrideProps(target, ['style'], flat);
402
+ return JSON.stringify({ status: 'ok', applied: true, note: 'style flattened to object; override applied' });
403
+ }
404
+ renderer.overrideProps(target, PATH, VALUE);
405
+ return JSON.stringify({ status: 'ok', applied: true });
406
+ } catch (e) {
407
+ return JSON.stringify({ status: 'error', message: String((e && e.message) || e) });
408
+ }
409
+ })();`;
410
+ }
411
+ /**
412
+ * Dump a host fiber's `memoizedProps` (the real JSX props RN passed to the native
413
+ * view — the JS-side analog of the native `/props` rawProps that Fabric drops).
414
+ * Functions become `"[Function: name]"`; cycles/over-depth become markers.
415
+ * Returns a JSON string `{status:'ok',props:{...}}` or `{status:'error',message}`.
416
+ */
417
+ function makeRnPropsScript(reactTag) {
418
+ return `(function() {
419
+ try {
420
+ var hook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
421
+ if (!hook || !hook.renderers || !hook.getFiberRoots) {
422
+ return JSON.stringify({ status: 'error', message: 'No React DevTools hook — not a dev/debug build?' });
423
+ }
424
+ var TAG = ${JSON.stringify(reactTag)};
425
+ ${FIBER_BY_TAG_HELPERS}
426
+ var hit = findByTag(hook, TAG);
427
+ if (!hit) return JSON.stringify({ status: 'error', message: 'no fiber for reactTag ' + TAG });
428
+ var seen = [];
429
+ function ser(v, depth) {
430
+ if (v === null || v === undefined) return v === undefined ? undefined : null;
431
+ var t = typeof v;
432
+ if (t === 'string' || t === 'boolean') return v;
433
+ if (t === 'number') return isFinite(v) ? v : String(v);
434
+ if (t === 'function') return '[Function: ' + (v.name || 'anonymous') + ']';
435
+ if (t === 'symbol') return v.toString();
436
+ if (t === 'bigint') return String(v) + 'n';
437
+ if (t === 'object') {
438
+ if (depth > 6) return '[Object: max depth]';
439
+ if (seen.indexOf(v) !== -1) return '[Circular]';
440
+ if (v && v.$$typeof) return '[ReactElement]';
441
+ seen.push(v);
442
+ var out;
443
+ if (Array.isArray(v)) {
444
+ out = [];
445
+ for (var i = 0; i < v.length && i < 200; i++) out.push(ser(v[i], depth + 1));
446
+ } else {
447
+ out = {};
448
+ var keys = Object.keys(v);
449
+ for (var k = 0; k < keys.length; k++) {
450
+ var val = ser(v[keys[k]], depth + 1);
451
+ if (val !== undefined) out[keys[k]] = val;
452
+ }
453
+ }
454
+ seen.pop();
455
+ return out;
456
+ }
457
+ return String(v);
458
+ }
459
+ var props = ser(hit.fiber.memoizedProps || {}, 0);
460
+ return JSON.stringify({ status: 'ok', props: props });
461
+ } catch (e) {
462
+ return JSON.stringify({ status: 'error', message: String((e && e.message) || e) });
463
+ }
464
+ })();`;
465
+ }
292
466
  /**
293
467
  * Inspect-at-point script. Uses React DevTools's own
294
468
  * `renderer.rendererConfig.getInspectorDataForViewAtPoint(inspectRef, x, y, cb)`,
package/dist/index.js CHANGED
@@ -9,6 +9,8 @@ const verbose_js_1 = require("./verbose.js");
9
9
  const sdk_js_1 = require("./android/sdk.js");
10
10
  const list_devices_js_1 = require("./commands/list-devices.js");
11
11
  const launch_app_js_1 = require("./commands/launch-app.js");
12
+ const native_js_1 = require("./commands/native.js");
13
+ const native_rn_js_1 = require("./commands/native-rn.js");
12
14
  const stop_app_js_1 = require("./commands/stop-app.js");
13
15
  const clear_state_js_1 = require("./commands/clear-state.js");
14
16
  const uninstall_app_js_1 = require("./commands/uninstall-app.js");
@@ -27,6 +29,7 @@ const run_flow_inline_js_1 = require("./commands/run-flow-inline.js");
27
29
  const press_key_js_1 = require("./commands/press-key.js");
28
30
  const session_js_1 = require("./commands/session.js");
29
31
  const daemon_js_1 = require("./commands/daemon.js");
32
+ const input_server_js_1 = require("./commands/input-server.js");
30
33
  const install_js_1 = require("./commands/install.js");
31
34
  const init_js_1 = require("./commands/init.js");
32
35
  const device_pool_js_1 = require("./commands/device-pool.js");
@@ -80,6 +83,27 @@ const COMMAND_HELP = {
80
83
  'download-app': download_app_js_1.HELP,
81
84
  'install-app': install_app_js_1.HELP,
82
85
  'launch-app': launch_app_js_1.HELP,
86
+ 'native-ping': native_js_1.PING_HELP,
87
+ 'native-inspect': native_js_1.INSPECT_HELP,
88
+ 'native-nav': native_js_1.NAV_HELP,
89
+ 'native-screenshot': native_js_1.SCREENSHOT_HELP,
90
+ 'native-image': native_js_1.IMAGE_HELP,
91
+ 'native-snapshot': native_js_1.SNAPSHOT_HELP,
92
+ 'native-view': native_js_1.VIEW_HELP,
93
+ 'native-set': native_js_1.SET_HELP,
94
+ 'native-props': native_js_1.PROPS_HELP,
95
+ 'native-rn-set': native_rn_js_1.RN_SET_HELP,
96
+ 'native-rn-props': native_rn_js_1.RN_PROPS_HELP,
97
+ 'native-constraints': native_js_1.CONSTRAINTS_HELP,
98
+ 'native-hittest': native_js_1.HITTEST_HELP,
99
+ 'native-highlight': native_js_1.HIGHLIGHT_HELP,
100
+ 'native-find': native_js_1.FIND_HELP,
101
+ 'native-raw': native_js_1.RAW_HELP,
102
+ 'native-console': native_js_1.CONSOLE_HELP,
103
+ 'native-network': native_js_1.NETWORK_HELP,
104
+ 'native-heap': native_js_1.HEAP_HELP,
105
+ 'native-appearance': native_js_1.APPEARANCE_HELP,
106
+ 'native-eval': native_js_1.EVAL_HELP,
83
107
  'stop-app': stop_app_js_1.HELP,
84
108
  'clear-state': clear_state_js_1.HELP,
85
109
  'uninstall-app': uninstall_app_js_1.HELP,
@@ -110,6 +134,7 @@ const COMMAND_HELP = {
110
134
  'daemon-start': daemon_js_1.HELP_DAEMON_START,
111
135
  'daemon-stop': daemon_js_1.HELP_DAEMON_STOP,
112
136
  'daemon-status': daemon_js_1.HELP_DAEMON_STATUS,
137
+ 'input-server': input_server_js_1.HELP,
113
138
  'device-pool': device_pool_js_1.HELP,
114
139
  'run-parallel': run_parallel_js_1.HELP,
115
140
  'run-sequence': run_sequence_js_1.HELP,
@@ -240,6 +265,9 @@ async function main() {
240
265
  'cdp-url',
241
266
  'cdp-target',
242
267
  'duration',
268
+ 'react-tag',
269
+ 'path',
270
+ 'value',
243
271
  ],
244
272
  alias: { h: 'help', v: 'verbose', V: 'version', o: 'output', y: 'yes' },
245
273
  });
@@ -370,6 +398,7 @@ async function main() {
370
398
  deviceType: argv['device-type'],
371
399
  systemImage: argv['system-image'],
372
400
  browser: argv['browser'],
401
+ memory: argv['memory'] !== undefined ? Number(argv['memory']) : undefined,
373
402
  });
374
403
  break;
375
404
  case 'list-devices':
@@ -423,9 +452,119 @@ async function main() {
423
452
  clearKeychain: argv['clear-keychain'],
424
453
  stopApp: argv['stop-app'] !== false,
425
454
  launchArgs,
455
+ inject: argv['inject'],
426
456
  });
427
457
  break;
428
458
  }
459
+ case 'native-ping': {
460
+ exitCode = await (0, native_js_1.nativePing)(opts, sessionName);
461
+ break;
462
+ }
463
+ case 'native-inspect': {
464
+ exitCode = await (0, native_js_1.nativeInspect)(opts, sessionName);
465
+ break;
466
+ }
467
+ case 'native-nav': {
468
+ exitCode = await (0, native_js_1.nativeNav)(opts, sessionName);
469
+ break;
470
+ }
471
+ case 'native-screenshot': {
472
+ exitCode = await (0, native_js_1.nativeScreenshot)(argv['output'], opts, sessionName);
473
+ break;
474
+ }
475
+ case 'native-image': {
476
+ exitCode = await (0, native_js_1.nativeImage)(rest[0], argv['output'], opts, sessionName);
477
+ break;
478
+ }
479
+ case 'native-snapshot': {
480
+ exitCode = await (0, native_js_1.nativeSnapshot)(rest[0], argv['with-subviews'], argv['output'], opts, sessionName);
481
+ break;
482
+ }
483
+ case 'native-view': {
484
+ exitCode = await (0, native_js_1.nativeView)(rest[0], opts, sessionName);
485
+ break;
486
+ }
487
+ case 'native-set': {
488
+ exitCode = await (0, native_js_1.nativeSet)(rest, opts, sessionName);
489
+ break;
490
+ }
491
+ case 'native-props': {
492
+ exitCode = await (0, native_js_1.nativeProps)(rest[0], opts, sessionName);
493
+ break;
494
+ }
495
+ case 'native-rn-set': {
496
+ const rnOpts = {
497
+ port: argv['port'] !== undefined ? Number(argv['port']) : undefined,
498
+ targetIndex: argv['target'] !== undefined ? Number(argv['target']) : undefined,
499
+ };
500
+ exitCode = await (0, native_rn_js_1.nativeRnSet)({
501
+ reactTag: argv['react-tag'],
502
+ path: argv['path'],
503
+ value: argv['value'],
504
+ }, opts, sessionName, rnOpts);
505
+ break;
506
+ }
507
+ case 'native-rn-props': {
508
+ const rnOpts = {
509
+ port: argv['port'] !== undefined ? Number(argv['port']) : undefined,
510
+ targetIndex: argv['target'] !== undefined ? Number(argv['target']) : undefined,
511
+ };
512
+ exitCode = await (0, native_rn_js_1.nativeRnProps)({ reactTag: argv['react-tag'] }, opts, sessionName, rnOpts);
513
+ break;
514
+ }
515
+ case 'native-constraints': {
516
+ exitCode = await (0, native_js_1.nativeConstraints)(rest[0], opts, sessionName);
517
+ break;
518
+ }
519
+ case 'native-hittest': {
520
+ exitCode = await (0, native_js_1.nativeHittest)(rest[0], opts, sessionName);
521
+ break;
522
+ }
523
+ case 'native-highlight': {
524
+ exitCode = await (0, native_js_1.nativeHighlight)(rest[0], opts, sessionName);
525
+ break;
526
+ }
527
+ case 'native-find': {
528
+ exitCode = await (0, native_js_1.nativeFind)({
529
+ className: argv['class'],
530
+ text: argv['text'],
531
+ }, opts, sessionName);
532
+ break;
533
+ }
534
+ case 'native-raw': {
535
+ exitCode = await (0, native_js_1.nativeRaw)(rest[0], argv['output'], opts, sessionName);
536
+ break;
537
+ }
538
+ case 'native-console': {
539
+ exitCode = await (0, native_js_1.nativeConsole)(argv['since'] !== undefined ? Number(argv['since']) : undefined, opts, sessionName);
540
+ break;
541
+ }
542
+ case 'native-network': {
543
+ exitCode = await (0, native_js_1.nativeNetwork)(argv['since'] !== undefined ? Number(argv['since']) : undefined, opts, sessionName);
544
+ break;
545
+ }
546
+ case 'native-heap': {
547
+ exitCode = await (0, native_js_1.nativeHeap)({
548
+ className: argv['class'],
549
+ pattern: argv['pattern'],
550
+ read: argv['read'],
551
+ key: argv['key'],
552
+ }, opts, sessionName);
553
+ break;
554
+ }
555
+ case 'native-appearance': {
556
+ exitCode = await (0, native_js_1.nativeAppearance)({
557
+ style: rest[0],
558
+ direction: argv['direction'],
559
+ contentSize: argv['content-size'],
560
+ animSpeed: argv['anim-speed'],
561
+ }, opts, sessionName);
562
+ break;
563
+ }
564
+ case 'native-eval': {
565
+ exitCode = await (0, native_js_1.nativeEval)(rest.join(' '), argv['mode'] === 'full' ? 'full' : 'expr', opts, sessionName);
566
+ break;
567
+ }
429
568
  case 'stop-app': {
430
569
  const appId = rest[0];
431
570
  exitCode = await (0, stop_app_js_1.stopApp)(appId, opts, sessionName);
@@ -705,6 +844,9 @@ async function main() {
705
844
  case 'daemon-status':
706
845
  exitCode = await (0, daemon_js_1.daemonStatusCmd)(opts, sessionName);
707
846
  break;
847
+ case 'input-server':
848
+ exitCode = await (0, input_server_js_1.inputServer)(opts, sessionName);
849
+ break;
708
850
  case 'device-pool': {
709
851
  const acquire = argv['acquire'];
710
852
  const release = argv['release'];