Skip to content

Commit 1827060

Browse files
committed
refactor: move app code into packages
1 parent a97fb70 commit 1827060

156 files changed

Lines changed: 194 additions & 145 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: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,19 @@ jobs:
3636
path: |
3737
~/.cargo/git
3838
~/.cargo/registry
39-
server/target
40-
key: rust-${{ runner.os }}-${{ hashFiles('server/Cargo.lock', 'server/Cargo.toml', 'server/build.rs', 'server/src/**/*.rs', 'cli/**/*.m') }}
39+
packages/server/target
40+
key: rust-${{ runner.os }}-${{ hashFiles('packages/server/Cargo.lock', 'packages/server/Cargo.toml', 'packages/server/build.rs', 'packages/server/src/**/*.rs', 'packages/server/native/**/*.m') }}
4141
restore-keys: |
4242
rust-${{ runner.os }}-
4343
4444
- name: Check Rust formatting
45-
run: cargo fmt --manifest-path server/Cargo.toml --check
45+
run: cargo fmt --manifest-path packages/server/Cargo.toml --check
4646

4747
- name: Clippy
48-
run: cargo clippy --manifest-path server/Cargo.toml --all-targets -- -D warnings
48+
run: cargo clippy --manifest-path packages/server/Cargo.toml --all-targets -- -D warnings
4949

5050
- name: Rust unit tests
51-
run: cargo test --manifest-path server/Cargo.toml
51+
run: cargo test --manifest-path packages/server/Cargo.toml
5252

5353
client:
5454
name: Client lint, build, and tests
@@ -63,13 +63,13 @@ jobs:
6363
cache: npm
6464
cache-dependency-path: |
6565
package-lock.json
66-
client/package-lock.json
66+
packages/client/package-lock.json
6767
6868
- name: Install root dependencies
6969
run: npm ci --ignore-scripts --force
7070

7171
- name: Install client dependencies
72-
run: npm ci --prefix client
72+
run: npm ci --prefix packages/client
7373

7474
- name: Check Prettier formatting
7575
run: npx prettier --check .
@@ -81,13 +81,13 @@ jobs:
8181
run: npm run test:integration-harness
8282

8383
- name: Typecheck client
84-
run: npm run --prefix client typecheck
84+
run: npm run --prefix packages/client typecheck
8585

8686
- name: Test client
87-
run: npm run --prefix client test
87+
run: npm run --prefix packages/client test
8888

8989
- name: Build client
90-
run: npm run --prefix client build
90+
run: npm run --prefix packages/client build
9191

9292
packages:
9393
name: Packages and VS Code extension
@@ -135,7 +135,7 @@ jobs:
135135
cache: npm
136136
cache-dependency-path: |
137137
package-lock.json
138-
client/package-lock.json
138+
packages/client/package-lock.json
139139
140140
- uses: dtolnay/rust-toolchain@stable
141141

@@ -148,17 +148,17 @@ jobs:
148148
path: |
149149
~/.cargo/git
150150
~/.cargo/registry
151-
server/target
151+
packages/server/target
152152
.cache/simdeck/fixture
153-
key: rust-${{ runner.os }}-${{ hashFiles('server/Cargo.lock', 'server/Cargo.toml', 'server/build.rs', 'server/src/**/*.rs', 'cli/**/*.m', 'scripts/integration/fixture.mjs') }}
153+
key: rust-${{ runner.os }}-${{ hashFiles('packages/server/Cargo.lock', 'packages/server/Cargo.toml', 'packages/server/build.rs', 'packages/server/src/**/*.rs', 'packages/server/native/**/*.m', 'scripts/integration/fixture.mjs') }}
154154
restore-keys: |
155155
rust-${{ runner.os }}-
156156
157157
- name: Install root dependencies
158158
run: npm ci --ignore-scripts
159159

160160
- name: Install client dependencies
161-
run: npm ci --prefix client
161+
run: npm ci --prefix packages/client
162162

163163
- name: Build CLI, client, and JS test API
164164
run: |
@@ -176,7 +176,7 @@ jobs:
176176
path: |
177177
build/simdeck
178178
build/simdeck-bin
179-
client/dist
179+
packages/client/dist
180180
packages/simdeck-test/dist
181181
.cache/simdeck/fixture
182182

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ jobs:
101101
cache: npm
102102
cache-dependency-path: |
103103
package-lock.json
104-
client/package-lock.json
104+
packages/client/package-lock.json
105105
packages/react-native-inspector/package-lock.json
106106
packages/nativescript-inspector/package-lock.json
107107
@@ -162,7 +162,7 @@ jobs:
162162

163163
- name: Install client dependencies (root simdeck only)
164164
if: ${{ steps.meta.outputs.kind == 'npm-cli' }}
165-
run: npm ci --prefix client
165+
run: npm ci --prefix packages/client
166166

167167
- name: Install package dependencies
168168
if: ${{ steps.meta.outputs.kind == 'npm' }}

.github/workflows/simdeck-provider.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,11 @@ jobs:
124124
./simdeck-src/scripts/build-client.sh
125125
./simdeck-src/scripts/build-cli.sh
126126
mkdir -p build
127-
mkdir -p client
127+
mkdir -p packages/client
128128
cp simdeck-src/build/simdeck build/simdeck
129129
cp simdeck-src/build/simdeck-bin build/simdeck-bin
130-
rm -rf client/dist
131-
cp -R simdeck-src/client/dist client/dist
130+
rm -rf packages/client/dist
131+
cp -R simdeck-src/packages/client/dist packages/client/dist
132132
chmod +x build/simdeck
133133
chmod +x build/simdeck-bin
134134
fi
@@ -218,7 +218,7 @@ jobs:
218218
--port 4310 \
219219
--bind 127.0.0.1 \
220220
--access-token "$PROVIDER_TOKEN" \
221-
--client-root "$PWD/client/dist" \
221+
--client-root "$PWD/packages/client/dist" \
222222
--video-codec software \
223223
--stream-quality "${SIMDECK_STREAM_QUALITY:-ci-software}" \
224224
>> simdeck.log 2>&1 &

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
dist/
55
build/
66
target/
7-
server/target/
8-
client/dist/
7+
packages/server/target/
8+
packages/client/dist/
99
packages/inspector-agent/.build/
1010
packages/inspector-agent/.swiftpm/
1111
packages/nativescript-inspector/build/
@@ -28,7 +28,7 @@ simdeck-snapshot.md
2828

2929
# Package manager installs and caches
3030
node_modules/
31-
client/node_modules/
31+
packages/client/node_modules/
3232
packages/nativescript-inspector/node_modules/
3333
packages/react-native-inspector/node_modules/
3434

AGENTS.md

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ This repository is a local-first simulator control plane. The product goal is a
44

55
## Product Shape
66

7-
- `cli/` is the native boundary.
8-
- `client/` is the browser UI.
7+
- `packages/server/native/` is the native boundary.
8+
- `packages/client/` is the browser UI.
99
- `skills/simdeck/SKILL.md` is the operator guide for using the tool from Codex.
1010
- `scripts/` holds repeatable build entrypoints.
1111
- `docs/` is the public VitePress documentation site (deployed to GitHub Pages by `.github/workflows/docs.yml`).
@@ -14,34 +14,34 @@ The native side should own anything that depends on macOS frameworks, `xcrun sim
1414

1515
## Current Architecture
1616

17-
- `server/src/main.rs`
17+
- `packages/server/src/main.rs`
1818
Owns the CLI entrypoint, Rust subcommands, HTTP server, and static asset serving.
19-
- `server/src/api/routes.rs`
19+
- `packages/server/src/api/routes.rs`
2020
Defines REST routes for simulator control, health, metrics, and chrome assets.
21-
- `server/src/transport/webrtc.rs`
21+
- `packages/server/src/transport/webrtc.rs`
2222
Exposes the H.264 WebRTC offer/answer endpoint for browser live video.
23-
- `server/src/webkit.rs`
23+
- `packages/server/src/webkit.rs`
2424
Discovers simulator WebKit Remote Inspector targets and bridges WebInspectorUI
2525
WebSocket traffic to the simulator `webinspectord` binary-plist socket.
26-
- `server/src/simulators/registry.rs`
26+
- `packages/server/src/simulators/registry.rs`
2727
Tracks Rust-side simulator session state and lazy native attachment by UDID.
28-
- `cli/XCWSimctl.*`
28+
- `packages/server/native/XCWSimctl.*`
2929
Wraps `xcrun simctl` for discovery, lifecycle management, app launching, URL opening, appearance toggles, and simulator log capture.
30-
- `cli/DFPrivateSimulatorDisplayBridge.*`
30+
- `packages/server/native/DFPrivateSimulatorDisplayBridge.*`
3131
Owns headless private display frames plus HID-based touch and keyboard injection.
32-
- `cli/XCWAccessibilityBridge.*`
32+
- `packages/server/native/XCWAccessibilityBridge.*`
3333
Owns private CoreSimulator accessibility snapshots through `AccessibilityPlatformTranslation`.
34-
- `cli/XCWPrivateSimulatorSession.*`
34+
- `packages/server/native/XCWPrivateSimulatorSession.*`
3535
Owns one private display bridge per booted simulator plus selectable hardware/software H.264 encode.
36-
- `cli/native/XCWNativeBridge.*`
36+
- `packages/server/native/bridge/XCWNativeBridge.*`
3737
Narrow C ABI for simulator control, chrome rendering, and native frame callbacks into Rust.
38-
- `cli/native/XCWNativeSession.*`
38+
- `packages/server/native/bridge/XCWNativeSession.*`
3939
Wraps one Objective-C private simulator session handle for the Rust registry.
40-
- `cli/XCWPrivateSimulatorBooter.*`
40+
- `packages/server/native/XCWPrivateSimulatorBooter.*`
4141
Uses private `CoreSimulator` APIs for direct simulator boot without launching Simulator.app.
42-
- `cli/XCWChromeRenderer.*`
42+
- `packages/server/native/XCWChromeRenderer.*`
4343
Renders Apple’s CoreSimulator device-type PDF chrome assets into PNGs for the browser.
44-
- `client/src/app/App.tsx`
44+
- `packages/client/src/app/App.tsx`
4545
Browser entrypoint for the React control surface.
4646
- `packages/nativescript-inspector/src/index.ts`
4747
NativeScript in-app inspector runtime that connects to the Rust server over
@@ -58,9 +58,9 @@ The native side should own anything that depends on macOS frameworks, `xcrun sim
5858

5959
## Working Rules
6060

61-
- Keep simulator-native logic in Objective-C under `cli/`.
62-
- Keep Rust server logic under `server/`.
63-
- Keep browser-only presentation logic in `client/`.
61+
- Keep simulator-native logic in Objective-C under `packages/server/native/`.
62+
- Keep Rust server logic under `packages/server/`.
63+
- Keep browser-only presentation logic in `packages/client/`.
6464
- Keep NativeScript app runtime inspection logic in `packages/nativescript-inspector/`.
6565
- Keep React Native app runtime inspection logic in `packages/react-native-inspector/`.
6666
- Keep Flutter app runtime inspection logic in `packages/flutter-inspector/`.
@@ -73,11 +73,11 @@ The native side should own anything that depends on macOS frameworks, `xcrun sim
7373

7474
Private simulator behavior is implemented locally in:
7575

76-
- Boot path: `cli/XCWPrivateSimulatorBooter.*`
77-
- Full live display bridge: `cli/DFPrivateSimulatorDisplayBridge.*`
78-
- Accessibility bridge: `cli/XCWAccessibilityBridge.*`
76+
- Boot path: `packages/server/native/XCWPrivateSimulatorBooter.*`
77+
- Full live display bridge: `packages/server/native/DFPrivateSimulatorDisplayBridge.*`
78+
- Accessibility bridge: `packages/server/native/XCWAccessibilityBridge.*`
7979

80-
The current repo uses the private boot path, private display bridge, and private accessibility translation bridge directly. The browser streams frames from that bridge, injects touch and keyboard events through the same native session layer, inspects accessibility through `AccessibilityPlatformTranslation`, and renders device chrome from `cli/XCWChromeRenderer.*`.
80+
The current repo uses the private boot path, private display bridge, and private accessibility translation bridge directly. The browser streams frames from that bridge, injects touch and keyboard events through the same native session layer, inspects accessibility through `AccessibilityPlatformTranslation`, and renders device chrome from `packages/server/native/XCWChromeRenderer.*`.
8181
CoreSimulator service contexts resolve the active developer directory from `DEVELOPER_DIR`, then `xcode-select -p`, then `/Applications/Xcode.app/Contents/Developer`. The display bridge prefers direct CoreSimulator screen IOSurface callbacks and activates the SimulatorKit offscreen renderable view only if direct callbacks are unavailable.
8282
Accessibility recovery may use simulator launchctl UIKit application state plus hit-tested translations to recover candidate foreground pids; the returned tree must still be rooted at tokenized `AXPTranslator` application objects, because `translationApplicationObjectForPid:` can omit the bridge delegate token after private display lifecycle changes. Full-tree snapshots merge those recovered roots with the private frontmost application translation. Shallow snapshots with `maxDepth <= 2` use the tokenized frontmost application translation directly when it is available, and only run the expensive recovery sweep if frontmost lookup fails, so agent-oriented describe loops avoid launchctl and hit-test recovery overhead. Interactive-only snapshots also prune non-actionable native AX leaves during Objective-C serialization before the Rust-side compacting pass; keep this native pruning conservative so selector taps still retain actionable rows plus their ancestors. When multiple candidate application roots are discovered, serialize all of them in preferred order: non-extension app roots first, then largest translated roots, with `.appex`/PlugIns processes de-prioritized so SpringBoard and Safari app roots stay primary while widgets and WebContent roots remain debuggable. Widget renderer extension roots may report local frames; normalize those roots and children against matching SpringBoard widget placeholder frames before returning the snapshot.
8383
Physical chrome button support uses DeviceKit `chrome.json` input geometry for browser hit targets. Volume, action, mute, Apple Watch digital crown, Watch side button, and Watch left-side button dispatch through `IndigoHIDMessageForHIDArbitrary` with consumer/telephony/vendor HID usage pairs from the device chrome metadata; home, lock, and app-switcher remain on the existing SimulatorKit button paths. Apple Watch Digital Crown rotation dispatches through `IndigoHIDMessageForDigitalCrownEvent` when SimulatorKit exposes it, with `IndigoHIDMessageForScrollEvent(..., target=0x34)` as the fallback. tvOS simulators do not support direct screen touch; browser/API tap maps to Enter, swipe maps to arrow keys, and the native bridge rejects tvOS touch packets before they reach guest `SimulatorHID`. watchOS/tvOS skip dynamic pointer/mouse service warm-up because those guest runtimes abort on unsupported virtual services. Apple TV and Apple Watch simulators are fixed-orientation devices, so client and server rotation paths must not expose or dispatch device rotation for those families.
@@ -101,16 +101,17 @@ npm run build:all
101101
npm run package:vscode
102102
```
103103

104-
This now builds the Rust server in `server/` and copies the resulting binary to `build/simdeck`.
104+
This now builds the Rust server in `packages/server/` and copies the resulting binary to `build/simdeck`.
105105

106106
Codex worktrees can use the checked-in local environment config at
107107
`.codex/local-environment.toml`. Its setup runs `npm run codex:setup`, which
108-
hydrates root/client `node_modules` and `server/target` from the shared cache
109-
under `~/.cache/simdeck/codex-worktree-cache` or from another SimDeck checkout
110-
before falling back to `npm ci` for missing package installs and ensuring
111-
Homebrew `pkgconf`/`x264` are available for native builds. Its Run action
112-
executes `npm run codex:run`, which builds the CLI and client, saves fresh
113-
caches, and restarts the workspace-local daemon.
108+
hydrates root and `packages/client` `node_modules` plus
109+
`packages/server/target` from the shared cache under
110+
`~/.cache/simdeck/codex-worktree-cache` or from another SimDeck checkout before
111+
falling back to `npm ci` for missing package installs and ensuring Homebrew
112+
`pkgconf`/`x264` are available for native builds. Its Run action executes
113+
`npm run codex:run`, which builds the CLI and client, saves fresh caches, and
114+
restarts the workspace-local daemon.
114115

115116
Run the local daemon:
116117

@@ -182,9 +183,3 @@ only booted simulator, in that order. For agent navigation, prefer
182183
- If you expand the private framework bridge, document the Xcode/runtime assumptions here.
183184
- If a feature depends on a booted simulator, fail with a clear JSON error instead of silently returning an empty asset.
184185
- Do not reintroduce legacy `/stream.h264` handling. The supported live path is the Rust-managed WebRTC H.264 offer endpoint.
185-
186-
## Near-Term Roadmap
187-
188-
- Compose the private frame stream and CoreSimulator chrome into a single server-side render path.
189-
- Keep private Indigo multi-touch packet assumptions documented when Xcode runtimes change.
190-
- Add simulator creation and log streaming commands.

CONTRIBUTING.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,19 @@ Granular targets:
3636

3737
```sh
3838
npm run build:cli # Rust server -> build/simdeck-bin
39-
npm run build:client # browser bundle -> client/dist
39+
npm run build:client # browser bundle -> packages/client/dist
4040
npm run build:inspectors # nativescript + react-native inspectors
4141
npm run build:simdeck-test # simdeck/test subpath export
4242
npm run build:vscode-extension # alias for package:vscode-extension
4343
```
4444

45-
`scripts/build-cli.sh` builds the Rust server in `server/` and copies the
45+
`scripts/build-cli.sh` builds the Rust server in `packages/server/` and copies the
4646
resulting binary to `build/simdeck-bin`. The default is a host-arch build for
4747
fast iteration. Set `SIMDECK_BUILD_TARGET=<rust-target-triple>` to pin the
4848
output to an explicit Rust target — the release workflow uses
4949
`SIMDECK_BUILD_TARGET=aarch64-apple-darwin` for deterministic arm64 builds.
5050

51-
SimDeck is **arm64-only** by design: `cli/*.m` contains AArch64 inline asm
51+
SimDeck is **arm64-only** by design: `packages/server/native/*.m` contains AArch64 inline asm
5252
that does not compile on x86_64, and the npm package is gated by
5353
`"cpu": ["arm64"]` so installs on Intel Macs fail fast.
5454

@@ -133,7 +133,7 @@ npm run docs:preview
133133
Install the agent skill from a source checkout with [skills.sh](https://skills.sh/):
134134

135135
```sh
136-
npx skills add NativeScript/SimDeck --skill simdeck -a codex -g
136+
npx skills add NativeScript/SimDeck --skill simdeck -g
137137
```
138138

139139
The npm postinstall message also prints this command after a global install.
@@ -148,8 +148,8 @@ SimDeck. The setup script runs:
148148
npm run codex:setup
149149
```
150150

151-
That hydrates the root `node_modules`, `client/node_modules`, and
152-
`server/target` from `~/.cache/simdeck/codex-worktree-cache` or a matching
151+
That hydrates the root `node_modules`, `packages/client/node_modules`, and
152+
`packages/server/target` from `~/.cache/simdeck/codex-worktree-cache` or a matching
153153
existing SimDeck checkout. If either `node_modules` directory is still missing,
154154
it falls back to `npm ci` for that package so lockfiles stay unchanged. On
155155
macOS it also ensures the Homebrew `pkgconf` and `x264` packages are available

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<p align="center">
2-
<img width="180" src="./client/public/simdeck.png">
2+
<img width="180" src="./packages/client/public/simdeck.png">
33

44
<h1 align="center">SimDeck</h1>
55

actions/run-android-comment-session/action.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,12 @@ runs:
263263
version="$(SIMDECK_METADATA="${metadata}" python3 -c 'import json, os; print(json.loads(os.environ["SIMDECK_METADATA"])["version"])')"
264264
rm -rf "${simdeck_dir:?}/"*
265265
curl -fsSL "${tarball}" | tar -xz -C "${simdeck_dir}" --strip-components=1
266-
chmod +x "${simdeck_dir}/bin/simdeck.mjs" "${simdeck_dir}/build/simdeck-bin"
267-
ln -sf "${simdeck_dir}/bin/simdeck.mjs" "${bin_dir}/simdeck"
266+
simdeck_launcher="${simdeck_dir}/packages/cli/bin/simdeck.mjs"
267+
if [[ ! -f "${simdeck_launcher}" ]]; then
268+
simdeck_launcher="${simdeck_dir}/bin/simdeck.mjs"
269+
fi
270+
chmod +x "${simdeck_launcher}" "${simdeck_dir}/build/simdeck-bin"
271+
ln -sf "${simdeck_launcher}" "${bin_dir}/simdeck"
268272
echo "Installed ${SIMDECK_PACKAGE} ${version}"
269273
) &
270274
simdeck_install_pid="$!"

actions/run-ios-comment-session/action.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,12 @@ runs:
228228
version="$(SIMDECK_METADATA="${metadata}" python3 -c 'import json, os; print(json.loads(os.environ["SIMDECK_METADATA"])["version"])')"
229229
rm -rf "${simdeck_dir:?}/"*
230230
curl -fsSL "${tarball}" | tar -xz -C "${simdeck_dir}" --strip-components=1
231-
chmod +x "${simdeck_dir}/bin/simdeck.mjs" "${simdeck_dir}/build/simdeck-bin"
232-
ln -sf "${simdeck_dir}/bin/simdeck.mjs" "${bin_dir}/simdeck"
231+
simdeck_launcher="${simdeck_dir}/packages/cli/bin/simdeck.mjs"
232+
if [[ ! -f "${simdeck_launcher}" ]]; then
233+
simdeck_launcher="${simdeck_dir}/bin/simdeck.mjs"
234+
fi
235+
chmod +x "${simdeck_launcher}" "${simdeck_dir}/build/simdeck-bin"
236+
ln -sf "${simdeck_launcher}" "${bin_dir}/simdeck"
233237
echo "Installed ${SIMDECK_PACKAGE} ${version}"
234238
) &
235239
simdeck_install_pid="$!"

0 commit comments

Comments
 (0)