@houwert/conductor 0.8.0 → 0.10.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.
@@ -41,6 +41,26 @@ const cdpUrl = process.env.CONDUCTOR_CDP_URL || undefined;
41
41
  * URL heuristics.
42
42
  */
43
43
  const cdpTargetId = process.env.CONDUCTOR_CDP_TARGET_ID || undefined;
44
+ /**
45
+ * PID of the process that should be considered the daemon's "owner". When set,
46
+ * the daemon polls for this process's existence and shuts down cleanly when it
47
+ * disappears. This prevents orphaned daemons (and their Playwright browsers)
48
+ * from piling up after the host app crashes or quits without calling
49
+ * `daemon-stop`.
50
+ *
51
+ * The daemon runs detached, so `process.ppid` becomes 1 after the parent exits
52
+ * and is useless for this purpose. The owner must be passed explicitly by the
53
+ * host app via the env when it invokes `conductor daemon-start` (or whatever
54
+ * code path ultimately triggers the daemon spawn).
55
+ */
56
+ const parentPid = (() => {
57
+ const raw = process.env.CONDUCTOR_PARENT_PID;
58
+ if (!raw)
59
+ return undefined;
60
+ const n = parseInt(raw, 10);
61
+ return Number.isFinite(n) && n > 0 ? n : undefined;
62
+ })();
63
+ const PARENT_POLL_INTERVAL_MS = 10000;
44
64
  const SOCKET_PATH = (0, protocol_js_1.socketPath)(sessionName);
45
65
  const PID_FILE = (0, protocol_js_1.pidFile)(sessionName);
46
66
  const LOG_FILE = (0, protocol_js_1.logFile)(sessionName);
@@ -123,6 +143,7 @@ async function main() {
123
143
  }
124
144
  let idleTimer;
125
145
  let healthTimer;
146
+ let parentWatchTimer;
126
147
  const idleTimeoutMs = Number(process.env.CONDUCTOR_IDLE_TIMEOUT_MS) || protocol_js_1.IDLE_TIMEOUT_MS;
127
148
  function resetIdleTimer() {
128
149
  if (idleTimer)
@@ -135,6 +156,10 @@ async function main() {
135
156
  async function cleanup() {
136
157
  if (healthTimer)
137
158
  clearInterval(healthTimer);
159
+ if (parentWatchTimer)
160
+ clearInterval(parentWatchTimer);
161
+ if (idleTimer)
162
+ clearTimeout(idleTimer);
138
163
  if (logCollector) {
139
164
  logCollector.stop();
140
165
  logCollector = null;
@@ -215,6 +240,30 @@ async function main() {
215
240
  }, DRIVER_HEALTH_INTERVAL_MS);
216
241
  healthTimer.unref(); // Don't keep the process alive just for health checks
217
242
  }
243
+ // If the host app told us who it is, shut down when it disappears. This is
244
+ // the primary defence against orphaned daemons + headless Chromiums when the
245
+ // host app crashes or force-quits without calling daemon-stop.
246
+ if (parentPid !== undefined) {
247
+ dlog(`Watching parent pid ${parentPid}`);
248
+ let shuttingDown = false;
249
+ parentWatchTimer = setInterval(() => {
250
+ if (shuttingDown)
251
+ return;
252
+ try {
253
+ process.kill(parentPid, 0);
254
+ }
255
+ catch (err) {
256
+ const code = err.code;
257
+ if (code === 'ESRCH') {
258
+ shuttingDown = true;
259
+ dlog(`Parent pid ${parentPid} exited — shutting down`);
260
+ cleanup().then(() => process.exit(0));
261
+ }
262
+ // EPERM means the process exists but we can't signal it — still alive.
263
+ }
264
+ }, PARENT_POLL_INTERVAL_MS);
265
+ parentWatchTimer.unref();
266
+ }
218
267
  // ── HTTP server on Unix socket ─────────────────────────────────────────────
219
268
  // Replaces the old raw-TCP accept-and-close with a proper HTTP server so we
220
269
  // can serve /status (aliveness) and /logs (buffered log entries).
@@ -35,6 +35,7 @@ exports.uninstallDriver = uninstallDriver;
35
35
  const child_process_1 = require("child_process");
36
36
  const crypto_1 = __importDefault(require("crypto"));
37
37
  const http_1 = __importDefault(require("http"));
38
+ const https_1 = __importDefault(require("https"));
38
39
  const net_1 = __importDefault(require("net"));
39
40
  const os_1 = __importDefault(require("os"));
40
41
  const fs_1 = __importDefault(require("fs"));
@@ -161,40 +162,195 @@ async function getDriverPort(platform, deviceId) {
161
162
  return port;
162
163
  });
163
164
  }
164
- // ── Bundled driver paths ───────────────────────────────────────────────────────
165
+ // ── Driver paths (bundled dev fallback + runtime download cache) ──────────────
165
166
  /**
166
- * Root of the bundled drivers directory (packages/cli/drivers/).
167
- *
168
167
  * Walk up from __dirname to find the package root (the directory containing
169
- * package.json). This handles both the normal build (dist/drivers/bootstrap.js)
170
- * and the test build (dist-tests/src/drivers/bootstrap.js) where __dirname has
171
- * an extra src/ level, making a fixed relative path incorrect.
168
+ * package.json). Handles both the normal build (dist/drivers/bootstrap.js)
169
+ * and the test build (dist-tests/src/drivers/bootstrap.js) where __dirname
170
+ * has an extra src/ level.
172
171
  */
173
- function findBundledDriversDir() {
172
+ function findPackageRoot() {
174
173
  let dir = __dirname;
175
174
  while (true) {
176
175
  if (fs_1.default.existsSync(path_1.default.join(dir, 'package.json'))) {
177
- return path_1.default.join(dir, 'drivers');
176
+ return dir;
178
177
  }
179
178
  const parent = path_1.default.dirname(dir);
180
179
  if (parent === dir)
181
180
  break;
182
181
  dir = parent;
183
182
  }
184
- // Fallback to original relative path
185
- return path_1.default.join(__dirname, '..', '..', 'drivers');
183
+ return path_1.default.join(__dirname, '..', '..');
184
+ }
185
+ const DRIVERS_CACHE_ROOT = path_1.default.join(os_1.default.homedir(), '.conductor', 'drivers');
186
+ const DRIVERS_DOWNLOAD_BASE = 'https://github.com/DouweBos/conductor/releases/download';
187
+ const DRIVERS_LOCK_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes (download can be slow)
188
+ const DRIVERS_LOCK_POLL_MS = 500;
189
+ let _driversDirPromise = null;
190
+ /**
191
+ * Resolve the directory containing the platform driver artifacts
192
+ * (`<dir>/{android,ios,tvos}/...`).
193
+ *
194
+ * Lookup order:
195
+ * 1. Legacy bundled drivers at `<pkg-root>/drivers/` — populated by
196
+ * `make build` for local development.
197
+ * 2. Runtime cache at `~/.conductor/drivers/<version>/` — downloaded
198
+ * on first use from the matching GitHub Release.
199
+ */
200
+ async function getDriversDir() {
201
+ if (_driversDirPromise)
202
+ return _driversDirPromise;
203
+ _driversDirPromise = (async () => {
204
+ const pkgRoot = findPackageRoot();
205
+ const legacyDir = path_1.default.join(pkgRoot, 'drivers');
206
+ if (fs_1.default.existsSync(legacyDir))
207
+ return legacyDir;
208
+ return await ensureDriversCache(pkgRoot);
209
+ })().catch((err) => {
210
+ _driversDirPromise = null;
211
+ throw err;
212
+ });
213
+ return _driversDirPromise;
214
+ }
215
+ async function ensureDriversCache(pkgRoot) {
216
+ const pkgJsonPath = path_1.default.join(pkgRoot, 'package.json');
217
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, 'utf-8'));
218
+ const version = pkg.version;
219
+ const cacheDir = path_1.default.join(DRIVERS_CACHE_ROOT, version);
220
+ const completeMarker = path_1.default.join(cacheDir, '.complete');
221
+ if (fs_1.default.existsSync(completeMarker))
222
+ return cacheDir;
223
+ fs_1.default.mkdirSync(DRIVERS_CACHE_ROOT, { recursive: true });
224
+ const lockFile = path_1.default.join(DRIVERS_CACHE_ROOT, `${version}.lock`);
225
+ await acquireDriversLock(lockFile);
226
+ try {
227
+ // Re-check after acquiring lock — another process may have finished.
228
+ if (fs_1.default.existsSync(completeMarker))
229
+ return cacheDir;
230
+ const tmpDir = path_1.default.join(DRIVERS_CACHE_ROOT, `.tmp-${version}-${process.pid}-${Date.now()}`);
231
+ fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
232
+ fs_1.default.mkdirSync(tmpDir, { recursive: true });
233
+ const tarball = path_1.default.join(tmpDir, 'drivers.tar.gz');
234
+ const url = `${DRIVERS_DOWNLOAD_BASE}/v${version}/drivers.tar.gz`;
235
+ (0, verbose_js_1.log)(`Downloading conductor drivers v${version} from ${url}...`);
236
+ try {
237
+ await downloadToFile(url, tarball);
238
+ (0, child_process_1.execFileSync)('tar', ['-xzf', tarball, '-C', tmpDir], { stdio: 'ignore' });
239
+ fs_1.default.unlinkSync(tarball);
240
+ if (fs_1.default.existsSync(cacheDir)) {
241
+ fs_1.default.rmSync(cacheDir, { recursive: true, force: true });
242
+ }
243
+ fs_1.default.renameSync(tmpDir, cacheDir);
244
+ fs_1.default.writeFileSync(completeMarker, version);
245
+ (0, verbose_js_1.log)(`Conductor drivers v${version} ready at ${cacheDir}`);
246
+ pruneOldDriverCaches(version);
247
+ return cacheDir;
248
+ }
249
+ catch (err) {
250
+ fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
251
+ throw new Error(`Failed to download conductor drivers v${version} from ${url}: ${err.message}`);
252
+ }
253
+ }
254
+ finally {
255
+ try {
256
+ fs_1.default.unlinkSync(lockFile);
257
+ }
258
+ catch {
259
+ /* ok */
260
+ }
261
+ }
262
+ }
263
+ /**
264
+ * Remove cached driver versions other than the current one. Old CLI builds
265
+ * would just re-download on demand, so there's no reason to keep them.
266
+ * Errors are swallowed — pruning is best-effort and must never block startup.
267
+ */
268
+ function pruneOldDriverCaches(currentVersion) {
269
+ try {
270
+ for (const entry of fs_1.default.readdirSync(DRIVERS_CACHE_ROOT, { withFileTypes: true })) {
271
+ if (!entry.isDirectory())
272
+ continue;
273
+ if (entry.name === currentVersion)
274
+ continue;
275
+ if (entry.name.startsWith('.tmp-'))
276
+ continue; // active concurrent extraction
277
+ const stale = path_1.default.join(DRIVERS_CACHE_ROOT, entry.name);
278
+ try {
279
+ fs_1.default.rmSync(stale, { recursive: true, force: true });
280
+ (0, verbose_js_1.log)(`Pruned stale driver cache ${stale}`);
281
+ }
282
+ catch {
283
+ /* ok — another process may be using it */
284
+ }
285
+ }
286
+ }
287
+ catch {
288
+ /* ok */
289
+ }
290
+ }
291
+ async function acquireDriversLock(lockFile) {
292
+ const deadline = Date.now() + DRIVERS_LOCK_TIMEOUT_MS;
293
+ while (Date.now() < deadline) {
294
+ try {
295
+ const fd = fs_1.default.openSync(lockFile, 'wx');
296
+ fs_1.default.closeSync(fd);
297
+ return;
298
+ }
299
+ catch {
300
+ await (0, utils_js_1.sleep)(DRIVERS_LOCK_POLL_MS);
301
+ }
302
+ }
303
+ throw new Error(`Could not acquire drivers cache lock (${lockFile})`);
304
+ }
305
+ function downloadToFile(url, dest, maxRedirects = 5) {
306
+ return new Promise((resolve, reject) => {
307
+ const fetch = (u, remaining) => {
308
+ const req = https_1.default.get(u, (res) => {
309
+ const status = res.statusCode ?? 0;
310
+ if ((status === 301 ||
311
+ status === 302 ||
312
+ status === 303 ||
313
+ status === 307 ||
314
+ status === 308) &&
315
+ res.headers.location) {
316
+ res.resume();
317
+ if (remaining <= 0) {
318
+ reject(new Error(`Too many redirects fetching ${url}`));
319
+ return;
320
+ }
321
+ const next = new URL(res.headers.location, u).toString();
322
+ fetch(next, remaining - 1);
323
+ return;
324
+ }
325
+ if (status !== 200) {
326
+ res.resume();
327
+ reject(new Error(`HTTP ${status} for ${u}`));
328
+ return;
329
+ }
330
+ const file = fs_1.default.createWriteStream(dest);
331
+ res.pipe(file);
332
+ file.on('finish', () => file.close((err) => (err ? reject(err) : resolve())));
333
+ file.on('error', (err) => {
334
+ fs_1.default.rmSync(dest, { force: true });
335
+ reject(err);
336
+ });
337
+ });
338
+ req.on('error', reject);
339
+ };
340
+ fetch(url, maxRedirects);
341
+ });
186
342
  }
187
- const BUNDLED_DRIVERS_DIR = findBundledDriversDir();
188
343
  /**
189
344
  * Install the Conductor Android driver APKs on the device.
190
345
  * Reads pre-built APKs directly from the bundled drivers directory.
191
346
  */
192
347
  async function installDriver(deviceId) {
193
348
  (0, verbose_js_1.log)(`installDriver: installing Android driver on ${deviceId}`);
194
- const appApk = path_1.default.join(BUNDLED_DRIVERS_DIR, 'android', 'conductor-app.apk');
195
- const serverApk = path_1.default.join(BUNDLED_DRIVERS_DIR, 'android', 'conductor-server.apk');
349
+ const driversDir = await getDriversDir();
350
+ const appApk = path_1.default.join(driversDir, 'android', 'conductor-app.apk');
351
+ const serverApk = path_1.default.join(driversDir, 'android', 'conductor-server.apk');
196
352
  if (!fs_1.default.existsSync(appApk) || !fs_1.default.existsSync(serverApk)) {
197
- throw new Error(`Conductor driver APKs not found at ${path_1.default.join(BUNDLED_DRIVERS_DIR, 'android')}.\n` +
353
+ throw new Error(`Conductor driver APKs not found at ${path_1.default.join(driversDir, 'android')}.\n` +
198
354
  `Run 'make package-cli' from the repo root to build and bundle the drivers.`);
199
355
  }
200
356
  await spawnAndWait('adb', ['-s', deviceId, 'install', '-r', '-t', '-g', appApk]);
@@ -214,13 +370,14 @@ const IOS_DRIVER_CACHE = path_1.default.join(os_1.default.homedir(), '.conductor
214
370
  * dir. Re-extracts only when the bundled xctestrun has changed (tracked by mtime).
215
371
  */
216
372
  async function setupIOSDriverCache() {
217
- const bundledXctestrun = path_1.default.join(BUNDLED_DRIVERS_DIR, 'ios', 'conductor-driver-ios-config.xctestrun');
218
- const bundledDriverZip = path_1.default.join(BUNDLED_DRIVERS_DIR, 'ios', 'conductor-driver-ios.zip');
219
- const bundledRunnerZip = path_1.default.join(BUNDLED_DRIVERS_DIR, 'ios', 'conductor-driver-iosUITests-Runner.zip');
373
+ const driversDir = await getDriversDir();
374
+ const bundledXctestrun = path_1.default.join(driversDir, 'ios', 'conductor-driver-ios-config.xctestrun');
375
+ const bundledDriverZip = path_1.default.join(driversDir, 'ios', 'conductor-driver-ios.zip');
376
+ const bundledRunnerZip = path_1.default.join(driversDir, 'ios', 'conductor-driver-iosUITests-Runner.zip');
220
377
  if (!fs_1.default.existsSync(bundledXctestrun) ||
221
378
  !fs_1.default.existsSync(bundledDriverZip) ||
222
379
  !fs_1.default.existsSync(bundledRunnerZip)) {
223
- throw new Error(`Conductor iOS driver files not found at ${path_1.default.join(BUNDLED_DRIVERS_DIR, 'ios')}.\n` +
380
+ throw new Error(`Conductor iOS driver files not found at ${path_1.default.join(driversDir, 'ios')}.\n` +
224
381
  `Run 'make package-cli' from the repo root to build and bundle the drivers.`);
225
382
  }
226
383
  const versionFile = path_1.default.join(IOS_DRIVER_CACHE, '.version');
@@ -335,13 +492,14 @@ const TVOS_DRIVER_CACHE = path_1.default.join(os_1.default.homedir(), '.conducto
335
492
  * dir. Re-extracts only when the bundled xctestrun has changed (tracked by mtime).
336
493
  */
337
494
  async function setupTvOSDriverCache() {
338
- const bundledXctestrun = path_1.default.join(BUNDLED_DRIVERS_DIR, 'tvos', 'conductor-driver-tvos-config.xctestrun');
339
- const bundledDriverZip = path_1.default.join(BUNDLED_DRIVERS_DIR, 'tvos', 'conductor-driver-tvos.zip');
340
- const bundledRunnerZip = path_1.default.join(BUNDLED_DRIVERS_DIR, 'tvos', 'conductor-driver-tvosUITests-Runner.zip');
495
+ const driversDir = await getDriversDir();
496
+ const bundledXctestrun = path_1.default.join(driversDir, 'tvos', 'conductor-driver-tvos-config.xctestrun');
497
+ const bundledDriverZip = path_1.default.join(driversDir, 'tvos', 'conductor-driver-tvos.zip');
498
+ const bundledRunnerZip = path_1.default.join(driversDir, 'tvos', 'conductor-driver-tvosUITests-Runner.zip');
341
499
  if (!fs_1.default.existsSync(bundledXctestrun) ||
342
500
  !fs_1.default.existsSync(bundledDriverZip) ||
343
501
  !fs_1.default.existsSync(bundledRunnerZip)) {
344
- throw new Error(`Conductor tvOS driver files not found at ${path_1.default.join(BUNDLED_DRIVERS_DIR, 'tvos')}.\n` +
502
+ throw new Error(`Conductor tvOS driver files not found at ${path_1.default.join(driversDir, 'tvos')}.\n` +
345
503
  `Run 'make package-cli' from the repo root to build and bundle the drivers.`);
346
504
  }
347
505
  const versionFile = path_1.default.join(TVOS_DRIVER_CACHE, '.version');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@houwert/conductor",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "CLI tool for mobile app interactions — optimized for AI agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,7 +17,6 @@
17
17
  "main": "./dist/index.js",
18
18
  "files": [
19
19
  "dist/",
20
- "drivers/",
21
20
  "skills/",
22
21
  "proto/",
23
22
  ".claude-plugin/"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: conductor
3
- version: 0.8.0
3
+ version: 0.10.0
4
4
  description: "Token-efficient CLI for mobile UI testing (iOS simulator + Android emulator), designed for AI agents"
5
5
  metadata.openclaw:
6
6
  category: service
@@ -3,6 +3,6 @@ skills:
3
3
  path: conductor/SKILL.md
4
4
  description: "Token-efficient CLI for mobile UI testing, designed for AI agents"
5
5
  category: service
6
- version: 0.8.0
6
+ version: 0.10.0
7
7
  requires:
8
8
  bins: [conductor]
Binary file
@@ -1,126 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>__xctestrun_metadata__</key>
6
- <dict>
7
- <key>ContainerInfo</key>
8
- <dict>
9
- <key>ContainerName</key>
10
- <string>conductor-driver-ios</string>
11
- <key>SchemeName</key>
12
- <string>conductor-driver-ios</string>
13
- </dict>
14
- <key>FormatVersion</key>
15
- <integer>1</integer>
16
- </dict>
17
- <key>conductor-driver-iosUITests</key>
18
- <dict>
19
- <key>BlueprintName</key>
20
- <string>conductor-driver-iosUITests</string>
21
- <key>BlueprintProviderName</key>
22
- <string>conductor-driver-ios</string>
23
- <key>BlueprintProviderRelativePath</key>
24
- <string>conductor-driver-ios.xcodeproj</string>
25
- <key>BundleIdentifiersForCrashReportEmphasis</key>
26
- <array>
27
- <string>dev.houwert.ConductorDriverLib</string>
28
- <string>dev.houwert.conductor-driver-ios</string>
29
- <string>dev.houwert.conductor-driver-iosUITests</string>
30
- </array>
31
- <key>CommandLineArguments</key>
32
- <array/>
33
- <key>DefaultTestExecutionTimeAllowance</key>
34
- <integer>600</integer>
35
- <key>DependentProductPaths</key>
36
- <array>
37
- <string>__TESTROOT__/Debug-iphonesimulator/ConductorDriverLib.framework</string>
38
- <string>__TESTROOT__/Debug-iphonesimulator/conductor-driver-ios.app</string>
39
- <string>__TESTROOT__/Debug-iphonesimulator/conductor-driver-iosUITests-Runner.app</string>
40
- <string>__TESTROOT__/Debug-iphonesimulator/conductor-driver-iosUITests-Runner.app/PlugIns/conductor-driver-iosUITests.xctest</string>
41
- </array>
42
- <key>DiagnosticCollectionPolicy</key>
43
- <integer>1</integer>
44
- <key>EnvironmentVariables</key>
45
- <dict>
46
- <key>APP_DISTRIBUTOR_ID_OVERRIDE</key>
47
- <string>com.apple.AppStore</string>
48
- <key>OS_ACTIVITY_DT_MODE</key>
49
- <string>YES</string>
50
- <key>SQLITE_ENABLE_THREAD_ASSERTIONS</key>
51
- <string>1</string>
52
- <key>TERM</key>
53
- <string>dumb</string>
54
- </dict>
55
- <key>IsUITestBundle</key>
56
- <true/>
57
- <key>IsXCTRunnerHostedTestBundle</key>
58
- <true/>
59
- <key>PreferredScreenCaptureFormat</key>
60
- <string>screenRecording</string>
61
- <key>ProductModuleName</key>
62
- <string>conductor_driver_iosUITests</string>
63
- <key>RunOrder</key>
64
- <integer>0</integer>
65
- <key>SkipTestIdentifiers</key>
66
- <array>
67
- <string>ViewHierarchyHandlerTests</string>
68
- <string>ViewHierarchyHandlerTests/testViewHierarchyHandlerReturnsNonEmptyHierarchy()</string>
69
- </array>
70
- <key>SystemAttachmentLifetime</key>
71
- <string>deleteOnSuccess</string>
72
- <key>TestBundlePath</key>
73
- <string>__TESTHOST__/PlugIns/conductor-driver-iosUITests.xctest</string>
74
- <key>TestHostBundleIdentifier</key>
75
- <string>dev.houwert.conductor-driver-iosUITests.xctrunner</string>
76
- <key>TestHostPath</key>
77
- <string>__TESTROOT__/Debug-iphonesimulator/conductor-driver-iosUITests-Runner.app</string>
78
- <key>TestLanguage</key>
79
- <string></string>
80
- <key>TestRegion</key>
81
- <string></string>
82
- <key>TestTimeoutsEnabled</key>
83
- <false/>
84
- <key>TestingEnvironmentVariables</key>
85
- <dict>
86
- <key>DYLD_FRAMEWORK_PATH</key>
87
- <string>__TESTROOT__/Debug-iphonesimulator:__TESTROOT__/Debug-iphonesimulator/PackageFrameworks:__PLATFORMS__/iPhoneSimulator.platform/Developer/Library/Frameworks</string>
88
- <key>DYLD_LIBRARY_PATH</key>
89
- <string>__TESTROOT__/Debug-iphonesimulator:__PLATFORMS__/iPhoneSimulator.platform/Developer/usr/lib</string>
90
- <key>XCODE_SCHEME_NAME</key>
91
- <string>conductor-driver-ios</string>
92
- <key>__XCODE_BUILT_PRODUCTS_DIR_PATHS</key>
93
- <string>__TESTROOT__/Debug-iphonesimulator</string>
94
- <key>__XPC_DYLD_FRAMEWORK_PATH</key>
95
- <string>__TESTROOT__/Debug-iphonesimulator</string>
96
- <key>__XPC_DYLD_LIBRARY_PATH</key>
97
- <string>__TESTROOT__/Debug-iphonesimulator</string>
98
- </dict>
99
- <key>ToolchainsSettingValue</key>
100
- <array/>
101
- <key>UITargetAppCommandLineArguments</key>
102
- <array/>
103
- <key>UITargetAppEnvironmentVariables</key>
104
- <dict>
105
- <key>APP_DISTRIBUTOR_ID_OVERRIDE</key>
106
- <string>com.apple.AppStore</string>
107
- <key>DYLD_FRAMEWORK_PATH</key>
108
- <string>__TESTROOT__/Debug-iphonesimulator:__TESTROOT__/Debug-iphonesimulator/PackageFrameworks</string>
109
- <key>DYLD_LIBRARY_PATH</key>
110
- <string>__TESTROOT__/Debug-iphonesimulator</string>
111
- <key>XCODE_SCHEME_NAME</key>
112
- <string>conductor-driver-ios</string>
113
- <key>__XCODE_BUILT_PRODUCTS_DIR_PATHS</key>
114
- <string>__TESTROOT__/Debug-iphonesimulator</string>
115
- <key>__XPC_DYLD_FRAMEWORK_PATH</key>
116
- <string>__TESTROOT__/Debug-iphonesimulator</string>
117
- <key>__XPC_DYLD_LIBRARY_PATH</key>
118
- <string>__TESTROOT__/Debug-iphonesimulator</string>
119
- </dict>
120
- <key>UITargetAppPath</key>
121
- <string>__TESTROOT__/Debug-iphonesimulator/conductor-driver-ios.app</string>
122
- <key>UserAttachmentLifetime</key>
123
- <string>deleteOnSuccess</string>
124
- </dict>
125
- </dict>
126
- </plist>
@@ -1,121 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>__xctestrun_metadata__</key>
6
- <dict>
7
- <key>ContainerInfo</key>
8
- <dict>
9
- <key>ContainerName</key>
10
- <string>conductor-driver-ios</string>
11
- <key>SchemeName</key>
12
- <string>conductor-driver-tvos</string>
13
- </dict>
14
- <key>FormatVersion</key>
15
- <integer>1</integer>
16
- </dict>
17
- <key>conductor-driver-tvosUITests</key>
18
- <dict>
19
- <key>BlueprintName</key>
20
- <string>conductor-driver-tvosUITests</string>
21
- <key>BlueprintProviderName</key>
22
- <string>conductor-driver-ios</string>
23
- <key>BlueprintProviderRelativePath</key>
24
- <string>conductor-driver-ios.xcodeproj</string>
25
- <key>BundleIdentifiersForCrashReportEmphasis</key>
26
- <array>
27
- <string>dev.houwert.ConductorDriverLib</string>
28
- <string>dev.houwert.conductor-driver-tvos</string>
29
- <string>dev.houwert.conductor-driver-tvosUITests</string>
30
- </array>
31
- <key>CommandLineArguments</key>
32
- <array/>
33
- <key>DefaultTestExecutionTimeAllowance</key>
34
- <integer>600</integer>
35
- <key>DependentProductPaths</key>
36
- <array>
37
- <string>__TESTROOT__/Debug-appletvsimulator/ConductorDriverLib.framework</string>
38
- <string>__TESTROOT__/Debug-appletvsimulator/conductor-driver-tvos.app</string>
39
- <string>__TESTROOT__/Debug-appletvsimulator/conductor-driver-tvosUITests-Runner.app</string>
40
- <string>__TESTROOT__/Debug-appletvsimulator/conductor-driver-tvosUITests-Runner.app/PlugIns/conductor-driver-tvosUITests.xctest</string>
41
- </array>
42
- <key>DiagnosticCollectionPolicy</key>
43
- <integer>1</integer>
44
- <key>EnvironmentVariables</key>
45
- <dict>
46
- <key>APP_DISTRIBUTOR_ID_OVERRIDE</key>
47
- <string>com.apple.AppStore</string>
48
- <key>OS_ACTIVITY_DT_MODE</key>
49
- <string>YES</string>
50
- <key>SQLITE_ENABLE_THREAD_ASSERTIONS</key>
51
- <string>1</string>
52
- <key>TERM</key>
53
- <string>dumb</string>
54
- </dict>
55
- <key>IsUITestBundle</key>
56
- <true/>
57
- <key>IsXCTRunnerHostedTestBundle</key>
58
- <true/>
59
- <key>PreferredScreenCaptureFormat</key>
60
- <string>screenRecording</string>
61
- <key>ProductModuleName</key>
62
- <string>conductor_driver_tvosUITests</string>
63
- <key>RunOrder</key>
64
- <integer>0</integer>
65
- <key>SystemAttachmentLifetime</key>
66
- <string>deleteOnSuccess</string>
67
- <key>TestBundlePath</key>
68
- <string>__TESTHOST__/PlugIns/conductor-driver-tvosUITests.xctest</string>
69
- <key>TestHostBundleIdentifier</key>
70
- <string>dev.houwert.conductor-driver-tvosUITests.xctrunner</string>
71
- <key>TestHostPath</key>
72
- <string>__TESTROOT__/Debug-appletvsimulator/conductor-driver-tvosUITests-Runner.app</string>
73
- <key>TestLanguage</key>
74
- <string></string>
75
- <key>TestRegion</key>
76
- <string></string>
77
- <key>TestTimeoutsEnabled</key>
78
- <false/>
79
- <key>TestingEnvironmentVariables</key>
80
- <dict>
81
- <key>DYLD_FRAMEWORK_PATH</key>
82
- <string>__TESTROOT__/Debug-appletvsimulator:__TESTROOT__/Debug-appletvsimulator/PackageFrameworks:__PLATFORMS__/AppleTVSimulator.platform/Developer/Library/Frameworks</string>
83
- <key>DYLD_LIBRARY_PATH</key>
84
- <string>__TESTROOT__/Debug-appletvsimulator:__PLATFORMS__/AppleTVSimulator.platform/Developer/usr/lib</string>
85
- <key>XCODE_SCHEME_NAME</key>
86
- <string>conductor-driver-tvos</string>
87
- <key>__XCODE_BUILT_PRODUCTS_DIR_PATHS</key>
88
- <string>__TESTROOT__/Debug-appletvsimulator</string>
89
- <key>__XPC_DYLD_FRAMEWORK_PATH</key>
90
- <string>__TESTROOT__/Debug-appletvsimulator</string>
91
- <key>__XPC_DYLD_LIBRARY_PATH</key>
92
- <string>__TESTROOT__/Debug-appletvsimulator</string>
93
- </dict>
94
- <key>ToolchainsSettingValue</key>
95
- <array/>
96
- <key>UITargetAppCommandLineArguments</key>
97
- <array/>
98
- <key>UITargetAppEnvironmentVariables</key>
99
- <dict>
100
- <key>APP_DISTRIBUTOR_ID_OVERRIDE</key>
101
- <string>com.apple.AppStore</string>
102
- <key>DYLD_FRAMEWORK_PATH</key>
103
- <string>__TESTROOT__/Debug-appletvsimulator:__TESTROOT__/Debug-appletvsimulator/PackageFrameworks</string>
104
- <key>DYLD_LIBRARY_PATH</key>
105
- <string>__TESTROOT__/Debug-appletvsimulator</string>
106
- <key>XCODE_SCHEME_NAME</key>
107
- <string>conductor-driver-tvos</string>
108
- <key>__XCODE_BUILT_PRODUCTS_DIR_PATHS</key>
109
- <string>__TESTROOT__/Debug-appletvsimulator</string>
110
- <key>__XPC_DYLD_FRAMEWORK_PATH</key>
111
- <string>__TESTROOT__/Debug-appletvsimulator</string>
112
- <key>__XPC_DYLD_LIBRARY_PATH</key>
113
- <string>__TESTROOT__/Debug-appletvsimulator</string>
114
- </dict>
115
- <key>UITargetAppPath</key>
116
- <string>__TESTROOT__/Debug-appletvsimulator/conductor-driver-tvos.app</string>
117
- <key>UserAttachmentLifetime</key>
118
- <string>deleteOnSuccess</string>
119
- </dict>
120
- </dict>
121
- </plist>