@tapflowio/ios-agent 0.27.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-APACHE-2.0 +202 -0
- package/NOTICE +12 -0
- package/dist/IOSAgent.d.ts +1 -0
- package/dist/IOSAgent.d.ts.map +1 -1
- package/dist/IOSAgent.js +22 -10
- package/dist/IOSAgent.js.map +1 -1
- package/dist/XCUITreeReader.d.ts +26 -6
- package/dist/XCUITreeReader.d.ts.map +1 -1
- package/dist/XCUITreeReader.js +283 -79
- package/dist/XCUITreeReader.js.map +1 -1
- package/dist/xcuiTree.d.ts.map +1 -1
- package/dist/xcuiTree.js +13 -6
- package/dist/xcuiTree.js.map +1 -1
- package/package.json +11 -9
- package/xctest-runner/TreeRunner/TreeServer.swift +21 -8
- package/xctest-runner/TreeRunner/TreeServerTest.swift +9 -6
package/dist/XCUITreeReader.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { spawn, execFile } from 'child_process';
|
|
2
2
|
import { promisify } from 'util';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { createHash, randomUUID } from 'crypto';
|
|
4
|
+
import { readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
5
|
+
import { join, relative } from 'path';
|
|
5
6
|
import { createLogger, PlatformError } from '@tapflowio/agent-core';
|
|
6
7
|
import { parseTreeText } from './xcuiTree.js';
|
|
7
8
|
const logger = createLogger('ios-agent:xcui-tree');
|
|
@@ -10,43 +11,99 @@ const RUNNER_DIR = join(import.meta.dirname, '..', 'xctest-runner');
|
|
|
10
11
|
const PROJECT = join(RUNNER_DIR, 'TapflowTreeRunner.xcodeproj');
|
|
11
12
|
const BUILD_DIR = join(RUNNER_DIR, 'build');
|
|
12
13
|
const PRODUCTS_DIR = join(BUILD_DIR, 'Build', 'Products');
|
|
14
|
+
const STAMP_FILE = join(BUILD_DIR, 'tapflow-runner.stamp');
|
|
13
15
|
const SCHEME = 'TreeRunner';
|
|
14
|
-
// The in-simulator
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
|
|
16
|
+
// The in-simulator process the UI-test session runs as. Killing xcodebuild already ends it (measured); this covers
|
|
17
|
+
// an xcodebuild that dies by SIGKILL without taking it along. `dev.tapflow.treerunner.host` was named here before,
|
|
18
|
+
// and is never installed: `test-without-building` installs only the runner.
|
|
19
|
+
const RUNNER_BUNDLE = 'dev.tapflow.treerunner.uitests.xctrunner';
|
|
20
|
+
const READY_DEADLINE_MS = 90_000;
|
|
21
|
+
const READY_LINE = /TAPFLOW_TREE_READY port=(\d+)/;
|
|
22
|
+
// Everything `build-for-testing` reads from this package: the runner and host sources, the checked-in project and
|
|
23
|
+
// its shared scheme (xcodegen does not run at build time, so `project.yml` alone changes nothing that is built). The toolchain is part
|
|
24
|
+
// of it, so an Xcode upgrade rebuilds too.
|
|
25
|
+
export function computeRunnerStamp(runnerDir, toolchain) {
|
|
26
|
+
const hash = createHash('sha256').update(toolchain);
|
|
27
|
+
const files = [];
|
|
28
|
+
const walk = (dir) => {
|
|
29
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
30
|
+
const path = join(dir, e.name);
|
|
31
|
+
if (e.isDirectory())
|
|
32
|
+
walk(path);
|
|
33
|
+
else if (e.isFile())
|
|
34
|
+
files.push(path);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
walk(join(runnerDir, 'TreeRunner'));
|
|
38
|
+
walk(join(runnerDir, 'TreeHost'));
|
|
39
|
+
files.push(join(runnerDir, 'TapflowTreeRunner.xcodeproj', 'project.pbxproj'));
|
|
40
|
+
files.push(join(runnerDir, 'TapflowTreeRunner.xcodeproj', 'xcshareddata', 'xcschemes', 'TreeRunner.xcscheme'));
|
|
41
|
+
for (const f of files.map((f) => relative(runnerDir, f)).sort()) {
|
|
42
|
+
hash.update(`\0${f}\0`).update(readFileSync(join(runnerDir, f)));
|
|
43
|
+
}
|
|
44
|
+
return hash.digest('hex');
|
|
45
|
+
}
|
|
22
46
|
const defaultNative = {
|
|
23
|
-
|
|
47
|
+
async sourceStamp() {
|
|
48
|
+
const { stdout } = await execFileAsync('xcodebuild', ['-version'], { timeout: 30_000 });
|
|
49
|
+
return computeRunnerStamp(RUNNER_DIR, stdout);
|
|
50
|
+
},
|
|
51
|
+
builtStamp() {
|
|
24
52
|
// test-without-building needs the .xctestrun, not just the .app — gate on it.
|
|
25
53
|
try {
|
|
26
|
-
|
|
54
|
+
if (!readdirSync(PRODUCTS_DIR).some((f) => f.endsWith('.xctestrun')))
|
|
55
|
+
return undefined;
|
|
56
|
+
return readFileSync(STAMP_FILE, 'utf8').trim();
|
|
27
57
|
}
|
|
28
58
|
catch {
|
|
29
|
-
return
|
|
59
|
+
return undefined;
|
|
30
60
|
}
|
|
31
61
|
},
|
|
32
|
-
async build(destination) {
|
|
62
|
+
async build(destination, stamp) {
|
|
33
63
|
await execFileAsync('xcodebuild', ['build-for-testing', '-project', PROJECT, '-scheme', SCHEME, '-destination', destination, '-derivedDataPath', BUILD_DIR, '-quiet'], { timeout: 300_000, maxBuffer: 64 * 1024 * 1024 });
|
|
64
|
+
writeFileSync(STAMP_FILE, stamp);
|
|
34
65
|
},
|
|
35
|
-
spawn(destination,
|
|
36
|
-
|
|
66
|
+
spawn(destination, token) {
|
|
67
|
+
// No `-quiet`: it also silences the test's own output, and the READY line is how the port arrives. The
|
|
68
|
+
// `TEST_RUNNER_` prefix is what makes xcodebuild hand a variable to the runner (it strips the prefix); without
|
|
69
|
+
// it nothing arrives.
|
|
70
|
+
return spawn('xcodebuild', ['test-without-building', '-project', PROJECT, '-scheme', SCHEME, '-destination', destination, '-derivedDataPath', BUILD_DIR], {
|
|
71
|
+
env: { ...process.env, TEST_RUNNER_TAPFLOW_TREE_PORT: '0', TEST_RUNNER_TAPFLOW_TREE_TOKEN: token },
|
|
72
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
73
|
+
detached: true,
|
|
74
|
+
});
|
|
37
75
|
},
|
|
38
|
-
|
|
39
|
-
execFile('xcrun', ['simctl', 'terminate', udid,
|
|
76
|
+
terminateRunner(udid) {
|
|
77
|
+
execFile('xcrun', ['simctl', 'terminate', udid, RUNNER_BUNDLE], () => { });
|
|
40
78
|
},
|
|
41
79
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
80
|
+
function refused(e) {
|
|
81
|
+
return e.cause?.code === 'ECONNREFUSED';
|
|
82
|
+
}
|
|
83
|
+
async function answers(port, token) {
|
|
84
|
+
try {
|
|
85
|
+
const r = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(1000) });
|
|
86
|
+
return r.ok && (await r.text()).trim() === token;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Drives the resident XCUITest tree runners, one per simulator: builds the runner once, launches it per device
|
|
93
|
+
// (staying resident), and queries GET /tree over the simulator-shared loopback. Replaces the AXUIElement path
|
|
94
|
+
// (UITreeReader), which required a Simulator.app window.
|
|
45
95
|
export class XCUITreeReader {
|
|
46
96
|
native;
|
|
47
|
-
|
|
97
|
+
runners = new Map();
|
|
98
|
+
starting = new Map();
|
|
48
99
|
building;
|
|
49
|
-
|
|
100
|
+
stamp;
|
|
101
|
+
// A launch compares the generation it began with before it spawns, because `test-without-building` boots a
|
|
102
|
+
// shut-down simulator and would power a device back up right after someone shut it down. A device's count is
|
|
103
|
+
// never deleted: a count that restarted at 0 would match a launch that began before it was cleared. `epoch` is
|
|
104
|
+
// stop()'s share, so stopping everything also cancels a device that is only building and holds no handle yet.
|
|
105
|
+
generations = new Map();
|
|
106
|
+
epoch = 0;
|
|
50
107
|
constructor(native = defaultNative) {
|
|
51
108
|
this.native = native;
|
|
52
109
|
}
|
|
@@ -54,84 +111,212 @@ export class XCUITreeReader {
|
|
|
54
111
|
// No arch — xcodebuild resolves it (arm64 on Apple Silicon, x86_64 on Intel).
|
|
55
112
|
return `platform=iOS Simulator,id=${udid}`;
|
|
56
113
|
}
|
|
114
|
+
generation(udid) {
|
|
115
|
+
return `${this.epoch}/${this.generations.get(udid) ?? 0}`;
|
|
116
|
+
}
|
|
117
|
+
bumpGeneration(udid) {
|
|
118
|
+
this.generations.set(udid, (this.generations.get(udid) ?? 0) + 1);
|
|
119
|
+
}
|
|
57
120
|
async ensureBuilt(udid) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
121
|
+
// Once per process: a stamp that changed while runners serve (a source edited under a running agent) must not
|
|
122
|
+
// rebuild the products they are executing.
|
|
123
|
+
const stamping = (this.stamp ??= this.native.sourceStamp());
|
|
124
|
+
// Every caller goes through the catch below, the ones that joined a build another device started included:
|
|
125
|
+
// with a runner per device, two first reads at once are the normal case, and the raw xcodebuild error is
|
|
126
|
+
// its whole log.
|
|
127
|
+
const building = (this.building ??= (async () => {
|
|
128
|
+
const stamp = await stamping;
|
|
129
|
+
if (this.native.builtStamp() === stamp)
|
|
130
|
+
return;
|
|
131
|
+
logger.info('building tree runner (first run, or its sources or Xcode changed — cached afterwards)...');
|
|
132
|
+
await this.native.build(this.destination(udid), stamp);
|
|
65
133
|
logger.info('tree runner built');
|
|
66
|
-
})();
|
|
134
|
+
})());
|
|
67
135
|
try {
|
|
68
|
-
await
|
|
136
|
+
await building;
|
|
69
137
|
}
|
|
70
138
|
catch (e) {
|
|
139
|
+
if (this.stamp === stamping)
|
|
140
|
+
this.stamp = undefined;
|
|
71
141
|
throw new PlatformError(`failed to build the UI-tree runner — ensure Xcode and an iOS simulator runtime are installed (xcode-select -p): ${e.message.slice(0, 300)}`);
|
|
72
142
|
}
|
|
73
143
|
finally {
|
|
74
|
-
this.building
|
|
144
|
+
if (this.building === building)
|
|
145
|
+
this.building = undefined;
|
|
75
146
|
}
|
|
76
147
|
}
|
|
77
148
|
runnerAlive(h) {
|
|
78
|
-
|
|
149
|
+
// `signalCode` too: a runner killed from outside (by signal) keeps `exitCode` null and `killed` false, and
|
|
150
|
+
// without it every read went on asking a dead port for as long as the agent ran.
|
|
151
|
+
return !!h && h.proc.exitCode === null && h.proc.signalCode === null && !h.proc.killed;
|
|
152
|
+
}
|
|
153
|
+
ready(h) {
|
|
154
|
+
return this.runnerAlive(h) && h.port !== undefined;
|
|
79
155
|
}
|
|
80
156
|
async ensureRunner(udid) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
157
|
+
// Serialize concurrent callers for one device so we never double-spawn or hand back an un-ready runner.
|
|
158
|
+
// A loop, not one wait: two callers that both waited out a failed launch would otherwise both start their own.
|
|
159
|
+
// Other devices are never touched.
|
|
160
|
+
for (;;) {
|
|
161
|
+
const held = this.runners.get(udid);
|
|
162
|
+
if (this.ready(held))
|
|
163
|
+
return held;
|
|
164
|
+
const pending = this.starting.get(udid);
|
|
165
|
+
if (!pending)
|
|
166
|
+
break;
|
|
167
|
+
const h = await pending.catch(() => undefined);
|
|
168
|
+
if (h && this.ready(h) && this.runners.get(udid) === h)
|
|
88
169
|
return h;
|
|
89
170
|
}
|
|
90
|
-
|
|
171
|
+
const starting = this.launchRunner(udid);
|
|
172
|
+
this.starting.set(udid, starting);
|
|
91
173
|
try {
|
|
92
|
-
return await
|
|
174
|
+
return await starting;
|
|
93
175
|
}
|
|
94
176
|
finally {
|
|
95
|
-
this.starting
|
|
177
|
+
if (this.starting.get(udid) === starting)
|
|
178
|
+
this.starting.delete(udid);
|
|
96
179
|
}
|
|
97
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Start the runner before anything asks for a tree, for a device an automation client just booted. A cold
|
|
183
|
+
* start is about 3 s on a running simulator and 8–9 s right after a boot (iOS 26.5), and on the first query
|
|
184
|
+
* that time is spent inside the step's selector timeout (10 s by default). Manual sessions are not warmed:
|
|
185
|
+
* they never read the tree, and a runner costs about 650 MB per device.
|
|
186
|
+
*
|
|
187
|
+
* Each device has its own runner, so warming one never touches another's. A read during the warm-up waits on
|
|
188
|
+
* the same launch.
|
|
189
|
+
*/
|
|
190
|
+
warm(udid) {
|
|
191
|
+
if (this.starting.has(udid))
|
|
192
|
+
return;
|
|
193
|
+
const held = this.runners.get(udid);
|
|
194
|
+
let generation = this.generation(udid);
|
|
195
|
+
// A runner already serving this device may have died with a simulator shut down outside tapflow, while its
|
|
196
|
+
// xcodebuild lingers for up to a minute and still looks alive: ask it before keeping it. Dropping it here is
|
|
197
|
+
// this warm-up's own doing, so it moves the generation this warm-up compares against.
|
|
198
|
+
const check = this.ready(held)
|
|
199
|
+
? answers(held.port, held.token).then((ok) => {
|
|
200
|
+
// Only a drop of its own moves the generation it compares against. A probe that failed because the
|
|
201
|
+
// device was shut down (or the agent stopped) meanwhile must leave that stop standing.
|
|
202
|
+
if (!ok && this.runners.get(udid) === held) {
|
|
203
|
+
this.dropRunner(udid, held);
|
|
204
|
+
generation = this.generation(udid);
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
: Promise.resolve();
|
|
208
|
+
check.then(() => {
|
|
209
|
+
// The device may have been shut down while the probe was out.
|
|
210
|
+
if (this.generation(udid) !== generation)
|
|
211
|
+
return;
|
|
212
|
+
return this.ensureRunner(udid);
|
|
213
|
+
}).catch((e) => {
|
|
214
|
+
// Stopped on purpose (the device was shut down mid-start) is not a fault worth sending anyone to Xcode for.
|
|
215
|
+
if (this.generation(udid) !== generation)
|
|
216
|
+
logger.debug(`tree runner warm-up for ${udid} cancelled: ${e.message}`);
|
|
217
|
+
else
|
|
218
|
+
logger.warn(`tree runner warm-up for ${udid} failed; the first query will try again: ${e.message}`);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
98
221
|
async launchRunner(udid) {
|
|
99
|
-
this.
|
|
222
|
+
const stale = this.runners.get(udid);
|
|
223
|
+
if (stale)
|
|
224
|
+
this.dropRunner(udid, stale);
|
|
225
|
+
const generation = this.generation(udid);
|
|
100
226
|
await this.ensureBuilt(udid);
|
|
101
|
-
|
|
227
|
+
if (this.generation(udid) !== generation)
|
|
228
|
+
throw new PlatformError('tree runner start cancelled — the runner was stopped while it was being built');
|
|
229
|
+
// No await between the check above and registering the handle, so a stop always finds what it must kill.
|
|
230
|
+
const token = randomUUID();
|
|
231
|
+
const proc = this.native.spawn(this.destination(udid), token);
|
|
102
232
|
proc.on('error', (e) => logger.error('tree runner process error:', e.message));
|
|
103
|
-
const handle = { proc, udid,
|
|
104
|
-
this.
|
|
105
|
-
await this.waitReady(handle);
|
|
233
|
+
const handle = { proc, udid, token };
|
|
234
|
+
this.runners.set(udid, handle);
|
|
235
|
+
const port = await this.waitReady(handle);
|
|
236
|
+
// Stopped while it was coming up: its xcodebuild takes seconds to exit, and until then the runner still answers.
|
|
237
|
+
if (this.runners.get(udid) !== handle)
|
|
238
|
+
throw new PlatformError('tree runner start cancelled — the runner was stopped while it was starting');
|
|
239
|
+
handle.port = port;
|
|
106
240
|
return handle;
|
|
107
241
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (r.ok)
|
|
242
|
+
// The runner announces its port on stdout once it is listening. Resolves with it, or rejects when the process
|
|
243
|
+
// exits first or the deadline passes. The listener stays for the life of the process: an undrained pipe would
|
|
244
|
+
// block the runner once its buffer filled.
|
|
245
|
+
readPort(handle, deadline) {
|
|
246
|
+
return new Promise((resolve, reject) => {
|
|
247
|
+
let pending = '';
|
|
248
|
+
let settled = false;
|
|
249
|
+
const settle = (err, port) => {
|
|
250
|
+
if (settled)
|
|
118
251
|
return;
|
|
252
|
+
settled = true;
|
|
253
|
+
clearTimeout(timer);
|
|
254
|
+
handle.proc.off('exit', onExit);
|
|
255
|
+
if (err)
|
|
256
|
+
reject(err);
|
|
257
|
+
else
|
|
258
|
+
resolve(port);
|
|
259
|
+
};
|
|
260
|
+
const onExit = () => settle(new PlatformError('tree runner exited before becoming ready — check Xcode/simulator state'));
|
|
261
|
+
const timer = setTimeout(() => settle(new PlatformError('tree runner did not become ready in time')), Math.max(0, deadline - Date.now()));
|
|
262
|
+
handle.proc.stdout?.on('data', (chunk) => {
|
|
263
|
+
if (settled)
|
|
264
|
+
return;
|
|
265
|
+
// A chunk boundary can split the line, so keep the unfinished tail.
|
|
266
|
+
pending += chunk.toString();
|
|
267
|
+
const m = READY_LINE.exec(pending);
|
|
268
|
+
if (m)
|
|
269
|
+
settle(undefined, Number(m[1]));
|
|
270
|
+
else
|
|
271
|
+
pending = pending.slice(pending.lastIndexOf('\n') + 1);
|
|
272
|
+
});
|
|
273
|
+
handle.proc.once('exit', onExit);
|
|
274
|
+
if (!this.runnerAlive(handle))
|
|
275
|
+
onExit();
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
async waitReady(handle) {
|
|
279
|
+
const deadline = Date.now() + READY_DEADLINE_MS;
|
|
280
|
+
try {
|
|
281
|
+
const port = await this.readPort(handle, deadline);
|
|
282
|
+
// A runner built before the port was chosen this way prints the port it was given, which is now 0.
|
|
283
|
+
if (port === 0)
|
|
284
|
+
throw new PlatformError('tree runner is out of date (announced port 0) — remove xctest-runner/build to rebuild it');
|
|
285
|
+
// A clock, not an iteration count: a refused connection fails at once, so the count would set the cap
|
|
286
|
+
// through the sleep below.
|
|
287
|
+
while (Date.now() < deadline) {
|
|
288
|
+
if (!this.runnerAlive(handle))
|
|
289
|
+
throw new PlatformError('tree runner exited before becoming ready — check Xcode/simulator state');
|
|
290
|
+
try {
|
|
291
|
+
const r = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(1000) });
|
|
292
|
+
if (r.ok) {
|
|
293
|
+
// Anything else answering is not the runner we started, and its tree would be another simulator's.
|
|
294
|
+
if ((await r.text()).trim() === handle.token)
|
|
295
|
+
return port;
|
|
296
|
+
throw new PlatformError(`port ${port} is answered by another tree runner — not reading from it`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (e) {
|
|
300
|
+
if (e instanceof PlatformError)
|
|
301
|
+
throw e;
|
|
302
|
+
/* not listening yet */
|
|
303
|
+
}
|
|
304
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
119
305
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
306
|
+
throw new PlatformError('tree runner did not become ready in time');
|
|
307
|
+
}
|
|
308
|
+
catch (e) {
|
|
309
|
+
this.dropRunner(handle.udid, handle);
|
|
310
|
+
throw e;
|
|
124
311
|
}
|
|
125
|
-
this.stop();
|
|
126
|
-
throw new PlatformError('tree runner did not become ready in time');
|
|
127
312
|
}
|
|
128
313
|
async read(udid, bundleId) {
|
|
129
314
|
if (!bundleId)
|
|
130
315
|
throw new PlatformError('UI tree query needs a foreground app — launch an app first');
|
|
131
|
-
const
|
|
316
|
+
const handle = await this.ensureRunner(udid);
|
|
132
317
|
let text;
|
|
133
318
|
try {
|
|
134
|
-
const r = await fetch(`http://localhost:${port}/tree?bundleId=${encodeURIComponent(bundleId)}`, { signal: AbortSignal.timeout(10_000) });
|
|
319
|
+
const r = await fetch(`http://localhost:${handle.port}/tree?bundleId=${encodeURIComponent(bundleId)}`, { signal: AbortSignal.timeout(10_000) });
|
|
135
320
|
if (!r.ok)
|
|
136
321
|
throw new PlatformError(`tree runner returned HTTP ${r.status} for ${bundleId}`);
|
|
137
322
|
text = await r.text();
|
|
@@ -139,28 +324,47 @@ export class XCUITreeReader {
|
|
|
139
324
|
catch (e) {
|
|
140
325
|
if (e instanceof PlatformError)
|
|
141
326
|
throw e;
|
|
327
|
+
// Nothing listening: the runner died (with its simulator, shut down outside tapflow) while xcodebuild lingers,
|
|
328
|
+
// so `runnerAlive` still says yes. Drop it, or every read until xcodebuild exits fails the same way. A timeout
|
|
329
|
+
// is not this: a runner on a screen that never goes idle is slow, not gone.
|
|
330
|
+
if (refused(e))
|
|
331
|
+
this.dropRunner(udid, handle);
|
|
142
332
|
throw new PlatformError(`UI tree query failed: ${e.message}`);
|
|
143
333
|
}
|
|
144
334
|
// Guard against a garbage / wrong-bundleId body silently parsing to an empty
|
|
145
335
|
// tree — consumers must see an error, never a false "screen has no elements".
|
|
336
|
+
// Load-bearing for launch readiness too: while a launched app is still starting the runner answers a "not found"
|
|
337
|
+
// query chain, and this error is what tells flow-runner's `launchApp` the screen is not up yet (see agent-core's
|
|
338
|
+
// `DeviceAgent.launchApp`). Turning it into an empty tree would make every launch read as ready at once.
|
|
146
339
|
if (!text.includes('Element subtree:') && !text.includes('Application,')) {
|
|
147
340
|
throw new PlatformError(`tree runner returned an unexpected response for ${bundleId} — is the app running in the foreground?`);
|
|
148
341
|
}
|
|
149
342
|
return parseTreeText(text);
|
|
150
343
|
}
|
|
151
|
-
//
|
|
152
|
-
stop()
|
|
153
|
-
|
|
154
|
-
if (
|
|
344
|
+
// Drop one device's runner, if `handle` is still the one it holds. Every fault path goes through here rather than
|
|
345
|
+
// stop(): one device's dead runner must not take the others down with it.
|
|
346
|
+
dropRunner(udid, handle) {
|
|
347
|
+
if (this.runners.get(udid) !== handle)
|
|
155
348
|
return;
|
|
156
|
-
this.
|
|
349
|
+
this.runners.delete(udid);
|
|
350
|
+
this.bumpGeneration(udid);
|
|
157
351
|
this.killHandle(handle);
|
|
158
352
|
}
|
|
159
|
-
// Stop
|
|
160
|
-
|
|
353
|
+
// Stop every device's runner, including launches still building (agent shutdown).
|
|
354
|
+
stop() {
|
|
355
|
+
this.epoch++;
|
|
356
|
+
for (const handle of this.runners.values())
|
|
357
|
+
this.killHandle(handle);
|
|
358
|
+
this.runners.clear();
|
|
359
|
+
}
|
|
360
|
+
// Stop this device's runner, or the launch starting one for it — on device shutdown and before an erase.
|
|
161
361
|
stopIfDevice(udid) {
|
|
162
|
-
|
|
163
|
-
|
|
362
|
+
this.bumpGeneration(udid);
|
|
363
|
+
const handle = this.runners.get(udid);
|
|
364
|
+
if (!handle)
|
|
365
|
+
return;
|
|
366
|
+
this.runners.delete(udid);
|
|
367
|
+
this.killHandle(handle);
|
|
164
368
|
}
|
|
165
369
|
killHandle(handle) {
|
|
166
370
|
const { proc, udid } = handle;
|
|
@@ -175,9 +379,9 @@ export class XCUITreeReader {
|
|
|
175
379
|
catch {
|
|
176
380
|
/* already gone */
|
|
177
381
|
}
|
|
178
|
-
// The in-simulator
|
|
179
|
-
//
|
|
180
|
-
this.native.
|
|
382
|
+
// The in-simulator runner is not in that group; ending xcodebuild normally ends it, and this covers the case
|
|
383
|
+
// where it does not.
|
|
384
|
+
this.native.terminateRunner(udid);
|
|
181
385
|
// SIGKILL fallback if SIGTERM did not take.
|
|
182
386
|
const timer = setTimeout(() => {
|
|
183
387
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XCUITreeReader.js","sourceRoot":"","sources":["../src/XCUITreeReader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAqB,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,IAAI,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,MAAM,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAA;AAClD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAEzC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,eAAe,CAAC,CAAA;AACnE,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,6BAA6B,CAAC,CAAA;AAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;AAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;AACzD,MAAM,MAAM,GAAG,YAAY,CAAA;AAC3B,gFAAgF;AAChF,gFAAgF;AAChF,sDAAsD;AACtD,MAAM,kBAAkB,GAAG,6BAA6B,CAAA;AACxD,8EAA8E;AAC9E,gFAAgF;AAChF,gFAAgF;AAChF,MAAM,IAAI,GAAG,KAAK,CAAA;AAiBlB,MAAM,aAAa,GAAiB;IAClC,cAAc;QACZ,8EAA8E;QAC9E,IAAI,CAAC;YACH,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAA;QACxE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IACD,KAAK,CAAC,KAAK,CAAC,WAAW;QACrB,MAAM,aAAa,CACjB,YAAY,EACZ,CAAC,mBAAmB,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,kBAAkB,EAAE,SAAS,EAAE,QAAQ,CAAC,EACnI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAClD,CAAA;IACH,CAAC;IACD,KAAK,CAAC,WAAW,EAAE,IAAI;QACrB,OAAO,KAAK,CACV,YAAY,EACZ,CAAC,uBAAuB,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,kBAAkB,EAAE,SAAS,EAAE,QAAQ,CAAC,EACvI,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAC9F,CAAA;IACH,CAAC;IACD,aAAa,CAAC,IAAI;QAChB,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,kBAAkB,CAAC,EAAE,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAA;IACnG,CAAC;CACF,CAAA;AAED,iFAAiF;AACjF,gFAAgF;AAChF,8EAA8E;AAC9E,MAAM,OAAO,cAAc;IAKI;IAJrB,MAAM,CAAe;IACrB,QAAQ,CAAgB;IACxB,QAAQ,CAAwB;IAExC,YAA6B,SAAuB,aAAa;QAApC,WAAM,GAAN,MAAM,CAA8B;IAAG,CAAC;IAE7D,WAAW,CAAC,IAAY;QAC9B,8EAA8E;QAC9E,OAAO,6BAA6B,IAAI,EAAE,CAAA;IAC5C,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,IAAY;QACpC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;YAAE,OAAM;QACxC,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAA;QACvC,IAAI,CAAC,QAAQ,GAAG,CAAC,KAAK,IAAI,EAAE;YAC1B,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAA;YACtE,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAA;YAC/C,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QAClC,CAAC,CAAC,EAAE,CAAA;QACJ,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAQ,CAAA;QACrB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,aAAa,CACrB,mHAAoH,CAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CACxJ,CAAA;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;QAC3B,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,CAA2B;QAC7C,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAA;IAC1D,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,IAAY;QACrC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,MAAM,CAAA;QAClF,wEAAwE;QACxE,+EAA+E;QAC/E,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;YACpD,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI;gBAAE,OAAO,CAAC,CAAA;QAC3D,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAA;QAC5B,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;QAC3B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,IAAY;QACrC,IAAI,CAAC,IAAI,EAAE,CAAA,CAAC,8CAA8C;QAC1D,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA;QAC5D,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;QAC9E,MAAM,MAAM,GAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;QACvD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QAC5B,OAAO,MAAM,CAAA;IACf,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,MAAoB;QAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;oBAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;gBACnD,MAAM,IAAI,aAAa,CAAC,wEAAwE,CAAC,CAAA;YACnG,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,oBAAoB,MAAM,CAAC,IAAI,SAAS,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;gBACtG,IAAI,CAAC,CAAC,EAAE;oBAAE,OAAM;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;QAC/C,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAA;QACX,MAAM,IAAI,aAAa,CAAC,0CAA0C,CAAC,CAAA;IACrE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,QAAgB;QACvC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,aAAa,CAAC,4DAA4D,CAAC,CAAA;QACpG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QAC9C,IAAI,IAAY,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,kBAAkB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACxI,IAAI,CAAC,CAAC,CAAC,EAAE;gBAAE,MAAM,IAAI,aAAa,CAAC,6BAA6B,CAAC,CAAC,MAAM,QAAQ,QAAQ,EAAE,CAAC,CAAA;YAC3F,IAAI,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAA;QACvB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,aAAa;gBAAE,MAAM,CAAC,CAAA;YACvC,MAAM,IAAI,aAAa,CAAC,yBAA0B,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;QAC1E,CAAC;QACD,6EAA6E;QAC7E,8EAA8E;QAC9E,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,aAAa,CAAC,mDAAmD,QAAQ,0CAA0C,CAAC,CAAA;QAChI,CAAC;QACD,OAAO,aAAa,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC;IAED,iEAAiE;IACjE,IAAI;QACF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QAC1B,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAA;QACvB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IACzB,CAAC;IAED,8EAA8E;IAC9E,uDAAuD;IACvD,YAAY,CAAC,IAAY;QACvB,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI;YAAE,IAAI,CAAC,IAAI,EAAE,CAAA;IAC7C,CAAC;IAEO,UAAU,CAAC,MAAoB;QACrC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,CAAA;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;QACpB,wEAAwE;QACxE,IAAI,CAAC;YACH,IAAI,GAAG;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;;gBACjC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;QACD,6EAA6E;QAC7E,yCAAyC;QACzC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;QAC/B,4CAA4C;QAC5C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC;gBACH,IAAI,GAAG;oBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU;YACZ,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,CAAA;QACR,KAAK,CAAC,KAAK,EAAE,EAAE,CAAA;IACjB,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"XCUITreeReader.js","sourceRoot":"","sources":["../src/XCUITreeReader.ts"],"names":[],"mappings":"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"}
|
package/dist/xcuiTree.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xcuiTree.d.ts","sourceRoot":"","sources":["../src/xcuiTree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"xcuiTree.d.ts","sourceRoot":"","sources":["../src/xcuiTree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,uBAAuB,CAAA;AAyFrE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAoDvD"}
|
package/dist/xcuiTree.js
CHANGED
|
@@ -48,6 +48,8 @@ function toRole(type) {
|
|
|
48
48
|
}
|
|
49
49
|
const ACTIONABLE = new Set(['button', 'input', 'checkbox', 'switch', 'slider', 'tab', 'cell']);
|
|
50
50
|
const round4 = (n) => Math.round(n * 10000) / 10000;
|
|
51
|
+
/** Down, for a far edge: `x + width` must not reach past 1 by a rounding step. */
|
|
52
|
+
const floor4 = (n) => Math.max(0, Math.floor(n * 10000 + 1e-9) / 10000);
|
|
51
53
|
const FRAME_RE = /\{\{(-?[\d.]+), (-?[\d.]+)\}, \{(-?[\d.]+), (-?[\d.]+)\}\}/;
|
|
52
54
|
// Terminate quoted fields on the next field boundary, so a quote inside the
|
|
53
55
|
// value (e.g. label: 'Don't') does not truncate the match. The `, value: `
|
|
@@ -108,15 +110,20 @@ export function parseTreeText(text) {
|
|
|
108
110
|
// Skip pure structural containers with no label and no actionable role.
|
|
109
111
|
if (!ACTIONABLE.has(role) && label === '' && !node.identifier)
|
|
110
112
|
continue;
|
|
113
|
+
// Clipped to the screen, as the Android agent does: a node partly scrolled or animated out would otherwise
|
|
114
|
+
// carry a frame outside 0–1, and every consumer refuses the whole tree for one such element. A node wholly
|
|
115
|
+
// off the screen is dropped — nothing can tap it.
|
|
116
|
+
const x1 = Math.max(0, (node.frame.x - basis.x) / basis.width);
|
|
117
|
+
const y1 = Math.max(0, (node.frame.y - basis.y) / basis.height);
|
|
118
|
+
const x2 = Math.min(1, (node.frame.x + node.frame.width - basis.x) / basis.width);
|
|
119
|
+
const y2 = Math.min(1, (node.frame.y + node.frame.height - basis.y) / basis.height);
|
|
120
|
+
if (x2 <= x1 || y2 <= y1)
|
|
121
|
+
continue;
|
|
111
122
|
const element = {
|
|
112
123
|
role,
|
|
113
124
|
label,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
y: round4((node.frame.y - basis.y) / basis.height),
|
|
117
|
-
width: round4(node.frame.width / basis.width),
|
|
118
|
-
height: round4(node.frame.height / basis.height),
|
|
119
|
-
},
|
|
125
|
+
// The far edge is rounded down, so rounding can never carry x + width past 1 — the consumers compare exactly.
|
|
126
|
+
frame: { x: round4(x1), y: round4(y1), width: floor4(x2 - round4(x1)), height: floor4(y2 - round4(y1)) },
|
|
120
127
|
enabled: true, // debugDescription does not expose enabled; default true (Open Q9)
|
|
121
128
|
};
|
|
122
129
|
if (node.identifier)
|
package/dist/xcuiTree.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xcuiTree.js","sourceRoot":"","sources":["../src/xcuiTree.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,4EAA4E;AAC5E,gFAAgF;AAChF,uEAAuE;AACvE,EAAE;AACF,8CAA8C;AAC9C,oFAAoF;AACpF,iGAAiG;AACjG,gGAAgG;AAChG,4FAA4F;AAE5F,mFAAmF;AACnF,mFAAmF;AACnF,8CAA8C;AAC9C,SAAS,MAAM,CAAC,IAAY;IAC1B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,KAAK;YACR,OAAO,QAAQ,CAAA;QACjB,KAAK,WAAW,CAAC;QACjB,KAAK,iBAAiB,CAAC;QACvB,KAAK,aAAa,CAAC;QACnB,KAAK,UAAU;YACb,OAAO,OAAO,CAAA;QAChB,KAAK,YAAY;YACf,OAAO,MAAM,CAAA;QACf,KAAK,OAAO,CAAC;QACb,KAAK,MAAM;YACT,OAAO,OAAO,CAAA;QAChB,KAAK,QAAQ,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAA;QACjB,KAAK,UAAU;YACb,OAAO,UAAU,CAAA;QACnB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAA;QACjB,KAAK,OAAO,CAAC;QACb,KAAK,gBAAgB,CAAC;QACtB,KAAK,YAAY;YACf,OAAO,MAAM,CAAA;QACf,KAAK,MAAM;YACT,OAAO,MAAM,CAAA;QACf,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU;YACb,OAAO,KAAK,CAAA;QACd;YACE,OAAO,OAAO,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,GAAG,CAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;AAC7G,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"xcuiTree.js","sourceRoot":"","sources":["../src/xcuiTree.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tapflowio/ios-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "iOS simulator agent for tapflow — xcrun simctl control and screen streaming",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tapflow",
|
|
@@ -44,7 +44,9 @@
|
|
|
44
44
|
"xctest-runner/TreeRunner",
|
|
45
45
|
"xctest-runner/TapflowTreeRunner.xcodeproj",
|
|
46
46
|
"README.md",
|
|
47
|
-
"LICENSE"
|
|
47
|
+
"LICENSE",
|
|
48
|
+
"LICENSE-APACHE-2.0",
|
|
49
|
+
"NOTICE"
|
|
48
50
|
],
|
|
49
51
|
"engines": {
|
|
50
52
|
"node": ">=22.0.0"
|
|
@@ -54,16 +56,16 @@
|
|
|
54
56
|
},
|
|
55
57
|
"dependencies": {
|
|
56
58
|
"ws": "^8.22.0",
|
|
57
|
-
"@tapflowio/agent-core": "0.
|
|
58
|
-
"@tapflowio/protocol": "0.
|
|
59
|
-
"@tapflowio/audiotap-helper": "0.3.
|
|
59
|
+
"@tapflowio/agent-core": "0.28.0",
|
|
60
|
+
"@tapflowio/protocol": "0.28.0",
|
|
61
|
+
"@tapflowio/audiotap-helper": "0.3.12"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^22.20.
|
|
63
|
-
"@types/ws": "^8.
|
|
64
|
+
"@types/node": "^22.20.5",
|
|
65
|
+
"@types/ws": "^8.18.2",
|
|
64
66
|
"typescript": "^5.0.0",
|
|
65
|
-
"vitest": "^4.1.
|
|
66
|
-
"@tapflowio/relay": "0.
|
|
67
|
+
"vitest": "^4.1.12",
|
|
68
|
+
"@tapflowio/relay": "0.28.0",
|
|
67
69
|
"@tapflowio/test-utils": "0.0.0"
|
|
68
70
|
},
|
|
69
71
|
"scripts": {
|