@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.
- package/dist/commands/input-server.js +28 -0
- package/dist/commands/launch-app.js +30 -3
- package/dist/commands/native-rn.js +110 -0
- package/dist/commands/native.js +320 -0
- package/dist/commands/start-device.js +62 -4
- package/dist/daemon/client.js +5 -0
- package/dist/daemon/input-backends.js +203 -0
- package/dist/daemon/input-protocol.js +40 -0
- package/dist/daemon/input-router.js +110 -0
- package/dist/daemon/input-server.js +124 -0
- package/dist/daemon/server.js +84 -0
- package/dist/daemon/web-server.js +80 -79
- package/dist/drivers/bootstrap.js +49 -0
- package/dist/drivers/eval-compiler.js +131 -0
- package/dist/drivers/ios-hid.js +95 -0
- package/dist/drivers/ios-inproc.js +198 -0
- package/dist/drivers/ios.js +39 -8
- package/dist/drivers/metro-scripts.js +174 -0
- package/dist/index.js +142 -0
- package/dist/runner.js +33 -0
- package/package.json +1 -1
- package/skills/conductor-device-interact/SKILL.md +13 -0
- package/skills/conductor-device-setup/SKILL.md +2 -1
- package/skills/conductor-inspect/SKILL.md +43 -0
- package/skills/conductor-metro-debugger/SKILL.md +10 -0
package/dist/runner.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.detectFirstDevice = detectFirstDevice;
|
|
4
4
|
exports.getDriver = getDriver;
|
|
5
5
|
exports.prewarmDriver = prewarmDriver;
|
|
6
|
+
exports.inputServerInfo = inputServerInfo;
|
|
6
7
|
exports.runDirect = runDirect;
|
|
7
8
|
exports.spawnCommand = spawnCommand;
|
|
8
9
|
exports.runInlineFlow = runInlineFlow;
|
|
@@ -243,6 +244,38 @@ async function prewarmDriver(deviceId) {
|
|
|
243
244
|
/* best-effort: a later command will report a real failure */
|
|
244
245
|
}
|
|
245
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Resolve the streaming-input socket for a session's device, starting the
|
|
249
|
+
* daemon (and its driver + input server) if needed. Returns the loopback
|
|
250
|
+
* WebSocket URL the host IDE connects to. Throws if the platform has no
|
|
251
|
+
* streaming input (web/vega) or the port never comes up.
|
|
252
|
+
*/
|
|
253
|
+
async function inputServerInfo(sessionName = 'default') {
|
|
254
|
+
const deviceId = await resolveDeviceId(sessionName);
|
|
255
|
+
if (!deviceId) {
|
|
256
|
+
throw new Error('No device found. Connect a device or start a simulator, then run again.');
|
|
257
|
+
}
|
|
258
|
+
const platform = await (0, bootstrap_js_1.detectPlatform)(deviceId);
|
|
259
|
+
if (platform !== 'ios' && platform !== 'tvos' && platform !== 'android') {
|
|
260
|
+
throw new Error(`Streaming input is not available for ${platform} devices.`);
|
|
261
|
+
}
|
|
262
|
+
await (0, client_js_1.startDaemon)(deviceId);
|
|
263
|
+
// The input server starts just after the driver — poll status until its port appears.
|
|
264
|
+
const deadline = Date.now() + 60000;
|
|
265
|
+
while (Date.now() < deadline) {
|
|
266
|
+
const status = await (0, client_js_1.fetchDaemonStatus)(deviceId);
|
|
267
|
+
if (status && typeof status.inputPort === 'number') {
|
|
268
|
+
return {
|
|
269
|
+
device: deviceId,
|
|
270
|
+
platform,
|
|
271
|
+
inputPort: status.inputPort,
|
|
272
|
+
url: `ws://127.0.0.1:${status.inputPort}/input`,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
276
|
+
}
|
|
277
|
+
throw new Error(`Input server for ${deviceId} did not come up within timeout.`);
|
|
278
|
+
}
|
|
246
279
|
/**
|
|
247
280
|
* Execute a function with the driver for the given session.
|
|
248
281
|
* Returns a RunResult for consistent error handling across commands.
|
package/package.json
CHANGED
|
@@ -51,6 +51,19 @@ conductor assert-visible "Dashboard"
|
|
|
51
51
|
| `conductor gesture <json\|--file path>` | Play a multi-touch path |
|
|
52
52
|
| `conductor clipboard read` / `clipboard write <text>` / `paste` | Clipboard (iOS) |
|
|
53
53
|
| `conductor list-options [command]` | List valid values for enumerated params |
|
|
54
|
+
| `conductor input-server` | Start (if needed) and print the streaming-input WebSocket URL for the device |
|
|
55
|
+
|
|
56
|
+
## Streaming input (host IDEs)
|
|
57
|
+
|
|
58
|
+
For continuous, low-latency input (live drags, fast typing) a host IDE can open
|
|
59
|
+
one persistent WebSocket per device instead of spawning a command per event.
|
|
60
|
+
`conductor input-server` ensures the daemon + driver are up and prints the
|
|
61
|
+
loopback URL (`ws://127.0.0.1:<port>/input`; also in `daemon-status --json` as
|
|
62
|
+
`inputPort`). The server sends a `hello` with per-platform capabilities, then
|
|
63
|
+
accepts normalized (0..1) frames: `pointer{id,phase,x,y}`, `key{code,mods,down}`,
|
|
64
|
+
`text{value}`, `button{name}`, `scroll{x,y,dx,dy}`, `tvremote{button}`. Conductor
|
|
65
|
+
owns coord→device translation and keymaps. For scripted, one-off actions use the
|
|
66
|
+
discrete commands above — this is for interactive host UIs.
|
|
54
67
|
|
|
55
68
|
## Discovering valid values
|
|
56
69
|
|
|
@@ -23,6 +23,7 @@ conductor list-apps # installed app ids / package names
|
|
|
23
23
|
| --------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
24
24
|
| `conductor start-device --platform <ios\|android\|tvos\|web\|vega>` | Boot a simulator/emulator, start the web driver, or attach to a Vega VVD |
|
|
25
25
|
| `conductor start-device --os-version <n> --device-type <name>` | Pick OS version + device type (creates if needed) |
|
|
26
|
+
| `conductor start-device --platform android --avd <name> --device-type <profile> --memory <mb>` | Create an Android AVD with a RAM floor (default 4096MB; only raises, creation-time only) |
|
|
26
27
|
| `conductor stop-device [<name-or-id>] [--all]` | Shut down device(s) |
|
|
27
28
|
| `conductor delete-device <name-or-id> [--all]` | Delete simulator(s)/AVD(s)/web session(s) |
|
|
28
29
|
| `conductor set-location --lat <n> --lng <n>` | Set GPS coordinates |
|
|
@@ -73,7 +74,7 @@ screen recording, clipboard, `clear-state`/`uninstall-app`.
|
|
|
73
74
|
| Command | Purpose |
|
|
74
75
|
| ----------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
75
76
|
| `conductor install-app <path>` | Install .app / .ipa / .apk |
|
|
76
|
-
| `conductor launch-app <appId>` | Launch app (saved to session); `--no-stop-app`, `--argument key=value` |
|
|
77
|
+
| `conductor launch-app <appId>` | Launch app (saved to session); `--no-stop-app`, `--argument key=value`, `--inject` |
|
|
77
78
|
| `conductor stop-app [<appId>]` | Stop app |
|
|
78
79
|
| `conductor uninstall-app <appId>` | Uninstall app |
|
|
79
80
|
| `conductor copy-app <bundleId> --from <id> --to <id>` | Copy an installed app between iOS simulators |
|
|
@@ -29,6 +29,49 @@ conductor capture-ui --output /tmp/screen.json
|
|
|
29
29
|
conductor tap-on @e5
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
## Native in-process inspection (iOS/tvOS simulator)
|
|
33
|
+
|
|
34
|
+
The commands above observe the app **externally** (accessibility snapshots), so
|
|
35
|
+
they can't see real component colors, fonts, or the view-controller stack. When
|
|
36
|
+
you need that native detail, launch the app with an injected in-process library
|
|
37
|
+
and use the `native-*` commands. Requires `launch-app <appId> --inject` first
|
|
38
|
+
(iOS/tvOS simulator only).
|
|
39
|
+
|
|
40
|
+
| Command | Purpose |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `conductor native-ping` | Verify the injected in-process control library is alive |
|
|
43
|
+
| `conductor native-inspect` | Real UIView/CALayer tree: resolved colors (`#RRGGBBAA`), fonts, text (incl. React Native Fabric), corner radius, borders, shadows, gradients, and each node's `absFrame` |
|
|
44
|
+
| `conductor native-nav` | Navigation state: `UINavigationController` stacks, tab selection, presented controllers, titles |
|
|
45
|
+
| `conductor native-screenshot --output <p.png>` | In-process PNG of the key window |
|
|
46
|
+
| `conductor native-image <x,y,w,h> --output <p.png>` | Extract a component as a PNG — pass a node's `absFrame` from `native-inspect` |
|
|
47
|
+
| `conductor native-snapshot <id> --output <p.png>` | Isolated PNG of one view's own content (transparent) — per-layer texture for a 3D explosion; `--with-subviews` composites the subtree |
|
|
48
|
+
| `conductor native-console [--since <n>]` / `native-network [--since <n>]` | App stdout/stderr + captured HTTP; poll with the returned `cursor` |
|
|
49
|
+
| `conductor native-heap --pattern <s> \| --class <name> \| --read <addr> [--key <keyPath>]` | Live-object browser (find classes/instances, read a property off an address) |
|
|
50
|
+
| `conductor native-appearance <light\|dark\|system> \| --direction <ltr\|rtl> \| --anim-speed <n>` | Force appearance / RTL / freeze animations app-wide |
|
|
51
|
+
| `conductor native-eval '<swift>'` | Compile & run arbitrary Swift inside the app (full UIKit / ObjC-runtime access); `--mode full` for a whole function body. e.g. `native-eval 'UIScreen.main.bounds'` |
|
|
52
|
+
| `conductor native-raw <path>` | Escape hatch — GET any in-process endpoint (e.g. `'/get?id=..&keyPath=layer.cornerRadius'`, `'/class?id=..'`, `'/responders?id=..'`, `'/swiftui'`, `'/defaults'`, `'/focus'`, `'/snapshots?scale=0.5'`). Full list in `packages/ios-inproc/README.md`. |
|
|
53
|
+
| `conductor native-view <id>` | Full property detail for one view (class chain, transform, layer, gestures, text/font) |
|
|
54
|
+
| `conductor native-set <id> <key> <value>` | **Live-edit** a property: alpha, hidden, backgroundColor, tintColor, cornerRadius, borderWidth, borderColor, frame, text, textColor. `text`/`textColor` work on RN Fabric text views too |
|
|
55
|
+
| `conductor native-props <id>` | React Native Fabric props: typed `ViewProps` + the raw JS prop bag (Fabric host views only) |
|
|
56
|
+
|
|
57
|
+
> **Editing RN Fabric text/props:** the native plane can't set text on `RCTParagraphComponentView` (no native setter) and `native-props` returns `rawProps: null` on Fabric. Edit through React instead with `conductor native-rn-set --react-tag <n> --path children --value '"…"'` (and read raw JSX props with `native-rn-props --react-tag <n>`). `reactTag` comes from this tree's `rn.reactTag`. See the conductor-metro-debugger skill. Dev builds only.
|
|
58
|
+
| `conductor native-constraints <id>` | Auto Layout constraints affecting a view + ambiguity |
|
|
59
|
+
| `conductor native-hittest <x,y>` | Topmost view at a point + ancestor chain (select-by-point) |
|
|
60
|
+
| `conductor native-highlight <id>` | Flash a highlight over the view on the device |
|
|
61
|
+
| `conductor native-find [--class <name>] [--text <s>]` | Search views by class and/or text |
|
|
62
|
+
|
|
63
|
+
Every `native-inspect` node has a stable `id` (for this launch). The Reveal-style loop:
|
|
64
|
+
inspect → pick an `id` → `native-view` for detail → `native-set` to edit live → see it
|
|
65
|
+
on the device. IDs are pointer-based and reset each launch, so re-inspect after relaunch.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
conductor launch-app com.example.app --inject
|
|
69
|
+
conductor native-inspect # tree with ids, colors, fonts, absFrame
|
|
70
|
+
conductor native-view 0x10280d0c0 # full detail for a view
|
|
71
|
+
conductor native-set 0x10280d0c0 backgroundColor '#FF3B30FF' # live-edit, visible on device
|
|
72
|
+
conductor native-image 816,286,288,288 --output /tmp/avatar.png
|
|
73
|
+
```
|
|
74
|
+
|
|
32
75
|
## Assertions
|
|
33
76
|
|
|
34
77
|
| Command | Purpose |
|
|
@@ -18,6 +18,16 @@ Playwright web.
|
|
|
18
18
|
| `conductor debug component-tree [--port N]` | On-screen React component tree |
|
|
19
19
|
| `conductor debug inspect-element <x,y>` | React component at a screen point |
|
|
20
20
|
| `conductor debug log-registry [--source metro]` | Summarize recent Metro/Hermes console logs |
|
|
21
|
+
| `conductor native-rn-set --react-tag <n> --path <dot.path> --value <json>` | Live-edit an RN component's props via React DevTools `overrideProps` (text via `--path children`, color via `--path style.color`). Dev builds only |
|
|
22
|
+
| `conductor native-rn-props --react-tag <n>` | Raw JSX props (`memoizedProps`) of an RN fiber by reactTag — the JS-side truth for Fabric where native `/props` `rawProps` is null |
|
|
23
|
+
|
|
24
|
+
`--react-tag` comes from `native-inspect`'s `rn.reactTag`. `--value` is JSON (a bare
|
|
25
|
+
string works for text). `--path` is a dot path into props: `children`, `style.color`,
|
|
26
|
+
`style.fontSize`, `accessibilityLabel`. `style.color` works whether the component's
|
|
27
|
+
`style` is an object or a composed array. These drive React itself over Metro CDP, so
|
|
28
|
+
they need a **dev/debug build** (the DevTools backend must be active) and a running
|
|
29
|
+
Metro; on a release build they return a clear "not a dev build" error. Output is
|
|
30
|
+
`{"status":"ok","applied":true}` or `{"status":"error","message":"…"}`.
|
|
21
31
|
|
|
22
32
|
## Logs
|
|
23
33
|
|