stim 1.10.1 → 1.12.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/dist/{build-progress-BXx-ZBe4.mjs → activity-CCZJs__P.mjs} +9 -182
- package/dist/{android-787HhP5w.mjs → android-75Sk2rIR.mjs} +81 -19
- package/dist/{android-Bu4mbDzc.mjs → android-B7X-8H7h.mjs} +426 -106
- package/dist/{android-DPov-fv2.mjs → android-BQiKJYK0.mjs} +1 -1
- package/dist/{android-cas-CITmIeWY.mjs → android-cas-DzLPXiEn.mjs} +7 -7
- package/dist/{app-install-Cfmqr3TQ.mjs → app-install-CsZi0SAT.mjs} +1 -1
- package/dist/{workspaces-wrH6dXfu.mjs → budget-DbzW5VTD.mjs} +651 -32
- package/dist/{dev-client-DExzPiOa.mjs → build-plan-CqntbR7b.mjs} +514 -38
- package/dist/build-progress-h60GPV27.mjs +179 -0
- package/dist/{cache-manifest-Pubfp8wV.mjs → cache-manifest-DWPF4RKJ.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +16 -16
- package/dist/collector-run.mjs +4 -4
- package/dist/{command-output-D5z2_bcF.mjs → command-output-BWCj5Vh-.mjs} +1 -1
- package/dist/{config-BEq0Qw_a.mjs → config-0jCcMM0E.mjs} +10 -1
- package/dist/{dependency-state-r9UesA9a.mjs → dependency-state-DNN0yfx6.mjs} +1 -1
- package/dist/{deps-DP4eWqea.mjs → deps-CO-_7UOm.mjs} +2 -2
- package/dist/{device-Czh5kO8A.mjs → device-9r9xRYDa.mjs} +49 -11
- package/dist/{device-lease-CbEaIk7b.mjs → device-lease-B9LAXIUH.mjs} +55 -55
- package/dist/{device-pool-BBWLAr55.mjs → device-pool-BoezJd-c.mjs} +4 -4
- package/dist/{device-remote-powUHdbK.mjs → device-remote-C0_o-tJH.mjs} +254 -579
- package/dist/{doctor-CmqK1LcQ.mjs → doctor-LfDlbR-N.mjs} +20 -19
- package/dist/{error-diagnostics-xxWKNO3-.mjs → error-diagnostics-CCxjn31V.mjs} +7 -7
- package/dist/{gc-zCDpmdHU.mjs → gc-C4nQFcTX.mjs} +220 -282
- package/dist/{guide-DwmaD_Wa.mjs → guide-BPBlh9ML.mjs} +512 -73
- package/dist/{guide-status-CWvti2Lg.mjs → guide-status-i9ogHt4v.mjs} +2 -2
- package/dist/{idle--jn7pBNe.mjs → idle-S3tFZ53_.mjs} +7 -6
- package/dist/{in-use-CNIWU-r-.mjs → in-use-D9XYEgFD.mjs} +7 -7
- package/dist/{ios-CbdqTqOc.mjs → ios-CDzWL1mj.mjs} +302 -88
- package/dist/{ios-COGcGEcN.mjs → ios-CZWOHTTc.mjs} +24 -19
- package/dist/{ios-device-DNjPXBnb.mjs → ios-device-D9cLxVr5.mjs} +1 -1
- package/dist/{launch-verify-BhgkYAws.mjs → launch-verify-B2oR_kFN.mjs} +2 -2
- package/dist/logs-SzuYudOj.mjs +485 -0
- package/dist/merge-state-ytFQCeh4.mjs +262 -0
- package/dist/{metro-BWLOJ_Wr.mjs → metro-Dzo30hvJ.mjs} +1 -1
- package/dist/{named-ports-DiTfSz6p.mjs → named-ports-Dn1o61D9.mjs} +3 -3
- package/dist/{ownership-BfPNRf3-.mjs → ownership-B8d4kXBx.mjs} +49 -16
- package/dist/{ownership-D2xbLVoz.mjs → ownership-Dqnrjrio.mjs} +2 -2
- package/dist/{ports-CLSSFOuz.mjs → ports-Dp_QTwTC.mjs} +3 -3
- package/dist/{project-BXZzOABt.mjs → project-B8rbutVC.mjs} +4 -72
- package/dist/{reload-CymyF6Kk.mjs → reload-nocmx8KB.mjs} +9 -9
- package/dist/remote-cache-BRsRZru5.mjs +526 -0
- package/dist/{server-bare-DVbb7kXH.mjs → server-bare-Gn3ssSdK.mjs} +1 -1
- package/dist/{server-expo-BvOCeakp.mjs → server-expo-CeT1nIIk.mjs} +2 -2
- package/dist/server-expo-eWi9Coof.mjs +2 -0
- package/dist/{settings-DOugPlPz.mjs → settings-BlyDn2Oz.mjs} +14 -5
- package/dist/{settings-EWYNwe72.mjs → settings-bE-Gu3Ti.mjs} +23 -11
- package/dist/settings.schema.json +73 -1
- package/dist/{simslim-DZUxzsjq.mjs → simslim-COtEEP7x.mjs} +152 -96
- package/dist/{slot-launch-Dk4oTREM.mjs → slot-launch-DIACGEfH.mjs} +4 -4
- package/dist/{spawn-claims-CUleC2cM.mjs → spawn-claims-PT8aQpCa.mjs} +25 -2
- package/dist/{start-qWapeB4W.mjs → start-BFstVBlx.mjs} +1 -1
- package/dist/{start-RbmFPeZ7.mjs → start-BboE1HIS.mjs} +108 -17
- package/dist/{state-WGdIbi_d.mjs → state-DcDgzfu3.mjs} +15 -3
- package/dist/{stats-BAgJaLA4.mjs → stats-D8rUTPHd.mjs} +1 -1
- package/dist/{stats-DBYJ5bxL.mjs → stats-DiCtmluY.mjs} +4 -4
- package/dist/{status-Dr4fRkym.mjs → status-BUASYyy_.mjs} +92 -33
- package/dist/{status-Zp8kvexe.mjs → status-DI9Tjo7T.mjs} +255 -38
- package/dist/stim-desktop-D0xhpZt8.mjs +29 -0
- package/dist/stop-BI7QY76M.mjs +3 -0
- package/dist/{stop-DcEv5sk-.mjs → stop-Bn6v-GvS.mjs} +205 -37
- package/dist/supervisor-run.mjs +11 -11
- package/dist/{workspace-process-lock-BXA96myD.mjs → workspace-process-lock-BvvJTfo_.mjs} +10 -5
- package/dist/{worktree-DEG2o9F8.mjs → worktree-B5sTRskL.mjs} +1 -1
- package/dist/{worktree-Bd4dRvx7.mjs → worktree-ChDL5fO1.mjs} +17 -16
- package/dist/{worktree-BlizKDpZ.mjs → worktree-DeBQSVtR.mjs} +3 -1
- package/dist/{xcode-B2tBkf0m.mjs → xcode-BzplpQzc.mjs} +7 -7
- package/package.json +5 -5
- package/dist/budget-nDCEwtJv.mjs +0 -620
- package/dist/logs-MARIy6m9.mjs +0 -209
- package/dist/server-expo-DBVTdult.mjs +0 -2
- package/dist/stop-DI4BG4Os.mjs +0 -3
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { O as process_identity_exports } from "./config-0jCcMM0E.mjs";
|
|
2
2
|
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-CbEaIk7b.mjs";
|
|
3
|
+
import { j as workspaceLogsDir, m as readWorkspaceState } from "./metro-Dzo30hvJ.mjs";
|
|
4
|
+
import { i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-B9LAXIUH.mjs";
|
|
6
5
|
import { closeSync, fstatSync, openSync, readFileSync, readSync, readdirSync } from "node:fs";
|
|
7
|
-
import { BUILD_PHASES } from "@stim-cli/core/state";
|
|
8
6
|
import { basename, join, resolve } from "node:path";
|
|
9
7
|
import { homedir } from "node:os";
|
|
10
8
|
//#region src/devices/activity.ts
|
|
@@ -68,6 +66,9 @@ function parseAgentDeviceRecord(kind, path, raw) {
|
|
|
68
66
|
path,
|
|
69
67
|
kind,
|
|
70
68
|
deviceId,
|
|
69
|
+
session: kind === "claim" && typeof entry?.session === "string" && entry.session ? entry.session : null,
|
|
70
|
+
workspace: kind === "claim" && typeof entry?.workspace === "string" && entry.workspace ? entry.workspace : null,
|
|
71
|
+
deviceName: kind === "claim" && typeof device?.name === "string" ? device.name : null,
|
|
71
72
|
readable: Boolean(entry && deviceId),
|
|
72
73
|
owner: entry ? field(entry, "ownerPid", "ownerStartTime") : null,
|
|
73
74
|
runner: entry && kind === "runner-lease" ? field(entry, "runnerPid", "runnerStartTime") : null,
|
|
@@ -298,7 +299,7 @@ function createActivityReader({ now = Date.now(), home = homedir(), startOf = pr
|
|
|
298
299
|
basis: "metro-bundle",
|
|
299
300
|
at: bundleAt
|
|
300
301
|
});
|
|
301
|
-
const usedAt = Date.parse(String(readWorkspaceState
|
|
302
|
+
const usedAt = Date.parse(String(readWorkspaceState(target.workspace)?.lastUsedAt ?? ""));
|
|
302
303
|
if (Number.isFinite(usedAt)) evidence.recency.push({
|
|
303
304
|
basis: "workspace-use",
|
|
304
305
|
at: usedAt
|
|
@@ -309,7 +310,7 @@ function createActivityReader({ now = Date.now(), home = homedir(), startOf = pr
|
|
|
309
310
|
}
|
|
310
311
|
function workspaceActivity(workspace, now = Date.now()) {
|
|
311
312
|
const dir = workspaceLogsDir(workspace);
|
|
312
|
-
const state = readWorkspaceState
|
|
313
|
+
const state = readWorkspaceState(workspace);
|
|
313
314
|
const recency = [];
|
|
314
315
|
const deviceAt = latestRecordAt(tailLines(join(dir, "device.ndjson")) ?? [], (record) => record.src === "device" && isDeviceRecord(record));
|
|
315
316
|
if (deviceAt !== null) recency.push({
|
|
@@ -335,178 +336,4 @@ function workspaceActivity(workspace, now = Date.now()) {
|
|
|
335
336
|
}, now);
|
|
336
337
|
}
|
|
337
338
|
//#endregion
|
|
338
|
-
|
|
339
|
-
const ACTIVE_BUILD_KEY = "activeBuild";
|
|
340
|
-
const NO_BUILD_PROGRESS = {
|
|
341
|
-
step: () => {},
|
|
342
|
-
durations: () => ({}),
|
|
343
|
-
clear: () => {}
|
|
344
|
-
};
|
|
345
|
-
const COLD_PHASES = [
|
|
346
|
-
"prebuild",
|
|
347
|
-
"pods",
|
|
348
|
-
"compile"
|
|
349
|
-
];
|
|
350
|
-
const DEVICE_PHASES = ["install", "launch"];
|
|
351
|
-
function startBuildProgress({ root, platform, slot, claim, now = Date.now, note = () => {} }) {
|
|
352
|
-
const startedAt = new Date(now()).toISOString();
|
|
353
|
-
const record = {
|
|
354
|
-
platform,
|
|
355
|
-
slot,
|
|
356
|
-
startedAt,
|
|
357
|
-
phase: "prepare",
|
|
358
|
-
phaseStartedAt: startedAt,
|
|
359
|
-
phases: [{
|
|
360
|
-
phase: "prepare",
|
|
361
|
-
startedAt
|
|
362
|
-
}],
|
|
363
|
-
claim: {
|
|
364
|
-
root: claim.root,
|
|
365
|
-
path: claim.path,
|
|
366
|
-
claimId: claim.claimId,
|
|
367
|
-
pid: claim.owner.pid
|
|
368
|
-
}
|
|
369
|
-
};
|
|
370
|
-
let warned = false;
|
|
371
|
-
const guard = (fn) => {
|
|
372
|
-
try {
|
|
373
|
-
fn();
|
|
374
|
-
} catch (error) {
|
|
375
|
-
if (warned) return;
|
|
376
|
-
warned = true;
|
|
377
|
-
note(`Build progress could not be recorded in the workspace state: ${error?.message || error}`);
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
const write = () => guard(() => updateWorkspaceState(root, (state) => ({
|
|
381
|
-
...state,
|
|
382
|
-
[ACTIVE_BUILD_KEY]: record
|
|
383
|
-
})));
|
|
384
|
-
write();
|
|
385
|
-
return {
|
|
386
|
-
step(phase) {
|
|
387
|
-
if (phase === record.phase) return;
|
|
388
|
-
const at = new Date(now()).toISOString();
|
|
389
|
-
record.phase = phase;
|
|
390
|
-
record.phaseStartedAt = at;
|
|
391
|
-
record.phases.push({
|
|
392
|
-
phase,
|
|
393
|
-
startedAt: at
|
|
394
|
-
});
|
|
395
|
-
write();
|
|
396
|
-
},
|
|
397
|
-
durations() {
|
|
398
|
-
return phaseDurations(record.phases, now());
|
|
399
|
-
},
|
|
400
|
-
clear() {
|
|
401
|
-
guard(() => {
|
|
402
|
-
clearWorkspaceStateKey(root, ACTIVE_BUILD_KEY, (value) => parseActiveBuild(value)?.claim.claimId === record.claim.claimId);
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
function phaseDurations(phases, now) {
|
|
408
|
-
const out = {};
|
|
409
|
-
phases.forEach(({ phase, startedAt }, index) => {
|
|
410
|
-
const start = Date.parse(startedAt);
|
|
411
|
-
const next = phases[index + 1];
|
|
412
|
-
const end = next ? Date.parse(next.startedAt) : now;
|
|
413
|
-
if (!Number.isFinite(start) || !Number.isFinite(end)) return;
|
|
414
|
-
out[phase] = (out[phase] ?? 0) + Math.max(0, end - start);
|
|
415
|
-
});
|
|
416
|
-
return out;
|
|
417
|
-
}
|
|
418
|
-
function parseActiveBuild(value) {
|
|
419
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
420
|
-
const record = value;
|
|
421
|
-
const claim = record.claim;
|
|
422
|
-
if (record.platform !== "ios" && record.platform !== "android") return null;
|
|
423
|
-
if (!isPhase(record.phase)) return null;
|
|
424
|
-
if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
|
|
425
|
-
if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
|
|
426
|
-
const phases = Array.isArray(record.phases) ? record.phases.filter((entry) => isPhase(entry?.phase) && typeof entry?.startedAt === "string") : [];
|
|
427
|
-
return {
|
|
428
|
-
platform: record.platform,
|
|
429
|
-
slot: typeof record.slot === "string" ? record.slot : "default",
|
|
430
|
-
startedAt: record.startedAt,
|
|
431
|
-
phase: record.phase,
|
|
432
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
433
|
-
phases,
|
|
434
|
-
claim: {
|
|
435
|
-
root: claim.root,
|
|
436
|
-
path: typeof claim.path === "string" ? claim.path : "",
|
|
437
|
-
claimId: claim.claimId,
|
|
438
|
-
pid: typeof claim.pid === "number" ? claim.pid : 0
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
function isPhase(value) {
|
|
443
|
-
return BUILD_PHASES.includes(value);
|
|
444
|
-
}
|
|
445
|
-
function activeBuildState(claim, survey = (0, ownership_claim_exports.readClaimSet)(claim.root)) {
|
|
446
|
-
if (survey.live.some((holder) => holder.claimId === claim.claimId)) return "running";
|
|
447
|
-
if (survey.dead.some((holder) => holder.claimId === claim.claimId)) return "stale";
|
|
448
|
-
return survey.unresolved.length ? "unknown" : "stale";
|
|
449
|
-
}
|
|
450
|
-
function liveOutcome(record) {
|
|
451
|
-
const seen = new Set(record.phases.map((entry) => entry.phase));
|
|
452
|
-
if (COLD_PHASES.some((phase) => seen.has(phase))) return "cold";
|
|
453
|
-
if (DEVICE_PHASES.some((phase) => seen.has(phase))) return "hit";
|
|
454
|
-
return null;
|
|
455
|
-
}
|
|
456
|
-
function median(values) {
|
|
457
|
-
if (!values.length) return null;
|
|
458
|
-
const sorted = values.toSorted((a, b) => a - b);
|
|
459
|
-
const mid = Math.floor(sorted.length / 2);
|
|
460
|
-
return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
461
|
-
}
|
|
462
|
-
function estimateBuild(history, platform, known, phase) {
|
|
463
|
-
const lists = history?.[platform];
|
|
464
|
-
const outcome = known ?? latestOutcome(lists);
|
|
465
|
-
const samples = outcome && lists?.[outcome] || [];
|
|
466
|
-
const phaseSamples = samples.flatMap((sample) => phase in sample.phases ? [sample.phases[phase]] : []);
|
|
467
|
-
return {
|
|
468
|
-
outcome,
|
|
469
|
-
expectedMs: median(samples.map((sample) => sample.durationMs)),
|
|
470
|
-
expectedPhaseMs: median(phaseSamples),
|
|
471
|
-
basis: samples.length
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
function latestOutcome(lists) {
|
|
475
|
-
let latest = null;
|
|
476
|
-
for (const outcome of ["hit", "cold"]) {
|
|
477
|
-
const last = lists?.[outcome]?.at(-1);
|
|
478
|
-
const at = last ? Date.parse(last.at) : NaN;
|
|
479
|
-
if (Number.isFinite(at) && (!latest || at > latest.at)) latest = {
|
|
480
|
-
outcome,
|
|
481
|
-
at
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
return latest?.outcome ?? null;
|
|
485
|
-
}
|
|
486
|
-
function buildReport(record, { state, history }) {
|
|
487
|
-
return {
|
|
488
|
-
platform: record.platform,
|
|
489
|
-
slot: record.slot,
|
|
490
|
-
state,
|
|
491
|
-
phase: record.phase,
|
|
492
|
-
startedAt: record.startedAt,
|
|
493
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
494
|
-
...estimateBuild(history, record.platform, liveOutcome(record), record.phase)
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
function remainingText(remainingMs) {
|
|
498
|
-
return remainingMs < 6e4 ? "under a minute left" : `about ${Math.ceil(remainingMs / 6e4)} min left`;
|
|
499
|
-
}
|
|
500
|
-
function buildStatusLine(report, now) {
|
|
501
|
-
const slot = report.slot === "default" ? "" : ` [${report.slot}]`;
|
|
502
|
-
if (report.state === "stale") return `build: stale ${report.platform}${slot} record from ${report.startedAt} (its run is gone; the next run replaces it)`;
|
|
503
|
-
const elapsedMs = Math.max(0, now - Date.parse(report.startedAt));
|
|
504
|
-
const head = `build: ${report.platform}${slot} ${report.phase}, ${formatElapsed(elapsedMs)} elapsed`;
|
|
505
|
-
if (report.state === "unknown") return `${head} (its native-run claim cannot be resolved, so it may not be running)`;
|
|
506
|
-
if (report.expectedMs === null) return head;
|
|
507
|
-
const basis = `median of ${plural(report.basis, `${report.outcome} run`)}`;
|
|
508
|
-
const remainingMs = report.expectedMs - elapsedMs;
|
|
509
|
-
return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
|
|
510
|
-
}
|
|
511
|
-
//#endregion
|
|
512
|
-
export { buildStatusLine as a, createActivityReader as c, buildReport as i, idleForMs as l, NO_BUILD_PROGRESS as n, parseActiveBuild as o, activeBuildState as r, startBuildProgress as s, ACTIVE_BUILD_KEY as t, workspaceActivity as u };
|
|
339
|
+
export { workspaceActivity as a, readAgentDeviceRecords as i, createActivityReader as n, idleForMs as r, agentDeviceLiveness as t };
|
|
@@ -1,12 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as loadConfig$1, d as getConfigDir } from "./config-0jCcMM0E.mjs";
|
|
2
2
|
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
3
|
-
import { P as withDirLock, c as signalProcessTree, i as pidExists } from "./metro-
|
|
4
|
-
import {
|
|
3
|
+
import { P as withDirLock, c as signalProcessTree, i as pidExists } from "./metro-Dzo30hvJ.mjs";
|
|
4
|
+
import { n as stimDesktopInstalled, t as settingDefault } from "./stim-desktop-D0xhpZt8.mjs";
|
|
5
|
+
import { c as androidDataPartitionSizeBytes } from "./settings-BlyDn2Oz.mjs";
|
|
5
6
|
import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
6
7
|
import { existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, renameSync as renameSync$1, rmSync as rmSync$1, statSync as statSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
7
8
|
import { dirname, isAbsolute, join, resolve } from "path";
|
|
8
|
-
import { createdDevicesFile, createdDevicesLock, readCreatedDevices, readCreatedDevices as readCreatedDevices$1 } from "@stim-cli/core/state";
|
|
9
|
+
import { ANDROID_EMULATOR_APPS, createdDevicesFile, createdDevicesLock, readCreatedDevices, readCreatedDevices as readCreatedDevices$1, settingDefinition } from "@stim-cli/core/state";
|
|
9
10
|
import { homedir, tmpdir } from "os";
|
|
11
|
+
//#region src/devices/android-emulator-viewer.ts
|
|
12
|
+
function configuredAndroidEmulatorApp(platform = process.platform) {
|
|
13
|
+
const value = loadConfig$1()?.androidEmulatorApp ?? settingDefault(settingDefinition("androidEmulatorApp"), () => stimDesktopInstalled(platform)).value;
|
|
14
|
+
if (ANDROID_EMULATOR_APPS.includes(value)) return value;
|
|
15
|
+
const error = /* @__PURE__ */ new Error("Invalid androidEmulatorApp in machine config. Use \"emulator\" or \"stim-desktop\".");
|
|
16
|
+
Object.assign(error, { code: "STIM_BAD_ARG" });
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
function openEmulatorInStimDesktop(serial) {
|
|
20
|
+
getExecutor().runFileQuiet("open", [
|
|
21
|
+
"-g",
|
|
22
|
+
"-a",
|
|
23
|
+
"Stim",
|
|
24
|
+
`stim-desktop://open?serial=${serial}`
|
|
25
|
+
], {
|
|
26
|
+
timeoutMs: 5e3,
|
|
27
|
+
killSignal: "SIGKILL"
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
10
31
|
//#region src/devices/created-devices.ts
|
|
11
32
|
function update(platform, change) {
|
|
12
33
|
const dir = getConfigDir();
|
|
@@ -70,7 +91,7 @@ const ANDROID_ABIS = /* @__PURE__ */ new Set([
|
|
|
70
91
|
"x86",
|
|
71
92
|
"x86_64"
|
|
72
93
|
]);
|
|
73
|
-
const
|
|
94
|
+
const DEFAULT_AVD_DEVICE_PROFILE = String(settingDefinition("android.deviceProfile")?.default);
|
|
74
95
|
function androidHome() {
|
|
75
96
|
const configured = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT;
|
|
76
97
|
if (configured) return configured;
|
|
@@ -184,7 +205,19 @@ function pickDefaultSystemImage(images, { systemImage, hostArch } = {}) {
|
|
|
184
205
|
if (matching.length === 0) return null;
|
|
185
206
|
return matching.toSorted((a, b) => pageSizeRank(a) - pageSizeRank(b) || b.api - a.api || (b.tag === "google_apis" ? 1 : 0) - (a.tag === "google_apis" ? 1 : 0))[0] ?? null;
|
|
186
207
|
}
|
|
187
|
-
|
|
208
|
+
const FOLD_FEATURE_PROFILES = /* @__PURE__ */ new Set(["pixel_fold", "resizable"]);
|
|
209
|
+
function profileNeedsFoldFeature(profile) {
|
|
210
|
+
return typeof profile === "string" && FOLD_FEATURE_PROFILES.has(profile);
|
|
211
|
+
}
|
|
212
|
+
function systemImageSupportsFold(pkg, home = androidHome()) {
|
|
213
|
+
try {
|
|
214
|
+
const ini = readFileSync$1(join(home, ...pkg.split(";"), "advancedFeatures.ini"), "utf8");
|
|
215
|
+
return /^\s*SupportPixelFold\s*=\s*on\s*$/im.test(ini);
|
|
216
|
+
} catch {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async function createOwnedAvd(label, { systemImage, deviceProfile = DEFAULT_AVD_DEVICE_PROFILE, spawn = (...args) => getExecutor().spawn(...args) } = {}) {
|
|
188
221
|
const pick = pickDefaultSystemImage(listInstalledSystemImages(), { systemImage });
|
|
189
222
|
if (!pick) {
|
|
190
223
|
const arch = hostSystemImageArch();
|
|
@@ -201,7 +234,7 @@ async function createOwnedAvd(label, { systemImage, spawn = (...args) => getExec
|
|
|
201
234
|
"-k",
|
|
202
235
|
pick.pkg,
|
|
203
236
|
"--device",
|
|
204
|
-
|
|
237
|
+
deviceProfile
|
|
205
238
|
];
|
|
206
239
|
const child = spawn(tool, args, {
|
|
207
240
|
detached: true,
|
|
@@ -229,17 +262,24 @@ async function createOwnedAvd(label, { systemImage, spawn = (...args) => getExec
|
|
|
229
262
|
if (result.code !== 0) throw new Error(`Command failed: ${tool} ${args.join(" ")} (${result.signal ?? result.code})\n${stderr.trim()}`);
|
|
230
263
|
return {
|
|
231
264
|
avdName,
|
|
232
|
-
systemImage: pick.pkg
|
|
265
|
+
systemImage: pick.pkg,
|
|
266
|
+
deviceProfile
|
|
233
267
|
};
|
|
234
268
|
}
|
|
235
269
|
function parseAvdSystemImage(configIni) {
|
|
270
|
+
const dir = avdIniValue(configIni, "image.sysdir.1")?.replace(/[\\/]+$/, "");
|
|
271
|
+
if (!dir) return null;
|
|
272
|
+
return dir.split(/[\\/]/).join(";");
|
|
273
|
+
}
|
|
274
|
+
function parseAvdDeviceProfile(configIni) {
|
|
275
|
+
return avdIniValue(configIni, "hw.device.name") || null;
|
|
276
|
+
}
|
|
277
|
+
function avdIniValue(configIni, key) {
|
|
236
278
|
for (const line of String(configIni).split(/\r?\n/)) {
|
|
237
279
|
const separator = line.indexOf("=");
|
|
238
280
|
if (separator < 0) continue;
|
|
239
|
-
if (line.slice(0, separator).trim() !==
|
|
240
|
-
|
|
241
|
-
if (!dir) return null;
|
|
242
|
-
return dir.split(/[\\/]/).join(";");
|
|
281
|
+
if (line.slice(0, separator).trim() !== key) continue;
|
|
282
|
+
return line.slice(separator + 1).trim();
|
|
243
283
|
}
|
|
244
284
|
return null;
|
|
245
285
|
}
|
|
@@ -252,6 +292,18 @@ function ownedAvdSystemImage(avdName, { avdDirectory = ownedAvdDirectory, readFi
|
|
|
252
292
|
return null;
|
|
253
293
|
}
|
|
254
294
|
}
|
|
295
|
+
function ownedAvdDeviceProfile(avdName) {
|
|
296
|
+
const configIni = avdConfigIni(avdName);
|
|
297
|
+
return configIni === null ? null : parseAvdDeviceProfile(configIni);
|
|
298
|
+
}
|
|
299
|
+
const AVDMANAGER_LIST_TIMEOUT_MS = 6e4;
|
|
300
|
+
function listAvdDeviceProfiles() {
|
|
301
|
+
return parseAvdList(getExecutor().runFile(androidToolPath("avdmanager"), [
|
|
302
|
+
"list",
|
|
303
|
+
"device",
|
|
304
|
+
"-c"
|
|
305
|
+
], { timeoutMs: AVDMANAGER_LIST_TIMEOUT_MS }));
|
|
306
|
+
}
|
|
255
307
|
function sanitizeAvdLabel(label) {
|
|
256
308
|
return String(label).replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
257
309
|
}
|
|
@@ -454,8 +506,9 @@ function nextConsolePort(claimedPorts) {
|
|
|
454
506
|
if (claimedPorts.length === 0) return 5554;
|
|
455
507
|
return Math.max(...claimedPorts) + 2;
|
|
456
508
|
}
|
|
457
|
-
function headlessEmulatorArgs(env = process.env, platform = process.platform) {
|
|
509
|
+
function headlessEmulatorArgs(env = process.env, platform = process.platform, app = "emulator") {
|
|
458
510
|
const args = [];
|
|
511
|
+
if (platform === "darwin" && app === "stim-desktop") args.push("-no-window", "-gpu", "host");
|
|
459
512
|
if (platform === "linux" && !env.DISPLAY && !env.WAYLAND_DISPLAY) args.push("-no-window", "-noaudio", "-no-boot-anim", "-gpu", "swiftshader_indirect", "-no-snapshot-save", "-no-snapshot-load");
|
|
460
513
|
return args;
|
|
461
514
|
}
|
|
@@ -631,10 +684,15 @@ function configureNewOwnedAvd(avdName, { dataPartitionSizeGb, avdConfig = {} },
|
|
|
631
684
|
for (const [key, value] of Object.entries(expected)) if (!verified.split(/\r?\n/).includes(`${key}=${value}`)) throw new Error(`Could not verify ${key} in ${configPath}.`);
|
|
632
685
|
return configPath;
|
|
633
686
|
}
|
|
634
|
-
|
|
687
|
+
/**
|
|
688
|
+
* Values every AVD Stim creates gets unless `android.avdConfig` or `android.avdConfigFile` sets the key. The
|
|
689
|
+
* emulator drops gRPC `sendKey` events on an AVD without a hardware keyboard.
|
|
690
|
+
*/
|
|
691
|
+
const OWNED_AVD_CONFIG_DEFAULTS = Object.freeze({ "hw.keyboard": "yes" });
|
|
692
|
+
function avdPoolConfiguration(dataPartitionSizeGb, avdConfig, deviceProfile = DEFAULT_AVD_DEVICE_PROFILE) {
|
|
635
693
|
return JSON.stringify(Object.entries({
|
|
636
694
|
...avdConfig,
|
|
637
|
-
"hw.device.name":
|
|
695
|
+
"hw.device.name": deviceProfile,
|
|
638
696
|
"disk.dataPartition.size": String(androidDataPartitionSizeBytes(dataPartitionSizeGb))
|
|
639
697
|
}).toSorted(([a], [b]) => a.localeCompare(b)));
|
|
640
698
|
}
|
|
@@ -751,7 +809,9 @@ function suppressEmulatorCrashConsent({ platform = process.platform, version = e
|
|
|
751
809
|
return [];
|
|
752
810
|
}
|
|
753
811
|
function bootAndroidEmulator(avdName, consolePort, { logFile, platform = process.platform } = {}) {
|
|
754
|
-
const
|
|
812
|
+
const exec = getExecutor();
|
|
813
|
+
const app = configuredAndroidEmulatorApp(platform);
|
|
814
|
+
const child = exec.spawn(androidToolPath("emulator"), [
|
|
755
815
|
"-avd",
|
|
756
816
|
avdName,
|
|
757
817
|
"-port",
|
|
@@ -759,7 +819,7 @@ function bootAndroidEmulator(avdName, consolePort, { logFile, platform = process
|
|
|
759
819
|
"-grpc",
|
|
760
820
|
String(consolePort + 3e3),
|
|
761
821
|
"-grpc-use-token",
|
|
762
|
-
...headlessEmulatorArgs(),
|
|
822
|
+
...headlessEmulatorArgs(process.env, platform, app),
|
|
763
823
|
...suppressEmulatorCrashConsent({ platform })
|
|
764
824
|
], {
|
|
765
825
|
cwd: androidToolCwd(platform),
|
|
@@ -767,7 +827,9 @@ function bootAndroidEmulator(avdName, consolePort, { logFile, platform = process
|
|
|
767
827
|
stdio: emulatorStdio(logFile)
|
|
768
828
|
});
|
|
769
829
|
child?.unref?.();
|
|
770
|
-
|
|
830
|
+
const pid = child?.pid ?? null;
|
|
831
|
+
if (pid !== null && platform === "darwin" && app === "stim-desktop") openEmulatorInStimDesktop(`emulator-${consolePort}`);
|
|
832
|
+
return pid;
|
|
771
833
|
}
|
|
772
834
|
function emulatorStdio(logFile) {
|
|
773
835
|
if (!logFile) return "ignore";
|
|
@@ -997,4 +1059,4 @@ function ownedAvdSerialResolver({ timeoutMs } = {}) {
|
|
|
997
1059
|
};
|
|
998
1060
|
}
|
|
999
1061
|
//#endregion
|
|
1000
|
-
export {
|
|
1062
|
+
export { forgetCreatedDevice as $, listOrphanedAvdDirectories as A, pickDefaultSystemImage as B, getAvdNameForSerial as C, listAvdDeviceProfiles as D, listAdbDevices as E, ownedAvdMatchesConfiguration as F, resolvePhysicalDevice as G, profileNeedsFoldFeature as H, ownedAvdName as I, systemImageSupportsFold as J, shutdownAndroidEmulator as K, ownedAvdSerialResolver as L, nextConsolePort as M, ownedAvdDeviceProfile as N, listAvds as O, ownedAvdDirectory as P, isStimOwnedSim as Q, ownedAvdSystemImage as R, findBuildTool as S, isStimOwnedAvdName as T, resetAdoptedAvd as U, probeEmulatorSerial as V, resolveOwnedAvdSerial as W, waitForBoot as X, waitForAndroidEmulatorShutdown as Y, wipeAvdUserData as Z, createOwnedAvd as _, androidHome as a, emulatorFailureRemedy as b, androidSystemImageAbi as c, assertOwnedAvdStopped as d, recordCreatedDevice as et, avdPathExists as f, configureNewOwnedAvd as g, bootAndroidEmulator as h, androidDeviceAbi as i, memoizeEmulatorProbe as j, listInstalledSystemImages as k, androidToolCwd as l, avdStorageRoots as m, OWNED_AVD_CONFIG_DEFAULTS as n, androidPoolCandidates as o, avdPoolConfiguration as p, sleepSync as q, androidBuildToolName as r, androidPoolNoCandidatesRefusal as s, DEFAULT_AVD_DEVICE_PROFILE as t, configuredAndroidEmulatorApp as tt, androidToolPath as u, deleteAvd as v, hostSystemImageArch as w, extractEmulatorFailure as x, emulatorDiskSpaceRemedy as y, physicalDeviceModel as z };
|