stim 1.13.0 → 1.15.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 +2 -0
- package/dist/{activity-DfVKZTEB.mjs → activity-B2-kb7k0.mjs} +281 -41
- package/dist/{android-BHfAu2mf.mjs → android-CYmq0jNi.mjs} +2 -2
- package/dist/{android-CD8pr8Q2.mjs → android-Cu_L4RpL.mjs} +524 -412
- package/dist/{android-qx_31wJo.mjs → android-Db2eEMaf.mjs} +152 -65
- package/dist/android-cas-PnKfAdB2.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{app-install-CDFY2nUL.mjs → app-install-CAAplXAt.mjs} +162 -173
- package/dist/{budget-E5o91NR1.mjs → budget-CMiqghig.mjs} +1048 -77
- package/dist/{build-plan-BTa93o_r.mjs → build-plan-aeGMFX7e.mjs} +193 -650
- package/dist/build-progress-C2Jv1AtA.mjs +872 -0
- package/dist/build-slots-Df1ApSuH.mjs +127 -0
- package/dist/{cache-manifest-DWPF4RKJ.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-B5hWgQJS.mjs → chrome-BrcVWQyD.mjs} +4 -4
- package/dist/cli-0cX5s4NM.mjs +45 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-C2IS36Qf.mjs +1333 -0
- package/dist/collector-run.mjs +8 -7
- package/dist/{command-output-BIL7rlX7.mjs → command-output-CliHHn7a.mjs} +1 -1
- package/dist/{config-0jCcMM0E.mjs → config-D0DbpZtM.mjs} +29 -29
- package/dist/{created-devices-Cd558h31.mjs → created-devices-BwVb3liH.mjs} +2 -2
- package/dist/{dependency-state-DNN0yfx6.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
- package/dist/{deps-2Wo81np9.mjs → deps-BFlKbOIp.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CjzLoNs0.mjs +80 -0
- package/dist/{device-Cf7vl-so.mjs → device-BZ1IyS5A.mjs} +7 -7
- package/dist/device-capacity-DMuKC7nx.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +769 -0
- package/dist/device-ios-DMQBUPus.mjs +381 -0
- package/dist/{device-lease-CL9dZf73.mjs → device-lease-W5Pi1q38.mjs} +43 -36
- package/dist/{device-pool-MuoiyRcu.mjs → device-pool-B2r38YjS.mjs} +4 -4
- package/dist/{device-remote-DT9ngZiD.mjs → device-remote-9ulPsdhY.mjs} +68 -162
- package/dist/{doctor-D2iysNNH.mjs → doctor-BcE5xsBn.mjs} +191 -99
- package/dist/{error-diagnostics-BoiOhck8.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-eA-PRBX8.mjs → gc-BuL1Genr.mjs} +430 -102
- package/dist/{android-cas-B9Kv9aIy.mjs → gradle-CmdOBq1d.mjs} +8 -294
- package/dist/{guide-BfZ0OmiP.mjs → guide-cCSGRFd3.mjs} +2052 -240
- package/dist/{guide-status-BaMYu55M.mjs → guide-status-CIoWK6mG.mjs} +3 -3
- package/dist/hosted-macos-DwowNU7W.mjs +447 -0
- package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
- package/dist/in-use-CndPMilN.mjs +110 -0
- package/dist/{ios-CmEzZiOj.mjs → ios-3CtCRhwr.mjs} +201 -10
- package/dist/{ios-CcfCeZ19.mjs → ios-Chob8ny7.mjs} +560 -259
- package/dist/{ios-device-BW-t_Lkv.mjs → ios-device-DERmMmk-.mjs} +12 -7
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{launch-verify-CuJaBpEa.mjs → launch-verify-CLlofxRt.mjs} +42 -11
- package/dist/{logs-DcSRbC2t.mjs → logs-h9h6MUvE.mjs} +95 -13
- package/dist/machine-usage-D_YYMzfR.mjs +283 -0
- package/dist/machines-CYtOCqcj.mjs +259 -0
- package/dist/macos-BwtbUtTN.mjs +468 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
- package/dist/{metro-BPeY1YMh.mjs → metro-Di8EN2Tb.mjs} +20 -120
- package/dist/{named-ports-n7tnJsI8.mjs → named-ports-Dj_XBNaL.mjs} +8 -64
- package/dist/native-run-DFDoIRbY.mjs +147 -0
- package/dist/{native-runtime-CiiFHt0e.mjs → native-runtime-i6OkVg-w.mjs} +11 -6
- package/dist/offload-worker.d.mts +121 -0
- package/dist/offload-worker.mjs +601 -0
- package/dist/{ownership-Bz2kETAS.mjs → ownership-BkYxUtuj.mjs} +3 -2
- package/dist/{page-BTu7I60K.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-C5UutqpJ.mjs → ports-DddwttKM.mjs} +3 -3
- package/dist/prebuild-BvxDlD6C.mjs +213 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-DGeclhvO.mjs → project-CV3tDFHl.mjs} +9 -18
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-GEXp4iBT.mjs +37 -0
- package/dist/{reload-C-cV5yy_.mjs → reload-ChPiwvot.mjs} +70 -22
- package/dist/{remote-cache--aehr4Pr.mjs → remote-cache-CO2elm_b.mjs} +4 -4
- package/dist/run-B-xqRrsg.mjs +119 -0
- package/dist/{server-bare-Bq8BpSIo.mjs → server-bare-X7PUgizL.mjs} +60 -13
- package/dist/{server-expo-DUCg52-K.mjs → server-expo-DhtX6bom.mjs} +6 -10
- package/dist/server-expo-KJeD109I.mjs +2 -0
- package/dist/{settings-xB0Frkg6.mjs → settings-CduVcoxj.mjs} +77 -26
- package/dist/{settings-ssVBToDR.mjs → settings-DbL6uhH8.mjs} +16 -10
- package/dist/settings.schema.json +357 -2
- package/dist/{simslim-Bbg9UWrt.mjs → simslim-Ciluxlq4.mjs} +8 -132
- package/dist/slot-launch-BY0BrOLh.mjs +65 -0
- package/dist/{spawn-claims-PT8aQpCa.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-DncpJvWL.mjs +16 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CPO4wRg7.mjs +2 -0
- package/dist/{start-BZhItkiL.mjs → start-CUD9nasA.mjs} +108 -61
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/state-BxCgeTQu.mjs +41 -0
- package/dist/{state-DwAU2_-D.mjs → state-CaeaHbDA.mjs} +7 -4
- package/dist/{state-l1pYwOre.mjs → state-DFm77wRn.mjs} +67 -5
- package/dist/stats-DBLLFmKd.mjs +66 -0
- package/dist/{status-TJlL0HWo.mjs → status-DYXxNOT0.mjs} +425 -260
- package/dist/{status-sszP4XKU.mjs → status-l84Gbvp2.mjs} +122 -20
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/{stop-BZ2qMiBP.mjs → stop-Bad61z_2.mjs} +128 -19
- package/dist/stop-Bvf1MflS.mjs +48 -0
- package/dist/{stop-DskDKNTU.mjs → stop-CceYh1yG.mjs} +2 -2
- package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
- package/dist/supervisor-run.d.mts +44 -12
- package/dist/supervisor-run.mjs +276 -33
- package/dist/support-CDQbDkL5.mjs +315 -0
- package/dist/support-WLOzVKUv.mjs +176 -0
- package/dist/teardown-BYuQafiA.mjs +718 -0
- package/dist/{xcode-LM6A8cNZ.mjs → toolchain-DmeYjXD9.mjs} +363 -13
- package/dist/warm-progress-DVHLN4uC.mjs +463 -0
- package/dist/{idle-DxLi5OkN.mjs → watchman-Bx0wceoF.mjs} +55 -8
- package/dist/{web-sWXd5iek.mjs → web-k6w8-HnE.mjs} +39 -22
- package/dist/web-run.mjs +326 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-CL2V2Ons.mjs +371 -0
- package/dist/worktree-BT_uULFx.mjs +2 -0
- package/dist/{worktree-DeBQSVtR.mjs → worktree-C0c5Udwa.mjs} +55 -54
- package/dist/{worktree-D4Do_XiQ.mjs → worktree-qXKzADSC.mjs} +161 -255
- package/package.json +10 -5
- package/shim/bundle-response.cjs +55 -10
- package/shim/bundle-response.d.cts +1 -0
- package/shim/expo-metro-config.cjs +10 -2
- package/dist/build-progress-l7d-X-ZP.mjs +0 -247
- package/dist/in-use-wYEaKQM9.mjs +0 -249
- package/dist/ownership-PUP4Dwai.mjs +0 -1138
- package/dist/server-expo-BeYwP_Xy.mjs +0 -2
- package/dist/slot-launch-BIWEW-wI.mjs +0 -19
- package/dist/start-Rw2GD3nV.mjs +0 -2
- package/dist/stats-CaSwmsSZ.mjs +0 -62
- package/dist/stats-D8rUTPHd.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/worktree-3cBa-bQt.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { a as
|
|
9
|
-
import { u as
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
import { E as upsertProject, H as projectDeviceSlots, S as removeProject, _ as loadConfig$1, a as clearDevice, d as getConfigDir, g as isPathPrefix, k as acquireAvdClaim, p as getProject } from "./config-D0DbpZtM.mjs";
|
|
3
|
+
import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
4
|
+
import { a as pullRequestLookup, r as endedPullRequest } from "./pull-request-pxnDCQzn.mjs";
|
|
5
|
+
import { b as workspaceDir, i as recordWorkspaceUse, r as readWorkspaceState$1 } from "./workspace-state-CL2V2Ons.mjs";
|
|
6
|
+
import { C as sourceCheckoutOf, S as restoreFile, T as warmWorktreePaths, _ as readWorktreeExclude, b as resolveFullRef, d as hasUncommittedWork, f as isPodInstallChurn, g as podsOutOfSync, h as locallyKnownUpstream, i as depsOutOfSync, l as hasPopulatedSubmodules, m as listWorktrees, n as cloneIgnoredEntries, o as dirtyPaths, r as deleteBranch, s as gitCommonDir, t as branchExists, u as hasRemote, v as removeWorktree, w as unpushedCommits } from "./worktree-C0c5Udwa.mjs";
|
|
7
|
+
import { a as findProjectRoot$1, n as appProjectProblem } from "./project-CV3tDFHl.mjs";
|
|
8
|
+
import { a as clearRemoteSession, c as readMetroTunnel, d as readRemoteSessionId, i as clearManagedMetroTunnel, u as readRemoteSession } from "./state-CaeaHbDA.mjs";
|
|
9
|
+
import { a as formatElapsed, h as shortUdid, i as formatDuration, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-CliHHn7a.mjs";
|
|
10
|
+
import { u as releaseWorkspaceLeases } from "./device-lease-W5Pi1q38.mjs";
|
|
11
|
+
import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
|
|
12
|
+
import { at as POOL_SETTING_REMEDY, dt as parkedMaxSetting } from "./android-Db2eEMaf.mjs";
|
|
13
|
+
import { l as resolveProjectMetro, o as pidExists, r as killMetroTree, u as signalProcessTree } from "./metro-Di8EN2Tb.mjs";
|
|
14
|
+
import { B as unknownSettingKeys, L as settingShapeErrors, N as resolveSettings, a as SETTING_SHAPE_REMEDY } from "./settings-CduVcoxj.mjs";
|
|
15
|
+
import { a as teardownOwnedBrowser, i as teardownOwnedAvd, o as teardownOwnedIosSim } from "./teardown-BYuQafiA.mjs";
|
|
16
|
+
import { t as clearNamedPorts } from "./named-ports-Dj_XBNaL.mjs";
|
|
17
|
+
import { o as readWebRecord } from "./state-DFm77wRn.mjs";
|
|
18
|
+
import { n as withIdleWorkspace, t as emptyWorkspaceDir } from "./in-use-CndPMilN.mjs";
|
|
19
|
+
import { g as withManagedRemoteWorktreeRemovalLock, l as withdrawDevServerStopRequest, p as stopTunnel, s as requestDevServerStop, u as resolveSupervisorTarget, v as withManagedTunnelRemovalLock } from "./stop-cause-CZ_Mr-v9.mjs";
|
|
20
|
+
import { n as verifyCollectorOwnership } from "./ownership-BkYxUtuj.mjs";
|
|
21
|
+
import { C as podInstallCommand, u as HEARTBEAT_INTERVAL_MS } from "./toolchain-DmeYjXD9.mjs";
|
|
22
|
+
import { t as stopMacosApp } from "./stop-Bvf1MflS.mjs";
|
|
23
|
+
import { a as runPodInstall, i as runCaptured, n as podsAreStale, r as readPodState, t as DEPS_ERROR } from "./deps-BFlKbOIp.mjs";
|
|
24
|
+
import { f as resolveEasCliBin } from "./remote-cache-CO2elm_b.mjs";
|
|
25
|
+
import { i as endRecordedSession } from "./device-remote-9ulPsdhY.mjs";
|
|
26
|
+
import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-BmsjKZ2H.mjs";
|
|
27
|
+
import { a as forgetStatusMeasures, t as startWarmProgress } from "./warm-progress-DVHLN4uC.mjs";
|
|
28
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
21
29
|
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
30
|
+
import { join, relative } from "node:path";
|
|
31
|
+
import { existsSync as existsSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1 } from "fs";
|
|
32
|
+
import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
|
|
24
33
|
import { workspaceName } from "@stim-cli/core";
|
|
25
|
-
import {
|
|
26
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
34
|
+
import { LAST_BUILD_KEYS, readMacosRecord } from "@stim-cli/core/state";
|
|
27
35
|
import chalk from "chalk";
|
|
28
36
|
//#region src/devices/reclaim.ts
|
|
29
37
|
async function reapCollectors(root, { verify = verifyCollectorOwnership, collectors }) {
|
|
@@ -166,14 +174,22 @@ function describeDereferenced(project) {
|
|
|
166
174
|
}
|
|
167
175
|
return devices;
|
|
168
176
|
}
|
|
169
|
-
function
|
|
177
|
+
function lastBuildCacheKey(projectPath, platform) {
|
|
178
|
+
const build = readWorkspaceState$1(projectPath)?.[LAST_BUILD_KEYS[platform]];
|
|
179
|
+
if (build === null || typeof build !== "object" || Array.isArray(build)) return null;
|
|
180
|
+
const { cacheKey } = build;
|
|
181
|
+
return typeof cacheKey === "string" ? cacheKey : null;
|
|
182
|
+
}
|
|
183
|
+
function parkRequest(project, projectPath, slot, simslimManaged) {
|
|
170
184
|
const { max, error } = parkedMaxSetting("ios");
|
|
171
185
|
if (error || max <= 0) return void 0;
|
|
172
186
|
return {
|
|
173
187
|
projectPath,
|
|
174
188
|
max,
|
|
175
189
|
simslimManaged,
|
|
176
|
-
slot
|
|
190
|
+
slot,
|
|
191
|
+
appId: typeof project?.bundleId === "string" ? project.bundleId : null,
|
|
192
|
+
cacheKey: lastBuildCacheKey(projectPath, "ios")
|
|
177
193
|
};
|
|
178
194
|
}
|
|
179
195
|
function reclaimOwnedDevices(project, projectPath, { park = false } = {}) {
|
|
@@ -191,7 +207,7 @@ function reclaimOwnedDevices(project, projectPath, { park = false } = {}) {
|
|
|
191
207
|
const r = teardownOwnedIosSim(udid, {
|
|
192
208
|
del: true,
|
|
193
209
|
label,
|
|
194
|
-
...park ? { park: parkRequest(projectPath, slot, Boolean(ios.simslimManaged)) } : {}
|
|
210
|
+
...park ? { park: parkRequest(project, projectPath, slot, Boolean(ios.simslimManaged)) } : {}
|
|
195
211
|
});
|
|
196
212
|
if (r.parkFallback) poolNotes.push(`could not park ${label}: ${r.parkFallback} -- deleted it instead`);
|
|
197
213
|
for (const failure of r.evictionFailures ?? []) poolNotes.push(failure);
|
|
@@ -230,7 +246,9 @@ function reclaimOwnedDevices(project, projectPath, { park = false } = {}) {
|
|
|
230
246
|
projectPath,
|
|
231
247
|
slot,
|
|
232
248
|
max: bound.max,
|
|
233
|
-
configuration: typeof android.poolConfiguration === "string" ? android.poolConfiguration : void 0
|
|
249
|
+
configuration: typeof android.poolConfiguration === "string" ? android.poolConfiguration : void 0,
|
|
250
|
+
appId: typeof project?.androidPackage === "string" ? project.androidPackage : null,
|
|
251
|
+
cacheKey: lastBuildCacheKey(projectPath, "android")
|
|
234
252
|
} } : {}
|
|
235
253
|
});
|
|
236
254
|
if (r.parkFallback) poolNotes.push(`could not park ${android.avdName}: ${r.parkFallback} -- deleted it instead`);
|
|
@@ -298,12 +316,12 @@ async function reclaimProject(path, options = {}) {
|
|
|
298
316
|
failedWorkspaceDirs: []
|
|
299
317
|
};
|
|
300
318
|
}
|
|
301
|
-
async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices = false, parkOwnedDevices = false, preserveProjectRecord = false, stopSession = defaultStopSession, stopMetroTunnel = defaultStopMetroTunnel, releaseLeases = releaseWorkspaceLeases, verifyCollector = verifyCollectorOwnership, teardownBrowser = teardownOwnedBrowser }) {
|
|
319
|
+
async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices = false, parkOwnedDevices = false, preserveProjectRecord = false, stopSession = defaultStopSession, stopMetroTunnel = defaultStopMetroTunnel, releaseLeases = releaseWorkspaceLeases, verifyCollector = verifyCollectorOwnership, teardownBrowser = teardownOwnedBrowser, stopRequester = { by: "stim gc --delete" } }) {
|
|
302
320
|
await clearNamedPorts(path, { stop: true });
|
|
303
321
|
const project = getProject(path);
|
|
304
322
|
for (const { platforms } of projectDeviceSlots(project)) if (platforms.android?.owned && platforms.android.avdName) (0, ownership_claim_exports.releaseClaim)(acquireAvdClaim(platforms.android.avdName));
|
|
305
323
|
const dereferenced = describeDereferenced(project);
|
|
306
|
-
const initialState = readWorkspaceState(path);
|
|
324
|
+
const initialState = readWorkspaceState$1(path);
|
|
307
325
|
let killedPid = null;
|
|
308
326
|
let skippedMetro = null;
|
|
309
327
|
let supervisorHeld = false;
|
|
@@ -318,7 +336,10 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
318
336
|
};
|
|
319
337
|
const orphanIdentity = supervisor.status === "stale" && typeof orphanServer.processToken === "string" ? (0, process_identity_exports.inspectProcessIdentity)(orphanServer) : null;
|
|
320
338
|
if (supervisor.status === "ours") {
|
|
321
|
-
|
|
339
|
+
requestDevServerStop(path, supervisor.processToken, stopRequester);
|
|
340
|
+
const signalled = killMetroTree(supervisor.pid, supervisor.processToken);
|
|
341
|
+
if (!signalled) withdrawDevServerStopRequest(path, supervisor.processToken);
|
|
342
|
+
if (signalled && await (0, process_identity_exports.waitForProcessExit)(supervisor, 1e4)) killedPid = supervisor.pid;
|
|
322
343
|
else {
|
|
323
344
|
skippedMetro = `could not confirm supervisor pid ${supervisor.pid} exited`;
|
|
324
345
|
supervisorHeld = true;
|
|
@@ -356,7 +377,7 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
356
377
|
failedCollectors.push(entry);
|
|
357
378
|
}
|
|
358
379
|
function retainReplacementProcesses() {
|
|
359
|
-
const currentState = readWorkspaceState(path);
|
|
380
|
+
const currentState = readWorkspaceState$1(path);
|
|
360
381
|
const currentProject = getProject(path);
|
|
361
382
|
if (Boolean(currentState?.supervisor && !(0, process_identity_exports.sameProcessRecord)(currentState.supervisor, initialState?.supervisor) || currentProject?.supervisor && !(0, process_identity_exports.sameProcessRecord)(currentProject.supervisor, project?.supervisor) || readWebRecord(path) !== null || Object.entries(currentState?.collectors ?? {}).some(([platform, record]) => !(0, process_identity_exports.sameProcessRecord)(record, initialState?.collectors?.[platform])))) {
|
|
362
383
|
supervisorHeld = true;
|
|
@@ -379,6 +400,17 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
379
400
|
skippedDevices.push(remote.failed);
|
|
380
401
|
failedDevices.push(remote.failed);
|
|
381
402
|
}
|
|
403
|
+
const hosted = readMacosRecord(path)?.host;
|
|
404
|
+
if (hosted) try {
|
|
405
|
+
await stopMacosApp(path);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
const failed = {
|
|
408
|
+
name: `hosted macOS session ${hosted.session} on ${hosted.machine}`,
|
|
409
|
+
reason: String(error?.message ?? error)
|
|
410
|
+
};
|
|
411
|
+
skippedDevices.push(failed);
|
|
412
|
+
failedDevices.push(failed);
|
|
413
|
+
}
|
|
382
414
|
const tunnel = await reclaimMetroTunnel(path, { stopMetroTunnel });
|
|
383
415
|
if (tunnel.failed) {
|
|
384
416
|
skippedDevices.push(tunnel.failed);
|
|
@@ -425,192 +457,6 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
425
457
|
};
|
|
426
458
|
}
|
|
427
459
|
//#endregion
|
|
428
|
-
//#region src/workspace/pull-request.ts
|
|
429
|
-
const GH_TIMEOUT_MS = 2e4;
|
|
430
|
-
const GH_ENV = {
|
|
431
|
-
GH_PROMPT_DISABLED: "1",
|
|
432
|
-
GH_NO_UPDATE_NOTIFIER: "1",
|
|
433
|
-
NO_COLOR: "1"
|
|
434
|
-
};
|
|
435
|
-
const GH_FIELDS = "number,state,url,headRefOid,mergedAt,closedAt,isCrossRepository";
|
|
436
|
-
const SIGNED_OUT_EXIT = 4;
|
|
437
|
-
function stateOf(state) {
|
|
438
|
-
if (state === "OPEN") return "open";
|
|
439
|
-
if (state === "MERGED") return "merged";
|
|
440
|
-
if (state === "CLOSED") return "closed";
|
|
441
|
-
return null;
|
|
442
|
-
}
|
|
443
|
-
function epoch(text) {
|
|
444
|
-
const at = text ? Date.parse(text) : NaN;
|
|
445
|
-
return Number.isFinite(at) ? at : null;
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Picks the pull request that describes `head` among those `gh pr list --head <branch>` returned. One whose head is
|
|
449
|
-
* `head` wins, then one whose head contains `head`, then one whose head `head` contains. An open one wins a tier,
|
|
450
|
-
* then the newest. A pull request unrelated to `head` is from an earlier use of the branch name, and one from a fork
|
|
451
|
-
* only shares the branch name; both are ignored.
|
|
452
|
-
* `isAncestor(a, b)` answers whether commit `a` is an ancestor of commit `b`, and false when git cannot tell.
|
|
453
|
-
*/
|
|
454
|
-
function selectPullRequest(pulls, head, isAncestor) {
|
|
455
|
-
const known = pulls.flatMap((pull) => {
|
|
456
|
-
const state = stateOf(pull.state);
|
|
457
|
-
return state && pull.headRefOid && !pull.isCrossRepository ? [{
|
|
458
|
-
pull,
|
|
459
|
-
state
|
|
460
|
-
}] : [];
|
|
461
|
-
});
|
|
462
|
-
const tiers = [
|
|
463
|
-
known.filter(({ pull }) => pull.headRefOid === head),
|
|
464
|
-
known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(head, pull.headRefOid)),
|
|
465
|
-
known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(pull.headRefOid, head))
|
|
466
|
-
];
|
|
467
|
-
const tier = tiers.findIndex((entries) => entries.length > 0);
|
|
468
|
-
if (tier < 0) return null;
|
|
469
|
-
const { pull, state } = tiers[tier].toSorted((a, b) => Number(b.state === "open") - Number(a.state === "open") || b.pull.number - a.pull.number)[0];
|
|
470
|
-
return {
|
|
471
|
-
number: pull.number,
|
|
472
|
-
state,
|
|
473
|
-
url: pull.url,
|
|
474
|
-
head: pull.headRefOid,
|
|
475
|
-
containsHead: tier < 2,
|
|
476
|
-
endedAt: state === "merged" ? epoch(pull.mergedAt) : state === "closed" ? epoch(pull.closedAt) : null
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
function firstLine(error) {
|
|
480
|
-
const { stderr, message } = error;
|
|
481
|
-
const text = String(stderr ?? "").trim() || String(message ?? error);
|
|
482
|
-
return text.split("\n")[0] ?? text;
|
|
483
|
-
}
|
|
484
|
-
function ghFailure(error, command) {
|
|
485
|
-
if (error.status === SIGNED_OUT_EXIT) return {
|
|
486
|
-
unavailable: "gh is not signed in; run `gh auth login`",
|
|
487
|
-
sticky: true
|
|
488
|
-
};
|
|
489
|
-
if (error.code === "ETIMEDOUT") return {
|
|
490
|
-
unavailable: `${command} did not answer within ${GH_TIMEOUT_MS / 1e3}s`,
|
|
491
|
-
sticky: true
|
|
492
|
-
};
|
|
493
|
-
return {
|
|
494
|
-
unavailable: `${command} failed: ${firstLine(error)}`,
|
|
495
|
-
sticky: false
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
function ancestry(cwd) {
|
|
499
|
-
const exec = getExecutor();
|
|
500
|
-
return (ancestor, descendant) => exec.runFileQuiet("git", [
|
|
501
|
-
"-C",
|
|
502
|
-
cwd,
|
|
503
|
-
"merge-base",
|
|
504
|
-
"--is-ancestor",
|
|
505
|
-
ancestor,
|
|
506
|
-
descendant
|
|
507
|
-
]) !== null;
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Asks GitHub, through `gh`, which pull requests have `branch` as their head, run from `cwd` so `gh` picks the
|
|
511
|
-
* repository from its remotes. Each call is one fixed `gh pr list` invocation. Once `gh` is missing, signed out or
|
|
512
|
-
* times out, every later lookup through the same function answers `unavailable` without running it again.
|
|
513
|
-
*/
|
|
514
|
-
function pullRequestLookup() {
|
|
515
|
-
let unavailable;
|
|
516
|
-
return (cwd, branch, head) => {
|
|
517
|
-
const exec = getExecutor();
|
|
518
|
-
if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
|
|
519
|
-
if (unavailable) return { unavailable };
|
|
520
|
-
let out;
|
|
521
|
-
try {
|
|
522
|
-
out = exec.runFile("gh", [
|
|
523
|
-
"pr",
|
|
524
|
-
"list",
|
|
525
|
-
"--head",
|
|
526
|
-
branch,
|
|
527
|
-
"--state",
|
|
528
|
-
"all",
|
|
529
|
-
"--limit",
|
|
530
|
-
"20",
|
|
531
|
-
"--json",
|
|
532
|
-
GH_FIELDS
|
|
533
|
-
], {
|
|
534
|
-
cwd,
|
|
535
|
-
timeoutMs: GH_TIMEOUT_MS,
|
|
536
|
-
env: GH_ENV
|
|
537
|
-
});
|
|
538
|
-
} catch (error) {
|
|
539
|
-
const failure = ghFailure(error, "gh pr list");
|
|
540
|
-
if (failure.sticky) unavailable = failure.unavailable;
|
|
541
|
-
return { unavailable: failure.unavailable };
|
|
542
|
-
}
|
|
543
|
-
let pulls;
|
|
544
|
-
try {
|
|
545
|
-
pulls = JSON.parse(out);
|
|
546
|
-
} catch {
|
|
547
|
-
return { unavailable: "gh pr list printed no JSON" };
|
|
548
|
-
}
|
|
549
|
-
return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd)) : null };
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
function branchesQuery(count) {
|
|
553
|
-
return `query($owner: String!, $repo: String!${Array.from({ length: count }, (_, i) => `, $b${i}: String!`).join("")}) { repository(owner: $owner, name: $repo) {${Array.from({ length: count }, (_, i) => ` b${i}: pullRequests(headRefName: $b${i}, states: [OPEN, CLOSED, MERGED], first: 20, orderBy: {field: CREATED_AT, direction: DESC}) { nodes { ${GH_FIELDS.replaceAll(",", " ")} } }`).join("")} } }`;
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* {@link pullRequestLookup} for every branch of one repository in one fixed `gh api graphql` call run from `repo`,
|
|
557
|
-
* which asks for the same 20 newest pull requests of each head branch that `gh pr list --head` returns. `gh` fills
|
|
558
|
-
* `{owner}` and `{repo}` from the remotes of `repo`; branch names travel as variables. Once `gh` is missing, signed
|
|
559
|
-
* out or times out, every later call through the same function answers `unavailable` without running it again.
|
|
560
|
-
*/
|
|
561
|
-
function pullRequestLookups() {
|
|
562
|
-
let unavailable;
|
|
563
|
-
return async (repo, queries) => {
|
|
564
|
-
const exec = getExecutor();
|
|
565
|
-
if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
|
|
566
|
-
const all = (lookup) => queries.map(() => lookup);
|
|
567
|
-
if (unavailable) return all({ unavailable });
|
|
568
|
-
if (!queries.length) return [];
|
|
569
|
-
const args = [
|
|
570
|
-
"api",
|
|
571
|
-
"graphql",
|
|
572
|
-
"-F",
|
|
573
|
-
"owner={owner}",
|
|
574
|
-
"-F",
|
|
575
|
-
"repo={repo}"
|
|
576
|
-
];
|
|
577
|
-
queries.forEach(({ branch }, i) => args.push("-f", `b${i}=${branch}`));
|
|
578
|
-
args.push("-f", `query=${branchesQuery(queries.length)}`);
|
|
579
|
-
let out;
|
|
580
|
-
try {
|
|
581
|
-
out = await exec.runFileAsync("gh", args, {
|
|
582
|
-
cwd: repo,
|
|
583
|
-
timeoutMs: GH_TIMEOUT_MS,
|
|
584
|
-
env: GH_ENV
|
|
585
|
-
});
|
|
586
|
-
} catch (error) {
|
|
587
|
-
const failure = ghFailure(error, "gh api graphql");
|
|
588
|
-
if (failure.sticky) unavailable = failure.unavailable;
|
|
589
|
-
return all({ unavailable: failure.unavailable });
|
|
590
|
-
}
|
|
591
|
-
let found;
|
|
592
|
-
try {
|
|
593
|
-
found = JSON.parse(out).data?.repository;
|
|
594
|
-
} catch {
|
|
595
|
-
return all({ unavailable: "gh api graphql printed no JSON" });
|
|
596
|
-
}
|
|
597
|
-
if (!found) return all({ unavailable: "gh api graphql printed no repository" });
|
|
598
|
-
return queries.map(({ cwd, head }, i) => {
|
|
599
|
-
const pulls = found[`b${i}`]?.nodes;
|
|
600
|
-
return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd)) : null };
|
|
601
|
-
});
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
/** The merged or closed pull request whose commits include HEAD, which makes the worktree removable. */
|
|
605
|
-
function endedPullRequest(lookup) {
|
|
606
|
-
const pr = lookup && "pullRequest" in lookup ? lookup.pullRequest : null;
|
|
607
|
-
return pr && pr.state !== "open" && pr.containsHead ? pr : null;
|
|
608
|
-
}
|
|
609
|
-
/** "PR #123 merged", for reports. */
|
|
610
|
-
function describePullRequest(pr) {
|
|
611
|
-
return `PR #${pr.number} ${pr.state}`;
|
|
612
|
-
}
|
|
613
|
-
//#endregion
|
|
614
460
|
//#region src/engine/warm-claim.ts
|
|
615
461
|
const WARM_CLAIM_LABEL = "worktree warm";
|
|
616
462
|
const WARM_CLAIM_POLL_MS = 250;
|
|
@@ -631,10 +477,10 @@ function defaultSleep(ms) {
|
|
|
631
477
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
632
478
|
}
|
|
633
479
|
function warmClaimsDir() {
|
|
634
|
-
return join
|
|
480
|
+
return join(getConfigDir(), "warm-locks");
|
|
635
481
|
}
|
|
636
482
|
function warmClaimPath(repositoryRoot) {
|
|
637
|
-
return join
|
|
483
|
+
return join(warmClaimsDir(), `${workspaceName(repositoryRoot)}.lock`);
|
|
638
484
|
}
|
|
639
485
|
function warmCommand(phase) {
|
|
640
486
|
return phase === "refresh" ? "stim worktree warm --refresh" : "stim worktree warm";
|
|
@@ -961,11 +807,11 @@ function stepLine(label, reason, action) {
|
|
|
961
807
|
return phaseLine(label, `${reason} -> ${action}`);
|
|
962
808
|
}
|
|
963
809
|
function installRecordFile(depsRoot) {
|
|
964
|
-
return join
|
|
810
|
+
return join(getConfigDir(), "warm-installs", `${workspaceName(depsRoot)}.json`);
|
|
965
811
|
}
|
|
966
812
|
function lockfileHash(depsRoot, lockfile) {
|
|
967
813
|
try {
|
|
968
|
-
return createHash("sha256").update(readFileSync(join
|
|
814
|
+
return createHash("sha256").update(readFileSync(join(depsRoot, lockfile))).digest("hex");
|
|
969
815
|
} catch {
|
|
970
816
|
return null;
|
|
971
817
|
}
|
|
@@ -987,7 +833,7 @@ function readInstallEvidence(depsRoot) {
|
|
|
987
833
|
function writeInstallEvidence(depsRoot, lockfile, hash, completed) {
|
|
988
834
|
const file = installRecordFile(depsRoot);
|
|
989
835
|
const tmp = `${file}.${process.pid}.${randomUUID()}.tmp`;
|
|
990
|
-
mkdirSync(join
|
|
836
|
+
mkdirSync(join(getConfigDir(), "warm-installs"), { recursive: true });
|
|
991
837
|
writeFileSync(tmp, JSON.stringify({
|
|
992
838
|
lock: lockfile,
|
|
993
839
|
hash: hash ?? "",
|
|
@@ -1005,9 +851,9 @@ function restoreInstallEvidence(depsRoot, prior) {
|
|
|
1005
851
|
else rmSync(installRecordFile(depsRoot), { force: true });
|
|
1006
852
|
}
|
|
1007
853
|
function inProgressOperation(gitDir) {
|
|
1008
|
-
if (existsSync(join
|
|
1009
|
-
if (existsSync(join
|
|
1010
|
-
return existsSync(join
|
|
854
|
+
if (existsSync(join(gitDir, "rebase-merge"))) return "rebase";
|
|
855
|
+
if (existsSync(join(gitDir, "rebase-apply"))) return existsSync(join(gitDir, "rebase-apply", "applying")) ? "am" : "rebase";
|
|
856
|
+
return existsSync(join(gitDir, "MERGE_HEAD")) ? "merge" : null;
|
|
1011
857
|
}
|
|
1012
858
|
function readMainCheckoutState(root) {
|
|
1013
859
|
const exec = getExecutor();
|
|
@@ -1261,7 +1107,7 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
|
|
|
1261
1107
|
const consumed = dependencies ? lockfileHash(dependencies.root, dependencies.lock) : null;
|
|
1262
1108
|
const deps = depsPlan({
|
|
1263
1109
|
lockfile: dependencies?.lock ?? null,
|
|
1264
|
-
lockfileChanged: dependencies ? pathChangedBetween(root, before, head, gitPath(relative
|
|
1110
|
+
lockfileChanged: dependencies ? pathChangedBetween(root, before, head, gitPath(relative(root, dependencies.root), dependencies.lock)) : false,
|
|
1265
1111
|
installed,
|
|
1266
1112
|
treeValid: dependencies?.lock === "package-lock.json" && installed ? installedNpmTreeIsValid(dependencies.root) : null,
|
|
1267
1113
|
lastInstall: priorInstall,
|
|
@@ -1293,11 +1139,11 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
|
|
|
1293
1139
|
if (marked) restoreInstallEvidence(marked.root, priorInstall);
|
|
1294
1140
|
emit(stepLine("deps", depsSubject, "skipped"));
|
|
1295
1141
|
}
|
|
1296
|
-
const app = relative
|
|
1142
|
+
const app = relative(root, appDir) || ".";
|
|
1297
1143
|
const where = `source ${appDir}: `;
|
|
1298
1144
|
const podState = readPodState(appDir);
|
|
1299
1145
|
const pods = podsPlan({
|
|
1300
|
-
hasIos: existsSync(join
|
|
1146
|
+
hasIos: existsSync(join(appDir, "ios")),
|
|
1301
1147
|
hasPodfile: podState.hasPodfile,
|
|
1302
1148
|
podfileLockChanged: pathChangedBetween(root, before, head, gitPath(app, "ios", "Podfile.lock")),
|
|
1303
1149
|
stale: podsAreStale(podState.lockText, podState.manifestText)
|
|
@@ -1328,12 +1174,12 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
|
|
|
1328
1174
|
//#endregion
|
|
1329
1175
|
//#region src/commands/worktree.ts
|
|
1330
1176
|
function dependencyInstallCommand(target, dir = ".") {
|
|
1331
|
-
const installRoot = resolve(target, dir);
|
|
1177
|
+
const installRoot = resolve$1(target, dir);
|
|
1332
1178
|
let command = "npm install";
|
|
1333
|
-
if (existsSync$1(resolve(installRoot, "pnpm-lock.yaml"))) command = "pnpm install";
|
|
1334
|
-
else if (existsSync$1(resolve(installRoot, "yarn.lock"))) command = "yarn install";
|
|
1335
|
-
else if (existsSync$1(resolve(installRoot, "bun.lock")) || existsSync$1(resolve(installRoot, "bun.lockb"))) command = "bun install";
|
|
1336
|
-
else if (existsSync$1(resolve(installRoot, "package-lock.json"))) command = "npm ci";
|
|
1179
|
+
if (existsSync$1(resolve$1(installRoot, "pnpm-lock.yaml"))) command = "pnpm install";
|
|
1180
|
+
else if (existsSync$1(resolve$1(installRoot, "yarn.lock"))) command = "yarn install";
|
|
1181
|
+
else if (existsSync$1(resolve$1(installRoot, "bun.lock")) || existsSync$1(resolve$1(installRoot, "bun.lockb"))) command = "bun install";
|
|
1182
|
+
else if (existsSync$1(resolve$1(installRoot, "package-lock.json"))) command = "npm ci";
|
|
1337
1183
|
return `cd '${installRoot.replaceAll("'", "'\\''")}' && ${command}`;
|
|
1338
1184
|
}
|
|
1339
1185
|
function reportCarriedStateHealth(root, target, copied) {
|
|
@@ -1351,7 +1197,7 @@ function reportCarriedStateHealth(root, target, copied) {
|
|
|
1351
1197
|
}
|
|
1352
1198
|
for (const p of podsOutOfSync(target, copied)) {
|
|
1353
1199
|
const where = p.dir === "." ? "Podfile.lock" : `${p.dir}/Podfile.lock`;
|
|
1354
|
-
const pod = podInstallCommand(p.dir === "." ? target : resolve(target, p.dir, ".."));
|
|
1200
|
+
const pod = podInstallCommand(p.dir === "." ? target : resolve$1(target, p.dir, ".."));
|
|
1355
1201
|
console.error(chalk.yellow(phaseLine("carry", p.reason === "missing" ? `carried ${p.dir === "." ? "Pods" : `${p.dir}/Pods`} but there is no ${where}. Run \`${pod}\` before building.` : `carried ${p.dir === "." ? "Pods" : `${p.dir}/Pods`} does not match the ${where} on disk here. Pods are gitignored and cloned; Podfile.lock is tracked, so the two can disagree. Run \`${pod}\` before building, or xcodebuild fails with "sandbox is not in sync" only after every pod has compiled.`)));
|
|
1356
1202
|
}
|
|
1357
1203
|
}
|
|
@@ -1363,18 +1209,51 @@ function reportRefreshFailure(failure) {
|
|
|
1363
1209
|
process.exitCode = 1;
|
|
1364
1210
|
}
|
|
1365
1211
|
function mainCheckoutAppDir(root, target) {
|
|
1366
|
-
const app = findProjectRoot(process.cwd());
|
|
1212
|
+
const app = findProjectRoot$1(process.cwd());
|
|
1367
1213
|
if (!app) return root;
|
|
1368
|
-
const rel = relative(target, app);
|
|
1369
|
-
if (!rel || rel.startsWith("..") || isAbsolute(rel)) return root;
|
|
1370
|
-
return resolve(root, rel);
|
|
1214
|
+
const rel = relative$1(target, app);
|
|
1215
|
+
if (!rel || rel.startsWith("..") || isAbsolute$1(rel)) return root;
|
|
1216
|
+
return resolve$1(root, rel);
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* The app workspace a warm prepares: the nearest app below the worktree root, or else the one app registered in
|
|
1220
|
+
* the source checkout, at the same place in this worktree, or else the worktree root when it is the app. A monorepo
|
|
1221
|
+
* root can declare react-native without being the app.
|
|
1222
|
+
*/
|
|
1223
|
+
function warmedWorkspace(root, target, cwd) {
|
|
1224
|
+
const nearest = findProjectRoot$1(cwd);
|
|
1225
|
+
const app = nearest && isPathPrefix(target, nearest) && appProjectProblem(nearest) === null ? nearest : null;
|
|
1226
|
+
if (app && app !== target) return app;
|
|
1227
|
+
const apps = /* @__PURE__ */ new Set();
|
|
1228
|
+
for (const path of Object.keys(loadConfig$1()?.projects ?? {})) {
|
|
1229
|
+
const rel = relative$1(root, path);
|
|
1230
|
+
if (rel.startsWith("..") || isAbsolute$1(rel)) continue;
|
|
1231
|
+
const mapped = resolve$1(target, rel);
|
|
1232
|
+
if (appProjectProblem(mapped) === null) apps.add(mapped);
|
|
1233
|
+
}
|
|
1234
|
+
return apps.size === 1 ? [...apps][0] : app;
|
|
1235
|
+
}
|
|
1236
|
+
function registerWarmedWorkspace(workspace) {
|
|
1237
|
+
try {
|
|
1238
|
+
if (!getProject(workspace)) upsertProject(workspace, {});
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
console.error(chalk.yellow(`Could not register ${workspace} for status: ${error?.message || String(error)}`));
|
|
1241
|
+
}
|
|
1371
1242
|
}
|
|
1372
1243
|
function registerWarm(worktree) {
|
|
1373
1244
|
worktree.command("warm").description("Copy missing ignored paths from the source checkout into the current linked worktree.").option("--refresh", "Before copying, fast-forward the source checkout to its upstream and install what the new commits moved.").action(async (opts) => {
|
|
1245
|
+
let progress = null;
|
|
1246
|
+
let workspace = null;
|
|
1374
1247
|
try {
|
|
1375
1248
|
const { root, target, common } = warmWorktreePaths(process.cwd());
|
|
1376
|
-
const app = findProjectRoot(process.cwd());
|
|
1249
|
+
const app = findProjectRoot$1(process.cwd());
|
|
1377
1250
|
if (app) recordWorkspaceUse(app);
|
|
1251
|
+
workspace = warmedWorkspace(root, target, process.cwd());
|
|
1252
|
+
if (!workspace) console.error(chalk.dim(phaseLine("project", "no single app to register here; run warm from the app directory to list it in status while it warms")));
|
|
1253
|
+
else {
|
|
1254
|
+
registerWarmedWorkspace(workspace);
|
|
1255
|
+
progress = startWarmProgress(workspace, opts.refresh ? "refresh" : "copy", { note: (line) => console.error(chalk.yellow(line)) });
|
|
1256
|
+
}
|
|
1378
1257
|
const readSettings = () => {
|
|
1379
1258
|
const settings = resolveSettings({
|
|
1380
1259
|
gitCommonDir: common,
|
|
@@ -1390,6 +1269,7 @@ function registerWarm(worktree) {
|
|
|
1390
1269
|
return settings;
|
|
1391
1270
|
};
|
|
1392
1271
|
const copy = (wait) => {
|
|
1272
|
+
progress?.step("copy");
|
|
1393
1273
|
if (wait?.holder) console.error(warmClaimAcquiredLine(wait));
|
|
1394
1274
|
const incomplete = incompleteInstallRefusal(root, mainCheckoutAppDir(root, target));
|
|
1395
1275
|
if (incomplete) {
|
|
@@ -1487,6 +1367,10 @@ function registerWarm(worktree) {
|
|
|
1487
1367
|
if (claim) console.error(chalk.dim(claim.remedy));
|
|
1488
1368
|
if (typeof code === "string" && code.startsWith("STIM_")) console.error(chalk.red(`failed: ${code}`));
|
|
1489
1369
|
process.exitCode = 1;
|
|
1370
|
+
} finally {
|
|
1371
|
+
progress?.finish(!process.exitCode);
|
|
1372
|
+
const links = workspace && !process.exitCode ? workspaceLinks(workspace) : void 0;
|
|
1373
|
+
if (links) console.error(chalk.dim(workspaceLinkLine(links)));
|
|
1490
1374
|
}
|
|
1491
1375
|
});
|
|
1492
1376
|
}
|
|
@@ -1501,6 +1385,20 @@ function porcelainPath(line) {
|
|
|
1501
1385
|
}
|
|
1502
1386
|
const SAFE_DIFF_PATH = /^[A-Za-z0-9._/-]+$/;
|
|
1503
1387
|
const POD_CHURN_PATH = /(?:^|\/)ios\/(?:Podfile\.lock|[^/]+\.xcodeproj\/project\.pbxproj)$/;
|
|
1388
|
+
const WATCHMAN_COOKIE_PATH = /(?:^|\/)\.watchman-cookie-[A-Za-z0-9._-]+$/;
|
|
1389
|
+
function excludeWatchmanCookies(lines) {
|
|
1390
|
+
const kept = [];
|
|
1391
|
+
const cookies = [];
|
|
1392
|
+
for (const line of lines || []) {
|
|
1393
|
+
const path = String(line).startsWith("?? ") ? porcelainPath(line) : null;
|
|
1394
|
+
if (path && SAFE_DIFF_PATH.test(path) && WATCHMAN_COOKIE_PATH.test(path)) cookies.push(path);
|
|
1395
|
+
else kept.push(line);
|
|
1396
|
+
}
|
|
1397
|
+
return {
|
|
1398
|
+
lines: kept,
|
|
1399
|
+
cookies
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1504
1402
|
function excludePodChurn(lines) {
|
|
1505
1403
|
const kept = [];
|
|
1506
1404
|
const restore = [];
|
|
@@ -1523,11 +1421,11 @@ function excludePodChurn(lines) {
|
|
|
1523
1421
|
}
|
|
1524
1422
|
function nativeCanonicalPath(path) {
|
|
1525
1423
|
const missing = [];
|
|
1526
|
-
for (let existing = resolve(path);; existing = dirname(existing)) try {
|
|
1527
|
-
return resolve(realpathSync$1.native(existing), ...missing);
|
|
1424
|
+
for (let existing = resolve$1(path);; existing = dirname$1(existing)) try {
|
|
1425
|
+
return resolve$1(realpathSync$1.native(existing), ...missing);
|
|
1528
1426
|
} catch {
|
|
1529
|
-
if (dirname(existing) === existing) return resolve(path);
|
|
1530
|
-
missing.unshift(basename(existing));
|
|
1427
|
+
if (dirname$1(existing) === existing) return resolve$1(path);
|
|
1428
|
+
missing.unshift(basename$1(existing));
|
|
1531
1429
|
}
|
|
1532
1430
|
}
|
|
1533
1431
|
function matchWorktreeEntry(entries, path) {
|
|
@@ -1581,7 +1479,7 @@ function describeKeptDevice(s) {
|
|
|
1581
1479
|
return s.udid && s.udid !== s.name ? `${s.name} (${s.udid})` : s.name;
|
|
1582
1480
|
}
|
|
1583
1481
|
function reclaimKeys(rootPath) {
|
|
1584
|
-
const cfg = loadConfig();
|
|
1482
|
+
const cfg = loadConfig$1();
|
|
1585
1483
|
const keys = /* @__PURE__ */ new Set([rootPath]);
|
|
1586
1484
|
const root = nativeCanonicalPath(rootPath);
|
|
1587
1485
|
if (cfg?.projects) {
|
|
@@ -1615,7 +1513,8 @@ async function reclaimAll(rootPath, keys = reclaimKeys(rootPath), { preserveRoot
|
|
|
1615
1513
|
r = await reclaimProject(key, {
|
|
1616
1514
|
deleteOwnedDevices: true,
|
|
1617
1515
|
parkOwnedDevices: true,
|
|
1618
|
-
preserveProjectRecord: preserveRootProject && key === rootPath
|
|
1516
|
+
preserveProjectRecord: preserveRootProject && key === rootPath,
|
|
1517
|
+
stopRequester: { by: "stim worktree remove" }
|
|
1619
1518
|
});
|
|
1620
1519
|
} catch (error) {
|
|
1621
1520
|
keptEntries.push(key);
|
|
@@ -1712,7 +1611,7 @@ function reportRetainedResources(root, result) {
|
|
|
1712
1611
|
process.exitCode = 1;
|
|
1713
1612
|
}
|
|
1714
1613
|
function hasRegisteredProjectUnder(rootPath) {
|
|
1715
|
-
const cfg = loadConfig();
|
|
1614
|
+
const cfg = loadConfig$1();
|
|
1716
1615
|
return Object.keys(cfg?.projects ?? {}).some((key) => isPathPrefix(rootPath, key));
|
|
1717
1616
|
}
|
|
1718
1617
|
async function reclaimEnvironment(root, why) {
|
|
@@ -1739,20 +1638,21 @@ function removalPath(target) {
|
|
|
1739
1638
|
return canonicalExistingPath(target ?? process.cwd());
|
|
1740
1639
|
}
|
|
1741
1640
|
function canonicalExistingPath(target) {
|
|
1742
|
-
const resolved = resolve(target);
|
|
1641
|
+
const resolved = resolve$1(target);
|
|
1743
1642
|
let existing = resolved;
|
|
1744
1643
|
const missing = [];
|
|
1745
1644
|
while (!existsSync$1(existing)) {
|
|
1746
|
-
const parent = dirname(existing);
|
|
1645
|
+
const parent = dirname$1(existing);
|
|
1747
1646
|
if (parent === existing) return resolved;
|
|
1748
|
-
missing.unshift(basename(existing));
|
|
1647
|
+
missing.unshift(basename$1(existing));
|
|
1749
1648
|
existing = parent;
|
|
1750
1649
|
}
|
|
1751
|
-
return resolve(realpathSync$1(existing), ...missing);
|
|
1650
|
+
return resolve$1(realpathSync$1(existing), ...missing);
|
|
1752
1651
|
}
|
|
1753
1652
|
function inspectRemoval(path, mergedHead) {
|
|
1754
1653
|
const gitAnswered = hasUncommittedWork(path);
|
|
1755
|
-
const { lines:
|
|
1654
|
+
const { lines: withoutCookies, cookies } = excludeWatchmanCookies(gitAnswered ? dirtyPaths(path, { limit: Infinity }) : []);
|
|
1655
|
+
const { lines: dirtyLines, restore: podChurn } = excludePodChurn(withoutCookies);
|
|
1756
1656
|
const dirty = gitAnswered === null ? null : dirtyLines.length > 0;
|
|
1757
1657
|
const unpushed = unpushedCommits(path);
|
|
1758
1658
|
const blockers = removalBlockers({
|
|
@@ -1763,6 +1663,7 @@ function inspectRemoval(path, mergedHead) {
|
|
|
1763
1663
|
return {
|
|
1764
1664
|
dirtyLines,
|
|
1765
1665
|
podChurn,
|
|
1666
|
+
cookies,
|
|
1766
1667
|
unpushed,
|
|
1767
1668
|
blockers
|
|
1768
1669
|
};
|
|
@@ -1781,6 +1682,9 @@ function printRemovalRefusal(path, inspection) {
|
|
|
1781
1682
|
console.error(chalk.dim("work stays on the branch."));
|
|
1782
1683
|
process.exitCode = 1;
|
|
1783
1684
|
}
|
|
1685
|
+
function deleteWatchmanCookies(path, cookies) {
|
|
1686
|
+
for (const cookie of cookies) rmSync$1(join$1(path, cookie), { force: true });
|
|
1687
|
+
}
|
|
1784
1688
|
function restorePodChurn(path, files) {
|
|
1785
1689
|
for (const file of files) if (restoreFile(path, file)) console.error(chalk.dim(` restored ${file} (pod install churn; the worktree is being removed)`));
|
|
1786
1690
|
else console.error(chalk.yellow(` could not restore ${file}; git may refuse to remove the worktree`));
|
|
@@ -1828,7 +1732,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1828
1732
|
console.error(chalk.dim(phaseLine("branch", `${branch} is already absent; cleared its pending cleanup record`)));
|
|
1829
1733
|
return;
|
|
1830
1734
|
}
|
|
1831
|
-
const checkedOutAt = listWorktrees(mainRoot).find((candidate) => candidate.branch === branch && resolve(candidate.path) !== resolve(path))?.path;
|
|
1735
|
+
const checkedOutAt = listWorktrees(mainRoot).find((candidate) => candidate.branch === branch && resolve$1(candidate.path) !== resolve$1(path))?.path;
|
|
1832
1736
|
if (checkedOutAt) {
|
|
1833
1737
|
console.error(chalk.red(`Refusing pending cleanup for ${branch}: it is checked out at ${checkedOutAt}.`));
|
|
1834
1738
|
console.error(chalk.dim("Switch that worktree to another branch, then retry this command."));
|
|
@@ -1944,6 +1848,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1944
1848
|
return;
|
|
1945
1849
|
}
|
|
1946
1850
|
restorePodChurn(path, current.podChurn);
|
|
1851
|
+
deleteWatchmanCookies(path, current.cookies);
|
|
1947
1852
|
try {
|
|
1948
1853
|
removeWorktree(path, {
|
|
1949
1854
|
from: source.path,
|
|
@@ -1959,6 +1864,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1959
1864
|
return;
|
|
1960
1865
|
}
|
|
1961
1866
|
onRemoved();
|
|
1867
|
+
forgetStatusMeasures(path, result.reclaimedKeys);
|
|
1962
1868
|
const finish = () => {
|
|
1963
1869
|
printRemovalCleanup(result, false);
|
|
1964
1870
|
console.error(chalk.dim(phaseLine("removed", path)));
|
|
@@ -1974,7 +1880,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1974
1880
|
worktreeRemovalComplete: true,
|
|
1975
1881
|
worktreePendingBranchSha: approvedBranchSha
|
|
1976
1882
|
});
|
|
1977
|
-
const checkedOutAt = listWorktrees(branchDeleteCwd).find((candidate) => candidate.branch === branch && resolve(candidate.path) !== resolve(path))?.path;
|
|
1883
|
+
const checkedOutAt = listWorktrees(branchDeleteCwd).find((candidate) => candidate.branch === branch && resolve$1(candidate.path) !== resolve$1(path))?.path;
|
|
1978
1884
|
if (checkedOutAt) {
|
|
1979
1885
|
console.error(chalk.yellow(phaseLine("branch", `kept ${branch} (it is checked out at ${checkedOutAt})`)));
|
|
1980
1886
|
console.error(chalk.dim(` Switch that worktree to another branch, then retry: stim worktree remove ${path}`));
|
|
@@ -2008,4 +1914,4 @@ function worktreeCommand(program) {
|
|
|
2008
1914
|
registerRemove(worktree);
|
|
2009
1915
|
}
|
|
2010
1916
|
//#endregion
|
|
2011
|
-
export {
|
|
1917
|
+
export { porcelainPath as a, registerWarm as c, removalRemedy as d, removeWorktreeTarget as f, reclaimProject as g, describeDereferenced as h, matchWorktreeEntry as i, removalBlockers as l, worktreeCommand as m, excludePodChurn as n, reclaimKeys as o, warmedWorkspace as p, excludeWatchmanCookies as r, registerRemove as s, dependencyInstallCommand as t, removalPath as u };
|