stim 1.6.0 → 1.7.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 +1 -1
- package/dist/{android-BkYmndPp.mjs → android-DWssqHQ8.mjs} +165 -661
- package/dist/{android-DLJB8ljN.mjs → android-Da-G_o3n.mjs} +646 -548
- package/dist/{android-BW8i_YxU.mjs → android-DeYdjjBP.mjs} +6 -2
- package/dist/{android-cas-CrzI_Zha.mjs → android-cas-SWIjzeuL.mjs} +54 -18
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/{app-install--PAocWvq.mjs → app-install-DJg7bVv-.mjs} +36 -10
- package/dist/build-lock-CgtsB6TV.mjs +604 -0
- package/dist/{build-slots-CuPszJDu.mjs → build-slots-C-oAHRT1.mjs} +2 -2
- package/dist/{cache-manifest-uoOKhgUD.mjs → cache-manifest-CYJi8-Hx.mjs} +2 -2
- package/dist/cache-manifest.d.mts +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +14 -14
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-BuIb_ZOI.mjs → command-output-B3ycpsYv.mjs} +2 -2
- package/dist/{config-DMP7L7H6.mjs → config-B7iyKWkL.mjs} +56 -16
- package/dist/{dependency-state-CTL8A9p3.mjs → dependency-state-D0M7oKA7.mjs} +2 -2
- package/dist/{deps-C1zGnr61.mjs → deps-oCXVNEqQ.mjs} +6 -6
- package/dist/detached-entry-Bpo6ZY_I.mjs +65 -0
- package/dist/{dev-client-BaTXAAnC.mjs → dev-client-DDUkWgJL.mjs} +12 -12
- package/dist/{device-xoQxw8hR.mjs → device-CBSaC6BU.mjs} +7 -7
- package/dist/{device-XY_5eGdN.mjs → device-CLeDp-KH.mjs} +17 -15
- package/dist/{device-lease-DBW-IL4p.mjs → device-lease-Ffz_M5t0.mjs} +3 -3
- package/dist/{device-pool-C0s_83Og.mjs → device-pool-DNSHL5z8.mjs} +4 -4
- package/dist/{device-remote-D9wN3CdE.mjs → device-remote-BprxZp-m.mjs} +11 -11
- package/dist/{doctor-BRO8UKlK.mjs → doctor-CTAx9gMu.mjs} +90 -46
- package/dist/{error-diagnostics-B5STzxqN.mjs → error-diagnostics-D1Kaf-eT.mjs} +23 -17
- package/dist/{exec-CyylIdq9.mjs → exec-B29XNuhP.mjs} +14 -2
- package/dist/{gc-C-6grAQI.mjs → gc-CX0KRfLG.mjs} +17 -16
- package/dist/{guide-CYtd7xbA.mjs → guide-CPmAG9me.mjs} +38 -15
- package/dist/{guide-status-BF6RsJJp.mjs → guide-status-Craq9z0t.mjs} +3 -3
- package/dist/{ios-Ccm6c8Hj.mjs → ios-BRXYSxSc.mjs} +34 -37
- package/dist/{ios-device-DJOi9FR5.mjs → ios-device-CDbvn5H2.mjs} +2 -2
- package/dist/{ios-device-D3pzTKQE.mjs → ios-device-CFXA46ez.mjs} +1 -1
- package/dist/{ios-Deh5js5V.mjs → ios-lEJ5pKsq.mjs} +3 -3
- package/dist/{logs-D4Poojxy.mjs → logs-CakdBTtm.mjs} +6 -6
- package/dist/{logs-query-Cdp5aaCH.mjs → logs-query-BGL-Pl12.mjs} +1 -1
- package/dist/metro-C7bcJ0uo.mjs +233 -0
- package/dist/{named-ports-DH9SXd0f.mjs → named-ports-DzMOlmaX.mjs} +57 -42
- package/dist/{ownership-CD_XnpDu.mjs → ownership-Cp52QAK1.mjs} +3 -3
- package/dist/{ownership-CVY9cqCr.mjs → ownership-D5vkdm8H.mjs} +13 -13
- package/dist/{ports-A6uTJSPj.mjs → ports-BIbJaKNW.mjs} +3 -3
- package/dist/{process-output-C7IlIzd7.mjs → process-output-Dl5uKE03.mjs} +1 -1
- package/dist/{project-B_SDt4ip.mjs → project-DDZWf_16.mjs} +3 -3
- package/dist/{reclaim-WXTbXPX4.mjs → reclaim-D614jI6_.mjs} +11 -11
- package/dist/{reload-xlQvHKfN.mjs → reload-ChW46VDb.mjs} +9 -9
- package/dist/{server-bare-CCLb90FS.mjs → server-bare-BQkyxa_b.mjs} +1 -1
- package/dist/{server-expo-CX-zkgWl.mjs → server-expo-BVAA1OqJ.mjs} +23 -11
- package/dist/server-expo-YDDG3eP7.mjs +2 -0
- package/dist/{settings-CGHTt5vb.mjs → settings-BXXorVM2.mjs} +3 -3
- package/dist/{slot-launch-BYjnljAs.mjs → slot-launch-DbLvyrup.mjs} +4 -4
- package/dist/{start-DHYAyGzm.mjs → start-TTVILlUi.mjs} +111 -38
- package/dist/{state-CnWzvCWP.mjs → state-DZobzxLW.mjs} +2 -2
- package/dist/{stats-Fo9ACIv7.mjs → stats-BYcZ6n1h.mjs} +1 -1
- package/dist/{stats-DHrO0frH.mjs → stats-CLg5RuDS.mjs} +4 -4
- package/dist/{status-QeLZb8SM.mjs → status-DUNy_HZs.mjs} +14 -15
- package/dist/{stop-CHTaw65F.mjs → stop-CnUpnFT5.mjs} +2 -2
- package/dist/{stop-DsdOx9Hj.mjs → stop-ZrfODZ51.mjs} +13 -13
- package/dist/supervisor-run.mjs +7 -5
- package/dist/{teardown-sm1FwF6V.mjs → teardown-5J5UXz2P.mjs} +14 -17
- package/dist/{workspace-process-lock-Bz19_R9R.mjs → workspace-process-lock-BYfZz_S-.mjs} +1 -1
- package/dist/{workspace-state-WVwWw_hB.mjs → workspace-state-BT5E3SA2.mjs} +3 -3
- package/dist/{worktree-CCNPg_f0.mjs → worktree-BfE4lzHK.mjs} +21 -16
- package/dist/{worktree-DJnBbQZ9.mjs → worktree-FG_ZKKdb.mjs} +13 -9
- package/dist/{xcode-DUF7jrXj.mjs → xcode-B6YaWeg0.mjs} +8 -8
- package/package.json +12 -8
- package/shim/android-optimizations.gradle +6 -0
- package/dist/metro-ato6ef3J.mjs +0 -99
- package/dist/ports-BZprTJRa.mjs +0 -90
- package/dist/server-expo-CjeTJ273.mjs +0 -2
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
2
|
-
import { E as ownership_claim_exports,
|
|
1
|
+
import { t as getExecutor } from "./exec-B29XNuhP.mjs";
|
|
2
|
+
import { B as validateDeviceSlot, E as ownership_claim_exports, F as deviceSlotKey, P as deviceSlotFileKey, S as upsertProject, f as getProject, l as getConcurrencyLimits } from "./config-B7iyKWkL.mjs";
|
|
3
3
|
import { r as createNdjsonWriter } from "./ndjson-BZwI1NBv.mjs";
|
|
4
|
-
import { _ as workspaceLogsDir, h as workspaceDir, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-
|
|
5
|
-
import { T as removeTemporaryEntry, g as repoRoot, s as gitCommonDir, w as makeTemporaryDirectory } from "./worktree-
|
|
6
|
-
import { a as findProjectRoot, c as projectShortcut, i as detectIsExpo, r as detectBundleId, t as appProjectProblem } from "./project-
|
|
7
|
-
import { n as MODE_EXPO, p as writeWorkspaceLaunch, t as MODE_BARE } from "./state-
|
|
8
|
-
import {
|
|
9
|
-
import { n as verifyCollectorOwnership } from "./ownership-
|
|
10
|
-
import { _ as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { C as resolveRemote, S as resolveEasCliBin, _ as exitAfterFlush, a as POOL_SETTING_REMEDY, f as RESOLVE_TIMEOUT_MS, g as easAuthNote, h as checkEasAuth, l as parkedMaxSetting, m as cacheLevel, p as UPLOAD_TIMEOUT_MS, v as isEasAuthFailureText, w as uploadRemote, y as loadProjectProvider } from "./teardown-
|
|
14
|
-
import { _ as easDeviceBuildRemedy, a as swapJsBundle, c as ensureWorkspaceStorageSafely, d as launchOutcomeRecord, f as noMetroMessage, g as warmMetro, h as sleep, l as gateShouldRetry, m as resolveMetroWithRetry, n as pickDevClientScheme, o as needsPrebuild, p as noMetroRemedy, r as schemesFromInfoPlist, s as runPrebuild, t as devClientScheme, u as isPhysicalDeviceRequest, v as isEasBuildFailure, y as resolveEasDevelopmentBuild } from "./dev-client-
|
|
15
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-
|
|
16
|
-
import { C as launchIosApp, E as unverifiedLaunchLines, O as verifyLaunch, T as readMetroRecords, b as isBundleProof, c as RELEASE_VERIFY_WAIT_MS, f as clearOtherUserApps, i as LAUNCH_BUNDLING, k as verifyReleaseLaunch, m as devClientUrl, n as DEFAULT_METRO_PORT, o as LAUNCH_FATAL, s as LAUNCH_UNVERIFIED, v as installIosApp, w as readCollectorRecords, y as iosAppProcess } from "./app-install
|
|
17
|
-
import { f as listIosRuntimes } from "./ios-
|
|
18
|
-
import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-
|
|
19
|
-
import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-
|
|
20
|
-
import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-
|
|
21
|
-
import { c as unknownIosRuntimeRefusal, i as ensureOwnedDevice, n as clearIosAdoptionPending, r as ensureBooted, s as unknownIosDeviceTypeRefusal, t as checkDeviceCapacity } from "./device-
|
|
22
|
-
import { a as ensureMetroReachable, b as ownedSessionName, c as remoteIosDeps, l as resolveRemoteContext, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, w as gateMetroOrigin } from "./device-remote-
|
|
23
|
-
import { a as compilationCacheActivityLine, c as readBundleExecutable, l as readBundleId, p as describeDiagnostic, r as buildIos, s as discoverXcodeProject, t as COMPILATION_CACHE_NOT_RUN, u as resolveScheme } from "./xcode-
|
|
24
|
-
import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-
|
|
4
|
+
import { _ as workspaceLogsDir, h as workspaceDir, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
|
|
5
|
+
import { T as removeTemporaryEntry, g as repoRoot, s as gitCommonDir, w as makeTemporaryDirectory } from "./worktree-FG_ZKKdb.mjs";
|
|
6
|
+
import { a as findProjectRoot, c as projectShortcut, i as detectIsExpo, r as detectBundleId, t as appProjectProblem } from "./project-DDZWf_16.mjs";
|
|
7
|
+
import { n as MODE_EXPO, p as writeWorkspaceLaunch, t as MODE_BARE } from "./state-DZobzxLW.mjs";
|
|
8
|
+
import { a as resolveProjectMetro, i as pidExists, o as signalProcessTree } from "./metro-C7bcJ0uo.mjs";
|
|
9
|
+
import { n as verifyCollectorOwnership } from "./ownership-Cp52QAK1.mjs";
|
|
10
|
+
import { A as resolveSettings, B as artifactCachePolicy, D as remoteDeviceSettingError, F as tunnelModeSetting, H as optimizationBuildProfile, I as unknownSettingKeys, N as settingShapeErrors, O as remoteIosSetting, R as detectProviders, T as publicUrlSetting, U as resolveOptimizations, _ as iosSigningIdentitySha1SettingError, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, f as iosLanHostSetting, g as iosSigningIdentitySha1Setting, h as iosSigningIdentitySettingError, k as resolveCacheProviderConfig, m as iosSigningIdentitySetting, p as iosLanHostSettingError, r as REMOTE_DEVICE_BACKENDS, x as metroWarmupUrlSetting } from "./settings-BXXorVM2.mjs";
|
|
11
|
+
import { _ as launchErrorPreview, c as launchErrorReport, g as stepTimer, h as stepClock, i as formatDuration, l as phaseLine, m as shortUdid, n as appReadinessMessage, p as shortHash } from "./command-output-B3ycpsYv.mjs";
|
|
12
|
+
import { C as untrackedNativeFiles, S as untrackedMissLine, _ as providerUploadOutcome, b as storeBuild, c as buildCacheKey, d as filesystemBuildCapability, f as fingerprintDiffRecord, g as providerDownloadPath, h as prepareProviderDownloadDir, i as releaseBuildLock, l as describeFingerprintMiss, m as fingerprintProject, n as acquireBuildLock, o as takeoverLine, p as fingerprintDiffSuffix, s as waitForBuild, t as WAIT_CEILING_MS, v as refingerprintAfterMutation, y as resolveBuild } from "./build-lock-CgtsB6TV.mjs";
|
|
13
|
+
import { C as resolveRemote, S as resolveEasCliBin, _ as exitAfterFlush, a as POOL_SETTING_REMEDY, f as RESOLVE_TIMEOUT_MS, g as easAuthNote, h as checkEasAuth, l as parkedMaxSetting, m as cacheLevel, p as UPLOAD_TIMEOUT_MS, v as isEasAuthFailureText, w as uploadRemote, y as loadProjectProvider } from "./teardown-5J5UXz2P.mjs";
|
|
14
|
+
import { _ as easDeviceBuildRemedy, a as swapJsBundle, c as ensureWorkspaceStorageSafely, d as launchOutcomeRecord, f as noMetroMessage, g as warmMetro, h as sleep, l as gateShouldRetry, m as resolveMetroWithRetry, n as pickDevClientScheme, o as needsPrebuild, p as noMetroRemedy, r as schemesFromInfoPlist, s as runPrebuild, t as devClientScheme, u as isPhysicalDeviceRequest, v as isEasBuildFailure, y as resolveEasDevelopmentBuild } from "./dev-client-DDUkWgJL.mjs";
|
|
15
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BYfZz_S-.mjs";
|
|
16
|
+
import { C as launchIosApp, E as unverifiedLaunchLines, O as verifyLaunch, T as readMetroRecords, b as isBundleProof, c as RELEASE_VERIFY_WAIT_MS, f as clearOtherUserApps, i as LAUNCH_BUNDLING, k as verifyReleaseLaunch, m as devClientUrl, n as DEFAULT_METRO_PORT, o as LAUNCH_FATAL, s as LAUNCH_UNVERIFIED, v as installIosApp, w as readCollectorRecords, y as iosAppProcess } from "./app-install-DJg7bVv-.mjs";
|
|
17
|
+
import { f as listIosRuntimes } from "./ios-lEJ5pKsq.mjs";
|
|
18
|
+
import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-DNSHL5z8.mjs";
|
|
19
|
+
import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-C-oAHRT1.mjs";
|
|
20
|
+
import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-BYcZ6n1h.mjs";
|
|
21
|
+
import { c as unknownIosRuntimeRefusal, i as ensureOwnedDevice, n as clearIosAdoptionPending, r as ensureBooted, s as unknownIosDeviceTypeRefusal, t as checkDeviceCapacity } from "./device-CLeDp-KH.mjs";
|
|
22
|
+
import { a as ensureMetroReachable, b as ownedSessionName, c as remoteIosDeps, l as resolveRemoteContext, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, w as gateMetroOrigin } from "./device-remote-BprxZp-m.mjs";
|
|
23
|
+
import { a as compilationCacheActivityLine, c as readBundleExecutable, l as readBundleId, p as describeDiagnostic, r as buildIos, s as discoverXcodeProject, t as COMPILATION_CACHE_NOT_RUN, u as resolveScheme } from "./xcode-B6YaWeg0.mjs";
|
|
24
|
+
import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-DbLvyrup.mjs";
|
|
25
25
|
import { t as spawnEntry } from "./spawn-entry-nCE6m770.mjs";
|
|
26
|
-
import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-
|
|
27
|
-
import { a as iosDeviceProcess, c as listIosDevices, d as verifyIosDeviceReleaseLaunch, i as installIosDeviceApp, l as localNetworkPending, n as LAUNCH_PROBE_TIMEOUT_MS, o as iosPoolCandidates, r as awaitIosDeviceLaunch, s as iosPoolNoCandidatesRefusal, t as DEVICECTL_INSTALL_TIMEOUT_MS, u as resolveIosPhysicalDevice } from "./ios-device-
|
|
28
|
-
import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-
|
|
26
|
+
import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-D1Kaf-eT.mjs";
|
|
27
|
+
import { a as iosDeviceProcess, c as listIosDevices, d as verifyIosDeviceReleaseLaunch, i as installIosDeviceApp, l as localNetworkPending, n as LAUNCH_PROBE_TIMEOUT_MS, o as iosPoolCandidates, r as awaitIosDeviceLaunch, s as iosPoolNoCandidatesRefusal, t as DEVICECTL_INSTALL_TIMEOUT_MS, u as resolveIosPhysicalDevice } from "./ios-device-CDbvn5H2.mjs";
|
|
28
|
+
import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-oCXVNEqQ.mjs";
|
|
29
29
|
import { existsSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "node:fs";
|
|
30
30
|
import { InvalidArgumentError } from "commander";
|
|
31
31
|
import { X509Certificate } from "node:crypto";
|
|
@@ -1503,14 +1503,14 @@ function hostLanCandidates(interfaces = networkInterfaces) {
|
|
|
1503
1503
|
//#endregion
|
|
1504
1504
|
//#region src/commands/ios/collector.ts
|
|
1505
1505
|
function collectorLogFile(root, slot) {
|
|
1506
|
-
return join(workspaceLogsDir(root), `collector-${
|
|
1506
|
+
return join(workspaceLogsDir(root), `collector-${deviceSlotFileKey("ios", slot)}.log`);
|
|
1507
1507
|
}
|
|
1508
1508
|
function collectorEntry() {
|
|
1509
1509
|
return spawnEntry("collector-run");
|
|
1510
1510
|
}
|
|
1511
1511
|
const COLLECTOR_EXIT_WAIT_MS = 2e3;
|
|
1512
1512
|
const COLLECTOR_POLL_MS = 25;
|
|
1513
|
-
async function stopPreviousCollector({ root, slot = "default", kill = (pid, signal) =>
|
|
1513
|
+
async function stopPreviousCollector({ root, slot = "default", kill = (pid, signal) => signalProcessTree(pid, signal), alive = pidExists, readState = readWorkspaceState, verify = verifyCollectorOwnership, waitMs = COLLECTOR_EXIT_WAIT_MS, note = (_line) => {} }) {
|
|
1514
1514
|
const previous = (readState(root)?.collectors)?.[deviceSlotKey("ios", slot)] || null;
|
|
1515
1515
|
const previousPid = Number(previous?.pid) || null;
|
|
1516
1516
|
let killed = null;
|
|
@@ -2138,14 +2138,11 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2138
2138
|
event: "launch",
|
|
2139
2139
|
msg: release ? `launched ${bundleId} on ${udid} (${configuration}, embedded JS bundle, no Metro)` : `launched ${bundleId} on ${udid} against Metro ${lanOriginUrl ?? `port ${metroPort}`}` + (launched?.mode === "openurl" || launched?.mode === "payload-url" ? " (expo-dev-client)" : "")
|
|
2140
2140
|
});
|
|
2141
|
-
if (remoteDevice)
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
appName,
|
|
2147
|
-
appExecutable,
|
|
2148
|
-
note
|
|
2141
|
+
if (remoteDevice) logWriter().write({
|
|
2142
|
+
src: "build",
|
|
2143
|
+
level: "info",
|
|
2144
|
+
event: "collector_skipped",
|
|
2145
|
+
msg: `remote session ${udid}: device logs come from agent-device/EAS, so no simctl log stream is attached`
|
|
2149
2146
|
});
|
|
2150
2147
|
if (physical) raiseLeaseFor(release ? RELEASE_VERIFY_WAIT_MS : DEBUG_VERIFY_STEP_MS, false);
|
|
2151
2148
|
const { state: launchState, warning: launchWarning } = await verifyIosRun({
|
|
@@ -2272,7 +2269,7 @@ function explicitSchemeRefusal(root, scheme, isExpo, d) {
|
|
|
2272
2269
|
return d.resolveScheme(project, { scheme }).error ?? null;
|
|
2273
2270
|
}
|
|
2274
2271
|
function iosSlotLogFile(root, slot) {
|
|
2275
|
-
return slot === "default" ? buildLogFile(root) : join(workspaceLogsDir(root), `build-${
|
|
2272
|
+
return slot === "default" ? buildLogFile(root) : join(workspaceLogsDir(root), `build-${deviceSlotFileKey("ios", slot)}.ndjson`);
|
|
2276
2273
|
}
|
|
2277
2274
|
function iosSlotDeps(d, slot) {
|
|
2278
2275
|
if (slot !== "default") {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
2
|
-
import { r as INSTALL_ERROR } from "./app-install
|
|
1
|
+
import { t as getExecutor } from "./exec-B29XNuhP.mjs";
|
|
2
|
+
import { r as INSTALL_ERROR } from "./app-install-DJg7bVv-.mjs";
|
|
3
3
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
2
|
-
import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-
|
|
1
|
+
import { t as getExecutor } from "./exec-B29XNuhP.mjs";
|
|
2
|
+
import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Dl5uKE03.mjs";
|
|
3
3
|
import { mkdtempSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
@@ -22,7 +22,7 @@ function hostMemoryPressureAdvice(pressure) {
|
|
|
22
22
|
return `macOS reports ${pressure} host memory pressure. Simulator processes can stall even when the device is Booted. Free memory before retrying: use \`stim stop\` only in workspaces you own, and ask before closing other apps or devices. For parallel iOS work, consider a reviewed SimSlim profile (\`stim guide lifecycle simslim\`). This observation does not establish an OOM crash.`;
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
|
-
//#region src/
|
|
25
|
+
//#region src/devices/ios.ts
|
|
26
26
|
function parseSimctlList(jsonOutput, { includeUnavailable = false } = {}) {
|
|
27
27
|
const parsed = JSON.parse(jsonOutput);
|
|
28
28
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Expected simctl list to return a JSON object with a devices object.");
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as validateDeviceSlot, g as loadConfig, h as isPathPrefix } from "./config-B7iyKWkL.mjs";
|
|
2
2
|
import { n as SOURCES, t as LEVELS } from "./ndjson-BZwI1NBv.mjs";
|
|
3
|
-
import { _ as workspaceLogsDir, r as readWorkspaceState } from "./workspace-state-
|
|
4
|
-
import { a as findProjectRoot } from "./project-
|
|
5
|
-
import { _ as launchErrorPreview } from "./command-output-
|
|
6
|
-
import { i as captureWorkspaceCrashes, t as errorDiagnostics } from "./error-diagnostics-
|
|
7
|
-
import { a as followLogs, c as queryLogs, i as fileSizes, n as buildCriteria, o as logFiles, r as compileGrep, s as parseSince } from "./logs-query-
|
|
3
|
+
import { _ as workspaceLogsDir, r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
|
|
4
|
+
import { a as findProjectRoot } from "./project-DDZWf_16.mjs";
|
|
5
|
+
import { _ as launchErrorPreview } from "./command-output-B3ycpsYv.mjs";
|
|
6
|
+
import { i as captureWorkspaceCrashes, t as errorDiagnostics } from "./error-diagnostics-D1Kaf-eT.mjs";
|
|
7
|
+
import { a as followLogs, c as queryLogs, i as fileSizes, n as buildCriteria, o as logFiles, r as compileGrep, s as parseSince } from "./logs-query-BGL-Pl12.mjs";
|
|
8
8
|
import { realpathSync } from "node:fs";
|
|
9
9
|
import { relative, sep } from "node:path";
|
|
10
10
|
import chalk from "chalk";
|
|
@@ -2,7 +2,7 @@ import { a as parseNdjsonLine, i as levelRank, o as parseNdjsonText } from "./nd
|
|
|
2
2
|
import { closeSync, openSync, readFileSync, readSync, readdirSync, statSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { StringDecoder } from "string_decoder";
|
|
5
|
-
//#region src/logs-query.ts
|
|
5
|
+
//#region src/diagnostics/logs-query.ts
|
|
6
6
|
const SINCE_UNITS = {
|
|
7
7
|
s: 1e3,
|
|
8
8
|
m: 6e4,
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-B29XNuhP.mjs";
|
|
2
|
+
import { A as isOnMountedVolume, g as loadConfig, j as listMountedVolumes, n as allMetroPorts, r as claimMetroPort, v as removeProject, w as process_identity_exports } from "./config-B7iyKWkL.mjs";
|
|
3
|
+
import { r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
|
|
4
|
+
import { existsSync, readlinkSync, realpathSync } from "fs";
|
|
5
|
+
import { sep } from "path";
|
|
6
|
+
import { request } from "http";
|
|
7
|
+
import { connect } from "net";
|
|
8
|
+
//#region src/ports.ts
|
|
9
|
+
function isMetroRunning(port) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const req = request({
|
|
12
|
+
hostname: "localhost",
|
|
13
|
+
port,
|
|
14
|
+
path: "/status",
|
|
15
|
+
timeout: 2e3
|
|
16
|
+
}, (res) => {
|
|
17
|
+
let data = "";
|
|
18
|
+
res.on("data", (chunk) => {
|
|
19
|
+
data += chunk;
|
|
20
|
+
});
|
|
21
|
+
res.on("end", () => resolve(data.includes("packager-status:running")));
|
|
22
|
+
});
|
|
23
|
+
req.on("error", () => resolve(false));
|
|
24
|
+
req.on("timeout", () => {
|
|
25
|
+
req.destroy();
|
|
26
|
+
resolve(false);
|
|
27
|
+
});
|
|
28
|
+
req.end();
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function isPortFree(port, { timeoutMs = 400 } = {}) {
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
const sock = connect({
|
|
34
|
+
port,
|
|
35
|
+
host: "127.0.0.1"
|
|
36
|
+
});
|
|
37
|
+
const done = (free) => {
|
|
38
|
+
sock.removeAllListeners();
|
|
39
|
+
sock.destroy();
|
|
40
|
+
resolve(free);
|
|
41
|
+
};
|
|
42
|
+
sock.setTimeout(timeoutMs);
|
|
43
|
+
sock.once("connect", () => done(false));
|
|
44
|
+
sock.once("error", () => done(true));
|
|
45
|
+
sock.once("timeout", () => done(false));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const FIRST_PORT = 8082;
|
|
49
|
+
async function computeNextPort(isFree = isPortFree) {
|
|
50
|
+
const taken = new Set(allMetroPorts());
|
|
51
|
+
for (let port = FIRST_PORT; port < 8282; port++) {
|
|
52
|
+
if (taken.has(port)) continue;
|
|
53
|
+
if (await isFree(port)) return port;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Found no free Metro port between ${FIRST_PORT} and 8281. Free one up, or stop a stale bundler (\`stim status\`, \`stim stop <port>\`).`);
|
|
56
|
+
}
|
|
57
|
+
async function findReclaimablePort(excludeProjectPath, probe = isMetroRunning, { isMounted = isOnMountedVolume, mountedVolumes } = {}) {
|
|
58
|
+
const cfg = loadConfig();
|
|
59
|
+
if (!cfg?.projects) return null;
|
|
60
|
+
const mounted = mountedVolumes || listMountedVolumes();
|
|
61
|
+
const candidates = [];
|
|
62
|
+
for (const [path, proj] of Object.entries(cfg.projects)) {
|
|
63
|
+
if (path === excludeProjectPath) continue;
|
|
64
|
+
if (Object.keys(proj.ports ?? {}).length) continue;
|
|
65
|
+
if (existsSync(path)) continue;
|
|
66
|
+
if (!isMounted(path, mounted)) continue;
|
|
67
|
+
if (typeof proj.metroPort === "number") candidates.push({
|
|
68
|
+
port: proj.metroPort,
|
|
69
|
+
ownerPath: path
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
for (const c of candidates) if (!await probe(c.port)) return c;
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
async function allocatePort(projectPath, probe = isMetroRunning, isFree = isPortFree) {
|
|
76
|
+
const reclaim = await findReclaimablePort(projectPath, probe);
|
|
77
|
+
if (reclaim && await isFree(reclaim.port)) {
|
|
78
|
+
removeProject(reclaim.ownerPath);
|
|
79
|
+
return reclaim.port;
|
|
80
|
+
}
|
|
81
|
+
return computeNextPort(isFree);
|
|
82
|
+
}
|
|
83
|
+
const RESERVE_ATTEMPTS = 5;
|
|
84
|
+
async function reserveMetroPort(projectPath, probe = isMetroRunning, isFree = isPortFree) {
|
|
85
|
+
for (let attempt = 0; attempt < RESERVE_ATTEMPTS; attempt++) {
|
|
86
|
+
const port = await allocatePort(projectPath, probe, isFree);
|
|
87
|
+
const claimed = claimMetroPort(projectPath, port);
|
|
88
|
+
if (claimed !== null) return claimed;
|
|
89
|
+
}
|
|
90
|
+
throw new Error(`Could not reserve a Metro port after ${RESERVE_ATTEMPTS} attempts: another Stim run claimed each one first. Retry.`);
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/metro.ts
|
|
94
|
+
/**
|
|
95
|
+
* True when some process with this pid exists right now. It cannot tell a recycled pid from the
|
|
96
|
+
* process that first held it, so it is only valid for a pid this run spawned and still holds a
|
|
97
|
+
* handle on. For a pid read from a record on disk, decide with `inspectProcessIdentity` on that
|
|
98
|
+
* record's process token, or take an ownership claim (`ownership-claim.ts`): this answer would keep
|
|
99
|
+
* a dead holder's record looking live until some unrelated process exits.
|
|
100
|
+
*/
|
|
101
|
+
function pidExists(pid) {
|
|
102
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
103
|
+
try {
|
|
104
|
+
process.kill(pid, 0);
|
|
105
|
+
return true;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
return error.code !== "ESRCH";
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function parseLsofPids(out) {
|
|
111
|
+
if (!out) return [];
|
|
112
|
+
return String(out).split("\n").map((s) => parseInt(s.trim(), 10)).filter((n) => Number.isFinite(n));
|
|
113
|
+
}
|
|
114
|
+
function addressPort(address) {
|
|
115
|
+
const colon = String(address ?? "").lastIndexOf(":");
|
|
116
|
+
return colon < 0 ? NaN : Number(String(address).slice(colon + 1));
|
|
117
|
+
}
|
|
118
|
+
function parseNetstatPids(out, port) {
|
|
119
|
+
const pids = [];
|
|
120
|
+
for (const line of String(out ?? "").split("\n")) {
|
|
121
|
+
const cols = line.trim().split(/\s+/);
|
|
122
|
+
if (cols.length < 5 || cols[0]?.toUpperCase() !== "TCP") continue;
|
|
123
|
+
if (addressPort(cols[1]) !== port || addressPort(cols[2]) !== 0) continue;
|
|
124
|
+
const pid = Number(cols.at(-1));
|
|
125
|
+
if (Number.isSafeInteger(pid) && pid > 0 && !pids.includes(pid)) pids.push(pid);
|
|
126
|
+
}
|
|
127
|
+
return pids;
|
|
128
|
+
}
|
|
129
|
+
function listeningPids(port, platform = process.platform) {
|
|
130
|
+
const pids = parseLsofPids(getExecutor().runQuiet(`lsof -nP -iTCP:${port} -sTCP:LISTEN -t`));
|
|
131
|
+
if (pids.length > 0 || platform !== "win32") return pids;
|
|
132
|
+
return parseNetstatPids(getExecutor().runQuiet("netstat -ano"), port);
|
|
133
|
+
}
|
|
134
|
+
function parseLsofCwd(out) {
|
|
135
|
+
if (!out) return null;
|
|
136
|
+
const lines = String(out).split("\n");
|
|
137
|
+
const idx = lines.findIndex((l) => l === "fcwd");
|
|
138
|
+
if (idx === -1) return null;
|
|
139
|
+
const nLine = lines.slice(idx + 1).find((l) => l.startsWith("n"));
|
|
140
|
+
return nLine ? nLine.slice(1) : null;
|
|
141
|
+
}
|
|
142
|
+
function processCwd(pid) {
|
|
143
|
+
if (process.platform === "linux") try {
|
|
144
|
+
return readlinkSync(`/proc/${pid}/cwd`);
|
|
145
|
+
} catch {}
|
|
146
|
+
return parseLsofCwd(getExecutor().runQuiet(`lsof -a -p ${pid} -d cwd -Fn`));
|
|
147
|
+
}
|
|
148
|
+
function canonicalPath(path) {
|
|
149
|
+
try {
|
|
150
|
+
return realpathSync(path);
|
|
151
|
+
} catch {
|
|
152
|
+
return path;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function isInsideProject(cwd, projectPath) {
|
|
156
|
+
if (!cwd || !projectPath) return false;
|
|
157
|
+
const a = canonicalPath(cwd);
|
|
158
|
+
const b = canonicalPath(projectPath);
|
|
159
|
+
return a === b || a.startsWith(b.endsWith(sep) ? b : b + sep);
|
|
160
|
+
}
|
|
161
|
+
const NOT_OURS_UNRESPONSIVE = "unresponsive";
|
|
162
|
+
const NOT_OURS_UNREADABLE_CWD = "unreadable-cwd";
|
|
163
|
+
const NOT_OURS_FOREIGN_CWD = "foreign-cwd";
|
|
164
|
+
function ownedSupervisor(projectPath, port) {
|
|
165
|
+
const supervisor = readWorkspaceState(canonicalPath(projectPath))?.supervisor;
|
|
166
|
+
if (supervisor?.port !== port || (0, process_identity_exports.inspectProcessIdentity)(supervisor) !== "same") return null;
|
|
167
|
+
return supervisor;
|
|
168
|
+
}
|
|
169
|
+
async function resolveProjectMetro(port, projectPath, { probe = isMetroRunning, cwdOf = processCwd } = {}) {
|
|
170
|
+
const pid = listeningPids(port)[0];
|
|
171
|
+
if (pid === void 0) return { missing: true };
|
|
172
|
+
if (!await probe(port)) return {
|
|
173
|
+
notOurs: `pid ${pid} on port ${port} does not answer Metro's /status`,
|
|
174
|
+
kind: NOT_OURS_UNRESPONSIVE,
|
|
175
|
+
pid
|
|
176
|
+
};
|
|
177
|
+
const cwd = cwdOf(pid);
|
|
178
|
+
if (!cwd) {
|
|
179
|
+
const owner = ownedSupervisor(projectPath, port);
|
|
180
|
+
if (owner && (pid === owner.pid || pid === owner.serverPid)) return { metro: {
|
|
181
|
+
pid,
|
|
182
|
+
leader: owner.pid,
|
|
183
|
+
cwd: canonicalPath(projectPath),
|
|
184
|
+
processToken: owner.processToken
|
|
185
|
+
} };
|
|
186
|
+
return {
|
|
187
|
+
notOurs: `pid ${pid} on port ${port}: working directory could not be read`,
|
|
188
|
+
kind: NOT_OURS_UNREADABLE_CWD,
|
|
189
|
+
pid
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (!isInsideProject(cwd, projectPath)) return {
|
|
193
|
+
notOurs: `pid ${pid} on port ${port} runs from ${cwd}, outside ${projectPath}`,
|
|
194
|
+
kind: NOT_OURS_FOREIGN_CWD,
|
|
195
|
+
pid
|
|
196
|
+
};
|
|
197
|
+
const owner = ownedSupervisor(projectPath, port);
|
|
198
|
+
return { metro: {
|
|
199
|
+
pid,
|
|
200
|
+
leader: owner ? owner.pid : pid,
|
|
201
|
+
cwd,
|
|
202
|
+
...owner ? { processToken: owner.processToken } : {}
|
|
203
|
+
} };
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Terminate a process and everything it spawned. On POSIX `group` signals the process group, which
|
|
207
|
+
* is what a detached leader owns. Windows has no process groups, and its SIGTERM is
|
|
208
|
+
* TerminateProcess: no handler runs and no child is reached, so a spawned dev server or `adb
|
|
209
|
+
* logcat` would outlive its parent. taskkill /T is the only route to the tree there, and it is
|
|
210
|
+
* always forceful.
|
|
211
|
+
*/
|
|
212
|
+
function signalProcessTree(pid, signal = "SIGTERM", { group = false, platform = process.platform } = {}) {
|
|
213
|
+
if (platform !== "win32") return process.kill(group ? -pid : pid, signal);
|
|
214
|
+
return getExecutor().runFileQuiet("taskkill", [
|
|
215
|
+
"/PID",
|
|
216
|
+
String(pid),
|
|
217
|
+
"/T",
|
|
218
|
+
"/F"
|
|
219
|
+
]) !== null;
|
|
220
|
+
}
|
|
221
|
+
function killMetroTree(leader, processToken) {
|
|
222
|
+
if (!leader || leader === process.pid || (0, process_identity_exports.inspectProcessIdentity)({
|
|
223
|
+
pid: leader,
|
|
224
|
+
processToken
|
|
225
|
+
}) !== "same") return false;
|
|
226
|
+
try {
|
|
227
|
+
return signalProcessTree(leader, "SIGTERM", { group: true });
|
|
228
|
+
} catch {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
export { resolveProjectMetro as a, isPortFree as c, pidExists as i, reserveMetroPort as l, killMetroTree as n, signalProcessTree as o, listeningPids as r, isMetroRunning as s, NOT_OURS_FOREIGN_CWD as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
2
|
-
import { C as withConfigLock, f as getProject, g as loadConfig, s as ensureConfig, u as getConfigDir, w as process_identity_exports, y as saveConfig } from "./config-
|
|
3
|
-
import {
|
|
4
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-
|
|
1
|
+
import { t as getExecutor } from "./exec-B29XNuhP.mjs";
|
|
2
|
+
import { C as withConfigLock, f as getProject, g as loadConfig, s as ensureConfig, u as getConfigDir, w as process_identity_exports, y as saveConfig } from "./config-B7iyKWkL.mjs";
|
|
3
|
+
import { c as isPortFree, o as signalProcessTree, r as listeningPids } from "./metro-C7bcJ0uo.mjs";
|
|
4
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BYfZz_S-.mjs";
|
|
5
5
|
import { realpathSync } from "node:fs";
|
|
6
6
|
//#region src/named-ports.ts
|
|
7
7
|
const FIRST_PORT = 8900;
|
|
@@ -10,7 +10,8 @@ function validatePortLabel(label) {
|
|
|
10
10
|
if (label === "metro") throw new Error("metro is managed by stim start and stim stop; choose another label.");
|
|
11
11
|
if (!/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/.test(label)) throw new Error("A port label must start with a letter and contain at most 64 letters, digits, underscores or hyphens.");
|
|
12
12
|
}
|
|
13
|
-
function portListeners(port) {
|
|
13
|
+
function portListeners(port, platform) {
|
|
14
|
+
if (platform === "win32") return listeningPids(port, platform);
|
|
14
15
|
let out;
|
|
15
16
|
try {
|
|
16
17
|
out = getExecutor().runFile("lsof", [
|
|
@@ -28,10 +29,29 @@ function portListeners(port) {
|
|
|
28
29
|
if (pids.some((pid) => !Number.isSafeInteger(pid) || pid <= 0)) throw new Error(`lsof returned an invalid listener for TCP port ${port}.`);
|
|
29
30
|
return [...new Set(pids)];
|
|
30
31
|
}
|
|
32
|
+
function processCommand(pid, platform) {
|
|
33
|
+
const e = getExecutor();
|
|
34
|
+
if (platform === "win32") {
|
|
35
|
+
const csv = e.runFileQuiet("tasklist", [
|
|
36
|
+
"/FI",
|
|
37
|
+
`PID eq ${pid}`,
|
|
38
|
+
"/FO",
|
|
39
|
+
"CSV",
|
|
40
|
+
"/NH"
|
|
41
|
+
], { timeoutMs: 5e3 });
|
|
42
|
+
return /^"([^"]*)"/.exec((csv ?? "").trim())?.[1] ?? "";
|
|
43
|
+
}
|
|
44
|
+
return (e.runFileQuiet("ps", [
|
|
45
|
+
"-p",
|
|
46
|
+
String(pid),
|
|
47
|
+
"-o",
|
|
48
|
+
"args="
|
|
49
|
+
], { timeoutMs: 5e3 }) ?? "").trim();
|
|
50
|
+
}
|
|
31
51
|
function withPortsLock(fn) {
|
|
32
52
|
return withWorkspaceProcessLock(getConfigDir(), "ports", fn, { external: true });
|
|
33
53
|
}
|
|
34
|
-
async function getNamedPort(projectPath, label, { isFree = async (port) => await isPortFree(port) && portListeners(port).length === 0, log = console.error } = {}) {
|
|
54
|
+
async function getNamedPort(projectPath, label, { isFree = async (port) => await isPortFree(port) && portListeners(port, process.platform).length === 0, log = console.error } = {}) {
|
|
35
55
|
validatePortLabel(label);
|
|
36
56
|
const root = realpathSync(projectPath);
|
|
37
57
|
return withPortsLock(async () => {
|
|
@@ -61,37 +81,33 @@ async function getNamedPort(projectPath, label, { isFree = async (port) => await
|
|
|
61
81
|
throw new Error(`No free named port between ${FIRST_PORT} and ${LAST_PORT}. Use stim ports stop or stim ports release in a workspace that no longer needs its ports.`);
|
|
62
82
|
});
|
|
63
83
|
}
|
|
64
|
-
async function stopListeners(port, label, dryRun, log) {
|
|
65
|
-
|
|
84
|
+
async function stopListeners(port, label, dryRun, log, platform) {
|
|
85
|
+
const listeners = () => portListeners(port, platform);
|
|
86
|
+
for (const pid of listeners()) {
|
|
66
87
|
if (pid === process.pid) throw new Error(`Refusing to stop Stim itself on ${label} (${port}).`);
|
|
67
88
|
const identity = (0, process_identity_exports.captureProcessIdentity)(pid);
|
|
68
89
|
if (!identity.ok) {
|
|
69
|
-
if (!
|
|
90
|
+
if (!listeners().includes(pid)) continue;
|
|
70
91
|
throw new Error(`Cannot identify pid ${pid} on ${label} (${port}): ${identity.reason}`);
|
|
71
92
|
}
|
|
72
93
|
const record = {
|
|
73
94
|
pid,
|
|
74
95
|
processToken: identity.token
|
|
75
96
|
};
|
|
76
|
-
const command =
|
|
77
|
-
"-p",
|
|
78
|
-
String(pid),
|
|
79
|
-
"-o",
|
|
80
|
-
"args="
|
|
81
|
-
], { timeoutMs: 5e3 }).trim();
|
|
97
|
+
const command = processCommand(pid, platform);
|
|
82
98
|
if (dryRun) {
|
|
83
99
|
log(`would stop ${label} (${port}): pid ${pid} ${command}`);
|
|
84
100
|
continue;
|
|
85
101
|
}
|
|
86
|
-
if (!
|
|
102
|
+
if (!listeners().includes(pid)) continue;
|
|
87
103
|
const status = (0, process_identity_exports.inspectProcessIdentity)(record);
|
|
88
104
|
if (status === "gone" || status === "different") continue;
|
|
89
105
|
if (status !== "same") throw new Error(`Cannot verify pid ${pid} on ${label} (${port}); allocation kept.`);
|
|
90
106
|
try {
|
|
91
|
-
|
|
107
|
+
signalProcessTree(pid, "SIGTERM", { platform });
|
|
92
108
|
if (!await (0, process_identity_exports.waitForProcessExit)(record, 2e3)) {
|
|
93
109
|
if ((0, process_identity_exports.inspectProcessIdentity)(record) !== "same") throw new Error(`Cannot verify pid ${pid} before SIGKILL.`);
|
|
94
|
-
|
|
110
|
+
signalProcessTree(pid, "SIGKILL", { platform });
|
|
95
111
|
if (!await (0, process_identity_exports.waitForProcessExit)(record, 2e3)) throw new Error(`Pid ${pid} did not exit.`);
|
|
96
112
|
}
|
|
97
113
|
} catch (error) {
|
|
@@ -99,36 +115,35 @@ async function stopListeners(port, label, dryRun, log) {
|
|
|
99
115
|
}
|
|
100
116
|
log(`stopped ${label} (${port}): pid ${pid} ${command}`);
|
|
101
117
|
}
|
|
102
|
-
if (!dryRun &&
|
|
118
|
+
if (!dryRun && listeners().length) throw new Error(`Port ${port} still has a listener; allocation kept.`);
|
|
103
119
|
}
|
|
104
|
-
async function clearNamedPorts(projectPath, { label, stop = false, dryRun = false, log = console.error } = {}) {
|
|
120
|
+
async function clearNamedPorts(projectPath, { label, stop = false, dryRun = false, log = console.error, platform = process.platform } = {}) {
|
|
105
121
|
if (label !== void 0) validatePortLabel(label);
|
|
106
122
|
await withPortsLock(async () => {
|
|
107
123
|
const ports = getProject(projectPath)?.ports ?? {};
|
|
124
|
+
const selected = Object.entries(ports).filter(([name]) => label === void 0 || name === label);
|
|
125
|
+
if (stop && selected.length > 0 && platform !== "win32" && !getExecutor().findExecutable("lsof")) throw new Error("Cannot stop named ports: lsof is not installed.");
|
|
108
126
|
const failures = [];
|
|
109
|
-
for (const [name, port] of
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
if (Object.values(loadConfig()?.projects ?? {}).some((project) => project.metroPort === port)) throw new Error(`Port ${port} is reserved for managed Metro; allocation kept.`);
|
|
115
|
-
await stopListeners(port, name, dryRun, log);
|
|
116
|
-
}
|
|
117
|
-
if (dryRun) {
|
|
118
|
-
log(`would release ${name} (${port})`);
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
withConfigLock(() => {
|
|
122
|
-
const cfg = loadConfig();
|
|
123
|
-
const current = cfg?.projects?.[projectPath]?.ports;
|
|
124
|
-
if (!cfg || current?.[name] !== port) return;
|
|
125
|
-
delete current[name];
|
|
126
|
-
saveConfig(cfg);
|
|
127
|
-
});
|
|
128
|
-
log(`released ${name} (${port})`);
|
|
129
|
-
} catch (error) {
|
|
130
|
-
failures.push(`${name} (${port}): ${error.message}`);
|
|
127
|
+
for (const [name, port] of selected) try {
|
|
128
|
+
if (!Number.isInteger(port) || port < FIRST_PORT || port > LAST_PORT) throw new Error(`Invalid named port ${name} (${port}); repair its config record before cleanup.`);
|
|
129
|
+
if (stop) {
|
|
130
|
+
if (Object.values(loadConfig()?.projects ?? {}).some((project) => project.metroPort === port)) throw new Error(`Port ${port} is reserved for managed Metro; allocation kept.`);
|
|
131
|
+
await stopListeners(port, name, dryRun, log, platform);
|
|
131
132
|
}
|
|
133
|
+
if (dryRun) {
|
|
134
|
+
log(`would release ${name} (${port})`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
withConfigLock(() => {
|
|
138
|
+
const cfg = loadConfig();
|
|
139
|
+
const current = cfg?.projects?.[projectPath]?.ports;
|
|
140
|
+
if (!cfg || current?.[name] !== port) return;
|
|
141
|
+
delete current[name];
|
|
142
|
+
saveConfig(cfg);
|
|
143
|
+
});
|
|
144
|
+
log(`released ${name} (${port})`);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
failures.push(`${name} (${port}): ${error.message}`);
|
|
132
147
|
}
|
|
133
148
|
if (failures.length) throw new Error(failures.join("\n"));
|
|
134
149
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { w as process_identity_exports } from "./config-
|
|
2
|
-
import { a as withWorkspaceStateLock, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-
|
|
3
|
-
import {
|
|
1
|
+
import { w as process_identity_exports } from "./config-B7iyKWkL.mjs";
|
|
2
|
+
import { a as withWorkspaceStateLock, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
|
|
3
|
+
import { i as pidExists } from "./metro-C7bcJ0uo.mjs";
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
5
|
//#region src/collector/state.ts
|
|
6
6
|
function collectorRoot(root) {
|