stim 1.2.0 → 1.3.1
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 +34 -3
- package/dist/{android-Bcmev2s2.mjs → android-CT-PkXUh.mjs} +157 -62
- package/dist/{android-cas-D6HPZ6UQ.mjs → android-cas-DXorPCi_.mjs} +5 -5
- package/dist/android-hMj83VpN.mjs +1374 -0
- package/dist/{app-install-NFxUahnH.mjs → app-install-DIp9riNx.mjs} +6 -6
- package/dist/{build-slots-D0b6sJyo.mjs → build-slots-C4AouyNz.mjs} +2 -2
- package/dist/{cache-manifest-Cu4_Znw9.mjs → cache-manifest-CXR-Y8pH.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +13 -13
- package/dist/collector-run.d.mts +3 -1
- package/dist/collector-run.mjs +33 -8
- package/dist/{config-CMtIaTk9.mjs → config-CcefMY2Q.mjs} +93 -12
- package/dist/{deps-BLBsTNDS.mjs → deps-0Yt0Inly.mjs} +1 -1
- package/dist/{dev-client-RpvXxCXV.mjs → dev-client-VfSZNLT4.mjs} +186 -9
- package/dist/{device-CoCPmazS.mjs → device-Bbv45Z9Z.mjs} +19 -11
- package/dist/{device-lease-Dpik41RY.mjs → device-lease-CJwK7OZr.mjs} +107 -83
- package/dist/{device-pool-B5pEVa3t.mjs → device-pool-CcBNTvM7.mjs} +18 -12
- package/dist/{device-remote-E81KAdXf.mjs → device-remote-DAA0Zm6Z.mjs} +7 -7
- package/dist/{doctor-CqPeMsSm.mjs → doctor-B4EITgQB.mjs} +11 -12
- package/dist/{doctor-D_CX7ib5.mjs → doctor-BueDfLYG.mjs} +4 -4
- package/dist/{error-diagnostics-Dw8Gn3yw.mjs → error-diagnostics-DwhNBFDU.mjs} +62 -52
- package/dist/{gc-B7KkDinF.mjs → gc-BRu62v4o.mjs} +66 -57
- package/dist/{guide-BS2Xc24o.mjs → guide-D95E0u3i.mjs} +307 -74
- package/dist/{ios-B7KLgIp5.mjs → ios-DAju3TVy.mjs} +183 -54
- package/dist/{ios-D1h1Di39.mjs → ios-Deh5js5V.mjs} +78 -40
- package/dist/{ios-device-xNt0Lg6v.mjs → ios-device-CWOM_S44.mjs} +1 -1
- package/dist/{logs-DcX9AvRF.mjs → logs-CAdwW6c2.mjs} +34 -6
- package/dist/{logs-query-oqn47Ffx.mjs → logs-query-Cdp5aaCH.mjs} +23 -6
- package/dist/{metro-COslRK_F.mjs → metro-CORqXyTL.mjs} +2 -2
- package/dist/{ndjson-DcAtEx_K.mjs → ndjson-BZwI1NBv.mjs} +5 -2
- package/dist/{ownership-CGPart6T.mjs → ownership-8O073GIC.mjs} +3 -3
- package/dist/{ownership-CYOyqxUo.mjs → ownership-DXcol4oU.mjs} +3 -3
- package/dist/{ownership-claim-7zRxxTfZ.mjs → ownership-claim-BtPtJVmq.mjs} +38 -23
- package/dist/{project-BBTVABUz.mjs → project-fKmuIaMI.mjs} +2 -2
- package/dist/{reclaim-C5Jmuahx.mjs → reclaim-CUmwucWG.mjs} +80 -74
- package/dist/{reload-Z8nKifAk.mjs → reload-CWpXoOgN.mjs} +32 -24
- package/dist/{server-bare-DEk37Mz2.mjs → server-bare-DEzPZLvf.mjs} +2 -2
- package/dist/server-expo-44em5Pmg.mjs +2 -0
- package/dist/{server-expo-C3ktAwUG.mjs → server-expo-DizT4OMk.mjs} +4 -4
- package/dist/{settings-DwU1_U_q.mjs → settings-DEJf6_kJ.mjs} +2 -2
- package/dist/slot-launch-CZklomj6.mjs +19 -0
- package/dist/{start-BrY4EuIg.mjs → start-B5G4NjiA.mjs} +11 -11
- package/dist/{state-CZ-ER-8d.mjs → state-B3XA2wp2.mjs} +9 -9
- package/dist/{stats-BCWEVLrM.mjs → stats-BR-kwj0B.mjs} +1 -1
- package/dist/{stats-BsF15Bti.mjs → stats-CaaQr4yN.mjs} +3 -3
- package/dist/{status-DFI1Hfpg.mjs → status-CI9clRSb.mjs} +55 -24
- package/dist/{stop-B7DR4awK.mjs → stop-CQhffpmX.mjs} +2 -2
- package/dist/{stop-Btg770vV.mjs → stop-CjlgDk0a.mjs} +93 -42
- package/dist/supervisor-run.d.mts +1 -2
- package/dist/supervisor-run.mjs +5 -5
- package/dist/{remote-cache-DDmJ1Roq.mjs → teardown--gESs9ck.mjs} +985 -887
- package/dist/{workspace-process-lock-BKfdys1q.mjs → workspace-process-lock-IBj1Towr.mjs} +1 -1
- package/dist/{worktree-BPTbI-LN.mjs → worktree-DtQGO9-s.mjs} +121 -111
- package/dist/{worktree-C79xx_kM.mjs → worktree-Eq6TLH8N.mjs} +1 -1
- package/dist/{xcode-DeKCribl.mjs → xcode-xnxyvJkD.mjs} +159 -96
- package/package.json +5 -5
- package/dist/android-K63_0UfF.mjs +0 -727
- package/dist/build-lock-BsVoLDaq.mjs +0 -645
- package/dist/server-expo-Drd7ksHu.mjs +0 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { V as validateDeviceSlot } from "./config-CcefMY2Q.mjs";
|
|
2
|
+
import { a as findProjectRoot } from "./project-fKmuIaMI.mjs";
|
|
2
3
|
import { r as clockTime } from "./command-output-8wHMEde0.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { c as listIosDevices, o as iosPoolCandidates, s as iosPoolNoCandidatesRefusal, u as resolveIosPhysicalDevice } from "./ios-device-
|
|
4
|
+
import { C as memoizeEmulatorProbe, P as resolvePhysicalDevice, i as androidPoolNoCandidatesRefusal, j as probeEmulatorSerial, k as physicalDeviceModel, r as androidPoolCandidates, y as listAdbDevices } from "./android-hMj83VpN.mjs";
|
|
5
|
+
import { f as takeLease, l as releaseWorkspaceLeases, n as fileLeaseIo, o as parseLeaseDuration } from "./device-lease-CJwK7OZr.mjs";
|
|
6
|
+
import { d as waitForDevice, s as parseDeviceWait, t as selectFromPool } from "./device-pool-CcBNTvM7.mjs";
|
|
7
|
+
import { c as listIosDevices, o as iosPoolCandidates, s as iosPoolNoCandidatesRefusal, u as resolveIosPhysicalDevice } from "./ios-device-CWOM_S44.mjs";
|
|
7
8
|
import chalk from "chalk";
|
|
8
9
|
//#region src/commands/device.ts
|
|
9
10
|
const DEFAULT_FOR = "5m";
|
|
@@ -24,7 +25,7 @@ const DEFAULT_DEPS = {
|
|
|
24
25
|
note: (line) => console.error(line)
|
|
25
26
|
};
|
|
26
27
|
function grantLine(facts, durationText) {
|
|
27
|
-
return `locked ${facts.deviceName ? `${facts.deviceName} (${facts.id})` : facts.id} for ${facts.holder} until ${clockTime(facts.expiresAt)} (${durationText}). Renew: stim device lock ${facts.platform} --for ${durationText}. Release: stim device unlock.`;
|
|
28
|
+
return `locked ${facts.deviceName ? `${facts.deviceName} (${facts.id})` : facts.id} for ${facts.holder} until ${clockTime(facts.expiresAt)} (${durationText}). Renew: stim device lock ${facts.platform}${facts.slot ? ` --slot ${facts.slot}` : ""} --for ${durationText}. Release: stim device unlock${facts.slot ? ` --slot ${facts.slot}` : ""}.`;
|
|
28
29
|
}
|
|
29
30
|
function releasedLine(lease) {
|
|
30
31
|
return `unlocked ${lease.deviceName ? `${lease.deviceName} (${lease.id})` : lease.id} -- the ${lease.platform} lease ran until ${clockTime(lease.expiresAt)}.`;
|
|
@@ -59,9 +60,10 @@ function resolveDevice(platform, requested, d) {
|
|
|
59
60
|
function isFailure(value) {
|
|
60
61
|
return "code" in value;
|
|
61
62
|
}
|
|
62
|
-
async function poolDevice(platform, idLabel, waitSeconds, deadline, root, d) {
|
|
63
|
+
async function poolDevice(platform, idLabel, waitSeconds, deadline, root, d, slot) {
|
|
63
64
|
const isEmulator = memoizeEmulatorProbe(d.probeEmulatorSerial);
|
|
64
65
|
const pooled = await d.selectFromPool({
|
|
66
|
+
...slot ? { slot } : {},
|
|
65
67
|
root,
|
|
66
68
|
platform,
|
|
67
69
|
idLabel,
|
|
@@ -140,10 +142,11 @@ async function runLock(platformArg, idArg, opts = {}, overrides = {}) {
|
|
|
140
142
|
const idLabel = platform === "ios" ? "udid" : "serial";
|
|
141
143
|
const deadline = d.now() + wait.seconds * 1e3;
|
|
142
144
|
const lastLine = { at: null };
|
|
143
|
-
const device = idArg ? resolveDevice(platform, idArg, d) : await poolDevice(platform, idLabel, wait.seconds, deadline, root, d);
|
|
145
|
+
const device = idArg ? resolveDevice(platform, idArg, d) : await poolDevice(platform, idLabel, wait.seconds, deadline, root, d, opts.slot);
|
|
144
146
|
if (isFailure(device)) return report(device);
|
|
145
147
|
for (;;) {
|
|
146
148
|
const outcome = await d.waitForDevice({
|
|
149
|
+
...opts.slot ? { slot: opts.slot } : {},
|
|
147
150
|
root,
|
|
148
151
|
platform,
|
|
149
152
|
id: device.id,
|
|
@@ -161,6 +164,7 @@ async function runLock(platformArg, idArg, opts = {}, overrides = {}) {
|
|
|
161
164
|
lease: outcome.refusal.lease
|
|
162
165
|
});
|
|
163
166
|
const taken = d.takeLease({
|
|
167
|
+
...opts.slot ? { slot: opts.slot } : {},
|
|
164
168
|
root,
|
|
165
169
|
platform,
|
|
166
170
|
id: device.id,
|
|
@@ -182,6 +186,7 @@ async function runLock(platformArg, idArg, opts = {}, overrides = {}) {
|
|
|
182
186
|
});
|
|
183
187
|
if (taken.status === "held") continue;
|
|
184
188
|
const facts = {
|
|
189
|
+
...taken.lease.slot ? { slot: taken.lease.slot } : {},
|
|
185
190
|
platform,
|
|
186
191
|
id: taken.lease.id,
|
|
187
192
|
deviceName: taken.lease.deviceName,
|
|
@@ -224,7 +229,10 @@ async function runUnlock(platformArg, opts = {}, overrides = {}) {
|
|
|
224
229
|
message: "Not in a React Native project (no package.json found).",
|
|
225
230
|
remedy: "Run this from the app directory -- the one holding package.json."
|
|
226
231
|
});
|
|
227
|
-
const released = d.releaseLeases(root, {
|
|
232
|
+
const released = d.releaseLeases(root, {
|
|
233
|
+
platform,
|
|
234
|
+
...opts.slot ? { slot: opts.slot } : {}
|
|
235
|
+
}, d.io);
|
|
228
236
|
if (released.length === 0) d.note(chalk.dim(`No ${platform ? `${platform} ` : ""}device lease to release for ${root}. \`stim status\` lists every lease on this machine.`));
|
|
229
237
|
if (json) d.out(JSON.stringify(released.map((lease) => ({
|
|
230
238
|
...lease,
|
|
@@ -235,10 +243,10 @@ async function runUnlock(platformArg, opts = {}, overrides = {}) {
|
|
|
235
243
|
}
|
|
236
244
|
function registerDevice(program, deps = {}) {
|
|
237
245
|
const device = program.command("device").description("Lease a connected physical device to this workspace, and give it back");
|
|
238
|
-
device.command("lock").argument("<platform>", "ios or android").argument("[id]", "the UDID or serial to lease; without one, the first free connected device is used").description("Lease a connected physical device to this workspace for a declared time, so another workspace's `--device` run waits instead of installing over it. Nothing but this command and a `--device` run moves the expiry.").option("--for <duration>", `How long to hold it: a whole number of seconds or minutes from 10s to 30m (default ${DEFAULT_FOR})`).option("--wait <seconds>", "How long to wait for a device another workspace holds, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once)").option("--json", "print the lease as JSON on stdout").action(async (platform, id, opts) => {
|
|
246
|
+
device.command("lock").argument("<platform>", "ios or android").argument("[id]", "the UDID or serial to lease; without one, the first free connected device is used").description("Lease a connected physical device to this workspace for a declared time, so another workspace's `--device` run waits instead of installing over it. Nothing but this command and a `--device` run moves the expiry.").option("--for <duration>", `How long to hold it: a whole number of seconds or minutes from 10s to 30m (default ${DEFAULT_FOR})`).option("--wait <seconds>", "How long to wait for a device another workspace holds, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once)").option("--slot <name>", "Use this workspace device slot", validateDeviceSlot).option("--json", "print the lease as JSON on stdout").action(async (platform, id, opts) => {
|
|
239
247
|
if ("code" in await runLock(platform, id, opts, deps)) process.exit(1);
|
|
240
248
|
});
|
|
241
|
-
device.command("unlock").argument("[platform]", "ios or android; without one, every lease this workspace holds is released").description("Release the device lease or leases this workspace holds. Releasing nothing is not an error.").option("--json", "print the released leases as JSON on stdout").action(async (platform, opts) => {
|
|
249
|
+
device.command("unlock").argument("[platform]", "ios or android; without one, every lease this workspace holds is released").description("Release the device lease or leases this workspace holds. Releasing nothing is not an error.").option("--slot <name>", "Use this workspace device slot", validateDeviceSlot).option("--json", "print the released leases as JSON on stdout").action(async (platform, opts) => {
|
|
242
250
|
const result = await runUnlock(platform, opts, deps);
|
|
243
251
|
if (!Array.isArray(result)) process.exit(1);
|
|
244
252
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { k as withDirLock, u as getConfigDir } from "./config-
|
|
2
|
-
import { _ as writeWorkspaceState, o as clearWorkspaceStateKeys, p as readWorkspaceState } from "./state-
|
|
3
|
-
import {
|
|
1
|
+
import { I as deviceSlotKey, R as parseDeviceSlotKey, V as validateDeviceSlot, k as withDirLock, u as getConfigDir } from "./config-CcefMY2Q.mjs";
|
|
2
|
+
import { _ as writeWorkspaceState, m as withWorkspaceStateLock, o as clearWorkspaceStateKeys, p as readWorkspaceState } from "./state-B3XA2wp2.mjs";
|
|
3
|
+
import { H as segment } from "./android-hMj83VpN.mjs";
|
|
4
4
|
import { mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { randomBytes } from "node:crypto";
|
|
6
6
|
import { join } from "node:path";
|
|
@@ -21,6 +21,7 @@ function deviceLeaseLockPath(platform, id) {
|
|
|
21
21
|
return join(deviceLocksDir(), `${leaseStem(platform, id)}${LOCK_SUFFIX}`);
|
|
22
22
|
}
|
|
23
23
|
const fileLeaseIo = {
|
|
24
|
+
withHolderLock: withWorkspaceStateLock,
|
|
24
25
|
now: () => Date.now(),
|
|
25
26
|
readLease(path) {
|
|
26
27
|
try {
|
|
@@ -83,8 +84,17 @@ function parseLease(raw) {
|
|
|
83
84
|
const token = text(entry.token);
|
|
84
85
|
const expiresAt = text(entry.expiresAt);
|
|
85
86
|
if (!id || !holder || !token || !expiresAt || !Number.isFinite(Date.parse(expiresAt))) return null;
|
|
87
|
+
if (entry.slot !== void 0) {
|
|
88
|
+
if (typeof entry.slot !== "string") return null;
|
|
89
|
+
try {
|
|
90
|
+
validateDeviceSlot(entry.slot);
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
86
95
|
return {
|
|
87
96
|
version: 1,
|
|
97
|
+
...typeof entry.slot === "string" ? { slot: entry.slot } : {},
|
|
88
98
|
platform: entry.platform,
|
|
89
99
|
id,
|
|
90
100
|
deviceName: text(entry.deviceName),
|
|
@@ -98,7 +108,7 @@ function parseWorkspaceLeases(value) {
|
|
|
98
108
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
99
109
|
const leases = {};
|
|
100
110
|
for (const [platform, entry] of Object.entries(value)) {
|
|
101
|
-
if (!
|
|
111
|
+
if (!parseDeviceSlotKey(platform) || !entry || typeof entry !== "object") continue;
|
|
102
112
|
const record = entry;
|
|
103
113
|
const id = text(record.id);
|
|
104
114
|
const token = text(record.token);
|
|
@@ -145,70 +155,74 @@ function writeLease(lease, io) {
|
|
|
145
155
|
io.writeLease(deviceLeasePath(lease.platform, lease.id), `${JSON.stringify(lease, null, 2)}\n`);
|
|
146
156
|
return lease;
|
|
147
157
|
}
|
|
148
|
-
function takeLease({ root, platform, id, deviceName = null, kind, durationMs = DEFAULT_LEASE_MS }, io = fileLeaseIo) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (current && !leaseIsExpired(current, now)) {
|
|
168
|
-
if (current.holder !== root) return {
|
|
169
|
-
status: "held",
|
|
170
|
-
lease: current
|
|
158
|
+
function takeLease({ root, platform, slot = "default", id, deviceName = null, kind, durationMs = DEFAULT_LEASE_MS }, io = fileLeaseIo) {
|
|
159
|
+
return withHolderLock(io, root, () => {
|
|
160
|
+
const key = deviceSlotKey(platform, slot);
|
|
161
|
+
const previous = io.readHolder(root)[key];
|
|
162
|
+
if (previous && previous.id !== id) releaseHeld(root, platform, previous, io, slot);
|
|
163
|
+
for (const entry of listLeaseFiles(io)) {
|
|
164
|
+
const other = entry.lease;
|
|
165
|
+
if (!other || other.platform !== platform || other.holder !== root || (other.slot ?? "default") !== slot || other.id === id) continue;
|
|
166
|
+
releaseByRoot(root, platform, other.id, io);
|
|
167
|
+
}
|
|
168
|
+
const declared = previous?.kind === "declared" && previous.id === id;
|
|
169
|
+
const path = deviceLeasePath(platform, id);
|
|
170
|
+
const result = io.withLeaseLock(deviceLeaseLockPath(platform, id), () => {
|
|
171
|
+
const now = io.now();
|
|
172
|
+
const raw = io.readLease(path);
|
|
173
|
+
const current = parseLease(raw);
|
|
174
|
+
if (raw !== null && !current) return {
|
|
175
|
+
status: "unreadable",
|
|
176
|
+
path
|
|
171
177
|
};
|
|
172
|
-
const
|
|
178
|
+
const asked = now + durationMs;
|
|
179
|
+
if (current && !leaseIsExpired(current, now)) {
|
|
180
|
+
if (current.holder !== root || (current.slot ?? "default") !== slot) return {
|
|
181
|
+
status: "held",
|
|
182
|
+
lease: current
|
|
183
|
+
};
|
|
184
|
+
const floor = declared && kind === "run" ? Math.max(asked, Date.parse(current.expiresAt)) : asked;
|
|
185
|
+
return {
|
|
186
|
+
status: "set",
|
|
187
|
+
lease: writeLease({
|
|
188
|
+
...current,
|
|
189
|
+
deviceName: deviceName ?? current.deviceName,
|
|
190
|
+
expiresAt: new Date(floor).toISOString()
|
|
191
|
+
}, io)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
const expiresAt = new Date(asked).toISOString();
|
|
173
195
|
return {
|
|
174
|
-
status: "
|
|
196
|
+
status: "taken",
|
|
175
197
|
lease: writeLease({
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
198
|
+
version: 1,
|
|
199
|
+
...slot === "default" ? {} : { slot },
|
|
200
|
+
platform,
|
|
201
|
+
id,
|
|
202
|
+
deviceName,
|
|
203
|
+
holder: root,
|
|
204
|
+
token: randomBytes(12).toString("hex"),
|
|
205
|
+
grantedAt: new Date(now).toISOString(),
|
|
206
|
+
expiresAt
|
|
179
207
|
}, io)
|
|
180
208
|
};
|
|
209
|
+
});
|
|
210
|
+
if (result.status === "taken" || result.status === "set") {
|
|
211
|
+
const recorded = result.status === "set" && declared ? "declared" : kind;
|
|
212
|
+
io.writeHolder(root, {
|
|
213
|
+
...io.readHolder(root),
|
|
214
|
+
[key]: {
|
|
215
|
+
id,
|
|
216
|
+
token: result.lease.token,
|
|
217
|
+
kind: recorded
|
|
218
|
+
}
|
|
219
|
+
});
|
|
181
220
|
}
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
status: "taken",
|
|
185
|
-
lease: writeLease({
|
|
186
|
-
version: 1,
|
|
187
|
-
platform,
|
|
188
|
-
id,
|
|
189
|
-
deviceName,
|
|
190
|
-
holder: root,
|
|
191
|
-
token: randomBytes(12).toString("hex"),
|
|
192
|
-
grantedAt: new Date(now).toISOString(),
|
|
193
|
-
expiresAt
|
|
194
|
-
}, io)
|
|
195
|
-
};
|
|
221
|
+
return result;
|
|
196
222
|
});
|
|
197
|
-
if (result.status === "taken" || result.status === "set") {
|
|
198
|
-
const recorded = result.status === "set" && declared ? "declared" : kind;
|
|
199
|
-
io.writeHolder(root, {
|
|
200
|
-
...io.readHolder(root),
|
|
201
|
-
[platform]: {
|
|
202
|
-
id,
|
|
203
|
-
token: result.lease.token,
|
|
204
|
-
kind: recorded
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
return result;
|
|
209
223
|
}
|
|
210
|
-
function raiseLease({ root, platform, minMs }, io = fileLeaseIo) {
|
|
211
|
-
const record = io.readHolder(root)[platform];
|
|
224
|
+
function raiseLease({ root, platform, slot = "default", minMs }, io = fileLeaseIo) {
|
|
225
|
+
const record = io.readHolder(root)[deviceSlotKey(platform, slot)];
|
|
212
226
|
if (!record) return { status: "none" };
|
|
213
227
|
const path = deviceLeasePath(platform, record.id);
|
|
214
228
|
return io.withLeaseLock(deviceLeaseLockPath(platform, record.id), () => {
|
|
@@ -239,7 +253,8 @@ function summarize(lease) {
|
|
|
239
253
|
expiresAt: lease.expiresAt
|
|
240
254
|
};
|
|
241
255
|
}
|
|
242
|
-
function releaseHeld(root, platform, record, io) {
|
|
256
|
+
function releaseHeld(root, platform, record, io, slot = "default") {
|
|
257
|
+
const key = deviceSlotKey(platform, slot);
|
|
243
258
|
const path = deviceLeasePath(platform, record.id);
|
|
244
259
|
const released = io.withLeaseLock(deviceLeaseLockPath(platform, record.id), () => {
|
|
245
260
|
const current = parseLease(io.readLease(path));
|
|
@@ -248,8 +263,8 @@ function releaseHeld(root, platform, record, io) {
|
|
|
248
263
|
return current;
|
|
249
264
|
});
|
|
250
265
|
const held = io.readHolder(root);
|
|
251
|
-
if (held[
|
|
252
|
-
delete held[
|
|
266
|
+
if (held[key]?.token === record.token) {
|
|
267
|
+
delete held[key];
|
|
253
268
|
io.writeHolder(root, held);
|
|
254
269
|
}
|
|
255
270
|
return released;
|
|
@@ -263,27 +278,33 @@ function releaseByRoot(root, platform, id, io) {
|
|
|
263
278
|
return current;
|
|
264
279
|
});
|
|
265
280
|
}
|
|
266
|
-
function releaseRunLease({ root, platform }, io = fileLeaseIo) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
281
|
+
function releaseRunLease({ root, platform, slot = "default" }, io = fileLeaseIo) {
|
|
282
|
+
return withHolderLock(io, root, () => {
|
|
283
|
+
const record = io.readHolder(root)[deviceSlotKey(platform, slot)];
|
|
284
|
+
if (!record || record.kind !== "run") return null;
|
|
285
|
+
const released = releaseHeld(root, platform, record, io, slot);
|
|
286
|
+
return released ? summarize(released) : null;
|
|
287
|
+
});
|
|
271
288
|
}
|
|
272
|
-
function releaseWorkspaceLeases(root, { platform = null } = {}, io = fileLeaseIo) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
289
|
+
function releaseWorkspaceLeases(root, { platform = null, slot = null } = {}, io = fileLeaseIo) {
|
|
290
|
+
return withHolderLock(io, root, () => {
|
|
291
|
+
const released = [];
|
|
292
|
+
for (const [name, record] of Object.entries(io.readHolder(root))) {
|
|
293
|
+
const parsed = parseDeviceSlotKey(name);
|
|
294
|
+
if (!parsed || platform && parsed.platform !== platform || slot !== null && parsed.slot !== slot) continue;
|
|
295
|
+
const lease = releaseHeld(root, parsed.platform, record, io, parsed.slot);
|
|
296
|
+
if (lease) released.push(summarize(lease));
|
|
297
|
+
}
|
|
298
|
+
for (const entry of listLeaseFiles(io)) {
|
|
299
|
+
const lease = entry.lease;
|
|
300
|
+
if (!lease || lease.holder !== root) continue;
|
|
301
|
+
if (platform && lease.platform !== platform) continue;
|
|
302
|
+
if (slot !== null && (lease.slot ?? "default") !== slot) continue;
|
|
303
|
+
const byRoot = releaseByRoot(root, lease.platform, lease.id, io);
|
|
304
|
+
if (byRoot) released.push(summarize(byRoot));
|
|
305
|
+
}
|
|
306
|
+
return released;
|
|
307
|
+
});
|
|
287
308
|
}
|
|
288
309
|
function removeExpiredLease(entry, io = fileLeaseIo) {
|
|
289
310
|
const lease = entry.lease;
|
|
@@ -331,5 +352,8 @@ function selectPoolDevice({ candidates, leases, held = null, now }) {
|
|
|
331
352
|
holders
|
|
332
353
|
};
|
|
333
354
|
}
|
|
355
|
+
function withHolderLock(io, root, fn) {
|
|
356
|
+
return io.withHolderLock ? io.withHolderLock(root, fn) : fn();
|
|
357
|
+
}
|
|
334
358
|
//#endregion
|
|
335
359
|
export { parseLease as a, releaseRunLease as c, selectPoolDevice as d, takeLease as f, listLeaseFiles as i, releaseWorkspaceLeases as l, fileLeaseIo as n, parseLeaseDuration as o, leaseIsExpired as r, raiseLease as s, deviceLeasePath as t, removeExpiredLease as u };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { I as deviceSlotKey } from "./config-CcefMY2Q.mjs";
|
|
1
2
|
import { a as formatElapsed, r as clockTime } from "./command-output-8wHMEde0.mjs";
|
|
2
|
-
import { A as APP_READINESS_TIMEOUT_MS, l as VERIFY_TIMEOUT_MS } from "./app-install-
|
|
3
|
-
import { a as parseLease, c as releaseRunLease, d as selectPoolDevice, f as takeLease, n as fileLeaseIo, r as leaseIsExpired, s as raiseLease, t as deviceLeasePath } from "./device-lease-
|
|
3
|
+
import { A as APP_READINESS_TIMEOUT_MS, l as VERIFY_TIMEOUT_MS } from "./app-install-DIp9riNx.mjs";
|
|
4
|
+
import { a as parseLease, c as releaseRunLease, d as selectPoolDevice, f as takeLease, n as fileLeaseIo, r as leaseIsExpired, s as raiseLease, t as deviceLeasePath } from "./device-lease-CJwK7OZr.mjs";
|
|
4
5
|
//#region src/engine/device-lease-run.ts
|
|
5
6
|
const LEASE_STEP_FLOOR_MS = 6e4;
|
|
6
7
|
const DEBUG_VERIFY_STEP_MS = VERIFY_TIMEOUT_MS + APP_READINESS_TIMEOUT_MS;
|
|
@@ -101,7 +102,7 @@ function lostRefusal(holder, expiresAt, now) {
|
|
|
101
102
|
lease: null
|
|
102
103
|
};
|
|
103
104
|
}
|
|
104
|
-
function runLease({ root, platform, kind, expiresAt, io = fileLeaseIo }) {
|
|
105
|
+
function runLease({ root, platform, slot = "default", kind, expiresAt, io = fileLeaseIo }) {
|
|
105
106
|
const handle = {
|
|
106
107
|
kind,
|
|
107
108
|
expiresAt,
|
|
@@ -115,6 +116,7 @@ function runLease({ root, platform, kind, expiresAt, io = fileLeaseIo }) {
|
|
|
115
116
|
const result = raiseLease({
|
|
116
117
|
root,
|
|
117
118
|
platform,
|
|
119
|
+
slot,
|
|
118
120
|
minMs: leaseStepMs(boundMs)
|
|
119
121
|
}, io);
|
|
120
122
|
if (result.status === "raised") {
|
|
@@ -137,7 +139,8 @@ function runLease({ root, platform, kind, expiresAt, io = fileLeaseIo }) {
|
|
|
137
139
|
if (handle.kind === null) return;
|
|
138
140
|
releaseRunLease({
|
|
139
141
|
root,
|
|
140
|
-
platform
|
|
142
|
+
platform,
|
|
143
|
+
slot
|
|
141
144
|
}, io);
|
|
142
145
|
},
|
|
143
146
|
facts() {
|
|
@@ -173,7 +176,7 @@ function releaseLeaseOnSignal(release, { on = (signal, handler) => {
|
|
|
173
176
|
installed.length = 0;
|
|
174
177
|
};
|
|
175
178
|
}
|
|
176
|
-
async function waitForDevice({ root, platform, id, idLabel, waitSeconds, noWait = false, appId = null, holderAppId = () => null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo, deadline, lastLine }) {
|
|
179
|
+
async function waitForDevice({ root, platform, slot = "default", id, idLabel, waitSeconds, noWait = false, appId = null, holderAppId = () => null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo, deadline, lastLine }) {
|
|
177
180
|
const path = deviceLeasePath(platform, id);
|
|
178
181
|
for (;;) {
|
|
179
182
|
const raw = io.readLease(path);
|
|
@@ -183,7 +186,7 @@ async function waitForDevice({ root, platform, id, idLabel, waitSeconds, noWait
|
|
|
183
186
|
refusal: unreadableRefusal(path)
|
|
184
187
|
};
|
|
185
188
|
if (!current || leaseIsExpired(current, now())) return { status: "free" };
|
|
186
|
-
if (current.holder === root) return {
|
|
189
|
+
if (current.holder === root && (current.slot ?? "default") === slot) return {
|
|
187
190
|
status: "ours",
|
|
188
191
|
lease: current
|
|
189
192
|
};
|
|
@@ -210,8 +213,8 @@ async function waitForDevice({ root, platform, id, idLabel, waitSeconds, noWait
|
|
|
210
213
|
await sleep(DEVICE_WAIT_POLL_MS);
|
|
211
214
|
}
|
|
212
215
|
}
|
|
213
|
-
async function acquireRunLease({ root, platform, id, deviceName = null, idLabel, waitSeconds, noWait, installBoundMs, appId = null, holderAppId = () => null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo }) {
|
|
214
|
-
const recorded = io.readHolder(root)[platform];
|
|
216
|
+
async function acquireRunLease({ root, platform, slot = "default", id, deviceName = null, idLabel, waitSeconds, noWait, installBoundMs, appId = null, holderAppId = () => null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo }) {
|
|
217
|
+
const recorded = io.readHolder(root)[deviceSlotKey(platform, slot)];
|
|
215
218
|
let held = recorded;
|
|
216
219
|
if (recorded && recorded.id !== id) {
|
|
217
220
|
const other = parseLease(io.readLease(deviceLeasePath(platform, recorded.id)));
|
|
@@ -234,6 +237,7 @@ async function acquireRunLease({ root, platform, id, deviceName = null, idLabel,
|
|
|
234
237
|
const raised = raiseLease({
|
|
235
238
|
root,
|
|
236
239
|
platform,
|
|
240
|
+
slot,
|
|
237
241
|
minMs: leaseStepMs(installBoundMs)
|
|
238
242
|
}, io);
|
|
239
243
|
if (raised.status === "raised") return {
|
|
@@ -245,6 +249,7 @@ async function acquireRunLease({ root, platform, id, deviceName = null, idLabel,
|
|
|
245
249
|
const outcome = await waitForDevice({
|
|
246
250
|
root,
|
|
247
251
|
platform,
|
|
252
|
+
slot,
|
|
248
253
|
id,
|
|
249
254
|
idLabel,
|
|
250
255
|
waitSeconds,
|
|
@@ -267,6 +272,7 @@ async function acquireRunLease({ root, platform, id, deviceName = null, idLabel,
|
|
|
267
272
|
const taken = takeLease({
|
|
268
273
|
root,
|
|
269
274
|
platform,
|
|
275
|
+
slot,
|
|
270
276
|
id,
|
|
271
277
|
deviceName,
|
|
272
278
|
kind: "run",
|
|
@@ -285,8 +291,8 @@ async function acquireRunLease({ root, platform, id, deviceName = null, idLabel,
|
|
|
285
291
|
}
|
|
286
292
|
//#endregion
|
|
287
293
|
//#region src/engine/device-pool.ts
|
|
288
|
-
function heldPoolId(root, platform, now, io = fileLeaseIo) {
|
|
289
|
-
const record = io.readHolder(root)[platform];
|
|
294
|
+
function heldPoolId(root, platform, now, io = fileLeaseIo, slot = "default") {
|
|
295
|
+
const record = io.readHolder(root)[deviceSlotKey(platform, slot)];
|
|
290
296
|
if (!record) return null;
|
|
291
297
|
const lease = parseLease(io.readLease(deviceLeasePath(platform, record.id)));
|
|
292
298
|
if (!lease || lease.token !== record.token || leaseIsExpired(lease, now)) return null;
|
|
@@ -352,8 +358,8 @@ function poolBusyRefusal(holders, leases, unreadable, now, waitSeconds) {
|
|
|
352
358
|
}
|
|
353
359
|
};
|
|
354
360
|
}
|
|
355
|
-
async function selectFromPool({ root, platform, idLabel, list, noCandidates, waitSeconds, deadline, noWait = false, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo }) {
|
|
356
|
-
const held = heldPoolId(root, platform, now(), io);
|
|
361
|
+
async function selectFromPool({ root, platform, slot = "default", idLabel, list, noCandidates, waitSeconds, deadline, noWait = false, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo }) {
|
|
362
|
+
const held = heldPoolId(root, platform, now(), io, slot);
|
|
357
363
|
const until = deadline ?? now() + waitSeconds * 1e3;
|
|
358
364
|
let lastLine = null;
|
|
359
365
|
for (;;) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CyylIdq9.mjs";
|
|
2
|
-
import { k as withDirLock, u as getConfigDir } from "./config-
|
|
3
|
-
import { D as workspaceLogsDir, O as workspaceName, T as workspaceDir, a as clearRemoteSession, c as readMetroTunnel, k as workspaceStateFile, u as readRemoteSession } from "./state-
|
|
4
|
-
import { r as pidExists } from "./metro-
|
|
5
|
-
import { z as planMetroReach } from "./settings-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { k as withDirLock, u as getConfigDir } from "./config-CcefMY2Q.mjs";
|
|
3
|
+
import { D as workspaceLogsDir, O as workspaceName, T as workspaceDir, a as clearRemoteSession, c as readMetroTunnel, k as workspaceStateFile, u as readRemoteSession } from "./state-B3XA2wp2.mjs";
|
|
4
|
+
import { r as pidExists } from "./metro-CORqXyTL.mjs";
|
|
5
|
+
import { z as planMetroReach } from "./settings-DEJf6_kJ.mjs";
|
|
6
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-IBj1Towr.mjs";
|
|
7
|
+
import { T as readMetroRecords, a as LAUNCH_ERROR, b as isBundleProof, p as devClientDeepLink, r as INSTALL_ERROR } from "./app-install-DIp9riNx.mjs";
|
|
8
|
+
import { S as sanitizeDeviceLabel } from "./ios-Deh5js5V.mjs";
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
11
11
|
import { homedir } from "node:os";
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CyylIdq9.mjs";
|
|
2
|
-
import { g as loadConfig, l as getConcurrencyLimits, o as configCorruptRepair } from "./config-
|
|
3
|
-
import { b as sharedBuildCache, w as workspaceDerivedData } from "./state-
|
|
4
|
-
import { S as makeTemporaryDirectory, a as dirtyFingerprintFiles, f as listWorktrees, g as repoRoot, s as gitCommonDir, w as temporaryRoot, x as filesystemDevice } from "./worktree-
|
|
5
|
-
import { i as detectIsExpo, t as appProjectProblem } from "./project-
|
|
6
|
-
import { d as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DDmJ1Roq.mjs";
|
|
7
|
-
import { A as resolveSettings, E as remoteAndroidSetting, I as unknownSettingKeys, M as settingOrigin, N as settingShapeErrors, O as remoteIosSetting, P as settingsLayers, U as resolveOptimizations, V as compilerCacheFallbackMessage, a as SETTING_SHAPE_REMEDY, i as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, n as PATH_SETTINGS, v as iosSimSlimProfileSetting, w as projectOptimizations, y as mergeSettingsLayers } from "./settings-DwU1_U_q.mjs";
|
|
2
|
+
import { g as loadConfig, l as getConcurrencyLimits, o as configCorruptRepair } from "./config-CcefMY2Q.mjs";
|
|
3
|
+
import { b as sharedBuildCache, w as workspaceDerivedData } from "./state-B3XA2wp2.mjs";
|
|
4
|
+
import { S as makeTemporaryDirectory, a as dirtyFingerprintFiles, f as listWorktrees, g as repoRoot, s as gitCommonDir, w as temporaryRoot, x as filesystemDevice } from "./worktree-Eq6TLH8N.mjs";
|
|
5
|
+
import { i as detectIsExpo, t as appProjectProblem } from "./project-fKmuIaMI.mjs";
|
|
8
6
|
import { d as quotedPath, u as plural } from "./command-output-8wHMEde0.mjs";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
7
|
+
import { B as listBuildLocks, Z as fingerprintProject, q as diffFingerprintSources, y as listAdbDevices } from "./android-hMj83VpN.mjs";
|
|
8
|
+
import { A as resolveSettings, E as remoteAndroidSetting, I as unknownSettingKeys, M as settingOrigin, N as settingShapeErrors, O as remoteIosSetting, P as settingsLayers, U as resolveOptimizations, V as compilerCacheFallbackMessage, a as SETTING_SHAPE_REMEDY, i as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, n as PATH_SETTINGS, v as iosSimSlimProfileSetting, w as projectOptimizations, y as mergeSettingsLayers } from "./settings-DEJf6_kJ.mjs";
|
|
9
|
+
import { a as POOL_SETTING_REMEDY, b as providerFromConfig, c as parkedMaxSetting, m as checkEasAuth$1, x as resolveEasCliBin, y as ownerFromConfig } from "./teardown--gESs9ck.mjs";
|
|
10
|
+
import { E as readHostMemoryPressure, T as hostMemoryPressureAdvice, u as listAllIosSims } from "./ios-Deh5js5V.mjs";
|
|
11
|
+
import { n as listBuildSlots } from "./build-slots-C4AouyNz.mjs";
|
|
12
|
+
import { C as liveOwnedDeviceCount, D as simslimIsOnPath, a as ccacheEnabled, g as podInstallCommand } from "./xcode-xnxyvJkD.mjs";
|
|
13
|
+
import { d as projectCmakeLauncher, i as apkOutputsDir, r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-DXorPCi_.mjs";
|
|
15
14
|
import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
|
|
16
15
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
17
16
|
import { existsSync as existsSync$1, lstatSync as lstatSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1 } from "fs";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CyylIdq9.mjs";
|
|
2
|
-
import { g as repoRoot } from "./worktree-
|
|
3
|
-
import { a as findProjectRoot } from "./project-
|
|
2
|
+
import { g as repoRoot } from "./worktree-Eq6TLH8N.mjs";
|
|
3
|
+
import { a as findProjectRoot } from "./project-fKmuIaMI.mjs";
|
|
4
4
|
import { l as phaseLine } from "./command-output-8wHMEde0.mjs";
|
|
5
|
-
import { s as detectXcodeMajor } from "./xcode-
|
|
6
|
-
import { c as repairCxxLauncherState, n as detectFingerprintParity, r as detectLinkedLibraryGitMetadata, s as runDoctor } from "./doctor-
|
|
5
|
+
import { s as detectXcodeMajor } from "./xcode-xnxyvJkD.mjs";
|
|
6
|
+
import { c as repairCxxLauncherState, n as detectFingerprintParity, r as detectLinkedLibraryGitMetadata, s as runDoctor } from "./doctor-B4EITgQB.mjs";
|
|
7
7
|
import { accessSync, constants, realpathSync, statSync } from "node:fs";
|
|
8
8
|
import { InvalidArgumentError } from "commander";
|
|
9
9
|
import { delimiter, join, resolve } from "node:path";
|