stim 1.3.1 → 1.5.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 +16 -3
- package/dist/{android-hMj83VpN.mjs → android-DJWiTBkz.mjs} +65 -72
- package/dist/{android-cas-DXorPCi_.mjs → android-cas-CSS8gjR7.mjs} +15 -12
- package/dist/{android-CT-PkXUh.mjs → android-sobvO9ia.mjs} +197 -114
- package/dist/{app-install-DIp9riNx.mjs → app-install--PAocWvq.mjs} +2 -2
- package/dist/{build-slots-C4AouyNz.mjs → build-slots-CuPszJDu.mjs} +7 -8
- package/dist/{cache-manifest-CXR-Y8pH.mjs → cache-manifest-uoOKhgUD.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +14 -13
- package/dist/collector-run.mjs +4 -4
- package/dist/{command-output-8wHMEde0.mjs → command-output-BuIb_ZOI.mjs} +1 -4
- package/dist/{config-CcefMY2Q.mjs → config-DMP7L7H6.mjs} +52 -52
- package/dist/dependency-state-CTL8A9p3.mjs +76 -0
- package/dist/{deps-0Yt0Inly.mjs → deps-BAGOnrc7.mjs} +1 -1
- package/dist/{dev-client-VfSZNLT4.mjs → dev-client-BoifdqkU.mjs} +12 -12
- package/dist/{device-Bbv45Z9Z.mjs → device-BUw4JBuH.mjs} +7 -7
- package/dist/{xcode-xnxyvJkD.mjs → device-DvKJ454A.mjs} +208 -967
- package/dist/{device-lease-CJwK7OZr.mjs → device-lease-r7yEQ1R8.mjs} +3 -3
- package/dist/{device-pool-CcBNTvM7.mjs → device-pool-DU4FQKp5.mjs} +4 -4
- package/dist/{device-remote-DAA0Zm6Z.mjs → device-remote-BTUqbl0i.mjs} +7 -6
- package/dist/{doctor-B4EITgQB.mjs → doctor-Di_B26uh.mjs} +396 -117
- package/dist/{error-diagnostics-DwhNBFDU.mjs → error-diagnostics-CTePWAzW.mjs} +7 -6
- package/dist/{gc-BRu62v4o.mjs → gc-C20dWw_8.mjs} +61 -27
- package/dist/{guide-D95E0u3i.mjs → guide-sAnoty2y.mjs} +151 -20
- package/dist/guide-status-BF6RsJJp.mjs +271 -0
- package/dist/{ios-DAju3TVy.mjs → ios-BdpkncL6.mjs} +2667 -2607
- package/dist/{ios-device-CWOM_S44.mjs → ios-device-DJOi9FR5.mjs} +1 -1
- package/dist/{logs-CAdwW6c2.mjs → logs-BfQdIhiF.mjs} +5 -5
- package/dist/metro-ato6ef3J.mjs +99 -0
- package/dist/named-ports-DH9SXd0f.mjs +137 -0
- package/dist/{ownership-8O073GIC.mjs → ownership-CD_XnpDu.mjs} +5 -5
- package/dist/{ownership-DXcol4oU.mjs → ownership-CVY9cqCr.mjs} +6 -6
- package/dist/ports-A6uTJSPj.mjs +39 -0
- package/dist/ports-BZprTJRa.mjs +90 -0
- package/dist/{project-fKmuIaMI.mjs → project-B_SDt4ip.mjs} +2 -2
- package/dist/{reclaim-CUmwucWG.mjs → reclaim-C_rB25f4.mjs} +20 -13
- package/dist/{reload-CWpXoOgN.mjs → reload-CYBJbJfI.mjs} +8 -8
- package/dist/rolldown-runtime-BsOwBuO_.mjs +30 -0
- package/dist/{server-bare-DEzPZLvf.mjs → server-bare-H3pAhbMs.mjs} +11 -35
- package/dist/server-expo-CSwUVYOa.mjs +2 -0
- package/dist/{server-expo-DizT4OMk.mjs → server-expo-Ds8_mfng.mjs} +6 -14
- package/dist/{settings-DEJf6_kJ.mjs → settings-kO2ZqIKy.mjs} +2 -2
- package/dist/{slot-launch-CZklomj6.mjs → slot-launch-BpHiHH6A.mjs} +4 -4
- package/dist/{start-B5G4NjiA.mjs → start-DiEfqEWk.mjs} +20 -22
- package/dist/state-CnWzvCWP.mjs +131 -0
- package/dist/{stats-CaaQr4yN.mjs → stats-DHrO0frH.mjs} +4 -4
- package/dist/{stats-BR-kwj0B.mjs → stats-Fo9ACIv7.mjs} +1 -1
- package/dist/{status-CI9clRSb.mjs → status-J5LAXpag.mjs} +15 -12
- package/dist/{stop-CjlgDk0a.mjs → stop-0jJNahwN.mjs} +15 -14
- package/dist/{stop-CQhffpmX.mjs → stop-CM1fejKW.mjs} +2 -2
- package/dist/supervisor-run.d.mts +7 -28
- package/dist/supervisor-run.mjs +20 -11
- package/dist/{teardown--gESs9ck.mjs → teardown-CAVcWeRD.mjs} +148 -109
- package/dist/{workspace-process-lock-IBj1Towr.mjs → workspace-process-lock-Bz19_R9R.mjs} +4 -4
- package/dist/workspace-state-WVwWw_hB.mjs +146 -0
- package/dist/{worktree-DtQGO9-s.mjs → worktree-CeUKDAQw.mjs} +38 -34
- package/dist/{worktree-Eq6TLH8N.mjs → worktree-DJnBbQZ9.mjs} +79 -22
- package/dist/xcode-BqDeRkpT.mjs +860 -0
- package/package.json +7 -7
- package/shim/expo-metro-config.cjs +11 -17
- package/dist/doctor-BueDfLYG.mjs +0 -530
- package/dist/metro-CORqXyTL.mjs +0 -184
- package/dist/ownership-claim-BtPtJVmq.mjs +0 -584
- package/dist/server-expo-44em5Pmg.mjs +0 -2
- package/dist/state-B3XA2wp2.mjs +0 -268
- package/shim/metro-cache-generation.cjs +0 -20
- package/shim/metro-cache-generation.d.cts +0 -5
package/dist/supervisor-run.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as clearSupervisor, w as process_identity_exports, x as setSupervisor } from "./config-DMP7L7H6.mjs";
|
|
2
2
|
import { r as createNdjsonWriter } from "./ndjson-BZwI1NBv.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { i as detectIsExpo } from "./project-
|
|
3
|
+
import { _ as workspaceLogsDir, a as withWorkspaceStateLock, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-WVwWw_hB.mjs";
|
|
4
|
+
import { i as detectIsExpo } from "./project-B_SDt4ip.mjs";
|
|
5
5
|
import { t as describeError } from "./errors-B6W7FkxQ.mjs";
|
|
6
|
+
import { c as readPidFile, f as writePidFile, n as MODE_EXPO, o as clearWorkspaceSupervisor, r as clearExpoMetroTunnel, t as MODE_BARE } from "./state-CnWzvCWP.mjs";
|
|
6
7
|
import { existsSync, realpathSync } from "node:fs";
|
|
7
8
|
import { isAbsolute, join, resolve } from "node:path";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
@@ -11,6 +12,7 @@ function parseArgs(argv) {
|
|
|
11
12
|
let root;
|
|
12
13
|
let port;
|
|
13
14
|
let tunnel = false;
|
|
15
|
+
let resetCache = false;
|
|
14
16
|
for (let i = 0; i < argv.length; i++) {
|
|
15
17
|
const arg = argv[i];
|
|
16
18
|
if (arg === "--root") {
|
|
@@ -25,25 +27,30 @@ function parseArgs(argv) {
|
|
|
25
27
|
tunnel = true;
|
|
26
28
|
continue;
|
|
27
29
|
}
|
|
28
|
-
|
|
30
|
+
if (arg === "--reset-cache") {
|
|
31
|
+
resetCache = true;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
return { error: `Unknown supervisor argument "${arg}". Usage: run.js --root <path> --port <n> [--tunnel] [--reset-cache]` };
|
|
29
35
|
}
|
|
30
|
-
if (!root) return { error: "Missing --root. Usage: run.js --root <path> --port <n> [--tunnel]" };
|
|
36
|
+
if (!root) return { error: "Missing --root. Usage: run.js --root <path> --port <n> [--tunnel] [--reset-cache]" };
|
|
31
37
|
if (!isAbsolute(root)) return { error: `--root must be an absolute path, got "${root}".` };
|
|
32
38
|
const parsedPort = Number(port);
|
|
33
39
|
if (!Number.isInteger(parsedPort) || parsedPort <= 0 || parsedPort > 65535) return { error: `--port must be a TCP port number, got "${port}".` };
|
|
34
40
|
return {
|
|
35
41
|
root: resolve(root),
|
|
36
42
|
port: parsedPort,
|
|
37
|
-
tunnel
|
|
43
|
+
tunnel,
|
|
44
|
+
resetCache
|
|
38
45
|
};
|
|
39
46
|
}
|
|
40
|
-
async function runSupervisor({ root, port, tunnel = false, isExpo = detectIsExpo, startBare = null, startExpo = null, now = Date.now, onExit = (code) => process.exit(code), attachSignals = true, stderr = (line) => console.error(line) }) {
|
|
47
|
+
async function runSupervisor({ root, port, tunnel = false, resetCache = false, isExpo = detectIsExpo, startBare = null, startExpo = null, now = Date.now, onExit = (code) => process.exit(code), attachSignals = true, stderr = (line) => console.error(line) }) {
|
|
41
48
|
root = realpathSync(root);
|
|
42
49
|
const logsDir = workspaceLogsDir(root);
|
|
43
50
|
const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"));
|
|
44
51
|
const mode = isExpo(root) ? MODE_EXPO : MODE_BARE;
|
|
45
52
|
const startedAt = new Date(now()).toISOString();
|
|
46
|
-
const processToken = captureProcessToken(process.pid);
|
|
53
|
+
const processToken = (0, process_identity_exports.captureProcessToken)(process.pid);
|
|
47
54
|
if (!processToken) {
|
|
48
55
|
stderr("Stim supervisor: could not capture process identity; refusing to start an unmanaged server.");
|
|
49
56
|
writer.close();
|
|
@@ -97,12 +104,13 @@ async function runSupervisor({ root, port, tunnel = false, isExpo = detectIsExpo
|
|
|
97
104
|
};
|
|
98
105
|
let server;
|
|
99
106
|
try {
|
|
100
|
-
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-
|
|
107
|
+
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-CSwUVYOa.mjs")).startExpoServer : startBare || (await import("./server-bare-H3pAhbMs.mjs")).startBareServer)({
|
|
101
108
|
root,
|
|
102
109
|
port,
|
|
103
110
|
logsDir,
|
|
104
111
|
writer,
|
|
105
112
|
tunnel,
|
|
113
|
+
resetCache,
|
|
106
114
|
onTunnelUrl: (url) => {
|
|
107
115
|
try {
|
|
108
116
|
withWorkspaceStateLock(root, () => {
|
|
@@ -190,7 +198,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
190
198
|
await runSupervisor({
|
|
191
199
|
root,
|
|
192
200
|
port: parsed.port,
|
|
193
|
-
tunnel: parsed.tunnel ?? false
|
|
201
|
+
tunnel: parsed.tunnel ?? false,
|
|
202
|
+
resetCache: parsed.resetCache ?? false
|
|
194
203
|
});
|
|
195
204
|
}
|
|
196
205
|
function invokedDirectly() {
|
|
@@ -207,4 +216,4 @@ if (invokedDirectly()) main().catch((err) => {
|
|
|
207
216
|
process.exit(1);
|
|
208
217
|
});
|
|
209
218
|
//#endregion
|
|
210
|
-
export { MODE_BARE, MODE_EXPO, clearExpoMetroTunnel, clearWorkspaceSupervisor, main, parseArgs, readPidFile,
|
|
219
|
+
export { MODE_BARE, MODE_EXPO, clearExpoMetroTunnel, clearWorkspaceSupervisor, main, parseArgs, readPidFile, runSupervisor, writePidFile };
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CyylIdq9.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { C as withConfigLock, E as ownership_claim_exports, F as deviceSlotPlatforms, L as projectDeviceSlots, N as assignSlotDevice, R as removeSlotDevice, T as acquireAvdClaim, d as getConfigPath, g as loadConfig, s as ensureConfig, u as getConfigDir, y as saveConfig } from "./config-DMP7L7H6.mjs";
|
|
3
3
|
import { r as createNdjsonWriter } from "./ndjson-BZwI1NBv.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { l as resolvePackageJson } from "./project-
|
|
4
|
+
import { _ as workspaceLogsDir } from "./workspace-state-WVwWw_hB.mjs";
|
|
5
|
+
import { l as resolvePackageJson } from "./project-B_SDt4ip.mjs";
|
|
6
6
|
import { n as stripAnsi } from "./process-output-C7IlIzd7.mjs";
|
|
7
|
-
import { l as phaseLine } from "./command-output-
|
|
8
|
-
import { E as ownedAvdMatchesConfiguration, F as shutdownAndroidEmulator, I as waitForAndroidEmulatorShutdown, N as resolveOwnedAvdSerial, O as ownedAvdSystemImage, S as listOrphanedAvdDirectories, T as ownedAvdDirectory, l as avdStorageRoots, o as assertOwnedAvdStopped, p as deleteAvd, s as avdPathExists } from "./android-
|
|
9
|
-
import { n as expoBinFromPackage, r as expoBinPath, s as findBinUpward } from "./server-expo-
|
|
7
|
+
import { l as phaseLine } from "./command-output-BuIb_ZOI.mjs";
|
|
8
|
+
import { E as ownedAvdMatchesConfiguration, F as shutdownAndroidEmulator, I as waitForAndroidEmulatorShutdown, N as resolveOwnedAvdSerial, O as ownedAvdSystemImage, S as listOrphanedAvdDirectories, T as ownedAvdDirectory, l as avdStorageRoots, o as assertOwnedAvdStopped, p as deleteAvd, s as avdPathExists } from "./android-DJWiTBkz.mjs";
|
|
9
|
+
import { n as expoBinFromPackage, r as expoBinPath, s as findBinUpward } from "./server-expo-Ds8_mfng.mjs";
|
|
10
10
|
import { C as shutdownIosSim, _ as renameIosSim, a as deleteIosSim, d as listIosDeviceTypes, g as parseRuntimeVersion, h as parkedSimName, o as deleteParkedIosSim, r as clearAppDataContainer, s as findAppDataContainer, x as resolveOwnedIosSim } from "./ios-Deh5js5V.mjs";
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
12
|
import { existsSync, lstatSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
14
|
import { dirname, join } from "node:path";
|
|
15
15
|
import { pathToFileURL } from "node:url";
|
|
16
|
-
import { format } from "node:util";
|
|
16
|
+
import { format, isDeepStrictEqual } from "node:util";
|
|
17
17
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
18
|
//#region src/engine/remote-cache.ts
|
|
19
19
|
const EAS_PROVIDER_PACKAGE = "eas-build-cache-provider";
|
|
@@ -593,8 +593,14 @@ function writeParked(config, platform, records) {
|
|
|
593
593
|
function oldestFirst(records) {
|
|
594
594
|
return records.toSorted((a, b) => String(a.parkedAt).localeCompare(String(b.parkedAt)));
|
|
595
595
|
}
|
|
596
|
+
function isLegacyDeletionClaim(value) {
|
|
597
|
+
if (value === void 0) return false;
|
|
598
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return true;
|
|
599
|
+
const marker = value;
|
|
600
|
+
return marker.kind !== "ownership-claim" || typeof marker.claimId !== "string" || marker.claimId.length === 0;
|
|
601
|
+
}
|
|
596
602
|
function selectParked(records, { deviceTypeIdentifier, runtimeIdentifier }) {
|
|
597
|
-
return oldestFirst(records.filter((r) => r.deletionClaim
|
|
603
|
+
return oldestFirst(records.filter((r) => !isLegacyDeletionClaim(r.deletionClaim) && r.deviceTypeIdentifier === deviceTypeIdentifier && r.runtimeIdentifier === runtimeIdentifier));
|
|
598
604
|
}
|
|
599
605
|
function evictOverflow(records, max) {
|
|
600
606
|
if (records.length <= max) return {
|
|
@@ -624,98 +630,91 @@ function parkSim({ platform, projectPath, slot = "default", record, max }) {
|
|
|
624
630
|
});
|
|
625
631
|
}
|
|
626
632
|
function adoptParked({ platform, projectPath, slot = "default", udid, device }) {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
const records = readParked(platform, { config: cfg });
|
|
630
|
-
const taken = records.find((r) => r.udid === udid);
|
|
631
|
-
if (!taken || taken.deletionClaim !== void 0) return null;
|
|
632
|
-
if (deviceSlotPlatforms(cfg.projects[projectPath], slot)?.[platform]) return null;
|
|
633
|
-
writeParked(cfg, platform, records.filter((r) => r.udid !== udid));
|
|
634
|
-
const project = cfg.projects[projectPath];
|
|
635
|
-
if (!project) throw new Error(`Project not registered: ${projectPath}`);
|
|
636
|
-
assignSlotDevice(project, platform, device, slot);
|
|
637
|
-
saveConfig(cfg);
|
|
638
|
-
return taken;
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
function isProcessAlive(pid) {
|
|
633
|
+
const claim = claimParkedOperation(platform, udid);
|
|
634
|
+
if (!claim) return null;
|
|
642
635
|
try {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
636
|
+
return withConfigLock(() => {
|
|
637
|
+
const cfg = ensureConfig();
|
|
638
|
+
const records = readParked(platform, { config: cfg });
|
|
639
|
+
const taken = records.find((r) => r.udid === udid);
|
|
640
|
+
if (!taken || isLegacyDeletionClaim(taken.deletionClaim)) return null;
|
|
641
|
+
if (deviceSlotPlatforms(cfg.projects[projectPath], slot)?.[platform]) return null;
|
|
642
|
+
writeParked(cfg, platform, records.filter((r) => r.udid !== udid));
|
|
643
|
+
const project = cfg.projects[projectPath];
|
|
644
|
+
if (!project) throw new Error(`Project not registered: ${projectPath}`);
|
|
645
|
+
assignSlotDevice(project, platform, device, slot);
|
|
646
|
+
saveConfig(cfg);
|
|
647
|
+
const adopted = { ...taken };
|
|
648
|
+
delete adopted.deletionClaim;
|
|
649
|
+
return adopted;
|
|
650
|
+
});
|
|
651
|
+
} finally {
|
|
652
|
+
(0, ownership_claim_exports.releaseClaim)(claim);
|
|
647
653
|
}
|
|
648
654
|
}
|
|
649
|
-
function
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
return {
|
|
655
|
-
pid: claim.pid,
|
|
656
|
-
token: claim.token
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
function claimParkedRemoval(platform, udid) {
|
|
660
|
-
return withConfigLock(() => {
|
|
661
|
-
const cfg = loadConfig();
|
|
662
|
-
if (!cfg) return null;
|
|
663
|
-
const records = readParked(platform, { config: cfg });
|
|
664
|
-
const record = records.find((candidate) => candidate.udid === udid);
|
|
665
|
-
if (!record) return null;
|
|
666
|
-
const existingClaim = parseDeletionClaim(record.deletionClaim);
|
|
667
|
-
if (record.deletionClaim !== void 0 && (!existingClaim || isProcessAlive(existingClaim.pid))) return null;
|
|
668
|
-
const token = randomUUID();
|
|
669
|
-
const claimedRecord = {
|
|
670
|
-
...record,
|
|
671
|
-
deletionClaim: {
|
|
672
|
-
pid: process.pid,
|
|
673
|
-
token
|
|
674
|
-
}
|
|
675
|
-
};
|
|
676
|
-
writeParked(cfg, platform, records.map((candidate) => candidate.udid === udid ? claimedRecord : candidate));
|
|
677
|
-
saveConfig(cfg);
|
|
678
|
-
const claimed = { ...record };
|
|
679
|
-
delete claimed.deletionClaim;
|
|
680
|
-
return {
|
|
681
|
-
record: claimed,
|
|
682
|
-
token
|
|
683
|
-
};
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
function clearParkedRemovalClaim(platform, udid, token) {
|
|
687
|
-
withConfigLock(() => {
|
|
688
|
-
const cfg = loadConfig();
|
|
689
|
-
if (!cfg) return;
|
|
690
|
-
const records = readParked(platform, { config: cfg });
|
|
691
|
-
const record = records.find((candidate) => candidate.udid === udid);
|
|
692
|
-
if (!record || parseDeletionClaim(record.deletionClaim)?.token !== token) return;
|
|
693
|
-
const restored = { ...record };
|
|
694
|
-
delete restored.deletionClaim;
|
|
695
|
-
writeParked(cfg, platform, records.map((candidate) => candidate.udid === udid ? restored : candidate));
|
|
696
|
-
saveConfig(cfg);
|
|
655
|
+
function claimParkedOperation(platform, udid) {
|
|
656
|
+
const attempt = (0, ownership_claim_exports.tryAcquireClaim)({
|
|
657
|
+
root: join(getConfigDir(), "pool-locks", platform, `${encodeURIComponent(udid.toLowerCase())}.lock`),
|
|
658
|
+
mode: "exclusive",
|
|
659
|
+
label: `parked ${platform} device ${udid}`
|
|
697
660
|
});
|
|
661
|
+
if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
|
|
662
|
+
return attempt.acquired ?? null;
|
|
698
663
|
}
|
|
699
664
|
function removeParkedAfter(platform, udid, beforeRemove) {
|
|
700
|
-
const claim =
|
|
665
|
+
const claim = claimParkedOperation(platform, udid);
|
|
701
666
|
if (!claim) return null;
|
|
702
667
|
try {
|
|
703
|
-
|
|
704
|
-
|
|
668
|
+
const claimed = withConfigLock(() => {
|
|
669
|
+
const cfg = loadConfig();
|
|
670
|
+
if (!cfg) return null;
|
|
671
|
+
const records = readParked(platform, { config: cfg });
|
|
672
|
+
const current = records.find((candidate) => candidate.udid === udid);
|
|
673
|
+
if (!current) return null;
|
|
674
|
+
if (isLegacyDeletionClaim(current.deletionClaim)) throw new Error(`Parked ${platform} device ${udid} has a legacy deletionClaim in ${getConfigPath()}. Its PID does not establish whether the original operation finished. Keep the device and pool record; after verifying that neither the old Stim process nor its native child is using it, remove only that record's deletionClaim field and retry.`);
|
|
675
|
+
const record = { ...current };
|
|
676
|
+
delete record.deletionClaim;
|
|
677
|
+
const marked = {
|
|
678
|
+
...record,
|
|
679
|
+
deletionClaim: {
|
|
680
|
+
kind: "ownership-claim",
|
|
681
|
+
claimId: claim.claimId
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
writeParked(cfg, platform, records.map((candidate) => candidate.udid === udid ? marked : candidate));
|
|
685
|
+
saveConfig(cfg);
|
|
686
|
+
return {
|
|
687
|
+
record,
|
|
688
|
+
marked
|
|
689
|
+
};
|
|
690
|
+
});
|
|
691
|
+
if (!claimed) return null;
|
|
692
|
+
let completed = false;
|
|
693
|
+
let removed = null;
|
|
705
694
|
try {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
695
|
+
(0, ownership_claim_exports.markClaimChildPending)(claim);
|
|
696
|
+
try {
|
|
697
|
+
beforeRemove(claimed.record);
|
|
698
|
+
} finally {
|
|
699
|
+
(0, ownership_claim_exports.clearClaimChild)(claim);
|
|
700
|
+
}
|
|
701
|
+
completed = true;
|
|
702
|
+
} finally {
|
|
703
|
+
withConfigLock(() => {
|
|
704
|
+
const cfg = loadConfig();
|
|
705
|
+
if (!cfg) return;
|
|
706
|
+
const records = readParked(platform, { config: cfg });
|
|
707
|
+
const current = records.find((candidate) => candidate.udid === udid);
|
|
708
|
+
if (!isDeepStrictEqual(current, claimed.marked)) return;
|
|
709
|
+
writeParked(cfg, platform, completed ? records.filter((candidate) => candidate.udid !== udid) : records.map((candidate) => candidate.udid === udid ? claimed.record : candidate));
|
|
710
|
+
saveConfig(cfg);
|
|
711
|
+
if (completed) removed = claimed.record;
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
return removed;
|
|
715
|
+
} finally {
|
|
716
|
+
(0, ownership_claim_exports.releaseClaim)(claim);
|
|
709
717
|
}
|
|
710
|
-
return withConfigLock(() => {
|
|
711
|
-
const cfg = loadConfig();
|
|
712
|
-
if (!cfg) return null;
|
|
713
|
-
const records = readParked(platform, { config: cfg });
|
|
714
|
-
if (parseDeletionClaim(records.find((candidate) => candidate.udid === udid)?.deletionClaim)?.token !== claim.token) return null;
|
|
715
|
-
writeParked(cfg, platform, records.filter((candidate) => candidate.udid !== udid));
|
|
716
|
-
saveConfig(cfg);
|
|
717
|
-
return claim.record;
|
|
718
|
-
});
|
|
719
718
|
}
|
|
720
719
|
function dropParked(platform, udid) {
|
|
721
720
|
return removeParkedAfter(platform, udid, () => {}) !== null;
|
|
@@ -942,18 +941,24 @@ function teardownOwnedIosSim(udid, { del = false, label, park } = {}) {
|
|
|
942
941
|
};
|
|
943
942
|
}
|
|
944
943
|
}
|
|
944
|
+
function assertAvdReferences(avdName, owner) {
|
|
945
|
+
const config = loadConfig();
|
|
946
|
+
if (!config) throw new Error("Cannot verify AVD references without a Stim config; the data was kept.");
|
|
947
|
+
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.`);
|
|
948
|
+
for (const [projectPath, project] of Object.entries(config.projects)) for (const { slot, platforms } of projectDeviceSlots(project)) {
|
|
949
|
+
if (platforms.android?.avdName?.toLowerCase() !== avdName.toLowerCase()) continue;
|
|
950
|
+
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.`);
|
|
951
|
+
}
|
|
952
|
+
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.`);
|
|
953
|
+
}
|
|
945
954
|
function removeOrphanedAvdDirectory(candidate, owner) {
|
|
955
|
+
const surveyed = listOrphanedAvdDirectories(candidate.name).find((entry) => entry.directory === candidate.directory);
|
|
956
|
+
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.`);
|
|
957
|
+
assertOwnedAvdStopped(candidate.name, { resolveDirectory: () => candidate.directory });
|
|
946
958
|
const detached = withConfigLock(() => {
|
|
947
|
-
const current =
|
|
948
|
-
if (!current
|
|
949
|
-
|
|
950
|
-
if (!config) throw new Error("Cannot verify AVD references without a Stim config; the data was kept.");
|
|
951
|
-
for (const [projectPath, project] of Object.entries(config.projects)) for (const { platforms } of projectDeviceSlots(project)) {
|
|
952
|
-
if (platforms.android?.avdName !== candidate.name) continue;
|
|
953
|
-
if (!owner || !("projectPath" in owner) || owner.projectPath !== projectPath || !platforms.android.owned) throw new Error(`AVD ${candidate.name} is referenced by ${projectPath}; its data was kept.`);
|
|
954
|
-
}
|
|
955
|
-
if (readParked("android", { config }).some((entry) => entry.name === candidate.name) && !(owner && "pool" in owner)) throw new Error(`AVD ${candidate.name} is in the emulator pool; its data was kept.`);
|
|
956
|
-
assertOwnedAvdStopped(candidate.name, { resolveDirectory: () => candidate.directory });
|
|
959
|
+
const current = lstatSync(candidate.directory);
|
|
960
|
+
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.`);
|
|
961
|
+
assertAvdReferences(candidate.name, owner);
|
|
957
962
|
const destination = join(dirname(candidate.directory), `stim-gc-${randomUUID()}.avd`);
|
|
958
963
|
renameSync(candidate.directory, destination);
|
|
959
964
|
return destination;
|
|
@@ -985,14 +990,31 @@ function teardownUnregisteredAvd(avdName, del, owner, surveyed) {
|
|
|
985
990
|
label: avdName
|
|
986
991
|
};
|
|
987
992
|
}
|
|
988
|
-
function teardownOwnedAvd(avdName,
|
|
989
|
-
|
|
993
|
+
function teardownOwnedAvd(avdName, options = {}) {
|
|
994
|
+
if (!/^stim-[A-Za-z0-9._-]+$/.test(avdName)) return {
|
|
995
|
+
status: "skipped",
|
|
996
|
+
kind: "not-owned",
|
|
997
|
+
reason: `AVD ${avdName} is not Stim-owned by name`
|
|
998
|
+
};
|
|
999
|
+
let claim;
|
|
990
1000
|
try {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1001
|
+
claim = acquireAvdClaim(avdName);
|
|
1002
|
+
const result = teardownClaimedAvd(avdName, claim, options);
|
|
1003
|
+
if (result.status === "torn-down" || result.status === "missing") options.onRemoved?.();
|
|
1004
|
+
return result;
|
|
1005
|
+
} catch (error) {
|
|
1006
|
+
return {
|
|
1007
|
+
status: "failed",
|
|
1008
|
+
reason: String(error?.message || error)
|
|
995
1009
|
};
|
|
1010
|
+
} finally {
|
|
1011
|
+
(0, ownership_claim_exports.releaseClaim)(claim);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
function teardownClaimedAvd(avdName, claim, { del = false, park, owner, orphanedDirectory, onlyIfMissing = false, waitForShutdown = waitForAndroidEmulatorShutdown, assertStopped = assertOwnedAvdStopped, resolveAvd = resolveOwnedAvdSerial }) {
|
|
1015
|
+
let parkFallback;
|
|
1016
|
+
try {
|
|
1017
|
+
if (del) withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
996
1018
|
const resolved = resolveAvd(avdName);
|
|
997
1019
|
if (resolved.notOwned) return {
|
|
998
1020
|
status: "skipped",
|
|
@@ -1000,6 +1022,10 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
1000
1022
|
reason: `AVD ${avdName} is not Stim-owned by name`
|
|
1001
1023
|
};
|
|
1002
1024
|
if (resolved.missing) return teardownUnregisteredAvd(avdName, del, owner, orphanedDirectory);
|
|
1025
|
+
if (onlyIfMissing) return {
|
|
1026
|
+
status: "skipped",
|
|
1027
|
+
reason: "AVD registration appeared; its record was kept."
|
|
1028
|
+
};
|
|
1003
1029
|
if (orphanedDirectory) return {
|
|
1004
1030
|
status: "skipped",
|
|
1005
1031
|
reason: "AVD registration appeared; its data was kept."
|
|
@@ -1015,7 +1041,14 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
1015
1041
|
id: serial
|
|
1016
1042
|
}, stillOwned);
|
|
1017
1043
|
if (!stillOwned()) throw new Error(`Owned AVD ${avdName} changed before shutdown; it was kept.`);
|
|
1018
|
-
waitForShutdown(avdName, (timeoutMs) =>
|
|
1044
|
+
waitForShutdown(avdName, (timeoutMs) => {
|
|
1045
|
+
(0, ownership_claim_exports.markClaimChildPending)(claim);
|
|
1046
|
+
try {
|
|
1047
|
+
shutdownAndroidEmulator(serial, timeoutMs);
|
|
1048
|
+
} finally {
|
|
1049
|
+
(0, ownership_claim_exports.clearClaimChild)(claim);
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1019
1052
|
} else assertStopped(avdName);
|
|
1020
1053
|
if (del) {
|
|
1021
1054
|
const current = resolveAvd(avdName);
|
|
@@ -1027,6 +1060,7 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
1027
1060
|
if (current.missing) return teardownUnregisteredAvd(avdName, del, owner);
|
|
1028
1061
|
if (current.serial) throw new Error(`Owned AVD ${avdName} started again before deletion.`);
|
|
1029
1062
|
assertStopped(avdName);
|
|
1063
|
+
withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
1030
1064
|
if (park && park.max > 0) try {
|
|
1031
1065
|
const systemImage = ownedAvdSystemImage(avdName);
|
|
1032
1066
|
if (!systemImage || !park.configuration || !ownedAvdMatchesConfiguration(avdName, park.configuration)) throw new Error("the AVD has no verified creation configuration");
|
|
@@ -1071,7 +1105,12 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
1071
1105
|
const directory = ownedAvdDirectory(avdName);
|
|
1072
1106
|
const paths = avdStorageRoots().map((root) => join(root, `${avdName}.ini`));
|
|
1073
1107
|
if (directory) paths.push(directory);
|
|
1074
|
-
|
|
1108
|
+
(0, ownership_claim_exports.markClaimChildPending)(claim);
|
|
1109
|
+
try {
|
|
1110
|
+
deleteAvd(avdName);
|
|
1111
|
+
} finally {
|
|
1112
|
+
(0, ownership_claim_exports.clearClaimChild)(claim);
|
|
1113
|
+
}
|
|
1075
1114
|
const remaining = paths.filter(avdPathExists);
|
|
1076
1115
|
if (remaining.length) throw new Error(`AVD ${avdName} was only partially deleted; data remains at ${remaining.join(", ")}.`);
|
|
1077
1116
|
}
|
|
@@ -1089,4 +1128,4 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
1089
1128
|
}
|
|
1090
1129
|
}
|
|
1091
1130
|
//#endregion
|
|
1092
|
-
export {
|
|
1131
|
+
export { resolveRemote as C, resolveEasCliBin as S, exitAfterFlush as _, POOL_SETTING_REMEDY as a, ownerFromConfig as b, isLegacyDeletionClaim as c, selectParked as d, RESOLVE_TIMEOUT_MS as f, easAuthNote as g, checkEasAuth as h, teardownParkedIosSim as i, parkedMaxSetting as l, cacheLevel as m, teardownOwnedIosSim as n, adoptParked as o, UPLOAD_TIMEOUT_MS as p, teardownParkedAvd as r, dropParked as s, teardownOwnedAvd as t, readParked as u, isEasAuthFailureText as v, uploadRemote as w, providerFromConfig as x, loadProjectProvider as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as ownership_claim_exports } from "./config-DMP7L7H6.mjs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
//#region src/engine/workspace-process-lock.ts
|
|
4
4
|
const DEFAULT_WAIT_MS = 6e4;
|
|
@@ -17,17 +17,17 @@ async function withWorkspaceProcessLock(root, name, fn, { now = Date.now, sleep
|
|
|
17
17
|
const path = lockPath(root, name, external);
|
|
18
18
|
const deadline = now() + waitMs;
|
|
19
19
|
for (;;) {
|
|
20
|
-
const attempt = tryAcquireClaim({
|
|
20
|
+
const attempt = (0, ownership_claim_exports.tryAcquireClaim)({
|
|
21
21
|
root: path,
|
|
22
22
|
mode: "exclusive",
|
|
23
23
|
label: `${name} lock`,
|
|
24
24
|
details: ownerPurpose ? { purpose: ownerPurpose } : {}
|
|
25
25
|
});
|
|
26
|
-
if (attempt.pending) releaseClaim(attempt.pending);
|
|
26
|
+
if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
|
|
27
27
|
if (attempt.acquired) try {
|
|
28
28
|
return await fn();
|
|
29
29
|
} finally {
|
|
30
|
-
releaseClaim(attempt.acquired);
|
|
30
|
+
(0, ownership_claim_exports.releaseClaim)(attempt.acquired);
|
|
31
31
|
}
|
|
32
32
|
const purpose = (attempt.held ?? attempt.waitingFor?.[0])?.details.purpose;
|
|
33
33
|
if (typeof purpose === "string" && rejectOwnerPurposes.includes(purpose)) {
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { D as withDirLock, u as getConfigDir } from "./config-DMP7L7H6.mjs";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { join as join$1, resolve as resolve$1 } from "path";
|
|
5
|
+
import { buildCacheRoot as sharedBuildCache, workspaceId, workspaceName as workspaceName$1, workspaceStateDir as workspaceDir } from "@stim-cli/core";
|
|
6
|
+
//#region src/paths.ts
|
|
7
|
+
const WORKSPACE_METADATA_FILE_NAME = "workspace.json";
|
|
8
|
+
function workspaceMetadataFile(projectRoot) {
|
|
9
|
+
return join$1(workspaceDir(projectRoot), WORKSPACE_METADATA_FILE_NAME);
|
|
10
|
+
}
|
|
11
|
+
function ensureWorkspaceStorage(projectRoot) {
|
|
12
|
+
const canonicalRoot = resolve$1(projectRoot);
|
|
13
|
+
const dir = workspaceDir(canonicalRoot);
|
|
14
|
+
const file = workspaceMetadataFile(canonicalRoot);
|
|
15
|
+
mkdirSync(dir, { recursive: true });
|
|
16
|
+
return withDirLock(join$1(dir, "metadata.lock"), () => {
|
|
17
|
+
if (!existsSync(file)) {
|
|
18
|
+
const metadata = {
|
|
19
|
+
projectRoot: canonicalRoot,
|
|
20
|
+
workspace: workspaceName$1(canonicalRoot),
|
|
21
|
+
version: 1
|
|
22
|
+
};
|
|
23
|
+
const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
24
|
+
writeFileSync(tmp, `${JSON.stringify(metadata, null, 2)}\n`);
|
|
25
|
+
try {
|
|
26
|
+
renameSync(tmp, file);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
rmSync(tmp, { force: true });
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
return dir;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
if (JSON.parse(readFileSync(file, "utf-8")).projectRoot === canonicalRoot) return dir;
|
|
35
|
+
} catch {}
|
|
36
|
+
const error = /* @__PURE__ */ new Error(`Stim workspace collision at ${dir}: its workspace.json does not belong to ${canonicalRoot}.`);
|
|
37
|
+
error.code = "STIM_WORKSPACE_COLLISION";
|
|
38
|
+
throw error;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function workspaceLogsDir(projectRoot) {
|
|
42
|
+
return join$1(workspaceDir(projectRoot), "logs");
|
|
43
|
+
}
|
|
44
|
+
function workspaceDerivedData(projectRoot) {
|
|
45
|
+
return join$1(workspaceDir(projectRoot), "derived-data");
|
|
46
|
+
}
|
|
47
|
+
function supervisorPidFile(projectRoot) {
|
|
48
|
+
return join$1(workspaceDir(projectRoot), "supervisor.pid");
|
|
49
|
+
}
|
|
50
|
+
function workspaceStateFile(projectRoot) {
|
|
51
|
+
return join$1(workspaceDir(projectRoot), "state.json");
|
|
52
|
+
}
|
|
53
|
+
function workspaceStateLock(projectRoot) {
|
|
54
|
+
return join$1(workspaceDir(projectRoot), "state.lock");
|
|
55
|
+
}
|
|
56
|
+
function supervisorLogFile(projectRoot) {
|
|
57
|
+
return join$1(workspaceLogsDir(projectRoot), "supervisor.log");
|
|
58
|
+
}
|
|
59
|
+
function emulatorLogFile(projectRoot) {
|
|
60
|
+
return join$1(workspaceLogsDir(projectRoot), "emulator.log");
|
|
61
|
+
}
|
|
62
|
+
function sharedCompilationCache() {
|
|
63
|
+
return join$1(getConfigDir(), "compilation-cache");
|
|
64
|
+
}
|
|
65
|
+
function sharedCcache() {
|
|
66
|
+
return join$1(getConfigDir(), "ccache");
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/workspace-state.ts
|
|
70
|
+
function readWorkspaceState(root) {
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse(readFileSync(workspaceStateFile(root), "utf-8"));
|
|
73
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
74
|
+
return parsed;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function withWorkspaceStateLock(root, fn) {
|
|
80
|
+
const file = workspaceStateFile(root);
|
|
81
|
+
return withDirLock(workspaceStateLock(root), fn, { ensureParent: () => {
|
|
82
|
+
ensureWorkspaceStorage(root);
|
|
83
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
84
|
+
} });
|
|
85
|
+
}
|
|
86
|
+
function writeWorkspaceState(root, patch) {
|
|
87
|
+
return updateWorkspaceState(root, (state) => ({
|
|
88
|
+
...state,
|
|
89
|
+
...patch
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
function updateWorkspaceState(root, update) {
|
|
93
|
+
return withWorkspaceStateLock(root, () => replaceWorkspaceState(root, update(readWorkspaceState(root) ?? {})));
|
|
94
|
+
}
|
|
95
|
+
function replaceWorkspaceState(root, state) {
|
|
96
|
+
const file = workspaceStateFile(root);
|
|
97
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
98
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
99
|
+
writeFileSync(tmp, `${JSON.stringify(state, null, 2)}\n`);
|
|
100
|
+
renameSync(tmp, file);
|
|
101
|
+
return state;
|
|
102
|
+
}
|
|
103
|
+
function clearWorkspaceStateKeys(root, keys) {
|
|
104
|
+
if (!existsSync(workspaceStateFile(root))) return;
|
|
105
|
+
withWorkspaceStateLock(root, () => {
|
|
106
|
+
const state = readWorkspaceState(root);
|
|
107
|
+
const file = workspaceStateFile(root);
|
|
108
|
+
if (!state) {
|
|
109
|
+
try {
|
|
110
|
+
rmSync(file, { force: true });
|
|
111
|
+
} catch {}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
let changed = false;
|
|
115
|
+
for (const key of keys) {
|
|
116
|
+
if (!(key in state)) continue;
|
|
117
|
+
delete state[key];
|
|
118
|
+
changed = true;
|
|
119
|
+
}
|
|
120
|
+
if (!changed) return;
|
|
121
|
+
if (Object.keys(state).length === 0) {
|
|
122
|
+
rmSync(file, { force: true });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
replaceWorkspaceState(root, state);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function clearWorkspaceStateKey(root, key, shouldClear) {
|
|
129
|
+
return withWorkspaceStateLock(root, () => {
|
|
130
|
+
const state = readWorkspaceState(root);
|
|
131
|
+
if (!state || !(key in state)) return true;
|
|
132
|
+
if (!shouldClear(state[key])) return false;
|
|
133
|
+
delete state[key];
|
|
134
|
+
const file = workspaceStateFile(root);
|
|
135
|
+
if (Object.keys(state).length === 0) {
|
|
136
|
+
try {
|
|
137
|
+
rmSync(file, { force: true });
|
|
138
|
+
} catch {}
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
replaceWorkspaceState(root, state);
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { workspaceLogsDir as _, withWorkspaceStateLock as a, ensureWorkspaceStorage as c, sharedCompilationCache as d, supervisorLogFile as f, workspaceId as g, workspaceDir as h, updateWorkspaceState as i, sharedBuildCache as l, workspaceDerivedData as m, clearWorkspaceStateKeys as n, writeWorkspaceState as o, supervisorPidFile as p, readWorkspaceState as r, emulatorLogFile as s, clearWorkspaceStateKey as t, sharedCcache as u, workspaceName$1 as v, workspaceStateFile as y };
|