simdeck 0.1.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/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2026 Dj
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,240 @@
1
+ # SimDeck
2
+
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.
5
+
6
+ ```sh
7
+ npm i -g simdeck@latest
8
+ ```
9
+
10
+ After installing the CLI, install the Codex skill so agents know the stable
11
+ SimDeck workflow:
12
+
13
+ ```sh
14
+ npx skills add NativeScript/SimDeck --skill simdeck -a codex -g
15
+ ```
16
+
17
+ For VS Code, install the `nativescript.simdeck` extension to open the simulator
18
+ view inside the editor.
19
+
20
+ ## Features
21
+
22
+ - WebTransport streaming server in Rust, plus experimental WebRTC for runner previews, using hardware encoded HEVC/H.264 video
23
+ - Simulator control & inspection using private accessibility APIs
24
+ - CoreSimulator chrome asset rendering for device bezels
25
+ - NativeScript and React Native runtime inspector plugins, plus a native UIKit inspector framework for other apps
26
+ - Project daemon reuse: normal CLI commands automatically start and reuse one warm native host per project.
27
+ - Optional macOS LaunchAgent service for an always-on local SimDeck daemon.
28
+ - `simdeck/test` for fast JS/TS app tests that can query accessibility state and drive simulator controls.
29
+
30
+ ## Documentation
31
+
32
+ Full documentation lives at [simdeck.nativescript.org](https://simdeck.nativescript.org/), with guides, the CLI reference, the REST API, the WebTransport video pipeline, and the inspector protocols.
33
+
34
+ ## Quick start
35
+
36
+ ```sh
37
+ simdeck
38
+ ```
39
+
40
+ This starts a workspace-local foreground daemon, prints local and LAN browser URLs, and stops when you press Ctrl-C.
41
+ To focus a specific simulator by name or UDID, pass it as the only argument:
42
+
43
+ ```sh
44
+ simdeck "iPhone 17 Pro Max"
45
+ ```
46
+
47
+ Use `simdeck ui --open` or `simdeck daemon start` when you want a reusable background daemon instead.
48
+ The no-subcommand lifecycle shortcuts are `simdeck -d` for detached start, `simdeck -k` to kill the background daemon, and `simdeck -r` to restart it.
49
+
50
+ CLI commands automatically use the same warm daemon:
51
+
52
+ ```sh
53
+ simdeck list
54
+ simdeck tap <udid> 0.5 0.5 --normalized
55
+ simdeck describe <udid> --format agent --max-depth 2
56
+ ```
57
+
58
+ ## CLI
59
+
60
+ ```sh
61
+ simdeck list
62
+ simdeck boot <udid>
63
+ simdeck shutdown <udid>
64
+ simdeck erase <udid>
65
+ simdeck install <udid> /path/to/App.app
66
+ simdeck uninstall <udid> com.example.App
67
+ simdeck open-url <udid> https://example.com
68
+ simdeck launch <udid> com.apple.Preferences
69
+ simdeck toggle-appearance <udid>
70
+ simdeck pasteboard set <udid> "hello"
71
+ simdeck pasteboard get <udid>
72
+ simdeck screenshot <udid> --output screen.png
73
+ simdeck describe <udid>
74
+ simdeck describe <udid> --format agent --max-depth 4
75
+ simdeck describe <udid> --point 120,240
76
+ simdeck tap <udid> 120 240
77
+ simdeck tap <udid> --label "Continue" --wait-timeout-ms 5000
78
+ simdeck swipe <udid> 200 700 200 200
79
+ simdeck gesture <udid> scroll-down
80
+ simdeck pinch <udid> --start-distance 160 --end-distance 80
81
+ simdeck rotate-gesture <udid> --radius 100 --degrees 90
82
+ simdeck touch <udid> 0.5 0.5 --phase began --normalized
83
+ simdeck touch <udid> 120 240 --down --up --delay-ms 800
84
+ simdeck key <udid> enter
85
+ simdeck key-sequence <udid> --keycodes h,e,l,l,o
86
+ simdeck key-combo <udid> --modifiers cmd --key a
87
+ simdeck type <udid> "hello"
88
+ simdeck type <udid> --file message.txt
89
+ simdeck button <udid> lock --duration-ms 1000
90
+ simdeck batch <udid> --step "tap --label Continue" --step "type 'hello'"
91
+ simdeck dismiss-keyboard <udid>
92
+ simdeck home <udid>
93
+ simdeck app-switcher <udid>
94
+ simdeck rotate-left <udid>
95
+ simdeck rotate-right <udid>
96
+ simdeck chrome-profile <udid>
97
+ simdeck logs <udid> --seconds 30 --limit 200
98
+ ```
99
+
100
+ `describe` uses the project daemon to prefer React Native, NativeScript, or
101
+ UIKit in-app inspectors, then falls back to the built-in private CoreSimulator
102
+ accessibility bridge. Use `--format agent` or `--format compact-json` for
103
+ lower-token hierarchy dumps. Coordinate commands accept screen coordinates from
104
+ the accessibility tree by default; pass `--normalized` to send `0.0..1.0`
105
+ coordinates directly.
106
+
107
+ ## Daemon
108
+
109
+ Manage the project daemon explicitly when needed:
110
+
111
+ ```sh
112
+ simdeck daemon start
113
+ simdeck daemon status
114
+ simdeck daemon stop
115
+ ```
116
+
117
+ `simdeck daemon` manages the normal per-project warm process. For an always-on
118
+ daemon that is available after login, use the macOS user service commands:
119
+
120
+ ```sh
121
+ simdeck service on
122
+ simdeck service off
123
+ ```
124
+
125
+ This uses a LaunchAgent, keeps the server bound to localhost by default, and is
126
+ best for agents or editor integrations that should be able to open SimDeck
127
+ without first starting a project daemon.
128
+
129
+ Use software H.264 when macOS screen recording starves the hardware encoder:
130
+
131
+ ```sh
132
+ simdeck daemon start --video-codec h264-software
133
+ ```
134
+
135
+ For LAN browser access:
136
+
137
+ ```sh
138
+ simdeck ui --bind 0.0.0.0 --advertise-host 192.168.1.50 --open
139
+ ```
140
+
141
+ Restart the CoreSimulator service layer when `simctl` reports a stale service
142
+ version or the live display gets stuck before the first frame:
143
+
144
+ ```sh
145
+ simdeck core-simulator restart
146
+ ```
147
+
148
+ You can also start or stop the CoreSimulator service layer explicitly:
149
+
150
+ ```sh
151
+ simdeck core-simulator start
152
+ simdeck core-simulator shutdown
153
+ ```
154
+
155
+ The daemon exposes HTTP on the requested port and WebTransport on `port + 1`.
156
+ The browser bootstrap comes from `GET /api/health`, which returns the WebTransport URL template,
157
+ certificate hash, and packet version needed by the client.
158
+ The served browser UI receives the generated API access token automatically.
159
+
160
+ ## JS/TS Tests
161
+
162
+ ```ts
163
+ import { connect } from "simdeck/test";
164
+
165
+ const sim = await connect();
166
+ try {
167
+ await sim.tap("<udid>", 0.5, 0.5);
168
+ await sim.waitFor("<udid>", { label: "Continue" });
169
+ await sim.screenshot("<udid>");
170
+ } finally {
171
+ sim.close();
172
+ }
173
+ ```
174
+
175
+ `connect()` starts the project daemon when needed, reuses it when it is already
176
+ healthy, and only stops daemons it started itself.
177
+
178
+ ## NativeScript Inspector
179
+
180
+ NativeScript apps can connect directly to the running server from JS and expose
181
+ their NativeScript logical hierarchy plus raw UIKit backing views without
182
+ linking the Swift inspector framework:
183
+
184
+ ```ts
185
+ import { startSimDeckInspector } from "@nativescript/simdeck-inspector";
186
+
187
+ if (__DEV__) {
188
+ startSimDeckInspector({ port: 4310 });
189
+ }
190
+ ```
191
+
192
+ The runtime connects to `GET /api/inspector/connect` as a WebSocket. The Rust
193
+ server prefers connected NativeScript inspectors for hierarchy requests and
194
+ falls back to the Swift TCP inspector or the built-in native accessibility
195
+ bridge when no matching app inspector is available.
196
+
197
+ ## React Native Inspector
198
+
199
+ React Native apps can expose their component tree and Metro dev-mode source
200
+ locations with the React Native inspector package:
201
+
202
+ ```ts
203
+ import { AppRegistry } from "react-native";
204
+ import { startSimDeckReactNativeInspector } from "react-native-simdeck";
205
+ import App from "./App";
206
+
207
+ if (__DEV__) {
208
+ startSimDeckReactNativeInspector({ port: 4310 });
209
+ }
210
+
211
+ AppRegistry.registerComponent("Example", () => App);
212
+ ```
213
+
214
+ Call it before `AppRegistry.registerComponent(...)` so the package can capture
215
+ React Fiber commits.
216
+
217
+ ## VS Code
218
+
219
+ Install the `nativescript.simdeck` extension from the VS Code Marketplace, then
220
+ run `SimDeck: Open Simulator View` from the Command Palette. The extension
221
+ opens the simulator inside a VS Code panel and auto-starts the local daemon
222
+ when it is not already reachable.
223
+
224
+ ## SimDeck Cloud
225
+
226
+ SimDeck Cloud uses the same server binary as its GitHub Actions provider. The
227
+ provider workflow starts `simdeck serve` on the runner, exposes it through a
228
+ tunnel, and lets the hosted control plane connect to the simulator with a
229
+ one-time access token.
230
+
231
+ ## Contributing
232
+
233
+ Contributors should read [CONTRIBUTING.md](CONTRIBUTING.md) for local build
234
+ instructions, the dev workflow, and architecture notes.
235
+
236
+ ## License
237
+
238
+ Copyright 2026 Dj
239
+
240
+ Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE).
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from "node:child_process";
4
+ import { existsSync } from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const packageRoot = path.resolve(
9
+ path.dirname(fileURLToPath(import.meta.url)),
10
+ "..",
11
+ );
12
+ const binaryPath = path.join(packageRoot, "build", "simdeck-bin");
13
+
14
+ if (process.platform !== "darwin") {
15
+ console.error("simdeck only supports macOS.");
16
+ process.exit(1);
17
+ }
18
+
19
+ if (!existsSync(binaryPath)) {
20
+ console.error(
21
+ "simdeck native binary is missing. Reinstall the npm package or run `npm run build:cli` from a source checkout.",
22
+ );
23
+ process.exit(1);
24
+ }
25
+
26
+ const child = spawn(binaryPath, process.argv.slice(2), {
27
+ cwd: process.cwd(),
28
+ stdio: "inherit",
29
+ });
30
+
31
+ child.on("error", (error) => {
32
+ console.error(error.message);
33
+ process.exit(1);
34
+ });
35
+
36
+ for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
37
+ process.once(signal, () => {
38
+ if (!child.killed) {
39
+ child.kill(signal);
40
+ }
41
+ });
42
+ }
43
+
44
+ child.on("exit", (code, signal) => {
45
+ if (signal) {
46
+ process.kill(process.pid, signal);
47
+ return;
48
+ }
49
+ process.exit(code ?? 1);
50
+ });
Binary file