zig-mobile-runner 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/CHANGELOG.md +484 -0
- package/CONTRIBUTING.md +42 -0
- package/FEATURES.md +112 -0
- package/LICENSE +21 -0
- package/README.md +255 -0
- package/SECURITY.md +34 -0
- package/build.zig +38 -0
- package/build.zig.zon +7 -0
- package/clients/README.md +144 -0
- package/clients/go/README.md +24 -0
- package/clients/go/examples/fake-session/main.go +93 -0
- package/clients/go/go.mod +3 -0
- package/clients/go/zmr/client.go +432 -0
- package/clients/kotlin/README.md +35 -0
- package/clients/kotlin/build.gradle.kts +35 -0
- package/clients/kotlin/settings.gradle.kts +15 -0
- package/clients/kotlin/src/main/kotlin/dev/zmr/FakeSession.kt +86 -0
- package/clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt +67 -0
- package/clients/python/README.md +29 -0
- package/clients/python/examples/fake_session.py +48 -0
- package/clients/python/pyproject.toml +13 -0
- package/clients/python/zmr_client.py +202 -0
- package/clients/rust/Cargo.lock +107 -0
- package/clients/rust/Cargo.toml +10 -0
- package/clients/rust/README.md +19 -0
- package/clients/rust/examples/fake_session.rs +70 -0
- package/clients/rust/src/lib.rs +461 -0
- package/clients/swift/Package.swift +16 -0
- package/clients/swift/README.md +36 -0
- package/clients/swift/Sources/ZMRClient/ZMRClient.swift +114 -0
- package/clients/swift/Sources/ZMRFakeSession/main.swift +86 -0
- package/clients/typescript/README.md +34 -0
- package/clients/typescript/examples/fake-session.mjs +36 -0
- package/clients/typescript/index.d.ts +144 -0
- package/clients/typescript/index.mjs +192 -0
- package/clients/typescript/package.json +8 -0
- package/docs/adr/0001-agent-native-runner-boundary.md +31 -0
- package/docs/adr/0002-app-local-zmr-contract.md +39 -0
- package/docs/adr/0003-ios-simulator-xctest-shim.md +41 -0
- package/docs/adr/0004-benchmark-claims-and-baseline-collection.md +37 -0
- package/docs/adr/README.md +12 -0
- package/docs/ai-agents.md +156 -0
- package/docs/app-integration.md +316 -0
- package/docs/benchmarking.md +275 -0
- package/docs/client-installation.md +141 -0
- package/docs/clients.md +98 -0
- package/docs/config.md +175 -0
- package/docs/demo.md +259 -0
- package/docs/dsl.md +57 -0
- package/docs/install.md +233 -0
- package/docs/market-positioning.md +70 -0
- package/docs/npm.md +359 -0
- package/docs/protocol-fixtures/README.md +8 -0
- package/docs/protocol-fixtures/core-session.requests.jsonl +8 -0
- package/docs/protocol-fixtures/core-session.responses.jsonl +8 -0
- package/docs/protocol-versioning.md +65 -0
- package/docs/protocol.md +560 -0
- package/docs/publication.md +77 -0
- package/docs/release-audit.md +99 -0
- package/docs/release-candidate.md +111 -0
- package/docs/release-evidence.md +188 -0
- package/docs/release-notes-template.md +58 -0
- package/docs/roadmap.md +334 -0
- package/docs/scenario-authoring.md +88 -0
- package/docs/shipping.md +170 -0
- package/docs/trace-privacy.md +88 -0
- package/docs/troubleshooting.md +256 -0
- package/examples/android-app-auth-probe.json +89 -0
- package/examples/android-app-error-state.json +13 -0
- package/examples/android-app-login-smoke.json +192 -0
- package/examples/android-app-onboarding.json +12 -0
- package/examples/android-app-referral-deep-link.json +12 -0
- package/examples/android-shim-smoke.json +19 -0
- package/examples/demo-failure.json +12 -0
- package/examples/demo-fake.json +14 -0
- package/examples/ios-dev-client-open-link.json +26 -0
- package/examples/ios-dev-client-route-snapshot.json +24 -0
- package/examples/ios-shim-smoke.json +23 -0
- package/examples/ios-smoke.json +9 -0
- package/go.work +3 -0
- package/npm/agents.mjs +183 -0
- package/npm/app-config.mjs +95 -0
- package/npm/build-zmr.mjs +21 -0
- package/npm/commands.mjs +104 -0
- package/npm/generated-files.mjs +50 -0
- package/npm/index.mjs +75 -0
- package/npm/init-app.mjs +80 -0
- package/npm/package-scripts.mjs +72 -0
- package/npm/postinstall.mjs +21 -0
- package/npm/scaffold.mjs +179 -0
- package/npm/scenarios.mjs +93 -0
- package/npm/setup.mjs +69 -0
- package/npm/wizard.mjs +117 -0
- package/npm/zmr.mjs +23 -0
- package/package.json +114 -0
- package/prebuilds/darwin-arm64/zmr +0 -0
- package/prebuilds/darwin-x64/zmr +0 -0
- package/prebuilds/linux-arm64/zmr +0 -0
- package/prebuilds/linux-x64/zmr +0 -0
- package/schemas/README.md +26 -0
- package/schemas/action-result.schema.json +27 -0
- package/schemas/capabilities-output.schema.json +98 -0
- package/schemas/devices-output.schema.json +25 -0
- package/schemas/doctor-output.schema.json +51 -0
- package/schemas/explain-output.schema.json +51 -0
- package/schemas/import-output.schema.json +23 -0
- package/schemas/init-output.schema.json +71 -0
- package/schemas/json-rpc.schema.json +55 -0
- package/schemas/release-manifest.schema.json +43 -0
- package/schemas/release-readiness-output.schema.json +127 -0
- package/schemas/run-output.schema.json +43 -0
- package/schemas/scenario.schema.json +128 -0
- package/schemas/schemas-output.schema.json +26 -0
- package/schemas/semantic-snapshot.schema.json +116 -0
- package/schemas/snapshot.schema.json +60 -0
- package/schemas/trace-event.schema.json +14 -0
- package/schemas/trace-manifest.schema.json +59 -0
- package/schemas/validate-output.schema.json +42 -0
- package/schemas/version-output.schema.json +23 -0
- package/schemas/zmr-config.schema.json +75 -0
- package/scripts/android-emulator.sh +126 -0
- package/scripts/assert-ios-physical-ready.sh +213 -0
- package/scripts/benchmark-command.sh +307 -0
- package/scripts/benchmark.sh +359 -0
- package/scripts/benchmark_gate.py +117 -0
- package/scripts/benchmark_result_row.py +88 -0
- package/scripts/compare-benchmarks.py +288 -0
- package/scripts/create-android-demo-app.sh +342 -0
- package/scripts/create-ios-demo-app.sh +261 -0
- package/scripts/demo-android-real.sh +232 -0
- package/scripts/demo-ios-real.sh +270 -0
- package/scripts/demo.sh +464 -0
- package/scripts/device-matrix.sh +338 -0
- package/scripts/ensure-ios-shim-target.rb +237 -0
- package/scripts/install-android-shim.sh +281 -0
- package/scripts/install-ios-shim.sh +589 -0
- package/scripts/pilot-gate.sh +560 -0
- package/scripts/release-readiness.py +838 -0
- package/scripts/release-readiness.sh +91 -0
- package/scripts/run-android-pilot.sh +561 -0
- package/scripts/run-ios-pilot.sh +509 -0
- package/shims/android/README.md +21 -0
- package/shims/android/ZMRShimInstrumentedTest.java +152 -0
- package/shims/android/protocol.md +18 -0
- package/shims/ios/README.md +50 -0
- package/shims/ios/ZMRShim.swift +110 -0
- package/shims/ios/ZMRShimUITestCase.swift +475 -0
- package/shims/ios/protocol.md +74 -0
- package/skills/zmr-mobile-testing/SKILL.md +127 -0
- package/src/android.zig +344 -0
- package/src/android_device_info.zig +99 -0
- package/src/android_emulator.zig +154 -0
- package/src/android_screen_recording.zig +112 -0
- package/src/android_shell.zig +112 -0
- package/src/bundle.zig +124 -0
- package/src/bundle_redaction.zig +272 -0
- package/src/bundle_tar.zig +123 -0
- package/src/cli_devices.zig +97 -0
- package/src/cli_doctor.zig +114 -0
- package/src/cli_import.zig +70 -0
- package/src/cli_info.zig +39 -0
- package/src/cli_init.zig +72 -0
- package/src/cli_output.zig +467 -0
- package/src/cli_run.zig +259 -0
- package/src/cli_serve.zig +287 -0
- package/src/cli_trace.zig +111 -0
- package/src/cli_validate.zig +41 -0
- package/src/command.zig +211 -0
- package/src/config.zig +305 -0
- package/src/config_diagnostics.zig +212 -0
- package/src/config_paths.zig +49 -0
- package/src/device_registry.zig +37 -0
- package/src/doctor.zig +412 -0
- package/src/doctor_hints.zig +52 -0
- package/src/errors.zig +55 -0
- package/src/fake_device.zig +163 -0
- package/src/health.zig +28 -0
- package/src/importer.zig +343 -0
- package/src/importer_json.zig +100 -0
- package/src/importer_model.zig +103 -0
- package/src/ios.zig +399 -0
- package/src/ios_devices.zig +219 -0
- package/src/ios_lifecycle.zig +72 -0
- package/src/ios_shim.zig +242 -0
- package/src/ios_snapshot.zig +20 -0
- package/src/json_fields.zig +80 -0
- package/src/json_rpc.zig +150 -0
- package/src/json_rpc_methods.zig +318 -0
- package/src/json_rpc_observation.zig +31 -0
- package/src/json_rpc_params.zig +52 -0
- package/src/json_rpc_protocol.zig +110 -0
- package/src/json_rpc_trace.zig +73 -0
- package/src/main.zig +135 -0
- package/src/mcp.zig +234 -0
- package/src/mcp_protocol.zig +64 -0
- package/src/mcp_trace.zig +83 -0
- package/src/report.zig +346 -0
- package/src/report_html.zig +63 -0
- package/src/report_values.zig +27 -0
- package/src/run_options.zig +152 -0
- package/src/runner.zig +280 -0
- package/src/runner_actions.zig +109 -0
- package/src/runner_config.zig +6 -0
- package/src/runner_diagnostics.zig +268 -0
- package/src/runner_events.zig +170 -0
- package/src/runner_native.zig +88 -0
- package/src/runner_waits.zig +300 -0
- package/src/scaffold.zig +472 -0
- package/src/scenario.zig +346 -0
- package/src/scenario_fields.zig +50 -0
- package/src/schema_registry.zig +53 -0
- package/src/selector.zig +84 -0
- package/src/semantic.zig +171 -0
- package/src/trace.zig +315 -0
- package/src/trace_json.zig +340 -0
- package/src/trace_summary.zig +218 -0
- package/src/trace_summary_diagnostic.zig +202 -0
- package/src/types.zig +120 -0
- package/src/uiautomator.zig +164 -0
- package/src/validation.zig +187 -0
- package/src/version.zig +22 -0
- package/viewer/app.js +373 -0
- package/viewer/index.html +126 -0
- package/viewer/parser.js +233 -0
- package/viewer/styles.css +585 -0
package/docs/npm.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# npm Package
|
|
2
|
+
|
|
3
|
+
ZMR can be installed in a mobile app codebase as a dev dependency:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install --save-dev zig-mobile-runner
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The package exposes:
|
|
10
|
+
|
|
11
|
+
- `zmr`: CLI binary wrapper.
|
|
12
|
+
- `zmr-init`: app-local scenario scaffolder.
|
|
13
|
+
- `zmr-wizard`: guided setup and dependency checker.
|
|
14
|
+
- `zmr-benchmark`: repeated-run wrapper with pass-rate and duration gates.
|
|
15
|
+
- `zmr-benchmark-command`: repeated-run wrapper for app-local baseline commands
|
|
16
|
+
so existing runner flows can be compared without custom glue.
|
|
17
|
+
- `zmr-compare-benchmarks`: generic comparison report for ZMR and app-local
|
|
18
|
+
baseline benchmark rows.
|
|
19
|
+
- `zmr-device-matrix`: local multi-device Android/iOS matrix runner with
|
|
20
|
+
simulator and physical iOS row support plus pass-rate gates.
|
|
21
|
+
- `zmr-pilot-gate`: external release pilot gate that delegates to the Android
|
|
22
|
+
and iOS app pilot wrappers on machines with real targets.
|
|
23
|
+
- `zmr-assert-ios-physical-ready`: verifies that a requested physical iOS
|
|
24
|
+
device is connected, trusted, and ready before physical-device pilots; pass
|
|
25
|
+
`--xcrun <path>` when using a custom Xcode toolchain and
|
|
26
|
+
`--evidence-out traces/zmr-pilots/evidence.jsonl` to append a
|
|
27
|
+
release-readiness row.
|
|
28
|
+
- `zmr-release-readiness`: checks one or more release/pilot evidence files for
|
|
29
|
+
dev-preview, production, or market-claim readiness, lists missing, insufficient, failed, and planned blockers, and emits safe claim wording.
|
|
30
|
+
- `zmr-install-android-shim`: writes the app-local Android instrumentation
|
|
31
|
+
shim command and source file.
|
|
32
|
+
- `zmr-install-ios-shim`: writes the app-local iOS XCTest shim command and
|
|
33
|
+
source files.
|
|
34
|
+
- `zmr-create-android-demo-app`: creates a generic native Android APK with a
|
|
35
|
+
matching `.zmr/` smoke scenario for public demos and emulator pilots.
|
|
36
|
+
- `zmr-create-ios-demo-app`: creates a generic SwiftUI simulator app with
|
|
37
|
+
`.zmr/` scenarios and the iOS shim already installed for public demos.
|
|
38
|
+
- `zmr-demo-android`: creates, installs, and runs the generated Android demo
|
|
39
|
+
through a real emulator/device.
|
|
40
|
+
- `zmr-demo-ios`: creates, builds, and runs the generated iOS simulator demo
|
|
41
|
+
through the real iOS pilot wrapper.
|
|
42
|
+
- `import { runZmr, spawnZmr, resolveBinary } from "zig-mobile-runner"` for Node scripts.
|
|
43
|
+
- packaged docs, schemas, examples, reference clients, and the reusable
|
|
44
|
+
`skills/zmr-mobile-testing` agent skill.
|
|
45
|
+
|
|
46
|
+
Maintainer release-candidate checks live in the source checkout, not the app-install npm package. Use `./scripts/release-candidate.sh` from the ZMR
|
|
47
|
+
repository when preparing a ZMR release; use `zmr-release-readiness` from an
|
|
48
|
+
app repo to evaluate evidence produced by app-local pilot gates.
|
|
49
|
+
|
|
50
|
+
## App Setup
|
|
51
|
+
|
|
52
|
+
From the app repo:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx zmr-wizard --app-id com.example.mobiletest
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This creates:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
.zmr/
|
|
62
|
+
config.json
|
|
63
|
+
android-smoke.json
|
|
64
|
+
ios-smoke.json
|
|
65
|
+
device-matrix.json
|
|
66
|
+
AGENTS.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`.zmr/config.json` is the app-local source of truth for default devices, trace directories, smoke scenario paths, and suggested script commands. `.zmr/device-matrix.json` gives CI a ready Android/iOS matrix starting point. ZMR auto-discovers config from the app repo, and explicit CLI flags override it. The wizard does not inspect or depend on any other mobile test runner configuration.
|
|
70
|
+
`.zmr/AGENTS.md` gives AI agents an app-local operating note with strict
|
|
71
|
+
doctor/validate commands, schema discovery, direct `zmr run` smoke commands,
|
|
72
|
+
JSON-RPC and MCP startup commands, selector guidance, the exact
|
|
73
|
+
`zmr explain traces/zmr-agent --json` failure-triage command, the exact
|
|
74
|
+
`zmr export traces/zmr-agent --out traces/zmr-agent-redacted.zmrtrace --redact`
|
|
75
|
+
redacted trace export command, and a
|
|
76
|
+
`zmr-release-readiness` claim guard for release summaries.
|
|
77
|
+
`zmr-init` and wizard runs without `--package-json` write direct commands in `.zmr/AGENTS.md` so agents can execute the generated guidance immediately.
|
|
78
|
+
`zmr-init` accepts the same platform, shim, and Expo dev-client scaffold flags as the wizard, plus `--package-json` for non-interactive app templates that do not need dependency checks.
|
|
79
|
+
`zmr-init` prints direct `Next steps` commands before the package-script snippet so humans and agents can run the generated smoke, reliability, matrix, pilot, JSON-RPC, MCP, failure-triage, and redacted-export commands without editing `package.json`.
|
|
80
|
+
For setup scripts and AI agents that need a machine-readable handoff, use
|
|
81
|
+
`npx zmr-init --json --dir . --app-id com.example.mobiletest` or
|
|
82
|
+
`npx zmr-wizard --json --dir . --app-id com.example.mobiletest --android --ios`.
|
|
83
|
+
The JSON form is covered by `schemas/init-output.schema.json` and includes
|
|
84
|
+
the generated config, scenario, Expo dev-client scenario, device matrix, and
|
|
85
|
+
`AGENTS.md` paths plus `nextCommands`, `scriptCount`, and `scriptNames`.
|
|
86
|
+
Wizard runs with `--package-json` write npm script commands in `.zmr/AGENTS.md` because the wizard installs those scripts into `package.json`. Run `npm run zmr:validate` after editing generated scenarios and before starting longer smoke, matrix, or pilot runs.
|
|
87
|
+
|
|
88
|
+
Add app-local scripts:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"scripts": {
|
|
93
|
+
"zmr:doctor": "zmr doctor --strict --json --config .zmr/config.json",
|
|
94
|
+
"zmr:schemas": "zmr schemas --json",
|
|
95
|
+
"zmr:validate": "zmr validate --json .zmr/android-smoke.json && zmr validate --json .zmr/ios-smoke.json",
|
|
96
|
+
"zmr:android": "zmr run .zmr/android-smoke.json --device emulator-5554 --trace-dir traces/zmr-android",
|
|
97
|
+
"zmr:android:report": "zmr report traces/zmr-android --out traces/zmr-android/report.html",
|
|
98
|
+
"zmr:android:reliability": "export ZMR_BIN=\"${ZMR_BIN:-zmr}\"; zmr-benchmark --zmr .zmr/android-smoke.json --device emulator-5554 --app-id com.example.mobiletest --runs 20 --trace-root traces/zmr-android-reliability --min-pass-rate 100 --max-failures 0 --max-p95-ms 30000 && \"$ZMR_BIN\" report traces/zmr-android-reliability --out traces/zmr-android-reliability/report.html",
|
|
99
|
+
"zmr:matrix": "ZMR_BIN=${ZMR_BIN:-zmr} zmr-device-matrix --matrix .zmr/device-matrix.json --trace-root traces/zmr-matrix --min-pass-rate 100 --max-failures 0",
|
|
100
|
+
"zmr:ios": "zmr run .zmr/ios-smoke.json --platform ios --device booted --trace-dir traces/zmr-ios",
|
|
101
|
+
"zmr:ios:report": "zmr report traces/zmr-ios --out traces/zmr-ios/report.html",
|
|
102
|
+
"zmr:ios:reliability": "export ZMR_BIN=\"${ZMR_BIN:-zmr}\"; zmr-benchmark --zmr .zmr/ios-smoke.json --platform ios --device booted --app-id com.example.mobiletest --xcrun xcrun --runs 20 --trace-root traces/zmr-ios-reliability --min-pass-rate 100 --max-failures 0 --max-p95-ms 45000 && \"$ZMR_BIN\" report traces/zmr-ios-reliability --out traces/zmr-ios-reliability/report.html",
|
|
103
|
+
"zmr:pilot": "zmr-pilot-gate --android --ios --android-app-root . --android-app-id com.example.mobiletest --android-device emulator-5554 --ios-app-root . --ios-app-path ./build/Debug-iphonesimulator/Sample.app --ios-app-id com.example.mobiletest --ios-device booted --runs 20 --min-pass-rate 100 --max-failures 0 --evidence-out traces/zmr-pilots/evidence.jsonl",
|
|
104
|
+
"zmr:readiness": "zmr-release-readiness --evidence traces/zmr-pilots/evidence.jsonl --target production --json",
|
|
105
|
+
"zmr:serve": "zmr serve --transport stdio --config .zmr/config.json --trace-dir traces/zmr-agent",
|
|
106
|
+
"zmr:mcp": "zmr mcp --config .zmr/config.json --trace-dir traces/zmr-agent",
|
|
107
|
+
"zmr:explain": "zmr explain traces/zmr-agent --json",
|
|
108
|
+
"zmr:export": "zmr export traces/zmr-agent --out traces/zmr-agent-redacted.zmrtrace --redact"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Reliability scripts export one `ZMR_BIN` value and reuse it for both
|
|
114
|
+
`zmr-benchmark` and report generation, so CI can pin a custom runner binary
|
|
115
|
+
without mixing binaries between the run and report steps.
|
|
116
|
+
|
|
117
|
+
For non-interactive CI or template setup:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx zmr-wizard \
|
|
121
|
+
--yes \
|
|
122
|
+
--app-id com.example.mobiletest \
|
|
123
|
+
--android \
|
|
124
|
+
--android-shim ./.zmr/android-shim \
|
|
125
|
+
--ios \
|
|
126
|
+
--ios-shim ./.zmr/ios-shim \
|
|
127
|
+
--expo-dev-client-scheme mobiletest \
|
|
128
|
+
--package-json
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The wizard checks Node, ZMR, ADB, `xcrun`, and Zig when applicable. It scaffolds `.zmr` scenarios and can patch `package.json` scripts.
|
|
132
|
+
It also ensures `traces/` is ignored in the app repo.
|
|
133
|
+
When `--expo-dev-client-scheme` is set, it also writes
|
|
134
|
+
`.zmr/android-dev-client-smoke.json` and `.zmr/ios-dev-client-open-link.json`.
|
|
135
|
+
Package-script setup also adds `zmr:android:dev-client`,
|
|
136
|
+
`zmr:android:dev-client:report`, `zmr:ios:dev-client`, and
|
|
137
|
+
`zmr:ios:dev-client:report` for the generated dev-client traces.
|
|
138
|
+
The Android scenario opens Metro through `10.0.2.2:8081`; the iOS simulator
|
|
139
|
+
scenario opens `127.0.0.1:8081`.
|
|
140
|
+
Rerunning the wizard refreshes generated `.zmr/config.json`,
|
|
141
|
+
`.zmr/device-matrix.json`, and `.zmr/AGENTS.md` for the selected platforms,
|
|
142
|
+
while existing scenario files are left in place so local flow edits are not
|
|
143
|
+
overwritten.
|
|
144
|
+
`zmr-init` can be used for the same non-interactive scaffold without dependency
|
|
145
|
+
checks:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npx zmr-init \
|
|
149
|
+
--dir . \
|
|
150
|
+
--app-id com.example.mobiletest \
|
|
151
|
+
--ios \
|
|
152
|
+
--ios-shim ./.zmr/ios-shim \
|
|
153
|
+
--expo-dev-client-scheme mobiletest \
|
|
154
|
+
--package-json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
When platform flags are omitted, `zmr-init` scaffolds both Android and iOS.
|
|
158
|
+
With `--package-json`, `zmr-init` patches `package.json` directly and writes
|
|
159
|
+
`.zmr/AGENTS.md` with `npm run zmr:*` commands. Without `--package-json`, it
|
|
160
|
+
prints the script map for copy-free review and keeps `.zmr/AGENTS.md` on direct
|
|
161
|
+
`zmr` commands.
|
|
162
|
+
Rerunning `zmr init --app` refreshes generated `.zmr/config.json`,
|
|
163
|
+
`.zmr/device-matrix.json`, and `.zmr/AGENTS.md` the same way, while preserving
|
|
164
|
+
existing scenario files. Pass `--force` only when you intentionally want to
|
|
165
|
+
replace the generated smoke scenarios too.
|
|
166
|
+
The reliability scripts use `zmr-benchmark` with `100%` pass-rate and zero-failure
|
|
167
|
+
defaults; tune p95 thresholds only after capturing stable local baseline runs.
|
|
168
|
+
The wizard only adds `zmr:readiness` for Android+iOS setups because the
|
|
169
|
+
production readiness target requires Android, iOS simulator, and physical iOS
|
|
170
|
+
evidence; single-platform setups should use `zmr:pilot` and the platform
|
|
171
|
+
reliability script until the full matrix is enabled.
|
|
172
|
+
For release validation, `zmr-pilot-gate` is safe to run from the app checkout:
|
|
173
|
+
relative app roots, APK paths, simulator app paths, shim paths, and trace roots
|
|
174
|
+
are resolved against the current app directory before the packaged runner
|
|
175
|
+
scripts are invoked. Pass `--zmr-bin ./node_modules/.bin/zmr` when CI needs an
|
|
176
|
+
explicit runner binary instead of relying on `PATH` or `ZMR_BIN`. Add
|
|
177
|
+
`--evidence-out traces/zmr-pilots/evidence.jsonl` so production-readiness rows
|
|
178
|
+
can be evaluated with `zmr-release-readiness`.
|
|
179
|
+
|
|
180
|
+
The standalone CLI has the same non-interactive app-local bootstrap for
|
|
181
|
+
source or release-archive installs:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
zmr init --app --json --dir . --app-id com.example.mobiletest
|
|
185
|
+
zmr doctor --strict --json --config .zmr/config.json
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
See [ai-agents.md](ai-agents.md) for JSON-RPC agent workflows and
|
|
189
|
+
[`../skills/zmr-mobile-testing/SKILL.md`](../skills/zmr-mobile-testing/SKILL.md)
|
|
190
|
+
for the packaged agent skill.
|
|
191
|
+
|
|
192
|
+
Omit `--android-shim` or `--ios-shim` for shell/screenshot-only smoke runs.
|
|
193
|
+
Include them when the app repo provides native shim commands for faster
|
|
194
|
+
hierarchy and selector actions.
|
|
195
|
+
|
|
196
|
+
## Android Demo App
|
|
197
|
+
|
|
198
|
+
For a clean public Android demo APK that does not depend on a private app:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npx zmr-demo-android --out /tmp/zmr-android-demo --device emulator-5554 --avd <avd-name>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
That command uses Android SDK command-line tools directly, so it does not need
|
|
205
|
+
Gradle or network access. It creates the demo APK, boots the named AVD when
|
|
206
|
+
the requested device is not already ready, installs the app, runs the smoke
|
|
207
|
+
scenario, and writes traces under `<out>/traces/pilot`.
|
|
208
|
+
|
|
209
|
+
To inspect or customize the generated app before running manually:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
npx zmr-create-android-demo-app --out /tmp/zmr-android-demo
|
|
213
|
+
adb install -r /tmp/zmr-android-demo/build/app-debug.apk
|
|
214
|
+
zmr run /tmp/zmr-android-demo/.zmr/android-smoke.json \
|
|
215
|
+
--device emulator-5554 \
|
|
216
|
+
--app-id com.example.mobiletest \
|
|
217
|
+
--trace-dir /tmp/zmr-android-demo/traces/android-demo
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## iOS Demo App
|
|
221
|
+
|
|
222
|
+
For a clean public iOS demo that does not depend on a private app:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
npx zmr-demo-ios --out /tmp/zmr-ios-demo --device booted --cleanup-build-products
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
That command creates the demo app, boots an available simulator when needed,
|
|
229
|
+
builds it with Xcode, runs the iOS pilot, and writes trace reports plus
|
|
230
|
+
redacted bundles. `--cleanup-build-products` removes generated Xcode
|
|
231
|
+
`DerivedData` after the trace reports are written, which keeps repeated demo
|
|
232
|
+
runs from filling local disk. To inspect or customize the app before running
|
|
233
|
+
the pilot manually:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
npx zmr-create-ios-demo-app --out /tmp/zmr-ios-demo
|
|
237
|
+
cd /tmp/zmr-ios-demo
|
|
238
|
+
xcodebuild -project ios/ZMRDemo.xcodeproj -scheme ZMRDemo -destination 'generic/platform=iOS Simulator' -derivedDataPath DerivedData build
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Then boot a simulator and run the pilot wrapper:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
zmr-pilot-gate \
|
|
245
|
+
--ios \
|
|
246
|
+
--ios-app-root /tmp/zmr-ios-demo \
|
|
247
|
+
--ios-app-path /tmp/zmr-ios-demo/DerivedData/Build/Products/Debug-iphonesimulator/ZMRDemo.app \
|
|
248
|
+
--ios-app-id com.example.mobiletest \
|
|
249
|
+
--ios-device booted \
|
|
250
|
+
--ios-shim /tmp/zmr-ios-demo/.zmr/ios-shim \
|
|
251
|
+
--zmr-bin ./node_modules/.bin/zmr
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
When `--ios-shim` is set, the pilot prewarms the XCTest shim before scenario
|
|
255
|
+
timing with an `appState` command. Pass `--skip-shim-prewarm` only when
|
|
256
|
+
intentionally measuring cold shim startup.
|
|
257
|
+
|
|
258
|
+
To scaffold the Android shim command into an app repo:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
npx zmr-install-android-shim \
|
|
262
|
+
--app-root . \
|
|
263
|
+
--test-package com.example.mobiletest.test \
|
|
264
|
+
--runner androidx.test.runner.AndroidJUnitRunner \
|
|
265
|
+
--android-module android/app \
|
|
266
|
+
--gradle-file android/app/build.gradle
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`--android-module` copies the shim into
|
|
270
|
+
`android/app/src/androidTest/java/dev/zmr/shim/ZMRShimInstrumentedTest.java`.
|
|
271
|
+
`--gradle-file` appends guarded Gradle blocks for `testInstrumentationRunner`,
|
|
272
|
+
AndroidX Test runner, JUnit extension, and UI Automator. If the Gradle file
|
|
273
|
+
already has a custom `testInstrumentationRunner` and `--runner` is omitted, the
|
|
274
|
+
generated `.zmr/android-shim` command uses that runner. Run ZMR with
|
|
275
|
+
`--android-shim ./.zmr/android-shim`.
|
|
276
|
+
|
|
277
|
+
To scaffold the iOS shim command into an app repo:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
npx zmr-install-ios-shim \
|
|
281
|
+
--app-root . \
|
|
282
|
+
--scheme SampleUITests \
|
|
283
|
+
--test-target SampleUITests \
|
|
284
|
+
--workspace ios/Sample.xcworkspace \
|
|
285
|
+
--app-target SampleApp \
|
|
286
|
+
--derived-data-path ios/build/ZMRDerivedData \
|
|
287
|
+
--bundle-id com.example.mobiletest \
|
|
288
|
+
--patch-xcodeproj
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The installer writes:
|
|
292
|
+
|
|
293
|
+
- `.zmr/ios-shim`
|
|
294
|
+
- `.zmr/ensure-ios-shim-target.sh`
|
|
295
|
+
- `.zmr/ensure-ios-shim-target.rb`
|
|
296
|
+
- `.zmr/ZMRShimUITestCase.swift`
|
|
297
|
+
- `.zmr/shims/ios/ZMRShim.swift`
|
|
298
|
+
- `.zmr/ZMRShimUITests-Info.plist`
|
|
299
|
+
- `.zmr/config.json` `tools.iosShimPath`, creating the config file when needed
|
|
300
|
+
|
|
301
|
+
Run `.zmr/ensure-ios-shim-target.sh` to create/update the UI test target, add
|
|
302
|
+
the Swift files, configure the generated Info.plist, and write a shared scheme.
|
|
303
|
+
The helper uses the Ruby `xcodeproj` gem. With `--workspace`, it resolves the
|
|
304
|
+
referenced `.xcodeproj` automatically when there is one project, or when exactly
|
|
305
|
+
one project contains `--app-target`, or when `--bundle-id` disambiguates
|
|
306
|
+
matching app targets. Pass `--project ios/Sample.xcodeproj` explicitly for
|
|
307
|
+
still-ambiguous multi-project workspaces or project-only apps.
|
|
308
|
+
|
|
309
|
+
Run ZMR with `--ios-shim ./.zmr/ios-shim`, or rely on the generated
|
|
310
|
+
`tools.iosShimPath` in `.zmr/config.json`.
|
|
311
|
+
The generated command caches `build-for-testing` output under
|
|
312
|
+
`.zmr/ios-shim-state/`, uses `test-without-building` for selector commands, and
|
|
313
|
+
prints the last Xcode log lines when XCTest fails. Set
|
|
314
|
+
`ZMR_IOS_SHIM_FORCE_REBUILD=1` after app-side target changes, or
|
|
315
|
+
`ZMR_IOS_SHIM_ONESHOT=1` for a cold-start fallback while debugging app-side Xcode
|
|
316
|
+
wiring.
|
|
317
|
+
|
|
318
|
+
## Native Binary Resolution
|
|
319
|
+
|
|
320
|
+
The npm wrapper resolves `zmr` in this order:
|
|
321
|
+
|
|
322
|
+
1. `ZMR_BIN=/path/to/zmr`
|
|
323
|
+
2. bundled `prebuilds/<platform>-<arch>/zmr`
|
|
324
|
+
3. local source build at `zig-out/bin/zmr`
|
|
325
|
+
|
|
326
|
+
Shipped shell helpers such as `zmr-pilot-gate`, `zmr-demo-ios`, and the pilot
|
|
327
|
+
wrappers resolve the runner in this order: `ZMR_BIN`, `PATH` `zmr`, then the
|
|
328
|
+
source-checkout `zig-out/bin/zmr` fallback. That keeps app installs on the npm
|
|
329
|
+
wrapper path while preserving source-checkout development.
|
|
330
|
+
Relative app paths passed to pilot wrappers are resolved from the app directory
|
|
331
|
+
where the command was started, not from the installed package directory.
|
|
332
|
+
|
|
333
|
+
If no binary is found, install Zig and run:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
npm run build:zmr
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
For release publishing, build npm tarballs with:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
npm run pack:npm
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
That command builds release binaries, copies them into `prebuilds/`, and runs `npm pack`.
|
|
346
|
+
|
|
347
|
+
## Node API
|
|
348
|
+
|
|
349
|
+
```js
|
|
350
|
+
import { runZmr } from "zig-mobile-runner";
|
|
351
|
+
|
|
352
|
+
await runZmr([
|
|
353
|
+
"run",
|
|
354
|
+
"--config",
|
|
355
|
+
".zmr/config.json",
|
|
356
|
+
]);
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Use the CLI for normal app scripts and the JS API for custom toolchains or agent orchestration.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Protocol Fixtures
|
|
2
|
+
|
|
3
|
+
These JSONL fixtures pin exact JSON-RPC request and response shapes for stable
|
|
4
|
+
core methods. The Zig unit suite feeds the request fixtures through the local
|
|
5
|
+
dispatcher and compares byte-for-byte response output.
|
|
6
|
+
|
|
7
|
+
When changing any response shape, update these fixtures deliberately and bump or
|
|
8
|
+
document protocol compatibility as needed.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{"jsonrpc":"2.0","id":1,"method":"runner.capabilities","params":{}}
|
|
2
|
+
{"jsonrpc":"2.0","id":2,"method":"device.list","params":{}}
|
|
3
|
+
{"jsonrpc":"2.0","id":3,"method":"session.create","params":{}}
|
|
4
|
+
{"jsonrpc":"2.0","id":4,"method":"app.launch","params":{}}
|
|
5
|
+
{"jsonrpc":"2.0","id":5,"method":"app.openLink","params":{"url":"exampleapp://fixture"}}
|
|
6
|
+
{"jsonrpc":"2.0","id":6,"method":"app.clearState","params":{}}
|
|
7
|
+
{"jsonrpc":"2.0","id":7,"method":"trace.export","params":{}}
|
|
8
|
+
{"jsonrpc":"2.0","id":8,"method":"session.close","params":{}}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{"jsonrpc":"2.0","id":1,"result":{"name":"zmr","version":"0.1.0","protocolVersion":"2026-04-28","protocol":{"version":"2026-04-28","minimumCompatibleVersion":"2026-04-28","stability":"dev-preview","breakingChangePolicy":"version-and-changelog"},"platforms":["android","ios"],"platformSupport":{"android":{"status":"supported","deviceTypes":["emulator","physical"],"automation":["adb","uiautomator","android-shim"]},"ios":{"status":"supported","deviceTypes":["simulator","physical"],"automation":["simctl","devicectl","xctest-shim"],"physicalDevices":true}},"iosPreview":false,"transports":["stdio","tcp"],"methods":["runner.capabilities","device.list","session.create","session.close","app.install","app.launch","app.stop","app.openLink","app.clearState","observe.snapshot","observe.semanticSnapshot","ui.tap","ui.type","ui.eraseText","ui.hideKeyboard","ui.swipe","ui.pressBack","ui.scrollUntilVisible","wait.until","wait.any","wait.gone","assert.visible","assert.notVisible","assert.healthy","trace.events","trace.export"]}}
|
|
2
|
+
{"jsonrpc":"2.0","id":2,"result":[{"serial":"fake-device-1","state":"device","ready":true}]}
|
|
3
|
+
{"jsonrpc":"2.0","id":3,"result":{"sessionId":"default"}}
|
|
4
|
+
{"jsonrpc":"2.0","id":4,"result":true}
|
|
5
|
+
{"jsonrpc":"2.0","id":5,"result":true}
|
|
6
|
+
{"jsonrpc":"2.0","id":6,"result":true}
|
|
7
|
+
{"jsonrpc":"2.0","id":7,"result":{"traceDir":null,"message":"start zmr serve with --trace-dir to enable live RPC trace export"}}
|
|
8
|
+
{"jsonrpc":"2.0","id":8,"result":true}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Protocol Versioning
|
|
2
|
+
|
|
3
|
+
ZMR exposes two public automation surfaces:
|
|
4
|
+
|
|
5
|
+
- scenario JSON files consumed by `zmr run`
|
|
6
|
+
- JSON-RPC methods exposed by `zmr serve`
|
|
7
|
+
|
|
8
|
+
The current protocol version is a date string. Before `v1.0.0`, breaking changes
|
|
9
|
+
are allowed only when the protocol version and changelog are updated together.
|
|
10
|
+
`runner.capabilities` exposes this policy in machine-readable form:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"protocol": {
|
|
15
|
+
"version": "2026-04-28",
|
|
16
|
+
"minimumCompatibleVersion": "2026-04-28",
|
|
17
|
+
"stability": "dev-preview",
|
|
18
|
+
"breakingChangePolicy": "version-and-changelog"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Clients should continue reading the top-level `protocolVersion` field for older
|
|
24
|
+
servers, but new clients should prefer `protocol.version` and reject servers
|
|
25
|
+
older than `protocol.minimumCompatibleVersion` unless they intentionally support
|
|
26
|
+
that older shape.
|
|
27
|
+
|
|
28
|
+
## Compatibility Rules
|
|
29
|
+
|
|
30
|
+
- Adding optional fields is non-breaking.
|
|
31
|
+
- Adding new methods or actions is non-breaking when existing behavior remains.
|
|
32
|
+
- Removing fields, renaming fields, changing required params, or changing error
|
|
33
|
+
codes is breaking.
|
|
34
|
+
- Native shim protocols are internal and not covered by the public compatibility
|
|
35
|
+
promise until explicitly documented as stable.
|
|
36
|
+
|
|
37
|
+
## Test Requirements
|
|
38
|
+
|
|
39
|
+
Protocol changes must update:
|
|
40
|
+
|
|
41
|
+
- `docs/protocol.md`
|
|
42
|
+
- `schemas/`
|
|
43
|
+
- JSON-RPC or scenario parser tests
|
|
44
|
+
- `CHANGELOG.md`
|
|
45
|
+
|
|
46
|
+
## Governance
|
|
47
|
+
|
|
48
|
+
The protocol is reviewed as a product contract, not an implementation detail.
|
|
49
|
+
Any change to scenario JSON, JSON-RPC methods, stable error codes, trace
|
|
50
|
+
schemas, or `runner.capabilities` must call out compatibility impact in the
|
|
51
|
+
pull request or release notes.
|
|
52
|
+
|
|
53
|
+
Governance rules:
|
|
54
|
+
|
|
55
|
+
- Non-breaking additions may ship in the current protocol version when existing
|
|
56
|
+
clients keep working unchanged.
|
|
57
|
+
- Breaking changes require a protocol version bump, changelog entry, fixture
|
|
58
|
+
update, and migration note in `docs/protocol.md`.
|
|
59
|
+
- Removing a documented field or method requires a deprecation window unless
|
|
60
|
+
the project is still before its first stable release and the changelog names
|
|
61
|
+
the break explicitly.
|
|
62
|
+
- Client authors should be able to discover support from `runner.capabilities`
|
|
63
|
+
without probing by failure.
|
|
64
|
+
- The protocol fixture files under `docs/protocol-fixtures/` are treated as
|
|
65
|
+
golden examples for agent integrations and must stay deterministic.
|