Skip to content

Commit 9805acc

Browse files
committed
Add RN inspector and simulator test API
1 parent d65e7f5 commit 9805acc

83 files changed

Lines changed: 7614 additions & 1440 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ jobs:
4242
run: npm run test:integration:cli
4343
env:
4444
SIMDECK_INTEGRATION_VERBOSE: "1"
45+
46+
- name: JS API simulator integration tests
47+
run: npm run test:integration:js-api

.github/workflows/release.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ jobs:
9292
"${ARTIFACTS_DIR}/simdeck-${VERSION}-macos.zip"
9393
9494
npm pack --pack-destination "${ARTIFACTS_DIR}"
95+
test -x "${BUNDLE_DIR}/simdeck"
96+
test -x "${BUNDLE_DIR}/simdeck-bin"
97+
tar -tzf "${ARTIFACTS_DIR}/simdeck-${VERSION}.tgz" | grep -qx "package/build/simdeck-bin"
9598
(
9699
cd packages/nativescript-inspector
97100
npm pack --pack-destination "${ARTIFACTS_DIR}"
@@ -112,7 +115,7 @@ jobs:
112115
exit 1
113116
fi
114117
115-
npm publish
118+
npm publish "${RUNNER_TEMP}/release-assets/simdeck-${VERSION}.tgz"
116119
117120
- name: Publish NativeScript inspector to npm
118121
env:

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ client/dist/
88
packages/inspector-agent/.build/
99
packages/inspector-agent/.swiftpm/
1010
packages/nativescript-inspector/dist/
11+
packages/react-native-inspector/dist/
1112
docs/.vitepress/dist/
1213
docs/.vitepress/cache/
14+
.playwright-mcp/
15+
simdeck-snapshot.md
1316

1417
# Package manager installs and caches
1518
node_modules/
1619
client/node_modules/
1720
packages/nativescript-inspector/node_modules/
21+
packages/react-native-inspector/node_modules/
1822

1923
# Local editor state
2024
.vscode/

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ build
55
client/dist
66
packages/inspector-agent/.build
77
packages/nativescript-inspector/dist
8+
packages/react-native-inspector/dist
89
node_modules
910
server/target
1011
docs/.vitepress/dist
1112
docs/.vitepress/cache
13+
.playwright-mcp
14+
simdeck-snapshot.md

AGENTS.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,18 @@ The native side should own anything that depends on macOS frameworks, `xcrun sim
4444
NativeScript in-app inspector runtime that connects to the Rust server over
4545
WebSocket, publishes NativeScript/UIKit hierarchies, and performs debug UIKit
4646
property edits from JavaScript.
47+
- `packages/react-native-inspector/src/index.ts`
48+
React Native in-app inspector runtime that connects to the Rust server over
49+
WebSocket, publishes React Fiber component hierarchies with Metro source
50+
locations, and performs best-effort debug JS/native prop edits.
4751

4852
## Working Rules
4953

5054
- Keep simulator-native logic in Objective-C under `cli/`.
5155
- Keep Rust server logic under `server/`.
5256
- Keep browser-only presentation logic in `client/`.
5357
- Keep NativeScript app runtime inspection logic in `packages/nativescript-inspector/`.
58+
- Keep React Native app runtime inspection logic in `packages/react-native-inspector/`.
5459
- Prefer adding a native API endpoint before adding client-only assumptions.
5560
- Do not add a Node or Swift dependency to solve work that already fits in Foundation/AppKit.
5661
- When touching private API usage, keep the adaptation small and explicit and document any simulator/runtime assumptions here.
@@ -82,22 +87,22 @@ Build the native CLI:
8287

8388
This now builds the Rust server in `server/` and copies the resulting binary to `build/simdeck`.
8489

85-
Run the local server:
90+
Run the local daemon:
8691

8792
```sh
88-
./build/simdeck serve --port 4310
93+
./build/simdeck daemon start --port 4310
8994
```
9095

9196
Use software H.264 when macOS screen recording starves the hardware encoder:
9297

9398
```sh
94-
./build/simdeck serve --port 4310 --video-codec h264-software
99+
./build/simdeck daemon start --port 4310 --video-codec h264-software
95100
```
96101

97102
For LAN access:
98103

99104
```sh
100-
./build/simdeck serve --port 4310 --bind 0.0.0.0 --advertise-host 192.168.1.50
105+
./build/simdeck daemon start --port 4310 --bind 0.0.0.0 --advertise-host 192.168.1.50
101106
```
102107

103108
Useful direct commands:
@@ -114,7 +119,7 @@ Useful direct commands:
114119
./build/simdeck pasteboard set <udid> "hello"
115120
./build/simdeck pasteboard get <udid>
116121
./build/simdeck screenshot <udid> --output screen.png
117-
./build/simdeck describe-ui <udid>
122+
./build/simdeck describe <udid>
118123
./build/simdeck tap <udid> 120 240
119124
./build/simdeck tap <udid> --label "Continue" --wait-timeout-ms 5000
120125
./build/simdeck swipe <udid> 200 700 200 200

README.md

Lines changed: 74 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
# SimDeck
22

3-
`simdeck` is a local simulator control panel & agent-first CLI for driving the simulator
3+
SimDeck is a developer tool built for streamlining mobile app development for coding agents.
4+
Drive iOS Simulator apps from the CLI, browser, and automated tests on macOS.
45

56
```sh
67
npm i -g simdeck@latest
78
```
89

9-
- `simctl`-backed simulator discovery and lifecycle commands
10-
- private CoreSimulator boot fallback
10+
## Features
11+
12+
- WebTransport based streaming server in Rust, hardware encoded HVEC/H264 video stream
13+
- Simulator control & inspection using private accessibility APIs
1114
- CoreSimulator chrome asset rendering for device bezels
12-
- NativeScript runtime inspector in `packages/nativescript-inspector/` for JS-driven UIKit querying and property edits
13-
- WebTransport video delivery over a self-signed local or LAN endpoint
15+
- NativeScript and React Native runtime inspector plugins, plus a native UIKit inspector framework for other apps
16+
- Project daemon reuse: normal CLI commands automatically start and reuse one warm native host per project.
17+
- `simdeck/test` for fast JS/TS app tests that can query accessibility state and drive simulator controls.
18+
- Agent [`SKILL.md`](./skills/simdeck/SKILL.md) reference
1419

1520
## Build
1621

@@ -19,21 +24,20 @@ npm i -g simdeck@latest
1924
./scripts/build-cli.sh
2025
```
2126

22-
## Install
23-
2427
Requirements:
2528

2629
- macOS
2730
- Xcode or Command Line Tools
28-
- Rust toolchain (`cargo`)
2931
- Node.js 18+
32+
- Rust toolchain (`cargo`) when building from source
3033

31-
The npm package builds the native Rust/Objective-C CLI during `postinstall`; it
32-
is not a prebuilt cross-platform binary.
34+
The npm package includes the native SimDeck binary and does not compile during
35+
install. Rust is only required when building from a source checkout.
3336

3437
Install the current local checkout globally from source:
3538

3639
```sh
40+
npm run build
3741
npm install -g .
3842
```
3943

@@ -46,46 +50,45 @@ Full documentation lives at [djdeveloperr.github.io/SimDeck](https://djdeveloper
4650
## Run
4751

4852
```sh
49-
simdeck serve --port 4310
53+
simdeck ui --open
5054
```
5155

52-
Then open [http://127.0.0.1:4310](http://127.0.0.1:4310).
53-
To focus a specific simulator, open
54-
[http://127.0.0.1:4310?device=UDID](http://127.0.0.1:4310?device=UDID).
56+
This starts or reuses the project daemon, enables the browser UI, and opens the authenticated local URL.
57+
To focus a specific simulator, add `?device=UDID` to the opened URL.
5558

56-
The Rust server exposes HTTP on the requested port and WebTransport on `port + 1`.
59+
The daemon exposes HTTP on the requested port and WebTransport on `port + 1`.
5760
The browser bootstrap comes from `GET /api/health`, which returns the WebTransport URL template,
5861
certificate hash, and packet version needed by the client.
59-
The served browser UI receives the generated API access token automatically; direct HTTP callers can use the startup token with `X-SimDeck-Token` or `Authorization: Bearer`.
62+
The served browser UI receives the generated API access token automatically.
6063

61-
For fastest agent control, keep `simdeck serve` or `simdeck service on` running and route hot CLI controls through the warm local service:
64+
CLI commands automatically use the same warm daemon:
6265

6366
```sh
64-
export SIMDECK_SERVER_URL=http://127.0.0.1:4310
67+
simdeck list
6568
simdeck tap <udid> 0.5 0.5 --normalized
66-
simdeck describe-ui <udid> --format agent --max-depth 2
69+
simdeck describe <udid> --format agent --max-depth 2
6770
```
6871

69-
You can also pass `--server-url http://127.0.0.1:4310` on individual commands. Supported fast-path controls include launch/open-url, normalized touch/tap/swipe/gesture input, key/key-sequence/key-combo, hardware buttons, dismiss-keyboard, home/app-switcher, rotate, and appearance toggles.
72+
## Daemon
7073

71-
## Service
72-
73-
Enable the per-user background service with `launchd`:
74+
Manage the project daemon explicitly when needed:
7475

7576
```sh
76-
simdeck service on --port 4310
77+
simdeck daemon start
78+
simdeck daemon status
79+
simdeck daemon stop
7780
```
7881

79-
Restart it:
82+
Use software H.264 when macOS screen recording starves the hardware encoder:
8083

8184
```sh
82-
simdeck service restart
85+
simdeck daemon start --video-codec h264-software
8386
```
8487

85-
Disable it:
88+
For LAN browser access:
8689

8790
```sh
88-
simdeck service off
91+
simdeck ui --bind 0.0.0.0 --advertise-host 192.168.1.50 --open
8992
```
9093

9194
Restart the CoreSimulator service layer when `simctl` reports a stale service
@@ -117,9 +120,9 @@ simdeck toggle-appearance <udid>
117120
simdeck pasteboard set <udid> "hello"
118121
simdeck pasteboard get <udid>
119122
simdeck screenshot <udid> --output screen.png
120-
simdeck describe-ui <udid>
121-
simdeck describe-ui <udid> --format agent --max-depth 4
122-
simdeck describe-ui <udid> --point 120,240
123+
simdeck describe <udid>
124+
simdeck describe <udid> --format agent --max-depth 4
125+
simdeck describe <udid> --point 120,240
123126
simdeck tap <udid> 120 240
124127
simdeck tap <udid> --label "Continue" --wait-timeout-ms 5000
125128
simdeck swipe <udid> 200 700 200 200
@@ -144,13 +147,30 @@ simdeck chrome-profile <udid>
144147
simdeck logs <udid> --seconds 30 --limit 200
145148
```
146149

147-
`describe-ui` can use the running local SimDeck service to prefer NativeScript or
150+
`describe` uses the project daemon to prefer React Native, NativeScript, or
148151
UIKit in-app inspectors, then falls back to the built-in private CoreSimulator
149152
accessibility bridge. Use `--format agent` or `--format compact-json` for
150153
lower-token hierarchy dumps. Coordinate commands accept screen coordinates from
151154
the accessibility tree by default; pass `--normalized` to send `0.0..1.0`
152-
coordinates directly. With `--server-url` or `SIMDECK_SERVER_URL`, normalized
153-
input commands use the warm service path to avoid repeated native setup.
155+
coordinates directly.
156+
157+
## JS/TS Tests
158+
159+
```ts
160+
import { connect } from "simdeck/test";
161+
162+
const sim = await connect();
163+
try {
164+
await sim.tap("<udid>", 0.5, 0.5);
165+
await sim.waitFor("<udid>", { label: "Continue" });
166+
await sim.screenshot("<udid>");
167+
} finally {
168+
sim.close();
169+
}
170+
```
171+
172+
`connect()` starts the project daemon when needed, reuses it when it is already
173+
healthy, and only stops daemons it started itself.
154174

155175
## NativeScript Inspector
156176

@@ -171,6 +191,26 @@ server prefers connected NativeScript inspectors for hierarchy requests and
171191
falls back to the Swift TCP inspector or the built-in native accessibility
172192
bridge when no matching app inspector is available.
173193

194+
## React Native Inspector
195+
196+
React Native apps can expose their component tree and Metro dev-mode source
197+
locations with the React Native inspector package:
198+
199+
```ts
200+
import { AppRegistry } from "react-native";
201+
import { startSimDeckReactNativeInspector } from "@simdeck/react-native-inspector";
202+
import App from "./App";
203+
204+
if (__DEV__) {
205+
startSimDeckReactNativeInspector({ port: 4310 });
206+
}
207+
208+
AppRegistry.registerComponent("Example", () => App);
209+
```
210+
211+
Call it before `AppRegistry.registerComponent(...)` so the package can capture
212+
React Fiber commits.
213+
174214
## VS Code
175215

176216
Package the local VS Code extension from this checkout:

bin/simdeck.mjs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ const packageRoot = path.resolve(
1111
);
1212
const binaryPath = path.join(packageRoot, "build", "simdeck-bin");
1313

14+
if (process.platform !== "darwin") {
15+
console.error("simdeck only supports macOS.");
16+
process.exit(1);
17+
}
18+
1419
if (!existsSync(binaryPath)) {
1520
console.error(
16-
"simdeck is not built yet. Reinstall or rebuild the package so the native CLI is available.",
21+
"simdeck native binary is missing. Reinstall the npm package or run `npm run build:cli` from a source checkout.",
1722
);
1823
process.exit(1);
1924
}

0 commit comments

Comments
 (0)