Skip to content

Commit d137eea

Browse files
authored
Merge pull request #164 from Lykhoyda/feat/rn-device-ios-first-mvp
feat(rn-device): iOS-first MVP — replace external agent-device iOS surface
2 parents 38e3569 + 7f76411 commit d137eea

72 files changed

Lines changed: 6654 additions & 1523 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.

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ reports
1010
# Vendored native drivers (installed by agent-device)
1111
drivers/
1212

13-
# Workspace symlinks (local dev only)
14-
scripts/fast-runner/build/
13+
# Xcode build artifacts for the imported iOS runner
14+
scripts/rn-fast-runner/build/
15+
scripts/rn-fast-runner/**/xcuserdata/
16+
scripts/rn-fast-runner/**/DerivedData/
1517

1618
# Local worktrees for isolated feature work
1719
.worktrees/

scripts/cdp-bridge/dist/agent-device-wrapper.js

Lines changed: 147 additions & 187 deletions
Large diffs are not rendered by default.

scripts/cdp-bridge/dist/fast-runner-ref-map.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
let refMap = new Map();
2+
let metadataMap = new Map();
23
let screenRect = null;
34
let lastUpdated = 0;
45
export function updateRefMap(nodes) {
@@ -35,9 +36,107 @@ export function getRefMapAge() {
3536
}
3637
export function clearRefMap() {
3738
refMap.clear();
39+
metadataMap.clear();
3840
screenRect = null;
3941
lastUpdated = 0;
4042
}
4143
export function hasRefMap() {
4244
return refMap.size > 0;
4345
}
46+
export function flattenXCUITree(tree) {
47+
const nodes = [];
48+
const localRefMap = new Map();
49+
let counter = 0;
50+
const walk = (node) => {
51+
if (!node || typeof node !== 'object')
52+
return;
53+
if (node.frame) {
54+
const id = `e${counter}`;
55+
counter++;
56+
const rect = {
57+
x: node.frame.x,
58+
y: node.frame.y,
59+
width: node.frame.width,
60+
height: node.frame.height,
61+
};
62+
const flat = {
63+
ref: `@${id}`,
64+
type: node.type ?? '',
65+
rect,
66+
};
67+
if (node.label !== undefined)
68+
flat.label = node.label;
69+
if (node.identifier !== undefined)
70+
flat.identifier = node.identifier;
71+
if (node.enabled !== undefined)
72+
flat.enabled = node.enabled;
73+
if (node.hittable !== undefined)
74+
flat.hittable = node.hittable;
75+
nodes.push(flat);
76+
localRefMap.set(id, rect);
77+
}
78+
if (Array.isArray(node.children)) {
79+
for (const child of node.children)
80+
walk(child);
81+
}
82+
};
83+
walk(tree);
84+
return { nodes, refMap: localRefMap };
85+
}
86+
export function updateRefMapFromFlat(nodes) {
87+
refMap.clear();
88+
metadataMap.clear();
89+
screenRect = null;
90+
for (const node of nodes) {
91+
if (!node.ref || !node.rect)
92+
continue;
93+
const key = node.ref.startsWith('@') ? node.ref.slice(1) : node.ref;
94+
refMap.set(key, node.rect);
95+
const meta = { type: node.type };
96+
if (node.label !== undefined)
97+
meta.label = node.label;
98+
if (node.identifier !== undefined)
99+
meta.identifier = node.identifier;
100+
metadataMap.set(key, meta);
101+
if (!screenRect && node.rect.x === 0 && node.rect.y === 0 && node.rect.width > 300) {
102+
screenRect = node.rect;
103+
}
104+
}
105+
lastUpdated = Date.now();
106+
}
107+
export function getCachedMetadata(ref) {
108+
const key = ref.startsWith('@') ? ref.slice(1) : ref;
109+
return metadataMap.get(key) ?? null;
110+
}
111+
function metadataMatches(a, b) {
112+
return a.type === b.type && a.label === b.label && a.identifier === b.identifier;
113+
}
114+
function flatNodeMetadata(node) {
115+
const meta = { type: node.type };
116+
if (node.label !== undefined)
117+
meta.label = node.label;
118+
if (node.identifier !== undefined)
119+
meta.identifier = node.identifier;
120+
return meta;
121+
}
122+
export function isRefStale(ref, newNodes) {
123+
const cached = getCachedMetadata(ref);
124+
if (!cached)
125+
return true;
126+
const target = ref.startsWith('@') ? ref : `@${ref}`;
127+
const fresh = newNodes.find((n) => n.ref === target);
128+
if (!fresh)
129+
return true;
130+
return !metadataMatches(cached, flatNodeMetadata(fresh));
131+
}
132+
export function findNewRefByMetadata(oldRef, newNodes) {
133+
const cached = getCachedMetadata(oldRef);
134+
if (!cached)
135+
return null;
136+
for (const node of newNodes) {
137+
if (metadataMatches(cached, flatNodeMetadata(node))) {
138+
return node.ref;
139+
}
140+
}
141+
return null;
142+
}

0 commit comments

Comments
 (0)