stim 1.3.0 → 1.4.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 +17 -3
- package/dist/{android-CqcW1hrP.mjs → android-BTR1KTMP.mjs} +206 -120
- package/dist/{android-BqVIJoG7.mjs → android-BkM4qTaN.mjs} +76 -77
- package/dist/{android-cas-BR5YJBYv.mjs → android-cas-BjLRZyks.mjs} +15 -12
- package/dist/{app-install-DIp9riNx.mjs → app-install--PAocWvq.mjs} +2 -2
- package/dist/{build-slots-C3-R4XQr.mjs → build-slots-D6sDzOe-.mjs} +7 -8
- package/dist/{cache-manifest-CXR-Y8pH.mjs → cache-manifest-D02TpYjA.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-6vdGngKa.mjs} +51 -51
- package/dist/dependency-state-BMirHEPD.mjs +76 -0
- package/dist/{deps-Spz8ozgo.mjs → deps-Ck4wuTwa.mjs} +1 -1
- package/dist/{dev-client-BjisHDB5.mjs → dev-client-Cd0v7iZk.mjs} +12 -12
- package/dist/{device-BkiW-gkk.mjs → device-CKXLnRRb.mjs} +7 -7
- package/dist/device-CMDFzx7C.mjs +1136 -0
- package/dist/{device-lease-BJYybF-2.mjs → device-lease-DDJr85OK.mjs} +3 -3
- package/dist/{device-pool-CPbLGfrB.mjs → device-pool-DJvbIBGW.mjs} +4 -4
- package/dist/{device-remote-AkYCKS8U.mjs → device-remote-CMfHhoc8.mjs} +7 -6
- package/dist/{doctor-Bmv86UUW.mjs → doctor-B_mfURdt.mjs} +536 -114
- package/dist/{error-diagnostics-DHC31rXA.mjs → error-diagnostics-_VmkqRZo.mjs} +8 -7
- package/dist/{gc-GGu-8ULN.mjs → gc-0AyxmECv.mjs} +61 -27
- package/dist/{guide-92CPA21s.mjs → guide-CGxdmQ0K.mjs} +236 -67
- package/dist/{ios-BSXFeO5H.mjs → ios-CtmGLx3X.mjs} +2667 -2607
- package/dist/{ios-device-CWOM_S44.mjs → ios-device-DJOi9FR5.mjs} +1 -1
- package/dist/{logs-DPNF4C9s.mjs → logs-BF3qPA7w.mjs} +32 -7
- package/dist/{logs-query-R-Cqc6Qv.mjs → logs-query-Cdp5aaCH.mjs} +1 -1
- package/dist/metro-DFLmaVz8.mjs +99 -0
- package/dist/named-ports-BO7Zpjp0.mjs +137 -0
- package/dist/{ownership-8O073GIC.mjs → ownership-BvSpZVBk.mjs} +5 -5
- package/dist/{ownership-BpCKiRlQ.mjs → ownership-C08Yzrp7.mjs} +6 -6
- package/dist/ports-BiKqP92J.mjs +39 -0
- package/dist/ports-ClqG8GPt.mjs +90 -0
- package/dist/{project-fKmuIaMI.mjs → project-CBFCwnN5.mjs} +2 -2
- package/dist/{reclaim-iW9Cad7k.mjs → reclaim-DpDVo-AP.mjs} +20 -13
- package/dist/{reload-DazHDSFA.mjs → reload-ByTqg6ZI.mjs} +8 -8
- package/dist/rolldown-runtime-BsOwBuO_.mjs +30 -0
- package/dist/{server-bare-DEzPZLvf.mjs → server-bare-Buk-k8tI.mjs} +3 -6
- package/dist/{server-expo-DizT4OMk.mjs → server-expo-D4P7iTvf.mjs} +3 -3
- package/dist/server-expo-Dho5Raiw.mjs +2 -0
- package/dist/{settings-DEJf6_kJ.mjs → settings-DwfltIXQ.mjs} +2 -2
- package/dist/{slot-launch-cci0xvmC.mjs → slot-launch-DeKen9e5.mjs} +4 -4
- package/dist/{start-mObjQH2W.mjs → start-BpKUHcU_.mjs} +16 -14
- package/dist/state-CDbvmZdt.mjs +131 -0
- package/dist/{stats-BR-kwj0B.mjs → stats-C59QLKm2.mjs} +1 -1
- package/dist/{stats-CaaQr4yN.mjs → stats-k5qMjyxo.mjs} +4 -4
- package/dist/{status-BxQNqu9t.mjs → status-Y2ij3dm6.mjs} +13 -12
- package/dist/{stop-DimGXEKY.mjs → stop-_P2OQwmZ.mjs} +15 -14
- package/dist/{stop-CrHGcjrV.mjs → stop-vKmmxhea.mjs} +2 -2
- package/dist/supervisor-run.d.mts +3 -27
- package/dist/supervisor-run.mjs +7 -6
- package/dist/{teardown-ClFp1Aax.mjs → teardown-KsPpvldq.mjs} +248 -110
- package/dist/{workspace-process-lock-3NcQnZ0X.mjs → workspace-process-lock-UEIrvZMJ.mjs} +4 -4
- package/dist/workspace-state-Do1e2mOH.mjs +146 -0
- package/dist/{worktree-DxTgN1CJ.mjs → worktree-BvcAIMdJ.mjs} +132 -123
- package/dist/{worktree-Eq6TLH8N.mjs → worktree-DWNx4tUg.mjs} +32 -2
- package/dist/xcode-D9tVItl-.mjs +860 -0
- package/package.json +7 -7
- package/dist/doctor-fAMXC4vl.mjs +0 -530
- package/dist/metro-CORqXyTL.mjs +0 -184
- package/dist/ownership-claim-Bf2CAfw3.mjs +0 -570
- package/dist/server-expo-44em5Pmg.mjs +0 -2
- package/dist/state-B3XA2wp2.mjs +0 -268
- package/dist/xcode-D7sAp-Zy.mjs +0 -1858
|
@@ -1,18 +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-6vdGngKa.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-Do1e2mOH.mjs";
|
|
5
|
+
import { l as resolvePackageJson } from "./project-CBFCwnN5.mjs";
|
|
6
6
|
import { n as stripAnsi } from "./process-output-C7IlIzd7.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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-BkM4qTaN.mjs";
|
|
9
|
+
import { n as expoBinFromPackage, r as expoBinPath, s as findBinUpward } from "./server-expo-D4P7iTvf.mjs";
|
|
9
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";
|
|
10
11
|
import { createRequire } from "node:module";
|
|
11
12
|
import { existsSync, lstatSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
12
13
|
import { randomUUID } from "node:crypto";
|
|
13
14
|
import { dirname, join } from "node:path";
|
|
14
15
|
import { pathToFileURL } from "node:url";
|
|
15
|
-
import { format } from "node:util";
|
|
16
|
+
import { format, isDeepStrictEqual } from "node:util";
|
|
16
17
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
17
18
|
//#region src/engine/remote-cache.ts
|
|
18
19
|
const EAS_PROVIDER_PACKAGE = "eas-build-cache-provider";
|
|
@@ -592,8 +593,14 @@ function writeParked(config, platform, records) {
|
|
|
592
593
|
function oldestFirst(records) {
|
|
593
594
|
return records.toSorted((a, b) => String(a.parkedAt).localeCompare(String(b.parkedAt)));
|
|
594
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
|
+
}
|
|
595
602
|
function selectParked(records, { deviceTypeIdentifier, runtimeIdentifier }) {
|
|
596
|
-
return oldestFirst(records.filter((r) => r.deletionClaim
|
|
603
|
+
return oldestFirst(records.filter((r) => !isLegacyDeletionClaim(r.deletionClaim) && r.deviceTypeIdentifier === deviceTypeIdentifier && r.runtimeIdentifier === runtimeIdentifier));
|
|
597
604
|
}
|
|
598
605
|
function evictOverflow(records, max) {
|
|
599
606
|
if (records.length <= max) return {
|
|
@@ -623,103 +630,167 @@ function parkSim({ platform, projectPath, slot = "default", record, max }) {
|
|
|
623
630
|
});
|
|
624
631
|
}
|
|
625
632
|
function adoptParked({ platform, projectPath, slot = "default", udid, device }) {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
const records = readParked(platform, { config: cfg });
|
|
629
|
-
const taken = records.find((r) => r.udid === udid);
|
|
630
|
-
if (!taken || taken.deletionClaim !== void 0) return null;
|
|
631
|
-
if (deviceSlotPlatforms(cfg.projects[projectPath], slot)?.[platform]) return null;
|
|
632
|
-
writeParked(cfg, platform, records.filter((r) => r.udid !== udid));
|
|
633
|
-
const project = cfg.projects[projectPath];
|
|
634
|
-
if (!project) throw new Error(`Project not registered: ${projectPath}`);
|
|
635
|
-
assignSlotDevice(project, platform, device, slot);
|
|
636
|
-
saveConfig(cfg);
|
|
637
|
-
return taken;
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
function isProcessAlive(pid) {
|
|
633
|
+
const claim = claimParkedOperation(platform, udid);
|
|
634
|
+
if (!claim) return null;
|
|
641
635
|
try {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
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);
|
|
646
653
|
}
|
|
647
654
|
}
|
|
648
|
-
function
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
return {
|
|
654
|
-
pid: claim.pid,
|
|
655
|
-
token: claim.token
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
function claimParkedRemoval(platform, udid) {
|
|
659
|
-
return withConfigLock(() => {
|
|
660
|
-
const cfg = loadConfig();
|
|
661
|
-
if (!cfg) return null;
|
|
662
|
-
const records = readParked(platform, { config: cfg });
|
|
663
|
-
const record = records.find((candidate) => candidate.udid === udid);
|
|
664
|
-
if (!record) return null;
|
|
665
|
-
const existingClaim = parseDeletionClaim(record.deletionClaim);
|
|
666
|
-
if (record.deletionClaim !== void 0 && (!existingClaim || isProcessAlive(existingClaim.pid))) return null;
|
|
667
|
-
const token = randomUUID();
|
|
668
|
-
const claimedRecord = {
|
|
669
|
-
...record,
|
|
670
|
-
deletionClaim: {
|
|
671
|
-
pid: process.pid,
|
|
672
|
-
token
|
|
673
|
-
}
|
|
674
|
-
};
|
|
675
|
-
writeParked(cfg, platform, records.map((candidate) => candidate.udid === udid ? claimedRecord : candidate));
|
|
676
|
-
saveConfig(cfg);
|
|
677
|
-
const claimed = { ...record };
|
|
678
|
-
delete claimed.deletionClaim;
|
|
679
|
-
return {
|
|
680
|
-
record: claimed,
|
|
681
|
-
token
|
|
682
|
-
};
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
function clearParkedRemovalClaim(platform, udid, token) {
|
|
686
|
-
withConfigLock(() => {
|
|
687
|
-
const cfg = loadConfig();
|
|
688
|
-
if (!cfg) return;
|
|
689
|
-
const records = readParked(platform, { config: cfg });
|
|
690
|
-
const record = records.find((candidate) => candidate.udid === udid);
|
|
691
|
-
if (!record || parseDeletionClaim(record.deletionClaim)?.token !== token) return;
|
|
692
|
-
const restored = { ...record };
|
|
693
|
-
delete restored.deletionClaim;
|
|
694
|
-
writeParked(cfg, platform, records.map((candidate) => candidate.udid === udid ? restored : candidate));
|
|
695
|
-
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}`
|
|
696
660
|
});
|
|
661
|
+
if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
|
|
662
|
+
return attempt.acquired ?? null;
|
|
697
663
|
}
|
|
698
664
|
function removeParkedAfter(platform, udid, beforeRemove) {
|
|
699
|
-
const claim =
|
|
665
|
+
const claim = claimParkedOperation(platform, udid);
|
|
700
666
|
if (!claim) return null;
|
|
701
667
|
try {
|
|
702
|
-
|
|
703
|
-
|
|
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;
|
|
704
694
|
try {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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);
|
|
708
717
|
}
|
|
709
|
-
return withConfigLock(() => {
|
|
710
|
-
const cfg = loadConfig();
|
|
711
|
-
if (!cfg) return null;
|
|
712
|
-
const records = readParked(platform, { config: cfg });
|
|
713
|
-
if (parseDeletionClaim(records.find((candidate) => candidate.udid === udid)?.deletionClaim)?.token !== claim.token) return null;
|
|
714
|
-
writeParked(cfg, platform, records.filter((candidate) => candidate.udid !== udid));
|
|
715
|
-
saveConfig(cfg);
|
|
716
|
-
return claim.record;
|
|
717
|
-
});
|
|
718
718
|
}
|
|
719
719
|
function dropParked(platform, udid) {
|
|
720
720
|
return removeParkedAfter(platform, udid, () => {}) !== null;
|
|
721
721
|
}
|
|
722
722
|
//#endregion
|
|
723
|
+
//#region src/agent-device-cleanup.ts
|
|
724
|
+
function parseAgentDeviceSessions(output) {
|
|
725
|
+
const result = JSON.parse(output);
|
|
726
|
+
if (result?.success !== true || !Array.isArray(result.data?.sessions)) throw new Error("agent-device did not return a successful session list");
|
|
727
|
+
return result.data.sessions.flatMap((entry) => {
|
|
728
|
+
if (!entry || typeof entry !== "object") return [];
|
|
729
|
+
const row = entry;
|
|
730
|
+
const id = row.platform === "ios" ? row.device_udid : row.id;
|
|
731
|
+
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 [];
|
|
732
|
+
return [{
|
|
733
|
+
name: row.name,
|
|
734
|
+
platform: row.platform,
|
|
735
|
+
id,
|
|
736
|
+
createdAt: row.createdAt
|
|
737
|
+
}];
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
function report(message) {
|
|
741
|
+
process.stderr.write(`${phaseLine("device", message)}\n`);
|
|
742
|
+
}
|
|
743
|
+
function closeOwnedDeviceSessions(device, stillOwned) {
|
|
744
|
+
const exec = getExecutor();
|
|
745
|
+
const deadline = Date.now() + 15e3;
|
|
746
|
+
const run = (args) => {
|
|
747
|
+
const remaining = deadline - Date.now();
|
|
748
|
+
if (remaining <= 0) throw new Error("agent-device cleanup timed out");
|
|
749
|
+
return exec.runFile("agent-device", [
|
|
750
|
+
...args,
|
|
751
|
+
"--json",
|
|
752
|
+
"--daemon-transport",
|
|
753
|
+
"socket"
|
|
754
|
+
], {
|
|
755
|
+
timeoutMs: Math.min(5e3, remaining),
|
|
756
|
+
killSignal: "SIGKILL"
|
|
757
|
+
});
|
|
758
|
+
};
|
|
759
|
+
const list = () => parseAgentDeviceSessions(run([
|
|
760
|
+
"session",
|
|
761
|
+
"list",
|
|
762
|
+
"--session",
|
|
763
|
+
"stim-teardown-inventory"
|
|
764
|
+
]));
|
|
765
|
+
try {
|
|
766
|
+
if (!exec.runQuiet("command -v agent-device", {
|
|
767
|
+
timeoutMs: 2e3,
|
|
768
|
+
killSignal: "SIGKILL"
|
|
769
|
+
})) return;
|
|
770
|
+
const sessions = list().filter((session) => session.platform === device.platform && session.id === device.id);
|
|
771
|
+
for (const session of sessions) try {
|
|
772
|
+
if (!list().some((current) => current.name === session.name && current.platform === session.platform && current.id === session.id && current.createdAt === session.createdAt)) continue;
|
|
773
|
+
if (!stillOwned()) return;
|
|
774
|
+
if (JSON.parse(run([
|
|
775
|
+
"close",
|
|
776
|
+
"--session",
|
|
777
|
+
session.name,
|
|
778
|
+
"--session-lock",
|
|
779
|
+
"reject",
|
|
780
|
+
"--platform",
|
|
781
|
+
device.platform,
|
|
782
|
+
device.platform === "ios" ? "--udid" : "--serial",
|
|
783
|
+
device.id
|
|
784
|
+
]))?.success !== true) throw new Error("agent-device did not confirm session close");
|
|
785
|
+
report(`closed agent-device session ${session.name} on ${device.id}`);
|
|
786
|
+
} catch (error) {
|
|
787
|
+
report(`could not close agent-device session ${session.name} on ${device.id}: ${error.message}`);
|
|
788
|
+
}
|
|
789
|
+
} catch (error) {
|
|
790
|
+
report(`could not list agent-device sessions for ${device.id}: ${error.message}`);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
//#endregion
|
|
723
794
|
//#region src/teardown.ts
|
|
724
795
|
function teardownParkedAvd(avdName) {
|
|
725
796
|
try {
|
|
@@ -746,7 +817,13 @@ function teardownParkedAvd(avdName) {
|
|
|
746
817
|
}
|
|
747
818
|
function teardownParkedIosSim(udid, { label, deleteSim = deleteParkedIosSim } = {}) {
|
|
748
819
|
try {
|
|
749
|
-
const removed = removeParkedAfter("ios", udid, () =>
|
|
820
|
+
const removed = removeParkedAfter("ios", udid, () => {
|
|
821
|
+
closeOwnedDeviceSessions({
|
|
822
|
+
platform: "ios",
|
|
823
|
+
id: udid
|
|
824
|
+
}, () => Boolean(resolveOwnedIosSim(udid).sim));
|
|
825
|
+
deleteSim(udid);
|
|
826
|
+
});
|
|
750
827
|
if (!removed) return {
|
|
751
828
|
status: "skipped",
|
|
752
829
|
kind: "not-parked",
|
|
@@ -812,6 +889,17 @@ function teardownOwnedIosSim(udid, { del = false, label, park } = {}) {
|
|
|
812
889
|
reason: `sim is now named "${resolved.notOwned}", not Stim-owned by name`
|
|
813
890
|
};
|
|
814
891
|
if (resolved.missing) return { status: "missing" };
|
|
892
|
+
closeOwnedDeviceSessions({
|
|
893
|
+
platform: "ios",
|
|
894
|
+
id: udid
|
|
895
|
+
}, () => Boolean(resolveOwnedIosSim(udid).sim));
|
|
896
|
+
const current = resolveOwnedIosSim(udid);
|
|
897
|
+
if (current.missing) return { status: "missing" };
|
|
898
|
+
if (current.notOwned) return {
|
|
899
|
+
status: "skipped",
|
|
900
|
+
kind: "not-owned",
|
|
901
|
+
reason: "simulator ownership changed before shutdown"
|
|
902
|
+
};
|
|
815
903
|
shutdownIosSim(udid);
|
|
816
904
|
const sim = resolved.sim;
|
|
817
905
|
if (del && park && park.max > 0) try {
|
|
@@ -853,18 +941,24 @@ function teardownOwnedIosSim(udid, { del = false, label, park } = {}) {
|
|
|
853
941
|
};
|
|
854
942
|
}
|
|
855
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
|
+
}
|
|
856
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 });
|
|
857
958
|
const detached = withConfigLock(() => {
|
|
858
|
-
const current =
|
|
859
|
-
if (!current
|
|
860
|
-
|
|
861
|
-
if (!config) throw new Error("Cannot verify AVD references without a Stim config; the data was kept.");
|
|
862
|
-
for (const [projectPath, project] of Object.entries(config.projects)) for (const { platforms } of projectDeviceSlots(project)) {
|
|
863
|
-
if (platforms.android?.avdName !== candidate.name) continue;
|
|
864
|
-
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.`);
|
|
865
|
-
}
|
|
866
|
-
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.`);
|
|
867
|
-
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);
|
|
868
962
|
const destination = join(dirname(candidate.directory), `stim-gc-${randomUUID()}.avd`);
|
|
869
963
|
renameSync(candidate.directory, destination);
|
|
870
964
|
return destination;
|
|
@@ -896,14 +990,31 @@ function teardownUnregisteredAvd(avdName, del, owner, surveyed) {
|
|
|
896
990
|
label: avdName
|
|
897
991
|
};
|
|
898
992
|
}
|
|
899
|
-
function teardownOwnedAvd(avdName,
|
|
900
|
-
|
|
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;
|
|
901
1000
|
try {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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)
|
|
906
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));
|
|
907
1018
|
const resolved = resolveAvd(avdName);
|
|
908
1019
|
if (resolved.notOwned) return {
|
|
909
1020
|
status: "skipped",
|
|
@@ -911,13 +1022,34 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
911
1022
|
reason: `AVD ${avdName} is not Stim-owned by name`
|
|
912
1023
|
};
|
|
913
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
|
+
};
|
|
914
1029
|
if (orphanedDirectory) return {
|
|
915
1030
|
status: "skipped",
|
|
916
1031
|
reason: "AVD registration appeared; its data was kept."
|
|
917
1032
|
};
|
|
918
1033
|
const serial = resolved.serial;
|
|
919
|
-
if (serial)
|
|
920
|
-
|
|
1034
|
+
if (serial) {
|
|
1035
|
+
const stillOwned = () => {
|
|
1036
|
+
const current = resolveAvd(avdName);
|
|
1037
|
+
return !current.notOwned && !current.missing && current.serial === serial;
|
|
1038
|
+
};
|
|
1039
|
+
closeOwnedDeviceSessions({
|
|
1040
|
+
platform: "android",
|
|
1041
|
+
id: serial
|
|
1042
|
+
}, stillOwned);
|
|
1043
|
+
if (!stillOwned()) throw new Error(`Owned AVD ${avdName} changed before shutdown; it was kept.`);
|
|
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
|
+
});
|
|
1052
|
+
} else assertStopped(avdName);
|
|
921
1053
|
if (del) {
|
|
922
1054
|
const current = resolveAvd(avdName);
|
|
923
1055
|
if (current.notOwned) return {
|
|
@@ -928,6 +1060,7 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
928
1060
|
if (current.missing) return teardownUnregisteredAvd(avdName, del, owner);
|
|
929
1061
|
if (current.serial) throw new Error(`Owned AVD ${avdName} started again before deletion.`);
|
|
930
1062
|
assertStopped(avdName);
|
|
1063
|
+
withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
931
1064
|
if (park && park.max > 0) try {
|
|
932
1065
|
const systemImage = ownedAvdSystemImage(avdName);
|
|
933
1066
|
if (!systemImage || !park.configuration || !ownedAvdMatchesConfiguration(avdName, park.configuration)) throw new Error("the AVD has no verified creation configuration");
|
|
@@ -972,7 +1105,12 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
972
1105
|
const directory = ownedAvdDirectory(avdName);
|
|
973
1106
|
const paths = avdStorageRoots().map((root) => join(root, `${avdName}.ini`));
|
|
974
1107
|
if (directory) paths.push(directory);
|
|
975
|
-
|
|
1108
|
+
(0, ownership_claim_exports.markClaimChildPending)(claim);
|
|
1109
|
+
try {
|
|
1110
|
+
deleteAvd(avdName);
|
|
1111
|
+
} finally {
|
|
1112
|
+
(0, ownership_claim_exports.clearClaimChild)(claim);
|
|
1113
|
+
}
|
|
976
1114
|
const remaining = paths.filter(avdPathExists);
|
|
977
1115
|
if (remaining.length) throw new Error(`AVD ${avdName} was only partially deleted; data remains at ${remaining.join(", ")}.`);
|
|
978
1116
|
}
|
|
@@ -990,4 +1128,4 @@ function teardownOwnedAvd(avdName, { del = false, park, owner, orphanedDirectory
|
|
|
990
1128
|
}
|
|
991
1129
|
}
|
|
992
1130
|
//#endregion
|
|
993
|
-
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-6vdGngKa.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-6vdGngKa.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 };
|