mobridge-mcp 0.0.1

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.
Files changed (47) hide show
  1. package/README.md +155 -0
  2. package/dist/adb-baseline/act.mjs +1 -0
  3. package/dist/adb-baseline/capture-lib.mjs +2 -0
  4. package/dist/main.obf.cjs +2 -0
  5. package/dist/protocol/fixtures/01-login-views/expected.json +32 -0
  6. package/dist/protocol/fixtures/01-login-views/snapshot.json +20 -0
  7. package/dist/protocol/fixtures/02-alert-dialog/expected.json +22 -0
  8. package/dist/protocol/fixtures/02-alert-dialog/snapshot.json +20 -0
  9. package/dist/protocol/fixtures/03-recyclerview-list/expected.json +22 -0
  10. package/dist/protocol/fixtures/03-recyclerview-list/snapshot.json +19 -0
  11. package/dist/protocol/fixtures/04-ambiguous-ctas/expected.json +17 -0
  12. package/dist/protocol/fixtures/04-ambiguous-ctas/snapshot.json +21 -0
  13. package/dist/protocol/fixtures/05-compose-settings/expected.json +17 -0
  14. package/dist/protocol/fixtures/05-compose-settings/snapshot.json +19 -0
  15. package/dist/protocol/fixtures/06-canvas-game/expected.json +12 -0
  16. package/dist/protocol/fixtures/06-canvas-game/snapshot.json +16 -0
  17. package/dist/protocol/fixtures/07-search-results/expected.json +22 -0
  18. package/dist/protocol/fixtures/07-search-results/snapshot.json +19 -0
  19. package/dist/protocol/fixtures/README.md +34 -0
  20. package/dist/protocol/platform-capabilities.json +95 -0
  21. package/dist/protocol/schemas/action.schema.json +170 -0
  22. package/dist/protocol/schemas/common.schema.json +59 -0
  23. package/dist/protocol/schemas/diff.schema.json +74 -0
  24. package/dist/protocol/schemas/error.schema.json +34 -0
  25. package/dist/protocol/schemas/node-ref.schema.json +100 -0
  26. package/dist/protocol/schemas/query.schema.json +53 -0
  27. package/dist/protocol/schemas/screen-snapshot.schema.json +50 -0
  28. package/dist/protocol/schemas/semantic-node.schema.json +95 -0
  29. package/dist/protocol/schemas/tools.schema.json +215 -0
  30. package/dist/protocol/schemas/wait.schema.json +57 -0
  31. package/dist/protocol/synonyms.json +74 -0
  32. package/dist/protocol/validate/package-lock.json +71 -0
  33. package/dist/protocol/validate/package.json +13 -0
  34. package/dist/protocol/validate/query-engine.mjs +1 -0
  35. package/dist/protocol/validate/run-fixtures.mjs +6 -0
  36. package/dist/protocol/validate/schema-lint.mjs +2 -0
  37. package/dist/protocol/validate/validate-file.mjs +1 -0
  38. package/integrity.json +4 -0
  39. package/loader.cjs +85 -0
  40. package/package.json +40 -0
  41. package/resources/android/app-developer-debug.apk +0 -0
  42. package/resources/ios/MobileSemantic/Fixture/MobileSemanticFixtureApp.swift +50 -0
  43. package/resources/ios/MobileSemantic/MobileSemantic.xcodeproj/project.pbxproj +463 -0
  44. package/resources/ios/MobileSemantic/MobileSemantic.xcodeproj/xcshareddata/xcschemes/MobileSemanticUITests.xcscheme +97 -0
  45. package/resources/ios/MobileSemantic/UITests/BridgeServer.swift +216 -0
  46. package/resources/ios/MobileSemantic/UITests/XcuiSnapshot.swift +73 -0
  47. package/resources/ios/MobileSemantic/gen_project.rb +67 -0
@@ -0,0 +1,32 @@
1
+ [
2
+ {
3
+ "name": "email by resourceId",
4
+ "query": { "resourceId": "com.example.app:id/email" },
5
+ "expect": { "matchCount": 1, "nodeIds": ["n2"] }
6
+ },
7
+ {
8
+ "name": "login button by role+text normalized",
9
+ "query": { "role": "BUTTON", "text": { "value": "đăng nhập", "match": "NORMALIZED_EXACT" } },
10
+ "expect": { "matchCount": 1, "nodeIds": ["n4"] }
11
+ },
12
+ {
13
+ "name": "role INPUT returns both fields",
14
+ "query": { "role": "INPUT" },
15
+ "expect": { "matchCount": 2, "nodeIds": ["n2", "n3"] }
16
+ },
17
+ {
18
+ "name": "exact case-sensitive misses normalized-only match",
19
+ "query": { "role": "BUTTON", "text": { "value": "đăng nhập", "match": "EXACT" } },
20
+ "expect": { "matchCount": 0 }
21
+ },
22
+ {
23
+ "name": "contains matches partial",
24
+ "query": { "role": "LINK", "text": { "value": "Quên", "match": "CONTAINS" } },
25
+ "expect": { "matchCount": 1, "nodeIds": ["n5"] }
26
+ },
27
+ {
28
+ "name": "text Đăng nhập matches both title(TEXT) and button unless role given",
29
+ "query": { "text": { "value": "Đăng nhập", "match": "NORMALIZED_EXACT" } },
30
+ "expect": { "matchCount": 2, "nodeIds": ["n1", "n4"] }
31
+ }
32
+ ]
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "deviceId": "pixel5",
4
+ "snapshotId": "s_0101",
5
+ "timestamp": 1784772000000,
6
+ "packageName": "com.example.app",
7
+ "windowId": 42,
8
+ "orientation": "portrait",
9
+ "screenStateId": "login:a91f",
10
+ "compact": true,
11
+ "nodes": [
12
+ { "nodeId": "n0", "parentId": null, "role": "SCREEN", "label": null, "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
13
+ { "nodeId": "n1", "parentId": "n0", "role": "TEXT", "label": null, "text": "Đăng nhập", "value": null, "hint": null, "resourceId": "com.example.app:id/title", "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
14
+ { "nodeId": "n2", "parentId": "n0", "role": "INPUT", "label": "Email", "text": null, "value": "", "hint": "Email", "resourceId": "com.example.app:id/email", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["FOCUS", "SET_TEXT", "CLEAR_TEXT"], "source": "ACCESSIBILITY", "confidence": 1.0 },
15
+ { "nodeId": "n3", "parentId": "n0", "role": "INPUT", "label": "Mật khẩu", "text": null, "value": "", "hint": "Mật khẩu", "resourceId": "com.example.app:id/password", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": true }, "actions": ["FOCUS", "SET_TEXT", "CLEAR_TEXT"], "source": "ACCESSIBILITY", "confidence": 1.0 },
16
+ { "nodeId": "n4", "parentId": "n0", "role": "BUTTON", "label": "Đăng nhập", "text": "Đăng nhập", "value": null, "hint": null, "resourceId": "com.example.app:id/login", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK", "FOCUS"], "source": "ACCESSIBILITY", "confidence": 1.0 },
17
+ { "nodeId": "n5", "parentId": "n0", "role": "LINK", "label": "Quên mật khẩu", "text": "Quên mật khẩu", "value": null, "hint": null, "resourceId": "com.example.app:id/forgot", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 1.0 }
18
+ ],
19
+ "treeHash": "e4c0a1"
20
+ }
@@ -0,0 +1,22 @@
1
+ [
2
+ {
3
+ "name": "OK is ambiguous without scope",
4
+ "query": { "role": "BUTTON", "text": { "value": "OK", "match": "EXACT" } },
5
+ "expect": { "matchCount": 2, "nodeIds": ["n1", "n5"], "ambiguous": true }
6
+ },
7
+ {
8
+ "name": "OK scoped to dialog is unique",
9
+ "query": { "role": "BUTTON", "text": { "value": "OK", "match": "EXACT" }, "within": { "role": "DIALOG" } },
10
+ "expect": { "matchCount": 1, "nodeIds": ["n5"] }
11
+ },
12
+ {
13
+ "name": "cancel in dialog",
14
+ "query": { "role": "BUTTON", "text": { "value": "Hủy", "match": "NORMALIZED_EXACT" }, "within": { "role": "DIALOG" } },
15
+ "expect": { "matchCount": 1, "nodeIds": ["n4"] }
16
+ },
17
+ {
18
+ "name": "dialog node itself",
19
+ "query": { "role": "DIALOG" },
20
+ "expect": { "matchCount": 1, "nodeIds": ["n2"] }
21
+ }
22
+ ]
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "deviceId": "pixel5",
4
+ "snapshotId": "s_0201",
5
+ "timestamp": 1784772100000,
6
+ "packageName": "com.example.app",
7
+ "windowId": 43,
8
+ "orientation": "portrait",
9
+ "screenStateId": "home+dialog:77b2",
10
+ "compact": true,
11
+ "nodes": [
12
+ { "nodeId": "n0", "parentId": null, "role": "SCREEN", "label": null, "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
13
+ { "nodeId": "n1", "parentId": "n0", "role": "BUTTON", "label": "OK", "text": "OK", "value": null, "hint": null, "resourceId": "com.example.app:id/bg_ok", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 1.0 },
14
+ { "nodeId": "n2", "parentId": "n0", "role": "DIALOG", "label": "Xác nhận", "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["DISMISS"], "source": "ACCESSIBILITY", "confidence": 1.0 },
15
+ { "nodeId": "n3", "parentId": "n2", "role": "TEXT", "label": null, "text": "Xóa mục này?", "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
16
+ { "nodeId": "n4", "parentId": "n2", "role": "BUTTON", "label": "Hủy", "text": "Hủy", "value": null, "hint": null, "resourceId": "android:id/button2", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 1.0 },
17
+ { "nodeId": "n5", "parentId": "n2", "role": "BUTTON", "label": "OK", "text": "OK", "value": null, "hint": null, "resourceId": "android:id/button1", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 1.0 }
18
+ ],
19
+ "treeHash": "77b2c9"
20
+ }
@@ -0,0 +1,22 @@
1
+ [
2
+ {
3
+ "name": "visible item resolves by itemKey",
4
+ "query": { "role": "LIST_ITEM", "text": { "value": "Item 4", "match": "EXACT" } },
5
+ "expect": { "matchCount": 1, "nodeIds": ["n3"] }
6
+ },
7
+ {
8
+ "name": "off-screen item not present (needs scroll)",
9
+ "query": { "role": "LIST_ITEM", "text": { "value": "Item 40", "match": "EXACT" } },
10
+ "expect": { "matchCount": 0, "error": "NODE_NOT_FOUND" }
11
+ },
12
+ {
13
+ "name": "nth visible list item",
14
+ "query": { "role": "LIST_ITEM", "nth": 0 },
15
+ "expect": { "matchCount": 1, "nodeIds": ["n2"] }
16
+ },
17
+ {
18
+ "name": "shared resourceId row is ambiguous alone",
19
+ "query": { "resourceId": "com.example.app:id/row" },
20
+ "expect": { "matchCount": 3, "nodeIds": ["n2", "n3", "n4"], "ambiguous": true }
21
+ }
22
+ ]
@@ -0,0 +1,19 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "deviceId": "pixel5",
4
+ "snapshotId": "s_0301",
5
+ "timestamp": 1784772200000,
6
+ "packageName": "com.example.app",
7
+ "windowId": 44,
8
+ "orientation": "portrait",
9
+ "screenStateId": "list:1c4d",
10
+ "compact": true,
11
+ "nodes": [
12
+ { "nodeId": "n0", "parentId": null, "role": "SCREEN", "label": null, "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
13
+ { "nodeId": "n1", "parentId": "n0", "role": "LIST", "label": null, "text": null, "value": null, "hint": null, "resourceId": "com.example.app:id/recycler", "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["SCROLL_FORWARD", "SCROLL_BACKWARD"], "source": "ACCESSIBILITY", "confidence": 1.0 },
14
+ { "nodeId": "n2", "parentId": "n1", "role": "LIST_ITEM", "label": "Item 3", "text": "Item 3", "value": null, "hint": null, "resourceId": "com.example.app:id/row", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "collection": { "index": 3, "itemKey": "Item 3", "rowCount": 200, "scrollContainerId": "n1", "ancestorFingerprint": "1c4d01" }, "source": "ACCESSIBILITY", "confidence": 1.0 },
15
+ { "nodeId": "n3", "parentId": "n1", "role": "LIST_ITEM", "label": "Item 4", "text": "Item 4", "value": null, "hint": null, "resourceId": "com.example.app:id/row", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "collection": { "index": 4, "itemKey": "Item 4", "rowCount": 200, "scrollContainerId": "n1", "ancestorFingerprint": "1c4d01" }, "source": "ACCESSIBILITY", "confidence": 1.0 },
16
+ { "nodeId": "n4", "parentId": "n1", "role": "LIST_ITEM", "label": "Item 5", "text": "Item 5", "value": null, "hint": null, "resourceId": "com.example.app:id/row", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "collection": { "index": 5, "itemKey": "Item 5", "rowCount": 200, "scrollContainerId": "n1", "ancestorFingerprint": "1c4d01" }, "source": "ACCESSIBILITY", "confidence": 1.0 }
17
+ ],
18
+ "treeHash": "1c4d5e"
19
+ }
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "name": "three identical CTAs are ambiguous",
4
+ "query": { "role": "BUTTON", "text": { "value": "Tiếp tục", "match": "NORMALIZED_EXACT" } },
5
+ "expect": { "matchCount": 3, "nodeIds": ["n2", "n4", "n6"], "ambiguous": true }
6
+ },
7
+ {
8
+ "name": "resolve by dialog ancestor",
9
+ "query": { "role": "BUTTON", "text": { "value": "Tiếp tục", "match": "NORMALIZED_EXACT" }, "within": { "role": "DIALOG" } },
10
+ "expect": { "matchCount": 1, "nodeIds": ["n6"] }
11
+ },
12
+ {
13
+ "name": "resolve by card_a ancestor resourceId",
14
+ "query": { "role": "BUTTON", "text": { "value": "Tiếp tục", "match": "NORMALIZED_EXACT" }, "within": { "resourceId": "com.example.app:id/card_a" } },
15
+ "expect": { "matchCount": 1, "nodeIds": ["n2"] }
16
+ }
17
+ ]
@@ -0,0 +1,21 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "deviceId": "pixel5",
4
+ "snapshotId": "s_0401",
5
+ "timestamp": 1784772300000,
6
+ "packageName": "com.example.app",
7
+ "windowId": 45,
8
+ "orientation": "portrait",
9
+ "screenStateId": "onboard:3fe1",
10
+ "compact": true,
11
+ "nodes": [
12
+ { "nodeId": "n0", "parentId": null, "role": "SCREEN", "label": null, "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
13
+ { "nodeId": "n1", "parentId": "n0", "role": "LIST_ITEM", "label": "card A", "text": null, "value": null, "hint": null, "resourceId": "com.example.app:id/card_a", "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
14
+ { "nodeId": "n2", "parentId": "n1", "role": "BUTTON", "label": "Tiếp tục", "text": "Tiếp tục", "value": null, "hint": null, "resourceId": "com.example.app:id/cta", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 1.0 },
15
+ { "nodeId": "n3", "parentId": "n0", "role": "LIST_ITEM", "label": "card B", "text": null, "value": null, "hint": null, "resourceId": "com.example.app:id/card_b", "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
16
+ { "nodeId": "n4", "parentId": "n3", "role": "BUTTON", "label": "Tiếp tục", "text": "Tiếp tục", "value": null, "hint": null, "resourceId": "com.example.app:id/cta", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 1.0 },
17
+ { "nodeId": "n5", "parentId": "n0", "role": "DIALOG", "label": "Xác nhận", "text": null, "value": null, "hint": null, "resourceId": "com.example.app:id/confirm_sheet", "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["DISMISS"], "source": "ACCESSIBILITY", "confidence": 1.0 },
18
+ { "nodeId": "n6", "parentId": "n5", "role": "BUTTON", "label": "Tiếp tục", "text": "Tiếp tục", "value": null, "hint": null, "resourceId": "com.example.app:id/cta", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 1.0 }
19
+ ],
20
+ "treeHash": "3fe1aa"
21
+ }
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "name": "switch by label (no resourceId in Compose)",
4
+ "query": { "role": "SWITCH", "label": { "value": "Notifications", "match": "EXACT" } },
5
+ "expect": { "matchCount": 1, "nodeIds": ["n1"] }
6
+ },
7
+ {
8
+ "name": "unchecked switches only",
9
+ "query": { "role": "SWITCH", "state": { "checked": false } },
10
+ "expect": { "matchCount": 1, "nodeIds": ["n1"] }
11
+ },
12
+ {
13
+ "name": "input current value",
14
+ "query": { "role": "INPUT", "label": { "value": "Name", "match": "EXACT" } },
15
+ "expect": { "matchCount": 1, "nodeIds": ["n3"] }
16
+ }
17
+ ]
@@ -0,0 +1,19 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "deviceId": "pixel5",
4
+ "snapshotId": "s_0501",
5
+ "timestamp": 1784772400000,
6
+ "packageName": "com.example.compose",
7
+ "windowId": 46,
8
+ "orientation": "portrait",
9
+ "screenStateId": "settings:9ab0",
10
+ "compact": true,
11
+ "nodes": [
12
+ { "nodeId": "n0", "parentId": null, "role": "SCREEN", "label": null, "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
13
+ { "nodeId": "n1", "parentId": "n0", "role": "SWITCH", "label": "Notifications", "text": null, "value": null, "hint": null, "resourceId": null, "className": "androidx.compose.ui.platform.ComposeView", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": false, "password": false }, "actions": ["SELECT", "CLICK"], "source": "ACCESSIBILITY", "confidence": 0.95 },
14
+ { "nodeId": "n2", "parentId": "n0", "role": "SWITCH", "label": "Dark mode", "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": true, "password": false }, "actions": ["SELECT", "CLICK"], "source": "ACCESSIBILITY", "confidence": 0.95 },
15
+ { "nodeId": "n3", "parentId": "n0", "role": "INPUT", "label": "Name", "text": null, "value": "Anh", "hint": "Your name", "resourceId": null, "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["FOCUS", "SET_TEXT", "CLEAR_TEXT"], "source": "ACCESSIBILITY", "confidence": 0.9 },
16
+ { "nodeId": "n4", "parentId": "n0", "role": "BUTTON", "label": "Save", "text": "Save", "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "source": "ACCESSIBILITY", "confidence": 0.92 }
17
+ ],
18
+ "treeHash": "9ab0f3"
19
+ }
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "name": "no semantic Play button -> vision required",
4
+ "query": { "role": "BUTTON", "text": { "value": "Play", "match": "CONTAINS" } },
5
+ "expect": { "matchCount": 0, "error": "VISION_REQUIRED" }
6
+ },
7
+ {
8
+ "name": "screen is a bare canvas",
9
+ "query": { "role": "CANVAS" },
10
+ "expect": { "matchCount": 1, "nodeIds": ["n1"] }
11
+ }
12
+ ]
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "deviceId": "pixel5",
4
+ "snapshotId": "s_0601",
5
+ "timestamp": 1784772500000,
6
+ "packageName": "com.example.unitygame",
7
+ "windowId": 47,
8
+ "orientation": "landscape",
9
+ "screenStateId": "game:canvas",
10
+ "compact": true,
11
+ "nodes": [
12
+ { "nodeId": "n0", "parentId": null, "role": "SCREEN", "label": null, "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
13
+ { "nodeId": "n1", "parentId": "n0", "role": "CANVAS", "label": null, "text": null, "value": null, "hint": null, "resourceId": "com.example.unitygame:id/unitySurface", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "bounds": [0, 0, 2340, 1080], "source": "ACCESSIBILITY", "confidence": 1.0 }
14
+ ],
15
+ "treeHash": "ca0000"
16
+ }
@@ -0,0 +1,22 @@
1
+ [
2
+ {
3
+ "name": "contains Pizza returns two",
4
+ "query": { "role": "LIST_ITEM", "text": { "value": "Pizza", "match": "CONTAINS" } },
5
+ "expect": { "matchCount": 2, "nodeIds": ["n2", "n3"] }
6
+ },
7
+ {
8
+ "name": "firstVisible pizza narrows to one",
9
+ "query": { "role": "LIST_ITEM", "text": { "value": "Pizza", "match": "CONTAINS" }, "firstVisible": true },
10
+ "expect": { "matchCount": 1, "nodeIds": ["n2"] }
11
+ },
12
+ {
13
+ "name": "nth=1 among all results",
14
+ "query": { "role": "LIST_ITEM", "resourceId": "com.example.app:id/result", "nth": 1 },
15
+ "expect": { "matchCount": 1, "nodeIds": ["n3"] }
16
+ },
17
+ {
18
+ "name": "regex anchored match",
19
+ "query": { "role": "LIST_ITEM", "text": { "value": "^Pho", "match": "REGEX" } },
20
+ "expect": { "matchCount": 1, "nodeIds": ["n4"] }
21
+ }
22
+ ]
@@ -0,0 +1,19 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "deviceId": "pixel5",
4
+ "snapshotId": "s_0701",
5
+ "timestamp": 1784772600000,
6
+ "packageName": "com.example.app",
7
+ "windowId": 48,
8
+ "orientation": "portrait",
9
+ "screenStateId": "search:6d2e",
10
+ "compact": true,
11
+ "nodes": [
12
+ { "nodeId": "n0", "parentId": null, "role": "SCREEN", "label": null, "text": null, "value": null, "hint": null, "resourceId": null, "state": { "enabled": true, "clickable": false, "focused": false, "selected": false, "checked": null, "password": false }, "actions": [], "source": "ACCESSIBILITY", "confidence": 1.0 },
13
+ { "nodeId": "n1", "parentId": "n0", "role": "INPUT", "label": "Search", "text": null, "value": "pi", "hint": "Search", "resourceId": "com.example.app:id/search", "state": { "enabled": true, "clickable": true, "focused": true, "selected": false, "checked": null, "password": false }, "actions": ["FOCUS", "SET_TEXT", "CLEAR_TEXT"], "source": "ACCESSIBILITY", "confidence": 1.0 },
14
+ { "nodeId": "n2", "parentId": "n0", "role": "LIST_ITEM", "label": null, "text": "Pizza Hut", "value": null, "hint": null, "resourceId": "com.example.app:id/result", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "collection": { "index": 0, "itemKey": "Pizza Hut", "rowCount": 3, "scrollContainerId": "n0", "ancestorFingerprint": "6d2e01" }, "source": "ACCESSIBILITY", "confidence": 1.0 },
15
+ { "nodeId": "n3", "parentId": "n0", "role": "LIST_ITEM", "label": null, "text": "Pizza 4P's", "value": null, "hint": null, "resourceId": "com.example.app:id/result", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "collection": { "index": 1, "itemKey": "Pizza 4P's", "rowCount": 3, "scrollContainerId": "n0", "ancestorFingerprint": "6d2e01" }, "source": "ACCESSIBILITY", "confidence": 1.0 },
16
+ { "nodeId": "n4", "parentId": "n0", "role": "LIST_ITEM", "label": null, "text": "Pho 24", "value": null, "hint": null, "resourceId": "com.example.app:id/result", "state": { "enabled": true, "clickable": true, "focused": false, "selected": false, "checked": null, "password": false }, "actions": ["CLICK"], "collection": { "index": 2, "itemKey": "Pho 24", "rowCount": 3, "scrollContainerId": "n0", "ancestorFingerprint": "6d2e01" }, "source": "ACCESSIBILITY", "confidence": 1.0 }
17
+ ],
18
+ "treeHash": "6d2e77"
19
+ }
@@ -0,0 +1,34 @@
1
+ # Fixtures
2
+
3
+ Each fixture is a folder with:
4
+ - `snapshot.json` — a `ScreenSnapshot` (validates against `msm:screen-snapshot.schema.json`).
5
+ - `expected.json` — query cases: `{ query, expect }` where `expect` is `{ matchCount, nodeIds?, error? }`.
6
+
7
+ These drive the P0 query/diff validator **with no device**. Concrete fixtures below are authored now; the remaining rows are captured from real devices in P1 (they need live Compose/WebView/RN/Flutter/Unity trees).
8
+
9
+ ## The 20 target screens
10
+
11
+ | # | Screen | UI tech | Authored | Purpose |
12
+ |---|--------|---------|----------|---------|
13
+ | 01 | Login | Views | ✅ | resource-id + role/label; NORMALIZED_EXACT |
14
+ | 02 | Alert dialog | Views | ✅ | `within` DIALOG scoping; DISMISS |
15
+ | 03 | Long list | RecyclerView | ✅ | collection identity; off-screen NODE_NOT_FOUND |
16
+ | 04 | Ambiguous CTAs | Views | ✅ | AMBIGUOUS_MATCH + ancestor disambiguation |
17
+ | 05 | Settings form | Compose | ✅ | Compose semantics; SWITCH state |
18
+ | 06 | Game menu | Canvas/Unity | ✅ | near-empty tree → VISION_REQUIRED |
19
+ | 07 | Search + results | Views | ✅ | CONTAINS + firstVisible/nth |
20
+ | 08 | Web article | WebView | ⬜ P1 | LINK role from WebView |
21
+ | 09 | Permission dialog | System | ⬜ P1 | system package window |
22
+ | 10 | Bottom sheet | Compose | ⬜ P1 | modal sheet as DIALOG |
23
+ | 11 | Product list | React Native | ⬜ P1 | RN accessibility mapping |
24
+ | 12 | Feed | Flutter | ⬜ P1 | Flutter semantics tree |
25
+ | 13 | Multi-window | Views | ⬜ P1 | two windows, windowId scoping |
26
+ | 14 | Notification shade | System | ⬜ P1 | shade open state |
27
+ | 15 | Landscape login | Views | ⬜ P1 | orientation + DPI locator stability |
28
+ | 16 | Large font scale | Views | ⬜ P1 | font scale, bounds shift |
29
+ | 17 | Dark mode home | Compose | ⬜ P1 | theme independence |
30
+ | 18 | Loading/skeleton | Views | ⬜ P1 | transient nodes, diff coalescing |
31
+ | 19 | Network error | Views | ⬜ P1 | error state + retry |
32
+ | 20 | Checkout (guarded) | Views | ⬜ P1 | financial-class action gating |
33
+
34
+ Legend: ✅ concrete JSON here · ⬜ device-capture in P1.
@@ -0,0 +1,95 @@
1
+ {
2
+ "$comment": "Operation-level platform capability manifest. SINGLE SOURCE OF TRUTH for iOS tool registration, per-call operation validation, the device.connect envelope (supportedTools/unsupportedCapabilities), docs and tests. Android is intentionally NOT enumerated: on Android the platform filter is a no-op and the existing profile system is authoritative, so nothing here can make the Android surface drift. A tool with no iOS entry (in `common` or the active mode) is level NONE => NOT registered on iOS. Entries are version-qualified (minIosVersion/minXcodeVersion) because support varies by toolchain; connect resolves the effective set against the detected environment.",
3
+ "version": 1,
4
+ "platforms": ["ANDROID", "IOS"],
5
+ "iosModes": ["physical", "simulator"],
6
+
7
+ "unsupportedCapabilities": {
8
+ "physical": ["APP_CLEAR_DATA", "APP_PERMISSION_GRANT", "BATTERYSTATS"],
9
+ "simulator": ["BATTERYSTATS"]
10
+ },
11
+
12
+ "ios": {
13
+ "common": {
14
+ "mobile.device.connect": { "level": "FULL" },
15
+ "mobile.app.open": { "level": "FULL", "allowedOperations": ["APP_OPEN", "APP_DEEP_LINK", "APP_BRING_TO_FRONT", "APP_CLOSE_UI"] },
16
+ "mobile.screen.get": { "level": "FULL" },
17
+ "mobile.screen.find": { "level": "FULL" },
18
+ "mobile.screen.act": { "level": "FULL" },
19
+ "mobile.screen.wait": { "level": "FULL" },
20
+ "mobile.screen.diff": { "level": "FULL" },
21
+ "mobile.system.action": { "level": "PARTIAL", "allowedOperations": ["HOME"], "reasonCode": "NO_GLOBAL_BACK_OR_RECENTS", "note": "iOS has no global BACK/RECENTS/NOTIFICATION_SHADE; BACK is a semantic UI action (find nav button + act)." },
22
+ "mobile.capability.invoke": { "level": "PARTIAL", "allowedOperations": ["APP", "CLIPBOARD"], "reasonCode": "NO_NOTIFICATION_LISTENER", "note": "APP ok; CLIPBOARD limited; no general notification listener." },
23
+
24
+ "mobile.screen.delta": { "level": "FULL" },
25
+ "mobile.batch": { "level": "FULL" },
26
+ "mobile.gesture.perform": { "level": "FULL" },
27
+ "mobile.screen.scrollTo": { "level": "FULL" },
28
+ "mobile.screen.capture": { "level": "FULL" },
29
+ "mobile.input.text": { "level": "FULL" },
30
+ "mobile.notification.act": { "level": "PARTIAL", "reasonCode": "NO_STABLE_LISTENER", "note": "UI automation of the notification surface only, not a stable capability." },
31
+
32
+ "mobile.perf.sample": { "level": "FULL" },
33
+ "mobile.diag.crash": { "level": "PARTIAL", "reasonCode": "PROCESS_SCOPED" },
34
+ "mobile.diag.startup": { "level": "FULL" },
35
+
36
+ "runtime.setup.status": { "level": "FULL" },
37
+ "runtime.setup.open": { "level": "PARTIAL", "reasonCode": "NO_DEEP_LINK_FOR_EVERY_PAGE" },
38
+ "runtime.setup.verify": { "level": "PARTIAL", "reasonCode": "PHYSICAL_PERMISSION_PROBE_LIMITED" },
39
+
40
+ "mobile.app.control.authorize": { "level": "FULL" },
41
+ "mobile.app.control.deauthorize": { "level": "FULL" },
42
+ "mobile.app.control.status": { "level": "FULL" },
43
+
44
+ "mobile.workflow.run": { "level": "FULL" },
45
+
46
+ "ios.app.terminate": { "level": "FULL", "note": "Terminate the test-session app only; NOT an OS force-stop." },
47
+ "ios.diag.logs": { "level": "PARTIAL", "reasonCode": "PROCESS_SCOPED", "replacesAndroidTool": "mobile.diag.logcat" },
48
+ "ios.diag.energyProfile": { "level": "PARTIAL", "reasonCode": "OWN_CONTRACT", "replacesAndroidTool": "mobile.diag.batterystats" }
49
+ },
50
+
51
+ "physical": {
52
+ "mobile.device.state": { "level": "PARTIAL", "reasonCode": "ORIENTATION_AND_APPSTATE_ONLY" },
53
+ "mobile.app.list": { "level": "PARTIAL", "reasonCode": "DEVICECTL_OR_MDM" },
54
+ "mobile.app.info": { "level": "PARTIAL", "reasonCode": "OWN_APP_OR_BUNDLE_METADATA" },
55
+ "mobile.diag.battery": { "level": "PARTIAL", "reasonCode": "ENERGY_NOT_BATTERYSTATS" },
56
+ "mobile.diag.netstats": { "level": "PARTIAL", "reasonCode": "INSTRUMENTS_PER_APP" },
57
+ "mobile.diag.storage": { "level": "PARTIAL", "reasonCode": "OWN_APP_SANDBOX_ONLY" },
58
+
59
+ "mobile.diag.logcat": { "level": "NONE", "replacementTool": "ios.diag.logs", "reasonCode": "PROCESS_SCOPED_ONLY" },
60
+ "mobile.diag.batterystats": { "level": "NONE", "replacementTool": "ios.diag.energyProfile", "reasonCode": "NO_PUBLIC_API" },
61
+
62
+ "mobile.app.forceStop": { "level": "NONE", "replacementTool": "ios.app.terminate", "reasonCode": "NO_OS_FORCE_STOP" },
63
+ "mobile.app.clearData": { "level": "NONE", "reasonCode": "NO_PUBLIC_API" },
64
+ "mobile.app.uninstall": { "level": "PARTIAL", "reasonCode": "SIGNED_DEVICECTL_OR_MDM" },
65
+ "mobile.app.install": { "level": "PARTIAL", "reasonCode": "SIGNED_IPA_OR_MDM" },
66
+ "mobile.app.permission.grant": { "level": "NONE", "reasonCode": "NO_PUBLIC_API" },
67
+ "mobile.app.permission.revoke": { "level": "PARTIAL", "replacementTool": "ios.permission.reset", "reasonCode": "XCUI_RESET_ONLY" },
68
+
69
+ "ios.permission.reset": { "level": "PARTIAL", "reasonCode": "XCUI_RESET_AUTHORIZATION" }
70
+ },
71
+
72
+ "simulator": {
73
+ "mobile.device.state": { "level": "FULL" },
74
+ "mobile.app.list": { "level": "FULL" },
75
+ "mobile.app.info": { "level": "FULL" },
76
+ "mobile.diag.battery": { "level": "PARTIAL", "reasonCode": "ENERGY_NOT_BATTERYSTATS" },
77
+ "mobile.diag.netstats": { "level": "PARTIAL", "reasonCode": "INSTRUMENTS_PER_APP" },
78
+ "mobile.diag.storage": { "level": "FULL" },
79
+
80
+ "mobile.diag.logcat": { "level": "NONE", "replacementTool": "ios.diag.logs", "reasonCode": "PROCESS_SCOPED_ONLY" },
81
+ "mobile.diag.batterystats": { "level": "NONE", "replacementTool": "ios.diag.energyProfile", "reasonCode": "NO_PUBLIC_API" },
82
+
83
+ "mobile.app.forceStop": { "level": "NONE", "replacementTool": "ios.app.terminate", "reasonCode": "NO_OS_FORCE_STOP" },
84
+ "mobile.app.clearData": { "level": "NONE", "replacementTool": "ios.simulator.resetAppData", "reasonCode": "USE_REINSTALL_NOT_ERASE" },
85
+ "mobile.app.uninstall": { "level": "FULL" },
86
+ "mobile.app.install": { "level": "FULL" },
87
+ "mobile.app.permission.grant": { "level": "PARTIAL", "reasonCode": "SIMCTL_PRIVACY" },
88
+ "mobile.app.permission.revoke": { "level": "PARTIAL", "reasonCode": "SIMCTL_PRIVACY" },
89
+
90
+ "ios.permission.reset": { "level": "FULL", "reasonCode": "SIMCTL_PRIVACY" },
91
+ "ios.simulator.resetAppData": { "level": "FULL", "note": "uninstall + reinstall the pinned artifact; NOT a device erase." },
92
+ "ios.simulator.eraseDevice": { "level": "FULL", "destructive": true, "defaultOff": true, "reasonCode": "FULL_SIMULATOR_WIPE" }
93
+ }
94
+ }
95
+ }