stim 1.14.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-CYVDcrt3.mjs → activity-B2-kb7k0.mjs} +281 -41
- package/dist/{android-XpvCrV7q.mjs → android-CYmq0jNi.mjs} +2 -2
- package/dist/{android-LbPFRWVL.mjs → android-Cu_L4RpL.mjs} +502 -407
- package/dist/{android-d6rGq1pA.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-BpgSgkJj.mjs → app-install-CAAplXAt.mjs} +95 -161
- package/dist/{budget-CGDkhvv_.mjs → budget-CMiqghig.mjs} +1038 -73
- package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-aeGMFX7e.mjs} +193 -653
- package/dist/build-progress-C2Jv1AtA.mjs +872 -0
- package/dist/build-slots-Df1ApSuH.mjs +127 -0
- package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
- 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-DVcpw6eE.mjs → command-output-CliHHn7a.mjs} +1 -1
- package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
- package/dist/{created-devices-CllH_8eb.mjs → created-devices-BwVb3liH.mjs} +2 -2
- package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
- package/dist/{deps-D9IcKqXS.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-CjuuAJjQ.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-5c3WrVRm.mjs → device-lease-W5Pi1q38.mjs} +43 -36
- package/dist/{device-pool-BiyDyPP-.mjs → device-pool-B2r38YjS.mjs} +4 -4
- package/dist/{device-remote-D87zEzaq.mjs → device-remote-9ulPsdhY.mjs} +68 -162
- package/dist/{doctor-x9pnU9fq.mjs → doctor-BcE5xsBn.mjs} +191 -99
- package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-ko6mUAYD.mjs → gc-BuL1Genr.mjs} +429 -101
- package/dist/{android-cas-iZK3DOCr.mjs → gradle-CmdOBq1d.mjs} +8 -294
- package/dist/{guide-6R0VNFqI.mjs → guide-cCSGRFd3.mjs} +1959 -222
- package/dist/{guide-status-BZrFPIA_.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-BwDPrnYQ.mjs → ios-3CtCRhwr.mjs} +201 -10
- package/dist/{ios-P1f5nm2n.mjs → ios-Chob8ny7.mjs} +512 -263
- package/dist/{ios-device-DGglU3E_.mjs → ios-device-DERmMmk-.mjs} +12 -7
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-CLlofxRt.mjs} +4 -4
- package/dist/{logs-Civ4gbBH.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-CcEo8Fl8.mjs → metro-Di8EN2Tb.mjs} +20 -120
- package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Dj_XBNaL.mjs} +6 -59
- package/dist/native-run-DFDoIRbY.mjs +147 -0
- package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-i6OkVg-w.mjs} +9 -5
- package/dist/offload-worker.d.mts +121 -0
- package/dist/offload-worker.mjs +601 -0
- package/dist/{ownership-DyYDF5ww.mjs → ownership-BkYxUtuj.mjs} +3 -2
- package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-BguS83ex.mjs → ports-DddwttKM.mjs} +3 -3
- package/dist/prebuild-BvxDlD6C.mjs +213 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-CWlvEaeN.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-BiniwsSZ.mjs → reload-ChPiwvot.mjs} +70 -22
- package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-CO2elm_b.mjs} +4 -4
- package/dist/run-B-xqRrsg.mjs +119 -0
- package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-X7PUgizL.mjs} +33 -15
- package/dist/{server-expo-BVuwQ65v.mjs → server-expo-DhtX6bom.mjs} +6 -10
- package/dist/server-expo-KJeD109I.mjs +2 -0
- package/dist/{settings-D61iNOsB.mjs → settings-CduVcoxj.mjs} +77 -26
- package/dist/{settings-B-fsC-Om.mjs → settings-DbL6uhH8.mjs} +16 -10
- package/dist/settings.schema.json +357 -2
- package/dist/{simslim-DrDN4WuV.mjs → simslim-Ciluxlq4.mjs} +8 -132
- package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-BY0BrOLh.mjs} +6 -6
- package/dist/{spawn-claims-Drw_o-Fb.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-s4RXp1wy.mjs → start-CUD9nasA.mjs} +108 -61
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/state-BxCgeTQu.mjs +41 -0
- package/dist/{state-DHqvsbqC.mjs → state-CaeaHbDA.mjs} +7 -4
- package/dist/{state-Dk9RVXI7.mjs → state-DFm77wRn.mjs} +67 -5
- package/dist/stats-DBLLFmKd.mjs +66 -0
- package/dist/{status-BsPAnfOI.mjs → status-DYXxNOT0.mjs} +423 -268
- package/dist/{status-BgAuxESg.mjs → status-l84Gbvp2.mjs} +116 -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-BzreOWJp.mjs → stop-Bad61z_2.mjs} +38 -12
- package/dist/stop-Bvf1MflS.mjs +48 -0
- package/dist/{stop-BWIF_6BK.mjs → stop-CceYh1yG.mjs} +2 -2
- package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
- package/dist/supervisor-run.d.mts +43 -11
- package/dist/supervisor-run.mjs +227 -19
- package/dist/support-CDQbDkL5.mjs +315 -0
- package/dist/support-WLOzVKUv.mjs +176 -0
- package/dist/teardown-BYuQafiA.mjs +718 -0
- package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DmeYjXD9.mjs} +363 -13
- package/dist/warm-progress-DVHLN4uC.mjs +463 -0
- package/dist/{idle-DXtx3RbX.mjs → watchman-Bx0wceoF.mjs} +55 -8
- package/dist/{web-BsQs1WlO.mjs → web-k6w8-HnE.mjs} +37 -20
- package/dist/web-run.mjs +309 -12
- 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-BVrHsYZG.mjs → worktree-C0c5Udwa.mjs} +55 -54
- package/dist/{worktree-UrQWXSeb.mjs → worktree-qXKzADSC.mjs} +154 -252
- package/package.json +10 -5
- package/shim/bundle-response.cjs +28 -12
- package/dist/build-progress-DxKpwnaS.mjs +0 -247
- package/dist/in-use-DlqBDKqY.mjs +0 -249
- package/dist/server-expo-DIHDhvGg.mjs +0 -2
- package/dist/start-Cetfvy8l.mjs +0 -2
- package/dist/stats-CFpFGlJV.mjs +0 -62
- package/dist/stats-CX1Z8Tca.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
- package/dist/worktree-CHWWvm5v.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`);
|
|
@@ -303,7 +321,7 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
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;
|
|
@@ -359,7 +377,7 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
359
377
|
failedCollectors.push(entry);
|
|
360
378
|
}
|
|
361
379
|
function retainReplacementProcesses() {
|
|
362
|
-
const currentState = readWorkspaceState(path);
|
|
380
|
+
const currentState = readWorkspaceState$1(path);
|
|
363
381
|
const currentProject = getProject(path);
|
|
364
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])))) {
|
|
365
383
|
supervisorHeld = true;
|
|
@@ -382,6 +400,17 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
382
400
|
skippedDevices.push(remote.failed);
|
|
383
401
|
failedDevices.push(remote.failed);
|
|
384
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
|
+
}
|
|
385
414
|
const tunnel = await reclaimMetroTunnel(path, { stopMetroTunnel });
|
|
386
415
|
if (tunnel.failed) {
|
|
387
416
|
skippedDevices.push(tunnel.failed);
|
|
@@ -428,192 +457,6 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
|
|
|
428
457
|
};
|
|
429
458
|
}
|
|
430
459
|
//#endregion
|
|
431
|
-
//#region src/workspace/pull-request.ts
|
|
432
|
-
const GH_TIMEOUT_MS = 2e4;
|
|
433
|
-
const GH_ENV = {
|
|
434
|
-
GH_PROMPT_DISABLED: "1",
|
|
435
|
-
GH_NO_UPDATE_NOTIFIER: "1",
|
|
436
|
-
NO_COLOR: "1"
|
|
437
|
-
};
|
|
438
|
-
const GH_FIELDS = "number,state,url,headRefOid,mergedAt,closedAt,isCrossRepository";
|
|
439
|
-
const SIGNED_OUT_EXIT = 4;
|
|
440
|
-
function stateOf(state) {
|
|
441
|
-
if (state === "OPEN") return "open";
|
|
442
|
-
if (state === "MERGED") return "merged";
|
|
443
|
-
if (state === "CLOSED") return "closed";
|
|
444
|
-
return null;
|
|
445
|
-
}
|
|
446
|
-
function epoch(text) {
|
|
447
|
-
const at = text ? Date.parse(text) : NaN;
|
|
448
|
-
return Number.isFinite(at) ? at : null;
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Picks the pull request that describes `head` among those `gh pr list --head <branch>` returned. One whose head is
|
|
452
|
-
* `head` wins, then one whose head contains `head`, then one whose head `head` contains. An open one wins a tier,
|
|
453
|
-
* then the newest. A pull request unrelated to `head` is from an earlier use of the branch name, and one from a fork
|
|
454
|
-
* only shares the branch name; both are ignored.
|
|
455
|
-
* `isAncestor(a, b)` answers whether commit `a` is an ancestor of commit `b`, and false when git cannot tell.
|
|
456
|
-
*/
|
|
457
|
-
function selectPullRequest(pulls, head, isAncestor) {
|
|
458
|
-
const known = pulls.flatMap((pull) => {
|
|
459
|
-
const state = stateOf(pull.state);
|
|
460
|
-
return state && pull.headRefOid && !pull.isCrossRepository ? [{
|
|
461
|
-
pull,
|
|
462
|
-
state
|
|
463
|
-
}] : [];
|
|
464
|
-
});
|
|
465
|
-
const tiers = [
|
|
466
|
-
known.filter(({ pull }) => pull.headRefOid === head),
|
|
467
|
-
known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(head, pull.headRefOid)),
|
|
468
|
-
known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(pull.headRefOid, head))
|
|
469
|
-
];
|
|
470
|
-
const tier = tiers.findIndex((entries) => entries.length > 0);
|
|
471
|
-
if (tier < 0) return null;
|
|
472
|
-
const { pull, state } = tiers[tier].toSorted((a, b) => Number(b.state === "open") - Number(a.state === "open") || b.pull.number - a.pull.number)[0];
|
|
473
|
-
return {
|
|
474
|
-
number: pull.number,
|
|
475
|
-
state,
|
|
476
|
-
url: pull.url,
|
|
477
|
-
head: pull.headRefOid,
|
|
478
|
-
containsHead: tier < 2,
|
|
479
|
-
endedAt: state === "merged" ? epoch(pull.mergedAt) : state === "closed" ? epoch(pull.closedAt) : null
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
function firstLine(error) {
|
|
483
|
-
const { stderr, message } = error;
|
|
484
|
-
const text = String(stderr ?? "").trim() || String(message ?? error);
|
|
485
|
-
return text.split("\n")[0] ?? text;
|
|
486
|
-
}
|
|
487
|
-
function ghFailure(error, command) {
|
|
488
|
-
if (error.status === SIGNED_OUT_EXIT) return {
|
|
489
|
-
unavailable: "gh is not signed in; run `gh auth login`",
|
|
490
|
-
sticky: true
|
|
491
|
-
};
|
|
492
|
-
if (error.code === "ETIMEDOUT") return {
|
|
493
|
-
unavailable: `${command} did not answer within ${GH_TIMEOUT_MS / 1e3}s`,
|
|
494
|
-
sticky: true
|
|
495
|
-
};
|
|
496
|
-
return {
|
|
497
|
-
unavailable: `${command} failed: ${firstLine(error)}`,
|
|
498
|
-
sticky: false
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
function ancestry(cwd) {
|
|
502
|
-
const exec = getExecutor();
|
|
503
|
-
return (ancestor, descendant) => exec.runFileQuiet("git", [
|
|
504
|
-
"-C",
|
|
505
|
-
cwd,
|
|
506
|
-
"merge-base",
|
|
507
|
-
"--is-ancestor",
|
|
508
|
-
ancestor,
|
|
509
|
-
descendant
|
|
510
|
-
]) !== null;
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* Asks GitHub, through `gh`, which pull requests have `branch` as their head, run from `cwd` so `gh` picks the
|
|
514
|
-
* repository from its remotes. Each call is one fixed `gh pr list` invocation. Once `gh` is missing, signed out or
|
|
515
|
-
* times out, every later lookup through the same function answers `unavailable` without running it again.
|
|
516
|
-
*/
|
|
517
|
-
function pullRequestLookup() {
|
|
518
|
-
let unavailable;
|
|
519
|
-
return (cwd, branch, head) => {
|
|
520
|
-
const exec = getExecutor();
|
|
521
|
-
if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
|
|
522
|
-
if (unavailable) return { unavailable };
|
|
523
|
-
let out;
|
|
524
|
-
try {
|
|
525
|
-
out = exec.runFile("gh", [
|
|
526
|
-
"pr",
|
|
527
|
-
"list",
|
|
528
|
-
"--head",
|
|
529
|
-
branch,
|
|
530
|
-
"--state",
|
|
531
|
-
"all",
|
|
532
|
-
"--limit",
|
|
533
|
-
"20",
|
|
534
|
-
"--json",
|
|
535
|
-
GH_FIELDS
|
|
536
|
-
], {
|
|
537
|
-
cwd,
|
|
538
|
-
timeoutMs: GH_TIMEOUT_MS,
|
|
539
|
-
env: GH_ENV
|
|
540
|
-
});
|
|
541
|
-
} catch (error) {
|
|
542
|
-
const failure = ghFailure(error, "gh pr list");
|
|
543
|
-
if (failure.sticky) unavailable = failure.unavailable;
|
|
544
|
-
return { unavailable: failure.unavailable };
|
|
545
|
-
}
|
|
546
|
-
let pulls;
|
|
547
|
-
try {
|
|
548
|
-
pulls = JSON.parse(out);
|
|
549
|
-
} catch {
|
|
550
|
-
return { unavailable: "gh pr list printed no JSON" };
|
|
551
|
-
}
|
|
552
|
-
return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd)) : null };
|
|
553
|
-
};
|
|
554
|
-
}
|
|
555
|
-
function branchesQuery(count) {
|
|
556
|
-
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("")} } }`;
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
* {@link pullRequestLookup} for every branch of one repository in one fixed `gh api graphql` call run from `repo`,
|
|
560
|
-
* which asks for the same 20 newest pull requests of each head branch that `gh pr list --head` returns. `gh` fills
|
|
561
|
-
* `{owner}` and `{repo}` from the remotes of `repo`; branch names travel as variables. Once `gh` is missing, signed
|
|
562
|
-
* out or times out, every later call through the same function answers `unavailable` without running it again.
|
|
563
|
-
*/
|
|
564
|
-
function pullRequestLookups() {
|
|
565
|
-
let unavailable;
|
|
566
|
-
return async (repo, queries) => {
|
|
567
|
-
const exec = getExecutor();
|
|
568
|
-
if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
|
|
569
|
-
const all = (lookup) => queries.map(() => lookup);
|
|
570
|
-
if (unavailable) return all({ unavailable });
|
|
571
|
-
if (!queries.length) return [];
|
|
572
|
-
const args = [
|
|
573
|
-
"api",
|
|
574
|
-
"graphql",
|
|
575
|
-
"-F",
|
|
576
|
-
"owner={owner}",
|
|
577
|
-
"-F",
|
|
578
|
-
"repo={repo}"
|
|
579
|
-
];
|
|
580
|
-
queries.forEach(({ branch }, i) => args.push("-f", `b${i}=${branch}`));
|
|
581
|
-
args.push("-f", `query=${branchesQuery(queries.length)}`);
|
|
582
|
-
let out;
|
|
583
|
-
try {
|
|
584
|
-
out = await exec.runFileAsync("gh", args, {
|
|
585
|
-
cwd: repo,
|
|
586
|
-
timeoutMs: GH_TIMEOUT_MS,
|
|
587
|
-
env: GH_ENV
|
|
588
|
-
});
|
|
589
|
-
} catch (error) {
|
|
590
|
-
const failure = ghFailure(error, "gh api graphql");
|
|
591
|
-
if (failure.sticky) unavailable = failure.unavailable;
|
|
592
|
-
return all({ unavailable: failure.unavailable });
|
|
593
|
-
}
|
|
594
|
-
let found;
|
|
595
|
-
try {
|
|
596
|
-
found = JSON.parse(out).data?.repository;
|
|
597
|
-
} catch {
|
|
598
|
-
return all({ unavailable: "gh api graphql printed no JSON" });
|
|
599
|
-
}
|
|
600
|
-
if (!found) return all({ unavailable: "gh api graphql printed no repository" });
|
|
601
|
-
return queries.map(({ cwd, head }, i) => {
|
|
602
|
-
const pulls = found[`b${i}`]?.nodes;
|
|
603
|
-
return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd)) : null };
|
|
604
|
-
});
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
/** The merged or closed pull request whose commits include HEAD, which makes the worktree removable. */
|
|
608
|
-
function endedPullRequest(lookup) {
|
|
609
|
-
const pr = lookup && "pullRequest" in lookup ? lookup.pullRequest : null;
|
|
610
|
-
return pr && pr.state !== "open" && pr.containsHead ? pr : null;
|
|
611
|
-
}
|
|
612
|
-
/** "PR #123 merged", for reports. */
|
|
613
|
-
function describePullRequest(pr) {
|
|
614
|
-
return `PR #${pr.number} ${pr.state}`;
|
|
615
|
-
}
|
|
616
|
-
//#endregion
|
|
617
460
|
//#region src/engine/warm-claim.ts
|
|
618
461
|
const WARM_CLAIM_LABEL = "worktree warm";
|
|
619
462
|
const WARM_CLAIM_POLL_MS = 250;
|
|
@@ -634,10 +477,10 @@ function defaultSleep(ms) {
|
|
|
634
477
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
635
478
|
}
|
|
636
479
|
function warmClaimsDir() {
|
|
637
|
-
return join
|
|
480
|
+
return join(getConfigDir(), "warm-locks");
|
|
638
481
|
}
|
|
639
482
|
function warmClaimPath(repositoryRoot) {
|
|
640
|
-
return join
|
|
483
|
+
return join(warmClaimsDir(), `${workspaceName(repositoryRoot)}.lock`);
|
|
641
484
|
}
|
|
642
485
|
function warmCommand(phase) {
|
|
643
486
|
return phase === "refresh" ? "stim worktree warm --refresh" : "stim worktree warm";
|
|
@@ -964,11 +807,11 @@ function stepLine(label, reason, action) {
|
|
|
964
807
|
return phaseLine(label, `${reason} -> ${action}`);
|
|
965
808
|
}
|
|
966
809
|
function installRecordFile(depsRoot) {
|
|
967
|
-
return join
|
|
810
|
+
return join(getConfigDir(), "warm-installs", `${workspaceName(depsRoot)}.json`);
|
|
968
811
|
}
|
|
969
812
|
function lockfileHash(depsRoot, lockfile) {
|
|
970
813
|
try {
|
|
971
|
-
return createHash("sha256").update(readFileSync(join
|
|
814
|
+
return createHash("sha256").update(readFileSync(join(depsRoot, lockfile))).digest("hex");
|
|
972
815
|
} catch {
|
|
973
816
|
return null;
|
|
974
817
|
}
|
|
@@ -990,7 +833,7 @@ function readInstallEvidence(depsRoot) {
|
|
|
990
833
|
function writeInstallEvidence(depsRoot, lockfile, hash, completed) {
|
|
991
834
|
const file = installRecordFile(depsRoot);
|
|
992
835
|
const tmp = `${file}.${process.pid}.${randomUUID()}.tmp`;
|
|
993
|
-
mkdirSync(join
|
|
836
|
+
mkdirSync(join(getConfigDir(), "warm-installs"), { recursive: true });
|
|
994
837
|
writeFileSync(tmp, JSON.stringify({
|
|
995
838
|
lock: lockfile,
|
|
996
839
|
hash: hash ?? "",
|
|
@@ -1008,9 +851,9 @@ function restoreInstallEvidence(depsRoot, prior) {
|
|
|
1008
851
|
else rmSync(installRecordFile(depsRoot), { force: true });
|
|
1009
852
|
}
|
|
1010
853
|
function inProgressOperation(gitDir) {
|
|
1011
|
-
if (existsSync(join
|
|
1012
|
-
if (existsSync(join
|
|
1013
|
-
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;
|
|
1014
857
|
}
|
|
1015
858
|
function readMainCheckoutState(root) {
|
|
1016
859
|
const exec = getExecutor();
|
|
@@ -1264,7 +1107,7 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
|
|
|
1264
1107
|
const consumed = dependencies ? lockfileHash(dependencies.root, dependencies.lock) : null;
|
|
1265
1108
|
const deps = depsPlan({
|
|
1266
1109
|
lockfile: dependencies?.lock ?? null,
|
|
1267
|
-
lockfileChanged: dependencies ? pathChangedBetween(root, before, head, gitPath(relative
|
|
1110
|
+
lockfileChanged: dependencies ? pathChangedBetween(root, before, head, gitPath(relative(root, dependencies.root), dependencies.lock)) : false,
|
|
1268
1111
|
installed,
|
|
1269
1112
|
treeValid: dependencies?.lock === "package-lock.json" && installed ? installedNpmTreeIsValid(dependencies.root) : null,
|
|
1270
1113
|
lastInstall: priorInstall,
|
|
@@ -1296,11 +1139,11 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
|
|
|
1296
1139
|
if (marked) restoreInstallEvidence(marked.root, priorInstall);
|
|
1297
1140
|
emit(stepLine("deps", depsSubject, "skipped"));
|
|
1298
1141
|
}
|
|
1299
|
-
const app = relative
|
|
1142
|
+
const app = relative(root, appDir) || ".";
|
|
1300
1143
|
const where = `source ${appDir}: `;
|
|
1301
1144
|
const podState = readPodState(appDir);
|
|
1302
1145
|
const pods = podsPlan({
|
|
1303
|
-
hasIos: existsSync(join
|
|
1146
|
+
hasIos: existsSync(join(appDir, "ios")),
|
|
1304
1147
|
hasPodfile: podState.hasPodfile,
|
|
1305
1148
|
podfileLockChanged: pathChangedBetween(root, before, head, gitPath(app, "ios", "Podfile.lock")),
|
|
1306
1149
|
stale: podsAreStale(podState.lockText, podState.manifestText)
|
|
@@ -1331,12 +1174,12 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
|
|
|
1331
1174
|
//#endregion
|
|
1332
1175
|
//#region src/commands/worktree.ts
|
|
1333
1176
|
function dependencyInstallCommand(target, dir = ".") {
|
|
1334
|
-
const installRoot = resolve(target, dir);
|
|
1177
|
+
const installRoot = resolve$1(target, dir);
|
|
1335
1178
|
let command = "npm install";
|
|
1336
|
-
if (existsSync$1(resolve(installRoot, "pnpm-lock.yaml"))) command = "pnpm install";
|
|
1337
|
-
else if (existsSync$1(resolve(installRoot, "yarn.lock"))) command = "yarn install";
|
|
1338
|
-
else if (existsSync$1(resolve(installRoot, "bun.lock")) || existsSync$1(resolve(installRoot, "bun.lockb"))) command = "bun install";
|
|
1339
|
-
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";
|
|
1340
1183
|
return `cd '${installRoot.replaceAll("'", "'\\''")}' && ${command}`;
|
|
1341
1184
|
}
|
|
1342
1185
|
function reportCarriedStateHealth(root, target, copied) {
|
|
@@ -1354,7 +1197,7 @@ function reportCarriedStateHealth(root, target, copied) {
|
|
|
1354
1197
|
}
|
|
1355
1198
|
for (const p of podsOutOfSync(target, copied)) {
|
|
1356
1199
|
const where = p.dir === "." ? "Podfile.lock" : `${p.dir}/Podfile.lock`;
|
|
1357
|
-
const pod = podInstallCommand(p.dir === "." ? target : resolve(target, p.dir, ".."));
|
|
1200
|
+
const pod = podInstallCommand(p.dir === "." ? target : resolve$1(target, p.dir, ".."));
|
|
1358
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.`)));
|
|
1359
1202
|
}
|
|
1360
1203
|
}
|
|
@@ -1366,18 +1209,51 @@ function reportRefreshFailure(failure) {
|
|
|
1366
1209
|
process.exitCode = 1;
|
|
1367
1210
|
}
|
|
1368
1211
|
function mainCheckoutAppDir(root, target) {
|
|
1369
|
-
const app = findProjectRoot(process.cwd());
|
|
1212
|
+
const app = findProjectRoot$1(process.cwd());
|
|
1370
1213
|
if (!app) return root;
|
|
1371
|
-
const rel = relative(target, app);
|
|
1372
|
-
if (!rel || rel.startsWith("..") || isAbsolute(rel)) return root;
|
|
1373
|
-
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
|
+
}
|
|
1374
1242
|
}
|
|
1375
1243
|
function registerWarm(worktree) {
|
|
1376
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;
|
|
1377
1247
|
try {
|
|
1378
1248
|
const { root, target, common } = warmWorktreePaths(process.cwd());
|
|
1379
|
-
const app = findProjectRoot(process.cwd());
|
|
1249
|
+
const app = findProjectRoot$1(process.cwd());
|
|
1380
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
|
+
}
|
|
1381
1257
|
const readSettings = () => {
|
|
1382
1258
|
const settings = resolveSettings({
|
|
1383
1259
|
gitCommonDir: common,
|
|
@@ -1393,6 +1269,7 @@ function registerWarm(worktree) {
|
|
|
1393
1269
|
return settings;
|
|
1394
1270
|
};
|
|
1395
1271
|
const copy = (wait) => {
|
|
1272
|
+
progress?.step("copy");
|
|
1396
1273
|
if (wait?.holder) console.error(warmClaimAcquiredLine(wait));
|
|
1397
1274
|
const incomplete = incompleteInstallRefusal(root, mainCheckoutAppDir(root, target));
|
|
1398
1275
|
if (incomplete) {
|
|
@@ -1490,6 +1367,10 @@ function registerWarm(worktree) {
|
|
|
1490
1367
|
if (claim) console.error(chalk.dim(claim.remedy));
|
|
1491
1368
|
if (typeof code === "string" && code.startsWith("STIM_")) console.error(chalk.red(`failed: ${code}`));
|
|
1492
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)));
|
|
1493
1374
|
}
|
|
1494
1375
|
});
|
|
1495
1376
|
}
|
|
@@ -1504,6 +1385,20 @@ function porcelainPath(line) {
|
|
|
1504
1385
|
}
|
|
1505
1386
|
const SAFE_DIFF_PATH = /^[A-Za-z0-9._/-]+$/;
|
|
1506
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
|
+
}
|
|
1507
1402
|
function excludePodChurn(lines) {
|
|
1508
1403
|
const kept = [];
|
|
1509
1404
|
const restore = [];
|
|
@@ -1526,11 +1421,11 @@ function excludePodChurn(lines) {
|
|
|
1526
1421
|
}
|
|
1527
1422
|
function nativeCanonicalPath(path) {
|
|
1528
1423
|
const missing = [];
|
|
1529
|
-
for (let existing = resolve(path);; existing = dirname(existing)) try {
|
|
1530
|
-
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);
|
|
1531
1426
|
} catch {
|
|
1532
|
-
if (dirname(existing) === existing) return resolve(path);
|
|
1533
|
-
missing.unshift(basename(existing));
|
|
1427
|
+
if (dirname$1(existing) === existing) return resolve$1(path);
|
|
1428
|
+
missing.unshift(basename$1(existing));
|
|
1534
1429
|
}
|
|
1535
1430
|
}
|
|
1536
1431
|
function matchWorktreeEntry(entries, path) {
|
|
@@ -1584,7 +1479,7 @@ function describeKeptDevice(s) {
|
|
|
1584
1479
|
return s.udid && s.udid !== s.name ? `${s.name} (${s.udid})` : s.name;
|
|
1585
1480
|
}
|
|
1586
1481
|
function reclaimKeys(rootPath) {
|
|
1587
|
-
const cfg = loadConfig();
|
|
1482
|
+
const cfg = loadConfig$1();
|
|
1588
1483
|
const keys = /* @__PURE__ */ new Set([rootPath]);
|
|
1589
1484
|
const root = nativeCanonicalPath(rootPath);
|
|
1590
1485
|
if (cfg?.projects) {
|
|
@@ -1716,7 +1611,7 @@ function reportRetainedResources(root, result) {
|
|
|
1716
1611
|
process.exitCode = 1;
|
|
1717
1612
|
}
|
|
1718
1613
|
function hasRegisteredProjectUnder(rootPath) {
|
|
1719
|
-
const cfg = loadConfig();
|
|
1614
|
+
const cfg = loadConfig$1();
|
|
1720
1615
|
return Object.keys(cfg?.projects ?? {}).some((key) => isPathPrefix(rootPath, key));
|
|
1721
1616
|
}
|
|
1722
1617
|
async function reclaimEnvironment(root, why) {
|
|
@@ -1743,20 +1638,21 @@ function removalPath(target) {
|
|
|
1743
1638
|
return canonicalExistingPath(target ?? process.cwd());
|
|
1744
1639
|
}
|
|
1745
1640
|
function canonicalExistingPath(target) {
|
|
1746
|
-
const resolved = resolve(target);
|
|
1641
|
+
const resolved = resolve$1(target);
|
|
1747
1642
|
let existing = resolved;
|
|
1748
1643
|
const missing = [];
|
|
1749
1644
|
while (!existsSync$1(existing)) {
|
|
1750
|
-
const parent = dirname(existing);
|
|
1645
|
+
const parent = dirname$1(existing);
|
|
1751
1646
|
if (parent === existing) return resolved;
|
|
1752
|
-
missing.unshift(basename(existing));
|
|
1647
|
+
missing.unshift(basename$1(existing));
|
|
1753
1648
|
existing = parent;
|
|
1754
1649
|
}
|
|
1755
|
-
return resolve(realpathSync$1(existing), ...missing);
|
|
1650
|
+
return resolve$1(realpathSync$1(existing), ...missing);
|
|
1756
1651
|
}
|
|
1757
1652
|
function inspectRemoval(path, mergedHead) {
|
|
1758
1653
|
const gitAnswered = hasUncommittedWork(path);
|
|
1759
|
-
const { lines:
|
|
1654
|
+
const { lines: withoutCookies, cookies } = excludeWatchmanCookies(gitAnswered ? dirtyPaths(path, { limit: Infinity }) : []);
|
|
1655
|
+
const { lines: dirtyLines, restore: podChurn } = excludePodChurn(withoutCookies);
|
|
1760
1656
|
const dirty = gitAnswered === null ? null : dirtyLines.length > 0;
|
|
1761
1657
|
const unpushed = unpushedCommits(path);
|
|
1762
1658
|
const blockers = removalBlockers({
|
|
@@ -1767,6 +1663,7 @@ function inspectRemoval(path, mergedHead) {
|
|
|
1767
1663
|
return {
|
|
1768
1664
|
dirtyLines,
|
|
1769
1665
|
podChurn,
|
|
1666
|
+
cookies,
|
|
1770
1667
|
unpushed,
|
|
1771
1668
|
blockers
|
|
1772
1669
|
};
|
|
@@ -1785,6 +1682,9 @@ function printRemovalRefusal(path, inspection) {
|
|
|
1785
1682
|
console.error(chalk.dim("work stays on the branch."));
|
|
1786
1683
|
process.exitCode = 1;
|
|
1787
1684
|
}
|
|
1685
|
+
function deleteWatchmanCookies(path, cookies) {
|
|
1686
|
+
for (const cookie of cookies) rmSync$1(join$1(path, cookie), { force: true });
|
|
1687
|
+
}
|
|
1788
1688
|
function restorePodChurn(path, files) {
|
|
1789
1689
|
for (const file of files) if (restoreFile(path, file)) console.error(chalk.dim(` restored ${file} (pod install churn; the worktree is being removed)`));
|
|
1790
1690
|
else console.error(chalk.yellow(` could not restore ${file}; git may refuse to remove the worktree`));
|
|
@@ -1832,7 +1732,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1832
1732
|
console.error(chalk.dim(phaseLine("branch", `${branch} is already absent; cleared its pending cleanup record`)));
|
|
1833
1733
|
return;
|
|
1834
1734
|
}
|
|
1835
|
-
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;
|
|
1836
1736
|
if (checkedOutAt) {
|
|
1837
1737
|
console.error(chalk.red(`Refusing pending cleanup for ${branch}: it is checked out at ${checkedOutAt}.`));
|
|
1838
1738
|
console.error(chalk.dim("Switch that worktree to another branch, then retry this command."));
|
|
@@ -1948,6 +1848,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1948
1848
|
return;
|
|
1949
1849
|
}
|
|
1950
1850
|
restorePodChurn(path, current.podChurn);
|
|
1851
|
+
deleteWatchmanCookies(path, current.cookies);
|
|
1951
1852
|
try {
|
|
1952
1853
|
removeWorktree(path, {
|
|
1953
1854
|
from: source.path,
|
|
@@ -1963,6 +1864,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1963
1864
|
return;
|
|
1964
1865
|
}
|
|
1965
1866
|
onRemoved();
|
|
1867
|
+
forgetStatusMeasures(path, result.reclaimedKeys);
|
|
1966
1868
|
const finish = () => {
|
|
1967
1869
|
printRemovalCleanup(result, false);
|
|
1968
1870
|
console.error(chalk.dim(phaseLine("removed", path)));
|
|
@@ -1978,7 +1880,7 @@ async function runRemove(target, opts, onRemoved) {
|
|
|
1978
1880
|
worktreeRemovalComplete: true,
|
|
1979
1881
|
worktreePendingBranchSha: approvedBranchSha
|
|
1980
1882
|
});
|
|
1981
|
-
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;
|
|
1982
1884
|
if (checkedOutAt) {
|
|
1983
1885
|
console.error(chalk.yellow(phaseLine("branch", `kept ${branch} (it is checked out at ${checkedOutAt})`)));
|
|
1984
1886
|
console.error(chalk.dim(` Switch that worktree to another branch, then retry: stim worktree remove ${path}`));
|
|
@@ -2012,4 +1914,4 @@ function worktreeCommand(program) {
|
|
|
2012
1914
|
registerRemove(worktree);
|
|
2013
1915
|
}
|
|
2014
1916
|
//#endregion
|
|
2015
|
-
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 };
|