stim 1.8.0 → 1.9.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/README.md +23 -155
- package/dist/{android-BRgBYzU0.mjs → android-BPGizezh.mjs} +112 -135
- package/dist/{android-DeYdjjBP.mjs → android-DEgo4oCo.mjs} +2 -2
- package/dist/{android-DWssqHQ8.mjs → android-_y4Ohi5z.mjs} +54 -15
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-eiExNLf7.mjs} +21 -14
- package/dist/app-install-Uf3a83Tv.mjs +819 -0
- package/dist/{build-lock-CgtsB6TV.mjs → build-lock-DPXPLgTc.mjs} +120 -24
- package/dist/build-progress-CVqkfPC6.mjs +188 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Dg7OnMrp.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-gByVmIjy.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-Cp9lM3wX.mjs} +187 -57
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-Bq5DcLGn.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-Cip5vUm1.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-KEu0_AXL.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-HyqISM0h.mjs} +1178 -635
- package/dist/{device-RdujjHLB.mjs → device-D4U-xLty.mjs} +13 -20
- package/dist/{device-lease-Ffz_M5t0.mjs → device-lease-Crs-HkJY.mjs} +16 -9
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-CnTAz8X1.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-AQ5rQPqr.mjs} +482 -35
- package/dist/{doctor-BMt156qe.mjs → doctor-B_Ei3bZu.mjs} +95 -107
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-Vfz83GCF.mjs} +22 -16
- package/dist/exec-jIAlgilk.mjs +132 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-Ckw8RQHi.mjs} +763 -126
- package/dist/{guide-BTAlD1_y.mjs → guide-BiAbhs1J.mjs} +891 -501
- package/dist/{guide-status-Craq9z0t.mjs → guide-status-BAMVU0ZA.mjs} +5 -3
- package/dist/{ios-BcCiI4TS.mjs → ios-BL2NFckr.mjs} +43 -20
- package/dist/{ios-BP04pY5f.mjs → ios-BzUJWk1K.mjs} +141 -175
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-D972i9wf.mjs} +149 -52
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-DPsSm0v_.mjs} +3 -2
- package/dist/launch-verify-Q_OtW1Rf.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-CI9NQSK7.mjs} +18 -13
- package/dist/{logs-query-BGL-Pl12.mjs → logs-query-Cqma3WIu.mjs} +36 -28
- package/dist/{metro-C7bcJ0uo.mjs → metro-DrLHaMn2.mjs} +78 -8
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-CmLQSIRj.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-9uFNRwfe.mjs} +36 -3
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D15Op8vN.mjs} +3 -3
- package/dist/{ownership-wolE-0Do.mjs → ownership-DCQPuWEc.mjs} +26 -7
- package/dist/{ports-BIbJaKNW.mjs → ports-BNKoWVWZ.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-DS112DYB.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-ZNJUo1pl.mjs} +12 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DWkkcIxV.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-B_lctBR3.mjs} +8 -7
- package/dist/server-expo-CeILEu86.mjs +2 -0
- package/dist/settings-BKNh5rl4.mjs +376 -0
- package/dist/{settings-BXXorVM2.mjs → settings-D030k0t4.mjs} +464 -152
- package/dist/settings.schema.json +989 -0
- package/dist/{teardown-BJqEzPo_.mjs → sim-pool-KaIsp2Ft.mjs} +14 -419
- package/dist/simslim-B_LsGLuJ.mjs +259 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-DU9A-gYw.mjs} +4 -4
- package/dist/spawn-claims-Dn3C_N6w.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-DYkkKF0s.mjs} +27 -31
- package/dist/{state-DZobzxLW.mjs → state-NcJzMEBF.mjs} +5 -3
- package/dist/{stats-CLg5RuDS.mjs → stats-B63-JVAY.mjs} +4 -4
- package/dist/{stats-BYcZ6n1h.mjs → stats-DG9e66Rz.mjs} +66 -5
- package/dist/status-S6ehL4Ui.mjs +932 -0
- package/dist/{stop-C8JW6kKp.mjs → stop-BO28HGqF.mjs} +101 -25
- package/dist/{stop-B1kOpYei.mjs → stop-T1R-cZRz.mjs} +2 -2
- package/dist/supervisor-run.mjs +52 -34
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-DWaiRD0e.mjs} +14 -9
- package/dist/{workspace-state-BT5E3SA2.mjs → workspace-state-DF2gCFhx.mjs} +52 -29
- package/dist/worktree-DKhSF0UX.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-LGB-UwgG.mjs} +603 -59
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-R_cUlE7s.mjs} +62 -41
- package/dist/{xcode-B6YaWeg0.mjs → xcode-BZqyxh3e.mjs} +216 -58
- package/package.json +5 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/build-slots-C-oAHRT1.mjs +0 -151
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,16 +1,428 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
import { A as withDirLock, K as projectDeviceSlots, N as readJsonObject, O as acquireAvdClaim, T as withConfigLock, U as deviceSlotPlatforms, g as loadConfig, k as ownership_claim_exports, u as getConfigDir } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-jIAlgilk.mjs";
|
|
3
|
+
import { S as workspaceStateFile, _ as workspaceDir, b as workspaceLogsDir, v as workspaceId, x as workspaceName } from "./workspace-state-DF2gCFhx.mjs";
|
|
4
|
+
import { c as ownedDeviceLabel } from "./project-DS112DYB.mjs";
|
|
5
|
+
import { a as clearRemoteSession, l as readRemoteSession, s as readMetroTunnel } from "./state-NcJzMEBF.mjs";
|
|
6
|
+
import { a as pidExists } from "./metro-DrLHaMn2.mjs";
|
|
7
|
+
import { G as planMetroReach } from "./settings-D030k0t4.mjs";
|
|
8
|
+
import { A as ownedAvdMatchesConfiguration, B as shutdownAndroidEmulator, E as listOrphanedAvdDirectories, N as ownedAvdSystemImage, R as resolveOwnedAvdSerial, V as waitForAndroidEmulatorShutdown, f as avdStorageRoots, g as deleteAvd, k as ownedAvdDirectory, l as assertOwnedAvdStopped, u as avdPathExists } from "./android-_y4Ohi5z.mjs";
|
|
9
|
+
import { l as phaseLine } from "./command-output-gByVmIjy.mjs";
|
|
10
|
+
import { a as parkSim, c as removeParkedAfter, s as readParked } from "./sim-pool-KaIsp2Ft.mjs";
|
|
11
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-DWaiRD0e.mjs";
|
|
12
|
+
import { c as readMetroRecords, o as isBundleProof } from "./launch-verify-Q_OtW1Rf.mjs";
|
|
13
|
+
import { a as LAUNCH_ERROR, i as INSTALL_ERROR, l as devClientDeepLink } from "./app-install-Uf3a83Tv.mjs";
|
|
14
|
+
import { C as resolveOwnedIosSim, T as shutdownIosSim, _ as parseRuntimeVersion, a as deleteIosSim, f as listIosDeviceTypes, g as parkedSimName, o as deleteParkedIosSim, r as clearAppDataContainer, s as findAppDataContainer, w as sanitizeDeviceLabel, y as renameIosSim } from "./ios-BL2NFckr.mjs";
|
|
10
15
|
import { t as probePublicHttp } from "./public-http-probe-CyMDrQ3c.mjs";
|
|
11
|
-
import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
16
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
12
17
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
18
|
+
import { randomUUID } from "node:crypto";
|
|
13
19
|
import { homedir } from "node:os";
|
|
20
|
+
import { isDeepStrictEqual } from "node:util";
|
|
21
|
+
//#region src/devices/agent-device-cleanup.ts
|
|
22
|
+
function parseAgentDeviceSessions(output) {
|
|
23
|
+
const result = JSON.parse(output);
|
|
24
|
+
if (result?.success !== true || !Array.isArray(result.data?.sessions)) throw new Error("agent-device did not return a successful session list");
|
|
25
|
+
return result.data.sessions.flatMap((entry) => {
|
|
26
|
+
if (!entry || typeof entry !== "object") return [];
|
|
27
|
+
const row = entry;
|
|
28
|
+
const id = row.platform === "ios" ? row.device_udid : row.id;
|
|
29
|
+
if (row.platform !== "ios" && row.platform !== "android" || typeof row.name !== "string" || !row.name.trim() || typeof id !== "string" || !id || typeof row.createdAt !== "number" || !Number.isFinite(row.createdAt) || row.platform === "ios" && row.id !== void 0 && row.id !== id) return [];
|
|
30
|
+
return [{
|
|
31
|
+
name: row.name,
|
|
32
|
+
platform: row.platform,
|
|
33
|
+
id,
|
|
34
|
+
createdAt: row.createdAt
|
|
35
|
+
}];
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function report(message) {
|
|
39
|
+
process.stderr.write(`${phaseLine("device", message)}\n`);
|
|
40
|
+
}
|
|
41
|
+
function closeOwnedDeviceSessions(device, stillOwned) {
|
|
42
|
+
const exec = getExecutor();
|
|
43
|
+
const deadline = Date.now() + 15e3;
|
|
44
|
+
const run = (args) => {
|
|
45
|
+
const remaining = deadline - Date.now();
|
|
46
|
+
if (remaining <= 0) throw new Error("agent-device cleanup timed out");
|
|
47
|
+
return exec.runFile("agent-device", [
|
|
48
|
+
...args,
|
|
49
|
+
"--json",
|
|
50
|
+
"--daemon-transport",
|
|
51
|
+
"socket"
|
|
52
|
+
], {
|
|
53
|
+
timeoutMs: Math.min(5e3, remaining),
|
|
54
|
+
killSignal: "SIGKILL"
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const list = () => parseAgentDeviceSessions(run([
|
|
58
|
+
"session",
|
|
59
|
+
"list",
|
|
60
|
+
"--session",
|
|
61
|
+
"stim-teardown-inventory"
|
|
62
|
+
]));
|
|
63
|
+
try {
|
|
64
|
+
if (!exec.findExecutable("agent-device")) return;
|
|
65
|
+
const sessions = list().filter((session) => session.platform === device.platform && session.id === device.id);
|
|
66
|
+
for (const session of sessions) try {
|
|
67
|
+
if (!list().some((current) => current.name === session.name && current.platform === session.platform && current.id === session.id && current.createdAt === session.createdAt)) continue;
|
|
68
|
+
if (!stillOwned()) return;
|
|
69
|
+
if (JSON.parse(run([
|
|
70
|
+
"close",
|
|
71
|
+
"--session",
|
|
72
|
+
session.name,
|
|
73
|
+
"--session-lock",
|
|
74
|
+
"reject",
|
|
75
|
+
"--platform",
|
|
76
|
+
device.platform,
|
|
77
|
+
device.platform === "ios" ? "--udid" : "--serial",
|
|
78
|
+
device.id
|
|
79
|
+
]))?.success !== true) throw new Error("agent-device did not confirm session close");
|
|
80
|
+
report(`closed agent-device session ${session.name} on ${device.id}`);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
report(`could not close agent-device session ${session.name} on ${device.id}: ${error.message}`);
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
report(`could not list agent-device sessions for ${device.id}: ${error.message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/devices/teardown.ts
|
|
90
|
+
function teardownParkedAvd(avdName) {
|
|
91
|
+
try {
|
|
92
|
+
return removeParkedAfter("android", avdName, () => {
|
|
93
|
+
const result = teardownOwnedAvd(avdName, {
|
|
94
|
+
del: true,
|
|
95
|
+
owner: { pool: true }
|
|
96
|
+
});
|
|
97
|
+
if (result.status !== "torn-down" && result.status !== "missing") throw new Error(result.reason);
|
|
98
|
+
}) ? {
|
|
99
|
+
status: "torn-down",
|
|
100
|
+
label: avdName
|
|
101
|
+
} : {
|
|
102
|
+
status: "skipped",
|
|
103
|
+
kind: "not-parked",
|
|
104
|
+
reason: "emulator is no longer parked"
|
|
105
|
+
};
|
|
106
|
+
} catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
status: "failed",
|
|
109
|
+
reason: String(error?.message || error)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function teardownParkedIosSim(udid, { label, deleteSim = deleteParkedIosSim } = {}) {
|
|
114
|
+
try {
|
|
115
|
+
const removed = removeParkedAfter("ios", udid, () => {
|
|
116
|
+
closeOwnedDeviceSessions({
|
|
117
|
+
platform: "ios",
|
|
118
|
+
id: udid
|
|
119
|
+
}, () => Boolean(resolveOwnedIosSim(udid).sim));
|
|
120
|
+
deleteSim(udid);
|
|
121
|
+
});
|
|
122
|
+
if (!removed) return {
|
|
123
|
+
status: "skipped",
|
|
124
|
+
kind: "not-parked",
|
|
125
|
+
reason: "simulator is no longer parked"
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
status: "torn-down",
|
|
129
|
+
label: label ?? removed.name
|
|
130
|
+
};
|
|
131
|
+
} catch (error) {
|
|
132
|
+
return {
|
|
133
|
+
status: "failed",
|
|
134
|
+
reason: String(error?.message || error)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function parkOwnedIosSim(udid, park) {
|
|
139
|
+
const resolved = resolveOwnedIosSim(udid);
|
|
140
|
+
if (resolved.missing) throw new Error(`simulator ${udid} disappeared after shutdown`);
|
|
141
|
+
if (resolved.notOwned) throw new Error(`simulator ${udid} is now named ${JSON.stringify(resolved.notOwned)}`);
|
|
142
|
+
const sim = resolved.sim;
|
|
143
|
+
if (sim.state !== "Shutdown") throw new Error(`simulator ${udid} is still ${sim.state} after shutdown`);
|
|
144
|
+
const model = listIosDeviceTypes().find((d) => d.identifier === sim.deviceTypeIdentifier)?.name ?? null;
|
|
145
|
+
const runtime = parseRuntimeVersion(sim.runtime);
|
|
146
|
+
if (park.bundleId) {
|
|
147
|
+
if (!sim.dataPath) throw new Error(`simulator ${udid} did not report a data path for app cleanup`);
|
|
148
|
+
const container = findAppDataContainer(sim.dataPath, park.bundleId);
|
|
149
|
+
if (container) clearAppDataContainer(container);
|
|
150
|
+
}
|
|
151
|
+
const name = parkedSimName(sim.udid, {
|
|
152
|
+
model,
|
|
153
|
+
runtime
|
|
154
|
+
});
|
|
155
|
+
renameIosSim(sim.udid, name);
|
|
156
|
+
const record = {
|
|
157
|
+
udid: sim.udid,
|
|
158
|
+
name,
|
|
159
|
+
deviceTypeIdentifier: sim.deviceTypeIdentifier,
|
|
160
|
+
runtimeIdentifier: sim.runtime,
|
|
161
|
+
parkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
162
|
+
simslimManaged: Boolean(park.simslimManaged),
|
|
163
|
+
...park.bundleId ? { bundleId: park.bundleId } : {},
|
|
164
|
+
...park.cacheKey ? { cacheKey: park.cacheKey } : {}
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
record,
|
|
168
|
+
evicted: parkSim({
|
|
169
|
+
platform: "ios",
|
|
170
|
+
projectPath: park.projectPath,
|
|
171
|
+
slot: park.slot,
|
|
172
|
+
record,
|
|
173
|
+
max: park.max
|
|
174
|
+
})
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function teardownOwnedIosSim(udid, { del = false, label, park } = {}) {
|
|
178
|
+
let parkFallback;
|
|
179
|
+
try {
|
|
180
|
+
const resolved = resolveOwnedIosSim(udid);
|
|
181
|
+
if (resolved.notOwned) return {
|
|
182
|
+
status: "skipped",
|
|
183
|
+
kind: "not-owned",
|
|
184
|
+
reason: `sim is now named "${resolved.notOwned}", not Stim-owned by name`
|
|
185
|
+
};
|
|
186
|
+
if (resolved.missing) return { status: "missing" };
|
|
187
|
+
closeOwnedDeviceSessions({
|
|
188
|
+
platform: "ios",
|
|
189
|
+
id: udid
|
|
190
|
+
}, () => Boolean(resolveOwnedIosSim(udid).sim));
|
|
191
|
+
const current = resolveOwnedIosSim(udid);
|
|
192
|
+
if (current.missing) return { status: "missing" };
|
|
193
|
+
if (current.notOwned) return {
|
|
194
|
+
status: "skipped",
|
|
195
|
+
kind: "not-owned",
|
|
196
|
+
reason: "simulator ownership changed before shutdown"
|
|
197
|
+
};
|
|
198
|
+
shutdownIosSim(udid);
|
|
199
|
+
const sim = resolved.sim;
|
|
200
|
+
if (del && park && park.max > 0) try {
|
|
201
|
+
const { record, evicted } = parkOwnedIosSim(udid, park);
|
|
202
|
+
const removed = [];
|
|
203
|
+
const failures = [];
|
|
204
|
+
for (const entry of evicted) {
|
|
205
|
+
const result = teardownParkedIosSim(entry.udid, { label: entry.name });
|
|
206
|
+
if (result.status === "torn-down") removed.push({
|
|
207
|
+
udid: entry.udid,
|
|
208
|
+
name: entry.name
|
|
209
|
+
});
|
|
210
|
+
else if (result.status === "failed") failures.push(`could not delete evicted ${entry.name} (${entry.udid}): ${result.reason}`);
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
status: "torn-down",
|
|
214
|
+
label: label ?? sim.name ?? udid,
|
|
215
|
+
parked: {
|
|
216
|
+
udid: record.udid,
|
|
217
|
+
name: record.name
|
|
218
|
+
},
|
|
219
|
+
evicted: removed,
|
|
220
|
+
...failures.length ? { evictionFailures: failures } : {}
|
|
221
|
+
};
|
|
222
|
+
} catch (e) {
|
|
223
|
+
parkFallback = String(e?.message || e);
|
|
224
|
+
}
|
|
225
|
+
if (del) deleteIosSim(udid);
|
|
226
|
+
return {
|
|
227
|
+
status: "torn-down",
|
|
228
|
+
label: label ?? sim.name ?? udid,
|
|
229
|
+
...parkFallback ? { parkFallback } : {}
|
|
230
|
+
};
|
|
231
|
+
} catch (e) {
|
|
232
|
+
return {
|
|
233
|
+
status: "failed",
|
|
234
|
+
reason: String(e?.message || e),
|
|
235
|
+
...parkFallback ? { parkFallback } : {}
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function assertAvdReferences(avdName, owner) {
|
|
240
|
+
const config = loadConfig();
|
|
241
|
+
if (!config) throw new Error("Cannot verify AVD references without a Stim config; the data was kept.");
|
|
242
|
+
if (owner && "projectPath" in owner && owner.expectedRecord && !isDeepStrictEqual(deviceSlotPlatforms(config.projects[owner.projectPath], owner.slot)?.android, owner.expectedRecord)) throw new Error(`AVD ${avdName} has a changed workspace record; its data was kept.`);
|
|
243
|
+
for (const [projectPath, project] of Object.entries(config.projects)) for (const { slot, platforms } of projectDeviceSlots(project)) {
|
|
244
|
+
if (platforms.android?.avdName?.toLowerCase() !== avdName.toLowerCase()) continue;
|
|
245
|
+
if (!owner || !("projectPath" in owner) || owner.projectPath !== projectPath || (owner.slot ?? "default") !== slot || !platforms.android.owned) throw new Error(`AVD ${avdName} is referenced by ${projectPath} (${slot}); its data was kept.`);
|
|
246
|
+
}
|
|
247
|
+
if (readParked("android", { config }).some((entry) => entry.name.toLowerCase() === avdName.toLowerCase()) && !(owner && "pool" in owner)) throw new Error(`AVD ${avdName} is in the emulator pool; its data was kept.`);
|
|
248
|
+
}
|
|
249
|
+
function removeOrphanedAvdDirectory(candidate, owner) {
|
|
250
|
+
const surveyed = listOrphanedAvdDirectories(candidate.name).find((entry) => entry.directory === candidate.directory);
|
|
251
|
+
if (!surveyed || surveyed.name !== candidate.name || surveyed.dev !== candidate.dev || surveyed.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
|
|
252
|
+
assertOwnedAvdStopped(candidate.name, { resolveDirectory: () => candidate.directory });
|
|
253
|
+
const detached = withConfigLock(() => {
|
|
254
|
+
const current = lstatSync(candidate.directory);
|
|
255
|
+
if (!current.isDirectory() || current.dev !== candidate.dev || current.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
|
|
256
|
+
assertAvdReferences(candidate.name, owner);
|
|
257
|
+
const destination = join(dirname(candidate.directory), `stim-gc-${randomUUID()}.avd`);
|
|
258
|
+
renameSync(candidate.directory, destination);
|
|
259
|
+
return destination;
|
|
260
|
+
});
|
|
261
|
+
const current = lstatSync(detached);
|
|
262
|
+
if (!current.isDirectory() || current.dev !== candidate.dev || current.ino !== candidate.ino) throw new Error(`Detached AVD data changed at ${detached}; it was kept.`);
|
|
263
|
+
try {
|
|
264
|
+
rmSync(detached, { recursive: true });
|
|
265
|
+
} catch (error) {
|
|
266
|
+
throw new Error(`Could not remove AVD data at ${detached}; retry gc --delete: ${error.message}`, { cause: error });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function teardownUnregisteredAvd(avdName, del, owner, surveyed) {
|
|
270
|
+
const candidates = surveyed ? [surveyed] : listOrphanedAvdDirectories(avdName);
|
|
271
|
+
if (candidates.length === 0) {
|
|
272
|
+
if (avdStorageRoots().some((root) => avdPathExists(join(root, `${avdName}.ini`)) || avdPathExists(join(root, `${avdName}.avd`)))) throw new Error(`AVD ${avdName} is not listed but its storage remains; it was kept.`);
|
|
273
|
+
return { status: "missing" };
|
|
274
|
+
}
|
|
275
|
+
if (!del) return {
|
|
276
|
+
status: "skipped",
|
|
277
|
+
reason: "AVD registration is missing; its data was kept."
|
|
278
|
+
};
|
|
279
|
+
for (const candidate of candidates) {
|
|
280
|
+
if (candidate.name !== avdName) throw new Error(`AVD data does not match ${avdName}; it was kept.`);
|
|
281
|
+
removeOrphanedAvdDirectory(candidate, owner);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
status: "torn-down",
|
|
285
|
+
label: avdName
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function teardownOwnedAvd(avdName, options = {}) {
|
|
289
|
+
if (!/^stim-[A-Za-z0-9._-]+$/.test(avdName)) return {
|
|
290
|
+
status: "skipped",
|
|
291
|
+
kind: "not-owned",
|
|
292
|
+
reason: `AVD ${avdName} is not Stim-owned by name`
|
|
293
|
+
};
|
|
294
|
+
let claim;
|
|
295
|
+
try {
|
|
296
|
+
claim = acquireAvdClaim(avdName);
|
|
297
|
+
const result = teardownClaimedAvd(avdName, claim, options);
|
|
298
|
+
if (result.status === "torn-down" || result.status === "missing") options.onRemoved?.();
|
|
299
|
+
return result;
|
|
300
|
+
} catch (error) {
|
|
301
|
+
return {
|
|
302
|
+
status: "failed",
|
|
303
|
+
reason: String(error?.message || error)
|
|
304
|
+
};
|
|
305
|
+
} finally {
|
|
306
|
+
(0, ownership_claim_exports.releaseClaim)(claim);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function teardownClaimedAvd(avdName, claim, { del = false, park, owner, orphanedDirectory, onlyIfMissing = false, waitForShutdown = waitForAndroidEmulatorShutdown, assertStopped = assertOwnedAvdStopped, resolveAvd = resolveOwnedAvdSerial }) {
|
|
310
|
+
let parkFallback;
|
|
311
|
+
try {
|
|
312
|
+
if (del) withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
313
|
+
const resolved = resolveAvd(avdName);
|
|
314
|
+
if (resolved.notOwned) return {
|
|
315
|
+
status: "skipped",
|
|
316
|
+
kind: "not-owned",
|
|
317
|
+
reason: `AVD ${avdName} is not Stim-owned by name`
|
|
318
|
+
};
|
|
319
|
+
if (resolved.missing) return teardownUnregisteredAvd(avdName, del, owner, orphanedDirectory);
|
|
320
|
+
if (onlyIfMissing) return {
|
|
321
|
+
status: "skipped",
|
|
322
|
+
reason: "AVD registration appeared; its record was kept."
|
|
323
|
+
};
|
|
324
|
+
if (orphanedDirectory) return {
|
|
325
|
+
status: "skipped",
|
|
326
|
+
reason: "AVD registration appeared; its data was kept."
|
|
327
|
+
};
|
|
328
|
+
const serial = resolved.serial;
|
|
329
|
+
if (serial) {
|
|
330
|
+
const stillOwned = () => {
|
|
331
|
+
const current = resolveAvd(avdName);
|
|
332
|
+
return !current.notOwned && !current.missing && current.serial === serial;
|
|
333
|
+
};
|
|
334
|
+
closeOwnedDeviceSessions({
|
|
335
|
+
platform: "android",
|
|
336
|
+
id: serial
|
|
337
|
+
}, stillOwned);
|
|
338
|
+
if (!stillOwned()) throw new Error(`Owned AVD ${avdName} changed before shutdown; it was kept.`);
|
|
339
|
+
waitForShutdown(avdName, (timeoutMs) => {
|
|
340
|
+
(0, ownership_claim_exports.markClaimChildPending)(claim);
|
|
341
|
+
try {
|
|
342
|
+
shutdownAndroidEmulator(serial, timeoutMs);
|
|
343
|
+
} finally {
|
|
344
|
+
(0, ownership_claim_exports.clearClaimChild)(claim);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
} else assertStopped(avdName);
|
|
348
|
+
if (del) {
|
|
349
|
+
const current = resolveAvd(avdName);
|
|
350
|
+
if (current.notOwned) return {
|
|
351
|
+
status: "skipped",
|
|
352
|
+
kind: "not-owned",
|
|
353
|
+
reason: `AVD ${avdName} is not Stim-owned by name`
|
|
354
|
+
};
|
|
355
|
+
if (current.missing) return teardownUnregisteredAvd(avdName, del, owner);
|
|
356
|
+
if (current.serial) throw new Error(`Owned AVD ${avdName} started again before deletion.`);
|
|
357
|
+
assertStopped(avdName);
|
|
358
|
+
withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
359
|
+
if (park && park.max > 0) try {
|
|
360
|
+
const systemImage = ownedAvdSystemImage(avdName);
|
|
361
|
+
if (!systemImage || !park.configuration || !ownedAvdMatchesConfiguration(avdName, park.configuration)) throw new Error("the AVD has no verified creation configuration");
|
|
362
|
+
const evicted = parkSim({
|
|
363
|
+
platform: "android",
|
|
364
|
+
projectPath: park.projectPath,
|
|
365
|
+
slot: park.slot,
|
|
366
|
+
max: park.max,
|
|
367
|
+
record: {
|
|
368
|
+
udid: avdName,
|
|
369
|
+
name: avdName,
|
|
370
|
+
systemImage,
|
|
371
|
+
configuration: park.configuration,
|
|
372
|
+
parkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
const removed = [];
|
|
376
|
+
const failures = [];
|
|
377
|
+
for (const entry of evicted) {
|
|
378
|
+
const result = teardownParkedAvd(entry.name);
|
|
379
|
+
if (result.status === "torn-down") removed.push({
|
|
380
|
+
udid: entry.name,
|
|
381
|
+
name: entry.name,
|
|
382
|
+
platform: "android"
|
|
383
|
+
});
|
|
384
|
+
else if (result.status === "failed") failures.push(`could not delete evicted ${entry.name}: ${result.reason}`);
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
status: "torn-down",
|
|
388
|
+
label: avdName,
|
|
389
|
+
parked: {
|
|
390
|
+
udid: avdName,
|
|
391
|
+
name: avdName,
|
|
392
|
+
platform: "android"
|
|
393
|
+
},
|
|
394
|
+
evicted: removed,
|
|
395
|
+
...failures.length ? { evictionFailures: failures } : {}
|
|
396
|
+
};
|
|
397
|
+
} catch (error) {
|
|
398
|
+
parkFallback = String(error?.message || error);
|
|
399
|
+
}
|
|
400
|
+
const directory = ownedAvdDirectory(avdName);
|
|
401
|
+
const paths = avdStorageRoots().map((root) => join(root, `${avdName}.ini`));
|
|
402
|
+
if (directory) paths.push(directory);
|
|
403
|
+
(0, ownership_claim_exports.markClaimChildPending)(claim);
|
|
404
|
+
try {
|
|
405
|
+
deleteAvd(avdName);
|
|
406
|
+
} finally {
|
|
407
|
+
(0, ownership_claim_exports.clearClaimChild)(claim);
|
|
408
|
+
}
|
|
409
|
+
const remaining = paths.filter(avdPathExists);
|
|
410
|
+
if (remaining.length) throw new Error(`AVD ${avdName} was only partially deleted; data remains at ${remaining.join(", ")}.`);
|
|
411
|
+
}
|
|
412
|
+
return {
|
|
413
|
+
status: "torn-down",
|
|
414
|
+
label: avdName,
|
|
415
|
+
serial: resolved.serial ?? null,
|
|
416
|
+
...parkFallback ? { parkFallback } : {}
|
|
417
|
+
};
|
|
418
|
+
} catch (e) {
|
|
419
|
+
return {
|
|
420
|
+
status: "failed",
|
|
421
|
+
reason: String(e?.message || e)
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
//#endregion
|
|
14
426
|
//#region src/engine/metro-gate.ts
|
|
15
427
|
const REMOTE_METRO_WRONG = "STIM_REMOTE_METRO_WRONG";
|
|
16
428
|
const GATE_TIMEOUT_MS = 25e3;
|
|
@@ -81,7 +493,9 @@ function remoteProfile({ daemon, platform, label }) {
|
|
|
81
493
|
session: scope,
|
|
82
494
|
tenant: scope,
|
|
83
495
|
runId: scope,
|
|
84
|
-
sessionIsolation: "tenant"
|
|
496
|
+
sessionIsolation: "tenant",
|
|
497
|
+
leaseProvider: "proxy",
|
|
498
|
+
clientId: scope
|
|
85
499
|
};
|
|
86
500
|
}
|
|
87
501
|
function daemonEnv(daemon) {
|
|
@@ -559,7 +973,9 @@ function resolveMetroOrigin({ metroPort, publicUrl = null, mode = "auto", isExpo
|
|
|
559
973
|
}
|
|
560
974
|
function describe(err) {
|
|
561
975
|
const e = err;
|
|
562
|
-
|
|
976
|
+
const stderr = typeof e?.stderr === "string" ? e.stderr.trim() : "";
|
|
977
|
+
if (err?.code === "ETIMEDOUT") return String(e?.message ?? err);
|
|
978
|
+
return stderr || String(e?.message ?? err);
|
|
563
979
|
}
|
|
564
980
|
const PROXY_CREDENTIAL_ENV = ["AGENT_DEVICE_DAEMON_BASE_URL", "AGENT_DEVICE_DAEMON_AUTH_TOKEN"];
|
|
565
981
|
function easExecOptions(root) {
|
|
@@ -569,6 +985,9 @@ function easExecOptions(root) {
|
|
|
569
985
|
};
|
|
570
986
|
}
|
|
571
987
|
const EAS_OPERATION_TIMEOUT_MS = 3e4;
|
|
988
|
+
const EAS_SESSION_CREATE_TIMEOUT_MS = 6e5;
|
|
989
|
+
const AGENT_DEVICE_TIMEOUT_MS = 12e4;
|
|
990
|
+
const AGENT_DEVICE_INSTALL_TIMEOUT_MS = 6e5;
|
|
572
991
|
function easBoundedExecOptions(root) {
|
|
573
992
|
return {
|
|
574
993
|
...easExecOptions(root),
|
|
@@ -643,8 +1062,22 @@ function remoteDeviceDeps(ctx) {
|
|
|
643
1062
|
label: ctx.label,
|
|
644
1063
|
platform: ctx.platform ?? "ios",
|
|
645
1064
|
maxDurationMinutes: ctx.maxDurationMinutes ?? null
|
|
646
|
-
}),
|
|
1065
|
+
}), {
|
|
1066
|
+
...easEnv,
|
|
1067
|
+
timeoutMs: EAS_SESSION_CREATE_TIMEOUT_MS,
|
|
1068
|
+
killSignal: "SIGKILL"
|
|
1069
|
+
});
|
|
647
1070
|
} catch (err) {
|
|
1071
|
+
if (err?.code === "ETIMEDOUT") {
|
|
1072
|
+
const partial = parseCreatedSession(String(err.stdout ?? ""));
|
|
1073
|
+
if (partial) return abandonSession(ctx, partial.id, `eas sim did not finish within ${EAS_SESSION_CREATE_TIMEOUT_MS / 6e4} minutes after creating session ${partial.id}.`);
|
|
1074
|
+
const name = ownedSessionName(ctx.label);
|
|
1075
|
+
return {
|
|
1076
|
+
failed: true,
|
|
1077
|
+
reason: `eas sim did not finish within ${EAS_SESSION_CREATE_TIMEOUT_MS / 6e4} minutes and the eas process was killed. EAS may still have started session ${name}; it has no Stim ownership claim, so \`stim gc\` will not stop it.`,
|
|
1078
|
+
remedy: `Run \`eas simulator:list --name ${name}\` and stop any running session with \`eas simulator:stop --id <id>\`, then retry.`
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
648
1081
|
return {
|
|
649
1082
|
failed: true,
|
|
650
1083
|
reason: `eas sim failed: ${describe(err)}`
|
|
@@ -674,13 +1107,17 @@ function remoteDeviceDeps(ctx) {
|
|
|
674
1107
|
try {
|
|
675
1108
|
getExecutor().runFile(ctx.agentDeviceBin, closeArgs(profilePath), {
|
|
676
1109
|
cwd: ctx.root,
|
|
677
|
-
env: daemonEnv(daemon)
|
|
1110
|
+
env: daemonEnv(daemon),
|
|
1111
|
+
timeoutMs: AGENT_DEVICE_TIMEOUT_MS,
|
|
1112
|
+
killSignal: "SIGKILL"
|
|
678
1113
|
});
|
|
679
1114
|
} catch {}
|
|
680
1115
|
try {
|
|
681
1116
|
getExecutor().runFile(ctx.agentDeviceBin, connectArgs(profilePath), {
|
|
682
1117
|
cwd: ctx.root,
|
|
683
|
-
env: daemonEnv(daemon)
|
|
1118
|
+
env: daemonEnv(daemon),
|
|
1119
|
+
timeoutMs: AGENT_DEVICE_TIMEOUT_MS,
|
|
1120
|
+
killSignal: "SIGKILL"
|
|
684
1121
|
});
|
|
685
1122
|
} catch (err) {
|
|
686
1123
|
if (createdHere) return abandonSession(ctx, createdHere, `agent-device connect failed: ${describe(err)}`);
|
|
@@ -706,7 +1143,9 @@ function remoteDeviceDeps(ctx) {
|
|
|
706
1143
|
try {
|
|
707
1144
|
getExecutor().runFile(ctx.agentDeviceBin, installArgs(session.profilePath, artifactPath), {
|
|
708
1145
|
cwd: ctx.root,
|
|
709
|
-
env: daemonEnv(session.daemon)
|
|
1146
|
+
env: daemonEnv(session.daemon),
|
|
1147
|
+
timeoutMs: AGENT_DEVICE_INSTALL_TIMEOUT_MS,
|
|
1148
|
+
killSignal: "SIGKILL"
|
|
710
1149
|
});
|
|
711
1150
|
return {
|
|
712
1151
|
ok: true,
|
|
@@ -725,7 +1164,9 @@ function remoteDeviceDeps(ctx) {
|
|
|
725
1164
|
if (metroPort === null) try {
|
|
726
1165
|
getExecutor().runFile(ctx.agentDeviceBin, openArgs(session.profilePath, appId, null, null), {
|
|
727
1166
|
cwd: ctx.root,
|
|
728
|
-
env: daemonEnv(session.daemon)
|
|
1167
|
+
env: daemonEnv(session.daemon),
|
|
1168
|
+
timeoutMs: AGENT_DEVICE_TIMEOUT_MS,
|
|
1169
|
+
killSignal: "SIGKILL"
|
|
729
1170
|
});
|
|
730
1171
|
return {
|
|
731
1172
|
ok: true,
|
|
@@ -753,12 +1194,16 @@ function remoteDeviceDeps(ctx) {
|
|
|
753
1194
|
try {
|
|
754
1195
|
getExecutor().runFile(ctx.agentDeviceBin, openArgs(session.profilePath, appId, url, metroHintFrom(origin.origin)), {
|
|
755
1196
|
cwd: ctx.root,
|
|
756
|
-
env: daemonEnv(session.daemon)
|
|
1197
|
+
env: daemonEnv(session.daemon),
|
|
1198
|
+
timeoutMs: AGENT_DEVICE_TIMEOUT_MS,
|
|
1199
|
+
killSignal: "SIGKILL"
|
|
757
1200
|
});
|
|
758
1201
|
if (url) try {
|
|
759
1202
|
getExecutor().runFile(ctx.agentDeviceBin, acceptAlertArgs(session.profilePath), {
|
|
760
1203
|
cwd: ctx.root,
|
|
761
|
-
env: daemonEnv(session.daemon)
|
|
1204
|
+
env: daemonEnv(session.daemon),
|
|
1205
|
+
timeoutMs: AGENT_DEVICE_TIMEOUT_MS,
|
|
1206
|
+
killSignal: "SIGKILL"
|
|
762
1207
|
});
|
|
763
1208
|
} catch {}
|
|
764
1209
|
return {
|
|
@@ -791,7 +1236,7 @@ function remoteDeviceDeps(ctx) {
|
|
|
791
1236
|
webPreviewUrl: () => session?.daemon.webPreviewUrl ?? null
|
|
792
1237
|
};
|
|
793
1238
|
}
|
|
794
|
-
async function resolveRemoteContext({ root,
|
|
1239
|
+
async function resolveRemoteContext({ root, backend, platform = "ios", easBin, env = process.env, lookupAgentDevice = defaultLookupAgentDevice, maxDurationMinutes = null }) {
|
|
795
1240
|
const agentDeviceBin = lookupAgentDevice();
|
|
796
1241
|
if (!agentDeviceBin) return {
|
|
797
1242
|
failed: "agent-device is not on PATH, and it is what drives a remote device.",
|
|
@@ -827,7 +1272,7 @@ async function resolveRemoteContext({ root, label, backend, platform = "ios", ea
|
|
|
827
1272
|
};
|
|
828
1273
|
return { ctx: {
|
|
829
1274
|
root,
|
|
830
|
-
label
|
|
1275
|
+
label: `${ownedDeviceLabel(root)}-${workspaceId(root)}`,
|
|
831
1276
|
backend,
|
|
832
1277
|
platform,
|
|
833
1278
|
easBin: easBin ?? "",
|
|
@@ -915,7 +1360,7 @@ function withRemoteSessionLock(root, fn, options = {}) {
|
|
|
915
1360
|
...options
|
|
916
1361
|
});
|
|
917
1362
|
}
|
|
918
|
-
async function ensureRemoteBootOwned({ root, platform, sessionName, startedAt, boot, createdSessionId, abandonCreatedSession, writeState, register = () => {}, withProjectLock = withEasProjectLock, withLock = withRemoteSessionLock, removeEasSessionClaim: removeClaim = removeEasSessionClaim, ledgerRoot = easMachineStateRoot() }) {
|
|
1363
|
+
async function ensureRemoteBootOwned({ root, platform, sessionName, startedAt, boot, createdSessionId, abandonCreatedSession, webPreviewUrl = () => null, writeState, register = () => {}, withProjectLock = withEasProjectLock, withLock = withRemoteSessionLock, removeEasSessionClaim: removeClaim = removeEasSessionClaim, ledgerRoot = easMachineStateRoot() }) {
|
|
919
1364
|
try {
|
|
920
1365
|
return await withProjectLock(root, () => withLock(root, async () => {
|
|
921
1366
|
register();
|
|
@@ -932,10 +1377,12 @@ async function ensureRemoteBootOwned({ root, platform, sessionName, startedAt, b
|
|
|
932
1377
|
workspaceHome: getConfigDir(),
|
|
933
1378
|
stateFile: workspaceStateFile(root)
|
|
934
1379
|
}, ledgerRoot);
|
|
1380
|
+
const preview = webPreviewUrl();
|
|
935
1381
|
writeState(root, { remoteDevice: {
|
|
936
1382
|
platform,
|
|
937
1383
|
sessionId,
|
|
938
|
-
startedAt
|
|
1384
|
+
startedAt,
|
|
1385
|
+
...preview ? { webPreviewUrl: preview } : {}
|
|
939
1386
|
} });
|
|
940
1387
|
return booted;
|
|
941
1388
|
} catch (err) {
|
|
@@ -1091,7 +1538,11 @@ function endRecordedSession({ root, sessionId, easBin, lookupAgentDevice, ledger
|
|
|
1091
1538
|
function teardownRemote(ctx, { sessionId }) {
|
|
1092
1539
|
const profilePath = remoteProfilePath(ctx.root);
|
|
1093
1540
|
try {
|
|
1094
|
-
getExecutor().runFile(ctx.agentDeviceBin, disconnectArgs(profilePath), {
|
|
1541
|
+
getExecutor().runFile(ctx.agentDeviceBin, disconnectArgs(profilePath), {
|
|
1542
|
+
cwd: ctx.root,
|
|
1543
|
+
timeoutMs: AGENT_DEVICE_TIMEOUT_MS,
|
|
1544
|
+
killSignal: "SIGKILL"
|
|
1545
|
+
});
|
|
1095
1546
|
} catch {}
|
|
1096
1547
|
if (!sessionId) return { status: "torn-down" };
|
|
1097
1548
|
const ledger = readEasSessionLedger(ctx.easLedgerRoot);
|
|
@@ -1202,16 +1653,12 @@ async function ensureMetroReachable({ ctx, metroPort, isExpo, tunnelMode = "auto
|
|
|
1202
1653
|
}
|
|
1203
1654
|
function bundleEntryPoint(root, isExpo) {
|
|
1204
1655
|
if (!isExpo) return "index";
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
return local ? normalized : `node_modules/${normalized}`;
|
|
1212
|
-
} catch {
|
|
1213
|
-
return "index";
|
|
1214
|
-
}
|
|
1656
|
+
const declared = readJsonObject(resolve(root, "package.json"))?.main;
|
|
1657
|
+
if (typeof declared !== "string" || !declared.trim()) return "index";
|
|
1658
|
+
const main = declared.trim();
|
|
1659
|
+
const local = main.startsWith(".") || /\.[cm]?[jt]sx?$/.test(main) || existsSync(resolve(root, main));
|
|
1660
|
+
const normalized = main.replace(/^\.\//, "").replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
1661
|
+
return local ? normalized : `node_modules/${normalized}`;
|
|
1215
1662
|
}
|
|
1216
1663
|
//#endregion
|
|
1217
|
-
export { verifyStoppedSession as C, stopSessionArgs as S, inspectSessionForTeardown as _, ensureMetroReachable as a, ownedSessionName as b, remoteIosDeps as c, withEasProjectLock as d, easMachineStateRoot as f, getSessionArgs as g, findOrphanedOwnedSessions as h, endRecordedSession as i, resolveRemoteContext as l, removeEasSessionClaim as m, binOnPath as n, ensureRemoteBootOwned as o, readEasSessionLedger as p, bundleEntryPoint as r, remoteAndroidDeps as s, REMOTE_SESSION_ERROR as t, withRemoteSessionLock as u, isDefinitiveMissingSessionError as v, gateMetroOrigin as w, parseSessionListPage as x, listOwnedSessionsArgs as y };
|
|
1664
|
+
export { verifyStoppedSession as C, teardownParkedAvd as D, teardownOwnedIosSim as E, teardownParkedIosSim as O, stopSessionArgs as S, teardownOwnedAvd as T, inspectSessionForTeardown as _, ensureMetroReachable as a, ownedSessionName as b, remoteIosDeps as c, withEasProjectLock as d, easMachineStateRoot as f, getSessionArgs as g, findOrphanedOwnedSessions as h, endRecordedSession as i, resolveRemoteContext as l, removeEasSessionClaim as m, binOnPath as n, ensureRemoteBootOwned as o, readEasSessionLedger as p, bundleEntryPoint as r, remoteAndroidDeps as s, REMOTE_SESSION_ERROR as t, withRemoteSessionLock as u, isDefinitiveMissingSessionError as v, gateMetroOrigin as w, parseSessionListPage as x, listOwnedSessionsArgs as y };
|